Merge branch 'arcnet-EAE'

Michael Grzeschik says:

====================
ARCNET: add support for EAE multi interfac card

this series adds support for the PLX Bridge based multi interface
pci cards and adds support to change device address on com200xx chips
during runtime.

This series is based on v3.17-rc7.
It is fixed for build against com20020_cs.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2014-09-29 14:36:33 -04:00
commit 2b7fc477b0
5 changed files with 332 additions and 90 deletions

View File

@ -777,7 +777,7 @@ irqreturn_t arcnet_interrupt(int irq, void *dev_id)
ACOMMAND(CFLAGScmd | RESETclear); ACOMMAND(CFLAGScmd | RESETclear);
AINTMASK(0); AINTMASK(0);
spin_unlock(&lp->lock); spin_unlock(&lp->lock);
return IRQ_HANDLED; return retval;
} }
BUGMSG(D_DURING, "in arcnet_inthandler (status=%Xh, intmask=%Xh)\n", BUGMSG(D_DURING, "in arcnet_inthandler (status=%Xh, intmask=%Xh)\n",

View File

@ -38,6 +38,7 @@
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/arcdevice.h> #include <linux/arcdevice.h>
#include <linux/com20020.h> #include <linux/com20020.h>
#include <linux/list.h>
#include <asm/io.h> #include <asm/io.h>
@ -61,115 +62,317 @@ module_param(clockp, int, 0);
module_param(clockm, int, 0); module_param(clockm, int, 0);
MODULE_LICENSE("GPL"); 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) 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 net_device *dev;
struct arcnet_local *lp; struct arcnet_local *lp;
int ioaddr, err; struct com20020_priv *priv;
int i, ioaddr, ret;
struct resource *r;
if (pci_enable_device(pdev)) if (pci_enable_device(pdev))
return -EIO; 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 for (i = 0; i < ci->devcount; i++) {
if (pdev->vendor==0x10B5) { struct com20020_pci_channel_map *cm = &ci->chan_map_tbl[i];
BUGMSG(D_NORMAL, "SOHARD\n"); struct com20020_dev *card;
ioaddr = pci_resource_start(pdev, 4);
} dev = alloc_arcdev(device);
else { if (!dev) {
BUGMSG(D_NORMAL, "Contemporary Controls\n"); ret = -ENOMEM;
ioaddr = pci_resource_start(pdev, 2); 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")) { pci_set_drvdata(pdev, priv);
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;
return 0; return 0;
out_port: out_port:
release_region(ioaddr, ARCNET_TOTAL_SIZE); com20020pci_remove(pdev);
out_dev: return ret;
free_netdev(dev);
return err;
} }
static void com20020pci_remove(struct pci_dev *pdev) static void com20020pci_remove(struct pci_dev *pdev)
{ {
struct net_device *dev = pci_get_drvdata(pdev); struct com20020_dev *card, *tmpcard;
unregister_netdev(dev); struct com20020_priv *priv;
free_irq(dev->irq, dev);
release_region(dev->base_addr, ARCNET_TOTAL_SIZE); priv = pci_get_drvdata(pdev);
free_netdev(dev);
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[] = { 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, 0xa001,
{ 0x1571, 0xa003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, PCI_ANY_ID, PCI_ANY_ID,
{ 0x1571, 0xa004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, 0, 0,
{ 0x1571, 0xa005, PCI_ANY_ID, PCI_ANY_ID, 0, 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, 0xa002,
{ 0x1571, 0xa009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_IS_5MBIT }, PCI_ANY_ID, PCI_ANY_ID,
{ 0x1571, 0xa00a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_IS_5MBIT }, 0, 0,
{ 0x1571, 0xa00b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_IS_5MBIT }, 0,
{ 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, 0xa003,
{ 0x1571, 0xa201, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT }, PCI_ANY_ID, PCI_ANY_ID,
{ 0x1571, 0xa202, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT }, 0, 0,
{ 0x1571, 0xa203, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT }, 0
{ 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 }, 0x1571, 0xa004,
{ 0x10B5, 0x9030, 0x10B5, 0x2978, 0, 0, ARC_CAN_10MBIT }, PCI_ANY_ID, PCI_ANY_ID,
{ 0x10B5, 0x9050, 0x10B5, 0x2273, 0, 0, ARC_CAN_10MBIT }, 0, 0,
{ 0x14BA, 0x6000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT }, 0,
{ 0x10B5, 0x2200, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT }, },
{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); MODULE_DEVICE_TABLE(pci, com20020pci_id_table);

View File

@ -149,11 +149,25 @@ int com20020_check(struct net_device *dev)
return 0; 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 = { const struct net_device_ops com20020_netdev_ops = {
.ndo_open = arcnet_open, .ndo_open = arcnet_open,
.ndo_stop = arcnet_close, .ndo_stop = arcnet_close,
.ndo_start_xmit = arcnet_send_packet, .ndo_start_xmit = arcnet_send_packet,
.ndo_tx_timeout = arcnet_timeout, .ndo_tx_timeout = arcnet_timeout,
.ndo_set_mac_address = com20020_set_hwaddr,
.ndo_set_rx_mode = com20020_set_mc_list, .ndo_set_rx_mode = com20020_set_mc_list,
}; };

View File

@ -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) static int com20020_probe(struct pcmcia_device *p_dev)
{ {
struct com20020_dev *info; struct com20020_dev *info;

View File

@ -41,6 +41,35 @@ extern const struct net_device_ops com20020_netdev_ops;
#define BUS_ALIGN 1 #define BUS_ALIGN 1
#endif #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 _INTMASK (ioaddr+BUS_ALIGN*0) /* writable */
#define _STATUS (ioaddr+BUS_ALIGN*0) /* readable */ #define _STATUS (ioaddr+BUS_ALIGN*0) /* readable */