Message ID | 20220719143912.2727014-1-dqfext@gmail.com (mailing list archive) |
---|---|
State | Not Applicable |
Headers | show |
Series | Handling standalone PCS IRQ | expand |
On Tue, Jul 19, 2022 at 10:39:12PM +0800, Qingfang DENG wrote: > Hi all, > > I was working with an SoC that has a built-in DWC XPCS with IRQ support. > However the current driver still uses polling. > > I may modify xpcs_create() to try getting an IRQ number from DT, and fall back > to polling if it fails (see the code below). But I don't know how to notify > phylink in the IRQ handler. > > There is a phylink_mac_change() function to notify phylink, but it is supposed > to be used in a MAC driver, and it requires a (struct phylink *), not a > (struct phylink_pcs *). Do we need a similar one for PCS? Russell should really answer this. But my take on this, is yes, you should add a phylink_pcs_change(), which calls phylink_run_resolve(). As you say, i don't currently see a way to go from phylink_pcs to phylink. So you might need to add a pointer to phylink_pcs. Just be careful of race conditions, phylink->pcs can change, and you don't want an interrupt delivered while it is changing. I would also make the value in phylink_pcs opaque, we don't want the PCS actually using information from the phylink structure. Andrew
--- a/drivers/net/pcs/pcs-xpcs.c +++ b/drivers/net/pcs/pcs-xpcs.c @@ -1272,6 +1272,13 @@ static const struct phylink_pcs_ops xpcs_phylink_ops = { .pcs_link_up = xpcs_link_up, }; +static irqreturn_t xpcs_irq(int irq, void *dev_id) { + struct dw_xpcs *xpcs = dev_id; + + /* XXX: notify phylink */ + return IRQ_HANDLED; +} + struct dw_xpcs *xpcs_create(struct mdio_device *mdiodev, phy_interface_t interface) { @@ -1303,7 +1310,21 @@ struct dw_xpcs *xpcs_create(struct mdio_device *mdiodev, } xpcs->pcs.ops = &xpcs_phylink_ops; - xpcs->pcs.poll = true; + + ret = of_irq_get(mdiodev->dev.of_node, 0); + if (ret == -EPROBE_DEFER) + goto out; + + if (ret > 0) { + ret = devm_request_threaded_irq(&mdiodev->dev, ret, + NULL, xpcs_irq, + IRQF_ONESHOT, + KBUILD_MODNAME, xpcs); + if (ret < 0) + goto out; + } else { + xpcs->pcs.poll = true; + } ret = xpcs_soft_reset(xpcs, compat); if (ret)