Skip to content

Commit 2cf1b5c

Browse files
committed
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: David S. Miller <[email protected]>
2 parents ecea499 + e577516 commit 2cf1b5c

File tree

7 files changed

+135
-24
lines changed

7 files changed

+135
-24
lines changed

drivers/net/ethernet/mellanox/mlxsw/Kconfig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ config MLXSW_CORE
1212

1313
config MLXSW_PCI
1414
tristate "PCI bus implementation for Mellanox Technologies Switch ASICs"
15-
depends on PCI && MLXSW_CORE
15+
depends on PCI && HAS_DMA && HAS_IOMEM && MLXSW_CORE
1616
default m
1717
---help---
1818
This is PCI bus implementation for Mellanox Technologies Switch ASICs.

drivers/net/ethernet/mellanox/mlxsw/core.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -865,6 +865,16 @@ static struct mlxsw_core *__mlxsw_core_get(void *driver_priv)
865865
return container_of(driver_priv, struct mlxsw_core, driver_priv);
866866
}
867867

868+
bool mlxsw_core_skb_transmit_busy(void *driver_priv,
869+
const struct mlxsw_tx_info *tx_info)
870+
{
871+
struct mlxsw_core *mlxsw_core = __mlxsw_core_get(driver_priv);
872+
873+
return mlxsw_core->bus->skb_transmit_busy(mlxsw_core->bus_priv,
874+
tx_info);
875+
}
876+
EXPORT_SYMBOL(mlxsw_core_skb_transmit_busy);
877+
868878
int mlxsw_core_skb_transmit(void *driver_priv, struct sk_buff *skb,
869879
const struct mlxsw_tx_info *tx_info)
870880
{
@@ -1063,7 +1073,7 @@ static int mlxsw_core_reg_access_emad(struct mlxsw_core *mlxsw_core,
10631073
mlxsw_core->emad.tid - 1);
10641074
mlxsw_core_buf_dump_dbg(mlxsw_core,
10651075
mlxsw_core->emad.resp_skb->data,
1066-
skb->len);
1076+
mlxsw_core->emad.resp_skb->len);
10671077

10681078
dev_kfree_skb(mlxsw_core->emad.resp_skb);
10691079
}

drivers/net/ethernet/mellanox/mlxsw/core.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@ struct mlxsw_tx_info {
7373
bool is_emad;
7474
};
7575

76+
bool mlxsw_core_skb_transmit_busy(void *driver_priv,
77+
const struct mlxsw_tx_info *tx_info);
78+
7679
int mlxsw_core_skb_transmit(void *driver_priv, struct sk_buff *skb,
7780
const struct mlxsw_tx_info *tx_info);
7881

