Differences
This shows you the differences between two versions of the page.
| Both sides previous revision Previous revision Next revision | Previous revision | ||
| phy_link_update [2018/08/27 21:45] – rpjday | phy_link_update [2018/08/28 11:57] (current) – [freescale/ucc_geth.c] rpjday | ||
|---|---|---|---|
| Line 3: | Line 3: | ||
| Observations and proper use of the PHY link status handler. | Observations and proper use of the PHY link status handler. | ||
| - | ===== struct phy_device ===== | + | Issues: |
| - | From '' | + | * Is [[https:// |
| + | |||
| + | ===== Explanation ===== | ||
| + | |||
| + | From [[https:// | ||
| < | < | ||
| + | Connecting to a PHY | ||
| + | |||
| + | | ||
| + | | ||
| + | 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 | ||
| + | | ||
| + | |||
| + | 3) The PAL handles everything, but checks in with the driver every second, | ||
| + | | ||
| + | does. | ||
| + | |||
| + | 4) The PAL serves only as a library of functions, with the network device | ||
| + | | ||
| + | </ | ||
| + | |||
| + | 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 | ||
| + | | ||
| + | |||
| + | | ||
| + | | ||
| + | |||
| + | | ||
| + | |||
| + | Next, you need to know the device name of the PHY connected to this device. | ||
| + | The name will look something like, " | ||
| + | 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: | ||
| + | |||
| + | | ||
| + | |||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | has one. The phydev structure will be populated with information about the | ||
| + | | ||
| + | | ||
| + | |||
| + | | ||
| + | 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/ | ||
| + | |||
| + | | ||
| + | | ||
| + | | ||
| + | |||
| + | Now just make sure that phydev-> | ||
| + | | ||
| + | | ||
| + | mask off SUPPORTED_1000baseT*). | ||
| + | for these bitfields. Note that you should not SET any bits, except the | ||
| + | | ||
| + | put into an unsupported state. | ||
| + | |||
| + | | ||
| + | | ||
| + | PHY to connect to the network. | ||
| + | just set phydev-> | ||
| + | | ||
| + | |||
| + | When you want to disconnect from the network (even if just briefly), you call | ||
| + | | ||
| + | </ | ||
| + | |||
| + | ===== struct phy_device ===== | ||
| + | |||
| + | < | ||
| + | enum phy_state { | ||
| + | PHY_DOWN = 0, | ||
| + | PHY_STARTING, | ||
| + | PHY_READY, | ||
| + | PHY_PENDING, | ||
| + | PHY_UP, | ||
| + | PHY_AN, | ||
| + | PHY_RUNNING, | ||
| + | PHY_NOLINK, | ||
| + | PHY_FORCING, | ||
| + | PHY_CHANGELINK, | ||
| + | PHY_HALTED, | ||
| + | PHY_RESUMING | ||
| + | }; | ||
| + | ... | ||
| struct phy_device { | struct phy_device { | ||
| - | | + | |
| - | | + | enum phy_state state; |
| - | | + | |
| + | | ||
| }; | }; | ||
| + | </ | ||
| + | |||
| + | Printing: | ||
| + | |||
| + | < | ||
| + | netdev_info(ndev, | ||
| + | phy-> | ||
| + | phy-> | ||
| + | phy-> | ||
| + | |||
| + | </ | ||
| + | |||
| + | ===== How many drivers use adjust_link()? | ||
| + | |||
| + | < | ||
| + | $ grep -rwl adjust_link * | ||
| + | amd/ | ||
| + | freescale/ | ||
| + | freescale/ | ||
| + | freescale/ | ||
| + | freescale/ | ||
| + | freescale/ | ||
| + | freescale/ | ||
| + | freescale/ | ||
| + | freescale/ | ||
| + | hisilicon/ | ||
| + | hisilicon/ | ||
| + | hisilicon/ | ||
| + | hisilicon/ | ||
| + | hisilicon/ | ||
| + | hisilicon/ | ||
| + | hisilicon/ | ||
| + | hisilicon/ | ||
| + | hisilicon/ | ||
| + | hisilicon/ | ||
| + | qualcomm/ | ||
| + | $ | ||
| + | </ | ||
| + | |||
| + | ===== Examples ===== | ||
| + | |||
| + | ==== freescale/ | ||
| + | |||
| + | < | ||
| + | / | ||
| + | | ||
| + | | ||
| + | static void generic_adjust_link(struct | ||
| + | { | ||
| + | struct fs_enet_private *fep = netdev_priv(dev); | ||
| + | struct phy_device *phydev = dev-> | ||
| + | int new_state = 0; | ||
| + | |||
| + | if (phydev-> | ||
| + | /* adjust to duplex mode */ | ||
| + | if (phydev-> | ||
| + | new_state = 1; | ||
| + | fep-> | ||
| + | } | ||
| + | |||
| + | if (phydev-> | ||
| + | new_state = 1; | ||
| + | fep-> | ||
| + | } | ||
| + | |||
| + | if (!fep-> | ||
| + | new_state = 1; | ||
| + | fep-> | ||
| + | } | ||
| + | |||
| + | if (new_state) | ||
| + | fep-> | ||
| + | } else if (fep-> | ||
| + | new_state = 1; | ||
| + | fep-> | ||
| + | fep-> | ||
| + | fep-> | ||
| + | } | ||
| + | |||
| + | if (new_state && netif_msg_link(fep)) | ||
| + | phy_print_status(phydev); | ||
| + | } | ||
| + | |||
| + | static void fs_adjust_link(struct net_device *dev) | ||
| + | { | ||
| + | struct fs_enet_private *fep = netdev_priv(dev); | ||
| + | unsigned long flags; | ||
| + | |||
| + | spin_lock_irqsave(& | ||
| + | |||
| + | if(fep-> | ||
| + | fep-> | ||
| + | else | ||
| + | generic_adjust_link(dev); | ||
| + | |||
| + | spin_unlock_irqrestore(& | ||
| + | } | ||
| + | |||
| + | static int fs_init_phy(struct net_device *dev) | ||
| + | { | ||
| + | struct fs_enet_private *fep = netdev_priv(dev); | ||
| + | struct phy_device *phydev; | ||
| + | phy_interface_t iface; | ||
| + | |||
| + | fep-> | ||
| + | fep-> | ||
| + | fep-> | ||
| + | |||
| + | iface = fep-> | ||
| + | PHY_INTERFACE_MODE_RMII : PHY_INTERFACE_MODE_MII; | ||
| + | |||
| + | phydev = of_phy_connect(dev, | ||
| + | iface); | ||
| + | if (!phydev) { | ||
| + | dev_err(& | ||
| + | return -ENODEV; | ||
| + | } | ||
| + | |||
| + | return 0; | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | ==== freescale/ | ||
| + | |||
| + | < | ||
| + | static void adjust_link(struct net_device *dev) | ||
| + | { | ||
| + | struct gfar_private *priv = netdev_priv(dev); | ||
| + | struct phy_device *phydev = dev-> | ||
| + | |||
| + | if (unlikely(phydev-> | ||
| + | | ||
| + | | ||
| + | gfar_update_link_state(priv); | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | ==== freescale/ | ||
| + | |||
| + | < | ||
| + | static void dpaa_adjust_link(struct net_device *net_dev) | ||
| + | { | ||
| + | struct mac_device *mac_dev; | ||
| + | struct dpaa_priv *priv; | ||
| + | |||
| + | priv = netdev_priv(net_dev); | ||
| + | mac_dev = priv-> | ||
| + | mac_dev-> | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | ==== freescale/ | ||
| + | |||
| + | < | ||
| + | /* Called every time the controller might need to be made | ||
| + | * aware of new link state. | ||
| + | * information through variables in the ugeth structure, and this | ||
| + | * function converts those variables into the appropriate | ||
| + | * register values, and can bring down the device if needed. | ||
| + | */ | ||
| + | |||
| + | static void adjust_link(struct net_device *dev) | ||
| + | { | ||
| + | struct ucc_geth_private *ugeth = netdev_priv(dev); | ||
| + | struct ucc_geth __iomem *ug_regs; | ||
| + | struct ucc_fast __iomem *uf_regs; | ||
| + | struct phy_device *phydev = ugeth-> | ||
| + | int new_state = 0; | ||
| + | |||
| + | ug_regs = ugeth-> | ||
| + | uf_regs = ugeth-> | ||
| + | |||
| + | if (phydev-> | ||
| + | </ | ||
| + | |||
| + | ==== hisilicon/ | ||
| + | |||
| + | < | ||
| + | /** | ||
| + | | ||
| + | | ||
| + | */ | ||
| + | static void hns_nic_adjust_link(struct net_device *ndev) | ||
| + | { | ||
| + | struct hns_nic_priv *priv = netdev_priv(ndev); | ||
| + | struct hnae_handle *h = priv-> | ||
| + | int state = 1; | ||
| + | |||
| + | if (ndev-> | ||
| + | h-> | ||
| + | | ||
| + | state = ndev-> | ||
| + | } | ||
| + | state = state && h-> | ||
| + | if (state != priv-> | ||
| + | if (state) { | ||
| + | netif_carrier_on(ndev); | ||
| + | netif_tx_wake_all_queues(ndev); | ||
| + | netdev_info(ndev, | ||
| + | } else { | ||
| + | netif_carrier_off(ndev); | ||
| + | netdev_info(ndev, | ||
| + | } | ||
| + | priv-> | ||
| + | } | ||
| + | } | ||
| </ | </ | ||