+ int pid = lp->phy_addr;
+ unsigned short lpa, bmcr;
+ char *speed = "", *duplex = "";
+
+ lpa = tc_mdio_read(dev, pid, MII_LPA);
+ bmcr = tc_mdio_read(dev, pid, MII_BMCR);
+ if (options.speed ? (bmcr & BMCR_SPEED100) : (lpa & (LPA_100HALF | LPA_100FULL)))
+ speed = "100Mb/s";
+ else
+ speed = "10Mb/s";
+ if (options.duplex ? (bmcr & BMCR_FULLDPLX) : (lpa & (LPA_100FULL | LPA_10FULL)))
+ duplex = "Full Duplex";
+ else
+ duplex = "Half Duplex";
+
+ if (netif_msg_link(lp))
+ printk(KERN_INFO "%s: Link is up at %s, %s.\n",
+ dev->name, speed, duplex);
+ printk(KERN_DEBUG "%s: MII BMCR %04x BMSR %04x LPA %04x\n",
+ dev->name,
+ bmcr, tc_mdio_read(dev, pid, MII_BMSR), lpa);
+}
+
+static void tc35815_display_forced_link_mode(struct net_device *dev)
+{
+ struct tc35815_local *lp = dev->priv;
+ int pid = lp->phy_addr;
+ unsigned short bmcr;
+ char *speed = "", *duplex = "";
+
+ bmcr = tc_mdio_read(dev, pid, MII_BMCR);
+ if (bmcr & BMCR_SPEED100)
+ speed = "100Mb/s";
+ else
+ speed = "10Mb/s";
+ if (bmcr & BMCR_FULLDPLX)
+ duplex = "Full Duplex.\n";
+ else
+ duplex = "Half Duplex.\n";
+
+ if (netif_msg_link(lp))
+ printk(KERN_INFO "%s: Link has been forced up at %s, %s",
+ dev->name, speed, duplex);
+}
+
+static void tc35815_set_link_modes(struct net_device *dev)
+{
+ struct tc35815_local *lp = dev->priv;
+ struct tc35815_regs __iomem *tr =
+ (struct tc35815_regs __iomem *)dev->base_addr;
+ int pid = lp->phy_addr;
+ unsigned short bmcr, lpa;
+ int speed;
+
+ if (lp->timer_state == arbwait) {
+ lpa = tc_mdio_read(dev, pid, MII_LPA);
+ bmcr = tc_mdio_read(dev, pid, MII_BMCR);
+ printk(KERN_DEBUG "%s: MII BMCR %04x BMSR %04x LPA %04x\n",
+ dev->name,
+ bmcr, tc_mdio_read(dev, pid, MII_BMSR), lpa);
+ if (!(lpa & (LPA_10HALF | LPA_10FULL |
+ LPA_100HALF | LPA_100FULL))) {
+ /* fall back to 10HALF */
+ printk(KERN_INFO "%s: bad ability %04x - falling back to 10HD.\n",
+ dev->name, lpa);
+ lpa = LPA_10HALF;
+ }
+ if (options.duplex ? (bmcr & BMCR_FULLDPLX) : (lpa & (LPA_100FULL | LPA_10FULL)))
+ lp->fullduplex = 1;
+ else
+ lp->fullduplex = 0;
+ if (options.speed ? (bmcr & BMCR_SPEED100) : (lpa & (LPA_100HALF | LPA_100FULL)))
+ speed = 100;
+ else
+ speed = 10;
+ } else {
+ /* Forcing a link mode. */
+ bmcr = tc_mdio_read(dev, pid, MII_BMCR);
+ if (bmcr & BMCR_FULLDPLX)
+ lp->fullduplex = 1;
+ else
+ lp->fullduplex = 0;
+ if (bmcr & BMCR_SPEED100)
+ speed = 100;
+ else
+ speed = 10;
+ }
+
+ tc_writel(tc_readl(&tr->MAC_Ctl) | MAC_HaltReq, &tr->MAC_Ctl);
+ if (lp->fullduplex) {
+ tc_writel(tc_readl(&tr->MAC_Ctl) | MAC_FullDup, &tr->MAC_Ctl);
+ } else {
+ tc_writel(tc_readl(&tr->MAC_Ctl) & ~MAC_FullDup, &tr->MAC_Ctl);
+ }
+ tc_writel(tc_readl(&tr->MAC_Ctl) & ~MAC_HaltReq, &tr->MAC_Ctl);
+
+ /* TX4939 PCFG.SPEEDn bit will be changed on NETDEV_CHANGE event. */
+
+#ifndef NO_CHECK_CARRIER
+ /* TX4939 does not have EnLCarr */
+ if (lp->boardtype != TC35815_TX4939) {
+#ifdef WORKAROUND_LOSTCAR
+ /* WORKAROUND: enable LostCrS only if half duplex operation */
+ if (!lp->fullduplex && lp->boardtype != TC35815_TX4939)
+ tc_writel(tc_readl(&tr->Tx_Ctl) | Tx_EnLCarr, &tr->Tx_Ctl);
+#endif
+ }
+#endif
+ lp->mii.full_duplex = lp->fullduplex;
+}
+
+static void tc35815_timer(unsigned long data)
+{
+ struct net_device *dev = (struct net_device *)data;
+ struct tc35815_local *lp = dev->priv;
+ int pid = lp->phy_addr;
+ unsigned short bmsr, bmcr, lpa;
+ int restart_timer = 0;
+
+ spin_lock_irq(&lp->lock);
+
+ lp->timer_ticks++;
+ switch (lp->timer_state) {
+ case arbwait:
+ /*
+ * Only allow for 5 ticks, thats 10 seconds and much too
+ * long to wait for arbitration to complete.
+ */
+ /* TC35815 need more times... */
+ if (lp->timer_ticks >= 10) {
+ /* Enter force mode. */
+ if (!options.doforce) {
+ printk(KERN_NOTICE "%s: Auto-Negotiation unsuccessful,"
+ " cable probblem?\n", dev->name);
+ /* Try to restart the adaptor. */
+ tc35815_restart(dev);
+ goto out;
+ }
+ printk(KERN_NOTICE "%s: Auto-Negotiation unsuccessful,"
+ " trying force link mode\n", dev->name);
+ printk(KERN_DEBUG "%s: BMCR %x BMSR %x\n", dev->name,
+ tc_mdio_read(dev, pid, MII_BMCR),
+ tc_mdio_read(dev, pid, MII_BMSR));
+ bmcr = BMCR_SPEED100;
+ tc_mdio_write(dev, pid, MII_BMCR, bmcr);
+
+ /*
+ * OK, seems we need do disable the transceiver
+ * for the first tick to make sure we get an
+ * accurate link state at the second tick.
+ */
+
+ lp->timer_state = ltrywait;
+ lp->timer_ticks = 0;
+ restart_timer = 1;
+ } else {
+ /* Anything interesting happen? */
+ bmsr = tc_mdio_read(dev, pid, MII_BMSR);
+ if (bmsr & BMSR_ANEGCOMPLETE) {
+ /* Just what we've been waiting for... */
+ tc35815_set_link_modes(dev);
+
+ /*
+ * Success, at least so far, advance our state
+ * engine.
+ */
+ lp->timer_state = lupwait;
+ restart_timer = 1;
+ } else {
+ restart_timer = 1;
+ }
+ }
+ break;
+
+ case lupwait:
+ /*
+ * Auto negotiation was successful and we are awaiting a
+ * link up status. I have decided to let this timer run
+ * forever until some sort of error is signalled, reporting
+ * a message to the user at 10 second intervals.
+ */
+ bmsr = tc_mdio_read(dev, pid, MII_BMSR);
+ if (bmsr & BMSR_LSTATUS) {
+ /*
+ * Wheee, it's up, display the link mode in use and put
+ * the timer to sleep.
+ */
+ tc35815_display_link_mode(dev);
+ netif_carrier_on(dev);
+#ifdef WORKAROUND_100HALF_PROMISC
+ /* delayed promiscuous enabling */
+ if (dev->flags & IFF_PROMISC)
+ tc35815_set_multicast_list(dev);
+#endif
+#if 1
+ lp->saved_lpa = tc_mdio_read(dev, pid, MII_LPA);
+ lp->timer_state = lcheck;
+ restart_timer = 1;
+#else
+ lp->timer_state = asleep;
+ restart_timer = 0;
+#endif
+ } else {
+ if (lp->timer_ticks >= 10) {
+ printk(KERN_NOTICE "%s: Auto negotiation successful, link still "
+ "not completely up.\n", dev->name);
+ lp->timer_ticks = 0;
+ restart_timer = 1;
+ } else {
+ restart_timer = 1;
+ }
+ }
+ break;
+
+ case ltrywait:
+ /*
+ * Making the timeout here too long can make it take
+ * annoyingly long to attempt all of the link mode
+ * permutations, but then again this is essentially
+ * error recovery code for the most part.
+ */
+ bmsr = tc_mdio_read(dev, pid, MII_BMSR);
+ bmcr = tc_mdio_read(dev, pid, MII_BMCR);
+ if (lp->timer_ticks == 1) {
+ /*
+ * Re-enable transceiver, we'll re-enable the
+ * transceiver next tick, then check link state
+ * on the following tick.
+ */
+ restart_timer = 1;
+ break;
+ }
+ if (lp->timer_ticks == 2) {
+ restart_timer = 1;
+ break;
+ }
+ if (bmsr & BMSR_LSTATUS) {
+ /* Force mode selection success. */
+ tc35815_display_forced_link_mode(dev);
+ netif_carrier_on(dev);
+ tc35815_set_link_modes(dev);
+#ifdef WORKAROUND_100HALF_PROMISC
+ /* delayed promiscuous enabling */
+ if (dev->flags & IFF_PROMISC)
+ tc35815_set_multicast_list(dev);
+#endif
+#if 1
+ lp->saved_lpa = tc_mdio_read(dev, pid, MII_LPA);
+ lp->timer_state = lcheck;
+ restart_timer = 1;
+#else
+ lp->timer_state = asleep;
+ restart_timer = 0;
+#endif