From b1df34d7bd872b2259a77b5dfc46edfe1a8fe20f Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 6 Jul 2017 17:10:31 +0100 Subject: [PATCH] [smsc75xx] Use common SMSC USB device functionality Signed-off-by: Michael Brown --- src/drivers/net/smsc75xx.c | 723 ++++++------------------------------- src/drivers/net/smsc75xx.h | 123 +------ 2 files changed, 126 insertions(+), 720 deletions(-) diff --git a/src/drivers/net/smsc75xx.c b/src/drivers/net/smsc75xx.c index 4ce98ac8..c04dc1a7 100644 --- a/src/drivers/net/smsc75xx.c +++ b/src/drivers/net/smsc75xx.c @@ -39,10 +39,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * */ -/** Interrupt completion profiler */ -static struct profiler smsc75xx_intr_profiler __profiler = - { .name = "smsc75xx.intr" }; - /** Bulk IN completion profiler */ static struct profiler smsc75xx_in_profiler __profiler = { .name = "smsc75xx.in" }; @@ -51,363 +47,6 @@ static struct profiler smsc75xx_in_profiler __profiler = static struct profiler smsc75xx_out_profiler __profiler = { .name = "smsc75xx.out" }; -/****************************************************************************** - * - * Register access - * - ****************************************************************************** - */ - -/** - * Write register (without byte-swapping) - * - * @v smsc75xx SMSC75xx device - * @v address Register address - * @v value Register value - * @ret rc Return status code - */ -static int smsc75xx_raw_writel ( struct smsc75xx_device *smsc75xx, - unsigned int address, uint32_t value ) { - int rc; - - /* Write register */ - if ( ( rc = usb_control ( smsc75xx->usb, SMSC75XX_REGISTER_WRITE, 0, - address, &value, sizeof ( value ) ) ) != 0 ) { - DBGC ( smsc75xx, "SMSC75XX %p could not write %03x: %s\n", - smsc75xx, address, strerror ( rc ) ); - return rc; - } - - return 0; -} - -/** - * Write register - * - * @v smsc75xx SMSC75xx device - * @v address Register address - * @v value Register value - * @ret rc Return status code - */ -static inline __attribute__ (( always_inline )) int -smsc75xx_writel ( struct smsc75xx_device *smsc75xx, unsigned int address, - uint32_t value ) { - int rc; - - /* Write register */ - if ( ( rc = smsc75xx_raw_writel ( smsc75xx, address, - cpu_to_le32 ( value ) ) ) != 0 ) - return rc; - - return 0; -} - -/** - * Read register (without byte-swapping) - * - * @v smsc75xx SMSC75xx device - * @v address Register address - * @ret value Register value - * @ret rc Return status code - */ -static int smsc75xx_raw_readl ( struct smsc75xx_device *smsc75xx, - unsigned int address, uint32_t *value ) { - int rc; - - /* Read register */ - if ( ( rc = usb_control ( smsc75xx->usb, SMSC75XX_REGISTER_READ, 0, - address, value, sizeof ( *value ) ) ) != 0 ) { - DBGC ( smsc75xx, "SMSC75XX %p could not read %03x: %s\n", - smsc75xx, address, strerror ( rc ) ); - return rc; - } - - return 0; -} - -/** - * Read register - * - * @v smsc75xx SMSC75xx device - * @v address Register address - * @ret value Register value - * @ret rc Return status code - */ -static inline __attribute__ (( always_inline )) int -smsc75xx_readl ( struct smsc75xx_device *smsc75xx, unsigned int address, - uint32_t *value ) { - int rc; - - /* Read register */ - if ( ( rc = smsc75xx_raw_readl ( smsc75xx, address, value ) ) != 0 ) - return rc; - le32_to_cpus ( value ); - - return 0; -} - -/****************************************************************************** - * - * EEPROM access - * - ****************************************************************************** - */ - -/** - * Wait for EEPROM to become idle - * - * @v smsc75xx SMSC75xx device - * @ret rc Return status code - */ -static int smsc75xx_eeprom_wait ( struct smsc75xx_device *smsc75xx ) { - uint32_t e2p_cmd; - unsigned int i; - int rc; - - /* Wait for EPC_BSY to become clear */ - for ( i = 0 ; i < SMSC75XX_EEPROM_MAX_WAIT_MS ; i++ ) { - - /* Read E2P_CMD and check EPC_BSY */ - if ( ( rc = smsc75xx_readl ( smsc75xx, SMSC75XX_E2P_CMD, - &e2p_cmd ) ) != 0 ) - return rc; - if ( ! ( e2p_cmd & SMSC75XX_E2P_CMD_EPC_BSY ) ) - return 0; - - /* Delay */ - mdelay ( 1 ); - } - - DBGC ( smsc75xx, "SMSC75XX %p timed out waiting for EEPROM\n", - smsc75xx ); - return -ETIMEDOUT; -} - -/** - * Read byte from EEPROM - * - * @v smsc75xx SMSC75xx device - * @v address EEPROM address - * @ret byte Byte read, or negative error - */ -static int smsc75xx_eeprom_read_byte ( struct smsc75xx_device *smsc75xx, - unsigned int address ) { - uint32_t e2p_cmd; - uint32_t e2p_data; - int rc; - - /* Wait for EEPROM to become idle */ - if ( ( rc = smsc75xx_eeprom_wait ( smsc75xx ) ) != 0 ) - return rc; - - /* Initiate read command */ - e2p_cmd = ( SMSC75XX_E2P_CMD_EPC_BSY | SMSC75XX_E2P_CMD_EPC_CMD_READ | - SMSC75XX_E2P_CMD_EPC_ADDR ( address ) ); - if ( ( rc = smsc75xx_writel ( smsc75xx, SMSC75XX_E2P_CMD, - e2p_cmd ) ) != 0 ) - return rc; - - /* Wait for command to complete */ - if ( ( rc = smsc75xx_eeprom_wait ( smsc75xx ) ) != 0 ) - return rc; - - /* Read EEPROM data */ - if ( ( rc = smsc75xx_readl ( smsc75xx, SMSC75XX_E2P_DATA, - &e2p_data ) ) != 0 ) - return rc; - - return SMSC75XX_E2P_DATA_GET ( e2p_data ); -} - -/** - * Read data from EEPROM - * - * @v smsc75xx SMSC75xx device - * @v address EEPROM address - * @v data Data buffer - * @v len Length of data - * @ret rc Return status code - */ -static int smsc75xx_eeprom_read ( struct smsc75xx_device *smsc75xx, - unsigned int address, void *data, - size_t len ) { - uint8_t *bytes; - int byte; - - /* Read bytes */ - for ( bytes = data ; len-- ; address++, bytes++ ) { - byte = smsc75xx_eeprom_read_byte ( smsc75xx, address ); - if ( byte < 0 ) - return byte; - *bytes = byte; - } - - return 0; -} - -/****************************************************************************** - * - * MII access - * - ****************************************************************************** - */ - -/** - * Wait for MII to become idle - * - * @v smsc75xx SMSC75xx device - * @ret rc Return status code - */ -static int smsc75xx_mii_wait ( struct smsc75xx_device *smsc75xx ) { - uint32_t mii_access; - unsigned int i; - int rc; - - /* Wait for MIIBZY to become clear */ - for ( i = 0 ; i < SMSC75XX_MII_MAX_WAIT_MS ; i++ ) { - - /* Read MII_ACCESS and check MIIBZY */ - if ( ( rc = smsc75xx_readl ( smsc75xx, SMSC75XX_MII_ACCESS, - &mii_access ) ) != 0 ) - return rc; - if ( ! ( mii_access & SMSC75XX_MII_ACCESS_MIIBZY ) ) - return 0; - - /* Delay */ - mdelay ( 1 ); - } - - DBGC ( smsc75xx, "SMSC75XX %p timed out waiting for MII\n", - smsc75xx ); - return -ETIMEDOUT; -} - -/** - * Read from MII register - * - * @v mii MII interface - * @v reg Register address - * @ret value Data read, or negative error - */ -static int smsc75xx_mii_read ( struct mii_interface *mii, unsigned int reg ) { - struct smsc75xx_device *smsc75xx = - container_of ( mii, struct smsc75xx_device, mii ); - uint32_t mii_access; - uint32_t mii_data; - int rc; - - /* Wait for MII to become idle */ - if ( ( rc = smsc75xx_mii_wait ( smsc75xx ) ) != 0 ) - return rc; - - /* Initiate read command */ - mii_access = ( SMSC75XX_MII_ACCESS_PHY_ADDRESS | - SMSC75XX_MII_ACCESS_MIIRINDA ( reg ) | - SMSC75XX_MII_ACCESS_MIIBZY ); - if ( ( rc = smsc75xx_writel ( smsc75xx, SMSC75XX_MII_ACCESS, - mii_access ) ) != 0 ) - return rc; - - /* Wait for command to complete */ - if ( ( rc = smsc75xx_mii_wait ( smsc75xx ) ) != 0 ) - return rc; - - /* Read MII data */ - if ( ( rc = smsc75xx_readl ( smsc75xx, SMSC75XX_MII_DATA, - &mii_data ) ) != 0 ) - return rc; - - return SMSC75XX_MII_DATA_GET ( mii_data ); -} - -/** - * Write to MII register - * - * @v mii MII interface - * @v reg Register address - * @v data Data to write - * @ret rc Return status code - */ -static int smsc75xx_mii_write ( struct mii_interface *mii, unsigned int reg, - unsigned int data ) { - struct smsc75xx_device *smsc75xx = - container_of ( mii, struct smsc75xx_device, mii ); - uint32_t mii_access; - uint32_t mii_data; - int rc; - - /* Wait for MII to become idle */ - if ( ( rc = smsc75xx_mii_wait ( smsc75xx ) ) != 0 ) - return rc; - - /* Write MII data */ - mii_data = SMSC75XX_MII_DATA_SET ( data ); - if ( ( rc = smsc75xx_writel ( smsc75xx, SMSC75XX_MII_DATA, - mii_data ) ) != 0 ) - return rc; - - /* Initiate write command */ - mii_access = ( SMSC75XX_MII_ACCESS_PHY_ADDRESS | - SMSC75XX_MII_ACCESS_MIIRINDA ( reg ) | - SMSC75XX_MII_ACCESS_MIIWNR | - SMSC75XX_MII_ACCESS_MIIBZY ); - if ( ( rc = smsc75xx_writel ( smsc75xx, SMSC75XX_MII_ACCESS, - mii_access ) ) != 0 ) - return rc; - - /* Wait for command to complete */ - if ( ( rc = smsc75xx_mii_wait ( smsc75xx ) ) != 0 ) - return rc; - - return 0; -} - -/** MII operations */ -static struct mii_operations smsc75xx_mii_operations = { - .read = smsc75xx_mii_read, - .write = smsc75xx_mii_write, -}; - -/** - * Check link status - * - * @v smsc75xx SMSC75xx device - * @ret rc Return status code - */ -static int smsc75xx_check_link ( struct smsc75xx_device *smsc75xx ) { - struct net_device *netdev = smsc75xx->netdev; - int intr; - int rc; - - /* Read PHY interrupt source */ - intr = mii_read ( &smsc75xx->mii, SMSC75XX_MII_PHY_INTR_SOURCE ); - if ( intr < 0 ) { - rc = intr; - DBGC ( smsc75xx, "SMSC75XX %p could not get PHY interrupt " - "source: %s\n", smsc75xx, strerror ( rc ) ); - return rc; - } - - /* Acknowledge PHY interrupt */ - if ( ( rc = mii_write ( &smsc75xx->mii, SMSC75XX_MII_PHY_INTR_SOURCE, - intr ) ) != 0 ) { - DBGC ( smsc75xx, "SMSC75XX %p could not acknowledge PHY " - "interrupt: %s\n", smsc75xx, strerror ( rc ) ); - return rc; - } - - /* Check link status */ - if ( ( rc = mii_check_link ( &smsc75xx->mii, netdev ) ) != 0 ) { - DBGC ( smsc75xx, "SMSC75XX %p could not check link: %s\n", - smsc75xx, strerror ( rc ) ); - return rc; - } - - DBGC ( smsc75xx, "SMSC75XX %p link %s (intr %#04x)\n", - smsc75xx, ( netdev_link_ok ( netdev ) ? "up" : "down" ), intr ); - return 0; -} - /****************************************************************************** * * Statistics (for debugging) @@ -415,35 +54,13 @@ static int smsc75xx_check_link ( struct smsc75xx_device *smsc75xx ) { ****************************************************************************** */ -/** - * Get statistics - * - * @v smsc75xx SMSC75xx device - * @v stats Statistics to fill in - * @ret rc Return status code - */ -static int smsc75xx_get_statistics ( struct smsc75xx_device *smsc75xx, - struct smsc75xx_statistics *stats ) { - int rc; - - /* Get statistics */ - if ( ( rc = usb_control ( smsc75xx->usb, SMSC75XX_GET_STATISTICS, 0, 0, - stats, sizeof ( *stats ) ) ) != 0 ) { - DBGC ( smsc75xx, "SMSC75XX %p could not get statistics: %s\n", - smsc75xx, strerror ( rc ) ); - return rc; - } - - return 0; -} - /** * Dump statistics (for debugging) * - * @v smsc75xx SMSC75xx device + * @v smscusb SMSC USB device * @ret rc Return status code */ -static int smsc75xx_dump_statistics ( struct smsc75xx_device *smsc75xx ) { +static int smsc75xx_dump_statistics ( struct smscusb_device *smscusb ) { struct smsc75xx_statistics stats; int rc; @@ -452,29 +69,33 @@ static int smsc75xx_dump_statistics ( struct smsc75xx_device *smsc75xx ) { return 0; /* Get statistics */ - if ( ( rc = smsc75xx_get_statistics ( smsc75xx, &stats ) ) != 0 ) + if ( ( rc = smscusb_get_statistics ( smscusb, 0, &stats, + sizeof ( stats ) ) ) != 0 ) { + DBGC ( smscusb, "SMSC75XX %p could not get statistics: " + "%s\n", smscusb, strerror ( rc ) ); return rc; + } /* Dump statistics */ - DBGC ( smsc75xx, "SMSC75XX %p RXE fcs %d aln %d frg %d jab %d und %d " - "ovr %d drp %d\n", smsc75xx, le32_to_cpu ( stats.rx.err.fcs ), + DBGC ( smscusb, "SMSC75XX %p RXE fcs %d aln %d frg %d jab %d und %d " + "ovr %d drp %d\n", smscusb, le32_to_cpu ( stats.rx.err.fcs ), le32_to_cpu ( stats.rx.err.alignment ), le32_to_cpu ( stats.rx.err.fragment ), le32_to_cpu ( stats.rx.err.jabber ), le32_to_cpu ( stats.rx.err.undersize ), le32_to_cpu ( stats.rx.err.oversize ), le32_to_cpu ( stats.rx.err.dropped ) ); - DBGC ( smsc75xx, "SMSC75XX %p RXB ucast %d bcast %d mcast %d\n", - smsc75xx, le32_to_cpu ( stats.rx.byte.unicast ), + DBGC ( smscusb, "SMSC75XX %p RXB ucast %d bcast %d mcast %d\n", + smscusb, le32_to_cpu ( stats.rx.byte.unicast ), le32_to_cpu ( stats.rx.byte.broadcast ), le32_to_cpu ( stats.rx.byte.multicast ) ); - DBGC ( smsc75xx, "SMSC75XX %p RXF ucast %d bcast %d mcast %d pause " - "%d\n", smsc75xx, le32_to_cpu ( stats.rx.frame.unicast ), + DBGC ( smscusb, "SMSC75XX %p RXF ucast %d bcast %d mcast %d pause " + "%d\n", smscusb, le32_to_cpu ( stats.rx.frame.unicast ), le32_to_cpu ( stats.rx.frame.broadcast ), le32_to_cpu ( stats.rx.frame.multicast ), le32_to_cpu ( stats.rx.frame.pause ) ); - DBGC ( smsc75xx, "SMSC75XX %p TXE fcs %d def %d car %d cnt %d sgl %d " - "mul %d exc %d lat %d\n", smsc75xx, + DBGC ( smscusb, "SMSC75XX %p TXE fcs %d def %d car %d cnt %d sgl %d " + "mul %d exc %d lat %d\n", smscusb, le32_to_cpu ( stats.tx.err.fcs ), le32_to_cpu ( stats.tx.err.deferral ), le32_to_cpu ( stats.tx.err.carrier ), @@ -483,12 +104,12 @@ static int smsc75xx_dump_statistics ( struct smsc75xx_device *smsc75xx ) { le32_to_cpu ( stats.tx.err.multiple ), le32_to_cpu ( stats.tx.err.excessive ), le32_to_cpu ( stats.tx.err.late ) ); - DBGC ( smsc75xx, "SMSC75XX %p TXB ucast %d bcast %d mcast %d\n", - smsc75xx, le32_to_cpu ( stats.tx.byte.unicast ), + DBGC ( smscusb, "SMSC75XX %p TXB ucast %d bcast %d mcast %d\n", + smscusb, le32_to_cpu ( stats.tx.byte.unicast ), le32_to_cpu ( stats.tx.byte.broadcast ), le32_to_cpu ( stats.tx.byte.multicast ) ); - DBGC ( smsc75xx, "SMSC75XX %p TXF ucast %d bcast %d mcast %d pause " - "%d\n", smsc75xx, le32_to_cpu ( stats.tx.frame.unicast ), + DBGC ( smscusb, "SMSC75XX %p TXF ucast %d bcast %d mcast %d pause " + "%d\n", smscusb, le32_to_cpu ( stats.tx.frame.unicast ), le32_to_cpu ( stats.tx.frame.broadcast ), le32_to_cpu ( stats.tx.frame.multicast ), le32_to_cpu ( stats.tx.frame.pause ) ); @@ -506,25 +127,25 @@ static int smsc75xx_dump_statistics ( struct smsc75xx_device *smsc75xx ) { /** * Reset device * - * @v smsc75xx SMSC75xx device + * @v smscusb SMSC USB device * @ret rc Return status code */ -static int smsc75xx_reset ( struct smsc75xx_device *smsc75xx ) { +static int smsc75xx_reset ( struct smscusb_device *smscusb ) { uint32_t hw_cfg; unsigned int i; int rc; /* Reset device */ - if ( ( rc = smsc75xx_writel ( smsc75xx, SMSC75XX_HW_CFG, - SMSC75XX_HW_CFG_LRST ) ) != 0 ) + if ( ( rc = smscusb_writel ( smscusb, SMSC75XX_HW_CFG, + SMSC75XX_HW_CFG_LRST ) ) != 0 ) return rc; /* Wait for reset to complete */ for ( i = 0 ; i < SMSC75XX_RESET_MAX_WAIT_MS ; i++ ) { /* Check if reset has completed */ - if ( ( rc = smsc75xx_readl ( smsc75xx, SMSC75XX_HW_CFG, - &hw_cfg ) ) != 0 ) + if ( ( rc = smscusb_readl ( smscusb, SMSC75XX_HW_CFG, + &hw_cfg ) ) != 0 ) return rc; if ( ! ( hw_cfg & SMSC75XX_HW_CFG_LRST ) ) return 0; @@ -533,8 +154,8 @@ static int smsc75xx_reset ( struct smsc75xx_device *smsc75xx ) { mdelay ( 1 ); } - DBGC ( smsc75xx, "SMSC75XX %p timed out waiting for reset\n", - smsc75xx ); + DBGC ( smscusb, "SMSC75XX %p timed out waiting for reset\n", + smscusb ); return -ETIMEDOUT; } @@ -545,60 +166,6 @@ static int smsc75xx_reset ( struct smsc75xx_device *smsc75xx ) { ****************************************************************************** */ -/** - * Complete interrupt transfer - * - * @v ep USB endpoint - * @v iobuf I/O buffer - * @v rc Completion status code - */ -static void smsc75xx_intr_complete ( struct usb_endpoint *ep, - struct io_buffer *iobuf, int rc ) { - struct smsc75xx_device *smsc75xx = - container_of ( ep, struct smsc75xx_device, usbnet.intr ); - struct net_device *netdev = smsc75xx->netdev; - struct smsc75xx_interrupt *intr; - - /* Profile completions */ - profile_start ( &smsc75xx_intr_profiler ); - - /* Ignore packets cancelled when the endpoint closes */ - if ( ! ep->open ) - goto done; - - /* Record USB errors against the network device */ - if ( rc != 0 ) { - DBGC ( smsc75xx, "SMSC75XX %p interrupt failed: %s\n", - smsc75xx, strerror ( rc ) ); - DBGC_HDA ( smsc75xx, 0, iobuf->data, iob_len ( iobuf ) ); - netdev_rx_err ( netdev, NULL, rc ); - goto done; - } - - /* Extract interrupt data */ - if ( iob_len ( iobuf ) != sizeof ( *intr ) ) { - DBGC ( smsc75xx, "SMSC75XX %p malformed interrupt\n", - smsc75xx ); - DBGC_HDA ( smsc75xx, 0, iobuf->data, iob_len ( iobuf ) ); - netdev_rx_err ( netdev, NULL, rc ); - goto done; - } - intr = iobuf->data; - - /* Record interrupt status */ - smsc75xx->int_sts = le32_to_cpu ( intr->int_sts ); - profile_stop ( &smsc75xx_intr_profiler ); - - done: - /* Free I/O buffer */ - free_iob ( iobuf ); -} - -/** Interrupt endpoint operations */ -static struct usb_endpoint_driver_operations smsc75xx_intr_operations = { - .complete = smsc75xx_intr_complete, -}; - /** * Complete bulk IN transfer * @@ -608,9 +175,9 @@ static struct usb_endpoint_driver_operations smsc75xx_intr_operations = { */ static void smsc75xx_in_complete ( struct usb_endpoint *ep, struct io_buffer *iobuf, int rc ) { - struct smsc75xx_device *smsc75xx = - container_of ( ep, struct smsc75xx_device, usbnet.in ); - struct net_device *netdev = smsc75xx->netdev; + struct smscusb_device *smscusb = + container_of ( ep, struct smscusb_device, usbnet.in ); + struct net_device *netdev = smscusb->netdev; struct smsc75xx_rx_header *header; /* Profile completions */ @@ -624,16 +191,16 @@ static void smsc75xx_in_complete ( struct usb_endpoint *ep, /* Record USB errors against the network device */ if ( rc != 0 ) { - DBGC ( smsc75xx, "SMSC75XX %p bulk IN failed: %s\n", - smsc75xx, strerror ( rc ) ); + DBGC ( smscusb, "SMSC75XX %p bulk IN failed: %s\n", + smscusb, strerror ( rc ) ); goto err; } /* Sanity check */ if ( iob_len ( iobuf ) < ( sizeof ( *header ) ) ) { - DBGC ( smsc75xx, "SMSC75XX %p underlength bulk IN\n", - smsc75xx ); - DBGC_HDA ( smsc75xx, 0, iobuf->data, iob_len ( iobuf ) ); + DBGC ( smscusb, "SMSC75XX %p underlength bulk IN\n", + smscusb ); + DBGC_HDA ( smscusb, 0, iobuf->data, iob_len ( iobuf ) ); rc = -EINVAL; goto err; } @@ -644,9 +211,9 @@ static void smsc75xx_in_complete ( struct usb_endpoint *ep, /* Check for errors */ if ( header->command & cpu_to_le32 ( SMSC75XX_RX_RED ) ) { - DBGC ( smsc75xx, "SMSC75XX %p receive error (%08x):\n", - smsc75xx, le32_to_cpu ( header->command ) ); - DBGC_HDA ( smsc75xx, 0, iobuf->data, iob_len ( iobuf ) ); + DBGC ( smscusb, "SMSC75XX %p receive error (%08x):\n", + smscusb, le32_to_cpu ( header->command ) ); + DBGC_HDA ( smscusb, 0, iobuf->data, iob_len ( iobuf ) ); rc = -EIO; goto err; } @@ -670,11 +237,11 @@ static struct usb_endpoint_driver_operations smsc75xx_in_operations = { /** * Transmit packet * - * @v smsc75xx SMSC75xx device + * @v smscusb SMSC USB device * @v iobuf I/O buffer * @ret rc Return status code */ -static int smsc75xx_out_transmit ( struct smsc75xx_device *smsc75xx, +static int smsc75xx_out_transmit ( struct smscusb_device *smscusb, struct io_buffer *iobuf ) { struct smsc75xx_tx_header *header; size_t len = iob_len ( iobuf ); @@ -692,35 +259,13 @@ static int smsc75xx_out_transmit ( struct smsc75xx_device *smsc75xx, header->mss = 0; /* Enqueue I/O buffer */ - if ( ( rc = usb_stream ( &smsc75xx->usbnet.out, iobuf, 0 ) ) != 0 ) + if ( ( rc = usb_stream ( &smscusb->usbnet.out, iobuf, 0 ) ) != 0 ) return rc; profile_stop ( &smsc75xx_out_profiler ); return 0; } -/** - * Complete bulk OUT transfer - * - * @v ep USB endpoint - * @v iobuf I/O buffer - * @v rc Completion status code - */ -static void smsc75xx_out_complete ( struct usb_endpoint *ep, - struct io_buffer *iobuf, int rc ) { - struct smsc75xx_device *smsc75xx = - container_of ( ep, struct smsc75xx_device, usbnet.out ); - struct net_device *netdev = smsc75xx->netdev; - - /* Report TX completion */ - netdev_tx_complete_err ( netdev, iobuf, rc ); -} - -/** Bulk OUT endpoint operations */ -static struct usb_endpoint_driver_operations smsc75xx_out_operations = { - .complete = smsc75xx_out_complete, -}; - /****************************************************************************** * * Network device interface @@ -735,110 +280,84 @@ static struct usb_endpoint_driver_operations smsc75xx_out_operations = { * @ret rc Return status code */ static int smsc75xx_open ( struct net_device *netdev ) { - struct smsc75xx_device *smsc75xx = netdev->priv; - union smsc75xx_mac mac; + struct smscusb_device *smscusb = netdev->priv; int rc; /* Clear stored interrupt status */ - smsc75xx->int_sts = 0; - - /* Copy MAC address */ - memset ( &mac, 0, sizeof ( mac ) ); - memcpy ( mac.raw, netdev->ll_addr, ETH_ALEN ); + smscusb->int_sts = 0; /* Configure bulk IN empty response */ - if ( ( rc = smsc75xx_writel ( smsc75xx, SMSC75XX_HW_CFG, - SMSC75XX_HW_CFG_BIR ) ) != 0 ) + if ( ( rc = smscusb_writel ( smscusb, SMSC75XX_HW_CFG, + SMSC75XX_HW_CFG_BIR ) ) != 0 ) goto err_hw_cfg; /* Open USB network device */ - if ( ( rc = usbnet_open ( &smsc75xx->usbnet ) ) != 0 ) { - DBGC ( smsc75xx, "SMSC75XX %p could not open: %s\n", - smsc75xx, strerror ( rc ) ); + if ( ( rc = usbnet_open ( &smscusb->usbnet ) ) != 0 ) { + DBGC ( smscusb, "SMSC75XX %p could not open: %s\n", + smscusb, strerror ( rc ) ); goto err_open; } /* Configure interrupt endpoint */ - if ( ( rc = smsc75xx_writel ( smsc75xx, SMSC75XX_INT_EP_CTL, - ( SMSC75XX_INT_EP_CTL_RDFO_EN | - SMSC75XX_INT_EP_CTL_PHY_EN ) ) ) != 0 ) + if ( ( rc = smscusb_writel ( smscusb, SMSC75XX_INT_EP_CTL, + ( SMSC75XX_INT_EP_CTL_RDFO_EN | + SMSC75XX_INT_EP_CTL_PHY_EN ) ) ) != 0 ) goto err_int_ep_ctl; /* Configure bulk IN delay */ - if ( ( rc = smsc75xx_writel ( smsc75xx, SMSC75XX_BULK_IN_DLY, - SMSC75XX_BULK_IN_DLY_SET ( 0 ) ) ) != 0 ) + if ( ( rc = smscusb_writel ( smscusb, SMSC75XX_BULK_IN_DLY, + SMSC75XX_BULK_IN_DLY_SET ( 0 ) ) ) != 0 ) goto err_bulk_in_dly; /* Configure receive filters */ - if ( ( rc = smsc75xx_writel ( smsc75xx, SMSC75XX_RFE_CTL, - ( SMSC75XX_RFE_CTL_AB | - SMSC75XX_RFE_CTL_AM | - SMSC75XX_RFE_CTL_AU ) ) ) != 0 ) + if ( ( rc = smscusb_writel ( smscusb, SMSC75XX_RFE_CTL, + ( SMSC75XX_RFE_CTL_AB | + SMSC75XX_RFE_CTL_AM | + SMSC75XX_RFE_CTL_AU ) ) ) != 0 ) goto err_rfe_ctl; /* Configure receive FIFO */ - if ( ( rc = smsc75xx_writel ( smsc75xx, SMSC75XX_FCT_RX_CTL, - ( SMSC75XX_FCT_RX_CTL_EN | - SMSC75XX_FCT_RX_CTL_BAD ) ) ) != 0 ) + if ( ( rc = smscusb_writel ( smscusb, SMSC75XX_FCT_RX_CTL, + ( SMSC75XX_FCT_RX_CTL_EN | + SMSC75XX_FCT_RX_CTL_BAD ) ) ) != 0 ) goto err_fct_rx_ctl; /* Configure transmit FIFO */ - if ( ( rc = smsc75xx_writel ( smsc75xx, SMSC75XX_FCT_TX_CTL, - SMSC75XX_FCT_TX_CTL_EN ) ) != 0 ) + if ( ( rc = smscusb_writel ( smscusb, SMSC75XX_FCT_TX_CTL, + SMSC75XX_FCT_TX_CTL_EN ) ) != 0 ) goto err_fct_tx_ctl; /* Configure receive datapath */ - if ( ( rc = smsc75xx_writel ( smsc75xx, SMSC75XX_MAC_RX, - ( SMSC75XX_MAC_RX_MAX_SIZE_DEFAULT | - SMSC75XX_MAC_RX_FCS | - SMSC75XX_MAC_RX_EN ) ) ) != 0 ) + if ( ( rc = smscusb_writel ( smscusb, SMSC75XX_MAC_RX, + ( SMSC75XX_MAC_RX_MAX_SIZE_DEFAULT | + SMSC75XX_MAC_RX_FCS | + SMSC75XX_MAC_RX_EN ) ) ) != 0 ) goto err_mac_rx; /* Configure transmit datapath */ - if ( ( rc = smsc75xx_writel ( smsc75xx, SMSC75XX_MAC_TX, - SMSC75XX_MAC_TX_EN ) ) != 0 ) + if ( ( rc = smscusb_writel ( smscusb, SMSC75XX_MAC_TX, + SMSC75XX_MAC_TX_EN ) ) != 0 ) goto err_mac_tx; - /* Write MAC address high register */ - if ( ( rc = smsc75xx_raw_writel ( smsc75xx, SMSC75XX_RX_ADDRH, - mac.addr.h ) ) != 0 ) - goto err_rx_addrh; + /* Set MAC address */ + if ( ( rc = smscusb_set_address ( smscusb, + SMSC75XX_RX_ADDR_BASE ) ) != 0 ) + goto err_set_address; - /* Write MAC address low register */ - if ( ( rc = smsc75xx_raw_writel ( smsc75xx, SMSC75XX_RX_ADDRL, - mac.addr.l ) ) != 0 ) - goto err_rx_addrl; + /* Set MAC address perfect filter */ + if ( ( rc = smscusb_set_filter ( smscusb, + SMSC75XX_ADDR_FILT_BASE ) ) != 0 ) + goto err_set_filter; - /* Write MAC address perfect filter high register */ - mac.addr.h |= cpu_to_le32 ( SMSC75XX_ADDR_FILTH_VALID ); - if ( ( rc = smsc75xx_raw_writel ( smsc75xx, SMSC75XX_ADDR_FILTH ( 0 ), - mac.addr.h ) ) != 0 ) - goto err_addr_filth; - - /* Write MAC address perfect filter low register */ - if ( ( rc = smsc75xx_raw_writel ( smsc75xx, SMSC75XX_ADDR_FILTL ( 0 ), - mac.addr.l ) ) != 0 ) - goto err_addr_filtl; - - /* Enable PHY interrupts */ - if ( ( rc = mii_write ( &smsc75xx->mii, SMSC75XX_MII_PHY_INTR_MASK, - ( SMSC75XX_PHY_INTR_ANEG_DONE | - SMSC75XX_PHY_INTR_LINK_DOWN ) ) ) != 0 ) { - DBGC ( smsc75xx, "SMSC75XX %p could not set PHY interrupt " - "mask: %s\n", smsc75xx, strerror ( rc ) ); - goto err_phy_intr_mask; - } - - /* Update link status */ - smsc75xx_check_link ( smsc75xx ); + /* Enable PHY interrupts and update link status */ + if ( ( rc = smscusb_mii_open ( smscusb ) ) != 0 ) + goto err_mii_open; return 0; - err_phy_intr_mask: - err_addr_filtl: - err_addr_filth: - err_rx_addrl: - err_rx_addrh: + err_mii_open: + err_set_filter: + err_set_address: err_mac_tx: err_mac_rx: err_fct_tx_ctl: @@ -846,10 +365,10 @@ static int smsc75xx_open ( struct net_device *netdev ) { err_rfe_ctl: err_bulk_in_dly: err_int_ep_ctl: - usbnet_close ( &smsc75xx->usbnet ); + usbnet_close ( &smscusb->usbnet ); err_open: err_hw_cfg: - smsc75xx_reset ( smsc75xx ); + smsc75xx_reset ( smscusb ); return rc; } @@ -859,16 +378,16 @@ static int smsc75xx_open ( struct net_device *netdev ) { * @v netdev Network device */ static void smsc75xx_close ( struct net_device *netdev ) { - struct smsc75xx_device *smsc75xx = netdev->priv; + struct smscusb_device *smscusb = netdev->priv; /* Close USB network device */ - usbnet_close ( &smsc75xx->usbnet ); + usbnet_close ( &smscusb->usbnet ); /* Dump statistics (for debugging) */ - smsc75xx_dump_statistics ( smsc75xx ); + smsc75xx_dump_statistics ( smscusb ); /* Reset device */ - smsc75xx_reset ( smsc75xx ); + smsc75xx_reset ( smscusb ); } /** @@ -880,11 +399,11 @@ static void smsc75xx_close ( struct net_device *netdev ) { */ static int smsc75xx_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { - struct smsc75xx_device *smsc75xx = netdev->priv; + struct smscusb_device *smscusb = netdev->priv; int rc; /* Transmit packet */ - if ( ( rc = smsc75xx_out_transmit ( smsc75xx, iobuf ) ) != 0 ) + if ( ( rc = smsc75xx_out_transmit ( smscusb, iobuf ) ) != 0 ) return rc; return 0; @@ -896,48 +415,47 @@ static int smsc75xx_transmit ( struct net_device *netdev, * @v netdev Network device */ static void smsc75xx_poll ( struct net_device *netdev ) { - struct smsc75xx_device *smsc75xx = netdev->priv; + struct smscusb_device *smscusb = netdev->priv; uint32_t int_sts; int rc; /* Poll USB bus */ - usb_poll ( smsc75xx->bus ); + usb_poll ( smscusb->bus ); /* Refill endpoints */ - if ( ( rc = usbnet_refill ( &smsc75xx->usbnet ) ) != 0 ) + if ( ( rc = usbnet_refill ( &smscusb->usbnet ) ) != 0 ) netdev_rx_err ( netdev, NULL, rc ); /* Do nothing more unless there are interrupts to handle */ - int_sts = smsc75xx->int_sts; + int_sts = smscusb->int_sts; if ( ! int_sts ) return; /* Check link status if applicable */ if ( int_sts & SMSC75XX_INT_STS_PHY_INT ) { - smsc75xx_check_link ( smsc75xx ); + smscusb_mii_check_link ( smscusb ); int_sts &= ~SMSC75XX_INT_STS_PHY_INT; } /* Record RX FIFO overflow if applicable */ if ( int_sts & SMSC75XX_INT_STS_RDFO_INT ) { - DBGC2 ( smsc75xx, "SMSC75XX %p RX FIFO overflowed\n", - smsc75xx ); + DBGC2 ( smscusb, "SMSC75XX %p RX FIFO overflowed\n", smscusb ); netdev_rx_err ( netdev, NULL, -ENOBUFS ); int_sts &= ~SMSC75XX_INT_STS_RDFO_INT; } /* Check for unexpected interrupts */ if ( int_sts ) { - DBGC ( smsc75xx, "SMSC75XX %p unexpected interrupt %#08x\n", - smsc75xx, int_sts ); + DBGC ( smscusb, "SMSC75XX %p unexpected interrupt %#08x\n", + smscusb, int_sts ); netdev_rx_err ( netdev, NULL, -ENOTTY ); } /* Clear interrupts */ - if ( ( rc = smsc75xx_writel ( smsc75xx, SMSC75XX_INT_STS, - smsc75xx->int_sts ) ) != 0 ) + if ( ( rc = smscusb_writel ( smscusb, SMSC75XX_INT_STS, + smscusb->int_sts ) ) != 0 ) netdev_rx_err ( netdev, NULL, rc ); - smsc75xx->int_sts = 0; + smscusb->int_sts = 0; } /** SMSC75xx network device operations */ @@ -964,48 +482,41 @@ static struct net_device_operations smsc75xx_operations = { */ static int smsc75xx_probe ( struct usb_function *func, struct usb_configuration_descriptor *config ) { - struct usb_device *usb = func->usb; struct net_device *netdev; - struct smsc75xx_device *smsc75xx; + struct smscusb_device *smscusb; int rc; /* Allocate and initialise structure */ - netdev = alloc_etherdev ( sizeof ( *smsc75xx ) ); + netdev = alloc_etherdev ( sizeof ( *smscusb ) ); if ( ! netdev ) { rc = -ENOMEM; goto err_alloc; } netdev_init ( netdev, &smsc75xx_operations ); netdev->dev = &func->dev; - smsc75xx = netdev->priv; - memset ( smsc75xx, 0, sizeof ( *smsc75xx ) ); - smsc75xx->usb = usb; - smsc75xx->bus = usb->port->hub->bus; - smsc75xx->netdev = netdev; - usbnet_init ( &smsc75xx->usbnet, func, &smsc75xx_intr_operations, - &smsc75xx_in_operations, &smsc75xx_out_operations ); - usb_refill_init ( &smsc75xx->usbnet.intr, 0, 0, - SMSC75XX_INTR_MAX_FILL ); - usb_refill_init ( &smsc75xx->usbnet.in, 0, SMSC75XX_IN_MTU, + smscusb = netdev->priv; + memset ( smscusb, 0, sizeof ( *smscusb ) ); + smscusb_init ( smscusb, netdev, func, &smsc75xx_in_operations ); + smscusb_mii_init ( smscusb, SMSC75XX_MII_BASE ); + usb_refill_init ( &smscusb->usbnet.in, 0, SMSC75XX_IN_MTU, SMSC75XX_IN_MAX_FILL ); - mii_init ( &smsc75xx->mii, &smsc75xx_mii_operations ); - DBGC ( smsc75xx, "SMSC75XX %p on %s\n", smsc75xx, func->name ); + DBGC ( smscusb, "SMSC75XX %p on %s\n", smscusb, func->name ); /* Describe USB network device */ - if ( ( rc = usbnet_describe ( &smsc75xx->usbnet, config ) ) != 0 ) { - DBGC ( smsc75xx, "SMSC75XX %p could not describe: %s\n", - smsc75xx, strerror ( rc ) ); + if ( ( rc = usbnet_describe ( &smscusb->usbnet, config ) ) != 0 ) { + DBGC ( smscusb, "SMSC75XX %p could not describe: %s\n", + smscusb, strerror ( rc ) ); goto err_describe; } /* Reset device */ - if ( ( rc = smsc75xx_reset ( smsc75xx ) ) != 0 ) + if ( ( rc = smsc75xx_reset ( smscusb ) ) != 0 ) goto err_reset; /* Read MAC address */ - if ( ( rc = smsc75xx_eeprom_read ( smsc75xx, SMSC75XX_EEPROM_MAC, - netdev->hw_addr, ETH_ALEN ) ) != 0 ) - goto err_eeprom_read; + if ( ( rc = smscusb_eeprom_fetch_mac ( smscusb, + SMSC75XX_E2P_BASE ) ) != 0 ) + goto err_fetch_mac; /* Register network device */ if ( ( rc = register_netdev ( netdev ) ) != 0 ) @@ -1016,7 +527,7 @@ static int smsc75xx_probe ( struct usb_function *func, unregister_netdev ( netdev ); err_register: - err_eeprom_read: + err_fetch_mac: err_reset: err_describe: netdev_nullify ( netdev ); diff --git a/src/drivers/net/smsc75xx.h b/src/drivers/net/smsc75xx.h index ae81fc16..0a330fd9 100644 --- a/src/drivers/net/smsc75xx.h +++ b/src/drivers/net/smsc75xx.h @@ -9,25 +9,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); -#include -#include -#include -#include - -/** Register write command */ -#define SMSC75XX_REGISTER_WRITE \ - ( USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE | \ - USB_REQUEST_TYPE ( 0xa0 ) ) - -/** Register read command */ -#define SMSC75XX_REGISTER_READ \ - ( USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE | \ - USB_REQUEST_TYPE ( 0xa1 ) ) - -/** Get statistics command */ -#define SMSC75XX_GET_STATISTICS \ - ( USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE | \ - USB_REQUEST_TYPE ( 0xa2 ) ) +#include "smscusb.h" /** Interrupt status register */ #define SMSC75XX_INT_STS 0x00c @@ -48,19 +30,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define SMSC75XX_BULK_IN_DLY 0x03c #define SMSC75XX_BULK_IN_DLY_SET(ticks) ( (ticks) << 0 ) /**< Delay / 16.7ns */ -/** EEPROM command register */ -#define SMSC75XX_E2P_CMD 0x040 -#define SMSC75XX_E2P_CMD_EPC_BSY 0x80000000UL /**< EPC busy */ -#define SMSC75XX_E2P_CMD_EPC_CMD_READ 0x00000000UL /**< READ command */ -#define SMSC75XX_E2P_CMD_EPC_ADDR(addr) ( (addr) << 0 ) /**< EPC address */ - -/** EEPROM data register */ -#define SMSC75XX_E2P_DATA 0x044 -#define SMSC75XX_E2P_DATA_GET(e2p_data) \ - ( ( (e2p_data) >> 0 ) & 0xff ) /**< EEPROM data */ - -/** MAC address EEPROM address */ -#define SMSC75XX_EEPROM_MAC 0x01 +/** EEPROM register base */ +#define SMSC75XX_E2P_BASE 0x040 /** Receive filtering engine control register */ #define SMSC75XX_RFE_CTL 0x060 @@ -89,56 +60,14 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define SMSC75XX_MAC_TX 0x108 #define SMSC75XX_MAC_TX_EN 0x00000001UL /**< TX enable */ -/** MAC receive address high register */ -#define SMSC75XX_RX_ADDRH 0x118 +/** MAC receive address register base */ +#define SMSC75XX_RX_ADDR_BASE 0x118 -/** MAC receive address low register */ -#define SMSC75XX_RX_ADDRL 0x11c +/** MII register base */ +#define SMSC75XX_MII_BASE 0x120 -/** MII access register */ -#define SMSC75XX_MII_ACCESS 0x120 -#define SMSC75XX_MII_ACCESS_PHY_ADDRESS 0x00000800UL /**< PHY address */ -#define SMSC75XX_MII_ACCESS_MIIRINDA(addr) ( (addr) << 6 ) /**< MII register */ -#define SMSC75XX_MII_ACCESS_MIIWNR 0x00000002UL /**< MII write */ -#define SMSC75XX_MII_ACCESS_MIIBZY 0x00000001UL /**< MII busy */ - -/** MII data register */ -#define SMSC75XX_MII_DATA 0x124 -#define SMSC75XX_MII_DATA_SET(data) ( (data) << 0 ) /**< Set data */ -#define SMSC75XX_MII_DATA_GET(mii_data) \ - ( ( (mii_data) >> 0 ) & 0xffff ) /**< Get data */ - -/** PHY interrupt source MII register */ -#define SMSC75XX_MII_PHY_INTR_SOURCE 29 - -/** PHY interrupt mask MII register */ -#define SMSC75XX_MII_PHY_INTR_MASK 30 - -/** PHY interrupt: auto-negotiation complete */ -#define SMSC75XX_PHY_INTR_ANEG_DONE 0x0040 - -/** PHY interrupt: link down */ -#define SMSC75XX_PHY_INTR_LINK_DOWN 0x0010 - -/** MAC address perfect filter N high register */ -#define SMSC75XX_ADDR_FILTH(n) ( 0x300 + ( 8 * (n) ) ) -#define SMSC75XX_ADDR_FILTH_VALID 0x80000000UL /**< Address valid */ - -/** MAC address perfect filter N low register */ -#define SMSC75XX_ADDR_FILTL(n) ( 0x304 + ( 8 * (n) ) ) - -/** MAC address */ -union smsc75xx_mac { - /** MAC receive address registers */ - struct { - /** MAC receive address low register */ - uint32_t l; - /** MAC receive address high register */ - uint32_t h; - } __attribute__ (( packed )) addr; - /** Raw MAC address */ - uint8_t raw[ETH_ALEN]; -}; +/** MAC address perfect filter register base */ +#define SMSC75XX_ADDR_FILT_BASE 0x300 /** Receive packet header */ struct smsc75xx_rx_header { @@ -168,12 +97,6 @@ struct smsc75xx_tx_header { /** Insert frame checksum and pad */ #define SMSC75XX_TX_FCS 0x00400000UL -/** Interrupt packet format */ -struct smsc75xx_interrupt { - /** Current value of INT_STS register */ - uint32_t int_sts; -} __attribute__ (( packed )); - /** Byte count statistics */ struct smsc75xx_byte_statistics { /** Unicast byte count */ @@ -264,37 +187,9 @@ struct smsc75xx_statistics { struct smsc75xx_tx_statistics tx; } __attribute__ (( packed )); -/** A SMSC75xx network device */ -struct smsc75xx_device { - /** USB device */ - struct usb_device *usb; - /** USB bus */ - struct usb_bus *bus; - /** Network device */ - struct net_device *netdev; - /** USB network device */ - struct usbnet_device usbnet; - /** MII interface */ - struct mii_interface mii; - /** Interrupt status */ - uint32_t int_sts; -}; - /** Maximum time to wait for reset (in milliseconds) */ #define SMSC75XX_RESET_MAX_WAIT_MS 100 -/** Maximum time to wait for EEPROM (in milliseconds) */ -#define SMSC75XX_EEPROM_MAX_WAIT_MS 100 - -/** Maximum time to wait for MII (in milliseconds) */ -#define SMSC75XX_MII_MAX_WAIT_MS 100 - -/** Interrupt maximum fill level - * - * This is a policy decision. - */ -#define SMSC75XX_INTR_MAX_FILL 2 - /** Bulk IN maximum fill level * * This is a policy decision.