diff options
author | Michael Buesch <mb@bu3sch.de> | 2008-04-02 13:46:56 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-04-08 16:44:40 -0400 |
commit | d625a29ba649a4df6027520ffc378f23c0e6883e (patch) | |
tree | 07b895d38717e24e655948c963f4287f551df42f /drivers/ssb | |
parent | 93af2614513103216038afa708718295e7016dbb (diff) |
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')
-rw-r--r-- | drivers/ssb/Kconfig | 5 | ||||
-rw-r--r-- | drivers/ssb/main.c | 102 | ||||
-rw-r--r-- | drivers/ssb/pci.c | 70 | ||||
-rw-r--r-- | drivers/ssb/pcmcia.c | 119 |
4 files changed, 296 insertions, 0 deletions
diff --git a/drivers/ssb/Kconfig b/drivers/ssb/Kconfig index 0f7cce2560d1..cd845b8acd17 100644 --- a/drivers/ssb/Kconfig +++ b/drivers/ssb/Kconfig | |||
@@ -24,6 +24,11 @@ config SSB | |||
24 | config SSB_SPROM | 24 | config SSB_SPROM |
25 | bool | 25 | bool |
26 | 26 | ||
27 | # Support for Block-I/O. SELECT this from the driver that needs it. | ||
28 | config SSB_BLOCKIO | ||
29 | bool | ||
30 | depends on SSB | ||
31 | |||
27 | config SSB_PCIHOST_POSSIBLE | 32 | config SSB_PCIHOST_POSSIBLE |
28 | bool | 33 | bool |
29 | depends on SSB && (PCI = y || PCI = SSB) | 34 | depends on SSB && (PCI = y || PCI = SSB) |
diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c index 3e58db7ef608..19ddd2bd1057 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) | |||
555 | return readl(bus->mmio + offset); | 555 | return readl(bus->mmio + offset); |
556 | } | 556 | } |
557 | 557 | ||
558 | #ifdef CONFIG_SSB_BLOCKIO | ||
559 | static void ssb_ssb_block_read(struct ssb_device *dev, void *buffer, | ||
560 | size_t count, u16 offset, u8 reg_width) | ||
561 | { | ||
562 | struct ssb_bus *bus = dev->bus; | ||
563 | void __iomem *addr; | ||
564 | |||
565 | offset += dev->core_index * SSB_CORE_SIZE; | ||
566 | addr = bus->mmio + offset; | ||
567 | |||
568 | switch (reg_width) { | ||
569 | case sizeof(u8): { | ||
570 | u8 *buf = buffer; | ||
571 | |||
572 | while (count) { | ||
573 | *buf = __raw_readb(addr); | ||
574 | buf++; | ||
575 | count--; | ||
576 | } | ||
577 | break; | ||
578 | } | ||
579 | case sizeof(u16): { | ||
580 | __le16 *buf = buffer; | ||
581 | |||
582 | SSB_WARN_ON(count & 1); | ||
583 | while (count) { | ||
584 | *buf = (__force __le16)__raw_readw(addr); | ||
585 | buf++; | ||
586 | count -= 2; | ||
587 | } | ||
588 | break; | ||
589 | } | ||
590 | case sizeof(u32): { | ||
591 | __le32 *buf = buffer; | ||
592 | |||
593 | SSB_WARN_ON(count & 3); | ||
594 | while (count) { | ||
595 | *buf = (__force __le32)__raw_readl(addr); | ||
596 | buf++; | ||
597 | count -= 4; | ||
598 | } | ||
599 | break; | ||
600 | } | ||
601 | default: | ||
602 | SSB_WARN_ON(1); | ||
603 | } | ||
604 | } | ||
605 | #endif /* CONFIG_SSB_BLOCKIO */ | ||
606 | |||
558 | static void ssb_ssb_write8(struct ssb_device *dev, u16 offset, u8 value) | 607 | static void ssb_ssb_write8(struct ssb_device *dev, u16 offset, u8 value) |
559 | { | 608 | { |
560 | struct ssb_bus *bus = dev->bus; | 609 | struct ssb_bus *bus = dev->bus; |
@@ -579,6 +628,55 @@ static void ssb_ssb_write32(struct ssb_device *dev, u16 offset, u32 value) | |||
579 | writel(value, bus->mmio + offset); | 628 | writel(value, bus->mmio + offset); |
580 | } | 629 | } |
581 | 630 | ||
631 | #ifdef CONFIG_SSB_BLOCKIO | ||
632 | static void ssb_ssb_block_write(struct ssb_device *dev, const void *buffer, | ||
633 | size_t count, u16 offset, u8 reg_width) | ||
634 | { | ||
635 | struct ssb_bus *bus = dev->bus; | ||
636 | void __iomem *addr; | ||
637 | |||
638 | offset += dev->core_index * SSB_CORE_SIZE; | ||
639 | addr = bus->mmio + offset; | ||
640 | |||
641 | switch (reg_width) { | ||
642 | case sizeof(u8): { | ||
643 | const u8 *buf = buffer; | ||
644 | |||
645 | while (count) { | ||
646 | __raw_writeb(*buf, addr); | ||
647 | buf++; | ||
648 | count--; | ||
649 | } | ||
650 | break; | ||
651 | } | ||
652 | case sizeof(u16): { | ||
653 | const __le16 *buf = buffer; | ||
654 | |||
655 | SSB_WARN_ON(count & 1); | ||
656 | while (count) { | ||
657 | __raw_writew((__force u16)(*buf), addr); | ||
658 | buf++; | ||
659 | count -= 2; | ||
660 | } | ||
661 | break; | ||
662 | } | ||
663 | case sizeof(u32): { | ||
664 | const __le32 *buf = buffer; | ||
665 | |||
666 | SSB_WARN_ON(count & 3); | ||
667 | while (count) { | ||
668 | __raw_writel((__force u32)(*buf), addr); | ||
669 | buf++; | ||
670 | count -= 4; | ||
671 | } | ||
672 | break; | ||
673 | } | ||
674 | default: | ||
675 | SSB_WARN_ON(1); | ||
676 | } | ||
677 | } | ||
678 | #endif /* CONFIG_SSB_BLOCKIO */ | ||
679 | |||
582 | /* Ops for the plain SSB bus without a host-device (no PCI or PCMCIA). */ | 680 | /* Ops for the plain SSB bus without a host-device (no PCI or PCMCIA). */ |
583 | static const struct ssb_bus_ops ssb_ssb_ops = { | 681 | static const struct ssb_bus_ops ssb_ssb_ops = { |
584 | .read8 = ssb_ssb_read8, | 682 | .read8 = ssb_ssb_read8, |
@@ -587,6 +685,10 @@ static const struct ssb_bus_ops ssb_ssb_ops = { | |||
587 | .write8 = ssb_ssb_write8, | 685 | .write8 = ssb_ssb_write8, |
588 | .write16 = ssb_ssb_write16, | 686 | .write16 = ssb_ssb_write16, |
589 | .write32 = ssb_ssb_write32, | 687 | .write32 = ssb_ssb_write32, |
688 | #ifdef CONFIG_SSB_BLOCKIO | ||
689 | .block_read = ssb_ssb_block_read, | ||
690 | .block_write = ssb_ssb_block_write, | ||
691 | #endif | ||
590 | }; | 692 | }; |
591 | 693 | ||
592 | static int ssb_fetch_invariants(struct ssb_bus *bus, | 694 | static int ssb_fetch_invariants(struct ssb_bus *bus, |
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) | |||
613 | return ioread32(bus->mmio + offset); | 613 | return ioread32(bus->mmio + offset); |
614 | } | 614 | } |
615 | 615 | ||
616 | #ifdef CONFIG_SSB_BLOCKIO | ||
617 | static void ssb_pci_block_read(struct ssb_device *dev, void *buffer, | ||
618 | size_t count, u16 offset, u8 reg_width) | ||
619 | { | ||
620 | struct ssb_bus *bus = dev->bus; | ||
621 | void __iomem *addr = bus->mmio + offset; | ||
622 | |||
623 | if (unlikely(ssb_pci_assert_buspower(bus))) | ||
624 | goto error; | ||
625 | if (unlikely(bus->mapped_device != dev)) { | ||
626 | if (unlikely(ssb_pci_switch_core(bus, dev))) | ||
627 | goto error; | ||
628 | } | ||
629 | switch (reg_width) { | ||
630 | case sizeof(u8): | ||
631 | ioread8_rep(addr, buffer, count); | ||
632 | break; | ||
633 | case sizeof(u16): | ||
634 | SSB_WARN_ON(count & 1); | ||
635 | ioread16_rep(addr, buffer, count >> 1); | ||
636 | break; | ||
637 | case sizeof(u32): | ||
638 | SSB_WARN_ON(count & 3); | ||
639 | ioread32_rep(addr, buffer, count >> 2); | ||
640 | break; | ||
641 | default: | ||
642 | SSB_WARN_ON(1); | ||
643 | } | ||
644 | |||
645 | return; | ||
646 | error: | ||
647 | memset(buffer, 0xFF, count); | ||
648 | } | ||
649 | #endif /* CONFIG_SSB_BLOCKIO */ | ||
650 | |||
616 | static void ssb_pci_write8(struct ssb_device *dev, u16 offset, u8 value) | 651 | static void ssb_pci_write8(struct ssb_device *dev, u16 offset, u8 value) |
617 | { | 652 | { |
618 | struct ssb_bus *bus = dev->bus; | 653 | struct ssb_bus *bus = dev->bus; |
@@ -652,6 +687,37 @@ static void ssb_pci_write32(struct ssb_device *dev, u16 offset, u32 value) | |||
652 | iowrite32(value, bus->mmio + offset); | 687 | iowrite32(value, bus->mmio + offset); |
653 | } | 688 | } |
654 | 689 | ||
690 | #ifdef CONFIG_SSB_BLOCKIO | ||
691 | static void ssb_pci_block_write(struct ssb_device *dev, const void *buffer, | ||
692 | size_t count, u16 offset, u8 reg_width) | ||
693 | { | ||
694 | struct ssb_bus *bus = dev->bus; | ||
695 | void __iomem *addr = bus->mmio + offset; | ||
696 | |||
697 | if (unlikely(ssb_pci_assert_buspower(bus))) | ||
698 | return; | ||
699 | if (unlikely(bus->mapped_device != dev)) { | ||
700 | if (unlikely(ssb_pci_switch_core(bus, dev))) | ||
701 | return; | ||
702 | } | ||
703 | switch (reg_width) { | ||
704 | case sizeof(u8): | ||
705 | iowrite8_rep(addr, buffer, count); | ||
706 | break; | ||
707 | case sizeof(u16): | ||
708 | SSB_WARN_ON(count & 1); | ||
709 | iowrite16_rep(addr, buffer, count >> 1); | ||
710 | break; | ||
711 | case sizeof(u32): | ||
712 | SSB_WARN_ON(count & 3); | ||
713 | iowrite32_rep(addr, buffer, count >> 2); | ||
714 | break; | ||
715 | default: | ||
716 | SSB_WARN_ON(1); | ||
717 | } | ||
718 | } | ||
719 | #endif /* CONFIG_SSB_BLOCKIO */ | ||
720 | |||
655 | /* Not "static", as it's used in main.c */ | 721 | /* Not "static", as it's used in main.c */ |
656 | const struct ssb_bus_ops ssb_pci_ops = { | 722 | const struct ssb_bus_ops ssb_pci_ops = { |
657 | .read8 = ssb_pci_read8, | 723 | .read8 = ssb_pci_read8, |
@@ -660,6 +726,10 @@ const struct ssb_bus_ops ssb_pci_ops = { | |||
660 | .write8 = ssb_pci_write8, | 726 | .write8 = ssb_pci_write8, |
661 | .write16 = ssb_pci_write16, | 727 | .write16 = ssb_pci_write16, |
662 | .write32 = ssb_pci_write32, | 728 | .write32 = ssb_pci_write32, |
729 | #ifdef CONFIG_SSB_BLOCKIO | ||
730 | .block_read = ssb_pci_block_read, | ||
731 | .block_write = ssb_pci_block_write, | ||
732 | #endif | ||
663 | }; | 733 | }; |
664 | 734 | ||
665 | static ssize_t ssb_pci_attr_sprom_show(struct device *pcidev, | 735 | static ssize_t ssb_pci_attr_sprom_show(struct device *pcidev, |
diff --git a/drivers/ssb/pcmcia.c b/drivers/ssb/pcmcia.c index dcaf2412bea7..24c2a46c1476 100644 --- a/drivers/ssb/pcmcia.c +++ b/drivers/ssb/pcmcia.c | |||
@@ -285,6 +285,64 @@ static u32 ssb_pcmcia_read32(struct ssb_device *dev, u16 offset) | |||
285 | return (lo | (hi << 16)); | 285 | return (lo | (hi << 16)); |
286 | } | 286 | } |
287 | 287 | ||
288 | #ifdef CONFIG_SSB_BLOCKIO | ||
289 | static void ssb_pcmcia_block_read(struct ssb_device *dev, void *buffer, | ||
290 | size_t count, u16 offset, u8 reg_width) | ||
291 | { | ||
292 | struct ssb_bus *bus = dev->bus; | ||
293 | unsigned long flags; | ||
294 | void __iomem *addr = bus->mmio + offset; | ||
295 | int err; | ||
296 | |||
297 | spin_lock_irqsave(&bus->bar_lock, flags); | ||
298 | err = select_core_and_segment(dev, &offset); | ||
299 | if (unlikely(err)) { | ||
300 | memset(buffer, 0xFF, count); | ||
301 | goto unlock; | ||
302 | } | ||
303 | switch (reg_width) { | ||
304 | case sizeof(u8): { | ||
305 | u8 *buf = buffer; | ||
306 | |||
307 | while (count) { | ||
308 | *buf = __raw_readb(addr); | ||
309 | buf++; | ||
310 | count--; | ||
311 | } | ||
312 | break; | ||
313 | } | ||
314 | case sizeof(u16): { | ||
315 | __le16 *buf = buffer; | ||
316 | |||
317 | SSB_WARN_ON(count & 1); | ||
318 | while (count) { | ||
319 | *buf = (__force __le16)__raw_readw(addr); | ||
320 | buf++; | ||
321 | count -= 2; | ||
322 | } | ||
323 | break; | ||
324 | } | ||
325 | case sizeof(u32): { | ||
326 | __le16 *buf = buffer; | ||
327 | |||
328 | SSB_WARN_ON(count & 3); | ||
329 | while (count) { | ||
330 | *buf = (__force __le16)__raw_readw(addr); | ||
331 | buf++; | ||
332 | *buf = (__force __le16)__raw_readw(addr + 2); | ||
333 | buf++; | ||
334 | count -= 4; | ||
335 | } | ||
336 | break; | ||
337 | } | ||
338 | default: | ||
339 | SSB_WARN_ON(1); | ||
340 | } | ||
341 | unlock: | ||
342 | spin_unlock_irqrestore(&bus->bar_lock, flags); | ||
343 | } | ||
344 | #endif /* CONFIG_SSB_BLOCKIO */ | ||
345 | |||
288 | static void ssb_pcmcia_write8(struct ssb_device *dev, u16 offset, u8 value) | 346 | static void ssb_pcmcia_write8(struct ssb_device *dev, u16 offset, u8 value) |
289 | { | 347 | { |
290 | struct ssb_bus *bus = dev->bus; | 348 | struct ssb_bus *bus = dev->bus; |
@@ -329,6 +387,63 @@ static void ssb_pcmcia_write32(struct ssb_device *dev, u16 offset, u32 value) | |||
329 | spin_unlock_irqrestore(&bus->bar_lock, flags); | 387 | spin_unlock_irqrestore(&bus->bar_lock, flags); |
330 | } | 388 | } |
331 | 389 | ||
390 | #ifdef CONFIG_SSB_BLOCKIO | ||
391 | static void ssb_pcmcia_block_write(struct ssb_device *dev, const void *buffer, | ||
392 | size_t count, u16 offset, u8 reg_width) | ||
393 | { | ||
394 | struct ssb_bus *bus = dev->bus; | ||
395 | unsigned long flags; | ||
396 | void __iomem *addr = bus->mmio + offset; | ||
397 | int err; | ||
398 | |||
399 | spin_lock_irqsave(&bus->bar_lock, flags); | ||
400 | err = select_core_and_segment(dev, &offset); | ||
401 | if (unlikely(err)) | ||
402 | goto unlock; | ||
403 | switch (reg_width) { | ||
404 | case sizeof(u8): { | ||
405 | const u8 *buf = buffer; | ||
406 | |||
407 | while (count) { | ||
408 | __raw_writeb(*buf, addr); | ||
409 | buf++; | ||
410 | count--; | ||
411 | } | ||
412 | break; | ||
413 | } | ||
414 | case sizeof(u16): { | ||
415 | const __le16 *buf = buffer; | ||
416 | |||
417 | SSB_WARN_ON(count & 1); | ||
418 | while (count) { | ||
419 | __raw_writew((__force u16)(*buf), addr); | ||
420 | buf++; | ||
421 | count -= 2; | ||
422 | } | ||
423 | break; | ||
424 | } | ||
425 | case sizeof(u32): { | ||
426 | const __le16 *buf = buffer; | ||
427 | |||
428 | SSB_WARN_ON(count & 3); | ||
429 | while (count) { | ||
430 | __raw_writew((__force u16)(*buf), addr); | ||
431 | buf++; | ||
432 | __raw_writew((__force u16)(*buf), addr + 2); | ||
433 | buf++; | ||
434 | count -= 4; | ||
435 | } | ||
436 | break; | ||
437 | } | ||
438 | default: | ||
439 | SSB_WARN_ON(1); | ||
440 | } | ||
441 | unlock: | ||
442 | mmiowb(); | ||
443 | spin_unlock_irqrestore(&bus->bar_lock, flags); | ||
444 | } | ||
445 | #endif /* CONFIG_SSB_BLOCKIO */ | ||
446 | |||
332 | /* Not "static", as it's used in main.c */ | 447 | /* Not "static", as it's used in main.c */ |
333 | const struct ssb_bus_ops ssb_pcmcia_ops = { | 448 | const struct ssb_bus_ops ssb_pcmcia_ops = { |
334 | .read8 = ssb_pcmcia_read8, | 449 | .read8 = ssb_pcmcia_read8, |
@@ -337,6 +452,10 @@ const struct ssb_bus_ops ssb_pcmcia_ops = { | |||
337 | .write8 = ssb_pcmcia_write8, | 452 | .write8 = ssb_pcmcia_write8, |
338 | .write16 = ssb_pcmcia_write16, | 453 | .write16 = ssb_pcmcia_write16, |
339 | .write32 = ssb_pcmcia_write32, | 454 | .write32 = ssb_pcmcia_write32, |
455 | #ifdef CONFIG_SSB_BLOCKIO | ||
456 | .block_read = ssb_pcmcia_block_read, | ||
457 | .block_write = ssb_pcmcia_block_write, | ||
458 | #endif | ||
340 | }; | 459 | }; |
341 | 460 | ||
342 | static int ssb_pcmcia_sprom_command(struct ssb_bus *bus, u8 command) | 461 | static int ssb_pcmcia_sprom_command(struct ssb_bus *bus, u8 command) |