linux/drivers/net/ethernet/intel/ice/ice_switch.c

145 lines
4.3 KiB
C
Raw Normal View History

2018-03-20 22:58:08 +08:00
// 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;
}