From owner-svn-src-all@freebsd.org Sat Sep 12 22:49:35 2015 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 48917A020AA; Sat, 12 Sep 2015 22:49:35 +0000 (UTC) (envelope-from marius@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 386B411B3; Sat, 12 Sep 2015 22:49:35 +0000 (UTC) (envelope-from marius@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.70]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id t8CMnZew089076; Sat, 12 Sep 2015 22:49:35 GMT (envelope-from marius@FreeBSD.org) Received: (from marius@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id t8CMnXpH089068; Sat, 12 Sep 2015 22:49:33 GMT (envelope-from marius@FreeBSD.org) Message-Id: <201509122249.t8CMnXpH089068@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: marius set sender to marius@FreeBSD.org using -f From: Marius Strobl Date: Sat, 12 Sep 2015 22:49:33 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r287726 - in head/sys: conf sparc64/pci X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 12 Sep 2015 22:49:35 -0000 Author: marius Date: Sat Sep 12 22:49:32 2015 New Revision: 287726 URL: https://svnweb.freebsd.org/changeset/base/287726 Log: - Factor out the common and generic parts of the sparc64 host-PCI-bridge drivers into the revived sys/sparc64/pci/ofw_pci.c, previously already serving a similar purpose. This has been done with sun4v in mind, which explains a) the otherwise not that obvious scheme employed and b) why reusing sys/powerpc/ofw/ofw_pci.c was even lesser an option. - Add a workaround for QEMU once again not emulating real machines, in this case by not providing the OFW_PCI_CS_MEM64 range. [1] Submitted by: jhb [1] MFC after: 1 week Added: head/sys/sparc64/pci/ofw_pci.c - copied, changed from r170929, head/sys/sparc64/pci/ofw_pci.c Modified: head/sys/conf/files.sparc64 head/sys/sparc64/pci/fire.c head/sys/sparc64/pci/firereg.h head/sys/sparc64/pci/firevar.h head/sys/sparc64/pci/ofw_pci.h head/sys/sparc64/pci/psycho.c head/sys/sparc64/pci/psychoreg.h head/sys/sparc64/pci/psychovar.h head/sys/sparc64/pci/schizo.c head/sys/sparc64/pci/schizoreg.h head/sys/sparc64/pci/schizovar.h Modified: head/sys/conf/files.sparc64 ============================================================================== --- head/sys/conf/files.sparc64 Sat Sep 12 21:23:24 2015 (r287725) +++ head/sys/conf/files.sparc64 Sat Sep 12 22:49:32 2015 (r287726) @@ -82,6 +82,7 @@ sparc64/isa/isa_dma.c optional isa sparc64/isa/ofw_isa.c optional ebus | isa sparc64/pci/apb.c optional pci sparc64/pci/fire.c optional pci +sparc64/pci/ofw_pci.c optional pci sparc64/pci/ofw_pcib.c optional pci sparc64/pci/ofw_pcib_subr.c optional pci sparc64/pci/ofw_pcibus.c optional pci Modified: head/sys/sparc64/pci/fire.c ============================================================================== --- head/sys/sparc64/pci/fire.c Sat Sep 12 21:23:24 2015 (r287725) +++ head/sys/sparc64/pci/fire.c Sat Sep 12 22:49:32 2015 (r287726) @@ -59,7 +59,6 @@ __FBSDID("$FreeBSD$"); #include #include -#include #include #include @@ -68,7 +67,6 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include #include #include #include @@ -111,19 +109,14 @@ static driver_filter_t fire_xcb; /* * Methods */ -static bus_activate_resource_t fire_activate_resource; -static bus_adjust_resource_t fire_adjust_resource; static pcib_alloc_msi_t fire_alloc_msi; static pcib_alloc_msix_t fire_alloc_msix; static bus_alloc_resource_t fire_alloc_resource; static device_attach_t fire_attach; -static bus_get_dma_tag_t fire_get_dma_tag; -static ofw_bus_get_node_t fire_get_node; static pcib_map_msi_t fire_map_msi; static pcib_maxslots_t fire_maxslots; static device_probe_t fire_probe; static pcib_read_config_t fire_read_config; -static bus_read_ivar_t fire_read_ivar; static pcib_release_msi_t fire_release_msi; static pcib_release_msix_t fire_release_msix; static pcib_route_interrupt_t fire_route_interrupt; @@ -140,15 +133,15 @@ static device_method_t fire_methods[] = DEVMETHOD(device_resume, bus_generic_resume), /* Bus interface */ - DEVMETHOD(bus_read_ivar, fire_read_ivar), + DEVMETHOD(bus_read_ivar, ofw_pci_read_ivar), DEVMETHOD(bus_setup_intr, fire_setup_intr), DEVMETHOD(bus_teardown_intr, fire_teardown_intr), DEVMETHOD(bus_alloc_resource, fire_alloc_resource), - DEVMETHOD(bus_activate_resource, fire_activate_resource), + DEVMETHOD(bus_activate_resource, ofw_pci_activate_resource), DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), - DEVMETHOD(bus_adjust_resource, fire_adjust_resource), + DEVMETHOD(bus_adjust_resource, ofw_pci_adjust_resource), DEVMETHOD(bus_release_resource, bus_generic_release_resource), - DEVMETHOD(bus_get_dma_tag, fire_get_dma_tag), + DEVMETHOD(bus_get_dma_tag, ofw_pci_get_dma_tag), /* pcib interface */ DEVMETHOD(pcib_maxslots, fire_maxslots), @@ -162,7 +155,7 @@ static device_method_t fire_methods[] = DEVMETHOD(pcib_map_msi, fire_map_msi), /* ofw_bus interface */ - DEVMETHOD(ofw_bus_get_node, fire_get_node), + DEVMETHOD(ofw_bus_get_node, ofw_pci_get_node), DEVMETHOD_END }; @@ -296,7 +289,7 @@ fire_attach(device_t dev) struct ofw_pci_msi_eq_to_devino msi_eq_to_devino; struct fire_msiqarg *fmqa; struct timecounter *tc; - struct ofw_pci_ranges *range; + bus_dma_tag_t dmat; uint64_t ino_bitmap, val; phandle_t node; uint32_t prop, prop_array[2]; @@ -310,7 +303,6 @@ fire_attach(device_t dev) mode = desc->fd_mode; sc->sc_dev = dev; - sc->sc_node = node; sc->sc_mode = mode; sc->sc_flags = 0; @@ -715,79 +707,21 @@ fire_attach(device_t dev) sc->sc_is.is_bushandle = rman_get_bushandle(sc->sc_mem_res[FIRE_PCI]); sc->sc_is.is_iommu = FO_PCI_MMU; val = FIRE_PCI_READ_8(sc, FO_PCI_MMU + IMR_CTL); - iommu_init(device_get_nameunit(sc->sc_dev), &sc->sc_is, 7, -1, 0); + iommu_init(device_get_nameunit(dev), &sc->sc_is, 7, -1, 0); #ifdef FIRE_DEBUG device_printf(dev, "FO_PCI_MMU + IMR_CTL 0x%016llx -> 0x%016llx\n", (long long unsigned)val, (long long unsigned)sc->sc_is.is_cr); #endif - - /* Initialize memory and I/O rmans. */ - sc->sc_pci_io_rman.rm_type = RMAN_ARRAY; - sc->sc_pci_io_rman.rm_descr = "Fire PCI I/O Ports"; - if (rman_init(&sc->sc_pci_io_rman) != 0 || - rman_manage_region(&sc->sc_pci_io_rman, 0, FO_IO_SIZE) != 0) - panic("%s: failed to set up I/O rman", __func__); - sc->sc_pci_mem_rman.rm_type = RMAN_ARRAY; - sc->sc_pci_mem_rman.rm_descr = "Fire PCI Memory"; - if (rman_init(&sc->sc_pci_mem_rman) != 0 || - rman_manage_region(&sc->sc_pci_mem_rman, 0, FO_MEM_SIZE) != 0) - panic("%s: failed to set up memory rman", __func__); - - i = OF_getprop_alloc(node, "ranges", sizeof(*range), (void **)&range); - /* - * Make sure that the expected ranges are present. The - * OFW_PCI_CS_MEM64 one is not currently used though. - */ - if (i != FIRE_NRANGE) - panic("%s: unsupported number of ranges", __func__); - /* - * Find the addresses of the various bus spaces. - * There should not be multiple ones of one kind. - * The physical start addresses of the ranges are the configuration, - * memory and I/O handles. - */ - for (i = 0; i < FIRE_NRANGE; i++) { - j = OFW_PCI_RANGE_CS(&range[i]); - if (sc->sc_pci_bh[j] != 0) - panic("%s: duplicate range for space %d", - __func__, j); - sc->sc_pci_bh[j] = OFW_PCI_RANGE_PHYS(&range[i]); - } - free(range, M_OFWPROP); - - /* Allocate our tags. */ - sc->sc_pci_iot = sparc64_alloc_bus_tag(NULL, PCI_IO_BUS_SPACE); - if (sc->sc_pci_iot == NULL) - panic("%s: could not allocate PCI I/O tag", __func__); - sc->sc_pci_cfgt = sparc64_alloc_bus_tag(NULL, PCI_CONFIG_BUS_SPACE); - if (sc->sc_pci_cfgt == NULL) - panic("%s: could not allocate PCI configuration space tag", - __func__); + /* Create our DMA tag. */ if (bus_dma_tag_create(bus_get_dma_tag(dev), 8, 0x100000000, sc->sc_is.is_pmaxaddr, ~0, NULL, NULL, sc->sc_is.is_pmaxaddr, - 0xff, 0xffffffff, 0, NULL, NULL, &sc->sc_pci_dmat) != 0) + 0xff, 0xffffffff, 0, NULL, NULL, &dmat) != 0) panic("%s: could not create PCI DMA tag", __func__); - /* Customize the tag. */ - sc->sc_pci_dmat->dt_cookie = &sc->sc_is; - sc->sc_pci_dmat->dt_mt = &sc->sc_dma_methods; + dmat->dt_cookie = &sc->sc_is; + dmat->dt_mt = &sc->sc_dma_methods; - /* - * Get the bus range from the firmware. - * NB: Neither Fire nor Oberon support PCI bus reenumeration. - */ - i = OF_getprop(node, "bus-range", (void *)prop_array, - sizeof(prop_array)); - if (i == -1) - panic("%s: could not get bus-range", __func__); - if (i != sizeof(prop_array)) - panic("%s: broken bus-range (%d)", __func__, i); - sc->sc_pci_secbus = prop_array[0]; - sc->sc_pci_subbus = prop_array[1]; - if (bootverbose != 0) - device_printf(dev, "bus range %u to %u; PCI bus %d\n", - sc->sc_pci_secbus, sc->sc_pci_subbus, sc->sc_pci_secbus); - - ofw_bus_setup_iinfo(node, &sc->sc_pci_iinfo, sizeof(ofw_pci_intr_t)); + if (ofw_pci_attach_common(dev, dmat, FO_IO_SIZE, FO_MEM_SIZE) != 0) + panic("%s: ofw_pci_attach_common() failed", __func__); #define FIRE_SYSCTL_ADD_UINT(name, arg, desc) \ SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), \ @@ -1390,136 +1324,44 @@ static uint32_t fire_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, int width) { - struct fire_softc *sc; - bus_space_handle_t bh; - u_long offset = 0; - uint32_t r, wrd; - int i; - uint16_t shrt; - uint8_t byte; - - sc = device_get_softc(dev); - if (bus < sc->sc_pci_secbus || bus > sc->sc_pci_subbus || - slot > PCI_SLOTMAX || func > PCI_FUNCMAX || reg > PCIE_REGMAX) - return (-1); - - offset = FO_CONF_OFF(bus, slot, func, reg); - bh = sc->sc_pci_bh[OFW_PCI_CS_CONFIG]; - switch (width) { - case 1: - i = bus_space_peek_1(sc->sc_pci_cfgt, bh, offset, &byte); - r = byte; - break; - case 2: - i = bus_space_peek_2(sc->sc_pci_cfgt, bh, offset, &shrt); - r = shrt; - break; - case 4: - i = bus_space_peek_4(sc->sc_pci_cfgt, bh, offset, &wrd); - r = wrd; - break; - default: - panic("%s: bad width", __func__); - /* NOTREACHED */ - } - if (i) { -#ifdef FIRE_DEBUG - printf("%s: read data error reading: %d.%d.%d: 0x%x\n", - __func__, bus, slot, func, reg); -#endif - r = -1; - } - return (r); + return (ofw_pci_read_config_common(dev, PCIE_REGMAX, FO_CONF_OFF(bus, + slot, func, reg), bus, slot, func, reg, width)); } static void fire_write_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, uint32_t val, int width) { - struct fire_softc *sc; - bus_space_handle_t bh; - u_long offset = 0; - - sc = device_get_softc(dev); - if (bus < sc->sc_pci_secbus || bus > sc->sc_pci_subbus || - slot > PCI_SLOTMAX || func > PCI_FUNCMAX || reg > PCIE_REGMAX) - return; - offset = FO_CONF_OFF(bus, slot, func, reg); - bh = sc->sc_pci_bh[OFW_PCI_CS_CONFIG]; - switch (width) { - case 1: - bus_space_write_1(sc->sc_pci_cfgt, bh, offset, val); - break; - case 2: - bus_space_write_2(sc->sc_pci_cfgt, bh, offset, val); - break; - case 4: - bus_space_write_4(sc->sc_pci_cfgt, bh, offset, val); - break; - default: - panic("%s: bad width", __func__); - /* NOTREACHED */ - } + ofw_pci_write_config_common(dev, PCIE_REGMAX, FO_CONF_OFF(bus, slot, + func, reg), bus, slot, func, reg, val, width); } static int fire_route_interrupt(device_t bridge, device_t dev, int pin) { - struct fire_softc *sc; - struct ofw_pci_register reg; - ofw_pci_intr_t pintr, mintr; - - sc = device_get_softc(bridge); - pintr = pin; - if (ofw_bus_lookup_imap(ofw_bus_get_node(dev), &sc->sc_pci_iinfo, - ®, sizeof(reg), &pintr, sizeof(pintr), &mintr, sizeof(mintr), - NULL) != 0) - return (mintr); - - device_printf(bridge, "could not route pin %d for device %d.%d\n", - pin, pci_get_slot(dev), pci_get_function(dev)); - return (PCI_INVALID_IRQ); -} - -static int -fire_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) -{ - struct fire_softc *sc; + ofw_pci_intr_t mintr; - sc = device_get_softc(dev); - switch (which) { - case PCIB_IVAR_DOMAIN: - *result = device_get_unit(dev); - return (0); - case PCIB_IVAR_BUS: - *result = sc->sc_pci_secbus; - return (0); - } - return (ENOENT); + mintr = ofw_pci_route_interrupt_common(bridge, dev, pin); + if (!PCI_INTERRUPT_VALID(mintr)) + device_printf(bridge, + "could not route pin %d for device %d.%d\n", + pin, pci_get_slot(dev), pci_get_function(dev)); + return (mintr); } static void fire_dmamap_sync(bus_dma_tag_t dt __unused, bus_dmamap_t map, bus_dmasync_op_t op) { - static u_char buf[VIS_BLOCKSIZE] __aligned(VIS_BLOCKSIZE); - register_t reg, s; if ((map->dm_flags & DMF_LOADED) == 0) return; - if ((op & BUS_DMASYNC_POSTREAD) != 0) { - s = intr_disable(); - reg = rd(fprs); - wr(fprs, reg | FPRS_FEF, 0); - __asm __volatile("stda %%f0, [%0] %1" - : : "r" (buf), "n" (ASI_BLK_COMMIT_S)); - membar(Sync); - wr(fprs, reg, 0); - intr_restore(s); - } else if ((op & BUS_DMASYNC_PREWRITE) != 0) + if ((op & BUS_DMASYNC_POSTREAD) != 0) + ofw_pci_dmamap_sync_stst_order_common(); + else if ((op & BUS_DMASYNC_PREWRITE) != 0) membar(Sync); } @@ -2013,121 +1855,13 @@ fire_alloc_resource(device_t bus, device u_long start, u_long end, u_long count, u_int flags) { struct fire_softc *sc; - struct resource *rv; - struct rman *rm; - sc = device_get_softc(bus); - switch (type) { - case SYS_RES_IRQ: - /* - * XXX: Don't accept blank ranges for now, only single - * interrupts. The other case should not happen with - * the MI PCI code... - * XXX: This may return a resource that is out of the - * range that was specified. Is this correct...? - */ - if (start != end) - panic("%s: XXX: interrupt range", __func__); - if (*rid == 0) - start = end = INTMAP_VEC(sc->sc_ign, end); - return (bus_generic_alloc_resource(bus, child, type, rid, - start, end, count, flags)); - case SYS_RES_MEMORY: - rm = &sc->sc_pci_mem_rman; - break; - case SYS_RES_IOPORT: - rm = &sc->sc_pci_io_rman; - break; - default: - return (NULL); - } - - rv = rman_reserve_resource(rm, start, end, count, flags & ~RF_ACTIVE, - child); - if (rv == NULL) - return (NULL); - rman_set_rid(rv, *rid); - - if ((flags & RF_ACTIVE) != 0 && bus_activate_resource(child, type, - *rid, rv) != 0) { - rman_release_resource(rv); - return (NULL); + if (type == SYS_RES_IRQ && *rid == 0) { + sc = device_get_softc(bus); + start = end = INTMAP_VEC(sc->sc_ign, end); } - return (rv); -} - -static int -fire_activate_resource(device_t bus, device_t child, int type, int rid, - struct resource *r) -{ - struct fire_softc *sc; - struct bus_space_tag *tag; - - sc = device_get_softc(bus); - switch (type) { - case SYS_RES_IRQ: - return (bus_generic_activate_resource(bus, child, type, rid, - r)); - case SYS_RES_MEMORY: - tag = sparc64_alloc_bus_tag(r, PCI_MEMORY_BUS_SPACE); - if (tag == NULL) - return (ENOMEM); - rman_set_bustag(r, tag); - rman_set_bushandle(r, sc->sc_pci_bh[OFW_PCI_CS_MEM32] + - rman_get_start(r)); - break; - case SYS_RES_IOPORT: - rman_set_bustag(r, sc->sc_pci_iot); - rman_set_bushandle(r, sc->sc_pci_bh[OFW_PCI_CS_IO] + - rman_get_start(r)); - break; - } - return (rman_activate_resource(r)); -} - -static int -fire_adjust_resource(device_t bus, device_t child, int type, - struct resource *r, u_long start, u_long end) -{ - struct fire_softc *sc; - struct rman *rm; - - sc = device_get_softc(bus); - switch (type) { - case SYS_RES_IRQ: - return (bus_generic_adjust_resource(bus, child, type, r, - start, end)); - case SYS_RES_MEMORY: - rm = &sc->sc_pci_mem_rman; - break; - case SYS_RES_IOPORT: - rm = &sc->sc_pci_io_rman; - break; - default: - return (EINVAL); - } - if (rman_is_region_manager(r, rm) == 0) - return (EINVAL); - return (rman_adjust_resource(r, start, end)); -} - -static bus_dma_tag_t -fire_get_dma_tag(device_t bus, device_t child __unused) -{ - struct fire_softc *sc; - - sc = device_get_softc(bus); - return (sc->sc_pci_dmat); -} - -static phandle_t -fire_get_node(device_t bus, device_t child __unused) -{ - struct fire_softc *sc; - - sc = device_get_softc(bus); - /* We only have one child, the PCI bus, which needs our own node. */ - return (sc->sc_node); + return (ofw_pci_alloc_resource(bus, child, type, rid, start, end, + count, flags)); } static u_int Modified: head/sys/sparc64/pci/firereg.h ============================================================================== --- head/sys/sparc64/pci/firereg.h Sat Sep 12 21:23:24 2015 (r287725) +++ head/sys/sparc64/pci/firereg.h Sat Sep 12 22:49:32 2015 (r287726) @@ -30,7 +30,6 @@ #define _SPARC64_PCI_FIREREG_H_ #define FIRE_NINTR 3 /* 2 OFW + 1 MSIq */ -#define FIRE_NRANGE 4 #define FIRE_NREG 2 #define FIRE_PCI 0 Modified: head/sys/sparc64/pci/firevar.h ============================================================================== --- head/sys/sparc64/pci/firevar.h Sat Sep 12 21:23:24 2015 (r287725) +++ head/sys/sparc64/pci/firevar.h Sat Sep 12 22:49:32 2015 (r287726) @@ -32,6 +32,12 @@ #define _SPARC64_PCI_FIREVAR_H_ struct fire_softc { + /* + * This is here so that we can hook up the common bus interface + * methods in ofw_pci.c directly. + */ + struct ofw_pci_softc sc_ops; + struct iommu_state sc_is; struct bus_dma_methods sc_dma_methods; @@ -42,13 +48,6 @@ struct fire_softc { struct resource *sc_irq_res[FIRE_NINTR]; void *sc_ihand[FIRE_NINTR]; - struct rman sc_pci_mem_rman; - struct rman sc_pci_io_rman; - bus_space_handle_t sc_pci_bh[FIRE_NRANGE]; - bus_space_tag_t sc_pci_cfgt; - bus_space_tag_t sc_pci_iot; - bus_dma_tag_t sc_pci_dmat; - device_t sc_dev; uint64_t *sc_msiq; @@ -66,8 +65,6 @@ struct fire_softc { uint32_t sc_msiq_first; uint32_t sc_msiq_ino_first; - phandle_t sc_node; - u_int sc_mode; #define FIRE_MODE_FIRE 0 #define FIRE_MODE_OBERON 1 @@ -87,11 +84,6 @@ struct fire_softc { uint32_t sc_stats_tlu_oe_rx_err; uint32_t sc_stats_tlu_oe_tx_err; uint32_t sc_stats_ubc_dmardue; - - uint8_t sc_pci_secbus; - uint8_t sc_pci_subbus; - - struct ofw_bus_iinfo sc_pci_iinfo; }; #endif /* !_SPARC64_PCI_FIREVAR_H_ */ Copied and modified: head/sys/sparc64/pci/ofw_pci.c (from r170929, head/sys/sparc64/pci/ofw_pci.c) ============================================================================== --- head/sys/sparc64/pci/ofw_pci.c Mon Jun 18 21:46:07 2007 (r170929, copy source) +++ head/sys/sparc64/pci/ofw_pci.c Sat Sep 12 22:49:32 2015 (r287726) @@ -1,6 +1,7 @@ /*- * Copyright (c) 1999, 2000 Matthew R. Green * Copyright (c) 2001 - 2003 by Thomas Moestl + * Copyright (c) 2005 - 2015 by Marius Strobl * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -35,42 +36,371 @@ __FBSDID("$FreeBSD$"); #include "opt_ofw_pci.h" #include -#include #include #include +#include +#include +#include +#include #include +#include +#include + +#include #include +#include +#include +#include +#include #include -static uint8_t pci_bus_cnt; -static phandle_t *pci_bus_map; -static int pci_bus_map_sz; - -#define PCI_BUS_MAP_INC 10 - -uint8_t -ofw_pci_alloc_busno(phandle_t node) -{ - phandle_t *om; - int osz; - uint8_t n; - - n = pci_bus_cnt++; - /* Establish a mapping between bus numbers and device nodes. */ - if (n >= pci_bus_map_sz) { - osz = pci_bus_map_sz; - om = pci_bus_map; - pci_bus_map_sz = n + PCI_BUS_MAP_INC; - pci_bus_map = malloc(sizeof(*pci_bus_map) * pci_bus_map_sz, - M_DEVBUF, M_WAITOK | M_ZERO); - if (om != NULL) { - bcopy(om, pci_bus_map, sizeof(*om) * osz); - free(om, M_DEVBUF); +int +ofw_pci_attach_common(device_t dev, bus_dma_tag_t dmat, u_long iosize, + u_long memsize) +{ + struct ofw_pci_softc *sc; + struct ofw_pci_ranges *range; + phandle_t node; + uint32_t prop_array[2]; + u_int i, j, nrange; + + sc = device_get_softc(dev); + node = ofw_bus_get_node(dev); + sc->sc_node = node; + sc->sc_pci_dmat = dmat; + + /* Initialize memory and I/O rmans. */ + sc->sc_pci_io_rman.rm_type = RMAN_ARRAY; + sc->sc_pci_io_rman.rm_descr = "PCI I/O Ports"; + if (rman_init(&sc->sc_pci_io_rman) != 0 || + rman_manage_region(&sc->sc_pci_io_rman, 0, iosize) != 0) { + device_printf(dev, "failed to set up I/O rman\n"); + return (ENXIO); + } + sc->sc_pci_mem_rman.rm_type = RMAN_ARRAY; + sc->sc_pci_mem_rman.rm_descr = "PCI Memory"; + if (rman_init(&sc->sc_pci_mem_rman) != 0 || + rman_manage_region(&sc->sc_pci_mem_rman, 0, memsize) != 0) { + device_printf(dev, "failed to set up memory rman\n"); + return (ENXIO); + } + + /* + * Find the addresses of the various bus spaces. The physical + * start addresses of the ranges are the configuration, I/O and + * memory handles. There should not be multiple ones of one kind. + */ + nrange = OF_getprop_alloc(node, "ranges", sizeof(*range), + (void **)&range); + for (i = 0; i < nrange; i++) { + j = OFW_PCI_RANGE_CS(&range[i]); + if (sc->sc_pci_bh[j] != 0) { + device_printf(dev, "duplicate range for space %d\n", + j); + free(range, M_OFWPROP); + return (EINVAL); } + sc->sc_pci_bh[j] = OFW_PCI_RANGE_PHYS(&range[i]); + } + free(range, M_OFWPROP); + + /* + * Make sure that the expected ranges are actually present. + * The OFW_PCI_CS_MEM64 one is not currently used. + */ + if (sc->sc_pci_bh[OFW_PCI_CS_CONFIG] == 0) { + device_printf(dev, "missing CONFIG range\n"); + return (ENXIO); + } + if (sc->sc_pci_bh[OFW_PCI_CS_IO] == 0) { + device_printf(dev, "missing IO range\n"); + return (ENXIO); + } + if (sc->sc_pci_bh[OFW_PCI_CS_MEM32] == 0) { + device_printf(dev, "missing MEM32 range\n"); + return (ENXIO); + } + + /* Allocate our tags. */ + sc->sc_pci_iot = sparc64_alloc_bus_tag(NULL, PCI_IO_BUS_SPACE); + if (sc->sc_pci_iot == NULL) { + device_printf(dev, "could not allocate PCI I/O tag\n"); + return (ENXIO); + } + sc->sc_pci_cfgt = sparc64_alloc_bus_tag(NULL, PCI_CONFIG_BUS_SPACE); + if (sc->sc_pci_cfgt == NULL) { + device_printf(dev, + "could not allocate PCI configuration space tag\n"); + return (ENXIO); + } + + /* + * Get the bus range from the firmware. + */ + i = OF_getprop(node, "bus-range", (void *)prop_array, + sizeof(prop_array)); + if (i == -1) { + device_printf(dev, "could not get bus-range\n"); + return (ENXIO); + } + if (i != sizeof(prop_array)) { + device_printf(dev, "broken bus-range (%d)", i); + return (EINVAL); + } + sc->sc_pci_secbus = prop_array[0]; + sc->sc_pci_subbus = prop_array[1]; + if (bootverbose != 0) + device_printf(dev, "bus range %u to %u; PCI bus %d\n", + sc->sc_pci_secbus, sc->sc_pci_subbus, sc->sc_pci_secbus); + + ofw_bus_setup_iinfo(node, &sc->sc_pci_iinfo, sizeof(ofw_pci_intr_t)); + + return (0); +} + +uint32_t +ofw_pci_read_config_common(device_t dev, u_int regmax, u_long offset, + u_int bus, u_int slot, u_int func, u_int reg, int width) +{ + struct ofw_pci_softc *sc; + bus_space_handle_t bh; + uint32_t r, wrd; + int i; + uint16_t shrt; + uint8_t byte; + + sc = device_get_softc(dev); + if (bus < sc->sc_pci_secbus || bus > sc->sc_pci_subbus || + slot > PCI_SLOTMAX || func > PCI_FUNCMAX || reg > regmax) + return (-1); + + bh = sc->sc_pci_bh[OFW_PCI_CS_CONFIG]; + switch (width) { + case 1: + i = bus_space_peek_1(sc->sc_pci_cfgt, bh, offset, &byte); + r = byte; + break; + case 2: + i = bus_space_peek_2(sc->sc_pci_cfgt, bh, offset, &shrt); + r = shrt; + break; + case 4: + i = bus_space_peek_4(sc->sc_pci_cfgt, bh, offset, &wrd); + r = wrd; + break; + default: + panic("%s: bad width %d", __func__, width); + /* NOTREACHED */ + } + + if (i) { +#ifdef OFW_PCI_DEBUG + printf("%s: read data error reading: %d.%d.%d: 0x%x\n", + __func__, bus, slot, func, reg); +#endif + r = -1; + } + return (r); +} + +void +ofw_pci_write_config_common(device_t dev, u_int regmax, u_long offset, + u_int bus, u_int slot, u_int func, u_int reg, uint32_t val, int width) +{ + struct ofw_pci_softc *sc; + bus_space_handle_t bh; + + sc = device_get_softc(dev); + if (bus < sc->sc_pci_secbus || bus > sc->sc_pci_subbus || + slot > PCI_SLOTMAX || func > PCI_FUNCMAX || reg > regmax) + return; + + bh = sc->sc_pci_bh[OFW_PCI_CS_CONFIG]; + switch (width) { + case 1: + bus_space_write_1(sc->sc_pci_cfgt, bh, offset, val); + break; + case 2: + bus_space_write_2(sc->sc_pci_cfgt, bh, offset, val); + break; + case 4: + bus_space_write_4(sc->sc_pci_cfgt, bh, offset, val); + break; + default: + panic("%s: bad width %d", __func__, width); + /* NOTREACHED */ + } +} + +ofw_pci_intr_t +ofw_pci_route_interrupt_common(device_t bridge, device_t dev, int pin) +{ + struct ofw_pci_softc *sc; + struct ofw_pci_register reg; + ofw_pci_intr_t pintr, mintr; + + sc = device_get_softc(bridge); + pintr = pin; + if (ofw_bus_lookup_imap(ofw_bus_get_node(dev), &sc->sc_pci_iinfo, + ®, sizeof(reg), &pintr, sizeof(pintr), &mintr, sizeof(mintr), + NULL) != 0) + return (mintr); + return (PCI_INVALID_IRQ); +} + +void +ofw_pci_dmamap_sync_stst_order_common(void) +{ + static u_char buf[VIS_BLOCKSIZE] __aligned(VIS_BLOCKSIZE); + register_t reg, s; + + s = intr_disable(); + reg = rd(fprs); + wr(fprs, reg | FPRS_FEF, 0); + __asm __volatile("stda %%f0, [%0] %1" + : : "r" (buf), "n" (ASI_BLK_COMMIT_S)); + membar(Sync); + wr(fprs, reg, 0); + intr_restore(s); +} + +int +ofw_pci_read_ivar(device_t dev, device_t child __unused, int which, + uintptr_t *result) +{ + struct ofw_pci_softc *sc; + + switch (which) { + case PCIB_IVAR_DOMAIN: + *result = device_get_unit(dev); + return (0); + case PCIB_IVAR_BUS: + sc = device_get_softc(dev); + *result = sc->sc_pci_secbus; + return (0); + } + return (ENOENT); +} + +struct resource * +ofw_pci_alloc_resource(device_t bus, device_t child, int type, int *rid, + u_long start, u_long end, u_long count, u_int flags) +{ + struct ofw_pci_softc *sc; + struct resource *rv; + struct rman *rm; + + sc = device_get_softc(bus); + switch (type) { + case SYS_RES_IRQ: + /* + * XXX: Don't accept blank ranges for now, only single + * interrupts. The other case should not happen with + * the MI PCI code ... + * XXX: This may return a resource that is out of the + * range that was specified. Is this correct ...? + */ + if (start != end) + panic("%s: XXX: interrupt range", __func__); + return (bus_generic_alloc_resource(bus, child, type, rid, + start, end, count, flags)); + case SYS_RES_MEMORY: + rm = &sc->sc_pci_mem_rman; + break; + case SYS_RES_IOPORT: + rm = &sc->sc_pci_io_rman; + break; + default: + return (NULL); + } + + rv = rman_reserve_resource(rm, start, end, count, flags & ~RF_ACTIVE, + child); + if (rv == NULL) + return (NULL); + rman_set_rid(rv, *rid); + + if ((flags & RF_ACTIVE) != 0 && bus_activate_resource(child, type, + *rid, rv) != 0) { + rman_release_resource(rv); + return (NULL); } - pci_bus_map[n] = node; - return (n); + return (rv); +} + +int +ofw_pci_activate_resource(device_t bus, device_t child, int type, int rid, + struct resource *r) +{ + struct ofw_pci_softc *sc; + struct bus_space_tag *tag; + + sc = device_get_softc(bus); + switch (type) { + case SYS_RES_IRQ: + return (bus_generic_activate_resource(bus, child, type, rid, + r)); + case SYS_RES_MEMORY: + tag = sparc64_alloc_bus_tag(r, PCI_MEMORY_BUS_SPACE); + if (tag == NULL) + return (ENOMEM); + rman_set_bustag(r, tag); + rman_set_bushandle(r, sc->sc_pci_bh[OFW_PCI_CS_MEM32] + + rman_get_start(r)); + break; + case SYS_RES_IOPORT: + rman_set_bustag(r, sc->sc_pci_iot); + rman_set_bushandle(r, sc->sc_pci_bh[OFW_PCI_CS_IO] + + rman_get_start(r)); + break; + } + return (rman_activate_resource(r)); +} + +int +ofw_pci_adjust_resource(device_t bus, device_t child, int type, + struct resource *r, u_long start, u_long end) +{ + struct ofw_pci_softc *sc; + struct rman *rm; + + sc = device_get_softc(bus); + switch (type) { + case SYS_RES_IRQ: + return (bus_generic_adjust_resource(bus, child, type, r, + start, end)); + case SYS_RES_MEMORY: + rm = &sc->sc_pci_mem_rman; + break; + case SYS_RES_IOPORT: + rm = &sc->sc_pci_io_rman; + break; + default: + return (EINVAL); + } + if (rman_is_region_manager(r, rm) == 0) + return (EINVAL); + return (rman_adjust_resource(r, start, end)); +} + +bus_dma_tag_t +ofw_pci_get_dma_tag(device_t bus, device_t child __unused) +{ + struct ofw_pci_softc *sc; + + sc = device_get_softc(bus); + return (sc->sc_pci_dmat); +} + +phandle_t +ofw_pci_get_node(device_t bus, device_t child __unused) +{ + struct ofw_pci_softc *sc; + + sc = device_get_softc(bus); + /* We only have one child, the PCI bus, which needs our own node. */ + return (sc->sc_node); } Modified: head/sys/sparc64/pci/ofw_pci.h ============================================================================== --- head/sys/sparc64/pci/ofw_pci.h Sat Sep 12 21:23:24 2015 (r287725) +++ head/sys/sparc64/pci/ofw_pci.h Sat Sep 12 22:49:32 2015 (r287726) @@ -62,6 +62,8 @@ #ifndef _SPARC64_PCI_OFW_PCI_H_ #define _SPARC64_PCI_OFW_PCI_H_ +#include + #include #include "ofw_pci_if.h" @@ -73,6 +75,7 @@ typedef uint32_t ofw_pci_intr_t; #define OFW_PCI_CS_IO 0x01 #define OFW_PCI_CS_MEM32 0x02 #define OFW_PCI_CS_MEM64 0x03 +#define OFW_PCI_NUM_CS 4 /* OFW device types */ #define OFW_TYPE_PCI "pci" @@ -124,4 +127,44 @@ struct ofw_pci_ranges { /* default values */ #define OFW_PCI_LATENCY 64 +/* + * Common and generic parts of host-PCI-bridge support + */ + +struct ofw_pci_softc { + struct rman sc_pci_mem_rman; + struct rman sc_pci_io_rman; + + bus_space_handle_t sc_pci_bh[OFW_PCI_NUM_CS]; + bus_space_tag_t sc_pci_cfgt; + bus_space_tag_t sc_pci_iot; + bus_dma_tag_t sc_pci_dmat; + + struct ofw_bus_iinfo sc_pci_iinfo; + + phandle_t sc_node; + + uint8_t sc_pci_secbus; + uint8_t sc_pci_subbus; +}; + +int ofw_pci_attach_common(device_t dev, bus_dma_tag_t dmat, u_long iosize, + u_long memsize); +uint32_t ofw_pci_read_config_common(device_t dev, u_int regmax, u_long offset, + u_int bus, u_int slot, u_int func, u_int reg, int width); +void ofw_pci_write_config_common(device_t dev, u_int regmax, u_long offset, + u_int bus, u_int slot, u_int func, u_int reg, uint32_t val, int width); +ofw_pci_intr_t ofw_pci_route_interrupt_common(device_t bridge, device_t dev, + int pin); + +void ofw_pci_dmamap_sync_stst_order_common(void); + +bus_activate_resource_t ofw_pci_activate_resource; +bus_adjust_resource_t ofw_pci_adjust_resource; +bus_alloc_resource_t ofw_pci_alloc_resource; +bus_get_dma_tag_t ofw_pci_get_dma_tag; +bus_read_ivar_t ofw_pci_read_ivar; + +ofw_bus_get_node_t ofw_pci_get_node; + #endif /* ! _SPARC64_PCI_OFW_PCI_H_ */ Modified: head/sys/sparc64/pci/psycho.c ============================================================================== --- head/sys/sparc64/pci/psycho.c Sat Sep 12 21:23:24 2015 (r287725) +++ head/sys/sparc64/pci/psycho.c Sat Sep 12 22:49:32 2015 (r287726) @@ -57,7 +57,6 @@ __FBSDID("$FreeBSD$"); #include #include -#include #include *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***