|
@@ -834,25 +834,31 @@ union reply_descriptor {
|
|
static irqreturn_t
|
|
static irqreturn_t
|
|
_base_interrupt(int irq, void *bus_id)
|
|
_base_interrupt(int irq, void *bus_id)
|
|
{
|
|
{
|
|
|
|
+ struct adapter_reply_queue *reply_q = bus_id;
|
|
union reply_descriptor rd;
|
|
union reply_descriptor rd;
|
|
u32 completed_cmds;
|
|
u32 completed_cmds;
|
|
u8 request_desript_type;
|
|
u8 request_desript_type;
|
|
u16 smid;
|
|
u16 smid;
|
|
u8 cb_idx;
|
|
u8 cb_idx;
|
|
u32 reply;
|
|
u32 reply;
|
|
- u8 msix_index;
|
|
|
|
- struct MPT2SAS_ADAPTER *ioc = bus_id;
|
|
|
|
|
|
+ u8 msix_index = reply_q->msix_index;
|
|
|
|
+ struct MPT2SAS_ADAPTER *ioc = reply_q->ioc;
|
|
Mpi2ReplyDescriptorsUnion_t *rpf;
|
|
Mpi2ReplyDescriptorsUnion_t *rpf;
|
|
u8 rc;
|
|
u8 rc;
|
|
|
|
|
|
if (ioc->mask_interrupts)
|
|
if (ioc->mask_interrupts)
|
|
return IRQ_NONE;
|
|
return IRQ_NONE;
|
|
|
|
|
|
- rpf = &ioc->reply_post_free[ioc->reply_post_host_index];
|
|
|
|
|
|
+ if (!atomic_add_unless(&reply_q->busy, 1, 1))
|
|
|
|
+ return IRQ_NONE;
|
|
|
|
+
|
|
|
|
+ rpf = &reply_q->reply_post_free[reply_q->reply_post_host_index];
|
|
request_desript_type = rpf->Default.ReplyFlags
|
|
request_desript_type = rpf->Default.ReplyFlags
|
|
& MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK;
|
|
& MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK;
|
|
- if (request_desript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED)
|
|
|
|
|
|
+ if (request_desript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) {
|
|
|
|
+ atomic_dec(&reply_q->busy);
|
|
return IRQ_NONE;
|
|
return IRQ_NONE;
|
|
|
|
+ }
|
|
|
|
|
|
completed_cmds = 0;
|
|
completed_cmds = 0;
|
|
cb_idx = 0xFF;
|
|
cb_idx = 0xFF;
|
|
@@ -861,9 +867,7 @@ _base_interrupt(int irq, void *bus_id)
|
|
if (rd.u.low == UINT_MAX || rd.u.high == UINT_MAX)
|
|
if (rd.u.low == UINT_MAX || rd.u.high == UINT_MAX)
|
|
goto out;
|
|
goto out;
|
|
reply = 0;
|
|
reply = 0;
|
|
- cb_idx = 0xFF;
|
|
|
|
smid = le16_to_cpu(rpf->Default.DescriptorTypeDependent1);
|
|
smid = le16_to_cpu(rpf->Default.DescriptorTypeDependent1);
|
|
- msix_index = rpf->Default.MSIxIndex;
|
|
|
|
if (request_desript_type ==
|
|
if (request_desript_type ==
|
|
MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY) {
|
|
MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY) {
|
|
reply = le32_to_cpu
|
|
reply = le32_to_cpu
|
|
@@ -907,31 +911,85 @@ _base_interrupt(int irq, void *bus_id)
|
|
next:
|
|
next:
|
|
|
|
|
|
rpf->Words = cpu_to_le64(ULLONG_MAX);
|
|
rpf->Words = cpu_to_le64(ULLONG_MAX);
|
|
- ioc->reply_post_host_index = (ioc->reply_post_host_index ==
|
|
|
|
|
|
+ reply_q->reply_post_host_index =
|
|
|
|
+ (reply_q->reply_post_host_index ==
|
|
(ioc->reply_post_queue_depth - 1)) ? 0 :
|
|
(ioc->reply_post_queue_depth - 1)) ? 0 :
|
|
- ioc->reply_post_host_index + 1;
|
|
|
|
|
|
+ reply_q->reply_post_host_index + 1;
|
|
request_desript_type =
|
|
request_desript_type =
|
|
- ioc->reply_post_free[ioc->reply_post_host_index].Default.
|
|
|
|
- ReplyFlags & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK;
|
|
|
|
|
|
+ reply_q->reply_post_free[reply_q->reply_post_host_index].
|
|
|
|
+ Default.ReplyFlags & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK;
|
|
completed_cmds++;
|
|
completed_cmds++;
|
|
if (request_desript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED)
|
|
if (request_desript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED)
|
|
goto out;
|
|
goto out;
|
|
- if (!ioc->reply_post_host_index)
|
|
|
|
- rpf = ioc->reply_post_free;
|
|
|
|
|
|
+ if (!reply_q->reply_post_host_index)
|
|
|
|
+ rpf = reply_q->reply_post_free;
|
|
else
|
|
else
|
|
rpf++;
|
|
rpf++;
|
|
} while (1);
|
|
} while (1);
|
|
|
|
|
|
out:
|
|
out:
|
|
|
|
|
|
- if (!completed_cmds)
|
|
|
|
|
|
+ if (!completed_cmds) {
|
|
|
|
+ atomic_dec(&reply_q->busy);
|
|
return IRQ_NONE;
|
|
return IRQ_NONE;
|
|
-
|
|
|
|
|
|
+ }
|
|
wmb();
|
|
wmb();
|
|
- writel(ioc->reply_post_host_index, &ioc->chip->ReplyPostHostIndex);
|
|
|
|
|
|
+ if (ioc->is_warpdrive) {
|
|
|
|
+ writel(reply_q->reply_post_host_index,
|
|
|
|
+ ioc->reply_post_host_index[msix_index]);
|
|
|
|
+ atomic_dec(&reply_q->busy);
|
|
|
|
+ return IRQ_HANDLED;
|
|
|
|
+ }
|
|
|
|
+ writel(reply_q->reply_post_host_index | (msix_index <<
|
|
|
|
+ MPI2_RPHI_MSIX_INDEX_SHIFT), &ioc->chip->ReplyPostHostIndex);
|
|
|
|
+ atomic_dec(&reply_q->busy);
|
|
return IRQ_HANDLED;
|
|
return IRQ_HANDLED;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * _base_is_controller_msix_enabled - is controller support muli-reply queues
|
|
|
|
+ * @ioc: per adapter object
|
|
|
|
+ *
|
|
|
|
+ */
|
|
|
|
+static inline int
|
|
|
|
+_base_is_controller_msix_enabled(struct MPT2SAS_ADAPTER *ioc)
|
|
|
|
+{
|
|
|
|
+ return (ioc->facts.IOCCapabilities &
|
|
|
|
+ MPI2_IOCFACTS_CAPABILITY_MSI_X_INDEX) && ioc->msix_enable;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * mpt2sas_base_flush_reply_queues - flushing the MSIX reply queues
|
|
|
|
+ * @ioc: per adapter object
|
|
|
|
+ * Context: ISR conext
|
|
|
|
+ *
|
|
|
|
+ * Called when a Task Management request has completed. We want
|
|
|
|
+ * to flush the other reply queues so all the outstanding IO has been
|
|
|
|
+ * completed back to OS before we process the TM completetion.
|
|
|
|
+ *
|
|
|
|
+ * Return nothing.
|
|
|
|
+ */
|
|
|
|
+void
|
|
|
|
+mpt2sas_base_flush_reply_queues(struct MPT2SAS_ADAPTER *ioc)
|
|
|
|
+{
|
|
|
|
+ struct adapter_reply_queue *reply_q;
|
|
|
|
+
|
|
|
|
+ /* If MSIX capability is turned off
|
|
|
|
+ * then multi-queues are not enabled
|
|
|
|
+ */
|
|
|
|
+ if (!_base_is_controller_msix_enabled(ioc))
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ list_for_each_entry(reply_q, &ioc->reply_queue_list, list) {
|
|
|
|
+ if (ioc->shost_recovery)
|
|
|
|
+ return;
|
|
|
|
+ /* TMs are on msix_index == 0 */
|
|
|
|
+ if (reply_q->msix_index == 0)
|
|
|
|
+ continue;
|
|
|
|
+ _base_interrupt(reply_q->vector, (void *)reply_q);
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* mpt2sas_base_release_callback_handler - clear interrupt callback handler
|
|
* mpt2sas_base_release_callback_handler - clear interrupt callback handler
|
|
* @cb_idx: callback index
|
|
* @cb_idx: callback index
|
|
@@ -1082,74 +1140,171 @@ _base_config_dma_addressing(struct MPT2SAS_ADAPTER *ioc, struct pci_dev *pdev)
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
- * _base_save_msix_table - backup msix vector table
|
|
|
|
|
|
+ * _base_check_enable_msix - checks MSIX capabable.
|
|
* @ioc: per adapter object
|
|
* @ioc: per adapter object
|
|
*
|
|
*
|
|
- * This address an errata where diag reset clears out the table
|
|
|
|
|
|
+ * Check to see if card is capable of MSIX, and set number
|
|
|
|
+ * of available msix vectors
|
|
*/
|
|
*/
|
|
-static void
|
|
|
|
-_base_save_msix_table(struct MPT2SAS_ADAPTER *ioc)
|
|
|
|
|
|
+static int
|
|
|
|
+_base_check_enable_msix(struct MPT2SAS_ADAPTER *ioc)
|
|
{
|
|
{
|
|
- int i;
|
|
|
|
|
|
+ int base;
|
|
|
|
+ u16 message_control;
|
|
|
|
|
|
- if (!ioc->msix_enable || ioc->msix_table_backup == NULL)
|
|
|
|
- return;
|
|
|
|
|
|
|
|
- for (i = 0; i < ioc->msix_vector_count; i++)
|
|
|
|
- ioc->msix_table_backup[i] = ioc->msix_table[i];
|
|
|
|
|
|
+ base = pci_find_capability(ioc->pdev, PCI_CAP_ID_MSIX);
|
|
|
|
+ if (!base) {
|
|
|
|
+ dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "msix not "
|
|
|
|
+ "supported\n", ioc->name));
|
|
|
|
+ return -EINVAL;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* get msix vector count */
|
|
|
|
+ /* NUMA_IO not supported for older controllers */
|
|
|
|
+ if (ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2004 ||
|
|
|
|
+ ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2008 ||
|
|
|
|
+ ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2108_1 ||
|
|
|
|
+ ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2108_2 ||
|
|
|
|
+ ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2108_3 ||
|
|
|
|
+ ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2116_1 ||
|
|
|
|
+ ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2116_2)
|
|
|
|
+ ioc->msix_vector_count = 1;
|
|
|
|
+ else {
|
|
|
|
+ pci_read_config_word(ioc->pdev, base + 2, &message_control);
|
|
|
|
+ ioc->msix_vector_count = (message_control & 0x3FF) + 1;
|
|
|
|
+ }
|
|
|
|
+ dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "msix is supported, "
|
|
|
|
+ "vector_count(%d)\n", ioc->name, ioc->msix_vector_count));
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
- * _base_restore_msix_table - this restores the msix vector table
|
|
|
|
|
|
+ * _base_free_irq - free irq
|
|
* @ioc: per adapter object
|
|
* @ioc: per adapter object
|
|
*
|
|
*
|
|
|
|
+ * Freeing respective reply_queue from the list.
|
|
*/
|
|
*/
|
|
static void
|
|
static void
|
|
-_base_restore_msix_table(struct MPT2SAS_ADAPTER *ioc)
|
|
|
|
|
|
+_base_free_irq(struct MPT2SAS_ADAPTER *ioc)
|
|
{
|
|
{
|
|
- int i;
|
|
|
|
|
|
+ struct adapter_reply_queue *reply_q, *next;
|
|
|
|
|
|
- if (!ioc->msix_enable || ioc->msix_table_backup == NULL)
|
|
|
|
|
|
+ if (list_empty(&ioc->reply_queue_list))
|
|
return;
|
|
return;
|
|
|
|
|
|
- for (i = 0; i < ioc->msix_vector_count; i++)
|
|
|
|
- ioc->msix_table[i] = ioc->msix_table_backup[i];
|
|
|
|
|
|
+ list_for_each_entry_safe(reply_q, next, &ioc->reply_queue_list, list) {
|
|
|
|
+ list_del(&reply_q->list);
|
|
|
|
+ synchronize_irq(reply_q->vector);
|
|
|
|
+ free_irq(reply_q->vector, reply_q);
|
|
|
|
+ kfree(reply_q);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
- * _base_check_enable_msix - checks MSIX capabable.
|
|
|
|
|
|
+ * _base_request_irq - request irq
|
|
* @ioc: per adapter object
|
|
* @ioc: per adapter object
|
|
|
|
+ * @index: msix index into vector table
|
|
|
|
+ * @vector: irq vector
|
|
*
|
|
*
|
|
- * Check to see if card is capable of MSIX, and set number
|
|
|
|
- * of available msix vectors
|
|
|
|
|
|
+ * Inserting respective reply_queue into the list.
|
|
*/
|
|
*/
|
|
static int
|
|
static int
|
|
-_base_check_enable_msix(struct MPT2SAS_ADAPTER *ioc)
|
|
|
|
|
|
+_base_request_irq(struct MPT2SAS_ADAPTER *ioc, u8 index, u32 vector)
|
|
{
|
|
{
|
|
- int base;
|
|
|
|
- u16 message_control;
|
|
|
|
- u32 msix_table_offset;
|
|
|
|
|
|
+ struct adapter_reply_queue *reply_q;
|
|
|
|
+ int r;
|
|
|
|
|
|
- base = pci_find_capability(ioc->pdev, PCI_CAP_ID_MSIX);
|
|
|
|
- if (!base) {
|
|
|
|
- dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "msix not "
|
|
|
|
- "supported\n", ioc->name));
|
|
|
|
- return -EINVAL;
|
|
|
|
|
|
+ reply_q = kzalloc(sizeof(struct adapter_reply_queue), GFP_KERNEL);
|
|
|
|
+ if (!reply_q) {
|
|
|
|
+ printk(MPT2SAS_ERR_FMT "unable to allocate memory %d!\n",
|
|
|
|
+ ioc->name, (int)sizeof(struct adapter_reply_queue));
|
|
|
|
+ return -ENOMEM;
|
|
|
|
+ }
|
|
|
|
+ reply_q->ioc = ioc;
|
|
|
|
+ reply_q->msix_index = index;
|
|
|
|
+ reply_q->vector = vector;
|
|
|
|
+ atomic_set(&reply_q->busy, 0);
|
|
|
|
+ if (ioc->msix_enable)
|
|
|
|
+ snprintf(reply_q->name, MPT_NAME_LENGTH, "%s%d-msix%d",
|
|
|
|
+ MPT2SAS_DRIVER_NAME, ioc->id, index);
|
|
|
|
+ else
|
|
|
|
+ snprintf(reply_q->name, MPT_NAME_LENGTH, "%s%d",
|
|
|
|
+ MPT2SAS_DRIVER_NAME, ioc->id);
|
|
|
|
+ r = request_irq(vector, _base_interrupt, IRQF_SHARED, reply_q->name,
|
|
|
|
+ reply_q);
|
|
|
|
+ if (r) {
|
|
|
|
+ printk(MPT2SAS_ERR_FMT "unable to allocate interrupt %d!\n",
|
|
|
|
+ reply_q->name, vector);
|
|
|
|
+ kfree(reply_q);
|
|
|
|
+ return -EBUSY;
|
|
}
|
|
}
|
|
|
|
|
|
- /* get msix vector count */
|
|
|
|
- pci_read_config_word(ioc->pdev, base + 2, &message_control);
|
|
|
|
- ioc->msix_vector_count = (message_control & 0x3FF) + 1;
|
|
|
|
|
|
+ INIT_LIST_HEAD(&reply_q->list);
|
|
|
|
+ list_add_tail(&reply_q->list, &ioc->reply_queue_list);
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
|
|
- /* get msix table */
|
|
|
|
- pci_read_config_dword(ioc->pdev, base + 4, &msix_table_offset);
|
|
|
|
- msix_table_offset &= 0xFFFFFFF8;
|
|
|
|
- ioc->msix_table = (u32 *)((void *)ioc->chip + msix_table_offset);
|
|
|
|
|
|
+/**
|
|
|
|
+ * _base_assign_reply_queues - assigning msix index for each cpu
|
|
|
|
+ * @ioc: per adapter object
|
|
|
|
+ *
|
|
|
|
+ * The enduser would need to set the affinity via /proc/irq/#/smp_affinity
|
|
|
|
+ *
|
|
|
|
+ * It would nice if we could call irq_set_affinity, however it is not
|
|
|
|
+ * an exported symbol
|
|
|
|
+ */
|
|
|
|
+static void
|
|
|
|
+_base_assign_reply_queues(struct MPT2SAS_ADAPTER *ioc)
|
|
|
|
+{
|
|
|
|
+ struct adapter_reply_queue *reply_q;
|
|
|
|
+ int cpu_id;
|
|
|
|
+ int cpu_grouping, loop, grouping, grouping_mod;
|
|
|
|
|
|
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "msix is supported, "
|
|
|
|
- "vector_count(%d), table_offset(0x%08x), table(%p)\n", ioc->name,
|
|
|
|
- ioc->msix_vector_count, msix_table_offset, ioc->msix_table));
|
|
|
|
- return 0;
|
|
|
|
|
|
+ if (!_base_is_controller_msix_enabled(ioc))
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ memset(ioc->cpu_msix_table, 0, ioc->cpu_msix_table_sz);
|
|
|
|
+ /* when there are more cpus than available msix vectors,
|
|
|
|
+ * then group cpus togeather on same irq
|
|
|
|
+ */
|
|
|
|
+ if (ioc->cpu_count > ioc->msix_vector_count) {
|
|
|
|
+ grouping = ioc->cpu_count / ioc->msix_vector_count;
|
|
|
|
+ grouping_mod = ioc->cpu_count % ioc->msix_vector_count;
|
|
|
|
+ if (grouping < 2 || (grouping == 2 && !grouping_mod))
|
|
|
|
+ cpu_grouping = 2;
|
|
|
|
+ else if (grouping < 4 || (grouping == 4 && !grouping_mod))
|
|
|
|
+ cpu_grouping = 4;
|
|
|
|
+ else if (grouping < 8 || (grouping == 8 && !grouping_mod))
|
|
|
|
+ cpu_grouping = 8;
|
|
|
|
+ else
|
|
|
|
+ cpu_grouping = 16;
|
|
|
|
+ } else
|
|
|
|
+ cpu_grouping = 0;
|
|
|
|
+
|
|
|
|
+ loop = 0;
|
|
|
|
+ reply_q = list_entry(ioc->reply_queue_list.next,
|
|
|
|
+ struct adapter_reply_queue, list);
|
|
|
|
+ for_each_online_cpu(cpu_id) {
|
|
|
|
+ if (!cpu_grouping) {
|
|
|
|
+ ioc->cpu_msix_table[cpu_id] = reply_q->msix_index;
|
|
|
|
+ reply_q = list_entry(reply_q->list.next,
|
|
|
|
+ struct adapter_reply_queue, list);
|
|
|
|
+ } else {
|
|
|
|
+ if (loop < cpu_grouping) {
|
|
|
|
+ ioc->cpu_msix_table[cpu_id] =
|
|
|
|
+ reply_q->msix_index;
|
|
|
|
+ loop++;
|
|
|
|
+ } else {
|
|
|
|
+ reply_q = list_entry(reply_q->list.next,
|
|
|
|
+ struct adapter_reply_queue, list);
|
|
|
|
+ ioc->cpu_msix_table[cpu_id] =
|
|
|
|
+ reply_q->msix_index;
|
|
|
|
+ loop = 1;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -1162,8 +1317,6 @@ _base_disable_msix(struct MPT2SAS_ADAPTER *ioc)
|
|
{
|
|
{
|
|
if (ioc->msix_enable) {
|
|
if (ioc->msix_enable) {
|
|
pci_disable_msix(ioc->pdev);
|
|
pci_disable_msix(ioc->pdev);
|
|
- kfree(ioc->msix_table_backup);
|
|
|
|
- ioc->msix_table_backup = NULL;
|
|
|
|
ioc->msix_enable = 0;
|
|
ioc->msix_enable = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -1176,10 +1329,13 @@ _base_disable_msix(struct MPT2SAS_ADAPTER *ioc)
|
|
static int
|
|
static int
|
|
_base_enable_msix(struct MPT2SAS_ADAPTER *ioc)
|
|
_base_enable_msix(struct MPT2SAS_ADAPTER *ioc)
|
|
{
|
|
{
|
|
- struct msix_entry entries;
|
|
|
|
|
|
+ struct msix_entry *entries, *a;
|
|
int r;
|
|
int r;
|
|
|
|
+ int i;
|
|
u8 try_msix = 0;
|
|
u8 try_msix = 0;
|
|
|
|
|
|
|
|
+ INIT_LIST_HEAD(&ioc->reply_queue_list);
|
|
|
|
+
|
|
if (msix_disable == -1 || msix_disable == 0)
|
|
if (msix_disable == -1 || msix_disable == 0)
|
|
try_msix = 1;
|
|
try_msix = 1;
|
|
|
|
|
|
@@ -1189,51 +1345,48 @@ _base_enable_msix(struct MPT2SAS_ADAPTER *ioc)
|
|
if (_base_check_enable_msix(ioc) != 0)
|
|
if (_base_check_enable_msix(ioc) != 0)
|
|
goto try_ioapic;
|
|
goto try_ioapic;
|
|
|
|
|
|
- ioc->msix_table_backup = kcalloc(ioc->msix_vector_count,
|
|
|
|
- sizeof(u32), GFP_KERNEL);
|
|
|
|
- if (!ioc->msix_table_backup) {
|
|
|
|
- dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "allocation for "
|
|
|
|
- "msix_table_backup failed!!!\n", ioc->name));
|
|
|
|
|
|
+ ioc->reply_queue_count = min_t(u8, ioc->cpu_count,
|
|
|
|
+ ioc->msix_vector_count);
|
|
|
|
+
|
|
|
|
+ entries = kcalloc(ioc->reply_queue_count, sizeof(struct msix_entry),
|
|
|
|
+ GFP_KERNEL);
|
|
|
|
+ if (!entries) {
|
|
|
|
+ dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "kcalloc "
|
|
|
|
+ "failed @ at %s:%d/%s() !!!\n", ioc->name, __FILE__,
|
|
|
|
+ __LINE__, __func__));
|
|
goto try_ioapic;
|
|
goto try_ioapic;
|
|
}
|
|
}
|
|
|
|
|
|
- memset(&entries, 0, sizeof(struct msix_entry));
|
|
|
|
- r = pci_enable_msix(ioc->pdev, &entries, 1);
|
|
|
|
|
|
+ for (i = 0, a = entries; i < ioc->reply_queue_count; i++, a++)
|
|
|
|
+ a->entry = i;
|
|
|
|
+
|
|
|
|
+ r = pci_enable_msix(ioc->pdev, entries, ioc->reply_queue_count);
|
|
if (r) {
|
|
if (r) {
|
|
dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "pci_enable_msix "
|
|
dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "pci_enable_msix "
|
|
"failed (r=%d) !!!\n", ioc->name, r));
|
|
"failed (r=%d) !!!\n", ioc->name, r));
|
|
|
|
+ kfree(entries);
|
|
goto try_ioapic;
|
|
goto try_ioapic;
|
|
}
|
|
}
|
|
|
|
|
|
- r = request_irq(entries.vector, _base_interrupt, IRQF_SHARED,
|
|
|
|
- ioc->name, ioc);
|
|
|
|
- if (r) {
|
|
|
|
- dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "unable to allocate "
|
|
|
|
- "interrupt %d !!!\n", ioc->name, entries.vector));
|
|
|
|
- pci_disable_msix(ioc->pdev);
|
|
|
|
- goto try_ioapic;
|
|
|
|
|
|
+ ioc->msix_enable = 1;
|
|
|
|
+ for (i = 0, a = entries; i < ioc->reply_queue_count; i++, a++) {
|
|
|
|
+ r = _base_request_irq(ioc, i, a->vector);
|
|
|
|
+ if (r) {
|
|
|
|
+ _base_free_irq(ioc);
|
|
|
|
+ _base_disable_msix(ioc);
|
|
|
|
+ kfree(entries);
|
|
|
|
+ goto try_ioapic;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
- ioc->pci_irq = entries.vector;
|
|
|
|
- ioc->msix_enable = 1;
|
|
|
|
|
|
+ kfree(entries);
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
/* failback to io_apic interrupt routing */
|
|
/* failback to io_apic interrupt routing */
|
|
try_ioapic:
|
|
try_ioapic:
|
|
|
|
|
|
- r = request_irq(ioc->pdev->irq, _base_interrupt, IRQF_SHARED,
|
|
|
|
- ioc->name, ioc);
|
|
|
|
- if (r) {
|
|
|
|
- printk(MPT2SAS_ERR_FMT "unable to allocate interrupt %d!\n",
|
|
|
|
- ioc->name, ioc->pdev->irq);
|
|
|
|
- r = -EBUSY;
|
|
|
|
- goto out_fail;
|
|
|
|
- }
|
|
|
|
|
|
+ r = _base_request_irq(ioc, 0, ioc->pdev->irq);
|
|
|
|
|
|
- ioc->pci_irq = ioc->pdev->irq;
|
|
|
|
- return 0;
|
|
|
|
-
|
|
|
|
- out_fail:
|
|
|
|
return r;
|
|
return r;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1252,6 +1405,7 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc)
|
|
int i, r = 0;
|
|
int i, r = 0;
|
|
u64 pio_chip = 0;
|
|
u64 pio_chip = 0;
|
|
u64 chip_phys = 0;
|
|
u64 chip_phys = 0;
|
|
|
|
+ struct adapter_reply_queue *reply_q;
|
|
|
|
|
|
dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n",
|
|
dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n",
|
|
ioc->name, __func__));
|
|
ioc->name, __func__));
|
|
@@ -1314,9 +1468,11 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc)
|
|
if (r)
|
|
if (r)
|
|
goto out_fail;
|
|
goto out_fail;
|
|
|
|
|
|
- printk(MPT2SAS_INFO_FMT "%s: IRQ %d\n",
|
|
|
|
- ioc->name, ((ioc->msix_enable) ? "PCI-MSI-X enabled" :
|
|
|
|
- "IO-APIC enabled"), ioc->pci_irq);
|
|
|
|
|
|
+ list_for_each_entry(reply_q, &ioc->reply_queue_list, list)
|
|
|
|
+ printk(MPT2SAS_INFO_FMT "%s: IRQ %d\n",
|
|
|
|
+ reply_q->name, ((ioc->msix_enable) ? "PCI-MSI-X enabled" :
|
|
|
|
+ "IO-APIC enabled"), reply_q->vector);
|
|
|
|
+
|
|
printk(MPT2SAS_INFO_FMT "iomem(0x%016llx), mapped(0x%p), size(%d)\n",
|
|
printk(MPT2SAS_INFO_FMT "iomem(0x%016llx), mapped(0x%p), size(%d)\n",
|
|
ioc->name, (unsigned long long)chip_phys, ioc->chip, memap_sz);
|
|
ioc->name, (unsigned long long)chip_phys, ioc->chip, memap_sz);
|
|
printk(MPT2SAS_INFO_FMT "ioport(0x%016llx), size(%d)\n",
|
|
printk(MPT2SAS_INFO_FMT "ioport(0x%016llx), size(%d)\n",
|
|
@@ -1331,7 +1487,6 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc)
|
|
if (ioc->chip_phys)
|
|
if (ioc->chip_phys)
|
|
iounmap(ioc->chip);
|
|
iounmap(ioc->chip);
|
|
ioc->chip_phys = 0;
|
|
ioc->chip_phys = 0;
|
|
- ioc->pci_irq = -1;
|
|
|
|
pci_release_selected_regions(ioc->pdev, ioc->bars);
|
|
pci_release_selected_regions(ioc->pdev, ioc->bars);
|
|
pci_disable_pcie_error_reporting(pdev);
|
|
pci_disable_pcie_error_reporting(pdev);
|
|
pci_disable_device(pdev);
|
|
pci_disable_device(pdev);
|
|
@@ -1578,6 +1733,12 @@ static inline void _base_writeq(__u64 b, volatile void __iomem *addr,
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
|
|
|
|
+static inline u8
|
|
|
|
+_base_get_msix_index(struct MPT2SAS_ADAPTER *ioc)
|
|
|
|
+{
|
|
|
|
+ return ioc->cpu_msix_table[smp_processor_id()];
|
|
|
|
+}
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* mpt2sas_base_put_smid_scsi_io - send SCSI_IO request to firmware
|
|
* mpt2sas_base_put_smid_scsi_io - send SCSI_IO request to firmware
|
|
* @ioc: per adapter object
|
|
* @ioc: per adapter object
|
|
@@ -1594,7 +1755,7 @@ mpt2sas_base_put_smid_scsi_io(struct MPT2SAS_ADAPTER *ioc, u16 smid, u16 handle)
|
|
|
|
|
|
|
|
|
|
descriptor.SCSIIO.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO;
|
|
descriptor.SCSIIO.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO;
|
|
- descriptor.SCSIIO.MSIxIndex = 0; /* TODO */
|
|
|
|
|
|
+ descriptor.SCSIIO.MSIxIndex = _base_get_msix_index(ioc);
|
|
descriptor.SCSIIO.SMID = cpu_to_le16(smid);
|
|
descriptor.SCSIIO.SMID = cpu_to_le16(smid);
|
|
descriptor.SCSIIO.DevHandle = cpu_to_le16(handle);
|
|
descriptor.SCSIIO.DevHandle = cpu_to_le16(handle);
|
|
descriptor.SCSIIO.LMID = 0;
|
|
descriptor.SCSIIO.LMID = 0;
|
|
@@ -1618,7 +1779,7 @@ mpt2sas_base_put_smid_hi_priority(struct MPT2SAS_ADAPTER *ioc, u16 smid)
|
|
|
|
|
|
descriptor.HighPriority.RequestFlags =
|
|
descriptor.HighPriority.RequestFlags =
|
|
MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY;
|
|
MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY;
|
|
- descriptor.HighPriority.MSIxIndex = 0; /* TODO */
|
|
|
|
|
|
+ descriptor.HighPriority.MSIxIndex = 0;
|
|
descriptor.HighPriority.SMID = cpu_to_le16(smid);
|
|
descriptor.HighPriority.SMID = cpu_to_le16(smid);
|
|
descriptor.HighPriority.LMID = 0;
|
|
descriptor.HighPriority.LMID = 0;
|
|
descriptor.HighPriority.Reserved1 = 0;
|
|
descriptor.HighPriority.Reserved1 = 0;
|
|
@@ -1640,7 +1801,7 @@ mpt2sas_base_put_smid_default(struct MPT2SAS_ADAPTER *ioc, u16 smid)
|
|
u64 *request = (u64 *)&descriptor;
|
|
u64 *request = (u64 *)&descriptor;
|
|
|
|
|
|
descriptor.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
|
|
descriptor.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
|
|
- descriptor.Default.MSIxIndex = 0; /* TODO */
|
|
|
|
|
|
+ descriptor.Default.MSIxIndex = _base_get_msix_index(ioc);
|
|
descriptor.Default.SMID = cpu_to_le16(smid);
|
|
descriptor.Default.SMID = cpu_to_le16(smid);
|
|
descriptor.Default.LMID = 0;
|
|
descriptor.Default.LMID = 0;
|
|
descriptor.Default.DescriptorTypeDependent = 0;
|
|
descriptor.Default.DescriptorTypeDependent = 0;
|
|
@@ -1665,7 +1826,7 @@ mpt2sas_base_put_smid_target_assist(struct MPT2SAS_ADAPTER *ioc, u16 smid,
|
|
|
|
|
|
descriptor.SCSITarget.RequestFlags =
|
|
descriptor.SCSITarget.RequestFlags =
|
|
MPI2_REQ_DESCRIPT_FLAGS_SCSI_TARGET;
|
|
MPI2_REQ_DESCRIPT_FLAGS_SCSI_TARGET;
|
|
- descriptor.SCSITarget.MSIxIndex = 0; /* TODO */
|
|
|
|
|
|
+ descriptor.SCSITarget.MSIxIndex = _base_get_msix_index(ioc);
|
|
descriptor.SCSITarget.SMID = cpu_to_le16(smid);
|
|
descriptor.SCSITarget.SMID = cpu_to_le16(smid);
|
|
descriptor.SCSITarget.LMID = 0;
|
|
descriptor.SCSITarget.LMID = 0;
|
|
descriptor.SCSITarget.IoIndex = cpu_to_le16(io_index);
|
|
descriptor.SCSITarget.IoIndex = cpu_to_le16(io_index);
|
|
@@ -2172,7 +2333,7 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
|
|
u16 max_sge_elements;
|
|
u16 max_sge_elements;
|
|
u16 num_of_reply_frames;
|
|
u16 num_of_reply_frames;
|
|
u16 chains_needed_per_io;
|
|
u16 chains_needed_per_io;
|
|
- u32 sz, total_sz;
|
|
|
|
|
|
+ u32 sz, total_sz, reply_post_free_sz;
|
|
u32 retry_sz;
|
|
u32 retry_sz;
|
|
u16 max_request_credit;
|
|
u16 max_request_credit;
|
|
int i;
|
|
int i;
|
|
@@ -2499,7 +2660,12 @@ chain_done:
|
|
total_sz += sz;
|
|
total_sz += sz;
|
|
|
|
|
|
/* reply post queue, 16 byte align */
|
|
/* reply post queue, 16 byte align */
|
|
- sz = ioc->reply_post_queue_depth * sizeof(Mpi2DefaultReplyDescriptor_t);
|
|
|
|
|
|
+ reply_post_free_sz = ioc->reply_post_queue_depth *
|
|
|
|
+ sizeof(Mpi2DefaultReplyDescriptor_t);
|
|
|
|
+ if (_base_is_controller_msix_enabled(ioc))
|
|
|
|
+ sz = reply_post_free_sz * ioc->reply_queue_count;
|
|
|
|
+ else
|
|
|
|
+ sz = reply_post_free_sz;
|
|
ioc->reply_post_free_dma_pool = pci_pool_create("reply_post_free pool",
|
|
ioc->reply_post_free_dma_pool = pci_pool_create("reply_post_free pool",
|
|
ioc->pdev, sz, 16, 0);
|
|
ioc->pdev, sz, 16, 0);
|
|
if (!ioc->reply_post_free_dma_pool) {
|
|
if (!ioc->reply_post_free_dma_pool) {
|
|
@@ -3187,6 +3353,7 @@ _base_get_ioc_facts(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
|
|
facts->MaxChainDepth = mpi_reply.MaxChainDepth;
|
|
facts->MaxChainDepth = mpi_reply.MaxChainDepth;
|
|
facts->WhoInit = mpi_reply.WhoInit;
|
|
facts->WhoInit = mpi_reply.WhoInit;
|
|
facts->NumberOfPorts = mpi_reply.NumberOfPorts;
|
|
facts->NumberOfPorts = mpi_reply.NumberOfPorts;
|
|
|
|
+ facts->MaxMSIxVectors = mpi_reply.MaxMSIxVectors;
|
|
facts->RequestCredit = le16_to_cpu(mpi_reply.RequestCredit);
|
|
facts->RequestCredit = le16_to_cpu(mpi_reply.RequestCredit);
|
|
facts->MaxReplyDescriptorPostQueueDepth =
|
|
facts->MaxReplyDescriptorPostQueueDepth =
|
|
le16_to_cpu(mpi_reply.MaxReplyDescriptorPostQueueDepth);
|
|
le16_to_cpu(mpi_reply.MaxReplyDescriptorPostQueueDepth);
|
|
@@ -3244,7 +3411,8 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
|
|
mpi_request.MsgVersion = cpu_to_le16(MPI2_VERSION);
|
|
mpi_request.MsgVersion = cpu_to_le16(MPI2_VERSION);
|
|
mpi_request.HeaderVersion = cpu_to_le16(MPI2_HEADER_VERSION);
|
|
mpi_request.HeaderVersion = cpu_to_le16(MPI2_HEADER_VERSION);
|
|
|
|
|
|
-
|
|
|
|
|
|
+ if (_base_is_controller_msix_enabled(ioc))
|
|
|
|
+ mpi_request.HostMSIxVectors = ioc->reply_queue_count;
|
|
mpi_request.SystemRequestFrameSize = cpu_to_le16(ioc->request_sz/4);
|
|
mpi_request.SystemRequestFrameSize = cpu_to_le16(ioc->request_sz/4);
|
|
mpi_request.ReplyDescriptorPostQueueDepth =
|
|
mpi_request.ReplyDescriptorPostQueueDepth =
|
|
cpu_to_le16(ioc->reply_post_queue_depth);
|
|
cpu_to_le16(ioc->reply_post_queue_depth);
|
|
@@ -3513,9 +3681,6 @@ _base_diag_reset(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
|
|
u32 hcb_size;
|
|
u32 hcb_size;
|
|
|
|
|
|
printk(MPT2SAS_INFO_FMT "sending diag reset !!\n", ioc->name);
|
|
printk(MPT2SAS_INFO_FMT "sending diag reset !!\n", ioc->name);
|
|
-
|
|
|
|
- _base_save_msix_table(ioc);
|
|
|
|
-
|
|
|
|
drsprintk(ioc, printk(MPT2SAS_INFO_FMT "clear interrupts\n",
|
|
drsprintk(ioc, printk(MPT2SAS_INFO_FMT "clear interrupts\n",
|
|
ioc->name));
|
|
ioc->name));
|
|
|
|
|
|
@@ -3611,7 +3776,6 @@ _base_diag_reset(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
|
|
goto out;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
|
|
- _base_restore_msix_table(ioc);
|
|
|
|
printk(MPT2SAS_INFO_FMT "diag reset: SUCCESS\n", ioc->name);
|
|
printk(MPT2SAS_INFO_FMT "diag reset: SUCCESS\n", ioc->name);
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
@@ -3692,6 +3856,9 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
|
|
u16 smid;
|
|
u16 smid;
|
|
struct _tr_list *delayed_tr, *delayed_tr_next;
|
|
struct _tr_list *delayed_tr, *delayed_tr_next;
|
|
u8 hide_flag;
|
|
u8 hide_flag;
|
|
|
|
+ struct adapter_reply_queue *reply_q;
|
|
|
|
+ long reply_post_free;
|
|
|
|
+ u32 reply_post_free_sz;
|
|
|
|
|
|
dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
|
|
dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
|
|
__func__));
|
|
__func__));
|
|
@@ -3757,19 +3924,43 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
|
|
ioc->reply_sz)
|
|
ioc->reply_sz)
|
|
ioc->reply_free[i] = cpu_to_le32(reply_address);
|
|
ioc->reply_free[i] = cpu_to_le32(reply_address);
|
|
|
|
|
|
|
|
+ /* initialize reply queues */
|
|
|
|
+ _base_assign_reply_queues(ioc);
|
|
|
|
+
|
|
/* initialize Reply Post Free Queue */
|
|
/* initialize Reply Post Free Queue */
|
|
- for (i = 0; i < ioc->reply_post_queue_depth; i++)
|
|
|
|
- ioc->reply_post_free[i].Words = cpu_to_le64(ULLONG_MAX);
|
|
|
|
|
|
+ reply_post_free = (long)ioc->reply_post_free;
|
|
|
|
+ reply_post_free_sz = ioc->reply_post_queue_depth *
|
|
|
|
+ sizeof(Mpi2DefaultReplyDescriptor_t);
|
|
|
|
+ list_for_each_entry(reply_q, &ioc->reply_queue_list, list) {
|
|
|
|
+ reply_q->reply_post_host_index = 0;
|
|
|
|
+ reply_q->reply_post_free = (Mpi2ReplyDescriptorsUnion_t *)
|
|
|
|
+ reply_post_free;
|
|
|
|
+ for (i = 0; i < ioc->reply_post_queue_depth; i++)
|
|
|
|
+ reply_q->reply_post_free[i].Words =
|
|
|
|
+ cpu_to_le64(ULLONG_MAX);
|
|
|
|
+ if (!_base_is_controller_msix_enabled(ioc))
|
|
|
|
+ goto skip_init_reply_post_free_queue;
|
|
|
|
+ reply_post_free += reply_post_free_sz;
|
|
|
|
+ }
|
|
|
|
+ skip_init_reply_post_free_queue:
|
|
|
|
|
|
r = _base_send_ioc_init(ioc, sleep_flag);
|
|
r = _base_send_ioc_init(ioc, sleep_flag);
|
|
if (r)
|
|
if (r)
|
|
return r;
|
|
return r;
|
|
|
|
|
|
- /* initialize the index's */
|
|
|
|
|
|
+ /* initialize reply free host index */
|
|
ioc->reply_free_host_index = ioc->reply_free_queue_depth - 1;
|
|
ioc->reply_free_host_index = ioc->reply_free_queue_depth - 1;
|
|
- ioc->reply_post_host_index = 0;
|
|
|
|
writel(ioc->reply_free_host_index, &ioc->chip->ReplyFreeHostIndex);
|
|
writel(ioc->reply_free_host_index, &ioc->chip->ReplyFreeHostIndex);
|
|
- writel(0, &ioc->chip->ReplyPostHostIndex);
|
|
|
|
|
|
+
|
|
|
|
+ /* initialize reply post host index */
|
|
|
|
+ list_for_each_entry(reply_q, &ioc->reply_queue_list, list) {
|
|
|
|
+ writel(reply_q->msix_index << MPI2_RPHI_MSIX_INDEX_SHIFT,
|
|
|
|
+ &ioc->chip->ReplyPostHostIndex);
|
|
|
|
+ if (!_base_is_controller_msix_enabled(ioc))
|
|
|
|
+ goto skip_init_reply_post_host_index;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ skip_init_reply_post_host_index:
|
|
|
|
|
|
_base_unmask_interrupts(ioc);
|
|
_base_unmask_interrupts(ioc);
|
|
r = _base_event_notification(ioc, sleep_flag);
|
|
r = _base_event_notification(ioc, sleep_flag);
|
|
@@ -3820,14 +4011,10 @@ mpt2sas_base_free_resources(struct MPT2SAS_ADAPTER *ioc)
|
|
ioc->shost_recovery = 1;
|
|
ioc->shost_recovery = 1;
|
|
_base_make_ioc_ready(ioc, CAN_SLEEP, SOFT_RESET);
|
|
_base_make_ioc_ready(ioc, CAN_SLEEP, SOFT_RESET);
|
|
ioc->shost_recovery = 0;
|
|
ioc->shost_recovery = 0;
|
|
- if (ioc->pci_irq) {
|
|
|
|
- synchronize_irq(pdev->irq);
|
|
|
|
- free_irq(ioc->pci_irq, ioc);
|
|
|
|
- }
|
|
|
|
|
|
+ _base_free_irq(ioc);
|
|
_base_disable_msix(ioc);
|
|
_base_disable_msix(ioc);
|
|
if (ioc->chip_phys)
|
|
if (ioc->chip_phys)
|
|
iounmap(ioc->chip);
|
|
iounmap(ioc->chip);
|
|
- ioc->pci_irq = -1;
|
|
|
|
ioc->chip_phys = 0;
|
|
ioc->chip_phys = 0;
|
|
pci_release_selected_regions(ioc->pdev, ioc->bars);
|
|
pci_release_selected_regions(ioc->pdev, ioc->bars);
|
|
pci_disable_pcie_error_reporting(pdev);
|
|
pci_disable_pcie_error_reporting(pdev);
|
|
@@ -3845,14 +4032,50 @@ int
|
|
mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
|
|
mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
|
|
{
|
|
{
|
|
int r, i;
|
|
int r, i;
|
|
|
|
+ int cpu_id, last_cpu_id = 0;
|
|
|
|
|
|
dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
|
|
dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
|
|
__func__));
|
|
__func__));
|
|
|
|
|
|
|
|
+ /* setup cpu_msix_table */
|
|
|
|
+ ioc->cpu_count = num_online_cpus();
|
|
|
|
+ for_each_online_cpu(cpu_id)
|
|
|
|
+ last_cpu_id = cpu_id;
|
|
|
|
+ ioc->cpu_msix_table_sz = last_cpu_id + 1;
|
|
|
|
+ ioc->cpu_msix_table = kzalloc(ioc->cpu_msix_table_sz, GFP_KERNEL);
|
|
|
|
+ ioc->reply_queue_count = 1;
|
|
|
|
+ if (!ioc->cpu_msix_table) {
|
|
|
|
+ dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "allocation for "
|
|
|
|
+ "cpu_msix_table failed!!!\n", ioc->name));
|
|
|
|
+ r = -ENOMEM;
|
|
|
|
+ goto out_free_resources;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (ioc->is_warpdrive) {
|
|
|
|
+ ioc->reply_post_host_index = kcalloc(ioc->cpu_msix_table_sz,
|
|
|
|
+ sizeof(resource_size_t *), GFP_KERNEL);
|
|
|
|
+ if (!ioc->reply_post_host_index) {
|
|
|
|
+ dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "allocation "
|
|
|
|
+ "for cpu_msix_table failed!!!\n", ioc->name));
|
|
|
|
+ r = -ENOMEM;
|
|
|
|
+ goto out_free_resources;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
r = mpt2sas_base_map_resources(ioc);
|
|
r = mpt2sas_base_map_resources(ioc);
|
|
if (r)
|
|
if (r)
|
|
return r;
|
|
return r;
|
|
|
|
|
|
|
|
+ if (ioc->is_warpdrive) {
|
|
|
|
+ ioc->reply_post_host_index[0] =
|
|
|
|
+ (resource_size_t *)&ioc->chip->ReplyPostHostIndex;
|
|
|
|
+
|
|
|
|
+ for (i = 1; i < ioc->cpu_msix_table_sz; i++)
|
|
|
|
+ ioc->reply_post_host_index[i] = (resource_size_t *)
|
|
|
|
+ ((u8 *)&ioc->chip->Doorbell + (0x4000 + ((i - 1)
|
|
|
|
+ * 4)));
|
|
|
|
+ }
|
|
|
|
+
|
|
pci_set_drvdata(ioc->pdev, ioc->shost);
|
|
pci_set_drvdata(ioc->pdev, ioc->shost);
|
|
r = _base_get_ioc_facts(ioc, CAN_SLEEP);
|
|
r = _base_get_ioc_facts(ioc, CAN_SLEEP);
|
|
if (r)
|
|
if (r)
|
|
@@ -3973,6 +4196,9 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
|
|
mpt2sas_base_free_resources(ioc);
|
|
mpt2sas_base_free_resources(ioc);
|
|
_base_release_memory_pools(ioc);
|
|
_base_release_memory_pools(ioc);
|
|
pci_set_drvdata(ioc->pdev, NULL);
|
|
pci_set_drvdata(ioc->pdev, NULL);
|
|
|
|
+ kfree(ioc->cpu_msix_table);
|
|
|
|
+ if (ioc->is_warpdrive)
|
|
|
|
+ kfree(ioc->reply_post_host_index);
|
|
kfree(ioc->pd_handles);
|
|
kfree(ioc->pd_handles);
|
|
kfree(ioc->tm_cmds.reply);
|
|
kfree(ioc->tm_cmds.reply);
|
|
kfree(ioc->transport_cmds.reply);
|
|
kfree(ioc->transport_cmds.reply);
|
|
@@ -4010,6 +4236,9 @@ mpt2sas_base_detach(struct MPT2SAS_ADAPTER *ioc)
|
|
mpt2sas_base_free_resources(ioc);
|
|
mpt2sas_base_free_resources(ioc);
|
|
_base_release_memory_pools(ioc);
|
|
_base_release_memory_pools(ioc);
|
|
pci_set_drvdata(ioc->pdev, NULL);
|
|
pci_set_drvdata(ioc->pdev, NULL);
|
|
|
|
+ kfree(ioc->cpu_msix_table);
|
|
|
|
+ if (ioc->is_warpdrive)
|
|
|
|
+ kfree(ioc->reply_post_host_index);
|
|
kfree(ioc->pd_handles);
|
|
kfree(ioc->pd_handles);
|
|
kfree(ioc->pfacts);
|
|
kfree(ioc->pfacts);
|
|
kfree(ioc->ctl_cmds.reply);
|
|
kfree(ioc->ctl_cmds.reply);
|