aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/mellanox/mlx4
diff options
context:
space:
mode:
authorJack Morgenstein <jackm@dev.mellanox.co.il>2012-08-03 04:40:48 -0400
committerRoland Dreier <roland@purestorage.com>2012-09-30 23:33:37 -0400
commit993c401e207946fa56f69c51e39f015e7108497b (patch)
tree17ef6798c9723d6cbaa3c48b6d24cda765d7057d /drivers/net/ethernet/mellanox/mlx4
parent3cf69cc8dbebf15b99deb342ea422105ae9c2774 (diff)
mlx4_core: Add IB port-state machine and port mgmt event propagation
For an IB port, a slave should not show port active until that slave has a valid alias-guid (provided by the subnet manager). Therefore the port-up event should be passed to a slave only after both the port is up, and the slave's alias-guid has been set. Also, provide the infrastructure for propagating port-management events (client-reregister, etc) to slaves. Signed-off-by: Jack Morgenstein <jackm@dev.mellanox.co.il> Signed-off-by: Roland Dreier <roland@purestorage.com>
Diffstat (limited to 'drivers/net/ethernet/mellanox/mlx4')
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/eq.c237
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/mlx4.h1
2 files changed, 222 insertions, 16 deletions
diff --git a/drivers/net/ethernet/mellanox/mlx4/eq.c b/drivers/net/ethernet/mellanox/mlx4/eq.c
index 99a04648fab0..c425826b1fc0 100644
--- a/drivers/net/ethernet/mellanox/mlx4/eq.c
+++ b/drivers/net/ethernet/mellanox/mlx4/eq.c
@@ -200,6 +200,196 @@ static void mlx4_slave_event(struct mlx4_dev *dev, int slave,
200 slave_event(dev, slave, eqe); 200 slave_event(dev, slave, eqe);
201} 201}
202 202
203int mlx4_gen_pkey_eqe(struct mlx4_dev *dev, int slave, u8 port)
204{
205 struct mlx4_eqe eqe;
206
207 struct mlx4_priv *priv = mlx4_priv(dev);
208 struct mlx4_slave_state *s_slave = &priv->mfunc.master.slave_state[slave];
209
210 if (!s_slave->active)
211 return 0;
212
213 memset(&eqe, 0, sizeof eqe);
214
215 eqe.type = MLX4_EVENT_TYPE_PORT_MNG_CHG_EVENT;
216 eqe.subtype = MLX4_DEV_PMC_SUBTYPE_PKEY_TABLE;
217 eqe.event.port_mgmt_change.port = port;
218
219 return mlx4_GEN_EQE(dev, slave, &eqe);
220}
221EXPORT_SYMBOL(mlx4_gen_pkey_eqe);
222
223int mlx4_gen_guid_change_eqe(struct mlx4_dev *dev, int slave, u8 port)
224{
225 struct mlx4_eqe eqe;
226
227 /*don't send if we don't have the that slave */
228 if (dev->num_vfs < slave)
229 return 0;
230 memset(&eqe, 0, sizeof eqe);
231
232 eqe.type = MLX4_EVENT_TYPE_PORT_MNG_CHG_EVENT;
233 eqe.subtype = MLX4_DEV_PMC_SUBTYPE_GUID_INFO;
234 eqe.event.port_mgmt_change.port = port;
235
236 return mlx4_GEN_EQE(dev, slave, &eqe);
237}
238EXPORT_SYMBOL(mlx4_gen_guid_change_eqe);
239
240int mlx4_gen_port_state_change_eqe(struct mlx4_dev *dev, int slave, u8 port,
241 u8 port_subtype_change)
242{
243 struct mlx4_eqe eqe;
244
245 /*don't send if we don't have the that slave */
246 if (dev->num_vfs < slave)
247 return 0;
248 memset(&eqe, 0, sizeof eqe);
249
250 eqe.type = MLX4_EVENT_TYPE_PORT_CHANGE;
251 eqe.subtype = port_subtype_change;
252 eqe.event.port_change.port = cpu_to_be32(port << 28);
253
254 mlx4_dbg(dev, "%s: sending: %d to slave: %d on port: %d\n", __func__,
255 port_subtype_change, slave, port);
256 return mlx4_GEN_EQE(dev, slave, &eqe);
257}
258EXPORT_SYMBOL(mlx4_gen_port_state_change_eqe);
259
260enum slave_port_state mlx4_get_slave_port_state(struct mlx4_dev *dev, int slave, u8 port)
261{
262 struct mlx4_priv *priv = mlx4_priv(dev);
263 struct mlx4_slave_state *s_state = priv->mfunc.master.slave_state;
264 if (slave >= dev->num_slaves || port > MLX4_MAX_PORTS) {
265 pr_err("%s: Error: asking for slave:%d, port:%d\n",
266 __func__, slave, port);
267 return SLAVE_PORT_DOWN;
268 }
269 return s_state[slave].port_state[port];
270}
271EXPORT_SYMBOL(mlx4_get_slave_port_state);
272
273static int mlx4_set_slave_port_state(struct mlx4_dev *dev, int slave, u8 port,
274 enum slave_port_state state)
275{
276 struct mlx4_priv *priv = mlx4_priv(dev);
277 struct mlx4_slave_state *s_state = priv->mfunc.master.slave_state;
278
279 if (slave >= dev->num_slaves || port > MLX4_MAX_PORTS || port == 0) {
280 pr_err("%s: Error: asking for slave:%d, port:%d\n",
281 __func__, slave, port);
282 return -1;
283 }
284 s_state[slave].port_state[port] = state;
285
286 return 0;
287}
288
289static void set_all_slave_state(struct mlx4_dev *dev, u8 port, int event)
290{
291 int i;
292 enum slave_port_gen_event gen_event;
293
294 for (i = 0; i < dev->num_slaves; i++)
295 set_and_calc_slave_port_state(dev, i, port, event, &gen_event);
296}
297/**************************************************************************
298 The function get as input the new event to that port,
299 and according to the prev state change the slave's port state.
300 The events are:
301 MLX4_PORT_STATE_DEV_EVENT_PORT_DOWN,
302 MLX4_PORT_STATE_DEV_EVENT_PORT_UP
303 MLX4_PORT_STATE_IB_EVENT_GID_VALID
304 MLX4_PORT_STATE_IB_EVENT_GID_INVALID
305***************************************************************************/
306int set_and_calc_slave_port_state(struct mlx4_dev *dev, int slave,
307 u8 port, int event,
308 enum slave_port_gen_event *gen_event)
309{
310 struct mlx4_priv *priv = mlx4_priv(dev);
311 struct mlx4_slave_state *ctx = NULL;
312 unsigned long flags;
313 int ret = -1;
314 enum slave_port_state cur_state =
315 mlx4_get_slave_port_state(dev, slave, port);
316
317 *gen_event = SLAVE_PORT_GEN_EVENT_NONE;
318
319 if (slave >= dev->num_slaves || port > MLX4_MAX_PORTS || port == 0) {
320 pr_err("%s: Error: asking for slave:%d, port:%d\n",
321 __func__, slave, port);
322 return ret;
323 }
324
325 ctx = &priv->mfunc.master.slave_state[slave];
326 spin_lock_irqsave(&ctx->lock, flags);
327
328 mlx4_dbg(dev, "%s: slave: %d, current state: %d new event :%d\n",
329 __func__, slave, cur_state, event);
330
331 switch (cur_state) {
332 case SLAVE_PORT_DOWN:
333 if (MLX4_PORT_STATE_DEV_EVENT_PORT_UP == event)
334 mlx4_set_slave_port_state(dev, slave, port,
335 SLAVE_PENDING_UP);
336 break;
337 case SLAVE_PENDING_UP:
338 if (MLX4_PORT_STATE_DEV_EVENT_PORT_DOWN == event)
339 mlx4_set_slave_port_state(dev, slave, port,
340 SLAVE_PORT_DOWN);
341 else if (MLX4_PORT_STATE_IB_PORT_STATE_EVENT_GID_VALID == event) {
342 mlx4_set_slave_port_state(dev, slave, port,
343 SLAVE_PORT_UP);
344 *gen_event = SLAVE_PORT_GEN_EVENT_UP;
345 }
346 break;
347 case SLAVE_PORT_UP:
348 if (MLX4_PORT_STATE_DEV_EVENT_PORT_DOWN == event) {
349 mlx4_set_slave_port_state(dev, slave, port,
350 SLAVE_PORT_DOWN);
351 *gen_event = SLAVE_PORT_GEN_EVENT_DOWN;
352 } else if (MLX4_PORT_STATE_IB_EVENT_GID_INVALID ==
353 event) {
354 mlx4_set_slave_port_state(dev, slave, port,
355 SLAVE_PENDING_UP);
356 *gen_event = SLAVE_PORT_GEN_EVENT_DOWN;
357 }
358 break;
359 default:
360 pr_err("%s: BUG!!! UNKNOWN state: "
361 "slave:%d, port:%d\n", __func__, slave, port);
362 goto out;
363 }
364 ret = mlx4_get_slave_port_state(dev, slave, port);
365 mlx4_dbg(dev, "%s: slave: %d, current state: %d new event"
366 " :%d gen_event: %d\n",
367 __func__, slave, cur_state, event, *gen_event);
368
369out:
370 spin_unlock_irqrestore(&ctx->lock, flags);
371 return ret;
372}
373
374EXPORT_SYMBOL(set_and_calc_slave_port_state);
375
376int mlx4_gen_slaves_port_mgt_ev(struct mlx4_dev *dev, u8 port, int attr)
377{
378 struct mlx4_eqe eqe;
379
380 memset(&eqe, 0, sizeof eqe);
381
382 eqe.type = MLX4_EVENT_TYPE_PORT_MNG_CHG_EVENT;
383 eqe.subtype = MLX4_DEV_PMC_SUBTYPE_PORT_INFO;
384 eqe.event.port_mgmt_change.port = port;
385 eqe.event.port_mgmt_change.params.port_info.changed_attr =
386 cpu_to_be32((u32) attr);
387
388 slave_event(dev, ALL_SLAVES, &eqe);
389 return 0;
390}
391EXPORT_SYMBOL(mlx4_gen_slaves_port_mgt_ev);
392
203void mlx4_master_handle_slave_flr(struct work_struct *work) 393void mlx4_master_handle_slave_flr(struct work_struct *work)
204{ 394{
205 struct mlx4_mfunc_master_ctx *master = 395 struct mlx4_mfunc_master_ctx *master =
@@ -251,6 +441,7 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq)
251 u32 flr_slave; 441 u32 flr_slave;
252 u8 update_slave_state; 442 u8 update_slave_state;
253 int i; 443 int i;
444 enum slave_port_gen_event gen_event;
254 445
255 while ((eqe = next_eqe_sw(eq))) { 446 while ((eqe = next_eqe_sw(eq))) {
256 /* 447 /*
@@ -347,35 +538,49 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq)
347 case MLX4_EVENT_TYPE_PORT_CHANGE: 538 case MLX4_EVENT_TYPE_PORT_CHANGE:
348 port = be32_to_cpu(eqe->event.port_change.port) >> 28; 539 port = be32_to_cpu(eqe->event.port_change.port) >> 28;
349 if (eqe->subtype == MLX4_PORT_CHANGE_SUBTYPE_DOWN) { 540 if (eqe->subtype == MLX4_PORT_CHANGE_SUBTYPE_DOWN) {
350 mlx4_dispatch_event(dev, 541 mlx4_dispatch_event(dev, MLX4_DEV_EVENT_PORT_DOWN,
351 MLX4_DEV_EVENT_PORT_DOWN,
352 port); 542 port);
353 mlx4_priv(dev)->sense.do_sense_port[port] = 1; 543 mlx4_priv(dev)->sense.do_sense_port[port] = 1;
354 if (mlx4_is_master(dev)) 544 if (!mlx4_is_master(dev))
355 /*change the state of all slave's port 545 break;
356 * to down:*/ 546 for (i = 0; i < dev->num_slaves; i++) {
357 for (i = 0; i < dev->num_slaves; i++) { 547 if (dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH) {
358 mlx4_dbg(dev, "%s: Sending " 548 if (i == mlx4_master_func_num(dev))
359 "MLX4_PORT_CHANGE_SUBTYPE_DOWN" 549 continue;
550 mlx4_dbg(dev, "%s: Sending MLX4_PORT_CHANGE_SUBTYPE_DOWN"
360 " to slave: %d, port:%d\n", 551 " to slave: %d, port:%d\n",
361 __func__, i, port); 552 __func__, i, port);
362 if (i == dev->caps.function)
363 continue;
364 mlx4_slave_event(dev, i, eqe); 553 mlx4_slave_event(dev, i, eqe);
554 } else { /* IB port */
555 set_and_calc_slave_port_state(dev, i, port,
556 MLX4_PORT_STATE_DEV_EVENT_PORT_DOWN,
557 &gen_event);
558 /*we can be in pending state, then do not send port_down event*/
559 if (SLAVE_PORT_GEN_EVENT_DOWN == gen_event) {
560 if (i == mlx4_master_func_num(dev))
561 continue;
562 mlx4_slave_event(dev, i, eqe);
563 }
365 } 564 }
565 }
366 } else { 566 } else {
367 mlx4_dispatch_event(dev, 567 mlx4_dispatch_event(dev, MLX4_DEV_EVENT_PORT_UP, port);
368 MLX4_DEV_EVENT_PORT_UP, 568
369 port);
370 mlx4_priv(dev)->sense.do_sense_port[port] = 0; 569 mlx4_priv(dev)->sense.do_sense_port[port] = 0;
371 570
372 if (mlx4_is_master(dev)) { 571 if (!mlx4_is_master(dev))
572 break;
573 if (dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH)
373 for (i = 0; i < dev->num_slaves; i++) { 574 for (i = 0; i < dev->num_slaves; i++) {
374 if (i == dev->caps.function) 575 if (i == mlx4_master_func_num(dev))
375 continue; 576 continue;
376 mlx4_slave_event(dev, i, eqe); 577 mlx4_slave_event(dev, i, eqe);
377 } 578 }
378 } 579 else /* IB port */
580 /* port-up event will be sent to a slave when the
581 * slave's alias-guid is set. This is done in alias_GUID.c
582 */
583 set_all_slave_state(dev, port, MLX4_DEV_EVENT_PORT_UP);
379 } 584 }
380 break; 585 break;
381 586
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4.h b/drivers/net/ethernet/mellanox/mlx4/mlx4.h
index 7d27c3158d0c..23f74759f403 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4.h
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4.h
@@ -452,6 +452,7 @@ struct mlx4_slave_state {
452 /*initialized via the kzalloc*/ 452 /*initialized via the kzalloc*/
453 u8 is_slave_going_down; 453 u8 is_slave_going_down;
454 u32 cookie; 454 u32 cookie;
455 enum slave_port_state port_state[MLX4_MAX_PORTS + 1];
455}; 456};
456 457
457struct slave_list { 458struct slave_list {