PERFORCE change 163771 for review

Alexander Motin mav at FreeBSD.org
Mon Jun 8 10:29:28 UTC 2009


http://perforce.freebsd.org/chv.cgi?CH=163771

Change 163771 by mav at mav_mavbook on 2009/06/08 10:29:12

	Add multi-vector MSI mode support..

Affected files ...

.. //depot/projects/scottl-camlock/src/sys/dev/ahci/ahci.c#19 edit
.. //depot/projects/scottl-camlock/src/sys/dev/ahci/ahci.h#7 edit

Differences ...

==== //depot/projects/scottl-camlock/src/sys/dev/ahci/ahci.c#19 (text+ko) ====

@@ -57,6 +57,7 @@
 /* local prototypes */
 static int ahci_setup_interrupt(device_t dev);
 static void ahci_intr(void *data);
+static void ahci_intr_one(void *data);
 static int ahci_suspend(device_t dev);
 static int ahci_resume(device_t dev);
 static int ahci_ch_suspend(device_t dev);
@@ -138,12 +139,6 @@
 		return (error);
 	}
 
-	if (ahci_setup_interrupt(dev)) {
-		bus_release_resource(dev, SYS_RES_MEMORY, ctlr->r_rid, ctlr->r_mem);
-		rman_fini(&ctlr->sc_iomem);
-		return ENXIO;
-	}
-
 	/* reset controller */
 	if ((error = ahci_ctlr_reset(dev)) != 0) {
 		bus_release_resource(dev, SYS_RES_MEMORY, ctlr->r_rid, ctlr->r_mem);
@@ -156,6 +151,12 @@
 	ctlr->channels = MAX(flsl(ctlr->ichannels),
 	    (ATA_INL(ctlr->r_mem, AHCI_CAP) & AHCI_CAP_NPMASK) + 1);
 
+	if (ahci_setup_interrupt(dev)) {
+		bus_release_resource(dev, SYS_RES_MEMORY, ctlr->r_rid, ctlr->r_mem);
+		rman_fini(&ctlr->sc_iomem);
+		return ENXIO;
+	}
+
 	/* announce we support the HW */
 	version = ATA_INL(ctlr->r_mem, AHCI_VS);
 	caps = ATA_INL(ctlr->r_mem, AHCI_CAP);
@@ -223,12 +224,15 @@
 		free(children, M_TEMP);
 	}
 
-	if (ctlr->r_irq) {
-		bus_teardown_intr(dev, ctlr->r_irq, ctlr->handle);
-		bus_release_resource(dev, SYS_RES_IRQ, ctlr->r_irq_rid, ctlr->r_irq);
-		if (ctlr->r_irq_rid != ATA_IRQ_RID)
-			pci_release_msi(dev);
+	for (i = 0; i < ctlr->numirqs; i++) {
+		if (ctlr->irqs[i].r_irq) {
+			bus_teardown_intr(dev, ctlr->irqs[i].r_irq,
+			    ctlr->irqs[i].handle);
+			bus_release_resource(dev, SYS_RES_IRQ,
+			    ctlr->irqs[i].r_irq_rid, ctlr->irqs[i].r_irq);
+		}
 	}
+	pci_release_msi(dev);
 
 	rman_fini(&ctlr->sc_iomem);
 	if (ctlr->r_mem)
@@ -303,23 +307,44 @@
 	int i, msi = 0;
 
 	if (resource_int_value(device_get_name(dev),
-	    device_get_unit(dev), "msi", &i) == 0 && i != 0)
-		msi = 1;
-	if (msi && pci_msi_count(dev) > 0 && pci_alloc_msi(dev, &msi) == 0) {
-		ctlr->r_irq_rid = 0x1;
+	    device_get_unit(dev), "msi", &i) == 0) {
+		if (i == 1)
+			msi = min(1, pci_msi_count(dev));
+		else if (i > 1)
+			msi = pci_msi_count(dev);
+	}
+	if (msi && pci_alloc_msi(dev, &msi) == 0) {
+		ctlr->numirqs = msi;
 	} else {
-		ctlr->r_irq_rid = ATA_IRQ_RID;
+		msi = 0;
+		ctlr->numirqs = 1;
 	}
