/*******************************************************************************
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*
* Copyright 2014 QLogic Corporation
* The contents of this file are subject to the terms of the
* QLogic End User License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the License at
* See the License for the specific language governing permissions
* and limitations under the License.
*
*
* Module Description:
* This file contains functions that implement SR-IOV virtualization on
* the PF side
*
******************************************************************************/
#ifdef VF_INVOLVED
#include "lm5710.h"
#include "lm_vf.h"
#include "577xx_int_offsets.h"
#include "command.h"
struct vf_pf_msg_hdr *lm_pf_validate_request_header(struct _lm_device_t *pdev, lm_vf_info_t *vf_info, void * virt_buffer)
{
}
return req_hdr;
}
{
} else {
}
return vf_info;
}
{
DbgMessage(pdev, WARN, "lm_pf_find_vf_info_by_abs_id: abs_vf_id:%d(%d)\n",abs_vf_id,pdev->hw_info.sriov_info.first_vf_in_pf);
DbgBreak();
}
} else {
DbgMessage(pdev, FATAL, "lm_pf_find_vf_info_by_abs_id: VF[a:%d,r:%d] is not enabled\n",abs_vf_id,relative_vf_id);
}
return vf_info;
}
lm_status_t lm_pf_download_standard_request(struct _lm_device_t *pdev, lm_vf_info_t *vf_info, void* virt_buffer, u32_t length)
{
DbgMessage(pdev, FATAL, "PFVF request with invalid parameters: %p, %p, %p, d\n", pdev,vf_info,virt_buffer,length);
return LM_STATUS_INVALID_PARAMETER;
}
DbgMessage(pdev, FATAL, "VF[%d] does not expect PFVF request (%d)\n", vf_info->relative_vf_id, vf_info->pf_vf_response.req_resp_state);
return LM_STATUS_FAILURE;
}
//requst_hdr = (struct vf_pf_msg_hdr *)virt_buffer;
if (length >= sizeof(struct vf_pf_msg_hdr)) {
if (requst_hdr != NULL) {
}
} else {
DbgMessage(pdev, FATAL, "VF[%d] received too short(%d) PFVF request\n", vf_info->relative_vf_id, length);
}
} else {
}
if (requst_hdr != NULL) {
mm_memcpy((u8_t*)vf_info->pf_vf_response.request_virt_addr + vf_info->pf_vf_response.request_offset, virt_buffer, length);
DbgMessage(pdev, WARN, "VF[%d]: lm_pf_download_standard_request: %d bytes from offset %d\n", vf_info->relative_vf_id,
} else {
vf_info->pf_vf_response.response_virt_addr = (u8_t*)vf_info->pf_vf_response.request_virt_addr + requst_hdr->resp_msg_offset;
}
} else {
}
} else {
}
return lm_status;
}
lm_status_t lm_pf_upload_standard_response(struct _lm_device_t *pdev, lm_vf_info_t *vf_info, void* virt_buffer, u32_t length)
{
DbgMessage(pdev, FATAL, "PFVF rresponse with invalid parameters: %p, %p, %p, d\n", pdev,vf_info,virt_buffer,length);
return LM_STATUS_INVALID_PARAMETER;
}
if (length < sizeof(struct pf_vf_msg_resp))
{
}
DbgMessage(pdev, WARN, "VF[%d]:lm_pf_upload_standard_response (LM_STATUS_FAILURE)\n",vf_info->relative_vf_id);
break;
if (length > sizeof(struct pf_vf_msg_resp))
{
length = sizeof(struct pf_vf_msg_resp);
}
break;
case VF_PF_RESPONSE_READY:
if (length <= response_rest) {
} else {
}
mm_memcpy(virt_buffer, (u8_t*)vf_info->pf_vf_response.response_virt_addr + vf_info->pf_vf_response.response_offset, length);
DbgMessage(pdev, WARN, "VF[%d]:lm_pf_upload_standard_response: %d bytes from offset %d\n",vf_info->relative_vf_id,length,
{
}
break;
default:
DbgBreak();
}
return lm_status;
}
lm_status_t lm_pf_upload_standard_request(struct _lm_device_t *pdev, lm_vf_info_t *vf_info, lm_address_t * phys_buffer, u32_t length)
{
return lm_status;
}
{
{
return LM_STATUS_INVALID_PARAMETER ;
}
if (!num_vfs) {
return LM_STATUS_FAILURE;
} else {
}
{
return LM_STATUS_RESOURCE ;
}
pdev->vfs_set.req_resp_size = (((sizeof(union vf_pf_msg) + CACHE_LINE_SIZE_MASK) & ~CACHE_LINE_SIZE_MASK)
{
return LM_STATUS_RESOURCE;
}
pdev->vfs_set.pf_fw_stats_set_data_sz = ((sizeof(struct per_queue_stats) + CACHE_LINE_SIZE_MASK) & ~CACHE_LINE_SIZE_MASK) * num_vfs;
pdev->vfs_set.pf_fw_stats_set_virt_data = mm_alloc_phys_mem(pdev, pdev->vfs_set.pf_fw_stats_set_data_sz,
{
return LM_STATUS_RESOURCE;
}
{
return LM_STATUS_RESOURCE ;
}
pdev->vfs_set.rss_update_size = ((sizeof(struct eth_rss_update_ramrod_data) + CACHE_LINE_SIZE_MASK) & ~CACHE_LINE_SIZE_MASK) * num_vfs;
{
return LM_STATUS_RESOURCE;
}
DbgMessage(pdev, WARN, "SRIOV enable(after FLR): init %d VFs: status %d\n",pdev->hw_info.sriov_info.num_vfs,lm_status);
if(lm_status != LM_STATUS_SUCCESS) {
DbgBreak();
return lm_status;
} else {
#if 0
if(lm_status != LM_STATUS_SUCCESS) {
DbgBreak();
return lm_status;
}
#endif
}
}
}
return lm_status;
}
{
DbgBreakIf(!(pdev && num_vfs && pdev->vfs_set.vfs_array && pdev->vfs_set.req_resp_virt_addr && pdev->vfs_set.pf_fw_stats_set_virt_data));
pdev->vfs_set.vfs_array[vf_idx].abs_vf_id = (u8_t)(vf_idx + pdev->hw_info.sriov_info.first_vf_in_pf);
}
pdev->vfs_set.vfs_array[vf_idx].vf_stats.pf_fw_stats_virt_data = (struct per_queue_stats *)mem_virt;
mem_virt += stats_size;
pdev->vfs_set.vfs_array[vf_idx].vf_stats.mirror_stats_fw = pdev->vfs_set.mirror_stats_fw_set + sizeof(lm_stats_fw_t) * vf_idx;
}
rss_upd_size = (sizeof(struct eth_rss_update_ramrod_data) + CACHE_LINE_SIZE_MASK) & ~CACHE_LINE_SIZE_MASK;
pdev->vfs_set.vfs_array[vf_idx].vf_slowpath_info.slowpath_data.rss_rdata = (struct eth_rss_update_ramrod_data *)mem_virt;
mem_virt += rss_upd_size;
}
return lm_status;
}
#if 0
{
/* TODO: Clean VF Database for FLR needs? */
DbgMessage(pf_dev, FATAL, "vf disable: clear VFs connections from %d till %d\n",start_cid, end_cid);
}
if (lm_is_function_after_flr(pf_dev)) {
return LM_STATUS_SUCCESS;
}
/* if MCP does not exist for each vf in pf, need to pretend to it and disable igu vf_msix and internal vfid enable bit */
}
/* This is a clear-on-write register, therefore we actually write 1 to the bit we want to reset */
//REG_WR(pf_dev, PGLUE_B_REG_DISABLE_FLR_SRIOV_DISABLED, PGLUE_B_DISABLE_FLR_SRIOV_DISABLED_REG_DISABLE_SRIOV_DISABLED_REQUEST);*/
}
return lm_status;
}
#endif
{
} else {
}
return lm_status;
}
{
} else {
}
return lm_status;
}
{
}
return is_mac_set;
}
{
} else {
}
return lm_status;
}
{
/* Either MP is disabled OR enabled but not a tx-only connection */
{
}
else
{
}
return client_info_idx;
}
{
} else {
}
return client_info_idx;
}
{
u8_t i,j;
for (j = 0; j < num; j++) {
ind = (i + j) / ELEM_OF_RES_ARRAY_SIZE_IN_BITS;
offset = (i+j) % ELEM_OF_RES_ARRAY_SIZE_IN_BITS;
break;
}
}
if (j == num) {
base_value = i;
break;
}
}
return base_value;
}
{
}
return;
}
{
return value;
}
{
}
return;
}
#ifndef ARRAY_SIZE
#endif
{
vf_info->num_allocated_chains = 0;
{
}
vf_info->vf_chains[chain_idx].sw_ndsb = lm_vf_get_free_resource(pdev->pf_resources.free_sbs, min_ndsb,
break;
}
#if 0
if (current_fw_client == 0xFF) {
break;
}
#endif
current_fw_client = vf_info->vf_chains[chain_idx].sw_client_id = lm_vf_get_free_resource(pdev->pf_resources.free_sw_clients, min_sw_client, client_info_entries, 1);
break;
}
vf_info->vf_chains[chain_idx].fw_qzone_id = LM_FW_DHC_QZONE_ID(pdev, vf_info->vf_chains[chain_idx].sw_ndsb);
}
if (vf_info->num_allocated_chains) {
lm_vf_acquire_resource(pdev->pf_resources.free_fw_clients, vf_info->vf_chains[chain_idx].fw_client_id - pdev->params.base_fw_client_id, 1);
lm_vf_acquire_resource(pdev->pf_resources.free_sw_clients, vf_info->vf_chains[chain_idx].sw_client_id, 1);
DbgMessage(pdev, WARN, "VF[%d(rel)] received resourses for chain %d: SW_NDSB=%d, FW_CLIENT_ID=%d, SW_CLIENT_ID=%d\n",
}
}
return vf_info->num_allocated_chains;
}
{
if (!vf_info->was_malicious)
{
{
lm_vf_release_resource(pdev->pf_resources.free_fw_clients, vf_info->vf_chains[chain_idx].fw_client_id - pdev->params.base_fw_client_id, 1);
lm_vf_release_resource(pdev->pf_resources.free_sw_clients, vf_info->vf_chains[chain_idx].sw_client_id, 1);
}
}
return;
}
void lm_pf_release_separate_vf_chain_resources(struct _lm_device_t *pdev, u16_t vf_id, u8_t chain_num)
{
if (!vf_info->was_malicious)
{
{
lm_vf_release_resource(pdev->pf_resources.free_fw_clients, vf_info->vf_chains[chain_num].fw_client_id - pdev->params.base_fw_client_id, 1);
lm_vf_release_resource(pdev->pf_resources.free_sw_clients, vf_info->vf_chains[chain_num].sw_client_id, 1);
}
}
return;
}
{
if (!CHIP_IS_E1(pdev))
{
}
return;
}
{
return;
}
{
}
lm_status_t lm_pf_init_vf_client_init_data(struct _lm_device_t *pdev, lm_vf_info_t *vf_info, u8_t q_id,
struct sw_vf_pf_rxq_params * rxq_params,
struct sw_vf_pf_txq_params * txq_params)
{
struct client_init_ramrod_data *
client_init_data_virt = &(pdev->client_info[LM_SW_VF_CLI_ID(vf_info,q_id)].client_init_data_virt->init_data);
{
return LM_STATUS_FAILURE;
}
/* General Structure */
client_init_data_virt->general.cos = 0;//The connection cos, if applicable only if STATIC_COS is set
client_init_data_virt->rx.status_block_id = LM_FW_VF_SB_ID(vf_info,q_id); //LM_FW_VF_SB_ID(vf_info, LM_VF_Q_TO_SB_ID(vf_info,q_id));
// client_init_data_virt->rx.tpa_en_flg = FALSE;
} else {
client_init_data_virt->rx.cache_line_alignment_log_size = (u8_t)LOG2(CACHE_LINE_SIZE/* TODO mm_get_cache_line_alignment()*/);
}
{
} else {
{
}
}
}
else
{
}
client_init_data_virt->rx.state = CLIENT_INIT_RX_DATA_ACCEPT_ANY_VLAN; /*If VF L2 client established without "accept_any_vlan" flag, the firmware is trying */
client_init_data_virt->tx.state = CLIENT_INIT_TX_DATA_ACCEPT_ANY_VLAN; /*to match packets with both MAC and VLAN, fails and send the packet to
the network (transfer leakage).
The "accept_any_vlan" is only set later in the "set rx mode" command,
and then the TX-switching is working again.*/
if (!q_id) {
}
client_init_data_virt->rx.max_bytes_on_bd = mm_cpu_to_le16((rxq_params->buf_sz) - (pdev)->params.rcv_buffer_offset);
/* Status block index init we do for Rx + Tx together so that we ask which cid we are only once */
/* TX Data (remaining , sb index above...) */
/* ooo cid doesn't have a tx chain... */
/* Tx Switching... */
#ifdef __LINUX
#else
#endif
/* FC */
#if 0
{
}
#endif
// for encapsulated packets
// the hw ip id will be the inner ip id, the hw will incremnet the inner ip id
// this means that if the outer ip header is ipv4, its ip id will not be incremented.
// In case of non-Lso encapsulated packets with L4 checksum offload, the pseudo checksum location - on BD
// In case of non-Lso encapsulated packets with outer L3 ip checksum offload, the pseudo checksum location - on BD
return lm_status;
}
{
} else {
}
} else {
}
return res;
}
{
{
DbgBreak();
return 0;
}
if (vf_info->num_igu_sb_available == 0)
{
return 0;
}
{
starting_from = vf_info->vf_chains[idx].igu_sb_id = lm_pf_get_next_free_igu_block_id(pdev, starting_from);
if (starting_from == 0xFF)
{
break;
}
}
#if 0
vf_info->num_igu_sb_available = pdev->hw_info.intr_blk_info.igu_info.vf_igu_info[vf_info->abs_vf_id].igu_sb_cnt;
{
vf_info->vf_chains[idx].igu_sb_id = pdev->hw_info.intr_blk_info.igu_info.vf_igu_info[vf_info->abs_vf_id].igu_base_sb + idx;
}
#endif
return num_of_vf_desired_vf_chains;
}
{
return;
}
{
return max_igu_sbs;
}
{
{
{
{
break;
}
}
}
return igu_free_sb_id;
}
{
{
{
{
}
}
}
return;
}
{
if (!(lm_igu_sb->status & LM_IGU_STATUS_PF) && (lm_igu_sb->status & LM_IGU_STATUS_AVAILABLE) && (igu_sb_idx < IGU_REG_MAPPING_MEMORY_SIZE))
{
}
else
{
DbgBreak();
}
return res;
}
u8_t lm_pf_acquire_vf_igu_block(lm_device_t *pdev, u8_t igu_sb_idx, u8_t abs_vf_id, u8_t vector_number)
{
{
}
else
{
DbgBreak();
}
return res;
}
{
{
{
{
}
}
}
return available_igu_sbs;
}
lm_status_t lm_pf_update_vf_default_vlan(IN struct _lm_device_t *pdev, IN struct _lm_vf_info_t * vf_info,
{
{
DbgBreak();
return LM_STATUS_FAILURE;
}
DbgBreakIf( LM_CLI_UPDATE_NOT_USED != pdev->client_info[LM_SW_VF_CLI_ID(vf_info, q_idx)].update.state);
type,
if (lm_status != LM_STATUS_SUCCESS)
{
return lm_status;
}
lm_status = lm_wait_state_change(pdev, &pdev->client_info[LM_SW_VF_CLI_ID(vf_info, q_idx)].update.state, LM_CLI_UPDATE_RECV);
}
return lm_status;
}
{
switch (interrupt_mod_level)
{
case VPORT_INT_MOD_UNDEFINED:
dhc_timeout = 0;
hc_tx_timeout = (u8_t)(ic->hc_usec_c_sb[HC_INDEX_VF_ETH_TX_CQ_CONS - HC_USTORM_SB_NUM_INDICES] / HC_TIMEOUT_RESOLUTION_IN_US);
break;
case VPORT_INT_MOD_ADAPTIVE:
hc_tx_timeout = (u8_t)(ic->hc_usec_c_sb[HC_INDEX_VF_ETH_TX_CQ_CONS - HC_USTORM_SB_NUM_INDICES] / HC_TIMEOUT_RESOLUTION_IN_US);
break;
case VPORT_INT_MOD_OFF:
dhc_timeout = 0;
hc_rx_timeout = 0;
hc_tx_timeout = 0;
break;
case VPORT_INT_MOD_LOW:
dhc_timeout = 0;
break;
case VPORT_INT_MOD_MEDIUM:
dhc_timeout = 0;
break;
case VPORT_INT_MOD_HIGH:
dhc_timeout = 0;
break;
default:
DbgBreak();
break;
}
if (lm_status == LM_STATUS_SUCCESS)
{
if (dhc_timeout)
{
dhc_enable = TRUE;
REG_WR(PFDEV(pdev), CSEM_REG_FAST_MEMORY + CSTORM_BYTE_COUNTER_OFFSET(LM_FW_VF_DHC_QZONE_ID(vf_info, relative_in_vf_ndsb), HC_INDEX_VF_ETH_RX_CQ_CONS), 0);
}
else
{
dhc_enable = FALSE;
}
lm_setup_ndsb_index(pdev, LM_SW_VF_SB_ID(vf_info,relative_in_vf_ndsb), HC_INDEX_VF_ETH_RX_CQ_CONS, SM_RX_ID, timeout, dhc_enable);
lm_setup_ndsb_index(pdev, LM_SW_VF_SB_ID(vf_info,relative_in_vf_ndsb), HC_INDEX_VF_ETH_TX_CQ_CONS, SM_TX_ID, hc_tx_timeout, FALSE);
LM_INTMEM_WRITE32(pdev, CSTORM_STATUS_BLOCK_DATA_OFFSET(LM_FW_VF_SB_ID(vf_info, relative_in_vf_ndsb)) + sizeof(u32_t)*index,
*((u32_t*)(&pdev->vars.status_blocks_arr[LM_SW_VF_SB_ID(vf_info,relative_in_vf_ndsb)].hc_status_block_data.e2_sb_data) + index), BAR_CSTRORM_INTMEM);
}
}
return lm_status;
}
{
{
}
else
{
}
switch (interrupt_mod_level)
{
case VPORT_INT_MOD_OFF:
break;
case VPORT_INT_MOD_UNDEFINED:
{
}
case VPORT_INT_MOD_ADAPTIVE:
case VPORT_INT_MOD_LOW:
case VPORT_INT_MOD_MEDIUM:
case VPORT_INT_MOD_HIGH:
if (!is_hc_available_on_host)
{
}
break;
default:
DbgBreak();
break;
}
if (lm_status != LM_STATUS_SUCCESS)
{
return lm_status;
}
{
if ((interrupt_mod_level == VPORT_INT_MOD_ADAPTIVE) && !pdev->client_info[LM_SW_VF_CLI_ID(vf_info,q_idx)].client_init_data_virt->init_data.rx.enable_dynamic_hc)
{
}
}
return lm_status;
}
#endif //VF_INVOLVED