diff options
Diffstat (limited to 'drivers/infiniband/hw/ipath/ipath_intr.c')
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_intr.c | 64 |
1 files changed, 35 insertions, 29 deletions
diff --git a/drivers/infiniband/hw/ipath/ipath_intr.c b/drivers/infiniband/hw/ipath/ipath_intr.c index b29fe7e9b1..6a5dd5cd77 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 | |
@@ -688,17 +705,9 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs) | |||
688 | chkerrpkts = 1; | 705 | chkerrpkts = 1; |
689 | dd->ipath_lastrcvhdrqtails[i] = tl; | 706 | dd->ipath_lastrcvhdrqtails[i] = tl; |
690 | pd->port_hdrqfull++; | 707 | pd->port_hdrqfull++; |
691 | if (test_bit(IPATH_PORT_WAITING_OVERFLOW, | 708 | /* flush hdrqfull so that poll() sees it */ |
692 | &pd->port_flag)) { | 709 | wmb(); |
693 | clear_bit( | 710 | wake_up_interruptible(&pd->port_wait); |
694 | IPATH_PORT_WAITING_OVERFLOW, | ||
695 | &pd->port_flag); | ||
696 | set_bit( | ||
697 | IPATH_PORT_WAITING_OVERFLOW, | ||
698 | &pd->int_flag); | ||
699 | wake_up_interruptible( | ||
700 | &pd->port_wait); | ||
701 | } | ||
702 | } | 711 | } |
703 | } | 712 | } |
704 | } | 713 | } |
@@ -960,6 +969,8 @@ static void handle_urcv(struct ipath_devdata *dd, u32 istat) | |||
960 | int i; | 969 | int i; |
961 | int rcvdint = 0; | 970 | int rcvdint = 0; |
962 | 971 | ||
972 | /* test_bit below needs this... */ | ||
973 | rmb(); | ||
963 | portr = ((istat >> INFINIPATH_I_RCVAVAIL_SHIFT) & | 974 | portr = ((istat >> INFINIPATH_I_RCVAVAIL_SHIFT) & |
964 | dd->ipath_i_rcvavail_mask) | 975 | dd->ipath_i_rcvavail_mask) |
965 | | ((istat >> INFINIPATH_I_RCVURG_SHIFT) & | 976 | | ((istat >> INFINIPATH_I_RCVURG_SHIFT) & |
@@ -967,22 +978,15 @@ static void handle_urcv(struct ipath_devdata *dd, u32 istat) | |||
967 | for (i = 1; i < dd->ipath_cfgports; i++) { | 978 | for (i = 1; i < dd->ipath_cfgports; i++) { |
968 | struct ipath_portdata *pd = dd->ipath_pd[i]; | 979 | struct ipath_portdata *pd = dd->ipath_pd[i]; |
969 | if (portr & (1 << i) && pd && pd->port_cnt) { | 980 | if (portr & (1 << i) && pd && pd->port_cnt) { |
970 | if (test_bit(IPATH_PORT_WAITING_RCV, | 981 | if (test_and_clear_bit(IPATH_PORT_WAITING_RCV, |
971 | &pd->port_flag)) { | 982 | &pd->port_flag)) { |
972 | clear_bit(IPATH_PORT_WAITING_RCV, | ||
973 | &pd->port_flag); | ||
974 | set_bit(IPATH_PORT_WAITING_RCV, | ||
975 | &pd->int_flag); | ||
976 | clear_bit(i + INFINIPATH_R_INTRAVAIL_SHIFT, | 983 | clear_bit(i + INFINIPATH_R_INTRAVAIL_SHIFT, |
977 | &dd->ipath_rcvctrl); | 984 | &dd->ipath_rcvctrl); |
978 | wake_up_interruptible(&pd->port_wait); | 985 | wake_up_interruptible(&pd->port_wait); |
979 | rcvdint = 1; | 986 | rcvdint = 1; |
980 | } else if (test_bit(IPATH_PORT_WAITING_URG, | 987 | } else if (test_and_clear_bit(IPATH_PORT_WAITING_URG, |
981 | &pd->port_flag)) { | 988 | &pd->port_flag)) { |
982 | clear_bit(IPATH_PORT_WAITING_URG, | 989 | pd->port_urgent++; |
983 | &pd->port_flag); | ||
984 | set_bit(IPATH_PORT_WAITING_URG, | ||
985 | &pd->int_flag); | ||
986 | wake_up_interruptible(&pd->port_wait); | 990 | wake_up_interruptible(&pd->port_wait); |
987 | } | 991 | } |
988 | } | 992 | } |
@@ -1085,8 +1089,8 @@ irqreturn_t ipath_intr(int irq, void *data) | |||
1085 | * GPIO_2 indicates (on some HT4xx boards) that a packet | 1089 | * GPIO_2 indicates (on some HT4xx boards) that a packet |
1086 | * has arrived for Port 0. Checking for this | 1090 | * has arrived for Port 0. Checking for this |
1087 | * is controlled by flag IPATH_GPIO_INTR. | 1091 | * is controlled by flag IPATH_GPIO_INTR. |
1088 | * GPIO_3..5 on IBA6120 Rev2 chips indicate errors | 1092 | * GPIO_3..5 on IBA6120 Rev2 and IBA6110 Rev4 chips indicate |
1089 | * that we need to count. Checking for this | 1093 | * errors that we need to count. Checking for this |
1090 | * is controlled by flag IPATH_GPIO_ERRINTRS. | 1094 | * is controlled by flag IPATH_GPIO_ERRINTRS. |
1091 | */ | 1095 | */ |
1092 | u32 gpiostatus; | 1096 | u32 gpiostatus; |
@@ -1137,10 +1141,8 @@ irqreturn_t ipath_intr(int irq, void *data) | |||
1137 | /* | 1141 | /* |
1138 | * Some unexpected bits remain. If they could have | 1142 | * Some unexpected bits remain. If they could have |
1139 | * caused the interrupt, complain and clear. | 1143 | * caused the interrupt, complain and clear. |
1140 | * MEA: this is almost certainly non-ideal. | 1144 | * To avoid repetition of this condition, also clear |
1141 | * we should look into auto-disable of unexpected | 1145 | * the mask. It is almost certainly due to error. |
1142 | * GPIO interrupts, possibly on a "three strikes" | ||
1143 | * basis. | ||
1144 | */ | 1146 | */ |
1145 | const u32 mask = (u32) dd->ipath_gpio_mask; | 1147 | const u32 mask = (u32) dd->ipath_gpio_mask; |
1146 | 1148 | ||
@@ -1148,6 +1150,10 @@ irqreturn_t ipath_intr(int irq, void *data) | |||
1148 | ipath_dbg("Unexpected GPIO IRQ bits %x\n", | 1150 | ipath_dbg("Unexpected GPIO IRQ bits %x\n", |
1149 | gpiostatus & mask); | 1151 | gpiostatus & mask); |
1150 | to_clear |= (gpiostatus & mask); | 1152 | to_clear |= (gpiostatus & mask); |
1153 | dd->ipath_gpio_mask &= ~(gpiostatus & mask); | ||
1154 | ipath_write_kreg(dd, | ||
1155 | dd->ipath_kregs->kr_gpio_mask, | ||
1156 | dd->ipath_gpio_mask); | ||
1151 | } | 1157 | } |
1152 | } | 1158 | } |
1153 | if (to_clear) { | 1159 | if (to_clear) { |