-	if (!(ctlr->r_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ,
-	    &ctlr->r_irq_rid, RF_SHAREABLE | RF_ACTIVE))) {
-		device_printf(dev, "unable to map interrupt\n");
-		return ENXIO;
+	if (ctlr->numirqs > 1 &&
+	    (ATA_INL(ctlr->r_mem, AHCI_GHC) & AHCI_GHC_MRSM) != 0) {
+		device_printf(dev, "Falling back to one MSI\n");
+		ctlr->numirqs = 1;
 	}
-	if ((bus_setup_intr(dev, ctlr->r_irq, ATA_INTR_FLAGS, NULL,
-	    ahci_intr, ctlr, &ctlr->handle))) {
-		/* SOS XXX release r_irq */
-		device_printf(dev, "unable to setup interrupt\n");
-		return ENXIO;
+	for (i = 0; i < ctlr->numirqs; i++) {
+		ctlr->irqs[i].ctlr = ctlr;
+		ctlr->irqs[i].r_irq_rid = i + (msi ? 1 : 0);
+		if (ctlr->numirqs == 1 || i >= ctlr->channels)
+			ctlr->irqs[i].mode = AHCI_IRQ_MODE_ALL;
+		else if (i == ctlr->numirqs - 1)
+			ctlr->irqs[i].mode = AHCI_IRQ_MODE_AFTER;
+		else
+			ctlr->irqs[i].mode = AHCI_IRQ_MODE_ONE;
+		if (!(ctlr->irqs[i].r_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ,
+		    &ctlr->irqs[i].r_irq_rid, RF_SHAREABLE | RF_ACTIVE))) {
+			device_printf(dev, "unable to map interrupt\n");
+			return ENXIO;
+		}
+		if ((bus_setup_intr(dev, ctlr->irqs[i].r_irq, ATA_INTR_FLAGS, NULL,
+		    (ctlr->irqs[i].mode == AHCI_IRQ_MODE_ONE) ? ahci_intr_one : ahci_intr,
+		    &ctlr->irqs[i], &ctlr->irqs[i].handle))) {
+			/* SOS XXX release r_irq */
+			device_printf(dev, "unable to setup interrupt\n");
+			return ENXIO;
+		}
 	}
 	return (0);
 }
@@ -327,19 +352,41 @@
 static void
 ahci_intr(void *data)
 {
-    struct ahci_controller *ctlr = data;
-    u_int32_t is = ATA_INL(ctlr->r_mem, AHCI_IS);
-    void *arg;
-    int unit;
+	struct ahci_controller_irq *irq = data;
+	struct ahci_controller *ctlr = irq->ctlr;
+	u_int32_t is;
+	void *arg;
+	int unit;
 
-//device_printf(ctlr->dev, "%s is %08x\n", __func__, is);
-    for (unit = 0; unit < ctlr->channels; unit++) {
-	if ((is & (1 << unit)) != 0 &&
-	    (arg = ctlr->interrupt[unit].argument)) {
-		ctlr->interrupt[unit].function(arg);
-		ATA_OUTL(ctlr->r_mem, AHCI_IS, 1 << unit);
+	is = ATA_INL(ctlr->r_mem, AHCI_IS);
+//device_printf(ctlr->dev, "%s is %08x inum %d\n", __func__, is, irq->r_irq_rid);
+	if (irq->mode == AHCI_IRQ_MODE_ALL)
+		unit = 0;
+	else	/* AHCI_IRQ_MODE_AFTER */
+		unit = irq->r_irq_rid - 1;
+	for (; unit < ctlr->channels; unit++) {
+		if ((is & (1 << unit)) != 0 &&
+		    (arg = ctlr->interrupt[unit].argument)) {
+			ctlr->interrupt[unit].function(arg);
+			ATA_OUTL(ctlr->r_mem, AHCI_IS, 1 << unit);
+		}
 	}
-    }
+}
+
+static void
+ahci_intr_one(void *data)
+{
+	struct ahci_controller_irq *irq = data;
+	struct ahci_controller *ctlr = irq->ctlr;
+//	u_int32_t is;
+	void *arg;
+	int unit;
+
+	unit = irq->r_irq_rid - 1;
+//		is = ATA_INL(ctlr->r_mem, AHCI_IS);
+//device_printf(ctlr->dev, "%s is %08x one %d\n", __func__, is, irq->r_irq_rid);
+	if ((arg = ctlr->interrupt[unit].argument))
+	    ctlr->interrupt[unit].function(arg);
 }
 
 static struct resource *
@@ -369,7 +416,7 @@
 		break;
 	case SYS_RES_IRQ:
 		if (*rid == ATA_IRQ_RID)
-			res = ctlr->r_irq;
+			res = ctlr->irqs[0].r_irq;
 		break;
 	}
 	return (res);
