Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

smscusb.c 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523
  1. /*
  2. * Copyright (C) 2017 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 <errno.h>
  26. #include <unistd.h>
  27. #include <ipxe/usb.h>
  28. #include <ipxe/usbnet.h>
  29. #include <ipxe/ethernet.h>
  30. #include <ipxe/profile.h>
  31. #include "smscusb.h"
  32. /** @file
  33. *
  34. * SMSC USB Ethernet drivers
  35. *
  36. */
  37. /** Interrupt completion profiler */
  38. static struct profiler smscusb_intr_profiler __profiler =
  39. { .name = "smscusb.intr" };
  40. /******************************************************************************
  41. *
  42. * EEPROM access
  43. *
  44. ******************************************************************************
  45. */
  46. /**
  47. * Wait for EEPROM to become idle
  48. *
  49. * @v smscusb SMSC USB device
  50. * @v e2p_base E2P register base
  51. * @ret rc Return status code
  52. */
  53. static int smscusb_eeprom_wait ( struct smscusb_device *smscusb,
  54. unsigned int e2p_base ) {
  55. uint32_t e2p_cmd;
  56. unsigned int i;
  57. int rc;
  58. /* Wait for EPC_BSY to become clear */
  59. for ( i = 0 ; i < SMSCUSB_EEPROM_MAX_WAIT_MS ; i++ ) {
  60. /* Read E2P_CMD and check EPC_BSY */
  61. if ( ( rc = smscusb_readl ( smscusb,
  62. ( e2p_base + SMSCUSB_E2P_CMD ),
  63. &e2p_cmd ) ) != 0 )
  64. return rc;
  65. if ( ! ( e2p_cmd & SMSCUSB_E2P_CMD_EPC_BSY ) )
  66. return 0;
  67. /* Delay */
  68. mdelay ( 1 );
  69. }
  70. DBGC ( smscusb, "SMSCUSB %p timed out waiting for EEPROM\n",
  71. smscusb );
  72. return -ETIMEDOUT;
  73. }
  74. /**
  75. * Read byte from EEPROM
  76. *
  77. * @v smscusb SMSC USB device
  78. * @v e2p_base E2P register base
  79. * @v address EEPROM address
  80. * @ret byte Byte read, or negative error
  81. */
  82. static int smscusb_eeprom_read_byte ( struct smscusb_device *smscusb,
  83. unsigned int e2p_base,
  84. unsigned int address ) {
  85. uint32_t e2p_cmd;
  86. uint32_t e2p_data;
  87. int rc;
  88. /* Wait for EEPROM to become idle */
  89. if ( ( rc = smscusb_eeprom_wait ( smscusb, e2p_base ) ) != 0 )
  90. return rc;
  91. /* Initiate read command */
  92. e2p_cmd = ( SMSCUSB_E2P_CMD_EPC_BSY | SMSCUSB_E2P_CMD_EPC_CMD_READ |
  93. SMSCUSB_E2P_CMD_EPC_ADDR ( address ) );
  94. if ( ( rc = smscusb_writel ( smscusb, ( e2p_base + SMSCUSB_E2P_CMD ),
  95. e2p_cmd ) ) != 0 )
  96. return rc;
  97. /* Wait for command to complete */
  98. if ( ( rc = smscusb_eeprom_wait ( smscusb, e2p_base ) ) != 0 )
  99. return rc;
  100. /* Read EEPROM data */
  101. if ( ( rc = smscusb_readl ( smscusb, ( e2p_base + SMSCUSB_E2P_DATA ),
  102. &e2p_data ) ) != 0 )
  103. return rc;
  104. return SMSCUSB_E2P_DATA_GET ( e2p_data );
  105. }
  106. /**
  107. * Read data from EEPROM
  108. *
  109. * @v smscusb SMSC USB device
  110. * @v e2p_base E2P register base
  111. * @v address EEPROM address
  112. * @v data Data buffer
  113. * @v len Length of data
  114. * @ret rc Return status code
  115. */
  116. static int smscusb_eeprom_read ( struct smscusb_device *smscusb,
  117. unsigned int e2p_base, unsigned int address,
  118. void *data, size_t len ) {
  119. uint8_t *bytes;
  120. int byte;
  121. /* Read bytes */
  122. for ( bytes = data ; len-- ; address++, bytes++ ) {
  123. byte = smscusb_eeprom_read_byte ( smscusb, e2p_base, address );
  124. if ( byte < 0 )
  125. return byte;
  126. *bytes = byte;
  127. }
  128. return 0;
  129. }
  130. /**
  131. * Fetch MAC address from EEPROM
  132. *
  133. * @v smscusb SMSC USB device
  134. * @v e2p_base E2P register base
  135. * @ret rc Return status code
  136. */
  137. int smscusb_eeprom_fetch_mac ( struct smscusb_device *smscusb,
  138. unsigned int e2p_base ) {
  139. struct net_device *netdev = smscusb->netdev;
  140. int rc;
  141. /* Read MAC address from EEPROM */
  142. if ( ( rc = smscusb_eeprom_read ( smscusb, e2p_base, SMSCUSB_EEPROM_MAC,
  143. netdev->hw_addr, ETH_ALEN ) ) != 0 )
  144. return rc;
  145. /* Check that EEPROM is physically present */
  146. if ( ! is_valid_ether_addr ( netdev->hw_addr ) ) {
  147. DBGC ( smscusb, "SMSCUSB %p has no EEPROM (%s)\n",
  148. smscusb, eth_ntoa ( netdev->hw_addr ) );
  149. return -ENODEV;
  150. }
  151. DBGC ( smscusb, "SMSCUSB %p using EEPROM MAC %s\n",
  152. smscusb, eth_ntoa ( netdev->hw_addr ) );
  153. return 0;
  154. }
  155. /******************************************************************************
  156. *
  157. * MII access
  158. *
  159. ******************************************************************************
  160. */
  161. /**
  162. * Wait for MII to become idle
  163. *
  164. * @v smscusb SMSC USB device
  165. * @ret rc Return status code
  166. */
  167. static int smscusb_mii_wait ( struct smscusb_device *smscusb ) {
  168. unsigned int base = smscusb->mii_base;
  169. uint32_t mii_access;
  170. unsigned int i;
  171. int rc;
  172. /* Wait for MIIBZY to become clear */
  173. for ( i = 0 ; i < SMSCUSB_MII_MAX_WAIT_MS ; i++ ) {
  174. /* Read MII_ACCESS and check MIIBZY */
  175. if ( ( rc = smscusb_readl ( smscusb,
  176. ( base + SMSCUSB_MII_ACCESS ),
  177. &mii_access ) ) != 0 )
  178. return rc;
  179. if ( ! ( mii_access & SMSCUSB_MII_ACCESS_MIIBZY ) )
  180. return 0;
  181. /* Delay */
  182. mdelay ( 1 );
  183. }
  184. DBGC ( smscusb, "SMSCUSB %p timed out waiting for MII\n",
  185. smscusb );
  186. return -ETIMEDOUT;
  187. }
  188. /**
  189. * Read from MII register
  190. *
  191. * @v mii MII interface
  192. * @v reg Register address
  193. * @ret value Data read, or negative error
  194. */
  195. static int smscusb_mii_read ( struct mii_interface *mii, unsigned int reg ) {
  196. struct smscusb_device *smscusb =
  197. container_of ( mii, struct smscusb_device, mii );
  198. unsigned int base = smscusb->mii_base;
  199. uint32_t mii_access;
  200. uint32_t mii_data;
  201. int rc;
  202. /* Wait for MII to become idle */
  203. if ( ( rc = smscusb_mii_wait ( smscusb ) ) != 0 )
  204. return rc;
  205. /* Initiate read command */
  206. mii_access = ( SMSCUSB_MII_ACCESS_PHY_ADDRESS |
  207. SMSCUSB_MII_ACCESS_MIIRINDA ( reg ) |
  208. SMSCUSB_MII_ACCESS_MIIBZY );
  209. if ( ( rc = smscusb_writel ( smscusb, ( base + SMSCUSB_MII_ACCESS ),
  210. mii_access ) ) != 0 )
  211. return rc;
  212. /* Wait for command to complete */
  213. if ( ( rc = smscusb_mii_wait ( smscusb ) ) != 0 )
  214. return rc;
  215. /* Read MII data */
  216. if ( ( rc = smscusb_readl ( smscusb, ( base + SMSCUSB_MII_DATA ),
  217. &mii_data ) ) != 0 )
  218. return rc;
  219. return SMSCUSB_MII_DATA_GET ( mii_data );
  220. }
  221. /**
  222. * Write to MII register
  223. *
  224. * @v mii MII interface
  225. * @v reg Register address
  226. * @v data Data to write
  227. * @ret rc Return status code
  228. */
  229. static int smscusb_mii_write ( struct mii_interface *mii, unsigned int reg,
  230. unsigned int data ) {
  231. struct smscusb_device *smscusb =
  232. container_of ( mii, struct smscusb_device, mii );
  233. unsigned int base = smscusb->mii_base;
  234. uint32_t mii_access;
  235. uint32_t mii_data;
  236. int rc;
  237. /* Wait for MII to become idle */
  238. if ( ( rc = smscusb_mii_wait ( smscusb ) ) != 0 )
  239. return rc;
  240. /* Write MII data */
  241. mii_data = SMSCUSB_MII_DATA_SET ( data );
  242. if ( ( rc = smscusb_writel ( smscusb, ( base + SMSCUSB_MII_DATA ),
  243. mii_data ) ) != 0 )
  244. return rc;
  245. /* Initiate write command */
  246. mii_access = ( SMSCUSB_MII_ACCESS_PHY_ADDRESS |
  247. SMSCUSB_MII_ACCESS_MIIRINDA ( reg ) |
  248. SMSCUSB_MII_ACCESS_MIIWNR |
  249. SMSCUSB_MII_ACCESS_MIIBZY );
  250. if ( ( rc = smscusb_writel ( smscusb, ( base + SMSCUSB_MII_ACCESS ),
  251. mii_access ) ) != 0 )
  252. return rc;
  253. /* Wait for command to complete */
  254. if ( ( rc = smscusb_mii_wait ( smscusb ) ) != 0 )
  255. return rc;
  256. return 0;
  257. }
  258. /** MII operations */
  259. struct mii_operations smscusb_mii_operations = {
  260. .read = smscusb_mii_read,
  261. .write = smscusb_mii_write,
  262. };
  263. /**
  264. * Check link status
  265. *
  266. * @v smscusb SMSC USB device
  267. * @ret rc Return status code
  268. */
  269. int smscusb_mii_check_link ( struct smscusb_device *smscusb ) {
  270. struct net_device *netdev = smscusb->netdev;
  271. int intr;
  272. int rc;
  273. /* Read PHY interrupt source */
  274. intr = mii_read ( &smscusb->mii, SMSCUSB_MII_PHY_INTR_SOURCE );
  275. if ( intr < 0 ) {
  276. rc = intr;
  277. DBGC ( smscusb, "SMSCUSB %p could not get PHY interrupt "
  278. "source: %s\n", smscusb, strerror ( rc ) );
  279. return rc;
  280. }
  281. /* Acknowledge PHY interrupt */
  282. if ( ( rc = mii_write ( &smscusb->mii, SMSCUSB_MII_PHY_INTR_SOURCE,
  283. intr ) ) != 0 ) {
  284. DBGC ( smscusb, "SMSCUSB %p could not acknowledge PHY "
  285. "interrupt: %s\n", smscusb, strerror ( rc ) );
  286. return rc;
  287. }
  288. /* Check link status */
  289. if ( ( rc = mii_check_link ( &smscusb->mii, netdev ) ) != 0 ) {
  290. DBGC ( smscusb, "SMSCUSB %p could not check link: %s\n",
  291. smscusb, strerror ( rc ) );
  292. return rc;
  293. }
  294. DBGC ( smscusb, "SMSCUSB %p link %s (intr %#04x)\n",
  295. smscusb, ( netdev_link_ok ( netdev ) ? "up" : "down" ), intr );
  296. return 0;
  297. }
  298. /**
  299. * Enable PHY interrupts and update link status
  300. *
  301. * @v smscusb SMSC USB device
  302. * @ret rc Return status code
  303. */
  304. int smscusb_mii_open ( struct smscusb_device *smscusb ) {
  305. int rc;
  306. /* Enable PHY interrupts */
  307. if ( ( rc = mii_write ( &smscusb->mii, SMSCUSB_MII_PHY_INTR_MASK,
  308. ( SMSCUSB_PHY_INTR_ANEG_DONE |
  309. SMSCUSB_PHY_INTR_LINK_DOWN ) ) ) != 0 ) {
  310. DBGC ( smscusb, "SMSCUSB %p could not set PHY interrupt "
  311. "mask: %s\n", smscusb, strerror ( rc ) );
  312. return rc;
  313. }
  314. /* Update link status */
  315. smscusb_mii_check_link ( smscusb );
  316. return 0;
  317. }
  318. /******************************************************************************
  319. *
  320. * Receive filtering
  321. *
  322. ******************************************************************************
  323. */
  324. /**
  325. * Set receive address
  326. *
  327. * @v smscusb SMSC USB device
  328. * @v addr_base Receive address register base
  329. * @ret rc Return status code
  330. */
  331. int smscusb_set_address ( struct smscusb_device *smscusb,
  332. unsigned int addr_base ) {
  333. struct net_device *netdev = smscusb->netdev;
  334. union smscusb_mac mac;
  335. int rc;
  336. /* Copy MAC address */
  337. memset ( &mac, 0, sizeof ( mac ) );
  338. memcpy ( mac.raw, netdev->ll_addr, ETH_ALEN );
  339. /* Write MAC address high register */
  340. if ( ( rc = smscusb_raw_writel ( smscusb,
  341. ( addr_base + SMSCUSB_RX_ADDRH ),
  342. mac.addr.h ) ) != 0 )
  343. return rc;
  344. /* Write MAC address low register */
  345. if ( ( rc = smscusb_raw_writel ( smscusb,
  346. ( addr_base + SMSCUSB_RX_ADDRL ),
  347. mac.addr.l ) ) != 0 )
  348. return rc;
  349. return 0;
  350. }
  351. /**
  352. * Set receive filter
  353. *
  354. * @v smscusb SMSC USB device
  355. * @v filt_base Receive filter register base
  356. * @ret rc Return status code
  357. */
  358. int smscusb_set_filter ( struct smscusb_device *smscusb,
  359. unsigned int filt_base ) {
  360. struct net_device *netdev = smscusb->netdev;
  361. union smscusb_mac mac;
  362. int rc;
  363. /* Copy MAC address */
  364. memset ( &mac, 0, sizeof ( mac ) );
  365. memcpy ( mac.raw, netdev->ll_addr, ETH_ALEN );
  366. mac.addr.h |= cpu_to_le32 ( SMSCUSB_ADDR_FILTH_VALID );
  367. /* Write MAC address perfect filter high register */
  368. if ( ( rc = smscusb_raw_writel ( smscusb,
  369. ( filt_base + SMSCUSB_ADDR_FILTH(0) ),
  370. mac.addr.h ) ) != 0 )
  371. return rc;
  372. /* Write MAC address perfect filter low register */
  373. if ( ( rc = smscusb_raw_writel ( smscusb,
  374. ( filt_base + SMSCUSB_ADDR_FILTL(0) ),
  375. mac.addr.l ) ) != 0 )
  376. return rc;
  377. return 0;
  378. }
  379. /******************************************************************************
  380. *
  381. * Endpoint operations
  382. *
  383. ******************************************************************************
  384. */
  385. /**
  386. * Complete interrupt transfer
  387. *
  388. * @v ep USB endpoint
  389. * @v iobuf I/O buffer
  390. * @v rc Completion status code
  391. */
  392. static void smscusb_intr_complete ( struct usb_endpoint *ep,
  393. struct io_buffer *iobuf, int rc ) {
  394. struct smscusb_device *smscusb =
  395. container_of ( ep, struct smscusb_device, usbnet.intr );
  396. struct net_device *netdev = smscusb->netdev;
  397. struct smscusb_interrupt *intr;
  398. /* Profile completions */
  399. profile_start ( &smscusb_intr_profiler );
  400. /* Ignore packets cancelled when the endpoint closes */
  401. if ( ! ep->open )
  402. goto done;
  403. /* Record USB errors against the network device */
  404. if ( rc != 0 ) {
  405. DBGC ( smscusb, "SMSCUSB %p interrupt failed: %s\n",
  406. smscusb, strerror ( rc ) );
  407. DBGC_HDA ( smscusb, 0, iobuf->data, iob_len ( iobuf ) );
  408. netdev_rx_err ( netdev, NULL, rc );
  409. goto done;
  410. }
  411. /* Extract interrupt data */
  412. if ( iob_len ( iobuf ) != sizeof ( *intr ) ) {
  413. DBGC ( smscusb, "SMSCUSB %p malformed interrupt\n",
  414. smscusb );
  415. DBGC_HDA ( smscusb, 0, iobuf->data, iob_len ( iobuf ) );
  416. netdev_rx_err ( netdev, NULL, rc );
  417. goto done;
  418. }
  419. intr = iobuf->data;
  420. /* Record interrupt status */
  421. smscusb->int_sts = le32_to_cpu ( intr->int_sts );
  422. profile_stop ( &smscusb_intr_profiler );
  423. done:
  424. /* Free I/O buffer */
  425. free_iob ( iobuf );
  426. }
  427. /** Interrupt endpoint operations */
  428. struct usb_endpoint_driver_operations smscusb_intr_operations = {
  429. .complete = smscusb_intr_complete,
  430. };
  431. /**
  432. * Complete bulk OUT transfer
  433. *
  434. * @v ep USB endpoint
  435. * @v iobuf I/O buffer
  436. * @v rc Completion status code
  437. */
  438. static void smscusb_out_complete ( struct usb_endpoint *ep,
  439. struct io_buffer *iobuf, int rc ) {
  440. struct smscusb_device *smscusb =
  441. container_of ( ep, struct smscusb_device, usbnet.out );
  442. struct net_device *netdev = smscusb->netdev;
  443. /* Report TX completion */
  444. netdev_tx_complete_err ( netdev, iobuf, rc );
  445. }
  446. /** Bulk OUT endpoint operations */
  447. struct usb_endpoint_driver_operations smscusb_out_operations = {
  448. .complete = smscusb_out_complete,
  449. };