diff options
author | James Smart <james.smart@emulex.com> | 2013-04-17 20:19:16 -0400 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2013-05-02 16:10:25 -0400 |
commit | 7bb03bbf1e8c0cb17309ac8a6dae6a54ebdfe66e (patch) | |
tree | 1fb2d70836583981000105a6b6884a746fcfea03 /drivers/scsi/lpfc | |
parent | 6a485eb9a921cd1276fc63b4967e6b713fffb6f3 (diff) |
[SCSI] lpfc 8.3.39: Fixed driver vector mapping to CPU affinity
Signed-off-by: James Smart <james.smart@emulex.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi/lpfc')
-rw-r--r-- | drivers/scsi/lpfc/lpfc.h | 1 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_attr.c | 137 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_hw4.h | 5 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_init.c | 322 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_sli.c | 22 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_sli4.h | 16 |
6 files changed, 488 insertions, 15 deletions
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 2d2261f4eab0..bcc56cac4fd8 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h | |||
@@ -709,6 +709,7 @@ struct lpfc_hba { | |||
709 | uint32_t cfg_poll_tmo; | 709 | uint32_t cfg_poll_tmo; |
710 | uint32_t cfg_use_msi; | 710 | uint32_t cfg_use_msi; |
711 | uint32_t cfg_fcp_imax; | 711 | uint32_t cfg_fcp_imax; |
712 | uint32_t cfg_fcp_cpu_map; | ||
712 | uint32_t cfg_fcp_wq_count; | 713 | uint32_t cfg_fcp_wq_count; |
713 | uint32_t cfg_fcp_eq_count; | 714 | uint32_t cfg_fcp_eq_count; |
714 | uint32_t cfg_fcp_io_channel; | 715 | uint32_t cfg_fcp_io_channel; |
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 57f1ad848edc..3c5625b8b1f4 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c | |||
@@ -3799,6 +3799,141 @@ lpfc_fcp_imax_init(struct lpfc_hba *phba, int val) | |||
3799 | static DEVICE_ATTR(lpfc_fcp_imax, S_IRUGO | S_IWUSR, | 3799 | static DEVICE_ATTR(lpfc_fcp_imax, S_IRUGO | S_IWUSR, |
3800 | lpfc_fcp_imax_show, lpfc_fcp_imax_store); | 3800 | lpfc_fcp_imax_show, lpfc_fcp_imax_store); |
3801 | 3801 | ||
3802 | /** | ||
3803 | * lpfc_state_show - Display current driver CPU affinity | ||
3804 | * @dev: class converted to a Scsi_host structure. | ||
3805 | * @attr: device attribute, not used. | ||
3806 | * @buf: on return contains text describing the state of the link. | ||
3807 | * | ||
3808 | * Returns: size of formatted string. | ||
3809 | **/ | ||
3810 | static ssize_t | ||
3811 | lpfc_fcp_cpu_map_show(struct device *dev, struct device_attribute *attr, | ||
3812 | char *buf) | ||
3813 | { | ||
3814 | struct Scsi_Host *shost = class_to_shost(dev); | ||
3815 | struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata; | ||
3816 | struct lpfc_hba *phba = vport->phba; | ||
3817 | struct lpfc_vector_map_info *cpup; | ||
3818 | int idx, len = 0; | ||
3819 | |||
3820 | if ((phba->sli_rev != LPFC_SLI_REV4) || | ||
3821 | (phba->intr_type != MSIX)) | ||
3822 | return len; | ||
3823 | |||
3824 | switch (phba->cfg_fcp_cpu_map) { | ||
3825 | case 0: | ||
3826 | len += snprintf(buf + len, PAGE_SIZE-len, | ||
3827 | "fcp_cpu_map: No mapping (%d)\n", | ||
3828 | phba->cfg_fcp_cpu_map); | ||
3829 | return len; | ||
3830 | case 1: | ||
3831 | len += snprintf(buf + len, PAGE_SIZE-len, | ||
3832 | "fcp_cpu_map: HBA centric mapping (%d): " | ||
3833 | "%d online CPUs\n", | ||
3834 | phba->cfg_fcp_cpu_map, | ||
3835 | phba->sli4_hba.num_online_cpu); | ||
3836 | break; | ||
3837 | case 2: | ||
3838 | len += snprintf(buf + len, PAGE_SIZE-len, | ||
3839 | "fcp_cpu_map: Driver centric mapping (%d): " | ||
3840 | "%d online CPUs\n", | ||
3841 | phba->cfg_fcp_cpu_map, | ||
3842 | phba->sli4_hba.num_online_cpu); | ||
3843 | break; | ||
3844 | } | ||
3845 | |||
3846 | cpup = phba->sli4_hba.cpu_map; | ||
3847 | for (idx = 0; idx < phba->sli4_hba.num_present_cpu; idx++) { | ||
3848 | if (cpup->irq == LPFC_VECTOR_MAP_EMPTY) | ||
3849 | len += snprintf(buf + len, PAGE_SIZE-len, | ||
3850 | "CPU %02d io_chan %02d " | ||
3851 | "physid %d coreid %d\n", | ||
3852 | idx, cpup->channel_id, cpup->phys_id, | ||
3853 | cpup->core_id); | ||
3854 | else | ||
3855 | len += snprintf(buf + len, PAGE_SIZE-len, | ||
3856 | "CPU %02d io_chan %02d " | ||
3857 | "physid %d coreid %d IRQ %d\n", | ||
3858 | idx, cpup->channel_id, cpup->phys_id, | ||
3859 | cpup->core_id, cpup->irq); | ||
3860 | |||
3861 | cpup++; | ||
3862 | } | ||
3863 | return len; | ||
3864 | } | ||
3865 | |||
3866 | /** | ||
3867 | * lpfc_fcp_cpu_map_store - Change CPU affinity of driver vectors | ||
3868 | * @dev: class device that is converted into a Scsi_host. | ||
3869 | * @attr: device attribute, not used. | ||
3870 | * @buf: one or more lpfc_polling_flags values. | ||
3871 | * @count: not used. | ||
3872 | * | ||
3873 | * Returns: | ||
3874 | * -EINVAL - Not implemented yet. | ||
3875 | **/ | ||
3876 | static ssize_t | ||
3877 | lpfc_fcp_cpu_map_store(struct device *dev, struct device_attribute *attr, | ||
3878 | const char *buf, size_t count) | ||
3879 | { | ||
3880 | int status = -EINVAL; | ||
3881 | return status; | ||
3882 | } | ||
3883 | |||
3884 | /* | ||
3885 | # lpfc_fcp_cpu_map: Defines how to map CPUs to IRQ vectors | ||
3886 | # for the HBA. | ||
3887 | # | ||
3888 | # Value range is [0 to 2]. Default value is LPFC_DRIVER_CPU_MAP (2). | ||
3889 | # 0 - Do not affinitze IRQ vectors | ||
3890 | # 1 - Affintize HBA vectors with respect to each HBA | ||
3891 | # (start with CPU0 for each HBA) | ||
3892 | # 2 - Affintize HBA vectors with respect to the entire driver | ||
3893 | # (round robin thru all CPUs across all HBAs) | ||
3894 | */ | ||
3895 | static int lpfc_fcp_cpu_map = LPFC_DRIVER_CPU_MAP; | ||
3896 | module_param(lpfc_fcp_cpu_map, int, S_IRUGO|S_IWUSR); | ||
3897 | MODULE_PARM_DESC(lpfc_fcp_cpu_map, | ||
3898 | "Defines how to map CPUs to IRQ vectors per HBA"); | ||
3899 | |||
3900 | /** | ||
3901 | * lpfc_fcp_cpu_map_init - Set the initial sr-iov virtual function enable | ||
3902 | * @phba: lpfc_hba pointer. | ||
3903 | * @val: link speed value. | ||
3904 | * | ||
3905 | * Description: | ||
3906 | * If val is in a valid range [0-2], then affinitze the adapter's | ||
3907 | * MSIX vectors. | ||
3908 | * | ||
3909 | * Returns: | ||
3910 | * zero if val saved. | ||
3911 | * -EINVAL val out of range | ||
3912 | **/ | ||
3913 | static int | ||
3914 | lpfc_fcp_cpu_map_init(struct lpfc_hba *phba, int val) | ||
3915 | { | ||
3916 | if (phba->sli_rev != LPFC_SLI_REV4) { | ||
3917 | phba->cfg_fcp_cpu_map = 0; | ||
3918 | return 0; | ||
3919 | } | ||
3920 | |||
3921 | if (val >= LPFC_MIN_CPU_MAP && val <= LPFC_MAX_CPU_MAP) { | ||
3922 | phba->cfg_fcp_cpu_map = val; | ||
3923 | return 0; | ||
3924 | } | ||
3925 | |||
3926 | lpfc_printf_log(phba, KERN_ERR, LOG_INIT, | ||
3927 | "3326 fcp_cpu_map: %d out of range, using default\n", | ||
3928 | val); | ||
3929 | phba->cfg_fcp_cpu_map = LPFC_DRIVER_CPU_MAP; | ||
3930 | |||
3931 | return 0; | ||
3932 | } | ||
3933 | |||
3934 | static DEVICE_ATTR(lpfc_fcp_cpu_map, S_IRUGO | S_IWUSR, | ||
3935 | lpfc_fcp_cpu_map_show, lpfc_fcp_cpu_map_store); | ||
3936 | |||
3802 | /* | 3937 | /* |
3803 | # lpfc_fcp_class: Determines FC class to use for the FCP protocol. | 3938 | # lpfc_fcp_class: Determines FC class to use for the FCP protocol. |
3804 | # Value range is [2,3]. Default value is 3. | 3939 | # Value range is [2,3]. Default value is 3. |
@@ -4154,6 +4289,7 @@ struct device_attribute *lpfc_hba_attrs[] = { | |||
4154 | &dev_attr_lpfc_poll_tmo, | 4289 | &dev_attr_lpfc_poll_tmo, |
4155 | &dev_attr_lpfc_use_msi, | 4290 | &dev_attr_lpfc_use_msi, |
4156 | &dev_attr_lpfc_fcp_imax, | 4291 | &dev_attr_lpfc_fcp_imax, |
4292 | &dev_attr_lpfc_fcp_cpu_map, | ||
4157 | &dev_attr_lpfc_fcp_wq_count, | 4293 | &dev_attr_lpfc_fcp_wq_count, |
4158 | &dev_attr_lpfc_fcp_eq_count, | 4294 | &dev_attr_lpfc_fcp_eq_count, |
4159 | &dev_attr_lpfc_fcp_io_channel, | 4295 | &dev_attr_lpfc_fcp_io_channel, |
@@ -5136,6 +5272,7 @@ lpfc_get_cfgparam(struct lpfc_hba *phba) | |||
5136 | lpfc_enable_rrq_init(phba, lpfc_enable_rrq); | 5272 | lpfc_enable_rrq_init(phba, lpfc_enable_rrq); |
5137 | lpfc_use_msi_init(phba, lpfc_use_msi); | 5273 | lpfc_use_msi_init(phba, lpfc_use_msi); |
5138 | lpfc_fcp_imax_init(phba, lpfc_fcp_imax); | 5274 | lpfc_fcp_imax_init(phba, lpfc_fcp_imax); |
5275 | lpfc_fcp_cpu_map_init(phba, lpfc_fcp_cpu_map); | ||
5139 | lpfc_fcp_wq_count_init(phba, lpfc_fcp_wq_count); | 5276 | lpfc_fcp_wq_count_init(phba, lpfc_fcp_wq_count); |
5140 | lpfc_fcp_eq_count_init(phba, lpfc_fcp_eq_count); | 5277 | lpfc_fcp_eq_count_init(phba, lpfc_fcp_eq_count); |
5141 | lpfc_fcp_io_channel_init(phba, lpfc_fcp_io_channel); | 5278 | lpfc_fcp_io_channel_init(phba, lpfc_fcp_io_channel); |
diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h index 42660c97119e..713a4613ec3a 100644 --- a/drivers/scsi/lpfc/lpfc_hw4.h +++ b/drivers/scsi/lpfc/lpfc_hw4.h | |||
@@ -200,6 +200,11 @@ struct lpfc_sli_intf { | |||
200 | #define LPFC_MAX_IMAX 5000000 | 200 | #define LPFC_MAX_IMAX 5000000 |
201 | #define LPFC_DEF_IMAX 50000 | 201 | #define LPFC_DEF_IMAX 50000 |
202 | 202 | ||
203 | #define LPFC_MIN_CPU_MAP 0 | ||
204 | #define LPFC_MAX_CPU_MAP 2 | ||
205 | #define LPFC_HBA_CPU_MAP 1 | ||
206 | #define LPFC_DRIVER_CPU_MAP 2 /* Default */ | ||
207 | |||
203 | /* PORT_CAPABILITIES constants. */ | 208 | /* PORT_CAPABILITIES constants. */ |
204 | #define LPFC_MAX_SUPPORTED_PAGES 8 | 209 | #define LPFC_MAX_SUPPORTED_PAGES 8 |
205 | 210 | ||
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 7af1eabf5ebc..3b574a0698d9 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <linux/slab.h> | 33 | #include <linux/slab.h> |
34 | #include <linux/firmware.h> | 34 | #include <linux/firmware.h> |
35 | #include <linux/miscdevice.h> | 35 | #include <linux/miscdevice.h> |
36 | #include <linux/percpu.h> | ||
36 | 37 | ||
37 | #include <scsi/scsi.h> | 38 | #include <scsi/scsi.h> |
38 | #include <scsi/scsi_device.h> | 39 | #include <scsi/scsi_device.h> |
@@ -58,6 +59,9 @@ char *_dump_buf_dif; | |||
58 | unsigned long _dump_buf_dif_order; | 59 | unsigned long _dump_buf_dif_order; |
59 | spinlock_t _dump_buf_lock; | 60 | spinlock_t _dump_buf_lock; |
60 | 61 | ||
62 | /* Used when mapping IRQ vectors in a driver centric manner */ | ||
63 | uint16_t lpfc_used_cpu[LPFC_MAX_CPU]; | ||
64 | |||
61 | static void lpfc_get_hba_model_desc(struct lpfc_hba *, uint8_t *, uint8_t *); | 65 | static void lpfc_get_hba_model_desc(struct lpfc_hba *, uint8_t *, uint8_t *); |
62 | static int lpfc_post_rcv_buf(struct lpfc_hba *); | 66 | static int lpfc_post_rcv_buf(struct lpfc_hba *); |
63 | static int lpfc_sli4_queue_verify(struct lpfc_hba *); | 67 | static int lpfc_sli4_queue_verify(struct lpfc_hba *); |
@@ -4861,6 +4865,7 @@ lpfc_sli_driver_resource_unset(struct lpfc_hba *phba) | |||
4861 | static int | 4865 | static int |
4862 | lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) | 4866 | lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) |
4863 | { | 4867 | { |
4868 | struct lpfc_vector_map_info *cpup; | ||
4864 | struct lpfc_sli *psli; | 4869 | struct lpfc_sli *psli; |
4865 | LPFC_MBOXQ_t *mboxq; | 4870 | LPFC_MBOXQ_t *mboxq; |
4866 | int rc, i, hbq_count, max_buf_size; | 4871 | int rc, i, hbq_count, max_buf_size; |
@@ -5198,6 +5203,26 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) | |||
5198 | goto out_free_fcp_eq_hdl; | 5203 | goto out_free_fcp_eq_hdl; |
5199 | } | 5204 | } |
5200 | 5205 | ||
5206 | phba->sli4_hba.cpu_map = kzalloc((sizeof(struct lpfc_vector_map_info) * | ||
5207 | phba->sli4_hba.num_present_cpu), | ||
5208 | GFP_KERNEL); | ||
5209 | if (!phba->sli4_hba.cpu_map) { | ||
5210 | lpfc_printf_log(phba, KERN_ERR, LOG_INIT, | ||
5211 | "3327 Failed allocate memory for msi-x " | ||
5212 | "interrupt vector mapping\n"); | ||
5213 | rc = -ENOMEM; | ||
5214 | goto out_free_msix; | ||
5215 | } | ||
5216 | /* Initialize io channels for round robin */ | ||
5217 | cpup = phba->sli4_hba.cpu_map; | ||
5218 | rc = 0; | ||
5219 | for (i = 0; i < phba->sli4_hba.num_present_cpu; i++) { | ||
5220 | cpup->channel_id = rc; | ||
5221 | rc++; | ||
5222 | if (rc >= phba->cfg_fcp_io_channel) | ||
5223 | rc = 0; | ||
5224 | } | ||
5225 | |||
5201 | /* | 5226 | /* |
5202 | * Enable sr-iov virtual functions if supported and configured | 5227 | * Enable sr-iov virtual functions if supported and configured |
5203 | * through the module parameter. | 5228 | * through the module parameter. |
@@ -5217,6 +5242,8 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) | |||
5217 | 5242 | ||
5218 | return 0; | 5243 | return 0; |
5219 | 5244 | ||
5245 | out_free_msix: | ||
5246 | kfree(phba->sli4_hba.msix_entries); | ||
5220 | out_free_fcp_eq_hdl: | 5247 | out_free_fcp_eq_hdl: |
5221 | kfree(phba->sli4_hba.fcp_eq_hdl); | 5248 | kfree(phba->sli4_hba.fcp_eq_hdl); |
5222 | out_free_fcf_rr_bmask: | 5249 | out_free_fcf_rr_bmask: |
@@ -5246,6 +5273,11 @@ lpfc_sli4_driver_resource_unset(struct lpfc_hba *phba) | |||
5246 | { | 5273 | { |
5247 | struct lpfc_fcf_conn_entry *conn_entry, *next_conn_entry; | 5274 | struct lpfc_fcf_conn_entry *conn_entry, *next_conn_entry; |
5248 | 5275 | ||
5276 | /* Free memory allocated for msi-x interrupt vector to CPU mapping */ | ||
5277 | kfree(phba->sli4_hba.cpu_map); | ||
5278 | phba->sli4_hba.num_present_cpu = 0; | ||
5279 | phba->sli4_hba.num_online_cpu = 0; | ||
5280 | |||
5249 | /* Free memory allocated for msi-x interrupt vector entries */ | 5281 | /* Free memory allocated for msi-x interrupt vector entries */ |
5250 | kfree(phba->sli4_hba.msix_entries); | 5282 | kfree(phba->sli4_hba.msix_entries); |
5251 | 5283 | ||
@@ -6792,6 +6824,7 @@ lpfc_sli4_queue_verify(struct lpfc_hba *phba) | |||
6792 | int cfg_fcp_io_channel; | 6824 | int cfg_fcp_io_channel; |
6793 | uint32_t cpu; | 6825 | uint32_t cpu; |
6794 | uint32_t i = 0; | 6826 | uint32_t i = 0; |
6827 | uint32_t j = 0; | ||
6795 | 6828 | ||
6796 | 6829 | ||
6797 | /* | 6830 | /* |
@@ -6802,15 +6835,21 @@ lpfc_sli4_queue_verify(struct lpfc_hba *phba) | |||
6802 | /* Sanity check on HBA EQ parameters */ | 6835 | /* Sanity check on HBA EQ parameters */ |
6803 | cfg_fcp_io_channel = phba->cfg_fcp_io_channel; | 6836 | cfg_fcp_io_channel = phba->cfg_fcp_io_channel; |
6804 | 6837 | ||
6805 | /* It doesn't make sense to have more io channels then CPUs */ | 6838 | /* It doesn't make sense to have more io channels then online CPUs */ |
6806 | for_each_online_cpu(cpu) { | 6839 | for_each_present_cpu(cpu) { |
6807 | i++; | 6840 | if (cpu_online(cpu)) |
6841 | i++; | ||
6842 | j++; | ||
6808 | } | 6843 | } |
6844 | phba->sli4_hba.num_online_cpu = i; | ||
6845 | phba->sli4_hba.num_present_cpu = j; | ||
6846 | |||
6809 | if (i < cfg_fcp_io_channel) { | 6847 | if (i < cfg_fcp_io_channel) { |
6810 | lpfc_printf_log(phba, | 6848 | lpfc_printf_log(phba, |
6811 | KERN_ERR, LOG_INIT, | 6849 | KERN_ERR, LOG_INIT, |
6812 | "3188 Reducing IO channels to match number of " | 6850 | "3188 Reducing IO channels to match number of " |
6813 | "CPUs: from %d to %d\n", cfg_fcp_io_channel, i); | 6851 | "online CPUs: from %d to %d\n", |
6852 | cfg_fcp_io_channel, i); | ||
6814 | cfg_fcp_io_channel = i; | 6853 | cfg_fcp_io_channel = i; |
6815 | } | 6854 | } |
6816 | 6855 | ||
@@ -8310,6 +8349,269 @@ lpfc_sli_disable_intr(struct lpfc_hba *phba) | |||
8310 | } | 8349 | } |
8311 | 8350 | ||
8312 | /** | 8351 | /** |
8352 | * lpfc_find_next_cpu - Find next available CPU that matches the phys_id | ||
8353 | * @phba: pointer to lpfc hba data structure. | ||
8354 | * | ||
8355 | * Find next available CPU to use for IRQ to CPU affinity. | ||
8356 | */ | ||
8357 | static int | ||
8358 | lpfc_find_next_cpu(struct lpfc_hba *phba, uint32_t phys_id) | ||
8359 | { | ||
8360 | struct lpfc_vector_map_info *cpup; | ||
8361 | int cpu; | ||
8362 | |||
8363 | cpup = phba->sli4_hba.cpu_map; | ||
8364 | for (cpu = 0; cpu < phba->sli4_hba.num_present_cpu; cpu++) { | ||
8365 | /* CPU must be online */ | ||
8366 | if (cpu_online(cpu)) { | ||
8367 | if ((cpup->irq == LPFC_VECTOR_MAP_EMPTY) && | ||
8368 | (lpfc_used_cpu[cpu] == LPFC_VECTOR_MAP_EMPTY) && | ||
8369 | (cpup->phys_id == phys_id)) { | ||
8370 | return cpu; | ||
8371 | } | ||
8372 | } | ||
8373 | cpup++; | ||
8374 | } | ||
8375 | |||
8376 | /* | ||
8377 | * If we get here, we have used ALL CPUs for the specific | ||
8378 | * phys_id. Now we need to clear out lpfc_used_cpu and start | ||
8379 | * reusing CPUs. | ||
8380 | */ | ||
8381 | |||
8382 | for (cpu = 0; cpu < phba->sli4_hba.num_present_cpu; cpu++) { | ||
8383 | if (lpfc_used_cpu[cpu] == phys_id) | ||
8384 | lpfc_used_cpu[cpu] = LPFC_VECTOR_MAP_EMPTY; | ||
8385 | } | ||
8386 | |||
8387 | cpup = phba->sli4_hba.cpu_map; | ||
8388 | for (cpu = 0; cpu < phba->sli4_hba.num_present_cpu; cpu++) { | ||
8389 | /* CPU must be online */ | ||
8390 | if (cpu_online(cpu)) { | ||
8391 | if ((cpup->irq == LPFC_VECTOR_MAP_EMPTY) && | ||
8392 | (cpup->phys_id == phys_id)) { | ||
8393 | return cpu; | ||
8394 | } | ||
8395 | } | ||
8396 | cpup++; | ||
8397 | } | ||
8398 | return LPFC_VECTOR_MAP_EMPTY; | ||
8399 | } | ||
8400 | |||
8401 | /** | ||
8402 | * lpfc_sli4_set_affinity - Set affinity for HBA IRQ vectors | ||
8403 | * @phba: pointer to lpfc hba data structure. | ||
8404 | * @vectors: number of HBA vectors | ||
8405 | * | ||
8406 | * Affinitize MSIX IRQ vectors to CPUs. Try to equally spread vector | ||
8407 | * affinization across multple physical CPUs (numa nodes). | ||
8408 | * In addition, this routine will assign an IO channel for each CPU | ||
8409 | * to use when issuing I/Os. | ||
8410 | */ | ||
8411 | static int | ||
8412 | lpfc_sli4_set_affinity(struct lpfc_hba *phba, int vectors) | ||
8413 | { | ||
8414 | int i, idx, saved_chann, used_chann, cpu, phys_id; | ||
8415 | int max_phys_id, num_io_channel, first_cpu; | ||
8416 | struct lpfc_vector_map_info *cpup; | ||
8417 | #ifdef CONFIG_X86 | ||
8418 | struct cpuinfo_x86 *cpuinfo; | ||
8419 | #endif | ||
8420 | struct cpumask *mask; | ||
8421 | uint8_t chann[LPFC_FCP_IO_CHAN_MAX+1]; | ||
8422 | |||
8423 | /* If there is no mapping, just return */ | ||
8424 | if (!phba->cfg_fcp_cpu_map) | ||
8425 | return 1; | ||
8426 | |||
8427 | /* Init cpu_map array */ | ||
8428 | memset(phba->sli4_hba.cpu_map, 0xff, | ||
8429 | (sizeof(struct lpfc_vector_map_info) * | ||
8430 | phba->sli4_hba.num_present_cpu)); | ||
8431 | |||
8432 | max_phys_id = 0; | ||
8433 | phys_id = 0; | ||
8434 | num_io_channel = 0; | ||
8435 | first_cpu = LPFC_VECTOR_MAP_EMPTY; | ||
8436 | |||
8437 | /* Update CPU map with physical id and core id of each CPU */ | ||
8438 | cpup = phba->sli4_hba.cpu_map; | ||
8439 | for (cpu = 0; cpu < phba->sli4_hba.num_present_cpu; cpu++) { | ||
8440 | #ifdef CONFIG_X86 | ||
8441 | cpuinfo = &cpu_data(cpu); | ||
8442 | cpup->phys_id = cpuinfo->phys_proc_id; | ||
8443 | cpup->core_id = cpuinfo->cpu_core_id; | ||
8444 | #else | ||
8445 | /* No distinction between CPUs for other platforms */ | ||
8446 | cpup->phys_id = 0; | ||
8447 | cpup->core_id = 0; | ||
8448 | #endif | ||
8449 | |||
8450 | lpfc_printf_log(phba, KERN_INFO, LOG_INIT, | ||
8451 | "3328 CPU physid %d coreid %d\n", | ||
8452 | cpup->phys_id, cpup->core_id); | ||
8453 | |||
8454 | if (cpup->phys_id > max_phys_id) | ||
8455 | max_phys_id = cpup->phys_id; | ||
8456 | cpup++; | ||
8457 | } | ||
8458 | |||
8459 | /* Now associate the HBA vectors with specific CPUs */ | ||
8460 | for (idx = 0; idx < vectors; idx++) { | ||
8461 | cpup = phba->sli4_hba.cpu_map; | ||
8462 | cpu = lpfc_find_next_cpu(phba, phys_id); | ||
8463 | if (cpu == LPFC_VECTOR_MAP_EMPTY) { | ||
8464 | |||
8465 | /* Try for all phys_id's */ | ||
8466 | for (i = 1; i < max_phys_id; i++) { | ||
8467 | phys_id++; | ||
8468 | if (phys_id > max_phys_id) | ||
8469 | phys_id = 0; | ||
8470 | cpu = lpfc_find_next_cpu(phba, phys_id); | ||
8471 | if (cpu == LPFC_VECTOR_MAP_EMPTY) | ||
8472 | continue; | ||
8473 | goto found; | ||
8474 | } | ||
8475 | |||
8476 | lpfc_printf_log(phba, KERN_ERR, LOG_INIT, | ||
8477 | "3329 Cannot set affinity:" | ||
8478 | "Error mapping vector %d (%d)\n", | ||
8479 | idx, vectors); | ||
8480 | return 0; | ||
8481 | } | ||
8482 | found: | ||
8483 | cpup += cpu; | ||
8484 | if (phba->cfg_fcp_cpu_map == LPFC_DRIVER_CPU_MAP) | ||
8485 | lpfc_used_cpu[cpu] = phys_id; | ||
8486 | |||
8487 | /* Associate vector with selected CPU */ | ||
8488 | cpup->irq = phba->sli4_hba.msix_entries[idx].vector; | ||
8489 | |||
8490 | /* Associate IO channel with selected CPU */ | ||
8491 | cpup->channel_id = idx; | ||
8492 | num_io_channel++; | ||
8493 | |||
8494 | if (first_cpu == LPFC_VECTOR_MAP_EMPTY) | ||
8495 | first_cpu = cpu; | ||
8496 | |||
8497 | /* Now affinitize to the selected CPU */ | ||
8498 | mask = &cpup->maskbits; | ||
8499 | cpumask_clear(mask); | ||
8500 | cpumask_set_cpu(cpu, mask); | ||
8501 | i = irq_set_affinity_hint(phba->sli4_hba.msix_entries[idx]. | ||
8502 | vector, mask); | ||
8503 | |||
8504 | lpfc_printf_log(phba, KERN_INFO, LOG_INIT, | ||
8505 | "3330 Set Affinity: CPU %d channel %d " | ||
8506 | "irq %d (%x)\n", | ||
8507 | cpu, cpup->channel_id, | ||
8508 | phba->sli4_hba.msix_entries[idx].vector, i); | ||
8509 | |||
8510 | /* Spread vector mapping across multple physical CPU nodes */ | ||
8511 | phys_id++; | ||
8512 | if (phys_id > max_phys_id) | ||
8513 | phys_id = 0; | ||
8514 | } | ||
8515 | |||
8516 | /* | ||
8517 | * Finally fill in the IO channel for any remaining CPUs. | ||
8518 | * At this point, all IO channels have been assigned to a specific | ||
8519 | * MSIx vector, mapped to a specific CPU. | ||
8520 | * Base the remaining IO channel assigned, to IO channels already | ||
8521 | * assigned to other CPUs on the same phys_id. | ||
8522 | */ | ||
8523 | for (i = 0; i <= max_phys_id; i++) { | ||
8524 | /* | ||
8525 | * If there are no io channels already mapped to | ||
8526 | * this phys_id, just round robin thru the io_channels. | ||
8527 | * Setup chann[] for round robin. | ||
8528 | */ | ||
8529 | for (idx = 0; idx < phba->cfg_fcp_io_channel; idx++) | ||
8530 | chann[idx] = idx; | ||
8531 | |||
8532 | saved_chann = 0; | ||
8533 | used_chann = 0; | ||
8534 | |||
8535 | /* | ||
8536 | * First build a list of IO channels already assigned | ||
8537 | * to this phys_id before reassigning the same IO | ||
8538 | * channels to the remaining CPUs. | ||
8539 | */ | ||
8540 | cpup = phba->sli4_hba.cpu_map; | ||
8541 | cpu = first_cpu; | ||
8542 | cpup += cpu; | ||
8543 | for (idx = 0; idx < phba->sli4_hba.num_present_cpu; | ||
8544 | idx++) { | ||
8545 | if (cpup->phys_id == i) { | ||
8546 | /* | ||
8547 | * Save any IO channels that are | ||
8548 | * already mapped to this phys_id. | ||
8549 | */ | ||
8550 | if (cpup->irq != LPFC_VECTOR_MAP_EMPTY) { | ||
8551 | chann[saved_chann] = | ||
8552 | cpup->channel_id; | ||
8553 | saved_chann++; | ||
8554 | goto out; | ||
8555 | } | ||
8556 | |||
8557 | /* See if we are using round-robin */ | ||
8558 | if (saved_chann == 0) | ||
8559 | saved_chann = | ||
8560 | phba->cfg_fcp_io_channel; | ||
8561 | |||
8562 | /* Associate next IO channel with CPU */ | ||
8563 | cpup->channel_id = chann[used_chann]; | ||
8564 | num_io_channel++; | ||
8565 | used_chann++; | ||
8566 | if (used_chann == saved_chann) | ||
8567 | used_chann = 0; | ||
8568 | |||
8569 | lpfc_printf_log(phba, KERN_INFO, LOG_INIT, | ||
8570 | "3331 Set IO_CHANN " | ||
8571 | "CPU %d channel %d\n", | ||
8572 | idx, cpup->channel_id); | ||
8573 | } | ||
8574 | out: | ||
8575 | cpu++; | ||
8576 | if (cpu >= phba->sli4_hba.num_present_cpu) { | ||
8577 | cpup = phba->sli4_hba.cpu_map; | ||
8578 | cpu = 0; | ||
8579 | } else { | ||
8580 | cpup++; | ||
8581 | } | ||
8582 | } | ||
8583 | } | ||
8584 | |||
8585 | if (phba->sli4_hba.num_online_cpu != phba->sli4_hba.num_present_cpu) { | ||
8586 | cpup = phba->sli4_hba.cpu_map; | ||
8587 | for (idx = 0; idx < phba->sli4_hba.num_present_cpu; idx++) { | ||
8588 | if (cpup->channel_id == LPFC_VECTOR_MAP_EMPTY) { | ||
8589 | cpup->channel_id = 0; | ||
8590 | num_io_channel++; | ||
8591 | |||
8592 | lpfc_printf_log(phba, KERN_INFO, LOG_INIT, | ||
8593 | "3332 Assign IO_CHANN " | ||
8594 | "CPU %d channel %d\n", | ||
8595 | idx, cpup->channel_id); | ||
8596 | } | ||
8597 | cpup++; | ||
8598 | } | ||
8599 | } | ||
8600 | |||
8601 | /* Sanity check */ | ||
8602 | if (num_io_channel != phba->sli4_hba.num_present_cpu) | ||
8603 | lpfc_printf_log(phba, KERN_ERR, LOG_INIT, | ||
8604 | "3333 Set affinity mismatch:" | ||
8605 | "%d chann != %d cpus: %d vactors\n", | ||
8606 | num_io_channel, phba->sli4_hba.num_present_cpu, | ||
8607 | vectors); | ||
8608 | |||
8609 | phba->cfg_fcp_io_sched = LPFC_FCP_SCHED_BY_CPU; | ||
8610 | return 1; | ||
8611 | } | ||
8612 | |||
8613 | |||
8614 | /** | ||
8313 | * lpfc_sli4_enable_msix - Enable MSI-X interrupt mode to SLI-4 device | 8615 | * lpfc_sli4_enable_msix - Enable MSI-X interrupt mode to SLI-4 device |
8314 | * @phba: pointer to lpfc hba data structure. | 8616 | * @phba: pointer to lpfc hba data structure. |
8315 | * | 8617 | * |
@@ -8360,9 +8662,7 @@ enable_msix_vectors: | |||
8360 | phba->sli4_hba.msix_entries[index].vector, | 8662 | phba->sli4_hba.msix_entries[index].vector, |
8361 | phba->sli4_hba.msix_entries[index].entry); | 8663 | phba->sli4_hba.msix_entries[index].entry); |
8362 | 8664 | ||
8363 | /* | 8665 | /* Assign MSI-X vectors to interrupt handlers */ |
8364 | * Assign MSI-X vectors to interrupt handlers | ||
8365 | */ | ||
8366 | for (index = 0; index < vectors; index++) { | 8666 | for (index = 0; index < vectors; index++) { |
8367 | memset(&phba->sli4_hba.handler_name[index], 0, 16); | 8667 | memset(&phba->sli4_hba.handler_name[index], 0, 16); |
8368 | sprintf((char *)&phba->sli4_hba.handler_name[index], | 8668 | sprintf((char *)&phba->sli4_hba.handler_name[index], |
@@ -8390,6 +8690,8 @@ enable_msix_vectors: | |||
8390 | phba->cfg_fcp_io_channel, vectors); | 8690 | phba->cfg_fcp_io_channel, vectors); |
8391 | phba->cfg_fcp_io_channel = vectors; | 8691 | phba->cfg_fcp_io_channel = vectors; |
8392 | } | 8692 | } |
8693 | |||
8694 | lpfc_sli4_set_affinity(phba, vectors); | ||
8393 | return rc; | 8695 | return rc; |
8394 | 8696 | ||
8395 | cfg_fail_out: | 8697 | cfg_fail_out: |
@@ -10667,6 +10969,7 @@ static struct miscdevice lpfc_mgmt_dev = { | |||
10667 | static int __init | 10969 | static int __init |
10668 | lpfc_init(void) | 10970 | lpfc_init(void) |
10669 | { | 10971 | { |
10972 | int cpu; | ||
10670 | int error = 0; | 10973 | int error = 0; |
10671 | 10974 | ||
10672 | printk(LPFC_MODULE_DESC "\n"); | 10975 | printk(LPFC_MODULE_DESC "\n"); |
@@ -10693,6 +10996,11 @@ lpfc_init(void) | |||
10693 | return -ENOMEM; | 10996 | return -ENOMEM; |
10694 | } | 10997 | } |
10695 | } | 10998 | } |
10999 | |||
11000 | /* Initialize in case vector mapping is needed */ | ||
11001 | for (cpu = 0; cpu < LPFC_MAX_CPU; cpu++) | ||
11002 | lpfc_used_cpu[cpu] = LPFC_VECTOR_MAP_EMPTY; | ||
11003 | |||
10696 | error = pci_register_driver(&lpfc_driver); | 11004 | error = pci_register_driver(&lpfc_driver); |
10697 | if (error) { | 11005 | if (error) { |
10698 | fc_release_transport(lpfc_transport_template); | 11006 | fc_release_transport(lpfc_transport_template); |
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index c13ab4fd36b9..94b017ee9aa3 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c | |||
@@ -7923,15 +7923,21 @@ lpfc_sli4_bpl2sgl(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq, | |||
7923 | static inline uint32_t | 7923 | static inline uint32_t |
7924 | lpfc_sli4_scmd_to_wqidx_distr(struct lpfc_hba *phba) | 7924 | lpfc_sli4_scmd_to_wqidx_distr(struct lpfc_hba *phba) |
7925 | { | 7925 | { |
7926 | int i; | 7926 | struct lpfc_vector_map_info *cpup; |
7927 | 7927 | int chann, cpu; | |
7928 | if (phba->cfg_fcp_io_sched == LPFC_FCP_SCHED_BY_CPU) | ||
7929 | i = smp_processor_id(); | ||
7930 | else | ||
7931 | i = atomic_add_return(1, &phba->fcp_qidx); | ||
7932 | 7928 | ||
7933 | i = (i % phba->cfg_fcp_io_channel); | 7929 | if (phba->cfg_fcp_io_sched == LPFC_FCP_SCHED_BY_CPU) { |
7934 | return i; | 7930 | cpu = smp_processor_id(); |
7931 | if (cpu < phba->sli4_hba.num_present_cpu) { | ||
7932 | cpup = phba->sli4_hba.cpu_map; | ||
7933 | cpup += cpu; | ||
7934 | return cpup->channel_id; | ||
7935 | } | ||
7936 | chann = cpu; | ||
7937 | } | ||
7938 | chann = atomic_add_return(1, &phba->fcp_qidx); | ||
7939 | chann = (chann % phba->cfg_fcp_io_channel); | ||
7940 | return chann; | ||
7935 | } | 7941 | } |
7936 | 7942 | ||
7937 | /** | 7943 | /** |
diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h index 347e22c527b1..67af460184ba 100644 --- a/drivers/scsi/lpfc/lpfc_sli4.h +++ b/drivers/scsi/lpfc/lpfc_sli4.h | |||
@@ -435,6 +435,17 @@ struct lpfc_sli4_lnk_info { | |||
435 | 435 | ||
436 | #define LPFC_SLI4_HANDLER_NAME_SZ 16 | 436 | #define LPFC_SLI4_HANDLER_NAME_SZ 16 |
437 | 437 | ||
438 | /* Used for IRQ vector to CPU mapping */ | ||
439 | struct lpfc_vector_map_info { | ||
440 | uint16_t phys_id; | ||
441 | uint16_t core_id; | ||
442 | uint16_t irq; | ||
443 | uint16_t channel_id; | ||
444 | struct cpumask maskbits; | ||
445 | }; | ||
446 | #define LPFC_VECTOR_MAP_EMPTY 0xffff | ||
447 | #define LPFC_MAX_CPU 256 | ||
448 | |||
438 | /* SLI4 HBA data structure entries */ | 449 | /* SLI4 HBA data structure entries */ |
439 | struct lpfc_sli4_hba { | 450 | struct lpfc_sli4_hba { |
440 | void __iomem *conf_regs_memmap_p; /* Kernel memory mapped address for | 451 | void __iomem *conf_regs_memmap_p; /* Kernel memory mapped address for |
@@ -568,6 +579,11 @@ struct lpfc_sli4_hba { | |||
568 | struct lpfc_iov iov; | 579 | struct lpfc_iov iov; |
569 | spinlock_t abts_scsi_buf_list_lock; /* list of aborted SCSI IOs */ | 580 | spinlock_t abts_scsi_buf_list_lock; /* list of aborted SCSI IOs */ |
570 | spinlock_t abts_sgl_list_lock; /* list of aborted els IOs */ | 581 | spinlock_t abts_sgl_list_lock; /* list of aborted els IOs */ |
582 | |||
583 | /* CPU to vector mapping information */ | ||
584 | struct lpfc_vector_map_info *cpu_map; | ||
585 | uint16_t num_online_cpu; | ||
586 | uint16_t num_present_cpu; | ||
571 | }; | 587 | }; |
572 | 588 | ||
573 | enum lpfc_sge_type { | 589 | enum lpfc_sge_type { |