1 /* 2 * Copyright (C) 2016 Cavium Inc. 3 * All rights reserved. 4 * 5 * Developed by Semihalf. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 #include "opt_platform.h" 29 30 #include <sys/cdefs.h> 31 __FBSDID("$FreeBSD$"); 32 33 #include <sys/param.h> 34 #include <sys/systm.h> 35 #include <sys/malloc.h> 36 #include <sys/types.h> 37 #include <sys/sysctl.h> 38 #include <sys/kernel.h> 39 #include <sys/rman.h> 40 #include <sys/module.h> 41 #include <sys/bus.h> 42 #include <sys/endian.h> 43 #include <sys/cpuset.h> 44 45 #include <dev/ofw/openfirm.h> 46 #include <dev/ofw/ofw_bus.h> 47 #include <dev/ofw/ofw_bus_subr.h> 48 49 #include <dev/pci/pcireg.h> 50 #include <dev/pci/pcivar.h> 51 #include <dev/pci/pci_host_generic.h> 52 #include <dev/pci/pci_host_generic_fdt.h> 53 #include <dev/pci/pcib_private.h> 54 55 #include "thunder_pcie_common.h" 56 57 #include "pcib_if.h" 58 59 #ifdef THUNDERX_PASS_1_1_ERRATA 60 static struct resource * thunder_pcie_fdt_alloc_resource(device_t, device_t, 61 int, int *, rman_res_t, rman_res_t, rman_res_t, u_int); 62 static int thunder_pcie_fdt_release_resource(device_t, device_t, 63 int, int, struct resource*); 64 #endif 65 static int thunder_pcie_fdt_attach(device_t); 66 static int thunder_pcie_fdt_probe(device_t); 67 static int thunder_pcie_fdt_get_id(device_t, device_t, enum pci_id_type, 68 uintptr_t *); 69 70 static const struct ofw_bus_devinfo *thunder_pcie_ofw_get_devinfo(device_t, 71 device_t); 72 73 /* OFW bus interface */ 74 struct thunder_pcie_ofw_devinfo { 75 struct ofw_bus_devinfo di_dinfo; 76 struct resource_list di_rl; 77 }; 78 79 static device_method_t thunder_pcie_fdt_methods[] = { 80 /* Device interface */ 81 DEVMETHOD(device_probe, thunder_pcie_fdt_probe), 82 DEVMETHOD(device_attach, thunder_pcie_fdt_attach), 83 #ifdef THUNDERX_PASS_1_1_ERRATA 84 DEVMETHOD(bus_alloc_resource, thunder_pcie_fdt_alloc_resource), 85 DEVMETHOD(bus_release_resource, thunder_pcie_fdt_release_resource), 86 #endif 87 88 /* pcib interface */ 89 DEVMETHOD(pcib_get_id, thunder_pcie_fdt_get_id), 90 91 /* ofw interface */ 92 DEVMETHOD(ofw_bus_get_devinfo, thunder_pcie_ofw_get_devinfo), 93 DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), 94 DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), 95 DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), 96 DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), 97 DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), 98 99 /* End */ 100 DEVMETHOD_END 101 }; 102 103 DEFINE_CLASS_1(pcib, thunder_pcie_fdt_driver, thunder_pcie_fdt_methods, 104 sizeof(struct generic_pcie_fdt_softc), generic_pcie_fdt_driver); 105 106 static devclass_t thunder_pcie_fdt_devclass; 107 108 DRIVER_MODULE(thunder_pcib, simplebus, thunder_pcie_fdt_driver, 109 thunder_pcie_fdt_devclass, 0, 0); 110 DRIVER_MODULE(thunder_pcib, ofwbus, thunder_pcie_fdt_driver, 111 thunder_pcie_fdt_devclass, 0, 0); 112 113 static const struct ofw_bus_devinfo * 114 thunder_pcie_ofw_get_devinfo(device_t bus __unused, device_t child) 115 { 116 struct thunder_pcie_ofw_devinfo *di; 117 118 di = device_get_ivars(child); 119 return (&di->di_dinfo); 120 } 121 122 static void 123 get_addr_size_cells(phandle_t node, pcell_t *addr_cells, pcell_t *size_cells) 124 { 125 126 *addr_cells = 2; 127 /* Find address cells if present */ 128 OF_getencprop(node, "#address-cells", addr_cells, sizeof(*addr_cells)); 129 130 *size_cells = 2; 131 /* Find size cells if present */ 132 OF_getencprop(node, "#size-cells", size_cells, sizeof(*size_cells)); 133 } 134 135 static int 136 thunder_pcie_ofw_bus_attach(device_t dev) 137 { 138 struct thunder_pcie_ofw_devinfo *di; 139 device_t child; 140 phandle_t parent, node; 141 pcell_t addr_cells, size_cells; 142 143 parent = ofw_bus_get_node(dev); 144 if (parent > 0) { 145 get_addr_size_cells(parent, &addr_cells, &size_cells); 146 /* Iterate through all bus subordinates */ 147 for (node = OF_child(parent); node > 0; node = OF_peer(node)) { 148 /* Allocate and populate devinfo. */ 149 di = malloc(sizeof(*di), M_DEVBUF, M_WAITOK | M_ZERO); 150 if (ofw_bus_gen_setup_devinfo(&di->di_dinfo, node) != 0) { 151 free(di, M_DEVBUF); 152 continue; 153 } 154 155 /* Initialize and populate resource list. */ 156 resource_list_init(&di->di_rl); 157 ofw_bus_reg_to_rl(dev, node, addr_cells, size_cells, 158 &di->di_rl); 159 ofw_bus_intr_to_rl(dev, node, &di->di_rl, NULL); 160 161 /* Add newbus device for this FDT node */ 162 child = device_add_child(dev, NULL, -1); 163 if (child == NULL) { 164 resource_list_free(&di->di_rl); 165 ofw_bus_gen_destroy_devinfo(&di->di_dinfo); 166 free(di, M_DEVBUF); 167 continue; 168 } 169 170 device_set_ivars(child, di); 171 } 172 } 173 174 return (0); 175 } 176 177 static int 178 thunder_pcie_fdt_probe(device_t dev) 179 { 180 181 /* Check if we're running on Cavium ThunderX */ 182 if (!CPU_MATCH(CPU_IMPL_MASK | CPU_PART_MASK, 183 CPU_IMPL_CAVIUM, CPU_PART_THUNDERX, 0, 0)) 184 return (ENXIO); 185 186 if (!ofw_bus_status_okay(dev)) 187 return (ENXIO); 188 189 if (ofw_bus_is_compatible(dev, "pci-host-ecam-generic") || 190 ofw_bus_is_compatible(dev, "cavium,thunder-pcie") || 191 ofw_bus_is_compatible(dev, "cavium,pci-host-thunder-ecam")) { 192 device_set_desc(dev, "Cavium Integrated PCI/PCI-E Controller"); 193 return (BUS_PROBE_DEFAULT); 194 } 195 196 return (ENXIO); 197 } 198 199 static int 200 thunder_pcie_fdt_attach(device_t dev) 201 { 202 struct generic_pcie_fdt_softc *sc; 203 204 sc = device_get_softc(dev); 205 thunder_pcie_identify_ecam(dev, &sc->base.ecam); 206 sc->base.coherent = 1; 207 208 /* Attach OFW bus */ 209 if (thunder_pcie_ofw_bus_attach(dev) != 0) 210 return (ENXIO); 211 212 return (pci_host_generic_attach(dev)); 213 } 214 215 static int 216 thunder_pcie_fdt_get_id(device_t pci, device_t child, enum pci_id_type type, 217 uintptr_t *id) 218 { 219 phandle_t node; 220 int bsf; 221 222 if (type != PCI_ID_MSI) 223 return (pcib_get_id(pci, child, type, id)); 224 225 node = ofw_bus_get_node(pci); 226 if (OF_hasprop(node, "msi-map")) 227 return (generic_pcie_get_id(pci, child, type, id)); 228 229 bsf = pci_get_rid(child); 230 *id = (pci_get_domain(child) << PCI_RID_DOMAIN_SHIFT) | bsf; 231 232 return (0); 233 } 234 235 #ifdef THUNDERX_PASS_1_1_ERRATA 236 struct resource * 237 thunder_pcie_fdt_alloc_resource(device_t dev, device_t child, int type, 238 int *rid, rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) 239 { 240 struct generic_pcie_fdt_softc *sc; 241 struct thunder_pcie_ofw_devinfo *di; 242 struct resource_list_entry *rle; 243 int i; 244 245 /* 246 * For PCIe devices that do not have FDT nodes pass 247 * the request to the core driver. 248 */ 249 if ((int)ofw_bus_get_node(child) <= 0) 250 return (thunder_pcie_alloc_resource(dev, child, type, 251 rid, start, end, count, flags)); 252 253 /* For other devices use OFW method */ 254 sc = device_get_softc(dev); 255 256 if (RMAN_IS_DEFAULT_RANGE(start, end)) { 257 if ((di = device_get_ivars(child)) == NULL) 258 return (NULL); 259 if (type == SYS_RES_IOPORT) 260 type = SYS_RES_MEMORY; 261 262 /* Find defaults for this rid */ 263 rle = resource_list_find(&di->di_rl, type, *rid); 264 if (rle == NULL) 265 return (NULL); 266 267 start = rle->start; 268 end = rle->end; 269 count = rle->count; 270 } 271 272 if (type == SYS_RES_MEMORY) { 273 /* Remap through ranges property */ 274 for (i = 0; i < MAX_RANGES_TUPLES; i++) { 275 if (start >= sc->base.ranges[i].phys_base && 276 end < (sc->base.ranges[i].pci_base + 277 sc->base.ranges[i].size)) { 278 start -= sc->base.ranges[i].phys_base; 279 start += sc->base.ranges[i].pci_base; 280 end -= sc->base.ranges[i].phys_base; 281 end += sc->base.ranges[i].pci_base; 282 break; 283 } 284 } 285 286 if (i == MAX_RANGES_TUPLES) { 287 device_printf(dev, "Could not map resource " 288 "%#jx-%#jx\n", start, end); 289 return (NULL); 290 } 291 } 292 293 return (bus_generic_alloc_resource(dev, child, type, rid, start, 294 end, count, flags)); 295 } 296 297 static int 298 thunder_pcie_fdt_release_resource(device_t dev, device_t child, int type, 299 int rid, struct resource *res) 300 { 301 302 if ((int)ofw_bus_get_node(child) <= 0) 303 return (pci_host_generic_core_release_resource(dev, child, type, 304 rid, res)); 305 306 return (bus_generic_release_resource(dev, child, type, rid, res)); 307 } 308 #endif 309