Skip to content

Commit 2460966

Browse files
Timur Tabidavem330
authored andcommitted
net: qcom/emac: do not use hardware mdio automatic polling
Use software polling (PHY_POLL) to check for link state changes instead of relying on the EMAC's hardware polling feature. Some PHY drivers are unable to get a functioning link because the HW polling is not robust enough. The EMAC is able to poll the PHY on the MDIO bus looking for link state changes (via the Link Status bit in the Status Register at address 0x1). When the link state changes, the EMAC triggers an interrupt and tells the driver what the new state is. The feature eliminates the need for software to poll the MDIO bus. Unfortunately, this feature is incompatible with phylib, because it ignores everything that the PHY core and PHY drivers are trying to do. In particular: 1. It assumes a compatible register set, so PHYs with different registers may not work. 2. It doesn't allow for hardware errata that have work-arounds implemented in the PHY driver. 3. It doesn't support multiple register pages. If the PHY core switches the register set to another page, the EMAC won't know the page has changed and will still attempt to read the same PHY register. 4. It only checks the copper side of the link, not the SGMII side. Some PHY drivers (e.g. at803x) may also check the SGMII side, and report the link as not ready during autonegotiation if the SGMII link is still down. Phylib then waits for another interrupt to query the PHY again, but the EMAC won't send another interrupt because it thinks the link is up. Cc: [email protected] # 4.11.x Tested-by: Manoj Iyer <[email protected]> Signed-off-by: Timur Tabi <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent f0c3192 commit 2460966

File tree

3 files changed

+6
-93
lines changed

3 files changed

+6
-93
lines changed

drivers/net/ethernet/qualcomm/emac/emac-mac.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -931,7 +931,7 @@ int emac_mac_up(struct emac_adapter *adpt)
931931
emac_mac_config(adpt);
932932
emac_mac_rx_descs_refill(adpt, &adpt->rx_q);
933933

934-
adpt->phydev->irq = PHY_IGNORE_INTERRUPT;
934+
adpt->phydev->irq = PHY_POLL;
935935
ret = phy_connect_direct(netdev, adpt->phydev, emac_adjust_link,
936936
PHY_INTERFACE_MODE_SGMII);
937937
if (ret) {

drivers/net/ethernet/qualcomm/emac/emac-phy.c

Lines changed: 4 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,11 @@
1313
/* Qualcomm Technologies, Inc. EMAC PHY Controller driver.
1414
*/
1515

16-
#include <linux/module.h>
17-
#include <linux/of.h>
18-
#include <linux/of_net.h>
1916
#include <linux/of_mdio.h>
2017
#include <linux/phy.h>
2118
#include <linux/iopoll.h>
2219
#include <linux/acpi.h>
2320
#include "emac.h"
24-
#include "emac-mac.h"
2521

2622
/* EMAC base register offsets */
2723
#define EMAC_MDIO_CTRL 0x001414
@@ -52,62 +48,10 @@
5248

5349
#define MDIO_WAIT_TIMES 1000
5450

55-
#define EMAC_LINK_SPEED_DEFAULT (\
56-
EMAC_LINK_SPEED_10_HALF |\
57-
EMAC_LINK_SPEED_10_FULL |\
58-
EMAC_LINK_SPEED_100_HALF |\
59-
EMAC_LINK_SPEED_100_FULL |\
60-
EMAC_LINK_SPEED_1GB_FULL)
61-
62-
/**
63-
* emac_phy_mdio_autopoll_disable() - disable mdio autopoll
64-
* @adpt: the emac adapter
65-
*
66-
* The autopoll feature takes over the MDIO bus. In order for
67-
* the PHY driver to be able to talk to the PHY over the MDIO
68-
* bus, we need to temporarily disable the autopoll feature.
69-
*/
70-
static int emac_phy_mdio_autopoll_disable(struct emac_adapter *adpt)
71-
{
72-
u32 val;
73-
74-
/* disable autopoll */
75-
emac_reg_update32(adpt->base + EMAC_MDIO_CTRL, MDIO_AP_EN, 0);
76-
77-
/* wait for any mdio polling to complete */
78-
if (!readl_poll_timeout(adpt->base + EMAC_MDIO_CTRL, val,
79-
!(val & MDIO_BUSY), 100, MDIO_WAIT_TIMES * 100))
80-
return 0;
81-
82-
/* failed to disable; ensure it is enabled before returning */
83-
emac_reg_update32(adpt->base + EMAC_MDIO_CTRL, 0, MDIO_AP_EN);
84-
85-
return -EBUSY;
86-
}
87-
88-
/**
89-
* emac_phy_mdio_autopoll_disable() - disable mdio autopoll
90-
* @adpt: the emac adapter
91-
*
92-
* The EMAC has the ability to poll the external PHY on the MDIO
93-
* bus for link state changes. This eliminates the need for the
94-
* driver to poll the phy. If if the link state does change,
95-
* the EMAC issues an interrupt on behalf of the PHY.
96-
*/
97-
static void emac_phy_mdio_autopoll_enable(struct emac_adapter *adpt)
98-
{
99-
emac_reg_update32(adpt->base + EMAC_MDIO_CTRL, 0, MDIO_AP_EN);
100-
}
101-
10251
static int emac_mdio_read(struct mii_bus *bus, int addr, int regnum)
10352
{
10453
struct emac_adapter *adpt = bus->priv;
10554
u32 reg;
106-
int ret;
107-
108-
ret = emac_phy_mdio_autopoll_disable(adpt);
109-
if (ret)
110-
return ret;
11155

11256
emac_reg_update32(adpt->base + EMAC_PHY_STS, PHY_ADDR_BMSK,
11357
(addr << PHY_ADDR_SHFT));
@@ -122,24 +66,15 @@ static int emac_mdio_read(struct mii_bus *bus, int addr, int regnum)
12266
if (readl_poll_timeout(adpt->base + EMAC_MDIO_CTRL, reg,
12367
!(reg & (MDIO_START | MDIO_BUSY)),
12468
100, MDIO_WAIT_TIMES * 100))
125-
ret = -EIO;
126-
else
127-
ret = (reg >> MDIO_DATA_SHFT) & MDIO_DATA_BMSK;
69+
return -EIO;
12870

129-
emac_phy_mdio_autopoll_enable(adpt);
130-
131-
return ret;
71+
return (reg >> MDIO_DATA_SHFT) & MDIO_DATA_BMSK;
13272
}
13373

