aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/infiniband/hw/mlx4/mad.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/infiniband/hw/mlx4/mad.c')
-rw-r--r--drivers/infiniband/hw/mlx4/mad.c118
1 files changed, 90 insertions, 28 deletions
diff --git a/drivers/infiniband/hw/mlx4/mad.c b/drivers/infiniband/hw/mlx4/mad.c
index 84786a9fb64f..58c45fb5bd31 100644
--- a/drivers/infiniband/hw/mlx4/mad.c
+++ b/drivers/infiniband/hw/mlx4/mad.c
@@ -147,47 +147,49 @@ static void update_sm_ah(struct mlx4_ib_dev *dev, u8 port_num, u16 lid, u8 sl)
147} 147}
148 148
149/* 149/*
150 * Snoop SM MADs for port info and P_Key table sets, so we can 150 * Snoop SM MADs for port info, GUID info, and P_Key table sets, so we can
151 * synthesize LID change and P_Key change events. 151 * synthesize LID change, Client-Rereg, GID change, and P_Key change events.
152 */ 152 */
153static void smp_snoop(struct ib_device *ibdev, u8 port_num, struct ib_mad *mad, 153static void smp_snoop(struct ib_device *ibdev, u8 port_num, struct ib_mad *mad,
154 u16 prev_lid) 154 u16 prev_lid)
155{ 155{
156 struct ib_event event; 156 struct ib_port_info *pinfo;
157 u16 lid;
157 158
159 struct mlx4_ib_dev *dev = to_mdev(ibdev);
158 if ((mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED || 160 if ((mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED ||
159 mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) && 161 mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) &&
160 mad->mad_hdr.method == IB_MGMT_METHOD_SET) { 162 mad->mad_hdr.method == IB_MGMT_METHOD_SET)
161 if (mad->mad_hdr.attr_id == IB_SMP_ATTR_PORT_INFO) { 163 switch (mad->mad_hdr.attr_id) {
162 struct ib_port_info *pinfo = 164 case IB_SMP_ATTR_PORT_INFO:
163 (struct ib_port_info *) ((struct ib_smp *) mad)->data; 165 pinfo = (struct ib_port_info *) ((struct ib_smp *) mad)->data;
164 u16 lid = be16_to_cpu(pinfo->lid); 166 lid = be16_to_cpu(pinfo->lid);
165 167
166 update_sm_ah(to_mdev(ibdev), port_num, 168 update_sm_ah(dev, port_num,
167 be16_to_cpu(pinfo->sm_lid), 169 be16_to_cpu(pinfo->sm_lid),
168 pinfo->neighbormtu_mastersmsl & 0xf); 170 pinfo->neighbormtu_mastersmsl & 0xf);
169 171
170 event.device = ibdev; 172 if (pinfo->clientrereg_resv_subnetto & 0x80)
171 event.element.port_num = port_num; 173 mlx4_ib_dispatch_event(dev, port_num,
174 IB_EVENT_CLIENT_REREGISTER);
172 175
173 if (pinfo->clientrereg_resv_subnetto & 0x80) { 176 if (prev_lid != lid)
174 event.event = IB_EVENT_CLIENT_REREGISTER; 177 mlx4_ib_dispatch_event(dev, port_num,
175 ib_dispatch_event(&event); 178 IB_EVENT_LID_CHANGE);
176 } 179 break;
177 180
178 if (prev_lid != lid) { 181 case IB_SMP_ATTR_PKEY_TABLE:
179 event.event = IB_EVENT_LID_CHANGE; 182 mlx4_ib_dispatch_event(dev, port_num,
180 ib_dispatch_event(&event); 183 IB_EVENT_PKEY_CHANGE);
181 } 184 break;
182 }
183 185
184 if (mad->mad_hdr.attr_id == IB_SMP_ATTR_PKEY_TABLE) { 186 case IB_SMP_ATTR_GUID_INFO:
185 event.device = ibdev; 187 mlx4_ib_dispatch_event(dev, port_num,
186 event.event = IB_EVENT_PKEY_CHANGE; 188 IB_EVENT_GID_CHANGE);
187 event.element.port_num = port_num; 189 break;
188 ib_dispatch_event(&event); 190 default:
191 break;
189 } 192 }
190 }
191} 193}
192 194
193static void node_desc_override(struct ib_device *dev, 195static void node_desc_override(struct ib_device *dev,
@@ -305,7 +307,8 @@ static int ib_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
305 return IB_MAD_RESULT_FAILURE; 307 return IB_MAD_RESULT_FAILURE;
306 308
307 if (!out_mad->mad_hdr.status) { 309 if (!out_mad->mad_hdr.status) {
308 smp_snoop(ibdev, port_num, in_mad, prev_lid); 310 if (!(to_mdev(ibdev)->dev->caps.flags & MLX4_DEV_CAP_FLAG_PORT_MNG_CHG_EV))
311 smp_snoop(ibdev, port_num, in_mad, prev_lid);
309 node_desc_override(ibdev, out_mad); 312 node_desc_override(ibdev, out_mad);
310 } 313 }
311 314
@@ -446,3 +449,62 @@ void mlx4_ib_mad_cleanup(struct mlx4_ib_dev *dev)
446 ib_destroy_ah(dev->sm_ah[p]); 449 ib_destroy_ah(dev->sm_ah[p]);
447 } 450 }
448} 451}
452
453void handle_port_mgmt_change_event(struct work_struct *work)
454{
455 struct ib_event_work *ew = container_of(work, struct ib_event_work, work);
456 struct mlx4_ib_dev *dev = ew->ib_dev;
457 struct mlx4_eqe *eqe = &(ew->ib_eqe);
458 u8 port = eqe->event.port_mgmt_change.port;
459 u32 changed_attr;
460
461 switch (eqe->subtype) {
462 case MLX4_DEV_PMC_SUBTYPE_PORT_INFO:
463 changed_attr = be32_to_cpu(eqe->event.port_mgmt_change.params.port_info.changed_attr);
464
465 /* Update the SM ah - This should be done before handling
466 the other changed attributes so that MADs can be sent to the SM */
467 if (changed_attr & MSTR_SM_CHANGE_MASK) {
468 u16 lid = be16_to_cpu(eqe->event.port_mgmt_change.params.port_info.mstr_sm_lid);
469 u8 sl = eqe->event.port_mgmt_change.params.port_info.mstr_sm_sl & 0xf;
470 update_sm_ah(dev, port, lid, sl);
471 }
472
473 /* Check if it is a lid change event */
474 if (changed_attr & MLX4_EQ_PORT_INFO_LID_CHANGE_MASK)
475 mlx4_ib_dispatch_event(dev, port, IB_EVENT_LID_CHANGE);
476
477 /* Generate GUID changed event */
478 if (changed_attr & MLX4_EQ_PORT_INFO_GID_PFX_CHANGE_MASK)
479 mlx4_ib_dispatch_event(dev, port, IB_EVENT_GID_CHANGE);
480
481 if (changed_attr & MLX4_EQ_PORT_INFO_CLIENT_REREG_MASK)
482 mlx4_ib_dispatch_event(dev, port,
483 IB_EVENT_CLIENT_REREGISTER);
484 break;
485
486 case MLX4_DEV_PMC_SUBTYPE_PKEY_TABLE:
487 mlx4_ib_dispatch_event(dev, port, IB_EVENT_PKEY_CHANGE);
488 break;
489 case MLX4_DEV_PMC_SUBTYPE_GUID_INFO:
490 mlx4_ib_dispatch_event(dev, port, IB_EVENT_GID_CHANGE);
491 break;
492 default:
493 pr_warn("Unsupported subtype 0x%x for "
494 "Port Management Change event\n", eqe->subtype);
495 }
496
497 kfree(ew);
498}
499
500void mlx4_ib_dispatch_event(struct mlx4_ib_dev *dev, u8 port_num,
501 enum ib_event_type type)
502{
503 struct ib_event event;
504
505 event.device = &dev->ib_dev;
506 event.element.port_num = port_num;
507 event.event = type;
508
509 ib_dispatch_event(&event);
510}