From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-pl1-f179.google.com (mail-pl1-f179.google.com [209.85.214.179]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6E10F3A05F2 for ; Mon, 6 Jul 2026 23:22:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.179 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783380147; cv=none; b=RM1hucuzaS4yQaJaFawwqjHcKxyBae6mGlyAo8GkQXyevF7/QneNZ38Q3LMgVOHXgoKq+TbkHHHMheCJyIZ4Uj6ZheIDYQEnqSm3VZ+ITpstgM99hmdXuySdigCndH5HWNGHn1LTrt922aR6qZTZOyVt2tuk7m97fvyp3M+b9Pg= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783380147; c=relaxed/simple; bh=GstWAS9uUqU28IR79vW8q+7sgJRmPJ9gzV2HjjFOIVg=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=OG1vMdHKxIcng0rXYV233op+rHrOKLXvuXwCCq9jnxurkHKgseRZSlCNCW2lH5Q++Sj6IuE0YSYGpvPv2Nc5PrgM7lIGA1EwfxczlA7Mn/5JNnl2OcEwsFqZpRq7+VlHM7xzERNzH0qbRA+hGHKk/jvH/4zjqDs8Pr0Ulj/8geM= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=Z+EMqEdu; arc=none smtp.client-ip=209.85.214.179 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="Z+EMqEdu" Received: by mail-pl1-f179.google.com with SMTP id d9443c01a7336-2cab973140bso43328705ad.3 for ; Mon, 06 Jul 2026 16:22:26 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1783380146; x=1783984946; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to:content-type; bh=HaoGqAArhfyoE1akQuRdmTkHXWVdhEZ6+mjxws6eIpw=; b=Z+EMqEduowmtE4xjoDpyUCM67HjvyO6che7Cn4uZsB70cuI3LQq2tco2is/sJzyQWY HriAuUsB/Bag12IaC97IDarLf7zdhW4X8lDgNNS+docAQGSkGvbVt4neU6MR+dP64ewy DNHTB7J4vYVQbUn/325VcqIwjQKftriJuKIBGPaxjx2iBvFruw7lZ6uhv3a4HK+5Zjk+ /K2S9LXA05qLI7BZxgZ6BapUElEhITrdiuDP1QePYcv7xkLaIgzYE5Ap/Nv02fmBtqbD sIWG771WPAV3UfOSsG3U1E+BG+utocX5eQVz8pYVrkxyqSkliCinGVE8uYw/wXMBVHG4 IMhg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1783380146; x=1783984946; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=HaoGqAArhfyoE1akQuRdmTkHXWVdhEZ6+mjxws6eIpw=; b=dNxAQZQygYvBEboGyI4pIEOHzUMcYaGxmRBKAZXUFXYDP/vtdbEVCSe/Ht6DhqApHb F1ybrNP371RTEilap+ckTZSZHIx605fUoQjrk4vSQ8ixGnnnppyS4hT725irz3YMfysV /YGyOuDTovuknZRh1/MTkYV9BNfjRv3ruqUzu9HoeMgzpaG3npzbvM+9+8a0jZDCb8t0 ugVlcxhpAgRKnWihopela9FZXxe+WXGGEb5eRYDqoeYnTd3En825ic9b+AGjyjB9Fipu 5kF+PRt2HzBuXdaOIjfhwsA/S5j8/ykSmXiQyFW4YRGCDeqcR5IA96IWlTYDeXrVt93h bxPg== X-Forwarded-Encrypted: i=1; AHgh+RrI0lyuyAfIFWBOM9DAuwKCjT0iyPDvl8R7KhO95V4AfTQ2+l1pEKN8WxyWeMM6Mp0I3msUxjF1K+lSCU4=@vger.kernel.org X-Gm-Message-State: AOJu0Yy9VFn+ieZ1x3TJD/MxarWVMyrzgO5LY4HPjUeYzSiAX8amvoBB Y1VyjPGmocWcS5q/hQR9oG2hE7UYuRY6H/Irg2t+4jB2TsTU2irKA8oa X-Gm-Gg: AfdE7cnggCECu7ayyzhlTAmDKXUScb85/bfIRTbx1GtwccjuOiJ+wrcCeIwKoDYwMry RMg52yDUE22jZsZ+N8oaPv9PgDtRFC6i+4CI9HzrNaAtteGVq8gYkkBDf/ISsAA/YSozv971nK9 VjT4juoFNinCiUhdJRLgXmWdz4H79sFuIwkvlZgJezJIZDaCHalwaNfNemlnPtX8NbiPLONrLT7 ca43r1Tf0o2xMccgdiyQzSfGM5GS+q9L+ksYDqtOiGvJHNDaa7FSUcp3Q8I28knwPuy1u8XIA1R olC2amch1OTxAPArM3nDJf36vbnCsuLNBL93AbPO48h2p8KuAItTkd6FFmu1R8M/EYz1oVHNdlS TVc7lIWPyyto3JRsGN7a5k9wSNGhGX2u+o7Q1UiuysjHecmkxryNO64PuLF0Lh77GS+L4J+vWUQ 92ylu/JyMlHeiCHAOSTglo3FfOj/M4igKC6nAIrOpsUMpa/nIJ9ynMARMQX+Z9HUUMJYgB1Jdyy RdNUAvv8w== X-Received: by 2002:a17:903:19ec:b0:2cc:8ad3:423d with SMTP id d9443c01a7336-2ccbf041c8cmr31406515ad.29.1783380145676; Mon, 06 Jul 2026 16:22:25 -0700 (PDT) Received: from ryzen.lan ([2601:644:8000:7a86::e34]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2ccc9d3d474sm1582725ad.70.2026.07.06.16.22.24 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 06 Jul 2026 16:22:25 -0700 (PDT) From: Rosen Penev To: linux-gpio@vger.kernel.org Cc: Linus Walleij , Bartosz Golaszewski , =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= , Andy Shevchenko , linux-kernel@vger.kernel.org (open list) Subject: [PATCHv2] gpio: mvebu: fix devres LIFO ordering between GPIO chip and IRQ domain Date: Mon, 6 Jul 2026 16:22:23 -0700 Message-ID: <20260706232223.774895-1-rosenp@gmail.com> X-Mailer: git-send-email 2.55.0 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit During driver removal, devres cleans up in LIFO order. The IRQ domain was created and its devm cleanup action registered after devm_gpiochip_add_data(), so the domain was destroyed before the GPIO chip was deregistered. If gpiod_to_irq() is called on a pin during this window, mvebu_gpio_to_irq() passes the freed mvchip->domain to irq_create_mapping(). Fix by moving the IRQ domain creation, devm cleanup action registration, generic chip allocation, and chip type setup before devm_gpiochip_add_data(). This ensures the GPIO chip is torn down first (preventing new IRQ mappings), then the IRQ domain is removed, and finally mvchip is freed. Fixes: 644ee70267a9 ("gpio: mvebu: fix irq domain leak") Assisted-by: opencode:big-pickle Signed-off-by: Rosen Penev --- v2: added Fixes tag drivers/gpio/gpio-mvebu.c | 133 +++++++++++++++++++------------------- 1 file changed, 68 insertions(+), 65 deletions(-) diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index 5b4408fcc10b..d8105a05d261 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -1250,6 +1250,59 @@ static int mvebu_gpio_probe(struct platform_device *pdev) BUG(); } + /* Some gpio controllers do not provide irq support */ + if (have_irqs) { + mvchip->domain = irq_domain_create_linear(dev_fwnode(&pdev->dev), + ngpios, + &irq_generic_chip_ops, + NULL); + if (!mvchip->domain) + return dev_err_probe(&pdev->dev, -ENODEV, + "couldn't allocate irq domain %s (DT).\n", + mvchip->chip.label); + + err = devm_add_action_or_reset(&pdev->dev, + mvebu_gpio_remove_irq_domain, + mvchip->domain); + if (err) + return err; + + err = irq_alloc_domain_generic_chips( + mvchip->domain, ngpios, 2, np->name, handle_level_irq, + IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_LEVEL, 0, + IRQ_GC_INIT_NESTED_LOCK); + if (err) + return dev_err_probe(&pdev->dev, err, + "couldn't allocate irq chips %s (DT).\n", + mvchip->chip.label); + + /* + * NOTE: The common accessors cannot be used because of the + * percpu access to the mask registers + */ + gc = irq_get_domain_generic_chip(mvchip->domain, 0); + gc->private = mvchip; + ct = &gc->chip_types[0]; + ct->type = IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW; + ct->chip.irq_mask = mvebu_gpio_level_irq_mask; + ct->chip.irq_unmask = mvebu_gpio_level_irq_unmask; + ct->chip.irq_set_type = mvebu_gpio_irq_set_type; + ct->chip.irq_set_wake = mvebu_gpio_set_wake_irq; + ct->chip.flags = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_MASK_ON_SUSPEND; + ct->chip.name = mvchip->chip.label; + + ct = &gc->chip_types[1]; + ct->type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING; + ct->chip.irq_ack = mvebu_gpio_irq_ack; + ct->chip.irq_mask = mvebu_gpio_edge_irq_mask; + ct->chip.irq_unmask = mvebu_gpio_edge_irq_unmask; + ct->chip.irq_set_type = mvebu_gpio_irq_set_type; + ct->chip.irq_set_wake = mvebu_gpio_set_wake_irq; + ct->chip.flags = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_MASK_ON_SUSPEND; + ct->handler = handle_edge_irq; + ct->chip.name = mvchip->chip.label; + } + err = devm_gpiochip_add_data(&pdev->dev, &mvchip->chip, mvchip); if (err) return dev_err_probe(&pdev->dev, err, @@ -1262,71 +1315,21 @@ static int mvebu_gpio_probe(struct platform_device *pdev) return err; } - /* Some gpio controllers do not provide irq support */ - if (!have_irqs) - return 0; - - mvchip->domain = irq_domain_create_linear(dev_fwnode(&pdev->dev), ngpios, - &irq_generic_chip_ops, NULL); - if (!mvchip->domain) { - dev_err(&pdev->dev, "couldn't allocate irq domain %s (DT).\n", - mvchip->chip.label); - return -ENODEV; - } - - err = devm_add_action_or_reset(&pdev->dev, mvebu_gpio_remove_irq_domain, - mvchip->domain); - if (err) - return err; - - err = irq_alloc_domain_generic_chips( - mvchip->domain, ngpios, 2, np->name, handle_level_irq, - IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_LEVEL, 0, IRQ_GC_INIT_NESTED_LOCK); - if (err) { - dev_err(&pdev->dev, "couldn't allocate irq chips %s (DT).\n", - mvchip->chip.label); - return err; - } - - /* - * NOTE: The common accessors cannot be used because of the percpu - * access to the mask registers - */ - gc = irq_get_domain_generic_chip(mvchip->domain, 0); - gc->private = mvchip; - ct = &gc->chip_types[0]; - ct->type = IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW; - ct->chip.irq_mask = mvebu_gpio_level_irq_mask; - ct->chip.irq_unmask = mvebu_gpio_level_irq_unmask; - ct->chip.irq_set_type = mvebu_gpio_irq_set_type; - ct->chip.irq_set_wake = mvebu_gpio_set_wake_irq; - ct->chip.flags = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_MASK_ON_SUSPEND; - ct->chip.name = mvchip->chip.label; - - ct = &gc->chip_types[1]; - ct->type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING; - ct->chip.irq_ack = mvebu_gpio_irq_ack; - ct->chip.irq_mask = mvebu_gpio_edge_irq_mask; - ct->chip.irq_unmask = mvebu_gpio_edge_irq_unmask; - ct->chip.irq_set_type = mvebu_gpio_irq_set_type; - ct->chip.irq_set_wake = mvebu_gpio_set_wake_irq; - ct->chip.flags = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_MASK_ON_SUSPEND; - ct->handler = handle_edge_irq; - ct->chip.name = mvchip->chip.label; - - /* - * Setup the interrupt handlers. Each chip can have up to 4 - * interrupt handlers, with each handler dealing with 8 GPIO - * pins. - */ - for (i = 0; i < ARRAY_SIZE(mvchip->bank_irq); i++) { - int irq = platform_get_irq_optional(pdev, i); - - if (irq < 0) - continue; - irq_set_chained_handler_and_data(irq, mvebu_gpio_irq_handler, - mvchip); - mvchip->bank_irq[i] = irq; + if (have_irqs) { + /* + * Setup the interrupt handlers. Each chip can have up to 4 + * interrupt handlers, with each handler dealing with 8 GPIO + * pins. + */ + for (i = 0; i < ARRAY_SIZE(mvchip->bank_irq); i++) { + int irq = platform_get_irq_optional(pdev, i); + + if (irq < 0) + continue; + irq_set_chained_handler_and_data(irq, + mvebu_gpio_irq_handler, mvchip); + mvchip->bank_irq[i] = irq; + } } return 0; -- 2.55.0