Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 29 Mar 2011 00:36:36 +0000 (UTC)
From:      Marcel Moolenaar <marcel@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r220119 - in projects/altix/sys/ia64: include sgisn
Message-ID:  <201103290036.p2T0aaGq011444@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: marcel
Date: Tue Mar 29 00:36:36 2011
New Revision: 220119
URL: http://svn.freebsd.org/changeset/base/220119

Log:
  o   Fleshed-out shub driver that creates pcib children.
  o   Modified pcib driver that attaches to shub.
  o   Slightly tweaked PROM-defined structures.

Modified:
  projects/altix/sys/ia64/include/sgisn.h
  projects/altix/sys/ia64/sgisn/sgisn_pcib.c
  projects/altix/sys/ia64/sgisn/sgisn_shub.c

Modified: projects/altix/sys/ia64/include/sgisn.h
==============================================================================
--- projects/altix/sys/ia64/include/sgisn.h	Tue Mar 29 00:33:02 2011	(r220118)
+++ projects/altix/sys/ia64/include/sgisn.h	Tue Mar 29 00:36:36 2011	(r220119)
@@ -29,6 +29,7 @@
 #define _MACHINE_SGISN_H_
 
 /* SAL functions */
+#define	SAL_SGISN_KLCONFIG_ADDR		0x02000005
 #define	SAL_SGISN_SAPIC_INFO		0x0200001d
 #define	SAL_SGISN_SN_INFO		0x0200001e
 #define	SAL_SGISN_PUTC			0x02000021
@@ -38,6 +39,8 @@
 #define	SAL_SGISN_IOHUB_INFO		0x02000055
 #define	SAL_SGISN_IOBUS_INFO		0x02000056
 #define	SAL_SGISN_IODEV_INFO		0x02000057
+#define	SAL_SGISN_FEATURE_GET_PROM	0x02000065
+#define	SAL_SGISN_FEATURE_SET_OS	0x02000066
 
 #define	SGISN_GEOID_MODULE(id)		(((id) >> 0) & 0xffffffffu)
 #define	SGISN_GEOID_TYPE(id)		(((id) >> 32) & 0xff)
@@ -61,23 +64,39 @@
 #define	SGISN_HUB_NITTES	8
 #define	SGISN_HUB_NWIDGETS	16
 
+#define	SHUB_IVAR_PCIBUS	1
+#define	SHUB_IVAR_PCISEG	2
+
+struct sgisn_fwhub;
+
 struct sgisn_widget {
 	uint32_t		wgt_hwmfg;
 	uint32_t		wgt_hwrev;
 	uint32_t		wgt_hwpn;
 	uint8_t			wgt_port;
-	char	_pad[3];
-	uint64_t		wgt_private;
-	uint64_t		wgt_provider;
+	uint8_t			_pad[3];
+	struct sgisn_fwhub	*wgt_hub;
+	uint64_t		wgt_funcs;
 	uint64_t		wgt_vertex;
 };
 
