aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJack Morgenstein <jackm@dev.mellanox.co.il>2013-11-03 03:03:21 -0500
committerDavid S. Miller <davem@davemloft.net>2013-11-04 16:19:07 -0500
commit2c957ff27dbbabec4ec406420fab9677d59f7161 (patch)
treeda99f8eff998ec40f3015aba40992a4a9bd73322
parent4874080dee8a3fd4ebc3aefd68503fa0e130bd12 (diff)
net/mlx4_core: Don't fail reg/unreg vlan for older guests
In upstream kernels under SRIOV, the vlan register/unregister calls were NOPs (doing nothing and returning OK). We detect these old calls from guests (via the comm channel), since previously the port number in mlx4_register_vlan was passed (improperly) in the out_param. This has been corrected so that the port number is now passed in bits 8..15 of the in_modifier field. For old calls, these bits will be zero, so if the passed port number is zero, we can still look at the out_param field to see if it contains a valid port number. If yes, the VM is running an old driver. Since for old drivers, the register/unregister_vlan wrappers were NOPs, we continue this policy -- the reason being that upstream had an additional bug in eth driver running on guests (where procedure mlx4_en_vlan_rx_kill_vid() had the following code: if (!mlx4_find_cached_vlan(mdev->dev, priv->port, vid, &idx)) mlx4_unregister_vlan(mdev->dev, priv->port, idx); else en_err(priv, "could not find vid %d in cache\n", vid); On a VM, mlx4_find_cached_vlan() will always fail, since the vlan cache is located on the Hypervisor; on guests it is empty. Therefore, if we allow upstream guests to register vlans, we will have vlan leakage since the unregister will never be performed. Leaving vlan reg/unreg for old guest drivers as a NOP is not a feature regression, since in upstream the register/unregister vlan wrapper is a NOP. Signed-off-by: Jack Morgenstein <jackm@dev.mellanox.co.il> Signed-off-by: Or Gerlitz <ogerlitz@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/cmd.c1
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/mlx4.h1
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/resource_tracker.c17
3 files changed, 18 insertions, 1 deletions
diff --git a/drivers/net/ethernet/mellanox/mlx4/cmd.c b/drivers/net/ethernet/mellanox/mlx4/cmd.c
index 887d62576f54..65d41b76fa2c 100644
--- a/drivers/net/ethernet/mellanox/mlx4/cmd.c
+++ b/drivers/net/ethernet/mellanox/mlx4/cmd.c
@@ -1718,6 +1718,7 @@ static void mlx4_master_do_cmd(struct mlx4_dev *dev, int slave, u8 cmd,
1718 if (cmd == MLX4_COMM_CMD_RESET) { 1718 if (cmd == MLX4_COMM_CMD_RESET) {
1719 mlx4_warn(dev, "Received reset from slave:%d\n", slave); 1719 mlx4_warn(dev, "Received reset from slave:%d\n", slave);
1720 slave_state[slave].active = false; 1720 slave_state[slave].active = false;
1721 slave_state[slave].old_vlan_api = false;
1721 mlx4_master_deactivate_admin_state(priv, slave); 1722 mlx4_master_deactivate_admin_state(priv, slave);
1722 for (i = 0; i < MLX4_EVENT_TYPES_NUM; ++i) { 1723 for (i = 0; i < MLX4_EVENT_TYPES_NUM; ++i) {
1723 slave_state[slave].event_eq[i].eqn = -1; 1724 slave_state[slave].event_eq[i].eqn = -1;
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4.h b/drivers/net/ethernet/mellanox/mlx4/mlx4.h
index f2ad4f61f58c..97941269bc14 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4.h
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4.h
@@ -455,6 +455,7 @@ struct mlx4_slave_state {
455 u8 last_cmd; 455 u8 last_cmd;
456 u8 init_port_mask; 456 u8 init_port_mask;
457 bool active; 457 bool active;
458 bool old_vlan_api;
458 u8 function; 459 u8 function;
459 dma_addr_t vhcr_dma; 460 dma_addr_t vhcr_dma;
460 u16 mtu[MLX4_MAX_PORTS + 1]; 461 u16 mtu[MLX4_MAX_PORTS + 1];
diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
index e18bfff04ced..35863889bec0 100644
--- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
+++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
@@ -1555,15 +1555,26 @@ static void rem_slave_vlans(struct mlx4_dev *dev, int slave)
1555} 1555}
1556 1556
1557static int vlan_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, 1557static int vlan_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd,
1558 u64 in_param, u64 *out_param, int port) 1558 u64 in_param, u64 *out_param, int in_port)
1559{ 1559{
1560 struct mlx4_priv *priv = mlx4_priv(dev);
1561 struct mlx4_slave_state *slave_state = priv->mfunc.master.slave_state;
1560 int err; 1562 int err;
1561 u16 vlan; 1563 u16 vlan;
1562 int vlan_index; 1564 int vlan_index;
1565 int port;
1566
1567 port = !in_port ? get_param_l(out_param) : in_port;
1563 1568
1564 if (!port || op != RES_OP_RESERVE_AND_MAP) 1569 if (!port || op != RES_OP_RESERVE_AND_MAP)
1565 return -EINVAL; 1570 return -EINVAL;
1566 1571
1572 /* upstream kernels had NOP for reg/unreg vlan. Continue this. */
1573 if (!in_port && port > 0 && port <= dev->caps.num_ports) {
1574 slave_state[slave].old_vlan_api = true;
1575 return 0;
1576 }
1577
1567 vlan = (u16) in_param; 1578 vlan = (u16) in_param;
1568 1579
1569 err = __mlx4_register_vlan(dev, port, vlan, &vlan_index); 1580 err = __mlx4_register_vlan(dev, port, vlan, &vlan_index);
@@ -1856,10 +1867,14 @@ static int mac_free_res(struct mlx4_dev *dev, int slave, int op, int cmd,
1856static int vlan_free_res(struct mlx4_dev *dev, int slave, int op, int cmd, 1867static int vlan_free_res(struct mlx4_dev *dev, int slave, int op, int cmd,
1857 u64 in_param, u64 *out_param, int port) 1868 u64 in_param, u64 *out_param, int port)
1858{ 1869{
1870 struct mlx4_priv *priv = mlx4_priv(dev);
1871 struct mlx4_slave_state *slave_state = priv->mfunc.master.slave_state;
1859 int err = 0; 1872 int err = 0;
1860 1873
1861 switch (op) { 1874 switch (op) {
1862 case RES_OP_RESERVE_AND_MAP: 1875 case RES_OP_RESERVE_AND_MAP:
1876 if (slave_state[slave].old_vlan_api)
1877 return 0;
1863 if (!port) 1878 if (!port)
1864 return -EINVAL; 1879 return -EINVAL;
1865 vlan_del_from_slave(dev, slave, in_param, port); 1880 vlan_del_from_slave(dev, slave, in_param, port);