diff options
author | Sudarsana Kalluru <Sudarsana.Kalluru@qlogic.com> | 2015-10-26 05:02:30 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-10-27 22:34:50 -0400 |
commit | 0d8e0aa05796c8a5652c164de5e4f16d8c9ee199 (patch) | |
tree | 746c8c6a282891763263d6afe048b932c4a5ca3f | |
parent | 2950219d87b040959f23484dd4ff5856bf1bc172 (diff) |
qede: classification configuration
Add the ability to configure basic classification in driver by
implementing ndo_set_mac_address() and ndo_set_rx_mode().
Signed-off-by: Sudarsana Kalluru <Sudarsana.Kalluru@qlogic.com>
Signed-off-by: Yuval Mintz <Yuval.Mintz@qlogic.com>
Signed-off-by: Ariel Elior <Ariel.Elior@qlogic.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/ethernet/qlogic/qede/qede.h | 10 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qede/qede_main.c | 241 |
2 files changed, 251 insertions, 0 deletions
diff --git a/drivers/net/ethernet/qlogic/qede/qede.h b/drivers/net/ethernet/qlogic/qede/qede.h index 424ef4a55828..79479427b6d4 100644 --- a/drivers/net/ethernet/qlogic/qede/qede.h +++ b/drivers/net/ethernet/qlogic/qede/qede.h | |||
@@ -87,6 +87,9 @@ struct qede_dev { | |||
87 | struct qed_update_vport_rss_params rss_params; | 87 | struct qed_update_vport_rss_params rss_params; |
88 | u16 q_num_rx_buffers; /* Must be a power of two */ | 88 | u16 q_num_rx_buffers; /* Must be a power of two */ |
89 | u16 q_num_tx_buffers; /* Must be a power of two */ | 89 | u16 q_num_tx_buffers; /* Must be a power of two */ |
90 | |||
91 | struct delayed_work sp_task; | ||
92 | unsigned long sp_flags; | ||
90 | }; | 93 | }; |
91 | 94 | ||
92 | enum QEDE_STATE { | 95 | enum QEDE_STATE { |
@@ -184,6 +187,13 @@ struct qede_fastpath { | |||
184 | 187 | ||
185 | #define QEDE_CSUM_ERROR BIT(0) | 188 | #define QEDE_CSUM_ERROR BIT(0) |
186 | #define QEDE_CSUM_UNNECESSARY BIT(1) | 189 | #define QEDE_CSUM_UNNECESSARY BIT(1) |
190 | |||
191 | #define QEDE_SP_RX_MODE 1 | ||
192 | |||
193 | union qede_reload_args { | ||
194 | u16 mtu; | ||
195 | }; | ||
196 | |||
187 | #define RX_RING_SIZE_POW 13 | 197 | #define RX_RING_SIZE_POW 13 |
188 | #define RX_RING_SIZE BIT(RX_RING_SIZE_POW) | 198 | #define RX_RING_SIZE BIT(RX_RING_SIZE_POW) |
189 | #define NUM_RX_BDS_MAX (RX_RING_SIZE - 1) | 199 | #define NUM_RX_BDS_MAX (RX_RING_SIZE - 1) |
diff --git a/drivers/net/ethernet/qlogic/qede/qede_main.c b/drivers/net/ethernet/qlogic/qede/qede_main.c index daba118f99ca..0351204317e7 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_main.c +++ b/drivers/net/ethernet/qlogic/qede/qede_main.c | |||
@@ -1030,10 +1030,31 @@ static irqreturn_t qede_msix_fp_int(int irq, void *fp_cookie) | |||
1030 | 1030 | ||
1031 | static int qede_open(struct net_device *ndev); | 1031 | static int qede_open(struct net_device *ndev); |
1032 | static int qede_close(struct net_device *ndev); | 1032 | static int qede_close(struct net_device *ndev); |
1033 | static int qede_set_mac_addr(struct net_device *ndev, void *p); | ||
1034 | static void qede_set_rx_mode(struct net_device *ndev); | ||
1035 | static void qede_config_rx_mode(struct net_device *ndev); | ||
1036 | |||
1037 | static int qede_set_ucast_rx_mac(struct qede_dev *edev, | ||
1038 | enum qed_filter_xcast_params_type opcode, | ||
1039 | unsigned char mac[ETH_ALEN]) | ||
1040 | { | ||
1041 | struct qed_filter_params filter_cmd; | ||
1042 | |||
1043 | memset(&filter_cmd, 0, sizeof(filter_cmd)); | ||
1044 | filter_cmd.type = QED_FILTER_TYPE_UCAST; | ||
1045 | filter_cmd.filter.ucast.type = opcode; | ||
1046 | filter_cmd.filter.ucast.mac_valid = 1; | ||
1047 | ether_addr_copy(filter_cmd.filter.ucast.mac, mac); | ||
1048 | |||
1049 | return edev->ops->filter_config(edev->cdev, &filter_cmd); | ||
1050 | } | ||
1051 | |||
1033 | static const struct net_device_ops qede_netdev_ops = { | 1052 | static const struct net_device_ops qede_netdev_ops = { |
1034 | .ndo_open = qede_open, | 1053 | .ndo_open = qede_open, |
1035 | .ndo_stop = qede_close, | 1054 | .ndo_stop = qede_close, |
1036 | .ndo_start_xmit = qede_start_xmit, | 1055 | .ndo_start_xmit = qede_start_xmit, |
1056 | .ndo_set_rx_mode = qede_set_rx_mode, | ||
1057 | .ndo_set_mac_address = qede_set_mac_addr, | ||
1037 | .ndo_validate_addr = eth_validate_addr, | 1058 | .ndo_validate_addr = eth_validate_addr, |
1038 | }; | 1059 | }; |
1039 | 1060 | ||
@@ -1198,6 +1219,20 @@ err: | |||
1198 | return -ENOMEM; | 1219 | return -ENOMEM; |
1199 | } | 1220 | } |
1200 | 1221 | ||
1222 | static void qede_sp_task(struct work_struct *work) | ||
1223 | { | ||
1224 | struct qede_dev *edev = container_of(work, struct qede_dev, | ||
1225 | sp_task.work); | ||
1226 | mutex_lock(&edev->qede_lock); | ||
1227 | |||
1228 | if (edev->state == QEDE_STATE_OPEN) { | ||
1229 | if (test_and_clear_bit(QEDE_SP_RX_MODE, &edev->sp_flags)) | ||
1230 | qede_config_rx_mode(edev->ndev); | ||
1231 | } | ||
1232 | |||
1233 | mutex_unlock(&edev->qede_lock); | ||
1234 | } | ||
1235 | |||
1201 | static void qede_update_pf_params(struct qed_dev *cdev) | 1236 | static void qede_update_pf_params(struct qed_dev *cdev) |
1202 | { | 1237 | { |
1203 | struct qed_pf_params pf_params; | 1238 | struct qed_pf_params pf_params; |
@@ -1269,6 +1304,9 @@ static int __qede_probe(struct pci_dev *pdev, u32 dp_module, u8 dp_level, | |||
1269 | 1304 | ||
1270 | edev->ops->common->set_id(cdev, edev->ndev->name, DRV_MODULE_VERSION); | 1305 | edev->ops->common->set_id(cdev, edev->ndev->name, DRV_MODULE_VERSION); |
1271 | 1306 | ||
1307 | INIT_DELAYED_WORK(&edev->sp_task, qede_sp_task); | ||
1308 | mutex_init(&edev->qede_lock); | ||
1309 | |||
1272 | DP_INFO(edev, "Ending successfully qede probe\n"); | 1310 | DP_INFO(edev, "Ending successfully qede probe\n"); |
1273 | 1311 | ||
1274 | return 0; | 1312 | return 0; |
@@ -1306,6 +1344,7 @@ static void __qede_remove(struct pci_dev *pdev, enum qede_remove_mode mode) | |||
1306 | 1344 | ||
1307 | DP_INFO(edev, "Starting qede_remove\n"); | 1345 | DP_INFO(edev, "Starting qede_remove\n"); |
1308 | 1346 | ||
1347 | cancel_delayed_work_sync(&edev->sp_task); | ||
1309 | unregister_netdev(ndev); | 1348 | unregister_netdev(ndev); |
1310 | 1349 | ||
1311 | edev->ops->common->set_power_state(cdev, PCI_D0); | 1350 | edev->ops->common->set_power_state(cdev, PCI_D0); |
@@ -2036,6 +2075,24 @@ static int qede_start_queues(struct qede_dev *edev) | |||
2036 | return 0; | 2075 | return 0; |
2037 | } | 2076 | } |
2038 | 2077 | ||
2078 | static int qede_set_mcast_rx_mac(struct qede_dev *edev, | ||
2079 | enum qed_filter_xcast_params_type opcode, | ||
2080 | unsigned char *mac, int num_macs) | ||
2081 | { | ||
2082 | struct qed_filter_params filter_cmd; | ||
2083 | int i; | ||
2084 | |||
2085 | memset(&filter_cmd, 0, sizeof(filter_cmd)); | ||
2086 | filter_cmd.type = QED_FILTER_TYPE_MCAST; | ||
2087 | filter_cmd.filter.mcast.type = opcode; | ||
2088 | filter_cmd.filter.mcast.num = num_macs; | ||
2089 | |||
2090 | for (i = 0; i < num_macs; i++, mac += ETH_ALEN) | ||
2091 | ether_addr_copy(filter_cmd.filter.mcast.mac[i], mac); | ||
2092 | |||
2093 | return edev->ops->filter_config(edev->cdev, &filter_cmd); | ||
2094 | } | ||
2095 | |||
2039 | enum qede_unload_mode { | 2096 | enum qede_unload_mode { |
2040 | QEDE_UNLOAD_NORMAL, | 2097 | QEDE_UNLOAD_NORMAL, |
2041 | }; | 2098 | }; |
@@ -2046,6 +2103,9 @@ static void qede_unload(struct qede_dev *edev, enum qede_unload_mode mode) | |||
2046 | 2103 | ||
2047 | DP_INFO(edev, "Starting qede unload\n"); | 2104 | DP_INFO(edev, "Starting qede unload\n"); |
2048 | 2105 | ||
2106 | mutex_lock(&edev->qede_lock); | ||
2107 | edev->state = QEDE_STATE_CLOSED; | ||
2108 | |||
2049 | /* Close OS Tx */ | 2109 | /* Close OS Tx */ |
2050 | netif_tx_disable(edev->ndev); | 2110 | netif_tx_disable(edev->ndev); |
2051 | netif_carrier_off(edev->ndev); | 2111 | netif_carrier_off(edev->ndev); |
@@ -2120,6 +2180,9 @@ static int qede_load(struct qede_dev *edev, enum qede_load_mode mode) | |||
2120 | /* Add primary mac and set Rx filters */ | 2180 | /* Add primary mac and set Rx filters */ |
2121 | ether_addr_copy(edev->primary_mac, edev->ndev->dev_addr); | 2181 | ether_addr_copy(edev->primary_mac, edev->ndev->dev_addr); |
2122 | 2182 | ||
2183 | mutex_lock(&edev->qede_lock); | ||
2184 | edev->state = QEDE_STATE_OPEN; | ||
2185 | mutex_unlock(&edev->qede_lock); | ||
2123 | DP_INFO(edev, "Ending successfully qede load\n"); | 2186 | DP_INFO(edev, "Ending successfully qede load\n"); |
2124 | 2187 | ||
2125 | return 0; | 2188 | return 0; |
@@ -2159,3 +2222,181 @@ static int qede_close(struct net_device *ndev) | |||
2159 | 2222 | ||
2160 | return 0; | 2223 | return 0; |
2161 | } | 2224 | } |
2225 | |||
2226 | static int qede_set_mac_addr(struct net_device *ndev, void *p) | ||
2227 | { | ||
2228 | struct qede_dev *edev = netdev_priv(ndev); | ||
2229 | struct sockaddr *addr = p; | ||
2230 | int rc; | ||
2231 | |||
2232 | ASSERT_RTNL(); /* @@@TBD To be removed */ | ||
2233 | |||
2234 | DP_INFO(edev, "Set_mac_addr called\n"); | ||
2235 | |||
2236 | if (!is_valid_ether_addr(addr->sa_data)) { | ||
2237 | DP_NOTICE(edev, "The MAC address is not valid\n"); | ||
2238 | return -EFAULT; | ||
2239 | } | ||
2240 | |||
2241 | ether_addr_copy(ndev->dev_addr, addr->sa_data); | ||
2242 | |||
2243 | if (!netif_running(ndev)) { | ||
2244 | DP_NOTICE(edev, "The device is currently down\n"); | ||
2245 | return 0; | ||
2246 | } | ||
2247 | |||
2248 | /* Remove the previous primary mac */ | ||
2249 | rc = qede_set_ucast_rx_mac(edev, QED_FILTER_XCAST_TYPE_DEL, | ||
2250 | edev->primary_mac); | ||
2251 | if (rc) | ||
2252 | return rc; | ||
2253 | |||
2254 | /* Add MAC filter according to the new unicast HW MAC address */ | ||
2255 | ether_addr_copy(edev->primary_mac, ndev->dev_addr); | ||
2256 | return qede_set_ucast_rx_mac(edev, QED_FILTER_XCAST_TYPE_ADD, | ||
2257 | edev->primary_mac); | ||
2258 | } | ||
2259 | |||
2260 | static int | ||
2261 | qede_configure_mcast_filtering(struct net_device *ndev, | ||
2262 | enum qed_filter_rx_mode_type *accept_flags) | ||
2263 | { | ||
2264 | struct qede_dev *edev = netdev_priv(ndev); | ||
2265 | unsigned char *mc_macs, *temp; | ||
2266 | struct netdev_hw_addr *ha; | ||
2267 | int rc = 0, mc_count; | ||
2268 | size_t size; | ||
2269 | |||
2270 | size = 64 * ETH_ALEN; | ||
2271 | |||
2272 | mc_macs = kzalloc(size, GFP_KERNEL); | ||
2273 | if (!mc_macs) { | ||
2274 | DP_NOTICE(edev, | ||
2275 | "Failed to allocate memory for multicast MACs\n"); | ||
2276 | rc = -ENOMEM; | ||
2277 | goto exit; | ||
2278 | } | ||
2279 | |||
2280 | temp = mc_macs; | ||
2281 | |||
2282 | /* Remove all previously configured MAC filters */ | ||
2283 | rc = qede_set_mcast_rx_mac(edev, QED_FILTER_XCAST_TYPE_DEL, | ||
2284 | mc_macs, 1); | ||
2285 | if (rc) | ||
2286 | goto exit; | ||
2287 | |||
2288 | netif_addr_lock_bh(ndev); | ||
2289 | |||
2290 | mc_count = netdev_mc_count(ndev); | ||
2291 | if (mc_count < 64) { | ||
2292 | netdev_for_each_mc_addr(ha, ndev) { | ||
2293 | ether_addr_copy(temp, ha->addr); | ||
2294 | temp += ETH_ALEN; | ||
2295 | } | ||
2296 | } | ||
2297 | |||
2298 | netif_addr_unlock_bh(ndev); | ||
2299 | |||
2300 | /* Check for all multicast @@@TBD resource allocation */ | ||
2301 | if ((ndev->flags & IFF_ALLMULTI) || | ||
2302 | (mc_count > 64)) { | ||
2303 | if (*accept_flags == QED_FILTER_RX_MODE_TYPE_REGULAR) | ||
2304 | *accept_flags = QED_FILTER_RX_MODE_TYPE_MULTI_PROMISC; | ||
2305 | } else { | ||
2306 | /* Add all multicast MAC filters */ | ||
2307 | rc = qede_set_mcast_rx_mac(edev, QED_FILTER_XCAST_TYPE_ADD, | ||
2308 | mc_macs, mc_count); | ||
2309 | } | ||
2310 | |||
2311 | exit: | ||
2312 | kfree(mc_macs); | ||
2313 | return rc; | ||
2314 | } | ||
2315 | |||
2316 | static void qede_set_rx_mode(struct net_device *ndev) | ||
2317 | { | ||
2318 | struct qede_dev *edev = netdev_priv(ndev); | ||
2319 | |||
2320 | DP_INFO(edev, "qede_set_rx_mode called\n"); | ||
2321 | |||
2322 | if (edev->state != QEDE_STATE_OPEN) { | ||
2323 | DP_INFO(edev, | ||
2324 | "qede_set_rx_mode called while interface is down\n"); | ||
2325 | } else { | ||
2326 | set_bit(QEDE_SP_RX_MODE, &edev->sp_flags); | ||
2327 | schedule_delayed_work(&edev->sp_task, 0); | ||
2328 | } | ||
2329 | } | ||
2330 | |||
2331 | /* Must be called with qede_lock held */ | ||
2332 | static void qede_config_rx_mode(struct net_device *ndev) | ||
2333 | { | ||
2334 | enum qed_filter_rx_mode_type accept_flags = QED_FILTER_TYPE_UCAST; | ||
2335 | struct qede_dev *edev = netdev_priv(ndev); | ||
2336 | struct qed_filter_params rx_mode; | ||
2337 | unsigned char *uc_macs, *temp; | ||
2338 | struct netdev_hw_addr *ha; | ||
2339 | int rc, uc_count; | ||
2340 | size_t size; | ||
2341 | |||
2342 | netif_addr_lock_bh(ndev); | ||
2343 | |||
2344 | uc_count = netdev_uc_count(ndev); | ||
2345 | size = uc_count * ETH_ALEN; | ||
2346 | |||
2347 | uc_macs = kzalloc(size, GFP_ATOMIC); | ||
2348 | if (!uc_macs) { | ||
2349 | DP_NOTICE(edev, "Failed to allocate memory for unicast MACs\n"); | ||
2350 | netif_addr_unlock_bh(ndev); | ||
2351 | return; | ||
2352 | } | ||
2353 | |||
2354 | temp = uc_macs; | ||
2355 | netdev_for_each_uc_addr(ha, ndev) { | ||
2356 | ether_addr_copy(temp, ha->addr); | ||
2357 | temp += ETH_ALEN; | ||
2358 | } | ||
2359 | |||
2360 | netif_addr_unlock_bh(ndev); | ||
2361 | |||
2362 | /* Configure the struct for the Rx mode */ | ||
2363 | memset(&rx_mode, 0, sizeof(struct qed_filter_params)); | ||
2364 | rx_mode.type = QED_FILTER_TYPE_RX_MODE; | ||
2365 | |||
2366 | /* Remove all previous unicast secondary macs and multicast macs | ||
2367 | * (configrue / leave the primary mac) | ||
2368 | */ | ||
2369 | rc = qede_set_ucast_rx_mac(edev, QED_FILTER_XCAST_TYPE_REPLACE, | ||
2370 | edev->primary_mac); | ||
2371 | if (rc) | ||
2372 | goto out; | ||
2373 | |||
2374 | /* Check for promiscuous */ | ||
2375 | if ((ndev->flags & IFF_PROMISC) || | ||
2376 | (uc_count > 15)) { /* @@@TBD resource allocation - 1 */ | ||
2377 | accept_flags = QED_FILTER_RX_MODE_TYPE_PROMISC; | ||
2378 | } else { | ||
2379 | /* Add MAC filters according to the unicast secondary macs */ | ||
2380 | int i; | ||
2381 | |||
2382 | temp = uc_macs; | ||
2383 | for (i = 0; i < uc_count; i++) { | ||
2384 | rc = qede_set_ucast_rx_mac(edev, | ||
2385 | QED_FILTER_XCAST_TYPE_ADD, | ||
2386 | temp); | ||
2387 | if (rc) | ||
2388 | goto out; | ||
2389 | |||
2390 | temp += ETH_ALEN; | ||
2391 | } | ||
2392 | |||
2393 | rc = qede_configure_mcast_filtering(ndev, &accept_flags); | ||
2394 | if (rc) | ||
2395 | goto out; | ||
2396 | } | ||
2397 | |||
2398 | rx_mode.filter.accept_flags = accept_flags; | ||
2399 | edev->ops->filter_config(edev->cdev, &rx_mode); | ||
2400 | out: | ||
2401 | kfree(uc_macs); | ||
2402 | } | ||