To Everyone: I need a test hardware recommendation for a lan7431/0 NIC in normal mode (not fixed-link mode). In prior patches this was not necessary, because I was able to ensure 100% backwards compatibility by careful coding alone. But I might soon come to a point where I need to test phy-connected devices as well.
Hi Andrew, thanks for commenting on my patch. > Am 17.05.2020 um 20:37 schrieb Andrew Lunn <and...@lunn.ch>: > >> @@ -946,6 +949,9 @@ static void lan743x_phy_link_status_change(struct >> net_device *netdev) >> { >> struct lan743x_adapter *adapter = netdev_priv(netdev); >> struct phy_device *phydev = netdev->phydev; >> + struct device_node *phynode; >> + phy_interface_t phyifc = PHY_INTERFACE_MODE_GMII; >> + u32 data; >> >> phy_print_status(phydev); >> if (phydev->state == PHY_RUNNING) { >> @@ -953,6 +959,48 @@ static void lan743x_phy_link_status_change(struct >> net_device *netdev) >> int remote_advertisement = 0; >> int local_advertisement = 0; >> >> + /* check if a fixed-link is defined in device-tree */ >> + phynode = of_node_get(adapter->pdev->dev.of_node); >> + if (phynode && of_phy_is_fixed_link(phynode)) { > > Hi Roelof > > The whole point for fixed link is that it looks like a PHY. You should > not need to care if it is a real PHY or a fixed link. > Ok, I can try to remove the additional speed and baud configuration, when the PHY simulation should lead to the same result. Understood, thanks, I’ll test this and remove the overhead. > >> + /* Configure MAC to fixed link parameters */ >> + data = lan743x_csr_read(adapter, MAC_CR); >> + /* Disable auto negotiation */ >> + data &= ~(MAC_CR_ADD_ | MAC_CR_ASD_); > > Why does the MAC care about autoneg? In general, all the MAC needs to > know is the speed and duplex. > My assumption is, that in fixed-link mode we should switch off the autonegotiation between MAC and remote peer (e.g. a switch). I didn’t test, if it would also wun with the hardware doing auto-negotiation, however it feels cleaner to me to prevent the hardware from initiating any auto-negotiation in fixed-link mode. >> + /* Set duplex mode */ >> + if (phydev->duplex) >> + data |= MAC_CR_DPX_; >> + else >> + data &= ~MAC_CR_DPX_; >> + /* Set bus speed */ >> + switch (phydev->speed) { >> + case 10: >> + data &= ~MAC_CR_CFG_H_; >> + data &= ~MAC_CR_CFG_L_; >> + break; >> + case 100: >> + data &= ~MAC_CR_CFG_H_; >> + data |= MAC_CR_CFG_L_; >> + break; >> + case 1000: >> + data |= MAC_CR_CFG_H_; >> + data |= MAC_CR_CFG_L_; >> + break; >> + } > > The current code is unusual, in that it uses > phy_ethtool_get_link_ksettings(). That should do the right thing with > a fixed-link PHY, although i don't know if anybody uses it like > this. So in theory, the current code should take care of duplex, flow > control, and speed for you. Just watch out for bug/missing features in > fixed link. Ok, I test and report if it works. Now I understand the concept. > > >> + /* Set interface mode */ >> + of_get_phy_mode(phynode, &phyifc); >> + if (phyifc == PHY_INTERFACE_MODE_RGMII || >> + phyifc == PHY_INTERFACE_MODE_RGMII_ID || >> + phyifc == PHY_INTERFACE_MODE_RGMII_RXID || >> + phyifc == PHY_INTERFACE_MODE_RGMII_TXID) >> + /* RGMII */ >> + data &= ~MAC_CR_MII_EN_; >> + else >> + /* GMII */ >> + data |= MAC_CR_MII_EN_; >> + lan743x_csr_write(adapter, MAC_CR, data); >> + } >> + of_node_put(phynode); > > It is normal to do of_get_phy_mode when connecting to the PHY, and > store the value in the private structure. This is also not specific to > fixed link. > > There is also a helper you can use phy_interface_mode_is_rgmii(). Thanks for pointing to the method is_rgmii, very handy. Using get_phy_mode() in all cases is not possible on a PC as it returns SGMII on a standard PC, but using GMII is today’s driver behavior. So what I basically did (on two places) is: if(fixed-link) Use get_phy_mode()’s result in of_phy_connect() and in the lan7431 register configuration. else Keep the prior behavior for backwards compatibility (i.e. ignoring the wrong interface mode config on a PC and use GMII constant) The method is_rgmii you mention can lessen the pain here, thanks, and lead to: if(is_rgmii() use RGMII else use GMII I need to think about this, because NOT passing get_phy_mode’s result directly into of_phy_connect or phy_connect_direct (and instead use above's (is_rgmii() ? RGMII : GMII) code) could have side effects. However I don’t dare to pass get_phy_mode’s result directly into of_phy_connect or phy_connect_direct on a PC because then I might change the behavior of all standard PC NIC drivers. I haven’t researched yet why on a PC SGMII is returned by get_phy_mode(), does someone know ?. > >> + >> memset(&ksettings, 0, sizeof(ksettings)); >> phy_ethtool_get_link_ksettings(netdev, &ksettings); >> local_advertisement = >> @@ -974,6 +1022,8 @@ static void lan743x_phy_close(struct lan743x_adapter >> *adapter) >> >> phy_stop(netdev->phydev); >> phy_disconnect(netdev->phydev); >> + if (of_phy_is_fixed_link(adapter->pdev->dev.of_node)) >> + of_phy_deregister_fixed_link(adapter->pdev->dev.of_node); >> netdev->phydev = NULL; >> } >> >> @@ -982,18 +1032,44 @@ static int lan743x_phy_open(struct lan743x_adapter >> *adapter) >> struct lan743x_phy *phy = &adapter->phy; >> struct phy_device *phydev; >> struct net_device *netdev; >> + struct device_node *phynode = NULL; >> + phy_interface_t phyifc = PHY_INTERFACE_MODE_GMII; >> int ret = -EIO; > > netdev uses reverse christmas tree, meaning the lines should be > sorted, longest first, getting shorter. Ok > >> >> netdev = adapter->netdev; >> - phydev = phy_find_first(adapter->mdiobus); >> - if (!phydev) >> - goto return_error; >> >> - ret = phy_connect_direct(netdev, phydev, >> - lan743x_phy_link_status_change, >> - PHY_INTERFACE_MODE_GMII); >> - if (ret) >> - goto return_error; >> + /* check if a fixed-link is defined in device-tree */ >> + phynode = of_node_get(adapter->pdev->dev.of_node); >> + if (phynode && of_phy_is_fixed_link(phynode)) { >> + netdev_dbg(netdev, "fixed-link detected\n"); > > This is something which is useful during debug. But once it works can > be removed. Ok > >> + ret = of_phy_register_fixed_link(phynode); >> + if (ret) { >> + netdev_err(netdev, "cannot register fixed PHY\n"); >> + goto return_error; >> + } >> + >> + of_get_phy_mode(phynode, &phyifc); >> + phydev = of_phy_connect(netdev, phynode, >> + lan743x_phy_link_status_change, >> + 0, phyifc); >> + if (!phydev) >> + goto return_error; >> + } else { >> + phydev = phy_find_first(adapter->mdiobus); >> + if (!phydev) >> + goto return_error; >> + >> + ret = phy_connect_direct(netdev, phydev, >> + lan743x_phy_link_status_change, >> + PHY_INTERFACE_MODE_GMII); >> + /* Note: We cannot use phyifc here because this would be SGMII >> + * on a standard PC. >> + */ > > I don't understand this comment. > See above the lengthy section. On a PC SGMII is returned when I call of_get_phy_mode(phynode, &phyifc); but the original driver is using PHY_INTERFACE_MODE_GMII; and I don’t dare to change this behavior. Which I would do when I would pass on the result of of_get_phy_mode(). That’s what I meant by the comment. Thanks a lot directing me to the proper way, Roelof