ftmac100.c 45 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582
  1. /****************************************************************************
  2. * drivers/net/ftmac100.c
  3. * Faraday FTMAC100 Ethernet MAC Driver
  4. *
  5. * Copyright (C) 2015 Anton D. Kachalov. All rights reserved.
  6. * Author: Anton D. Kachalov <mouse@yandex.ru>
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. *
  12. * 1. Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. * 2. Redistributions in binary form must reproduce the above copyright
  15. * notice, this list of conditions and the following disclaimer in
  16. * the documentation and/or other materials provided with the
  17. * distribution.
  18. * 3. Neither the name NuttX nor the names of its contributors may be
  19. * used to endorse or promote products derived from this software
  20. * without specific prior written permission.
  21. *
  22. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  23. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  24. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  25. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  26. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  27. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  28. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  29. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  30. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  31. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  32. * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  33. * POSSIBILITY OF SUCH DAMAGE.
  34. *
  35. ****************************************************************************/
  36. /****************************************************************************
  37. * Included Files
  38. ****************************************************************************/
  39. #include <nuttx/config.h>
  40. #if defined(CONFIG_NET) && defined(CONFIG_NET_FTMAC100)
  41. #include <stdint.h>
  42. #include <stdlib.h>
  43. #include <stdbool.h>
  44. #include <time.h>
  45. #include <string.h>
  46. #include <errno.h>
  47. #include <assert.h>
  48. #include <debug.h>
  49. #include <crc32.h>
  50. #include <arpa/inet.h>
  51. #include <nuttx/arch.h>
  52. #include <nuttx/irq.h>
  53. #include <nuttx/wdog.h>
  54. #include <nuttx/wqueue.h>
  55. #include <nuttx/net/arp.h>
  56. #include <nuttx/net/netdev.h>
  57. #include <nuttx/net/ftmac100.h>
  58. #ifdef CONFIG_NET_PKT
  59. # include <nuttx/net/pkt.h>
  60. #endif
  61. /****************************************************************************
  62. * Pre-processor Definitions
  63. ****************************************************************************/
  64. /* If processing is not done at the interrupt level, then work queue support
  65. * is required.
  66. */
  67. #if !defined(CONFIG_SCHED_WORKQUEUE)
  68. # error Work queue support is required in this configuration (CONFIG_SCHED_WORKQUEUE)
  69. #endif
  70. /* The low priority work queue is preferred. If it is not enabled, LPWORK
  71. * will be the same as HPWORK.
  72. *
  73. * NOTE: However, the network should NEVER run on the high priority work
  74. * queue! That queue is intended only to service short back end interrupt
  75. * processing that never suspends. Suspending the high priority work queue
  76. * may bring the system to its knees!
  77. */
  78. #define FTMAWORK LPWORK
  79. /* CONFIG_FTMAC100_NINTERFACES determines the number of physical interfaces
  80. * that will be supported.
  81. */
  82. #ifndef CONFIG_FTMAC100_NINTERFACES
  83. # define CONFIG_FTMAC100_NINTERFACES 1
  84. #endif
  85. /* TX poll delay = 1 seconds. CLK_TCK is the number of clock ticks per second */
  86. #define FTMAC100_WDDELAY (1*CLK_TCK)
  87. /* TX timeout = 1 minute */
  88. #define FTMAC100_TXTIMEOUT (60*CLK_TCK)
  89. /* This is a helper pointer for accessing the contents of the Ethernet header */
  90. #define BUF ((struct eth_hdr_s *)priv->ft_dev.d_buf)
  91. /* RX/TX buffer alignment */
  92. #define MAX_PKT_SIZE 1536
  93. #define RX_BUF_SIZE 2044
  94. #define ETH_ZLEN 60
  95. #if defined(CONFIG_NET_MCASTGROUP) || defined(CONFIG_NET_ICMPv6)
  96. # define MACCR_ENABLE_ALL (FTMAC100_MACCR_XMT_EN | \
  97. FTMAC100_MACCR_RCV_EN | \
  98. FTMAC100_MACCR_XDMA_EN | \
  99. FTMAC100_MACCR_RDMA_EN | \
  100. FTMAC100_MACCR_CRC_APD | \
  101. FTMAC100_MACCR_FULLDUP | \
  102. FTMAC100_MACCR_RX_RUNT | \
  103. FTMAC100_MACCR_HT_MULTI_EN | \
  104. FTMAC100_MACCR_RX_BROADPKT)
  105. #else
  106. # define MACCR_ENABLE_ALL (FTMAC100_MACCR_XMT_EN | \
  107. FTMAC100_MACCR_RCV_EN | \
  108. FTMAC100_MACCR_XDMA_EN | \
  109. FTMAC100_MACCR_RDMA_EN | \
  110. FTMAC100_MACCR_CRC_APD | \
  111. FTMAC100_MACCR_FULLDUP | \
  112. FTMAC100_MACCR_RX_RUNT | \
  113. FTMAC100_MACCR_RX_BROADPKT)
  114. #endif
  115. #define MACCR_DISABLE_ALL 0
  116. #define INT_MASK_ALL_ENABLED (FTMAC100_INT_RPKT_FINISH | \
  117. FTMAC100_INT_NORXBUF | \
  118. FTMAC100_INT_XPKT_OK | \
  119. FTMAC100_INT_XPKT_LOST | \
  120. FTMAC100_INT_RPKT_LOST | \
  121. FTMAC100_INT_AHB_ERR | \
  122. FTMAC100_INT_PHYSTS_CHG)
  123. #define INT_MASK_ALL_DISABLED 0
  124. #define putreg32(v, x) (*(volatile uint32_t*)(x) = (v))
  125. #define getreg32(x) (*(uint32_t *)(x))
  126. /****************************************************************************
  127. * Private Types
  128. ****************************************************************************/
  129. /* The ftmac100_driver_s encapsulates all state information for a single hardware
  130. * interface
  131. */
  132. struct ftmac100_driver_s
  133. {
  134. struct ftmac100_txdes_s txdes[CONFIG_FTMAC100_TX_DESC];
  135. struct ftmac100_rxdes_s rxdes[CONFIG_FTMAC100_RX_DESC];
  136. int rx_pointer;
  137. int tx_pointer;
  138. int tx_clean_pointer;
  139. int tx_pending;
  140. uint32_t iobase;
  141. /* NuttX net data */
  142. bool ft_bifup; /* true:ifup false:ifdown */
  143. WDOG_ID ft_txpoll; /* TX poll timer */
  144. WDOG_ID ft_txtimeout; /* TX timeout timer */
  145. unsigned int status; /* Last ISR status */
  146. struct work_s ft_irqwork; /* For deferring work to the work queue */
  147. struct work_s ft_pollwork; /* For deferring work to the work queue */
  148. /* This holds the information visible to the NuttX network */
  149. struct net_driver_s ft_dev; /* Interface understood by the network */
  150. };
  151. /****************************************************************************
  152. * Private Data
  153. ****************************************************************************/
  154. /* A single packet buffer is used */
  155. static uint8_t g_pktbuf[MAX_NETDEV_PKTSIZE + CONFIG_NET_GUARDSIZE];
  156. /* Driver state structure. */
  157. static struct ftmac100_driver_s g_ftmac100[CONFIG_FTMAC100_NINTERFACES]
  158. __attribute__((aligned(16)));
  159. /****************************************************************************
  160. * Private Function Prototypes
  161. ****************************************************************************/
  162. /* Common TX logic */
  163. static int ftmac100_transmit(FAR struct ftmac100_driver_s *priv);
  164. static int ftmac100_txpoll(struct net_driver_s *dev);
  165. /* Interrupt handling */
  166. static void ftmac100_reset(FAR struct ftmac100_driver_s *priv);
  167. static void ftmac100_receive(FAR struct ftmac100_driver_s *priv);
  168. static void ftmac100_txdone(FAR struct ftmac100_driver_s *priv);
  169. static void ftmac100_interrupt_work(FAR void *arg);
  170. static int ftmac100_interrupt(int irq, FAR void *context, FAR void *arg);
  171. /* Watchdog timer expirations */
  172. static void ftmac100_txtimeout_work(FAR void *arg);
  173. static void ftmac100_txtimeout_expiry(int argc, uint32_t arg, ...);
  174. static void ftmac100_poll_work(FAR void *arg);
  175. static void ftmac100_poll_expiry(int argc, uint32_t arg, ...);
  176. /* NuttX callback functions */
  177. static int ftmac100_ifup(FAR struct net_driver_s *dev);
  178. static int ftmac100_ifdown(FAR struct net_driver_s *dev);
  179. static void ftmac100_txavail_work(FAR void *arg);
  180. static int ftmac100_txavail(FAR struct net_driver_s *dev);
  181. #if defined(CONFIG_NET_MCASTGROUP) || defined(CONFIG_NET_ICMPv6)
  182. static int ftmac100_addmac(FAR struct net_driver_s *dev, FAR const uint8_t *mac);
  183. #ifdef CONFIG_NET_MCASTGROUP
  184. static int ftmac100_rmmac(FAR struct net_driver_s *dev, FAR const uint8_t *mac);
  185. #endif
  186. #ifdef CONFIG_NET_ICMPv6
  187. static void ftmac100_ipv6multicast(FAR struct ftmac100_driver_s *priv);
  188. #endif
  189. #endif
  190. /****************************************************************************
  191. * Private Functions
  192. ****************************************************************************/
  193. /****************************************************************************
  194. * Name: ftmac100_transmit
  195. *
  196. * Description:
  197. * Start hardware transmission. Called either from the txdone interrupt
  198. * handling or from watchdog based polling.
  199. *
  200. * Input Parameters:
  201. * priv - Reference to the driver state structure
  202. *
  203. * Returned Value:
  204. * OK on success; a negated errno on failure
  205. *
  206. * Assumptions:
  207. * May or may not be called from an interrupt handler. In either case,
  208. * global interrupts are disabled, either explicitly or indirectly through
  209. * interrupt handling logic.
  210. *
  211. ****************************************************************************/
  212. static FAR struct ftmac100_rxdes_s *
  213. ftmac100_current_rxdes(FAR struct ftmac100_driver_s *priv)
  214. {
  215. return &priv->rxdes[priv->rx_pointer];
  216. }
  217. static FAR struct ftmac100_txdes_s *
  218. ftmac100_current_txdes(FAR struct ftmac100_driver_s *priv)
  219. {
  220. return &priv->txdes[priv->tx_pointer];
  221. }
  222. static FAR struct ftmac100_txdes_s *
  223. ftmac100_current_clean_txdes(FAR struct ftmac100_driver_s *priv)
  224. {
  225. return &priv->txdes[priv->tx_clean_pointer];
  226. }
  227. static int ftmac100_transmit(FAR struct ftmac100_driver_s *priv)
  228. {
  229. FAR struct ftmac100_register_s *iobase = (FAR struct ftmac100_register_s *)priv->iobase;
  230. FAR struct ftmac100_txdes_s *txdes;
  231. int len = priv->ft_dev.d_len;
  232. //irqstate_t flags;
  233. //flags = enter_critical_section();
  234. //ninfo("flags=%08x\n", flags);
  235. txdes = ftmac100_current_txdes(priv);
  236. /* Verify that the hardware is ready to send another packet. If we get
  237. * here, then we are committed to sending a packet; Higher level logic
  238. * must have assured that there is no transmission in progress.
  239. */
  240. len = len < ETH_ZLEN ? ETH_ZLEN : len;
  241. /* Send the packet: address=priv->ft_dev.d_buf, length=priv->ft_dev.d_len */
  242. //memcpy((void *)txdes->txdes2, priv->ft_dev.d_buf, len);
  243. txdes->txdes2 = (unsigned int)priv->ft_dev.d_buf;
  244. txdes->txdes1 &= FTMAC100_TXDES1_EDOTR;
  245. txdes->txdes1 |= (FTMAC100_TXDES1_FTS |
  246. FTMAC100_TXDES1_LTS |
  247. FTMAC100_TXDES1_TXIC |
  248. FTMAC100_TXDES1_TXBUF_SIZE(len));
  249. txdes->txdes0 |= FTMAC100_TXDES0_TXDMA_OWN;
  250. ninfo("ftmac100_transmit[%x]: copy %08x to %08x %04x\n",
  251. priv->tx_pointer, priv->ft_dev.d_buf, txdes->txdes2, len);
  252. priv->tx_pointer = (priv->tx_pointer + 1) & (CONFIG_FTMAC100_TX_DESC - 1);
  253. priv->tx_pending++;
  254. /* Enable Tx polling */
  255. /* FIXME: enable interrupts */
  256. putreg32(1, &iobase->txpd);
  257. /* Setup the TX timeout watchdog (perhaps restarting the timer) */
  258. (void)wd_start(priv->ft_txtimeout, FTMAC100_TXTIMEOUT,
  259. ftmac100_txtimeout_expiry, 1, (wdparm_t)priv);
  260. //leave_critical_section(flags);
  261. return OK;
  262. }
  263. /****************************************************************************
  264. * Name: ftmac100_txpoll
  265. *
  266. * Description:
  267. * The transmitter is available, check if the network has any outgoing packets
  268. * ready to send. This is a callback from devif_poll(). devif_poll() may
  269. * be called:
  270. *
  271. * 1. When the preceding TX packet send is complete,
  272. * 2. When the preceding TX packet send timesout and the interface is
  273. * reset
  274. * 3. During normal TX polling
  275. *
  276. * Input Parameters:
  277. * dev - Reference to the NuttX driver state structure
  278. *
  279. * Returned Value:
  280. * OK on success; a negated errno on failure
  281. *
  282. * Assumptions:
  283. * May or may not be called from an interrupt handler. In either case,
  284. * global interrupts are disabled, either explicitly or indirectly through
  285. * interrupt handling logic.
  286. *
  287. ****************************************************************************/
  288. static int ftmac100_txpoll(struct net_driver_s *dev)
  289. {
  290. FAR struct ftmac100_driver_s *priv = (FAR struct ftmac100_driver_s *)dev->d_private;
  291. /* If the polling resulted in data that should be sent out on the network,
  292. * the field d_len is set to a value > 0.
  293. */
  294. if (priv->ft_dev.d_len > 0)
  295. {
  296. /* Look up the destination MAC address and add it to the Ethernet
  297. * header.
  298. */
  299. #ifdef CONFIG_NET_IPv4
  300. #ifdef CONFIG_NET_IPv6
  301. if (IFF_IS_IPv4(priv->ft_dev.d_flags))
  302. #endif
  303. {
  304. arp_out(&priv->ft_dev);
  305. }
  306. #endif /* CONFIG_NET_IPv4 */
  307. #ifdef CONFIG_NET_IPv6
  308. #ifdef CONFIG_NET_IPv4
  309. else
  310. #endif
  311. {
  312. neighbor_out(&priv->ft_dev);
  313. }
  314. #endif /* CONFIG_NET_IPv6 */
  315. if (!devif_loopback(&priv->ft_dev))
  316. {
  317. /* Send the packet */
  318. ftmac100_transmit(priv);
  319. /* Check if there is room in the device to hold another packet. If not,
  320. * return a non-zero value to terminate the poll.
  321. */
  322. }
  323. }
  324. /* If zero is returned, the polling will continue until all connections have
  325. * been examined.
  326. */
  327. return 0;
  328. }
  329. /****************************************************************************
  330. * Name: ftmac100_reset
  331. *
  332. * Description:
  333. * Do the HW reset
  334. *
  335. * Input Parameters:
  336. * priv - Reference to the NuttX driver state structure
  337. *
  338. * Returned Value:
  339. * None
  340. *
  341. * Assumptions:
  342. * Global interrupts are disabled by interrupt handling logic.
  343. *
  344. ****************************************************************************/
  345. static void ftmac100_reset(FAR struct ftmac100_driver_s *priv)
  346. {
  347. FAR struct ftmac100_register_s *iobase = (FAR struct ftmac100_register_s *)priv->iobase;
  348. ninfo("%s(): iobase=%p\n", __func__, iobase);
  349. putreg32 (FTMAC100_MACCR_SW_RST, &iobase->maccr);
  350. while (getreg32 (&iobase->maccr) & FTMAC100_MACCR_SW_RST)
  351. ;
  352. }
  353. /****************************************************************************
  354. * Name: ftmac100_init
  355. *
  356. * Description:
  357. * Perform HW initialization
  358. *
  359. * Input Parameters:
  360. * priv - Reference to the NuttX driver state structure
  361. *
  362. * Returned Value:
  363. * None
  364. *
  365. * Assumptions:
  366. * Global interrupts are disabled by interrupt handling logic.
  367. *
  368. ****************************************************************************/
  369. static void ftmac100_init(FAR struct ftmac100_driver_s *priv)
  370. {
  371. FAR struct ftmac100_register_s *iobase = (FAR struct ftmac100_register_s *)priv->iobase;
  372. FAR struct ftmac100_txdes_s *txdes = priv->txdes;
  373. FAR struct ftmac100_rxdes_s *rxdes = priv->rxdes;
  374. FAR unsigned char *kmem;
  375. int i;
  376. nerr ("%s()\n", __func__);
  377. /* Disable all interrupts */
  378. putreg32(0, &iobase->imr);
  379. /* Initialize descriptors */
  380. priv->rx_pointer = 0;
  381. priv->tx_pointer = 0;
  382. priv->tx_clean_pointer = 0;
  383. priv->tx_pending = 0;
  384. rxdes[CONFIG_FTMAC100_RX_DESC - 1].rxdes1 = FTMAC100_RXDES1_EDORR;
  385. kmem = memalign(RX_BUF_SIZE, CONFIG_FTMAC100_RX_DESC * RX_BUF_SIZE);
  386. ninfo("KMEM=%08x\n", kmem);
  387. for (i = 0; i < CONFIG_FTMAC100_RX_DESC; i++)
  388. {
  389. /* RXBUF_BADR */
  390. rxdes[i].rxdes0 = FTMAC100_RXDES0_RXDMA_OWN;
  391. rxdes[i].rxdes1 |= FTMAC100_RXDES1_RXBUF_SIZE(RX_BUF_SIZE);
  392. rxdes[i].rxdes2 = (unsigned int)(kmem + i * RX_BUF_SIZE);
  393. rxdes[i].rxdes3 = (unsigned int)(rxdes + i + 1); /* Next ring */
  394. }
  395. rxdes[CONFIG_FTMAC100_RX_DESC - 1].rxdes3 = (unsigned int)rxdes; /* Next ring */
  396. for (i = 0; i < CONFIG_FTMAC100_TX_DESC; i++)
  397. {
  398. /* TXBUF_BADR */
  399. txdes[i].txdes0 = 0;
  400. txdes[i].txdes1 = 0;
  401. txdes[i].txdes2 = 0;
  402. txdes[i].txdes3 = 0;
  403. // txdes[i].txdes3 = (unsigned int)(txdes + i + 1); /* Next ring */
  404. }
  405. txdes[CONFIG_FTMAC100_TX_DESC - 1].txdes1 = FTMAC100_TXDES1_EDOTR;
  406. //txdes[CONFIG_FTMAC100_TX_DESC - 1].txdes3 = (unsigned int)txdes; /* Next ring */
  407. /* transmit ring */
  408. ninfo("priv=%08x txdes=%08x rxdes=%08x\n", priv, txdes, rxdes);
  409. putreg32 ((unsigned int)txdes, &iobase->txr_badr);
  410. /* receive ring */
  411. putreg32 ((unsigned int)rxdes, &iobase->rxr_badr);
  412. /* set RXINT_THR and TXINT_THR */
  413. //putreg32 (FTMAC100_ITC_RXINT_THR(1) | FTMAC100_ITC_TXINT_THR(1), &iobase->itc);
  414. /* poll receive descriptor automatically */
  415. putreg32 (FTMAC100_APTC_RXPOLL_CNT(1), &iobase->aptc);
  416. #if 1
  417. /* Set DMA burst length */
  418. putreg32 (FTMAC100_DBLAC_RXFIFO_LTHR(2) |
  419. FTMAC100_DBLAC_RXFIFO_HTHR(6) |
  420. FTMAC100_DBLAC_RX_THR_EN, &iobase->dblac);
  421. //putreg32 (getreg32(&iobase->fcr) | 0x1, &iobase->fcr);
  422. //putreg32 (getreg32(&iobase->bpr) | 0x1, &iobase->bpr);
  423. #endif
  424. /* enable transmitter, receiver */
  425. putreg32 (MACCR_ENABLE_ALL, &iobase->maccr);
  426. /* enable Rx, Tx interrupts */
  427. putreg32 (INT_MASK_ALL_ENABLED, &iobase->imr);
  428. }
  429. /****************************************************************************
  430. * Name: ftmac100_mdio_read
  431. *
  432. * Description:
  433. * Read MII registers
  434. *
  435. * Input Parameters:
  436. * iobase - Pointer to the driver's registers base
  437. * reg - MII register number
  438. *
  439. * Returned Value:
  440. * Register value
  441. *
  442. * Assumptions:
  443. *
  444. *
  445. ****************************************************************************/
  446. static uint32_t ftmac100_mdio_read(FAR struct ftmac100_register_s *iobase, int reg)
  447. {
  448. int i;
  449. uint32_t phycr = FTMAC100_PHYCR_PHYAD(1) |
  450. FTMAC100_PHYCR_REGAD(reg) |
  451. FTMAC100_PHYCR_MIIRD;
  452. putreg32(phycr, &iobase->phycr);
  453. for (i = 0; i < 10; i++)
  454. {
  455. phycr = getreg32(&iobase->phycr);
  456. ninfo("%02x %d phycr=%08x\n", reg, i, phycr);
  457. if ((phycr & FTMAC100_PHYCR_MIIRD) == 0)
  458. {
  459. break;
  460. }
  461. }
  462. return phycr & 0xffff;
  463. }
  464. /****************************************************************************
  465. * Name: ftmac100_set_mac
  466. *
  467. * Description:
  468. * Set the MAC address
  469. *
  470. * Input Parameters:
  471. * priv - Reference to the NuttX driver state structure
  472. * mac - Six bytes MAC address
  473. *
  474. * Returned Value:
  475. * None
  476. *
  477. * Assumptions:
  478. *
  479. ****************************************************************************/
  480. static void ftmac100_set_mac(FAR struct ftmac100_driver_s *priv,
  481. FAR const unsigned char *mac)
  482. {
  483. FAR struct ftmac100_register_s *iobase = (FAR struct ftmac100_register_s *)priv->iobase;
  484. unsigned int maddr = mac[0] << 8 | mac[1];
  485. unsigned int laddr = mac[2] << 24 | mac[3] << 16 | mac[4] << 8 | mac[5];
  486. ninfo("%s(%x %x)\n", __func__, maddr, laddr);
  487. putreg32(maddr, &iobase->mac_madr);
  488. putreg32(laddr, &iobase->mac_ladr);
  489. }
  490. /****************************************************************************
  491. * Name: ftmac100_receive
  492. *
  493. * Description:
  494. * An interrupt was received indicating the availability of a new RX packet
  495. *
  496. * Input Parameters:
  497. * priv - Reference to the driver state structure
  498. *
  499. * Returned Value:
  500. * None
  501. *
  502. * Assumptions:
  503. * Global interrupts are disabled by interrupt handling logic.
  504. *
  505. ****************************************************************************/
  506. static void ftmac100_receive(FAR struct ftmac100_driver_s *priv)
  507. {
  508. FAR struct ftmac100_rxdes_s *rxdes;
  509. FAR uint8_t *data;
  510. uint32_t len;
  511. int found;
  512. do
  513. {
  514. found = false;
  515. rxdes = ftmac100_current_rxdes(priv);
  516. while (!(rxdes->rxdes0 & FTMAC100_RXDES0_RXDMA_OWN))
  517. {
  518. if (rxdes->rxdes0 & FTMAC100_RXDES0_FRS)
  519. {
  520. found = true;
  521. break;
  522. }
  523. /* Clear status bits */
  524. rxdes->rxdes0 = FTMAC100_RXDES0_RXDMA_OWN;
  525. priv->rx_pointer = (priv->rx_pointer + 1) & (CONFIG_FTMAC100_RX_DESC - 1);
  526. rxdes = ftmac100_current_rxdes(priv);
  527. }
  528. if (!found)
  529. {
  530. ninfo("\nNOT FOUND\nCurrent RX %d rxdes0=%08x\n",
  531. priv->rx_pointer, rxdes->rxdes0);
  532. return;
  533. }
  534. len = FTMAC100_RXDES0_RFL(rxdes->rxdes0);
  535. data = (uint8_t *)rxdes->rxdes2;
  536. ninfo ("RX buffer %d (%08x), %x received (%d)\n",
  537. priv->rx_pointer, data, len, (rxdes->rxdes0 & FTMAC100_RXDES0_LRS));
  538. /* Copy the data data from the hardware to priv->ft_dev.d_buf. Set
  539. * amount of data in priv->ft_dev.d_len
  540. */
  541. memcpy(priv->ft_dev.d_buf, data, len);
  542. priv->ft_dev.d_len = len;
  543. #ifdef CONFIG_NET_PKT
  544. /* When packet sockets are enabled, feed the frame into the packet tap */
  545. pkt_input(&priv->ft_dev);
  546. #endif
  547. /* We only accept IP packets of the configured type and ARP packets */
  548. #ifdef CONFIG_NET_IPv4
  549. if (BUF->type == HTONS(ETHTYPE_IP))
  550. {
  551. ninfo("IPv4 frame\n");
  552. /* Handle ARP on input then give the IPv4 packet to the network
  553. * layer
  554. */
  555. arp_ipin(&priv->ft_dev);
  556. ipv4_input(&priv->ft_dev);
  557. /* If the above function invocation resulted in data that should be
  558. * sent out on the network, the field d_len will set to a value > 0.
  559. */
  560. if (priv->ft_dev.d_len > 0)
  561. {
  562. /* Update the Ethernet header with the correct MAC address */
  563. #ifdef CONFIG_NET_IPv6
  564. if (IFF_IS_IPv4(priv->ft_dev.d_flags))
  565. #endif
  566. {
  567. arp_out(&priv->ft_dev);
  568. }
  569. #ifdef CONFIG_NET_IPv6
  570. else
  571. {
  572. neighbor_out(&priv->ft_dev);
  573. }
  574. #endif
  575. /* And send the packet */
  576. ftmac100_transmit(priv);
  577. }
  578. }
  579. else
  580. #endif
  581. #ifdef CONFIG_NET_IPv6
  582. if (BUF->type == HTONS(ETHTYPE_IP6))
  583. {
  584. ninfo("Iv6 frame\n");
  585. /* Give the IPv6 packet to the network layer */
  586. ipv6_input(&priv->ft_dev);
  587. /* If the above function invocation resulted in data that should be
  588. * sent out on the network, the field d_len will set to a value > 0.
  589. */
  590. if (priv->ft_dev.d_len > 0)
  591. {
  592. /* Update the Ethernet header with the correct MAC address */
  593. #ifdef CONFIG_NET_IPv4
  594. if (IFF_IS_IPv4(priv->ft_dev.d_flags))
  595. {
  596. arp_out(&priv->ft_dev);
  597. }
  598. else
  599. #endif
  600. #ifdef CONFIG_NET_IPv6
  601. {
  602. neighbor_out(&priv->ft_dev);
  603. }
  604. #endif
  605. /* And send the packet */
  606. ftmac100_transmit(priv);
  607. }
  608. }
  609. else
  610. #endif
  611. #ifdef CONFIG_NET_ARP
  612. if (BUF->type == htons(ETHTYPE_ARP))
  613. {
  614. arp_arpin(&priv->ft_dev);
  615. /* If the above function invocation resulted in data that should be
  616. * sent out on the network, the field d_len will set to a value > 0.
  617. */
  618. if (priv->ft_dev.d_len > 0)
  619. {
  620. ftmac100_transmit(priv);
  621. }
  622. }
  623. #endif
  624. priv->rx_pointer = (priv->rx_pointer + 1) & (CONFIG_FTMAC100_RX_DESC - 1);
  625. rxdes->rxdes1 &= FTMAC100_RXDES1_EDORR;
  626. rxdes->rxdes1 |= FTMAC100_RXDES1_RXBUF_SIZE(RX_BUF_SIZE);
  627. rxdes->rxdes0 |= FTMAC100_RXDES0_RXDMA_OWN;
  628. }
  629. while (true); /* While there are more packets to be processed */
  630. }
  631. /****************************************************************************
  632. * Name: ftmac100_txdone
  633. *
  634. * Description:
  635. * An interrupt was received indicating that the last TX packet(s) is done
  636. *
  637. * Input Parameters:
  638. * priv - Reference to the driver state structure
  639. *
  640. * Returned Value:
  641. * None
  642. *
  643. * Assumptions:
  644. * Global interrupts are disabled by the watchdog logic.
  645. *
  646. ****************************************************************************/
  647. static void ftmac100_txdone(FAR struct ftmac100_driver_s *priv)
  648. {
  649. FAR struct ftmac100_txdes_s *txdes;
  650. /* Check if a Tx was pending */
  651. while (priv->tx_pending)
  652. {
  653. txdes = ftmac100_current_clean_txdes(priv);
  654. /* txdes owned by dma */
  655. if (txdes->txdes0 & FTMAC100_TXDES0_TXDMA_OWN)
  656. {
  657. break;
  658. }
  659. /* TODO: check for excessive and late collisions */
  660. /* txdes reset */
  661. txdes->txdes0 = 0;
  662. txdes->txdes1 &= FTMAC100_TXDES1_EDOTR;
  663. txdes->txdes2 = 0;
  664. txdes->txdes3 = 0;
  665. priv->tx_clean_pointer = (priv->tx_clean_pointer + 1) & (CONFIG_FTMAC100_TX_DESC - 1);
  666. priv->tx_pending--;
  667. }
  668. /* If no further xmits are pending, then cancel the TX timeout and
  669. * disable further Tx interrupts.
  670. */
  671. ninfo("txpending=%d\n", priv->tx_pending);
  672. /* Cancel the TX timeout */
  673. wd_cancel(priv->ft_txtimeout);
  674. /* Then poll the network for new XMIT data */
  675. (void)devif_poll(&priv->ft_dev, ftmac100_txpoll);
  676. }
  677. /****************************************************************************
  678. * Name: ftmac100_interrupt_work
  679. *
  680. * Description:
  681. * Perform interrupt related work from the worker thread
  682. *
  683. * Input Parameters:
  684. * arg - The argument passed when work_queue() was called.
  685. *
  686. * Returned Value:
  687. * OK on success
  688. *
  689. * Assumptions:
  690. * Ethernet interrupts are disabled
  691. *
  692. ****************************************************************************/
  693. static void ftmac100_interrupt_work(FAR void *arg)
  694. {
  695. FAR struct ftmac100_driver_s *priv = (FAR struct ftmac100_driver_s *)arg;
  696. FAR struct ftmac100_register_s *iobase = (FAR struct ftmac100_register_s *)priv->iobase;
  697. unsigned int status;
  698. unsigned int phycr;
  699. /* Process pending Ethernet interrupts */
  700. net_lock();
  701. status = priv->status;
  702. ninfo("status=%08x(%08x) BASE=%p ISR=%p PHYCR=%p\n",
  703. status, getreg32(&iobase->isr), iobase, &iobase->isr, &iobase->phycr);
  704. if (!status)
  705. {
  706. goto out;
  707. }
  708. /* Handle interrupts according to status bit settings */
  709. /* Check if we received an incoming packet, if so, call ftmac100_receive() */
  710. if (status & FTMAC100_INT_RPKT_SAV)
  711. {
  712. putreg32(1, &iobase->rxpd);
  713. }
  714. if (status & (FTMAC100_INT_RPKT_FINISH | FTMAC100_INT_NORXBUF))
  715. {
  716. ftmac100_receive(priv);
  717. }
  718. /* Check if a packet transmission just completed. If so, call ftmac100_txdone.
  719. * This may disable further Tx interrupts if there are no pending
  720. * transmissions.
  721. */
  722. if (status & (FTMAC100_INT_XPKT_OK))
  723. {
  724. ninfo("\n\nTXDONE\n\n");
  725. ftmac100_txdone(priv);
  726. }
  727. if (status & FTMAC100_INT_PHYSTS_CHG)
  728. {
  729. /* PHY link status change */
  730. phycr = ftmac100_mdio_read(iobase, 1);
  731. if (phycr & 0x04)
  732. {
  733. priv->ft_bifup = true;
  734. }
  735. else
  736. {
  737. priv->ft_bifup = false;
  738. }
  739. ninfo("Link: %s\n", priv->ft_bifup ? "UP" : "DOWN");
  740. ftmac100_mdio_read(iobase, 5);
  741. }
  742. #if 0
  743. #define REG(x) (*(volatile uint32_t *)(x))
  744. ninfo("\n=============================================================\n");
  745. ninfo("TM CNTL=%08x INTRS=%08x MASK=%08x LOAD=%08x COUNT=%08x M1=%08x\n",
  746. REG(0x98400030), REG(0x98400034), REG(0x98400038), REG(0x98400004),
  747. REG(0x98400000), REG(0x98400008));
  748. ninfo("IRQ STATUS=%08x MASK=%08x MODE=%08x LEVEL=%08x\n",
  749. REG(0x98800014), REG(0x98800004), REG(0x9880000C), REG(0x98800010));
  750. ninfo("FIQ STATUS=%08x MASK=%08x MODE=%08x LEVEL=%08x\n", REG(0x98800034),
  751. REG(0x98800024), REG(0x9880002C), REG(0x98800020));
  752. ninfo("=============================================================\n");
  753. #endif
  754. out:
  755. putreg32 (INT_MASK_ALL_ENABLED, &iobase->imr);
  756. ninfo("ISR-done\n");
  757. net_unlock();
  758. /* Re-enable Ethernet interrupts */
  759. up_enable_irq(CONFIG_FTMAC100_IRQ);
  760. }
  761. /****************************************************************************
  762. * Name: ftmac100_interrupt
  763. *
  764. * Description:
  765. * Hardware interrupt handler
  766. *
  767. * Input Parameters:
  768. * irq - Number of the IRQ that generated the interrupt
  769. * context - Interrupt register state save info (architecture-specific)
  770. *
  771. * Returned Value:
  772. * OK on success
  773. *
  774. * Assumptions:
  775. *
  776. ****************************************************************************/
  777. static int ftmac100_interrupt(int irq, FAR void *context, FAR void *arg)
  778. {
  779. FAR struct ftmac100_driver_s *priv = &g_ftmac100[0];
  780. FAR struct ftmac100_register_s *iobase = (FAR struct ftmac100_register_s *)priv->iobase;
  781. /* Disable further Ethernet interrupts. Because Ethernet interrupts are
  782. * also disabled if the TX timeout event occurs, there can be no race
  783. * condition here.
  784. */
  785. priv->status = getreg32(&iobase->isr);
  786. up_disable_irq(CONFIG_FTMAC100_IRQ);
  787. putreg32 (INT_MASK_ALL_DISABLED, &iobase->imr);
  788. /* TODO: Determine if a TX transfer just completed */
  789. ninfo("===> status=%08x\n", priv->status);
  790. if (priv->status & (FTMAC100_INT_XPKT_OK))
  791. {
  792. /* If a TX transfer just completed, then cancel the TX timeout so
  793. * there will be do race condition between any subsequent timeout
  794. * expiration and the deferred interrupt processing.
  795. */
  796. ninfo("\n\nTXDONE 0\n\n");
  797. wd_cancel(priv->ft_txtimeout);
  798. }
  799. /* Schedule to perform the interrupt processing on the worker thread. */
  800. work_queue(FTMAWORK, &priv->ft_irqwork, ftmac100_interrupt_work, priv, 0);
  801. return OK;
  802. }
  803. /****************************************************************************
  804. * Name: ftmac100_txtimeout_work
  805. *
  806. * Description:
  807. * Perform TX timeout related work from the worker thread
  808. *
  809. * Input Parameters:
  810. * arg - The argument passed when work_queue() as called.
  811. *
  812. * Returned Value:
  813. * OK on success
  814. *
  815. * Assumptions:
  816. * Ethernet interrupts are disabled
  817. *
  818. ****************************************************************************/
  819. static void ftmac100_txtimeout_work(FAR void *arg)
  820. {
  821. FAR struct ftmac100_driver_s *priv = (FAR struct ftmac100_driver_s *)arg;
  822. ninfo("TXTIMEOUT\n");
  823. /* Process pending Ethernet interrupts */
  824. net_lock();
  825. /* Then poll the network for new XMIT data */
  826. (void)devif_poll(&priv->ft_dev, ftmac100_txpoll);
  827. net_unlock();
  828. }
  829. /****************************************************************************
  830. * Name: ftmac100_txtimeout_expiry
  831. *
  832. * Description:
  833. * Our TX watchdog timed out. Called from the timer interrupt handler.
  834. * The last TX never completed. Reset the hardware and start again.
  835. *
  836. * Input Parameters:
  837. * argc - The number of available arguments
  838. * arg - The first argument
  839. *
  840. * Returned Value:
  841. * None
  842. *
  843. * Assumptions:
  844. * Global interrupts are disabled by the watchdog logic.
  845. *
  846. ****************************************************************************/
  847. static void ftmac100_txtimeout_expiry(int argc, uint32_t arg, ...)
  848. {
  849. FAR struct ftmac100_driver_s *priv = (FAR struct ftmac100_driver_s *)arg;
  850. /* Disable further Ethernet interrupts. This will prevent some race
  851. * conditions with interrupt work. There is still a potential race
  852. * condition with interrupt work that is already queued and in progress.
  853. */
  854. up_disable_irq(CONFIG_FTMAC100_IRQ);
  855. /* Schedule to perform the TX timeout processing on the worker thread. */
  856. work_queue(FTMAWORK, &priv->ft_irqwork, ftmac100_txtimeout_work, priv, 0);
  857. }
  858. /****************************************************************************
  859. * Name: ftmac100_poll_work
  860. *
  861. * Description:
  862. * Perform periodic polling from the worker thread
  863. *
  864. * Input Parameters:
  865. * arg - The argument passed when work_queue() as called.
  866. *
  867. * Returned Value:
  868. * OK on success
  869. *
  870. * Assumptions:
  871. * Ethernet interrupts are disabled
  872. *
  873. ****************************************************************************/
  874. static void ftmac100_poll_work(FAR void *arg)
  875. {
  876. FAR struct ftmac100_driver_s *priv = (FAR struct ftmac100_driver_s *)arg;
  877. /* Perform the poll */
  878. net_lock();
  879. /* Check if there is room in the send another TX packet. We cannot perform
  880. * the TX poll if he are unable to accept another packet for transmission.
  881. */
  882. /* If so, update TCP timing states and poll the network for new XMIT data. Hmmm..
  883. * might be bug here. Does this mean if there is a transmit in progress,
  884. * we will missing TCP time state updates?
  885. */
  886. (void)devif_timer(&priv->ft_dev, ftmac100_txpoll);
  887. /* Setup the watchdog poll timer again */
  888. (void)wd_start(priv->ft_txpoll, FTMAC100_WDDELAY, ftmac100_poll_expiry, 1,
  889. (wdparm_t)priv);
  890. net_unlock();
  891. }
  892. /****************************************************************************
  893. * Name: ftmac100_poll_expiry
  894. *
  895. * Description:
  896. * Periodic timer handler. Called from the timer interrupt handler.
  897. *
  898. * Input Parameters:
  899. * argc - The number of available arguments
  900. * arg - The first argument
  901. *
  902. * Returned Value:
  903. * None
  904. *
  905. * Assumptions:
  906. * Global interrupts are disabled by the watchdog logic.
  907. *
  908. ****************************************************************************/
  909. static void ftmac100_poll_expiry(int argc, uint32_t arg, ...)
  910. {
  911. FAR struct ftmac100_driver_s *priv = (FAR struct ftmac100_driver_s *)arg;
  912. /* Schedule to perform the interrupt processing on the worker thread. */
  913. work_queue(FTMAWORK, &priv->ft_pollwork, ftmac100_poll_work, priv, 0);
  914. }
  915. /****************************************************************************
  916. * Name: ftmac100_ifup
  917. *
  918. * Description:
  919. * NuttX Callback: Bring up the Ethernet interface when an IP address is
  920. * provided
  921. *
  922. * Input Parameters:
  923. * dev - Reference to the NuttX driver state structure
  924. *
  925. * Returned Value:
  926. * None
  927. *
  928. * Assumptions:
  929. *
  930. ****************************************************************************/
  931. static int ftmac100_ifup(struct net_driver_s *dev)
  932. {
  933. FAR struct ftmac100_driver_s *priv = (FAR struct ftmac100_driver_s *)dev->d_private;
  934. #ifdef CONFIG_NET_IPv4
  935. ninfo("Bringing up: %d.%d.%d.%d\n",
  936. dev->d_ipaddr & 0xff, (dev->d_ipaddr >> 8) & 0xff,
  937. (dev->d_ipaddr >> 16) & 0xff, dev->d_ipaddr >> 24);
  938. #endif
  939. #ifdef CONFIG_NET_IPv6
  940. ninfo("Bringing up: %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
  941. dev->d_ipv6addr[0], dev->d_ipv6addr[1], dev->d_ipv6addr[2],
  942. dev->d_ipv6addr[3], dev->d_ipv6addr[4], dev->d_ipv6addr[5],
  943. dev->d_ipv6addr[6], dev->d_ipv6addr[7]);
  944. #endif
  945. /* Initialize PHYs, the Ethernet interface, and setup up Ethernet
  946. * interrupts.
  947. */
  948. ftmac100_init(priv);
  949. /* Instantiate the MAC address from priv->ft_dev.d_mac.ether.ether_addr_octet */
  950. ftmac100_set_mac(priv, priv->ft_dev.d_mac.ether.ether_addr_octet);
  951. #ifdef CONFIG_NET_ICMPv6
  952. /* Set up IPv6 multicast address filtering */
  953. ftmac100_ipv6multicast(priv);
  954. #endif
  955. /* Set and activate a timer process */
  956. (void)wd_start(priv->ft_txpoll, FTMAC100_WDDELAY, ftmac100_poll_expiry, 1,
  957. (wdparm_t)priv);
  958. /* Enable the Ethernet interrupt */
  959. priv->ft_bifup = true;
  960. up_enable_irq(CONFIG_FTMAC100_IRQ);
  961. return OK;
  962. }
  963. /****************************************************************************
  964. * Name: ftmac100_ifdown
  965. *
  966. * Description:
  967. * NuttX Callback: Stop the interface.
  968. *
  969. * Input Parameters:
  970. * dev - Reference to the NuttX driver state structure
  971. *
  972. * Returned Value:
  973. * None
  974. *
  975. * Assumptions:
  976. *
  977. ****************************************************************************/
  978. static int ftmac100_ifdown(struct net_driver_s *dev)
  979. {
  980. FAR struct ftmac100_driver_s *priv = (FAR struct ftmac100_driver_s *)dev->d_private;
  981. FAR struct ftmac100_register_s *iobase = (FAR struct ftmac100_register_s *)priv->iobase;
  982. irqstate_t flags;
  983. /* Disable the Ethernet interrupt */
  984. flags = enter_critical_section();
  985. up_disable_irq(CONFIG_FTMAC100_IRQ);
  986. /* Cancel the TX poll timer and TX timeout timers */
  987. wd_cancel(priv->ft_txpoll);
  988. wd_cancel(priv->ft_txtimeout);
  989. /* Put the EMAC in its reset, non-operational state. This should be
  990. * a known configuration that will guarantee the ftmac100_ifup() always
  991. * successfully brings the interface back up.
  992. */
  993. putreg32 (0, &iobase->maccr);
  994. /* Mark the device "down" */
  995. priv->ft_bifup = false;
  996. leave_critical_section(flags);
  997. return OK;
  998. }
  999. /****************************************************************************
  1000. * Name: ftmac100_txavail_work
  1001. *
  1002. * Description:
  1003. * Perform an out-of-cycle poll on the worker thread.
  1004. *
  1005. * Input Parameters:
  1006. * arg - Reference to the NuttX driver state structure (cast to void*)
  1007. *
  1008. * Returned Value:
  1009. * None
  1010. *
  1011. * Assumptions:
  1012. * Called on the higher priority worker thread.
  1013. *
  1014. ****************************************************************************/
  1015. static void ftmac100_txavail_work(FAR void *arg)
  1016. {
  1017. FAR struct ftmac100_driver_s *priv = (FAR struct ftmac100_driver_s *)arg;
  1018. /* Perform the poll */
  1019. net_lock();
  1020. /* Ignore the notification if the interface is not yet up */
  1021. if (priv->ft_bifup)
  1022. {
  1023. /* Check if there is room in the hardware to hold another outgoing packet. */
  1024. /* If so, then poll the network for new XMIT data */
  1025. (void)devif_poll(&priv->ft_dev, ftmac100_txpoll);
  1026. }
  1027. net_unlock();
  1028. }
  1029. /****************************************************************************
  1030. * Name: ftmac100_txavail
  1031. *
  1032. * Description:
  1033. * Driver callback invoked when new TX data is available. This is a
  1034. * stimulus perform an out-of-cycle poll and, thereby, reduce the TX
  1035. * latency.
  1036. *
  1037. * Input Parameters:
  1038. * dev - Reference to the NuttX driver state structure
  1039. *
  1040. * Returned Value:
  1041. * None
  1042. *
  1043. * Assumptions:
  1044. * Called in normal user mode
  1045. *
  1046. ****************************************************************************/
  1047. static int ftmac100_txavail(struct net_driver_s *dev)
  1048. {
  1049. FAR struct ftmac100_driver_s *priv = (FAR struct ftmac100_driver_s *)dev->d_private;
  1050. /* Is our single work structure available? It may not be if there are
  1051. * pending interrupt actions and we will have to ignore the Tx
  1052. * availability action.
  1053. */
  1054. if (work_available(&priv->ft_pollwork))
  1055. {
  1056. /* Schedule to serialize the poll on the worker thread. */
  1057. work_queue(FTMAWORK, &priv->ft_pollwork, ftmac100_txavail_work, priv, 0);
  1058. }
  1059. return OK;
  1060. }
  1061. /****************************************************************************
  1062. * Name: ftmac100_addmac
  1063. *
  1064. * Description:
  1065. * NuttX Callback: Add the specified MAC address to the hardware multicast
  1066. * address filtering
  1067. *
  1068. * Input Parameters:
  1069. * dev - Reference to the NuttX driver state structure
  1070. * mac - The MAC address to be added
  1071. *
  1072. * Returned Value:
  1073. * None
  1074. *
  1075. * Assumptions:
  1076. *
  1077. ****************************************************************************/
  1078. #if defined(CONFIG_NET_MCASTGROUP) || defined(CONFIG_NET_ICMPv6)
  1079. static int ftmac100_addmac(struct net_driver_s *dev, FAR const uint8_t *mac)
  1080. {
  1081. FAR struct ftmac100_driver_s *priv = (FAR struct ftmac100_driver_s *)dev->d_private;
  1082. FAR struct ftmac100_register_s *iobase = (FAR struct ftmac100_register_s *)priv->iobase;
  1083. uint32_t hash_value, hash_reg, hash_bit;
  1084. uint32_t mta;
  1085. /* Calculate Ethernet CRC32 for MAC */
  1086. hash_value = crc32part(mac, 6, ~0L);
  1087. /* The HASH Table is a register array of 2 32-bit registers.
  1088. * It is treated like an array of 64 bits. We want to set
  1089. * bit BitArray[hash_value]. So we figure out what register
  1090. * the bit is in, read it, OR in the new bit, then write
  1091. * back the new value. The register is determined by the
  1092. * upper 7 bits of the hash value and the bit within that
  1093. * register are determined by the lower 5 bits of the value.
  1094. */
  1095. hash_reg = (hash_value >> 31) & 0x1;
  1096. hash_bit = (hash_value >> 26) & 0x1f;
  1097. /* Add the MAC address to the hardware multicast routing table */
  1098. mta = getreg32(&iobase->maht0 + hash_reg);
  1099. mta |= (1 << hash_bit);
  1100. putreg32(mta, &iobase->maht0 + hash_reg);
  1101. return OK;
  1102. }
  1103. #endif
  1104. /****************************************************************************
  1105. * Name: ftmac100_rmmac
  1106. *
  1107. * Description:
  1108. * NuttX Callback: Remove the specified MAC address from the hardware multicast
  1109. * address filtering
  1110. *
  1111. * Input Parameters:
  1112. * dev - Reference to the NuttX driver state structure
  1113. * mac - The MAC address to be removed
  1114. *
  1115. * Returned Value:
  1116. * None
  1117. *
  1118. * Assumptions:
  1119. *
  1120. ****************************************************************************/
  1121. #ifdef CONFIG_NET_MCASTGROUP
  1122. static int ftmac100_rmmac(struct net_driver_s *dev, FAR const uint8_t *mac)
  1123. {
  1124. FAR struct ftmac100_driver_s *priv = (FAR struct ftmac100_driver_s *)dev->d_private;
  1125. FAR struct ftmac100_register_s *iobase = (FAR struct ftmac100_register_s *)priv->iobase;
  1126. uint32_t hash_value, hash_reg, hash_bit;
  1127. uint32_t mta;
  1128. /* Calculate Ethernet CRC32 for MAC */
  1129. hash_value = crc32part(mac, 6, ~0L);
  1130. hash_reg = (hash_value >> 31) & 0x1;
  1131. hash_bit = (hash_value >> 26) & 0x1f;
  1132. /* Remove the MAC address to the hardware multicast routing table */
  1133. mta = getreg32(&iobase->maht0 + hash_reg);
  1134. mta &= ~(1 << hash_bit);
  1135. putreg32(mta, &iobase->maht0 + hash_reg);
  1136. return OK;
  1137. }
  1138. #endif
  1139. /****************************************************************************
  1140. * Name: ftmac100_ipv6multicast
  1141. *
  1142. * Description:
  1143. * Configure the IPv6 multicast MAC address.
  1144. *
  1145. * Input Parameters:
  1146. * priv - A reference to the private driver state structure
  1147. *
  1148. * Returned Value:
  1149. * OK on success; Negated errno on failure.
  1150. *
  1151. * Assumptions:
  1152. *
  1153. ****************************************************************************/
  1154. #ifdef CONFIG_NET_ICMPv6
  1155. static void ftmac100_ipv6multicast(FAR struct ftmac100_driver_s *priv)
  1156. {
  1157. FAR struct net_driver_s *dev;
  1158. uint16_t tmp16;
  1159. uint8_t mac[6];
  1160. /* For ICMPv6, we need to add the IPv6 multicast address
  1161. *
  1162. * For IPv6 multicast addresses, the Ethernet MAC is derived by
  1163. * the four low-order octets OR'ed with the MAC 33:33:00:00:00:00,
  1164. * so for example the IPv6 address FF02:DEAD:BEEF::1:3 would map
  1165. * to the Ethernet MAC address 33:33:00:01:00:03.
  1166. *
  1167. * NOTES: This appears correct for the ICMPv6 Router Solicitation
  1168. * Message, but the ICMPv6 Neighbor Solicitation message seems to
  1169. * use 33:33:ff:01:00:03.
  1170. */
  1171. mac[0] = 0x33;
  1172. mac[1] = 0x33;
  1173. dev = &priv->ft_dev;
  1174. tmp16 = dev->d_ipv6addr[6];
  1175. mac[2] = 0xff;
  1176. mac[3] = tmp16 >> 8;
  1177. tmp16 = dev->d_ipv6addr[7];
  1178. mac[4] = tmp16 & 0xff;
  1179. mac[5] = tmp16 >> 8;
  1180. ninfo("IPv6 Multicast: %02x:%02x:%02x:%02x:%02x:%02x\n",
  1181. mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
  1182. (void)ftmac100_addmac(dev, mac);
  1183. #ifdef CONFIG_NET_ICMPv6_AUTOCONF
  1184. /* Add the IPv6 all link-local nodes Ethernet address. This is the
  1185. * address that we expect to receive ICMPv6 Router Advertisement
  1186. * packets.
  1187. */
  1188. (void)ftmac100_addmac(dev, g_ipv6_ethallnodes.ether_addr_octet);
  1189. #endif /* CONFIG_NET_ICMPv6_AUTOCONF */
  1190. #ifdef CONFIG_NET_ICMPv6_ROUTER
  1191. /* Add the IPv6 all link-local routers Ethernet address. This is the
  1192. * address that we expect to receive ICMPv6 Router Solicitation
  1193. * packets.
  1194. */
  1195. (void)ftmac100_addmac(dev, g_ipv6_ethallrouters.ether_addr_octet);
  1196. #endif /* CONFIG_NET_ICMPv6_ROUTER */
  1197. }
  1198. #endif /* CONFIG_NET_ICMPv6 */
  1199. /****************************************************************************
  1200. * Public Functions
  1201. ****************************************************************************/
  1202. /****************************************************************************
  1203. * Name: ftmac100_initialize
  1204. *
  1205. * Description:
  1206. * Initialize the Ethernet controller and driver
  1207. *
  1208. * Input Parameters:
  1209. * intf - In the case where there are multiple EMACs, this value
  1210. * identifies which EMAC is to be initialized.
  1211. *
  1212. * Returned Value:
  1213. * OK on success; Negated errno on failure.
  1214. *
  1215. * Assumptions:
  1216. *
  1217. ****************************************************************************/
  1218. int ftmac100_initialize(int intf)
  1219. {
  1220. struct ftmac100_driver_s *priv;
  1221. /* Get the interface structure associated with this interface number. */
  1222. DEBUGASSERT(intf < CONFIG_FTMAC100_NINTERFACES);
  1223. priv = &g_ftmac100[intf];
  1224. /* Attach the IRQ to the driver */
  1225. if (irq_attach(CONFIG_FTMAC100_IRQ, ftmac100_interrupt, NULL))
  1226. {
  1227. /* We could not attach the ISR to the interrupt */
  1228. return -EAGAIN;
  1229. }
  1230. /* Initialize the driver structure */
  1231. memset(priv, 0, sizeof(struct ftmac100_driver_s));
  1232. priv->ft_dev.d_buf = g_pktbuf; /* Single packet buffer */
  1233. priv->ft_dev.d_ifup = ftmac100_ifup; /* I/F up (new IP address) callback */
  1234. priv->ft_dev.d_ifdown = ftmac100_ifdown; /* I/F down callback */
  1235. priv->ft_dev.d_txavail = ftmac100_txavail; /* New TX data callback */
  1236. #ifdef CONFIG_NET_MCASTGROUP
  1237. priv->ft_dev.d_addmac = ftmac100_addmac; /* Add multicast MAC address */
  1238. priv->ft_dev.d_rmmac = ftmac100_rmmac; /* Remove multicast MAC address */
  1239. #endif
  1240. priv->ft_dev.d_private = (FAR void *)g_ftmac100; /* Used to recover private state from dev */
  1241. /* Create a watchdog for timing polling for and timing of transmissions */
  1242. priv->ft_txpoll = wd_create(); /* Create periodic poll timer */
  1243. priv->ft_txtimeout = wd_create(); /* Create TX timeout timer */
  1244. priv->iobase = CONFIG_FTMAC100_BASE;
  1245. /* Put the interface in the down state. This usually amounts to resetting
  1246. * the device and/or calling ftmac100_ifdown().
  1247. */
  1248. ftmac100_reset(priv);
  1249. /* Read the MAC address from the hardware into priv->ft_dev.d_mac.ether.ether_addr_octet */
  1250. memcpy(priv->ft_dev.d_mac.ether.ether_addr_octet, (void *)(CONFIG_FTMAC100_MAC0_ENV_ADDR), 6);
  1251. /* Register the device with the OS so that socket IOCTLs can be performed */
  1252. (void)netdev_register(&priv->ft_dev, NET_LL_ETHERNET);
  1253. return OK;
  1254. }
  1255. #endif /* CONFIG_NET && CONFIG_NET_FTMAC100 */