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 @@
#include <asm/dbdma.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/macio.h>
#include "mace.h"
static struct net_device *mace_devs;
static int port_aaui = -1;
#define N_RX_RING 8
......@@ -61,8 +62,7 @@ struct mace_data {
int timeout_active;
int port_aaui;
int chipid;
struct device_node* of_node;
struct net_device *next_mace;
struct macio_dev *mdev;
spinlock_t lock;
};
......@@ -76,8 +76,6 @@ struct mace_data {
+ (N_RX_RING + NCMDS_TX * N_TX_RING + 3) * sizeof(struct dbdma_cmd))
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_close(struct net_device *dev);
static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev);
......@@ -110,26 +108,19 @@ bitrev(int b)
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 mace_data *mp;
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",
mace->full_name);
return;
return -ENODEV;
}
addr = get_property(mace, "mac-address", NULL);
......@@ -138,48 +129,48 @@ static void __init mace_probe1(struct device_node *mace)
if (addr == NULL) {
printk(KERN_ERR "Can't get mac-address for MACE %s\n",
mace->full_name);
return;
return -ENODEV;
}
}
/*
* lazy allocation - it's a driver-wide thing and it will live until
* the unload, but we don't allocate it until it's needed
* lazy allocate the driver-wide dummy buffer. (Note that we
* never have more than one MACE in the system anyway)
*/
if (dummy_buf == NULL) {
dummy_buf = kmalloc(RX_BUFLEN+2, GFP_KERNEL);
if (dummy_buf == NULL) {
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);
if (!dev)
return;
if (!dev) {
printk(KERN_ERR "MACE: can't allocate ethernet device !\n");
rc = -ENOMEM;
goto err_release;
}
SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &mdev->ofdev.dev);
mp = dev->priv;
mp->of_node = mace;
if (!request_OF_resource(mace, 0, " (mace)")) {
printk(KERN_ERR "MACE: can't request IO resource !\n");
goto out1;
}
if (!request_OF_resource(mace, 1, " (mace tx dma)")) {
printk(KERN_ERR "MACE: can't request TX DMA resource !\n");
goto out2;
mp->mdev = mdev;
macio_set_drvdata(mdev, dev);
dev->base_addr = macio_resource_start(mdev, 0);
mp->mace = (volatile struct mace *)ioremap(dev->base_addr, 0x1000);
if (mp->mace == NULL) {
printk(KERN_ERR "MACE: can't map IO resources !\n");
rc = -ENOMEM;
goto err_free;
}
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;
dev->irq = macio_irq(mdev, 0);
printk(KERN_INFO "%s: MACE at", dev->name);
rev = addr[0] == 0 && addr[1] == 0xA0;
......@@ -194,12 +185,24 @@ static void __init mace_probe1(struct device_node *mace)
mp = (struct mace_data *) dev->priv;
mp->maccc = ENXMT | ENRCV;
mp->tx_dma = (volatile struct dbdma_regs *)
ioremap(mace->addrs[1].address, 0x1000);
mp->tx_dma_intr = mace->intrs[1].line;
ioremap(macio_resource_start(mdev, 1), 0x1000);
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 *)
ioremap(mace->addrs[2].address, 0x1000);
mp->rx_dma_intr = mace->intrs[2].line;
ioremap(macio_resource_start(mdev, 2), 0x1000);
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->rx_cmds = mp->tx_cmds + NCMDS_TX * N_TX_RING + 1;
......@@ -233,43 +236,81 @@ static void __init mace_probe1(struct device_node *mace)
dev->set_multicast_list = mace_set_multicast;
dev->set_mac_address = mace_set_address;
/*
* Most of what is below could be moved to mace_open()
*/
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);
goto out4;
goto err_unmap_rx_dma;
}
if (request_irq(mace->intrs[1].line, mace_txdma_intr, 0, "MACE-txdma",
dev)) {
rc = request_irq(mp->tx_dma_intr, mace_txdma_intr, 0, "MACE-txdma", dev);
if (rc) {
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",
dev)) {
rc = request_irq(mp->rx_dma_intr, mace_rxdma_intr, 0, "MACE-rxdma", dev);
if (rc) {
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;
mace_devs = dev;
return;
out7:
free_irq(mp->rx_dma_intr, dev);
out6:
free_irq(mp->tx_dma_intr, dev);
out5:
rc = register_netdev(dev);
if (rc) {
printk(KERN_ERR "Cannot register net device, aborting.\n");
goto err_free_rx_irq;
}
return 0;
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);
out4:
release_OF_resource(mp->of_node, 2);
out3:
release_OF_resource(mp->of_node, 1);
out2:
release_OF_resource(mp->of_node, 0);
out1:
free_irq(mp->tx_dma_intr, dev);
free_irq(mp->rx_dma_intr, dev);
iounmap((void*)mp->rx_dma);
iounmap((void*)mp->tx_dma);
iounmap((void*)mp->mace);
free_netdev(dev);
macio_release_resources(mdev);
return 0;
}
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)
return IRQ_HANDLED;
}
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");
static struct of_match mace_match[] =
{
{
.name = "mace",
.type = OF_ANY_MATCH,
.compatible = OF_ANY_MATCH
},
{},
};
static void __exit mace_cleanup (void)
static struct macio_driver mace_driver =
{
struct net_device *dev;
struct mace_data *mp;
.name = "mace",
.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);
free_irq(dev->irq, dev);
free_irq(mp->tx_dma_intr, dev);
free_irq(mp->rx_dma_intr, dev);
static int __init mace_init(void)
{
return macio_register_driver(&mace_driver);
}
release_OF_resource(mp->of_node, 0);
release_OF_resource(mp->of_node, 1);
release_OF_resource(mp->of_node, 2);
static void __exit mace_cleanup(void)
{
macio_unregister_driver(&mace_driver);
free_netdev(dev);
}
if (dummy_buf != NULL) {
if (dummy_buf) {
kfree(dummy_buf);
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);
......@@ -40,7 +40,7 @@
#define AIRPORT_IO_LEN (0x1000) /* one page */
struct airport {
struct device_node *node;
struct macio_dev *mdev;
void *vaddr;
int irq_requested;
int ndev_registered;
......@@ -51,7 +51,6 @@ airport_suspend(struct macio_dev *mdev, u32 state)
{
struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev);
struct orinoco_private *priv = dev->priv;
struct airport *card = priv->card;
unsigned long flags;
int err;
......@@ -76,7 +75,7 @@ airport_suspend(struct macio_dev *mdev, u32 state)
orinoco_unlock(priv, &flags);
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;
}
......@@ -86,14 +85,14 @@ airport_resume(struct macio_dev *mdev)
{
struct net_device *dev = dev_get_drvdata(&mdev->ofdev.dev);
struct orinoco_private *priv = dev->priv;
struct airport *card = priv->card;
unsigned long flags;
int err;
printk(KERN_DEBUG "%s: Airport waking up\n", dev->name);
pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, card->node, 0, 1);
mdelay(200);
pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(mdev), 0, 1);
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(HZ/5);
enable_irq(dev->irq);
......@@ -142,15 +141,13 @@ airport_detach(struct macio_dev *mdev)
iounmap(card->vaddr);
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, card->node, 0, 0);
current->state = TASK_UNINTERRUPTIBLE;
pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(mdev), 0, 0);
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(HZ);
dev_set_drvdata(&mdev->ofdev.dev, NULL);
macio_set_drvdata(mdev, NULL);
free_netdev(dev);
return 0;
......@@ -173,11 +170,11 @@ static int airport_hard_reset(struct orinoco_private *priv)
* off. */
disable_irq(dev->irq);
pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, card->node, 0, 0);
current->state = TASK_UNINTERRUPTIBLE;
pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(card->mdev), 0, 0);
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(HZ);
pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, card->node, 0, 1);
current->state = TASK_UNINTERRUPTIBLE;
pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(card->mdev), 0, 1);
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(HZ);
enable_irq(dev->irq);
......@@ -194,10 +191,9 @@ airport_attach(struct macio_dev *mdev, const struct of_match *match)
struct net_device *dev;
struct airport *card;
unsigned long phys_addr;
struct device_node *of_node = mdev->ofdev.node;
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");
return -ENODEV;
}
......@@ -212,27 +208,26 @@ airport_attach(struct macio_dev *mdev, const struct of_match *match)
card = priv->card;
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");
free_netdev(dev);
return -ENODEV;
return -EBUSY;
}
dev->name[0] = '\0'; /* register_netdev will give us an ethX name */
SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &mdev->ofdev.dev);
dev_set_drvdata(&mdev->ofdev.dev, dev);
macio_set_drvdata(mdev, dev);
/* Setup interrupts & base address */
dev->irq = of_node->intrs[0].line;
phys_addr = of_node->addrs[0].address; /* Physical address */
dev->irq = macio_irq(mdev, 0);
phys_addr = macio_resource_start(mdev, 0); /* Physical address */
printk(KERN_DEBUG "Airport at physical address %lx\n", phys_addr);
dev->base_addr = phys_addr;
card->vaddr = ioremap(phys_addr, AIRPORT_IO_LEN);
if (! card->vaddr) {
if (!card->vaddr) {
printk("airport: ioremap() failed\n");
goto failed;
}
......@@ -241,8 +236,8 @@ airport_attach(struct macio_dev *mdev, const struct of_match *match)
HERMES_MEM, HERMES_16BIT_REGSPACING);
/* Power up card */
pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, card->node, 0, 1);
current->state = TASK_UNINTERRUPTIBLE;
pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, macio_get_of_node(mdev), 0, 1);
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(HZ);
/* 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