summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2015-12-01 21:02:05 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2015-12-01 21:02:05 +0000
commit3b6c579ae94b204ce00ec5d2dd804bd05f927701 (patch)
tree28f51bc7a7f5a026345f7140b14389cedd658d3e /sys
parentc017c7ea476b7e78020bcbf1fe9ccc38ce3bf189 (diff)
Teach ppb(4) how to allocate PCI bus numbers such that it can properly
condigure bridges left unconfigured by the system firmware. Not perfect yet, but good enough to make the Apple Thunderbolt Giabit Ethernet adapter work when inserted at boot time. ok deraadt@
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/pci/ppb.c62
1 files changed, 61 insertions, 1 deletions
diff --git a/sys/dev/pci/ppb.c b/sys/dev/pci/ppb.c
index bbd13f25233..95a71e53096 100644
--- a/sys/dev/pci/ppb.c
+++ b/sys/dev/pci/ppb.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ppb.c,v 1.64 2015/10/19 19:24:54 kettenis Exp $ */
+/* $OpenBSD: ppb.c,v 1.65 2015/12/01 21:02:04 kettenis Exp $ */
/* $NetBSD: ppb.c,v 1.16 1997/06/06 23:48:05 thorpej Exp $ */
/*
@@ -66,6 +66,7 @@ struct ppb_softc {
pcitag_t sc_tag; /* ...and tag. */
pci_intr_handle_t sc_ih[4];
void *sc_intrhand;
+ struct extent *sc_busex;
struct extent *sc_ioex;
struct extent *sc_memex;
struct extent *sc_pmemex;
@@ -106,6 +107,8 @@ struct cfdriver ppb_cd = {
NULL, "ppb", DV_DULL
};
+void ppb_alloc_busrange(struct ppb_softc *, struct pci_attach_args *,
+ pcireg_t *);
void ppb_alloc_resources(struct ppb_softc *, struct pci_attach_args *);
int ppb_intr(void *);
void ppb_hotplug_insert(void *);
@@ -151,6 +154,7 @@ ppbattach(struct device *parent, struct device *self, void *aux)
pci_intr_handle_t ih;
pcireg_t busdata, reg, blr;
char *name;
+ int sec, sub;
int pin;
sc->sc_pc = pc;
@@ -158,6 +162,16 @@ ppbattach(struct device *parent, struct device *self, void *aux)
busdata = pci_conf_read(pc, pa->pa_tag, PPB_REG_BUSINFO);
+ /*
+ * When the bus number isn't configured, try to allocate one
+ * ourselves.
+ */
+ if (busdata == 0 && pa->pa_busex)
+ ppb_alloc_busrange(sc, pa, &busdata);
+
+ /*
+ * When the bus number still isn't set correctly, give up.
+ */
if (PPB_BUSINFO_SECONDARY(busdata) == 0) {
printf(": not configured by system firmware\n");
return;
@@ -175,6 +189,19 @@ ppbattach(struct device *parent, struct device *self, void *aux)
pa->pa_bus, PPB_BUSINFO_PRIMARY(busdata));
#endif
+ sec = PPB_BUSINFO_SECONDARY(busdata);
+ sub = PPB_BUSINFO_SUBORDINATE(busdata);
+ if (sub > sec) {
+ name = malloc(PPB_EXNAMLEN, M_DEVBUF, M_NOWAIT);
+ if (name) {
+ snprintf(name, PPB_EXNAMLEN, "%s pcibus", sc->sc_dev.dv_xname);
+ sc->sc_busex = extent_create(name, 0, 0xff,
+ M_DEVBUF, NULL, 0, EX_NOWAIT | EX_FILLED);
+ extent_free(sc->sc_busex, sec + 1,
+ sub - sec, EX_NOWAIT);
+ }
+ }
+
/* Check for PCI Express capabilities and setup hotplug support. */
if (pci_get_capability(pc, pa->pa_tag, PCI_CAP_PCIEXPRESS,
&sc->sc_cap_off, &reg) && (reg & PCI_PCIE_XCAP_SI)) {
@@ -313,6 +340,7 @@ ppbattach(struct device *parent, struct device *self, void *aux)
pba.pba_dmat = pa->pa_dmat;
pba.pba_pc = pc;
pba.pba_flags = pa->pa_flags & ~PCI_FLAGS_MRM_OKAY;
+ pba.pba_busex = sc->sc_busex;
pba.pba_ioex = sc->sc_ioex;
pba.pba_memex = sc->sc_memex;
pba.pba_pmemex = sc->sc_pmemex;
@@ -338,6 +366,12 @@ ppbdetach(struct device *self, int flags)
rv = config_detach_children(self, flags);
+ if (sc->sc_busex) {
+ name = sc->sc_busex->ex_name;
+ extent_destroy(sc->sc_busex);
+ free(name, M_DEVBUF, PPB_EXNAMLEN);
+ }
+
if (sc->sc_ioex) {
name = sc->sc_ioex->ex_name;
extent_destroy(sc->sc_ioex);
@@ -485,6 +519,25 @@ ppbactivate(struct device *self, int act)
}
void
+ppb_alloc_busrange(struct ppb_softc *sc, struct pci_attach_args *pa,
+ pcireg_t *busdata)
+{
+ pci_chipset_tag_t pc = sc->sc_pc;
+ u_long busnum, busrange;
+
+ for (busrange = 16; busrange > 0; busrange >>= 1) {
+ if (extent_alloc(pa->pa_busex, busrange, 1, 0, 0,
+ EX_NOWAIT, &busnum))
+ continue;
+ *busdata |= pa->pa_bus;
+ *busdata |= (busnum << 8);
+ *busdata |= ((busnum + busrange - 1) << 16);
+ pci_conf_write(pc, pa->pa_tag, PPB_REG_BUSINFO, *busdata);
+ return;
+ }
+}
+
+void
ppb_alloc_resources(struct ppb_softc *sc, struct pci_attach_args *pa)
{
pci_chipset_tag_t pc = sc->sc_pc;
@@ -530,11 +583,15 @@ ppb_alloc_resources(struct ppb_softc *sc, struct pci_attach_args *pa)
reg_start = PCI_MAPREG_START;
reg_end = PCI_MAPREG_PPB_END;
reg_rom = 0; /* 0x38 */
+ io_count++;
+ mem_count++;
break;
case 2: /* PCI-Cardbus bridge */
reg_start = PCI_MAPREG_START;
reg_end = PCI_MAPREG_PCB_END;
reg_rom = 0;
+ io_count++;
+ mem_count++;
break;
default:
return;
@@ -633,6 +690,9 @@ ppb_alloc_resources(struct ppb_softc *sc, struct pci_attach_args *pa)
}
}
+ /* Enable bus master. */
+ csr |= PCI_COMMAND_MASTER_ENABLE;
+
pci_conf_write(pc, sc->sc_tag, PCI_COMMAND_STATUS_REG, csr);
}