From ffc7689ddae5cbe12bde437ae0f2b386d568b5cd Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Wed, 20 Feb 2008 19:08:10 +0100 Subject: ssb: Add support for 8bit register access This adds support for 8bit wide register reads/writes. This is needed in order to support the gigabit ethernet core. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/ssb/main.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'drivers/ssb/main.c') diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c index bedb2b4ee9d..8db40c4b86e 100644 --- a/drivers/ssb/main.c +++ b/drivers/ssb/main.c @@ -505,6 +505,14 @@ error: return err; } +static u8 ssb_ssb_read8(struct ssb_device *dev, u16 offset) +{ + struct ssb_bus *bus = dev->bus; + + offset += dev->core_index * SSB_CORE_SIZE; + return readb(bus->mmio + offset); +} + static u16 ssb_ssb_read16(struct ssb_device *dev, u16 offset) { struct ssb_bus *bus = dev->bus; @@ -521,6 +529,14 @@ static u32 ssb_ssb_read32(struct ssb_device *dev, u16 offset) return readl(bus->mmio + offset); } +static void ssb_ssb_write8(struct ssb_device *dev, u16 offset, u8 value) +{ + struct ssb_bus *bus = dev->bus; + + offset += dev->core_index * SSB_CORE_SIZE; + writeb(value, bus->mmio + offset); +} + static void ssb_ssb_write16(struct ssb_device *dev, u16 offset, u16 value) { struct ssb_bus *bus = dev->bus; @@ -539,8 +555,10 @@ static void ssb_ssb_write32(struct ssb_device *dev, u16 offset, u32 value) /* Ops for the plain SSB bus without a host-device (no PCI or PCMCIA). */ static const struct ssb_bus_ops ssb_ssb_ops = { + .read8 = ssb_ssb_read8, .read16 = ssb_ssb_read16, .read32 = ssb_ssb_read32, + .write8 = ssb_ssb_write8, .write16 = ssb_ssb_write16, .write32 = ssb_ssb_write32, }; -- cgit v1.2.3 From aab547ce0d1493d400b6468c521a0137cd8c1edf Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Fri, 29 Feb 2008 11:36:12 +0100 Subject: 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 Signed-off-by: John W. Linville --- drivers/ssb/main.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) (limited to 'drivers/ssb/main.c') diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c index 8db40c4b86e..49d7bbb9bea 100644 --- a/drivers/ssb/main.c +++ b/drivers/ssb/main.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -68,6 +69,25 @@ found: } #endif /* CONFIG_SSB_PCIHOST */ +int ssb_for_each_bus_call(unsigned long data, + int (*func)(struct ssb_bus *bus, unsigned long data)) +{ + struct ssb_bus *bus; + int res; + + ssb_buses_lock(); + list_for_each_entry(bus, &buses, list) { + res = func(bus, data); + if (res >= 0) { + ssb_buses_unlock(); + return res; + } + } + ssb_buses_unlock(); + + return -ENODEV; +} + static struct ssb_device *ssb_device_get(struct ssb_device *dev) { if (dev) @@ -1171,7 +1191,14 @@ static int __init ssb_modinit(void) err = b43_pci_ssb_bridge_init(); if (err) { ssb_printk(KERN_ERR "Broadcom 43xx PCI-SSB-bridge " - "initialization failed"); + "initialization failed\n"); + /* don't fail SSB init because of this */ + err = 0; + } + err = ssb_gige_init(); + if (err) { + ssb_printk(KERN_ERR "SSB Broadcom Gigabit Ethernet " + "driver initialization failed\n"); /* don't fail SSB init because of this */ err = 0; } @@ -1185,6 +1212,7 @@ fs_initcall(ssb_modinit); static void __exit ssb_modexit(void) { + ssb_gige_exit(); b43_pci_ssb_bridge_exit(); bus_unregister(&ssb_bustype); } -- cgit v1.2.3 From e7ec2e3230633a858af1b0b359f6c4670dbeb997 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Mon, 10 Mar 2008 17:26:32 +0100 Subject: ssb: Add SPROM/invariants support for PCMCIA devices This adds support for reading/writing the SPROM invariants for PCMCIA based devices. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/ssb/main.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) (limited to 'drivers/ssb/main.c') diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c index 49d7bbb9bea..e1237191644 100644 --- a/drivers/ssb/main.c +++ b/drivers/ssb/main.c @@ -69,6 +69,25 @@ found: } #endif /* CONFIG_SSB_PCIHOST */ +#ifdef CONFIG_SSB_PCMCIAHOST +struct ssb_bus *ssb_pcmcia_dev_to_bus(struct pcmcia_device *pdev) +{ + struct ssb_bus *bus; + + ssb_buses_lock(); + list_for_each_entry(bus, &buses, list) { + if (bus->bustype == SSB_BUSTYPE_PCMCIA && + bus->host_pcmcia == pdev) + goto found; + } + bus = NULL; +found: + ssb_buses_unlock(); + + return bus; +} +#endif /* CONFIG_SSB_PCMCIAHOST */ + int ssb_for_each_bus_call(unsigned long data, int (*func)(struct ssb_bus *bus, unsigned long data)) { @@ -398,7 +417,7 @@ void ssb_bus_unregister(struct ssb_bus *bus) list_del(&bus->list); ssb_buses_unlock(); - /* ssb_pcmcia_exit(bus); */ + ssb_pcmcia_exit(bus); ssb_pci_exit(bus); ssb_iounmap(bus); } @@ -663,7 +682,7 @@ out: err_dequeue: list_del(&bus->list); err_pcmcia_exit: -/* ssb_pcmcia_exit(bus); */ + ssb_pcmcia_exit(bus); err_pci_exit: ssb_pci_exit(bus); err_unmap: -- cgit v1.2.3 From 9788ba7500c3a6268ceb63296a0f37f34d450beb Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Fri, 28 Mar 2008 10:34:55 +0100 Subject: ssb-pcmcia: IRQ and DMA related fixes Here come some IRQ and DMA related fixes for the ssb PCMCIA-host code. Not much to say, actually. I think the patch explains itself. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/ssb/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/ssb/main.c') diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c index e1237191644..2fcfd73b3b6 100644 --- a/drivers/ssb/main.c +++ b/drivers/ssb/main.c @@ -1064,9 +1064,9 @@ u32 ssb_dma_translation(struct ssb_device *dev) { switch (dev->bus->bustype) { case SSB_BUSTYPE_SSB: + case SSB_BUSTYPE_PCMCIA: return 0; case SSB_BUSTYPE_PCI: - case SSB_BUSTYPE_PCMCIA: return SSB_PCI_DMA; } return 0; -- cgit v1.2.3 From 8fe2b65a18e49bfde56a59ed4ab3fc7aa0c2f325 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sun, 30 Mar 2008 00:10:50 +0100 Subject: ssb: Turn suspend/resume upside down Turn the SSB bus suspend mechanism upside down. Instead of deciding by an internal reference count when to suspend/resume, let the parent bus call us in their suspend/resume routine. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/ssb/main.c | 81 +++++++++++++++++++++++------------------------------- 1 file changed, 34 insertions(+), 47 deletions(-) (limited to 'drivers/ssb/main.c') diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c index 2fcfd73b3b6..c0cbdba07ae 100644 --- a/drivers/ssb/main.c +++ b/drivers/ssb/main.c @@ -120,35 +120,12 @@ static void ssb_device_put(struct ssb_device *dev) put_device(dev->dev); } -static int ssb_bus_resume(struct ssb_bus *bus) -{ - int err; - - ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 1); - err = ssb_pcmcia_init(bus); - if (err) { - /* No need to disable XTAL, as we don't have one on PCMCIA. */ - return err; - } - ssb_chipco_resume(&bus->chipco); - - return 0; -} - static int ssb_device_resume(struct device *dev) { struct ssb_device *ssb_dev = dev_to_ssb_dev(dev); struct ssb_driver *ssb_drv; - struct ssb_bus *bus; int err = 0; - bus = ssb_dev->bus; - if (bus->suspend_cnt == bus->nr_devices) { - err = ssb_bus_resume(bus); - if (err) - return err; - } - bus->suspend_cnt--; if (dev->driver) { ssb_drv = drv_to_ssb_drv(dev->driver); if (ssb_drv && ssb_drv->resume) @@ -160,27 +137,10 @@ out: return err; } -static void ssb_bus_suspend(struct ssb_bus *bus, pm_message_t state) -{ - ssb_chipco_suspend(&bus->chipco, state); - ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 0); - - /* Reset HW state information in memory, so that HW is - * completely reinitialized on resume. */ - bus->mapped_device = NULL; -#ifdef CONFIG_SSB_DRIVER_PCICORE - bus->pcicore.setup_done = 0; -#endif -#ifdef CONFIG_SSB_DEBUG - bus->powered_up = 0; -#endif -} - static int ssb_device_suspend(struct device *dev, pm_message_t state) { struct ssb_device *ssb_dev = dev_to_ssb_dev(dev); struct ssb_driver *ssb_drv; - struct ssb_bus *bus; int err = 0; if (dev->driver) { @@ -190,17 +150,44 @@ static int ssb_device_suspend(struct device *dev, pm_message_t state) if (err) goto out; } +out: + return err; +} + +int ssb_bus_resume(struct ssb_bus *bus) +{ + int err; - bus = ssb_dev->bus; - bus->suspend_cnt++; - if (bus->suspend_cnt == bus->nr_devices) { - /* All devices suspended. Shutdown the bus. */ - ssb_bus_suspend(bus, state); + /* Reset HW state information in memory, so that HW is + * completely reinitialized. */ + bus->mapped_device = NULL; +#ifdef CONFIG_SSB_DRIVER_PCICORE + bus->pcicore.setup_done = 0; +#endif + + err = ssb_bus_powerup(bus, 0); + if (err) + return err; + err = ssb_pcmcia_hardware_setup(bus); + if (err) { + ssb_bus_may_powerdown(bus); + return err; } + ssb_chipco_resume(&bus->chipco); + ssb_bus_may_powerdown(bus); -out: - return err; + return 0; +} +EXPORT_SYMBOL(ssb_bus_resume); + +int ssb_bus_suspend(struct ssb_bus *bus) +{ + ssb_chipco_suspend(&bus->chipco); + ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 0); + + return 0; } +EXPORT_SYMBOL(ssb_bus_suspend); #ifdef CONFIG_SSB_PCIHOST int ssb_devices_freeze(struct ssb_bus *bus) -- cgit v1.2.3 From d72bb40fe38608fcf7870b4d768e4416502b23b5 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Wed, 2 Apr 2008 17:03:26 +0200 Subject: ssb: Fix build for non-PCIhost This fixes a build error when PCMCIA-host support is built, but PCI-host support is disabled. Hell, who on earth would use such a weird configuration. :D drivers/built-in.o: In function `ssb_attr_sprom_store': (.text+0x1c4b79): undefined reference to `ssb_devices_freeze' drivers/built-in.o: In function `ssb_attr_sprom_store': (.text+0x1c4bb3): undefined reference to `ssb_devices_thaw' make[1]: *** [.tmp_vmlinux1] Error 1 Signed-off-by: Michael Buesch Acked-by: Randy Dunlap Signed-off-by: John W. Linville --- drivers/ssb/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/ssb/main.c') diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c index c0cbdba07ae..3e58db7ef60 100644 --- a/drivers/ssb/main.c +++ b/drivers/ssb/main.c @@ -189,7 +189,7 @@ int ssb_bus_suspend(struct ssb_bus *bus) } EXPORT_SYMBOL(ssb_bus_suspend); -#ifdef CONFIG_SSB_PCIHOST +#ifdef CONFIG_SSB_SPROM int ssb_devices_freeze(struct ssb_bus *bus) { struct ssb_device *dev; @@ -275,7 +275,7 @@ int ssb_devices_thaw(struct ssb_bus *bus) return 0; } -#endif /* CONFIG_SSB_PCIHOST */ +#endif /* CONFIG_SSB_SPROM */ static void ssb_device_shutdown(struct device *dev) { -- cgit v1.2.3 From d625a29ba649a4df6027520ffc378f23c0e6883e Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Wed, 2 Apr 2008 19:46:56 +0200 Subject: ssb: Add support for block-I/O This adds support for block based I/O to SSB. This is needed in order to efficiently support PIO data transfers to the card. The block-I/O support is only compiled, if it's selected by the weird driver that needs it. So there's no overhead for sane devices. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/ssb/main.c | 102 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) (limited to 'drivers/ssb/main.c') diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c index 3e58db7ef60..19ddd2bd105 100644 --- a/drivers/ssb/main.c +++ b/drivers/ssb/main.c @@ -555,6 +555,55 @@ static u32 ssb_ssb_read32(struct ssb_device *dev, u16 offset) return readl(bus->mmio + offset); } +#ifdef CONFIG_SSB_BLOCKIO +static void ssb_ssb_block_read(struct ssb_device *dev, void *buffer, + size_t count, u16 offset, u8 reg_width) +{ + struct ssb_bus *bus = dev->bus; + void __iomem *addr; + + offset += dev->core_index * SSB_CORE_SIZE; + addr = bus->mmio + offset; + + switch (reg_width) { + case sizeof(u8): { + u8 *buf = buffer; + + while (count) { + *buf = __raw_readb(addr); + buf++; + count--; + } + break; + } + case sizeof(u16): { + __le16 *buf = buffer; + + SSB_WARN_ON(count & 1); + while (count) { + *buf = (__force __le16)__raw_readw(addr); + buf++; + count -= 2; + } + break; + } + case sizeof(u32): { + __le32 *buf = buffer; + + SSB_WARN_ON(count & 3); + while (count) { + *buf = (__force __le32)__raw_readl(addr); + buf++; + count -= 4; + } + break; + } + default: + SSB_WARN_ON(1); + } +} +#endif /* CONFIG_SSB_BLOCKIO */ + static void ssb_ssb_write8(struct ssb_device *dev, u16 offset, u8 value) { struct ssb_bus *bus = dev->bus; @@ -579,6 +628,55 @@ static void ssb_ssb_write32(struct ssb_device *dev, u16 offset, u32 value) writel(value, bus->mmio + offset); } +#ifdef CONFIG_SSB_BLOCKIO +static void ssb_ssb_block_write(struct ssb_device *dev, const void *buffer, + size_t count, u16 offset, u8 reg_width) +{ + struct ssb_bus *bus = dev->bus; + void __iomem *addr; + + offset += dev->core_index * SSB_CORE_SIZE; + addr = bus->mmio + offset; + + switch (reg_width) { + case sizeof(u8): { + const u8 *buf = buffer; + + while (count) { + __raw_writeb(*buf, addr); + buf++; + count--; + } + break; + } + case sizeof(u16): { + const __le16 *buf = buffer; + + SSB_WARN_ON(count & 1); + while (count) { + __raw_writew((__force u16)(*buf), addr); + buf++; + count -= 2; + } + break; + } + case sizeof(u32): { + const __le32 *buf = buffer; + + SSB_WARN_ON(count & 3); + while (count) { + __raw_writel((__force u32)(*buf), addr); + buf++; + count -= 4; + } + break; + } + default: + SSB_WARN_ON(1); + } +} +#endif /* CONFIG_SSB_BLOCKIO */ + /* Ops for the plain SSB bus without a host-device (no PCI or PCMCIA). */ static const struct ssb_bus_ops ssb_ssb_ops = { .read8 = ssb_ssb_read8, @@ -587,6 +685,10 @@ static const struct ssb_bus_ops ssb_ssb_ops = { .write8 = ssb_ssb_write8, .write16 = ssb_ssb_write16, .write32 = ssb_ssb_write32, +#ifdef CONFIG_SSB_BLOCKIO + .block_read = ssb_ssb_block_read, + .block_write = ssb_ssb_block_write, +#endif }; static int ssb_fetch_invariants(struct ssb_bus *bus, -- cgit v1.2.3