[mii] Separate concepts of MII interface and MII device

We currently have no generic concept of a PHY address, since all
existing implementations simply hardcode the PHY address within the
MII access methods.

A bit-bashing MII interface will need to be provided with an explicit
PHY address in order to generate the correct waveform.  Allow for this
by separating out the concept of a MII device (i.e. a specific PHY
address attached to a particular MII interface).

Signed-off-by: Michael Brown <mcb30@ipxe.org>
pull/72/merge
Michael Brown 2018-04-19 12:38:55 +01:00
parent 285e3e5287
commit 6804a8c89b
10 changed files with 118 additions and 59 deletions

View File

@ -37,10 +37,10 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** /**
* Restart autonegotiation * Restart autonegotiation
* *
* @v mii MII interface * @v mii MII device
* @ret rc Return status code * @ret rc Return status code
*/ */
int mii_restart ( struct mii_interface *mii ) { int mii_restart ( struct mii_device *mii ) {
int bmcr; int bmcr;
int rc; int rc;
@ -66,12 +66,12 @@ int mii_restart ( struct mii_interface *mii ) {
} }
/** /**
* Reset MII interface * Reset MII device
* *
* @v mii MII interface * @v mii MII device
* @ret rc Return status code * @ret rc Return status code
*/ */
int mii_reset ( struct mii_interface *mii ) { int mii_reset ( struct mii_device *mii ) {
unsigned int i; unsigned int i;
int bmcr; int bmcr;
int rc; int rc;
@ -119,11 +119,11 @@ int mii_reset ( struct mii_interface *mii ) {
/** /**
* Update link status via MII * Update link status via MII
* *
* @v mii MII interface * @v mii MII device
* @v netdev Network device * @v netdev Network device
* @ret rc Return status code * @ret rc Return status code
*/ */
int mii_check_link ( struct mii_interface *mii, struct net_device *netdev ) { int mii_check_link ( struct mii_device *mii, struct net_device *netdev ) {
int bmsr; int bmsr;
int link; int link;
int rc; int rc;

View File

@ -242,12 +242,15 @@ static int realtek_init_eeprom ( struct net_device *netdev ) {
/** /**
* Read from MII register * Read from MII register
* *
* @v mii MII interface * @v mdio MII interface
* @v phy PHY address
* @v reg Register address * @v reg Register address
* @ret value Data read, or negative error * @ret value Data read, or negative error
*/ */
static int realtek_mii_read ( struct mii_interface *mii, unsigned int reg ) { static int realtek_mii_read ( struct mii_interface *mdio,
struct realtek_nic *rtl = container_of ( mii, struct realtek_nic, mii ); unsigned int phy __unused, unsigned int reg ) {
struct realtek_nic *rtl =
container_of ( mdio, struct realtek_nic, mdio );
unsigned int i; unsigned int i;
uint32_t value; uint32_t value;
@ -279,14 +282,17 @@ static int realtek_mii_read ( struct mii_interface *mii, unsigned int reg ) {
/** /**
* Write to MII register * Write to MII register
* *
* @v mii MII interface * @v mdio MII interface
* @v phy PHY address
* @v reg Register address * @v reg Register address
* @v data Data to write * @v data Data to write
* @ret rc Return status code * @ret rc Return status code
*/ */
static int realtek_mii_write ( struct mii_interface *mii, unsigned int reg, static int realtek_mii_write ( struct mii_interface *mdio,
unsigned int data) { unsigned int phy __unused, unsigned int reg,
struct realtek_nic *rtl = container_of ( mii, struct realtek_nic, mii ); unsigned int data ) {
struct realtek_nic *rtl =
container_of ( mdio, struct realtek_nic, mdio );
unsigned int i; unsigned int i;
/* Fail if PHYAR register is not present */ /* Fail if PHYAR register is not present */
@ -1158,7 +1164,8 @@ static int realtek_probe ( struct pci_device *pci ) {
} }
/* Initialise and reset MII interface */ /* Initialise and reset MII interface */
mii_init ( &rtl->mii, &realtek_mii_operations ); mdio_init ( &rtl->mdio, &realtek_mii_operations );
mii_init ( &rtl->mii, &rtl->mdio, 0 );
if ( ( rc = realtek_phy_reset ( rtl ) ) != 0 ) if ( ( rc = realtek_phy_reset ( rtl ) ) != 0 )
goto err_phy_reset; goto err_phy_reset;

View File

@ -283,7 +283,9 @@ struct realtek_nic {
/** Non-volatile options */ /** Non-volatile options */
struct nvo_block nvo; struct nvo_block nvo;
/** MII interface */ /** MII interface */
struct mii_interface mii; struct mii_interface mdio;
/** MII device */
struct mii_device mii;
/** Legacy datapath mode */ /** Legacy datapath mode */
int legacy; int legacy;

View File

@ -49,12 +49,14 @@ FILE_LICENCE ( GPL2_OR_LATER );
/** /**
* Read from MII register * Read from MII register
* *
* @v mii MII interface * @v mdio MII interface
* @v phy PHY address
* @v reg Register address * @v reg Register address
* @ret value Data read, or negative error * @ret value Data read, or negative error
*/ */
static int rhine_mii_read ( struct mii_interface *mii, unsigned int reg ) { static int rhine_mii_read ( struct mii_interface *mdio,
struct rhine_nic *rhn = container_of ( mii, struct rhine_nic, mii ); unsigned int phy __unused, unsigned int reg ) {
struct rhine_nic *rhn = container_of ( mdio, struct rhine_nic, mdio );
unsigned int timeout = RHINE_TIMEOUT_US; unsigned int timeout = RHINE_TIMEOUT_US;
uint8_t cr; uint8_t cr;
@ -80,14 +82,16 @@ static int rhine_mii_read ( struct mii_interface *mii, unsigned int reg ) {
/** /**
* Write to MII register * Write to MII register
* *
* @v mii MII interface * @v mdio MII interface
* @v phy PHY address
* @v reg Register address * @v reg Register address
* @v data Data to write * @v data Data to write
* @ret rc Return status code * @ret rc Return status code
*/ */
static int rhine_mii_write ( struct mii_interface *mii, unsigned int reg, static int rhine_mii_write ( struct mii_interface *mdio,
unsigned int phy __unused, unsigned int reg,
unsigned int data ) { unsigned int data ) {
struct rhine_nic *rhn = container_of ( mii, struct rhine_nic, mii ); struct rhine_nic *rhn = container_of ( mdio, struct rhine_nic, mdio );
unsigned int timeout = RHINE_TIMEOUT_US; unsigned int timeout = RHINE_TIMEOUT_US;
uint8_t cr; uint8_t cr;
@ -719,7 +723,8 @@ static int rhine_probe ( struct pci_device *pci ) {
netdev->hw_addr[i] = readb ( rhn->regs + RHINE_MAC + i ); netdev->hw_addr[i] = readb ( rhn->regs + RHINE_MAC + i );
/* Initialise and reset MII interface */ /* Initialise and reset MII interface */
mii_init ( &rhn->mii, &rhine_mii_operations ); mdio_init ( &rhn->mdio, &rhine_mii_operations );
mii_init ( &rhn->mii, &rhn->mdio, 0 );
if ( ( rc = mii_reset ( &rhn->mii ) ) != 0 ) { if ( ( rc = mii_reset ( &rhn->mii ) ) != 0 ) {
DBGC ( rhn, "RHINE %p could not reset MII: %s\n", DBGC ( rhn, "RHINE %p could not reset MII: %s\n",
rhn, strerror ( rc ) ); rhn, strerror ( rc ) );

View File

@ -237,7 +237,9 @@ struct rhine_nic {
uint8_t cr1; uint8_t cr1;
/** MII interface */ /** MII interface */
struct mii_interface mii; struct mii_interface mdio;
/** MII device */
struct mii_device mii;
/** Transmit descriptor ring */ /** Transmit descriptor ring */
struct rhine_ring tx; struct rhine_ring tx;

View File

@ -481,13 +481,15 @@ static int smscusb_mii_wait ( struct smscusb_device *smscusb ) {
/** /**
* Read from MII register * Read from MII register
* *
* @v mii MII interface * @v mdio MII interface
* @v phy PHY address
* @v reg Register address * @v reg Register address
* @ret value Data read, or negative error * @ret value Data read, or negative error
*/ */
static int smscusb_mii_read ( struct mii_interface *mii, unsigned int reg ) { static int smscusb_mii_read ( struct mii_interface *mdio,
unsigned int phy __unused, unsigned int reg ) {
struct smscusb_device *smscusb = struct smscusb_device *smscusb =
container_of ( mii, struct smscusb_device, mii ); container_of ( mdio, struct smscusb_device, mdio );
unsigned int base = smscusb->mii_base; unsigned int base = smscusb->mii_base;
uint32_t mii_access; uint32_t mii_access;
uint32_t mii_data; uint32_t mii_data;
@ -520,15 +522,17 @@ static int smscusb_mii_read ( struct mii_interface *mii, unsigned int reg ) {
/** /**
* Write to MII register * Write to MII register
* *
* @v mii MII interface * @v mdio MII interface
* @v phy PHY address
* @v reg Register address * @v reg Register address
* @v data Data to write * @v data Data to write
* @ret rc Return status code * @ret rc Return status code
*/ */
static int smscusb_mii_write ( struct mii_interface *mii, unsigned int reg, static int smscusb_mii_write ( struct mii_interface *mdio,
unsigned int phy __unused, unsigned int reg,
unsigned int data ) { unsigned int data ) {
struct smscusb_device *smscusb = struct smscusb_device *smscusb =
container_of ( mii, struct smscusb_device, mii ); container_of ( mdio, struct smscusb_device, mdio );
unsigned int base = smscusb->mii_base; unsigned int base = smscusb->mii_base;
uint32_t mii_access; uint32_t mii_access;
uint32_t mii_data; uint32_t mii_data;

View File

@ -151,7 +151,9 @@ struct smscusb_device {
/** USB network device */ /** USB network device */
struct usbnet_device usbnet; struct usbnet_device usbnet;
/** MII interface */ /** MII interface */
struct mii_interface mii; struct mii_interface mdio;
/** MII device */
struct mii_device mii;
/** MII register base */ /** MII register base */
uint16_t mii_base; uint16_t mii_base;
/** PHY interrupt source register */ /** PHY interrupt source register */
@ -275,7 +277,8 @@ static inline __attribute__ (( always_inline )) void
smscusb_mii_init ( struct smscusb_device *smscusb, unsigned int mii_base, smscusb_mii_init ( struct smscusb_device *smscusb, unsigned int mii_base,
unsigned int phy_source ) { unsigned int phy_source ) {
mii_init ( &smscusb->mii, &smscusb_mii_operations ); mdio_init ( &smscusb->mdio, &smscusb_mii_operations );
mii_init ( &smscusb->mii, &smscusb->mdio, 0 );
smscusb->mii_base = mii_base; smscusb->mii_base = mii_base;
smscusb->phy_source = phy_source; smscusb->phy_source = phy_source;
} }

View File

@ -100,13 +100,15 @@ static int velocity_autopoll_start ( struct velocity_nic *vlc ) {
/** /**
* Read from MII register * Read from MII register
* *
* @v mii MII interface * @v mdio MII interface
* @v phy PHY address
* @v reg Register address * @v reg Register address
* @ret value Data read, or negative error * @ret value Data read, or negative error
*/ */
static int velocity_mii_read ( struct mii_interface *mii, unsigned int reg ) { static int velocity_mii_read ( struct mii_interface *mdio,
unsigned int phy __unused, unsigned int reg ) {
struct velocity_nic *vlc = struct velocity_nic *vlc =
container_of ( mii, struct velocity_nic, mii ); container_of ( mdio, struct velocity_nic, mdio );
int timeout = VELOCITY_TIMEOUT_US; int timeout = VELOCITY_TIMEOUT_US;
int result; int result;
@ -140,15 +142,17 @@ static int velocity_mii_read ( struct mii_interface *mii, unsigned int reg ) {
/** /**
* Write to MII register * Write to MII register
* *
* @v mii MII interface * @v mdio MII interface
* @v phy PHY address
* @v reg Register address * @v reg Register address
* @v data Data to write * @v data Data to write
* @ret rc Return status code * @ret rc Return status code
*/ */
static int velocity_mii_write ( struct mii_interface *mii, unsigned int reg, static int velocity_mii_write ( struct mii_interface *mdio,
unsigned int phy __unused, unsigned int reg,
unsigned int data) { unsigned int data) {
struct velocity_nic *vlc = struct velocity_nic *vlc =
container_of ( mii, struct velocity_nic, mii ); container_of ( mdio, struct velocity_nic, mdio );
int timeout = VELOCITY_TIMEOUT_US; int timeout = VELOCITY_TIMEOUT_US;
DBGC2 ( vlc, "VELOCITY %p MII write reg %d data 0x%04x\n", DBGC2 ( vlc, "VELOCITY %p MII write reg %d data 0x%04x\n",
@ -747,7 +751,8 @@ static int velocity_probe ( struct pci_device *pci ) {
netdev->hw_addr[5] = readb ( vlc->regs + VELOCITY_MAC5 ); netdev->hw_addr[5] = readb ( vlc->regs + VELOCITY_MAC5 );
/* Initialise and reset MII interface */ /* Initialise and reset MII interface */
mii_init ( &vlc->mii, &velocity_mii_operations ); mdio_init ( &vlc->mdio, &velocity_mii_operations );
mii_init ( &vlc->mii, &vlc->mdio, 0 );
if ( ( rc = mii_reset ( &vlc->mii ) ) != 0 ) { if ( ( rc = mii_reset ( &vlc->mii ) ) != 0 ) {
DBGC ( vlc, "VELOCITY %p could not reset MII: %s\n", DBGC ( vlc, "VELOCITY %p could not reset MII: %s\n",
vlc, strerror ( rc ) ); vlc, strerror ( rc ) );

View File

@ -326,7 +326,9 @@ struct velocity_nic {
/** Registers */ /** Registers */
void *regs; void *regs;
/** MII interface */ /** MII interface */
struct mii_interface mii; struct mii_interface mdio;
/** MII device */
struct mii_device mii;
/** Netdev */ /** Netdev */
struct net_device *netdev; struct net_device *netdev;

View File

@ -19,21 +19,24 @@ struct mii_operations {
/** /**
* Read from MII register * Read from MII register
* *
* @v mii MII interface * @v mdio MII interface
* @v phy PHY address
* @v reg Register address * @v reg Register address
* @ret data Data read, or negative error * @ret data Data read, or negative error
*/ */
int ( * read ) ( struct mii_interface *mii, unsigned int reg ); int ( * read ) ( struct mii_interface *mdio, unsigned int phy,
unsigned int reg );
/** /**
* Write to MII register * Write to MII register
* *
* @v mii MII interface * @v mdio MII interface
* @v phy PHY address
* @v reg Register address * @v reg Register address
* @v data Data to write * @v data Data to write
* @ret rc Return status code * @ret rc Return status code
*/ */
int ( * write ) ( struct mii_interface *mii, unsigned int reg, int ( * write ) ( struct mii_interface *mdio, unsigned int phy,
unsigned int data ); unsigned int reg, unsigned int data );
}; };
/** An MII interface */ /** An MII interface */
@ -42,49 +45,75 @@ struct mii_interface {
struct mii_operations *op; struct mii_operations *op;
}; };
/** An MII device */
struct mii_device {
/** MII interface */
struct mii_interface *mdio;
/** PHY address */
unsigned int address;
};
/** /**
* Initialise MII interface * Initialise MII interface
* *
* @v mii MII interface * @v mdio MII interface
* @v op MII interface operations * @v op MII interface operations
*/ */
static inline __attribute__ (( always_inline )) void static inline __attribute__ (( always_inline )) void
mii_init ( struct mii_interface *mii, struct mii_operations *op ) { mdio_init ( struct mii_interface *mdio, struct mii_operations *op ) {
mii->op = op; mdio->op = op;
}
/**
* Initialise MII device
*
* @v mii MII device
* @v mii MII interface
* @v address PHY address
*/
static inline __attribute__ (( always_inline )) void
mii_init ( struct mii_device *mii, struct mii_interface *mdio,
unsigned int address ) {
mii->mdio = mdio;
mii->address = address;
} }
/** /**
* Read from MII register * Read from MII register
* *
* @v mii MII interface * @v mii MII device
* @v reg Register address * @v reg Register address
* @ret data Data read, or negative error * @ret data Data read, or negative error
*/ */
static inline __attribute__ (( always_inline )) int static inline __attribute__ (( always_inline )) int
mii_read ( struct mii_interface *mii, unsigned int reg ) { mii_read ( struct mii_device *mii, unsigned int reg ) {
return mii->op->read ( mii, reg ); struct mii_interface *mdio = mii->mdio;
return mdio->op->read ( mdio, mii->address, reg );
} }
/** /**
* Write to MII register * Write to MII register
* *
* @v mii MII interface * @v mii MII device
* @v reg Register address * @v reg Register address
* @v data Data to write * @v data Data to write
* @ret rc Return status code * @ret rc Return status code
*/ */
static inline __attribute__ (( always_inline )) int static inline __attribute__ (( always_inline )) int
mii_write ( struct mii_interface *mii, unsigned int reg, unsigned int data ) { mii_write ( struct mii_device *mii, unsigned int reg, unsigned int data ) {
return mii->op->write ( mii, reg, data ); struct mii_interface *mdio = mii->mdio;
return mdio->op->write ( mdio, mii->address, reg, data );
} }
/** /**
* Dump MII registers (for debugging) * Dump MII registers (for debugging)
* *
* @v mii MII interface * @v mii MII device
*/ */
static inline void static inline void
mii_dump ( struct mii_interface *mii ) { mii_dump ( struct mii_device *mii ) {
unsigned int i; unsigned int i;
int data; int data;
@ -112,9 +141,9 @@ mii_dump ( struct mii_interface *mii ) {
/** Maximum time to wait for a reset, in milliseconds */ /** Maximum time to wait for a reset, in milliseconds */
#define MII_RESET_MAX_WAIT_MS 500 #define MII_RESET_MAX_WAIT_MS 500
extern int mii_restart ( struct mii_interface *mii ); extern int mii_restart ( struct mii_device *mii );
extern int mii_reset ( struct mii_interface *mii ); extern int mii_reset ( struct mii_device *mii );
extern int mii_check_link ( struct mii_interface *mii, extern int mii_check_link ( struct mii_device *mii,
struct net_device *netdev ); struct net_device *netdev );
#endif /* _IPXE_MII_H */ #endif /* _IPXE_MII_H */