/* Broadcom NetXtreme-C/E network driver. * * Copyright (c) 2016-2017 Broadcom Limited * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation.
*/ #include <linux/pci.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/rtnetlink.h> #include <linux/jhash.h> #include <net/pkt_cls.h> #include <linux/bnxt/hsi.h>
/* Enable link and TX only if the parent PF is open. */ if (netif_running(bp->dev)) {
netif_carrier_on(dev);
netif_tx_start_all_queues(dev);
} return 0;
}
/* as only PORT_PARENT_ID is supported currently use common code * between PF and VF-rep for now.
*/ return bnxt_get_port_parent_id(vf_rep->bp->dev, ppid);
}
/* Called when the parent PF interface is closed: * As the mode transition from SWITCHDEV to LEGACY * happens under the netdev instance lock this routine is safe
*/ void bnxt_vf_reps_close(struct bnxt *bp)
{ struct bnxt_vf_rep *vf_rep;
u16 num_vfs, i;
if (bp->eswitch_mode != DEVLINK_ESWITCH_MODE_SWITCHDEV) return;
num_vfs = pci_num_vf(bp->pdev); for (i = 0; i < num_vfs; i++) {
vf_rep = bp->vf_reps[i]; if (netif_running(vf_rep->dev))
bnxt_vf_rep_close(vf_rep->dev);
}
}
/* Called when the parent PF interface is opened (re-opened): * As the mode transition from SWITCHDEV to LEGACY * happen under the netdev instance lock this routine is safe
*/ void bnxt_vf_reps_open(struct bnxt *bp)
{ int i;
if (bp->eswitch_mode != DEVLINK_ESWITCH_MODE_SWITCHDEV) return;
for (i = 0; i < pci_num_vf(bp->pdev); i++) { /* Open the VF-Rep only if it is allocated in the FW */ if (bp->vf_reps[i]->tx_cfa_action != CFA_HANDLE_INVALID)
bnxt_vf_rep_open(bp->vf_reps[i]->dev);
}
}
for (i = 0; i < num_vfs; i++) {
vf_rep = bp->vf_reps[i]; if (vf_rep) {
__bnxt_free_one_vf_rep(bp, vf_rep); if (vf_rep->dev) { /* if register_netdev failed, then netdev_ops * would have been set to NULL
*/ if (vf_rep->dev->netdev_ops)
unregister_netdev(vf_rep->dev);
free_netdev(vf_rep->dev);
}
}
}
if (bp->eswitch_mode != DEVLINK_ESWITCH_MODE_SWITCHDEV) return;
if (!bp->vf_reps) return;
/* Ensure that parent PF's and VF-reps' RX/TX has been quiesced * before proceeding with VF-rep cleanup.
*/
netdev_lock(bp->dev); if (netif_running(bp->dev)) {
bnxt_close_nic(bp, false, false);
closed = true;
} /* un-publish cfa_code_map so that RX path can't see it anymore */
kfree(bp->cfa_code_map);
bp->cfa_code_map = NULL;
if (closed) { /* Temporarily set legacy mode to avoid re-opening * representors and restore switchdev mode after that.
*/
bp->eswitch_mode = DEVLINK_ESWITCH_MODE_LEGACY;
bnxt_open_nic(bp, false, false);
bp->eswitch_mode = DEVLINK_ESWITCH_MODE_SWITCHDEV;
}
netdev_unlock(bp->dev);
/* Need to call vf_reps_destroy() outside of netdev instance lock * as unregister_netdev takes it
*/
__bnxt_vf_reps_destroy(bp);
}
/* Free the VF-Reps in firmware, during firmware hot-reset processing. * Note that the VF-Rep netdevs are still active (not unregistered) during * this process. As the mode transition from SWITCHDEV to LEGACY happens * under the netdev instance lock this routine is safe.
*/ void bnxt_vf_reps_free(struct bnxt *bp)
{
u16 num_vfs = pci_num_vf(bp->pdev); int i;
if (bp->eswitch_mode != DEVLINK_ESWITCH_MODE_SWITCHDEV) return;
for (i = 0; i < num_vfs; i++)
__bnxt_free_one_vf_rep(bp, bp->vf_reps[i]);
}
staticint bnxt_alloc_vf_rep(struct bnxt *bp, struct bnxt_vf_rep *vf_rep,
u16 *cfa_code_map)
{ /* get cfa handles from FW */ if (hwrm_cfa_vfr_alloc(bp, vf_rep->vf_idx, &vf_rep->tx_cfa_action,
&vf_rep->rx_cfa_code)) return -ENOLINK;
/* only cfa_action is needed to mux a packet while TXing */
vf_rep->dst->u.port_info.port_id = vf_rep->tx_cfa_action;
vf_rep->dst->u.port_info.lower_dev = bp->dev;
return 0;
}
/* Allocate the VF-Reps in firmware, during firmware hot-reset processing. * Note that the VF-Rep netdevs are still active (not unregistered) during * this process. As the mode transition from SWITCHDEV to LEGACY happens * under the netdev instance lock this routine is safe.
*/ int bnxt_vf_reps_alloc(struct bnxt *bp)
{
u16 *cfa_code_map = bp->cfa_code_map, num_vfs = pci_num_vf(bp->pdev); struct bnxt_vf_rep *vf_rep; int rc, i;
if (bp->eswitch_mode != DEVLINK_ESWITCH_MODE_SWITCHDEV) return 0;
if (!cfa_code_map) return -EINVAL;
for (i = 0; i < MAX_CFA_CODE; i++)
cfa_code_map[i] = VF_IDX_INVALID;
for (i = 0; i < num_vfs; i++) {
vf_rep = bp->vf_reps[i];
vf_rep->vf_idx = i;
rc = bnxt_alloc_vf_rep(bp, vf_rep, cfa_code_map); if (rc) goto err;
}
/* Use the OUI of the PF's perm addr and report the same mac addr * for the same VF-rep each time
*/ staticvoid bnxt_vf_rep_eth_addr_gen(u8 *src_mac, u16 vf_idx, u8 *mac)
{
u32 addr;
rc = bnxt_alloc_vf_rep(bp, vf_rep, cfa_code_map); if (rc) goto err;
bnxt_vf_rep_netdev_init(bp, vf_rep, dev);
rc = register_netdev(dev); if (rc) { /* no need for unregister_netdev in cleanup */
dev->netdev_ops = NULL; goto err;
}
}
/* publish cfa_code_map only after all VF-reps have been initialized */
bp->cfa_code_map = cfa_code_map;
netif_keep_dst(bp->dev); return 0;
switch (mode) { case DEVLINK_ESWITCH_MODE_LEGACY:
bnxt_vf_reps_destroy(bp); break;
case DEVLINK_ESWITCH_MODE_SWITCHDEV: if (bp->hwrm_spec_code < 0x10803) {
netdev_warn(bp->dev, "FW does not support SRIOV E-Switch SWITCHDEV mode\n"); return -ENOTSUPP;
}
/* Create representors for existing VFs */ if (pci_num_vf(bp->pdev) > 0)
ret = bnxt_vf_reps_create(bp); break;
default: return -EINVAL;
}
if (!ret)
bp->eswitch_mode = mode;
return ret;
}
#endif
Messung V0.5
¤ Dauer der Verarbeitung: 0.11 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.