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 { 46ee5c7fb3SSathya Perla netdev_info(bp->dev, "%s error rc=%d", __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) 63ee5c7fb3SSathya Perla netdev_info(bp->dev, "%s error rc=%d", __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 1649e0fd15dSJiri Pirko static int bnxt_vf_rep_setup_tc_block(struct net_device *dev, 1659e0fd15dSJiri Pirko struct tc_block_offload *f) 1669e0fd15dSJiri Pirko { 1679e0fd15dSJiri Pirko struct bnxt_vf_rep *vf_rep = netdev_priv(dev); 1689e0fd15dSJiri Pirko 1699e0fd15dSJiri Pirko if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS) 1709e0fd15dSJiri Pirko return -EOPNOTSUPP; 1719e0fd15dSJiri Pirko 1729e0fd15dSJiri Pirko switch (f->command) { 1739e0fd15dSJiri Pirko case TC_BLOCK_BIND: 1749e0fd15dSJiri Pirko return tcf_block_cb_register(f->block, 1759e0fd15dSJiri Pirko bnxt_vf_rep_setup_tc_block_cb, 1769e0fd15dSJiri Pirko vf_rep, vf_rep); 1779e0fd15dSJiri Pirko case TC_BLOCK_UNBIND: 1789e0fd15dSJiri Pirko tcf_block_cb_unregister(f->block, 1799e0fd15dSJiri Pirko bnxt_vf_rep_setup_tc_block_cb, vf_rep); 1809e0fd15dSJiri Pirko return 0; 1819e0fd15dSJiri Pirko default: 1829e0fd15dSJiri Pirko return -EOPNOTSUPP; 1839e0fd15dSJiri Pirko } 1849e0fd15dSJiri Pirko } 1859e0fd15dSJiri Pirko 1869e0fd15dSJiri Pirko static int bnxt_vf_rep_setup_tc(struct net_device *dev, enum tc_setup_type type, 1879e0fd15dSJiri Pirko void *type_data) 1889e0fd15dSJiri Pirko { 1899e0fd15dSJiri Pirko switch (type) { 1909e0fd15dSJiri Pirko case TC_SETUP_BLOCK: 1919e0fd15dSJiri Pirko return bnxt_vf_rep_setup_tc_block(dev, type_data); 1929e0fd15dSJiri Pirko default: 1939e0fd15dSJiri Pirko return -EOPNOTSUPP; 1949e0fd15dSJiri Pirko } 1959e0fd15dSJiri Pirko } 1969e0fd15dSJiri Pirko 197ee5c7fb3SSathya Perla struct net_device *bnxt_get_vf_rep(struct bnxt *bp, u16 cfa_code) 198ee5c7fb3SSathya Perla { 199ee5c7fb3SSathya Perla u16 vf_idx; 200ee5c7fb3SSathya Perla 201ee5c7fb3SSathya Perla if (cfa_code && bp->cfa_code_map && BNXT_PF(bp)) { 202ee5c7fb3SSathya Perla vf_idx = bp->cfa_code_map[cfa_code]; 203ee5c7fb3SSathya Perla if (vf_idx != VF_IDX_INVALID) 204ee5c7fb3SSathya Perla return bp->vf_reps[vf_idx]->dev; 205ee5c7fb3SSathya Perla } 206ee5c7fb3SSathya Perla return NULL; 207ee5c7fb3SSathya Perla } 208ee5c7fb3SSathya Perla 209ee5c7fb3SSathya Perla void bnxt_vf_rep_rx(struct bnxt *bp, struct sk_buff *skb) 210ee5c7fb3SSathya Perla { 211ee5c7fb3SSathya Perla struct bnxt_vf_rep *vf_rep = netdev_priv(skb->dev); 212ee5c7fb3SSathya Perla struct bnxt_vf_rep_stats *rx_stats; 213ee5c7fb3SSathya Perla 214ee5c7fb3SSathya Perla rx_stats = &vf_rep->rx_stats; 215ee5c7fb3SSathya Perla vf_rep->rx_stats.bytes += skb->len; 216ee5c7fb3SSathya Perla vf_rep->rx_stats.packets++; 217ee5c7fb3SSathya Perla 218ee5c7fb3SSathya Perla netif_receive_skb(skb); 219ee5c7fb3SSathya Perla } 220ee5c7fb3SSathya Perla 221c124a62fSSathya Perla static int bnxt_vf_rep_get_phys_port_name(struct net_device *dev, char *buf, 222c124a62fSSathya Perla size_t len) 223c124a62fSSathya Perla { 224c124a62fSSathya Perla struct bnxt_vf_rep *vf_rep = netdev_priv(dev); 22553f70b8bSSathya Perla struct pci_dev *pf_pdev = vf_rep->bp->pdev; 226c124a62fSSathya Perla int rc; 227c124a62fSSathya Perla 22853f70b8bSSathya Perla rc = snprintf(buf, len, "pf%dvf%d", PCI_FUNC(pf_pdev->devfn), 22953f70b8bSSathya Perla vf_rep->vf_idx); 230c124a62fSSathya Perla if (rc >= len) 231c124a62fSSathya Perla return -EOPNOTSUPP; 232c124a62fSSathya Perla return 0; 233c124a62fSSathya Perla } 234c124a62fSSathya Perla 235ee5c7fb3SSathya Perla static void bnxt_vf_rep_get_drvinfo(struct net_device *dev, 236ee5c7fb3SSathya Perla struct ethtool_drvinfo *info) 237ee5c7fb3SSathya Perla { 238ee5c7fb3SSathya Perla strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver)); 239ee5c7fb3SSathya Perla strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version)); 240ee5c7fb3SSathya Perla } 241ee5c7fb3SSathya Perla 242c124a62fSSathya Perla static int bnxt_vf_rep_port_attr_get(struct net_device *dev, 243c124a62fSSathya Perla struct switchdev_attr *attr) 244c124a62fSSathya Perla { 245c124a62fSSathya Perla struct bnxt_vf_rep *vf_rep = netdev_priv(dev); 246c124a62fSSathya Perla 247c124a62fSSathya Perla /* as only PORT_PARENT_ID is supported currently use common code 248c124a62fSSathya Perla * between PF and VF-rep for now. 249c124a62fSSathya Perla */ 250c124a62fSSathya Perla return bnxt_port_attr_get(vf_rep->bp, attr); 251c124a62fSSathya Perla } 252c124a62fSSathya Perla 253c124a62fSSathya Perla static const struct switchdev_ops bnxt_vf_rep_switchdev_ops = { 254c124a62fSSathya Perla .switchdev_port_attr_get = bnxt_vf_rep_port_attr_get 255c124a62fSSathya Perla }; 256c124a62fSSathya Perla 257ee5c7fb3SSathya Perla static const struct ethtool_ops bnxt_vf_rep_ethtool_ops = { 258ee5c7fb3SSathya Perla .get_drvinfo = bnxt_vf_rep_get_drvinfo 259ee5c7fb3SSathya Perla }; 260ee5c7fb3SSathya Perla 261ee5c7fb3SSathya Perla static const struct net_device_ops bnxt_vf_rep_netdev_ops = { 262ee5c7fb3SSathya Perla .ndo_open = bnxt_vf_rep_open, 263ee5c7fb3SSathya Perla .ndo_stop = bnxt_vf_rep_close, 264ee5c7fb3SSathya Perla .ndo_start_xmit = bnxt_vf_rep_xmit, 265c124a62fSSathya Perla .ndo_get_stats64 = bnxt_vf_rep_get_stats64, 2662ae7408fSSathya Perla .ndo_setup_tc = bnxt_vf_rep_setup_tc, 267c124a62fSSathya Perla .ndo_get_phys_port_name = bnxt_vf_rep_get_phys_port_name 268ee5c7fb3SSathya Perla }; 269ee5c7fb3SSathya Perla 270dd4ea1daSSathya Perla bool bnxt_dev_is_vf_rep(struct net_device *dev) 271dd4ea1daSSathya Perla { 272dd4ea1daSSathya Perla return dev->netdev_ops == &bnxt_vf_rep_netdev_ops; 273dd4ea1daSSathya Perla } 274dd4ea1daSSathya Perla 275ee5c7fb3SSathya Perla /* Called when the parent PF interface is closed: 276ee5c7fb3SSathya Perla * As the mode transition from SWITCHDEV to LEGACY 277ee5c7fb3SSathya Perla * happens under the rtnl_lock() this routine is safe 278ee5c7fb3SSathya Perla * under the rtnl_lock() 279ee5c7fb3SSathya Perla */ 280ee5c7fb3SSathya Perla void bnxt_vf_reps_close(struct bnxt *bp) 281ee5c7fb3SSathya Perla { 282ee5c7fb3SSathya Perla struct bnxt_vf_rep *vf_rep; 283ee5c7fb3SSathya Perla u16 num_vfs, i; 284ee5c7fb3SSathya Perla 285ee5c7fb3SSathya Perla if (bp->eswitch_mode != DEVLINK_ESWITCH_MODE_SWITCHDEV) 286ee5c7fb3SSathya Perla return; 287ee5c7fb3SSathya Perla 288ee5c7fb3SSathya Perla num_vfs = pci_num_vf(bp->pdev); 289ee5c7fb3SSathya Perla for (i = 0; i < num_vfs; i++) { 290ee5c7fb3SSathya Perla vf_rep = bp->vf_reps[i]; 291ee5c7fb3SSathya Perla if (netif_running(vf_rep->dev)) 292ee5c7fb3SSathya Perla bnxt_vf_rep_close(vf_rep->dev); 293ee5c7fb3SSathya Perla } 294ee5c7fb3SSathya Perla } 295ee5c7fb3SSathya Perla 296ee5c7fb3SSathya Perla /* Called when the parent PF interface is opened (re-opened): 297ee5c7fb3SSathya Perla * As the mode transition from SWITCHDEV to LEGACY 298ee5c7fb3SSathya Perla * happen under the rtnl_lock() this routine is safe 299ee5c7fb3SSathya Perla * under the rtnl_lock() 300ee5c7fb3SSathya Perla */ 301ee5c7fb3SSathya Perla void bnxt_vf_reps_open(struct bnxt *bp) 302ee5c7fb3SSathya Perla { 303ee5c7fb3SSathya Perla int i; 304ee5c7fb3SSathya Perla 305ee5c7fb3SSathya Perla if (bp->eswitch_mode != DEVLINK_ESWITCH_MODE_SWITCHDEV) 306ee5c7fb3SSathya Perla return; 307ee5c7fb3SSathya Perla 308ee5c7fb3SSathya Perla for (i = 0; i < pci_num_vf(bp->pdev); i++) 309ee5c7fb3SSathya Perla bnxt_vf_rep_open(bp->vf_reps[i]->dev); 310ee5c7fb3SSathya Perla } 3114ab0c6a8SSathya Perla 3124ab0c6a8SSathya Perla static void __bnxt_vf_reps_destroy(struct bnxt *bp) 3134ab0c6a8SSathya Perla { 3144ab0c6a8SSathya Perla u16 num_vfs = pci_num_vf(bp->pdev); 3154ab0c6a8SSathya Perla struct bnxt_vf_rep *vf_rep; 3164ab0c6a8SSathya Perla int i; 3174ab0c6a8SSathya Perla 3184ab0c6a8SSathya Perla for (i = 0; i < num_vfs; i++) { 3194ab0c6a8SSathya Perla vf_rep = bp->vf_reps[i]; 3204ab0c6a8SSathya Perla if (vf_rep) { 321ee5c7fb3SSathya Perla dst_release((struct dst_entry *)vf_rep->dst); 322ee5c7fb3SSathya Perla 323ee5c7fb3SSathya Perla if (vf_rep->tx_cfa_action != CFA_HANDLE_INVALID) 324ee5c7fb3SSathya Perla hwrm_cfa_vfr_free(bp, vf_rep->vf_idx); 325ee5c7fb3SSathya Perla 3264ab0c6a8SSathya Perla if (vf_rep->dev) { 3274ab0c6a8SSathya Perla /* if register_netdev failed, then netdev_ops 3284ab0c6a8SSathya Perla * would have been set to NULL 3294ab0c6a8SSathya Perla */ 3304ab0c6a8SSathya Perla if (vf_rep->dev->netdev_ops) 3314ab0c6a8SSathya Perla unregister_netdev(vf_rep->dev); 3324ab0c6a8SSathya Perla free_netdev(vf_rep->dev); 3334ab0c6a8SSathya Perla } 3344ab0c6a8SSathya Perla } 3354ab0c6a8SSathya Perla } 3364ab0c6a8SSathya Perla 3374ab0c6a8SSathya Perla kfree(bp->vf_reps); 3384ab0c6a8SSathya Perla bp->vf_reps = NULL; 3394ab0c6a8SSathya Perla } 3404ab0c6a8SSathya Perla 3414ab0c6a8SSathya Perla void bnxt_vf_reps_destroy(struct bnxt *bp) 3424ab0c6a8SSathya Perla { 3434ab0c6a8SSathya Perla bool closed = false; 3444ab0c6a8SSathya Perla 3454ab0c6a8SSathya Perla if (bp->eswitch_mode != DEVLINK_ESWITCH_MODE_SWITCHDEV) 3464ab0c6a8SSathya Perla return; 3474ab0c6a8SSathya Perla 3484ab0c6a8SSathya Perla if (!bp->vf_reps) 3494ab0c6a8SSathya Perla return; 3504ab0c6a8SSathya Perla 3514ab0c6a8SSathya Perla /* Ensure that parent PF's and VF-reps' RX/TX has been quiesced 3524ab0c6a8SSathya Perla * before proceeding with VF-rep cleanup. 3534ab0c6a8SSathya Perla */ 3544ab0c6a8SSathya Perla rtnl_lock(); 3554ab0c6a8SSathya Perla if (netif_running(bp->dev)) { 3564ab0c6a8SSathya Perla bnxt_close_nic(bp, false, false); 3574ab0c6a8SSathya Perla closed = true; 3584ab0c6a8SSathya Perla } 359ee5c7fb3SSathya Perla /* un-publish cfa_code_map so that RX path can't see it anymore */ 360ee5c7fb3SSathya Perla kfree(bp->cfa_code_map); 361ee5c7fb3SSathya Perla bp->cfa_code_map = NULL; 3624ab0c6a8SSathya Perla bp->eswitch_mode = DEVLINK_ESWITCH_MODE_LEGACY; 3634ab0c6a8SSathya Perla 3644ab0c6a8SSathya Perla if (closed) 3654ab0c6a8SSathya Perla bnxt_open_nic(bp, false, false); 3664ab0c6a8SSathya Perla rtnl_unlock(); 3674ab0c6a8SSathya Perla 3684ab0c6a8SSathya Perla /* Need to call vf_reps_destroy() outside of rntl_lock 3694ab0c6a8SSathya Perla * as unregister_netdev takes rtnl_lock 3704ab0c6a8SSathya Perla */ 3714ab0c6a8SSathya Perla __bnxt_vf_reps_destroy(bp); 3724ab0c6a8SSathya Perla } 3734ab0c6a8SSathya Perla 3744ab0c6a8SSathya Perla /* Use the OUI of the PF's perm addr and report the same mac addr 3754ab0c6a8SSathya Perla * for the same VF-rep each time 3764ab0c6a8SSathya Perla */ 3774ab0c6a8SSathya Perla static void bnxt_vf_rep_eth_addr_gen(u8 *src_mac, u16 vf_idx, u8 *mac) 3784ab0c6a8SSathya Perla { 3794ab0c6a8SSathya Perla u32 addr; 3804ab0c6a8SSathya Perla 3814ab0c6a8SSathya Perla ether_addr_copy(mac, src_mac); 3824ab0c6a8SSathya Perla 3834ab0c6a8SSathya Perla addr = jhash(src_mac, ETH_ALEN, 0) + vf_idx; 3844ab0c6a8SSathya Perla mac[3] = (u8)(addr & 0xFF); 3854ab0c6a8SSathya Perla mac[4] = (u8)((addr >> 8) & 0xFF); 3864ab0c6a8SSathya Perla mac[5] = (u8)((addr >> 16) & 0xFF); 3874ab0c6a8SSathya Perla } 3884ab0c6a8SSathya Perla 3894ab0c6a8SSathya Perla static void bnxt_vf_rep_netdev_init(struct bnxt *bp, struct bnxt_vf_rep *vf_rep, 3904ab0c6a8SSathya Perla struct net_device *dev) 3914ab0c6a8SSathya Perla { 3924ab0c6a8SSathya Perla struct net_device *pf_dev = bp->dev; 3939d96465bSSriharsha Basavapatna u16 max_mtu; 3944ab0c6a8SSathya Perla 395ee5c7fb3SSathya Perla dev->netdev_ops = &bnxt_vf_rep_netdev_ops; 396ee5c7fb3SSathya Perla dev->ethtool_ops = &bnxt_vf_rep_ethtool_ops; 397e408ebdcSSathya Perla SWITCHDEV_SET_OPS(dev, &bnxt_vf_rep_switchdev_ops); 3984ab0c6a8SSathya Perla /* Just inherit all the featues of the parent PF as the VF-R 3994ab0c6a8SSathya Perla * uses the RX/TX rings of the parent PF 4004ab0c6a8SSathya Perla */ 4014ab0c6a8SSathya Perla dev->hw_features = pf_dev->hw_features; 4024ab0c6a8SSathya Perla dev->gso_partial_features = pf_dev->gso_partial_features; 4034ab0c6a8SSathya Perla dev->vlan_features = pf_dev->vlan_features; 4044ab0c6a8SSathya Perla dev->hw_enc_features = pf_dev->hw_enc_features; 4054ab0c6a8SSathya Perla dev->features |= pf_dev->features; 4064ab0c6a8SSathya Perla bnxt_vf_rep_eth_addr_gen(bp->pf.mac_addr, vf_rep->vf_idx, 4074ab0c6a8SSathya Perla dev->perm_addr); 4084ab0c6a8SSathya Perla ether_addr_copy(dev->dev_addr, dev->perm_addr); 4099d96465bSSriharsha Basavapatna /* Set VF-Rep's max-mtu to the corresponding VF's max-mtu */ 4109d96465bSSriharsha Basavapatna if (!bnxt_hwrm_vfr_qcfg(bp, vf_rep, &max_mtu)) 4119d96465bSSriharsha Basavapatna dev->max_mtu = max_mtu; 4129d96465bSSriharsha Basavapatna dev->min_mtu = ETH_ZLEN; 4134ab0c6a8SSathya Perla } 4144ab0c6a8SSathya Perla 415dd4ea1daSSathya Perla static int bnxt_pcie_dsn_get(struct bnxt *bp, u8 dsn[]) 416dd4ea1daSSathya Perla { 417dd4ea1daSSathya Perla struct pci_dev *pdev = bp->pdev; 418dd4ea1daSSathya Perla int pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_DSN); 419dd4ea1daSSathya Perla u32 dw; 420dd4ea1daSSathya Perla 421dd4ea1daSSathya Perla if (!pos) { 422dd4ea1daSSathya Perla netdev_info(bp->dev, "Unable do read adapter's DSN"); 423dd4ea1daSSathya Perla return -EOPNOTSUPP; 424dd4ea1daSSathya Perla } 425dd4ea1daSSathya Perla 426dd4ea1daSSathya Perla /* DSN (two dw) is at an offset of 4 from the cap pos */ 427dd4ea1daSSathya Perla pos += 4; 428dd4ea1daSSathya Perla pci_read_config_dword(pdev, pos, &dw); 429dd4ea1daSSathya Perla put_unaligned_le32(dw, &dsn[0]); 430dd4ea1daSSathya Perla pci_read_config_dword(pdev, pos + 4, &dw); 431dd4ea1daSSathya Perla put_unaligned_le32(dw, &dsn[4]); 432dd4ea1daSSathya Perla return 0; 433dd4ea1daSSathya Perla } 434dd4ea1daSSathya Perla 4354ab0c6a8SSathya Perla static int bnxt_vf_reps_create(struct bnxt *bp) 4364ab0c6a8SSathya Perla { 437ee5c7fb3SSathya Perla u16 *cfa_code_map = NULL, num_vfs = pci_num_vf(bp->pdev); 4384ab0c6a8SSathya Perla struct bnxt_vf_rep *vf_rep; 4394ab0c6a8SSathya Perla struct net_device *dev; 4404ab0c6a8SSathya Perla int rc, i; 4414ab0c6a8SSathya Perla 4424ab0c6a8SSathya Perla bp->vf_reps = kcalloc(num_vfs, sizeof(vf_rep), GFP_KERNEL); 4434ab0c6a8SSathya Perla if (!bp->vf_reps) 4444ab0c6a8SSathya Perla return -ENOMEM; 4454ab0c6a8SSathya Perla 446ee5c7fb3SSathya Perla /* storage for cfa_code to vf-idx mapping */ 4476da2ec56SKees Cook cfa_code_map = kmalloc_array(MAX_CFA_CODE, sizeof(*bp->cfa_code_map), 448ee5c7fb3SSathya Perla GFP_KERNEL); 449ee5c7fb3SSathya Perla if (!cfa_code_map) { 450ee5c7fb3SSathya Perla rc = -ENOMEM; 451ee5c7fb3SSathya Perla goto err; 452ee5c7fb3SSathya Perla } 453ee5c7fb3SSathya Perla for (i = 0; i < MAX_CFA_CODE; i++) 454ee5c7fb3SSathya Perla cfa_code_map[i] = VF_IDX_INVALID; 455ee5c7fb3SSathya Perla 4564ab0c6a8SSathya Perla for (i = 0; i < num_vfs; i++) { 4574ab0c6a8SSathya Perla dev = alloc_etherdev(sizeof(*vf_rep)); 4584ab0c6a8SSathya Perla if (!dev) { 4594ab0c6a8SSathya Perla rc = -ENOMEM; 4604ab0c6a8SSathya Perla goto err; 4614ab0c6a8SSathya Perla } 4624ab0c6a8SSathya Perla 4634ab0c6a8SSathya Perla vf_rep = netdev_priv(dev); 4644ab0c6a8SSathya Perla bp->vf_reps[i] = vf_rep; 4654ab0c6a8SSathya Perla vf_rep->dev = dev; 4664ab0c6a8SSathya Perla vf_rep->bp = bp; 4674ab0c6a8SSathya Perla vf_rep->vf_idx = i; 4684ab0c6a8SSathya Perla vf_rep->tx_cfa_action = CFA_HANDLE_INVALID; 4694ab0c6a8SSathya Perla 470ee5c7fb3SSathya Perla /* get cfa handles from FW */ 471ee5c7fb3SSathya Perla rc = hwrm_cfa_vfr_alloc(bp, vf_rep->vf_idx, 472ee5c7fb3SSathya Perla &vf_rep->tx_cfa_action, 473ee5c7fb3SSathya Perla &vf_rep->rx_cfa_code); 474ee5c7fb3SSathya Perla if (rc) { 475ee5c7fb3SSathya Perla rc = -ENOLINK; 476ee5c7fb3SSathya Perla goto err; 477ee5c7fb3SSathya Perla } 478ee5c7fb3SSathya Perla cfa_code_map[vf_rep->rx_cfa_code] = vf_rep->vf_idx; 479ee5c7fb3SSathya Perla 480ee5c7fb3SSathya Perla vf_rep->dst = metadata_dst_alloc(0, METADATA_HW_PORT_MUX, 481ee5c7fb3SSathya Perla GFP_KERNEL); 482ee5c7fb3SSathya Perla if (!vf_rep->dst) { 483ee5c7fb3SSathya Perla rc = -ENOMEM; 484ee5c7fb3SSathya Perla goto err; 485ee5c7fb3SSathya Perla } 486ee5c7fb3SSathya Perla /* only cfa_action is needed to mux a packet while TXing */ 487ee5c7fb3SSathya Perla vf_rep->dst->u.port_info.port_id = vf_rep->tx_cfa_action; 488ee5c7fb3SSathya Perla vf_rep->dst->u.port_info.lower_dev = bp->dev; 489ee5c7fb3SSathya Perla 4904ab0c6a8SSathya Perla bnxt_vf_rep_netdev_init(bp, vf_rep, dev); 4914ab0c6a8SSathya Perla rc = register_netdev(dev); 4924ab0c6a8SSathya Perla if (rc) { 4934ab0c6a8SSathya Perla /* no need for unregister_netdev in cleanup */ 4944ab0c6a8SSathya Perla dev->netdev_ops = NULL; 4954ab0c6a8SSathya Perla goto err; 4964ab0c6a8SSathya Perla } 4974ab0c6a8SSathya Perla } 4984ab0c6a8SSathya Perla 499dd4ea1daSSathya Perla /* Read the adapter's DSN to use as the eswitch switch_id */ 500dd4ea1daSSathya Perla rc = bnxt_pcie_dsn_get(bp, bp->switch_id); 501dd4ea1daSSathya Perla if (rc) 502dd4ea1daSSathya Perla goto err; 503dd4ea1daSSathya Perla 504ee5c7fb3SSathya Perla /* publish cfa_code_map only after all VF-reps have been initialized */ 505ee5c7fb3SSathya Perla bp->cfa_code_map = cfa_code_map; 5064ab0c6a8SSathya Perla bp->eswitch_mode = DEVLINK_ESWITCH_MODE_SWITCHDEV; 507ee5c7fb3SSathya Perla netif_keep_dst(bp->dev); 5084ab0c6a8SSathya Perla return 0; 5094ab0c6a8SSathya Perla 5104ab0c6a8SSathya Perla err: 5114ab0c6a8SSathya Perla netdev_info(bp->dev, "%s error=%d", __func__, rc); 512ee5c7fb3SSathya Perla kfree(cfa_code_map); 5134ab0c6a8SSathya Perla __bnxt_vf_reps_destroy(bp); 5144ab0c6a8SSathya Perla return rc; 5154ab0c6a8SSathya Perla } 5164ab0c6a8SSathya Perla 5174ab0c6a8SSathya Perla /* Devlink related routines */ 5183c467bf3SSteve Lin int bnxt_dl_eswitch_mode_get(struct devlink *devlink, u16 *mode) 5194ab0c6a8SSathya Perla { 5204ab0c6a8SSathya Perla struct bnxt *bp = bnxt_get_bp_from_dl(devlink); 5214ab0c6a8SSathya Perla 5224ab0c6a8SSathya Perla *mode = bp->eswitch_mode; 5234ab0c6a8SSathya Perla return 0; 5244ab0c6a8SSathya Perla } 5254ab0c6a8SSathya Perla 5263c467bf3SSteve Lin int bnxt_dl_eswitch_mode_set(struct devlink *devlink, u16 mode) 5274ab0c6a8SSathya Perla { 5284ab0c6a8SSathya Perla struct bnxt *bp = bnxt_get_bp_from_dl(devlink); 5294ab0c6a8SSathya Perla int rc = 0; 5304ab0c6a8SSathya Perla 5314ab0c6a8SSathya Perla mutex_lock(&bp->sriov_lock); 5324ab0c6a8SSathya Perla if (bp->eswitch_mode == mode) { 5334ab0c6a8SSathya Perla netdev_info(bp->dev, "already in %s eswitch mode", 5344ab0c6a8SSathya Perla mode == DEVLINK_ESWITCH_MODE_LEGACY ? 5354ab0c6a8SSathya Perla "legacy" : "switchdev"); 5364ab0c6a8SSathya Perla rc = -EINVAL; 5374ab0c6a8SSathya Perla goto done; 5384ab0c6a8SSathya Perla } 5394ab0c6a8SSathya Perla 5404ab0c6a8SSathya Perla switch (mode) { 5414ab0c6a8SSathya Perla case DEVLINK_ESWITCH_MODE_LEGACY: 5424ab0c6a8SSathya Perla bnxt_vf_reps_destroy(bp); 5434ab0c6a8SSathya Perla break; 5444ab0c6a8SSathya Perla 5454ab0c6a8SSathya Perla case DEVLINK_ESWITCH_MODE_SWITCHDEV: 5464ab0c6a8SSathya Perla if (pci_num_vf(bp->pdev) == 0) { 5474ab0c6a8SSathya Perla netdev_info(bp->dev, 548bd76b879SColin Ian King "Enable VFs before setting switchdev mode"); 5494ab0c6a8SSathya Perla rc = -EPERM; 5504ab0c6a8SSathya Perla goto done; 5514ab0c6a8SSathya Perla } 5524ab0c6a8SSathya Perla rc = bnxt_vf_reps_create(bp); 5534ab0c6a8SSathya Perla break; 5544ab0c6a8SSathya Perla 5554ab0c6a8SSathya Perla default: 5564ab0c6a8SSathya Perla rc = -EINVAL; 5574ab0c6a8SSathya Perla goto done; 5584ab0c6a8SSathya Perla } 5594ab0c6a8SSathya Perla done: 5604ab0c6a8SSathya Perla mutex_unlock(&bp->sriov_lock); 5614ab0c6a8SSathya Perla return rc; 5624ab0c6a8SSathya Perla } 5634ab0c6a8SSathya Perla 564d3e3beceSSathya Perla #endif 565