ssb: Add Gigabit Ethernet driver

This adds the Gigabit Ethernet driver for the SSB
Gigabit Ethernet core. This driver actually is a frontend to
the Tigon3 driver. So the real work is done by tg3.
This device is used in the Linksys WRT350N.

Signed-off-by: Michael Buesch <mb@bu3sch.de>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
diff --git a/drivers/ssb/embedded.c b/drivers/ssb/embedded.c
index d3ade82..7dc3a6b 100644
--- a/drivers/ssb/embedded.c
+++ b/drivers/ssb/embedded.c
@@ -10,6 +10,9 @@
 
 #include <linux/ssb/ssb.h>
 #include <linux/ssb/ssb_embedded.h>
+#include <linux/ssb/ssb_driver_pci.h>
+#include <linux/ssb/ssb_driver_gige.h>
+#include <linux/pci.h>
 
 #include "ssb_private.h"
 
@@ -130,3 +133,90 @@
 	return res;
 }
 EXPORT_SYMBOL(ssb_gpio_polarity);
+
+#ifdef CONFIG_SSB_DRIVER_GIGE
+static int gige_pci_init_callback(struct ssb_bus *bus, unsigned long data)
+{
+	struct pci_dev *pdev = (struct pci_dev *)data;
+	struct ssb_device *dev;
+	unsigned int i;
+	int res;
+
+	for (i = 0; i < bus->nr_devices; i++) {
+		dev = &(bus->devices[i]);
+		if (dev->id.coreid != SSB_DEV_ETHERNET_GBIT)
+			continue;
+		if (!dev->dev ||
+		    !dev->dev->driver ||
+		    !device_is_registered(dev->dev))
+			continue;
+		res = ssb_gige_pcibios_plat_dev_init(dev, pdev);
+		if (res >= 0)
+			return res;
+	}
+
+	return -ENODEV;
+}
+#endif /* CONFIG_SSB_DRIVER_GIGE */
+
+int ssb_pcibios_plat_dev_init(struct pci_dev *dev)
+{
+	int err;
+
+	err = ssb_pcicore_plat_dev_init(dev);
+	if (!err)
+		return 0;
+#ifdef CONFIG_SSB_DRIVER_GIGE
+	err = ssb_for_each_bus_call((unsigned long)dev, gige_pci_init_callback);
+	if (err >= 0)
+		return err;
+#endif
+	/* This is not a PCI device on any SSB device. */
+
+	return -ENODEV;
+}
+
+#ifdef CONFIG_SSB_DRIVER_GIGE
+static int gige_map_irq_callback(struct ssb_bus *bus, unsigned long data)
+{
+	const struct pci_dev *pdev = (const struct pci_dev *)data;
+	struct ssb_device *dev;
+	unsigned int i;
+	int res;
+
+	for (i = 0; i < bus->nr_devices; i++) {
+		dev = &(bus->devices[i]);
+		if (dev->id.coreid != SSB_DEV_ETHERNET_GBIT)
+			continue;
+		if (!dev->dev ||
+		    !dev->dev->driver ||
+		    !device_is_registered(dev->dev))
+			continue;
+		res = ssb_gige_map_irq(dev, pdev);
+		if (res >= 0)
+			return res;
+	}
+
+	return -ENODEV;
+}
+#endif /* CONFIG_SSB_DRIVER_GIGE */
+
+int ssb_pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+{
+	int res;
+
+	/* Check if this PCI device is a device on a SSB bus or device
+	 * and return the IRQ number for it. */
+
+	res = ssb_pcicore_pcibios_map_irq(dev, slot, pin);
+	if (res >= 0)
+		return res;
+#ifdef CONFIG_SSB_DRIVER_GIGE
+	res = ssb_for_each_bus_call((unsigned long)dev, gige_map_irq_callback);
+	if (res >= 0)
+		return res;
+#endif
+	/* This is not a PCI device on any SSB device. */
+
+	return -ENODEV;
+}