summaryrefslogtreecommitdiff
path: root/drivers/net/ethernet/marvell/prestera/prestera_main.c
diff options
context:
space:
mode:
authorVolodymyr Mytnyk <vmytnyk@marvell.com>2021-10-29 08:38:07 +0300
committerDavid S. Miller <davem@davemloft.net>2021-10-29 13:55:29 +0100
commitbb5dbf2cc64d5cfa696765944c784c0010c48ae8 (patch)
tree313ebedc308f297e345b4416f30615b7bfb41940 /drivers/net/ethernet/marvell/prestera/prestera_main.c
parentc52ef04d592024c007ea596e05c72bfc671757b5 (diff)
net: marvell: prestera: add firmware v4.0 support
Add firmware (FW) version 4.0 support for Marvell Prestera driver. Major changes have been made to new v4.0 FW ABI to add support of new features, introduce the stability of the FW ABI and ensure better forward compatibility for the future driver vesrions. Current v4.0 FW feature set support does not expect any changes to ABI, as it was defined and tested through long period of time. The ABI may be extended in case of new features, but it will not break the backward compatibility. ABI major changes done in v4.0: - L1 ABI, where MAC and PHY API configuration are split. - ACL has been split to low-level TCAM and Counters ABI to provide more HW ACL capabilities for future driver versions. To support backward support, the addition compatibility layer is required in the driver which will have two different codebase under "if FW-VER elif FW-VER else" conditions that will be removed in the future anyway, So, the idea was to break backward support and focus on more stable FW instead of supporting old version with very minimal and limited set of features/capabilities. Improve FW msg validation: * Use __le64, __le32, __le16 types in msg to/from FW to catch endian mismatch by sparse. * Use BUILD_BUG_ON for structures sent/recv to/from FW. Co-developed-by: Vadym Kochan <vkochan@marvell.com> Signed-off-by: Vadym Kochan <vkochan@marvell.com> Signed-off-by: Yevhen Orlov <yevhen.orlov@plvision.eu> Signed-off-by: Taras Chornyi <tchornyi@marvell.com> Signed-off-by: Volodymyr Mytnyk <vmytnyk@marvell.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/marvell/prestera/prestera_main.c')
-rw-r--r--drivers/net/ethernet/marvell/prestera/prestera_main.c144
1 files changed, 100 insertions, 44 deletions
diff --git a/drivers/net/ethernet/marvell/prestera/prestera_main.c b/drivers/net/ethernet/marvell/prestera/prestera_main.c
index d0d5a229d19d..625b40149fac 100644
--- a/drivers/net/ethernet/marvell/prestera/prestera_main.c
+++ b/drivers/net/ethernet/marvell/prestera/prestera_main.c
@@ -80,27 +80,76 @@ struct prestera_port *prestera_find_port(struct prestera_switch *sw, u32 id)
return port;
}
-static int prestera_port_open(struct net_device *dev)
+int prestera_port_cfg_mac_read(struct prestera_port *port,
+ struct prestera_port_mac_config *cfg)
+{
+ *cfg = port->cfg_mac;
+ return 0;
+}
+
+int prestera_port_cfg_mac_write(struct prestera_port *port,
+ struct prestera_port_mac_config *cfg)
{
- struct prestera_port *port = netdev_priv(dev);
int err;
- err = prestera_hw_port_state_set(port, true);
+ err = prestera_hw_port_mac_mode_set(port, cfg->admin,
+ cfg->mode, cfg->inband, cfg->speed,
+ cfg->duplex, cfg->fec);
if (err)
return err;
+ port->cfg_mac = *cfg;
+ return 0;
+}
+
+static int prestera_port_open(struct net_device *dev)
+{
+ struct prestera_port *port = netdev_priv(dev);
+ struct prestera_port_mac_config cfg_mac;
+ int err = 0;
+
+ if (port->caps.transceiver == PRESTERA_PORT_TCVR_SFP) {
+ err = prestera_port_cfg_mac_read(port, &cfg_mac);
+ if (!err) {
+ cfg_mac.admin = true;
+ err = prestera_port_cfg_mac_write(port, &cfg_mac);
+ }
+ } else {
+ port->cfg_phy.admin = true;
+ err = prestera_hw_port_phy_mode_set(port, true, port->autoneg,
+ port->cfg_phy.mode,
+ port->adver_link_modes,
+ port->cfg_phy.mdix);
+ }
+
netif_start_queue(dev);
- return 0;
+ return err;
}
static int prestera_port_close(struct net_device *dev)
{
struct prestera_port *port = netdev_priv(dev);
+ struct prestera_port_mac_config cfg_mac;
+ int err = 0;
netif_stop_queue(dev);
- return prestera_hw_port_state_set(port, false);
+ if (port->caps.transceiver == PRESTERA_PORT_TCVR_SFP) {
+ err = prestera_port_cfg_mac_read(port, &cfg_mac);
+ if (!err) {
+ cfg_mac.admin = false;
+ prestera_port_cfg_mac_write(port, &cfg_mac);
+ }
+ } else {
+ port->cfg_phy.admin = false;
+ err = prestera_hw_port_phy_mode_set(port, false, port->autoneg,
+ port->cfg_phy.mode,
+ port->adver_link_modes,
+ port->cfg_phy.mdix);
+ }
+
+ return err;
}
static netdev_tx_t prestera_port_xmit(struct sk_buff *skb,
@@ -228,46 +277,23 @@ static const struct net_device_ops prestera_netdev_ops = {
.ndo_get_devlink_port = prestera_devlink_get_port,
};
-int prestera_port_autoneg_set(struct prestera_port *port, bool enable,
- u64 adver_link_modes, u8 adver_fec)
+int prestera_port_autoneg_set(struct prestera_port *port, u64 link_modes)
{
- bool refresh = false;
- u64 link_modes;
int err;
- u8 fec;
-
- if (port->caps.type != PRESTERA_PORT_TYPE_TP)
- return enable ? -EINVAL : 0;
-
- if (!enable)
- goto set_autoneg;
-
- link_modes = port->caps.supp_link_modes & adver_link_modes;
- fec = port->caps.supp_fec & adver_fec;
-
- if (!link_modes && !fec)
- return -EOPNOTSUPP;
-
- if (link_modes && port->adver_link_modes != link_modes) {
- port->adver_link_modes = link_modes;
- refresh = true;
- }
-
- if (fec && port->adver_fec != fec) {
- port->adver_fec = fec;
- refresh = true;
- }
-set_autoneg:
- if (port->autoneg == enable && !refresh)
+ if (port->autoneg && port->adver_link_modes == link_modes)
return 0;
- err = prestera_hw_port_autoneg_set(port, enable, port->adver_link_modes,
- port->adver_fec);
+ err = prestera_hw_port_phy_mode_set(port, port->cfg_phy.admin,
+ true, 0, link_modes,
+ port->cfg_phy.mdix);
if (err)
return err;
- port->autoneg = enable;
+ port->adver_fec = BIT(PRESTERA_PORT_FEC_OFF);
+ port->adver_link_modes = link_modes;
+ port->cfg_phy.mode = 0;
+ port->autoneg = true;
return 0;
}
@@ -288,6 +314,7 @@ static void prestera_port_list_del(struct prestera_port *port)
static int prestera_port_create(struct prestera_switch *sw, u32 id)
{
+ struct prestera_port_mac_config cfg_mac;
struct prestera_port *port;
struct net_device *dev;
int err;
@@ -359,16 +386,43 @@ static int prestera_port_create(struct prestera_switch *sw, u32 id)
goto err_port_init;
}
- port->adver_fec = BIT(PRESTERA_PORT_FEC_OFF);
- prestera_port_autoneg_set(port, true, port->caps.supp_link_modes,
- port->caps.supp_fec);
+ port->adver_link_modes = port->caps.supp_link_modes;
+ port->adver_fec = 0;
+ port->autoneg = true;
+
+ /* initialize config mac */
+ if (port->caps.transceiver != PRESTERA_PORT_TCVR_SFP) {
+ cfg_mac.admin = true;
+ cfg_mac.mode = PRESTERA_MAC_MODE_INTERNAL;
+ } else {
+ cfg_mac.admin = false;
+ cfg_mac.mode = PRESTERA_MAC_MODE_MAX;
+ }
+ cfg_mac.inband = false;
+ cfg_mac.speed = 0;
+ cfg_mac.duplex = DUPLEX_UNKNOWN;
+ cfg_mac.fec = PRESTERA_PORT_FEC_OFF;
- err = prestera_hw_port_state_set(port, false);
+ err = prestera_port_cfg_mac_write(port, &cfg_mac);
if (err) {
- dev_err(prestera_dev(sw), "Failed to set port(%u) down\n", id);
+ dev_err(prestera_dev(sw), "Failed to set port(%u) mac mode\n", id);
goto err_port_init;
}
+ /* initialize config phy (if this is inegral) */
+ if (port->caps.transceiver != PRESTERA_PORT_TCVR_SFP) {
+ port->cfg_phy.mdix = ETH_TP_MDI_AUTO;
+ port->cfg_phy.admin = false;
+ err = prestera_hw_port_phy_mode_set(port,
+ port->cfg_phy.admin,
+ false, 0, 0,
+ port->cfg_phy.mdix);
+ if (err) {
+ dev_err(prestera_dev(sw), "Failed to set port(%u) phy mode\n", id);
+ goto err_port_init;
+ }
+ }
+
err = prestera_rxtx_port_init(port);
if (err)
goto err_port_init;
@@ -449,8 +503,10 @@ static void prestera_port_handle_event(struct prestera_switch *sw,
caching_dw = &port->cached_hw_stats.caching_dw;
- if (evt->id == PRESTERA_PORT_EVENT_STATE_CHANGED) {
- if (evt->port_evt.data.oper_state) {
+ prestera_ethtool_port_state_changed(port, &evt->port_evt);
+
+ if (evt->id == PRESTERA_PORT_EVENT_MAC_STATE_CHANGED) {
+ if (port->state_mac.oper) {
netif_carrier_on(port->dev);
if (!delayed_work_pending(caching_dw))
queue_delayed_work(prestera_wq, caching_dw, 0);