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

Commit 775637df authored by Andrew Victor's avatar Andrew Victor Committed by Jeff Garzik
Browse files

[PATCH] AT91RM9200 Ethernet #1: Link poll



For Ethernet PHYs that don't have an IRQ pin or boards that don't
connect the IRQ pin to the processor, we enable a timer to poll the
PHY's link state.

Patch originally supplied by Eric Benard and Roman Kolesnikov.

Signed-off-by: default avatarAndrew Victor <andrew@sanpeople.com>
Signed-off-by: default avatarJeff Garzik <jeff@garzik.org>
parent d955d90b
Loading
Loading
Loading
Loading
+43 −18
Original line number Original line Diff line number Diff line
@@ -45,6 +45,9 @@
static struct net_device *at91_dev;
static struct net_device *at91_dev;
static struct clk *ether_clk;
static struct clk *ether_clk;


static struct timer_list check_timer;
#define LINK_POLL_INTERVAL	(HZ)

/* ..................................................................... */
/* ..................................................................... */


/*
/*
@@ -143,7 +146,7 @@ static void read_phy(unsigned char phy_addr, unsigned char address, unsigned int
 * MAC accordingly.
 * MAC accordingly.
 * If no link or auto-negotiation is busy, then no changes are made.
 * If no link or auto-negotiation is busy, then no changes are made.
 */
 */
static void update_linkspeed(struct net_device *dev)
static void update_linkspeed(struct net_device *dev, int silent)
{
{
	struct at91_private *lp = (struct at91_private *) dev->priv;
	struct at91_private *lp = (struct at91_private *) dev->priv;
	unsigned int bmsr, bmcr, lpa, mac_cfg;
	unsigned int bmsr, bmcr, lpa, mac_cfg;
@@ -151,6 +154,7 @@ static void update_linkspeed(struct net_device *dev)


	if (!mii_link_ok(&lp->mii)) {		/* no link */
	if (!mii_link_ok(&lp->mii)) {		/* no link */
		netif_carrier_off(dev);
		netif_carrier_off(dev);
		if (!silent)
			printk(KERN_INFO "%s: Link down.\n", dev->name);
			printk(KERN_INFO "%s: Link down.\n", dev->name);
		return;
		return;
	}
	}
@@ -186,6 +190,7 @@ static void update_linkspeed(struct net_device *dev)
	}
	}
	at91_emac_write(AT91_EMAC_CFG, mac_cfg);
	at91_emac_write(AT91_EMAC_CFG, mac_cfg);


	if (!silent)
		printk(KERN_INFO "%s: Link now %i-%s\n", dev->name, speed, (duplex == DUPLEX_FULL) ? "FullDuplex" : "HalfDuplex");
		printk(KERN_INFO "%s: Link now %i-%s\n", dev->name, speed, (duplex == DUPLEX_FULL) ? "FullDuplex" : "HalfDuplex");
	netif_carrier_on(dev);
	netif_carrier_on(dev);
}
}
@@ -226,7 +231,7 @@ static irqreturn_t at91ether_phy_interrupt(int irq, void *dev_id, struct pt_regs
			goto done;
			goto done;
	}
	}


	update_linkspeed(dev);
	update_linkspeed(dev, 0);


done:
done:
	disable_mdi();
	disable_mdi();