13474
static int emac_mdio_write(struct mii_bus *bus, int addr, int regnum, u16 val)
13575
{
13676
struct emac_adapter *adpt = bus->priv;
13777
u32 reg;
138-
int ret;
139-
140-
ret = emac_phy_mdio_autopoll_disable(adpt);
141-
if (ret)
142-
return ret;
14378

14479
emac_reg_update32(adpt->base + EMAC_PHY_STS, PHY_ADDR_BMSK,
14580
(addr << PHY_ADDR_SHFT));
@@ -155,11 +90,9 @@ static int emac_mdio_write(struct mii_bus *bus, int addr, int regnum, u16 val)
15590
if (readl_poll_timeout(adpt->base + EMAC_MDIO_CTRL, reg,
15691
!(reg & (MDIO_START | MDIO_BUSY)), 100,
15792
MDIO_WAIT_TIMES * 100))
158-
ret = -EIO;
93+
return -EIO;
15994

160-
emac_phy_mdio_autopoll_enable(adpt);
161-
162-
return ret;
95+
return 0;
16396
}
16497

16598
/* Configure the MDIO bus and connect the external PHY */

drivers/net/ethernet/qualcomm/emac/emac.c

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -50,30 +50,14 @@
5050
#define DMAR_DLY_CNT_DEF 15
5151
#define DMAW_DLY_CNT_DEF 4
5252

53-
#define IMR_NORMAL_MASK (\
54-
ISR_ERROR |\
55-
ISR_GPHY_LINK |\
56-
ISR_TX_PKT |\
57-
GPHY_WAKEUP_INT)
58-
59-
#define IMR_EXTENDED_MASK (\
60-
SW_MAN_INT |\
61-
ISR_OVER |\
62-
ISR_ERROR |\
63-
ISR_GPHY_LINK |\
64-
ISR_TX_PKT |\
65-
GPHY_WAKEUP_INT)
53+
#define IMR_NORMAL_MASK (ISR_ERROR | ISR_OVER | ISR_TX_PKT)
6654

6755
#define ISR_TX_PKT (\
6856
TX_PKT_INT |\
6957
TX_PKT_INT1 |\
7058
TX_PKT_INT2 |\
7159
TX_PKT_INT3)
7260

73-
#define ISR_GPHY_LINK (\
74-
GPHY_LINK_UP_INT |\
75-
GPHY_LINK_DOWN_INT)
76-
7761
#define ISR_OVER (\
7862
RFD0_UR_INT |\
7963
RFD1_UR_INT |\
@@ -187,10 +171,6 @@ irqreturn_t emac_isr(int _irq, void *data)
187171
if (status & ISR_OVER)
188172
net_warn_ratelimited("warning: TX/RX overflow\n");
189173

190-
/* link event */
191-
if (status & ISR_GPHY_LINK)
192-
phy_mac_interrupt(adpt->phydev, !!(status & GPHY_LINK_UP_INT));
193-
194174
exit:
195175
/* enable the interrupt */
196176
writel(irq->mask, adpt->base + EMAC_INT_MASK);

0 commit comments

Comments
 (0)