Commit 32a47e72 authored by Yuval Mintz's avatar Yuval Mintz Committed by David S. Miller

qed: Add CONFIG_QED_SRIOV

Add support for a new Kconfig option for qed* driver which would allow
[eventually] the support in VFs.

This patch adds the necessary logic in the PF to learn about the possible
VFs it will have to support [Based on PCI configuration space and HW],
and prepare a database with an entry per-VF as infrastructure for future
interaction with said VFs.
Signed-off-by: default avatarYuval Mintz <Yuval.Mintz@qlogic.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 631ad4a3
...@@ -98,6 +98,16 @@ config QED ...@@ -98,6 +98,16 @@ config QED
---help--- ---help---
This enables the support for ... This enables the support for ...
config QED_SRIOV
bool "QLogic QED 25/40/100Gb SR-IOV support"
depends on QED && PCI_IOV
default y
---help---
This configuration parameter enables Single Root Input Output
Virtualization support for QED devices.
This allows for virtual function acceleration in virtualized
environments.
config QEDE config QEDE
tristate "QLogic QED 25/40/100Gb Ethernet NIC" tristate "QLogic QED 25/40/100Gb Ethernet NIC"
depends on QED depends on QED
......
...@@ -3,3 +3,4 @@ obj-$(CONFIG_QED) := qed.o ...@@ -3,3 +3,4 @@ obj-$(CONFIG_QED) := qed.o
qed-y := qed_cxt.o qed_dev.o qed_hw.o qed_init_fw_funcs.o qed_init_ops.o \ qed-y := qed_cxt.o qed_dev.o qed_hw.o qed_init_fw_funcs.o qed_init_ops.o \
qed_int.o qed_main.o qed_mcp.o qed_sp_commands.o qed_spq.o qed_l2.o \ qed_int.o qed_main.o qed_mcp.o qed_sp_commands.o qed_spq.o qed_l2.o \
qed_selftest.o qed_selftest.o
qed-$(CONFIG_QED_SRIOV) += qed_sriov.o
...@@ -152,6 +152,7 @@ enum QED_RESOURCES { ...@@ -152,6 +152,7 @@ enum QED_RESOURCES {
enum QED_FEATURE { enum QED_FEATURE {
QED_PF_L2_QUE, QED_PF_L2_QUE,
QED_VF,
QED_MAX_FEATURES, QED_MAX_FEATURES,
}; };
...@@ -360,6 +361,7 @@ struct qed_hwfn { ...@@ -360,6 +361,7 @@ struct qed_hwfn {
/* True if the driver requests for the link */ /* True if the driver requests for the link */
bool b_drv_link_init; bool b_drv_link_init;
struct qed_pf_iov *pf_iov_info;
struct qed_mcp_info *mcp_info; struct qed_mcp_info *mcp_info;
struct qed_hw_cid_data *p_tx_cids; struct qed_hw_cid_data *p_tx_cids;
...@@ -484,6 +486,10 @@ struct qed_dev { ...@@ -484,6 +486,10 @@ struct qed_dev {
u8 num_hwfns; u8 num_hwfns;
struct qed_hwfn hwfns[MAX_HWFNS_PER_DEVICE]; struct qed_hwfn hwfns[MAX_HWFNS_PER_DEVICE];
/* SRIOV */
struct qed_hw_sriov_info *p_iov_info;
#define IS_QED_SRIOV(cdev) (!!(cdev)->p_iov_info)
unsigned long tunn_mode; unsigned long tunn_mode;
u32 drv_type; u32 drv_type;
...@@ -514,6 +520,7 @@ struct qed_dev { ...@@ -514,6 +520,7 @@ struct qed_dev {
const struct firmware *firmware; const struct firmware *firmware;
}; };
#define NUM_OF_VFS(dev) MAX_NUM_VFS_BB
#define NUM_OF_SBS(dev) MAX_SB_PER_PATH_BB #define NUM_OF_SBS(dev) MAX_SB_PER_PATH_BB
#define NUM_OF_ENG_PFS(dev) MAX_NUM_PFS_BB #define NUM_OF_ENG_PFS(dev) MAX_NUM_PFS_BB
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include "qed_mcp.h" #include "qed_mcp.h"
#include "qed_reg_addr.h" #include "qed_reg_addr.h"
#include "qed_sp.h" #include "qed_sp.h"
#include "qed_sriov.h"
/* API common to all protocols */ /* API common to all protocols */
enum BAR_ID { enum BAR_ID {
...@@ -136,6 +137,7 @@ void qed_resc_free(struct qed_dev *cdev) ...@@ -136,6 +137,7 @@ void qed_resc_free(struct qed_dev *cdev)
qed_eq_free(p_hwfn, p_hwfn->p_eq); qed_eq_free(p_hwfn, p_hwfn->p_eq);
qed_consq_free(p_hwfn, p_hwfn->p_consq); qed_consq_free(p_hwfn, p_hwfn->p_consq);
qed_int_free(p_hwfn); qed_int_free(p_hwfn);
qed_iov_free(p_hwfn);
qed_dmae_info_free(p_hwfn); qed_dmae_info_free(p_hwfn);
} }
} }
...@@ -316,6 +318,10 @@ int qed_resc_alloc(struct qed_dev *cdev) ...@@ -316,6 +318,10 @@ int qed_resc_alloc(struct qed_dev *cdev)
if (rc) if (rc)
goto alloc_err; goto alloc_err;
rc = qed_iov_alloc(p_hwfn);
if (rc)
goto alloc_err;
/* EQ */ /* EQ */
p_eq = qed_eq_alloc(p_hwfn, 256); p_eq = qed_eq_alloc(p_hwfn, 256);
if (!p_eq) { if (!p_eq) {
...@@ -373,6 +379,8 @@ void qed_resc_setup(struct qed_dev *cdev) ...@@ -373,6 +379,8 @@ void qed_resc_setup(struct qed_dev *cdev)
p_hwfn->mcp_info->mfw_mb_length); p_hwfn->mcp_info->mfw_mb_length);
qed_int_setup(p_hwfn, p_hwfn->p_main_ptt); qed_int_setup(p_hwfn, p_hwfn->p_main_ptt);
qed_iov_setup(p_hwfn, p_hwfn->p_main_ptt);
} }
} }
...@@ -1238,6 +1246,13 @@ qed_get_hw_info(struct qed_hwfn *p_hwfn, ...@@ -1238,6 +1246,13 @@ qed_get_hw_info(struct qed_hwfn *p_hwfn,
u32 port_mode; u32 port_mode;
int rc; int rc;
/* Since all information is common, only first hwfns should do this */
if (IS_LEAD_HWFN(p_hwfn)) {
rc = qed_iov_hw_info(p_hwfn);
if (rc)
return rc;
}
/* Read the port mode */ /* Read the port mode */
port_mode = qed_rd(p_hwfn, p_ptt, port_mode = qed_rd(p_hwfn, p_ptt,
CNIG_REG_NW_PORT_MODE_BB_B0); CNIG_REG_NW_PORT_MODE_BB_B0);
...@@ -1397,6 +1412,8 @@ static int qed_hw_prepare_single(struct qed_hwfn *p_hwfn, ...@@ -1397,6 +1412,8 @@ static int qed_hw_prepare_single(struct qed_hwfn *p_hwfn,
return rc; return rc;
err2: err2:
if (IS_LEAD_HWFN(p_hwfn))
qed_iov_free_hw_info(p_hwfn->cdev);
qed_mcp_free(p_hwfn); qed_mcp_free(p_hwfn);
err1: err1:
qed_hw_hwfn_free(p_hwfn); qed_hw_hwfn_free(p_hwfn);
...@@ -1463,6 +1480,8 @@ void qed_hw_remove(struct qed_dev *cdev) ...@@ -1463,6 +1480,8 @@ void qed_hw_remove(struct qed_dev *cdev)
qed_hw_hwfn_free(p_hwfn); qed_hw_hwfn_free(p_hwfn);
qed_mcp_free(p_hwfn); qed_mcp_free(p_hwfn);
} }
qed_iov_free_hw_info(cdev);
} }
int qed_chain_alloc(struct qed_dev *cdev, int qed_chain_alloc(struct qed_dev *cdev,
......
...@@ -338,6 +338,17 @@ void qed_port_unpretend(struct qed_hwfn *p_hwfn, ...@@ -338,6 +338,17 @@ void qed_port_unpretend(struct qed_hwfn *p_hwfn,
*(u32 *)&p_ptt->pxp.pretend); *(u32 *)&p_ptt->pxp.pretend);
} }
u32 qed_vfid_to_concrete(struct qed_hwfn *p_hwfn, u8 vfid)
{
u32 concrete_fid = 0;
SET_FIELD(concrete_fid, PXP_CONCRETE_FID_PFID, p_hwfn->rel_pf_id);
SET_FIELD(concrete_fid, PXP_CONCRETE_FID_VFID, vfid);
SET_FIELD(concrete_fid, PXP_CONCRETE_FID_VFVALID, 1);
return concrete_fid;
}
/* DMAE */ /* DMAE */
static void qed_dmae_opcode(struct qed_hwfn *p_hwfn, static void qed_dmae_opcode(struct qed_hwfn *p_hwfn,
const u8 is_src_type_grc, const u8 is_src_type_grc,
......
...@@ -220,6 +220,16 @@ void qed_port_pretend(struct qed_hwfn *p_hwfn, ...@@ -220,6 +220,16 @@ void qed_port_pretend(struct qed_hwfn *p_hwfn,
void qed_port_unpretend(struct qed_hwfn *p_hwfn, void qed_port_unpretend(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt); struct qed_ptt *p_ptt);
/**
* @brief qed_vfid_to_concrete - build a concrete FID for a
* given VF ID
*
* @param p_hwfn
* @param p_ptt
* @param vfid
*/
u32 qed_vfid_to_concrete(struct qed_hwfn *p_hwfn, u8 vfid);
/** /**
* @brief qed_dmae_idx_to_go_cmd - map the idx to dmae cmd * @brief qed_dmae_idx_to_go_cmd - map the idx to dmae cmd
* this is declared here since other files will require it. * this is declared here since other files will require it.
......
This diff is collapsed.
/* QLogic qed NIC Driver
* Copyright (c) 2015 QLogic Corporation
*
* This software is available under the terms of the GNU General Public License
* (GPL) Version 2, available from the file COPYING in the main directory of
* this source tree.
*/
#ifndef _QED_SRIOV_H
#define _QED_SRIOV_H
#include <linux/types.h>
#include "qed_vf.h"
#define QED_VF_ARRAY_LENGTH (3)
#define IS_VF(cdev) ((cdev)->b_is_vf)
#define IS_PF(cdev) (!((cdev)->b_is_vf))
#ifdef CONFIG_QED_SRIOV
#define IS_PF_SRIOV(p_hwfn) (!!((p_hwfn)->cdev->p_iov_info))
#else
#define IS_PF_SRIOV(p_hwfn) (0)
#endif
#define IS_PF_SRIOV_ALLOC(p_hwfn) (!!((p_hwfn)->pf_iov_info))
/* This struct is part of qed_dev and contains data relevant to all hwfns;
* Initialized only if SR-IOV cpabability is exposed in PCIe config space.
*/
struct qed_hw_sriov_info {
int pos; /* capability position */
int nres; /* number of resources */
u32 cap; /* SR-IOV Capabilities */
u16 ctrl; /* SR-IOV Control */
u16 total_vfs; /* total VFs associated with the PF */
u16 num_vfs; /* number of vfs that have been started */
u16 initial_vfs; /* initial VFs associated with the PF */
u16 nr_virtfn; /* number of VFs available */
u16 offset; /* first VF Routing ID offset */
u16 stride; /* following VF stride */
u16 vf_device_id; /* VF device id */
u32 pgsz; /* page size for BAR alignment */
u8 link; /* Function Dependency Link */
u32 first_vf_in_pf;
};
/* This mailbox is maintained per VF in its PF contains all information
* required for sending / receiving a message.
*/
struct qed_iov_vf_mbx {
union vfpf_tlvs *req_virt;
dma_addr_t req_phys;
union pfvf_tlvs *reply_virt;
dma_addr_t reply_phys;
};
enum vf_state {
VF_STOPPED /* VF, Stopped */
};
/* PFs maintain an array of this structure, per VF */
struct qed_vf_info {
struct qed_iov_vf_mbx vf_mbx;
enum vf_state state;
bool b_init;
struct qed_bulletin bulletin;
dma_addr_t vf_bulletin;
u32 concrete_fid;
u16 opaque_fid;
u8 vport_id;
u8 relative_vf_id;
u8 abs_vf_id;
#define QED_VF_ABS_ID(p_hwfn, p_vf) (QED_PATH_ID(p_hwfn) ? \
(p_vf)->abs_vf_id + MAX_NUM_VFS_BB : \
(p_vf)->abs_vf_id)
};
/* This structure is part of qed_hwfn and used only for PFs that have sriov
* capability enabled.
*/
struct qed_pf_iov {
struct qed_vf_info vfs_array[MAX_NUM_VFS];
u64 pending_events[QED_VF_ARRAY_LENGTH];
u64 pending_flr[QED_VF_ARRAY_LENGTH];
/* Allocate message address continuosuly and split to each VF */
void *mbx_msg_virt_addr;
dma_addr_t mbx_msg_phys_addr;
u32 mbx_msg_size;
void *mbx_reply_virt_addr;
dma_addr_t mbx_reply_phys_addr;
u32 mbx_reply_size;
void *p_bulletins;
dma_addr_t bulletins_phys;
u32 bulletins_size;
};
#ifdef CONFIG_QED_SRIOV
/**
* @brief - Given a VF index, return index of next [including that] active VF.
*
* @param p_hwfn
* @param rel_vf_id
*
* @return MAX_NUM_VFS in case no further active VFs, otherwise index.
*/
u16 qed_iov_get_next_active_vf(struct qed_hwfn *p_hwfn, u16 rel_vf_id);
/**
* @brief Read sriov related information and allocated resources
* reads from configuraiton space, shmem, etc.
*
* @param p_hwfn
*
* @return int
*/
int qed_iov_hw_info(struct qed_hwfn *p_hwfn);
/**
* @brief qed_iov_alloc - allocate sriov related resources
*
* @param p_hwfn
*
* @return int
*/
int qed_iov_alloc(struct qed_hwfn *p_hwfn);
/**
* @brief qed_iov_setup - setup sriov related resources
*
* @param p_hwfn
* @param p_ptt
*/
void qed_iov_setup(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt);
/**
* @brief qed_iov_free - free sriov related resources
*
* @param p_hwfn
*/
void qed_iov_free(struct qed_hwfn *p_hwfn);
/**
* @brief free sriov related memory that was allocated during hw_prepare
*
* @param cdev
*/
void qed_iov_free_hw_info(struct qed_dev *cdev);
#else
static inline u16 qed_iov_get_next_active_vf(struct qed_hwfn *p_hwfn,
u16 rel_vf_id)
{
return MAX_NUM_VFS;
}
static inline int qed_iov_hw_info(struct qed_hwfn *p_hwfn)
{
return 0;
}
static inline int qed_iov_alloc(struct qed_hwfn *p_hwfn)
{
return 0;
}
static inline void qed_iov_setup(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
{
}
static inline void qed_iov_free(struct qed_hwfn *p_hwfn)
{
}
static inline void qed_iov_free_hw_info(struct qed_dev *cdev)
{
}
#endif
#define qed_for_each_vf(_p_hwfn, _i) \
for (_i = qed_iov_get_next_active_vf(_p_hwfn, 0); \
_i < MAX_NUM_VFS; \
_i = qed_iov_get_next_active_vf(_p_hwfn, _i + 1))
#endif
/* QLogic qed NIC Driver
* Copyright (c) 2015 QLogic Corporation
*
* This software is available under the terms of the GNU General Public License
* (GPL) Version 2, available from the file COPYING in the main directory of
* this source tree.
*/
#ifndef _QED_VF_H
#define _QED_VF_H
#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;
};
struct qed_bulletin_content {
/* crc of structure to ensure is not in mid-update */
u32 crc;
u32 version;
/* bitmap indicating which fields hold valid values */
u64 valid_bitmap;
};
struct qed_bulletin {
dma_addr_t phys;
struct qed_bulletin_content *p_virt;
u32 size;
};
#endif
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