diff options
Diffstat (limited to 'drivers/net/pcmcia/3c574_cs.c')
-rw-r--r-- | drivers/net/pcmcia/3c574_cs.c | 148 |
1 files changed, 62 insertions, 86 deletions
diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c index 0e9110a8b..4e4fc4157 100644 --- a/drivers/net/pcmcia/3c574_cs.c +++ b/drivers/net/pcmcia/3c574_cs.c @@ -119,7 +119,7 @@ static int irq_list[4] = { -1 }; #define TX_TIMEOUT ((800*HZ)/1000) /* Maximum events (Rx packets, etc.) to handle at each interrupt. */ -static int max_interrupt_work = 64; +static int max_interrupt_work = 32; /* Force full duplex modes? */ static int full_duplex = 0; @@ -207,6 +207,8 @@ enum Window4 { /* Window 4: Xcvr/media bits. */ #define MEDIA_TP 0x00C0 /* Enable link beat and jabber for 10baseT. */ struct el3_private { + dev_link_t link; + struct net_device dev; dev_node_t node; struct net_device_stats stats; u16 advertising, partner; /* NWay media advertisement */ @@ -253,13 +255,11 @@ static void media_check(u_long arg); static int el3_open(struct net_device *dev); static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev); static void el3_interrupt(int irq, void *dev_id, struct pt_regs *regs); -static void update_stats(ioaddr_t addr, struct net_device *dev); +static void update_stats(struct net_device *dev); static struct net_device_stats *el3_get_stats(struct net_device *dev); static int el3_rx(struct net_device *dev, int worklimit); static int el3_close(struct net_device *dev); -#ifdef HAVE_PRIVATE_IOCTL -static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -#endif +static int el3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static void set_rx_mode(struct net_device *dev); static dev_info_t dev_info = "3c574_cs"; @@ -307,6 +307,7 @@ static int tc574_init(struct net_device *dev) static dev_link_t *tc574_attach(void) { + struct el3_private *lp; client_reg_t client_reg; dev_link_t *link; struct net_device *dev; @@ -316,8 +317,12 @@ static dev_link_t *tc574_attach(void) flush_stale_links(); /* Create the PC card device object. */ - link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); - memset(link, 0, sizeof(struct dev_link_t)); + lp = kmalloc(sizeof(*lp), GFP_KERNEL); + if (!lp) return NULL; + memset(lp, 0, sizeof(*lp)); + link = &lp->link; dev = &lp->dev; + link->priv = dev->priv = link->irq.Instance = lp; + link->release.function = &tc574_release; link->release.data = (u_long)link; link->io.NumPorts1 = 32; @@ -336,33 +341,18 @@ static dev_link_t *tc574_attach(void) link->conf.ConfigIndex = 1; link->conf.Present = PRESENT_OPTION; - /* Create the network device object. */ - dev = kmalloc(sizeof(struct net_device), GFP_KERNEL); - memset(dev, 0, sizeof(struct net_device)); - - /* Make up a Odie-specific data structure. */ - dev->priv = kmalloc(sizeof(struct el3_private), GFP_KERNEL); - memset(dev->priv, 0, sizeof(struct el3_private)); - /* The EL3-specific entries in the device structure. */ dev->hard_start_xmit = &el3_start_xmit; dev->get_stats = &el3_get_stats; -#ifdef HAVE_PRIVATE_IOCTL - dev->do_ioctl = &private_ioctl; -#endif + dev->do_ioctl = &el3_ioctl; dev->set_multicast_list = &set_rx_mode; ether_setup(dev); - dev->name = ((struct el3_private *)dev->priv)->node.dev_name; + dev->name = lp->node.dev_name; dev->init = &tc574_init; dev->open = &el3_open; dev->stop = &el3_close; dev->tbusy = 1; - link->priv = dev; -#if CS_RELEASE_CODE > 0x2911 - link->irq.Instance = dev; -#endif - /* Register with Card Services */ link->next = dev_list; dev_list = link; @@ -396,6 +386,7 @@ static dev_link_t *tc574_attach(void) static void tc574_detach(dev_link_t *link) { + struct el3_private *lp = link->priv; dev_link_t **linkp; long flags; @@ -428,15 +419,9 @@ static void tc574_detach(dev_link_t *link) /* Unlink device structure, free bits */ *linkp = link->next; - if (link->priv) { - struct net_device *dev = link->priv; - if (link->dev != NULL) - unregister_netdev(dev); - if (dev->priv) - kfree(dev->priv); - kfree(link->priv); - } - kfree(link); + if (link->dev) + unregister_netdev(&lp->dev); + kfree(lp); } /* tc574_detach */ @@ -451,9 +436,9 @@ while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed static void tc574_config(dev_link_t *link) { - client_handle_t handle; - struct net_device *dev; - struct el3_private *lp; + client_handle_t handle = link->handle; + struct el3_private *lp = link->priv; + struct net_device *dev = &lp->dev; tuple_t tuple; cisparse_t parse; u_short buf[32]; @@ -462,8 +447,6 @@ static void tc574_config(dev_link_t *link) u16 *phys_addr; char *cardname; - handle = link->handle; - dev = link->priv; phys_addr = (u16 *)dev->dev_addr; DEBUG(0, "3c574_config(0x%p)\n", link); @@ -528,7 +511,6 @@ static void tc574_config(dev_link_t *link) link->state &= ~DEV_CONFIG_PENDING; ioaddr = dev->base_addr; - lp = (struct el3_private *)dev->priv; link->dev = &lp->node; /* The 3c574 normally uses an EEPROM for configuration info, including @@ -641,7 +623,8 @@ failed: static void tc574_release(u_long arg) { dev_link_t *link = (dev_link_t *)arg; - struct net_device *dev = link->priv; + struct el3_private *lp = link->priv; + struct net_device *dev = &lp->dev; DEBUG(0, "3c574_release(0x%p)\n", link); @@ -675,7 +658,8 @@ static int tc574_event(event_t event, int priority, event_callback_args_t *args) { dev_link_t *link = args->client_data; - struct net_device *dev = link->priv; + struct el3_private *lp = link->priv; + struct net_device *dev = &lp->dev; DEBUG(1, "3c574_event(0x%06x)\n", event); @@ -922,10 +906,8 @@ static void tc574_reset(struct net_device *dev) static int el3_open(struct net_device *dev) { struct el3_private *lp = (struct el3_private *)dev->priv; - dev_link_t *link; + dev_link_t *link = &lp->link; - for (link = dev_list; link; link = link->next) - if (link->priv == dev) break; if (!DEV_OK(link)) return -ENODEV; @@ -935,14 +917,14 @@ static int el3_open(struct net_device *dev) tc574_reset(dev); lp->media.function = &media_check; - lp->media.data = (u_long)dev; + lp->media.data = (u_long)lp; lp->media.expires = jiffies + HZ; add_timer(&lp->media); DEBUG(2, "%s: opened, status %4.4x.\n", dev->name, inw(dev->base_addr + EL3_STATUS)); - return 0; /* Always succeed */ + return 0; } static void el3_tx_timeout(struct net_device *dev) @@ -1054,14 +1036,13 @@ static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev) /* The EL3 interrupt handler. */ static void el3_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - struct net_device *dev = (struct net_device *)dev_id; - struct el3_private *lp; + struct el3_private *lp = dev_id; + struct net_device *dev = &lp->dev; ioaddr_t ioaddr, status; int work_budget = max_interrupt_work; - if ((dev == NULL) || !dev->start) + if ((lp == NULL) || !dev->start) return; - lp = (struct el3_private *)dev->priv; ioaddr = dev->base_addr; #ifdef PCMCIA_DEBUG @@ -1098,7 +1079,7 @@ static void el3_interrupt(int irq, void *dev_id, struct pt_regs *regs) if (status & (AdapterFailure | RxEarly | StatsFull)) { /* Handle all uncommon interrupts. */ if (status & StatsFull) - update_stats(ioaddr, dev); + update_stats(dev); if (status & RxEarly) { work_budget = el3_rx(dev, work_budget); outw(AckIntr | RxEarly, ioaddr + EL3_CMD); @@ -1151,8 +1132,8 @@ static void el3_interrupt(int irq, void *dev_id, struct pt_regs *regs) */ static void media_check(u_long arg) { - struct net_device *dev = (struct net_device *)(arg); - struct el3_private *lp = (struct el3_private *)dev->priv; + struct el3_private *lp = (struct el3_private *)arg; + struct net_device *dev = &lp->dev; ioaddr_t ioaddr = dev->base_addr; u_long flags; u_short /* cable, */ media, partner; @@ -1165,7 +1146,7 @@ static void media_check(u_long arg) (inb(ioaddr + Timer) == 0xff)) { if (!lp->fast_poll) printk(KERN_INFO "%s: interrupt(s) dropped!\n", dev->name); - el3_interrupt(dev->irq, dev, NULL); + el3_interrupt(dev->irq, lp, NULL); lp->fast_poll = HZ; } if (lp->fast_poll) { @@ -1228,7 +1209,7 @@ static struct net_device_stats *el3_get_stats(struct net_device *dev) struct el3_private *lp = (struct el3_private *)dev->priv; if (dev->start) - update_stats(dev->base_addr, dev); + update_stats(dev); return &lp->stats; } @@ -1236,9 +1217,10 @@ static struct net_device_stats *el3_get_stats(struct net_device *dev) Suprisingly this need not be run single-threaded, but it effectively is. The counters clear when read, so the adds must merely be atomic. */ -static void update_stats(ioaddr_t ioaddr, struct net_device *dev) +static void update_stats(struct net_device *dev) { struct el3_private *lp = (struct el3_private *)dev->priv; + ioaddr_t ioaddr = dev->base_addr; u8 upper_cnt; DEBUG(2, "%s: updating the statistics.\n", dev->name); @@ -1252,16 +1234,16 @@ static void update_stats(ioaddr_t ioaddr, struct net_device *dev) lp->stats.tx_carrier_errors += inb(ioaddr + 0); lp->stats.tx_heartbeat_errors += inb(ioaddr + 1); /* Multiple collisions. */ inb(ioaddr + 2); - lp->stats.collisions += inb(ioaddr + 3); - lp->stats.tx_window_errors += inb(ioaddr + 4); - lp->stats.rx_fifo_errors += inb(ioaddr + 5); - lp->stats.tx_packets += inb(ioaddr + 6); - upper_cnt = inb(ioaddr + 9); - lp->stats.tx_packets += (upper_cnt&0x30) << 4; - /* Rx packets */ inb(ioaddr + 7); - /* Tx deferrals */ inb(ioaddr + 8); - lp->stats.rx_bytes += inw(ioaddr + 10); - lp->stats.tx_bytes += inw(ioaddr + 12); + lp->stats.collisions += inb(ioaddr + 3); + lp->stats.tx_window_errors += inb(ioaddr + 4); + lp->stats.rx_fifo_errors += inb(ioaddr + 5); + lp->stats.tx_packets += inb(ioaddr + 6); + upper_cnt = inb(ioaddr + 9); + lp->stats.tx_packets += (upper_cnt&0x30) << 4; + /* Rx packets */ inb(ioaddr + 7); + /* Tx deferrals */ inb(ioaddr + 8); + lp->stats.rx_bytes += inw(ioaddr + 10); + lp->stats.tx_bytes += inw(ioaddr + 12); /* With Vortex and later we must also clear the BadSSD counter. */ EL3WINDOW(4); @@ -1284,12 +1266,12 @@ static int el3_rx(struct net_device *dev, int worklimit) short error = rx_status & 0x3800; lp->stats.rx_errors++; switch (error) { - case 0x0000: lp->stats.rx_over_errors++; break; - case 0x0800: lp->stats.rx_length_errors++; break; - case 0x1000: lp->stats.rx_frame_errors++; break; - case 0x1800: lp->stats.rx_length_errors++; break; - case 0x2000: lp->stats.rx_frame_errors++; break; - case 0x2800: lp->stats.rx_crc_errors++; break; + case 0x0000: lp->stats.rx_over_errors++; break; + case 0x0800: lp->stats.rx_length_errors++; break; + case 0x1000: lp->stats.rx_frame_errors++; break; + case 0x1800: lp->stats.rx_length_errors++; break; + case 0x2000: lp->stats.rx_frame_errors++; break; + case 0x2800: lp->stats.rx_crc_errors++; break; } } else { short pkt_len = rx_status & 0x7ff; @@ -1343,14 +1325,13 @@ static int el3_rx(struct net_device *dev, int worklimit) return worklimit; } -#ifdef HAVE_PRIVATE_IOCTL /* Provide ioctl() calls to examine the MII xcvr state. */ -static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +static int el3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - struct el3_private *vp = (struct el3_private *)dev->priv; + struct el3_private *lp = (struct el3_private *)dev->priv; ioaddr_t ioaddr = dev->base_addr; u16 *data = (u16 *)&rq->ifr_data; - int phy = vp->phys[0] & 0x1f; + int phy = lp->phys[0] & 0x1f; DEBUG(2, "%s: In ioct(%-.6s, %#4.4x) %4.4x %4.4x %4.4x %4.4x.\n", dev->name, rq->ifr_ifrn.ifrn_name, cmd, @@ -1378,7 +1359,7 @@ static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) int saved_window; long flags; - if (!suser()) + if (!capable(CAP_NET_ADMIN)) return -EPERM; save_flags(flags); cli(); @@ -1393,7 +1374,6 @@ static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) return -EOPNOTSUPP; } } -#endif /* HAVE_PRIVATE_IOCTL */ /* The Odie chip has a 64 bin multicast filter, but the bit layout is not documented. Until it is we revert to receiving all multicast frames when @@ -1419,12 +1399,8 @@ static void set_rx_mode(struct net_device *dev) static int el3_close(struct net_device *dev) { ioaddr_t ioaddr = dev->base_addr; - dev_link_t *link; - - for (link = dev_list; link; link = link->next) - if (link->priv == dev) break; - if (link == NULL) - return -ENODEV; + struct el3_private *lp = dev->priv; + dev_link_t *link = &lp->link; DEBUG(2, "%s: shutting down ethercard.\n", dev->name); @@ -1439,12 +1415,12 @@ static int el3_close(struct net_device *dev) /* Note: Switching to window 0 may disable the IRQ. */ EL3WINDOW(0); - update_stats(ioaddr, dev); + update_stats(dev); } link->open--; dev->start = 0; - del_timer(&((struct el3_private *)dev->priv)->media); + del_timer(&lp->media); if (link->state & DEV_STALE_CONFIG) { link->release.expires = jiffies + HZ/20; link->state |= DEV_RELEASE_PENDING; |