Merge branch 'r8169-clk-fixes'

Hans de Goede says:

====================
r8169 (x86) clk fixes to fix S0ix not being reached

This series adds code to the r8169 ethernet driver to get and enable an
external clock if present, avoiding the need for a hack in the
clk-pmc-atom driver where that clock was left on continuesly causing x86
some devices to not reach deep power saving states (S0ix) when suspended
causing to them to quickly drain their battery while suspended.

The 3 commits in this series need to be merged in order to avoid
regressions while bisecting. The clk-pmc-atom driver does not see much
changes (it was last touched over a year ago). So the clk maintainers
have agreed with merging all 3 patches through the net tree.
All 3 patches have Stephen Boyd's Acked-by for this purpose.

This v2 of the series only had some minor tweaks done to the commit
messages and is ready for merging through the net tree now.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2018-09-17 18:47:58 -07:00
commit 89bfd48d67
2 changed files with 44 additions and 7 deletions

View File

@ -55,6 +55,7 @@ struct clk_plt_data {
u8 nparents; u8 nparents;
struct clk_plt *clks[PMC_CLK_NUM]; struct clk_plt *clks[PMC_CLK_NUM];
struct clk_lookup *mclk_lookup; struct clk_lookup *mclk_lookup;
struct clk_lookup *ether_clk_lookup;
}; };
/* Return an index in parent table */ /* Return an index in parent table */
@ -186,13 +187,6 @@ static struct clk_plt *plt_clk_register(struct platform_device *pdev, int id,
pclk->reg = base + PMC_CLK_CTL_OFFSET + id * PMC_CLK_CTL_SIZE; pclk->reg = base + PMC_CLK_CTL_OFFSET + id * PMC_CLK_CTL_SIZE;
spin_lock_init(&pclk->lock); spin_lock_init(&pclk->lock);
/*
* If the clock was already enabled by the firmware mark it as critical
* to avoid it being gated by the clock framework if no driver owns it.
*/
if (plt_clk_is_enabled(&pclk->hw))
init.flags |= CLK_IS_CRITICAL;
ret = devm_clk_hw_register(&pdev->dev, &pclk->hw); ret = devm_clk_hw_register(&pdev->dev, &pclk->hw);
if (ret) { if (ret) {
pclk = ERR_PTR(ret); pclk = ERR_PTR(ret);
@ -351,11 +345,20 @@ static int plt_clk_probe(struct platform_device *pdev)
goto err_unreg_clk_plt; goto err_unreg_clk_plt;
} }
data->ether_clk_lookup = clkdev_hw_create(&data->clks[4]->hw,
"ether_clk", NULL);
if (!data->ether_clk_lookup) {
err = -ENOMEM;
goto err_drop_mclk;
}
plt_clk_free_parent_names_loop(parent_names, data->nparents); plt_clk_free_parent_names_loop(parent_names, data->nparents);
platform_set_drvdata(pdev, data); platform_set_drvdata(pdev, data);
return 0; return 0;
err_drop_mclk:
clkdev_drop(data->mclk_lookup);
err_unreg_clk_plt: err_unreg_clk_plt:
plt_clk_unregister_loop(data, i); plt_clk_unregister_loop(data, i);
plt_clk_unregister_parents(data); plt_clk_unregister_parents(data);
@ -369,6 +372,7 @@ static int plt_clk_remove(struct platform_device *pdev)
data = platform_get_drvdata(pdev); data = platform_get_drvdata(pdev);
clkdev_drop(data->ether_clk_lookup);
clkdev_drop(data->mclk_lookup); clkdev_drop(data->mclk_lookup);
plt_clk_unregister_loop(data, PMC_CLK_NUM); plt_clk_unregister_loop(data, PMC_CLK_NUM);
plt_clk_unregister_parents(data); plt_clk_unregister_parents(data);

View File

@ -13,6 +13,7 @@
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <linux/clk.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/ethtool.h> #include <linux/ethtool.h>
#include <linux/phy.h> #include <linux/phy.h>
@ -665,6 +666,7 @@ struct rtl8169_private {
u16 event_slow; u16 event_slow;
const struct rtl_coalesce_info *coalesce_info; const struct rtl_coalesce_info *coalesce_info;
struct clk *clk;
struct mdio_ops { struct mdio_ops {
void (*write)(struct rtl8169_private *, int, int); void (*write)(struct rtl8169_private *, int, int);
@ -7262,6 +7264,11 @@ static int rtl_jumbo_max(struct rtl8169_private *tp)
} }
} }
static void rtl_disable_clk(void *data)
{
clk_disable_unprepare(data);
}
static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{ {
const struct rtl_cfg_info *cfg = rtl_cfg_infos + ent->driver_data; const struct rtl_cfg_info *cfg = rtl_cfg_infos + ent->driver_data;
@ -7282,6 +7289,32 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
tp->msg_enable = netif_msg_init(debug.msg_enable, R8169_MSG_DEFAULT); tp->msg_enable = netif_msg_init(debug.msg_enable, R8169_MSG_DEFAULT);
tp->supports_gmii = cfg->has_gmii; tp->supports_gmii = cfg->has_gmii;
/* Get the *optional* external "ether_clk" used on some boards */
tp->clk = devm_clk_get(&pdev->dev, "ether_clk");
if (IS_ERR(tp->clk)) {
rc = PTR_ERR(tp->clk);
if (rc == -ENOENT) {
/* clk-core allows NULL (for suspend / resume) */
tp->clk = NULL;
} else if (rc == -EPROBE_DEFER) {
return rc;
} else {
dev_err(&pdev->dev, "failed to get clk: %d\n", rc);
return rc;
}
} else {
rc = clk_prepare_enable(tp->clk);
if (rc) {
dev_err(&pdev->dev, "failed to enable clk: %d\n", rc);
return rc;
}
rc = devm_add_action_or_reset(&pdev->dev, rtl_disable_clk,
tp->clk);
if (rc)
return rc;
}
/* enable device (incl. PCI PM wakeup and hotplug setup) */ /* enable device (incl. PCI PM wakeup and hotplug setup) */
rc = pcim_enable_device(pdev); rc = pcim_enable_device(pdev);
if (rc < 0) { if (rc < 0) {