// SPDX-License-Identifier: GPL-2.0-only /* * JaguarMicro virtual dev driver for virtio dataplane offloading * * Copyright (C) 2022 JaguarMicro Corporation. * * Author: Angus Chen * */ #include #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"); }