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
This commit is contained in:
Landon J. Fuller 2018-01-10 22:19:11 +00:00
parent c02fc9607a
commit a1df0d9592
2 changed files with 27 additions and 10 deletions

View File

@ -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 slot, u_int func, u_int reg,
{
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 slot, u_int func,
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 slot, u_int func,
break;
}
}
mtx_unlock_spin(&sc->sc_cfg_mtx);
}
static int
@ -224,13 +241,11 @@ uninorth_enable_config(struct uninorth_softc *sc, u_int bus, u_int slot,
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.

View File

@ -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 {