Refine locking inside of syscon driver.
In some cases, the syscon driver may be used by consumer requiring better control about locking (ie. it may be used as registe file provider for clock driver which needs locked access to multiple registers). Add fine locking protocol methods together with bunch of helper functions in syscon driver and implement this functionality in syscon_generic driver. MFC after: 4 weeks
This commit is contained in:
parent
0d46edd0bb
commit
01d0f9c0e4
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=366161
@ -67,6 +67,12 @@ typedef TAILQ_HEAD(syscon_list, syscon) syscon_list_t;
|
||||
*/
|
||||
static int syscon_method_init(struct syscon *syscon);
|
||||
static int syscon_method_uninit(struct syscon *syscon);
|
||||
static uint32_t syscon_method_read_4(struct syscon *syscon, bus_size_t offset);
|
||||
static int syscon_method_write_4(struct syscon *syscon, bus_size_t offset,
|
||||
uint32_t val);
|
||||
static int syscon_method_modify_4(struct syscon *syscon, bus_size_t offset,
|
||||
uint32_t clear_bits, uint32_t set_bits);
|
||||
|
||||
|
||||
MALLOC_DEFINE(M_SYSCON, "syscon", "Syscon driver");
|
||||
|
||||
@ -80,6 +86,9 @@ SX_SYSINIT(syscon_topology, &syscon_topo_lock, "Syscon topology lock");
|
||||
static syscon_method_t syscon_methods[] = {
|
||||
SYSCONMETHOD(syscon_init, syscon_method_init),
|
||||
SYSCONMETHOD(syscon_uninit, syscon_method_uninit),
|
||||
SYSCONMETHOD(syscon_read_4, syscon_method_read_4),
|
||||
SYSCONMETHOD(syscon_write_4, syscon_method_write_4),
|
||||
SYSCONMETHOD(syscon_modify_4, syscon_method_modify_4),
|
||||
|
||||
SYSCONMETHOD_END
|
||||
};
|
||||
@ -115,6 +124,39 @@ syscon_get_softc(struct syscon *syscon)
|
||||
return (syscon->softc);
|
||||
};
|
||||
|
||||
static uint32_t
|
||||
syscon_method_read_4(struct syscon *syscon, bus_size_t offset)
|
||||
{
|
||||
uint32_t val;
|
||||
|
||||
SYSCON_DEVICE_LOCK(syscon->pdev);
|
||||
val = SYSCON_UNLOCKED_READ_4(syscon, offset);
|
||||
SYSCON_DEVICE_UNLOCK(syscon->pdev);
|
||||
return(val);
|
||||
}
|
||||
|
||||
static int
|
||||
syscon_method_write_4(struct syscon *syscon, bus_size_t offset, uint32_t val)
|
||||
{
|
||||
int rv;
|
||||
|
||||
SYSCON_DEVICE_LOCK(syscon->pdev);
|
||||
rv = SYSCON_UNLOCKED_WRITE_4(syscon, offset, val);
|
||||
SYSCON_DEVICE_UNLOCK(syscon->pdev);
|
||||
return(rv);
|
||||
}
|
||||
|
||||
static int
|
||||
syscon_method_modify_4(struct syscon *syscon, bus_size_t offset,
|
||||
uint32_t clear_bits, uint32_t set_bits)
|
||||
{
|
||||
int rv;
|
||||
|
||||
SYSCON_DEVICE_LOCK(syscon->pdev);
|
||||
rv = SYSCON_UNLOCKED_MODIFY_4(syscon, offset, clear_bits, set_bits);
|
||||
SYSCON_DEVICE_UNLOCK(syscon->pdev);
|
||||
return(rv);
|
||||
}
|
||||
/*
|
||||
* Create and initialize syscon object, but do not register it.
|
||||
*/
|
||||
@ -254,14 +296,3 @@ syscon_get_by_ofw_property(device_t cdev, phandle_t cnode, char *name,
|
||||
return (0);
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
syscon_get_handle_default(device_t dev, struct syscon **syscon)
|
||||
{
|
||||
device_t parent;
|
||||
|
||||
parent = device_get_parent(dev);
|
||||
if (parent == NULL)
|
||||
return (ENODEV);
|
||||
return (SYSCON_GET_HANDLE(parent, syscon));
|
||||
}
|
||||
|
@ -55,11 +55,12 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
MALLOC_DECLARE(M_SYSCON);
|
||||
|
||||
static uint32_t syscon_generic_read_4(struct syscon *syscon, bus_size_t offset);
|
||||
static int syscon_generic_write_4(struct syscon *syscon, bus_size_t offset,
|
||||
uint32_t val);
|
||||
static int syscon_generic_modify_4(struct syscon *syscon, bus_size_t offset,
|
||||
uint32_t clear_bits, uint32_t set_bits);
|
||||
static uint32_t syscon_generic_unlocked_read_4(struct syscon *syscon,
|
||||
bus_size_t offset);
|
||||
static int syscon_generic_unlocked_write_4(struct syscon *syscon,
|
||||
bus_size_t offset, uint32_t val);
|
||||
static int syscon_generic_unlocked_modify_4(struct syscon *syscon,
|
||||
bus_size_t offset, uint32_t clear_bits, uint32_t set_bits);
|
||||
static int syscon_generic_detach(device_t dev);
|
||||
/*
|
||||
* Generic syscon driver (FDT)
|
||||
@ -78,9 +79,9 @@ static struct ofw_compat_data compat_data[] = {
|
||||
#define SYSCON_ASSERT_UNLOCKED(_sc) mtx_assert(&(_sc)->mtx, MA_NOTOWNED);
|
||||
|
||||
static syscon_method_t syscon_generic_methods[] = {
|
||||
SYSCONMETHOD(syscon_read_4, syscon_generic_read_4),
|
||||
SYSCONMETHOD(syscon_write_4, syscon_generic_write_4),
|
||||
SYSCONMETHOD(syscon_modify_4, syscon_generic_modify_4),
|
||||
SYSCONMETHOD(syscon_unlocked_read_4, syscon_generic_unlocked_read_4),
|
||||
SYSCONMETHOD(syscon_unlocked_write_4, syscon_generic_unlocked_write_4),
|
||||
SYSCONMETHOD(syscon_unlocked_modify_4, syscon_generic_unlocked_modify_4),
|
||||
|
||||
SYSCONMETHOD_END
|
||||
};
|
||||
@ -88,50 +89,62 @@ DEFINE_CLASS_1(syscon_generic, syscon_generic_class, syscon_generic_methods,
|
||||
0, syscon_class);
|
||||
|
||||
static uint32_t
|
||||
syscon_generic_read_4(struct syscon *syscon, bus_size_t offset)
|
||||
syscon_generic_unlocked_read_4(struct syscon *syscon, bus_size_t offset)
|
||||
{
|
||||
struct syscon_generic_softc *sc;
|
||||
uint32_t val;
|
||||
|
||||
sc = device_get_softc(syscon->pdev);
|
||||
|
||||
SYSCON_LOCK(sc);
|
||||
SYSCON_ASSERT_UNLOCKED(sc);
|
||||
val = bus_read_4(sc->mem_res, offset);
|
||||
SYSCON_UNLOCK(sc);
|
||||
return (val);
|
||||
}
|
||||
|
||||
static int
|
||||
syscon_generic_write_4(struct syscon *syscon, bus_size_t offset, uint32_t val)
|
||||
syscon_generic_unlocked_write_4(struct syscon *syscon, bus_size_t offset, uint32_t val)
|
||||
{
|
||||
struct syscon_generic_softc *sc;
|
||||
|
||||
sc = device_get_softc(syscon->pdev);
|
||||
|
||||
SYSCON_LOCK(sc);
|
||||
SYSCON_ASSERT_UNLOCKED(sc);
|
||||
bus_write_4(sc->mem_res, offset, val);
|
||||
SYSCON_UNLOCK(sc);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
syscon_generic_modify_4(struct syscon *syscon, bus_size_t offset,
|
||||
syscon_generic_unlocked_modify_4(struct syscon *syscon, bus_size_t offset,
|
||||
uint32_t clear_bits, uint32_t set_bits)
|
||||
{
|
||||
struct syscon_generic_softc *sc;
|
||||
uint32_t val;
|
||||
|
||||
sc = device_get_softc(syscon->pdev);
|
||||
|
||||
SYSCON_LOCK(sc);
|
||||
SYSCON_ASSERT_UNLOCKED(sc);
|
||||
val = bus_read_4(sc->mem_res, offset);
|
||||
val &= ~clear_bits;
|
||||
val |= set_bits;
|
||||
bus_write_4(sc->mem_res, offset, val);
|
||||
SYSCON_UNLOCK(sc);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
syscon_generic_lock(device_t dev)
|
||||
{
|
||||
struct syscon_generic_softc *sc;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
SYSCON_LOCK(sc);
|
||||
}
|
||||
|
||||
static void
|
||||
syscon_generic_unlock(device_t dev)
|
||||
{
|
||||
struct syscon_generic_softc *sc;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
SYSCON_UNLOCK(sc);
|
||||
}
|
||||
|
||||
static int
|
||||
syscon_generic_probe(device_t dev)
|
||||
{
|
||||
@ -211,6 +224,9 @@ static device_method_t syscon_generic_dmethods[] = {
|
||||
DEVMETHOD(device_attach, syscon_generic_attach),
|
||||
DEVMETHOD(device_detach, syscon_generic_detach),
|
||||
|
||||
DEVMETHOD(syscon_device_lock, syscon_generic_lock),
|
||||
DEVMETHOD(syscon_device_unlock, syscon_generic_unlock),
|
||||
|
||||
DEVMETHOD_END
|
||||
};
|
||||
|
||||
|
@ -35,6 +35,36 @@ HEADER {
|
||||
int syscon_get_handle_default(device_t dev, struct syscon **syscon);
|
||||
}
|
||||
|
||||
CODE {
|
||||
#include <sys/systm.h>
|
||||
#include <sys/bus.h>
|
||||
|
||||
int
|
||||
syscon_get_handle_default(device_t dev, struct syscon **syscon)
|
||||
{
|
||||
device_t parent;
|
||||
|
||||
parent = device_get_parent(dev);
|
||||
if (parent == NULL)
|
||||
return (ENODEV);
|
||||
return (SYSCON_GET_HANDLE(parent, syscon));
|
||||
}
|
||||
|
||||
static void
|
||||
syscon_device_lock_default(device_t dev)
|
||||
{
|
||||
|
||||
panic("syscon_device_lock is not implemented");
|
||||
};
|
||||
|
||||
static void
|
||||
syscon_device_unlock_default(device_t dev)
|
||||
{
|
||||
|
||||
panic("syscon_device_unlock is not implemented");
|
||||
};
|
||||
}
|
||||
|
||||
METHOD int init {
|
||||
struct syscon *syscon;
|
||||
};
|
||||
@ -64,6 +94,38 @@ METHOD int modify_4 {
|
||||
uint32_t set_bits;
|
||||
};
|
||||
|
||||
/**
|
||||
* Unlocked verion of access function
|
||||
*/
|
||||
METHOD uint32_t unlocked_read_4 {
|
||||
struct syscon *syscon;
|
||||
bus_size_t offset;
|
||||
};
|
||||
|
||||
METHOD int unlocked_write_4 {
|
||||
struct syscon *syscon;
|
||||
bus_size_t offset;
|
||||
uint32_t val;
|
||||
};
|
||||
|
||||
METHOD int unlocked_modify_4 {
|
||||
struct syscon *syscon;
|
||||
bus_size_t offset;
|
||||
uint32_t clear_bits;
|
||||
uint32_t set_bits;
|
||||
};
|
||||
|
||||
/**
|
||||
* Locking for exclusive access to underlying device
|
||||
*/
|
||||
METHOD void device_lock {
|
||||
device_t dev;
|
||||
} DEFAULT syscon_device_lock_default;
|
||||
|
||||
METHOD void device_unlock {
|
||||
device_t dev;
|
||||
} DEFAULT syscon_device_unlock_default;
|
||||
|
||||
/**
|
||||
* Get syscon handle from parent driver
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user