diff options
author | Rajesh Borundia <rajesh.borundia@qlogic.com> | 2013-04-19 03:01:12 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-04-19 16:14:40 -0400 |
commit | 91b7282b613d4da65e8b4c87d521156cdc64c169 (patch) | |
tree | 1b412de7cd339ab96922cd9e427572bf123c8ff0 /drivers/net | |
parent | 4000e7a78d12d71e37fcd2366c73fcb02e97fffb (diff) |
qlcnic: Support VLAN id config.
o Add support for VLAN id configuration per VF using
iproute2 tool.
o VLAN id's 1-4094 are treated as PVID by the PF and
Guest VLAN tagging is not allowed by default.
o PVID is disabled when the VLAN id is set to 0
o Guest VLAN tagging is allowed when the VLAN id is set to 4095.
o Only one Guest VLAN id is supported.
o VLAN id can be changed only when the VF driver is not loaded.
Signed-off-by: Manish Chopra <manish.chopra@qlogic.com>
Signed-off-by: Sucheta Chakraborty <sucheta.chakraborty@qlogic.com>
Signed-off-by: Rajesh Borundia <rajesh.borundia@qlogic.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic.h | 17 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c | 5 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c | 18 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c | 8 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c | 41 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h | 18 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c | 171 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c | 243 |
8 files changed, 492 insertions, 29 deletions
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h index 2b13bd0495ea..7dc7e02d00aa 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h | |||
@@ -979,7 +979,8 @@ struct qlcnic_adapter { | |||
979 | u8 reset_ctx_cnt; | 979 | u8 reset_ctx_cnt; |
980 | 980 | ||
981 | u16 is_up; | 981 | u16 is_up; |
982 | u16 pvid; | 982 | u16 rx_pvid; |
983 | u16 tx_pvid; | ||
983 | 984 | ||
984 | u32 irq; | 985 | u32 irq; |
985 | u32 heartbeat; | 986 | u32 heartbeat; |
@@ -1445,10 +1446,10 @@ void qlcnic_post_rx_buffers(struct qlcnic_adapter *adapter, | |||
1445 | struct qlcnic_host_rds_ring *rds_ring, u8 ring_id); | 1446 | struct qlcnic_host_rds_ring *rds_ring, u8 ring_id); |
1446 | int qlcnic_process_rcv_ring(struct qlcnic_host_sds_ring *sds_ring, int max); | 1447 | int qlcnic_process_rcv_ring(struct qlcnic_host_sds_ring *sds_ring, int max); |
1447 | void qlcnic_set_multi(struct net_device *netdev); | 1448 | void qlcnic_set_multi(struct net_device *netdev); |
1448 | void __qlcnic_set_multi(struct net_device *netdev); | 1449 | void __qlcnic_set_multi(struct net_device *, u16); |
1449 | int qlcnic_nic_add_mac(struct qlcnic_adapter *, const u8 *); | 1450 | int qlcnic_nic_add_mac(struct qlcnic_adapter *, const u8 *, u16); |
1450 | int qlcnic_nic_del_mac(struct qlcnic_adapter *, const u8 *); | 1451 | int qlcnic_nic_del_mac(struct qlcnic_adapter *, const u8 *); |
1451 | void qlcnic_free_mac_list(struct qlcnic_adapter *adapter); | 1452 | void qlcnic_82xx_free_mac_list(struct qlcnic_adapter *adapter); |
1452 | 1453 | ||
1453 | int qlcnic_fw_cmd_set_mtu(struct qlcnic_adapter *adapter, int mtu); | 1454 | int qlcnic_fw_cmd_set_mtu(struct qlcnic_adapter *adapter, int mtu); |
1454 | int qlcnic_fw_cmd_set_drv_version(struct qlcnic_adapter *); | 1455 | int qlcnic_fw_cmd_set_drv_version(struct qlcnic_adapter *); |
@@ -1530,7 +1531,7 @@ int qlcnic_83xx_configure_opmode(struct qlcnic_adapter *adapter); | |||
1530 | int qlcnic_read_mac_addr(struct qlcnic_adapter *); | 1531 | int qlcnic_read_mac_addr(struct qlcnic_adapter *); |
1531 | int qlcnic_setup_netdev(struct qlcnic_adapter *, struct net_device *, int); | 1532 | int qlcnic_setup_netdev(struct qlcnic_adapter *, struct net_device *, int); |
1532 | void qlcnic_sriov_vf_schedule_multi(struct net_device *); | 1533 | void qlcnic_sriov_vf_schedule_multi(struct net_device *); |
1533 | void qlcnic_vf_add_mc_list(struct net_device *); | 1534 | void qlcnic_vf_add_mc_list(struct net_device *, u16); |
1534 | 1535 | ||
1535 | /* | 1536 | /* |
1536 | * QLOGIC Board information | 1537 | * QLOGIC Board information |
@@ -1606,6 +1607,7 @@ struct qlcnic_hardware_ops { | |||
1606 | int (*config_promisc_mode) (struct qlcnic_adapter *, u32); | 1607 | int (*config_promisc_mode) (struct qlcnic_adapter *, u32); |
1607 | void (*change_l2_filter) (struct qlcnic_adapter *, u64 *, u16); | 1608 | void (*change_l2_filter) (struct qlcnic_adapter *, u64 *, u16); |
1608 | int (*get_board_info) (struct qlcnic_adapter *); | 1609 | int (*get_board_info) (struct qlcnic_adapter *); |
1610 | void (*free_mac_list) (struct qlcnic_adapter *); | ||
1609 | }; | 1611 | }; |
1610 | 1612 | ||
1611 | extern struct qlcnic_nic_template qlcnic_vf_ops; | 1613 | extern struct qlcnic_nic_template qlcnic_vf_ops; |
@@ -1815,6 +1817,11 @@ static inline int qlcnic_get_board_info(struct qlcnic_adapter *adapter) | |||
1815 | return adapter->ahw->hw_ops->get_board_info(adapter); | 1817 | return adapter->ahw->hw_ops->get_board_info(adapter); |
1816 | } | 1818 | } |
1817 | 1819 | ||
1820 | static inline void qlcnic_free_mac_list(struct qlcnic_adapter *adapter) | ||
1821 | { | ||
1822 | return adapter->ahw->hw_ops->free_mac_list(adapter); | ||
1823 | } | ||
1824 | |||
1818 | static inline void qlcnic_dev_request_reset(struct qlcnic_adapter *adapter, | 1825 | static inline void qlcnic_dev_request_reset(struct qlcnic_adapter *adapter, |
1819 | u32 key) | 1826 | u32 key) |
1820 | { | 1827 | { |
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c index 4035e82167a8..3a4b5723b94e 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c | |||
@@ -172,6 +172,7 @@ static struct qlcnic_hardware_ops qlcnic_83xx_hw_ops = { | |||
172 | .config_promisc_mode = qlcnic_83xx_nic_set_promisc, | 172 | .config_promisc_mode = qlcnic_83xx_nic_set_promisc, |
173 | .change_l2_filter = qlcnic_83xx_change_l2_filter, | 173 | .change_l2_filter = qlcnic_83xx_change_l2_filter, |
174 | .get_board_info = qlcnic_83xx_get_port_info, | 174 | .get_board_info = qlcnic_83xx_get_port_info, |
175 | .free_mac_list = qlcnic_82xx_free_mac_list, | ||
175 | }; | 176 | }; |
176 | 177 | ||
177 | static struct qlcnic_nic_template qlcnic_83xx_ops = { | 178 | static struct qlcnic_nic_template qlcnic_83xx_ops = { |
@@ -1797,6 +1798,10 @@ int qlcnic_83xx_sre_macaddr_change(struct qlcnic_adapter *adapter, u8 *addr, | |||
1797 | if (err) | 1798 | if (err) |
1798 | return err; | 1799 | return err; |
1799 | 1800 | ||
1801 | if (vlan_id) | ||
1802 | op = (op == QLCNIC_MAC_ADD || op == QLCNIC_MAC_VLAN_ADD) ? | ||
1803 | QLCNIC_MAC_VLAN_ADD : QLCNIC_MAC_VLAN_DEL; | ||
1804 | |||
1800 | cmd.req.arg[1] = op | (1 << 8); | 1805 | cmd.req.arg[1] = op | (1 << 8); |
1801 | qlcnic_83xx_set_interface_id_macaddr(adapter, &temp); | 1806 | qlcnic_83xx_set_interface_id_macaddr(adapter, &temp); |
1802 | cmd.req.arg[1] |= temp; | 1807 | cmd.req.arg[1] |= temp; |
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c index c3cbfaea97c3..6a6512ba9f38 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c | |||
@@ -468,7 +468,7 @@ int qlcnic_nic_del_mac(struct qlcnic_adapter *adapter, const u8 *addr) | |||
468 | return err; | 468 | return err; |
469 | } | 469 | } |
470 | 470 | ||
471 | int qlcnic_nic_add_mac(struct qlcnic_adapter *adapter, const u8 *addr) | 471 | int qlcnic_nic_add_mac(struct qlcnic_adapter *adapter, const u8 *addr, u16 vlan) |
472 | { | 472 | { |
473 | struct list_head *head; | 473 | struct list_head *head; |
474 | struct qlcnic_mac_list_s *cur; | 474 | struct qlcnic_mac_list_s *cur; |
@@ -487,7 +487,7 @@ int qlcnic_nic_add_mac(struct qlcnic_adapter *adapter, const u8 *addr) | |||
487 | memcpy(cur->mac_addr, addr, ETH_ALEN); | 487 | memcpy(cur->mac_addr, addr, ETH_ALEN); |
488 | 488 | ||
489 | if (qlcnic_sre_macaddr_change(adapter, | 489 | if (qlcnic_sre_macaddr_change(adapter, |
490 | cur->mac_addr, 0, QLCNIC_MAC_ADD)) { | 490 | cur->mac_addr, vlan, QLCNIC_MAC_ADD)) { |
491 | kfree(cur); | 491 | kfree(cur); |
492 | return -EIO; | 492 | return -EIO; |
493 | } | 493 | } |
@@ -496,7 +496,7 @@ int qlcnic_nic_add_mac(struct qlcnic_adapter *adapter, const u8 *addr) | |||
496 | return 0; | 496 | return 0; |
497 | } | 497 | } |
498 | 498 | ||
499 | void __qlcnic_set_multi(struct net_device *netdev) | 499 | void __qlcnic_set_multi(struct net_device *netdev, u16 vlan) |
500 | { | 500 | { |
501 | struct qlcnic_adapter *adapter = netdev_priv(netdev); | 501 | struct qlcnic_adapter *adapter = netdev_priv(netdev); |
502 | struct netdev_hw_addr *ha; | 502 | struct netdev_hw_addr *ha; |
@@ -509,8 +509,8 @@ void __qlcnic_set_multi(struct net_device *netdev) | |||
509 | return; | 509 | return; |
510 | 510 | ||
511 | if (!qlcnic_sriov_vf_check(adapter)) | 511 | if (!qlcnic_sriov_vf_check(adapter)) |
512 | qlcnic_nic_add_mac(adapter, adapter->mac_addr); | 512 | qlcnic_nic_add_mac(adapter, adapter->mac_addr, vlan); |
513 | qlcnic_nic_add_mac(adapter, bcast_addr); | 513 | qlcnic_nic_add_mac(adapter, bcast_addr, vlan); |
514 | 514 | ||
515 | if (netdev->flags & IFF_PROMISC) { | 515 | if (netdev->flags & IFF_PROMISC) { |
516 | if (!(adapter->flags & QLCNIC_PROMISC_DISABLED)) | 516 | if (!(adapter->flags & QLCNIC_PROMISC_DISABLED)) |
@@ -526,12 +526,12 @@ void __qlcnic_set_multi(struct net_device *netdev) | |||
526 | 526 | ||
527 | if (!netdev_mc_empty(netdev) && !qlcnic_sriov_vf_check(adapter)) { | 527 | if (!netdev_mc_empty(netdev) && !qlcnic_sriov_vf_check(adapter)) { |
528 | netdev_for_each_mc_addr(ha, netdev) { | 528 | netdev_for_each_mc_addr(ha, netdev) { |
529 | qlcnic_nic_add_mac(adapter, ha->addr); | 529 | qlcnic_nic_add_mac(adapter, ha->addr, vlan); |
530 | } | 530 | } |
531 | } | 531 | } |
532 | 532 | ||
533 | if (qlcnic_sriov_vf_check(adapter)) | 533 | if (qlcnic_sriov_vf_check(adapter)) |
534 | qlcnic_vf_add_mc_list(netdev); | 534 | qlcnic_vf_add_mc_list(netdev, vlan); |
535 | 535 | ||
536 | send_fw_cmd: | 536 | send_fw_cmd: |
537 | if (!qlcnic_sriov_vf_check(adapter)) { | 537 | if (!qlcnic_sriov_vf_check(adapter)) { |
@@ -570,7 +570,7 @@ void qlcnic_set_multi(struct net_device *netdev) | |||
570 | qlcnic_sriov_vf_schedule_multi(adapter->netdev); | 570 | qlcnic_sriov_vf_schedule_multi(adapter->netdev); |
571 | return; | 571 | return; |
572 | } | 572 | } |
573 | __qlcnic_set_multi(netdev); | 573 | __qlcnic_set_multi(netdev, 0); |
574 | } | 574 | } |
575 | 575 | ||
576 | int qlcnic_82xx_nic_set_promisc(struct qlcnic_adapter *adapter, u32 mode) | 576 | int qlcnic_82xx_nic_set_promisc(struct qlcnic_adapter *adapter, u32 mode) |
@@ -592,7 +592,7 @@ int qlcnic_82xx_nic_set_promisc(struct qlcnic_adapter *adapter, u32 mode) | |||
592 | (struct cmd_desc_type0 *)&req, 1); | 592 | (struct cmd_desc_type0 *)&req, 1); |
593 | } | 593 | } |
594 | 594 | ||
595 | void qlcnic_free_mac_list(struct qlcnic_adapter *adapter) | 595 | void qlcnic_82xx_free_mac_list(struct qlcnic_adapter *adapter) |
596 | { | 596 | { |
597 | struct qlcnic_mac_list_s *cur; | 597 | struct qlcnic_mac_list_s *cur; |
598 | struct list_head *head = &adapter->mac_list; | 598 | struct list_head *head = &adapter->mac_list; |
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c index f3fe31e8f6bd..356859b9f21c 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c | |||
@@ -344,14 +344,14 @@ static int qlcnic_tx_pkt(struct qlcnic_adapter *adapter, | |||
344 | flags = FLAGS_VLAN_OOB; | 344 | flags = FLAGS_VLAN_OOB; |
345 | vlan_tci = vlan_tx_tag_get(skb); | 345 | vlan_tci = vlan_tx_tag_get(skb); |
346 | } | 346 | } |
347 | if (unlikely(adapter->pvid)) { | 347 | if (unlikely(adapter->tx_pvid)) { |
348 | if (vlan_tci && !(adapter->flags & QLCNIC_TAGGING_ENABLED)) | 348 | if (vlan_tci && !(adapter->flags & QLCNIC_TAGGING_ENABLED)) |
349 | return -EIO; | 349 | return -EIO; |
350 | if (vlan_tci && (adapter->flags & QLCNIC_TAGGING_ENABLED)) | 350 | if (vlan_tci && (adapter->flags & QLCNIC_TAGGING_ENABLED)) |
351 | goto set_flags; | 351 | goto set_flags; |
352 | 352 | ||
353 | flags = FLAGS_VLAN_OOB; | 353 | flags = FLAGS_VLAN_OOB; |
354 | vlan_tci = adapter->pvid; | 354 | vlan_tci = adapter->tx_pvid; |
355 | } | 355 | } |
356 | set_flags: | 356 | set_flags: |
357 | qlcnic_set_tx_vlan_tci(first_desc, vlan_tci); | 357 | qlcnic_set_tx_vlan_tci(first_desc, vlan_tci); |
@@ -980,10 +980,10 @@ static inline int qlcnic_check_rx_tagging(struct qlcnic_adapter *adapter, | |||
980 | memmove(skb->data + VLAN_HLEN, eth_hdr, ETH_ALEN * 2); | 980 | memmove(skb->data + VLAN_HLEN, eth_hdr, ETH_ALEN * 2); |
981 | skb_pull(skb, VLAN_HLEN); | 981 | skb_pull(skb, VLAN_HLEN); |
982 | } | 982 | } |
983 | if (!adapter->pvid) | 983 | if (!adapter->rx_pvid) |
984 | return 0; | 984 | return 0; |
985 | 985 | ||
986 | if (*vlan_tag == adapter->pvid) { | 986 | if (*vlan_tag == adapter->rx_pvid) { |
987 | /* Outer vlan tag. Packet should follow non-vlan path */ | 987 | /* Outer vlan tag. Packet should follow non-vlan path */ |
988 | *vlan_tag = 0xffff; | 988 | *vlan_tag = 0xffff; |
989 | return 0; | 989 | return 0; |
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c index b3ab7a3386e3..9890aa8abdcd 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c | |||
@@ -290,7 +290,7 @@ static int qlcnic_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], | |||
290 | return err; | 290 | return err; |
291 | 291 | ||
292 | if (is_unicast_ether_addr(addr)) | 292 | if (is_unicast_ether_addr(addr)) |
293 | err = qlcnic_nic_add_mac(adapter, addr); | 293 | err = qlcnic_nic_add_mac(adapter, addr, 0); |
294 | else if (is_multicast_ether_addr(addr)) | 294 | else if (is_multicast_ether_addr(addr)) |
295 | err = dev_mc_add_excl(netdev, addr); | 295 | err = dev_mc_add_excl(netdev, addr); |
296 | else | 296 | else |
@@ -345,6 +345,7 @@ static const struct net_device_ops qlcnic_netdev_ops = { | |||
345 | .ndo_set_vf_mac = qlcnic_sriov_set_vf_mac, | 345 | .ndo_set_vf_mac = qlcnic_sriov_set_vf_mac, |
346 | .ndo_set_vf_tx_rate = qlcnic_sriov_set_vf_tx_rate, | 346 | .ndo_set_vf_tx_rate = qlcnic_sriov_set_vf_tx_rate, |
347 | .ndo_get_vf_config = qlcnic_sriov_get_vf_config, | 347 | .ndo_get_vf_config = qlcnic_sriov_get_vf_config, |
348 | .ndo_set_vf_vlan = qlcnic_sriov_set_vf_vlan, | ||
348 | #endif | 349 | #endif |
349 | }; | 350 | }; |
350 | 351 | ||
@@ -404,6 +405,7 @@ static struct qlcnic_hardware_ops qlcnic_hw_ops = { | |||
404 | .config_promisc_mode = qlcnic_82xx_nic_set_promisc, | 405 | .config_promisc_mode = qlcnic_82xx_nic_set_promisc, |
405 | .change_l2_filter = qlcnic_82xx_change_filter, | 406 | .change_l2_filter = qlcnic_82xx_change_filter, |
406 | .get_board_info = qlcnic_82xx_get_board_info, | 407 | .get_board_info = qlcnic_82xx_get_board_info, |
408 | .free_mac_list = qlcnic_82xx_free_mac_list, | ||
407 | }; | 409 | }; |
408 | 410 | ||
409 | int qlcnic_enable_msix(struct qlcnic_adapter *adapter, u32 num_msix) | 411 | int qlcnic_enable_msix(struct qlcnic_adapter *adapter, u32 num_msix) |
@@ -900,16 +902,31 @@ void qlcnic_set_vlan_config(struct qlcnic_adapter *adapter, | |||
900 | else | 902 | else |
901 | adapter->flags |= QLCNIC_TAGGING_ENABLED; | 903 | adapter->flags |= QLCNIC_TAGGING_ENABLED; |
902 | 904 | ||
903 | if (esw_cfg->vlan_id) | 905 | if (esw_cfg->vlan_id) { |
904 | adapter->pvid = esw_cfg->vlan_id; | 906 | adapter->rx_pvid = esw_cfg->vlan_id; |
905 | else | 907 | adapter->tx_pvid = esw_cfg->vlan_id; |
906 | adapter->pvid = 0; | 908 | } else { |
909 | adapter->rx_pvid = 0; | ||
910 | adapter->tx_pvid = 0; | ||
911 | } | ||
907 | } | 912 | } |
908 | 913 | ||
909 | static int | 914 | static int |
910 | qlcnic_vlan_rx_add(struct net_device *netdev, __be16 proto, u16 vid) | 915 | qlcnic_vlan_rx_add(struct net_device *netdev, __be16 proto, u16 vid) |
911 | { | 916 | { |
912 | struct qlcnic_adapter *adapter = netdev_priv(netdev); | 917 | struct qlcnic_adapter *adapter = netdev_priv(netdev); |
918 | int err; | ||
919 | |||
920 | if (qlcnic_sriov_vf_check(adapter)) { | ||
921 | err = qlcnic_sriov_cfg_vf_guest_vlan(adapter, vid, 1); | ||
922 | if (err) { | ||
923 | netdev_err(netdev, | ||
924 | "Cannot add VLAN filter for VLAN id %d, err=%d", | ||
925 | vid, err); | ||
926 | return err; | ||
927 | } | ||
928 | } | ||
929 | |||
913 | set_bit(vid, adapter->vlans); | 930 | set_bit(vid, adapter->vlans); |
914 | return 0; | 931 | return 0; |
915 | } | 932 | } |
@@ -918,6 +935,17 @@ static int | |||
918 | qlcnic_vlan_rx_del(struct net_device *netdev, __be16 proto, u16 vid) | 935 | qlcnic_vlan_rx_del(struct net_device *netdev, __be16 proto, u16 vid) |
919 | { | 936 | { |
920 | struct qlcnic_adapter *adapter = netdev_priv(netdev); | 937 | struct qlcnic_adapter *adapter = netdev_priv(netdev); |
938 | int err; | ||
939 | |||
940 | if (qlcnic_sriov_vf_check(adapter)) { | ||
941 | err = qlcnic_sriov_cfg_vf_guest_vlan(adapter, vid, 0); | ||
942 | if (err) { | ||
943 | netdev_err(netdev, | ||
944 | "Cannot delete VLAN filter for VLAN id %d, err=%d", | ||
945 | vid, err); | ||
946 | return err; | ||
947 | } | ||
948 | } | ||
921 | 949 | ||
922 | qlcnic_restore_indev_addr(netdev, NETDEV_DOWN); | 950 | qlcnic_restore_indev_addr(netdev, NETDEV_DOWN); |
923 | clear_bit(vid, adapter->vlans); | 951 | clear_bit(vid, adapter->vlans); |
@@ -1736,6 +1764,9 @@ qlcnic_setup_netdev(struct qlcnic_adapter *adapter, struct net_device *netdev, | |||
1736 | if (qlcnic_vlan_tx_check(adapter)) | 1764 | if (qlcnic_vlan_tx_check(adapter)) |
1737 | netdev->features |= (NETIF_F_HW_VLAN_CTAG_TX); | 1765 | netdev->features |= (NETIF_F_HW_VLAN_CTAG_TX); |
1738 | 1766 | ||
1767 | if (qlcnic_sriov_vf_check(adapter)) | ||
1768 | netdev->features |= NETIF_F_HW_VLAN_CTAG_FILTER; | ||
1769 | |||
1739 | if (adapter->ahw->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO) | 1770 | if (adapter->ahw->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO) |
1740 | netdev->features |= NETIF_F_LRO; | 1771 | netdev->features |= NETIF_F_LRO; |
1741 | 1772 | ||
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h index 5f73d42d6689..d85fbb57c25b 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h | |||
@@ -48,6 +48,8 @@ struct qlcnic_bc_hdr { | |||
48 | enum qlcnic_bc_commands { | 48 | enum qlcnic_bc_commands { |
49 | QLCNIC_BC_CMD_CHANNEL_INIT = 0x0, | 49 | QLCNIC_BC_CMD_CHANNEL_INIT = 0x0, |
50 | QLCNIC_BC_CMD_CHANNEL_TERM = 0x1, | 50 | QLCNIC_BC_CMD_CHANNEL_TERM = 0x1, |
51 | QLCNIC_BC_CMD_GET_ACL = 0x2, | ||
52 | QLCNIC_BC_CMD_CFG_GUEST_VLAN = 0x3, | ||
51 | }; | 53 | }; |
52 | 54 | ||
53 | #define QLC_BC_CMD 1 | 55 | #define QLC_BC_CMD 1 |
@@ -95,6 +97,12 @@ enum qlcnic_vf_state { | |||
95 | QLC_BC_VF_SOFT_FLR, | 97 | QLC_BC_VF_SOFT_FLR, |
96 | }; | 98 | }; |
97 | 99 | ||
100 | enum qlcnic_vlan_mode { | ||
101 | QLC_NO_VLAN_MODE = 0, | ||
102 | QLC_PVID_MODE, | ||
103 | QLC_GUEST_VLAN_MODE, | ||
104 | }; | ||
105 | |||
98 | struct qlcnic_resources { | 106 | struct qlcnic_resources { |
99 | u16 num_tx_mac_filters; | 107 | u16 num_tx_mac_filters; |
100 | u16 num_rx_ucast_mac_filters; | 108 | u16 num_rx_ucast_mac_filters; |
@@ -118,6 +126,9 @@ struct qlcnic_vport { | |||
118 | u16 handle; | 126 | u16 handle; |
119 | u16 max_tx_bw; | 127 | u16 max_tx_bw; |
120 | u16 min_tx_bw; | 128 | u16 min_tx_bw; |
129 | u8 vlan_mode; | ||
130 | u16 vlan; | ||
131 | u8 qos; | ||
121 | u8 mac[6]; | 132 | u8 mac[6]; |
122 | }; | 133 | }; |
123 | 134 | ||
@@ -156,6 +167,11 @@ struct qlcnic_back_channel { | |||
156 | struct qlcnic_sriov { | 167 | struct qlcnic_sriov { |
157 | u16 vp_handle; | 168 | u16 vp_handle; |
158 | u8 num_vfs; | 169 | u8 num_vfs; |
170 | u8 any_vlan; | ||
171 | u8 vlan_mode; | ||
172 | u16 num_allowed_vlans; | ||
173 | u16 *allowed_vlans; | ||
174 | u16 vlan; | ||
159 | struct qlcnic_resources ff_max; | 175 | struct qlcnic_resources ff_max; |
160 | struct qlcnic_back_channel bc; | 176 | struct qlcnic_back_channel bc; |
161 | struct qlcnic_vf_info *vf_info; | 177 | struct qlcnic_vf_info *vf_info; |
@@ -177,6 +193,7 @@ int __qlcnic_sriov_add_act_list(struct qlcnic_sriov *, struct qlcnic_vf_info *, | |||
177 | struct qlcnic_bc_trans *); | 193 | struct qlcnic_bc_trans *); |
178 | int qlcnic_sriov_get_vf_vport_info(struct qlcnic_adapter *, | 194 | int qlcnic_sriov_get_vf_vport_info(struct qlcnic_adapter *, |
179 | struct qlcnic_info *, u16); | 195 | struct qlcnic_info *, u16); |
196 | int qlcnic_sriov_cfg_vf_guest_vlan(struct qlcnic_adapter *, u16, u8); | ||
180 | 197 | ||
181 | static inline bool qlcnic_sriov_enable_check(struct qlcnic_adapter *adapter) | 198 | static inline bool qlcnic_sriov_enable_check(struct qlcnic_adapter *adapter) |
182 | { | 199 | { |
@@ -207,6 +224,7 @@ int qlcnic_sriov_set_vf_mac(struct net_device *, int, u8 *); | |||
207 | int qlcnic_sriov_set_vf_tx_rate(struct net_device *, int, int); | 224 | int qlcnic_sriov_set_vf_tx_rate(struct net_device *, int, int); |
208 | int qlcnic_sriov_get_vf_config(struct net_device *, int , | 225 | int qlcnic_sriov_get_vf_config(struct net_device *, int , |
209 | struct ifla_vf_info *); | 226 | struct ifla_vf_info *); |
227 | int qlcnic_sriov_set_vf_vlan(struct net_device *, int, u16, u8); | ||
210 | #else | 228 | #else |
211 | static inline void qlcnic_sriov_pf_disable(struct qlcnic_adapter *adapter) {} | 229 | static inline void qlcnic_sriov_pf_disable(struct qlcnic_adapter *adapter) {} |
212 | static inline void qlcnic_sriov_pf_cleanup(struct qlcnic_adapter *adapter) {} | 230 | static inline void qlcnic_sriov_pf_cleanup(struct qlcnic_adapter *adapter) {} |
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c index b00cba96a82a..d5b626dad16b 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c | |||
@@ -28,6 +28,8 @@ | |||
28 | #define QLC_83XX_VF_RESET_FAIL_THRESH 8 | 28 | #define QLC_83XX_VF_RESET_FAIL_THRESH 8 |
29 | #define QLC_BC_CMD_MAX_RETRY_CNT 5 | 29 | #define QLC_BC_CMD_MAX_RETRY_CNT 5 |
30 | 30 | ||
31 | static void qlcnic_sriov_vf_free_mac_list(struct qlcnic_adapter *); | ||
32 | static int qlcnic_sriov_alloc_bc_mbx_args(struct qlcnic_cmd_args *, u32); | ||
31 | static void qlcnic_sriov_vf_poll_dev_state(struct work_struct *); | 33 | static void qlcnic_sriov_vf_poll_dev_state(struct work_struct *); |
32 | static void qlcnic_sriov_vf_cancel_fw_work(struct qlcnic_adapter *); | 34 | static void qlcnic_sriov_vf_cancel_fw_work(struct qlcnic_adapter *); |
33 | static void qlcnic_sriov_cleanup_transaction(struct qlcnic_bc_trans *); | 35 | static void qlcnic_sriov_cleanup_transaction(struct qlcnic_bc_trans *); |
@@ -64,6 +66,7 @@ static struct qlcnic_hardware_ops qlcnic_sriov_vf_hw_ops = { | |||
64 | .config_promisc_mode = qlcnic_83xx_nic_set_promisc, | 66 | .config_promisc_mode = qlcnic_83xx_nic_set_promisc, |
65 | .change_l2_filter = qlcnic_83xx_change_l2_filter, | 67 | .change_l2_filter = qlcnic_83xx_change_l2_filter, |
66 | .get_board_info = qlcnic_83xx_get_port_info, | 68 | .get_board_info = qlcnic_83xx_get_port_info, |
69 | .free_mac_list = qlcnic_sriov_vf_free_mac_list, | ||
67 | }; | 70 | }; |
68 | 71 | ||
69 | static struct qlcnic_nic_template qlcnic_sriov_vf_ops = { | 72 | static struct qlcnic_nic_template qlcnic_sriov_vf_ops = { |
@@ -79,6 +82,8 @@ static struct qlcnic_nic_template qlcnic_sriov_vf_ops = { | |||
79 | static const struct qlcnic_mailbox_metadata qlcnic_sriov_bc_mbx_tbl[] = { | 82 | static const struct qlcnic_mailbox_metadata qlcnic_sriov_bc_mbx_tbl[] = { |
80 | {QLCNIC_BC_CMD_CHANNEL_INIT, 2, 2}, | 83 | {QLCNIC_BC_CMD_CHANNEL_INIT, 2, 2}, |
81 | {QLCNIC_BC_CMD_CHANNEL_TERM, 2, 2}, | 84 | {QLCNIC_BC_CMD_CHANNEL_TERM, 2, 2}, |
85 | {QLCNIC_BC_CMD_GET_ACL, 3, 14}, | ||
86 | {QLCNIC_BC_CMD_CFG_GUEST_VLAN, 2, 2}, | ||
82 | }; | 87 | }; |
83 | 88 | ||
84 | static inline bool qlcnic_sriov_bc_msg_check(u32 val) | 89 | static inline bool qlcnic_sriov_bc_msg_check(u32 val) |
@@ -446,6 +451,71 @@ int qlcnic_sriov_get_vf_vport_info(struct qlcnic_adapter *adapter, | |||
446 | return err; | 451 | return err; |
447 | } | 452 | } |
448 | 453 | ||
454 | static int qlcnic_sriov_set_pvid_mode(struct qlcnic_adapter *adapter, | ||
455 | struct qlcnic_cmd_args *cmd) | ||
456 | { | ||
457 | adapter->rx_pvid = (cmd->rsp.arg[1] >> 16) & 0xffff; | ||
458 | adapter->flags &= ~QLCNIC_TAGGING_ENABLED; | ||
459 | return 0; | ||
460 | } | ||
461 | |||
462 | static int qlcnic_sriov_set_guest_vlan_mode(struct qlcnic_adapter *adapter, | ||
463 | struct qlcnic_cmd_args *cmd) | ||
464 | { | ||
465 | struct qlcnic_sriov *sriov = adapter->ahw->sriov; | ||
466 | int i, num_vlans; | ||
467 | u16 *vlans; | ||
468 | |||
469 | if (sriov->allowed_vlans) | ||
470 | return 0; | ||
471 | |||
472 | sriov->any_vlan = cmd->rsp.arg[2] & 0xf; | ||
473 | if (!sriov->any_vlan) | ||
474 | return 0; | ||
475 | |||
476 | sriov->num_allowed_vlans = cmd->rsp.arg[2] >> 16; | ||
477 | num_vlans = sriov->num_allowed_vlans; | ||
478 | sriov->allowed_vlans = kzalloc(sizeof(u16) * num_vlans, GFP_KERNEL); | ||
479 | if (!sriov->allowed_vlans) | ||
480 | return -ENOMEM; | ||
481 | |||
482 | vlans = (u16 *)&cmd->rsp.arg[3]; | ||
483 | for (i = 0; i < num_vlans; i++) | ||
484 | sriov->allowed_vlans[i] = vlans[i]; | ||
485 | |||
486 | return 0; | ||
487 | } | ||
488 | |||
489 | static int qlcnic_sriov_get_vf_acl(struct qlcnic_adapter *adapter) | ||
490 | { | ||
491 | struct qlcnic_sriov *sriov = adapter->ahw->sriov; | ||
492 | struct qlcnic_cmd_args cmd; | ||
493 | int ret; | ||
494 | |||
495 | ret = qlcnic_sriov_alloc_bc_mbx_args(&cmd, QLCNIC_BC_CMD_GET_ACL); | ||
496 | if (ret) | ||
497 | return ret; | ||
498 | |||
499 | ret = qlcnic_issue_cmd(adapter, &cmd); | ||
500 | if (ret) { | ||
501 | dev_err(&adapter->pdev->dev, "Failed to get ACL, err=%d\n", | ||
502 | ret); | ||
503 | } else { | ||
504 | sriov->vlan_mode = cmd.rsp.arg[1] & 0x3; | ||
505 | switch (sriov->vlan_mode) { | ||
506 | case QLC_GUEST_VLAN_MODE: | ||
507 | ret = qlcnic_sriov_set_guest_vlan_mode(adapter, &cmd); | ||
508 | break; | ||
509 | case QLC_PVID_MODE: | ||
510 | ret = qlcnic_sriov_set_pvid_mode(adapter, &cmd); | ||
511 | break; | ||
512 | } | ||
513 | } | ||
514 | |||
515 | qlcnic_free_mbx_args(&cmd); | ||
516 | return ret; | ||
517 | } | ||
518 | |||
449 | static int qlcnic_sriov_vf_init_driver(struct qlcnic_adapter *adapter) | 519 | static int qlcnic_sriov_vf_init_driver(struct qlcnic_adapter *adapter) |
450 | { | 520 | { |
451 | struct qlcnic_info nic_info; | 521 | struct qlcnic_info nic_info; |
@@ -460,6 +530,10 @@ static int qlcnic_sriov_vf_init_driver(struct qlcnic_adapter *adapter) | |||
460 | if (err) | 530 | if (err) |
461 | return -EIO; | 531 | return -EIO; |
462 | 532 | ||
533 | err = qlcnic_sriov_get_vf_acl(adapter); | ||
534 | if (err) | ||
535 | return err; | ||
536 | |||
463 | if (qlcnic_83xx_get_port_info(adapter)) | 537 | if (qlcnic_83xx_get_port_info(adapter)) |
464 | return -EIO; | 538 | return -EIO; |
465 | 539 | ||
@@ -1411,7 +1485,7 @@ out: | |||
1411 | return ret; | 1485 | return ret; |
1412 | } | 1486 | } |
1413 | 1487 | ||
1414 | void qlcnic_vf_add_mc_list(struct net_device *netdev) | 1488 | void qlcnic_vf_add_mc_list(struct net_device *netdev, u16 vlan) |
1415 | { | 1489 | { |
1416 | struct qlcnic_adapter *adapter = netdev_priv(netdev); | 1490 | struct qlcnic_adapter *adapter = netdev_priv(netdev); |
1417 | struct qlcnic_mac_list_s *cur; | 1491 | struct qlcnic_mac_list_s *cur; |
@@ -1431,7 +1505,7 @@ void qlcnic_vf_add_mc_list(struct net_device *netdev) | |||
1431 | while (!list_empty(&tmp_list)) { | 1505 | while (!list_empty(&tmp_list)) { |
1432 | cur = list_entry((&tmp_list)->next, | 1506 | cur = list_entry((&tmp_list)->next, |
1433 | struct qlcnic_mac_list_s, list); | 1507 | struct qlcnic_mac_list_s, list); |
1434 | qlcnic_nic_add_mac(adapter, cur->mac_addr); | 1508 | qlcnic_nic_add_mac(adapter, cur->mac_addr, vlan); |
1435 | list_del(&cur->list); | 1509 | list_del(&cur->list); |
1436 | kfree(cur); | 1510 | kfree(cur); |
1437 | } | 1511 | } |
@@ -1454,11 +1528,13 @@ void qlcnic_sriov_cleanup_async_list(struct qlcnic_back_channel *bc) | |||
1454 | static void qlcnic_sriov_vf_set_multi(struct net_device *netdev) | 1528 | static void qlcnic_sriov_vf_set_multi(struct net_device *netdev) |
1455 | { | 1529 | { |
1456 | struct qlcnic_adapter *adapter = netdev_priv(netdev); | 1530 | struct qlcnic_adapter *adapter = netdev_priv(netdev); |
1531 | u16 vlan; | ||
1457 | 1532 | ||
1458 | if (!test_bit(__QLCNIC_FW_ATTACHED, &adapter->state)) | 1533 | if (!test_bit(__QLCNIC_FW_ATTACHED, &adapter->state)) |
1459 | return; | 1534 | return; |
1460 | 1535 | ||
1461 | __qlcnic_set_multi(netdev); | 1536 | vlan = adapter->ahw->sriov->vlan; |
1537 | __qlcnic_set_multi(netdev, vlan); | ||
1462 | } | 1538 | } |
1463 | 1539 | ||
1464 | static void qlcnic_sriov_handle_async_multi(struct work_struct *work) | 1540 | static void qlcnic_sriov_handle_async_multi(struct work_struct *work) |
@@ -1787,3 +1863,92 @@ static void qlcnic_sriov_vf_cancel_fw_work(struct qlcnic_adapter *adapter) | |||
1787 | clear_bit(__QLCNIC_RESETTING, &adapter->state); | 1863 | clear_bit(__QLCNIC_RESETTING, &adapter->state); |
1788 | cancel_delayed_work_sync(&adapter->fw_work); | 1864 | cancel_delayed_work_sync(&adapter->fw_work); |
1789 | } | 1865 | } |
1866 | |||
1867 | static int qlcnic_sriov_validate_vlan_cfg(struct qlcnic_sriov *sriov, | ||
1868 | u16 vid, u8 enable) | ||
1869 | { | ||
1870 | u16 vlan = sriov->vlan; | ||
1871 | u8 allowed = 0; | ||
1872 | int i; | ||
1873 | |||
1874 | if (sriov->vlan_mode != QLC_GUEST_VLAN_MODE) | ||
1875 | return -EINVAL; | ||
1876 | |||
1877 | if (enable) { | ||
1878 | if (vlan) | ||
1879 | return -EINVAL; | ||
1880 | |||
1881 | if (sriov->any_vlan) { | ||
1882 | for (i = 0; i < sriov->num_allowed_vlans; i++) { | ||
1883 | if (sriov->allowed_vlans[i] == vid) | ||
1884 | allowed = 1; | ||
1885 | } | ||
1886 | |||
1887 | if (!allowed) | ||
1888 | return -EINVAL; | ||
1889 | } | ||
1890 | } else { | ||
1891 | if (!vlan || vlan != vid) | ||
1892 | return -EINVAL; | ||
1893 | } | ||
1894 | |||
1895 | return 0; | ||
1896 | } | ||
1897 | |||
1898 | int qlcnic_sriov_cfg_vf_guest_vlan(struct qlcnic_adapter *adapter, | ||
1899 | u16 vid, u8 enable) | ||
1900 | { | ||
1901 | struct qlcnic_sriov *sriov = adapter->ahw->sriov; | ||
1902 | struct qlcnic_cmd_args cmd; | ||
1903 | int ret; | ||
1904 | |||
1905 | if (vid == 0) | ||
1906 | return 0; | ||
1907 | |||
1908 | ret = qlcnic_sriov_validate_vlan_cfg(sriov, vid, enable); | ||
1909 | if (ret) | ||
1910 | return ret; | ||
1911 | |||
1912 | ret = qlcnic_sriov_alloc_bc_mbx_args(&cmd, | ||
1913 | QLCNIC_BC_CMD_CFG_GUEST_VLAN); | ||
1914 | if (ret) | ||
1915 | return ret; | ||
1916 | |||
1917 | cmd.req.arg[1] = (enable & 1) | vid << 16; | ||
1918 | |||
1919 | qlcnic_sriov_cleanup_async_list(&sriov->bc); | ||
1920 | ret = qlcnic_issue_cmd(adapter, &cmd); | ||
1921 | if (ret) { | ||
1922 | dev_err(&adapter->pdev->dev, | ||
1923 | "Failed to configure guest VLAN, err=%d\n", ret); | ||
1924 | } else { | ||
1925 | qlcnic_free_mac_list(adapter); | ||
1926 | |||
1927 | if (enable) | ||
1928 | sriov->vlan = vid; | ||
1929 | else | ||
1930 | sriov->vlan = 0; | ||
1931 | |||
1932 | qlcnic_sriov_vf_set_multi(adapter->netdev); | ||
1933 | } | ||
1934 | |||
1935 | qlcnic_free_mbx_args(&cmd); | ||
1936 | return ret; | ||
1937 | } | ||
1938 | |||
1939 | static void qlcnic_sriov_vf_free_mac_list(struct qlcnic_adapter *adapter) | ||
1940 | { | ||
1941 | struct list_head *head = &adapter->mac_list; | ||
1942 | struct qlcnic_mac_list_s *cur; | ||
1943 | u16 vlan; | ||
1944 | |||
1945 | vlan = adapter->ahw->sriov->vlan; | ||
1946 | |||
1947 | while (!list_empty(head)) { | ||
1948 | cur = list_entry(head->next, struct qlcnic_mac_list_s, list); | ||
1949 | qlcnic_sre_macaddr_change(adapter, cur->mac_addr, | ||
1950 | vlan, QLCNIC_MAC_DEL); | ||
1951 | list_del(&cur->list); | ||
1952 | kfree(cur); | ||
1953 | } | ||
1954 | } | ||
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c index 59d385b7ccd7..c81be2da119b 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c | |||
@@ -286,6 +286,29 @@ out: | |||
286 | return ret; | 286 | return ret; |
287 | } | 287 | } |
288 | 288 | ||
289 | static int qlcnic_sriov_pf_cfg_vlan_filtering(struct qlcnic_adapter *adapter, | ||
290 | u8 enable) | ||
291 | { | ||
292 | struct qlcnic_cmd_args cmd; | ||
293 | int err; | ||
294 | |||
295 | err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_SET_NIC_INFO); | ||
296 | if (err) | ||
297 | return err; | ||
298 | |||
299 | cmd.req.arg[1] = 0x4; | ||
300 | if (enable) | ||
301 | cmd.req.arg[1] |= BIT_16; | ||
302 | |||
303 | err = qlcnic_issue_cmd(adapter, &cmd); | ||
304 | if (err) | ||
305 | dev_err(&adapter->pdev->dev, | ||
306 | "Failed to configure VLAN filtering, err=%d\n", err); | ||
307 | |||
308 | qlcnic_free_mbx_args(&cmd); | ||
309 | return err; | ||
310 | } | ||
311 | |||
289 | static int qlcnic_sriov_pf_cfg_eswitch(struct qlcnic_adapter *adapter, | 312 | static int qlcnic_sriov_pf_cfg_eswitch(struct qlcnic_adapter *adapter, |
290 | u8 func, u8 enable) | 313 | u8 func, u8 enable) |
291 | { | 314 | { |
@@ -350,6 +373,7 @@ void qlcnic_sriov_pf_cleanup(struct qlcnic_adapter *adapter) | |||
350 | qlcnic_sriov_cfg_bc_intr(adapter, 0); | 373 | qlcnic_sriov_cfg_bc_intr(adapter, 0); |
351 | qlcnic_sriov_pf_config_vport(adapter, 0, func); | 374 | qlcnic_sriov_pf_config_vport(adapter, 0, func); |
352 | qlcnic_sriov_pf_cfg_eswitch(adapter, func, 0); | 375 | qlcnic_sriov_pf_cfg_eswitch(adapter, func, 0); |
376 | qlcnic_sriov_pf_cfg_vlan_filtering(adapter, 0); | ||
353 | __qlcnic_sriov_cleanup(adapter); | 377 | __qlcnic_sriov_cleanup(adapter); |
354 | adapter->ahw->op_mode = QLCNIC_MGMT_FUNC; | 378 | adapter->ahw->op_mode = QLCNIC_MGMT_FUNC; |
355 | clear_bit(__QLCNIC_SRIOV_ENABLE, &adapter->state); | 379 | clear_bit(__QLCNIC_SRIOV_ENABLE, &adapter->state); |
@@ -402,10 +426,14 @@ static int qlcnic_sriov_pf_init(struct qlcnic_adapter *adapter) | |||
402 | if (!qlcnic_sriov_enable_check(adapter)) | 426 | if (!qlcnic_sriov_enable_check(adapter)) |
403 | return 0; | 427 | return 0; |
404 | 428 | ||
405 | err = qlcnic_sriov_pf_cfg_eswitch(adapter, func, 1); | 429 | err = qlcnic_sriov_pf_cfg_vlan_filtering(adapter, 1); |
406 | if (err) | 430 | if (err) |
407 | return err; | 431 | return err; |
408 | 432 | ||
433 | err = qlcnic_sriov_pf_cfg_eswitch(adapter, func, 1); | ||
434 | if (err) | ||
435 | goto disable_vlan_filtering; | ||
436 | |||
409 | err = qlcnic_sriov_pf_config_vport(adapter, 1, func); | 437 | err = qlcnic_sriov_pf_config_vport(adapter, 1, func); |
410 | if (err) | 438 | if (err) |
411 | goto disable_eswitch; | 439 | goto disable_eswitch; |
@@ -439,6 +467,9 @@ delete_vport: | |||
439 | disable_eswitch: | 467 | disable_eswitch: |
440 | qlcnic_sriov_pf_cfg_eswitch(adapter, func, 0); | 468 | qlcnic_sriov_pf_cfg_eswitch(adapter, func, 0); |
441 | 469 | ||
470 | disable_vlan_filtering: | ||
471 | qlcnic_sriov_pf_cfg_vlan_filtering(adapter, 0); | ||
472 | |||
442 | return err; | 473 | return err; |
443 | } | 474 | } |
444 | 475 | ||
@@ -544,6 +575,36 @@ int qlcnic_pci_sriov_configure(struct pci_dev *dev, int num_vfs) | |||
544 | return err; | 575 | return err; |
545 | } | 576 | } |
546 | 577 | ||
578 | static int qlcnic_sriov_set_vf_acl(struct qlcnic_adapter *adapter, u8 func) | ||
579 | { | ||
580 | struct qlcnic_cmd_args cmd; | ||
581 | struct qlcnic_vport *vp; | ||
582 | int err, id; | ||
583 | |||
584 | id = qlcnic_sriov_func_to_index(adapter, func); | ||
585 | if (id < 0) | ||
586 | return id; | ||
587 | |||
588 | vp = adapter->ahw->sriov->vf_info[id].vp; | ||
589 | err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_SET_NIC_INFO); | ||
590 | if (err) | ||
591 | return err; | ||
592 | |||
593 | cmd.req.arg[1] = 0x3 | func << 16; | ||
594 | if (vp->vlan_mode == QLC_PVID_MODE) { | ||
595 | cmd.req.arg[2] |= BIT_6; | ||
596 | cmd.req.arg[3] |= vp->vlan << 8; | ||
597 | } | ||
598 | |||
599 | err = qlcnic_issue_cmd(adapter, &cmd); | ||
600 | if (err) | ||
601 | dev_err(&adapter->pdev->dev, "Failed to set ACL, err=%d\n", | ||
602 | err); | ||
603 | |||
604 | qlcnic_free_mbx_args(&cmd); | ||
605 | return err; | ||
606 | } | ||
607 | |||
547 | static int qlcnic_sriov_set_vf_vport_info(struct qlcnic_adapter *adapter, | 608 | static int qlcnic_sriov_set_vf_vport_info(struct qlcnic_adapter *adapter, |
548 | u16 func) | 609 | u16 func) |
549 | { | 610 | { |
@@ -554,6 +615,10 @@ static int qlcnic_sriov_set_vf_vport_info(struct qlcnic_adapter *adapter, | |||
554 | if (err) | 615 | if (err) |
555 | return -EIO; | 616 | return -EIO; |
556 | 617 | ||
618 | err = qlcnic_sriov_set_vf_acl(adapter, func); | ||
619 | if (err) | ||
620 | return err; | ||
621 | |||
557 | return 0; | 622 | return 0; |
558 | } | 623 | } |
559 | 624 | ||
@@ -661,6 +726,7 @@ static int qlcnic_sriov_pf_create_rx_ctx_cmd(struct qlcnic_bc_trans *tran, | |||
661 | struct qlcnic_adapter *adapter = vf->adapter; | 726 | struct qlcnic_adapter *adapter = vf->adapter; |
662 | struct qlcnic_rcv_mbx_out *mbx_out; | 727 | struct qlcnic_rcv_mbx_out *mbx_out; |
663 | int err; | 728 | int err; |
729 | u16 vlan; | ||
664 | 730 | ||
665 | err = qlcnic_sriov_validate_create_rx_ctx(cmd); | 731 | err = qlcnic_sriov_validate_create_rx_ctx(cmd); |
666 | if (err) { | 732 | if (err) { |
@@ -671,11 +737,12 @@ static int qlcnic_sriov_pf_create_rx_ctx_cmd(struct qlcnic_bc_trans *tran, | |||
671 | cmd->req.arg[6] = vf->vp->handle; | 737 | cmd->req.arg[6] = vf->vp->handle; |
672 | err = qlcnic_issue_cmd(adapter, cmd); | 738 | err = qlcnic_issue_cmd(adapter, cmd); |
673 | 739 | ||
740 | vlan = vf->vp->vlan; | ||
674 | if (!err) { | 741 | if (!err) { |
675 | mbx_out = (struct qlcnic_rcv_mbx_out *)&cmd->rsp.arg[1]; | 742 | mbx_out = (struct qlcnic_rcv_mbx_out *)&cmd->rsp.arg[1]; |
676 | vf->rx_ctx_id = mbx_out->ctx_id; | 743 | vf->rx_ctx_id = mbx_out->ctx_id; |
677 | qlcnic_sriov_cfg_vf_def_mac(adapter, vf->vp, vf->pci_func, | 744 | qlcnic_sriov_cfg_vf_def_mac(adapter, vf->vp, vf->pci_func, |
678 | 0, QLCNIC_MAC_ADD); | 745 | vlan, QLCNIC_MAC_ADD); |
679 | } else { | 746 | } else { |
680 | vf->rx_ctx_id = 0; | 747 | vf->rx_ctx_id = 0; |
681 | } | 748 | } |
@@ -759,6 +826,7 @@ static int qlcnic_sriov_pf_del_rx_ctx_cmd(struct qlcnic_bc_trans *trans, | |||
759 | struct qlcnic_vf_info *vf = trans->vf; | 826 | struct qlcnic_vf_info *vf = trans->vf; |
760 | struct qlcnic_adapter *adapter = vf->adapter; | 827 | struct qlcnic_adapter *adapter = vf->adapter; |
761 | int err; | 828 | int err; |
829 | u16 vlan; | ||
762 | 830 | ||
763 | err = qlcnic_sriov_validate_del_rx_ctx(vf, cmd); | 831 | err = qlcnic_sriov_validate_del_rx_ctx(vf, cmd); |
764 | if (err) { | 832 | if (err) { |
@@ -766,8 +834,9 @@ static int qlcnic_sriov_pf_del_rx_ctx_cmd(struct qlcnic_bc_trans *trans, | |||
766 | return err; | 834 | return err; |
767 | } | 835 | } |
768 | 836 | ||
837 | vlan = vf->vp->vlan; | ||
769 | qlcnic_sriov_cfg_vf_def_mac(adapter, vf->vp, vf->pci_func, | 838 | qlcnic_sriov_cfg_vf_def_mac(adapter, vf->vp, vf->pci_func, |
770 | 0, QLCNIC_MAC_DEL); | 839 | vlan, QLCNIC_MAC_DEL); |
771 | cmd->req.arg[1] |= vf->vp->handle << 16; | 840 | cmd->req.arg[1] |= vf->vp->handle << 16; |
772 | err = qlcnic_issue_cmd(adapter, cmd); | 841 | err = qlcnic_issue_cmd(adapter, cmd); |
773 | 842 | ||
@@ -1012,6 +1081,8 @@ static int qlcnic_sriov_validate_cfg_macvlan(struct qlcnic_adapter *adapter, | |||
1012 | struct qlcnic_cmd_args *cmd) | 1081 | struct qlcnic_cmd_args *cmd) |
1013 | { | 1082 | { |
1014 | struct qlcnic_macvlan_mbx *macvlan; | 1083 | struct qlcnic_macvlan_mbx *macvlan; |
1084 | struct qlcnic_vport *vp = vf->vp; | ||
1085 | u8 op, new_op; | ||
1015 | 1086 | ||
1016 | if (!(cmd->req.arg[1] & BIT_8)) | 1087 | if (!(cmd->req.arg[1] & BIT_8)) |
1017 | return -EINVAL; | 1088 | return -EINVAL; |
@@ -1027,6 +1098,15 @@ static int qlcnic_sriov_validate_cfg_macvlan(struct qlcnic_adapter *adapter, | |||
1027 | return -EINVAL; | 1098 | return -EINVAL; |
1028 | } | 1099 | } |
1029 | 1100 | ||
1101 | if (vp->vlan_mode == QLC_PVID_MODE) { | ||
1102 | op = cmd->req.arg[1] & 0x7; | ||
1103 | cmd->req.arg[1] &= ~0x7; | ||
1104 | new_op = (op == QLCNIC_MAC_ADD || op == QLCNIC_MAC_VLAN_ADD) ? | ||
1105 | QLCNIC_MAC_VLAN_ADD : QLCNIC_MAC_VLAN_DEL; | ||
1106 | cmd->req.arg[3] |= vp->vlan << 16; | ||
1107 | cmd->req.arg[1] |= new_op; | ||
1108 | } | ||
1109 | |||
1030 | return 0; | 1110 | return 0; |
1031 | } | 1111 | } |
1032 | 1112 | ||
@@ -1089,6 +1169,109 @@ static int qlcnic_sriov_pf_cfg_promisc_cmd(struct qlcnic_bc_trans *trans, | |||
1089 | return err; | 1169 | return err; |
1090 | } | 1170 | } |
1091 | 1171 | ||
1172 | static int qlcnic_sriov_pf_get_acl_cmd(struct qlcnic_bc_trans *trans, | ||
1173 | struct qlcnic_cmd_args *cmd) | ||
1174 | { | ||
1175 | struct qlcnic_vf_info *vf = trans->vf; | ||
1176 | struct qlcnic_vport *vp = vf->vp; | ||
1177 | u8 cmd_op, mode = vp->vlan_mode; | ||
1178 | |||
1179 | cmd_op = trans->req_hdr->cmd_op; | ||
1180 | cmd->rsp.arg[0] = (cmd_op & 0xffff) | 14 << 16 | 1 << 25; | ||
1181 | |||
1182 | switch (mode) { | ||
1183 | case QLC_GUEST_VLAN_MODE: | ||
1184 | cmd->rsp.arg[1] = mode | 1 << 8; | ||
1185 | cmd->rsp.arg[2] = 1 << 16; | ||
1186 | break; | ||
1187 | case QLC_PVID_MODE: | ||
1188 | cmd->rsp.arg[1] = mode | 1 << 8 | vp->vlan << 16; | ||
1189 | break; | ||
1190 | } | ||
1191 | |||
1192 | return 0; | ||
1193 | } | ||
1194 | |||
1195 | static int qlcnic_sriov_pf_del_guest_vlan(struct qlcnic_adapter *adapter, | ||
1196 | struct qlcnic_vf_info *vf) | ||
1197 | |||
1198 | { | ||
1199 | struct qlcnic_vport *vp = vf->vp; | ||
1200 | |||
1201 | if (!vp->vlan) | ||
1202 | return -EINVAL; | ||
1203 | |||
1204 | if (!vf->rx_ctx_id) { | ||
1205 | vp->vlan = 0; | ||
1206 | return 0; | ||
1207 | } | ||
1208 | |||
1209 | qlcnic_sriov_cfg_vf_def_mac(adapter, vp, vf->pci_func, | ||
1210 | vp->vlan, QLCNIC_MAC_DEL); | ||
1211 | vp->vlan = 0; | ||
1212 | qlcnic_sriov_cfg_vf_def_mac(adapter, vp, vf->pci_func, | ||
1213 | 0, QLCNIC_MAC_ADD); | ||
1214 | return 0; | ||
1215 | } | ||
1216 | |||
1217 | static int qlcnic_sriov_pf_add_guest_vlan(struct qlcnic_adapter *adapter, | ||
1218 | struct qlcnic_vf_info *vf, | ||
1219 | struct qlcnic_cmd_args *cmd) | ||
1220 | { | ||
1221 | struct qlcnic_vport *vp = vf->vp; | ||
1222 | int err = -EIO; | ||
1223 | |||
1224 | if (vp->vlan) | ||
1225 | return err; | ||
1226 | |||
1227 | if (!vf->rx_ctx_id) { | ||
1228 | vp->vlan = cmd->req.arg[1] >> 16; | ||
1229 | return 0; | ||
1230 | } | ||
1231 | |||
1232 | err = qlcnic_sriov_cfg_vf_def_mac(adapter, vp, vf->pci_func, | ||
1233 | 0, QLCNIC_MAC_DEL); | ||
1234 | if (err) | ||
1235 | return err; | ||
1236 | |||
1237 | vp->vlan = cmd->req.arg[1] >> 16; | ||
1238 | err = qlcnic_sriov_cfg_vf_def_mac(adapter, vp, vf->pci_func, | ||
1239 | vp->vlan, QLCNIC_MAC_ADD); | ||
1240 | |||
1241 | if (err) { | ||
1242 | qlcnic_sriov_cfg_vf_def_mac(adapter, vp, vf->pci_func, | ||
1243 | 0, QLCNIC_MAC_ADD); | ||
1244 | vp->vlan = 0; | ||
1245 | } | ||
1246 | |||
1247 | return err; | ||
1248 | } | ||
1249 | |||
1250 | static int qlcnic_sriov_pf_cfg_guest_vlan_cmd(struct qlcnic_bc_trans *tran, | ||
1251 | struct qlcnic_cmd_args *cmd) | ||
1252 | { | ||
1253 | struct qlcnic_vf_info *vf = tran->vf; | ||
1254 | struct qlcnic_adapter *adapter = vf->adapter; | ||
1255 | struct qlcnic_vport *vp = vf->vp; | ||
1256 | int err = -EIO; | ||
1257 | u8 op; | ||
1258 | |||
1259 | if (vp->vlan_mode != QLC_GUEST_VLAN_MODE) { | ||
1260 | cmd->rsp.arg[0] |= 2 << 25; | ||
1261 | return err; | ||
1262 | } | ||
1263 | |||
1264 | op = cmd->req.arg[1] & 0xf; | ||
1265 | |||
1266 | if (op) | ||
1267 | err = qlcnic_sriov_pf_add_guest_vlan(adapter, vf, cmd); | ||
1268 | else | ||
1269 | err = qlcnic_sriov_pf_del_guest_vlan(adapter, vf); | ||
1270 | |||
1271 | cmd->rsp.arg[0] |= err ? 2 << 25 : 1 << 25; | ||
1272 | return err; | ||
1273 | } | ||
1274 | |||
1092 | static const int qlcnic_pf_passthru_supp_cmds[] = { | 1275 | static const int qlcnic_pf_passthru_supp_cmds[] = { |
1093 | QLCNIC_CMD_GET_STATISTICS, | 1276 | QLCNIC_CMD_GET_STATISTICS, |
1094 | QLCNIC_CMD_GET_PORT_CONFIG, | 1277 | QLCNIC_CMD_GET_PORT_CONFIG, |
@@ -1098,6 +1281,8 @@ static const int qlcnic_pf_passthru_supp_cmds[] = { | |||
1098 | static const struct qlcnic_sriov_cmd_handler qlcnic_pf_bc_cmd_hdlr[] = { | 1281 | static const struct qlcnic_sriov_cmd_handler qlcnic_pf_bc_cmd_hdlr[] = { |
1099 | [QLCNIC_BC_CMD_CHANNEL_INIT] = {&qlcnic_sriov_pf_channel_cfg_cmd}, | 1282 | [QLCNIC_BC_CMD_CHANNEL_INIT] = {&qlcnic_sriov_pf_channel_cfg_cmd}, |
1100 | [QLCNIC_BC_CMD_CHANNEL_TERM] = {&qlcnic_sriov_pf_channel_cfg_cmd}, | 1283 | [QLCNIC_BC_CMD_CHANNEL_TERM] = {&qlcnic_sriov_pf_channel_cfg_cmd}, |
1284 | [QLCNIC_BC_CMD_GET_ACL] = {&qlcnic_sriov_pf_get_acl_cmd}, | ||
1285 | [QLCNIC_BC_CMD_CFG_GUEST_VLAN] = {&qlcnic_sriov_pf_cfg_guest_vlan_cmd}, | ||
1101 | }; | 1286 | }; |
1102 | 1287 | ||
1103 | static const struct qlcnic_sriov_fw_cmd_handler qlcnic_pf_fw_cmd_hdlr[] = { | 1288 | static const struct qlcnic_sriov_fw_cmd_handler qlcnic_pf_fw_cmd_hdlr[] = { |
@@ -1518,6 +1703,56 @@ int qlcnic_sriov_set_vf_tx_rate(struct net_device *netdev, int vf, int tx_rate) | |||
1518 | return 0; | 1703 | return 0; |
1519 | } | 1704 | } |
1520 | 1705 | ||
1706 | int qlcnic_sriov_set_vf_vlan(struct net_device *netdev, int vf, | ||
1707 | u16 vlan, u8 qos) | ||
1708 | { | ||
1709 | struct qlcnic_adapter *adapter = netdev_priv(netdev); | ||
1710 | struct qlcnic_sriov *sriov = adapter->ahw->sriov; | ||
1711 | struct qlcnic_vf_info *vf_info; | ||
1712 | struct qlcnic_vport *vp; | ||
1713 | |||
1714 | if (!qlcnic_sriov_pf_check(adapter)) | ||
1715 | return -EOPNOTSUPP; | ||
1716 | |||
1717 | if (vf >= sriov->num_vfs || qos > 7) | ||
1718 | return -EINVAL; | ||
1719 | |||
1720 | if (vlan > MAX_VLAN_ID) { | ||
1721 | netdev_err(netdev, | ||
1722 | "Invalid VLAN ID, allowed range is [0 - %d]\n", | ||
1723 | MAX_VLAN_ID); | ||
1724 | return -EINVAL; | ||
1725 | } | ||
1726 | |||
1727 | vf_info = &sriov->vf_info[vf]; | ||
1728 | vp = vf_info->vp; | ||
1729 | if (test_bit(QLC_BC_VF_STATE, &vf_info->state)) { | ||
1730 | netdev_err(netdev, | ||
1731 | "VLAN change failed for VF %d, as VF driver is loaded. Please unload VF driver and retry the operation\n", | ||
1732 | vf); | ||
1733 | return -EOPNOTSUPP; | ||
1734 | } | ||
1735 | |||
1736 | switch (vlan) { | ||
1737 | case 4095: | ||
1738 | vp->vlan_mode = QLC_GUEST_VLAN_MODE; | ||
1739 | break; | ||
1740 | case 0: | ||
1741 | vp->vlan_mode = QLC_NO_VLAN_MODE; | ||
1742 | vp->vlan = 0; | ||
1743 | vp->qos = 0; | ||
1744 | break; | ||
1745 | default: | ||
1746 | vp->vlan_mode = QLC_PVID_MODE; | ||
1747 | vp->vlan = vlan; | ||
1748 | vp->qos = qos; | ||
1749 | } | ||
1750 | |||
1751 | netdev_info(netdev, "Setting VLAN %d, QoS %d, for VF %d\n", | ||
1752 | vlan, qos, vf); | ||
1753 | return 0; | ||
1754 | } | ||
1755 | |||
1521 | int qlcnic_sriov_get_vf_config(struct net_device *netdev, | 1756 | int qlcnic_sriov_get_vf_config(struct net_device *netdev, |
1522 | int vf, struct ifla_vf_info *ivi) | 1757 | int vf, struct ifla_vf_info *ivi) |
1523 | { | 1758 | { |
@@ -1533,6 +1768,8 @@ int qlcnic_sriov_get_vf_config(struct net_device *netdev, | |||
1533 | 1768 | ||
1534 | vp = sriov->vf_info[vf].vp; | 1769 | vp = sriov->vf_info[vf].vp; |
1535 | memcpy(&ivi->mac, vp->mac, ETH_ALEN); | 1770 | memcpy(&ivi->mac, vp->mac, ETH_ALEN); |
1771 | ivi->vlan = vp->vlan; | ||
1772 | ivi->qos = vp->qos; | ||
1536 | if (vp->max_tx_bw == MAX_BW) | 1773 | if (vp->max_tx_bw == MAX_BW) |
1537 | ivi->tx_rate = 0; | 1774 | ivi->tx_rate = 0; |
1538 | else | 1775 | else |