diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2007-06-04 01:15:36 -0400 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2007-06-14 08:29:56 -0400 |
commit | 3d5134ee8341bffc4f539049abb9e90d469b448d (patch) | |
tree | 037958e0daa97b4ef350908a53182167ee2c8a03 /include/asm-powerpc | |
parent | c19c03fc749147f565e807fa65f1729066800571 (diff) |
[POWERPC] Rewrite IO allocation & mapping on powerpc64
This rewrites pretty much from scratch the handling of MMIO and PIO
space allocations on powerpc64. The main goals are:
- Get rid of imalloc and use more common code where possible
- Simplify the current mess so that PIO space is allocated and
mapped in a single place for PCI bridges
- Handle allocation constraints of PIO for all bridges including
hot plugged ones within the 2GB space reserved for IO ports,
so that devices on hotplugged busses will now work with drivers
that assume IO ports fit in an int.
- Cleanup and separate tracking of the ISA space in the reserved
low 64K of IO space. No ISA -> Nothing mapped there.
I booted a cell blade with IDE on PIO and MMIO and a dual G5 so
far, that's it :-)
With this patch, all allocations are done using the code in
mm/vmalloc.c, though we use the low level __get_vm_area with
explicit start/stop constraints in order to manage separate
areas for vmalloc/vmap, ioremap, and PCI IOs.
This greatly simplifies a lot of things, as you can see in the
diffstat of that patch :-)
A new pair of functions pcibios_map/unmap_io_space() now replace
all of the previous code that used to manipulate PCI IOs space.
The allocation is done at mapping time, which is now called from
scan_phb's, just before the devices are probed (instead of after,
which is by itself a bug fix). The only other caller is the PCI
hotplug code for hot adding PCI-PCI bridges (slots).
imalloc is gone, as is the "sub-allocation" thing, but I do beleive
that hotplug should still work in the sense that the space allocation
is always done by the PHB, but if you unmap a child bus of this PHB
(which seems to be possible), then the code should properly tear
down all the HPTE mappings for that area of the PHB allocated IO space.
I now always reserve the first 64K of IO space for the bridge with
the ISA bus on it. I have moved the code for tracking ISA in a separate
file which should also make it smarter if we ever are capable of
hot unplugging or re-plugging an ISA bridge.
This should have a side effect on platforms like powermac where VGA IOs
will no longer work. This is done on purpose though as they would have
worked semi-randomly before. The idea at this point is to isolate drivers
that might need to access those and fix them by providing a proper
function to obtain an offset to the legacy IOs of a given bus.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'include/asm-powerpc')
-rw-r--r-- | include/asm-powerpc/floppy.h | 6 | ||||
-rw-r--r-- | include/asm-powerpc/io.h | 19 | ||||
-rw-r--r-- | include/asm-powerpc/pci-bridge.h | 6 | ||||
-rw-r--r-- | include/asm-powerpc/pci.h | 4 | ||||
-rw-r--r-- | include/asm-powerpc/pgtable-ppc64.h | 21 | ||||
-rw-r--r-- | include/asm-powerpc/ppc-pci.h | 6 | ||||
-rw-r--r-- | include/asm-powerpc/tlbflush.h | 5 |
7 files changed, 40 insertions, 27 deletions
diff --git a/include/asm-powerpc/floppy.h b/include/asm-powerpc/floppy.h index afa700ded877..34146f0eea63 100644 --- a/include/asm-powerpc/floppy.h +++ b/include/asm-powerpc/floppy.h | |||
@@ -29,7 +29,7 @@ | |||
29 | #define fd_free_irq() free_irq(FLOPPY_IRQ, NULL); | 29 | #define fd_free_irq() free_irq(FLOPPY_IRQ, NULL); |
30 | 30 | ||
31 | #include <linux/pci.h> | 31 | #include <linux/pci.h> |
32 | #include <asm/ppc-pci.h> /* for ppc64_isabridge_dev */ | 32 | #include <asm/ppc-pci.h> /* for isa_bridge_pcidev */ |
33 | 33 | ||
34 | #define fd_dma_setup(addr,size,mode,io) fd_ops->_dma_setup(addr,size,mode,io) | 34 | #define fd_dma_setup(addr,size,mode,io) fd_ops->_dma_setup(addr,size,mode,io) |
35 | 35 | ||
@@ -139,12 +139,12 @@ static int hard_dma_setup(char *addr, unsigned long size, int mode, int io) | |||
139 | if (bus_addr | 139 | if (bus_addr |
140 | && (addr != prev_addr || size != prev_size || dir != prev_dir)) { | 140 | && (addr != prev_addr || size != prev_size || dir != prev_dir)) { |
141 | /* different from last time -- unmap prev */ | 141 | /* different from last time -- unmap prev */ |
142 | pci_unmap_single(ppc64_isabridge_dev, bus_addr, prev_size, prev_dir); | 142 | pci_unmap_single(isa_bridge_pcidev, bus_addr, prev_size, prev_dir); |
143 | bus_addr = 0; | 143 | bus_addr = 0; |
144 | } | 144 | } |
145 | 145 | ||
146 | if (!bus_addr) /* need to map it */ | 146 | if (!bus_addr) /* need to map it */ |
147 | bus_addr = pci_map_single(ppc64_isabridge_dev, addr, size, dir); | 147 | bus_addr = pci_map_single(isa_bridge_pcidev, addr, size, dir); |
148 | 148 | ||
149 | /* remember this one as prev */ | 149 | /* remember this one as prev */ |
150 | prev_addr = addr; | 150 | prev_addr = addr; |
diff --git a/include/asm-powerpc/io.h b/include/asm-powerpc/io.h index 350c9bdb31dc..17efea5b594c 100644 --- a/include/asm-powerpc/io.h +++ b/include/asm-powerpc/io.h | |||
@@ -607,9 +607,9 @@ static inline void iosync(void) | |||
607 | * | 607 | * |
608 | * * iounmap undoes such a mapping and can be hooked | 608 | * * iounmap undoes such a mapping and can be hooked |
609 | * | 609 | * |
610 | * * __ioremap_explicit (and the pending __iounmap_explicit) are low level | 610 | * * __ioremap_at (and the pending __iounmap_at) are low level functions to |
611 | * functions to create hand-made mappings for use only by the PCI code | 611 | * create hand-made mappings for use only by the PCI code and cannot |
612 | * and cannot currently be hooked. | 612 | * currently be hooked. Must be page aligned. |
613 | * | 613 | * |
614 | * * __ioremap is the low level implementation used by ioremap and | 614 | * * __ioremap is the low level implementation used by ioremap and |
615 | * ioremap_flags and cannot be hooked (but can be used by a hook on one | 615 | * ioremap_flags and cannot be hooked (but can be used by a hook on one |
@@ -629,12 +629,9 @@ extern void __iomem *__ioremap(phys_addr_t, unsigned long size, | |||
629 | unsigned long flags); | 629 | unsigned long flags); |
630 | extern void __iounmap(volatile void __iomem *addr); | 630 | extern void __iounmap(volatile void __iomem *addr); |
631 | 631 | ||
632 | extern int __ioremap_explicit(phys_addr_t p_addr, unsigned long v_addr, | 632 | extern void __iomem * __ioremap_at(phys_addr_t pa, void *ea, |
633 | unsigned long size, unsigned long flags); | 633 | unsigned long size, unsigned long flags); |
634 | extern int __iounmap_explicit(volatile void __iomem *start, | 634 | extern void __iounmap_at(void *ea, unsigned long size); |
635 | unsigned long size); | ||
636 | |||
637 | extern void __iomem * reserve_phb_iospace(unsigned long size); | ||
638 | 635 | ||
639 | /* Those are more 32 bits only functions */ | 636 | /* Those are more 32 bits only functions */ |
640 | extern unsigned long iopa(unsigned long addr); | 637 | extern unsigned long iopa(unsigned long addr); |
@@ -651,8 +648,8 @@ extern void io_block_mapping(unsigned long virt, phys_addr_t phys, | |||
651 | */ | 648 | */ |
652 | #define HAVE_ARCH_PIO_SIZE 1 | 649 | #define HAVE_ARCH_PIO_SIZE 1 |
653 | #define PIO_OFFSET 0x00000000UL | 650 | #define PIO_OFFSET 0x00000000UL |
654 | #define PIO_MASK 0x3fffffffUL | 651 | #define PIO_MASK (FULL_IO_SIZE - 1) |
655 | #define PIO_RESERVED 0x40000000UL | 652 | #define PIO_RESERVED (FULL_IO_SIZE) |
656 | 653 | ||
657 | #define mmio_read16be(addr) readw_be(addr) | 654 | #define mmio_read16be(addr) readw_be(addr) |
658 | #define mmio_read32be(addr) readl_be(addr) | 655 | #define mmio_read32be(addr) readl_be(addr) |
diff --git a/include/asm-powerpc/pci-bridge.h b/include/asm-powerpc/pci-bridge.h index c49ce41cfa95..5261527ed7b1 100644 --- a/include/asm-powerpc/pci-bridge.h +++ b/include/asm-powerpc/pci-bridge.h | |||
@@ -31,6 +31,7 @@ struct pci_controller { | |||
31 | int last_busno; | 31 | int last_busno; |
32 | 32 | ||
33 | void __iomem *io_base_virt; | 33 | void __iomem *io_base_virt; |
34 | void *io_base_alloc; | ||
34 | resource_size_t io_base_phys; | 35 | resource_size_t io_base_phys; |
35 | 36 | ||
36 | /* Some machines have a non 1:1 mapping of | 37 | /* Some machines have a non 1:1 mapping of |
@@ -167,6 +168,11 @@ static inline unsigned long pci_address_to_pio(phys_addr_t address) | |||
167 | } | 168 | } |
168 | #endif | 169 | #endif |
169 | 170 | ||
171 | extern void isa_bridge_find_early(struct pci_controller *hose); | ||
172 | |||
173 | extern int pcibios_unmap_io_space(struct pci_bus *bus); | ||
174 | extern int pcibios_map_io_space(struct pci_bus *bus); | ||
175 | |||
170 | /* Return values for ppc_md.pci_probe_mode function */ | 176 | /* Return values for ppc_md.pci_probe_mode function */ |
171 | #define PCI_PROBE_NONE -1 /* Don't look at this bus at all */ | 177 | #define PCI_PROBE_NONE -1 /* Don't look at this bus at all */ |
172 | #define PCI_PROBE_NORMAL 0 /* Do normal PCI probing */ | 178 | #define PCI_PROBE_NORMAL 0 /* Do normal PCI probing */ |
diff --git a/include/asm-powerpc/pci.h b/include/asm-powerpc/pci.h index ce0f13e8eb14..93e3752df6b7 100644 --- a/include/asm-powerpc/pci.h +++ b/include/asm-powerpc/pci.h | |||
@@ -220,10 +220,6 @@ static inline struct resource *pcibios_select_root(struct pci_dev *pdev, | |||
220 | return root; | 220 | return root; |
221 | } | 221 | } |
222 | 222 | ||
223 | extern int unmap_bus_range(struct pci_bus *bus); | ||
224 | |||
225 | extern int remap_bus_range(struct pci_bus *bus); | ||
226 | |||
227 | extern void pcibios_fixup_device_resources(struct pci_dev *dev, | 223 | extern void pcibios_fixup_device_resources(struct pci_dev *dev, |
228 | struct pci_bus *bus); | 224 | struct pci_bus *bus); |
229 | 225 | ||
diff --git a/include/asm-powerpc/pgtable-ppc64.h b/include/asm-powerpc/pgtable-ppc64.h index 704c4e669fe0..9b0f51ccad05 100644 --- a/include/asm-powerpc/pgtable-ppc64.h +++ b/include/asm-powerpc/pgtable-ppc64.h | |||
@@ -27,7 +27,7 @@ struct mm_struct; | |||
27 | */ | 27 | */ |
28 | #define PGTABLE_EADDR_SIZE (PTE_INDEX_SIZE + PMD_INDEX_SIZE + \ | 28 | #define PGTABLE_EADDR_SIZE (PTE_INDEX_SIZE + PMD_INDEX_SIZE + \ |
29 | PUD_INDEX_SIZE + PGD_INDEX_SIZE + PAGE_SHIFT) | 29 | PUD_INDEX_SIZE + PGD_INDEX_SIZE + PAGE_SHIFT) |
30 | #define PGTABLE_RANGE (1UL << PGTABLE_EADDR_SIZE) | 30 | #define PGTABLE_RANGE (ASM_CONST(1) << PGTABLE_EADDR_SIZE) |
31 | 31 | ||
32 | #if TASK_SIZE_USER64 > PGTABLE_RANGE | 32 | #if TASK_SIZE_USER64 > PGTABLE_RANGE |
33 | #error TASK_SIZE_USER64 exceeds pagetable range | 33 | #error TASK_SIZE_USER64 exceeds pagetable range |
@@ -37,19 +37,28 @@ struct mm_struct; | |||
37 | #error TASK_SIZE_USER64 exceeds user VSID range | 37 | #error TASK_SIZE_USER64 exceeds user VSID range |
38 | #endif | 38 | #endif |
39 | 39 | ||
40 | |||
40 | /* | 41 | /* |
41 | * Define the address range of the vmalloc VM area. | 42 | * Define the address range of the vmalloc VM area. |
42 | */ | 43 | */ |
43 | #define VMALLOC_START ASM_CONST(0xD000000000000000) | 44 | #define VMALLOC_START ASM_CONST(0xD000000000000000) |
44 | #define VMALLOC_SIZE ASM_CONST(0x80000000000) | 45 | #define VMALLOC_SIZE (PGTABLE_RANGE >> 1) |
45 | #define VMALLOC_END (VMALLOC_START + VMALLOC_SIZE) | 46 | #define VMALLOC_END (VMALLOC_START + VMALLOC_SIZE) |
46 | 47 | ||
47 | /* | 48 | /* |
48 | * Define the address range of the imalloc VM area. | 49 | * Define the address ranges for MMIO and IO space : |
50 | * | ||
51 | * ISA_IO_BASE = VMALLOC_END, 64K reserved area | ||
52 | * PHB_IO_BASE = ISA_IO_BASE + 64K to ISA_IO_BASE + 2G, PHB IO spaces | ||
53 | * IOREMAP_BASE = ISA_IO_BASE + 2G to VMALLOC_START + PGTABLE_RANGE | ||
49 | */ | 54 | */ |
50 | #define PHBS_IO_BASE VMALLOC_END | 55 | #define FULL_IO_SIZE 0x80000000ul |
51 | #define IMALLOC_BASE (PHBS_IO_BASE + 0x80000000ul) /* Reserve 2 gigs for PHBs */ | 56 | #define ISA_IO_BASE (VMALLOC_END) |
52 | #define IMALLOC_END (VMALLOC_START + PGTABLE_RANGE) | 57 | #define ISA_IO_END (VMALLOC_END + 0x10000ul) |
58 | #define PHB_IO_BASE (ISA_IO_END) | ||
59 | #define PHB_IO_END (VMALLOC_END + FULL_IO_SIZE) | ||
60 | #define IOREMAP_BASE (PHB_IO_END) | ||
61 | #define IOREMAP_END (VMALLOC_START + PGTABLE_RANGE) | ||
53 | 62 | ||
54 | /* | 63 | /* |
55 | * Region IDs | 64 | * Region IDs |
diff --git a/include/asm-powerpc/ppc-pci.h b/include/asm-powerpc/ppc-pci.h index 2a6ac69cadc9..b847aa10074b 100644 --- a/include/asm-powerpc/ppc-pci.h +++ b/include/asm-powerpc/ppc-pci.h | |||
@@ -26,7 +26,7 @@ extern int global_phb_number; | |||
26 | 26 | ||
27 | extern void find_and_init_phbs(void); | 27 | extern void find_and_init_phbs(void); |
28 | 28 | ||
29 | extern struct pci_dev *ppc64_isabridge_dev; /* may be NULL if no ISA bus */ | 29 | extern struct pci_dev *isa_bridge_pcidev; /* may be NULL if no ISA bus */ |
30 | 30 | ||
31 | /** Bus Unit ID macros; get low and hi 32-bits of the 64-bit BUID */ | 31 | /** Bus Unit ID macros; get low and hi 32-bits of the 64-bit BUID */ |
32 | #define BUID_HI(buid) ((buid) >> 32) | 32 | #define BUID_HI(buid) ((buid) >> 32) |
@@ -47,8 +47,8 @@ extern void init_pci_config_tokens (void); | |||
47 | extern unsigned long get_phb_buid (struct device_node *); | 47 | extern unsigned long get_phb_buid (struct device_node *); |
48 | extern int rtas_setup_phb(struct pci_controller *phb); | 48 | extern int rtas_setup_phb(struct pci_controller *phb); |
49 | 49 | ||
50 | /* From pSeries_pci.h */ | 50 | /* From iSeries PCI */ |
51 | extern void pSeries_final_fixup(void); | 51 | extern void iSeries_pcibios_init(void); |
52 | 52 | ||
53 | extern unsigned long pci_probe_only; | 53 | extern unsigned long pci_probe_only; |
54 | 54 | ||
diff --git a/include/asm-powerpc/tlbflush.h b/include/asm-powerpc/tlbflush.h index 86e6266a028b..99a0439baa50 100644 --- a/include/asm-powerpc/tlbflush.h +++ b/include/asm-powerpc/tlbflush.h | |||
@@ -155,6 +155,11 @@ static inline void flush_tlb_kernel_range(unsigned long start, | |||
155 | { | 155 | { |
156 | } | 156 | } |
157 | 157 | ||
158 | /* Private function for use by PCI IO mapping code */ | ||
159 | extern void __flush_hash_table_range(struct mm_struct *mm, unsigned long start, | ||
160 | unsigned long end); | ||
161 | |||
162 | |||
158 | #endif | 163 | #endif |
159 | 164 | ||
160 | /* | 165 | /* |