mirror of
https://github.com/torvalds/linux
synced 2024-11-05 18:23:50 +00:00
Merge branch 'amd-xgbe'
Tom Lendacky says: ==================== amd-xgbe: AMD XGBE driver update 2014-08-05 The following series of patches includes fixes/updates to the driver. - Use dma_set_mask_and_coherent to set the DMA mask - Move the phy connect/disconnect logic to allow for module unloading Changes in V2: - Check the return value of the dma_set_mask_and_coherent call ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
0ca58d6242
3 changed files with 126 additions and 101 deletions
|
@ -122,6 +122,7 @@
|
|||
#include <linux/clk.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/net_tstamp.h>
|
||||
#include <linux/phy.h>
|
||||
|
||||
#include "xgbe.h"
|
||||
#include "xgbe-common.h"
|
||||
|
@ -521,6 +522,114 @@ static void xgbe_free_rx_skbuff(struct xgbe_prv_data *pdata)
|
|||
DBGPR("<--xgbe_free_rx_skbuff\n");
|
||||
}
|
||||
|
||||
static void xgbe_adjust_link(struct net_device *netdev)
|
||||
{
|
||||
struct xgbe_prv_data *pdata = netdev_priv(netdev);
|
||||
struct xgbe_hw_if *hw_if = &pdata->hw_if;
|
||||
struct phy_device *phydev = pdata->phydev;
|
||||
int new_state = 0;
|
||||
|
||||
if (phydev == NULL)
|
||||
return;
|
||||
|
||||
if (phydev->link) {
|
||||
/* Flow control support */
|
||||
if (pdata->pause_autoneg) {
|
||||
if (phydev->pause || phydev->asym_pause) {
|
||||
pdata->tx_pause = 1;
|
||||
pdata->rx_pause = 1;
|
||||
} else {
|
||||
pdata->tx_pause = 0;
|
||||
pdata->rx_pause = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (pdata->tx_pause != pdata->phy_tx_pause) {
|
||||
hw_if->config_tx_flow_control(pdata);
|
||||
pdata->phy_tx_pause = pdata->tx_pause;
|
||||
}
|
||||
|
||||
if (pdata->rx_pause != pdata->phy_rx_pause) {
|
||||
hw_if->config_rx_flow_control(pdata);
|
||||
pdata->phy_rx_pause = pdata->rx_pause;
|
||||
}
|
||||
|
||||
/* Speed support */
|
||||
if (phydev->speed != pdata->phy_speed) {
|
||||
new_state = 1;
|
||||
|
||||
switch (phydev->speed) {
|
||||
case SPEED_10000:
|
||||
hw_if->set_xgmii_speed(pdata);
|
||||
break;
|
||||
|
||||
case SPEED_2500:
|
||||
hw_if->set_gmii_2500_speed(pdata);
|
||||
break;
|
||||
|
||||
case SPEED_1000:
|
||||
hw_if->set_gmii_speed(pdata);
|
||||
break;
|
||||
}
|
||||
pdata->phy_speed = phydev->speed;
|
||||
}
|
||||
|
||||
if (phydev->link != pdata->phy_link) {
|
||||
new_state = 1;
|
||||
pdata->phy_link = 1;
|
||||
}
|
||||
} else if (pdata->phy_link) {
|
||||
new_state = 1;
|
||||
pdata->phy_link = 0;
|
||||
pdata->phy_speed = SPEED_UNKNOWN;
|
||||
}
|
||||
|
||||
if (new_state)
|
||||
phy_print_status(phydev);
|
||||
}
|
||||
|
||||
static int xgbe_phy_init(struct xgbe_prv_data *pdata)
|
||||
{
|
||||
struct net_device *netdev = pdata->netdev;
|
||||
struct phy_device *phydev = pdata->phydev;
|
||||
int ret;
|
||||
|
||||
pdata->phy_link = -1;
|
||||
pdata->phy_speed = SPEED_UNKNOWN;
|
||||
pdata->phy_tx_pause = pdata->tx_pause;
|
||||
pdata->phy_rx_pause = pdata->rx_pause;
|
||||
|
||||
ret = phy_connect_direct(netdev, phydev, &xgbe_adjust_link,
|
||||
pdata->phy_mode);
|
||||
if (ret) {
|
||||
netdev_err(netdev, "phy_connect_direct failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!phydev->drv || (phydev->drv->phy_id == 0)) {
|
||||
netdev_err(netdev, "phy_id not valid\n");
|
||||
ret = -ENODEV;
|
||||
goto err_phy_connect;
|
||||
}
|
||||
DBGPR(" phy_connect_direct succeeded for PHY %s, link=%d\n",
|
||||
dev_name(&phydev->dev), phydev->link);
|
||||
|
||||
return 0;
|
||||
|
||||
err_phy_connect:
|
||||
phy_disconnect(phydev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void xgbe_phy_exit(struct xgbe_prv_data *pdata)
|
||||
{
|
||||
if (!pdata->phydev)
|
||||
return;
|
||||
|
||||
phy_disconnect(pdata->phydev);
|
||||
}
|
||||
|
||||
int xgbe_powerdown(struct net_device *netdev, unsigned int caller)
|
||||
{
|
||||
struct xgbe_prv_data *pdata = netdev_priv(netdev);
|
||||
|
@ -986,11 +1095,16 @@ static int xgbe_open(struct net_device *netdev)
|
|||
|
||||
DBGPR("-->xgbe_open\n");
|
||||
|
||||
/* Initialize the phy */
|
||||
ret = xgbe_phy_init(pdata);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Enable the clocks */
|
||||
ret = clk_prepare_enable(pdata->sysclk);
|
||||
if (ret) {
|
||||
netdev_alert(netdev, "dma clk_prepare_enable failed\n");
|
||||
return ret;
|
||||
goto err_phy_init;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(pdata->ptpclk);
|
||||
|
@ -1047,6 +1161,9 @@ static int xgbe_open(struct net_device *netdev)
|
|||
err_sysclk:
|
||||
clk_disable_unprepare(pdata->sysclk);
|
||||
|
||||
err_phy_init:
|
||||
xgbe_phy_exit(pdata);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1077,6 +1194,9 @@ static int xgbe_close(struct net_device *netdev)
|
|||
clk_disable_unprepare(pdata->ptpclk);
|
||||
clk_disable_unprepare(pdata->sysclk);
|
||||
|
||||
/* Release the phy */
|
||||
xgbe_phy_exit(pdata);
|
||||
|
||||
DBGPR("<--xgbe_close\n");
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -303,8 +303,11 @@ static int xgbe_probe(struct platform_device *pdev)
|
|||
/* Set the DMA mask */
|
||||
if (!dev->dma_mask)
|
||||
dev->dma_mask = &dev->coherent_dma_mask;
|
||||
*(dev->dma_mask) = DMA_BIT_MASK(40);
|
||||
dev->coherent_dma_mask = DMA_BIT_MASK(40);
|
||||
ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(40));
|
||||
if (ret) {
|
||||
dev_err(dev, "dma_set_mask_and_coherent failed\n");
|
||||
goto err_io;
|
||||
}
|
||||
|
||||
if (of_property_read_bool(dev->of_node, "dma-coherent")) {
|
||||
pdata->axdomain = XGBE_DMA_OS_AXDOMAIN;
|
||||
|
|
|
@ -116,7 +116,6 @@
|
|||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kmod.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/mdio.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/of.h>
|
||||
|
@ -158,77 +157,6 @@ static int xgbe_mdio_write(struct mii_bus *mii, int prtad, int mmd_reg,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void xgbe_adjust_link(struct net_device *netdev)
|
||||
{
|
||||
struct xgbe_prv_data *pdata = netdev_priv(netdev);
|
||||
struct xgbe_hw_if *hw_if = &pdata->hw_if;
|
||||
struct phy_device *phydev = pdata->phydev;
|
||||
int new_state = 0;
|
||||
|
||||
if (phydev == NULL)
|
||||
return;
|
||||
|
||||
DBGPR_MDIO("-->xgbe_adjust_link: address=%d, newlink=%d, curlink=%d\n",
|
||||
phydev->addr, phydev->link, pdata->phy_link);
|
||||
|
||||
if (phydev->link) {
|
||||
/* Flow control support */
|
||||
if (pdata->pause_autoneg) {
|
||||
if (phydev->pause || phydev->asym_pause) {
|
||||
pdata->tx_pause = 1;
|
||||
pdata->rx_pause = 1;
|
||||
} else {
|
||||
pdata->tx_pause = 0;
|
||||
pdata->rx_pause = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (pdata->tx_pause != pdata->phy_tx_pause) {
|
||||
hw_if->config_tx_flow_control(pdata);
|
||||
pdata->phy_tx_pause = pdata->tx_pause;
|
||||
}
|
||||
|
||||
if (pdata->rx_pause != pdata->phy_rx_pause) {
|
||||
hw_if->config_rx_flow_control(pdata);
|
||||
pdata->phy_rx_pause = pdata->rx_pause;
|
||||
}
|
||||
|
||||
/* Speed support */
|
||||
if (phydev->speed != pdata->phy_speed) {
|
||||
new_state = 1;
|
||||
|
||||
switch (phydev->speed) {
|
||||
case SPEED_10000:
|
||||
hw_if->set_xgmii_speed(pdata);
|
||||
break;
|
||||
|
||||
case SPEED_2500:
|
||||
hw_if->set_gmii_2500_speed(pdata);
|
||||
break;
|
||||
|
||||
case SPEED_1000:
|
||||
hw_if->set_gmii_speed(pdata);
|
||||
break;
|
||||
}
|
||||
pdata->phy_speed = phydev->speed;
|
||||
}
|
||||
|
||||
if (phydev->link != pdata->phy_link) {
|
||||
new_state = 1;
|
||||
pdata->phy_link = 1;
|
||||
}
|
||||
} else if (pdata->phy_link) {
|
||||
new_state = 1;
|
||||
pdata->phy_link = 0;
|
||||
pdata->phy_speed = SPEED_UNKNOWN;
|
||||
}
|
||||
|
||||
if (new_state)
|
||||
phy_print_status(phydev);
|
||||
|
||||
DBGPR_MDIO("<--xgbe_adjust_link\n");
|
||||
}
|
||||
|
||||
void xgbe_dump_phy_registers(struct xgbe_prv_data *pdata)
|
||||
{
|
||||
struct device *dev = pdata->dev;
|
||||
|
@ -278,7 +206,6 @@ void xgbe_dump_phy_registers(struct xgbe_prv_data *pdata)
|
|||
|
||||
int xgbe_mdio_register(struct xgbe_prv_data *pdata)
|
||||
{
|
||||
struct net_device *netdev = pdata->netdev;
|
||||
struct device_node *phy_node;
|
||||
struct mii_bus *mii;
|
||||
struct phy_device *phydev;
|
||||
|
@ -293,7 +220,6 @@ int xgbe_mdio_register(struct xgbe_prv_data *pdata)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Register with the MDIO bus */
|
||||
mii = mdiobus_alloc();
|
||||
if (mii == NULL) {
|
||||
dev_err(pdata->dev, "mdiobus_alloc failed\n");
|
||||
|
@ -348,26 +274,6 @@ int xgbe_mdio_register(struct xgbe_prv_data *pdata)
|
|||
pdata->mii = mii;
|
||||
pdata->mdio_mmd = MDIO_MMD_PCS;
|
||||
|
||||
pdata->phy_link = -1;
|
||||
pdata->phy_speed = SPEED_UNKNOWN;
|
||||
pdata->phy_tx_pause = pdata->tx_pause;
|
||||
pdata->phy_rx_pause = pdata->rx_pause;
|
||||
|
||||
ret = phy_connect_direct(netdev, phydev, &xgbe_adjust_link,
|
||||
pdata->phy_mode);
|
||||
if (ret) {
|
||||
netdev_err(netdev, "phy_connect_direct failed\n");
|
||||
goto err_phy_device;
|
||||
}
|
||||
|
||||
if (!phydev->drv || (phydev->drv->phy_id == 0)) {
|
||||
netdev_err(netdev, "phy_id not valid\n");
|
||||
ret = -ENODEV;
|
||||
goto err_phy_connect;
|
||||
}
|
||||
DBGPR(" phy_connect_direct succeeded for PHY %s, link=%d\n",
|
||||
dev_name(&phydev->dev), phydev->link);
|
||||
|
||||
phydev->autoneg = pdata->default_autoneg;
|
||||
if (phydev->autoneg == AUTONEG_DISABLE) {
|
||||
phydev->speed = pdata->default_speed;
|
||||
|
@ -386,9 +292,6 @@ int xgbe_mdio_register(struct xgbe_prv_data *pdata)
|
|||
|
||||
return 0;
|
||||
|
||||
err_phy_connect:
|
||||
phy_disconnect(phydev);
|
||||
|
||||
err_phy_device:
|
||||
phy_device_free(phydev);
|
||||
|
||||
|
@ -408,7 +311,6 @@ void xgbe_mdio_unregister(struct xgbe_prv_data *pdata)
|
|||
{
|
||||
DBGPR("-->xgbe_mdio_unregister\n");
|
||||
|
||||
phy_disconnect(pdata->phydev);
|
||||
pdata->phydev = NULL;
|
||||
|
||||
module_put(pdata->phy_module);
|
||||
|
|
Loading…
Reference in a new issue