Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 19 Mar 2017 19:11:40 +0000 (UTC)
From:      Alexander Motin <mav@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r315579 - head/sys/dev/isp
Message-ID:  <201703191911.v2JJBedF084426@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: mav
Date: Sun Mar 19 19:11:40 2017
New Revision: 315579
URL: https://svnweb.freebsd.org/changeset/base/315579

Log:
  Add initial support for multiple MSI-X vectors.
  
  For 24xx and above use 2 vectors (default and response queue).
  For 26xx and above use 3 vectors (default, response and ATIO queues).
  Due to global lock interrupt hardlers never run simultaneously now, but
  at least this allows to save one regitster read per interrupt.
  
  MFC after:	2 weeks

Modified:
  head/sys/dev/isp/isp.c
  head/sys/dev/isp/isp_freebsd.c
  head/sys/dev/isp/isp_freebsd.h
  head/sys/dev/isp/isp_pci.c
  head/sys/dev/isp/isp_sbus.c
  head/sys/dev/isp/ispmbox.h
  head/sys/dev/isp/ispvar.h

Modified: head/sys/dev/isp/isp.c
==============================================================================
--- head/sys/dev/isp/isp.c	Sun Mar 19 19:10:23 2017	(r315578)
+++ head/sys/dev/isp/isp.c	Sun Mar 19 19:11:40 2017	(r315579)
@@ -2089,7 +2089,7 @@ isp_fibre_init_2400(ispsoftc_t *isp)
 	}
 
 	if (IS_26XX(isp)) {
-		/* We don't support MSI-X yet, so set this unconditionally. */
+		/* Use handshake to reduce global lock congestion. */
 		icbp->icb_fwoptions2 |= ICB2400_OPT2_ENA_IHR;
 		icbp->icb_fwoptions2 |= ICB2400_OPT2_ENA_IHA;
 	}
@@ -2187,6 +2187,12 @@ isp_fibre_init_2400(ispsoftc_t *isp)
 	    DMA_WD1(isp->isp_atioq_dma), DMA_WD0(isp->isp_atioq_dma));
 #endif
 
+	if (ISP_CAP_MSIX(isp) && isp->isp_nirq >= 2) {
+		icbp->icb_msixresp = 1;
+		if (IS_26XX(isp) && isp->isp_nirq >= 3)
+			icbp->icb_msixatio = 2;
+	}
+
 	isp_prt(isp, ISP_LOGDEBUG0, "isp_fibre_init_2400: fwopt1 0x%x fwopt2 0x%x fwopt3 0x%x", icbp->icb_fwoptions1, icbp->icb_fwoptions2, icbp->icb_fwoptions3);
 
 	isp_prt(isp, ISP_LOGDEBUG0, "isp_fibre_init_2400: rqst %04x%04x%04x%04x rsp %04x%04x%04x%04x", DMA_WD3(isp->isp_rquest_dma), DMA_WD2(isp->isp_rquest_dma),

Modified: head/sys/dev/isp/isp_freebsd.c
==============================================================================
--- head/sys/dev/isp/isp_freebsd.c	Sun Mar 19 19:10:23 2017	(r315578)
+++ head/sys/dev/isp/isp_freebsd.c	Sun Mar 19 19:11:40 2017	(r315579)
@@ -4160,6 +4160,34 @@ isp_platform_intr(void *arg)
 }
 
 void
