Skip to content

Commit f166f89

Browse files
lunndavem330
authored andcommitted
net: ethernet: fec: Replace interrupt driven MDIO with polled IO
Measurements of the MDIO bus have shown that driving the MDIO bus using interrupts is slow. Back to back MDIO transactions take about 90us, with 25us spent performing the transaction, and the remainder of the time the bus is idle. Replacing the completion interrupt with polled IO results in back to back transactions of 40us. The polling loop waiting for the hardware to complete the transaction takes around 28us. Which suggests interrupt handling has an overhead of 50us, and polled IO nearly halves this overhead, and doubles the MDIO performance. Care has to be taken when setting the MII_SPEED register, or it can trigger an MII event> That then upsets the polling, due to an unexpected pending event. Suggested-by: Chris Heally <[email protected]> Signed-off-by: Andrew Lunn <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 40b9422 commit f166f89

File tree

2 files changed

+45
-36
lines changed

2 files changed

+45
-36
lines changed

drivers/net/ethernet/freescale/fec.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -376,8 +376,7 @@ struct bufdesc_ex {
376376
#define FEC_ENET_TS_AVAIL ((uint)0x00010000)
377377
#define FEC_ENET_TS_TIMER ((uint)0x00008000)
378378

379-
#define FEC_DEFAULT_IMASK (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII)
380-
#define FEC_NAPI_IMASK FEC_ENET_MII
379+
#define FEC_DEFAULT_IMASK (FEC_ENET_TXF | FEC_ENET_RXF)
381380
#define FEC_RX_DISABLED_IMASK (FEC_DEFAULT_IMASK & (~FEC_ENET_RXF))
382381

383382
/* ENET interrupt coalescing macro define */
@@ -543,7 +542,6 @@ struct fec_enet_private {
543542
int link;
544543
int full_duplex;
545544
int speed;
546-
struct completion mdio_done;
547545
int irq[FEC_IRQ_NUM];
548546
bool bufdesc_ex;
549547
int pause_flag;

drivers/net/ethernet/freescale/fec_main.c

Lines changed: 44 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -976,8 +976,8 @@ fec_restart(struct net_device *ndev)
976976
writel((__force u32)cpu_to_be32(temp_mac[1]),
977977
fep->hwp + FEC_ADDR_HIGH);
978978

979-
/* Clear any outstanding interrupt. */
980-
writel(0xffffffff, fep->hwp + FEC_IEVENT);
979+
/* Clear any outstanding interrupt, except MDIO. */
980+
writel((0xffffffff & ~FEC_ENET_MII), fep->hwp + FEC_IEVENT);
981981

982982
fec_enet_bd_init(ndev);
983983

@@ -1123,7 +1123,7 @@ fec_restart(struct net_device *ndev)
11231123
if (fep->link)
11241124
writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
11251125
else
1126-
writel(FEC_ENET_MII, fep->hwp + FEC_IMASK);
1126+
writel(0, fep->hwp + FEC_IMASK);
11271127

11281128
/* Init the interrupt coalescing */
11291129
fec_enet_itr_coal_init(ndev);
@@ -1652,23 +1652,23 @@ fec_enet_interrupt(int irq, void *dev_id)
16521652
irqreturn_t ret = IRQ_NONE;
16531653

16541654
int_events = readl(fep->hwp + FEC_IEVENT);
1655+
1656+
/* Don't clear MDIO events, we poll for those */
1657+
int_events &= ~FEC_ENET_MII;
1658+
16551659
writel(int_events, fep->hwp + FEC_IEVENT);
16561660
fec_enet_collect_events(fep, int_events);
16571661

16581662
if ((fep->work_tx || fep->work_rx) && fep->link) {
16591663
ret = IRQ_HANDLED;
16601664

16611665
if (napi_schedule_prep(&fep->napi)) {
1662-
/* Disable the NAPI interrupts */
1663-
writel(FEC_NAPI_IMASK, fep->hwp + FEC_IMASK);
1666+
/* Disable interrupts */
1667+
writel(0, fep->hwp + FEC_IMASK);
16641668
__napi_schedule(&fep->napi);
16651669
}
16661670
}
16671671

1668-
if (int_events & FEC_ENET_MII) {
1669-
ret = IRQ_HANDLED;
1670-
complete(&fep->mdio_done);
1671-
}
16721672
return ret;
16731673
}
16741674

@@ -1818,20 +1818,31 @@ static void fec_enet_adjust_link(struct net_device *ndev)
18181818
phy_print_status(phy_dev);
18191819
}
18201820

