Date: Mon, 16 Jan 2012 19:41:24 +0000 (UTC) From: Nathan Whitehorn <nwhitehorn@FreeBSD.org> To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r230227 - projects/pseries/powerpc/pseries Message-ID: <201201161941.q0GJfOo2048684@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: nwhitehorn Date: Mon Jan 16 19:41:24 2012 New Revision: 230227 URL: http://svn.freebsd.org/changeset/base/230227 Log: Actually follow the spec with respect to the "ranges" property of PCI bridges instead of the ad hoc parsing we had before. This lets it successfully attach and operate emulated PCI devices in QEMU. Modified: projects/pseries/powerpc/pseries/rtas_pci.c Modified: projects/pseries/powerpc/pseries/rtas_pci.c ============================================================================== --- projects/pseries/powerpc/pseries/rtas_pci.c Mon Jan 16 19:34:21 2012 (r230226) +++ projects/pseries/powerpc/pseries/rtas_pci.c Mon Jan 16 19:41:24 2012 (r230227) @@ -99,11 +99,9 @@ static phandle_t rtaspci_get_node(device struct ofw_pci_range { uint32_t pci_hi; - uint32_t pci_mid; - uint32_t pci_lo; + uint64_t pci; uint64_t host; - uint32_t size_hi; - uint32_t size_lo; + uint64_t size; }; static int rtaspci_fill_ranges(phandle_t node, struct ofw_pci_range **ranges, @@ -156,7 +154,6 @@ struct rtaspci_softc { struct rman sc_mem_rman; bus_space_tag_t sc_memt; bus_dma_tag_t sc_dmat; - vm_offset_t sc_iostart; struct ofw_bus_iinfo sc_pci_iinfo; }; @@ -196,8 +193,8 @@ rtaspci_attach(device_t dev) struct rtaspci_softc *sc; phandle_t node; u_int32_t busrange[2]; - struct ofw_pci_range *rp, *io, *mem[5]; - int nmem, i, error; + struct ofw_pci_range *rp; + int error; node = ofw_bus_get_node(dev); sc = device_get_softc(dev); @@ -225,53 +222,40 @@ rtaspci_attach(device_t dev) return (ENXIO); } - io = NULL; - nmem = 0; + sc->sc_io_rman.rm_type = RMAN_ARRAY; + sc->sc_io_rman.rm_descr = "PCI I/O Ports"; + error = rman_init(&sc->sc_io_rman); + if (error) { + device_printf(dev, "rman_init() failed. error = %d\n", error); + return (error); + } + + sc->sc_mem_rman.rm_type = RMAN_ARRAY; + sc->sc_mem_rman.rm_descr = "PCI Memory"; + error = rman_init(&sc->sc_mem_rman); + if (error) { + device_printf(dev, "rman_init() failed. error = %d\n", error); + return (error); + } for (rp = sc->sc_range; rp < sc->sc_range + sc->sc_nrange && rp->pci_hi != 0; rp++) { + error = 0; + switch (rp->pci_hi & OFW_PCI_PHYS_HI_SPACEMASK) { case OFW_PCI_PHYS_HI_SPACE_CONFIG: break; case OFW_PCI_PHYS_HI_SPACE_IO: - io = rp; + error = rman_manage_region(&sc->sc_io_rman, rp->pci, + rp->pci + rp->size); break; case OFW_PCI_PHYS_HI_SPACE_MEM32: - mem[nmem] = rp; - nmem++; - break; case OFW_PCI_PHYS_HI_SPACE_MEM64: + error = rman_manage_region(&sc->sc_mem_rman, rp->pci, + rp->pci + rp->size); break; } - } - if (io == NULL) { - device_printf(dev, "can't find io range\n"); - return (ENXIO); - } - sc->sc_io_rman.rm_type = RMAN_ARRAY; - sc->sc_io_rman.rm_descr = "PCI I/O Ports"; - sc->sc_iostart = io->host; - if (rman_init(&sc->sc_io_rman) != 0 || - rman_manage_region(&sc->sc_io_rman, io->pci_lo, - io->pci_lo + io->size_lo) != 0) { - panic("rtaspci_attach: failed to set up I/O rman"); - } - - if (nmem == 0) { - device_printf(dev, "can't find mem ranges\n"); - return (ENXIO); - } - sc->sc_mem_rman.rm_type = RMAN_ARRAY; - sc->sc_mem_rman.rm_descr = "PCI Memory"; - error = rman_init(&sc->sc_mem_rman); - if (error) { - device_printf(dev, "rman_init() failed. error = %d\n", error); - return (error); - } - for (i = 0; i < nmem; i++) { - error = rman_manage_region(&sc->sc_mem_rman, mem[i]->pci_lo, - mem[i]->pci_lo + mem[i]->size_lo); if (error) { device_printf(dev, "rman_manage_region() failed. error = %d\n", error); @@ -481,16 +465,37 @@ rtaspci_activate_resource(device_t bus, return (bus_activate_resource(bus, type, rid, res)); } if (type == SYS_RES_MEMORY || type == SYS_RES_IOPORT) { + struct ofw_pci_range *rp; vm_offset_t start; + int space; start = (vm_offset_t)rman_get_start(res); /* - * Some bridges have I/O ports relative to the start of I/O - * space, so adjust if we are under that. + * Map this through the ranges list */ - if (type == SYS_RES_IOPORT && start < sc->sc_iostart) - start += sc->sc_iostart; + for (rp = sc->sc_range; rp < sc->sc_range + sc->sc_nrange && + rp->pci_hi != 0; rp++) { + if (start < rp->pci || start >= rp->pci + rp->size) + continue; + + switch (rp->pci_hi & OFW_PCI_PHYS_HI_SPACEMASK) { + case OFW_PCI_PHYS_HI_SPACE_IO: + space = SYS_RES_IOPORT; + break; + case OFW_PCI_PHYS_HI_SPACE_MEM32: + case OFW_PCI_PHYS_HI_SPACE_MEM64: + space = SYS_RES_MEMORY; + break; + default: + space = -1; + } + + if (type == space) { + start += (rp->host - rp->pci); + break; + } + } if (bootverbose) printf("rtaspci mapdev: start %zx, len %ld\n", start, @@ -540,15 +545,23 @@ static int rtaspci_fill_ranges(phandle_t node, struct ofw_pci_range **ranges, int *nranges) { - int address_cells = 1; + int host_address_cells = 1, pci_address_cells = 3, size_cells = 2; cell_t *base_ranges; ssize_t nbase_ranges; int i, j; - OF_getprop(OF_parent(node), "#address-cells", &address_cells, - sizeof(address_cells)); - if (address_cells > 2) - panic("RTAS PCI: Addresses too wide (%d)", address_cells); + OF_getprop(OF_parent(node), "#address-cells", &host_address_cells, + sizeof(host_address_cells)); + if (host_address_cells > 2) + panic("RTAS PCI: Addresses too wide (%d)", host_address_cells); + OF_getprop(node, "#address-cells", &pci_address_cells, + sizeof(pci_address_cells)); + if (pci_address_cells > 3) + panic("RTAS PCI: PCI addresses too wide (%d)", + pci_address_cells); + OF_getprop(node, "#size-cells", &size_cells, sizeof(size_cells)); + if (size_cells > 2) + panic("RTAS PCI: Sizes too wide (%d)", size_cells); nbase_ranges = OF_getproplen(node, "ranges"); if (nbase_ranges <= 0) @@ -556,21 +569,28 @@ rtaspci_fill_ranges(phandle_t node, stru base_ranges = malloc(nbase_ranges, M_DEVBUF, M_WAITOK); OF_getprop(node, "ranges", base_ranges, nbase_ranges); - *nranges = nbase_ranges / sizeof(cell_t) / (5 + address_cells); + *nranges = nbase_ranges / sizeof(cell_t) / + (pci_address_cells + host_address_cells + size_cells); *ranges = malloc(*nranges * sizeof(struct ofw_pci_range), M_DEVBUF, M_WAITOK); for (i = 0, j = 0; i < *nranges; i++) { (*ranges)[i].pci_hi = base_ranges[j++]; - (*ranges)[i].pci_mid = base_ranges[j++]; - (*ranges)[i].pci_lo = base_ranges[j++]; + (*ranges)[i].pci = base_ranges[j++]; + if (pci_address_cells == 3) { + (*ranges)[i].pci <<= 32; + (*ranges)[i].pci |= base_ranges[j++]; + } (*ranges)[i].host = base_ranges[j++]; - if (address_cells == 2) { + if (host_address_cells == 2) { (*ranges)[i].host <<= 32; (*ranges)[i].host |= base_ranges[j++]; } - (*ranges)[i].size_hi = base_ranges[j++]; - (*ranges)[i].size_lo = base_ranges[j++]; + (*ranges)[i].size = base_ranges[j++]; + if (size_cells == 2) { + (*ranges)[i].size <<= 32; + (*ranges)[i].size |= base_ranges[j++]; + } } free(base_ranges, M_DEVBUF);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201201161941.q0GJfOo2048684>