Jintao 50c46e6857 Add LingYao
Change-Id: Iae6634ce565940904ee320c678d0f77473bebb90
2025-01-03 16:08:55 +08:00

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");
}