diff options
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/ethernet/cisco/enic/enic.h | 27 | ||||
-rw-r--r-- | drivers/net/ethernet/cisco/enic/enic_main.c | 72 |
2 files changed, 99 insertions, 0 deletions
diff --git a/drivers/net/ethernet/cisco/enic/enic.h b/drivers/net/ethernet/cisco/enic/enic.h index 6401ba99457f..1671fa3332c2 100644 --- a/drivers/net/ethernet/cisco/enic/enic.h +++ b/drivers/net/ethernet/cisco/enic/enic.h | |||
@@ -50,6 +50,7 @@ struct enic_msix_entry { | |||
50 | char devname[IFNAMSIZ]; | 50 | char devname[IFNAMSIZ]; |
51 | irqreturn_t (*isr)(int, void *); | 51 | irqreturn_t (*isr)(int, void *); |
52 | void *devid; | 52 | void *devid; |
53 | cpumask_var_t affinity_mask; | ||
53 | }; | 54 | }; |
54 | 55 | ||
55 | /* Store only the lower range. Higher range is given by fw. */ | 56 | /* Store only the lower range. Higher range is given by fw. */ |
@@ -263,6 +264,32 @@ static inline unsigned int enic_msix_notify_intr(struct enic *enic) | |||
263 | return enic->rq_count + enic->wq_count + 1; | 264 | return enic->rq_count + enic->wq_count + 1; |
264 | } | 265 | } |
265 | 266 | ||
267 | static inline bool enic_is_err_intr(struct enic *enic, int intr) | ||
268 | { | ||
269 | switch (vnic_dev_get_intr_mode(enic->vdev)) { | ||
270 | case VNIC_DEV_INTR_MODE_INTX: | ||
271 | return intr == enic_legacy_err_intr(); | ||
272 | case VNIC_DEV_INTR_MODE_MSIX: | ||
273 | return intr == enic_msix_err_intr(enic); | ||
274 | case VNIC_DEV_INTR_MODE_MSI: | ||
275 | default: | ||
276 | return false; | ||
277 | } | ||
278 | } | ||
279 | |||
280 | static inline bool enic_is_notify_intr(struct enic *enic, int intr) | ||
281 | { | ||
282 | switch (vnic_dev_get_intr_mode(enic->vdev)) { | ||
283 | case VNIC_DEV_INTR_MODE_INTX: | ||
284 | return intr == enic_legacy_notify_intr(); | ||
285 | case VNIC_DEV_INTR_MODE_MSIX: | ||
286 | return intr == enic_msix_notify_intr(enic); | ||
287 | case VNIC_DEV_INTR_MODE_MSI: | ||
288 | default: | ||
289 | return false; | ||
290 | } | ||
291 | } | ||
292 | |||
266 | static inline int enic_dma_map_check(struct enic *enic, dma_addr_t dma_addr) | 293 | static inline int enic_dma_map_check(struct enic *enic, dma_addr_t dma_addr) |
267 | { | 294 | { |
268 | if (unlikely(pci_dma_mapping_error(enic->pdev, dma_addr))) { | 295 | if (unlikely(pci_dma_mapping_error(enic->pdev, dma_addr))) { |
diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c index 0c22fd014378..b36643ef0593 100644 --- a/drivers/net/ethernet/cisco/enic/enic_main.c +++ b/drivers/net/ethernet/cisco/enic/enic_main.c | |||
@@ -39,6 +39,7 @@ | |||
39 | #include <linux/prefetch.h> | 39 | #include <linux/prefetch.h> |
40 | #include <net/ip6_checksum.h> | 40 | #include <net/ip6_checksum.h> |
41 | #include <linux/ktime.h> | 41 | #include <linux/ktime.h> |
42 | #include <linux/numa.h> | ||
42 | #ifdef CONFIG_RFS_ACCEL | 43 | #ifdef CONFIG_RFS_ACCEL |
43 | #include <linux/cpu_rmap.h> | 44 | #include <linux/cpu_rmap.h> |
44 | #endif | 45 | #endif |
@@ -112,6 +113,71 @@ static struct enic_intr_mod_range mod_range[ENIC_MAX_LINK_SPEEDS] = { | |||
112 | {3, 6}, /* 10 - 40 Gbps */ | 113 | {3, 6}, /* 10 - 40 Gbps */ |
113 | }; | 114 | }; |
114 | 115 | ||
116 | static void enic_init_affinity_hint(struct enic *enic) | ||
117 | { | ||
118 | int numa_node = dev_to_node(&enic->pdev->dev); | ||
119 | int i; | ||
120 | |||
121 | for (i = 0; i < enic->intr_count; i++) { | ||
122 | if (enic_is_err_intr(enic, i) || enic_is_notify_intr(enic, i) || | ||
123 | (enic->msix[i].affinity_mask && | ||
124 | !cpumask_empty(enic->msix[i].affinity_mask))) | ||
125 | continue; | ||
126 | if (zalloc_cpumask_var(&enic->msix[i].affinity_mask, | ||
127 | GFP_KERNEL)) | ||
128 | cpumask_set_cpu(cpumask_local_spread(i, numa_node), | ||
129 | enic->msix[i].affinity_mask); | ||
130 | } | ||
131 | } | ||
132 | |||
133 | static void enic_free_affinity_hint(struct enic *enic) | ||
134 | { | ||
135 | int i; | ||
136 | |||
137 | for (i = 0; i < enic->intr_count; i++) { | ||
138 | if (enic_is_err_intr(enic, i) || enic_is_notify_intr(enic, i)) | ||
139 | continue; | ||
140 | free_cpumask_var(enic->msix[i].affinity_mask); | ||
141 | } | ||
142 | } | ||
143 | |||
144 | static void enic_set_affinity_hint(struct enic *enic) | ||
145 | { | ||
146 | int i; | ||
147 | int err; | ||
148 | |||
149 | for (i = 0; i < enic->intr_count; i++) { | ||
150 | if (enic_is_err_intr(enic, i) || | ||
151 | enic_is_notify_intr(enic, i) || | ||
152 | !enic->msix[i].affinity_mask || | ||
153 | cpumask_empty(enic->msix[i].affinity_mask)) | ||
154 | continue; | ||
155 | err = irq_set_affinity_hint(enic->msix_entry[i].vector, | ||
156 | enic->msix[i].affinity_mask); | ||
157 | if (err) | ||
158 | netdev_warn(enic->netdev, "irq_set_affinity_hint failed, err %d\n", | ||
159 | err); | ||
160 | } | ||
161 | |||
162 | for (i = 0; i < enic->wq_count; i++) { | ||
163 | int wq_intr = enic_msix_wq_intr(enic, i); | ||
164 | |||
165 | if (enic->msix[wq_intr].affinity_mask && | ||
166 | !cpumask_empty(enic->msix[wq_intr].affinity_mask)) | ||
167 | netif_set_xps_queue(enic->netdev, | ||
168 | enic->msix[wq_intr].affinity_mask, | ||
169 | i); | ||
170 | } | ||
171 | } | ||
172 | |||
173 | static void enic_unset_affinity_hint(struct enic *enic) | ||
174 | { | ||
175 | int i; | ||
176 | |||
177 | for (i = 0; i < enic->intr_count; i++) | ||
178 | irq_set_affinity_hint(enic->msix_entry[i].vector, NULL); | ||
179 | } | ||
180 | |||
115 | int enic_is_dynamic(struct enic *enic) | 181 | int enic_is_dynamic(struct enic *enic) |
116 | { | 182 | { |
117 | return enic->pdev->device == PCI_DEVICE_ID_CISCO_VIC_ENET_DYN; | 183 | return enic->pdev->device == PCI_DEVICE_ID_CISCO_VIC_ENET_DYN; |
@@ -1649,6 +1715,8 @@ static int enic_open(struct net_device *netdev) | |||
1649 | netdev_err(netdev, "Unable to request irq.\n"); | 1715 | netdev_err(netdev, "Unable to request irq.\n"); |
1650 | return err; | 1716 | return err; |
1651 | } | 1717 | } |
1718 | enic_init_affinity_hint(enic); | ||
1719 | enic_set_affinity_hint(enic); | ||
1652 | 1720 | ||
1653 | err = enic_dev_notify_set(enic); | 1721 | err = enic_dev_notify_set(enic); |
1654 | if (err) { | 1722 | if (err) { |
@@ -1701,6 +1769,7 @@ err_out_free_rq: | |||
1701 | vnic_rq_clean(&enic->rq[i], enic_free_rq_buf); | 1769 | vnic_rq_clean(&enic->rq[i], enic_free_rq_buf); |
1702 | enic_dev_notify_unset(enic); | 1770 | enic_dev_notify_unset(enic); |
1703 | err_out_free_intr: | 1771 | err_out_free_intr: |
1772 | enic_unset_affinity_hint(enic); | ||
1704 | enic_free_intr(enic); | 1773 | enic_free_intr(enic); |
1705 | 1774 | ||
1706 | return err; | 1775 | return err; |
@@ -1754,6 +1823,7 @@ static int enic_stop(struct net_device *netdev) | |||
1754 | } | 1823 | } |
1755 | 1824 | ||
1756 | enic_dev_notify_unset(enic); | 1825 | enic_dev_notify_unset(enic); |
1826 | enic_unset_affinity_hint(enic); | ||
1757 | enic_free_intr(enic); | 1827 | enic_free_intr(enic); |
1758 | 1828 | ||
1759 | for (i = 0; i < enic->wq_count; i++) | 1829 | for (i = 0; i < enic->wq_count; i++) |
@@ -2309,6 +2379,7 @@ static void enic_dev_deinit(struct enic *enic) | |||
2309 | 2379 | ||
2310 | enic_free_vnic_resources(enic); | 2380 | enic_free_vnic_resources(enic); |
2311 | enic_clear_intr_mode(enic); | 2381 | enic_clear_intr_mode(enic); |
2382 | enic_free_affinity_hint(enic); | ||
2312 | } | 2383 | } |
2313 | 2384 | ||
2314 | static void enic_kdump_kernel_config(struct enic *enic) | 2385 | static void enic_kdump_kernel_config(struct enic *enic) |
@@ -2404,6 +2475,7 @@ static int enic_dev_init(struct enic *enic) | |||
2404 | return 0; | 2475 | return 0; |
2405 | 2476 | ||
2406 | err_out_free_vnic_resources: | 2477 | err_out_free_vnic_resources: |
2478 | enic_free_affinity_hint(enic); | ||
2407 | enic_clear_intr_mode(enic); | 2479 | enic_clear_intr_mode(enic); |
2408 | enic_free_vnic_resources(enic); | 2480 | enic_free_vnic_resources(enic); |
2409 | 2481 | ||