mirror of
https://github.com/torvalds/linux.git
synced 2024-11-26 14:12:06 +00:00
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>
This commit is contained in:
parent
c52ef04d59
commit
bb5dbf2cc6
@ -53,6 +53,8 @@ struct prestera_port_stats {
|
||||
u64 good_octets_sent;
|
||||
};
|
||||
|
||||
#define PRESTERA_AP_PORT_MAX (10)
|
||||
|
||||
struct prestera_port_caps {
|
||||
u64 supp_link_modes;
|
||||
u8 supp_fec;
|
||||
@ -69,6 +71,39 @@ struct prestera_lag {
|
||||
|
||||
struct prestera_flow_block;
|
||||
|
||||
struct prestera_port_mac_state {
|
||||
u32 mode;
|
||||
u32 speed;
|
||||
bool oper;
|
||||
u8 duplex;
|
||||
u8 fc;
|
||||
u8 fec;
|
||||
};
|
||||
|
||||
struct prestera_port_phy_state {
|
||||
u64 lmode_bmap;
|
||||
struct {
|
||||
bool pause;
|
||||
bool asym_pause;
|
||||
} remote_fc;
|
||||
u8 mdix;
|
||||
};
|
||||
|
||||
struct prestera_port_mac_config {
|
||||
u32 mode;
|
||||
u32 speed;
|
||||
bool admin;
|
||||
u8 inband;
|
||||
u8 duplex;
|
||||
u8 fec;
|
||||
};
|
||||
|
||||
struct prestera_port_phy_config {
|
||||
u32 mode;
|
||||
bool admin;
|
||||
u8 mdix;
|
||||
};
|
||||
|
||||
struct prestera_port {
|
||||
struct net_device *dev;
|
||||
struct prestera_switch *sw;
|
||||
@ -91,6 +126,10 @@ struct prestera_port {
|
||||
struct prestera_port_stats stats;
|
||||
struct delayed_work caching_dw;
|
||||
} cached_hw_stats;
|
||||
struct prestera_port_mac_config cfg_mac;
|
||||
struct prestera_port_phy_config cfg_phy;
|
||||
struct prestera_port_mac_state state_mac;
|
||||
struct prestera_port_phy_state state_phy;
|
||||
};
|
||||
|
||||
struct prestera_device {
|
||||
@ -107,7 +146,7 @@ struct prestera_device {
|
||||
int (*recv_msg)(struct prestera_device *dev, void *msg, size_t size);
|
||||
|
||||
/* called by higher layer to send request to the firmware */
|
||||
int (*send_req)(struct prestera_device *dev, void *in_msg,
|
||||
int (*send_req)(struct prestera_device *dev, int qid, void *in_msg,
|
||||
size_t in_size, void *out_msg, size_t out_size,
|
||||
unsigned int wait);
|
||||
};
|
||||
@ -129,13 +168,28 @@ enum prestera_rxtx_event_id {
|
||||
|
||||
enum prestera_port_event_id {
|
||||
PRESTERA_PORT_EVENT_UNSPEC,
|
||||
PRESTERA_PORT_EVENT_STATE_CHANGED,
|
||||
PRESTERA_PORT_EVENT_MAC_STATE_CHANGED,
|
||||
};
|
||||
|
||||
struct prestera_port_event {
|
||||
u32 port_id;
|
||||
union {
|
||||
u32 oper_state;
|
||||
struct {
|
||||
u32 mode;
|
||||
u32 speed;
|
||||
u8 oper;
|
||||
u8 duplex;
|
||||
u8 fc;
|
||||
u8 fec;
|
||||
} mac;
|
||||
struct {
|
||||
u64 lmode_bmap;
|
||||
struct {
|
||||
bool pause;
|
||||
bool asym_pause;
|
||||
} remote_fc;
|
||||
u8 mdix;
|
||||
} phy;
|
||||
} data;
|
||||
};
|
||||
|
||||
@ -223,11 +277,16 @@ void prestera_device_unregister(struct prestera_device *dev);
|
||||
struct prestera_port *prestera_port_find_by_hwid(struct prestera_switch *sw,
|
||||
u32 dev_id, u32 hw_id);
|
||||
|
||||
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);
|
||||
|
||||
struct prestera_port *prestera_find_port(struct prestera_switch *sw, u32 id);
|
||||
|
||||
int prestera_port_cfg_mac_read(struct prestera_port *port,
|
||||
struct prestera_port_mac_config *cfg);
|
||||
|
||||
int prestera_port_cfg_mac_write(struct prestera_port *port,
|
||||
struct prestera_port_mac_config *cfg);
|
||||
|
||||
struct prestera_port *prestera_port_dev_lower_find(struct net_device *dev);
|
||||
|
||||
int prestera_port_pvid_set(struct prestera_port *port, u16 vid);
|
||||
|
@ -323,7 +323,6 @@ static int prestera_port_type_set(const struct ethtool_link_ksettings *ecmd,
|
||||
{
|
||||
u32 new_mode = PRESTERA_LINK_MODE_MAX;
|
||||
u32 type, mode;
|
||||
int err;
|
||||
|
||||
for (type = 0; type < PRESTERA_PORT_TYPE_MAX; type++) {
|
||||
if (port_types[type].eth_type == ecmd->base.port &&
|
||||
@ -348,13 +347,8 @@ static int prestera_port_type_set(const struct ethtool_link_ksettings *ecmd,
|
||||
}
|
||||
}
|
||||
|
||||
if (new_mode < PRESTERA_LINK_MODE_MAX)
|
||||
err = prestera_hw_port_link_mode_set(port, new_mode);
|
||||
else
|
||||
err = -EINVAL;
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
if (new_mode >= PRESTERA_LINK_MODE_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
port->caps.type = type;
|
||||
port->autoneg = false;
|
||||
@ -434,27 +428,33 @@ static void prestera_port_supp_types_get(struct ethtool_link_ksettings *ecmd,
|
||||
static void prestera_port_remote_cap_get(struct ethtool_link_ksettings *ecmd,
|
||||
struct prestera_port *port)
|
||||
{
|
||||
struct prestera_port_phy_state *state = &port->state_phy;
|
||||
bool asym_pause;
|
||||
bool pause;
|
||||
u64 bitmap;
|
||||
int err;
|
||||
|
||||
err = prestera_hw_port_remote_cap_get(port, &bitmap);
|
||||
if (!err) {
|
||||
prestera_modes_to_eth(ecmd->link_modes.lp_advertising,
|
||||
bitmap, 0, PRESTERA_PORT_TYPE_NONE);
|
||||
err = prestera_hw_port_phy_mode_get(port, NULL, &state->lmode_bmap,
|
||||
&state->remote_fc.pause,
|
||||
&state->remote_fc.asym_pause);
|
||||
if (err)
|
||||
netdev_warn(port->dev, "Remote link caps get failed %d",
|
||||
port->caps.transceiver);
|
||||
|
||||
if (!bitmap_empty(ecmd->link_modes.lp_advertising,
|
||||
__ETHTOOL_LINK_MODE_MASK_NBITS)) {
|
||||
ethtool_link_ksettings_add_link_mode(ecmd,
|
||||
lp_advertising,
|
||||
Autoneg);
|
||||
}
|
||||
bitmap = state->lmode_bmap;
|
||||
|
||||
prestera_modes_to_eth(ecmd->link_modes.lp_advertising,
|
||||
bitmap, 0, PRESTERA_PORT_TYPE_NONE);
|
||||
|
||||
if (!bitmap_empty(ecmd->link_modes.lp_advertising,
|
||||
__ETHTOOL_LINK_MODE_MASK_NBITS)) {
|
||||
ethtool_link_ksettings_add_link_mode(ecmd,
|
||||
lp_advertising,
|
||||
Autoneg);
|
||||
}
|
||||
|
||||
err = prestera_hw_port_remote_fc_get(port, &pause, &asym_pause);
|
||||
if (err)
|
||||
return;
|
||||
pause = state->remote_fc.pause;
|
||||
asym_pause = state->remote_fc.asym_pause;
|
||||
|
||||
if (pause)
|
||||
ethtool_link_ksettings_add_link_mode(ecmd,
|
||||
@ -466,30 +466,46 @@ static void prestera_port_remote_cap_get(struct ethtool_link_ksettings *ecmd,
|
||||
Asym_Pause);
|
||||
}
|
||||
|
||||
static void prestera_port_speed_get(struct ethtool_link_ksettings *ecmd,
|
||||
struct prestera_port *port)
|
||||
static void prestera_port_link_mode_get(struct ethtool_link_ksettings *ecmd,
|
||||
struct prestera_port *port)
|
||||
{
|
||||
struct prestera_port_mac_state *state = &port->state_mac;
|
||||
u32 speed;
|
||||
int err;
|
||||
|
||||
err = prestera_hw_port_speed_get(port, &speed);
|
||||
ecmd->base.speed = err ? SPEED_UNKNOWN : speed;
|
||||
}
|
||||
|
||||
static void prestera_port_duplex_get(struct ethtool_link_ksettings *ecmd,
|
||||
struct prestera_port *port)
|
||||
{
|
||||
u8 duplex;
|
||||
int err;
|
||||
|
||||
err = prestera_hw_port_duplex_get(port, &duplex);
|
||||
if (err) {
|
||||
ecmd->base.duplex = DUPLEX_UNKNOWN;
|
||||
if (!port->state_mac.oper)
|
||||
return;
|
||||
|
||||
if (state->speed == SPEED_UNKNOWN || state->duplex == DUPLEX_UNKNOWN) {
|
||||
err = prestera_hw_port_mac_mode_get(port, NULL, &speed,
|
||||
&duplex, NULL);
|
||||
if (err) {
|
||||
state->speed = SPEED_UNKNOWN;
|
||||
state->duplex = DUPLEX_UNKNOWN;
|
||||
} else {
|
||||
state->speed = speed;
|
||||
state->duplex = duplex == PRESTERA_PORT_DUPLEX_FULL ?
|
||||
DUPLEX_FULL : DUPLEX_HALF;
|
||||
}
|
||||
}
|
||||
|
||||
ecmd->base.duplex = duplex == PRESTERA_PORT_DUPLEX_FULL ?
|
||||
DUPLEX_FULL : DUPLEX_HALF;
|
||||
ecmd->base.speed = port->state_mac.speed;
|
||||
ecmd->base.duplex = port->state_mac.duplex;
|
||||
}
|
||||
|
||||
static void prestera_port_mdix_get(struct ethtool_link_ksettings *ecmd,
|
||||
struct prestera_port *port)
|
||||
{
|
||||
struct prestera_port_phy_state *state = &port->state_phy;
|
||||
|
||||
if (prestera_hw_port_phy_mode_get(port, &state->mdix, NULL, NULL, NULL)) {
|
||||
netdev_warn(port->dev, "MDIX params get failed");
|
||||
state->mdix = ETH_TP_MDI_INVALID;
|
||||
}
|
||||
|
||||
ecmd->base.eth_tp_mdix = port->state_phy.mdix;
|
||||
ecmd->base.eth_tp_mdix_ctrl = port->cfg_phy.mdix;
|
||||
}
|
||||
|
||||
static int
|
||||
@ -501,6 +517,8 @@ prestera_ethtool_get_link_ksettings(struct net_device *dev,
|
||||
ethtool_link_ksettings_zero_link_mode(ecmd, supported);
|
||||
ethtool_link_ksettings_zero_link_mode(ecmd, advertising);
|
||||
ethtool_link_ksettings_zero_link_mode(ecmd, lp_advertising);
|
||||
ecmd->base.speed = SPEED_UNKNOWN;
|
||||
ecmd->base.duplex = DUPLEX_UNKNOWN;
|
||||
|
||||
ecmd->base.autoneg = port->autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE;
|
||||
|
||||
@ -521,13 +539,8 @@ prestera_ethtool_get_link_ksettings(struct net_device *dev,
|
||||
|
||||
prestera_port_supp_types_get(ecmd, port);
|
||||
|
||||
if (netif_carrier_ok(dev)) {
|
||||
prestera_port_speed_get(ecmd, port);
|
||||
prestera_port_duplex_get(ecmd, port);
|
||||
} else {
|
||||
ecmd->base.speed = SPEED_UNKNOWN;
|
||||
ecmd->base.duplex = DUPLEX_UNKNOWN;
|
||||
}
|
||||
if (netif_carrier_ok(dev))
|
||||
prestera_port_link_mode_get(ecmd, port);
|
||||
|
||||
ecmd->base.port = prestera_port_type_get(port);
|
||||
|
||||
@ -545,8 +558,7 @@ prestera_ethtool_get_link_ksettings(struct net_device *dev,
|
||||
|
||||
if (port->caps.type == PRESTERA_PORT_TYPE_TP &&
|
||||
port->caps.transceiver == PRESTERA_PORT_TCVR_COPPER)
|
||||
prestera_hw_port_mdix_get(port, &ecmd->base.eth_tp_mdix,
|
||||
&ecmd->base.eth_tp_mdix_ctrl);
|
||||
prestera_port_mdix_get(ecmd, port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -555,12 +567,17 @@ static int prestera_port_mdix_set(const struct ethtool_link_ksettings *ecmd,
|
||||
struct prestera_port *port)
|
||||
{
|
||||
if (ecmd->base.eth_tp_mdix_ctrl != ETH_TP_MDI_INVALID &&
|
||||
port->caps.transceiver == PRESTERA_PORT_TCVR_COPPER &&
|
||||
port->caps.type == PRESTERA_PORT_TYPE_TP)
|
||||
return prestera_hw_port_mdix_set(port,
|
||||
ecmd->base.eth_tp_mdix_ctrl);
|
||||
|
||||
port->caps.transceiver == PRESTERA_PORT_TCVR_COPPER &&
|
||||
port->caps.type == PRESTERA_PORT_TYPE_TP) {
|
||||
port->cfg_phy.mdix = ecmd->base.eth_tp_mdix_ctrl;
|
||||
return prestera_hw_port_phy_mode_set(port, port->cfg_phy.admin,
|
||||
port->autoneg,
|
||||
port->cfg_phy.mode,
|
||||
port->adver_link_modes,
|
||||
port->cfg_phy.mdix);
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static int prestera_port_link_mode_set(struct prestera_port *port,
|
||||
@ -568,12 +585,15 @@ static int prestera_port_link_mode_set(struct prestera_port *port,
|
||||
{
|
||||
u32 new_mode = PRESTERA_LINK_MODE_MAX;
|
||||
u32 mode;
|
||||
int err;
|
||||
|
||||
for (mode = 0; mode < PRESTERA_LINK_MODE_MAX; mode++) {
|
||||
if (speed != port_link_modes[mode].speed)
|
||||
if (speed != SPEED_UNKNOWN &&
|
||||
speed != port_link_modes[mode].speed)
|
||||
continue;
|
||||
|
||||
if (duplex != port_link_modes[mode].duplex)
|
||||
if (duplex != DUPLEX_UNKNOWN &&
|
||||
duplex != port_link_modes[mode].duplex)
|
||||
continue;
|
||||
|
||||
if (!(port_link_modes[mode].pr_mask &
|
||||
@ -590,36 +610,31 @@ static int prestera_port_link_mode_set(struct prestera_port *port,
|
||||
if (new_mode == PRESTERA_LINK_MODE_MAX)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return prestera_hw_port_link_mode_set(port, new_mode);
|
||||
err = prestera_hw_port_phy_mode_set(port, port->cfg_phy.admin,
|
||||
false, new_mode, 0,
|
||||
port->cfg_phy.mdix);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
port->adver_fec = BIT(PRESTERA_PORT_FEC_OFF);
|
||||
port->adver_link_modes = 0;
|
||||
port->cfg_phy.mode = new_mode;
|
||||
port->autoneg = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
prestera_port_speed_duplex_set(const struct ethtool_link_ksettings *ecmd,
|
||||
struct prestera_port *port)
|
||||
{
|
||||
u32 curr_mode;
|
||||
u8 duplex;
|
||||
u32 speed;
|
||||
int err;
|
||||
|
||||
err = prestera_hw_port_link_mode_get(port, &curr_mode);
|
||||
if (err)
|
||||
return err;
|
||||
if (curr_mode >= PRESTERA_LINK_MODE_MAX)
|
||||
return -EINVAL;
|
||||
u8 duplex = DUPLEX_UNKNOWN;
|
||||
|
||||
if (ecmd->base.duplex != DUPLEX_UNKNOWN)
|
||||
duplex = ecmd->base.duplex == DUPLEX_FULL ?
|
||||
PRESTERA_PORT_DUPLEX_FULL : PRESTERA_PORT_DUPLEX_HALF;
|
||||
else
|
||||
duplex = port_link_modes[curr_mode].duplex;
|
||||
|
||||
if (ecmd->base.speed != SPEED_UNKNOWN)
|
||||
speed = ecmd->base.speed;
|
||||
else
|
||||
speed = port_link_modes[curr_mode].speed;
|
||||
|
||||
return prestera_port_link_mode_set(port, speed, duplex,
|
||||
return prestera_port_link_mode_set(port, ecmd->base.speed, duplex,
|
||||
port->caps.type);
|
||||
}
|
||||
|
||||
@ -645,19 +660,12 @@ prestera_ethtool_set_link_ksettings(struct net_device *dev,
|
||||
prestera_modes_from_eth(ecmd->link_modes.advertising, &adver_modes,
|
||||
&adver_fec, port->caps.type);
|
||||
|
||||
err = prestera_port_autoneg_set(port,
|
||||
ecmd->base.autoneg == AUTONEG_ENABLE,
|
||||
adver_modes, adver_fec);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (ecmd->base.autoneg == AUTONEG_DISABLE) {
|
||||
if (ecmd->base.autoneg == AUTONEG_ENABLE)
|
||||
err = prestera_port_autoneg_set(port, adver_modes);
|
||||
else
|
||||
err = prestera_port_speed_duplex_set(ecmd, port);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
static int prestera_ethtool_get_fecparam(struct net_device *dev,
|
||||
@ -668,7 +676,7 @@ static int prestera_ethtool_get_fecparam(struct net_device *dev,
|
||||
u32 mode;
|
||||
int err;
|
||||
|
||||
err = prestera_hw_port_fec_get(port, &active);
|
||||
err = prestera_hw_port_mac_mode_get(port, NULL, NULL, NULL, &active);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@ -693,18 +701,19 @@ static int prestera_ethtool_set_fecparam(struct net_device *dev,
|
||||
struct ethtool_fecparam *fecparam)
|
||||
{
|
||||
struct prestera_port *port = netdev_priv(dev);
|
||||
u8 fec, active;
|
||||
struct prestera_port_mac_config cfg_mac;
|
||||
u32 mode;
|
||||
int err;
|
||||
u8 fec;
|
||||
|
||||
if (port->autoneg) {
|
||||
netdev_err(dev, "FEC set is not allowed while autoneg is on\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = prestera_hw_port_fec_get(port, &active);
|
||||
if (err)
|
||||
return err;
|
||||
if (port->caps.transceiver == PRESTERA_PORT_TCVR_SFP) {
|
||||
netdev_err(dev, "FEC set is not allowed on non-SFP ports\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
fec = PRESTERA_PORT_FEC_MAX;
|
||||
for (mode = 0; mode < PRESTERA_PORT_FEC_MAX; mode++) {
|
||||
@ -715,13 +724,19 @@ static int prestera_ethtool_set_fecparam(struct net_device *dev,
|
||||
}
|
||||
}
|
||||
|
||||
if (fec == active)
|
||||
prestera_port_cfg_mac_read(port, &cfg_mac);
|
||||
|
||||
if (fec == cfg_mac.fec)
|
||||
return 0;
|
||||
|
||||
if (fec == PRESTERA_PORT_FEC_MAX)
|
||||
return -EOPNOTSUPP;
|
||||
if (fec == PRESTERA_PORT_FEC_MAX) {
|
||||
netdev_err(dev, "Unsupported FEC requested");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return prestera_hw_port_fec_set(port, fec);
|
||||
cfg_mac.fec = fec;
|
||||
|
||||
return prestera_port_cfg_mac_write(port, &cfg_mac);
|
||||
}
|
||||
|
||||
static int prestera_ethtool_get_sset_count(struct net_device *dev, int sset)
|
||||
@ -766,6 +781,28 @@ static int prestera_ethtool_nway_reset(struct net_device *dev)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
void prestera_ethtool_port_state_changed(struct prestera_port *port,
|
||||
struct prestera_port_event *evt)
|
||||
{
|
||||
struct prestera_port_mac_state *smac = &port->state_mac;
|
||||
|
||||
smac->oper = evt->data.mac.oper;
|
||||
|
||||
if (smac->oper) {
|
||||
smac->mode = evt->data.mac.mode;
|
||||
smac->speed = evt->data.mac.speed;
|
||||
smac->duplex = evt->data.mac.duplex;
|
||||
smac->fc = evt->data.mac.fc;
|
||||
smac->fec = evt->data.mac.fec;
|
||||
} else {
|
||||
smac->mode = PRESTERA_MAC_MODE_MAX;
|
||||
smac->speed = SPEED_UNKNOWN;
|
||||
smac->duplex = DUPLEX_UNKNOWN;
|
||||
smac->fc = 0;
|
||||
smac->fec = 0;
|
||||
}
|
||||
}
|
||||
|
||||
const struct ethtool_ops prestera_ethtool_ops = {
|
||||
.get_drvinfo = prestera_ethtool_get_drvinfo,
|
||||
.get_link_ksettings = prestera_ethtool_get_link_ksettings,
|
||||
|
@ -6,6 +6,12 @@
|
||||
|
||||
#include <linux/ethtool.h>
|
||||
|
||||
struct prestera_port_event;
|
||||
struct prestera_port;
|
||||
|
||||
extern const struct ethtool_ops prestera_ethtool_ops;
|
||||
|
||||
void prestera_ethtool_port_state_changed(struct prestera_port *port,
|
||||
struct prestera_port_event *evt);
|
||||
|
||||
#endif /* _PRESTERA_ETHTOOL_H_ */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -19,6 +19,23 @@ enum prestera_fdb_flush_mode {
|
||||
| PRESTERA_FDB_FLUSH_MODE_STATIC,
|
||||
};
|
||||
|
||||
enum {
|
||||
PRESTERA_MAC_MODE_INTERNAL,
|
||||
PRESTERA_MAC_MODE_SGMII,
|
||||
PRESTERA_MAC_MODE_1000BASE_X,
|
||||
PRESTERA_MAC_MODE_KR,
|
||||
PRESTERA_MAC_MODE_KR2,
|
||||
PRESTERA_MAC_MODE_KR4,
|
||||
PRESTERA_MAC_MODE_CR,
|
||||
PRESTERA_MAC_MODE_CR2,
|
||||
PRESTERA_MAC_MODE_CR4,
|
||||
PRESTERA_MAC_MODE_SR_LR,
|
||||
PRESTERA_MAC_MODE_SR_LR2,
|
||||
PRESTERA_MAC_MODE_SR_LR4,
|
||||
|
||||
PRESTERA_MAC_MODE_MAX
|
||||
};
|
||||
|
||||
enum {
|
||||
PRESTERA_LINK_MODE_10baseT_Half,
|
||||
PRESTERA_LINK_MODE_10baseT_Full,
|
||||
@ -116,32 +133,29 @@ int prestera_hw_switch_mac_set(struct prestera_switch *sw, const char *mac);
|
||||
/* Port API */
|
||||
int prestera_hw_port_info_get(const struct prestera_port *port,
|
||||
u32 *dev_id, u32 *hw_id, u16 *fp_id);
|
||||
int prestera_hw_port_state_set(const struct prestera_port *port,
|
||||
bool admin_state);
|
||||
|
||||
int prestera_hw_port_mac_mode_get(const struct prestera_port *port,
|
||||
u32 *mode, u32 *speed, u8 *duplex, u8 *fec);
|
||||
int prestera_hw_port_mac_mode_set(const struct prestera_port *port,
|
||||
bool admin, u32 mode, u8 inband,
|
||||
u32 speed, u8 duplex, u8 fec);
|
||||
int prestera_hw_port_phy_mode_get(const struct prestera_port *port,
|
||||
u8 *mdix, u64 *lmode_bmap,
|
||||
bool *fc_pause, bool *fc_asym);
|
||||
int prestera_hw_port_phy_mode_set(const struct prestera_port *port,
|
||||
bool admin, bool adv, u32 mode, u64 modes,
|
||||
u8 mdix);
|
||||
|
||||
int prestera_hw_port_mtu_set(const struct prestera_port *port, u32 mtu);
|
||||
int prestera_hw_port_mtu_get(const struct prestera_port *port, u32 *mtu);
|
||||
int prestera_hw_port_mac_set(const struct prestera_port *port, const char *mac);
|
||||
int prestera_hw_port_mac_get(const struct prestera_port *port, char *mac);
|
||||
int prestera_hw_port_cap_get(const struct prestera_port *port,
|
||||
struct prestera_port_caps *caps);
|
||||
int prestera_hw_port_remote_cap_get(const struct prestera_port *port,
|
||||
u64 *link_mode_bitmap);
|
||||
int prestera_hw_port_remote_fc_get(const struct prestera_port *port,
|
||||
bool *pause, bool *asym_pause);
|
||||
int prestera_hw_port_type_get(const struct prestera_port *port, u8 *type);
|
||||
int prestera_hw_port_fec_get(const struct prestera_port *port, u8 *fec);
|
||||
int prestera_hw_port_fec_set(const struct prestera_port *port, u8 fec);
|
||||
int prestera_hw_port_autoneg_set(const struct prestera_port *port,
|
||||
bool autoneg, u64 link_modes, u8 fec);
|
||||
int prestera_hw_port_autoneg_restart(struct prestera_port *port);
|
||||
int prestera_hw_port_duplex_get(const struct prestera_port *port, u8 *duplex);
|
||||
int prestera_hw_port_stats_get(const struct prestera_port *port,
|
||||
struct prestera_port_stats *stats);
|
||||
int prestera_hw_port_link_mode_set(const struct prestera_port *port, u32 mode);
|
||||
int prestera_hw_port_link_mode_get(const struct prestera_port *port, u32 *mode);
|
||||
int prestera_hw_port_mdix_get(const struct prestera_port *port, u8 *status,
|
||||
u8 *admin_mode);
|
||||
int prestera_hw_port_mdix_set(const struct prestera_port *port, u8 mode);
|
||||
int prestera_hw_port_speed_get(const struct prestera_port *port, u32 *speed);
|
||||
int prestera_hw_port_learning_set(struct prestera_port *port, bool enable);
|
||||
int prestera_hw_port_flood_set(struct prestera_port *port, unsigned long mask,
|
||||
@ -206,7 +220,6 @@ void prestera_hw_event_handler_unregister(struct prestera_switch *sw,
|
||||
/* RX/TX */
|
||||
int prestera_hw_rxtx_init(struct prestera_switch *sw,
|
||||
struct prestera_rxtx_params *params);
|
||||
int prestera_hw_rxtx_port_init(struct prestera_port *port);
|
||||
|
||||
/* LAG API */
|
||||
int prestera_hw_lag_member_add(struct prestera_port *port, u16 lag_id);
|
||||
|
@ -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;
|
||||
|
||||
err = prestera_hw_port_state_set(port, false);
|
||||
/* 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_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);
|
||||
|
@ -14,10 +14,10 @@
|
||||
|
||||
#define PRESTERA_MSG_MAX_SIZE 1500
|
||||
|
||||
#define PRESTERA_SUPP_FW_MAJ_VER 3
|
||||
#define PRESTERA_SUPP_FW_MAJ_VER 4
|
||||
#define PRESTERA_SUPP_FW_MIN_VER 0
|
||||
|
||||
#define PRESTERA_PREV_FW_MAJ_VER 2
|
||||
#define PRESTERA_PREV_FW_MAJ_VER 4
|
||||
#define PRESTERA_PREV_FW_MIN_VER 0
|
||||
|
||||
#define PRESTERA_FW_PATH_FMT "mrvl/prestera/mvsw_prestera_fw-v%u.%u.img"
|
||||
@ -102,23 +102,30 @@ struct prestera_fw_evtq_regs {
|
||||
u32 len;
|
||||
};
|
||||
|
||||
#define PRESTERA_CMD_QNUM_MAX 4
|
||||
|
||||
struct prestera_fw_cmdq_regs {
|
||||
u32 req_ctl;
|
||||
u32 req_len;
|
||||
u32 rcv_ctl;
|
||||
u32 rcv_len;
|
||||
u32 offs;
|
||||
u32 len;
|
||||
};
|
||||
|
||||
struct prestera_fw_regs {
|
||||
u32 fw_ready;
|
||||
u32 pad;
|
||||
u32 cmd_offs;
|
||||
u32 cmd_len;
|
||||
u32 cmd_qnum;
|
||||
u32 evt_offs;
|
||||
u32 evt_qnum;
|
||||
|
||||
u32 cmd_req_ctl;
|
||||
u32 cmd_req_len;
|
||||
u32 cmd_rcv_ctl;
|
||||
u32 cmd_rcv_len;
|
||||
|
||||
u32 fw_status;
|
||||
u32 rx_status;
|
||||
|
||||
struct prestera_fw_evtq_regs evtq_list[PRESTERA_EVT_QNUM_MAX];
|
||||
struct prestera_fw_cmdq_regs cmdq_list[PRESTERA_EVT_QNUM_MAX];
|
||||
struct prestera_fw_evtq_regs evtq_list[PRESTERA_CMD_QNUM_MAX];
|
||||
};
|
||||
|
||||
#define PRESTERA_FW_REG_OFFSET(f) offsetof(struct prestera_fw_regs, f)
|
||||
@ -130,14 +137,22 @@ struct prestera_fw_regs {
|
||||
|
||||
#define PRESTERA_CMD_BUF_OFFS_REG PRESTERA_FW_REG_OFFSET(cmd_offs)
|
||||
#define PRESTERA_CMD_BUF_LEN_REG PRESTERA_FW_REG_OFFSET(cmd_len)
|
||||
#define PRESTERA_CMD_QNUM_REG PRESTERA_FW_REG_OFFSET(cmd_qnum)
|
||||
#define PRESTERA_EVT_BUF_OFFS_REG PRESTERA_FW_REG_OFFSET(evt_offs)
|
||||
#define PRESTERA_EVT_QNUM_REG PRESTERA_FW_REG_OFFSET(evt_qnum)
|
||||
|
||||
#define PRESTERA_CMD_REQ_CTL_REG PRESTERA_FW_REG_OFFSET(cmd_req_ctl)
|
||||
#define PRESTERA_CMD_REQ_LEN_REG PRESTERA_FW_REG_OFFSET(cmd_req_len)
|
||||
#define PRESTERA_CMDQ_REG_OFFSET(q, f) \
|
||||
(PRESTERA_FW_REG_OFFSET(cmdq_list) + \
|
||||
(q) * sizeof(struct prestera_fw_cmdq_regs) + \
|
||||
offsetof(struct prestera_fw_cmdq_regs, f))
|
||||
|
||||
#define PRESTERA_CMDQ_REQ_CTL_REG(q) PRESTERA_CMDQ_REG_OFFSET(q, req_ctl)
|
||||
#define PRESTERA_CMDQ_REQ_LEN_REG(q) PRESTERA_CMDQ_REG_OFFSET(q, req_len)
|
||||
#define PRESTERA_CMDQ_RCV_CTL_REG(q) PRESTERA_CMDQ_REG_OFFSET(q, rcv_ctl)
|
||||
#define PRESTERA_CMDQ_RCV_LEN_REG(q) PRESTERA_CMDQ_REG_OFFSET(q, rcv_len)
|
||||
#define PRESTERA_CMDQ_OFFS_REG(q) PRESTERA_CMDQ_REG_OFFSET(q, offs)
|
||||
#define PRESTERA_CMDQ_LEN_REG(q) PRESTERA_CMDQ_REG_OFFSET(q, len)
|
||||
|
||||
#define PRESTERA_CMD_RCV_CTL_REG PRESTERA_FW_REG_OFFSET(cmd_rcv_ctl)
|
||||
#define PRESTERA_CMD_RCV_LEN_REG PRESTERA_FW_REG_OFFSET(cmd_rcv_len)
|
||||
#define PRESTERA_FW_STATUS_REG PRESTERA_FW_REG_OFFSET(fw_status)
|
||||
#define PRESTERA_RX_STATUS_REG PRESTERA_FW_REG_OFFSET(rx_status)
|
||||
|
||||
@ -174,6 +189,13 @@ struct prestera_fw_evtq {
|
||||
size_t len;
|
||||
};
|
||||
|
||||
struct prestera_fw_cmdq {
|
||||
/* serialize access to dev->send_req */
|
||||
struct mutex cmd_mtx;
|
||||
u8 __iomem *addr;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
struct prestera_fw {
|
||||
struct prestera_fw_rev rev_supp;
|
||||
const struct firmware *bin;
|
||||
@ -183,9 +205,10 @@ struct prestera_fw {
|
||||
u8 __iomem *ldr_ring_buf;
|
||||
u32 ldr_buf_len;
|
||||
u32 ldr_wr_idx;
|
||||
struct mutex cmd_mtx; /* serialize access to dev->send_req */
|
||||
size_t cmd_mbox_len;
|
||||
u8 __iomem *cmd_mbox;
|
||||
struct prestera_fw_cmdq cmd_queue[PRESTERA_CMD_QNUM_MAX];
|
||||
u8 cmd_qnum;
|
||||
struct prestera_fw_evtq evt_queue[PRESTERA_EVT_QNUM_MAX];
|
||||
u8 evt_qnum;
|
||||
struct work_struct evt_work;
|
||||
@ -324,7 +347,27 @@ static int prestera_fw_wait_reg32(struct prestera_fw *fw, u32 reg, u32 cmp,
|
||||
1 * USEC_PER_MSEC, waitms * USEC_PER_MSEC);
|
||||
}
|
||||
|
||||
static int prestera_fw_cmd_send(struct prestera_fw *fw,
|
||||
static void prestera_fw_cmdq_lock(struct prestera_fw *fw, u8 qid)
|
||||
{
|
||||
mutex_lock(&fw->cmd_queue[qid].cmd_mtx);
|
||||
}
|
||||
|
||||
static void prestera_fw_cmdq_unlock(struct prestera_fw *fw, u8 qid)
|
||||
{
|
||||
mutex_unlock(&fw->cmd_queue[qid].cmd_mtx);
|
||||
}
|
||||
|
||||
static u32 prestera_fw_cmdq_len(struct prestera_fw *fw, u8 qid)
|
||||
{
|
||||
return fw->cmd_queue[qid].len;
|
||||
}
|
||||
|
||||
static u8 __iomem *prestera_fw_cmdq_buf(struct prestera_fw *fw, u8 qid)
|
||||
{
|
||||
return fw->cmd_queue[qid].addr;
|
||||
}
|
||||
|
||||
static int prestera_fw_cmd_send(struct prestera_fw *fw, int qid,
|
||||
void *in_msg, size_t in_size,
|
||||
void *out_msg, size_t out_size,
|
||||
unsigned int waitms)
|
||||
@ -335,30 +378,32 @@ static int prestera_fw_cmd_send(struct prestera_fw *fw,
|
||||
if (!waitms)
|
||||
waitms = PRESTERA_FW_CMD_DEFAULT_WAIT_MS;
|
||||
|
||||
if (ALIGN(in_size, 4) > fw->cmd_mbox_len)
|
||||
if (ALIGN(in_size, 4) > prestera_fw_cmdq_len(fw, qid))
|
||||
return -EMSGSIZE;
|
||||
|
||||
/* wait for finish previous reply from FW */
|
||||
err = prestera_fw_wait_reg32(fw, PRESTERA_CMD_RCV_CTL_REG, 0, 30);
|
||||
err = prestera_fw_wait_reg32(fw, PRESTERA_CMDQ_RCV_CTL_REG(qid), 0, 30);
|
||||
if (err) {
|
||||
dev_err(fw->dev.dev, "finish reply from FW is timed out\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
prestera_fw_write(fw, PRESTERA_CMD_REQ_LEN_REG, in_size);
|
||||
memcpy_toio(fw->cmd_mbox, in_msg, in_size);
|
||||
prestera_fw_write(fw, PRESTERA_CMDQ_REQ_LEN_REG(qid), in_size);
|
||||
|
||||
prestera_fw_write(fw, PRESTERA_CMD_REQ_CTL_REG, PRESTERA_CMD_F_REQ_SENT);
|
||||
memcpy_toio(prestera_fw_cmdq_buf(fw, qid), in_msg, in_size);
|
||||
|
||||
prestera_fw_write(fw, PRESTERA_CMDQ_REQ_CTL_REG(qid),
|
||||
PRESTERA_CMD_F_REQ_SENT);
|
||||
|
||||
/* wait for reply from FW */
|
||||
err = prestera_fw_wait_reg32(fw, PRESTERA_CMD_RCV_CTL_REG,
|
||||
err = prestera_fw_wait_reg32(fw, PRESTERA_CMDQ_RCV_CTL_REG(qid),
|
||||
PRESTERA_CMD_F_REPL_SENT, waitms);
|
||||
if (err) {
|
||||
dev_err(fw->dev.dev, "reply from FW is timed out\n");
|
||||
goto cmd_exit;
|
||||
}
|
||||
|
||||
ret_size = prestera_fw_read(fw, PRESTERA_CMD_RCV_LEN_REG);
|
||||
ret_size = prestera_fw_read(fw, PRESTERA_CMDQ_RCV_LEN_REG(qid));
|
||||
if (ret_size > out_size) {
|
||||
dev_err(fw->dev.dev, "ret_size (%u) > out_len(%zu)\n",
|
||||
ret_size, out_size);
|
||||
@ -366,14 +411,15 @@ static int prestera_fw_cmd_send(struct prestera_fw *fw,
|
||||
goto cmd_exit;
|
||||
}
|
||||
|
||||
memcpy_fromio(out_msg, fw->cmd_mbox + in_size, ret_size);
|
||||
memcpy_fromio(out_msg, prestera_fw_cmdq_buf(fw, qid) + in_size, ret_size);
|
||||
|
||||
cmd_exit:
|
||||
prestera_fw_write(fw, PRESTERA_CMD_REQ_CTL_REG, PRESTERA_CMD_F_REPL_RCVD);
|
||||
prestera_fw_write(fw, PRESTERA_CMDQ_REQ_CTL_REG(qid),
|
||||
PRESTERA_CMD_F_REPL_RCVD);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int prestera_fw_send_req(struct prestera_device *dev,
|
||||
static int prestera_fw_send_req(struct prestera_device *dev, int qid,
|
||||
void *in_msg, size_t in_size, void *out_msg,
|
||||
size_t out_size, unsigned int waitms)
|
||||
{
|
||||
@ -382,9 +428,10 @@ static int prestera_fw_send_req(struct prestera_device *dev,
|
||||
|
||||
fw = container_of(dev, struct prestera_fw, dev);
|
||||
|
||||
mutex_lock(&fw->cmd_mtx);
|
||||
ret = prestera_fw_cmd_send(fw, in_msg, in_size, out_msg, out_size, waitms);
|
||||
mutex_unlock(&fw->cmd_mtx);
|
||||
prestera_fw_cmdq_lock(fw, qid);
|
||||
ret = prestera_fw_cmd_send(fw, qid, in_msg, in_size, out_msg, out_size,
|
||||
waitms);
|
||||
prestera_fw_cmdq_unlock(fw, qid);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -414,7 +461,16 @@ static int prestera_fw_init(struct prestera_fw *fw)
|
||||
|
||||
fw->cmd_mbox = base + prestera_fw_read(fw, PRESTERA_CMD_BUF_OFFS_REG);
|
||||
fw->cmd_mbox_len = prestera_fw_read(fw, PRESTERA_CMD_BUF_LEN_REG);
|
||||
mutex_init(&fw->cmd_mtx);
|
||||
fw->cmd_qnum = prestera_fw_read(fw, PRESTERA_CMD_QNUM_REG);
|
||||
|
||||
for (qid = 0; qid < fw->cmd_qnum; qid++) {
|
||||
u32 offs = prestera_fw_read(fw, PRESTERA_CMDQ_OFFS_REG(qid));
|
||||
struct prestera_fw_cmdq *cmdq = &fw->cmd_queue[qid];
|
||||
|
||||
cmdq->len = prestera_fw_read(fw, PRESTERA_CMDQ_LEN_REG(qid));
|
||||
cmdq->addr = fw->cmd_mbox + offs;
|
||||
mutex_init(&cmdq->cmd_mtx);
|
||||
}
|
||||
|
||||
fw->evt_buf = base + prestera_fw_read(fw, PRESTERA_EVT_BUF_OFFS_REG);
|
||||
fw->evt_qnum = prestera_fw_read(fw, PRESTERA_EVT_QNUM_REG);
|
||||
|
@ -794,14 +794,7 @@ void prestera_rxtx_switch_fini(struct prestera_switch *sw)
|
||||
|
||||
int prestera_rxtx_port_init(struct prestera_port *port)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = prestera_hw_rxtx_port_init(port);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
port->dev->needed_headroom = PRESTERA_DSA_HLEN;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user