// SPDX-License-Identifier: GPL-2.0-only
/* Huawei HiNIC PCI Express Linux driver
* Copyright(c) 2017 Huawei Technologies Co., Ltd
*/
#include <linux/pci.h>
#include <linux/if_vlan.h>
#include <linux/interrupt.h>
#include <linux/etherdevice.h>
#include <linux/netdevice.h>
#include "hinic_hw_dev.h"
#include "hinic_dev.h"
#include "hinic_hw_mbox.h"
#include "hinic_hw_cmdq.h"
#include "hinic_port.h"
#include "hinic_sriov.h"
static unsigned char set_vf_link_state;
module_param(set_vf_link_state, byte, 0444);
MODULE_PARM_DESC(set_vf_link_state, "Set vf link state, 0 represents link auto, 1 represents link always up, 2 represents link always down. - default is 0.");
#define HINIC_VLAN_PRIORITY_SHIFT 13
#define HINIC_ADD_VLAN_IN_MAC 0x8000
#define HINIC_TX_RATE_TABLE_FULL 12
static int hinic_set_mac(struct hinic_hwdev *hwdev, const u8 *mac_addr,
u16 vlan_id, u16 func_id)
{
struct hinic_port_mac_cmd mac_info = {0};
u16 out_size = sizeof(mac_info);
int err;
mac_info.func_idx = func_id;
mac_info.vlan_id = vlan_id;
memcpy(mac_info.mac, mac_addr, ETH_ALEN);
err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_SET_MAC, &mac_info,
sizeof(mac_info), &mac_info, &out_size);
if (err || out_size != sizeof(mac_info) ||
(mac_info.status && mac_info.status != HINIC_PF_SET_VF_ALREADY &&
mac_info.status != HINIC_MGMT_STATUS_EXIST)) {
dev_err(&hwdev->func_to_io.hwif->pdev->dev, "Failed to set MAC, err: %d, status: 0x%x, out size: 0x%x\n",
err, mac_info.status, out_size);
return -EIO;
}
return 0;
}
static void hinic_notify_vf_link_status(struct hinic_hwdev *hwdev, u16 vf_id,
u8 link_status)
{
struct vf_data_storage *vf_infos = hwdev->func_to_io.vf_infos;
struct hinic_port_link_status link = {0};
u16 out_size = sizeof(link);
int err;
if (vf_infos[HW_VF_ID_TO_OS(vf_id)].registered) {
link.link = link_status;
link.func_id = hinic_glb_pf_vf_offset(hwdev->hwif) + vf_id;
err = hinic_mbox_to_vf(hwdev, HINIC_MOD_L2NIC,
vf_id,