Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

smsc75xx.c 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577
  1. /*
  2. * Copyright (C) 2015 Michael Brown <mbrown@fensystems.co.uk>.
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License as
  6. * published by the Free Software Foundation; either version 2 of the
  7. * License, or (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful, but
  10. * WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  17. * 02110-1301, USA.
  18. *
  19. * You can also choose to distribute this program under the terms of
  20. * the Unmodified Binary Distribution Licence (as given in the file
  21. * COPYING.UBDL), provided that you have satisfied its requirements.
  22. */
  23. FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
  24. #include <string.h>
  25. #include <unistd.h>
  26. #include <errno.h>
  27. #include <byteswap.h>
  28. #include <ipxe/ethernet.h>
  29. #include <ipxe/usb.h>
  30. #include <ipxe/usbnet.h>
  31. #include <ipxe/profile.h>
  32. #include "smsc75xx.h"
  33. /** @file
  34. *
  35. * SMSC LAN75xx USB Ethernet driver
  36. *
  37. */
  38. /** Bulk IN completion profiler */
  39. static struct profiler smsc75xx_in_profiler __profiler =
  40. { .name = "smsc75xx.in" };
  41. /** Bulk OUT profiler */
  42. static struct profiler smsc75xx_out_profiler __profiler =
  43. { .name = "smsc75xx.out" };
  44. /******************************************************************************
  45. *
  46. * Statistics (for debugging)
  47. *
  48. ******************************************************************************
  49. */
  50. /**
  51. * Dump statistics (for debugging)
  52. *
  53. * @v smscusb SMSC USB device
  54. * @ret rc Return status code
  55. */
  56. int smsc75xx_dump_statistics ( struct smscusb_device *smscusb ) {
  57. struct smsc75xx_statistics stats;
  58. int rc;
  59. /* Do nothing unless debugging is enabled */
  60. if ( ! DBG_LOG )
  61. return 0;
  62. /* Get statistics */
  63. if ( ( rc = smscusb_get_statistics ( smscusb, 0, &stats,
  64. sizeof ( stats ) ) ) != 0 ) {
  65. DBGC ( smscusb, "SMSC75XX %p could not get statistics: "
  66. "%s\n", smscusb, strerror ( rc ) );
  67. return rc;
  68. }
  69. /* Dump statistics */
  70. DBGC ( smscusb, "SMSC75XX %p RXE fcs %d aln %d frg %d jab %d und %d "
  71. "ovr %d drp %d\n", smscusb, le32_to_cpu ( stats.rx.err.fcs ),
  72. le32_to_cpu ( stats.rx.err.alignment ),
  73. le32_to_cpu ( stats.rx.err.fragment ),
  74. le32_to_cpu ( stats.rx.err.jabber ),
  75. le32_to_cpu ( stats.rx.err.undersize ),
  76. le32_to_cpu ( stats.rx.err.oversize ),
  77. le32_to_cpu ( stats.rx.err.dropped ) );
  78. DBGC ( smscusb, "SMSC75XX %p RXB ucast %d bcast %d mcast %d\n",
  79. smscusb, le32_to_cpu ( stats.rx.byte.unicast ),
  80. le32_to_cpu ( stats.rx.byte.broadcast ),
  81. le32_to_cpu ( stats.rx.byte.multicast ) );
  82. DBGC ( smscusb, "SMSC75XX %p RXF ucast %d bcast %d mcast %d pause "
  83. "%d\n", smscusb, le32_to_cpu ( stats.rx.frame.unicast ),
  84. le32_to_cpu ( stats.rx.frame.broadcast ),
  85. le32_to_cpu ( stats.rx.frame.multicast ),
  86. le32_to_cpu ( stats.rx.frame.pause ) );
  87. DBGC ( smscusb, "SMSC75XX %p TXE fcs %d def %d car %d cnt %d sgl %d "
  88. "mul %d exc %d lat %d\n", smscusb,
  89. le32_to_cpu ( stats.tx.err.fcs ),
  90. le32_to_cpu ( stats.tx.err.deferral ),
  91. le32_to_cpu ( stats.tx.err.carrier ),
  92. le32_to_cpu ( stats.tx.err.count ),
  93. le32_to_cpu ( stats.tx.err.single ),
  94. le32_to_cpu ( stats.tx.err.multiple ),
  95. le32_to_cpu ( stats.tx.err.excessive ),
  96. le32_to_cpu ( stats.tx.err.late ) );
  97. DBGC ( smscusb, "SMSC75XX %p TXB ucast %d bcast %d mcast %d\n",
  98. smscusb, le32_to_cpu ( stats.tx.byte.unicast ),
  99. le32_to_cpu ( stats.tx.byte.broadcast ),
  100. le32_to_cpu ( stats.tx.byte.multicast ) );
  101. DBGC ( smscusb, "SMSC75XX %p TXF ucast %d bcast %d mcast %d pause "
  102. "%d\n", smscusb, le32_to_cpu ( stats.tx.frame.unicast ),
  103. le32_to_cpu ( stats.tx.frame.broadcast ),
  104. le32_to_cpu ( stats.tx.frame.multicast ),
  105. le32_to_cpu ( stats.tx.frame.pause ) );
  106. return 0;
  107. }
  108. /******************************************************************************
  109. *
  110. * Device reset
  111. *
  112. ******************************************************************************
  113. */
  114. /**
  115. * Reset device
  116. *
  117. * @v smscusb SMSC USB device
  118. * @ret rc Return status code
  119. */
  120. static int smsc75xx_reset ( struct smscusb_device *smscusb ) {
  121. uint32_t hw_cfg;
  122. unsigned int i;
  123. int rc;
  124. /* Reset device */
  125. if ( ( rc = smscusb_writel ( smscusb, SMSC75XX_HW_CFG,
  126. SMSC75XX_HW_CFG_LRST ) ) != 0 )
  127. return rc;
  128. /* Wait for reset to complete */
  129. for ( i = 0 ; i < SMSC75XX_RESET_MAX_WAIT_MS ; i++ ) {
  130. /* Check if reset has completed */
  131. if ( ( rc = smscusb_readl ( smscusb, SMSC75XX_HW_CFG,
  132. &hw_cfg ) ) != 0 )
  133. return rc;
  134. if ( ! ( hw_cfg & SMSC75XX_HW_CFG_LRST ) )
  135. return 0;
  136. /* Delay */
  137. mdelay ( 1 );
  138. }
  139. DBGC ( smscusb, "SMSC75XX %p timed out waiting for reset\n",
  140. smscusb );
  141. return -ETIMEDOUT;
  142. }
  143. /******************************************************************************
  144. *
  145. * Endpoint operations
  146. *
  147. ******************************************************************************
  148. */
  149. /**
  150. * Complete bulk IN transfer
  151. *
  152. * @v ep USB endpoint
  153. * @v iobuf I/O buffer
  154. * @v rc Completion status code
  155. */
  156. static void smsc75xx_in_complete ( struct usb_endpoint *ep,
  157. struct io_buffer *iobuf, int rc ) {
  158. struct smscusb_device *smscusb =
  159. container_of ( ep, struct smscusb_device, usbnet.in );
  160. struct net_device *netdev = smscusb->netdev;
  161. struct smsc75xx_rx_header *header;
  162. /* Profile completions */
  163. profile_start ( &smsc75xx_in_profiler );
  164. /* Ignore packets cancelled when the endpoint closes */
  165. if ( ! ep->open ) {
  166. free_iob ( iobuf );
  167. return;
  168. }
  169. /* Record USB errors against the network device */
  170. if ( rc != 0 ) {
  171. DBGC ( smscusb, "SMSC75XX %p bulk IN failed: %s\n",
  172. smscusb, strerror ( rc ) );
  173. goto err;
  174. }
  175. /* Sanity check */
  176. if ( iob_len ( iobuf ) < ( sizeof ( *header ) ) ) {
  177. DBGC ( smscusb, "SMSC75XX %p underlength bulk IN\n",
  178. smscusb );
  179. DBGC_HDA ( smscusb, 0, iobuf->data, iob_len ( iobuf ) );
  180. rc = -EINVAL;
  181. goto err;
  182. }
  183. /* Strip header */
  184. header = iobuf->data;
  185. iob_pull ( iobuf, sizeof ( *header ) );
  186. /* Check for errors */
  187. if ( header->command & cpu_to_le32 ( SMSC75XX_RX_RED ) ) {
  188. DBGC ( smscusb, "SMSC75XX %p receive error (%08x):\n",
  189. smscusb, le32_to_cpu ( header->command ) );
  190. DBGC_HDA ( smscusb, 0, iobuf->data, iob_len ( iobuf ) );
  191. rc = -EIO;
  192. goto err;
  193. }
  194. /* Hand off to network stack */
  195. netdev_rx ( netdev, iob_disown ( iobuf ) );
  196. profile_stop ( &smsc75xx_in_profiler );
  197. return;
  198. err:
  199. /* Hand off to network stack */
  200. netdev_rx_err ( netdev, iob_disown ( iobuf ), rc );
  201. }
  202. /** Bulk IN endpoint operations */
  203. struct usb_endpoint_driver_operations smsc75xx_in_operations = {
  204. .complete = smsc75xx_in_complete,
  205. };
  206. /**
  207. * Transmit packet
  208. *
  209. * @v smscusb SMSC USB device
  210. * @v iobuf I/O buffer
  211. * @ret rc Return status code
  212. */
  213. static int smsc75xx_out_transmit ( struct smscusb_device *smscusb,
  214. struct io_buffer *iobuf ) {
  215. struct smsc75xx_tx_header *header;
  216. size_t len = iob_len ( iobuf );
  217. int rc;
  218. /* Profile transmissions */
  219. profile_start ( &smsc75xx_out_profiler );
  220. /* Prepend header */
  221. if ( ( rc = iob_ensure_headroom ( iobuf, sizeof ( *header ) ) ) != 0 )
  222. return rc;
  223. header = iob_push ( iobuf, sizeof ( *header ) );
  224. header->command = cpu_to_le32 ( SMSC75XX_TX_FCS | len );
  225. header->tag = 0;
  226. header->mss = 0;
  227. /* Enqueue I/O buffer */
  228. if ( ( rc = usb_stream ( &smscusb->usbnet.out, iobuf, 0 ) ) != 0 )
  229. return rc;
  230. profile_stop ( &smsc75xx_out_profiler );
  231. return 0;
  232. }
  233. /******************************************************************************
  234. *
  235. * Network device interface
  236. *
  237. ******************************************************************************
  238. */
  239. /**
  240. * Open network device
  241. *
  242. * @v netdev Network device
  243. * @ret rc Return status code
  244. */
  245. static int smsc75xx_open ( struct net_device *netdev ) {
  246. struct smscusb_device *smscusb = netdev->priv;
  247. int rc;
  248. /* Clear stored interrupt status */
  249. smscusb->int_sts = 0;
  250. /* Configure bulk IN empty response */
  251. if ( ( rc = smscusb_writel ( smscusb, SMSC75XX_HW_CFG,
  252. SMSC75XX_HW_CFG_BIR ) ) != 0 )
  253. goto err_hw_cfg;
  254. /* Open USB network device */
  255. if ( ( rc = usbnet_open ( &smscusb->usbnet ) ) != 0 ) {
  256. DBGC ( smscusb, "SMSC75XX %p could not open: %s\n",
  257. smscusb, strerror ( rc ) );
  258. goto err_open;
  259. }
  260. /* Configure interrupt endpoint */
  261. if ( ( rc = smscusb_writel ( smscusb, SMSC75XX_INT_EP_CTL,
  262. ( SMSC75XX_INT_EP_CTL_RDFO_EN |
  263. SMSC75XX_INT_EP_CTL_PHY_EN ) ) ) != 0 )
  264. goto err_int_ep_ctl;
  265. /* Configure bulk IN delay */
  266. if ( ( rc = smscusb_writel ( smscusb, SMSC75XX_BULK_IN_DLY,
  267. SMSC75XX_BULK_IN_DLY_SET ( 0 ) ) ) != 0 )
  268. goto err_bulk_in_dly;
  269. /* Configure receive filters */
  270. if ( ( rc = smscusb_writel ( smscusb, SMSC75XX_RFE_CTL,
  271. ( SMSC75XX_RFE_CTL_AB |
  272. SMSC75XX_RFE_CTL_AM |
  273. SMSC75XX_RFE_CTL_AU ) ) ) != 0 )
  274. goto err_rfe_ctl;
  275. /* Configure receive FIFO */
  276. if ( ( rc = smscusb_writel ( smscusb, SMSC75XX_FCT_RX_CTL,
  277. ( SMSC75XX_FCT_RX_CTL_EN |
  278. SMSC75XX_FCT_RX_CTL_BAD ) ) ) != 0 )
  279. goto err_fct_rx_ctl;
  280. /* Configure transmit FIFO */
  281. if ( ( rc = smscusb_writel ( smscusb, SMSC75XX_FCT_TX_CTL,
  282. SMSC75XX_FCT_TX_CTL_EN ) ) != 0 )
  283. goto err_fct_tx_ctl;
  284. /* Configure receive datapath */
  285. if ( ( rc = smscusb_writel ( smscusb, SMSC75XX_MAC_RX,
  286. ( SMSC75XX_MAC_RX_MAX_SIZE_DEFAULT |
  287. SMSC75XX_MAC_RX_FCS |
  288. SMSC75XX_MAC_RX_EN ) ) ) != 0 )
  289. goto err_mac_rx;
  290. /* Configure transmit datapath */
  291. if ( ( rc = smscusb_writel ( smscusb, SMSC75XX_MAC_TX,
  292. SMSC75XX_MAC_TX_EN ) ) != 0 )
  293. goto err_mac_tx;
  294. /* Set MAC address */
  295. if ( ( rc = smscusb_set_address ( smscusb,
  296. SMSC75XX_RX_ADDR_BASE ) ) != 0 )
  297. goto err_set_address;
  298. /* Set MAC address perfect filter */
  299. if ( ( rc = smscusb_set_filter ( smscusb,
  300. SMSC75XX_ADDR_FILT_BASE ) ) != 0 )
  301. goto err_set_filter;
  302. /* Enable PHY interrupts and update link status */
  303. if ( ( rc = smscusb_mii_open ( smscusb, SMSC75XX_MII_PHY_INTR_MASK,
  304. ( SMSC75XX_PHY_INTR_ANEG_DONE |
  305. SMSC75XX_PHY_INTR_LINK_DOWN ) ) ) != 0)
  306. goto err_mii_open;
  307. return 0;
  308. err_mii_open:
  309. err_set_filter:
  310. err_set_address:
  311. err_mac_tx:
  312. err_mac_rx:
  313. err_fct_tx_ctl:
  314. err_fct_rx_ctl:
  315. err_rfe_ctl:
  316. err_bulk_in_dly:
  317. err_int_ep_ctl:
  318. usbnet_close ( &smscusb->usbnet );
  319. err_open:
  320. err_hw_cfg:
  321. smsc75xx_reset ( smscusb );
  322. return rc;
  323. }
  324. /**
  325. * Close network device
  326. *
  327. * @v netdev Network device
  328. */
  329. static void smsc75xx_close ( struct net_device *netdev ) {
  330. struct smscusb_device *smscusb = netdev->priv;
  331. /* Close USB network device */
  332. usbnet_close ( &smscusb->usbnet );
  333. /* Dump statistics (for debugging) */
  334. if ( DBG_LOG )
  335. smsc75xx_dump_statistics ( smscusb );
  336. /* Reset device */
  337. smsc75xx_reset ( smscusb );
  338. }
  339. /**
  340. * Transmit packet
  341. *
  342. * @v netdev Network device
  343. * @v iobuf I/O buffer
  344. * @ret rc Return status code
  345. */
  346. int smsc75xx_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) {
  347. struct smscusb_device *smscusb = netdev->priv;
  348. int rc;
  349. /* Transmit packet */
  350. if ( ( rc = smsc75xx_out_transmit ( smscusb, iobuf ) ) != 0 )
  351. return rc;
  352. return 0;
  353. }
  354. /**
  355. * Poll for completed and received packets
  356. *
  357. * @v netdev Network device
  358. */
  359. void smsc75xx_poll ( struct net_device *netdev ) {
  360. struct smscusb_device *smscusb = netdev->priv;
  361. uint32_t int_sts;
  362. int rc;
  363. /* Poll USB bus */
  364. usb_poll ( smscusb->bus );
  365. /* Refill endpoints */
  366. if ( ( rc = usbnet_refill ( &smscusb->usbnet ) ) != 0 )
  367. netdev_rx_err ( netdev, NULL, rc );
  368. /* Do nothing more unless there are interrupts to handle */
  369. int_sts = smscusb->int_sts;
  370. if ( ! int_sts )
  371. return;
  372. /* Check link status if applicable */
  373. if ( int_sts & SMSC75XX_INT_STS_PHY_INT ) {
  374. smscusb_mii_check_link ( smscusb );
  375. int_sts &= ~SMSC75XX_INT_STS_PHY_INT;
  376. }
  377. /* Record RX FIFO overflow if applicable */
  378. if ( int_sts & SMSC75XX_INT_STS_RDFO_INT ) {
  379. DBGC2 ( smscusb, "SMSC75XX %p RX FIFO overflowed\n", smscusb );
  380. netdev_rx_err ( netdev, NULL, -ENOBUFS );
  381. int_sts &= ~SMSC75XX_INT_STS_RDFO_INT;
  382. }
  383. /* Check for unexpected interrupts */
  384. if ( int_sts ) {
  385. DBGC ( smscusb, "SMSC75XX %p unexpected interrupt %#08x\n",
  386. smscusb, int_sts );
  387. netdev_rx_err ( netdev, NULL, -ENOTTY );
  388. }
  389. /* Clear interrupts */
  390. if ( ( rc = smscusb_writel ( smscusb, SMSC75XX_INT_STS,
  391. smscusb->int_sts ) ) != 0 )
  392. netdev_rx_err ( netdev, NULL, rc );
  393. smscusb->int_sts = 0;
  394. }
  395. /** SMSC75xx network device operations */
  396. static struct net_device_operations smsc75xx_operations = {
  397. .open = smsc75xx_open,
  398. .close = smsc75xx_close,
  399. .transmit = smsc75xx_transmit,
  400. .poll = smsc75xx_poll,
  401. };
  402. /******************************************************************************
  403. *
  404. * USB interface
  405. *
  406. ******************************************************************************
  407. */
  408. /**
  409. * Probe device
  410. *
  411. * @v func USB function
  412. * @v config Configuration descriptor
  413. * @ret rc Return status code
  414. */
  415. static int smsc75xx_probe ( struct usb_function *func,
  416. struct usb_configuration_descriptor *config ) {
  417. struct net_device *netdev;
  418. struct smscusb_device *smscusb;
  419. int rc;
  420. /* Allocate and initialise structure */
  421. netdev = alloc_etherdev ( sizeof ( *smscusb ) );
  422. if ( ! netdev ) {
  423. rc = -ENOMEM;
  424. goto err_alloc;
  425. }
  426. netdev_init ( netdev, &smsc75xx_operations );
  427. netdev->dev = &func->dev;
  428. smscusb = netdev->priv;
  429. memset ( smscusb, 0, sizeof ( *smscusb ) );
  430. smscusb_init ( smscusb, netdev, func, &smsc75xx_in_operations );
  431. smscusb_mii_init ( smscusb, SMSC75XX_MII_BASE,
  432. SMSC75XX_MII_PHY_INTR_SOURCE );
  433. usb_refill_init ( &smscusb->usbnet.in, 0, SMSC75XX_IN_MTU,
  434. SMSC75XX_IN_MAX_FILL );
  435. DBGC ( smscusb, "SMSC75XX %p on %s\n", smscusb, func->name );
  436. /* Describe USB network device */
  437. if ( ( rc = usbnet_describe ( &smscusb->usbnet, config ) ) != 0 ) {
  438. DBGC ( smscusb, "SMSC75XX %p could not describe: %s\n",
  439. smscusb, strerror ( rc ) );
  440. goto err_describe;
  441. }
  442. /* Reset device */
  443. if ( ( rc = smsc75xx_reset ( smscusb ) ) != 0 )
  444. goto err_reset;
  445. /* Read MAC address */
  446. if ( ( rc = smscusb_eeprom_fetch_mac ( smscusb,
  447. SMSC75XX_E2P_BASE ) ) != 0 )
  448. goto err_fetch_mac;
  449. /* Register network device */
  450. if ( ( rc = register_netdev ( netdev ) ) != 0 )
  451. goto err_register;
  452. usb_func_set_drvdata ( func, netdev );
  453. return 0;
  454. unregister_netdev ( netdev );
  455. err_register:
  456. err_fetch_mac:
  457. err_reset:
  458. err_describe:
  459. netdev_nullify ( netdev );
  460. netdev_put ( netdev );
  461. err_alloc:
  462. return rc;
  463. }
  464. /**
  465. * Remove device
  466. *
  467. * @v func USB function
  468. */
  469. static void smsc75xx_remove ( struct usb_function *func ) {
  470. struct net_device *netdev = usb_func_get_drvdata ( func );
  471. unregister_netdev ( netdev );
  472. netdev_nullify ( netdev );
  473. netdev_put ( netdev );
  474. }
  475. /** SMSC75xx device IDs */
  476. static struct usb_device_id smsc75xx_ids[] = {
  477. {
  478. .name = "smsc7500",
  479. .vendor = 0x0424,
  480. .product = 0x7500,
  481. },
  482. {
  483. .name = "smsc7505",
  484. .vendor = 0x0424,
  485. .product = 0x7505,
  486. },
  487. };
  488. /** SMSC LAN75xx driver */
  489. struct usb_driver smsc75xx_driver __usb_driver = {
  490. .ids = smsc75xx_ids,
  491. .id_count = ( sizeof ( smsc75xx_ids ) / sizeof ( smsc75xx_ids[0] ) ),
  492. .class = USB_CLASS_ID ( 0xff, 0x00, 0xff ),
  493. .score = USB_SCORE_NORMAL,
  494. .probe = smsc75xx_probe,
  495. .remove = smsc75xx_remove,
  496. };