diff options
author | Rajesh Borundia <rajesh.borundia@qlogic.com> | 2014-05-09 02:51:31 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-05-09 13:08:58 -0400 |
commit | d747c3337484afac9953c44ea56a912869778559 (patch) | |
tree | 02a4b3c00eee7fc0e50b60ced8e170643fa0e7de | |
parent | 74b7ba1a8bc994f92cfe4716d80c17f90df5eba3 (diff) |
qlcnic: Add mac learning support to SR-IOV VF.
o SR-IOV VF can be uplinked to bridge/macvtap device.
Enable mac learning to support communication through
embedded switch.
o Learn vlan filters based on QLCNIC_VLAN_FILTERING flag.
Signed-off-by: Rajesh Borundia <rajesh.borundia@qlogic.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic.h | 12 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c | 12 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c | 16 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c | 51 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c | 14 |
6 files changed, 78 insertions, 28 deletions
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h index 7bad613becba..557b911a89f8 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h | |||
@@ -1019,6 +1019,8 @@ struct qlcnic_ipaddr { | |||
1019 | #define QLCNIC_DEL_VXLAN_PORT 0x200000 | 1019 | #define QLCNIC_DEL_VXLAN_PORT 0x200000 |
1020 | #endif | 1020 | #endif |
1021 | 1021 | ||
1022 | #define QLCNIC_VLAN_FILTERING 0x800000 | ||
1023 | |||
1022 | #define QLCNIC_IS_MSI_FAMILY(adapter) \ | 1024 | #define QLCNIC_IS_MSI_FAMILY(adapter) \ |
1023 | ((adapter)->flags & (QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED)) | 1025 | ((adapter)->flags & (QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED)) |
1024 | #define QLCNIC_IS_TSO_CAPABLE(adapter) \ | 1026 | #define QLCNIC_IS_TSO_CAPABLE(adapter) \ |
@@ -2355,6 +2357,16 @@ static inline bool qlcnic_83xx_vf_check(struct qlcnic_adapter *adapter) | |||
2355 | return (device == PCI_DEVICE_ID_QLOGIC_VF_QLE834X) ? true : false; | 2357 | return (device == PCI_DEVICE_ID_QLOGIC_VF_QLE834X) ? true : false; |
2356 | } | 2358 | } |
2357 | 2359 | ||
2360 | static inline bool qlcnic_sriov_check(struct qlcnic_adapter *adapter) | ||
2361 | { | ||
2362 | bool status; | ||
2363 | |||
2364 | status = (qlcnic_sriov_pf_check(adapter) || | ||
2365 | qlcnic_sriov_vf_check(adapter)) ? true : false; | ||
2366 | |||
2367 | return status; | ||
2368 | } | ||
2369 | |||
2358 | static inline u32 qlcnic_get_vnic_func_count(struct qlcnic_adapter *adapter) | 2370 | static inline u32 qlcnic_get_vnic_func_count(struct qlcnic_adapter *adapter) |
2359 | { | 2371 | { |
2360 | if (qlcnic_84xx_check(adapter)) | 2372 | if (qlcnic_84xx_check(adapter)) |
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c index deb2278b48d5..e45bf09af0c9 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c | |||
@@ -313,20 +313,16 @@ static void qlcnic_send_filter(struct qlcnic_adapter *adapter, | |||
313 | u16 vlan_id = 0; | 313 | u16 vlan_id = 0; |
314 | u8 hindex, hval; | 314 | u8 hindex, hval; |
315 | 315 | ||
316 | if (!qlcnic_sriov_pf_check(adapter)) { | 316 | if (ether_addr_equal(phdr->h_source, adapter->mac_addr)) |
317 | if (ether_addr_equal(phdr->h_source, adapter->mac_addr)) | 317 | return; |
318 | return; | 318 | |
319 | } else { | 319 | if (adapter->flags & QLCNIC_VLAN_FILTERING) { |
320 | if (protocol == ETH_P_8021Q) { | 320 | if (protocol == ETH_P_8021Q) { |
321 | vh = (struct vlan_ethhdr *)skb->data; | 321 | vh = (struct vlan_ethhdr *)skb->data; |
322 | vlan_id = ntohs(vh->h_vlan_TCI); | 322 | vlan_id = ntohs(vh->h_vlan_TCI); |
323 | } else if (vlan_tx_tag_present(skb)) { | 323 | } else if (vlan_tx_tag_present(skb)) { |
324 | vlan_id = vlan_tx_tag_get(skb); | 324 | vlan_id = vlan_tx_tag_get(skb); |
325 | } | 325 | } |
326 | |||
327 | if (ether_addr_equal(phdr->h_source, adapter->mac_addr) && | ||
328 | !vlan_id) | ||
329 | return; | ||
330 | } | 326 | } |
331 | 327 | ||
332 | memcpy(&src_addr, phdr->h_source, ETH_ALEN); | 328 | memcpy(&src_addr, phdr->h_source, ETH_ALEN); |
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c index 1a52a781401f..8a570fa3542b 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c | |||
@@ -378,7 +378,8 @@ static int qlcnic_fdb_del(struct ndmsg *ndm, struct nlattr *tb[], | |||
378 | if (!adapter->fdb_mac_learn) | 378 | if (!adapter->fdb_mac_learn) |
379 | return ndo_dflt_fdb_del(ndm, tb, netdev, addr); | 379 | return ndo_dflt_fdb_del(ndm, tb, netdev, addr); |
380 | 380 | ||
381 | if (adapter->flags & QLCNIC_ESWITCH_ENABLED) { | 381 | if ((adapter->flags & QLCNIC_ESWITCH_ENABLED) || |
382 | qlcnic_sriov_check(adapter)) { | ||
382 | if (is_unicast_ether_addr(addr)) { | 383 | if (is_unicast_ether_addr(addr)) { |
383 | err = dev_uc_del(netdev, addr); | 384 | err = dev_uc_del(netdev, addr); |
384 | if (!err) | 385 | if (!err) |
@@ -402,7 +403,8 @@ static int qlcnic_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], | |||
402 | if (!adapter->fdb_mac_learn) | 403 | if (!adapter->fdb_mac_learn) |
403 | return ndo_dflt_fdb_add(ndm, tb, netdev, addr, flags); | 404 | return ndo_dflt_fdb_add(ndm, tb, netdev, addr, flags); |
404 | 405 | ||
405 | if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED)) { | 406 | if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED) && |
407 | !qlcnic_sriov_check(adapter)) { | ||
406 | pr_info("%s: FDB e-switch is not enabled\n", __func__); | 408 | pr_info("%s: FDB e-switch is not enabled\n", __func__); |
407 | return -EOPNOTSUPP; | 409 | return -EOPNOTSUPP; |
408 | } | 410 | } |
@@ -432,7 +434,8 @@ static int qlcnic_fdb_dump(struct sk_buff *skb, struct netlink_callback *ncb, | |||
432 | if (!adapter->fdb_mac_learn) | 434 | if (!adapter->fdb_mac_learn) |
433 | return ndo_dflt_fdb_dump(skb, ncb, netdev, idx); | 435 | return ndo_dflt_fdb_dump(skb, ncb, netdev, idx); |
434 | 436 | ||
435 | if (adapter->flags & QLCNIC_ESWITCH_ENABLED) | 437 | if ((adapter->flags & QLCNIC_ESWITCH_ENABLED) || |
438 | qlcnic_sriov_check(adapter)) | ||
436 | idx = ndo_dflt_fdb_dump(skb, ncb, netdev, idx); | 439 | idx = ndo_dflt_fdb_dump(skb, ncb, netdev, idx); |
437 | 440 | ||
438 | return idx; | 441 | return idx; |
@@ -2809,6 +2812,8 @@ static int qlcnic_close(struct net_device *netdev) | |||
2809 | return 0; | 2812 | return 0; |
2810 | } | 2813 | } |
2811 | 2814 | ||
2815 | #define QLCNIC_VF_LB_BUCKET_SIZE 1 | ||
2816 | |||
2812 | void qlcnic_alloc_lb_filters_mem(struct qlcnic_adapter *adapter) | 2817 | void qlcnic_alloc_lb_filters_mem(struct qlcnic_adapter *adapter) |
2813 | { | 2818 | { |
2814 | void *head; | 2819 | void *head; |
@@ -2824,7 +2829,10 @@ void qlcnic_alloc_lb_filters_mem(struct qlcnic_adapter *adapter) | |||
2824 | spin_lock_init(&adapter->mac_learn_lock); | 2829 | spin_lock_init(&adapter->mac_learn_lock); |
2825 | spin_lock_init(&adapter->rx_mac_learn_lock); | 2830 | spin_lock_init(&adapter->rx_mac_learn_lock); |
2826 | 2831 | ||
2827 | if (qlcnic_82xx_check(adapter)) { | 2832 | if (qlcnic_sriov_vf_check(adapter)) { |
2833 | filter_size = QLCNIC_83XX_SRIOV_VF_MAX_MAC - 1; | ||
2834 | adapter->fhash.fbucket_size = QLCNIC_VF_LB_BUCKET_SIZE; | ||
2835 | } else if (qlcnic_82xx_check(adapter)) { | ||
2828 | filter_size = QLCNIC_LB_MAX_FILTERS; | 2836 | filter_size = QLCNIC_LB_MAX_FILTERS; |
2829 | adapter->fhash.fbucket_size = QLCNIC_LB_BUCKET_SIZE; | 2837 | adapter->fhash.fbucket_size = QLCNIC_LB_BUCKET_SIZE; |
2830 | } else { | 2838 | } else { |
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h index 54159bde2bc7..335b50f7bd3e 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h | |||
@@ -52,6 +52,7 @@ enum qlcnic_bc_commands { | |||
52 | QLCNIC_BC_CMD_CFG_GUEST_VLAN = 0x3, | 52 | QLCNIC_BC_CMD_CFG_GUEST_VLAN = 0x3, |
53 | }; | 53 | }; |
54 | 54 | ||
55 | #define QLCNIC_83XX_SRIOV_VF_MAX_MAC 2 | ||
55 | #define QLC_BC_CMD 1 | 56 | #define QLC_BC_CMD 1 |
56 | 57 | ||
57 | struct qlcnic_trans_list { | 58 | struct qlcnic_trans_list { |
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c index 44cd5bd03744..3b39ab2ad5e9 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c | |||
@@ -199,6 +199,7 @@ int qlcnic_sriov_init(struct qlcnic_adapter *adapter, int num_vfs) | |||
199 | goto qlcnic_destroy_async_wq; | 199 | goto qlcnic_destroy_async_wq; |
200 | } | 200 | } |
201 | sriov->vf_info[i].vp = vp; | 201 | sriov->vf_info[i].vp = vp; |
202 | vp->vlan_mode = QLC_GUEST_VLAN_MODE; | ||
202 | vp->max_tx_bw = MAX_BW; | 203 | vp->max_tx_bw = MAX_BW; |
203 | vp->spoofchk = false; | 204 | vp->spoofchk = false; |
204 | random_ether_addr(vp->mac); | 205 | random_ether_addr(vp->mac); |
@@ -517,6 +518,8 @@ static int qlcnic_sriov_setup_vf(struct qlcnic_adapter *adapter, | |||
517 | { | 518 | { |
518 | int err; | 519 | int err; |
519 | 520 | ||
521 | adapter->flags |= QLCNIC_VLAN_FILTERING; | ||
522 | adapter->ahw->total_nic_func = 1; | ||
520 | INIT_LIST_HEAD(&adapter->vf_mc_list); | 523 | INIT_LIST_HEAD(&adapter->vf_mc_list); |
521 | if (!qlcnic_use_msi_x && !!qlcnic_use_msi) | 524 | if (!qlcnic_use_msi_x && !!qlcnic_use_msi) |
522 | dev_warn(&adapter->pdev->dev, | 525 | dev_warn(&adapter->pdev->dev, |
@@ -772,6 +775,7 @@ static int qlcnic_sriov_prepare_bc_hdr(struct qlcnic_bc_trans *trans, | |||
772 | cmd->req.arg = (u32 *)trans->req_pay; | 775 | cmd->req.arg = (u32 *)trans->req_pay; |
773 | cmd->rsp.arg = (u32 *)trans->rsp_pay; | 776 | cmd->rsp.arg = (u32 *)trans->rsp_pay; |
774 | cmd_op = cmd->req.arg[0] & 0xff; | 777 | cmd_op = cmd->req.arg[0] & 0xff; |
778 | cmd->cmd_op = cmd_op; | ||
775 | remainder = (trans->rsp_pay_size) % (bc_pay_sz); | 779 | remainder = (trans->rsp_pay_size) % (bc_pay_sz); |
776 | num_frags = (trans->rsp_pay_size) / (bc_pay_sz); | 780 | num_frags = (trans->rsp_pay_size) / (bc_pay_sz); |
777 | if (remainder) | 781 | if (remainder) |
@@ -1410,12 +1414,17 @@ retry: | |||
1410 | (mbx_err_code == QLCNIC_MBX_PORT_RSP_OK)) { | 1414 | (mbx_err_code == QLCNIC_MBX_PORT_RSP_OK)) { |
1411 | rsp = QLCNIC_RCODE_SUCCESS; | 1415 | rsp = QLCNIC_RCODE_SUCCESS; |
1412 | } else { | 1416 | } else { |
1413 | rsp = mbx_err_code; | 1417 | if (cmd->type == QLC_83XX_MBX_CMD_NO_WAIT) { |
1414 | if (!rsp) | 1418 | rsp = QLCNIC_RCODE_SUCCESS; |
1415 | rsp = 1; | 1419 | } else { |
1416 | dev_err(dev, | 1420 | rsp = mbx_err_code; |
1417 | "MBX command 0x%x failed with err:0x%x for VF %d\n", | 1421 | if (!rsp) |
1418 | opcode, mbx_err_code, func); | 1422 | rsp = 1; |
1423 | |||
1424 | dev_err(dev, | ||
1425 | "MBX command 0x%x failed with err:0x%x for VF %d\n", | ||
1426 | opcode, mbx_err_code, func); | ||
1427 | } | ||
1419 | } | 1428 | } |
1420 | 1429 | ||
1421 | err_out: | 1430 | err_out: |
@@ -1537,6 +1546,28 @@ void qlcnic_sriov_vf_set_multi(struct net_device *netdev) | |||
1537 | } | 1546 | } |
1538 | } | 1547 | } |
1539 | 1548 | ||
1549 | /* configure unicast MAC address, if there is not sufficient space | ||
1550 | * to store all the unicast addresses then enable promiscuous mode | ||
1551 | */ | ||
1552 | if (netdev_uc_count(netdev) > ahw->max_uc_count) { | ||
1553 | mode = VPORT_MISS_MODE_ACCEPT_ALL; | ||
1554 | } else if (!netdev_uc_empty(netdev)) { | ||
1555 | netdev_for_each_uc_addr(ha, netdev) | ||
1556 | qlcnic_vf_add_mc_list(netdev, ha->addr); | ||
1557 | } | ||
1558 | |||
1559 | if (adapter->pdev->is_virtfn) { | ||
1560 | if (mode == VPORT_MISS_MODE_ACCEPT_ALL && | ||
1561 | !adapter->fdb_mac_learn) { | ||
1562 | qlcnic_alloc_lb_filters_mem(adapter); | ||
1563 | adapter->drv_mac_learn = 1; | ||
1564 | adapter->rx_mac_learn = true; | ||
1565 | } else { | ||
1566 | adapter->drv_mac_learn = 0; | ||
1567 | adapter->rx_mac_learn = false; | ||
1568 | } | ||
1569 | } | ||
1570 | |||
1540 | qlcnic_nic_set_promisc(adapter, mode); | 1571 | qlcnic_nic_set_promisc(adapter, mode); |
1541 | } | 1572 | } |
1542 | 1573 | ||
@@ -1830,6 +1861,12 @@ static int qlcnic_sriov_vf_idc_unknown_state(struct qlcnic_adapter *adapter) | |||
1830 | return 0; | 1861 | return 0; |
1831 | } | 1862 | } |
1832 | 1863 | ||
1864 | static void qlcnic_sriov_vf_periodic_tasks(struct qlcnic_adapter *adapter) | ||
1865 | { | ||
1866 | if (adapter->fhash.fnum) | ||
1867 | qlcnic_prune_lb_filters(adapter); | ||
1868 | } | ||
1869 | |||
1833 | static void qlcnic_sriov_vf_poll_dev_state(struct work_struct *work) | 1870 | static void qlcnic_sriov_vf_poll_dev_state(struct work_struct *work) |
1834 | { | 1871 | { |
1835 | struct qlcnic_adapter *adapter; | 1872 | struct qlcnic_adapter *adapter; |
@@ -1861,6 +1898,8 @@ static void qlcnic_sriov_vf_poll_dev_state(struct work_struct *work) | |||
1861 | } | 1898 | } |
1862 | 1899 | ||
1863 | idc->prev_state = idc->curr_state; | 1900 | idc->prev_state = idc->curr_state; |
1901 | qlcnic_sriov_vf_periodic_tasks(adapter); | ||
1902 | |||
1864 | if (!ret && test_bit(QLC_83XX_MODULE_LOADED, &idc->status)) | 1903 | if (!ret && test_bit(QLC_83XX_MODULE_LOADED, &idc->status)) |
1865 | qlcnic_schedule_work(adapter, qlcnic_sriov_vf_poll_dev_state, | 1904 | qlcnic_schedule_work(adapter, qlcnic_sriov_vf_poll_dev_state, |
1866 | idc->delay); | 1905 | idc->delay); |
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c index 199ab7c6fbad..6d2f72f114f2 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c | |||
@@ -84,7 +84,7 @@ static int qlcnic_sriov_pf_cal_res_limit(struct qlcnic_adapter *adapter, | |||
84 | info->max_tx_ques = res->num_tx_queues / max; | 84 | info->max_tx_ques = res->num_tx_queues / max; |
85 | 85 | ||
86 | if (qlcnic_83xx_pf_check(adapter)) | 86 | if (qlcnic_83xx_pf_check(adapter)) |
87 | num_macs = 1; | 87 | num_macs = QLCNIC_83XX_SRIOV_VF_MAX_MAC; |
88 | 88 | ||
89 | info->max_rx_mcast_mac_filters = res->num_rx_mcast_mac_filters; | 89 | info->max_rx_mcast_mac_filters = res->num_rx_mcast_mac_filters; |
90 | 90 | ||
@@ -338,9 +338,12 @@ static int qlcnic_sriov_pf_cfg_vlan_filtering(struct qlcnic_adapter *adapter, | |||
338 | 338 | ||
339 | cmd.req.arg[1] = 0x4; | 339 | cmd.req.arg[1] = 0x4; |
340 | if (enable) { | 340 | if (enable) { |
341 | adapter->flags |= QLCNIC_VLAN_FILTERING; | ||
341 | cmd.req.arg[1] |= BIT_16; | 342 | cmd.req.arg[1] |= BIT_16; |
342 | if (qlcnic_84xx_check(adapter)) | 343 | if (qlcnic_84xx_check(adapter)) |
343 | cmd.req.arg[1] |= QLC_SRIOV_ALLOW_VLAN0; | 344 | cmd.req.arg[1] |= QLC_SRIOV_ALLOW_VLAN0; |
345 | } else { | ||
346 | adapter->flags &= ~QLCNIC_VLAN_FILTERING; | ||
344 | } | 347 | } |
345 | 348 | ||
346 | err = qlcnic_issue_cmd(adapter, &cmd); | 349 | err = qlcnic_issue_cmd(adapter, &cmd); |
@@ -1253,7 +1256,6 @@ static int qlcnic_sriov_validate_cfg_macvlan(struct qlcnic_adapter *adapter, | |||
1253 | struct qlcnic_vf_info *vf, | 1256 | struct qlcnic_vf_info *vf, |
1254 | struct qlcnic_cmd_args *cmd) | 1257 | struct qlcnic_cmd_args *cmd) |
1255 | { | 1258 | { |
1256 | struct qlcnic_macvlan_mbx *macvlan; | ||
1257 | struct qlcnic_vport *vp = vf->vp; | 1259 | struct qlcnic_vport *vp = vf->vp; |
1258 | u8 op, new_op; | 1260 | u8 op, new_op; |
1259 | 1261 | ||
@@ -1263,14 +1265,6 @@ static int qlcnic_sriov_validate_cfg_macvlan(struct qlcnic_adapter *adapter, | |||
1263 | cmd->req.arg[1] |= (vf->vp->handle << 16); | 1265 | cmd->req.arg[1] |= (vf->vp->handle << 16); |
1264 | cmd->req.arg[1] |= BIT_31; | 1266 | cmd->req.arg[1] |= BIT_31; |
1265 | 1267 | ||
1266 | macvlan = (struct qlcnic_macvlan_mbx *)&cmd->req.arg[2]; | ||
1267 | if (!(macvlan->mac_addr0 & BIT_0)) { | ||
1268 | dev_err(&adapter->pdev->dev, | ||
1269 | "MAC address change is not allowed from VF %d", | ||
1270 | vf->pci_func); | ||
1271 | return -EINVAL; | ||
1272 | } | ||
1273 | |||
1274 | if (vp->vlan_mode == QLC_PVID_MODE) { | 1268 | if (vp->vlan_mode == QLC_PVID_MODE) { |
1275 | op = cmd->req.arg[1] & 0x7; | 1269 | op = cmd->req.arg[1] & 0x7; |
1276 | cmd->req.arg[1] &= ~0x7; | 1270 | cmd->req.arg[1] &= ~0x7; |