svn commit: r220060 - projects/altix/sys/ia64/sgisn

Marcel Moolenaar marcel at FreeBSD.org
Sun Mar 27 19:27:57 UTC 2011


Author: marcel
Date: Sun Mar 27 19:27:57 2011
New Revision: 220060
URL: http://svn.freebsd.org/changeset/base/220060

Log:
  Add the beginnings of a driver for the SHub ASIC. There's a SHub for each
  node in the system. The SHub serves as a crossbar between the FSB,
  supporting 1 or 2 CPUs, the memory, the 2 NUMAlink network interfaces and
  the Xtalk I/O interface.
  
  Since the PCI/PCI-X host controllers connect to the SHub via the Xtalk
  interfaces, the shub driver will become the parent of the pci host
  controller driver.

Added:
  projects/altix/sys/ia64/sgisn/sgisn_shub.c

Added: projects/altix/sys/ia64/sgisn/sgisn_shub.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ projects/altix/sys/ia64/sgisn/sgisn_shub.c	Sun Mar 27 19:27:57 2011	(r220060)
@@ -0,0 +1,328 @@
+/*-
+ * Copyright (c) 2011 Marcel Moolenaar
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/pcpu.h>
+#include <sys/rman.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+#include <machine/bus.h>
+#include <machine/md_var.h>
+#include <machine/resource.h>
+#include <machine/sal.h>
+#include <machine/sgisn.h>
+
+#include <contrib/dev/acpica/include/acpi.h>
+#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;
+	device_t	sc_dev;
+	void		*sc_promaddr;
+	u_int		sc_domain;
+	u_int		sc_busnr;
+};
+
+static int sgisn_shub_attach(device_t);
+static void sgisn_shub_identify(driver_t *, device_t);
+static int sgisn_shub_probe(device_t);
+
+static int sgisn_shub_activate_resource(device_t, device_t, int, int,
+    struct resource *);
+static int sgisn_shub_read_ivar(device_t, device_t, int, uintptr_t *);
+static int sgisn_shub_write_ivar(device_t, device_t, int, uintptr_t);
+
+/*
+ * Bus interface definitions.
+ */
+static device_method_t sgisn_shub_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_identify,	sgisn_shub_identify),
+	DEVMETHOD(device_probe,		sgisn_shub_probe),
+	DEVMETHOD(device_attach,	sgisn_shub_attach),
+
+	/* Bus interface */
+        DEVMETHOD(bus_read_ivar,	sgisn_shub_read_ivar),
+        DEVMETHOD(bus_write_ivar,	sgisn_shub_write_ivar),
+	DEVMETHOD(bus_print_child,	bus_generic_print_child),
+	DEVMETHOD(bus_alloc_resource,	bus_generic_alloc_resource),
+	DEVMETHOD(bus_release_resource,	bus_generic_release_resource),
+	DEVMETHOD(bus_activate_resource, sgisn_shub_activate_resource),
+	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
+	DEVMETHOD(bus_setup_intr,	bus_generic_setup_intr),
+	DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
+
+	{ 0, 0 }
+};
+
+static devclass_t sgisn_shub_devclass;
+static char sgisn_shub_name[] = "shub";
+
+static driver_t sgisn_shub_driver = {
+	sgisn_shub_name,
+	sgisn_shub_methods,
+	sizeof(struct sgisn_shub_softc),
+};
+
+
+DRIVER_MODULE(shub, nexus, sgisn_shub_driver, sgisn_shub_devclass, 0, 0);
+
+static int
+sgisn_shub_activate_resource(device_t dev, device_t child, int type, int rid,
+    struct resource *res)
+{
+#if 0
+	struct ia64_sal_result r;
+	struct sgisn_shub_softc *sc;
+	device_t parent;
+	void *vaddr;
+	uintptr_t func, slot;
+	vm_paddr_t paddr;
+	u_long base;
+	int bar, error;
+ 
+	parent = device_get_parent(child);
+
+	error = BUS_READ_IVAR(parent, child, PCI_IVAR_SLOT, &slot);
+	if (!error)
+		error = BUS_READ_IVAR(parent, child, PCI_IVAR_FUNCTION, &func);
+	if (error)
+		return (error);
+
+	sc = device_get_softc(dev);
+
+	r = ia64_sal_entry(SAL_SGISN_IODEV_INFO, sc->sc_domain, sc->sc_busnr,
+	    (slot << 3) | func, ia64_tpa((uintptr_t)&sgisn_dev),
+	    ia64_tpa((uintptr_t)&sgisn_irq), 0, 0);
+	if (r.sal_status != 0)
+		return (ENXIO);
+
+	paddr = rman_get_start(res);
+
+	if (type == SYS_RES_IRQ) {
+		/* For now, only warn when there's a mismatch. */
+		if (paddr != sgisn_irq.irq_nr)
+			device_printf(dev, "interrupt mismatch: (actual=%u)\n",
+			    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);
+
+		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);
+
+		goto out;
+	}
+
+	bar = PCI_RID2BAR(rid);
+	if (bar < 0 || bar > PCIR_MAX_BAR_0)
+		return (EINVAL);
+	base = sgisn_dev.dev_bar[bar];
+	if (base != paddr)
+		device_printf(dev, "PCI bus address %#lx mapped to CPU "
+		    "address %#lx\n", paddr, base);
+
+	/* I/O port space is presented as memory mapped I/O. */
+	rman_set_bustag(res, IA64_BUS_SPACE_MEM);
+	vaddr = pmap_mapdev(base, rman_get_size(res));
+	rman_set_bushandle(res, (bus_space_handle_t) vaddr);
+	if (type == SYS_RES_MEMORY)
+		rman_set_virtual(res, vaddr);
+
+ out:
+	return (rman_activate_resource(res));
+#endif
+
+	return (EDOOFUS);
+}
+
+static void
+sgisn_shub_dump_sn_info(struct ia64_sal_result *r)
+{
+
+	printf("XXX: SHub type: %lu (0=SHub1, 1=SHub2)\n",
+	    r->sal_result[0] & 0xff);
+	printf("XXX: Max nodes in system: %u\n",
+	    1 << ((r->sal_result[0] >> 8) & 0xff));
+	printf("XXX: Max nodes in sharing domain: %u\n",
+	    1 << ((r->sal_result[0] >> 16) & 0xff));
+	printf("XXX: Partition ID: %lu\n", (r->sal_result[0] >> 24) & 0xff);
+	printf("XXX: Coherency ID: %lu\n", (r->sal_result[0] >> 32) & 0xff);
+	printf("XXX: Region size: %lu\n", (r->sal_result[0] >> 40) & 0xff);
+
+	printf("XXX: NasID mask: %#lx\n", r->sal_result[1] & 0xffff);
+	printf("XXX: NasID bit position: %lu\n",
+	    (r->sal_result[1] >> 16) & 0xff);
+
+}
+
+static void
+sgisn_shub_srat_parse(ACPI_SUBTABLE_HEADER *entry, void *arg)
+{
+	ACPI_SRAT_CPU_AFFINITY *cpu;
+	ACPI_SRAT_MEM_AFFINITY *mem;
+	device_t bus, dev;
+	uint32_t domain;
+
+	bus = arg;
+
+	/*
+	 * Use all possible entry types for learning about domains.
+	 * This probably is highly redundant and could possible be
+	 * wrong, but it seems more harmful to miss a domain than
+	 * anything else.
+	 */
+	domain = 0;
+	switch (entry->Type) {
+	case ACPI_SRAT_TYPE_CPU_AFFINITY:
+		cpu = (ACPI_SRAT_CPU_AFFINITY *)(void *)entry;
+		domain = cpu->ProximityDomainLo |
+		    cpu->ProximityDomainHi[0] << 8 |
+		    cpu->ProximityDomainHi[1] << 16 |
+		    cpu->ProximityDomainHi[2] << 24;
+		break;
+	case ACPI_SRAT_TYPE_MEMORY_AFFINITY:
+		mem = (ACPI_SRAT_MEM_AFFINITY *)(void *)entry;
+		domain = mem->ProximityDomain;
+		break;
+	default:
+		return;
+	}
+
+	/*
+	 * We're done if we've already seen the domain.
+	 */
+	dev = devclass_get_device(sgisn_shub_devclass, domain);
+	if (dev != NULL)
+		return;
+
+	if (bootverbose)
+		printf("%s: found now domain %u\n", sgisn_shub_name, domain);
+
+	/*
+	 * First encounter of this domain. Add a SHub device with a unit
+	 * number equal to the domain number. Order the SHub devices by
+	 * unit (and thus domain) number.
+	 */
+	dev = BUS_ADD_CHILD(bus, domain, sgisn_shub_name, domain);
+}
+
+static void
+sgisn_shub_identify(driver_t *drv, device_t bus)
+{
+	struct ia64_sal_result r;
+	ACPI_TABLE_HEADER *tbl;
+	void *ptr;
+
+	KASSERT(drv == &sgisn_shub_driver, ("%s: driver mismatch", __func__));
+
+	/*
+	 * The presence of SHub ASICs is conditional upon the platform
+	 * (SGI Altix SN). Check that first...
+	 */
+	r = ia64_sal_entry(SAL_SGISN_SN_INFO, 0, 0, 0, 0, 0, 0, 0);
+	if (r.sal_status != 0)
+		return;
+
+	if (bootverbose)
+		sgisn_shub_dump_sn_info(&r);
+
+	/*
+	 * The number of SHub ASICs is determined by the number of nodes
+	 * in the SRAT table.
+	 */
+	tbl = ptr = acpi_find_table(ACPI_SIG_SRAT);
+	if (tbl == NULL) {
+		printf("WARNING: no SRAT table found...\n");
+		return;
+	}
+
+	acpi_walk_subtables((uint8_t *)ptr + sizeof(ACPI_TABLE_SRAT),
+	    (uint8_t *)ptr + tbl->Length, sgisn_shub_srat_parse, bus);
+}
+
+static int
+sgisn_shub_probe(device_t dev)
+{
+	struct sgisn_shub_softc *sc;
+
+	sc = device_get_softc(dev);
+
+	device_set_desc(dev, "SGI SHub ASIC ");
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+sgisn_shub_attach(device_t dev)
+{
+	struct sgisn_shub_softc *sc;
+
+	sc = device_get_softc(dev);
+	sc->sc_dev = dev;
+
+	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);
+
+	return (ENOENT);
+}
+
+static int
+sgisn_shub_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
+{
+// XXX	struct sgisn_shub_softc *sc = device_get_softc(dev);
+
+	return (ENOENT);
+}


More information about the svn-src-projects mailing list