diff options
author | Alexander Duyck <alexander.h.duyck@intel.com> | 2014-09-20 19:53:08 -0400 |
---|---|---|
committer | Jeff Kirsher <jeffrey.t.kirsher@intel.com> | 2014-09-23 06:59:21 -0400 |
commit | 9f801abc3d4fe1e770268ae4e610556e79be6fca (patch) | |
tree | c17b84e3a206c7fc6716983230e78ebc08463f87 /drivers/net/ethernet/intel/fm10k | |
parent | 883a9ccbae560a5b8be2a403d4a0744cd60b784c (diff) |
fm10k: Add support for IEEE DCBx
This patch adds support for management of the limited QOS features of the
FM10000 interface. Specifically we can support up to 8 traffic classes,
however the part only provides 1 Rx and 1 Tx FIFO in the host interface and
as a result this can lead to head-of-line blocking on Rx. This can be
avoided by setting PFC only for priorities that cannot afford to drop
frames.
Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com>
Acked-by: John Fastabend <john.r.fastabend@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Diffstat (limited to 'drivers/net/ethernet/intel/fm10k')
-rw-r--r-- | drivers/net/ethernet/intel/fm10k/Makefile | 3 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/fm10k/fm10k.h | 5 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/fm10k/fm10k_dcbnl.c | 174 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/fm10k/fm10k_pci.c | 7 |
4 files changed, 185 insertions, 4 deletions
diff --git a/drivers/net/ethernet/intel/fm10k/Makefile b/drivers/net/ethernet/intel/fm10k/Makefile index 70565abfc62a..502362584165 100644 --- a/drivers/net/ethernet/intel/fm10k/Makefile +++ b/drivers/net/ethernet/intel/fm10k/Makefile | |||
@@ -29,4 +29,5 @@ 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 fm10k_vf.o \ | 31 | fm10k_netdev.o fm10k_ethtool.o fm10k_pf.o fm10k_vf.o \ |
32 | fm10k_mbx.o fm10k_iov.o fm10k_tlv.o | 32 | fm10k_mbx.o fm10k_iov.o fm10k_tlv.o \ |
33 | fm10k_dcbnl.o | ||
diff --git a/drivers/net/ethernet/intel/fm10k/fm10k.h b/drivers/net/ethernet/intel/fm10k/fm10k.h index fb718719c196..33a59493094c 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k.h +++ b/drivers/net/ethernet/intel/fm10k/fm10k.h | |||
@@ -307,7 +307,7 @@ struct fm10k_intfc { | |||
307 | /* VXLAN port tracking information */ | 307 | /* VXLAN port tracking information */ |
308 | struct list_head vxlan_port; | 308 | struct list_head vxlan_port; |
309 | 309 | ||
310 | #if defined(HAVE_DCBNL_IEEE) && defined(CONFIG_DCB) | 310 | #ifdef CONFIG_DCB |
311 | u8 pfc_en; | 311 | u8 pfc_en; |
312 | #endif | 312 | #endif |
313 | u8 rx_pause; | 313 | u8 rx_pause; |
@@ -467,4 +467,7 @@ int fm10k_ndo_set_vf_bw(struct net_device *netdev, int vf_idx, int rate, | |||
467 | int unused); | 467 | int unused); |
468 | int fm10k_ndo_get_vf_config(struct net_device *netdev, | 468 | int fm10k_ndo_get_vf_config(struct net_device *netdev, |
469 | int vf_idx, struct ifla_vf_info *ivi); | 469 | int vf_idx, struct ifla_vf_info *ivi); |
470 | |||
471 | /* DCB */ | ||
472 | void fm10k_dcbnl_set_ops(struct net_device *dev); | ||
470 | #endif /* _FM10K_H_ */ | 473 | #endif /* _FM10K_H_ */ |
diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_dcbnl.c b/drivers/net/ethernet/intel/fm10k/fm10k_dcbnl.c new file mode 100644 index 000000000000..212a92dad222 --- /dev/null +++ b/drivers/net/ethernet/intel/fm10k/fm10k_dcbnl.c | |||
@@ -0,0 +1,174 @@ | |||
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.h" | ||
22 | |||
23 | #ifdef CONFIG_DCB | ||
24 | /** | ||
25 | * fm10k_dcbnl_ieee_getets - get the ETS configuration for the device | ||
26 | * @dev: netdev interface for the device | ||
27 | * @ets: ETS structure to push configuration to | ||
28 | **/ | ||
29 | static int fm10k_dcbnl_ieee_getets(struct net_device *dev, struct ieee_ets *ets) | ||
30 | { | ||
31 | int i; | ||
32 | |||
33 | /* we support 8 TCs in all modes */ | ||
34 | ets->ets_cap = IEEE_8021QAZ_MAX_TCS; | ||
35 | ets->cbs = 0; | ||
36 | |||
37 | /* we only support strict priority and cannot do traffic shaping */ | ||
38 | memset(ets->tc_tx_bw, 0, sizeof(ets->tc_tx_bw)); | ||
39 | memset(ets->tc_rx_bw, 0, sizeof(ets->tc_rx_bw)); | ||
40 | memset(ets->tc_tsa, IEEE_8021QAZ_TSA_STRICT, sizeof(ets->tc_tsa)); | ||
41 | |||
42 | /* populate the prio map based on the netdev */ | ||
43 | for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) | ||
44 | ets->prio_tc[i] = netdev_get_prio_tc_map(dev, i); | ||
45 | |||
46 | return 0; | ||
47 | } | ||
48 | |||
49 | /** | ||
50 | * fm10k_dcbnl_ieee_setets - set the ETS configuration for the device | ||
51 | * @dev: netdev interface for the device | ||
52 | * @ets: ETS structure to pull configuration from | ||
53 | **/ | ||
54 | static int fm10k_dcbnl_ieee_setets(struct net_device *dev, struct ieee_ets *ets) | ||
55 | { | ||
56 | u8 num_tc = 0; | ||
57 | int i, err; | ||
58 | |||
59 | /* verify type and determine num_tcs needed */ | ||
60 | for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { | ||
61 | if (ets->tc_tx_bw[i] || ets->tc_rx_bw[i]) | ||
62 | return -EINVAL; | ||
63 | if (ets->tc_tsa[i] != IEEE_8021QAZ_TSA_STRICT) | ||
64 | return -EINVAL; | ||
65 | if (ets->prio_tc[i] > num_tc) | ||
66 | num_tc = ets->prio_tc[i]; | ||
67 | } | ||
68 | |||
69 | /* if requested TC is greater than 0 then num_tcs is max + 1 */ | ||
70 | if (num_tc) | ||
71 | num_tc++; | ||
72 | |||
73 | if (num_tc > IEEE_8021QAZ_MAX_TCS) | ||
74 | return -EINVAL; | ||
75 | |||
76 | /* update TC hardware mapping if necessary */ | ||
77 | if (num_tc != netdev_get_num_tc(dev)) { | ||
78 | err = fm10k_setup_tc(dev, num_tc); | ||
79 | if (err) | ||
80 | return err; | ||
81 | } | ||
82 | |||
83 | /* update priority mapping */ | ||
84 | for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) | ||
85 | netdev_set_prio_tc_map(dev, i, ets->prio_tc[i]); | ||
86 | |||
87 | return 0; | ||
88 | } | ||
89 | |||
90 | /** | ||
91 | * fm10k_dcbnl_ieee_getpfc - get the PFC configuration for the device | ||
92 | * @dev: netdev interface for the device | ||
93 | * @pfc: PFC structure to push configuration to | ||
94 | **/ | ||
95 | static int fm10k_dcbnl_ieee_getpfc(struct net_device *dev, struct ieee_pfc *pfc) | ||
96 | { | ||
97 | struct fm10k_intfc *interface = netdev_priv(dev); | ||
98 | |||
99 | /* record flow control max count and state of TCs */ | ||
100 | pfc->pfc_cap = IEEE_8021QAZ_MAX_TCS; | ||
101 | pfc->pfc_en = interface->pfc_en; | ||
102 | |||
103 | return 0; | ||
104 | } | ||
105 | |||
106 | /** | ||
107 | * fm10k_dcbnl_ieee_setpfc - set the PFC configuration for the device | ||
108 | * @dev: netdev interface for the device | ||
109 | * @pfc: PFC structure to pull configuration from | ||
110 | **/ | ||
111 | static int fm10k_dcbnl_ieee_setpfc(struct net_device *dev, struct ieee_pfc *pfc) | ||
112 | { | ||
113 | struct fm10k_intfc *interface = netdev_priv(dev); | ||
114 | |||
115 | /* record PFC configuration to interface */ | ||
116 | interface->pfc_en = pfc->pfc_en; | ||
117 | |||
118 | /* if we are running update the drop_en state for all queues */ | ||
119 | if (netif_running(dev)) | ||
120 | fm10k_update_rx_drop_en(interface); | ||
121 | |||
122 | return 0; | ||
123 | } | ||
124 | |||
125 | /** | ||
126 | * fm10k_dcbnl_ieee_getdcbx - get the DCBX configuration for the device | ||
127 | * @dev: netdev interface for the device | ||
128 | * | ||
129 | * Returns that we support only IEEE DCB for this interface | ||
130 | **/ | ||
131 | static u8 fm10k_dcbnl_getdcbx(struct net_device *dev) | ||
132 | { | ||
133 | return DCB_CAP_DCBX_HOST | DCB_CAP_DCBX_VER_IEEE; | ||
134 | } | ||
135 | |||
136 | /** | ||
137 | * fm10k_dcbnl_ieee_setdcbx - get the DCBX configuration for the device | ||
138 | * @dev: netdev interface for the device | ||
139 | * @mode: new mode for this device | ||
140 | * | ||
141 | * Returns error on attempt to enable anything but IEEE DCB for this interface | ||
142 | **/ | ||
143 | static u8 fm10k_dcbnl_setdcbx(struct net_device *dev, u8 mode) | ||
144 | { | ||
145 | return (mode != (DCB_CAP_DCBX_HOST | DCB_CAP_DCBX_VER_IEEE)) ? 1 : 0; | ||
146 | } | ||
147 | |||
148 | static const struct dcbnl_rtnl_ops fm10k_dcbnl_ops = { | ||
149 | .ieee_getets = fm10k_dcbnl_ieee_getets, | ||
150 | .ieee_setets = fm10k_dcbnl_ieee_setets, | ||
151 | .ieee_getpfc = fm10k_dcbnl_ieee_getpfc, | ||
152 | .ieee_setpfc = fm10k_dcbnl_ieee_setpfc, | ||
153 | |||
154 | .getdcbx = fm10k_dcbnl_getdcbx, | ||
155 | .setdcbx = fm10k_dcbnl_setdcbx, | ||
156 | }; | ||
157 | |||
158 | #endif /* CONFIG_DCB */ | ||
159 | /** | ||
160 | * fm10k_dcbnl_set_ops - Configures dcbnl ops pointer for netdev | ||
161 | * @dev: netdev interface for the device | ||
162 | * | ||
163 | * Enables PF for DCB by assigning DCBNL ops pointer. | ||
164 | **/ | ||
165 | void fm10k_dcbnl_set_ops(struct net_device *dev) | ||
166 | { | ||
167 | #ifdef CONFIG_DCB | ||
168 | struct fm10k_intfc *interface = netdev_priv(dev); | ||
169 | struct fm10k_hw *hw = &interface->hw; | ||
170 | |||
171 | if (hw->mac.type == fm10k_mac_pf) | ||
172 | dev->dcbnl_ops = &fm10k_dcbnl_ops; | ||
173 | #endif /* CONFIG_DCB */ | ||
174 | } | ||
diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_pci.c b/drivers/net/ethernet/intel/fm10k/fm10k_pci.c index 7935c1aad6d5..04ca7f2ab385 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_pci.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_pci.c | |||
@@ -649,7 +649,7 @@ static void fm10k_configure_rx_ring(struct fm10k_intfc *interface, | |||
649 | fm10k_write_reg(hw, FM10K_SRRCTL(reg_idx), srrctl); | 649 | fm10k_write_reg(hw, FM10K_SRRCTL(reg_idx), srrctl); |
650 | 650 | ||
651 | /* Enable drop on empty */ | 651 | /* Enable drop on empty */ |
652 | #if defined(HAVE_DCBNL_IEEE) && defined(CONFIG_DCB) | 652 | #ifdef CONFIG_DCB |
653 | if (interface->pfc_en) | 653 | if (interface->pfc_en) |
654 | rx_pause = interface->pfc_en; | 654 | rx_pause = interface->pfc_en; |
655 | #endif | 655 | #endif |
@@ -688,7 +688,7 @@ void fm10k_update_rx_drop_en(struct fm10k_intfc *interface) | |||
688 | u8 rx_pause = interface->rx_pause; | 688 | u8 rx_pause = interface->rx_pause; |
689 | int i; | 689 | int i; |
690 | 690 | ||
691 | #if defined(HAVE_DCBNL_IEEE) && defined(CONFIG_DCB) | 691 | #ifdef CONFIG_DCB |
692 | if (interface->pfc_en) | 692 | if (interface->pfc_en) |
693 | rx_pause = interface->pfc_en; | 693 | rx_pause = interface->pfc_en; |
694 | 694 | ||
@@ -1556,6 +1556,9 @@ static int fm10k_sw_init(struct fm10k_intfc *interface, | |||
1556 | netdev->hw_features &= ~NETIF_F_GSO_UDP_TUNNEL; | 1556 | netdev->hw_features &= ~NETIF_F_GSO_UDP_TUNNEL; |
1557 | } | 1557 | } |
1558 | 1558 | ||
1559 | /* initialize DCBNL interface */ | ||
1560 | fm10k_dcbnl_set_ops(netdev); | ||
1561 | |||
1559 | /* Initialize service timer and service task */ | 1562 | /* Initialize service timer and service task */ |
1560 | set_bit(__FM10K_SERVICE_DISABLE, &interface->state); | 1563 | set_bit(__FM10K_SERVICE_DISABLE, &interface->state); |
1561 | setup_timer(&interface->service_timer, &fm10k_service_timer, | 1564 | setup_timer(&interface->service_timer, &fm10k_service_timer, |