diff options
author | Ralph Campbell <ralph.campbell@qlogic.com> | 2007-09-19 19:47:31 -0400 |
---|---|---|
committer | Roland Dreier <rolandd@cisco.com> | 2007-10-10 00:01:38 -0400 |
commit | 49739b3e24a10d819d3167a1c5b319d0b1186245 (patch) | |
tree | 487d4df80efa73d31ab414564021503d289b6b3f /drivers/infiniband | |
parent | 6a733cdc71b7aa8107caa57f2a16629aa731242a (diff) |
IB/ipath: Fix IB_EVENT_PORT_ERR event
The link state event calls were being generated when the SM told the SMA
to change link states. This works for IB_EVENT_PORT_ACTIVE but not if
the link goes down and stays down. The fix is to generate event calls
from the interrupt handler when the HW link state changes.
Signed-off-by: Ralph Campbell <ralph.campbell@qlogic.com>
Signed-off-by: Roland Dreier <rolandd@cisco.com>
Diffstat (limited to 'drivers/infiniband')
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_driver.c | 2 | ||||
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_intr.c | 17 | ||||
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_kernel.h | 2 | ||||
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_mad.c | 10 | ||||
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_verbs.c | 12 |
5 files changed, 31 insertions, 12 deletions
diff --git a/drivers/infiniband/hw/ipath/ipath_driver.c b/drivers/infiniband/hw/ipath/ipath_driver.c index 44784d049b71..1f152ded1e3c 100644 --- a/drivers/infiniband/hw/ipath/ipath_driver.c +++ b/drivers/infiniband/hw/ipath/ipath_driver.c | |||
@@ -2086,6 +2086,8 @@ void ipath_shutdown_device(struct ipath_devdata *dd) | |||
2086 | INFINIPATH_IBCC_LINKINITCMD_SHIFT); | 2086 | INFINIPATH_IBCC_LINKINITCMD_SHIFT); |
2087 | ipath_cancel_sends(dd, 0); | 2087 | ipath_cancel_sends(dd, 0); |
2088 | 2088 | ||
2089 | signal_ib_event(dd, IB_EVENT_PORT_ERR); | ||
2090 | |||
2089 | /* disable IBC */ | 2091 | /* disable IBC */ |
2090 | dd->ipath_control &= ~INFINIPATH_C_LINKENABLE; | 2092 | dd->ipath_control &= ~INFINIPATH_C_LINKENABLE; |
2091 | ipath_write_kreg(dd, dd->ipath_kregs->kr_control, | 2093 | ipath_write_kreg(dd, dd->ipath_kregs->kr_control, |
diff --git a/drivers/infiniband/hw/ipath/ipath_intr.c b/drivers/infiniband/hw/ipath/ipath_intr.c index 801a20d06de6..6a5dd5cd773d 100644 --- a/drivers/infiniband/hw/ipath/ipath_intr.c +++ b/drivers/infiniband/hw/ipath/ipath_intr.c | |||
@@ -275,6 +275,16 @@ static char *ib_linkstate(u32 linkstate) | |||
275 | return ret; | 275 | return ret; |
276 | } | 276 | } |
277 | 277 | ||
278 | void signal_ib_event(struct ipath_devdata *dd, enum ib_event_type ev) | ||
279 | { | ||
280 | struct ib_event event; | ||
281 | |||
282 | event.device = &dd->verbs_dev->ibdev; | ||
283 | event.element.port_num = 1; | ||
284 | event.event = ev; | ||
285 | ib_dispatch_event(&event); | ||
286 | } | ||
287 | |||
278 | static void handle_e_ibstatuschanged(struct ipath_devdata *dd, | 288 | static void handle_e_ibstatuschanged(struct ipath_devdata *dd, |
279 | ipath_err_t errs, int noprint) | 289 | ipath_err_t errs, int noprint) |
280 | { | 290 | { |
@@ -373,6 +383,8 @@ static void handle_e_ibstatuschanged(struct ipath_devdata *dd, | |||
373 | dd->ipath_ibpollcnt = 0; /* some state other than 2 or 3 */ | 383 | dd->ipath_ibpollcnt = 0; /* some state other than 2 or 3 */ |
374 | ipath_stats.sps_iblink++; | 384 | ipath_stats.sps_iblink++; |
375 | if (ltstate != INFINIPATH_IBCS_LT_STATE_LINKUP) { | 385 | if (ltstate != INFINIPATH_IBCS_LT_STATE_LINKUP) { |
386 | if (dd->ipath_flags & IPATH_LINKACTIVE) | ||
387 | signal_ib_event(dd, IB_EVENT_PORT_ERR); | ||
376 | dd->ipath_flags |= IPATH_LINKDOWN; | 388 | dd->ipath_flags |= IPATH_LINKDOWN; |
377 | dd->ipath_flags &= ~(IPATH_LINKUNK | IPATH_LINKINIT | 389 | dd->ipath_flags &= ~(IPATH_LINKUNK | IPATH_LINKINIT |
378 | | IPATH_LINKACTIVE | | 390 | | IPATH_LINKACTIVE | |
@@ -405,7 +417,10 @@ static void handle_e_ibstatuschanged(struct ipath_devdata *dd, | |||
405 | *dd->ipath_statusp |= | 417 | *dd->ipath_statusp |= |
406 | IPATH_STATUS_IB_READY | IPATH_STATUS_IB_CONF; | 418 | IPATH_STATUS_IB_READY | IPATH_STATUS_IB_CONF; |
407 | dd->ipath_f_setextled(dd, lstate, ltstate); | 419 | dd->ipath_f_setextled(dd, lstate, ltstate); |
420 | signal_ib_event(dd, IB_EVENT_PORT_ACTIVE); | ||
408 | } else if ((val & IPATH_IBSTATE_MASK) == IPATH_IBSTATE_INIT) { | 421 | } else if ((val & IPATH_IBSTATE_MASK) == IPATH_IBSTATE_INIT) { |
422 | if (dd->ipath_flags & IPATH_LINKACTIVE) | ||
423 | signal_ib_event(dd, IB_EVENT_PORT_ERR); | ||
409 | /* | 424 | /* |
410 | * set INIT and DOWN. Down is checked by most of the other | 425 | * set INIT and DOWN. Down is checked by most of the other |
411 | * code, but INIT is useful to know in a few places. | 426 | * code, but INIT is useful to know in a few places. |
@@ -418,6 +433,8 @@ static void handle_e_ibstatuschanged(struct ipath_devdata *dd, | |||
418 | | IPATH_STATUS_IB_READY); | 433 | | IPATH_STATUS_IB_READY); |
419 | dd->ipath_f_setextled(dd, lstate, ltstate); | 434 | dd->ipath_f_setextled(dd, lstate, ltstate); |
420 | } else if ((val & IPATH_IBSTATE_MASK) == IPATH_IBSTATE_ARM) { | 435 | } else if ((val & IPATH_IBSTATE_MASK) == IPATH_IBSTATE_ARM) { |
436 | if (dd->ipath_flags & IPATH_LINKACTIVE) | ||
437 | signal_ib_event(dd, IB_EVENT_PORT_ERR); | ||
421 | dd->ipath_flags |= IPATH_LINKARMED; | 438 | dd->ipath_flags |= IPATH_LINKARMED; |
422 | dd->ipath_flags &= | 439 | dd->ipath_flags &= |
423 | ~(IPATH_LINKUNK | IPATH_LINKDOWN | IPATH_LINKINIT | | 440 | ~(IPATH_LINKUNK | IPATH_LINKDOWN | IPATH_LINKINIT | |
diff --git a/drivers/infiniband/hw/ipath/ipath_kernel.h b/drivers/infiniband/hw/ipath/ipath_kernel.h index 872fb36703d9..8786dd7922e4 100644 --- a/drivers/infiniband/hw/ipath/ipath_kernel.h +++ b/drivers/infiniband/hw/ipath/ipath_kernel.h | |||
@@ -42,6 +42,7 @@ | |||
42 | #include <linux/pci.h> | 42 | #include <linux/pci.h> |
43 | #include <linux/dma-mapping.h> | 43 | #include <linux/dma-mapping.h> |
44 | #include <asm/io.h> | 44 | #include <asm/io.h> |
45 | #include <rdma/ib_verbs.h> | ||
45 | 46 | ||
46 | #include "ipath_common.h" | 47 | #include "ipath_common.h" |
47 | #include "ipath_debug.h" | 48 | #include "ipath_debug.h" |
@@ -775,6 +776,7 @@ void ipath_get_eeprom_info(struct ipath_devdata *); | |||
775 | int ipath_update_eeprom_log(struct ipath_devdata *dd); | 776 | int ipath_update_eeprom_log(struct ipath_devdata *dd); |
776 | void ipath_inc_eeprom_err(struct ipath_devdata *dd, u32 eidx, u32 incr); | 777 | void ipath_inc_eeprom_err(struct ipath_devdata *dd, u32 eidx, u32 incr); |
777 | u64 ipath_snap_cntr(struct ipath_devdata *, ipath_creg); | 778 | u64 ipath_snap_cntr(struct ipath_devdata *, ipath_creg); |
779 | void signal_ib_event(struct ipath_devdata *dd, enum ib_event_type ev); | ||
778 | 780 | ||
779 | /* | 781 | /* |
780 | * Set LED override, only the two LSBs have "public" meaning, but | 782 | * Set LED override, only the two LSBs have "public" meaning, but |
diff --git a/drivers/infiniband/hw/ipath/ipath_mad.c b/drivers/infiniband/hw/ipath/ipath_mad.c index 8f152167208a..0ae3a7c3f86e 100644 --- a/drivers/infiniband/hw/ipath/ipath_mad.c +++ b/drivers/infiniband/hw/ipath/ipath_mad.c | |||
@@ -570,26 +570,16 @@ static int recv_subn_set_portinfo(struct ib_smp *smp, | |||
570 | else | 570 | else |
571 | goto err; | 571 | goto err; |
572 | ipath_set_linkstate(dd, lstate); | 572 | ipath_set_linkstate(dd, lstate); |
573 | if (flags & IPATH_LINKACTIVE) { | ||
574 | event.event = IB_EVENT_PORT_ERR; | ||
575 | ib_dispatch_event(&event); | ||
576 | } | ||
577 | break; | 573 | break; |
578 | case IB_PORT_ARMED: | 574 | case IB_PORT_ARMED: |
579 | if (!(flags & (IPATH_LINKINIT | IPATH_LINKACTIVE))) | 575 | if (!(flags & (IPATH_LINKINIT | IPATH_LINKACTIVE))) |
580 | break; | 576 | break; |
581 | ipath_set_linkstate(dd, IPATH_IB_LINKARM); | 577 | ipath_set_linkstate(dd, IPATH_IB_LINKARM); |
582 | if (flags & IPATH_LINKACTIVE) { | ||
583 | event.event = IB_EVENT_PORT_ERR; | ||
584 | ib_dispatch_event(&event); | ||
585 | } | ||
586 | break; | 578 | break; |
587 | case IB_PORT_ACTIVE: | 579 | case IB_PORT_ACTIVE: |
588 | if (!(flags & IPATH_LINKARMED)) | 580 | if (!(flags & IPATH_LINKARMED)) |
589 | break; | 581 | break; |
590 | ipath_set_linkstate(dd, IPATH_IB_LINKACTIVE); | 582 | ipath_set_linkstate(dd, IPATH_IB_LINKACTIVE); |
591 | event.event = IB_EVENT_PORT_ACTIVE; | ||
592 | ib_dispatch_event(&event); | ||
593 | break; | 583 | break; |
594 | default: | 584 | default: |
595 | /* XXX We have already partially updated our state! */ | 585 | /* XXX We have already partially updated our state! */ |
diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.c b/drivers/infiniband/hw/ipath/ipath_verbs.c index 13aba3d40543..74f77e7c2c1b 100644 --- a/drivers/infiniband/hw/ipath/ipath_verbs.c +++ b/drivers/infiniband/hw/ipath/ipath_verbs.c | |||
@@ -948,6 +948,7 @@ bail: | |||
948 | int ipath_verbs_send(struct ipath_qp *qp, struct ipath_ib_header *hdr, | 948 | int ipath_verbs_send(struct ipath_qp *qp, struct ipath_ib_header *hdr, |
949 | u32 hdrwords, struct ipath_sge_state *ss, u32 len) | 949 | u32 hdrwords, struct ipath_sge_state *ss, u32 len) |
950 | { | 950 | { |
951 | struct ipath_devdata *dd = to_idev(qp->ibqp.device)->dd; | ||
951 | u32 plen; | 952 | u32 plen; |
952 | int ret; | 953 | int ret; |
953 | u32 dwords = (len + 3) >> 2; | 954 | u32 dwords = (len + 3) >> 2; |
@@ -955,8 +956,15 @@ int ipath_verbs_send(struct ipath_qp *qp, struct ipath_ib_header *hdr, | |||
955 | /* +1 is for the qword padding of pbc */ | 956 | /* +1 is for the qword padding of pbc */ |
956 | plen = hdrwords + dwords + 1; | 957 | plen = hdrwords + dwords + 1; |
957 | 958 | ||
958 | ret = ipath_verbs_send_pio(qp, (u32 *) hdr, hdrwords, | 959 | /* Drop non-VL15 packets if we are not in the active state */ |
959 | ss, len, plen, dwords); | 960 | if (!(dd->ipath_flags & IPATH_LINKACTIVE) && |
961 | qp->ibqp.qp_type != IB_QPT_SMI) { | ||
962 | if (qp->s_wqe) | ||
963 | ipath_send_complete(qp, qp->s_wqe, IB_WC_SUCCESS); | ||
964 | ret = 0; | ||
965 | } else | ||
966 | ret = ipath_verbs_send_pio(qp, (u32 *) hdr, hdrwords, | ||
967 | ss, len, plen, dwords); | ||
960 | 968 | ||
961 | return ret; | 969 | return ret; |
962 | } | 970 | } |