Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 97b72e43 authored by Baruch Siach's avatar Baruch Siach Committed by David S. Miller
Browse files

fec: use interrupt for MDIO completion indication



With the move to phylib (commit e6b043d5) I was seeing sporadic "MDIO write
timeout" messages. Measure of the actual time spent showed latency times of
more than 1600us.

This patch uses the MII event indication of the FEC hardware to detect
completion of MDIO transactions.

Signed-off-by: default avatarBaruch Siach <baruch@tkos.co.il>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 15fd0cd9
Loading
Loading
Loading
Loading
+25 −30
Original line number Original line Diff line number Diff line
@@ -187,6 +187,7 @@ struct fec_enet_private {
	int	index;
	int	index;
	int	link;
	int	link;
	int	full_duplex;
	int	full_duplex;
	struct	completion mdio_done;
};
};


static irqreturn_t fec_enet_interrupt(int irq, void * dev_id);
static irqreturn_t fec_enet_interrupt(int irq, void * dev_id);
@@ -205,7 +206,7 @@ static void fec_stop(struct net_device *dev);
#define FEC_MMFR_TA		(2 << 16)
#define FEC_MMFR_TA		(2 << 16)
#define FEC_MMFR_DATA(v)	(v & 0xffff)
#define FEC_MMFR_DATA(v)	(v & 0xffff)


#define FEC_MII_TIMEOUT		10000
#define FEC_MII_TIMEOUT		1000 /* us */


/* Transmitter timeout */
/* Transmitter timeout */
#define TX_TIMEOUT (2 * HZ)
#define TX_TIMEOUT (2 * HZ)
@@ -334,6 +335,11 @@ fec_enet_interrupt(int irq, void * dev_id)
			ret = IRQ_HANDLED;
			ret = IRQ_HANDLED;
			fec_enet_tx(dev);
			fec_enet_tx(dev);
		}
		}

		if (int_events & FEC_ENET_MII) {
			ret = IRQ_HANDLED;
			complete(&fep->mdio_done);
		}
	} while (int_events);
	} while (int_events);


	return ret;
	return ret;
@@ -608,18 +614,13 @@ spin_unlock:
		phy_print_status(phy_dev);
		phy_print_status(phy_dev);
}
}


/*
 * NOTE: a MII transaction is during around 25 us, so polling it...
 */
static int fec_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
static int fec_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
{
{
	struct fec_enet_private *fep = bus->priv;
	struct fec_enet_private *fep = bus->priv;
	int timeout = FEC_MII_TIMEOUT;
	unsigned long time_left;


	fep->mii_timeout = 0;
	fep->mii_timeout = 0;

	init_completion(&fep->mdio_done);
	/* clear MII end of transfer bit*/
	writel(FEC_ENET_MII, fep->hwp + FEC_IEVENT);


	/* start a read op */
	/* start a read op */
	writel(FEC_MMFR_ST | FEC_MMFR_OP_READ |
	writel(FEC_MMFR_ST | FEC_MMFR_OP_READ |
@@ -627,14 +628,13 @@ static int fec_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
		FEC_MMFR_TA, fep->hwp + FEC_MII_DATA);
		FEC_MMFR_TA, fep->hwp + FEC_MII_DATA);


	/* wait for end of transfer */
	/* wait for end of transfer */
	while (!(readl(fep->hwp + FEC_IEVENT) & FEC_ENET_MII)) {
	time_left = wait_for_completion_timeout(&fep->mdio_done,
		cpu_relax();
			usecs_to_jiffies(FEC_MII_TIMEOUT));
		if (timeout-- < 0) {
	if (time_left == 0) {
		fep->mii_timeout = 1;
		fep->mii_timeout = 1;
		printk(KERN_ERR "FEC: MDIO read timeout\n");
		printk(KERN_ERR "FEC: MDIO read timeout\n");
		return -ETIMEDOUT;
		return -ETIMEDOUT;
	}
	}
	}


	/* return value */
	/* return value */
	return FEC_MMFR_DATA(readl(fep->hwp + FEC_MII_DATA));
	return FEC_MMFR_DATA(readl(fep->hwp + FEC_MII_DATA));
@@ -644,12 +644,10 @@ static int fec_enet_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
			   u16 value)
			   u16 value)
{
{
	struct fec_enet_private *fep = bus->priv;
	struct fec_enet_private *fep = bus->priv;
	int timeout = FEC_MII_TIMEOUT;
	unsigned long time_left;


	fep->mii_timeout = 0;
	fep->mii_timeout = 0;

	init_completion(&fep->mdio_done);
	/* clear MII end of transfer bit*/
	writel(FEC_ENET_MII, fep->hwp + FEC_IEVENT);


	/* start a read op */
	/* start a read op */
	writel(FEC_MMFR_ST | FEC_MMFR_OP_READ |
	writel(FEC_MMFR_ST | FEC_MMFR_OP_READ |
@@ -658,14 +656,13 @@ static int fec_enet_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
		fep->hwp + FEC_MII_DATA);
		fep->hwp + FEC_MII_DATA);


	/* wait for end of transfer */
	/* wait for end of transfer */
	while (!(readl(fep->hwp + FEC_IEVENT) & FEC_ENET_MII)) {
	time_left = wait_for_completion_timeout(&fep->mdio_done,
		cpu_relax();
			usecs_to_jiffies(FEC_MII_TIMEOUT));
		if (timeout-- < 0) {
	if (time_left == 0) {
		fep->mii_timeout = 1;
		fep->mii_timeout = 1;
		printk(KERN_ERR "FEC: MDIO write timeout\n");
		printk(KERN_ERR "FEC: MDIO write timeout\n");
		return -ETIMEDOUT;
		return -ETIMEDOUT;
	}
	}
	}


	return 0;
	return 0;
}
}
@@ -1216,7 +1213,8 @@ fec_restart(struct net_device *dev, int duplex)
	writel(0, fep->hwp + FEC_R_DES_ACTIVE);
	writel(0, fep->hwp + FEC_R_DES_ACTIVE);


	/* Enable interrupts we wish to service */
	/* Enable interrupts we wish to service */
	writel(FEC_ENET_TXF | FEC_ENET_RXF, fep->hwp + FEC_IMASK);
	writel(FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII,
			fep->hwp + FEC_IMASK);
}
}


static void
static void
@@ -1236,9 +1234,6 @@ fec_stop(struct net_device *dev)
	writel(1, fep->hwp + FEC_ECNTRL);
	writel(1, fep->hwp + FEC_ECNTRL);
	udelay(10);
	udelay(10);


	/* Clear outstanding MII command interrupts. */
	writel(FEC_ENET_MII, fep->hwp + FEC_IEVENT);

	writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
	writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
}
}