diff options
author | Jack Morgenstein <jackm@dev.mellanox.co.il> | 2013-06-27 12:05:21 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-07-01 16:10:22 -0400 |
commit | b01978cacfd7e3a4ca703b0e48f2e18de8865df5 (patch) | |
tree | 73beae91335dbcf4a4129b3970be68f1082aff0b /drivers/net/ethernet | |
parent | 4e144d3a807d6d2aa03d2cb234d88ef1a140e8c3 (diff) |
net/mlx4_core: Dynamic VST to VST vlan/qos changes
Within VST mode, enable modifying the vlan and/or qos
for a VF without requiring unbind/rebind.
This requires firmware which supports the UPDATE_QP command.
(If the command is not available, we fall back to requiring
unbind/bind to activate these changes).
To avoid race conditions with modify-qp on QPs that are affected
by update-qp, this operation is performed on the comm_wq.
If the update operation succeeds for all the necessary QPs, a
vlan_unregister is performed for the abandoned vlan id.
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>
Diffstat (limited to 'drivers/net/ethernet')
-rw-r--r-- | drivers/net/ethernet/mellanox/mlx4/cmd.c | 122 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlx4/fw.c | 5 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlx4/mlx4.h | 20 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlx4/resource_tracker.c | 145 |
4 files changed, 282 insertions, 10 deletions
diff --git a/drivers/net/ethernet/mellanox/mlx4/cmd.c b/drivers/net/ethernet/mellanox/mlx4/cmd.c index df04c8206ebe..7b927891dc35 100644 --- a/drivers/net/ethernet/mellanox/mlx4/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx4/cmd.c | |||
@@ -112,6 +112,14 @@ enum { | |||
112 | GO_BIT_TIMEOUT_MSECS = 10000 | 112 | GO_BIT_TIMEOUT_MSECS = 10000 |
113 | }; | 113 | }; |
114 | 114 | ||
115 | enum mlx4_vlan_transition { | ||
116 | MLX4_VLAN_TRANSITION_VST_VST = 0, | ||
117 | MLX4_VLAN_TRANSITION_VST_VGT = 1, | ||
118 | MLX4_VLAN_TRANSITION_VGT_VST = 2, | ||
119 | MLX4_VLAN_TRANSITION_VGT_VGT = 3, | ||
120 | }; | ||
121 | |||
122 | |||
115 | struct mlx4_cmd_context { | 123 | struct mlx4_cmd_context { |
116 | struct completion done; | 124 | struct completion done; |
117 | int result; | 125 | int result; |
@@ -792,6 +800,15 @@ static int mlx4_MAD_IFC_wrapper(struct mlx4_dev *dev, int slave, | |||
792 | vhcr->op, MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE); | 800 | vhcr->op, MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE); |
793 | } | 801 | } |
794 | 802 | ||
803 | int MLX4_CMD_UPDATE_QP_wrapper(struct mlx4_dev *dev, int slave, | ||
804 | struct mlx4_vhcr *vhcr, | ||
805 | struct mlx4_cmd_mailbox *inbox, | ||
806 | struct mlx4_cmd_mailbox *outbox, | ||
807 | struct mlx4_cmd_info *cmd) | ||
808 | { | ||
809 | return -EPERM; | ||
810 | } | ||
811 | |||
795 | int mlx4_DMA_wrapper(struct mlx4_dev *dev, int slave, | 812 | int mlx4_DMA_wrapper(struct mlx4_dev *dev, int slave, |
796 | struct mlx4_vhcr *vhcr, | 813 | struct mlx4_vhcr *vhcr, |
797 | struct mlx4_cmd_mailbox *inbox, | 814 | struct mlx4_cmd_mailbox *inbox, |
@@ -1226,6 +1243,15 @@ static struct mlx4_cmd_info cmd_info[] = { | |||
1226 | .wrapper = mlx4_GEN_QP_wrapper | 1243 | .wrapper = mlx4_GEN_QP_wrapper |
1227 | }, | 1244 | }, |
1228 | { | 1245 | { |
1246 | .opcode = MLX4_CMD_UPDATE_QP, | ||
1247 | .has_inbox = false, | ||
1248 | .has_outbox = false, | ||
1249 | .out_is_imm = false, | ||
1250 | .encode_slave_id = false, | ||
1251 | .verify = NULL, | ||
1252 | .wrapper = MLX4_CMD_UPDATE_QP_wrapper | ||
1253 | }, | ||
1254 | { | ||
1229 | .opcode = MLX4_CMD_CONF_SPECIAL_QP, | 1255 | .opcode = MLX4_CMD_CONF_SPECIAL_QP, |
1230 | .has_inbox = false, | 1256 | .has_inbox = false, |
1231 | .has_outbox = false, | 1257 | .has_outbox = false, |
@@ -1495,6 +1521,72 @@ out: | |||
1495 | return ret; | 1521 | return ret; |
1496 | } | 1522 | } |
1497 | 1523 | ||
1524 | |||
1525 | int mlx4_master_immediate_activate_vlan_qos(struct mlx4_priv *priv, | ||
1526 | int slave, int port) | ||
1527 | { | ||
1528 | struct mlx4_vport_oper_state *vp_oper; | ||
1529 | struct mlx4_vport_state *vp_admin; | ||
1530 | struct mlx4_vf_immed_vlan_work *work; | ||
1531 | int err; | ||
1532 | int admin_vlan_ix = NO_INDX; | ||
1533 | |||
1534 | vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port]; | ||
1535 | vp_admin = &priv->mfunc.master.vf_admin[slave].vport[port]; | ||
1536 | |||
1537 | if (vp_oper->state.default_vlan == vp_admin->default_vlan && | ||
1538 | vp_oper->state.default_qos == vp_admin->default_qos) | ||
1539 | return 0; | ||
1540 | |||
1541 | work = kzalloc(sizeof(*work), GFP_KERNEL); | ||
1542 | if (!work) | ||
1543 | return -ENOMEM; | ||
1544 | |||
1545 | if (vp_oper->state.default_vlan != vp_admin->default_vlan) { | ||
1546 | err = __mlx4_register_vlan(&priv->dev, port, | ||
1547 | vp_admin->default_vlan, | ||
1548 | &admin_vlan_ix); | ||
1549 | if (err) { | ||
1550 | mlx4_warn((&priv->dev), | ||
1551 | "No vlan resources slave %d, port %d\n", | ||
1552 | slave, port); | ||
1553 | return err; | ||
1554 | } | ||
1555 | work->flags |= MLX4_VF_IMMED_VLAN_FLAG_VLAN; | ||
1556 | mlx4_dbg((&(priv->dev)), | ||
1557 | "alloc vlan %d idx %d slave %d port %d\n", | ||
1558 | (int)(vp_admin->default_vlan), | ||
1559 | admin_vlan_ix, slave, port); | ||
1560 | } | ||
1561 | |||
1562 | /* save original vlan ix and vlan id */ | ||
1563 | work->orig_vlan_id = vp_oper->state.default_vlan; | ||
1564 | work->orig_vlan_ix = vp_oper->vlan_idx; | ||
1565 | |||
1566 | /* handle new qos */ | ||
1567 | if (vp_oper->state.default_qos != vp_admin->default_qos) | ||
1568 | work->flags |= MLX4_VF_IMMED_VLAN_FLAG_QOS; | ||
1569 | |||
1570 | if (work->flags & MLX4_VF_IMMED_VLAN_FLAG_VLAN) | ||
1571 | vp_oper->vlan_idx = admin_vlan_ix; | ||
1572 | |||
1573 | vp_oper->state.default_vlan = vp_admin->default_vlan; | ||
1574 | vp_oper->state.default_qos = vp_admin->default_qos; | ||
1575 | |||
1576 | /* iterate over QPs owned by this slave, using UPDATE_QP */ | ||
1577 | work->port = port; | ||
1578 | work->slave = slave; | ||
1579 | work->qos = vp_oper->state.default_qos; | ||
1580 | work->vlan_id = vp_oper->state.default_vlan; | ||
1581 | work->vlan_ix = vp_oper->vlan_idx; | ||
1582 | work->priv = priv; | ||
1583 | INIT_WORK(&work->work, mlx4_vf_immed_vlan_work_handler); | ||
1584 | queue_work(priv->mfunc.master.comm_wq, &work->work); | ||
1585 | |||
1586 | return 0; | ||
1587 | } | ||
1588 | |||
1589 | |||
1498 | static int mlx4_master_activate_admin_state(struct mlx4_priv *priv, int slave) | 1590 | static int mlx4_master_activate_admin_state(struct mlx4_priv *priv, int slave) |
1499 | { | 1591 | { |
1500 | int port, err; | 1592 | int port, err; |
@@ -2109,11 +2201,18 @@ int mlx4_set_vf_mac(struct mlx4_dev *dev, int port, int vf, u64 mac) | |||
2109 | } | 2201 | } |
2110 | EXPORT_SYMBOL_GPL(mlx4_set_vf_mac); | 2202 | EXPORT_SYMBOL_GPL(mlx4_set_vf_mac); |
2111 | 2203 | ||
2204 | static int calculate_transition(u16 oper_vlan, u16 admin_vlan) | ||
2205 | { | ||
2206 | return (2 * (oper_vlan == MLX4_VGT) + (admin_vlan == MLX4_VGT)); | ||
2207 | } | ||
2208 | |||
2112 | int mlx4_set_vf_vlan(struct mlx4_dev *dev, int port, int vf, u16 vlan, u8 qos) | 2209 | int mlx4_set_vf_vlan(struct mlx4_dev *dev, int port, int vf, u16 vlan, u8 qos) |
2113 | { | 2210 | { |
2114 | struct mlx4_priv *priv = mlx4_priv(dev); | 2211 | struct mlx4_priv *priv = mlx4_priv(dev); |
2115 | struct mlx4_vport_state *s_info; | 2212 | struct mlx4_vport_oper_state *vf_oper; |
2213 | struct mlx4_vport_state *vf_admin; | ||
2116 | int slave; | 2214 | int slave; |
2215 | enum mlx4_vlan_transition vlan_trans; | ||
2117 | 2216 | ||
2118 | if ((!mlx4_is_master(dev)) || | 2217 | if ((!mlx4_is_master(dev)) || |
2119 | !(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_VLAN_CONTROL)) | 2218 | !(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_VLAN_CONTROL)) |
@@ -2126,12 +2225,25 @@ int mlx4_set_vf_vlan(struct mlx4_dev *dev, int port, int vf, u16 vlan, u8 qos) | |||
2126 | if (slave < 0) | 2225 | if (slave < 0) |
2127 | return -EINVAL; | 2226 | return -EINVAL; |
2128 | 2227 | ||
2129 | s_info = &priv->mfunc.master.vf_admin[slave].vport[port]; | 2228 | vf_admin = &priv->mfunc.master.vf_admin[slave].vport[port]; |
2229 | vf_oper = &priv->mfunc.master.vf_oper[slave].vport[port]; | ||
2230 | |||
2130 | if ((0 == vlan) && (0 == qos)) | 2231 | if ((0 == vlan) && (0 == qos)) |
2131 | s_info->default_vlan = MLX4_VGT; | 2232 | vf_admin->default_vlan = MLX4_VGT; |
2132 | else | 2233 | else |
2133 | s_info->default_vlan = vlan; | 2234 | vf_admin->default_vlan = vlan; |
2134 | s_info->default_qos = qos; | 2235 | vf_admin->default_qos = qos; |
2236 | |||
2237 | vlan_trans = calculate_transition(vf_oper->state.default_vlan, | ||
2238 | vf_admin->default_vlan); | ||
2239 | |||
2240 | if (priv->mfunc.master.slave_state[slave].active && | ||
2241 | dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_UPDATE_QP && | ||
2242 | vlan_trans == MLX4_VLAN_TRANSITION_VST_VST) { | ||
2243 | mlx4_info(dev, "updating vf %d port %d config params immediately\n", | ||
2244 | vf, port); | ||
2245 | mlx4_master_immediate_activate_vlan_qos(priv, slave, port); | ||
2246 | } | ||
2135 | return 0; | 2247 | return 0; |
2136 | } | 2248 | } |
2137 | EXPORT_SYMBOL_GPL(mlx4_set_vf_vlan); | 2249 | EXPORT_SYMBOL_GPL(mlx4_set_vf_vlan); |
diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.c b/drivers/net/ethernet/mellanox/mlx4/fw.c index 569bbe3e7403..8873d6802c80 100644 --- a/drivers/net/ethernet/mellanox/mlx4/fw.c +++ b/drivers/net/ethernet/mellanox/mlx4/fw.c | |||
@@ -133,7 +133,8 @@ static void dump_dev_cap_flags2(struct mlx4_dev *dev, u64 flags) | |||
133 | [4] = "Automatic MAC reassignment support", | 133 | [4] = "Automatic MAC reassignment support", |
134 | [5] = "Time stamping support", | 134 | [5] = "Time stamping support", |
135 | [6] = "VST (control vlan insertion/stripping) support", | 135 | [6] = "VST (control vlan insertion/stripping) support", |
136 | [7] = "FSM (MAC anti-spoofing) support" | 136 | [7] = "FSM (MAC anti-spoofing) support", |
137 | [8] = "Dynamic QP updates support" | ||
137 | }; | 138 | }; |
138 | int i; | 139 | int i; |
139 | 140 | ||
@@ -659,6 +660,8 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) | |||
659 | QUERY_DEV_CAP_MAX_COUNTERS_OFFSET); | 660 | QUERY_DEV_CAP_MAX_COUNTERS_OFFSET); |
660 | 661 | ||
661 | MLX4_GET(field32, outbox, QUERY_DEV_CAP_EXT_2_FLAGS_OFFSET); | 662 | MLX4_GET(field32, outbox, QUERY_DEV_CAP_EXT_2_FLAGS_OFFSET); |
663 | if (field32 & (1 << 16)) | ||
664 | dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_UPDATE_QP; | ||
662 | if (field32 & (1 << 26)) | 665 | if (field32 & (1 << 26)) |
663 | dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_VLAN_CONTROL; | 666 | dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_VLAN_CONTROL; |
664 | if (field32 & (1 << 20)) | 667 | if (field32 & (1 << 20)) |
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4.h b/drivers/net/ethernet/mellanox/mlx4/mlx4.h index 75272935a3f7..5abcb6501e30 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4.h | |||
@@ -571,6 +571,24 @@ struct mlx4_cmd { | |||
571 | u8 comm_toggle; | 571 | u8 comm_toggle; |
572 | }; | 572 | }; |
573 | 573 | ||
574 | enum { | ||
575 | MLX4_VF_IMMED_VLAN_FLAG_VLAN = 1 << 0, | ||
576 | MLX4_VF_IMMED_VLAN_FLAG_QOS = 1 << 1, | ||
577 | }; | ||
578 | struct mlx4_vf_immed_vlan_work { | ||
579 | struct work_struct work; | ||
580 | struct mlx4_priv *priv; | ||
581 | int flags; | ||
582 | int slave; | ||
583 | int vlan_ix; | ||
584 | int orig_vlan_ix; | ||
585 | u8 port; | ||
586 | u8 qos; | ||
587 | u16 vlan_id; | ||
588 | u16 orig_vlan_id; | ||
589 | }; | ||
590 | |||
591 | |||
574 | struct mlx4_uar_table { | 592 | struct mlx4_uar_table { |
575 | struct mlx4_bitmap bitmap; | 593 | struct mlx4_bitmap bitmap; |
576 | }; | 594 | }; |
@@ -1218,4 +1236,6 @@ static inline spinlock_t *mlx4_tlock(struct mlx4_dev *dev) | |||
1218 | 1236 | ||
1219 | #define NOT_MASKED_PD_BITS 17 | 1237 | #define NOT_MASKED_PD_BITS 17 |
1220 | 1238 | ||
1239 | void mlx4_vf_immed_vlan_work_handler(struct work_struct *_work); | ||
1240 | |||
1221 | #endif /* MLX4_H */ | 1241 | #endif /* MLX4_H */ |
diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c index 1157f028a90f..46323a20060c 100644 --- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c +++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c | |||
@@ -101,6 +101,8 @@ struct res_qp { | |||
101 | spinlock_t mcg_spl; | 101 | spinlock_t mcg_spl; |
102 | int local_qpn; | 102 | int local_qpn; |
103 | atomic_t ref_count; | 103 | atomic_t ref_count; |
104 | u32 qpc_flags; | ||
105 | u8 sched_queue; | ||
104 | }; | 106 | }; |
105 | 107 | ||
106 | enum res_mtt_states { | 108 | enum res_mtt_states { |
@@ -355,7 +357,7 @@ static void update_gid(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *inbox, | |||
355 | 357 | ||
356 | static int update_vport_qp_param(struct mlx4_dev *dev, | 358 | static int update_vport_qp_param(struct mlx4_dev *dev, |
357 | struct mlx4_cmd_mailbox *inbox, | 359 | struct mlx4_cmd_mailbox *inbox, |
358 | u8 slave) | 360 | u8 slave, u32 qpn) |
359 | { | 361 | { |
360 | struct mlx4_qp_context *qpc = inbox->buf + 8; | 362 | struct mlx4_qp_context *qpc = inbox->buf + 8; |
361 | struct mlx4_vport_oper_state *vp_oper; | 363 | struct mlx4_vport_oper_state *vp_oper; |
@@ -369,9 +371,17 @@ static int update_vport_qp_param(struct mlx4_dev *dev, | |||
369 | 371 | ||
370 | if (MLX4_VGT != vp_oper->state.default_vlan) { | 372 | if (MLX4_VGT != vp_oper->state.default_vlan) { |
371 | qp_type = (be32_to_cpu(qpc->flags) >> 16) & 0xff; | 373 | qp_type = (be32_to_cpu(qpc->flags) >> 16) & 0xff; |
372 | if (MLX4_QP_ST_RC == qp_type) | 374 | if (MLX4_QP_ST_RC == qp_type || |
375 | (MLX4_QP_ST_UD == qp_type && | ||
376 | !mlx4_is_qp_reserved(dev, qpn))) | ||
373 | return -EINVAL; | 377 | return -EINVAL; |
374 | 378 | ||
379 | /* the reserved QPs (special, proxy, tunnel) | ||
380 | * do not operate over vlans | ||
381 | */ | ||
382 | if (mlx4_is_qp_reserved(dev, qpn)) | ||
383 | return 0; | ||
384 | |||
375 | /* force strip vlan by clear vsd */ | 385 | /* force strip vlan by clear vsd */ |
376 | qpc->param3 &= ~cpu_to_be32(MLX4_STRIP_VLAN); | 386 | qpc->param3 &= ~cpu_to_be32(MLX4_STRIP_VLAN); |
377 | if (0 != vp_oper->state.default_vlan) { | 387 | if (0 != vp_oper->state.default_vlan) { |
@@ -2114,6 +2124,8 @@ int mlx4_RST2INIT_QP_wrapper(struct mlx4_dev *dev, int slave, | |||
2114 | if (err) | 2124 | if (err) |
2115 | return err; | 2125 | return err; |
2116 | qp->local_qpn = local_qpn; | 2126 | qp->local_qpn = local_qpn; |
2127 | qp->sched_queue = 0; | ||
2128 | qp->qpc_flags = be32_to_cpu(qpc->flags); | ||
2117 | 2129 | ||
2118 | err = get_res(dev, slave, mtt_base, RES_MTT, &mtt); | 2130 | err = get_res(dev, slave, mtt_base, RES_MTT, &mtt); |
2119 | if (err) | 2131 | if (err) |
@@ -2836,6 +2848,9 @@ int mlx4_INIT2RTR_QP_wrapper(struct mlx4_dev *dev, int slave, | |||
2836 | { | 2848 | { |
2837 | int err; | 2849 | int err; |
2838 | struct mlx4_qp_context *qpc = inbox->buf + 8; | 2850 | struct mlx4_qp_context *qpc = inbox->buf + 8; |
2851 | int qpn = vhcr->in_modifier & 0x7fffff; | ||
2852 | struct res_qp *qp; | ||
2853 | u8 orig_sched_queue; | ||
2839 | 2854 | ||
2840 | err = verify_qp_parameters(dev, inbox, QP_TRANS_INIT2RTR, slave); | 2855 | err = verify_qp_parameters(dev, inbox, QP_TRANS_INIT2RTR, slave); |
2841 | if (err) | 2856 | if (err) |
@@ -2844,11 +2859,30 @@ int mlx4_INIT2RTR_QP_wrapper(struct mlx4_dev *dev, int slave, | |||
2844 | update_pkey_index(dev, slave, inbox); | 2859 | update_pkey_index(dev, slave, inbox); |
2845 | update_gid(dev, inbox, (u8)slave); | 2860 | update_gid(dev, inbox, (u8)slave); |
2846 | adjust_proxy_tun_qkey(dev, vhcr, qpc); | 2861 | adjust_proxy_tun_qkey(dev, vhcr, qpc); |
2847 | err = update_vport_qp_param(dev, inbox, slave); | 2862 | orig_sched_queue = qpc->pri_path.sched_queue; |
2863 | err = update_vport_qp_param(dev, inbox, slave, qpn); | ||
2848 | if (err) | 2864 | if (err) |
2849 | return err; | 2865 | return err; |
2850 | 2866 | ||
2851 | return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd); | 2867 | err = get_res(dev, slave, qpn, RES_QP, &qp); |
2868 | if (err) | ||
2869 | return err; | ||
2870 | if (qp->com.from_state != RES_QP_HW) { | ||
2871 | err = -EBUSY; | ||
2872 | goto out; | ||
2873 | } | ||
2874 | |||
2875 | err = mlx4_DMA_wrapper(dev, slave, vhcr, inbox, outbox, cmd); | ||
2876 | out: | ||
2877 | /* if no error, save sched queue value passed in by VF. This is | ||
2878 | * essentially the QOS value provided by the VF. This will be useful | ||
2879 | * if we allow dynamic changes from VST back to VGT | ||
2880 | */ | ||
2881 | if (!err) | ||
2882 | qp->sched_queue = orig_sched_queue; | ||
2883 | |||
2884 | put_res(dev, slave, qpn, RES_QP); | ||
2885 | return err; | ||
2852 | } | 2886 | } |
2853 | 2887 | ||
2854 | int mlx4_RTR2RTS_QP_wrapper(struct mlx4_dev *dev, int slave, | 2888 | int mlx4_RTR2RTS_QP_wrapper(struct mlx4_dev *dev, int slave, |
@@ -3932,3 +3966,106 @@ void mlx4_delete_all_resources_for_slave(struct mlx4_dev *dev, int slave) | |||
3932 | rem_slave_xrcdns(dev, slave); | 3966 | rem_slave_xrcdns(dev, slave); |
3933 | mutex_unlock(&priv->mfunc.master.res_tracker.slave_list[slave].mutex); | 3967 | mutex_unlock(&priv->mfunc.master.res_tracker.slave_list[slave].mutex); |
3934 | } | 3968 | } |
3969 | |||
3970 | void mlx4_vf_immed_vlan_work_handler(struct work_struct *_work) | ||
3971 | { | ||
3972 | struct mlx4_vf_immed_vlan_work *work = | ||
3973 | container_of(_work, struct mlx4_vf_immed_vlan_work, work); | ||
3974 | struct mlx4_cmd_mailbox *mailbox; | ||
3975 | struct mlx4_update_qp_context *upd_context; | ||
3976 | struct mlx4_dev *dev = &work->priv->dev; | ||
3977 | struct mlx4_resource_tracker *tracker = | ||
3978 | &work->priv->mfunc.master.res_tracker; | ||
3979 | struct list_head *qp_list = | ||
3980 | &tracker->slave_list[work->slave].res_list[RES_QP]; | ||
3981 | struct res_qp *qp; | ||
3982 | struct res_qp *tmp; | ||
3983 | u64 qp_mask = ((1ULL << MLX4_UPD_QP_PATH_MASK_ETH_TX_BLOCK_UNTAGGED) | | ||
3984 | (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_TX_BLOCK_1P) | | ||
3985 | (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_TX_BLOCK_TAGGED) | | ||
3986 | (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_RX_BLOCK_UNTAGGED) | | ||
3987 | (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_RX_BLOCK_1P) | | ||
3988 | (1ULL << MLX4_UPD_QP_PATH_MASK_ETH_RX_BLOCK_TAGGED) | | ||
3989 | (1ULL << MLX4_UPD_QP_PATH_MASK_VLAN_INDEX) | | ||
3990 | (1ULL << MLX4_UPD_QP_PATH_MASK_SCHED_QUEUE)); | ||
3991 | |||
3992 | int err; | ||
3993 | int port, errors = 0; | ||
3994 | u8 vlan_control; | ||
3995 | |||
3996 | if (mlx4_is_slave(dev)) { | ||
3997 | mlx4_warn(dev, "Trying to update-qp in slave %d\n", | ||
3998 | work->slave); | ||
3999 | goto out; | ||
4000 | } | ||
4001 | |||
4002 | mailbox = mlx4_alloc_cmd_mailbox(dev); | ||
4003 | if (IS_ERR(mailbox)) | ||
4004 | goto out; | ||
4005 | |||
4006 | if (!work->vlan_id) | ||
4007 | vlan_control = MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED | | ||
4008 | MLX4_VLAN_CTRL_ETH_RX_BLOCK_TAGGED; | ||
4009 | else | ||
4010 | vlan_control = MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED | | ||
4011 | MLX4_VLAN_CTRL_ETH_RX_BLOCK_PRIO_TAGGED | | ||
4012 | MLX4_VLAN_CTRL_ETH_RX_BLOCK_UNTAGGED; | ||
4013 | |||
4014 | upd_context = mailbox->buf; | ||
4015 | upd_context->primary_addr_path_mask = cpu_to_be64(qp_mask); | ||
4016 | upd_context->qp_context.pri_path.vlan_control = vlan_control; | ||
4017 | upd_context->qp_context.pri_path.vlan_index = work->vlan_ix; | ||
4018 | |||
4019 | spin_lock_irq(mlx4_tlock(dev)); | ||
4020 | list_for_each_entry_safe(qp, tmp, qp_list, com.list) { | ||
4021 | spin_unlock_irq(mlx4_tlock(dev)); | ||
4022 | if (qp->com.owner == work->slave) { | ||
4023 | if (qp->com.from_state != RES_QP_HW || | ||
4024 | !qp->sched_queue || /* no INIT2RTR trans yet */ | ||
4025 | mlx4_is_qp_reserved(dev, qp->local_qpn) || | ||
4026 | qp->qpc_flags & (1 << MLX4_RSS_QPC_FLAG_OFFSET)) { | ||
4027 | spin_lock_irq(mlx4_tlock(dev)); | ||
4028 | continue; | ||
4029 | } | ||
4030 | port = (qp->sched_queue >> 6 & 1) + 1; | ||
4031 | if (port != work->port) { | ||
4032 | spin_lock_irq(mlx4_tlock(dev)); | ||
4033 | continue; | ||
4034 | } | ||
4035 | upd_context->qp_context.pri_path.sched_queue = | ||
4036 | qp->sched_queue & 0xC7; | ||
4037 | upd_context->qp_context.pri_path.sched_queue |= | ||
4038 | ((work->qos & 0x7) << 3); | ||
4039 | |||
4040 | err = mlx4_cmd(dev, mailbox->dma, | ||
4041 | qp->local_qpn & 0xffffff, | ||
4042 | 0, MLX4_CMD_UPDATE_QP, | ||
4043 | MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE); | ||
4044 | if (err) { | ||
4045 | mlx4_info(dev, "UPDATE_QP failed for slave %d, " | ||
4046 | "port %d, qpn %d (%d)\n", | ||
4047 | work->slave, port, qp->local_qpn, | ||
4048 | err); | ||
4049 | errors++; | ||
4050 | } | ||
4051 | } | ||
4052 | spin_lock_irq(mlx4_tlock(dev)); | ||
4053 | } | ||
4054 | spin_unlock_irq(mlx4_tlock(dev)); | ||
4055 | mlx4_free_cmd_mailbox(dev, mailbox); | ||
4056 | |||
4057 | if (errors) | ||
4058 | mlx4_err(dev, "%d UPDATE_QP failures for slave %d, port %d\n", | ||
4059 | errors, work->slave, work->port); | ||
4060 | |||
4061 | /* unregister previous vlan_id if needed and we had no errors | ||
4062 | * while updating the QPs | ||
4063 | */ | ||
4064 | if (work->flags & MLX4_VF_IMMED_VLAN_FLAG_VLAN && !errors && | ||
4065 | NO_INDX != work->orig_vlan_ix) | ||
4066 | __mlx4_unregister_vlan(&work->priv->dev, work->port, | ||
4067 | work->orig_vlan_ix); | ||
4068 | out: | ||
4069 | kfree(work); | ||
4070 | return; | ||
4071 | } | ||