On 11/17/2015 11:20 AM, [email protected] wrote:
> From: Wen Xiong <[email protected]>
>
> ---
> drivers/scsi/ipr.c | 223
> +++++++++++++++++++++++++++++++++++++++++++++++++++-
> drivers/scsi/ipr.h | 17 ++++
> 2 files changed, 239 insertions(+), 1 deletions(-)
>
> diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
> index 536cd5a..ba92b16 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 = 2;
> static unsigned int ipr_fast_reboot;
> +static unsigned int ipr_cpu_map = 0;
No need to init to 0 since its a static variable.
> +
> +static unsigned int *ipr_used_cpu;
> +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:2)");
> 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, "Defines how to map CPUs to IRQ vectors per
> adapter");
Were are we going to document the syntax for this parameter?
> MODULE_LICENSE("GPL");
> MODULE_VERSION(IPR_DRIVER_VERSION);
>
> @@ -1053,6 +1060,18 @@ 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->set_cpu_affinity == IPR_SET_IO_CPU_AFFINITY
> + && 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;
> + }
> + }
I'm thinking we should be taking into account the NUMA topology here.
Seems like we'd want the affinity for an IRQ to be bound to a core and not a
CPU.
That way it could fire on any available SMT thread.
It seems like what the code here does now is done per SMT thread, so on a P8,
which
has 8 threads per core, don't we end up running everything on the first 2 cores?
Or am I not looking close enough at the code?
Thanks,
Brian
>
> if (ioa_cfg->hrrq_num == 1)
> hrrq = 0;
> @@ -4086,6 +4105,77 @@ 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 ",
> + map_per_cpu->cpu_id,
> + map_per_cpu->hrrq_id);
> + else
> + len += snprintf(buf + len, PAGE_SIZE-len,
> + "CPU %02d io_hrrq %02d "
> + "IRQ=%d\n", map_per_cpu->cpu_id,
> + 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 ssize_t
> +ipr_store_cpu_map_tbl(struct device *dev, struct device_attribute *attr,
> + const char *buf, size_t count)
> +{
> + int status = -EINVAL;
> + return status;
> +}
> +
> +static struct device_attribute ipr_cpu_map_attr = {
> + .attr = {
> + .name = "cpu_map",
> + .mode = S_IRUGO | S_IWUSR,
> + },
> + .show = ipr_show_cpu_map_tbl,
> + .store = ipr_store_cpu_map_tbl
> +};
> +
> static struct device_attribute *ipr_ioa_attrs[] = {
> &ipr_fw_version_attr,
> &ipr_log_level_attr,
> @@ -4095,6 +4185,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,
> };
>
> @@ -9333,6 +9424,8 @@ static void ipr_free_mem(struct ipr_ioa_cfg *ioa_cfg)
>
> ipr_free_dump(ioa_cfg);
> kfree(ioa_cfg->trace);
> + if (ioa_cfg->cpu_map)
> + kfree(ioa_cfg->cpu_map_tbl);
> }
>
> /**
> @@ -9352,9 +9445,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]);
>
> @@ -9585,11 +9682,35 @@ 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;
> + }
> +
> + if (ipr_used_cpu == NULL) {
> + ipr_used_cpu = kzalloc((sizeof(uint16_t) *
> + ipr_possible_cpu_cnt), GFP_KERNEL);
> + if (!ipr_used_cpu)
> + goto out_free_cpu_map_tbl;
> +
> + 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_cpu_map_tbl:
> + if (ioa_cfg->cpu_map)
> + kfree(ioa_cfg->cpu_map_tbl);
> +out_free_trace:
> + kfree(ioa_cfg->trace);
> out_free_hostrcb_dma:
> while (i-- > 0) {
> dma_free_coherent(&pdev->dev, sizeof(struct ipr_hostrcb),
> @@ -9791,6 +9912,94 @@ 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, uint32_t 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;
> + u32 cpu_idx = 0, hrrq_num = 0, next_cpu_id, i;
> +
> + if (!ioa_cfg->cpu_map)
> + return 1;
> +
> + 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++;
> + }
> + }
> +
> + ioa_cfg->set_cpu_affinity = IPR_SET_IO_CPU_AFFINITY;
> +
> + return 1;
> +}
> +
> static int ipr_enable_msix(struct ipr_ioa_cfg *ioa_cfg)
> {
> struct msix_entry entries[IPR_MAX_MSIX_VECTORS];
> @@ -10045,6 +10254,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);
>
> @@ -10106,6 +10316,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);
> @@ -10200,6 +10412,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;
> @@ -10644,9 +10859,14 @@ 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);
>
> + ipr_used_cpu = NULL;
> + for_each_present_cpu(cpu)
> + ipr_possible_cpu_cnt++;
> +
> register_reboot_notifier(&ipr_notifier);
> return pci_register_driver(&ipr_driver);
> }
> @@ -10663,6 +10883,7 @@ static void __exit ipr_exit(void)
> {
> unregister_reboot_notifier(&ipr_notifier);
> pci_unregister_driver(&ipr_driver);
> + kfree(ipr_used_cpu);
> }
>
> module_init(ipr_init);
> diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h
> index a34c7a5..c28a673 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,13 @@ struct ipr_ioa_cfg {
>
> u32 iopoll_weight;
>
> + u32 cpu_map;
> + struct ipr_vector_map_info *cpu_map_tbl;
> + u16 possible_cpu_cnt;
> + u16 set_cpu_affinity;
> +
> + u32 use_blk_mq;
> +
> }; /* struct ipr_ioa_cfg */
>
> struct ipr_cmnd {
>
--
Brian King
Power Linux I/O
IBM Linux Technology Center
------------------------------------------------------------------------------
Give your users amazing mobile app experiences with Intel XDK.
Use one codebase in this all-in-one HTML5 development environment.
Design, debug & build mobile apps & 2-D/3-D games for multiple OSs.
Then get your creation into app stores sooner, with many ways to monetize.
http://pubads.g.doubleclick.net/gampad/clk?id=254741551&iu=/4140
_______________________________________________
Iprdd-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/iprdd-devel