From a2b0006e89c7c71c8d1e5613f1ba6336a419ea33 Mon Sep 17 00:00:00 2001 From: mmel Date: Tue, 15 Mar 2016 15:28:24 +0000 Subject: [PATCH] CLK: Add and use explicit locking for access to clock device registers. Implicit locking (for read/write/modify) is not sufficient for complex cases. --- sys/dev/extres/clk/clk_div.c | 13 ++++++++++++- sys/dev/extres/clk/clk_gate.c | 13 +++++++++++-- sys/dev/extres/clk/clk_mux.c | 16 ++++++++++++++-- sys/dev/extres/clk/clkdev_if.m | 31 +++++++++++++++++++++++++++++++ 4 files changed, 68 insertions(+), 5 deletions(-) diff --git a/sys/dev/extres/clk/clk_div.c b/sys/dev/extres/clk/clk_div.c index fcb0a57c4f7b..51cc838303a5 100644 --- a/sys/dev/extres/clk/clk_div.c +++ b/sys/dev/extres/clk/clk_div.c @@ -46,6 +46,10 @@ __FBSDID("$FreeBSD$"); CLKDEV_READ_4(clknode_get_device(_clk), off, val) #define MD4(_clk, off, clr, set ) \ CLKDEV_MODIFY_4(clknode_get_device(_clk), off, clr, set) +#define DEVICE_LOCK(_clk) \ + CLKDEV_DEVICE_LOCK(clknode_get_device(_clk)) +#define DEVICE_UNLOCK(_clk) \ + CLKDEV_DEVICE_UNLOCK(clknode_get_device(_clk)) static int clknode_div_init(struct clknode *clk, device_t dev); static int clknode_div_recalc(struct clknode *clk, uint64_t *req); @@ -86,7 +90,9 @@ clknode_div_init(struct clknode *clk, device_t dev) sc = clknode_get_softc(clk); + DEVICE_LOCK(clk); rv = RD4(clk, sc->offset, ®); + DEVICE_UNLOCK(clk); if (rv != 0) return (rv); @@ -171,12 +177,17 @@ clknode_div_set_freq(struct clknode *clk, uint64_t fin, uint64_t *fout, (*fout != (_fin / divider))) return (ERANGE); + DEVICE_LOCK(clk); rv = MD4(clk, sc->offset, (sc->i_mask << sc->i_shift) | (sc->f_mask << sc->f_shift), (i_div << sc->i_shift) | (f_div << sc->f_shift)); - if (rv != 0) + if (rv != 0) { + DEVICE_UNLOCK(clk); return (rv); + } RD4(clk, sc->offset, ®); + DEVICE_UNLOCK(clk); + sc->divider = divider; } diff --git a/sys/dev/extres/clk/clk_gate.c b/sys/dev/extres/clk/clk_gate.c index 2107450042b6..e0673fd81a7e 100644 --- a/sys/dev/extres/clk/clk_gate.c +++ b/sys/dev/extres/clk/clk_gate.c @@ -46,7 +46,10 @@ __FBSDID("$FreeBSD$"); CLKDEV_READ_4(clknode_get_device(_clk), off, val) #define MD4(_clk, off, clr, set ) \ CLKDEV_MODIFY_4(clknode_get_device(_clk), off, clr, set) - +#define DEVICE_LOCK(_clk) \ + CLKDEV_DEVICE_LOCK(clknode_get_device(_clk)) +#define DEVICE_UNLOCK(_clk) \ + CLKDEV_DEVICE_UNLOCK(clknode_get_device(_clk)) static int clknode_gate_init(struct clknode *clk, device_t dev); static int clknode_gate_set_gate(struct clknode *clk, bool enable); @@ -77,7 +80,9 @@ clknode_gate_init(struct clknode *clk, device_t dev) int rv; sc = clknode_get_softc(clk); + DEVICE_LOCK(clk); rv = RD4(clk, sc->offset, ®); + DEVICE_UNLOCK(clk); if (rv != 0) return (rv); reg = (reg >> sc->shift) & sc->mask; @@ -95,11 +100,15 @@ clknode_gate_set_gate(struct clknode *clk, bool enable) sc = clknode_get_softc(clk); sc->ungated = enable; + DEVICE_LOCK(clk); rv = MD4(clk, sc->offset, sc->mask << sc->shift, (sc->ungated ? sc->on_value : sc->off_value) << sc->shift); - if (rv != 0) + if (rv != 0) { + DEVICE_UNLOCK(clk); return (rv); + } RD4(clk, sc->offset, ®); + DEVICE_UNLOCK(clk); return(0); } diff --git a/sys/dev/extres/clk/clk_mux.c b/sys/dev/extres/clk/clk_mux.c index 54e0653cc05f..624f587b0cc1 100644 --- a/sys/dev/extres/clk/clk_mux.c +++ b/sys/dev/extres/clk/clk_mux.c @@ -46,6 +46,10 @@ __FBSDID("$FreeBSD$"); CLKDEV_READ_4(clknode_get_device(_clk), off, val) #define MD4(_clk, off, clr, set ) \ CLKDEV_MODIFY_4(clknode_get_device(_clk), off, clr, set) +#define DEVICE_LOCK(_clk) \ + CLKDEV_DEVICE_LOCK(clknode_get_device(_clk)) +#define DEVICE_UNLOCK(_clk) \ + CLKDEV_DEVICE_UNLOCK(clknode_get_device(_clk)) static int clknode_mux_init(struct clknode *clk, device_t dev); static int clknode_mux_set_mux(struct clknode *clk, int idx); @@ -76,9 +80,12 @@ clknode_mux_init(struct clknode *clk, device_t dev) sc = clknode_get_softc(clk); + DEVICE_LOCK(clk); rv = RD4(clk, sc->offset, ®); - if (rv != 0) + DEVICE_UNLOCK(clk); + if (rv != 0) { return (rv); + } reg = (reg >> sc->shift) & sc->mask; clknode_init_parent_idx(clk, reg); return(0); @@ -93,11 +100,16 @@ clknode_mux_set_mux(struct clknode *clk, int idx) sc = clknode_get_softc(clk); + DEVICE_LOCK(clk); rv = MD4(clk, sc->offset, sc->mask << sc->shift, (idx & sc->mask) << sc->shift); - if (rv != 0) + if (rv != 0) { + DEVICE_UNLOCK(clk); return (rv); + } RD4(clk, sc->offset, ®); + DEVICE_UNLOCK(clk); + return(0); } diff --git a/sys/dev/extres/clk/clkdev_if.m b/sys/dev/extres/clk/clkdev_if.m index b43d2058023a..710ee4640d89 100644 --- a/sys/dev/extres/clk/clkdev_if.m +++ b/sys/dev/extres/clk/clkdev_if.m @@ -30,6 +30,23 @@ INTERFACE clkdev; +CODE { + #include + static void + clkdev_default_device_lock(device_t dev) + { + + panic("clkdev_device_lock() is not implemented"); + } + + static void + clkdev_default_device_unlock(device_t dev) + { + + panic("clkdev_device_unlock() is not implemented"); + } +} + # # Write single register # @@ -57,3 +74,17 @@ METHOD int modify_4 { uint32_t clear_mask; uint32_t set_mask; }; + +# +# Get exclusive access to underlying device +# +METHOD void device_lock { + device_t dev; +} DEFAULT clkdev_default_device_lock; + +# +# Release exclusive access to underlying device +# +METHOD void device_unlock { + device_t dev; +} DEFAULT clkdev_default_device_unlock;