@@ -177,6 +180,8 @@ struct mlxsw_bus {
177180
int (*init)(void *bus_priv, struct mlxsw_core *mlxsw_core,
178181
const struct mlxsw_config_profile *profile);
179182
void (*fini)(void *bus_priv);
183+
bool (*skb_transmit_busy)(void *bus_priv,
184+
const struct mlxsw_tx_info *tx_info);
180185
int (*skb_transmit)(void *bus_priv, struct sk_buff *skb,
181186
const struct mlxsw_tx_info *tx_info);
182187
int (*cmd_exec)(void *bus_priv, u16 opcode, u8 opcode_mod,

drivers/net/ethernet/mellanox/mlxsw/pci.c

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -667,6 +667,7 @@ static void mlxsw_pci_cqe_rdq_handle(struct mlxsw_pci *mlxsw_pci,
667667
char *wqe;
668668
struct sk_buff *skb;
669669
struct mlxsw_rx_info rx_info;
670+
u16 byte_count;
670671
int err;
671672

672673
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,
686687
rx_info.sys_port = mlxsw_pci_cqe_system_port_get(cqe);
687688
rx_info.trap_id = mlxsw_pci_cqe_trap_id_get(cqe);
688689

689-
skb_put(skb, mlxsw_pci_cqe_byte_count_get(cqe));
690+
byte_count = mlxsw_pci_cqe_byte_count_get(cqe);
691+
if (mlxsw_pci_cqe_crc_get(cqe))
692+
byte_count -= ETH_FCS_LEN;
693+
skb_put(skb, byte_count);
690694
mlxsw_core_skb_receive(mlxsw_pci->core, skb, &rx_info);
691695

692696
put_new_skb:
@@ -1439,6 +1443,15 @@ mlxsw_pci_sdq_pick(struct mlxsw_pci *mlxsw_pci,
14391443
return mlxsw_pci_sdq_get(mlxsw_pci, sdqn);
14401444
}
14411445

1446+
static bool mlxsw_pci_skb_transmit_busy(void *bus_priv,
1447+
const struct mlxsw_tx_info *tx_info)
1448+
{
1449+
struct mlxsw_pci *mlxsw_pci = bus_priv;
1450+
struct mlxsw_pci_queue *q = mlxsw_pci_sdq_pick(mlxsw_pci, tx_info);
1451+
1452+
return !mlxsw_pci_queue_elem_info_producer_get(q);
1453+
}
1454+
14421455
static int mlxsw_pci_skb_transmit(void *bus_priv, struct sk_buff *skb,
14431456
const struct mlxsw_tx_info *tx_info)
14441457
{
@@ -1621,11 +1634,12 @@ static int mlxsw_pci_cmd_exec(void *bus_priv, u16 opcode, u8 opcode_mod,
16211634
}
16221635

16231636
static const struct mlxsw_bus mlxsw_pci_bus = {
1624-
.kind = "pci",
1625-
.init = mlxsw_pci_init,
1626-
.fini = mlxsw_pci_fini,
1627-
.skb_transmit = mlxsw_pci_skb_transmit,
1628-
.cmd_exec = mlxsw_pci_cmd_exec,
1637+
.kind = "pci",
1638+
.init = mlxsw_pci_init,
1639+
.fini = mlxsw_pci_fini,
1640+
.skb_transmit_busy = mlxsw_pci_skb_transmit_busy,
1641+
.skb_transmit = mlxsw_pci_skb_transmit,
1642+
.cmd_exec = mlxsw_pci_cmd_exec,
16291643
};
16301644

16311645
static int mlxsw_pci_sw_reset(struct mlxsw_pci *mlxsw_pci)

drivers/net/ethernet/mellanox/mlxsw/pci.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,12 @@ MLXSW_ITEM32(pci, cqe, byte_count, 0x04, 0, 14);
155155
*/
156156
MLXSW_ITEM32(pci, cqe, trap_id, 0x08, 0, 8);
157157

158+
/* pci_cqe_crc
159+
* Length include CRC. Indicates the length field includes
160+
* the packet's CRC.
161+
*/
162+
MLXSW_ITEM32(pci, cqe, crc, 0x0C, 8, 1);
163+
158164
/* pci_cqe_e
159165
* CQE with Error.
160166
*/

drivers/net/ethernet/mellanox/mlxsw/reg.h

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,64 @@ static inline void mlxsw_reg_smid_pack(char *payload, u16 mid)
150150
mlxsw_reg_smid_port_mask_set(payload, MLXSW_PORT_CPU_PORT, 1);
151151
}
152152

153+
/* SSPR - Switch System Port Record Register
154+
* -----------------------------------------
155+
* Configures the system port to local port mapping.
156+
*/
157+
#define MLXSW_REG_SSPR_ID 0x2008
158+
#define MLXSW_REG_SSPR_LEN 0x8
159+
160+
static const struct mlxsw_reg_info mlxsw_reg_sspr = {
161+
.id = MLXSW_REG_SSPR_ID,
162+
.len = MLXSW_REG_SSPR_LEN,
163+
};
164+
165+
/* reg_sspr_m
166+
* Master - if set, then the record describes the master system port.
167+
* This is needed in case a local port is mapped into several system ports
168+
* (for multipathing). That number will be reported as the source system
169+
* port when packets are forwarded to the CPU. Only one master port is allowed
170+
* per local port.
171+
*
172+
* Note: Must be set for Spectrum.
173+
* Access: RW
174+
*/
175+
MLXSW_ITEM32(reg, sspr, m, 0x00, 31, 1);
176+
177+
/* reg_sspr_local_port
178+
* Local port number.
179+
*
180+
* Access: RW
181+
*/
182+
MLXSW_ITEM32(reg, sspr, local_port, 0x00, 16, 8);
183+
184+
/* reg_sspr_sub_port
185+
* Virtual port within the physical port.
186+
* Should be set to 0 when virtual ports are not enabled on the port.
187+
*
188+
* Access: RW
189+
*/
190+
MLXSW_ITEM32(reg, sspr, sub_port, 0x00, 8, 8);
191+
192+
/* reg_sspr_system_port
193+
* Unique identifier within the stacking domain that represents all the ports
194+
* that are available in the system (external ports).
195+
*
196+
* Currently, only single-ASIC configurations are supported, so we default to
197+
* 1:1 mapping between system ports and local ports.
198+
* Access: Index
199+
*/
200+
MLXSW_ITEM32(reg, sspr, system_port, 0x04, 0, 16);
201+
202+
static inline void mlxsw_reg_sspr_pack(char *payload, u8 local_port)
203+
{
204+
MLXSW_REG_ZERO(sspr, payload);
205+
mlxsw_reg_sspr_m_set(payload, 1);
206+
mlxsw_reg_sspr_local_port_set(payload, local_port);
207+
mlxsw_reg_sspr_sub_port_set(payload, 0);
208+
mlxsw_reg_sspr_system_port_set(payload, local_port);
209+
}
210+
153211
/* SPMS - Switch Port MSTP/RSTP State Register
154212
* -------------------------------------------
155213
* Configures the spanning tree state of a physical port.
@@ -1216,6 +1274,8 @@ static inline const char *mlxsw_reg_id_str(u16 reg_id)
12161274
return "SPAD";
12171275
case MLXSW_REG_SMID_ID:
12181276
return "SMID";
1277+
case MLXSW_REG_SSPR_ID:
1278+
return "SSPR";
12191279
case MLXSW_REG_SPMS_ID:
12201280
return "SPMS";
12211281
case MLXSW_REG_SFGC_ID:

drivers/net/ethernet/mellanox/mlxsw/switchx2.c

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,16 @@ static int mlxsw_sx_port_swid_set(struct mlxsw_sx_port *mlxsw_sx_port, u8 swid)
245245
return mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(pspa), pspa_pl);
246246
}
247247

248+
static int
249+
mlxsw_sx_port_system_port_mapping_set(struct mlxsw_sx_port *mlxsw_sx_port)
250+
{
251+
struct mlxsw_sx *mlxsw_sx = mlxsw_sx_port->mlxsw_sx;
252+
char sspr_pl[MLXSW_REG_SSPR_LEN];
253+
254+
mlxsw_reg_sspr_pack(sspr_pl, mlxsw_sx_port->local_port);
255+
return mlxsw_reg_write(mlxsw_sx->core, MLXSW_REG(sspr), sspr_pl);
256+
}
257+
248258
static int mlxsw_sx_port_module_check(struct mlxsw_sx_port *mlxsw_sx_port,
249259
bool *p_usable)
250260
{
@@ -290,37 +300,34 @@ static netdev_tx_t mlxsw_sx_port_xmit(struct sk_buff *skb,
290300
.local_port = mlxsw_sx_port->local_port,
291301
.is_emad = false,
292302
};
293-
struct sk_buff *skb_old = NULL;
303+
u64 len;
294304
int err;
295305

306+
if (mlxsw_core_skb_transmit_busy(mlxsw_sx, &tx_info))
307+
return NETDEV_TX_BUSY;
308+
296309
if (unlikely(skb_headroom(skb) < MLXSW_TXHDR_LEN)) {
297-
struct sk_buff *skb_new;
310+
struct sk_buff *skb_orig = skb;
298311

299-
skb_old = skb;
300-
skb_new = skb_realloc_headroom(skb, MLXSW_TXHDR_LEN);
301-
if (!skb_new) {
312+
skb = skb_realloc_headroom(skb, MLXSW_TXHDR_LEN);
313+
if (!skb) {
302314
this_cpu_inc(mlxsw_sx_port->pcpu_stats->tx_dropped);
303-
dev_kfree_skb_any(skb_old);
315+
dev_kfree_skb_any(skb_orig);
304316
return NETDEV_TX_OK;
305317
}
306-
skb = skb_new;
307318
}
308319
mlxsw_sx_txhdr_construct(skb, &tx_info);
320+
len = skb->len;
321+
/* Due to a race we might fail here because of a full queue. In that
322+
* unlikely case we simply drop the packet.
323+
*/
309324
err = mlxsw_core_skb_transmit(mlxsw_sx, skb, &tx_info);
310-
if (err == -EAGAIN) {
311-
if (skb_old)
312-
dev_kfree_skb_any(skb);
313-
return NETDEV_TX_BUSY;
314-
}
315-
316-
if (skb_old)
317-
dev_kfree_skb_any(skb_old);
318325

319326
if (!err) {
320327
pcpu_stats = this_cpu_ptr(mlxsw_sx_port->pcpu_stats);
321328
u64_stats_update_begin(&pcpu_stats->syncp);
322329
pcpu_stats->tx_packets++;
323-
pcpu_stats->tx_bytes += skb->len;
330+
pcpu_stats->tx_bytes += len;
324331
u64_stats_update_end(&pcpu_stats->syncp);
325332
} else {
326333
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)
10011008
goto port_not_usable;
10021009
}
10031010

1011+
err = mlxsw_sx_port_system_port_mapping_set(mlxsw_sx_port);
1012+
if (err) {
1013+
dev_err(mlxsw_sx->bus_info->dev, "Port %d: Failed to set system port mapping\n",
1014+
mlxsw_sx_port->local_port);
1015+
goto err_port_system_port_mapping_set;
1016+
}
1017+
10041018
err = mlxsw_sx_port_swid_set(mlxsw_sx_port, 0);
10051019
if (err) {
10061020
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)
10611075
err_port_mtu_set:
10621076
err_port_speed_set:
10631077
err_port_swid_set:
1078+
err_port_system_port_mapping_set:
10641079
port_not_usable:
10651080
err_port_module_check:
10661081
err_dev_addr_get:
@@ -1079,6 +1094,7 @@ static void mlxsw_sx_port_remove(struct mlxsw_sx *mlxsw_sx, u8 local_port)
10791094
unregister_netdev(mlxsw_sx_port->dev); /* This calls ndo_stop */
10801095
mlxsw_sx_port_swid_set(mlxsw_sx_port, MLXSW_PORT_SWID_DISABLED_PORT);
10811096
free_percpu(mlxsw_sx_port->pcpu_stats);
1097+
free_netdev(mlxsw_sx_port->dev);
10821098
}
10831099

10841100
static void mlxsw_sx_ports_remove(struct mlxsw_sx *mlxsw_sx)

0 commit comments

Comments
 (0)