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]
|
#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 @@
|
|||||||
#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 {
|
|||||||
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 {
|
|||||||
|
|
||||||
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 {
|
|||||||
__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 {
|
|||||||
#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
|
|||||||
* 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
|
|||||||
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);
|
|||||||
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 @@
|
|||||||
|
|
||||||
#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
|
|||||||
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
|
|||||||
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)
|
|||||||
/* 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)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
* 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 @@ retry_next:
|
|||||||
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)
|
|||||||
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,
|
|||||||
* 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 = {
|
|||||||
|
|
||||||
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)
|
|||||||
}
|
}
|
||||||
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)
|
||||||
|
@ -44,98 +44,128 @@
|
|||||||
|
|
||||||
#include "aacraid.h"
|
#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;
|
unsigned long bellbits, bellbits_shifted;
|
||||||
int our_interrupt = 0;
|
int vector_no;
|
||||||
int isFastResponse;
|
int isFastResponse, mode;
|
||||||
u32 index, handle;
|
u32 index, handle;
|
||||||
|
|
||||||
bellbits = src_readl(dev, MUnit.ODR_R);
|
ctx = (struct aac_msix_ctx *)dev_id;
|
||||||
if (bellbits & PmDoorBellResponseSent) {
|
dev = ctx->dev;
|
||||||
bellbits = PmDoorBellResponseSent;
|
vector_no = ctx->vector_no;
|
||||||
/* handle async. status */
|
|
||||||
src_writel(dev, MUnit.ODR_C, bellbits);
|
if (dev->msi_enabled) {
|
||||||
src_readl(dev, MUnit.ODR_C);
|
mode = AAC_INT_MODE_MSI;
|
||||||
our_interrupt = 1;
|
if (vector_no == 0) {
|
||||||
index = dev->host_rrq_idx;
|
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 (;;) {
|
for (;;) {
|
||||||
isFastResponse = 0;
|
isFastResponse = 0;
|
||||||
/* remove toggle bit (31) */
|
/* remove toggle bit (31) */
|
||||||
handle = le32_to_cpu(dev->host_rrq[index]) & 0x7fffffff;
|
handle = (dev->host_rrq[index] & 0x7fffffff);
|
||||||
/* check fast response bit (30) */
|
/* check fast response bit (30) */
|
||||||
if (handle & 0x40000000)
|
if (handle & 0x40000000)
|
||||||
isFastResponse = 1;
|
isFastResponse = 1;
|
||||||
handle &= 0x0000ffff;
|
handle &= 0x0000ffff;
|
||||||
if (handle == 0)
|
if (handle == 0)
|
||||||
break;
|
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);
|
aac_intr_normal(dev, handle-1, 0, isFastResponse, NULL);
|
||||||
|
|
||||||
dev->host_rrq[index++] = 0;
|
dev->host_rrq[index++] = 0;
|
||||||
if (index == dev->scsi_host_ptr->can_queue +
|
if (index == (vector_no + 1) * dev->vector_cap)
|
||||||
AAC_NUM_MGT_FIB)
|
index = vector_no * dev->vector_cap;
|
||||||
index = 0;
|
dev->host_rrq_idx[vector_no] = index;
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
mode = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (our_interrupt) {
|
return IRQ_HANDLED;
|
||||||
return IRQ_HANDLED;
|
|
||||||
}
|
|
||||||
return IRQ_NONE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -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)
|
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.
|
* 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
|
* 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.
|
* 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.
|
* 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;
|
ok = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -254,11 +293,16 @@ static int src_sync_cmd(struct aac_dev *dev, u32 command,
|
|||||||
*r3 = readl(&dev->IndexRegs->Mailbox[3]);
|
*r3 = readl(&dev->IndexRegs->Mailbox[3]);
|
||||||
if (r4)
|
if (r4)
|
||||||
*r4 = readl(&dev->IndexRegs->Mailbox[4]);
|
*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.
|
* 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)
|
static void aac_src_start_adapter(struct aac_dev *dev)
|
||||||
{
|
{
|
||||||
struct aac_init *init;
|
struct aac_init *init;
|
||||||
|
int i;
|
||||||
|
|
||||||
/* reset host_rrq_idx first */
|
/* 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 = dev->init;
|
||||||
init->HostElapsedSeconds = cpu_to_le32(get_seconds());
|
init->HostElapsedSeconds = cpu_to_le32(get_seconds());
|
||||||
@ -400,6 +449,33 @@ static int aac_src_deliver_message(struct fib *fib)
|
|||||||
q->numpending++;
|
q->numpending++;
|
||||||
spin_unlock_irqrestore(q->lock, qflags);
|
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) {
|
if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE2) {
|
||||||
/* Calculate the amount to the fibsize bits */
|
/* Calculate the amount to the fibsize bits */
|
||||||
fibsize = (hdr_size + 127) / 128 - 1;
|
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);
|
0, 0, 0, 0, 0, 0, &var, &reset_mask, NULL, NULL, NULL);
|
||||||
if (bled || (var != 0x00000001))
|
if (bled || (var != 0x00000001))
|
||||||
return -EINVAL;
|
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 &
|
if (dev->supplement_adapter_info.SupportedOptions2 &
|
||||||
AAC_OPTION_DOORBELL_RESET) {
|
AAC_OPTION_DOORBELL_RESET) {
|
||||||
src_writel(dev, MUnit.IDR, reset_mask);
|
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->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,
|
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)
|
if (dev->msi)
|
||||||
pci_disable_msi(dev->pdev);
|
pci_disable_msi(dev->pdev);
|
||||||
@ -688,6 +776,7 @@ int aac_srcv_init(struct aac_dev *dev)
|
|||||||
unsigned long status;
|
unsigned long status;
|
||||||
int restart = 0;
|
int restart = 0;
|
||||||
int instance = dev->id;
|
int instance = dev->id;
|
||||||
|
int i, j;
|
||||||
const char *name = dev->name;
|
const char *name = dev->name;
|
||||||
|
|
||||||
dev->a_ops.adapter_ioremap = aac_srcv_ioremap;
|
dev->a_ops.adapter_ioremap = aac_srcv_ioremap;
|
||||||
@ -802,14 +891,41 @@ int aac_srcv_init(struct aac_dev *dev)
|
|||||||
goto error_iounmap;
|
goto error_iounmap;
|
||||||
if (dev->comm_interface != AAC_COMM_MESSAGE_TYPE2)
|
if (dev->comm_interface != AAC_COMM_MESSAGE_TYPE2)
|
||||||
goto error_iounmap;
|
goto error_iounmap;
|
||||||
dev->msi = aac_msi && !pci_enable_msi(dev->pdev);
|
if (dev->msi_enabled)
|
||||||
if (request_irq(dev->pdev->irq, dev->a_ops.adapter_intr,
|
aac_src_access_devreg(dev, AAC_ENABLE_MSIX);
|
||||||
IRQF_SHARED, "aacraid", dev) < 0) {
|
if (!dev->sync_mode && dev->msi_enabled && dev->max_msix > 1) {
|
||||||
if (dev->msi)
|
for (i = 0; i < dev->max_msix; i++) {
|
||||||
pci_disable_msi(dev->pdev);
|
dev->aac_msix[i].vector_no = i;
|
||||||
printk(KERN_ERR "%s%d: Interrupt unavailable.\n",
|
dev->aac_msix[i].dev = dev;
|
||||||
name, instance);
|
|
||||||
goto error_iounmap;
|
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 = dev->base_start;
|
||||||
dev->dbg_base_mapped = dev->base;
|
dev->dbg_base_mapped = dev->base;
|
||||||
@ -831,3 +947,93 @@ error_iounmap:
|
|||||||
return -1;
|
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…
x
Reference in New Issue
Block a user