| File: | arch/amd64/pci/acpipci.c |
| Warning: | line 278, column 3 Value stored to 'tra' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* $OpenBSD: acpipci.c,v 1.7 2022/02/21 11:03:39 mpi Exp $ */ |
| 2 | /* |
| 3 | * Copyright (c) 2018 Mark Kettenis |
| 4 | * |
| 5 | * Permission to use, copy, modify, and distribute this software for any |
| 6 | * purpose with or without fee is hereby granted, provided that the above |
| 7 | * copyright notice and this permission notice appear in all copies. |
| 8 | * |
| 9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
| 10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
| 11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
| 12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| 13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
| 14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
| 15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| 16 | */ |
| 17 | |
| 18 | #include <sys/param.h> |
| 19 | #include <sys/device.h> |
| 20 | #include <sys/extent.h> |
| 21 | #include <sys/malloc.h> |
| 22 | #include <sys/systm.h> |
| 23 | |
| 24 | #include <dev/acpi/acpireg.h> |
| 25 | #include <dev/acpi/acpivar.h> |
| 26 | #include <dev/acpi/acpidev.h> |
| 27 | #include <dev/acpi/amltypes.h> |
| 28 | #include <dev/acpi/dsdt.h> |
| 29 | |
| 30 | #include <dev/pci/pcidevs.h> |
| 31 | #include <dev/pci/pcireg.h> |
| 32 | #include <dev/pci/pcivar.h> |
| 33 | |
| 34 | /* 33DB4D5B-1FF7-401C-9657-7441C03DD766 */ |
| 35 | #define ACPI_PCI_UUID{ 0x5b, 0x4d, 0xdb, 0x33, 0xf7, 0x1f, 0x1c, 0x40, 0x96, 0x57, 0x74, 0x41, 0xc0, 0x3d, 0xd7, 0x66 } \ |
| 36 | { 0x5b, 0x4d, 0xdb, 0x33, \ |
| 37 | 0xf7, 0x1f, \ |
| 38 | 0x1c, 0x40, \ |
| 39 | 0x96, 0x57, \ |
| 40 | 0x74, 0x41, 0xc0, 0x3d, 0xd7, 0x66 } |
| 41 | |
| 42 | /* Support field. */ |
| 43 | #define ACPI_PCI_PCIE_CONFIG0x00000001 0x00000001 |
| 44 | #define ACPI_PCI_ASPM0x00000002 0x00000002 |
| 45 | #define ACPI_PCI_CPMC0x00000004 0x00000004 |
| 46 | #define ACPI_PCI_SEGMENTS0x00000008 0x00000008 |
| 47 | #define ACPI_PCI_MSI0x00000010 0x00000010 |
| 48 | |
| 49 | /* Control field. */ |
| 50 | #define ACPI_PCI_PCIE_HOTPLUG0x00000001 0x00000001 |
| 51 | |
| 52 | struct acpipci_softc { |
| 53 | struct device sc_dev; |
| 54 | struct acpi_softc *sc_acpi; |
| 55 | struct aml_node *sc_node; |
| 56 | |
| 57 | bus_space_tag_t sc_iot; |
| 58 | bus_space_tag_t sc_memt; |
| 59 | bus_dma_tag_t sc_dmat; |
| 60 | |
| 61 | struct extent *sc_busex; |
| 62 | struct extent *sc_memex; |
| 63 | struct extent *sc_ioex; |
| 64 | char sc_busex_name[32]; |
| 65 | char sc_ioex_name[32]; |
| 66 | char sc_memex_name[32]; |
| 67 | int sc_bus; |
| 68 | uint32_t sc_seg; |
| 69 | }; |
| 70 | |
| 71 | int acpipci_match(struct device *, void *, void *); |
| 72 | void acpipci_attach(struct device *, struct device *, void *); |
| 73 | |
| 74 | const struct cfattach acpipci_ca = { |
| 75 | sizeof(struct acpipci_softc), acpipci_match, acpipci_attach |
| 76 | }; |
| 77 | |
| 78 | struct cfdriver acpipci_cd = { |
| 79 | NULL((void *)0), "acpipci", DV_DULL |
| 80 | }; |
| 81 | |
| 82 | const char *acpipci_hids[] = { |
| 83 | "PNP0A08", |
| 84 | "PNP0A03", |
| 85 | NULL((void *)0) |
| 86 | }; |
| 87 | |
| 88 | void acpipci_attach_deferred(struct device *); |
| 89 | int acpipci_print(void *, const char *); |
| 90 | int acpipci_parse_resources(int, union acpi_resource *, void *); |
| 91 | void acpipci_osc(struct acpipci_softc *); |
| 92 | |
| 93 | int |
| 94 | acpipci_match(struct device *parent, void *match, void *aux) |
| 95 | { |
| 96 | struct acpi_attach_args *aaa = aux; |
| 97 | struct cfdata *cf = match; |
| 98 | |
| 99 | return acpi_matchhids(aaa, acpipci_hids, cf->cf_driver->cd_name); |
| 100 | } |
| 101 | |
| 102 | void |
| 103 | acpipci_attach(struct device *parent, struct device *self, void *aux) |
| 104 | { |
| 105 | struct acpi_attach_args *aaa = aux; |
| 106 | struct acpipci_softc *sc = (struct acpipci_softc *)self; |
| 107 | struct aml_value res; |
| 108 | uint64_t bbn = 0; |
| 109 | uint64_t seg = 0; |
| 110 | |
| 111 | acpi_haspci = 1; |
| 112 | |
| 113 | sc->sc_iot = aaa->aaa_iot; |
| 114 | sc->sc_memt = aaa->aaa_memt; |
| 115 | sc->sc_dmat = aaa->aaa_dmat; |
| 116 | |
| 117 | sc->sc_acpi = (struct acpi_softc *)parent; |
| 118 | sc->sc_node = aaa->aaa_node; |
| 119 | printf(" %s", sc->sc_node->name); |
| 120 | |
| 121 | acpipci_osc(sc); |
| 122 | |
| 123 | aml_evalinteger(sc->sc_acpi, sc->sc_node, "_BBN", 0, NULL((void *)0), &bbn); |
| 124 | sc->sc_bus = bbn; |
| 125 | |
| 126 | aml_evalinteger(sc->sc_acpi, sc->sc_node, "_SEG", 0, NULL((void *)0), &seg); |
| 127 | sc->sc_seg = seg; |
| 128 | |
| 129 | if (aml_evalname(sc->sc_acpi, sc->sc_node, "_CRS", 0, NULL((void *)0), &res)) { |
| 130 | printf(": can't find resources\n"); |
| 131 | |
| 132 | pci_init_extents(); |
| 133 | sc->sc_busex = pcibus_ex; |
| 134 | sc->sc_ioex = pciio_ex; |
| 135 | sc->sc_memex = pcimem_ex; |
| 136 | |
| 137 | return; |
| 138 | } |
| 139 | |
| 140 | /* Create extents for our address spaces. */ |
| 141 | snprintf(sc->sc_busex_name, sizeof(sc->sc_busex_name), |
| 142 | "%s pcibus", sc->sc_dev.dv_xname); |
| 143 | snprintf(sc->sc_ioex_name, sizeof(sc->sc_ioex_name), |
| 144 | "%s pciio", sc->sc_dev.dv_xname); |
| 145 | snprintf(sc->sc_memex_name, sizeof(sc->sc_memex_name), |
| 146 | "%s pcimem", sc->sc_dev.dv_xname); |
| 147 | sc->sc_busex = extent_create(sc->sc_busex_name, 0, 255, |
| 148 | M_DEVBUF2, NULL((void *)0), 0, EX_WAITOK0x0001 | EX_FILLED0x0100); |
| 149 | sc->sc_ioex = extent_create(sc->sc_ioex_name, 0, 0xffffffff, |
| 150 | M_DEVBUF2, NULL((void *)0), 0, EX_WAITOK0x0001 | EX_FILLED0x0100); |
| 151 | sc->sc_memex = extent_create(sc->sc_memex_name, 0, (u_long)-1, |
| 152 | M_DEVBUF2, NULL((void *)0), 0, EX_WAITOK0x0001 | EX_FILLED0x0100); |
| 153 | |
| 154 | aml_parse_resource(&res, acpipci_parse_resources, sc); |
| 155 | |
| 156 | if (sc->sc_acpi->sc_major < 5) { |
| 157 | extent_destroy(sc->sc_ioex); |
| 158 | extent_destroy(sc->sc_memex); |
| 159 | |
| 160 | pci_init_extents(); |
| 161 | sc->sc_ioex = pciio_ex; |
| 162 | sc->sc_memex = pcimem_ex; |
| 163 | } |
| 164 | |
| 165 | printf("\n"); |
| 166 | |
| 167 | #ifdef ACPIPCI_DEBUG |
| 168 | extent_print(sc->sc_busex); |
| 169 | extent_print(sc->sc_ioex); |
| 170 | extent_print(sc->sc_memex); |
| 171 | #endif |
| 172 | } |
| 173 | |
| 174 | void |
| 175 | acpipci_attach_bus(struct device *parent, struct acpipci_softc *sc) |
| 176 | { |
| 177 | struct pcibus_attach_args pba; |
| 178 | pcitag_t tag; |
| 179 | pcireg_t id, class; |
| 180 | |
| 181 | memset(&pba, 0, sizeof(pba))__builtin_memset((&pba), (0), (sizeof(pba))); |
| 182 | pba.pba_busname = "pci"; |
| 183 | pba.pba_iot = sc->sc_iot; |
| 184 | pba.pba_memt = sc->sc_memt; |
| 185 | pba.pba_dmat = sc->sc_dmat; |
| 186 | pba.pba_busex = sc->sc_busex; |
| 187 | pba.pba_ioex = sc->sc_ioex; |
| 188 | pba.pba_memex = sc->sc_memex; |
| 189 | pba.pba_pmemex = sc->sc_memex; |
| 190 | pba.pba_domain = pci_ndomains++; |
| 191 | pba.pba_bus = sc->sc_bus; |
| 192 | |
| 193 | /* Enable MSI in ACPI 2.0 and above, unless we're told not to. */ |
| 194 | if (sc->sc_acpi->sc_fadt->hdr.revision >= 2 && |
| 195 | (sc->sc_acpi->sc_fadt->iapc_boot_arch & FADT_NO_MSI0x0008) == 0) |
| 196 | pba.pba_flags |= PCI_FLAGS_MSI_ENABLED0x20; |
| 197 | |
| 198 | /* |
| 199 | * Don't enable MSI on chipsets from low-end manufacturers |
| 200 | * like VIA and SiS. We do this by looking at the host |
| 201 | * bridge, which should be device 0 function 0. |
| 202 | */ |
| 203 | tag = pci_make_tag(pba.pba_pc, sc->sc_bus, 0, 0); |
| 204 | id = pci_conf_read(pba.pba_pc, tag, PCI_ID_REG0x00); |
| 205 | class = pci_conf_read(pba.pba_pc, tag, PCI_CLASS_REG0x08); |
| 206 | if (PCI_CLASS(class)(((class) >> 24) & 0xff) == PCI_CLASS_BRIDGE0x06 && |
| 207 | PCI_SUBCLASS(class)(((class) >> 16) & 0xff) != PCI_SUBCLASS_BRIDGE_HOST0x00 && |
| 208 | PCI_VENDOR(id)(((id) >> 0) & 0xffff) != PCI_VENDOR_AMD0x1022 && |
| 209 | PCI_VENDOR(id)(((id) >> 0) & 0xffff) != PCI_VENDOR_NVIDIA0x10de && |
| 210 | PCI_VENDOR(id)(((id) >> 0) & 0xffff) != PCI_VENDOR_INTEL0x8086) |
| 211 | pba.pba_flags &= ~PCI_FLAGS_MSI_ENABLED0x20; |
| 212 | |
| 213 | /* |
| 214 | * Don't enable MSI on a HyperTransport bus. In order to |
| 215 | * determine that a bus is a HyperTransport bus, we look at |
| 216 | * device 24 function 0, which is the HyperTransport |
| 217 | * host/primary interface integrated on most 64-bit AMD CPUs. |
| 218 | * If that device has a HyperTransport capability, this must |
| 219 | * be a HyperTransport bus and we disable MSI. |
| 220 | */ |
| 221 | tag = pci_make_tag(pba.pba_pc, sc->sc_bus, 24, 0); |
| 222 | if (pci_get_capability(pba.pba_pc, tag, PCI_CAP_HT0x08, NULL((void *)0), NULL((void *)0))) |
| 223 | pba.pba_flags &= ~PCI_FLAGS_MSI_ENABLED0x20; |
| 224 | |
| 225 | config_found(parent, &pba, acpipci_print)config_found_sm((parent), (&pba), (acpipci_print), ((void *)0)); |
| 226 | } |
| 227 | |
| 228 | void |
| 229 | acpipci_attach_busses(struct device *parent) |
| 230 | { |
| 231 | int i; |
| 232 | |
| 233 | for (i = 0; i < acpipci_cd.cd_ndevs; i++) { |
| 234 | if (acpipci_cd.cd_devs[i]) |
| 235 | acpipci_attach_bus(parent, acpipci_cd.cd_devs[i]); |
| 236 | } |
| 237 | } |
| 238 | |
| 239 | int |
| 240 | acpipci_print(void *aux, const char *pnp) |
| 241 | { |
| 242 | struct pcibus_attach_args *pba = aux; |
| 243 | |
| 244 | if (pnp) |
| 245 | printf("%s at %s", pba->pba_busname, pnp); |
| 246 | printf(" bus %d", pba->pba_bus); |
| 247 | return (UNCONF1); |
| 248 | } |
| 249 | |
| 250 | int |
| 251 | acpipci_parse_resources(int crsidx, union acpi_resource *crs, void *arg) |
| 252 | { |
| 253 | struct acpipci_softc *sc = arg; |
| 254 | int type = AML_CRSTYPE(crs)((crs)->hdr.typecode & 0x80 ? (crs)->hdr.typecode : (crs)->hdr.typecode >> 3); |
| 255 | int restype, tflags = 0; |
| 256 | u_long min, len = 0, tra = 0; |
| 257 | |
| 258 | switch (type) { |
| 259 | case LR_WORD0x88: |
| 260 | restype = crs->lr_word.type; |
| 261 | tflags = crs->lr_word.tflags; |
| 262 | min = crs->lr_word._min; |
| 263 | len = crs->lr_word._len; |
| 264 | tra = crs->lr_word._tra; |
| 265 | break; |
| 266 | case LR_DWORD0x87: |
| 267 | restype = crs->lr_dword.type; |
| 268 | tflags = crs->lr_dword.tflags; |
| 269 | min = crs->lr_dword._min; |
| 270 | len = crs->lr_dword._len; |
| 271 | tra = crs->lr_dword._tra; |
| 272 | break; |
| 273 | case LR_QWORD0x8A: |
| 274 | restype = crs->lr_qword.type; |
| 275 | tflags = crs->lr_qword.tflags; |
| 276 | min = crs->lr_qword._min; |
| 277 | len = crs->lr_qword._len; |
| 278 | tra = crs->lr_qword._tra; |
Value stored to 'tra' is never read | |
| 279 | break; |
| 280 | case LR_MEM32FIXED0x86: |
| 281 | /* |
| 282 | * Coreboot on the PC Engines apu2 incorrectly uses a |
| 283 | * Memory32Fixed resource descriptor to describe mmio |
| 284 | * address space forwarded to the PCI bus. |
| 285 | */ |
| 286 | restype = LR_TYPE_MEMORY0; |
| 287 | min = crs->lr_m32fixed._bas; |
| 288 | len = crs->lr_m32fixed._len; |
| 289 | break; |
| 290 | } |
| 291 | |
| 292 | if (len == 0) |
| 293 | return 0; |
| 294 | |
| 295 | switch (restype) { |
| 296 | case LR_TYPE_MEMORY0: |
| 297 | if (tflags & LR_MEMORY_TTP(1L << 5)) |
| 298 | return 0; |
| 299 | extent_free(sc->sc_memex, min, len, EX_WAITOK0x0001 | EX_CONFLICTOK0x0080); |
| 300 | break; |
| 301 | case LR_TYPE_IO1: |
| 302 | if (tflags & LR_IO_TTP(1L << 4)) |
| 303 | return 0; |
| 304 | extent_free(sc->sc_ioex, min, len, EX_WAITOK0x0001 | EX_CONFLICTOK0x0080); |
| 305 | break; |
| 306 | case LR_TYPE_BUS2: |
| 307 | extent_free(sc->sc_busex, min, len, EX_WAITOK0x0001); |
| 308 | /* |
| 309 | * Let _CRS minimum bus number override _BBN. |
| 310 | */ |
| 311 | sc->sc_bus = min; |
| 312 | break; |
| 313 | } |
| 314 | |
| 315 | return 0; |
| 316 | } |
| 317 | |
| 318 | void |
| 319 | acpipci_osc(struct acpipci_softc *sc) |
| 320 | { |
| 321 | struct aml_value args[4]; |
| 322 | struct aml_value res; |
| 323 | static uint8_t uuid[16] = ACPI_PCI_UUID{ 0x5b, 0x4d, 0xdb, 0x33, 0xf7, 0x1f, 0x1c, 0x40, 0x96, 0x57, 0x74, 0x41, 0xc0, 0x3d, 0xd7, 0x66 }; |
| 324 | uint32_t buf[3]; |
| 325 | |
| 326 | memset(args, 0, sizeof(args))__builtin_memset((args), (0), (sizeof(args))); |
| 327 | args[0].type = AML_OBJTYPE_BUFFER; |
| 328 | args[0].v_buffer_.vbuffer = uuid; |
| 329 | args[0].length = sizeof(uuid); |
| 330 | args[1].type = AML_OBJTYPE_INTEGER; |
| 331 | args[1].v_integer_.vinteger = 1; |
| 332 | args[2].type = AML_OBJTYPE_INTEGER; |
| 333 | args[2].v_integer_.vinteger = 3; |
| 334 | args[3].type = AML_OBJTYPE_BUFFER; |
| 335 | args[3].v_buffer_.vbuffer = (uint8_t *)buf; |
| 336 | args[3].length = sizeof(buf); |
| 337 | |
| 338 | memset(buf, 0, sizeof(buf))__builtin_memset((buf), (0), (sizeof(buf))); |
| 339 | buf[0] = 0x0; |
| 340 | buf[1] = ACPI_PCI_PCIE_CONFIG0x00000001 | ACPI_PCI_MSI0x00000010; |
| 341 | buf[2] = ACPI_PCI_PCIE_HOTPLUG0x00000001; |
| 342 | |
| 343 | if (aml_evalname(sc->sc_acpi, sc->sc_node, "_OSC", 4, args, &res)) |
| 344 | return; |
| 345 | |
| 346 | if (res.type == AML_OBJTYPE_BUFFER) { |
| 347 | size_t len = res.length; |
| 348 | uint32_t *p = (uint32_t *)res.v_buffer_.vbuffer; |
| 349 | |
| 350 | printf(":"); |
| 351 | while (len >= 4) { |
| 352 | printf(" 0x%08x", *p); |
| 353 | p++; |
| 354 | len -= 4; |
| 355 | } |
| 356 | } |
| 357 | } |