* David S. Miller (davem@redhat.com)
* 2.01:
* 11/08/01: Use library crc32 functions (Matt_Domsch@dell.com)
- *
+ *
*/
#undef DEBUG_DRIVER
-static char version[] =
- "sunlance.c:v2.02 24/Aug/03 Miguel de Icaza (miguel@nuclecu.unam.mx)\n";
-
static char lancestr[] = "LANCE";
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/ethtool.h>
+#include <linux/bitops.h>
#include <asm/system.h>
-#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <asm/pgtable.h>
#include <asm/auxio.h> /* For tpe-link-test? setting */
#include <asm/irq.h>
+#define DRV_NAME "sunlance"
+#define DRV_VERSION "2.02"
+#define DRV_RELDATE "8/24/03"
+#define DRV_AUTHOR "Miguel de Icaza (miguel@nuclecu.unam.mx)"
+
+static char version[] =
+ DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " " DRV_AUTHOR "\n";
+
+MODULE_VERSION(DRV_VERSION);
+MODULE_AUTHOR(DRV_AUTHOR);
+MODULE_DESCRIPTION("Sun Lance ethernet driver");
+MODULE_LICENSE("GPL");
+
/* Define: 2^4 Tx buffers and 2^4 Rx buffers */
#ifndef LANCE_LOG_TX_BUFFERS
#define LANCE_LOG_TX_BUFFERS 4
s16 length; /* Length is 2s complement (negative)! */
u16 misc;
};
-
+
/* The LANCE initialization block, described in databook. */
/* On the Sparc, this block should be on a DMA region */
struct lance_init_block {
u16 rx_len; /* receive len and high addr */
u16 tx_ptr; /* transmit descriptor addr */
u16 tx_len; /* transmit len and high addr */
-
+
/* The Tx and Rx ring entries must aligned on 8-byte boundaries. */
struct lance_rx_desc brx_ring[RX_RING_SIZE];
struct lance_tx_desc btx_ring[TX_RING_SIZE];
-
+
u8 tx_buf [TX_RING_SIZE][TX_BUFF_SIZE];
u8 pad[2]; /* align rx_buf for copy_and_sum(). */
u8 rx_buf [RX_RING_SIZE][RX_BUFF_SIZE];
((__u32)(((unsigned long)(&(((struct lance_init_block *)0)->rt[elem][0])))))
struct lance_private {
- unsigned long lregs; /* Lance RAP/RDP regs. */
- unsigned long dregs; /* DMA controller regs. */
- volatile struct lance_init_block *init_block;
-
+ void __iomem *lregs; /* Lance RAP/RDP regs. */
+ void __iomem *dregs; /* DMA controller regs. */
+ struct lance_init_block __iomem *init_block_iomem;
+ struct lance_init_block *init_block_mem;
+
spinlock_t lock;
int rx_new, tx_new;
int rx_old, tx_old;
-
+
struct net_device_stats stats;
struct sbus_dma *ledma; /* If set this points to ledma */
char tpe; /* cable-selection is TPE */
char *name;
dma_addr_t init_block_dvma;
struct net_device *dev; /* Backpointer */
- struct lance_private *next_module;
struct sbus_dev *sdev;
struct timer_list multicast_timer;
};
#define LANCE_REG_SIZE 0x04UL
#define STOP_LANCE(__lp) \
-do { unsigned long __base = (__lp)->lregs; \
+do { void __iomem *__base = (__lp)->lregs; \
sbus_writew(LE_CSR0, __base + RAP); \
sbus_writew(LE_C0_STOP, __base + RDP); \
} while (0)
#define LANCE_ADDR(x) ((long)(x) & ~0xff000000)
-static struct lance_private *root_lance_dev;
-
/* Load the CSR registers */
static void load_csrs(struct lance_private *lp)
{
static void lance_init_ring_dvma(struct net_device *dev)
{
struct lance_private *lp = netdev_priv(dev);
- volatile struct lance_init_block *ib = lp->init_block;
+ struct lance_init_block *ib = lp->init_block_mem;
dma_addr_t aib = lp->init_block_dvma;
__u32 leptr;
int i;
-
+
/* Lock out other processes while setting up hardware */
netif_stop_queue(dev);
lp->rx_new = lp->tx_new = 0;
}
/* Setup the initialization block */
-
+
/* Setup rx descriptor pointer */
leptr = LANCE_ADDR(aib + libdesc_offset(brx_ring, 0));
ib->rx_len = (LANCE_LOG_RX_BUFFERS << 13) | (leptr >> 16);
ib->rx_ptr = leptr;
-
+
/* Setup tx descriptor pointer */
leptr = LANCE_ADDR(aib + libdesc_offset(btx_ring, 0));
ib->tx_len = (LANCE_LOG_TX_BUFFERS << 13) | (leptr >> 16);
static void lance_init_ring_pio(struct net_device *dev)
{
struct lance_private *lp = netdev_priv(dev);
- volatile struct lance_init_block *ib = lp->init_block;
+ struct lance_init_block __iomem *ib = lp->init_block_iomem;
u32 leptr;
int i;
-
+
/* Lock out other processes while setting up hardware */
netif_stop_queue(dev);
lp->rx_new = lp->tx_new = 0;
}
/* Setup the initialization block */
-
+
/* Setup rx descriptor pointer */
leptr = libdesc_offset(brx_ring, 0);
sbus_writew((LANCE_LOG_RX_BUFFERS << 13) | (leptr >> 16),
&ib->rx_len);
sbus_writew(leptr, &ib->rx_ptr);
-
+
/* Setup tx descriptor pointer */
leptr = libdesc_offset(btx_ring, 0);
sbus_writew((LANCE_LOG_TX_BUFFERS << 13) | (leptr >> 16),
static void lance_rx_dvma(struct net_device *dev)
{
struct lance_private *lp = netdev_priv(dev);
- volatile struct lance_init_block *ib = lp->init_block;
- volatile struct lance_rx_desc *rd;
+ struct lance_init_block *ib = lp->init_block_mem;
+ struct lance_rx_desc *rd;
u8 bits;
int len, entry = lp->rx_new;
struct sk_buff *skb;
lp->rx_new = RX_NEXT(entry);
return;
}
-
+
lp->stats.rx_bytes += len;
skb->dev = dev;
static void lance_tx_dvma(struct net_device *dev)
{
struct lance_private *lp = netdev_priv(dev);
- volatile struct lance_init_block *ib = lp->init_block;
+ struct lance_init_block *ib = lp->init_block_mem;
int i, j;
spin_lock(&lp->lock);
j = lp->tx_old;
for (i = j; i != lp->tx_new; i = j) {
- volatile struct lance_tx_desc *td = &ib->btx_ring [i];
+ struct lance_tx_desc *td = &ib->btx_ring [i];
u8 bits = td->tmd1_bits;
/* If we hit a packet not owned by us, stop */
if (bits & LE_T1_OWN)
break;
-
+
if (bits & LE_T1_ERR) {
u16 status = td->misc;
-
+
lp->stats.tx_errors++;
if (status & LE_T3_RTY) lp->stats.tx_aborted_errors++;
if (status & LE_T3_LCOL) lp->stats.tx_window_errors++;
lp->stats.tx_packets++;
}
-
+
j = TX_NEXT(j);
}
lp->tx_old = j;
spin_unlock(&lp->lock);
}
-static void lance_piocopy_to_skb(struct sk_buff *skb, volatile void *piobuf, int len)
+static void lance_piocopy_to_skb(struct sk_buff *skb, void __iomem *piobuf, int len)
{
u16 *p16 = (u16 *) skb->data;
u32 *p32;
u8 *p8;
- unsigned long pbuf = (unsigned long) piobuf;
+ void __iomem *pbuf = piobuf;
/* We know here that both src and dest are on a 16bit boundary. */
*p16++ = sbus_readw(pbuf);
static void lance_rx_pio(struct net_device *dev)
{
struct lance_private *lp = netdev_priv(dev);
- volatile struct lance_init_block *ib = lp->init_block;
- volatile struct lance_rx_desc *rd;
+ struct lance_init_block __iomem *ib = lp->init_block_iomem;
+ struct lance_rx_desc __iomem *rd;
unsigned char bits;
int len, entry;
struct sk_buff *skb;
lp->rx_new = RX_NEXT(entry);
return;
}
-
+
lp->stats.rx_bytes += len;
skb->dev = dev;
static void lance_tx_pio(struct net_device *dev)
{
struct lance_private *lp = netdev_priv(dev);
- volatile struct lance_init_block *ib = lp->init_block;
+ struct lance_init_block __iomem *ib = lp->init_block_iomem;
int i, j;
spin_lock(&lp->lock);
j = lp->tx_old;
for (i = j; i != lp->tx_new; i = j) {
- volatile struct lance_tx_desc *td = &ib->btx_ring [i];
+ struct lance_tx_desc __iomem *td = &ib->btx_ring [i];
u8 bits = sbus_readb(&td->tmd1_bits);
/* If we hit a packet not owned by us, stop */
if (bits & LE_T1_OWN)
break;
-
+
if (bits & LE_T1_ERR) {
u16 status = sbus_readw(&td->misc);
-
+
lp->stats.tx_errors++;
if (status & LE_T3_RTY) lp->stats.tx_aborted_errors++;
if (status & LE_T3_LCOL) lp->stats.tx_window_errors++;
lp->stats.tx_packets++;
}
-
+
j = TX_NEXT(j);
}
lp->tx_old = j;
spin_unlock(&lp->lock);
}
-static irqreturn_t lance_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t lance_interrupt(int irq, void *dev_id)
{
- struct net_device *dev = (struct net_device *)dev_id;
+ struct net_device *dev = dev_id;
struct lance_private *lp = netdev_priv(dev);
int csr0;
-
+
sbus_writew(LE_CSR0, lp->lregs + RAP);
csr0 = sbus_readw(lp->lregs + RDP);
/* Acknowledge all the interrupt sources ASAP */
sbus_writew(csr0 & (LE_C0_INTR | LE_C0_TINT | LE_C0_RINT),
lp->lregs + RDP);
-
+
if ((csr0 & LE_C0_ERR) != 0) {
/* Clear the error condition */
sbus_writew((LE_C0_BABL | LE_C0_ERR | LE_C0_MISS |
LE_C0_CERR | LE_C0_MERR),
lp->lregs + RDP);
}
-
+
if (csr0 & LE_C0_RINT)
lp->rx(dev);
-
+
if (csr0 & LE_C0_TINT)
lp->tx(dev);
-
+
if (csr0 & LE_C0_BABL)
lp->stats.tx_errors++;
static void build_fake_packet(struct lance_private *lp)
{
struct net_device *dev = lp->dev;
- volatile struct lance_init_block *ib = lp->init_block;
- u16 *packet;
- struct ethhdr *eth;
int i, entry;
entry = lp->tx_new & TX_RING_MOD_MASK;
- packet = (u16 *) &(ib->tx_buf[entry][0]);
- eth = (struct ethhdr *) packet;
if (lp->pio_buffer) {
+ struct lance_init_block __iomem *ib = lp->init_block_iomem;
+ u16 __iomem *packet = (u16 __iomem *) &(ib->tx_buf[entry][0]);
+ struct ethhdr __iomem *eth = (struct ethhdr __iomem *) packet;
for (i = 0; i < (ETH_ZLEN / sizeof(u16)); i++)
sbus_writew(0, &packet[i]);
for (i = 0; i < 6; i++) {
sbus_writew(0, &ib->btx_ring[entry].misc);
sbus_writeb(LE_T1_POK|LE_T1_OWN, &ib->btx_ring[entry].tmd1_bits);
} else {
+ struct lance_init_block *ib = lp->init_block_mem;
+ u16 *packet = (u16 *) &(ib->tx_buf[entry][0]);
+ struct ethhdr *eth = (struct ethhdr *) packet;
memset(packet, 0, ETH_ZLEN);
for (i = 0; i < 6; i++) {
eth->h_dest[i] = dev->dev_addr[i];
lp->tx_new = TX_NEXT(entry);
}
-struct net_device *last_dev = 0;
+struct net_device *last_dev;
static int lance_open(struct net_device *dev)
{
struct lance_private *lp = netdev_priv(dev);
- volatile struct lance_init_block *ib = lp->init_block;
int status = 0;
last_dev = dev;
STOP_LANCE(lp);
- if (request_irq(dev->irq, &lance_interrupt, SA_SHIRQ,
+ if (request_irq(dev->irq, &lance_interrupt, IRQF_SHARED,
lancestr, (void *) dev)) {
- printk(KERN_ERR "Lance: Can't get irq %s\n", __irq_itoa(dev->irq));
+ printk(KERN_ERR "Lance: Can't get irq %d\n", dev->irq);
return -EAGAIN;
}
* BTW it is common bug in all lance drivers! --ANK
*/
if (lp->pio_buffer) {
+ struct lance_init_block __iomem *ib = lp->init_block_iomem;
sbus_writew(0, &ib->mode);
sbus_writel(0, &ib->filter[0]);
sbus_writel(0, &ib->filter[1]);
} else {
+ struct lance_init_block *ib = lp->init_block_mem;
ib->mode = 0;
ib->filter [0] = 0;
ib->filter [1] = 0;
{
struct lance_private *lp = netdev_priv(dev);
int status;
-
+
STOP_LANCE(lp);
/* On the 4m, reset the dma too */
return status;
}
-static void lance_piocopy_from_skb(volatile void *dest, unsigned char *src, int len)
+static void lance_piocopy_from_skb(void __iomem *dest, unsigned char *src, int len)
{
- unsigned long piobuf = (unsigned long) dest;
+ void __iomem *piobuf = dest;
u32 *p32;
u16 *p16;
u8 *p8;
sbus_writeb(src[0], piobuf);
}
-static void lance_piozero(volatile void *dest, int len)
+static void lance_piozero(void __iomem *dest, int len)
{
- unsigned long piobuf = (unsigned long) dest;
+ void __iomem *piobuf = dest;
- if (piobuf & 1) {
+ if ((unsigned long)piobuf & 1) {
sbus_writeb(0, piobuf);
piobuf += 1;
len -= 1;
sbus_writeb(0, piobuf);
return;
}
- if (piobuf & 2) {
+ if ((unsigned long)piobuf & 2) {
sbus_writew(0, piobuf);
piobuf += 2;
len -= 2;
static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct lance_private *lp = netdev_priv(dev);
- volatile struct lance_init_block *ib = lp->init_block;
int entry, skblen, len;
skblen = skb->len;
entry = lp->tx_new & TX_RING_MOD_MASK;
if (lp->pio_buffer) {
+ struct lance_init_block __iomem *ib = lp->init_block_iomem;
sbus_writew((-len) | 0xf000, &ib->btx_ring[entry].length);
sbus_writew(0, &ib->btx_ring[entry].misc);
lance_piocopy_from_skb(&ib->tx_buf[entry][0], skb->data, skblen);
lance_piozero(&ib->tx_buf[entry][skblen], len - skblen);
sbus_writeb(LE_T1_POK | LE_T1_OWN, &ib->btx_ring[entry].tmd1_bits);
} else {
+ struct lance_init_block *ib = lp->init_block_mem;
ib->btx_ring [entry].length = (-len) | 0xf000;
ib->btx_ring [entry].misc = 0;
memcpy((char *)&ib->tx_buf [entry][0], skb->data, skblen);
dev->trans_start = jiffies;
dev_kfree_skb(skb);
-
+
return 0;
}
static void lance_load_multicast(struct net_device *dev)
{
struct lance_private *lp = netdev_priv(dev);
- volatile struct lance_init_block *ib = lp->init_block;
- volatile u16 *mcast_table = (u16 *) &ib->filter;
struct dev_mc_list *dmi = dev->mc_list;
char *addrs;
int i;
u32 crc;
-
+ u32 val;
+
/* set all multicast bits */
- if (dev->flags & IFF_ALLMULTI) {
- if (lp->pio_buffer) {
- sbus_writel(0xffffffff, &ib->filter[0]);
- sbus_writel(0xffffffff, &ib->filter[1]);
- } else {
- ib->filter [0] = 0xffffffff;
- ib->filter [1] = 0xffffffff;
- }
- return;
- }
- /* clear the multicast filter */
+ if (dev->flags & IFF_ALLMULTI)
+ val = ~0;
+ else
+ val = 0;
+
if (lp->pio_buffer) {
- sbus_writel(0, &ib->filter[0]);
- sbus_writel(0, &ib->filter[1]);
+ struct lance_init_block __iomem *ib = lp->init_block_iomem;
+ sbus_writel(val, &ib->filter[0]);
+ sbus_writel(val, &ib->filter[1]);
} else {
- ib->filter [0] = 0;
- ib->filter [1] = 0;
+ struct lance_init_block *ib = lp->init_block_mem;
+ ib->filter [0] = val;
+ ib->filter [1] = val;
}
+ if (dev->flags & IFF_ALLMULTI)
+ return;
+
/* Add addresses */
for (i = 0; i < dev->mc_count; i++) {
addrs = dmi->dmi_addr;
crc = ether_crc_le(6, addrs);
crc = crc >> 26;
if (lp->pio_buffer) {
+ struct lance_init_block __iomem *ib = lp->init_block_iomem;
+ u16 __iomem *mcast_table = (u16 __iomem *) &ib->filter;
u16 tmp = sbus_readw(&mcast_table[crc>>4]);
tmp |= 1 << (crc & 0xf);
sbus_writew(tmp, &mcast_table[crc>>4]);
} else {
+ struct lance_init_block *ib = lp->init_block_mem;
+ u16 *mcast_table = (u16 *) &ib->filter;
mcast_table [crc >> 4] |= 1 << (crc & 0xf);
}
}
static void lance_set_multicast(struct net_device *dev)
{
struct lance_private *lp = netdev_priv(dev);
- volatile struct lance_init_block *ib = lp->init_block;
+ struct lance_init_block *ib_mem = lp->init_block_mem;
+ struct lance_init_block __iomem *ib_iomem = lp->init_block_iomem;
u16 mode;
if (!netif_running(dev))
lp->init_ring(dev);
if (lp->pio_buffer)
- mode = sbus_readw(&ib->mode);
+ mode = sbus_readw(&ib_iomem->mode);
else
- mode = ib->mode;
+ mode = ib_mem->mode;
if (dev->flags & IFF_PROMISC) {
mode |= LE_MO_PROM;
if (lp->pio_buffer)
- sbus_writew(mode, &ib->mode);
+ sbus_writew(mode, &ib_iomem->mode);
else
- ib->mode = mode;
+ ib_mem->mode = mode;
} else {
mode &= ~LE_MO_PROM;
if (lp->pio_buffer)
- sbus_writew(mode, &ib->mode);
+ sbus_writew(mode, &ib_iomem->mode);
else
- ib->mode = mode;
+ ib_mem->mode = mode;
lance_load_multicast(dev);
}
load_csrs(lp);
{
if (lp->lregs)
sbus_iounmap(lp->lregs, LANCE_REG_SIZE);
- if (lp->init_block != NULL) {
- if (lp->pio_buffer) {
- sbus_iounmap((unsigned long)lp->init_block,
- sizeof(struct lance_init_block));
- } else {
- sbus_free_consistent(lp->sdev,
- sizeof(struct lance_init_block),
- (void *)lp->init_block,
- lp->init_block_dvma);
- }
+ if (lp->init_block_iomem) {
+ sbus_iounmap(lp->init_block_iomem,
+ sizeof(struct lance_init_block));
+ } else if (lp->init_block_mem) {
+ sbus_free_consistent(lp->sdev,
+ sizeof(struct lance_init_block),
+ lp->init_block_mem,
+ lp->init_block_dvma);
}
}
return 1;
}
-static struct ethtool_ops sparc_lance_ethtool_ops = {
+static const struct ethtool_ops sparc_lance_ethtool_ops = {
.get_drvinfo = sparc_lance_get_drvinfo,
.get_link = sparc_lance_get_link,
};
-static int __init sparc_lance_init(struct sbus_dev *sdev,
- struct sbus_dma *ledma,
- struct sbus_dev *lebuffer)
+static int __devinit sparc_lance_probe_one(struct sbus_dev *sdev,
+ struct sbus_dma *ledma,
+ struct sbus_dev *lebuffer)
{
static unsigned version_printed;
struct net_device *dev;
return -ENOMEM;
lp = netdev_priv(dev);
+ memset(lp, 0, sizeof(*lp));
if (sparc_lance_debug && version_printed++ == 0)
printk (KERN_INFO "%s", version);
/* Get the IO region */
lp->lregs = sbus_ioremap(&sdev->resource[0], 0,
LANCE_REG_SIZE, lancestr);
- if (lp->lregs == 0UL) {
+ if (!lp->lregs) {
printk(KERN_ERR "SunLance: Cannot map registers.\n");
goto fail;
}
lp->sdev = sdev;
if (lebuffer) {
- lp->init_block = (volatile struct lance_init_block *)
+ /* sanity check */
+ if (lebuffer->resource[0].start & 7) {
+ printk(KERN_ERR "SunLance: ERROR: Rx and Tx rings not on even boundary.\n");
+ goto fail;
+ }
+ lp->init_block_iomem =
sbus_ioremap(&lebuffer->resource[0], 0,
sizeof(struct lance_init_block), "lebuffer");
- if (lp->init_block == NULL) {
+ if (!lp->init_block_iomem) {
printk(KERN_ERR "SunLance: Cannot map PIO buffer.\n");
goto fail;
}
lp->rx = lance_rx_pio;
lp->tx = lance_tx_pio;
} else {
- lp->init_block = (volatile struct lance_init_block *)
+ lp->init_block_mem =
sbus_alloc_consistent(sdev, sizeof(struct lance_init_block),
&lp->init_block_dvma);
- if (lp->init_block == NULL ||
- lp->init_block_dvma == 0) {
+ if (!lp->init_block_mem || lp->init_block_dvma == 0) {
printk(KERN_ERR "SunLance: Cannot allocate consistent DMA memory.\n");
goto fail;
}
udelay(200);
sbus_writel(csr & ~DMA_RST_ENET, lp->dregs + DMA_CSR);
} else
- lp->dregs = 0;
-
- /* This should never happen. */
- if ((unsigned long)(lp->init_block->brx_ring) & 0x07) {
- printk(KERN_ERR "SunLance: ERROR: Rx and Tx rings not on even boundary.\n");
- goto fail;
- }
+ lp->dregs = NULL;
lp->dev = dev;
SET_MODULE_OWNER(dev);
+ SET_NETDEV_DEV(dev, &sdev->ofdev.dev);
dev->open = &lance_open;
dev->stop = &lance_close;
dev->hard_start_xmit = &lance_start_xmit;
goto fail;
}
- lp->next_module = root_lance_dev;
- root_lance_dev = lp;
+ dev_set_drvdata(&sdev->ofdev.dev, lp);
printk(KERN_INFO "%s: LANCE ", dev->name);
return 0;
fail:
- if (lp != NULL)
- lance_free_hwresources(lp);
+ lance_free_hwresources(lp);
free_netdev(dev);
return -ENODEV;
}
/* On 4m, find the associated dma for the lance chip */
-static inline struct sbus_dma *find_ledma(struct sbus_dev *sdev)
+static struct sbus_dma * __devinit find_ledma(struct sbus_dev *sdev)
{
struct sbus_dma *p;
#include <asm/machines.h>
/* Find all the lance cards on the system and initialize them */
-static int __init sparc_lance_probe(void)
+static struct sbus_dev sun4_sdev;
+static int __devinit sparc_lance_init(void)
{
- static struct sbus_dev sdev;
- static int called;
-
- root_lance_dev = NULL;
-
- if (called)
- return -ENODEV;
- called++;
-
if ((idprom->id_machtype == (SM_SUN4|SM_4_330)) ||
(idprom->id_machtype == (SM_SUN4|SM_4_470))) {
- memset(&sdev, 0, sizeof(sdev));
- sdev.reg_addrs[0].phys_addr = sun4_eth_physaddr;
- sdev.irqs[0] = 6;
- return sparc_lance_init(&sdev, 0, 0);
+ memset(&sun4_sdev, 0, sizeof(struct sbus_dev));
+ sun4_sdev.reg_addrs[0].phys_addr = sun4_eth_physaddr;
+ sun4_sdev.irqs[0] = 6;
+ return sparc_lance_probe_one(&sun4_sdev, NULL, NULL);
}
return -ENODEV;
}
+static int __exit sunlance_sun4_remove(void)
+{
+ struct lance_private *lp = dev_get_drvdata(&sun4_sdev.ofdev.dev);
+ struct net_device *net_dev = lp->dev;
+
+ unregister_netdevice(net_dev);
+
+ lance_free_hwresources(lp);
+
+ free_netdev(net_dev);
+
+ dev_set_drvdata(&sun4_sdev.ofdev.dev, NULL);
+
+ return 0;
+}
+
#else /* !CONFIG_SUN4 */
-/* Find all the lance cards on the system and initialize them */
-static int __init sparc_lance_probe(void)
+static int __devinit sunlance_sbus_probe(struct of_device *dev, const struct of_device_id *match)
{
- struct sbus_bus *bus;
- struct sbus_dev *sdev = 0;
- struct sbus_dma *ledma = 0;
- static int called;
- int cards = 0, v;
-
- root_lance_dev = NULL;
-
- if (called)
- return -ENODEV;
- called++;
-
- for_each_sbus (bus) {
- for_each_sbusdev (sdev, bus) {
- if (strcmp(sdev->prom_name, "le") == 0) {
- cards++;
- if ((v = sparc_lance_init(sdev, 0, 0)))
- return v;
- continue;
- }
- if (strcmp(sdev->prom_name, "ledma") == 0) {
- cards++;
- ledma = find_ledma(sdev);
- if ((v = sparc_lance_init(sdev->child,
- ledma, 0)))
- return v;
- continue;
- }
- if (strcmp(sdev->prom_name, "lebuffer") == 0){
- cards++;
- if ((v = sparc_lance_init(sdev->child,
- 0, sdev)))
- return v;
- continue;
- }
- } /* for each sbusdev */
- } /* for each sbus */
- if (!cards)
- return -ENODEV;
- return 0;
+ struct sbus_dev *sdev = to_sbus_device(&dev->dev);
+ int err;
+
+ if (sdev->parent) {
+ struct of_device *parent = &sdev->parent->ofdev;
+
+ if (!strcmp(parent->node->name, "ledma")) {
+ struct sbus_dma *ledma = find_ledma(to_sbus_device(&parent->dev));
+
+ err = sparc_lance_probe_one(sdev, ledma, NULL);
+ } else if (!strcmp(parent->node->name, "lebuffer")) {
+ err = sparc_lance_probe_one(sdev, NULL, to_sbus_device(&parent->dev));
+ } else
+ err = sparc_lance_probe_one(sdev, NULL, NULL);
+ } else
+ err = sparc_lance_probe_one(sdev, NULL, NULL);
+
+ return err;
}
-#endif /* !CONFIG_SUN4 */
-static void __exit sparc_lance_cleanup(void)
+static int __devexit sunlance_sbus_remove(struct of_device *dev)
{
- struct lance_private *lp;
+ struct lance_private *lp = dev_get_drvdata(&dev->dev);
+ struct net_device *net_dev = lp->dev;
- while (root_lance_dev) {
- lp = root_lance_dev->next_module;
+ unregister_netdevice(net_dev);
- unregister_netdev(root_lance_dev->dev);
- lance_free_hwresources(root_lance_dev);
- free_netdev(root_lance_dev->dev);
- root_lance_dev = lp;
- }
+ lance_free_hwresources(lp);
+
+ free_netdev(net_dev);
+
+ dev_set_drvdata(&dev->dev, NULL);
+
+ return 0;
}
-module_init(sparc_lance_probe);
-module_exit(sparc_lance_cleanup);
-MODULE_LICENSE("GPL");
+static struct of_device_id sunlance_sbus_match[] = {
+ {
+ .name = "le",
+ },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, sunlance_sbus_match);
+
+static struct of_platform_driver sunlance_sbus_driver = {
+ .name = "sunlance",
+ .match_table = sunlance_sbus_match,
+ .probe = sunlance_sbus_probe,
+ .remove = __devexit_p(sunlance_sbus_remove),
+};
+
+
+/* Find all the lance cards on the system and initialize them */
+static int __init sparc_lance_init(void)
+{
+ return of_register_driver(&sunlance_sbus_driver, &sbus_bus_type);
+}
+#endif /* !CONFIG_SUN4 */
+
+static void __exit sparc_lance_exit(void)
+{
+#ifdef CONFIG_SUN4
+ sunlance_sun4_remove();
+#else
+ of_unregister_driver(&sunlance_sbus_driver);
+#endif
+}
+
+module_init(sparc_lance_init);
+module_exit(sparc_lance_exit);