svn commit: r287726 - in head/sys: conf sparc64/pci

Marius Strobl marius at FreeBSD.org
Sat Sep 12 22:49:35 UTC 2015


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 <sys/timetc.h>
 
 #include <dev/ofw/ofw_bus.h>
-#include <dev/ofw/ofw_pci.h>
 #include <dev/ofw/openfirm.h>
 
 #include <vm/vm.h>
@@ -68,7 +67,6 @@ __FBSDID("$FreeBSD$");
 #include <machine/bus.h>
 #include <machine/bus_common.h>
 #include <machine/bus_private.h>
-#include <machine/fsr.h>
 #include <machine/iommureg.h>
 #include <machine/iommuvar.h>
 #include <machine/pmap.h>
@@ -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,
-	    &reg, 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 <tmm at FreeBSD.org>
+ * Copyright (c) 2005 - 2015 by Marius Strobl <marius at FreeBSD.org>
  * 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 <sys/param.h>
-#include <sys/kernel.h>
 #include <sys/systm.h>
 #include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/rman.h>
 
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_pci.h>
 #include <dev/ofw/openfirm.h>
 
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+
+#include <machine/asi.h>
 #include <machine/bus.h>
+#include <machine/bus_private.h>
+#include <machine/cpufunc.h>
+#include <machine/fsr.h>
+#include <machine/resource.h>
 
 #include <sparc64/pci/ofw_pci.h>
 
-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,
+	    &reg, 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 <sys/rman.h>
+
 #include <dev/ofw/ofw_bus_subr.h>
 
 #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 <sys/sysctl.h>
 
 #include <dev/ofw/ofw_bus.h>
-#include <dev/ofw/ofw_pci.h>
 #include <dev/ofw/openfirm.h>

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-head mailing list