204 lines
4.9 KiB
C
204 lines
4.9 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* JaguarMicro virtual dev driver for virtio dataplane offloading
|
|
*
|
|
* Copyright (C) 2022 JaguarMicro Corporation.
|
|
*
|
|
* Author: Angus Chen <angus.chen@jaguarmicro.com>
|
|
*
|
|
*/
|
|
#include <linux/vdpa.h>
|
|
#include "../crete-core/crete_cmd_if.h"
|
|
#include "crete_nic.h"
|
|
|
|
void crete_vnic_priv_cleanup(struct crete_vnic_priv *priv)
|
|
{
|
|
struct crete_core_dev *core_dev = priv->coredev;
|
|
struct pci_dev *pdev;
|
|
struct crete_net_common_cfg *netcfg = &priv->net_cfg;
|
|
|
|
if (!priv->coredev)
|
|
return;
|
|
|
|
pdev = core_dev->pdev;
|
|
dev_err(&pdev->dev, "enter crete_priv_cleanup\n");
|
|
|
|
kfree(netcfg->mc_list);
|
|
netcfg->mc_list = NULL;
|
|
|
|
kfree(netcfg->uc_list);
|
|
netcfg->uc_list = NULL;
|
|
|
|
// memset(priv, 0, sizeof(*priv));
|
|
dev_err(&pdev->dev, "exit crete_priv_cleanup\n");
|
|
}
|
|
|
|
int crete_nic_set_device_type(struct crete_core_dev *core_dev, enum crete_dev_type op)
|
|
{
|
|
|
|
int ret;
|
|
struct pci_dev *pdev = core_dev->pdev;
|
|
u32 devtype = 0;
|
|
|
|
ret = crete_set_dev_type(core_dev, op);
|
|
if (ret) {
|
|
dev_err(&pdev->dev,
|
|
"Failed to set device type %x, set cmd error\n", op);
|
|
return -EINVAL;
|
|
}
|
|
ret = crete_get_dev_type(core_dev, &devtype);
|
|
if (ret) {
|
|
dev_err(&pdev->dev, "set dev type failed\n");
|
|
goto out;
|
|
}
|
|
|
|
if (devtype != op) {
|
|
dev_err(&pdev->dev,
|
|
" dev type not right check failed. dev type %x\n", op);
|
|
goto out;
|
|
}
|
|
|
|
return ret;
|
|
out:
|
|
return -EINVAL;
|
|
}
|
|
|
|
u64 crete_net_get_supported_features(struct crete_core_dev *core_dev,
|
|
enum crete_feature_opcode op)
|
|
{
|
|
|
|
struct pci_dev *pdev = core_dev->pdev;
|
|
u64 dev_features;
|
|
u64 ret;
|
|
|
|
ret = crete_cmd_get_features(core_dev, op, &dev_features);
|
|
if (ret) {
|
|
dev_err(&pdev->dev, "get device features is error\n");
|
|
ret = -EINVAL;
|
|
}
|
|
core_dev->cap.hw_features = dev_features;
|
|
dev_info(&pdev->dev, "device supported features[0x%llx]\n",
|
|
core_dev->cap.hw_features);
|
|
return ret;
|
|
}
|
|
|
|
u64 crete_net_get_max_supported_vqs(struct crete_core_dev *core_dev)
|
|
{
|
|
int ret;
|
|
u16 max_queue_size;
|
|
u8 max_qp_num;
|
|
u8 ctrl_queue_size;
|
|
struct pci_dev *pdev = core_dev->pdev;
|
|
|
|
ret =
|
|
crete_get_qp_cap(core_dev, &max_queue_size, &max_qp_num,
|
|
&ctrl_queue_size);
|
|
if (ret) {
|
|
dev_err(&pdev->dev, "%s is error\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
core_dev->cap.qpcap.ctrl_queue_size = ctrl_queue_size;
|
|
core_dev->cap.qpcap.max_qp_num = max_qp_num;
|
|
core_dev->cap.qpcap.max_queue_size = max_queue_size;
|
|
|
|
dev_info(&pdev->dev,
|
|
"crete vqs: ctl_qlen[0x%x] ioqlen[0x%x] maxvqs[%d]\n",
|
|
ctrl_queue_size, max_queue_size, max_qp_num);
|
|
return 0;
|
|
}
|
|
|
|
//todo: keyi cmd_if
|
|
|
|
int crete_trim_rings(struct crete_core_dev *cdev)
|
|
{
|
|
int cpunums = num_online_cpus();
|
|
int maxqpnums = cdev->cap.qpcap.max_qp_num;
|
|
|
|
if (maxqpnums > CRETE_VNIC_MAX_QUEUES) {
|
|
cdev->cap.qpcap.max_qp_num = CRETE_VNIC_MAX_QUEUES;
|
|
crete_err(cdev->device, "max qp greater than %d\n",
|
|
CRETE_VNIC_MAX_QUEUES);
|
|
}
|
|
cdev->ring_size = min(cpunums, maxqpnums);
|
|
if (!cdev->ring_size) {
|
|
crete_err(cdev->device, "ring size zero not right\n");
|
|
return -1;
|
|
}
|
|
return 0;
|
|
} //todo: keyi cmd_if
|
|
|
|
int crete_vnic_priv_init(struct crete_vnic_priv *priv,
|
|
struct net_device *netdev,
|
|
struct crete_core_dev *core_dev)
|
|
{
|
|
int mem_size = (CRETE_MAX_UC_ADDRS - 1) * ETH_ALEN;
|
|
struct crete_net_common_cfg *netcfg = &priv->net_cfg;
|
|
int rc = 0;
|
|
|
|
priv->coredev = core_dev;
|
|
priv->netdev = netdev;
|
|
|
|
netcfg->uc_list = kmalloc(mem_size, GFP_KERNEL);
|
|
if (!netcfg->uc_list) {
|
|
rc = -ENOMEM;
|
|
goto err_uc_list_alloc;
|
|
}
|
|
netcfg->mc_list_size = CRETE_MAX_MC_ADDRS * ETH_ALEN;
|
|
netcfg->mc_list = kmalloc(netcfg->mc_list_size, GFP_KERNEL);
|
|
if (!netcfg->mc_list) {
|
|
rc = -ENOMEM;
|
|
goto err_mc_list_alloc;
|
|
}
|
|
|
|
return 0;
|
|
err_mc_list_alloc:
|
|
kfree(netcfg->uc_list);
|
|
netcfg->uc_list = NULL;
|
|
err_uc_list_alloc:
|
|
return rc;
|
|
} //todo: keyi cmd_if
|
|
|
|
struct net_device *crete_vnic_create_netdev(struct crete_core_dev *coredev)
|
|
{
|
|
struct net_device *netdev;
|
|
unsigned int txqs, rxqs;
|
|
struct crete_vnic_priv *priv;
|
|
struct pci_dev *pdev = coredev->pdev;
|
|
int err;
|
|
|
|
txqs = coredev->ring_size;
|
|
rxqs = coredev->ring_size;
|
|
/* crete netdevice with max qp number */
|
|
netdev = alloc_etherdev_mqs(sizeof(struct crete_vnic_priv), txqs, rxqs);
|
|
if (!netdev) {
|
|
dev_err(&pdev->dev, "alloc_etherdev_mqs() failed\n");
|
|
return NULL;
|
|
}
|
|
priv = netdev_priv(netdev);
|
|
coredev->netdev = netdev;
|
|
err = crete_vnic_priv_init(priv, netdev, coredev);
|
|
if (err) {
|
|
dev_err(&pdev->dev, "crete_vnic_priv_init failed\n");
|
|
goto err_priv_init;
|
|
}
|
|
|
|
netif_tx_disable(netdev);
|
|
return netdev;
|
|
|
|
err_priv_init:
|
|
free_netdev(netdev);
|
|
return NULL;
|
|
} //todo: keyi cmd_if
|
|
|
|
void crete_build_common_netdev(struct net_device *netdev)
|
|
{
|
|
struct crete_vnic_priv *priv = netdev_priv(netdev);
|
|
struct crete_core_dev *core_dev = priv->coredev;
|
|
struct pci_dev *pdev = core_dev->pdev;
|
|
|
|
netdev->watchdog_timeo = 5 * HZ;
|
|
strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1);
|
|
SET_NETDEV_DEV(netdev, &pdev->dev);
|
|
strcpy(netdev->name, "eth%d");
|
|
}
|