diff options
Diffstat (limited to 'drivers/net/ethernet/cisco/enic/enic_main.c')
-rw-r--r-- | drivers/net/ethernet/cisco/enic/enic_main.c | 85 |
1 files changed, 73 insertions, 12 deletions
diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c index 5448df2d78c2..d4918eef5050 100644 --- a/drivers/net/ethernet/cisco/enic/enic_main.c +++ b/drivers/net/ethernet/cisco/enic/enic_main.c | |||
@@ -42,6 +42,9 @@ | |||
42 | #ifdef CONFIG_RFS_ACCEL | 42 | #ifdef CONFIG_RFS_ACCEL |
43 | #include <linux/cpu_rmap.h> | 43 | #include <linux/cpu_rmap.h> |
44 | #endif | 44 | #endif |
45 | #ifdef CONFIG_NET_RX_BUSY_POLL | ||
46 | #include <net/busy_poll.h> | ||
47 | #endif | ||
45 | 48 | ||
46 | #include "cq_enet_desc.h" | 49 | #include "cq_enet_desc.h" |
47 | #include "vnic_dev.h" | 50 | #include "vnic_dev.h" |
@@ -1053,10 +1056,12 @@ static void enic_rq_indicate_buf(struct vnic_rq *rq, | |||
1053 | if (vlan_stripped) | 1056 | if (vlan_stripped) |
1054 | __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan_tci); | 1057 | __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan_tci); |
1055 | 1058 | ||
1056 | if (netdev->features & NETIF_F_GRO) | 1059 | skb_mark_napi_id(skb, &enic->napi[rq->index]); |
1057 | napi_gro_receive(&enic->napi[q_number], skb); | 1060 | if (enic_poll_busy_polling(rq) || |
1058 | else | 1061 | !(netdev->features & NETIF_F_GRO)) |
1059 | netif_receive_skb(skb); | 1062 | netif_receive_skb(skb); |
1063 | else | ||
1064 | napi_gro_receive(&enic->napi[q_number], skb); | ||
1060 | if (enic->rx_coalesce_setting.use_adaptive_rx_coalesce) | 1065 | if (enic->rx_coalesce_setting.use_adaptive_rx_coalesce) |
1061 | enic_intr_update_pkt_size(&cq->pkt_size_counter, | 1066 | enic_intr_update_pkt_size(&cq->pkt_size_counter, |
1062 | bytes_written); | 1067 | bytes_written); |
@@ -1093,16 +1098,22 @@ static int enic_poll(struct napi_struct *napi, int budget) | |||
1093 | unsigned int work_done, rq_work_done = 0, wq_work_done; | 1098 | unsigned int work_done, rq_work_done = 0, wq_work_done; |
1094 | int err; | 1099 | int err; |
1095 | 1100 | ||
1096 | /* Service RQ (first) and WQ | 1101 | wq_work_done = vnic_cq_service(&enic->cq[cq_wq], wq_work_to_do, |
1097 | */ | 1102 | enic_wq_service, NULL); |
1103 | |||
1104 | if (!enic_poll_lock_napi(&enic->rq[cq_rq])) { | ||
1105 | if (wq_work_done > 0) | ||
1106 | vnic_intr_return_credits(&enic->intr[intr], | ||
1107 | wq_work_done, | ||
1108 | 0 /* dont unmask intr */, | ||
1109 | 0 /* dont reset intr timer */); | ||
1110 | return rq_work_done; | ||
1111 | } | ||
1098 | 1112 | ||
1099 | if (budget > 0) | 1113 | if (budget > 0) |
1100 | rq_work_done = vnic_cq_service(&enic->cq[cq_rq], | 1114 | rq_work_done = vnic_cq_service(&enic->cq[cq_rq], |
1101 | rq_work_to_do, enic_rq_service, NULL); | 1115 | rq_work_to_do, enic_rq_service, NULL); |
1102 | 1116 | ||
1103 | wq_work_done = vnic_cq_service(&enic->cq[cq_wq], | ||
1104 | wq_work_to_do, enic_wq_service, NULL); | ||
1105 | |||
1106 | /* Accumulate intr event credits for this polling | 1117 | /* Accumulate intr event credits for this polling |
1107 | * cycle. An intr event is the completion of a | 1118 | * cycle. An intr event is the completion of a |
1108 | * a WQ or RQ packet. | 1119 | * a WQ or RQ packet. |
@@ -1134,6 +1145,7 @@ static int enic_poll(struct napi_struct *napi, int budget) | |||
1134 | napi_complete(napi); | 1145 | napi_complete(napi); |
1135 | vnic_intr_unmask(&enic->intr[intr]); | 1146 | vnic_intr_unmask(&enic->intr[intr]); |
1136 | } | 1147 | } |
1148 | enic_poll_unlock_napi(&enic->rq[cq_rq]); | ||
1137 | 1149 | ||
1138 | return rq_work_done; | 1150 | return rq_work_done; |
1139 | } | 1151 | } |
@@ -1234,6 +1246,34 @@ static void enic_set_rx_cpu_rmap(struct enic *enic) | |||
1234 | 1246 | ||
1235 | #endif /* CONFIG_RFS_ACCEL */ | 1247 | #endif /* CONFIG_RFS_ACCEL */ |
1236 | 1248 | ||
1249 | #ifdef CONFIG_NET_RX_BUSY_POLL | ||
1250 | int enic_busy_poll(struct napi_struct *napi) | ||
1251 | { | ||
1252 | struct net_device *netdev = napi->dev; | ||
1253 | struct enic *enic = netdev_priv(netdev); | ||
1254 | unsigned int rq = (napi - &enic->napi[0]); | ||
1255 | unsigned int cq = enic_cq_rq(enic, rq); | ||
1256 | unsigned int intr = enic_msix_rq_intr(enic, rq); | ||
1257 | unsigned int work_to_do = -1; /* clean all pkts possible */ | ||
1258 | unsigned int work_done; | ||
1259 | |||
1260 | if (!enic_poll_lock_poll(&enic->rq[rq])) | ||
1261 | return LL_FLUSH_BUSY; | ||
1262 | work_done = vnic_cq_service(&enic->cq[cq], work_to_do, | ||
1263 | enic_rq_service, NULL); | ||
1264 | |||
1265 | if (work_done > 0) | ||
1266 | vnic_intr_return_credits(&enic->intr[intr], | ||
1267 | work_done, 0, 0); | ||
1268 | vnic_rq_fill(&enic->rq[rq], enic_rq_alloc_buf); | ||
1269 | if (enic->rx_coalesce_setting.use_adaptive_rx_coalesce) | ||
1270 | enic_calc_int_moderation(enic, &enic->rq[rq]); | ||
1271 | enic_poll_unlock_poll(&enic->rq[rq]); | ||
1272 | |||
1273 | return work_done; | ||
1274 | } | ||
1275 | #endif /* CONFIG_NET_RX_BUSY_POLL */ | ||
1276 | |||
1237 | static int enic_poll_msix(struct napi_struct *napi, int budget) | 1277 | static int enic_poll_msix(struct napi_struct *napi, int budget) |
1238 | { | 1278 | { |
1239 | struct net_device *netdev = napi->dev; | 1279 | struct net_device *netdev = napi->dev; |
@@ -1245,6 +1285,8 @@ static int enic_poll_msix(struct napi_struct *napi, int budget) | |||
1245 | unsigned int work_done = 0; | 1285 | unsigned int work_done = 0; |
1246 | int err; | 1286 | int err; |
1247 | 1287 | ||
1288 | if (!enic_poll_lock_napi(&enic->rq[rq])) | ||
1289 | return work_done; | ||
1248 | /* Service RQ | 1290 | /* Service RQ |
1249 | */ | 1291 | */ |
1250 | 1292 | ||
@@ -1290,6 +1332,7 @@ static int enic_poll_msix(struct napi_struct *napi, int budget) | |||
1290 | enic_set_int_moderation(enic, &enic->rq[rq]); | 1332 | enic_set_int_moderation(enic, &enic->rq[rq]); |
1291 | vnic_intr_unmask(&enic->intr[intr]); | 1333 | vnic_intr_unmask(&enic->intr[intr]); |
1292 | } | 1334 | } |
1335 | enic_poll_unlock_napi(&enic->rq[rq]); | ||
1293 | 1336 | ||
1294 | return work_done; | 1337 | return work_done; |
1295 | } | 1338 | } |
@@ -1538,8 +1581,10 @@ static int enic_open(struct net_device *netdev) | |||
1538 | 1581 | ||
1539 | netif_tx_wake_all_queues(netdev); | 1582 | netif_tx_wake_all_queues(netdev); |
1540 | 1583 | ||
1541 | for (i = 0; i < enic->rq_count; i++) | 1584 | for (i = 0; i < enic->rq_count; i++) { |
1585 | enic_busy_poll_init_lock(&enic->rq[i]); | ||
1542 | napi_enable(&enic->napi[i]); | 1586 | napi_enable(&enic->napi[i]); |
1587 | } | ||
1543 | 1588 | ||
1544 | enic_dev_enable(enic); | 1589 | enic_dev_enable(enic); |
1545 | 1590 | ||
@@ -1578,8 +1623,13 @@ static int enic_stop(struct net_device *netdev) | |||
1578 | 1623 | ||
1579 | enic_dev_disable(enic); | 1624 | enic_dev_disable(enic); |
1580 | 1625 | ||
1581 | for (i = 0; i < enic->rq_count; i++) | 1626 | local_bh_disable(); |
1627 | for (i = 0; i < enic->rq_count; i++) { | ||
1582 | napi_disable(&enic->napi[i]); | 1628 | napi_disable(&enic->napi[i]); |
1629 | while (!enic_poll_lock_napi(&enic->rq[i])) | ||
1630 | mdelay(1); | ||
1631 | } | ||
1632 | local_bh_enable(); | ||
1583 | 1633 | ||
1584 | netif_carrier_off(netdev); | 1634 | netif_carrier_off(netdev); |
1585 | netif_tx_disable(netdev); | 1635 | netif_tx_disable(netdev); |
@@ -2070,6 +2120,9 @@ static const struct net_device_ops enic_netdev_dynamic_ops = { | |||
2070 | #ifdef CONFIG_RFS_ACCEL | 2120 | #ifdef CONFIG_RFS_ACCEL |
2071 | .ndo_rx_flow_steer = enic_rx_flow_steer, | 2121 | .ndo_rx_flow_steer = enic_rx_flow_steer, |
2072 | #endif | 2122 | #endif |
2123 | #ifdef CONFIG_NET_RX_BUSY_POLL | ||
2124 | .ndo_busy_poll = enic_busy_poll, | ||
2125 | #endif | ||
2073 | }; | 2126 | }; |
2074 | 2127 | ||
2075 | static const struct net_device_ops enic_netdev_ops = { | 2128 | static const struct net_device_ops enic_netdev_ops = { |
@@ -2093,14 +2146,19 @@ static const struct net_device_ops enic_netdev_ops = { | |||
2093 | #ifdef CONFIG_RFS_ACCEL | 2146 | #ifdef CONFIG_RFS_ACCEL |
2094 | .ndo_rx_flow_steer = enic_rx_flow_steer, | 2147 | .ndo_rx_flow_steer = enic_rx_flow_steer, |
2095 | #endif | 2148 | #endif |
2149 | #ifdef CONFIG_NET_RX_BUSY_POLL | ||
2150 | .ndo_busy_poll = enic_busy_poll, | ||
2151 | #endif | ||
2096 | }; | 2152 | }; |
2097 | 2153 | ||
2098 | static void enic_dev_deinit(struct enic *enic) | 2154 | static void enic_dev_deinit(struct enic *enic) |
2099 | { | 2155 | { |
2100 | unsigned int i; | 2156 | unsigned int i; |
2101 | 2157 | ||
2102 | for (i = 0; i < enic->rq_count; i++) | 2158 | for (i = 0; i < enic->rq_count; i++) { |
2159 | napi_hash_del(&enic->napi[i]); | ||
2103 | netif_napi_del(&enic->napi[i]); | 2160 | netif_napi_del(&enic->napi[i]); |
2161 | } | ||
2104 | 2162 | ||
2105 | enic_free_vnic_resources(enic); | 2163 | enic_free_vnic_resources(enic); |
2106 | enic_clear_intr_mode(enic); | 2164 | enic_clear_intr_mode(enic); |
@@ -2166,11 +2224,14 @@ static int enic_dev_init(struct enic *enic) | |||
2166 | switch (vnic_dev_get_intr_mode(enic->vdev)) { | 2224 | switch (vnic_dev_get_intr_mode(enic->vdev)) { |
2167 | default: | 2225 | default: |
2168 | netif_napi_add(netdev, &enic->napi[0], enic_poll, 64); | 2226 | netif_napi_add(netdev, &enic->napi[0], enic_poll, 64); |
2227 | napi_hash_add(&enic->napi[0]); | ||
2169 | break; | 2228 | break; |
2170 | case VNIC_DEV_INTR_MODE_MSIX: | 2229 | case VNIC_DEV_INTR_MODE_MSIX: |
2171 | for (i = 0; i < enic->rq_count; i++) | 2230 | for (i = 0; i < enic->rq_count; i++) { |
2172 | netif_napi_add(netdev, &enic->napi[i], | 2231 | netif_napi_add(netdev, &enic->napi[i], |
2173 | enic_poll_msix, 64); | 2232 | enic_poll_msix, 64); |
2233 | napi_hash_add(&enic->napi[i]); | ||
2234 | } | ||
2174 | break; | 2235 | break; |
2175 | } | 2236 | } |
2176 | 2237 | ||