ns8390.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836
  1. /**************************************************************************
  2. ETHERBOOT - BOOTP/TFTP Bootstrap Program
  3. Author: Martin Renters
  4. Date: May/94
  5. This code is based heavily on David Greenman's if_ed.c driver
  6. Copyright (C) 1993-1994, David Greenman, Martin Renters.
  7. This software may be used, modified, copied, distributed, and sold, in
  8. both source and binary form provided that the above copyright and these
  9. terms are retained. Under no circumstances are the authors responsible for
  10. the proper functioning of this software, nor do the authors assume any
  11. responsibility for damages incurred with its use.
  12. 3c503 support added by Bill Paul (wpaul@ctr.columbia.edu) on 11/15/94
  13. SMC8416 support added by Bill Paul (wpaul@ctr.columbia.edu) on 12/25/94
  14. 3c503 PIO support added by Jim Hague (jim.hague@acm.org) on 2/17/98
  15. RX overrun by Klaus Espenlaub (espenlaub@informatik.uni-ulm.de) on 3/10/99
  16. parts taken from the Linux 8390 driver (by Donald Becker and Paul Gortmaker)
  17. **************************************************************************/
  18. #include "etherboot.h"
  19. #include "nic.h"
  20. #include "ns8390.h"
  21. #ifdef INCLUDE_NS8390
  22. #include "pci.h"
  23. #endif
  24. #include "cards.h"
  25. static unsigned char eth_vendor, eth_flags, eth_laar;
  26. static unsigned short eth_nic_base, eth_asic_base;
  27. static unsigned char eth_memsize, eth_rx_start, eth_tx_start;
  28. static Address eth_bmem, eth_rmem;
  29. static unsigned char eth_drain_receiver;
  30. #ifdef INCLUDE_WD
  31. static struct wd_board {
  32. const char *name;
  33. char id;
  34. char flags;
  35. char memsize;
  36. } wd_boards[] = {
  37. {"WD8003S", TYPE_WD8003S, 0, MEM_8192},
  38. {"WD8003E", TYPE_WD8003E, 0, MEM_8192},
  39. {"WD8013EBT", TYPE_WD8013EBT, FLAG_16BIT, MEM_16384},
  40. {"WD8003W", TYPE_WD8003W, 0, MEM_8192},
  41. {"WD8003EB", TYPE_WD8003EB, 0, MEM_8192},
  42. {"WD8013W", TYPE_WD8013W, FLAG_16BIT, MEM_16384},
  43. {"WD8003EP/WD8013EP",
  44. TYPE_WD8013EP, 0, MEM_8192},
  45. {"WD8013WC", TYPE_WD8013WC, FLAG_16BIT, MEM_16384},
  46. {"WD8013EPC", TYPE_WD8013EPC, FLAG_16BIT, MEM_16384},
  47. {"SMC8216T", TYPE_SMC8216T, FLAG_16BIT | FLAG_790, MEM_16384},
  48. {"SMC8216C", TYPE_SMC8216C, FLAG_16BIT | FLAG_790, MEM_16384},
  49. {"SMC8416T", TYPE_SMC8416T, FLAG_16BIT | FLAG_790, MEM_8192},
  50. {"SMC8416C/BT", TYPE_SMC8416C, FLAG_16BIT | FLAG_790, MEM_8192},
  51. {"SMC8013EBP", TYPE_SMC8013EBP,FLAG_16BIT, MEM_16384},
  52. {NULL, 0, 0, 0}
  53. };
  54. #endif
  55. #ifdef INCLUDE_3C503
  56. static unsigned char t503_output; /* AUI or internal xcvr (Thinnet) */
  57. #endif
  58. #if defined(INCLUDE_WD)
  59. #define eth_probe wd_probe
  60. #if defined(INCLUDE_3C503) || defined(INCLUDE_NE) || defined(INCLUDE_NS8390)
  61. Error you must only define one of INCLUDE_WD, INCLUDE_3C503, INCLUDE_NE, INCLUDE_NS8390
  62. #endif
  63. #endif
  64. #if defined(INCLUDE_3C503)
  65. #define eth_probe t503_probe
  66. #if defined(INCLUDE_NE) || defined(INCLUDE_NS8390) || defined(INCLUDE_WD)
  67. Error you must only define one of INCLUDE_WD, INCLUDE_3C503, INCLUDE_NE, INCLUDE_NS8390
  68. #endif
  69. #endif
  70. #if defined(INCLUDE_NE)
  71. #define eth_probe ne_probe
  72. #if defined(INCLUDE_NS8390) || defined(INCLUDE_3C503) || defined(INCLUDE_WD)
  73. Error you must only define one of INCLUDE_WD, INCLUDE_3C503, INCLUDE_NE, INCLUDE_NS8390
  74. #endif
  75. #endif
  76. #if defined(INCLUDE_NS8390)
  77. #define eth_probe nepci_probe
  78. #if defined(INCLUDE_NE) || defined(INCLUDE_3C503) || defined(INCLUDE_WD)
  79. Error you must only define one of INCLUDE_WD, INCLUDE_3C503, INCLUDE_NE, INCLUDE_NS8390
  80. #endif
  81. #endif
  82. #if defined(INCLUDE_3C503)
  83. #define ASIC_PIO _3COM_RFMSB
  84. #else
  85. #if defined(INCLUDE_NE) || defined(INCLUDE_NS8390)
  86. #define ASIC_PIO NE_DATA
  87. #endif
  88. #endif
  89. #if defined(INCLUDE_NE) || defined(INCLUDE_NS8390) || (defined(INCLUDE_3C503) && !defined(T503_SHMEM))
  90. /**************************************************************************
  91. ETH_PIO_READ - Read a frame via Programmed I/O
  92. **************************************************************************/
  93. static void eth_pio_read(unsigned int src, unsigned char *dst, unsigned int cnt)
  94. {
  95. if (eth_flags & FLAG_16BIT) { ++cnt; cnt &= ~1; }
  96. outb(D8390_COMMAND_RD2 |
  97. D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
  98. outb(cnt, eth_nic_base + D8390_P0_RBCR0);
  99. outb(cnt>>8, eth_nic_base + D8390_P0_RBCR1);
  100. outb(src, eth_nic_base + D8390_P0_RSAR0);
  101. outb(src>>8, eth_nic_base + D8390_P0_RSAR1);
  102. outb(D8390_COMMAND_RD0 |
  103. D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
  104. #ifdef INCLUDE_3C503
  105. outb(src & 0xff, eth_asic_base + _3COM_DALSB);
  106. outb(src >> 8, eth_asic_base + _3COM_DAMSB);
  107. outb(t503_output | _3COM_CR_START, eth_asic_base + _3COM_CR);
  108. #endif
  109. if (eth_flags & FLAG_16BIT)
  110. cnt >>= 1;
  111. while(cnt--) {
  112. #ifdef INCLUDE_3C503
  113. while((inb(eth_asic_base + _3COM_STREG) & _3COM_STREG_DPRDY) == 0)
  114. ;
  115. #endif
  116. if (eth_flags & FLAG_16BIT) {
  117. *((unsigned short *)dst) = inw(eth_asic_base + ASIC_PIO);
  118. dst += 2;
  119. }
  120. else
  121. *(dst++) = inb(eth_asic_base + ASIC_PIO);
  122. }
  123. #ifdef INCLUDE_3C503
  124. outb(t503_output, eth_asic_base + _3COM_CR);
  125. #endif
  126. }
  127. /**************************************************************************
  128. ETH_PIO_WRITE - Write a frame via Programmed I/O
  129. **************************************************************************/
  130. static void eth_pio_write(const unsigned char *src, unsigned int dst, unsigned int cnt)
  131. {
  132. #ifdef COMPEX_RL2000_FIX
  133. unsigned int x;
  134. #endif /* COMPEX_RL2000_FIX */
  135. if (eth_flags & FLAG_16BIT) { ++cnt; cnt &= ~1; }
  136. outb(D8390_COMMAND_RD2 |
  137. D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
  138. outb(D8390_ISR_RDC, eth_nic_base + D8390_P0_ISR);
  139. outb(cnt, eth_nic_base + D8390_P0_RBCR0);
  140. outb(cnt>>8, eth_nic_base + D8390_P0_RBCR1);
  141. outb(dst, eth_nic_base + D8390_P0_RSAR0);
  142. outb(dst>>8, eth_nic_base + D8390_P0_RSAR1);
  143. outb(D8390_COMMAND_RD1 |
  144. D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
  145. #ifdef INCLUDE_3C503
  146. outb(dst & 0xff, eth_asic_base + _3COM_DALSB);
  147. outb(dst >> 8, eth_asic_base + _3COM_DAMSB);
  148. outb(t503_output | _3COM_CR_DDIR | _3COM_CR_START, eth_asic_base + _3COM_CR);
  149. #endif
  150. if (eth_flags & FLAG_16BIT)
  151. cnt >>= 1;
  152. while(cnt--)
  153. {
  154. #ifdef INCLUDE_3C503
  155. while((inb(eth_asic_base + _3COM_STREG) & _3COM_STREG_DPRDY) == 0)
  156. ;
  157. #endif
  158. if (eth_flags & FLAG_16BIT) {
  159. outw(*((unsigned short *)src), eth_asic_base + ASIC_PIO);
  160. src += 2;
  161. }
  162. else
  163. outb(*(src++), eth_asic_base + ASIC_PIO);
  164. }
  165. #ifdef INCLUDE_3C503
  166. outb(t503_output, eth_asic_base + _3COM_CR);
  167. #else
  168. #ifdef COMPEX_RL2000_FIX
  169. for (x = 0;
  170. x < COMPEX_RL2000_TRIES &&
  171. (inb(eth_nic_base + D8390_P0_ISR) & D8390_ISR_RDC)
  172. != D8390_ISR_RDC;
  173. ++x);
  174. if (x >= COMPEX_RL2000_TRIES)
  175. printf("Warning: Compex RL2000 aborted wait!\n");
  176. #endif /* COMPEX_RL2000_FIX */
  177. while((inb(eth_nic_base + D8390_P0_ISR) & D8390_ISR_RDC)
  178. != D8390_ISR_RDC);
  179. #endif
  180. }
  181. #else
  182. /**************************************************************************
  183. ETH_PIO_READ - Dummy routine when NE2000 not compiled in
  184. **************************************************************************/
  185. static void eth_pio_read(unsigned int src, unsigned char *dst, unsigned int cnt) {}
  186. #endif
  187. /**************************************************************************
  188. NS8390_RESET - Reset adapter
  189. **************************************************************************/
  190. static void ns8390_reset(struct nic *nic)
  191. {
  192. int i;
  193. eth_drain_receiver = 0;
  194. #ifdef INCLUDE_WD
  195. if (eth_flags & FLAG_790)
  196. outb(D8390_COMMAND_PS0 | D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
  197. else
  198. #endif
  199. outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 |
  200. D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
  201. if (eth_flags & FLAG_16BIT)
  202. outb(0x49, eth_nic_base+D8390_P0_DCR);
  203. else
  204. outb(0x48, eth_nic_base+D8390_P0_DCR);
  205. outb(0, eth_nic_base+D8390_P0_RBCR0);
  206. outb(0, eth_nic_base+D8390_P0_RBCR1);
  207. outb(0x20, eth_nic_base+D8390_P0_RCR); /* monitor mode */
  208. outb(2, eth_nic_base+D8390_P0_TCR);
  209. outb(eth_tx_start, eth_nic_base+D8390_P0_TPSR);
  210. outb(eth_rx_start, eth_nic_base+D8390_P0_PSTART);
  211. #ifdef INCLUDE_WD
  212. if (eth_flags & FLAG_790) outb(0, eth_nic_base + 0x09);
  213. #endif
  214. outb(eth_memsize, eth_nic_base+D8390_P0_PSTOP);
  215. outb(eth_memsize - 1, eth_nic_base+D8390_P0_BOUND);
  216. outb(0xFF, eth_nic_base+D8390_P0_ISR);
  217. outb(0, eth_nic_base+D8390_P0_IMR);
  218. #ifdef INCLUDE_WD
  219. if (eth_flags & FLAG_790)
  220. outb(D8390_COMMAND_PS1 |
  221. D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
  222. else
  223. #endif
  224. outb(D8390_COMMAND_PS1 |
  225. D8390_COMMAND_RD2 | D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
  226. for (i=0; i<ETH_ALEN; i++)
  227. outb(nic->node_addr[i], eth_nic_base+D8390_P1_PAR0+i);
  228. for (i=0; i<ETH_ALEN; i++)
  229. outb(0xFF, eth_nic_base+D8390_P1_MAR0+i);
  230. outb(eth_rx_start, eth_nic_base+D8390_P1_CURR);
  231. #ifdef INCLUDE_WD
  232. if (eth_flags & FLAG_790)
  233. outb(D8390_COMMAND_PS0 |
  234. D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
  235. else
  236. #endif
  237. outb(D8390_COMMAND_PS0 |
  238. D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
  239. outb(0xFF, eth_nic_base+D8390_P0_ISR);
  240. outb(0, eth_nic_base+D8390_P0_TCR);
  241. outb(4, eth_nic_base+D8390_P0_RCR); /* allow broadcast frames */
  242. #ifdef INCLUDE_3C503
  243. /*
  244. * No way to tell whether or not we're supposed to use
  245. * the 3Com's transceiver unless the user tells us.
  246. * 'flags' should have some compile time default value
  247. * which can be changed from the command menu.
  248. */
  249. t503_output = (nic->flags) ? 0 : _3COM_CR_XSEL;
  250. outb(t503_output, eth_asic_base + _3COM_CR);
  251. #endif
  252. }
  253. static int ns8390_poll(struct nic *nic);
  254. #ifndef INCLUDE_3C503
  255. /**************************************************************************
  256. ETH_RX_OVERRUN - Bring adapter back to work after an RX overrun
  257. **************************************************************************/
  258. static void eth_rx_overrun(struct nic *nic)
  259. {
  260. int start_time;
  261. #ifdef INCLUDE_WD
  262. if (eth_flags & FLAG_790)
  263. outb(D8390_COMMAND_PS0 | D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
  264. else
  265. #endif
  266. outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 |
  267. D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
  268. /* wait for at least 1.6ms - we wait one timer tick */
  269. start_time = currticks();
  270. while (currticks() - start_time <= 1)
  271. /* Nothing */;
  272. outb(0, eth_nic_base+D8390_P0_RBCR0); /* reset byte counter */
  273. outb(0, eth_nic_base+D8390_P0_RBCR1);
  274. /*
  275. * Linux driver checks for interrupted TX here. This is not necessary,
  276. * because the transmit routine waits until the frame is sent.
  277. */
  278. /* enter loopback mode and restart NIC */
  279. outb(2, eth_nic_base+D8390_P0_TCR);
  280. #ifdef INCLUDE_WD
  281. if (eth_flags & FLAG_790)
  282. outb(D8390_COMMAND_PS0 | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
  283. else
  284. #endif
  285. outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 |
  286. D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
  287. /* clear the RX ring, acknowledge overrun interrupt */
  288. eth_drain_receiver = 1;
  289. while (ns8390_poll(nic))
  290. /* Nothing */;
  291. eth_drain_receiver = 0;
  292. outb(D8390_ISR_OVW, eth_nic_base+D8390_P0_ISR);
  293. /* leave loopback mode - no packets to be resent (see Linux driver) */
  294. outb(0, eth_nic_base+D8390_P0_TCR);
  295. }
  296. #endif /* INCLUDE_3C503 */
  297. /**************************************************************************
  298. NS8390_TRANSMIT - Transmit a frame
  299. **************************************************************************/
  300. static void ns8390_transmit(
  301. struct nic *nic,
  302. const char *d, /* Destination */
  303. unsigned int t, /* Type */
  304. unsigned int s, /* size */
  305. const char *p) /* Packet */
  306. {
  307. #ifdef INCLUDE_3C503
  308. if (!(eth_flags & FLAG_PIO)) {
  309. memcpy((char *)eth_bmem, d, ETH_ALEN); /* dst */
  310. memcpy((char *)eth_bmem+ETH_ALEN, nic->node_addr, ETH_ALEN); /* src */
  311. *((char *)eth_bmem+12) = t>>8; /* type */
  312. *((char *)eth_bmem+13) = t;
  313. memcpy((char *)eth_bmem+ETH_HLEN, p, s);
  314. s += ETH_HLEN;
  315. while (s < ETH_ZLEN) *((char *)eth_bmem+(s++)) = 0;
  316. }
  317. #endif
  318. #ifdef INCLUDE_WD
  319. /* Memory interface */
  320. if (eth_flags & FLAG_16BIT) {
  321. outb(eth_laar | WD_LAAR_M16EN, eth_asic_base + WD_LAAR);
  322. inb(0x84);
  323. }
  324. if (eth_flags & FLAG_790) {
  325. outb(WD_MSR_MENB, eth_asic_base + WD_MSR);
  326. inb(0x84);
  327. }
  328. inb(0x84);
  329. memcpy((char *)eth_bmem, d, ETH_ALEN); /* dst */
  330. memcpy((char *)eth_bmem+ETH_ALEN, nic->node_addr, ETH_ALEN); /* src */
  331. *((char *)eth_bmem+12) = t>>8; /* type */
  332. *((char *)eth_bmem+13) = t;
  333. memcpy((char *)eth_bmem+ETH_HLEN, p, s);
  334. s += ETH_HLEN;
  335. while (s < ETH_ZLEN) *((char *)eth_bmem+(s++)) = 0;
  336. if (eth_flags & FLAG_790) {
  337. outb(0, eth_asic_base + WD_MSR);
  338. inb(0x84);
  339. }
  340. if (eth_flags & FLAG_16BIT) {
  341. outb(eth_laar & ~WD_LAAR_M16EN, eth_asic_base + WD_LAAR);
  342. inb(0x84);
  343. }
  344. #endif
  345. #if defined(INCLUDE_3C503)
  346. if (eth_flags & FLAG_PIO) {
  347. #endif
  348. #if defined(INCLUDE_NE) || defined(INCLUDE_NS8390) || (defined(INCLUDE_3C503) && !defined(T503_SHMEM))
  349. /* Programmed I/O */
  350. unsigned short type;
  351. type = (t >> 8) | (t << 8);
  352. eth_pio_write(d, eth_tx_start<<8, ETH_ALEN);
  353. eth_pio_write(nic->node_addr, (eth_tx_start<<8)+ETH_ALEN, ETH_ALEN);
  354. /* bcc generates worse code without (const+const) below */
  355. eth_pio_write((unsigned char *)&type, (eth_tx_start<<8)+(ETH_ALEN+ETH_ALEN), 2);
  356. eth_pio_write(p, (eth_tx_start<<8)+ETH_HLEN, s);
  357. s += ETH_HLEN;
  358. if (s < ETH_ZLEN) s = ETH_ZLEN;
  359. #endif
  360. #if defined(INCLUDE_3C503)
  361. }
  362. #endif
  363. #ifdef INCLUDE_WD
  364. if (eth_flags & FLAG_790)
  365. outb(D8390_COMMAND_PS0 |
  366. D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
  367. else
  368. #endif
  369. outb(D8390_COMMAND_PS0 |
  370. D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
  371. outb(eth_tx_start, eth_nic_base+D8390_P0_TPSR);
  372. outb(s, eth_nic_base+D8390_P0_TBCR0);
  373. outb(s>>8, eth_nic_base+D8390_P0_TBCR1);
  374. #ifdef INCLUDE_WD
  375. if (eth_flags & FLAG_790)
  376. outb(D8390_COMMAND_PS0 |
  377. D8390_COMMAND_TXP | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
  378. else
  379. #endif
  380. outb(D8390_COMMAND_PS0 |
  381. D8390_COMMAND_TXP | D8390_COMMAND_RD2 |
  382. D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
  383. }
  384. /**************************************************************************
  385. NS8390_POLL - Wait for a frame
  386. **************************************************************************/
  387. static int ns8390_poll(struct nic *nic)
  388. {
  389. int ret = 0;
  390. unsigned char rstat, curr, next;
  391. unsigned short len, frag;
  392. unsigned short pktoff;
  393. unsigned char *p;
  394. struct ringbuffer pkthdr;
  395. #ifndef INCLUDE_3C503
  396. /* avoid infinite recursion: see eth_rx_overrun() */
  397. if (!eth_drain_receiver && (inb(eth_nic_base+D8390_P0_ISR) & D8390_ISR_OVW)) {
  398. eth_rx_overrun(nic);
  399. return(0);
  400. }
  401. #endif /* INCLUDE_3C503 */
  402. rstat = inb(eth_nic_base+D8390_P0_RSR);
  403. if (!(rstat & D8390_RSTAT_PRX)) return(0);
  404. next = inb(eth_nic_base+D8390_P0_BOUND)+1;
  405. if (next >= eth_memsize) next = eth_rx_start;
  406. outb(D8390_COMMAND_PS1, eth_nic_base+D8390_P0_COMMAND);
  407. curr = inb(eth_nic_base+D8390_P1_CURR);
  408. outb(D8390_COMMAND_PS0, eth_nic_base+D8390_P0_COMMAND);
  409. if (curr >= eth_memsize) curr=eth_rx_start;
  410. if (curr == next) return(0);
  411. #ifdef INCLUDE_WD
  412. if (eth_flags & FLAG_16BIT) {
  413. outb(eth_laar | WD_LAAR_M16EN, eth_asic_base + WD_LAAR);
  414. inb(0x84);
  415. }
  416. if (eth_flags & FLAG_790) {
  417. outb(WD_MSR_MENB, eth_asic_base + WD_MSR);
  418. inb(0x84);
  419. }
  420. inb(0x84);
  421. #endif
  422. pktoff = next << 8;
  423. if (eth_flags & FLAG_PIO)
  424. eth_pio_read(pktoff, (char *)&pkthdr, 4);
  425. else
  426. memcpy(&pkthdr, (char *)eth_rmem + pktoff, 4);
  427. pktoff += sizeof(pkthdr);
  428. /* incoming length includes FCS so must sub 4 */
  429. len = pkthdr.len - 4;
  430. if ((pkthdr.status & D8390_RSTAT_PRX) == 0 || len < ETH_ZLEN
  431. || len > ETH_FRAME_LEN) {
  432. printf("Bogus packet, ignoring\n");
  433. return (0);
  434. }
  435. else {
  436. p = nic->packet;
  437. nic->packetlen = len; /* available to caller */
  438. frag = (eth_memsize << 8) - pktoff;
  439. if (len > frag) { /* We have a wrap-around */
  440. /* read first part */
  441. if (eth_flags & FLAG_PIO)
  442. eth_pio_read(pktoff, p, frag);
  443. else
  444. memcpy(p, (char *)eth_rmem + pktoff, frag);
  445. pktoff = eth_rx_start << 8;
  446. p += frag;
  447. len -= frag;
  448. }
  449. /* read second part */
  450. if (eth_flags & FLAG_PIO)
  451. eth_pio_read(pktoff, p, len);
  452. else
  453. memcpy(p, (char *)eth_rmem + pktoff, len);
  454. ret = 1;
  455. }
  456. #ifdef INCLUDE_WD
  457. if (eth_flags & FLAG_790) {
  458. outb(0, eth_asic_base + WD_MSR);
  459. inb(0x84);
  460. }
  461. if (eth_flags & FLAG_16BIT) {
  462. outb(eth_laar & ~WD_LAAR_M16EN, eth_asic_base + WD_LAAR);
  463. inb(0x84);
  464. }
  465. inb(0x84);
  466. #endif
  467. next = pkthdr.next; /* frame number of next packet */
  468. if (next == eth_rx_start)
  469. next = eth_memsize;
  470. outb(next-1, eth_nic_base+D8390_P0_BOUND);
  471. return(ret);
  472. }
  473. /**************************************************************************
  474. NS8390_DISABLE - Turn off adapter
  475. **************************************************************************/
  476. static void ns8390_disable(struct nic *nic)
  477. {
  478. }
  479. /**************************************************************************
  480. ETH_PROBE - Look for an adapter
  481. **************************************************************************/
  482. #ifdef INCLUDE_NS8390
  483. struct nic *eth_probe(struct nic *nic, unsigned short *probe_addrs,
  484. struct pci_device *pci)
  485. #else
  486. struct nic *eth_probe(struct nic *nic, unsigned short *probe_addrs)
  487. #endif
  488. {
  489. int i;
  490. struct wd_board *brd;
  491. unsigned short chksum;
  492. unsigned char c;
  493. eth_vendor = VENDOR_NONE;
  494. eth_drain_receiver = 0;
  495. #ifdef INCLUDE_WD
  496. /******************************************************************
  497. Search for WD/SMC cards
  498. ******************************************************************/
  499. for (eth_asic_base = WD_LOW_BASE; eth_asic_base <= WD_HIGH_BASE;
  500. eth_asic_base += 0x20) {
  501. chksum = 0;
  502. for (i=8; i<16; i++)
  503. chksum += inb(eth_asic_base+i);
  504. /* Extra checks to avoid soundcard */
  505. if ((chksum & 0xFF) == 0xFF &&
  506. inb(eth_asic_base+8) != 0xFF &&
  507. inb(eth_asic_base+9) != 0xFF)
  508. break;
  509. }
  510. if (eth_asic_base > WD_HIGH_BASE)
  511. return (0);
  512. /* We've found a board */
  513. eth_vendor = VENDOR_WD;
  514. eth_nic_base = eth_asic_base + WD_NIC_ADDR;
  515. c = inb(eth_asic_base+WD_BID); /* Get board id */
  516. for (brd = wd_boards; brd->name; brd++)
  517. if (brd->id == c) break;
  518. if (!brd->name) {
  519. printf("Unknown WD/SMC NIC type %hhX\n", c);
  520. return (0); /* Unknown type */
  521. }
  522. eth_flags = brd->flags;
  523. eth_memsize = brd->memsize;
  524. eth_tx_start = 0;
  525. eth_rx_start = D8390_TXBUF_SIZE;
  526. if ((c == TYPE_WD8013EP) &&
  527. (inb(eth_asic_base + WD_ICR) & WD_ICR_16BIT)) {
  528. eth_flags = FLAG_16BIT;
  529. eth_memsize = MEM_16384;
  530. }
  531. if ((c & WD_SOFTCONFIG) && (!(eth_flags & FLAG_790))) {
  532. eth_bmem = (0x80000 |
  533. ((inb(eth_asic_base + WD_MSR) & 0x3F) << 13));
  534. } else
  535. eth_bmem = WD_DEFAULT_MEM;
  536. if (brd->id == TYPE_SMC8216T || brd->id == TYPE_SMC8216C) {
  537. *((unsigned int *)(eth_bmem + 8192)) = (unsigned int)0;
  538. if (*((unsigned int *)(eth_bmem + 8192))) {
  539. brd += 2;
  540. eth_memsize = brd->memsize;
  541. }
  542. }
  543. outb(0x80, eth_asic_base + WD_MSR); /* Reset */
  544. for (i=0; i<ETH_ALEN; i++) {
  545. nic->node_addr[i] = inb(i+eth_asic_base+WD_LAR);
  546. }
  547. printf("\n%s base %#hx, memory %#hx, addr %!\n",
  548. brd->name, eth_asic_base, eth_bmem, nic->node_addr);
  549. if (eth_flags & FLAG_790) {
  550. outb(WD_MSR_MENB, eth_asic_base+WD_MSR);
  551. outb((inb(eth_asic_base+0x04) |
  552. 0x80), eth_asic_base+0x04);
  553. outb((((unsigned)eth_bmem >> 13) & 0x0F) |
  554. (((unsigned)eth_bmem >> 11) & 0x40) |
  555. (inb(eth_asic_base+0x0B) & 0xB0), eth_asic_base+0x0B);
  556. outb((inb(eth_asic_base+0x04) &
  557. ~0x80), eth_asic_base+0x04);
  558. } else {
  559. outb((((unsigned)eth_bmem >> 13) & 0x3F) | 0x40, eth_asic_base+WD_MSR);
  560. }
  561. if (eth_flags & FLAG_16BIT) {
  562. if (eth_flags & FLAG_790) {
  563. eth_laar = inb(eth_asic_base + WD_LAAR);
  564. outb(WD_LAAR_M16EN, eth_asic_base + WD_LAAR);
  565. } else {
  566. outb((eth_laar =
  567. WD_LAAR_L16EN | 1), eth_asic_base + WD_LAAR);
  568. /*
  569. The previous line used to be
  570. WD_LAAR_M16EN | WD_LAAR_L16EN | 1));
  571. jluke@deakin.edu.au reported that removing WD_LAAR_M16EN made
  572. it work for WD8013s. This seems to work for my 8013 boards. I
  573. don't know what is really happening. I wish I had data sheets
  574. or more time to decode the Linux driver. - Ken
  575. */
  576. }
  577. inb(0x84);
  578. }
  579. #endif
  580. #ifdef INCLUDE_3C503
  581. /******************************************************************
  582. Search for 3Com 3c503 if no WD/SMC cards
  583. ******************************************************************/
  584. if (eth_vendor == VENDOR_NONE) {
  585. int idx;
  586. int iobase_reg, membase_reg;
  587. static unsigned short base[] = {
  588. 0x300, 0x310, 0x330, 0x350,
  589. 0x250, 0x280, 0x2A0, 0x2E0, 0 };
  590. /* Loop through possible addresses checking each one */
  591. for (idx = 0; (eth_nic_base = base[idx]) != 0; ++idx) {
  592. eth_asic_base = eth_nic_base + _3COM_ASIC_OFFSET;
  593. /*
  594. * Note that we use the same settings for both 8 and 16 bit cards:
  595. * both have an 8K bank of memory at page 1 while only the 16 bit
  596. * cards have a bank at page 0.
  597. */
  598. eth_memsize = MEM_16384;
  599. eth_tx_start = 32;
  600. eth_rx_start = 32 + D8390_TXBUF_SIZE;
  601. /* Check our base address. iobase and membase should */
  602. /* both have a maximum of 1 bit set or be 0. */
  603. iobase_reg = inb(eth_asic_base + _3COM_BCFR);
  604. membase_reg = inb(eth_asic_base + _3COM_PCFR);
  605. if ((iobase_reg & (iobase_reg - 1)) ||
  606. (membase_reg & (membase_reg - 1)))
  607. continue; /* nope */
  608. /* Now get the shared memory address */
  609. eth_flags = 0;
  610. switch (membase_reg) {
  611. case _3COM_PCFR_DC000:
  612. eth_bmem = 0xdc000;
  613. break;
  614. case _3COM_PCFR_D8000:
  615. eth_bmem = 0xd8000;
  616. break;
  617. case _3COM_PCFR_CC000:
  618. eth_bmem = 0xcc000;
  619. break;
  620. case _3COM_PCFR_C8000:
  621. eth_bmem = 0xc8000;
  622. break;
  623. case _3COM_PCFR_PIO:
  624. eth_flags |= FLAG_PIO;
  625. eth_bmem = 0;
  626. break;
  627. default:
  628. continue; /* nope */
  629. }
  630. break;
  631. }
  632. if (base[idx] == 0) /* not found */
  633. return (0);
  634. #ifndef T503_SHMEM
  635. eth_flags |= FLAG_PIO; /* force PIO mode */
  636. eth_bmem = 0;
  637. #endif
  638. eth_vendor = VENDOR_3COM;
  639. /* Need this to make ns8390_poll() happy. */
  640. eth_rmem = eth_bmem - 0x2000;
  641. /* Reset NIC and ASIC */
  642. outb(_3COM_CR_RST | _3COM_CR_XSEL, eth_asic_base + _3COM_CR );
  643. outb(_3COM_CR_XSEL, eth_asic_base + _3COM_CR );
  644. /* Get our ethernet address */
  645. outb(_3COM_CR_EALO | _3COM_CR_XSEL, eth_asic_base + _3COM_CR);
  646. printf("\n3Com 3c503 base %#hx, ", eth_nic_base);
  647. if (eth_flags & FLAG_PIO)
  648. printf("PIO mode");
  649. else
  650. printf("memory %#hx", eth_bmem);
  651. for (i=0; i<ETH_ALEN; i++) {
  652. nic->node_addr[i] = inb(eth_nic_base+i);
  653. }
  654. printf(", %s, addr %!\n", nic->flags ? "AUI" : "internal xcvr",
  655. nic->node_addr);
  656. outb(_3COM_CR_XSEL, eth_asic_base + _3COM_CR);
  657. /*
  658. * Initialize GA configuration register. Set bank and enable shared
  659. * mem. We always use bank 1. Disable interrupts.
  660. */
  661. outb(_3COM_GACFR_RSEL |
  662. _3COM_GACFR_MBS0 | _3COM_GACFR_TCM | _3COM_GACFR_NIM, eth_asic_base + _3COM_GACFR);
  663. outb(0xff, eth_asic_base + _3COM_VPTR2);
  664. outb(0xff, eth_asic_base + _3COM_VPTR1);
  665. outb(0x00, eth_asic_base + _3COM_VPTR0);
  666. /*
  667. * Clear memory and verify that it worked (we use only 8K)
  668. */
  669. if (!(eth_flags & FLAG_PIO)) {
  670. memset((char *)eth_bmem, 0, 0x2000);
  671. for(i = 0; i < 0x2000; ++i)
  672. if (*(((char *)eth_bmem)+i)) {
  673. printf ("Failed to clear 3c503 shared mem.\n");
  674. return (0);
  675. }
  676. }
  677. /*
  678. * Initialize GA page/start/stop registers.
  679. */
  680. outb(eth_tx_start, eth_asic_base + _3COM_PSTR);
  681. outb(eth_memsize, eth_asic_base + _3COM_PSPR);
  682. }
  683. #endif
  684. #if defined(INCLUDE_NE) || defined(INCLUDE_NS8390)
  685. /******************************************************************
  686. Search for NE1000/2000 if no WD/SMC or 3com cards
  687. ******************************************************************/
  688. if (eth_vendor == VENDOR_NONE) {
  689. char romdata[16], testbuf[32];
  690. int idx;
  691. static char test[] = "NE*000 memory";
  692. static unsigned short base[] = {
  693. #ifdef NE_SCAN
  694. NE_SCAN,
  695. #endif
  696. 0 };
  697. /* if no addresses supplied, fall back on defaults */
  698. if (probe_addrs == 0 || probe_addrs[0] == 0)
  699. probe_addrs = base;
  700. eth_bmem = 0; /* No shared memory */
  701. for (idx = 0; (eth_nic_base = probe_addrs[idx]) != 0; ++idx) {
  702. eth_flags = FLAG_PIO;
  703. eth_asic_base = eth_nic_base + NE_ASIC_OFFSET;
  704. eth_memsize = MEM_16384;
  705. eth_tx_start = 32;
  706. eth_rx_start = 32 + D8390_TXBUF_SIZE;
  707. c = inb(eth_asic_base + NE_RESET);
  708. outb(c, eth_asic_base + NE_RESET);
  709. inb(0x84);
  710. outb(D8390_COMMAND_STP |
  711. D8390_COMMAND_RD2, eth_nic_base + D8390_P0_COMMAND);
  712. outb(D8390_RCR_MON, eth_nic_base + D8390_P0_RCR);
  713. outb(D8390_DCR_FT1 | D8390_DCR_LS, eth_nic_base + D8390_P0_DCR);
  714. outb(MEM_8192, eth_nic_base + D8390_P0_PSTART);
  715. outb(MEM_16384, eth_nic_base + D8390_P0_PSTOP);
  716. #ifdef NS8390_FORCE_16BIT
  717. eth_flags |= FLAG_16BIT; /* force 16-bit mode */
  718. #endif
  719. eth_pio_write(test, 8192, sizeof(test));
  720. eth_pio_read(8192, testbuf, sizeof(test));
  721. if (!memcmp(test, testbuf, sizeof(test)))
  722. break;
  723. eth_flags |= FLAG_16BIT;
  724. eth_memsize = MEM_32768;
  725. eth_tx_start = 64;
  726. eth_rx_start = 64 + D8390_TXBUF_SIZE;
  727. outb(D8390_DCR_WTS |
  728. D8390_DCR_FT1 | D8390_DCR_LS, eth_nic_base + D8390_P0_DCR);
  729. outb(MEM_16384, eth_nic_base + D8390_P0_PSTART);
  730. outb(MEM_32768, eth_nic_base + D8390_P0_PSTOP);
  731. eth_pio_write(test, 16384, sizeof(test));
  732. eth_pio_read(16384, testbuf, sizeof(test));
  733. if (!memcmp(testbuf, test, sizeof(test)))
  734. break;
  735. }
  736. if (eth_nic_base == 0)
  737. return (0);
  738. if (eth_nic_base > ISA_MAX_ADDR) /* PCI probably */
  739. eth_flags |= FLAG_16BIT;
  740. eth_vendor = VENDOR_NOVELL;
  741. eth_pio_read(0, romdata, sizeof(romdata));
  742. for (i=0; i<ETH_ALEN; i++) {
  743. nic->node_addr[i] = romdata[i + ((eth_flags & FLAG_16BIT) ? i : 0)];
  744. }
  745. printf("\nNE%c000 base %#hx, addr %!\n",
  746. (eth_flags & FLAG_16BIT) ? '2' : '1', eth_nic_base,
  747. nic->node_addr);
  748. }
  749. #endif
  750. if (eth_vendor == VENDOR_NONE)
  751. return(0);
  752. if (eth_vendor != VENDOR_3COM)
  753. eth_rmem = eth_bmem;
  754. ns8390_reset(nic);
  755. nic->reset = ns8390_reset;
  756. nic->poll = ns8390_poll;
  757. nic->transmit = ns8390_transmit;
  758. nic->disable = ns8390_disable;
  759. return(nic);
  760. }
  761. /*
  762. * Local variables:
  763. * c-basic-offset: 8
  764. * End:
  765. */