svn commit: r207422 - in projects/ppc64/sys: conf dev/ofw dev/pci powerpc/aim powerpc/booke powerpc/include powerpc/ofw powerpc/powermac powerpc/powerpc sparc64/isa sparc64/pci

Nathan Whitehorn nwhitehorn at FreeBSD.org
Fri Apr 30 05:44:54 UTC 2010


Author: nwhitehorn
Date: Fri Apr 30 05:44:54 2010
New Revision: 207422
URL: http://svn.freebsd.org/changeset/base/207422

Log:
  Mega-patch to support last-generation PCI-Express-based PowerMacs. This
  accomplishes several things, and, after appropriate review, will be split
  into several corresponding patches before being committed to HEAD.
  
  - Add multiple cascaded PIC support. This is required to support devices
  attached to the U3 PIC on previous Powermac G5s, and should simplify
  ISA IRQ attachment on PowerPC systems with ISA buses (untested). This
  requires changes in the use of the OFW interrupt map lookup code, and
  so also affects sparc64.
  
  - Connect the I2C bus and OpenPIC in the U3/U4 northbridge. This portion
  of the patch was contributed by Andreas Tobler.
  
  - Split the Uninorth support into two files: one for Uninorth's PCI bits
  and one for the Uninorth system controller bits. Most of this work
  is also due to Andreas Tobler.
  
  - Rewrite cpcht(4) completely in order to expose directly the underlying
  HT bridge and many PCI bridges it has internally. This allows direct
  access to the IO-APIC in the midbridge.
  
  - Coordinate the U4 PIC's interrupt setup with the remote IO-APIC in
  the HT2000 south bridge.
  
  Current status on PowerMac 11,2 is that it will boot multiuser SMP over the
  network. cpufreq(4) is a bit dodgy, and USB, SATA, and SMU are
  non-functional. It is possible that the USB and SATA problems are artifacts
  of the cpcht rewrite and so the brokenness may have propagated to all
  other G5 systems. Users of this branch should upgrade with caution.
  
  Thanks to Andreas Tobler and Justin Hibbits for code and experimentation.

Added:
  projects/ppc64/sys/powerpc/powermac/uninorthpci.c
Deleted:
  projects/ppc64/sys/powerpc/powermac/cpchtvar.h
Modified:
  projects/ppc64/sys/conf/files.powerpc
  projects/ppc64/sys/conf/files.powerpc64
  projects/ppc64/sys/dev/ofw/ofw_bus_subr.c
  projects/ppc64/sys/dev/ofw/ofw_bus_subr.h
  projects/ppc64/sys/dev/pci/pci.c
  projects/ppc64/sys/powerpc/aim/interrupt.c
  projects/ppc64/sys/powerpc/booke/interrupt.c
  projects/ppc64/sys/powerpc/include/bus.h
  projects/ppc64/sys/powerpc/include/intr_machdep.h
  projects/ppc64/sys/powerpc/include/openpicvar.h
  projects/ppc64/sys/powerpc/ofw/ofw_pcib_pci.c
  projects/ppc64/sys/powerpc/ofw/ofw_pcibus.c
  projects/ppc64/sys/powerpc/powermac/cpcht.c
  projects/ppc64/sys/powerpc/powermac/grackle.c
  projects/ppc64/sys/powerpc/powermac/hrowpic.c
  projects/ppc64/sys/powerpc/powermac/kiic.c
  projects/ppc64/sys/powerpc/powermac/macgpio.c
  projects/ppc64/sys/powerpc/powermac/macio.c
  projects/ppc64/sys/powerpc/powermac/openpic_macio.c
  projects/ppc64/sys/powerpc/powermac/uninorth.c
  projects/ppc64/sys/powerpc/powermac/uninorthvar.h
  projects/ppc64/sys/powerpc/powerpc/intr_machdep.c
  projects/ppc64/sys/powerpc/powerpc/mp_machdep.c
  projects/ppc64/sys/powerpc/powerpc/openpic.c
  projects/ppc64/sys/powerpc/powerpc/pic_if.m
  projects/ppc64/sys/sparc64/isa/ofw_isa.c
  projects/ppc64/sys/sparc64/pci/fire.c
  projects/ppc64/sys/sparc64/pci/ofw_pcib_subr.c
  projects/ppc64/sys/sparc64/pci/psycho.c
  projects/ppc64/sys/sparc64/pci/schizo.c

Modified: projects/ppc64/sys/conf/files.powerpc
==============================================================================
--- projects/ppc64/sys/conf/files.powerpc	Fri Apr 30 04:21:22 2010	(r207421)
+++ projects/ppc64/sys/conf/files.powerpc	Fri Apr 30 05:44:54 2010	(r207422)
@@ -139,7 +139,8 @@ powerpc/powermac/openpic_macio.c optiona
 powerpc/powermac/pswitch.c	optional	powermac pswitch
 powerpc/powermac/pmu.c		optional	powermac pmu 
 powerpc/powermac/smu.c		optional	powermac smu 
-powerpc/powermac/uninorth.c	optional	powermac pci
+powerpc/powermac/uninorth.c	optional	powermac
+powerpc/powermac/uninorthpci.c	optional	powermac pci
 powerpc/powermac/vcoregpio.c	optional	powermac 
 powerpc/powerpc/altivec.c	optional	aim
 powerpc/powerpc/atomic.S	standard

Modified: projects/ppc64/sys/conf/files.powerpc64
==============================================================================
--- projects/ppc64/sys/conf/files.powerpc64	Fri Apr 30 04:21:22 2010	(r207421)
+++ projects/ppc64/sys/conf/files.powerpc64	Fri Apr 30 05:44:54 2010	(r207422)
@@ -93,7 +93,8 @@ powerpc/powermac/openpic_macio.c optiona
 powerpc/powermac/pswitch.c	optional	powermac pswitch
 powerpc/powermac/pmu.c		optional	powermac pmu 
 powerpc/powermac/smu.c		optional	powermac smu 
