drivers: net: xgene: Add backward compatibility
This patch adds xgene_enet_check_phy_hanlde() function that checks whether MDIO driver is probed successfully and sets pdata->mdio_driver to true. If MDIO driver is not probed, ethernet driver falls back to backward compatibility mode. Since enum xgene_enet_cmd is used by MDIO driver, removing this from ethernet driver. Signed-off-by: Iyappan Subramanian <isubramanian@apm.com> Tested-by: Fushen Chen <fchen@apm.com> Tested-by: Toan Le <toanle@apm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
43b3cf6634
commit
8089a96f60
5 changed files with 100 additions and 53 deletions
|
@ -572,7 +572,9 @@ static void xgene_gmac_init(struct xgene_enet_pdata *pdata)
|
||||||
{
|
{
|
||||||
u32 value;
|
u32 value;
|
||||||
|
|
||||||
xgene_gmac_reset(pdata);
|
if (!pdata->mdio_driver)
|
||||||
|
xgene_gmac_reset(pdata);
|
||||||
|
|
||||||
xgene_gmac_set_speed(pdata);
|
xgene_gmac_set_speed(pdata);
|
||||||
xgene_gmac_set_mac_addr(pdata);
|
xgene_gmac_set_mac_addr(pdata);
|
||||||
|
|
||||||
|
@ -680,6 +682,11 @@ static int xgene_enet_reset(struct xgene_enet_pdata *pdata)
|
||||||
if (!xgene_ring_mgr_init(pdata))
|
if (!xgene_ring_mgr_init(pdata))
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
|
if (pdata->mdio_driver) {
|
||||||
|
xgene_enet_config_ring_if_assoc(pdata);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (dev->of_node) {
|
if (dev->of_node) {
|
||||||
clk_prepare_enable(pdata->clk);
|
clk_prepare_enable(pdata->clk);
|
||||||
udelay(5);
|
udelay(5);
|
||||||
|
@ -799,21 +806,47 @@ static void xgene_enet_adjust_link(struct net_device *ndev)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int xgene_enet_phy_connect(struct net_device *ndev)
|
#ifdef CONFIG_ACPI
|
||||||
|
static struct acpi_device *acpi_phy_find_device(struct device *dev)
|
||||||
|
{
|
||||||
|
struct acpi_reference_args args;
|
||||||
|
struct fwnode_handle *fw_node;
|
||||||
|
int status;
|
||||||
|
|
||||||
|
fw_node = acpi_fwnode_handle(ACPI_COMPANION(dev));
|
||||||
|
status = acpi_node_get_property_reference(fw_node, "phy-handle", 0,
|
||||||
|
&args);
|
||||||
|
if (ACPI_FAILURE(status)) {
|
||||||
|
dev_dbg(dev, "No matching phy in ACPI table\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return args.adev;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int xgene_enet_phy_connect(struct net_device *ndev)
|
||||||
{
|
{
|
||||||
struct xgene_enet_pdata *pdata = netdev_priv(ndev);
|
struct xgene_enet_pdata *pdata = netdev_priv(ndev);
|
||||||
struct device_node *phy_np;
|
struct device_node *np;
|
||||||
struct phy_device *phy_dev;
|
struct phy_device *phy_dev;
|
||||||
struct device *dev = &pdata->pdev->dev;
|
struct device *dev = &pdata->pdev->dev;
|
||||||
|
struct acpi_device *adev;
|
||||||
|
int i;
|
||||||
|
|
||||||
if (dev->of_node) {
|
if (dev->of_node) {
|
||||||
phy_np = of_parse_phandle(dev->of_node, "phy-handle", 0);
|
for (i = 0 ; i < 2; i++) {
|
||||||
if (!phy_np) {
|
np = of_parse_phandle(dev->of_node, "phy-handle", i);
|
||||||
|
if (np)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!np) {
|
||||||
netdev_dbg(ndev, "No phy-handle found in DT\n");
|
netdev_dbg(ndev, "No phy-handle found in DT\n");
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
phy_dev = of_phy_connect(ndev, phy_np, &xgene_enet_adjust_link,
|
phy_dev = of_phy_connect(ndev, np, &xgene_enet_adjust_link,
|
||||||
0, pdata->phy_mode);
|
0, pdata->phy_mode);
|
||||||
if (!phy_dev) {
|
if (!phy_dev) {
|
||||||
netdev_err(ndev, "Could not connect to PHY\n");
|
netdev_err(ndev, "Could not connect to PHY\n");
|
||||||
|
@ -822,6 +855,11 @@ static int xgene_enet_phy_connect(struct net_device *ndev)
|
||||||
|
|
||||||
pdata->phy_dev = phy_dev;
|
pdata->phy_dev = phy_dev;
|
||||||
} else {
|
} else {
|
||||||
|
#ifdef CONFIG_ACPI
|
||||||
|
adev = acpi_phy_find_device(dev);
|
||||||
|
if (adev)
|
||||||
|
pdata->phy_dev = adev->driver_data;
|
||||||
|
|
||||||
phy_dev = pdata->phy_dev;
|
phy_dev = pdata->phy_dev;
|
||||||
|
|
||||||
if (!phy_dev ||
|
if (!phy_dev ||
|
||||||
|
@ -830,6 +868,7 @@ static int xgene_enet_phy_connect(struct net_device *ndev)
|
||||||
netdev_err(ndev, "Could not connect to PHY\n");
|
netdev_err(ndev, "Could not connect to PHY\n");
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
pdata->phy_speed = SPEED_UNKNOWN;
|
pdata->phy_speed = SPEED_UNKNOWN;
|
||||||
|
@ -930,6 +969,12 @@ int xgene_enet_mdio_config(struct xgene_enet_pdata *pdata)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void xgene_enet_phy_disconnect(struct xgene_enet_pdata *pdata)
|
||||||
|
{
|
||||||
|
if (pdata->phy_dev)
|
||||||
|
phy_disconnect(pdata->phy_dev);
|
||||||
|
}
|
||||||
|
|
||||||
void xgene_enet_mdio_remove(struct xgene_enet_pdata *pdata)
|
void xgene_enet_mdio_remove(struct xgene_enet_pdata *pdata)
|
||||||
{
|
{
|
||||||
if (pdata->phy_dev)
|
if (pdata->phy_dev)
|
||||||
|
|
|
@ -301,11 +301,6 @@ enum xgene_enet_ring_bufnum {
|
||||||
RING_BUFNUM_INVALID
|
RING_BUFNUM_INVALID
|
||||||
};
|
};
|
||||||
|
|
||||||
enum xgene_enet_cmd {
|
|
||||||
XGENE_ENET_WR_CMD = BIT(31),
|
|
||||||
XGENE_ENET_RD_CMD = BIT(30)
|
|
||||||
};
|
|
||||||
|
|
||||||
enum xgene_enet_err_code {
|
enum xgene_enet_err_code {
|
||||||
HBF_READ_DATA = 3,
|
HBF_READ_DATA = 3,
|
||||||
HBF_LL_READ = 4,
|
HBF_LL_READ = 4,
|
||||||
|
@ -351,6 +346,8 @@ void xgene_enet_parse_error(struct xgene_enet_desc_ring *ring,
|
||||||
int xgene_enet_mdio_config(struct xgene_enet_pdata *pdata);
|
int xgene_enet_mdio_config(struct xgene_enet_pdata *pdata);
|
||||||
void xgene_enet_mdio_remove(struct xgene_enet_pdata *pdata);
|
void xgene_enet_mdio_remove(struct xgene_enet_pdata *pdata);
|
||||||
bool xgene_ring_mgr_init(struct xgene_enet_pdata *p);
|
bool xgene_ring_mgr_init(struct xgene_enet_pdata *p);
|
||||||
|
int xgene_enet_phy_connect(struct net_device *ndev);
|
||||||
|
void xgene_enet_phy_disconnect(struct xgene_enet_pdata *pdata);
|
||||||
|
|
||||||
extern const struct xgene_mac_ops xgene_gmac_ops;
|
extern const struct xgene_mac_ops xgene_gmac_ops;
|
||||||
extern const struct xgene_port_ops xgene_gport_ops;
|
extern const struct xgene_port_ops xgene_gport_ops;
|
||||||
|
|
|
@ -763,7 +763,7 @@ static int xgene_enet_close(struct net_device *ndev)
|
||||||
mac_ops->tx_disable(pdata);
|
mac_ops->tx_disable(pdata);
|
||||||
mac_ops->rx_disable(pdata);
|
mac_ops->rx_disable(pdata);
|
||||||
|
|
||||||
if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII)
|
if (pdata->phy_dev)
|
||||||
phy_stop(pdata->phy_dev);
|
phy_stop(pdata->phy_dev);
|
||||||
else
|
else
|
||||||
cancel_delayed_work_sync(&pdata->link_work);
|
cancel_delayed_work_sync(&pdata->link_work);
|
||||||
|
@ -1295,6 +1295,23 @@ static int xgene_enet_get_irqs(struct xgene_enet_pdata *pdata)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int xgene_enet_check_phy_handle(struct xgene_enet_pdata *pdata)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (pdata->phy_mode == PHY_INTERFACE_MODE_XGMII)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!IS_ENABLED(CONFIG_MDIO_XGENE))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
ret = xgene_enet_phy_connect(pdata->ndev);
|
||||||
|
if (!ret)
|
||||||
|
pdata->mdio_driver = true;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata)
|
static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata)
|
||||||
{
|
{
|
||||||
struct platform_device *pdev;
|
struct platform_device *pdev;
|
||||||
|
@ -1380,6 +1397,10 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata)
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
ret = xgene_enet_check_phy_handle(pdata);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
pdata->clk = devm_clk_get(&pdev->dev, NULL);
|
pdata->clk = devm_clk_get(&pdev->dev, NULL);
|
||||||
if (IS_ERR(pdata->clk)) {
|
if (IS_ERR(pdata->clk)) {
|
||||||
/* Firmware may have set up the clock already. */
|
/* Firmware may have set up the clock already. */
|
||||||
|
@ -1574,7 +1595,7 @@ static int xgene_enet_probe(struct platform_device *pdev)
|
||||||
struct net_device *ndev;
|
struct net_device *ndev;
|
||||||
struct xgene_enet_pdata *pdata;
|
struct xgene_enet_pdata *pdata;
|
||||||
struct device *dev = &pdev->dev;
|
struct device *dev = &pdev->dev;
|
||||||
const struct xgene_mac_ops *mac_ops;
|
void (*link_state)(struct work_struct *);
|
||||||
const struct of_device_id *of_id;
|
const struct of_device_id *of_id;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -1636,14 +1657,17 @@ static int xgene_enet_probe(struct platform_device *pdev)
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_netdev;
|
goto err_netdev;
|
||||||
|
|
||||||
mac_ops = pdata->mac_ops;
|
link_state = pdata->mac_ops->link_state;
|
||||||
if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) {
|
if (pdata->phy_mode == PHY_INTERFACE_MODE_XGMII) {
|
||||||
ret = xgene_enet_mdio_config(pdata);
|
INIT_DELAYED_WORK(&pdata->link_work, link_state);
|
||||||
if (ret)
|
} else if (!pdata->mdio_driver) {
|
||||||
goto err_netdev;
|
if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII)
|
||||||
} else {
|
ret = xgene_enet_mdio_config(pdata);
|
||||||
INIT_DELAYED_WORK(&pdata->link_work, mac_ops->link_state);
|
else
|
||||||
|
INIT_DELAYED_WORK(&pdata->link_work, link_state);
|
||||||
}
|
}
|
||||||
|
if (ret)
|
||||||
|
goto err;
|
||||||
|
|
||||||
xgene_enet_napi_add(pdata);
|
xgene_enet_napi_add(pdata);
|
||||||
ret = register_netdev(ndev);
|
ret = register_netdev(ndev);
|
||||||
|
@ -1676,11 +1700,11 @@ static int xgene_enet_remove(struct platform_device *pdev)
|
||||||
dev_close(ndev);
|
dev_close(ndev);
|
||||||
rtnl_unlock();
|
rtnl_unlock();
|
||||||
|
|
||||||
mac_ops->rx_disable(pdata);
|
if (pdata->mdio_driver)
|
||||||
mac_ops->tx_disable(pdata);
|
xgene_enet_phy_disconnect(pdata);
|
||||||
|
else if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII)
|
||||||
if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII)
|
|
||||||
xgene_enet_mdio_remove(pdata);
|
xgene_enet_mdio_remove(pdata);
|
||||||
|
|
||||||
unregister_netdev(ndev);
|
unregister_netdev(ndev);
|
||||||
pdata->port_ops->shutdown(pdata);
|
pdata->port_ops->shutdown(pdata);
|
||||||
xgene_enet_delete_desc_rings(pdata);
|
xgene_enet_delete_desc_rings(pdata);
|
||||||
|
|
|
@ -38,6 +38,7 @@
|
||||||
#include "xgene_enet_hw.h"
|
#include "xgene_enet_hw.h"
|
||||||
#include "xgene_enet_cle.h"
|
#include "xgene_enet_cle.h"
|
||||||
#include "xgene_enet_ring2.h"
|
#include "xgene_enet_ring2.h"
|
||||||
|
#include "../../../phy/mdio-xgene.h"
|
||||||
|
|
||||||
#define XGENE_DRV_VERSION "v1.0"
|
#define XGENE_DRV_VERSION "v1.0"
|
||||||
#define XGENE_ENET_MAX_MTU 1536
|
#define XGENE_ENET_MAX_MTU 1536
|
||||||
|
@ -214,6 +215,7 @@ struct xgene_enet_pdata {
|
||||||
u32 mss;
|
u32 mss;
|
||||||
u8 tx_delay;
|
u8 tx_delay;
|
||||||
u8 rx_delay;
|
u8 rx_delay;
|
||||||
|
bool mdio_driver;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct xgene_indirect_ctl {
|
struct xgene_indirect_ctl {
|
||||||
|
@ -223,34 +225,6 @@ struct xgene_indirect_ctl {
|
||||||
void __iomem *cmd_done;
|
void __iomem *cmd_done;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Set the specified value into a bit-field defined by its starting position
|
|
||||||
* and length within a single u64.
|
|
||||||
*/
|
|
||||||
static inline u64 xgene_enet_set_field_value(int pos, int len, u64 val)
|
|
||||||
{
|
|
||||||
return (val & ((1ULL << len) - 1)) << pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define SET_VAL(field, val) \
|
|
||||||
xgene_enet_set_field_value(field ## _POS, field ## _LEN, val)
|
|
||||||
|
|
||||||
#define SET_BIT(field) \
|
|
||||||
xgene_enet_set_field_value(field ## _POS, 1, 1)
|
|
||||||
|
|
||||||
/* Get the value from a bit-field defined by its starting position
|
|
||||||
* and length within the specified u64.
|
|
||||||
*/
|
|
||||||
static inline u64 xgene_enet_get_field_value(int pos, int len, u64 src)
|
|
||||||
{
|
|
||||||
return (src >> pos) & ((1ULL << len) - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define GET_VAL(field, src) \
|
|
||||||
xgene_enet_get_field_value(field ## _POS, field ## _LEN, src)
|
|
||||||
|
|
||||||
#define GET_BIT(field, src) \
|
|
||||||
xgene_enet_get_field_value(field ## _POS, 1, src)
|
|
||||||
|
|
||||||
static inline struct device *ndev_to_dev(struct net_device *ndev)
|
static inline struct device *ndev_to_dev(struct net_device *ndev)
|
||||||
{
|
{
|
||||||
return ndev->dev.parent;
|
return ndev->dev.parent;
|
||||||
|
|
|
@ -366,7 +366,9 @@ static void xgene_sgmac_init(struct xgene_enet_pdata *p)
|
||||||
u32 cfg_bypass_reg, rx_dv_gate_reg;
|
u32 cfg_bypass_reg, rx_dv_gate_reg;
|
||||||
u32 data, offset;
|
u32 data, offset;
|
||||||
|
|
||||||
xgene_sgmac_reset(p);
|
if (!(p->enet_id == XGENE_ENET2 && p->mdio_driver))
|
||||||
|
xgene_sgmac_reset(p);
|
||||||
|
|
||||||
xgene_sgmii_enable_autoneg(p);
|
xgene_sgmii_enable_autoneg(p);
|
||||||
xgene_sgmac_set_speed(p);
|
xgene_sgmac_set_speed(p);
|
||||||
xgene_sgmac_set_mac_addr(p);
|
xgene_sgmac_set_mac_addr(p);
|
||||||
|
@ -445,6 +447,11 @@ static int xgene_enet_reset(struct xgene_enet_pdata *p)
|
||||||
if (!xgene_ring_mgr_init(p))
|
if (!xgene_ring_mgr_init(p))
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
|
if (p->mdio_driver && p->enet_id == XGENE_ENET2) {
|
||||||
|
xgene_enet_config_ring_if_assoc(p);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (p->enet_id == XGENE_ENET2)
|
if (p->enet_id == XGENE_ENET2)
|
||||||
xgene_enet_wr_clkrst_csr(p, XGENET_CONFIG_REG_ADDR, SGMII_EN);
|
xgene_enet_wr_clkrst_csr(p, XGENET_CONFIG_REG_ADDR, SGMII_EN);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue