diff options
Diffstat (limited to 'drivers/net/pcmcia/axnet_cs.c')
-rw-r--r-- | drivers/net/pcmcia/axnet_cs.c | 189 |
1 files changed, 99 insertions, 90 deletions
diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c index aa558136939..448a0948852 100644 --- a/drivers/net/pcmcia/axnet_cs.c +++ b/drivers/net/pcmcia/axnet_cs.c @@ -35,6 +35,7 @@ #include <linux/spinlock.h> #include <linux/ethtool.h> #include <linux/netdevice.h> +#include <linux/crc32.h> #include "../8390.h" #include <pcmcia/cs_types.h> @@ -85,8 +86,8 @@ static char *version = /*====================================================================*/ -static void axnet_config(dev_link_t *link); -static void axnet_release(dev_link_t *link); +static int axnet_config(struct pcmcia_device *link); +static void axnet_release(struct pcmcia_device *link); static int axnet_open(struct net_device *dev); static int axnet_close(struct net_device *dev); static int axnet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); @@ -116,7 +117,7 @@ static irqreturn_t ax_interrupt(int irq, void *dev_id, struct pt_regs *regs); /*====================================================================*/ typedef struct axnet_dev_t { - dev_link_t link; + struct pcmcia_device *p_dev; dev_node_t node; caddr_t base; struct timer_list watchdog; @@ -141,10 +142,9 @@ static inline axnet_dev_t *PRIV(struct net_device *dev) ======================================================================*/ -static int axnet_attach(struct pcmcia_device *p_dev) +static int axnet_probe(struct pcmcia_device *link) { axnet_dev_t *info; - dev_link_t *link; struct net_device *dev; DEBUG(0, "axnet_attach()\n"); @@ -156,7 +156,7 @@ static int axnet_attach(struct pcmcia_device *p_dev) return -ENOMEM; info = PRIV(dev); - link = &info->link; + info->p_dev = link; link->priv = dev; link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; link->irq.IRQInfo1 = IRQ_LEVEL_ID; @@ -168,13 +168,7 @@ static int axnet_attach(struct pcmcia_device *p_dev) dev->do_ioctl = &axnet_ioctl; SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops); - link->handle = p_dev; - p_dev->instance = link; - - link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; - axnet_config(link); - - return 0; + return axnet_config(link); } /* axnet_attach */ /*====================================================================== @@ -186,18 +180,16 @@ static int axnet_attach(struct pcmcia_device *p_dev) ======================================================================*/ -static void axnet_detach(struct pcmcia_device *p_dev) +static void axnet_detach(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); struct net_device *dev = link->priv; DEBUG(0, "axnet_detach(0x%p)\n", link); - if (link->dev) + if (link->dev_node) unregister_netdev(dev); - if (link->state & DEV_CONFIG) - axnet_release(link); + axnet_release(link); free_netdev(dev); } /* axnet_detach */ @@ -208,7 +200,7 @@ static void axnet_detach(struct pcmcia_device *p_dev) ======================================================================*/ -static int get_prom(dev_link_t *link) +static int get_prom(struct pcmcia_device *link) { struct net_device *dev = link->priv; kio_addr_t ioaddr = dev->base_addr; @@ -262,7 +254,7 @@ static int get_prom(dev_link_t *link) #define CS_CHECK(fn, ret) \ do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) -static int try_io_port(dev_link_t *link) +static int try_io_port(struct pcmcia_device *link) { int j, ret; if (link->io.NumPorts1 == 32) { @@ -283,25 +275,23 @@ static int try_io_port(dev_link_t *link) for (j = 0; j < 0x400; j += 0x20) { link->io.BasePort1 = j ^ 0x300; link->io.BasePort2 = (j ^ 0x300) + 0x10; - ret = pcmcia_request_io(link->handle, &link->io); + ret = pcmcia_request_io(link, &link->io); if (ret == CS_SUCCESS) return ret; } return ret; } else { - return pcmcia_request_io(link->handle, &link->io); + return pcmcia_request_io(link, &link->io); } } -static void axnet_config(dev_link_t *link) +static int axnet_config(struct pcmcia_device *link) { - client_handle_t handle = link->handle; struct net_device *dev = link->priv; axnet_dev_t *info = PRIV(dev); tuple_t tuple; cisparse_t parse; int i, j, last_ret, last_fn; u_short buf[64]; - config_info_t conf; DEBUG(0, "axnet_config(0x%p)\n", link); @@ -310,29 +300,22 @@ static void axnet_config(dev_link_t *link) tuple.TupleDataMax = sizeof(buf); tuple.TupleOffset = 0; tuple.DesiredTuple = CISTPL_CONFIG; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); + CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); link->conf.ConfigBase = parse.config.base; /* don't trust the CIS on this; Linksys got it wrong */ link->conf.Present = 0x63; - /* Configure card */ - link->state |= DEV_CONFIG; - - /* Look up current Vcc */ - CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(handle, &conf)); - link->conf.Vcc = conf.Vcc; - tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; tuple.Attributes = 0; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); while (last_ret == CS_SUCCESS) { cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); cistpl_io_t *io = &(parse.cftable_entry.io); - if (pcmcia_get_tuple_data(handle, &tuple) != 0 || - pcmcia_parse_tuple(handle, &tuple, &parse) != 0 || + if (pcmcia_get_tuple_data(link, &tuple) != 0 || + pcmcia_parse_tuple(link, &tuple, &parse) != 0 || cfg->index == 0 || cfg->io.nwin == 0) goto next_entry; @@ -354,21 +337,21 @@ static void axnet_config(dev_link_t *link) if (last_ret == CS_SUCCESS) break; } next_entry: - last_ret = pcmcia_get_next_tuple(handle, &tuple); + last_ret = pcmcia_get_next_tuple(link, &tuple); } if (last_ret != CS_SUCCESS) { - cs_error(handle, RequestIO, last_ret); + cs_error(link, RequestIO, last_ret); goto failed; } - CS_CHECK(RequestIRQ, pcmcia_request_irq(handle, &link->irq)); + CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); if (link->io.NumPorts2 == 8) { link->conf.Attributes |= CONF_ENABLE_SPKR; link->conf.Status = CCSR_AUDIO_ENA; } - CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf)); + CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); dev->irq = link->irq.AssignedIRQ; dev->base_addr = link->io.BasePort1; @@ -405,7 +388,7 @@ static void axnet_config(dev_link_t *link) Bit 2 of CCSR is active low. */ if (i == 32) { conf_reg_t reg = { 0, CS_WRITE, CISREG_CCSR, 0x04 }; - pcmcia_access_configuration_register(link->handle, ®); + pcmcia_access_configuration_register(link, ®); for (i = 0; i < 32; i++) { j = mdio_read(dev->base_addr + AXNET_MII_EEP, i, 1); if ((j != 0) && (j != 0xffff)) break; @@ -413,13 +396,12 @@ static void axnet_config(dev_link_t *link) } info->phy_id = (i < 32) ? i : -1; - link->dev = &info->node; - link->state &= ~DEV_CONFIG_PENDING; - SET_NETDEV_DEV(dev, &handle_to_dev(handle)); + link->dev_node = &info->node; + SET_NETDEV_DEV(dev, &handle_to_dev(link)); if (register_netdev(dev) != 0) { printk(KERN_NOTICE "axnet_cs: register_netdev() failed\n"); - link->dev = NULL; + link->dev_node = NULL; goto failed; } @@ -435,14 +417,13 @@ static void axnet_config(dev_link_t *link) } else { printk(KERN_NOTICE " No MII transceivers found!\n"); } - return; + return 0; cs_failed: - cs_error(link->handle, last_fn, last_ret); + cs_error(link, last_fn, last_ret); failed: axnet_release(link); - link->state &= ~DEV_CONFIG_PENDING; - return; + return -ENODEV; } /* axnet_config */ /*====================================================================== @@ -453,45 +434,29 @@ failed: ======================================================================*/ -static void axnet_release(dev_link_t *link) +static void axnet_release(struct pcmcia_device *link) { - DEBUG(0, "axnet_release(0x%p)\n", link); - - pcmcia_release_configuration(link->handle); - pcmcia_release_io(link->handle, &link->io); - pcmcia_release_irq(link->handle, &link->irq); - - link->state &= ~DEV_CONFIG; + pcmcia_disable_device(link); } -static int axnet_suspend(struct pcmcia_device *p_dev) +static int axnet_suspend(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); struct net_device *dev = link->priv; - link->state |= DEV_SUSPEND; - if (link->state & DEV_CONFIG) { - if (link->open) - netif_device_detach(dev); - pcmcia_release_configuration(link->handle); - } + if (link->open) + netif_device_detach(dev); return 0; } -static int axnet_resume(struct pcmcia_device *p_dev) +static int axnet_resume(struct pcmcia_device *link) { - dev_link_t *link = dev_to_instance(p_dev); struct net_device *dev = link->priv; - link->state &= ~DEV_SUSPEND; - if (link->state & DEV_CONFIG) { - pcmcia_request_configuration(link->handle, &link->conf); - if (link->open) { - axnet_reset_8390(dev); - AX88190_init(dev, 1); - netif_device_attach(dev); - } + if (link->open) { + axnet_reset_8390(dev); + AX88190_init(dev, 1); + netif_device_attach(dev); } return 0; @@ -561,11 +526,11 @@ static void mdio_write(kio_addr_t addr, int phy_id, int loc, int value) static int axnet_open(struct net_device *dev) { axnet_dev_t *info = PRIV(dev); - dev_link_t *link = &info->link; + struct pcmcia_device *link = info->p_dev; DEBUG(2, "axnet_open('%s')\n", dev->name); - if (!DEV_OK(link)) + if (!pcmcia_dev_present(link)) return -ENODEV; link->open++; @@ -587,7 +552,7 @@ static int axnet_open(struct net_device *dev) static int axnet_close(struct net_device *dev) { axnet_dev_t *info = PRIV(dev); - dev_link_t *link = &info->link; + struct pcmcia_device *link = info->p_dev; DEBUG(2, "axnet_close('%s')\n", dev->name); @@ -832,7 +797,7 @@ static struct pcmcia_driver axnet_cs_driver = { .drv = { .name = "axnet_cs", }, - .probe = axnet_attach, + .probe = axnet_probe, .remove = axnet_detach, .id_table = axnet_ids, .suspend = axnet_suspend, @@ -1595,7 +1560,7 @@ static void ei_receive(struct net_device *dev) static void ei_rx_overrun(struct net_device *dev) { - axnet_dev_t *info = (axnet_dev_t *)dev; + axnet_dev_t *info = PRIV(dev); long e8390_base = dev->base_addr; unsigned char was_txing, must_resend = 0; struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); @@ -1682,17 +1647,67 @@ static struct net_device_stats *get_stats(struct net_device *dev) return &ei_local->stat; } +/* + * Form the 64 bit 8390 multicast table from the linked list of addresses + * associated with this dev structure. + */ + +static inline void make_mc_bits(u8 *bits, struct net_device *dev) +{ + struct dev_mc_list *dmi; + u32 crc; + + for (dmi=dev->mc_list; dmi; dmi=dmi->next) { + + crc = ether_crc(ETH_ALEN, dmi->dmi_addr); + /* + * The 8390 uses the 6 most significant bits of the + * CRC to index the multicast table. + */ + bits[crc>>29] |= (1<<((crc>>26)&7)); + } +} + /** * do_set_multicast_list - set/clear multicast filter * @dev: net device for which multicast filter is adjusted * - * Set or clear the multicast filter for this adaptor. May be called - * from a BH in 2.1.x. Must be called with lock held. + * Set or clear the multicast filter for this adaptor. + * Must be called with lock held. */ static void do_set_multicast_list(struct net_device *dev) { long e8390_base = dev->base_addr; + int i; + struct ei_device *ei_local = (struct ei_device*)netdev_priv(dev); + + if (!(dev->flags&(IFF_PROMISC|IFF_ALLMULTI))) { + memset(ei_local->mcfilter, 0, 8); + if (dev->mc_list) + make_mc_bits(ei_local->mcfilter, dev); + } else { + /* set to accept-all */ + memset(ei_local->mcfilter, 0xFF, 8); + } + + /* + * DP8390 manuals don't specify any magic sequence for altering + * the multicast regs on an already running card. To be safe, we + * ensure multicast mode is off prior to loading up the new hash + * table. If this proves to be not enough, we can always resort + * to stopping the NIC, loading the table and then restarting. + */ + + if (netif_running(dev)) + outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR); + + outb_p(E8390_NODMA + E8390_PAGE1, e8390_base + E8390_CMD); + for(i = 0; i < 8; i++) + { + outb_p(ei_local->mcfilter[i], e8390_base + EN1_MULT_SHIFT(i)); + } + outb_p(E8390_NODMA + E8390_PAGE0, e8390_base + E8390_CMD); if(dev->flags&IFF_PROMISC) outb_p(E8390_RXCONFIG | 0x58, e8390_base + EN0_RXCR); @@ -1794,12 +1809,6 @@ static void AX88190_init(struct net_device *dev, int startp) if(inb_p(e8390_base + EN1_PHYS_SHIFT(i))!=dev->dev_addr[i]) printk(KERN_ERR "Hw. address read/write mismap %d\n",i); } - /* - * Initialize the multicast list to accept-all. If we enable multicast - * the higher levels can do the filtering. - */ - for (i = 0; i < 8; i++) - outb_p(0xff, e8390_base + EN1_MULT + i); outb_p(ei_local->rx_start_page, e8390_base + EN1_CURPAG); outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD); |