* Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that 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 "ka_barrier_pub.h"
#include "ka_net_pub.h"
#include "ka_driver_pub.h"
#include "ka_memory_pub.h"
#include "ka_system_pub.h"
#include "ka_pci_pub.h"
#include "pbl/pbl_uda.h"
#include "pcivnic_host.h"
#include "pcivnic_main.h"
struct pcivnic_netdev *g_vnic_dev = NULL;
unsigned char g_pcivnic_mac[KA_ETH_ALEN] = {0};
struct pcivnic_ctrl_msg_get_stat pcivnic_stat = {{0}};
struct pcivnic_pcidev *pcivnic_get_pcidev(void *msg_chan)
{
return (struct pcivnic_pcidev *)devdrv_get_msg_chan_priv(msg_chan);
}
struct pcivnic_sq_desc *pcivnic_get_w_sq_desc(void *msg_chan, u32 *tail)
{
void *sq_desc = NULL;
sq_desc = devdrv_get_msg_chan_slave_sq_tail(msg_chan, tail);
return (struct pcivnic_sq_desc *)sq_desc;
}
void pcivnic_set_w_sq_desc_head(void *msg_chan, u32 head)
{
devdrv_set_msg_chan_slave_sq_head(msg_chan, head);
}
void pcivnic_copy_sq_desc_to_remote(struct pcivnic_pcidev *pcidev, const struct pcivnic_sq_desc *sq_desc)
{
void *msg_chan = pcidev->msg_chan;
(void)sq_desc;
devdrv_move_msg_chan_slave_sq_tail(msg_chan);
ka_wmb();
devdrv_msg_ring_doorbell(msg_chan);
}
bool pcivnic_w_sq_full_check(void *msg_chan)
{
return devdrv_msg_chan_slave_sq_full_check(msg_chan);
}
struct pcivnic_sq_desc *pcivnic_get_r_sq_desc(void *msg_chan, u32 *head)
{
void *sq_desc = NULL;
sq_desc = devdrv_get_msg_chan_host_sq_head(msg_chan, head);
return (struct pcivnic_sq_desc *)sq_desc;
}
void pcivnic_move_r_sq_desc(void *msg_chan)
{
devdrv_move_msg_chan_host_sq_head(msg_chan);
return;
}
int pcivnic_dma_copy(const struct pcivnic_pcidev *pcidev, u64 src, u64 dst, u32 size,
struct devdrv_asyn_dma_para_info *para_info)
{
int ret;
ret = hal_kernel_devdrv_dma_async_copy(pcidev->dev_id, DEVDRV_DMA_DATA_COMMON, src, dst, size,
DEVDRV_DMA_DEVICE_TO_HOST, para_info);
if (ret != 0) {
devdrv_err("dev %d dma copy failed size %x\n", pcidev->dev_id, size);
}
return ret;
}
struct pcivnic_cq_desc *pcivnic_get_w_cq_desc(void *msg_chan)
{
void *cq_desc = NULL;
cq_desc = devdrv_get_msg_chan_slave_cq_tail(msg_chan);
return (struct pcivnic_cq_desc *)cq_desc;
}
void pcivnic_copy_cq_desc_to_remote(struct pcivnic_pcidev *pcidev, const struct pcivnic_cq_desc *cq_desc)
{
void *msg_chan = pcidev->msg_chan;
(void)cq_desc;
devdrv_move_msg_chan_slave_cq_tail(msg_chan);
ka_wmb();
devdrv_msg_ring_cq_doorbell(msg_chan);
}
struct pcivnic_cq_desc *pcivnic_get_r_cq_desc(void *msg_chan)
{
void *cq_desc = NULL;
cq_desc = devdrv_get_msg_chan_host_cq_head(msg_chan);
return (struct pcivnic_cq_desc *)cq_desc;
}
void pcivnic_move_r_cq_desc(void *msg_chan)
{
devdrv_move_msg_chan_host_cq_head(msg_chan);
}
struct pcivnic_pcidev *pcivnic_get_pciedev(const ka_device_t *dev)
{
struct pcivnic_pcidev *pcidev = NULL;
u32 dev_id;
if (g_vnic_dev != NULL) {
for (dev_id = 0; dev_id < NETDEV_PCIDEV_NUM; dev_id++) {
pcidev = g_vnic_dev->pcidev[dev_id];
if (pcidev == NULL) {
continue;
}
if (pcidev->dev == dev) {
break;
}
pcidev = NULL;
}
}
return pcidev;
}
bool pcivnic_is_p2p_enabled(u32 dev_id, u32 peer_dev_id)
{
return devdrv_is_p2p_enabled(dev_id, peer_dev_id);
}
int pcivnic_up_get_next_hop(const unsigned char *dmac)
{
if ((*(u32 *)g_pcivnic_mac == *(u32 *)dmac) && (g_pcivnic_mac[PCIVNIC_MAC_4] == dmac[PCIVNIC_MAC_4])) {
if (dmac[PCIVNIC_MAC_5] == HOST_MAC_LAST_BYTE) {
return PCIVNIC_NEXT_HOP_LOCAL_NETDEV;
} else if (dmac[PCIVNIC_MAC_5] < NETDEV_PF_PCIDEV_NUM) {
return dmac[PCIVNIC_MAC_5];
}
}
return PCIVNIC_NEXT_HOP_BROADCAST;
}
int pcivnic_down_get_next_hop(const unsigned char *dmac)
{
if ((*(u32 *)g_pcivnic_mac == *(u32 *)dmac) && (g_pcivnic_mac[PCIVNIC_MAC_4] == dmac[PCIVNIC_MAC_4])) {
if (dmac[PCIVNIC_MAC_5] < NETDEV_PF_PCIDEV_NUM) {
return dmac[PCIVNIC_MAC_5];
}
}
return PCIVNIC_NEXT_HOP_BROADCAST;
}
ssize_t pcivnic_get_dev_stat(ka_device_t *dev, ka_device_attribute_t *attr, char *buf)
{
struct pcivnic_pcidev *pcidev = pcivnic_get_pciedev(dev);
ssize_t offset = 0;
u32 out_len, msg_len;
int ret;
(void)attr;
if (pcidev == NULL) {
devdrv_err("not find pcidev\n");
return offset;
}
offset = pcivnic_get_dev_stat_inner(dev, buf);
ret = snprintf_s(buf + offset, KA_MM_PAGE_SIZE - offset, KA_MM_PAGE_SIZE - offset - 1, "\ndevice stat:\n");
if (ret >= 0) {
offset += ret;
}
pcivnic_stat.head.msg_type = PCIVNIC_CTRL_MSG_TYPE_GET_STAT;
msg_len = sizeof(pcivnic_stat);
if (msg_len > VNIC_STAT_MSG_MAX_LEN) {
msg_len = VNIC_STAT_MSG_MAX_LEN;
}
ret = devdrv_common_msg_send(pcidev->dev_id, (void *)&pcivnic_stat, sizeof(pcivnic_stat.head),
msg_len, &out_len, DEVDRV_COMMON_MSG_PCIVNIC);
if ((ret == 0) && (pcivnic_stat.msg_len < KA_MM_PAGE_SIZE - offset)) {
pcivnic_stat.msg[pcivnic_stat.msg_len] = '\0';
ret = snprintf_s(buf + offset, KA_MM_PAGE_SIZE - offset, KA_MM_PAGE_SIZE - offset - 1, "%s\n", pcivnic_stat.msg);
if (ret >= 0) {
offset += ret;
}
}
return offset;
}
struct devdrv_trans_msg_chan_info g_msg_chan_info = {
.msg_type = devdrv_msg_client_pcivnic,
.queue_depth = PCIVNIC_DESC_QUEUE_DEPTH,
.level = DEVDRV_MSG_CHAN_LEVEL_LOW,
.cq_desc_size = sizeof(struct pcivnic_cq_desc),
.sq_desc_size = sizeof(struct pcivnic_sq_desc),
.rx_msg_notify = pcivnic_rx_msg_notify,
.tx_finish_notify = pcivnic_tx_finish_notify,
};
int pcivnic_device_status_abnormal(const void *msg_chan)
{
return devdrv_device_status_abnormal_check(msg_chan);
}
STATIC void pcivnic_msg_chan_guard_work_sched(struct pcivnic_pcidev *pcidev)
{
if (pcivnic_device_status_abnormal(pcidev->msg_chan) != 0) {
return;
}
pcivnic_rx_msg_notify(pcidev->msg_chan);
}
STATIC void pcivnic_guard_work_sched(ka_work_struct_t *p_work)
{
struct pcivnic_pcidev *pcidev =
ka_container_of(p_work, struct pcivnic_pcidev, guard_work.work);
pcivnic_msg_chan_guard_work_sched(pcidev);
ka_task_schedule_delayed_work(&pcidev->guard_work, ka_system_msecs_to_jiffies(PCIVNIC_GUARD_WORK_DELAY_TIME));
}
STATIC void pcivnic_guard_work_init(struct pcivnic_pcidev *pcidev)
{
KA_TASK_INIT_DELAYED_WORK(&pcidev->guard_work, pcivnic_guard_work_sched);
ka_task_schedule_delayed_work(&pcidev->guard_work, 0);
}
STATIC void pcivnic_guard_work_uninit(struct pcivnic_pcidev *pcidev)
{
ka_task_cancel_delayed_work_sync(&pcidev->guard_work);
}
STATIC int pcivnic_init_msg_chan(struct pcivnic_pcidev *pcidev)
{
u32 devid = pcidev->dev_id;
void *msg_chan = NULL;
msg_chan = devdrv_pcimsg_alloc_trans_queue(devid, &g_msg_chan_info);
if (msg_chan == NULL) {
devdrv_info("dev %d init host msg chan abnormal!\n", devid);
return -EINVAL;
}
pcivnic_init_msgchan_cq_desc(msg_chan);
pcidev->msg_chan = msg_chan;
devdrv_set_msg_chan_priv(msg_chan, (void *)pcidev);
return 0;
}
STATIC void pcivnic_uninit_msg_chan(struct pcivnic_pcidev *pcidev)
{
if (pcidev->msg_chan == NULL) {
return;
}
devdrv_pcimsg_realease_trans_queue(pcidev->msg_chan);
pcidev->msg_chan = NULL;
}
STATIC int pcivnic_init_msg_instance(struct pcivnic_pcidev *pcidev)
{
struct pcivnic_netdev *vnic_dev = (struct pcivnic_netdev *)pcidev->netdev;
struct pcivnic_ctrl_msg_register_netdev register_msg;
struct pcivnic_ctrl_msg_set_mac msg;
u32 i, len = 0;
int ret;
msg.head.msg_type = PCIVNIC_CTRL_MSG_TYPE_SET_MAC;
msg.head.host_udevid = pcidev->dev_id;
for (i = 0; i < KA_ETH_ALEN; i++) {
msg.mac[i] = g_pcivnic_mac[i];
}
ret = devdrv_common_msg_send(pcidev->dev_id, (void *)&msg, sizeof(msg), sizeof(msg), &len,
DEVDRV_COMMON_MSG_PCIVNIC);
if (ret != 0) {
devdrv_err("dev %d sync abnormal, wait for device startup.\n", pcidev->dev_id);
return ret;
}
ret = pcivnic_init_msg_chan(pcidev);
if (ret != 0) {
#ifndef DRV_UT
devdrv_err("dev %d init msg chan for netdev failed!\n", pcidev->dev_id);
return ret;
#endif
}
pcidev->status = BIT_STATUS_LINK;
register_msg.head.msg_type = PCIVNIC_CTRL_MSG_TYPE_RIGISTER_NETDEV;
ret = devdrv_common_msg_send(pcidev->dev_id, (void *)®ister_msg, sizeof(register_msg), sizeof(register_msg),
&len, DEVDRV_COMMON_MSG_PCIVNIC);
if (ret != 0) {
pcivnic_uninit_msg_chan(pcidev);
devdrv_err("dev %d register device netdev fail.\n", pcidev->dev_id);
return ret;
}
(void)devdrv_set_module_init_finish((int)pcidev->dev_id, DEVDRV_HOST_MODULE_PCIVNIC);
* do not change it. !!!!!
*/
devdrv_info("dev id %d: %s, alloc new pcivnic device <%s> success (locked and finish).\n",
pcidev->dev_id, ka_driver_dev_driver_string(pcidev->dev), ka_net_netdev_get_name(vnic_dev->ndev));
return 0;
}
STATIC int pcivnic_ctrl_msg_recv(u32 devid, void *data, u32 in_data_len, u32 out_data_len, u32 *real_out_len)
{
*real_out_len = 0;
return 0;
}
struct devdrv_common_msg_client g_pcivnic_host_comm_msg_client = {
.type = DEVDRV_COMMON_MSG_PCIVNIC,
.common_msg_recv = pcivnic_ctrl_msg_recv,
};
u64 pcivnic_dma_map_single(struct pcivnic_pcidev *pcidev, ka_sk_buff_t *skb, u32 buff_type, u32 index)
{
ka_dma_data_direction_t dma_dir;
u64 dma_addr = (~(ka_dma_addr_t)0);
size_t len;
dma_dir = (buff_type == PCIVNIC_DESC_QUEUE_TX) ? KA_DMA_TO_DEVICE : KA_DMA_FROM_DEVICE;
len = (buff_type == PCIVNIC_DESC_QUEUE_TX) ? skb->len : PCIVNIC_MAX_PKT_SIZE;
#ifdef CFG_FEATURE_AGENT_SMMU
if ((devdrv_get_connect_protocol(pcidev->dev_id) == CONNECT_PROTOCOL_HCCS) && (pcidev->host_phy_mach_flag == 0)) {
if (buff_type == PCIVNIC_DESC_QUEUE_TX) {
if (memcpy_s(pcidev->tx_buff[index].addr, len, skb->data, len) != 0) {
devdrv_err_spinlock("device %d memcpy_s fail.\n", pcidev->dev_id);
return (~(ka_dma_addr_t)0);
}
dma_addr = pcidev->tx_buff[index].dma_addr;
}
if (buff_type == PCIVNIC_DESC_QUEUE_RX) {
dma_addr = pcidev->rx_buff[index].dma_addr;
}
return dma_addr;
}
#endif
dma_addr = hal_kernel_devdrv_dma_map_single(pcidev->dev, skb->data, len, dma_dir);
if (ka_mm_dma_mapping_error(pcidev->dev, dma_addr) != 0) {
devdrv_err_spinlock("device %d dma map is error\n", pcidev->dev_id);
return (~(ka_dma_addr_t)0);
}
return dma_addr;
}
void pcivnic_dma_unmap_single(struct pcivnic_pcidev *pcidev, ka_sk_buff_t *skb, u32 buff_type, u32 index)
{
#ifdef CFG_FEATURE_AGENT_SMMU
if ((devdrv_get_connect_protocol(pcidev->dev_id) == CONNECT_PROTOCOL_HCCS) && (pcidev->host_phy_mach_flag == 0)) {
if (buff_type == PCIVNIC_DESC_QUEUE_RX) {
if (memcpy_s(skb->data, PCIVNIC_MAX_PKT_SIZE, pcidev->rx_buff[index].addr, PCIVNIC_MAX_PKT_SIZE) != 0) {
devdrv_err_spinlock("device %d memcpy_s fail.\n", pcidev->dev_id);
}
}
return;
}
#endif
if (buff_type == PCIVNIC_DESC_QUEUE_TX) {
hal_kernel_devdrv_dma_unmap_single(pcidev->dev, pcidev->tx[index].addr, skb->len, KA_DMA_TO_DEVICE);
pcidev->tx[index].addr = (~(ka_dma_addr_t)0);
}
if (buff_type == PCIVNIC_DESC_QUEUE_RX) {
hal_kernel_devdrv_dma_unmap_single(pcidev->dev, pcidev->rx[index].addr, PCIVNIC_MAX_PKT_SIZE, KA_DMA_FROM_DEVICE);
pcidev->rx[index].addr = (~(ka_dma_addr_t)0);
}
}
void pcivnic_skb_data_buff_uninit(struct pcivnic_pcidev *pcidev)
{
#ifdef CFG_FEATURE_AGENT_SMMU
u32 host_flag;
int ret;
int i;
ret = devdrv_get_host_phy_mach_flag(pcidev->dev_id, &host_flag);
if (ret != 0) {
return;
}
if ((devdrv_get_connect_protocol(pcidev->dev_id) != CONNECT_PROTOCOL_HCCS) || (host_flag != 0)) {
return;
}
for (i = 0; i < PCIVNIC_DESC_QUEUE_DEPTH; i++) {
if (pcidev->tx_buff[i].addr != NULL) {
hal_kernel_devdrv_dma_free_coherent(pcidev->dev, PCIVNIC_MAX_SKB_BUFF_SIZE, pcidev->tx_buff[i].addr,
pcidev->tx_buff[i].dma_addr);
pcidev->tx_buff[i].addr = NULL;
}
pcidev->tx_buff[i].dma_addr = (~(ka_dma_addr_t)0);
if (pcidev->rx_buff[i].addr != NULL) {
hal_kernel_devdrv_dma_free_coherent(pcidev->dev, PCIVNIC_MAX_SKB_BUFF_SIZE, pcidev->rx_buff[i].addr,
pcidev->rx_buff[i].dma_addr);
pcidev->rx_buff[i].addr = NULL;
}
pcidev->rx_buff[i].dma_addr = (~(ka_dma_addr_t)0);
}
#endif
}
int pcivnic_skb_data_buff_init(struct pcivnic_pcidev *pcidev)
{
#ifdef CFG_FEATURE_AGENT_SMMU
u32 host_phy_mach_flag;
int ret;
int i;
ret = devdrv_get_host_phy_mach_flag(pcidev->dev_id, &host_phy_mach_flag);
if (ret != 0) {
pcidev->host_phy_mach_flag = DEVDRV_HOST_PHY_MACH_FLAG;
return 0;
}
pcidev->host_phy_mach_flag = host_phy_mach_flag;
if ((devdrv_get_connect_protocol(pcidev->dev_id) != CONNECT_PROTOCOL_HCCS) || (host_phy_mach_flag != 0)) {
return 0;
}
for (i = 0; i < PCIVNIC_DESC_QUEUE_DEPTH; i++) {
pcidev->tx_buff[i].addr = hal_kernel_devdrv_dma_zalloc_coherent(pcidev->dev, PCIVNIC_MAX_SKB_BUFF_SIZE,
&pcidev->tx_buff[i].dma_addr, KA_GFP_KERNEL);
if (pcidev->tx_buff[i].addr == NULL) {
pcivnic_skb_data_buff_uninit(pcidev);
devdrv_err("Call skb_data tx buff failed. (dev_id=%d)\n", pcidev->dev_id);
return -ENOMEM;
}
pcidev->rx_buff[i].addr = hal_kernel_devdrv_dma_zalloc_coherent(pcidev->dev, PCIVNIC_MAX_SKB_BUFF_SIZE,
&pcidev->rx_buff[i].dma_addr, KA_GFP_KERNEL);
if (pcidev->rx_buff[i].addr == NULL) {
pcivnic_skb_data_buff_uninit(pcidev);
devdrv_err("Call skb_data rx buff failed. (dev_id=%d)\n", pcidev->dev_id);
return -ENOMEM;
}
}
#endif
return 0;
}
STATIC bool pcivnic_init_instance_check(u32 dev_id)
{
if (devdrv_get_connect_protocol(dev_id) == CONNECT_PROTOCOL_UB) {
devdrv_info("Connect protocol is ub, don't need to init and uninit.(dev_id=%d)\n", dev_id);
return false;
}
if ((devdrv_get_pfvf_type_by_devid(dev_id) == DEVDRV_SRIOV_TYPE_VF) &&
(devdrv_is_mdev_vm_full_spec(dev_id) != true)) {
return false;
}
return true;
}
STATIC int pcivnic_init_npu_instance(u32 dev_id)
{
struct pcivnic_ctrl_msg_dev_instance instance_msg;
u32 len = 0;
int ret;
instance_msg.head.msg_type = PCIVNIC_CTRL_MSG_TYPE_INSTANCE;
instance_msg.head.host_udevid = dev_id;
ret = devdrv_common_msg_send(dev_id, (void *)&instance_msg, sizeof(instance_msg), sizeof(instance_msg),
&len, DEVDRV_COMMON_MSG_PCIVNIC);
if (ret != 0) {
devdrv_err("dev %d instance device netdev fail.\n", dev_id);
#ifdef DRV_UT
ret = 0;
#endif
return ret;
}
return 0;
}
STATIC int pcivnic_init_instance(u32 dev_id, ka_device_t *dev)
{
struct pcivnic_netdev *vnic_dev = g_vnic_dev;
struct pcivnic_pcidev *pcidev = NULL;
int ret;
if (dev_id >= NETDEV_PCIDEV_NUM) {
devdrv_err("dev_id is invalid, dev_id=%d\n", dev_id);
return -EINVAL;
}
if (pcivnic_init_instance_check(dev_id) == false) {
return 0;
}
ret = pcivnic_init_npu_instance(dev_id);
if (ret != 0) {
devdrv_err("dev %d instance device netdev fail.\n", dev_id);
return ret;
}
pcidev = pcivnic_add_dev(vnic_dev, dev, PCIVNIC_DESC_QUEUE_DEPTH, dev_id);
if (pcidev == NULL) {
devdrv_err("dev_id %u add pcidev failed!\n", dev_id);
return -ENOMEM;
}
ret = devdrv_register_common_msg_client(&g_pcivnic_host_comm_msg_client);
if (ret != 0) {
pcivnic_del_dev(vnic_dev, (int)dev_id);
devdrv_err("dev_id %u register_common_msg failed ret %d", dev_id, ret);
return ret;
}
ret = pcivnic_init_msg_instance(pcidev);
if (ret != 0) {
#ifndef DRV_UT
(void)devdrv_unregister_common_msg_client(dev_id, &g_pcivnic_host_comm_msg_client);
pcivnic_del_dev(vnic_dev, (int)dev_id);
return ret;
#endif
}
pcivnic_guard_work_init(pcidev);
devdrv_info("Pcivnic_init_instance finish.(dev_id=%d)\n", pcidev->dev_id);
return 0;
}
STATIC int pcivnic_uninit_instance(u32 dev_id)
{
struct pcivnic_pcidev *pcidev = NULL;
if (dev_id >= NETDEV_PCIDEV_NUM) {
devdrv_err("dev_id is invalid, dev_id=%d\n", dev_id);
return -EINVAL;
}
if (pcivnic_init_instance_check(dev_id) == false) {
return 0;
}
pcidev = g_vnic_dev->pcidev[dev_id];
if (pcidev == NULL) {
return 0;
}
pcivnic_guard_work_uninit(pcidev);
(void)devdrv_unregister_common_msg_client(pcidev->dev_id, &g_pcivnic_host_comm_msg_client);
devdrv_set_msg_chan_priv(pcidev->msg_chan, NULL);
pcivnic_del_dev(g_vnic_dev, (int)pcidev->dev_id);
pcivnic_uninit_msg_chan(pcidev);
devdrv_info("Pcivnic_uninit_instance finish.(dev_id=%d)\n", pcidev->dev_id);
return 0;
}
bool pcivnic_get_sysfs_creat_group_capbility(ka_device_t *dev, int dev_id)
{
ka_pci_dev_t *pdev = NULL;
int devnum_by_pdev;
pdev = ka_pci_to_pci_dev(dev);
devnum_by_pdev = devdrv_get_davinci_dev_num_by_pdev(pdev);
if (devnum_by_pdev <= 0) {
return false;
}
if (dev_id % devnum_by_pdev == 0) {
return true;
}
return false;
}
#define PCIVNIC_HOST_NOTIFIER "vnic_host"
STATIC int pcivnic_host_notifier_func(u32 udevid, enum uda_notified_action action)
{
int ret = 0;
if (udevid >= NETDEV_PCIDEV_NUM) {
return 0;
}
if (action == UDA_INIT) {
ret = pcivnic_init_instance(udevid, uda_get_device(udevid));
} else if (action == UDA_UNINIT) {
ret = pcivnic_uninit_instance(udevid);
} else {
#ifndef DRV_UT
return 0;
#endif
}
devdrv_info("notifier action. (udevid=%u; action=%d; ret=%d)\n", udevid, action, ret);
return ret;
}
struct pcivnic_netdev *pcivnic_alloc_vnic_dev(void)
{
struct pcivnic_netdev *vnic_dev = NULL;
char *ndev_name = "endvnic";
devdrv_info("pcivnic_alloc_vnic_dev start.\n");
vnic_dev = pcivnic_alloc_netdev(ndev_name, PCIVNIC_NAME_SIZE);
if (vnic_dev == NULL) {
devdrv_err("alloc netdev failed!\n");
return NULL;
}
pcivnic_get_mac(HOST_MAC_LAST_BYTE, g_pcivnic_mac);
pcivnic_set_netdev_mac(vnic_dev, g_pcivnic_mac);
g_vnic_dev = vnic_dev;
return vnic_dev;
}
void pcivnic_free_vnic_dev(void)
{
struct pcivnic_netdev *vnic_dev = g_vnic_dev;
if (vnic_dev != NULL) {
devdrv_info("destroy pcivnic device <%s>.\n", ka_net_netdev_get_name(vnic_dev->ndev));
pcivnic_free_netdev(vnic_dev);
}
return;
}
int pcivnic_register_client(void)
{
struct uda_dev_type type;
struct pcivnic_netdev *vnic_dev = g_vnic_dev;
int ret;
uda_davinci_near_real_entity_type_pack(&type);
ret = uda_notifier_register(PCIVNIC_HOST_NOTIFIER, &type, UDA_PRI1, pcivnic_host_notifier_func);
if (ret != 0) {
pcivnic_free_netdev(vnic_dev);
devdrv_err("uda_notifier_register fail ret = %d\n", ret);
return ret;
}
return 0;
}
int pcivnic_init_netdev(struct pcivnic_netdev *vnic_dev)
{
u32 chip_type = HISI_CHIP_NUM;
int cycle_times = 0;
int retry_times = 0;
int dev_num;
int ret;
u32 i;
dev_num = devdrv_get_dev_num();
retry:
for (i = 0; i < NETDEV_PCIDEV_NUM; i++) {
if (cycle_times == dev_num) {
break;
}
chip_type = devdrv_get_dev_chip_type_by_addid(i);
if (chip_type == HISI_CHIP_UNKNOWN) {
continue;
}
cycle_times++;
if (pcivnic_is_register_netdev(i) == true) {
ret = pcivnic_register_netdev(vnic_dev);
if (ret != 0) {
devdrv_err("register netdev fail ret = %d\n", ret);
}
return ret;
}
}
if ((cycle_times != dev_num) && (retry_times <= PCIVNIC_INIT_NETDEV_RETRY_TIMES)) {
cycle_times = 0;
retry_times++;
ka_system_msleep(1000);
goto retry;
}
return 0;
}
int pcivnic_unregister_client(void)
{
struct uda_dev_type type;
uda_davinci_near_real_entity_type_pack(&type);
return uda_notifier_unregister(PCIVNIC_HOST_NOTIFIER, &type);
}