Commit c1a9f80e authored by David S. Miller's avatar David S. Miller

Merge branch 'qed-vf-tunnel'

Manish Chopra says:

====================
qed/qede: VF tunnelling support

With this series VFs can run vxlan/geneve/gre tunnels over it.
Please consider applying this series to "net-next"
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 36784277 eaf3c0c6
......@@ -149,9 +149,35 @@ enum qed_tunn_clss {
QED_TUNN_CLSS_MAC_VNI,
QED_TUNN_CLSS_INNER_MAC_VLAN,
QED_TUNN_CLSS_INNER_MAC_VNI,
QED_TUNN_CLSS_MAC_VLAN_DUAL_STAGE,
MAX_QED_TUNN_CLSS,
};
struct qed_tunn_update_type {
bool b_update_mode;
bool b_mode_enabled;
enum qed_tunn_clss tun_cls;
};
struct qed_tunn_update_udp_port {
bool b_update_port;
u16 port;
};
struct qed_tunnel_info {
struct qed_tunn_update_type vxlan;
struct qed_tunn_update_type l2_geneve;
struct qed_tunn_update_type ip_geneve;
struct qed_tunn_update_type l2_gre;
struct qed_tunn_update_type ip_gre;
struct qed_tunn_update_udp_port vxlan_port;
struct qed_tunn_update_udp_port geneve_port;
bool b_update_rx_cls;
bool b_update_tx_cls;
};
struct qed_tunn_start_params {
unsigned long tunn_mode;
u16 vxlan_udp_port;
......@@ -648,9 +674,7 @@ struct qed_dev {
/* SRIOV */
struct qed_hw_sriov_info *p_iov_info;
#define IS_QED_SRIOV(cdev) (!!(cdev)->p_iov_info)
unsigned long tunn_mode;
struct qed_tunnel_info tunnel;
bool b_is_vf;
u32 drv_type;
struct qed_eth_stats *reset_stats;
......@@ -694,6 +718,7 @@ struct qed_dev {
u32 rdma_max_sge;
u32 rdma_max_inline;
u32 rdma_max_srq_sge;
u16 tunn_feature_mask;
};
#define NUM_OF_VFS(dev) (QED_IS_BB(dev) ? MAX_NUM_VFS_BB \
......
......@@ -1453,7 +1453,7 @@ static int qed_hw_init_port(struct qed_hwfn *p_hwfn,
static int qed_hw_init_pf(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
struct qed_tunn_start_params *p_tunn,
struct qed_tunnel_info *p_tunn,
int hw_mode,
bool b_hw_start,
enum qed_int_mode int_mode,
......@@ -1594,6 +1594,19 @@ qed_fill_load_req_params(struct qed_load_req_params *p_load_req,
p_load_req->override_force_load = p_drv_load->override_force_load;
}
static int qed_vf_start(struct qed_hwfn *p_hwfn,
struct qed_hw_init_params *p_params)
{
if (p_params->p_tunn) {
qed_vf_set_vf_start_tunn_update_param(p_params->p_tunn);
qed_vf_pf_tunnel_param_update(p_hwfn, p_params->p_tunn);
}
p_hwfn->b_int_enabled = 1;
return 0;
}
int qed_hw_init(struct qed_dev *cdev, struct qed_hw_init_params *p_params)
{
struct qed_load_req_params load_req_params;
......@@ -1623,7 +1636,7 @@ int qed_hw_init(struct qed_dev *cdev, struct qed_hw_init_params *p_params)
}
if (IS_VF(cdev)) {
p_hwfn->b_int_enabled = 1;
qed_vf_start(p_hwfn, p_params);
continue;
}
......
......@@ -113,7 +113,7 @@ struct qed_drv_load_params {
struct qed_hw_init_params {
/* Tunneling parameters */
struct qed_tunn_start_params *p_tunn;
struct qed_tunnel_info *p_tunn;
bool b_hw_start;
......
......@@ -2285,31 +2285,46 @@ static int qed_stop_txq(struct qed_dev *cdev, u8 rss_id, void *handle)
static int qed_tunn_configure(struct qed_dev *cdev,
struct qed_tunn_params *tunn_params)
{
struct qed_tunn_update_params tunn_info;
struct qed_tunnel_info tunn_info;
int i, rc;
if (IS_VF(cdev))
return 0;
memset(&tunn_info, 0, sizeof(tunn_info));
if (tunn_params->update_vxlan_port == 1) {
tunn_info.update_vxlan_udp_port = 1;
tunn_info.vxlan_udp_port = tunn_params->vxlan_port;
if (tunn_params->update_vxlan_port) {
tunn_info.vxlan_port.b_update_port = true;
tunn_info.vxlan_port.port = tunn_params->vxlan_port;
}
if (tunn_params->update_geneve_port == 1) {
tunn_info.update_geneve_udp_port = 1;
tunn_info.geneve_udp_port = tunn_params->geneve_port;
if (tunn_params->update_geneve_port) {
tunn_info.geneve_port.b_update_port = true;
tunn_info.geneve_port.port = tunn_params->geneve_port;
}
for_each_hwfn(cdev, i) {
struct qed_hwfn *hwfn = &cdev->hwfns[i];
struct qed_tunnel_info *tun;
tun = &hwfn->cdev->tunnel;
rc = qed_sp_pf_update_tunn_cfg(hwfn, &tunn_info,
QED_SPQ_MODE_EBLOCK, NULL);
if (rc)
return rc;
if (IS_PF_SRIOV(hwfn)) {
u16 vxlan_port, geneve_port;
int j;
vxlan_port = tun->vxlan_port.port;
geneve_port = tun->geneve_port.port;
qed_for_each_vf(hwfn, j) {
qed_iov_bulletin_set_udp_ports(hwfn, j,
vxlan_port,
geneve_port);
}
qed_schedule_iov(hwfn, QED_IOV_WQ_BULLETIN_UPDATE_FLAG);
}
}
return 0;
......
......@@ -230,10 +230,25 @@ static int qed_init_pci(struct qed_dev *cdev, struct pci_dev *pdev)
int qed_fill_dev_info(struct qed_dev *cdev,
struct qed_dev_info *dev_info)
{
struct qed_tunnel_info *tun = &cdev->tunnel;
struct qed_ptt *ptt;
memset(dev_info, 0, sizeof(struct qed_dev_info));
if (tun->vxlan.tun_cls == QED_TUNN_CLSS_MAC_VLAN &&
tun->vxlan.b_mode_enabled)
dev_info->vxlan_enable = true;
if (tun->l2_gre.b_mode_enabled && tun->ip_gre.b_mode_enabled &&
tun->l2_gre.tun_cls == QED_TUNN_CLSS_MAC_VLAN &&
tun->ip_gre.tun_cls == QED_TUNN_CLSS_MAC_VLAN)
dev_info->gre_enable = true;
if (tun->l2_geneve.b_mode_enabled && tun->ip_geneve.b_mode_enabled &&
tun->l2_geneve.tun_cls == QED_TUNN_CLSS_MAC_VLAN &&
tun->ip_geneve.tun_cls == QED_TUNN_CLSS_MAC_VLAN)
dev_info->geneve_enable = true;
dev_info->num_hwfns = cdev->num_hwfns;
dev_info->pci_mem_start = cdev->pci_params.mem_start;
dev_info->pci_mem_end = cdev->pci_params.mem_end;
......@@ -909,8 +924,8 @@ static int qed_slowpath_start(struct qed_dev *cdev,
{
struct qed_drv_load_params drv_load_params;
struct qed_hw_init_params hw_init_params;
struct qed_tunn_start_params tunn_info;
struct qed_mcp_drv_version drv_version;
struct qed_tunnel_info tunn_info;
const u8 *data = NULL;
struct qed_hwfn *hwfn;
struct qed_ptt *p_ptt;
......@@ -974,19 +989,19 @@ static int qed_slowpath_start(struct qed_dev *cdev,
qed_dbg_pf_init(cdev);
}
memset(&tunn_info, 0, sizeof(tunn_info));
tunn_info.tunn_mode |= 1 << QED_MODE_VXLAN_TUNN |
1 << QED_MODE_L2GRE_TUNN |
1 << QED_MODE_IPGRE_TUNN |
1 << QED_MODE_L2GENEVE_TUNN |
1 << QED_MODE_IPGENEVE_TUNN;
tunn_info.tunn_clss_vxlan = QED_TUNN_CLSS_MAC_VLAN;
tunn_info.tunn_clss_l2gre = QED_TUNN_CLSS_MAC_VLAN;
tunn_info.tunn_clss_ipgre = QED_TUNN_CLSS_MAC_VLAN;
/* Start the slowpath */
memset(&hw_init_params, 0, sizeof(hw_init_params));
memset(&tunn_info, 0, sizeof(tunn_info));
tunn_info.vxlan.b_mode_enabled = true;
tunn_info.l2_gre.b_mode_enabled = true;
tunn_info.ip_gre.b_mode_enabled = true;
tunn_info.l2_geneve.b_mode_enabled = true;
tunn_info.ip_geneve.b_mode_enabled = true;
tunn_info.vxlan.tun_cls = QED_TUNN_CLSS_MAC_VLAN;
tunn_info.l2_gre.tun_cls = QED_TUNN_CLSS_MAC_VLAN;
tunn_info.ip_gre.tun_cls = QED_TUNN_CLSS_MAC_VLAN;
tunn_info.l2_geneve.tun_cls = QED_TUNN_CLSS_MAC_VLAN;
tunn_info.ip_geneve.tun_cls = QED_TUNN_CLSS_MAC_VLAN;
hw_init_params.p_tunn = &tunn_info;
hw_init_params.b_hw_start = true;
hw_init_params.int_mode = cdev->int_params.out.int_mode;
......@@ -1007,6 +1022,14 @@ static int qed_slowpath_start(struct qed_dev *cdev,
DP_INFO(cdev,
"HW initialization and function start completed successfully\n");
if (IS_PF(cdev)) {
cdev->tunn_feature_mask = (BIT(QED_MODE_VXLAN_TUNN) |
BIT(QED_MODE_L2GENEVE_TUNN) |
BIT(QED_MODE_IPGENEVE_TUNN) |
BIT(QED_MODE_L2GRE_TUNN) |
BIT(QED_MODE_IPGRE_TUNN));
}
/* Allocate LL2 interface if needed */
if (QED_LEADING_HWFN(cdev)->using_ll2) {
rc = qed_ll2_alloc_if(cdev);
......
......@@ -409,7 +409,7 @@ int qed_sp_init_request(struct qed_hwfn *p_hwfn,
*/
int qed_sp_pf_start(struct qed_hwfn *p_hwfn,
struct qed_tunn_start_params *p_tunn,
struct qed_tunnel_info *p_tunn,
enum qed_mf_mode mode, bool allow_npar_tx_switch);
/**
......@@ -442,7 +442,7 @@ int qed_sp_pf_update(struct qed_hwfn *p_hwfn);
int qed_sp_pf_stop(struct qed_hwfn *p_hwfn);
int qed_sp_pf_update_tunn_cfg(struct qed_hwfn *p_hwfn,
struct qed_tunn_update_params *p_tunn,
struct qed_tunnel_info *p_tunn,
enum spq_mode comp_mode,
struct qed_spq_comp_cb *p_comp_data);
/**
......
......@@ -2019,6 +2019,220 @@ static void qed_iov_vf_mbx_start_rxq(struct qed_hwfn *p_hwfn,
qed_iov_vf_mbx_start_rxq_resp(p_hwfn, p_ptt, vf, status, b_legacy_vf);
}
static void
qed_iov_pf_update_tun_response(struct pfvf_update_tunn_param_tlv *p_resp,
struct qed_tunnel_info *p_tun,
u16 tunn_feature_mask)
{
p_resp->tunn_feature_mask = tunn_feature_mask;
p_resp->vxlan_mode = p_tun->vxlan.b_mode_enabled;
p_resp->l2geneve_mode = p_tun->l2_geneve.b_mode_enabled;
p_resp->ipgeneve_mode = p_tun->ip_geneve.b_mode_enabled;
p_resp->l2gre_mode = p_tun->l2_gre.b_mode_enabled;
p_resp->ipgre_mode = p_tun->l2_gre.b_mode_enabled;
p_resp->vxlan_clss = p_tun->vxlan.tun_cls;
p_resp->l2gre_clss = p_tun->l2_gre.tun_cls;
p_resp->ipgre_clss = p_tun->ip_gre.tun_cls;
p_resp->l2geneve_clss = p_tun->l2_geneve.tun_cls;
p_resp->ipgeneve_clss = p_tun->ip_geneve.tun_cls;
p_resp->geneve_udp_port = p_tun->geneve_port.port;
p_resp->vxlan_udp_port = p_tun->vxlan_port.port;
}
static void
__qed_iov_pf_update_tun_param(struct vfpf_update_tunn_param_tlv *p_req,
struct qed_tunn_update_type *p_tun,
enum qed_tunn_mode mask, u8 tun_cls)
{
if (p_req->tun_mode_update_mask & BIT(mask)) {
p_tun->b_update_mode = true;
if (p_req->tunn_mode & BIT(mask))
p_tun->b_mode_enabled = true;
}
p_tun->tun_cls = tun_cls;
}
static void
qed_iov_pf_update_tun_param(struct vfpf_update_tunn_param_tlv *p_req,
struct qed_tunn_update_type *p_tun,
struct qed_tunn_update_udp_port *p_port,
enum qed_tunn_mode mask,
u8 tun_cls, u8 update_port, u16 port)
{
if (update_port) {
p_port->b_update_port = true;
p_port->port = port;
}
__qed_iov_pf_update_tun_param(p_req, p_tun, mask, tun_cls);
}
static bool
qed_iov_pf_validate_tunn_param(struct vfpf_update_tunn_param_tlv *p_req)
{
bool b_update_requested = false;
if (p_req->tun_mode_update_mask || p_req->update_tun_cls ||
p_req->update_geneve_port || p_req->update_vxlan_port)
b_update_requested = true;
return b_update_requested;
}
static void qed_pf_validate_tunn_mode(struct qed_tunn_update_type *tun, int *rc)
{
if (tun->b_update_mode && !tun->b_mode_enabled) {
tun->b_update_mode = false;
*rc = -EINVAL;
}
}
static int
qed_pf_validate_modify_tunn_config(struct qed_hwfn *p_hwfn,
u16 *tun_features, bool *update,
struct qed_tunnel_info *tun_src)
{
struct qed_eth_cb_ops *ops = p_hwfn->cdev->protocol_ops.eth;
struct qed_tunnel_info *tun = &p_hwfn->cdev->tunnel;
u16 bultn_vxlan_port, bultn_geneve_port;
void *cookie = p_hwfn->cdev->ops_cookie;
int i, rc = 0;
*tun_features = p_hwfn->cdev->tunn_feature_mask;
bultn_vxlan_port = tun->vxlan_port.port;
bultn_geneve_port = tun->geneve_port.port;
qed_pf_validate_tunn_mode(&tun_src->vxlan, &rc);
qed_pf_validate_tunn_mode(&tun_src->l2_geneve, &rc);
qed_pf_validate_tunn_mode(&tun_src->ip_geneve, &rc);
qed_pf_validate_tunn_mode(&tun_src->l2_gre, &rc);
qed_pf_validate_tunn_mode(&tun_src->ip_gre, &rc);
if ((tun_src->b_update_rx_cls || tun_src->b_update_tx_cls) &&
(tun_src->vxlan.tun_cls != QED_TUNN_CLSS_MAC_VLAN ||
tun_src->l2_geneve.tun_cls != QED_TUNN_CLSS_MAC_VLAN ||
tun_src->ip_geneve.tun_cls != QED_TUNN_CLSS_MAC_VLAN ||
tun_src->l2_gre.tun_cls != QED_TUNN_CLSS_MAC_VLAN ||
tun_src->ip_gre.tun_cls != QED_TUNN_CLSS_MAC_VLAN)) {
tun_src->b_update_rx_cls = false;
tun_src->b_update_tx_cls = false;
rc = -EINVAL;
}
if (tun_src->vxlan_port.b_update_port) {
if (tun_src->vxlan_port.port == tun->vxlan_port.port) {
tun_src->vxlan_port.b_update_port = false;
} else {
*update = true;
bultn_vxlan_port = tun_src->vxlan_port.port;
}
}
if (tun_src->geneve_port.b_update_port) {
if (tun_src->geneve_port.port == tun->geneve_port.port) {
tun_src->geneve_port.b_update_port = false;
} else {
*update = true;
bultn_geneve_port = tun_src->geneve_port.port;
}
}
qed_for_each_vf(p_hwfn, i) {
qed_iov_bulletin_set_udp_ports(p_hwfn, i, bultn_vxlan_port,
bultn_geneve_port);
}
qed_schedule_iov(p_hwfn, QED_IOV_WQ_BULLETIN_UPDATE_FLAG);
ops->ports_update(cookie, bultn_vxlan_port, bultn_geneve_port);
return rc;
}
static void qed_iov_vf_mbx_update_tunn_param(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
struct qed_vf_info *p_vf)
{
struct qed_tunnel_info *p_tun = &p_hwfn->cdev->tunnel;
struct qed_iov_vf_mbx *mbx = &p_vf->vf_mbx;
struct pfvf_update_tunn_param_tlv *p_resp;
struct vfpf_update_tunn_param_tlv *p_req;
u8 status = PFVF_STATUS_SUCCESS;
bool b_update_required = false;
struct qed_tunnel_info tunn;
u16 tunn_feature_mask = 0;
int i, rc = 0;
mbx->offset = (u8 *)mbx->reply_virt;
memset(&tunn, 0, sizeof(tunn));
p_req = &mbx->req_virt->tunn_param_update;
if (!qed_iov_pf_validate_tunn_param(p_req)) {
DP_VERBOSE(p_hwfn, QED_MSG_IOV,
"No tunnel update requested by VF\n");
status = PFVF_STATUS_FAILURE;
goto send_resp;
}
tunn.b_update_rx_cls = p_req->update_tun_cls;
tunn.b_update_tx_cls = p_req->update_tun_cls;
qed_iov_pf_update_tun_param(p_req, &tunn.vxlan, &tunn.vxlan_port,
QED_MODE_VXLAN_TUNN, p_req->vxlan_clss,
p_req->update_vxlan_port,
p_req->vxlan_port);
qed_iov_pf_update_tun_param(p_req, &tunn.l2_geneve, &tunn.geneve_port,
QED_MODE_L2GENEVE_TUNN,
p_req->l2geneve_clss,
p_req->update_geneve_port,
p_req->geneve_port);
__qed_iov_pf_update_tun_param(p_req, &tunn.ip_geneve,
QED_MODE_IPGENEVE_TUNN,
p_req->ipgeneve_clss);
__qed_iov_pf_update_tun_param(p_req, &tunn.l2_gre,
QED_MODE_L2GRE_TUNN, p_req->l2gre_clss);
__qed_iov_pf_update_tun_param(p_req, &tunn.ip_gre,
QED_MODE_IPGRE_TUNN, p_req->ipgre_clss);
/* If PF modifies VF's req then it should
* still return an error in case of partial configuration
* or modified configuration as opposed to requested one.
*/
rc = qed_pf_validate_modify_tunn_config(p_hwfn, &tunn_feature_mask,
&b_update_required, &tunn);
if (rc)
status = PFVF_STATUS_FAILURE;
/* If QED client is willing to update anything ? */
if (b_update_required) {
u16 geneve_port;
rc = qed_sp_pf_update_tunn_cfg(p_hwfn, &tunn,
QED_SPQ_MODE_EBLOCK, NULL);
if (rc)
status = PFVF_STATUS_FAILURE;
geneve_port = p_tun->geneve_port.port;
qed_for_each_vf(p_hwfn, i) {
qed_iov_bulletin_set_udp_ports(p_hwfn, i,
p_tun->vxlan_port.port,
geneve_port);
}
}
send_resp:
p_resp = qed_add_tlv(p_hwfn, &mbx->offset,
CHANNEL_TLV_UPDATE_TUNN_PARAM, sizeof(*p_resp));
qed_iov_pf_update_tun_response(p_resp, p_tun, tunn_feature_mask);
qed_add_tlv(p_hwfn, &mbx->offset, CHANNEL_TLV_LIST_END,
sizeof(struct channel_list_end_tlv));
qed_iov_send_response(p_hwfn, p_ptt, p_vf, sizeof(*p_resp), status);
}
static void qed_iov_vf_mbx_start_txq_resp(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
struct qed_vf_info *p_vf, u8 status)
......@@ -3275,6 +3489,9 @@ static void qed_iov_process_mbx_req(struct qed_hwfn *p_hwfn,
case CHANNEL_TLV_RELEASE:
qed_iov_vf_mbx_release(p_hwfn, p_ptt, p_vf);
break;
case CHANNEL_TLV_UPDATE_TUNN_PARAM:
qed_iov_vf_mbx_update_tunn_param(p_hwfn, p_ptt, p_vf);
break;
}
} else if (qed_iov_tlv_supported(mbx->first_tlv.tl.type)) {
DP_VERBOSE(p_hwfn, QED_MSG_IOV,
......@@ -3511,6 +3728,29 @@ static void qed_iov_bulletin_set_forced_vlan(struct qed_hwfn *p_hwfn,
qed_iov_configure_vport_forced(p_hwfn, vf_info, feature);
}
void qed_iov_bulletin_set_udp_ports(struct qed_hwfn *p_hwfn,
int vfid, u16 vxlan_port, u16 geneve_port)
{
struct qed_vf_info *vf_info;
vf_info = qed_iov_get_vf_info(p_hwfn, (u16)vfid, true);
if (!vf_info) {
DP_NOTICE(p_hwfn->cdev,
"Can not set udp ports, invalid vfid [%d]\n", vfid);
return;
}
if (vf_info->b_malicious) {
DP_VERBOSE(p_hwfn, QED_MSG_IOV,
"Can not set udp ports to malicious VF [%d]\n",
vfid);
return;
}
vf_info->bulletin.p_virt->vxlan_udp_port = vxlan_port;
vf_info->bulletin.p_virt->geneve_udp_port = geneve_port;
}
static bool qed_iov_vf_has_vport_instance(struct qed_hwfn *p_hwfn, int vfid)
{
struct qed_vf_info *p_vf_info;
......
......@@ -270,6 +270,9 @@ enum qed_iov_wq_flag {
*/
u16 qed_iov_get_next_active_vf(struct qed_hwfn *p_hwfn, u16 rel_vf_id);
void qed_iov_bulletin_set_udp_ports(struct qed_hwfn *p_hwfn,
int vfid, u16 vxlan_port, u16 geneve_port);
/**
* @brief Read sriov related information and allocated resources
* reads from configuraiton space, shmem, etc.
......@@ -378,6 +381,12 @@ static inline u16 qed_iov_get_next_active_vf(struct qed_hwfn *p_hwfn,
return MAX_NUM_VFS;
}
static inline void
qed_iov_bulletin_set_udp_ports(struct qed_hwfn *p_hwfn, int vfid,
u16 vxlan_port, u16 geneve_port)
{
}
static inline int qed_iov_hw_info(struct qed_hwfn *p_hwfn)
{
return 0;
......
......@@ -418,6 +418,155 @@ int qed_vf_hw_prepare(struct qed_hwfn *p_hwfn)
#define MSTORM_QZONE_START(dev) (TSTORM_QZONE_START + \
(TSTORM_QZONE_SIZE * NUM_OF_L2_QUEUES(dev)))
static void
__qed_vf_prep_tunn_req_tlv(struct vfpf_update_tunn_param_tlv *p_req,
struct qed_tunn_update_type *p_src,
enum qed_tunn_clss mask, u8 *p_cls)
{
if (p_src->b_update_mode) {
p_req->tun_mode_update_mask |= BIT(mask);
if (p_src->b_mode_enabled)
p_req->tunn_mode |= BIT(mask);
}
*p_cls = p_src->tun_cls;
}
static void
qed_vf_prep_tunn_req_tlv(struct vfpf_update_tunn_param_tlv *p_req,
struct qed_tunn_update_type *p_src,
enum qed_tunn_clss mask,
u8 *p_cls, struct qed_tunn_update_udp_port *p_port,
u8 *p_update_port, u16 *p_udp_port)
{
if (p_port->b_update_port) {
*p_update_port = 1;
*p_udp_port = p_port->port;
}
__qed_vf_prep_tunn_req_tlv(p_req, p_src, mask, p_cls);
}
void qed_vf_set_vf_start_tunn_update_param(struct qed_tunnel_info *p_tun)
{
if (p_tun->vxlan.b_mode_enabled)
p_tun->vxlan.b_update_mode = true;
if (p_tun->l2_geneve.b_mode_enabled)
p_tun->l2_geneve.b_update_mode = true;
if (p_tun->ip_geneve.b_mode_enabled)
p_tun->ip_geneve.b_update_mode = true;
if (p_tun->l2_gre.b_mode_enabled)
p_tun->l2_gre.b_update_mode = true;
if (p_tun->ip_gre.b_mode_enabled)
p_tun->ip_gre.b_update_mode = true;
p_tun->b_update_rx_cls = true;
p_tun->b_update_tx_cls = true;
}
static void
__qed_vf_update_tunn_param(struct qed_tunn_update_type *p_tun,
u16 feature_mask, u8 tunn_mode,
u8 tunn_cls, enum qed_tunn_mode val)
{
if (feature_mask & BIT(val)) {
p_tun->b_mode_enabled = tunn_mode;
p_tun->tun_cls = tunn_cls;
} else {
p_tun->b_mode_enabled = false;
}
}
static void qed_vf_update_tunn_param(struct qed_hwfn *p_hwfn,
struct qed_tunnel_info *p_tun,
struct pfvf_update_tunn_param_tlv *p_resp)
{
/* Update mode and classes provided by PF */
u16 feat_mask = p_resp->tunn_feature_mask;
__qed_vf_update_tunn_param(&p_tun->vxlan, feat_mask,
p_resp->vxlan_mode, p_resp->vxlan_clss,
QED_MODE_VXLAN_TUNN);
__qed_vf_update_tunn_param(&p_tun->l2_geneve, feat_mask,
p_resp->l2geneve_mode,
p_resp->l2geneve_clss,
QED_MODE_L2GENEVE_TUNN);
__qed_vf_update_tunn_param(&p_tun->ip_geneve, feat_mask,
p_resp->ipgeneve_mode,
p_resp->ipgeneve_clss,
QED_MODE_IPGENEVE_TUNN);
__qed_vf_update_tunn_param(&p_tun->l2_gre, feat_mask,
p_resp->l2gre_mode, p_resp->l2gre_clss,
QED_MODE_L2GRE_TUNN);
__qed_vf_update_tunn_param(&p_tun->ip_gre, feat_mask,
p_resp->ipgre_mode, p_resp->ipgre_clss,
QED_MODE_IPGRE_TUNN);
p_tun->geneve_port.port = p_resp->geneve_udp_port;
p_tun->vxlan_port.port = p_resp->vxlan_udp_port;
DP_VERBOSE(p_hwfn, QED_MSG_IOV,
"tunn mode: vxlan=0x%x, l2geneve=0x%x, ipgeneve=0x%x, l2gre=0x%x, ipgre=0x%x",
p_tun->vxlan.b_mode_enabled, p_tun->l2_geneve.b_mode_enabled,
p_tun->ip_geneve.b_mode_enabled,
p_tun->l2_gre.b_mode_enabled, p_tun->ip_gre.b_mode_enabled);
}
int qed_vf_pf_tunnel_param_update(struct qed_hwfn *p_hwfn,
struct qed_tunnel_info *p_src)
{
struct qed_tunnel_info *p_tun = &p_hwfn->cdev->tunnel;
struct qed_vf_iov *p_iov = p_hwfn->vf_iov_info;
struct pfvf_update_tunn_param_tlv *p_resp;
struct vfpf_update_tunn_param_tlv *p_req;
int rc;
p_req = qed_vf_pf_prep(p_hwfn, CHANNEL_TLV_UPDATE_TUNN_PARAM,
sizeof(*p_req));
if (p_src->b_update_rx_cls && p_src->b_update_tx_cls)
p_req->update_tun_cls = 1;
qed_vf_prep_tunn_req_tlv(p_req, &p_src->vxlan, QED_MODE_VXLAN_TUNN,
&p_req->vxlan_clss, &p_src->vxlan_port,
&p_req->update_vxlan_port,
&p_req->vxlan_port);
qed_vf_prep_tunn_req_tlv(p_req, &p_src->l2_geneve,
QED_MODE_L2GENEVE_TUNN,
&p_req->l2geneve_clss, &p_src->geneve_port,
&p_req->update_geneve_port,
&p_req->geneve_port);
__qed_vf_prep_tunn_req_tlv(p_req, &p_src->ip_geneve,
QED_MODE_IPGENEVE_TUNN,
&p_req->ipgeneve_clss);
__qed_vf_prep_tunn_req_tlv(p_req, &p_src->l2_gre,
QED_MODE_L2GRE_TUNN, &p_req->l2gre_clss);
__qed_vf_prep_tunn_req_tlv(p_req, &p_src->ip_gre,
QED_MODE_IPGRE_TUNN, &p_req->ipgre_clss);
/* add list termination tlv */
qed_add_tlv(p_hwfn, &p_iov->offset,
CHANNEL_TLV_LIST_END,
sizeof(struct channel_list_end_tlv));
p_resp = &p_iov->pf2vf_reply->tunn_param_resp;
rc = qed_send_msg2pf(p_hwfn, &p_resp->hdr.status, sizeof(*p_resp));
if (rc)
goto exit;
if (p_resp->hdr.status != PFVF_STATUS_SUCCESS) {
DP_VERBOSE(p_hwfn, QED_MSG_IOV,
"Failed to update tunnel parameters\n");
rc = -EINVAL;
}
qed_vf_update_tunn_param(p_hwfn, p_tun, p_resp);
exit:
qed_vf_pf_req_end(p_hwfn, rc);
return rc;
}
int
qed_vf_pf_rxq_start(struct qed_hwfn *p_hwfn,
struct qed_queue_cid *p_cid,
......@@ -1251,6 +1400,18 @@ static bool qed_vf_bulletin_get_forced_mac(struct qed_hwfn *hwfn,
return true;
}
static void
qed_vf_bulletin_get_udp_ports(struct qed_hwfn *p_hwfn,
u16 *p_vxlan_port, u16 *p_geneve_port)
{
struct qed_bulletin_content *p_bulletin;
p_bulletin = &p_hwfn->vf_iov_info->bulletin_shadow;
*p_vxlan_port = p_bulletin->vxlan_udp_port;
*p_geneve_port = p_bulletin->geneve_udp_port;
}
void qed_vf_get_fw_version(struct qed_hwfn *p_hwfn,
u16 *fw_major, u16 *fw_minor,
u16 *fw_rev, u16 *fw_eng)
......@@ -1270,12 +1431,16 @@ static void qed_handle_bulletin_change(struct qed_hwfn *hwfn)
struct qed_eth_cb_ops *ops = hwfn->cdev->protocol_ops.eth;
u8 mac[ETH_ALEN], is_mac_exist, is_mac_forced;
void *cookie = hwfn->cdev->ops_cookie;
u16 vxlan_port, geneve_port;
qed_vf_bulletin_get_udp_ports(hwfn, &vxlan_port, &geneve_port);
is_mac_exist = qed_vf_bulletin_get_forced_mac(hwfn, mac,
&is_mac_forced);
if (is_mac_exist && cookie)
ops->force_mac(cookie, mac, !!is_mac_forced);
ops->ports_update(cookie, vxlan_port, geneve_port);
/* Always update link configuration according to bulletin */
qed_link_update(hwfn);
}
......
......@@ -429,6 +429,43 @@ struct vfpf_ucast_filter_tlv {
u16 padding[3];
};
/* tunnel update param tlv */
struct vfpf_update_tunn_param_tlv {
struct vfpf_first_tlv first_tlv;
u8 tun_mode_update_mask;
u8 tunn_mode;
u8 update_tun_cls;
u8 vxlan_clss;
u8 l2gre_clss;
u8 ipgre_clss;
u8 l2geneve_clss;
u8 ipgeneve_clss;
u8 update_geneve_port;
u8 update_vxlan_port;
u16 geneve_port;
u16 vxlan_port;
u8 padding[2];
};
struct pfvf_update_tunn_param_tlv {
struct pfvf_tlv hdr;
u16 tunn_feature_mask;
u8 vxlan_mode;
u8 l2geneve_mode;
u8 ipgeneve_mode;
u8 l2gre_mode;
u8 ipgre_mode;
u8 vxlan_clss;
u8 l2gre_clss;
u8 ipgre_clss;
u8 l2geneve_clss;
u8 ipgeneve_clss;
u16 vxlan_udp_port;
u16 geneve_udp_port;
};
struct tlv_buffer_size {
u8 tlv_buffer[TLV_BUFFER_SIZE];
};
......@@ -444,6 +481,7 @@ union vfpf_tlvs {
struct vfpf_vport_start_tlv start_vport;
struct vfpf_vport_update_tlv vport_update;
struct vfpf_ucast_filter_tlv ucast_filter;
struct vfpf_update_tunn_param_tlv tunn_param_update;
struct channel_list_end_tlv list_end;
struct tlv_buffer_size tlv_buf_size;
};
......@@ -453,6 +491,7 @@ union pfvf_tlvs {
struct pfvf_acquire_resp_tlv acquire_resp;
struct tlv_buffer_size tlv_buf_size;
struct pfvf_start_queue_resp_tlv queue_start;
struct pfvf_update_tunn_param_tlv tunn_param_resp;
};
enum qed_bulletin_bit {
......@@ -513,7 +552,9 @@ struct qed_bulletin_content {
u8 partner_rx_flow_ctrl_en;
u8 partner_adv_pause;
u8 sfp_tx_fault;
u8 padding4[6];
u16 vxlan_udp_port;
u16 geneve_udp_port;
u8 padding4[2];
u32 speed;
u32 partner_adv_speed;
......@@ -555,6 +596,7 @@ enum {
CHANNEL_TLV_VPORT_UPDATE_RSS,
CHANNEL_TLV_VPORT_UPDATE_ACCEPT_ANY_VLAN,
CHANNEL_TLV_VPORT_UPDATE_SGE_TPA,
CHANNEL_TLV_UPDATE_TUNN_PARAM,
CHANNEL_TLV_MAX,
/* Required for iterating over vport-update tlvs.
......@@ -872,6 +914,9 @@ void __qed_vf_get_link_caps(struct qed_hwfn *p_hwfn,
struct qed_bulletin_content *p_bulletin);
void qed_iov_vf_task(struct work_struct *work);
void qed_vf_set_vf_start_tunn_update_param(struct qed_tunnel_info *p_tun);
int qed_vf_pf_tunnel_param_update(struct qed_hwfn *p_hwfn,
struct qed_tunnel_info *p_tunn);
#else
static inline void qed_vf_get_link_params(struct qed_hwfn *p_hwfn,
struct qed_mcp_link_params *params)
......@@ -1033,6 +1078,17 @@ __qed_vf_get_link_caps(struct qed_hwfn *p_hwfn,
static inline void qed_iov_vf_task(struct work_struct *work)
{
}
static inline void
qed_vf_set_vf_start_tunn_update_param(struct qed_tunnel_info *p_tun)
{
}
static inline int qed_vf_pf_tunnel_param_update(struct qed_hwfn *p_hwfn,
struct qed_tunnel_info *p_tunn)
{
return -EINVAL;
}
#endif
#endif
......@@ -442,8 +442,6 @@ struct qede_fastpath {
#define QEDE_TUNN_CSUM_UNNECESSARY BIT(2)
#define QEDE_SP_RX_MODE 1
#define QEDE_SP_VXLAN_PORT_CONFIG 2
#define QEDE_SP_GENEVE_PORT_CONFIG 3
#ifdef CONFIG_RFS_ACCEL
int qede_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb,
......@@ -482,6 +480,7 @@ irqreturn_t qede_msix_fp_int(int irq, void *fp_cookie);
/* Filtering function definitions */
void qede_force_mac(void *dev, u8 *mac, bool forced);
void qede_udp_ports_update(void *dev, u16 vxlan_port, u16 geneve_port);
int qede_set_mac_addr(struct net_device *ndev, void *p);
int qede_vlan_rx_add_vid(struct net_device *dev, __be16 proto, u16 vid);
......
......@@ -480,6 +480,17 @@ int qede_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb,
}
#endif
void qede_udp_ports_update(void *dev, u16 vxlan_port, u16 geneve_port)
{
struct qede_dev *edev = dev;
if (edev->vxlan_dst_port != vxlan_port)
edev->vxlan_dst_port = 0;
if (edev->geneve_dst_port != geneve_port)
edev->geneve_dst_port = 0;
}
void qede_force_mac(void *dev, u8 *mac, bool forced)
{
struct qede_dev *edev = dev;
......@@ -883,69 +894,112 @@ int qede_set_features(struct net_device *dev, netdev_features_t features)
void qede_udp_tunnel_add(struct net_device *dev, struct udp_tunnel_info *ti)
{
struct qede_dev *edev = netdev_priv(dev);
struct qed_tunn_params tunn_params;
u16 t_port = ntohs(ti->port);
int rc;
memset(&tunn_params, 0, sizeof(tunn_params));
switch (ti->type) {
case UDP_TUNNEL_TYPE_VXLAN:
if (!edev->dev_info.common.vxlan_enable)
return;
if (edev->vxlan_dst_port)
return;
edev->vxlan_dst_port = t_port;
tunn_params.update_vxlan_port = 1;
tunn_params.vxlan_port = t_port;
DP_VERBOSE(edev, QED_MSG_DEBUG, "Added vxlan port=%d\n",
t_port);
__qede_lock(edev);
rc = edev->ops->tunn_config(edev->cdev, &tunn_params);
__qede_unlock(edev);
if (!rc) {
edev->vxlan_dst_port = t_port;
DP_VERBOSE(edev, QED_MSG_DEBUG, "Added vxlan port=%d\n",
t_port);
} else {
DP_NOTICE(edev, "Failed to add vxlan UDP port=%d\n",
t_port);
}
set_bit(QEDE_SP_VXLAN_PORT_CONFIG, &edev->sp_flags);
break;
case UDP_TUNNEL_TYPE_GENEVE:
if (!edev->dev_info.common.geneve_enable)
return;
if (edev->geneve_dst_port)
return;
edev->geneve_dst_port = t_port;
tunn_params.update_geneve_port = 1;
tunn_params.geneve_port = t_port;
__qede_lock(edev);
rc = edev->ops->tunn_config(edev->cdev, &tunn_params);
__qede_unlock(edev);
if (!rc) {
edev->geneve_dst_port = t_port;
DP_VERBOSE(edev, QED_MSG_DEBUG,
"Added geneve port=%d\n", t_port);
} else {
DP_NOTICE(edev, "Failed to add geneve UDP port=%d\n",
t_port);
}
DP_VERBOSE(edev, QED_MSG_DEBUG, "Added geneve port=%d\n",
t_port);
set_bit(QEDE_SP_GENEVE_PORT_CONFIG, &edev->sp_flags);
break;
default:
return;
}
schedule_delayed_work(&edev->sp_task, 0);
}
void qede_udp_tunnel_del(struct net_device *dev, struct udp_tunnel_info *ti)
void qede_udp_tunnel_del(struct net_device *dev,
struct udp_tunnel_info *ti)
{
struct qede_dev *edev = netdev_priv(dev);
struct qed_tunn_params tunn_params;
u16 t_port = ntohs(ti->port);
memset(&tunn_params, 0, sizeof(tunn_params));
switch (ti->type) {
case UDP_TUNNEL_TYPE_VXLAN:
if (t_port != edev->vxlan_dst_port)
return;
tunn_params.update_vxlan_port = 1;
tunn_params.vxlan_port = 0;
__qede_lock(edev);
edev->ops->tunn_config(edev->cdev, &tunn_params);
__qede_unlock(edev);
edev->vxlan_dst_port = 0;
DP_VERBOSE(edev, QED_MSG_DEBUG, "Deleted vxlan port=%d\n",
t_port);
set_bit(QEDE_SP_VXLAN_PORT_CONFIG, &edev->sp_flags);
break;
case UDP_TUNNEL_TYPE_GENEVE:
if (t_port != edev->geneve_dst_port)
return;
tunn_params.update_geneve_port = 1;
tunn_params.geneve_port = 0;
__qede_lock(edev);
edev->ops->tunn_config(edev->cdev, &tunn_params);
__qede_unlock(edev);
edev->geneve_dst_port = 0;
DP_VERBOSE(edev, QED_MSG_DEBUG, "Deleted geneve port=%d\n",
t_port);
set_bit(QEDE_SP_GENEVE_PORT_CONFIG, &edev->sp_flags);
break;
default:
return;
}
schedule_delayed_work(&edev->sp_task, 0);
}
static void qede_xdp_reload_func(struct qede_dev *edev,
......
......@@ -1697,13 +1697,24 @@ netdev_features_t qede_features_check(struct sk_buff *skb,
}
/* Disable offloads for geneve tunnels, as HW can't parse
* the geneve header which has option length greater than 32B.
* the geneve header which has option length greater than 32b
* and disable offloads for the ports which are not offloaded.
*/
if ((l4_proto == IPPROTO_UDP) &&
((skb_inner_mac_header(skb) -
skb_transport_header(skb)) > QEDE_MAX_TUN_HDR_LEN))
return features & ~(NETIF_F_CSUM_MASK |
NETIF_F_GSO_MASK);
if (l4_proto == IPPROTO_UDP) {
struct qede_dev *edev = netdev_priv(dev);
u16 hdrlen, vxln_port, gnv_port;
hdrlen = QEDE_MAX_TUN_HDR_LEN;
vxln_port = edev->vxlan_dst_port;
gnv_port = edev->geneve_dst_port;
if ((skb_inner_mac_header(skb) -
skb_transport_header(skb)) > hdrlen ||
(ntohs(udp_hdr(skb)->dest) != vxln_port &&
ntohs(udp_hdr(skb)->dest) != gnv_port))
return features & ~(NETIF_F_CSUM_MASK |
NETIF_F_GSO_MASK);
}
}
return features;
......
......@@ -231,6 +231,7 @@ static struct qed_eth_cb_ops qede_ll_ops = {
.link_update = qede_link_update,
},
.force_mac = qede_force_mac,
.ports_update = qede_udp_ports_update,
};
static int qede_netdev_event(struct notifier_block *this, unsigned long event,
......@@ -609,6 +610,7 @@ static void qede_init_ndev(struct qede_dev *edev)
{
struct net_device *ndev = edev->ndev;
struct pci_dev *pdev = edev->pdev;
bool udp_tunnel_enable = false;
netdev_features_t hw_features;
pci_set_drvdata(pdev, ndev);
......@@ -631,20 +633,33 @@ static void qede_init_ndev(struct qede_dev *edev)
NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
NETIF_F_TSO | NETIF_F_TSO6;
/* Encap features*/
hw_features |= NETIF_F_GSO_GRE | NETIF_F_GSO_UDP_TUNNEL |
NETIF_F_TSO_ECN | NETIF_F_GSO_UDP_TUNNEL_CSUM |
NETIF_F_GSO_GRE_CSUM;
if (!IS_VF(edev) && edev->dev_info.common.num_hwfns == 1)
hw_features |= NETIF_F_NTUPLE;
ndev->hw_enc_features = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO_ECN |
NETIF_F_TSO6 | NETIF_F_GSO_GRE |
NETIF_F_GSO_UDP_TUNNEL | NETIF_F_RXCSUM |
NETIF_F_GSO_UDP_TUNNEL_CSUM |
NETIF_F_GSO_GRE_CSUM;
if (edev->dev_info.common.vxlan_enable ||
edev->dev_info.common.geneve_enable)
udp_tunnel_enable = true;
if (udp_tunnel_enable || edev->dev_info.common.gre_enable) {
hw_features |= NETIF_F_TSO_ECN;
ndev->hw_enc_features = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
NETIF_F_SG | NETIF_F_TSO |
NETIF_F_TSO_ECN | NETIF_F_TSO6 |
NETIF_F_RXCSUM;
}
if (udp_tunnel_enable) {
hw_features |= (NETIF_F_GSO_UDP_TUNNEL |
NETIF_F_GSO_UDP_TUNNEL_CSUM);
ndev->hw_enc_features |= (NETIF_F_GSO_UDP_TUNNEL |
NETIF_F_GSO_UDP_TUNNEL_CSUM);
}
if (edev->dev_info.common.gre_enable) {
hw_features |= (NETIF_F_GSO_GRE | NETIF_F_GSO_GRE_CSUM);
ndev->hw_enc_features |= (NETIF_F_GSO_GRE |
NETIF_F_GSO_GRE_CSUM);
}
ndev->vlan_features = hw_features | NETIF_F_RXHASH | NETIF_F_RXCSUM |
NETIF_F_HIGHDMA;
......@@ -782,7 +797,6 @@ static void qede_sp_task(struct work_struct *work)
{
struct qede_dev *edev = container_of(work, struct qede_dev,
sp_task.work);
struct qed_dev *cdev = edev->cdev;
__qede_lock(edev);
......@@ -790,24 +804,6 @@ static void qede_sp_task(struct work_struct *work)
if (edev->state == QEDE_STATE_OPEN)
qede_config_rx_mode(edev->ndev);
if (test_and_clear_bit(QEDE_SP_VXLAN_PORT_CONFIG, &edev->sp_flags)) {
struct qed_tunn_params tunn_params;
memset(&tunn_params, 0, sizeof(tunn_params));
tunn_params.update_vxlan_port = 1;
tunn_params.vxlan_port = edev->vxlan_dst_port;
qed_ops->tunn_config(cdev, &tunn_params);
}
if (test_and_clear_bit(QEDE_SP_GENEVE_PORT_CONFIG, &edev->sp_flags)) {
struct qed_tunn_params tunn_params;
memset(&tunn_params, 0, sizeof(tunn_params));
tunn_params.update_geneve_port = 1;
tunn_params.geneve_port = edev->geneve_dst_port;
qed_ops->tunn_config(cdev, &tunn_params);
}
#ifdef CONFIG_RFS_ACCEL
if (test_and_clear_bit(QEDE_SP_ARFS_CONFIG, &edev->sp_flags)) {
if (edev->state == QEDE_STATE_OPEN)
......
......@@ -158,6 +158,7 @@ struct qed_tunn_params {
struct qed_eth_cb_ops {
struct qed_common_cb_ops common;
void (*force_mac) (void *dev, u8 *mac, bool forced);
void (*ports_update)(void *dev, u16 vxlan_port, u16 geneve_port);
};
#define QED_MAX_PHC_DRIFT_PPB 291666666
......
......@@ -338,6 +338,11 @@ struct qed_dev_info {
bool wol_support;
enum qed_dev_type dev_type;
/* Output parameters for qede */
bool vxlan_enable;
bool gre_enable;
bool geneve_enable;
};
enum qed_sb_type {
......
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