diff options
author | Amir Vadai <amirv@mellanox.com> | 2012-04-04 17:33:26 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-04-05 05:08:04 -0400 |
commit | 564c274c3df07d727fbe23684dc3077a9dd30607 (patch) | |
tree | 32cf7763a8cb6c0035348573e4f09354230bd071 /drivers | |
parent | e5395e92a470769d67369c002a41e59619f5214b (diff) |
net/mlx4_en: DCB QoS support
Set TSA, promised BW and PFC using IEEE 802.1qaz netlink commands.
Signed-off-by: Amir Vadai <amirv@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/ethernet/mellanox/mlx4/Kconfig | 12 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlx4/Makefile | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c | 209 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlx4/en_netdev.c | 5 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlx4/mlx4_en.h | 21 |
5 files changed, 248 insertions, 0 deletions
diff --git a/drivers/net/ethernet/mellanox/mlx4/Kconfig b/drivers/net/ethernet/mellanox/mlx4/Kconfig index 1bb93531f1ba..5f027f95cc84 100644 --- a/drivers/net/ethernet/mellanox/mlx4/Kconfig +++ b/drivers/net/ethernet/mellanox/mlx4/Kconfig | |||
@@ -11,6 +11,18 @@ config MLX4_EN | |||
11 | This driver supports Mellanox Technologies ConnectX Ethernet | 11 | This driver supports Mellanox Technologies ConnectX Ethernet |
12 | devices. | 12 | devices. |
13 | 13 | ||
14 | config MLX4_EN_DCB | ||
15 | bool "Data Center Bridging (DCB) Support" | ||
16 | default y | ||
17 | depends on MLX4_EN && DCB | ||
18 | ---help--- | ||
19 | Say Y here if you want to use Data Center Bridging (DCB) in the | ||
20 | driver. | ||
21 | If set to N, will not be able to configure QoS and ratelimit attributes. | ||
22 | This flag is depended on the kernel's DCB support. | ||
23 | |||
24 | If unsure, set to Y | ||
25 | |||
14 | config MLX4_CORE | 26 | config MLX4_CORE |
15 | tristate | 27 | tristate |
16 | depends on PCI | 28 | depends on PCI |
diff --git a/drivers/net/ethernet/mellanox/mlx4/Makefile b/drivers/net/ethernet/mellanox/mlx4/Makefile index 4a40ab967eeb..293127d28b33 100644 --- a/drivers/net/ethernet/mellanox/mlx4/Makefile +++ b/drivers/net/ethernet/mellanox/mlx4/Makefile | |||
@@ -7,3 +7,4 @@ obj-$(CONFIG_MLX4_EN) += mlx4_en.o | |||
7 | 7 | ||
8 | mlx4_en-y := en_main.o en_tx.o en_rx.o en_ethtool.o en_port.o en_cq.o \ | 8 | mlx4_en-y := en_main.o en_tx.o en_rx.o en_ethtool.o en_port.o en_cq.o \ |
9 | en_resources.o en_netdev.o en_selftest.o | 9 | en_resources.o en_netdev.o en_selftest.o |
10 | mlx4_en-$(CONFIG_MLX4_EN_DCB) += en_dcb_nl.o | ||
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c b/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c new file mode 100644 index 000000000000..6892320adaf7 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c | |||
@@ -0,0 +1,209 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2011 Mellanox Technologies. All rights reserved. | ||
3 | * | ||
4 | * This software is available to you under a choice of one of two | ||
5 | * licenses. You may choose to be licensed under the terms of the GNU | ||
6 | * General Public License (GPL) Version 2, available from the file | ||
7 | * COPYING in the main directory of this source tree, or the | ||
8 | * OpenIB.org BSD license below: | ||
9 | * | ||
10 | * Redistribution and use in source and binary forms, with or | ||
11 | * without modification, are permitted provided that the following | ||
12 | * conditions are met: | ||
13 | * | ||
14 | * - Redistributions of source code must retain the above | ||
15 | * copyright notice, this list of conditions and the following | ||
16 | * disclaimer. | ||
17 | * | ||
18 | * - Redistributions in binary form must reproduce the above | ||
19 | * copyright notice, this list of conditions and the following | ||
20 | * disclaimer in the documentation and/or other materials | ||
21 | * provided with the distribution. | ||
22 | * | ||
23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
24 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
25 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
26 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
27 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
28 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
29 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
30 | * SOFTWARE. | ||
31 | * | ||
32 | */ | ||
33 | |||
34 | #include <linux/dcbnl.h> | ||
35 | |||
36 | #include "mlx4_en.h" | ||
37 | |||
38 | static int mlx4_en_dcbnl_ieee_getets(struct net_device *dev, | ||
39 | struct ieee_ets *ets) | ||
40 | { | ||
41 | struct mlx4_en_priv *priv = netdev_priv(dev); | ||
42 | struct ieee_ets *my_ets = &priv->ets; | ||
43 | |||
44 | /* No IEEE PFC settings available */ | ||
45 | if (!my_ets) | ||
46 | return -EINVAL; | ||
47 | |||
48 | ets->ets_cap = IEEE_8021QAZ_MAX_TCS; | ||
49 | ets->cbs = my_ets->cbs; | ||
50 | memcpy(ets->tc_tx_bw, my_ets->tc_tx_bw, sizeof(ets->tc_tx_bw)); | ||
51 | memcpy(ets->tc_tsa, my_ets->tc_tsa, sizeof(ets->tc_tsa)); | ||
52 | memcpy(ets->prio_tc, my_ets->prio_tc, sizeof(ets->prio_tc)); | ||
53 | |||
54 | return 0; | ||
55 | } | ||
56 | |||
57 | static int mlx4_en_ets_validate(struct mlx4_en_priv *priv, struct ieee_ets *ets) | ||
58 | { | ||
59 | int i; | ||
60 | int total_ets_bw = 0; | ||
61 | int has_ets_tc = 0; | ||
62 | |||
63 | for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { | ||
64 | if (ets->prio_tc[i] > MLX4_EN_NUM_UP) { | ||
65 | en_err(priv, "Bad priority in UP <=> TC mapping. TC: %d, UP: %d\n", | ||
66 | i, ets->prio_tc[i]); | ||
67 | return -EINVAL; | ||
68 | } | ||
69 | |||
70 | switch (ets->tc_tsa[i]) { | ||
71 | case IEEE_8021QAZ_TSA_STRICT: | ||
72 | break; | ||
73 | case IEEE_8021QAZ_TSA_ETS: | ||
74 | has_ets_tc = 1; | ||
75 | total_ets_bw += ets->tc_tx_bw[i]; | ||
76 | break; | ||
77 | default: | ||
78 | en_err(priv, "TC[%d]: Not supported TSA: %d\n", | ||
79 | i, ets->tc_tsa[i]); | ||
80 | return -ENOTSUPP; | ||
81 | } | ||
82 | } | ||
83 | |||
84 | if (has_ets_tc && total_ets_bw != MLX4_EN_BW_MAX) { | ||
85 | en_err(priv, "Bad ETS BW sum: %d. Should be exactly 100%%\n", | ||
86 | total_ets_bw); | ||
87 | return -EINVAL; | ||
88 | } | ||
89 | |||
90 | return 0; | ||
91 | } | ||
92 | |||
93 | static int mlx4_en_config_port_scheduler(struct mlx4_en_priv *priv, | ||
94 | struct ieee_ets *ets, u16 *ratelimit) | ||
95 | { | ||
96 | struct mlx4_en_dev *mdev = priv->mdev; | ||
97 | int num_strict = 0; | ||
98 | int i; | ||
99 | __u8 tc_tx_bw[IEEE_8021QAZ_MAX_TCS] = { 0 }; | ||
100 | __u8 pg[IEEE_8021QAZ_MAX_TCS] = { 0 }; | ||
101 | |||
102 | ets = ets ?: &priv->ets; | ||
103 | |||
104 | /* higher TC means higher priority => lower pg */ | ||
105 | for (i = IEEE_8021QAZ_MAX_TCS - 1; i >= 0; i--) { | ||
106 | switch (ets->tc_tsa[i]) { | ||
107 | case IEEE_8021QAZ_TSA_STRICT: | ||
108 | pg[i] = num_strict++; | ||
109 | tc_tx_bw[i] = MLX4_EN_BW_MAX; | ||
110 | break; | ||
111 | case IEEE_8021QAZ_TSA_ETS: | ||
112 | pg[i] = MLX4_EN_TC_ETS; | ||
113 | tc_tx_bw[i] = ets->tc_tx_bw[i] ?: MLX4_EN_BW_MIN; | ||
114 | break; | ||
115 | } | ||
116 | } | ||
117 | |||
118 | return mlx4_SET_PORT_SCHEDULER(mdev->dev, priv->port, tc_tx_bw, pg, | ||
119 | ratelimit); | ||
120 | } | ||
121 | |||
122 | static int | ||
123 | mlx4_en_dcbnl_ieee_setets(struct net_device *dev, struct ieee_ets *ets) | ||
124 | { | ||
125 | struct mlx4_en_priv *priv = netdev_priv(dev); | ||
126 | struct mlx4_en_dev *mdev = priv->mdev; | ||
127 | int err; | ||
128 | |||
129 | err = mlx4_en_ets_validate(priv, ets); | ||
130 | if (err) | ||
131 | return err; | ||
132 | |||
133 | err = mlx4_SET_PORT_PRIO2TC(mdev->dev, priv->port, ets->prio_tc); | ||
134 | if (err) | ||
135 | return err; | ||
136 | |||
137 | err = mlx4_en_config_port_scheduler(priv, ets, NULL); | ||
138 | if (err) | ||
139 | return err; | ||
140 | |||
141 | memcpy(&priv->ets, ets, sizeof(priv->ets)); | ||
142 | |||
143 | return 0; | ||
144 | } | ||
145 | |||
146 | static int mlx4_en_dcbnl_ieee_getpfc(struct net_device *dev, | ||
147 | struct ieee_pfc *pfc) | ||
148 | { | ||
149 | struct mlx4_en_priv *priv = netdev_priv(dev); | ||
150 | |||
151 | pfc->pfc_cap = IEEE_8021QAZ_MAX_TCS; | ||
152 | pfc->pfc_en = priv->prof->tx_ppp; | ||
153 | |||
154 | return 0; | ||
155 | } | ||
156 | |||
157 | static int mlx4_en_dcbnl_ieee_setpfc(struct net_device *dev, | ||
158 | struct ieee_pfc *pfc) | ||
159 | { | ||
160 | struct mlx4_en_priv *priv = netdev_priv(dev); | ||
161 | struct mlx4_en_dev *mdev = priv->mdev; | ||
162 | int err; | ||
163 | |||
164 | en_dbg(DRV, priv, "cap: 0x%x en: 0x%x mbc: 0x%x delay: %d\n", | ||
165 | pfc->pfc_cap, | ||
166 | pfc->pfc_en, | ||
167 | pfc->mbc, | ||
168 | pfc->delay); | ||
169 | |||
170 | priv->prof->rx_pause = priv->prof->tx_pause = !!pfc->pfc_en; | ||
171 | priv->prof->rx_ppp = priv->prof->tx_ppp = pfc->pfc_en; | ||
172 | |||
173 | err = mlx4_SET_PORT_general(mdev->dev, priv->port, | ||
174 | priv->rx_skb_size + ETH_FCS_LEN, | ||
175 | priv->prof->tx_pause, | ||
176 | priv->prof->tx_ppp, | ||
177 | priv->prof->rx_pause, | ||
178 | priv->prof->rx_ppp); | ||
179 | if (err) | ||
180 | en_err(priv, "Failed setting pause params\n"); | ||
181 | |||
182 | return err; | ||
183 | } | ||
184 | |||
185 | static u8 mlx4_en_dcbnl_getdcbx(struct net_device *dev) | ||
186 | { | ||
187 | return DCB_CAP_DCBX_VER_IEEE; | ||
188 | } | ||
189 | |||
190 | static u8 mlx4_en_dcbnl_setdcbx(struct net_device *dev, u8 mode) | ||
191 | { | ||
192 | if ((mode & DCB_CAP_DCBX_LLD_MANAGED) || | ||
193 | (mode & DCB_CAP_DCBX_VER_CEE) || | ||
194 | !(mode & DCB_CAP_DCBX_VER_IEEE) || | ||
195 | !(mode & DCB_CAP_DCBX_HOST)) | ||
196 | return 1; | ||
197 | |||
198 | return 0; | ||
199 | } | ||
200 | |||
201 | const struct dcbnl_rtnl_ops mlx4_en_dcbnl_ops = { | ||
202 | .ieee_getets = mlx4_en_dcbnl_ieee_getets, | ||
203 | .ieee_setets = mlx4_en_dcbnl_ieee_setets, | ||
204 | .ieee_getpfc = mlx4_en_dcbnl_ieee_getpfc, | ||
205 | .ieee_setpfc = mlx4_en_dcbnl_ieee_setpfc, | ||
206 | |||
207 | .getdcbx = mlx4_en_dcbnl_getdcbx, | ||
208 | .setdcbx = mlx4_en_dcbnl_setdcbx, | ||
209 | }; | ||
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index 2322622b6098..107f00553bd3 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c | |||
@@ -967,6 +967,7 @@ void mlx4_en_destroy_netdev(struct net_device *dev) | |||
967 | mutex_unlock(&mdev->state_lock); | 967 | mutex_unlock(&mdev->state_lock); |
968 | 968 | ||
969 | mlx4_en_free_resources(priv); | 969 | mlx4_en_free_resources(priv); |
970 | |||
970 | free_netdev(dev); | 971 | free_netdev(dev); |
971 | } | 972 | } |
972 | 973 | ||
@@ -1080,6 +1081,10 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, | |||
1080 | INIT_WORK(&priv->watchdog_task, mlx4_en_restart); | 1081 | INIT_WORK(&priv->watchdog_task, mlx4_en_restart); |
1081 | INIT_WORK(&priv->linkstate_task, mlx4_en_linkstate); | 1082 | INIT_WORK(&priv->linkstate_task, mlx4_en_linkstate); |
1082 | INIT_DELAYED_WORK(&priv->stats_task, mlx4_en_do_get_stats); | 1083 | INIT_DELAYED_WORK(&priv->stats_task, mlx4_en_do_get_stats); |
1084 | #ifdef CONFIG_MLX4_EN_DCB | ||
1085 | if (!mlx4_is_slave(priv->mdev->dev)) | ||
1086 | dev->dcbnl_ops = &mlx4_en_dcbnl_ops; | ||
1087 | #endif | ||
1083 | 1088 | ||
1084 | /* Query for default mac and max mtu */ | 1089 | /* Query for default mac and max mtu */ |
1085 | priv->max_mtu = mdev->dev->caps.eth_mtu_cap[priv->port]; | 1090 | priv->max_mtu = mdev->dev->caps.eth_mtu_cap[priv->port]; |
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h index 5bd7c2a3823e..97d4f3540f6e 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h | |||
@@ -40,6 +40,9 @@ | |||
40 | #include <linux/mutex.h> | 40 | #include <linux/mutex.h> |
41 | #include <linux/netdevice.h> | 41 | #include <linux/netdevice.h> |
42 | #include <linux/if_vlan.h> | 42 | #include <linux/if_vlan.h> |
43 | #ifdef CONFIG_MLX4_EN_DCB | ||
44 | #include <linux/dcbnl.h> | ||
45 | #endif | ||
43 | 46 | ||
44 | #include <linux/mlx4/device.h> | 47 | #include <linux/mlx4/device.h> |
45 | #include <linux/mlx4/qp.h> | 48 | #include <linux/mlx4/qp.h> |
@@ -110,6 +113,7 @@ enum { | |||
110 | #define MLX4_EN_NUM_TX_RINGS 8 | 113 | #define MLX4_EN_NUM_TX_RINGS 8 |
111 | #define MLX4_EN_NUM_PPP_RINGS 8 | 114 | #define MLX4_EN_NUM_PPP_RINGS 8 |
112 | #define MAX_TX_RINGS (MLX4_EN_NUM_TX_RINGS + MLX4_EN_NUM_PPP_RINGS) | 115 | #define MAX_TX_RINGS (MLX4_EN_NUM_TX_RINGS + MLX4_EN_NUM_PPP_RINGS) |
116 | #define MLX4_EN_NUM_UP 8 | ||
113 | #define MLX4_EN_DEF_TX_RING_SIZE 512 | 117 | #define MLX4_EN_DEF_TX_RING_SIZE 512 |
114 | #define MLX4_EN_DEF_RX_RING_SIZE 1024 | 118 | #define MLX4_EN_DEF_RX_RING_SIZE 1024 |
115 | 119 | ||
@@ -410,6 +414,15 @@ struct mlx4_en_frag_info { | |||
410 | 414 | ||
411 | }; | 415 | }; |
412 | 416 | ||
417 | #ifdef CONFIG_MLX4_EN_DCB | ||
418 | /* Minimal TC BW - setting to 0 will block traffic */ | ||
419 | #define MLX4_EN_BW_MIN 1 | ||
420 | #define MLX4_EN_BW_MAX 100 /* Utilize 100% of the line */ | ||
421 | |||
422 | #define MLX4_EN_TC_ETS 7 | ||
423 | |||
424 | #endif | ||
425 | |||
413 | struct mlx4_en_priv { | 426 | struct mlx4_en_priv { |
414 | struct mlx4_en_dev *mdev; | 427 | struct mlx4_en_dev *mdev; |
415 | struct mlx4_en_port_profile *prof; | 428 | struct mlx4_en_port_profile *prof; |
@@ -483,6 +496,10 @@ struct mlx4_en_priv { | |||
483 | int vids[128]; | 496 | int vids[128]; |
484 | bool wol; | 497 | bool wol; |
485 | struct device *ddev; | 498 | struct device *ddev; |
499 | |||
500 | #ifdef CONFIG_MLX4_EN_DCB | ||
501 | struct ieee_ets ets; | ||
502 | #endif | ||
486 | }; | 503 | }; |
487 | 504 | ||
488 | enum mlx4_en_wol { | 505 | enum mlx4_en_wol { |
@@ -557,6 +574,10 @@ int mlx4_SET_VLAN_FLTR(struct mlx4_dev *dev, struct mlx4_en_priv *priv); | |||
557 | int mlx4_en_DUMP_ETH_STATS(struct mlx4_en_dev *mdev, u8 port, u8 reset); | 574 | int mlx4_en_DUMP_ETH_STATS(struct mlx4_en_dev *mdev, u8 port, u8 reset); |
558 | int mlx4_en_QUERY_PORT(struct mlx4_en_dev *mdev, u8 port); | 575 | int mlx4_en_QUERY_PORT(struct mlx4_en_dev *mdev, u8 port); |
559 | 576 | ||
577 | #ifdef CONFIG_MLX4_EN_DCB | ||
578 | extern const struct dcbnl_rtnl_ops mlx4_en_dcbnl_ops; | ||
579 | #endif | ||
580 | |||
560 | #define MLX4_EN_NUM_SELF_TEST 5 | 581 | #define MLX4_EN_NUM_SELF_TEST 5 |
561 | void mlx4_en_ex_selftest(struct net_device *dev, u32 *flags, u64 *buf); | 582 | void mlx4_en_ex_selftest(struct net_device *dev, u32 *flags, u64 *buf); |
562 | u64 mlx4_en_mac_to_u64(u8 *addr); | 583 | u64 mlx4_en_mac_to_u64(u8 *addr); |