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 = ioremap(base.addr, base.size); 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(struct pci_dev *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 bar; 173 u64 size, pci_addr; 174 int type, i; 175 176 *addr = INVALID_PHYS_ADDR; 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 pci_addr = ALIGN(as->pci_start + as->allocated, size); 203 size += pci_addr - (as->pci_start + as->allocated); 204 assert(as->allocated + size <= as->size); 205 *addr = pci_addr; 206 as->allocated += size; 207 208 return true; 209 } 210 211 bool pci_probe(void) 212 { 213 struct pci_dev pci_dev; 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 < PCI_DEVFN_MAX; dev++) { 225 if (!pci_dev_exists(dev)) 226 continue; 227 228 pci_dev_init(&pci_dev, dev); 229 230 /* We are only interested in normal PCI devices */ 231 header = pci_config_readb(dev, PCI_HEADER_TYPE); 232 if ((header & PCI_HEADER_TYPE_MASK) != PCI_HEADER_TYPE_NORMAL) 233 continue; 234 235 cmd = PCI_COMMAND_SERR | PCI_COMMAND_PARITY; 236 237 for (i = 0; i < PCI_BAR_NUM; i++) { 238 u64 addr; 239 240 if (pci_alloc_resource(&pci_dev, i, &addr)) { 241 pci_bar_set_addr(&pci_dev, i, addr); 242 243 if (pci_bar_is_memory(&pci_dev, i)) 244 cmd |= PCI_COMMAND_MEMORY; 245 else 246 cmd |= PCI_COMMAND_IO; 247 } 248 249 if (pci_bar_is64(&pci_dev, i)) 250 i++; 251 } 252 253 pci_config_writew(dev, PCI_COMMAND, cmd); 254 } 255 256 return true; 257 } 258 259 /* 260 * This function is to be called from pci_translate_addr() to provide 261 * mapping between this host bridge's PCI busses address and CPU physical 262 * address. 263 */ 264 phys_addr_t pci_host_bridge_get_paddr(u64 pci_addr) 265 { 266 struct pci_host_bridge *host = pci_host_bridge; 267 struct pci_addr_space *as = &host->addr_space[0]; 268 int i; 269 270 for (i = 0; i < host->nr_addr_spaces; i++) { 271 if (pci_addr >= as->pci_start && 272 pci_addr < as->pci_start + as->size) 273 return as->start + (pci_addr - as->pci_start); 274 as++; 275 } 276 277 return INVALID_PHYS_ADDR; 278 } 279 280 static void __iomem *pci_get_dev_conf(struct pci_host_bridge *host, int devfn) 281 { 282 return host->start + (devfn << PCI_ECAM_DEVFN_SHIFT); 283 } 284 285 u8 pci_config_readb(pcidevaddr_t dev, u8 off) 286 { 287 void __iomem *conf = pci_get_dev_conf(pci_host_bridge, dev); 288 return readb(conf + off); 289 } 290 291 u16 pci_config_readw(pcidevaddr_t dev, u8 off) 292 { 293 void __iomem *conf = pci_get_dev_conf(pci_host_bridge, dev); 294 return readw(conf + off); 295 } 296 297 u32 pci_config_readl(pcidevaddr_t dev, u8 off) 298 { 299 void __iomem *conf = pci_get_dev_conf(pci_host_bridge, dev); 300 return readl(conf + off); 301 } 302 303 void pci_config_writeb(pcidevaddr_t dev, u8 off, u8 val) 304 { 305 void __iomem *conf = pci_get_dev_conf(pci_host_bridge, dev); 306 writeb(val, conf + off); 307 } 308 309 void pci_config_writew(pcidevaddr_t dev, u8 off, u16 val) 310 { 311 void __iomem *conf = pci_get_dev_conf(pci_host_bridge, dev); 312 writew(val, conf + off); 313 } 314 315 void pci_config_writel(pcidevaddr_t dev, u8 off, u32 val) 316 { 317 void __iomem *conf = pci_get_dev_conf(pci_host_bridge, dev); 318 writel(val, conf + off); 319 } 320