diff options
Diffstat (limited to 'drivers/infiniband/hw/mlx4/mad.c')
-rw-r--r-- | drivers/infiniband/hw/mlx4/mad.c | 118 |
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 | */ |
153 | static void smp_snoop(struct ib_device *ibdev, u8 port_num, struct ib_mad *mad, | 153 | static 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 | ||
193 | static void node_desc_override(struct ib_device *dev, | 195 | static 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 | |||
453 | void 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 | |||
500 | void 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 | } | ||