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