static int el3_config(struct net_device *dev, struct ifmap *map) { if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) { if (map->port <= 3) { dev->if_port = map->port; netdev_info(dev, "switched to %s port\n", if_names[dev->if_port]); tc589_set_xcvr(dev, dev->if_port); } else return -EINVAL; } return 0; }
/* Reset and restore all of the 3c589 registers. */ static void tc589_reset(struct net_device *dev) { unsigned int ioaddr = dev->base_addr; int i; EL3WINDOW(0); outw(0x0001, ioaddr + 4); /* Activate board. */ outw(0x3f00, ioaddr + 8); /* Set the IRQ line. */ /* Set the station address in window 2. */ EL3WINDOW(2); for (i = 0; i < 6; i++) outb(dev->dev_addr[i], ioaddr + i); tc589_set_xcvr(dev, dev->if_port); /* Switch to the stats window, and clear all stats by reading. */ outw(StatsDisable, ioaddr + EL3_CMD); EL3WINDOW(6); for (i = 0; i < 9; i++) inb(ioaddr+i); inw(ioaddr + 10); inw(ioaddr + 12); /* Switch to register set 1 for normal use. */ EL3WINDOW(1); /* Accept b-cast and phys addr only. */ outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD); outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */ outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */ outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */ /* Allow status bits to be seen. */ outw(SetStatusEnb | 0xff, ioaddr + EL3_CMD); /* Ack all pending events, and set active indicator mask. */ outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq, ioaddr + EL3_CMD); outw(SetIntrEnb | IntLatch | TxAvailable | RxComplete | StatsFull | AdapterFailure, ioaddr + EL3_CMD); }
static void media_check(unsigned long arg) { struct net_device *dev = (struct net_device *)(arg); struct el3_private *lp = netdev_priv(dev); unsigned int ioaddr = dev->base_addr; u16 media, errs; unsigned long flags; if (!netif_device_present(dev)) goto reschedule; /* Check for pending interrupt with expired latency timer: with this, we can limp along even if the interrupt is blocked */ if ((inw(ioaddr + EL3_STATUS) & IntLatch) && (inb(ioaddr + EL3_TIMER) == 0xff)) { if (!lp->fast_poll) netdev_warn(dev, "interrupt(s) dropped!\n"); local_irq_save(flags); el3_interrupt(dev->irq, dev); local_irq_restore(flags); lp->fast_poll = HZ; } if (lp->fast_poll) { lp->fast_poll--; lp->media.expires = jiffies + HZ/100; add_timer(&lp->media); return; } /* lp->lock guards the EL3 window. Window should always be 1 except when the lock is held */ spin_lock_irqsave(&lp->lock, flags); EL3WINDOW(4); media = inw(ioaddr+WN4_MEDIA) & 0xc810; /* Ignore collisions unless we've had no irq's recently */ if (time_before(jiffies, lp->last_irq + HZ)) { media &= ~0x0010; } else { /* Try harder to detect carrier errors */ EL3WINDOW(6); outw(StatsDisable, ioaddr + EL3_CMD); errs = inb(ioaddr + 0); outw(StatsEnable, ioaddr + EL3_CMD); dev->stats.tx_carrier_errors += errs; if (errs || (lp->media_status & 0x0010)) media |= 0x0010; } if (media != lp->media_status) { if ((media & lp->media_status & 0x8000) && ((lp->media_status ^ media) & 0x0800)) netdev_info(dev, "%s link beat\n", (lp->media_status & 0x0800 ? "lost" : "found")); else if ((media & lp->media_status & 0x4000) && ((lp->media_status ^ media) & 0x0010)) netdev_info(dev, "coax cable %s\n", (lp->media_status & 0x0010 ? "ok" : "problem")); if (dev->if_port == 0) { if (media & 0x8000) { if (media & 0x0800) netdev_info(dev, "flipped to 10baseT\n"); else tc589_set_xcvr(dev, 2); } else if (media & 0x4000) { if (media & 0x0010) tc589_set_xcvr(dev, 1); else netdev_info(dev, "flipped to 10base2\n"); } } lp->media_status = media; } EL3WINDOW(1); spin_unlock_irqrestore(&lp->lock, flags); reschedule: lp->media.expires = jiffies + HZ; add_timer(&lp->media); }
static void media_check(u_long arg) { struct el3_private *lp = (struct el3_private *)(arg); struct net_device *dev = &lp->dev; ioaddr_t ioaddr = dev->base_addr; u_short media, errs; u_long flags; if (!netif_device_present(dev)) goto reschedule; EL3WINDOW(1); /* Check for pending interrupt with expired latency timer: with this, we can limp along even if the interrupt is blocked */ if ((inw(ioaddr + EL3_STATUS) & IntLatch) && (inb(ioaddr + EL3_TIMER) == 0xff)) { if (!lp->fast_poll) printk(KERN_INFO "%s: interrupt(s) dropped!\n", dev->name); el3_interrupt(dev->irq, lp, NULL); lp->fast_poll = HZ; } if (lp->fast_poll) { lp->fast_poll--; lp->media.expires = jiffies + 1; add_timer(&lp->media); return; } save_flags(flags); cli(); EL3WINDOW(4); media = inw(ioaddr+WN4_MEDIA) & 0xc810; /* Ignore collisions unless we've had no irq's recently */ if (jiffies - lp->last_irq < HZ) { media &= ~0x0010; } else { /* Try harder to detect carrier errors */ EL3WINDOW(6); outw(StatsDisable, ioaddr + EL3_CMD); errs = inb(ioaddr + 0); outw(StatsEnable, ioaddr + EL3_CMD); lp->stats.tx_carrier_errors += errs; if (errs || (lp->media_status & 0x0010)) media |= 0x0010; } if (media != lp->media_status) { if ((media & lp->media_status & 0x8000) && ((lp->media_status ^ media) & 0x0800)) printk(KERN_INFO "%s: %s link beat\n", dev->name, (lp->media_status & 0x0800 ? "lost" : "found")); else if ((media & lp->media_status & 0x4000) && ((lp->media_status ^ media) & 0x0010)) printk(KERN_INFO "%s: coax cable %s\n", dev->name, (lp->media_status & 0x0010 ? "ok" : "problem")); if (dev->if_port == 0) { if (media & 0x8000) { if (media & 0x0800) printk(KERN_INFO "%s: flipped to 10baseT\n", dev->name); else tc589_set_xcvr(dev, 2); } else if (media & 0x4000) { if (media & 0x0010) tc589_set_xcvr(dev, 1); else printk(KERN_INFO "%s: flipped to 10base2\n", dev->name); } } lp->media_status = media; } EL3WINDOW(1); restore_flags(flags); reschedule: lp->media.expires = jiffies + HZ; add_timer(&lp->media); }