Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[POWERPC] 4xx: PLB to PCI 2.x support

This adds to the previous patch the support for the 4xx PCI 2.x
bridges.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Josh Boyer <jwboyer@linux.vnet.ibm.com>

authored by

Benjamin Herrenschmidt and committed by
Josh Boyer
c839e0ef 5738ec6d

+198 -1
+179 -1
arch/powerpc/sysdev/ppc4xx_pci.c
··· 21 21 /* Move that to a useable header */ 22 22 extern unsigned long total_memory; 23 23 24 + static void fixup_ppc4xx_pci_bridge(struct pci_dev *dev) 25 + { 26 + struct pci_controller *hose; 27 + int i; 28 + 29 + if (dev->devfn != 0 || dev->bus->self != NULL) 30 + return; 31 + 32 + hose = pci_bus_to_host(dev->bus); 33 + if (hose == NULL) 34 + return; 35 + 36 + if (!of_device_is_compatible(hose->dn, "ibm,plb-pciex") && 37 + !of_device_is_compatible(hose->dn, "ibm,plb-pcix") && 38 + !of_device_is_compatible(hose->dn, "ibm,plb-pci")) 39 + return; 40 + 41 + /* Hide the PCI host BARs from the kernel as their content doesn't 42 + * fit well in the resource management 43 + */ 44 + for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { 45 + dev->resource[i].start = dev->resource[i].end = 0; 46 + dev->resource[i].flags = 0; 47 + } 48 + 49 + printk(KERN_INFO "PCI: Hiding 4xx host bridge resources %s\n", 50 + pci_name(dev)); 51 + } 52 + DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, fixup_ppc4xx_pci_bridge); 53 + 24 54 static int __init ppc4xx_parse_dma_ranges(struct pci_controller *hose, 25 55 void __iomem *reg, 26 56 struct resource *res) ··· 156 126 /* 157 127 * 4xx PCI 2.x part 158 128 */ 129 + 130 + static void __init ppc4xx_configure_pci_PMMs(struct pci_controller *hose, 131 + void __iomem *reg) 132 + { 133 + u32 la, ma, pcila, pciha; 134 + int i, j; 135 + 136 + /* Setup outbound memory windows */ 137 + for (i = j = 0; i < 3; i++) { 138 + struct resource *res = &hose->mem_resources[i]; 139 + 140 + /* we only care about memory windows */ 141 + if (!(res->flags & IORESOURCE_MEM)) 142 + continue; 143 + if (j > 2) { 144 + printk(KERN_WARNING "%s: Too many ranges\n", 145 + hose->dn->full_name); 146 + break; 147 + } 148 + 149 + /* Calculate register values */ 150 + la = res->start; 151 + #ifdef CONFIG_RESOURCES_64BIT 152 + pciha = (res->start - hose->pci_mem_offset) >> 32; 153 + pcila = (res->start - hose->pci_mem_offset) & 0xffffffffu; 154 + #else 155 + pciha = 0; 156 + pcila = res->start - hose->pci_mem_offset; 157 + #endif 158 + 159 + ma = res->end + 1 - res->start; 160 + if (!is_power_of_2(ma) || ma < 0x1000 || ma > 0xffffffffu) { 161 + printk(KERN_WARNING "%s: Resource out of range\n", 162 + hose->dn->full_name); 163 + continue; 164 + } 165 + ma = (0xffffffffu << ilog2(ma)) | 0x1; 166 + if (res->flags & IORESOURCE_PREFETCH) 167 + ma |= 0x2; 168 + 169 + /* Program register values */ 170 + writel(la, reg + PCIL0_PMM0LA + (0x10 * j)); 171 + writel(pcila, reg + PCIL0_PMM0PCILA + (0x10 * j)); 172 + writel(pciha, reg + PCIL0_PMM0PCIHA + (0x10 * j)); 173 + writel(ma, reg + PCIL0_PMM0MA + (0x10 * j)); 174 + j++; 175 + } 176 + } 177 + 178 + static void __init ppc4xx_configure_pci_PTMs(struct pci_controller *hose, 179 + void __iomem *reg, 180 + const struct resource *res) 181 + { 182 + resource_size_t size = res->end - res->start + 1; 183 + u32 sa; 184 + 185 + /* Calculate window size */ 186 + sa = (0xffffffffu << ilog2(size)) | 1; 187 + sa |= 0x1; 188 + 189 + /* RAM is always at 0 local for now */ 190 + writel(0, reg + PCIL0_PTM1LA); 191 + writel(sa, reg + PCIL0_PTM1MS); 192 + 193 + /* Map on PCI side */ 194 + early_write_config_dword(hose, hose->first_busno, 0, 195 + PCI_BASE_ADDRESS_1, res->start); 196 + early_write_config_dword(hose, hose->first_busno, 0, 197 + PCI_BASE_ADDRESS_2, 0x00000000); 198 + early_write_config_word(hose, hose->first_busno, 0, 199 + PCI_COMMAND, 0x0006); 200 + } 201 + 159 202 static void __init ppc4xx_probe_pci_bridge(struct device_node *np) 160 203 { 161 204 /* NYI */ 205 + struct resource rsrc_cfg; 206 + struct resource rsrc_reg; 207 + struct resource dma_window; 208 + struct pci_controller *hose = NULL; 209 + void __iomem *reg = NULL; 210 + const int *bus_range; 211 + int primary = 0; 212 + 213 + /* Fetch config space registers address */ 214 + if (of_address_to_resource(np, 0, &rsrc_cfg)) { 215 + printk(KERN_ERR "%s:Can't get PCI config register base !", 216 + np->full_name); 217 + return; 218 + } 219 + /* Fetch host bridge internal registers address */ 220 + if (of_address_to_resource(np, 3, &rsrc_reg)) { 221 + printk(KERN_ERR "%s: Can't get PCI internal register base !", 222 + np->full_name); 223 + return; 224 + } 225 + 226 + /* Check if primary bridge */ 227 + if (of_get_property(np, "primary", NULL)) 228 + primary = 1; 229 + 230 + /* Get bus range if any */ 231 + bus_range = of_get_property(np, "bus-range", NULL); 232 + 233 + /* Map registers */ 234 + reg = ioremap(rsrc_reg.start, rsrc_reg.end + 1 - rsrc_reg.start); 235 + if (reg == NULL) { 236 + printk(KERN_ERR "%s: Can't map registers !", np->full_name); 237 + goto fail; 238 + } 239 + 240 + /* Allocate the host controller data structure */ 241 + hose = pcibios_alloc_controller(np); 242 + if (!hose) 243 + goto fail; 244 + 245 + hose->first_busno = bus_range ? bus_range[0] : 0x0; 246 + hose->last_busno = bus_range ? bus_range[1] : 0xff; 247 + 248 + /* Setup config space */ 249 + setup_indirect_pci(hose, rsrc_cfg.start, rsrc_cfg.start + 0x4, 0); 250 + 251 + /* Disable all windows */ 252 + writel(0, reg + PCIL0_PMM0MA); 253 + writel(0, reg + PCIL0_PMM1MA); 254 + writel(0, reg + PCIL0_PMM2MA); 255 + writel(0, reg + PCIL0_PTM1MS); 256 + writel(0, reg + PCIL0_PTM2MS); 257 + 258 + /* Parse outbound mapping resources */ 259 + pci_process_bridge_OF_ranges(hose, np, primary); 260 + 261 + /* Parse inbound mapping resources */ 262 + if (ppc4xx_parse_dma_ranges(hose, reg, &dma_window) != 0) 263 + goto fail; 264 + 265 + /* Configure outbound ranges POMs */ 266 + ppc4xx_configure_pci_PMMs(hose, reg); 267 + 268 + /* Configure inbound ranges PIMs */ 269 + ppc4xx_configure_pci_PTMs(hose, reg, &dma_window); 270 + 271 + /* We don't need the registers anymore */ 272 + iounmap(reg); 273 + return; 274 + 275 + fail: 276 + if (hose) 277 + pcibios_free_controller(hose); 278 + if (reg) 279 + iounmap(reg); 162 280 } 163 281 164 282 /* ··· 333 155 } 334 156 335 157 /* Calculate register values */ 336 - #ifdef CONFIG_PTE_64BIT 158 + #ifdef CONFIG_RESOURCES_64BIT 337 159 lah = res->start >> 32; 338 160 lal = res->start & 0xffffffffu; 339 161 pciah = (res->start - hose->pci_mem_offset) >> 32;
+19
arch/powerpc/sysdev/ppc4xx_pci.h
··· 101 101 #define PCIX0_MSGOH 0x10c 102 102 #define PCIX0_IM 0x1f8 103 103 104 + /* 105 + * 4xx PCI bridge register definitions 106 + */ 107 + #define PCIL0_PMM0LA 0x00 108 + #define PCIL0_PMM0MA 0x04 109 + #define PCIL0_PMM0PCILA 0x08 110 + #define PCIL0_PMM0PCIHA 0x0c 111 + #define PCIL0_PMM1LA 0x10 112 + #define PCIL0_PMM1MA 0x14 113 + #define PCIL0_PMM1PCILA 0x18 114 + #define PCIL0_PMM1PCIHA 0x1c 115 + #define PCIL0_PMM2LA 0x20 116 + #define PCIL0_PMM2MA 0x24 117 + #define PCIL0_PMM2PCILA 0x28 118 + #define PCIL0_PMM2PCIHA 0x2c 119 + #define PCIL0_PTM1MS 0x30 120 + #define PCIL0_PTM1LA 0x34 121 + #define PCIL0_PTM2MS 0x38 122 + #define PCIL0_PTM2LA 0x3c 104 123 105 124 106 125 #endif /* __PPC4XX_PCI_H__ */