User Tools

Site Tools


This is an old revision of the document!

Table of Contents


Observations and proper use of the PHY link status handler.



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
 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

 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

From include/linux/phy.h:

struct phy_device {
        ... snip ...
        void (*adjust_link)(struct net_device *dev);
        ... snip ...

How many drivers take advantage of it?

$ grep -rwl adjust_link *
phy_link_update.1535450784.txt.gz · Last modified: 2018/08/28 10:06 by rpjday