Commit 2cf1b5ce authored by David S. Miller's avatar David S. Miller

Merge branch 'mlxsw-fixes'

Jiri Pirko says:

====================
mlxsw: Couple of fixes/adjustments

Ido Schimmel (5):
  mlxsw: Call free_netdev when removing port
  mlxsw: Make system port to local port mapping explicit
  mlxsw: Simplify mlxsw_sx_port_xmit function
  mlxsw: Use correct skb length when dumping payload
  mlxsw: Fix use-after-free bug in mlxsw_sx_port_xmit

Jiri Pirko (2):
  mlxsw: Make pci module dependent on HAS_DMA and HAS_IOMEM
  mlxsw: Strip FCS from incoming packets
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents ecea4991 e577516b
...@@ -12,7 +12,7 @@ config MLXSW_CORE ...@@ -12,7 +12,7 @@ config MLXSW_CORE
config MLXSW_PCI config MLXSW_PCI
tristate "PCI bus implementation for Mellanox Technologies Switch ASICs" tristate "PCI bus implementation for Mellanox Technologies Switch ASICs"
depends on PCI && MLXSW_CORE depends on PCI && HAS_DMA && HAS_IOMEM && MLXSW_CORE
default m default m
---help--- ---help---
This is PCI bus implementation for Mellanox Technologies Switch ASICs. This is PCI bus implementation for Mellanox Technologies Switch ASICs.
......
...@@ -865,6 +865,16 @@ static struct mlxsw_core *__mlxsw_core_get(void *driver_priv) ...@@ -865,6 +865,16 @@ static struct mlxsw_core *__mlxsw_core_get(void *driver_priv)
return container_of(driver_priv, struct mlxsw_core, driver_priv); return container_of(driver_priv, struct mlxsw_core, driver_priv);
} }
bool mlxsw_core_skb_transmit_busy(void *driver_priv,
const struct mlxsw_tx_info *tx_info)
{
struct mlxsw_core *mlxsw_core = __mlxsw_core_get(driver_priv);
return mlxsw_core->bus->skb_transmit_busy(mlxsw_core->bus_priv,
tx_info);
}
EXPORT_SYMBOL(mlxsw_core_skb_transmit_busy);
int mlxsw_core_skb_transmit(void *driver_priv, struct sk_buff *skb, int mlxsw_core_skb_transmit(void *driver_priv, struct sk_buff *skb,
const struct mlxsw_tx_info *tx_info) const struct mlxsw_tx_info *tx_info)
{ {
...@@ -1063,7 +1073,7 @@ static int mlxsw_core_reg_access_emad(struct mlxsw_core *mlxsw_core, ...@@ -1063,7 +1073,7 @@ static int mlxsw_core_reg_access_emad(struct mlxsw_core *mlxsw_core,
mlxsw_core->emad.tid - 1); mlxsw_core->emad.tid - 1);
mlxsw_core_buf_dump_dbg(mlxsw_core, mlxsw_core_buf_dump_dbg(mlxsw_core,
mlxsw_core->emad.resp_skb->data, mlxsw_core->emad.resp_skb->data,
skb->len); mlxsw_core->emad.resp_skb->len);
dev_kfree_skb(mlxsw_core->emad.resp_skb); dev_kfree_skb(mlxsw_core->emad.resp_skb);
} }
......
...@@ -73,6 +73,9 @@ struct mlxsw_tx_info { ...@@ -73,6 +73,9 @@ struct mlxsw_tx_info {
bool is_emad; bool is_emad;
}; };
bool mlxsw_core_skb_transmit_busy(void *driver_priv,
const struct mlxsw_tx_info *tx_info);
int mlxsw_core_skb_transmit(void *driver_priv, struct sk_buff *skb, int mlxsw_core_skb_transmit(void *driver_priv, struct sk_buff *skb,
const struct mlxsw_tx_info *tx_info); const struct mlxsw_tx_info *tx_info);
...@@ -177,6 +180,8 @@ struct mlxsw_bus { ...@@ -177,6 +180,8 @@ struct mlxsw_bus {
int (*init)(void *bus_priv, struct mlxsw_core *mlxsw_core, int (*init)(void *bus_priv, struct mlxsw_core *mlxsw_core,
const struct mlxsw_config_profile *profile); const struct mlxsw_config_profile *profile);
void (*fini)(void *bus_priv); void (*fini)(void *bus_priv);
bool (*skb_transmit_busy)(void *bus_priv,
const struct mlxsw_tx_info *tx_info);
int (*skb_transmit)(void *bus_priv, struct sk_buff *skb, int (*skb_transmit)(void *bus_priv, struct sk_buff *skb,
const struct mlxsw_tx_info *tx_info); const struct mlxsw_tx_info *tx_info);
int (*cmd_exec)(void *bus_priv, u16 opcode, u8 opcode_mod, int (*cmd_exec)(void *bus_priv, u16 opcode, u8 opcode_mod,
......
...@@ -667,6 +667,7 @@ static void mlxsw_pci_cqe_rdq_handle(struct mlxsw_pci *mlxsw_pci, ...@@ -667,6 +667,7 @@ static void mlxsw_pci_cqe_rdq_handle(struct mlxsw_pci *mlxsw_pci,
char *wqe; char *wqe;
struct sk_buff *skb; struct sk_buff *skb;
struct mlxsw_rx_info rx_info; struct mlxsw_rx_info rx_info;
u16 byte_count;
int err; int err;
elem_info = mlxsw_pci_queue_elem_info_consumer_get(q); elem_info = mlxsw_pci_queue_elem_info_consumer_get(q);
...@@ -686,7 +687,10 @@ static void mlxsw_pci_cqe_rdq_handle(struct mlxsw_pci *mlxsw_pci, ...@@ -686,7 +687,10 @@ static void mlxsw_pci_cqe_rdq_handle(struct mlxsw_pci *mlxsw_pci,
rx_info.sys_port = mlxsw_pci_cqe_system_port_get(cqe); rx_info.sys_port = mlxsw_pci_cqe_system_port_get(cqe);
rx_info.trap_id = mlxsw_pci_cqe_trap_id_get(cqe); rx_info.trap_id = mlxsw_pci_cqe_trap_id_get(cqe);
skb_put(skb, mlxsw_pci_cqe_byte_count_get(cqe)); byte_count = mlxsw_pci_cqe_byte_count_get(cqe);
if (mlxsw_pci_cqe_crc_get(cqe))
byte_count -= ETH_FCS_LEN;
skb_put(skb, byte_count);
mlxsw_core_skb_receive(mlxsw_pci->core, skb, &rx_info); mlxsw_core_skb_receive(mlxsw_pci->core, skb, &rx_info);
put_new_skb: put_new_skb:
...@@ -1439,6 +1443,15 @@ mlxsw_pci_sdq_pick(struct mlxsw_pci *mlxsw_pci, ...@@ -1439,6 +1443,15 @@ mlxsw_pci_sdq_pick(struct mlxsw_pci *mlxsw_pci,
return mlxsw_pci_sdq_get(mlxsw_pci, sdqn); return mlxsw_pci_sdq_get(mlxsw_pci, sdqn);
} }
static bool mlxsw_pci_skb_transmit_busy(void *bus_priv,
const struct mlxsw_tx_info *tx_info)
{
struct mlxsw_pci *mlxsw_pci = bus_priv;
struct mlxsw_pci_queue *q = mlxsw_pci_sdq_pick(mlxsw_pci, tx_info);
return !mlxsw_pci_queue_elem_info_producer_get(q);
}
static int mlxsw_pci_skb_transmit(void *bus_priv, struct sk_buff *skb, static int mlxsw_pci_skb_transmit(void *bus_priv, struct sk_buff *skb,
const struct mlxsw_tx_info *tx_info) const struct mlxsw_tx_info *tx_info)
{ {
...@@ -1621,11 +1634,12 @@ static int mlxsw_pci_cmd_exec(void *bus_priv, u16 opcode, u8 opcode_mod, ...@@ -1621,11 +1634,12 @@ static int mlxsw_pci_cmd_exec(void *bus_priv, u16 opcode, u8 opcode_mod,
} }
static const struct mlxsw_bus mlxsw_pci_bus = { static const struct mlxsw_bus mlxsw_pci_bus = {
.kind = "pci", .kind = "pci",
.init = mlxsw_pci_init, .init = mlxsw_pci_init,
.fini = mlxsw_pci_fini, .fini = mlxsw_pci_fini,
.skb_transmit = mlxsw_pci_skb_transmit, .skb_transmit_busy = mlxsw_pci_skb_transmit_busy,
.cmd_exec = mlxsw_pci_cmd_exec, .skb_transmit = mlxsw_pci_skb_transmit,
.cmd_exec = mlxsw_pci_cmd_exec,
}; };
static int mlxsw_pci_sw_reset(struct mlxsw_pci *mlxsw_pci) static int mlxsw_pci_sw_reset(struct mlxsw_pci *mlxsw_pci)
......
...@@ -155,6 +155,12 @@ MLXSW_ITEM32(pci, cqe, byte_count, 0x04, 0, 14); ...@@ -155,6 +155,12 @@ MLXSW_ITEM32(pci, cqe, byte_count, 0x04, 0, 14);
*/ */
MLXSW_ITEM32(pci, cqe, trap_id, 0x08, 0, 8); MLXSW_ITEM32(pci, cqe, trap_id, 0x08, 0, 8);
/* pci_cqe_crc
* Length include CRC. Indicates the length field includes
* the packet's CRC.
*/
MLXSW_ITEM32(pci, cqe, crc, 0x0C, 8, 1);
/* pci_cqe_e /* pci_cqe_e
* CQE with Error. * CQE with Error.
*/ */
......
...@@ -150,6 +150,64 @@ static inline void mlxsw_reg_smid_pack(char *payload, u16 mid) ...@@ -150,6 +150,64 @@ static inline void mlxsw_reg_smid_pack(char *payload, u16 mid)
mlxsw_reg_smid_port_mask_set(payload, MLXSW_PORT_CPU_PORT, 1); mlxsw_reg_smid_port_mask_set(payload, MLXSW_PORT_CPU_PORT, 1);
} }
/* SSPR - Switch System Port Record Register
* -----------------------------------------
* Configures the system port to local port mapping.
*/
#define MLXSW_REG_SSPR_ID 0x2008
#define MLXSW_REG_SSPR_LEN 0x8
static const struct mlxsw_reg_info mlxsw_reg_sspr = {
.id = MLXSW_REG_SSPR_ID,
.len = MLXSW_REG_SSPR_LEN,
};
/* reg_sspr_m
* Master - if set, then the record describes the master system port.
* This is needed in case a local port is mapped into several system ports
* (for multipathing). That number will be reported as the source system
* port when packets are forwarded to the CPU. Only one master port is allowed
* per local port.
*
* Note: Must be set for Spectrum.
* Access: RW
*/
MLXSW_ITEM32(reg, sspr, m, 0x00, 31, 1);
/* reg_sspr_local_port
* Local port number.
*
* Access: RW
*/
MLXSW_ITEM32(reg, sspr, local_port, 0x00, 16, 8);
/* reg_sspr_sub_port
* Virtual port within the physical port.
* Should be set to 0 when virtual ports are not enabled on the port.
*
* Access: RW
*/
MLXSW_ITEM32(reg, sspr, sub_port, 0x00, 8, 8);
/* reg_sspr_system_port
* Unique identifier within the stacking domain that represents all the ports
* that are available in the system (external ports).
*
* Currently, only single-ASIC configurations are supported, so we default to
* 1:1 mapping between system ports and local ports.
* Access: Index
*/
MLXSW_ITEM32(reg, sspr, system_port, 0x04, 0, 16);
static inline void mlxsw_reg_sspr_pack(char *payload, u8 local_port)
{
MLXSW_REG_ZERO(sspr, payload);
mlxsw_reg_sspr_m_set(payload, 1);
mlxsw_reg_sspr_local_port_set(payload, local_port);
mlxsw_reg_sspr_sub_port_set(payload, 0);
mlxsw_reg_sspr_system_port_set(payload, local_port);
}
/* SPMS - Switch Port MSTP/RSTP State Register /* SPMS - Switch Port MSTP/RSTP State Register
* ------------------------------------------- * -------------------------------------------
* Configures the spanning tree state of a physical port. * Configures the spanning tree state of a physical port.
...@@ -1216,6 +1274,8 @@ static inline const char *mlxsw_reg_id_str(u16 reg_id) ...@@ -1216,6 +1274,8 @@ static inline const char *mlxsw_reg_id_str(u16 reg_id)
return "SPAD"; return "SPAD";
case MLXSW_REG_SMID_ID: case MLXSW_REG_SMID_ID:
return "SMID"; return "SMID";
case MLXSW_REG_SSPR_ID:
return "SSPR";
case MLXSW_REG_SPMS_ID: case MLXSW_REG_SPMS_ID:
return "SPMS"; return "SPMS";
case MLXSW_REG_SFGC_ID: case MLXSW_REG_SFGC_ID:
......
...@@ -245,6 +245,16 @@ static int mlxsw_sx_port_swid_set(struct mlxsw_sx_port *mlxsw_sx_port, u8 swid) ...@@ -245,6 +245,16 @@ static int mlxsw_sx_port_swid_set(struct mlxsw_sx_port *mlxsw_sx_port, u8 swid)
return mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(pspa), pspa_pl); return mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(pspa), pspa_pl);
} }
static int
mlxsw_sx_port_system_port_mapping_set(struct mlxsw_sx_port *mlxsw_sx_port)
{
struct mlxsw_sx *mlxsw_sx = mlxsw_sx_port->mlxsw_sx;
char sspr_pl[MLXSW_REG_SSPR_LEN];
mlxsw_reg_sspr_pack(sspr_pl, mlxsw_sx_port->local_port);
return mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(sspr), sspr_pl);
}
static int mlxsw_sx_port_module_check(struct mlxsw_sx_port *mlxsw_sx_port, static int mlxsw_sx_port_module_check(struct mlxsw_sx_port *mlxsw_sx_port,
bool *p_usable) bool *p_usable)
{ {
...@@ -290,37 +300,34 @@ static netdev_tx_t mlxsw_sx_port_xmit(struct sk_buff *skb, ...@@ -290,37 +300,34 @@ static netdev_tx_t mlxsw_sx_port_xmit(struct sk_buff *skb,
.local_port = mlxsw_sx_port->local_port, .local_port = mlxsw_sx_port->local_port,
.is_emad = false, .is_emad = false,
}; };
struct sk_buff *skb_old = NULL; u64 len;
int err; int err;
if (mlxsw_core_skb_transmit_busy(mlxsw_sx, &tx_info))
return NETDEV_TX_BUSY;
if (unlikely(skb_headroom(skb) < MLXSW_TXHDR_LEN)) { if (unlikely(skb_headroom(skb) < MLXSW_TXHDR_LEN)) {
struct sk_buff *skb_new; struct sk_buff *skb_orig = skb;
skb_old = skb; skb = skb_realloc_headroom(skb, MLXSW_TXHDR_LEN);
skb_new = skb_realloc_headroom(skb, MLXSW_TXHDR_LEN); if (!skb) {
if (!skb_new) {
this_cpu_inc(mlxsw_sx_port->pcpu_stats->tx_dropped); this_cpu_inc(mlxsw_sx_port->pcpu_stats->tx_dropped);
dev_kfree_skb_any(skb_old); dev_kfree_skb_any(skb_orig);
return NETDEV_TX_OK; return NETDEV_TX_OK;
} }
skb = skb_new;
} }
mlxsw_sx_txhdr_construct(skb, &tx_info); mlxsw_sx_txhdr_construct(skb, &tx_info);
len = skb->len;
/* Due to a race we might fail here because of a full queue. In that
* unlikely case we simply drop the packet.
*/
err = mlxsw_core_skb_transmit(mlxsw_sx, skb, &tx_info); err = mlxsw_core_skb_transmit(mlxsw_sx, skb, &tx_info);
if (err == -EAGAIN) {
if (skb_old)
dev_kfree_skb_any(skb);
return NETDEV_TX_BUSY;
}
if (skb_old)
dev_kfree_skb_any(skb_old);
if (!err) { if (!err) {
pcpu_stats = this_cpu_ptr(mlxsw_sx_port->pcpu_stats); pcpu_stats = this_cpu_ptr(mlxsw_sx_port->pcpu_stats);
u64_stats_update_begin(&pcpu_stats->syncp); u64_stats_update_begin(&pcpu_stats->syncp);
pcpu_stats->tx_packets++; pcpu_stats->tx_packets++;
pcpu_stats->tx_bytes += skb->len; pcpu_stats->tx_bytes += len;
u64_stats_update_end(&pcpu_stats->syncp); u64_stats_update_end(&pcpu_stats->syncp);
} else { } else {
this_cpu_inc(mlxsw_sx_port->pcpu_stats->tx_dropped); this_cpu_inc(mlxsw_sx_port->pcpu_stats->tx_dropped);
...@@ -1001,6 +1008,13 @@ static int mlxsw_sx_port_create(struct mlxsw_sx *mlxsw_sx, u8 local_port) ...@@ -1001,6 +1008,13 @@ static int mlxsw_sx_port_create(struct mlxsw_sx *mlxsw_sx, u8 local_port)
goto port_not_usable; goto port_not_usable;
} }
err = mlxsw_sx_port_system_port_mapping_set(mlxsw_sx_port);
if (err) {
dev_err(mlxsw_sx->bus_info->dev, "Port %d: Failed to set system port mapping\n",
mlxsw_sx_port->local_port);
goto err_port_system_port_mapping_set;
}
err = mlxsw_sx_port_swid_set(mlxsw_sx_port, 0); err = mlxsw_sx_port_swid_set(mlxsw_sx_port, 0);
if (err) { if (err) {
dev_err(mlxsw_sx->bus_info->dev, "Port %d: Failed to set SWID\n", dev_err(mlxsw_sx->bus_info->dev, "Port %d: Failed to set SWID\n",
...@@ -1061,6 +1075,7 @@ static int mlxsw_sx_port_create(struct mlxsw_sx *mlxsw_sx, u8 local_port) ...@@ -1061,6 +1075,7 @@ static int mlxsw_sx_port_create(struct mlxsw_sx *mlxsw_sx, u8 local_port)
err_port_mtu_set: err_port_mtu_set:
err_port_speed_set: err_port_speed_set:
err_port_swid_set: err_port_swid_set:
err_port_system_port_mapping_set:
port_not_usable: port_not_usable:
err_port_module_check: err_port_module_check:
err_dev_addr_get: err_dev_addr_get:
...@@ -1079,6 +1094,7 @@ static void mlxsw_sx_port_remove(struct mlxsw_sx *mlxsw_sx, u8 local_port) ...@@ -1079,6 +1094,7 @@ static void mlxsw_sx_port_remove(struct mlxsw_sx *mlxsw_sx, u8 local_port)
unregister_netdev(mlxsw_sx_port->dev); /* This calls ndo_stop */ unregister_netdev(mlxsw_sx_port->dev); /* This calls ndo_stop */
mlxsw_sx_port_swid_set(mlxsw_sx_port, MLXSW_PORT_SWID_DISABLED_PORT); mlxsw_sx_port_swid_set(mlxsw_sx_port, MLXSW_PORT_SWID_DISABLED_PORT);
free_percpu(mlxsw_sx_port->pcpu_stats); free_percpu(mlxsw_sx_port->pcpu_stats);
free_netdev(mlxsw_sx_port->dev);
} }
static void mlxsw_sx_ports_remove(struct mlxsw_sx *mlxsw_sx) static void mlxsw_sx_ports_remove(struct mlxsw_sx *mlxsw_sx)
......
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