aacraid: MSI-x support
Signed-off-by: Mahesh Rajashekhara <Mahesh.Rajashekhara@pmcs.com> Reviewed-by: Hannes Reinecke <hare@suse.de> Reviewed-by: Murthy Bhat <Murthy.Bhat@pmcs.com> Signed-off-by: James Bottomley <JBottomley@Odin.com>
This commit is contained in:
parent
b836439faf
commit
495c021767
@ -6,11 +6,61 @@
|
||||
#define nblank(x) _nblank(x)[0]
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* 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
|
||||
# define AAC_DRIVER_BUILD 30300
|
||||
# define AAC_DRIVER_BRANCH "-ms"
|
||||
@ -36,6 +86,7 @@
|
||||
#define CONTAINER_TO_ID(cont) (cont)
|
||||
#define CONTAINER_TO_LUN(cont) (0)
|
||||
|
||||
#define PMC_DEVICE_S6 0x28b
|
||||
#define PMC_DEVICE_S7 0x28c
|
||||
#define PMC_DEVICE_S8 0x28d
|
||||
#define PMC_DEVICE_S9 0x28f
|
||||
@ -434,7 +485,7 @@ enum fib_xfer_state {
|
||||
struct aac_init
|
||||
{
|
||||
__le32 InitStructRevision;
|
||||
__le32 MiniPortRevision;
|
||||
__le32 Sa_MSIXVectors;
|
||||
__le32 fsrev;
|
||||
__le32 CommHeaderAddress;
|
||||
__le32 FastIoCommAreaAddress;
|
||||
@ -755,7 +806,8 @@ struct rkt_registers {
|
||||
|
||||
struct src_mu_registers {
|
||||
/* 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 IISR; /* 24h | Inbound Int. Status Register */
|
||||
__le32 reserved1[3]; /* 28h | Reserved */
|
||||
@ -767,17 +819,18 @@ struct src_mu_registers {
|
||||
__le32 OMR; /* bch | Outbound Message Register */
|
||||
__le32 IQ_L; /* c0h | Inbound Queue (Low address) */
|
||||
__le32 IQ_H; /* c4h | Inbound Queue (High address) */
|
||||
__le32 ODR_MSI; /* c8h | MSI register for sync./AIF */
|
||||
};
|
||||
|
||||
struct src_registers {
|
||||
struct src_mu_registers MUnit; /* 00h - c7h */
|
||||
struct src_mu_registers MUnit; /* 00h - cbh */
|
||||
union {
|
||||
struct {
|
||||
__le32 reserved1[130790]; /* c8h - 7fc5fh */
|
||||
__le32 reserved1[130789]; /* cch - 7fc5fh */
|
||||
struct src_inbound IndexRegs; /* 7fc60h */
|
||||
} tupelo;
|
||||
struct {
|
||||
__le32 reserved1[974]; /* c8h - fffh */
|
||||
__le32 reserved1[973]; /* cch - fffh */
|
||||
struct src_inbound IndexRegs; /* 1000h */
|
||||
} denali;
|
||||
} u;
|
||||
@ -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_TYPE4 cpu_to_le32(1<<31)
|
||||
|
||||
/* MSIX context */
|
||||
struct aac_msix_ctx {
|
||||
int vector_no;
|
||||
struct aac_dev *dev;
|
||||
};
|
||||
|
||||
struct aac_dev
|
||||
{
|
||||
@ -1084,8 +1142,10 @@ struct aac_dev
|
||||
* if AAC_COMM_MESSAGE_TYPE1 */
|
||||
|
||||
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 */
|
||||
void * printfbuf; /* pointer to buffer used for printf's from the adapter */
|
||||
void * comm_addr; /* Base address of Comm area */
|
||||
@ -1154,6 +1214,11 @@ struct aac_dev
|
||||
int sync_mode;
|
||||
struct fib *sync_fib;
|
||||
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) \
|
||||
@ -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);
|
||||
#define fib_data(fibctx) ((void *)(fibctx)->hw_fib_va->data)
|
||||
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_containers(struct aac_dev *dev);
|
||||
int aac_scsi_cmd(struct scsi_cmnd *cmd);
|
||||
|
@ -43,6 +43,8 @@
|
||||
|
||||
#include "aacraid.h"
|
||||
|
||||
static void aac_define_int_mode(struct aac_dev *dev);
|
||||
|
||||
struct aac_common aac_config = {
|
||||
.irq_mod = 1
|
||||
};
|
||||
@ -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);
|
||||
if (dev->max_fib_size != sizeof(struct hw_fib))
|
||||
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);
|
||||
|
||||
/*
|
||||
@ -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);
|
||||
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->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"));
|
||||
}
|
||||
|
||||
@ -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 */
|
||||
if (status != -ERESTARTSYS)
|
||||
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;
|
||||
}
|
||||
|
||||
@ -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,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
status+0, status+1, status+2, status+3, status+4))
|
||||
@ -461,6 +471,11 @@ struct aac_dev *aac_init_adapter(struct aac_dev *dev)
|
||||
if (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
|
||||
*/
|
||||
@ -489,4 +504,78 @@ struct aac_dev *aac_init_adapter(struct aac_dev *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)
|
||||
* 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)
|
||||
{
|
||||
struct hw_fib * hw_fib = fibptr->hw_fib_va;
|
||||
@ -1251,7 +1251,7 @@ retry_next:
|
||||
static int _aac_reset_adapter(struct aac_dev *aac, int forced)
|
||||
{
|
||||
int index, quirks;
|
||||
int retval;
|
||||
int retval, i;
|
||||
struct Scsi_Host *host;
|
||||
struct scsi_device *dev;
|
||||
struct scsi_cmnd *command;
|
||||
@ -1319,7 +1319,21 @@ static int _aac_reset_adapter(struct aac_dev *aac, int forced)
|
||||
aac->comm_phys = 0;
|
||||
kfree(aac->queues);
|
||||
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)
|
||||
pci_disable_msi(aac->pdev);
|
||||
kfree(aac->fsa_dev);
|
||||
|
@ -389,8 +389,13 @@ unsigned int aac_intr_normal(struct aac_dev *dev, u32 index,
|
||||
* NOTE: we cannot touch the fib after this
|
||||
* call, because it may have been deallocated.
|
||||
*/
|
||||
fib->flags &= FIB_CONTEXT_FLAG_FASTRESP;
|
||||
fib->callback(fib->callback_data, fib);
|
||||
if (likely(fib->callback && fib->callback_data)) {
|
||||
fib->flags &= FIB_CONTEXT_FLAG_FASTRESP;
|
||||
fib->callback(fib->callback_data, fib);
|
||||
} else {
|
||||
aac_fib_complete(fib);
|
||||
aac_fib_free(fib);
|
||||
}
|
||||
} else {
|
||||
unsigned long flagv;
|
||||
dprintk((KERN_INFO "event_wait up\n"));
|
||||
|
@ -1082,6 +1082,8 @@ static struct scsi_host_template aac_driver_template = {
|
||||
|
||||
static void __aac_shutdown(struct aac_dev * aac)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (aac->aif_thread) {
|
||||
int i;
|
||||
/* Clear out events first */
|
||||
@ -1095,9 +1097,25 @@ static void __aac_shutdown(struct aac_dev * aac)
|
||||
}
|
||||
aac_send_shutdown(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)
|
||||
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)
|
||||
|
@ -44,98 +44,128 @@
|
||||
|
||||
#include "aacraid.h"
|
||||
|
||||
static irqreturn_t aac_src_intr_message(int irq, void *dev_id)
|
||||
static int aac_src_get_sync_status(struct aac_dev *dev);
|
||||
|
||||
irqreturn_t aac_src_intr_message(int irq, void *dev_id)
|
||||
{
|
||||
struct aac_dev *dev = dev_id;
|
||||
struct aac_msix_ctx *ctx;
|
||||
struct aac_dev *dev;
|
||||
unsigned long bellbits, bellbits_shifted;
|
||||
int our_interrupt = 0;
|
||||
int isFastResponse;
|
||||
int vector_no;
|
||||
int isFastResponse, mode;
|
||||
u32 index, handle;
|
||||
|
||||
bellbits = src_readl(dev, MUnit.ODR_R);
|
||||
if (bellbits & PmDoorBellResponseSent) {
|
||||
bellbits = PmDoorBellResponseSent;
|
||||
/* handle async. status */
|
||||
src_writel(dev, MUnit.ODR_C, bellbits);
|
||||
src_readl(dev, MUnit.ODR_C);
|
||||
our_interrupt = 1;
|
||||
index = dev->host_rrq_idx;
|
||||
ctx = (struct aac_msix_ctx *)dev_id;
|
||||
dev = ctx->dev;
|
||||
vector_no = ctx->vector_no;
|
||||
|
||||
if (dev->msi_enabled) {
|
||||
mode = AAC_INT_MODE_MSI;
|
||||
if (vector_no == 0) {
|
||||
bellbits = src_readl(dev, MUnit.ODR_MSI);
|
||||
if (bellbits & 0x40000)
|
||||
mode |= AAC_INT_MODE_AIF;
|
||||
if (bellbits & 0x1000)
|
||||
mode |= AAC_INT_MODE_SYNC;
|
||||
}
|
||||
} else {
|
||||
mode = AAC_INT_MODE_INTX;
|
||||
bellbits = src_readl(dev, MUnit.ODR_R);
|
||||
if (bellbits & PmDoorBellResponseSent) {
|
||||
bellbits = PmDoorBellResponseSent;
|
||||
src_writel(dev, MUnit.ODR_C, bellbits);
|
||||
src_readl(dev, MUnit.ODR_C);
|
||||
} else {
|
||||
bellbits_shifted = (bellbits >> SRC_ODR_SHIFT);
|
||||
src_writel(dev, MUnit.ODR_C, bellbits);
|
||||
src_readl(dev, MUnit.ODR_C);
|
||||
|
||||
if (bellbits_shifted & DoorBellAifPending)
|
||||
mode |= AAC_INT_MODE_AIF;
|
||||
else if (bellbits_shifted & OUTBOUNDDOORBELL_0)
|
||||
mode |= AAC_INT_MODE_SYNC;
|
||||
}
|
||||
}
|
||||
|
||||
if (mode & AAC_INT_MODE_SYNC) {
|
||||
unsigned long sflags;
|
||||
struct list_head *entry;
|
||||
int send_it = 0;
|
||||
extern int aac_sync_mode;
|
||||
|
||||
if (!aac_sync_mode && !dev->msi_enabled) {
|
||||
src_writel(dev, MUnit.ODR_C, bellbits);
|
||||
src_readl(dev, MUnit.ODR_C);
|
||||
}
|
||||
|
||||
if (dev->sync_fib) {
|
||||
if (dev->sync_fib->callback)
|
||||
dev->sync_fib->callback(dev->sync_fib->callback_data,
|
||||
dev->sync_fib);
|
||||
spin_lock_irqsave(&dev->sync_fib->event_lock, sflags);
|
||||
if (dev->sync_fib->flags & FIB_CONTEXT_FLAG_WAIT) {
|
||||
dev->management_fib_count--;
|
||||
up(&dev->sync_fib->event_wait);
|
||||
}
|
||||
spin_unlock_irqrestore(&dev->sync_fib->event_lock,
|
||||
sflags);
|
||||
spin_lock_irqsave(&dev->sync_lock, sflags);
|
||||
if (!list_empty(&dev->sync_fib_list)) {
|
||||
entry = dev->sync_fib_list.next;
|
||||
dev->sync_fib = list_entry(entry,
|
||||
struct fib,
|
||||
fiblink);
|
||||
list_del(entry);
|
||||
send_it = 1;
|
||||
} else {
|
||||
dev->sync_fib = NULL;
|
||||
}
|
||||
spin_unlock_irqrestore(&dev->sync_lock, sflags);
|
||||
if (send_it) {
|
||||
aac_adapter_sync_cmd(dev, SEND_SYNCHRONOUS_FIB,
|
||||
(u32)dev->sync_fib->hw_fib_pa,
|
||||
0, 0, 0, 0, 0,
|
||||
NULL, NULL, NULL, NULL, NULL);
|
||||
}
|
||||
}
|
||||
if (!dev->msi_enabled)
|
||||
mode = 0;
|
||||
|
||||
}
|
||||
|
||||
if (mode & AAC_INT_MODE_AIF) {
|
||||
/* handle AIF */
|
||||
aac_intr_normal(dev, 0, 2, 0, NULL);
|
||||
if (dev->msi_enabled)
|
||||
aac_src_access_devreg(dev, AAC_CLEAR_AIF_BIT);
|
||||
mode = 0;
|
||||
}
|
||||
|
||||
if (mode) {
|
||||
index = dev->host_rrq_idx[vector_no];
|
||||
|
||||
for (;;) {
|
||||
isFastResponse = 0;
|
||||
/* remove toggle bit (31) */
|
||||
handle = le32_to_cpu(dev->host_rrq[index]) & 0x7fffffff;
|
||||
handle = (dev->host_rrq[index] & 0x7fffffff);
|
||||
/* check fast response bit (30) */
|
||||
if (handle & 0x40000000)
|
||||
isFastResponse = 1;
|
||||
handle &= 0x0000ffff;
|
||||
if (handle == 0)
|
||||
break;
|
||||
|
||||
if (dev->msi_enabled && dev->max_msix > 1)
|
||||
atomic_dec(&dev->rrq_outstanding[vector_no]);
|
||||
aac_intr_normal(dev, handle-1, 0, isFastResponse, NULL);
|
||||
|
||||
dev->host_rrq[index++] = 0;
|
||||
if (index == dev->scsi_host_ptr->can_queue +
|
||||
AAC_NUM_MGT_FIB)
|
||||
index = 0;
|
||||
dev->host_rrq_idx = index;
|
||||
}
|
||||
} else {
|
||||
bellbits_shifted = (bellbits >> SRC_ODR_SHIFT);
|
||||
if (bellbits_shifted & DoorBellAifPending) {
|
||||
src_writel(dev, MUnit.ODR_C, bellbits);
|
||||
src_readl(dev, MUnit.ODR_C);
|
||||
our_interrupt = 1;
|
||||
/* handle AIF */
|
||||
aac_intr_normal(dev, 0, 2, 0, NULL);
|
||||
} else if (bellbits_shifted & OUTBOUNDDOORBELL_0) {
|
||||
unsigned long sflags;
|
||||
struct list_head *entry;
|
||||
int send_it = 0;
|
||||
extern int aac_sync_mode;
|
||||
|
||||
src_writel(dev, MUnit.ODR_C, bellbits);
|
||||
src_readl(dev, MUnit.ODR_C);
|
||||
|
||||
if (!aac_sync_mode) {
|
||||
src_writel(dev, MUnit.ODR_C, bellbits);
|
||||
src_readl(dev, MUnit.ODR_C);
|
||||
our_interrupt = 1;
|
||||
}
|
||||
|
||||
if (dev->sync_fib) {
|
||||
our_interrupt = 1;
|
||||
if (dev->sync_fib->callback)
|
||||
dev->sync_fib->callback(dev->sync_fib->callback_data,
|
||||
dev->sync_fib);
|
||||
spin_lock_irqsave(&dev->sync_fib->event_lock, sflags);
|
||||
if (dev->sync_fib->flags & FIB_CONTEXT_FLAG_WAIT) {
|
||||
dev->management_fib_count--;
|
||||
up(&dev->sync_fib->event_wait);
|
||||
}
|
||||
spin_unlock_irqrestore(&dev->sync_fib->event_lock, sflags);
|
||||
spin_lock_irqsave(&dev->sync_lock, sflags);
|
||||
if (!list_empty(&dev->sync_fib_list)) {
|
||||
entry = dev->sync_fib_list.next;
|
||||
dev->sync_fib = list_entry(entry, struct fib, fiblink);
|
||||
list_del(entry);
|
||||
send_it = 1;
|
||||
} else {
|
||||
dev->sync_fib = NULL;
|
||||
}
|
||||
spin_unlock_irqrestore(&dev->sync_lock, sflags);
|
||||
if (send_it) {
|
||||
aac_adapter_sync_cmd(dev, SEND_SYNCHRONOUS_FIB,
|
||||
(u32)dev->sync_fib->hw_fib_pa, 0, 0, 0, 0, 0,
|
||||
NULL, NULL, NULL, NULL, NULL);
|
||||
}
|
||||
}
|
||||
if (index == (vector_no + 1) * dev->vector_cap)
|
||||
index = vector_no * dev->vector_cap;
|
||||
dev->host_rrq_idx[vector_no] = index;
|
||||
}
|
||||
mode = 0;
|
||||
}
|
||||
|
||||
if (our_interrupt) {
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
return IRQ_NONE;
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -155,7 +185,7 @@ static void aac_src_disable_interrupt(struct aac_dev *dev)
|
||||
|
||||
static void aac_src_enable_interrupt_message(struct aac_dev *dev)
|
||||
{
|
||||
src_writel(dev, MUnit.OIMR, dev->OIMR = 0xfffffff8);
|
||||
aac_src_access_devreg(dev, AAC_ENABLE_INTERRUPT);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -191,7 +221,10 @@ static int src_sync_cmd(struct aac_dev *dev, u32 command,
|
||||
/*
|
||||
* Clear the synch command doorbell to start on a clean slate.
|
||||
*/
|
||||
src_writel(dev, MUnit.ODR_C, OUTBOUNDDOORBELL_0 << SRC_ODR_SHIFT);
|
||||
if (!dev->msi_enabled)
|
||||
src_writel(dev,
|
||||
MUnit.ODR_C,
|
||||
OUTBOUNDDOORBELL_0 << SRC_ODR_SHIFT);
|
||||
|
||||
/*
|
||||
* Disable doorbell interrupts
|
||||
@ -221,11 +254,17 @@ static int src_sync_cmd(struct aac_dev *dev, u32 command,
|
||||
/*
|
||||
* Mon960 will set doorbell0 bit when it has completed the command.
|
||||
*/
|
||||
if ((src_readl(dev, MUnit.ODR_R) >> SRC_ODR_SHIFT) & OUTBOUNDDOORBELL_0) {
|
||||
if (aac_src_get_sync_status(dev) & OUTBOUNDDOORBELL_0) {
|
||||
/*
|
||||
* Clear the doorbell.
|
||||
*/
|
||||
src_writel(dev, MUnit.ODR_C, OUTBOUNDDOORBELL_0 << SRC_ODR_SHIFT);
|
||||
if (dev->msi_enabled)
|
||||
aac_src_access_devreg(dev,
|
||||
AAC_CLEAR_SYNC_BIT);
|
||||
else
|
||||
src_writel(dev,
|
||||
MUnit.ODR_C,
|
||||
OUTBOUNDDOORBELL_0 << SRC_ODR_SHIFT);
|
||||
ok = 1;
|
||||
break;
|
||||
}
|
||||
@ -254,11 +293,16 @@ static int src_sync_cmd(struct aac_dev *dev, u32 command,
|
||||
*r3 = readl(&dev->IndexRegs->Mailbox[3]);
|
||||
if (r4)
|
||||
*r4 = readl(&dev->IndexRegs->Mailbox[4]);
|
||||
|
||||
if (command == GET_COMM_PREFERRED_SETTINGS)
|
||||
dev->max_msix =
|
||||
readl(&dev->IndexRegs->Mailbox[5]) & 0xFFFF;
|
||||
/*
|
||||
* Clear the synch command doorbell.
|
||||
*/
|
||||
src_writel(dev, MUnit.ODR_C, OUTBOUNDDOORBELL_0 << SRC_ODR_SHIFT);
|
||||
if (!dev->msi_enabled)
|
||||
src_writel(dev,
|
||||
MUnit.ODR_C,
|
||||
OUTBOUNDDOORBELL_0 << SRC_ODR_SHIFT);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -335,9 +379,14 @@ static void aac_src_notify_adapter(struct aac_dev *dev, u32 event)
|
||||
static void aac_src_start_adapter(struct aac_dev *dev)
|
||||
{
|
||||
struct aac_init *init;
|
||||
int i;
|
||||
|
||||
/* reset host_rrq_idx first */
|
||||
dev->host_rrq_idx = 0;
|
||||
for (i = 0; i < dev->max_msix; i++) {
|
||||
dev->host_rrq_idx[i] = i * dev->vector_cap;
|
||||
atomic_set(&dev->rrq_outstanding[i], 0);
|
||||
}
|
||||
dev->fibs_pushed_no = 0;
|
||||
|
||||
init = dev->init;
|
||||
init->HostElapsedSeconds = cpu_to_le32(get_seconds());
|
||||
@ -400,6 +449,33 @@ static int aac_src_deliver_message(struct fib *fib)
|
||||
q->numpending++;
|
||||
spin_unlock_irqrestore(q->lock, qflags);
|
||||
|
||||
if (dev->msi_enabled && fib->hw_fib_va->header.Command != AifRequest &&
|
||||
dev->max_msix > 1) {
|
||||
u_int16_t vector_no, first_choice = 0xffff;
|
||||
|
||||
vector_no = dev->fibs_pushed_no % dev->max_msix;
|
||||
do {
|
||||
vector_no += 1;
|
||||
if (vector_no == dev->max_msix)
|
||||
vector_no = 1;
|
||||
if (atomic_read(&dev->rrq_outstanding[vector_no]) <
|
||||
dev->vector_cap)
|
||||
break;
|
||||
if (0xffff == first_choice)
|
||||
first_choice = vector_no;
|
||||
else if (vector_no == first_choice)
|
||||
break;
|
||||
} while (1);
|
||||
if (vector_no == first_choice)
|
||||
vector_no = 0;
|
||||
atomic_inc(&dev->rrq_outstanding[vector_no]);
|
||||
if (dev->fibs_pushed_no == 0xffffffff)
|
||||
dev->fibs_pushed_no = 0;
|
||||
else
|
||||
dev->fibs_pushed_no++;
|
||||
fib->hw_fib_va->header.Handle += (vector_no << 16);
|
||||
}
|
||||
|
||||
if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE2) {
|
||||
/* Calculate the amount to the fibsize bits */
|
||||
fibsize = (hdr_size + 127) / 128 - 1;
|
||||
@ -502,10 +578,19 @@ static int aac_src_restart_adapter(struct aac_dev *dev, int bled)
|
||||
0, 0, 0, 0, 0, 0, &var, &reset_mask, NULL, NULL, NULL);
|
||||
if (bled || (var != 0x00000001))
|
||||
return -EINVAL;
|
||||
|
||||
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);
|
||||
dev->msi_enabled = 0;
|
||||
msleep(5000); /* Delay 5 seconds */
|
||||
}
|
||||
|
||||
if (dev->supplement_adapter_info.SupportedOptions2 &
|
||||
AAC_OPTION_DOORBELL_RESET) {
|
||||
src_writel(dev, MUnit.IDR, reset_mask);
|
||||
msleep(5000); /* Delay 5 seconds */
|
||||
ssleep(45);
|
||||
}
|
||||
}
|
||||
|
||||
@ -646,8 +731,11 @@ int aac_src_init(struct aac_dev *dev)
|
||||
|
||||
dev->msi = aac_msi && !pci_enable_msi(dev->pdev);
|
||||
|
||||
dev->aac_msix[0].vector_no = 0;
|
||||
dev->aac_msix[0].dev = dev;
|
||||
|
||||
if (request_irq(dev->pdev->irq, dev->a_ops.adapter_intr,
|
||||
IRQF_SHARED, "aacraid", dev) < 0) {
|
||||
IRQF_SHARED, "aacraid", &(dev->aac_msix[0])) < 0) {
|
||||
|
||||
if (dev->msi)
|
||||
pci_disable_msi(dev->pdev);
|
||||
@ -688,6 +776,7 @@ int aac_srcv_init(struct aac_dev *dev)
|
||||
unsigned long status;
|
||||
int restart = 0;
|
||||
int instance = dev->id;
|
||||
int i, j;
|
||||
const char *name = dev->name;
|
||||
|
||||
dev->a_ops.adapter_ioremap = aac_srcv_ioremap;
|
||||
@ -802,14 +891,41 @@ int aac_srcv_init(struct aac_dev *dev)
|
||||
goto error_iounmap;
|
||||
if (dev->comm_interface != AAC_COMM_MESSAGE_TYPE2)
|
||||
goto error_iounmap;
|
||||
dev->msi = aac_msi && !pci_enable_msi(dev->pdev);
|
||||
if (request_irq(dev->pdev->irq, dev->a_ops.adapter_intr,
|
||||
IRQF_SHARED, "aacraid", dev) < 0) {
|
||||
if (dev->msi)
|
||||
pci_disable_msi(dev->pdev);
|
||||
printk(KERN_ERR "%s%d: Interrupt unavailable.\n",
|
||||
name, instance);
|
||||
goto error_iounmap;
|
||||
if (dev->msi_enabled)
|
||||
aac_src_access_devreg(dev, AAC_ENABLE_MSIX);
|
||||
if (!dev->sync_mode && dev->msi_enabled && dev->max_msix > 1) {
|
||||
for (i = 0; i < dev->max_msix; i++) {
|
||||
dev->aac_msix[i].vector_no = i;
|
||||
dev->aac_msix[i].dev = dev;
|
||||
|
||||
if (request_irq(dev->msixentry[i].vector,
|
||||
dev->a_ops.adapter_intr,
|
||||
0,
|
||||
"aacraid",
|
||||
&(dev->aac_msix[i]))) {
|
||||
printk(KERN_ERR "%s%d: Failed to register IRQ for vector %d.\n",
|
||||
name, instance, i);
|
||||
for (j = 0 ; j < i ; j++)
|
||||
free_irq(dev->msixentry[j].vector,
|
||||
&(dev->aac_msix[j]));
|
||||
pci_disable_msix(dev->pdev);
|
||||
goto error_iounmap;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
dev->aac_msix[0].vector_no = 0;
|
||||
dev->aac_msix[0].dev = dev;
|
||||
|
||||
if (request_irq(dev->pdev->irq, dev->a_ops.adapter_intr,
|
||||
IRQF_SHARED,
|
||||
"aacraid",
|
||||
&(dev->aac_msix[0])) < 0) {
|
||||
if (dev->msi)
|
||||
pci_disable_msi(dev->pdev);
|
||||
printk(KERN_ERR "%s%d: Interrupt unavailable.\n",
|
||||
name, instance);
|
||||
goto error_iounmap;
|
||||
}
|
||||
}
|
||||
dev->dbg_base = dev->base_start;
|
||||
dev->dbg_base_mapped = dev->base;
|
||||
@ -831,3 +947,93 @@ error_iounmap:
|
||||
return -1;
|
||||
}
|
||||
|
||||
void aac_src_access_devreg(struct aac_dev *dev, int mode)
|
||||
{
|
||||
u_int32_t val;
|
||||
|
||||
switch (mode) {
|
||||
case AAC_ENABLE_INTERRUPT:
|
||||
src_writel(dev,
|
||||
MUnit.OIMR,
|
||||
dev->OIMR = (dev->msi_enabled ?
|
||||
AAC_INT_ENABLE_TYPE1_MSIX :
|
||||
AAC_INT_ENABLE_TYPE1_INTX));
|
||||
break;
|
||||
|
||||
case AAC_DISABLE_INTERRUPT:
|
||||
src_writel(dev,
|
||||
MUnit.OIMR,
|
||||
dev->OIMR = AAC_INT_DISABLE_ALL);
|
||||
break;
|
||||
|
||||
case AAC_ENABLE_MSIX:
|
||||
/* set bit 6 */
|
||||
val = src_readl(dev, MUnit.IDR);
|
||||
val |= 0x40;
|
||||
src_writel(dev, MUnit.IDR, val);
|
||||
src_readl(dev, MUnit.IDR);
|
||||
/* unmask int. */
|
||||
val = PMC_ALL_INTERRUPT_BITS;
|
||||
src_writel(dev, MUnit.IOAR, val);
|
||||
val = src_readl(dev, MUnit.OIMR);
|
||||
src_writel(dev,
|
||||
MUnit.OIMR,
|
||||
val & (~(PMC_GLOBAL_INT_BIT2 | PMC_GLOBAL_INT_BIT0)));
|
||||
break;
|
||||
|
||||
case AAC_DISABLE_MSIX:
|
||||
/* reset bit 6 */
|
||||
val = src_readl(dev, MUnit.IDR);
|
||||
val &= ~0x40;
|
||||
src_writel(dev, MUnit.IDR, val);
|
||||
src_readl(dev, MUnit.IDR);
|
||||
break;
|
||||
|
||||
case AAC_CLEAR_AIF_BIT:
|
||||
/* set bit 5 */
|
||||
val = src_readl(dev, MUnit.IDR);
|
||||
val |= 0x20;
|
||||
src_writel(dev, MUnit.IDR, val);
|
||||
src_readl(dev, MUnit.IDR);
|
||||
break;
|
||||
|
||||
case AAC_CLEAR_SYNC_BIT:
|
||||
/* set bit 4 */
|
||||
val = src_readl(dev, MUnit.IDR);
|
||||
val |= 0x10;
|
||||
src_writel(dev, MUnit.IDR, val);
|
||||
src_readl(dev, MUnit.IDR);
|
||||
break;
|
||||
|
||||
case AAC_ENABLE_INTX:
|
||||
/* set bit 7 */
|
||||
val = src_readl(dev, MUnit.IDR);
|
||||
val |= 0x80;
|
||||
src_writel(dev, MUnit.IDR, val);
|
||||
src_readl(dev, MUnit.IDR);
|
||||
/* unmask int. */
|
||||
val = PMC_ALL_INTERRUPT_BITS;
|
||||
src_writel(dev, MUnit.IOAR, val);
|
||||
src_readl(dev, MUnit.IOAR);
|
||||
val = src_readl(dev, MUnit.OIMR);
|
||||
src_writel(dev, MUnit.OIMR,
|
||||
val & (~(PMC_GLOBAL_INT_BIT2)));
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int aac_src_get_sync_status(struct aac_dev *dev)
|
||||
{
|
||||
|
||||
int val;
|
||||
|
||||
if (dev->msi_enabled)
|
||||
val = src_readl(dev, MUnit.ODR_MSI) & 0x1000 ? 1 : 0;
|
||||
else
|
||||
val = src_readl(dev, MUnit.ODR_R) >> SRC_ODR_SHIFT;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user