Commit 179ac142 authored by Sumit Saxena's avatar Sumit Saxena Committed by Martin K. Petersen

megaraid_sas: Reply Descriptor Post Queue (RDPQ) support

This patch will create a reply queue pool for each MSI-X index and will
provide an array of base addresses instead of the single address of
legacy mode. Using this new interface the driver can support higher
queue depths through scattered DMA pools.

If array mode is not supported driver will fall back to the legacy
method of reply pool allocation. This limits controller queue depth to
1K max. To enable a queue depth of more than 1K driver requires firmware
to support array mode and scratch_pad3 will provide the new queue depth
value.

When RDPQ is used, downgrading to an older firmware release should not
be permitted. This may cause firmware fault and is not supported.
Signed-off-by: default avatarKashyap Desai <kashyap.desai@avagotech.com>
Signed-off-by: default avatarSumit Saxena <sumit.saxena@avagotech.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 8f05024c
...@@ -152,6 +152,7 @@ ...@@ -152,6 +152,7 @@
#define MFI_RESET_FLAGS MFI_INIT_READY| \ #define MFI_RESET_FLAGS MFI_INIT_READY| \
MFI_INIT_MFIMODE| \ MFI_INIT_MFIMODE| \
MFI_INIT_ABORT MFI_INIT_ABORT
#define MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE (0x01)
/* /*
* MFI frame flags * MFI frame flags
...@@ -1416,6 +1417,7 @@ enum DCMD_TIMEOUT_ACTION { ...@@ -1416,6 +1417,7 @@ enum DCMD_TIMEOUT_ACTION {
#define MR_MAX_REPLY_QUEUES_EXT_OFFSET 0X003FC000 #define MR_MAX_REPLY_QUEUES_EXT_OFFSET 0X003FC000
#define MR_MAX_REPLY_QUEUES_EXT_OFFSET_SHIFT 14 #define MR_MAX_REPLY_QUEUES_EXT_OFFSET_SHIFT 14
#define MR_MAX_MSIX_REG_ARRAY 16 #define MR_MAX_MSIX_REG_ARRAY 16
#define MR_RDPQ_MODE_OFFSET 0X00800000
/* /*
* register set for both 1068 and 1078 controllers * register set for both 1068 and 1078 controllers
* structure extended for 1078 registers * structure extended for 1078 registers
...@@ -1455,8 +1457,9 @@ struct megasas_register_set { ...@@ -1455,8 +1457,9 @@ struct megasas_register_set {
u32 outbound_scratch_pad ; /*00B0h*/ u32 outbound_scratch_pad ; /*00B0h*/
u32 outbound_scratch_pad_2; /*00B4h*/ u32 outbound_scratch_pad_2; /*00B4h*/
u32 outbound_scratch_pad_3; /*00B8h*/
u32 reserved_4[2]; /*00B8h*/ u32 reserved_4; /*00BCh*/
u32 inbound_low_queue_port ; /*00C0h*/ u32 inbound_low_queue_port ; /*00C0h*/
...@@ -2117,6 +2120,7 @@ struct megasas_instance { ...@@ -2117,6 +2120,7 @@ struct megasas_instance {
u8 mask_interrupts; u8 mask_interrupts;
u16 max_chain_frame_sz; u16 max_chain_frame_sz;
u8 is_imr; u8 is_imr;
u8 is_rdpq;
bool dev_handle; bool dev_handle;
}; };
struct MR_LD_VF_MAP { struct MR_LD_VF_MAP {
......
...@@ -92,6 +92,10 @@ int smp_affinity_enable = 1; ...@@ -92,6 +92,10 @@ int smp_affinity_enable = 1;
module_param(smp_affinity_enable, int, S_IRUGO); module_param(smp_affinity_enable, int, S_IRUGO);
MODULE_PARM_DESC(smp_affinity_enable, "SMP affinity feature enable/disbale Default: enable(1)"); MODULE_PARM_DESC(smp_affinity_enable, "SMP affinity feature enable/disbale Default: enable(1)");
int rdpq_enable = 1;
module_param(rdpq_enable, int, S_IRUGO);
MODULE_PARM_DESC(rdpq_enable, " Allocate reply queue in chunks for large queue depth enable/disable Default: disable(0)");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_VERSION(MEGASAS_VERSION); MODULE_VERSION(MEGASAS_VERSION);
MODULE_AUTHOR("megaraidlinux.pdl@avagotech.com"); MODULE_AUTHOR("megaraidlinux.pdl@avagotech.com");
...@@ -5080,6 +5084,9 @@ static int megasas_init_fw(struct megasas_instance *instance) ...@@ -5080,6 +5084,9 @@ static int megasas_init_fw(struct megasas_instance *instance)
instance->msix_vectors = ((scratch_pad_2 instance->msix_vectors = ((scratch_pad_2
& MR_MAX_REPLY_QUEUES_EXT_OFFSET) & MR_MAX_REPLY_QUEUES_EXT_OFFSET)
>> MR_MAX_REPLY_QUEUES_EXT_OFFSET_SHIFT) + 1; >> MR_MAX_REPLY_QUEUES_EXT_OFFSET_SHIFT) + 1;
if (rdpq_enable)
instance->is_rdpq = (scratch_pad_2 & MR_RDPQ_MODE_OFFSET) ?
1 : 0;
fw_msix_count = instance->msix_vectors; fw_msix_count = instance->msix_vectors;
/* Save 1-15 reply post index address to local memory /* Save 1-15 reply post index address to local memory
* Index 0 is already saved from reg offset * Index 0 is already saved from reg offset
...@@ -5116,6 +5123,8 @@ static int megasas_init_fw(struct megasas_instance *instance) ...@@ -5116,6 +5123,8 @@ static int megasas_init_fw(struct megasas_instance *instance)
dev_info(&instance->pdev->dev, dev_info(&instance->pdev->dev,
"current msix/online cpus\t: (%d/%d)\n", "current msix/online cpus\t: (%d/%d)\n",
instance->msix_vectors, (unsigned int)num_online_cpus()); instance->msix_vectors, (unsigned int)num_online_cpus());
dev_info(&instance->pdev->dev,
"RDPQ mode\t: (%s)\n", instance->is_rdpq ? "enabled" : "disabled");
tasklet_init(&instance->isr_tasklet, instance->instancet->tasklet, tasklet_init(&instance->isr_tasklet, instance->instancet->tasklet,
(unsigned long)instance); (unsigned long)instance);
......
...@@ -92,6 +92,8 @@ void megasas_start_timer(struct megasas_instance *instance, ...@@ -92,6 +92,8 @@ void megasas_start_timer(struct megasas_instance *instance,
void *fn, unsigned long interval); void *fn, unsigned long interval);
extern struct megasas_mgmt_info megasas_mgmt_info; extern struct megasas_mgmt_info megasas_mgmt_info;
extern int resetwaittime; extern int resetwaittime;
static void megasas_free_rdpq_fusion(struct megasas_instance *instance);
static void megasas_free_reply_fusion(struct megasas_instance *instance);
...@@ -205,112 +207,74 @@ megasas_fire_cmd_fusion(struct megasas_instance *instance, ...@@ -205,112 +207,74 @@ megasas_fire_cmd_fusion(struct megasas_instance *instance,
#endif #endif
} }
/** /**
* megasas_teardown_frame_pool_fusion - Destroy the cmd frame DMA pool * megasas_free_cmds_fusion - Free all the cmds in the free cmd pool
* @instance: Adapter soft state * @instance: Adapter soft state
*/ */
static void megasas_teardown_frame_pool_fusion( void
struct megasas_instance *instance) megasas_free_cmds_fusion(struct megasas_instance *instance)
{ {
int i; int i;
struct fusion_context *fusion = instance->ctrl_context; struct fusion_context *fusion = instance->ctrl_context;
u16 max_cmd = instance->max_fw_cmds;
struct megasas_cmd_fusion *cmd; struct megasas_cmd_fusion *cmd;
if (!fusion->sg_dma_pool || !fusion->sense_dma_pool) { /* SG, Sense */
dev_err(&instance->pdev->dev, "dma pool is null. SG Pool %p, " for (i = 0; i < instance->max_fw_cmds; i++) {
"sense pool : %p\n", fusion->sg_dma_pool,
fusion->sense_dma_pool);
return;
}
/*
* Return all frames to pool
*/
for (i = 0; i < max_cmd; i++) {
cmd = fusion->cmd_list[i]; cmd = fusion->cmd_list[i];
if (cmd) {
if (cmd->sg_frame) if (cmd->sg_frame)
pci_pool_free(fusion->sg_dma_pool, cmd->sg_frame, pci_pool_free(fusion->sg_dma_pool, cmd->sg_frame,
cmd->sg_frame_phys_addr); cmd->sg_frame_phys_addr);
if (cmd->sense)
if (cmd->sense) pci_pool_free(fusion->sense_dma_pool, cmd->sense,
pci_pool_free(fusion->sense_dma_pool, cmd->sense,
cmd->sense_phys_addr); cmd->sense_phys_addr);
}
} }
/* if (fusion->sg_dma_pool) {
* Now destroy the pool itself pci_pool_destroy(fusion->sg_dma_pool);
*/ fusion->sg_dma_pool = NULL;
pci_pool_destroy(fusion->sg_dma_pool); }
pci_pool_destroy(fusion->sense_dma_pool); if (fusion->sense_dma_pool) {
pci_pool_destroy(fusion->sense_dma_pool);
fusion->sg_dma_pool = NULL; fusion->sense_dma_pool = NULL;
fusion->sense_dma_pool = NULL; }
}
/**
* megasas_free_cmds_fusion - Free all the cmds in the free cmd pool
* @instance: Adapter soft state
*/
void
megasas_free_cmds_fusion(struct megasas_instance *instance)
{
int i;
struct fusion_context *fusion = instance->ctrl_context;
u32 max_cmds, req_sz, reply_sz, io_frames_sz;
req_sz = fusion->request_alloc_sz;
reply_sz = fusion->reply_alloc_sz;
io_frames_sz = fusion->io_frames_alloc_sz;
max_cmds = instance->max_fw_cmds; /* Reply Frame, Desc*/
if (instance->is_rdpq)
megasas_free_rdpq_fusion(instance);
else
megasas_free_reply_fusion(instance);
/* Free descriptors and request Frames memory */ /* Request Frame, Desc*/
if (fusion->req_frames_desc) if (fusion->req_frames_desc)
dma_free_coherent(&instance->pdev->dev, req_sz, dma_free_coherent(&instance->pdev->dev,
fusion->req_frames_desc, fusion->request_alloc_sz, fusion->req_frames_desc,
fusion->req_frames_desc_phys); fusion->req_frames_desc_phys);
if (fusion->io_request_frames)
if (fusion->reply_frames_desc) {
pci_pool_free(fusion->reply_frames_desc_pool,
fusion->reply_frames_desc,
fusion->reply_frames_desc_phys);
pci_pool_destroy(fusion->reply_frames_desc_pool);
}
if (fusion->io_request_frames) {
pci_pool_free(fusion->io_request_frames_pool, pci_pool_free(fusion->io_request_frames_pool,
fusion->io_request_frames, fusion->io_request_frames,
fusion->io_request_frames_phys); fusion->io_request_frames_phys);
if (fusion->io_request_frames_pool) {
pci_pool_destroy(fusion->io_request_frames_pool); pci_pool_destroy(fusion->io_request_frames_pool);
fusion->io_request_frames_pool = NULL;
} }
/* Free the Fusion frame pool */
megasas_teardown_frame_pool_fusion(instance);
/* Free all the commands in the cmd_list */ /* cmd_list */
for (i = 0; i < max_cmds; i++) for (i = 0; i < instance->max_fw_cmds; i++)
kfree(fusion->cmd_list[i]); kfree(fusion->cmd_list[i]);
/* Free the cmd_list buffer itself */
kfree(fusion->cmd_list); kfree(fusion->cmd_list);
fusion->cmd_list = NULL;
} }
/** /**
* megasas_create_frame_pool_fusion - Creates DMA pool for cmd frames * megasas_create_sg_sense_fusion - Creates DMA pool for cmd frames
* @instance: Adapter soft state * @instance: Adapter soft state
* *
*/ */
static int megasas_create_frame_pool_fusion(struct megasas_instance *instance) static int megasas_create_sg_sense_fusion(struct megasas_instance *instance)
{ {
int i; int i;
u32 max_cmd; u32 max_cmd;
...@@ -321,25 +285,17 @@ static int megasas_create_frame_pool_fusion(struct megasas_instance *instance) ...@@ -321,25 +285,17 @@ static int megasas_create_frame_pool_fusion(struct megasas_instance *instance)
max_cmd = instance->max_fw_cmds; max_cmd = instance->max_fw_cmds;
/* fusion->sg_dma_pool =
* Use DMA pool facility provided by PCI layer pci_pool_create("mr_sg", instance->pdev,
*/ instance->max_chain_frame_sz, 4, 0);
/* SCSI_SENSE_BUFFERSIZE = 96 bytes */
fusion->sg_dma_pool = pci_pool_create("sg_pool_fusion", instance->pdev, fusion->sense_dma_pool =
instance->max_chain_frame_sz, pci_pool_create("mr_sense", instance->pdev,
4, 0); SCSI_SENSE_BUFFERSIZE, 64, 0);
if (!fusion->sg_dma_pool) {
dev_printk(KERN_DEBUG, &instance->pdev->dev, "failed to setup request pool fusion\n");
return -ENOMEM;
}
fusion->sense_dma_pool = pci_pool_create("sense pool fusion",
instance->pdev,
SCSI_SENSE_BUFFERSIZE, 64, 0);
if (!fusion->sense_dma_pool) { if (!fusion->sense_dma_pool || !fusion->sg_dma_pool) {
dev_printk(KERN_DEBUG, &instance->pdev->dev, "failed to setup sense pool fusion\n"); dev_err(&instance->pdev->dev,
pci_pool_destroy(fusion->sg_dma_pool); "Failed from %s %d\n", __func__, __LINE__);
fusion->sg_dma_pool = NULL;
return -ENOMEM; return -ENOMEM;
} }
...@@ -347,160 +303,280 @@ static int megasas_create_frame_pool_fusion(struct megasas_instance *instance) ...@@ -347,160 +303,280 @@ static int megasas_create_frame_pool_fusion(struct megasas_instance *instance)
* Allocate and attach a frame to each of the commands in cmd_list * Allocate and attach a frame to each of the commands in cmd_list
*/ */
for (i = 0; i < max_cmd; i++) { for (i = 0; i < max_cmd; i++) {
cmd = fusion->cmd_list[i]; cmd = fusion->cmd_list[i];
cmd->sg_frame = pci_pool_alloc(fusion->sg_dma_pool, cmd->sg_frame = pci_pool_alloc(fusion->sg_dma_pool,
GFP_KERNEL, GFP_KERNEL, &cmd->sg_frame_phys_addr);
&cmd->sg_frame_phys_addr);
cmd->sense = pci_pool_alloc(fusion->sense_dma_pool, cmd->sense = pci_pool_alloc(fusion->sense_dma_pool,
GFP_KERNEL, &cmd->sense_phys_addr); GFP_KERNEL, &cmd->sense_phys_addr);
/*
* megasas_teardown_frame_pool_fusion() takes care of freeing
* whatever has been allocated
*/
if (!cmd->sg_frame || !cmd->sense) { if (!cmd->sg_frame || !cmd->sense) {
dev_printk(KERN_DEBUG, &instance->pdev->dev, "pci_pool_alloc failed\n"); dev_err(&instance->pdev->dev,
megasas_teardown_frame_pool_fusion(instance); "Failed from %s %d\n", __func__, __LINE__);
return -ENOMEM; return -ENOMEM;
} }
} }
return 0; return 0;
} }
/**
* megasas_alloc_cmds_fusion - Allocates the command packets
* @instance: Adapter soft state
*
*
* Each frame has a 32-bit field called context. This context is used to get
* back the megasas_cmd_fusion from the frame when a frame gets completed
* In this driver, the 32 bit values are the indices into an array cmd_list.
* This array is used only to look up the megasas_cmd_fusion given the context.
* The free commands themselves are maintained in a linked list called cmd_pool.
*
* cmds are formed in the io_request and sg_frame members of the
* megasas_cmd_fusion. The context field is used to get a request descriptor
* and is used as SMID of the cmd.
* SMID value range is from 1 to max_fw_cmds.
*/
int int
megasas_alloc_cmds_fusion(struct megasas_instance *instance) megasas_alloc_cmdlist_fusion(struct megasas_instance *instance)
{ {
int i, j, count; u32 max_cmd, i;
u32 max_cmd, io_frames_sz;
struct fusion_context *fusion; struct fusion_context *fusion;
struct megasas_cmd_fusion *cmd;
union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc;
u32 offset;
dma_addr_t io_req_base_phys;
u8 *io_req_base;
fusion = instance->ctrl_context; fusion = instance->ctrl_context;
max_cmd = instance->max_fw_cmds; max_cmd = instance->max_fw_cmds;
/*
* fusion->cmd_list is an array of struct megasas_cmd_fusion pointers.
* Allocate the dynamic array first and then allocate individual
* commands.
*/
fusion->cmd_list = kzalloc(sizeof(struct megasas_cmd_fusion *) * max_cmd,
GFP_KERNEL);
if (!fusion->cmd_list) {
dev_err(&instance->pdev->dev,
"Failed from %s %d\n", __func__, __LINE__);
return -ENOMEM;
}
for (i = 0; i < max_cmd; i++) {
fusion->cmd_list[i] = kzalloc(sizeof(struct megasas_cmd_fusion),
GFP_KERNEL);
if (!fusion->cmd_list[i]) {
dev_err(&instance->pdev->dev,
"Failed from %s %d\n", __func__, __LINE__);
return -ENOMEM;
}
}
return 0;
}
int
megasas_alloc_request_fusion(struct megasas_instance *instance)
{
struct fusion_context *fusion;
fusion = instance->ctrl_context;
fusion->req_frames_desc = fusion->req_frames_desc =
dma_alloc_coherent(&instance->pdev->dev, dma_alloc_coherent(&instance->pdev->dev,
fusion->request_alloc_sz, fusion->request_alloc_sz,
&fusion->req_frames_desc_phys, GFP_KERNEL); &fusion->req_frames_desc_phys, GFP_KERNEL);
if (!fusion->req_frames_desc) { if (!fusion->req_frames_desc) {
dev_err(&instance->pdev->dev, "Could not allocate memory for " dev_err(&instance->pdev->dev,
"request_frames\n"); "Failed from %s %d\n", __func__, __LINE__);
goto fail_req_desc; return -ENOMEM;
} }
fusion->io_request_frames_pool =
pci_pool_create("mr_ioreq", instance->pdev,
fusion->io_frames_alloc_sz, 16, 0);
if (!fusion->io_request_frames_pool) {
dev_err(&instance->pdev->dev,
"Failed from %s %d\n", __func__, __LINE__);
return -ENOMEM;
}
fusion->io_request_frames =
pci_pool_alloc(fusion->io_request_frames_pool,
GFP_KERNEL, &fusion->io_request_frames_phys);
if (!fusion->io_request_frames) {
dev_err(&instance->pdev->dev,
"Failed from %s %d\n", __func__, __LINE__);
return -ENOMEM;
}
return 0;
}
int
megasas_alloc_reply_fusion(struct megasas_instance *instance)
{
int i, count;
struct fusion_context *fusion;
union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc;
fusion = instance->ctrl_context;
count = instance->msix_vectors > 0 ? instance->msix_vectors : 1; count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
fusion->reply_frames_desc_pool = fusion->reply_frames_desc_pool =
pci_pool_create("reply_frames pool", instance->pdev, pci_pool_create("mr_reply", instance->pdev,
fusion->reply_alloc_sz * count, 16, 0); fusion->reply_alloc_sz * count, 16, 0);
if (!fusion->reply_frames_desc_pool) { if (!fusion->reply_frames_desc_pool) {
dev_err(&instance->pdev->dev, "Could not allocate memory for " dev_err(&instance->pdev->dev,
"reply_frame pool\n"); "Failed from %s %d\n", __func__, __LINE__);
goto fail_reply_desc; return -ENOMEM;
} }
fusion->reply_frames_desc = fusion->reply_frames_desc[0] =
pci_pool_alloc(fusion->reply_frames_desc_pool, GFP_KERNEL, pci_pool_alloc(fusion->reply_frames_desc_pool,
&fusion->reply_frames_desc_phys); GFP_KERNEL, &fusion->reply_frames_desc_phys[0]);
if (!fusion->reply_frames_desc) { if (!fusion->reply_frames_desc[0]) {
dev_err(&instance->pdev->dev, "Could not allocate memory for " dev_err(&instance->pdev->dev,
"reply_frame pool\n"); "Failed from %s %d\n", __func__, __LINE__);
pci_pool_destroy(fusion->reply_frames_desc_pool); return -ENOMEM;
goto fail_reply_desc;
} }
reply_desc = fusion->reply_frames_desc[0];
reply_desc = fusion->reply_frames_desc;
for (i = 0; i < fusion->reply_q_depth * count; i++, reply_desc++) for (i = 0; i < fusion->reply_q_depth * count; i++, reply_desc++)
reply_desc->Words = cpu_to_le64(ULLONG_MAX); reply_desc->Words = cpu_to_le64(ULLONG_MAX);
io_frames_sz = fusion->io_frames_alloc_sz; /* This is not a rdpq mode, but driver still populate
* reply_frame_desc array to use same msix index in ISR path.
*/
for (i = 0; i < (count - 1); i++)
fusion->reply_frames_desc[i + 1] =
fusion->reply_frames_desc[i] +
(fusion->reply_alloc_sz)/sizeof(union MPI2_REPLY_DESCRIPTORS_UNION);
fusion->io_request_frames_pool = return 0;
pci_pool_create("io_request_frames pool", instance->pdev, }
fusion->io_frames_alloc_sz, 16, 0);
if (!fusion->io_request_frames_pool) { int
dev_err(&instance->pdev->dev, "Could not allocate memory for " megasas_alloc_rdpq_fusion(struct megasas_instance *instance)
"io_request_frame pool\n"); {
goto fail_io_frames; int i, j, count;
struct fusion_context *fusion;
union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc;
fusion = instance->ctrl_context;
fusion->rdpq_virt = pci_alloc_consistent(instance->pdev,
sizeof(struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY) * MAX_MSIX_QUEUES_FUSION,
&fusion->rdpq_phys);
if (!fusion->rdpq_virt) {
dev_err(&instance->pdev->dev,
"Failed from %s %d\n", __func__, __LINE__);
return -ENOMEM;
} }
fusion->io_request_frames = memset(fusion->rdpq_virt, 0,
pci_pool_alloc(fusion->io_request_frames_pool, GFP_KERNEL, sizeof(struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY) * MAX_MSIX_QUEUES_FUSION);
&fusion->io_request_frames_phys); count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
if (!fusion->io_request_frames) { fusion->reply_frames_desc_pool = pci_pool_create("mr_rdpq",
dev_err(&instance->pdev->dev, "Could not allocate memory for " instance->pdev, fusion->reply_alloc_sz, 16, 0);
"io_request_frames frames\n");
pci_pool_destroy(fusion->io_request_frames_pool); if (!fusion->reply_frames_desc_pool) {
goto fail_io_frames; dev_err(&instance->pdev->dev,
"Failed from %s %d\n", __func__, __LINE__);
return -ENOMEM;
} }
/* for (i = 0; i < count; i++) {
* fusion->cmd_list is an array of struct megasas_cmd_fusion pointers. fusion->reply_frames_desc[i] =
* Allocate the dynamic array first and then allocate individual pci_pool_alloc(fusion->reply_frames_desc_pool,
* commands. GFP_KERNEL, &fusion->reply_frames_desc_phys[i]);
*/ if (!fusion->reply_frames_desc[i]) {
fusion->cmd_list = kzalloc(sizeof(struct megasas_cmd_fusion *) dev_err(&instance->pdev->dev,
* max_cmd, GFP_KERNEL); "Failed from %s %d\n", __func__, __LINE__);
return -ENOMEM;
}
if (!fusion->cmd_list) { fusion->rdpq_virt[i].RDPQBaseAddress =
dev_printk(KERN_DEBUG, &instance->pdev->dev, "out of memory. Could not alloc " fusion->reply_frames_desc_phys[i];
"memory for cmd_list_fusion\n");
goto fail_cmd_list; reply_desc = fusion->reply_frames_desc[i];
for (j = 0; j < fusion->reply_q_depth; j++, reply_desc++)
reply_desc->Words = cpu_to_le64(ULLONG_MAX);
} }
return 0;
}
max_cmd = instance->max_fw_cmds; static void
for (i = 0; i < max_cmd; i++) { megasas_free_rdpq_fusion(struct megasas_instance *instance) {
fusion->cmd_list[i] = kmalloc(sizeof(struct megasas_cmd_fusion),
GFP_KERNEL);
if (!fusion->cmd_list[i]) {
dev_err(&instance->pdev->dev, "Could not alloc cmd list fusion\n");
for (j = 0; j < i; j++) int i;
kfree(fusion->cmd_list[j]); struct fusion_context *fusion;
kfree(fusion->cmd_list); fusion = instance->ctrl_context;
fusion->cmd_list = NULL;
goto fail_cmd_list; for (i = 0; i < MAX_MSIX_QUEUES_FUSION; i++) {
} if (fusion->reply_frames_desc[i])
pci_pool_free(fusion->reply_frames_desc_pool,
fusion->reply_frames_desc[i],
fusion->reply_frames_desc_phys[i]);
} }
/* The first 256 bytes (SMID 0) is not used. Don't add to cmd list */ if (fusion->reply_frames_desc_pool)
io_req_base = fusion->io_request_frames + pci_pool_destroy(fusion->reply_frames_desc_pool);
MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE;
io_req_base_phys = fusion->io_request_frames_phys + if (fusion->rdpq_virt)
MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE; pci_free_consistent(instance->pdev,
sizeof(struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY) * MAX_MSIX_QUEUES_FUSION,
fusion->rdpq_virt, fusion->rdpq_phys);
}
static void
megasas_free_reply_fusion(struct megasas_instance *instance) {
struct fusion_context *fusion;
fusion = instance->ctrl_context;
if (fusion->reply_frames_desc[0])
pci_pool_free(fusion->reply_frames_desc_pool,
fusion->reply_frames_desc[0],
fusion->reply_frames_desc_phys[0]);
if (fusion->reply_frames_desc_pool)
pci_pool_destroy(fusion->reply_frames_desc_pool);
}
/**
* megasas_alloc_cmds_fusion - Allocates the command packets
* @instance: Adapter soft state
*
*
* Each frame has a 32-bit field called context. This context is used to get
* back the megasas_cmd_fusion from the frame when a frame gets completed
* In this driver, the 32 bit values are the indices into an array cmd_list.
* This array is used only to look up the megasas_cmd_fusion given the context.
* The free commands themselves are maintained in a linked list called cmd_pool.
*
* cmds are formed in the io_request and sg_frame members of the
* megasas_cmd_fusion. The context field is used to get a request descriptor
* and is used as SMID of the cmd.
* SMID value range is from 1 to max_fw_cmds.
*/
int
megasas_alloc_cmds_fusion(struct megasas_instance *instance)
{
int i;
struct fusion_context *fusion;
struct megasas_cmd_fusion *cmd;
u32 offset;
dma_addr_t io_req_base_phys;
u8 *io_req_base;
fusion = instance->ctrl_context;
if (megasas_alloc_cmdlist_fusion(instance))
goto fail_exit;
if (megasas_alloc_request_fusion(instance))
goto fail_exit;
if (instance->is_rdpq) {
if (megasas_alloc_rdpq_fusion(instance))
goto fail_exit;
} else
if (megasas_alloc_reply_fusion(instance))
goto fail_exit;
/* The first 256 bytes (SMID 0) is not used. Don't add to the cmd list */
io_req_base = fusion->io_request_frames + MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE;
io_req_base_phys = fusion->io_request_frames_phys + MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE;
/* /*
* Add all the commands to command pool (fusion->cmd_pool) * Add all the commands to command pool (fusion->cmd_pool)
*/ */
/* SMID 0 is reserved. Set SMID/index from 1 */ /* SMID 0 is reserved. Set SMID/index from 1 */
for (i = 0; i < max_cmd; i++) { for (i = 0; i < instance->max_fw_cmds; i++) {
cmd = fusion->cmd_list[i]; cmd = fusion->cmd_list[i];
offset = MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE * i; offset = MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE * i;
memset(cmd, 0, sizeof(struct megasas_cmd_fusion)); memset(cmd, 0, sizeof(struct megasas_cmd_fusion));
...@@ -518,35 +594,13 @@ megasas_alloc_cmds_fusion(struct megasas_instance *instance) ...@@ -518,35 +594,13 @@ megasas_alloc_cmds_fusion(struct megasas_instance *instance)
cmd->io_request_phys_addr = io_req_base_phys + offset; cmd->io_request_phys_addr = io_req_base_phys + offset;
} }
/* if (megasas_create_sg_sense_fusion(instance))
* Create a frame pool and assign one frame to each cmd goto fail_exit;
*/
if (megasas_create_frame_pool_fusion(instance)) {
dev_printk(KERN_DEBUG, &instance->pdev->dev, "Error creating frame DMA pool\n");
megasas_free_cmds_fusion(instance);
goto fail_req_desc;
}
return 0; return 0;
fail_cmd_list: fail_exit:
pci_pool_free(fusion->io_request_frames_pool, fusion->io_request_frames, megasas_free_cmds_fusion(instance);
fusion->io_request_frames_phys);
pci_pool_destroy(fusion->io_request_frames_pool);
fail_io_frames:
dma_free_coherent(&instance->pdev->dev, fusion->request_alloc_sz,
fusion->reply_frames_desc,
fusion->reply_frames_desc_phys);
pci_pool_free(fusion->reply_frames_desc_pool,
fusion->reply_frames_desc,
fusion->reply_frames_desc_phys);
pci_pool_destroy(fusion->reply_frames_desc_pool);
fail_reply_desc:
dma_free_coherent(&instance->pdev->dev, fusion->request_alloc_sz,
fusion->req_frames_desc,
fusion->req_frames_desc_phys);
fail_req_desc:
return -ENOMEM; return -ENOMEM;
} }
...@@ -594,16 +648,17 @@ int ...@@ -594,16 +648,17 @@ int
megasas_ioc_init_fusion(struct megasas_instance *instance) megasas_ioc_init_fusion(struct megasas_instance *instance)
{ {
struct megasas_init_frame *init_frame; struct megasas_init_frame *init_frame;
struct MPI2_IOC_INIT_REQUEST *IOCInitMessage; struct MPI2_IOC_INIT_REQUEST *IOCInitMessage = NULL;
dma_addr_t ioc_init_handle; dma_addr_t ioc_init_handle;
struct megasas_cmd *cmd; struct megasas_cmd *cmd;
u8 ret; u8 ret, cur_rdpq_mode;
struct fusion_context *fusion; struct fusion_context *fusion;
union MEGASAS_REQUEST_DESCRIPTOR_UNION req_desc; union MEGASAS_REQUEST_DESCRIPTOR_UNION req_desc;
int i; int i;
struct megasas_header *frame_hdr; struct megasas_header *frame_hdr;
const char *sys_info; const char *sys_info;
MFI_CAPABILITIES *drv_ops; MFI_CAPABILITIES *drv_ops;
u32 scratch_pad_2;
fusion = instance->ctrl_context; fusion = instance->ctrl_context;
...@@ -615,6 +670,18 @@ megasas_ioc_init_fusion(struct megasas_instance *instance) ...@@ -615,6 +670,18 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
goto fail_get_cmd; goto fail_get_cmd;
} }
scratch_pad_2 = readl
(&instance->reg_set->outbound_scratch_pad_2);
cur_rdpq_mode = (scratch_pad_2 & MR_RDPQ_MODE_OFFSET) ? 1 : 0;
if (instance->is_rdpq && !cur_rdpq_mode) {
dev_err(&instance->pdev->dev, "Firmware downgrade *NOT SUPPORTED*"
" from RDPQ mode to non RDPQ mode\n");
ret = 1;
goto fail_fw_init;
}
IOCInitMessage = IOCInitMessage =
dma_alloc_coherent(&instance->pdev->dev, dma_alloc_coherent(&instance->pdev->dev,
sizeof(struct MPI2_IOC_INIT_REQUEST), sizeof(struct MPI2_IOC_INIT_REQUEST),
...@@ -636,7 +703,11 @@ megasas_ioc_init_fusion(struct megasas_instance *instance) ...@@ -636,7 +703,11 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
IOCInitMessage->SystemRequestFrameSize = cpu_to_le16(MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE / 4); IOCInitMessage->SystemRequestFrameSize = cpu_to_le16(MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE / 4);
IOCInitMessage->ReplyDescriptorPostQueueDepth = cpu_to_le16(fusion->reply_q_depth); IOCInitMessage->ReplyDescriptorPostQueueDepth = cpu_to_le16(fusion->reply_q_depth);
IOCInitMessage->ReplyDescriptorPostQueueAddress = cpu_to_le64(fusion->reply_frames_desc_phys); IOCInitMessage->ReplyDescriptorPostQueueAddress = instance->is_rdpq ?
cpu_to_le64(fusion->rdpq_phys) :
cpu_to_le64(fusion->reply_frames_desc_phys[0]);
IOCInitMessage->MsgFlags = instance->is_rdpq ?
MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE : 0;
IOCInitMessage->SystemRequestFrameBaseAddress = cpu_to_le64(fusion->io_request_frames_phys); IOCInitMessage->SystemRequestFrameBaseAddress = cpu_to_le64(fusion->io_request_frames_phys);
IOCInitMessage->HostMSIxVectors = instance->msix_vectors; IOCInitMessage->HostMSIxVectors = instance->msix_vectors;
init_frame = (struct megasas_init_frame *)cmd->frame; init_frame = (struct megasas_init_frame *)cmd->frame;
...@@ -1087,7 +1158,10 @@ megasas_init_adapter_fusion(struct megasas_instance *instance) ...@@ -1087,7 +1158,10 @@ megasas_init_adapter_fusion(struct megasas_instance *instance)
*/ */
instance->max_fw_cmds = instance->max_fw_cmds =
instance->instancet->read_fw_status_reg(reg_set) & 0x00FFFF; instance->instancet->read_fw_status_reg(reg_set) & 0x00FFFF;
instance->max_fw_cmds = min(instance->max_fw_cmds, (u16)1008); dev_info(&instance->pdev->dev,
"firmware support max fw cmd\t: (%d)\n", instance->max_fw_cmds);
if (!instance->is_rdpq)
instance->max_fw_cmds = min_t(u16, instance->max_fw_cmds, 1024);
/* /*
* Reduce the max supported cmds by 1. This is to ensure that the * Reduce the max supported cmds by 1. This is to ensure that the
...@@ -2110,10 +2184,8 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex) ...@@ -2110,10 +2184,8 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex)
if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR)
return IRQ_HANDLED; return IRQ_HANDLED;
desc = fusion->reply_frames_desc; desc = fusion->reply_frames_desc[MSIxIndex] +
desc += ((MSIxIndex * fusion->reply_alloc_sz)/ fusion->last_reply_idx[MSIxIndex];
sizeof(union MPI2_REPLY_DESCRIPTORS_UNION)) +
fusion->last_reply_idx[MSIxIndex];
reply_desc = (struct MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR *)desc; reply_desc = (struct MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR *)desc;
...@@ -2208,9 +2280,7 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex) ...@@ -2208,9 +2280,7 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex)
/* Get the next reply descriptor */ /* Get the next reply descriptor */
if (!fusion->last_reply_idx[MSIxIndex]) if (!fusion->last_reply_idx[MSIxIndex])
desc = fusion->reply_frames_desc + desc = fusion->reply_frames_desc[MSIxIndex];
((MSIxIndex * fusion->reply_alloc_sz)/
sizeof(union MPI2_REPLY_DESCRIPTORS_UNION));
else else
desc++; desc++;
...@@ -2688,17 +2758,18 @@ int megasas_wait_for_outstanding_fusion(struct megasas_instance *instance, ...@@ -2688,17 +2758,18 @@ int megasas_wait_for_outstanding_fusion(struct megasas_instance *instance,
void megasas_reset_reply_desc(struct megasas_instance *instance) void megasas_reset_reply_desc(struct megasas_instance *instance)
{ {
int i, count; int i, j, count;
struct fusion_context *fusion; struct fusion_context *fusion;
union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc; union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc;
fusion = instance->ctrl_context; fusion = instance->ctrl_context;
count = instance->msix_vectors > 0 ? instance->msix_vectors : 1; count = instance->msix_vectors > 0 ? instance->msix_vectors : 1;
for (i = 0 ; i < count ; i++) for (i = 0 ; i < count ; i++) {
fusion->last_reply_idx[i] = 0; fusion->last_reply_idx[i] = 0;
reply_desc = fusion->reply_frames_desc; reply_desc = fusion->reply_frames_desc[i];
for (i = 0 ; i < fusion->reply_q_depth * count; i++, reply_desc++) for (j = 0 ; j < fusion->reply_q_depth; j++, reply_desc++)
reply_desc->Words = cpu_to_le64(ULLONG_MAX); reply_desc->Words = cpu_to_le64(ULLONG_MAX);
}
} }
/* /*
......
...@@ -928,6 +928,12 @@ struct MR_PD_CFG_SEQ_NUM_SYNC { ...@@ -928,6 +928,12 @@ struct MR_PD_CFG_SEQ_NUM_SYNC {
struct MR_PD_CFG_SEQ seq[1]; struct MR_PD_CFG_SEQ seq[1];
} __packed; } __packed;
struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY {
u64 RDPQBaseAddress;
u32 Reserved1;
u32 Reserved2;
};
struct fusion_context { struct fusion_context {
struct megasas_cmd_fusion **cmd_list; struct megasas_cmd_fusion **cmd_list;
dma_addr_t req_frames_desc_phys; dma_addr_t req_frames_desc_phys;
...@@ -940,8 +946,8 @@ struct fusion_context { ...@@ -940,8 +946,8 @@ struct fusion_context {
struct dma_pool *sg_dma_pool; struct dma_pool *sg_dma_pool;
struct dma_pool *sense_dma_pool; struct dma_pool *sense_dma_pool;
dma_addr_t reply_frames_desc_phys; dma_addr_t reply_frames_desc_phys[MAX_MSIX_QUEUES_FUSION];
union MPI2_REPLY_DESCRIPTORS_UNION *reply_frames_desc; union MPI2_REPLY_DESCRIPTORS_UNION *reply_frames_desc[MAX_MSIX_QUEUES_FUSION];
struct dma_pool *reply_frames_desc_pool; struct dma_pool *reply_frames_desc_pool;
u16 last_reply_idx[MAX_MSIX_QUEUES_FUSION]; u16 last_reply_idx[MAX_MSIX_QUEUES_FUSION];
...@@ -951,6 +957,8 @@ struct fusion_context { ...@@ -951,6 +957,8 @@ struct fusion_context {
u32 reply_alloc_sz; u32 reply_alloc_sz;
u32 io_frames_alloc_sz; u32 io_frames_alloc_sz;
struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY *rdpq_virt;
dma_addr_t rdpq_phys;
u16 max_sge_in_main_msg; u16 max_sge_in_main_msg;
u16 max_sge_in_chain; u16 max_sge_in_chain;
......
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