aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/drivers/net/ethernet/huawei/hinic/hinic_main.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/ethernet/huawei/hinic/hinic_main.c')
-rw-r--r--drivers/net/ethernet/huawei/hinic/hinic_main.c158
1 files changed, 127 insertions, 31 deletions
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_main.c b/drivers/net/ethernet/huawei/hinic/hinic_main.c
index 13560975c103..e9e6f4c9309a 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_main.c
+++ b/drivers/net/ethernet/huawei/hinic/hinic_main.c
@@ -29,6 +29,7 @@
#include "hinic_tx.h"
#include "hinic_rx.h"
#include "hinic_dev.h"
+#include "hinic_sriov.h"
MODULE_AUTHOR("Huawei Technologies CO., Ltd");
MODULE_DESCRIPTION("Huawei Intelligent NIC driver");
@@ -46,6 +47,7 @@ MODULE_PARM_DESC(rx_weight, "Number Rx packets for NAPI budget (default=64)");
#define HINIC_DEV_ID_DUAL_PORT_100GE 0x0200
#define HINIC_DEV_ID_DUAL_PORT_100GE_MEZZ 0x0205
#define HINIC_DEV_ID_QUAD_PORT_25GE_MEZZ 0x0210
+#define HINIC_DEV_ID_VF 0x375e
#define HINIC_WQ_NAME "hinic_dev"
@@ -65,6 +67,8 @@ MODULE_PARM_DESC(rx_weight, "Number Rx packets for NAPI budget (default=64)");
#define rx_mode_work_to_nic_dev(rx_mode_work) \
container_of(rx_mode_work, struct hinic_dev, rx_mode_work)
+#define HINIC_WAIT_SRIOV_CFG_TIMEOUT 15000
+
static int change_mac_addr(struct net_device *netdev, const u8 *addr);
static int set_features(struct hinic_dev *nic_dev,
@@ -322,7 +326,6 @@ static void hinic_enable_rss(struct hinic_dev *nic_dev)
int i, node, err = 0;
u16 num_cpus = 0;
- nic_dev->max_qps = hinic_hwdev_max_num_qps(hwdev);
if (nic_dev->max_qps <= 1) {
nic_dev->flags &= ~HINIC_RSS_ENABLE;
nic_dev->rss_limit = nic_dev->max_qps;
@@ -368,14 +371,15 @@ static void hinic_enable_rss(struct hinic_dev *nic_dev)
netif_err(nic_dev, drv, netdev, "Failed to init rss\n");
}
-static int hinic_open(struct net_device *netdev)
+int hinic_open(struct net_device *netdev)
{
struct hinic_dev *nic_dev = netdev_priv(netdev);
enum hinic_port_link_state link_state;
int err, ret;
if (!(nic_dev->flags & HINIC_INTF_UP)) {
- err = hinic_hwdev_ifup(nic_dev->hwdev);
+ err = hinic_hwdev_ifup(nic_dev->hwdev, nic_dev->sq_depth,
+ nic_dev->rq_depth);
if (err) {
netif_err(nic_dev, drv, netdev,
"Failed - HW interface up\n");
@@ -423,9 +427,6 @@ static int hinic_open(struct net_device *netdev)
goto err_func_port_state;
}
- /* Wait up to 3 sec between port enable to link state */
- msleep(3000);
-
down(&nic_dev->mgmt_lock);
err = hinic_port_link_state(nic_dev, &link_state);
@@ -434,6 +435,9 @@ static int hinic_open(struct net_device *netdev)
goto err_port_link;
}
+ if (!HINIC_IS_VF(nic_dev->hwdev->hwif))
+ hinic_notify_all_vfs_link_changed(nic_dev->hwdev, link_state);
+
if (link_state == HINIC_LINK_STATE_UP)
nic_dev->flags |= HINIC_LINK_UP;
@@ -479,11 +483,10 @@ err_create_txqs:
return err;
}
-static int hinic_close(struct net_device *netdev)
+int hinic_close(struct net_device *netdev)
{
struct hinic_dev *nic_dev = netdev_priv(netdev);
unsigned int flags;
- int err;
down(&nic_dev->mgmt_lock);
@@ -497,20 +500,12 @@ static int hinic_close(struct net_device *netdev)
up(&nic_dev->mgmt_lock);
- err = hinic_port_set_func_state(nic_dev, HINIC_FUNC_PORT_DISABLE);
- if (err) {
- netif_err(nic_dev, drv, netdev,
- "Failed to set func port state\n");
- nic_dev->flags |= (flags & HINIC_INTF_UP);
- return err;
- }
+ if (!HINIC_IS_VF(nic_dev->hwdev->hwif))
+ hinic_notify_all_vfs_link_changed(nic_dev->hwdev, 0);
- err = hinic_port_set_state(nic_dev, HINIC_PORT_DISABLE);
- if (err) {
- netif_err(nic_dev, drv, netdev, "Failed to set port state\n");
- nic_dev->flags |= (flags & HINIC_INTF_UP);
- return err;
- }
+ hinic_port_set_state(nic_dev, HINIC_PORT_DISABLE);
+
+ hinic_port_set_func_state(nic_dev, HINIC_FUNC_PORT_DISABLE);
if (nic_dev->flags & HINIC_RSS_ENABLE) {
hinic_rss_deinit(nic_dev);
@@ -685,7 +680,7 @@ static int hinic_vlan_rx_add_vid(struct net_device *netdev,
}
err = hinic_port_add_mac(nic_dev, netdev->dev_addr, vid);
- if (err) {
+ if (err && err != HINIC_PF_SET_VF_ALREADY) {
netif_err(nic_dev, drv, netdev, "Failed to set mac\n");
goto err_add_mac;
}
@@ -737,8 +732,6 @@ static void set_rx_mode(struct work_struct *work)
struct hinic_rx_mode_work *rx_mode_work = work_to_rx_mode_work(work);
struct hinic_dev *nic_dev = rx_mode_work_to_nic_dev(rx_mode_work);
- netif_info(nic_dev, drv, nic_dev->netdev, "set rx mode work\n");
-
hinic_port_set_rx_mode(nic_dev, rx_mode_work->rx_mode);
__dev_uc_sync(nic_dev->netdev, add_mac_addr, remove_mac_addr);
@@ -757,10 +750,12 @@ static void hinic_set_rx_mode(struct net_device *netdev)
HINIC_RX_MODE_MC |
HINIC_RX_MODE_BC;
- if (netdev->flags & IFF_PROMISC)
- rx_mode |= HINIC_RX_MODE_PROMISC;
- else if (netdev->flags & IFF_ALLMULTI)
+ if (netdev->flags & IFF_PROMISC) {
+ if (!HINIC_IS_VF(nic_dev->hwdev->hwif))
+ rx_mode |= HINIC_RX_MODE_PROMISC;
+ } else if (netdev->flags & IFF_ALLMULTI) {
rx_mode |= HINIC_RX_MODE_MC_ALL;
+ }
rx_mode_work->rx_mode = rx_mode;
@@ -770,8 +765,26 @@ static void hinic_set_rx_mode(struct net_device *netdev)
static void hinic_tx_timeout(struct net_device *netdev, unsigned int txqueue)
{
struct hinic_dev *nic_dev = netdev_priv(netdev);
+ u16 sw_pi, hw_ci, sw_ci;
+ struct hinic_sq *sq;
+ u16 num_sqs, q_id;
+
+ num_sqs = hinic_hwdev_num_qps(nic_dev->hwdev);
netif_err(nic_dev, drv, netdev, "Tx timeout\n");
+
+ for (q_id = 0; q_id < num_sqs; q_id++) {
+ if (!netif_xmit_stopped(netdev_get_tx_queue(netdev, q_id)))
+ continue;
+
+ sq = hinic_hwdev_get_sq(nic_dev->hwdev, q_id);
+ sw_pi = atomic_read(&sq->wq->prod_idx) & sq->wq->mask;
+ hw_ci = be16_to_cpu(*(u16 *)(sq->hw_ci_addr)) & sq->wq->mask;
+ sw_ci = atomic_read(&sq->wq->cons_idx) & sq->wq->mask;
+ netif_err(nic_dev, drv, netdev, "Txq%d: sw_pi: %d, hw_ci: %d, sw_ci: %d, napi->state: 0x%lx\n",
+ q_id, sw_pi, hw_ci, sw_ci,
+ nic_dev->txqs[q_id].napi.state);
+ }
}
static void hinic_get_stats64(struct net_device *netdev,
@@ -837,6 +850,29 @@ static const struct net_device_ops hinic_netdev_ops = {
.ndo_get_stats64 = hinic_get_stats64,
.ndo_fix_features = hinic_fix_features,
.ndo_set_features = hinic_set_features,
+ .ndo_set_vf_mac = hinic_ndo_set_vf_mac,
+ .ndo_set_vf_vlan = hinic_ndo_set_vf_vlan,
+ .ndo_get_vf_config = hinic_ndo_get_vf_config,
+ .ndo_set_vf_trust = hinic_ndo_set_vf_trust,
+ .ndo_set_vf_rate = hinic_ndo_set_vf_bw,
+ .ndo_set_vf_spoofchk = hinic_ndo_set_vf_spoofchk,
+ .ndo_set_vf_link_state = hinic_ndo_set_vf_link_state,
+};
+
+static const struct net_device_ops hinicvf_netdev_ops = {
+ .ndo_open = hinic_open,
+ .ndo_stop = hinic_close,
+ .ndo_change_mtu = hinic_change_mtu,
+ .ndo_set_mac_address = hinic_set_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_vlan_rx_add_vid = hinic_vlan_rx_add_vid,
+ .ndo_vlan_rx_kill_vid = hinic_vlan_rx_kill_vid,
+ .ndo_set_rx_mode = hinic_set_rx_mode,
+ .ndo_start_xmit = hinic_xmit_frame,
+ .ndo_tx_timeout = hinic_tx_timeout,
+ .ndo_get_stats64 = hinic_get_stats64,
+ .ndo_fix_features = hinic_fix_features,
+ .ndo_set_features = hinic_set_features,
};
static void netdev_features_init(struct net_device *netdev)
@@ -896,6 +932,10 @@ static void link_status_event_handler(void *handle, void *buf_in, u16 in_size,
netif_info(nic_dev, drv, nic_dev->netdev, "HINIC_Link is DOWN\n");
}
+ if (!HINIC_IS_VF(nic_dev->hwdev->hwif))
+ hinic_notify_all_vfs_link_changed(nic_dev->hwdev,
+ link_status->link);
+
ret_link_status = buf_out;
ret_link_status->status = 0;
@@ -969,7 +1009,12 @@ static int nic_dev_init(struct pci_dev *pdev)
}
hinic_set_ethtool_ops(netdev);
- netdev->netdev_ops = &hinic_netdev_ops;
+
+ if (!HINIC_IS_VF(hwdev->hwif))
+ netdev->netdev_ops = &hinic_netdev_ops;
+ else
+ netdev->netdev_ops = &hinicvf_netdev_ops;
+
netdev->max_mtu = ETH_MAX_MTU;
nic_dev = netdev_priv(netdev);
@@ -981,6 +1026,11 @@ static int nic_dev_init(struct pci_dev *pdev)
nic_dev->rxqs = NULL;
nic_dev->tx_weight = tx_weight;
nic_dev->rx_weight = rx_weight;
+ nic_dev->sq_depth = HINIC_SQ_DEPTH;
+ nic_dev->rq_depth = HINIC_RQ_DEPTH;
+ nic_dev->sriov_info.hwdev = hwdev;
+ nic_dev->sriov_info.pdev = pdev;
+ nic_dev->max_qps = num_qps;
sema_init(&nic_dev->mgmt_lock, 1);
@@ -1007,11 +1057,25 @@ static int nic_dev_init(struct pci_dev *pdev)
pci_set_drvdata(pdev, netdev);
err = hinic_port_get_mac(nic_dev, netdev->dev_addr);
- if (err)
- dev_warn(&pdev->dev, "Failed to get mac address\n");
+ if (err) {
+ dev_err(&pdev->dev, "Failed to get mac address\n");
+ goto err_get_mac;
+ }
+
+ if (!is_valid_ether_addr(netdev->dev_addr)) {
+ if (!HINIC_IS_VF(nic_dev->hwdev->hwif)) {
+ dev_err(&pdev->dev, "Invalid MAC address\n");
+ err = -EIO;
+ goto err_add_mac;
+ }
+
+ dev_info(&pdev->dev, "Invalid MAC address %pM, using random\n",
+ netdev->dev_addr);
+ eth_hw_addr_random(netdev);
+ }
err = hinic_port_add_mac(nic_dev, netdev->dev_addr, 0);
- if (err) {
+ if (err && err != HINIC_PF_SET_VF_ALREADY) {
dev_err(&pdev->dev, "Failed to add mac\n");
goto err_add_mac;
}
@@ -1053,6 +1117,7 @@ err_set_features:
cancel_work_sync(&rx_mode_work->work);
err_set_mtu:
+err_get_mac:
err_add_mac:
pci_set_drvdata(pdev, NULL);
destroy_workqueue(nic_dev->workq);
@@ -1126,14 +1191,41 @@ err_pci_regions:
return err;
}
+#define HINIC_WAIT_SRIOV_CFG_TIMEOUT 15000
+
+static void wait_sriov_cfg_complete(struct hinic_dev *nic_dev)
+{
+ struct hinic_sriov_info *sriov_info = &nic_dev->sriov_info;
+ u32 loop_cnt = 0;
+
+ set_bit(HINIC_FUNC_REMOVE, &sriov_info->state);
+ usleep_range(9900, 10000);
+
+ while (loop_cnt < HINIC_WAIT_SRIOV_CFG_TIMEOUT) {
+ if (!test_bit(HINIC_SRIOV_ENABLE, &sriov_info->state) &&
+ !test_bit(HINIC_SRIOV_DISABLE, &sriov_info->state))
+ return;
+
+ usleep_range(9900, 10000);
+ loop_cnt++;
+ }
+}
+
static void hinic_remove(struct pci_dev *pdev)
{
struct net_device *netdev = pci_get_drvdata(pdev);
struct hinic_dev *nic_dev = netdev_priv(netdev);
struct hinic_rx_mode_work *rx_mode_work;
+ if (!HINIC_IS_VF(nic_dev->hwdev->hwif)) {
+ wait_sriov_cfg_complete(nic_dev);
+ hinic_pci_sriov_disable(pdev);
+ }
+
unregister_netdev(netdev);
+ hinic_port_del_mac(nic_dev, netdev->dev_addr, 0);
+
hinic_hwdev_cb_unregister(nic_dev->hwdev,
HINIC_MGMT_MSG_CMD_LINK_STATUS);
@@ -1144,6 +1236,8 @@ static void hinic_remove(struct pci_dev *pdev)
destroy_workqueue(nic_dev->workq);
+ hinic_vf_func_free(nic_dev->hwdev);
+
hinic_free_hwdev(nic_dev->hwdev);
free_netdev(netdev);
@@ -1164,6 +1258,7 @@ static const struct pci_device_id hinic_pci_table[] = {
{ PCI_VDEVICE(HUAWEI, HINIC_DEV_ID_DUAL_PORT_100GE), 0},
{ PCI_VDEVICE(HUAWEI, HINIC_DEV_ID_DUAL_PORT_100GE_MEZZ), 0},
{ PCI_VDEVICE(HUAWEI, HINIC_DEV_ID_QUAD_PORT_25GE_MEZZ), 0},
+ { PCI_VDEVICE(HUAWEI, HINIC_DEV_ID_VF), 0},
{ 0, 0}
};
MODULE_DEVICE_TABLE(pci, hinic_pci_table);
@@ -1174,6 +1269,7 @@ static struct pci_driver hinic_driver = {
.probe = hinic_probe,
.remove = hinic_remove,
.shutdown = hinic_shutdown,
+ .sriov_configure = hinic_pci_sriov_configure,
};
module_pci_driver(hinic_driver);