Commit 050bbb19 authored by David S. Miller's avatar David S. Miller

[NET] sunhme: Convert to new SBUS driver framework.

And make it a real PCI driver too.
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 9e326acf
/* $Id: sunhme.c,v 1.124 2002/01/15 06:25:51 davem Exp $
* sunhme.c: Sparc HME/BigMac 10/100baseT half/full duplex auto switching,
/* sunhme.c: Sparc HME/BigMac 10/100baseT half/full duplex auto switching,
* auto carrier detecting ethernet driver. Also known as the
* "Happy Meal Ethernet" found on SunSwift SBUS cards.
*
* Copyright (C) 1996, 1998, 1999, 2002, 2003 David S. Miller (davem@redhat.com)
* Copyright (C) 1996, 1998, 1999, 2002, 2003,
2006 David S. Miller (davem@davemloft.net)
*
* Changes :
* 2000/11/11 Willy Tarreau <willy AT meta-x.org>
......@@ -47,9 +47,6 @@
#include <asm/oplib.h>
#include <asm/prom.h>
#include <asm/auxio.h>
#ifndef CONFIG_SPARC64
#include <asm/io-unit.h>
#endif
#endif
#include <asm/uaccess.h>
......@@ -66,9 +63,9 @@
#include "sunhme.h"
#define DRV_NAME "sunhme"
#define DRV_VERSION "2.02"
#define DRV_RELDATE "8/24/03"
#define DRV_AUTHOR "David S. Miller (davem@redhat.com)"
#define DRV_VERSION "3.00"
#define DRV_RELDATE "June 23, 2006"
#define DRV_AUTHOR "David S. Miller (davem@davemloft.net)"
static char version[] =
DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " " DRV_AUTHOR "\n";
......@@ -84,8 +81,6 @@ static int macaddr[6];
module_param_array(macaddr, int, NULL, 0);
MODULE_PARM_DESC(macaddr, "Happy Meal MAC address to set");
static struct happy_meal *root_happy_dev;
#ifdef CONFIG_SBUS
static struct quattro *qfe_sbus_list;
#endif
......@@ -182,26 +177,6 @@ static __inline__ void tx_dump_ring(struct happy_meal *hp)
#define DEFAULT_IPG2 4 /* For all modes */
#define DEFAULT_JAMSIZE 4 /* Toe jam */
#if defined(CONFIG_PCI) && defined(MODULE)
/* This happy_pci_ids is declared __initdata because it is only used
as an advisory to depmod. If this is ported to the new PCI interface
where it could be referenced at any time due to hot plugging,
the __initdata reference should be removed. */
static struct pci_device_id happymeal_pci_ids[] = {
{
.vendor = PCI_VENDOR_ID_SUN,
.device = PCI_DEVICE_ID_SUN_HAPPYMEAL,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
},
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(pci, happymeal_pci_ids);
#endif
/* NOTE: In the descriptor writes one _must_ write the address
* member _first_. The card must not be allowed to see
* the updated descriptor flags until the address is
......@@ -2656,6 +2631,17 @@ static void __init quattro_sbus_register_irqs(void)
}
}
}
static void __devexit quattro_sbus_free_irqs(void)
{
struct quattro *qp;
for (qp = qfe_sbus_list; qp != NULL; qp = qp->next) {
struct sbus_dev *sdev = qp->quattro_dev;
free_irq(sdev->irqs[0], qp);
}
}
#endif /* CONFIG_SBUS */
#ifdef CONFIG_PCI
......@@ -2690,8 +2676,9 @@ static struct quattro * __init quattro_pci_find(struct pci_dev *pdev)
#endif /* CONFIG_PCI */
#ifdef CONFIG_SBUS
static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe)
static int __init happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe)
{
struct device_node *dp = sdev->ofdev.node;
struct quattro *qp = NULL;
struct happy_meal *hp;
struct net_device *dev;
......@@ -2714,6 +2701,7 @@ static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe)
if (!dev)
goto err_out;
SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &sdev->ofdev.dev);
if (hme_version_printed++ == 0)
printk(KERN_INFO "%s", version);
......@@ -2729,12 +2717,15 @@ static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe)
for (i = 0; i < 6; i++)
dev->dev_addr[i] = macaddr[i];
macaddr[5]++;
} else if (qfe_slot != -1 &&
prom_getproplen(sdev->prom_node,
"local-mac-address") == 6) {
prom_getproperty(sdev->prom_node, "local-mac-address",
dev->dev_addr, 6);
} else {
unsigned char *addr;
int len;
addr = of_get_property(dp, "local-mac-address", &len);
if (qfe_slot != -1 && addr && len == 6)
memcpy(dev->dev_addr, addr, 6);
else
memcpy(dev->dev_addr, idprom->id_ethaddr, 6);
}
......@@ -2746,9 +2737,8 @@ static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe)
err = -ENODEV;
if (sdev->num_registers != 5) {
printk(KERN_ERR "happymeal: Device does not have 5 regs, it has %d.\n",
printk(KERN_ERR "happymeal: Device needs 5 regs, has %d.\n",
sdev->num_registers);
printk(KERN_ERR "happymeal: Would you like that for here or to go?\n");
goto err_out_free_netdev;
}
......@@ -2762,39 +2752,39 @@ static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe)
hp->gregs = sbus_ioremap(&sdev->resource[0], 0,
GREG_REG_SIZE, "HME Global Regs");
if (!hp->gregs) {
printk(KERN_ERR "happymeal: Cannot map Happy Meal global registers.\n");
printk(KERN_ERR "happymeal: Cannot map global registers.\n");
goto err_out_free_netdev;
}
hp->etxregs = sbus_ioremap(&sdev->resource[1], 0,
ETX_REG_SIZE, "HME TX Regs");
if (!hp->etxregs) {
printk(KERN_ERR "happymeal: Cannot map Happy Meal MAC Transmit registers.\n");
printk(KERN_ERR "happymeal: Cannot map MAC TX registers.\n");
goto err_out_iounmap;
}
hp->erxregs = sbus_ioremap(&sdev->resource[2], 0,
ERX_REG_SIZE, "HME RX Regs");
if (!hp->erxregs) {
printk(KERN_ERR "happymeal: Cannot map Happy Meal MAC Receive registers.\n");
printk(KERN_ERR "happymeal: Cannot map MAC RX registers.\n");
goto err_out_iounmap;
}
hp->bigmacregs = sbus_ioremap(&sdev->resource[3], 0,
BMAC_REG_SIZE, "HME BIGMAC Regs");
if (!hp->bigmacregs) {
printk(KERN_ERR "happymeal: Cannot map Happy Meal BIGMAC registers.\n");
printk(KERN_ERR "happymeal: Cannot map BIGMAC registers.\n");
goto err_out_iounmap;
}
hp->tcvregs = sbus_ioremap(&sdev->resource[4], 0,
TCVR_REG_SIZE, "HME Tranceiver Regs");
if (!hp->tcvregs) {
printk(KERN_ERR "happymeal: Cannot map Happy Meal Tranceiver registers.\n");
printk(KERN_ERR "happymeal: Cannot map TCVR registers.\n");
goto err_out_iounmap;
}
hp->hm_revision = prom_getintdefault(sdev->prom_node, "hm-rev", 0xff);
hp->hm_revision = of_getintprop_default(dp, "hm-rev", 0xff);
if (hp->hm_revision == 0xff)
hp->hm_revision = 0xa0;
......@@ -2808,7 +2798,7 @@ static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe)
hp->happy_flags |= HFLAG_QUATTRO;
/* Get the supported DVMA burst sizes from our Happy SBUS. */
hp->happy_bursts = prom_getintdefault(sdev->bus->prom_node,
hp->happy_bursts = of_getintprop_default(sdev->bus->ofdev.node,
"burst-sizes", 0x00);
hp->happy_block = sbus_alloc_consistent(hp->happy_dev,
......@@ -2872,6 +2862,8 @@ static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe)
goto err_out_free_consistent;
}
dev_set_drvdata(&sdev->ofdev.dev, hp);
if (qfe_slot != -1)
printk(KERN_INFO "%s: Quattro HME slot %d (SBUS) 10/100baseT Ethernet ",
dev->name, qfe_slot);
......@@ -2884,12 +2876,6 @@ static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe)
dev->dev_addr[i], i == 5 ? ' ' : ':');
printk("\n");
/* We are home free at this point, link us in to the happy
* device list.
*/
hp->next_module = root_happy_dev;
root_happy_dev = hp;
return 0;
err_out_free_consistent:
......@@ -3009,7 +2995,8 @@ static void get_hme_mac_nonsparc(struct pci_dev *pdev, unsigned char *dev_addr)
}
#endif /* !(CONFIG_SPARC) */
static int __init happy_meal_pci_init(struct pci_dev *pdev)
static int __devinit happy_meal_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
struct quattro *qp = NULL;
#ifdef CONFIG_SPARC
......@@ -3214,6 +3201,8 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev)
goto err_out_iounmap;
}
dev_set_drvdata(&pdev->dev, hp);
if (!qfe_slot) {
struct pci_dev *qpdev = qp->quattro_dev;
......@@ -3243,12 +3232,6 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev)
printk("\n");
/* We are home free at this point, link us in to the happy
* device list.
*/
hp->next_module = root_happy_dev;
root_happy_dev = hp;
return 0;
err_out_iounmap:
......@@ -3266,107 +3249,88 @@ err_out_clear_quattro:
err_out:
return err;
}
#endif
#ifdef CONFIG_SBUS
static int __init happy_meal_sbus_probe(void)
static void __devexit happy_meal_pci_remove(struct pci_dev *pdev)
{
struct sbus_bus *sbus;
struct sbus_dev *sdev;
int cards = 0;
char model[128];
struct happy_meal *hp = dev_get_drvdata(&pdev->dev);
struct net_device *net_dev = hp->dev;
for_each_sbus(sbus) {
for_each_sbusdev(sdev, sbus) {
char *name = sdev->prom_name;
if (!strcmp(name, "SUNW,hme")) {
cards++;
prom_getstring(sdev->prom_node, "model",
model, sizeof(model));
if (!strcmp(model, "SUNW,sbus-qfe"))
happy_meal_sbus_init(sdev, 1);
else
happy_meal_sbus_init(sdev, 0);
} else if (!strcmp(name, "qfe") ||
!strcmp(name, "SUNW,qfe")) {
cards++;
happy_meal_sbus_init(sdev, 1);
}
}
}
if (cards != 0)
quattro_sbus_register_irqs();
return cards;
unregister_netdev(net_dev);
pci_free_consistent(hp->happy_dev,
PAGE_SIZE,
hp->happy_block,
hp->hblock_dvma);
iounmap(hp->gregs);
pci_release_regions(hp->happy_dev);
free_netdev(net_dev);
dev_set_drvdata(&pdev->dev, NULL);
}
#endif
#ifdef CONFIG_PCI
static int __init happy_meal_pci_probe(void)
{
struct pci_dev *pdev = NULL;
int cards = 0;
static struct pci_device_id happymeal_pci_ids[] = {
{
.vendor = PCI_VENDOR_ID_SUN,
.device = PCI_DEVICE_ID_SUN_HAPPYMEAL,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
},
{ } /* Terminating entry */
};
while ((pdev = pci_find_device(PCI_VENDOR_ID_SUN,
PCI_DEVICE_ID_SUN_HAPPYMEAL, pdev)) != NULL) {
if (pci_enable_device(pdev))
continue;
pci_set_master(pdev);
cards++;
happy_meal_pci_init(pdev);
}
return cards;
MODULE_DEVICE_TABLE(pci, happymeal_pci_ids);
static struct pci_driver hme_pci_driver = {
.name = "hme",
.id_table = happymeal_pci_ids,
.probe = happy_meal_pci_probe,
.remove = __devexit_p(happy_meal_pci_remove),
};
static int __init happy_meal_pci_init(void)
{
return pci_module_init(&hme_pci_driver);
}
#endif
static int __init happy_meal_probe(void)
static void happy_meal_pci_exit(void)
{
static int called = 0;
int cards;
pci_unregister_driver(&hme_pci_driver);
root_happy_dev = NULL;
while (qfe_pci_list) {
struct quattro *qfe = qfe_pci_list;
struct quattro *next = qfe->next;
if (called)
return -ENODEV;
called++;
kfree(qfe);
cards = 0;
#ifdef CONFIG_SBUS
cards += happy_meal_sbus_probe();
#endif
#ifdef CONFIG_PCI
cards += happy_meal_pci_probe();
#endif
if (!cards)
return -ENODEV;
return 0;
qfe_pci_list = next;
}
}
#endif
static void __exit happy_meal_cleanup_module(void)
{
#ifdef CONFIG_SBUS
struct quattro *last_seen_qfe = NULL;
#endif
static int __devinit hme_sbus_probe(struct of_device *dev, const struct of_device_id *match)
{
struct sbus_dev *sdev = to_sbus_device(&dev->dev);
struct device_node *dp = dev->node;
char *model = of_get_property(dp, "model", NULL);
int is_qfe = (match->data != NULL);
while (root_happy_dev) {
struct happy_meal *hp = root_happy_dev;
struct happy_meal *next = root_happy_dev->next_module;
struct net_device *dev = hp->dev;
if (!is_qfe && model && !strcmp(model, "SUNW,sbus-qfe"))
is_qfe = 1;
/* Unregister netdev before unmapping registers as this
* call can end up trying to access those registers.
*/
unregister_netdev(dev);
return happy_meal_sbus_probe_one(sdev, is_qfe);
}
#ifdef CONFIG_SBUS
if (!(hp->happy_flags & HFLAG_PCI)) {
if (hp->happy_flags & HFLAG_QUATTRO) {
if (hp->qfe_parent != last_seen_qfe) {
free_irq(dev->irq, hp->qfe_parent);
last_seen_qfe = hp->qfe_parent;
}
}
static int __devexit hme_sbus_remove(struct of_device *dev)
{
struct happy_meal *hp = dev_get_drvdata(&dev->dev);
struct net_device *net_dev = hp->dev;
unregister_netdevice(net_dev);
/* XXX qfe parent interrupt... */
sbus_iounmap(hp->gregs, GREG_REG_SIZE);
sbus_iounmap(hp->etxregs, ETX_REG_SIZE);
......@@ -3377,25 +3341,54 @@ static void __exit happy_meal_cleanup_module(void)
PAGE_SIZE,
hp->happy_block,
hp->hblock_dvma);
}
#endif
#ifdef CONFIG_PCI
if ((hp->happy_flags & HFLAG_PCI)) {
pci_free_consistent(hp->happy_dev,
PAGE_SIZE,
hp->happy_block,
hp->hblock_dvma);
iounmap(hp->gregs);
pci_release_regions(hp->happy_dev);
}
#endif
free_netdev(dev);
root_happy_dev = next;
}
free_netdev(net_dev);
dev_set_drvdata(&dev->dev, NULL);
return 0;
}
static struct of_device_id hme_sbus_match[] = {
{
.name = "SUNW,hme",
},
{
.name = "SUNW,qfe",
.data = (void *) 1,
},
{
.name = "qfe",
.data = (void *) 1,
},
{},
};
MODULE_DEVICE_TABLE(of, hme_sbus_match);
static struct of_platform_driver hme_sbus_driver = {
.name = "hme",
.match_table = hme_sbus_match,
.probe = hme_sbus_probe,
.remove = __devexit_p(hme_sbus_remove),
};
static int __init happy_meal_sbus_init(void)
{
int err;
err = of_register_driver(&hme_sbus_driver, &sbus_bus_type);
if (!err)
quattro_sbus_register_irqs();
return err;
}
static void happy_meal_sbus_exit(void)
{
of_unregister_driver(&hme_sbus_driver);
quattro_sbus_free_irqs();
/* Now cleanup the quattro lists. */
#ifdef CONFIG_SBUS
while (qfe_sbus_list) {
struct quattro *qfe = qfe_sbus_list;
struct quattro *next = qfe->next;
......@@ -3404,18 +3397,39 @@ static void __exit happy_meal_cleanup_module(void)
qfe_sbus_list = next;
}
}
#endif
#ifdef CONFIG_PCI
while (qfe_pci_list) {
struct quattro *qfe = qfe_pci_list;
struct quattro *next = qfe->next;
kfree(qfe);
static int __init happy_meal_probe(void)
{
int err = 0;
qfe_pci_list = next;
#ifdef CONFIG_SBUS
err = happy_meal_sbus_init();
#endif
#ifdef CONFIG_PCI
if (!err) {
err = happy_meal_pci_init();
#ifdef CONFIG_SBUS
if (err)
happy_meal_sbus_exit();
#endif
}
#endif
return err;
}
static void __exit happy_meal_exit(void)
{
#ifdef CONFIG_SBUS
happy_meal_sbus_exit();
#endif
#ifdef CONFIG_PCI
happy_meal_pci_exit();
#endif
}
module_init(happy_meal_probe);
module_exit(happy_meal_cleanup_module);
module_exit(happy_meal_exit);
......@@ -461,7 +461,6 @@ struct happy_meal {
struct net_device *dev; /* Backpointer */
struct quattro *qfe_parent; /* For Quattro cards */
int qfe_ent; /* Which instance on quattro */
struct happy_meal *next_module;
};
/* Here are the happy flags. */
......
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