-struct sgisn_hub {
+struct sgisn_fwbus {
+	uint32_t		bus_asic;
+	uint32_t		bus_xid;
+	uint32_t		bus_busnr;
+	uint32_t		bus_segment;
+	uint64_t		bus_ioport_addr;
+	uint64_t		bus_memio_addr;
+	uint64_t		bus_base;
+	struct sgisn_widget	*bus_wgt_info;
+};
+
+struct sgisn_fwhub {
 	uint64_t		hub_geoid;
 	uint16_t		hub_nasid;
 	uint16_t		hub_peer_nasid;
-	char	_pad[4];
-	uint64_t		hub_pointer;
+	uint32_t		_pad;
+	void 			*hub_widgets;
 	uint64_t		hub_dma_itte[SGISN_HUB_NITTES];
 	struct sgisn_widget	hub_widget[SGISN_HUB_NWIDGETS];
 
@@ -88,29 +107,33 @@ struct sgisn_hub {
 	uint32_t		hub_pci_maxbus;
 };
 
-struct sgisn_irq {
-	uint64_t		irq_unused;
-	uint16_t		irq_nasid;
-	char	_pad1[2];
-	u_int			irq_slice;
-	u_int			irq_cpuid;
-	u_int			irq_no;
-	u_int			irq_pin;
-	uint64_t		irq_xtaddr;
-	u_int			irq_br_type;
-	char	_pad2[4];
-	uint64_t		irq_bridge;
-	uint64_t		irq_io_info;
-	u_int			irq_last;
-	u_int			irq_cookie;
-	u_int			irq_flags;
-	u_int			irq_refcnt;
+struct sgisn_fwirq {
+	uint64_t		_obsolete;
+	uint16_t		irq_tgt_nasid;
+	uint16_t		_pad1;
+	uint32_t		irq_tgt_slice;
+	uint32_t		irq_cpuid;
+	uint32_t		irq_nr;
+	uint32_t		irq_pin;
+	uint64_t		irq_tgt_xtaddr;
+	uint32_t		irq_br_type;
+	uint32_t		_pad2;
+	void			*irq_bridge;	/* Originating */
+	void			*irq_io_info;
+	uint32_t		irq_last;
+	uint32_t		irq_cookie;
+	uint32_t		irq_flags;
+	uint32_t		irq_refcnt;
 };
 
-struct sgisn_dev {
+struct sgisn_fwdev {
 	uint64_t		dev_bar[6];
-	uint64_t		dev_rom;
+	uint64_t		dev_romaddr;
 	uint64_t		dev_handle;
+	struct sgisn_fwbus	*dev_bus_softc;
+	struct sgisn_fwdev	*dev_parent;
+	void			*dev_os_devptr;
+	struct sgisn_fwirq	*dev_irq;
 };
 
 #endif /* !_MACHINE_SGISN_H_ */

Modified: projects/altix/sys/ia64/sgisn/sgisn_pcib.c
==============================================================================
--- projects/altix/sys/ia64/sgisn/sgisn_pcib.c	Tue Mar 29 00:33:02 2011	(r220118)
+++ projects/altix/sys/ia64/sgisn/sgisn_pcib.c	Tue Mar 29 00:36:36 2011	(r220119)
@@ -50,9 +50,8 @@ __FBSDID("$FreeBSD$");
 #include <machine/sal.h>
 #include <machine/sgisn.h>
 
-static struct sgisn_hub sgisn_hub;
-static struct sgisn_dev sgisn_dev;
-static struct sgisn_irq sgisn_irq;
+static struct sgisn_fwdev sgisn_dev;
+static struct sgisn_fwirq sgisn_irq;
 
 struct sgisn_pcib_softc {
 	device_t	sc_dev;
@@ -62,7 +61,6 @@ struct sgisn_pcib_softc {
 };
 
 static int sgisn_pcib_attach(device_t);
-static void sgisn_pcib_identify(driver_t *, device_t);
 static int sgisn_pcib_probe(device_t);
 
 static int sgisn_pcib_activate_resource(device_t, device_t, int, int,
@@ -84,7 +82,6 @@ static int sgisn_pcib_scan(struct sgisn_
  */
 static device_method_t sgisn_pcib_methods[] = {
 	/* Device interface */
-	DEVMETHOD(device_identify,	sgisn_pcib_identify),
 	DEVMETHOD(device_probe,		sgisn_pcib_probe),
 	DEVMETHOD(device_attach,	sgisn_pcib_attach),
 
@@ -116,7 +113,7 @@ static driver_t sgisn_pcib_driver = {
 
 devclass_t pcib_devclass;
 
-DRIVER_MODULE(pcib, nexus, sgisn_pcib_driver, pcib_devclass, 0, 0);
+DRIVER_MODULE(pcib, shub, sgisn_pcib_driver, pcib_devclass, 0, 0);
 
 static int
 sgisn_pcib_maxslots(device_t dev)
@@ -184,9 +181,30 @@ sgisn_pcib_activate_resource(device_t de
 
 	if (type == SYS_RES_IRQ) {
 		/* For now, only warn when there's a mismatch. */
-		if (paddr != sgisn_irq.irq_no)
+		if (paddr != sgisn_irq.irq_nr)
 			device_printf(dev, "interrupt mismatch: (actual=%u)\n",
-			    sgisn_irq.irq_no);
+			    sgisn_irq.irq_nr);
+
+	printf("XXX: %s: %u, %u, %u, %u, %u, %#lx\n", __func__,
+	    sgisn_irq.irq_tgt_nasid, sgisn_irq.irq_tgt_slice,
+	    sgisn_irq.irq_cpuid, sgisn_irq.irq_nr, sgisn_irq.irq_pin,
+	    sgisn_irq.irq_tgt_xtaddr);
+	printf("\t%u, %p, %p, %u, %#x, %#x, %u\n", sgisn_irq.irq_br_type,
+	    sgisn_irq.irq_bridge, sgisn_irq.irq_io_info, sgisn_irq.irq_last,
+	    sgisn_irq.irq_cookie, sgisn_irq.irq_flags, sgisn_irq.irq_refcnt);
+
+#if 0
+		r = ia64_sal_entry(SAL_SGISN_INTERRUPT, 1 /*alloc*/,
+		    sgisn_irq.irq_tgt_nasid,
+		    (sgisn_irq.irq_bridge >> 24) & 15
+		    ia64_tpa((uintptr_t)&sgisn_irq),
+		    paddr,
+		    sgisn_irq.irq_tgt_nasid,
+		    sgisn_irq.irq_tgt_slice);
+		if (r.status != 0)
+			return (ENXIO);
+#endif
+
 		goto out;
 	}
 
@@ -209,44 +227,19 @@ sgisn_pcib_activate_resource(device_t de
 	return (rman_activate_resource(res));
 }
 
-static void
-sgisn_pcib_identify(driver_t *drv, device_t bus)
-{
-	struct ia64_sal_result r;
-	device_t dev;
-	struct sgisn_pcib_softc *sc;
-	void *addr;
-	u_int busno, segno;
-
-	sgisn_hub.hub_pci_maxseg = 0xffffffff;
-	sgisn_hub.hub_pci_maxbus = 0xff;
-	r = ia64_sal_entry(SAL_SGISN_IOHUB_INFO, PCPU_GET(md.sgisn_nasid),
-	    ia64_tpa((uintptr_t)&sgisn_hub), 0, 0, 0, 0, 0);
-	if (r.sal_status != 0)
-		return;
-
-	for (segno = 0; segno <= sgisn_hub.hub_pci_maxseg; segno++) {
-		for (busno = 0; busno <= sgisn_hub.hub_pci_maxbus; busno++) {
-			r = ia64_sal_entry(SAL_SGISN_IOBUS_INFO, segno, busno,
-			    ia64_tpa((uintptr_t)&addr), 0, 0, 0, 0);
-
-			if (r.sal_status == 0 && addr != NULL) {
-				dev = BUS_ADD_CHILD(bus, 0, drv->name, -1);
-				if (dev == NULL)
-					continue;
-				device_set_driver(dev, drv);
-				sc = device_get_softc(dev);
-				sc->sc_promaddr = addr;
-				sc->sc_domain = segno;
-				sc->sc_busnr = busno;
-			}
-		}
-	}
-}
-
 static int
 sgisn_pcib_probe(device_t dev)
 {
+	device_t parent;
+	uintptr_t bus, seg;
+
+	parent = device_get_parent(dev);
+	if (parent == NULL)
+		return (ENXIO);
+
+	if (BUS_READ_IVAR(parent, dev, SHUB_IVAR_PCISEG, &seg) ||
+	    BUS_READ_IVAR(parent, dev, SHUB_IVAR_PCIBUS, &bus))
+		return (ENXIO);
 
 	device_set_desc(dev, "SGI PCI-X host controller");
 	return (BUS_PROBE_DEFAULT);
@@ -256,10 +249,18 @@ static int
 sgisn_pcib_attach(device_t dev)
 {
 	struct sgisn_pcib_softc *sc;
+	device_t parent;
+	uintptr_t bus, seg;
 
 	sc = device_get_softc(dev);
 	sc->sc_dev = dev;
 
+	parent = device_get_parent(dev);
+	BUS_READ_IVAR(parent, dev, SHUB_IVAR_PCIBUS, &bus);
+	sc->sc_busnr = bus;
+	BUS_READ_IVAR(parent, dev, SHUB_IVAR_PCISEG, &seg);
+	sc->sc_domain = seg;
+
 #if 0
 	sgisn_pcib_scan(sc, sc->sc_busnr, sgisn_pcib_maxslots(dev));
 #endif
@@ -301,8 +302,8 @@ sgisn_pcib_write_ivar(device_t dev, devi
 static int
 sgisn_pcib_scan(struct sgisn_pcib_softc *sc, u_int bus, u_int maxslot)
 {
-	static struct sgisn_dev dev;
-	static struct sgisn_irq irq;
+	static struct sgisn_fwdev dev;
+	static struct sgisn_fwirq irq;
 	struct ia64_sal_result r;
 	u_int devfn, func, maxfunc, slot;
 	uint8_t hdrtype;

Modified: projects/altix/sys/ia64/sgisn/sgisn_shub.c
==============================================================================
--- projects/altix/sys/ia64/sgisn/sgisn_shub.c	Tue Mar 29 00:33:02 2011	(r220118)
+++ projects/altix/sys/ia64/sgisn/sgisn_shub.c	Tue Mar 29 00:36:36 2011	(r220119)
@@ -32,6 +32,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/kernel.h>
 #include <sys/module.h>
 #include <sys/bus.h>
+#include <sys/malloc.h>
 #include <sys/pcpu.h>
 #include <sys/rman.h>
 
@@ -48,14 +49,16 @@ __FBSDID("$FreeBSD$");
 #include <contrib/dev/acpica/include/actables.h>
 #include <dev/acpica/acpivar.h>
 
-// XXX static struct sgisn_hub sgisn_hub;
-
 struct sgisn_shub_softc {
-	struct sgisn_hub	sc_prom_hub;
+	struct sgisn_fwhub *sc_fwhub;
 	device_t	sc_dev;
-	void		*sc_promaddr;
+	vm_paddr_t	sc_membase;
+	vm_size_t	sc_memsize;
 	u_int		sc_domain;
-	u_int		sc_busnr;
+	u_int		sc_hubtype;	/* SHub type (0=SHub1, 1=SHub2) */
+	u_int		sc_nasid_mask;
+	u_int		sc_nasid_shft;
+	u_int		sc_nasid;
 };
 
 static int sgisn_shub_attach(device_t);
@@ -204,7 +207,7 @@ sgisn_shub_dump_sn_info(struct ia64_sal_
 }
 
 static void
-sgisn_shub_srat_parse(ACPI_SUBTABLE_HEADER *entry, void *arg)
+sgisn_shub_identify_srat_cb(ACPI_SUBTABLE_HEADER *entry, void *arg)
 {
 	ACPI_SRAT_CPU_AFFINITY *cpu;
 	ACPI_SRAT_MEM_AFFINITY *mem;
@@ -215,7 +218,7 @@ sgisn_shub_srat_parse(ACPI_SUBTABLE_HEAD
 
 	/*
 	 * Use all possible entry types for learning about domains.
-	 * This probably is highly redundant and could possible be
+	 * This probably is highly redundant and could possibly be
 	 * wrong, but it seems more harmful to miss a domain than
 	 * anything else.
 	 */
@@ -244,7 +247,7 @@ sgisn_shub_srat_parse(ACPI_SUBTABLE_HEAD
 		return;
 
 	if (bootverbose)
-		printf("%s: found now domain %u\n", sgisn_shub_name, domain);
+		printf("%s: new domain %u\n", sgisn_shub_name, domain);
 
 	/*
 	 * First encounter of this domain. Add a SHub device with a unit
@@ -285,37 +288,175 @@ sgisn_shub_identify(driver_t *drv, devic
 	}
 
 	acpi_walk_subtables((uint8_t *)ptr + sizeof(ACPI_TABLE_SRAT),
-	    (uint8_t *)ptr + tbl->Length, sgisn_shub_srat_parse, bus);
+	    (uint8_t *)ptr + tbl->Length, sgisn_shub_identify_srat_cb, bus);
 }
 
 static int
 sgisn_shub_probe(device_t dev)
 {
+	struct ia64_sal_result r;
+	char desc[80];
+	u_int v;
+
+	/*
+	 * NOTICE: This can only be done on a CPU that's connected to the
+	 * FSB of the SHub ASIC. As such, the BSP can only validly probe
+	 * the SHub it's connected to.
+	 *
+	 * In order to probe and attach SHubs in other domains, we need to
+	 * defer to some CPU connected to that SHub.
+	 *
+	 * XXX For now, we assume that SHub types are the same across the
+	 * system, so we simply query the SHub in our domain and pretend
+	 * we queried the one corresponding to the domain this instance
+	 * refers to.
+	 */
+	r = ia64_sal_entry(SAL_SGISN_SN_INFO, 0, 0, 0, 0, 0, 0, 0);
+	if (r.sal_status != 0)
+		return (ENXIO);
+
+	v = (r.sal_result[0] & 0xff) + 1;;
+	snprintf(desc, sizeof(desc), "SGI SHub%u ASIC", v);
+	device_set_desc_copy(dev, desc);
+	return (BUS_PROBE_DEFAULT);
+}
+
+static void
+sgisn_shub_attach_srat_cb(ACPI_SUBTABLE_HEADER *entry, void *arg)
+{
+	device_t dev = arg;
+	ACPI_SRAT_MEM_AFFINITY *mem;
 	struct sgisn_shub_softc *sc;
+ 
+	if (entry->Type != ACPI_SRAT_TYPE_MEMORY_AFFINITY)
+		return;
 
 	sc = device_get_softc(dev);
 
-	device_set_desc(dev, "SGI SHub ASIC ");
-	return (BUS_PROBE_DEFAULT);
+	mem = (ACPI_SRAT_MEM_AFFINITY *)(void *)entry;
+	if (mem->ProximityDomain != sc->sc_domain)
+		return;
+	if ((mem->Flags & ACPI_SRAT_MEM_ENABLED) == 0)
+		return;
+
+	sc->sc_membase = mem->BaseAddress;
+	sc->sc_memsize = mem->Length;
 }
 
 static int
 sgisn_shub_attach(device_t dev)
 {
+	struct ia64_sal_result r;
 	struct sgisn_shub_softc *sc;
+	ACPI_TABLE_HEADER *tbl;
+	device_t child;
+	void *ptr;
+	u_long addr;
+	u_int bus, seg, wdgt;
 
 	sc = device_get_softc(dev);
 	sc->sc_dev = dev;
+	sc->sc_domain = device_get_unit(dev);
+
+	/*
+	 * Get the physical memory region that is connected to the MD I/F
+	 * of this SHub. It allows us to allocate memory that's close to
+	 * this SHub. Fail the attach if we don't have local memory, as
+	 * we really depend on it.
+	 */
+	tbl = ptr = acpi_find_table(ACPI_SIG_SRAT);
+	acpi_walk_subtables((uint8_t *)ptr + sizeof(ACPI_TABLE_SRAT),
+	    (uint8_t *)ptr + tbl->Length, sgisn_shub_attach_srat_cb, dev);
+	if (sc->sc_memsize == 0)
+		return (ENXIO);
+
+	if (bootverbose)
+		device_printf(dev, "%#lx bytes of attached memory at %#lx\n",
+		    sc->sc_memsize, sc->sc_membase);
+
+	/*
+	 * Obtain our NASID.
+	 */
+	r = ia64_sal_entry(SAL_SGISN_SN_INFO, 0, 0, 0, 0, 0, 0, 0);
+	if (r.sal_status != 0)
+		return (ENXIO);
+
+	sc->sc_hubtype = r.sal_result[0] & 0xff;
+	sc->sc_nasid_mask = r.sal_result[1] & 0xffff;
+	sc->sc_nasid_shft = (r.sal_result[1] >> 16) & 0xff;
+	sc->sc_nasid = (sc->sc_membase >> sc->sc_nasid_shft) &
+	    sc->sc_nasid_mask;
+
+	if (bootverbose)
+		device_printf(dev, "NASID=%#x\n", sc->sc_nasid);
+
+	/*
+	 * Allocate contiguous memory, local to the SHub, for collecting
+	 * SHub information from the PROM and for discovering the PCI
+	 * host controllers connected to the SHub.
+	 */
+	sc->sc_fwhub = contigmalloc(sizeof(struct sgisn_fwhub), M_DEVBUF,
+	    M_ZERO, sc->sc_membase, sc->sc_membase + sc->sc_memsize, 16, 0);
+
+	sc->sc_fwhub->hub_pci_maxseg = 0xffffffff;
+	sc->sc_fwhub->hub_pci_maxbus = 0xff;
+	r = ia64_sal_entry(SAL_SGISN_IOHUB_INFO, sc->sc_nasid,
+	    ia64_tpa((uintptr_t)sc->sc_fwhub), 0, 0, 0, 0, 0);
+	if (r.sal_status != 0) {
+		contigfree(sc->sc_fwhub, sizeof(struct sgisn_fwhub), M_DEVBUF);
+		return (ENXIO);
+	}
+
+	for (wdgt = 0; wdgt < SGISN_HUB_NWIDGETS; wdgt++)
+		sc->sc_fwhub->hub_widget[wdgt].wgt_hub = sc->sc_fwhub;
+
+	r = ia64_sal_entry(SAL_SGISN_KLCONFIG_ADDR, sc->sc_nasid,
+	    0, 0, 0, 0, 0, 0);
+	device_printf(dev, "KLCONFIG: status=%#lx, addr=%#lx\n",
+	    r.sal_status, r.sal_result[0]);
+
+	/*
+	 * XXX Hack to avoid having the same PCI busses as children of any
+	 * SHub we have. The problem is that we can't pass the nasid to the
+	 * the SAL function. So either we get all the busses, irrespective
+	 * of the node in which they live or we always get the busses local
+	 * to the CPU. I can't tell the difference, because I don't have
+	 * busses on the other brick right now.
+	 * In any case: we don't have a good way yet to figure out if the
+	 * bus connects to the SHub in question.
+         */
+	if (sc->sc_nasid != 0)
+		return (0);
+
+	for (seg = 0; seg <= sc->sc_fwhub->hub_pci_maxseg; seg++) {
+		for (bus = 0; bus <= sc->sc_fwhub->hub_pci_maxbus; bus++) {
+			r = ia64_sal_entry(SAL_SGISN_IOBUS_INFO, seg, bus,
+			    ia64_tpa((uintptr_t)&addr), 0, 0, 0, 0);
+			if (r.sal_status == 0 && addr != 0) {
+				child = device_add_child(dev, "pcib", -1);
+				device_set_ivars(child, (void *)(uintptr_t)
+				  ((seg << 8) | (bus & 0xff)));
+			}
+		}
+	}
 
-	device_add_child(dev, "pci", -1);
 	return (bus_generic_attach(dev));
 }
 
 static int
 sgisn_shub_read_ivar(device_t dev, device_t child, int which, uintptr_t *res)
 {
-// XXX	struct sgisn_shub_softc *sc = device_get_softc(dev);
+	uintptr_t ivars;
 
+	ivars = (uintptr_t)device_get_ivars(child);
+	switch (which) {
+	case SHUB_IVAR_PCIBUS:
+		*res = ivars & 0xff;
+		return (0);
+	case SHUB_IVAR_PCISEG:
+		*res = ivars >> 8;
+		return (0);
+	}
 	return (ENOENT);
 }
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201103290036.p2T0aaGq011444>