Commit f6dd59bc authored by Russell King's avatar Russell King Committed by Jeff Garzik

[PATCH] etherh updates

Update Acorn EtherH driver - convert to use mmio instead of emulated
PIO.  Convert card-specific parameters to a data structure rather
than code-based selected.

Please review and submit upstream.  Thanks.
parent 00ec66df
......@@ -131,8 +131,19 @@ struct ei_device {
#define inb_p(port) in_8(port)
#define outb_p(val,port) out_8(port,val)
#elif defined(CONFIG_ARM_ETHERH) || defined(CONFIG_ARM_ETHERH_MODULE) || \
defined(CONFIG_NET_CBUS)
#elif defined(CONFIG_ARM_ETHERH) || defined(CONFIG_ARM_ETHERH_MODULE)
#define EI_SHIFT(x) (ei_local->reg_offset[x])
#undef inb
#undef inb_p
#undef outb
#undef outb_p
#define inb(_p) readb(_p)
#define outb(_v,_p) writeb(_v,_p)
#define inb_p(_p) inb(_p)
#define outb_p(_v,_p) outb(_v,_p)
#elif defined(CONFIG_NET_CBUS)
#define EI_SHIFT(x) (ei_local->reg_offset[x])
#else
#define EI_SHIFT(x) (x)
......
......@@ -60,11 +60,28 @@ static unsigned int net_debug = NET_DEBUG;
struct etherh_priv {
struct ei_device eidev;
void *ioc_fast;
void *memc;
unsigned int id;
unsigned int ctrl_port;
void *ctrl_port;
unsigned int ctrl;
};
struct etherh_data {
unsigned long ns8390_offset;
unsigned long dataport_offset;
unsigned long ctrlport_offset;
int ctrl_ioc;
const char name[16];
/*
* netdev flags and port
*/
unsigned short flags;
unsigned char if_port;
unsigned char tx_start_page;
unsigned char stop_page;
};
MODULE_AUTHOR("Russell King");
MODULE_DESCRIPTION("EtherH/EtherM driver");
MODULE_LICENSE("GPL");
......@@ -72,13 +89,13 @@ MODULE_LICENSE("GPL");
static char version[] __initdata =
"EtherH/EtherM Driver (c) 2002 Russell King v1.09\n";
#define ETHERH500_DATAPORT 0x200 /* MEMC */
#define ETHERH500_DATAPORT 0x800 /* MEMC */
#define ETHERH500_NS8390 0x000 /* MEMC */
#define ETHERH500_CTRLPORT 0x200 /* IOC */
#define ETHERH500_CTRLPORT 0x800 /* IOC */
#define ETHERH600_DATAPORT 16 /* MEMC */
#define ETHERH600_NS8390 0x200 /* MEMC */
#define ETHERH600_CTRLPORT 0x080 /* MEMC */
#define ETHERH600_DATAPORT 0x040 /* MEMC */
#define ETHERH600_NS8390 0x800 /* MEMC */
#define ETHERH600_CTRLPORT 0x200 /* MEMC */
#define ETHERH_CP_IE 1
#define ETHERH_CP_IF 2
......@@ -90,9 +107,9 @@ static char version[] __initdata =
/*
* These came from CK/TEW
*/
#define ETHERM_DATAPORT 0x080 /* MEMC */
#define ETHERM_NS8390 0x200 /* MEMC */
#define ETHERM_CTRLPORT 0x08f /* MEMC */
#define ETHERM_DATAPORT 0x200 /* MEMC */
#define ETHERM_NS8390 0x800 /* MEMC */
#define ETHERM_CTRLPORT 0x23c /* MEMC */
#define ETHERM_TX_START_PAGE 64
#define ETHERM_STOP_PAGE 127
......@@ -102,18 +119,18 @@ static char version[] __initdata =
static inline void etherh_set_ctrl(struct etherh_priv *eh, unsigned int mask)
{
eh->ctrl |= mask;
outb(eh->ctrl, eh->ctrl_port);
writeb(eh->ctrl, eh->ctrl_port);
}
static inline void etherh_clr_ctrl(struct etherh_priv *eh, unsigned int mask)
{
eh->ctrl &= ~mask;
outb(eh->ctrl, eh->ctrl_port);
writeb(eh->ctrl, eh->ctrl_port);
}
static inline unsigned int etherh_get_stat(struct etherh_priv *eh)
{
return inb(eh->ctrl_port);
return readb(eh->ctrl_port);
}
......@@ -158,10 +175,10 @@ etherh_setif(struct net_device *dev)
switch (dev->if_port) {
case IF_PORT_10BASE2:
outb((inb(addr) & 0xf8) | 1, addr);
writeb((readb(addr) & 0xf8) | 1, addr);
break;
case IF_PORT_10BASET:
outb((inb(addr) & 0xf8), addr);
writeb((readb(addr) & 0xf8), addr);
break;
}
break;
......@@ -200,7 +217,7 @@ etherh_getifstat(struct net_device *dev)
stat = 1;
break;
case IF_PORT_10BASET:
stat = inb(dev->base_addr+EN0_RCNTHI) & 4;
stat = readb(dev->base_addr+EN0_RCNTHI) & 4;
break;
}
break;
......@@ -258,7 +275,7 @@ etherh_reset(struct net_device *dev)
{
struct ei_device *ei_local = netdev_priv(dev);
outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, dev->base_addr);
writeb(E8390_NODMA+E8390_PAGE0+E8390_STOP, dev->base_addr);
/*
* See if we need to change the interface type.
......@@ -306,31 +323,31 @@ etherh_block_output (struct net_device *dev, int count, const unsigned char *buf
dma_addr = dev->mem_start;
count = (count + 1) & ~1;
outb (E8390_NODMA | E8390_PAGE0 | E8390_START, addr + E8390_CMD);
writeb (E8390_NODMA | E8390_PAGE0 | E8390_START, addr + E8390_CMD);
outb (0x42, addr + EN0_RCNTLO);
outb (0x00, addr + EN0_RCNTHI);
outb (0x42, addr + EN0_RSARLO);
outb (0x00, addr + EN0_RSARHI);
outb (E8390_RREAD | E8390_START, addr + E8390_CMD);
writeb (0x42, addr + EN0_RCNTLO);
writeb (0x00, addr + EN0_RCNTHI);
writeb (0x42, addr + EN0_RSARLO);
writeb (0x00, addr + EN0_RSARHI);
writeb (E8390_RREAD | E8390_START, addr + E8390_CMD);
udelay (1);
outb (ENISR_RDC, addr + EN0_ISR);
outb (count, addr + EN0_RCNTLO);
outb (count >> 8, addr + EN0_RCNTHI);
outb (0, addr + EN0_RSARLO);
outb (start_page, addr + EN0_RSARHI);
outb (E8390_RWRITE | E8390_START, addr + E8390_CMD);
writeb (ENISR_RDC, addr + EN0_ISR);
writeb (count, addr + EN0_RCNTLO);
writeb (count >> 8, addr + EN0_RCNTHI);
writeb (0, addr + EN0_RSARLO);
writeb (start_page, addr + EN0_RSARHI);
writeb (E8390_RWRITE | E8390_START, addr + E8390_CMD);
if (ei_local->word16)
outsw (dma_addr, buf, count >> 1);
writesw (dma_addr, buf, count >> 1);
else
outsb (dma_addr, buf, count);
writesb (dma_addr, buf, count);
dma_start = jiffies;
while ((inb (addr + EN0_ISR) & ENISR_RDC) == 0)
while ((readb (addr + EN0_ISR) & ENISR_RDC) == 0)
if (jiffies - dma_start > 2*HZ/100) { /* 20ms */
printk(KERN_ERR "%s: timeout waiting for TX RDC\n",
dev->name);
......@@ -339,7 +356,7 @@ etherh_block_output (struct net_device *dev, int count, const unsigned char *buf
break;
}
outb (ENISR_RDC, addr + EN0_ISR);
writeb (ENISR_RDC, addr + EN0_ISR);
ei_local->dmaing = 0;
}
......@@ -366,21 +383,21 @@ etherh_block_input (struct net_device *dev, int count, struct sk_buff *skb, int
dma_addr = dev->mem_start;
buf = skb->data;
outb (E8390_NODMA | E8390_PAGE0 | E8390_START, addr + E8390_CMD);
outb (count, addr + EN0_RCNTLO);
outb (count >> 8, addr + EN0_RCNTHI);
outb (ring_offset, addr + EN0_RSARLO);
outb (ring_offset >> 8, addr + EN0_RSARHI);
outb (E8390_RREAD | E8390_START, addr + E8390_CMD);
writeb (E8390_NODMA | E8390_PAGE0 | E8390_START, addr + E8390_CMD);
writeb (count, addr + EN0_RCNTLO);
writeb (count >> 8, addr + EN0_RCNTHI);
writeb (ring_offset, addr + EN0_RSARLO);
writeb (ring_offset >> 8, addr + EN0_RSARHI);
writeb (E8390_RREAD | E8390_START, addr + E8390_CMD);
if (ei_local->word16) {
insw (dma_addr, buf, count >> 1);
readsw (dma_addr, buf, count >> 1);
if (count & 1)
buf[count - 1] = inb (dma_addr);
buf[count - 1] = readb (dma_addr);
} else
insb (dma_addr, buf, count);
readsb (dma_addr, buf, count);
outb (ENISR_RDC, addr + EN0_ISR);
writeb (ENISR_RDC, addr + EN0_ISR);
ei_local->dmaing = 0;
}
......@@ -405,19 +422,19 @@ etherh_get_header (struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_p
addr = dev->base_addr;
dma_addr = dev->mem_start;
outb (E8390_NODMA | E8390_PAGE0 | E8390_START, addr + E8390_CMD);
outb (sizeof (*hdr), addr + EN0_RCNTLO);
outb (0, addr + EN0_RCNTHI);
outb (0, addr + EN0_RSARLO);
outb (ring_page, addr + EN0_RSARHI);
outb (E8390_RREAD | E8390_START, addr + E8390_CMD);
writeb (E8390_NODMA | E8390_PAGE0 | E8390_START, addr + E8390_CMD);
writeb (sizeof (*hdr), addr + EN0_RCNTLO);
writeb (0, addr + EN0_RCNTHI);
writeb (0, addr + EN0_RSARLO);
writeb (ring_page, addr + EN0_RSARHI);
writeb (E8390_RREAD | E8390_START, addr + E8390_CMD);
if (ei_local->word16)
insw (dma_addr, hdr, sizeof (*hdr) >> 1);
readsw (dma_addr, hdr, sizeof (*hdr) >> 1);
else
insb (dma_addr, hdr, sizeof (*hdr));
readsb (dma_addr, hdr, sizeof (*hdr));
outb (ENISR_RDC, addr + EN0_ISR);
writeb (ENISR_RDC, addr + EN0_ISR);
ei_local->dmaing = 0;
}
......@@ -543,18 +560,22 @@ static u32 etherm_regoffsets[16];
static int __init
etherh_probe(struct expansion_card *ec, const struct ecard_id *id)
{
const struct etherh_data *data = id->data;
struct ei_device *ei_local;
struct net_device *dev;
struct etherh_priv *eh;
const char *dev_type;
int i, size, ret;
int i, ret;
etherh_banner();
ret = ecard_request_resources(ec);
if (ret)
goto out;
dev = alloc_ei_netdev();
if (!dev) {
ret = -ENOMEM;
goto out;
goto release;
}
eh = netdev_priv(dev);
......@@ -562,111 +583,64 @@ etherh_probe(struct expansion_card *ec, const struct ecard_id *id)
spin_lock_init(&eh->eidev.page_lock);
SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &ec->dev);
dev->open = etherh_open;
dev->stop = etherh_close;
dev->set_config = etherh_set_config;
dev->irq = ec->irq;
dev->base_addr = ecard_address(ec, ECARD_MEMC, 0);
dev->if_port = data->if_port;
dev->flags |= data->flags;
/*
* IRQ and control port handling
*/
if (ec->irq != 11) {
ec->ops = &etherh_ops;
ec->irq_data = eh;
}
eh->ctrl = 0;
eh->id = ec->cid.product;
switch (ec->cid.product) {
case PROD_ANT_ETHERM:
etherm_addr(dev->dev_addr);
dev->base_addr += ETHERM_NS8390;
dev->mem_start = dev->base_addr + ETHERM_DATAPORT;
eh->ctrl_port = dev->base_addr + ETHERM_CTRLPORT;
break;
case PROD_I3_ETHERLAN500:
etherh_addr(dev->dev_addr, ec);
dev->base_addr += ETHERH500_NS8390;
dev->mem_start = dev->base_addr + ETHERH500_DATAPORT;
eh->ctrl_port = ecard_address (ec, ECARD_IOC, ECARD_FAST)
+ ETHERH500_CTRLPORT;
break;
case PROD_I3_ETHERLAN600:
case PROD_I3_ETHERLAN600A:
etherh_addr(dev->dev_addr, ec);
dev->base_addr += ETHERH600_NS8390;
dev->mem_start = dev->base_addr + ETHERH600_DATAPORT;
eh->ctrl_port = dev->base_addr + ETHERH600_CTRLPORT;
break;
default:
printk(KERN_ERR "%s: unknown card type %x\n",
dev->name, ec->cid.product);
ret = -ENODEV;
eh->memc = ioremap(ecard_resource_start(ec, ECARD_RES_MEMC), PAGE_SIZE);
if (!eh->memc) {
ret = -ENOMEM;
goto free;
}
size = 16;
if (ec->cid.product == PROD_ANT_ETHERM)
size <<= 3;
if (!request_region(dev->base_addr, size, dev->name)) {
ret = -EBUSY;
eh->ctrl_port = eh->memc;
if (data->ctrl_ioc) {
eh->ioc_fast = ioremap(ecard_resource_start(ec, ECARD_RES_IOCFAST), PAGE_SIZE);
if (!eh->ioc_fast) {
ret = -ENOMEM;
goto free;
}
eh->ctrl_port = eh->ioc_fast;
}
dev->base_addr = (unsigned long)eh->memc + data->ns8390_offset;
dev->mem_start = (unsigned long)eh->memc + data->dataport_offset;
eh->ctrl_port += data->ctrlport_offset;
/*
* IRQ and control port handling - only for non-NIC slot cards.
*/
if (ec->slot_no != 8) {
ec->ops = &etherh_ops;
ec->irq_data = eh;
} else {
/*
* If we're in the NIC slot, make sure the IRQ is enabled
*/
if (dev->irq == 11)
etherh_set_ctrl(eh, ETHERH_CP_IE);
switch (ec->cid.product) {
case PROD_ANT_ETHERM:
dev_type = "ANT EtherM";
dev->if_port = IF_PORT_UNKNOWN;
break;
case PROD_I3_ETHERLAN500:
dev_type = "i3 EtherH 500";
dev->if_port = IF_PORT_UNKNOWN;
break;
case PROD_I3_ETHERLAN600:
dev_type = "i3 EtherH 600";
dev->flags |= IFF_PORTSEL | IFF_AUTOMEDIA;
dev->if_port = IF_PORT_10BASET;
break;
case PROD_I3_ETHERLAN600A:
dev_type = "i3 EtherH 600A";
dev->flags |= IFF_PORTSEL | IFF_AUTOMEDIA;
dev->if_port = IF_PORT_10BASET;
break;
default:
dev_type = "unknown";
break;
}
ei_local = netdev_priv(dev);
ei_local = &eh->eidev;
if (ec->cid.product == PROD_ANT_ETHERM) {
ei_local->tx_start_page = ETHERM_TX_START_PAGE;
ei_local->stop_page = ETHERM_STOP_PAGE;
etherm_addr(dev->dev_addr);
ei_local->reg_offset = etherm_regoffsets;
} else {
ei_local->tx_start_page = ETHERH_TX_START_PAGE;
ei_local->stop_page = ETHERH_STOP_PAGE;
etherh_addr(dev->dev_addr, ec);
ei_local->reg_offset = etherh_regoffsets;
}
ei_local->name = dev->name;
ei_local->word16 = 1;
ei_local->tx_start_page = data->tx_start_page;
ei_local->rx_start_page = ei_local->tx_start_page + TX_PAGES;
ei_local->stop_page = data->stop_page;
ei_local->reset_8390 = etherh_reset;
ei_local->block_input = etherh_block_input;
ei_local->block_output = etherh_block_output;
......@@ -678,10 +652,10 @@ etherh_probe(struct expansion_card *ec, const struct ecard_id *id)
ret = register_netdev(dev);
if (ret)
goto release;
goto free;
printk(KERN_INFO "%s: %s in slot %d, ",
dev->name, dev_type, ec->slot_no);
dev->name, data->name, ec->slot_no);
for (i = 0; i < 6; i++)
printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':');
......@@ -690,10 +664,14 @@ etherh_probe(struct expansion_card *ec, const struct ecard_id *id)
return 0;
release:
release_region(dev->base_addr, 16);
free:
if (eh->ioc_fast)
iounmap(eh->ioc_fast);
if (eh->memc)
iounmap(eh->memc);
free_netdev(dev);
release:
ecard_release_resources(ec);
out:
return ret;
}
......@@ -701,25 +679,69 @@ etherh_probe(struct expansion_card *ec, const struct ecard_id *id)
static void __devexit etherh_remove(struct expansion_card *ec)
{
struct net_device *dev = ecard_get_drvdata(ec);
int size = 16;
struct etherh_priv *eh = netdev_priv(dev);
ecard_set_drvdata(ec, NULL);
unregister_netdev(dev);
if (ec->cid.product == PROD_ANT_ETHERM)
size <<= 3;
release_region(dev->base_addr, size);
if (eh->ioc_fast)
iounmap(eh->ioc_fast);
iounmap(eh->memc);
free_netdev(dev);
ec->ops = NULL;
kfree(ec->irq_data);
ecard_release_resources(ec);
}
static struct etherh_data etherm_data = {
.ns8390_offset = ETHERM_NS8390,
.dataport_offset = ETHERM_NS8390 + ETHERM_DATAPORT,
.ctrlport_offset = ETHERM_NS8390 + ETHERM_CTRLPORT,
.name = "ANT EtherM",
.if_port = IF_PORT_UNKNOWN,
.tx_start_page = ETHERM_TX_START_PAGE,
.stop_page = ETHERM_STOP_PAGE,
};
static struct etherh_data etherlan500_data = {
.ns8390_offset = ETHERH500_NS8390,
.dataport_offset = ETHERH500_NS8390 + ETHERH500_DATAPORT,
.ctrlport_offset = ETHERH500_CTRLPORT,
.ctrl_ioc = 1,
.name = "i3 EtherH 500",
.if_port = IF_PORT_UNKNOWN,
.tx_start_page = ETHERH_TX_START_PAGE,
.stop_page = ETHERH_STOP_PAGE,
};
static struct etherh_data etherlan600_data = {
.ns8390_offset = ETHERH600_NS8390,
.dataport_offset = ETHERH600_NS8390 + ETHERH600_DATAPORT,
.ctrlport_offset = ETHERH600_NS8390 + ETHERH600_CTRLPORT,
.name = "i3 EtherH 600",
.flags = IFF_PORTSEL | IFF_AUTOMEDIA,
.if_port = IF_PORT_10BASET,
.tx_start_page = ETHERH_TX_START_PAGE,
.stop_page = ETHERH_STOP_PAGE,
};
static struct etherh_data etherlan600a_data = {
.ns8390_offset = ETHERH600_NS8390,
.dataport_offset = ETHERH600_NS8390 + ETHERH600_DATAPORT,
.ctrlport_offset = ETHERH600_NS8390 + ETHERH600_CTRLPORT,
.name = "i3 EtherH 600A",
.flags = IFF_PORTSEL | IFF_AUTOMEDIA,
.if_port = IF_PORT_10BASET,
.tx_start_page = ETHERH_TX_START_PAGE,
.stop_page = ETHERH_STOP_PAGE,
};
static const struct ecard_id etherh_ids[] = {
{ MANU_ANT, PROD_ANT_ETHERM },
{ MANU_I3, PROD_I3_ETHERLAN500 },
{ MANU_I3, PROD_I3_ETHERLAN600 },
{ MANU_I3, PROD_I3_ETHERLAN600A },
{ MANU_ANT, PROD_ANT_ETHERM, &etherm_data },
{ MANU_I3, PROD_I3_ETHERLAN500, &etherlan500_data },
{ MANU_I3, PROD_I3_ETHERLAN600, &etherlan600_data },
{ MANU_I3, PROD_I3_ETHERLAN600A, &etherlan600a_data },
{ 0xffff, 0xffff }
};
......@@ -737,8 +759,8 @@ static int __init etherh_init(void)
int i;
for (i = 0; i < 16; i++) {
etherh_regoffsets[i] = i;
etherm_regoffsets[i] = i << 3;
etherh_regoffsets[i] = i << 2;
etherm_regoffsets[i] = i << 5;
}
return ecard_register_driver(&etherh_driver);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment