14ab0c6a8SSathya Perla /* Broadcom NetXtreme-C/E network driver. 24ab0c6a8SSathya Perla * 34ab0c6a8SSathya Perla * Copyright (c) 2016-2017 Broadcom Limited 44ab0c6a8SSathya Perla * 54ab0c6a8SSathya Perla * This program is free software; you can redistribute it and/or modify 64ab0c6a8SSathya Perla * it under the terms of the GNU General Public License as published by 74ab0c6a8SSathya Perla * the Free Software Foundation. 84ab0c6a8SSathya Perla */ 94ab0c6a8SSathya Perla #include <linux/pci.h> 104ab0c6a8SSathya Perla #include <linux/netdevice.h> 114ab0c6a8SSathya Perla #include <linux/etherdevice.h> 124ab0c6a8SSathya Perla #include <linux/rtnetlink.h> 134ab0c6a8SSathya Perla #include <linux/jhash.h> 142ae7408fSSathya Perla #include <net/pkt_cls.h> 154ab0c6a8SSathya Perla 164ab0c6a8SSathya Perla #include "bnxt_hsi.h" 174ab0c6a8SSathya Perla #include "bnxt.h" 184ab0c6a8SSathya Perla #include "bnxt_vfr.h" 193c467bf3SSteve Lin #include "bnxt_devlink.h" 202ae7408fSSathya Perla #include "bnxt_tc.h" 214ab0c6a8SSathya Perla 22d3e3beceSSathya Perla #ifdef CONFIG_BNXT_SRIOV 23d3e3beceSSathya Perla 244ab0c6a8SSathya Perla #define CFA_HANDLE_INVALID 0xffff 25ee5c7fb3SSathya Perla #define VF_IDX_INVALID 0xffff 26ee5c7fb3SSathya Perla 27ee5c7fb3SSathya Perla static int hwrm_cfa_vfr_alloc(struct bnxt *bp, u16 vf_idx, 28ee5c7fb3SSathya Perla u16 *tx_cfa_action, u16 *rx_cfa_code) 29ee5c7fb3SSathya Perla { 30ee5c7fb3SSathya Perla struct hwrm_cfa_vfr_alloc_output *resp = bp->hwrm_cmd_resp_addr; 31ee5c7fb3SSathya Perla struct hwrm_cfa_vfr_alloc_input req = { 0 }; 32ee5c7fb3SSathya Perla int rc; 33ee5c7fb3SSathya Perla 34ee5c7fb3SSathya Perla bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_CFA_VFR_ALLOC, -1, -1); 35ee5c7fb3SSathya Perla req.vf_id = cpu_to_le16(vf_idx); 36ee5c7fb3SSathya Perla sprintf(req.vfr_name, "vfr%d", vf_idx); 37ee5c7fb3SSathya Perla 38ee5c7fb3SSathya Perla mutex_lock(&bp->hwrm_cmd_lock); 39ee5c7fb3SSathya Perla rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); 40ee5c7fb3SSathya Perla if (!rc) { 41ee5c7fb3SSathya Perla *tx_cfa_action = le16_to_cpu(resp->tx_cfa_action); 42ee5c7fb3SSathya Perla *rx_cfa_code = le16_to_cpu(resp->rx_cfa_code); 43ee5c7fb3SSathya Perla netdev_dbg(bp->dev, "tx_cfa_action=0x%x, rx_cfa_code=0x%x", 44ee5c7fb3SSathya Perla *tx_cfa_action, *rx_cfa_code); 45ee5c7fb3SSathya Perla } else { 469a005c38SJonathan Lemon netdev_info(bp->dev, "%s error rc=%d\n", __func__, rc); 47ee5c7fb3SSathya Perla } 48ee5c7fb3SSathya Perla 49ee5c7fb3SSathya Perla mutex_unlock(&bp->hwrm_cmd_lock); 50ee5c7fb3SSathya Perla return rc; 51ee5c7fb3SSathya Perla } 52ee5c7fb3SSathya Perla 53ee5c7fb3SSathya Perla static int hwrm_cfa_vfr_free(struct bnxt *bp, u16 vf_idx) 54ee5c7fb3SSathya Perla { 55ee5c7fb3SSathya Perla struct hwrm_cfa_vfr_free_input req = { 0 }; 56ee5c7fb3SSathya Perla int rc; 57ee5c7fb3SSathya Perla 58ee5c7fb3SSathya Perla bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_CFA_VFR_FREE, -1, -1); 59ee5c7fb3SSathya Perla sprintf(req.vfr_name, "vfr%d", vf_idx); 60ee5c7fb3SSathya Perla 61ee5c7fb3SSathya Perla rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); 62ee5c7fb3SSathya Perla if (rc) 639a005c38SJonathan Lemon netdev_info(bp->dev, "%s error rc=%d\n", __func__, rc); 64ee5c7fb3SSathya Perla return rc; 65ee5c7fb3SSathya Perla } 66ee5c7fb3SSathya Perla 679d96465bSSriharsha Basavapatna static int bnxt_hwrm_vfr_qcfg(struct bnxt *bp, struct bnxt_vf_rep *vf_rep, 689d96465bSSriharsha Basavapatna u16 *max_mtu) 699d96465bSSriharsha Basavapatna { 709d96465bSSriharsha Basavapatna struct hwrm_func_qcfg_output *resp = bp->hwrm_cmd_resp_addr; 719d96465bSSriharsha Basavapatna struct hwrm_func_qcfg_input req = {0}; 729d96465bSSriharsha Basavapatna u16 mtu; 739d96465bSSriharsha Basavapatna int rc; 749d96465bSSriharsha Basavapatna 759d96465bSSriharsha Basavapatna bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_QCFG, -1, -1); 769d96465bSSriharsha Basavapatna req.fid = cpu_to_le16(bp->pf.vf[vf_rep->vf_idx].fw_fid); 779d96465bSSriharsha Basavapatna 789d96465bSSriharsha Basavapatna mutex_lock(&bp->hwrm_cmd_lock); 799d96465bSSriharsha Basavapatna 809d96465bSSriharsha Basavapatna rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); 819d96465bSSriharsha Basavapatna if (!rc) { 829d96465bSSriharsha Basavapatna mtu = le16_to_cpu(resp->max_mtu_configured); 839d96465bSSriharsha Basavapatna if (!mtu) 849d96465bSSriharsha Basavapatna *max_mtu = BNXT_MAX_MTU; 859d96465bSSriharsha Basavapatna else 869d96465bSSriharsha Basavapatna *max_mtu = mtu; 879d96465bSSriharsha Basavapatna } 889d96465bSSriharsha Basavapatna mutex_unlock(&bp->hwrm_cmd_lock); 899d96465bSSriharsha Basavapatna return rc; 909d96465bSSriharsha Basavapatna } 919d96465bSSriharsha Basavapatna 92ee5c7fb3SSathya Perla static int bnxt_vf_rep_open(struct net_device *dev) 93ee5c7fb3SSathya Perla { 94ee5c7fb3SSathya Perla struct bnxt_vf_rep *vf_rep = netdev_priv(dev); 95ee5c7fb3SSathya Perla struct bnxt *bp = vf_rep->bp; 96ee5c7fb3SSathya Perla 97ee5c7fb3SSathya Perla /* Enable link and TX only if the parent PF is open. */ 98ee5c7fb3SSathya Perla if (netif_running(bp->dev)) { 99ee5c7fb3SSathya Perla netif_carrier_on(dev); 100ee5c7fb3SSathya Perla netif_tx_start_all_queues(dev); 101ee5c7fb3SSathya Perla } 102ee5c7fb3SSathya Perla return 0; 103ee5c7fb3SSathya Perla } 104ee5c7fb3SSathya Perla 105ee5c7fb3SSathya Perla static int bnxt_vf_rep_close(struct net_device *dev) 106ee5c7fb3SSathya Perla { 107ee5c7fb3SSathya Perla netif_carrier_off(dev); 108ee5c7fb3SSathya Perla netif_tx_disable(dev); 109ee5c7fb3SSathya Perla 110ee5c7fb3SSathya Perla return 0; 111ee5c7fb3SSathya Perla } 112ee5c7fb3SSathya Perla 113ee5c7fb3SSathya Perla static netdev_tx_t bnxt_vf_rep_xmit(struct sk_buff *skb, 114ee5c7fb3SSathya Perla struct net_device *dev) 115ee5c7fb3SSathya Perla { 116ee5c7fb3SSathya Perla struct bnxt_vf_rep *vf_rep = netdev_priv(dev); 117ee5c7fb3SSathya Perla int rc, len = skb->len; 118ee5c7fb3SSathya Perla 119ee5c7fb3SSathya Perla skb_dst_drop(skb); 120ee5c7fb3SSathya Perla dst_hold((struct dst_entry *)vf_rep->dst); 121ee5c7fb3SSathya Perla skb_dst_set(skb, (struct dst_entry *)vf_rep->dst); 122ee5c7fb3SSathya Perla skb->dev = vf_rep->dst->u.port_info.lower_dev; 123ee5c7fb3SSathya Perla 124ee5c7fb3SSathya Perla rc = dev_queue_xmit(skb); 125ee5c7fb3SSathya Perla if (!rc) { 126ee5c7fb3SSathya Perla vf_rep->tx_stats.packets++; 127ee5c7fb3SSathya Perla vf_rep->tx_stats.bytes += len; 128ee5c7fb3SSathya Perla } 129ee5c7fb3SSathya Perla return rc; 130ee5c7fb3SSathya Perla } 131ee5c7fb3SSathya Perla 132ee5c7fb3SSathya Perla static void 133ee5c7fb3SSathya Perla bnxt_vf_rep_get_stats64(struct net_device *dev, 134ee5c7fb3SSathya Perla struct rtnl_link_stats64 *stats) 135ee5c7fb3SSathya Perla { 136ee5c7fb3SSathya Perla struct bnxt_vf_rep *vf_rep = netdev_priv(dev); 137ee5c7fb3SSathya Perla 138ee5c7fb3SSathya Perla stats->rx_packets = vf_rep->rx_stats.packets; 139ee5c7fb3SSathya Perla stats->rx_bytes = vf_rep->rx_stats.bytes; 140ee5c7fb3SSathya Perla stats->tx_packets = vf_rep->tx_stats.packets; 141ee5c7fb3SSathya Perla stats->tx_bytes = vf_rep->tx_stats.bytes; 142ee5c7fb3SSathya Perla } 143ee5c7fb3SSathya Perla 1449e0fd15dSJiri Pirko static int bnxt_vf_rep_setup_tc_block_cb(enum tc_setup_type type, 1459e0fd15dSJiri Pirko void *type_data, 1469e0fd15dSJiri Pirko void *cb_priv) 1472ae7408fSSathya Perla { 1489e0fd15dSJiri Pirko struct bnxt_vf_rep *vf_rep = cb_priv; 1492ae7408fSSathya Perla struct bnxt *bp = vf_rep->bp; 1502ae7408fSSathya Perla int vf_fid = bp->pf.vf[vf_rep->vf_idx].fw_fid; 1512ae7408fSSathya Perla 152312324f1SJakub Kicinski if (!bnxt_tc_flower_enabled(vf_rep->bp) || 153312324f1SJakub Kicinski !tc_cls_can_offload_and_chain0(bp->dev, type_data)) 154cd66358eSSathya Perla return -EOPNOTSUPP; 155cd66358eSSathya Perla 1562ae7408fSSathya Perla switch (type) { 1572ae7408fSSathya Perla case TC_SETUP_CLSFLOWER: 1582ae7408fSSathya Perla return bnxt_tc_setup_flower(bp, vf_fid, type_data); 1592ae7408fSSathya Perla default: 1602ae7408fSSathya Perla return -EOPNOTSUPP; 1612ae7408fSSathya Perla } 1622ae7408fSSathya Perla } 1632ae7408fSSathya Perla 164955bcb6eSPablo Neira Ayuso static LIST_HEAD(bnxt_vf_block_cb_list); 165955bcb6eSPablo Neira Ayuso 1669e0fd15dSJiri Pirko static int bnxt_vf_rep_setup_tc(struct net_device *dev, enum tc_setup_type type, 1679e0fd15dSJiri Pirko void *type_data) 1689e0fd15dSJiri Pirko { 1694e95bc26SPablo Neira Ayuso struct bnxt_vf_rep *vf_rep = netdev_priv(dev); 1704e95bc26SPablo Neira Ayuso 1719e0fd15dSJiri Pirko switch (type) { 1729e0fd15dSJiri Pirko case TC_SETUP_BLOCK: 173955bcb6eSPablo Neira Ayuso return flow_block_cb_setup_simple(type_data, 174955bcb6eSPablo Neira Ayuso &bnxt_vf_block_cb_list, 1754e95bc26SPablo Neira Ayuso bnxt_vf_rep_setup_tc_block_cb, 1764e95bc26SPablo Neira Ayuso vf_rep, vf_rep, true); 1779e0fd15dSJiri Pirko default: 1789e0fd15dSJiri Pirko return -EOPNOTSUPP; 1799e0fd15dSJiri Pirko } 1809e0fd15dSJiri Pirko } 1819e0fd15dSJiri Pirko 182ee5c7fb3SSathya Perla struct net_device *bnxt_get_vf_rep(struct bnxt *bp, u16 cfa_code) 183ee5c7fb3SSathya Perla { 184ee5c7fb3SSathya Perla u16 vf_idx; 185ee5c7fb3SSathya Perla 186ee5c7fb3SSathya Perla if (cfa_code && bp->cfa_code_map && BNXT_PF(bp)) { 187ee5c7fb3SSathya Perla vf_idx = bp->cfa_code_map[cfa_code]; 188ee5c7fb3SSathya Perla if (vf_idx != VF_IDX_INVALID) 189ee5c7fb3SSathya Perla return bp->vf_reps[vf_idx]->dev; 190ee5c7fb3SSathya Perla } 191ee5c7fb3SSathya Perla return NULL; 192ee5c7fb3SSathya Perla } 193ee5c7fb3SSathya Perla 194ee5c7fb3SSathya Perla void bnxt_vf_rep_rx(struct bnxt *bp, struct sk_buff *skb) 195ee5c7fb3SSathya Perla { 196ee5c7fb3SSathya Perla struct bnxt_vf_rep *vf_rep = netdev_priv(skb->dev); 197ee5c7fb3SSathya Perla 198ee5c7fb3SSathya Perla vf_rep->rx_stats.bytes += skb->len; 199ee5c7fb3SSathya Perla vf_rep->rx_stats.packets++; 200ee5c7fb3SSathya Perla 201ee5c7fb3SSathya Perla netif_receive_skb(skb); 202ee5c7fb3SSathya Perla } 203ee5c7fb3SSathya Perla 204c124a62fSSathya Perla static int bnxt_vf_rep_get_phys_port_name(struct net_device *dev, char *buf, 205c124a62fSSathya Perla size_t len) 206c124a62fSSathya Perla { 207c124a62fSSathya Perla struct bnxt_vf_rep *vf_rep = netdev_priv(dev); 20853f70b8bSSathya Perla struct pci_dev *pf_pdev = vf_rep->bp->pdev; 209c124a62fSSathya Perla int rc; 210c124a62fSSathya Perla 21153f70b8bSSathya Perla rc = snprintf(buf, len, "pf%dvf%d", PCI_FUNC(pf_pdev->devfn), 21253f70b8bSSathya Perla vf_rep->vf_idx); 213c124a62fSSathya Perla if (rc >= len) 214c124a62fSSathya Perla return -EOPNOTSUPP; 215c124a62fSSathya Perla return 0; 216c124a62fSSathya Perla } 217c124a62fSSathya Perla 218ee5c7fb3SSathya Perla static void bnxt_vf_rep_get_drvinfo(struct net_device *dev, 219ee5c7fb3SSathya Perla struct ethtool_drvinfo *info) 220ee5c7fb3SSathya Perla { 221ee5c7fb3SSathya Perla strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver)); 222ee5c7fb3SSathya Perla } 223ee5c7fb3SSathya Perla 22452d5254aSFlorian Fainelli static int bnxt_vf_rep_get_port_parent_id(struct net_device *dev, 22552d5254aSFlorian Fainelli struct netdev_phys_item_id *ppid) 226c124a62fSSathya Perla { 227c124a62fSSathya Perla struct bnxt_vf_rep *vf_rep = netdev_priv(dev); 228c124a62fSSathya Perla 229c124a62fSSathya Perla /* as only PORT_PARENT_ID is supported currently use common code 230c124a62fSSathya Perla * between PF and VF-rep for now. 231c124a62fSSathya Perla */ 23252d5254aSFlorian Fainelli return bnxt_get_port_parent_id(vf_rep->bp->dev, ppid); 233c124a62fSSathya Perla } 234c124a62fSSathya Perla 235ee5c7fb3SSathya Perla static const struct ethtool_ops bnxt_vf_rep_ethtool_ops = { 236ee5c7fb3SSathya Perla .get_drvinfo = bnxt_vf_rep_get_drvinfo 237ee5c7fb3SSathya Perla }; 238ee5c7fb3SSathya Perla 239ee5c7fb3SSathya Perla static const struct net_device_ops bnxt_vf_rep_netdev_ops = { 240ee5c7fb3SSathya Perla .ndo_open = bnxt_vf_rep_open, 241ee5c7fb3SSathya Perla .ndo_stop = bnxt_vf_rep_close, 242ee5c7fb3SSathya Perla .ndo_start_xmit = bnxt_vf_rep_xmit, 243c124a62fSSathya Perla .ndo_get_stats64 = bnxt_vf_rep_get_stats64, 2442ae7408fSSathya Perla .ndo_setup_tc = bnxt_vf_rep_setup_tc, 24552d5254aSFlorian Fainelli .ndo_get_port_parent_id = bnxt_vf_rep_get_port_parent_id, 246c124a62fSSathya Perla .ndo_get_phys_port_name = bnxt_vf_rep_get_phys_port_name 247ee5c7fb3SSathya Perla }; 248ee5c7fb3SSathya Perla 249dd4ea1daSSathya Perla bool bnxt_dev_is_vf_rep(struct net_device *dev) 250dd4ea1daSSathya Perla { 251dd4ea1daSSathya Perla return dev->netdev_ops == &bnxt_vf_rep_netdev_ops; 252dd4ea1daSSathya Perla } 253dd4ea1daSSathya Perla 254ee5c7fb3SSathya Perla /* Called when the parent PF interface is closed: 255ee5c7fb3SSathya Perla * As the mode transition from SWITCHDEV to LEGACY 256ee5c7fb3SSathya Perla * happens under the rtnl_lock() this routine is safe 257ee5c7fb3SSathya Perla * under the rtnl_lock() 258ee5c7fb3SSathya Perla */ 259ee5c7fb3SSathya Perla void bnxt_vf_reps_close(struct bnxt *bp) 260ee5c7fb3SSathya Perla { 261ee5c7fb3SSathya Perla struct bnxt_vf_rep *vf_rep; 262ee5c7fb3SSathya Perla u16 num_vfs, i; 263ee5c7fb3SSathya Perla 264ee5c7fb3SSathya Perla if (bp->eswitch_mode != DEVLINK_ESWITCH_MODE_SWITCHDEV) 265ee5c7fb3SSathya Perla return; 266ee5c7fb3SSathya Perla 267ee5c7fb3SSathya Perla num_vfs = pci_num_vf(bp->pdev); 268ee5c7fb3SSathya Perla for (i = 0; i < num_vfs; i++) { 269ee5c7fb3SSathya Perla vf_rep = bp->vf_reps[i]; 270ee5c7fb3SSathya Perla if (netif_running(vf_rep->dev)) 271ee5c7fb3SSathya Perla bnxt_vf_rep_close(vf_rep->dev); 272ee5c7fb3SSathya Perla } 273ee5c7fb3SSathya Perla } 274ee5c7fb3SSathya Perla 275ee5c7fb3SSathya Perla /* Called when the parent PF interface is opened (re-opened): 276ee5c7fb3SSathya Perla * As the mode transition from SWITCHDEV to LEGACY 277ee5c7fb3SSathya Perla * happen under the rtnl_lock() this routine is safe 278ee5c7fb3SSathya Perla * under the rtnl_lock() 279ee5c7fb3SSathya Perla */ 280ee5c7fb3SSathya Perla void bnxt_vf_reps_open(struct bnxt *bp) 281ee5c7fb3SSathya Perla { 282ee5c7fb3SSathya Perla int i; 283ee5c7fb3SSathya Perla 284ee5c7fb3SSathya Perla if (bp->eswitch_mode != DEVLINK_ESWITCH_MODE_SWITCHDEV) 285ee5c7fb3SSathya Perla return; 286ee5c7fb3SSathya Perla 287*ac797cedSSriharsha Basavapatna for (i = 0; i < pci_num_vf(bp->pdev); i++) { 288*ac797cedSSriharsha Basavapatna /* Open the VF-Rep only if it is allocated in the FW */ 289*ac797cedSSriharsha Basavapatna if (bp->vf_reps[i]->tx_cfa_action != CFA_HANDLE_INVALID) 290ee5c7fb3SSathya Perla bnxt_vf_rep_open(bp->vf_reps[i]->dev); 291ee5c7fb3SSathya Perla } 292*ac797cedSSriharsha Basavapatna } 2934ab0c6a8SSathya Perla 29490f4fd02SMichael Chan static void __bnxt_free_one_vf_rep(struct bnxt *bp, struct bnxt_vf_rep *vf_rep) 29590f4fd02SMichael Chan { 29690f4fd02SMichael Chan if (!vf_rep) 29790f4fd02SMichael Chan return; 29890f4fd02SMichael Chan 29990f4fd02SMichael Chan if (vf_rep->dst) { 30090f4fd02SMichael Chan dst_release((struct dst_entry *)vf_rep->dst); 30190f4fd02SMichael Chan vf_rep->dst = NULL; 30290f4fd02SMichael Chan } 30390f4fd02SMichael Chan if (vf_rep->tx_cfa_action != CFA_HANDLE_INVALID) { 30490f4fd02SMichael Chan hwrm_cfa_vfr_free(bp, vf_rep->vf_idx); 30590f4fd02SMichael Chan vf_rep->tx_cfa_action = CFA_HANDLE_INVALID; 30690f4fd02SMichael Chan } 30790f4fd02SMichael Chan } 30890f4fd02SMichael Chan 3094ab0c6a8SSathya Perla static void __bnxt_vf_reps_destroy(struct bnxt *bp) 3104ab0c6a8SSathya Perla { 3114ab0c6a8SSathya Perla u16 num_vfs = pci_num_vf(bp->pdev); 3124ab0c6a8SSathya Perla struct bnxt_vf_rep *vf_rep; 3134ab0c6a8SSathya Perla int i; 3144ab0c6a8SSathya Perla 3154ab0c6a8SSathya Perla for (i = 0; i < num_vfs; i++) { 3164ab0c6a8SSathya Perla vf_rep = bp->vf_reps[i]; 3174ab0c6a8SSathya Perla if (vf_rep) { 31890f4fd02SMichael Chan __bnxt_free_one_vf_rep(bp, vf_rep); 3194ab0c6a8SSathya Perla if (vf_rep->dev) { 3204ab0c6a8SSathya Perla /* if register_netdev failed, then netdev_ops 3214ab0c6a8SSathya Perla * would have been set to NULL 3224ab0c6a8SSathya Perla */ 3234ab0c6a8SSathya Perla if (vf_rep->dev->netdev_ops) 3244ab0c6a8SSathya Perla unregister_netdev(vf_rep->dev); 3254ab0c6a8SSathya Perla free_netdev(vf_rep->dev); 3264ab0c6a8SSathya Perla } 3274ab0c6a8SSathya Perla } 3284ab0c6a8SSathya Perla } 3294ab0c6a8SSathya Perla 3304ab0c6a8SSathya Perla kfree(bp->vf_reps); 3314ab0c6a8SSathya Perla bp->vf_reps = NULL; 3324ab0c6a8SSathya Perla } 3334ab0c6a8SSathya Perla 3344ab0c6a8SSathya Perla void bnxt_vf_reps_destroy(struct bnxt *bp) 3354ab0c6a8SSathya Perla { 3364ab0c6a8SSathya Perla bool closed = false; 3374ab0c6a8SSathya Perla 3384ab0c6a8SSathya Perla if (bp->eswitch_mode != DEVLINK_ESWITCH_MODE_SWITCHDEV) 3394ab0c6a8SSathya Perla return; 3404ab0c6a8SSathya Perla 3414ab0c6a8SSathya Perla if (!bp->vf_reps) 3424ab0c6a8SSathya Perla return; 3434ab0c6a8SSathya Perla 3444ab0c6a8SSathya Perla /* Ensure that parent PF's and VF-reps' RX/TX has been quiesced 3454ab0c6a8SSathya Perla * before proceeding with VF-rep cleanup. 3464ab0c6a8SSathya Perla */ 3474ab0c6a8SSathya Perla rtnl_lock(); 3484ab0c6a8SSathya Perla if (netif_running(bp->dev)) { 3494ab0c6a8SSathya Perla bnxt_close_nic(bp, false, false); 3504ab0c6a8SSathya Perla closed = true; 3514ab0c6a8SSathya Perla } 352ee5c7fb3SSathya Perla /* un-publish cfa_code_map so that RX path can't see it anymore */ 353ee5c7fb3SSathya Perla kfree(bp->cfa_code_map); 354ee5c7fb3SSathya Perla bp->cfa_code_map = NULL; 3554ab0c6a8SSathya Perla bp->eswitch_mode = DEVLINK_ESWITCH_MODE_LEGACY; 3564ab0c6a8SSathya Perla 3574ab0c6a8SSathya Perla if (closed) 3584ab0c6a8SSathya Perla bnxt_open_nic(bp, false, false); 3594ab0c6a8SSathya Perla rtnl_unlock(); 3604ab0c6a8SSathya Perla 3614ab0c6a8SSathya Perla /* Need to call vf_reps_destroy() outside of rntl_lock 3624ab0c6a8SSathya Perla * as unregister_netdev takes rtnl_lock 3634ab0c6a8SSathya Perla */ 3644ab0c6a8SSathya Perla __bnxt_vf_reps_destroy(bp); 3654ab0c6a8SSathya Perla } 3664ab0c6a8SSathya Perla 367*ac797cedSSriharsha Basavapatna /* Free the VF-Reps in firmware, during firmware hot-reset processing. 368*ac797cedSSriharsha Basavapatna * Note that the VF-Rep netdevs are still active (not unregistered) during 369*ac797cedSSriharsha Basavapatna * this process. As the mode transition from SWITCHDEV to LEGACY happens 370*ac797cedSSriharsha Basavapatna * under the rtnl_lock() this routine is safe under the rtnl_lock(). 371*ac797cedSSriharsha Basavapatna */ 372*ac797cedSSriharsha Basavapatna void bnxt_vf_reps_free(struct bnxt *bp) 373*ac797cedSSriharsha Basavapatna { 374*ac797cedSSriharsha Basavapatna u16 num_vfs = pci_num_vf(bp->pdev); 375*ac797cedSSriharsha Basavapatna int i; 376*ac797cedSSriharsha Basavapatna 377*ac797cedSSriharsha Basavapatna if (bp->eswitch_mode != DEVLINK_ESWITCH_MODE_SWITCHDEV) 378*ac797cedSSriharsha Basavapatna return; 379*ac797cedSSriharsha Basavapatna 380*ac797cedSSriharsha Basavapatna for (i = 0; i < num_vfs; i++) 381*ac797cedSSriharsha Basavapatna __bnxt_free_one_vf_rep(bp, bp->vf_reps[i]); 382*ac797cedSSriharsha Basavapatna } 383*ac797cedSSriharsha Basavapatna 384ea2d37b2SSriharsha Basavapatna static int bnxt_alloc_vf_rep(struct bnxt *bp, struct bnxt_vf_rep *vf_rep, 385ea2d37b2SSriharsha Basavapatna u16 *cfa_code_map) 386ea2d37b2SSriharsha Basavapatna { 387ea2d37b2SSriharsha Basavapatna /* get cfa handles from FW */ 388ea2d37b2SSriharsha Basavapatna if (hwrm_cfa_vfr_alloc(bp, vf_rep->vf_idx, &vf_rep->tx_cfa_action, 389ea2d37b2SSriharsha Basavapatna &vf_rep->rx_cfa_code)) 390ea2d37b2SSriharsha Basavapatna return -ENOLINK; 391ea2d37b2SSriharsha Basavapatna 392ea2d37b2SSriharsha Basavapatna cfa_code_map[vf_rep->rx_cfa_code] = vf_rep->vf_idx; 393ea2d37b2SSriharsha Basavapatna vf_rep->dst = metadata_dst_alloc(0, METADATA_HW_PORT_MUX, GFP_KERNEL); 394ea2d37b2SSriharsha Basavapatna if (!vf_rep->dst) 395ea2d37b2SSriharsha Basavapatna return -ENOMEM; 396ea2d37b2SSriharsha Basavapatna 397ea2d37b2SSriharsha Basavapatna /* only cfa_action is needed to mux a packet while TXing */ 398ea2d37b2SSriharsha Basavapatna vf_rep->dst->u.port_info.port_id = vf_rep->tx_cfa_action; 399ea2d37b2SSriharsha Basavapatna vf_rep->dst->u.port_info.lower_dev = bp->dev; 400ea2d37b2SSriharsha Basavapatna 401ea2d37b2SSriharsha Basavapatna return 0; 402ea2d37b2SSriharsha Basavapatna } 403ea2d37b2SSriharsha Basavapatna 404*ac797cedSSriharsha Basavapatna /* Allocate the VF-Reps in firmware, during firmware hot-reset processing. 405*ac797cedSSriharsha Basavapatna * Note that the VF-Rep netdevs are still active (not unregistered) during 406*ac797cedSSriharsha Basavapatna * this process. As the mode transition from SWITCHDEV to LEGACY happens 407*ac797cedSSriharsha Basavapatna * under the rtnl_lock() this routine is safe under the rtnl_lock(). 408*ac797cedSSriharsha Basavapatna */ 409*ac797cedSSriharsha Basavapatna int bnxt_vf_reps_alloc(struct bnxt *bp) 410*ac797cedSSriharsha Basavapatna { 411*ac797cedSSriharsha Basavapatna u16 *cfa_code_map = bp->cfa_code_map, num_vfs = pci_num_vf(bp->pdev); 412*ac797cedSSriharsha Basavapatna struct bnxt_vf_rep *vf_rep; 413*ac797cedSSriharsha Basavapatna int rc, i; 414*ac797cedSSriharsha Basavapatna 415*ac797cedSSriharsha Basavapatna if (bp->eswitch_mode != DEVLINK_ESWITCH_MODE_SWITCHDEV) 416*ac797cedSSriharsha Basavapatna return 0; 417*ac797cedSSriharsha Basavapatna 418*ac797cedSSriharsha Basavapatna if (!cfa_code_map) 419*ac797cedSSriharsha Basavapatna return -EINVAL; 420*ac797cedSSriharsha Basavapatna 421*ac797cedSSriharsha Basavapatna for (i = 0; i < MAX_CFA_CODE; i++) 422*ac797cedSSriharsha Basavapatna cfa_code_map[i] = VF_IDX_INVALID; 423*ac797cedSSriharsha Basavapatna 424*ac797cedSSriharsha Basavapatna for (i = 0; i < num_vfs; i++) { 425*ac797cedSSriharsha Basavapatna vf_rep = bp->vf_reps[i]; 426*ac797cedSSriharsha Basavapatna vf_rep->vf_idx = i; 427*ac797cedSSriharsha Basavapatna 428*ac797cedSSriharsha Basavapatna rc = bnxt_alloc_vf_rep(bp, vf_rep, cfa_code_map); 429*ac797cedSSriharsha Basavapatna if (rc) 430*ac797cedSSriharsha Basavapatna goto err; 431*ac797cedSSriharsha Basavapatna } 432*ac797cedSSriharsha Basavapatna 433*ac797cedSSriharsha Basavapatna return 0; 434*ac797cedSSriharsha Basavapatna 435*ac797cedSSriharsha Basavapatna err: 436*ac797cedSSriharsha Basavapatna netdev_info(bp->dev, "%s error=%d\n", __func__, rc); 437*ac797cedSSriharsha Basavapatna bnxt_vf_reps_free(bp); 438*ac797cedSSriharsha Basavapatna return rc; 439*ac797cedSSriharsha Basavapatna } 440*ac797cedSSriharsha Basavapatna 4414ab0c6a8SSathya Perla /* Use the OUI of the PF's perm addr and report the same mac addr 4424ab0c6a8SSathya Perla * for the same VF-rep each time 4434ab0c6a8SSathya Perla */ 4444ab0c6a8SSathya Perla static void bnxt_vf_rep_eth_addr_gen(u8 *src_mac, u16 vf_idx, u8 *mac) 4454ab0c6a8SSathya Perla { 4464ab0c6a8SSathya Perla u32 addr; 4474ab0c6a8SSathya Perla 4484ab0c6a8SSathya Perla ether_addr_copy(mac, src_mac); 4494ab0c6a8SSathya Perla 4504ab0c6a8SSathya Perla addr = jhash(src_mac, ETH_ALEN, 0) + vf_idx; 4514ab0c6a8SSathya Perla mac[3] = (u8)(addr & 0xFF); 4524ab0c6a8SSathya Perla mac[4] = (u8)((addr >> 8) & 0xFF); 4534ab0c6a8SSathya Perla mac[5] = (u8)((addr >> 16) & 0xFF); 4544ab0c6a8SSathya Perla } 4554ab0c6a8SSathya Perla 4564ab0c6a8SSathya Perla static void bnxt_vf_rep_netdev_init(struct bnxt *bp, struct bnxt_vf_rep *vf_rep, 4574ab0c6a8SSathya Perla struct net_device *dev) 4584ab0c6a8SSathya Perla { 4594ab0c6a8SSathya Perla struct net_device *pf_dev = bp->dev; 4609d96465bSSriharsha Basavapatna u16 max_mtu; 4614ab0c6a8SSathya Perla 462ee5c7fb3SSathya Perla dev->netdev_ops = &bnxt_vf_rep_netdev_ops; 463ee5c7fb3SSathya Perla dev->ethtool_ops = &bnxt_vf_rep_ethtool_ops; 4644ab0c6a8SSathya Perla /* Just inherit all the featues of the parent PF as the VF-R 4654ab0c6a8SSathya Perla * uses the RX/TX rings of the parent PF 4664ab0c6a8SSathya Perla */ 4674ab0c6a8SSathya Perla dev->hw_features = pf_dev->hw_features; 4684ab0c6a8SSathya Perla dev->gso_partial_features = pf_dev->gso_partial_features; 4694ab0c6a8SSathya Perla dev->vlan_features = pf_dev->vlan_features; 4704ab0c6a8SSathya Perla dev->hw_enc_features = pf_dev->hw_enc_features; 4714ab0c6a8SSathya Perla dev->features |= pf_dev->features; 4724ab0c6a8SSathya Perla bnxt_vf_rep_eth_addr_gen(bp->pf.mac_addr, vf_rep->vf_idx, 4734ab0c6a8SSathya Perla dev->perm_addr); 4744ab0c6a8SSathya Perla ether_addr_copy(dev->dev_addr, dev->perm_addr); 4759d96465bSSriharsha Basavapatna /* Set VF-Rep's max-mtu to the corresponding VF's max-mtu */ 4769d96465bSSriharsha Basavapatna if (!bnxt_hwrm_vfr_qcfg(bp, vf_rep, &max_mtu)) 4779d96465bSSriharsha Basavapatna dev->max_mtu = max_mtu; 4789d96465bSSriharsha Basavapatna dev->min_mtu = ETH_ZLEN; 4794ab0c6a8SSathya Perla } 4804ab0c6a8SSathya Perla 4814ab0c6a8SSathya Perla static int bnxt_vf_reps_create(struct bnxt *bp) 4824ab0c6a8SSathya Perla { 483ee5c7fb3SSathya Perla u16 *cfa_code_map = NULL, num_vfs = pci_num_vf(bp->pdev); 4844ab0c6a8SSathya Perla struct bnxt_vf_rep *vf_rep; 4854ab0c6a8SSathya Perla struct net_device *dev; 4864ab0c6a8SSathya Perla int rc, i; 4874ab0c6a8SSathya Perla 488d061b241SMichael Chan if (!(bp->flags & BNXT_FLAG_DSN_VALID)) 489d061b241SMichael Chan return -ENODEV; 490d061b241SMichael Chan 4914ab0c6a8SSathya Perla bp->vf_reps = kcalloc(num_vfs, sizeof(vf_rep), GFP_KERNEL); 4924ab0c6a8SSathya Perla if (!bp->vf_reps) 4934ab0c6a8SSathya Perla return -ENOMEM; 4944ab0c6a8SSathya Perla 495ee5c7fb3SSathya Perla /* storage for cfa_code to vf-idx mapping */ 4966da2ec56SKees Cook cfa_code_map = kmalloc_array(MAX_CFA_CODE, sizeof(*bp->cfa_code_map), 497ee5c7fb3SSathya Perla GFP_KERNEL); 498ee5c7fb3SSathya Perla if (!cfa_code_map) { 499ee5c7fb3SSathya Perla rc = -ENOMEM; 500ee5c7fb3SSathya Perla goto err; 501ee5c7fb3SSathya Perla } 502ee5c7fb3SSathya Perla for (i = 0; i < MAX_CFA_CODE; i++) 503ee5c7fb3SSathya Perla cfa_code_map[i] = VF_IDX_INVALID; 504ee5c7fb3SSathya Perla 5054ab0c6a8SSathya Perla for (i = 0; i < num_vfs; i++) { 5064ab0c6a8SSathya Perla dev = alloc_etherdev(sizeof(*vf_rep)); 5074ab0c6a8SSathya Perla if (!dev) { 5084ab0c6a8SSathya Perla rc = -ENOMEM; 5094ab0c6a8SSathya Perla goto err; 5104ab0c6a8SSathya Perla } 5114ab0c6a8SSathya Perla 5124ab0c6a8SSathya Perla vf_rep = netdev_priv(dev); 5134ab0c6a8SSathya Perla bp->vf_reps[i] = vf_rep; 5144ab0c6a8SSathya Perla vf_rep->dev = dev; 5154ab0c6a8SSathya Perla vf_rep->bp = bp; 5164ab0c6a8SSathya Perla vf_rep->vf_idx = i; 5174ab0c6a8SSathya Perla vf_rep->tx_cfa_action = CFA_HANDLE_INVALID; 5184ab0c6a8SSathya Perla 519ea2d37b2SSriharsha Basavapatna rc = bnxt_alloc_vf_rep(bp, vf_rep, cfa_code_map); 520ea2d37b2SSriharsha Basavapatna if (rc) 521ee5c7fb3SSathya Perla goto err; 522ee5c7fb3SSathya Perla 5234ab0c6a8SSathya Perla bnxt_vf_rep_netdev_init(bp, vf_rep, dev); 5244ab0c6a8SSathya Perla rc = register_netdev(dev); 5254ab0c6a8SSathya Perla if (rc) { 5264ab0c6a8SSathya Perla /* no need for unregister_netdev in cleanup */ 5274ab0c6a8SSathya Perla dev->netdev_ops = NULL; 5284ab0c6a8SSathya Perla goto err; 5294ab0c6a8SSathya Perla } 5304ab0c6a8SSathya Perla } 5314ab0c6a8SSathya Perla 532ee5c7fb3SSathya Perla /* publish cfa_code_map only after all VF-reps have been initialized */ 533ee5c7fb3SSathya Perla bp->cfa_code_map = cfa_code_map; 5344ab0c6a8SSathya Perla bp->eswitch_mode = DEVLINK_ESWITCH_MODE_SWITCHDEV; 535ee5c7fb3SSathya Perla netif_keep_dst(bp->dev); 5364ab0c6a8SSathya Perla return 0; 5374ab0c6a8SSathya Perla 5384ab0c6a8SSathya Perla err: 5399a005c38SJonathan Lemon netdev_info(bp->dev, "%s error=%d\n", __func__, rc); 540ee5c7fb3SSathya Perla kfree(cfa_code_map); 5414ab0c6a8SSathya Perla __bnxt_vf_reps_destroy(bp); 5424ab0c6a8SSathya Perla return rc; 5434ab0c6a8SSathya Perla } 5444ab0c6a8SSathya Perla 5454ab0c6a8SSathya Perla /* Devlink related routines */ 5463c467bf3SSteve Lin int bnxt_dl_eswitch_mode_get(struct devlink *devlink, u16 *mode) 5474ab0c6a8SSathya Perla { 5484ab0c6a8SSathya Perla struct bnxt *bp = bnxt_get_bp_from_dl(devlink); 5494ab0c6a8SSathya Perla 5504ab0c6a8SSathya Perla *mode = bp->eswitch_mode; 5514ab0c6a8SSathya Perla return 0; 5524ab0c6a8SSathya Perla } 5534ab0c6a8SSathya Perla 554db7ff19eSEli Britstein int bnxt_dl_eswitch_mode_set(struct devlink *devlink, u16 mode, 555db7ff19eSEli Britstein struct netlink_ext_ack *extack) 5564ab0c6a8SSathya Perla { 5574ab0c6a8SSathya Perla struct bnxt *bp = bnxt_get_bp_from_dl(devlink); 5584ab0c6a8SSathya Perla int rc = 0; 5594ab0c6a8SSathya Perla 5604ab0c6a8SSathya Perla mutex_lock(&bp->sriov_lock); 5614ab0c6a8SSathya Perla if (bp->eswitch_mode == mode) { 5629a005c38SJonathan Lemon netdev_info(bp->dev, "already in %s eswitch mode\n", 5634ab0c6a8SSathya Perla mode == DEVLINK_ESWITCH_MODE_LEGACY ? 5644ab0c6a8SSathya Perla "legacy" : "switchdev"); 5654ab0c6a8SSathya Perla rc = -EINVAL; 5664ab0c6a8SSathya Perla goto done; 5674ab0c6a8SSathya Perla } 5684ab0c6a8SSathya Perla 5694ab0c6a8SSathya Perla switch (mode) { 5704ab0c6a8SSathya Perla case DEVLINK_ESWITCH_MODE_LEGACY: 5714ab0c6a8SSathya Perla bnxt_vf_reps_destroy(bp); 5724ab0c6a8SSathya Perla break; 5734ab0c6a8SSathya Perla 5744ab0c6a8SSathya Perla case DEVLINK_ESWITCH_MODE_SWITCHDEV: 5756354b95eSVasundhara Volam if (bp->hwrm_spec_code < 0x10803) { 5766354b95eSVasundhara Volam netdev_warn(bp->dev, "FW does not support SRIOV E-Switch SWITCHDEV mode\n"); 5776354b95eSVasundhara Volam rc = -ENOTSUPP; 5786354b95eSVasundhara Volam goto done; 5796354b95eSVasundhara Volam } 5806354b95eSVasundhara Volam 5814ab0c6a8SSathya Perla if (pci_num_vf(bp->pdev) == 0) { 5829a005c38SJonathan Lemon netdev_info(bp->dev, "Enable VFs before setting switchdev mode\n"); 5834ab0c6a8SSathya Perla rc = -EPERM; 5844ab0c6a8SSathya Perla goto done; 5854ab0c6a8SSathya Perla } 5864ab0c6a8SSathya Perla rc = bnxt_vf_reps_create(bp); 5874ab0c6a8SSathya Perla break; 5884ab0c6a8SSathya Perla 5894ab0c6a8SSathya Perla default: 5904ab0c6a8SSathya Perla rc = -EINVAL; 5914ab0c6a8SSathya Perla goto done; 5924ab0c6a8SSathya Perla } 5934ab0c6a8SSathya Perla done: 5944ab0c6a8SSathya Perla mutex_unlock(&bp->sriov_lock); 5954ab0c6a8SSathya Perla return rc; 5964ab0c6a8SSathya Perla } 5974ab0c6a8SSathya Perla 598d3e3beceSSathya Perla #endif 599