Commit 1ab4434c authored by Ariel Elior's avatar Ariel Elior Committed by David S. Miller

bnx2x: Support probing and removing of VF device

To support probing and removing of a bnx2x virtual function
the following were added:
1. add bnx2x_vfpf.h: defines the VF to PF channel
2. add bnx2x_sriov.h: header for bnx2x SR-IOV functionality
3. enumerate VF hw types (identify VFs)
4. if driving a VF, map VF bar
5. if driving a VF, allocate Vf to PF channel
6. refactor interrupt flows to include VF
Signed-off-by: default avatarAriel Elior <ariele@broadcom.com>
Signed-off-by: default avatarEilon Greenstein <eilong@broadcom.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 7f51c587
...@@ -49,6 +49,12 @@ ...@@ -49,6 +49,12 @@
#include "bnx2x_dcb.h" #include "bnx2x_dcb.h"
#include "bnx2x_stats.h" #include "bnx2x_stats.h"
enum bnx2x_int_mode {
BNX2X_INT_MODE_MSIX,
BNX2X_INT_MODE_INTX,
BNX2X_INT_MODE_MSI
};
/* error/debug prints */ /* error/debug prints */
#define DRV_MODULE_NAME "bnx2x" #define DRV_MODULE_NAME "bnx2x"
...@@ -954,6 +960,9 @@ struct bnx2x_port { ...@@ -954,6 +960,9 @@ struct bnx2x_port {
extern struct workqueue_struct *bnx2x_wq; extern struct workqueue_struct *bnx2x_wq;
#define BNX2X_MAX_NUM_OF_VFS 64 #define BNX2X_MAX_NUM_OF_VFS 64
#define BNX2X_VF_CID_WND 0
#define BNX2X_CIDS_PER_VF (1 << BNX2X_VF_CID_WND)
#define BNX2X_VF_CIDS (BNX2X_MAX_NUM_OF_VFS * BNX2X_CIDS_PER_VF)
#define BNX2X_VF_ID_INVALID 0xFF #define BNX2X_VF_ID_INVALID 0xFF
/* /*
...@@ -1231,6 +1240,10 @@ struct bnx2x { ...@@ -1231,6 +1240,10 @@ struct bnx2x {
(vn) * ((CHIP_IS_E1x(bp) || (CHIP_MODE_IS_4_PORT(bp))) ? 2 : 1)) (vn) * ((CHIP_IS_E1x(bp) || (CHIP_MODE_IS_4_PORT(bp))) ? 2 : 1))
#define BP_FW_MB_IDX(bp) BP_FW_MB_IDX_VN(bp, BP_VN(bp)) #define BP_FW_MB_IDX(bp) BP_FW_MB_IDX_VN(bp, BP_VN(bp))
/* vf pf channel mailbox contains request and response buffers */
struct bnx2x_vf_mbx_msg *vf2pf_mbox;
dma_addr_t vf2pf_mbox_mapping;
struct net_device *dev; struct net_device *dev;
struct pci_dev *pdev; struct pci_dev *pdev;
...@@ -1318,8 +1331,6 @@ struct bnx2x { ...@@ -1318,8 +1331,6 @@ struct bnx2x {
#define DISABLE_MSI_FLAG (1 << 7) #define DISABLE_MSI_FLAG (1 << 7)
#define TPA_ENABLE_FLAG (1 << 8) #define TPA_ENABLE_FLAG (1 << 8)
#define NO_MCP_FLAG (1 << 9) #define NO_MCP_FLAG (1 << 9)
#define BP_NOMCP(bp) (bp->flags & NO_MCP_FLAG)
#define GRO_ENABLE_FLAG (1 << 10) #define GRO_ENABLE_FLAG (1 << 10)
#define MF_FUNC_DIS (1 << 11) #define MF_FUNC_DIS (1 << 11)
#define OWN_CNIC_IRQ (1 << 12) #define OWN_CNIC_IRQ (1 << 12)
...@@ -1330,6 +1341,11 @@ struct bnx2x { ...@@ -1330,6 +1341,11 @@ struct bnx2x {
#define BC_SUPPORTS_FCOE_FEATURES (1 << 19) #define BC_SUPPORTS_FCOE_FEATURES (1 << 19)
#define USING_SINGLE_MSIX_FLAG (1 << 20) #define USING_SINGLE_MSIX_FLAG (1 << 20)
#define BC_SUPPORTS_DCBX_MSG_NON_PMF (1 << 21) #define BC_SUPPORTS_DCBX_MSG_NON_PMF (1 << 21)
#define IS_VF_FLAG (1 << 22)
#define BP_NOMCP(bp) ((bp)->flags & NO_MCP_FLAG)
#define IS_VF(bp) ((bp)->flags & IS_VF_FLAG)
#define IS_PF(bp) (!((bp)->flags & IS_VF_FLAG))
#define NO_ISCSI(bp) ((bp)->flags & NO_ISCSI_FLAG) #define NO_ISCSI(bp) ((bp)->flags & NO_ISCSI_FLAG)
#define NO_ISCSI_OOO(bp) ((bp)->flags & NO_ISCSI_OOO_FLAG) #define NO_ISCSI_OOO(bp) ((bp)->flags & NO_ISCSI_OOO_FLAG)
...@@ -1432,6 +1448,7 @@ struct bnx2x { ...@@ -1432,6 +1448,7 @@ struct bnx2x {
u8 igu_sb_cnt; u8 igu_sb_cnt;
u8 min_msix_vec_cnt; u8 min_msix_vec_cnt;
u32 igu_base_addr;
dma_addr_t def_status_blk_mapping; dma_addr_t def_status_blk_mapping;
struct bnx2x_slowpath *slowpath; struct bnx2x_slowpath *slowpath;
......
...@@ -1439,12 +1439,15 @@ void bnx2x_free_irq(struct bnx2x *bp) ...@@ -1439,12 +1439,15 @@ void bnx2x_free_irq(struct bnx2x *bp)
int bnx2x_enable_msix(struct bnx2x *bp) int bnx2x_enable_msix(struct bnx2x *bp)
{ {
int msix_vec = 0, i, rc, req_cnt; int msix_vec = 0, i, rc;
bp->msix_table[msix_vec].entry = msix_vec; /* VFs don't have a default status block */
BNX2X_DEV_INFO("msix_table[0].entry = %d (slowpath)\n", if (IS_PF(bp)) {
bp->msix_table[0].entry); bp->msix_table[msix_vec].entry = msix_vec;
msix_vec++; BNX2X_DEV_INFO("msix_table[0].entry = %d (slowpath)\n",
bp->msix_table[0].entry);
msix_vec++;
}
/* Cnic requires an msix vector for itself */ /* Cnic requires an msix vector for itself */
if (CNIC_SUPPORT(bp)) { if (CNIC_SUPPORT(bp)) {
...@@ -1462,9 +1465,10 @@ int bnx2x_enable_msix(struct bnx2x *bp) ...@@ -1462,9 +1465,10 @@ int bnx2x_enable_msix(struct bnx2x *bp)
msix_vec++; msix_vec++;
} }
req_cnt = BNX2X_NUM_ETH_QUEUES(bp) + CNIC_SUPPORT(bp) + 1; DP(BNX2X_MSG_SP, "about to request enable msix with %d vectors\n",
msix_vec);
rc = pci_enable_msix(bp->pdev, &bp->msix_table[0], req_cnt); rc = pci_enable_msix(bp->pdev, &bp->msix_table[0], msix_vec);
/* /*
* reconfigure number of tx/rx queues according to available * reconfigure number of tx/rx queues according to available
...@@ -1472,7 +1476,7 @@ int bnx2x_enable_msix(struct bnx2x *bp) ...@@ -1472,7 +1476,7 @@ int bnx2x_enable_msix(struct bnx2x *bp)
*/ */
if (rc >= BNX2X_MIN_MSIX_VEC_CNT(bp)) { if (rc >= BNX2X_MIN_MSIX_VEC_CNT(bp)) {
/* how less vectors we will have? */ /* how less vectors we will have? */
int diff = req_cnt - rc; int diff = msix_vec - rc;
BNX2X_DEV_INFO("Trying to use less MSI-X vectors: %d\n", rc); BNX2X_DEV_INFO("Trying to use less MSI-X vectors: %d\n", rc);
...@@ -3905,7 +3909,10 @@ int bnx2x_alloc_mem_bp(struct bnx2x *bp) ...@@ -3905,7 +3909,10 @@ int bnx2x_alloc_mem_bp(struct bnx2x *bp)
* The biggest MSI-X table we might need is as a maximum number of fast * The biggest MSI-X table we might need is as a maximum number of fast
* path IGU SBs plus default SB (for PF). * path IGU SBs plus default SB (for PF).
*/ */
msix_table_size = bp->igu_sb_cnt + 1; msix_table_size = bp->igu_sb_cnt;
if (IS_PF(bp))
msix_table_size++;
BNX2X_DEV_INFO("msix_table_size %d\n", msix_table_size);
/* fp array: RSS plus CNIC related L2 queues */ /* fp array: RSS plus CNIC related L2 queues */
fp_array_size = BNX2X_MAX_RSS_COUNT(bp) + CNIC_SUPPORT(bp); fp_array_size = BNX2X_MAX_RSS_COUNT(bp) + CNIC_SUPPORT(bp);
......
...@@ -863,7 +863,7 @@ static inline void bnx2x_del_all_napi(struct bnx2x *bp) ...@@ -863,7 +863,7 @@ static inline void bnx2x_del_all_napi(struct bnx2x *bp)
netif_napi_del(&bnx2x_fp(bp, i, napi)); netif_napi_del(&bnx2x_fp(bp, i, napi));
} }
void bnx2x_set_int_mode(struct bnx2x *bp); int bnx2x_set_int_mode(struct bnx2x *bp);
static inline void bnx2x_disable_msi(struct bnx2x *bp) static inline void bnx2x_disable_msi(struct bnx2x *bp)
{ {
......
...@@ -59,6 +59,8 @@ ...@@ -59,6 +59,8 @@
#include "bnx2x_init.h" #include "bnx2x_init.h"
#include "bnx2x_init_ops.h" #include "bnx2x_init_ops.h"
#include "bnx2x_cmn.h" #include "bnx2x_cmn.h"
#include "bnx2x_vfpf.h"
#include "bnx2x_sriov.h"
#include "bnx2x_dcb.h" #include "bnx2x_dcb.h"
#include "bnx2x_sp.h" #include "bnx2x_sp.h"
...@@ -133,39 +135,49 @@ enum bnx2x_board_type { ...@@ -133,39 +135,49 @@ enum bnx2x_board_type {
BCM57711E, BCM57711E,
BCM57712, BCM57712,
BCM57712_MF, BCM57712_MF,
BCM57712_VF,
BCM57800, BCM57800,
BCM57800_MF, BCM57800_MF,
BCM57800_VF,
BCM57810, BCM57810,
BCM57810_MF, BCM57810_MF,
BCM57840_O, BCM57810_VF,
BCM57840_4_10, BCM57840_4_10,
BCM57840_2_20, BCM57840_2_20,
BCM57840_MFO,
BCM57840_MF, BCM57840_MF,
BCM57840_VF,
BCM57811, BCM57811,
BCM57811_MF BCM57811_MF,
BCM57840_O,
BCM57840_MFO,
BCM57811_VF
}; };
/* indexed by board_type, above */ /* indexed by board_type, above */
static struct { static struct {
char *name; char *name;
} board_info[] = { } board_info[] = {
{ "Broadcom NetXtreme II BCM57710 10 Gigabit PCIe [Everest]" }, [BCM57710] = { "Broadcom NetXtreme II BCM57710 10 Gigabit PCIe [Everest]" },
{ "Broadcom NetXtreme II BCM57711 10 Gigabit PCIe" }, [BCM57711] = { "Broadcom NetXtreme II BCM57711 10 Gigabit PCIe" },
{ "Broadcom NetXtreme II BCM57711E 10 Gigabit PCIe" }, [BCM57711E] = { "Broadcom NetXtreme II BCM57711E 10 Gigabit PCIe" },
{ "Broadcom NetXtreme II BCM57712 10 Gigabit Ethernet" }, [BCM57712] = { "Broadcom NetXtreme II BCM57712 10 Gigabit Ethernet" },
{ "Broadcom NetXtreme II BCM57712 10 Gigabit Ethernet Multi Function" }, [BCM57712_MF] = { "Broadcom NetXtreme II BCM57712 10 Gigabit Ethernet Multi Function" },
{ "Broadcom NetXtreme II BCM57800 10 Gigabit Ethernet" }, [BCM57712_VF] = { "Broadcom NetXtreme II BCM57712 10 Gigabit Ethernet Virtual Function" },
{ "Broadcom NetXtreme II BCM57800 10 Gigabit Ethernet Multi Function" }, [BCM57800] = { "Broadcom NetXtreme II BCM57800 10 Gigabit Ethernet" },
{ "Broadcom NetXtreme II BCM57810 10 Gigabit Ethernet" }, [BCM57800_MF] = { "Broadcom NetXtreme II BCM57800 10 Gigabit Ethernet Multi Function" },
{ "Broadcom NetXtreme II BCM57810 10 Gigabit Ethernet Multi Function" }, [BCM57800_VF] = { "Broadcom NetXtreme II BCM57800 10 Gigabit Ethernet Virtual Function" },
{ "Broadcom NetXtreme II BCM57840 10/20 Gigabit Ethernet" }, [BCM57810] = { "Broadcom NetXtreme II BCM57810 10 Gigabit Ethernet" },
{ "Broadcom NetXtreme II BCM57840 10 Gigabit Ethernet" }, [BCM57810_MF] = { "Broadcom NetXtreme II BCM57810 10 Gigabit Ethernet Multi Function" },
{ "Broadcom NetXtreme II BCM57840 20 Gigabit Ethernet" }, [BCM57810_VF] = { "Broadcom NetXtreme II BCM57810 10 Gigabit Ethernet Virtual Function" },
{ "Broadcom NetXtreme II BCM57840 10/20 Gigabit Ethernet Multi Function"}, [BCM57840_4_10] = { "Broadcom NetXtreme II BCM57840 10 Gigabit Ethernet" },
{ "Broadcom NetXtreme II BCM57840 10/20 Gigabit Ethernet Multi Function"}, [BCM57840_2_20] = { "Broadcom NetXtreme II BCM57840 20 Gigabit Ethernet" },
{ "Broadcom NetXtreme II BCM57811 10 Gigabit Ethernet"}, [BCM57840_MF] = { "Broadcom NetXtreme II BCM57840 10/20 Gigabit Ethernet Multi Function" },
{ "Broadcom NetXtreme II BCM57811 10 Gigabit Ethernet Multi Function"}, [BCM57840_VF] = { "Broadcom NetXtreme II BCM57840 10/20 Gigabit Ethernet Virtual Function" },
[BCM57811] = { "Broadcom NetXtreme II BCM57811 10 Gigabit Ethernet" },
[BCM57811_MF] = { "Broadcom NetXtreme II BCM57811 10 Gigabit Ethernet Multi Function" },
[BCM57840_O] = { "Broadcom NetXtreme II BCM57840 10/20 Gigabit Ethernet" },
[BCM57840_MFO] = { "Broadcom NetXtreme II BCM57840 10/20 Gigabit Ethernet Multi Function" },
[BCM57811_VF] = { "Broadcom NetXtreme II BCM57840 10/20 Gigabit Ethernet Virtual Function" }
}; };
#ifndef PCI_DEVICE_ID_NX2_57710 #ifndef PCI_DEVICE_ID_NX2_57710
...@@ -7792,41 +7804,49 @@ int bnx2x_setup_leading(struct bnx2x *bp) ...@@ -7792,41 +7804,49 @@ int bnx2x_setup_leading(struct bnx2x *bp)
* *
* In case of MSI-X it will also try to enable MSI-X. * In case of MSI-X it will also try to enable MSI-X.
*/ */
void bnx2x_set_int_mode(struct bnx2x *bp) int bnx2x_set_int_mode(struct bnx2x *bp)
{ {
int rc = 0;
if (IS_VF(bp) && int_mode != BNX2X_INT_MODE_MSIX)
return -EINVAL;
switch (int_mode) { switch (int_mode) {
case INT_MODE_MSI: case BNX2X_INT_MODE_MSIX:
/* attempt to enable msix */
rc = bnx2x_enable_msix(bp);
/* msix attained */
if (!rc)
return 0;
/* vfs use only msix */
if (rc && IS_VF(bp))
return rc;
/* failed to enable multiple MSI-X */
BNX2X_DEV_INFO("Failed to enable multiple MSI-X (%d), set number of queues to %d\n",
bp->num_queues,
1 + bp->num_cnic_queues);
/* falling through... */
case BNX2X_INT_MODE_MSI:
bnx2x_enable_msi(bp); bnx2x_enable_msi(bp);
/* falling through... */ /* falling through... */
case INT_MODE_INTx: case BNX2X_INT_MODE_INTX:
bp->num_ethernet_queues = 1; bp->num_ethernet_queues = 1;
bp->num_queues = bp->num_ethernet_queues + bp->num_cnic_queues; bp->num_queues = bp->num_ethernet_queues + bp->num_cnic_queues;
BNX2X_DEV_INFO("set number of queues to 1\n"); BNX2X_DEV_INFO("set number of queues to 1\n");
break; break;
default: default:
/* if we can't use MSI-X we only need one fp, BNX2X_DEV_INFO("unknown value in int_mode module parameter\n");
* so try to enable MSI-X with the requested number of fp's return -EINVAL;
* and fallback to MSI or legacy INTx with one fp
*/
if (bnx2x_enable_msix(bp) ||
bp->flags & USING_SINGLE_MSIX_FLAG) {
/* failed to enable multiple MSI-X */
BNX2X_DEV_INFO("Failed to enable multiple MSI-X (%d), set number of queues to %d\n",
bp->num_queues,
1 + bp->num_cnic_queues);
bp->num_queues = 1 + bp->num_cnic_queues;
/* Try to enable MSI */
if (!(bp->flags & USING_SINGLE_MSIX_FLAG) &&
!(bp->flags & DISABLE_MSI_FLAG))
bnx2x_enable_msi(bp);
}
break;
} }
return 0;
} }
/* must be called prioir to any HW initializations */ /* must be called prior to any HW initializations */
static inline u16 bnx2x_cid_ilt_lines(struct bnx2x *bp) static inline u16 bnx2x_cid_ilt_lines(struct bnx2x *bp)
{ {
return L2_ILT_LINES(bp); return L2_ILT_LINES(bp);
...@@ -11081,9 +11101,13 @@ static int bnx2x_init_bp(struct bnx2x *bp) ...@@ -11081,9 +11101,13 @@ static int bnx2x_init_bp(struct bnx2x *bp)
INIT_DELAYED_WORK(&bp->sp_task, bnx2x_sp_task); INIT_DELAYED_WORK(&bp->sp_task, bnx2x_sp_task);
INIT_DELAYED_WORK(&bp->sp_rtnl_task, bnx2x_sp_rtnl_task); INIT_DELAYED_WORK(&bp->sp_rtnl_task, bnx2x_sp_rtnl_task);
INIT_DELAYED_WORK(&bp->period_task, bnx2x_period_task); INIT_DELAYED_WORK(&bp->period_task, bnx2x_period_task);
rc = bnx2x_get_hwinfo(bp); if (IS_PF(bp)) {
if (rc) rc = bnx2x_get_hwinfo(bp);
return rc; if (rc)
return rc;
} else {
random_ether_addr(bp->dev->dev_addr);
}
bnx2x_set_modes_bitmap(bp); bnx2x_set_modes_bitmap(bp);
...@@ -11096,7 +11120,7 @@ static int bnx2x_init_bp(struct bnx2x *bp) ...@@ -11096,7 +11120,7 @@ static int bnx2x_init_bp(struct bnx2x *bp)
func = BP_FUNC(bp); func = BP_FUNC(bp);
/* need to reset chip if undi was active */ /* need to reset chip if undi was active */
if (!BP_NOMCP(bp)) { if (IS_PF(bp) && !BP_NOMCP(bp)) {
/* init fw_seq */ /* init fw_seq */
bp->fw_seq = bp->fw_seq =
SHMEM_RD(bp, func_mb[BP_FW_MB_IDX(bp)].drv_mb_header) & SHMEM_RD(bp, func_mb[BP_FW_MB_IDX(bp)].drv_mb_header) &
...@@ -11133,6 +11157,8 @@ static int bnx2x_init_bp(struct bnx2x *bp) ...@@ -11133,6 +11157,8 @@ static int bnx2x_init_bp(struct bnx2x *bp)
bp->mrrs = mrrs; bp->mrrs = mrrs;
bp->tx_ring_size = IS_MF_FCOE_AFEX(bp) ? 0 : MAX_TX_AVAIL; bp->tx_ring_size = IS_MF_FCOE_AFEX(bp) ? 0 : MAX_TX_AVAIL;
if (IS_VF(bp))
bp->rx_ring_size = MAX_RX_AVAIL;
/* make sure that the numbers are in the right granularity */ /* make sure that the numbers are in the right granularity */
bp->tx_ticks = (50 / BNX2X_BTR) * BNX2X_BTR; bp->tx_ticks = (50 / BNX2X_BTR) * BNX2X_BTR;
...@@ -11161,12 +11187,18 @@ static int bnx2x_init_bp(struct bnx2x *bp) ...@@ -11161,12 +11187,18 @@ static int bnx2x_init_bp(struct bnx2x *bp)
bp->cnic_base_cl_id = FP_SB_MAX_E2; bp->cnic_base_cl_id = FP_SB_MAX_E2;
/* multiple tx priority */ /* multiple tx priority */
if (CHIP_IS_E1x(bp)) if (IS_VF(bp))
bp->max_cos = 1;
else if (CHIP_IS_E1x(bp))
bp->max_cos = BNX2X_MULTI_TX_COS_E1X; bp->max_cos = BNX2X_MULTI_TX_COS_E1X;
if (CHIP_IS_E2(bp) || CHIP_IS_E3A0(bp)) else if (CHIP_IS_E2(bp) || CHIP_IS_E3A0(bp))
bp->max_cos = BNX2X_MULTI_TX_COS_E2_E3A0; bp->max_cos = BNX2X_MULTI_TX_COS_E2_E3A0;
if (CHIP_IS_E3B0(bp)) else if (CHIP_IS_E3B0(bp))
bp->max_cos = BNX2X_MULTI_TX_COS_E3B0; bp->max_cos = BNX2X_MULTI_TX_COS_E3B0;
else
BNX2X_ERR("unknown chip %x revision %x\n",
CHIP_NUM(bp), CHIP_REV(bp));
BNX2X_DEV_INFO("set bp->max_cos to %d\n", bp->max_cos);
/* We need at least one default status block for slow-path events, /* We need at least one default status block for slow-path events,
* second status block for the L2 queue, and a third status block for * second status block for the L2 queue, and a third status block for
...@@ -11551,10 +11583,9 @@ static int bnx2x_set_coherency_mask(struct bnx2x *bp) ...@@ -11551,10 +11583,9 @@ static int bnx2x_set_coherency_mask(struct bnx2x *bp)
return 0; return 0;
} }
static int bnx2x_init_dev(struct pci_dev *pdev, struct net_device *dev, static int bnx2x_init_dev(struct bnx2x *bp, struct pci_dev *pdev,
unsigned long board_type) struct net_device *dev, unsigned long board_type)
{ {
struct bnx2x *bp;
int rc; int rc;
u32 pci_cfg_dword; u32 pci_cfg_dword;
bool chip_is_e1x = (board_type == BCM57710 || bool chip_is_e1x = (board_type == BCM57710 ||
...@@ -11562,11 +11593,9 @@ static int bnx2x_init_dev(struct pci_dev *pdev, struct net_device *dev, ...@@ -11562,11 +11593,9 @@ static int bnx2x_init_dev(struct pci_dev *pdev, struct net_device *dev,
board_type == BCM57711E); board_type == BCM57711E);
SET_NETDEV_DEV(dev, &pdev->dev); SET_NETDEV_DEV(dev, &pdev->dev);
bp = netdev_priv(dev);
bp->dev = dev; bp->dev = dev;
bp->pdev = pdev; bp->pdev = pdev;
bp->flags = 0;
rc = pci_enable_device(pdev); rc = pci_enable_device(pdev);
if (rc) { if (rc) {
...@@ -11582,9 +11611,8 @@ static int bnx2x_init_dev(struct pci_dev *pdev, struct net_device *dev, ...@@ -11582,9 +11611,8 @@ static int bnx2x_init_dev(struct pci_dev *pdev, struct net_device *dev,
goto err_out_disable; goto err_out_disable;
} }
if (!(pci_resource_flags(pdev, 2) & IORESOURCE_MEM)) { if (IS_PF(bp) && !(pci_resource_flags(pdev, 2) & IORESOURCE_MEM)) {
dev_err(&bp->pdev->dev, "Cannot find second PCI device" dev_err(&bp->pdev->dev, "Cannot find second PCI device base address, aborting\n");
" base address, aborting\n");
rc = -ENODEV; rc = -ENODEV;
goto err_out_disable; goto err_out_disable;
} }
...@@ -11609,12 +11637,14 @@ static int bnx2x_init_dev(struct pci_dev *pdev, struct net_device *dev, ...@@ -11609,12 +11637,14 @@ static int bnx2x_init_dev(struct pci_dev *pdev, struct net_device *dev,
pci_save_state(pdev); pci_save_state(pdev);
} }
bp->pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM); if (IS_PF(bp)) {
if (bp->pm_cap == 0) { bp->pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
dev_err(&bp->pdev->dev, if (bp->pm_cap == 0) {
"Cannot find power management capability, aborting\n"); dev_err(&bp->pdev->dev,
rc = -EIO; "Cannot find power management capability, aborting\n");
goto err_out_release; rc = -EIO;
goto err_out_release;
}
} }
if (!pci_is_pcie(pdev)) { if (!pci_is_pcie(pdev)) {
...@@ -11665,25 +11695,28 @@ static int bnx2x_init_dev(struct pci_dev *pdev, struct net_device *dev, ...@@ -11665,25 +11695,28 @@ static int bnx2x_init_dev(struct pci_dev *pdev, struct net_device *dev,
* Clean the following indirect addresses for all functions since it * Clean the following indirect addresses for all functions since it
* is not used by the driver. * is not used by the driver.
*/ */
REG_WR(bp, PXP2_REG_PGL_ADDR_88_F0, 0); if (IS_PF(bp)) {
REG_WR(bp, PXP2_REG_PGL_ADDR_8C_F0, 0); REG_WR(bp, PXP2_REG_PGL_ADDR_88_F0, 0);
REG_WR(bp, PXP2_REG_PGL_ADDR_90_F0, 0); REG_WR(bp, PXP2_REG_PGL_ADDR_8C_F0, 0);
REG_WR(bp, PXP2_REG_PGL_ADDR_94_F0, 0); REG_WR(bp, PXP2_REG_PGL_ADDR_90_F0, 0);
REG_WR(bp, PXP2_REG_PGL_ADDR_94_F0, 0);
if (chip_is_e1x) {
REG_WR(bp, PXP2_REG_PGL_ADDR_88_F1, 0);
REG_WR(bp, PXP2_REG_PGL_ADDR_8C_F1, 0);
REG_WR(bp, PXP2_REG_PGL_ADDR_90_F1, 0);
REG_WR(bp, PXP2_REG_PGL_ADDR_94_F1, 0);
}
if (chip_is_e1x) { /* Enable internal target-read (in case we are probed after PF
REG_WR(bp, PXP2_REG_PGL_ADDR_88_F1, 0); * FLR). Must be done prior to any BAR read access. Only for
REG_WR(bp, PXP2_REG_PGL_ADDR_8C_F1, 0); * 57712 and up
REG_WR(bp, PXP2_REG_PGL_ADDR_90_F1, 0); */
REG_WR(bp, PXP2_REG_PGL_ADDR_94_F1, 0); if (!chip_is_e1x)
REG_WR(bp,
PGLUE_B_REG_INTERNAL_PFID_ENABLE_TARGET_READ, 1);
} }
/*
* Enable internal target-read (in case we are probed after PF FLR).
* Must be done prior to any BAR read access. Only for 57712 and up
*/
if (!chip_is_e1x)
REG_WR(bp, PGLUE_B_REG_INTERNAL_PFID_ENABLE_TARGET_READ, 1);
dev->watchdog_timeo = TX_TIMEOUT; dev->watchdog_timeo = TX_TIMEOUT;
dev->netdev_ops = &bnx2x_netdev_ops; dev->netdev_ops = &bnx2x_netdev_ops;
...@@ -11734,8 +11767,9 @@ static int bnx2x_init_dev(struct pci_dev *pdev, struct net_device *dev, ...@@ -11734,8 +11767,9 @@ static int bnx2x_init_dev(struct pci_dev *pdev, struct net_device *dev,
static void bnx2x_get_pcie_width_speed(struct bnx2x *bp, int *width, int *speed) static void bnx2x_get_pcie_width_speed(struct bnx2x *bp, int *width, int *speed)
{ {
u32 val = REG_RD(bp, PCICFG_OFFSET + PCICFG_LINK_CONTROL); u32 val = 0;
pci_read_config_dword(bp->pdev, PCICFG_LINK_CONTROL, &val);
*width = (val & PCICFG_LINK_WIDTH) >> PCICFG_LINK_WIDTH_SHIFT; *width = (val & PCICFG_LINK_WIDTH) >> PCICFG_LINK_WIDTH_SHIFT;
/* return value of 1=2.5GHz 2=5GHz */ /* return value of 1=2.5GHz 2=5GHz */
...@@ -12012,10 +12046,10 @@ static int bnx2x_set_qm_cid_count(struct bnx2x *bp) ...@@ -12012,10 +12046,10 @@ static int bnx2x_set_qm_cid_count(struct bnx2x *bp)
* *
*/ */
static int bnx2x_get_num_non_def_sbs(struct pci_dev *pdev, static int bnx2x_get_num_non_def_sbs(struct pci_dev *pdev,
int cnic_cnt) int cnic_cnt, bool is_vf)
{ {
int pos; int pos, index;
u16 control; u16 control = 0;
pos = pci_find_capability(pdev, PCI_CAP_ID_MSIX); pos = pci_find_capability(pdev, PCI_CAP_ID_MSIX);
...@@ -12023,85 +12057,114 @@ static int bnx2x_get_num_non_def_sbs(struct pci_dev *pdev, ...@@ -12023,85 +12057,114 @@ static int bnx2x_get_num_non_def_sbs(struct pci_dev *pdev,
* If MSI-X is not supported - return number of SBs needed to support * If MSI-X is not supported - return number of SBs needed to support
* one fast path queue: one FP queue + SB for CNIC * one fast path queue: one FP queue + SB for CNIC
*/ */
if (!pos) if (!pos) {
dev_info(&pdev->dev, "no msix capability found\n");
return 1 + cnic_cnt; return 1 + cnic_cnt;
}
dev_info(&pdev->dev, "msix capability found\n");
/* /*
* The value in the PCI configuration space is the index of the last * The value in the PCI configuration space is the index of the last
* entry, namely one less than the actual size of the table, which is * entry, namely one less than the actual size of the table, which is
* exactly what we want to return from this function: number of all SBs * exactly what we want to return from this function: number of all SBs
* without the default SB. * without the default SB.
* For VFs there is no default SB, then we return (index+1).
*/ */
pci_read_config_word(pdev, pos + PCI_MSI_FLAGS, &control); pci_read_config_word(pdev, pos + PCI_MSI_FLAGS, &control);
return control & PCI_MSIX_FLAGS_QSIZE;
}
struct cnic_eth_dev *bnx2x_cnic_probe(struct net_device *); index = control & PCI_MSIX_FLAGS_QSIZE;
static int bnx2x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) return is_vf ? index + 1 : index;
{ }
struct net_device *dev = NULL;
struct bnx2x *bp;
int pcie_width, pcie_speed;
int rc, max_non_def_sbs;
int rx_count, tx_count, rss_count, doorbell_size;
int cnic_cnt;
/*
* An estimated maximum supported CoS number according to the chip
* version.
* We will try to roughly estimate the maximum number of CoSes this chip
* may support in order to minimize the memory allocated for Tx
* netdev_queue's. This number will be accurately calculated during the
* initialization of bp->max_cos based on the chip versions AND chip
* revision in the bnx2x_init_bp().
*/
u8 max_cos_est = 0;
switch (ent->driver_data) { static int set_max_cos_est(int chip_id)
{
switch (chip_id) {
case BCM57710: case BCM57710:
case BCM57711: case BCM57711:
case BCM57711E: case BCM57711E:
max_cos_est = BNX2X_MULTI_TX_COS_E1X; return BNX2X_MULTI_TX_COS_E1X;
break;
case BCM57712: case BCM57712:
case BCM57712_MF: case BCM57712_MF:
max_cos_est = BNX2X_MULTI_TX_COS_E2_E3A0; case BCM57712_VF:
break; return BNX2X_MULTI_TX_COS_E2_E3A0;
case BCM57800: case BCM57800:
case BCM57800_MF: case BCM57800_MF:
case BCM57800_VF:
case BCM57810: case BCM57810:
case BCM57810_MF: case BCM57810_MF:
case BCM57840_O:
case BCM57840_4_10: case BCM57840_4_10:
case BCM57840_2_20: case BCM57840_2_20:
case BCM57840_O:
case BCM57840_MFO: case BCM57840_MFO:
case BCM57810_VF:
case BCM57840_MF: case BCM57840_MF:
case BCM57840_VF:
case BCM57811: case BCM57811:
case BCM57811_MF: case BCM57811_MF:
max_cos_est = BNX2X_MULTI_TX_COS_E3B0; case BCM57811_VF:
break; return BNX2X_MULTI_TX_COS_E3B0;
return 1;
default: default:
pr_err("Unknown board_type (%ld), aborting\n", pr_err("Unknown board_type (%d), aborting\n", chip_id);
ent->driver_data);
return -ENODEV; return -ENODEV;
} }
}
cnic_cnt = 1; static int set_is_vf(int chip_id)
max_non_def_sbs = bnx2x_get_num_non_def_sbs(pdev, cnic_cnt); {
switch (chip_id) {
case BCM57712_VF:
case BCM57800_VF:
case BCM57810_VF:
case BCM57840_VF:
case BCM57811_VF:
return true;
default:
return false;
}
}
WARN_ON(!max_non_def_sbs); struct cnic_eth_dev *bnx2x_cnic_probe(struct net_device *dev);
static int bnx2x_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
struct net_device *dev = NULL;
struct bnx2x *bp;
int pcie_width, pcie_speed;
int rc, max_non_def_sbs;
int rx_count, tx_count, rss_count, doorbell_size;
int max_cos_est;
bool is_vf;
int cnic_cnt;
/* An estimated maximum supported CoS number according to the chip
* version.
* We will try to roughly estimate the maximum number of CoSes this chip
* may support in order to minimize the memory allocated for Tx
* netdev_queue's. This number will be accurately calculated during the
* initialization of bp->max_cos based on the chip versions AND chip
* revision in the bnx2x_init_bp().
*/
max_cos_est = set_max_cos_est(ent->driver_data);
if (max_cos_est < 0)
return max_cos_est;
is_vf = set_is_vf(ent->driver_data);
cnic_cnt = is_vf ? 0 : 1;
max_non_def_sbs = bnx2x_get_num_non_def_sbs(pdev, cnic_cnt, is_vf);
/* Maximum number of RSS queues: one IGU SB goes to CNIC */ /* Maximum number of RSS queues: one IGU SB goes to CNIC */
rss_count = max_non_def_sbs - cnic_cnt; rss_count = is_vf ? 1 : max_non_def_sbs - cnic_cnt;
if (rss_count < 1)
return -EINVAL;
/* Maximum number of netdev Rx queues: RSS + FCoE L2 */ /* Maximum number of netdev Rx queues: RSS + FCoE L2 */
rx_count = rss_count + cnic_cnt; rx_count = rss_count + cnic_cnt;
/* /* Maximum number of netdev Tx queues:
* Maximum number of netdev Tx queues:
* Maximum TSS queues * Maximum supported number of CoS + FCoE L2 * Maximum TSS queues * Maximum supported number of CoS + FCoE L2
*/ */
tx_count = rss_count * max_cos_est + cnic_cnt; tx_count = rss_count * max_cos_est + cnic_cnt;
...@@ -12113,22 +12176,28 @@ static int bnx2x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -12113,22 +12176,28 @@ static int bnx2x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
bp = netdev_priv(dev); bp = netdev_priv(dev);
bp->flags = 0;
if (is_vf)
bp->flags |= IS_VF_FLAG;
bp->igu_sb_cnt = max_non_def_sbs; bp->igu_sb_cnt = max_non_def_sbs;
bp->igu_base_addr = IS_VF(bp) ? PXP_VF_ADDR_IGU_START : BAR_IGU_INTMEM;
bp->msg_enable = debug; bp->msg_enable = debug;
bp->cnic_support = cnic_cnt; bp->cnic_support = cnic_cnt;
bp->cnic_probe = bnx2x_cnic_probe; bp->cnic_probe = bnx2x_cnic_probe;
pci_set_drvdata(pdev, dev); pci_set_drvdata(pdev, dev);
rc = bnx2x_init_dev(pdev, dev, ent->driver_data); rc = bnx2x_init_dev(bp, pdev, dev, ent->driver_data);
if (rc < 0) { if (rc < 0) {
free_netdev(dev); free_netdev(dev);
return rc; return rc;
} }
BNX2X_DEV_INFO("This is a %s function\n",
IS_PF(bp) ? "physical" : "virtual");
BNX2X_DEV_INFO("Cnic support is %s\n", CNIC_SUPPORT(bp) ? "on" : "off"); BNX2X_DEV_INFO("Cnic support is %s\n", CNIC_SUPPORT(bp) ? "on" : "off");
BNX2X_DEV_INFO("max_non_def_sbs %d\n", max_non_def_sbs); BNX2X_DEV_INFO("Max num of status blocks %d\n", max_non_def_sbs);
BNX2X_DEV_INFO("Allocated netdev with %d tx and %d rx queues\n", BNX2X_DEV_INFO("Allocated netdev with %d tx and %d rx queues\n",
tx_count, rx_count); tx_count, rx_count);
...@@ -12136,19 +12205,28 @@ static int bnx2x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -12136,19 +12205,28 @@ static int bnx2x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (rc) if (rc)
goto init_one_exit; goto init_one_exit;
/* /* Map doorbells here as we need the real value of bp->max_cos which
* Map doorbels here as we need the real value of bp->max_cos which * is initialized in bnx2x_init_bp() to determine the number of
* is initialized in bnx2x_init_bp(). * l2 connections.
*/ */
doorbell_size = BNX2X_L2_MAX_CID(bp) * (1 << BNX2X_DB_SHIFT); if (IS_VF(bp)) {
if (doorbell_size > pci_resource_len(pdev, 2)) { /* vf doorbells are embedded within the regview */
dev_err(&bp->pdev->dev, bp->doorbells = bp->regview + PXP_VF_ADDR_DB_START;
"Cannot map doorbells, bar size too small, aborting\n");
rc = -ENOMEM; /* allocate vf2pf mailbox for vf to pf channel */
goto init_one_exit; BNX2X_PCI_ALLOC(bp->vf2pf_mbox, &bp->vf2pf_mbox_mapping,
sizeof(struct bnx2x_vf_mbx_msg));
} else {
doorbell_size = BNX2X_L2_MAX_CID(bp) * (1 << BNX2X_DB_SHIFT);
if (doorbell_size > pci_resource_len(pdev, 2)) {
dev_err(&bp->pdev->dev,
"Cannot map doorbells, bar size too small, aborting\n");
rc = -ENOMEM;
goto init_one_exit;
}
bp->doorbells = ioremap_nocache(pci_resource_start(pdev, 2),
doorbell_size);
} }
bp->doorbells = ioremap_nocache(pci_resource_start(pdev, 2),
doorbell_size);
if (!bp->doorbells) { if (!bp->doorbells) {
dev_err(&bp->pdev->dev, dev_err(&bp->pdev->dev,
"Cannot map doorbell space, aborting\n"); "Cannot map doorbell space, aborting\n");
...@@ -12158,6 +12236,7 @@ static int bnx2x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -12158,6 +12236,7 @@ static int bnx2x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
/* calc qm_cid_count */ /* calc qm_cid_count */
bp->qm_cid_count = bnx2x_set_qm_cid_count(bp); bp->qm_cid_count = bnx2x_set_qm_cid_count(bp);
BNX2X_DEV_INFO("qm_cid_count %d\n", bp->qm_cid_count);
/* disable FCOE L2 queue for E1x*/ /* disable FCOE L2 queue for E1x*/
if (CHIP_IS_E1x(bp)) if (CHIP_IS_E1x(bp))
...@@ -12179,13 +12258,19 @@ static int bnx2x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -12179,13 +12258,19 @@ static int bnx2x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
/* Configure interrupt mode: try to enable MSI-X/MSI if /* Configure interrupt mode: try to enable MSI-X/MSI if
* needed. * needed.
*/ */
bnx2x_set_int_mode(bp); rc = bnx2x_set_int_mode(bp);
if (rc) {
dev_err(&pdev->dev, "Cannot set interrupts\n");
goto init_one_exit;
}
/* register the net device */
rc = register_netdev(dev); rc = register_netdev(dev);
if (rc) { if (rc) {
dev_err(&pdev->dev, "Cannot register net device\n"); dev_err(&pdev->dev, "Cannot register net device\n");
goto init_one_exit; goto init_one_exit;
} }
BNX2X_DEV_INFO("device name after netdev register %s\n", dev->name);
if (!NO_FCOE(bp)) { if (!NO_FCOE(bp)) {
...@@ -12196,6 +12281,8 @@ static int bnx2x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -12196,6 +12281,8 @@ static int bnx2x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
} }
bnx2x_get_pcie_width_speed(bp, &pcie_width, &pcie_speed); bnx2x_get_pcie_width_speed(bp, &pcie_width, &pcie_speed);
BNX2X_DEV_INFO("got pcie width %d and speed %d\n",
pcie_width, pcie_speed);
BNX2X_DEV_INFO( BNX2X_DEV_INFO(
"%s (%c%d) PCI-E x%d %s found at mem %lx, IRQ %d, node addr %pM\n", "%s (%c%d) PCI-E x%d %s found at mem %lx, IRQ %d, node addr %pM\n",
...@@ -12209,11 +12296,16 @@ static int bnx2x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -12209,11 +12296,16 @@ static int bnx2x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
return 0; return 0;
alloc_mem_err:
BNX2X_PCI_FREE(bp->vf2pf_mbox, bp->vf2pf_mbox_mapping,
sizeof(struct bnx2x_vf_mbx_msg));
rc = -ENOMEM;
init_one_exit: init_one_exit:
if (bp->regview) if (bp->regview)
iounmap(bp->regview); iounmap(bp->regview);
if (bp->doorbells) if (IS_PF(bp) && bp->doorbells)
iounmap(bp->doorbells); iounmap(bp->doorbells);
free_netdev(dev); free_netdev(dev);
...@@ -12253,13 +12345,15 @@ static void bnx2x_remove_one(struct pci_dev *pdev) ...@@ -12253,13 +12345,15 @@ static void bnx2x_remove_one(struct pci_dev *pdev)
unregister_netdev(dev); unregister_netdev(dev);
/* Power on: we can't let PCI layer write to us while we are in D3 */ /* Power on: we can't let PCI layer write to us while we are in D3 */
bnx2x_set_power_state(bp, PCI_D0); if (IS_PF(bp))
bnx2x_set_power_state(bp, PCI_D0);
/* Disable MSI/MSI-X */ /* Disable MSI/MSI-X */
bnx2x_disable_msi(bp); bnx2x_disable_msi(bp);
/* Power off */ /* Power off */
bnx2x_set_power_state(bp, PCI_D3hot); if (IS_PF(bp))
bnx2x_set_power_state(bp, PCI_D3hot);
/* Make sure RESET task is not scheduled before continuing */ /* Make sure RESET task is not scheduled before continuing */
cancel_delayed_work_sync(&bp->sp_rtnl_task); cancel_delayed_work_sync(&bp->sp_rtnl_task);
...@@ -12267,11 +12361,15 @@ static void bnx2x_remove_one(struct pci_dev *pdev) ...@@ -12267,11 +12361,15 @@ static void bnx2x_remove_one(struct pci_dev *pdev)
if (bp->regview) if (bp->regview)
iounmap(bp->regview); iounmap(bp->regview);
if (bp->doorbells) /* for vf doorbells are part of the regview and were unmapped along with
iounmap(bp->doorbells); * it. FW is only loaded by PF.
*/
bnx2x_release_firmware(bp); if (IS_PF(bp)) {
if (bp->doorbells)
iounmap(bp->doorbells);
bnx2x_release_firmware(bp);
}
bnx2x_free_mem_bp(bp); bnx2x_free_mem_bp(bp);
free_netdev(dev); free_netdev(dev);
......
...@@ -6554,6 +6554,15 @@ ...@@ -6554,6 +6554,15 @@
(7L<<ME_REG_ABS_PF_NUM_SHIFT) /* Absolute PF Num */ (7L<<ME_REG_ABS_PF_NUM_SHIFT) /* Absolute PF Num */
#define PXP_VF_ADDR_IGU_START 0
#define PXP_VF_ADDR_IGU_SIZE 0x3000
#define PXP_VF_ADDR_IGU_END\
((PXP_VF_ADDR_IGU_START) + (PXP_VF_ADDR_IGU_SIZE) - 1)
#define PXP_VF_ADDR_DB_START 0x7c00
#define PXP_VF_ADDR_DB_SIZE 0x200
#define PXP_VF_ADDR_DB_END\
((PXP_VF_ADDR_DB_START) + (PXP_VF_ADDR_DB_SIZE) - 1)
#define MDIO_REG_BANK_CL73_IEEEB0 0x0 #define MDIO_REG_BANK_CL73_IEEEB0 0x0
#define MDIO_CL73_IEEEB0_CL73_AN_CONTROL 0x0 #define MDIO_CL73_IEEEB0_CL73_AN_CONTROL 0x0
#define MDIO_CL73_IEEEB0_CL73_AN_CONTROL_RESTART_AN 0x0200 #define MDIO_CL73_IEEEB0_CL73_AN_CONTROL_RESTART_AN 0x0200
......
/* bnx2x_sriov.h: Broadcom Everest network driver.
*
* Copyright 2009-2012 Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2, available
* at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL").
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a
* license other than the GPL, without Broadcom's express prior written
* consent.
*
* Maintained by: Eilon Greenstein <eilong@broadcom.com>
* Written by: Shmulik Ravid <shmulikr@broadcom.com>
* Ariel Elior <ariele@broadcom.com>
*/
#ifndef BNX2X_SRIOV_H
#define BNX2X_SRIOV_H
struct bnx2x_vf_mbx_msg {
union vfpf_tlvs req;
union pfvf_tlvs resp;
};
#endif /* bnx2x_sriov.h */
/* bnx2x_vfpf.h: Broadcom Everest network driver.
*
* Copyright (c) 2011-2012 Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2, available
* at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL").
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a
* license other than the GPL, without Broadcom's express prior written
* consent.
*
* Maintained by: Eilon Greenstein <eilong@broadcom.com>
* Written by: Ariel Elior <ariele@broadcom.com>
*/
#ifndef VF_PF_IF_H
#define VF_PF_IF_H
/* HW VF-PF channel definitions
* A.K.A VF-PF mailbox
*/
#define TLV_BUFFER_SIZE 1024
struct tlv_buffer_size {
u8 tlv_buffer[TLV_BUFFER_SIZE];
};
union vfpf_tlvs {
struct tlv_buffer_size tlv_buf_size;
};
union pfvf_tlvs {
struct tlv_buffer_size tlv_buf_size;
};
#endif /* VF_PF_IF_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment