From: Wen Xiong <wenxi...@linux.vnet.ibm.com> Enable MSIX vector mapping to CPU affinity. This feature is enabled by setting ipr_cpu_map=1 when loading ipr module.
Signed-off-by: Wen Xiong <wenxi...@linux.vnet.ibm.com> --- drivers/scsi/ipr.c | 198 +++++++++++++++++++++++++++++++++++++++++++++++++++- drivers/scsi/ipr.h | 16 ++++ 2 files changed, 213 insertions(+), 1 deletions(-) diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index bb9ec50..468c690 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -100,6 +100,11 @@ static unsigned int ipr_max_devs = IPR_DEFAULT_SIS64_DEVS; static unsigned int ipr_dual_ioa_raid = 1; static unsigned int ipr_number_of_msix = 16; static unsigned int ipr_fast_reboot; +static unsigned int ipr_cpu_map = 1; + +static unsigned int ipr_used_cpu[NR_CPUS]; +static unsigned int ipr_possible_cpu_cnt; + static DEFINE_SPINLOCK(ipr_driver_lock); /* This table describes the differences between DMA controller chips */ @@ -224,6 +229,8 @@ module_param_named(number_of_msix, ipr_number_of_msix, int, 0); MODULE_PARM_DESC(number_of_msix, "Specify the number of MSIX interrupts to use on capable adapters (1 - 16). (default:16)"); module_param_named(fast_reboot, ipr_fast_reboot, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(fast_reboot, "Skip adapter shutdown during reboot. Set to 1 to enable. (default: 0)"); +module_param_named(cpu_map, ipr_cpu_map, int, 0); +MODULE_PARM_DESC(cpu_map, "Enable CPU affinity per adapter. (default:1)"); MODULE_LICENSE("GPL"); MODULE_VERSION(IPR_DRIVER_VERSION); @@ -1053,6 +1060,17 @@ static void ipr_send_blocking_cmd(struct ipr_cmnd *ipr_cmd, static int ipr_get_hrrq_index(struct ipr_ioa_cfg *ioa_cfg) { unsigned int hrrq; + struct ipr_vector_map_info *map_per_cpu; + u32 cpu; + + if (ioa_cfg->cpu_map && ioa_cfg->hrrq_num > 1) { + cpu = smp_processor_id(); + map_per_cpu = ioa_cfg->cpu_map_tbl; + if (cpu < ioa_cfg->possible_cpu_cnt) { + map_per_cpu += cpu; + return map_per_cpu->hrrq_id; + } + } if (ioa_cfg->hrrq_num == 1) hrrq = 0; @@ -4089,6 +4107,68 @@ static struct device_attribute ipr_ioa_fw_type_attr = { .show = ipr_show_fw_type }; +static ssize_t +ipr_show_cpu_map_tbl(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata; + struct ipr_vector_map_info *map_per_cpu; + int len = 0, show_current_cpu = 0; + + if (ioa_cfg->intr_flag != IPR_USE_MSIX) + return len; + + switch (ioa_cfg->cpu_map) { + case 0: + len += snprintf(buf + len, PAGE_SIZE - len, + "ipr driver cpu map: No mapping (%d)\n", + ioa_cfg->cpu_map); + return len; + case 1: + len += snprintf(buf + len, PAGE_SIZE - len, + "ipr driver cpu map: IRQ vector to CPU mapping (%d): " + "%d online CPUs\n", + ioa_cfg->cpu_map, + num_online_cpus()); + break; + } + + while (show_current_cpu < ioa_cfg->possible_cpu_cnt) { + map_per_cpu = &ioa_cfg->cpu_map_tbl[show_current_cpu]; + + if (map_per_cpu->irq_id == IPR_VECTOR_MAP_EMPTY) + len += snprintf(buf + len, PAGE_SIZE - len, + "CPU %02d io_hrrq %02d\n", + show_current_cpu, + map_per_cpu->hrrq_id); + else + len += snprintf(buf + len, PAGE_SIZE - len, + "CPU %02d io_hrrq %02d " + " IRQ=%d\n", + show_current_cpu, + map_per_cpu->hrrq_id, map_per_cpu->irq_id); + + show_current_cpu++; + + if (show_current_cpu < ioa_cfg->possible_cpu_cnt + && (len >= (PAGE_SIZE - 64))) { + len += snprintf(buf + len, PAGE_SIZE - len, "more...\n"); + break; + } + } + + return len; +} + +static struct device_attribute ipr_cpu_map_attr = { + .attr = { + .name = "cpu_map", + .mode = S_IRUGO | S_IWUSR, + }, + .show = ipr_show_cpu_map_tbl, +}; + static struct device_attribute *ipr_ioa_attrs[] = { &ipr_fw_version_attr, &ipr_log_level_attr, @@ -4098,6 +4178,7 @@ static struct device_attribute *ipr_ioa_attrs[] = { &ipr_update_fw_attr, &ipr_ioa_fw_type_attr, &ipr_iopoll_weight_attr, + &ipr_cpu_map_attr, NULL, }; @@ -9335,6 +9416,7 @@ static void ipr_free_mem(struct ipr_ioa_cfg *ioa_cfg) ipr_free_dump(ioa_cfg); kfree(ioa_cfg->trace); + kfree(ioa_cfg->cpu_map_tbl); } /** @@ -9354,9 +9436,13 @@ static void ipr_free_irqs(struct ipr_ioa_cfg *ioa_cfg) if (ioa_cfg->intr_flag == IPR_USE_MSI || ioa_cfg->intr_flag == IPR_USE_MSIX) { int i; - for (i = 0; i < ioa_cfg->nvectors; i++) + for (i = 0; i < ioa_cfg->nvectors; i++) { + if (ioa_cfg->cpu_map) + irq_set_affinity_hint( + ioa_cfg->vectors_info[i].vec, NULL); free_irq(ioa_cfg->vectors_info[i].vec, &ioa_cfg->hrrq[i]); + } } else free_irq(pdev->irq, &ioa_cfg->hrrq[0]); @@ -9587,11 +9673,25 @@ static int ipr_alloc_mem(struct ipr_ioa_cfg *ioa_cfg) if (!ioa_cfg->trace) goto out_free_hostrcb_dma; + if (ioa_cfg->cpu_map) { + ioa_cfg->cpu_map_tbl = + kzalloc(sizeof(struct ipr_vector_map_info) * + ioa_cfg->possible_cpu_cnt, GFP_KERNEL); + + if (!ioa_cfg->cpu_map_tbl) + goto out_free_trace; + } + + for (i = 0; i < ipr_possible_cpu_cnt; i++) + ipr_used_cpu[i] = IPR_VECTOR_MAP_EMPTY; + rc = 0; out: LEAVE; return rc; +out_free_trace: + kfree(ioa_cfg->trace); out_free_hostrcb_dma: while (i-- > 0) { dma_free_coherent(&pdev->dev, sizeof(struct ipr_hostrcb), @@ -9793,6 +9893,92 @@ static void ipr_wait_for_pci_err_recovery(struct ipr_ioa_cfg *ioa_cfg) } } +static int +ipr_find_next_free_cpu(struct ipr_ioa_cfg *ioa_cfg, u32 cpu_id) +{ + struct ipr_vector_map_info *map_per_cpu; + int i; + + map_per_cpu = ioa_cfg->cpu_map_tbl; + for (i = 0; i < ioa_cfg->possible_cpu_cnt; i++) { + if (cpu_online(i)) { + if ((map_per_cpu->irq_id == IPR_VECTOR_MAP_EMPTY) && + (ipr_used_cpu[i] == IPR_VECTOR_MAP_EMPTY) && + (map_per_cpu->cpu_id == cpu_id)) + return i; + } + map_per_cpu++; + } + + return IPR_VECTOR_MAP_EMPTY; +} + +static int ipr_set_cpu_affinity_for_hrrq(struct ipr_ioa_cfg *ioa_cfg, + int vectors) +{ + struct ipr_vector_map_info *map_per_cpu; + int cpu_idx = 0, hrrq_num, next_cpu_id, i; + + memset(ioa_cfg->cpu_map_tbl, 0xff, + (sizeof(struct ipr_vector_map_info) * + ioa_cfg->possible_cpu_cnt)); + + map_per_cpu = ioa_cfg->cpu_map_tbl; + for (i = 0; i < ioa_cfg->possible_cpu_cnt; i++, map_per_cpu++) + map_per_cpu->cpu_id = i; + + for (i = 0; i < ipr_possible_cpu_cnt; i++) { + if (ipr_used_cpu[i] == IPR_VECTOR_MAP_EMPTY) { + cpu_idx = i; + break; + } + } + + hrrq_num = 0; + for (i = 0; i < vectors; i++) { + map_per_cpu = ioa_cfg->cpu_map_tbl; + next_cpu_id = ipr_find_next_free_cpu(ioa_cfg, cpu_idx); + + if (next_cpu_id == IPR_VECTOR_MAP_EMPTY) { + int j; + + for (j = 0; j < i; j++) + irq_set_affinity_hint( + ioa_cfg->vectors_info[j].vec, NULL); + ioa_cfg->cpu_map = 0; + dev_info(&ioa_cfg->pdev->dev, "Cannot set cpu affinity\n"); + return 0; + } + + map_per_cpu += next_cpu_id; + ipr_used_cpu[next_cpu_id] = next_cpu_id; + + map_per_cpu->irq_id = ioa_cfg->vectors_info[i].vec; + map_per_cpu->hrrq_id = hrrq_num; + irq_set_affinity_hint(ioa_cfg->vectors_info[i].vec, + get_cpu_mask(next_cpu_id)); + cpu_idx++; + hrrq_num++; + } + + hrrq_num = 0; + if (vectors < ioa_cfg->possible_cpu_cnt) { + map_per_cpu = ioa_cfg->cpu_map_tbl; + for (i = 0; i < ioa_cfg->possible_cpu_cnt; i++) { + if (map_per_cpu->hrrq_id == IPR_VECTOR_MAP_EMPTY) { + map_per_cpu->hrrq_id = hrrq_num; + hrrq_num++; + } + + if (hrrq_num == ioa_cfg->hrrq_num) + hrrq_num = 0; + map_per_cpu++; + } + } + + return 1; +} + static int ipr_enable_msix(struct ipr_ioa_cfg *ioa_cfg) { struct msix_entry entries[IPR_MAX_MSIX_VECTORS]; @@ -10047,6 +10233,7 @@ static int ipr_probe_ioa(struct pci_dev *pdev, ioa_cfg->hdw_dma_regs = ipr_regs; ioa_cfg->hdw_dma_regs_pci = ipr_regs_pci; ioa_cfg->ioa_mailbox = ioa_cfg->chip_cfg->mailbox + ipr_regs; + ioa_cfg->cpu_map = ipr_cpu_map; ipr_init_regs(ioa_cfg); @@ -10108,6 +10295,8 @@ static int ipr_probe_ioa(struct pci_dev *pdev, } } + ioa_cfg->possible_cpu_cnt = ipr_possible_cpu_cnt; + if (ioa_cfg->intr_flag == IPR_USE_MSI || ioa_cfg->intr_flag == IPR_USE_MSIX) { rc = ipr_test_msi(ioa_cfg, pdev); @@ -10202,6 +10391,9 @@ static int ipr_probe_ioa(struct pci_dev *pdev, goto cleanup_nolog; } + if (ioa_cfg->cpu_map) + ipr_set_cpu_affinity_for_hrrq(ioa_cfg, ioa_cfg->nvectors); + if ((dev_id->driver_data & IPR_USE_PCI_WARM_RESET) || (dev_id->device == PCI_DEVICE_ID_IBM_OBSIDIAN_E && !ioa_cfg->revid)) { ioa_cfg->needs_warm_reset = 1; @@ -10645,9 +10837,13 @@ static struct notifier_block ipr_notifier = { **/ static int __init ipr_init(void) { + int cpu; ipr_info("IBM Power RAID SCSI Device Driver version: %s %s\n", IPR_DRIVER_VERSION, IPR_DRIVER_DATE); + for_each_present_cpu(cpu) + ipr_possible_cpu_cnt++; + register_reboot_notifier(&ipr_notifier); return pci_register_driver(&ipr_driver); } diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h index 56c5706..8f8ab6b 100644 --- a/drivers/scsi/ipr.h +++ b/drivers/scsi/ipr.h @@ -1464,6 +1464,16 @@ enum ipr_sdt_state { DUMP_OBTAINED }; +#define IPR_VECTOR_MAP_EMPTY 0xffff +#define IPR_SET_IO_CPU_AFFINITY 0x1 + +/* IRQ vector to CPU mapping when set CPU affinity*/ +struct ipr_vector_map_info { + u16 cpu_id; + u16 irq_id; + u16 hrrq_id; +}; + /* Per-controller data */ struct ipr_ioa_cfg { char eye_catcher[8]; @@ -1595,6 +1605,12 @@ struct ipr_ioa_cfg { u32 iopoll_weight; + u32 cpu_map; + struct ipr_vector_map_info *cpu_map_tbl; + u16 possible_cpu_cnt; + + u32 use_blk_mq; + }; /* struct ipr_ioa_cfg */ struct ipr_cmnd { -- 1.7.1 ------------------------------------------------------------------------------ Transform Data into Opportunity. Accelerate data analysis in your applications with Intel Data Analytics Acceleration Library. Click to learn more. http://pubads.g.doubleclick.net/gampad/clk?id=278785111&iu=/4140 _______________________________________________ Iprdd-devel mailing list Iprdd-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/iprdd-devel