diff options
author | Thomas Petazzoni <thomas.petazzoni@free-electrons.com> | 2013-03-26 13:14:24 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2013-04-03 11:56:11 -0400 |
commit | 029baf14a027a44b3ac8a9fe5cb1e516cbb9007e (patch) | |
tree | 5d60490910a4015db3690f10ddaa64c7aaf6a7d5 | |
parent | 01223f365074d62bbc24709dad9b4a905206fa02 (diff) |
ARM: 7683/1: pci: add a align_resource hook
The PCI specifications says that an I/O region must be aligned on a 4
KB boundary, and a memory region aligned on a 1 MB boundary.
However, the Marvell PCIe interfaces rely on address decoding windows
(which allow to associate a range of physical addresses with a given
device). For PCIe memory windows, those windows are defined with a 1
MB granularity (which matches the PCI specs), but PCIe I/O windows can
only be defined with a 64 KB granularity, so they have to be 64 KB
aligned. We therefore need to tell the PCI core about this special
alignement requirement.
The PCI core already calls pcibios_align_resource() in the ARM PCI
core, specifically for such purposes. So this patch extends the ARM
PCI core so that it calls a ->align_resource() hook registered by the
PCI driver, exactly like the existing ->map_irq() and ->swizzle()
hooks.
A particular PCI driver can register a align_resource() hook, and do
its own specific alignement, depending on the specific constraints of
the underlying hardware.
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-rw-r--r-- | arch/arm/include/asm/mach/pci.h | 11 | ||||
-rw-r--r-- | arch/arm/kernel/bios32.c | 6 |
2 files changed, 17 insertions, 0 deletions
diff --git a/arch/arm/include/asm/mach/pci.h b/arch/arm/include/asm/mach/pci.h index 5cf2e979b4be..7d2c3c843801 100644 --- a/arch/arm/include/asm/mach/pci.h +++ b/arch/arm/include/asm/mach/pci.h | |||
@@ -30,6 +30,11 @@ struct hw_pci { | |||
30 | void (*postinit)(void); | 30 | void (*postinit)(void); |
31 | u8 (*swizzle)(struct pci_dev *dev, u8 *pin); | 31 | u8 (*swizzle)(struct pci_dev *dev, u8 *pin); |
32 | int (*map_irq)(const struct pci_dev *dev, u8 slot, u8 pin); | 32 | int (*map_irq)(const struct pci_dev *dev, u8 slot, u8 pin); |
33 | resource_size_t (*align_resource)(struct pci_dev *dev, | ||
34 | const struct resource *res, | ||
35 | resource_size_t start, | ||
36 | resource_size_t size, | ||
37 | resource_size_t align); | ||
33 | }; | 38 | }; |
34 | 39 | ||
35 | /* | 40 | /* |
@@ -51,6 +56,12 @@ struct pci_sys_data { | |||
51 | u8 (*swizzle)(struct pci_dev *, u8 *); | 56 | u8 (*swizzle)(struct pci_dev *, u8 *); |
52 | /* IRQ mapping */ | 57 | /* IRQ mapping */ |
53 | int (*map_irq)(const struct pci_dev *, u8, u8); | 58 | int (*map_irq)(const struct pci_dev *, u8, u8); |
59 | /* Resource alignement requirements */ | ||
60 | resource_size_t (*align_resource)(struct pci_dev *dev, | ||
61 | const struct resource *res, | ||
62 | resource_size_t start, | ||
63 | resource_size_t size, | ||
64 | resource_size_t align); | ||
54 | void *private_data; /* platform controller private data */ | 65 | void *private_data; /* platform controller private data */ |
55 | }; | 66 | }; |
56 | 67 | ||
diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c index a1f73b502ef0..b2ed73c45489 100644 --- a/arch/arm/kernel/bios32.c +++ b/arch/arm/kernel/bios32.c | |||
@@ -462,6 +462,7 @@ static void pcibios_init_hw(struct hw_pci *hw, struct list_head *head) | |||
462 | sys->busnr = busnr; | 462 | sys->busnr = busnr; |
463 | sys->swizzle = hw->swizzle; | 463 | sys->swizzle = hw->swizzle; |
464 | sys->map_irq = hw->map_irq; | 464 | sys->map_irq = hw->map_irq; |
465 | sys->align_resource = hw->align_resource; | ||
465 | INIT_LIST_HEAD(&sys->resources); | 466 | INIT_LIST_HEAD(&sys->resources); |
466 | 467 | ||
467 | if (hw->private_data) | 468 | if (hw->private_data) |
@@ -574,6 +575,8 @@ char * __init pcibios_setup(char *str) | |||
574 | resource_size_t pcibios_align_resource(void *data, const struct resource *res, | 575 | resource_size_t pcibios_align_resource(void *data, const struct resource *res, |
575 | resource_size_t size, resource_size_t align) | 576 | resource_size_t size, resource_size_t align) |
576 | { | 577 | { |
578 | struct pci_dev *dev = data; | ||
579 | struct pci_sys_data *sys = dev->sysdata; | ||
577 | resource_size_t start = res->start; | 580 | resource_size_t start = res->start; |
578 | 581 | ||
579 | if (res->flags & IORESOURCE_IO && start & 0x300) | 582 | if (res->flags & IORESOURCE_IO && start & 0x300) |
@@ -581,6 +584,9 @@ resource_size_t pcibios_align_resource(void *data, const struct resource *res, | |||
581 | 584 | ||
582 | start = (start + align - 1) & ~(align - 1); | 585 | start = (start + align - 1) & ~(align - 1); |
583 | 586 | ||
587 | if (sys->align_resource) | ||
588 | return sys->align_resource(dev, res, start, size, align); | ||
589 | |||
584 | return start; | 590 | return start; |
585 | } | 591 | } |
586 | 592 | ||