Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 49739b3e authored by Ralph Campbell's avatar Ralph Campbell Committed by Roland Dreier
Browse files

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: default avatarRalph Campbell <ralph.campbell@qlogic.com>
Signed-off-by: default avatarRoland Dreier <rolandd@cisco.com>
parent 6a733cdc
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -2086,6 +2086,8 @@ void ipath_shutdown_device(struct ipath_devdata *dd)
			    INFINIPATH_IBCC_LINKINITCMD_SHIFT);
	ipath_cancel_sends(dd, 0);

	signal_ib_event(dd, IB_EVENT_PORT_ERR);

	/* disable IBC */
	dd->ipath_control &= ~INFINIPATH_C_LINKENABLE;
	ipath_write_kreg(dd, dd->ipath_kregs->kr_control,
+17 −0
Original line number Diff line number Diff line
@@ -275,6 +275,16 @@ static char *ib_linkstate(u32 linkstate)
	return ret;
}

void signal_ib_event(struct ipath_devdata *dd, enum ib_event_type ev)
{
	struct ib_event event;

	event.device = &dd->verbs_dev->ibdev;
	event.element.port_num = 1;
	event.event = ev;
	ib_dispatch_event(&event);
}

static void handle_e_ibstatuschanged(struct ipath_devdata *dd,
				     ipath_err_t errs, int noprint)
{
@@ -373,6 +383,8 @@ static void handle_e_ibstatuschanged(struct ipath_devdata *dd,
	dd->ipath_ibpollcnt = 0;	/* some state other than 2 or 3 */
	ipath_stats.sps_iblink++;
	if (ltstate != INFINIPATH_IBCS_LT_STATE_LINKUP) {
		if (dd->ipath_flags & IPATH_LINKACTIVE)
			signal_ib_event(dd, IB_EVENT_PORT_ERR);
		dd->ipath_flags |= IPATH_LINKDOWN;
		dd->ipath_flags &= ~(IPATH_LINKUNK | IPATH_LINKINIT
				     | IPATH_LINKACTIVE |
@@ -405,7 +417,10 @@ static void handle_e_ibstatuschanged(struct ipath_devdata *dd,
		*dd->ipath_statusp |=
			IPATH_STATUS_IB_READY | IPATH_STATUS_IB_CONF;
		dd->ipath_f_setextled(dd, lstate, ltstate);
		signal_ib_event(dd, IB_EVENT_PORT_ACTIVE);
	} else if ((val & IPATH_IBSTATE_MASK) == IPATH_IBSTATE_INIT) {
		if (dd->ipath_flags & IPATH_LINKACTIVE)
			signal_ib_event(dd, IB_EVENT_PORT_ERR);
		/*
		 * set INIT and DOWN.  Down is checked by most of the other
		 * code, but INIT is useful to know in a few places.
@@ -418,6 +433,8 @@ static void handle_e_ibstatuschanged(struct ipath_devdata *dd,
					| IPATH_STATUS_IB_READY);
		dd->ipath_f_setextled(dd, lstate, ltstate);
	} else if ((val & IPATH_IBSTATE_MASK) == IPATH_IBSTATE_ARM) {
		if (dd->ipath_flags & IPATH_LINKACTIVE)
			signal_ib_event(dd, IB_EVENT_PORT_ERR);
		dd->ipath_flags |= IPATH_LINKARMED;
		dd->ipath_flags &=
			~(IPATH_LINKUNK | IPATH_LINKDOWN | IPATH_LINKINIT |
+2 −0
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@
#include <linux/pci.h>
#include <linux/dma-mapping.h>
#include <asm/io.h>
#include <rdma/ib_verbs.h>

#include "ipath_common.h"
#include "ipath_debug.h"
@@ -775,6 +776,7 @@ void ipath_get_eeprom_info(struct ipath_devdata *);
int ipath_update_eeprom_log(struct ipath_devdata *dd);
void ipath_inc_eeprom_err(struct ipath_devdata *dd, u32 eidx, u32 incr);
u64 ipath_snap_cntr(struct ipath_devdata *, ipath_creg);
void signal_ib_event(struct ipath_devdata *dd, enum ib_event_type ev);

/*
 * Set LED override, only the two LSBs have "public" meaning, but
+0 −10
Original line number Diff line number Diff line
@@ -570,26 +570,16 @@ static int recv_subn_set_portinfo(struct ib_smp *smp,
		else
			goto err;
		ipath_set_linkstate(dd, lstate);
		if (flags & IPATH_LINKACTIVE) {
			event.event = IB_EVENT_PORT_ERR;
			ib_dispatch_event(&event);
		}
		break;
	case IB_PORT_ARMED:
		if (!(flags & (IPATH_LINKINIT | IPATH_LINKACTIVE)))
			break;
		ipath_set_linkstate(dd, IPATH_IB_LINKARM);
		if (flags & IPATH_LINKACTIVE) {
			event.event = IB_EVENT_PORT_ERR;
			ib_dispatch_event(&event);
		}
		break;
	case IB_PORT_ACTIVE:
		if (!(flags & IPATH_LINKARMED))
			break;
		ipath_set_linkstate(dd, IPATH_IB_LINKACTIVE);
		event.event = IB_EVENT_PORT_ACTIVE;
		ib_dispatch_event(&event);
		break;
	default:
		/* XXX We have already partially updated our state! */
+10 −2
Original line number Diff line number Diff line
@@ -948,6 +948,7 @@ static int ipath_verbs_send_pio(struct ipath_qp *qp, u32 *hdr, u32 hdrwords,
int ipath_verbs_send(struct ipath_qp *qp, struct ipath_ib_header *hdr,
		     u32 hdrwords, struct ipath_sge_state *ss, u32 len)
{
	struct ipath_devdata *dd = to_idev(qp->ibqp.device)->dd;
	u32 plen;
	int ret;
	u32 dwords = (len + 3) >> 2;
@@ -955,6 +956,13 @@ int ipath_verbs_send(struct ipath_qp *qp, struct ipath_ib_header *hdr,
	/* +1 is for the qword padding of pbc */
	plen = hdrwords + dwords + 1;

	/* Drop non-VL15 packets if we are not in the active state */
	if (!(dd->ipath_flags & IPATH_LINKACTIVE) &&
	    qp->ibqp.qp_type != IB_QPT_SMI) {
		if (qp->s_wqe)
			ipath_send_complete(qp, qp->s_wqe, IB_WC_SUCCESS);
		ret = 0;
	} else
		ret = ipath_verbs_send_pio(qp, (u32 *) hdr, hdrwords,
					   ss, len, plen, dwords);