@@ -243,14 +248,17 @@ static void enable_phyirq(struct net_device *dev)
	unsigned int dsintr, irq_number;
	unsigned int dsintr, irq_number;
	int status;
	int status;


	if (lp->phy_type == MII_RTL8201_ID)	/* RTL8201 does not have an interrupt */
	irq_number = lp->board_data.phy_irq_pin;
		return;
	if (!irq_number) {
	if (lp->phy_type == MII_DP83847_ID)	/* DP83847 does not have an interrupt */
		/*
		return;
		 * PHY doesn't have an IRQ pin (RTL8201, DP83847, AC101L),
	if (lp->phy_type == MII_AC101L_ID)	/* AC101L interrupt not supported yet */
		 * or board does not have it connected.
		 */
		check_timer.expires = jiffies + LINK_POLL_INTERVAL;
		add_timer(&check_timer);
		return;
		return;
	}


	irq_number = lp->board_data.phy_irq_pin;
	status = request_irq(irq_number, at91ether_phy_interrupt, 0, dev->name, dev);
	status = request_irq(irq_number, at91ether_phy_interrupt, 0, dev->name, dev);
	if (status) {
	if (status) {
		printk(KERN_ERR "at91_ether: PHY IRQ %d request failed - status %d!\n", irq_number, status);
		printk(KERN_ERR "at91_ether: PHY IRQ %d request failed - status %d!\n", irq_number, status);
@@ -292,12 +300,11 @@ static void disable_phyirq(struct net_device *dev)
	unsigned int dsintr;
	unsigned int dsintr;
	unsigned int irq_number;
	unsigned int irq_number;


	if (lp->phy_type == MII_RTL8201_ID) 	/* RTL8201 does not have an interrupt */
	irq_number = lp->board_data.phy_irq_pin;
		return;
	if (!irq_number) {
	if (lp->phy_type == MII_DP83847_ID)	/* DP83847 does not have an interrupt */
		del_timer_sync(&check_timer);
		return;
	if (lp->phy_type == MII_AC101L_ID)	/* AC101L interrupt not supported yet */
		return;
		return;
	}


	spin_lock_irq(&lp->lock);
	spin_lock_irq(&lp->lock);
	enable_mdi();
	enable_mdi();
@@ -326,7 +333,6 @@ static void disable_phyirq(struct net_device *dev)
	disable_mdi();
	disable_mdi();
	spin_unlock_irq(&lp->lock);
	spin_unlock_irq(&lp->lock);


	irq_number = lp->board_data.phy_irq_pin;
	free_irq(irq_number, dev);			/* Free interrupt handler */
	free_irq(irq_number, dev);			/* Free interrupt handler */
}
}


@@ -355,6 +361,18 @@ static void reset_phy(struct net_device *dev)
}
}
#endif
#endif


static void at91ether_check_link(unsigned long dev_id)
{
	struct net_device *dev = (struct net_device *) dev_id;

	enable_mdi();
	update_linkspeed(dev, 1);
	disable_mdi();

	check_timer.expires = jiffies + LINK_POLL_INTERVAL;
	add_timer(&check_timer);
}

/* ......................... ADDRESS MANAGEMENT ........................ */
/* ......................... ADDRESS MANAGEMENT ........................ */


/*
/*
@@ -708,7 +726,7 @@ static int at91ether_open(struct net_device *dev)
	/* Determine current link speed */
	/* Determine current link speed */
	spin_lock_irq(&lp->lock);
	spin_lock_irq(&lp->lock);
	enable_mdi();
	enable_mdi();
	update_linkspeed(dev);
	update_linkspeed(dev, 0);
	disable_mdi();
	disable_mdi();
	spin_unlock_irq(&lp->lock);
	spin_unlock_irq(&lp->lock);


@@ -992,11 +1010,18 @@ static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_add
	/* Determine current link speed */
	/* Determine current link speed */
	spin_lock_irq(&lp->lock);
	spin_lock_irq(&lp->lock);
	enable_mdi();
	enable_mdi();
	update_linkspeed(dev);
	update_linkspeed(dev, 0);
	disable_mdi();
	disable_mdi();
	spin_unlock_irq(&lp->lock);
	spin_unlock_irq(&lp->lock);
	netif_carrier_off(dev);		/* will be enabled in open() */
	netif_carrier_off(dev);		/* will be enabled in open() */


	/* If board has no PHY IRQ, use a timer to poll the PHY */
	if (!lp->board_data.phy_irq_pin) {
		init_timer(&check_timer);
		check_timer.data = (unsigned long)dev;
		check_timer.function = at91ether_check_link;
	}

	/* Display ethernet banner */
	/* Display ethernet banner */
	printk(KERN_INFO "%s: AT91 ethernet at 0x%08x int=%d %s%s (%02x:%02x:%02x:%02x:%02x:%02x)\n",
	printk(KERN_INFO "%s: AT91 ethernet at 0x%08x int=%d %s%s (%02x:%02x:%02x:%02x:%02x:%02x)\n",
		dev->name, (uint) dev->base_addr, dev->irq,
		dev->name, (uint) dev->base_addr, dev->irq,