Message ID | 1381795140-10792-6-git-send-email-soren.brinkmann@xilinx.com |
---|---|
State | RFC, archived |
Delegated to: | David Miller |
Headers | show |
On 15/10/2013 01:59, Soren Brinkmann : > Adjust the ethernet clock according to the negotiated link speed. > > Signed-off-by: Soren Brinkmann <soren.brinkmann@xilinx.com> I will need more time to study this one. Moreover, I will have to add the "tx_clk" to every user of this driver before switchin to the addition of this clock. Best regards, > --- > drivers/net/ethernet/cadence/macb.c | 66 +++++++++++++++++++++++++++++++++++++ > drivers/net/ethernet/cadence/macb.h | 1 + > 2 files changed, 67 insertions(+) > > diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c > index 603844b1d483..beb9fa863811 100644 > --- a/drivers/net/ethernet/cadence/macb.c > +++ b/drivers/net/ethernet/cadence/macb.c > @@ -204,6 +204,49 @@ static int macb_mdio_reset(struct mii_bus *bus) > return 0; > } > > +/** > + * macb_set_tx_clk() - Set a clock to a new frequency > + * @clk Pointer to the clock to change > + * @rate New frequency in Hz > + * @dev Pointer to the struct net_device > + */ > +static void macb_set_tx_clk(struct clk *clk, int speed, struct net_device *dev) > +{ > + long ferr; > + long rate; > + long rate_rounded; > + > + switch (speed) { > + case SPEED_10: > + rate = 2500000; > + break; > + case SPEED_100: > + rate = 25000000; > + break; > + case SPEED_1000: > + rate = 125000000; > + break; > + default: > + break; > + } > + > + rate_rounded = clk_round_rate(clk, rate); > + if (rate_rounded < 0) > + return; > + > + /* RGMII allows 50 ppm frequency error. Test and warn if this limit > + * are not satisfied. > + */ > + ferr = abs(rate_rounded - rate); > + ferr = DIV_ROUND_UP(ferr, rate / 100000); > + if (ferr > 5) > + netdev_warn(dev, "unable to generate target frequency: %ld Hz\n", > + rate); > + > + if (clk_set_rate(clk, rate_rounded)) > + netdev_err(dev, "adjusting tx_clk failed.\n"); > +} > + > static void macb_handle_link_change(struct net_device *dev) > { > struct macb *bp = netdev_priv(dev); > @@ -251,6 +294,9 @@ static void macb_handle_link_change(struct net_device *dev) > > spin_unlock_irqrestore(&bp->lock, flags); > > + if (!IS_ERR(bp->tx_clk)) > + macb_set_tx_clk(bp->tx_clk, phydev->speed, dev); > + > if (status_change) { > if (phydev->link) { > netif_carrier_on(dev); > @@ -1805,6 +1851,8 @@ static int __init macb_probe(struct platform_device *pdev) > goto err_out_free_dev; > } > > + bp->tx_clk = devm_clk_get(&pdev->dev, "tx_clk"); > + > err = clk_prepare_enable(bp->pclk); > if (err) { > dev_err(&pdev->dev, "failed to enable pclk (%u)\n", err); > @@ -1817,6 +1865,15 @@ static int __init macb_probe(struct platform_device *pdev) > goto err_out_disable_pclk; > } > > + if (!IS_ERR(bp->tx_clk)) { > + err = clk_prepare_enable(bp->tx_clk); > + if (err) { > + dev_err(&pdev->dev, "failed to enable tx_clk (%u)\n", > + err); > + goto err_out_disable_hclk; > + } > + } > + > bp->regs = devm_ioremap(&pdev->dev, regs->start, resource_size(regs)); > if (!bp->regs) { > dev_err(&pdev->dev, "failed to map registers, aborting.\n"); > @@ -1917,6 +1974,9 @@ static int __init macb_probe(struct platform_device *pdev) > err_out_unregister_netdev: > unregister_netdev(dev); > err_out_disable_clocks: > + if (!IS_ERR(bp->tx_clk)) > + clk_disable_unprepare(bp->tx_clk); > +err_out_disable_hclk: > clk_disable_unprepare(bp->hclk); > err_out_disable_pclk: > clk_disable_unprepare(bp->pclk); > @@ -1941,6 +2001,8 @@ static int __exit macb_remove(struct platform_device *pdev) > kfree(bp->mii_bus->irq); > mdiobus_free(bp->mii_bus); > unregister_netdev(dev); > + if (!IS_ERR(bp->tx_clk)) > + clk_disable_unprepare(bp->tx_clk); > clk_disable_unprepare(bp->hclk); > clk_disable_unprepare(bp->pclk); > free_netdev(dev); > @@ -1959,6 +2021,8 @@ static int macb_suspend(struct device *dev) > netif_carrier_off(netdev); > netif_device_detach(netdev); > > + if (!IS_ERR(bp->tx_clk)) > + clk_disable_unprepare(bp->tx_clk); > clk_disable_unprepare(bp->hclk); > clk_disable_unprepare(bp->pclk); > > @@ -1973,6 +2037,8 @@ static int macb_resume(struct device *dev) > > clk_prepare_enable(bp->pclk); > clk_prepare_enable(bp->hclk); > + if (!IS_ERR(bp->tx_clk)) > + clk_prepare_enable(bp->tx_clk); > > netif_device_attach(netdev); > > diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h > index f4076155bed7..51c02442160a 100644 > --- a/drivers/net/ethernet/cadence/macb.h > +++ b/drivers/net/ethernet/cadence/macb.h > @@ -572,6 +572,7 @@ struct macb { > struct platform_device *pdev; > struct clk *pclk; > struct clk *hclk; > + struct clk *tx_clk; > struct net_device *dev; > struct napi_struct napi; > struct work_struct tx_error_task; >
On 10/15/2013 09:54 AM, Nicolas Ferre wrote: > On 15/10/2013 01:59, Soren Brinkmann : >> Adjust the ethernet clock according to the negotiated link speed. >> >> Signed-off-by: Soren Brinkmann <soren.brinkmann@xilinx.com> > > I will need more time to study this one. > > Moreover, I will have to add the "tx_clk" to every user of this driver before switchin to the addition of this clock. As I am reading this patch, Soren just protected this case that if this clk is not specified then it is not used. But anyway feel free to take more time to study it. If there is device-tree binding then it should be extend by this optional value. Thanks, Michal -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Tue, Oct 15, 2013 at 09:58:09AM +0200, Michal Simek wrote: > On 10/15/2013 09:54 AM, Nicolas Ferre wrote: > > On 15/10/2013 01:59, Soren Brinkmann : > >> Adjust the ethernet clock according to the negotiated link speed. > >> > >> Signed-off-by: Soren Brinkmann <soren.brinkmann@xilinx.com> > > > > I will need more time to study this one. > > > > Moreover, I will have to add the "tx_clk" to every user of this driver before switchin to the addition of this clock. > > As I am reading this patch, Soren just protected this > case that if this clk is not specified then it is not used. That is how I sketched things in this patch. But as I said, I'm not fully convinced this approach fits all or is the best. So, if anybody has a better approach, let us know. Sören -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Hi Nicolas, On Tue, Oct 15, 2013 at 09:54:21AM +0200, Nicolas Ferre wrote: > On 15/10/2013 01:59, Soren Brinkmann : > >Adjust the ethernet clock according to the negotiated link speed. > > > >Signed-off-by: Soren Brinkmann <soren.brinkmann@xilinx.com> > > I will need more time to study this one. > > Moreover, I will have to add the "tx_clk" to every user of this > driver before switchin to the addition of this clock. I just wanted to follow up on this. Did you have a chance to look at this closer? Thanks, Sören -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c index 603844b1d483..beb9fa863811 100644 --- a/drivers/net/ethernet/cadence/macb.c +++ b/drivers/net/ethernet/cadence/macb.c @@ -204,6 +204,49 @@ static int macb_mdio_reset(struct mii_bus *bus) return 0; } +/** + * macb_set_tx_clk() - Set a clock to a new frequency + * @clk Pointer to the clock to change + * @rate New frequency in Hz + * @dev Pointer to the struct net_device + */ +static void macb_set_tx_clk(struct clk *clk, int speed, struct net_device *dev) +{ + long ferr; + long rate; + long rate_rounded; + + switch (speed) { + case SPEED_10: + rate = 2500000; + break; + case SPEED_100: + rate = 25000000; + break; + case SPEED_1000: + rate = 125000000; + break; + default: + break; + } + + rate_rounded = clk_round_rate(clk, rate); + if (rate_rounded < 0) + return; + + /* RGMII allows 50 ppm frequency error. Test and warn if this limit + * are not satisfied. + */ + ferr = abs(rate_rounded - rate); + ferr = DIV_ROUND_UP(ferr, rate / 100000); + if (ferr > 5) + netdev_warn(dev, "unable to generate target frequency: %ld Hz\n", + rate); + + if (clk_set_rate(clk, rate_rounded)) + netdev_err(dev, "adjusting tx_clk failed.\n"); +} + static void macb_handle_link_change(struct net_device *dev) { struct macb *bp = netdev_priv(dev); @@ -251,6 +294,9 @@ static void macb_handle_link_change(struct net_device *dev) spin_unlock_irqrestore(&bp->lock, flags); + if (!IS_ERR(bp->tx_clk)) + macb_set_tx_clk(bp->tx_clk, phydev->speed, dev); + if (status_change) { if (phydev->link) { netif_carrier_on(dev); @@ -1805,6 +1851,8 @@ static int __init macb_probe(struct platform_device *pdev) goto err_out_free_dev; } + bp->tx_clk = devm_clk_get(&pdev->dev, "tx_clk"); + err = clk_prepare_enable(bp->pclk); if (err) { dev_err(&pdev->dev, "failed to enable pclk (%u)\n", err); @@ -1817,6 +1865,15 @@ static int __init macb_probe(struct platform_device *pdev) goto err_out_disable_pclk; } + if (!IS_ERR(bp->tx_clk)) { + err = clk_prepare_enable(bp->tx_clk); + if (err) { + dev_err(&pdev->dev, "failed to enable tx_clk (%u)\n", + err); + goto err_out_disable_hclk; + } + } + bp->regs = devm_ioremap(&pdev->dev, regs->start, resource_size(regs)); if (!bp->regs) { dev_err(&pdev->dev, "failed to map registers, aborting.\n"); @@ -1917,6 +1974,9 @@ static int __init macb_probe(struct platform_device *pdev) err_out_unregister_netdev: unregister_netdev(dev); err_out_disable_clocks: + if (!IS_ERR(bp->tx_clk)) + clk_disable_unprepare(bp->tx_clk); +err_out_disable_hclk: clk_disable_unprepare(bp->hclk); err_out_disable_pclk: clk_disable_unprepare(bp->pclk); @@ -1941,6 +2001,8 @@ static int __exit macb_remove(struct platform_device *pdev) kfree(bp->mii_bus->irq); mdiobus_free(bp->mii_bus); unregister_netdev(dev); + if (!IS_ERR(bp->tx_clk)) + clk_disable_unprepare(bp->tx_clk); clk_disable_unprepare(bp->hclk); clk_disable_unprepare(bp->pclk); free_netdev(dev); @@ -1959,6 +2021,8 @@ static int macb_suspend(struct device *dev) netif_carrier_off(netdev); netif_device_detach(netdev); + if (!IS_ERR(bp->tx_clk)) + clk_disable_unprepare(bp->tx_clk); clk_disable_unprepare(bp->hclk); clk_disable_unprepare(bp->pclk); @@ -1973,6 +2037,8 @@ static int macb_resume(struct device *dev) clk_prepare_enable(bp->pclk); clk_prepare_enable(bp->hclk); + if (!IS_ERR(bp->tx_clk)) + clk_prepare_enable(bp->tx_clk); netif_device_attach(netdev); diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h index f4076155bed7..51c02442160a 100644 --- a/drivers/net/ethernet/cadence/macb.h +++ b/drivers/net/ethernet/cadence/macb.h @@ -572,6 +572,7 @@ struct macb { struct platform_device *pdev; struct clk *pclk; struct clk *hclk; + struct clk *tx_clk; struct net_device *dev; struct napi_struct napi; struct work_struct tx_error_task;
Adjust the ethernet clock according to the negotiated link speed. Signed-off-by: Soren Brinkmann <soren.brinkmann@xilinx.com> --- drivers/net/ethernet/cadence/macb.c | 66 +++++++++++++++++++++++++++++++++++++ drivers/net/ethernet/cadence/macb.h | 1 + 2 files changed, 67 insertions(+)