Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 47b03ca9 authored by Julia Cartwright's avatar Julia Cartwright Committed by Linus Walleij
Browse files

pinctrl: qcom: Use raw spinlock variants



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

Reported-by: default avatarBrian Wrenn <dcbrianw@gmail.com>
Tested-by: default avatarBrian Wrenn <dcbrianw@gmail.com>
Signed-off-by: default avatarJulia Cartwright <julia@ni.com>
Acked-by: default avatarBjorn Andersson <bjorn.andersson@linaro.org>
Signed-off-by: default avatarLinus Walleij <linus.walleij@linaro.org>
parent 1f7b8eae
Loading
Loading
Loading
Loading
+24 −24
Original line number Diff line number Diff line
@@ -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);