1 /* $OpenBSD: dwpcie.c,v 1.14 2019/06/03 00:43:26 kettenis Exp $ */ 2 /* 3 * Copyright (c) 2018 Mark Kettenis <kettenis@openbsd.org> 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/systm.h> 20 #include <sys/device.h> 21 #include <sys/extent.h> 22 #include <sys/malloc.h> 23 24 #include <machine/intr.h> 25 #include <machine/bus.h> 26 #include <machine/fdt.h> 27 28 #include <dev/pci/pcidevs.h> 29 #include <dev/pci/pcireg.h> 30 #include <dev/pci/pcivar.h> 31 #include <dev/pci/ppbreg.h> 32 33 #include <dev/ofw/openfirm.h> 34 #include <dev/ofw/ofw_clock.h> 35 #include <dev/ofw/ofw_gpio.h> 36 #include <dev/ofw/ofw_misc.h> 37 #include <dev/ofw/ofw_pinctrl.h> 38 #include <dev/ofw/ofw_power.h> 39 #include <dev/ofw/fdt.h> 40 41 /* Registers */ 42 #define PCIE_PORT_LINK_CTRL 0x710 43 #define PCIE_PORT_LINK_CTRL_LANES_MASK (0x3f << 16) 44 #define PCIE_PORT_LINK_CTRL_LANES_1 (0x1 << 16) 45 #define PCIE_PORT_LINK_CTRL_LANES_2 (0x3 << 16) 46 #define PCIE_PORT_LINK_CTRL_LANES_4 (0x7 << 16) 47 #define PCIE_PORT_LINK_CTRL_LANES_8 (0xf << 16) 48 #define PCIE_PHY_DEBUG_R1 0x72c 49 #define PCIE_PHY_DEBUG_R1_XMLH_LINK_IN_TRAINING (1 << 29) 50 #define PCIE_PHY_DEBUG_R1_XMLH_LINK_UP (1 << 4) 51 #define PCIE_LINK_WIDTH_SPEED_CTRL 0x80c 52 #define PCIE_LINK_WIDTH_SPEED_CTRL_LANES_MASK (0x1f << 8) 53 #define PCIE_LINK_WIDTH_SPEED_CTRL_LANES_1 (0x1 << 8) 54 #define PCIE_LINK_WIDTH_SPEED_CTRL_LANES_2 (0x2 << 8) 55 #define PCIE_LINK_WIDTH_SPEED_CTRL_LANES_4 (0x4 << 8) 56 #define PCIE_LINK_WIDTH_SPEED_CTRL_LANES_8 (0x8 << 8) 57 #define PCIE_LINK_WIDTH_SPEED_CTRL_CHANGE (1 << 17) 58 59 #define MISC_CONTROL_1 0x8bc 60 #define MISC_CONTROL_1_DBI_RO_WR_EN (1 << 0) 61 #define IATU_VIEWPORT 0x900 62 #define IATU_VIEWPORT_INDEX0 0 63 #define IATU_VIEWPORT_INDEX1 1 64 #define IATU_VIEWPORT_INDEX2 2 65 #define IATU_OFFSET_VIEWPORT 0x904 66 #define IATU_OFFSET_UNROLL(x) (0x200 * (x)) 67 #define IATU_REGION_CTRL_1 0x000 68 #define IATU_REGION_CTRL_1_TYPE_MEM 0 69 #define IATU_REGION_CTRL_1_TYPE_IO 2 70 #define IATU_REGION_CTRL_1_TYPE_CFG0 4 71 #define IATU_REGION_CTRL_1_TYPE_CFG1 5 72 #define IATU_REGION_CTRL_2 0x004 73 #define IATU_REGION_CTRL_2_REGION_EN (1U << 31) 74 #define IATU_LWR_BASE_ADDR 0x08 75 #define IATU_UPPER_BASE_ADDR 0x0c 76 #define IATU_LIMIT_ADDR 0x10 77 #define IATU_LWR_TARGET_ADDR 0x14 78 #define IATU_UPPER_TARGET_ADDR 0x18 79 80 #define PCIE_GLOBAL_CTRL 0x8000 81 #define PCIE_GLOBAL_CTRL_APP_LTSSM_EN (1 << 2) 82 #define PCIE_GLOBAL_CTRL_DEVICE_TYPE_MASK (0xf << 4) 83 #define PCIE_GLOBAL_CTRL_DEVICE_TYPE_RC (0x4 << 4) 84 #define PCIE_GLOBAL_STATUS 0x8008 85 #define PCIE_GLOBAL_STATUS_RDLH_LINK_UP (1 << 1) 86 #define PCIE_GLOBAL_STATUS_PHY_LINK_UP (1 << 9) 87 #define PCIE_PM_STATUS 0x8014 88 #define PCIE_GLOBAL_INT_CAUSE 0x801c 89 #define PCIE_GLOBAL_INT_MASK 0x8020 90 #define PCIE_GLOBAL_INT_MASK_INT_A (1 << 9) 91 #define PCIE_GLOBAL_INT_MASK_INT_B (1 << 10) 92 #define PCIE_GLOBAL_INT_MASK_INT_C (1 << 11) 93 #define PCIE_GLOBAL_INT_MASK_INT_D (1 << 12) 94 #define PCIE_ARCACHE_TRC 0x8050 95 #define PCIE_ARCACHE_TRC_DEFAULT 0x3511 96 #define PCIE_AWCACHE_TRC 0x8054 97 #define PCIE_AWCACHE_TRC_DEFAULT 0x5311 98 #define PCIE_ARUSER 0x805c 99 #define PCIE_AWUSER 0x8060 100 #define PCIE_AXUSER_DOMAIN_MASK (0x3 << 4) 101 #define PCIE_AXUSER_DOMAIN_INNER_SHARABLE (0x1 << 4) 102 #define PCIE_AXUSER_DOMAIN_OUTER_SHARABLE (0x2 << 4) 103 104 /* i.MX8MQ registers */ 105 #define PCIE_RC_LCR 0x7c 106 #define PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN1 0x1 107 #define PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN2 0x2 108 #define PCIE_RC_LCR_MAX_LINK_SPEEDS_MASK 0xf 109 #define PCIE_RC_LCR_L1EL_MASK (0x7 << 15) 110 #define PCIE_RC_LCR_L1EL_64US (0x6 << 15) 111 112 #define IOMUXC_GPR12 0x30 113 #define IMX8MQ_GPR_PCIE2_DEVICE_TYPE_MASK (0xf << 8) 114 #define IMX8MQ_GPR_PCIE2_DEVICE_TYPE_RC (0x4 << 8) 115 #define IMX8MQ_GPR_PCIE1_DEVICE_TYPE_MASK (0xf << 12) 116 #define IMX8MQ_GPR_PCIE1_DEVICE_TYPE_RC (0x4 << 12) 117 #define IOMUXC_GPR14 0x38 118 #define IOMUXC_GPR16 0x40 119 #define IMX8MQ_GPR_PCIE_REF_USE_PAD (1 << 9) 120 #define IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE_EN (1 << 10) 121 #define IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE (1 << 11) 122 123 #define ANATOP_PLLOUT_CTL 0x74 124 #define ANATOP_PLLOUT_CTL_CKE (1 << 4) 125 #define ANATOP_PLLOUT_CTL_SEL_SYSPLL1 0xb 126 #define ANATOP_PLLOUT_CTL_SEL_MASK 0xf 127 #define ANATOP_PLLOUT_DIV 0x7c 128 #define ANATOP_PLLOUT_DIV_SYSPLL1 0x7 129 130 #define HREAD4(sc, reg) \ 131 (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))) 132 #define HWRITE4(sc, reg, val) \ 133 bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) 134 #define HSET4(sc, reg, bits) \ 135 HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits)) 136 #define HCLR4(sc, reg, bits) \ 137 HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits)) 138 139 struct dwpcie_range { 140 uint32_t flags; 141 uint64_t pci_base; 142 uint64_t phys_base; 143 uint64_t size; 144 }; 145 146 struct dwpcie_softc { 147 struct device sc_dev; 148 bus_space_tag_t sc_iot; 149 bus_space_handle_t sc_ioh; 150 bus_space_handle_t sc_cfg0_ioh; 151 bus_space_handle_t sc_cfg1_ioh; 152 153 bus_addr_t sc_cfg0_base; 154 bus_size_t sc_cfg0_size; 155 bus_addr_t sc_cfg1_base; 156 bus_size_t sc_cfg1_size; 157 bus_addr_t sc_io_base; 158 bus_addr_t sc_io_bus_addr; 159 bus_size_t sc_io_size; 160 bus_addr_t sc_mem_base; 161 bus_addr_t sc_mem_bus_addr; 162 bus_size_t sc_mem_size; 163 164 int sc_node; 165 int sc_acells; 166 int sc_scells; 167 int sc_pacells; 168 int sc_pscells; 169 struct dwpcie_range *sc_ranges; 170 int sc_nranges; 171 172 struct bus_space sc_bus_iot; 173 struct bus_space sc_bus_memt; 174 175 struct arm64_pci_chipset sc_pc; 176 int sc_bus; 177 178 int sc_num_viewport; 179 bus_addr_t sc_atu_base; 180 int sc_atu_unroll; 181 182 void *sc_ih; 183 }; 184 185 int dwpcie_match(struct device *, void *, void *); 186 void dwpcie_attach(struct device *, struct device *, void *); 187 188 struct cfattach dwpcie_ca = { 189 sizeof (struct dwpcie_softc), dwpcie_match, dwpcie_attach 190 }; 191 192 struct cfdriver dwpcie_cd = { 193 NULL, "dwpcie", DV_DULL 194 }; 195 196 int 197 dwpcie_match(struct device *parent, void *match, void *aux) 198 { 199 struct fdt_attach_args *faa = aux; 200 201 return (OF_is_compatible(faa->fa_node, "marvell,armada8k-pcie") || 202 OF_is_compatible(faa->fa_node, "fsl,imx8mq-pcie")); 203 } 204 205 void dwpcie_atu_config(struct dwpcie_softc *, int, int, 206 uint64_t, uint64_t, uint64_t); 207 void dwpcie_link_config(struct dwpcie_softc *); 208 int dwpcie_link_up(struct dwpcie_softc *); 209 210 void dwpcie_armada8k_init(struct dwpcie_softc *); 211 int dwpcie_armada8k_link_up(struct dwpcie_softc *); 212 int dwpcie_armada8k_intr(void *); 213 214 void dwpcie_imx8mq_init(struct dwpcie_softc *); 215 int dwpcie_imx8mq_intr(void *); 216 217 void dwpcie_attach_hook(struct device *, struct device *, 218 struct pcibus_attach_args *); 219 int dwpcie_bus_maxdevs(void *, int); 220 pcitag_t dwpcie_make_tag(void *, int, int, int); 221 void dwpcie_decompose_tag(void *, pcitag_t, int *, int *, int *); 222 int dwpcie_conf_size(void *, pcitag_t); 223 pcireg_t dwpcie_conf_read(void *, pcitag_t, int); 224 void dwpcie_conf_write(void *, pcitag_t, int, pcireg_t); 225 226 int dwpcie_intr_map(struct pci_attach_args *, pci_intr_handle_t *); 227 const char *dwpcie_intr_string(void *, pci_intr_handle_t); 228 void *dwpcie_intr_establish(void *, pci_intr_handle_t, int, 229 int (*)(void *), void *, char *); 230 void dwpcie_intr_disestablish(void *, void *); 231 232 void *dwpcie_armada8k_intr_establish(void *, pci_intr_handle_t, int, 233 int (*)(void *), void *, char *); 234 235 int dwpcie_bs_iomap(bus_space_tag_t, bus_addr_t, bus_size_t, int, 236 bus_space_handle_t *); 237 int dwpcie_bs_memmap(bus_space_tag_t, bus_addr_t, bus_size_t, int, 238 bus_space_handle_t *); 239 240 void 241 dwpcie_attach(struct device *parent, struct device *self, void *aux) 242 { 243 struct dwpcie_softc *sc = (struct dwpcie_softc *)self; 244 struct fdt_attach_args *faa = aux; 245 struct pcibus_attach_args pba; 246 bus_addr_t iobase, iolimit; 247 bus_addr_t membase, memlimit; 248 uint32_t bus_range[2]; 249 uint32_t *ranges; 250 int i, j, nranges, rangeslen; 251 pcireg_t bir, blr, csr; 252 253 if (faa->fa_nreg < 2) { 254 printf(": no registers\n"); 255 return; 256 } 257 258 sc->sc_iot = faa->fa_iot; 259 sc->sc_node = faa->fa_node; 260 261 sc->sc_acells = OF_getpropint(sc->sc_node, "#address-cells", 262 faa->fa_acells); 263 sc->sc_scells = OF_getpropint(sc->sc_node, "#size-cells", 264 faa->fa_scells); 265 sc->sc_pacells = faa->fa_acells; 266 sc->sc_pscells = faa->fa_scells; 267 268 rangeslen = OF_getproplen(sc->sc_node, "ranges"); 269 if (rangeslen <= 0 || (rangeslen % sizeof(uint32_t)) || 270 (rangeslen / sizeof(uint32_t)) % (sc->sc_acells + 271 sc->sc_pacells + sc->sc_scells)) { 272 printf(": invalid ranges property\n"); 273 return; 274 } 275 276 ranges = malloc(rangeslen, M_TEMP, M_WAITOK); 277 OF_getpropintarray(sc->sc_node, "ranges", ranges, 278 rangeslen); 279 280 nranges = (rangeslen / sizeof(uint32_t)) / 281 (sc->sc_acells + sc->sc_pacells + sc->sc_scells); 282 sc->sc_ranges = mallocarray(nranges, 283 sizeof(struct dwpcie_range), M_TEMP, M_WAITOK); 284 sc->sc_nranges = nranges; 285 286 for (i = 0, j = 0; i < sc->sc_nranges; i++) { 287 sc->sc_ranges[i].flags = ranges[j++]; 288 sc->sc_ranges[i].pci_base = ranges[j++]; 289 if (sc->sc_acells - 1 == 2) { 290 sc->sc_ranges[i].pci_base <<= 32; 291 sc->sc_ranges[i].pci_base |= ranges[j++]; 292 } 293 sc->sc_ranges[i].phys_base = ranges[j++]; 294 if (sc->sc_pacells == 2) { 295 sc->sc_ranges[i].phys_base <<= 32; 296 sc->sc_ranges[i].phys_base |= ranges[j++]; 297 } 298 sc->sc_ranges[i].size = ranges[j++]; 299 if (sc->sc_scells == 2) { 300 sc->sc_ranges[i].size <<= 32; 301 sc->sc_ranges[i].size |= ranges[j++]; 302 } 303 } 304 305 free(ranges, M_TEMP, rangeslen); 306 307 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, 308 faa->fa_reg[0].size, 0, &sc->sc_ioh)) { 309 printf(": can't map ctrl registers\n"); 310 return; 311 } 312 313 sc->sc_cfg0_base = faa->fa_reg[1].addr; 314 sc->sc_cfg0_size = faa->fa_reg[1].size / 2; 315 sc->sc_cfg0_base = faa->fa_reg[1].addr + sc->sc_cfg0_size; 316 sc->sc_cfg1_size = sc->sc_cfg0_size; 317 318 if (bus_space_map(sc->sc_iot, sc->sc_cfg0_base, 319 sc->sc_cfg1_size, 0, &sc->sc_cfg0_ioh)) { 320 bus_space_unmap(sc->sc_iot, sc->sc_ioh, faa->fa_reg[0].size); 321 printf(": can't map config registers\n"); 322 return; 323 } 324 325 if (bus_space_map(sc->sc_iot, sc->sc_cfg1_base, 326 sc->sc_cfg1_size, 0, &sc->sc_cfg1_ioh)) { 327 bus_space_unmap(sc->sc_iot, sc->sc_cfg0_ioh, sc->sc_cfg0_size); 328 bus_space_unmap(sc->sc_iot, sc->sc_ioh, faa->fa_reg[0].size); 329 printf(": can't map config registers\n"); 330 return; 331 } 332 333 sc->sc_num_viewport = OF_getpropint(sc->sc_node, "num-viewport", 2); 334 335 printf("\n"); 336 337 pinctrl_byname(sc->sc_node, "default"); 338 339 clock_set_assigned(sc->sc_node); 340 341 if (OF_is_compatible(sc->sc_node, "marvell,armada8k-pcie")) 342 dwpcie_armada8k_init(sc); 343 if (OF_is_compatible(sc->sc_node, "fsl,imx8mq-pcie")) 344 dwpcie_imx8mq_init(sc); 345 346 if (HREAD4(sc, IATU_VIEWPORT) == 0xffffffff) { 347 sc->sc_atu_base = 0x300000; 348 sc->sc_atu_unroll = 1; 349 } 350 351 /* Set up address translation for I/O space. */ 352 sc->sc_io_bus_addr = sc->sc_mem_bus_addr = -1; 353 for (i = 0; i < sc->sc_nranges; i++) { 354 if ((sc->sc_ranges[i].flags & 0x03000000) == 0x01000000 && 355 sc->sc_ranges[i].size > 0) { 356 sc->sc_io_base = sc->sc_ranges[i].phys_base; 357 sc->sc_io_bus_addr = sc->sc_ranges[i].pci_base; 358 sc->sc_io_size = sc->sc_ranges[i].size; 359 } 360 if ((sc->sc_ranges[i].flags & 0x03000000) == 0x02000000 && 361 sc->sc_ranges[i].size > 0) { 362 sc->sc_mem_base = sc->sc_ranges[i].phys_base; 363 sc->sc_mem_bus_addr = sc->sc_ranges[i].pci_base; 364 sc->sc_mem_size = sc->sc_ranges[i].size; 365 } 366 } 367 368 dwpcie_atu_config(sc, IATU_VIEWPORT_INDEX0, 369 IATU_REGION_CTRL_1_TYPE_MEM, sc->sc_mem_base, 370 sc->sc_mem_bus_addr, sc->sc_mem_size); 371 if (sc->sc_num_viewport > 2) 372 dwpcie_atu_config(sc, IATU_VIEWPORT_INDEX2, 373 IATU_REGION_CTRL_1_TYPE_IO, sc->sc_io_base, 374 sc->sc_io_bus_addr, sc->sc_io_size); 375 376 /* Enable modification of read-only bits. */ 377 HSET4(sc, MISC_CONTROL_1, MISC_CONTROL_1_DBI_RO_WR_EN); 378 379 /* A Root Port is a PCI-PCI Bridge. */ 380 HWRITE4(sc, PCI_CLASS_REG, 381 PCI_CLASS_BRIDGE << PCI_CLASS_SHIFT | 382 PCI_SUBCLASS_BRIDGE_PCI << PCI_SUBCLASS_SHIFT); 383 384 /* Clear BAR as U-Boot seems to leave garbage in it. */ 385 HWRITE4(sc, PCI_MAPREG_START, PCI_MAPREG_MEM_TYPE_64BIT); 386 HWRITE4(sc, PCI_MAPREG_START + 4, 0); 387 388 /* Make sure read-only bits are write-protected. */ 389 HCLR4(sc, MISC_CONTROL_1, MISC_CONTROL_1_DBI_RO_WR_EN); 390 391 /* Set up bus range. */ 392 if (OF_getpropintarray(sc->sc_node, "bus-range", bus_range, 393 sizeof(bus_range)) != sizeof(bus_range) || 394 bus_range[0] >= 32 || bus_range[1] >= 32) { 395 bus_range[0] = 0; 396 bus_range[1] = 31; 397 } 398 sc->sc_bus = bus_range[0]; 399 400 /* Initialize bus range. */ 401 bir = bus_range[0]; 402 bir |= ((bus_range[0] + 1) << 8); 403 bir |= (bus_range[1] << 16); 404 HWRITE4(sc, PPB_REG_BUSINFO, bir); 405 406 /* Initialize I/O window. */ 407 iobase = sc->sc_io_bus_addr; 408 iolimit = iobase + sc->sc_io_size - 1; 409 blr = iolimit & PPB_IO_MASK; 410 blr |= (iobase >> PPB_IO_SHIFT); 411 HWRITE4(sc, PPB_REG_IOSTATUS, blr); 412 blr = (iobase & 0xffff0000) >> 16; 413 blr |= iolimit & 0xffff0000; 414 HWRITE4(sc, PPB_REG_IO_HI, blr); 415 416 /* Initialize memory mapped I/O window. */ 417 membase = sc->sc_mem_bus_addr; 418 memlimit = membase + sc->sc_mem_size - 1; 419 blr = memlimit & PPB_MEM_MASK; 420 blr |= (membase >> PPB_MEM_SHIFT); 421 HWRITE4(sc, PPB_REG_MEM, blr); 422 423 /* Reset prefetchable memory mapped I/O window. */ 424 HWRITE4(sc, PPB_REG_PREFMEM, 0x0000ffff); 425 HWRITE4(sc, PPB_REG_PREFBASE_HI32, 0); 426 HWRITE4(sc, PPB_REG_PREFLIM_HI32, 0); 427 428 csr = PCI_COMMAND_MASTER_ENABLE; 429 if (iolimit > iobase) 430 csr |= PCI_COMMAND_IO_ENABLE; 431 if (memlimit > membase) 432 csr |= PCI_COMMAND_MEM_ENABLE; 433 HWRITE4(sc, PCI_COMMAND_STATUS_REG, csr); 434 435 memcpy(&sc->sc_bus_iot, sc->sc_iot, sizeof(sc->sc_bus_iot)); 436 sc->sc_bus_iot.bus_private = sc; 437 sc->sc_bus_iot._space_map = dwpcie_bs_iomap; 438 memcpy(&sc->sc_bus_memt, sc->sc_iot, sizeof(sc->sc_bus_memt)); 439 sc->sc_bus_memt.bus_private = sc; 440 sc->sc_bus_memt._space_map = dwpcie_bs_memmap; 441 442 sc->sc_pc.pc_conf_v = sc; 443 sc->sc_pc.pc_attach_hook = dwpcie_attach_hook; 444 sc->sc_pc.pc_bus_maxdevs = dwpcie_bus_maxdevs; 445 sc->sc_pc.pc_make_tag = dwpcie_make_tag; 446 sc->sc_pc.pc_decompose_tag = dwpcie_decompose_tag; 447 sc->sc_pc.pc_conf_size = dwpcie_conf_size; 448 sc->sc_pc.pc_conf_read = dwpcie_conf_read; 449 sc->sc_pc.pc_conf_write = dwpcie_conf_write; 450 451 sc->sc_pc.pc_intr_v = sc; 452 sc->sc_pc.pc_intr_map = dwpcie_intr_map; 453 sc->sc_pc.pc_intr_map_msi = _pci_intr_map_msi; 454 sc->sc_pc.pc_intr_map_msix = _pci_intr_map_msix; 455 sc->sc_pc.pc_intr_string = dwpcie_intr_string; 456 sc->sc_pc.pc_intr_establish = dwpcie_intr_establish; 457 sc->sc_pc.pc_intr_disestablish = dwpcie_intr_disestablish; 458 459 memset(&pba, 0, sizeof(pba)); 460 pba.pba_busname = "pci"; 461 pba.pba_iot = &sc->sc_bus_iot; 462 pba.pba_memt = &sc->sc_bus_memt; 463 pba.pba_dmat = faa->fa_dmat; 464 pba.pba_pc = &sc->sc_pc; 465 pba.pba_domain = pci_ndomains++; 466 pba.pba_bus = sc->sc_bus; 467 if (OF_is_compatible(faa->fa_node, "marvell,armada8k-pcie")) 468 pba.pba_flags |= PCI_FLAGS_MSI_ENABLED; 469 470 config_found(self, &pba, NULL); 471 } 472 473 void 474 dwpcie_link_config(struct dwpcie_softc *sc) 475 { 476 uint32_t mode, width, reg; 477 int lanes; 478 479 lanes = OF_getpropint(sc->sc_node, "num-lanes", 0); 480 481 switch (lanes) { 482 case 1: 483 mode = PCIE_PORT_LINK_CTRL_LANES_1; 484 width = PCIE_LINK_WIDTH_SPEED_CTRL_LANES_1; 485 break; 486 case 2: 487 mode = PCIE_PORT_LINK_CTRL_LANES_2; 488 width = PCIE_LINK_WIDTH_SPEED_CTRL_LANES_2; 489 break; 490 case 4: 491 mode = PCIE_PORT_LINK_CTRL_LANES_4; 492 width = PCIE_LINK_WIDTH_SPEED_CTRL_LANES_4; 493 break; 494 case 8: 495 mode = PCIE_PORT_LINK_CTRL_LANES_8; 496 width = PCIE_LINK_WIDTH_SPEED_CTRL_LANES_8; 497 break; 498 default: 499 printf("%s: %d lanes not supported\n", __func__, lanes); 500 return; 501 } 502 503 reg = HREAD4(sc, PCIE_PORT_LINK_CTRL); 504 reg &= ~PCIE_PORT_LINK_CTRL_LANES_MASK; 505 reg |= mode; 506 HWRITE4(sc, PCIE_PORT_LINK_CTRL, reg); 507 508 reg = HREAD4(sc, PCIE_LINK_WIDTH_SPEED_CTRL); 509 reg &= ~PCIE_LINK_WIDTH_SPEED_CTRL_LANES_MASK; 510 reg |= width; 511 HWRITE4(sc, PCIE_LINK_WIDTH_SPEED_CTRL, reg); 512 513 reg = HREAD4(sc, PCIE_LINK_WIDTH_SPEED_CTRL); 514 reg |= PCIE_LINK_WIDTH_SPEED_CTRL_CHANGE; 515 HWRITE4(sc, PCIE_LINK_WIDTH_SPEED_CTRL, reg); 516 } 517 518 void 519 dwpcie_armada8k_init(struct dwpcie_softc *sc) 520 { 521 uint32_t reg; 522 int timo; 523 524 clock_enable_all(sc->sc_node); 525 526 dwpcie_link_config(sc); 527 528 if (!dwpcie_armada8k_link_up(sc)) { 529 reg = HREAD4(sc, PCIE_GLOBAL_CTRL); 530 reg &= ~PCIE_GLOBAL_CTRL_APP_LTSSM_EN; 531 HWRITE4(sc, PCIE_GLOBAL_CTRL, reg); 532 } 533 534 /* Enable Root Complex mode. */ 535 reg = HREAD4(sc, PCIE_GLOBAL_CTRL); 536 reg &= ~PCIE_GLOBAL_CTRL_DEVICE_TYPE_MASK; 537 reg |= PCIE_GLOBAL_CTRL_DEVICE_TYPE_RC; 538 HWRITE4(sc, PCIE_GLOBAL_CTRL, reg); 539 540 HWRITE4(sc, PCIE_ARCACHE_TRC, PCIE_ARCACHE_TRC_DEFAULT); 541 HWRITE4(sc, PCIE_AWCACHE_TRC, PCIE_AWCACHE_TRC_DEFAULT); 542 reg = HREAD4(sc, PCIE_ARUSER); 543 reg &= ~PCIE_AXUSER_DOMAIN_MASK; 544 reg |= PCIE_AXUSER_DOMAIN_OUTER_SHARABLE; 545 HWRITE4(sc, PCIE_ARUSER, reg); 546 reg = HREAD4(sc, PCIE_AWUSER); 547 reg &= ~PCIE_AXUSER_DOMAIN_MASK; 548 reg |= PCIE_AXUSER_DOMAIN_OUTER_SHARABLE; 549 HWRITE4(sc, PCIE_AWUSER, reg); 550 551 if (!dwpcie_armada8k_link_up(sc)) { 552 reg = HREAD4(sc, PCIE_GLOBAL_CTRL); 553 reg |= PCIE_GLOBAL_CTRL_APP_LTSSM_EN; 554 HWRITE4(sc, PCIE_GLOBAL_CTRL, reg); 555 } 556 557 for (timo = 40; timo > 0; timo--) { 558 if (dwpcie_armada8k_link_up(sc)) 559 break; 560 delay(1000); 561 } 562 563 sc->sc_ih = fdt_intr_establish(sc->sc_node, IPL_AUDIO | IPL_MPSAFE, 564 dwpcie_armada8k_intr, sc, sc->sc_dev.dv_xname); 565 566 /* Unmask INTx interrupts. */ 567 HWRITE4(sc, PCIE_GLOBAL_INT_MASK, 568 PCIE_GLOBAL_INT_MASK_INT_A | PCIE_GLOBAL_INT_MASK_INT_B | 569 PCIE_GLOBAL_INT_MASK_INT_C | PCIE_GLOBAL_INT_MASK_INT_D); 570 } 571 572 int 573 dwpcie_armada8k_link_up(struct dwpcie_softc *sc) 574 { 575 uint32_t reg, mask; 576 577 mask = PCIE_GLOBAL_STATUS_RDLH_LINK_UP; 578 mask |= PCIE_GLOBAL_STATUS_PHY_LINK_UP; 579 reg = HREAD4(sc, PCIE_GLOBAL_STATUS); 580 return ((reg & mask) == mask); 581 } 582 583 int 584 dwpcie_armada8k_intr(void *arg) 585 { 586 struct dwpcie_softc *sc = arg; 587 uint32_t cause; 588 589 /* Acknowledge interrupts. */ 590 cause = HREAD4(sc, PCIE_GLOBAL_INT_CAUSE); 591 HWRITE4(sc, PCIE_GLOBAL_INT_CAUSE, cause); 592 593 /* INTx interrupt, so not really ours. */ 594 return 0; 595 } 596 597 void 598 dwpcie_imx8mq_init(struct dwpcie_softc *sc) 599 { 600 uint32_t *clkreq_gpio, *disable_gpio, *reset_gpio; 601 ssize_t clkreq_gpiolen, disable_gpiolen, reset_gpiolen; 602 struct regmap *anatop, *gpc, *gpr; 603 uint32_t off, reg; 604 int timo; 605 606 anatop = regmap_bycompatible("fsl,imx8mq-anatop"); 607 gpc = regmap_bycompatible("fsl,imx8mq-gpc"); 608 gpr = regmap_bycompatible("fsl,imx8mq-iomuxc-gpr"); 609 KASSERT(anatop != NULL); 610 KASSERT(gpc != NULL); 611 KASSERT(gpr != NULL); 612 613 clkreq_gpiolen = OF_getproplen(sc->sc_node, "clkreq-gpio"); 614 disable_gpiolen = OF_getproplen(sc->sc_node, "disable-gpio"); 615 reset_gpiolen = OF_getproplen(sc->sc_node, "reset-gpio"); 616 617 if (clkreq_gpiolen > 0) { 618 clkreq_gpio = malloc(clkreq_gpiolen, M_TEMP, M_WAITOK); 619 OF_getpropintarray(sc->sc_node, "clkreq-gpio", clkreq_gpio, 620 clkreq_gpiolen); 621 gpio_controller_config_pin(clkreq_gpio, GPIO_CONFIG_OUTPUT); 622 gpio_controller_set_pin(clkreq_gpio, 1); 623 } 624 625 if (disable_gpiolen > 0) { 626 disable_gpio = malloc(disable_gpiolen, M_TEMP, M_WAITOK); 627 OF_getpropintarray(sc->sc_node, "disable-gpio", disable_gpio, 628 disable_gpiolen); 629 gpio_controller_config_pin(disable_gpio, GPIO_CONFIG_OUTPUT); 630 gpio_controller_set_pin(disable_gpio, 0); 631 } 632 633 if (reset_gpiolen > 0) { 634 reset_gpio = malloc(reset_gpiolen, M_TEMP, M_WAITOK); 635 OF_getpropintarray(sc->sc_node, "reset-gpio", reset_gpio, 636 reset_gpiolen); 637 gpio_controller_config_pin(reset_gpio, GPIO_CONFIG_OUTPUT); 638 gpio_controller_set_pin(reset_gpio, 1); 639 } 640 641 power_domain_enable(sc->sc_node); 642 reset_assert(sc->sc_node, "pciephy"); 643 reset_assert(sc->sc_node, "apps"); 644 645 reg = regmap_read_4(gpr, IOMUXC_GPR12); 646 if (OF_getpropint(sc->sc_node, "ctrl-id", 0) == 0) { 647 off = IOMUXC_GPR14; 648 reg &= ~IMX8MQ_GPR_PCIE1_DEVICE_TYPE_MASK; 649 reg |= IMX8MQ_GPR_PCIE1_DEVICE_TYPE_RC; 650 } else { 651 off = IOMUXC_GPR16; 652 reg &= ~IMX8MQ_GPR_PCIE2_DEVICE_TYPE_MASK; 653 reg |= IMX8MQ_GPR_PCIE2_DEVICE_TYPE_RC; 654 } 655 regmap_write_4(gpr, IOMUXC_GPR12, reg); 656 657 if (OF_getproplen(sc->sc_node, "ext_osc") == 0) { 658 reg = regmap_read_4(gpr, off); 659 reg |= IMX8MQ_GPR_PCIE_REF_USE_PAD; 660 regmap_write_4(gpr, off, reg); 661 } else { 662 reg = regmap_read_4(gpr, off); 663 reg &= ~IMX8MQ_GPR_PCIE_REF_USE_PAD; 664 regmap_write_4(gpr, off, reg); 665 666 regmap_write_4(anatop, ANATOP_PLLOUT_CTL, 667 ANATOP_PLLOUT_CTL_CKE | ANATOP_PLLOUT_CTL_SEL_SYSPLL1); 668 regmap_write_4(anatop, ANATOP_PLLOUT_DIV, 669 ANATOP_PLLOUT_DIV_SYSPLL1); 670 } 671 672 clock_enable(sc->sc_node, "pcie_phy"); 673 clock_enable(sc->sc_node, "pcie_bus"); 674 clock_enable(sc->sc_node, "pcie"); 675 676 /* Allow clocks to stabilize. */ 677 delay(200); 678 679 if (reset_gpiolen > 0) { 680 gpio_controller_set_pin(reset_gpio, 1); 681 delay(20000); 682 gpio_controller_set_pin(reset_gpio, 0); 683 delay(20000); 684 } 685 686 reset_deassert(sc->sc_node, "pciephy"); 687 688 reg = HREAD4(sc, 0x100000 + PCIE_RC_LCR); 689 reg &= ~PCIE_RC_LCR_L1EL_MASK; 690 reg |= PCIE_RC_LCR_L1EL_64US; 691 HWRITE4(sc, 0x100000 + PCIE_RC_LCR, reg); 692 693 dwpcie_link_config(sc); 694 695 reg = HREAD4(sc, PCIE_RC_LCR); 696 reg &= ~PCIE_RC_LCR_MAX_LINK_SPEEDS_MASK; 697 reg |= PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN1; 698 HWRITE4(sc, PCIE_RC_LCR, reg); 699 700 reset_deassert(sc->sc_node, "apps"); 701 702 for (timo = 20000; timo > 0; timo--) { 703 if (dwpcie_link_up(sc)) 704 break; 705 delay(10); 706 } 707 if (timo == 0) 708 printf("%s:%d: timeout\n", __func__, __LINE__); 709 710 if (OF_getpropint(sc->sc_node, "fsl,max-link-speed", 1) >= 2) { 711 reg = HREAD4(sc, PCIE_RC_LCR); 712 reg &= ~PCIE_RC_LCR_MAX_LINK_SPEEDS_MASK; 713 reg |= PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN2; 714 HWRITE4(sc, PCIE_RC_LCR, reg); 715 716 reg = HREAD4(sc, PCIE_LINK_WIDTH_SPEED_CTRL); 717 reg |= PCIE_LINK_WIDTH_SPEED_CTRL_CHANGE; 718 HWRITE4(sc, PCIE_LINK_WIDTH_SPEED_CTRL, reg); 719 720 for (timo = 20000; timo > 0; timo--) { 721 if (dwpcie_link_up(sc)) 722 break; 723 delay(10); 724 } 725 if (timo == 0) 726 printf("%s:%d: timeout\n", __func__, __LINE__); 727 } 728 729 sc->sc_ih = fdt_intr_establish(sc->sc_node, IPL_AUDIO | IPL_MPSAFE, 730 dwpcie_imx8mq_intr, sc, sc->sc_dev.dv_xname); 731 732 /* Unmask INTx interrupts. */ 733 HWRITE4(sc, PCIE_GLOBAL_INT_MASK, 734 PCIE_GLOBAL_INT_MASK_INT_A | PCIE_GLOBAL_INT_MASK_INT_B | 735 PCIE_GLOBAL_INT_MASK_INT_C | PCIE_GLOBAL_INT_MASK_INT_D); 736 737 if (clkreq_gpiolen > 0) 738 free(clkreq_gpio, M_TEMP, clkreq_gpiolen); 739 if (disable_gpiolen > 0) 740 free(disable_gpio, M_TEMP, disable_gpiolen); 741 if (reset_gpiolen > 0) 742 free(reset_gpio, M_TEMP, reset_gpiolen); 743 } 744 745 int 746 dwpcie_imx8mq_intr(void *arg) 747 { 748 struct dwpcie_softc *sc = arg; 749 uint32_t cause; 750 751 /* Acknowledge interrupts. */ 752 cause = HREAD4(sc, PCIE_GLOBAL_INT_CAUSE); 753 HWRITE4(sc, PCIE_GLOBAL_INT_CAUSE, cause); 754 755 /* INTx interrupt, so not really ours. */ 756 return 0; 757 } 758 759 void 760 dwpcie_atu_config(struct dwpcie_softc *sc, int index, int type, 761 uint64_t cpu_addr, uint64_t pci_addr, uint64_t size) 762 { 763 uint32_t reg, off; 764 int timo; 765 766 off = sc->sc_atu_base + IATU_OFFSET_UNROLL(index); 767 if (!sc->sc_atu_unroll) { 768 off = IATU_OFFSET_VIEWPORT; 769 HWRITE4(sc, IATU_VIEWPORT, index); 770 } 771 772 HWRITE4(sc, off + IATU_LWR_BASE_ADDR, cpu_addr); 773 HWRITE4(sc, off + IATU_UPPER_BASE_ADDR, cpu_addr >> 32); 774 HWRITE4(sc, off + IATU_LIMIT_ADDR, cpu_addr + size - 1); 775 HWRITE4(sc, off + IATU_LWR_TARGET_ADDR, pci_addr); 776 HWRITE4(sc, off + IATU_UPPER_TARGET_ADDR, pci_addr >> 32); 777 HWRITE4(sc, off + IATU_REGION_CTRL_1, type); 778 HWRITE4(sc, off + IATU_REGION_CTRL_2, IATU_REGION_CTRL_2_REGION_EN); 779 780 for (timo = 5; timo > 0; timo--) { 781 reg = HREAD4(sc, off + IATU_REGION_CTRL_2); 782 if (reg & IATU_REGION_CTRL_2_REGION_EN) 783 break; 784 delay(9000); 785 } 786 if (timo == 0) 787 printf("%s:%d: timeout\n", __func__, __LINE__); 788 } 789 790 int 791 dwpcie_link_up(struct dwpcie_softc *sc) 792 { 793 uint32_t reg; 794 795 reg = HREAD4(sc, PCIE_PHY_DEBUG_R1); 796 if ((reg & PCIE_PHY_DEBUG_R1_XMLH_LINK_UP) != 0 && 797 (reg & PCIE_PHY_DEBUG_R1_XMLH_LINK_IN_TRAINING) == 0) 798 return 1; 799 return 0; 800 } 801 802 void 803 dwpcie_attach_hook(struct device *parent, struct device *self, 804 struct pcibus_attach_args *pba) 805 { 806 } 807 808 int 809 dwpcie_bus_maxdevs(void *v, int bus) 810 { 811 struct dwpcie_softc *sc = v; 812 813 if (bus == sc->sc_bus || bus == sc->sc_bus + 1) 814 return 1; 815 return 32; 816 } 817 818 pcitag_t 819 dwpcie_make_tag(void *v, int bus, int device, int function) 820 { 821 return ((bus << 24) | (device << 19) | (function << 16)); 822 } 823 824 void 825 dwpcie_decompose_tag(void *v, pcitag_t tag, int *bp, int *dp, int *fp) 826 { 827 if (bp != NULL) 828 *bp = (tag >> 24) & 0xff; 829 if (dp != NULL) 830 *dp = (tag >> 19) & 0x1f; 831 if (fp != NULL) 832 *fp = (tag >> 16) & 0x7; 833 } 834 835 int 836 dwpcie_conf_size(void *v, pcitag_t tag) 837 { 838 return PCIE_CONFIG_SPACE_SIZE; 839 } 840 841 pcireg_t 842 dwpcie_conf_read(void *v, pcitag_t tag, int reg) 843 { 844 struct dwpcie_softc *sc = v; 845 int bus, dev, fn; 846 uint32_t ret; 847 848 dwpcie_decompose_tag(sc, tag, &bus, &dev, &fn); 849 if (bus == sc->sc_bus) { 850 KASSERT(dev == 0); 851 return HREAD4(sc, tag | reg); 852 } 853 854 if (bus == sc->sc_bus + 1) { 855 dwpcie_atu_config(sc, IATU_VIEWPORT_INDEX1, 856 IATU_REGION_CTRL_1_TYPE_CFG0, 857 sc->sc_cfg0_base, tag, sc->sc_cfg0_size); 858 ret = bus_space_read_4(sc->sc_iot, sc->sc_cfg0_ioh, reg); 859 } else { 860 dwpcie_atu_config(sc, IATU_VIEWPORT_INDEX1, 861 IATU_REGION_CTRL_1_TYPE_CFG1, 862 sc->sc_cfg1_base, tag, sc->sc_cfg1_size); 863 ret = bus_space_read_4(sc->sc_iot, sc->sc_cfg1_ioh, reg); 864 } 865 if (sc->sc_num_viewport <= 2) 866 dwpcie_atu_config(sc, IATU_VIEWPORT_INDEX1, 867 IATU_REGION_CTRL_1_TYPE_IO, sc->sc_io_base, 868 sc->sc_io_bus_addr, sc->sc_io_size); 869 870 return ret; 871 } 872 873 void 874 dwpcie_conf_write(void *v, pcitag_t tag, int reg, pcireg_t data) 875 { 876 struct dwpcie_softc *sc = v; 877 int bus, dev, fn; 878 879 dwpcie_decompose_tag(sc, tag, &bus, &dev, &fn); 880 if (bus == sc->sc_bus) { 881 KASSERT(dev == 0); 882 HWRITE4(sc, tag | reg, data); 883 return; 884 } 885 886 if (bus == sc->sc_bus + 1) { 887 dwpcie_atu_config(sc, IATU_VIEWPORT_INDEX1, 888 IATU_REGION_CTRL_1_TYPE_CFG0, 889 sc->sc_cfg0_base, tag, sc->sc_cfg0_size); 890 bus_space_write_4(sc->sc_iot, sc->sc_cfg0_ioh, reg, data); 891 } else { 892 dwpcie_atu_config(sc, IATU_VIEWPORT_INDEX1, 893 IATU_REGION_CTRL_1_TYPE_CFG1, 894 sc->sc_cfg1_base, tag, sc->sc_cfg1_size); 895 bus_space_write_4(sc->sc_iot, sc->sc_cfg1_ioh, reg, data); 896 } 897 if (sc->sc_num_viewport <= 2) 898 dwpcie_atu_config(sc, IATU_VIEWPORT_INDEX1, 899 IATU_REGION_CTRL_1_TYPE_IO, sc->sc_io_base, 900 sc->sc_io_bus_addr, sc->sc_io_size); 901 } 902 903 int 904 dwpcie_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp) 905 { 906 int pin = pa->pa_rawintrpin; 907 908 if (pin == 0 || pin > PCI_INTERRUPT_PIN_MAX) 909 return -1; 910 911 if (pa->pa_tag == 0) 912 return -1; 913 914 ihp->ih_pc = pa->pa_pc; 915 ihp->ih_tag = pa->pa_intrtag; 916 ihp->ih_intrpin = pa->pa_intrpin; 917 ihp->ih_type = PCI_INTX; 918 919 return 0; 920 } 921 922 const char * 923 dwpcie_intr_string(void *v, pci_intr_handle_t ih) 924 { 925 switch (ih.ih_type) { 926 case PCI_MSI: 927 return "msi"; 928 case PCI_MSIX: 929 return "msix"; 930 } 931 932 return "intx"; 933 } 934 935 void * 936 dwpcie_intr_establish(void *v, pci_intr_handle_t ih, int level, 937 int (*func)(void *), void *arg, char *name) 938 { 939 struct dwpcie_softc *sc = v; 940 void *cookie; 941 942 KASSERT(ih.ih_type != PCI_NONE); 943 944 if (ih.ih_type != PCI_INTX) { 945 uint64_t addr, data; 946 947 /* Assume hardware passes Requester ID as sideband data. */ 948 data = pci_requester_id(ih.ih_pc, ih.ih_tag); 949 cookie = fdt_intr_establish_msi(sc->sc_node, &addr, 950 &data, level, func, arg, (void *)name); 951 if (cookie == NULL) 952 return NULL; 953 954 /* TODO: translate address to the PCI device's view */ 955 956 if (ih.ih_type == PCI_MSIX) { 957 pci_msix_enable(ih.ih_pc, ih.ih_tag, 958 &sc->sc_bus_memt, ih.ih_intrpin, addr, data); 959 } else 960 pci_msi_enable(ih.ih_pc, ih.ih_tag, addr, data); 961 } else { 962 int bus, dev, fn; 963 uint32_t reg[4]; 964 965 dwpcie_decompose_tag(sc, ih.ih_tag, &bus, &dev, &fn); 966 967 reg[0] = bus << 16 | dev << 11 | fn << 8; 968 reg[1] = reg[2] = 0; 969 reg[3] = ih.ih_intrpin; 970 971 cookie = fdt_intr_establish_imap(sc->sc_node, reg, 972 sizeof(reg), level, func, arg, name); 973 } 974 975 return cookie; 976 } 977 978 void 979 dwpcie_intr_disestablish(void *v, void *cookie) 980 { 981 panic("%s", __func__); 982 } 983 984 int 985 dwpcie_bs_iomap(bus_space_tag_t t, bus_addr_t addr, bus_size_t size, 986 int flags, bus_space_handle_t *bshp) 987 { 988 struct dwpcie_softc *sc = t->bus_private; 989 int i; 990 991 for (i = 0; i < sc->sc_nranges; i++) { 992 uint64_t pci_start = sc->sc_ranges[i].pci_base; 993 uint64_t pci_end = pci_start + sc->sc_ranges[i].size; 994 uint64_t phys_start = sc->sc_ranges[i].phys_base; 995 996 if ((sc->sc_ranges[i].flags & 0x03000000) == 0x01000000 && 997 addr >= pci_start && addr + size <= pci_end) { 998 return bus_space_map(sc->sc_iot, 999 addr - pci_start + phys_start, size, flags, bshp); 1000 } 1001 } 1002 1003 return ENXIO; 1004 } 1005 1006 int 1007 dwpcie_bs_memmap(bus_space_tag_t t, bus_addr_t addr, bus_size_t size, 1008 int flags, bus_space_handle_t *bshp) 1009 { 1010 struct dwpcie_softc *sc = t->bus_private; 1011 int i; 1012 1013 for (i = 0; i < sc->sc_nranges; i++) { 1014 uint64_t pci_start = sc->sc_ranges[i].pci_base; 1015 uint64_t pci_end = pci_start + sc->sc_ranges[i].size; 1016 uint64_t phys_start = sc->sc_ranges[i].phys_base; 1017 1018 if ((sc->sc_ranges[i].flags & 0x03000000) == 0x02000000 && 1019 addr >= pci_start && addr + size <= pci_end) { 1020 return bus_space_map(sc->sc_iot, 1021 addr - pci_start + phys_start, size, flags, bshp); 1022 } 1023 } 1024 1025 return ENXIO; 1026 } 1027