+isp_platform_intr_resp(void *arg)
+{
+	ispsoftc_t *isp = arg;
+
+	ISP_LOCK(isp);
+	isp_intr_respq(isp);
+	ISP_UNLOCK(isp);
+
+	/* We have handshake enabled, so explicitly complete interrupt */
+	ISP_WRITE(isp, BIU2400_HCCR, HCCR_2400_CMD_CLEAR_RISC_INT);
+}
+
+void
+isp_platform_intr_atio(void *arg)
+{
+	ispsoftc_t *isp = arg;
+
+	ISP_LOCK(isp);
+#ifdef	ISP_TARGET_MODE
+	isp_intr_atioq(isp);
+#endif
+	ISP_UNLOCK(isp);
+
+	/* We have handshake enabled, so explicitly complete interrupt */
+	ISP_WRITE(isp, BIU2400_HCCR, HCCR_2400_CMD_CLEAR_RISC_INT);
+}
+
+void
 isp_common_dmateardown(ispsoftc_t *isp, struct ccb_scsiio *csio, uint32_t hdl)
 {
 	if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {

Modified: head/sys/dev/isp/isp_freebsd.h
==============================================================================
--- head/sys/dev/isp/isp_freebsd.h	Sun Mar 19 19:10:23 2017	(r315578)
+++ head/sys/dev/isp/isp_freebsd.h	Sun Mar 19 19:11:40 2017	(r315579)
@@ -722,6 +722,8 @@ void isp_mbox_release(ispsoftc_t *);
 int isp_fc_scratch_acquire(ispsoftc_t *, int);
 int isp_mstohz(int);
 void isp_platform_intr(void *);
+void isp_platform_intr_resp(void *);
+void isp_platform_intr_atio(void *);
 void isp_common_dmateardown(ispsoftc_t *, struct ccb_scsiio *, uint32_t);
 void isp_fcp_reset_crn(ispsoftc_t *, int, uint32_t, int);
 int isp_fcp_next_crn(ispsoftc_t *, uint8_t *, XS_T *);
@@ -734,8 +736,6 @@ int isp_fcp_next_crn(ispsoftc_t *, uint8
 	bus_dma_tag_create(a, b, c, d, e, f, g, h, i, j, k, \
 	busdma_lock_mutex, &isp->isp_osinfo.lock, z)
 
-#define	isp_setup_intr	bus_setup_intr
-
 #define	isp_sim_alloc(a, b, c, d, e, f, g, h)	\
 	cam_sim_alloc(a, b, c, d, e, &(d)->isp_osinfo.lock, f, g, h)
 

Modified: head/sys/dev/isp/isp_pci.c
==============================================================================
--- head/sys/dev/isp/isp_pci.c	Sun Mar 19 19:10:23 2017	(r315578)
+++ head/sys/dev/isp/isp_pci.c	Sun Mar 19 19:11:40 2017	(r315579)
@@ -364,15 +364,17 @@ struct isp_pcisoftc {
 	struct resource *		regs;
 	struct resource *		regs1;
 	struct resource *		regs2;
-	void *				irq;
-	int				iqd;
+	struct {
+		int				iqd;
+		struct resource *		irq;
+		void *				ih;
+	} irq[ISP_MAX_IRQS];
 	int				rtp;
 	int				rgd;
 	int				rtp1;
 	int				rgd1;
 	int				rtp2;
 	int				rgd2;
-	void *				ih;
 	int16_t				pci_poff[_NREG_BLKS];
 	bus_dma_tag_t			dmat;
 	int				msicount;
@@ -691,8 +693,8 @@ isp_pci_attach(device_t dev)
 	isp_get_generic_options(dev, isp);
 
 	linesz = PCI_DFLT_LNSZ;
-	pcs->irq = pcs->regs = pcs->regs2 = NULL;
-	pcs->rgd = pcs->rtp = pcs->iqd = 0;
+	pcs->regs = pcs->regs2 = NULL;
+	pcs->rgd = pcs->rtp = 0;
 
 	pcs->pci_dev = dev;
 	pcs->pci_poff[BIU_BLOCK >> _BLK_REG_SHFT] = BIU_REGS_OFF;
@@ -932,41 +934,6 @@ isp_pci_attach(device_t dev)
 	data &= ~1;
 	pci_write_config(dev, PCIR_ROMADDR, data, 4);
 
-	if (IS_26XX(isp)) {
-		/* 26XX chips support only MSI-X, so start from them. */
-		pcs->msicount = imin(pci_msix_count(dev), 1);
-		if (pcs->msicount > 0 &&
-		    (i = pci_alloc_msix(dev, &pcs->msicount)) == 0) {
-			pcs->iqd = 1;
-		} else {
-			pcs->msicount = 0;
-		}
-	}
-	if (pcs->msicount == 0 && (IS_24XX(isp) || IS_2322(isp))) {
-		/*
-		 * Older chips support both MSI and MSI-X, but I have
-		 * feeling that older firmware may not support MSI-X,
-		 * but we have no way to check the firmware flag here.
-		 */
-		pcs->msicount = imin(pci_msi_count(dev), 1);
-		if (pcs->msicount > 0 &&
-		    pci_alloc_msi(dev, &pcs->msicount) == 0) {
-			pcs->iqd = 1;
-		} else {
-			pcs->msicount = 0;
-		}
-	}
-	pcs->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &pcs->iqd, RF_ACTIVE | RF_SHAREABLE);
-	if (pcs->irq == NULL) {
-		device_printf(dev, "could not allocate interrupt\n");
-		goto bad;
-	}
-
-	if (isp_setup_intr(dev, pcs->irq, ISP_IFLAGS, NULL, isp_platform_intr, isp, &pcs->ih)) {
-		device_printf(dev, "could not setup interrupt\n");
-		goto bad;
-	}
-
 	/*
 	 * Last minute checks...
 	 */
@@ -992,11 +959,10 @@ isp_pci_attach(device_t dev)
 	return (0);
 
 bad:
-	if (pcs->ih) {
-		(void) bus_teardown_intr(dev, pcs->irq, pcs->ih);
-	}
-	if (pcs->irq) {
-		(void) bus_release_resource(dev, SYS_RES_IRQ, pcs->iqd, pcs->irq);
+	for (i = 0; i < isp->isp_nirq; i++) {
+		(void) bus_teardown_intr(dev, pcs->irq[i].irq, pcs->irq[i].ih);
+		(void) bus_release_resource(dev, SYS_RES_IRQ, pcs->irq[i].iqd,
+		    pcs->irq[0].irq);
 	}
 	if (pcs->msicount) {
 		pci_release_msi(dev);
@@ -1024,7 +990,7 @@ isp_pci_detach(device_t dev)
 {
 	struct isp_pcisoftc *pcs = device_get_softc(dev);
 	ispsoftc_t *isp = &pcs->pci_isp;
-	int status;
+	int i, status;
 
 	status = isp_detach(isp);
 	if (status)
@@ -1032,9 +998,11 @@ isp_pci_detach(device_t dev)
 	ISP_LOCK(isp);
 	isp_shutdown(isp);
 	ISP_UNLOCK(isp);
-	if (pcs->ih)
-		(void) bus_teardown_intr(dev, pcs->irq, pcs->ih);
-	(void) bus_release_resource(dev, SYS_RES_IRQ, pcs->iqd, pcs->irq);
+	for (i = 0; i < isp->isp_nirq; i++) {
+		(void) bus_teardown_intr(dev, pcs->irq[i].irq, pcs->irq[i].ih);
+		(void) bus_release_resource(dev, SYS_RES_IRQ, pcs->irq[i].iqd,
+		    pcs->irq[i].irq);
+	}
 	if (pcs->msicount)
 		pci_release_msi(dev);
 	(void) bus_release_resource(dev, pcs->rtp, pcs->rgd, pcs->regs);
@@ -2077,8 +2045,57 @@ isp_pci_dmasetup(ispsoftc_t *isp, struct
 static int
 isp_pci_irqsetup(ispsoftc_t *isp)
 {
+	device_t dev = isp->isp_osinfo.dev;
+	struct isp_pcisoftc *pcs = device_get_softc(dev);
+	driver_intr_t *f;
+	int i, max_irq;
 
-	return (0);
+	/* Allocate IRQs only once. */
+	if (isp->isp_nirq > 0)
+		return (0);
+
+	if (ISP_CAP_MSIX(isp)) {
+		max_irq = min(ISP_MAX_IRQS, IS_26XX(isp) ? 3 : 2);
+		pcs->msicount = imin(pci_msix_count(dev), max_irq);
+		if (pcs->msicount > 0 &&
+		    pci_alloc_msix(dev, &pcs->msicount) != 0)
+			pcs->msicount = 0;
+	}
+	if (pcs->msicount == 0) {
+		pcs->msicount = imin(pci_msi_count(dev), 1);
+		if (pcs->msicount > 0 &&
+		    pci_alloc_msi(dev, &pcs->msicount) != 0)
+			pcs->msicount = 0;
+	}
+	for (i = 0; i < MAX(1, pcs->msicount); i++) {
+		pcs->irq[i].iqd = i + (pcs->msicount > 0);
+		pcs->irq[i].irq = bus_alloc_resource_any(dev, SYS_RES_IRQ,
+		    &pcs->irq[i].iqd, RF_ACTIVE | RF_SHAREABLE);
+		if (pcs->irq[i].irq == NULL) {
+			device_printf(dev, "could not allocate interrupt\n");
+			break;
+		}
+		if (i == 0)
+			f = isp_platform_intr;
+		else if (i == 1)
+			f = isp_platform_intr_resp;
+		else
+			f = isp_platform_intr_atio;
+		if (bus_setup_intr(dev, pcs->irq[i].irq, ISP_IFLAGS, NULL,
+		    f, isp, &pcs->irq[i].ih)) {
+			device_printf(dev, "could not setup interrupt\n");
+			(void) bus_release_resource(dev, SYS_RES_IRQ,
+			    pcs->irq[i].iqd, pcs->irq[i].irq);
+			break;
+		}
+		if (pcs->msicount > 1) {
+			bus_describe_intr(dev, pcs->irq[i].irq, pcs->irq[i].ih,
+			    "%d", i);
+		}
+		isp->isp_nirq = i + 1;
+	}
+
+	return (isp->isp_nirq == 0);
 }
 
 static void

Modified: head/sys/dev/isp/isp_sbus.c
==============================================================================
--- head/sys/dev/isp/isp_sbus.c	Sun Mar 19 19:10:23 2017	(r315578)
+++ head/sys/dev/isp/isp_sbus.c	Sun Mar 19 19:11:40 2017	(r315579)
@@ -139,7 +139,6 @@ isp_sbus_attach(device_t dev)
 	struct isp_sbussoftc *sbs = device_get_softc(dev);
 	ispsoftc_t *isp = &sbs->sbus_isp;
 	int tval, isp_debug, role, ispburst, default_id;
-	int ints_setup = 0;
 
 	sbs->sbus_dev = dev;
 	sbs->sbus_mdvec = mdvec;
@@ -262,12 +261,14 @@ isp_sbus_attach(device_t dev)
 		goto bad;
 	}
 
-	if (isp_setup_intr(dev, sbs->irq, ISP_IFLAGS, NULL, isp_platform_intr,
+	if (bus_setup_intr(dev, sbs->irq, ISP_IFLAGS, NULL, isp_platform_intr,
 	    isp, &sbs->ih)) {
 		device_printf(dev, "could not setup interrupt\n");
+		(void) bus_release_resource(dev, SYS_RES_IRQ,
+		    sbs->iqd, sbs->irq);
 		goto bad;
 	}
-	ints_setup++;
+	isp->isp_nirq = 1;
 
 	/*
 	 * Set up logging levels.
@@ -299,13 +300,10 @@ isp_sbus_attach(device_t dev)
 	return (0);
 
 bad:
-
-	if (sbs && ints_setup) {
+	if (isp->isp_nirq > 0) {
 		(void) bus_teardown_intr(dev, sbs->irq, sbs->ih);
-	}
-
-	if (sbs && sbs->irq) {
-		bus_release_resource(dev, SYS_RES_IRQ, sbs->iqd, sbs->irq);
+		(void) bus_release_resource(dev, SYS_RES_IRQ, sbs->iqd,
+		    sbs->irq);
 	}
 
 	if (sbs->regs) {
@@ -329,9 +327,11 @@ isp_sbus_detach(device_t dev)
 	ISP_LOCK(isp);
 	isp_shutdown(isp);
 	ISP_UNLOCK(isp);
-	if (sbs->ih)
+	if (isp->isp_nirq > 0) {
 		(void) bus_teardown_intr(dev, sbs->irq, sbs->ih);
-	(void) bus_release_resource(dev, SYS_RES_IRQ, sbs->iqd, sbs->irq);
+		(void) bus_release_resource(dev, SYS_RES_IRQ, sbs->iqd,
+		    sbs->irq);
+	}
 	(void) bus_release_resource(dev, SYS_RES_MEMORY, sbs->rgd, sbs->regs);
 	isp_sbus_mbxdmafree(isp);
 	mtx_destroy(&isp->isp_osinfo.lock);

Modified: head/sys/dev/isp/ispmbox.h
==============================================================================
--- head/sys/dev/isp/ispmbox.h	Sun Mar 19 19:10:23 2017	(r315578)
+++ head/sys/dev/isp/ispmbox.h	Sun Mar 19 19:11:40 2017	(r315579)
@@ -895,6 +895,8 @@ typedef struct {
 	(IS_24XX(isp)? (isp->isp_fwattr & ISP2400_FW_ATTR_MULTIID) : 0)
 #define	ISP_GET_VPIDX(isp, tag) \
 	(ISP_CAP_MULTI_ID(isp) ? tag : 0)
+#define	ISP_CAP_MSIX(isp)	\
+	(IS_24XX(isp)? (isp->isp_fwattr & ISP2400_FW_ATTR_MSIX) : 0)
 #define	ISP_CAP_VP0(isp)	\
 	(IS_24XX(isp)? (isp->isp_fwattr & ISP2400_FW_ATTR_VP0) : 0)
 

Modified: head/sys/dev/isp/ispvar.h
==============================================================================
--- head/sys/dev/isp/ispvar.h	Sun Mar 19 19:10:23 2017	(r315578)
+++ head/sys/dev/isp/ispvar.h	Sun Mar 19 19:11:40 2017	(r315579)
@@ -80,6 +80,7 @@ struct ispmdvec {
 #endif
 #define	ISP_MAX_TARGETS(isp)	(IS_FC(isp)? MAX_FC_TARG : MAX_TARGETS)
 #define	ISP_MAX_LUNS(isp)	(isp)->isp_maxluns
+#define	ISP_MAX_IRQS		3
 
 /*
  * Macros to access ISP registers through bus specific layers-
@@ -526,6 +527,7 @@ struct ispsoftc {
 	uint16_t		isp_maxcmds;	/* max possible I/O cmds */
 	uint8_t			isp_type;	/* HBA Chip Type */
 	uint8_t			isp_revision;	/* HBA Chip H/W Revision */
+	uint8_t			isp_nirq;	/* number of IRQs */
 	uint16_t		isp_nchan;	/* number of channels */
 	uint32_t		isp_maxluns;	/* maximum luns supported */
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201703191911.v2JJBedF084426>