Revision 0251d196b0e1a19c870be882e5d4f496de8ab758 authored by Guangbin Huang on 27 October 2021, 12:11:45 UTC, committed by David S. Miller on 27 October 2021, 13:47:33 UTC
Currently, if there is a reset event triggered by RAS during device in
initialization process, driver may run reset process concurrently with
initialization process. In this case, it may cause problem. For example,
the RSS indirection table may has not been alloc memory in initialization
process yet, but it is used in reset process, it will cause a call trace
like this:

[61228.744836] Unable to handle kernel NULL pointer dereference at virtual address 0000000000000000
...
[61228.897677] Workqueue: hclgevf hclgevf_service_task [hclgevf]
[61228.911390] pstate: 40400009 (nZcv daif +PAN -UAO -TCO BTYPE=--)
[61228.918670] pc : hclgevf_set_rss_indir_table+0xb4/0x190 [hclgevf]
[61228.927812] lr : hclgevf_set_rss_indir_table+0x90/0x190 [hclgevf]
[61228.937248] sp : ffff8000162ebb50
[61228.941087] x29: ffff8000162ebb50 x28: ffffb77add72dbc0 x27: ffff0820c7dc8080
[61228.949516] x26: 0000000000000000 x25: ffff0820ad4fc880 x24: ffff0820c7dc8080
[61228.958220] x23: ffff0820c7dc8090 x22: 00000000ffffffff x21: 0000000000000040
[61228.966360] x20: ffffb77add72b9c0 x19: 0000000000000000 x18: 0000000000000030
[61228.974646] x17: 0000000000000000 x16: ffffb77ae713feb0 x15: ffff0820ad4fcce8
[61228.982808] x14: ffffffffffffffff x13: ffff8000962eb7f7 x12: 00003834ec70c960
[61228.991990] x11: 00e0fafa8c206982 x10: 9670facc78a8f9a8 x9 : ffffb77add717530
[61229.001123] x8 : ffff0820ad4fd6b8 x7 : 0000000000000000 x6 : 0000000000000011
[61229.010249] x5 : 00000000000cb1b0 x4 : 0000000000002adb x3 : 0000000000000049
[61229.018662] x2 : ffff8000162ebbb8 x1 : 0000000000000000 x0 : 0000000000000480
[61229.027002] Call trace:
[61229.030177]  hclgevf_set_rss_indir_table+0xb4/0x190 [hclgevf]
[61229.039009]  hclgevf_rss_init_hw+0x128/0x1b4 [hclgevf]
[61229.046809]  hclgevf_reset_rebuild+0x17c/0x69c [hclgevf]
[61229.053862]  hclgevf_reset_service_task+0x4cc/0xa80 [hclgevf]
[61229.061306]  hclgevf_service_task+0x6c/0x630 [hclgevf]
[61229.068491]  process_one_work+0x1dc/0x48c
[61229.074121]  worker_thread+0x15c/0x464
[61229.078562]  kthread+0x168/0x16c
[61229.082873]  ret_from_fork+0x10/0x18
[61229.088221] Code: 7900e7f6 f904a683 d503201f 9101a3e2 (38616b43)
[61229.095357] ---[ end trace 153661a538f6768c ]---

To fix this problem, don't schedule reset task before initialization
process is done.

Signed-off-by: Guangbin Huang <huangguangbin2@huawei.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent f29da40
Raw File
gpio-rda.c
// SPDX-License-Identifier: GPL-2.0-only
/*
 * RDA Micro GPIO driver
 *
 * Copyright (C) 2012 RDA Micro Inc.
 * Copyright (C) 2019 Manivannan Sadhasivam
 */

#include <linux/bitops.h>
#include <linux/gpio/driver.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>

#define RDA_GPIO_OEN_VAL		0x00
#define RDA_GPIO_OEN_SET_OUT		0x04
#define RDA_GPIO_OEN_SET_IN		0x08
#define RDA_GPIO_VAL			0x0c
#define RDA_GPIO_SET			0x10
#define RDA_GPIO_CLR			0x14
#define RDA_GPIO_INT_CTRL_SET		0x18
#define RDA_GPIO_INT_CTRL_CLR		0x1c
#define RDA_GPIO_INT_CLR		0x20
#define RDA_GPIO_INT_STATUS		0x24

#define RDA_GPIO_IRQ_RISE_SHIFT		0
#define RDA_GPIO_IRQ_FALL_SHIFT		8
#define RDA_GPIO_DEBOUCE_SHIFT		16
#define RDA_GPIO_LEVEL_SHIFT		24

#define RDA_GPIO_IRQ_MASK		0xff

/* Each bank consists of 32 GPIOs */
#define RDA_GPIO_BANK_NR	32

