Commit 3ecf65ae authored by Russell King's avatar Russell King

[ARM] Update Acorn ethernet expansion cards

This cset implements validity checks on the ethernet MAC address when
the device is opened, and refuses to open the device if this check
fails.  We also provide the set_mac_address method to allow ifconfig
to change the mac address to something valid.

In addition, the driver is converted from the old expansion card
discovery methods to the new device model driver framework.
parent 8025567f
......@@ -43,6 +43,7 @@
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/device.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
......@@ -80,11 +81,6 @@ static char version[] __initdata = "ether1 ethernet driver (c) 2000 Russell King
#define BUS_16 16
#define BUS_8 8
static const card_ids __init ether1_cids[] = {
{ MANU_ACORN, PROD_ACORN_ETHER1 },
{ 0xffff, 0xffff }
};
/* ------------------------------------------------------------------------- */
#define DISABLEIRQS 1
......@@ -647,6 +643,12 @@ ether1_open (struct net_device *dev)
{
struct ether1_priv *priv = (struct ether1_priv *)dev->priv;
if (!is_valid_ether_addr(dev->dev_addr)) {
printk(KERN_WARNING "%s: invalid ethernet MAC address\n",
dev->name);
return -EINVAL;
}
if (request_irq(dev->irq, ether1_interrupt, 0, "ether1", dev))
return -EAGAIN;
......@@ -971,6 +973,23 @@ ether1_getstats (struct net_device *dev)
return &priv->stats;
}
static int
ether1_set_mac_address(struct net_device *dev, void *p)
{
struct sockaddr *addr = p;
if (netif_running(dev))
return -EBUSY;
memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
/*
* We'll set the MAC address on the chip when we open it.
*/
return 0;
}
/*
* Set or clear the multicast filter for this adaptor.
* num_addrs == -1 Promiscuous mode, receive all packets.
......@@ -993,19 +1012,22 @@ static void __init ether1_banner(void)
printk(KERN_INFO "%s", version);
}
static struct net_device * __init ether1_init_one(struct expansion_card *ec)
static int __devinit
ether1_probe(struct expansion_card *ec, const struct ecard_id *id)
{
struct net_device *dev;
struct ether1_priv *priv;
int i;
int i, ret = 0;
ether1_banner();
ecard_claim(ec);
dev = init_etherdev(NULL, sizeof(struct ether1_priv));
if (!dev)
if (!dev) {
ret = -ENOMEM;
goto out;
}
SET_MODULE_OWNER(dev);
......@@ -1019,8 +1041,10 @@ static struct net_device * __init ether1_init_one(struct expansion_card *ec)
request_region(dev->base_addr + 0x800, 4096, dev->name);
priv = (struct ether1_priv *)dev->priv;
if ((priv->bus_type = ether1_reset(dev)) == 0)
if ((priv->bus_type = ether1_reset(dev)) == 0) {
ret = -ENODEV;
goto release;
}
printk(KERN_INFO "%s: ether1 in slot %d, ",
dev->name, ec->slot_no);
......@@ -1030,16 +1054,21 @@ static struct net_device * __init ether1_init_one(struct expansion_card *ec)
printk ("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':');
}
if (ether1_init_2(dev))
if (ether1_init_2(dev)) {
ret = -ENODEV;
goto release;
}
dev->open = ether1_open;
dev->stop = ether1_close;
dev->hard_start_xmit = ether1_sendpacket;
dev->get_stats = ether1_getstats;
dev->set_multicast_list = ether1_setmulticastlist;
dev->set_mac_address = ether1_set_mac_address;
dev->tx_timeout = ether1_timeout;
dev->watchdog_timeo = 5 * HZ / 100;
ecard_set_drvdata(ec, dev);
return 0;
release:
......@@ -1049,55 +1078,46 @@ static struct net_device * __init ether1_init_one(struct expansion_card *ec)
kfree(dev);
out:
ecard_release(ec);
return dev;
return ret;
}
static struct expansion_card *e_card[MAX_ECARDS];
static struct net_device *e_dev[MAX_ECARDS];
static int __init ether1_init(void)
static void __devexit ether1_remove(struct expansion_card *ec)
{
int i, ret = -ENODEV;
struct net_device *dev = ecard_get_drvdata(ec);
ecard_startfind();
ecard_set_drvdata(ec, NULL);
for (i = 0; i < MAX_ECARDS; i++) {
struct expansion_card *ec;
struct net_device *dev;
unregister_netdev(dev);
ec = ecard_find(0, ether1_cids);
if (!ec)
break;
release_region(dev->base_addr, 16);
release_region(dev->base_addr + 0x800, 4096);
kfree(dev);
dev = ether1_init_one(ec);
if (!dev)
break;
ecard_release(ec);
}
e_card[i] = ec;
e_dev[i] = dev;
ret = 0;
}
static const struct ecard_id ether1_ids[] = {
{ MANU_ACORN, PROD_ACORN_ETHER1 },
{ 0xffff, 0xffff }
};
return ret;
static struct ecard_driver ether1_driver = {
.probe = ether1_probe,
.remove = __devexit_p(ether1_remove),
.id_table = ether1_ids,
.drv = {
.name = "ether1",
},
};
static int __init ether1_init(void)
{
return ecard_register_driver(&ether1_driver);
}
static void __exit ether1_exit(void)
{
int i;
for (i = 0; i < MAX_ECARDS; i++) {
if (e_dev[i]) {
unregister_netdev(e_dev[i]);
release_region(e_dev[i]->base_addr, 16);
release_region(e_dev[i]->base_addr + 0x800, 4096);
kfree(e_dev[i]);
e_dev[i] = NULL;
}
if (e_card[i]) {
ecard_release(e_card[i]);
e_card[i] = NULL;
}
}
ecard_remove_driver(&ether1_driver);
}
module_init(ether1_init);
......
......@@ -61,6 +61,7 @@
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/device.h>
#include <linux/init.h>
#include <linux/delay.h>
......@@ -75,12 +76,6 @@ static char version[] __initdata = "ether3 ethernet driver (c) 1995-2000 R.M.Kin
#include "ether3.h"
static unsigned int net_debug = NET_DEBUG;
static const card_ids __init ether3_cids[] = {
{ MANU_ANT2, PROD_ANT_ETHER3 },
{ MANU_ANT, PROD_ANT_ETHER3 },
{ MANU_ANT, PROD_ANT_ETHERB },
{ 0xffff, 0xffff }
};
static void ether3_setmulticastlist(struct net_device *dev);
static int ether3_rx(struct net_device *dev, struct dev_priv *priv, unsigned int maxcnt);
......@@ -417,6 +412,12 @@ ether3_probe_bus_16(struct net_device *dev, int val)
static int
ether3_open(struct net_device *dev)
{
if (!is_valid_ether_addr(dev->dev_addr)) {
printk(KERN_WARNING "%s: invalid ethernet MAC address\n",
dev->name);
return -EINVAL;
}
if (request_irq(dev->irq, ether3_interrupt, 0, "ether3", dev))
return -EAGAIN;
......@@ -460,6 +461,23 @@ static struct net_device_stats *ether3_getstats(struct net_device *dev)
return &priv->stats;
}
static int
ether3_set_mac_address(struct net_device *dev, void *p)
{
struct sockaddr *addr = p;
if (netif_running(dev))
return -EBUSY;
memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
/*
* We'll set the MAC address on the chip when we open it.
*/
return 0;
}
/*
* Set or clear promiscuous/multicast mode filter for this adaptor.
*
......@@ -784,6 +802,7 @@ static const char * __init
ether3_get_dev(struct net_device *dev, struct expansion_card *ec)
{
const char *name = "ether3";
dev->base_addr = ecard_address(ec, ECARD_MEMC, 0);
dev->irq = ec->irq;
......@@ -796,38 +815,44 @@ ether3_get_dev(struct net_device *dev, struct expansion_card *ec)
ec->irqaddr = (volatile unsigned char *)ioaddr(dev->base_addr);
ec->irqmask = 0xf0;
if (ether3_addr(dev->dev_addr, ec))
name = NULL;
ether3_addr(dev->dev_addr, ec);
return name;
}
static struct net_device * __init ether3_init_one(struct expansion_card *ec)
static int __devinit
ether3_probe(struct expansion_card *ec, const struct ecard_id *id)
{
struct net_device *dev;
struct dev_priv *priv;
const char *name;
int i, bus_type;
int i, bus_type, ret;
ether3_banner();
ecard_claim(ec);
dev = init_etherdev(NULL, sizeof(struct dev_priv));
if (!dev)
if (!dev) {
ret = -ENOMEM;
goto out;
}
SET_MODULE_OWNER(dev);
name = ether3_get_dev(dev, ec);
if (!name)
if (!name) {
ret = -ENODEV;
goto free;
}
/*
* this will not fail - the nature of the bus ensures this
*/
if (!request_region(dev->base_addr, 128, dev->name))
if (!request_region(dev->base_addr, 128, dev->name)) {
ret = -EBUSY;
goto free;
}
priv = (struct dev_priv *) dev->priv;
......@@ -852,11 +877,13 @@ static struct net_device * __init ether3_init_one(struct expansion_card *ec)
switch (bus_type) {
case BUS_UNKNOWN:
printk(KERN_ERR "%s: unable to identify bus width\n", dev->name);
ret = -ENODEV;
goto failed;
case BUS_8:
printk(KERN_ERR "%s: %s found, but is an unsupported "
"8-bit card\n", dev->name, name);
ret = -ENODEV;
goto failed;
default:
......@@ -867,16 +894,21 @@ static struct net_device * __init ether3_init_one(struct expansion_card *ec)
for (i = 0; i < 6; i++)
printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':');
if (ether3_init_2(dev))
if (ether3_init_2(dev)) {
ret = -ENODEV;
goto failed;
}
dev->open = ether3_open;
dev->stop = ether3_close;
dev->hard_start_xmit = ether3_sendpacket;
dev->get_stats = ether3_getstats;
dev->set_multicast_list = ether3_setmulticastlist;
dev->set_mac_address = ether3_set_mac_address;
dev->tx_timeout = ether3_timeout;
dev->watchdog_timeo = 5 * HZ / 100;
ecard_set_drvdata(ec, dev);
return 0;
failed:
......@@ -886,54 +918,46 @@ static struct net_device * __init ether3_init_one(struct expansion_card *ec)
kfree(dev);
out:
ecard_release(ec);
return NULL;
return ret;
}
static struct expansion_card *e_card[MAX_ECARDS];
static struct net_device *e_dev[MAX_ECARDS];
static int ether3_init(void)
static void __devexit ether3_remove(struct expansion_card *ec)
{
int i, ret = -ENODEV;
struct net_device *dev = ecard_get_drvdata(ec);
ecard_startfind();
ecard_set_drvdata(ec, NULL);
for (i = 0; i < MAX_ECARDS; i++) {
struct net_device *dev;
struct expansion_card *ec;
unregister_netdev(dev);
release_region(dev->base_addr, 128);
kfree(dev);
ec = ecard_find(0, ether3_cids);
if (!ec)
break;
ecard_release(ec);
}
dev = ether3_init_one(ec);
if (!dev)
break;
static const struct ecard_id ether3_ids[] = {
{ MANU_ANT2, PROD_ANT_ETHER3 },
{ MANU_ANT, PROD_ANT_ETHER3 },
{ MANU_ANT, PROD_ANT_ETHERB },
{ 0xffff, 0xffff }
};
e_card[i] = ec;
e_dev[i] = dev;
ret = 0;
}
static struct ecard_driver ether3_driver = {
.probe = ether3_probe,
.remove = __devexit_p(ether3_remove),
.id_table = ether3_ids,
.drv = {
.name = "ether3",
},
};
return ret;
static int __init ether3_init(void)
{
return ecard_register_driver(&ether3_driver);
}
static void ether3_exit(void)
static void __exit ether3_exit(void)
{
int i;
for (i = 0; i < MAX_ECARDS; i++) {
if (e_dev[i]) {
unregister_netdev(e_dev[i]);
release_region(e_dev[i]->base_addr, 128);
kfree(e_dev[i]);
e_dev[i] = NULL;
}
if (e_card[i]) {
ecard_release(e_card[i]);
e_card[i] = NULL;
}
}
ecard_remove_driver(&ether3_driver);
}
module_init(ether3_init);
......
......@@ -42,6 +42,7 @@
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/init.h>
#include <asm/system.h>
......@@ -57,14 +58,6 @@
static unsigned int net_debug = NET_DEBUG;
static const card_ids __init etherh_cids[] = {
{ MANU_ANT, PROD_ANT_ETHERM },
{ MANU_I3, PROD_I3_ETHERLAN500 },
{ MANU_I3, PROD_I3_ETHERLAN600 },
{ MANU_I3, PROD_I3_ETHERLAN600A },
{ 0xffff, 0xffff }
};
struct etherh_priv {
struct ei_device eidev;
unsigned int id;
......@@ -441,6 +434,12 @@ etherh_open(struct net_device *dev)
{
struct ei_device *ei_local = (struct ei_device *) dev->priv;
if (!is_valid_ether_addr(dev->dev_addr)) {
printk(KERN_WARNING "%s: invalid ethernet MAC address\n",
dev->name);
return -EINVAL;
}
if (request_irq(dev->irq, ei_interrupt, 0, dev->name, dev))
return -EAGAIN;
......@@ -483,6 +482,23 @@ etherh_close(struct net_device *dev)
return 0;
}
static int
etherh_set_mac_address(struct net_device *dev, void *p)
{
struct sockaddr *addr = p;
if (netif_running(dev))
return -EBUSY;
memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
/*
* We'll set the MAC address on the chip when we open it.
*/
return 0;
}
/*
* Initialisation
*/
......@@ -541,21 +557,24 @@ static int __init etherm_addr(char *addr)
static u32 etherh_regoffsets[16];
static u32 etherm_regoffsets[16];
static struct net_device * __init etherh_init_one(struct expansion_card *ec)
static int __init
etherh_probe(struct expansion_card *ec, const struct ecard_id *id)
{
struct ei_device *ei_local;
struct net_device *dev;
struct etherh_priv *eh;
const char *dev_type;
int i, size;
int i, size, ret;
etherh_banner();
ecard_claim(ec);
dev = init_etherdev(NULL, sizeof(struct etherh_priv));
if (!dev)
if (!dev) {
ret = -ENOMEM;
goto out;
}
/*
* init_etherdev allocs and zeros dev->priv
......@@ -568,31 +587,31 @@ static struct net_device * __init etherh_init_one(struct expansion_card *ec)
dev->open = etherh_open;
dev->stop = etherh_close;
dev->set_mac_address = etherh_set_mac_address;
dev->set_config = etherh_set_config;
dev->irq = ec->irq;
dev->base_addr = ecard_address(ec, ECARD_MEMC, 0);
dev->priv = eh;
/*
* 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:
if (etherm_addr(dev->dev_addr))
goto free;
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:
if (etherh_addr(dev->dev_addr, ec))
goto free;
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)
......@@ -601,8 +620,7 @@ static struct net_device * __init etherh_init_one(struct expansion_card *ec)
case PROD_I3_ETHERLAN600:
case PROD_I3_ETHERLAN600A:
if (etherh_addr(dev->dev_addr, ec))
goto free;
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;
......@@ -611,6 +629,7 @@ static struct net_device * __init etherh_init_one(struct expansion_card *ec)
default:
printk(KERN_ERR "%s: unknown card type %x\n",
dev->name, ec->cid.product);
ret = -ENODEV;
goto free;
}
......@@ -618,11 +637,15 @@ static struct net_device * __init etherh_init_one(struct expansion_card *ec)
if (ec->cid.product == PROD_ANT_ETHERM)
size <<= 3;
if (!request_region(dev->base_addr, size, dev->name))
if (!request_region(dev->base_addr, size, dev->name)) {
ret = -EBUSY;
goto free;
}
if (ethdev_init(dev))
if (ethdev_init(dev)) {
ret = -ENODEV;
goto release;
}
/*
* If we're in the NIC slot, make sure the IRQ is enabled
......@@ -690,7 +713,10 @@ static struct net_device * __init etherh_init_one(struct expansion_card *ec)
etherh_reset(dev);
NS8390_init(dev, 0);
return dev;
ecard_set_drvdata(ec, dev);
return 0;
release:
release_region(dev->base_addr, 16);
......@@ -700,67 +726,59 @@ static struct net_device * __init etherh_init_one(struct expansion_card *ec)
kfree(dev);
out:
ecard_release(ec);
return NULL;
return ret;
}
#define MAX_ETHERH_CARDS 2
static void __devexit etherh_remove(struct expansion_card *ec)
{
struct net_device *dev = ecard_get_drvdata(ec);
int size = 16;
static struct net_device *e_dev[MAX_ETHERH_CARDS];
static struct expansion_card *e_card[MAX_ETHERH_CARDS];
ecard_set_drvdata(ec, NULL);
unregister_netdev(dev);
if (ec->cid.product == PROD_ANT_ETHERM)
size <<= 3;
release_region(dev->base_addr, size);
kfree(dev);
ec->ops = NULL;
kfree(ec->irq_data);
ecard_release(ec);
}
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 },
{ 0xffff, 0xffff }
};
static struct ecard_driver etherh_driver = {
.probe = etherh_probe,
.remove = __devexit_p(etherh_remove),
.id_table = etherh_ids,
.drv = {
.name = "etherh",
},
};
static int __init etherh_init(void)
{
int i, ret = -ENODEV;
int i;
for (i = 0; i < 16; i++) {
etherh_regoffsets[i] = i;
etherm_regoffsets[i] = i << 3;
}
ecard_startfind();
for (i = 0; i < MAX_ECARDS; i++) {
struct expansion_card *ec;
struct net_device *dev;
ec = ecard_find(0, etherh_cids);
if (!ec)
break;
dev = etherh_init_one(ec);
if (!dev)
break;
e_card[i] = ec;
e_dev[i] = dev;
ret = 0;
}
return ret;
return ecard_register_driver(&etherh_driver);
}
static void __exit etherh_exit(void)
{
int i;
for (i = 0; i < MAX_ETHERH_CARDS; i++) {
if (e_dev[i]) {
int size;
unregister_netdev(e_dev[i]);
size = 16;
if (e_card[i]->cid.product == PROD_ANT_ETHERM)
size <<= 3;
release_region(e_dev[i]->base_addr, size);
kfree(e_dev[i]);
e_dev[i] = NULL;
}
if (e_card[i]) {
e_card[i]->ops = NULL;
kfree(e_card[i]->irq_data);
ecard_release(e_card[i]);
e_card[i] = NULL;
}
}
ecard_remove_driver(&etherh_driver);
}
module_init(etherh_init);
......
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