ax88796.c 28 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003
  1. /*
  2. * Copyright (C) 2003-2005 by egnite Software GmbH. All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. *
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. * 3. Neither the name of the copyright holders nor the names of
  14. * contributors may be used to endorse or promote products derived
  15. * from this software without specific prior written permission.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  18. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  19. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  20. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  21. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  22. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  23. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  24. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  25. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  26. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  27. * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  28. * SUCH DAMAGE.
  29. *
  30. * For additional information see http://www.ethernut.de/
  31. *
  32. * --
  33. * Initially taken from Marek Hummel's port of the Realtek driver.
  34. *
  35. * Revision 1.0 2004/07/20 17:29:08 MarekH
  36. */
  37. /*
  38. * $Log$
  39. * Revision 1.9 2009/01/17 11:26:37 haraldkipp
  40. * Getting rid of two remaining BSD types in favor of stdint.
  41. * Replaced 'u_int' by 'unsinged int' and 'uptr_t' by 'uintptr_t'.
  42. *
  43. * Revision 1.8 2008/08/28 11:12:15 haraldkipp
  44. * Added interface flags, which will be required to implement Ethernet ioctl
  45. * functions.
  46. *
  47. * Revision 1.7 2008/08/11 06:59:07 haraldkipp
  48. * BSD types replaced by stdint types (feature request #1282721).
  49. *
  50. * Revision 1.6 2007/05/02 11:22:51 haraldkipp
  51. * Added multicast table entry.
  52. *
  53. * Revision 1.5 2006/06/28 17:10:15 haraldkipp
  54. * Include more general header file for ARM.
  55. *
  56. * Revision 1.4 2006/03/02 19:48:19 haraldkipp
  57. * Replaced inline assembly nops with their portable counterparts.
  58. *
  59. * Revision 1.3 2006/01/23 17:27:47 haraldkipp
  60. * Previous hack to fix missing network configuration routines disabled
  61. * non-volatile memory access for ARM.
  62. *
  63. * Revision 1.2 2005/10/22 08:55:47 haraldkipp
  64. * CPU specific headers moved to subdirectories for the CPU family.
  65. *
  66. * Revision 1.1 2005/07/26 18:02:26 haraldkipp
  67. * Moved from dev.
  68. *
  69. * Revision 1.1 2005/04/05 17:47:48 haraldkipp
  70. * Initial check in. For ARM only.
  71. *
  72. */
  73. #include <arch/arm.h>
  74. #include <string.h>
  75. //#include <stdio.h>
  76. #include <sys/atom.h>
  77. #include <sys/heap.h>
  78. #include <sys/thread.h>
  79. #include <sys/event.h>
  80. #include <sys/timer.h>
  81. #include <sys/confnet.h>
  82. #include <dev/irqreg.h>
  83. #include <dev/ax88796.h>
  84. #include "reg_ax88796.h"
  85. #define ASIX_RESET_PIN 10
  86. static NICINFO dcb_eth0;
  87. /*!
  88. * \addtogroup xgNicAsix
  89. */
  90. /*@{*/
  91. /*!
  92. * \brief Network interface information structure.
  93. *
  94. * Used to call.
  95. */
  96. static IFNET ifn_eth0 = {
  97. IFT_ETHER, /*!< \brief Interface type. */
  98. 0, /*!< \brief Interface flags, if_flags. */
  99. {0, 0, 0, 0, 0, 0}, /*!< \brief Hardware net address. */
  100. 0, /*!< \brief IP address. */
  101. 0, /*!< \brief Remote IP address for point to point. */
  102. 0, /*!< \brief IP network mask. */
  103. ETHERMTU, /*!< \brief Maximum size of a transmission unit. */
  104. 0, /*!< \brief Packet identifier. */
  105. 0, /*!< \brief Linked list of arp entries. */
  106. 0, /*!< \brief Linked list of multicast address entries, if_mcast. */
  107. NutEtherInput, /*!< \brief Routine to pass received data to, if_recv(). */
  108. AsixOutput, /*!< \brief Driver output routine, if_send(). */
  109. NutEtherOutput, /*!< \brief Media output routine, if_output(). */
  110. NULL /*!< \brief Interface specific control function, if_ioctl(). */
  111. #ifdef NUT_PERFMON
  112. , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
  113. #endif
  114. };
  115. /*!
  116. * \brief Device information structure.
  117. *
  118. * A pointer to this structure must be passed to NutRegisterDevice()
  119. * to bind this Ethernet device driver to the Nut/OS kernel.
  120. * An application may then call NutNetIfConfig() with the name \em eth0
  121. * of this driver to initialize the network interface.
  122. *
  123. */
  124. NUTDEVICE devAx88796 = {
  125. 0, /* Pointer to next device. */
  126. {'e', 't', 'h', '0', 0, 0, 0, 0, 0}, /* Unique device name. */
  127. IFTYP_NET, /* Type of device. */
  128. 0, /* Base address. */
  129. 0, /* First interrupt number. */
  130. &ifn_eth0, /* Interface control block. */
  131. &dcb_eth0, /* Driver control block. */
  132. AsixInit, /* Driver initialization routine. */
  133. 0, /* Driver specific control function. */
  134. 0, /* Read from device. */
  135. 0, /* Write to device. */
  136. 0, /* Open a device or file. */
  137. 0, /* Close a device or file. */
  138. 0, /* Request file size. */
  139. 0, /* Select function, optional, not yet implemented */
  140. };
  141. /*!
  142. * Asix packet header.
  143. */
  144. struct nic_pkt_header {
  145. uint8_t ph_status; /*!< \brief Status, contents of RSR register */
  146. uint8_t ph_nextpg; /*!< \brief Page for next packet */
  147. uint16_t ph_size; /*!< \brief Size of header and packet in octets */
  148. };
  149. /*
  150. * This delay has been added by Bengt Florin and is used to minimize
  151. * the effect of the IORDY line during reads. Bengt contributed a
  152. * more versatile loop, which unfortunately wasn't portable to the
  153. * ImageCraft compiler.
  154. *
  155. * Both versions depend on the CPU clock and had been tested with
  156. * 14.7456 MHz.
  157. */
  158. void Delay16Cycles(void)
  159. {
  160. _NOP();
  161. _NOP();
  162. _NOP();
  163. _NOP();
  164. _NOP();
  165. _NOP();
  166. _NOP();
  167. _NOP();
  168. _NOP();
  169. _NOP();
  170. _NOP();
  171. _NOP();
  172. _NOP();
  173. _NOP();
  174. _NOP();
  175. _NOP();
  176. }
  177. //==============================================================================
  178. /*!
  179. * \brief Read and write MII bus.
  180. *
  181. *
  182. */
  183. static uint16_t MIIPutGet(uint16_t data, uint8_t bitCount)
  184. {
  185. uint16_t rc = 0;
  186. uint16_t mask;
  187. uint8_t i;
  188. mask = 1 << (bitCount - 1);
  189. for (i = 0; i < bitCount; i++) {
  190. /* send data to MII */
  191. if (data & mask) {
  192. Asix_Write(MII_EEP, (Asix_Read(MII_EEP) | MII_EEP_MDO));
  193. } else {
  194. Asix_Write(MII_EEP, (Asix_Read(MII_EEP) & ~(MII_EEP_MDO)));
  195. }
  196. /* clock and data recieve from MII */
  197. Asix_Write(MII_EEP, (Asix_Read(MII_EEP) | MII_EEP_MDC)); //clock up
  198. Delay16Cycles();
  199. data <<= 1;
  200. rc <<= 1;
  201. rc |= (Asix_Read(MII_EEP) & MII_EEP_MDI) != 0; //read MII
  202. Asix_Write(MII_EEP, (Asix_Read(MII_EEP) & ~(MII_EEP_MDC))); //clock down
  203. }
  204. return rc;
  205. }
  206. //==============================================================================
  207. /*!
  208. * \brief Read contents of internel PHY register on 0x10 adress.
  209. *
  210. *
  211. * \return Contents of the specified register.
  212. */
  213. uint16_t NicPhyRead(uint8_t reg)
  214. {
  215. uint16_t rc = 0;
  216. /* Select Bank 0. */
  217. Asix_Write(CR, (Asix_Read(CR) & ~(CR_PS0)));
  218. /* Preamble. Send idle pattern, 32 '1's to synchronize MII. */
  219. MIIPutGet(0xFFFF, 16);
  220. MIIPutGet(0xFFFF, 16);
  221. /* Start(01), Read(10), PhyAdr(10000) */
  222. MIIPutGet(0xD0, 9);
  223. /* Reg address<5:0> */
  224. MIIPutGet(reg, 5);
  225. /* TA(Z0), no support high-Z */
  226. MIIPutGet(0x0, 1);
  227. /* Read data from internel PHY */
  228. rc = MIIPutGet(0, 16);
  229. return rc;
  230. }
  231. //==============================================================================
  232. /*!
  233. * \brief Write value to PHY register.
  234. *
  235. * \note NIC interrupts must have been disabled before calling this routine.
  236. *
  237. * \param reg PHY register number.
  238. * \param val Value to write.
  239. */
  240. void NicPhyWrite(uint8_t reg, uint16_t val)
  241. {
  242. /* Select Bank 0. */
  243. Asix_Write(CR, (Asix_Read(CR) & ~(CR_PS0)));
  244. /* Preamble. Send idle pattern, 32 '1's to synchronize MII. */
  245. MIIPutGet(0xFFFF, 16);
  246. MIIPutGet(0xFFFF, 16);
  247. /* Start(01), Write(01), PhyAdr(10000) */
  248. MIIPutGet(0xB0, 9);
  249. /* Reg address<5:0> */
  250. MIIPutGet(reg, 5);
  251. /* TA(01) */
  252. MIIPutGet(0x02, 2);
  253. /* Write data to internel PHY */
  254. MIIPutGet(val, 16);
  255. }
  256. //==============================================================================
  257. /*!
  258. * Complete remote DMA.
  259. */
  260. static void NicCompleteDma(void)
  261. {
  262. uint8_t i;
  263. /* Check that we have a DMA complete flag. */
  264. do {
  265. i = Asix_Read(PG0_ISR);
  266. } while ((i & ISR_RDC) == 0);
  267. /* Complete remote dma. */
  268. Asix_Write(CR, CR_START | CR_RD2);
  269. /* Reset remote dma complete flag. */
  270. Asix_Write(PG0_ISR, ISR_RDC);
  271. /* Wait for intterupt flag. */
  272. Delay16Cycles();
  273. }
  274. //==============================================================================
  275. /*!
  276. * \brief Reset the Ethernet controller.
  277. *
  278. * \return 0 on success, -1 otherwise.
  279. */
  280. static int NicReset(void)
  281. {
  282. int tmp;
  283. //uint16_t test;
  284. //printf("NicReset()\n");
  285. outr(PIO_PER, _BV(ASIX_RESET_PIN)); /* Set PIO Enable Register */
  286. outr(PIO_OER, _BV(ASIX_RESET_PIN)); /* Set PIO Status Register */
  287. outr(PIO_SODR, _BV(ASIX_RESET_PIN)); /* ASIX_RESET_PIN = 1 */
  288. NutDelay(100);
  289. outr(PIO_CODR, _BV(ASIX_RESET_PIN)); /* ASIX_RESET_PIN = 0 */
  290. /* wait for PHY to come out of reset. */
  291. tmp = 10;
  292. while (1) {
  293. NutDelay(255);
  294. if (!(Asix_Read(TR) & TR_RST_B))
  295. break;
  296. if (tmp-- == 0)
  297. return -1;
  298. }
  299. //test = NicPhyRead(PHY_MR2);
  300. //printf("PHY_MR2 = 0x%.04x\n\r", test);
  301. //test = NicPhyRead(PHY_MR3);
  302. //printf("PHY_MR3 = 0x%.04x\n\r", test);
  303. /* Following actions will fix the problem of long auto negotiation. */
  304. // NicPhyWrite(0x00,0x0800);
  305. // NutSleep(2500);
  306. // NicPhyWrite(0x00,0x1200); /* set speed to auto */
  307. return 0;
  308. }
  309. //==============================================================================
  310. /*
  311. * Fires up the network interface. NIC interrupts
  312. * should have been disabled when calling this
  313. * function.
  314. *
  315. * \param mac Six byte unique MAC address.
  316. */
  317. static int NicStart(const uint8_t * mac)
  318. {
  319. uint8_t i;
  320. //printf("NicStart()\n");
  321. if (NicReset())
  322. return -1;
  323. /* Stop the NIC, abort DMA, page 0. */
  324. Asix_Write(CR, (CR_RD2 | CR_STOP));
  325. /* Selects word-wide DMA transfers. */
  326. Asix_Write(PG0_DCR, DCR_WTS);
  327. /* Load data byte count for remote DMA. */
  328. Asix_Write(PG0_RBCR0, 0x00);
  329. Asix_Write(PG0_RBCR1, 0x00);
  330. /* Temporarily set receiver to monitor mode. */
  331. Asix_Write(PG0_RCR, RCR_MON);
  332. /* Transmitter set to internal loopback mode. */
  333. Asix_Write(PG0_TCR, TCR_LB0);
  334. /* Initialize Recieve Buffer Ring. */
  335. Asix_Write(PG0_BNRY, RXSTART_INIT);
  336. Asix_Write(PG0_PSTART, RXSTART_INIT);
  337. Asix_Write(PG0_PSTOP, RXSTOP_INIT);
  338. /* Clear interrupt status. */
  339. Asix_Write(PG0_ISR, 0xFF);
  340. /* Initialize interrupt mask. */
  341. Asix_Write(PG0_IMR, IMR_PRXE | IMR_PTXE | IMR_RXEE | IMR_TXEE | IMR_OVWE);
  342. /* Stop the NIC, abort DMA, page 1. */
  343. Asix_Write(CR, (CR_PS0 | CR_RD2 | CR_STOP));
  344. Delay16Cycles();
  345. /* Set Physical address - MAC. */
  346. for (i = 0; i < 6; i++) {
  347. Asix_Write(PG1_PAR0 + i, mac[i]);
  348. }
  349. /* Set Multicast address. */
  350. for (i = 0; i < 8; i++) {
  351. Asix_Write(PG1_MAR0 + i, 0x00);
  352. }
  353. /* Set Current pointer point. */
  354. Asix_Write(PG1_CPR, RXSTART_INIT + 1);
  355. /* Start the NIC, Abort DMA, page 0. */
  356. Asix_Write(CR, (CR_RD2 | CR_START)); // stop the NIC, abort DMA, page 0
  357. Delay16Cycles();
  358. /* Select media interfac. */
  359. Asix_Write(GPOC, 0x10);
  360. /* Check PHY speed setting 100base = full duplex, 10base > half duplex. */
  361. if (Asix_Read(GPI) & 0x04) {
  362. //printf("Full duplex\n");
  363. Asix_Write(PG0_TCR, TCR_FDU);
  364. }
  365. else {
  366. //printf("Half duplex\n");
  367. Asix_Write(PG0_TCR, 0);
  368. }
  369. /* Enable receiver and set accept broadcast. */
  370. //Asix_Write(PG0_RCR, (RCR_INTT | RCR_AB));
  371. Asix_Write(PG0_RCR, RCR_AB);
  372. return 0;
  373. }
  374. //==============================================================================
  375. /*
  376. * Write data block to the NIC.
  377. */
  378. static void NicWrite(uint8_t * buf, uint16_t len)
  379. {
  380. register uint16_t *wp = (uint16_t *) buf;
  381. if (len & 1)
  382. len++;
  383. len >>= 1;
  384. //printf("Write(%u): ", len);
  385. while (len--) {
  386. //printf("%04X ", *wp);
  387. Asix_WriteWord(DATAPORT, *wp);
  388. wp++;
  389. }
  390. //putchar('\n');
  391. }
  392. //==============================================================================
  393. /*
  394. * Read data block from the NIC.
  395. */
  396. static void NicRead(uint8_t * buf, uint16_t len)
  397. {
  398. register uint16_t *wp = (uint16_t *) buf;
  399. if (len & 1)
  400. len++;
  401. len >>= 1;
  402. //printf("Read(%u): ", len);
  403. while (len--) {
  404. *wp = Asix_ReadWord(DATAPORT);
  405. //printf("%04X ", *wp);
  406. wp++;
  407. }
  408. //putchar('\n');
  409. }
  410. //==============================================================================
  411. /*!
  412. * \brief Fetch the next packet out of the receive ring buffer.
  413. *
  414. * Nic interrupts must be disabled when calling this funtion.
  415. *
  416. * \return Pointer to an allocated ::NETBUF. If there is no
  417. * no data available, then the function returns a
  418. * null pointer. If the NIC's buffer seems to be
  419. * corrupted, a pointer to 0xFFFF is returned.
  420. */
  421. static NETBUF *NicGetPacket(void)
  422. {
  423. NETBUF *nb = 0;
  424. struct nic_pkt_header hdr;
  425. uint16_t count;
  426. uint8_t nextpg;
  427. uint8_t bnry;
  428. uint8_t curr;
  429. uint8_t drop = 0;
  430. /* we don't want to be interrupted by NIC owerflow */
  431. NutEnterCritical();
  432. /*
  433. * Get the current page pointer. It points to the page where the NIC
  434. * will start saving the next incoming packet.
  435. */
  436. curr = Asix_Read(PG0_CPR);
  437. //printf("curr=%02X\n", curr);
  438. /*
  439. * Get the pointer to the last page we read from. The following page
  440. * is the one where we start reading. If it's equal to the current
  441. * page pointer, then there's nothing to read. In this case we return
  442. * a null pointer.
  443. */
  444. if ((bnry = Asix_Read(PG0_BNRY) + 1) >= RXSTOP_INIT) {
  445. //printf("bnry=%02X?\n", bnry);
  446. bnry = RXSTART_INIT;
  447. }
  448. if (bnry == curr) {
  449. //printf("bnry=%02X\n", bnry);
  450. NutJumpOutCritical();
  451. return 0;
  452. }
  453. /*
  454. * Read the NIC specific packet header (4 bytes).
  455. */
  456. Asix_Write(PG0_RBCR0, sizeof(struct nic_pkt_header));
  457. Asix_Write(PG0_RBCR1, 0);
  458. Asix_Write(PG0_RSAR0, 0);
  459. Asix_Write(PG0_RSAR1, bnry);
  460. Asix_Write(CR, CR_START | CR_RD0);
  461. Delay16Cycles();
  462. NicRead((uint8_t *) & hdr, sizeof(struct nic_pkt_header));
  463. NicCompleteDma();
  464. //printf("[S=%02X N=%02X L=%u]", hdr.ph_status, hdr.ph_nextpg, hdr.ph_size);
  465. /*
  466. * Check packet length. Silently discard packets of illegal size.
  467. */
  468. if (hdr.ph_size < 60 + sizeof(struct nic_pkt_header) || hdr.ph_size > 1514 + sizeof(struct nic_pkt_header)) {
  469. //printf("Drop\n");
  470. drop = 1;
  471. }
  472. /*
  473. * Calculate the page of the next packet. If it differs from the
  474. * pointer in the packet header, we discard the whole buffer
  475. * and return a null pointer.
  476. */
  477. // nextpg = hdr.ph_nextpg;
  478. // bnry = hdr.ph_nextpg - 1;
  479. // if(bnry < RXSTART_INIT) bnry = RXSTOP_INIT - 1;
  480. // printf("hdr.ph_size = %02u\n\r",hdr.ph_size);
  481. // printf("hdr.ph_nextpg = %02x\n\r",hdr.ph_nextpg);
  482. nextpg = bnry + (hdr.ph_size >> 8) + ((hdr.ph_size & 0xFF) != 0);
  483. //printf("[nextpg = %02x ->", nextpg);
  484. if (nextpg >= RXSTOP_INIT) {
  485. nextpg -= RXSTOP_INIT;
  486. nextpg += RXSTART_INIT;
  487. }
  488. if (nextpg != hdr.ph_nextpg) {
  489. uint8_t nextpg1 = nextpg + 1;
  490. if (nextpg1 >= RXSTOP_INIT) {
  491. nextpg1 -= RXSTOP_INIT;
  492. nextpg1 += RXSTART_INIT;
  493. }
  494. //HK if (nextpg1 != hdr.ph_nextpg) {
  495. //HK return (NETBUF *) 0xFFFF;
  496. //HK }
  497. nextpg = nextpg1;
  498. }
  499. //printf("%02x]", nextpg);
  500. /*
  501. * Check packet status. It should have set bit 0, but
  502. * even without this bit packets seem to be OK.
  503. */
  504. //printf("Drop=%u Status=%02X\n", drop, hdr.ph_status & 0x0E);
  505. if (!drop && ((hdr.ph_status & 0x0E) == 0)) {
  506. /* Allocate a NETBUF. */
  507. count = hdr.ph_size - sizeof(struct nic_pkt_header);
  508. //printf("Count=%u\n", count);
  509. if ((nb = NutNetBufAlloc(0, NBAF_DATALINK, count))) {
  510. /*
  511. * Set remote dma byte count and
  512. * start address. Don't read the
  513. * header again.
  514. */
  515. Asix_Write(PG0_RBCR0, count);
  516. Asix_Write(PG0_RBCR1, count >> 8);
  517. Asix_Write(PG0_RSAR0, sizeof(struct nic_pkt_header));
  518. Asix_Write(PG0_RSAR1, bnry);
  519. /*
  520. * Perform the read.
  521. */
  522. Asix_Write(CR, CR_START | CR_RD0);
  523. Delay16Cycles();
  524. NicRead(nb->nb_dl.vp, count);
  525. NicCompleteDma();
  526. }
  527. }
  528. /*
  529. * Set boundary register to the last page we read.
  530. * This also drops packets with errors
  531. */
  532. if (--nextpg < RXSTART_INIT)
  533. nextpg = RXSTOP_INIT - 1;
  534. Asix_Write(PG0_BNRY, nextpg);
  535. NutExitCritical();
  536. return nb;
  537. }
  538. //==============================================================================
  539. /*
  540. * \brief Handle NIC overflows.
  541. *
  542. * When a receiver buffer overflow occurs, the NIC will defer any subsequent
  543. * action until properly restarted.
  544. *
  545. * This routine is called within interrupt context, which introduces a big
  546. * problem. It waits for the last transmission to finish, which may take
  547. * several milliseconds. Since Nut/OS 3.5, we do not support nested interrupts
  548. * on AVR systems anymore. So this routine may now increase interrupt
  549. * latency in an unacceptable way. The solution might be to handle overflows
  550. * in the receiver thread.
  551. *
  552. * In any case, this routines needs a major redesign. But it has been
  553. * tested in its current form to gracefully withstand ping floods. Thanks
  554. * to Bengt Florin for contributing his code, which provides much more
  555. * stability than its predecessor.
  556. */
  557. static uint8_t NicOverflow(volatile uint8_t * base)
  558. {
  559. unsigned int cr;
  560. unsigned int resend = 0;
  561. unsigned int curr;
  562. /*
  563. * Wait for any transmission in progress. Save the command register,
  564. * so we can later determine, if NIC transmitter has been interrupted.
  565. * or reception in progress.
  566. */
  567. while (Asix_Read(CR) & CR_TXP);
  568. cr = Asix_Read(CR);
  569. /*
  570. * Get the current page pointer. It points to the page where the NIC
  571. * will start saving the next incoming packet.
  572. */
  573. Asix_Write(CR, CR_STOP | CR_RD2 | CR_PS0);
  574. curr = Asix_Read(PG1_CPR);
  575. Asix_Write(CR, CR_STOP | CR_RD2);
  576. /* Clear remote byte count register. */
  577. Asix_Write(PG0_RBCR0, 0);
  578. Asix_Write(PG0_RBCR1, 0);
  579. /* Check for any incomplete transmission. */
  580. if ((cr & CR_TXP) && ((Asix_Read(PG0_ISR) & (ISR_PTX | ISR_TXE)) == 0)) {
  581. resend = 1;
  582. }
  583. /* Enter loopback mode and restart the NIC. */
  584. Asix_Write(PG0_TCR, TCR_LB0);
  585. Asix_Write(CR, CR_START | CR_RD2);
  586. /*
  587. * Discard all packets from the receiver buffer. Set boundary
  588. * register to the last page we read.
  589. */
  590. if (--curr < TXSTART_INIT) {
  591. curr = RXSTOP_INIT - 1;
  592. }
  593. Asix_Write(PG0_BNRY, curr);
  594. /* Switch from loopback to normal mode mode. */
  595. Asix_Write(PG0_TCR, 0);
  596. /* Re-invoke any interrupted transmission. */
  597. if (resend) {
  598. Asix_Write(CR, CR_START | CR_TXP | CR_RD2);
  599. }
  600. /* Finally clear the overflow flag */
  601. Asix_Write(PG0_ISR, ISR_OVW);
  602. return resend;
  603. }
  604. //==============================================================================
  605. static int NicPutPacket(NETBUF * nb)
  606. {
  607. uint16_t sz; // packed size
  608. uint16_t send_sz; // send packed size, min 60
  609. static uint8_t first_put = 0;
  610. int tmp;
  611. /*
  612. * Fix problem after power on.
  613. */
  614. if (first_put != 1) {
  615. Asix_Write(CR, 0x21);
  616. NutDelay(1);
  617. Asix_Write(CR, 0x22);
  618. first_put = 1;
  619. }
  620. /*
  621. * Calculate the number of bytes to be send. Do not
  622. * send packets larger than 1518 bytes.
  623. */
  624. sz = nb->nb_dl.sz + nb->nb_nw.sz + nb->nb_tp.sz + nb->nb_ap.sz;
  625. if (sz > 1518)
  626. return -1;
  627. //printf("Asix Send %u\n", sz);
  628. /*
  629. * Calculate the number of min bytes. Pad will be
  630. * added when packet lenght less than 60. Enable in TCR reg. PD = 0.
  631. */
  632. send_sz = sz;
  633. if (sz <= 60)
  634. send_sz = 60;
  635. /* Disable Asix interrupts. */
  636. NutEnterCritical();
  637. /* start the NIC */
  638. Asix_Write(CR, (CR_RD2 | CR_START));
  639. /*
  640. * Bengt Florin introduces polling mode for the transmitter. Be
  641. * aware, that this may introduce other problems. If a high
  642. * priority thread is waiting for the transmitter, it may hold
  643. * the CPU for more than 1.2 milliseconds in worst cases.
  644. */
  645. tmp = 120;
  646. while ((Asix_Read(CR) & CR_TXP) && tmp--)
  647. NutDelay(1);
  648. /* set start address for remote DMA operation */
  649. Asix_Write(PG0_RSAR0, 0x00);
  650. Asix_Write(PG0_RSAR1, TXSTART_INIT);
  651. /* load data byte count for remote DMA */
  652. Asix_Write(PG0_RBCR0, (unsigned char) (sz));
  653. Asix_Write(PG0_RBCR1, (unsigned char) (sz >> 8));
  654. /* do remote write operation */
  655. Asix_Write(CR, (CR_RD1 | CR_START));
  656. /* Transfer the Ethernet frame. */
  657. NicWrite(nb->nb_dl.vp, nb->nb_dl.sz);
  658. NicWrite(nb->nb_nw.vp, nb->nb_nw.sz);
  659. NicWrite(nb->nb_tp.vp, nb->nb_tp.sz);
  660. NicWrite(nb->nb_ap.vp, nb->nb_ap.sz);
  661. /* Complete remote dma. */
  662. NicCompleteDma();
  663. /* Clear interrupt flags. */
  664. Asix_Write(PG0_ISR, (ISR_PTX | ISR_TXE));
  665. Delay16Cycles();
  666. /* Set size and pointer to data. */
  667. Asix_Write(CR, CR_START | CR_RD2);
  668. //printf("Asix Start Send\n");
  669. Asix_Write(PG0_TBCR0, (unsigned char) (send_sz));
  670. Asix_Write(PG0_TBCR1, (unsigned char) ((send_sz) >> 8));
  671. Asix_Write(PG0_TPSR, TXSTART_INIT);
  672. /* Start transmission. */
  673. Asix_Write(CR, CR_START | CR_TXP | CR_RD2);
  674. /* Enable Asix interrupts. */
  675. NutExitCritical();
  676. return 0;
  677. }
  678. //==============================================================================
  679. /*!
  680. * \brief NIC receiver thread.
  681. *
  682. */
  683. THREAD(NicRxAsix, arg)
  684. {
  685. NUTDEVICE *dev;
  686. IFNET *ifn;
  687. NICINFO *ni;
  688. NETBUF *nb;
  689. /* Hack! Unfortunately no parameter passing with ARM */
  690. dev = &devAx88796;
  691. ifn = (IFNET *) dev->dev_icb;
  692. ni = (NICINFO *) dev->dev_dcb;
  693. /*
  694. * This is a temporary hack. Due to a change in initialization,
  695. * we may not have got a MAC address yet. Wait until a valid one
  696. * has been set.
  697. */
  698. while (!ETHER_IS_UNICAST(ifn->if_mac)) {
  699. NutSleep(10);
  700. }
  701. NutEnterCritical();
  702. NicStart(ifn->if_mac);
  703. NutExitCritical();
  704. /* Run at high priority. */
  705. //printf("Increase prio\n");
  706. NutThreadSetPriority(9);
  707. while (1) {
  708. //printf("-------- Wait rx\n");
  709. NutEventWait(&ni->ni_rx_rdy, 0);
  710. //printf("-------- Got rx\n");
  711. /*
  712. * Fetch all packets from the NIC's internal
  713. * buffer and pass them to the registered handler.
  714. */
  715. do {
  716. nb = NicGetPacket();
  717. /* The sanity check may fail because the controller is too busy.
  718. restart the NIC. */
  719. if (0) { //HK if ((u_short)nb == 0xFFFF) {
  720. NicStart(ifn->if_mac);
  721. // ni->ni_rx_size_errors++;
  722. } else if (nb) {
  723. ni->ni_rx_packets++;
  724. (*ifn->if_recv) (dev, nb);
  725. }
  726. } while (nb);
  727. }
  728. }
  729. //==============================================================================
  730. /*
  731. * NIC interrupt entry.
  732. */
  733. static void NicInterrupt(void *arg)
  734. {
  735. uint8_t isr;
  736. volatile uint8_t *base = (uint8_t *) (((NUTDEVICE *) arg)->dev_base);
  737. NICINFO *ni = (NICINFO *) ((NUTDEVICE *) arg)->dev_dcb;
  738. ni->ni_interrupts++;
  739. isr = Asix_Read(PG0_ISR);
  740. Delay16Cycles();
  741. Asix_Write(PG0_ISR, isr);
  742. //if(isr)
  743. // printf("%02X\n", isr);
  744. //else
  745. // return;
  746. /*
  747. * Recover from receive buffer overflow. This may take some
  748. * time, so we enable global interrupts but keep NIC
  749. * interrupts disabled.
  750. */
  751. if (isr & ISR_OVW) {
  752. ni->ni_rx_pending++;
  753. if (NicOverflow(base))
  754. ni->ni_tx_bsy++;
  755. else {
  756. NutEventPostAsync(&ni->ni_tx_rdy);
  757. }
  758. ni->ni_overruns++;
  759. } else {
  760. /*
  761. * If this is a transmit interrupt, then a packet has been sent.
  762. * So we can clear the transmitter busy flag and wake up the
  763. * transmitter thread.
  764. */
  765. if (isr & (ISR_PTX | ISR_TXE)) {
  766. ni->ni_tx_bsy = 0;
  767. }
  768. /*
  769. * If this is a receive interrupt, then wake up the receiver
  770. * thread.
  771. */
  772. if (isr & ISR_PRX) {
  773. ni->ni_rx_pending++;
  774. //printf("Post %lX\n", (uint32_t) ni->ni_rx_rdy);
  775. NutEventPostFromIrq(&ni->ni_rx_rdy);
  776. }
  777. /* Rx error. */
  778. if (isr & ISR_RXE) {
  779. if (Asix_Read(PG0_RSR) & RSR_FAE)
  780. ni->ni_rx_frame_errors++;
  781. if (Asix_Read(PG0_RSR) & RSR_CR)
  782. ni->ni_rx_crc_errors++;
  783. if (Asix_Read(PG0_RSR) & RSR_MPA)
  784. ni->ni_rx_missed_errors++;
  785. }
  786. }
  787. }
  788. void NicInterruptEntry(void) NUT_NAKED_FUNC;
  789. void NicInterruptEntry(void)
  790. {
  791. IRQ_ENTRY();
  792. //putchar('i');
  793. NicInterrupt(&devAx88796);
  794. IRQ_EXIT();
  795. }
  796. //==============================================================================
  797. /*!
  798. * \brief Send Ethernet packet.
  799. *
  800. * \param dev Identifies the device to use.
  801. * \param nb Network buffer structure containing the packet to be sent.
  802. * The structure must have been allocated by a previous
  803. * call NutNetBufAlloc().
  804. *
  805. * \return 0 on success, -1 in case of any errors.
  806. */
  807. int AsixOutput(NUTDEVICE * dev, NETBUF * nb)
  808. {
  809. int rc = -1;
  810. NICINFO *ni = (NICINFO *) dev->dev_dcb;
  811. if (NicPutPacket(nb) == 0) {
  812. ni->ni_tx_packets++;
  813. rc = 0;
  814. }
  815. return rc;
  816. }
  817. //==============================================================================
  818. /*!
  819. * \brief Initialize Ethernet hardware.
  820. *
  821. * Resets the Asix Asix_L Ethernet controller, initializes all required
  822. * hardware registers and starts a background thread for incoming
  823. * Ethernet traffic.
  824. *
  825. * Applications should do not directly call this function. It is
  826. * automatically executed during during device registration by
  827. * NutRegisterDevice().
  828. *
  829. * If the network configuration hasn't been set by the application
  830. * before registering the specified device, this function will
  831. * call NutNetLoadConfig() to get the MAC address.
  832. *
  833. * \param dev Identifies the device to initialize.
  834. */
  835. int AsixInit(NUTDEVICE * dev)
  836. {
  837. //printf("Set confnet\n");
  838. confnet.cd_size = sizeof(CONFNET);
  839. strcpy(confnet.cd_name, "eth0");
  840. memset(confnet.cdn_mac, 0xFF, 6);
  841. /* Disable NIC interrupt and clear NICINFO structure. */
  842. //printf("Clear nicinfo\n");
  843. memset(dev->dev_dcb, 0, sizeof(NICINFO));
  844. /*
  845. * Start the receiver thread.
  846. */
  847. //printf("Create rxi5(%lX)\n", (u_long) dev);
  848. NutThreadCreate("rxi5", NicRxAsix, dev, 1024);
  849. outr(PIO_PDR, _BV(9));
  850. /* Register interrupt handler and enable interrupts. */
  851. /* Disable timer 0 interrupts. */
  852. outr(AIC_IDCR, _BV(IRQ0_ID));
  853. /* Set the TC0 IRQ handler address */
  854. outr(AIC_SVR(IRQ0_ID), (unsigned int) NicInterruptEntry);
  855. /* Set the trigg and priority for timer 0 interrupt */
  856. /* Level 7 is highest, level 0 lowest. */
  857. outr(AIC_SMR(IRQ0_ID), (AIC_SRCTYPE_EXT_NEGATIVE_EDGE | 5));
  858. /* Clear timer 0 interrupt */
  859. outr(AIC_ICCR, _BV(IRQ0_ID));
  860. /* Enable timer 0 interrupts */
  861. outr(AIC_IECR, _BV(IRQ0_ID));
  862. //printf("======== AsixcInit done ========\n");
  863. return 0;
  864. }
  865. /*@}*/