X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fnet%2Fpcmcia%2Faxnet_cs.c;fp=drivers%2Fnet%2Fpcmcia%2Faxnet_cs.c;h=aa5581369399ce98569275853666265525b10fb5;hb=64ba3f394c830ec48a1c31b53dcae312c56f1604;hp=297e9f8053663e0efefda780c0d7978669ce5b64;hpb=be1e6109ac94a859551f8e1774eb9a8469fe055c;p=linux-2.6.git diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c index 297e9f805..aa5581369 100644 --- a/drivers/net/pcmcia/axnet_cs.c +++ b/drivers/net/pcmcia/axnet_cs.c @@ -35,7 +35,6 @@ #include #include #include -#include #include "../8390.h" #include @@ -86,8 +85,8 @@ static char *version = /*====================================================================*/ -static int axnet_config(struct pcmcia_device *link); -static void axnet_release(struct pcmcia_device *link); +static void axnet_config(dev_link_t *link); +static void axnet_release(dev_link_t *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); @@ -117,7 +116,7 @@ static irqreturn_t ax_interrupt(int irq, void *dev_id, struct pt_regs *regs); /*====================================================================*/ typedef struct axnet_dev_t { - struct pcmcia_device *p_dev; + dev_link_t link; dev_node_t node; caddr_t base; struct timer_list watchdog; @@ -142,9 +141,10 @@ static inline axnet_dev_t *PRIV(struct net_device *dev) ======================================================================*/ -static int axnet_probe(struct pcmcia_device *link) +static int axnet_attach(struct pcmcia_device *p_dev) { axnet_dev_t *info; + dev_link_t *link; struct net_device *dev; DEBUG(0, "axnet_attach()\n"); @@ -156,7 +156,7 @@ static int axnet_probe(struct pcmcia_device *link) return -ENOMEM; info = PRIV(dev); - info->p_dev = link; + link = &info->link; link->priv = dev; link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; link->irq.IRQInfo1 = IRQ_LEVEL_ID; @@ -168,7 +168,13 @@ static int axnet_probe(struct pcmcia_device *link) dev->do_ioctl = &axnet_ioctl; SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops); - return axnet_config(link); + link->handle = p_dev; + p_dev->instance = link; + + link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; + axnet_config(link); + + return 0; } /* axnet_attach */ /*====================================================================== @@ -180,16 +186,18 @@ static int axnet_probe(struct pcmcia_device *link) ======================================================================*/ -static void axnet_detach(struct pcmcia_device *link) +static void axnet_detach(struct pcmcia_device *p_dev) { + 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_node) + if (link->dev) unregister_netdev(dev); - axnet_release(link); + if (link->state & DEV_CONFIG) + axnet_release(link); free_netdev(dev); } /* axnet_detach */ @@ -200,7 +208,7 @@ static void axnet_detach(struct pcmcia_device *link) ======================================================================*/ -static int get_prom(struct pcmcia_device *link) +static int get_prom(dev_link_t *link) { struct net_device *dev = link->priv; kio_addr_t ioaddr = dev->base_addr; @@ -254,7 +262,7 @@ static int get_prom(struct pcmcia_device *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(struct pcmcia_device *link) +static int try_io_port(dev_link_t *link) { int j, ret; if (link->io.NumPorts1 == 32) { @@ -275,23 +283,25 @@ static int try_io_port(struct pcmcia_device *link) for (j = 0; j < 0x400; j += 0x20) { link->io.BasePort1 = j ^ 0x300; link->io.BasePort2 = (j ^ 0x300) + 0x10; - ret = pcmcia_request_io(link, &link->io); + ret = pcmcia_request_io(link->handle, &link->io); if (ret == CS_SUCCESS) return ret; } return ret; } else { - return pcmcia_request_io(link, &link->io); + return pcmcia_request_io(link->handle, &link->io); } } -static int axnet_config(struct pcmcia_device *link) +static void axnet_config(dev_link_t *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); @@ -300,22 +310,29 @@ static int axnet_config(struct pcmcia_device *link) tuple.TupleDataMax = sizeof(buf); tuple.TupleOffset = 0; tuple.DesiredTuple = CISTPL_CONFIG; - 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)); + 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)); 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(link, &tuple)); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &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(link, &tuple) != 0 || - pcmcia_parse_tuple(link, &tuple, &parse) != 0 || + if (pcmcia_get_tuple_data(handle, &tuple) != 0 || + pcmcia_parse_tuple(handle, &tuple, &parse) != 0 || cfg->index == 0 || cfg->io.nwin == 0) goto next_entry; @@ -337,21 +354,21 @@ static int axnet_config(struct pcmcia_device *link) if (last_ret == CS_SUCCESS) break; } next_entry: - last_ret = pcmcia_get_next_tuple(link, &tuple); + last_ret = pcmcia_get_next_tuple(handle, &tuple); } if (last_ret != CS_SUCCESS) { - cs_error(link, RequestIO, last_ret); + cs_error(handle, RequestIO, last_ret); goto failed; } - CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); + CS_CHECK(RequestIRQ, pcmcia_request_irq(handle, &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(link, &link->conf)); + CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf)); dev->irq = link->irq.AssignedIRQ; dev->base_addr = link->io.BasePort1; @@ -388,7 +405,7 @@ static int axnet_config(struct pcmcia_device *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, ®); + pcmcia_access_configuration_register(link->handle, ®); for (i = 0; i < 32; i++) { j = mdio_read(dev->base_addr + AXNET_MII_EEP, i, 1); if ((j != 0) && (j != 0xffff)) break; @@ -396,12 +413,13 @@ static int axnet_config(struct pcmcia_device *link) } info->phy_id = (i < 32) ? i : -1; - link->dev_node = &info->node; - SET_NETDEV_DEV(dev, &handle_to_dev(link)); + link->dev = &info->node; + link->state &= ~DEV_CONFIG_PENDING; + SET_NETDEV_DEV(dev, &handle_to_dev(handle)); if (register_netdev(dev) != 0) { printk(KERN_NOTICE "axnet_cs: register_netdev() failed\n"); - link->dev_node = NULL; + link->dev = NULL; goto failed; } @@ -417,13 +435,14 @@ static int axnet_config(struct pcmcia_device *link) } else { printk(KERN_NOTICE " No MII transceivers found!\n"); } - return 0; + return; cs_failed: - cs_error(link, last_fn, last_ret); + cs_error(link->handle, last_fn, last_ret); failed: axnet_release(link); - return -ENODEV; + link->state &= ~DEV_CONFIG_PENDING; + return; } /* axnet_config */ /*====================================================================== @@ -434,29 +453,45 @@ failed: ======================================================================*/ -static void axnet_release(struct pcmcia_device *link) +static void axnet_release(dev_link_t *link) { - pcmcia_disable_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; } -static int axnet_suspend(struct pcmcia_device *link) +static int axnet_suspend(struct pcmcia_device *p_dev) { + dev_link_t *link = dev_to_instance(p_dev); struct net_device *dev = link->priv; - if (link->open) - netif_device_detach(dev); + link->state |= DEV_SUSPEND; + if (link->state & DEV_CONFIG) { + if (link->open) + netif_device_detach(dev); + pcmcia_release_configuration(link->handle); + } return 0; } -static int axnet_resume(struct pcmcia_device *link) +static int axnet_resume(struct pcmcia_device *p_dev) { + dev_link_t *link = dev_to_instance(p_dev); struct net_device *dev = link->priv; - if (link->open) { - axnet_reset_8390(dev); - AX88190_init(dev, 1); - netif_device_attach(dev); + 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); + } } return 0; @@ -526,16 +561,16 @@ 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); - struct pcmcia_device *link = info->p_dev; + dev_link_t *link = &info->link; DEBUG(2, "axnet_open('%s')\n", dev->name); - if (!pcmcia_dev_present(link)) + if (!DEV_OK(link)) return -ENODEV; link->open++; - request_irq(dev->irq, ei_irq_wrapper, IRQF_SHARED, "axnet_cs", dev); + request_irq(dev->irq, ei_irq_wrapper, SA_SHIRQ, "axnet_cs", dev); info->link_status = 0x00; init_timer(&info->watchdog); @@ -552,7 +587,7 @@ static int axnet_open(struct net_device *dev) static int axnet_close(struct net_device *dev) { axnet_dev_t *info = PRIV(dev); - struct pcmcia_device *link = info->p_dev; + dev_link_t *link = &info->link; DEBUG(2, "axnet_close('%s')\n", dev->name); @@ -797,7 +832,7 @@ static struct pcmcia_driver axnet_cs_driver = { .drv = { .name = "axnet_cs", }, - .probe = axnet_probe, + .probe = axnet_attach, .remove = axnet_detach, .id_table = axnet_ids, .suspend = axnet_suspend, @@ -1560,7 +1595,7 @@ static void ei_receive(struct net_device *dev) static void ei_rx_overrun(struct net_device *dev) { - axnet_dev_t *info = PRIV(dev); + axnet_dev_t *info = (axnet_dev_t *)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); @@ -1647,56 +1682,17 @@ 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. - * Must be called with lock held. + * 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. */ 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); - } - - 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); @@ -1704,8 +1700,6 @@ static void do_set_multicast_list(struct net_device *dev) outb_p(E8390_RXCONFIG | 0x48, e8390_base + EN0_RXCR); else outb_p(E8390_RXCONFIG | 0x40, e8390_base + EN0_RXCR); - - outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base+E8390_CMD); } /* @@ -1800,6 +1794,12 @@ 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);