The diff below teaches ppb(4) how to configure PCI bridges that are
left unconfigured by firmware.  This happens for example on Apple
hardware, where devices connected through Thunderbolt are left
unconfigured.  And since Thunderbolt is basically a bunch of PCI
bridges (or more correctly PCIe switches), this includes a couple of
ppb(4) devices.

With this diff, an Apple Thunderbolt Gigabit Ethernet adapter that is
plugged in when my MacBookPro12,1 is booted starts working:

bge0 at pci9 dev 0 function 0 "Broadcom BCM57762" rev 0x00, unknown BCM57766 
(0x57766000): msi, address 98:5a:eb:c7:30:e4
brgphy0 at bge0 phy 1: BCM57765 10/100/1000baseT PHY, rev. 0

Since this diff changes the code that deals with partly configured PCI
bridges as well, it would be good to test this on a wide variety of
hardware, especially if you have one of those 4-port or 6-port em(4)
cards.

If you find any regressions, please send me:

* dmesg (with and without this diff)
* pcidump -vxx (with and without this diff)

Thanks,

Mark


Index: ppb.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/ppb.c,v
retrieving revision 1.64
diff -u -p -r1.64 ppb.c
--- ppb.c       19 Oct 2015 19:24:54 -0000      1.64
+++ ppb.c       28 Nov 2015 12:44:06 -0000
@@ -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 
        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 
 
        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 
                    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 
        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 = 8; 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
                        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;
@@ -632,6 +689,9 @@ ppb_alloc_resources(struct ppb_softc *sc
                        }
                }
        }
+
+       /* Enable bus master. */
+       csr |= PCI_COMMAND_MASTER_ENABLE;
 
        pci_conf_write(pc, sc->sc_tag, PCI_COMMAND_STATUS_REG, csr);
 }

Reply via email to