ether8003.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. #include "u.h"
  2. #include "../port/lib.h"
  3. #include "mem.h"
  4. #include "dat.h"
  5. #include "fns.h"
  6. #include "io.h"
  7. #include "../port/error.h"
  8. #include "../port/netif.h"
  9. #include "etherif.h"
  10. #include "ether8390.h"
  11. /*
  12. * Western Digital/Standard Microsystems Corporation cards (WD80[01]3).
  13. * Also handles 8216 cards (Elite Ultra).
  14. * Configuration code based on that provided by SMC a long time ago.
  15. */
  16. enum { /* 83C584 Bus Interface Controller */
  17. Msr = 0x00, /* Memory Select Register */
  18. Icr = 0x01, /* Interface Configuration Register */
  19. Iar = 0x02, /* I/O Address Register */
  20. Bio = 0x03, /* BIOS ROM Address Register */
  21. Ear = 0x03, /* EEROM Address Register (shared with Bio) */
  22. Irr = 0x04, /* Interrupt Request Register */
  23. Hcr = 0x04, /* 8216 hardware control */
  24. Laar = 0x05, /* LA Address Register */
  25. Ijr = 0x06, /* Initialisation Jumpers */
  26. Gp2 = 0x07, /* General Purpose Data Register */
  27. Lar = 0x08, /* LAN Address Registers */
  28. Id = 0x0E, /* Card ID byte */
  29. Cksum = 0x0F, /* Checksum */
  30. };
  31. enum { /* Msr */
  32. Rst = 0x80, /* software reset */
  33. Menb = 0x40, /* memory enable */
  34. };
  35. enum { /* Icr */
  36. Bit16 = 0x01, /* 16-bit bus */
  37. Other = 0x02, /* other register access */
  38. Ir2 = 0x04, /* IR2 */
  39. Msz = 0x08, /* SRAM size */
  40. Rla = 0x10, /* recall LAN address */
  41. Rx7 = 0x20, /* recall all but I/O and LAN address */
  42. Rio = 0x40, /* recall I/O address from EEROM */
  43. Sto = 0x80, /* non-volatile EEROM store */
  44. };
  45. enum { /* Laar */
  46. ZeroWS16 = 0x20, /* zero wait states for 16-bit ops */
  47. L16en = 0x40, /* enable 16-bit LAN operation */
  48. M16en = 0x80, /* enable 16-bit memory access */
  49. };
  50. enum { /* Ijr */
  51. Ienable = 0x01, /* 8216 interrupt enable */
  52. };
  53. /*
  54. * Mapping from configuration bits to interrupt level.
  55. */
  56. static int irq8003[8] = {
  57. 9, 3, 5, 7, 10, 11, 15, 4,
  58. };
  59. static int irq8216[8] = {
  60. 0, 9, 3, 5, 7, 10, 11, 15,
  61. };
  62. static void
  63. reset8003(Ether* ether, uchar ea[Eaddrlen], uchar ic[8])
  64. {
  65. Dp8390 *ctlr;
  66. ulong port;
  67. ctlr = ether->ctlr;
  68. port = ether->port;
  69. /*
  70. * Check for old, dumb 8003E, which doesn't have an interface
  71. * chip. Only Msr exists out of the 1st eight registers, reads
  72. * of the others just alias the 2nd eight registers, the LAN
  73. * address ROM. Can check Icr, Irr and Laar against the ethernet
  74. * address read above and if they match it's an 8003E (or an
  75. * 8003EBT, 8003S, 8003SH or 8003WT, doesn't matter), in which
  76. * case the default irq gets used.
  77. */
  78. if(memcmp(&ea[1], &ic[1], 5) == 0){
  79. memset(ic, 0, sizeof(ic));
  80. ic[Msr] = (((ulong)ether->mem)>>13) & 0x3F;
  81. }
  82. else{
  83. /*
  84. * As a final sanity check for the 8013EBT, which doesn't have
  85. * the 83C584 interface chip, but has 2 real registers, write Gp2
  86. * and if it reads back the same, it's not an 8013EBT.
  87. */
  88. outb(port+Gp2, 0xAA);
  89. inb(port+Msr); /* wiggle bus */
  90. if(inb(port+Gp2) != 0xAA){
  91. memset(ic, 0, sizeof(ic));
  92. ic[Msr] = (((ulong)ether->mem)>>13) & 0x3F;
  93. }
  94. else
  95. ether->irq = irq8003[((ic[Irr]>>5) & 0x3)|(ic[Icr] & 0x4)];
  96. /*
  97. * Check if 16-bit card.
  98. * If Bit16 is read/write, then it's an 8-bit card.
  99. * If Bit16 is set, it's in a 16-bit slot.
  100. */
  101. outb(port+Icr, ic[Icr]^Bit16);
  102. inb(port+Msr); /* wiggle bus */
  103. if((inb(port+Icr) & Bit16) == (ic[Icr] & Bit16)){
  104. ctlr->width = 2;
  105. ic[Icr] &= ~Bit16;
  106. }
  107. outb(port+Icr, ic[Icr]);
  108. if(ctlr->width == 2 && (inb(port+Icr) & Bit16) == 0)
  109. ctlr->width = 1;
  110. }
  111. ether->mem = (ulong)KADDR((ic[Msr] & 0x3F)<<13);
  112. if(ctlr->width == 2)
  113. ether->mem |= (ic[Laar] & 0x1F)<<19;
  114. else
  115. ether->mem |= 0x80000;
  116. if(ic[Icr] & (1<<3))
  117. ether->size = 32*1024;
  118. if(ctlr->width == 2)
  119. ether->size <<= 1;
  120. /*
  121. * Enable interface RAM, set interface width.
  122. */
  123. outb(port+Msr, ic[Msr]|Menb);
  124. if(ctlr->width == 2)
  125. outb(port+Laar, ic[Laar]|L16en|M16en|ZeroWS16);
  126. }
  127. static void
  128. reset8216(Ether* ether, uchar[8])
  129. {
  130. uchar hcr, irq, x;
  131. ulong addr, port;
  132. Dp8390 *ctlr;
  133. ctlr = ether->ctlr;
  134. port = ether->port;
  135. ctlr->width = 2;
  136. /*
  137. * Switch to the alternate register set and retrieve the memory
  138. * and irq information.
  139. */
  140. hcr = inb(port+Hcr);
  141. outb(port+Hcr, 0x80|hcr);
  142. addr = inb(port+0x0B) & 0xFF;
  143. irq = inb(port+0x0D);
  144. outb(port+Hcr, hcr);
  145. ether->mem = (ulong)KADDR(0xC0000+((((addr>>2) & 0x30)|(addr & 0x0F))<<13));
  146. ether->size = 8192*(1<<((addr>>4) & 0x03));
  147. ether->irq = irq8216[((irq>>4) & 0x04)|((irq>>2) & 0x03)];
  148. /*
  149. * Enable interface RAM, set interface width, and enable interrupts.
  150. */
  151. x = inb(port+Msr) & ~Rst;
  152. outb(port+Msr, Menb|x);
  153. x = inb(port+Laar);
  154. outb(port+Laar, M16en|x);
  155. outb(port+Ijr, Ienable);
  156. }
  157. /*
  158. * Get configuration parameters, enable memory.
  159. * There are opportunities here for buckets of code, try to resist.
  160. */
  161. static int
  162. reset(Ether* ether)
  163. {
  164. int i;
  165. uchar ea[Eaddrlen], ic[8], id, nullea[Eaddrlen], sum;
  166. ulong port;
  167. Dp8390 *ctlr;
  168. /*
  169. * Set up the software configuration.
  170. * Use defaults for port, irq, mem and size if not specified.
  171. * Defaults are set for the dumb 8003E which can't be
  172. * autoconfigured.
  173. */
  174. if(ether->port == 0)
  175. ether->port = 0x280;
  176. if(ether->irq == 0)
  177. ether->irq = 3;
  178. if(ether->mem == 0)
  179. ether->mem = 0xD0000;
  180. if(ether->size == 0)
  181. ether->size = 8*1024;
  182. if(ioalloc(ether->port, 0x20, 0, "wd8003") < 0)
  183. return -1;
  184. /*
  185. * Look for the interface. Read the LAN address ROM
  186. * and validate the checksum - the sum of all 8 bytes
  187. * should be 0xFF.
  188. * At the same time, get the (possible) interface chip
  189. * registers, they'll be used later to check for aliasing.
  190. */
  191. port = ether->port;
  192. sum = 0;
  193. for(i = 0; i < sizeof(ea); i++){
  194. ea[i] = inb(port+Lar+i);
  195. sum += ea[i];
  196. ic[i] = inb(port+i);
  197. }
  198. id = inb(port+Id);
  199. sum += id;
  200. sum += inb(port+Cksum);
  201. if(sum != 0xFF){
  202. iofree(ether->port);
  203. return -1;
  204. }
  205. ether->ctlr = malloc(sizeof(Dp8390));
  206. ctlr = ether->ctlr;
  207. ctlr->ram = 1;
  208. if((id & 0xFE) == 0x2A)
  209. reset8216(ether, ic);
  210. else
  211. reset8003(ether, ea, ic);
  212. /*
  213. * Set the DP8390 ring addresses.
  214. */
  215. ctlr->port = port+0x10;
  216. ctlr->tstart = 0;
  217. ctlr->pstart = HOWMANY(sizeof(Etherpkt), Dp8390BufSz);
  218. ctlr->pstop = HOWMANY(ether->size, Dp8390BufSz);
  219. /*
  220. * Finally, init the 8390, set the ethernet address
  221. * and claim the memory used.
  222. */
  223. dp8390reset(ether);
  224. memset(nullea, 0, Eaddrlen);
  225. if(memcmp(nullea, ether->ea, Eaddrlen) == 0){
  226. for(i = 0; i < sizeof(ether->ea); i++)
  227. ether->ea[i] = ea[i];
  228. }
  229. dp8390setea(ether);
  230. if(umbrwmalloc(PADDR(ether->mem), ether->size, 0) == 0)
  231. print("ether8003: warning - 0x%luX unavailable\n",
  232. PADDR(ether->mem));
  233. return 0;
  234. }
  235. void
  236. ether8003link(void)
  237. {
  238. addethercard("WD8003", reset);
  239. }