You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

smsc75xx.c 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574
  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. static 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. static 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 ) ) != 0 )
  304. goto err_mii_open;
  305. return 0;
  306. err_mii_open:
  307. err_set_filter:
  308. err_set_address:
  309. err_mac_tx:
  310. err_mac_rx:
  311. err_fct_tx_ctl:
  312. err_fct_rx_ctl:
  313. err_rfe_ctl:
  314. err_bulk_in_dly:
  315. err_int_ep_ctl:
  316. usbnet_close ( &smscusb->usbnet );
  317. err_open:
  318. err_hw_cfg:
  319. smsc75xx_reset ( smscusb );
  320. return rc;
  321. }
  322. /**
  323. * Close network device
  324. *
  325. * @v netdev Network device
  326. */
  327. static void smsc75xx_close ( struct net_device *netdev ) {
  328. struct smscusb_device *smscusb = netdev->priv;
  329. /* Close USB network device */
  330. usbnet_close ( &smscusb->usbnet );
  331. /* Dump statistics (for debugging) */
  332. smsc75xx_dump_statistics ( smscusb );
  333. /* Reset device */
  334. smsc75xx_reset ( smscusb );
  335. }
  336. /**
  337. * Transmit packet
  338. *
  339. * @v netdev Network device
  340. * @v iobuf I/O buffer
  341. * @ret rc Return status code
  342. */
  343. static int smsc75xx_transmit ( struct net_device *netdev,
  344. struct io_buffer *iobuf ) {
  345. struct smscusb_device *smscusb = netdev->priv;
  346. int rc;
  347. /* Transmit packet */
  348. if ( ( rc = smsc75xx_out_transmit ( smscusb, iobuf ) ) != 0 )
  349. return rc;
  350. return 0;
  351. }
  352. /**
  353. * Poll for completed and received packets
  354. *
  355. * @v netdev Network device
  356. */
  357. static void smsc75xx_poll ( struct net_device *netdev ) {
  358. struct smscusb_device *smscusb = netdev->priv;
  359. uint32_t int_sts;
  360. int rc;
  361. /* Poll USB bus */
  362. usb_poll ( smscusb->bus );
  363. /* Refill endpoints */
  364. if ( ( rc = usbnet_refill ( &smscusb->usbnet ) ) != 0 )
  365. netdev_rx_err ( netdev, NULL, rc );
  366. /* Do nothing more unless there are interrupts to handle */
  367. int_sts = smscusb->int_sts;
  368. if ( ! int_sts )
  369. return;
  370. /* Check link status if applicable */
  371. if ( int_sts & SMSC75XX_INT_STS_PHY_INT ) {
  372. smscusb_mii_check_link ( smscusb );
  373. int_sts &= ~SMSC75XX_INT_STS_PHY_INT;
  374. }
  375. /* Record RX FIFO overflow if applicable */
  376. if ( int_sts & SMSC75XX_INT_STS_RDFO_INT ) {
  377. DBGC2 ( smscusb, "SMSC75XX %p RX FIFO overflowed\n", smscusb );
  378. netdev_rx_err ( netdev, NULL, -ENOBUFS );
  379. int_sts &= ~SMSC75XX_INT_STS_RDFO_INT;
  380. }
  381. /* Check for unexpected interrupts */
  382. if ( int_sts ) {
  383. DBGC ( smscusb, "SMSC75XX %p unexpected interrupt %#08x\n",
  384. smscusb, int_sts );
  385. netdev_rx_err ( netdev, NULL, -ENOTTY );
  386. }
  387. /* Clear interrupts */
  388. if ( ( rc = smscusb_writel ( smscusb, SMSC75XX_INT_STS,
  389. smscusb->int_sts ) ) != 0 )
  390. netdev_rx_err ( netdev, NULL, rc );
  391. smscusb->int_sts = 0;
  392. }
  393. /** SMSC75xx network device operations */
  394. static struct net_device_operations smsc75xx_operations = {
  395. .open = smsc75xx_open,
  396. .close = smsc75xx_close,
  397. .transmit = smsc75xx_transmit,
  398. .poll = smsc75xx_poll,
  399. };
  400. /******************************************************************************
  401. *
  402. * USB interface
  403. *
  404. ******************************************************************************
  405. */
  406. /**
  407. * Probe device
  408. *
  409. * @v func USB function
  410. * @v config Configuration descriptor
  411. * @ret rc Return status code
  412. */
  413. static int smsc75xx_probe ( struct usb_function *func,
  414. struct usb_configuration_descriptor *config ) {
  415. struct net_device *netdev;
  416. struct smscusb_device *smscusb;
  417. int rc;
  418. /* Allocate and initialise structure */
  419. netdev = alloc_etherdev ( sizeof ( *smscusb ) );
  420. if ( ! netdev ) {
  421. rc = -ENOMEM;
  422. goto err_alloc;
  423. }
  424. netdev_init ( netdev, &smsc75xx_operations );
  425. netdev->dev = &func->dev;
  426. smscusb = netdev->priv;
  427. memset ( smscusb, 0, sizeof ( *smscusb ) );
  428. smscusb_init ( smscusb, netdev, func, &smsc75xx_in_operations );
  429. smscusb_mii_init ( smscusb, SMSC75XX_MII_BASE );
  430. usb_refill_init ( &smscusb->usbnet.in, 0, SMSC75XX_IN_MTU,
  431. SMSC75XX_IN_MAX_FILL );
  432. DBGC ( smscusb, "SMSC75XX %p on %s\n", smscusb, func->name );
  433. /* Describe USB network device */
  434. if ( ( rc = usbnet_describe ( &smscusb->usbnet, config ) ) != 0 ) {
  435. DBGC ( smscusb, "SMSC75XX %p could not describe: %s\n",
  436. smscusb, strerror ( rc ) );
  437. goto err_describe;
  438. }
  439. /* Reset device */
  440. if ( ( rc = smsc75xx_reset ( smscusb ) ) != 0 )
  441. goto err_reset;
  442. /* Read MAC address */
  443. if ( ( rc = smscusb_eeprom_fetch_mac ( smscusb,
  444. SMSC75XX_E2P_BASE ) ) != 0 )
  445. goto err_fetch_mac;
  446. /* Register network device */
  447. if ( ( rc = register_netdev ( netdev ) ) != 0 )
  448. goto err_register;
  449. usb_func_set_drvdata ( func, netdev );
  450. return 0;
  451. unregister_netdev ( netdev );
  452. err_register:
  453. err_fetch_mac:
  454. err_reset:
  455. err_describe:
  456. netdev_nullify ( netdev );
  457. netdev_put ( netdev );
  458. err_alloc:
  459. return rc;
  460. }
  461. /**
  462. * Remove device
  463. *
  464. * @v func USB function
  465. */
  466. static void smsc75xx_remove ( struct usb_function *func ) {
  467. struct net_device *netdev = usb_func_get_drvdata ( func );
  468. unregister_netdev ( netdev );
  469. netdev_nullify ( netdev );
  470. netdev_put ( netdev );
  471. }
  472. /** SMSC75xx device IDs */
  473. static struct usb_device_id smsc75xx_ids[] = {
  474. {
  475. .name = "smsc7500",
  476. .vendor = 0x0424,
  477. .product = 0x7500,
  478. },
  479. {
  480. .name = "smsc7505",
  481. .vendor = 0x0424,
  482. .product = 0x7505,
  483. },
  484. };
  485. /** SMSC LAN75xx driver */
  486. struct usb_driver smsc75xx_driver __usb_driver = {
  487. .ids = smsc75xx_ids,
  488. .id_count = ( sizeof ( smsc75xx_ids ) / sizeof ( smsc75xx_ids[0] ) ),
  489. .class = USB_CLASS_ID ( 0xff, 0x00, 0xff ),
  490. .score = USB_SCORE_NORMAL,
  491. .probe = smsc75xx_probe,
  492. .remove = smsc75xx_remove,
  493. };