-powerpc/powermac/uninorth.c	optional	powermac pci
+powerpc/powermac/uninorth.c	optional	powermac
+powerpc/powermac/uninorthpci.c	optional	powermac pci
 powerpc/powermac/vcoregpio.c	optional	powermac 
 powerpc/powerpc/altivec.c	optional	aim
 powerpc/powerpc/atomic.S	standard

Modified: projects/ppc64/sys/dev/ofw/ofw_bus_subr.c
==============================================================================
--- projects/ppc64/sys/dev/ofw/ofw_bus_subr.c	Fri Apr 30 04:21:22 2010	(r207421)
+++ projects/ppc64/sys/dev/ofw/ofw_bus_subr.c	Fri Apr 30 05:44:54 2010	(r207422)
@@ -174,7 +174,7 @@ ofw_bus_setup_iinfo(phandle_t node, stru
 int
 ofw_bus_lookup_imap(phandle_t node, struct ofw_bus_iinfo *ii, void *reg,
     int regsz, void *pintr, int pintrsz, void *mintr, int mintrsz,
-    void *maskbuf)
+    phandle_t *iparent, void *maskbuf)
 {
 	int rv;
 
@@ -188,7 +188,7 @@ ofw_bus_lookup_imap(phandle_t node, stru
 		panic("ofw_bus_lookup_imap: could not get reg property");
 	return (ofw_bus_search_intrmap(pintr, pintrsz, reg, ii->opi_addrc,
 	    ii->opi_imap, ii->opi_imapsz, ii->opi_imapmsk, maskbuf, mintr,
-	    mintrsz));
+	    mintrsz, iparent));
 }
 
 /*
@@ -211,7 +211,7 @@ ofw_bus_lookup_imap(phandle_t node, stru
 int
 ofw_bus_search_intrmap(void *intr, int intrsz, void *regs, int physsz,
     void *imap, int imapsz, void *imapmsk, void *maskbuf, void *result,
-    int rintrsz)
+    int rintrsz, phandle_t *iparent)
 {
 	phandle_t parent;
 	uint8_t *ref = maskbuf;
@@ -255,6 +255,9 @@ ofw_bus_search_intrmap(void *intr, int i
 		if (bcmp(ref, mptr, physsz + intrsz) == 0) {
 			bcopy(mptr + physsz + intrsz + sizeof(parent),
 			    result, rintrsz);
+
+			if (iparent != NULL)
+				*iparent = parent;
 			return (1);
 		}
 		mptr += tsz;

Modified: projects/ppc64/sys/dev/ofw/ofw_bus_subr.h
==============================================================================
--- projects/ppc64/sys/dev/ofw/ofw_bus_subr.h	Fri Apr 30 04:21:22 2010	(r207421)
+++ projects/ppc64/sys/dev/ofw/ofw_bus_subr.h	Fri Apr 30 05:44:54 2010	(r207422)
@@ -63,8 +63,11 @@ bus_child_pnpinfo_str_t	ofw_bus_gen_chil
 /* Routines for processing firmware interrupt maps */
 void	ofw_bus_setup_iinfo(phandle_t, struct ofw_bus_iinfo *, int);
 int	ofw_bus_lookup_imap(phandle_t, struct ofw_bus_iinfo *, void *, int,
-	    void *, int, void *, int, void *);
+	    void *, int, void *, int, phandle_t *, void *);
 int	ofw_bus_search_intrmap(void *, int, void *, int, void *, int, void *,
-	    void *, void *, int);
+	    void *, void *, int, phandle_t *);
+
+/* Helper to get node's interrupt parent */
+void	ofw_bus_find_iparent(phandle_t);
 
 #endif /* !_DEV_OFW_OFW_BUS_SUBR_H_ */

Modified: projects/ppc64/sys/dev/pci/pci.c
==============================================================================
--- projects/ppc64/sys/dev/pci/pci.c	Fri Apr 30 04:21:22 2010	(r207421)
+++ projects/ppc64/sys/dev/pci/pci.c	Fri Apr 30 05:44:54 2010	(r207422)
@@ -53,7 +53,7 @@ __FBSDID("$FreeBSD$");
 #include <machine/resource.h>
 #include <machine/stdarg.h>
 
-#if defined(__i386__) || defined(__amd64__)
+#if defined(__i386__) || defined(__amd64__) || defined(__powerpc__)
 #include <machine/intr_machdep.h>
 #endif
 
