Commit c32262de authored by Benjamin Herrenschmidt's avatar Benjamin Herrenschmidt Committed by Jeff Garzik

[PATCH] bmac network driver update

Hi !

I didn't include that with the bitkeeper based PowerMac updates so Jeff
can assume his role as maintainer/filter of network driver updates :)

Here's my latest update to this pmac-only driver, please apply if you
are ok with it. The driver now uses the macio infrastructure for
detection & power management notifications, getting into sysfs at
the same time.

Ben.


# This is a BitKeeper generated diff -Nru style patch.
#
# ChangeSet
#   2004/01/23 09:38:35+11:00 benh@kernel.crashing.org
#   Update PowerMac "bmac" driver to the "macio" device so it fits in sysfs
#   and gets proper power management ordering
#
# drivers/net/bmac.c
#   2004/01/23 09:38:22+11:00 benh@kernel.crashing.org +185 -203
#   Update PowerMac "bmac" driver to the "macio" device so it fits in sysfs
#   and gets proper power management ordering
#
parent 92d3a215
...@@ -26,11 +26,9 @@ ...@@ -26,11 +26,9 @@
#include <asm/pgtable.h> #include <asm/pgtable.h>
#include <asm/machdep.h> #include <asm/machdep.h>
#include <asm/pmac_feature.h> #include <asm/pmac_feature.h>
#include <asm/macio.h>
#include <asm/irq.h> #include <asm/irq.h>
#ifdef CONFIG_PMAC_PBOOK
#include <linux/adb.h>
#include <linux/pmu.h>
#endif
#include "bmac.h" #include "bmac.h"
#define trunc_page(x) ((void *)(((unsigned long)(x)) & ~((unsigned long)(PAGE_SIZE - 1)))) #define trunc_page(x) ((void *)(((unsigned long)(x)) & ~((unsigned long)(PAGE_SIZE - 1))))
...@@ -67,7 +65,7 @@ struct bmac_data { ...@@ -67,7 +65,7 @@ struct bmac_data {
int rx_dma_intr; int rx_dma_intr;
volatile struct dbdma_cmd *tx_cmds; /* xmit dma command list */ volatile struct dbdma_cmd *tx_cmds; /* xmit dma command list */
volatile struct dbdma_cmd *rx_cmds; /* recv dma command list */ volatile struct dbdma_cmd *rx_cmds; /* recv dma command list */
struct device_node *node; struct macio_dev *mdev;
int is_bmac_plus; int is_bmac_plus;
struct sk_buff *rx_bufs[N_RX_RING]; struct sk_buff *rx_bufs[N_RX_RING];
int rx_fill; int rx_fill;
...@@ -84,9 +82,10 @@ struct bmac_data { ...@@ -84,9 +82,10 @@ struct bmac_data {
unsigned short hash_use_count[64]; unsigned short hash_use_count[64];
unsigned short hash_table_mask[4]; unsigned short hash_table_mask[4];
spinlock_t lock; spinlock_t lock;
struct net_device *next_bmac;
}; };
#if 0 /* Move that to ethtool */
typedef struct bmac_reg_entry { typedef struct bmac_reg_entry {
char *name; char *name;
unsigned short reg_offset; unsigned short reg_offset;
...@@ -128,16 +127,10 @@ static bmac_reg_entry_t reg_entries[N_REG_ENTRIES] = { ...@@ -128,16 +127,10 @@ static bmac_reg_entry_t reg_entries[N_REG_ENTRIES] = {
{"RXCV", RXCV} {"RXCV", RXCV}
}; };
static struct net_device *bmac_devs;
static unsigned char *bmac_emergency_rxbuf;
#ifdef CONFIG_PMAC_PBOOK
static int bmac_sleep_notify(struct pmu_sleep_notifier *self, int when);
static struct pmu_sleep_notifier bmac_sleep_notifier = {
bmac_sleep_notify, SLEEP_LEVEL_NET,
};
#endif #endif
static unsigned char *bmac_emergency_rxbuf;
/* /*
* Number of bytes of private data per BMAC: allow enough for * Number of bytes of private data per BMAC: allow enough for
* the rx and tx dma commands plus a branch dma command each, * the rx and tx dma commands plus a branch dma command each,
...@@ -149,7 +142,6 @@ static struct pmu_sleep_notifier bmac_sleep_notifier = { ...@@ -149,7 +142,6 @@ static struct pmu_sleep_notifier bmac_sleep_notifier = {
+ sizeof(struct sk_buff_head)) + sizeof(struct sk_buff_head))
static unsigned char bitrev(unsigned char b); static unsigned char bitrev(unsigned char b);
static void bmac_probe1(struct device_node *bmac, int is_bmac_plus);
static int bmac_open(struct net_device *dev); static int bmac_open(struct net_device *dev);
static int bmac_close(struct net_device *dev); static int bmac_close(struct net_device *dev);
static int bmac_transmit_packet(struct sk_buff *skb, struct net_device *dev); static int bmac_transmit_packet(struct sk_buff *skb, struct net_device *dev);
...@@ -166,7 +158,6 @@ static irqreturn_t bmac_txdma_intr(int irq, void *dev_id, struct pt_regs *regs); ...@@ -166,7 +158,6 @@ static irqreturn_t bmac_txdma_intr(int irq, void *dev_id, struct pt_regs *regs);
static irqreturn_t bmac_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs); static irqreturn_t bmac_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs);
static void bmac_set_timeout(struct net_device *dev); static void bmac_set_timeout(struct net_device *dev);
static void bmac_tx_timeout(unsigned long data); static void bmac_tx_timeout(unsigned long data);
static int bmac_proc_info ( char *buffer, char **start, off_t offset, int length);
static int bmac_output(struct sk_buff *skb, struct net_device *dev); static int bmac_output(struct sk_buff *skb, struct net_device *dev);
static void bmac_start(struct net_device *dev); static void bmac_start(struct net_device *dev);
...@@ -244,7 +235,7 @@ bmac_enable_and_reset_chip(struct net_device *dev) ...@@ -244,7 +235,7 @@ bmac_enable_and_reset_chip(struct net_device *dev)
if (td) if (td)
dbdma_reset(td); dbdma_reset(td);
pmac_call_feature(PMAC_FTR_BMAC_ENABLE, bp->node, 0, 1); pmac_call_feature(PMAC_FTR_BMAC_ENABLE, macio_get_of_node(bp->mdev), 0, 1);
} }
#define MIFDELAY udelay(10) #define MIFDELAY udelay(10)
...@@ -457,34 +448,21 @@ bmac_init_phy(struct net_device *dev) ...@@ -457,34 +448,21 @@ bmac_init_phy(struct net_device *dev)
} }
} }
static void static void bmac_init_chip(struct net_device *dev)
bmac_init_chip(struct net_device *dev)
{ {
bmac_init_phy(dev); bmac_init_phy(dev);
bmac_init_registers(dev); bmac_init_registers(dev);
} }
#ifdef CONFIG_PMAC_PBOOK #ifdef CONFIG_PM
static int static int bmac_suspend(struct macio_dev *mdev, u32 state)
bmac_sleep_notify(struct pmu_sleep_notifier *self, int when)
{ {
struct bmac_data *bp; struct net_device* dev = macio_get_drvdata(mdev);
struct bmac_data *bp = dev->priv;
unsigned long flags; unsigned long flags;
unsigned short config; unsigned short config;
struct net_device* dev = bmac_devs;
int i; int i;
if (bmac_devs == 0)
return PBOOK_SLEEP_OK;
bp = (struct bmac_data *) dev->priv;
switch (when) {
case PBOOK_SLEEP_REQUEST:
break;
case PBOOK_SLEEP_REJECT:
break;
case PBOOK_SLEEP_NOW:
netif_device_detach(dev); netif_device_detach(dev);
/* prolly should wait for dma to finish & turn off the chip */ /* prolly should wait for dma to finish & turn off the chip */
spin_lock_irqsave(&bp->lock, flags); spin_lock_irqsave(&bp->lock, flags);
...@@ -523,21 +501,27 @@ bmac_sleep_notify(struct pmu_sleep_notifier *self, int when) ...@@ -523,21 +501,27 @@ bmac_sleep_notify(struct pmu_sleep_notifier *self, int when)
} }
} }
} }
pmac_call_feature(PMAC_FTR_BMAC_ENABLE, bp->node, 0, 0); pmac_call_feature(PMAC_FTR_BMAC_ENABLE, macio_get_of_node(bp->mdev), 0, 0);
break; return 0;
case PBOOK_WAKE: }
static int bmac_resume(struct macio_dev *mdev)
{
struct net_device* dev = macio_get_drvdata(mdev);
struct bmac_data *bp = dev->priv;
/* see if this is enough */ /* see if this is enough */
if (bp->opened) if (bp->opened)
bmac_reset_and_enable(dev); bmac_reset_and_enable(dev);
enable_irq(dev->irq); enable_irq(dev->irq);
enable_irq(bp->tx_dma_intr); enable_irq(bp->tx_dma_intr);
enable_irq(bp->rx_dma_intr); enable_irq(bp->rx_dma_intr);
netif_device_attach(dev); netif_device_attach(dev);
break;
} return 0;
return PBOOK_SLEEP_OK;
} }
#endif #endif /* CONFIG_PM */
static int bmac_set_address(struct net_device *dev, void *addr) static int bmac_set_address(struct net_device *dev, void *addr)
{ {
...@@ -1277,103 +1261,61 @@ static void bmac_reset_and_enable(struct net_device *dev) ...@@ -1277,103 +1261,61 @@ static void bmac_reset_and_enable(struct net_device *dev)
spin_unlock_irqrestore(&bp->lock, flags); spin_unlock_irqrestore(&bp->lock, flags);
} }
static int __init bmac_probe(void) static int __devinit bmac_probe(struct macio_dev *mdev, const struct of_match *match)
{
struct device_node *bmac;
MOD_INC_USE_COUNT;
for (bmac = find_devices("bmac"); bmac != 0; bmac = bmac->next)
bmac_probe1(bmac, 0);
for (bmac = find_compatible_devices("network", "bmac+"); bmac != 0;
bmac = bmac->next)
bmac_probe1(bmac, 1);
if (bmac_devs != 0) {
proc_net_create ("bmac", 0, bmac_proc_info);
#ifdef CONFIG_PMAC_PBOOK
pmu_register_sleep_notifier(&bmac_sleep_notifier);
#endif
}
MOD_DEC_USE_COUNT;
return bmac_devs? 0: -ENODEV;
}
static void __init bmac_probe1(struct device_node *bmac, int is_bmac_plus)
{ {
int j, rev, ret; int j, rev, ret;
struct bmac_data *bp; struct bmac_data *bp;
unsigned char *addr; unsigned char *addr;
struct net_device *dev; struct net_device *dev;
int is_bmac_plus = ((int)match->data) != 0;
if (bmac->n_addrs != 3 || bmac->n_intrs != 3) { if (macio_resource_count(mdev) != 3 || macio_irq_count(mdev) != 3) {
printk(KERN_ERR "can't use BMAC %s: need 3 addrs and 3 intrs\n", printk(KERN_ERR "BMAC: can't use, need 3 addrs and 3 intrs\n");
bmac->full_name); return -ENODEV;
return;
} }
addr = get_property(bmac, "mac-address", NULL); addr = get_property(macio_get_of_node(mdev), "mac-address", NULL);
if (addr == NULL) { if (addr == NULL) {
addr = get_property(bmac, "local-mac-address", NULL); addr = get_property(macio_get_of_node(mdev), "local-mac-address", NULL);
if (addr == NULL) { if (addr == NULL) {
printk(KERN_ERR "Can't get mac-address for BMAC %s\n", printk(KERN_ERR "BMAC: Can't get mac-address\n");
bmac->full_name); return -ENODEV;
return;
}
}
if (bmac_emergency_rxbuf == NULL) {
bmac_emergency_rxbuf = kmalloc(RX_BUFLEN, GFP_KERNEL);
if (bmac_emergency_rxbuf == NULL) {
printk(KERN_ERR "BMAC: can't allocate emergency RX buffer\n");
return;
} }
} }
dev = alloc_etherdev(PRIV_BYTES); dev = alloc_etherdev(PRIV_BYTES);
if (!dev) { if (!dev) {
printk(KERN_ERR "alloc_etherdev failed, out of memory for BMAC %s\n", printk(KERN_ERR "BMAC: alloc_etherdev failed, out of memory\n");
bmac->full_name); return -ENOMEM;
return;
} }
bp = (struct bmac_data *) dev->priv; bp = (struct bmac_data *) dev->priv;
SET_MODULE_OWNER(dev); SET_MODULE_OWNER(dev);
bp->node = bmac; SET_NETDEV_DEV(dev, &mdev->ofdev.dev);
macio_set_drvdata(mdev, dev);
bp->mdev = mdev;
spin_lock_init(&bp->lock); spin_lock_init(&bp->lock);
if (!request_OF_resource(bmac, 0, " (bmac)")) { if (macio_request_resources(mdev, "bmac")) {
printk(KERN_ERR "BMAC: can't request IO resource !\n"); printk(KERN_ERR "BMAC: can't request IO resource !\n");
goto out1; goto out_free;
}
if (!request_OF_resource(bmac, 1, " (bmac tx dma)")) {
printk(KERN_ERR "BMAC: can't request TX DMA resource !\n");
goto out2;
}
if (!request_OF_resource(bmac, 2, " (bmac rx dma)")) {
printk(KERN_ERR "BMAC: can't request RX DMA resource !\n");
goto out3;
} }
dev->base_addr = (unsigned long) dev->base_addr = (unsigned long)
ioremap(bmac->addrs[0].address, bmac->addrs[0].size); ioremap(macio_resource_start(mdev, 0), macio_resource_len(mdev, 0));
if (!dev->base_addr) if (dev->base_addr == 0)
goto out4; goto out_release;
dev->irq = bmac->intrs[0].line; dev->irq = macio_irq(mdev, 0);
bmac_enable_and_reset_chip(dev); bmac_enable_and_reset_chip(dev);
bmwrite(dev, INTDISABLE, DisableAll); bmwrite(dev, INTDISABLE, DisableAll);
printk(KERN_INFO "%s: BMAC%s at", dev->name, (is_bmac_plus? "+": ""));
rev = addr[0] == 0 && addr[1] == 0xA0; rev = addr[0] == 0 && addr[1] == 0xA0;
for (j = 0; j < 6; ++j) { for (j = 0; j < 6; ++j) {
dev->dev_addr[j] = rev? bitrev(addr[j]): addr[j]; dev->dev_addr[j] = rev? bitrev(addr[j]): addr[j];
printk("%c%.2x", (j? ':': ' '), dev->dev_addr[j]); printk("%c%.2x", (j? ':': ' '), dev->dev_addr[j]);
} }
XXDEBUG((", base_addr=%#0lx", dev->base_addr));
printk("\n");
/* Enable chip without interrupts for now */ /* Enable chip without interrupts for now */
bmac_enable_and_reset_chip(dev); bmac_enable_and_reset_chip(dev);
...@@ -1392,15 +1334,15 @@ static void __init bmac_probe1(struct device_node *bmac, int is_bmac_plus) ...@@ -1392,15 +1334,15 @@ static void __init bmac_probe1(struct device_node *bmac, int is_bmac_plus)
bp->is_bmac_plus = is_bmac_plus; bp->is_bmac_plus = is_bmac_plus;
bp->tx_dma = (volatile struct dbdma_regs *) bp->tx_dma = (volatile struct dbdma_regs *)
ioremap(bmac->addrs[1].address, bmac->addrs[1].size); ioremap(macio_resource_start(mdev, 1), macio_resource_len(mdev, 1));
if (!bp->tx_dma) if (!bp->tx_dma)
goto err_out_iounmap; goto err_out_iounmap;
bp->tx_dma_intr = bmac->intrs[1].line; bp->tx_dma_intr = macio_irq(mdev, 1);
bp->rx_dma = (volatile struct dbdma_regs *) bp->rx_dma = (volatile struct dbdma_regs *)
ioremap(bmac->addrs[2].address, bmac->addrs[2].size); ioremap(macio_resource_start(mdev, 2), macio_resource_len(mdev, 2));
if (!bp->rx_dma) if (!bp->rx_dma)
goto err_out_iounmap_tx; goto err_out_iounmap_tx;
bp->rx_dma_intr = bmac->intrs[2].line; bp->rx_dma_intr = macio_irq(mdev, 2);
bp->tx_cmds = (volatile struct dbdma_cmd *) DBDMA_ALIGN(bp + 1); bp->tx_cmds = (volatile struct dbdma_cmd *) DBDMA_ALIGN(bp + 1);
bp->rx_cmds = bp->tx_cmds + N_TX_RING + 1; bp->rx_cmds = bp->tx_cmds + N_TX_RING + 1;
...@@ -1415,14 +1357,14 @@ static void __init bmac_probe1(struct device_node *bmac, int is_bmac_plus) ...@@ -1415,14 +1357,14 @@ static void __init bmac_probe1(struct device_node *bmac, int is_bmac_plus)
printk(KERN_ERR "BMAC: can't get irq %d\n", dev->irq); printk(KERN_ERR "BMAC: can't get irq %d\n", dev->irq);
goto err_out_iounmap_rx; goto err_out_iounmap_rx;
} }
ret = request_irq(bmac->intrs[1].line, bmac_txdma_intr, 0, "BMAC-txdma", dev); ret = request_irq(bp->tx_dma_intr, bmac_txdma_intr, 0, "BMAC-txdma", dev);
if (ret) { if (ret) {
printk(KERN_ERR "BMAC: can't get irq %d\n", bmac->intrs[1].line); printk(KERN_ERR "BMAC: can't get irq %d\n", bp->tx_dma_intr);
goto err_out_irq0; goto err_out_irq0;
} }
ret = request_irq(bmac->intrs[2].line, bmac_rxdma_intr, 0, "BMAC-rxdma", dev); ret = request_irq(bp->rx_dma_intr, bmac_rxdma_intr, 0, "BMAC-rxdma", dev);
if (ret) { if (ret) {
printk(KERN_ERR "BMAC: can't get irq %d\n", bmac->intrs[2].line); printk(KERN_ERR "BMAC: can't get irq %d\n", bp->rx_dma_intr);
goto err_out_irq1; goto err_out_irq1;
} }
...@@ -1430,22 +1372,23 @@ static void __init bmac_probe1(struct device_node *bmac, int is_bmac_plus) ...@@ -1430,22 +1372,23 @@ static void __init bmac_probe1(struct device_node *bmac, int is_bmac_plus)
* re-enabled on open() * re-enabled on open()
*/ */
disable_irq(dev->irq); disable_irq(dev->irq);
pmac_call_feature(PMAC_FTR_BMAC_ENABLE, bp->node, 0, 0); pmac_call_feature(PMAC_FTR_BMAC_ENABLE, macio_get_of_node(bp->mdev), 0, 0);
if (register_netdev(dev) != 0) { if (register_netdev(dev) != 0) {
printk(KERN_ERR "registration failed for BMAC %s\n", printk(KERN_ERR "BMAC: Ethernet registration failed\n");
bmac->full_name);
goto err_out_irq2; goto err_out_irq2;
} }
bp->next_bmac = bmac_devs; printk(KERN_INFO "%s: BMAC%s at", dev->name, (is_bmac_plus? "+": ""));
bmac_devs = dev; XXDEBUG((", base_addr=%#0lx", dev->base_addr));
return; printk("\n");
return 0;
err_out_irq2: err_out_irq2:
free_irq(bmac->intrs[2].line, dev); free_irq(bp->rx_dma_intr, dev);
err_out_irq1: err_out_irq1:
free_irq(bmac->intrs[1].line, dev); free_irq(bp->tx_dma_intr, dev);
err_out_irq0: err_out_irq0:
free_irq(dev->irq, dev); free_irq(dev->irq, dev);
err_out_iounmap_rx: err_out_iounmap_rx:
...@@ -1454,15 +1397,13 @@ static void __init bmac_probe1(struct device_node *bmac, int is_bmac_plus) ...@@ -1454,15 +1397,13 @@ static void __init bmac_probe1(struct device_node *bmac, int is_bmac_plus)
iounmap((void *)bp->tx_dma); iounmap((void *)bp->tx_dma);
err_out_iounmap: err_out_iounmap:
iounmap((void *)dev->base_addr); iounmap((void *)dev->base_addr);
out4: out_release:
release_OF_resource(bp->node, 2); macio_release_resources(mdev);
out3: out_free:
release_OF_resource(bp->node, 1); pmac_call_feature(PMAC_FTR_BMAC_ENABLE, macio_get_of_node(bp->mdev), 0, 0);
out2:
release_OF_resource(bp->node, 0);
out1:
pmac_call_feature(PMAC_FTR_BMAC_ENABLE, bp->node, 0, 0);
free_netdev(dev); free_netdev(dev);
return -ENODEV;
} }
static int bmac_open(struct net_device *dev) static int bmac_open(struct net_device *dev)
...@@ -1520,7 +1461,7 @@ static int bmac_close(struct net_device *dev) ...@@ -1520,7 +1461,7 @@ static int bmac_close(struct net_device *dev)
bp->opened = 0; bp->opened = 0;
disable_irq(dev->irq); disable_irq(dev->irq);
pmac_call_feature(PMAC_FTR_BMAC_ENABLE, bp->node, 0, 0); pmac_call_feature(PMAC_FTR_BMAC_ENABLE, macio_get_of_node(bp->mdev), 0, 0);
return 0; return 0;
} }
...@@ -1649,6 +1590,7 @@ static void dump_dbdma(volatile struct dbdma_cmd *cp,int count) ...@@ -1649,6 +1590,7 @@ static void dump_dbdma(volatile struct dbdma_cmd *cp,int count)
} }
#endif #endif
#if 0
static int static int
bmac_proc_info(char *buffer, char **start, off_t offset, int length) bmac_proc_info(char *buffer, char **start, off_t offset, int length)
{ {
...@@ -1683,46 +1625,86 @@ bmac_proc_info(char *buffer, char **start, off_t offset, int length) ...@@ -1683,46 +1625,86 @@ bmac_proc_info(char *buffer, char **start, off_t offset, int length)
return len; return len;
} }
MODULE_AUTHOR("Randy Gobbel/Paul Mackerras");
MODULE_DESCRIPTION("PowerMac BMAC ethernet driver.");
MODULE_LICENSE("GPL");
static void __exit bmac_cleanup (void)
{
struct bmac_data *bp;
struct net_device *dev;
if (bmac_emergency_rxbuf != NULL) {
kfree(bmac_emergency_rxbuf);
bmac_emergency_rxbuf = NULL;
}
if (bmac_devs == 0)
return;
#ifdef CONFIG_PMAC_PBOOK
pmu_unregister_sleep_notifier(&bmac_sleep_notifier);
#endif #endif
proc_net_remove("bmac");
do { static int __devexit bmac_remove(struct macio_dev *mdev)
dev = bmac_devs; {
bp = (struct bmac_data *) dev->priv; struct net_device *dev = macio_get_drvdata(mdev);
bmac_devs = bp->next_bmac; struct bmac_data *bp = dev->priv;
unregister_netdev(dev); unregister_netdev(dev);
release_OF_resource(bp->node, 0);
release_OF_resource(bp->node, 1);
release_OF_resource(bp->node, 2);
free_irq(dev->irq, dev); free_irq(dev->irq, dev);
free_irq(bp->tx_dma_intr, dev); free_irq(bp->tx_dma_intr, dev);
free_irq(bp->rx_dma_intr, dev); free_irq(bp->rx_dma_intr, dev);
iounmap((void *)dev->base_addr);
iounmap((void *)bp->tx_dma);
iounmap((void *)bp->rx_dma);
macio_release_resources(mdev);
free_netdev(dev); free_netdev(dev);
} while (bmac_devs != NULL);
return 0;
} }
module_init(bmac_probe); static struct of_match bmac_match[] =
module_exit(bmac_cleanup); {
{
.name = "bmac",
.type = OF_ANY_MATCH,
.compatible = OF_ANY_MATCH,
.data = (void *)0,
},
{
.name = OF_ANY_MATCH,
.type = "network",
.compatible = "bmac+",
.data = (void *)1,
},
{},
};
static struct macio_driver bmac_driver =
{
.name = "bmac",
.match_table = bmac_match,
.probe = bmac_probe,
.remove = bmac_remove,
#ifdef CONFIG_PM
.suspend = bmac_suspend,
.resume = bmac_resume,
#endif
};
static int __init bmac_init(void)
{
if (bmac_emergency_rxbuf == NULL) {
bmac_emergency_rxbuf = kmalloc(RX_BUFLEN, GFP_KERNEL);
if (bmac_emergency_rxbuf == NULL) {
printk(KERN_ERR "BMAC: can't allocate emergency RX buffer\n");
return -ENOMEM;
}
}
return macio_register_driver(&bmac_driver);
}
static void __exit bmac_exit(void)
{
macio_unregister_driver(&bmac_driver);
if (bmac_emergency_rxbuf != NULL) {
kfree(bmac_emergency_rxbuf);
bmac_emergency_rxbuf = NULL;
}
}
MODULE_AUTHOR("Randy Gobbel/Paul Mackerras");
MODULE_DESCRIPTION("PowerMac BMAC ethernet driver.");
MODULE_LICENSE("GPL");
module_init(bmac_init);
module_exit(bmac_exit);
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