Commit 39651abd authored by Sudarsana Reddy Kalluru's avatar Sudarsana Reddy Kalluru Committed by David S. Miller

qed: add support for dcbx.

This patch adds the necessary driver support for Management Firmware to
configure the device/firmware with the dcbx results. Management Firmware
is responsible for communicating the DCBX and driving the negotiation,
but the driver has responsibility of receiving async notification and
configuring the results in hw/fw. This patch also adds the dcbx support for
future protocols (e.g., FCoE) as preparation to their imminent submission.
Signed-off-by: default avatarSudarsana Reddy Kalluru <sudarsana.kalluru@qlogic.com>
Signed-off-by: default avatarYuval Mintz <Yuval.Mintz@qlogic.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent ccf92824
......@@ -2,5 +2,5 @@ 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_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_dcbx.o
qed-$(CONFIG_QED_SRIOV) += qed_sriov.o qed_vf.o
......@@ -367,6 +367,8 @@ struct qed_hwfn {
struct qed_pf_iov *pf_iov_info;
struct qed_mcp_info *mcp_info;
struct qed_dcbx_info *p_dcbx_info;
struct qed_hw_cid_data *p_tx_cids;
struct qed_hw_cid_data *p_rx_cids;
......
......@@ -130,6 +130,16 @@ void qed_cxt_hw_init_pf(struct qed_hwfn *p_hwfn);
void qed_qm_init_pf(struct qed_hwfn *p_hwfn);
/**
* @brief Reconfigures QM pf on the fly
*
* @param p_hwfn
* @param p_ptt
*
* @return int
*/
int qed_qm_reconf(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt);
/**
* @brief qed_cxt_release - Release a cid
*
......
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_DCBX_H
#define _QED_DCBX_H
#include <linux/types.h>
#include <linux/slab.h>
#include "qed.h"
#include "qed_hsi.h"
#include "qed_hw.h"
#include "qed_mcp.h"
#include "qed_reg_addr.h"
#define DCBX_CONFIG_MAX_APP_PROTOCOL 4
enum qed_mib_read_type {
QED_DCBX_OPERATIONAL_MIB,
QED_DCBX_REMOTE_MIB,
QED_DCBX_LOCAL_MIB,
QED_DCBX_REMOTE_LLDP_MIB,
QED_DCBX_LOCAL_LLDP_MIB
};
struct qed_dcbx_app_data {
bool enable; /* DCB enabled */
bool update; /* Update indication */
u8 priority; /* Priority */
u8 tc; /* Traffic Class */
};
struct qed_dcbx_results {
bool dcbx_enabled;
u8 pf_id;
struct qed_dcbx_app_data arr[DCBX_MAX_PROTOCOL_TYPE];
};
struct qed_dcbx_app_metadata {
enum dcbx_protocol_type id;
char *name;
enum qed_pci_personality personality;
};
#define QED_MFW_GET_FIELD(name, field) \
(((name) & (field ## _MASK)) >> (field ## _SHIFT))
struct qed_dcbx_info {
struct lldp_status_params_s lldp_remote[LLDP_MAX_LLDP_AGENTS];
struct lldp_config_params_s lldp_local[LLDP_MAX_LLDP_AGENTS];
struct dcbx_local_params local_admin;
struct qed_dcbx_results results;
struct dcbx_mib operational;
struct dcbx_mib remote;
u8 dcbx_cap;
};
struct qed_dcbx_mib_meta_data {
struct lldp_config_params_s *lldp_local;
struct lldp_status_params_s *lldp_remote;
struct dcbx_local_params *local_admin;
struct dcbx_mib *mib;
size_t size;
u32 addr;
};
/* QED local interface routines */
int
qed_dcbx_mib_update_event(struct qed_hwfn *,
struct qed_ptt *, enum qed_mib_read_type);
int qed_dcbx_info_alloc(struct qed_hwfn *p_hwfn);
void qed_dcbx_info_free(struct qed_hwfn *, struct qed_dcbx_info *);
void qed_dcbx_set_pf_update_params(struct qed_dcbx_results *p_src,
struct pf_update_ramrod_data *p_dest);
#endif
......@@ -22,6 +22,7 @@
#include <linux/qed/qed_if.h>
#include "qed.h"
#include "qed_cxt.h"
#include "qed_dcbx.h"
#include "qed_dev_api.h"
#include "qed_hsi.h"
#include "qed_hw.h"
......@@ -33,6 +34,9 @@
#include "qed_sriov.h"
#include "qed_vf.h"
static spinlock_t qm_lock;
static bool qm_lock_init = false;
/* API common to all protocols */
enum BAR_ID {
BAR_ID_0, /* used for GRC */
......@@ -147,6 +151,7 @@ void qed_resc_free(struct qed_dev *cdev)
qed_int_free(p_hwfn);
qed_iov_free(p_hwfn);
qed_dmae_info_free(p_hwfn);
qed_dcbx_info_free(p_hwfn, p_hwfn->p_dcbx_info);
}
}
......@@ -200,13 +205,19 @@ static int qed_init_qm_info(struct qed_hwfn *p_hwfn)
vport_id = (u8)RESC_START(p_hwfn, QED_VPORT);
/* First init per-TC PQs */
for (i = 0; i < multi_cos_tcs; i++, curr_queue++) {
for (i = 0; i < multi_cos_tcs; i++) {
struct init_qm_pq_params *params =
&qm_info->qm_pq_params[curr_queue];
&qm_info->qm_pq_params[curr_queue++];
params->vport_id = vport_id;
params->tc_id = p_hwfn->hw_info.non_offload_tc;
params->wrr_group = 1;
if (p_hwfn->hw_info.personality == QED_PCI_ETH) {
params->vport_id = vport_id;
params->tc_id = p_hwfn->hw_info.non_offload_tc;
params->wrr_group = 1;
} else {
params->vport_id = vport_id;
params->tc_id = p_hwfn->hw_info.offload_tc;
params->wrr_group = 1;
}
}
/* Then init pure-LB PQ */
......@@ -266,6 +277,63 @@ static int qed_init_qm_info(struct qed_hwfn *p_hwfn)
return -ENOMEM;
}
/* This function reconfigures the QM pf on the fly.
* For this purpose we:
* 1. reconfigure the QM database
* 2. set new values to runtime arrat
* 3. send an sdm_qm_cmd through the rbc interface to stop the QM
* 4. activate init tool in QM_PF stage
* 5. send an sdm_qm_cmd through rbc interface to release the QM
*/
int qed_qm_reconf(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
{
struct qed_qm_info *qm_info = &p_hwfn->qm_info;
bool b_rc;
int rc;
/* qm_info is allocated in qed_init_qm_info() which is already called
* from qed_resc_alloc() or previous call of qed_qm_reconf().
* The allocated size may change each init, so we free it before next
* allocation.
*/
qed_qm_info_free(p_hwfn);
/* initialize qed's qm data structure */
rc = qed_init_qm_info(p_hwfn);
if (rc)
return rc;
/* stop PF's qm queues */
spin_lock_bh(&qm_lock);
b_rc = qed_send_qm_stop_cmd(p_hwfn, p_ptt, false, true,
qm_info->start_pq, qm_info->num_pqs);
spin_unlock_bh(&qm_lock);
if (!b_rc)
return -EINVAL;
/* clear the QM_PF runtime phase leftovers from previous init */
qed_init_clear_rt_data(p_hwfn);
/* prepare QM portion of runtime array */
qed_qm_init_pf(p_hwfn);
/* activate init tool on runtime array */
rc = qed_init_run(p_hwfn, p_ptt, PHASE_QM_PF, p_hwfn->rel_pf_id,
p_hwfn->hw_info.hw_mode);
if (rc)
return rc;
/* start PF's qm queues */
spin_lock_bh(&qm_lock);
b_rc = qed_send_qm_stop_cmd(p_hwfn, p_ptt, true, true,
qm_info->start_pq, qm_info->num_pqs);
spin_unlock_bh(&qm_lock);
if (!b_rc)
return -EINVAL;
return 0;
}
int qed_resc_alloc(struct qed_dev *cdev)
{
struct qed_consq *p_consq;
......@@ -375,6 +443,14 @@ int qed_resc_alloc(struct qed_dev *cdev)
"Failed to allocate memory for dmae_info structure\n");
goto alloc_err;
}
/* DCBX initialization */
rc = qed_dcbx_info_alloc(p_hwfn);
if (rc) {
DP_NOTICE(p_hwfn,
"Failed to allocate memory for dcbx structure\n");
goto alloc_err;
}
}
cdev->reset_stats = kzalloc(sizeof(*cdev->reset_stats), GFP_KERNEL);
......@@ -780,6 +856,11 @@ int qed_hw_init(struct qed_dev *cdev,
p_hwfn->first_on_engine = (load_code ==
FW_MSG_CODE_DRV_LOAD_ENGINE);
if (!qm_lock_init) {
spin_lock_init(&qm_lock);
qm_lock_init = true;
}
switch (load_code) {
case FW_MSG_CODE_DRV_LOAD_ENGINE:
rc = qed_hw_init_common(p_hwfn, p_hwfn->p_main_ptt,
......@@ -821,6 +902,20 @@ int qed_hw_init(struct qed_dev *cdev,
return mfw_rc;
}
/* send DCBX attention request command */
DP_VERBOSE(p_hwfn,
QED_MSG_DCB,
"sending phony dcbx set command to trigger DCBx attention handling\n");
mfw_rc = qed_mcp_cmd(p_hwfn, p_hwfn->p_main_ptt,
DRV_MSG_CODE_SET_DCBX,
1 << DRV_MB_PARAM_DCBX_NOTIFY_SHIFT,
&load_code, &param);
if (mfw_rc) {
DP_NOTICE(p_hwfn,
"Failed to send DCBX attention request\n");
return mfw_rc;
}
p_hwfn->hw_init_done = true;
}
......
......@@ -634,6 +634,14 @@ struct pf_start_ramrod_data {
u8 reserved0[4];
};
/* Data for port update ramrod */
struct protocol_dcb_data {
u8 dcb_enable_flag;
u8 dcb_priority;
u8 dcb_tc;
u8 reserved;
};
/* tunnel configuration */
struct pf_update_tunnel_config {
u8 update_rx_pf_clss;
......@@ -656,8 +664,17 @@ struct pf_update_tunnel_config {
};
struct pf_update_ramrod_data {
u32 reserved[2];
u32 reserved_1[6];
u8 pf_id;
u8 update_eth_dcb_data_flag;
u8 update_fcoe_dcb_data_flag;
u8 update_iscsi_dcb_data_flag;
u8 update_roce_dcb_data_flag;
u8 update_mf_vlan_flag;
__le16 mf_vlan;
struct protocol_dcb_data eth_dcb_data;
struct protocol_dcb_data fcoe_dcb_data;
struct protocol_dcb_data iscsi_dcb_data;
struct protocol_dcb_data roce_dcb_data;
struct pf_update_tunnel_config tunnel_config;
};
......
......@@ -15,6 +15,7 @@
#include <linux/spinlock.h>
#include <linux/string.h>
#include "qed.h"
#include "qed_dcbx.h"
#include "qed_hsi.h"
#include "qed_hw.h"
#include "qed_mcp.h"
......@@ -825,6 +826,18 @@ int qed_mcp_handle_events(struct qed_hwfn *p_hwfn,
case MFW_DRV_MSG_VF_DISABLED:
qed_mcp_handle_vf_flr(p_hwfn, p_ptt);
break;
case MFW_DRV_MSG_LLDP_DATA_UPDATED:
qed_dcbx_mib_update_event(p_hwfn, p_ptt,
QED_DCBX_REMOTE_LLDP_MIB);
break;
case MFW_DRV_MSG_DCBX_REMOTE_MIB_UPDATED:
qed_dcbx_mib_update_event(p_hwfn, p_ptt,
QED_DCBX_REMOTE_MIB);
break;
case MFW_DRV_MSG_DCBX_OPERATIONAL_MIB_UPDATED:
qed_dcbx_mib_update_event(p_hwfn, p_ptt,
QED_DCBX_OPERATIONAL_MIB);
break;
case MFW_DRV_MSG_TRANSCEIVER_STATE_CHANGE:
qed_mcp_handle_transceiver_change(p_hwfn, p_ptt);
break;
......
......@@ -353,6 +353,19 @@ int qed_sp_pf_start(struct qed_hwfn *p_hwfn,
struct qed_tunn_start_params *p_tunn,
enum qed_mf_mode mode, bool allow_npar_tx_switch);
/**
* @brief qed_sp_pf_update - PF Function Update Ramrod
*
* This ramrod updates function-related parameters. Every parameter can be
* updated independently, according to configuration flags.
*
* @param p_hwfn
*
* @return int
*/
int qed_sp_pf_update(struct qed_hwfn *p_hwfn);
/**
* @brief qed_sp_pf_stop - PF Function Stop Ramrod
*
......
......@@ -15,6 +15,7 @@
#include "qed.h"
#include <linux/qed/qed_chain.h>
#include "qed_cxt.h"
#include "qed_dcbx.h"
#include "qed_hsi.h"
#include "qed_hw.h"
#include "qed_int.h"
......@@ -384,6 +385,30 @@ int qed_sp_pf_start(struct qed_hwfn *p_hwfn,
return rc;
}
int qed_sp_pf_update(struct qed_hwfn *p_hwfn)
{
struct qed_spq_entry *p_ent = NULL;
struct qed_sp_init_data init_data;
int rc = -EINVAL;
/* Get SPQ entry */
memset(&init_data, 0, sizeof(init_data));
init_data.cid = qed_spq_get_cid(p_hwfn);
init_data.opaque_fid = p_hwfn->hw_info.opaque_fid;
init_data.comp_mode = QED_SPQ_MODE_CB;
rc = qed_sp_init_request(p_hwfn, &p_ent,
COMMON_RAMROD_PF_UPDATE, PROTOCOLID_COMMON,
&init_data);
if (rc)
return rc;
qed_dcbx_set_pf_update_params(&p_hwfn->p_dcbx_info->results,
&p_ent->ramrod.pf_update);
return qed_spq_post(p_hwfn, p_ent, NULL);
}
/* Set pf update ramrod command params */
int qed_sp_pf_update_tunn_cfg(struct qed_hwfn *p_hwfn,
struct qed_tunn_update_params *p_tunn,
......
......@@ -25,6 +25,15 @@
#include <linux/qed/common_hsi.h>
#include <linux/qed/qed_chain.h>
enum dcbx_protocol_type {
DCBX_PROTOCOL_ISCSI,
DCBX_PROTOCOL_FCOE,
DCBX_PROTOCOL_ROCE,
DCBX_PROTOCOL_ROCE_V2,
DCBX_PROTOCOL_ETH,
DCBX_MAX_PROTOCOL_TYPE
};
enum qed_led_mode {
QED_LED_MODE_OFF,
QED_LED_MODE_ON,
......
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