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); 57219820Sjeff 58272407Shselasky#ifdef CONFIG_NET_RX_BUSY_POLL 59272407Shselasky/* must be called with local_bh_disable()d */ 60272407Shselaskystatic int mlx4_en_low_latency_recv(struct napi_struct *napi) 61272407Shselasky{ 62272407Shselasky struct mlx4_en_cq *cq = container_of(napi, struct mlx4_en_cq, napi); 63272407Shselasky struct net_device *dev = cq->dev; 64272407Shselasky struct mlx4_en_priv *priv = netdev_priv(dev); 65272407Shselasky struct mlx4_en_rx_ring *rx_ring = priv->rx_ring[cq->ring]; 66272407Shselasky int done; 67272407Shselasky 68272407Shselasky if (!priv->port_up) 69272407Shselasky return LL_FLUSH_FAILED; 70272407Shselasky 71272407Shselasky if (!mlx4_en_cq_lock_poll(cq)) 72272407Shselasky return LL_FLUSH_BUSY; 73272407Shselasky 74272407Shselasky done = mlx4_en_process_rx_cq(dev, cq, 4); 75272407Shselasky#ifdef LL_EXTENDED_STATS 76272407Shselasky if (done) 77272407Shselasky rx_ring->cleaned += done; 78272407Shselasky else 79272407Shselasky rx_ring->misses++; 80272407Shselasky#endif 81272407Shselasky 82272407Shselasky mlx4_en_cq_unlock_poll(cq); 83272407Shselasky 84272407Shselasky return done; 85272407Shselasky} 86272407Shselasky#endif /* CONFIG_NET_RX_BUSY_POLL */ 87272407Shselasky 88272407Shselasky#ifdef CONFIG_RFS_ACCEL 89272407Shselasky 90272407Shselaskystruct mlx4_en_filter { 91272407Shselasky struct list_head next; 92272407Shselasky struct work_struct work; 93272407Shselasky 94272407Shselasky u8 ip_proto; 95272407Shselasky __be32 src_ip; 96272407Shselasky __be32 dst_ip; 97272407Shselasky __be16 src_port; 98272407Shselasky __be16 dst_port; 99272407Shselasky 100272407Shselasky int rxq_index; 101272407Shselasky struct mlx4_en_priv *priv; 102272407Shselasky u32 flow_id; /* RFS infrastructure id */ 103272407Shselasky int id; /* mlx4_en driver id */ 104272407Shselasky u64 reg_id; /* Flow steering API id */ 105272407Shselasky u8 activated; /* Used to prevent expiry before filter 106272407Shselasky * is attached 107272407Shselasky */ 108272407Shselasky struct hlist_node filter_chain; 109272407Shselasky}; 110272407Shselasky 111272407Shselaskystatic void mlx4_en_filter_rfs_expire(struct mlx4_en_priv *priv); 112272407Shselasky 113272407Shselaskystatic enum mlx4_net_trans_rule_id mlx4_ip_proto_to_trans_rule_id(u8 ip_proto) 114272407Shselasky{ 115272407Shselasky switch (ip_proto) { 116272407Shselasky case IPPROTO_UDP: 117272407Shselasky return MLX4_NET_TRANS_RULE_ID_UDP; 118272407Shselasky case IPPROTO_TCP: 119272407Shselasky return MLX4_NET_TRANS_RULE_ID_TCP; 120272407Shselasky default: 121272407Shselasky return -EPROTONOSUPPORT; 122272407Shselasky } 123272407Shselasky}; 124272407Shselasky 125272407Shselaskystatic void mlx4_en_filter_work(struct work_struct *work) 126272407Shselasky{ 127272407Shselasky struct mlx4_en_filter *filter = container_of(work, 128272407Shselasky struct mlx4_en_filter, 129272407Shselasky work); 130272407Shselasky struct mlx4_en_priv *priv = filter->priv; 131272407Shselasky struct mlx4_spec_list spec_tcp_udp = { 132272407Shselasky .id = mlx4_ip_proto_to_trans_rule_id(filter->ip_proto), 133272407Shselasky { 134272407Shselasky .tcp_udp = { 135272407Shselasky .dst_port = filter->dst_port, 136272407Shselasky .dst_port_msk = (__force __be16)-1, 137272407Shselasky .src_port = filter->src_port, 138272407Shselasky .src_port_msk = (__force __be16)-1, 139272407Shselasky }, 140272407Shselasky }, 141272407Shselasky }; 142272407Shselasky struct mlx4_spec_list spec_ip = { 143272407Shselasky .id = MLX4_NET_TRANS_RULE_ID_IPV4, 144272407Shselasky { 145272407Shselasky .ipv4 = { 146272407Shselasky .dst_ip = filter->dst_ip, 147272407Shselasky .dst_ip_msk = (__force __be32)-1, 148272407Shselasky .src_ip = filter->src_ip, 149272407Shselasky .src_ip_msk = (__force __be32)-1, 150272407Shselasky }, 151272407Shselasky }, 152272407Shselasky }; 153272407Shselasky struct mlx4_spec_list spec_eth = { 154272407Shselasky .id = MLX4_NET_TRANS_RULE_ID_ETH, 155272407Shselasky }; 156272407Shselasky struct mlx4_net_trans_rule rule = { 157272407Shselasky .list = LIST_HEAD_INIT(rule.list), 158272407Shselasky .queue_mode = MLX4_NET_TRANS_Q_LIFO, 159272407Shselasky .exclusive = 1, 160272407Shselasky .allow_loopback = 1, 161272407Shselasky .promisc_mode = MLX4_FS_REGULAR, 162272407Shselasky .port = priv->port, 163272407Shselasky .priority = MLX4_DOMAIN_RFS, 164272407Shselasky }; 165272407Shselasky int rc; 166272407Shselasky __be64 mac_mask = cpu_to_be64(MLX4_MAC_MASK << 16); 167272407Shselasky 168272407Shselasky if (spec_tcp_udp.id < 0) { 169272407Shselasky en_warn(priv, "RFS: ignoring unsupported ip protocol (%d)\n", 170272407Shselasky filter->ip_proto); 171272407Shselasky goto ignore; 172272407Shselasky } 173272407Shselasky list_add_tail(&spec_eth.list, &rule.list); 174272407Shselasky list_add_tail(&spec_ip.list, &rule.list); 175272407Shselasky list_add_tail(&spec_tcp_udp.list, &rule.list); 176272407Shselasky 177272407Shselasky rule.qpn = priv->rss_map.qps[filter->rxq_index].qpn; 178272407Shselasky memcpy(spec_eth.eth.dst_mac, priv->dev->dev_addr, ETH_ALEN); 179272407Shselasky memcpy(spec_eth.eth.dst_mac_msk, &mac_mask, ETH_ALEN); 180272407Shselasky 181272407Shselasky filter->activated = 0; 182272407Shselasky 183272407Shselasky if (filter->reg_id) { 184272407Shselasky rc = mlx4_flow_detach(priv->mdev->dev, filter->reg_id); 185272407Shselasky if (rc && rc != -ENOENT) 186272407Shselasky en_err(priv, "Error detaching flow. rc = %d\n", rc); 187272407Shselasky } 188272407Shselasky 189272407Shselasky rc = mlx4_flow_attach(priv->mdev->dev, &rule, &filter->reg_id); 190272407Shselasky if (rc) 191272407Shselasky en_err(priv, "Error attaching flow. err = %d\n", rc); 192272407Shselasky 193272407Shselaskyignore: 194272407Shselasky mlx4_en_filter_rfs_expire(priv); 195272407Shselasky 196272407Shselasky filter->activated = 1; 197272407Shselasky} 198272407Shselasky 199272407Shselaskystatic inline struct hlist_head * 200272407Shselaskyfilter_hash_bucket(struct mlx4_en_priv *priv, __be32 src_ip, __be32 dst_ip, 201272407Shselasky __be16 src_port, __be16 dst_port) 202272407Shselasky{ 203272407Shselasky unsigned long l; 204272407Shselasky int bucket_idx; 205272407Shselasky 206272407Shselasky l = (__force unsigned long)src_port | 207272407Shselasky ((__force unsigned long)dst_port << 2); 208272407Shselasky l ^= (__force unsigned long)(src_ip ^ dst_ip); 209272407Shselasky 210272407Shselasky bucket_idx = hash_long(l, MLX4_EN_FILTER_HASH_SHIFT); 211272407Shselasky 212272407Shselasky return &priv->filter_hash[bucket_idx]; 213272407Shselasky} 214272407Shselasky 215272407Shselaskystatic struct mlx4_en_filter * 216272407Shselaskymlx4_en_filter_alloc(struct mlx4_en_priv *priv, int rxq_index, __be32 src_ip, 217272407Shselasky __be32 dst_ip, u8 ip_proto, __be16 src_port, 218272407Shselasky __be16 dst_port, u32 flow_id) 219272407Shselasky{ 220272407Shselasky struct mlx4_en_filter *filter = NULL; 221272407Shselasky 222272407Shselasky filter = kzalloc(sizeof(struct mlx4_en_filter), GFP_ATOMIC); 223272407Shselasky if (!filter) 224272407Shselasky return NULL; 225272407Shselasky 226272407Shselasky filter->priv = priv; 227272407Shselasky filter->rxq_index = rxq_index; 228272407Shselasky INIT_WORK(&filter->work, mlx4_en_filter_work); 229272407Shselasky 230272407Shselasky filter->src_ip = src_ip; 231272407Shselasky filter->dst_ip = dst_ip; 232272407Shselasky filter->ip_proto = ip_proto; 233272407Shselasky filter->src_port = src_port; 234272407Shselasky filter->dst_port = dst_port; 235272407Shselasky 236272407Shselasky filter->flow_id = flow_id; 237272407Shselasky 238272407Shselasky filter->id = priv->last_filter_id++ % RPS_NO_FILTER; 239272407Shselasky 240272407Shselasky list_add_tail(&filter->next, &priv->filters); 241272407Shselasky hlist_add_head(&filter->filter_chain, 242272407Shselasky filter_hash_bucket(priv, src_ip, dst_ip, src_port, 243272407Shselasky dst_port)); 244272407Shselasky 245272407Shselasky return filter; 246272407Shselasky} 247272407Shselasky 248272407Shselaskystatic void mlx4_en_filter_free(struct mlx4_en_filter *filter) 249272407Shselasky{ 250272407Shselasky struct mlx4_en_priv *priv = filter->priv; 251272407Shselasky int rc; 252272407Shselasky 253272407Shselasky list_del(&filter->next); 254272407Shselasky 255272407Shselasky rc = mlx4_flow_detach(priv->mdev->dev, filter->reg_id); 256272407Shselasky if (rc && rc != -ENOENT) 257272407Shselasky en_err(priv, "Error detaching flow. rc = %d\n", rc); 258272407Shselasky 259272407Shselasky kfree(filter); 260272407Shselasky} 261272407Shselasky 262272407Shselaskystatic inline struct mlx4_en_filter * 263272407Shselaskymlx4_en_filter_find(struct mlx4_en_priv *priv, __be32 src_ip, __be32 dst_ip, 264272407Shselasky u8 ip_proto, __be16 src_port, __be16 dst_port) 265272407Shselasky{ 266272407Shselasky struct hlist_node *elem; 267272407Shselasky struct mlx4_en_filter *filter; 268272407Shselasky struct mlx4_en_filter *ret = NULL; 269272407Shselasky 270272407Shselasky hlist_for_each_entry(filter, elem, 271272407Shselasky filter_hash_bucket(priv, src_ip, dst_ip, 272272407Shselasky src_port, dst_port), 273272407Shselasky filter_chain) { 274272407Shselasky if (filter->src_ip == src_ip && 275272407Shselasky filter->dst_ip == dst_ip && 276272407Shselasky filter->ip_proto == ip_proto && 277272407Shselasky filter->src_port == src_port && 278272407Shselasky filter->dst_port == dst_port) { 279272407Shselasky ret = filter; 280272407Shselasky break; 281272407Shselasky } 282272407Shselasky } 283272407Shselasky 284272407Shselasky return ret; 285272407Shselasky} 286272407Shselasky 287272407Shselaskystatic int 288272407Shselaskymlx4_en_filter_rfs(struct net_device *net_dev, const struct sk_buff *skb, 289272407Shselasky u16 rxq_index, u32 flow_id) 290272407Shselasky{ 291272407Shselasky struct mlx4_en_priv *priv = netdev_priv(net_dev); 292272407Shselasky struct mlx4_en_filter *filter; 293272407Shselasky const struct iphdr *ip; 294272407Shselasky const __be16 *ports; 295272407Shselasky u8 ip_proto; 296272407Shselasky __be32 src_ip; 297272407Shselasky __be32 dst_ip; 298272407Shselasky __be16 src_port; 299272407Shselasky __be16 dst_port; 300272407Shselasky int nhoff = skb_network_offset(skb); 301272407Shselasky int ret = 0; 302272407Shselasky 303272407Shselasky if (skb->protocol != htons(ETH_P_IP)) 304272407Shselasky return -EPROTONOSUPPORT; 305272407Shselasky 306272407Shselasky ip = (const struct iphdr *)(skb->data + nhoff); 307272407Shselasky if (ip_is_fragment(ip)) 308272407Shselasky return -EPROTONOSUPPORT; 309272407Shselasky 310272407Shselasky if ((ip->protocol != IPPROTO_TCP) && (ip->protocol != IPPROTO_UDP)) 311272407Shselasky return -EPROTONOSUPPORT; 312272407Shselasky ports = (const __be16 *)(skb->data + nhoff + 4 * ip->ihl); 313272407Shselasky 314272407Shselasky ip_proto = ip->protocol; 315272407Shselasky src_ip = ip->saddr; 316272407Shselasky dst_ip = ip->daddr; 317272407Shselasky src_port = ports[0]; 318272407Shselasky dst_port = ports[1]; 319272407Shselasky 320272407Shselasky spin_lock_bh(&priv->filters_lock); 321272407Shselasky filter = mlx4_en_filter_find(priv, src_ip, dst_ip, ip_proto, 322272407Shselasky src_port, dst_port); 323272407Shselasky if (filter) { 324272407Shselasky if (filter->rxq_index == rxq_index) 325272407Shselasky goto out; 326272407Shselasky 327272407Shselasky filter->rxq_index = rxq_index; 328272407Shselasky } else { 329272407Shselasky filter = mlx4_en_filter_alloc(priv, rxq_index, 330272407Shselasky src_ip, dst_ip, ip_proto, 331272407Shselasky src_port, dst_port, flow_id); 332272407Shselasky if (!filter) { 333272407Shselasky ret = -ENOMEM; 334272407Shselasky goto err; 335272407Shselasky } 336272407Shselasky } 337272407Shselasky 338272407Shselasky queue_work(priv->mdev->workqueue, &filter->work); 339272407Shselasky 340272407Shselaskyout: 341272407Shselasky ret = filter->id; 342272407Shselaskyerr: 343272407Shselasky spin_unlock_bh(&priv->filters_lock); 344272407Shselasky 345272407Shselasky return ret; 346272407Shselasky} 347272407Shselasky 348272407Shselaskyvoid mlx4_en_cleanup_filters(struct mlx4_en_priv *priv, 349272407Shselasky struct mlx4_en_rx_ring *rx_ring) 350272407Shselasky{ 351272407Shselasky struct mlx4_en_filter *filter, *tmp; 352272407Shselasky LIST_HEAD(del_list); 353272407Shselasky 354272407Shselasky spin_lock_bh(&priv->filters_lock); 355272407Shselasky list_for_each_entry_safe(filter, tmp, &priv->filters, next) { 356272407Shselasky list_move(&filter->next, &del_list); 357272407Shselasky hlist_del(&filter->filter_chain); 358272407Shselasky } 359272407Shselasky spin_unlock_bh(&priv->filters_lock); 360272407Shselasky 361272407Shselasky list_for_each_entry_safe(filter, tmp, &del_list, next) { 362272407Shselasky cancel_work_sync(&filter->work); 363272407Shselasky mlx4_en_filter_free(filter); 364272407Shselasky } 365272407Shselasky} 366272407Shselasky 367272407Shselaskystatic void mlx4_en_filter_rfs_expire(struct mlx4_en_priv *priv) 368272407Shselasky{ 369272407Shselasky struct mlx4_en_filter *filter = NULL, *tmp, *last_filter = NULL; 370272407Shselasky LIST_HEAD(del_list); 371272407Shselasky int i = 0; 372272407Shselasky 373272407Shselasky spin_lock_bh(&priv->filters_lock); 374272407Shselasky list_for_each_entry_safe(filter, tmp, &priv->filters, next) { 375272407Shselasky if (i > MLX4_EN_FILTER_EXPIRY_QUOTA) 376272407Shselasky break; 377272407Shselasky 378272407Shselasky if (filter->activated && 379272407Shselasky !work_pending(&filter->work) && 380272407Shselasky rps_may_expire_flow(priv->dev, 381272407Shselasky filter->rxq_index, filter->flow_id, 382272407Shselasky filter->id)) { 383272407Shselasky list_move(&filter->next, &del_list); 384272407Shselasky hlist_del(&filter->filter_chain); 385272407Shselasky } else 386272407Shselasky last_filter = filter; 387272407Shselasky 388272407Shselasky i++; 389272407Shselasky } 390272407Shselasky 391272407Shselasky if (last_filter && (&last_filter->next != priv->filters.next)) 392272407Shselasky list_move(&priv->filters, &last_filter->next); 393272407Shselasky 394272407Shselasky spin_unlock_bh(&priv->filters_lock); 395272407Shselasky 396272407Shselasky list_for_each_entry_safe(filter, tmp, &del_list, next) 397272407Shselasky mlx4_en_filter_free(filter); 398272407Shselasky} 399272407Shselasky#endif 400272407Shselasky 401219820Sjeffstatic void mlx4_en_vlan_rx_add_vid(void *arg, struct net_device *dev, u16 vid) 402219820Sjeff{ 403219820Sjeff struct mlx4_en_priv *priv = netdev_priv(dev); 404272407Shselasky struct mlx4_en_dev *mdev = priv->mdev; 405272407Shselasky int err; 406219820Sjeff int idx; 407219820Sjeff 408258280Salfred if (arg != priv) 409258280Salfred return; 410258280Salfred 411219820Sjeff en_dbg(HW, priv, "adding VLAN:%d\n", vid); 412272407Shselasky 413272407Shselasky set_bit(vid, priv->active_vlans); 414272407Shselasky 415272407Shselasky /* Add VID to port VLAN filter */ 416272407Shselasky mutex_lock(&mdev->state_lock); 417272407Shselasky if (mdev->device_up && priv->port_up) { 418272407Shselasky err = mlx4_SET_VLAN_FLTR(mdev->dev, priv); 419272407Shselasky if (err) 420272407Shselasky en_err(priv, "Failed configuring VLAN filter\n"); 421272407Shselasky } 422272407Shselasky if (mlx4_register_vlan(mdev->dev, priv->port, vid, &idx)) 423272407Shselasky en_dbg(HW, priv, "failed adding vlan %d\n", vid); 424272407Shselasky mutex_unlock(&mdev->state_lock); 425272407Shselasky 426219820Sjeff} 427219820Sjeff 428219820Sjeffstatic void mlx4_en_vlan_rx_kill_vid(void *arg, struct net_device *dev, u16 vid) 429219820Sjeff{ 430219820Sjeff struct mlx4_en_priv *priv = netdev_priv(dev); 431272407Shselasky struct mlx4_en_dev *mdev = priv->mdev; 432272407Shselasky int err; 433219820Sjeff 434258280Salfred if (arg != priv) 435258280Salfred return; 436258280Salfred 437219820Sjeff en_dbg(HW, priv, "Killing VID:%d\n", vid); 438272407Shselasky 439272407Shselasky clear_bit(vid, priv->active_vlans); 440272407Shselasky 441272407Shselasky /* Remove VID from port VLAN filter */ 442272407Shselasky mutex_lock(&mdev->state_lock); 443272407Shselasky mlx4_unregister_vlan(mdev->dev, priv->port, vid); 444272407Shselasky 445272407Shselasky if (mdev->device_up && priv->port_up) { 446272407Shselasky err = mlx4_SET_VLAN_FLTR(mdev->dev, priv); 447272407Shselasky if (err) 448272407Shselasky en_err(priv, "Failed configuring VLAN filter\n"); 449272407Shselasky } 450272407Shselasky mutex_unlock(&mdev->state_lock); 451272407Shselasky 452219820Sjeff} 453219820Sjeff 454272407Shselaskystatic int mlx4_en_uc_steer_add(struct mlx4_en_priv *priv, 455272407Shselasky unsigned char *mac, int *qpn, u64 *reg_id) 456219820Sjeff{ 457272407Shselasky struct mlx4_en_dev *mdev = priv->mdev; 458272407Shselasky struct mlx4_dev *dev = mdev->dev; 459272407Shselasky int err; 460219820Sjeff 461272407Shselasky switch (dev->caps.steering_mode) { 462272407Shselasky case MLX4_STEERING_MODE_B0: { 463272407Shselasky struct mlx4_qp qp; 464272407Shselasky u8 gid[16] = {0}; 465272407Shselasky 466272407Shselasky qp.qpn = *qpn; 467272407Shselasky memcpy(&gid[10], mac, ETH_ALEN); 468272407Shselasky gid[5] = priv->port; 469272407Shselasky 470272407Shselasky err = mlx4_unicast_attach(dev, &qp, gid, 0, MLX4_PROT_ETH); 471272407Shselasky break; 472219820Sjeff } 473272407Shselasky case MLX4_STEERING_MODE_DEVICE_MANAGED: { 474272407Shselasky struct mlx4_spec_list spec_eth = { {NULL} }; 475272407Shselasky __be64 mac_mask = cpu_to_be64(MLX4_MAC_MASK << 16); 476272407Shselasky 477272407Shselasky struct mlx4_net_trans_rule rule = { 478272407Shselasky .queue_mode = MLX4_NET_TRANS_Q_FIFO, 479272407Shselasky .exclusive = 0, 480272407Shselasky .allow_loopback = 1, 481272407Shselasky .promisc_mode = MLX4_FS_REGULAR, 482272407Shselasky .priority = MLX4_DOMAIN_NIC, 483272407Shselasky }; 484272407Shselasky 485272407Shselasky rule.port = priv->port; 486272407Shselasky rule.qpn = *qpn; 487272407Shselasky INIT_LIST_HEAD(&rule.list); 488272407Shselasky 489272407Shselasky spec_eth.id = MLX4_NET_TRANS_RULE_ID_ETH; 490272407Shselasky memcpy(spec_eth.eth.dst_mac, mac, ETH_ALEN); 491272407Shselasky memcpy(spec_eth.eth.dst_mac_msk, &mac_mask, ETH_ALEN); 492272407Shselasky list_add_tail(&spec_eth.list, &rule.list); 493272407Shselasky 494272407Shselasky err = mlx4_flow_attach(dev, &rule, reg_id); 495272407Shselasky break; 496272407Shselasky } 497272407Shselasky default: 498272407Shselasky return -EINVAL; 499272407Shselasky } 500272407Shselasky if (err) 501272407Shselasky en_warn(priv, "Failed Attaching Unicast\n"); 502272407Shselasky 503272407Shselasky return err; 504219820Sjeff} 505219820Sjeff 506272407Shselaskystatic void mlx4_en_uc_steer_release(struct mlx4_en_priv *priv, 507272407Shselasky unsigned char *mac, int qpn, u64 reg_id) 508219820Sjeff{ 509272407Shselasky struct mlx4_en_dev *mdev = priv->mdev; 510272407Shselasky struct mlx4_dev *dev = mdev->dev; 511219820Sjeff 512272407Shselasky switch (dev->caps.steering_mode) { 513272407Shselasky case MLX4_STEERING_MODE_B0: { 514272407Shselasky struct mlx4_qp qp; 515272407Shselasky u8 gid[16] = {0}; 516272407Shselasky 517272407Shselasky qp.qpn = qpn; 518272407Shselasky memcpy(&gid[10], mac, ETH_ALEN); 519272407Shselasky gid[5] = priv->port; 520272407Shselasky 521272407Shselasky mlx4_unicast_detach(dev, &qp, gid, MLX4_PROT_ETH); 522272407Shselasky break; 523219820Sjeff } 524272407Shselasky case MLX4_STEERING_MODE_DEVICE_MANAGED: { 525272407Shselasky mlx4_flow_detach(dev, reg_id); 526272407Shselasky break; 527272407Shselasky } 528272407Shselasky default: 529272407Shselasky en_err(priv, "Invalid steering mode.\n"); 530272407Shselasky } 531272407Shselasky} 532272407Shselasky 533272407Shselaskystatic int mlx4_en_get_qp(struct mlx4_en_priv *priv) 534272407Shselasky{ 535272407Shselasky struct mlx4_en_dev *mdev = priv->mdev; 536272407Shselasky struct mlx4_dev *dev = mdev->dev; 537272407Shselasky struct mlx4_mac_entry *entry; 538272407Shselasky int index = 0; 539272407Shselasky int err = 0; 540272407Shselasky u64 reg_id; 541272407Shselasky int *qpn = &priv->base_qpn; 542272407Shselasky u64 mac = mlx4_mac_to_u64(IF_LLADDR(priv->dev)); 543272407Shselasky 544272407Shselasky en_dbg(DRV, priv, "Registering MAC: %pM for adding\n", 545272407Shselasky IF_LLADDR(priv->dev)); 546272407Shselasky index = mlx4_register_mac(dev, priv->port, mac); 547272407Shselasky if (index < 0) { 548272407Shselasky err = index; 549272407Shselasky en_err(priv, "Failed adding MAC: %pM\n", 550272407Shselasky IF_LLADDR(priv->dev)); 551272407Shselasky return err; 552272407Shselasky } 553272407Shselasky 554272407Shselasky if (dev->caps.steering_mode == MLX4_STEERING_MODE_A0) { 555272407Shselasky int base_qpn = mlx4_get_base_qpn(dev, priv->port); 556272407Shselasky *qpn = base_qpn + index; 557272407Shselasky return 0; 558272407Shselasky } 559272407Shselasky 560272407Shselasky err = mlx4_qp_reserve_range(dev, 1, 1, qpn, 0); 561272407Shselasky en_dbg(DRV, priv, "Reserved qp %d\n", *qpn); 562272407Shselasky if (err) { 563272407Shselasky en_err(priv, "Failed to reserve qp for mac registration\n"); 564272407Shselasky goto qp_err; 565272407Shselasky } 566272407Shselasky 567272407Shselasky err = mlx4_en_uc_steer_add(priv, IF_LLADDR(priv->dev), qpn, ®_id); 568272407Shselasky if (err) 569272407Shselasky goto steer_err; 570272407Shselasky 571272407Shselasky entry = kmalloc(sizeof(*entry), GFP_KERNEL); 572272407Shselasky if (!entry) { 573272407Shselasky err = -ENOMEM; 574272407Shselasky goto alloc_err; 575272407Shselasky } 576272407Shselasky memcpy(entry->mac, IF_LLADDR(priv->dev), sizeof(entry->mac)); 577272407Shselasky entry->reg_id = reg_id; 578272407Shselasky 579272407Shselasky hlist_add_head(&entry->hlist, 580272407Shselasky &priv->mac_hash[entry->mac[MLX4_EN_MAC_HASH_IDX]]); 581272407Shselasky 582272407Shselasky return 0; 583272407Shselasky 584272407Shselaskyalloc_err: 585272407Shselasky mlx4_en_uc_steer_release(priv, IF_LLADDR(priv->dev), *qpn, reg_id); 586272407Shselasky 587272407Shselaskysteer_err: 588272407Shselasky mlx4_qp_release_range(dev, *qpn, 1); 589272407Shselasky 590272407Shselaskyqp_err: 591272407Shselasky mlx4_unregister_mac(dev, priv->port, mac); 592272407Shselasky return err; 593272407Shselasky} 594272407Shselasky 595272407Shselaskystatic void mlx4_en_put_qp(struct mlx4_en_priv *priv) 596272407Shselasky{ 597272407Shselasky struct mlx4_en_dev *mdev = priv->mdev; 598272407Shselasky struct mlx4_dev *dev = mdev->dev; 599272407Shselasky int qpn = priv->base_qpn; 600272407Shselasky u64 mac; 601272407Shselasky 602272407Shselasky if (dev->caps.steering_mode == MLX4_STEERING_MODE_A0) { 603272407Shselasky mac = mlx4_mac_to_u64(IF_LLADDR(priv->dev)); 604272407Shselasky en_dbg(DRV, priv, "Registering MAC: %pM for deleting\n", 605272407Shselasky IF_LLADDR(priv->dev)); 606272407Shselasky mlx4_unregister_mac(dev, priv->port, mac); 607272407Shselasky } else { 608272407Shselasky struct mlx4_mac_entry *entry; 609272407Shselasky struct hlist_node *n, *tmp; 610272407Shselasky struct hlist_head *bucket; 611272407Shselasky unsigned int i; 612272407Shselasky 613272407Shselasky for (i = 0; i < MLX4_EN_MAC_HASH_SIZE; ++i) { 614272407Shselasky bucket = &priv->mac_hash[i]; 615272407Shselasky hlist_for_each_entry_safe(entry, n, tmp, bucket, hlist) { 616272407Shselasky mac = mlx4_mac_to_u64(entry->mac); 617272407Shselasky en_dbg(DRV, priv, "Registering MAC: %pM for deleting\n", 618272407Shselasky entry->mac); 619272407Shselasky mlx4_en_uc_steer_release(priv, entry->mac, 620272407Shselasky qpn, entry->reg_id); 621272407Shselasky 622272407Shselasky mlx4_unregister_mac(dev, priv->port, mac); 623272407Shselasky hlist_del(&entry->hlist); 624272407Shselasky kfree(entry); 625272407Shselasky } 626219820Sjeff } 627272407Shselasky 628272407Shselasky en_dbg(DRV, priv, "Releasing qp: port %d, qpn %d\n", 629272407Shselasky priv->port, qpn); 630272407Shselasky mlx4_qp_release_range(dev, qpn, 1); 631272407Shselasky priv->flags &= ~MLX4_EN_FLAG_FORCE_PROMISC; 632219820Sjeff } 633219820Sjeff} 634219820Sjeff 635272407Shselaskystatic void mlx4_en_clear_list(struct net_device *dev) 636259608Salfred{ 637259608Salfred struct mlx4_en_priv *priv = netdev_priv(dev); 638272407Shselasky struct mlx4_en_mc_list *tmp, *mc_to_del; 639272407Shselasky 640272407Shselasky list_for_each_entry_safe(mc_to_del, tmp, &priv->mc_list, list) { 641272407Shselasky list_del(&mc_to_del->list); 642272407Shselasky kfree(mc_to_del); 643272407Shselasky } 644259608Salfred} 645219820Sjeff 646272407Shselaskystatic void mlx4_en_cache_mclist(struct net_device *dev) 647259608Salfred{ 648272407Shselasky struct ifmultiaddr *ifma; 649272407Shselasky struct mlx4_en_mc_list *tmp; 650259608Salfred struct mlx4_en_priv *priv = netdev_priv(dev); 651259608Salfred 652283175Shselasky if_maddr_rlock(dev); 653272407Shselasky TAILQ_FOREACH(ifma, &dev->if_multiaddrs, ifma_link) { 654272407Shselasky if (ifma->ifma_addr->sa_family != AF_LINK) 655272407Shselasky continue; 656272407Shselasky if (((struct sockaddr_dl *)ifma->ifma_addr)->sdl_alen != 657272407Shselasky ETHER_ADDR_LEN) 658272407Shselasky continue; 659272407Shselasky /* Make sure the list didn't grow. */ 660272407Shselasky tmp = kzalloc(sizeof(struct mlx4_en_mc_list), GFP_ATOMIC); 661292107Shselasky if (tmp == NULL) { 662292107Shselasky en_err(priv, "Failed to allocate multicast list\n"); 663283175Shselasky break; 664292107Shselasky } 665272407Shselasky memcpy(tmp->addr, 666272407Shselasky LLADDR((struct sockaddr_dl *)ifma->ifma_addr), ETH_ALEN); 667272407Shselasky list_add_tail(&tmp->list, &priv->mc_list); 668272407Shselasky } 669283175Shselasky if_maddr_runlock(dev); 670259608Salfred} 671259608Salfred 672272407Shselaskystatic void update_mclist_flags(struct mlx4_en_priv *priv, 673272407Shselasky struct list_head *dst, 674272407Shselasky struct list_head *src) 675219820Sjeff{ 676272407Shselasky struct mlx4_en_mc_list *dst_tmp, *src_tmp, *new_mc; 677272407Shselasky bool found; 678272407Shselasky 679272407Shselasky /* Find all the entries that should be removed from dst, 680272407Shselasky * These are the entries that are not found in src 681272407Shselasky */ 682272407Shselasky list_for_each_entry(dst_tmp, dst, list) { 683272407Shselasky found = false; 684272407Shselasky list_for_each_entry(src_tmp, src, list) { 685272407Shselasky if (!memcmp(dst_tmp->addr, src_tmp->addr, ETH_ALEN)) { 686272407Shselasky found = true; 687272407Shselasky break; 688272407Shselasky } 689272407Shselasky } 690272407Shselasky if (!found) 691272407Shselasky dst_tmp->action = MCLIST_REM; 692272407Shselasky } 693272407Shselasky 694272407Shselasky /* Add entries that exist in src but not in dst 695272407Shselasky * mark them as need to add 696272407Shselasky */ 697272407Shselasky list_for_each_entry(src_tmp, src, list) { 698272407Shselasky found = false; 699272407Shselasky list_for_each_entry(dst_tmp, dst, list) { 700272407Shselasky if (!memcmp(dst_tmp->addr, src_tmp->addr, ETH_ALEN)) { 701272407Shselasky dst_tmp->action = MCLIST_NONE; 702272407Shselasky found = true; 703272407Shselasky break; 704272407Shselasky } 705272407Shselasky } 706272407Shselasky if (!found) { 707272407Shselasky new_mc = kmalloc(sizeof(struct mlx4_en_mc_list), 708272407Shselasky GFP_KERNEL); 709272407Shselasky if (!new_mc) { 710272407Shselasky en_err(priv, "Failed to allocate current multicast list\n"); 711272407Shselasky return; 712272407Shselasky } 713272407Shselasky memcpy(new_mc, src_tmp, 714272407Shselasky sizeof(struct mlx4_en_mc_list)); 715272407Shselasky new_mc->action = MCLIST_ADD; 716272407Shselasky list_add_tail(&new_mc->list, dst); 717272407Shselasky } 718272407Shselasky } 719272407Shselasky} 720272407Shselasky 721272407Shselaskystatic void mlx4_en_set_rx_mode(struct net_device *dev) 722272407Shselasky{ 723219820Sjeff struct mlx4_en_priv *priv = netdev_priv(dev); 724219820Sjeff 725219820Sjeff if (!priv->port_up) 726219820Sjeff return; 727219820Sjeff 728272407Shselasky queue_work(priv->mdev->workqueue, &priv->rx_mode_task); 729219820Sjeff} 730219820Sjeff 731272407Shselaskystatic void mlx4_en_set_promisc_mode(struct mlx4_en_priv *priv, 732272407Shselasky struct mlx4_en_dev *mdev) 733219820Sjeff{ 734272407Shselasky int err = 0; 735272407Shselasky if (!(priv->flags & MLX4_EN_FLAG_PROMISC)) { 736272407Shselasky priv->flags |= MLX4_EN_FLAG_PROMISC; 737219820Sjeff 738272407Shselasky /* Enable promiscouos mode */ 739272407Shselasky switch (mdev->dev->caps.steering_mode) { 740272407Shselasky case MLX4_STEERING_MODE_DEVICE_MANAGED: 741272407Shselasky err = mlx4_flow_steer_promisc_add(mdev->dev, 742272407Shselasky priv->port, 743272407Shselasky priv->base_qpn, 744272407Shselasky MLX4_FS_ALL_DEFAULT); 745219820Sjeff if (err) 746272407Shselasky en_err(priv, "Failed enabling promiscuous mode\n"); 747272407Shselasky priv->flags |= MLX4_EN_FLAG_MC_PROMISC; 748272407Shselasky break; 749219820Sjeff 750272407Shselasky case MLX4_STEERING_MODE_B0: 751272407Shselasky err = mlx4_unicast_promisc_add(mdev->dev, 752272407Shselasky priv->base_qpn, 753272407Shselasky priv->port); 754219820Sjeff if (err) 755272407Shselasky en_err(priv, "Failed enabling unicast promiscuous mode\n"); 756219820Sjeff 757272407Shselasky /* Add the default qp number as multicast 758272407Shselasky * promisc 759272407Shselasky */ 760272407Shselasky if (!(priv->flags & MLX4_EN_FLAG_MC_PROMISC)) { 761272407Shselasky err = mlx4_multicast_promisc_add(mdev->dev, 762272407Shselasky priv->base_qpn, 763272407Shselasky priv->port); 764272407Shselasky if (err) 765272407Shselasky en_err(priv, "Failed enabling multicast promiscuous mode\n"); 766272407Shselasky priv->flags |= MLX4_EN_FLAG_MC_PROMISC; 767272407Shselasky } 768272407Shselasky break; 769272407Shselasky 770272407Shselasky case MLX4_STEERING_MODE_A0: 771272407Shselasky err = mlx4_SET_PORT_qpn_calc(mdev->dev, 772272407Shselasky priv->port, 773272407Shselasky priv->base_qpn, 774272407Shselasky 1); 775219820Sjeff if (err) 776272407Shselasky en_err(priv, "Failed enabling promiscuous mode\n"); 777272407Shselasky break; 778219820Sjeff } 779272407Shselasky 780272407Shselasky /* Disable port multicast filter (unconditionally) */ 781272407Shselasky err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0, 782272407Shselasky 0, MLX4_MCAST_DISABLE); 783272407Shselasky if (err) 784272407Shselasky en_err(priv, "Failed disabling multicast filter\n"); 785219820Sjeff } 786272407Shselasky} 787219820Sjeff 788272407Shselaskystatic void mlx4_en_clear_promisc_mode(struct mlx4_en_priv *priv, 789272407Shselasky struct mlx4_en_dev *mdev) 790272407Shselasky{ 791272407Shselasky int err = 0; 792219820Sjeff 793272407Shselasky priv->flags &= ~MLX4_EN_FLAG_PROMISC; 794219820Sjeff 795272407Shselasky /* Disable promiscouos mode */ 796272407Shselasky switch (mdev->dev->caps.steering_mode) { 797272407Shselasky case MLX4_STEERING_MODE_DEVICE_MANAGED: 798272407Shselasky err = mlx4_flow_steer_promisc_remove(mdev->dev, 799272407Shselasky priv->port, 800272407Shselasky MLX4_FS_ALL_DEFAULT); 801219820Sjeff if (err) 802272407Shselasky en_err(priv, "Failed disabling promiscuous mode\n"); 803272407Shselasky priv->flags &= ~MLX4_EN_FLAG_MC_PROMISC; 804272407Shselasky break; 805219820Sjeff 806272407Shselasky case MLX4_STEERING_MODE_B0: 807272407Shselasky err = mlx4_unicast_promisc_remove(mdev->dev, 808272407Shselasky priv->base_qpn, 809272407Shselasky priv->port); 810219820Sjeff if (err) 811272407Shselasky en_err(priv, "Failed disabling unicast promiscuous mode\n"); 812272407Shselasky /* Disable Multicast promisc */ 813272407Shselasky if (priv->flags & MLX4_EN_FLAG_MC_PROMISC) { 814272407Shselasky err = mlx4_multicast_promisc_remove(mdev->dev, 815272407Shselasky priv->base_qpn, 816272407Shselasky priv->port); 817272407Shselasky if (err) 818272407Shselasky en_err(priv, "Failed disabling multicast promiscuous mode\n"); 819272407Shselasky priv->flags &= ~MLX4_EN_FLAG_MC_PROMISC; 820272407Shselasky } 821272407Shselasky break; 822272407Shselasky 823272407Shselasky case MLX4_STEERING_MODE_A0: 824272407Shselasky err = mlx4_SET_PORT_qpn_calc(mdev->dev, 825272407Shselasky priv->port, 826272407Shselasky priv->base_qpn, 0); 827272407Shselasky if (err) 828272407Shselasky en_err(priv, "Failed disabling promiscuous mode\n"); 829272407Shselasky break; 830219820Sjeff } 831272407Shselasky} 832219820Sjeff 833272407Shselaskystatic void mlx4_en_do_multicast(struct mlx4_en_priv *priv, 834272407Shselasky struct net_device *dev, 835272407Shselasky struct mlx4_en_dev *mdev) 836272407Shselasky{ 837272407Shselasky struct mlx4_en_mc_list *mclist, *tmp; 838272407Shselasky u8 mc_list[16] = {0}; 839272407Shselasky int err = 0; 840272407Shselasky u64 mcast_addr = 0; 841272407Shselasky 842272407Shselasky 843219820Sjeff /* Enable/disable the multicast filter according to IFF_ALLMULTI */ 844219820Sjeff if (dev->if_flags & IFF_ALLMULTI) { 845219820Sjeff err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0, 846219820Sjeff 0, MLX4_MCAST_DISABLE); 847219820Sjeff if (err) 848219820Sjeff en_err(priv, "Failed disabling multicast filter\n"); 849272407Shselasky 850272407Shselasky /* Add the default qp number as multicast promisc */ 851272407Shselasky if (!(priv->flags & MLX4_EN_FLAG_MC_PROMISC)) { 852272407Shselasky switch (mdev->dev->caps.steering_mode) { 853272407Shselasky case MLX4_STEERING_MODE_DEVICE_MANAGED: 854272407Shselasky err = mlx4_flow_steer_promisc_add(mdev->dev, 855272407Shselasky priv->port, 856272407Shselasky priv->base_qpn, 857272407Shselasky MLX4_FS_MC_DEFAULT); 858272407Shselasky break; 859272407Shselasky 860272407Shselasky case MLX4_STEERING_MODE_B0: 861272407Shselasky err = mlx4_multicast_promisc_add(mdev->dev, 862272407Shselasky priv->base_qpn, 863272407Shselasky priv->port); 864272407Shselasky break; 865272407Shselasky 866272407Shselasky case MLX4_STEERING_MODE_A0: 867272407Shselasky break; 868272407Shselasky } 869272407Shselasky if (err) 870272407Shselasky en_err(priv, "Failed entering multicast promisc mode\n"); 871272407Shselasky priv->flags |= MLX4_EN_FLAG_MC_PROMISC; 872272407Shselasky } 873219820Sjeff } else { 874272407Shselasky /* Disable Multicast promisc */ 875272407Shselasky if (priv->flags & MLX4_EN_FLAG_MC_PROMISC) { 876272407Shselasky switch (mdev->dev->caps.steering_mode) { 877272407Shselasky case MLX4_STEERING_MODE_DEVICE_MANAGED: 878272407Shselasky err = mlx4_flow_steer_promisc_remove(mdev->dev, 879272407Shselasky priv->port, 880272407Shselasky MLX4_FS_MC_DEFAULT); 881272407Shselasky break; 882219820Sjeff 883272407Shselasky case MLX4_STEERING_MODE_B0: 884272407Shselasky err = mlx4_multicast_promisc_remove(mdev->dev, 885272407Shselasky priv->base_qpn, 886272407Shselasky priv->port); 887272407Shselasky break; 888272407Shselasky 889272407Shselasky case MLX4_STEERING_MODE_A0: 890272407Shselasky break; 891272407Shselasky } 892272407Shselasky if (err) 893272407Shselasky en_err(priv, "Failed disabling multicast promiscuous mode\n"); 894272407Shselasky priv->flags &= ~MLX4_EN_FLAG_MC_PROMISC; 895272407Shselasky } 896272407Shselasky 897219820Sjeff err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0, 898219820Sjeff 0, MLX4_MCAST_DISABLE); 899219820Sjeff if (err) 900219820Sjeff en_err(priv, "Failed disabling multicast filter\n"); 901219820Sjeff 902219820Sjeff /* Flush mcast filter and init it with broadcast address */ 903219820Sjeff mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, ETH_BCAST, 904219820Sjeff 1, MLX4_MCAST_CONFIG); 905219820Sjeff 906219820Sjeff /* Update multicast list - we cache all addresses so they won't 907219820Sjeff * change while HW is updated holding the command semaphor */ 908272407Shselasky mlx4_en_cache_mclist(dev); 909272407Shselasky list_for_each_entry(mclist, &priv->mc_list, list) { 910272407Shselasky mcast_addr = mlx4_mac_to_u64(mclist->addr); 911219820Sjeff mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 912272407Shselasky mcast_addr, 0, MLX4_MCAST_CONFIG); 913272407Shselasky } 914219820Sjeff err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0, 915219820Sjeff 0, MLX4_MCAST_ENABLE); 916219820Sjeff if (err) 917219820Sjeff en_err(priv, "Failed enabling multicast filter\n"); 918219820Sjeff 919272407Shselasky update_mclist_flags(priv, &priv->curr_list, &priv->mc_list); 920272407Shselasky list_for_each_entry_safe(mclist, tmp, &priv->curr_list, list) { 921272407Shselasky if (mclist->action == MCLIST_REM) { 922272407Shselasky /* detach this address and delete from list */ 923272407Shselasky memcpy(&mc_list[10], mclist->addr, ETH_ALEN); 924272407Shselasky mc_list[5] = priv->port; 925272407Shselasky err = mlx4_multicast_detach(mdev->dev, 926272407Shselasky &priv->rss_map.indir_qp, 927272407Shselasky mc_list, 928272407Shselasky MLX4_PROT_ETH, 929272407Shselasky mclist->reg_id); 930272407Shselasky if (err) 931272407Shselasky en_err(priv, "Fail to detach multicast address\n"); 932272407Shselasky 933272407Shselasky /* remove from list */ 934272407Shselasky list_del(&mclist->list); 935272407Shselasky kfree(mclist); 936272407Shselasky } else if (mclist->action == MCLIST_ADD) { 937272407Shselasky /* attach the address */ 938272407Shselasky memcpy(&mc_list[10], mclist->addr, ETH_ALEN); 939272407Shselasky /* needed for B0 steering support */ 940272407Shselasky mc_list[5] = priv->port; 941272407Shselasky err = mlx4_multicast_attach(mdev->dev, 942272407Shselasky &priv->rss_map.indir_qp, 943272407Shselasky mc_list, 944272407Shselasky priv->port, 0, 945272407Shselasky MLX4_PROT_ETH, 946272407Shselasky &mclist->reg_id); 947272407Shselasky if (err) 948272407Shselasky en_err(priv, "Fail to attach multicast address\n"); 949272407Shselasky 950272407Shselasky } 951272407Shselasky } 952219820Sjeff } 953272407Shselasky} 954272407Shselasky 955272407Shselaskystatic void mlx4_en_do_set_rx_mode(struct work_struct *work) 956272407Shselasky{ 957272407Shselasky struct mlx4_en_priv *priv = container_of(work, struct mlx4_en_priv, 958272407Shselasky rx_mode_task); 959272407Shselasky struct mlx4_en_dev *mdev = priv->mdev; 960272407Shselasky struct net_device *dev = priv->dev; 961272407Shselasky 962272407Shselasky 963272407Shselasky mutex_lock(&mdev->state_lock); 964272407Shselasky if (!mdev->device_up) { 965272407Shselasky en_dbg(HW, priv, "Card is not up, ignoring rx mode change.\n"); 966272407Shselasky goto out; 967272407Shselasky } 968272407Shselasky if (!priv->port_up) { 969272407Shselasky en_dbg(HW, priv, "Port is down, ignoring rx mode change.\n"); 970272407Shselasky goto out; 971272407Shselasky } 972272407Shselasky if (!mlx4_en_QUERY_PORT(mdev, priv->port)) { 973272407Shselasky if (priv->port_state.link_state) { 974272407Shselasky priv->last_link_state = MLX4_DEV_EVENT_PORT_UP; 975292107Shselasky /* update netif baudrate */ 976292107Shselasky priv->dev->if_baudrate = 977292107Shselasky IF_Mbps(priv->port_state.link_speed); 978272407Shselasky /* Important note: the following call for if_link_state_change 979272407Shselasky * is needed for interface up scenario (start port, link state 980272407Shselasky * change) */ 981272407Shselasky if_link_state_change(priv->dev, LINK_STATE_UP); 982272407Shselasky en_dbg(HW, priv, "Link Up\n"); 983272407Shselasky } 984272407Shselasky } 985272407Shselasky 986272407Shselasky /* Promsicuous mode: disable all filters */ 987272407Shselasky if ((dev->if_flags & IFF_PROMISC) || 988272407Shselasky (priv->flags & MLX4_EN_FLAG_FORCE_PROMISC)) { 989272407Shselasky mlx4_en_set_promisc_mode(priv, mdev); 990272407Shselasky goto out; 991272407Shselasky } 992272407Shselasky 993272407Shselasky /* Not in promiscuous mode */ 994272407Shselasky if (priv->flags & MLX4_EN_FLAG_PROMISC) 995272407Shselasky mlx4_en_clear_promisc_mode(priv, mdev); 996272407Shselasky 997272407Shselasky mlx4_en_do_multicast(priv, dev, mdev); 998219820Sjeffout: 999219820Sjeff mutex_unlock(&mdev->state_lock); 1000219820Sjeff} 1001219820Sjeff 1002219820Sjeff#ifdef CONFIG_NET_POLL_CONTROLLER 1003219820Sjeffstatic void mlx4_en_netpoll(struct net_device *dev) 1004219820Sjeff{ 1005219820Sjeff struct mlx4_en_priv *priv = netdev_priv(dev); 1006219820Sjeff struct mlx4_en_cq *cq; 1007219820Sjeff unsigned long flags; 1008219820Sjeff int i; 1009219820Sjeff 1010219820Sjeff for (i = 0; i < priv->rx_ring_num; i++) { 1011272407Shselasky cq = priv->rx_cq[i]; 1012219820Sjeff spin_lock_irqsave(&cq->lock, flags); 1013219820Sjeff napi_synchronize(&cq->napi); 1014219859Sjeff mlx4_en_process_rx_cq(dev, cq, 0); 1015219820Sjeff spin_unlock_irqrestore(&cq->lock, flags); 1016219820Sjeff } 1017219820Sjeff} 1018219820Sjeff#endif 1019219820Sjeff 1020219820Sjeffstatic void mlx4_en_watchdog_timeout(void *arg) 1021219820Sjeff{ 1022272407Shselasky struct mlx4_en_priv *priv = arg; 1023272407Shselasky struct mlx4_en_dev *mdev = priv->mdev; 1024219820Sjeff 1025272407Shselasky en_dbg(DRV, priv, "Scheduling watchdog\n"); 1026272407Shselasky queue_work(mdev->workqueue, &priv->watchdog_task); 1027272407Shselasky if (priv->port_up) 1028272407Shselasky callout_reset(&priv->watchdog_timer, MLX4_EN_WATCHDOG_TIMEOUT, 1029272407Shselasky mlx4_en_watchdog_timeout, priv); 1030219820Sjeff} 1031219820Sjeff 1032219820Sjeff 1033272407Shselasky 1034219820Sjeffstatic void mlx4_en_set_default_moderation(struct mlx4_en_priv *priv) 1035219820Sjeff{ 1036219820Sjeff struct mlx4_en_cq *cq; 1037219820Sjeff int i; 1038219820Sjeff 1039219820Sjeff /* If we haven't received a specific coalescing setting 1040272407Shselasky * (module param), we set the moderation parameters as follows: 1041219820Sjeff * - moder_cnt is set to the number of mtu sized packets to 1042219820Sjeff * satisfy our coelsing target. 1043219820Sjeff * - moder_time is set to a fixed value. 1044219820Sjeff */ 1045219820Sjeff priv->rx_frames = MLX4_EN_RX_COAL_TARGET / priv->dev->if_mtu + 1; 1046219820Sjeff priv->rx_usecs = MLX4_EN_RX_COAL_TIME; 1047272407Shselasky priv->tx_frames = MLX4_EN_TX_COAL_PKTS; 1048272407Shselasky priv->tx_usecs = MLX4_EN_TX_COAL_TIME; 1049272407Shselasky en_dbg(INTR, priv, "Default coalesing params for mtu: %u - " 1050272407Shselasky "rx_frames:%d rx_usecs:%d\n", 1051272407Shselasky (unsigned)priv->dev->if_mtu, priv->rx_frames, priv->rx_usecs); 1052219820Sjeff 1053219820Sjeff /* Setup cq moderation params */ 1054219820Sjeff for (i = 0; i < priv->rx_ring_num; i++) { 1055272407Shselasky cq = priv->rx_cq[i]; 1056219820Sjeff cq->moder_cnt = priv->rx_frames; 1057219820Sjeff cq->moder_time = priv->rx_usecs; 1058257867Salfred priv->last_moder_time[i] = MLX4_EN_AUTO_CONF; 1059257867Salfred priv->last_moder_packets[i] = 0; 1060257867Salfred priv->last_moder_bytes[i] = 0; 1061219820Sjeff } 1062219820Sjeff 1063219820Sjeff for (i = 0; i < priv->tx_ring_num; i++) { 1064272407Shselasky cq = priv->tx_cq[i]; 1065272407Shselasky cq->moder_cnt = priv->tx_frames; 1066272407Shselasky cq->moder_time = priv->tx_usecs; 1067219820Sjeff } 1068219820Sjeff 1069219820Sjeff /* Reset auto-moderation params */ 1070219820Sjeff priv->pkt_rate_low = MLX4_EN_RX_RATE_LOW; 1071219820Sjeff priv->rx_usecs_low = MLX4_EN_RX_COAL_TIME_LOW; 1072219820Sjeff priv->pkt_rate_high = MLX4_EN_RX_RATE_HIGH; 1073219820Sjeff priv->rx_usecs_high = MLX4_EN_RX_COAL_TIME_HIGH; 1074219820Sjeff priv->sample_interval = MLX4_EN_SAMPLE_INTERVAL; 1075219820Sjeff priv->adaptive_rx_coal = 1; 1076219820Sjeff priv->last_moder_jiffies = 0; 1077219820Sjeff priv->last_moder_tx_packets = 0; 1078219820Sjeff} 1079219820Sjeff 1080219820Sjeffstatic void mlx4_en_auto_moderation(struct mlx4_en_priv *priv) 1081219820Sjeff{ 1082219820Sjeff unsigned long period = (unsigned long) (jiffies - priv->last_moder_jiffies); 1083219820Sjeff struct mlx4_en_cq *cq; 1084219820Sjeff unsigned long packets; 1085219820Sjeff unsigned long rate; 1086219820Sjeff unsigned long avg_pkt_size; 1087219820Sjeff unsigned long rx_packets; 1088219820Sjeff unsigned long rx_bytes; 1089219820Sjeff unsigned long rx_pkt_diff; 1090219820Sjeff int moder_time; 1091257867Salfred int ring, err; 1092219820Sjeff 1093219820Sjeff if (!priv->adaptive_rx_coal || period < priv->sample_interval * HZ) 1094219820Sjeff return; 1095272407Shselasky 1096257867Salfred for (ring = 0; ring < priv->rx_ring_num; ring++) { 1097272407Shselasky spin_lock(&priv->stats_lock); 1098272407Shselasky rx_packets = priv->rx_ring[ring]->packets; 1099272407Shselasky rx_bytes = priv->rx_ring[ring]->bytes; 1100257867Salfred spin_unlock(&priv->stats_lock); 1101219820Sjeff 1102257867Salfred rx_pkt_diff = ((unsigned long) (rx_packets - 1103257867Salfred priv->last_moder_packets[ring])); 1104257867Salfred packets = rx_pkt_diff; 1105257867Salfred rate = packets * HZ / period; 1106257867Salfred avg_pkt_size = packets ? ((unsigned long) (rx_bytes - 1107257867Salfred priv->last_moder_bytes[ring])) / packets : 0; 1108219820Sjeff 1109257867Salfred /* Apply auto-moderation only when packet rate 1110272407Shselasky * exceeds a rate that it matters */ 1111257867Salfred if (rate > (MLX4_EN_RX_RATE_THRESH / priv->rx_ring_num) && 1112272407Shselasky avg_pkt_size > MLX4_EN_AVG_PKT_SMALL) { 1113272407Shselasky if (rate < priv->pkt_rate_low) 1114219820Sjeff moder_time = priv->rx_usecs_low; 1115219820Sjeff else if (rate > priv->pkt_rate_high) 1116219820Sjeff moder_time = priv->rx_usecs_high; 1117219820Sjeff else 1118219820Sjeff moder_time = (rate - priv->pkt_rate_low) * 1119219820Sjeff (priv->rx_usecs_high - priv->rx_usecs_low) / 1120219820Sjeff (priv->pkt_rate_high - priv->pkt_rate_low) + 1121219820Sjeff priv->rx_usecs_low; 1122257867Salfred } else { 1123257867Salfred moder_time = priv->rx_usecs_low; 1124219820Sjeff } 1125219820Sjeff 1126257867Salfred if (moder_time != priv->last_moder_time[ring]) { 1127257867Salfred priv->last_moder_time[ring] = moder_time; 1128272407Shselasky cq = priv->rx_cq[ring]; 1129219820Sjeff cq->moder_time = moder_time; 1130219820Sjeff err = mlx4_en_set_cq_moder(priv, cq); 1131257867Salfred if (err) 1132272407Shselasky en_err(priv, "Failed modifying moderation for cq:%d\n", 1133272407Shselasky ring); 1134219820Sjeff } 1135257867Salfred priv->last_moder_packets[ring] = rx_packets; 1136257867Salfred priv->last_moder_bytes[ring] = rx_bytes; 1137219820Sjeff } 1138219820Sjeff 1139219820Sjeff priv->last_moder_jiffies = jiffies; 1140219820Sjeff} 1141219820Sjeff 1142219820Sjeffstatic void mlx4_en_do_get_stats(struct work_struct *work) 1143219820Sjeff{ 1144219820Sjeff struct delayed_work *delay = to_delayed_work(work); 1145219820Sjeff struct mlx4_en_priv *priv = container_of(delay, struct mlx4_en_priv, 1146219820Sjeff stats_task); 1147219820Sjeff struct mlx4_en_dev *mdev = priv->mdev; 1148219820Sjeff int err; 1149219820Sjeff 1150219820Sjeff mutex_lock(&mdev->state_lock); 1151219820Sjeff if (mdev->device_up) { 1152219820Sjeff if (priv->port_up) { 1153272407Shselasky err = mlx4_en_DUMP_ETH_STATS(mdev, priv->port, 0); 1154272407Shselasky if (err) 1155272407Shselasky en_dbg(HW, priv, "Could not update stats\n"); 1156219820Sjeff 1157219820Sjeff mlx4_en_auto_moderation(priv); 1158219820Sjeff } 1159219820Sjeff 1160219820Sjeff queue_delayed_work(mdev->workqueue, &priv->stats_task, STATS_DELAY); 1161219820Sjeff } 1162219820Sjeff mutex_unlock(&mdev->state_lock); 1163219820Sjeff} 1164219820Sjeff 1165272407Shselasky/* mlx4_en_service_task - Run service task for tasks that needed to be done 1166272407Shselasky * periodically 1167272407Shselasky */ 1168272407Shselaskystatic void mlx4_en_service_task(struct work_struct *work) 1169272407Shselasky{ 1170272407Shselasky struct delayed_work *delay = to_delayed_work(work); 1171272407Shselasky struct mlx4_en_priv *priv = container_of(delay, struct mlx4_en_priv, 1172272407Shselasky service_task); 1173272407Shselasky struct mlx4_en_dev *mdev = priv->mdev; 1174272407Shselasky 1175272407Shselasky mutex_lock(&mdev->state_lock); 1176272407Shselasky if (mdev->device_up) { 1177272407Shselasky queue_delayed_work(mdev->workqueue, &priv->service_task, 1178272407Shselasky SERVICE_TASK_DELAY); 1179272407Shselasky } 1180272407Shselasky mutex_unlock(&mdev->state_lock); 1181272407Shselasky} 1182272407Shselasky 1183219820Sjeffstatic void mlx4_en_linkstate(struct work_struct *work) 1184219820Sjeff{ 1185219820Sjeff struct mlx4_en_priv *priv = container_of(work, struct mlx4_en_priv, 1186219820Sjeff linkstate_task); 1187219820Sjeff struct mlx4_en_dev *mdev = priv->mdev; 1188219820Sjeff int linkstate = priv->link_state; 1189219820Sjeff 1190219820Sjeff mutex_lock(&mdev->state_lock); 1191219820Sjeff /* If observable port state changed set carrier state and 1192219820Sjeff * report to system log */ 1193219820Sjeff if (priv->last_link_state != linkstate) { 1194219820Sjeff if (linkstate == MLX4_DEV_EVENT_PORT_DOWN) { 1195272407Shselasky en_info(priv, "Link Down\n"); 1196219820Sjeff if_link_state_change(priv->dev, LINK_STATE_DOWN); 1197273879Shselasky /* update netif baudrate */ 1198273879Shselasky priv->dev->if_baudrate = 0; 1199273879Shselasky 1200292107Shselasky /* make sure the port is up before notifying the OS. 1201292107Shselasky * This is tricky since we get here on INIT_PORT and 1202272407Shselasky * in such case we can't tell the OS the port is up. 1203272407Shselasky * To solve this there is a call to if_link_state_change 1204272407Shselasky * in set_rx_mode. 1205272407Shselasky * */ 1206272407Shselasky } else if (priv->port_up && (linkstate == MLX4_DEV_EVENT_PORT_UP)){ 1207273879Shselasky if (mlx4_en_QUERY_PORT(priv->mdev, priv->port)) 1208273879Shselasky en_info(priv, "Query port failed\n"); 1209273879Shselasky priv->dev->if_baudrate = 1210273879Shselasky IF_Mbps(priv->port_state.link_speed); 1211219820Sjeff en_info(priv, "Link Up\n"); 1212219820Sjeff if_link_state_change(priv->dev, LINK_STATE_UP); 1213219820Sjeff } 1214219820Sjeff } 1215219820Sjeff priv->last_link_state = linkstate; 1216219820Sjeff mutex_unlock(&mdev->state_lock); 1217219820Sjeff} 1218219820Sjeff 1219219820Sjeff 1220272407Shselaskyint mlx4_en_start_port(struct net_device *dev) 1221219820Sjeff{ 1222219820Sjeff struct mlx4_en_priv *priv = netdev_priv(dev); 1223219820Sjeff struct mlx4_en_dev *mdev = priv->mdev; 1224219820Sjeff struct mlx4_en_cq *cq; 1225219820Sjeff struct mlx4_en_tx_ring *tx_ring; 1226219820Sjeff int rx_index = 0; 1227219820Sjeff int tx_index = 0; 1228219820Sjeff int err = 0; 1229219820Sjeff int i; 1230219820Sjeff int j; 1231272407Shselasky u8 mc_list[16] = {0}; 1232219820Sjeff 1233272407Shselasky 1234219820Sjeff if (priv->port_up) { 1235219820Sjeff en_dbg(DRV, priv, "start port called while port already up\n"); 1236219820Sjeff return 0; 1237219820Sjeff } 1238219820Sjeff 1239272407Shselasky INIT_LIST_HEAD(&priv->mc_list); 1240272407Shselasky INIT_LIST_HEAD(&priv->curr_list); 1241272407Shselasky INIT_LIST_HEAD(&priv->ethtool_list); 1242272407Shselasky 1243219820Sjeff /* Calculate Rx buf size */ 1244219820Sjeff dev->if_mtu = min(dev->if_mtu, priv->max_mtu); 1245272407Shselasky mlx4_en_calc_rx_buf(dev); 1246219820Sjeff en_dbg(DRV, priv, "Rx buf size:%d\n", priv->rx_mb_size); 1247219820Sjeff 1248219820Sjeff /* Configure rx cq's and rings */ 1249219820Sjeff err = mlx4_en_activate_rx_rings(priv); 1250219820Sjeff if (err) { 1251219820Sjeff en_err(priv, "Failed to activate RX rings\n"); 1252219820Sjeff return err; 1253219820Sjeff } 1254219820Sjeff for (i = 0; i < priv->rx_ring_num; i++) { 1255272407Shselasky cq = priv->rx_cq[i]; 1256219820Sjeff 1257272407Shselasky mlx4_en_cq_init_lock(cq); 1258272407Shselasky err = mlx4_en_activate_cq(priv, cq, i); 1259219820Sjeff if (err) { 1260219820Sjeff en_err(priv, "Failed activating Rx CQ\n"); 1261219820Sjeff goto cq_err; 1262219820Sjeff } 1263219820Sjeff for (j = 0; j < cq->size; j++) 1264219820Sjeff cq->buf[j].owner_sr_opcode = MLX4_CQE_OWNER_MASK; 1265219820Sjeff err = mlx4_en_set_cq_moder(priv, cq); 1266219820Sjeff if (err) { 1267219820Sjeff en_err(priv, "Failed setting cq moderation parameters"); 1268219820Sjeff mlx4_en_deactivate_cq(priv, cq); 1269219820Sjeff goto cq_err; 1270219820Sjeff } 1271219820Sjeff mlx4_en_arm_cq(priv, cq); 1272272407Shselasky priv->rx_ring[i]->cqn = cq->mcq.cqn; 1273219820Sjeff ++rx_index; 1274219820Sjeff } 1275219820Sjeff 1276272407Shselasky /* Set qp number */ 1277272407Shselasky en_dbg(DRV, priv, "Getting qp number for port %d\n", priv->port); 1278272407Shselasky err = mlx4_en_get_qp(priv); 1279272407Shselasky if (err) { 1280272407Shselasky en_err(priv, "Failed getting eth qp\n"); 1281272407Shselasky goto cq_err; 1282272407Shselasky } 1283272407Shselasky mdev->mac_removed[priv->port] = 0; 1284272407Shselasky 1285272407Shselasky /* gets default allocated counter index from func cap */ 1286272407Shselasky /* or sink counter index if no resources */ 1287272407Shselasky priv->counter_index = mdev->dev->caps.def_counter_index[priv->port - 1]; 1288272407Shselasky 1289272407Shselasky en_dbg(DRV, priv, "%s: default counter index %d for port %d\n", 1290272407Shselasky __func__, priv->counter_index, priv->port); 1291272407Shselasky 1292219820Sjeff err = mlx4_en_config_rss_steer(priv); 1293219820Sjeff if (err) { 1294219820Sjeff en_err(priv, "Failed configuring rss steering\n"); 1295272407Shselasky goto mac_err; 1296219820Sjeff } 1297219820Sjeff 1298272407Shselasky err = mlx4_en_create_drop_qp(priv); 1299272407Shselasky if (err) 1300272407Shselasky goto rss_err; 1301272407Shselasky 1302219820Sjeff /* Configure tx cq's and rings */ 1303219820Sjeff for (i = 0; i < priv->tx_ring_num; i++) { 1304219820Sjeff /* Configure cq */ 1305272407Shselasky cq = priv->tx_cq[i]; 1306272407Shselasky err = mlx4_en_activate_cq(priv, cq, i); 1307219820Sjeff if (err) { 1308279731Shselasky en_err(priv, "Failed activating Tx CQ\n"); 1309219820Sjeff goto tx_err; 1310219820Sjeff } 1311219820Sjeff err = mlx4_en_set_cq_moder(priv, cq); 1312219820Sjeff if (err) { 1313219820Sjeff en_err(priv, "Failed setting cq moderation parameters"); 1314219820Sjeff mlx4_en_deactivate_cq(priv, cq); 1315219820Sjeff goto tx_err; 1316219820Sjeff } 1317219820Sjeff en_dbg(DRV, priv, "Resetting index of collapsed CQ:%d to -1\n", i); 1318219820Sjeff cq->buf->wqe_index = cpu_to_be16(0xffff); 1319219820Sjeff 1320219820Sjeff /* Configure ring */ 1321272407Shselasky tx_ring = priv->tx_ring[i]; 1322272407Shselasky 1323272407Shselasky err = mlx4_en_activate_tx_ring(priv, tx_ring, cq->mcq.cqn, 1324272407Shselasky i / priv->num_tx_rings_p_up); 1325219820Sjeff if (err) { 1326279731Shselasky en_err(priv, "Failed activating Tx ring %d\n", i); 1327219820Sjeff mlx4_en_deactivate_cq(priv, cq); 1328219820Sjeff goto tx_err; 1329219820Sjeff } 1330272407Shselasky 1331272407Shselasky /* Arm CQ for TX completions */ 1332272407Shselasky mlx4_en_arm_cq(priv, cq); 1333272407Shselasky 1334219820Sjeff /* Set initial ownership of all Tx TXBBs to SW (1) */ 1335219820Sjeff for (j = 0; j < tx_ring->buf_size; j += STAMP_STRIDE) 1336219820Sjeff *((u32 *) (tx_ring->buf + j)) = 0xffffffff; 1337219820Sjeff ++tx_index; 1338219820Sjeff } 1339219820Sjeff 1340219820Sjeff /* Configure port */ 1341219820Sjeff err = mlx4_SET_PORT_general(mdev->dev, priv->port, 1342272407Shselasky priv->rx_mb_size, 1343219820Sjeff priv->prof->tx_pause, 1344219820Sjeff priv->prof->tx_ppp, 1345219820Sjeff priv->prof->rx_pause, 1346219820Sjeff priv->prof->rx_ppp); 1347219820Sjeff if (err) { 1348272407Shselasky en_err(priv, "Failed setting port general configurations for port %d, with error %d\n", 1349272407Shselasky priv->port, err); 1350219820Sjeff goto tx_err; 1351219820Sjeff } 1352219820Sjeff /* Set default qp number */ 1353219820Sjeff err = mlx4_SET_PORT_qpn_calc(mdev->dev, priv->port, priv->base_qpn, 0); 1354219820Sjeff if (err) { 1355219820Sjeff en_err(priv, "Failed setting default qp numbers\n"); 1356219820Sjeff goto tx_err; 1357219820Sjeff } 1358219820Sjeff 1359219820Sjeff /* Init port */ 1360219820Sjeff en_dbg(HW, priv, "Initializing port\n"); 1361219820Sjeff err = mlx4_INIT_PORT(mdev->dev, priv->port); 1362219820Sjeff if (err) { 1363219820Sjeff en_err(priv, "Failed Initializing port\n"); 1364272407Shselasky goto tx_err; 1365219820Sjeff } 1366219820Sjeff 1367272407Shselasky /* Attach rx QP to bradcast address */ 1368272407Shselasky memset(&mc_list[10], 0xff, ETH_ALEN); 1369272407Shselasky mc_list[5] = priv->port; /* needed for B0 steering support */ 1370272407Shselasky if (mlx4_multicast_attach(mdev->dev, &priv->rss_map.indir_qp, mc_list, 1371272407Shselasky priv->port, 0, MLX4_PROT_ETH, 1372272407Shselasky &priv->broadcast_id)) 1373272407Shselasky mlx4_warn(mdev, "Failed Attaching Broadcast\n"); 1374219820Sjeff 1375272407Shselasky /* Must redo promiscuous mode setup. */ 1376272407Shselasky priv->flags &= ~(MLX4_EN_FLAG_PROMISC | MLX4_EN_FLAG_MC_PROMISC); 1377220016Sjeff 1378272407Shselasky /* Schedule multicast task to populate multicast list */ 1379272407Shselasky queue_work(mdev->workqueue, &priv->rx_mode_task); 1380220016Sjeff 1381219820Sjeff priv->port_up = true; 1382219820Sjeff 1383272407Shselasky /* Enable the queues. */ 1384272407Shselasky dev->if_drv_flags &= ~IFF_DRV_OACTIVE; 1385272407Shselasky dev->if_drv_flags |= IFF_DRV_RUNNING; 1386272407Shselasky#ifdef CONFIG_DEBUG_FS 1387272407Shselasky mlx4_en_create_debug_files(priv); 1388272407Shselasky#endif 1389272407Shselasky callout_reset(&priv->watchdog_timer, MLX4_EN_WATCHDOG_TIMEOUT, 1390272407Shselasky mlx4_en_watchdog_timeout, priv); 1391219820Sjeff 1392219820Sjeff 1393219820Sjeff return 0; 1394219820Sjeff 1395219820Sjefftx_err: 1396219820Sjeff while (tx_index--) { 1397272407Shselasky mlx4_en_deactivate_tx_ring(priv, priv->tx_ring[tx_index]); 1398272407Shselasky mlx4_en_deactivate_cq(priv, priv->tx_cq[tx_index]); 1399219820Sjeff } 1400272407Shselasky mlx4_en_destroy_drop_qp(priv); 1401272407Shselaskyrss_err: 1402219820Sjeff mlx4_en_release_rss_steer(priv); 1403272407Shselaskymac_err: 1404272407Shselasky mlx4_en_put_qp(priv); 1405219820Sjeffcq_err: 1406219820Sjeff while (rx_index--) 1407272407Shselasky mlx4_en_deactivate_cq(priv, priv->rx_cq[rx_index]); 1408219820Sjeff for (i = 0; i < priv->rx_ring_num; i++) 1409272407Shselasky mlx4_en_deactivate_rx_ring(priv, priv->rx_ring[i]); 1410219820Sjeff 1411219820Sjeff return err; /* need to close devices */ 1412219820Sjeff} 1413219820Sjeff 1414219820Sjeff 1415272407Shselaskyvoid mlx4_en_stop_port(struct net_device *dev) 1416219820Sjeff{ 1417219820Sjeff struct mlx4_en_priv *priv = netdev_priv(dev); 1418219820Sjeff struct mlx4_en_dev *mdev = priv->mdev; 1419272407Shselasky struct mlx4_en_mc_list *mclist, *tmp; 1420219820Sjeff int i; 1421272407Shselasky u8 mc_list[16] = {0}; 1422219820Sjeff 1423219820Sjeff if (!priv->port_up) { 1424219820Sjeff en_dbg(DRV, priv, "stop port called while port already down\n"); 1425219820Sjeff return; 1426219820Sjeff } 1427219820Sjeff 1428272407Shselasky#ifdef CONFIG_DEBUG_FS 1429272407Shselasky mlx4_en_delete_debug_files(priv); 1430272407Shselasky#endif 1431272407Shselasky 1432272407Shselasky /* close port*/ 1433272407Shselasky mlx4_CLOSE_PORT(mdev->dev, priv->port); 1434272407Shselasky 1435219820Sjeff /* Set port as not active */ 1436219820Sjeff priv->port_up = false; 1437272407Shselasky if (priv->counter_index != 0xff) { 1438272407Shselasky mlx4_counter_free(mdev->dev, priv->port, priv->counter_index); 1439272407Shselasky priv->counter_index = 0xff; 1440272407Shselasky } 1441219820Sjeff 1442272407Shselasky /* Promsicuous mode */ 1443272407Shselasky if (mdev->dev->caps.steering_mode == 1444272407Shselasky MLX4_STEERING_MODE_DEVICE_MANAGED) { 1445272407Shselasky priv->flags &= ~(MLX4_EN_FLAG_PROMISC | 1446272407Shselasky MLX4_EN_FLAG_MC_PROMISC); 1447272407Shselasky mlx4_flow_steer_promisc_remove(mdev->dev, 1448272407Shselasky priv->port, 1449272407Shselasky MLX4_FS_ALL_DEFAULT); 1450272407Shselasky mlx4_flow_steer_promisc_remove(mdev->dev, 1451272407Shselasky priv->port, 1452272407Shselasky MLX4_FS_MC_DEFAULT); 1453272407Shselasky } else if (priv->flags & MLX4_EN_FLAG_PROMISC) { 1454272407Shselasky priv->flags &= ~MLX4_EN_FLAG_PROMISC; 1455219820Sjeff 1456272407Shselasky /* Disable promiscouos mode */ 1457272407Shselasky mlx4_unicast_promisc_remove(mdev->dev, priv->base_qpn, 1458272407Shselasky priv->port); 1459272407Shselasky 1460272407Shselasky /* Disable Multicast promisc */ 1461272407Shselasky if (priv->flags & MLX4_EN_FLAG_MC_PROMISC) { 1462272407Shselasky mlx4_multicast_promisc_remove(mdev->dev, priv->base_qpn, 1463272407Shselasky priv->port); 1464272407Shselasky priv->flags &= ~MLX4_EN_FLAG_MC_PROMISC; 1465272407Shselasky } 1466272407Shselasky } 1467272407Shselasky 1468272407Shselasky /* Detach All multicasts */ 1469272407Shselasky memset(&mc_list[10], 0xff, ETH_ALEN); 1470272407Shselasky mc_list[5] = priv->port; /* needed for B0 steering support */ 1471272407Shselasky mlx4_multicast_detach(mdev->dev, &priv->rss_map.indir_qp, mc_list, 1472272407Shselasky MLX4_PROT_ETH, priv->broadcast_id); 1473272407Shselasky list_for_each_entry(mclist, &priv->curr_list, list) { 1474272407Shselasky memcpy(&mc_list[10], mclist->addr, ETH_ALEN); 1475272407Shselasky mc_list[5] = priv->port; 1476272407Shselasky mlx4_multicast_detach(mdev->dev, &priv->rss_map.indir_qp, 1477272407Shselasky mc_list, MLX4_PROT_ETH, mclist->reg_id); 1478272407Shselasky } 1479272407Shselasky mlx4_en_clear_list(dev); 1480272407Shselasky list_for_each_entry_safe(mclist, tmp, &priv->curr_list, list) { 1481272407Shselasky list_del(&mclist->list); 1482272407Shselasky kfree(mclist); 1483272407Shselasky } 1484272407Shselasky 1485272407Shselasky /* Flush multicast filter */ 1486272407Shselasky mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0, 1, MLX4_MCAST_CONFIG); 1487272407Shselasky mlx4_en_destroy_drop_qp(priv); 1488272407Shselasky 1489219820Sjeff /* Free TX Rings */ 1490219820Sjeff for (i = 0; i < priv->tx_ring_num; i++) { 1491272407Shselasky mlx4_en_deactivate_tx_ring(priv, priv->tx_ring[i]); 1492272407Shselasky mlx4_en_deactivate_cq(priv, priv->tx_cq[i]); 1493219820Sjeff } 1494219820Sjeff msleep(10); 1495219820Sjeff 1496219820Sjeff for (i = 0; i < priv->tx_ring_num; i++) 1497272407Shselasky mlx4_en_free_tx_buf(dev, priv->tx_ring[i]); 1498219820Sjeff 1499219820Sjeff /* Free RSS qps */ 1500219820Sjeff mlx4_en_release_rss_steer(priv); 1501219820Sjeff 1502272407Shselasky /* Unregister Mac address for the port */ 1503272407Shselasky mlx4_en_put_qp(priv); 1504272407Shselasky mdev->mac_removed[priv->port] = 1; 1505272407Shselasky 1506219820Sjeff /* Free RX Rings */ 1507219820Sjeff for (i = 0; i < priv->rx_ring_num; i++) { 1508272407Shselasky struct mlx4_en_cq *cq = priv->rx_cq[i]; 1509272407Shselasky mlx4_en_deactivate_rx_ring(priv, priv->rx_ring[i]); 1510272407Shselasky mlx4_en_deactivate_cq(priv, cq); 1511219820Sjeff } 1512219820Sjeff 1513272407Shselasky callout_stop(&priv->watchdog_timer); 1514219820Sjeff 1515272407Shselasky dev->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 1516219820Sjeff} 1517219820Sjeff 1518219820Sjeffstatic void mlx4_en_restart(struct work_struct *work) 1519219820Sjeff{ 1520219820Sjeff struct mlx4_en_priv *priv = container_of(work, struct mlx4_en_priv, 1521219820Sjeff watchdog_task); 1522219820Sjeff struct mlx4_en_dev *mdev = priv->mdev; 1523219820Sjeff struct net_device *dev = priv->dev; 1524219820Sjeff struct mlx4_en_tx_ring *ring; 1525219820Sjeff int i; 1526219820Sjeff 1527272407Shselasky 1528219820Sjeff if (priv->blocked == 0 || priv->port_up == 0) 1529219820Sjeff return; 1530219820Sjeff for (i = 0; i < priv->tx_ring_num; i++) { 1531272407Shselasky ring = priv->tx_ring[i]; 1532219820Sjeff if (ring->blocked && 1533272407Shselasky ring->watchdog_time + MLX4_EN_WATCHDOG_TIMEOUT < ticks) 1534219820Sjeff goto reset; 1535219820Sjeff } 1536219820Sjeff return; 1537219820Sjeff 1538219820Sjeffreset: 1539219820Sjeff priv->port_stats.tx_timeout++; 1540219820Sjeff en_dbg(DRV, priv, "Watchdog task called for port %d\n", priv->port); 1541219820Sjeff 1542219820Sjeff mutex_lock(&mdev->state_lock); 1543219820Sjeff if (priv->port_up) { 1544272407Shselasky mlx4_en_stop_port(dev); 1545272407Shselasky //for (i = 0; i < priv->tx_ring_num; i++) 1546272407Shselasky // netdev_tx_reset_queue(priv->tx_ring[i]->tx_queue); 1547272407Shselasky if (mlx4_en_start_port(dev)) 1548219820Sjeff en_err(priv, "Failed restarting port %d\n", priv->port); 1549219820Sjeff } 1550219820Sjeff mutex_unlock(&mdev->state_lock); 1551219820Sjeff} 1552219820Sjeff 1553272407Shselaskystatic void mlx4_en_clear_stats(struct net_device *dev) 1554219820Sjeff{ 1555272407Shselasky struct mlx4_en_priv *priv = netdev_priv(dev); 1556272407Shselasky struct mlx4_en_dev *mdev = priv->mdev; 1557272407Shselasky int i; 1558253774Sjhb 1559272407Shselasky if (!mlx4_is_slave(mdev->dev)) 1560272407Shselasky if (mlx4_en_DUMP_ETH_STATS(mdev, priv->port, 1)) 1561272407Shselasky en_dbg(HW, priv, "Failed dumping statistics\n"); 1562272407Shselasky 1563272407Shselasky memset(&priv->pstats, 0, sizeof(priv->pstats)); 1564272407Shselasky memset(&priv->pkstats, 0, sizeof(priv->pkstats)); 1565272407Shselasky memset(&priv->port_stats, 0, sizeof(priv->port_stats)); 1566272407Shselasky memset(&priv->vport_stats, 0, sizeof(priv->vport_stats)); 1567272407Shselasky 1568272407Shselasky for (i = 0; i < priv->tx_ring_num; i++) { 1569272407Shselasky priv->tx_ring[i]->bytes = 0; 1570272407Shselasky priv->tx_ring[i]->packets = 0; 1571272407Shselasky priv->tx_ring[i]->tx_csum = 0; 1572292107Shselasky priv->tx_ring[i]->oversized_packets = 0; 1573272407Shselasky } 1574272407Shselasky for (i = 0; i < priv->rx_ring_num; i++) { 1575272407Shselasky priv->rx_ring[i]->bytes = 0; 1576272407Shselasky priv->rx_ring[i]->packets = 0; 1577272407Shselasky priv->rx_ring[i]->csum_ok = 0; 1578272407Shselasky priv->rx_ring[i]->csum_none = 0; 1579272407Shselasky } 1580253774Sjhb} 1581253774Sjhb 1582272407Shselaskystatic void mlx4_en_open(void* arg) 1583253774Sjhb{ 1584253774Sjhb 1585272407Shselasky struct mlx4_en_priv *priv; 1586272407Shselasky struct mlx4_en_dev *mdev; 1587272407Shselasky struct net_device *dev; 1588272407Shselasky int err = 0; 1589219820Sjeff 1590272407Shselasky priv = arg; 1591272407Shselasky mdev = priv->mdev; 1592272407Shselasky dev = priv->dev; 1593219820Sjeff 1594272407Shselasky 1595272407Shselasky mutex_lock(&mdev->state_lock); 1596272407Shselasky 1597219820Sjeff if (!mdev->device_up) { 1598219820Sjeff en_err(priv, "Cannot open - device down/disabled\n"); 1599272407Shselasky goto out; 1600219820Sjeff } 1601219820Sjeff 1602272407Shselasky /* Reset HW statistics and SW counters */ 1603272407Shselasky mlx4_en_clear_stats(dev); 1604219820Sjeff 1605272407Shselasky err = mlx4_en_start_port(dev); 1606272407Shselasky if (err) 1607272407Shselasky en_err(priv, "Failed starting port:%d\n", priv->port); 1608219820Sjeff 1609272407Shselaskyout: 1610272407Shselasky mutex_unlock(&mdev->state_lock); 1611272407Shselasky return; 1612219820Sjeff} 1613219820Sjeff 1614219820Sjeffvoid mlx4_en_free_resources(struct mlx4_en_priv *priv) 1615219820Sjeff{ 1616219820Sjeff int i; 1617219820Sjeff 1618272407Shselasky#ifdef CONFIG_RFS_ACCEL 1619272407Shselasky if (priv->dev->rx_cpu_rmap) { 1620272407Shselasky free_irq_cpu_rmap(priv->dev->rx_cpu_rmap); 1621272407Shselasky priv->dev->rx_cpu_rmap = NULL; 1622272407Shselasky } 1623272407Shselasky#endif 1624272407Shselasky 1625219820Sjeff for (i = 0; i < priv->tx_ring_num; i++) { 1626272407Shselasky if (priv->tx_ring && priv->tx_ring[i]) 1627219820Sjeff mlx4_en_destroy_tx_ring(priv, &priv->tx_ring[i]); 1628272407Shselasky if (priv->tx_cq && priv->tx_cq[i]) 1629219820Sjeff mlx4_en_destroy_cq(priv, &priv->tx_cq[i]); 1630219820Sjeff } 1631219820Sjeff 1632219820Sjeff for (i = 0; i < priv->rx_ring_num; i++) { 1633272407Shselasky if (priv->rx_ring[i]) 1634272407Shselasky mlx4_en_destroy_rx_ring(priv, &priv->rx_ring[i], 1635272407Shselasky priv->prof->rx_ring_size, priv->stride); 1636272407Shselasky if (priv->rx_cq[i]) 1637219820Sjeff mlx4_en_destroy_cq(priv, &priv->rx_cq[i]); 1638219820Sjeff } 1639272407Shselasky 1640318540Shselasky if (priv->stat_sysctl != NULL) 1641219820Sjeff sysctl_ctx_free(&priv->stat_ctx); 1642219820Sjeff} 1643219820Sjeff 1644219820Sjeffint mlx4_en_alloc_resources(struct mlx4_en_priv *priv) 1645219820Sjeff{ 1646219820Sjeff struct mlx4_en_port_profile *prof = priv->prof; 1647219820Sjeff int i; 1648272407Shselasky int node = 0; 1649219820Sjeff 1650272407Shselasky /* Create rx Rings */ 1651272407Shselasky for (i = 0; i < priv->rx_ring_num; i++) { 1652272407Shselasky if (mlx4_en_create_cq(priv, &priv->rx_cq[i], 1653272407Shselasky prof->rx_ring_size, i, RX, node)) 1654219820Sjeff goto err; 1655219820Sjeff 1656272407Shselasky if (mlx4_en_create_rx_ring(priv, &priv->rx_ring[i], 1657272407Shselasky prof->rx_ring_size, node)) 1658219820Sjeff goto err; 1659219820Sjeff } 1660219820Sjeff 1661272407Shselasky /* Create tx Rings */ 1662272407Shselasky for (i = 0; i < priv->tx_ring_num; i++) { 1663272407Shselasky if (mlx4_en_create_cq(priv, &priv->tx_cq[i], 1664272407Shselasky prof->tx_ring_size, i, TX, node)) 1665219820Sjeff goto err; 1666219820Sjeff 1667272407Shselasky if (mlx4_en_create_tx_ring(priv, &priv->tx_ring[i], 1668272407Shselasky prof->tx_ring_size, TXBB_SIZE, node, i)) 1669219820Sjeff goto err; 1670219820Sjeff } 1671219820Sjeff 1672272407Shselasky#ifdef CONFIG_RFS_ACCEL 1673272407Shselasky priv->dev->rx_cpu_rmap = alloc_irq_cpu_rmap(priv->rx_ring_num); 1674272407Shselasky if (!priv->dev->rx_cpu_rmap) 1675272407Shselasky goto err; 1676272407Shselasky#endif 1677272407Shselasky /* Re-create stat sysctls in case the number of rings changed. */ 1678219820Sjeff mlx4_en_sysctl_stat(priv); 1679219820Sjeff return 0; 1680219820Sjeff 1681219820Sjefferr: 1682219820Sjeff en_err(priv, "Failed to allocate NIC resources\n"); 1683272407Shselasky for (i = 0; i < priv->rx_ring_num; i++) { 1684272407Shselasky if (priv->rx_ring[i]) 1685272407Shselasky mlx4_en_destroy_rx_ring(priv, &priv->rx_ring[i], 1686272407Shselasky prof->rx_ring_size, 1687272407Shselasky priv->stride); 1688272407Shselasky if (priv->rx_cq[i]) 1689272407Shselasky mlx4_en_destroy_cq(priv, &priv->rx_cq[i]); 1690272407Shselasky } 1691272407Shselasky for (i = 0; i < priv->tx_ring_num; i++) { 1692272407Shselasky if (priv->tx_ring[i]) 1693272407Shselasky mlx4_en_destroy_tx_ring(priv, &priv->tx_ring[i]); 1694272407Shselasky if (priv->tx_cq[i]) 1695272407Shselasky mlx4_en_destroy_cq(priv, &priv->tx_cq[i]); 1696272407Shselasky } 1697272407Shselasky priv->port_up = false; 1698219820Sjeff return -ENOMEM; 1699219820Sjeff} 1700219820Sjeff 1701272407Shselaskystruct en_port_attribute { 1702272407Shselasky struct attribute attr; 1703272407Shselasky ssize_t (*show)(struct en_port *, struct en_port_attribute *, char *buf); 1704272407Shselasky ssize_t (*store)(struct en_port *, struct en_port_attribute *, char *buf, size_t count); 1705272407Shselasky}; 1706219820Sjeff 1707272407Shselasky#define PORT_ATTR_RO(_name) \ 1708272407Shselaskystruct en_port_attribute en_port_attr_##_name = __ATTR_RO(_name) 1709272407Shselasky 1710272407Shselasky#define EN_PORT_ATTR(_name, _mode, _show, _store) \ 1711272407Shselaskystruct en_port_attribute en_port_attr_##_name = __ATTR(_name, _mode, _show, _store) 1712272407Shselasky 1713219820Sjeffvoid mlx4_en_destroy_netdev(struct net_device *dev) 1714219820Sjeff{ 1715219820Sjeff struct mlx4_en_priv *priv = netdev_priv(dev); 1716219820Sjeff struct mlx4_en_dev *mdev = priv->mdev; 1717219820Sjeff 1718219820Sjeff en_dbg(DRV, priv, "Destroying netdev on port:%d\n", priv->port); 1719219820Sjeff 1720272407Shselasky if (priv->vlan_attach != NULL) 1721272407Shselasky EVENTHANDLER_DEREGISTER(vlan_config, priv->vlan_attach); 1722272407Shselasky if (priv->vlan_detach != NULL) 1723272407Shselasky EVENTHANDLER_DEREGISTER(vlan_unconfig, priv->vlan_detach); 1724219820Sjeff 1725219820Sjeff /* Unregister device - this will close the port if it was up */ 1726292107Shselasky if (priv->registered) { 1727292107Shselasky mutex_lock(&mdev->state_lock); 1728219820Sjeff ether_ifdetach(dev); 1729292107Shselasky mutex_unlock(&mdev->state_lock); 1730292107Shselasky } 1731219820Sjeff 1732253774Sjhb mutex_lock(&mdev->state_lock); 1733272407Shselasky mlx4_en_stop_port(dev); 1734253774Sjhb mutex_unlock(&mdev->state_lock); 1735253774Sjhb 1736319567Shselasky if (priv->allocated) 1737319567Shselasky mlx4_free_hwq_res(mdev->dev, &priv->res, MLX4_EN_PAGE_SIZE); 1738272407Shselasky 1739219820Sjeff cancel_delayed_work(&priv->stats_task); 1740272407Shselasky cancel_delayed_work(&priv->service_task); 1741219820Sjeff /* flush any pending task for this netdev */ 1742219820Sjeff flush_workqueue(mdev->workqueue); 1743272407Shselasky callout_drain(&priv->watchdog_timer); 1744219820Sjeff 1745219820Sjeff /* Detach the netdev so tasks would not attempt to access it */ 1746219820Sjeff mutex_lock(&mdev->state_lock); 1747219820Sjeff mdev->pndev[priv->port] = NULL; 1748219820Sjeff mutex_unlock(&mdev->state_lock); 1749219820Sjeff 1750272407Shselasky 1751219820Sjeff mlx4_en_free_resources(priv); 1752255932Salfred 1753272407Shselasky /* freeing the sysctl conf cannot be called from within mlx4_en_free_resources */ 1754318540Shselasky if (priv->conf_sysctl != NULL) 1755256810Salfred sysctl_ctx_free(&priv->conf_ctx); 1756256810Salfred 1757272407Shselasky kfree(priv->tx_ring); 1758272407Shselasky kfree(priv->tx_cq); 1759272407Shselasky 1760272407Shselasky kfree(priv); 1761272407Shselasky if_free(dev); 1762272407Shselasky 1763219820Sjeff} 1764219820Sjeff 1765219820Sjeffstatic int mlx4_en_change_mtu(struct net_device *dev, int new_mtu) 1766219820Sjeff{ 1767219820Sjeff struct mlx4_en_priv *priv = netdev_priv(dev); 1768219820Sjeff struct mlx4_en_dev *mdev = priv->mdev; 1769219820Sjeff int err = 0; 1770219820Sjeff 1771272407Shselasky en_dbg(DRV, priv, "Change MTU called - current:%u new:%u\n", 1772272407Shselasky (unsigned)dev->if_mtu, (unsigned)new_mtu); 1773219820Sjeff 1774219820Sjeff if ((new_mtu < MLX4_EN_MIN_MTU) || (new_mtu > priv->max_mtu)) { 1775322507Shselasky en_err(priv, "Bad MTU size:%d, max %u.\n", new_mtu, 1776322507Shselasky priv->max_mtu); 1777219820Sjeff return -EPERM; 1778219820Sjeff } 1779219820Sjeff mutex_lock(&mdev->state_lock); 1780219820Sjeff dev->if_mtu = new_mtu; 1781219820Sjeff if (dev->if_drv_flags & IFF_DRV_RUNNING) { 1782219820Sjeff if (!mdev->device_up) { 1783219820Sjeff /* NIC is probably restarting - let watchdog task reset 1784272407Shselasky * * the port */ 1785219820Sjeff en_dbg(DRV, priv, "Change MTU called with card down!?\n"); 1786219820Sjeff } else { 1787272407Shselasky mlx4_en_stop_port(dev); 1788272407Shselasky err = mlx4_en_start_port(dev); 1789219820Sjeff if (err) { 1790219820Sjeff en_err(priv, "Failed restarting port:%d\n", 1791272407Shselasky priv->port); 1792219820Sjeff queue_work(mdev->workqueue, &priv->watchdog_task); 1793219820Sjeff } 1794219820Sjeff } 1795219820Sjeff } 1796219820Sjeff mutex_unlock(&mdev->state_lock); 1797219820Sjeff return 0; 1798219820Sjeff} 1799219820Sjeff 1800219820Sjeffstatic int mlx4_en_calc_media(struct mlx4_en_priv *priv) 1801219820Sjeff{ 1802219820Sjeff int trans_type; 1803219820Sjeff int active; 1804219820Sjeff 1805219820Sjeff active = IFM_ETHER; 1806219820Sjeff if (priv->last_link_state == MLX4_DEV_EVENT_PORT_DOWN) 1807219820Sjeff return (active); 1808219820Sjeff active |= IFM_FDX; 1809219820Sjeff trans_type = priv->port_state.transciver; 1810219820Sjeff /* XXX I don't know all of the transceiver values. */ 1811234099Sjhb switch (priv->port_state.link_speed) { 1812234099Sjhb case 1000: 1813219820Sjeff active |= IFM_1000_T; 1814234099Sjhb break; 1815234099Sjhb case 10000: 1816234099Sjhb if (trans_type > 0 && trans_type <= 0xC) 1817234099Sjhb active |= IFM_10G_SR; 1818234099Sjhb else if (trans_type == 0x80 || trans_type == 0) 1819234099Sjhb active |= IFM_10G_CX4; 1820234099Sjhb break; 1821234099Sjhb case 40000: 1822234099Sjhb active |= IFM_40G_CR4; 1823234099Sjhb break; 1824234099Sjhb } 1825219820Sjeff if (priv->prof->tx_pause) 1826219820Sjeff active |= IFM_ETH_TXPAUSE; 1827219820Sjeff if (priv->prof->rx_pause) 1828219820Sjeff active |= IFM_ETH_RXPAUSE; 1829219820Sjeff 1830219820Sjeff return (active); 1831219820Sjeff} 1832219820Sjeff 1833219820Sjeffstatic void mlx4_en_media_status(struct ifnet *dev, struct ifmediareq *ifmr) 1834219820Sjeff{ 1835219820Sjeff struct mlx4_en_priv *priv; 1836219820Sjeff 1837219820Sjeff priv = dev->if_softc; 1838219820Sjeff ifmr->ifm_status = IFM_AVALID; 1839219820Sjeff if (priv->last_link_state != MLX4_DEV_EVENT_PORT_DOWN) 1840219820Sjeff ifmr->ifm_status |= IFM_ACTIVE; 1841219820Sjeff ifmr->ifm_active = mlx4_en_calc_media(priv); 1842219820Sjeff 1843219820Sjeff return; 1844219820Sjeff} 1845219820Sjeff 1846219820Sjeffstatic int mlx4_en_media_change(struct ifnet *dev) 1847219820Sjeff{ 1848219820Sjeff struct mlx4_en_priv *priv; 1849219820Sjeff struct ifmedia *ifm; 1850219820Sjeff int rxpause; 1851219820Sjeff int txpause; 1852219820Sjeff int error; 1853219820Sjeff 1854219820Sjeff priv = dev->if_softc; 1855219820Sjeff ifm = &priv->media; 1856219820Sjeff rxpause = txpause = 0; 1857219820Sjeff error = 0; 1858219820Sjeff 1859219820Sjeff if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) 1860219820Sjeff return (EINVAL); 1861219820Sjeff switch (IFM_SUBTYPE(ifm->ifm_media)) { 1862219820Sjeff case IFM_AUTO: 1863219820Sjeff break; 1864219820Sjeff case IFM_10G_SR: 1865219820Sjeff case IFM_10G_CX4: 1866219820Sjeff case IFM_1000_T: 1867272407Shselasky case IFM_40G_CR4: 1868272407Shselasky if ((IFM_SUBTYPE(ifm->ifm_media) 1869272407Shselasky == IFM_SUBTYPE(mlx4_en_calc_media(priv))) 1870272407Shselasky && (ifm->ifm_media & IFM_FDX)) 1871219820Sjeff break; 1872219820Sjeff /* Fallthrough */ 1873219820Sjeff default: 1874219820Sjeff printf("%s: Only auto media type\n", if_name(dev)); 1875219820Sjeff return (EINVAL); 1876219820Sjeff } 1877219820Sjeff /* Allow user to set/clear pause */ 1878219820Sjeff if (IFM_OPTIONS(ifm->ifm_media) & IFM_ETH_RXPAUSE) 1879219820Sjeff rxpause = 1; 1880219820Sjeff if (IFM_OPTIONS(ifm->ifm_media) & IFM_ETH_TXPAUSE) 1881219820Sjeff txpause = 1; 1882219820Sjeff if (priv->prof->tx_pause != txpause || priv->prof->rx_pause != rxpause) { 1883219820Sjeff priv->prof->tx_pause = txpause; 1884219820Sjeff priv->prof->rx_pause = rxpause; 1885219820Sjeff error = -mlx4_SET_PORT_general(priv->mdev->dev, priv->port, 1886219820Sjeff priv->rx_mb_size + ETHER_CRC_LEN, priv->prof->tx_pause, 1887219820Sjeff priv->prof->tx_ppp, priv->prof->rx_pause, 1888219820Sjeff priv->prof->rx_ppp); 1889219820Sjeff } 1890219820Sjeff return (error); 1891219820Sjeff} 1892219820Sjeff 1893219820Sjeffstatic int mlx4_en_ioctl(struct ifnet *dev, u_long command, caddr_t data) 1894219820Sjeff{ 1895219820Sjeff struct mlx4_en_priv *priv; 1896219820Sjeff struct mlx4_en_dev *mdev; 1897219820Sjeff struct ifreq *ifr; 1898219820Sjeff int error; 1899219820Sjeff int mask; 1900219820Sjeff 1901219820Sjeff error = 0; 1902219820Sjeff mask = 0; 1903219820Sjeff priv = dev->if_softc; 1904219820Sjeff mdev = priv->mdev; 1905219820Sjeff ifr = (struct ifreq *) data; 1906219820Sjeff switch (command) { 1907272407Shselasky 1908219820Sjeff case SIOCSIFMTU: 1909219820Sjeff error = -mlx4_en_change_mtu(dev, ifr->ifr_mtu); 1910219820Sjeff break; 1911219820Sjeff case SIOCSIFFLAGS: 1912219820Sjeff if (dev->if_flags & IFF_UP) { 1913280018Shselasky if ((dev->if_drv_flags & IFF_DRV_RUNNING) == 0) { 1914280018Shselasky mutex_lock(&mdev->state_lock); 1915219820Sjeff mlx4_en_start_port(dev); 1916280018Shselasky mutex_unlock(&mdev->state_lock); 1917280018Shselasky } else { 1918272407Shselasky mlx4_en_set_rx_mode(dev); 1919280018Shselasky } 1920219820Sjeff } else { 1921280018Shselasky mutex_lock(&mdev->state_lock); 1922219820Sjeff if (dev->if_drv_flags & IFF_DRV_RUNNING) { 1923219820Sjeff mlx4_en_stop_port(dev); 1924280018Shselasky if_link_state_change(dev, LINK_STATE_DOWN); 1925219820Sjeff } 1926280018Shselasky mutex_unlock(&mdev->state_lock); 1927219820Sjeff } 1928219820Sjeff break; 1929219820Sjeff case SIOCADDMULTI: 1930219820Sjeff case SIOCDELMULTI: 1931272407Shselasky mlx4_en_set_rx_mode(dev); 1932219820Sjeff break; 1933219820Sjeff case SIOCSIFMEDIA: 1934219820Sjeff case SIOCGIFMEDIA: 1935219820Sjeff error = ifmedia_ioctl(dev, ifr, &priv->media, command); 1936219820Sjeff break; 1937219820Sjeff case SIOCSIFCAP: 1938253774Sjhb mutex_lock(&mdev->state_lock); 1939219820Sjeff mask = ifr->ifr_reqcap ^ dev->if_capenable; 1940292107Shselasky if (mask & IFCAP_TXCSUM) { 1941292107Shselasky dev->if_capenable ^= IFCAP_TXCSUM; 1942292107Shselasky dev->if_hwassist ^= (CSUM_TCP | CSUM_UDP | CSUM_IP); 1943292107Shselasky 1944292107Shselasky if (IFCAP_TSO4 & dev->if_capenable && 1945292107Shselasky !(IFCAP_TXCSUM & dev->if_capenable)) { 1946292107Shselasky dev->if_capenable &= ~IFCAP_TSO4; 1947292107Shselasky dev->if_hwassist &= ~CSUM_IP_TSO; 1948292107Shselasky if_printf(dev, 1949292107Shselasky "tso4 disabled due to -txcsum.\n"); 1950292107Shselasky } 1951292107Shselasky } 1952292107Shselasky if (mask & IFCAP_TXCSUM_IPV6) { 1953292107Shselasky dev->if_capenable ^= IFCAP_TXCSUM_IPV6; 1954292107Shselasky dev->if_hwassist ^= (CSUM_UDP_IPV6 | CSUM_TCP_IPV6); 1955292107Shselasky 1956292107Shselasky if (IFCAP_TSO6 & dev->if_capenable && 1957292107Shselasky !(IFCAP_TXCSUM_IPV6 & dev->if_capenable)) { 1958292107Shselasky dev->if_capenable &= ~IFCAP_TSO6; 1959292107Shselasky dev->if_hwassist &= ~CSUM_IP6_TSO; 1960292107Shselasky if_printf(dev, 1961292107Shselasky "tso6 disabled due to -txcsum6.\n"); 1962292107Shselasky } 1963292107Shselasky } 1964292107Shselasky if (mask & IFCAP_RXCSUM) 1965292107Shselasky dev->if_capenable ^= IFCAP_RXCSUM; 1966292107Shselasky if (mask & IFCAP_RXCSUM_IPV6) 1967292107Shselasky dev->if_capenable ^= IFCAP_RXCSUM_IPV6; 1968292107Shselasky 1969292107Shselasky if (mask & IFCAP_TSO4) { 1970292107Shselasky if (!(IFCAP_TSO4 & dev->if_capenable) && 1971292107Shselasky !(IFCAP_TXCSUM & dev->if_capenable)) { 1972292107Shselasky if_printf(dev, "enable txcsum first.\n"); 1973292107Shselasky error = EAGAIN; 1974292107Shselasky goto out; 1975292107Shselasky } 1976219820Sjeff dev->if_capenable ^= IFCAP_TSO4; 1977292107Shselasky dev->if_hwassist ^= CSUM_IP_TSO; 1978292107Shselasky } 1979292107Shselasky if (mask & IFCAP_TSO6) { 1980292107Shselasky if (!(IFCAP_TSO6 & dev->if_capenable) && 1981292107Shselasky !(IFCAP_TXCSUM_IPV6 & dev->if_capenable)) { 1982292107Shselasky if_printf(dev, "enable txcsum6 first.\n"); 1983292107Shselasky error = EAGAIN; 1984292107Shselasky goto out; 1985292107Shselasky } 1986272407Shselasky dev->if_capenable ^= IFCAP_TSO6; 1987292107Shselasky dev->if_hwassist ^= CSUM_IP6_TSO; 1988292107Shselasky } 1989219820Sjeff if (mask & IFCAP_LRO) 1990219820Sjeff dev->if_capenable ^= IFCAP_LRO; 1991219820Sjeff if (mask & IFCAP_VLAN_HWTAGGING) 1992219820Sjeff dev->if_capenable ^= IFCAP_VLAN_HWTAGGING; 1993219820Sjeff if (mask & IFCAP_VLAN_HWFILTER) 1994219820Sjeff dev->if_capenable ^= IFCAP_VLAN_HWFILTER; 1995220016Sjeff if (mask & IFCAP_WOL_MAGIC) 1996220016Sjeff dev->if_capenable ^= IFCAP_WOL_MAGIC; 1997219820Sjeff if (dev->if_drv_flags & IFF_DRV_RUNNING) 1998272407Shselasky mlx4_en_start_port(dev); 1999292107Shselaskyout: 2000253774Sjhb mutex_unlock(&mdev->state_lock); 2001219820Sjeff VLAN_CAPABILITIES(dev); 2002219820Sjeff break; 2003292107Shselasky#if __FreeBSD_version >= 1100036 2004286841Sglebius case SIOCGI2C: { 2005286841Sglebius struct ifi2creq i2c; 2006286841Sglebius 2007286841Sglebius error = copyin(ifr->ifr_data, &i2c, sizeof(i2c)); 2008286841Sglebius if (error) 2009286841Sglebius break; 2010286841Sglebius if (i2c.len > sizeof(i2c.data)) { 2011286841Sglebius error = EINVAL; 2012286841Sglebius break; 2013286841Sglebius } 2014286841Sglebius /* 2015286841Sglebius * Note that we ignore i2c.addr here. The driver hardcodes 2016286841Sglebius * the address to 0x50, while standard expects it to be 0xA0. 2017286841Sglebius */ 2018286841Sglebius error = mlx4_get_module_info(mdev->dev, priv->port, 2019286841Sglebius i2c.offset, i2c.len, i2c.data); 2020286841Sglebius if (error < 0) { 2021286841Sglebius error = -error; 2022286841Sglebius break; 2023286841Sglebius } 2024286841Sglebius error = copyout(&i2c, ifr->ifr_data, sizeof(i2c)); 2025286841Sglebius break; 2026286841Sglebius } 2027292107Shselasky#endif 2028219820Sjeff default: 2029219820Sjeff error = ether_ioctl(dev, command, data); 2030219820Sjeff break; 2031219820Sjeff } 2032219820Sjeff 2033219820Sjeff return (error); 2034219820Sjeff} 2035219820Sjeff 2036272407Shselasky 2037272407Shselaskyint mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, 2038272407Shselasky struct mlx4_en_port_profile *prof) 2039219820Sjeff{ 2040272407Shselasky struct net_device *dev; 2041272407Shselasky struct mlx4_en_priv *priv; 2042272407Shselasky uint8_t dev_addr[ETHER_ADDR_LEN]; 2043272407Shselasky int err; 2044272407Shselasky int i; 2045219820Sjeff 2046272407Shselasky priv = kzalloc(sizeof(*priv), GFP_KERNEL); 2047272407Shselasky dev = priv->dev = if_alloc(IFT_ETHER); 2048272407Shselasky if (dev == NULL) { 2049272407Shselasky en_err(priv, "Net device allocation failed\n"); 2050272407Shselasky kfree(priv); 2051272407Shselasky return -ENOMEM; 2052272407Shselasky } 2053272407Shselasky dev->if_softc = priv; 2054320067Shselasky if_initname(dev, "mlxen", (device_get_unit( 2055320067Shselasky mdev->pdev->dev.bsddev) * MLX4_MAX_PORTS) + port - 1); 2056272407Shselasky dev->if_mtu = ETHERMTU; 2057272407Shselasky dev->if_init = mlx4_en_open; 2058272407Shselasky dev->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 2059272407Shselasky dev->if_ioctl = mlx4_en_ioctl; 2060272407Shselasky dev->if_transmit = mlx4_en_transmit; 2061272407Shselasky dev->if_qflush = mlx4_en_qflush; 2062272407Shselasky dev->if_snd.ifq_maxlen = prof->tx_ring_size; 2063219820Sjeff 2064272407Shselasky /* 2065272407Shselasky * Initialize driver private data 2066272407Shselasky */ 2067272407Shselasky priv->counter_index = 0xff; 2068272407Shselasky spin_lock_init(&priv->stats_lock); 2069272407Shselasky INIT_WORK(&priv->rx_mode_task, mlx4_en_do_set_rx_mode); 2070272407Shselasky INIT_WORK(&priv->watchdog_task, mlx4_en_restart); 2071272407Shselasky INIT_WORK(&priv->linkstate_task, mlx4_en_linkstate); 2072272407Shselasky INIT_DELAYED_WORK(&priv->stats_task, mlx4_en_do_get_stats); 2073272407Shselasky INIT_DELAYED_WORK(&priv->service_task, mlx4_en_service_task); 2074272407Shselasky callout_init(&priv->watchdog_timer, 1); 2075272407Shselasky#ifdef CONFIG_RFS_ACCEL 2076272407Shselasky INIT_LIST_HEAD(&priv->filters); 2077272407Shselasky spin_lock_init(&priv->filters_lock); 2078272407Shselasky#endif 2079219820Sjeff 2080272407Shselasky priv->msg_enable = MLX4_EN_MSG_LEVEL; 2081272407Shselasky priv->dev = dev; 2082272407Shselasky priv->mdev = mdev; 2083272407Shselasky priv->ddev = &mdev->pdev->dev; 2084272407Shselasky priv->prof = prof; 2085272407Shselasky priv->port = port; 2086272407Shselasky priv->port_up = false; 2087272407Shselasky priv->flags = prof->flags; 2088272407Shselasky 2089272407Shselasky priv->num_tx_rings_p_up = mdev->profile.num_tx_rings_p_up; 2090272407Shselasky priv->tx_ring_num = prof->tx_ring_num; 2091272407Shselasky priv->tx_ring = kcalloc(MAX_TX_RINGS, 2092272407Shselasky sizeof(struct mlx4_en_tx_ring *), GFP_KERNEL); 2093272407Shselasky if (!priv->tx_ring) { 2094272407Shselasky err = -ENOMEM; 2095272407Shselasky goto out; 2096219820Sjeff } 2097272407Shselasky priv->tx_cq = kcalloc(sizeof(struct mlx4_en_cq *), MAX_TX_RINGS, 2098272407Shselasky GFP_KERNEL); 2099272407Shselasky if (!priv->tx_cq) { 2100272407Shselasky err = -ENOMEM; 2101272407Shselasky goto out; 2102272407Shselasky } 2103292107Shselasky 2104272407Shselasky priv->rx_ring_num = prof->rx_ring_num; 2105272407Shselasky priv->cqe_factor = (mdev->dev->caps.cqe_size == 64) ? 1 : 0; 2106272407Shselasky priv->mac_index = -1; 2107272407Shselasky priv->last_ifq_jiffies = 0; 2108272407Shselasky priv->if_counters_rx_errors = 0; 2109272407Shselasky priv->if_counters_rx_no_buffer = 0; 2110272407Shselasky#ifdef CONFIG_MLX4_EN_DCB 2111272407Shselasky if (!mlx4_is_slave(priv->mdev->dev)) { 2112272407Shselasky priv->dcbx_cap = DCB_CAP_DCBX_HOST; 2113272407Shselasky priv->flags |= MLX4_EN_FLAG_DCB_ENABLED; 2114272407Shselasky if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_ETS_CFG) { 2115272407Shselasky dev->dcbnl_ops = &mlx4_en_dcbnl_ops; 2116272407Shselasky } else { 2117272407Shselasky en_info(priv, "QoS disabled - no HW support\n"); 2118272407Shselasky dev->dcbnl_ops = &mlx4_en_dcbnl_pfc_ops; 2119272407Shselasky } 2120272407Shselasky } 2121272407Shselasky#endif 2122272407Shselasky 2123272407Shselasky for (i = 0; i < MLX4_EN_MAC_HASH_SIZE; ++i) 2124272407Shselasky INIT_HLIST_HEAD(&priv->mac_hash[i]); 2125272407Shselasky 2126272407Shselasky /* Query for default mac and max mtu */ 2127272407Shselasky priv->max_mtu = mdev->dev->caps.eth_mtu_cap[priv->port]; 2128272407Shselasky priv->mac = mdev->dev->caps.def_mac[priv->port]; 2129272407Shselasky if (ILLEGAL_MAC(priv->mac)) { 2130272407Shselasky#if BITS_PER_LONG == 64 2131272407Shselasky en_err(priv, "Port: %d, invalid mac burned: 0x%lx, quiting\n", 2132272407Shselasky priv->port, priv->mac); 2133272407Shselasky#elif BITS_PER_LONG == 32 2134272407Shselasky en_err(priv, "Port: %d, invalid mac burned: 0x%llx, quiting\n", 2135272407Shselasky priv->port, priv->mac); 2136272407Shselasky#endif 2137272407Shselasky err = -EINVAL; 2138272407Shselasky goto out; 2139272407Shselasky } 2140272407Shselasky 2141272407Shselasky priv->stride = roundup_pow_of_two(sizeof(struct mlx4_en_rx_desc) + 2142272407Shselasky DS_SIZE); 2143272407Shselasky 2144272407Shselasky mlx4_en_sysctl_conf(priv); 2145272407Shselasky 2146219820Sjeff err = mlx4_en_alloc_resources(priv); 2147272407Shselasky if (err) 2148272407Shselasky goto out; 2149272407Shselasky 2150272407Shselasky /* Allocate page for receive rings */ 2151272407Shselasky err = mlx4_alloc_hwq_res(mdev->dev, &priv->res, 2152272407Shselasky MLX4_EN_PAGE_SIZE, MLX4_EN_PAGE_SIZE); 2153219820Sjeff if (err) { 2154272407Shselasky en_err(priv, "Failed to allocate page for rx qps\n"); 2155219820Sjeff goto out; 2156219820Sjeff } 2157272407Shselasky priv->allocated = 1; 2158272407Shselasky 2159272407Shselasky /* 2160272407Shselasky * Set driver features 2161272407Shselasky */ 2162292107Shselasky dev->if_capabilities |= IFCAP_HWCSUM | IFCAP_HWCSUM_IPV6; 2163272407Shselasky dev->if_capabilities |= IFCAP_VLAN_MTU | IFCAP_VLAN_HWTAGGING; 2164272407Shselasky dev->if_capabilities |= IFCAP_VLAN_HWCSUM | IFCAP_VLAN_HWFILTER; 2165272407Shselasky dev->if_capabilities |= IFCAP_LINKSTATE | IFCAP_JUMBO_MTU; 2166272407Shselasky dev->if_capabilities |= IFCAP_LRO; 2167306955Shselasky dev->if_capabilities |= IFCAP_HWSTATS; 2168272407Shselasky 2169272407Shselasky if (mdev->LSO_support) 2170272407Shselasky dev->if_capabilities |= IFCAP_TSO4 | IFCAP_TSO6 | IFCAP_VLAN_HWTSO; 2171274043Shselasky 2172272407Shselasky /* set TSO limits so that we don't have to drop TX packets */ 2173292107Shselasky dev->if_hw_tsomax = MLX4_EN_TX_MAX_PAYLOAD_SIZE - (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN) /* hdr */; 2174292107Shselasky dev->if_hw_tsomaxsegcount = MLX4_EN_TX_MAX_MBUF_FRAGS - 1 /* hdr */; 2175292107Shselasky dev->if_hw_tsomaxsegsize = MLX4_EN_TX_MAX_MBUF_SIZE; 2176274043Shselasky 2177272407Shselasky dev->if_capenable = dev->if_capabilities; 2178272407Shselasky 2179272407Shselasky dev->if_hwassist = 0; 2180272407Shselasky if (dev->if_capenable & (IFCAP_TSO4 | IFCAP_TSO6)) 2181272407Shselasky dev->if_hwassist |= CSUM_TSO; 2182272407Shselasky if (dev->if_capenable & IFCAP_TXCSUM) 2183272407Shselasky dev->if_hwassist |= (CSUM_TCP | CSUM_UDP | CSUM_IP); 2184292107Shselasky if (dev->if_capenable & IFCAP_TXCSUM_IPV6) 2185292107Shselasky dev->if_hwassist |= (CSUM_UDP_IPV6 | CSUM_TCP_IPV6); 2186272407Shselasky 2187272407Shselasky 2188272407Shselasky /* Register for VLAN events */ 2189272407Shselasky priv->vlan_attach = EVENTHANDLER_REGISTER(vlan_config, 2190272407Shselasky mlx4_en_vlan_rx_add_vid, priv, EVENTHANDLER_PRI_FIRST); 2191272407Shselasky priv->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig, 2192272407Shselasky mlx4_en_vlan_rx_kill_vid, priv, EVENTHANDLER_PRI_FIRST); 2193272407Shselasky 2194272407Shselasky mdev->pndev[priv->port] = dev; 2195272407Shselasky 2196272407Shselasky priv->last_link_state = MLX4_DEV_EVENT_PORT_DOWN; 2197272407Shselasky mlx4_en_set_default_moderation(priv); 2198272407Shselasky 2199272407Shselasky /* Set default MAC */ 2200272407Shselasky for (i = 0; i < ETHER_ADDR_LEN; i++) 2201272407Shselasky dev_addr[ETHER_ADDR_LEN - 1 - i] = (u8) (priv->mac >> (8 * i)); 2202272407Shselasky 2203272407Shselasky 2204272407Shselasky ether_ifattach(dev, dev_addr); 2205272407Shselasky if_link_state_change(dev, LINK_STATE_DOWN); 2206272407Shselasky ifmedia_init(&priv->media, IFM_IMASK | IFM_ETH_FMASK, 2207272407Shselasky mlx4_en_media_change, mlx4_en_media_status); 2208272407Shselasky ifmedia_add(&priv->media, IFM_ETHER | IFM_FDX | IFM_1000_T, 0, NULL); 2209272407Shselasky ifmedia_add(&priv->media, IFM_ETHER | IFM_FDX | IFM_10G_SR, 0, NULL); 2210272407Shselasky ifmedia_add(&priv->media, IFM_ETHER | IFM_FDX | IFM_10G_CX4, 0, NULL); 2211272407Shselasky ifmedia_add(&priv->media, IFM_ETHER | IFM_FDX | IFM_40G_CR4, 0, NULL); 2212272407Shselasky ifmedia_add(&priv->media, IFM_ETHER | IFM_AUTO, 0, NULL); 2213272407Shselasky ifmedia_set(&priv->media, IFM_ETHER | IFM_AUTO); 2214272407Shselasky 2215272407Shselasky en_warn(priv, "Using %d TX rings\n", prof->tx_ring_num); 2216272407Shselasky en_warn(priv, "Using %d RX rings\n", prof->rx_ring_num); 2217272407Shselasky 2218272407Shselasky priv->registered = 1; 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 2224272407Shselasky priv->rx_mb_size = dev->if_mtu + ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN; 2225272407Shselasky err = mlx4_SET_PORT_general(mdev->dev, priv->port, 2226272407Shselasky priv->rx_mb_size, 2227272407Shselasky prof->tx_pause, prof->tx_ppp, 2228272407Shselasky prof->rx_pause, prof->rx_ppp); 2229272407Shselasky if (err) { 2230272407Shselasky en_err(priv, "Failed setting port general configurations " 2231272407Shselasky "for port %d, with error %d\n", priv->port, err); 2232272407Shselasky goto out; 2233219820Sjeff } 2234272407Shselasky 2235272407Shselasky /* Init port */ 2236272407Shselasky en_warn(priv, "Initializing port\n"); 2237272407Shselasky err = mlx4_INIT_PORT(mdev->dev, priv->port); 2238272407Shselasky if (err) { 2239272407Shselasky en_err(priv, "Failed Initializing port\n"); 2240272407Shselasky goto out; 2241272407Shselasky } 2242272407Shselasky 2243272407Shselasky queue_delayed_work(mdev->workqueue, &priv->stats_task, STATS_DELAY); 2244272407Shselasky 2245272407Shselasky if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_TS) 2246272407Shselasky queue_delayed_work(mdev->workqueue, &priv->service_task, SERVICE_TASK_DELAY); 2247272407Shselasky 2248272407Shselasky return 0; 2249272407Shselasky 2250219820Sjeffout: 2251272407Shselasky mlx4_en_destroy_netdev(dev); 2252219820Sjeff return err; 2253219820Sjeff} 2254279731Shselasky 2255272407Shselaskystatic int mlx4_en_set_ring_size(struct net_device *dev, 2256272407Shselasky int rx_size, int tx_size) 2257272407Shselasky{ 2258272407Shselasky struct mlx4_en_priv *priv = netdev_priv(dev); 2259272407Shselasky struct mlx4_en_dev *mdev = priv->mdev; 2260272407Shselasky int port_up = 0; 2261272407Shselasky int err = 0; 2262219820Sjeff 2263272407Shselasky rx_size = roundup_pow_of_two(rx_size); 2264272407Shselasky rx_size = max_t(u32, rx_size, MLX4_EN_MIN_RX_SIZE); 2265272407Shselasky rx_size = min_t(u32, rx_size, MLX4_EN_MAX_RX_SIZE); 2266272407Shselasky tx_size = roundup_pow_of_two(tx_size); 2267272407Shselasky tx_size = max_t(u32, tx_size, MLX4_EN_MIN_TX_SIZE); 2268272407Shselasky tx_size = min_t(u32, tx_size, MLX4_EN_MAX_TX_SIZE); 2269272407Shselasky 2270272407Shselasky if (rx_size == (priv->port_up ? 2271272407Shselasky priv->rx_ring[0]->actual_size : priv->rx_ring[0]->size) && 2272272407Shselasky tx_size == priv->tx_ring[0]->size) 2273272407Shselasky return 0; 2274272407Shselasky mutex_lock(&mdev->state_lock); 2275272407Shselasky if (priv->port_up) { 2276272407Shselasky port_up = 1; 2277272407Shselasky mlx4_en_stop_port(dev); 2278272407Shselasky } 2279272407Shselasky mlx4_en_free_resources(priv); 2280272407Shselasky priv->prof->tx_ring_size = tx_size; 2281272407Shselasky priv->prof->rx_ring_size = rx_size; 2282272407Shselasky err = mlx4_en_alloc_resources(priv); 2283272407Shselasky if (err) { 2284272407Shselasky en_err(priv, "Failed reallocating port resources\n"); 2285272407Shselasky goto out; 2286272407Shselasky } 2287272407Shselasky if (port_up) { 2288272407Shselasky err = mlx4_en_start_port(dev); 2289272407Shselasky if (err) 2290272407Shselasky en_err(priv, "Failed starting port\n"); 2291272407Shselasky } 2292272407Shselaskyout: 2293272407Shselasky mutex_unlock(&mdev->state_lock); 2294272407Shselasky return err; 2295272407Shselasky} 2296219820Sjeffstatic int mlx4_en_set_rx_ring_size(SYSCTL_HANDLER_ARGS) 2297219820Sjeff{ 2298272407Shselasky struct mlx4_en_priv *priv; 2299272407Shselasky int size; 2300272407Shselasky int error; 2301219820Sjeff 2302272407Shselasky priv = arg1; 2303272407Shselasky size = priv->prof->rx_ring_size; 2304272407Shselasky error = sysctl_handle_int(oidp, &size, 0, req); 2305272407Shselasky if (error || !req->newptr) 2306272407Shselasky return (error); 2307272407Shselasky error = -mlx4_en_set_ring_size(priv->dev, size, 2308272407Shselasky priv->prof->tx_ring_size); 2309272407Shselasky return (error); 2310219820Sjeff} 2311219820Sjeff 2312219820Sjeffstatic int mlx4_en_set_tx_ring_size(SYSCTL_HANDLER_ARGS) 2313219820Sjeff{ 2314272407Shselasky struct mlx4_en_priv *priv; 2315272407Shselasky int size; 2316272407Shselasky int error; 2317219820Sjeff 2318272407Shselasky priv = arg1; 2319272407Shselasky size = priv->prof->tx_ring_size; 2320272407Shselasky error = sysctl_handle_int(oidp, &size, 0, req); 2321272407Shselasky if (error || !req->newptr) 2322272407Shselasky return (error); 2323272407Shselasky error = -mlx4_en_set_ring_size(priv->dev, priv->prof->rx_ring_size, 2324272407Shselasky size); 2325219820Sjeff 2326272407Shselasky return (error); 2327219820Sjeff} 2328219820Sjeff 2329292107Shselaskystatic int mlx4_en_get_module_info(struct net_device *dev, 2330292107Shselasky struct ethtool_modinfo *modinfo) 2331292107Shselasky{ 2332292107Shselasky struct mlx4_en_priv *priv = netdev_priv(dev); 2333292107Shselasky struct mlx4_en_dev *mdev = priv->mdev; 2334292107Shselasky int ret; 2335292107Shselasky u8 data[4]; 2336292107Shselasky 2337292107Shselasky /* Read first 2 bytes to get Module & REV ID */ 2338292107Shselasky ret = mlx4_get_module_info(mdev->dev, priv->port, 2339292107Shselasky 0/*offset*/, 2/*size*/, data); 2340292107Shselasky 2341292107Shselasky if (ret < 2) { 2342292107Shselasky en_err(priv, "Failed to read eeprom module first two bytes, error: 0x%x\n", -ret); 2343292107Shselasky return -EIO; 2344292107Shselasky } 2345292107Shselasky 2346292107Shselasky switch (data[0] /* identifier */) { 2347292107Shselasky case MLX4_MODULE_ID_QSFP: 2348292107Shselasky modinfo->type = ETH_MODULE_SFF_8436; 2349292107Shselasky modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN; 2350292107Shselasky break; 2351292107Shselasky case MLX4_MODULE_ID_QSFP_PLUS: 2352292107Shselasky if (data[1] >= 0x3) { /* revision id */ 2353292107Shselasky modinfo->type = ETH_MODULE_SFF_8636; 2354292107Shselasky modinfo->eeprom_len = ETH_MODULE_SFF_8636_LEN; 2355292107Shselasky } else { 2356292107Shselasky modinfo->type = ETH_MODULE_SFF_8436; 2357292107Shselasky modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN; 2358292107Shselasky } 2359292107Shselasky break; 2360292107Shselasky case MLX4_MODULE_ID_QSFP28: 2361292107Shselasky modinfo->type = ETH_MODULE_SFF_8636; 2362292107Shselasky modinfo->eeprom_len = ETH_MODULE_SFF_8636_LEN; 2363292107Shselasky break; 2364292107Shselasky case MLX4_MODULE_ID_SFP: 2365292107Shselasky modinfo->type = ETH_MODULE_SFF_8472; 2366292107Shselasky modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN; 2367292107Shselasky break; 2368292107Shselasky default: 2369292107Shselasky en_err(priv, "mlx4_en_get_module_info : Not recognized cable type\n"); 2370292107Shselasky return -EINVAL; 2371292107Shselasky } 2372292107Shselasky 2373292107Shselasky return 0; 2374292107Shselasky} 2375292107Shselasky 2376292107Shselaskystatic int mlx4_en_get_module_eeprom(struct net_device *dev, 2377292107Shselasky struct ethtool_eeprom *ee, 2378292107Shselasky u8 *data) 2379292107Shselasky{ 2380292107Shselasky struct mlx4_en_priv *priv = netdev_priv(dev); 2381292107Shselasky struct mlx4_en_dev *mdev = priv->mdev; 2382292107Shselasky int offset = ee->offset; 2383292107Shselasky int i = 0, ret; 2384292107Shselasky 2385292107Shselasky if (ee->len == 0) 2386292107Shselasky return -EINVAL; 2387292107Shselasky 2388292107Shselasky memset(data, 0, ee->len); 2389292107Shselasky 2390292107Shselasky while (i < ee->len) { 2391292107Shselasky en_dbg(DRV, priv, 2392292107Shselasky "mlx4_get_module_info i(%d) offset(%d) len(%d)\n", 2393292107Shselasky i, offset, ee->len - i); 2394292107Shselasky 2395292107Shselasky ret = mlx4_get_module_info(mdev->dev, priv->port, 2396292107Shselasky offset, ee->len - i, data + i); 2397292107Shselasky 2398292107Shselasky if (!ret) /* Done reading */ 2399292107Shselasky return 0; 2400292107Shselasky 2401292107Shselasky if (ret < 0) { 2402292107Shselasky en_err(priv, 2403292107Shselasky "mlx4_get_module_info i(%d) offset(%d) bytes_to_read(%d) - FAILED (0x%x)\n", 2404292107Shselasky i, offset, ee->len - i, ret); 2405292107Shselasky return -1; 2406292107Shselasky } 2407292107Shselasky 2408292107Shselasky i += ret; 2409292107Shselasky offset += ret; 2410292107Shselasky } 2411292107Shselasky return 0; 2412292107Shselasky} 2413292107Shselasky 2414292107Shselaskystatic void mlx4_en_print_eeprom(u8 *data, __u32 len) 2415292107Shselasky{ 2416292107Shselasky int i; 2417292107Shselasky int j = 0; 2418292107Shselasky int row = 0; 2419292107Shselasky const int NUM_OF_BYTES = 16; 2420292107Shselasky 2421292107Shselasky printf("\nOffset\t\tValues\n"); 2422292107Shselasky printf("------\t\t------\n"); 2423292107Shselasky while(row < len){ 2424292107Shselasky printf("0x%04x\t\t",row); 2425292107Shselasky for(i=0; i < NUM_OF_BYTES; i++){ 2426292107Shselasky printf("%02x ", data[j]); 2427292107Shselasky row++; 2428292107Shselasky j++; 2429292107Shselasky } 2430292107Shselasky printf("\n"); 2431292107Shselasky } 2432292107Shselasky} 2433292107Shselasky 2434292107Shselasky/* Read cable EEPROM module information by first inspecting the first 2435292107Shselasky * two bytes to get the length and then read the rest of the information. 2436292107Shselasky * The information is printed to dmesg. */ 2437292107Shselaskystatic int mlx4_en_read_eeprom(SYSCTL_HANDLER_ARGS) 2438292107Shselasky{ 2439292107Shselasky 2440292107Shselasky u8* data; 2441292107Shselasky int error; 2442292107Shselasky int result = 0; 2443292107Shselasky struct mlx4_en_priv *priv; 2444292107Shselasky struct net_device *dev; 2445292107Shselasky struct ethtool_modinfo modinfo; 2446292107Shselasky struct ethtool_eeprom ee; 2447292107Shselasky 2448292107Shselasky error = sysctl_handle_int(oidp, &result, 0, req); 2449292107Shselasky if (error || !req->newptr) 2450292107Shselasky return (error); 2451292107Shselasky 2452292107Shselasky if (result == 1) { 2453292107Shselasky priv = arg1; 2454292107Shselasky dev = priv->dev; 2455292107Shselasky data = kmalloc(PAGE_SIZE, GFP_KERNEL); 2456292107Shselasky 2457292107Shselasky error = mlx4_en_get_module_info(dev, &modinfo); 2458292107Shselasky if (error) { 2459292107Shselasky en_err(priv, 2460292107Shselasky "mlx4_en_get_module_info returned with error - FAILED (0x%x)\n", 2461292107Shselasky -error); 2462292107Shselasky goto out; 2463292107Shselasky } 2464292107Shselasky 2465292107Shselasky ee.len = modinfo.eeprom_len; 2466292107Shselasky ee.offset = 0; 2467292107Shselasky 2468292107Shselasky error = mlx4_en_get_module_eeprom(dev, &ee, data); 2469292107Shselasky if (error) { 2470292107Shselasky en_err(priv, 2471292107Shselasky "mlx4_en_get_module_eeprom returned with error - FAILED (0x%x)\n", 2472292107Shselasky -error); 2473292107Shselasky /* Continue printing partial information in case of an error */ 2474292107Shselasky } 2475292107Shselasky 2476292107Shselasky /* EEPROM information will be printed in dmesg */ 2477292107Shselasky mlx4_en_print_eeprom(data, ee.len); 2478292107Shselaskyout: 2479292107Shselasky kfree(data); 2480292107Shselasky } 2481292107Shselasky /* Return zero to prevent sysctl failure. */ 2482292107Shselasky return (0); 2483292107Shselasky} 2484292107Shselasky 2485219859Sjeffstatic int mlx4_en_set_tx_ppp(SYSCTL_HANDLER_ARGS) 2486219859Sjeff{ 2487272407Shselasky struct mlx4_en_priv *priv; 2488272407Shselasky int ppp; 2489272407Shselasky int error; 2490219859Sjeff 2491272407Shselasky priv = arg1; 2492272407Shselasky ppp = priv->prof->tx_ppp; 2493272407Shselasky error = sysctl_handle_int(oidp, &ppp, 0, req); 2494272407Shselasky if (error || !req->newptr) 2495272407Shselasky return (error); 2496272407Shselasky if (ppp > 0xff || ppp < 0) 2497272407Shselasky return (-EINVAL); 2498272407Shselasky priv->prof->tx_ppp = ppp; 2499272407Shselasky error = -mlx4_SET_PORT_general(priv->mdev->dev, priv->port, 2500272407Shselasky priv->rx_mb_size + ETHER_CRC_LEN, 2501272407Shselasky priv->prof->tx_pause, 2502272407Shselasky priv->prof->tx_ppp, 2503272407Shselasky priv->prof->rx_pause, 2504272407Shselasky priv->prof->rx_ppp); 2505219859Sjeff 2506272407Shselasky return (error); 2507219859Sjeff} 2508219859Sjeff 2509219859Sjeffstatic int mlx4_en_set_rx_ppp(SYSCTL_HANDLER_ARGS) 2510219859Sjeff{ 2511272407Shselasky struct mlx4_en_priv *priv; 2512272407Shselasky struct mlx4_en_dev *mdev; 2513272407Shselasky int ppp; 2514272407Shselasky int error; 2515272407Shselasky int port_up; 2516219859Sjeff 2517272407Shselasky port_up = 0; 2518272407Shselasky priv = arg1; 2519272407Shselasky mdev = priv->mdev; 2520272407Shselasky ppp = priv->prof->rx_ppp; 2521272407Shselasky error = sysctl_handle_int(oidp, &ppp, 0, req); 2522272407Shselasky if (error || !req->newptr) 2523272407Shselasky return (error); 2524272407Shselasky if (ppp > 0xff || ppp < 0) 2525272407Shselasky return (-EINVAL); 2526272407Shselasky /* See if we have to change the number of tx queues. */ 2527272407Shselasky if (!ppp != !priv->prof->rx_ppp) { 2528272407Shselasky mutex_lock(&mdev->state_lock); 2529272407Shselasky if (priv->port_up) { 2530272407Shselasky port_up = 1; 2531272407Shselasky mlx4_en_stop_port(priv->dev); 2532272407Shselasky } 2533272407Shselasky mlx4_en_free_resources(priv); 2534272407Shselasky priv->prof->rx_ppp = ppp; 2535272407Shselasky error = -mlx4_en_alloc_resources(priv); 2536272407Shselasky if (error) 2537272407Shselasky en_err(priv, "Failed reallocating port resources\n"); 2538272407Shselasky if (error == 0 && port_up) { 2539272407Shselasky error = -mlx4_en_start_port(priv->dev); 2540272407Shselasky if (error) 2541272407Shselasky en_err(priv, "Failed starting port\n"); 2542272407Shselasky } 2543272407Shselasky mutex_unlock(&mdev->state_lock); 2544272407Shselasky return (error); 2545219859Sjeff 2546272407Shselasky } 2547272407Shselasky priv->prof->rx_ppp = ppp; 2548272407Shselasky error = -mlx4_SET_PORT_general(priv->mdev->dev, priv->port, 2549272407Shselasky priv->rx_mb_size + ETHER_CRC_LEN, 2550272407Shselasky priv->prof->tx_pause, 2551272407Shselasky priv->prof->tx_ppp, 2552272407Shselasky priv->prof->rx_pause, 2553272407Shselasky priv->prof->rx_ppp); 2554219859Sjeff 2555272407Shselasky return (error); 2556219859Sjeff} 2557219859Sjeff 2558219820Sjeffstatic void mlx4_en_sysctl_conf(struct mlx4_en_priv *priv) 2559219820Sjeff{ 2560272407Shselasky struct net_device *dev; 2561272407Shselasky struct sysctl_ctx_list *ctx; 2562272407Shselasky struct sysctl_oid *node; 2563272407Shselasky struct sysctl_oid_list *node_list; 2564272407Shselasky struct sysctl_oid *coal; 2565272407Shselasky struct sysctl_oid_list *coal_list; 2566273246Shselasky const char *pnameunit; 2567219820Sjeff 2568272407Shselasky dev = priv->dev; 2569272407Shselasky ctx = &priv->conf_ctx; 2570273246Shselasky pnameunit = device_get_nameunit(priv->mdev->pdev->dev.bsddev); 2571219820Sjeff 2572272407Shselasky sysctl_ctx_init(ctx); 2573318540Shselasky priv->conf_sysctl = SYSCTL_ADD_NODE(ctx, SYSCTL_STATIC_CHILDREN(_hw), 2574272407Shselasky OID_AUTO, dev->if_xname, CTLFLAG_RD, 0, "mlx4 10gig ethernet"); 2575318540Shselasky node = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(priv->conf_sysctl), OID_AUTO, 2576272407Shselasky "conf", CTLFLAG_RD, NULL, "Configuration"); 2577272407Shselasky node_list = SYSCTL_CHILDREN(node); 2578219820Sjeff 2579272407Shselasky SYSCTL_ADD_UINT(ctx, node_list, OID_AUTO, "msg_enable", 2580272407Shselasky CTLFLAG_RW, &priv->msg_enable, 0, 2581272407Shselasky "Driver message enable bitfield"); 2582272407Shselasky SYSCTL_ADD_UINT(ctx, node_list, OID_AUTO, "rx_rings", 2583273246Shselasky CTLFLAG_RD, &priv->rx_ring_num, 0, 2584272407Shselasky "Number of receive rings"); 2585272407Shselasky SYSCTL_ADD_UINT(ctx, node_list, OID_AUTO, "tx_rings", 2586273246Shselasky CTLFLAG_RD, &priv->tx_ring_num, 0, 2587272407Shselasky "Number of transmit rings"); 2588272407Shselasky SYSCTL_ADD_PROC(ctx, node_list, OID_AUTO, "rx_size", 2589272407Shselasky CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, priv, 0, 2590272407Shselasky mlx4_en_set_rx_ring_size, "I", "Receive ring size"); 2591272407Shselasky SYSCTL_ADD_PROC(ctx, node_list, OID_AUTO, "tx_size", 2592272407Shselasky CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, priv, 0, 2593272407Shselasky mlx4_en_set_tx_ring_size, "I", "Transmit ring size"); 2594272407Shselasky SYSCTL_ADD_PROC(ctx, node_list, OID_AUTO, "tx_ppp", 2595272407Shselasky CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, priv, 0, 2596272407Shselasky mlx4_en_set_tx_ppp, "I", "TX Per-priority pause"); 2597272407Shselasky SYSCTL_ADD_PROC(ctx, node_list, OID_AUTO, "rx_ppp", 2598272407Shselasky CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, priv, 0, 2599272407Shselasky mlx4_en_set_rx_ppp, "I", "RX Per-priority pause"); 2600273246Shselasky SYSCTL_ADD_UINT(ctx, node_list, OID_AUTO, "port_num", 2601273246Shselasky CTLFLAG_RD, &priv->port, 0, 2602273246Shselasky "Port Number"); 2603273246Shselasky SYSCTL_ADD_STRING(ctx, node_list, OID_AUTO, "device_name", 2604273246Shselasky CTLFLAG_RD, __DECONST(void *, pnameunit), 0, 2605273246Shselasky "PCI device name"); 2606219820Sjeff 2607272407Shselasky /* Add coalescer configuration. */ 2608272407Shselasky coal = SYSCTL_ADD_NODE(ctx, node_list, OID_AUTO, 2609272407Shselasky "coalesce", CTLFLAG_RD, NULL, "Interrupt coalesce configuration"); 2610292107Shselasky coal_list = SYSCTL_CHILDREN(coal); 2611272407Shselasky SYSCTL_ADD_UINT(ctx, coal_list, OID_AUTO, "pkt_rate_low", 2612272407Shselasky CTLFLAG_RW, &priv->pkt_rate_low, 0, 2613272407Shselasky "Packets per-second for minimum delay"); 2614272407Shselasky SYSCTL_ADD_UINT(ctx, coal_list, OID_AUTO, "rx_usecs_low", 2615272407Shselasky CTLFLAG_RW, &priv->rx_usecs_low, 0, 2616272407Shselasky "Minimum RX delay in micro-seconds"); 2617272407Shselasky SYSCTL_ADD_UINT(ctx, coal_list, OID_AUTO, "pkt_rate_high", 2618272407Shselasky CTLFLAG_RW, &priv->pkt_rate_high, 0, 2619272407Shselasky "Packets per-second for maximum delay"); 2620272407Shselasky SYSCTL_ADD_UINT(ctx, coal_list, OID_AUTO, "rx_usecs_high", 2621272407Shselasky CTLFLAG_RW, &priv->rx_usecs_high, 0, 2622272407Shselasky "Maximum RX delay in micro-seconds"); 2623272407Shselasky SYSCTL_ADD_UINT(ctx, coal_list, OID_AUTO, "sample_interval", 2624272407Shselasky CTLFLAG_RW, &priv->sample_interval, 0, 2625272407Shselasky "adaptive frequency in units of HZ ticks"); 2626272407Shselasky SYSCTL_ADD_UINT(ctx, coal_list, OID_AUTO, "adaptive_rx_coal", 2627272407Shselasky CTLFLAG_RW, &priv->adaptive_rx_coal, 0, 2628272407Shselasky "Enable adaptive rx coalescing"); 2629292107Shselasky /* EEPROM support */ 2630292107Shselasky SYSCTL_ADD_PROC(ctx, node_list, OID_AUTO, "eeprom_info", 2631292107Shselasky CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, priv, 0, 2632292107Shselasky mlx4_en_read_eeprom, "I", "EEPROM information"); 2633219820Sjeff} 2634219820Sjeff 2635219820Sjeffstatic void mlx4_en_sysctl_stat(struct mlx4_en_priv *priv) 2636219820Sjeff{ 2637219820Sjeff struct sysctl_ctx_list *ctx; 2638219820Sjeff struct sysctl_oid_list *node_list; 2639219820Sjeff struct sysctl_oid *ring_node; 2640219820Sjeff struct sysctl_oid_list *ring_list; 2641219820Sjeff struct mlx4_en_tx_ring *tx_ring; 2642219820Sjeff struct mlx4_en_rx_ring *rx_ring; 2643219820Sjeff char namebuf[128]; 2644219820Sjeff int i; 2645219820Sjeff 2646219820Sjeff ctx = &priv->stat_ctx; 2647219820Sjeff sysctl_ctx_init(ctx); 2648318540Shselasky priv->stat_sysctl = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(priv->conf_sysctl), OID_AUTO, 2649219820Sjeff "stat", CTLFLAG_RD, NULL, "Statistics"); 2650318540Shselasky node_list = SYSCTL_CHILDREN(priv->stat_sysctl); 2651219820Sjeff 2652219820Sjeff#ifdef MLX4_EN_PERF_STAT 2653219820Sjeff SYSCTL_ADD_UINT(ctx, node_list, OID_AUTO, "tx_poll", CTLFLAG_RD, 2654219820Sjeff &priv->pstats.tx_poll, "TX Poll calls"); 2655219820Sjeff SYSCTL_ADD_QUAD(ctx, node_list, OID_AUTO, "tx_pktsz_avg", CTLFLAG_RD, 2656219820Sjeff &priv->pstats.tx_pktsz_avg, "TX average packet size"); 2657219820Sjeff SYSCTL_ADD_UINT(ctx, node_list, OID_AUTO, "inflight_avg", CTLFLAG_RD, 2658219820Sjeff &priv->pstats.inflight_avg, "TX average packets in-flight"); 2659219820Sjeff SYSCTL_ADD_UINT(ctx, node_list, OID_AUTO, "tx_coal_avg", CTLFLAG_RD, 2660219820Sjeff &priv->pstats.tx_coal_avg, "TX average coalesced completions"); 2661219820Sjeff SYSCTL_ADD_UINT(ctx, node_list, OID_AUTO, "rx_coal_avg", CTLFLAG_RD, 2662219820Sjeff &priv->pstats.rx_coal_avg, "RX average coalesced completions"); 2663219820Sjeff#endif 2664219820Sjeff 2665219820Sjeff SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tso_packets", CTLFLAG_RD, 2666219820Sjeff &priv->port_stats.tso_packets, "TSO packets sent"); 2667219820Sjeff SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "queue_stopped", CTLFLAG_RD, 2668219820Sjeff &priv->port_stats.queue_stopped, "Queue full"); 2669219820Sjeff SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "wake_queue", CTLFLAG_RD, 2670219820Sjeff &priv->port_stats.wake_queue, "Queue resumed after full"); 2671219820Sjeff SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_timeout", CTLFLAG_RD, 2672219820Sjeff &priv->port_stats.tx_timeout, "Transmit timeouts"); 2673292107Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_oversized_packets", CTLFLAG_RD, 2674292107Shselasky &priv->port_stats.oversized_packets, "TX oversized packets, m_defrag failed"); 2675219820Sjeff SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_alloc_failed", CTLFLAG_RD, 2676219820Sjeff &priv->port_stats.rx_alloc_failed, "RX failed to allocate mbuf"); 2677219820Sjeff SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_chksum_good", CTLFLAG_RD, 2678219820Sjeff &priv->port_stats.rx_chksum_good, "RX checksum offload success"); 2679219820Sjeff SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_chksum_none", CTLFLAG_RD, 2680219820Sjeff &priv->port_stats.rx_chksum_none, "RX without checksum offload"); 2681219820Sjeff SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_chksum_offload", 2682219820Sjeff CTLFLAG_RD, &priv->port_stats.tx_chksum_offload, 2683219820Sjeff "TX checksum offloads"); 2684322531Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "defrag_attempts", CTLFLAG_RD, 2685322531Shselasky &priv->port_stats.defrag_attempts, "Oversized chains defragged"); 2686219820Sjeff 2687219820Sjeff /* Could strdup the names and add in a loop. This is simpler. */ 2688272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_bytes", CTLFLAG_RD, 2689272407Shselasky &priv->pkstats.rx_bytes, "RX Bytes"); 2690272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_packets", CTLFLAG_RD, 2691272407Shselasky &priv->pkstats.rx_packets, "RX packets"); 2692272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_multicast_packets", CTLFLAG_RD, 2693272407Shselasky &priv->pkstats.rx_multicast_packets, "RX Multicast Packets"); 2694272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_broadcast_packets", CTLFLAG_RD, 2695272407Shselasky &priv->pkstats.rx_broadcast_packets, "RX Broadcast Packets"); 2696272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_errors", CTLFLAG_RD, 2697272407Shselasky &priv->pkstats.rx_errors, "RX Errors"); 2698272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_dropped", CTLFLAG_RD, 2699272407Shselasky &priv->pkstats.rx_dropped, "RX Dropped"); 2700272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_length_errors", CTLFLAG_RD, 2701272407Shselasky &priv->pkstats.rx_length_errors, "RX Length Errors"); 2702272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_over_errors", CTLFLAG_RD, 2703272407Shselasky &priv->pkstats.rx_over_errors, "RX Over Errors"); 2704272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_crc_errors", CTLFLAG_RD, 2705272407Shselasky &priv->pkstats.rx_crc_errors, "RX CRC Errors"); 2706272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_jabbers", CTLFLAG_RD, 2707272407Shselasky &priv->pkstats.rx_jabbers, "RX Jabbers"); 2708219820Sjeff 2709272407Shselasky 2710272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_in_range_length_error", CTLFLAG_RD, 2711272407Shselasky &priv->pkstats.rx_in_range_length_error, "RX IN_Range Length Error"); 2712272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_out_range_length_error", 2713272407Shselasky CTLFLAG_RD, &priv->pkstats.rx_out_range_length_error, 2714272407Shselasky "RX Out Range Length Error"); 2715272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_lt_64_bytes_packets", CTLFLAG_RD, 2716272407Shselasky &priv->pkstats.rx_lt_64_bytes_packets, "RX Lt 64 Bytes Packets"); 2717272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_127_bytes_packets", CTLFLAG_RD, 2718272407Shselasky &priv->pkstats.rx_127_bytes_packets, "RX 127 bytes Packets"); 2719272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_255_bytes_packets", CTLFLAG_RD, 2720272407Shselasky &priv->pkstats.rx_255_bytes_packets, "RX 255 bytes Packets"); 2721272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_511_bytes_packets", CTLFLAG_RD, 2722272407Shselasky &priv->pkstats.rx_511_bytes_packets, "RX 511 bytes Packets"); 2723272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_1023_bytes_packets", CTLFLAG_RD, 2724272407Shselasky &priv->pkstats.rx_1023_bytes_packets, "RX 1023 bytes Packets"); 2725272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_1518_bytes_packets", CTLFLAG_RD, 2726272407Shselasky &priv->pkstats.rx_1518_bytes_packets, "RX 1518 bytes Packets"); 2727272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_1522_bytes_packets", CTLFLAG_RD, 2728272407Shselasky &priv->pkstats.rx_1522_bytes_packets, "RX 1522 bytes Packets"); 2729272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_1548_bytes_packets", CTLFLAG_RD, 2730272407Shselasky &priv->pkstats.rx_1548_bytes_packets, "RX 1548 bytes Packets"); 2731272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "rx_gt_1548_bytes_packets", CTLFLAG_RD, 2732272407Shselasky &priv->pkstats.rx_gt_1548_bytes_packets, 2733272407Shselasky "RX Greater Then 1548 bytes Packets"); 2734272407Shselasky 2735272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_packets", CTLFLAG_RD, 2736272407Shselasky &priv->pkstats.tx_packets, "TX packets"); 2737272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_bytes", CTLFLAG_RD, 2738292107Shselasky &priv->pkstats.tx_bytes, "TX Bytes"); 2739272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_multicast_packets", CTLFLAG_RD, 2740272407Shselasky &priv->pkstats.tx_multicast_packets, "TX Multicast Packets"); 2741272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_broadcast_packets", CTLFLAG_RD, 2742272407Shselasky &priv->pkstats.tx_broadcast_packets, "TX Broadcast Packets"); 2743272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_errors", CTLFLAG_RD, 2744272407Shselasky &priv->pkstats.tx_errors, "TX Errors"); 2745272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_dropped", CTLFLAG_RD, 2746272407Shselasky &priv->pkstats.tx_dropped, "TX Dropped"); 2747272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_lt_64_bytes_packets", CTLFLAG_RD, 2748272407Shselasky &priv->pkstats.tx_lt_64_bytes_packets, "TX Less Then 64 Bytes Packets"); 2749272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_127_bytes_packets", CTLFLAG_RD, 2750272407Shselasky &priv->pkstats.tx_127_bytes_packets, "TX 127 Bytes Packets"); 2751272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_255_bytes_packets", CTLFLAG_RD, 2752272407Shselasky &priv->pkstats.tx_255_bytes_packets, "TX 255 Bytes Packets"); 2753272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_511_bytes_packets", CTLFLAG_RD, 2754272407Shselasky &priv->pkstats.tx_511_bytes_packets, "TX 511 Bytes Packets"); 2755272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_1023_bytes_packets", CTLFLAG_RD, 2756272407Shselasky &priv->pkstats.tx_1023_bytes_packets, "TX 1023 Bytes Packets"); 2757272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_1518_bytes_packets", CTLFLAG_RD, 2758272407Shselasky &priv->pkstats.tx_1518_bytes_packets, "TX 1518 Bytes Packets"); 2759272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_1522_bytes_packets", CTLFLAG_RD, 2760272407Shselasky &priv->pkstats.tx_1522_bytes_packets, "TX 1522 Bytes Packets"); 2761272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_1548_bytes_packets", CTLFLAG_RD, 2762272407Shselasky &priv->pkstats.tx_1548_bytes_packets, "TX 1548 Bytes Packets"); 2763272407Shselasky SYSCTL_ADD_ULONG(ctx, node_list, OID_AUTO, "tx_gt_1548_bytes_packets", CTLFLAG_RD, 2764272407Shselasky &priv->pkstats.tx_gt_1548_bytes_packets, 2765272407Shselasky "TX Greater Then 1548 Bytes Packets"); 2766272407Shselasky 2767272407Shselasky 2768272407Shselasky 2769219820Sjeff for (i = 0; i < priv->tx_ring_num; i++) { 2770272407Shselasky tx_ring = priv->tx_ring[i]; 2771219820Sjeff snprintf(namebuf, sizeof(namebuf), "tx_ring%d", i); 2772219820Sjeff ring_node = SYSCTL_ADD_NODE(ctx, node_list, OID_AUTO, namebuf, 2773219820Sjeff CTLFLAG_RD, NULL, "TX Ring"); 2774219820Sjeff ring_list = SYSCTL_CHILDREN(ring_node); 2775219820Sjeff SYSCTL_ADD_ULONG(ctx, ring_list, OID_AUTO, "packets", 2776219820Sjeff CTLFLAG_RD, &tx_ring->packets, "TX packets"); 2777219820Sjeff SYSCTL_ADD_ULONG(ctx, ring_list, OID_AUTO, "bytes", 2778219820Sjeff CTLFLAG_RD, &tx_ring->bytes, "TX bytes"); 2779322531Shselasky SYSCTL_ADD_ULONG(ctx, ring_list, OID_AUTO, "tso_packets", 2780322531Shselasky CTLFLAG_RD, &tx_ring->tso_packets, "TSO packets"); 2781322531Shselasky SYSCTL_ADD_ULONG(ctx, ring_list, OID_AUTO, "defrag_attempts", 2782322531Shselasky CTLFLAG_RD, &tx_ring->defrag_attempts, "Oversized chains defragged"); 2783292107Shselasky } 2784219820Sjeff 2785219820Sjeff for (i = 0; i < priv->rx_ring_num; i++) { 2786272407Shselasky rx_ring = priv->rx_ring[i]; 2787219820Sjeff snprintf(namebuf, sizeof(namebuf), "rx_ring%d", i); 2788219820Sjeff ring_node = SYSCTL_ADD_NODE(ctx, node_list, OID_AUTO, namebuf, 2789219820Sjeff CTLFLAG_RD, NULL, "RX Ring"); 2790219820Sjeff ring_list = SYSCTL_CHILDREN(ring_node); 2791219820Sjeff SYSCTL_ADD_ULONG(ctx, ring_list, OID_AUTO, "packets", 2792219820Sjeff CTLFLAG_RD, &rx_ring->packets, "RX packets"); 2793219820Sjeff SYSCTL_ADD_ULONG(ctx, ring_list, OID_AUTO, "bytes", 2794219820Sjeff CTLFLAG_RD, &rx_ring->bytes, "RX bytes"); 2795219820Sjeff SYSCTL_ADD_ULONG(ctx, ring_list, OID_AUTO, "error", 2796219820Sjeff CTLFLAG_RD, &rx_ring->errors, "RX soft errors"); 2797219820Sjeff } 2798219820Sjeff} 2799