@@ -559,7 +559,7 @@ pci_read_extcap(device_t pcib, pcicfgreg
 {
 #define	REG(n, w)	PCIB_READ_CONFIG(pcib, cfg->bus, cfg->slot, cfg->func, n, w)
 #define	WREG(n, v, w)	PCIB_WRITE_CONFIG(pcib, cfg->bus, cfg->slot, cfg->func, n, v, w)
-#if defined(__i386__) || defined(__amd64__)
+#if defined(__i386__) || defined(__amd64__) || defined(__powerpc__)
 	uint64_t addr;
 #endif
 	uint32_t val;
@@ -603,7 +603,7 @@ pci_read_extcap(device_t pcib, pcicfgreg
 					cfg->pp.pp_data = ptr + PCIR_POWER_DATA;
 			}
 			break;
-#if defined(__i386__) || defined(__amd64__)
+#if defined(__i386__) || defined(__amd64__) || defined(__powerpc__)
 		case PCIY_HT:		/* HyperTransport */
 			/* Determine HT-specific capability type. */
 			val = REG(ptr + PCIR_HT_COMMAND, 2);

Modified: projects/ppc64/sys/powerpc/aim/interrupt.c
==============================================================================
--- projects/ppc64/sys/powerpc/aim/interrupt.c	Fri Apr 30 04:21:22 2010	(r207421)
+++ projects/ppc64/sys/powerpc/aim/interrupt.c	Fri Apr 30 05:44:54 2010	(r207422)
@@ -81,7 +81,7 @@ powerpc_interrupt(struct trapframe *fram
 	switch (framep->exc) {
 	case EXC_EXI:
 		critical_enter();
-		PIC_DISPATCH(pic, framep);
+		PIC_DISPATCH(root_pic, framep);
 		critical_exit();
 		break;
 

Modified: projects/ppc64/sys/powerpc/booke/interrupt.c
==============================================================================
--- projects/ppc64/sys/powerpc/booke/interrupt.c	Fri Apr 30 04:21:22 2010	(r207421)
+++ projects/ppc64/sys/powerpc/booke/interrupt.c	Fri Apr 30 05:44:54 2010	(r207422)
@@ -134,7 +134,7 @@ powerpc_extr_interrupt(struct trapframe 
 {
 
 	critical_enter();
-	PIC_DISPATCH(pic, framep);
+	PIC_DISPATCH(root_pic, framep);
 	critical_exit();
 	framep->srr1 &= ~PSL_WE;
 }

Modified: projects/ppc64/sys/powerpc/include/bus.h
==============================================================================
--- projects/ppc64/sys/powerpc/include/bus.h	Fri Apr 30 04:21:22 2010	(r207421)
+++ projects/ppc64/sys/powerpc/include/bus.h	Fri Apr 30 05:44:54 2010	(r207422)
@@ -77,18 +77,24 @@
 
 #define BUS_SPACE_ALIGNED_POINTER(p, t) ALIGNED_POINTER(p, t)
 
-#define BUS_SPACE_MAXADDR_24BIT	0xFFFFFF
-#define BUS_SPACE_MAXADDR_32BIT 0xFFFFFFFF
-#define BUS_SPACE_MAXADDR 	0xFFFFFFFF
-#define BUS_SPACE_MAXSIZE_24BIT	0xFFFFFF
-#define BUS_SPACE_MAXSIZE_32BIT	0xFFFFFFFF
-#define BUS_SPACE_MAXSIZE 	0xFFFFFFFF
+#define BUS_SPACE_MAXADDR_24BIT	0xFFFFFFUL
+#define BUS_SPACE_MAXADDR_32BIT 0xFFFFFFFFUL
+#define BUS_SPACE_MAXSIZE_24BIT	0xFFFFFFUL
+#define BUS_SPACE_MAXSIZE_32BIT	0xFFFFFFFFUL
+
+#ifdef __powerpc64__
+#define BUS_SPACE_MAXADDR 	0xFFFFFFFFFFFFFFFFUL
+#define BUS_SPACE_MAXSIZE 	0xFFFFFFFFFFFFFFFFUL
+#else
+#define BUS_SPACE_MAXADDR 	0xFFFFFFFFUL
+#define BUS_SPACE_MAXSIZE 	0xFFFFFFFFUL
+#endif
 
 #define	BUS_SPACE_MAP_CACHEABLE		0x01
 #define	BUS_SPACE_MAP_LINEAR		0x02
 #define	BUS_SPACE_MAP_PREFETCHABLE     	0x04
 
-#define	BUS_SPACE_UNRESTRICTED	(~0)
+#define	BUS_SPACE_UNRESTRICTED	(~0UL)
 
 #define	BUS_SPACE_BARRIER_READ	0x01
 #define	BUS_SPACE_BARRIER_WRITE	0x02

Modified: projects/ppc64/sys/powerpc/include/intr_machdep.h
==============================================================================
--- projects/ppc64/sys/powerpc/include/intr_machdep.h	Fri Apr 30 04:21:22 2010	(r207421)
+++ projects/ppc64/sys/powerpc/include/intr_machdep.h	Fri Apr 30 05:44:54 2010	(r207422)
@@ -29,21 +29,32 @@
 #define	_MACHINE_INTR_MACHDEP_H_
 
 #define	INTR_VECTORS	256
+#define	MAX_PICS	5
 
-extern device_t pic;
-extern device_t pic8259;
+#define	IGN_SHIFT	8
+#define	INTR_INTLINE(irq) (irq & ((1 << IGN_SHIFT) - 1))
+#define	INTR_IGN(irq)	(irq >> IGN_SHIFT)
+
+#define	INTR_VEC(pic_id, irq) ((powerpc_ign_lookup(pic_id) << IGN_SHIFT) | irq)
+
+/*
+ * Default base address for MSI messages on PowerPC
+ */
+#define	MSI_INTEL_ADDR_BASE		0xfee00000
+
+extern device_t root_pic;
 
 struct trapframe;
 
 driver_filter_t powerpc_ipi_handler;
 
 void	powerpc_register_pic(device_t, u_int);
-void	powerpc_register_8259(device_t);
+int	powerpc_ign_lookup(uint32_t pic_id);
 
 void	powerpc_dispatch_intr(u_int, struct trapframe *);
 int	powerpc_enable_intr(void);
-int	powerpc_setup_intr(const char *, u_int, driver_filter_t,
-    driver_intr_t, void *, enum intr_type, void **);
+int	powerpc_setup_intr(const char *, u_int, driver_filter_t, driver_intr_t,
+	    void *, enum intr_type, void **);
 int	powerpc_teardown_intr(void *);
 int	powerpc_config_intr(int, enum intr_trigger, enum intr_polarity);
 

Modified: projects/ppc64/sys/powerpc/include/openpicvar.h
==============================================================================
--- projects/ppc64/sys/powerpc/include/openpicvar.h	Fri Apr 30 04:21:22 2010	(r207421)
+++ projects/ppc64/sys/powerpc/include/openpicvar.h	Fri Apr 30 05:44:54 2010	(r207422)
@@ -35,10 +35,13 @@
 struct openpic_softc {
 	device_t	sc_dev;
 	struct resource	*sc_memr;
+	struct resource	*sc_intr;
 	bus_space_tag_t sc_bt;
 	bus_space_handle_t sc_bh;
 	char		*sc_version;
 	int		sc_rid;
+	int		sc_irq;
+	void		*sc_icookie;
 	u_int		sc_ncpu;
 	u_int		sc_nirq;
 	int		sc_psim;

Modified: projects/ppc64/sys/powerpc/ofw/ofw_pcib_pci.c
==============================================================================
--- projects/ppc64/sys/powerpc/ofw/ofw_pcib_pci.c	Fri Apr 30 04:21:22 2010	(r207421)
+++ projects/ppc64/sys/powerpc/ofw/ofw_pcib_pci.c	Fri Apr 30 05:44:54 2010	(r207422)
@@ -42,6 +42,8 @@
 #include <dev/pci/pcireg.h>
 #include <dev/pci/pcib_private.h>
 
+#include <machine/intr_machdep.h>
+
 #include "pcib_if.h"
 
 static int	ofw_pcib_pci_probe(device_t bus);
@@ -149,6 +151,7 @@ ofw_pcib_pci_route_interrupt(device_t br
 	struct ofw_bus_iinfo *ii;
 	struct ofw_pci_register reg;
 	cell_t pintr, mintr;
+	phandle_t iparent;
 	uint8_t maskbuf[sizeof(reg) + sizeof(pintr)];
 
 	sc = device_get_softc(bridge);
@@ -157,13 +160,13 @@ ofw_pcib_pci_route_interrupt(device_t br
 		pintr = intpin;
 		if (ofw_bus_lookup_imap(ofw_bus_get_node(dev), ii, &reg,
 		    sizeof(reg), &pintr, sizeof(pintr), &mintr, sizeof(mintr),
-		    maskbuf)) {
+		    &iparent, maskbuf)) {
 			/*
 			 * If we've found a mapping, return it and don't map
 			 * it again on higher levels - that causes problems
 			 * in some cases, and never seems to be required.
 			 */
-			return (mintr);
+			return (INTR_VEC(iparent, mintr));
 		}
 	} else if (intpin >= 1 && intpin <= 4) {
 		/*

Modified: projects/ppc64/sys/powerpc/ofw/ofw_pcibus.c
==============================================================================
--- projects/ppc64/sys/powerpc/ofw/ofw_pcibus.c	Fri Apr 30 04:21:22 2010	(r207421)
+++ projects/ppc64/sys/powerpc/ofw/ofw_pcibus.c	Fri Apr 30 05:44:54 2010	(r207422)
@@ -43,6 +43,7 @@ __FBSDID("$FreeBSD$");
 #include <dev/ofw/openfirm.h>
 
 #include <machine/bus.h>
+#include <machine/intr_machdep.h>
 #include <machine/resource.h>
 
 #include <dev/pci/pcireg.h>
@@ -198,10 +199,15 @@ ofw_pcibus_enum_devtree(device_t dev, u_
 		 * resource list.
                  */
                 if (dinfo->opd_dinfo.cfg.intpin == 0) {
+			phandle_t iparent;
                         ofw_pci_intr_t intr;
 
 			if (OF_getprop(child, "interrupts", &intr, 
 			    sizeof(intr)) > 0) {
+				if (OF_getprop(child, "interrupt-parent",
+				    &iparent, sizeof(iparent)) > 0)
+					intr = INTR_VEC(iparent, intr);
+
                                 resource_list_add(&dinfo->opd_dinfo.resources,
                                     SYS_RES_IRQ, 0, intr, intr, 1);
 			}
@@ -276,7 +282,7 @@ static int
 ofw_pcibus_assign_interrupt(device_t dev, device_t child)
 {
 	ofw_pci_intr_t intr;
-	phandle_t node;
+	phandle_t node, iparent;
 	int isz;
 
 	node = ofw_bus_get_node(child);
@@ -286,8 +292,8 @@ ofw_pcibus_assign_interrupt(device_t dev
 	
 		/*
 		 * XXX: Right now we don't have anything sensible to do here,
-		 * since the ofw_imap stuff relies on nodes have a reg
-		 * property. There exists ways around this, so the ePAPR
+		 * since the ofw_imap stuff relies on nodes having a reg
+		 * property. There exist ways around this, so the ePAPR
 		 * spec will need to be studied.
 		 */
 
@@ -301,18 +307,30 @@ ofw_pcibus_assign_interrupt(device_t dev
 	}
 	
 	/*
+	 * Try to determine the node's interrupt parent so we know which
+	 * PIC to use.
+	 */
+
+	if (OF_getprop(node, "interrupt-parent", &iparent, sizeof(iparent)) <
+	    sizeof(iparent))
+		iparent = -1;
+	
+	/*
 	 * Any AAPL,interrupts property gets priority and is
 	 * fully specified (i.e. does not need routing)
 	 */
 
 	isz = OF_getprop(node, "AAPL,interrupts", &intr, sizeof(intr));
 	if (isz == sizeof(intr)) {
-		return (intr);
+		return ((iparent == -1) ? intr : INTR_VEC(iparent, intr));
 	}
 
 	isz = OF_getprop(node, "interrupts", &intr, sizeof(intr));
-	if (isz != sizeof(intr)) {
-		/* No property; our best guess is the intpin. */
+	if (isz == sizeof(intr)) {
+		if (iparent != -1)
+			intr = INTR_VEC(iparent, intr);
+	} else {
+		/* No property: our best guess is the intpin. */
 		intr = pci_get_intpin(child);
 	}
 	

Modified: projects/ppc64/sys/powerpc/powermac/cpcht.c
==============================================================================
--- projects/ppc64/sys/powerpc/powermac/cpcht.c	Fri Apr 30 04:21:22 2010	(r207421)
+++ projects/ppc64/sys/powerpc/powermac/cpcht.c	Fri Apr 30 05:44:54 2010	(r207422)
@@ -1,5 +1,5 @@
 /*-
- * Copyright (C) 2008 Nathan Whitehorn
+ * Copyright (C) 2008-2010 Nathan Whitehorn
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -39,7 +39,9 @@
 #include <dev/pci/pcireg.h>
 
 #include <machine/bus.h>
+#include <machine/intr_machdep.h>
 #include <machine/md_var.h>
+#include <machine/openpicvar.h>
 #include <machine/pio.h>
 #include <machine/resource.h>
 
@@ -47,396 +49,301 @@
 
 #include <dev/ofw/ofw_bus.h>
 #include <dev/ofw/ofw_bus_subr.h>
-#include <powerpc/powermac/cpchtvar.h>
 
 #include <vm/vm.h>
 #include <vm/pmap.h>
 
 #include "pcib_if.h"
-
-#include "opt_isa.h"
-
-#ifdef DEV_ISA
-#include <isa/isavar.h>
-#endif
-
-static MALLOC_DEFINE(M_CPCHT, "cpcht", "CPC HT device information");
+#include "pic_if.h"
 
 /*
- * HT Driver methods.
+ * IBM CPC9X5 Hypertransport Device interface.
  */
 static int		cpcht_probe(device_t);
 static int		cpcht_attach(device_t);
-static ofw_bus_get_devinfo_t cpcht_get_devinfo;
-
 
-static device_method_t	cpcht_methods[] = {
-	/* Device interface */
-	DEVMETHOD(device_probe,		cpcht_probe),
-	DEVMETHOD(device_attach,	cpcht_attach),
-
-	/* Bus interface */
-	DEVMETHOD(bus_print_child,	bus_generic_print_child),
-	DEVMETHOD(bus_read_ivar,	bus_generic_read_ivar),
-	DEVMETHOD(bus_setup_intr,	bus_generic_setup_intr),
-	DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
-	DEVMETHOD(bus_alloc_resource,	bus_generic_alloc_resource),
-	DEVMETHOD(bus_release_resource,	bus_generic_release_resource),
-	DEVMETHOD(bus_activate_resource,bus_generic_activate_resource),
-
-	/* ofw_bus interface */
-	DEVMETHOD(ofw_bus_get_devinfo,  cpcht_get_devinfo),
-	DEVMETHOD(ofw_bus_get_compat,   ofw_bus_gen_get_compat),
-	DEVMETHOD(ofw_bus_get_model,    ofw_bus_gen_get_model),
-	DEVMETHOD(ofw_bus_get_name,     ofw_bus_gen_get_name),
-	DEVMETHOD(ofw_bus_get_node,     ofw_bus_gen_get_node),
-	DEVMETHOD(ofw_bus_get_type,     ofw_bus_gen_get_type),
-
-	{ 0, 0 }
-};
-
-static driver_t	cpcht_driver = {
-	"cpcht",
-	cpcht_methods,
-	0
-};
-
-static devclass_t	cpcht_devclass;
-
-DRIVER_MODULE(cpcht, nexus, cpcht_driver, cpcht_devclass, 0, 0);
-
-static int 
-cpcht_probe(device_t dev) 
-{
-	const char	*type, *compatible;
-
-	type = ofw_bus_get_type(dev);
-	compatible = ofw_bus_get_compat(dev);
-
-	if (type == NULL || compatible == NULL)
-		return (ENXIO);
-
-	if (strcmp(type, "ht") != 0)
-		return (ENXIO);
-
-	if (strcmp(compatible, "u3-ht") == 0) {
-		device_set_desc(dev, "IBM CPC925 HyperTransport Tunnel");
-		return (0);
-	} else if (strcmp(compatible,"u4-ht") == 0) {
-		device_set_desc(dev, "IBM CPC945 HyperTransport Tunnel");
-		return (0);
-	}
-
-	return (ENXIO);
-}
-
-static int 
-cpcht_attach(device_t dev) 
-{
-	phandle_t root, child;
-	device_t cdev;
-	struct ofw_bus_devinfo *dinfo;
-	u_int32_t reg[6];
-
-	root = ofw_bus_get_node(dev);
-
-	if (OF_getprop(root, "reg", reg, sizeof(reg)) < 8)
-		return (ENXIO);
-
-	for (child = OF_child(root); child != 0; child = OF_peer(child)) {
-		dinfo = malloc(sizeof(*dinfo), M_CPCHT, M_WAITOK | M_ZERO);
-
-                if (ofw_bus_gen_setup_devinfo(dinfo, child) != 0) {
-                        free(dinfo, M_CPCHT);
-                        continue;
-                }
-                cdev = device_add_child(dev, NULL, -1);
-                if (cdev == NULL) {
-                        device_printf(dev, "<%s>: device_add_child failed\n",
-                            dinfo->obd_name);
-                        ofw_bus_gen_destroy_devinfo(dinfo);
-                        free(dinfo, M_CPCHT);
-                        continue;
-                }
-		device_set_ivars(cdev, dinfo);
-	}
-
-	return (bus_generic_attach(dev));
-}
-
-static const struct ofw_bus_devinfo *
-cpcht_get_devinfo(device_t dev, device_t child) 
-{
-	return (device_get_ivars(child));	
-}
-
-#ifdef DEV_ISA
-
-/*
- * CPC ISA Device interface.
- */
-static int		cpcisa_probe(device_t);
-
-/*
- * Driver methods.
- */
-static device_method_t	cpcisa_methods[] = {
-	/* Device interface */
-	DEVMETHOD(device_probe,		cpcisa_probe),
-	DEVMETHOD(device_attach,	isab_attach),
-
-	/* Bus interface */
-	DEVMETHOD(bus_print_child,	bus_generic_print_child),
-	DEVMETHOD(bus_read_ivar,	bus_generic_read_ivar),
-	DEVMETHOD(bus_setup_intr,	bus_generic_setup_intr),
-	DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
-	DEVMETHOD(bus_alloc_resource,	bus_generic_alloc_resource),
-	DEVMETHOD(bus_release_resource,	bus_generic_release_resource),
-	DEVMETHOD(bus_activate_resource,bus_generic_activate_resource),
-
-	{0,0}
-};
-
-static driver_t	cpcisa_driver = {
-	"isab",
-	cpcisa_methods,
-	0
-};
-
-DRIVER_MODULE(cpcisa, cpcht, cpcisa_driver, isab_devclass, 0, 0);
-
-static int
-cpcisa_probe(device_t dev)
-{
-	const char	*type;
-
-	type = ofw_bus_get_type(dev);
-
-	if (type == NULL)
-		return (ENXIO);
-
-	if (strcmp(type, "isa") != 0)
-		return (ENXIO);
-
-	device_set_desc(dev, "HyperTransport-ISA bridge");
-	
-	return (0);
-}
-
-#endif /* DEV_ISA */
-
-/*
- * CPC PCI Device interface.
- */
-static int		cpcpci_probe(device_t);
-static int		cpcpci_attach(device_t);
+static void		cpcht_build_htirq_map(device_t);
 
 /*
  * Bus interface.
  */
-static int		cpcpci_read_ivar(device_t, device_t, int,
+static int		cpcht_read_ivar(device_t, device_t, int,
 			    uintptr_t *);
-static struct		resource * cpcpci_alloc_resource(device_t bus,
-			    device_t child, int type, int *rid, u_long start,
-			    u_long end, u_long count, u_int flags);
-static int		cpcpci_activate_resource(device_t bus, device_t child,
+static struct resource *cpcht_alloc_resource(device_t bus, device_t child,
+			    int type, int *rid, u_long start, u_long end,
+			    u_long count, u_int flags);
+static int		cpcht_activate_resource(device_t bus, device_t child,
+			    int type, int rid, struct resource *res);
+static int		cpcht_release_resource(device_t bus, device_t child,
+			    int type, int rid, struct resource *res);
+static int		cpcht_deactivate_resource(device_t bus, device_t child,
 			    int type, int rid, struct resource *res);
 
 /*
  * pcib interface.
  */
-static int		cpcpci_maxslots(device_t);
-static u_int32_t	cpcpci_read_config(device_t, u_int, u_int, u_int,
+static int		cpcht_maxslots(device_t);
+static u_int32_t	cpcht_read_config(device_t, u_int, u_int, u_int,
 			    u_int, int);
-static void		cpcpci_write_config(device_t, u_int, u_int, u_int,
+static void		cpcht_write_config(device_t, u_int, u_int, u_int,
 			    u_int, u_int32_t, int);
-static int		cpcpci_route_interrupt(device_t, device_t, int);
+static int		cpcht_route_interrupt(device_t bus, device_t dev,
+			    int pin);
 
 /*
  * ofw_bus interface
  */
 
-static phandle_t	cpcpci_get_node(device_t bus, device_t child);
+static phandle_t	cpcht_get_node(device_t bus, device_t child);
 
 /*
  * Driver methods.
  */
-static device_method_t	cpcpci_methods[] = {
+static device_method_t	cpcht_methods[] = {
 	/* Device interface */
-	DEVMETHOD(device_probe,		cpcpci_probe),
-	DEVMETHOD(device_attach,	cpcpci_attach),
+	DEVMETHOD(device_probe,		cpcht_probe),
+	DEVMETHOD(device_attach,	cpcht_attach),
 
 	/* Bus interface */
 	DEVMETHOD(bus_print_child,	bus_generic_print_child),
-	DEVMETHOD(bus_read_ivar,	cpcpci_read_ivar),
+	DEVMETHOD(bus_read_ivar,	cpcht_read_ivar),
 	DEVMETHOD(bus_setup_intr,	bus_generic_setup_intr),
 	DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
-	DEVMETHOD(bus_alloc_resource,	cpcpci_alloc_resource),
-	DEVMETHOD(bus_activate_resource,	cpcpci_activate_resource),
+	DEVMETHOD(bus_alloc_resource,	cpcht_alloc_resource),
+	DEVMETHOD(bus_release_resource,	cpcht_release_resource),
+	DEVMETHOD(bus_activate_resource,	cpcht_activate_resource),
+	DEVMETHOD(bus_deactivate_resource,	cpcht_deactivate_resource),
 
 	/* pcib interface */
-	DEVMETHOD(pcib_maxslots,	cpcpci_maxslots),
-	DEVMETHOD(pcib_read_config,	cpcpci_read_config),
-	DEVMETHOD(pcib_write_config,	cpcpci_write_config),
-	DEVMETHOD(pcib_route_interrupt,	cpcpci_route_interrupt),
+	DEVMETHOD(pcib_maxslots,	cpcht_maxslots),
+	DEVMETHOD(pcib_read_config,	cpcht_read_config),
+	DEVMETHOD(pcib_write_config,	cpcht_write_config),
+	DEVMETHOD(pcib_route_interrupt,	cpcht_route_interrupt),
 
 	/* ofw_bus interface */
-	DEVMETHOD(ofw_bus_get_node,     cpcpci_get_node),
+	DEVMETHOD(ofw_bus_get_node,     cpcht_get_node),
 	{ 0, 0 }
 };
 
-static driver_t	cpcpci_driver = {
+struct cpcht_irq {
+	int		ht_source;
+
+	vm_offset_t	ht_base;
+	vm_offset_t	apple_eoi;
+	uint32_t	eoi_data;
+};
+
+static struct cpcht_irq *cpcht_irqmap = NULL;
+
+struct cpcht_softc {
+	device_t		sc_dev;
+	phandle_t		sc_node;
+	vm_offset_t		sc_data;
+	int			sc_bus;
+	struct			rman sc_mem_rman;
+
+	struct cpcht_irq	htirq_map[128];
+};
+
+static driver_t	cpcht_driver = {
 	"pcib",
-	cpcpci_methods,
-	sizeof(struct cpcpci_softc)
+	cpcht_methods,
+	sizeof(struct cpcht_softc)
 };
 
-static devclass_t	cpcpci_devclass;
+static devclass_t	cpcht_devclass;
 
-DRIVER_MODULE(cpcpci, cpcht, cpcpci_driver, cpcpci_devclass, 0, 0);
+DRIVER_MODULE(cpcht, nexus, cpcht_driver, cpcht_devclass, 0, 0);
 
 static int
-cpcpci_probe(device_t dev)
+cpcht_probe(device_t dev)
 {
-	const char	*type;
+	const char	*type, *compatible;
 
 	type = ofw_bus_get_type(dev);
+	compatible = ofw_bus_get_compat(dev);
 
-	if (type == NULL)
+	if (type == NULL || compatible == NULL)
 		return (ENXIO);
 
-	if (strcmp(type, "pci") != 0)
+	if (strcmp(type, "ht") != 0)
 		return (ENXIO);
 
-	device_set_desc(dev, "HyperTransport-PCI bridge");
-	
+	if (strcmp(compatible, "u3-ht") != 0)
+		return (ENXIO);
+
+
+	device_set_desc(dev, "IBM CPC9X5 HyperTransport Tunnel");
 	return (0);
 }
 
 static int
-cpcpci_attach(device_t dev)
+cpcht_attach(device_t dev)
 {
-	struct		cpcpci_softc *sc;
+	struct		cpcht_softc *sc;
 	phandle_t	node;
-	u_int32_t	reg[2], busrange[2], config_base;
-	struct		cpcpci_range *rp, *io, *mem[2];
-	struct		cpcpci_range fakeio;
-	int		nmem, i;
+	u_int32_t	reg[3];
+	int		error;
 
 	node = ofw_bus_get_node(dev);
 	sc = device_get_softc(dev);
 
-	if (OF_getprop(OF_parent(node), "reg", reg, sizeof(reg)) < 8)
-		return (ENXIO);
-
-	if (OF_getprop(node, "bus-range", busrange, sizeof(busrange)) != 8)
+	if (OF_getprop(node, "reg", reg, sizeof(reg)) < 12)
 		return (ENXIO);
 
 	sc->sc_dev = dev;
 	sc->sc_node = node;
-	sc->sc_bus = busrange[0];
-	config_base = reg[1];
-	if (sc->sc_bus)
-		config_base += 0x01000000UL + (sc->sc_bus << 16);
-	sc->sc_data = (vm_offset_t)pmap_mapdev(config_base, PAGE_SIZE << 4);
-
-	bzero(sc->sc_range, sizeof(sc->sc_range));
-	sc->sc_nrange = OF_getprop(node, "ranges", sc->sc_range,
-	    sizeof(sc->sc_range));
+	sc->sc_bus = 0;
+	sc->sc_data = (vm_offset_t)pmap_mapdev(reg[1], reg[2]);
 
-	if (sc->sc_nrange == -1) {
-		device_printf(dev, "could not get ranges\n");
-		return (ENXIO);
-	}
+	device_add_child(dev, "pci", device_get_unit(dev));
 
-	sc->sc_range[6].pci_hi = 0;
-	io = NULL;
-	nmem = 0;
-
-	for (rp = sc->sc_range; rp->pci_hi != 0; rp++) {
-		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;
-			break;
-		case OFW_PCI_PHYS_HI_SPACE_MEM32:
-			mem[nmem] = rp;
-			nmem++;
-			break;
-		case OFW_PCI_PHYS_HI_SPACE_MEM64:
-			break;
-		}
-	}
+	sc->sc_mem_rman.rm_type = RMAN_ARRAY;
+	sc->sc_mem_rman.rm_descr = "CPCHT Device Memory";
+	error = rman_init(&sc->sc_mem_rman);
 
-	if (io == NULL) {
-		/*
-		 * On at least some machines, the I/O port range is
-		 * not exported in the OF device tree. So hardcode it.
-		 */
-
-		fakeio.host_lo = 0;
-		fakeio.pci_lo = reg[1];
-		fakeio.size_lo = 0x00400000;
-		if (sc->sc_bus)
-			fakeio.pci_lo += 0x02000000UL + (sc->sc_bus << 14);
-		io = &fakeio;
-	}
-	sc->sc_io_rman.rm_type = RMAN_ARRAY;
-	sc->sc_io_rman.rm_descr = "CPC 9xx PCI I/O Ports";
-	sc->sc_iostart = io->host_lo;
-	if (rman_init(&sc->sc_io_rman) != 0 ||
-	    rman_manage_region(&sc->sc_io_rman, io->pci_lo,
-	    io->pci_lo + io->size_lo - 1) != 0) {
-		device_printf(dev, "failed to set up io range management\n");
-		return (ENXIO);
+	if (error) {
+		device_printf(dev, "rman_init() failed. error = %d\n", error);
+		return (error);
 	}
 
-	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 = "CPC 9xx PCI Memory";
-	if (rman_init(&sc->sc_mem_rman) != 0) {
-		device_printf(dev,
-		    "failed to init mem range resources\n");
-		return (ENXIO);
-	}
-	for (i = 0; i < nmem; i++) {
-		if (rman_manage_region(&sc->sc_mem_rman, mem[i]->pci_lo,
-		    mem[i]->pci_lo + mem[i]->size_lo - 1) != 0) {
-			device_printf(dev,
-			    "failed to set up memory range management\n");
-			return (ENXIO);
-		}
-	}
+	/* Build up the HT->MPIC mapping */
+	cpcht_build_htirq_map(dev);
+
+	return (bus_generic_attach(dev));
+}
 
-	ofw_bus_setup_iinfo(node, &sc->sc_pci_iinfo, sizeof(cell_t));
+static void
+cpcht_build_htirq_map(device_t dev)
+{
+	struct cpcht_softc *sc;
+	int pcifunchigh, hdrtype;
+	int ptr, nextptr;
+	uint32_t vend, val;
+	int nirq, irq;
+	int i, s, f;
 
-	device_add_child(dev, "pci", device_get_unit(dev));
+	sc = device_get_softc(dev);
+	bzero(sc->htirq_map, sizeof(sc->htirq_map));
 
-	return (bus_generic_attach(dev));
+	/*
+	 * Now we need to build up the HT->MPIC IRQ map. One would naively
+	 * hope that enabling, disabling, and EOIing interrupts would cause
+	 * the appropriate HT bus transactions to that effect. This is not
+	 * the case.
+	 *
+	 * Instead, we have to muck about on the HT peer's root PCI bridges,
+	 * figure out what interrupts they send, enable them, and cache
+	 * the location of their WaitForEOI registers so that we can
+	 * send EOIs later.
+	 */
+
+	for (s = 0; s < 0x1f; s++) {
+	    pcifunchigh = 0;
+	    hdrtype = PCIB_READ_CONFIG(dev, 0, s, 0, PCIR_HDRTYPE, 1);
+
+	    if ((hdrtype & PCIM_HDRTYPE) > PCI_MAXHDRTYPE)
+		continue;
+	    if (hdrtype & PCIM_MFDEV)
+		pcifunchigh = PCI_FUNCMAX;
+	    for (f = 0; f <= pcifunchigh; f++) {
+		vend = PCIB_READ_CONFIG(dev, 0, s, f, PCIR_DEVVENDOR, 4);
+		if (vend == 0xfffffffful)
+			continue;
+
+		/* All the devices we are interested in have caps */
+		if (!(PCIB_READ_CONFIG(dev, 0, s, f, PCIR_STATUS, 2)
+		    & PCIM_STATUS_CAPPRESENT))
+			continue;
+
+		nextptr = PCIB_READ_CONFIG(dev, 0, s, f, PCIR_CAP_PTR, 1);
+		while (nextptr != 0) {
+			ptr = nextptr;
+			nextptr = PCIB_READ_CONFIG(dev, 0, s, f,
+			    ptr + PCICAP_NEXTPTR, 1);
+
+			/* Find the HT IRQ capabilities */
+			if (PCIB_READ_CONFIG(dev, 0, s, f,
+			    ptr + PCICAP_ID, 1) != PCIY_HT)
+				continue;
+
+			val = PCIB_READ_CONFIG(dev, 0, s, f,
+			    ptr + PCIR_HT_COMMAND, 2);
+			if ((val & PCIM_HTCMD_CAP_MASK) !=
+			    PCIM_HTCAP_INTERRUPT)
+				continue;
+
+			/* Ask for the IRQ count */
+			PCIB_WRITE_CONFIG(dev, 0, s, f,
+			     ptr + PCIR_HT_COMMAND, 0x1, 1);
+			nirq = PCIB_READ_CONFIG(dev, 0, s, f, ptr + 4, 4);
+			nirq = (nirq >> 16) & 0xff;
+
+			device_printf(dev, "%d HT IRQs on device %d.%d\n",
+			    nirq, s, f);
+
+			for (i = 0; i <= nirq; i++) {
+				PCIB_WRITE_CONFIG(dev, 0, s, f,
+				     ptr + PCIR_HT_COMMAND, 0x10 + (i << 1), 1);
+				irq = PCIB_READ_CONFIG(dev, 0, s, f, ptr + 4, 4);
+
+				/*
+				 * Enable immediately as a level interrupt.
+				 * It is still masked in the MPIC.
+				 */
+				PCIB_WRITE_CONFIG(dev, 0, s, f, ptr + 4,
+				    (irq & ~0x23) | 0x22, 4);
+				irq = (irq >> 16) & 0xff;
+
+				sc->htirq_map[irq].ht_source = i;
+				sc->htirq_map[irq].ht_base = sc->sc_data + 
+				    (((((s & 0x1f) << 3) | (f & 0x07)) << 8)
+				    | (ptr));
+
+				PCIB_WRITE_CONFIG(dev, 0, s, f,
+				     ptr + PCIR_HT_COMMAND, 0x11 + (i << 1), 1);
+				sc->htirq_map[irq].eoi_data =
+				    PCIB_READ_CONFIG(dev, 0, s, f, ptr + 4, 4) |
+				    0x80000000;
+
+				/*
+				 * Apple uses a non-compliant IO/APIC that differs
+				 * in how we signal EOIs. Check if this device was 
+				 * made by Apple, and act accordingly.
+				 */
+				if ((vend & 0xffff) == 0x106b)
+					sc->htirq_map[irq].apple_eoi = 
+					 (sc->htirq_map[irq].ht_base - ptr) + 0x60;
+			}
+		}
+	    }
+	}
+
+	/* Now make this table available to the MPIC */
+	cpcht_irqmap = sc->htirq_map;
 }
 
 static int
-cpcpci_maxslots(device_t dev)
+cpcht_maxslots(device_t dev)
 {
 
 	return (PCI_SLOTMAX);
 }
 
 static u_int32_t
-cpcpci_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg,
+cpcht_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg,
     int width)
 {
-	struct		cpcpci_softc *sc;
+	struct		cpcht_softc *sc;
 	vm_offset_t	caoff;
 
 	sc = device_get_softc(dev);
 	caoff = sc->sc_data + 
 		(((((slot & 0x1f) << 3) | (func & 0x07)) << 8) | reg);
 
+	if (bus > 0)
+		caoff += 0x01000000UL + (bus << 16);
+
 	switch (width) {
 	case 1:
 		return (in8rb(caoff));
@@ -453,16 +360,19 @@ cpcpci_read_config(device_t dev, u_int b
 }
 
 static void
-cpcpci_write_config(device_t dev, u_int bus, u_int slot, u_int func,
+cpcht_write_config(device_t dev, u_int bus, u_int slot, u_int func,
     u_int reg, u_int32_t val, int width)
 {
-	struct		cpcpci_softc *sc;
+	struct		cpcht_softc *sc;
 	vm_offset_t	caoff;
 
 	sc = device_get_softc(dev);
 	caoff = sc->sc_data + 
 		(((((slot & 0x1f) << 3) | (func & 0x07)) << 8) | reg);
 
+	if (bus > 0)
+		caoff += 0x01000000UL + (bus << 16);
+
 	switch (width) {
 	case 1:
 		out8rb(caoff, val);
@@ -477,9 +387,9 @@ cpcpci_write_config(device_t dev, u_int 
 }
 
 static int
-cpcpci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
+cpcht_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
 {
-	struct	cpcpci_softc *sc;
+	struct	cpcht_softc *sc;
 
 	sc = device_get_softc(dev);
 
@@ -495,29 +405,45 @@ cpcpci_read_ivar(device_t dev, device_t 
 	return (ENOENT);
 }
 
+static phandle_t
+cpcht_get_node(device_t bus, device_t dev)
+{
+	struct cpcht_softc *sc;
+
+	sc = device_get_softc(bus);
+	/* We only have one child, the PCI bus, which needs our own node. */
+	return (sc->sc_node);
+}
+
+static int
+cpcht_route_interrupt(device_t bus, device_t dev, int pin)
+{
+	return (pin);

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


More information about the svn-src-projects mailing list