struct rda_gpio {
	struct gpio_chip chip;
	void __iomem *base;
	spinlock_t lock;
	struct irq_chip irq_chip;
	int irq;
};

static inline void rda_gpio_update(struct gpio_chip *chip, unsigned int offset,
				   u16 reg, int val)
{
	struct rda_gpio *rda_gpio = gpiochip_get_data(chip);
	void __iomem *base = rda_gpio->base;
	unsigned long flags;
	u32 tmp;

	spin_lock_irqsave(&rda_gpio->lock, flags);
	tmp = readl_relaxed(base + reg);

	if (val)
		tmp |= BIT(offset);
	else
		tmp &= ~BIT(offset);

	writel_relaxed(tmp, base + reg);
	spin_unlock_irqrestore(&rda_gpio->lock, flags);
}

static void rda_gpio_irq_mask(struct irq_data *data)
{
	struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
	struct rda_gpio *rda_gpio = gpiochip_get_data(chip);
	void __iomem *base = rda_gpio->base;
	u32 offset = irqd_to_hwirq(data);
	u32 value;

	value = BIT(offset) << RDA_GPIO_IRQ_RISE_SHIFT;
	value |= BIT(offset) << RDA_GPIO_IRQ_FALL_SHIFT;

	writel_relaxed(value, base + RDA_GPIO_INT_CTRL_CLR);
}

static void rda_gpio_irq_ack(struct irq_data *data)
{
	struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
	u32 offset = irqd_to_hwirq(data);

	rda_gpio_update(chip, offset, RDA_GPIO_INT_CLR, 1);
}

static int rda_gpio_set_irq(struct gpio_chip *chip, u32 offset,
			    unsigned int flow_type)
{
	struct rda_gpio *rda_gpio = gpiochip_get_data(chip);
	void __iomem *base = rda_gpio->base;
	u32 value;

	switch (flow_type) {
	case IRQ_TYPE_EDGE_RISING:
		/* Set rising edge trigger */
		value = BIT(offset) << RDA_GPIO_IRQ_RISE_SHIFT;
		writel_relaxed(value, base + RDA_GPIO_INT_CTRL_SET);

		/* Switch to edge trigger interrupt */
		value = BIT(offset) << RDA_GPIO_LEVEL_SHIFT;
		writel_relaxed(value, base + RDA_GPIO_INT_CTRL_CLR);
		break;

	case IRQ_TYPE_EDGE_FALLING:
		/* Set falling edge trigger */
		value = BIT(offset) << RDA_GPIO_IRQ_FALL_SHIFT;
		writel_relaxed(value, base + RDA_GPIO_INT_CTRL_SET);

		/* Switch to edge trigger interrupt */
		value = BIT(offset) << RDA_GPIO_LEVEL_SHIFT;
		writel_relaxed(value, base + RDA_GPIO_INT_CTRL_CLR);
		break;

	case IRQ_TYPE_EDGE_BOTH:
		/* Set both edge trigger */
		value = BIT(offset) << RDA_GPIO_IRQ_RISE_SHIFT;
		value |= BIT(offset) << RDA_GPIO_IRQ_FALL_SHIFT;
		writel_relaxed(value, base + RDA_GPIO_INT_CTRL_SET);

		/* Switch to edge trigger interrupt */
		value = BIT(offset) << RDA_GPIO_LEVEL_SHIFT;
		writel_relaxed(value, base + RDA_GPIO_INT_CTRL_CLR);
		break;

	case IRQ_TYPE_LEVEL_HIGH:
		/* Set high level trigger */
		value = BIT(offset) << RDA_GPIO_IRQ_RISE_SHIFT;

		/* Switch to level trigger interrupt */
		value |= BIT(offset) << RDA_GPIO_LEVEL_SHIFT;
		writel_relaxed(value, base + RDA_GPIO_INT_CTRL_SET);
		break;

	case IRQ_TYPE_LEVEL_LOW:
		/* Set low level trigger */
		value = BIT(offset) << RDA_GPIO_IRQ_FALL_SHIFT;

		/* Switch to level trigger interrupt */
		value |= BIT(offset) << RDA_GPIO_LEVEL_SHIFT;
		writel_relaxed(value, base + RDA_GPIO_INT_CTRL_SET);
		break;

	default:
		return -EINVAL;
	}

	return 0;
}

static void rda_gpio_irq_unmask(struct irq_data *data)
{
	struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
	u32 offset = irqd_to_hwirq(data);
	u32 trigger = irqd_get_trigger_type(data);

	rda_gpio_set_irq(chip, offset, trigger);
}

