Re: [PATCH] pinctrl: qcom: Use raw spinlock variants

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Julia and others,

I'm happy to contribute and am grateful for the assistance.  It looks
like we'll be using PREEMPT RT for sometime to come from now onward,
so I may be reaching out for help again in the future.

Best Regards!
-Brian

On Fri, Jan 20, 2017 at 11:13 AM, Julia Cartwright <julia@xxxxxx> wrote:
> The MSM pinctrl driver currently implements an irq_chip for handling
> GPIO interrupts; due to how irq_chip handling is done, it's necessary
> for the irq_chip methods to be invoked from hardirq context, even on a
> a real-time kernel.  Because the spinlock_t type becomes a "sleeping"
> spinlock w/ RT kernels, it is not suitable to be used with irq_chips.
>
> A quick audit of the operations under the lock reveal that they do only
> minimal, bounded work, and are therefore safe to do under a raw
> spinlock.
>
> On real-time kernels, this fixes an OOPs which looks like the following,
> as reported by Brian Wrenn:
>
>     kernel BUG at kernel/locking/rtmutex.c:1014!
>     Internal error: Oops - BUG: 0 [#1] PREEMPT SMP
>     Modules linked in: spidev_irq(O) smsc75xx wcn36xx [last unloaded: spidev]
>     CPU: 0 PID: 1163 Comm: irq/144-mmc0 Tainted: G        W  O    4.4.9-linaro-lt-qcom #1
>     PC is at rt_spin_lock_slowlock+0x80/0x2d8
>     LR is at rt_spin_lock_slowlock+0x68/0x2d8
>     [..]
>   Call trace:
>     rt_spin_lock_slowlock
>     rt_spin_lock
>     msm_gpio_irq_ack
>     handle_edge_irq
>     generic_handle_irq
>     msm_gpio_irq_handler
>     generic_handle_irq
>     __handle_domain_irq
>     gic_handle_irq
>
> Cc: Bjorn Andersson <bjorn.andersson@xxxxxxxxxx>
> Reported-by: Brian Wrenn <dcbrianw@xxxxxxxxx>
> Tested-by: Brian Wrenn <dcbrianw@xxxxxxxxx>
> Signed-off-by: Julia Cartwright <julia@xxxxxx>
> ---
> Thanks for the test, Brian!  I've turned your response into a Tested-by.
>
> Linus-  on quick glance, this is but one of many drivers which suffer
> the same class of problem :(.  I'm wondering if we can do some
> coccinelle magic to check specifically drivers which implement irq_chip
> callbacks and use spin_locks...
>
>    Julia
>
>  drivers/pinctrl/qcom/pinctrl-msm.c | 48 +++++++++++++++++++-------------------
>  1 file changed, 24 insertions(+), 24 deletions(-)
>
> diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c
> index 775c883..f8e9e1c 100644
> --- a/drivers/pinctrl/qcom/pinctrl-msm.c
> +++ b/drivers/pinctrl/qcom/pinctrl-msm.c
> @@ -61,7 +61,7 @@ struct msm_pinctrl {
>         struct notifier_block restart_nb;
>         int irq;
>
> -       spinlock_t lock;
> +       raw_spinlock_t lock;
>
>         DECLARE_BITMAP(dual_edge_irqs, MAX_NR_GPIO);
>         DECLARE_BITMAP(enabled_irqs, MAX_NR_GPIO);
> @@ -153,14 +153,14 @@ static int msm_pinmux_set_mux(struct pinctrl_dev *pctldev,
>         if (WARN_ON(i == g->nfuncs))
>                 return -EINVAL;
>
> -       spin_lock_irqsave(&pctrl->lock, flags);
> +       raw_spin_lock_irqsave(&pctrl->lock, flags);
>
>         val = readl(pctrl->regs + g->ctl_reg);
>         val &= ~mask;
>         val |= i << g->mux_bit;
>         writel(val, pctrl->regs + g->ctl_reg);
>
> -       spin_unlock_irqrestore(&pctrl->lock, flags);
> +       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
>
>         return 0;
>  }
> @@ -323,14 +323,14 @@ static int msm_config_group_set(struct pinctrl_dev *pctldev,
>                         break;
>                 case PIN_CONFIG_OUTPUT:
>                         /* set output value */
> -                       spin_lock_irqsave(&pctrl->lock, flags);
> +                       raw_spin_lock_irqsave(&pctrl->lock, flags);
>                         val = readl(pctrl->regs + g->io_reg);
>                         if (arg)
>                                 val |= BIT(g->out_bit);
>                         else
>                                 val &= ~BIT(g->out_bit);
>                         writel(val, pctrl->regs + g->io_reg);
> -                       spin_unlock_irqrestore(&pctrl->lock, flags);
> +                       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
>
>                         /* enable output */
>                         arg = 1;
> @@ -351,12 +351,12 @@ static int msm_config_group_set(struct pinctrl_dev *pctldev,
>                         return -EINVAL;
>                 }
>
> -               spin_lock_irqsave(&pctrl->lock, flags);
> +               raw_spin_lock_irqsave(&pctrl->lock, flags);
>                 val = readl(pctrl->regs + g->ctl_reg);
>                 val &= ~(mask << bit);
>                 val |= arg << bit;
>                 writel(val, pctrl->regs + g->ctl_reg);
> -               spin_unlock_irqrestore(&pctrl->lock, flags);
> +               raw_spin_unlock_irqrestore(&pctrl->lock, flags);
>         }
>
>         return 0;
> @@ -384,13 +384,13 @@ static int msm_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
>
>         g = &pctrl->soc->groups[offset];
>
> -       spin_lock_irqsave(&pctrl->lock, flags);
> +       raw_spin_lock_irqsave(&pctrl->lock, flags);
>
>         val = readl(pctrl->regs + g->ctl_reg);
>         val &= ~BIT(g->oe_bit);
>         writel(val, pctrl->regs + g->ctl_reg);
>
> -       spin_unlock_irqrestore(&pctrl->lock, flags);
> +       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
>
>         return 0;
>  }
> @@ -404,7 +404,7 @@ static int msm_gpio_direction_output(struct gpio_chip *chip, unsigned offset, in
>
>         g = &pctrl->soc->groups[offset];
>
> -       spin_lock_irqsave(&pctrl->lock, flags);
> +       raw_spin_lock_irqsave(&pctrl->lock, flags);
>
>         val = readl(pctrl->regs + g->io_reg);
>         if (value)
> @@ -417,7 +417,7 @@ static int msm_gpio_direction_output(struct gpio_chip *chip, unsigned offset, in
>         val |= BIT(g->oe_bit);
>         writel(val, pctrl->regs + g->ctl_reg);
>
> -       spin_unlock_irqrestore(&pctrl->lock, flags);
> +       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
>
>         return 0;
>  }
> @@ -443,7 +443,7 @@ static void msm_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
>
>         g = &pctrl->soc->groups[offset];
>
> -       spin_lock_irqsave(&pctrl->lock, flags);
> +       raw_spin_lock_irqsave(&pctrl->lock, flags);
>
>         val = readl(pctrl->regs + g->io_reg);
>         if (value)
> @@ -452,7 +452,7 @@ static void msm_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
>                 val &= ~BIT(g->out_bit);
>         writel(val, pctrl->regs + g->io_reg);
>
> -       spin_unlock_irqrestore(&pctrl->lock, flags);
> +       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
>  }
>
>  #ifdef CONFIG_DEBUG_FS
> @@ -571,7 +571,7 @@ static void msm_gpio_irq_mask(struct irq_data *d)
>
>         g = &pctrl->soc->groups[d->hwirq];
>
> -       spin_lock_irqsave(&pctrl->lock, flags);
> +       raw_spin_lock_irqsave(&pctrl->lock, flags);
>
>         val = readl(pctrl->regs + g->intr_cfg_reg);
>         val &= ~BIT(g->intr_enable_bit);
> @@ -579,7 +579,7 @@ static void msm_gpio_irq_mask(struct irq_data *d)
>
>         clear_bit(d->hwirq, pctrl->enabled_irqs);
>
> -       spin_unlock_irqrestore(&pctrl->lock, flags);
> +       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
>  }
>
>  static void msm_gpio_irq_unmask(struct irq_data *d)
> @@ -592,7 +592,7 @@ static void msm_gpio_irq_unmask(struct irq_data *d)
>
>         g = &pctrl->soc->groups[d->hwirq];
>
> -       spin_lock_irqsave(&pctrl->lock, flags);
> +       raw_spin_lock_irqsave(&pctrl->lock, flags);
>
>         val = readl(pctrl->regs + g->intr_status_reg);
>         val &= ~BIT(g->intr_status_bit);
> @@ -604,7 +604,7 @@ static void msm_gpio_irq_unmask(struct irq_data *d)
>
>         set_bit(d->hwirq, pctrl->enabled_irqs);
>
> -       spin_unlock_irqrestore(&pctrl->lock, flags);
> +       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
>  }
>
>  static void msm_gpio_irq_ack(struct irq_data *d)
> @@ -617,7 +617,7 @@ static void msm_gpio_irq_ack(struct irq_data *d)
>
>         g = &pctrl->soc->groups[d->hwirq];
>
> -       spin_lock_irqsave(&pctrl->lock, flags);
> +       raw_spin_lock_irqsave(&pctrl->lock, flags);
>
>         val = readl(pctrl->regs + g->intr_status_reg);
>         if (g->intr_ack_high)
> @@ -629,7 +629,7 @@ static void msm_gpio_irq_ack(struct irq_data *d)
>         if (test_bit(d->hwirq, pctrl->dual_edge_irqs))
>                 msm_gpio_update_dual_edge_pos(pctrl, g, d);
>
> -       spin_unlock_irqrestore(&pctrl->lock, flags);
> +       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
>  }
>
>  static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type)
> @@ -642,7 +642,7 @@ static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type)
>
>         g = &pctrl->soc->groups[d->hwirq];
>
> -       spin_lock_irqsave(&pctrl->lock, flags);
> +       raw_spin_lock_irqsave(&pctrl->lock, flags);
>
>         /*
>          * For hw without possibility of detecting both edges
> @@ -716,7 +716,7 @@ static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type)
>         if (test_bit(d->hwirq, pctrl->dual_edge_irqs))
>                 msm_gpio_update_dual_edge_pos(pctrl, g, d);
>
> -       spin_unlock_irqrestore(&pctrl->lock, flags);
> +       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
>
>         if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
>                 irq_set_handler_locked(d, handle_level_irq);
> @@ -732,11 +732,11 @@ static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
>         struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
>         unsigned long flags;
>
> -       spin_lock_irqsave(&pctrl->lock, flags);
> +       raw_spin_lock_irqsave(&pctrl->lock, flags);
>
>         irq_set_irq_wake(pctrl->irq, on);
>
> -       spin_unlock_irqrestore(&pctrl->lock, flags);
> +       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
>
>         return 0;
>  }
> @@ -882,7 +882,7 @@ int msm_pinctrl_probe(struct platform_device *pdev,
>         pctrl->soc = soc_data;
>         pctrl->chip = msm_gpio_template;
>
> -       spin_lock_init(&pctrl->lock);
> +       raw_spin_lock_init(&pctrl->lock);
>
>         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>         pctrl->regs = devm_ioremap_resource(&pdev->dev, res);
> --
> 2.10.2
--
To unsubscribe from this list: send the line "unsubscribe linux-soc" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Samsung SoC]     [Linux Rockchip SoC]     [Linux Actions SoC]     [Linux for Synopsys ARC Processors]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]


  Powered by Linux