From: George Kashperko <george@xxxxxxxxxxx> Add support for AI-style bus on PCI host. This is preliminary and untested yet. Signed-off-by: George Kashperko <george@xxxxxxxxxxx> --- drivers/ssb/ssb_ai.c | 100 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) --- linux-wireless-testing.orig/drivers/ssb/ssb_ai.c 2011-02-17 16:01:51.000000000 +0200 +++ linux-wireless-testing/drivers/ssb/ssb_ai.c 2011-02-17 16:04:43.000000000 +0200 @@ -48,6 +48,93 @@ struct ssb_bus_aiops ssb_ssb_aiops = { .write32 = ssb_ssb_aiwrite32, }; +#ifdef CONFIG_SSB_PCIHOST +#define SSB_VERBOSE_PCICOREAISWITCH_DEBUG 0 +static int ssb_pci_switch_aicoreidx(struct ssb_bus *bus, u8 coreidx) +{ + int err; + int attempts = 0; + u32 cur_core; + + while (true) { + err = pci_write_config_dword(bus->host_pci, SSB_BAR0_WIN2, + (coreidx * SSB_CORE_SIZE) + + SSB_AI_BASE); + if (err) + goto error; + err = pci_read_config_dword(bus->host_pci, SSB_BAR0_WIN2, + &cur_core); + if (err) + goto error; + cur_core = (cur_core - SSB_AI_BASE) + / SSB_CORE_SIZE; + if (cur_core == coreidx) + break; + + if (attempts++ > SSB_BAR0_MAX_RETRIES) + goto error; + udelay(10); + } + return 0; +error: + ssb_printk(KERN_ERR PFX "Failed to switch to AI core %u\n", coreidx); + return -ENODEV; +} + +static int ssb_pci_switch_aicore(struct ssb_bus *bus, + struct ssb_device *dev) +{ + int err; + unsigned long flags; + +#if SSB_VERBOSE_PCICOREAISWITCH_DEBUG + ssb_printk(KERN_INFO PFX + "Switching to %s AI core, index %d\n", + ssb_core_name(dev->id.coreid), + dev->core_index); +#endif + + spin_lock_irqsave(&bus->bar_lock, flags); + err = ssb_pci_switch_aicoreidx(bus, dev->core_index); + if (!err) + bus->ai.mapped_device = dev; + spin_unlock_irqrestore(&bus->bar_lock, flags); + + return err; +} + +static u32 ssb_pci_airead32(struct ssb_device *dev, u16 offset) +{ + struct ssb_bus *bus = dev->bus; + + if (unlikely(!bus->powered_up)) + return 0xFFFFFFFF; + if (unlikely(bus->ai.mapped_device != dev)) { + if (unlikely(ssb_pci_switch_aicore(bus, dev))) + return 0xFFFFFFFF; + } + return ioread32(bus->ai.mmio + offset); +} + +static void ssb_pci_aiwrite32(struct ssb_device *dev, u16 offset, u32 value) +{ + struct ssb_bus *bus = dev->bus; + + if (unlikely(!bus->powered_up)) + return; + if (unlikely(bus->ai.mapped_device != dev)) { + if (unlikely(ssb_pci_switch_aicore(bus, dev))) + return; + } + iowrite32(value, bus->ai.mmio + offset); +} + +struct ssb_bus_aiops ssb_pci_aiops = { + .read32 = ssb_pci_airead32, + .write32 = ssb_pci_aiwrite32, +}; +#endif /* CONFIG_SSB_PCIHOST */ + /* The 47162a0 hangs when reading its registers */ static inline bool ssb_bcm47162a0_quirk(struct ssb_device *dev) { @@ -188,6 +275,10 @@ void ssb_iounmap_ai(struct ssb_bus *bus) iounmap(bus->mmio); iounmap(bus->ai.mmio); break; +#ifdef CONFIG_SSB_PCIHOST + case SSB_BUSTYPE_PCI: + pci_iounmap(bus->host_pci, bus->mmio); +#endif default: break; } @@ -263,6 +354,15 @@ int ssb_bus_scan_ai(struct ssb_bus *bus, if (!eromptr) return -ENOMEM; break; +#ifdef CONFIG_SSB_PCIHOST + case SSB_BUSTYPE_PCI: + bus->ai.ops = &ssb_pci_aiops; + /* point second bar0 window at the EROM */ + pci_write_config_dword(bus->host_pci, SSB_BAR0_WIN2, erombase); + eromptr = bus->mmio; + bus->ai.mmio = bus->mmio + 0x1000; + break; +#endif /* CONFIG_SSB_PCIHOST */ default: return -ENODEV; } -- To unsubscribe from this list: send the line "unsubscribe linux-wireless" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html