/*
* Huawei HiNIC PCI Express Linux driver
* Copyright(c) 2017 Huawei Technologies Co., Ltd
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/pci.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/etherdevice.h>
#include <linux/netdevice.h>
#include <linux/slab.h>
#include <linux/if_vlan.h>
#include <linux/semaphore.h>
#include <linux/workqueue.h>
#include <net/ip.h>
#include <linux/bitops.h>
#include <linux/bitmap.h>
#include <linux/delay.h>
#include <linux/err.h>
#include "hinic_hw_qp.h"
#include "hinic_hw_dev.h"
#include "hinic_port.h"
#include "hinic_tx.h"
#include "hinic_rx.h"
#include "hinic_dev.h"
MODULE_AUTHOR("Huawei Technologies CO., Ltd");
MODULE_DESCRIPTION("Huawei Intelligent NIC driver");
MODULE_LICENSE("GPL");
static unsigned int tx_weight = 64;
module_param(tx_weight, uint, 0644);
MODULE_PARM_DESC(tx_weight, "Number Tx packets for NAPI budget (default=64)");
static unsigned int rx_weight = 64;
module_param(rx_weight, uint, 0644);
MODULE_PARM_DESC(rx_weight, "Number Rx packets for NAPI budget (default=64)");
#define HINIC_DEV_ID_QUAD_PORT_25GE 0x1822
#define HINIC_DEV_ID_DUAL_PORT_25GE 0x0200
#define HINIC_DEV_ID_DUAL_PORT_100GE 0x0201
#define HINIC_WQ_NAME "hinic_dev"
#define MSG_ENABLE_DEFAULT (NETIF_MSG_DRV | NETIF_MSG_PROBE | \
NETIF_MSG_IFUP | \
NETIF_MSG_TX_ERR | NETIF_MSG_RX_ERR)
#define VLAN_BITMAP_SIZE(nic_dev) (ALIGN(VLAN_N_VID, 8) / 8)
#define work_to_rx_mode_work(work) \
container_of(work, struct hinic_rx_mode_work, work)
#define rx_mode_work_to_nic_dev(rx_mode_work) \
container_of(rx_mode_work, struct hinic_dev, rx_mode_work)
static int change_mac_addr(struct net_device *netdev, const u8 *addr);
static void set_link_speed(struct ethtool_link_ksettings *link_ksettings,
enum hinic_speed speed)
{
switch (speed) {
case HINIC_SPEED_10MB_LINK:
link_ksettings->base.speed = SPEED_10;
break;
case HINIC_SPEED_100MB_LINK:
link_ksettings->base.speed = SPEED_100;
break;
case HINIC_SPEED_1000MB_LINK:
link_ksettings->base.speed = SPEED_1000;
break;
case HINIC_SPEED_10GB_LINK:
link_ksettings->base.speed = SPEED_10000;
break;
case HINIC_SPEED_25GB_LINK:
link_ksettings->base.speed = SPEED_25000;
break;
case HINIC_SPEED_40GB_LINK:
link_ksettings->base.speed = SPEED_40000;
break;
case HINIC_SPEED_100GB_LINK:
link_ksettings->base.speed = SPEED_100000;
break;
default:
link_ksettings->base.speed = SPEED_UNKNOWN;
break;
}
}
static int hinic_get_link_ksettings(struct net_device *netdev,
struct ethtool_link_ksettings
*link_ksettings)
{
struct hinic_dev *nic_dev = netdev_priv(netdev);
enum hinic_port_link_state link_state;
struct hinic_port_cap port_cap;
int err;
ethtool_link_ksettings_zero_link_mode(link_ksettings, advertising);
ethtool_link_ksettings_add_link_mode(link_ksettings, supported,
Autoneg);
link_ksettings->base.speed = SPEED_UNKNOWN;
link_ksettings->base.autoneg = AUTONEG_DISABLE;
link_ksettings->base.duplex = DUPLEX_UNKNOWN;
err = hinic_port_get_cap(nic_dev, &port_cap);
if (err) {
netif_err(nic_dev, drv, netdev,
"Failed to get port capabilities\n");
return err;
}
err = hinic_port_link_state(nic_dev, &link_state);
if (err) {
netif_err(nic_dev, drv, netdev,
"Failed to get port link state\n");
return err;
}
if (link_state != HINIC_LINK_STATE_UP) {
netif_info(nic_dev, drv, netdev, "No link\n");