nvethernet: Reset MAC registers on interface down and up.

Issue: MAC registers are not getting reset on ether_close(),
which lead to old values in MAC registers at the time of
osi_hw_core_init().

Fix: Assert MAC-RST gpio and disable clocks in ether_close().
Enable clock, reset MAC_RST gpio and poll for swr, which will
reset all MAC registers.

Note: To read MAC registers, you must have clocks enable and MAC
out of reset

Bug 200512422

Change-Id: If253eff0ae456702d3cdcbe1f177dd91a5aae20d
Signed-off-by: Rakesh Goyal <rgoyal@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/2138031
Reviewed-by: Narayan Reddy <narayanr@nvidia.com>
GVS: Gerrit_Virtual_Submit
Reviewed-by: Sachin Nikam <snikam@nvidia.com>
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
This commit is contained in:
Rakesh Goyal
2019-06-18 15:04:03 +05:30
committed by Revanth Kumar Uppala
parent d3161de4da
commit f71600879c

View File

@@ -16,6 +16,130 @@
#include "ether_linux.h"
/**
* ether_disable_clks - Disable all MAC related clks.
* @pdata: OSD private data.
*
* Algorithm: Release the reference counter for the clks by using
* clock subsystem provided API's.
*
* Dependencies: None.
*
* Protection: None.
*
* Return: None.
*/
static void ether_disable_clks(struct ether_priv_data *pdata)
{
if (!IS_ERR_OR_NULL(pdata->axi_cbb_clk)) {
clk_disable_unprepare(pdata->axi_cbb_clk);
}
if (!IS_ERR_OR_NULL(pdata->axi_clk)) {
clk_disable_unprepare(pdata->axi_clk);
}
if (!IS_ERR_OR_NULL(pdata->rx_clk)) {
clk_disable_unprepare(pdata->rx_clk);
}
if (!IS_ERR_OR_NULL(pdata->ptp_ref_clk)) {
clk_disable_unprepare(pdata->ptp_ref_clk);
}
if (!IS_ERR_OR_NULL(pdata->tx_clk)) {
clk_disable_unprepare(pdata->tx_clk);
}
if (!IS_ERR_OR_NULL(pdata->pllrefe_clk)) {
clk_disable_unprepare(pdata->pllrefe_clk);
}
}
/**
* ether_enable_clks - Enable all MAC related clks.
* @pdata: OSD private data.
*
* Algorithm: Enables the clks by using clock subsystem provided API's.
*
* Dependencies: None.
*
* Protection: None.
*
* Return: 0 - success, negative value - failure.
*/
static int ether_enable_clks(struct ether_priv_data *pdata)
{
int ret;
if (!IS_ERR_OR_NULL(pdata->pllrefe_clk)) {
ret = clk_prepare_enable(pdata->pllrefe_clk);
if (ret < 0) {
return ret;
}
}
if (!IS_ERR_OR_NULL(pdata->axi_cbb_clk)) {
ret = clk_prepare_enable(pdata->axi_cbb_clk);
if (ret) {
goto err_axi_cbb;
}
}
if (!IS_ERR_OR_NULL(pdata->axi_clk)) {
ret = clk_prepare_enable(pdata->axi_clk);
if (ret < 0) {
goto err_axi;
}
}
if (!IS_ERR_OR_NULL(pdata->rx_clk)) {
ret = clk_prepare_enable(pdata->rx_clk);
if (ret < 0) {
goto err_rx;
}
}
if (!IS_ERR_OR_NULL(pdata->ptp_ref_clk)) {
ret = clk_prepare_enable(pdata->ptp_ref_clk);
if (ret < 0) {
goto err_ptp_ref;
}
}
if (!IS_ERR_OR_NULL(pdata->tx_clk)) {
ret = clk_prepare_enable(pdata->tx_clk);
if (ret < 0) {
goto err_tx;
}
}
return 0;
err_tx:
if (!IS_ERR_OR_NULL(pdata->ptp_ref_clk)) {
clk_disable_unprepare(pdata->ptp_ref_clk);
}
err_ptp_ref:
if (!IS_ERR_OR_NULL(pdata->rx_clk)) {
clk_disable_unprepare(pdata->rx_clk);
}
err_rx:
if (!IS_ERR_OR_NULL(pdata->axi_clk)) {
clk_disable_unprepare(pdata->axi_clk);
}
err_axi:
if (!IS_ERR_OR_NULL(pdata->axi_cbb_clk)) {
clk_disable_unprepare(pdata->axi_cbb_clk);
}
err_axi_cbb:
if (!IS_ERR_OR_NULL(pdata->pllrefe_clk)) {
clk_disable_unprepare(pdata->pllrefe_clk);
}
return ret;
}
/**
* ether_adjust_link - Adjust link call back
* @dev: Net device data.
@@ -1021,14 +1145,35 @@ static int ether_therm_init(struct ether_priv_data *pdata)
static int ether_open(struct net_device *dev)
{
struct ether_priv_data *pdata = netdev_priv(dev);
struct osi_core_priv_data *osi_core = pdata->osi_core;
int ret = 0;
ret = ether_enable_clks(pdata);
if (ret < 0) {
dev_err(&dev->dev, "failed to enable clks\n");
return ret;
}
if (pdata->mac_rst) {
ret = reset_control_reset(pdata->mac_rst);
if (ret < 0) {
dev_err(&dev->dev, "failed to reset MAC HW\n");
goto err_mac_rst;
}
}
ret = osi_poll_for_swr(osi_core);
if (ret < 0) {
dev_err(&dev->dev, "failed to poll MAC Software reset\n");
goto err_poll_swr;
}
/* PHY reset and initialization */
ret = ether_phy_init(dev);
if (ret < 0) {
dev_err(&dev->dev, "%s: Cannot attach to PHY (error: %d)\n",
__func__, ret);
return ret;
goto err_phy_init;
}
/* request tx/rx/common irq */
@@ -1109,8 +1254,16 @@ err_therm:
err_alloc:
ether_free_irqs(pdata);
err_r_irq:
if (pdata->phydev)
if (pdata->phydev) {
phy_disconnect(pdata->phydev);
}
err_phy_init:
err_poll_swr:
if (pdata->mac_rst) {
reset_control_assert(pdata->mac_rst);
}
err_mac_rst:
ether_disable_clks(pdata);
return ret;
}
@@ -1131,17 +1284,17 @@ err_r_irq:
*/
static int ether_close(struct net_device *dev)
{
int ret = 0;
struct ether_priv_data *pdata = netdev_priv(dev);
int ret = 0;
/* Stop and disconnect the PHY */
if (pdata->phydev != NULL) {
phy_stop(pdata->phydev);
phy_disconnect(pdata->phydev);
if (gpio_is_valid(pdata->phy_reset))
if (gpio_is_valid(pdata->phy_reset)) {
gpio_set_value(pdata->phy_reset, 0);
}
pdata->phydev = NULL;
}
@@ -1169,6 +1322,14 @@ static int ether_close(struct net_device *dev)
ether_napi_disable(pdata);
/* Assert MAC RST gpio */
if (pdata->mac_rst) {
reset_control_assert(pdata->mac_rst);
}
/* Disable clock */
ether_disable_clks(pdata);
return ret;
}
@@ -2387,113 +2548,6 @@ static int ether_get_mac_address(struct ether_priv_data *pdata)
return ret;
}
/**
* ether_disable_clks - Disable all MAC related clks.
* @pdata: OSD private data.
*
* Algorithm: Release the reference counter for the clks by using
* clock subsystem provided API's.
*
* Dependencies: None.
*
* Protection: None.
*
* Return: None.
*/
static void ether_disable_clks(struct ether_priv_data *pdata)
{
if (!IS_ERR_OR_NULL(pdata->axi_cbb_clk))
clk_disable_unprepare(pdata->axi_cbb_clk);
if (!IS_ERR_OR_NULL(pdata->axi_clk))
clk_disable_unprepare(pdata->axi_clk);
if (!IS_ERR_OR_NULL(pdata->rx_clk))
clk_disable_unprepare(pdata->rx_clk);
if (!IS_ERR_OR_NULL(pdata->ptp_ref_clk))
clk_disable_unprepare(pdata->ptp_ref_clk);
if (!IS_ERR_OR_NULL(pdata->tx_clk))
clk_disable_unprepare(pdata->tx_clk);
if (!IS_ERR_OR_NULL(pdata->pllrefe_clk))
clk_disable_unprepare(pdata->pllrefe_clk);
}
/**
* ether_enable_clks - Enable all MAC related clks.
* @pdata: OSD private data.
*
* Algorithm: Enables the clks by using clock subsystem provided API's.
*
* Dependencies: None.
*
* Protection: None.
*
* Return: 0 - success, negative value - failure.
*/
static int ether_enable_clks(struct ether_priv_data *pdata)
{
int ret;
if (!IS_ERR_OR_NULL(pdata->pllrefe_clk)) {
ret = clk_prepare_enable(pdata->pllrefe_clk);
if (ret < 0)
return ret;
}
if (!IS_ERR_OR_NULL(pdata->axi_cbb_clk)) {
ret = clk_prepare_enable(pdata->axi_cbb_clk);
if (ret)
goto err_axi_cbb;
}
if (!IS_ERR_OR_NULL(pdata->axi_clk)) {
ret = clk_prepare_enable(pdata->axi_clk);
if (ret < 0)
goto err_axi;
}
if (!IS_ERR_OR_NULL(pdata->rx_clk)) {
ret = clk_prepare_enable(pdata->rx_clk);
if (ret < 0)
goto err_rx;
}
if (!IS_ERR_OR_NULL(pdata->ptp_ref_clk)) {
ret = clk_prepare_enable(pdata->ptp_ref_clk);
if (ret < 0)
goto err_ptp_ref;
}
if (!IS_ERR_OR_NULL(pdata->tx_clk)) {
ret = clk_prepare_enable(pdata->tx_clk);
if (ret < 0)
goto err_tx;
}
return 0;
err_tx:
if (!IS_ERR_OR_NULL(pdata->ptp_ref_clk))
clk_disable_unprepare(pdata->ptp_ref_clk);
err_ptp_ref:
if (!IS_ERR_OR_NULL(pdata->rx_clk))
clk_disable_unprepare(pdata->rx_clk);
err_rx:
if (!IS_ERR_OR_NULL(pdata->axi_clk))
clk_disable_unprepare(pdata->axi_clk);
err_axi:
if (!IS_ERR_OR_NULL(pdata->axi_cbb_clk))
clk_disable_unprepare(pdata->axi_cbb_clk);
err_axi_cbb:
if (!IS_ERR_OR_NULL(pdata->pllrefe_clk))
clk_disable_unprepare(pdata->pllrefe_clk);
return ret;
}
/**
* ether_put_clks - Put back MAC related clocks.
* @pdata: OSD private data.
@@ -2695,8 +2749,9 @@ static int ether_configure_car(struct platform_device *pdev,
return ret;
err_swr:
if (pdata->mac_rst)
reset_control_deassert(pdata->mac_rst);
if (pdata->mac_rst) {
reset_control_assert(pdata->mac_rst);
}
err_rst:
ether_disable_clks(pdata);
err_enable_clks:
@@ -3326,6 +3381,8 @@ static int ether_probe(struct platform_device *pdev)
spin_lock_init(&pdata->lock);
spin_lock_init(&pdata->ioctl_lock);
init_filter_values(pdata);
/* Disable Clocks */
ether_disable_clks(pdata);
dev_info(&pdev->dev,
"%s (HW ver: %02x) created with %u DMA channels\n",
@@ -3377,6 +3434,10 @@ static int ether_remove(struct platform_device *pdev)
}
ether_disable_clks(pdata);
/* Assert MAC RST gpio */
if (pdata->mac_rst) {
reset_control_assert(pdata->mac_rst);
}
free_netdev(ndev);
return 0;