Author: landonf
Date: Wed Jan 10 22:19:11 2018
New Revision: 327798
URL: https://svnweb.freebsd.org/changeset/base/327798

Log:
  Fix minor locking issues in the Power Mac Uninorth PCI bridge driver.
  
  - Call resource_int_value() once during attach, rather than within the
    pci_(read|write)_config() code path; this avoids taking a blocking mutex
    to read kenv variables.
  
  - Use a spin lock to protect non-atomic config space accesses; this matches
    the behavior of Darwin's AppleMacRiscPCI driver.
  
  Reviewed by:  jhibbits
  Differential Revision:        https://reviews.freebsd.org/D13839

Modified:
  head/sys/powerpc/powermac/uninorthpci.c
  head/sys/powerpc/powermac/uninorthvar.h

Modified: head/sys/powerpc/powermac/uninorthpci.c
==============================================================================
--- head/sys/powerpc/powermac/uninorthpci.c     Wed Jan 10 21:59:21 2018        
(r327797)
+++ head/sys/powerpc/powermac/uninorthpci.c     Wed Jan 10 22:19:11 2018        
(r327798)
@@ -34,6 +34,8 @@ __FBSDID("$FreeBSD$");
 #include <sys/bus.h>
 #include <sys/conf.h>
 #include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
 #include <sys/rman.h>
 
 #include <dev/ofw/openfirm.h>
@@ -134,13 +136,17 @@ uninorth_attach(device_t dev)
 {
        struct          uninorth_softc *sc;
        const char      *compatible;
+       const char      *name;
        phandle_t       node;
        uint32_t        reg[3];
        uint64_t        regbase;
        cell_t          acells;
+       int             unit;
 
        node = ofw_bus_get_node(dev);
        sc = device_get_softc(dev);
+       name = device_get_name(dev);
+       unit = device_get_unit(dev);
 
        if (OF_getprop(node, "reg", reg, sizeof(reg)) < 8)
                return (ENXIO);
@@ -164,6 +170,11 @@ uninorth_attach(device_t dev)
        sc->sc_addr = (vm_offset_t)pmap_mapdev(regbase + 0x800000, PAGE_SIZE);
        sc->sc_data = (vm_offset_t)pmap_mapdev(regbase + 0xc00000, PAGE_SIZE);
 
+       if (resource_int_value(name, unit, "skipslot", &sc->sc_skipslot) != 0)
+               sc->sc_skipslot = -1;
+
+       mtx_init(&sc->sc_cfg_mtx, "uninorth pcicfg", NULL, MTX_SPIN);
+
        return (ofw_pci_attach(dev));
 }
 
@@ -173,25 +184,29 @@ uninorth_read_config(device_t dev, u_int bus, u_int sl
 {
        struct          uninorth_softc *sc;
        vm_offset_t     caoff;
+       u_int32_t       val;
 
        sc = device_get_softc(dev);
        caoff = sc->sc_data + (reg & 0x07);
+       val = 0xffffffff;
 
+       mtx_lock_spin(&sc->sc_cfg_mtx);
        if (uninorth_enable_config(sc, bus, slot, func, reg) != 0) {
                switch (width) {
                case 1: 
-                       return (in8rb(caoff));
+                       val = in8rb(caoff);
                        break;
                case 2:
-                       return (in16rb(caoff));
+                       val = in16rb(caoff);
                        break;
                case 4:
-                       return (in32rb(caoff));
+                       val = in32rb(caoff);
                        break;
                }
        }
+       mtx_unlock_spin(&sc->sc_cfg_mtx);
 
-       return (0xffffffff);
+       return (val);
 }
 
 static void
@@ -204,6 +219,7 @@ uninorth_write_config(device_t dev, u_int bus, u_int s
        sc = device_get_softc(dev);
        caoff = sc->sc_data + (reg & 0x07);
 
+       mtx_lock_spin(&sc->sc_cfg_mtx);
        if (uninorth_enable_config(sc, bus, slot, func, reg)) {
                switch (width) {
                case 1:
@@ -217,6 +233,7 @@ uninorth_write_config(device_t dev, u_int bus, u_int s
                        break;
                }
        }
+       mtx_unlock_spin(&sc->sc_cfg_mtx);
 }
 
 static int
@@ -224,13 +241,11 @@ uninorth_enable_config(struct uninorth_softc *sc, u_in
     u_int func, u_int reg)
 {
        uint32_t        cfgval;
-       uint32_t        pass;
 
-       if (resource_int_value(device_get_name(sc->pci_sc.sc_dev),
-               device_get_unit(sc->pci_sc.sc_dev), "skipslot", &pass) == 0) {
-               if (pass == slot)
-                       return (0);
-       }
+       mtx_assert(&sc->sc_cfg_mtx, MA_OWNED);
+
+       if (sc->sc_skipslot == slot)
+               return (0);
 
        /*
         * Issue type 0 configuration space accesses for the root bus.

Modified: head/sys/powerpc/powermac/uninorthvar.h
==============================================================================
--- head/sys/powerpc/powermac/uninorthvar.h     Wed Jan 10 21:59:21 2018        
(r327797)
+++ head/sys/powerpc/powermac/uninorthvar.h     Wed Jan 10 22:19:11 2018        
(r327798)
@@ -39,6 +39,8 @@ struct uninorth_softc {
        vm_offset_t             sc_addr;
        vm_offset_t             sc_data;
        int                     sc_ver;
+       int                     sc_skipslot;
+       struct mtx              sc_cfg_mtx;
 };
 
 struct unin_chip_softc {
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to