Message ID | 20220724171057.18549-1-marex@denx.de |
---|---|
State | New |
Headers | show |
Series | [v3,1/2] gpio: mxc: Protect GPIO irqchip RMW with bgpio spinlock | expand |
Where is the cover letter? If sending more than a single patch, please include one. On Sun, 24 Jul 2022 18:10:56 +0100, Marek Vasut <marex@denx.de> wrote: > > The driver currently performs register read-modify-write without locking > in its irqchip part, this could lead to a race condition when configuring > interrupt mode setting. Add the missing bgpio spinlock lock/unlock around > the register read-modify-write. > > Fixes: 07bd1a6cc7cbb ("MXC arch: Add gpio support for the whole platform") > Signed-off-by: Marek Vasut <marex@denx.de> > Cc: Bartosz Golaszewski <bgolaszewski@baylibre.com> > Cc: Linus Walleij <linus.walleij@linaro.org> > Cc: Loic Poulain <loic.poulain@linaro.org> > Cc: Marc Zyngier <maz@kernel.org> > Cc: NXP Linux Team <linux-imx@nxp.com> > Cc: Peng Fan <peng.fan@nxp.com> > Cc: Shawn Guo <shawnguo@kernel.org> > --- > V3: New patch > --- > drivers/gpio/gpio-mxc.c | 10 ++++++++++ > 1 file changed, 10 insertions(+) > > diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c > index c871602fc5ba9..74a50139c9202 100644 > --- a/drivers/gpio/gpio-mxc.c > +++ b/drivers/gpio/gpio-mxc.c > @@ -147,6 +147,7 @@ static int gpio_set_irq_type(struct irq_data *d, u32 type) > { > struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); > struct mxc_gpio_port *port = gc->private; > + unsigned long flags; > u32 bit, val; > u32 gpio_idx = d->hwirq; > int edge; > @@ -185,6 +186,8 @@ static int gpio_set_irq_type(struct irq_data *d, u32 type) > return -EINVAL; > } > > + spin_lock_irqsave(&port->gc.bgpio_lock, flags); In my tree, bgpio is a raw spinlock, and has been since 3c938cc5cebcb. Now, looking a bit closer at this code, I have to withdraw my earlier comment about the lack of mutual exclusion in the existing code. All writes are of the form: writel(single_bit_mask, some_addr + MXS_{SET,CLR}); which indicates that the write side can be accessed with a hot-bit pattern, avoiding a RWM pattern and thus the need for a lock. Your second patch, however requires the lock. I'm not sure it is safe to do after the interrupt type has been configured though. You may want to refer to the TRM for this. M.
On 7/24/22 19:50, Marc Zyngier wrote: [...] >> +++ b/drivers/gpio/gpio-mxc.c >> @@ -147,6 +147,7 @@ static int gpio_set_irq_type(struct irq_data *d, u32 type) >> { >> struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); >> struct mxc_gpio_port *port = gc->private; >> + unsigned long flags; >> u32 bit, val; >> u32 gpio_idx = d->hwirq; >> int edge; >> @@ -185,6 +186,8 @@ static int gpio_set_irq_type(struct irq_data *d, u32 type) >> return -EINVAL; >> } >> >> + spin_lock_irqsave(&port->gc.bgpio_lock, flags); > > In my tree, bgpio is a raw spinlock, and has been since 3c938cc5cebcb. > > Now, looking a bit closer at this code, I have to withdraw my earlier > comment about the lack of mutual exclusion in the existing code. All > writes are of the form: > > writel(single_bit_mask, some_addr + MXS_{SET,CLR}); > > which indicates that the write side can be accessed with a hot-bit > pattern, avoiding a RWM pattern and thus the need for a lock. Only for the ISR/IMR, not for the GDIR register, that's why the locks are added only around the RMW which don't have these "hot bits". > Your second patch, however requires the lock. I'm not sure it is safe > to do after the interrupt type has been configured though. You may > want to refer to the TRM for this. There is in fact another unprotected RMW in gpio_set_irq_type() , look for GPIO_EDGE_SEL, so the locks should be valid as they are now, right ?
Hi Marek, I love your patch! Yet something to improve: [auto build test ERROR on brgl/gpio/for-next] [also build test ERROR on linus/master v5.19-rc7 next-20220722] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/Marek-Vasut/gpio-mxc-Protect-GPIO-irqchip-RMW-with-bgpio-spinlock/20220725-011230 base: https://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux.git gpio/for-next config: hexagon-randconfig-r041-20220724 (https://download.01.org/0day-ci/archive/20220725/202207250224.XFYIB7dF-lkp@intel.com/config) compiler: clang version 15.0.0 (https://github.com/llvm/llvm-project 12fbd2d377e396ad61bce56d71c98a1eb1bebfa9) reproduce (this is a W=1 build): wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # https://github.com/intel-lab-lkp/linux/commit/af6c815e16849c7ec370f755916d06a6b1e5b759 git remote add linux-review https://github.com/intel-lab-lkp/linux git fetch --no-tags linux-review Marek-Vasut/gpio-mxc-Protect-GPIO-irqchip-RMW-with-bgpio-spinlock/20220725-011230 git checkout af6c815e16849c7ec370f755916d06a6b1e5b759 # save the config file mkdir build_dir && cp config build_dir/.config COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=hexagon SHELL=/bin/bash drivers/gpio/ If you fix the issue, kindly add following tag where applicable Reported-by: kernel test robot <lkp@intel.com> All errors (new ones prefixed by >>): >> drivers/gpio/gpio-mxc.c:189:20: error: incompatible pointer types passing 'raw_spinlock_t *' (aka 'struct raw_spinlock *') to parameter of type 'spinlock_t *' (aka 'struct spinlock *') [-Werror,-Wincompatible-pointer-types] spin_lock_irqsave(&port->gc.bgpio_lock, flags); ^~~~~~~~~~~~~~~~~~~~ include/linux/spinlock.h:379:39: note: expanded from macro 'spin_lock_irqsave' raw_spin_lock_irqsave(spinlock_check(lock), flags); \ ^~~~ include/linux/spinlock.h:264:26: note: expanded from macro 'raw_spin_lock_irqsave' _raw_spin_lock_irqsave(lock, flags); \ ^~~~ include/linux/spinlock_api_up.h:69:60: note: expanded from macro '_raw_spin_lock_irqsave' #define _raw_spin_lock_irqsave(lock, flags) __LOCK_IRQSAVE(lock, flags) ^~~~ include/linux/spinlock_api_up.h:40:38: note: expanded from macro '__LOCK_IRQSAVE' do { local_irq_save(flags); __LOCK(lock); } while (0) ^~~~ include/linux/spinlock_api_up.h:31:35: note: expanded from macro '__LOCK' do { preempt_disable(); ___LOCK(lock); } while (0) ^~~~ include/linux/spinlock_api_up.h:28:32: note: expanded from macro '___LOCK' do { __acquire(lock); (void)(lock); } while (0) ^~~~ include/linux/spinlock.h:322:67: note: passing argument to parameter 'lock' here static __always_inline raw_spinlock_t *spinlock_check(spinlock_t *lock) ^ drivers/gpio/gpio-mxc.c:210:25: error: incompatible pointer types passing 'raw_spinlock_t *' (aka 'struct raw_spinlock *') to parameter of type 'spinlock_t *' (aka 'struct spinlock *') [-Werror,-Wincompatible-pointer-types] spin_unlock_irqrestore(&port->gc.bgpio_lock, flags); ^~~~~~~~~~~~~~~~~~~~ include/linux/spinlock.h:402:64: note: passing argument to parameter 'lock' here static __always_inline void spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags) ^ drivers/gpio/gpio-mxc.c:222:20: error: incompatible pointer types passing 'raw_spinlock_t *' (aka 'struct raw_spinlock *') to parameter of type 'spinlock_t *' (aka 'struct spinlock *') [-Werror,-Wincompatible-pointer-types] spin_lock_irqsave(&port->gc.bgpio_lock, flags); ^~~~~~~~~~~~~~~~~~~~ include/linux/spinlock.h:379:39: note: expanded from macro 'spin_lock_irqsave' raw_spin_lock_irqsave(spinlock_check(lock), flags); \ ^~~~ include/linux/spinlock.h:264:26: note: expanded from macro 'raw_spin_lock_irqsave' _raw_spin_lock_irqsave(lock, flags); \ ^~~~ include/linux/spinlock_api_up.h:69:60: note: expanded from macro '_raw_spin_lock_irqsave' #define _raw_spin_lock_irqsave(lock, flags) __LOCK_IRQSAVE(lock, flags) ^~~~ include/linux/spinlock_api_up.h:40:38: note: expanded from macro '__LOCK_IRQSAVE' do { local_irq_save(flags); __LOCK(lock); } while (0) ^~~~ include/linux/spinlock_api_up.h:31:35: note: expanded from macro '__LOCK' do { preempt_disable(); ___LOCK(lock); } while (0) ^~~~ include/linux/spinlock_api_up.h:28:32: note: expanded from macro '___LOCK' do { __acquire(lock); (void)(lock); } while (0) ^~~~ include/linux/spinlock.h:322:67: note: passing argument to parameter 'lock' here static __always_inline raw_spinlock_t *spinlock_check(spinlock_t *lock) ^ drivers/gpio/gpio-mxc.c:242:25: error: incompatible pointer types passing 'raw_spinlock_t *' (aka 'struct raw_spinlock *') to parameter of type 'spinlock_t *' (aka 'struct spinlock *') [-Werror,-Wincompatible-pointer-types] spin_unlock_irqrestore(&port->gc.bgpio_lock, flags); ^~~~~~~~~~~~~~~~~~~~ include/linux/spinlock.h:402:64: note: passing argument to parameter 'lock' here static __always_inline void spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags) ^ 4 errors generated. vim +189 drivers/gpio/gpio-mxc.c 145 146 static int gpio_set_irq_type(struct irq_data *d, u32 type) 147 { 148 struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); 149 struct mxc_gpio_port *port = gc->private; 150 unsigned long flags; 151 u32 bit, val; 152 u32 gpio_idx = d->hwirq; 153 int edge; 154 void __iomem *reg = port->base; 155 156 port->both_edges &= ~(1 << gpio_idx); 157 switch (type) { 158 case IRQ_TYPE_EDGE_RISING: 159 edge = GPIO_INT_RISE_EDGE; 160 break; 161 case IRQ_TYPE_EDGE_FALLING: 162 edge = GPIO_INT_FALL_EDGE; 163 break; 164 case IRQ_TYPE_EDGE_BOTH: 165 if (GPIO_EDGE_SEL >= 0) { 166 edge = GPIO_INT_BOTH_EDGES; 167 } else { 168 val = port->gc.get(&port->gc, gpio_idx); 169 if (val) { 170 edge = GPIO_INT_LOW_LEV; 171 pr_debug("mxc: set GPIO %d to low trigger\n", gpio_idx); 172 } else { 173 edge = GPIO_INT_HIGH_LEV; 174 pr_debug("mxc: set GPIO %d to high trigger\n", gpio_idx); 175 } 176 port->both_edges |= 1 << gpio_idx; 177 } 178 break; 179 case IRQ_TYPE_LEVEL_LOW: 180 edge = GPIO_INT_LOW_LEV; 181 break; 182 case IRQ_TYPE_LEVEL_HIGH: 183 edge = GPIO_INT_HIGH_LEV; 184 break; 185 default: 186 return -EINVAL; 187 } 188 > 189 spin_lock_irqsave(&port->gc.bgpio_lock, flags); 190 191 if (GPIO_EDGE_SEL >= 0) { 192 val = readl(port->base + GPIO_EDGE_SEL); 193 if (edge == GPIO_INT_BOTH_EDGES) 194 writel(val | (1 << gpio_idx), 195 port->base + GPIO_EDGE_SEL); 196 else 197 writel(val & ~(1 << gpio_idx), 198 port->base + GPIO_EDGE_SEL); 199 } 200 201 if (edge != GPIO_INT_BOTH_EDGES) { 202 reg += GPIO_ICR1 + ((gpio_idx & 0x10) >> 2); /* lower or upper register */ 203 bit = gpio_idx & 0xf; 204 val = readl(reg) & ~(0x3 << (bit << 1)); 205 writel(val | (edge << (bit << 1)), reg); 206 } 207 208 writel(1 << gpio_idx, port->base + GPIO_ISR); 209 210 spin_unlock_irqrestore(&port->gc.bgpio_lock, flags); 211 212 return 0; 213 } 214
Hi Marek, I love your patch! Yet something to improve: [auto build test ERROR on brgl/gpio/for-next] [also build test ERROR on linus/master v5.19-rc7 next-20220722] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/Marek-Vasut/gpio-mxc-Protect-GPIO-irqchip-RMW-with-bgpio-spinlock/20220725-011230 base: https://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux.git gpio/for-next config: openrisc-buildonly-randconfig-r005-20220724 (https://download.01.org/0day-ci/archive/20220725/202207250224.0POKsKcZ-lkp@intel.com/config) compiler: or1k-linux-gcc (GCC) 12.1.0 reproduce (this is a W=1 build): wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # https://github.com/intel-lab-lkp/linux/commit/af6c815e16849c7ec370f755916d06a6b1e5b759 git remote add linux-review https://github.com/intel-lab-lkp/linux git fetch --no-tags linux-review Marek-Vasut/gpio-mxc-Protect-GPIO-irqchip-RMW-with-bgpio-spinlock/20220725-011230 git checkout af6c815e16849c7ec370f755916d06a6b1e5b759 # save the config file mkdir build_dir && cp config build_dir/.config COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=openrisc SHELL=/bin/bash drivers/gpio/ If you fix the issue, kindly add following tag where applicable Reported-by: kernel test robot <lkp@intel.com> All errors (new ones prefixed by >>): In file included from include/linux/rwsem.h:15, from include/linux/notifier.h:15, from include/linux/clk.h:14, from drivers/gpio/gpio-mxc.c:10: drivers/gpio/gpio-mxc.c: In function 'gpio_set_irq_type': >> drivers/gpio/gpio-mxc.c:189:27: error: passing argument 1 of 'spinlock_check' from incompatible pointer type [-Werror=incompatible-pointer-types] 189 | spin_lock_irqsave(&port->gc.bgpio_lock, flags); | ^~~~~~~~~~~~~~~~~~~~ | | | raw_spinlock_t * {aka struct raw_spinlock *} include/linux/spinlock.h:242:48: note: in definition of macro 'raw_spin_lock_irqsave' 242 | flags = _raw_spin_lock_irqsave(lock); \ | ^~~~ drivers/gpio/gpio-mxc.c:189:9: note: in expansion of macro 'spin_lock_irqsave' 189 | spin_lock_irqsave(&port->gc.bgpio_lock, flags); | ^~~~~~~~~~~~~~~~~ include/linux/spinlock.h:322:67: note: expected 'spinlock_t *' {aka 'struct spinlock *'} but argument is of type 'raw_spinlock_t *' {aka 'struct raw_spinlock *'} 322 | static __always_inline raw_spinlock_t *spinlock_check(spinlock_t *lock) | ~~~~~~~~~~~~^~~~ >> drivers/gpio/gpio-mxc.c:210:32: error: passing argument 1 of 'spin_unlock_irqrestore' from incompatible pointer type [-Werror=incompatible-pointer-types] 210 | spin_unlock_irqrestore(&port->gc.bgpio_lock, flags); | ^~~~~~~~~~~~~~~~~~~~ | | | raw_spinlock_t * {aka struct raw_spinlock *} include/linux/spinlock.h:402:64: note: expected 'spinlock_t *' {aka 'struct spinlock *'} but argument is of type 'raw_spinlock_t *' {aka 'struct raw_spinlock *'} 402 | static __always_inline void spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags) | ~~~~~~~~~~~~^~~~ drivers/gpio/gpio-mxc.c: In function 'mxc_flip_edge': drivers/gpio/gpio-mxc.c:222:27: error: passing argument 1 of 'spinlock_check' from incompatible pointer type [-Werror=incompatible-pointer-types] 222 | spin_lock_irqsave(&port->gc.bgpio_lock, flags); | ^~~~~~~~~~~~~~~~~~~~ | | | raw_spinlock_t * {aka struct raw_spinlock *} include/linux/spinlock.h:242:48: note: in definition of macro 'raw_spin_lock_irqsave' 242 | flags = _raw_spin_lock_irqsave(lock); \ | ^~~~ drivers/gpio/gpio-mxc.c:222:9: note: in expansion of macro 'spin_lock_irqsave' 222 | spin_lock_irqsave(&port->gc.bgpio_lock, flags); | ^~~~~~~~~~~~~~~~~ include/linux/spinlock.h:322:67: note: expected 'spinlock_t *' {aka 'struct spinlock *'} but argument is of type 'raw_spinlock_t *' {aka 'struct raw_spinlock *'} 322 | static __always_inline raw_spinlock_t *spinlock_check(spinlock_t *lock) | ~~~~~~~~~~~~^~~~ drivers/gpio/gpio-mxc.c:242:32: error: passing argument 1 of 'spin_unlock_irqrestore' from incompatible pointer type [-Werror=incompatible-pointer-types] 242 | spin_unlock_irqrestore(&port->gc.bgpio_lock, flags); | ^~~~~~~~~~~~~~~~~~~~ | | | raw_spinlock_t * {aka struct raw_spinlock *} include/linux/spinlock.h:402:64: note: expected 'spinlock_t *' {aka 'struct spinlock *'} but argument is of type 'raw_spinlock_t *' {aka 'struct raw_spinlock *'} 402 | static __always_inline void spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags) | ~~~~~~~~~~~~^~~~ cc1: some warnings being treated as errors vim +/spinlock_check +189 drivers/gpio/gpio-mxc.c 145 146 static int gpio_set_irq_type(struct irq_data *d, u32 type) 147 { 148 struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); 149 struct mxc_gpio_port *port = gc->private; 150 unsigned long flags; 151 u32 bit, val; 152 u32 gpio_idx = d->hwirq; 153 int edge; 154 void __iomem *reg = port->base; 155 156 port->both_edges &= ~(1 << gpio_idx); 157 switch (type) { 158 case IRQ_TYPE_EDGE_RISING: 159 edge = GPIO_INT_RISE_EDGE; 160 break; 161 case IRQ_TYPE_EDGE_FALLING: 162 edge = GPIO_INT_FALL_EDGE; 163 break; 164 case IRQ_TYPE_EDGE_BOTH: 165 if (GPIO_EDGE_SEL >= 0) { 166 edge = GPIO_INT_BOTH_EDGES; 167 } else { 168 val = port->gc.get(&port->gc, gpio_idx); 169 if (val) { 170 edge = GPIO_INT_LOW_LEV; 171 pr_debug("mxc: set GPIO %d to low trigger\n", gpio_idx); 172 } else { 173 edge = GPIO_INT_HIGH_LEV; 174 pr_debug("mxc: set GPIO %d to high trigger\n", gpio_idx); 175 } 176 port->both_edges |= 1 << gpio_idx; 177 } 178 break; 179 case IRQ_TYPE_LEVEL_LOW: 180 edge = GPIO_INT_LOW_LEV; 181 break; 182 case IRQ_TYPE_LEVEL_HIGH: 183 edge = GPIO_INT_HIGH_LEV; 184 break; 185 default: 186 return -EINVAL; 187 } 188 > 189 spin_lock_irqsave(&port->gc.bgpio_lock, flags); 190 191 if (GPIO_EDGE_SEL >= 0) { 192 val = readl(port->base + GPIO_EDGE_SEL); 193 if (edge == GPIO_INT_BOTH_EDGES) 194 writel(val | (1 << gpio_idx), 195 port->base + GPIO_EDGE_SEL); 196 else 197 writel(val & ~(1 << gpio_idx), 198 port->base + GPIO_EDGE_SEL); 199 } 200 201 if (edge != GPIO_INT_BOTH_EDGES) { 202 reg += GPIO_ICR1 + ((gpio_idx & 0x10) >> 2); /* lower or upper register */ 203 bit = gpio_idx & 0xf; 204 val = readl(reg) & ~(0x3 << (bit << 1)); 205 writel(val | (edge << (bit << 1)), reg); 206 } 207 208 writel(1 << gpio_idx, port->base + GPIO_ISR); 209 > 210 spin_unlock_irqrestore(&port->gc.bgpio_lock, flags); 211 212 return 0; 213 } 214
On Sun, 24 Jul 2022 19:15:26 +0100, Marek Vasut <marex@denx.de> wrote: > > On 7/24/22 19:50, Marc Zyngier wrote: > > [...] > > >> +++ b/drivers/gpio/gpio-mxc.c > >> @@ -147,6 +147,7 @@ static int gpio_set_irq_type(struct irq_data *d, u32 type) > >> { > >> struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); > >> struct mxc_gpio_port *port = gc->private; > >> + unsigned long flags; > >> u32 bit, val; > >> u32 gpio_idx = d->hwirq; > >> int edge; > >> @@ -185,6 +186,8 @@ static int gpio_set_irq_type(struct irq_data *d, u32 type) > >> return -EINVAL; > >> } > >> + spin_lock_irqsave(&port->gc.bgpio_lock, flags); > > > > In my tree, bgpio is a raw spinlock, and has been since 3c938cc5cebcb. > > > > Now, looking a bit closer at this code, I have to withdraw my earlier > > comment about the lack of mutual exclusion in the existing code. All > > writes are of the form: > > > > writel(single_bit_mask, some_addr + MXS_{SET,CLR}); > > > > which indicates that the write side can be accessed with a hot-bit > > pattern, avoiding a RWM pattern and thus the need for a lock. > > Only for the ISR/IMR, not for the GDIR register, that's why the locks > are added only around the RMW which don't have these "hot bits". Only your patch adds any GDIR access. > > Your second patch, however requires the lock. I'm not sure it is safe > > to do after the interrupt type has been configured though. You may > > want to refer to the TRM for this. > > There is in fact another unprotected RMW in gpio_set_irq_type() , look > for GPIO_EDGE_SEL, so the locks should be valid as they are now, right > ? I seem to be confused with gpio-mxs.c, and gpio-mxc indeed needs the lock. However, you have totally ignored my earlier comments in your v4: - This doesn't compile, as bgpio_lock has been changed to a *raw* spinlock. You obviously haven't even bothered testing your patch. - I asked for a cover letter for any series with multiple patch. That's not exactly a new requirement. So we got 4 versions in just over 24 hours, none of which actually work. Do you see the overarching problem? M.
On 7/25/22 08:53, Marc Zyngier wrote: > On Sun, 24 Jul 2022 19:15:26 +0100, > Marek Vasut <marex@denx.de> wrote: >> >> On 7/24/22 19:50, Marc Zyngier wrote: >> >> [...] >> >>>> +++ b/drivers/gpio/gpio-mxc.c >>>> @@ -147,6 +147,7 @@ static int gpio_set_irq_type(struct irq_data *d, u32 type) >>>> { >>>> struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); >>>> struct mxc_gpio_port *port = gc->private; >>>> + unsigned long flags; >>>> u32 bit, val; >>>> u32 gpio_idx = d->hwirq; >>>> int edge; >>>> @@ -185,6 +186,8 @@ static int gpio_set_irq_type(struct irq_data *d, u32 type) >>>> return -EINVAL; >>>> } >>>> + spin_lock_irqsave(&port->gc.bgpio_lock, flags); >>> >>> In my tree, bgpio is a raw spinlock, and has been since 3c938cc5cebcb. >>> >>> Now, looking a bit closer at this code, I have to withdraw my earlier >>> comment about the lack of mutual exclusion in the existing code. All >>> writes are of the form: >>> >>> writel(single_bit_mask, some_addr + MXS_{SET,CLR}); >>> >>> which indicates that the write side can be accessed with a hot-bit >>> pattern, avoiding a RWM pattern and thus the need for a lock. >> >> Only for the ISR/IMR, not for the GDIR register, that's why the locks >> are added only around the RMW which don't have these "hot bits". > > Only your patch adds any GDIR access. > >>> Your second patch, however requires the lock. I'm not sure it is safe >>> to do after the interrupt type has been configured though. You may >>> want to refer to the TRM for this. >> >> There is in fact another unprotected RMW in gpio_set_irq_type() , look >> for GPIO_EDGE_SEL, so the locks should be valid as they are now, right >> ? > > I seem to be confused with gpio-mxs.c, and gpio-mxc indeed needs the > lock. > > However, you have totally ignored my earlier comments in your v4: > > - This doesn't compile, as bgpio_lock has been changed to a *raw* > spinlock. You obviously haven't even bothered testing your patch. Yes indeed, I tested every single one on 5.18.y . I noticed the raw spinlock change is only in next. > - I asked for a cover letter for any series with multiple patch. > That's not exactly a new requirement. > > So we got 4 versions in just over 24 hours, none of which actually > work. Do you see the overarching problem? Lemme rebase this on next and send v5.
On Mon, 25 Jul 2022 10:57:32 +0100, Marek Vasut <marex@denx.de> wrote: > > On 7/25/22 08:53, Marc Zyngier wrote: > > However, you have totally ignored my earlier comments in your v4: > > > > - This doesn't compile, as bgpio_lock has been changed to a *raw* > > spinlock. You obviously haven't even bothered testing your patch. > > Yes indeed, I tested every single one on 5.18.y . I noticed the raw > spinlock change is only in next. $ git describe --contains 3c938cc5cebcb --match=v* v5.19-rc1~134^2~25 Only in -next? Not quite. > > > - I asked for a cover letter for any series with multiple patch. > > That's not exactly a new requirement. > > > > So we got 4 versions in just over 24 hours, none of which actually > > work. Do you see the overarching problem? > > Lemme rebase this on next and send v5. Rebasing on -rc1 is the right thing to do. You should never base something on -next, as this is a moving target. M.
diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c index c871602fc5ba9..74a50139c9202 100644 --- a/drivers/gpio/gpio-mxc.c +++ b/drivers/gpio/gpio-mxc.c @@ -147,6 +147,7 @@ static int gpio_set_irq_type(struct irq_data *d, u32 type) { struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); struct mxc_gpio_port *port = gc->private; + unsigned long flags; u32 bit, val; u32 gpio_idx = d->hwirq; int edge; @@ -185,6 +186,8 @@ static int gpio_set_irq_type(struct irq_data *d, u32 type) return -EINVAL; } + spin_lock_irqsave(&port->gc.bgpio_lock, flags); + if (GPIO_EDGE_SEL >= 0) { val = readl(port->base + GPIO_EDGE_SEL); if (edge == GPIO_INT_BOTH_EDGES) @@ -204,15 +207,20 @@ static int gpio_set_irq_type(struct irq_data *d, u32 type) writel(1 << gpio_idx, port->base + GPIO_ISR); + spin_unlock_irqrestore(&port->gc.bgpio_lock, flags); + return 0; } static void mxc_flip_edge(struct mxc_gpio_port *port, u32 gpio) { void __iomem *reg = port->base; + unsigned long flags; u32 bit, val; int edge; + spin_lock_irqsave(&port->gc.bgpio_lock, flags); + reg += GPIO_ICR1 + ((gpio & 0x10) >> 2); /* lower or upper register */ bit = gpio & 0xf; val = readl(reg); @@ -230,6 +238,8 @@ static void mxc_flip_edge(struct mxc_gpio_port *port, u32 gpio) return; } writel(val | (edge << (bit << 1)), reg); + + spin_unlock_irqrestore(&port->gc.bgpio_lock, flags); } /* handle 32 interrupts in one status register */
The driver currently performs register read-modify-write without locking in its irqchip part, this could lead to a race condition when configuring interrupt mode setting. Add the missing bgpio spinlock lock/unlock around the register read-modify-write. Fixes: 07bd1a6cc7cbb ("MXC arch: Add gpio support for the whole platform") Signed-off-by: Marek Vasut <marex@denx.de> Cc: Bartosz Golaszewski <bgolaszewski@baylibre.com> Cc: Linus Walleij <linus.walleij@linaro.org> Cc: Loic Poulain <loic.poulain@linaro.org> Cc: Marc Zyngier <maz@kernel.org> Cc: NXP Linux Team <linux-imx@nxp.com> Cc: Peng Fan <peng.fan@nxp.com> Cc: Shawn Guo <shawnguo@kernel.org> --- V3: New patch --- drivers/gpio/gpio-mxc.c | 10 ++++++++++ 1 file changed, 10 insertions(+)