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>
This commit is contained in:
parent
93af261451
commit
d625a29ba6
5 changed files with 315 additions and 0 deletions
|
@ -24,6 +24,11 @@ config SSB
|
||||||
config SSB_SPROM
|
config SSB_SPROM
|
||||||
bool
|
bool
|
||||||
|
|
||||||
|
# Support for Block-I/O. SELECT this from the driver that needs it.
|
||||||
|
config SSB_BLOCKIO
|
||||||
|
bool
|
||||||
|
depends on SSB
|
||||||
|
|
||||||
config SSB_PCIHOST_POSSIBLE
|
config SSB_PCIHOST_POSSIBLE
|
||||||
bool
|
bool
|
||||||
depends on SSB && (PCI = y || PCI = SSB)
|
depends on SSB && (PCI = y || PCI = SSB)
|
||||||
|
|
|
@ -555,6 +555,55 @@ static u32 ssb_ssb_read32(struct ssb_device *dev, u16 offset)
|
||||||
return readl(bus->mmio + 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)
|
static void ssb_ssb_write8(struct ssb_device *dev, u16 offset, u8 value)
|
||||||
{
|
{
|
||||||
struct ssb_bus *bus = dev->bus;
|
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);
|
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). */
|
/* Ops for the plain SSB bus without a host-device (no PCI or PCMCIA). */
|
||||||
static const struct ssb_bus_ops ssb_ssb_ops = {
|
static const struct ssb_bus_ops ssb_ssb_ops = {
|
||||||
.read8 = ssb_ssb_read8,
|
.read8 = ssb_ssb_read8,
|
||||||
|
@ -587,6 +685,10 @@ static const struct ssb_bus_ops ssb_ssb_ops = {
|
||||||
.write8 = ssb_ssb_write8,
|
.write8 = ssb_ssb_write8,
|
||||||
.write16 = ssb_ssb_write16,
|
.write16 = ssb_ssb_write16,
|
||||||
.write32 = ssb_ssb_write32,
|
.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,
|
static int ssb_fetch_invariants(struct ssb_bus *bus,
|
||||||
|
|
|
@ -613,6 +613,41 @@ static u32 ssb_pci_read32(struct ssb_device *dev, u16 offset)
|
||||||
return ioread32(bus->mmio + 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)
|
static void ssb_pci_write8(struct ssb_device *dev, u16 offset, u8 value)
|
||||||
{
|
{
|
||||||
struct ssb_bus *bus = dev->bus;
|
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);
|
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 */
|
/* Not "static", as it's used in main.c */
|
||||||
const struct ssb_bus_ops ssb_pci_ops = {
|
const struct ssb_bus_ops ssb_pci_ops = {
|
||||||
.read8 = ssb_pci_read8,
|
.read8 = ssb_pci_read8,
|
||||||
|
@ -660,6 +726,10 @@ const struct ssb_bus_ops ssb_pci_ops = {
|
||||||
.write8 = ssb_pci_write8,
|
.write8 = ssb_pci_write8,
|
||||||
.write16 = ssb_pci_write16,
|
.write16 = ssb_pci_write16,
|
||||||
.write32 = ssb_pci_write32,
|
.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,
|
static ssize_t ssb_pci_attr_sprom_show(struct device *pcidev,
|
||||||
|
|
|
@ -285,6 +285,64 @@ static u32 ssb_pcmcia_read32(struct ssb_device *dev, u16 offset)
|
||||||
return (lo | (hi << 16));
|
return (lo | (hi << 16));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_SSB_BLOCKIO
|
||||||
|
static void ssb_pcmcia_block_read(struct ssb_device *dev, void *buffer,
|
||||||
|
size_t count, u16 offset, u8 reg_width)
|
||||||
|
{
|
||||||
|
struct ssb_bus *bus = dev->bus;
|
||||||
|
unsigned long flags;
|
||||||
|
void __iomem *addr = bus->mmio + offset;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&bus->bar_lock, flags);
|
||||||
|
err = select_core_and_segment(dev, &offset);
|
||||||
|
if (unlikely(err)) {
|
||||||
|
memset(buffer, 0xFF, count);
|
||||||
|
goto unlock;
|
||||||
|
}
|
||||||
|
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): {
|
||||||
|
__le16 *buf = buffer;
|
||||||
|
|
||||||
|
SSB_WARN_ON(count & 3);
|
||||||
|
while (count) {
|
||||||
|
*buf = (__force __le16)__raw_readw(addr);
|
||||||
|
buf++;
|
||||||
|
*buf = (__force __le16)__raw_readw(addr + 2);
|
||||||
|
buf++;
|
||||||
|
count -= 4;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
SSB_WARN_ON(1);
|
||||||
|
}
|
||||||
|
unlock:
|
||||||
|
spin_unlock_irqrestore(&bus->bar_lock, flags);
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_SSB_BLOCKIO */
|
||||||
|
|
||||||
static void ssb_pcmcia_write8(struct ssb_device *dev, u16 offset, u8 value)
|
static void ssb_pcmcia_write8(struct ssb_device *dev, u16 offset, u8 value)
|
||||||
{
|
{
|
||||||
struct ssb_bus *bus = dev->bus;
|
struct ssb_bus *bus = dev->bus;
|
||||||
|
@ -329,6 +387,63 @@ static void ssb_pcmcia_write32(struct ssb_device *dev, u16 offset, u32 value)
|
||||||
spin_unlock_irqrestore(&bus->bar_lock, flags);
|
spin_unlock_irqrestore(&bus->bar_lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_SSB_BLOCKIO
|
||||||
|
static void ssb_pcmcia_block_write(struct ssb_device *dev, const void *buffer,
|
||||||
|
size_t count, u16 offset, u8 reg_width)
|
||||||
|
{
|
||||||
|
struct ssb_bus *bus = dev->bus;
|
||||||
|
unsigned long flags;
|
||||||
|
void __iomem *addr = bus->mmio + offset;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&bus->bar_lock, flags);
|
||||||
|
err = select_core_and_segment(dev, &offset);
|
||||||
|
if (unlikely(err))
|
||||||
|
goto unlock;
|
||||||
|
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 __le16 *buf = buffer;
|
||||||
|
|
||||||
|
SSB_WARN_ON(count & 3);
|
||||||
|
while (count) {
|
||||||
|
__raw_writew((__force u16)(*buf), addr);
|
||||||
|
buf++;
|
||||||
|
__raw_writew((__force u16)(*buf), addr + 2);
|
||||||
|
buf++;
|
||||||
|
count -= 4;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
SSB_WARN_ON(1);
|
||||||
|
}
|
||||||
|
unlock:
|
||||||
|
mmiowb();
|
||||||
|
spin_unlock_irqrestore(&bus->bar_lock, flags);
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_SSB_BLOCKIO */
|
||||||
|
|
||||||
/* Not "static", as it's used in main.c */
|
/* Not "static", as it's used in main.c */
|
||||||
const struct ssb_bus_ops ssb_pcmcia_ops = {
|
const struct ssb_bus_ops ssb_pcmcia_ops = {
|
||||||
.read8 = ssb_pcmcia_read8,
|
.read8 = ssb_pcmcia_read8,
|
||||||
|
@ -337,6 +452,10 @@ const struct ssb_bus_ops ssb_pcmcia_ops = {
|
||||||
.write8 = ssb_pcmcia_write8,
|
.write8 = ssb_pcmcia_write8,
|
||||||
.write16 = ssb_pcmcia_write16,
|
.write16 = ssb_pcmcia_write16,
|
||||||
.write32 = ssb_pcmcia_write32,
|
.write32 = ssb_pcmcia_write32,
|
||||||
|
#ifdef CONFIG_SSB_BLOCKIO
|
||||||
|
.block_read = ssb_pcmcia_block_read,
|
||||||
|
.block_write = ssb_pcmcia_block_write,
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
static int ssb_pcmcia_sprom_command(struct ssb_bus *bus, u8 command)
|
static int ssb_pcmcia_sprom_command(struct ssb_bus *bus, u8 command)
|
||||||
|
|
|
@ -78,6 +78,12 @@ struct ssb_bus_ops {
|
||||||
void (*write8)(struct ssb_device *dev, u16 offset, u8 value);
|
void (*write8)(struct ssb_device *dev, u16 offset, u8 value);
|
||||||
void (*write16)(struct ssb_device *dev, u16 offset, u16 value);
|
void (*write16)(struct ssb_device *dev, u16 offset, u16 value);
|
||||||
void (*write32)(struct ssb_device *dev, u16 offset, u32 value);
|
void (*write32)(struct ssb_device *dev, u16 offset, u32 value);
|
||||||
|
#ifdef CONFIG_SSB_BLOCKIO
|
||||||
|
void (*block_read)(struct ssb_device *dev, void *buffer,
|
||||||
|
size_t count, u16 offset, u8 reg_width);
|
||||||
|
void (*block_write)(struct ssb_device *dev, const void *buffer,
|
||||||
|
size_t count, u16 offset, u8 reg_width);
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -374,6 +380,19 @@ static inline void ssb_write32(struct ssb_device *dev, u16 offset, u32 value)
|
||||||
{
|
{
|
||||||
dev->ops->write32(dev, offset, value);
|
dev->ops->write32(dev, offset, value);
|
||||||
}
|
}
|
||||||
|
#ifdef CONFIG_SSB_BLOCKIO
|
||||||
|
static inline void ssb_block_read(struct ssb_device *dev, void *buffer,
|
||||||
|
size_t count, u16 offset, u8 reg_width)
|
||||||
|
{
|
||||||
|
dev->ops->block_read(dev, buffer, count, offset, reg_width);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void ssb_block_write(struct ssb_device *dev, const void *buffer,
|
||||||
|
size_t count, u16 offset, u8 reg_width)
|
||||||
|
{
|
||||||
|
dev->ops->block_write(dev, buffer, count, offset, reg_width);
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_SSB_BLOCKIO */
|
||||||
|
|
||||||
|
|
||||||
/* Translation (routing) bits that need to be ORed to DMA
|
/* Translation (routing) bits that need to be ORed to DMA
|
||||||
|
|
Loading…
Reference in a new issue