-/* $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>
* argument : macaddr=0x00,0x10,0x20,0x30,0x40,0x50
*/
-static char version[] =
- "sunhme.c:v2.02 24/Aug/2003 David S. Miller (davem@redhat.com)\n";
-
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
+#include <linux/mm.h>
+#include <linux/bitops.h>
#include <asm/system.h>
-#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <asm/byteorder.h>
-#ifdef __sparc__
+#ifdef CONFIG_SPARC
#include <asm/idprom.h>
#include <asm/sbus.h>
#include <asm/openprom.h>
#include <asm/oplib.h>
+#include <asm/prom.h>
#include <asm/auxio.h>
-#ifndef __sparc_v9__
-#include <asm/io-unit.h>
-#endif
#endif
#include <asm/uaccess.h>
#ifdef CONFIG_PCI
#include <linux/pci.h>
-#ifdef __sparc__
+#ifdef CONFIG_SPARC
#include <asm/pbm.h>
#endif
#endif
#include "sunhme.h"
+#define DRV_NAME "sunhme"
+#define DRV_VERSION "3.00"
+#define DRV_RELDATE "June 23, 2006"
+#define DRV_AUTHOR "David S. Miller (davem@davemloft.net)"
-#define DRV_NAME "sunhme"
+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 HappyMealEthernet(HME) 10/100baseT ethernet driver");
+MODULE_LICENSE("GPL");
static int macaddr[6];
/* accept MAC address of the form macaddr=0x08,0x00,0x20,0x30,0x40,0x50 */
-MODULE_PARM(macaddr, "6i");
+module_param_array(macaddr, int, NULL, 0);
MODULE_PARM_DESC(macaddr, "Happy Meal MAC address to set");
-MODULE_LICENSE("GPL");
-
-static struct happy_meal *root_happy_dev;
#ifdef CONFIG_SBUS
static struct quattro *qfe_sbus_list;
#define DEFAULT_IPG2 4 /* For all modes */
#define DEFAULT_JAMSIZE 4 /* Toe jam */
-#ifdef CONFIG_PCI
-/* 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. */
-
-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
unsigned short value)
{
int tries = TCVR_WRITE_TRIES;
-
+
ASD(("happy_meal_tcvr_write: reg=0x%02x value=%04x\n", reg, value));
/* Welcome to Sun Microsystems, can I take your order please? */
* flags, thus:
*
* skb->csum = rxd->rx_flags & 0xffff;
- * skb->ip_summed = CHECKSUM_HW;
+ * skb->ip_summed = CHECKSUM_COMPLETE;
*
* before sending off the skb to the protocols, and we are good as gold.
*/
HMD(("happy_meal_init: old[%08x] bursts<",
hme_read32(hp, gregs + GREG_CFG)));
-#ifndef __sparc__
+#ifndef CONFIG_SPARC
/* It is always PCI and can handle 64byte bursts. */
hme_write32(hp, gregs + GREG_CFG, GREG_CFG_BURST64);
#else
HMD(("XXX>"));
hme_write32(hp, gregs + GREG_CFG, 0);
}
-#endif /* __sparc__ */
+#endif /* CONFIG_SPARC */
/* Turn off interrupts we do not want to hear. */
HMD((", enable global interrupts, "));
static int happy_meal_is_not_so_happy(struct happy_meal *hp, u32 status)
{
int reset = 0;
-
+
/* Only print messages for non-counter related interrupts. */
if (status & (GREG_STAT_STSTERR | GREG_STAT_TFIFO_UND |
GREG_STAT_MAXPKTERR | GREG_STAT_RXERR |
/* This card is _fucking_ hot... */
skb->csum = ntohs(csum ^ 0xffff);
- skb->ip_summed = CHECKSUM_HW;
+ skb->ip_summed = CHECKSUM_COMPLETE;
RXD(("len=%d csum=%4x]", len, csum));
skb->protocol = eth_type_trans(skb, dev);
RXD((">"));
}
-static irqreturn_t happy_meal_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t happy_meal_interrupt(int irq, void *dev_id)
{
- struct net_device *dev = (struct net_device *) dev_id;
- struct happy_meal *hp = dev->priv;
+ struct net_device *dev = dev_id;
+ struct happy_meal *hp = netdev_priv(dev);
u32 happy_status = hme_read32(hp, hp->gregs + GREG_STAT);
HMD(("happy_meal_interrupt: status=%08x ", happy_status));
}
#ifdef CONFIG_SBUS
-static irqreturn_t quattro_sbus_interrupt(int irq, void *cookie, struct pt_regs *ptregs)
+static irqreturn_t quattro_sbus_interrupt(int irq, void *cookie)
{
struct quattro *qp = (struct quattro *) cookie;
int i;
*/
if ((hp->happy_flags & (HFLAG_QUATTRO|HFLAG_PCI)) != HFLAG_QUATTRO) {
if (request_irq(dev->irq, &happy_meal_interrupt,
- SA_SHIRQ, dev->name, (void *)dev)) {
+ IRQF_SHARED, dev->name, (void *)dev)) {
HMD(("EAGAIN\n"));
-#ifdef __sparc__
- printk(KERN_ERR "happy_meal(SBUS): Can't order irq %s to go.\n",
- __irq_itoa(dev->irq));
-#else
printk(KERN_ERR "happy_meal(SBUS): Can't order irq %d to go.\n",
dev->irq);
-#endif
return -EAGAIN;
}
u32 tx_flags;
tx_flags = TXFLAG_OWN;
- if (skb->ip_summed == CHECKSUM_HW) {
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
u32 csum_start_off, csum_stuff_off;
csum_start_off = (u32) (skb->h.raw - skb->data);
- csum_stuff_off = (u32) ((skb->h.raw + skb->csum) - skb->data);
+ csum_stuff_off = csum_start_off + skb->csum_offset;
tx_flags = (TXFLAG_OWN | TXFLAG_CSENABLE |
((csum_start_off << 14) & TXFLAG_CSBUFBEGIN) |
return (hp->sw_bmsr & BMSR_LSTATUS);
}
-static struct ethtool_ops hme_ethtool_ops = {
+static const struct ethtool_ops hme_ethtool_ops = {
.get_settings = hme_get_settings,
.set_settings = hme_set_settings,
.get_drvinfo = hme_get_drvinfo,
static int hme_version_printed;
#ifdef CONFIG_SBUS
-void __init quattro_get_ranges(struct quattro *qp)
+void __devinit quattro_get_ranges(struct quattro *qp)
{
struct sbus_dev *sdev = qp->quattro_dev;
int err;
qp->nranges = (err / sizeof(struct linux_prom_ranges));
}
-static void __init quattro_apply_ranges(struct quattro *qp, struct happy_meal *hp)
+static void __devinit quattro_apply_ranges(struct quattro *qp, struct happy_meal *hp)
{
struct sbus_dev *sdev = hp->happy_dev;
int rng;
*
* Return NULL on failure.
*/
-static struct quattro * __init quattro_sbus_find(struct sbus_dev *goal_sdev)
+static struct quattro * __devinit quattro_sbus_find(struct sbus_dev *goal_sdev)
{
- struct sbus_bus *sbus;
struct sbus_dev *sdev;
struct quattro *qp;
int i;
- if (qfe_sbus_list == NULL)
- goto found;
-
for (qp = qfe_sbus_list; qp != NULL; qp = qp->next) {
for (i = 0, sdev = qp->quattro_dev;
(sdev != NULL) && (i < 4);
return qp;
}
}
- for_each_sbus(sbus) {
- for_each_sbusdev(sdev, sbus) {
- if (sdev == goal_sdev)
- goto found;
- }
- }
- /* Cannot find quattro parent, fail. */
- return NULL;
-
-found:
qp = kmalloc(sizeof(struct quattro), GFP_KERNEL);
if (qp != NULL) {
int i;
err = request_irq(sdev->irqs[0],
quattro_sbus_interrupt,
- SA_SHIRQ, "Quattro",
+ IRQF_SHARED, "Quattro",
qp);
if (err != 0) {
printk(KERN_ERR "Quattro: Fatal IRQ registery error %d.\n", err);
}
}
}
+
+static void 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
#endif /* CONFIG_PCI */
#ifdef CONFIG_SBUS
-static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe)
+static int __devinit 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;
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);
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 {
- memcpy(dev->dev_addr, idprom->id_ethaddr, 6);
+ 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);
}
hp = dev->priv;
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;
}
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;
hp->happy_flags |= HFLAG_QUATTRO;
/* Get the supported DVMA burst sizes from our Happy SBUS. */
- hp->happy_bursts = prom_getintdefault(sdev->bus->prom_node,
- "burst-sizes", 0x00);
+ hp->happy_bursts = of_getintprop_default(sdev->bus->ofdev.node,
+ "burst-sizes", 0x00);
hp->happy_block = sbus_alloc_consistent(hp->happy_dev,
PAGE_SIZE,
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);
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:
#endif
#ifdef CONFIG_PCI
-#ifndef __sparc__
+#ifndef CONFIG_SPARC
static int is_quattro_p(struct pci_dev *pdev)
{
struct pci_dev *busdev = pdev->bus->self;
}
/* Fetch MAC address from vital product data of PCI ROM. */
-static void find_eth_addr_in_vpd(void *rom_base, int len, int index, unsigned char *dev_addr)
+static int find_eth_addr_in_vpd(void __iomem *rom_base, int len, int index, unsigned char *dev_addr)
{
int this_offset;
for (this_offset = 0x20; this_offset < len; this_offset++) {
- void *p = rom_base + this_offset;
+ void __iomem *p = rom_base + this_offset;
if (readb(p + 0) != 0x90 ||
readb(p + 1) != 0x00 ||
for (i = 0; i < 6; i++)
dev_addr[i] = readb(p + i);
- break;
+ return 1;
}
index--;
}
+ return 0;
}
static void get_hme_mac_nonsparc(struct pci_dev *pdev, unsigned char *dev_addr)
{
- u32 rom_reg_orig;
- void *p;
- int index;
+ size_t size;
+ void __iomem *p = pci_map_rom(pdev, &size);
- index = 0;
- if (is_quattro_p(pdev))
- index = PCI_SLOT(pdev->devfn);
+ if (p) {
+ int index = 0;
+ int found;
- if (pdev->resource[PCI_ROM_RESOURCE].parent == NULL) {
- if (pci_assign_resource(pdev, PCI_ROM_RESOURCE) < 0)
- goto use_random;
- }
+ if (is_quattro_p(pdev))
+ index = PCI_SLOT(pdev->devfn);
- pci_read_config_dword(pdev, pdev->rom_base_reg, &rom_reg_orig);
- pci_write_config_dword(pdev, pdev->rom_base_reg,
- rom_reg_orig | PCI_ROM_ADDRESS_ENABLE);
-
- p = ioremap(pci_resource_start(pdev, PCI_ROM_RESOURCE), (64 * 1024));
- if (p != NULL && readb(p) == 0x55 && readb(p + 1) == 0xaa)
- find_eth_addr_in_vpd(p, (64 * 1024), index, dev_addr);
-
- if (p != NULL)
- iounmap(p);
-
- pci_write_config_dword(pdev, pdev->rom_base_reg, rom_reg_orig);
- return;
+ found = readb(p) == 0x55 &&
+ readb(p + 1) == 0xaa &&
+ find_eth_addr_in_vpd(p, (64 * 1024), index, dev_addr);
+ pci_unmap_rom(pdev, p);
+ if (found)
+ return;
+ }
-use_random:
/* Sun MAC prefix then 3 random bytes. */
dev_addr[0] = 0x08;
dev_addr[1] = 0x00;
get_random_bytes(&dev_addr[3], 3);
return;
}
-#endif /* !(__sparc__) */
+#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 __sparc__
+#ifdef CONFIG_SPARC
struct pcidev_cookie *pcp;
- int node;
#endif
struct happy_meal *hp;
struct net_device *dev;
int err;
/* Now make sure pci_dev cookie is there. */
-#ifdef __sparc__
+#ifdef CONFIG_SPARC
pcp = pdev->sysdata;
- if (pcp == NULL || pcp->prom_node == -1) {
+ if (pcp == NULL) {
printk(KERN_ERR "happymeal(PCI): Some PCI device info missing\n");
return -ENODEV;
}
- node = pcp->prom_node;
-
- prom_getstring(node, "name", prom_name, sizeof(prom_name));
+
+ strcpy(prom_name, pcp->prom_node->name);
#else
if (is_quattro_p(pdev))
strcpy(prom_name, "SUNW,qfe");
#endif
err = -ENODEV;
+
+ if (pci_enable_device(pdev))
+ goto err_out;
+ pci_set_master(pdev);
+
if (!strcmp(prom_name, "SUNW,qfe") || !strcmp(prom_name, "qfe")) {
qp = quattro_pci_find(pdev);
if (qp == NULL)
hp->qfe_parent = qp;
hp->qfe_ent = qfe_slot;
qp->happy_meals[qfe_slot] = dev;
- }
+ }
hpreg_res = pci_resource_start(pdev, 0);
err = -ENODEV;
dev->dev_addr[i] = macaddr[i];
macaddr[5]++;
} else {
-#ifdef __sparc__
+#ifdef CONFIG_SPARC
+ unsigned char *addr;
+ int len;
+
if (qfe_slot != -1 &&
- prom_getproplen(node, "local-mac-address") == 6) {
- prom_getproperty(node, "local-mac-address",
- dev->dev_addr, 6);
+ (addr = of_get_property(pcp->prom_node,
+ "local-mac-address", &len)) != NULL
+ && len == 6) {
+ memcpy(dev->dev_addr, addr, 6);
} else {
memcpy(dev->dev_addr, idprom->id_ethaddr, 6);
}
get_hme_mac_nonsparc(pdev, &dev->dev_addr[0]);
#endif
}
-
+
/* Layout registers. */
hp->gregs = (hpreg_base + 0x0000UL);
hp->etxregs = (hpreg_base + 0x2000UL);
hp->bigmacregs = (hpreg_base + 0x6000UL);
hp->tcvregs = (hpreg_base + 0x7000UL);
-#ifdef __sparc__
- hp->hm_revision = prom_getintdefault(node, "hm-rev", 0xff);
+#ifdef CONFIG_SPARC
+ hp->hm_revision = of_getintprop_default(pcp->prom_node, "hm-rev", 0xff);
if (hp->hm_revision == 0xff) {
unsigned char prev;
/* And of course, indicate this is PCI. */
hp->happy_flags |= HFLAG_PCI;
-#ifdef __sparc__
+#ifdef CONFIG_SPARC
/* Assume PCI happy meals can handle all burst sizes. */
hp->happy_bursts = DMA_BURSTBITS;
#endif
goto err_out_iounmap;
}
+ dev_set_drvdata(&pdev->dev, hp);
+
if (!qfe_slot) {
struct pci_dev *qpdev = qp->quattro_dev;
qpdev->device == PCI_DEVICE_ID_DEC_21153)
printk("DEC 21153 PCI Bridge\n");
else
- printk("unknown bridge %04x.%04x\n",
+ printk("unknown bridge %04x.%04x\n",
qpdev->vendor, qpdev->device);
}
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:
- iounmap((void *)hp->gregs);
+ iounmap(hp->gregs);
err_out_free_res:
pci_release_regions(pdev);
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];
-
- 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;
+ struct happy_meal *hp = dev_get_drvdata(&pdev->dev);
+ struct net_device *net_dev = hp->dev;
+
+ 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)
+static struct pci_device_id happymeal_pci_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_HAPPYMEAL) },
+ { } /* Terminating entry */
+};
+
+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)
{
- struct pci_dev *pdev = NULL;
- int cards = 0;
+ return pci_register_driver(&hme_pci_driver);
+}
- 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);
+static void happy_meal_pci_exit(void)
+{
+ pci_unregister_driver(&hme_pci_driver);
+
+ while (qfe_pci_list) {
+ struct quattro *qfe = qfe_pci_list;
+ struct quattro *next = qfe->next;
+
+ kfree(qfe);
+
+ qfe_pci_list = next;
}
- return cards;
}
+
#endif
-static int __init happy_meal_probe(void)
+#ifdef CONFIG_SBUS
+static int __devinit hme_sbus_probe(struct of_device *dev, const struct of_device_id *match)
{
- static int called = 0;
- int cards;
+ 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);
- root_happy_dev = NULL;
+ if (!is_qfe && model && !strcmp(model, "SUNW,sbus-qfe"))
+ is_qfe = 1;
- if (called)
- return -ENODEV;
- called++;
+ return happy_meal_sbus_probe_one(sdev, is_qfe);
+}
+
+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);
+ sbus_iounmap(hp->erxregs, ERX_REG_SIZE);
+ sbus_iounmap(hp->bigmacregs, BMAC_REG_SIZE);
+ sbus_iounmap(hp->tcvregs, TCVR_REG_SIZE);
+ sbus_free_consistent(hp->happy_dev,
+ PAGE_SIZE,
+ hp->happy_block,
+ hp->hblock_dvma);
+
+ free_netdev(net_dev);
+
+ dev_set_drvdata(&dev->dev, NULL);
- 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;
}
+static struct of_device_id hme_sbus_match[] = {
+ {
+ .name = "SUNW,hme",
+ },
+ {
+ .name = "SUNW,qfe",
+ .data = (void *) 1,
+ },
+ {
+ .name = "qfe",
+ .data = (void *) 1,
+ },
+ {},
+};
-static void __exit happy_meal_cleanup_module(void)
-{
-#ifdef CONFIG_SBUS
- struct quattro *last_seen_qfe = NULL;
-#endif
+MODULE_DEVICE_TABLE(of, hme_sbus_match);
- 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;
+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),
+};
- /* Unregister netdev before unmapping registers as this
- * call can end up trying to access those registers.
- */
- unregister_netdev(dev);
+static int __init happy_meal_sbus_init(void)
+{
+ int err;
-#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;
- }
- }
+ err = of_register_driver(&hme_sbus_driver, &sbus_bus_type);
+ if (!err)
+ quattro_sbus_register_irqs();
- sbus_iounmap(hp->gregs, GREG_REG_SIZE);
- sbus_iounmap(hp->etxregs, ETX_REG_SIZE);
- sbus_iounmap(hp->erxregs, ERX_REG_SIZE);
- sbus_iounmap(hp->bigmacregs, BMAC_REG_SIZE);
- sbus_iounmap(hp->tcvregs, TCVR_REG_SIZE);
- sbus_free_consistent(hp->happy_dev,
- 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((void *)hp->gregs);
- pci_release_regions(hp->happy_dev);
- }
-#endif
- free_netdev(dev);
+ return err;
+}
- root_happy_dev = next;
- }
+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;
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);