// SPDX-License-Identifier: GPL-2.0-only
/*
* Huawei HiNIC PCI Express Linux driver
* Copyright(c) 2017 Huawei Technologies Co., Ltd
*/
#include <linux/types.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/if_vlan.h>
#include <linux/pci.h>
#include <linux/device.h>
#include <linux/errno.h>
#include "hinic_hw_if.h"
#include "hinic_hw_dev.h"
#include "hinic_port.h"
#include "hinic_dev.h"
#define HINIC_MIN_MTU_SIZE 256
#define HINIC_MAX_JUMBO_FRAME_SIZE 15872
enum mac_op {
MAC_DEL,
MAC_SET,
};
/**
* change_mac - change(add or delete) mac address
* @nic_dev: nic device
* @addr: mac address
* @vlan_id: vlan number to set with the mac
* @op: add or delete the mac
*
* Return 0 - Success, negative - Failure
**/
static int change_mac(struct hinic_dev *nic_dev, const u8 *addr,
u16 vlan_id, enum mac_op op)
{
struct hinic_hwdev *hwdev = nic_dev->hwdev;
struct hinic_port_mac_cmd port_mac_cmd;
struct hinic_hwif *hwif = hwdev->hwif;
u16 out_size = sizeof(port_mac_cmd);
struct pci_dev *pdev = hwif->pdev;
enum hinic_port_cmd cmd;
int err;
if (op == MAC_SET)
cmd = HINIC_PORT_CMD_SET_MAC;
else
cmd = HINIC_PORT_CMD_DEL_MAC;
port_mac_cmd.func_idx = HINIC_HWIF_FUNC_IDX(hwif);
port_mac_cmd.vlan_id = vlan_id;
memcpy(port_mac_cmd.mac, addr, ETH_ALEN);
err = hinic_port_msg_cmd(hwdev, cmd, &port_mac_cmd,
sizeof(port_mac_cmd),
&port_mac_cmd, &out_size);
if (err || out_size != sizeof(port_mac_cmd) ||
(port_mac_cmd.status &&
port_mac_cmd.status != HINIC_PF_SET_VF_ALREADY &&
port_mac_cmd.status != HINIC_MGMT_STATUS_EXIST)) {
dev_err(&pdev->dev, "Failed to change MAC, ret = %d\n",
port_mac_cmd.status);
return -EFAULT;
}
if (port_mac_cmd.status == HINIC_PF_SET_VF_ALREADY) {
dev_warn(&pdev->dev, "PF has already set VF mac, ignore %s operation\n",
(op == MAC_SET) ? "set" : "del");
return HINIC_PF_SET_VF_ALREADY;
}
if (cmd == HINIC_PORT_CMD_SET_MAC && port_mac_cmd.status ==
HINIC_MGMT_STATUS_EXIST)
dev_warn(&pdev->dev, "MAC is repeated, ignore set operation\n");
return 0;
}
/**
* hinic_port_add_mac - add mac address
* @nic_dev: nic device
* @addr: mac address
* @vlan_id: vlan number to set with the mac
*
* Return 0 - Success, negative - Failure
**/
int hinic_port_add_mac(struct hinic_dev *nic_dev,
const u8 *addr, u16 vlan_id)
{
return change_mac(nic_dev, addr, vlan_id, MAC_SET);
}
/**