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:
parent
c02fc9607a
commit
a1df0d9592
@ -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.
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user