1 /* 2 * Generic PCI host controller as described in PCI Bus Binding to Open Firmware 3 * 4 * Copyright (C) 2016, Red Hat Inc, Alexander Gordeev <agordeev@redhat.com> 5 * 6 * This work is licensed under the terms of the GNU LGPL, version 2. 7 */ 8 #include "libcflat.h" 9 #include "devicetree.h" 10 #include "alloc.h" 11 #include "pci.h" 12 #include "asm/pci.h" 13 #include "asm/io.h" 14 #include "pci-host-generic.h" 15 #include <linux/pci_regs.h> 16 17 static struct pci_host_bridge *pci_host_bridge; 18 19 static int of_flags_to_pci_type(u32 of_flags) 20 { 21 static int type_map[] = { 22 [1] = PCI_BASE_ADDRESS_SPACE_IO, 23 [2] = PCI_BASE_ADDRESS_MEM_TYPE_32, 24 [3] = PCI_BASE_ADDRESS_MEM_TYPE_64 25 }; 26 int idx = (of_flags >> 24) & 0x03; 27 int res; 28 29 assert(idx > 0); 30 res = type_map[idx]; 31 32 if (of_flags & 0x40000000) 33 res |= PCI_BASE_ADDRESS_MEM_PREFETCH; 34 35 return res; 36 } 37 38 static int pci_bar_type(u32 bar) 39 { 40 if (bar & PCI_BASE_ADDRESS_SPACE) 41 return PCI_BASE_ADDRESS_SPACE_IO; 42 else 43 return bar & (PCI_BASE_ADDRESS_MEM_TYPE_MASK | 44 PCI_BASE_ADDRESS_MEM_PREFETCH); 45 } 46 47 /* 48 * Probe DT for a generic PCI host controller 49 * See kernel Documentation/devicetree/bindings/pci/host-generic-pci.txt 50 * and function gen_pci_probe() in drivers/pci/host/pci-host-generic.c 51 */ 52 static struct pci_host_bridge *pci_dt_probe(void) 53 { 54 struct pci_host_bridge *host; 55 const void *fdt = dt_fdt(); 56 const struct fdt_property *prop; 57 struct dt_pbus_reg base; 58 struct dt_device dt_dev; 59 struct dt_bus dt_bus; 60 struct pci_addr_space *as; 61 fdt32_t *data; 62 u32 bus, bus_max; 63 u32 nac, nsc, nac_root, nsc_root; 64 int nr_range_cells, nr_addr_spaces; 65 int ret, node, len, i; 66 67 if (!dt_available()) { 68 printf("No device tree found\n"); 69 return NULL; 70 } 71 72 dt_bus_init_defaults(&dt_bus); 73 dt_device_init(&dt_dev, &dt_bus, NULL); 74 75 node = fdt_path_offset(fdt, "/"); 76 assert(node >= 0); 77 78 ret = dt_get_nr_cells(node, &nac_root, &nsc_root); 79 assert(ret == 0); 80 assert(nac_root == 1 || nac_root == 2); 81 82 node = fdt_node_offset_by_compatible(fdt, node, 83 "pci-host-ecam-generic"); 84 if (node == -FDT_ERR_NOTFOUND) { 85 printf("No PCIe ECAM compatible controller found\n"); 86 return NULL; 87 } 88 assert(node >= 0); 89 90 prop = fdt_get_property(fdt, node, "device_type", &len); 91 assert(prop && len == 4 && !strcmp((char *)prop->data, "pci")); 92 93 dt_device_bind_node(&dt_dev, node); 94 ret = dt_pbus_get_base(&dt_dev, &base); 95 assert(ret == 0); 96 97 prop = fdt_get_property(fdt, node, "bus-range", &len); 98 if (prop == NULL) { 99 assert(len == -FDT_ERR_NOTFOUND); 100 bus = 0x00; 101 bus_max = 0xff; 102 } else { 103 data = (fdt32_t *)prop->data; 104 bus = fdt32_to_cpu(data[0]); 105 bus_max = fdt32_to_cpu(data[1]); 106 assert(bus <= bus_max); 107 } 108 assert(bus_max < base.size / (1 << PCI_ECAM_BUS_SHIFT)); 109 110 ret = dt_get_nr_cells(node, &nac, &nsc); 111 assert(ret == 0); 112 assert(nac == 3 && nsc == 2); 113 114 prop = fdt_get_property(fdt, node, "ranges", &len); 115 assert(prop != NULL); 116 117 nr_range_cells = nac + nsc + nac_root; 118 nr_addr_spaces = (len / 4) / nr_range_cells; 119 assert(nr_addr_spaces); 120 121 host = malloc(sizeof(*host) + 122 sizeof(host->addr_space[0]) * nr_addr_spaces); 123 assert(host != NULL); 124 125 host->start = base.addr; 126 host->size = base.size; 127 host->bus = bus; 128 host->bus_max = bus_max; 129 host->nr_addr_spaces = nr_addr_spaces; 130 131 data = (fdt32_t *)prop->data; 132 as = &host->addr_space[0]; 133 134 for (i = 0; i < nr_addr_spaces; i++) { 135 /* 136 * The PCI binding encodes the PCI address with three 137 * cells as follows: 138 * 139 * phys.hi cell: npt000ss bbbbbbbb dddddfff rrrrrrrr 140 * phys.mid cell: hhhhhhhh hhhhhhhh hhhhhhhh hhhhhhhh 141 * phys.lo cell: llllllll llllllll llllllll llllllll 142 * 143 * PCI device bus address and flags are encoded into phys.high 144 * PCI 64 bit address is encoded into phys.mid and phys.low 145 */ 146 as->type = of_flags_to_pci_type(fdt32_to_cpu(data[0])); 147 as->pci_start = ((u64)fdt32_to_cpu(data[1]) << 32) | 148 fdt32_to_cpu(data[2]); 149 150 if (nr_range_cells == 6) { 151 as->start = fdt32_to_cpu(data[3]); 152 as->size = ((u64)fdt32_to_cpu(data[4]) << 32) | 153 fdt32_to_cpu(data[5]); 154 } else { 155 as->start = ((u64)fdt32_to_cpu(data[3]) << 32) | 156 fdt32_to_cpu(data[4]); 157 as->size = ((u64)fdt32_to_cpu(data[5]) << 32) | 158 fdt32_to_cpu(data[6]); 159 } 160 161 data += nr_range_cells; 162 as++; 163 } 164 165 return host; 166 } 167 168 static bool pci_alloc_resource(pcidevaddr_t dev, int bar_num, u64 *addr) 169 { 170 struct pci_host_bridge *host = pci_host_bridge; 171 struct pci_addr_space *as = &host->addr_space[0]; 172 u32 mask, bar; 173 u64 size; 174 int type, i; 175 176 *addr = ~0; 177 178 size = pci_bar_size(dev, bar_num); 179 if (!size) 180 return false; 181 182 bar = pci_bar_get(dev, bar_num); 183 type = pci_bar_type(bar); 184 if (type & PCI_BASE_ADDRESS_MEM_TYPE_MASK) 185 type &= ~PCI_BASE_ADDRESS_MEM_PREFETCH; 186 187 for (i = 0; i < host->nr_addr_spaces; i++) { 188 if (as->type == type) 189 break; 190 as++; 191 } 192 193 if (i >= host->nr_addr_spaces) { 194 printf("%s: warning: can't satisfy request for ", __func__); 195 pci_dev_print_id(dev); 196 printf(" "); 197 pci_bar_print(dev, bar_num); 198 printf("\n"); 199 return false; 200 } 201 202 mask = pci_bar_mask(bar); 203 size = ALIGN(size, ~mask + 1); 204 assert(as->allocated + size <= as->size); 205 206 *addr = as->pci_start + as->allocated; 207 as->allocated += size; 208 209 return true; 210 } 211 212 bool pci_probe(void) 213 { 214 pcidevaddr_t dev; 215 u8 header; 216 u32 cmd; 217 int i; 218 219 assert(!pci_host_bridge); 220 pci_host_bridge = pci_dt_probe(); 221 if (!pci_host_bridge) 222 return false; 223 224 for (dev = 0; dev < 256; dev++) { 225 if (!pci_dev_exists(dev)) 226 continue; 227 228 /* We are only interested in normal PCI devices */ 229 header = pci_config_readb(dev, PCI_HEADER_TYPE); 230 if ((header & PCI_HEADER_TYPE_MASK) != PCI_HEADER_TYPE_NORMAL) 231 continue; 232 233 cmd = PCI_COMMAND_SERR | PCI_COMMAND_PARITY; 234 235 for (i = 0; i < 6; i++) { 236 u64 addr; 237 238 if (pci_alloc_resource(dev, i, &addr)) { 239 pci_bar_set_addr(dev, i, addr); 240 241 if (pci_bar_is_memory(dev, i)) 242 cmd |= PCI_COMMAND_MEMORY; 243 else 244 cmd |= PCI_COMMAND_IO; 245 } 246 247 if (pci_bar_is64(dev, i)) 248 i++; 249 } 250 251 pci_config_writew(dev, PCI_COMMAND, cmd); 252 } 253 254 return true; 255 } 256 257 /* 258 * This function is to be called from pci_translate_addr() to provide 259 * mapping between this host bridge's PCI busses address and CPU physical 260 * address. 261 */ 262 phys_addr_t pci_host_bridge_get_paddr(u64 pci_addr) 263 { 264 struct pci_host_bridge *host = pci_host_bridge; 265 struct pci_addr_space *as = &host->addr_space[0]; 266 int i; 267 268 for (i = 0; i < host->nr_addr_spaces; i++) { 269 if (pci_addr >= as->pci_start && 270 pci_addr < as->pci_start + as->size) 271 return as->start + (pci_addr - as->pci_start); 272 as++; 273 } 274 275 return 0; 276 } 277 278 static void __iomem *pci_get_dev_conf(struct pci_host_bridge *host, int devfn) 279 { 280 return (void __iomem *)(unsigned long) 281 host->start + (devfn << PCI_ECAM_DEVFN_SHIFT); 282 } 283 284 u8 pci_config_readb(pcidevaddr_t dev, u8 off) 285 { 286 void __iomem *conf = pci_get_dev_conf(pci_host_bridge, dev); 287 return readb(conf + off); 288 } 289 290 u16 pci_config_readw(pcidevaddr_t dev, u8 off) 291 { 292 void __iomem *conf = pci_get_dev_conf(pci_host_bridge, dev); 293 return readw(conf + off); 294 } 295 296 u32 pci_config_readl(pcidevaddr_t dev, u8 off) 297 { 298 void __iomem *conf = pci_get_dev_conf(pci_host_bridge, dev); 299 return readl(conf + off); 300 } 301 302 void pci_config_writeb(pcidevaddr_t dev, u8 off, u8 val) 303 { 304 void __iomem *conf = pci_get_dev_conf(pci_host_bridge, dev); 305 writeb(val, conf + off); 306 } 307 308 void pci_config_writew(pcidevaddr_t dev, u8 off, u16 val) 309 { 310 void __iomem *conf = pci_get_dev_conf(pci_host_bridge, dev); 311 writew(val, conf + off); 312 } 313 314 void pci_config_writel(pcidevaddr_t dev, u8 off, u32 val) 315 { 316 void __iomem *conf = pci_get_dev_conf(pci_host_bridge, dev); 317 writel(val, conf + off); 318 } 319