diff options
Diffstat (limited to 'drivers/infiniband')
-rw-r--r-- | drivers/infiniband/hw/ehca/ehca_classes.h | 6 | ||||
-rw-r--r-- | drivers/infiniband/hw/ehca/ehca_hca.c | 34 | ||||
-rw-r--r-- | drivers/infiniband/hw/ehca/ehca_irq.c | 89 | ||||
-rw-r--r-- | drivers/infiniband/hw/ehca/ehca_iverbs.h | 3 |
4 files changed, 101 insertions, 31 deletions
diff --git a/drivers/infiniband/hw/ehca/ehca_classes.h b/drivers/infiniband/hw/ehca/ehca_classes.h index f1e0db2ff16c..daf823ea1ace 100644 --- a/drivers/infiniband/hw/ehca/ehca_classes.h +++ b/drivers/infiniband/hw/ehca/ehca_classes.h | |||
@@ -87,11 +87,17 @@ struct ehca_eq { | |||
87 | struct ehca_eqe_cache_entry eqe_cache[EHCA_EQE_CACHE_SIZE]; | 87 | struct ehca_eqe_cache_entry eqe_cache[EHCA_EQE_CACHE_SIZE]; |
88 | }; | 88 | }; |
89 | 89 | ||
90 | struct ehca_sma_attr { | ||
91 | u16 lid, lmc, sm_sl, sm_lid; | ||
92 | u16 pkey_tbl_len, pkeys[16]; | ||
93 | }; | ||
94 | |||
90 | struct ehca_sport { | 95 | struct ehca_sport { |
91 | struct ib_cq *ibcq_aqp1; | 96 | struct ib_cq *ibcq_aqp1; |
92 | struct ib_qp *ibqp_aqp1; | 97 | struct ib_qp *ibqp_aqp1; |
93 | enum ib_rate rate; | 98 | enum ib_rate rate; |
94 | enum ib_port_state port_state; | 99 | enum ib_port_state port_state; |
100 | struct ehca_sma_attr saved_attr; | ||
95 | }; | 101 | }; |
96 | 102 | ||
97 | struct ehca_shca { | 103 | struct ehca_shca { |
diff --git a/drivers/infiniband/hw/ehca/ehca_hca.c b/drivers/infiniband/hw/ehca/ehca_hca.c index b310de5c94ae..bbd3c6a5822f 100644 --- a/drivers/infiniband/hw/ehca/ehca_hca.c +++ b/drivers/infiniband/hw/ehca/ehca_hca.c | |||
@@ -193,6 +193,40 @@ query_port1: | |||
193 | return ret; | 193 | return ret; |
194 | } | 194 | } |
195 | 195 | ||
196 | int ehca_query_sma_attr(struct ehca_shca *shca, | ||
197 | u8 port, struct ehca_sma_attr *attr) | ||
198 | { | ||
199 | int ret = 0; | ||
200 | struct hipz_query_port *rblock; | ||
201 | |||
202 | rblock = ehca_alloc_fw_ctrlblock(GFP_ATOMIC); | ||
203 | if (!rblock) { | ||
204 | ehca_err(&shca->ib_device, "Can't allocate rblock memory."); | ||
205 | return -ENOMEM; | ||
206 | } | ||
207 | |||
208 | if (hipz_h_query_port(shca->ipz_hca_handle, port, rblock) != H_SUCCESS) { | ||
209 | ehca_err(&shca->ib_device, "Can't query port properties"); | ||
210 | ret = -EINVAL; | ||
211 | goto query_sma_attr1; | ||
212 | } | ||
213 | |||
214 | memset(attr, 0, sizeof(struct ehca_sma_attr)); | ||
215 | |||
216 | attr->lid = rblock->lid; | ||
217 | attr->lmc = rblock->lmc; | ||
218 | attr->sm_sl = rblock->sm_sl; | ||
219 | attr->sm_lid = rblock->sm_lid; | ||
220 | |||
221 | attr->pkey_tbl_len = rblock->pkey_tbl_len; | ||
222 | memcpy(attr->pkeys, rblock->pkey_entries, sizeof(attr->pkeys)); | ||
223 | |||
224 | query_sma_attr1: | ||
225 | ehca_free_fw_ctrlblock(rblock); | ||
226 | |||
227 | return ret; | ||
228 | } | ||
229 | |||
196 | int ehca_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 *pkey) | 230 | int ehca_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 *pkey) |
197 | { | 231 | { |
198 | int ret = 0; | 232 | int ret = 0; |
diff --git a/drivers/infiniband/hw/ehca/ehca_irq.c b/drivers/infiniband/hw/ehca/ehca_irq.c index 02b73c84c49b..96eba3830754 100644 --- a/drivers/infiniband/hw/ehca/ehca_irq.c +++ b/drivers/infiniband/hw/ehca/ehca_irq.c | |||
@@ -61,6 +61,7 @@ | |||
61 | #define NEQE_EVENT_CODE EHCA_BMASK_IBM(2,7) | 61 | #define NEQE_EVENT_CODE EHCA_BMASK_IBM(2,7) |
62 | #define NEQE_PORT_NUMBER EHCA_BMASK_IBM(8,15) | 62 | #define NEQE_PORT_NUMBER EHCA_BMASK_IBM(8,15) |
63 | #define NEQE_PORT_AVAILABILITY EHCA_BMASK_IBM(16,16) | 63 | #define NEQE_PORT_AVAILABILITY EHCA_BMASK_IBM(16,16) |
64 | #define NEQE_DISRUPTIVE EHCA_BMASK_IBM(16,16) | ||
64 | 65 | ||
65 | #define ERROR_DATA_LENGTH EHCA_BMASK_IBM(52,63) | 66 | #define ERROR_DATA_LENGTH EHCA_BMASK_IBM(52,63) |
66 | #define ERROR_DATA_TYPE EHCA_BMASK_IBM(0,7) | 67 | #define ERROR_DATA_TYPE EHCA_BMASK_IBM(0,7) |
@@ -286,30 +287,61 @@ static void parse_identifier(struct ehca_shca *shca, u64 eqe) | |||
286 | return; | 287 | return; |
287 | } | 288 | } |
288 | 289 | ||
289 | static void parse_ec(struct ehca_shca *shca, u64 eqe) | 290 | static void dispatch_port_event(struct ehca_shca *shca, int port_num, |
291 | enum ib_event_type type, const char *msg) | ||
290 | { | 292 | { |
291 | struct ib_event event; | 293 | struct ib_event event; |
294 | |||
295 | ehca_info(&shca->ib_device, "port %d %s.", port_num, msg); | ||
296 | event.device = &shca->ib_device; | ||
297 | event.event = type; | ||
298 | event.element.port_num = port_num; | ||
299 | ib_dispatch_event(&event); | ||
300 | } | ||
301 | |||
302 | static void notify_port_conf_change(struct ehca_shca *shca, int port_num) | ||
303 | { | ||
304 | struct ehca_sma_attr new_attr; | ||
305 | struct ehca_sma_attr *old_attr = &shca->sport[port_num - 1].saved_attr; | ||
306 | |||
307 | ehca_query_sma_attr(shca, port_num, &new_attr); | ||
308 | |||
309 | if (new_attr.sm_sl != old_attr->sm_sl || | ||
310 | new_attr.sm_lid != old_attr->sm_lid) | ||
311 | dispatch_port_event(shca, port_num, IB_EVENT_SM_CHANGE, | ||
312 | "SM changed"); | ||
313 | |||
314 | if (new_attr.lid != old_attr->lid || | ||
315 | new_attr.lmc != old_attr->lmc) | ||
316 | dispatch_port_event(shca, port_num, IB_EVENT_LID_CHANGE, | ||
317 | "LID changed"); | ||
318 | |||
319 | if (new_attr.pkey_tbl_len != old_attr->pkey_tbl_len || | ||
320 | memcmp(new_attr.pkeys, old_attr->pkeys, | ||
321 | sizeof(u16) * new_attr.pkey_tbl_len)) | ||
322 | dispatch_port_event(shca, port_num, IB_EVENT_PKEY_CHANGE, | ||
323 | "P_Key changed"); | ||
324 | |||
325 | *old_attr = new_attr; | ||
326 | } | ||
327 | |||
328 | static void parse_ec(struct ehca_shca *shca, u64 eqe) | ||
329 | { | ||
292 | u8 ec = EHCA_BMASK_GET(NEQE_EVENT_CODE, eqe); | 330 | u8 ec = EHCA_BMASK_GET(NEQE_EVENT_CODE, eqe); |
293 | u8 port = EHCA_BMASK_GET(NEQE_PORT_NUMBER, eqe); | 331 | u8 port = EHCA_BMASK_GET(NEQE_PORT_NUMBER, eqe); |
294 | 332 | ||
295 | switch (ec) { | 333 | switch (ec) { |
296 | case 0x30: /* port availability change */ | 334 | case 0x30: /* port availability change */ |
297 | if (EHCA_BMASK_GET(NEQE_PORT_AVAILABILITY, eqe)) { | 335 | if (EHCA_BMASK_GET(NEQE_PORT_AVAILABILITY, eqe)) { |
298 | ehca_info(&shca->ib_device, | ||
299 | "port %x is active.", port); | ||
300 | event.device = &shca->ib_device; | ||
301 | event.event = IB_EVENT_PORT_ACTIVE; | ||
302 | event.element.port_num = port; | ||
303 | shca->sport[port - 1].port_state = IB_PORT_ACTIVE; | 336 | shca->sport[port - 1].port_state = IB_PORT_ACTIVE; |
304 | ib_dispatch_event(&event); | 337 | dispatch_port_event(shca, port, IB_EVENT_PORT_ACTIVE, |
338 | "is active"); | ||
339 | ehca_query_sma_attr(shca, port, | ||
340 | &shca->sport[port - 1].saved_attr); | ||
305 | } else { | 341 | } else { |
306 | ehca_info(&shca->ib_device, | ||
307 | "port %x is inactive.", port); | ||
308 | event.device = &shca->ib_device; | ||
309 | event.event = IB_EVENT_PORT_ERR; | ||
310 | event.element.port_num = port; | ||
311 | shca->sport[port - 1].port_state = IB_PORT_DOWN; | 342 | shca->sport[port - 1].port_state = IB_PORT_DOWN; |
312 | ib_dispatch_event(&event); | 343 | dispatch_port_event(shca, port, IB_EVENT_PORT_ERR, |
344 | "is inactive"); | ||
313 | } | 345 | } |
314 | break; | 346 | break; |
315 | case 0x31: | 347 | case 0x31: |
@@ -317,24 +349,19 @@ static void parse_ec(struct ehca_shca *shca, u64 eqe) | |||
317 | * disruptive change is caused by | 349 | * disruptive change is caused by |
318 | * LID, PKEY or SM change | 350 | * LID, PKEY or SM change |
319 | */ | 351 | */ |
320 | ehca_warn(&shca->ib_device, | 352 | if (EHCA_BMASK_GET(NEQE_DISRUPTIVE, eqe)) { |
321 | "disruptive port %x configuration change", port); | 353 | ehca_warn(&shca->ib_device, "disruptive port " |
322 | 354 | "%d configuration change", port); | |
323 | ehca_info(&shca->ib_device, | 355 | |
324 | "port %x is inactive.", port); | 356 | shca->sport[port - 1].port_state = IB_PORT_DOWN; |
325 | event.device = &shca->ib_device; | 357 | dispatch_port_event(shca, port, IB_EVENT_PORT_ERR, |
326 | event.event = IB_EVENT_PORT_ERR; | 358 | "is inactive"); |
327 | event.element.port_num = port; | 359 | |
328 | shca->sport[port - 1].port_state = IB_PORT_DOWN; | 360 | shca->sport[port - 1].port_state = IB_PORT_ACTIVE; |
329 | ib_dispatch_event(&event); | 361 | dispatch_port_event(shca, port, IB_EVENT_PORT_ACTIVE, |
330 | 362 | "is active"); | |
331 | ehca_info(&shca->ib_device, | 363 | } else |
332 | "port %x is active.", port); | 364 | notify_port_conf_change(shca, port); |
333 | event.device = &shca->ib_device; | ||
334 | event.event = IB_EVENT_PORT_ACTIVE; | ||
335 | event.element.port_num = port; | ||
336 | shca->sport[port - 1].port_state = IB_PORT_ACTIVE; | ||
337 | ib_dispatch_event(&event); | ||
338 | break; | 365 | break; |
339 | case 0x32: /* adapter malfunction */ | 366 | case 0x32: /* adapter malfunction */ |
340 | ehca_err(&shca->ib_device, "Adapter malfunction."); | 367 | ehca_err(&shca->ib_device, "Adapter malfunction."); |
diff --git a/drivers/infiniband/hw/ehca/ehca_iverbs.h b/drivers/infiniband/hw/ehca/ehca_iverbs.h index fd84a804814c..77aeca6a2c2f 100644 --- a/drivers/infiniband/hw/ehca/ehca_iverbs.h +++ b/drivers/infiniband/hw/ehca/ehca_iverbs.h | |||
@@ -49,6 +49,9 @@ int ehca_query_device(struct ib_device *ibdev, struct ib_device_attr *props); | |||
49 | int ehca_query_port(struct ib_device *ibdev, u8 port, | 49 | int ehca_query_port(struct ib_device *ibdev, u8 port, |
50 | struct ib_port_attr *props); | 50 | struct ib_port_attr *props); |
51 | 51 | ||
52 | int ehca_query_sma_attr(struct ehca_shca *shca, u8 port, | ||
53 | struct ehca_sma_attr *attr); | ||
54 | |||
52 | int ehca_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 * pkey); | 55 | int ehca_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 * pkey); |
53 | 56 | ||
54 | int ehca_query_gid(struct ib_device *ibdev, u8 port, int index, | 57 | int ehca_query_gid(struct ib_device *ibdev, u8 port, int index, |