diff --git a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c index 3b790de6c976..09de683c167e 100644 --- a/drivers/net/arcnet/arcnet.c +++ b/drivers/net/arcnet/arcnet.c @@ -777,7 +777,7 @@ irqreturn_t arcnet_interrupt(int irq, void *dev_id) ACOMMAND(CFLAGScmd | RESETclear); AINTMASK(0); spin_unlock(&lp->lock); - return IRQ_HANDLED; + return retval; } BUGMSG(D_DURING, "in arcnet_inthandler (status=%Xh, intmask=%Xh)\n", diff --git a/drivers/net/arcnet/com20020-pci.c b/drivers/net/arcnet/com20020-pci.c index 7bb292e59559..6c99ff0b0bdd 100644 --- a/drivers/net/arcnet/com20020-pci.c +++ b/drivers/net/arcnet/com20020-pci.c @@ -38,6 +38,7 @@ #include #include #include +#include #include @@ -61,115 +62,317 @@ module_param(clockp, int, 0); module_param(clockm, int, 0); MODULE_LICENSE("GPL"); +static void com20020pci_remove(struct pci_dev *pdev); + static int com20020pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { + struct com20020_pci_card_info *ci; struct net_device *dev; struct arcnet_local *lp; - int ioaddr, err; + struct com20020_priv *priv; + int i, ioaddr, ret; + struct resource *r; if (pci_enable_device(pdev)) return -EIO; - dev = alloc_arcdev(device); - if (!dev) - return -ENOMEM; - dev->netdev_ops = &com20020_netdev_ops; + priv = devm_kzalloc(&pdev->dev, sizeof(struct com20020_priv), + GFP_KERNEL); + ci = (struct com20020_pci_card_info *)id->driver_data; + priv->ci = ci; - lp = netdev_priv(dev); + INIT_LIST_HEAD(&priv->list_dev); - pci_set_drvdata(pdev, dev); - // SOHARD needs PCI base addr 4 - if (pdev->vendor==0x10B5) { - BUGMSG(D_NORMAL, "SOHARD\n"); - ioaddr = pci_resource_start(pdev, 4); - } - else { - BUGMSG(D_NORMAL, "Contemporary Controls\n"); - ioaddr = pci_resource_start(pdev, 2); + for (i = 0; i < ci->devcount; i++) { + struct com20020_pci_channel_map *cm = &ci->chan_map_tbl[i]; + struct com20020_dev *card; + + dev = alloc_arcdev(device); + if (!dev) { + ret = -ENOMEM; + goto out_port; + } + + dev->netdev_ops = &com20020_netdev_ops; + + lp = netdev_priv(dev); + + BUGMSG(D_NORMAL, "%s Controls\n", ci->name); + ioaddr = pci_resource_start(pdev, cm->bar) + cm->offset; + + r = devm_request_region(&pdev->dev, ioaddr, cm->size, + "com20020-pci"); + if (!r) { + pr_err("IO region %xh-%xh already allocated.\n", + ioaddr, ioaddr + cm->size - 1); + ret = -EBUSY; + goto out_port; + } + + /* Dummy access after Reset + * ARCNET controller needs + * this access to detect bustype + */ + outb(0x00, ioaddr + 1); + inb(ioaddr + 1); + + dev->base_addr = ioaddr; + dev->dev_addr[0] = node; + dev->irq = pdev->irq; + lp->card_name = "PCI COM20020"; + lp->card_flags = ci->flags; + lp->backplane = backplane; + lp->clockp = clockp & 7; + lp->clockm = clockm & 3; + lp->timeout = timeout; + lp->hw.owner = THIS_MODULE; + + if (ASTATUS() == 0xFF) { + pr_err("IO address %Xh is empty!\n", ioaddr); + ret = -EIO; + goto out_port; + } + if (com20020_check(dev)) { + ret = -EIO; + goto out_port; + } + + card = devm_kzalloc(&pdev->dev, sizeof(struct com20020_dev), + GFP_KERNEL); + if (!card) { + pr_err("%s out of memory!\n", __func__); + return -ENOMEM; + } + + card->index = i; + card->pci_priv = priv; + card->dev = dev; + + dev_set_drvdata(&dev->dev, card); + + ret = com20020_found(dev, IRQF_SHARED); + if (ret) + goto out_port; + + list_add(&card->list, &priv->list_dev); } - if (!request_region(ioaddr, ARCNET_TOTAL_SIZE, "com20020-pci")) { - BUGMSG(D_INIT, "IO region %xh-%xh already allocated.\n", - ioaddr, ioaddr + ARCNET_TOTAL_SIZE - 1); - err = -EBUSY; - goto out_dev; - } - - // Dummy access after Reset - // ARCNET controller needs this access to detect bustype - outb(0x00,ioaddr+1); - inb(ioaddr+1); - - dev->base_addr = ioaddr; - dev->irq = pdev->irq; - dev->dev_addr[0] = node; - lp->card_name = "PCI COM20020"; - lp->card_flags = id->driver_data; - lp->backplane = backplane; - lp->clockp = clockp & 7; - lp->clockm = clockm & 3; - lp->timeout = timeout; - lp->hw.owner = THIS_MODULE; - - if (ASTATUS() == 0xFF) { - BUGMSG(D_NORMAL, "IO address %Xh was reported by PCI BIOS, " - "but seems empty!\n", ioaddr); - err = -EIO; - goto out_port; - } - if (com20020_check(dev)) { - err = -EIO; - goto out_port; - } - - if ((err = com20020_found(dev, IRQF_SHARED)) != 0) - goto out_port; + pci_set_drvdata(pdev, priv); return 0; out_port: - release_region(ioaddr, ARCNET_TOTAL_SIZE); -out_dev: - free_netdev(dev); - return err; + com20020pci_remove(pdev); + return ret; } static void com20020pci_remove(struct pci_dev *pdev) { - struct net_device *dev = pci_get_drvdata(pdev); - unregister_netdev(dev); - free_irq(dev->irq, dev); - release_region(dev->base_addr, ARCNET_TOTAL_SIZE); - free_netdev(dev); + struct com20020_dev *card, *tmpcard; + struct com20020_priv *priv; + + priv = pci_get_drvdata(pdev); + + list_for_each_entry_safe(card, tmpcard, &priv->list_dev, list) { + struct net_device *dev = card->dev; + + unregister_netdev(dev); + free_irq(dev->irq, dev); + free_netdev(dev); + } } +static struct com20020_pci_card_info card_info_10mbit = { + .name = "ARC-PCI", + .devcount = 1, + .chan_map_tbl = { + { 2, 0x00, 0x08 }, + }, + .flags = ARC_CAN_10MBIT, +}; + +static struct com20020_pci_card_info card_info_5mbit = { + .name = "ARC-PCI", + .devcount = 1, + .chan_map_tbl = { + { 2, 0x00, 0x08 }, + }, + .flags = ARC_IS_5MBIT, +}; + +static struct com20020_pci_card_info card_info_sohard = { + .name = "PLX-PCI", + .devcount = 1, + /* SOHARD needs PCI base addr 4 */ + .chan_map_tbl = { + {4, 0x00, 0x08}, + }, + .flags = ARC_CAN_10MBIT, +}; + +static struct com20020_pci_card_info card_info_eae = { + .name = "EAE PLX-PCI", + .devcount = 2, + .chan_map_tbl = { + { 2, 0x00, 0x08 }, + { 2, 0x08, 0x08 } + }, + .flags = ARC_CAN_10MBIT, +}; + static const struct pci_device_id com20020pci_id_table[] = { - { 0x1571, 0xa001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { 0x1571, 0xa002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { 0x1571, 0xa003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { 0x1571, 0xa004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { 0x1571, 0xa005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { 0x1571, 0xa006, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { 0x1571, 0xa007, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { 0x1571, 0xa008, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { 0x1571, 0xa009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_IS_5MBIT }, - { 0x1571, 0xa00a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_IS_5MBIT }, - { 0x1571, 0xa00b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_IS_5MBIT }, - { 0x1571, 0xa00c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_IS_5MBIT }, - { 0x1571, 0xa00d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_IS_5MBIT }, - { 0x1571, 0xa00e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_IS_5MBIT }, - { 0x1571, 0xa201, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT }, - { 0x1571, 0xa202, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT }, - { 0x1571, 0xa203, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT }, - { 0x1571, 0xa204, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT }, - { 0x1571, 0xa205, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT }, - { 0x1571, 0xa206, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT }, - { 0x10B5, 0x9030, 0x10B5, 0x2978, 0, 0, ARC_CAN_10MBIT }, - { 0x10B5, 0x9050, 0x10B5, 0x2273, 0, 0, ARC_CAN_10MBIT }, - { 0x14BA, 0x6000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT }, - { 0x10B5, 0x2200, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT }, - {0,} + { + 0x1571, 0xa001, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + 0, + }, + { + 0x1571, 0xa002, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + 0, + }, + { + 0x1571, 0xa003, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + 0 + }, + { + 0x1571, 0xa004, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + 0, + }, + { + 0x1571, 0xa005, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + 0 + }, + { + 0x1571, 0xa006, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + 0 + }, + { + 0x1571, 0xa007, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + 0 + }, + { + 0x1571, 0xa008, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + 0 + }, + { + 0x1571, 0xa009, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + (kernel_ulong_t)&card_info_5mbit + }, + { + 0x1571, 0xa00a, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + (kernel_ulong_t)&card_info_5mbit + }, + { + 0x1571, 0xa00b, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + (kernel_ulong_t)&card_info_5mbit + }, + { + 0x1571, 0xa00c, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + (kernel_ulong_t)&card_info_5mbit + }, + { + 0x1571, 0xa00d, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + (kernel_ulong_t)&card_info_5mbit + }, + { + 0x1571, 0xa00e, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + (kernel_ulong_t)&card_info_5mbit + }, + { + 0x1571, 0xa201, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + (kernel_ulong_t)&card_info_10mbit + }, + { + 0x1571, 0xa202, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + (kernel_ulong_t)&card_info_10mbit + }, + { + 0x1571, 0xa203, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + (kernel_ulong_t)&card_info_10mbit + }, + { + 0x1571, 0xa204, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + (kernel_ulong_t)&card_info_10mbit + }, + { + 0x1571, 0xa205, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + (kernel_ulong_t)&card_info_10mbit + }, + { + 0x1571, 0xa206, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + (kernel_ulong_t)&card_info_10mbit + }, + { + 0x10B5, 0x9030, + 0x10B5, 0x2978, + 0, 0, + (kernel_ulong_t)&card_info_sohard + }, + { + 0x10B5, 0x9050, + 0x10B5, 0x2273, + 0, 0, + (kernel_ulong_t)&card_info_sohard + }, + { + 0x10B5, 0x9050, + 0x10B5, 0x3292, + 0, 0, + (kernel_ulong_t)&card_info_eae + }, + { + 0x14BA, 0x6000, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + (kernel_ulong_t)&card_info_10mbit + }, + { + 0x10B5, 0x2200, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + (kernel_ulong_t)&card_info_10mbit + }, + { 0, } }; MODULE_DEVICE_TABLE(pci, com20020pci_id_table); diff --git a/drivers/net/arcnet/com20020.c b/drivers/net/arcnet/com20020.c index 7b96c5f47e8d..1a8437842fbc 100644 --- a/drivers/net/arcnet/com20020.c +++ b/drivers/net/arcnet/com20020.c @@ -149,11 +149,25 @@ int com20020_check(struct net_device *dev) return 0; } +static int com20020_set_hwaddr(struct net_device *dev, void *addr) +{ + int ioaddr = dev->base_addr; + struct arcnet_local *lp = netdev_priv(dev); + struct sockaddr *hwaddr = addr; + + memcpy(dev->dev_addr, hwaddr->sa_data, 1); + SET_SUBADR(SUB_NODE); + outb(dev->dev_addr[0], _XREG); + + return 0; +} + const struct net_device_ops com20020_netdev_ops = { .ndo_open = arcnet_open, .ndo_stop = arcnet_close, .ndo_start_xmit = arcnet_send_packet, .ndo_tx_timeout = arcnet_timeout, + .ndo_set_mac_address = com20020_set_hwaddr, .ndo_set_rx_mode = com20020_set_mc_list, }; diff --git a/drivers/net/arcnet/com20020_cs.c b/drivers/net/arcnet/com20020_cs.c index 1a790a20210d..057d9582132a 100644 --- a/drivers/net/arcnet/com20020_cs.c +++ b/drivers/net/arcnet/com20020_cs.c @@ -112,10 +112,6 @@ static void com20020_detach(struct pcmcia_device *p_dev); /*====================================================================*/ -struct com20020_dev { - struct net_device *dev; -}; - static int com20020_probe(struct pcmcia_device *p_dev) { struct com20020_dev *info; diff --git a/include/linux/com20020.h b/include/linux/com20020.h index 5dcfb944b6ce..85898995b234 100644 --- a/include/linux/com20020.h +++ b/include/linux/com20020.h @@ -41,6 +41,35 @@ extern const struct net_device_ops com20020_netdev_ops; #define BUS_ALIGN 1 #endif +#define PLX_PCI_MAX_CARDS 2 + +struct com20020_pci_channel_map { + u32 bar; + u32 offset; + u32 size; /* 0x00 - auto, e.g. length of entire bar */ +}; + +struct com20020_pci_card_info { + const char *name; + int devcount; + + struct com20020_pci_channel_map chan_map_tbl[PLX_PCI_MAX_CARDS]; + + unsigned int flags; +}; + +struct com20020_priv { + struct com20020_pci_card_info *ci; + struct list_head list_dev; +}; + +struct com20020_dev { + struct list_head list; + struct net_device *dev; + + struct com20020_priv *pci_priv; + int index; +}; #define _INTMASK (ioaddr+BUS_ALIGN*0) /* writable */ #define _STATUS (ioaddr+BUS_ALIGN*0) /* readable */