Commit 84b4aa49 authored by Grygorii Strashko's avatar Grygorii Strashko Committed by Jakub Kicinski

net: ethernet: ti: am65-cpsw: add multi port support in mac-only mode

This patch adds final multi-port support to TI AM65x CPSW driver path in
preparation for adding support for multi-port devices, like Main CPSW0 on
K3 J721E SoC or future CPSW3g on K3 AM64x SoC.
- the separate netdev is created for every enabled external Port;
- DMA channels are common/shared for all external Ports and the RX/TX NAPI
and DMA processing assigned to first available netdev;
- external Ports are configured in mac-only mode, which is similar to TI
"dual-mac" mode for legacy TI CPSW - packets are sent to the Host port only
in ingress and directly to the Port on egress. No packet switching between
external ports happens.
- every port supports the same features as current AM65x CPSW on external
device.
Signed-off-by: default avatarGrygorii Strashko <grygorii.strashko@ti.com>
Reviewed-by: default avatarJesse Brandeburg <jesse.brandeburg@intel.com>
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent a9e60cf0
...@@ -272,7 +272,7 @@ static int am65_cpsw_nuss_ndo_slave_kill_vid(struct net_device *ndev, ...@@ -272,7 +272,7 @@ static int am65_cpsw_nuss_ndo_slave_kill_vid(struct net_device *ndev,
return ret; return ret;
} }
static void am65_cpsw_slave_set_promisc_2g(struct am65_cpsw_port *port, static void am65_cpsw_slave_set_promisc(struct am65_cpsw_port *port,
bool promisc) bool promisc)
{ {
struct am65_cpsw_common *common = port->common; struct am65_cpsw_common *common = port->common;
...@@ -298,7 +298,7 @@ static void am65_cpsw_nuss_ndo_slave_set_rx_mode(struct net_device *ndev) ...@@ -298,7 +298,7 @@ static void am65_cpsw_nuss_ndo_slave_set_rx_mode(struct net_device *ndev)
bool promisc; bool promisc;
promisc = !!(ndev->flags & IFF_PROMISC); promisc = !!(ndev->flags & IFF_PROMISC);
am65_cpsw_slave_set_promisc_2g(port, promisc); am65_cpsw_slave_set_promisc(port, promisc);
if (promisc) if (promisc)
return; return;
...@@ -629,13 +629,13 @@ static int am65_cpsw_nuss_ndo_slave_open(struct net_device *ndev) ...@@ -629,13 +629,13 @@ static int am65_cpsw_nuss_ndo_slave_open(struct net_device *ndev)
am65_cpsw_port_set_sl_mac(port, ndev->dev_addr); am65_cpsw_port_set_sl_mac(port, ndev->dev_addr);
if (port->slave.mac_only) if (port->slave.mac_only) {
/* enable mac-only mode on port */ /* enable mac-only mode on port */
cpsw_ale_control_set(common->ale, port->port_id, cpsw_ale_control_set(common->ale, port->port_id,
ALE_PORT_MACONLY, 1); ALE_PORT_MACONLY, 1);
if (AM65_CPSW_IS_CPSW2G(common))
cpsw_ale_control_set(common->ale, port->port_id, cpsw_ale_control_set(common->ale, port->port_id,
ALE_PORT_NOLEARN, 1); ALE_PORT_NOLEARN, 1);
}
port_mask = BIT(port->port_id) | ALE_PORT_HOST; port_mask = BIT(port->port_id) | ALE_PORT_HOST;
cpsw_ale_add_ucast(common->ale, ndev->dev_addr, cpsw_ale_add_ucast(common->ale, ndev->dev_addr,
...@@ -1441,7 +1441,7 @@ static void am65_cpsw_nuss_ndo_get_stats(struct net_device *dev, ...@@ -1441,7 +1441,7 @@ static void am65_cpsw_nuss_ndo_get_stats(struct net_device *dev,
stats->tx_dropped = dev->stats.tx_dropped; stats->tx_dropped = dev->stats.tx_dropped;
} }
static const struct net_device_ops am65_cpsw_nuss_netdev_ops_2g = { static const struct net_device_ops am65_cpsw_nuss_netdev_ops = {
.ndo_open = am65_cpsw_nuss_ndo_slave_open, .ndo_open = am65_cpsw_nuss_ndo_slave_open,
.ndo_stop = am65_cpsw_nuss_ndo_slave_stop, .ndo_stop = am65_cpsw_nuss_ndo_slave_stop,
.ndo_start_xmit = am65_cpsw_nuss_ndo_slave_xmit, .ndo_start_xmit = am65_cpsw_nuss_ndo_slave_xmit,
...@@ -1463,7 +1463,6 @@ static void am65_cpsw_nuss_slave_disable_unused(struct am65_cpsw_port *port) ...@@ -1463,7 +1463,6 @@ static void am65_cpsw_nuss_slave_disable_unused(struct am65_cpsw_port *port)
if (!port->disabled) if (!port->disabled)
return; return;
common->disabled_ports_mask |= BIT(port->port_id);
cpsw_ale_control_set(common->ale, port->port_id, cpsw_ale_control_set(common->ale, port->port_id,
ALE_PORT_STATE, ALE_PORT_STATE_DISABLE); ALE_PORT_STATE, ALE_PORT_STATE_DISABLE);
...@@ -1832,8 +1831,10 @@ static int am65_cpsw_nuss_init_slave_ports(struct am65_cpsw_common *common) ...@@ -1832,8 +1831,10 @@ static int am65_cpsw_nuss_init_slave_ports(struct am65_cpsw_common *common)
return PTR_ERR(port->slave.mac_sl); return PTR_ERR(port->slave.mac_sl);
port->disabled = !of_device_is_available(port_np); port->disabled = !of_device_is_available(port_np);
if (port->disabled) if (port->disabled) {
common->disabled_ports_mask |= BIT(port->port_id);
continue; continue;
}
port->slave.ifphy = devm_of_phy_get(dev, port_np, NULL); port->slave.ifphy = devm_of_phy_get(dev, port_np, NULL);
if (IS_ERR(port->slave.ifphy)) { if (IS_ERR(port->slave.ifphy)) {
...@@ -1887,6 +1888,12 @@ static int am65_cpsw_nuss_init_slave_ports(struct am65_cpsw_common *common) ...@@ -1887,6 +1888,12 @@ static int am65_cpsw_nuss_init_slave_ports(struct am65_cpsw_common *common)
} }
of_node_put(node); of_node_put(node);
/* is there at least one ext.port */
if (!(~common->disabled_ports_mask & GENMASK(common->port_num, 1))) {
dev_err(dev, "No Ext. port are available\n");
return -ENODEV;
}
return 0; return 0;
} }
...@@ -1897,14 +1904,18 @@ static void am65_cpsw_pcpu_stats_free(void *data) ...@@ -1897,14 +1904,18 @@ static void am65_cpsw_pcpu_stats_free(void *data)
free_percpu(stats); free_percpu(stats);
} }
static int am65_cpsw_nuss_init_ndev_2g(struct am65_cpsw_common *common) static int
am65_cpsw_nuss_init_port_ndev(struct am65_cpsw_common *common, u32 port_idx)
{ {
struct am65_cpsw_ndev_priv *ndev_priv; struct am65_cpsw_ndev_priv *ndev_priv;
struct device *dev = common->dev; struct device *dev = common->dev;
struct am65_cpsw_port *port; struct am65_cpsw_port *port;
int ret; int ret;
port = am65_common_get_port(common, 1); port = &common->ports[port_idx];
if (port->disabled)
return 0;
/* alloc netdev */ /* alloc netdev */
port->ndev = devm_alloc_etherdev_mqs(common->dev, port->ndev = devm_alloc_etherdev_mqs(common->dev,
...@@ -1933,7 +1944,7 @@ static int am65_cpsw_nuss_init_ndev_2g(struct am65_cpsw_common *common) ...@@ -1933,7 +1944,7 @@ static int am65_cpsw_nuss_init_ndev_2g(struct am65_cpsw_common *common)
port->ndev->features = port->ndev->hw_features | port->ndev->features = port->ndev->hw_features |
NETIF_F_HW_VLAN_CTAG_FILTER; NETIF_F_HW_VLAN_CTAG_FILTER;
port->ndev->vlan_features |= NETIF_F_SG; port->ndev->vlan_features |= NETIF_F_SG;
port->ndev->netdev_ops = &am65_cpsw_nuss_netdev_ops_2g; port->ndev->netdev_ops = &am65_cpsw_nuss_netdev_ops;
port->ndev->ethtool_ops = &am65_cpsw_ethtool_ops_slave; port->ndev->ethtool_ops = &am65_cpsw_ethtool_ops_slave;
/* Disable TX checksum offload by default due to HW bug */ /* Disable TX checksum offload by default due to HW bug */
...@@ -1946,29 +1957,41 @@ static int am65_cpsw_nuss_init_ndev_2g(struct am65_cpsw_common *common) ...@@ -1946,29 +1957,41 @@ static int am65_cpsw_nuss_init_ndev_2g(struct am65_cpsw_common *common)
ret = devm_add_action_or_reset(dev, am65_cpsw_pcpu_stats_free, ret = devm_add_action_or_reset(dev, am65_cpsw_pcpu_stats_free,
ndev_priv->stats); ndev_priv->stats);
if (ret) { if (ret)
dev_err(dev, "Failed to add percpu stat free action %d\n", ret); dev_err(dev, "failed to add percpu stat free action %d\n", ret);
if (!common->dma_ndev)
common->dma_ndev = port->ndev;
return ret;
}
static int am65_cpsw_nuss_init_ndevs(struct am65_cpsw_common *common)
{
int ret;
int i;
for (i = 0; i < common->port_num; i++) {
ret = am65_cpsw_nuss_init_port_ndev(common, i);
if (ret)
return ret; return ret;
} }
netif_napi_add(port->ndev, &common->napi_rx, netif_napi_add(common->dma_ndev, &common->napi_rx,
am65_cpsw_nuss_rx_poll, NAPI_POLL_WEIGHT); am65_cpsw_nuss_rx_poll, NAPI_POLL_WEIGHT);
return ret; return ret;
} }
static int am65_cpsw_nuss_ndev_add_napi_2g(struct am65_cpsw_common *common) static int am65_cpsw_nuss_ndev_add_tx_napi(struct am65_cpsw_common *common)
{ {
struct device *dev = common->dev; struct device *dev = common->dev;
struct am65_cpsw_port *port;
int i, ret = 0; int i, ret = 0;
port = am65_common_get_port(common, 1);
for (i = 0; i < common->tx_ch_num; i++) { for (i = 0; i < common->tx_ch_num; i++) {
struct am65_cpsw_tx_chn *tx_chn = &common->tx_chns[i]; struct am65_cpsw_tx_chn *tx_chn = &common->tx_chns[i];
netif_tx_napi_add(port->ndev, &tx_chn->napi_tx, netif_tx_napi_add(common->dma_ndev, &tx_chn->napi_tx,
am65_cpsw_nuss_tx_poll, NAPI_POLL_WEIGHT); am65_cpsw_nuss_tx_poll, NAPI_POLL_WEIGHT);
ret = devm_request_irq(dev, tx_chn->irq, ret = devm_request_irq(dev, tx_chn->irq,
...@@ -1986,16 +2009,27 @@ static int am65_cpsw_nuss_ndev_add_napi_2g(struct am65_cpsw_common *common) ...@@ -1986,16 +2009,27 @@ static int am65_cpsw_nuss_ndev_add_napi_2g(struct am65_cpsw_common *common)
return ret; return ret;
} }
static int am65_cpsw_nuss_ndev_reg_2g(struct am65_cpsw_common *common) static void am65_cpsw_nuss_cleanup_ndev(struct am65_cpsw_common *common)
{
struct am65_cpsw_port *port;
int i;
for (i = 0; i < common->port_num; i++) {
port = &common->ports[i];
if (port->ndev)
unregister_netdev(port->ndev);
}
}
static int am65_cpsw_nuss_register_ndevs(struct am65_cpsw_common *common)
{ {
struct device *dev = common->dev; struct device *dev = common->dev;
struct am65_cpsw_port *port; struct am65_cpsw_port *port;
int ret = 0; int ret = 0, i;
port = am65_common_get_port(common, 1); ret = am65_cpsw_nuss_ndev_add_tx_napi(common);
ret = am65_cpsw_nuss_ndev_add_napi_2g(common);
if (ret) if (ret)
goto err; return ret;
ret = devm_request_irq(dev, common->rx_chns.irq, ret = devm_request_irq(dev, common->rx_chns.irq,
am65_cpsw_nuss_rx_irq, am65_cpsw_nuss_rx_irq,
...@@ -2003,17 +2037,31 @@ static int am65_cpsw_nuss_ndev_reg_2g(struct am65_cpsw_common *common) ...@@ -2003,17 +2037,31 @@ static int am65_cpsw_nuss_ndev_reg_2g(struct am65_cpsw_common *common)
if (ret) { if (ret) {
dev_err(dev, "failure requesting rx irq %u, %d\n", dev_err(dev, "failure requesting rx irq %u, %d\n",
common->rx_chns.irq, ret); common->rx_chns.irq, ret);
goto err; return ret;
} }
for (i = 0; i < common->port_num; i++) {
port = &common->ports[i];
if (!port->ndev)
continue;
ret = register_netdev(port->ndev); ret = register_netdev(port->ndev);
if (ret) if (ret) {
dev_err(dev, "error registering slave net device %d\n", ret); dev_err(dev, "error registering slave net device%i %d\n",
i, ret);
goto err_cleanup_ndev;
}
}
/* can't auto unregister ndev using devm_add_action() due to /* can't auto unregister ndev using devm_add_action() due to
* devres release sequence in DD core for DMA * devres release sequence in DD core for DMA
*/ */
err: return 0;
err_cleanup_ndev:
am65_cpsw_nuss_cleanup_ndev(common);
return ret; return ret;
} }
...@@ -2026,19 +2074,7 @@ int am65_cpsw_nuss_update_tx_chns(struct am65_cpsw_common *common, int num_tx) ...@@ -2026,19 +2074,7 @@ int am65_cpsw_nuss_update_tx_chns(struct am65_cpsw_common *common, int num_tx)
if (ret) if (ret)
return ret; return ret;
return am65_cpsw_nuss_ndev_add_napi_2g(common); return am65_cpsw_nuss_ndev_add_tx_napi(common);
}
static void am65_cpsw_nuss_cleanup_ndev(struct am65_cpsw_common *common)
{
struct am65_cpsw_port *port;
int i;
for (i = 0; i < common->port_num; i++) {
port = &common->ports[i];
if (port->ndev)
unregister_netdev(port->ndev);
}
} }
struct am65_cpsw_soc_pdata { struct am65_cpsw_soc_pdata {
...@@ -2126,9 +2162,6 @@ static int am65_cpsw_nuss_probe(struct platform_device *pdev) ...@@ -2126,9 +2162,6 @@ static int am65_cpsw_nuss_probe(struct platform_device *pdev)
return -ENOENT; return -ENOENT;
of_node_put(node); of_node_put(node);
if (common->port_num != 1)
return -EOPNOTSUPP;
common->rx_flow_id_base = -1; common->rx_flow_id_base = -1;
init_completion(&common->tdown_complete); init_completion(&common->tdown_complete);
common->tx_ch_num = 1; common->tx_ch_num = 1;
...@@ -2223,11 +2256,11 @@ static int am65_cpsw_nuss_probe(struct platform_device *pdev) ...@@ -2223,11 +2256,11 @@ static int am65_cpsw_nuss_probe(struct platform_device *pdev)
dev_set_drvdata(dev, common); dev_set_drvdata(dev, common);
ret = am65_cpsw_nuss_init_ndev_2g(common); ret = am65_cpsw_nuss_init_ndevs(common);
if (ret) if (ret)
goto err_of_clear; goto err_of_clear;
ret = am65_cpsw_nuss_ndev_reg_2g(common); ret = am65_cpsw_nuss_register_ndevs(common);
if (ret) if (ret)
goto err_of_clear; goto err_of_clear;
......
...@@ -95,6 +95,7 @@ struct am65_cpsw_common { ...@@ -95,6 +95,7 @@ struct am65_cpsw_common {
struct am65_cpsw_host host; struct am65_cpsw_host host;
struct am65_cpsw_port *ports; struct am65_cpsw_port *ports;
u32 disabled_ports_mask; u32 disabled_ports_mask;
struct net_device *dma_ndev;
int usage_count; /* number of opened ports */ int usage_count; /* number of opened ports */
struct cpsw_ale *ale; struct cpsw_ale *ale;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment