Commit 495c0217 authored by Mahesh Rajashekhara's avatar Mahesh Rajashekhara Committed by James Bottomley

aacraid: MSI-x support

Signed-off-by: default avatarMahesh Rajashekhara <Mahesh.Rajashekhara@pmcs.com>
Reviewed-by: default avatarHannes Reinecke <hare@suse.de>
Reviewed-by: default avatarMurthy Bhat <Murthy.Bhat@pmcs.com>
Signed-off-by: default avatarJames Bottomley <JBottomley@Odin.com>
parent b836439f
...@@ -6,11 +6,61 @@ ...@@ -6,11 +6,61 @@
#define nblank(x) _nblank(x)[0] #define nblank(x) _nblank(x)[0]
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/pci.h>
/*------------------------------------------------------------------------------ /*------------------------------------------------------------------------------
* D E F I N E S * D E F I N E S
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define AAC_MAX_MSIX 32 /* vectors */
#define AAC_PCI_MSI_ENABLE 0x8000
enum {
AAC_ENABLE_INTERRUPT = 0x0,
AAC_DISABLE_INTERRUPT,
AAC_ENABLE_MSIX,
AAC_DISABLE_MSIX,
AAC_CLEAR_AIF_BIT,
AAC_CLEAR_SYNC_BIT,
AAC_ENABLE_INTX
};
#define AAC_INT_MODE_INTX (1<<0)
#define AAC_INT_MODE_MSI (1<<1)
#define AAC_INT_MODE_AIF (1<<2)
#define AAC_INT_MODE_SYNC (1<<3)
#define AAC_INT_ENABLE_TYPE1_INTX 0xfffffffb
#define AAC_INT_ENABLE_TYPE1_MSIX 0xfffffffa
#define AAC_INT_DISABLE_ALL 0xffffffff
/* Bit definitions in IOA->Host Interrupt Register */
#define PMC_TRANSITION_TO_OPERATIONAL (1<<31)
#define PMC_IOARCB_TRANSFER_FAILED (1<<28)
#define PMC_IOA_UNIT_CHECK (1<<27)
#define PMC_NO_HOST_RRQ_FOR_CMD_RESPONSE (1<<26)
#define PMC_CRITICAL_IOA_OP_IN_PROGRESS (1<<25)
#define PMC_IOARRIN_LOST (1<<4)
#define PMC_SYSTEM_BUS_MMIO_ERROR (1<<3)
#define PMC_IOA_PROCESSOR_IN_ERROR_STATE (1<<2)
#define PMC_HOST_RRQ_VALID (1<<1)
#define PMC_OPERATIONAL_STATUS (1<<31)
#define PMC_ALLOW_MSIX_VECTOR0 (1<<0)
#define PMC_IOA_ERROR_INTERRUPTS (PMC_IOARCB_TRANSFER_FAILED | \
PMC_IOA_UNIT_CHECK | \
PMC_NO_HOST_RRQ_FOR_CMD_RESPONSE | \
PMC_IOARRIN_LOST | \
PMC_SYSTEM_BUS_MMIO_ERROR | \
PMC_IOA_PROCESSOR_IN_ERROR_STATE)
#define PMC_ALL_INTERRUPT_BITS (PMC_IOA_ERROR_INTERRUPTS | \
PMC_HOST_RRQ_VALID | \
PMC_TRANSITION_TO_OPERATIONAL | \
PMC_ALLOW_MSIX_VECTOR0)
#define PMC_GLOBAL_INT_BIT2 0x00000004
#define PMC_GLOBAL_INT_BIT0 0x00000001
#ifndef AAC_DRIVER_BUILD #ifndef AAC_DRIVER_BUILD
# define AAC_DRIVER_BUILD 30300 # define AAC_DRIVER_BUILD 30300
# define AAC_DRIVER_BRANCH "-ms" # define AAC_DRIVER_BRANCH "-ms"
...@@ -36,6 +86,7 @@ ...@@ -36,6 +86,7 @@
#define CONTAINER_TO_ID(cont) (cont) #define CONTAINER_TO_ID(cont) (cont)
#define CONTAINER_TO_LUN(cont) (0) #define CONTAINER_TO_LUN(cont) (0)
#define PMC_DEVICE_S6 0x28b
#define PMC_DEVICE_S7 0x28c #define PMC_DEVICE_S7 0x28c
#define PMC_DEVICE_S8 0x28d #define PMC_DEVICE_S8 0x28d
#define PMC_DEVICE_S9 0x28f #define PMC_DEVICE_S9 0x28f
...@@ -434,7 +485,7 @@ enum fib_xfer_state { ...@@ -434,7 +485,7 @@ enum fib_xfer_state {
struct aac_init struct aac_init
{ {
__le32 InitStructRevision; __le32 InitStructRevision;
__le32 MiniPortRevision; __le32 Sa_MSIXVectors;
__le32 fsrev; __le32 fsrev;
__le32 CommHeaderAddress; __le32 CommHeaderAddress;
__le32 FastIoCommAreaAddress; __le32 FastIoCommAreaAddress;
...@@ -755,7 +806,8 @@ struct rkt_registers { ...@@ -755,7 +806,8 @@ struct rkt_registers {
struct src_mu_registers { struct src_mu_registers {
/* PCI*| Name */ /* PCI*| Name */
__le32 reserved0[8]; /* 00h | Reserved */ __le32 reserved0[6]; /* 00h | Reserved */
__le32 IOAR[2]; /* 18h | IOA->host interrupt register */
__le32 IDR; /* 20h | Inbound Doorbell Register */ __le32 IDR; /* 20h | Inbound Doorbell Register */
__le32 IISR; /* 24h | Inbound Int. Status Register */ __le32 IISR; /* 24h | Inbound Int. Status Register */
__le32 reserved1[3]; /* 28h | Reserved */ __le32 reserved1[3]; /* 28h | Reserved */
...@@ -767,17 +819,18 @@ struct src_mu_registers { ...@@ -767,17 +819,18 @@ struct src_mu_registers {
__le32 OMR; /* bch | Outbound Message Register */ __le32 OMR; /* bch | Outbound Message Register */
__le32 IQ_L; /* c0h | Inbound Queue (Low address) */ __le32 IQ_L; /* c0h | Inbound Queue (Low address) */
__le32 IQ_H; /* c4h | Inbound Queue (High address) */ __le32 IQ_H; /* c4h | Inbound Queue (High address) */
__le32 ODR_MSI; /* c8h | MSI register for sync./AIF */
}; };
struct src_registers { struct src_registers {
struct src_mu_registers MUnit; /* 00h - c7h */ struct src_mu_registers MUnit; /* 00h - cbh */
union { union {
struct { struct {
__le32 reserved1[130790]; /* c8h - 7fc5fh */ __le32 reserved1[130789]; /* cch - 7fc5fh */
struct src_inbound IndexRegs; /* 7fc60h */ struct src_inbound IndexRegs; /* 7fc60h */
} tupelo; } tupelo;
struct { struct {
__le32 reserved1[974]; /* c8h - fffh */ __le32 reserved1[973]; /* cch - fffh */
struct src_inbound IndexRegs; /* 1000h */ struct src_inbound IndexRegs; /* 1000h */
} denali; } denali;
} u; } u;
...@@ -1029,6 +1082,11 @@ struct aac_bus_info_response { ...@@ -1029,6 +1082,11 @@ struct aac_bus_info_response {
#define AAC_OPT_NEW_COMM_TYPE3 cpu_to_le32(1<<30) #define AAC_OPT_NEW_COMM_TYPE3 cpu_to_le32(1<<30)
#define AAC_OPT_NEW_COMM_TYPE4 cpu_to_le32(1<<31) #define AAC_OPT_NEW_COMM_TYPE4 cpu_to_le32(1<<31)
/* MSIX context */
struct aac_msix_ctx {
int vector_no;
struct aac_dev *dev;
};
struct aac_dev struct aac_dev
{ {
...@@ -1084,8 +1142,10 @@ struct aac_dev ...@@ -1084,8 +1142,10 @@ struct aac_dev
* if AAC_COMM_MESSAGE_TYPE1 */ * if AAC_COMM_MESSAGE_TYPE1 */
dma_addr_t host_rrq_pa; /* phys. address */ dma_addr_t host_rrq_pa; /* phys. address */
u32 host_rrq_idx; /* index into rrq buffer */ /* index into rrq buffer */
u32 host_rrq_idx[AAC_MAX_MSIX];
atomic_t rrq_outstanding[AAC_MAX_MSIX];
u32 fibs_pushed_no;
struct pci_dev *pdev; /* Our PCI interface */ struct pci_dev *pdev; /* Our PCI interface */
void * printfbuf; /* pointer to buffer used for printf's from the adapter */ void * printfbuf; /* pointer to buffer used for printf's from the adapter */
void * comm_addr; /* Base address of Comm area */ void * comm_addr; /* Base address of Comm area */
...@@ -1154,6 +1214,11 @@ struct aac_dev ...@@ -1154,6 +1214,11 @@ struct aac_dev
int sync_mode; int sync_mode;
struct fib *sync_fib; struct fib *sync_fib;
struct list_head sync_fib_list; struct list_head sync_fib_list;
u32 max_msix; /* max. MSI-X vectors */
u32 vector_cap; /* MSI-X vector capab.*/
int msi_enabled; /* MSI/MSI-X enabled */
struct msix_entry msixentry[AAC_MAX_MSIX];
struct aac_msix_ctx aac_msix[AAC_MAX_MSIX]; /* context */
}; };
#define aac_adapter_interrupt(dev) \ #define aac_adapter_interrupt(dev) \
...@@ -2036,6 +2101,7 @@ void aac_consumer_free(struct aac_dev * dev, struct aac_queue * q, u32 qnum); ...@@ -2036,6 +2101,7 @@ void aac_consumer_free(struct aac_dev * dev, struct aac_queue * q, u32 qnum);
int aac_fib_complete(struct fib * context); int aac_fib_complete(struct fib * context);
#define fib_data(fibctx) ((void *)(fibctx)->hw_fib_va->data) #define fib_data(fibctx) ((void *)(fibctx)->hw_fib_va->data)
struct aac_dev *aac_init_adapter(struct aac_dev *dev); struct aac_dev *aac_init_adapter(struct aac_dev *dev);
void aac_src_access_devreg(struct aac_dev *dev, int mode);
int aac_get_config_status(struct aac_dev *dev, int commit_flag); int aac_get_config_status(struct aac_dev *dev, int commit_flag);
int aac_get_containers(struct aac_dev *dev); int aac_get_containers(struct aac_dev *dev);
int aac_scsi_cmd(struct scsi_cmnd *cmd); int aac_scsi_cmd(struct scsi_cmnd *cmd);
......
...@@ -43,6 +43,8 @@ ...@@ -43,6 +43,8 @@
#include "aacraid.h" #include "aacraid.h"
static void aac_define_int_mode(struct aac_dev *dev);
struct aac_common aac_config = { struct aac_common aac_config = {
.irq_mod = 1 .irq_mod = 1
}; };
...@@ -91,7 +93,7 @@ static int aac_alloc_comm(struct aac_dev *dev, void **commaddr, unsigned long co ...@@ -91,7 +93,7 @@ static int aac_alloc_comm(struct aac_dev *dev, void **commaddr, unsigned long co
init->InitStructRevision = cpu_to_le32(ADAPTER_INIT_STRUCT_REVISION); init->InitStructRevision = cpu_to_le32(ADAPTER_INIT_STRUCT_REVISION);
if (dev->max_fib_size != sizeof(struct hw_fib)) if (dev->max_fib_size != sizeof(struct hw_fib))
init->InitStructRevision = cpu_to_le32(ADAPTER_INIT_STRUCT_REVISION_4); init->InitStructRevision = cpu_to_le32(ADAPTER_INIT_STRUCT_REVISION_4);
init->MiniPortRevision = cpu_to_le32(Sa_MINIPORT_REVISION); init->Sa_MSIXVectors = cpu_to_le32(Sa_MINIPORT_REVISION);
init->fsrev = cpu_to_le32(dev->fsrev); init->fsrev = cpu_to_le32(dev->fsrev);
/* /*
...@@ -140,7 +142,8 @@ static int aac_alloc_comm(struct aac_dev *dev, void **commaddr, unsigned long co ...@@ -140,7 +142,8 @@ static int aac_alloc_comm(struct aac_dev *dev, void **commaddr, unsigned long co
INITFLAGS_NEW_COMM_TYPE2_SUPPORTED | INITFLAGS_FAST_JBOD_SUPPORTED); INITFLAGS_NEW_COMM_TYPE2_SUPPORTED | INITFLAGS_FAST_JBOD_SUPPORTED);
init->HostRRQ_AddrHigh = cpu_to_le32((u32)((u64)dev->host_rrq_pa >> 32)); init->HostRRQ_AddrHigh = cpu_to_le32((u32)((u64)dev->host_rrq_pa >> 32));
init->HostRRQ_AddrLow = cpu_to_le32((u32)(dev->host_rrq_pa & 0xffffffff)); init->HostRRQ_AddrLow = cpu_to_le32((u32)(dev->host_rrq_pa & 0xffffffff));
init->MiniPortRevision = cpu_to_le32(0L); /* number of MSI-X */ /* number of MSI-X */
init->Sa_MSIXVectors = cpu_to_le32(dev->max_msix);
dprintk((KERN_WARNING"aacraid: New Comm Interface type2 enabled\n")); dprintk((KERN_WARNING"aacraid: New Comm Interface type2 enabled\n"));
} }
...@@ -228,6 +231,11 @@ int aac_send_shutdown(struct aac_dev * dev) ...@@ -228,6 +231,11 @@ int aac_send_shutdown(struct aac_dev * dev)
/* FIB should be freed only after getting the response from the F/W */ /* FIB should be freed only after getting the response from the F/W */
if (status != -ERESTARTSYS) if (status != -ERESTARTSYS)
aac_fib_free(fibctx); aac_fib_free(fibctx);
if ((dev->pdev->device == PMC_DEVICE_S7 ||
dev->pdev->device == PMC_DEVICE_S8 ||
dev->pdev->device == PMC_DEVICE_S9) &&
dev->msi_enabled)
aac_src_access_devreg(dev, AAC_ENABLE_INTX);
return status; return status;
} }
...@@ -388,6 +396,8 @@ struct aac_dev *aac_init_adapter(struct aac_dev *dev) ...@@ -388,6 +396,8 @@ struct aac_dev *aac_init_adapter(struct aac_dev *dev)
} }
} }
} }
dev->max_msix = 0;
dev->msi_enabled = 0;
if ((!aac_adapter_sync_cmd(dev, GET_COMM_PREFERRED_SETTINGS, if ((!aac_adapter_sync_cmd(dev, GET_COMM_PREFERRED_SETTINGS,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
status+0, status+1, status+2, status+3, status+4)) status+0, status+1, status+2, status+3, status+4))
...@@ -461,6 +471,11 @@ struct aac_dev *aac_init_adapter(struct aac_dev *dev) ...@@ -461,6 +471,11 @@ struct aac_dev *aac_init_adapter(struct aac_dev *dev)
if (host->can_queue > AAC_NUM_IO_FIB) if (host->can_queue > AAC_NUM_IO_FIB)
host->can_queue = AAC_NUM_IO_FIB; host->can_queue = AAC_NUM_IO_FIB;
if (dev->pdev->device == PMC_DEVICE_S6 ||
dev->pdev->device == PMC_DEVICE_S7 ||
dev->pdev->device == PMC_DEVICE_S8 ||
dev->pdev->device == PMC_DEVICE_S9)
aac_define_int_mode(dev);
/* /*
* Ok now init the communication subsystem * Ok now init the communication subsystem
*/ */
...@@ -489,4 +504,78 @@ struct aac_dev *aac_init_adapter(struct aac_dev *dev) ...@@ -489,4 +504,78 @@ struct aac_dev *aac_init_adapter(struct aac_dev *dev)
return dev; return dev;
} }
static void aac_define_int_mode(struct aac_dev *dev)
{
int i, msi_count;
/* max. vectors from GET_COMM_PREFERRED_SETTINGS */
if (dev->max_msix == 0 ||
dev->pdev->device == PMC_DEVICE_S6 ||
dev->sync_mode) {
dev->max_msix = 1;
dev->vector_cap =
dev->scsi_host_ptr->can_queue +
AAC_NUM_MGT_FIB;
return;
}
msi_count = min(dev->max_msix,
(unsigned int)num_online_cpus());
dev->max_msix = msi_count;
if (msi_count > AAC_MAX_MSIX)
msi_count = AAC_MAX_MSIX;
for (i = 0; i < msi_count; i++)
dev->msixentry[i].entry = i;
if (msi_count > 1 &&
pci_find_capability(dev->pdev, PCI_CAP_ID_MSIX)) {
i = pci_enable_msix(dev->pdev,
dev->msixentry,
msi_count);
/* Check how many MSIX vectors are allocated */
if (i >= 0) {
dev->msi_enabled = 1;
if (i) {
msi_count = i;
if (pci_enable_msix(dev->pdev,
dev->msixentry,
msi_count)) {
dev->msi_enabled = 0;
printk(KERN_ERR "%s%d: MSIX not supported!! Will try MSI 0x%x.\n",
dev->name, dev->id, i);
}
}
} else {
dev->msi_enabled = 0;
printk(KERN_ERR "%s%d: MSIX not supported!! Will try MSI 0x%x.\n",
dev->name, dev->id, i);
}
}
if (!dev->msi_enabled) {
msi_count = 1;
i = pci_enable_msi(dev->pdev);
if (!i) {
dev->msi_enabled = 1;
dev->msi = 1;
} else {
printk(KERN_ERR "%s%d: MSI not supported!! Will try INTx 0x%x.\n",
dev->name, dev->id, i);
}
}
if (!dev->msi_enabled)
dev->max_msix = msi_count = 1;
else {
if (dev->max_msix > msi_count)
dev->max_msix = msi_count;
}
dev->vector_cap =
(dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB) /
msi_count;
}
...@@ -868,7 +868,7 @@ void aac_printf(struct aac_dev *dev, u32 val) ...@@ -868,7 +868,7 @@ void aac_printf(struct aac_dev *dev, u32 val)
* dispatches it to the appropriate routine for handling. * dispatches it to the appropriate routine for handling.
*/ */
#define AIF_SNIFF_TIMEOUT (30*HZ) #define AIF_SNIFF_TIMEOUT (500*HZ)
static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr) static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
{ {
struct hw_fib * hw_fib = fibptr->hw_fib_va; struct hw_fib * hw_fib = fibptr->hw_fib_va;
...@@ -1251,7 +1251,7 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr) ...@@ -1251,7 +1251,7 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
static int _aac_reset_adapter(struct aac_dev *aac, int forced) static int _aac_reset_adapter(struct aac_dev *aac, int forced)
{ {
int index, quirks; int index, quirks;
int retval; int retval, i;
struct Scsi_Host *host; struct Scsi_Host *host;
struct scsi_device *dev; struct scsi_device *dev;
struct scsi_cmnd *command; struct scsi_cmnd *command;
...@@ -1319,7 +1319,21 @@ static int _aac_reset_adapter(struct aac_dev *aac, int forced) ...@@ -1319,7 +1319,21 @@ static int _aac_reset_adapter(struct aac_dev *aac, int forced)
aac->comm_phys = 0; aac->comm_phys = 0;
kfree(aac->queues); kfree(aac->queues);
aac->queues = NULL; aac->queues = NULL;
free_irq(aac->pdev->irq, aac); if (aac->pdev->device == PMC_DEVICE_S6 ||
aac->pdev->device == PMC_DEVICE_S7 ||
aac->pdev->device == PMC_DEVICE_S8 ||
aac->pdev->device == PMC_DEVICE_S9) {
if (aac->max_msix > 1) {
for (i = 0; i < aac->max_msix; i++)
free_irq(aac->msixentry[i].vector,
&(aac->aac_msix[i]));
pci_disable_msix(aac->pdev);
} else {
free_irq(aac->pdev->irq, &(aac->aac_msix[0]));
}
} else {
free_irq(aac->pdev->irq, aac);
}
if (aac->msi) if (aac->msi)
pci_disable_msi(aac->pdev); pci_disable_msi(aac->pdev);
kfree(aac->fsa_dev); kfree(aac->fsa_dev);
......
...@@ -389,8 +389,13 @@ unsigned int aac_intr_normal(struct aac_dev *dev, u32 index, ...@@ -389,8 +389,13 @@ unsigned int aac_intr_normal(struct aac_dev *dev, u32 index,
* NOTE: we cannot touch the fib after this * NOTE: we cannot touch the fib after this
* call, because it may have been deallocated. * call, because it may have been deallocated.
*/ */
fib->flags &= FIB_CONTEXT_FLAG_FASTRESP; if (likely(fib->callback && fib->callback_data)) {
fib->callback(fib->callback_data, fib); fib->flags &= FIB_CONTEXT_FLAG_FASTRESP;
fib->callback(fib->callback_data, fib);
} else {
aac_fib_complete(fib);
aac_fib_free(fib);
}
} else { } else {
unsigned long flagv; unsigned long flagv;
dprintk((KERN_INFO "event_wait up\n")); dprintk((KERN_INFO "event_wait up\n"));
......
...@@ -1082,6 +1082,8 @@ static struct scsi_host_template aac_driver_template = { ...@@ -1082,6 +1082,8 @@ static struct scsi_host_template aac_driver_template = {
static void __aac_shutdown(struct aac_dev * aac) static void __aac_shutdown(struct aac_dev * aac)
{ {
int i;
if (aac->aif_thread) { if (aac->aif_thread) {
int i; int i;
/* Clear out events first */ /* Clear out events first */
...@@ -1095,9 +1097,25 @@ static void __aac_shutdown(struct aac_dev * aac) ...@@ -1095,9 +1097,25 @@ static void __aac_shutdown(struct aac_dev * aac)
} }
aac_send_shutdown(aac); aac_send_shutdown(aac);
aac_adapter_disable_int(aac); aac_adapter_disable_int(aac);
free_irq(aac->pdev->irq, aac); if (aac->pdev->device == PMC_DEVICE_S6 ||
aac->pdev->device == PMC_DEVICE_S7 ||
aac->pdev->device == PMC_DEVICE_S8 ||
aac->pdev->device == PMC_DEVICE_S9) {
if (aac->max_msix > 1) {
for (i = 0; i < aac->max_msix; i++)
free_irq(aac->msixentry[i].vector,
&(aac->aac_msix[i]));
} else {
free_irq(aac->pdev->irq,
&(aac->aac_msix[0]));
}
} else {
free_irq(aac->pdev->irq, aac);
}
if (aac->msi) if (aac->msi)
pci_disable_msi(aac->pdev); pci_disable_msi(aac->pdev);
else if (aac->max_msix > 1)
pci_disable_msix(aac->pdev);
} }
static int aac_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) static int aac_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment