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 8C89233DEF7; Fri, 7 Aug 2026 14:55:17 +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=1786114522; cv=none; b=irDKymrQ/FJUZdFiJ2iWWDnEyFC2f8MnVEO+NH+/9ehziGUuo6kWfIPTKHpPeXO9I128vZil9zilQ4cyvT+/qkO0GYsDzVatNW1Cx0Gy0bTYgVhI5LYlhhCHmG4uoyYtq6XS3C0RCmJYTyHpAJEVVv1hTr88QA514H+Rc6ETjLc= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786114522; c=relaxed/simple; bh=T3/hiHpz1qZ9uVAWFa4zdLsBgVAyJOV4uO4HG6TNmJE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=eZ3aMNIGlV9SSEXIJkPzQjG9IOZ2bo4q9jj/uYO/vlYyBLy9dIBteEkQe6bKooYj3mqqHpwd5YyNTqJd5Jtv18U49FDsVvJk/6/qgpEuIYAJZhZ/ZBgFUpJ5W+oR2YzQUSFlowe8HUJkzfykt78TWTJpr/qn/K1wCqVIivMrFoE= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linuxfoundation.org header.i=@linuxfoundation.org header.b=u3hLs2bB; 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="u3hLs2bB" Received: by smtp.kernel.org (Postfix) with ESMTPSA id AE6461F00A3D; Fri, 7 Aug 2026 14:55:12 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linuxfoundation.org; s=korg; t=1786114513; bh=k851tAI2+QLTJZfanOud2SjV0krEVXKuDGXRk2VVLUk=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=u3hLs2bBIj+mMhenYn2FXemIqhceVBrmqnJMLH+6B8q+ayGfWM7vex9V5ZENQ2cXm w+DSrajFxBhXCA0hDxDGp12aOE4/q3QySfSh1WZ2lMFZZ3ej8Zxo7UfI4Gvc1xUSUq j9/dT8/CHY3YcXHgRjgeQVNKBoFnDCmOzjkabk7E= 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.12 290/337] gpio: pch: use raw_spinlock_t for the register lock Date: Fri, 7 Aug 2026 16:38:13 +0200 Message-ID: <20260807143424.818543599@linuxfoundation.org> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260807143418.516897842@linuxfoundation.org> References: <20260807143418.516897842@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.12-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(-) --- a/drivers/gpio/gpio-pch.c +++ b/drivers/gpio/gpio-pch.c @@ -96,7 +96,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) @@ -105,7 +105,7 @@ static void pch_gpio_set(struct gpio_chi 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); @@ -113,7 +113,7 @@ static void pch_gpio_set(struct gpio_chi 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) @@ -131,7 +131,7 @@ static int pch_gpio_direction_output(str 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) @@ -145,7 +145,7 @@ static int pch_gpio_direction_output(str pm |= BIT(nr); iowrite32(pm, &chip->reg->pm); - spin_unlock_irqrestore(&chip->spinlock, flags); + raw_spin_unlock_irqrestore(&chip->spinlock, flags); return 0; } @@ -156,12 +156,12 @@ static int pch_gpio_direction_input(stru 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; } @@ -263,7 +263,7 @@ static int pch_irq_type(struct irq_data 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)); @@ -275,7 +275,7 @@ static int pch_irq_type(struct irq_data 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; } @@ -372,7 +372,7 @@ static int pch_gpio_probe(struct pci_dev 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); @@ -405,9 +405,9 @@ static int __maybe_unused pch_gpio_suspe 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; } @@ -417,11 +417,11 @@ static int __maybe_unused pch_gpio_resum 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; }