From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C86833D7D70; Mon, 17 Aug 2026 15:23:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786980184; cv=none; b=Q6PwoDr7OPH/KkhUerzNSkhW0YI6z7JE5a+PNvfMB8d6cqVwXBAo9/V1aPzZ2kGFFBgXTVxvUCN1QaqX8zttdOAOfHnhx7ziWl32VyyuiI+3FA+oAirh8sHlMQbTbiolQMQsq9kBcuzCY9el2tAJrwAE0stOoCVC/pUZ+/seLPM= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786980184; c=relaxed/simple; bh=HsxFl1ph7fYkFw8lWGHyD3rRf+v4ULUJIr45VdNpQ1g=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=JROReQN8ckwupjbPqZRZrFlBbedOzb7+whjBv31Pll4y3KrnNhIyNADCkxMqHByheXkkBNwM4vuL+zJeEoF7fDLhM0qhqgrNsXelkaydvMx0RWjJ2QfzC7pfqy9b3iYmXyDWcD/esMnxK3U21C/vPeyv9YimFYNqJ8WWbTyXgRU= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linuxfoundation.org header.i=@linuxfoundation.org header.b=NPcV7SHb; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linuxfoundation.org header.i=@linuxfoundation.org header.b="NPcV7SHb" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 59DAB1F00A3A; Mon, 17 Aug 2026 15:23:02 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linuxfoundation.org; s=korg; t=1786980182; bh=J5RjhsyZnEO9HAc/TjIO7i/lPk01FUFzhEtPe+Y+L5g=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=NPcV7SHbsUrT8jbaU6Wu80bou/Uem2DNAlyTGSgseAuSLsERTg+3bRhKMtlRg2Jfs WvSg/UfGqRJ0pROC9RmjGl4zyavj9+8ZLv4pU0FzSP8hu1ezdY5o2qku0sZhP7UDhq sIx1HyhvMN1eEMlCvngwR6xwd8EKRTNMU7lINRTk= From: Greg Kroah-Hartman To: stable@vger.kernel.org Cc: Greg Kroah-Hartman , patches@lists.linux.dev, Junjie Cao , Linus Walleij , Bartosz Golaszewski , Sasha Levin Subject: [PATCH 6.1 482/609] gpio: pch: use raw_spinlock_t for the register lock Date: Mon, 17 Aug 2026 15:32:58 +0200 Message-ID: <20260817132600.064181403@linuxfoundation.org> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260817132543.039278408@linuxfoundation.org> References: <20260817132543.039278408@linuxfoundation.org> User-Agent: quilt/0.69 X-stable: review X-Patchwork-Hint: ignore Precedence: bulk X-Mailing-List: patches@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit 6.1-stable review patch. If anyone has any objections, please let me know. ------------------ From: Junjie Cao [ Upstream commit a02b8950d619123da64f69b70fe1dadef217dfe4 ] pch_irq_type() is registered as the irq_chip .irq_set_type callback and takes chip->spinlock with spin_lock_irqsave(). This callback is reached from __setup_irq() -> __irq_set_trigger() -> chip->irq_set_type() while the caller holds desc->lock, a raw_spinlock_t, with hardirqs disabled. That context is not sleepable, but on PREEMPT_RT a regular spinlock_t is an rtmutex-backed sleeping lock, so acquiring it there is invalid. This was confirmed on a PREEMPT_RT kernel with lockdep (PROVE_RAW_LOCK_NESTING and DEBUG_ATOMIC_SLEEP). A grounded PoC mirrored pch_irq_type()'s locking and drove it through the real genirq carrier irq_set_irq_type() -> __irq_set_trigger() -> chip->irq_set_type(), i.e. the same __irq_set_trigger() edge that __setup_irq() takes for a requested IRQ. With the original spin_lock_irqsave() edge lockdep reported an invalid wait context, immediately followed by: BUG: sleeping function called from invalid context at kernel/locking/spinlock_rt.c:48 in_atomic(): 1, irqs_disabled(): 1, non_block: 0, pid: 95, name: insmod hardirqs last disabled at (3784): _raw_spin_lock_irqsave+0x4f/0x60 rt_spin_lock+0x3a/0x1c0 repro_irq_set_type+0x64/0xa0 [pch_repro] __irq_set_trigger+0x69/0x140 irq_set_irq_type+0x78/0xd0 Switching the mirrored lock to raw_spinlock_t made both splats go away. Convert the register lock to raw_spinlock_t. The same lock also serializes the GPIO direction/value callbacks and the suspend/resume register save/restore, but all of those critical sections only perform MMIO register accesses (ioread32()/iowrite32()) and irq_set_handler_locked(); none of them contain sleepable operations. Keeping this register lock non-sleeping is therefore appropriate for the irqchip callbacks and does not change the GPIO-side locking contract. This is the same class of issue and fix as recently addressed for other GPIO controllers, e.g. commit 286533cb14a3 ("gpio: sch: use raw_spinlock_t in the irq startup path") and commit 90f0109019e6 ("gpio: eic-sprd: use raw_spinlock_t in the irq startup path"). Fixes: 38eb18a6f92d ("gpio-pch: Support interrupt function") Cc: stable@vger.kernel.org Signed-off-by: Junjie Cao Reviewed-by: Linus Walleij Link: https://patch.msgid.link/20260723014129.1129730-1-junjie.cao@intel.com Signed-off-by: Bartosz Golaszewski (cherry picked from commit a02b8950d619123da64f69b70fe1dadef217dfe4) Signed-off-by: Sasha Levin --- drivers/gpio/gpio-pch.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/gpio/gpio-pch.c b/drivers/gpio/gpio-pch.c index ee37ecb615cb1..77e84e0e6c1ba 100644 --- a/drivers/gpio/gpio-pch.c +++ b/drivers/gpio/gpio-pch.c @@ -97,7 +97,7 @@ struct pch_gpio { struct pch_gpio_reg_data pch_gpio_reg; int irq_base; enum pch_type_t ioh; - spinlock_t spinlock; + raw_spinlock_t spinlock; }; static void pch_gpio_set(struct gpio_chip *gpio, unsigned int nr, int val) @@ -106,7 +106,7 @@ static void pch_gpio_set(struct gpio_chip *gpio, unsigned int nr, int val) struct pch_gpio *chip = gpiochip_get_data(gpio); unsigned long flags; - spin_lock_irqsave(&chip->spinlock, flags); + raw_spin_lock_irqsave(&chip->spinlock, flags); reg_val = ioread32(&chip->reg->po); if (val) reg_val |= BIT(nr); @@ -114,7 +114,7 @@ static void pch_gpio_set(struct gpio_chip *gpio, unsigned int nr, int val) reg_val &= ~BIT(nr); iowrite32(reg_val, &chip->reg->po); - spin_unlock_irqrestore(&chip->spinlock, flags); + raw_spin_unlock_irqrestore(&chip->spinlock, flags); } static int pch_gpio_get(struct gpio_chip *gpio, unsigned int nr) @@ -132,7 +132,7 @@ static int pch_gpio_direction_output(struct gpio_chip *gpio, unsigned int nr, u32 reg_val; unsigned long flags; - spin_lock_irqsave(&chip->spinlock, flags); + raw_spin_lock_irqsave(&chip->spinlock, flags); reg_val = ioread32(&chip->reg->po); if (val) @@ -146,7 +146,7 @@ static int pch_gpio_direction_output(struct gpio_chip *gpio, unsigned int nr, pm |= BIT(nr); iowrite32(pm, &chip->reg->pm); - spin_unlock_irqrestore(&chip->spinlock, flags); + raw_spin_unlock_irqrestore(&chip->spinlock, flags); return 0; } @@ -157,12 +157,12 @@ static int pch_gpio_direction_input(struct gpio_chip *gpio, unsigned int nr) u32 pm; unsigned long flags; - spin_lock_irqsave(&chip->spinlock, flags); + raw_spin_lock_irqsave(&chip->spinlock, flags); pm = ioread32(&chip->reg->pm); pm &= BIT(gpio_pins[chip->ioh]) - 1; pm &= ~BIT(nr); iowrite32(pm, &chip->reg->pm); - spin_unlock_irqrestore(&chip->spinlock, flags); + raw_spin_unlock_irqrestore(&chip->spinlock, flags); return 0; } @@ -264,7 +264,7 @@ static int pch_irq_type(struct irq_data *d, unsigned int type) return 0; } - spin_lock_irqsave(&chip->spinlock, flags); + raw_spin_lock_irqsave(&chip->spinlock, flags); /* Set interrupt mode */ im = ioread32(im_reg) & ~(PCH_IM_MASK << (im_pos * 4)); @@ -276,7 +276,7 @@ static int pch_irq_type(struct irq_data *d, unsigned int type) else if (type & IRQ_TYPE_EDGE_BOTH) irq_set_handler_locked(d, handle_edge_irq); - spin_unlock_irqrestore(&chip->spinlock, flags); + raw_spin_unlock_irqrestore(&chip->spinlock, flags); return 0; } @@ -373,7 +373,7 @@ static int pch_gpio_probe(struct pci_dev *pdev, chip->ioh = id->driver_data; chip->reg = chip->base; pci_set_drvdata(pdev, chip); - spin_lock_init(&chip->spinlock); + raw_spin_lock_init(&chip->spinlock); pch_gpio_setup(chip); ret = devm_gpiochip_add_data(dev, &chip->gpio, chip); @@ -406,9 +406,9 @@ static int __maybe_unused pch_gpio_suspend(struct device *dev) struct pch_gpio *chip = dev_get_drvdata(dev); unsigned long flags; - spin_lock_irqsave(&chip->spinlock, flags); + raw_spin_lock_irqsave(&chip->spinlock, flags); pch_gpio_save_reg_conf(chip); - spin_unlock_irqrestore(&chip->spinlock, flags); + raw_spin_unlock_irqrestore(&chip->spinlock, flags); return 0; } @@ -418,11 +418,11 @@ static int __maybe_unused pch_gpio_resume(struct device *dev) struct pch_gpio *chip = dev_get_drvdata(dev); unsigned long flags; - spin_lock_irqsave(&chip->spinlock, flags); + raw_spin_lock_irqsave(&chip->spinlock, flags); iowrite32(0x01, &chip->reg->reset); iowrite32(0x00, &chip->reg->reset); pch_gpio_restore_reg_conf(chip); - spin_unlock_irqrestore(&chip->spinlock, flags); + raw_spin_unlock_irqrestore(&chip->spinlock, flags); return 0; } -- 2.53.0