static int rda_gpio_irq_set_type(struct irq_data *data, unsigned int flow_type)
{
	struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
	u32 offset = irqd_to_hwirq(data);
	int ret;

	ret = rda_gpio_set_irq(chip, offset, flow_type);
	if (ret)
		return ret;

	if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
		irq_set_handler_locked(data, handle_level_irq);
	else if (flow_type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
		irq_set_handler_locked(data, handle_edge_irq);

	return 0;
}

static void rda_gpio_irq_handler(struct irq_desc *desc)
{
	struct gpio_chip *chip = irq_desc_get_handler_data(desc);
	struct irq_chip *ic = irq_desc_get_chip(desc);
	struct rda_gpio *rda_gpio = gpiochip_get_data(chip);
	unsigned long status;
	u32 n;

	chained_irq_enter(ic, desc);

	status = readl_relaxed(rda_gpio->base + RDA_GPIO_INT_STATUS);
	/* Only lower 8 bits are capable of generating interrupts */
	status &= RDA_GPIO_IRQ_MASK;

	for_each_set_bit(n, &status, RDA_GPIO_BANK_NR)
		generic_handle_domain_irq(chip->irq.domain, n);

	chained_irq_exit(ic, desc);
}

static int rda_gpio_probe(struct platform_device *pdev)
{
	struct device_node *np = pdev->dev.of_node;
	struct device *dev = &pdev->dev;
	struct gpio_irq_chip *girq;
	struct rda_gpio *rda_gpio;
	u32 ngpios;
	int ret;

	rda_gpio = devm_kzalloc(dev, sizeof(*rda_gpio), GFP_KERNEL);
	if (!rda_gpio)
		return -ENOMEM;

	ret = device_property_read_u32(dev, "ngpios", &ngpios);
	if (ret < 0)
		return ret;

	/*
	 * Not all ports have interrupt capability. For instance, on
	 * RDA8810PL, GPIOC doesn't support interrupt. So we must handle
	 * those also.
	 */
	rda_gpio->irq = platform_get_irq(pdev, 0);

	rda_gpio->base = devm_platform_ioremap_resource(pdev, 0);
	if (IS_ERR(rda_gpio->base))
		return PTR_ERR(rda_gpio->base);

	spin_lock_init(&rda_gpio->lock);

	ret = bgpio_init(&rda_gpio->chip, dev, 4,
			 rda_gpio->base + RDA_GPIO_VAL,
			 rda_gpio->base + RDA_GPIO_SET,
			 rda_gpio->base + RDA_GPIO_CLR,
			 rda_gpio->base + RDA_GPIO_OEN_SET_OUT,
			 rda_gpio->base + RDA_GPIO_OEN_SET_IN,
			 BGPIOF_READ_OUTPUT_REG_SET);
	if (ret) {
		dev_err(dev, "bgpio_init failed\n");
		return ret;
	}

	rda_gpio->chip.label = dev_name(dev);
	rda_gpio->chip.ngpio = ngpios;
	rda_gpio->chip.base = -1;
	rda_gpio->chip.parent = dev;
	rda_gpio->chip.of_node = np;

	if (rda_gpio->irq >= 0) {
		rda_gpio->irq_chip.name = "rda-gpio",
		rda_gpio->irq_chip.irq_ack = rda_gpio_irq_ack,
		rda_gpio->irq_chip.irq_mask = rda_gpio_irq_mask,
		rda_gpio->irq_chip.irq_unmask = rda_gpio_irq_unmask,
		rda_gpio->irq_chip.irq_set_type = rda_gpio_irq_set_type,
		rda_gpio->irq_chip.flags = IRQCHIP_SKIP_SET_WAKE,

		girq = &rda_gpio->chip.irq;
		girq->chip = &rda_gpio->irq_chip;
		girq->handler = handle_bad_irq;
		girq->default_type = IRQ_TYPE_NONE;
		girq->parent_handler = rda_gpio_irq_handler;
		girq->parent_handler_data = rda_gpio;
		girq->num_parents = 1;
		girq->parents = devm_kcalloc(dev, 1,
					     sizeof(*girq->parents),
					     GFP_KERNEL);
		if (!girq->parents)
			return -ENOMEM;
		girq->parents[0] = rda_gpio->irq;
	}

	platform_set_drvdata(pdev, rda_gpio);

	return devm_gpiochip_add_data(dev, &rda_gpio->chip, rda_gpio);
}

static const struct of_device_id rda_gpio_of_match[] = {
	{ .compatible = "rda,8810pl-gpio", },
	{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, rda_gpio_of_match);

static struct platform_driver rda_gpio_driver = {
	.probe = rda_gpio_probe,
	.driver = {
		.name = "rda-gpio",
		.of_match_table	= rda_gpio_of_match,
	},
};

module_platform_driver_probe(rda_gpio_driver, rda_gpio_probe);

MODULE_DESCRIPTION("RDA Micro GPIO driver");
MODULE_AUTHOR("Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>");
MODULE_LICENSE("GPL v2");
back to top