1821+
static int fec_enet_mdio_wait(struct fec_enet_private *fep)
1822+
{
1823+
uint ievent;
1824+
int ret;
1825+
1826+
ret = readl_poll_timeout_atomic(fep->hwp + FEC_IEVENT, ievent,
1827+
ievent & FEC_ENET_MII, 2, 30000);
1828+
1829+
if (!ret)
1830+
writel(FEC_ENET_MII, fep->hwp + FEC_IEVENT);
1831+
1832+
return ret;
1833+
}
1834+
18211835
static int fec_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
18221836
{
18231837
struct fec_enet_private *fep = bus->priv;
18241838
struct device *dev = &fep->pdev->dev;
1825-
unsigned long time_left;
18261839
int ret = 0, frame_start, frame_addr, frame_op;
18271840
bool is_c45 = !!(regnum & MII_ADDR_C45);
18281841

18291842
ret = pm_runtime_get_sync(dev);
18301843
if (ret < 0)
18311844
return ret;
18321845

1833-
reinit_completion(&fep->mdio_done);
1834-
18351846
if (is_c45) {
18361847
frame_start = FEC_MMFR_ST_C45;
18371848

@@ -1843,11 +1854,9 @@ static int fec_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
18431854
fep->hwp + FEC_MII_DATA);
18441855

18451856
/* wait for end of transfer */
1846-
time_left = wait_for_completion_timeout(&fep->mdio_done,
1847-
usecs_to_jiffies(FEC_MII_TIMEOUT));
1848-
if (time_left == 0) {
1857+
ret = fec_enet_mdio_wait(fep);
1858+
if (ret) {
18491859
netdev_err(fep->netdev, "MDIO address write timeout\n");
1850-
ret = -ETIMEDOUT;
18511860
goto out;
18521861
}
18531862

@@ -1866,11 +1875,9 @@ static int fec_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
18661875
FEC_MMFR_TA, fep->hwp + FEC_MII_DATA);
18671876

18681877
/* wait for end of transfer */
1869-
time_left = wait_for_completion_timeout(&fep->mdio_done,
1870-
usecs_to_jiffies(FEC_MII_TIMEOUT));
1871-
if (time_left == 0) {
1878+
ret = fec_enet_mdio_wait(fep);
1879+
if (ret) {
18721880
netdev_err(fep->netdev, "MDIO read timeout\n");
1873-
ret = -ETIMEDOUT;
18741881
goto out;
18751882
}
18761883

@@ -1888,7 +1895,6 @@ static int fec_enet_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
18881895
{
18891896
struct fec_enet_private *fep = bus->priv;
18901897
struct device *dev = &fep->pdev->dev;
1891-
unsigned long time_left;
18921898
int ret, frame_start, frame_addr;
18931899
bool is_c45 = !!(regnum & MII_ADDR_C45);
18941900

@@ -1898,8 +1904,6 @@ static int fec_enet_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
18981904
else
18991905
ret = 0;
19001906

1901-
reinit_completion(&fep->mdio_done);
1902-
19031907
if (is_c45) {
19041908
frame_start = FEC_MMFR_ST_C45;
19051909

@@ -1911,11 +1915,9 @@ static int fec_enet_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
19111915
fep->hwp + FEC_MII_DATA);
19121916

19131917
/* wait for end of transfer */
1914-
time_left = wait_for_completion_timeout(&fep->mdio_done,
1915-
usecs_to_jiffies(FEC_MII_TIMEOUT));
1916-
if (time_left == 0) {
1918+
ret = fec_enet_mdio_wait(fep);
1919+
if (ret) {
19171920
netdev_err(fep->netdev, "MDIO address write timeout\n");
1918-
ret = -ETIMEDOUT;
19191921
goto out;
19201922
}
19211923
} else {
@@ -1931,12 +1933,9 @@ static int fec_enet_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
19311933
fep->hwp + FEC_MII_DATA);
19321934

19331935
/* wait for end of transfer */
1934-
time_left = wait_for_completion_timeout(&fep->mdio_done,
1935-
usecs_to_jiffies(FEC_MII_TIMEOUT));
1936-
if (time_left == 0) {
1936+
ret = fec_enet_mdio_wait(fep);
1937+
if (ret)
19371938
netdev_err(fep->netdev, "MDIO write timeout\n");
1938-
ret = -ETIMEDOUT;
1939-
}
19401939

19411940
out:
19421941
pm_runtime_mark_last_busy(dev);
@@ -2143,8 +2142,21 @@ static int fec_enet_mii_init(struct platform_device *pdev)
21432142
if (suppress_preamble)
21442143
fep->phy_speed |= BIT(7);
21452144

2145+
/* Clear MMFR to avoid to generate MII event by writing MSCR.
2146+
* MII event generation condition:
2147+
* - writing MSCR:
2148+
* - mmfr[31:0]_not_zero & mscr[7:0]_is_zero &
2149+
* mscr_reg_data_in[7:0] != 0
2150+
* - writing MMFR:
2151+
* - mscr[7:0]_not_zero
2152+
*/
2153+
writel(0, fep->hwp + FEC_MII_DATA);
2154+
21462155
writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
21472156

2157+
/* Clear any pending transaction complete indication */
2158+
writel(FEC_ENET_MII, fep->hwp + FEC_IEVENT);
2159+
21482160
fep->mii_bus = mdiobus_alloc();
21492161
if (fep->mii_bus == NULL) {
21502162
err = -ENOMEM;
@@ -3686,7 +3698,6 @@ fec_probe(struct platform_device *pdev)
36863698
fep->irq[i] = irq;
36873699
}
36883700

3689-
init_completion(&fep->mdio_done);
36903701
ret = fec_enet_mii_init(pdev);
36913702
if (ret)
36923703
goto failed_mii_init;

0 commit comments

Comments
 (0)