Skip to content

Commit

Permalink
phy: renesas: rcar-gen3-usb2: Move IRQ request in probe
Browse files Browse the repository at this point in the history
Commit 08b0ad3 ("phy: renesas: rcar-gen3-usb2: move IRQ registration
to init") moved the IRQ request operation from probe to
struct phy_ops::phy_init API to avoid triggering interrupts (which lead to
register accesses) while the PHY clocks (enabled through runtime PM APIs)
are not active. If this happens, it results in a synchronous abort.

One way to reproduce this issue is by enabling CONFIG_DEBUG_SHIRQ, which
calls free_irq() on driver removal.

Move the IRQ request and free operations back to probe, and take the
runtime PM state into account in IRQ handler. This commit is preparatory
for the subsequent fixes in this series.

Reviewed-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Tested-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Reviewed-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
Link: https://lore.kernel.org/r/20250507125032.565017-3-claudiu.beznea.uj@bp.renesas.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
  • Loading branch information
Claudiu Beznea authored and Vinod Koul committed May 14, 2025
1 parent 54c4c58 commit de76809
Showing 1 changed file with 26 additions and 20 deletions.
46 changes: 26 additions & 20 deletions drivers/phy/renesas/phy-rcar-gen3-usb2.c
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,6 @@ struct rcar_gen3_chan {
struct work_struct work;
struct mutex lock; /* protects rphys[...].powered */
enum usb_dr_mode dr_mode;
int irq;
u32 obint_enable_bits;
bool extcon_host;
bool is_otg_channel;
Expand Down Expand Up @@ -428,16 +427,25 @@ static irqreturn_t rcar_gen3_phy_usb2_irq(int irq, void *_ch)
{
struct rcar_gen3_chan *ch = _ch;
void __iomem *usb2_base = ch->base;
u32 status = readl(usb2_base + USB2_OBINTSTA);
struct device *dev = ch->dev;
irqreturn_t ret = IRQ_NONE;
u32 status;

pm_runtime_get_noresume(dev);

if (pm_runtime_suspended(dev))
goto rpm_put;

status = readl(usb2_base + USB2_OBINTSTA);
if (status & ch->obint_enable_bits) {
dev_vdbg(ch->dev, "%s: %08x\n", __func__, status);
dev_vdbg(dev, "%s: %08x\n", __func__, status);
writel(ch->obint_enable_bits, usb2_base + USB2_OBINTSTA);
rcar_gen3_device_recognition(ch);
ret = IRQ_HANDLED;
}

rpm_put:
pm_runtime_put_noidle(dev);
return ret;
}

Expand All @@ -447,17 +455,6 @@ static int rcar_gen3_phy_usb2_init(struct phy *p)
struct rcar_gen3_chan *channel = rphy->ch;
void __iomem *usb2_base = channel->base;
u32 val;
int ret;

if (!rcar_gen3_is_any_rphy_initialized(channel) && channel->irq >= 0) {
INIT_WORK(&channel->work, rcar_gen3_phy_usb2_work);
ret = request_irq(channel->irq, rcar_gen3_phy_usb2_irq,
IRQF_SHARED, dev_name(channel->dev), channel);
if (ret < 0) {
dev_err(channel->dev, "No irq handler (%d)\n", channel->irq);
return ret;
}
}

/* Initialize USB2 part */
val = readl(usb2_base + USB2_INT_ENABLE);
Expand Down Expand Up @@ -490,9 +487,6 @@ static int rcar_gen3_phy_usb2_exit(struct phy *p)
val &= ~USB2_INT_ENABLE_UCOM_INTEN;
writel(val, usb2_base + USB2_INT_ENABLE);

if (channel->irq >= 0 && !rcar_gen3_is_any_rphy_initialized(channel))
free_irq(channel->irq, channel);

return 0;
}

Expand Down Expand Up @@ -698,7 +692,7 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct rcar_gen3_chan *channel;
struct phy_provider *provider;
int ret = 0, i;
int ret = 0, i, irq;

if (!dev->of_node) {
dev_err(dev, "This driver needs device tree\n");
Expand All @@ -714,8 +708,6 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
return PTR_ERR(channel->base);

channel->obint_enable_bits = USB2_OBINT_BITS;
/* get irq number here and request_irq for OTG in phy_init */
channel->irq = platform_get_irq_optional(pdev, 0);
channel->dr_mode = rcar_gen3_get_dr_mode(dev->of_node);
if (channel->dr_mode != USB_DR_MODE_UNKNOWN) {
channel->is_otg_channel = true;
Expand Down Expand Up @@ -784,6 +776,20 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
channel->vbus = NULL;
}

irq = platform_get_irq_optional(pdev, 0);
if (irq < 0 && irq != -ENXIO) {
ret = irq;
goto error;
} else if (irq > 0) {
INIT_WORK(&channel->work, rcar_gen3_phy_usb2_work);
ret = devm_request_irq(dev, irq, rcar_gen3_phy_usb2_irq,
IRQF_SHARED, dev_name(dev), channel);
if (ret < 0) {
dev_err(dev, "Failed to request irq (%d)\n", irq);
goto error;
}
}

provider = devm_of_phy_provider_register(dev, rcar_gen3_phy_usb2_xlate);
if (IS_ERR(provider)) {
dev_err(dev, "Failed to register PHY provider\n");
Expand Down

0 comments on commit de76809

Please sign in to comment.