diff options
author | Michael Buesch <mb@bu3sch.de> | 2008-04-02 21:46:56 +0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-04-09 00:44:40 +0400 |
commit | d625a29ba649a4df6027520ffc378f23c0e6883e (patch) | |
tree | 07b895d38717e24e655948c963f4287f551df42f /drivers/ssb/pci.c | |
parent | 93af2614513103216038afa708718295e7016dbb (diff) | |
download | linux-d625a29ba649a4df6027520ffc378f23c0e6883e.tar.xz |
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 <mb@bu3sch.de>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/ssb/pci.c')
-rw-r--r-- | drivers/ssb/pci.c | 70 |
1 files changed, 70 insertions, 0 deletions
diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c index f1514b33cfae..904b1a8d0885 100644 --- a/drivers/ssb/pci.c +++ b/drivers/ssb/pci.c @@ -613,6 +613,41 @@ static u32 ssb_pci_read32(struct ssb_device *dev, u16 offset) return ioread32(bus->mmio + offset); } +#ifdef CONFIG_SSB_BLOCKIO +static void ssb_pci_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 = bus->mmio + offset; + + if (unlikely(ssb_pci_assert_buspower(bus))) + goto error; + if (unlikely(bus->mapped_device != dev)) { + if (unlikely(ssb_pci_switch_core(bus, dev))) + goto error; + } + switch (reg_width) { + case sizeof(u8): + ioread8_rep(addr, buffer, count); + break; + case sizeof(u16): + SSB_WARN_ON(count & 1); + ioread16_rep(addr, buffer, count >> 1); + break; + case sizeof(u32): + SSB_WARN_ON(count & 3); + ioread32_rep(addr, buffer, count >> 2); + break; + default: + SSB_WARN_ON(1); + } + + return; +error: + memset(buffer, 0xFF, count); +} +#endif /* CONFIG_SSB_BLOCKIO */ + static void ssb_pci_write8(struct ssb_device *dev, u16 offset, u8 value) { struct ssb_bus *bus = dev->bus; @@ -652,6 +687,37 @@ static void ssb_pci_write32(struct ssb_device *dev, u16 offset, u32 value) iowrite32(value, bus->mmio + offset); } +#ifdef CONFIG_SSB_BLOCKIO +static void ssb_pci_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 = bus->mmio + offset; + + if (unlikely(ssb_pci_assert_buspower(bus))) + return; + if (unlikely(bus->mapped_device != dev)) { + if (unlikely(ssb_pci_switch_core(bus, dev))) + return; + } + switch (reg_width) { + case sizeof(u8): + iowrite8_rep(addr, buffer, count); + break; + case sizeof(u16): + SSB_WARN_ON(count & 1); + iowrite16_rep(addr, buffer, count >> 1); + break; + case sizeof(u32): + SSB_WARN_ON(count & 3); + iowrite32_rep(addr, buffer, count >> 2); + break; + default: + SSB_WARN_ON(1); + } +} +#endif /* CONFIG_SSB_BLOCKIO */ + /* Not "static", as it's used in main.c */ const struct ssb_bus_ops ssb_pci_ops = { .read8 = ssb_pci_read8, @@ -660,6 +726,10 @@ const struct ssb_bus_ops ssb_pci_ops = { .write8 = ssb_pci_write8, .write16 = ssb_pci_write16, .write32 = ssb_pci_write32, +#ifdef CONFIG_SSB_BLOCKIO + .block_read = ssb_pci_block_read, + .block_write = ssb_pci_block_write, +#endif }; static ssize_t ssb_pci_attr_sprom_show(struct device *pcidev, |