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, ®,
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