@@ -807,15 +854,14 @@
 	int i, ccs;
 
 	mtx_lock(&ch->mtx);
-	/* Read interrupt and command statuses. */
+	/* Read and clear interrupt statuses. */
 	istatus = ATA_INL(ch->r_mem, AHCI_P_IS);
+	ATA_OUTL(ch->r_mem, AHCI_P_IS, istatus);
+	/* Read command statuses. */
 	cstatus = ATA_INL(ch->r_mem, AHCI_P_CI);
 	sstatus = ATA_INL(ch->r_mem, AHCI_P_SACT);
 //device_printf(dev, "%s is %08x cs %08x ss %08x rslots %08x\n", __func__, istatus, cstatus, sstatus, ch->rslots);
 
-	/* Clear interrupt(s) */
-	ATA_OUTL(ch->r_mem, AHCI_P_IS, istatus);
-
 	/* Process PHY events */
 	if (istatus & (AHCI_P_IX_PRC | AHCI_P_IX_PC))
 		ahci_phy_check_events(dev);

==== //depot/projects/scottl-camlock/src/sys/dev/ahci/ahci.h#7 (text+ko) ====

@@ -168,6 +168,7 @@
 
 #define AHCI_GHC                    0x04
 #define         AHCI_GHC_AE         0x80000000
+#define         AHCI_GHC_MRSM       0x00000004
 #define         AHCI_GHC_IE         0x00000002
 #define         AHCI_GHC_HR         0x00000001
 
@@ -306,7 +307,6 @@
 
 /* structure holding DMA related information */
 struct ata_dma {
-    bus_dma_tag_t               dmatag;         /* parent DMA tag */
     bus_dma_tag_t               work_tag;       /* workspace DMA tag */
     bus_dmamap_t                work_map;       /* workspace DMA map */
     u_int8_t                    *work;          /* workspace */
@@ -383,18 +383,26 @@
 
 /* structure describing a AHCI controller */
 struct ahci_controller {
-	device_t            dev;
-	int                 r_rid;
-	struct resource     *r_mem;
-	int                 r_irq_rid;
-	struct resource     *r_irq;
-	void                *handle;
+	device_t		dev;
+	int			r_rid;
+	struct resource		*r_mem;
 	struct rman		sc_iomem;
-	int                 channels;
+	struct ahci_controller_irq {
+		struct ahci_controller	*ctlr;
+		struct resource		*r_irq;
+		void			*handle;
+		int			r_irq_rid;
+		int			mode;
+#define	AHCI_IRQ_MODE_ALL	0
+#define	AHCI_IRQ_MODE_AFTER	1
+#define	AHCI_IRQ_MODE_ONE	2
+	} irqs[16];
+	int			numirqs;
+	int			channels;
 	int			ichannels;
 	struct {
-		void        (*function)(void *);
-		void        *argument;
+		void			(*function)(void *);
+		void			*argument;
 	} interrupt[AHCI_MAX_PORTS];
 };
 


More information about the p4-projects mailing list