mirror of https://gitee.com/openkylin/linux.git
145 lines
4.3 KiB
C
145 lines
4.3 KiB
C
|
// SPDX-License-Identifier: GPL-2.0
|
||
|
/* Copyright (c) 2018, Intel Corporation. */
|
||
|
|
||
|
#include "ice_switch.h"
|
||
|
|
||
|
/**
|
||
|
* ice_aq_get_sw_cfg - get switch configuration
|
||
|
* @hw: pointer to the hardware structure
|
||
|
* @buf: pointer to the result buffer
|
||
|
* @buf_size: length of the buffer available for response
|
||
|
* @req_desc: pointer to requested descriptor
|
||
|
* @num_elems: pointer to number of elements
|
||
|
* @cd: pointer to command details structure or NULL
|
||
|
*
|
||
|
* Get switch configuration (0x0200) to be placed in 'buff'.
|
||
|
* This admin command returns information such as initial VSI/port number
|
||
|
* and switch ID it belongs to.
|
||
|
*
|
||
|
* NOTE: *req_desc is both an input/output parameter.
|
||
|
* The caller of this function first calls this function with *request_desc set
|
||
|
* to 0. If the response from f/w has *req_desc set to 0, all the switch
|
||
|
* configuration information has been returned; if non-zero (meaning not all
|
||
|
* the information was returned), the caller should call this function again
|
||
|
* with *req_desc set to the previous value returned by f/w to get the
|
||
|
* next block of switch configuration information.
|
||
|
*
|
||
|
* *num_elems is output only parameter. This reflects the number of elements
|
||
|
* in response buffer. The caller of this function to use *num_elems while
|
||
|
* parsing the response buffer.
|
||
|
*/
|
||
|
static enum ice_status
|
||
|
ice_aq_get_sw_cfg(struct ice_hw *hw, struct ice_aqc_get_sw_cfg_resp *buf,
|
||
|
u16 buf_size, u16 *req_desc, u16 *num_elems,
|
||
|
struct ice_sq_cd *cd)
|
||
|
{
|
||
|
struct ice_aqc_get_sw_cfg *cmd;
|
||
|
enum ice_status status;
|
||
|
struct ice_aq_desc desc;
|
||
|
|
||
|
ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_sw_cfg);
|
||
|
cmd = &desc.params.get_sw_conf;
|
||
|
cmd->element = cpu_to_le16(*req_desc);
|
||
|
|
||
|
status = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd);
|
||
|
if (!status) {
|
||
|
*req_desc = le16_to_cpu(cmd->element);
|
||
|
*num_elems = le16_to_cpu(cmd->num_elems);
|
||
|
}
|
||
|
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
/* ice_init_port_info - Initialize port_info with switch configuration data
|
||
|
* @pi: pointer to port_info
|
||
|
* @vsi_port_num: VSI number or port number
|
||
|
* @type: Type of switch element (port or VSI)
|
||
|
* @swid: switch ID of the switch the element is attached to
|
||
|
* @pf_vf_num: PF or VF number
|
||
|
* @is_vf: true if the element is a VF, false otherwise
|
||
|
*/
|
||
|
static void
|
||
|
ice_init_port_info(struct ice_port_info *pi, u16 vsi_port_num, u8 type,
|
||
|
u16 swid, u16 pf_vf_num, bool is_vf)
|
||
|
{
|
||
|
switch (type) {
|
||
|
case ICE_AQC_GET_SW_CONF_RESP_PHYS_PORT:
|
||
|
pi->lport = (u8)(vsi_port_num & ICE_LPORT_MASK);
|
||
|
pi->sw_id = swid;
|
||
|
pi->pf_vf_num = pf_vf_num;
|
||
|
pi->is_vf = is_vf;
|
||
|
pi->dflt_tx_vsi_num = ICE_DFLT_VSI_INVAL;
|
||
|
pi->dflt_rx_vsi_num = ICE_DFLT_VSI_INVAL;
|
||
|
break;
|
||
|
default:
|
||
|
ice_debug(pi->hw, ICE_DBG_SW,
|
||
|
"incorrect VSI/port type received\n");
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* ice_get_initial_sw_cfg - Get initial port and default VSI data
|
||
|
* @hw: pointer to the hardware structure
|
||
|
*/
|
||
|
enum ice_status ice_get_initial_sw_cfg(struct ice_hw *hw)
|
||
|
{
|
||
|
struct ice_aqc_get_sw_cfg_resp *rbuf;
|
||
|
enum ice_status status;
|
||
|
u16 req_desc = 0;
|
||
|
u16 num_elems;
|
||
|
u16 i;
|
||
|
|
||
|
rbuf = devm_kzalloc(ice_hw_to_dev(hw), ICE_SW_CFG_MAX_BUF_LEN,
|
||
|
GFP_KERNEL);
|
||
|
|
||
|
if (!rbuf)
|
||
|
return ICE_ERR_NO_MEMORY;
|
||
|
|
||
|
/* Multiple calls to ice_aq_get_sw_cfg may be required
|
||
|
* to get all the switch configuration information. The need
|
||
|
* for additional calls is indicated by ice_aq_get_sw_cfg
|
||
|
* writing a non-zero value in req_desc
|
||
|
*/
|
||
|
do {
|
||
|
status = ice_aq_get_sw_cfg(hw, rbuf, ICE_SW_CFG_MAX_BUF_LEN,
|
||
|
&req_desc, &num_elems, NULL);
|
||
|
|
||
|
if (status)
|
||
|
break;
|
||
|
|
||
|
for (i = 0; i < num_elems; i++) {
|
||
|
struct ice_aqc_get_sw_cfg_resp_elem *ele;
|
||
|
u16 pf_vf_num, swid, vsi_port_num;
|
||
|
bool is_vf = false;
|
||
|
u8 type;
|
||
|
|
||
|
ele = rbuf[i].elements;
|
||
|
vsi_port_num = le16_to_cpu(ele->vsi_port_num) &
|
||
|
ICE_AQC_GET_SW_CONF_RESP_VSI_PORT_NUM_M;
|
||
|
|
||
|
pf_vf_num = le16_to_cpu(ele->pf_vf_num) &
|
||
|
ICE_AQC_GET_SW_CONF_RESP_FUNC_NUM_M;
|
||
|
|
||
|
swid = le16_to_cpu(ele->swid);
|
||
|
|
||
|
if (le16_to_cpu(ele->pf_vf_num) &
|
||
|
ICE_AQC_GET_SW_CONF_RESP_IS_VF)
|
||
|
is_vf = true;
|
||
|
|
||
|
type = le16_to_cpu(ele->vsi_port_num) >>
|
||
|
ICE_AQC_GET_SW_CONF_RESP_TYPE_S;
|
||
|
|
||
|
if (type == ICE_AQC_GET_SW_CONF_RESP_VSI) {
|
||
|
/* FW VSI is not needed. Just continue. */
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
ice_init_port_info(hw->port_info, vsi_port_num,
|
||
|
type, swid, pf_vf_num, is_vf);
|
||
|
}
|
||
|
} while (req_desc && !status);
|
||
|
|
||
|
devm_kfree(ice_hw_to_dev(hw), (void *)rbuf);
|
||
|
return status;
|
||
|
}
|