1219820Sjeff/* 2272407Shselasky * Copyright (c) 2007, 2014 Mellanox Technologies. All rights reserved. 3219820Sjeff * 4219820Sjeff * This software is available to you under a choice of one of two 5219820Sjeff * licenses. You may choose to be licensed under the terms of the GNU 6219820Sjeff * General Public License (GPL) Version 2, available from the file 7219820Sjeff * COPYING in the main directory of this source tree, or the 8219820Sjeff * OpenIB.org BSD license below: 9219820Sjeff * 10219820Sjeff * Redistribution and use in source and binary forms, with or 11219820Sjeff * without modification, are permitted provided that the following 12219820Sjeff * conditions are met: 13219820Sjeff * 14219820Sjeff * - Redistributions of source code must retain the above 15219820Sjeff * copyright notice, this list of conditions and the following 16219820Sjeff * disclaimer. 17219820Sjeff * 18219820Sjeff * - Redistributions in binary form must reproduce the above 19219820Sjeff * copyright notice, this list of conditions and the following 20219820Sjeff * disclaimer in the documentation and/or other materials 21219820Sjeff * provided with the distribution. 22219820Sjeff * 23219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30219820Sjeff * SOFTWARE. 31219820Sjeff * 32219820Sjeff */ 33219820Sjeff 34272407Shselasky#include <linux/etherdevice.h> 35272407Shselasky#include <linux/delay.h> 36272407Shselasky#include <linux/slab.h> 37272407Shselasky#ifdef CONFIG_NET_RX_BUSY_POLL 38272407Shselasky#include <net/busy_poll.h> 39272407Shselasky#endif 40219820Sjeff 41272407Shselasky#include <linux/list.h> 42272407Shselasky#include <linux/if_ether.h> 43272407Shselasky 44219820Sjeff#include <linux/mlx4/driver.h> 45219820Sjeff#include <linux/mlx4/device.h> 46219820Sjeff#include <linux/mlx4/cmd.h> 47219820Sjeff#include <linux/mlx4/cq.h> 48219820Sjeff 49219820Sjeff#include <sys/sockio.h> 50272407Shselasky#include <sys/sysctl.h> 51219820Sjeff 52272407Shselasky#include "mlx4_en.h" 53272407Shselasky#include "en_port.h" 54272407Shselasky 55219820Sjeffstatic void mlx4_en_sysctl_stat(struct mlx4_en_priv *priv); 56272407Shselaskystatic void mlx4_en_sysctl_conf(struct mlx4_en_priv *priv); 57272407Shselaskystatic int mlx4_en_unit; 58219820Sjeff 59272407Shselasky#ifdef CONFIG_NET_RX_BUSY_POLL 60272407Shselasky/* must be called with local_bh_disable()d */ 61272407Shselaskystatic int mlx4_en_low_latency_recv(struct napi_struct *napi) 62272407Shselasky{ 63272407Shselasky struct mlx4_en_cq *cq = container_of(napi, struct mlx4_en_cq, napi); 64272407Shselasky struct net_device *dev = cq->dev; 65272407Shselasky struct mlx4_en_priv *priv = netdev_priv(dev); 66272407Shselasky struct mlx4_en_rx_ring *rx_ring = priv->rx_ring[cq->ring]; 67272407Shselasky int done; 68272407Shselasky 69272407Shselasky if (!priv->port_up) 70272407Shselasky return LL_FLUSH_FAILED; 71272407Shselasky 72272407Shselasky if (!mlx4_en_cq_lock_poll(cq)) 73272407Shselasky return LL_FLUSH_BUSY; 74272407Shselasky 75272407Shselasky done = mlx4_en_process_rx_cq(dev, cq, 4); 76272407Shselasky#ifdef LL_EXTENDED_STATS 77272407Shselasky if (done) 78272407Shselasky rx_ring->cleaned += done; 79272407Shselasky else 80272407Shselasky rx_ring->misses++; 81272407Shselasky#endif 82272407Shselasky 83272407Shselasky mlx4_en_cq_unlock_poll(cq); 84272407Shselasky 85272407Shselasky return done; 86272407Shselasky} 87272407Shselasky#endif /* CONFIG_NET_RX_BUSY_POLL */ 88272407Shselasky 89272407Shselasky#ifdef CONFIG_RFS_ACCEL 90272407Shselasky 91272407Shselaskystruct mlx4_en_filter { 92272407Shselasky struct list_head next; 93272407Shselasky struct work_struct work; 94272407Shselasky 95272407Shselasky u8 ip_proto; 96272407Shselasky __be32 src_ip; 97272407Shselasky __be32 dst_ip; 98272407Shselasky __be16 src_port; 99272407Shselasky __be16 dst_port; 100272407Shselasky 101272407Shselasky int rxq_index; 102272407Shselasky struct mlx4_en_priv *priv; 103272407Shselasky u32 flow_id; /* RFS infrastructure id */ 104272407Shselasky int id; /* mlx4_en driver id */ 105272407Shselasky u64 reg_id; /* Flow steering API id */ 106272407Shselasky u8 activated; /* Used to prevent expiry before filter 107272407Shselasky * is attached 108272407Shselasky */ 109272407Shselasky struct hlist_node filter_chain; 110272407Shselasky}; 111272407Shselasky 112272407Shselaskystatic void mlx4_en_filter_rfs_expire(struct mlx4_en_priv *priv); 113272407Shselasky 114272407Shselaskystatic enum mlx4_net_trans_rule_id mlx4_ip_proto_to_trans_rule_id(u8 ip_proto) 115272407Shselasky{ 116272407Shselasky switch (ip_proto) { 117272407Shselasky case IPPROTO_UDP: 118272407Shselasky return MLX4_NET_TRANS_RULE_ID_UDP; 119272407Shselasky case IPPROTO_TCP: 120272407Shselasky return MLX4_NET_TRANS_RULE_ID_TCP; 121272407Shselasky default: 122272407Shselasky return -EPROTONOSUPPORT; 123272407Shselasky } 124272407Shselasky}; 125272407Shselasky 126272407Shselaskystatic void mlx4_en_filter_work(struct work_struct *work) 127272407Shselasky{ 128272407Shselasky struct mlx4_en_filter *filter = container_of(work, 129272407Shselasky struct mlx4_en_filter, 130272407Shselasky work); 131272407Shselasky struct mlx4_en_priv *priv = filter->priv; 132272407Shselasky struct mlx4_spec_list spec_tcp_udp = { 133272407Shselasky .id = mlx4_ip_proto_to_trans_rule_id(filter->ip_proto), 134272407Shselasky { 135272407Shselasky .tcp_udp = { 136272407Shselasky .dst_port = filter->dst_port, 137272407Shselasky .dst_port_msk = (__force __be16)-1, 138272407Shselasky .src_port = filter->src_port, 139272407Shselasky .src_port_msk = (__force __be16)-1, 140272407Shselasky }, 141272407Shselasky }, 142272407Shselasky }; 143272407Shselasky struct mlx4_spec_list spec_ip = { 144272407Shselasky .id = MLX4_NET_TRANS_RULE_ID_IPV4, 145272407Shselasky { 146272407Shselasky .ipv4 = { 147272407Shselasky .dst_ip = filter->dst_ip, 148272407Shselasky .dst_ip_msk = (__force __be32)-1, 149272407Shselasky .src_ip = filter->src_ip, 150272407Shselasky .src_ip_msk = (__force __be32)-1, 151272407Shselasky }, 152272407Shselasky }, 153272407Shselasky }; 154272407Shselasky struct mlx4_spec_list spec_eth = { 155272407Shselasky .id = MLX4_NET_TRANS_RULE_ID_ETH, 156272407Shselasky }; 157272407Shselasky struct mlx4_net_trans_rule rule = { 158272407Shselasky .list = LIST_HEAD_INIT(rule.list), 159272407Shselasky .queue_mode = MLX4_NET_TRANS_Q_LIFO, 160272407Shselasky .exclusive = 1, 161272407Shselasky .allow_loopback = 1, 162272407Shselasky .promisc_mode = MLX4_FS_REGULAR, 163272407Shselasky .port = priv->port, 164272407Shselasky .priority = MLX4_DOMAIN_RFS, 165272407Shselasky }; 166272407Shselasky int rc; 167272407Shselasky __be64 mac_mask = cpu_to_be64(MLX4_MAC_MASK << 16); 168272407Shselasky 169272407Shselasky if (spec_tcp_udp.id < 0) { 170272407Shselasky en_warn(priv, "RFS: ignoring unsupported ip protocol (%d)\n", 171272407Shselasky filter->ip_proto); 172272407Shselasky goto ignore; 173272407Shselasky } 174272407Shselasky list_add_tail(&spec_eth.list, &rule.list); 175272407Shselasky list_add_tail(&spec_ip.list, &rule.list); 176272407Shselasky list_add_tail(&spec_tcp_udp.list, &rule.list); 177272407Shselasky 178272407Shselasky rule.qpn = priv->rss_map.qps[filter->rxq_index].qpn; 179272407Shselasky memcpy(spec_eth.eth.dst_mac, priv->dev->dev_addr, ETH_ALEN); 180272407Shselasky memcpy(spec_eth.eth.dst_mac_msk, &mac_mask, ETH_ALEN); 181272407Shselasky 182272407Shselasky filter->activated = 0; 183272407Shselasky 184272407Shselasky if (filter->reg_id) { 185272407Shselasky rc = mlx4_flow_detach(priv->mdev->dev, filter->reg_id); 186272407Shselasky if (rc && rc != -ENOENT) 187272407Shselasky en_err(priv, "Error detaching flow. rc = %d\n", rc); 188272407Shselasky } 189272407Shselasky 190272407Shselasky rc = mlx4_flow_attach(priv->mdev->dev, &rule, &filter->reg_id); 191272407Shselasky if (rc) 192272407Shselasky en_err(priv, "Error attaching flow. err = %d\n", rc); 193272407Shselasky 194272407Shselaskyignore: 195272407Shselasky mlx4_en_filter_rfs_expire(priv); 196272407Shselasky 197272407Shselasky filter->activated = 1; 198272407Shselasky} 199272407Shselasky 200272407Shselaskystatic inline struct hlist_head * 201272407Shselaskyfilter_hash_bucket(struct mlx4_en_priv *priv, __be32 src_ip, __be32 dst_ip, 202272407Shselasky __be16 src_port, __be16 dst_port) 203272407Shselasky{ 204272407Shselasky unsigned long l; 205272407Shselasky int bucket_idx; 206272407Shselasky 207272407Shselasky l = (__force unsigned long)src_port | 208272407Shselasky ((__force unsigned long)dst_port << 2); 209272407Shselasky l ^= (__force unsigned long)(src_ip ^ dst_ip); 210272407Shselasky 211272407Shselasky bucket_idx = hash_long(l, MLX4_EN_FILTER_HASH_SHIFT); 212272407Shselasky 213272407Shselasky return &priv->filter_hash[bucket_idx]; 214272407Shselasky} 215272407Shselasky 216272407Shselaskystatic struct mlx4_en_filter * 217272407Shselaskymlx4_en_filter_alloc(struct mlx4_en_priv *priv, int rxq_index, __be32 src_ip, 218272407Shselasky __be32 dst_ip, u8 ip_proto, __be16 src_port, 219272407Shselasky __be16 dst_port, u32 flow_id) 220272407Shselasky{ 221272407Shselasky struct mlx4_en_filter *filter = NULL; 222272407Shselasky 223272407Shselasky filter = kzalloc(sizeof(struct mlx4_en_filter), GFP_ATOMIC); 224272407Shselasky if (!filter) 225272407Shselasky return NULL; 226272407Shselasky 227272407Shselasky filter->priv = priv; 228272407Shselasky filter->rxq_index = rxq_index; 229272407Shselasky INIT_WORK(&filter->work, mlx4_en_filter_work); 230272407Shselasky 231272407Shselasky filter->src_ip = src_ip; 232272407Shselasky filter->dst_ip = dst_ip; 233272407Shselasky filter->ip_proto = ip_proto; 234272407Shselasky filter->src_port = src_port; 235272407Shselasky filter->dst_port = dst_port; 236272407Shselasky 237272407Shselasky filter->flow_id = flow_id; 238272407Shselasky 239272407Shselasky filter->id = priv->last_filter_id++ % RPS_NO_FILTER; 240272407Shselasky 241272407Shselasky list_add_tail(&filter->next, &priv->filters); 242272407Shselasky hlist_add_head(&filter->filter_chain, 243272407Shselasky filter_hash_bucket(priv, src_ip, dst_ip, src_port, 244272407Shselasky dst_port)); 245272407Shselasky 246272407Shselasky return filter; 247272407Shselasky} 248272407Shselasky 249272407Shselaskystatic void mlx4_en_filter_free(struct mlx4_en_filter *filter) 250272407Shselasky{ 251272407Shselasky struct mlx4_en_priv *priv = filter->priv; 252272407Shselasky int rc; 253272407Shselasky 254272407Shselasky list_del(&filter->next); 255272407Shselasky 256272407Shselasky rc = mlx4_flow_detach(priv->mdev->dev, filter->reg_id); 257272407Shselasky if (rc && rc != -ENOENT) 258272407Shselasky en_err(priv, "Error detaching flow. rc = %d\n", rc); 259272407Shselasky 260272407Shselasky kfree(filter); 261272407Shselasky} 262272407Shselasky 263272407Shselaskystatic inline struct mlx4_en_filter * 264272407Shselaskymlx4_en_filter_find(struct mlx4_en_priv *priv, __be32 src_ip, __be32 dst_ip, 265272407Shselasky u8 ip_proto, __be16 src_port, __be16 dst_port) 266272407Shselasky{ 267272407Shselasky struct hlist_node *elem; 268272407Shselasky struct mlx4_en_filter *filter; 269272407Shselasky struct mlx4_en_filter *ret = NULL; 270272407Shselasky 271272407Shselasky hlist_for_each_entry(filter, elem, 272272407Shselasky filter_hash_bucket(priv, src_ip, dst_ip, 273272407Shselasky src_port, dst_port), 274272407Shselasky filter_chain) { 275272407Shselasky if (filter->src_ip == src_ip && 276272407Shselasky filter->dst_ip == dst_ip && 277272407Shselasky filter->ip_proto == ip_proto && 278272407Shselasky filter->src_port == src_port && 279272407Shselasky filter->dst_port == dst_port) { 280272407Shselasky ret = filter; 281272407Shselasky break; 282272407Shselasky } 283272407Shselasky } 284272407Shselasky 285272407Shselasky return ret; 286272407Shselasky} 287272407Shselasky 288272407Shselaskystatic int 289272407Shselaskymlx4_en_filter_rfs(struct net_device *net_dev, const struct sk_buff *skb, 290272407Shselasky u16 rxq_index, u32 flow_id) 291272407Shselasky{ 292272407Shselasky struct mlx4_en_priv *priv = netdev_priv(net_dev); 293272407Shselasky struct mlx4_en_filter *filter; 294272407Shselasky const struct iphdr *ip; 295272407Shselasky const __be16 *ports; 296272407Shselasky u8 ip_proto; 297272407Shselasky __be32 src_ip; 298272407Shselasky __be32 dst_ip; 299272407Shselasky __be16 src_port; 300272407Shselasky __be16 dst_port; 301272407Shselasky int nhoff = skb_network_offset(skb); 302272407Shselasky int ret = 0; 303272407Shselasky 304272407Shselasky if (skb->protocol != htons(ETH_P_IP)) 305272407Shselasky return -EPROTONOSUPPORT; 306272407Shselasky 307272407Shselasky ip = (const struct iphdr *)(skb->data + nhoff); 308272407Shselasky if (ip_is_fragment(ip)) 309272407Shselasky return -EPROTONOSUPPORT; 310272407Shselasky 311272407Shselasky if ((ip->protocol != IPPROTO_TCP) && (ip->protocol != IPPROTO_UDP)) 312272407Shselasky return -EPROTONOSUPPORT; 313272407Shselasky ports = (const __be16 *)(skb->data + nhoff + 4 * ip->ihl); 314272407Shselasky 315272407Shselasky ip_proto = ip->protocol; 316272407Shselasky src_ip = ip->saddr; 317272407Shselasky dst_ip = ip->daddr; 318272407Shselasky src_port = ports[0]; 319272407Shselasky dst_port = ports[1]; 320272407Shselasky 321272407Shselasky spin_lock_bh(&priv->filters_lock); 322272407Shselasky filter = mlx4_en_filter_find(priv, src_ip, dst_ip, ip_proto, 323272407Shselasky src_port, dst_port); 324272407Shselasky if (filter) { 325272407Shselasky if (filter->rxq_index == rxq_index) 326272407Shselasky goto out; 327272407Shselasky 328272407Shselasky filter->rxq_index = rxq_index; 329272407Shselasky } else { 330272407Shselasky filter = mlx4_en_filter_alloc(priv, rxq_index, 331272407Shselasky src_ip, dst_ip, ip_proto, 332272407Shselasky src_port, dst_port, flow_id); 333272407Shselasky if (!filter) { 334272407Shselasky ret = -ENOMEM; 335272407Shselasky goto err; 336272407Shselasky } 337272407Shselasky } 338272407Shselasky 339272407Shselasky queue_work(priv->mdev->workqueue, &filter->work); 340272407Shselasky 341272407Shselaskyout: 342272407Shselasky ret = filter->id; 343272407Shselaskyerr: 344272407Shselasky spin_unlock_bh(&priv->filters_lock); 345272407Shselasky 346272407Shselasky return ret; 347272407Shselasky} 348272407Shselasky 349272407Shselaskyvoid mlx4_en_cleanup_filters(struct mlx4_en_priv *priv, 350272407Shselasky struct mlx4_en_rx_ring *rx_ring) 351272407Shselasky{ 352272407Shselasky struct mlx4_en_filter *filter, *tmp; 353272407Shselasky LIST_HEAD(del_list); 354272407Shselasky 355272407Shselasky spin_lock_bh(&priv->filters_lock); 356272407Shselasky list_for_each_entry_safe(filter, tmp, &priv->filters, next) { 357272407Shselasky list_move(&filter->next, &del_list); 358272407Shselasky hlist_del(&filter->filter_chain); 359272407Shselasky } 360272407Shselasky spin_unlock_bh(&priv->filters_lock); 361272407Shselasky 362272407Shselasky list_for_each_entry_safe(filter, tmp, &del_list, next) { 363272407Shselasky cancel_work_sync(&filter->work); 364272407Shselasky mlx4_en_filter_free(filter); 365272407Shselasky } 366272407Shselasky} 367272407Shselasky 368272407Shselaskystatic void mlx4_en_filter_rfs_expire(struct mlx4_en_priv *priv) 369272407Shselasky{ 370272407Shselasky struct mlx4_en_filter *filter = NULL, *tmp, *last_filter = NULL; 371272407Shselasky LIST_HEAD(del_list); 372272407Shselasky int i = 0; 373272407Shselasky 374272407Shselasky spin_lock_bh(&priv->filters_lock); 375272407Shselasky list_for_each_entry_safe(filter, tmp, &priv->filters, next) { 376272407Shselasky if (i > MLX4_EN_FILTER_EXPIRY_QUOTA) 377272407Shselasky break; 378272407Shselasky 379272407Shselasky if (filter->activated && 380272407Shselasky !work_pending(&filter->work) && 381272407Shselasky rps_may_expire_flow(priv->dev, 382272407Shselasky filter->rxq_index, filter->flow_id, 383272407Shselasky filter->id)) { 384272407Shselasky list_move(&filter->next, &del_list); 385272407Shselasky hlist_del(&filter->filter_chain); 386272407Shselasky } else 387272407Shselasky last_filter = filter; 388272407Shselasky 389272407Shselasky i++; 390272407Shselasky } 391272407Shselasky 392272407Shselasky if (last_filter && (&last_filter->next != priv->filters.next)) 393272407Shselasky list_move(&priv->filters, &last_filter->next); 394272407Shselasky 395272407Shselasky spin_unlock_bh(&priv->filters_lock); 396272407Shselasky 397272407Shselasky list_for_each_entry_safe(filter, tmp, &del_list, next) 398272407Shselasky mlx4_en_filter_free(filter); 399272407Shselasky} 400272407Shselasky#endif 401272407Shselasky 402219820Sjeffstatic void mlx4_en_vlan_rx_add_vid(void *arg, struct net_device *dev, u16 vid) 403219820Sjeff{ 404219820Sjeff struct mlx4_en_priv *priv = netdev_priv(dev); 405272407Shselasky struct mlx4_en_dev *mdev = priv->mdev; 406272407Shselasky int err; 407219820Sjeff int idx; 408219820Sjeff 409258280Salfred if (arg != priv) 410258280Salfred return; 411258280Salfred 412219820Sjeff en_dbg(HW, priv, "adding VLAN:%d\n", vid); 413272407Shselasky 414272407Shselasky set_bit(vid, priv->active_vlans); 415272407Shselasky 416272407Shselasky /* Add VID to port VLAN filter */ 417272407Shselasky mutex_lock(&mdev->state_lock); 418272407Shselasky if (mdev->device_up && priv->port_up) { 419272407Shselasky err = mlx4_SET_VLAN_FLTR(mdev->dev, priv); 420272407Shselasky if (err) 421272407Shselasky en_err(priv, "Failed configuring VLAN filter\n"); 422272407Shselasky } 423272407Shselasky if (mlx4_register_vlan(mdev->dev, priv->port, vid, &idx)) 424272407Shselasky en_dbg(HW, priv, "failed adding vlan %d\n", vid); 425272407Shselasky mutex_unlock(&mdev->state_lock); 426272407Shselasky 427219820Sjeff} 428219820Sjeff 429219820Sjeffstatic void mlx4_en_vlan_rx_kill_vid(void *arg, struct net_device *dev, u16 vid) 430219820Sjeff{ 431219820Sjeff struct mlx4_en_priv *priv = netdev_priv(dev); 432272407Shselasky struct mlx4_en_dev *mdev = priv->mdev; 433272407Shselasky int err; 434219820Sjeff 435258280Salfred if (arg != priv) 436258280Salfred return; 437258280Salfred 438219820Sjeff en_dbg(HW, priv, "Killing VID:%d\n", vid); 439272407Shselasky 440272407Shselasky clear_bit(vid, priv->active_vlans); 441272407Shselasky 442272407Shselasky /* Remove VID from port VLAN filter */ 443272407Shselasky mutex_lock(&mdev->state_lock); 444272407Shselasky mlx4_unregister_vlan(mdev->dev, priv->port, vid); 445272407Shselasky 446272407Shselasky if (mdev->device_up && priv->port_up) { 447272407Shselasky err = mlx4_SET_VLAN_FLTR(mdev->dev, priv); 448272407Shselasky if (err) 449272407Shselasky en_err(priv, "Failed configuring VLAN filter\n"); 450272407Shselasky } 451272407Shselasky mutex_unlock(&mdev->state_lock); 452272407Shselasky 453219820Sjeff} 454219820Sjeff 455272407Shselaskystatic int mlx4_en_uc_steer_add(struct mlx4_en_priv *priv, 456272407Shselasky unsigned char *mac, int *qpn, u64 *reg_id) 457219820Sjeff{ 458272407Shselasky struct mlx4_en_dev *mdev = priv->mdev; 459272407Shselasky struct mlx4_dev *dev = mdev->dev; 460272407Shselasky int err; 461219820Sjeff 462272407Shselasky switch (dev->caps.steering_mode) { 463272407Shselasky case MLX4_STEERING_MODE_B0: { 464272407Shselasky struct mlx4_qp qp; 465272407Shselasky u8 gid[16] = {0}; 466272407Shselasky 467272407Shselasky qp.qpn = *qpn; 468272407Shselasky memcpy(&gid[10], mac, ETH_ALEN); 469272407Shselasky gid[5] = priv->port; 470272407Shselasky 471272407Shselasky err = mlx4_unicast_attach(dev, &qp, gid, 0, MLX4_PROT_ETH); 472272407Shselasky break; 473219820Sjeff } 474272407Shselasky case MLX4_STEERING_MODE_DEVICE_MANAGED: { 475272407Shselasky struct mlx4_spec_list spec_eth = { {NULL} }; 476272407Shselasky __be64 mac_mask = cpu_to_be64(MLX4_MAC_MASK << 16); 477272407Shselasky 478272407Shselasky struct mlx4_net_trans_rule rule = { 479272407Shselasky .queue_mode = MLX4_NET_TRANS_Q_FIFO, 480272407Shselasky .exclusive = 0, 481272407Shselasky .allow_loopback = 1, 482272407Shselasky .promisc_mode = MLX4_FS_REGULAR, 483272407Shselasky .priority = MLX4_DOMAIN_NIC, 484272407Shselasky }; 485272407Shselasky 486272407Shselasky rule.port = priv->port; 487272407Shselasky rule.qpn = *qpn; 488272407Shselasky INIT_LIST_HEAD(&rule.list); 489272407Shselasky 490272407Shselasky spec_eth.id = MLX4_NET_TRANS_RULE_ID_ETH; 491272407Shselasky memcpy(spec_eth.eth.dst_mac, mac, ETH_ALEN); 492272407Shselasky memcpy(spec_eth.eth.dst_mac_msk, &mac_mask, ETH_ALEN); 493272407Shselasky list_add_tail(&spec_eth.list, &rule.list); 494272407Shselasky 495272407Shselasky err = mlx4_flow_attach(dev, &rule, reg_id); 496272407Shselasky break; 497272407Shselasky } 498272407Shselasky default: 499272407Shselasky return -EINVAL; 500272407Shselasky } 501272407Shselasky if (err) 502272407Shselasky en_warn(priv, "Failed Attaching Unicast\n"); 503272407Shselasky 504272407Shselasky return err; 505219820Sjeff} 506219820Sjeff 507272407Shselaskystatic void mlx4_en_uc_steer_release(struct mlx4_en_priv *priv, 508272407Shselasky unsigned char *mac, int qpn, u64 reg_id) 509219820Sjeff{ 510272407Shselasky struct mlx4_en_dev *mdev = priv->mdev; 511272407Shselasky struct mlx4_dev *dev = mdev->dev; 512219820Sjeff 513272407Shselasky switch (dev->caps.steering_mode) { 514272407Shselasky case MLX4_STEERING_MODE_B0: { 515272407Shselasky struct mlx4_qp qp; 516272407Shselasky u8 gid[16] = {0}; 517272407Shselasky 518272407Shselasky qp.qpn = qpn; 519272407Shselasky memcpy(&gid[10], mac, ETH_ALEN); 520272407Shselasky gid[5] = priv->port; 521272407Shselasky 522272407Shselasky mlx4_unicast_detach(dev, &qp, gid, MLX4_PROT_ETH); 523272407Shselasky break; 524219820Sjeff } 525272407Shselasky case MLX4_STEERING_MODE_DEVICE_MANAGED: { 526272407Shselasky mlx4_flow_detach(dev, reg_id); 527272407Shselasky break; 528272407Shselasky } 529272407Shselasky default: 530272407Shselasky en_err(priv, "Invalid steering mode.\n"); 531272407Shselasky } 532272407Shselasky} 533272407Shselasky 534272407Shselaskystatic int mlx4_en_get_qp(struct mlx4_en_priv *priv) 535272407Shselasky{ 536272407Shselasky struct mlx4_en_dev *mdev = priv->mdev; 537272407Shselasky struct mlx4_dev *dev = mdev->dev; 538272407Shselasky struct mlx4_mac_entry *entry; 539272407Shselasky int index = 0; 540272407Shselasky int err = 0; 541272407Shselasky u64 reg_id; 542272407Shselasky int *qpn = &priv->base_qpn; 543272407Shselasky u64 mac = mlx4_mac_to_u64(IF_LLADDR(priv->dev)); 544272407Shselasky 545272407Shselasky en_dbg(DRV, priv, "Registering MAC: %pM for adding\n", 546272407Shselasky IF_LLADDR(priv->dev)); 547272407Shselasky index = mlx4_register_mac(dev, priv->port, mac); 548272407Shselasky if (index < 0) { 549272407Shselasky err = index; 550272407Shselasky en_err(priv, "Failed adding MAC: %pM\n", 551272407Shselasky IF_LLADDR(priv->dev)); 552272407Shselasky return err; 553272407Shselasky } 554272407Shselasky 555272407Shselasky if (dev->caps.steering_mode == MLX4_STEERING_MODE_A0) { 556272407Shselasky int base_qpn = mlx4_get_base_qpn(dev, priv->port); 557272407Shselasky *qpn = base_qpn + index; 558272407Shselasky return 0; 559272407Shselasky } 560272407Shselasky 561272407Shselasky err = mlx4_qp_reserve_range(dev, 1, 1, qpn, 0); 562272407Shselasky en_dbg(DRV, priv, "Reserved qp %d\n", *qpn); 563272407Shselasky if (err) { 564272407Shselasky en_err(priv, "Failed to reserve qp for mac registration\n"); 565272407Shselasky goto qp_err; 566272407Shselasky } 567272407Shselasky 568272407Shselasky err = mlx4_en_uc_steer_add(priv, IF_LLADDR(priv->dev), qpn, ®_id); 569272407Shselasky if (err) 570272407Shselasky goto steer_err; 571272407Shselasky 572272407Shselasky entry = kmalloc(sizeof(*entry), GFP_KERNEL); 573272407Shselasky if (!entry) { 574272407Shselasky err = -ENOMEM; 575272407Shselasky goto alloc_err; 576272407Shselasky } 577272407Shselasky memcpy(entry->mac, IF_LLADDR(priv->dev), sizeof(entry->mac)); 578272407Shselasky entry->reg_id = reg_id; 579272407Shselasky 580272407Shselasky hlist_add_head(&entry->hlist, 581272407Shselasky &priv->mac_hash[entry->mac[MLX4_EN_MAC_HASH_IDX]]); 582272407Shselasky 583272407Shselasky return 0; 584272407Shselasky 585272407Shselaskyalloc_err: 586272407Shselasky mlx4_en_uc_steer_release(priv, IF_LLADDR(priv->dev), *qpn, reg_id); 587272407Shselasky 588272407Shselaskysteer_err: 589272407Shselasky mlx4_qp_release_range(dev, *qpn, 1); 590272407Shselasky 591272407Shselaskyqp_err: 592272407Shselasky mlx4_unregister_mac(dev, priv->port, mac); 593272407Shselasky return err; 594272407Shselasky} 595272407Shselasky 596272407Shselaskystatic void mlx4_en_put_qp(struct mlx4_en_priv *priv) 597272407Shselasky{ 598272407Shselasky struct mlx4_en_dev *mdev = priv->mdev; 599272407Shselasky struct mlx4_dev *dev = mdev->dev; 600272407Shselasky int qpn = priv->base_qpn; 601272407Shselasky u64 mac; 602272407Shselasky 603272407Shselasky if (dev->caps.steering_mode == MLX4_STEERING_MODE_A0) { 604272407Shselasky mac = mlx4_mac_to_u64(IF_LLADDR(priv->dev)); 605272407Shselasky en_dbg(DRV, priv, "Registering MAC: %pM for deleting\n", 606272407Shselasky IF_LLADDR(priv->dev)); 607272407Shselasky mlx4_unregister_mac(dev, priv->port, mac); 608272407Shselasky } else { 609272407Shselasky struct mlx4_mac_entry *entry; 610272407Shselasky struct hlist_node *n, *tmp; 611272407Shselasky struct hlist_head *bucket; 612272407Shselasky unsigned int i; 613272407Shselasky 614272407Shselasky for (i = 0; i < MLX4_EN_MAC_HASH_SIZE; ++i) { 615272407Shselasky bucket = &priv->mac_hash[i]; 616272407Shselasky hlist_for_each_entry_safe(entry, n, tmp, bucket, hlist) { 617272407Shselasky mac = mlx4_mac_to_u64(entry->mac); 618272407Shselasky en_dbg(DRV, priv, "Registering MAC: %pM for deleting\n", 619272407Shselasky entry->mac); 620272407Shselasky mlx4_en_uc_steer_release(priv, entry->mac, 621272407Shselasky qpn, entry->reg_id); 622272407Shselasky 623272407Shselasky mlx4_unregister_mac(dev, priv->port, mac); 624272407Shselasky hlist_del(&entry->hlist); 625272407Shselasky kfree(entry); 626272407Shselasky } 627219820Sjeff } 628272407Shselasky 629272407Shselasky en_dbg(DRV, priv, "Releasing qp: port %d, qpn %d\n", 630272407Shselasky priv->port, qpn); 631272407Shselasky mlx4_qp_release_range(dev, qpn, 1); 632272407Shselasky priv->flags &= ~MLX4_EN_FLAG_FORCE_PROMISC; 633219820Sjeff } 634219820Sjeff} 635219820Sjeff 636272407Shselaskystatic void mlx4_en_clear_list(struct net_device *dev) 637259608Salfred{ 638259608Salfred struct mlx4_en_priv *priv = netdev_priv(dev); 639272407Shselasky struct mlx4_en_mc_list *tmp, *mc_to_del; 640272407Shselasky 641272407Shselasky list_for_each_entry_safe(mc_to_del, tmp, &priv->mc_list, list) { 642272407Shselasky list_del(&mc_to_del->list); 643272407Shselasky kfree(mc_to_del); 644272407Shselasky } 645259608Salfred} 646219820Sjeff 647272407Shselaskystatic void mlx4_en_cache_mclist(struct net_device *dev) 648259608Salfred{ 649272407Shselasky struct ifmultiaddr *ifma; 650272407Shselasky struct mlx4_en_mc_list *tmp; 651259608Salfred struct mlx4_en_priv *priv = netdev_priv(dev); 652259608Salfred 653283175Shselasky if_maddr_rlock(dev); 654272407Shselasky TAILQ_FOREACH(ifma, &dev->if_multiaddrs, ifma_link) { 655272407Shselasky if (ifma->ifma_addr->sa_family != AF_LINK) 656272407Shselasky continue; 657272407Shselasky if (((struct sockaddr_dl *)ifma->ifma_addr)->sdl_alen != 658272407Shselasky ETHER_ADDR_LEN) 659272407Shselasky continue; 660272407Shselasky /* Make sure the list didn't grow. */ 661272407Shselasky tmp = kzalloc(sizeof(struct mlx4_en_mc_list), GFP_ATOMIC); 662292107Shselasky if (tmp == NULL) { 663292107Shselasky en_err(priv, "Failed to allocate multicast list\n"); 664283175Shselasky break; 665292107Shselasky } 666272407Shselasky memcpy(tmp->addr, 667272407Shselasky LLADDR((struct sockaddr_dl *)ifma->ifma_addr), ETH_ALEN); 668272407Shselasky list_add_tail(&tmp->list, &priv->mc_list); 669272407Shselasky } 670283175Shselasky if_maddr_runlock(dev); 671259608Salfred} 672259608Salfred 673272407Shselaskystatic void update_mclist_flags(struct mlx4_en_priv *priv, 674272407Shselasky struct list_head *dst, 675272407Shselasky struct list_head *src) 676219820Sjeff{ 677272407Shselasky struct mlx4_en_mc_list *dst_tmp, *src_tmp, *new_mc; 678272407Shselasky bool found; 679272407Shselasky 680272407Shselasky /* Find all the entries that should be removed from dst, 681272407Shselasky * These are the entries that are not found in src 682272407Shselasky */ 683272407Shselasky list_for_each_entry(dst_tmp, dst, list) { 684272407Shselasky found = false; 685272407Shselasky list_for_each_entry(src_tmp, src, list) { 686272407Shselasky if (!memcmp(dst_tmp->addr, src_tmp->addr, ETH_ALEN)) { 687272407Shselasky found = true; 688272407Shselasky break; 689272407Shselasky } 690272407Shselasky } 691272407Shselasky if (!found) 692272407Shselasky dst_tmp->action = MCLIST_REM; 693272407Shselasky } 694272407Shselasky 695272407Shselasky /* Add entries that exist in src but not in dst 696272407Shselasky * mark them as need to add 697272407Shselasky */ 698272407Shselasky list_for_each_entry(src_tmp, src, list) { 699272407Shselasky found = false; 700272407Shselasky list_for_each_entry(dst_tmp, dst, list) { 701272407Shselasky if (!memcmp(dst_tmp->addr, src_tmp->addr, ETH_ALEN)) { 702272407Shselasky dst_tmp->action = MCLIST_NONE; 703272407Shselasky found = true; 704272407Shselasky break; 705272407Shselasky } 706272407Shselasky } 707272407Shselasky if (!found) { 708272407Shselasky new_mc = kmalloc(sizeof(struct mlx4_en_mc_list), 709272407Shselasky GFP_KERNEL); 710272407Shselasky if (!new_mc) { 711272407Shselasky en_err(priv, "Failed to allocate current multicast list\n"); 712272407Shselasky return; 713272407Shselasky } 714272407Shselasky memcpy(new_mc, src_tmp, 715272407Shselasky sizeof(struct mlx4_en_mc_list)); 716272407Shselasky new_mc->action = MCLIST_ADD; 717272407Shselasky list_add_tail(&new_mc->list, dst); 718272407Shselasky } 719272407Shselasky } 720272407Shselasky} 721272407Shselasky 722272407Shselaskystatic void mlx4_en_set_rx_mode(struct net_device *dev) 723272407Shselasky{ 724219820Sjeff struct mlx4_en_priv *priv = netdev_priv(dev); 725219820Sjeff 726219820Sjeff if (!priv->port_up) 727219820Sjeff return; 728219820Sjeff 729272407Shselasky queue_work(priv->mdev->workqueue, &priv->rx_mode_task); 730219820Sjeff} 731219820Sjeff 732272407Shselaskystatic void mlx4_en_set_promisc_mode(struct mlx4_en_priv *priv, 733272407Shselasky struct mlx4_en_dev *mdev) 734219820Sjeff{ 735272407Shselasky int err = 0; 736272407Shselasky if (!(priv->flags & MLX4_EN_FLAG_PROMISC)) { 737272407Shselasky priv->flags |= MLX4_EN_FLAG_PROMISC; 738219820Sjeff 739272407Shselasky /* Enable promiscouos mode */ 740272407Shselasky switch (mdev->dev->caps.steering_mode) { 741272407Shselasky case MLX4_STEERING_MODE_DEVICE_MANAGED: 742272407Shselasky err = mlx4_flow_steer_promisc_add(mdev->dev, 743272407Shselasky priv->port, 744272407Shselasky priv->base_qpn, 745272407Shselasky MLX4_FS_ALL_DEFAULT); 746219820Sjeff if (err) 747272407Shselasky en_err(priv, "Failed enabling promiscuous mode\n"); 748272407Shselasky priv->flags |= MLX4_EN_FLAG_MC_PROMISC; 749272407Shselasky break; 750219820Sjeff 751272407Shselasky case MLX4_STEERING_MODE_B0: 752272407Shselasky err = mlx4_unicast_promisc_add(mdev->dev, 753272407Shselasky priv->base_qpn, 754272407Shselasky priv->port); 755219820Sjeff if (err) 756272407Shselasky en_err(priv, "Failed enabling unicast promiscuous mode\n"); 757219820Sjeff 758272407Shselasky /* Add the default qp number as multicast 759272407Shselasky * promisc 760272407Shselasky */ 761272407Shselasky if (!(priv->flags & MLX4_EN_FLAG_MC_PROMISC)) { 762272407Shselasky err = mlx4_multicast_promisc_add(mdev->dev, 763272407Shselasky priv->base_qpn, 764272407Shselasky priv->port); 765272407Shselasky if (err) 766272407Shselasky en_err(priv, "Failed enabling multicast promiscuous mode\n"); 767272407Shselasky priv->flags |= MLX4_EN_FLAG_MC_PROMISC; 768272407Shselasky } 769272407Shselasky break; 770272407Shselasky 771272407Shselasky case MLX4_STEERING_MODE_A0: 772272407Shselasky err = mlx4_SET_PORT_qpn_calc(mdev->dev, 773272407Shselasky priv->port, 774272407Shselasky priv->base_qpn, 775272407Shselasky 1); 776219820Sjeff if (err) 777272407Shselasky en_err(priv, "Failed enabling promiscuous mode\n"); 778272407Shselasky break; 779219820Sjeff } 780272407Shselasky 781272407Shselasky /* Disable port multicast filter (unconditionally) */ 782272407Shselasky err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0, 783272407Shselasky 0, MLX4_MCAST_DISABLE); 784272407Shselasky if (err) 785272407Shselasky en_err(priv, "Failed disabling multicast filter\n"); 786219820Sjeff } 787272407Shselasky} 788219820Sjeff 789272407Shselaskystatic void mlx4_en_clear_promisc_mode(struct mlx4_en_priv *priv, 790272407Shselasky struct mlx4_en_dev *mdev) 791272407Shselasky{ 792272407Shselasky int err = 0; 793219820Sjeff 794272407Shselasky priv->flags &= ~MLX4_EN_FLAG_PROMISC; 795219820Sjeff 796272407Shselasky /* Disable promiscouos mode */ 797272407Shselasky switch (mdev->dev->caps.steering_mode) { 798272407Shselasky case MLX4_STEERING_MODE_DEVICE_MANAGED: 799272407Shselasky err = mlx4_flow_steer_promisc_remove(mdev->dev, 800272407Shselasky priv->port, 801272407Shselasky MLX4_FS_ALL_DEFAULT); 802219820Sjeff if (err) 803272407Shselasky en_err(priv, "Failed disabling promiscuous mode\n"); 804272407Shselasky priv->flags &= ~MLX4_EN_FLAG_MC_PROMISC; 805272407Shselasky break; 806219820Sjeff 807272407Shselasky case MLX4_STEERING_MODE_B0: 808272407Shselasky err = mlx4_unicast_promisc_remove(mdev->dev, 809272407Shselasky priv->base_qpn, 810272407Shselasky priv->port); 811219820Sjeff if (err) 812272407Shselasky en_err(priv, "Failed disabling unicast promiscuous mode\n"); 813272407Shselasky /* Disable Multicast promisc */ 814272407Shselasky if (priv->flags & MLX4_EN_FLAG_MC_PROMISC) { 815272407Shselasky err = mlx4_multicast_promisc_remove(mdev->dev, 816272407Shselasky priv->base_qpn, 817272407Shselasky priv->port); 818272407Shselasky if (err) 819272407Shselasky en_err(priv, "Failed disabling multicast promiscuous mode\n"); 820272407Shselasky priv->flags &= ~MLX4_EN_FLAG_MC_PROMISC; 821272407Shselasky } 822272407Shselasky break; 823272407Shselasky 824272407Shselasky case MLX4_STEERING_MODE_A0: 825272407Shselasky err = mlx4_SET_PORT_qpn_calc(mdev->dev, 826272407Shselasky priv->port, 827272407Shselasky priv->base_qpn, 0); 828272407Shselasky if (err) 829272407Shselasky en_err(priv, "Failed disabling promiscuous mode\n"); 830272407Shselasky break; 831219820Sjeff } 832272407Shselasky} 833219820Sjeff 834272407Shselaskystatic void mlx4_en_do_multicast(struct mlx4_en_priv *priv, 835272407Shselasky struct net_device *dev, 836272407Shselasky struct mlx4_en_dev *mdev) 837272407Shselasky{ 838272407Shselasky struct mlx4_en_mc_list *mclist, *tmp; 839272407Shselasky u8 mc_list[16] = {0}; 840272407Shselasky int err = 0; 841272407Shselasky u64 mcast_addr = 0; 842272407Shselasky 843272407Shselasky 844219820Sjeff /* Enable/disable the multicast filter according to IFF_ALLMULTI */ 845219820Sjeff if (dev->if_flags & IFF_ALLMULTI) { 846219820Sjeff err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0, 847219820Sjeff 0, MLX4_MCAST_DISABLE); 848219820Sjeff if (err) 849219820Sjeff en_err(priv, "Failed disabling multicast filter\n"); 850272407Shselasky 851272407Shselasky /* Add the default qp number as multicast promisc */ 852272407Shselasky if (!(priv->flags & MLX4_EN_FLAG_MC_PROMISC)) { 853272407Shselasky switch (mdev->dev->caps.steering_mode) { 854272407Shselasky case MLX4_STEERING_MODE_DEVICE_MANAGED: 855272407Shselasky err = mlx4_flow_steer_promisc_add(mdev->dev, 856272407Shselasky priv->port, 857272407Shselasky priv->base_qpn, 858272407Shselasky MLX4_FS_MC_DEFAULT); 859272407Shselasky break; 860272407Shselasky 861272407Shselasky case MLX4_STEERING_MODE_B0: 862272407Shselasky err = mlx4_multicast_promisc_add(mdev->dev, 863272407Shselasky priv->base_qpn, 864272407Shselasky priv->port); 865272407Shselasky break; 866272407Shselasky 867272407Shselasky case MLX4_STEERING_MODE_A0: 868272407Shselasky break; 869272407Shselasky } 870272407Shselasky if (err) 871272407Shselasky en_err(priv, "Failed entering multicast promisc mode\n"); 872272407Shselasky priv->flags |= MLX4_EN_FLAG_MC_PROMISC; 873272407Shselasky } 874219820Sjeff } else { 875272407Shselasky /* Disable Multicast promisc */ 876272407Shselasky if (priv->flags & MLX4_EN_FLAG_MC_PROMISC) { 877272407Shselasky switch (mdev->dev->caps.steering_mode) { 878272407Shselasky case MLX4_STEERING_MODE_DEVICE_MANAGED: 879272407Shselasky err = mlx4_flow_steer_promisc_remove(mdev->dev, 880272407Shselasky priv->port, 881272407Shselasky MLX4_FS_MC_DEFAULT); 882272407Shselasky break; 883219820Sjeff 884272407Shselasky case MLX4_STEERING_MODE_B0: 885272407Shselasky err = mlx4_multicast_promisc_remove(mdev->dev, 886272407Shselasky priv->base_qpn, 887272407Shselasky priv->port); 888272407Shselasky break; 889272407Shselasky 890272407Shselasky case MLX4_STEERING_MODE_A0: 891272407Shselasky break; 892272407Shselasky } 893272407Shselasky if (err) 894272407Shselasky en_err(priv, "Failed disabling multicast promiscuous mode\n"); 895272407Shselasky priv->flags &= ~MLX4_EN_FLAG_MC_PROMISC; 896272407Shselasky } 897272407Shselasky 898219820Sjeff err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0, 899219820Sjeff 0, MLX4_MCAST_DISABLE); 900219820Sjeff if (err) 901219820Sjeff en_err(priv, "Failed disabling multicast filter\n"); 902219820Sjeff 903219820Sjeff /* Flush mcast filter and init it with broadcast address */ 904219820Sjeff mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, ETH_BCAST, 905219820Sjeff 1, MLX4_MCAST_CONFIG); 906219820Sjeff 907219820Sjeff /* Update multicast list - we cache all addresses so they won't 908219820Sjeff * change while HW is updated holding the command semaphor */ 909272407Shselasky mlx4_en_cache_mclist(dev); 910272407Shselasky list_for_each_entry(mclist, &priv->mc_list, list) { 911272407Shselasky mcast_addr = mlx4_mac_to_u64(mclist->addr); 912219820Sjeff mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 913272407Shselasky mcast_addr, 0, MLX4_MCAST_CONFIG); 914272407Shselasky } 915219820Sjeff err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0, 916219820Sjeff 0, MLX4_MCAST_ENABLE); 917219820Sjeff if (err) 918219820Sjeff en_err(priv, "Failed enabling multicast filter\n"); 919219820Sjeff 920272407Shselasky update_mclist_flags(priv, &priv->curr_list, &priv->mc_list); 921272407Shselasky list_for_each_entry_safe(mclist, tmp, &priv->curr_list, list) { 922272407Shselasky if (mclist->action == MCLIST_REM) { 923272407Shselasky /* detach this address and delete from list */ 924272407Shselasky memcpy(&mc_list[10], mclist->addr, ETH_ALEN); 925272407Shselasky mc_list[5] = priv->port; 926272407Shselasky err = mlx4_multicast_detach(mdev->dev, 927272407Shselasky &priv->rss_map.indir_qp, 928272407Shselasky mc_list, 929272407Shselasky MLX4_PROT_ETH, 930272407Shselasky mclist->reg_id); 931272407Shselasky if (err) 932272407Shselasky en_err(priv, "Fail to detach multicast address\n"); 933272407Shselasky 934272407Shselasky /* remove from list */ 935272407Shselasky list_del(&mclist->list); 936272407Shselasky kfree(mclist); 937272407Shselasky } else if (mclist->action == MCLIST_ADD) { 938272407Shselasky /* attach the address */ 939272407Shselasky memcpy(&mc_list[10], mclist->addr, ETH_ALEN); 940272407Shselasky /* needed for B0 steering support */ 941272407Shselasky mc_list[5] = priv->port; 942272407Shselasky err = mlx4_multicast_attach(mdev->dev, 943272407Shselasky &priv->rss_map.indir_qp, 944272407Shselasky mc_list, 945272407Shselasky priv->port, 0, 946272407Shselasky MLX4_PROT_ETH, 947272407Shselasky &mclist->reg_id); 948272407Shselasky if (err) 949272407Shselasky en_err(priv, "Fail to attach multicast address\n"); 950272407Shselasky 951272407Shselasky } 952272407Shselasky } 953219820Sjeff } 954272407Shselasky} 955272407Shselasky 956272407Shselaskystatic void mlx4_en_do_set_rx_mode(struct work_struct *work) 957272407Shselasky{ 958272407Shselasky struct mlx4_en_priv *priv = container_of(work, struct mlx4_en_priv, 959272407Shselasky rx_mode_task); 960272407Shselasky struct mlx4_en_dev *mdev = priv->mdev; 961272407Shselasky struct net_device *dev = priv->dev; 962272407Shselasky 963272407Shselasky 964272407Shselasky mutex_lock(&mdev->state_lock); 965272407Shselasky if (!mdev->device_up) { 966272407Shselasky en_dbg(HW, priv, "Card is not up, ignoring rx mode change.\n"); 967272407Shselasky goto out; 968272407Shselasky } 969272407Shselasky if (!priv->port_up) { 970272407Shselasky en_dbg(HW, priv, "Port is down, ignoring rx mode change.\n"); 971272407Shselasky goto out; 972272407Shselasky } 973272407Shselasky if (!mlx4_en_QUERY_PORT(mdev, priv->port)) { 974272407Shselasky if (priv->port_state.link_state) { 975272407Shselasky priv->last_link_state = MLX4_DEV_EVENT_PORT_UP; 976292107Shselasky /* update netif baudrate */ 977292107Shselasky priv->dev->if_baudrate = 978292107Shselasky IF_Mbps(priv->port_state.link_speed); 979272407Shselasky /* Important note: the following call for if_link_state_change 980272407Shselasky * is needed for interface up scenario (start port, link state 981272407Shselasky * change) */ 982272407Shselasky if_link_state_change(priv->dev, LINK_STATE_UP); 983272407Shselasky en_dbg(HW, priv, "Link Up\n"); 984272407Shselasky } 985272407Shselasky } 986272407Shselasky 987272407Shselasky /* Promsicuous mode: disable all filters */ 988272407Shselasky if ((dev->if_flags & IFF_PROMISC) || 989272407Shselasky (priv->flags & MLX4_EN_FLAG_FORCE_PROMISC)) { 990272407Shselasky mlx4_en_set_promisc_mode(priv, mdev); 991272407Shselasky goto out; 992272407Shselasky } 993272407Shselasky 994272407Shselasky /* Not in promiscuous mode */ 995272407Shselasky if (priv->flags & MLX4_EN_FLAG_PROMISC) 996272407Shselasky mlx4_en_clear_promisc_mode(priv, mdev); 997272407Shselasky 998272407Shselasky mlx4_en_do_multicast(priv, dev, mdev); 999219820Sjeffout: 1000219820Sjeff mutex_unlock(&mdev->state_lock); 1001219820Sjeff} 1002219820Sjeff 1003219820Sjeff#ifdef CONFIG_NET_POLL_CONTROLLER 1004219820Sjeffstatic void mlx4_en_netpoll(struct net_device *dev) 1005219820Sjeff{ 1006219820Sjeff struct mlx4_en_priv *priv = netdev_priv(dev); 1007219820Sjeff struct mlx4_en_cq *cq; 1008219820Sjeff unsigned long flags; 1009219820Sjeff int i; 1010219820Sjeff 1011219820Sjeff for (i = 0; i < priv->rx_ring_num; i++) { 1012272407Shselasky cq = priv->rx_cq[i]; 1013219820Sjeff spin_lock_irqsave(&cq->lock, flags); 1014219820Sjeff napi_synchronize(&cq->napi); 1015219859Sjeff mlx4_en_process_rx_cq(dev, cq, 0); 1016219820Sjeff spin_unlock_irqrestore(&cq->lock, flags); 1017219820Sjeff } 1018219820Sjeff} 1019219820Sjeff#endif 1020219820Sjeff 1021219820Sjeffstatic void mlx4_en_watchdog_timeout(void *arg) 1022219820Sjeff{ 1023272407Shselasky struct mlx4_en_priv *priv = arg; 1024272407Shselasky struct mlx4_en_dev *mdev = priv->mdev; 1025219820Sjeff 1026272407Shselasky en_dbg(DRV, priv, "Scheduling watchdog\n"); 1027272407Shselasky queue_work(mdev->workqueue, &priv->watchdog_task); 1028272407Shselasky if (priv->port_up) 1029272407Shselasky callout_reset(&priv->watchdog_timer, MLX4_EN_WATCHDOG_TIMEOUT, 1030272407Shselasky mlx4_en_watchdog_timeout, priv); 1031219820Sjeff} 1032219820Sjeff 1033219820Sjeff 1034272407Shselasky 1035219820Sjeffstatic void mlx4_en_set_default_moderation(struct mlx4_en_priv *priv) 1036219820Sjeff{ 1037219820Sjeff struct mlx4_en_cq *cq; 1038219820Sjeff int i; 1039219820Sjeff 1040219820Sjeff /* If we haven't received a specific coalescing setting 1041272407Shselasky * (module param), we set the moderation parameters as follows: 1042219820Sjeff * - moder_cnt is set to the number of mtu sized packets to 1043219820Sjeff * satisfy our coelsing target. 1044219820Sjeff * - moder_time is set to a fixed value. 1045219820Sjeff */ 1046219820Sjeff priv->rx_frames = MLX4_EN_RX_COAL_TARGET / priv->dev->if_mtu + 1; 1047219820Sjeff priv->rx_usecs = MLX4_EN_RX_COAL_TIME; 1048272407Shselasky priv->tx_frames = MLX4_EN_TX_COAL_PKTS; 1049272407Shselasky priv->tx_usecs = MLX4_EN_TX_COAL_TIME; 1050272407Shselasky en_dbg(INTR, priv, "Default coalesing params for mtu: %u - " 1051272407Shselasky "rx_frames:%d rx_usecs:%d\n", 1052272407Shselasky (unsigned)priv->dev->if_mtu, priv->rx_frames, priv->rx_usecs); 1053219820Sjeff 1054219820Sjeff /* Setup cq moderation params */ 1055219820Sjeff for (i = 0; i < priv->rx_ring_num; i++) { 1056272407Shselasky cq = priv->rx_cq[i]; 1057219820Sjeff cq->moder_cnt = priv->rx_frames; 1058219820Sjeff cq->moder_time = priv->rx_usecs; 1059257867Salfred priv->last_moder_time[i] = MLX4_EN_AUTO_CONF; 1060257867Salfred priv->last_moder_packets[i] = 0; 1061257867Salfred priv->last_moder_bytes[i] = 0; 1062219820Sjeff } 1063219820Sjeff 1064219820Sjeff for (i = 0; i < priv->tx_ring_num; i++) { 1065272407Shselasky cq = priv->tx_cq[i]; 1066272407Shselasky cq->moder_cnt = priv->tx_frames; 1067272407Shselasky cq->moder_time = priv->tx_usecs; 1068219820Sjeff } 1069219820Sjeff 1070219820Sjeff /* Reset auto-moderation params */ 1071219820Sjeff priv->pkt_rate_low = MLX4_EN_RX_RATE_LOW; 1072219820Sjeff priv->rx_usecs_low = MLX4_EN_RX_COAL_TIME_LOW; 1073219820Sjeff priv->pkt_rate_high = MLX4_EN_RX_RATE_HIGH; 1074219820Sjeff priv->rx_usecs_high = MLX4_EN_RX_COAL_TIME_HIGH; 1075219820Sjeff priv->sample_interval = MLX4_EN_SAMPLE_INTERVAL; 1076219820Sjeff priv->adaptive_rx_coal = 1; 1077219820Sjeff priv->last_moder_jiffies = 0; 1078219820Sjeff priv->last_moder_tx_packets = 0; 1079219820Sjeff} 1080219820Sjeff 1081219820Sjeffstatic void mlx4_en_auto_moderation(struct mlx4_en_priv *priv) 1082219820Sjeff{ 1083219820Sjeff unsigned long period = (unsigned long) (jiffies - priv->last_moder_jiffies); 1084219820Sjeff struct mlx4_en_cq *cq; 1085219820Sjeff unsigned long packets; 1086219820Sjeff unsigned long rate; 1087219820Sjeff unsigned long avg_pkt_size; 1088219820Sjeff unsigned long rx_packets; 1089219820Sjeff unsigned long rx_bytes; 1090219820Sjeff unsigned long rx_pkt_diff; 1091219820Sjeff int moder_time; 1092257867Salfred int ring, err; 1093219820Sjeff 1094219820Sjeff if (!priv->adaptive_rx_coal || period < priv->sample_interval * HZ) 1095219820Sjeff return; 1096272407Shselasky 1097257867Salfred for (ring = 0; ring < priv->rx_ring_num; ring++) { 1098272407Shselasky spin_lock(&priv->stats_lock); 1099272407Shselasky rx_packets = priv->rx_ring[ring]->packets; 1100272407Shselasky rx_bytes = priv->rx_ring[ring]->bytes; 1101257867Salfred spin_unlock(&priv->stats_lock); 1102219820Sjeff 1103257867Salfred rx_pkt_diff = ((unsigned long) (rx_packets - 1104257867Salfred priv->last_moder_packets[ring])); 1105257867Salfred packets = rx_pkt_diff; 1106257867Salfred rate = packets * HZ / period; 1107257867Salfred avg_pkt_size = packets ? ((unsigned long) (rx_bytes - 1108257867Salfred priv->last_moder_bytes[ring])) / packets : 0; 1109219820Sjeff 1110257867Salfred /* Apply auto-moderation only when packet rate 1111272407Shselasky * exceeds a rate that it matters */ 1112257867Salfred if (rate > (MLX4_EN_RX_RATE_THRESH / priv->rx_ring_num) && 1113272407Shselasky avg_pkt_size > MLX4_EN_AVG_PKT_SMALL) { 1114272407Shselasky if (rate < priv->pkt_rate_low) 1115219820Sjeff moder_time = priv->rx_usecs_low; 1116219820Sjeff else if (rate > priv->pkt_rate_high) 1117219820Sjeff moder_time = priv->rx_usecs_high; 1118219820Sjeff else 1119219820Sjeff moder_time = (rate - priv->pkt_rate_low) * 1120219820Sjeff (priv->rx_usecs_high - priv->rx_usecs_low) / 1121219820Sjeff (priv->pkt_rate_high - priv->pkt_rate_low) + 1122219820Sjeff priv->rx_usecs_low; 1123257867Salfred } else { 1124257867Salfred moder_time = priv->rx_usecs_low; 1125219820Sjeff } 1126219820Sjeff 1127257867Salfred if (moder_time != priv->last_moder_time[ring]) { 1128257867Salfred priv->last_moder_time[ring] = moder_time; 1129272407Shselasky cq = priv->rx_cq[ring]; 1130219820Sjeff cq->moder_time = moder_time; 1131219820Sjeff err = mlx4_en_set_cq_moder(priv, cq); 1132257867Salfred if (err) 1133272407Shselasky en_err(priv, "Failed modifying moderation for cq:%d\n", 1134272407Shselasky ring); 1135219820Sjeff } 1136257867Salfred priv->last_moder_packets[ring] = rx_packets; 1137257867Salfred priv->last_moder_bytes[ring] = rx_bytes; 1138219820Sjeff } 1139219820Sjeff 1140219820Sjeff priv->last_moder_jiffies = jiffies; 1141219820Sjeff} 1142219820Sjeff 1143219820Sjeffstatic void mlx4_en_do_get_stats(struct work_struct *work) 1144219820Sjeff{ 1145219820Sjeff struct delayed_work *delay = to_delayed_work(work); 1146219820Sjeff struct mlx4_en_priv *priv = container_of(delay, struct mlx4_en_priv, 1147219820Sjeff stats_task); 1148219820Sjeff struct mlx4_en_dev *mdev = priv->mdev; 1149219820Sjeff int err; 1150219820Sjeff 1151219820Sjeff mutex_lock(&mdev->state_lock); 1152219820Sjeff if (mdev->device_up) { 1153219820Sjeff if (priv->port_up) { 1154272407Shselasky err = mlx4_en_DUMP_ETH_STATS(mdev, priv->port, 0); 1155272407Shselasky if (err) 1156272407Shselasky en_dbg(HW, priv, "Could not update stats\n"); 1157219820Sjeff 1158219820Sjeff mlx4_en_auto_moderation(priv); 1159219820Sjeff } 1160219820Sjeff 1161219820Sjeff queue_delayed_work(mdev->workqueue, &priv->stats_task, STATS_DELAY); 1162219820Sjeff } 1163219820Sjeff mutex_unlock(&mdev->state_lock); 1164219820Sjeff} 1165219820Sjeff 1166272407Shselasky/* mlx4_en_service_task - Run service task for tasks that needed to be done 1167272407Shselasky * periodically 1168272407Shselasky */ 1169272407Shselaskystatic void mlx4_en_service_task(struct work_struct *work) 1170272407Shselasky{ 1171272407Shselasky struct delayed_work *delay = to_delayed_work(work); 1172272407Shselasky struct mlx4_en_priv *priv = container_of(delay, struct mlx4_en_priv, 1173272407Shselasky service_task); 1174272407Shselasky struct mlx4_en_dev *mdev = priv->mdev; 1175272407Shselasky 1176272407Shselasky mutex_lock(&mdev->state_lock); 1177272407Shselasky if (mdev->device_up) { 1178272407Shselasky queue_delayed_work(mdev->workqueue, &priv->service_task, 1179272407Shselasky SERVICE_TASK_DELAY); 1180272407Shselasky } 1181272407Shselasky mutex_unlock(&mdev->state_lock); 1182272407Shselasky} 1183272407Shselasky 1184219820Sjeffstatic void mlx4_en_linkstate(struct work_struct *work) 1185219820Sjeff{ 1186219820Sjeff struct mlx4_en_priv *priv = container_of(work, struct mlx4_en_priv, 1187219820Sjeff linkstate_task); 1188219820Sjeff struct mlx4_en_dev *mdev = priv->mdev; 1189219820Sjeff int linkstate = priv->link_state; 1190219820Sjeff 1191219820Sjeff mutex_lock(&mdev->state_lock); 1192219820Sjeff /* If observable port state changed set carrier state and 1193219820Sjeff * report to system log */ 1194219820Sjeff if (priv->last_link_state != linkstate) { 1195219820Sjeff if (linkstate == MLX4_DEV_EVENT_PORT_DOWN) { 1196272407Shselasky en_info(priv, "Link Down\n"); 1197219820Sjeff if_link_state_change(priv->dev, LINK_STATE_DOWN); 1198273879Shselasky /* update netif baudrate */ 1199273879Shselasky priv->dev->if_baudrate = 0; 1200273879Shselasky 1201292107Shselasky /* make sure the port is up before notifying the OS. 1202292107Shselasky * This is tricky since we get here on INIT_PORT and 1203272407Shselasky * in such case we can't tell the OS the port is up. 1204272407Shselasky * To solve this there is a call to if_link_state_change 1205272407Shselasky * in set_rx_mode. 1206272407Shselasky * */ 1207272407Shselasky } else if (priv->port_up && (linkstate == MLX4_DEV_EVENT_PORT_UP)){ 1208273879Shselasky if (mlx4_en_QUERY_PORT(priv->mdev, priv->port)) 1209273879Shselasky en_info(priv, "Query port failed\n"); 1210273879Shselasky priv->dev->if_baudrate = 1211273879Shselasky IF_Mbps(priv->port_state.link_speed); 1212219820Sjeff en_info(priv, "Link Up\n"); 1213219820Sjeff if_link_state_change(priv->dev, LINK_STATE_UP); 1214219820Sjeff } 1215219820Sjeff } 1216219820Sjeff priv->last_link_state = linkstate; 1217219820Sjeff mutex_unlock(&mdev->state_lock); 1218219820Sjeff} 1219219820Sjeff 1220219820Sjeff 1221272407Shselaskyint mlx4_en_start_port(struct net_device *dev) 1222219820Sjeff{ 1223219820Sjeff struct mlx4_en_priv *priv = netdev_priv(dev); 1224219820Sjeff struct mlx4_en_dev *mdev = priv->mdev; 1225219820Sjeff struct mlx4_en_cq *cq; 1226219820Sjeff struct mlx4_en_tx_ring *tx_ring; 1227219820Sjeff int rx_index = 0; 1228219820Sjeff int tx_index = 0; 1229219820Sjeff int err = 0; 1230219820Sjeff int i; 1231219820Sjeff int j; 1232272407Shselasky u8 mc_list[16] = {0}; 1233219820Sjeff 1234272407Shselasky 1235219820Sjeff if (priv->port_up) { 1236219820Sjeff en_dbg(DRV, priv, "start port called while port already up\n"); 1237219820Sjeff return 0; 1238219820Sjeff } 1239219820Sjeff 1240272407Shselasky INIT_LIST_HEAD(&priv->mc_list); 1241272407Shselasky INIT_LIST_HEAD(&priv->curr_list); 1242272407Shselasky INIT_LIST_HEAD(&priv->ethtool_list); 1243272407Shselasky 1244219820Sjeff /* Calculate Rx buf size */ 1245219820Sjeff dev->if_mtu = min(dev->if_mtu, priv->max_mtu); 1246272407Shselasky mlx4_en_calc_rx_buf(dev); 1247272407Shselasky priv->rx_alloc_size = max_t(int, 2 * roundup_pow_of_two(priv->rx_mb_size), 1248272407Shselasky PAGE_SIZE); 1249272407Shselasky priv->rx_alloc_order = get_order(priv->rx_alloc_size); 1250272407Shselasky priv->rx_buf_size = roundup_pow_of_two(priv->rx_mb_size); 1251219820Sjeff en_dbg(DRV, priv, "Rx buf size:%d\n", priv->rx_mb_size); 1252219820Sjeff 1253219820Sjeff /* Configure rx cq's and rings */ 1254219820Sjeff err = mlx4_en_activate_rx_rings(priv); 1255219820Sjeff if (err) { 1256219820Sjeff en_err(priv, "Failed to activate RX rings\n"); 1257219820Sjeff return err; 1258219820Sjeff } 1259219820Sjeff for (i = 0; i < priv->rx_ring_num; i++) { 1260272407Shselasky cq = priv->rx_cq[i]; 1261219820Sjeff 1262272407Shselasky mlx4_en_cq_init_lock(cq); 1263272407Shselasky err = mlx4_en_activate_cq(priv, cq, i); 1264219820Sjeff if (err) { 1265219820Sjeff en_err(priv, "Failed activating Rx CQ\n"); 1266219820Sjeff goto cq_err; 1267219820Sjeff } 1268219820Sjeff for (j = 0; j < cq->size; j++) 1269219820Sjeff cq->buf[j].owner_sr_opcode = MLX4_CQE_OWNER_MASK; 1270219820Sjeff err = mlx4_en_set_cq_moder(priv, cq); 1271219820Sjeff if (err) { 1272219820Sjeff en_err(priv, "Failed setting cq moderation parameters"); 1273219820Sjeff mlx4_en_deactivate_cq(priv, cq); 1274219820Sjeff goto cq_err; 1275219820Sjeff } 1276219820Sjeff mlx4_en_arm_cq(priv, cq); 1277272407Shselasky priv->rx_ring[i]->cqn = cq->mcq.cqn; 1278219820Sjeff ++rx_index; 1279219820Sjeff } 1280219820Sjeff 1281272407Shselasky /* Set qp number */ 1282272407Shselasky en_dbg(DRV, priv, "Getting qp number for port %d\n", priv->port); 1283272407Shselasky err = mlx4_en_get_qp(priv); 1284272407Shselasky if (err) { 1285272407Shselasky en_err(priv, "Failed getting eth qp\n"); 1286272407Shselasky goto cq_err; 1287272407Shselasky } 1288272407Shselasky mdev->mac_removed[priv->port] = 0; 1289272407Shselasky 1290272407Shselasky /* gets default allocated counter index from func cap */ 1291272407Shselasky /* or sink counter index if no resources */ 1292272407Shselasky priv->counter_index = mdev->dev->caps.def_counter_index[priv->port - 1]; 1293272407Shselasky 1294272407Shselasky en_dbg(DRV, priv, "%s: default counter index %d for port %d\n", 1295272407Shselasky __func__, priv->counter_index, priv->port); 1296272407Shselasky 1297219820Sjeff err = mlx4_en_config_rss_steer(priv); 1298219820Sjeff if (err) { 1299219820Sjeff en_err(priv, "Failed configuring rss steering\n"); 1300272407Shselasky goto mac_err; 1301219820Sjeff } 1302219820Sjeff 1303272407Shselasky err = mlx4_en_create_drop_qp(priv); 1304272407Shselasky if (err) 1305272407Shselasky goto rss_err; 1306272407Shselasky 1307219820Sjeff /* Configure tx cq's and rings */ 1308219820Sjeff for (i = 0; i < priv->tx_ring_num; i++) { 1309219820Sjeff /* Configure cq */ 1310272407Shselasky cq = priv->tx_cq[i]; 1311272407Shselasky err = mlx4_en_activate_cq(priv, cq, i); 1312219820Sjeff if (err) { 1313279731Shselasky en_err(priv, "Failed activating Tx CQ\n"); 1314219820Sjeff goto tx_err; 1315219820Sjeff } 1316219820Sjeff err = mlx4_en_set_cq_moder(priv, cq); 1317219820Sjeff if (err) { 1318219820Sjeff en_err(priv, "Failed setting cq moderation parameters"); 1319219820Sjeff mlx4_en_deactivate_cq(priv, cq); 1320219820Sjeff goto tx_err; 1321219820Sjeff } 1322219820Sjeff en_dbg(DRV, priv, "Resetting index of collapsed CQ:%d to -1\n", i); 1323219820Sjeff cq->buf->wqe_index = cpu_to_be16(0xffff); 1324219820Sjeff 1325219820Sjeff /* Configure ring */ 1326272407Shselasky tx_ring = priv->tx_ring[i]; 1327272407Shselasky 1328272407Shselasky err = mlx4_en_activate_tx_ring(priv, tx_ring, cq->mcq.cqn, 1329272407Shselasky i / priv->num_tx_rings_p_up); 1330219820Sjeff if (err) { 1331279731Shselasky en_err(priv, "Failed activating Tx ring %d\n", i); 1332219820Sjeff mlx4_en_deactivate_cq(priv, cq); 1333219820Sjeff goto tx_err; 1334219820Sjeff } 1335272407Shselasky 1336272407Shselasky /* Arm CQ for TX completions */ 1337272407Shselasky mlx4_en_arm_cq(priv, cq); 1338272407Shselasky 1339219820Sjeff /* Set initial ownership of all Tx TXBBs to SW (1) */ 1340219820Sjeff for (j = 0; j < tx_ring->buf_size; j += STAMP_STRIDE) 1341219820Sjeff *((u32 *) (tx_ring->buf + j)) = 0xffffffff; 1342219820Sjeff ++tx_index; 1343219820Sjeff } 1344219820Sjeff 1345219820Sjeff /* Configure port */ 1346219820Sjeff err = mlx4_SET_PORT_general(mdev->dev, priv->port, 1347272407Shselasky priv->rx_mb_size, 1348219820Sjeff priv->prof->tx_pause, 1349219820Sjeff priv->prof->tx_ppp, 1350219820Sjeff priv->prof->rx_pause, 1351219820Sjeff priv->prof->rx_ppp); 1352219820Sjeff if (err) { 1353272407Shselasky en_err(priv, "Failed setting port general configurations for port %d, with error %d\n", 1354272407Shselasky priv->port, err); 1355219820Sjeff goto tx_err; 1356219820Sjeff } 1357219820Sjeff /* Set default qp number */ 1358219820Sjeff err = mlx4_SET_PORT_qpn_calc(mdev->dev, priv->port, priv->base_qpn, 0); 1359219820Sjeff if (err) { 1360219820Sjeff en_err(priv, "Failed setting default qp numbers\n"); 1361219820Sjeff goto tx_err; 1362219820Sjeff } 1363219820Sjeff 1364219820Sjeff /* Init port */ 1365219820Sjeff en_dbg(HW, priv, "Initializing port\n"); 1366219820Sjeff err = mlx4_INIT_PORT(mdev->dev, priv->port); 1367219820Sjeff if (err) { 1368219820Sjeff en_err(priv, "Failed Initializing port\n"); 1369272407Shselasky goto tx_err; 1370219820Sjeff } 1371219820Sjeff 1372272407Shselasky /* Attach rx QP to bradcast address */ 1373272407Shselasky memset(&mc_list[10], 0xff, ETH_ALEN); 1374272407Shselasky mc_list[5] = priv->port; /* needed for B0 steering support */ 1375272407Shselasky if (mlx4_multicast_attach(mdev->dev, &priv->rss_map.indir_qp, mc_list, 1376272407Shselasky priv->port, 0, MLX4_PROT_ETH, 1377272407Shselasky &priv->broadcast_id)) 1378272407Shselasky mlx4_warn(mdev, "Failed Attaching Broadcast\n"); 1379219820Sjeff 1380272407Shselasky /* Must redo promiscuous mode setup. */ 1381272407Shselasky priv->flags &= ~(MLX4_EN_FLAG_PROMISC | MLX4_EN_FLAG_MC_PROMISC); 1382220016Sjeff 1383272407Shselasky /* Schedule multicast task to populate multicast list */ 1384272407Shselasky queue_work(mdev->workqueue, &priv->rx_mode_task); 1385220016Sjeff 1386272407Shselasky mlx4_set_stats_bitmap(mdev->dev, priv->stats_bitmap); 1387272407Shselasky 1388219820Sjeff priv->port_up = true; 1389219820Sjeff 1390272407Shselasky /* Enable the queues. */ 1391272407Shselasky dev->if_drv_flags &= ~IFF_DRV_OACTIVE; 1392272407Shselasky dev->if_drv_flags |= IFF_DRV_RUNNING; 1393272407Shselasky#ifdef CONFIG_DEBUG_FS 1394272407Shselasky mlx4_en_create_debug_files(priv); 1395272407Shselasky#endif 1396272407Shselasky callout_reset(&priv->watchdog_timer, MLX4_EN_WATCHDOG_TIMEOUT, 1397272407Shselasky mlx4_en_watchdog_timeout, priv); 1398219820Sjeff 1399219820Sjeff 1400219820Sjeff return 0; 1401219820Sjeff 1402219820Sjefftx_err: 1403219820Sjeff while (tx_index--) { 1404272407Shselasky mlx4_en_deactivate_tx_ring(priv, priv->tx_ring[tx_index]); 1405272407Shselasky mlx4_en_deactivate_cq(priv, priv->tx_cq[tx_index]); 1406219820Sjeff } 1407272407Shselasky mlx4_en_destroy_drop_qp(priv); 1408272407Shselaskyrss_err: 1409219820Sjeff mlx4_en_release_rss_steer(priv); 1410272407Shselaskymac_err: 1411272407Shselasky mlx4_en_put_qp(priv); 1412219820Sjeffcq_err: 1413219820Sjeff while (rx_index--) 1414272407Shselasky mlx4_en_deactivate_cq(priv, priv->rx_cq[rx_index]); 1415219820Sjeff for (i = 0; i < priv->rx_ring_num; i++) 1416272407Shselasky mlx4_en_deactivate_rx_ring(priv, priv->rx_ring[i]); 1417219820Sjeff 1418219820Sjeff return err; /* need to close devices */ 1419219820Sjeff} 1420219820Sjeff 1421219820Sjeff 1422272407Shselaskyvoid mlx4_en_stop_port(struct net_device *dev) 1423219820Sjeff{ 1424219820Sjeff struct mlx4_en_priv *priv = netdev_priv(dev); 1425219820Sjeff struct mlx4_en_dev *mdev = priv->mdev; 1426272407Shselasky struct mlx4_en_mc_list *mclist, *tmp; 1427219820Sjeff int i; 1428272407Shselasky u8 mc_list[16] = {0}; 1429219820Sjeff 1430219820Sjeff if (!priv->port_up) { 1431219820Sjeff en_dbg(DRV, priv, "stop port called while port already down\n"); 1432219820Sjeff return; 1433219820Sjeff } 1434219820Sjeff 1435272407Shselasky#ifdef CONFIG_DEBUG_FS 1436272407Shselasky mlx4_en_delete_debug_files(priv); 1437272407Shselasky#endif 1438272407Shselasky 1439272407Shselasky /* close port*/ 1440272407Shselasky mlx4_CLOSE_PORT(mdev->dev, priv->port); 1441272407Shselasky 1442219820Sjeff /* Set port as not active */ 1443219820Sjeff priv->port_up = false; 1444272407Shselasky if (priv->counter_index != 0xff) { 1445272407Shselasky mlx4_counter_free(mdev->dev, priv->port, priv->counter_index); 1446272407Shselasky priv->counter_index = 0xff; 1447272407Shselasky } 1448219820Sjeff 1449272407Shselasky /* Promsicuous mode */ 1450272407Shselasky if (mdev->dev->caps.steering_mode == 1451272407Shselasky MLX4_STEERING_MODE_DEVICE_MANAGED) { 1452272407Shselasky priv->flags &= ~(MLX4_EN_FLAG_PROMISC | 1453272407Shselasky MLX4_EN_FLAG_MC_PROMISC); 1454272407Shselasky mlx4_flow_steer_promisc_remove(mdev->dev, 1455272407Shselasky priv->port, 1456272407Shselasky MLX4_FS_ALL_DEFAULT); 1457272407Shselasky mlx4_flow_steer_promisc_remove(mdev->dev, 1458272407Shselasky priv->port, 1459272407Shselasky MLX4_FS_MC_DEFAULT); 1460272407Shselasky } else if (priv->flags & MLX4_EN_FLAG_PROMISC) { 1461272407Shselasky priv->flags &= ~MLX4_EN_FLAG_PROMISC; 1462219820Sjeff 1463272407Shselasky /* Disable promiscouos mode */ 1464272407Shselasky mlx4_unicast_promisc_remove(mdev->dev, priv->base_qpn, 1465272407Shselasky priv->port); 1466272407Shselasky 1467272407Shselasky /* Disable Multicast promisc */ 1468272407Shselasky if (priv->flags & MLX4_EN_FLAG_MC_PROMISC) { 1469272407Shselasky mlx4_multicast_promisc_remove(mdev->dev, priv->base_qpn, 1470272407Shselasky priv->port); 1471272407Shselasky priv->flags &= ~MLX4_EN_FLAG_MC_PROMISC; 1472272407Shselasky } 1473272407Shselasky } 1474272407Shselasky 1475272407Shselasky /* Detach All multicasts */ 1476272407Shselasky memset(&mc_list[10], 0xff, ETH_ALEN); 1477272407Shselasky mc_list[5] = priv->port; /* needed for B0 steering support */ 1478272407Shselasky mlx4_multicast_detach(mdev->dev, &priv->rss_map.indir_qp, mc_list, 1479272407Shselasky MLX4_PROT_ETH, priv->broadcast_id); 1480272407Shselasky list_for_each_entry(mclist, &priv->curr_list, list) { 1481272407Shselasky memcpy(&mc_list[10], mclist->addr, ETH_ALEN); 1482272407Shselasky mc_list[5] = priv->port; 1483272407Shselasky mlx4_multicast_detach(mdev->dev, &priv->rss_map.indir_qp, 1484272407Shselasky mc_list, MLX4_PROT_ETH, mclist->reg_id); 1485272407Shselasky } 1486272407Shselasky mlx4_en_clear_list(dev); 1487272407Shselasky list_for_each_entry_safe(mclist, tmp, &priv->curr_list, list) { 1488272407Shselasky list_del(&mclist->list); 1489272407Shselasky kfree(mclist); 1490272407Shselasky } 1491272407Shselasky 1492272407Shselasky /* Flush multicast filter */ 1493272407Shselasky mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0, 1, MLX4_MCAST_CONFIG); 1494272407Shselasky mlx4_en_destroy_drop_qp(priv); 1495272407Shselasky 1496219820Sjeff /* Free TX Rings */ 1497219820Sjeff for (i = 0; i < priv->tx_ring_num; i++) { 1498272407Shselasky mlx4_en_deactivate_tx_ring(priv, priv->tx_ring[i]); 1499272407Shselasky mlx4_en_deactivate_cq(priv, priv->tx_cq[i]); 1500219820Sjeff } 1501219820Sjeff msleep(10); 1502219820Sjeff 1503219820Sjeff for (i = 0; i < priv->tx_ring_num; i++) 1504272407Shselasky mlx4_en_free_tx_buf(dev, priv->tx_ring[i]); 1505219820Sjeff 1506219820Sjeff /* Free RSS qps */ 1507219820Sjeff mlx4_en_release_rss_steer(priv); 1508219820Sjeff 1509272407Shselasky /* Unregister Mac address for the port */ 1510272407Shselasky mlx4_en_put_qp(priv); 1511272407Shselasky mdev->mac_removed[priv->port] = 1; 1512272407Shselasky 1513219820Sjeff /* Free RX Rings */ 1514219820Sjeff for (i = 0; i < priv->rx_ring_num; i++) { 1515272407Shselasky struct mlx4_en_cq *cq = priv->rx_cq[i]; 1516272407Shselasky mlx4_en_deactivate_rx_ring(priv, priv->rx_ring[i]); 1517272407Shselasky mlx4_en_deactivate_cq(priv, cq); 1518219820Sjeff } 1519219820Sjeff 1520272407Shselasky callout_stop(&priv->watchdog_timer); 1521219820Sjeff 1522272407Shselasky dev->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 1523219820Sjeff} 1524219820Sjeff 1525219820Sjeffstatic void mlx4_en_restart(struct work_struct *work) 1526219820Sjeff{ 1527219820Sjeff struct mlx4_en_priv *priv = container_of(work, struct mlx4_en_priv, 1528219820Sjeff watchdog_task); 1529219820Sjeff struct mlx4_en_dev *mdev = priv->mdev; 1530219820Sjeff struct net_device *dev = priv->dev; 1531219820Sjeff struct mlx4_en_tx_ring *ring; 1532219820Sjeff int i; 1533219820Sjeff 1534272407Shselasky 1535219820Sjeff if (priv->blocked == 0 || priv->port_up == 0) 1536219820Sjeff return; 1537219820Sjeff for (i = 0; i < priv->tx_ring_num; i++) { 1538272407Shselasky ring = priv->tx_ring[i]; 1539219820Sjeff if (ring->blocked && 1540272407Shselasky ring->watchdog_time + MLX4_EN_WATCHDOG_TIMEOUT < ticks) 1541219820Sjeff goto reset; 1542219820Sjeff } 1543219820Sjeff return; 1544219820Sjeff 1545219820Sjeffreset: 1546219820Sjeff priv->port_stats.tx_timeout++; 1547219820Sjeff en_dbg(DRV, priv, "Watchdog task called for port %d\n", priv->port); 1548219820Sjeff 1549219820Sjeff mutex_lock(&mdev->state_lock); 1550219820Sjeff if (priv->port_up) { 1551272407Shselasky mlx4_en_stop_port(dev); 1552272407Shselasky //for (i = 0; i < priv->tx_ring_num; i++) 1553272407Shselasky // netdev_tx_reset_queue(priv->tx_ring[i]->tx_queue); 1554272407Shselasky if (mlx4_en_start_port(dev)) 1555219820Sjeff en_err(priv, "Failed restarting port %d\n", priv->port); 1556219820Sjeff } 1557219820Sjeff mutex_unlock(&mdev->state_lock); 1558219820Sjeff} 1559219820Sjeff 1560272407Shselaskystatic void mlx4_en_clear_stats(struct net_device *dev) 1561219820Sjeff{ 1562272407Shselasky struct mlx4_en_priv *priv = netdev_priv(dev); 1563272407Shselasky struct mlx4_en_dev *mdev = priv->mdev; 1564272407Shselasky int i; 1565253774Sjhb 1566272407Shselasky if (!mlx4_is_slave(mdev->dev)) 1567272407Shselasky if (mlx4_en_DUMP_ETH_STATS(mdev, priv->port, 1)) 1568272407Shselasky en_dbg(HW, priv, "Failed dumping statistics\n"); 1569272407Shselasky 1570272407Shselasky memset(&priv->pstats, 0, sizeof(priv->pstats)); 1571272407Shselasky memset(&priv->pkstats, 0, sizeof(priv->pkstats)); 1572272407Shselasky memset(&priv->port_stats, 0, sizeof(priv->port_stats)); 1573272407Shselasky memset(&priv->vport_stats, 0, sizeof(priv->vport_stats)); 1574272407Shselasky 1575272407Shselasky for (i = 0; i < priv->tx_ring_num; i++) { 1576272407Shselasky priv->tx_ring[i]->bytes = 0; 1577272407Shselasky priv->tx_ring[i]->packets = 0; 1578272407Shselasky priv->tx_ring[i]->tx_csum = 0; 1579292107Shselasky priv->tx_ring[i]->oversized_packets = 0; 1580272407Shselasky } 1581272407Shselasky for (i = 0; i < priv->rx_ring_num; i++) { 1582272407Shselasky priv->rx_ring[i]->bytes = 0; 1583272407Shselasky priv->rx_ring[i]->packets = 0; 1584272407Shselasky priv->rx_ring[i]->csum_ok = 0; 1585272407Shselasky priv->rx_ring[i]->csum_none = 0; 1586272407Shselasky } 1587253774Sjhb} 1588253774Sjhb 1589272407Shselaskystatic void mlx4_en_open(void* arg) 1590253774Sjhb{ 1591253774Sjhb 1592272407Shselasky struct mlx4_en_priv *priv; 1593272407Shselasky struct mlx4_en_dev *mdev; 1594272407Shselasky struct net_device *dev; 1595272407Shselasky int err = 0; 1596219820Sjeff 1597272407Shselasky priv = arg; 1598272407Shselasky mdev = priv->mdev; 1599272407Shselasky dev = priv->dev; 1600219820Sjeff 1601272407Shselasky 1602272407Shselasky mutex_lock(&mdev->state_lock); 1603272407Shselasky 1604219820Sjeff if (!mdev->device_up) { 1605219820Sjeff en_err(priv, "Cannot open - device down/disabled\n"); 1606272407Shselasky goto out; 1607219820Sjeff } 1608219820Sjeff 1609272407Shselasky /* Reset HW statistics and SW counters */ 1610272407Shselasky mlx4_en_clear_stats(dev); 1611219820Sjeff 1612272407Shselasky err = mlx4_en_start_port(dev); 1613272407Shselasky if (err) 1614272407Shselasky en_err(priv, "Failed starting port:%d\n", priv->port); 1615219820Sjeff 1616272407Shselaskyout: 1617272407Shselasky mutex_unlock(&mdev->state_lock); 1618272407Shselasky return; 1619219820Sjeff} 1620219820Sjeff 1621219820Sjeffvoid mlx4_en_free_resources(struct mlx4_en_priv *priv) 1622219820Sjeff{ 1623219820Sjeff int i; 1624219820Sjeff 1625272407Shselasky#ifdef CONFIG_RFS_ACCEL 1626272407Shselasky if (priv->dev->rx_cpu_rmap) { 1627272407Shselasky free_irq_cpu_rmap(priv->dev->rx_cpu_rmap); 1628272407Shselasky priv->dev->rx_cpu_rmap = NULL; 1629272407Shselasky } 1630272407Shselasky#endif 1631272407Shselasky 1632219820Sjeff for (i = 0; i < priv->tx_ring_num; i++) { 1633272407Shselasky if (priv->tx_ring && priv->tx_ring[i]) 1634219820Sjeff mlx4_en_destroy_tx_ring(priv, &priv->tx_ring[i]); 1635272407Shselasky if (priv->tx_cq && priv->tx_cq[i]) 1636219820Sjeff mlx4_en_destroy_cq(priv, &priv->tx_cq[i]); 1637219820Sjeff } 1638219820Sjeff 1639219820Sjeff for (i = 0; i < priv->rx_ring_num; i++) { 1640272407Shselasky if (priv->rx_ring[i]) 1641272407Shselasky mlx4_en_destroy_rx_ring(priv, &priv->rx_ring[i], 1642272407Shselasky priv->prof->rx_ring_size, priv->stride); 1643272407Shselasky if (priv->rx_cq[i]) 1644219820Sjeff mlx4_en_destroy_cq(priv, &priv->rx_cq[i]); 1645219820Sjeff } 1646272407Shselasky 1647219820Sjeff if (priv->sysctl) 1648219820Sjeff sysctl_ctx_free(&priv->stat_ctx); 1649219820Sjeff} 1650219820Sjeff 1651219820Sjeffint mlx4_en_alloc_resources(struct mlx4_en_priv *priv) 1652219820Sjeff{ 1653219820Sjeff struct mlx4_en_port_profile *prof = priv->prof; 1654219820Sjeff int i; 1655272407Shselasky int node = 0; 1656219820Sjeff 1657272407Shselasky /* Create rx Rings */ 1658272407Shselasky for (i = 0; i < priv->rx_ring_num; i++) { 1659272407Shselasky if (mlx4_en_create_cq(priv, &priv->rx_cq[i], 1660272407Shselasky prof->rx_ring_size, i, RX, node)) 1661219820Sjeff goto err; 1662219820Sjeff 1663272407Shselasky if (mlx4_en_create_rx_ring(priv, &priv->rx_ring[i], 1664272407Shselasky prof->rx_ring_size, node)) 1665219820Sjeff goto err; 1666219820Sjeff } 1667219820Sjeff 1668272407Shselasky /* Create tx Rings */ 1669272407Shselasky for (i = 0; i < priv->tx_ring_num; i++) { 1670272407Shselasky if (mlx4_en_create_cq(priv, &priv->tx_cq[i], 1671272407Shselasky prof->tx_ring_size, i, TX, node)) 1672219820Sjeff goto err; 1673219820Sjeff 1674272407Shselasky if (mlx4_en_create_tx_ring(priv, &priv->tx_ring[i], 1675272407Shselasky prof->tx_ring_size, TXBB_SIZE, node, i)) 1676219820Sjeff goto err; 1677219820Sjeff } 1678219820Sjeff 1679272407Shselasky#ifdef CONFIG_RFS_ACCEL 1680272407Shselasky priv->dev->rx_cpu_rmap = alloc_irq_cpu_rmap(priv->rx_ring_num); 1681272407Shselasky if (!priv->dev->rx_cpu_rmap) 1682272407Shselasky goto err; 1683272407Shselasky#endif 1684272407Shselasky /* Re-create stat sysctls in case the number of rings changed. */ 1685219820Sjeff mlx4_en_sysctl_stat(priv); 1686219820Sjeff return 0; 1687219820Sjeff 1688219820Sjefferr: 1689219820Sjeff en_err(priv, "Failed to allocate NIC resources\n"); 1690272407Shselasky for (i = 0; i < priv->rx_ring_num; i++) { 1691272407Shselasky if (priv->rx_ring[i]) 1692272407Shselasky mlx4_en_destroy_rx_ring(priv, &priv->rx_ring[i], 1693272407Shselasky prof->rx_ring_size, 1694272407Shselasky priv->stride); 1695272407Shselasky if (priv->rx_cq[i]) 1696272407Shselasky mlx4_en_destroy_cq(priv, &priv->rx_cq[i]); 1697272407Shselasky } 1698272407Shselasky for (i = 0; i < priv->tx_ring_num; i++) { 1699272407Shselasky if (priv->tx_ring[i]) 1700272407Shselasky mlx4_en_destroy_tx_ring(priv, &priv->tx_ring[i]); 1701272407Shselasky if (priv->tx_cq[i]) 1702272407Shselasky mlx4_en_destroy_cq(priv, &priv->tx_cq[i]); 1703272407Shselasky } 1704272407Shselasky priv->port_up = false; 1705219820Sjeff return -ENOMEM; 1706219820Sjeff} 1707219820Sjeff 1708272407Shselaskystruct en_port_attribute { 1709272407Shselasky struct attribute attr; 1710272407Shselasky ssize_t (*show)(struct en_port *, struct en_port_attribute *, char *buf); 1711272407Shselasky ssize_t (*store)(struct en_port *, struct en_port_attribute *, char *buf, size_t count); 1712272407Shselasky}; 1713219820Sjeff 1714272407Shselasky#define PORT_ATTR_RO(_name) \ 1715272407Shselaskystruct en_port_attribute en_port_attr_##_name = __ATTR_RO(_name) 1716272407Shselasky 1717272407Shselasky#define EN_PORT_ATTR(_name, _mode, _show, _store) \ 1718272407Shselaskystruct en_port_attribute en_port_attr_##_name = __ATTR(_name, _mode, _show, _store) 1719272407Shselasky 1720219820Sjeffvoid mlx4_en_destroy_netdev(struct net_device *dev) 1721219820Sjeff{ 1722219820Sjeff struct mlx4_en_priv *priv = netdev_priv(dev); 1723219820Sjeff struct mlx4_en_dev *mdev = priv->mdev; 1724219820Sjeff 1725219820Sjeff en_dbg(DRV, priv, "Destroying netdev on port:%d\n", priv->port); 1726219820Sjeff 1727272407Shselasky if (priv->vlan_attach != NULL) 1728272407Shselasky EVENTHANDLER_DEREGISTER(vlan_config, priv->vlan_attach); 1729272407Shselasky if (priv->vlan_detach != NULL) 1730272407Shselasky EVENTHANDLER_DEREGISTER(vlan_unconfig, priv->vlan_detach); 1731219820Sjeff 1732219820Sjeff /* Unregister device - this will close the port if it was up */ 1733292107Shselasky if (priv->registered) { 1734292107Shselasky mutex_lock(&mdev->state_lock); 1735219820Sjeff ether_ifdetach(dev); 1736292107Shselasky mutex_unlock(&mdev->state_lock); 1737292107Shselasky } 1738219820Sjeff 1739219820Sjeff if (priv->allocated) 1740219820Sjeff mlx4_free_hwq_res(mdev->dev, &priv->res, MLX4_EN_PAGE_SIZE); 1741219820Sjeff 1742253774Sjhb mutex_lock(&mdev->state_lock); 1743272407Shselasky mlx4_en_stop_port(dev); 1744253774Sjhb mutex_unlock(&mdev->state_lock); 1745253774Sjhb 1746272407Shselasky 1747219820Sjeff cancel_delayed_work(&priv->stats_task); 1748272407Shselasky cancel_delayed_work(&priv->service_task); 1749219820Sjeff /* flush any pending task for this netdev */ 1750219820Sjeff flush_workqueue(mdev->workqueue); 1751272407Shselasky callout_drain(&priv->watchdog_timer); 1752219820Sjeff 1753219820Sjeff /* Detach the netdev so tasks would not attempt to access it */ 1754219820Sjeff mutex_lock(&mdev->state_lock); 1755219820Sjeff mdev->pndev[priv->port] = NULL; 1756219820Sjeff mutex_unlock(&mdev->state_lock); 1757219820Sjeff 1758272407Shselasky 1759219820Sjeff mlx4_en_free_resources(priv); 1760255932Salfred 1761272407Shselasky /* freeing the sysctl conf cannot be called from within mlx4_en_free_resources */ 1762256810Salfred if (priv->sysctl) 1763256810Salfred sysctl_ctx_free(&priv->conf_ctx); 1764256810Salfred 1765272407Shselasky kfree(priv->tx_ring); 1766272407Shselasky kfree(priv->tx_cq); 1767272407Shselasky 1768272407Shselasky kfree(priv); 1769272407Shselasky if_free(dev); 1770272407Shselasky 1771219820Sjeff} 1772219820Sjeff 1773219820Sjeffstatic int mlx4_en_change_mtu(struct net_device *dev, int new_mtu) 1774219820Sjeff{ 1775219820Sjeff struct mlx4_en_priv *priv = netdev_priv(dev); 1776219820Sjeff struct mlx4_en_dev *mdev = priv->mdev; 1777219820Sjeff int err = 0; 1778219820Sjeff 1779272407Shselasky en_dbg(DRV, priv, "Change MTU called - current:%u new:%u\n", 1780272407Shselasky (unsigned)dev->if_mtu, (unsigned)new_mtu); 1781219820Sjeff 1782219820Sjeff if ((new_mtu < MLX4_EN_MIN_MTU) || (new_mtu > priv->max_mtu)) { 1783219820Sjeff en_err(priv, "Bad MTU size:%d.\n", new_mtu); 1784219820Sjeff return -EPERM; 1785219820Sjeff } 1786219820Sjeff mutex_lock(&mdev->state_lock); 1787219820Sjeff dev->if_mtu = new_mtu; 1788219820Sjeff if (dev->if_drv_flags & IFF_DRV_RUNNING) { 1789219820Sjeff if (!mdev->device_up) { 1790219820Sjeff /* NIC is probably restarting - let watchdog task reset 1791272407Shselasky * * the port */ 1792219820Sjeff en_dbg(DRV, priv, "Change MTU called with card down!?\n"); 1793219820Sjeff } else { 1794272407Shselasky mlx4_en_stop_port(dev); 1795272407Shselasky err = mlx4_en_start_port(dev); 1796219820Sjeff if (err) { 1797219820Sjeff en_err(priv, "Failed restarting port:%d\n", 1798272407Shselasky priv->port); 1799219820Sjeff queue_work(mdev->workqueue, &priv->watchdog_task); 1800219820Sjeff } 1801219820Sjeff } 1802219820Sjeff } 1803219820Sjeff mutex_unlock(&mdev->state_lock); 1804219820Sjeff return 0; 1805219820Sjeff} 1806219820Sjeff 1807219820Sjeffstatic int mlx4_en_calc_media(struct mlx4_en_priv *priv) 1808219820Sjeff{ 1809219820Sjeff int trans_type; 1810219820Sjeff int active; 1811219820Sjeff 1812219820Sjeff active = IFM_ETHER; 1813219820Sjeff if (priv->last_link_state == MLX4_DEV_EVENT_PORT_DOWN) 1814219820Sjeff return (active); 1815219820Sjeff active |= IFM_FDX; 1816219820Sjeff trans_type = priv->port_state.transciver; 1817219820Sjeff /* XXX I don't know all of the transceiver values. */ 1818234099Sjhb switch (priv->port_state.link_speed) { 1819234099Sjhb case 1000: 1820219820Sjeff active |= IFM_1000_T; 1821234099Sjhb break; 1822234099Sjhb case 10000: 1823234099Sjhb if (trans_type > 0 && trans_type <= 0xC) 1824234099Sjhb active |= IFM_10G_SR; 1825234099Sjhb else if (trans_type == 0x80 || trans_type == 0) 1826234099Sjhb active |= IFM_10G_CX4; 1827234099Sjhb break; 1828234099Sjhb case 40000: 1829234099Sjhb active |= IFM_40G_CR4; 1830234099Sjhb break; 1831234099Sjhb } 1832219820Sjeff if (priv->prof->tx_pause) 1833219820Sjeff active |= IFM_ETH_TXPAUSE; 1834219820Sjeff if (priv->prof->rx_pause) 1835219820Sjeff active |= IFM_ETH_RXPAUSE; 1836219820Sjeff 1837219820Sjeff return (active); 1838219820Sjeff} 1839219820Sjeff 1840219820Sjeffstatic void mlx4_en_media_status(struct ifnet *dev, struct ifmediareq *ifmr) 1841219820Sjeff{ 1842219820Sjeff struct mlx4_en_priv *priv; 1843219820Sjeff 1844219820Sjeff priv = dev->if_softc; 1845219820Sjeff ifmr->ifm_status = IFM_AVALID; 1846219820Sjeff if (priv->last_link_state != MLX4_DEV_EVENT_PORT_DOWN) 1847219820Sjeff ifmr->ifm_status |= IFM_ACTIVE; 1848219820Sjeff ifmr->ifm_active = mlx4_en_calc_media(priv); 1849219820Sjeff 1850219820Sjeff return; 1851219820Sjeff} 1852219820Sjeff 1853219820Sjeffstatic int mlx4_en_media_change(struct ifnet *dev) 1854219820Sjeff{ 1855219820Sjeff struct mlx4_en_priv *priv; 1856219820Sjeff struct ifmedia *ifm; 1857219820Sjeff int rxpause; 1858219820Sjeff int txpause; 1859219820Sjeff int error; 1860219820Sjeff 1861219820Sjeff priv = dev->if_softc; 1862219820Sjeff ifm = &priv->media; 1863219820Sjeff rxpause = txpause = 0; 1864219820Sjeff error = 0; 1865219820Sjeff 1866219820Sjeff if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) 1867219820Sjeff return (EINVAL); 1868219820Sjeff switch (IFM_SUBTYPE(ifm->ifm_media)) { 1869219820Sjeff case IFM_AUTO: 1870219820Sjeff break; 1871219820Sjeff case IFM_10G_SR: 1872219820Sjeff case IFM_10G_CX4: 1873219820Sjeff case IFM_1000_T: 1874272407Shselasky case IFM_40G_CR4: 1875272407Shselasky if ((IFM_SUBTYPE(ifm->ifm_media) 1876272407Shselasky == IFM_SUBTYPE(mlx4_en_calc_media(priv))) 1877272407Shselasky && (ifm->ifm_media & IFM_FDX)) 1878219820Sjeff break; 1879219820Sjeff /* Fallthrough */ 1880219820Sjeff default: 1881219820Sjeff printf("%s: Only auto media type\n", if_name(dev)); 1882219820Sjeff return (EINVAL); 1883219820Sjeff } 1884219820Sjeff /* Allow user to set/clear pause */ 1885219820Sjeff if (IFM_OPTIONS(ifm->ifm_media) & IFM_ETH_RXPAUSE) 1886219820Sjeff rxpause = 1; 1887219820Sjeff if (IFM_OPTIONS(ifm->ifm_media) & IFM_ETH_TXPAUSE) 1888219820Sjeff txpause = 1; 1889219820Sjeff if (priv->prof->tx_pause != txpause || priv->prof->rx_pause != rxpause) { 1890219820Sjeff priv->prof->tx_pause = txpause; 1891219820Sjeff priv->prof->rx_pause = rxpause; 1892219820Sjeff error = -mlx4_SET_PORT_general(priv->mdev->dev, priv->port, 1893219820Sjeff priv->rx_mb_size + ETHER_CRC_LEN, priv->prof->tx_pause, 1894219820Sjeff priv->prof->tx_ppp, priv->prof->rx_pause, 1895219820Sjeff priv->prof->rx_ppp); 1896219820Sjeff } 1897219820Sjeff return (error); 1898219820Sjeff} 1899219820Sjeff 1900219820Sjeffstatic int mlx4_en_ioctl(struct ifnet *dev, u_long command, caddr_t data) 1901219820Sjeff{ 1902219820Sjeff struct mlx4_en_priv *priv; 1903219820Sjeff struct mlx4_en_dev *mdev; 1904219820Sjeff struct ifreq *ifr; 1905219820Sjeff int error; 1906219820Sjeff int mask; 1907219820Sjeff 1908219820Sjeff error = 0; 1909219820Sjeff mask = 0; 1910219820Sjeff priv = dev->if_softc; 1911219820Sjeff mdev = priv->mdev; 1912219820Sjeff ifr = (struct ifreq *) data; 1913219820Sjeff switch (command) { 1914272407Shselasky 1915219820Sjeff case SIOCSIFMTU: 1916219820Sjeff error = -mlx4_en_change_mtu(dev, ifr->ifr_mtu); 1917219820Sjeff break; 1918219820Sjeff case SIOCSIFFLAGS: 1919219820Sjeff if (dev->if_flags & IFF_UP) { 1920280018Shselasky if ((dev->if_drv_flags & IFF_DRV_RUNNING) == 0) { 1921280018Shselasky mutex_lock(&mdev->state_lock); 1922219820Sjeff mlx4_en_start_port(dev); 1923280018Shselasky mutex_unlock(&mdev->state_lock); 1924280018Shselasky } else { 1925272407Shselasky mlx4_en_set_rx_mode(dev); 1926280018Shselasky } 1927219820Sjeff } else { 1928280018Shselasky mutex_lock(&mdev->state_lock); 1929219820Sjeff if (dev->if_drv_flags & IFF_DRV_RUNNING) { 1930219820Sjeff mlx4_en_stop_port(dev); 1931280018Shselasky if_link_state_change(dev, LINK_STATE_DOWN); 1932219820Sjeff } 1933280018Shselasky mutex_unlock(&mdev->state_lock); 1934219820Sjeff } 1935219820Sjeff break; 1936219820Sjeff case SIOCADDMULTI: 1937219820Sjeff case SIOCDELMULTI: 1938272407Shselasky mlx4_en_set_rx_mode(dev); 1939219820Sjeff break; 1940219820Sjeff case SIOCSIFMEDIA: 1941219820Sjeff case SIOCGIFMEDIA: 1942219820Sjeff error = ifmedia_ioctl(dev, ifr, &priv->media, command); 1943219820Sjeff break; 1944219820Sjeff case SIOCSIFCAP: 1945253774Sjhb mutex_lock(&mdev->state_lock); 1946219820Sjeff mask = ifr->ifr_reqcap ^ dev->if_capenable; 1947292107Shselasky if (mask & IFCAP_TXCSUM) { 1948292107Shselasky dev->if_capenable ^= IFCAP_TXCSUM; 1949292107Shselasky dev->if_hwassist ^= (CSUM_TCP | CSUM_UDP | CSUM_IP); 1950292107Shselasky 1951292107Shselasky if (IFCAP_TSO4 & dev->if_capenable && 1952292107Shselasky !(IFCAP_TXCSUM & dev->if_capenable)) { 1953292107Shselasky dev->if_capenable &= ~IFCAP_TSO4; 1954292107Shselasky dev->if_hwassist &= ~CSUM_IP_TSO; 1955292107Shselasky if_printf(dev, 1956292107Shselasky "tso4 disabled due to -txcsum.\n"); 1957292107Shselasky } 1958292107Shselasky } 1959292107Shselasky if (mask & IFCAP_TXCSUM_IPV6) { 1960292107Shselasky dev->if_capenable ^= IFCAP_TXCSUM_IPV6; 1961292107Shselasky dev->if_hwassist ^= (CSUM_UDP_IPV6 | CSUM_TCP_IPV6); 1962292107Shselasky 1963292107Shselasky if (IFCAP_TSO6 & dev->if_capenable && 1964292107Shselasky !(IFCAP_TXCSUM_IPV6 & dev->if_capenable)) { 1965292107Shselasky dev->if_capenable &= ~IFCAP_TSO6; 1966292107Shselasky dev->if_hwassist &= ~CSUM_IP6_TSO; 1967292107Shselasky if_printf(dev, 1968292107Shselasky "tso6 disabled due to -txcsum6.\n"); 1969292107Shselasky } 1970292107Shselasky } 1971292107Shselasky if (mask & IFCAP_RXCSUM) 1972292107Shselasky dev->if_capenable ^= IFCAP_RXCSUM; 1973292107Shselasky if (mask & IFCAP_RXCSUM_IPV6) 1974292107Shselasky dev->if_capenable ^= IFCAP_RXCSUM_IPV6; 1975292107Shselasky 1976292107Shselasky if (mask & IFCAP_TSO4) { 1977292107Shselasky if (!(IFCAP_TSO4 & dev->if_capenable) && 1978292107Shselasky !(IFCAP_TXCSUM & dev->if_capenable)) { 1979292107Shselasky if_printf(dev, "enable txcsum first.\n"); 1980292107Shselasky error = EAGAIN; 1981292107Shselasky goto out; 1982292107Shselasky } 1983219820Sjeff dev->if_capenable ^= IFCAP_TSO4; 1984292107Shselasky dev->if_hwassist ^= CSUM_IP_TSO; 1985292107Shselasky } 1986292107Shselasky if (mask & IFCAP_TSO6) { 1987292107Shselasky if (!(IFCAP_TSO6 & dev->if_capenable) && 1988292107Shselasky !(IFCAP_TXCSUM_IPV6 & dev->if_capenable)) { 1989292107Shselasky if_printf(dev, "enable txcsum6 first.\n"); 1990292107Shselasky error = EAGAIN; 1991292107Shselasky goto out; 1992292107Shselasky } 1993272407Shselasky dev->if_capenable ^= IFCAP_TSO6; 1994292107Shselasky dev->if_hwassist ^= CSUM_IP6_TSO; 1995292107Shselasky } 1996219820Sjeff if (mask & IFCAP_LRO) 1997219820Sjeff dev->if_capenable ^= IFCAP_LRO; 1998219820Sjeff if (mask & IFCAP_VLAN_HWTAGGING) 1999219820Sjeff dev->if_capenable ^= IFCAP_VLAN_HWTAGGING; 2000219820Sjeff if (mask & IFCAP_VLAN_HWFILTER) 2001219820Sjeff dev->if_capenable ^= IFCAP_VLAN_HWFILTER; 2002220016Sjeff if (mask & IFCAP_WOL_MAGIC) 2003220016Sjeff dev->if_capenable ^= IFCAP_WOL_MAGIC; 2004219820Sjeff if (dev->if_drv_flags & IFF_DRV_RUNNING) 2005272407Shselasky mlx4_en_start_port(dev); 2006292107Shselaskyout: 2007253774Sjhb mutex_unlock(&mdev->state_lock); 2008219820Sjeff VLAN_CAPABILITIES(dev); 2009219820Sjeff break; 2010292107Shselasky#if __FreeBSD_version >= 1100036 2011286841Sglebius case SIOCGI2C: { 2012286841Sglebius struct ifi2creq i2c; 2013286841Sglebius 2014286841Sglebius error = copyin(ifr->ifr_data, &i2c, sizeof(i2c)); 2015286841Sglebius if (error) 2016286841Sglebius break; 2017286841Sglebius if (i2c.len > sizeof(i2c.data)) { 2018286841Sglebius error = EINVAL; 2019286841Sglebius break; 2020286841Sglebius } 2021286841Sglebius /* 2022286841Sglebius * Note that we ignore i2c.addr here. The driver hardcodes 2023286841Sglebius * the address to 0x50, while standard expects it to be 0xA0. 2024286841Sglebius */ 2025286841Sglebius error = mlx4_get_module_info(mdev->dev, priv->port, 2026286841Sglebius i2c.offset, i2c.len, i2c.data); 2027286841Sglebius if (error < 0) { 2028286841Sglebius error = -error; 2029286841Sglebius break; 2030286841Sglebius } 2031286841Sglebius error = copyout(&i2c, ifr->ifr_data, sizeof(i2c)); 2032286841Sglebius break; 2033286841Sglebius } 2034292107Shselasky#endif 2035219820Sjeff default: 2036219820Sjeff error = ether_ioctl(dev, command, data); 2037219820Sjeff break; 2038219820Sjeff } 2039219820Sjeff 2040219820Sjeff return (error); 2041219820Sjeff} 2042219820Sjeff 2043272407Shselasky 2044272407Shselaskyint mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, 2045272407Shselasky struct mlx4_en_port_profile *prof) 2046219820Sjeff{ 2047272407Shselasky struct net_device *dev; 2048272407Shselasky struct mlx4_en_priv *priv; 2049272407Shselasky uint8_t dev_addr[ETHER_ADDR_LEN]; 2050272407Shselasky int err; 2051272407Shselasky int i; 2052219820Sjeff 2053272407Shselasky priv = kzalloc(sizeof(*priv), GFP_KERNEL); 2054272407Shselasky dev = priv->dev = if_alloc(IFT_ETHER); 2055272407Shselasky if (dev == NULL) { 2056272407Shselasky en_err(priv, "Net device allocation failed\n"); 2057272407Shselasky kfree(priv); 2058272407Shselasky return -ENOMEM; 2059272407Shselasky } 2060272407Shselasky dev->if_softc = priv; 2061272407Shselasky if_initname(dev, "mlxen", atomic_fetchadd_int(&mlx4_en_unit, 1)); 2062272407Shselasky dev->if_mtu = ETHERMTU; 2063272407Shselasky dev->if_init = mlx4_en_open; 2064272407Shselasky dev->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 2065272407Shselasky dev->if_ioctl = mlx4_en_ioctl; 2066272407Shselasky dev->if_transmit = mlx4_en_transmit; 2067272407Shselasky dev->if_qflush = mlx4_en_qflush; 2068272407Shselasky dev->if_snd.ifq_maxlen = prof->tx_ring_size; 2069219820Sjeff 2070272407Shselasky /* 2071272407Shselasky * Initialize driver private data 2072272407Shselasky */ 2073272407Shselasky priv->counter_index = 0xff; 2074272407Shselasky spin_lock_init(&priv->stats_lock); 2075272407Shselasky INIT_WORK(&priv->rx_mode_task, mlx4_en_do_set_rx_mode); 2076272407Shselasky INIT_WORK(&priv->watchdog_task, mlx4_en_restart); 2077272407Shselasky INIT_WORK(&priv->linkstate_task, mlx4_en_linkstate); 2078272407Shselasky INIT_DELAYED_WORK(&priv->stats_task, mlx4_en_do_get_stats); 2079272407Shselasky INIT_DELAYED_WORK(&priv->service_task, mlx4_en_service_task); 2080272407Shselasky callout_init(&priv->watchdog_timer, 1); 2081272407Shselasky#ifdef CONFIG_RFS_ACCEL 2082272407Shselasky INIT_LIST_HEAD(&priv->filters); 2083272407Shselasky spin_lock_init(&priv->filters_lock); 2084272407Shselasky#endif 2085219820Sjeff 2086272407Shselasky priv->msg_enable = MLX4_EN_MSG_LEVEL; 2087272407Shselasky priv->dev = dev; 2088272407Shselasky priv->mdev = mdev; 2089272407Shselasky priv->ddev = &mdev->pdev->dev; 2090272407Shselasky priv->prof = prof; 2091272407Shselasky priv->port = port; 2092272407Shselasky priv->port_up = false; 2093272407Shselasky priv->flags = prof->flags; 2094272407Shselasky 2095272407Shselasky priv->num_tx_rings_p_up = mdev->profile.num_tx_rings_p_up; 2096272407Shselasky priv->tx_ring_num = prof->tx_ring_num; 2097272407Shselasky priv->tx_ring = kcalloc(MAX_TX_RINGS, 2098272407Shselasky sizeof(struct mlx4_en_tx_ring *), GFP_KERNEL); 2099272407Shselasky if (!priv->tx_ring) { 2100272407Shselasky err = -ENOMEM; 2101272407Shselasky goto out; 2102219820Sjeff } 2103272407Shselasky priv->tx_cq = kcalloc(sizeof(struct mlx4_en_cq *), MAX_TX_RINGS, 2104272407Shselasky GFP_KERNEL); 2105272407Shselasky if (!priv->tx_cq) { 2106272407Shselasky err = -ENOMEM; 2107272407Shselasky goto out; 2108272407Shselasky } 2109292107Shselasky 2110272407Shselasky priv->rx_ring_num = prof->rx_ring_num; 2111272407Shselasky priv->cqe_factor = (mdev->dev->caps.cqe_size == 64) ? 1 : 0; 2112272407Shselasky priv->mac_index = -1; 2113272407Shselasky priv->last_ifq_jiffies = 0; 2114272407Shselasky priv->if_counters_rx_errors = 0; 2115272407Shselasky priv->if_counters_rx_no_buffer = 0; 2116272407Shselasky#ifdef CONFIG_MLX4_EN_DCB 2117272407Shselasky if (!mlx4_is_slave(priv->mdev->dev)) { 2118272407Shselasky priv->dcbx_cap = DCB_CAP_DCBX_HOST; 2119272407Shselasky priv->flags |= MLX4_EN_FLAG_DCB_ENABLED; 2120272407Shselasky if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_ETS_CFG) { 2121272407Shselasky dev->dcbnl_ops = &mlx4_en_dcbnl_ops; 2122272407Shselasky } else { 2123272407Shselasky en_info(priv, "QoS disabled - no HW support\n"); 2124272407Shselasky dev->dcbnl_ops = &mlx4_en_dcbnl_pfc_ops; 2125272407Shselasky } 2126272407Shselasky } 2127272407Shselasky#endif 2128272407Shselasky 2129272407Shselasky for (i = 0; i < MLX4_EN_MAC_HASH_SIZE; ++i) 2130272407Shselasky INIT_HLIST_HEAD(&priv->mac_hash[i]); 2131272407Shselasky 2132272407Shselasky /* Query for default mac and max mtu */ 2133272407Shselasky priv->max_mtu = mdev->dev->caps.eth_mtu_cap[priv->port]; 2134272407Shselasky priv->mac = mdev->dev->caps.def_mac[priv->port]; 2135272407Shselasky if (ILLEGAL_MAC(priv->mac)) { 2136272407Shselasky#if BITS_PER_LONG == 64 2137272407Shselasky en_err(priv, "Port: %d, invalid mac burned: 0x%lx, quiting\n", 2138272407Shselasky priv->port, priv->mac); 2139272407Shselasky#elif BITS_PER_LONG == 32 2140272407Shselasky en_err(priv, "Port: %d, invalid mac burned: 0x%llx, quiting\n", 2141272407Shselasky priv->port, priv->mac); 2142272407Shselasky#endif 2143272407Shselasky err = -EINVAL; 2144272407Shselasky goto out; 2145272407Shselasky } 2146272407Shselasky 2147272407Shselasky priv->stride = roundup_pow_of_two(sizeof(struct mlx4_en_rx_desc) + 2148272407Shselasky DS_SIZE); 2149272407Shselasky 2150272407Shselasky mlx4_en_sysctl_conf(priv); 2151272407Shselasky 2152219820Sjeff err = mlx4_en_alloc_resources(priv); 2153272407Shselasky if (err) 2154272407Shselasky goto out; 2155272407Shselasky 2156272407Shselasky /* Allocate page for receive rings */ 2157272407Shselasky err = mlx4_alloc_hwq_res(mdev->dev, &priv->res, 2158272407Shselasky MLX4_EN_PAGE_SIZE, MLX4_EN_PAGE_SIZE); 2159219820Sjeff if (err) { 2160272407Shselasky en_err(priv, "Failed to allocate page for rx qps\n"); 2161219820Sjeff goto out; 2162219820Sjeff } 2163272407Shselasky priv->allocated = 1; 2164272407Shselasky 2165272407Shselasky /* 2166272407Shselasky * Set driver features 2167272407Shselasky */ 2168292107Shselasky dev->if_capabilities |= IFCAP_HWCSUM | IFCAP_HWCSUM_IPV6; 2169272407Shselasky dev->if_capabilities |= IFCAP_VLAN_MTU | IFCAP_VLAN_HWTAGGING; 2170272407Shselasky dev->if_capabilities |= IFCAP_VLAN_HWCSUM | IFCAP_VLAN_HWFILTER; 2171272407Shselasky dev->if_capabilities |= IFCAP_LINKSTATE | IFCAP_JUMBO_MTU; 2172272407Shselasky dev->if_capabilities |= IFCAP_LRO; 2173272407Shselasky 2174272407Shselasky if (mdev->LSO_support) 2175272407Shselasky dev->if_capabilities |= IFCAP_TSO4 | IFCAP_TSO6 | IFCAP_VLAN_HWTSO; 2176274043Shselasky 2177272407Shselasky /* set TSO limits so that we don't have to drop TX packets */ 2178292107Shselasky dev->if_hw_tsomax = MLX4_EN_TX_MAX_PAYLOAD_SIZE - (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN) /* hdr */; 2179292107Shselasky dev->if_hw_tsomaxsegcount = MLX4_EN_TX_MAX_MBUF_FRAGS - 1 /* hdr */; 2180292107Shselasky dev->if_hw_tsomaxsegsize = MLX4_EN_TX_MAX_MBUF_SIZE; 2181274043Shselasky 2182272407Shselasky dev->if_capenable = dev->if_capabilities; 2183272407Shselasky 2184272407Shselasky dev->if_hwassist = 0; 2185272407Shselasky if (dev->if_capenable & (IFCAP_TSO4 | IFCAP_TSO6)) 2186272407Shselasky dev->if_hwassist |= CSUM_TSO; 2187272407Shselasky if (dev->if_capenable & IFCAP_TXCSUM) 2188272407Shselasky dev->if_hwassist |= (CSUM_TCP | CSUM_UDP | CSUM_IP); 2189292107Shselasky if (dev->if_capenable & IFCAP_TXCSUM_IPV6) 2190292107Shselasky dev->if_hwassist |= (CSUM_UDP_IPV6 | CSUM_TCP_IPV6); 2191272407Shselasky 2192272407Shselasky 2193272407Shselasky /* Register for VLAN events */ 2194272407Shselasky priv->vlan_attach = EVENTHANDLER_REGISTER(vlan_config, 2195272407Shselasky mlx4_en_vlan_rx_add_vid, priv, EVENTHANDLER_PRI_FIRST); 2196272407Shselasky priv->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig, 2197272407Shselasky mlx4_en_vlan_rx_kill_vid, priv, EVENTHANDLER_PRI_FIRST); 2198272407Shselasky 2199272407Shselasky mdev->pndev[priv->port] = dev; 2200272407Shselasky 2201272407Shselasky priv->last_link_state = MLX4_DEV_EVENT_PORT_DOWN; 2202272407Shselasky mlx4_en_set_default_moderation(priv); 2203272407Shselasky 2204272407Shselasky /* Set default MAC */ 2205272407Shselasky for (i = 0; i < ETHER_ADDR_LEN; i++) 2206272407Shselasky dev_addr[ETHER_ADDR_LEN - 1 - i] = (u8) (priv->mac >> (8 * i)); 2207272407Shselasky 2208272407Shselasky 2209272407Shselasky ether_ifattach(dev, dev_addr); 2210272407Shselasky if_link_state_change(dev, LINK_STATE_DOWN); 2211272407Shselasky ifmedia_init(&priv->media, IFM_IMASK | IFM_ETH_FMASK, 2212272407Shselasky mlx4_en_media_change, mlx4_en_media_status); 2213272407Shselasky ifmedia_add(&priv->media, IFM_ETHER | IFM_FDX | IFM_1000_T, 0, NULL); 2214272407Shselasky ifmedia_add(&priv->media, IFM_ETHER | IFM_FDX | IFM_10G_SR, 0, NULL); 2215272407Shselasky ifmedia_add(&priv->media, IFM_ETHER | IFM_FDX | IFM_10G_CX4, 0, NULL); 2216272407Shselasky ifmedia_add(&priv->media, IFM_ETHER | IFM_FDX | IFM_40G_CR4, 0, NULL); 2217272407Shselasky ifmedia_add(&priv->media, IFM_ETHER | IFM_AUTO, 0, NULL); 2218272407Shselasky ifmedia_set(&priv->media, IFM_ETHER | IFM_AUTO); 2219272407Shselasky 2220272407Shselasky en_warn(priv, "Using %d TX rings\n", prof->tx_ring_num); 2221272407Shselasky en_warn(priv, "Using %d RX rings\n", prof->rx_ring_num); 2222272407Shselasky 2223272407Shselasky priv->registered = 1; 2224272407Shselasky 2225272407Shselasky en_warn(priv, "Using %d TX rings\n", prof->tx_ring_num); 2226272407Shselasky en_warn(priv, "Using %d RX rings\n", prof->rx_ring_num); 2227272407Shselasky 2228272407Shselasky 2229272407Shselasky priv->rx_mb_size = dev->if_mtu + ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN; 2230272407Shselasky err = mlx4_SET_PORT_general(mdev->dev, priv->port, 2231272407Shselasky priv->rx_mb_size, 2232272407Shselasky prof->tx_pause, prof->tx_ppp, 2233272407Shselasky prof->rx_pause, prof->rx_ppp); 2234272407Shselasky if (err) { 2235272407Shselasky en_err(priv, "Failed setting port general configurations " 2236272407Shselasky "for port %d, with error %d\n", priv->port, err); 2237272407Shselasky goto out; 2238219820Sjeff } 2239272407Shselasky 2240272407Shselasky /* Init port */ 2241272407Shselasky en_warn(priv, "Initializing port\n"); 2242272407Shselasky err = mlx4_INIT_PORT(mdev->dev, priv->port); 2243272407Shselasky if (err) { 2244272407Shselasky en_err(priv, "Failed Initializing port\n"); 2245272407Shselasky goto out; 2246272407Shselasky } 2247272407Shselasky 2248272407Shselasky queue_delayed_work(mdev->workqueue, &priv->stats_task, STATS_DELAY); 2249272407Shselasky 2250272407Shselasky if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_TS) 2251272407Shselasky queue_delayed_work(mdev->workqueue, &priv->service_task, SERVICE_TASK_DELAY); 2252272407Shselasky 2253272407Shselasky return 0; 2254272407Shselasky 2255219820Sjeffout: 2256272407Shselasky mlx4_en_destroy_netdev(dev); 2257219820Sjeff return err; 2258219820Sjeff} 2259279731Shselasky 2260272407Shselaskystatic int mlx4_en_set_ring_size(struct net_device *dev, 2261272407Shselasky int rx_size, int tx_size) 2262272407Shselasky{ 2263272407Shselasky struct mlx4_en_priv *priv = netdev_priv(dev); 2264272407Shselasky struct mlx4_en_dev *mdev = priv->mdev; 2265272407Shselasky int port_up = 0; 2266272407Shselasky int err = 0; 2267219820Sjeff 2268272407Shselasky rx_size = roundup_pow_of_two(rx_size); 2269272407Shselasky rx_size = max_t(u32, rx_size, MLX4_EN_MIN_RX_SIZE); 2270272407Shselasky rx_size = min_t(u32, rx_size, MLX4_EN_MAX_RX_SIZE); 2271272407Shselasky tx_size = roundup_pow_of_two(tx_size); 2272272407Shselasky tx_size = max_t(u32, tx_size, MLX4_EN_MIN_TX_SIZE); 2273272407Shselasky tx_size = min_t(u32, tx_size, MLX4_EN_MAX_TX_SIZE); 2274272407Shselasky 2275272407Shselasky if (rx_size == (priv->port_up ? 2276272407Shselasky priv->rx_ring[0]->actual_size : priv->rx_ring[0]->size) && 2277272407Shselasky tx_size == priv->tx_ring[0]->size) 2278272407Shselasky return 0; 2279272407Shselasky mutex_lock(&mdev->state_lock); 2280272407Shselasky if (priv->port_up) { 2281272407Shselasky port_up = 1; 2282272407Shselasky mlx4_en_stop_port(dev); 2283272407Shselasky } 2284272407Shselasky mlx4_en_free_resources(priv); 2285272407Shselasky priv->prof->tx_ring_size = tx_size; 2286272407Shselasky priv->prof->rx_ring_size = rx_size; 2287272407Shselasky err = mlx4_en_alloc_resources(priv); 2288272407Shselasky if (err) { 2289272407Shselasky en_err(priv, "Failed reallocating port resources\n"); 2290272407Shselasky goto out; 2291272407Shselasky } 2292272407Shselasky if (port_up) { 2293272407Shselasky err = mlx4_en_start_port(dev); 2294272407Shselasky if (err) 2295272407Shselasky en_err(priv, "Failed starting port\n"); 2296272407Shselasky } 2297272407Shselaskyout: 2298272407Shselasky mutex_unlock(&mdev->state_lock); 2299272407Shselasky return err; 2300272407Shselasky} 2301219820Sjeffstatic int mlx4_en_set_rx_ring_size(SYSCTL_HANDLER_ARGS) 2302219820Sjeff{ 2303272407Shselasky struct mlx4_en_priv *priv; 2304272407Shselasky int size; 2305272407Shselasky int error; 2306219820Sjeff 2307272407Shselasky priv = arg1; 2308272407Shselasky size = priv->prof->rx_ring_size; 2309272407Shselasky error = sysctl_handle_int(oidp, &size, 0, req); 2310272407Shselasky if (error || !req->newptr) 2311272407Shselasky return (error); 2312272407Shselasky error = -mlx4_en_set_ring_size(priv->dev, size, 2313272407Shselasky priv->prof->tx_ring_size); 2314272407Shselasky return (error); 2315219820Sjeff} 2316219820Sjeff 2317219820Sjeffstatic int mlx4_en_set_tx_ring_size(SYSCTL_HANDLER_ARGS) 2318219820Sjeff{ 2319272407Shselasky struct mlx4_en_priv *priv; 2320272407Shselasky int size; 2321272407Shselasky int error; 2322219820Sjeff 2323272407Shselasky priv = arg1; 2324272407Shselasky size = priv->prof->tx_ring_size; 2325272407Shselasky error = sysctl_handle_int(oidp, &size, 0, req); 2326272407Shselasky if (error || !req->newptr) 2327272407Shselasky return (error); 2328272407Shselasky error = -mlx4_en_set_ring_size(priv->dev, priv->prof->rx_ring_size, 2329272407Shselasky size); 2330219820Sjeff 2331272407Shselasky return (error); 2332219820Sjeff} 2333219820Sjeff 2334292107Shselaskystatic int mlx4_en_get_module_info(struct net_device *dev, 2335292107Shselasky struct ethtool_modinfo *modinfo) 2336292107Shselasky{ 2337292107Shselasky struct mlx4_en_priv *priv = netdev_priv(dev); 2338292107Shselasky struct mlx4_en_dev *mdev = priv->mdev; 2339292107Shselasky int ret; 2340292107Shselasky u8 data[4]; 2341292107Shselasky 2342292107Shselasky /* Read first 2 bytes to get Module & REV ID */ 2343292107Shselasky ret = mlx4_get_module_info(mdev->dev, priv->port, 2344292107Shselasky 0/*offset*/, 2/*size*/, data); 2345292107Shselasky 2346292107Shselasky if (ret < 2) { 2347292107Shselasky en_err(priv, "Failed to read eeprom module first two bytes, error: 0x%x\n", -ret); 2348292107Shselasky return -EIO; 2349292107Shselasky } 2350292107Shselasky 2351292107Shselasky switch (data[0] /* identifier */) { 2352292107Shselasky case MLX4_MODULE_ID_QSFP: 2353292107Shselasky modinfo->type = ETH_MODULE_SFF_8436; 2354292107Shselasky modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN; 2355292107Shselasky break; 2356292107Shselasky case MLX4_MODULE_ID_QSFP_PLUS: 2357292107Shselasky if (data[1] >= 0x3) { /* revision id */ 2358292107Shselasky modinfo->type = ETH_MODULE_SFF_8636; 2359292107Shselasky modinfo->eeprom_len = ETH_MODULE_SFF_8636_LEN; 2360292107Shselasky } else { 2361292107Shselasky modinfo->type = ETH_MODULE_SFF_8436; 2362292107Shselasky modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN; 2363292107Shselasky } 2364292107Shselasky break; 2365292107Shselasky case MLX4_MODULE_ID_QSFP28: 2366292107Shselasky modinfo->type = ETH_MODULE_SFF_8636; 2367292107Shselasky modinfo->eeprom_len = ETH_MODULE_SFF_8636_LEN; 2368292107Shselasky break; 2369292107Shselasky case MLX4_MODULE_ID_SFP: 2370292107Shselasky modinfo->type = ETH_MODULE_SFF_8472; 2371292107Shselasky modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN; 2372292107Shselasky break; 2373292107Shselasky default: 2374292107Shselasky en_err(priv, "mlx4_en_get_module_info : Not recognized cable type\n"); 2375292107Shselasky return -EINVAL; 2376292107Shselasky } 2377292107Shselasky 2378292107Shselasky return 0; 2379292107Shselasky} 2380292107Shselasky 2381292107Shselaskystatic int mlx4_en_get_module_eeprom(struct net_device *dev, 2382292107Shselasky struct ethtool_eeprom *ee, 2383292107Shselasky u8 *data) 2384292107Shselasky{ 2385292107Shselasky struct mlx4_en_priv *priv = netdev_priv(dev); 2386292107Shselasky struct mlx4_en_dev *mdev = priv->mdev; 2387292107Shselasky int offset = ee->offset; 2388292107Shselasky int i = 0, ret; 2389292107Shselasky 2390292107Shselasky if (ee->len == 0) 2391292107Shselasky return -EINVAL; 2392292107Shselasky 2393292107Shselasky memset(data, 0, ee->len); 2394292107Shselasky 2395292107Shselasky while (i < ee->len) { 2396292107Shselasky en_dbg(DRV, priv, 2397292107Shselasky "mlx4_get_module_info i(%d) offset(%d) len(%d)\n", 2398292107Shselasky i, offset, ee->len - i); 2399292107Shselasky 2400292107Shselasky ret = mlx4_get_module_info(mdev->dev, priv->port, 2401292107Shselasky offset, ee->len - i, data + i); 2402292107Shselasky 2403292107Shselasky if (!ret) /* Done reading */ 2404292107Shselasky return 0; 2405292107Shselasky 2406292107Shselasky if (ret < 0) { 2407292107Shselasky en_err(priv, 2408292107Shselasky "mlx4_get_module_info i(%d) offset(%d) bytes_to_read(%d) - FAILED (0x%x)\n", 2409292107Shselasky i, offset, ee->len - i, ret); 2410292107Shselasky return -1; 2411292107Shselasky } 2412292107Shselasky 2413292107Shselasky i += ret; 2414292107Shselasky offset += ret; 2415292107Shselasky } 2416292107Shselasky return 0; 2417292107Shselasky} 2418292107Shselasky 2419292107Shselaskystatic void mlx4_en_print_eeprom(u8 *data, __u32 len) 2420292107Shselasky{ 2421292107Shselasky int i; 2422292107Shselasky int j = 0; 2423292107Shselasky int row = 0; 2424292107Shselasky const int NUM_OF_BYTES = 16; 2425292107Shselasky 2426292107Shselasky printf("\nOffset\t\tValues\n"); 2427292107Shselasky printf("------\t\t------\n"); 2428292107Shselasky while(row < len){ 2429292107Shselasky printf("0x%04x\t\t",row); 2430292107Shselasky for(i=0; i < NUM_OF_BYTES; i++){ 2431292107Shselasky printf("%02x ", data[j]); 2432292107Shselasky row++; 2433292107Shselasky j++; 2434292107Shselasky } 2435292107Shselasky printf("\n"); 2436292107Shselasky } 2437292107Shselasky} 2438292107Shselasky 2439292107Shselasky/* Read cable EEPROM module information by first inspecting the first 2440292107Shselasky * two bytes to get the length and then read the rest of the information. 2441292107Shselasky * The information is printed to dmesg. */ 2442292107Shselaskystatic int mlx4_en_read_eeprom(SYSCTL_HANDLER_ARGS) 2443292107Shselasky{ 2444292107Shselasky 2445292107Shselasky u8* data; 2446292107Shselasky int error; 2447292107Shselasky int result = 0; 2448292107Shselasky struct mlx4_en_priv *priv; 2449292107Shselasky struct net_device *dev; 2450292107Shselasky struct ethtool_modinfo modinfo; 2451292107Shselasky struct ethtool_eeprom ee; 2452292107Shselasky 2453292107Shselasky error = sysctl_handle_int(oidp, &result, 0, req); 2454292107Shselasky if (error || !req->newptr) 2455292107Shselasky return (error); 2456292107Shselasky 2457292107Shselasky if (result == 1) { 2458292107Shselasky priv = arg1; 2459292107Shselasky dev = priv->dev; 2460292107Shselasky data = kmalloc(PAGE_SIZE, GFP_KERNEL); 2461292107Shselasky 2462292107Shselasky error = mlx4_en_get_module_info(dev, &modinfo); 2463292107Shselasky if (error) { 2464292107Shselasky en_err(priv, 2465292107Shselasky "mlx4_en_get_module_info returned with error - FAILED (0x%x)\n", 2466292107Shselasky -error); 2467292107Shselasky goto out; 2468292107Shselasky } 2469292107Shselasky 2470292107Shselasky ee.len = modinfo.eeprom_len; 2471292107Shselasky ee.offset = 0; 2472292107Shselasky 2473292107Shselasky error = mlx4_en_get_module_eeprom(dev, &ee, data); 2474292107Shselasky if (error) { 2475292107Shselasky en_err(priv, 2476292107Shselasky "mlx4_en_get_module_eeprom returned with error - FAILED (0x%x)\n", 2477292107Shselasky -error); 2478292107Shselasky /* Continue printing partial information in case of an error */ 2479292107Shselasky } 2480292107Shselasky 2481292107Shselasky /* EEPROM information will be printed in dmesg */ 2482292107Shselasky mlx4_en_print_eeprom(data, ee.len); 2483292107Shselaskyout: 2484292107Shselasky kfree(data); 2485292107Shselasky } 2486292107Shselasky /* Return zero to prevent sysctl failure. */ 2487292107Shselasky return (0); 2488292107Shselasky} 2489292107Shselasky 2490219859Sjeffstatic int mlx4_en_set_tx_ppp(SYSCTL_HANDLER_ARGS) 2491219859Sjeff{ 2492272407Shselasky struct mlx4_en_priv *priv; 2493272407Shselasky int ppp; 2494272407Shselasky int error; 2495219859Sjeff 2496272407Shselasky priv = arg1; 2497272407Shselasky ppp = priv->prof->tx_ppp; 2498272407Shselasky error = sysctl_handle_int(oidp, &ppp, 0, req); 2499272407Shselasky if (error || !req->newptr) 2500272407Shselasky return (error); 2501272407Shselasky if (ppp > 0xff || ppp < 0) 2502272407Shselasky return (-EINVAL); 2503272407Shselasky priv->prof->tx_ppp = ppp; 2504272407Shselasky error = -mlx4_SET_PORT_general(priv->mdev->dev, priv->port, 2505272407Shselasky priv->rx_mb_size + ETHER_CRC_LEN, 2506272407Shselasky priv->prof->tx_pause, 2507272407Shselasky priv->prof->tx_ppp, 2508272407Shselasky priv->prof->rx_pause, 2509272407Shselasky priv->prof->rx_ppp); 2510219859Sjeff 2511272407Shselasky return (error); 2512219859Sjeff} 2513219859Sjeff 2514219859Sjeffstatic int mlx4_en_set_rx_ppp(SYSCTL_HANDLER_ARGS) 2515219859Sjeff{ 2516272407Shselasky struct mlx4_en_priv *priv; 2517272407Shselasky struct mlx4_en_dev *mdev; 2518272407Shselasky int ppp; 2519272407Shselasky int error; 2520272407Shselasky int port_up; 2521219859Sjeff 2522272407Shselasky port_up = 0; 2523272407Shselasky priv = arg1; 2524272407Shselasky mdev = priv->mdev; 2525272407Shselasky ppp = priv->prof->rx_ppp; 2526272407Shselasky error = sysctl_handle_int(oidp, &ppp, 0, req); 2527272407Shselasky if (error || !req->newptr) 2528272407Shselasky return (error); 2529272407Shselasky if (ppp > 0xff || ppp < 0) 2530272407Shselasky return (-EINVAL); 2531272407Shselasky /* See if we have to change the number of tx queues. */ 2532272407Shselasky if (!ppp != !priv->prof->rx_ppp) { 2533272407Shselasky mutex_lock(&mdev->state_lock); 2534272407Shselasky if (priv->port_up) { 2535272407Shselasky port_up = 1; 2536272407Shselasky mlx4_en_stop_port(priv->dev); 2537272407Shselasky } 2538272407Shselasky mlx4_en_free_resources(priv); 2539272407Shselasky priv->prof->rx_ppp = ppp; 2540272407Shselasky error = -mlx4_en_alloc_resources(priv); 2541272407Shselasky if (error) 2542272407Shselasky en_err(priv, "Failed reallocating port resources\n"); 2543272407Shselasky if (error == 0 && port_up) { 2544272407Shselasky error = -mlx4_en_start_port(priv->dev); 2545272407Shselasky if (error) 2546272407Shselasky en_err(priv, "Failed starting port\n"); 2547272407Shselasky } 2548272407Shselasky mutex_unlock(&mdev->state_lock); 2549272407Shselasky return (error); 2550219859Sjeff 2551272407Shselasky } 2552272407Shselasky priv->prof->rx_ppp = ppp; 2553272407Shselasky error = -mlx4_SET_PORT_general(priv->mdev->dev, priv->port, 2554272407Shselasky priv->rx_mb_size + ETHER_CRC_LEN, 2555272407Shselasky priv->prof->tx_pause, 2556272407Shselasky priv->prof->tx_ppp, 2557272407Shselasky priv->prof->rx_pause, 2558272407Shselasky priv->prof->rx_ppp); 2559219859Sjeff 2560272407Shselasky return (error); 2561219859Sjeff} 2562219859Sjeff 2563219820Sjeffstatic void mlx4_en_sysctl_conf(struct mlx4_en_priv *priv) 2564219820Sjeff{ 2565272407Shselasky struct net_device *dev; 2566272407Shselasky struct sysctl_ctx_list *ctx; 2567272407Shselasky struct sysctl_oid *node; 2568272407Shselasky struct sysctl_oid_list *node_list; 2569272407Shselasky struct sysctl_oid *coal; 2570272407Shselasky struct sysctl_oid_list *coal_list; 2571273246Shselasky const char *pnameunit; 2572219820Sjeff 2573272407Shselasky dev = priv->dev; 2574272407Shselasky ctx = &priv->conf_ctx; 2575273246Shselasky pnameunit = device_get_nameunit(priv->mdev->pdev->dev.bsddev); 2576219820Sjeff 2577272407Shselasky sysctl_ctx_init(ctx); 2578272407Shselasky priv->sysctl = SYSCTL_ADD_NODE(ctx, SYSCTL_STATIC_CHILDREN(_hw), 2579272407Shselasky OID_AUTO, dev->if_xname, CTLFLAG_RD, 0, "mlx4 10gig ethernet"); 2580272407Shselasky node = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(priv->sysctl), OID_AUTO, 2581272407Shselasky "conf", CTLFLAG_RD, NULL, "Configuration"); 2582272407Shselasky node_list = SYSCTL_CHILDREN(node); 2583219820Sjeff 2584272407Shselasky SYSCTL_ADD_UINT(ctx, node_list, OID_AUTO, "msg_enable", 2585272407Shselasky CTLFLAG_RW, &priv->msg_enable, 0, 2586272407Shselasky "Driver message enable bitfield"); 2587272407Shselasky SYSCTL_ADD_UINT(ctx, node_list, OID_AUTO, "rx_rings", 2588273246Shselasky CTLFLAG_RD, &priv->rx_ring_num, 0, 2589272407Shselasky "Number of receive rings"); 2590272407Shselasky SYSCTL_ADD_UINT(ctx, node_list, OID_AUTO, "tx_rings", 2591273246Shselasky CTLFLAG_RD, &priv->tx_ring_num, 0, 2592272407Shselasky "Number of transmit rings"); 2593272407Shselasky SYSCTL_ADD_PROC(ctx, node_list, OID_AUTO, "rx_size", 2594272407Shselasky CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, priv, 0, 2595272407Shselasky mlx4_en_set_rx_ring_size, "I", "Receive ring size"); 2596272407Shselasky SYSCTL_ADD_PROC(ctx, node_list, OID_AUTO, "tx_size", 2597272407Shselasky CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, priv, 0, 2598272407Shselasky mlx4_en_set_tx_ring_size, "I", "Transmit ring size"); 2599272407Shselasky SYSCTL_ADD_PROC(ctx, node_list, OID_AUTO, "tx_ppp", 2600272407Shselasky CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, priv, 0, 2601272407Shselasky mlx4_en_set_tx_ppp, "I", "TX Per-priority pause"); 2602272407Shselasky SYSCTL_ADD_PROC(ctx, node_list, OID_AUTO, "rx_ppp", 2603272407Shselasky CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, priv, 0, 2604272407Shselasky mlx4_en_set_rx_ppp, "I", "RX Per-priority pause"); 2605273246Shselasky SYSCTL_ADD_UINT(ctx, node_list, OID_AUTO, "port_num", 2606273246Shselasky CTLFLAG_RD, &priv->port, 0, 2607273246Shselasky "Port Number"); 2608273246Shselasky SYSCTL_ADD_STRING(ctx, node_list, OID_AUTO, "device_name", 2609273246Shselasky CTLFLAG_RD, __DECONST(void *, pnameunit), 0, 2610273246Shselasky "PCI device name"); 2611219820Sjeff 2612272407Shselasky /* Add coalescer configuration. */ 2613272407Shselasky coal = SYSCTL_ADD_NODE(ctx, node_list, OID_AUTO, 2614272407Shselasky "coalesce", CTLFLAG_RD, NULL, "Interrupt coalesce configuration"); 2615292107Shselasky coal_list = SYSCTL_CHILDREN(coal); 2616272407Shselasky SYSCTL_ADD_UINT(ctx, coal_list, OID_AUTO, "pkt_rate_low", 2617272407Shselasky CTLFLAG_RW, &priv->pkt_rate_low, 0, 2618272407Shselasky "Packets per-second for minimum delay"); 2619272407Shselasky SYSCTL_ADD_UINT(ctx, coal_list, OID_AUTO, "rx_usecs_low", 2620272407Shselasky CTLFLAG_RW, &priv->rx_usecs_low, 0, 2621272407Shselasky "Minimum RX delay in micro-seconds"); 2622272407Shselasky SYSCTL_ADD_UINT(ctx, coal_list, OID_AUTO, "pkt_rate_high", 2623272407Shselasky CTLFLAG_RW, &priv->pkt_rate_high, 0, 2624272407Shselasky "Packets per-second for maximum delay"); 2625272407Shselasky SYSCTL_ADD_UINT(ctx, coal_list, OID_AUTO, "rx_usecs_high", 2626272407Shselasky CTLFLAG_RW, &priv->rx_usecs_high, 0, 2627272407Shselasky "Maximum RX delay in micro-seconds"); 2628272407Shselasky SYSCTL_ADD_UINT(ctx, coal_list, OID_AUTO, "sample_interval", 2629272407Shselasky CTLFLAG_RW, &priv->sample_interval, 0, 2630272407Shselasky "adaptive frequency in units of HZ ticks"); 2631272407Shselasky SYSCTL_ADD_UINT(ctx, coal_list, OID_AUTO, "adaptive_rx_coal", 2632272407Shselasky CTLFLAG_RW, &priv->adaptive_rx_coal, 0, 2633272407Shselasky "Enable adaptive rx coalescing"); 2634292107Shselasky /* EEPROM support */ 2635292107Shselasky SYSCTL_ADD_PROC(ctx, node_list, OID_AUTO, "eeprom_info", 2636292107Shselasky CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, priv, 0, 2637292107Shselasky mlx4_en_read_eeprom, "I", "EEPROM information"); 2638219820Sjeff} 2639219820Sjeff 2640219820Sjeffstatic void mlx4_en_sysctl_stat(struct mlx4_en_priv *priv) 2641219820Sjeff{ 2642219820Sjeff struct sysctl_ctx_list *ctx; 2643219820Sjeff struct sysctl_oid *node; 2644219820Sjeff struct sysctl_oid_list *node_list; 2645219820Sjeff struct sysctl_oid *ring_node; 2646219820Sjeff struct sysctl_oid_list *ring_list; 2647219820Sjeff struct mlx4_en_tx_ring *tx_ring; 2648219820Sjeff struct mlx4_en_rx_ring *rx_ring; 2649219820Sjeff char namebuf[128]; 2650219820Sjeff int i; 2651219820Sjeff 2652219820Sjeff ctx = &priv->stat_ctx; 2653219820Sjeff sysctl_ctx_init(ctx); 2654219820Sjeff node = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(priv->sysctl), OID_AUTO, 2655219820Sjeff "stat", CTLFLAG_RD, NULL, "Statistics"); 2656219820Sjeff node_list = SYSCTL_CHILDREN(node); 2657219820Sjeff 2658219820Sjeff#ifdef MLX4_EN_PERF_STAT 2659219820Sjeff SYSCTL_ADD_UINT(ctx, node_list, OID_AUTO, "tx_poll", CTLFLAG_RD, 2660219820Sjeff &priv->pstats.tx_poll, "TX Poll calls"); 2661219820Sjeff SYSCTL_ADD_QUAD(ctx, node_list, OID_AUTO, "tx_pktsz_avg", CTLFLAG_RD, 2662219820Sjeff &priv->pstats.tx_pktsz_avg, "TX average packet size"); 2663219820Sjeff SYSCTL_ADD_UINT(ctx, node_list, OID_AUTO, "inflight_avg", CTLFLAG_RD, 2664219820Sjeff &priv->pstats.inflight_avg, "TX average packets in-flight"); 2665219820Sjeff SYSCTL_ADD_UINT(ctx, node_list, OID_AUTO, "tx_coal_avg", CTLFLAG_RD, 2666219820Sjeff &priv->pstats.tx_coal_avg, "TX average coalesced completions"); 2667219820Sjeff SYSCTL_ADD_UINT(ctx, node_list, OID_AUTO, "rx_coal_avg", CTLFLAG_RD, 2668219820Sjeff &priv->pstats.rx_coal_avg, "RX average coalesced completions"); 2669219820Sjeff#endif 2670219820Sjeff 2671219820Sjeff SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tso_packets", CTLFLAG_RD, 2672219820Sjeff &priv->port_stats.tso_packets, "TSO packets sent"); 2673219820Sjeff SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "queue_stopped", CTLFLAG_RD, 2674219820Sjeff &priv->port_stats.queue_stopped, "Queue full"); 2675219820Sjeff SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "wake_queue", CTLFLAG_RD, 2676219820Sjeff &priv->port_stats.wake_queue, "Queue resumed after full"); 2677219820Sjeff SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_timeout", CTLFLAG_RD, 2678219820Sjeff &priv->port_stats.tx_timeout, "Transmit timeouts"); 2679292107Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_oversized_packets", CTLFLAG_RD, 2680292107Shselasky &priv->port_stats.oversized_packets, "TX oversized packets, m_defrag failed"); 2681219820Sjeff SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_alloc_failed", CTLFLAG_RD, 2682219820Sjeff &priv->port_stats.rx_alloc_failed, "RX failed to allocate mbuf"); 2683219820Sjeff SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_chksum_good", CTLFLAG_RD, 2684219820Sjeff &priv->port_stats.rx_chksum_good, "RX checksum offload success"); 2685219820Sjeff SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_chksum_none", CTLFLAG_RD, 2686219820Sjeff &priv->port_stats.rx_chksum_none, "RX without checksum offload"); 2687219820Sjeff SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_chksum_offload", 2688219820Sjeff CTLFLAG_RD, &priv->port_stats.tx_chksum_offload, 2689219820Sjeff "TX checksum offloads"); 2690219820Sjeff 2691219820Sjeff /* Could strdup the names and add in a loop. This is simpler. */ 2692272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_bytes", CTLFLAG_RD, 2693272407Shselasky &priv->pkstats.rx_bytes, "RX Bytes"); 2694272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_packets", CTLFLAG_RD, 2695272407Shselasky &priv->pkstats.rx_packets, "RX packets"); 2696272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_multicast_packets", CTLFLAG_RD, 2697272407Shselasky &priv->pkstats.rx_multicast_packets, "RX Multicast Packets"); 2698272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_broadcast_packets", CTLFLAG_RD, 2699272407Shselasky &priv->pkstats.rx_broadcast_packets, "RX Broadcast Packets"); 2700272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_errors", CTLFLAG_RD, 2701272407Shselasky &priv->pkstats.rx_errors, "RX Errors"); 2702272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_dropped", CTLFLAG_RD, 2703272407Shselasky &priv->pkstats.rx_dropped, "RX Dropped"); 2704272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_length_errors", CTLFLAG_RD, 2705272407Shselasky &priv->pkstats.rx_length_errors, "RX Length Errors"); 2706272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_over_errors", CTLFLAG_RD, 2707272407Shselasky &priv->pkstats.rx_over_errors, "RX Over Errors"); 2708272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_crc_errors", CTLFLAG_RD, 2709272407Shselasky &priv->pkstats.rx_crc_errors, "RX CRC Errors"); 2710272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_jabbers", CTLFLAG_RD, 2711272407Shselasky &priv->pkstats.rx_jabbers, "RX Jabbers"); 2712219820Sjeff 2713272407Shselasky 2714272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_in_range_length_error", CTLFLAG_RD, 2715272407Shselasky &priv->pkstats.rx_in_range_length_error, "RX IN_Range Length Error"); 2716272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_out_range_length_error", 2717272407Shselasky CTLFLAG_RD, &priv->pkstats.rx_out_range_length_error, 2718272407Shselasky "RX Out Range Length Error"); 2719272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_lt_64_bytes_packets", CTLFLAG_RD, 2720272407Shselasky &priv->pkstats.rx_lt_64_bytes_packets, "RX Lt 64 Bytes Packets"); 2721272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_127_bytes_packets", CTLFLAG_RD, 2722272407Shselasky &priv->pkstats.rx_127_bytes_packets, "RX 127 bytes Packets"); 2723272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_255_bytes_packets", CTLFLAG_RD, 2724272407Shselasky &priv->pkstats.rx_255_bytes_packets, "RX 255 bytes Packets"); 2725272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_511_bytes_packets", CTLFLAG_RD, 2726272407Shselasky &priv->pkstats.rx_511_bytes_packets, "RX 511 bytes Packets"); 2727272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_1023_bytes_packets", CTLFLAG_RD, 2728272407Shselasky &priv->pkstats.rx_1023_bytes_packets, "RX 1023 bytes Packets"); 2729272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_1518_bytes_packets", CTLFLAG_RD, 2730272407Shselasky &priv->pkstats.rx_1518_bytes_packets, "RX 1518 bytes Packets"); 2731272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_1522_bytes_packets", CTLFLAG_RD, 2732272407Shselasky &priv->pkstats.rx_1522_bytes_packets, "RX 1522 bytes Packets"); 2733272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_1548_bytes_packets", CTLFLAG_RD, 2734272407Shselasky &priv->pkstats.rx_1548_bytes_packets, "RX 1548 bytes Packets"); 2735272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_gt_1548_bytes_packets", CTLFLAG_RD, 2736272407Shselasky &priv->pkstats.rx_gt_1548_bytes_packets, 2737272407Shselasky "RX Greater Then 1548 bytes Packets"); 2738272407Shselasky 2739272407Shselaskystruct mlx4_en_pkt_stats { 2740272407Shselasky unsigned long tx_packets; 2741272407Shselasky unsigned long tx_bytes; 2742272407Shselasky unsigned long tx_multicast_packets; 2743272407Shselasky unsigned long tx_broadcast_packets; 2744272407Shselasky unsigned long tx_errors; 2745272407Shselasky unsigned long tx_dropped; 2746272407Shselasky unsigned long tx_lt_64_bytes_packets; 2747272407Shselasky unsigned long tx_127_bytes_packets; 2748272407Shselasky unsigned long tx_255_bytes_packets; 2749272407Shselasky unsigned long tx_511_bytes_packets; 2750272407Shselasky unsigned long tx_1023_bytes_packets; 2751272407Shselasky unsigned long tx_1518_bytes_packets; 2752272407Shselasky unsigned long tx_1522_bytes_packets; 2753272407Shselasky unsigned long tx_1548_bytes_packets; 2754272407Shselasky unsigned long tx_gt_1548_bytes_packets; 2755272407Shselasky unsigned long rx_prio[NUM_PRIORITIES][NUM_PRIORITY_STATS]; 2756272407Shselasky unsigned long tx_prio[NUM_PRIORITIES][NUM_PRIORITY_STATS]; 2757272407Shselasky#define NUM_PKT_STATS 72 2758272407Shselasky}; 2759272407Shselasky 2760272407Shselasky 2761272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_packets", CTLFLAG_RD, 2762272407Shselasky &priv->pkstats.tx_packets, "TX packets"); 2763272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_bytes", CTLFLAG_RD, 2764292107Shselasky &priv->pkstats.tx_bytes, "TX Bytes"); 2765272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_multicast_packets", CTLFLAG_RD, 2766272407Shselasky &priv->pkstats.tx_multicast_packets, "TX Multicast Packets"); 2767272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_broadcast_packets", CTLFLAG_RD, 2768272407Shselasky &priv->pkstats.tx_broadcast_packets, "TX Broadcast Packets"); 2769272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_errors", CTLFLAG_RD, 2770272407Shselasky &priv->pkstats.tx_errors, "TX Errors"); 2771272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_dropped", CTLFLAG_RD, 2772272407Shselasky &priv->pkstats.tx_dropped, "TX Dropped"); 2773272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_lt_64_bytes_packets", CTLFLAG_RD, 2774272407Shselasky &priv->pkstats.tx_lt_64_bytes_packets, "TX Less Then 64 Bytes Packets"); 2775272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_127_bytes_packets", CTLFLAG_RD, 2776272407Shselasky &priv->pkstats.tx_127_bytes_packets, "TX 127 Bytes Packets"); 2777272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_255_bytes_packets", CTLFLAG_RD, 2778272407Shselasky &priv->pkstats.tx_255_bytes_packets, "TX 255 Bytes Packets"); 2779272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_511_bytes_packets", CTLFLAG_RD, 2780272407Shselasky &priv->pkstats.tx_511_bytes_packets, "TX 511 Bytes Packets"); 2781272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_1023_bytes_packets", CTLFLAG_RD, 2782272407Shselasky &priv->pkstats.tx_1023_bytes_packets, "TX 1023 Bytes Packets"); 2783272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_1518_bytes_packets", CTLFLAG_RD, 2784272407Shselasky &priv->pkstats.tx_1518_bytes_packets, "TX 1518 Bytes Packets"); 2785272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_1522_bytes_packets", CTLFLAG_RD, 2786272407Shselasky &priv->pkstats.tx_1522_bytes_packets, "TX 1522 Bytes Packets"); 2787272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_1548_bytes_packets", CTLFLAG_RD, 2788272407Shselasky &priv->pkstats.tx_1548_bytes_packets, "TX 1548 Bytes Packets"); 2789272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_gt_1548_bytes_packets", CTLFLAG_RD, 2790272407Shselasky &priv->pkstats.tx_gt_1548_bytes_packets, 2791272407Shselasky "TX Greater Then 1548 Bytes Packets"); 2792272407Shselasky 2793272407Shselasky 2794272407Shselasky 2795219820Sjeff for (i = 0; i < priv->tx_ring_num; i++) { 2796272407Shselasky tx_ring = priv->tx_ring[i]; 2797219820Sjeff snprintf(namebuf, sizeof(namebuf), "tx_ring%d", i); 2798219820Sjeff ring_node = SYSCTL_ADD_NODE(ctx, node_list, OID_AUTO, namebuf, 2799219820Sjeff CTLFLAG_RD, NULL, "TX Ring"); 2800219820Sjeff ring_list = SYSCTL_CHILDREN(ring_node); 2801219820Sjeff SYSCTL_ADD_ULONG(ctx, ring_list, OID_AUTO, "packets", 2802219820Sjeff CTLFLAG_RD, &tx_ring->packets, "TX packets"); 2803219820Sjeff SYSCTL_ADD_ULONG(ctx, ring_list, OID_AUTO, "bytes", 2804219820Sjeff CTLFLAG_RD, &tx_ring->bytes, "TX bytes"); 2805292107Shselasky } 2806219820Sjeff 2807219820Sjeff for (i = 0; i < priv->rx_ring_num; i++) { 2808272407Shselasky rx_ring = priv->rx_ring[i]; 2809219820Sjeff snprintf(namebuf, sizeof(namebuf), "rx_ring%d", i); 2810219820Sjeff ring_node = SYSCTL_ADD_NODE(ctx, node_list, OID_AUTO, namebuf, 2811219820Sjeff CTLFLAG_RD, NULL, "RX Ring"); 2812219820Sjeff ring_list = SYSCTL_CHILDREN(ring_node); 2813219820Sjeff SYSCTL_ADD_ULONG(ctx, ring_list, OID_AUTO, "packets", 2814219820Sjeff CTLFLAG_RD, &rx_ring->packets, "RX packets"); 2815219820Sjeff SYSCTL_ADD_ULONG(ctx, ring_list, OID_AUTO, "bytes", 2816219820Sjeff CTLFLAG_RD, &rx_ring->bytes, "RX bytes"); 2817219820Sjeff SYSCTL_ADD_ULONG(ctx, ring_list, OID_AUTO, "error", 2818219820Sjeff CTLFLAG_RD, &rx_ring->errors, "RX soft errors"); 2819219820Sjeff } 2820219820Sjeff} 2821