diff options
Diffstat (limited to 'drivers/net/ethernet/intel/fm10k')
-rw-r--r-- | drivers/net/ethernet/intel/fm10k/Makefile | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/fm10k/fm10k.h | 4 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/fm10k/fm10k_ethtool.c | 114 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/fm10k/fm10k_mbx.c | 4 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/fm10k/fm10k_netdev.c | 15 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/fm10k/fm10k_pci.c | 102 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/fm10k/fm10k_type.h | 9 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/fm10k/fm10k_vf.c | 523 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/fm10k/fm10k_vf.h | 68 |
9 files changed, 837 insertions, 4 deletions
diff --git a/drivers/net/ethernet/intel/fm10k/Makefile b/drivers/net/ethernet/intel/fm10k/Makefile index b72815e45604..f70893a880c5 100644 --- a/drivers/net/ethernet/intel/fm10k/Makefile +++ b/drivers/net/ethernet/intel/fm10k/Makefile | |||
@@ -28,5 +28,5 @@ | |||
28 | obj-$(CONFIG_FM10K) += fm10k.o | 28 | obj-$(CONFIG_FM10K) += fm10k.o |
29 | 29 | ||
30 | fm10k-objs := fm10k_main.o fm10k_common.o fm10k_pci.o \ | 30 | fm10k-objs := fm10k_main.o fm10k_common.o fm10k_pci.o \ |
31 | fm10k_netdev.o fm10k_ethtool.o fm10k_pf.o \ | 31 | fm10k_netdev.o fm10k_ethtool.o fm10k_pf.o fm10k_vf.o \ |
32 | fm10k_mbx.o fm10k_tlv.o | 32 | fm10k_mbx.o fm10k_tlv.o |
diff --git a/drivers/net/ethernet/intel/fm10k/fm10k.h b/drivers/net/ethernet/intel/fm10k/fm10k.h index 58c1475ade7c..639698c7c108 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k.h +++ b/drivers/net/ethernet/intel/fm10k/fm10k.h | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/pci.h> | 28 | #include <linux/pci.h> |
29 | 29 | ||
30 | #include "fm10k_pf.h" | 30 | #include "fm10k_pf.h" |
31 | #include "fm10k_vf.h" | ||
31 | 32 | ||
32 | #define FM10K_MAX_JUMBO_FRAME_SIZE 15358 /* Maximum supported size 15K */ | 33 | #define FM10K_MAX_JUMBO_FRAME_SIZE 15358 /* Maximum supported size 15K */ |
33 | 34 | ||
@@ -180,12 +181,13 @@ static inline struct netdev_queue *txring_txq(const struct fm10k_ring *ring) | |||
180 | #define MIN_Q_VECTORS 1 | 181 | #define MIN_Q_VECTORS 1 |
181 | enum fm10k_non_q_vectors { | 182 | enum fm10k_non_q_vectors { |
182 | FM10K_MBX_VECTOR, | 183 | FM10K_MBX_VECTOR, |
184 | #define NON_Q_VECTORS_VF NON_Q_VECTORS_PF | ||
183 | NON_Q_VECTORS_PF | 185 | NON_Q_VECTORS_PF |
184 | }; | 186 | }; |
185 | 187 | ||
186 | #define NON_Q_VECTORS(hw) (((hw)->mac.type == fm10k_mac_pf) ? \ | 188 | #define NON_Q_VECTORS(hw) (((hw)->mac.type == fm10k_mac_pf) ? \ |
187 | NON_Q_VECTORS_PF : \ | 189 | NON_Q_VECTORS_PF : \ |
188 | 0) | 190 | NON_Q_VECTORS_VF) |
189 | #define MIN_MSIX_COUNT(hw) (MIN_Q_VECTORS + NON_Q_VECTORS(hw)) | 191 | #define MIN_MSIX_COUNT(hw) (MIN_Q_VECTORS + NON_Q_VECTORS(hw)) |
190 | 192 | ||
191 | struct fm10k_q_vector { | 193 | struct fm10k_q_vector { |
diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_ethtool.c b/drivers/net/ethernet/intel/fm10k/fm10k_ethtool.c index 54e8ebd9fbe4..42beb89ae15d 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_ethtool.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_ethtool.c | |||
@@ -102,6 +102,17 @@ static const struct fm10k_stats fm10k_gstrings_stats[] = { | |||
102 | FM10K_NETDEV_STATS_LEN + \ | 102 | FM10K_NETDEV_STATS_LEN + \ |
103 | FM10K_QUEUE_STATS_LEN) | 103 | FM10K_QUEUE_STATS_LEN) |
104 | 104 | ||
105 | static const char fm10k_gstrings_test[][ETH_GSTRING_LEN] = { | ||
106 | "Mailbox test (on/offline)" | ||
107 | }; | ||
108 | |||
109 | #define FM10K_TEST_LEN (sizeof(fm10k_gstrings_test) / ETH_GSTRING_LEN) | ||
110 | |||
111 | enum fm10k_self_test_types { | ||
112 | FM10K_TEST_MBX, | ||
113 | FM10K_TEST_MAX = FM10K_TEST_LEN | ||
114 | }; | ||
115 | |||
105 | static void fm10k_get_strings(struct net_device *dev, u32 stringset, | 116 | static void fm10k_get_strings(struct net_device *dev, u32 stringset, |
106 | u8 *data) | 117 | u8 *data) |
107 | { | 118 | { |
@@ -109,6 +120,10 @@ static void fm10k_get_strings(struct net_device *dev, u32 stringset, | |||
109 | int i; | 120 | int i; |
110 | 121 | ||
111 | switch (stringset) { | 122 | switch (stringset) { |
123 | case ETH_SS_TEST: | ||
124 | memcpy(data, *fm10k_gstrings_test, | ||
125 | FM10K_TEST_LEN * ETH_GSTRING_LEN); | ||
126 | break; | ||
112 | case ETH_SS_STATS: | 127 | case ETH_SS_STATS: |
113 | for (i = 0; i < FM10K_NETDEV_STATS_LEN; i++) { | 128 | for (i = 0; i < FM10K_NETDEV_STATS_LEN; i++) { |
114 | memcpy(p, fm10k_gstrings_net_stats[i].stat_string, | 129 | memcpy(p, fm10k_gstrings_net_stats[i].stat_string, |
@@ -138,6 +153,8 @@ static void fm10k_get_strings(struct net_device *dev, u32 stringset, | |||
138 | static int fm10k_get_sset_count(struct net_device *dev, int sset) | 153 | static int fm10k_get_sset_count(struct net_device *dev, int sset) |
139 | { | 154 | { |
140 | switch (sset) { | 155 | switch (sset) { |
156 | case ETH_SS_TEST: | ||
157 | return FM10K_TEST_LEN; | ||
141 | case ETH_SS_STATS: | 158 | case ETH_SS_STATS: |
142 | return FM10K_STATS_LEN; | 159 | return FM10K_STATS_LEN; |
143 | default: | 160 | default: |
@@ -288,6 +305,28 @@ static void fm10k_get_regs(struct net_device *netdev, | |||
288 | *(buff++) = fm10k_read_reg(hw, FM10K_ITR(i)); | 305 | *(buff++) = fm10k_read_reg(hw, FM10K_ITR(i)); |
289 | 306 | ||
290 | break; | 307 | break; |
308 | case fm10k_mac_vf: | ||
309 | /* General VF registers */ | ||
310 | *(buff++) = fm10k_read_reg(hw, FM10K_VFCTRL); | ||
311 | *(buff++) = fm10k_read_reg(hw, FM10K_VFINT_MAP); | ||
312 | *(buff++) = fm10k_read_reg(hw, FM10K_VFSYSTIME); | ||
313 | |||
314 | /* Interrupt Throttling Registers */ | ||
315 | for (i = 0; i < 8; i++) | ||
316 | *(buff++) = fm10k_read_reg(hw, FM10K_VFITR(i)); | ||
317 | |||
318 | fm10k_get_reg_vsi(hw, buff, 0); | ||
319 | buff += FM10K_REGS_LEN_VSI; | ||
320 | |||
321 | for (i = 0; i < FM10K_MAX_QUEUES_POOL; i++) { | ||
322 | if (i < hw->mac.max_queues) | ||
323 | fm10k_get_reg_q(hw, buff, i); | ||
324 | else | ||
325 | memset(buff, 0, sizeof(u32) * FM10K_REGS_LEN_Q); | ||
326 | buff += FM10K_REGS_LEN_Q; | ||
327 | } | ||
328 | |||
329 | break; | ||
291 | default: | 330 | default: |
292 | return; | 331 | return; |
293 | } | 332 | } |
@@ -296,6 +335,8 @@ static void fm10k_get_regs(struct net_device *netdev, | |||
296 | /* If function above adds more registers these define need to be updated */ | 335 | /* If function above adds more registers these define need to be updated */ |
297 | #define FM10K_REGS_LEN_PF \ | 336 | #define FM10K_REGS_LEN_PF \ |
298 | (162 + (65 * FM10K_REGS_LEN_VSI) + (FM10K_MAX_QUEUES_PF * FM10K_REGS_LEN_Q)) | 337 | (162 + (65 * FM10K_REGS_LEN_VSI) + (FM10K_MAX_QUEUES_PF * FM10K_REGS_LEN_Q)) |
338 | #define FM10K_REGS_LEN_VF \ | ||
339 | (11 + FM10K_REGS_LEN_VSI + (FM10K_MAX_QUEUES_POOL * FM10K_REGS_LEN_Q)) | ||
299 | 340 | ||
300 | static int fm10k_get_regs_len(struct net_device *netdev) | 341 | static int fm10k_get_regs_len(struct net_device *netdev) |
301 | { | 342 | { |
@@ -305,6 +346,8 @@ static int fm10k_get_regs_len(struct net_device *netdev) | |||
305 | switch (hw->mac.type) { | 346 | switch (hw->mac.type) { |
306 | case fm10k_mac_pf: | 347 | case fm10k_mac_pf: |
307 | return FM10K_REGS_LEN_PF * sizeof(u32); | 348 | return FM10K_REGS_LEN_PF * sizeof(u32); |
349 | case fm10k_mac_vf: | ||
350 | return FM10K_REGS_LEN_VF * sizeof(u32); | ||
308 | default: | 351 | default: |
309 | return 0; | 352 | return 0; |
310 | } | 353 | } |
@@ -734,6 +777,76 @@ static int fm10k_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd) | |||
734 | return ret; | 777 | return ret; |
735 | } | 778 | } |
736 | 779 | ||
780 | static int fm10k_mbx_test(struct fm10k_intfc *interface, u64 *data) | ||
781 | { | ||
782 | struct fm10k_hw *hw = &interface->hw; | ||
783 | struct fm10k_mbx_info *mbx = &hw->mbx; | ||
784 | u32 attr_flag, test_msg[6]; | ||
785 | unsigned long timeout; | ||
786 | int err; | ||
787 | |||
788 | /* For now this is a VF only feature */ | ||
789 | if (hw->mac.type != fm10k_mac_vf) | ||
790 | return 0; | ||
791 | |||
792 | /* loop through both nested and unnested attribute types */ | ||
793 | for (attr_flag = (1 << FM10K_TEST_MSG_UNSET); | ||
794 | attr_flag < (1 << (2 * FM10K_TEST_MSG_NESTED)); | ||
795 | attr_flag += attr_flag) { | ||
796 | /* generate message to be tested */ | ||
797 | fm10k_tlv_msg_test_create(test_msg, attr_flag); | ||
798 | |||
799 | fm10k_mbx_lock(interface); | ||
800 | mbx->test_result = FM10K_NOT_IMPLEMENTED; | ||
801 | err = mbx->ops.enqueue_tx(hw, mbx, test_msg); | ||
802 | fm10k_mbx_unlock(interface); | ||
803 | |||
804 | /* wait up to 1 second for response */ | ||
805 | timeout = jiffies + HZ; | ||
806 | do { | ||
807 | if (err < 0) | ||
808 | goto err_out; | ||
809 | |||
810 | usleep_range(500, 1000); | ||
811 | |||
812 | fm10k_mbx_lock(interface); | ||
813 | mbx->ops.process(hw, mbx); | ||
814 | fm10k_mbx_unlock(interface); | ||
815 | |||
816 | err = mbx->test_result; | ||
817 | if (!err) | ||
818 | break; | ||
819 | } while (time_is_after_jiffies(timeout)); | ||
820 | |||
821 | /* reporting errors */ | ||
822 | if (err) | ||
823 | goto err_out; | ||
824 | } | ||
825 | |||
826 | err_out: | ||
827 | *data = err < 0 ? (attr_flag) : (err > 0); | ||
828 | return err; | ||
829 | } | ||
830 | |||
831 | static void fm10k_self_test(struct net_device *dev, | ||
832 | struct ethtool_test *eth_test, u64 *data) | ||
833 | { | ||
834 | struct fm10k_intfc *interface = netdev_priv(dev); | ||
835 | struct fm10k_hw *hw = &interface->hw; | ||
836 | |||
837 | memset(data, 0, sizeof(*data) * FM10K_TEST_LEN); | ||
838 | |||
839 | if (FM10K_REMOVED(hw)) { | ||
840 | netif_err(interface, drv, dev, | ||
841 | "Interface removed - test blocked\n"); | ||
842 | eth_test->flags |= ETH_TEST_FL_FAILED; | ||
843 | return; | ||
844 | } | ||
845 | |||
846 | if (fm10k_mbx_test(interface, &data[FM10K_TEST_MBX])) | ||
847 | eth_test->flags |= ETH_TEST_FL_FAILED; | ||
848 | } | ||
849 | |||
737 | static u32 fm10k_get_reta_size(struct net_device *netdev) | 850 | static u32 fm10k_get_reta_size(struct net_device *netdev) |
738 | { | 851 | { |
739 | return FM10K_RETA_SIZE * FM10K_RETA_ENTRIES_PER_REG; | 852 | return FM10K_RETA_SIZE * FM10K_RETA_ENTRIES_PER_REG; |
@@ -911,6 +1024,7 @@ static const struct ethtool_ops fm10k_ethtool_ops = { | |||
911 | .set_rxnfc = fm10k_set_rxnfc, | 1024 | .set_rxnfc = fm10k_set_rxnfc, |
912 | .get_regs = fm10k_get_regs, | 1025 | .get_regs = fm10k_get_regs, |
913 | .get_regs_len = fm10k_get_regs_len, | 1026 | .get_regs_len = fm10k_get_regs_len, |
1027 | .self_test = fm10k_self_test, | ||
914 | .get_rxfh_indir_size = fm10k_get_reta_size, | 1028 | .get_rxfh_indir_size = fm10k_get_reta_size, |
915 | .get_rxfh_key_size = fm10k_get_rssrk_size, | 1029 | .get_rxfh_key_size = fm10k_get_rssrk_size, |
916 | .get_rxfh = fm10k_get_rssh, | 1030 | .get_rxfh = fm10k_get_rssh, |
diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_mbx.c b/drivers/net/ethernet/intel/fm10k/fm10k_mbx.c index a6a66fd9e2c2..14a4ea795c01 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_mbx.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_mbx.c | |||
@@ -1517,6 +1517,10 @@ s32 fm10k_pfvf_mbx_init(struct fm10k_hw *hw, struct fm10k_mbx_info *mbx, | |||
1517 | { | 1517 | { |
1518 | /* initialize registers */ | 1518 | /* initialize registers */ |
1519 | switch (hw->mac.type) { | 1519 | switch (hw->mac.type) { |
1520 | case fm10k_mac_vf: | ||
1521 | mbx->mbx_reg = FM10K_VFMBX; | ||
1522 | mbx->mbmem_reg = FM10K_VFMBMEM(FM10K_VFMBMEM_VF_XOR); | ||
1523 | break; | ||
1520 | case fm10k_mac_pf: | 1524 | case fm10k_mac_pf: |
1521 | /* there are only 64 VF <-> PF mailboxes */ | 1525 | /* there are only 64 VF <-> PF mailboxes */ |
1522 | if (id < 64) { | 1526 | if (id < 64) { |
diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c b/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c index 268966bfe019..c0d6758ea16e 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c | |||
@@ -976,6 +976,21 @@ void fm10k_restore_rx_state(struct fm10k_intfc *interface) | |||
976 | int xcast_mode; | 976 | int xcast_mode; |
977 | u16 vid, glort; | 977 | u16 vid, glort; |
978 | 978 | ||
979 | /* restore our address if perm_addr is set */ | ||
980 | if (hw->mac.type == fm10k_mac_vf) { | ||
981 | if (is_valid_ether_addr(hw->mac.perm_addr)) { | ||
982 | ether_addr_copy(hw->mac.addr, hw->mac.perm_addr); | ||
983 | ether_addr_copy(netdev->perm_addr, hw->mac.perm_addr); | ||
984 | ether_addr_copy(netdev->dev_addr, hw->mac.perm_addr); | ||
985 | netdev->addr_assign_type &= ~NET_ADDR_RANDOM; | ||
986 | } | ||
987 | |||
988 | if (hw->mac.vlan_override) | ||
989 | netdev->features &= ~NETIF_F_HW_VLAN_CTAG_RX; | ||
990 | else | ||
991 | netdev->features |= NETIF_F_HW_VLAN_CTAG_RX; | ||
992 | } | ||
993 | |||
979 | /* record glort for this interface */ | 994 | /* record glort for this interface */ |
980 | glort = interface->glort; | 995 | glort = interface->glort; |
981 | 996 | ||
diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_pci.c b/drivers/net/ethernet/intel/fm10k/fm10k_pci.c index d647814550f1..9cc4d627eb75 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_pci.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_pci.c | |||
@@ -25,6 +25,7 @@ | |||
25 | 25 | ||
26 | static const struct fm10k_info *fm10k_info_tbl[] = { | 26 | static const struct fm10k_info *fm10k_info_tbl[] = { |
27 | [fm10k_device_pf] = &fm10k_pf_info, | 27 | [fm10k_device_pf] = &fm10k_pf_info, |
28 | [fm10k_device_vf] = &fm10k_vf_info, | ||
28 | }; | 29 | }; |
29 | 30 | ||
30 | /** | 31 | /** |
@@ -38,6 +39,7 @@ static const struct fm10k_info *fm10k_info_tbl[] = { | |||
38 | */ | 39 | */ |
39 | static const struct pci_device_id fm10k_pci_tbl[] = { | 40 | static const struct pci_device_id fm10k_pci_tbl[] = { |
40 | { PCI_VDEVICE(INTEL, FM10K_DEV_ID_PF), fm10k_device_pf }, | 41 | { PCI_VDEVICE(INTEL, FM10K_DEV_ID_PF), fm10k_device_pf }, |
42 | { PCI_VDEVICE(INTEL, FM10K_DEV_ID_VF), fm10k_device_vf }, | ||
41 | /* required last entry */ | 43 | /* required last entry */ |
42 | { 0, } | 44 | { 0, } |
43 | }; | 45 | }; |
@@ -805,6 +807,28 @@ static irqreturn_t fm10k_msix_clean_rings(int irq, void *data) | |||
805 | return IRQ_HANDLED; | 807 | return IRQ_HANDLED; |
806 | } | 808 | } |
807 | 809 | ||
810 | static irqreturn_t fm10k_msix_mbx_vf(int irq, void *data) | ||
811 | { | ||
812 | struct fm10k_intfc *interface = data; | ||
813 | struct fm10k_hw *hw = &interface->hw; | ||
814 | struct fm10k_mbx_info *mbx = &hw->mbx; | ||
815 | |||
816 | /* re-enable mailbox interrupt and indicate 20us delay */ | ||
817 | fm10k_write_reg(hw, FM10K_VFITR(FM10K_MBX_VECTOR), | ||
818 | FM10K_ITR_ENABLE | FM10K_MBX_INT_DELAY); | ||
819 | |||
820 | /* service upstream mailbox */ | ||
821 | if (fm10k_mbx_trylock(interface)) { | ||
822 | mbx->ops.process(hw, mbx); | ||
823 | fm10k_mbx_unlock(interface); | ||
824 | } | ||
825 | |||
826 | hw->mac.get_host_state = 1; | ||
827 | fm10k_service_event_schedule(interface); | ||
828 | |||
829 | return IRQ_HANDLED; | ||
830 | } | ||
831 | |||
808 | #define FM10K_ERR_MSG(type) case (type): error = #type; break | 832 | #define FM10K_ERR_MSG(type) case (type): error = #type; break |
809 | static void fm10k_print_fault(struct fm10k_intfc *interface, int type, | 833 | static void fm10k_print_fault(struct fm10k_intfc *interface, int type, |
810 | struct fm10k_fault *fault) | 834 | struct fm10k_fault *fault) |
@@ -996,6 +1020,8 @@ void fm10k_mbx_free_irq(struct fm10k_intfc *interface) | |||
996 | FM10K_EIMR_DISABLE(VFLR) | | 1020 | FM10K_EIMR_DISABLE(VFLR) | |
997 | FM10K_EIMR_DISABLE(MAXHOLDTIME)); | 1021 | FM10K_EIMR_DISABLE(MAXHOLDTIME)); |
998 | itr_reg = FM10K_ITR(FM10K_MBX_VECTOR); | 1022 | itr_reg = FM10K_ITR(FM10K_MBX_VECTOR); |
1023 | } else { | ||
1024 | itr_reg = FM10K_VFITR(FM10K_MBX_VECTOR); | ||
999 | } | 1025 | } |
1000 | 1026 | ||
1001 | fm10k_write_reg(hw, itr_reg, FM10K_ITR_MASK_SET); | 1027 | fm10k_write_reg(hw, itr_reg, FM10K_ITR_MASK_SET); |
@@ -1003,6 +1029,33 @@ void fm10k_mbx_free_irq(struct fm10k_intfc *interface) | |||
1003 | free_irq(entry->vector, interface); | 1029 | free_irq(entry->vector, interface); |
1004 | } | 1030 | } |
1005 | 1031 | ||
1032 | static s32 fm10k_mbx_mac_addr(struct fm10k_hw *hw, u32 **results, | ||
1033 | struct fm10k_mbx_info *mbx) | ||
1034 | { | ||
1035 | bool vlan_override = hw->mac.vlan_override; | ||
1036 | u16 default_vid = hw->mac.default_vid; | ||
1037 | struct fm10k_intfc *interface; | ||
1038 | s32 err; | ||
1039 | |||
1040 | err = fm10k_msg_mac_vlan_vf(hw, results, mbx); | ||
1041 | if (err) | ||
1042 | return err; | ||
1043 | |||
1044 | interface = container_of(hw, struct fm10k_intfc, hw); | ||
1045 | |||
1046 | /* MAC was changed so we need reset */ | ||
1047 | if (is_valid_ether_addr(hw->mac.perm_addr) && | ||
1048 | memcmp(hw->mac.perm_addr, hw->mac.addr, ETH_ALEN)) | ||
1049 | interface->flags |= FM10K_FLAG_RESET_REQUESTED; | ||
1050 | |||
1051 | /* VLAN override was changed, or default VLAN changed */ | ||
1052 | if ((vlan_override != hw->mac.vlan_override) || | ||
1053 | (default_vid != hw->mac.default_vid)) | ||
1054 | interface->flags |= FM10K_FLAG_RESET_REQUESTED; | ||
1055 | |||
1056 | return 0; | ||
1057 | } | ||
1058 | |||
1006 | /* generic error handler for mailbox issues */ | 1059 | /* generic error handler for mailbox issues */ |
1007 | static s32 fm10k_mbx_error(struct fm10k_hw *hw, u32 **results, | 1060 | static s32 fm10k_mbx_error(struct fm10k_hw *hw, u32 **results, |
1008 | struct fm10k_mbx_info *mbx) | 1061 | struct fm10k_mbx_info *mbx) |
@@ -1019,6 +1072,46 @@ static s32 fm10k_mbx_error(struct fm10k_hw *hw, u32 **results, | |||
1019 | return 0; | 1072 | return 0; |
1020 | } | 1073 | } |
1021 | 1074 | ||
1075 | static const struct fm10k_msg_data vf_mbx_data[] = { | ||
1076 | FM10K_TLV_MSG_TEST_HANDLER(fm10k_tlv_msg_test), | ||
1077 | FM10K_VF_MSG_MAC_VLAN_HANDLER(fm10k_mbx_mac_addr), | ||
1078 | FM10K_VF_MSG_LPORT_STATE_HANDLER(fm10k_msg_lport_state_vf), | ||
1079 | FM10K_TLV_MSG_ERROR_HANDLER(fm10k_mbx_error), | ||
1080 | }; | ||
1081 | |||
1082 | static int fm10k_mbx_request_irq_vf(struct fm10k_intfc *interface) | ||
1083 | { | ||
1084 | struct msix_entry *entry = &interface->msix_entries[FM10K_MBX_VECTOR]; | ||
1085 | struct net_device *dev = interface->netdev; | ||
1086 | struct fm10k_hw *hw = &interface->hw; | ||
1087 | int err; | ||
1088 | |||
1089 | /* Use timer0 for interrupt moderation on the mailbox */ | ||
1090 | u32 itr = FM10K_INT_MAP_TIMER0 | entry->entry; | ||
1091 | |||
1092 | /* register mailbox handlers */ | ||
1093 | err = hw->mbx.ops.register_handlers(&hw->mbx, vf_mbx_data); | ||
1094 | if (err) | ||
1095 | return err; | ||
1096 | |||
1097 | /* request the IRQ */ | ||
1098 | err = request_irq(entry->vector, fm10k_msix_mbx_vf, 0, | ||
1099 | dev->name, interface); | ||
1100 | if (err) { | ||
1101 | netif_err(interface, probe, dev, | ||
1102 | "request_irq for msix_mbx failed: %d\n", err); | ||
1103 | return err; | ||
1104 | } | ||
1105 | |||
1106 | /* map all of the interrupt sources */ | ||
1107 | fm10k_write_reg(hw, FM10K_VFINT_MAP, itr); | ||
1108 | |||
1109 | /* enable interrupt */ | ||
1110 | fm10k_write_reg(hw, FM10K_VFITR(entry->entry), FM10K_ITR_ENABLE); | ||
1111 | |||
1112 | return 0; | ||
1113 | } | ||
1114 | |||
1022 | static s32 fm10k_lport_map(struct fm10k_hw *hw, u32 **results, | 1115 | static s32 fm10k_lport_map(struct fm10k_hw *hw, u32 **results, |
1023 | struct fm10k_mbx_info *mbx) | 1116 | struct fm10k_mbx_info *mbx) |
1024 | { | 1117 | { |
@@ -1142,7 +1235,10 @@ int fm10k_mbx_request_irq(struct fm10k_intfc *interface) | |||
1142 | int err; | 1235 | int err; |
1143 | 1236 | ||
1144 | /* enable Mailbox cause */ | 1237 | /* enable Mailbox cause */ |
1145 | err = fm10k_mbx_request_irq_pf(interface); | 1238 | if (hw->mac.type == fm10k_mac_pf) |
1239 | err = fm10k_mbx_request_irq_pf(interface); | ||
1240 | else | ||
1241 | err = fm10k_mbx_request_irq_vf(interface); | ||
1146 | 1242 | ||
1147 | /* connect mailbox */ | 1243 | /* connect mailbox */ |
1148 | if (!err) | 1244 | if (!err) |
@@ -1220,7 +1316,9 @@ int fm10k_qv_request_irq(struct fm10k_intfc *interface) | |||
1220 | } | 1316 | } |
1221 | 1317 | ||
1222 | /* Assign ITR register to q_vector */ | 1318 | /* Assign ITR register to q_vector */ |
1223 | q_vector->itr = &interface->uc_addr[FM10K_ITR(entry->entry)]; | 1319 | q_vector->itr = (hw->mac.type == fm10k_mac_pf) ? |
1320 | &interface->uc_addr[FM10K_ITR(entry->entry)] : | ||
1321 | &interface->uc_addr[FM10K_VFITR(entry->entry)]; | ||
1224 | 1322 | ||
1225 | /* request the IRQ */ | 1323 | /* request the IRQ */ |
1226 | err = request_irq(entry->vector, &fm10k_msix_clean_rings, 0, | 1324 | err = request_irq(entry->vector, &fm10k_msix_clean_rings, 0, |
diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_type.h b/drivers/net/ethernet/intel/fm10k/fm10k_type.h index eda0c7cfd861..cc1df60d8552 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_type.h +++ b/drivers/net/ethernet/intel/fm10k/fm10k_type.h | |||
@@ -351,6 +351,13 @@ struct fm10k_hw; | |||
351 | #define FM10K_QUEUE_DISABLE_TIMEOUT 100 | 351 | #define FM10K_QUEUE_DISABLE_TIMEOUT 100 |
352 | #define FM10K_RESET_TIMEOUT 100 | 352 | #define FM10K_RESET_TIMEOUT 100 |
353 | 353 | ||
354 | /* VF registers */ | ||
355 | #define FM10K_VFCTRL 0x00000 | ||
356 | #define FM10K_VFCTRL_RST 0x00000008 | ||
357 | #define FM10K_VFINT_MAP 0x00030 | ||
358 | #define FM10K_VFSYSTIME 0x00040 | ||
359 | #define FM10K_VFITR(_n) ((_n) + 0x00060) | ||
360 | |||
354 | enum fm10k_int_source { | 361 | enum fm10k_int_source { |
355 | fm10k_int_Mailbox = 0, | 362 | fm10k_int_Mailbox = 0, |
356 | fm10k_int_PCIeFault = 1, | 363 | fm10k_int_PCIeFault = 1, |
@@ -522,6 +529,7 @@ struct fm10k_mac_ops { | |||
522 | enum fm10k_mac_type { | 529 | enum fm10k_mac_type { |
523 | fm10k_mac_unknown = 0, | 530 | fm10k_mac_unknown = 0, |
524 | fm10k_mac_pf, | 531 | fm10k_mac_pf, |
532 | fm10k_mac_vf, | ||
525 | fm10k_num_macs | 533 | fm10k_num_macs |
526 | }; | 534 | }; |
527 | 535 | ||
@@ -561,6 +569,7 @@ enum fm10k_xcast_modes { | |||
561 | 569 | ||
562 | enum fm10k_devices { | 570 | enum fm10k_devices { |
563 | fm10k_device_pf, | 571 | fm10k_device_pf, |
572 | fm10k_device_vf, | ||
564 | }; | 573 | }; |
565 | 574 | ||
566 | struct fm10k_info { | 575 | struct fm10k_info { |
diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_vf.c b/drivers/net/ethernet/intel/fm10k/fm10k_vf.c new file mode 100644 index 000000000000..25c23fce60f8 --- /dev/null +++ b/drivers/net/ethernet/intel/fm10k/fm10k_vf.c | |||
@@ -0,0 +1,523 @@ | |||
1 | /* Intel Ethernet Switch Host Interface Driver | ||
2 | * Copyright(c) 2013 - 2014 Intel Corporation. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | * | ||
13 | * The full GNU General Public License is included in this distribution in | ||
14 | * the file called "COPYING". | ||
15 | * | ||
16 | * Contact Information: | ||
17 | * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> | ||
18 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
19 | */ | ||
20 | |||
21 | #include "fm10k_vf.h" | ||
22 | |||
23 | /** | ||
24 | * fm10k_stop_hw_vf - Stop Tx/Rx units | ||
25 | * @hw: pointer to hardware structure | ||
26 | * | ||
27 | **/ | ||
28 | static s32 fm10k_stop_hw_vf(struct fm10k_hw *hw) | ||
29 | { | ||
30 | u8 *perm_addr = hw->mac.perm_addr; | ||
31 | u32 bal = 0, bah = 0; | ||
32 | s32 err; | ||
33 | u16 i; | ||
34 | |||
35 | /* we need to disable the queues before taking further steps */ | ||
36 | err = fm10k_stop_hw_generic(hw); | ||
37 | if (err) | ||
38 | return err; | ||
39 | |||
40 | /* If permenant address is set then we need to restore it */ | ||
41 | if (is_valid_ether_addr(perm_addr)) { | ||
42 | bal = (((u32)perm_addr[3]) << 24) | | ||
43 | (((u32)perm_addr[4]) << 16) | | ||
44 | (((u32)perm_addr[5]) << 8); | ||
45 | bah = (((u32)0xFF) << 24) | | ||
46 | (((u32)perm_addr[0]) << 16) | | ||
47 | (((u32)perm_addr[1]) << 8) | | ||
48 | ((u32)perm_addr[2]); | ||
49 | } | ||
50 | |||
51 | /* The queues have already been disabled so we just need to | ||
52 | * update their base address registers | ||
53 | */ | ||
54 | for (i = 0; i < hw->mac.max_queues; i++) { | ||
55 | fm10k_write_reg(hw, FM10K_TDBAL(i), bal); | ||
56 | fm10k_write_reg(hw, FM10K_TDBAH(i), bah); | ||
57 | fm10k_write_reg(hw, FM10K_RDBAL(i), bal); | ||
58 | fm10k_write_reg(hw, FM10K_RDBAH(i), bah); | ||
59 | } | ||
60 | |||
61 | return 0; | ||
62 | } | ||
63 | |||
64 | /** | ||
65 | * fm10k_reset_hw_vf - VF hardware reset | ||
66 | * @hw: pointer to hardware structure | ||
67 | * | ||
68 | * This function should return the hardare to a state similar to the | ||
69 | * one it is in after just being initialized. | ||
70 | **/ | ||
71 | static s32 fm10k_reset_hw_vf(struct fm10k_hw *hw) | ||
72 | { | ||
73 | s32 err; | ||
74 | |||
75 | /* shut down queues we own and reset DMA configuration */ | ||
76 | err = fm10k_stop_hw_vf(hw); | ||
77 | if (err) | ||
78 | return err; | ||
79 | |||
80 | /* Inititate VF reset */ | ||
81 | fm10k_write_reg(hw, FM10K_VFCTRL, FM10K_VFCTRL_RST); | ||
82 | |||
83 | /* Flush write and allow 100us for reset to complete */ | ||
84 | fm10k_write_flush(hw); | ||
85 | udelay(FM10K_RESET_TIMEOUT); | ||
86 | |||
87 | /* Clear reset bit and verify it was cleared */ | ||
88 | fm10k_write_reg(hw, FM10K_VFCTRL, 0); | ||
89 | if (fm10k_read_reg(hw, FM10K_VFCTRL) & FM10K_VFCTRL_RST) | ||
90 | err = FM10K_ERR_RESET_FAILED; | ||
91 | |||
92 | return err; | ||
93 | } | ||
94 | |||
95 | /** | ||
96 | * fm10k_init_hw_vf - VF hardware initialization | ||
97 | * @hw: pointer to hardware structure | ||
98 | * | ||
99 | **/ | ||
100 | static s32 fm10k_init_hw_vf(struct fm10k_hw *hw) | ||
101 | { | ||
102 | u32 tqdloc, tqdloc0 = ~fm10k_read_reg(hw, FM10K_TQDLOC(0)); | ||
103 | s32 err; | ||
104 | u16 i; | ||
105 | |||
106 | /* assume we always have at least 1 queue */ | ||
107 | for (i = 1; tqdloc0 && (i < FM10K_MAX_QUEUES_POOL); i++) { | ||
108 | /* verify the Descriptor cache offsets are increasing */ | ||
109 | tqdloc = ~fm10k_read_reg(hw, FM10K_TQDLOC(i)); | ||
110 | if (!tqdloc || (tqdloc == tqdloc0)) | ||
111 | break; | ||
112 | |||
113 | /* check to verify the PF doesn't own any of our queues */ | ||
114 | if (!~fm10k_read_reg(hw, FM10K_TXQCTL(i)) || | ||
115 | !~fm10k_read_reg(hw, FM10K_RXQCTL(i))) | ||
116 | break; | ||
117 | } | ||
118 | |||
119 | /* shut down queues we own and reset DMA configuration */ | ||
120 | err = fm10k_disable_queues_generic(hw, i); | ||
121 | if (err) | ||
122 | return err; | ||
123 | |||
124 | /* record maximum queue count */ | ||
125 | hw->mac.max_queues = i; | ||
126 | |||
127 | return 0; | ||
128 | } | ||
129 | |||
130 | /** | ||
131 | * fm10k_is_slot_appropriate_vf - Indicate appropriate slot for this SKU | ||
132 | * @hw: pointer to hardware structure | ||
133 | * | ||
134 | * Looks at the PCIe bus info to confirm whether or not this slot can support | ||
135 | * the necessary bandwidth for this device. Since the VF has no control over | ||
136 | * the "slot" it is in, always indicate that the slot is appropriate. | ||
137 | **/ | ||
138 | static bool fm10k_is_slot_appropriate_vf(struct fm10k_hw *hw) | ||
139 | { | ||
140 | return true; | ||
141 | } | ||
142 | |||
143 | /* This structure defines the attibutes to be parsed below */ | ||
144 | const struct fm10k_tlv_attr fm10k_mac_vlan_msg_attr[] = { | ||
145 | FM10K_TLV_ATTR_U32(FM10K_MAC_VLAN_MSG_VLAN), | ||
146 | FM10K_TLV_ATTR_BOOL(FM10K_MAC_VLAN_MSG_SET), | ||
147 | FM10K_TLV_ATTR_MAC_ADDR(FM10K_MAC_VLAN_MSG_MAC), | ||
148 | FM10K_TLV_ATTR_MAC_ADDR(FM10K_MAC_VLAN_MSG_DEFAULT_MAC), | ||
149 | FM10K_TLV_ATTR_MAC_ADDR(FM10K_MAC_VLAN_MSG_MULTICAST), | ||
150 | FM10K_TLV_ATTR_LAST | ||
151 | }; | ||
152 | |||
153 | /** | ||
154 | * fm10k_update_vlan_vf - Update status of VLAN ID in VLAN filter table | ||
155 | * @hw: pointer to hardware structure | ||
156 | * @vid: VLAN ID to add to table | ||
157 | * @vsi: Reserved, should always be 0 | ||
158 | * @set: Indicates if this is a set or clear operation | ||
159 | * | ||
160 | * This function adds or removes the corresponding VLAN ID from the VLAN | ||
161 | * filter table for this VF. | ||
162 | **/ | ||
163 | static s32 fm10k_update_vlan_vf(struct fm10k_hw *hw, u32 vid, u8 vsi, bool set) | ||
164 | { | ||
165 | struct fm10k_mbx_info *mbx = &hw->mbx; | ||
166 | u32 msg[4]; | ||
167 | |||
168 | /* verify the index is not set */ | ||
169 | if (vsi) | ||
170 | return FM10K_ERR_PARAM; | ||
171 | |||
172 | /* verify upper 4 bits of vid and length are 0 */ | ||
173 | if ((vid << 16 | vid) >> 28) | ||
174 | return FM10K_ERR_PARAM; | ||
175 | |||
176 | /* encode set bit into the VLAN ID */ | ||
177 | if (!set) | ||
178 | vid |= FM10K_VLAN_CLEAR; | ||
179 | |||
180 | /* generate VLAN request */ | ||
181 | fm10k_tlv_msg_init(msg, FM10K_VF_MSG_ID_MAC_VLAN); | ||
182 | fm10k_tlv_attr_put_u32(msg, FM10K_MAC_VLAN_MSG_VLAN, vid); | ||
183 | |||
184 | /* load onto outgoing mailbox */ | ||
185 | return mbx->ops.enqueue_tx(hw, mbx, msg); | ||
186 | } | ||
187 | |||
188 | /** | ||
189 | * fm10k_msg_mac_vlan_vf - Read device MAC address from mailbox message | ||
190 | * @hw: pointer to the HW structure | ||
191 | * @results: Attributes for message | ||
192 | * @mbx: unused mailbox data | ||
193 | * | ||
194 | * This function should determine the MAC address for the VF | ||
195 | **/ | ||
196 | s32 fm10k_msg_mac_vlan_vf(struct fm10k_hw *hw, u32 **results, | ||
197 | struct fm10k_mbx_info *mbx) | ||
198 | { | ||
199 | u8 perm_addr[ETH_ALEN]; | ||
200 | u16 vid; | ||
201 | s32 err; | ||
202 | |||
203 | /* record MAC address requested */ | ||
204 | err = fm10k_tlv_attr_get_mac_vlan( | ||
205 | results[FM10K_MAC_VLAN_MSG_DEFAULT_MAC], | ||
206 | perm_addr, &vid); | ||
207 | if (err) | ||
208 | return err; | ||
209 | |||
210 | ether_addr_copy(hw->mac.perm_addr, perm_addr); | ||
211 | hw->mac.default_vid = vid & (FM10K_VLAN_TABLE_VID_MAX - 1); | ||
212 | hw->mac.vlan_override = !!(vid & FM10K_VLAN_CLEAR); | ||
213 | |||
214 | return 0; | ||
215 | } | ||
216 | |||
217 | /** | ||
218 | * fm10k_read_mac_addr_vf - Read device MAC address | ||
219 | * @hw: pointer to the HW structure | ||
220 | * | ||
221 | * This function should determine the MAC address for the VF | ||
222 | **/ | ||
223 | static s32 fm10k_read_mac_addr_vf(struct fm10k_hw *hw) | ||
224 | { | ||
225 | u8 perm_addr[ETH_ALEN]; | ||
226 | u32 base_addr; | ||
227 | |||
228 | base_addr = fm10k_read_reg(hw, FM10K_TDBAL(0)); | ||
229 | |||
230 | /* last byte should be 0 */ | ||
231 | if (base_addr << 24) | ||
232 | return FM10K_ERR_INVALID_MAC_ADDR; | ||
233 | |||
234 | perm_addr[3] = (u8)(base_addr >> 24); | ||
235 | perm_addr[4] = (u8)(base_addr >> 16); | ||
236 | perm_addr[5] = (u8)(base_addr >> 8); | ||
237 | |||
238 | base_addr = fm10k_read_reg(hw, FM10K_TDBAH(0)); | ||
239 | |||
240 | /* first byte should be all 1's */ | ||
241 | if ((~base_addr) >> 24) | ||
242 | return FM10K_ERR_INVALID_MAC_ADDR; | ||
243 | |||
244 | perm_addr[0] = (u8)(base_addr >> 16); | ||
245 | perm_addr[1] = (u8)(base_addr >> 8); | ||
246 | perm_addr[2] = (u8)(base_addr); | ||
247 | |||
248 | ether_addr_copy(hw->mac.perm_addr, perm_addr); | ||
249 | ether_addr_copy(hw->mac.addr, perm_addr); | ||
250 | |||
251 | return 0; | ||
252 | } | ||
253 | |||
254 | /** | ||
255 | * fm10k_update_uc_addr_vf - Update device unicast address | ||
256 | * @hw: pointer to the HW structure | ||
257 | * @glort: unused | ||
258 | * @mac: MAC address to add/remove from table | ||
259 | * @vid: VLAN ID to add/remove from table | ||
260 | * @add: Indicates if this is an add or remove operation | ||
261 | * @flags: flags field to indicate add and secure - unused | ||
262 | * | ||
263 | * This function is used to add or remove unicast MAC addresses for | ||
264 | * the VF. | ||
265 | **/ | ||
266 | static s32 fm10k_update_uc_addr_vf(struct fm10k_hw *hw, u16 glort, | ||
267 | const u8 *mac, u16 vid, bool add, u8 flags) | ||
268 | { | ||
269 | struct fm10k_mbx_info *mbx = &hw->mbx; | ||
270 | u32 msg[7]; | ||
271 | |||
272 | /* verify VLAN ID is valid */ | ||
273 | if (vid >= FM10K_VLAN_TABLE_VID_MAX) | ||
274 | return FM10K_ERR_PARAM; | ||
275 | |||
276 | /* verify MAC address is valid */ | ||
277 | if (!is_valid_ether_addr(mac)) | ||
278 | return FM10K_ERR_PARAM; | ||
279 | |||
280 | /* verify we are not locked down on the MAC address */ | ||
281 | if (is_valid_ether_addr(hw->mac.perm_addr) && | ||
282 | memcmp(hw->mac.perm_addr, mac, ETH_ALEN)) | ||
283 | return FM10K_ERR_PARAM; | ||
284 | |||
285 | /* add bit to notify us if this is a set of clear operation */ | ||
286 | if (!add) | ||
287 | vid |= FM10K_VLAN_CLEAR; | ||
288 | |||
289 | /* generate VLAN request */ | ||
290 | fm10k_tlv_msg_init(msg, FM10K_VF_MSG_ID_MAC_VLAN); | ||
291 | fm10k_tlv_attr_put_mac_vlan(msg, FM10K_MAC_VLAN_MSG_MAC, mac, vid); | ||
292 | |||
293 | /* load onto outgoing mailbox */ | ||
294 | return mbx->ops.enqueue_tx(hw, mbx, msg); | ||
295 | } | ||
296 | |||
297 | /** | ||
298 | * fm10k_update_mc_addr_vf - Update device multicast address | ||
299 | * @hw: pointer to the HW structure | ||
300 | * @glort: unused | ||
301 | * @mac: MAC address to add/remove from table | ||
302 | * @vid: VLAN ID to add/remove from table | ||
303 | * @add: Indicates if this is an add or remove operation | ||
304 | * | ||
305 | * This function is used to add or remove multicast MAC addresses for | ||
306 | * the VF. | ||
307 | **/ | ||
308 | static s32 fm10k_update_mc_addr_vf(struct fm10k_hw *hw, u16 glort, | ||
309 | const u8 *mac, u16 vid, bool add) | ||
310 | { | ||
311 | struct fm10k_mbx_info *mbx = &hw->mbx; | ||
312 | u32 msg[7]; | ||
313 | |||
314 | /* verify VLAN ID is valid */ | ||
315 | if (vid >= FM10K_VLAN_TABLE_VID_MAX) | ||
316 | return FM10K_ERR_PARAM; | ||
317 | |||
318 | /* verify multicast address is valid */ | ||
319 | if (!is_multicast_ether_addr(mac)) | ||
320 | return FM10K_ERR_PARAM; | ||
321 | |||
322 | /* add bit to notify us if this is a set of clear operation */ | ||
323 | if (!add) | ||
324 | vid |= FM10K_VLAN_CLEAR; | ||
325 | |||
326 | /* generate VLAN request */ | ||
327 | fm10k_tlv_msg_init(msg, FM10K_VF_MSG_ID_MAC_VLAN); | ||
328 | fm10k_tlv_attr_put_mac_vlan(msg, FM10K_MAC_VLAN_MSG_MULTICAST, | ||
329 | mac, vid); | ||
330 | |||
331 | /* load onto outgoing mailbox */ | ||
332 | return mbx->ops.enqueue_tx(hw, mbx, msg); | ||
333 | } | ||
334 | |||
335 | /** | ||
336 | * fm10k_update_int_moderator_vf - Request update of interrupt moderator list | ||
337 | * @hw: pointer to hardware structure | ||
338 | * | ||
339 | * This function will issue a request to the PF to rescan our MSI-X table | ||
340 | * and to update the interrupt moderator linked list. | ||
341 | **/ | ||
342 | static void fm10k_update_int_moderator_vf(struct fm10k_hw *hw) | ||
343 | { | ||
344 | struct fm10k_mbx_info *mbx = &hw->mbx; | ||
345 | u32 msg[1]; | ||
346 | |||
347 | /* generate MSI-X request */ | ||
348 | fm10k_tlv_msg_init(msg, FM10K_VF_MSG_ID_MSIX); | ||
349 | |||
350 | /* load onto outgoing mailbox */ | ||
351 | mbx->ops.enqueue_tx(hw, mbx, msg); | ||
352 | } | ||
353 | |||
354 | /* This structure defines the attibutes to be parsed below */ | ||
355 | const struct fm10k_tlv_attr fm10k_lport_state_msg_attr[] = { | ||
356 | FM10K_TLV_ATTR_BOOL(FM10K_LPORT_STATE_MSG_DISABLE), | ||
357 | FM10K_TLV_ATTR_U8(FM10K_LPORT_STATE_MSG_XCAST_MODE), | ||
358 | FM10K_TLV_ATTR_BOOL(FM10K_LPORT_STATE_MSG_READY), | ||
359 | FM10K_TLV_ATTR_LAST | ||
360 | }; | ||
361 | |||
362 | /** | ||
363 | * fm10k_msg_lport_state_vf - Message handler for lport_state message from PF | ||
364 | * @hw: Pointer to hardware structure | ||
365 | * @results: pointer array containing parsed data | ||
366 | * @mbx: Pointer to mailbox information structure | ||
367 | * | ||
368 | * This handler is meant to capture the indication from the PF that we | ||
369 | * are ready to bring up the interface. | ||
370 | **/ | ||
371 | s32 fm10k_msg_lport_state_vf(struct fm10k_hw *hw, u32 **results, | ||
372 | struct fm10k_mbx_info *mbx) | ||
373 | { | ||
374 | hw->mac.dglort_map = !results[FM10K_LPORT_STATE_MSG_READY] ? | ||
375 | FM10K_DGLORTMAP_NONE : FM10K_DGLORTMAP_ZERO; | ||
376 | |||
377 | return 0; | ||
378 | } | ||
379 | |||
380 | /** | ||
381 | * fm10k_update_lport_state_vf - Update device state in lower device | ||
382 | * @hw: pointer to the HW structure | ||
383 | * @glort: unused | ||
384 | * @count: number of logical ports to enable - unused (always 1) | ||
385 | * @enable: boolean value indicating if this is an enable or disable request | ||
386 | * | ||
387 | * Notify the lower device of a state change. If the lower device is | ||
388 | * enabled we can add filters, if it is disabled all filters for this | ||
389 | * logical port are flushed. | ||
390 | **/ | ||
391 | static s32 fm10k_update_lport_state_vf(struct fm10k_hw *hw, u16 glort, | ||
392 | u16 count, bool enable) | ||
393 | { | ||
394 | struct fm10k_mbx_info *mbx = &hw->mbx; | ||
395 | u32 msg[2]; | ||
396 | |||
397 | /* reset glort mask 0 as we have to wait to be enabled */ | ||
398 | hw->mac.dglort_map = FM10K_DGLORTMAP_NONE; | ||
399 | |||
400 | /* generate port state request */ | ||
401 | fm10k_tlv_msg_init(msg, FM10K_VF_MSG_ID_LPORT_STATE); | ||
402 | if (!enable) | ||
403 | fm10k_tlv_attr_put_bool(msg, FM10K_LPORT_STATE_MSG_DISABLE); | ||
404 | |||
405 | /* load onto outgoing mailbox */ | ||
406 | return mbx->ops.enqueue_tx(hw, mbx, msg); | ||
407 | } | ||
408 | |||
409 | /** | ||
410 | * fm10k_update_xcast_mode_vf - Request update of multicast mode | ||
411 | * @hw: pointer to hardware structure | ||
412 | * @glort: unused | ||
413 | * @mode: integer value indicating mode being requested | ||
414 | * | ||
415 | * This function will attempt to request a higher mode for the port | ||
416 | * so that it can enable either multicast, multicast promiscuous, or | ||
417 | * promiscuous mode of operation. | ||
418 | **/ | ||
419 | static s32 fm10k_update_xcast_mode_vf(struct fm10k_hw *hw, u16 glort, u8 mode) | ||
420 | { | ||
421 | struct fm10k_mbx_info *mbx = &hw->mbx; | ||
422 | u32 msg[3]; | ||
423 | |||
424 | if (mode > FM10K_XCAST_MODE_NONE) | ||
425 | return FM10K_ERR_PARAM; | ||
426 | /* generate message requesting to change xcast mode */ | ||
427 | fm10k_tlv_msg_init(msg, FM10K_VF_MSG_ID_LPORT_STATE); | ||
428 | fm10k_tlv_attr_put_u8(msg, FM10K_LPORT_STATE_MSG_XCAST_MODE, mode); | ||
429 | |||
430 | /* load onto outgoing mailbox */ | ||
431 | return mbx->ops.enqueue_tx(hw, mbx, msg); | ||
432 | } | ||
433 | |||
434 | /** | ||
435 | * fm10k_update_hw_stats_vf - Updates hardware related statistics of VF | ||
436 | * @hw: pointer to hardware structure | ||
437 | * @stats: pointer to statistics structure | ||
438 | * | ||
439 | * This function collects and aggregates per queue hardware statistics. | ||
440 | **/ | ||
441 | static void fm10k_update_hw_stats_vf(struct fm10k_hw *hw, | ||
442 | struct fm10k_hw_stats *stats) | ||
443 | { | ||
444 | fm10k_update_hw_stats_q(hw, stats->q, 0, hw->mac.max_queues); | ||
445 | } | ||
446 | |||
447 | /** | ||
448 | * fm10k_rebind_hw_stats_vf - Resets base for hardware statistics of VF | ||
449 | * @hw: pointer to hardware structure | ||
450 | * @stats: pointer to the stats structure to update | ||
451 | * | ||
452 | * This function resets the base for queue hardware statistics. | ||
453 | **/ | ||
454 | static void fm10k_rebind_hw_stats_vf(struct fm10k_hw *hw, | ||
455 | struct fm10k_hw_stats *stats) | ||
456 | { | ||
457 | /* Unbind Queue Statistics */ | ||
458 | fm10k_unbind_hw_stats_q(stats->q, 0, hw->mac.max_queues); | ||
459 | |||
460 | /* Reinitialize bases for all stats */ | ||
461 | fm10k_update_hw_stats_vf(hw, stats); | ||
462 | } | ||
463 | |||
464 | /** | ||
465 | * fm10k_configure_dglort_map_vf - Configures GLORT entry and queues | ||
466 | * @hw: pointer to hardware structure | ||
467 | * @dglort: pointer to dglort configuration structure | ||
468 | * | ||
469 | * Reads the configuration structure contained in dglort_cfg and uses | ||
470 | * that information to then populate a DGLORTMAP/DEC entry and the queues | ||
471 | * to which it has been assigned. | ||
472 | **/ | ||
473 | static s32 fm10k_configure_dglort_map_vf(struct fm10k_hw *hw, | ||
474 | struct fm10k_dglort_cfg *dglort) | ||
475 | { | ||
476 | /* verify the dglort pointer */ | ||
477 | if (!dglort) | ||
478 | return FM10K_ERR_PARAM; | ||
479 | |||
480 | /* stub for now until we determine correct message for this */ | ||
481 | |||
482 | return 0; | ||
483 | } | ||
484 | |||
485 | static const struct fm10k_msg_data fm10k_msg_data_vf[] = { | ||
486 | FM10K_TLV_MSG_TEST_HANDLER(fm10k_tlv_msg_test), | ||
487 | FM10K_VF_MSG_MAC_VLAN_HANDLER(fm10k_msg_mac_vlan_vf), | ||
488 | FM10K_VF_MSG_LPORT_STATE_HANDLER(fm10k_msg_lport_state_vf), | ||
489 | FM10K_TLV_MSG_ERROR_HANDLER(fm10k_tlv_msg_error), | ||
490 | }; | ||
491 | |||
492 | static struct fm10k_mac_ops mac_ops_vf = { | ||
493 | .get_bus_info = &fm10k_get_bus_info_generic, | ||
494 | .reset_hw = &fm10k_reset_hw_vf, | ||
495 | .init_hw = &fm10k_init_hw_vf, | ||
496 | .start_hw = &fm10k_start_hw_generic, | ||
497 | .stop_hw = &fm10k_stop_hw_vf, | ||
498 | .is_slot_appropriate = &fm10k_is_slot_appropriate_vf, | ||
499 | .update_vlan = &fm10k_update_vlan_vf, | ||
500 | .read_mac_addr = &fm10k_read_mac_addr_vf, | ||
501 | .update_uc_addr = &fm10k_update_uc_addr_vf, | ||
502 | .update_mc_addr = &fm10k_update_mc_addr_vf, | ||
503 | .update_xcast_mode = &fm10k_update_xcast_mode_vf, | ||
504 | .update_int_moderator = &fm10k_update_int_moderator_vf, | ||
505 | .update_lport_state = &fm10k_update_lport_state_vf, | ||
506 | .update_hw_stats = &fm10k_update_hw_stats_vf, | ||
507 | .rebind_hw_stats = &fm10k_rebind_hw_stats_vf, | ||
508 | .configure_dglort_map = &fm10k_configure_dglort_map_vf, | ||
509 | .get_host_state = &fm10k_get_host_state_generic, | ||
510 | }; | ||
511 | |||
512 | static s32 fm10k_get_invariants_vf(struct fm10k_hw *hw) | ||
513 | { | ||
514 | fm10k_get_invariants_generic(hw); | ||
515 | |||
516 | return fm10k_pfvf_mbx_init(hw, &hw->mbx, fm10k_msg_data_vf, 0); | ||
517 | } | ||
518 | |||
519 | struct fm10k_info fm10k_vf_info = { | ||
520 | .mac = fm10k_mac_vf, | ||
521 | .get_invariants = &fm10k_get_invariants_vf, | ||
522 | .mac_ops = &mac_ops_vf, | ||
523 | }; | ||
diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_vf.h b/drivers/net/ethernet/intel/fm10k/fm10k_vf.h new file mode 100644 index 000000000000..8e96ee53c147 --- /dev/null +++ b/drivers/net/ethernet/intel/fm10k/fm10k_vf.h | |||
@@ -0,0 +1,68 @@ | |||
1 | /* Intel Ethernet Switch Host Interface Driver | ||
2 | * Copyright(c) 2013 - 2014 Intel Corporation. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | * | ||
13 | * The full GNU General Public License is included in this distribution in | ||
14 | * the file called "COPYING". | ||
15 | * | ||
16 | * Contact Information: | ||
17 | * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> | ||
18 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | ||
19 | */ | ||
20 | |||
21 | #ifndef _FM10K_VF_H_ | ||
22 | #define _FM10K_VF_H_ | ||
23 | |||
24 | #include "fm10k_type.h" | ||
25 | #include "fm10k_common.h" | ||
26 | |||
27 | enum fm10k_vf_tlv_msg_id { | ||
28 | FM10K_VF_MSG_ID_TEST = 0, /* msg ID reserved for testing */ | ||
29 | FM10K_VF_MSG_ID_MSIX, | ||
30 | FM10K_VF_MSG_ID_MAC_VLAN, | ||
31 | FM10K_VF_MSG_ID_LPORT_STATE, | ||
32 | FM10K_VF_MSG_ID_MAX, | ||
33 | }; | ||
34 | |||
35 | enum fm10k_tlv_mac_vlan_attr_id { | ||
36 | FM10K_MAC_VLAN_MSG_VLAN, | ||
37 | FM10K_MAC_VLAN_MSG_SET, | ||
38 | FM10K_MAC_VLAN_MSG_MAC, | ||
39 | FM10K_MAC_VLAN_MSG_DEFAULT_MAC, | ||
40 | FM10K_MAC_VLAN_MSG_MULTICAST, | ||
41 | FM10K_MAC_VLAN_MSG_ID_MAX | ||
42 | }; | ||
43 | |||
44 | enum fm10k_tlv_lport_state_attr_id { | ||
45 | FM10K_LPORT_STATE_MSG_DISABLE, | ||
46 | FM10K_LPORT_STATE_MSG_XCAST_MODE, | ||
47 | FM10K_LPORT_STATE_MSG_READY, | ||
48 | FM10K_LPORT_STATE_MSG_MAX | ||
49 | }; | ||
50 | |||
51 | #define FM10K_VF_MSG_MSIX_HANDLER(func) \ | ||
52 | FM10K_MSG_HANDLER(FM10K_VF_MSG_ID_MSIX, NULL, func) | ||
53 | |||
54 | s32 fm10k_msg_mac_vlan_vf(struct fm10k_hw *, u32 **, struct fm10k_mbx_info *); | ||
55 | extern const struct fm10k_tlv_attr fm10k_mac_vlan_msg_attr[]; | ||
56 | #define FM10K_VF_MSG_MAC_VLAN_HANDLER(func) \ | ||
57 | FM10K_MSG_HANDLER(FM10K_VF_MSG_ID_MAC_VLAN, \ | ||
58 | fm10k_mac_vlan_msg_attr, func) | ||
59 | |||
60 | s32 fm10k_msg_lport_state_vf(struct fm10k_hw *, u32 **, | ||
61 | struct fm10k_mbx_info *); | ||
62 | extern const struct fm10k_tlv_attr fm10k_lport_state_msg_attr[]; | ||
63 | #define FM10K_VF_MSG_LPORT_STATE_HANDLER(func) \ | ||
64 | FM10K_MSG_HANDLER(FM10K_VF_MSG_ID_LPORT_STATE, \ | ||
65 | fm10k_lport_state_msg_attr, func) | ||
66 | |||
67 | extern struct fm10k_info fm10k_vf_info; | ||
68 | #endif /* _FM10K_VF_H */ | ||