diff options
Diffstat (limited to 'drivers/net/mlx4')
-rw-r--r-- | drivers/net/mlx4/Makefile | 2 | ||||
-rw-r--r-- | drivers/net/mlx4/alloc.c | 17 | ||||
-rw-r--r-- | drivers/net/mlx4/en_ethtool.c | 173 | ||||
-rw-r--r-- | drivers/net/mlx4/en_main.c | 24 | ||||
-rw-r--r-- | drivers/net/mlx4/en_netdev.c | 28 | ||||
-rw-r--r-- | drivers/net/mlx4/en_port.c | 32 | ||||
-rw-r--r-- | drivers/net/mlx4/en_port.h | 14 | ||||
-rw-r--r-- | drivers/net/mlx4/en_rx.c | 104 | ||||
-rw-r--r-- | drivers/net/mlx4/en_selftest.c | 179 | ||||
-rw-r--r-- | drivers/net/mlx4/en_tx.c | 20 | ||||
-rw-r--r-- | drivers/net/mlx4/eq.c | 44 | ||||
-rw-r--r-- | drivers/net/mlx4/fw.c | 15 | ||||
-rw-r--r-- | drivers/net/mlx4/fw.h | 6 | ||||
-rw-r--r-- | drivers/net/mlx4/main.c | 6 | ||||
-rw-r--r-- | drivers/net/mlx4/mlx4_en.h | 39 | ||||
-rw-r--r-- | drivers/net/mlx4/profile.c | 2 |
16 files changed, 510 insertions, 195 deletions
diff --git a/drivers/net/mlx4/Makefile b/drivers/net/mlx4/Makefile index 1fd068e1d930..d1aa45a15854 100644 --- a/drivers/net/mlx4/Makefile +++ b/drivers/net/mlx4/Makefile | |||
@@ -6,4 +6,4 @@ mlx4_core-y := alloc.o catas.o cmd.o cq.o eq.o fw.o icm.o intf.o main.o mcg.o \ | |||
6 | obj-$(CONFIG_MLX4_EN) += mlx4_en.o | 6 | 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 | 9 | en_resources.o en_netdev.o en_selftest.o |
diff --git a/drivers/net/mlx4/alloc.c b/drivers/net/mlx4/alloc.c index 8c8515619b8e..8f4bf1f07c11 100644 --- a/drivers/net/mlx4/alloc.c +++ b/drivers/net/mlx4/alloc.c | |||
@@ -74,7 +74,7 @@ void mlx4_bitmap_free(struct mlx4_bitmap *bitmap, u32 obj) | |||
74 | 74 | ||
75 | u32 mlx4_bitmap_alloc_range(struct mlx4_bitmap *bitmap, int cnt, int align) | 75 | u32 mlx4_bitmap_alloc_range(struct mlx4_bitmap *bitmap, int cnt, int align) |
76 | { | 76 | { |
77 | u32 obj, i; | 77 | u32 obj; |
78 | 78 | ||
79 | if (likely(cnt == 1 && align == 1)) | 79 | if (likely(cnt == 1 && align == 1)) |
80 | return mlx4_bitmap_alloc(bitmap); | 80 | return mlx4_bitmap_alloc(bitmap); |
@@ -91,8 +91,7 @@ u32 mlx4_bitmap_alloc_range(struct mlx4_bitmap *bitmap, int cnt, int align) | |||
91 | } | 91 | } |
92 | 92 | ||
93 | if (obj < bitmap->max) { | 93 | if (obj < bitmap->max) { |
94 | for (i = 0; i < cnt; i++) | 94 | bitmap_set(bitmap->table, obj, cnt); |
95 | set_bit(obj + i, bitmap->table); | ||
96 | if (obj == bitmap->last) { | 95 | if (obj == bitmap->last) { |
97 | bitmap->last = (obj + cnt); | 96 | bitmap->last = (obj + cnt); |
98 | if (bitmap->last >= bitmap->max) | 97 | if (bitmap->last >= bitmap->max) |
@@ -109,13 +108,10 @@ u32 mlx4_bitmap_alloc_range(struct mlx4_bitmap *bitmap, int cnt, int align) | |||
109 | 108 | ||
110 | void mlx4_bitmap_free_range(struct mlx4_bitmap *bitmap, u32 obj, int cnt) | 109 | void mlx4_bitmap_free_range(struct mlx4_bitmap *bitmap, u32 obj, int cnt) |
111 | { | 110 | { |
112 | u32 i; | ||
113 | |||
114 | obj &= bitmap->max + bitmap->reserved_top - 1; | 111 | obj &= bitmap->max + bitmap->reserved_top - 1; |
115 | 112 | ||
116 | spin_lock(&bitmap->lock); | 113 | spin_lock(&bitmap->lock); |
117 | for (i = 0; i < cnt; i++) | 114 | bitmap_clear(bitmap->table, obj, cnt); |
118 | clear_bit(obj + i, bitmap->table); | ||
119 | bitmap->last = min(bitmap->last, obj); | 115 | bitmap->last = min(bitmap->last, obj); |
120 | bitmap->top = (bitmap->top + bitmap->max + bitmap->reserved_top) | 116 | bitmap->top = (bitmap->top + bitmap->max + bitmap->reserved_top) |
121 | & bitmap->mask; | 117 | & bitmap->mask; |
@@ -125,8 +121,6 @@ void mlx4_bitmap_free_range(struct mlx4_bitmap *bitmap, u32 obj, int cnt) | |||
125 | int mlx4_bitmap_init(struct mlx4_bitmap *bitmap, u32 num, u32 mask, | 121 | int mlx4_bitmap_init(struct mlx4_bitmap *bitmap, u32 num, u32 mask, |
126 | u32 reserved_bot, u32 reserved_top) | 122 | u32 reserved_bot, u32 reserved_top) |
127 | { | 123 | { |
128 | int i; | ||
129 | |||
130 | /* num must be a power of 2 */ | 124 | /* num must be a power of 2 */ |
131 | if (num != roundup_pow_of_two(num)) | 125 | if (num != roundup_pow_of_two(num)) |
132 | return -EINVAL; | 126 | return -EINVAL; |
@@ -142,8 +136,7 @@ int mlx4_bitmap_init(struct mlx4_bitmap *bitmap, u32 num, u32 mask, | |||
142 | if (!bitmap->table) | 136 | if (!bitmap->table) |
143 | return -ENOMEM; | 137 | return -ENOMEM; |
144 | 138 | ||
145 | for (i = 0; i < reserved_bot; ++i) | 139 | bitmap_set(bitmap->table, 0, reserved_bot); |
146 | set_bit(i, bitmap->table); | ||
147 | 140 | ||
148 | return 0; | 141 | return 0; |
149 | } | 142 | } |
@@ -188,7 +181,7 @@ int mlx4_buf_alloc(struct mlx4_dev *dev, int size, int max_direct, | |||
188 | buf->nbufs = (size + PAGE_SIZE - 1) / PAGE_SIZE; | 181 | buf->nbufs = (size + PAGE_SIZE - 1) / PAGE_SIZE; |
189 | buf->npages = buf->nbufs; | 182 | buf->npages = buf->nbufs; |
190 | buf->page_shift = PAGE_SHIFT; | 183 | buf->page_shift = PAGE_SHIFT; |
191 | buf->page_list = kzalloc(buf->nbufs * sizeof *buf->page_list, | 184 | buf->page_list = kcalloc(buf->nbufs, sizeof(*buf->page_list), |
192 | GFP_KERNEL); | 185 | GFP_KERNEL); |
193 | if (!buf->page_list) | 186 | if (!buf->page_list) |
194 | return -ENOMEM; | 187 | return -ENOMEM; |
diff --git a/drivers/net/mlx4/en_ethtool.c b/drivers/net/mlx4/en_ethtool.c index b275238fe70d..056152b3ff58 100644 --- a/drivers/net/mlx4/en_ethtool.c +++ b/drivers/net/mlx4/en_ethtool.c | |||
@@ -39,21 +39,6 @@ | |||
39 | #include "en_port.h" | 39 | #include "en_port.h" |
40 | 40 | ||
41 | 41 | ||
42 | static void mlx4_en_update_lro_stats(struct mlx4_en_priv *priv) | ||
43 | { | ||
44 | int i; | ||
45 | |||
46 | priv->port_stats.lro_aggregated = 0; | ||
47 | priv->port_stats.lro_flushed = 0; | ||
48 | priv->port_stats.lro_no_desc = 0; | ||
49 | |||
50 | for (i = 0; i < priv->rx_ring_num; i++) { | ||
51 | priv->port_stats.lro_aggregated += priv->rx_ring[i].lro.stats.aggregated; | ||
52 | priv->port_stats.lro_flushed += priv->rx_ring[i].lro.stats.flushed; | ||
53 | priv->port_stats.lro_no_desc += priv->rx_ring[i].lro.stats.no_desc; | ||
54 | } | ||
55 | } | ||
56 | |||
57 | static void | 42 | static void |
58 | mlx4_en_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo) | 43 | mlx4_en_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo) |
59 | { | 44 | { |
@@ -112,7 +97,7 @@ static const char main_strings[][ETH_GSTRING_LEN] = { | |||
112 | "tx_heartbeat_errors", "tx_window_errors", | 97 | "tx_heartbeat_errors", "tx_window_errors", |
113 | 98 | ||
114 | /* port statistics */ | 99 | /* port statistics */ |
115 | "lro_aggregated", "lro_flushed", "lro_no_desc", "tso_packets", | 100 | "tso_packets", |
116 | "queue_stopped", "wake_queue", "tx_timeout", "rx_alloc_failed", | 101 | "queue_stopped", "wake_queue", "tx_timeout", "rx_alloc_failed", |
117 | "rx_csum_good", "rx_csum_none", "tx_chksum_offload", | 102 | "rx_csum_good", "rx_csum_none", "tx_chksum_offload", |
118 | 103 | ||
@@ -125,6 +110,14 @@ static const char main_strings[][ETH_GSTRING_LEN] = { | |||
125 | #define NUM_MAIN_STATS 21 | 110 | #define NUM_MAIN_STATS 21 |
126 | #define NUM_ALL_STATS (NUM_MAIN_STATS + NUM_PORT_STATS + NUM_PKT_STATS + NUM_PERF_STATS) | 111 | #define NUM_ALL_STATS (NUM_MAIN_STATS + NUM_PORT_STATS + NUM_PKT_STATS + NUM_PERF_STATS) |
127 | 112 | ||
113 | static const char mlx4_en_test_names[][ETH_GSTRING_LEN]= { | ||
114 | "Interupt Test", | ||
115 | "Link Test", | ||
116 | "Speed Test", | ||
117 | "Register Test", | ||
118 | "Loopback Test", | ||
119 | }; | ||
120 | |||
128 | static u32 mlx4_en_get_msglevel(struct net_device *dev) | 121 | static u32 mlx4_en_get_msglevel(struct net_device *dev) |
129 | { | 122 | { |
130 | return ((struct mlx4_en_priv *) netdev_priv(dev))->msg_enable; | 123 | return ((struct mlx4_en_priv *) netdev_priv(dev))->msg_enable; |
@@ -146,10 +139,15 @@ static int mlx4_en_get_sset_count(struct net_device *dev, int sset) | |||
146 | { | 139 | { |
147 | struct mlx4_en_priv *priv = netdev_priv(dev); | 140 | struct mlx4_en_priv *priv = netdev_priv(dev); |
148 | 141 | ||
149 | if (sset != ETH_SS_STATS) | 142 | switch (sset) { |
143 | case ETH_SS_STATS: | ||
144 | return NUM_ALL_STATS + | ||
145 | (priv->tx_ring_num + priv->rx_ring_num) * 2; | ||
146 | case ETH_SS_TEST: | ||
147 | return MLX4_EN_NUM_SELF_TEST - !(priv->mdev->dev->caps.loopback_support) * 2; | ||
148 | default: | ||
150 | return -EOPNOTSUPP; | 149 | return -EOPNOTSUPP; |
151 | 150 | } | |
152 | return NUM_ALL_STATS + (priv->tx_ring_num + priv->rx_ring_num) * 2; | ||
153 | } | 151 | } |
154 | 152 | ||
155 | static void mlx4_en_get_ethtool_stats(struct net_device *dev, | 153 | static void mlx4_en_get_ethtool_stats(struct net_device *dev, |
@@ -161,8 +159,6 @@ static void mlx4_en_get_ethtool_stats(struct net_device *dev, | |||
161 | 159 | ||
162 | spin_lock_bh(&priv->stats_lock); | 160 | spin_lock_bh(&priv->stats_lock); |
163 | 161 | ||
164 | mlx4_en_update_lro_stats(priv); | ||
165 | |||
166 | for (i = 0; i < NUM_MAIN_STATS; i++) | 162 | for (i = 0; i < NUM_MAIN_STATS; i++) |
167 | data[index++] = ((unsigned long *) &priv->stats)[i]; | 163 | data[index++] = ((unsigned long *) &priv->stats)[i]; |
168 | for (i = 0; i < NUM_PORT_STATS; i++) | 164 | for (i = 0; i < NUM_PORT_STATS; i++) |
@@ -181,6 +177,12 @@ static void mlx4_en_get_ethtool_stats(struct net_device *dev, | |||
181 | 177 | ||
182 | } | 178 | } |
183 | 179 | ||
180 | static void mlx4_en_self_test(struct net_device *dev, | ||
181 | struct ethtool_test *etest, u64 *buf) | ||
182 | { | ||
183 | mlx4_en_ex_selftest(dev, &etest->flags, buf); | ||
184 | } | ||
185 | |||
184 | static void mlx4_en_get_strings(struct net_device *dev, | 186 | static void mlx4_en_get_strings(struct net_device *dev, |
185 | uint32_t stringset, uint8_t *data) | 187 | uint32_t stringset, uint8_t *data) |
186 | { | 188 | { |
@@ -188,44 +190,76 @@ static void mlx4_en_get_strings(struct net_device *dev, | |||
188 | int index = 0; | 190 | int index = 0; |
189 | int i; | 191 | int i; |
190 | 192 | ||
191 | if (stringset != ETH_SS_STATS) | 193 | switch (stringset) { |
192 | return; | 194 | case ETH_SS_TEST: |
193 | 195 | for (i = 0; i < MLX4_EN_NUM_SELF_TEST - 2; i++) | |
194 | /* Add main counters */ | 196 | strcpy(data + i * ETH_GSTRING_LEN, mlx4_en_test_names[i]); |
195 | for (i = 0; i < NUM_MAIN_STATS; i++) | 197 | if (priv->mdev->dev->caps.loopback_support) |
196 | strcpy(data + (index++) * ETH_GSTRING_LEN, main_strings[i]); | 198 | for (; i < MLX4_EN_NUM_SELF_TEST; i++) |
197 | for (i = 0; i < NUM_PORT_STATS; i++) | 199 | strcpy(data + i * ETH_GSTRING_LEN, mlx4_en_test_names[i]); |
198 | strcpy(data + (index++) * ETH_GSTRING_LEN, | 200 | break; |
201 | |||
202 | case ETH_SS_STATS: | ||
203 | /* Add main counters */ | ||
204 | for (i = 0; i < NUM_MAIN_STATS; i++) | ||
205 | strcpy(data + (index++) * ETH_GSTRING_LEN, main_strings[i]); | ||
206 | for (i = 0; i< NUM_PORT_STATS; i++) | ||
207 | strcpy(data + (index++) * ETH_GSTRING_LEN, | ||
199 | main_strings[i + NUM_MAIN_STATS]); | 208 | main_strings[i + NUM_MAIN_STATS]); |
200 | for (i = 0; i < priv->tx_ring_num; i++) { | 209 | for (i = 0; i < priv->tx_ring_num; i++) { |
201 | sprintf(data + (index++) * ETH_GSTRING_LEN, | 210 | sprintf(data + (index++) * ETH_GSTRING_LEN, |
202 | "tx%d_packets", i); | 211 | "tx%d_packets", i); |
203 | sprintf(data + (index++) * ETH_GSTRING_LEN, | 212 | sprintf(data + (index++) * ETH_GSTRING_LEN, |
204 | "tx%d_bytes", i); | 213 | "tx%d_bytes", i); |
205 | } | 214 | } |
206 | for (i = 0; i < priv->rx_ring_num; i++) { | 215 | for (i = 0; i < priv->rx_ring_num; i++) { |
207 | sprintf(data + (index++) * ETH_GSTRING_LEN, | 216 | sprintf(data + (index++) * ETH_GSTRING_LEN, |
208 | "rx%d_packets", i); | 217 | "rx%d_packets", i); |
209 | sprintf(data + (index++) * ETH_GSTRING_LEN, | 218 | sprintf(data + (index++) * ETH_GSTRING_LEN, |
210 | "rx%d_bytes", i); | 219 | "rx%d_bytes", i); |
211 | } | 220 | } |
212 | for (i = 0; i < NUM_PKT_STATS; i++) | 221 | for (i = 0; i< NUM_PKT_STATS; i++) |
213 | strcpy(data + (index++) * ETH_GSTRING_LEN, | 222 | strcpy(data + (index++) * ETH_GSTRING_LEN, |
214 | main_strings[i + NUM_MAIN_STATS + NUM_PORT_STATS]); | 223 | main_strings[i + NUM_MAIN_STATS + NUM_PORT_STATS]); |
224 | break; | ||
225 | } | ||
215 | } | 226 | } |
216 | 227 | ||
217 | static int mlx4_en_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) | 228 | static int mlx4_en_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) |
218 | { | 229 | { |
230 | struct mlx4_en_priv *priv = netdev_priv(dev); | ||
231 | int trans_type; | ||
232 | |||
219 | cmd->autoneg = AUTONEG_DISABLE; | 233 | cmd->autoneg = AUTONEG_DISABLE; |
220 | cmd->supported = SUPPORTED_10000baseT_Full; | 234 | cmd->supported = SUPPORTED_10000baseT_Full; |
221 | cmd->advertising = ADVERTISED_1000baseT_Full; | 235 | cmd->advertising = ADVERTISED_10000baseT_Full; |
236 | |||
237 | if (mlx4_en_QUERY_PORT(priv->mdev, priv->port)) | ||
238 | return -ENOMEM; | ||
239 | |||
240 | trans_type = priv->port_state.transciver; | ||
222 | if (netif_carrier_ok(dev)) { | 241 | if (netif_carrier_ok(dev)) { |
223 | cmd->speed = SPEED_10000; | 242 | cmd->speed = priv->port_state.link_speed; |
224 | cmd->duplex = DUPLEX_FULL; | 243 | cmd->duplex = DUPLEX_FULL; |
225 | } else { | 244 | } else { |
226 | cmd->speed = -1; | 245 | cmd->speed = -1; |
227 | cmd->duplex = -1; | 246 | cmd->duplex = -1; |
228 | } | 247 | } |
248 | |||
249 | if (trans_type > 0 && trans_type <= 0xC) { | ||
250 | cmd->port = PORT_FIBRE; | ||
251 | cmd->transceiver = XCVR_EXTERNAL; | ||
252 | cmd->supported |= SUPPORTED_FIBRE; | ||
253 | cmd->advertising |= ADVERTISED_FIBRE; | ||
254 | } else if (trans_type == 0x80 || trans_type == 0) { | ||
255 | cmd->port = PORT_TP; | ||
256 | cmd->transceiver = XCVR_INTERNAL; | ||
257 | cmd->supported |= SUPPORTED_TP; | ||
258 | cmd->advertising |= ADVERTISED_TP; | ||
259 | } else { | ||
260 | cmd->port = -1; | ||
261 | cmd->transceiver = -1; | ||
262 | } | ||
229 | return 0; | 263 | return 0; |
230 | } | 264 | } |
231 | 265 | ||
@@ -343,8 +377,9 @@ static int mlx4_en_set_ringparam(struct net_device *dev, | |||
343 | tx_size = max_t(u32, tx_size, MLX4_EN_MIN_TX_SIZE); | 377 | tx_size = max_t(u32, tx_size, MLX4_EN_MIN_TX_SIZE); |
344 | tx_size = min_t(u32, tx_size, MLX4_EN_MAX_TX_SIZE); | 378 | tx_size = min_t(u32, tx_size, MLX4_EN_MAX_TX_SIZE); |
345 | 379 | ||
346 | if (rx_size == priv->prof->rx_ring_size && | 380 | if (rx_size == (priv->port_up ? priv->rx_ring[0].actual_size : |
347 | tx_size == priv->prof->tx_ring_size) | 381 | priv->rx_ring[0].size) && |
382 | tx_size == priv->tx_ring[0].size) | ||
348 | return 0; | 383 | return 0; |
349 | 384 | ||
350 | mutex_lock(&mdev->state_lock); | 385 | mutex_lock(&mdev->state_lock); |
@@ -378,49 +413,13 @@ static void mlx4_en_get_ringparam(struct net_device *dev, | |||
378 | struct ethtool_ringparam *param) | 413 | struct ethtool_ringparam *param) |
379 | { | 414 | { |
380 | struct mlx4_en_priv *priv = netdev_priv(dev); | 415 | struct mlx4_en_priv *priv = netdev_priv(dev); |
381 | struct mlx4_en_dev *mdev = priv->mdev; | ||
382 | 416 | ||
383 | memset(param, 0, sizeof(*param)); | 417 | memset(param, 0, sizeof(*param)); |
384 | param->rx_max_pending = MLX4_EN_MAX_RX_SIZE; | 418 | param->rx_max_pending = MLX4_EN_MAX_RX_SIZE; |
385 | param->tx_max_pending = MLX4_EN_MAX_TX_SIZE; | 419 | param->tx_max_pending = MLX4_EN_MAX_TX_SIZE; |
386 | param->rx_pending = mdev->profile.prof[priv->port].rx_ring_size; | 420 | param->rx_pending = priv->port_up ? |
387 | param->tx_pending = mdev->profile.prof[priv->port].tx_ring_size; | 421 | priv->rx_ring[0].actual_size : priv->rx_ring[0].size; |
388 | } | 422 | param->tx_pending = priv->tx_ring[0].size; |
389 | |||
390 | static int mlx4_ethtool_op_set_flags(struct net_device *dev, u32 data) | ||
391 | { | ||
392 | struct mlx4_en_priv *priv = netdev_priv(dev); | ||
393 | struct mlx4_en_dev *mdev = priv->mdev; | ||
394 | int rc = 0; | ||
395 | int changed = 0; | ||
396 | |||
397 | if (data & ~ETH_FLAG_LRO) | ||
398 | return -EOPNOTSUPP; | ||
399 | |||
400 | if (data & ETH_FLAG_LRO) { | ||
401 | if (mdev->profile.num_lro == 0) | ||
402 | return -EOPNOTSUPP; | ||
403 | if (!(dev->features & NETIF_F_LRO)) | ||
404 | changed = 1; | ||
405 | } else if (dev->features & NETIF_F_LRO) { | ||
406 | changed = 1; | ||
407 | } | ||
408 | |||
409 | if (changed) { | ||
410 | if (netif_running(dev)) { | ||
411 | mutex_lock(&mdev->state_lock); | ||
412 | mlx4_en_stop_port(dev); | ||
413 | } | ||
414 | dev->features ^= NETIF_F_LRO; | ||
415 | if (netif_running(dev)) { | ||
416 | rc = mlx4_en_start_port(dev); | ||
417 | if (rc) | ||
418 | en_err(priv, "Failed to restart port\n"); | ||
419 | mutex_unlock(&mdev->state_lock); | ||
420 | } | ||
421 | } | ||
422 | |||
423 | return rc; | ||
424 | } | 423 | } |
425 | 424 | ||
426 | const struct ethtool_ops mlx4_en_ethtool_ops = { | 425 | const struct ethtool_ops mlx4_en_ethtool_ops = { |
@@ -441,6 +440,7 @@ const struct ethtool_ops mlx4_en_ethtool_ops = { | |||
441 | .get_strings = mlx4_en_get_strings, | 440 | .get_strings = mlx4_en_get_strings, |
442 | .get_sset_count = mlx4_en_get_sset_count, | 441 | .get_sset_count = mlx4_en_get_sset_count, |
443 | .get_ethtool_stats = mlx4_en_get_ethtool_stats, | 442 | .get_ethtool_stats = mlx4_en_get_ethtool_stats, |
443 | .self_test = mlx4_en_self_test, | ||
444 | .get_wol = mlx4_en_get_wol, | 444 | .get_wol = mlx4_en_get_wol, |
445 | .get_msglevel = mlx4_en_get_msglevel, | 445 | .get_msglevel = mlx4_en_get_msglevel, |
446 | .set_msglevel = mlx4_en_set_msglevel, | 446 | .set_msglevel = mlx4_en_set_msglevel, |
@@ -451,7 +451,6 @@ const struct ethtool_ops mlx4_en_ethtool_ops = { | |||
451 | .get_ringparam = mlx4_en_get_ringparam, | 451 | .get_ringparam = mlx4_en_get_ringparam, |
452 | .set_ringparam = mlx4_en_set_ringparam, | 452 | .set_ringparam = mlx4_en_set_ringparam, |
453 | .get_flags = ethtool_op_get_flags, | 453 | .get_flags = ethtool_op_get_flags, |
454 | .set_flags = mlx4_ethtool_op_set_flags, | ||
455 | }; | 454 | }; |
456 | 455 | ||
457 | 456 | ||
diff --git a/drivers/net/mlx4/en_main.c b/drivers/net/mlx4/en_main.c index 97934f1ec53a..143906417048 100644 --- a/drivers/net/mlx4/en_main.c +++ b/drivers/net/mlx4/en_main.c | |||
@@ -63,15 +63,12 @@ static const char mlx4_en_version[] = | |||
63 | */ | 63 | */ |
64 | 64 | ||
65 | 65 | ||
66 | /* Use a XOR rathern than Toeplitz hash function for RSS */ | 66 | /* Enable RSS TCP traffic */ |
67 | MLX4_EN_PARM_INT(rss_xor, 0, "Use XOR hash function for RSS"); | 67 | MLX4_EN_PARM_INT(tcp_rss, 1, |
68 | 68 | "Enable RSS for incomming TCP traffic or disabled (0)"); | |
69 | /* RSS hash type mask - default to <saddr, daddr, sport, dport> */ | 69 | /* Enable RSS UDP traffic */ |
70 | MLX4_EN_PARM_INT(rss_mask, 0xf, "RSS hash type bitmask"); | 70 | MLX4_EN_PARM_INT(udp_rss, 1, |
71 | 71 | "Enable RSS for incomming UDP traffic or disabled (0)"); | |
72 | /* Number of LRO sessions per Rx ring (rounded up to a power of two) */ | ||
73 | MLX4_EN_PARM_INT(num_lro, MLX4_EN_MAX_LRO_DESCRIPTORS, | ||
74 | "Number of LRO sessions per ring or disabled (0)"); | ||
75 | 72 | ||
76 | /* Priority pausing */ | 73 | /* Priority pausing */ |
77 | MLX4_EN_PARM_INT(pfctx, 0, "Priority based Flow Control policy on TX[7:0]." | 74 | MLX4_EN_PARM_INT(pfctx, 0, "Priority based Flow Control policy on TX[7:0]." |
@@ -107,9 +104,12 @@ static int mlx4_en_get_profile(struct mlx4_en_dev *mdev) | |||
107 | struct mlx4_en_profile *params = &mdev->profile; | 104 | struct mlx4_en_profile *params = &mdev->profile; |
108 | int i; | 105 | int i; |
109 | 106 | ||
110 | params->rss_xor = (rss_xor != 0); | 107 | params->tcp_rss = tcp_rss; |
111 | params->rss_mask = rss_mask & 0x1f; | 108 | params->udp_rss = udp_rss; |
112 | params->num_lro = min_t(int, num_lro , MLX4_EN_MAX_LRO_DESCRIPTORS); | 109 | if (params->udp_rss && !mdev->dev->caps.udp_rss) { |
110 | mlx4_warn(mdev, "UDP RSS is not supported on this device.\n"); | ||
111 | params->udp_rss = 0; | ||
112 | } | ||
113 | for (i = 1; i <= MLX4_MAX_PORTS; i++) { | 113 | for (i = 1; i <= MLX4_MAX_PORTS; i++) { |
114 | params->prof[i].rx_pause = 1; | 114 | params->prof[i].rx_pause = 1; |
115 | params->prof[i].rx_ppp = pfcrx; | 115 | params->prof[i].rx_ppp = pfcrx; |
diff --git a/drivers/net/mlx4/en_netdev.c b/drivers/net/mlx4/en_netdev.c index a0d8a26f5a02..411bda581c04 100644 --- a/drivers/net/mlx4/en_netdev.c +++ b/drivers/net/mlx4/en_netdev.c | |||
@@ -109,7 +109,7 @@ static void mlx4_en_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) | |||
109 | mutex_unlock(&mdev->state_lock); | 109 | mutex_unlock(&mdev->state_lock); |
110 | } | 110 | } |
111 | 111 | ||
112 | static u64 mlx4_en_mac_to_u64(u8 *addr) | 112 | u64 mlx4_en_mac_to_u64(u8 *addr) |
113 | { | 113 | { |
114 | u64 mac = 0; | 114 | u64 mac = 0; |
115 | int i; | 115 | int i; |
@@ -513,6 +513,10 @@ static void mlx4_en_do_get_stats(struct work_struct *work) | |||
513 | 513 | ||
514 | queue_delayed_work(mdev->workqueue, &priv->stats_task, STATS_DELAY); | 514 | queue_delayed_work(mdev->workqueue, &priv->stats_task, STATS_DELAY); |
515 | } | 515 | } |
516 | if (mdev->mac_removed[MLX4_MAX_PORTS + 1 - priv->port]) { | ||
517 | queue_work(mdev->workqueue, &priv->mac_task); | ||
518 | mdev->mac_removed[MLX4_MAX_PORTS + 1 - priv->port] = 0; | ||
519 | } | ||
516 | mutex_unlock(&mdev->state_lock); | 520 | mutex_unlock(&mdev->state_lock); |
517 | } | 521 | } |
518 | 522 | ||
@@ -528,10 +532,10 @@ static void mlx4_en_linkstate(struct work_struct *work) | |||
528 | * report to system log */ | 532 | * report to system log */ |
529 | if (priv->last_link_state != linkstate) { | 533 | if (priv->last_link_state != linkstate) { |
530 | if (linkstate == MLX4_DEV_EVENT_PORT_DOWN) { | 534 | if (linkstate == MLX4_DEV_EVENT_PORT_DOWN) { |
531 | en_dbg(LINK, priv, "Link Down\n"); | 535 | en_info(priv, "Link Down\n"); |
532 | netif_carrier_off(priv->dev); | 536 | netif_carrier_off(priv->dev); |
533 | } else { | 537 | } else { |
534 | en_dbg(LINK, priv, "Link Up\n"); | 538 | en_info(priv, "Link Up\n"); |
535 | netif_carrier_on(priv->dev); | 539 | netif_carrier_on(priv->dev); |
536 | } | 540 | } |
537 | } | 541 | } |
@@ -653,6 +657,7 @@ int mlx4_en_start_port(struct net_device *dev) | |||
653 | en_err(priv, "Failed setting port mac\n"); | 657 | en_err(priv, "Failed setting port mac\n"); |
654 | goto tx_err; | 658 | goto tx_err; |
655 | } | 659 | } |
660 | mdev->mac_removed[priv->port] = 0; | ||
656 | 661 | ||
657 | /* Init port */ | 662 | /* Init port */ |
658 | en_dbg(HW, priv, "Initializing port\n"); | 663 | en_dbg(HW, priv, "Initializing port\n"); |
@@ -704,12 +709,12 @@ void mlx4_en_stop_port(struct net_device *dev) | |||
704 | netif_tx_stop_all_queues(dev); | 709 | netif_tx_stop_all_queues(dev); |
705 | netif_tx_unlock_bh(dev); | 710 | netif_tx_unlock_bh(dev); |
706 | 711 | ||
707 | /* close port*/ | 712 | /* Set port as not active */ |
708 | priv->port_up = false; | 713 | priv->port_up = false; |
709 | mlx4_CLOSE_PORT(mdev->dev, priv->port); | ||
710 | 714 | ||
711 | /* Unregister Mac address for the port */ | 715 | /* Unregister Mac address for the port */ |
712 | mlx4_unregister_mac(mdev->dev, priv->port, priv->mac_index); | 716 | mlx4_unregister_mac(mdev->dev, priv->port, priv->mac_index); |
717 | mdev->mac_removed[priv->port] = 1; | ||
713 | 718 | ||
714 | /* Free TX Rings */ | 719 | /* Free TX Rings */ |
715 | for (i = 0; i < priv->tx_ring_num; i++) { | 720 | for (i = 0; i < priv->tx_ring_num; i++) { |
@@ -731,6 +736,9 @@ void mlx4_en_stop_port(struct net_device *dev) | |||
731 | msleep(1); | 736 | msleep(1); |
732 | mlx4_en_deactivate_cq(priv, &priv->rx_cq[i]); | 737 | mlx4_en_deactivate_cq(priv, &priv->rx_cq[i]); |
733 | } | 738 | } |
739 | |||
740 | /* close port*/ | ||
741 | mlx4_CLOSE_PORT(mdev->dev, priv->port); | ||
734 | } | 742 | } |
735 | 743 | ||
736 | static void mlx4_en_restart(struct work_struct *work) | 744 | static void mlx4_en_restart(struct work_struct *work) |
@@ -1023,9 +1031,10 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, | |||
1023 | 1031 | ||
1024 | /* Set defualt MAC */ | 1032 | /* Set defualt MAC */ |
1025 | dev->addr_len = ETH_ALEN; | 1033 | dev->addr_len = ETH_ALEN; |
1026 | for (i = 0; i < ETH_ALEN; i++) | 1034 | for (i = 0; i < ETH_ALEN; i++) { |
1027 | dev->dev_addr[ETH_ALEN - 1 - i] = | 1035 | dev->dev_addr[ETH_ALEN - 1 - i] = (u8) (priv->mac >> (8 * i)); |
1028 | (u8) (priv->mac >> (8 * i)); | 1036 | dev->perm_addr[ETH_ALEN - 1 - i] = (u8) (priv->mac >> (8 * i)); |
1037 | } | ||
1029 | 1038 | ||
1030 | /* | 1039 | /* |
1031 | * Set driver features | 1040 | * Set driver features |
@@ -1038,8 +1047,7 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, | |||
1038 | dev->features |= NETIF_F_HW_VLAN_TX | | 1047 | dev->features |= NETIF_F_HW_VLAN_TX | |
1039 | NETIF_F_HW_VLAN_RX | | 1048 | NETIF_F_HW_VLAN_RX | |
1040 | NETIF_F_HW_VLAN_FILTER; | 1049 | NETIF_F_HW_VLAN_FILTER; |
1041 | if (mdev->profile.num_lro) | 1050 | dev->features |= NETIF_F_GRO; |
1042 | dev->features |= NETIF_F_LRO; | ||
1043 | if (mdev->LSO_support) { | 1051 | if (mdev->LSO_support) { |
1044 | dev->features |= NETIF_F_TSO; | 1052 | dev->features |= NETIF_F_TSO; |
1045 | dev->features |= NETIF_F_TSO6; | 1053 | dev->features |= NETIF_F_TSO6; |
diff --git a/drivers/net/mlx4/en_port.c b/drivers/net/mlx4/en_port.c index a29abe845d2e..aa3ef2aee5bf 100644 --- a/drivers/net/mlx4/en_port.c +++ b/drivers/net/mlx4/en_port.c | |||
@@ -142,6 +142,38 @@ int mlx4_SET_PORT_qpn_calc(struct mlx4_dev *dev, u8 port, u32 base_qpn, | |||
142 | return err; | 142 | return err; |
143 | } | 143 | } |
144 | 144 | ||
145 | int mlx4_en_QUERY_PORT(struct mlx4_en_dev *mdev, u8 port) | ||
146 | { | ||
147 | struct mlx4_en_query_port_context *qport_context; | ||
148 | struct mlx4_en_priv *priv = netdev_priv(mdev->pndev[port]); | ||
149 | struct mlx4_en_port_state *state = &priv->port_state; | ||
150 | struct mlx4_cmd_mailbox *mailbox; | ||
151 | int err; | ||
152 | |||
153 | mailbox = mlx4_alloc_cmd_mailbox(mdev->dev); | ||
154 | if (IS_ERR(mailbox)) | ||
155 | return PTR_ERR(mailbox); | ||
156 | memset(mailbox->buf, 0, sizeof(*qport_context)); | ||
157 | err = mlx4_cmd_box(mdev->dev, 0, mailbox->dma, port, 0, | ||
158 | MLX4_CMD_QUERY_PORT, MLX4_CMD_TIME_CLASS_B); | ||
159 | if (err) | ||
160 | goto out; | ||
161 | qport_context = mailbox->buf; | ||
162 | |||
163 | /* This command is always accessed from Ethtool context | ||
164 | * already synchronized, no need in locking */ | ||
165 | state->link_state = !!(qport_context->link_up & MLX4_EN_LINK_UP_MASK); | ||
166 | if ((qport_context->link_speed & MLX4_EN_SPEED_MASK) == | ||
167 | MLX4_EN_1G_SPEED) | ||
168 | state->link_speed = 1000; | ||
169 | else | ||
170 | state->link_speed = 10000; | ||
171 | state->transciver = qport_context->transceiver; | ||
172 | |||
173 | out: | ||
174 | mlx4_free_cmd_mailbox(mdev->dev, mailbox); | ||
175 | return err; | ||
176 | } | ||
145 | 177 | ||
146 | int mlx4_en_DUMP_ETH_STATS(struct mlx4_en_dev *mdev, u8 port, u8 reset) | 178 | int mlx4_en_DUMP_ETH_STATS(struct mlx4_en_dev *mdev, u8 port, u8 reset) |
147 | { | 179 | { |
diff --git a/drivers/net/mlx4/en_port.h b/drivers/net/mlx4/en_port.h index e6477f12beb5..f6511aa2b7df 100644 --- a/drivers/net/mlx4/en_port.h +++ b/drivers/net/mlx4/en_port.h | |||
@@ -84,6 +84,20 @@ enum { | |||
84 | MLX4_MCAST_ENABLE = 2, | 84 | MLX4_MCAST_ENABLE = 2, |
85 | }; | 85 | }; |
86 | 86 | ||
87 | struct mlx4_en_query_port_context { | ||
88 | u8 link_up; | ||
89 | #define MLX4_EN_LINK_UP_MASK 0x80 | ||
90 | u8 reserved; | ||
91 | __be16 mtu; | ||
92 | u8 reserved2; | ||
93 | u8 link_speed; | ||
94 | #define MLX4_EN_SPEED_MASK 0x3 | ||
95 | #define MLX4_EN_1G_SPEED 0x2 | ||
96 | u16 reserved3[5]; | ||
97 | __be64 mac; | ||
98 | u8 transceiver; | ||
99 | }; | ||
100 | |||
87 | 101 | ||
88 | struct mlx4_en_stat_out_mbox { | 102 | struct mlx4_en_stat_out_mbox { |
89 | /* Received frames with a length of 64 octets */ | 103 | /* Received frames with a length of 64 octets */ |
diff --git a/drivers/net/mlx4/en_rx.c b/drivers/net/mlx4/en_rx.c index 8e2fcb7103c3..570f2508fb30 100644 --- a/drivers/net/mlx4/en_rx.c +++ b/drivers/net/mlx4/en_rx.c | |||
@@ -42,18 +42,6 @@ | |||
42 | #include "mlx4_en.h" | 42 | #include "mlx4_en.h" |
43 | 43 | ||
44 | 44 | ||
45 | static int mlx4_en_get_frag_header(struct skb_frag_struct *frags, void **mac_hdr, | ||
46 | void **ip_hdr, void **tcpudp_hdr, | ||
47 | u64 *hdr_flags, void *priv) | ||
48 | { | ||
49 | *mac_hdr = page_address(frags->page) + frags->page_offset; | ||
50 | *ip_hdr = *mac_hdr + ETH_HLEN; | ||
51 | *tcpudp_hdr = (struct tcphdr *)(*ip_hdr + sizeof(struct iphdr)); | ||
52 | *hdr_flags = LRO_IPV4 | LRO_TCP; | ||
53 | |||
54 | return 0; | ||
55 | } | ||
56 | |||
57 | static int mlx4_en_alloc_frag(struct mlx4_en_priv *priv, | 45 | static int mlx4_en_alloc_frag(struct mlx4_en_priv *priv, |
58 | struct mlx4_en_rx_desc *rx_desc, | 46 | struct mlx4_en_rx_desc *rx_desc, |
59 | struct skb_frag_struct *skb_frags, | 47 | struct skb_frag_struct *skb_frags, |
@@ -251,7 +239,6 @@ reduce_rings: | |||
251 | ring->prod--; | 239 | ring->prod--; |
252 | mlx4_en_free_rx_desc(priv, ring, ring->actual_size); | 240 | mlx4_en_free_rx_desc(priv, ring, ring->actual_size); |
253 | } | 241 | } |
254 | ring->size_mask = ring->actual_size - 1; | ||
255 | } | 242 | } |
256 | 243 | ||
257 | return 0; | 244 | return 0; |
@@ -313,28 +300,8 @@ int mlx4_en_create_rx_ring(struct mlx4_en_priv *priv, | |||
313 | } | 300 | } |
314 | ring->buf = ring->wqres.buf.direct.buf; | 301 | ring->buf = ring->wqres.buf.direct.buf; |
315 | 302 | ||
316 | /* Configure lro mngr */ | ||
317 | memset(&ring->lro, 0, sizeof(struct net_lro_mgr)); | ||
318 | ring->lro.dev = priv->dev; | ||
319 | ring->lro.features = LRO_F_NAPI; | ||
320 | ring->lro.frag_align_pad = NET_IP_ALIGN; | ||
321 | ring->lro.ip_summed = CHECKSUM_UNNECESSARY; | ||
322 | ring->lro.ip_summed_aggr = CHECKSUM_UNNECESSARY; | ||
323 | ring->lro.max_desc = mdev->profile.num_lro; | ||
324 | ring->lro.max_aggr = MAX_SKB_FRAGS; | ||
325 | ring->lro.lro_arr = kzalloc(mdev->profile.num_lro * | ||
326 | sizeof(struct net_lro_desc), | ||
327 | GFP_KERNEL); | ||
328 | if (!ring->lro.lro_arr) { | ||
329 | en_err(priv, "Failed to allocate lro array\n"); | ||
330 | goto err_map; | ||
331 | } | ||
332 | ring->lro.get_frag_header = mlx4_en_get_frag_header; | ||
333 | |||
334 | return 0; | 303 | return 0; |
335 | 304 | ||
336 | err_map: | ||
337 | mlx4_en_unmap_buffer(&ring->wqres.buf); | ||
338 | err_hwq: | 305 | err_hwq: |
339 | mlx4_free_hwq_res(mdev->dev, &ring->wqres, ring->buf_size); | 306 | mlx4_free_hwq_res(mdev->dev, &ring->wqres, ring->buf_size); |
340 | err_ring: | 307 | err_ring: |
@@ -389,6 +356,7 @@ int mlx4_en_activate_rx_rings(struct mlx4_en_priv *priv) | |||
389 | for (ring_ind = 0; ring_ind < priv->rx_ring_num; ring_ind++) { | 356 | for (ring_ind = 0; ring_ind < priv->rx_ring_num; ring_ind++) { |
390 | ring = &priv->rx_ring[ring_ind]; | 357 | ring = &priv->rx_ring[ring_ind]; |
391 | 358 | ||
359 | ring->size_mask = ring->actual_size - 1; | ||
392 | mlx4_en_update_rx_prod_db(ring); | 360 | mlx4_en_update_rx_prod_db(ring); |
393 | } | 361 | } |
394 | 362 | ||
@@ -412,7 +380,6 @@ void mlx4_en_destroy_rx_ring(struct mlx4_en_priv *priv, | |||
412 | { | 380 | { |
413 | struct mlx4_en_dev *mdev = priv->mdev; | 381 | struct mlx4_en_dev *mdev = priv->mdev; |
414 | 382 | ||
415 | kfree(ring->lro.lro_arr); | ||
416 | mlx4_en_unmap_buffer(&ring->wqres.buf); | 383 | mlx4_en_unmap_buffer(&ring->wqres.buf); |
417 | mlx4_free_hwq_res(mdev->dev, &ring->wqres, ring->buf_size + TXBB_SIZE); | 384 | mlx4_free_hwq_res(mdev->dev, &ring->wqres, ring->buf_size + TXBB_SIZE); |
418 | vfree(ring->rx_info); | 385 | vfree(ring->rx_info); |
@@ -459,7 +426,7 @@ static int mlx4_en_complete_rx_desc(struct mlx4_en_priv *priv, | |||
459 | goto fail; | 426 | goto fail; |
460 | 427 | ||
461 | /* Unmap buffer */ | 428 | /* Unmap buffer */ |
462 | pci_unmap_single(mdev->pdev, dma, skb_frags[nr].size, | 429 | pci_unmap_single(mdev->pdev, dma, skb_frags_rx[nr].size, |
463 | PCI_DMA_FROMDEVICE); | 430 | PCI_DMA_FROMDEVICE); |
464 | } | 431 | } |
465 | /* Adjust size of last fragment to match actual length */ | 432 | /* Adjust size of last fragment to match actual length */ |
@@ -541,6 +508,21 @@ static struct sk_buff *mlx4_en_rx_skb(struct mlx4_en_priv *priv, | |||
541 | return skb; | 508 | return skb; |
542 | } | 509 | } |
543 | 510 | ||
511 | static void validate_loopback(struct mlx4_en_priv *priv, struct sk_buff *skb) | ||
512 | { | ||
513 | int i; | ||
514 | int offset = ETH_HLEN; | ||
515 | |||
516 | for (i = 0; i < MLX4_LOOPBACK_TEST_PAYLOAD; i++, offset++) { | ||
517 | if (*(skb->data + offset) != (unsigned char) (i & 0xff)) | ||
518 | goto out_loopback; | ||
519 | } | ||
520 | /* Loopback found */ | ||
521 | priv->loopback_ok = 1; | ||
522 | |||
523 | out_loopback: | ||
524 | dev_kfree_skb_any(skb); | ||
525 | } | ||
544 | 526 | ||
545 | int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int budget) | 527 | int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int budget) |
546 | { | 528 | { |
@@ -548,7 +530,6 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud | |||
548 | struct mlx4_cqe *cqe; | 530 | struct mlx4_cqe *cqe; |
549 | struct mlx4_en_rx_ring *ring = &priv->rx_ring[cq->ring]; | 531 | struct mlx4_en_rx_ring *ring = &priv->rx_ring[cq->ring]; |
550 | struct skb_frag_struct *skb_frags; | 532 | struct skb_frag_struct *skb_frags; |
551 | struct skb_frag_struct lro_frags[MLX4_EN_MAX_RX_FRAGS]; | ||
552 | struct mlx4_en_rx_desc *rx_desc; | 533 | struct mlx4_en_rx_desc *rx_desc; |
553 | struct sk_buff *skb; | 534 | struct sk_buff *skb; |
554 | int index; | 535 | int index; |
@@ -608,37 +589,35 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud | |||
608 | * - TCP/IP (v4) | 589 | * - TCP/IP (v4) |
609 | * - without IP options | 590 | * - without IP options |
610 | * - not an IP fragment */ | 591 | * - not an IP fragment */ |
611 | if (mlx4_en_can_lro(cqe->status) && | 592 | if (dev->features & NETIF_F_GRO) { |
612 | dev->features & NETIF_F_LRO) { | 593 | struct sk_buff *gro_skb = napi_get_frags(&cq->napi); |
594 | if (!gro_skb) | ||
595 | goto next; | ||
613 | 596 | ||
614 | nr = mlx4_en_complete_rx_desc( | 597 | nr = mlx4_en_complete_rx_desc( |
615 | priv, rx_desc, | 598 | priv, rx_desc, |
616 | skb_frags, lro_frags, | 599 | skb_frags, skb_shinfo(gro_skb)->frags, |
617 | ring->page_alloc, length); | 600 | ring->page_alloc, length); |
618 | if (!nr) | 601 | if (!nr) |
619 | goto next; | 602 | goto next; |
620 | 603 | ||
604 | skb_shinfo(gro_skb)->nr_frags = nr; | ||
605 | gro_skb->len = length; | ||
606 | gro_skb->data_len = length; | ||
607 | gro_skb->truesize += length; | ||
608 | gro_skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
609 | |||
621 | if (priv->vlgrp && (cqe->vlan_my_qpn & | 610 | if (priv->vlgrp && (cqe->vlan_my_qpn & |
622 | cpu_to_be32(MLX4_CQE_VLAN_PRESENT_MASK))) { | 611 | cpu_to_be32(MLX4_CQE_VLAN_PRESENT_MASK))) |
623 | lro_vlan_hwaccel_receive_frags( | 612 | vlan_gro_frags(&cq->napi, priv->vlgrp, be16_to_cpu(cqe->sl_vid)); |
624 | &ring->lro, lro_frags, | 613 | else |
625 | length, length, | 614 | napi_gro_frags(&cq->napi); |
626 | priv->vlgrp, | ||
627 | be16_to_cpu(cqe->sl_vid), | ||
628 | NULL, 0); | ||
629 | } else | ||
630 | lro_receive_frags(&ring->lro, | ||
631 | lro_frags, | ||
632 | length, | ||
633 | length, | ||
634 | NULL, 0); | ||
635 | 615 | ||
636 | goto next; | 616 | goto next; |
637 | } | 617 | } |
638 | 618 | ||
639 | /* LRO not possible, complete processing here */ | 619 | /* LRO not possible, complete processing here */ |
640 | ip_summed = CHECKSUM_UNNECESSARY; | 620 | ip_summed = CHECKSUM_UNNECESSARY; |
641 | INC_PERF_COUNTER(priv->pstats.lro_misses); | ||
642 | } else { | 621 | } else { |
643 | ip_summed = CHECKSUM_NONE; | 622 | ip_summed = CHECKSUM_NONE; |
644 | priv->port_stats.rx_chksum_none++; | 623 | priv->port_stats.rx_chksum_none++; |
@@ -655,6 +634,11 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud | |||
655 | goto next; | 634 | goto next; |
656 | } | 635 | } |
657 | 636 | ||
637 | if (unlikely(priv->validate_loopback)) { | ||
638 | validate_loopback(priv, skb); | ||
639 | goto next; | ||
640 | } | ||
641 | |||
658 | skb->ip_summed = ip_summed; | 642 | skb->ip_summed = ip_summed; |
659 | skb->protocol = eth_type_trans(skb, dev); | 643 | skb->protocol = eth_type_trans(skb, dev); |
660 | skb_record_rx_queue(skb, cq->ring); | 644 | skb_record_rx_queue(skb, cq->ring); |
@@ -674,14 +658,10 @@ next: | |||
674 | if (++polled == budget) { | 658 | if (++polled == budget) { |
675 | /* We are here because we reached the NAPI budget - | 659 | /* We are here because we reached the NAPI budget - |
676 | * flush only pending LRO sessions */ | 660 | * flush only pending LRO sessions */ |
677 | lro_flush_all(&ring->lro); | ||
678 | goto out; | 661 | goto out; |
679 | } | 662 | } |
680 | } | 663 | } |
681 | 664 | ||
682 | /* If CQ is empty flush all LRO sessions unconditionally */ | ||
683 | lro_flush_all(&ring->lro); | ||
684 | |||
685 | out: | 665 | out: |
686 | AVG_PERF_COUNTER(priv->pstats.rx_coal_avg, polled); | 666 | AVG_PERF_COUNTER(priv->pstats.rx_coal_avg, polled); |
687 | mlx4_cq_set_ci(&cq->mcq); | 667 | mlx4_cq_set_ci(&cq->mcq); |
@@ -816,7 +796,7 @@ static int mlx4_en_config_rss_qp(struct mlx4_en_priv *priv, int qpn, | |||
816 | qp->event = mlx4_en_sqp_event; | 796 | qp->event = mlx4_en_sqp_event; |
817 | 797 | ||
818 | memset(context, 0, sizeof *context); | 798 | memset(context, 0, sizeof *context); |
819 | mlx4_en_fill_qp_context(priv, ring->size, ring->stride, 0, 0, | 799 | mlx4_en_fill_qp_context(priv, ring->actual_size, ring->stride, 0, 0, |
820 | qpn, ring->cqn, context); | 800 | qpn, ring->cqn, context); |
821 | context->db_rec_addr = cpu_to_be64(ring->wqres.db.dma); | 801 | context->db_rec_addr = cpu_to_be64(ring->wqres.db.dma); |
822 | 802 | ||
@@ -839,8 +819,7 @@ int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv) | |||
839 | struct mlx4_qp_context context; | 819 | struct mlx4_qp_context context; |
840 | struct mlx4_en_rss_context *rss_context; | 820 | struct mlx4_en_rss_context *rss_context; |
841 | void *ptr; | 821 | void *ptr; |
842 | int rss_xor = mdev->profile.rss_xor; | 822 | u8 rss_mask = 0x3f; |
843 | u8 rss_mask = mdev->profile.rss_mask; | ||
844 | int i, qpn; | 823 | int i, qpn; |
845 | int err = 0; | 824 | int err = 0; |
846 | int good_qps = 0; | 825 | int good_qps = 0; |
@@ -886,9 +865,10 @@ int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv) | |||
886 | rss_context->base_qpn = cpu_to_be32(ilog2(priv->rx_ring_num) << 24 | | 865 | rss_context->base_qpn = cpu_to_be32(ilog2(priv->rx_ring_num) << 24 | |
887 | (rss_map->base_qpn)); | 866 | (rss_map->base_qpn)); |
888 | rss_context->default_qpn = cpu_to_be32(rss_map->base_qpn); | 867 | rss_context->default_qpn = cpu_to_be32(rss_map->base_qpn); |
889 | rss_context->hash_fn = rss_xor & 0x3; | 868 | rss_context->flags = rss_mask; |
890 | rss_context->flags = rss_mask << 2; | ||
891 | 869 | ||
870 | if (priv->mdev->profile.udp_rss) | ||
871 | rss_context->base_qpn_udp = rss_context->default_qpn; | ||
892 | err = mlx4_qp_to_ready(mdev->dev, &priv->res.mtt, &context, | 872 | err = mlx4_qp_to_ready(mdev->dev, &priv->res.mtt, &context, |
893 | &rss_map->indir_qp, &rss_map->indir_state); | 873 | &rss_map->indir_qp, &rss_map->indir_state); |
894 | if (err) | 874 | if (err) |
diff --git a/drivers/net/mlx4/en_selftest.c b/drivers/net/mlx4/en_selftest.c new file mode 100644 index 000000000000..9c91a92da705 --- /dev/null +++ b/drivers/net/mlx4/en_selftest.c | |||
@@ -0,0 +1,179 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2007 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/kernel.h> | ||
35 | #include <linux/ethtool.h> | ||
36 | #include <linux/netdevice.h> | ||
37 | #include <linux/delay.h> | ||
38 | #include <linux/mlx4/driver.h> | ||
39 | |||
40 | #include "mlx4_en.h" | ||
41 | |||
42 | |||
43 | static int mlx4_en_test_registers(struct mlx4_en_priv *priv) | ||
44 | { | ||
45 | return mlx4_cmd(priv->mdev->dev, 0, 0, 0, MLX4_CMD_HW_HEALTH_CHECK, | ||
46 | MLX4_CMD_TIME_CLASS_A); | ||
47 | } | ||
48 | |||
49 | static int mlx4_en_test_loopback_xmit(struct mlx4_en_priv *priv) | ||
50 | { | ||
51 | struct sk_buff *skb; | ||
52 | struct ethhdr *ethh; | ||
53 | unsigned char *packet; | ||
54 | unsigned int packet_size = MLX4_LOOPBACK_TEST_PAYLOAD; | ||
55 | unsigned int i; | ||
56 | int err; | ||
57 | |||
58 | |||
59 | /* build the pkt before xmit */ | ||
60 | skb = netdev_alloc_skb(priv->dev, MLX4_LOOPBACK_TEST_PAYLOAD + ETH_HLEN + NET_IP_ALIGN); | ||
61 | if (!skb) { | ||
62 | en_err(priv, "-LOOPBACK_TEST_XMIT- failed to create skb for xmit\n"); | ||
63 | return -ENOMEM; | ||
64 | } | ||
65 | skb_reserve(skb, NET_IP_ALIGN); | ||
66 | |||
67 | ethh = (struct ethhdr *)skb_put(skb, sizeof(struct ethhdr)); | ||
68 | packet = (unsigned char *)skb_put(skb, packet_size); | ||
69 | memcpy(ethh->h_dest, priv->dev->dev_addr, ETH_ALEN); | ||
70 | memset(ethh->h_source, 0, ETH_ALEN); | ||
71 | ethh->h_proto = htons(ETH_P_ARP); | ||
72 | skb_set_mac_header(skb, 0); | ||
73 | for (i = 0; i < packet_size; ++i) /* fill our packet */ | ||
74 | packet[i] = (unsigned char)(i & 0xff); | ||
75 | |||
76 | /* xmit the pkt */ | ||
77 | err = mlx4_en_xmit(skb, priv->dev); | ||
78 | return err; | ||
79 | } | ||
80 | |||
81 | static int mlx4_en_test_loopback(struct mlx4_en_priv *priv) | ||
82 | { | ||
83 | u32 loopback_ok = 0; | ||
84 | int i; | ||
85 | |||
86 | |||
87 | priv->loopback_ok = 0; | ||
88 | priv->validate_loopback = 1; | ||
89 | |||
90 | /* xmit */ | ||
91 | if (mlx4_en_test_loopback_xmit(priv)) { | ||
92 | en_err(priv, "Transmitting loopback packet failed\n"); | ||
93 | goto mlx4_en_test_loopback_exit; | ||
94 | } | ||
95 | |||
96 | /* polling for result */ | ||
97 | for (i = 0; i < MLX4_EN_LOOPBACK_RETRIES; ++i) { | ||
98 | msleep(MLX4_EN_LOOPBACK_TIMEOUT); | ||
99 | if (priv->loopback_ok) { | ||
100 | loopback_ok = 1; | ||
101 | break; | ||
102 | } | ||
103 | } | ||
104 | if (!loopback_ok) | ||
105 | en_err(priv, "Loopback packet didn't arrive\n"); | ||
106 | |||
107 | mlx4_en_test_loopback_exit: | ||
108 | |||
109 | priv->validate_loopback = 0; | ||
110 | return !loopback_ok; | ||
111 | } | ||
112 | |||
113 | |||
114 | static int mlx4_en_test_link(struct mlx4_en_priv *priv) | ||
115 | { | ||
116 | if (mlx4_en_QUERY_PORT(priv->mdev, priv->port)) | ||
117 | return -ENOMEM; | ||
118 | if (priv->port_state.link_state == 1) | ||
119 | return 0; | ||
120 | else | ||
121 | return 1; | ||
122 | } | ||
123 | |||
124 | static int mlx4_en_test_speed(struct mlx4_en_priv *priv) | ||
125 | { | ||
126 | |||
127 | if (mlx4_en_QUERY_PORT(priv->mdev, priv->port)) | ||
128 | return -ENOMEM; | ||
129 | |||
130 | /* The device currently only supports 10G speed */ | ||
131 | if (priv->port_state.link_speed != SPEED_10000) | ||
132 | return priv->port_state.link_speed; | ||
133 | return 0; | ||
134 | } | ||
135 | |||
136 | |||
137 | void mlx4_en_ex_selftest(struct net_device *dev, u32 *flags, u64 *buf) | ||
138 | { | ||
139 | struct mlx4_en_priv *priv = netdev_priv(dev); | ||
140 | struct mlx4_en_dev *mdev = priv->mdev; | ||
141 | struct mlx4_en_tx_ring *tx_ring; | ||
142 | int i, carrier_ok; | ||
143 | |||
144 | memset(buf, 0, sizeof(u64) * MLX4_EN_NUM_SELF_TEST); | ||
145 | |||
146 | if (*flags & ETH_TEST_FL_OFFLINE) { | ||
147 | /* disable the interface */ | ||
148 | carrier_ok = netif_carrier_ok(dev); | ||
149 | |||
150 | netif_carrier_off(dev); | ||
151 | retry_tx: | ||
152 | /* Wait untill all tx queues are empty. | ||
153 | * there should not be any additional incoming traffic | ||
154 | * since we turned the carrier off */ | ||
155 | msleep(200); | ||
156 | for (i = 0; i < priv->tx_ring_num && carrier_ok; i++) { | ||
157 | tx_ring = &priv->tx_ring[i]; | ||
158 | if (tx_ring->prod != (tx_ring->cons + tx_ring->last_nr_txbb)) | ||
159 | goto retry_tx; | ||
160 | } | ||
161 | |||
162 | if (priv->mdev->dev->caps.loopback_support){ | ||
163 | buf[3] = mlx4_en_test_registers(priv); | ||
164 | buf[4] = mlx4_en_test_loopback(priv); | ||
165 | } | ||
166 | |||
167 | if (carrier_ok) | ||
168 | netif_carrier_on(dev); | ||
169 | |||
170 | } | ||
171 | buf[0] = mlx4_test_interrupts(mdev->dev); | ||
172 | buf[1] = mlx4_en_test_link(priv); | ||
173 | buf[2] = mlx4_en_test_speed(priv); | ||
174 | |||
175 | for (i = 0; i < MLX4_EN_NUM_SELF_TEST; i++) { | ||
176 | if (buf[i]) | ||
177 | *flags |= ETH_TEST_FL_FAILED; | ||
178 | } | ||
179 | } | ||
diff --git a/drivers/net/mlx4/en_tx.c b/drivers/net/mlx4/en_tx.c index 580968f304eb..98dd620042a8 100644 --- a/drivers/net/mlx4/en_tx.c +++ b/drivers/net/mlx4/en_tx.c | |||
@@ -38,6 +38,7 @@ | |||
38 | #include <linux/skbuff.h> | 38 | #include <linux/skbuff.h> |
39 | #include <linux/if_vlan.h> | 39 | #include <linux/if_vlan.h> |
40 | #include <linux/vmalloc.h> | 40 | #include <linux/vmalloc.h> |
41 | #include <linux/tcp.h> | ||
41 | 42 | ||
42 | #include "mlx4_en.h" | 43 | #include "mlx4_en.h" |
43 | 44 | ||
@@ -600,6 +601,9 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) | |||
600 | struct mlx4_wqe_data_seg *data; | 601 | struct mlx4_wqe_data_seg *data; |
601 | struct skb_frag_struct *frag; | 602 | struct skb_frag_struct *frag; |
602 | struct mlx4_en_tx_info *tx_info; | 603 | struct mlx4_en_tx_info *tx_info; |
604 | struct ethhdr *ethh; | ||
605 | u64 mac; | ||
606 | u32 mac_l, mac_h; | ||
603 | int tx_ind = 0; | 607 | int tx_ind = 0; |
604 | int nr_txbb; | 608 | int nr_txbb; |
605 | int desc_size; | 609 | int desc_size; |
@@ -612,6 +616,9 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) | |||
612 | int lso_header_size; | 616 | int lso_header_size; |
613 | void *fragptr; | 617 | void *fragptr; |
614 | 618 | ||
619 | if (!priv->port_up) | ||
620 | goto tx_drop; | ||
621 | |||
615 | real_size = get_real_size(skb, dev, &lso_header_size); | 622 | real_size = get_real_size(skb, dev, &lso_header_size); |
616 | if (unlikely(!real_size)) | 623 | if (unlikely(!real_size)) |
617 | goto tx_drop; | 624 | goto tx_drop; |
@@ -676,6 +683,19 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) | |||
676 | priv->port_stats.tx_chksum_offload++; | 683 | priv->port_stats.tx_chksum_offload++; |
677 | } | 684 | } |
678 | 685 | ||
686 | if (unlikely(priv->validate_loopback)) { | ||
687 | /* Copy dst mac address to wqe */ | ||
688 | skb_reset_mac_header(skb); | ||
689 | ethh = eth_hdr(skb); | ||
690 | if (ethh && ethh->h_dest) { | ||
691 | mac = mlx4_en_mac_to_u64(ethh->h_dest); | ||
692 | mac_h = (u32) ((mac & 0xffff00000000ULL) >> 16); | ||
693 | mac_l = (u32) (mac & 0xffffffff); | ||
694 | tx_desc->ctrl.srcrb_flags |= cpu_to_be32(mac_h); | ||
695 | tx_desc->ctrl.imm = cpu_to_be32(mac_l); | ||
696 | } | ||
697 | } | ||
698 | |||
679 | /* Handle LSO (TSO) packets */ | 699 | /* Handle LSO (TSO) packets */ |
680 | if (lso_header_size) { | 700 | if (lso_header_size) { |
681 | /* Mark opcode as LSO */ | 701 | /* Mark opcode as LSO */ |
diff --git a/drivers/net/mlx4/eq.c b/drivers/net/mlx4/eq.c index 6d7b2bf210ce..552d0fce6f67 100644 --- a/drivers/net/mlx4/eq.c +++ b/drivers/net/mlx4/eq.c | |||
@@ -699,3 +699,47 @@ void mlx4_cleanup_eq_table(struct mlx4_dev *dev) | |||
699 | 699 | ||
700 | kfree(priv->eq_table.uar_map); | 700 | kfree(priv->eq_table.uar_map); |
701 | } | 701 | } |
702 | |||
703 | /* A test that verifies that we can accept interrupts on all | ||
704 | * the irq vectors of the device. | ||
705 | * Interrupts are checked using the NOP command. | ||
706 | */ | ||
707 | int mlx4_test_interrupts(struct mlx4_dev *dev) | ||
708 | { | ||
709 | struct mlx4_priv *priv = mlx4_priv(dev); | ||
710 | int i; | ||
711 | int err; | ||
712 | |||
713 | err = mlx4_NOP(dev); | ||
714 | /* When not in MSI_X, there is only one irq to check */ | ||
715 | if (!(dev->flags & MLX4_FLAG_MSI_X)) | ||
716 | return err; | ||
717 | |||
718 | /* A loop over all completion vectors, for each vector we will check | ||
719 | * whether it works by mapping command completions to that vector | ||
720 | * and performing a NOP command | ||
721 | */ | ||
722 | for(i = 0; !err && (i < dev->caps.num_comp_vectors); ++i) { | ||
723 | /* Temporary use polling for command completions */ | ||
724 | mlx4_cmd_use_polling(dev); | ||
725 | |||
726 | /* Map the new eq to handle all asyncronous events */ | ||
727 | err = mlx4_MAP_EQ(dev, MLX4_ASYNC_EVENT_MASK, 0, | ||
728 | priv->eq_table.eq[i].eqn); | ||
729 | if (err) { | ||
730 | mlx4_warn(dev, "Failed mapping eq for interrupt test\n"); | ||
731 | mlx4_cmd_use_events(dev); | ||
732 | break; | ||
733 | } | ||
734 | |||
735 | /* Go back to using events */ | ||
736 | mlx4_cmd_use_events(dev); | ||
737 | err = mlx4_NOP(dev); | ||
738 | } | ||
739 | |||
740 | /* Return to default */ | ||
741 | mlx4_MAP_EQ(dev, MLX4_ASYNC_EVENT_MASK, 0, | ||
742 | priv->eq_table.eq[dev->caps.num_comp_vectors].eqn); | ||
743 | return err; | ||
744 | } | ||
745 | EXPORT_SYMBOL(mlx4_test_interrupts); | ||
diff --git a/drivers/net/mlx4/fw.c b/drivers/net/mlx4/fw.c index 04f42ae1eda0..b716e1a1b298 100644 --- a/drivers/net/mlx4/fw.c +++ b/drivers/net/mlx4/fw.c | |||
@@ -141,6 +141,7 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) | |||
141 | struct mlx4_cmd_mailbox *mailbox; | 141 | struct mlx4_cmd_mailbox *mailbox; |
142 | u32 *outbox; | 142 | u32 *outbox; |
143 | u8 field; | 143 | u8 field; |
144 | u32 field32; | ||
144 | u16 size; | 145 | u16 size; |
145 | u16 stat_rate; | 146 | u16 stat_rate; |
146 | int err; | 147 | int err; |
@@ -178,6 +179,8 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) | |||
178 | #define QUERY_DEV_CAP_MAX_GID_OFFSET 0x3b | 179 | #define QUERY_DEV_CAP_MAX_GID_OFFSET 0x3b |
179 | #define QUERY_DEV_CAP_RATE_SUPPORT_OFFSET 0x3c | 180 | #define QUERY_DEV_CAP_RATE_SUPPORT_OFFSET 0x3c |
180 | #define QUERY_DEV_CAP_MAX_PKEY_OFFSET 0x3f | 181 | #define QUERY_DEV_CAP_MAX_PKEY_OFFSET 0x3f |
182 | #define QUERY_DEV_CAP_UDP_RSS_OFFSET 0x42 | ||
183 | #define QUERY_DEV_CAP_ETH_UC_LOOPBACK_OFFSET 0x43 | ||
181 | #define QUERY_DEV_CAP_FLAGS_OFFSET 0x44 | 184 | #define QUERY_DEV_CAP_FLAGS_OFFSET 0x44 |
182 | #define QUERY_DEV_CAP_RSVD_UAR_OFFSET 0x48 | 185 | #define QUERY_DEV_CAP_RSVD_UAR_OFFSET 0x48 |
183 | #define QUERY_DEV_CAP_UAR_SZ_OFFSET 0x49 | 186 | #define QUERY_DEV_CAP_UAR_SZ_OFFSET 0x49 |
@@ -268,6 +271,10 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) | |||
268 | dev_cap->max_msg_sz = 1 << (field & 0x1f); | 271 | dev_cap->max_msg_sz = 1 << (field & 0x1f); |
269 | MLX4_GET(stat_rate, outbox, QUERY_DEV_CAP_RATE_SUPPORT_OFFSET); | 272 | MLX4_GET(stat_rate, outbox, QUERY_DEV_CAP_RATE_SUPPORT_OFFSET); |
270 | dev_cap->stat_rate_support = stat_rate; | 273 | dev_cap->stat_rate_support = stat_rate; |
274 | MLX4_GET(field, outbox, QUERY_DEV_CAP_UDP_RSS_OFFSET); | ||
275 | dev_cap->udp_rss = field & 0x1; | ||
276 | MLX4_GET(field, outbox, QUERY_DEV_CAP_ETH_UC_LOOPBACK_OFFSET); | ||
277 | dev_cap->loopback_support = field & 0x1; | ||
271 | MLX4_GET(dev_cap->flags, outbox, QUERY_DEV_CAP_FLAGS_OFFSET); | 278 | MLX4_GET(dev_cap->flags, outbox, QUERY_DEV_CAP_FLAGS_OFFSET); |
272 | MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_UAR_OFFSET); | 279 | MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_UAR_OFFSET); |
273 | dev_cap->reserved_uars = field >> 4; | 280 | dev_cap->reserved_uars = field >> 4; |
@@ -365,6 +372,9 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) | |||
365 | #define QUERY_PORT_MAX_MACVLAN_OFFSET 0x0a | 372 | #define QUERY_PORT_MAX_MACVLAN_OFFSET 0x0a |
366 | #define QUERY_PORT_MAX_VL_OFFSET 0x0b | 373 | #define QUERY_PORT_MAX_VL_OFFSET 0x0b |
367 | #define QUERY_PORT_MAC_OFFSET 0x10 | 374 | #define QUERY_PORT_MAC_OFFSET 0x10 |
375 | #define QUERY_PORT_TRANS_VENDOR_OFFSET 0x18 | ||
376 | #define QUERY_PORT_WAVELENGTH_OFFSET 0x1c | ||
377 | #define QUERY_PORT_TRANS_CODE_OFFSET 0x20 | ||
368 | 378 | ||
369 | for (i = 1; i <= dev_cap->num_ports; ++i) { | 379 | for (i = 1; i <= dev_cap->num_ports; ++i) { |
370 | err = mlx4_cmd_box(dev, 0, mailbox->dma, i, 0, MLX4_CMD_QUERY_PORT, | 380 | err = mlx4_cmd_box(dev, 0, mailbox->dma, i, 0, MLX4_CMD_QUERY_PORT, |
@@ -388,6 +398,11 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) | |||
388 | dev_cap->log_max_vlans[i] = field >> 4; | 398 | dev_cap->log_max_vlans[i] = field >> 4; |
389 | MLX4_GET(dev_cap->eth_mtu[i], outbox, QUERY_PORT_ETH_MTU_OFFSET); | 399 | MLX4_GET(dev_cap->eth_mtu[i], outbox, QUERY_PORT_ETH_MTU_OFFSET); |
390 | MLX4_GET(dev_cap->def_mac[i], outbox, QUERY_PORT_MAC_OFFSET); | 400 | MLX4_GET(dev_cap->def_mac[i], outbox, QUERY_PORT_MAC_OFFSET); |
401 | MLX4_GET(field32, outbox, QUERY_PORT_TRANS_VENDOR_OFFSET); | ||
402 | dev_cap->trans_type[i] = field32 >> 24; | ||
403 | dev_cap->vendor_oui[i] = field32 & 0xffffff; | ||
404 | MLX4_GET(dev_cap->wavelength[i], outbox, QUERY_PORT_WAVELENGTH_OFFSET); | ||
405 | MLX4_GET(dev_cap->trans_code[i], outbox, QUERY_PORT_TRANS_CODE_OFFSET); | ||
391 | } | 406 | } |
392 | } | 407 | } |
393 | 408 | ||
diff --git a/drivers/net/mlx4/fw.h b/drivers/net/mlx4/fw.h index 526d7f30c041..65cc72eb899d 100644 --- a/drivers/net/mlx4/fw.h +++ b/drivers/net/mlx4/fw.h | |||
@@ -73,7 +73,13 @@ struct mlx4_dev_cap { | |||
73 | int max_pkeys[MLX4_MAX_PORTS + 1]; | 73 | int max_pkeys[MLX4_MAX_PORTS + 1]; |
74 | u64 def_mac[MLX4_MAX_PORTS + 1]; | 74 | u64 def_mac[MLX4_MAX_PORTS + 1]; |
75 | u16 eth_mtu[MLX4_MAX_PORTS + 1]; | 75 | u16 eth_mtu[MLX4_MAX_PORTS + 1]; |
76 | int trans_type[MLX4_MAX_PORTS + 1]; | ||
77 | int vendor_oui[MLX4_MAX_PORTS + 1]; | ||
78 | u16 wavelength[MLX4_MAX_PORTS + 1]; | ||
79 | u64 trans_code[MLX4_MAX_PORTS + 1]; | ||
76 | u16 stat_rate_support; | 80 | u16 stat_rate_support; |
81 | int udp_rss; | ||
82 | int loopback_support; | ||
77 | u32 flags; | 83 | u32 flags; |
78 | int reserved_uars; | 84 | int reserved_uars; |
79 | int uar_size; | 85 | int uar_size; |
diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c index 5102ab1ac561..569fa3df381f 100644 --- a/drivers/net/mlx4/main.c +++ b/drivers/net/mlx4/main.c | |||
@@ -184,6 +184,10 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) | |||
184 | dev->caps.eth_mtu_cap[i] = dev_cap->eth_mtu[i]; | 184 | dev->caps.eth_mtu_cap[i] = dev_cap->eth_mtu[i]; |
185 | dev->caps.def_mac[i] = dev_cap->def_mac[i]; | 185 | dev->caps.def_mac[i] = dev_cap->def_mac[i]; |
186 | dev->caps.supported_type[i] = dev_cap->supported_port_types[i]; | 186 | dev->caps.supported_type[i] = dev_cap->supported_port_types[i]; |
187 | dev->caps.trans_type[i] = dev_cap->trans_type[i]; | ||
188 | dev->caps.vendor_oui[i] = dev_cap->vendor_oui[i]; | ||
189 | dev->caps.wavelength[i] = dev_cap->wavelength[i]; | ||
190 | dev->caps.trans_code[i] = dev_cap->trans_code[i]; | ||
187 | } | 191 | } |
188 | 192 | ||
189 | dev->caps.num_uars = dev_cap->uar_size / PAGE_SIZE; | 193 | dev->caps.num_uars = dev_cap->uar_size / PAGE_SIZE; |
@@ -221,6 +225,8 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) | |||
221 | dev->caps.bmme_flags = dev_cap->bmme_flags; | 225 | dev->caps.bmme_flags = dev_cap->bmme_flags; |
222 | dev->caps.reserved_lkey = dev_cap->reserved_lkey; | 226 | dev->caps.reserved_lkey = dev_cap->reserved_lkey; |
223 | dev->caps.stat_rate_support = dev_cap->stat_rate_support; | 227 | dev->caps.stat_rate_support = dev_cap->stat_rate_support; |
228 | dev->caps.udp_rss = dev_cap->udp_rss; | ||
229 | dev->caps.loopback_support = dev_cap->loopback_support; | ||
224 | dev->caps.max_gso_sz = dev_cap->max_gso_sz; | 230 | dev->caps.max_gso_sz = dev_cap->max_gso_sz; |
225 | 231 | ||
226 | dev->caps.log_num_macs = log_num_mac; | 232 | dev->caps.log_num_macs = log_num_mac; |
diff --git a/drivers/net/mlx4/mlx4_en.h b/drivers/net/mlx4/mlx4_en.h index 449210994ee9..1fc16ab7ad2f 100644 --- a/drivers/net/mlx4/mlx4_en.h +++ b/drivers/net/mlx4/mlx4_en.h | |||
@@ -38,19 +38,19 @@ | |||
38 | #include <linux/list.h> | 38 | #include <linux/list.h> |
39 | #include <linux/mutex.h> | 39 | #include <linux/mutex.h> |
40 | #include <linux/netdevice.h> | 40 | #include <linux/netdevice.h> |
41 | #include <linux/inet_lro.h> | ||
42 | 41 | ||
43 | #include <linux/mlx4/device.h> | 42 | #include <linux/mlx4/device.h> |
44 | #include <linux/mlx4/qp.h> | 43 | #include <linux/mlx4/qp.h> |
45 | #include <linux/mlx4/cq.h> | 44 | #include <linux/mlx4/cq.h> |
46 | #include <linux/mlx4/srq.h> | 45 | #include <linux/mlx4/srq.h> |
47 | #include <linux/mlx4/doorbell.h> | 46 | #include <linux/mlx4/doorbell.h> |
47 | #include <linux/mlx4/cmd.h> | ||
48 | 48 | ||
49 | #include "en_port.h" | 49 | #include "en_port.h" |
50 | 50 | ||
51 | #define DRV_NAME "mlx4_en" | 51 | #define DRV_NAME "mlx4_en" |
52 | #define DRV_VERSION "1.4.1.1" | 52 | #define DRV_VERSION "1.5.1.6" |
53 | #define DRV_RELDATE "June 2009" | 53 | #define DRV_RELDATE "August 2010" |
54 | 54 | ||
55 | #define MLX4_EN_MSG_LEVEL (NETIF_MSG_LINK | NETIF_MSG_IFDOWN) | 55 | #define MLX4_EN_MSG_LEVEL (NETIF_MSG_LINK | NETIF_MSG_IFDOWN) |
56 | 56 | ||
@@ -61,7 +61,6 @@ | |||
61 | 61 | ||
62 | #define MLX4_EN_PAGE_SHIFT 12 | 62 | #define MLX4_EN_PAGE_SHIFT 12 |
63 | #define MLX4_EN_PAGE_SIZE (1 << MLX4_EN_PAGE_SHIFT) | 63 | #define MLX4_EN_PAGE_SIZE (1 << MLX4_EN_PAGE_SHIFT) |
64 | #define MAX_TX_RINGS 16 | ||
65 | #define MAX_RX_RINGS 16 | 64 | #define MAX_RX_RINGS 16 |
66 | #define TXBB_SIZE 64 | 65 | #define TXBB_SIZE 64 |
67 | #define HEADROOM (2048 / TXBB_SIZE + 1) | 66 | #define HEADROOM (2048 / TXBB_SIZE + 1) |
@@ -107,6 +106,7 @@ enum { | |||
107 | #define MLX4_EN_SMALL_PKT_SIZE 64 | 106 | #define MLX4_EN_SMALL_PKT_SIZE 64 |
108 | #define MLX4_EN_NUM_TX_RINGS 8 | 107 | #define MLX4_EN_NUM_TX_RINGS 8 |
109 | #define MLX4_EN_NUM_PPP_RINGS 8 | 108 | #define MLX4_EN_NUM_PPP_RINGS 8 |
109 | #define MAX_TX_RINGS (MLX4_EN_NUM_TX_RINGS + MLX4_EN_NUM_PPP_RINGS) | ||
110 | #define MLX4_EN_DEF_TX_RING_SIZE 512 | 110 | #define MLX4_EN_DEF_TX_RING_SIZE 512 |
111 | #define MLX4_EN_DEF_RX_RING_SIZE 1024 | 111 | #define MLX4_EN_DEF_RX_RING_SIZE 1024 |
112 | 112 | ||
@@ -139,10 +139,14 @@ enum { | |||
139 | 139 | ||
140 | #define SMALL_PACKET_SIZE (256 - NET_IP_ALIGN) | 140 | #define SMALL_PACKET_SIZE (256 - NET_IP_ALIGN) |
141 | #define HEADER_COPY_SIZE (128 - NET_IP_ALIGN) | 141 | #define HEADER_COPY_SIZE (128 - NET_IP_ALIGN) |
142 | #define MLX4_LOOPBACK_TEST_PAYLOAD (HEADER_COPY_SIZE - ETH_HLEN) | ||
142 | 143 | ||
143 | #define MLX4_EN_MIN_MTU 46 | 144 | #define MLX4_EN_MIN_MTU 46 |
144 | #define ETH_BCAST 0xffffffffffffULL | 145 | #define ETH_BCAST 0xffffffffffffULL |
145 | 146 | ||
147 | #define MLX4_EN_LOOPBACK_RETRIES 5 | ||
148 | #define MLX4_EN_LOOPBACK_TIMEOUT 100 | ||
149 | |||
146 | #ifdef MLX4_EN_PERF_STAT | 150 | #ifdef MLX4_EN_PERF_STAT |
147 | /* Number of samples to 'average' */ | 151 | /* Number of samples to 'average' */ |
148 | #define AVG_SIZE 128 | 152 | #define AVG_SIZE 128 |
@@ -249,7 +253,6 @@ struct mlx4_en_rx_desc { | |||
249 | struct mlx4_en_rx_ring { | 253 | struct mlx4_en_rx_ring { |
250 | struct mlx4_hwq_resources wqres; | 254 | struct mlx4_hwq_resources wqres; |
251 | struct mlx4_en_rx_alloc page_alloc[MLX4_EN_MAX_RX_FRAGS]; | 255 | struct mlx4_en_rx_alloc page_alloc[MLX4_EN_MAX_RX_FRAGS]; |
252 | struct net_lro_mgr lro; | ||
253 | u32 size ; /* number of Rx descs*/ | 256 | u32 size ; /* number of Rx descs*/ |
254 | u32 actual_size; | 257 | u32 actual_size; |
255 | u32 size_mask; | 258 | u32 size_mask; |
@@ -313,7 +316,8 @@ struct mlx4_en_port_profile { | |||
313 | 316 | ||
314 | struct mlx4_en_profile { | 317 | struct mlx4_en_profile { |
315 | int rss_xor; | 318 | int rss_xor; |
316 | int num_lro; | 319 | int tcp_rss; |
320 | int udp_rss; | ||
317 | u8 rss_mask; | 321 | u8 rss_mask; |
318 | u32 active_ports; | 322 | u32 active_ports; |
319 | u32 small_pkt_int; | 323 | u32 small_pkt_int; |
@@ -337,6 +341,7 @@ struct mlx4_en_dev { | |||
337 | struct mlx4_mr mr; | 341 | struct mlx4_mr mr; |
338 | u32 priv_pdn; | 342 | u32 priv_pdn; |
339 | spinlock_t uar_lock; | 343 | spinlock_t uar_lock; |
344 | u8 mac_removed[MLX4_MAX_PORTS + 1]; | ||
340 | }; | 345 | }; |
341 | 346 | ||
342 | 347 | ||
@@ -355,6 +360,13 @@ struct mlx4_en_rss_context { | |||
355 | u8 hash_fn; | 360 | u8 hash_fn; |
356 | u8 flags; | 361 | u8 flags; |
357 | __be32 rss_key[10]; | 362 | __be32 rss_key[10]; |
363 | __be32 base_qpn_udp; | ||
364 | }; | ||
365 | |||
366 | struct mlx4_en_port_state { | ||
367 | int link_state; | ||
368 | int link_speed; | ||
369 | int transciver; | ||
358 | }; | 370 | }; |
359 | 371 | ||
360 | struct mlx4_en_pkt_stats { | 372 | struct mlx4_en_pkt_stats { |
@@ -365,9 +377,6 @@ struct mlx4_en_pkt_stats { | |||
365 | }; | 377 | }; |
366 | 378 | ||
367 | struct mlx4_en_port_stats { | 379 | struct mlx4_en_port_stats { |
368 | unsigned long lro_aggregated; | ||
369 | unsigned long lro_flushed; | ||
370 | unsigned long lro_no_desc; | ||
371 | unsigned long tso_packets; | 380 | unsigned long tso_packets; |
372 | unsigned long queue_stopped; | 381 | unsigned long queue_stopped; |
373 | unsigned long wake_queue; | 382 | unsigned long wake_queue; |
@@ -376,7 +385,7 @@ struct mlx4_en_port_stats { | |||
376 | unsigned long rx_chksum_good; | 385 | unsigned long rx_chksum_good; |
377 | unsigned long rx_chksum_none; | 386 | unsigned long rx_chksum_none; |
378 | unsigned long tx_chksum_offload; | 387 | unsigned long tx_chksum_offload; |
379 | #define NUM_PORT_STATS 11 | 388 | #define NUM_PORT_STATS 8 |
380 | }; | 389 | }; |
381 | 390 | ||
382 | struct mlx4_en_perf_stats { | 391 | struct mlx4_en_perf_stats { |
@@ -405,6 +414,7 @@ struct mlx4_en_priv { | |||
405 | struct vlan_group *vlgrp; | 414 | struct vlan_group *vlgrp; |
406 | struct net_device_stats stats; | 415 | struct net_device_stats stats; |
407 | struct net_device_stats ret_stats; | 416 | struct net_device_stats ret_stats; |
417 | struct mlx4_en_port_state port_state; | ||
408 | spinlock_t stats_lock; | 418 | spinlock_t stats_lock; |
409 | 419 | ||
410 | unsigned long last_moder_packets; | 420 | unsigned long last_moder_packets; |
@@ -423,6 +433,8 @@ struct mlx4_en_priv { | |||
423 | u16 sample_interval; | 433 | u16 sample_interval; |
424 | u16 adaptive_rx_coal; | 434 | u16 adaptive_rx_coal; |
425 | u32 msg_enable; | 435 | u32 msg_enable; |
436 | u32 loopback_ok; | ||
437 | u32 validate_loopback; | ||
426 | 438 | ||
427 | struct mlx4_hwq_resources res; | 439 | struct mlx4_hwq_resources res; |
428 | int link_state; | 440 | int link_state; |
@@ -531,6 +543,11 @@ int mlx4_SET_PORT_qpn_calc(struct mlx4_dev *dev, u8 port, u32 base_qpn, | |||
531 | u8 promisc); | 543 | u8 promisc); |
532 | 544 | ||
533 | int mlx4_en_DUMP_ETH_STATS(struct mlx4_en_dev *mdev, u8 port, u8 reset); | 545 | int mlx4_en_DUMP_ETH_STATS(struct mlx4_en_dev *mdev, u8 port, u8 reset); |
546 | int mlx4_en_QUERY_PORT(struct mlx4_en_dev *mdev, u8 port); | ||
547 | |||
548 | #define MLX4_EN_NUM_SELF_TEST 5 | ||
549 | void mlx4_en_ex_selftest(struct net_device *dev, u32 *flags, u64 *buf); | ||
550 | u64 mlx4_en_mac_to_u64(u8 *addr); | ||
534 | 551 | ||
535 | /* | 552 | /* |
536 | * Globals | 553 | * Globals |
@@ -555,6 +572,8 @@ do { \ | |||
555 | en_print(KERN_WARNING, priv, format, ##arg) | 572 | en_print(KERN_WARNING, priv, format, ##arg) |
556 | #define en_err(priv, format, arg...) \ | 573 | #define en_err(priv, format, arg...) \ |
557 | en_print(KERN_ERR, priv, format, ##arg) | 574 | en_print(KERN_ERR, priv, format, ##arg) |
575 | #define en_info(priv, format, arg...) \ | ||
576 | en_print(KERN_INFO, priv, format, ## arg) | ||
558 | 577 | ||
559 | #define mlx4_err(mdev, format, arg...) \ | 578 | #define mlx4_err(mdev, format, arg...) \ |
560 | pr_err("%s %s: " format, DRV_NAME, \ | 579 | pr_err("%s %s: " format, DRV_NAME, \ |
diff --git a/drivers/net/mlx4/profile.c b/drivers/net/mlx4/profile.c index 5caf0115fa5b..e749f82865fe 100644 --- a/drivers/net/mlx4/profile.c +++ b/drivers/net/mlx4/profile.c | |||
@@ -85,7 +85,7 @@ u64 mlx4_make_profile(struct mlx4_dev *dev, | |||
85 | struct mlx4_resource tmp; | 85 | struct mlx4_resource tmp; |
86 | int i, j; | 86 | int i, j; |
87 | 87 | ||
88 | profile = kzalloc(MLX4_RES_NUM * sizeof *profile, GFP_KERNEL); | 88 | profile = kcalloc(MLX4_RES_NUM, sizeof(*profile), GFP_KERNEL); |
89 | if (!profile) | 89 | if (!profile) |
90 | return -ENOMEM; | 90 | return -ENOMEM; |
91 | 91 | ||