Commit e93aa383 authored by Jeff Garzik's avatar Jeff Garzik Committed by Linus Torvalds

[PATCH] Update mac network drivers

This should merge up the final piece of the ppc32/64 saga: the mac
PowerMac MACE and Airport network drivers.

Both of them are ported to the mac-io infrastructure, all probe code
rewritting & cleaned up, better error handling & resource management.
parent c727c2f4
...@@ -20,9 +20,10 @@ ...@@ -20,9 +20,10 @@
#include <asm/dbdma.h> #include <asm/dbdma.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
#include <asm/macio.h>
#include "mace.h" #include "mace.h"
static struct net_device *mace_devs;
static int port_aaui = -1; static int port_aaui = -1;
#define N_RX_RING 8 #define N_RX_RING 8
...@@ -61,8 +62,7 @@ struct mace_data { ...@@ -61,8 +62,7 @@ struct mace_data {
int timeout_active; int timeout_active;
int port_aaui; int port_aaui;
int chipid; int chipid;
struct device_node* of_node; struct macio_dev *mdev;
struct net_device *next_mace;
spinlock_t lock; spinlock_t lock;
}; };
...@@ -76,8 +76,6 @@ struct mace_data { ...@@ -76,8 +76,6 @@ struct mace_data {
+ (N_RX_RING + NCMDS_TX * N_TX_RING + 3) * sizeof(struct dbdma_cmd)) + (N_RX_RING + NCMDS_TX * N_TX_RING + 3) * sizeof(struct dbdma_cmd))
static int bitrev(int); static int bitrev(int);
static int mace_probe(void);
static void mace_probe1(struct device_node *mace);
static int mace_open(struct net_device *dev); static int mace_open(struct net_device *dev);
static int mace_close(struct net_device *dev); static int mace_close(struct net_device *dev);
static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev); static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev);
...@@ -110,26 +108,19 @@ bitrev(int b) ...@@ -110,26 +108,19 @@ bitrev(int b)
return d; return d;
} }
static int __init mace_probe(void)
{
struct device_node *mace;
for (mace = find_devices("mace"); mace != NULL; mace = mace->next)
mace_probe1(mace);
return mace_devs? 0: -ENODEV;
}
static void __init mace_probe1(struct device_node *mace) static int __devinit mace_probe(struct macio_dev *mdev, const struct of_match *match)
{ {
int j, rev; struct device_node *mace = macio_get_of_node(mdev);
struct net_device *dev; struct net_device *dev;
struct mace_data *mp; struct mace_data *mp;
unsigned char *addr; unsigned char *addr;
int j, rev, rc = -EBUSY;
if (mace->n_addrs != 3 || mace->n_intrs != 3) { if (macio_resource_count(mdev) != 3 || macio_irq_count(mdev) != 3) {
printk(KERN_ERR "can't use MACE %s: need 3 addrs and 3 irqs\n", printk(KERN_ERR "can't use MACE %s: need 3 addrs and 3 irqs\n",
mace->full_name); mace->full_name);
return; return -ENODEV;
} }
addr = get_property(mace, "mac-address", NULL); addr = get_property(mace, "mac-address", NULL);
...@@ -138,48 +129,48 @@ static void __init mace_probe1(struct device_node *mace) ...@@ -138,48 +129,48 @@ static void __init mace_probe1(struct device_node *mace)
if (addr == NULL) { if (addr == NULL) {
printk(KERN_ERR "Can't get mac-address for MACE %s\n", printk(KERN_ERR "Can't get mac-address for MACE %s\n",
mace->full_name); mace->full_name);
return; return -ENODEV;
} }
} }
/* /*
* lazy allocation - it's a driver-wide thing and it will live until * lazy allocate the driver-wide dummy buffer. (Note that we
* the unload, but we don't allocate it until it's needed * never have more than one MACE in the system anyway)
*/ */
if (dummy_buf == NULL) { if (dummy_buf == NULL) {
dummy_buf = kmalloc(RX_BUFLEN+2, GFP_KERNEL); dummy_buf = kmalloc(RX_BUFLEN+2, GFP_KERNEL);
if (dummy_buf == NULL) { if (dummy_buf == NULL) {
printk(KERN_ERR "MACE: couldn't allocate dummy buffer\n"); printk(KERN_ERR "MACE: couldn't allocate dummy buffer\n");
return; return -ENOMEM;
} }
} }
if (macio_request_resources(mdev, "mace")) {
printk(KERN_ERR "MACE: can't request IO resources !\n");
return -EBUSY;
}
dev = alloc_etherdev(PRIV_BYTES); dev = alloc_etherdev(PRIV_BYTES);
if (!dev) if (!dev) {
return; printk(KERN_ERR "MACE: can't allocate ethernet device !\n");
rc = -ENOMEM;
goto err_release;
}
SET_MODULE_OWNER(dev); SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &mdev->ofdev.dev);
mp = dev->priv; mp = dev->priv;
mp->of_node = mace; mp->mdev = mdev;
macio_set_drvdata(mdev, dev);
if (!request_OF_resource(mace, 0, " (mace)")) {
printk(KERN_ERR "MACE: can't request IO resource !\n"); dev->base_addr = macio_resource_start(mdev, 0);
goto out1; mp->mace = (volatile struct mace *)ioremap(dev->base_addr, 0x1000);
} if (mp->mace == NULL) {
if (!request_OF_resource(mace, 1, " (mace tx dma)")) { printk(KERN_ERR "MACE: can't map IO resources !\n");
printk(KERN_ERR "MACE: can't request TX DMA resource !\n"); rc = -ENOMEM;
goto out2; goto err_free;
} }
dev->irq = macio_irq(mdev, 0);
if (!request_OF_resource(mace, 2, " (mace tx dma)")) {
printk(KERN_ERR "MACE: can't request RX DMA resource !\n");
goto out3;
}
dev->base_addr = mace->addrs[0].address;
mp->mace = (volatile struct mace *)
ioremap(mace->addrs[0].address, 0x1000);
dev->irq = mace->intrs[0].line;
printk(KERN_INFO "%s: MACE at", dev->name); printk(KERN_INFO "%s: MACE at", dev->name);
rev = addr[0] == 0 && addr[1] == 0xA0; rev = addr[0] == 0 && addr[1] == 0xA0;
...@@ -194,12 +185,24 @@ static void __init mace_probe1(struct device_node *mace) ...@@ -194,12 +185,24 @@ static void __init mace_probe1(struct device_node *mace)
mp = (struct mace_data *) dev->priv; mp = (struct mace_data *) dev->priv;
mp->maccc = ENXMT | ENRCV; mp->maccc = ENXMT | ENRCV;
mp->tx_dma = (volatile struct dbdma_regs *) mp->tx_dma = (volatile struct dbdma_regs *)
ioremap(mace->addrs[1].address, 0x1000); ioremap(macio_resource_start(mdev, 1), 0x1000);
mp->tx_dma_intr = mace->intrs[1].line; if (mp->tx_dma == NULL) {
printk(KERN_ERR "MACE: can't map TX DMA resources !\n");
rc = -ENOMEM;
goto err_unmap_io;
}
mp->tx_dma_intr = macio_irq(mdev, 1);
mp->rx_dma = (volatile struct dbdma_regs *) mp->rx_dma = (volatile struct dbdma_regs *)
ioremap(mace->addrs[2].address, 0x1000); ioremap(macio_resource_start(mdev, 2), 0x1000);
mp->rx_dma_intr = mace->intrs[2].line; if (mp->rx_dma == NULL) {
printk(KERN_ERR "MACE: can't map RX DMA resources !\n");
rc = -ENOMEM;
goto err_unmap_tx_dma;
}
mp->rx_dma_intr = macio_irq(mdev, 2);;
mp->tx_cmds = (volatile struct dbdma_cmd *) DBDMA_ALIGN(mp + 1); mp->tx_cmds = (volatile struct dbdma_cmd *) DBDMA_ALIGN(mp + 1);
mp->rx_cmds = mp->tx_cmds + NCMDS_TX * N_TX_RING + 1; mp->rx_cmds = mp->tx_cmds + NCMDS_TX * N_TX_RING + 1;
...@@ -233,43 +236,81 @@ static void __init mace_probe1(struct device_node *mace) ...@@ -233,43 +236,81 @@ static void __init mace_probe1(struct device_node *mace)
dev->set_multicast_list = mace_set_multicast; dev->set_multicast_list = mace_set_multicast;
dev->set_mac_address = mace_set_address; dev->set_mac_address = mace_set_address;
/*
* Most of what is below could be moved to mace_open()
*/
mace_reset(dev); mace_reset(dev);
if (request_irq(dev->irq, mace_interrupt, 0, "MACE", dev)) { rc = request_irq(dev->irq, mace_interrupt, 0, "MACE", dev);
if (rc) {
printk(KERN_ERR "MACE: can't get irq %d\n", dev->irq); printk(KERN_ERR "MACE: can't get irq %d\n", dev->irq);
goto out4; goto err_unmap_rx_dma;
} }
if (request_irq(mace->intrs[1].line, mace_txdma_intr, 0, "MACE-txdma", rc = request_irq(mp->tx_dma_intr, mace_txdma_intr, 0, "MACE-txdma", dev);
dev)) { if (rc) {
printk(KERN_ERR "MACE: can't get irq %d\n", mace->intrs[1].line); printk(KERN_ERR "MACE: can't get irq %d\n", mace->intrs[1].line);
goto out5; goto err_free_irq;
} }
if (request_irq(mace->intrs[2].line, mace_rxdma_intr, 0, "MACE-rxdma", rc = request_irq(mp->rx_dma_intr, mace_rxdma_intr, 0, "MACE-rxdma", dev);
dev)) { if (rc) {
printk(KERN_ERR "MACE: can't get irq %d\n", mace->intrs[2].line); printk(KERN_ERR "MACE: can't get irq %d\n", mace->intrs[2].line);
goto out6; goto err_free_tx_irq;
} }
if (register_netdev(dev) != 0)
goto out7;
mp->next_mace = mace_devs; rc = register_netdev(dev);
mace_devs = dev; if (rc) {
return; printk(KERN_ERR "Cannot register net device, aborting.\n");
goto err_free_rx_irq;
out7: }
free_irq(mp->rx_dma_intr, dev);
out6: return 0;
free_irq(mp->tx_dma_intr, dev);
out5: err_free_rx_irq:
free_irq(macio_irq(mdev, 2), dev);
err_free_tx_irq:
free_irq(macio_irq(mdev, 1), dev);
err_free_irq:
free_irq(macio_irq(mdev, 0), dev);
err_unmap_rx_dma:
iounmap((void*)mp->rx_dma);
err_unmap_tx_dma:
iounmap((void*)mp->tx_dma);
err_unmap_io:
iounmap((void*)mp->mace);
err_free:
free_netdev(dev);
err_release:
macio_release_resources(mdev);
return rc;
}
static int __devexit mace_remove(struct macio_dev *mdev)
{
struct net_device *dev = macio_get_drvdata(mdev);
struct mace_data *mp;
BUG_ON(dev == NULL);
macio_set_drvdata(mdev, NULL);
mp = dev->priv;
unregister_netdev(dev);
free_irq(dev->irq, dev); free_irq(dev->irq, dev);
out4: free_irq(mp->tx_dma_intr, dev);
release_OF_resource(mp->of_node, 2); free_irq(mp->rx_dma_intr, dev);
out3:
release_OF_resource(mp->of_node, 1); iounmap((void*)mp->rx_dma);
out2: iounmap((void*)mp->tx_dma);
release_OF_resource(mp->of_node, 0); iounmap((void*)mp->mace);
out1:
free_netdev(dev); free_netdev(dev);
macio_release_resources(mdev);
return 0;
} }
static void dbdma_reset(volatile struct dbdma_regs *dma) static void dbdma_reset(volatile struct dbdma_regs *dma)
...@@ -967,37 +1008,45 @@ static irqreturn_t mace_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs) ...@@ -967,37 +1008,45 @@ static irqreturn_t mace_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
MODULE_AUTHOR("Paul Mackerras"); static struct of_match mace_match[] =
MODULE_DESCRIPTION("PowerMac MACE driver."); {
MODULE_PARM(port_aaui, "i"); {
MODULE_PARM_DESC(port_aaui, "MACE uses AAUI port (0-1)"); .name = "mace",
MODULE_LICENSE("GPL"); .type = OF_ANY_MATCH,
.compatible = OF_ANY_MATCH
},
{},
};
static void __exit mace_cleanup (void) static struct macio_driver mace_driver =
{ {
struct net_device *dev; .name = "mace",
struct mace_data *mp; .match_table = mace_match,
.probe = mace_probe,
.remove = mace_remove,
};
while ((dev = mace_devs) != 0) {
mp = (struct mace_data *) mace_devs->priv;
mace_devs = mp->next_mace;
unregister_netdev(dev); static int __init mace_init(void)
free_irq(dev->irq, dev); {
free_irq(mp->tx_dma_intr, dev); return macio_register_driver(&mace_driver);
free_irq(mp->rx_dma_intr, dev); }
release_OF_resource(mp->of_node, 0); static void __exit mace_cleanup(void)
release_OF_resource(mp->of_node, 1); {
release_OF_resource(mp->of_node, 2); macio_unregister_driver(&mace_driver);
free_netdev(dev); if (dummy_buf) {
}
if (dummy_buf != NULL) {
kfree(dummy_buf); kfree(dummy_buf);
dummy_buf = NULL; dummy_buf = NULL;
} }
} }
module_init(mace_probe); MODULE_AUTHOR("Paul Mackerras");
MODULE_DESCRIPTION("PowerMac MACE driver.");
MODULE_PARM(port_aaui, "i");
MODULE_PARM_DESC(port_aaui, "MACE uses AAUI port (0-1)");
MODULE_LICENSE("GPL");
module_init(mace_init);
module_exit(mace_cleanup); module_exit(mace_cleanup);
...@@ -40,7 +40,7 @@ ...@@ -40,7 +40,7 @@
#define AIRPORT_IO_LEN (0x1000) /* one page */ #define AIRPORT_IO_LEN (0x1000) /* one page */
struct airport { struct airport {
struct device_node *node; struct macio_dev *mdev;
void *vaddr; void *vaddr;
int irq_requested; int irq_requested;
int ndev_registered; int ndev_registered;
...@@ -51,7 +51,6 @@ airport_suspend(struct macio_dev *mdev, u32 state) ...@@ -51,7 +51,6 @@ airport_suspend(struct macio_dev *mdev, u32 state)
{ {
struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev); struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev);
struct orinoco_private *priv = dev->priv; struct orinoco_private *priv = dev->priv;
struct airport *card = priv->card;
unsigned long flags; unsigned long flags;
int err; int err;
...@@ -76,7 +75,7 @@ airport_suspend(struct macio_dev *mdev, u32 state) ...@@ -76,7 +75,7 @@ airport_suspend(struct macio_dev *mdev, u32 state)
orinoco_unlock(priv, &flags); orinoco_unlock(priv, &flags);
disable_irq(dev->irq); disable_irq(dev->irq);
pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, card->node, 0, 0); pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(mdev), 0, 0);
return 0; return 0;
} }
...@@ -86,14 +85,14 @@ airport_resume(struct macio_dev *mdev) ...@@ -86,14 +85,14 @@ airport_resume(struct macio_dev *mdev)
{ {
struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev); struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev);
struct orinoco_private *priv = dev->priv; struct orinoco_private *priv = dev->priv;
struct airport *card = priv->card;
unsigned long flags; unsigned long flags;
int err; int err;
printk(KERN_DEBUG "%s: Airport waking up\n", dev->name); printk(KERN_DEBUG "%s: Airport waking up\n", dev->name);
pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, card->node, 0, 1); pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(mdev), 0, 1);
mdelay(200); set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(HZ/5);
enable_irq(dev->irq); enable_irq(dev->irq);
...@@ -142,15 +141,13 @@ airport_detach(struct macio_dev *mdev) ...@@ -142,15 +141,13 @@ airport_detach(struct macio_dev *mdev)
iounmap(card->vaddr); iounmap(card->vaddr);
card->vaddr = 0; card->vaddr = 0;
dev->base_addr = 0; macio_release_resource(mdev, 0);
release_OF_resource(card->node, 0); pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(mdev), 0, 0);
set_current_state(TASK_UNINTERRUPTIBLE);
pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, card->node, 0, 0);
current->state = TASK_UNINTERRUPTIBLE;
schedule_timeout(HZ); schedule_timeout(HZ);
dev_set_drvdata(&mdev->ofdev.dev, NULL); macio_set_drvdata(mdev, NULL);
free_netdev(dev); free_netdev(dev);
return 0; return 0;
...@@ -173,11 +170,11 @@ static int airport_hard_reset(struct orinoco_private *priv) ...@@ -173,11 +170,11 @@ static int airport_hard_reset(struct orinoco_private *priv)
* off. */ * off. */
disable_irq(dev->irq); disable_irq(dev->irq);
pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, card->node, 0, 0); pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(card->mdev), 0, 0);
current->state = TASK_UNINTERRUPTIBLE; set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(HZ); schedule_timeout(HZ);
pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, card->node, 0, 1); pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(card->mdev), 0, 1);
current->state = TASK_UNINTERRUPTIBLE; set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(HZ); schedule_timeout(HZ);
enable_irq(dev->irq); enable_irq(dev->irq);
...@@ -194,10 +191,9 @@ airport_attach(struct macio_dev *mdev, const struct of_match *match) ...@@ -194,10 +191,9 @@ airport_attach(struct macio_dev *mdev, const struct of_match *match)
struct net_device *dev; struct net_device *dev;
struct airport *card; struct airport *card;
unsigned long phys_addr; unsigned long phys_addr;
struct device_node *of_node = mdev->ofdev.node;
hermes_t *hw; hermes_t *hw;
if (of_node->n_addrs < 1 || of_node->n_intrs < 1) { if (macio_resource_count(mdev) < 1 || macio_irq_count(mdev) < 1) {
printk(KERN_ERR "airport: wrong interrupt/addresses in OF tree\n"); printk(KERN_ERR "airport: wrong interrupt/addresses in OF tree\n");
return -ENODEV; return -ENODEV;
} }
...@@ -212,27 +208,26 @@ airport_attach(struct macio_dev *mdev, const struct of_match *match) ...@@ -212,27 +208,26 @@ airport_attach(struct macio_dev *mdev, const struct of_match *match)
card = priv->card; card = priv->card;
hw = &priv->hw; hw = &priv->hw;
card->node = of_node; card->mdev = mdev;
if (! request_OF_resource(of_node, 0, " (airport)")) { if (macio_request_resource(mdev, 0, "airport")) {
printk(KERN_ERR "airport: can't request IO resource !\n"); printk(KERN_ERR "airport: can't request IO resource !\n");
free_netdev(dev); free_netdev(dev);
return -ENODEV; return -EBUSY;
} }
dev->name[0] = '\0'; /* register_netdev will give us an ethX name */
SET_MODULE_OWNER(dev); SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &mdev->ofdev.dev); SET_NETDEV_DEV(dev, &mdev->ofdev.dev);
dev_set_drvdata(&mdev->ofdev.dev, dev); macio_set_drvdata(mdev, dev);
/* Setup interrupts & base address */ /* Setup interrupts & base address */
dev->irq = of_node->intrs[0].line; dev->irq = macio_irq(mdev, 0);
phys_addr = of_node->addrs[0].address; /* Physical address */ phys_addr = macio_resource_start(mdev, 0); /* Physical address */
printk(KERN_DEBUG "Airport at physical address %lx\n", phys_addr); printk(KERN_DEBUG "Airport at physical address %lx\n", phys_addr);
dev->base_addr = phys_addr; dev->base_addr = phys_addr;
card->vaddr = ioremap(phys_addr, AIRPORT_IO_LEN); card->vaddr = ioremap(phys_addr, AIRPORT_IO_LEN);
if (! card->vaddr) { if (!card->vaddr) {
printk("airport: ioremap() failed\n"); printk("airport: ioremap() failed\n");
goto failed; goto failed;
} }
...@@ -241,8 +236,8 @@ airport_attach(struct macio_dev *mdev, const struct of_match *match) ...@@ -241,8 +236,8 @@ airport_attach(struct macio_dev *mdev, const struct of_match *match)
HERMES_MEM, HERMES_16BIT_REGSPACING); HERMES_MEM, HERMES_16BIT_REGSPACING);
/* Power up card */ /* Power up card */
pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, card->node, 0, 1); pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(mdev), 0, 1);
current->state = TASK_UNINTERRUPTIBLE; set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(HZ); schedule_timeout(HZ);
/* Reset it before we get the interrupt */ /* Reset it before we get the interrupt */
......
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