This is an old revision of the document!
Overview
Explanation
From here:
Connecting to a PHY Sometime during startup, the network driver needs to establish a connection between the PHY device, and the network device. At this time, the PHY's bus and drivers need to all have been loaded, so it is ready for the connection. At this point, there are several ways to connect to the PHY: 1) The PAL handles everything, and only calls the network driver when the link state changes, so it can react. 2) The PAL handles everything except interrupts (usually because the controller has the interrupt registers). 3) The PAL handles everything, but checks in with the driver every second, allowing the network driver to react first to any changes before the PAL does. 4) The PAL serves only as a library of functions, with the network device manually calling functions to update status, and configure the PHY
Scenario 1):
Letting the PHY Abstraction Layer do Everything If you choose option 1 (The hope is that every driver can, but to still be useful to drivers that can't), connecting to the PHY is simple: First, you need a function to react to changes in the link state. This function follows this protocol: static void adjust_link(struct net_device *dev); Next, you need to know the device name of the PHY connected to this device. The name will look something like, "0:00", where the first number is the bus id, and the second is the PHY's address on that bus. Typically, the bus is responsible for making its ID unique. Now, to connect, just call this function: phydev = phy_connect(dev, phy_name, &adjust_link, interface); phydev is a pointer to the phy_device structure which represents the PHY. If phy_connect is successful, it will return the pointer. dev, here, is the pointer to your net_device. Once done, this function will have started the PHY's software state machine, and registered for the PHY's interrupt, if it has one. The phydev structure will be populated with information about the current state, though the PHY will not yet be truly operational at this point. PHY-specific flags should be set in phydev->dev_flags prior to the call to phy_connect() such that the underlying PHY driver can check for flags and perform specific operations based on them. This is useful if the system has put hardware restrictions on the PHY/controller, of which the PHY needs to be aware. interface is a u32 which specifies the connection type used between the controller and the PHY. Examples are GMII, MII, RGMII, and SGMII. For a full list, see include/linux/phy.h Now just make sure that phydev->supported and phydev->advertising have any values pruned from them which don't make sense for your controller (a 10/100 controller may be connected to a gigabit capable PHY, so you would need to mask off SUPPORTED_1000baseT*). See include/linux/ethtool.h for definitions for these bitfields. Note that you should not SET any bits, except the SUPPORTED_Pause and SUPPORTED_AsymPause bits (see below), or the PHY may get put into an unsupported state. Lastly, once the controller is ready to handle network traffic, you call phy_start(phydev). This tells the PAL that you are ready, and configures the PHY to connect to the network. If you want to handle your own interrupts, just set phydev->irq to PHY_IGNORE_INTERRUPT before you call phy_start. Similarly, if you don't want to use interrupts, set phydev->irq to PHY_POLL. When you want to disconnect from the network (even if just briefly), you call phy_stop(phydev).
adjust_link()
How many drivers?
$ grep -rwl adjust_link * amd/xgbe/xgbe-mdio.c freescale/fs_enet/fs_enet.h freescale/fs_enet/fs_enet-main.c freescale/gianfar.c freescale/dpaa/dpaa_ethtool.c freescale/dpaa/dpaa_eth.c freescale/fman/mac.c freescale/fman/mac.h freescale/ucc_geth.c hisilicon/hns3/hnae3.h hisilicon/hns/hns_ethtool.c hisilicon/hns/hns_dsaf_xgmac.c hisilicon/hns/hns_dsaf_gmac.c hisilicon/hns/hns_ae_adapt.c hisilicon/hns/hns_dsaf_mac.h hisilicon/hns/hnae.c hisilicon/hns/hns_enet.c hisilicon/hns/hnae.h hisilicon/hns/hns_dsaf_mac.c qualcomm/emac/emac-mac.c $