|
|
|
|
@ -408,6 +408,11 @@ void am65_cpsw_nuss_set_p0_ptype(struct am65_cpsw_common *common)
|
|
|
|
|
writel(val, host_p->port_base + AM65_CPSW_PORT_REG_PRI_CTL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void am65_cpsw_init_host_port_switch(struct am65_cpsw_common *common);
|
|
|
|
|
static void am65_cpsw_init_host_port_emac(struct am65_cpsw_common *common);
|
|
|
|
|
static void am65_cpsw_init_port_switch_ale(struct am65_cpsw_port *port);
|
|
|
|
|
static void am65_cpsw_init_port_emac_ale(struct am65_cpsw_port *port);
|
|
|
|
|
|
|
|
|
|
static int am65_cpsw_nuss_common_open(struct am65_cpsw_common *common,
|
|
|
|
|
netdev_features_t features)
|
|
|
|
|
{
|
|
|
|
|
@ -454,9 +459,6 @@ static int am65_cpsw_nuss_common_open(struct am65_cpsw_common *common,
|
|
|
|
|
ALE_DEFAULT_THREAD_ID, 0);
|
|
|
|
|
cpsw_ale_control_set(common->ale, HOST_PORT_NUM,
|
|
|
|
|
ALE_DEFAULT_THREAD_ENABLE, 1);
|
|
|
|
|
if (AM65_CPSW_IS_CPSW2G(common))
|
|
|
|
|
cpsw_ale_control_set(common->ale, HOST_PORT_NUM,
|
|
|
|
|
ALE_PORT_NOLEARN, 1);
|
|
|
|
|
/* switch to vlan unaware mode */
|
|
|
|
|
cpsw_ale_control_set(common->ale, HOST_PORT_NUM, ALE_VLAN_AWARE, 1);
|
|
|
|
|
cpsw_ale_control_set(common->ale, HOST_PORT_NUM,
|
|
|
|
|
@ -470,6 +472,11 @@ static int am65_cpsw_nuss_common_open(struct am65_cpsw_common *common,
|
|
|
|
|
port_mask, port_mask,
|
|
|
|
|
port_mask & ~ALE_PORT_HOST);
|
|
|
|
|
|
|
|
|
|
if (common->is_emac_mode)
|
|
|
|
|
am65_cpsw_init_host_port_emac(common);
|
|
|
|
|
else
|
|
|
|
|
am65_cpsw_init_host_port_switch(common);
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < common->rx_chns.descs_num; i++) {
|
|
|
|
|
skb = __netdev_alloc_skb_ip_align(NULL,
|
|
|
|
|
AM65_CPSW_MAX_PACKET_SIZE,
|
|
|
|
|
@ -598,7 +605,6 @@ static int am65_cpsw_nuss_ndo_slave_open(struct net_device *ndev)
|
|
|
|
|
{
|
|
|
|
|
struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
|
|
|
|
|
struct am65_cpsw_port *port = am65_ndev_to_port(ndev);
|
|
|
|
|
u32 port_mask;
|
|
|
|
|
int ret, i;
|
|
|
|
|
|
|
|
|
|
ret = pm_runtime_get_sync(common->dev);
|
|
|
|
|
@ -631,19 +637,10 @@ static int am65_cpsw_nuss_ndo_slave_open(struct net_device *ndev)
|
|
|
|
|
|
|
|
|
|
am65_cpsw_port_set_sl_mac(port, ndev->dev_addr);
|
|
|
|
|
|
|
|
|
|
if (port->slave.mac_only) {
|
|
|
|
|
/* enable mac-only mode on port */
|
|
|
|
|
cpsw_ale_control_set(common->ale, port->port_id,
|
|
|
|
|
ALE_PORT_MACONLY, 1);
|
|
|
|
|
cpsw_ale_control_set(common->ale, port->port_id,
|
|
|
|
|
ALE_PORT_NOLEARN, 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
port_mask = BIT(port->port_id) | ALE_PORT_HOST;
|
|
|
|
|
cpsw_ale_add_ucast(common->ale, ndev->dev_addr,
|
|
|
|
|
HOST_PORT_NUM, ALE_SECURE, 0);
|
|
|
|
|
cpsw_ale_add_mcast(common->ale, ndev->broadcast,
|
|
|
|
|
port_mask, 0, 0, ALE_MCAST_FWD_2);
|
|
|
|
|
if (common->is_emac_mode)
|
|
|
|
|
am65_cpsw_init_port_emac_ale(port);
|
|
|
|
|
else
|
|
|
|
|
am65_cpsw_init_port_switch_ale(port);
|
|
|
|
|
|
|
|
|
|
/* mac_sl should be configured via phy-link interface */
|
|
|
|
|
am65_cpsw_sl_ctl_reset(port);
|
|
|
|
|
@ -1451,6 +1448,13 @@ static void am65_cpsw_nuss_ndo_get_stats(struct net_device *dev,
|
|
|
|
|
stats->tx_dropped = dev->stats.tx_dropped;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct devlink_port *am65_cpsw_ndo_get_devlink_port(struct net_device *ndev)
|
|
|
|
|
{
|
|
|
|
|
struct am65_cpsw_port *port = am65_ndev_to_port(ndev);
|
|
|
|
|
|
|
|
|
|
return &port->devlink_port;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const struct net_device_ops am65_cpsw_nuss_netdev_ops = {
|
|
|
|
|
.ndo_open = am65_cpsw_nuss_ndo_slave_open,
|
|
|
|
|
.ndo_stop = am65_cpsw_nuss_ndo_slave_stop,
|
|
|
|
|
@ -1464,6 +1468,7 @@ static const struct net_device_ops am65_cpsw_nuss_netdev_ops = {
|
|
|
|
|
.ndo_vlan_rx_kill_vid = am65_cpsw_nuss_ndo_slave_kill_vid,
|
|
|
|
|
.ndo_do_ioctl = am65_cpsw_nuss_ndo_slave_ioctl,
|
|
|
|
|
.ndo_setup_tc = am65_cpsw_qos_ndo_setup_tc,
|
|
|
|
|
.ndo_get_devlink_port = am65_cpsw_ndo_get_devlink_port,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static void am65_cpsw_nuss_slave_disable_unused(struct am65_cpsw_port *port)
|
|
|
|
|
@ -2031,6 +2036,316 @@ static void am65_cpsw_nuss_cleanup_ndev(struct am65_cpsw_common *common)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const struct devlink_ops am65_cpsw_devlink_ops = {};
|
|
|
|
|
|
|
|
|
|
static void am65_cpsw_init_stp_ale_entry(struct am65_cpsw_common *cpsw)
|
|
|
|
|
{
|
|
|
|
|
cpsw_ale_add_mcast(cpsw->ale, eth_stp_addr, ALE_PORT_HOST, ALE_SUPER, 0,
|
|
|
|
|
ALE_MCAST_BLOCK_LEARN_FWD);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void am65_cpsw_init_host_port_switch(struct am65_cpsw_common *common)
|
|
|
|
|
{
|
|
|
|
|
struct am65_cpsw_host *host = am65_common_get_host(common);
|
|
|
|
|
|
|
|
|
|
writel(common->default_vlan, host->port_base + AM65_CPSW_PORT_VLAN_REG_OFFSET);
|
|
|
|
|
|
|
|
|
|
am65_cpsw_init_stp_ale_entry(common);
|
|
|
|
|
|
|
|
|
|
cpsw_ale_control_set(common->ale, HOST_PORT_NUM, ALE_P0_UNI_FLOOD, 1);
|
|
|
|
|
dev_dbg(common->dev, "Set P0_UNI_FLOOD\n");
|
|
|
|
|
cpsw_ale_control_set(common->ale, HOST_PORT_NUM, ALE_PORT_NOLEARN, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void am65_cpsw_init_host_port_emac(struct am65_cpsw_common *common)
|
|
|
|
|
{
|
|
|
|
|
struct am65_cpsw_host *host = am65_common_get_host(common);
|
|
|
|
|
|
|
|
|
|
writel(0, host->port_base + AM65_CPSW_PORT_VLAN_REG_OFFSET);
|
|
|
|
|
|
|
|
|
|
cpsw_ale_control_set(common->ale, HOST_PORT_NUM, ALE_P0_UNI_FLOOD, 0);
|
|
|
|
|
dev_dbg(common->dev, "unset P0_UNI_FLOOD\n");
|
|
|
|
|
|
|
|
|
|
/* learning make no sense in multi-mac mode */
|
|
|
|
|
cpsw_ale_control_set(common->ale, HOST_PORT_NUM, ALE_PORT_NOLEARN, 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int am65_cpsw_dl_switch_mode_get(struct devlink *dl, u32 id,
|
|
|
|
|
struct devlink_param_gset_ctx *ctx)
|
|
|
|
|
{
|
|
|
|
|
struct am65_cpsw_devlink *dl_priv = devlink_priv(dl);
|
|
|
|
|
struct am65_cpsw_common *common = dl_priv->common;
|
|
|
|
|
|
|
|
|
|
dev_dbg(common->dev, "%s id:%u\n", __func__, id);
|
|
|
|
|
|
|
|
|
|
if (id != AM65_CPSW_DL_PARAM_SWITCH_MODE)
|
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
|
|
ctx->val.vbool = !common->is_emac_mode;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void am65_cpsw_init_port_emac_ale(struct am65_cpsw_port *port)
|
|
|
|
|
{
|
|
|
|
|
struct am65_cpsw_slave_data *slave = &port->slave;
|
|
|
|
|
struct am65_cpsw_common *common = port->common;
|
|
|
|
|
u32 port_mask;
|
|
|
|
|
|
|
|
|
|
writel(slave->port_vlan, port->port_base + AM65_CPSW_PORT_VLAN_REG_OFFSET);
|
|
|
|
|
|
|
|
|
|
if (slave->mac_only)
|
|
|
|
|
/* enable mac-only mode on port */
|
|
|
|
|
cpsw_ale_control_set(common->ale, port->port_id,
|
|
|
|
|
ALE_PORT_MACONLY, 1);
|
|
|
|
|
|
|
|
|
|
cpsw_ale_control_set(common->ale, port->port_id, ALE_PORT_NOLEARN, 1);
|
|
|
|
|
|
|
|
|
|
port_mask = BIT(port->port_id) | ALE_PORT_HOST;
|
|
|
|
|
|
|
|
|
|
cpsw_ale_add_ucast(common->ale, port->ndev->dev_addr,
|
|
|
|
|
HOST_PORT_NUM, ALE_SECURE, slave->port_vlan);
|
|
|
|
|
cpsw_ale_add_mcast(common->ale, port->ndev->broadcast,
|
|
|
|
|
port_mask, ALE_VLAN, slave->port_vlan, ALE_MCAST_FWD_2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void am65_cpsw_init_port_switch_ale(struct am65_cpsw_port *port)
|
|
|
|
|
{
|
|
|
|
|
struct am65_cpsw_slave_data *slave = &port->slave;
|
|
|
|
|
struct am65_cpsw_common *cpsw = port->common;
|
|
|
|
|
u32 port_mask;
|
|
|
|
|
|
|
|
|
|
cpsw_ale_control_set(cpsw->ale, port->port_id,
|
|
|
|
|
ALE_PORT_NOLEARN, 0);
|
|
|
|
|
|
|
|
|
|
cpsw_ale_add_ucast(cpsw->ale, port->ndev->dev_addr,
|
|
|
|
|
HOST_PORT_NUM, ALE_SECURE | ALE_BLOCKED | ALE_VLAN,
|
|
|
|
|
slave->port_vlan);
|
|
|
|
|
|
|
|
|
|
port_mask = BIT(port->port_id) | ALE_PORT_HOST;
|
|
|
|
|
|
|
|
|
|
cpsw_ale_add_mcast(cpsw->ale, port->ndev->broadcast,
|
|
|
|
|
port_mask, ALE_VLAN, slave->port_vlan,
|
|
|
|
|
ALE_MCAST_FWD_2);
|
|
|
|
|
|
|
|
|
|
writel(slave->port_vlan, port->port_base + AM65_CPSW_PORT_VLAN_REG_OFFSET);
|
|
|
|
|
|
|
|
|
|
cpsw_ale_control_set(cpsw->ale, port->port_id,
|
|
|
|
|
ALE_PORT_MACONLY, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int am65_cpsw_dl_switch_mode_set(struct devlink *dl, u32 id,
|
|
|
|
|
struct devlink_param_gset_ctx *ctx)
|
|
|
|
|
{
|
|
|
|
|
struct am65_cpsw_devlink *dl_priv = devlink_priv(dl);
|
|
|
|
|
struct am65_cpsw_common *cpsw = dl_priv->common;
|
|
|
|
|
bool switch_en = ctx->val.vbool;
|
|
|
|
|
bool if_running = false;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
dev_dbg(cpsw->dev, "%s id:%u\n", __func__, id);
|
|
|
|
|
|
|
|
|
|
if (id != AM65_CPSW_DL_PARAM_SWITCH_MODE)
|
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
|
|
if (switch_en == !cpsw->is_emac_mode)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if (!switch_en && cpsw->br_members) {
|
|
|
|
|
dev_err(cpsw->dev, "Remove ports from bridge before disabling switch mode\n");
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rtnl_lock();
|
|
|
|
|
|
|
|
|
|
cpsw->is_emac_mode = !switch_en;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < cpsw->port_num; i++) {
|
|
|
|
|
struct net_device *sl_ndev = cpsw->ports[i].ndev;
|
|
|
|
|
|
|
|
|
|
if (!sl_ndev || !netif_running(sl_ndev))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if_running = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!if_running) {
|
|
|
|
|
/* all ndevs are down */
|
|
|
|
|
for (i = 0; i < cpsw->port_num; i++) {
|
|
|
|
|
struct net_device *sl_ndev = cpsw->ports[i].ndev;
|
|
|
|
|
struct am65_cpsw_slave_data *slave;
|
|
|
|
|
|
|
|
|
|
if (!sl_ndev)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
slave = am65_ndev_to_slave(sl_ndev);
|
|
|
|
|
if (switch_en)
|
|
|
|
|
slave->port_vlan = cpsw->default_vlan;
|
|
|
|
|
else
|
|
|
|
|
slave->port_vlan = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
goto exit;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cpsw_ale_control_set(cpsw->ale, 0, ALE_BYPASS, 1);
|
|
|
|
|
/* clean up ALE table */
|
|
|
|
|
cpsw_ale_control_set(cpsw->ale, HOST_PORT_NUM, ALE_CLEAR, 1);
|
|
|
|
|
cpsw_ale_control_get(cpsw->ale, HOST_PORT_NUM, ALE_AGEOUT);
|
|
|
|
|
|
|
|
|
|
if (switch_en) {
|
|
|
|
|
dev_info(cpsw->dev, "Enable switch mode\n");
|
|
|
|
|
|
|
|
|
|
am65_cpsw_init_host_port_switch(cpsw);
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < cpsw->port_num; i++) {
|
|
|
|
|
struct net_device *sl_ndev = cpsw->ports[i].ndev;
|
|
|
|
|
struct am65_cpsw_slave_data *slave;
|
|
|
|
|
struct am65_cpsw_port *port;
|
|
|
|
|
|
|
|
|
|
if (!sl_ndev)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
port = am65_ndev_to_port(sl_ndev);
|
|
|
|
|
slave = am65_ndev_to_slave(sl_ndev);
|
|
|
|
|
slave->port_vlan = cpsw->default_vlan;
|
|
|
|
|
|
|
|
|
|
if (netif_running(sl_ndev))
|
|
|
|
|
am65_cpsw_init_port_switch_ale(port);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
dev_info(cpsw->dev, "Disable switch mode\n");
|
|
|
|
|
|
|
|
|
|
am65_cpsw_init_host_port_emac(cpsw);
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < cpsw->port_num; i++) {
|
|
|
|
|
struct net_device *sl_ndev = cpsw->ports[i].ndev;
|
|
|
|
|
struct am65_cpsw_port *port;
|
|
|
|
|
|
|
|
|
|
if (!sl_ndev)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
port = am65_ndev_to_port(sl_ndev);
|
|
|
|
|
port->slave.port_vlan = 0;
|
|
|
|
|
if (netif_running(sl_ndev))
|
|
|
|
|
am65_cpsw_init_port_emac_ale(port);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
cpsw_ale_control_set(cpsw->ale, HOST_PORT_NUM, ALE_BYPASS, 0);
|
|
|
|
|
exit:
|
|
|
|
|
rtnl_unlock();
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const struct devlink_param am65_cpsw_devlink_params[] = {
|
|
|
|
|
DEVLINK_PARAM_DRIVER(AM65_CPSW_DL_PARAM_SWITCH_MODE, "switch_mode",
|
|
|
|
|
DEVLINK_PARAM_TYPE_BOOL,
|
|
|
|
|
BIT(DEVLINK_PARAM_CMODE_RUNTIME),
|
|
|
|
|
am65_cpsw_dl_switch_mode_get,
|
|
|
|
|
am65_cpsw_dl_switch_mode_set, NULL),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static void am65_cpsw_unregister_devlink_ports(struct am65_cpsw_common *common)
|
|
|
|
|
{
|
|
|
|
|
struct devlink_port *dl_port;
|
|
|
|
|
struct am65_cpsw_port *port;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i = 1; i <= common->port_num; i++) {
|
|
|
|
|
port = am65_common_get_port(common, i);
|
|
|
|
|
dl_port = &port->devlink_port;
|
|
|
|
|
|
|
|
|
|
if (dl_port->registered)
|
|
|
|
|
devlink_port_unregister(dl_port);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int am65_cpsw_nuss_register_devlink(struct am65_cpsw_common *common)
|
|
|
|
|
{
|
|
|
|
|
struct devlink_port_attrs attrs = {};
|
|
|
|
|
struct am65_cpsw_devlink *dl_priv;
|
|
|
|
|
struct device *dev = common->dev;
|
|
|
|
|
struct devlink_port *dl_port;
|
|
|
|
|
struct am65_cpsw_port *port;
|
|
|
|
|
int ret = 0;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
common->devlink =
|
|
|
|
|
devlink_alloc(&am65_cpsw_devlink_ops, sizeof(*dl_priv));
|
|
|
|
|
if (!common->devlink)
|
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
|
|
dl_priv = devlink_priv(common->devlink);
|
|
|
|
|
dl_priv->common = common;
|
|
|
|
|
|
|
|
|
|
ret = devlink_register(common->devlink, dev);
|
|
|
|
|
if (ret) {
|
|
|
|
|
dev_err(dev, "devlink reg fail ret:%d\n", ret);
|
|
|
|
|
goto dl_free;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Provide devlink hook to switch mode when multiple external ports
|
|
|
|
|
* are present NUSS switchdev driver is enabled.
|
|
|
|
|
*/
|
|
|
|
|
if (!AM65_CPSW_IS_CPSW2G(common) &&
|
|
|
|
|
IS_ENABLED(CONFIG_TI_K3_AM65_CPSW_SWITCHDEV)) {
|
|
|
|
|
ret = devlink_params_register(common->devlink,
|
|
|
|
|
am65_cpsw_devlink_params,
|
|
|
|
|
ARRAY_SIZE(am65_cpsw_devlink_params));
|
|
|
|
|
if (ret) {
|
|
|
|
|
dev_err(dev, "devlink params reg fail ret:%d\n", ret);
|
|
|
|
|
goto dl_unreg;
|
|
|
|
|
}
|
|
|
|
|
devlink_params_publish(common->devlink);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (i = 1; i <= common->port_num; i++) {
|
|
|
|
|
port = am65_common_get_port(common, i);
|
|
|
|
|
dl_port = &port->devlink_port;
|
|
|
|
|
|
|
|
|
|
attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL;
|
|
|
|
|
attrs.phys.port_number = port->port_id;
|
|
|
|
|
attrs.switch_id.id_len = sizeof(resource_size_t);
|
|
|
|
|
memcpy(attrs.switch_id.id, common->switch_id, attrs.switch_id.id_len);
|
|
|
|
|
devlink_port_attrs_set(dl_port, &attrs);
|
|
|
|
|
|
|
|
|
|
ret = devlink_port_register(common->devlink, dl_port, port->port_id);
|
|
|
|
|
if (ret) {
|
|
|
|
|
dev_err(dev, "devlink_port reg fail for port %d, ret:%d\n",
|
|
|
|
|
port->port_id, ret);
|
|
|
|
|
goto dl_port_unreg;
|
|
|
|
|
}
|
|
|
|
|
devlink_port_type_eth_set(dl_port, port->ndev);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
|
|
dl_port_unreg:
|
|
|
|
|
am65_cpsw_unregister_devlink_ports(common);
|
|
|
|
|
dl_unreg:
|
|
|
|
|
devlink_unregister(common->devlink);
|
|
|
|
|
dl_free:
|
|
|
|
|
devlink_free(common->devlink);
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void am65_cpsw_unregister_devlink(struct am65_cpsw_common *common)
|
|
|
|
|
{
|
|
|
|
|
if (!AM65_CPSW_IS_CPSW2G(common) &&
|
|
|
|
|
IS_ENABLED(CONFIG_TI_K3_AM65_CPSW_SWITCHDEV)) {
|
|
|
|
|
devlink_params_unpublish(common->devlink);
|
|
|
|
|
devlink_params_unregister(common->devlink, am65_cpsw_devlink_params,
|
|
|
|
|
ARRAY_SIZE(am65_cpsw_devlink_params));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
am65_cpsw_unregister_devlink_ports(common);
|
|
|
|
|
devlink_unregister(common->devlink);
|
|
|
|
|
devlink_free(common->devlink);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int am65_cpsw_nuss_register_ndevs(struct am65_cpsw_common *common)
|
|
|
|
|
{
|
|
|
|
|
struct device *dev = common->dev;
|
|
|
|
|
@ -2064,12 +2379,15 @@ static int am65_cpsw_nuss_register_ndevs(struct am65_cpsw_common *common)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ret = am65_cpsw_nuss_register_devlink(common);
|
|
|
|
|
if (ret)
|
|
|
|
|
goto err_cleanup_ndev;
|
|
|
|
|
|
|
|
|
|
/* can't auto unregister ndev using devm_add_action() due to
|
|
|
|
|
* devres release sequence in DD core for DMA
|
|
|
|
|
*/
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
err_cleanup_ndev:
|
|
|
|
|
am65_cpsw_nuss_cleanup_ndev(common);
|
|
|
|
|
return ret;
|
|
|
|
|
@ -2151,6 +2469,7 @@ static int am65_cpsw_nuss_probe(struct platform_device *pdev)
|
|
|
|
|
struct device_node *node;
|
|
|
|
|
struct resource *res;
|
|
|
|
|
struct clk *clk;
|
|
|
|
|
u64 id_temp;
|
|
|
|
|
int ret, i;
|
|
|
|
|
|
|
|
|
|
common = devm_kzalloc(dev, sizeof(struct am65_cpsw_common), GFP_KERNEL);
|
|
|
|
|
@ -2170,6 +2489,9 @@ static int am65_cpsw_nuss_probe(struct platform_device *pdev)
|
|
|
|
|
if (IS_ERR(common->ss_base))
|
|
|
|
|
return PTR_ERR(common->ss_base);
|
|
|
|
|
common->cpsw_base = common->ss_base + AM65_CPSW_CPSW_NU_BASE;
|
|
|
|
|
/* Use device's physical base address as switch id */
|
|
|
|
|
id_temp = cpu_to_be64(res->start);
|
|
|
|
|
memcpy(common->switch_id, &id_temp, sizeof(res->start));
|
|
|
|
|
|
|
|
|
|
node = of_get_child_by_name(dev->of_node, "ethernet-ports");
|
|
|
|
|
if (!node)
|
|
|
|
|
@ -2183,6 +2505,7 @@ static int am65_cpsw_nuss_probe(struct platform_device *pdev)
|
|
|
|
|
init_completion(&common->tdown_complete);
|
|
|
|
|
common->tx_ch_num = 1;
|
|
|
|
|
common->pf_p0_rx_ptype_rrobin = false;
|
|
|
|
|
common->default_vlan = 1;
|
|
|
|
|
|
|
|
|
|
common->ports = devm_kcalloc(dev, common->port_num,
|
|
|
|
|
sizeof(*common->ports),
|
|
|
|
|
@ -2262,6 +2585,8 @@ static int am65_cpsw_nuss_probe(struct platform_device *pdev)
|
|
|
|
|
|
|
|
|
|
dev_set_drvdata(dev, common);
|
|
|
|
|
|
|
|
|
|
common->is_emac_mode = true;
|
|
|
|
|
|
|
|
|
|
ret = am65_cpsw_nuss_init_ndevs(common);
|
|
|
|
|
if (ret)
|
|
|
|
|
goto err_of_clear;
|
|
|
|
|
@ -2295,6 +2620,8 @@ static int am65_cpsw_nuss_remove(struct platform_device *pdev)
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
am65_cpsw_unregister_devlink(common);
|
|
|
|
|
|
|
|
|
|
/* must unregister ndevs here because DD release_driver routine calls
|
|
|
|
|
* dma_deconfigure(dev) before devres_release_all(dev)
|
|
|
|
|
*/
|
|
|
|
|
|