1d6aed566Sopenharmony_ci/* 2d6aed566Sopenharmony_ci * Copyright (c) 2020-2021 Huawei Device Co., Ltd. 3d6aed566Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 4d6aed566Sopenharmony_ci * you may not use this file except in compliance with the License. 5d6aed566Sopenharmony_ci * You may obtain a copy of the License at 6d6aed566Sopenharmony_ci * 7d6aed566Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 8d6aed566Sopenharmony_ci * 9d6aed566Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 10d6aed566Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 11d6aed566Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12d6aed566Sopenharmony_ci * See the License for the specific language governing permissions and 13d6aed566Sopenharmony_ci * limitations under the License. 14d6aed566Sopenharmony_ci */ 15d6aed566Sopenharmony_ci 16d6aed566Sopenharmony_ci/* enable lwip 'netif_add' API */ 17d6aed566Sopenharmony_ci#define __LWIP__ 18d6aed566Sopenharmony_ci 19d6aed566Sopenharmony_ci#include "los_reg.h" 20d6aed566Sopenharmony_ci#include "los_compiler.h" 21d6aed566Sopenharmony_ci#include "los_debug.h" 22d6aed566Sopenharmony_ci#include "los_interrupt.h" 23d6aed566Sopenharmony_ci 24d6aed566Sopenharmony_ci#define IFNAMSIZ IF_NAMESIZE 25d6aed566Sopenharmony_ci 26d6aed566Sopenharmony_ci#include "los_task.h" 27d6aed566Sopenharmony_ci#include "los_sched.h" 28d6aed566Sopenharmony_ciVOID LOS_TaskLockSave(UINT32 *intSave) 29d6aed566Sopenharmony_ci{ 30d6aed566Sopenharmony_ci *intSave = LOS_IntLock(); 31d6aed566Sopenharmony_ci g_losTaskLock++; 32d6aed566Sopenharmony_ci} 33d6aed566Sopenharmony_ci 34d6aed566Sopenharmony_ciVOID LOS_TaskUnlockRestore(UINT32 intSave) 35d6aed566Sopenharmony_ci{ 36d6aed566Sopenharmony_ci if (g_losTaskLock > 0) { 37d6aed566Sopenharmony_ci g_losTaskLock--; 38d6aed566Sopenharmony_ci if (g_losTaskLock == 0) { 39d6aed566Sopenharmony_ci LOS_IntRestore(intSave); 40d6aed566Sopenharmony_ci LOS_Schedule(); 41d6aed566Sopenharmony_ci return; 42d6aed566Sopenharmony_ci } 43d6aed566Sopenharmony_ci } 44d6aed566Sopenharmony_ci 45d6aed566Sopenharmony_ci LOS_IntRestore(intSave); 46d6aed566Sopenharmony_ci} 47d6aed566Sopenharmony_ci 48d6aed566Sopenharmony_ci#define LOS_SpinLock(lock) LOS_TaskLock() 49d6aed566Sopenharmony_ci#define LOS_SpinUnlock(lock) LOS_TaskUnlock() 50d6aed566Sopenharmony_ci#define LOS_SpinLockSave(lock, intSave) LOS_TaskLockSave(intSave) 51d6aed566Sopenharmony_ci#define LOS_SpinUnlockRestore(lock, intSave) LOS_TaskUnlockRestore(intSave) 52d6aed566Sopenharmony_ci 53d6aed566Sopenharmony_ci#include "stddef.h" 54d6aed566Sopenharmony_citypedef struct Spinlock { 55d6aed566Sopenharmony_ci size_t rawLock; 56d6aed566Sopenharmony_ci#ifdef LOSCFG_KERNEL_SMP 57d6aed566Sopenharmony_ci UINT32 cpuid; 58d6aed566Sopenharmony_ci VOID *owner; 59d6aed566Sopenharmony_ci const CHAR *name; 60d6aed566Sopenharmony_ci#endif 61d6aed566Sopenharmony_ci} SPIN_LOCK_S; 62d6aed566Sopenharmony_ci 63d6aed566Sopenharmony_ci/* kernel changed lwip 'netif->client_data' size, so this should be prior */ 64d6aed566Sopenharmony_ci#include "netinet/if_ether.h" 65d6aed566Sopenharmony_ci 66d6aed566Sopenharmony_ci#include "lwip/opt.h" 67d6aed566Sopenharmony_ci#include "lwip/netif.h" 68d6aed566Sopenharmony_ci#include "lwip/etharp.h" 69d6aed566Sopenharmony_ci#include "lwip/tcpip.h" 70d6aed566Sopenharmony_ci#include "lwip/mem.h" 71d6aed566Sopenharmony_ci#include "virtmmio.h" 72d6aed566Sopenharmony_ci 73d6aed566Sopenharmony_ci#define VIRTIO_NET_F_MTU (1 << 3) 74d6aed566Sopenharmony_ci#define VIRTIO_NET_F_MAC (1 << 5) 75d6aed566Sopenharmony_cistruct VirtnetConfig { 76d6aed566Sopenharmony_ci uint8_t mac[6]; 77d6aed566Sopenharmony_ci uint16_t status; 78d6aed566Sopenharmony_ci uint16_t maxVirtqPairs; 79d6aed566Sopenharmony_ci uint16_t mtu; 80d6aed566Sopenharmony_ci}; 81d6aed566Sopenharmony_ci 82d6aed566Sopenharmony_ci#define VIRTMMIO_NETIF_NAME "virtnet" 83d6aed566Sopenharmony_ci#define VIRTMMIO_NETIF_NICK "vn0" 84d6aed566Sopenharmony_ci#define VIRTMMIO_NETIF_DFT_IP "10.0.2.15" 85d6aed566Sopenharmony_ci#define VIRTMMIO_NETIF_DFT_GW "10.0.2.2" 86d6aed566Sopenharmony_ci#define VIRTMMIO_NETIF_DFT_MASK "255.255.255.0" 87d6aed566Sopenharmony_ci#define VIRTMMIO_NETIF_DFT_RXQSZ 16 88d6aed566Sopenharmony_ci#define VIRTMMIO_NETIF_DFT_TXQSZ 32 89d6aed566Sopenharmony_ci 90d6aed566Sopenharmony_ci/* This struct is actually ignored by this simple driver */ 91d6aed566Sopenharmony_cistruct VirtnetHdr { 92d6aed566Sopenharmony_ci uint8_t flag; 93d6aed566Sopenharmony_ci uint8_t gsoType; 94d6aed566Sopenharmony_ci uint16_t hdrLen; 95d6aed566Sopenharmony_ci uint16_t gsoSize; 96d6aed566Sopenharmony_ci uint16_t csumStart; 97d6aed566Sopenharmony_ci uint16_t csumOffset; 98d6aed566Sopenharmony_ci uint16_t numBuffers; 99d6aed566Sopenharmony_ci}; 100d6aed566Sopenharmony_ci 101d6aed566Sopenharmony_ci/* 102d6aed566Sopenharmony_ci * We use two queues for Tx/Rx respectively. When Tx/Rx, no dynamic memory alloc/free: 103d6aed566Sopenharmony_ci * output pbuf directly put into queue and freed by tcpip_thread when used; input has 104d6aed566Sopenharmony_ci * some fixed-size buffers just after the queues and released by application when consumed. 105d6aed566Sopenharmony_ci * 106d6aed566Sopenharmony_ci * Tx/Rx queues memory layout: 107d6aed566Sopenharmony_ci * Rx queue Tx queue Rx buffers 108d6aed566Sopenharmony_ci * +-----------------+------------------+------------------++------+-------+------++----------------------+ 109d6aed566Sopenharmony_ci * | desc: 16B align | avail: 2B align | used: 4B align || desc | avail | used || 4B align | 110d6aed566Sopenharmony_ci * | 16∗(Queue Size) | 4+2∗(Queue Size) | 4+8∗(Queue Size) || | | || 1528*(Rx Queue Size) | 111d6aed566Sopenharmony_ci * +-----------------+------------------+------------------++------+-------+------++----------------------+ 112d6aed566Sopenharmony_ci */ 113d6aed566Sopenharmony_ci#define VIRTQ_NUM_NET 2 114d6aed566Sopenharmony_ci#define VIRTQ_RXBUF_ALIGN 4 115d6aed566Sopenharmony_ci#define VIRTQ_RXBUF_SIZE ALIGN(sizeof(struct VirtnetHdr) + ETH_FRAME_LEN, VIRTQ_RXBUF_ALIGN) 116d6aed566Sopenharmony_ci 117d6aed566Sopenharmony_cistruct RbufRecord { 118d6aed566Sopenharmony_ci struct pbuf_custom cbuf; 119d6aed566Sopenharmony_ci struct VirtNetif *nic; 120d6aed566Sopenharmony_ci uint16_t id; /* index to Rx vq[0].desc[] */ 121d6aed566Sopenharmony_ci}; 122d6aed566Sopenharmony_ci 123d6aed566Sopenharmony_cistruct TbufRecord { 124d6aed566Sopenharmony_ci struct pbuf *head; /* first pbuf address of this pbuf chain */ 125d6aed566Sopenharmony_ci uint16_t count; /* occupied desc entries, including VirtnetHdr */ 126d6aed566Sopenharmony_ci uint16_t tail; /* tail pbuf's index to Tx vq[1].desc[] */ 127d6aed566Sopenharmony_ci}; 128d6aed566Sopenharmony_ci 129d6aed566Sopenharmony_cistruct VirtNetif { 130d6aed566Sopenharmony_ci struct VirtmmioDev dev; 131d6aed566Sopenharmony_ci 132d6aed566Sopenharmony_ci struct RbufRecord *rbufRec; 133d6aed566Sopenharmony_ci SPIN_LOCK_S recvLock; 134d6aed566Sopenharmony_ci 135d6aed566Sopenharmony_ci uint16_t tFreeHdr; /* head of Tx free desc entries list */ 136d6aed566Sopenharmony_ci uint16_t tFreeNum; 137d6aed566Sopenharmony_ci struct TbufRecord *tbufRec; 138d6aed566Sopenharmony_ci SPIN_LOCK_S transLock; 139d6aed566Sopenharmony_ci 140d6aed566Sopenharmony_ci struct VirtnetHdr vnHdr; 141d6aed566Sopenharmony_ci}; 142d6aed566Sopenharmony_ci 143d6aed566Sopenharmony_cistatic bool Feature0(uint32_t features, uint32_t *supported, void *dev) 144d6aed566Sopenharmony_ci{ 145d6aed566Sopenharmony_ci struct netif *netif = dev; 146d6aed566Sopenharmony_ci struct VirtNetif *nic = netif->state; 147d6aed566Sopenharmony_ci struct VirtnetConfig *conf = (struct VirtnetConfig *)(nic->dev.base + VIRTMMIO_REG_CONFIG); 148d6aed566Sopenharmony_ci int i; 149d6aed566Sopenharmony_ci 150d6aed566Sopenharmony_ci if (features & VIRTIO_NET_F_MTU) { 151d6aed566Sopenharmony_ci if (conf->mtu > ETH_DATA_LEN) { 152d6aed566Sopenharmony_ci PRINT_ERR("unsupported backend net MTU: %u\n", conf->mtu); 153d6aed566Sopenharmony_ci return false; 154d6aed566Sopenharmony_ci } 155d6aed566Sopenharmony_ci netif->mtu = conf->mtu; 156d6aed566Sopenharmony_ci *supported |= VIRTIO_NET_F_MTU; 157d6aed566Sopenharmony_ci } else { 158d6aed566Sopenharmony_ci netif->mtu = ETH_DATA_LEN; 159d6aed566Sopenharmony_ci } 160d6aed566Sopenharmony_ci 161d6aed566Sopenharmony_ci LOS_ASSERT(features & VIRTIO_NET_F_MAC); 162d6aed566Sopenharmony_ci for (i = 0; i < ETHARP_HWADDR_LEN; i++) { 163d6aed566Sopenharmony_ci netif->hwaddr[i] = conf->mac[i]; 164d6aed566Sopenharmony_ci } 165d6aed566Sopenharmony_ci netif->hwaddr_len = ETHARP_HWADDR_LEN; 166d6aed566Sopenharmony_ci *supported |= VIRTIO_NET_F_MAC; 167d6aed566Sopenharmony_ci 168d6aed566Sopenharmony_ci return true; 169d6aed566Sopenharmony_ci} 170d6aed566Sopenharmony_ci 171d6aed566Sopenharmony_cistatic bool Feature1(uint32_t features, uint32_t *supported, void *dev) 172d6aed566Sopenharmony_ci{ 173d6aed566Sopenharmony_ci if (features & VIRTIO_F_VERSION_1) { 174d6aed566Sopenharmony_ci *supported |= VIRTIO_F_VERSION_1; 175d6aed566Sopenharmony_ci } else { 176d6aed566Sopenharmony_ci PRINT_ERR("net device has no VERSION_1 feature\n"); 177d6aed566Sopenharmony_ci return false; 178d6aed566Sopenharmony_ci } 179d6aed566Sopenharmony_ci 180d6aed566Sopenharmony_ci return true; 181d6aed566Sopenharmony_ci} 182d6aed566Sopenharmony_ci 183d6aed566Sopenharmony_cistatic err_t InitTxFreelist(struct VirtNetif *nic) 184d6aed566Sopenharmony_ci{ 185d6aed566Sopenharmony_ci int i; 186d6aed566Sopenharmony_ci 187d6aed566Sopenharmony_ci nic->tbufRec = malloc(sizeof(struct TbufRecord) * nic->dev.vq[1].qsz); 188d6aed566Sopenharmony_ci if (nic->tbufRec == NULL) { 189d6aed566Sopenharmony_ci PRINT_ERR("alloc nic->tbufRec memory failed\n"); 190d6aed566Sopenharmony_ci return ERR_MEM; 191d6aed566Sopenharmony_ci } 192d6aed566Sopenharmony_ci 193d6aed566Sopenharmony_ci for (i = 0; i < nic->dev.vq[1].qsz - 1; i++) { 194d6aed566Sopenharmony_ci nic->dev.vq[1].desc[i].flag = VIRTQ_DESC_F_NEXT; 195d6aed566Sopenharmony_ci nic->dev.vq[1].desc[i].next = i + 1; 196d6aed566Sopenharmony_ci } 197d6aed566Sopenharmony_ci nic->tFreeHdr = 0; 198d6aed566Sopenharmony_ci nic->tFreeNum = nic->dev.vq[1].qsz; 199d6aed566Sopenharmony_ci 200d6aed566Sopenharmony_ci return ERR_OK; 201d6aed566Sopenharmony_ci} 202d6aed566Sopenharmony_ci 203d6aed566Sopenharmony_cistatic void FreeTxEntry(struct VirtNetif *nic, uint16_t head) 204d6aed566Sopenharmony_ci{ 205d6aed566Sopenharmony_ci uint16_t count, idx, tail; 206d6aed566Sopenharmony_ci struct pbuf *phead = NULL; 207d6aed566Sopenharmony_ci struct Virtq *q = &nic->dev.vq[1]; 208d6aed566Sopenharmony_ci 209d6aed566Sopenharmony_ci idx = q->desc[head].next; 210d6aed566Sopenharmony_ci phead = nic->tbufRec[idx].head; 211d6aed566Sopenharmony_ci count = nic->tbufRec[idx].count; 212d6aed566Sopenharmony_ci tail = nic->tbufRec[idx].tail; 213d6aed566Sopenharmony_ci 214d6aed566Sopenharmony_ci LOS_SpinLock(&nic->transLock); 215d6aed566Sopenharmony_ci if (nic->tFreeNum > 0) { 216d6aed566Sopenharmony_ci q->desc[tail].next = nic->tFreeHdr; 217d6aed566Sopenharmony_ci q->desc[tail].flag = VIRTQ_DESC_F_NEXT; 218d6aed566Sopenharmony_ci } 219d6aed566Sopenharmony_ci nic->tFreeNum += count; 220d6aed566Sopenharmony_ci nic->tFreeHdr = head; 221d6aed566Sopenharmony_ci LOS_SpinUnlock(&nic->transLock); 222d6aed566Sopenharmony_ci 223d6aed566Sopenharmony_ci pbuf_free_callback(phead); 224d6aed566Sopenharmony_ci} 225d6aed566Sopenharmony_ci 226d6aed566Sopenharmony_cistatic void ReleaseRxEntry(struct pbuf *p) 227d6aed566Sopenharmony_ci{ 228d6aed566Sopenharmony_ci struct RbufRecord *pc = (struct RbufRecord *)p; 229d6aed566Sopenharmony_ci struct VirtNetif *nic = pc->nic; 230d6aed566Sopenharmony_ci uint32_t intSave; 231d6aed566Sopenharmony_ci 232d6aed566Sopenharmony_ci LOS_SpinLockSave(&nic->recvLock, &intSave); 233d6aed566Sopenharmony_ci nic->dev.vq[0].avail->ring[nic->dev.vq[0].avail->index % nic->dev.vq[0].qsz] = pc->id; 234d6aed566Sopenharmony_ci DSB; 235d6aed566Sopenharmony_ci nic->dev.vq[0].avail->index++; 236d6aed566Sopenharmony_ci LOS_SpinUnlockRestore(&nic->recvLock, intSave); 237d6aed566Sopenharmony_ci 238d6aed566Sopenharmony_ci if (nic->dev.vq[0].used->flag != VIRTQ_USED_F_NO_NOTIFY) { 239d6aed566Sopenharmony_ci FENCE_WRITE_UINT32(0, nic->dev.base + VIRTMMIO_REG_QUEUENOTIFY); 240d6aed566Sopenharmony_ci } 241d6aed566Sopenharmony_ci} 242d6aed566Sopenharmony_ci 243d6aed566Sopenharmony_cistatic err_t ConfigRxBuffer(struct VirtNetif *nic, VADDR_T buf) 244d6aed566Sopenharmony_ci{ 245d6aed566Sopenharmony_ci uint32_t i; 246d6aed566Sopenharmony_ci PADDR_T paddr; 247d6aed566Sopenharmony_ci struct Virtq *q = &nic->dev.vq[0]; 248d6aed566Sopenharmony_ci 249d6aed566Sopenharmony_ci nic->rbufRec = calloc(q->qsz, sizeof(struct RbufRecord)); 250d6aed566Sopenharmony_ci if (nic->rbufRec == NULL) { 251d6aed566Sopenharmony_ci PRINT_ERR("alloc nic->rbufRec memory failed\n"); 252d6aed566Sopenharmony_ci return ERR_MEM; 253d6aed566Sopenharmony_ci } 254d6aed566Sopenharmony_ci 255d6aed566Sopenharmony_ci paddr = VMM_TO_DMA_ADDR(buf); 256d6aed566Sopenharmony_ci 257d6aed566Sopenharmony_ci for (i = 0; i < q->qsz; i++) { 258d6aed566Sopenharmony_ci q->desc[i].pAddr = u32_to_u64(paddr); 259d6aed566Sopenharmony_ci q->desc[i].len = sizeof(struct VirtnetHdr) + ETH_FRAME_LEN; 260d6aed566Sopenharmony_ci q->desc[i].flag = VIRTQ_DESC_F_WRITE; 261d6aed566Sopenharmony_ci paddr += VIRTQ_RXBUF_SIZE; 262d6aed566Sopenharmony_ci 263d6aed566Sopenharmony_ci q->avail->ring[i] = i; 264d6aed566Sopenharmony_ci 265d6aed566Sopenharmony_ci nic->rbufRec[i].cbuf.custom_free_function = ReleaseRxEntry; 266d6aed566Sopenharmony_ci nic->rbufRec[i].nic = nic; 267d6aed566Sopenharmony_ci nic->rbufRec[i].id = i; 268d6aed566Sopenharmony_ci } 269d6aed566Sopenharmony_ci 270d6aed566Sopenharmony_ci return ERR_OK; 271d6aed566Sopenharmony_ci} 272d6aed566Sopenharmony_ci 273d6aed566Sopenharmony_cistatic err_t ConfigQueue(struct VirtNetif *nic) 274d6aed566Sopenharmony_ci{ 275d6aed566Sopenharmony_ci VADDR_T buf, pad; 276d6aed566Sopenharmony_ci void *base = NULL; 277d6aed566Sopenharmony_ci err_t ret; 278d6aed566Sopenharmony_ci size_t size; 279d6aed566Sopenharmony_ci uint16_t qsz[VIRTQ_NUM_NET]; 280d6aed566Sopenharmony_ci 281d6aed566Sopenharmony_ci /* 282d6aed566Sopenharmony_ci * lwip request (packet address - ETH_PAD_SIZE) must align with 4B. 283d6aed566Sopenharmony_ci * We pad before the first Rx buf to happy it. Rx buf = VirtnetHdr + packet, 284d6aed566Sopenharmony_ci * then (buf base + pad + VirtnetHdr - ETH_PAD_SIZE) should align with 4B. 285d6aed566Sopenharmony_ci * When allocating memory, VIRTQ_RXBUF_ALIGN - 1 is enough for padding. 286d6aed566Sopenharmony_ci */ 287d6aed566Sopenharmony_ci qsz[0] = VIRTMMIO_NETIF_DFT_RXQSZ; 288d6aed566Sopenharmony_ci qsz[1] = VIRTMMIO_NETIF_DFT_TXQSZ; 289d6aed566Sopenharmony_ci size = VirtqSize(qsz[0]) + VirtqSize(qsz[1]) + VIRTQ_RXBUF_ALIGN - 1 + qsz[0] * VIRTQ_RXBUF_SIZE; 290d6aed566Sopenharmony_ci 291d6aed566Sopenharmony_ci base = calloc(1, size); 292d6aed566Sopenharmony_ci if (base == NULL) { 293d6aed566Sopenharmony_ci PRINT_ERR("alloc queues memory failed\n"); 294d6aed566Sopenharmony_ci return ERR_MEM; 295d6aed566Sopenharmony_ci } 296d6aed566Sopenharmony_ci 297d6aed566Sopenharmony_ci buf = VirtmmioConfigQueue(&nic->dev, (VADDR_T)base, qsz, VIRTQ_NUM_NET); 298d6aed566Sopenharmony_ci if (buf == 0) { 299d6aed566Sopenharmony_ci return ERR_IF; 300d6aed566Sopenharmony_ci } 301d6aed566Sopenharmony_ci 302d6aed566Sopenharmony_ci pad = (buf + sizeof(struct VirtnetHdr) - ETH_PAD_SIZE) % VIRTQ_RXBUF_ALIGN; 303d6aed566Sopenharmony_ci if (pad) { 304d6aed566Sopenharmony_ci pad = VIRTQ_RXBUF_ALIGN - pad; 305d6aed566Sopenharmony_ci } 306d6aed566Sopenharmony_ci buf += pad; 307d6aed566Sopenharmony_ci if ((ret = ConfigRxBuffer(nic, buf)) != ERR_OK) { 308d6aed566Sopenharmony_ci return ret; 309d6aed566Sopenharmony_ci } 310d6aed566Sopenharmony_ci 311d6aed566Sopenharmony_ci if ((ret = InitTxFreelist(nic)) != ERR_OK) { 312d6aed566Sopenharmony_ci return ret; 313d6aed566Sopenharmony_ci } 314d6aed566Sopenharmony_ci 315d6aed566Sopenharmony_ci return ERR_OK; 316d6aed566Sopenharmony_ci} 317d6aed566Sopenharmony_ci 318d6aed566Sopenharmony_cistatic uint16_t GetTxFreeEntry(struct VirtNetif *nic, uint16_t count) 319d6aed566Sopenharmony_ci{ 320d6aed566Sopenharmony_ci uint32_t intSave; 321d6aed566Sopenharmony_ci uint16_t head, tail, idx; 322d6aed566Sopenharmony_ci 323d6aed566Sopenharmony_ciRETRY: 324d6aed566Sopenharmony_ci LOS_SpinLockSave(&nic->transLock, &intSave); 325d6aed566Sopenharmony_ci if (count > nic->tFreeNum) { 326d6aed566Sopenharmony_ci LOS_SpinUnlockRestore(&nic->transLock, intSave); 327d6aed566Sopenharmony_ci LOS_TaskYield(); 328d6aed566Sopenharmony_ci goto RETRY; 329d6aed566Sopenharmony_ci } 330d6aed566Sopenharmony_ci 331d6aed566Sopenharmony_ci nic->tFreeNum -= count; 332d6aed566Sopenharmony_ci head = nic->tFreeHdr; 333d6aed566Sopenharmony_ci idx = head; 334d6aed566Sopenharmony_ci while (count--) { 335d6aed566Sopenharmony_ci tail = idx; 336d6aed566Sopenharmony_ci idx = nic->dev.vq[1].desc[idx].next; 337d6aed566Sopenharmony_ci } 338d6aed566Sopenharmony_ci nic->tFreeHdr = idx; /* may be invalid if empty, but tFreeNum must be valid: 0 */ 339d6aed566Sopenharmony_ci LOS_SpinUnlockRestore(&nic->transLock, intSave); 340d6aed566Sopenharmony_ci nic->dev.vq[1].desc[tail].flag &= ~VIRTQ_DESC_F_NEXT; 341d6aed566Sopenharmony_ci 342d6aed566Sopenharmony_ci return head; 343d6aed566Sopenharmony_ci} 344d6aed566Sopenharmony_ci 345d6aed566Sopenharmony_cistatic err_t LowLevelOutput(struct netif *netif, struct pbuf *p) 346d6aed566Sopenharmony_ci{ 347d6aed566Sopenharmony_ci uint16_t add, idx, head, tmp; 348d6aed566Sopenharmony_ci struct pbuf *q = NULL; 349d6aed566Sopenharmony_ci struct VirtNetif *nic = netif->state; 350d6aed566Sopenharmony_ci struct Virtq *trans = &nic->dev.vq[1]; 351d6aed566Sopenharmony_ci 352d6aed566Sopenharmony_ci#if ETH_PAD_SIZE 353d6aed566Sopenharmony_ci pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */ 354d6aed566Sopenharmony_ci#endif 355d6aed566Sopenharmony_ci 356d6aed566Sopenharmony_ci /* plus 1 for VirtnetHdr */ 357d6aed566Sopenharmony_ci add = pbuf_clen(p) + 1; 358d6aed566Sopenharmony_ci if (add > trans->qsz) { 359d6aed566Sopenharmony_ci PRINT_ERR("packet pbuf_clen %u larger than supported %u\n", add - 1, trans->qsz - 1); 360d6aed566Sopenharmony_ci return ERR_IF; 361d6aed566Sopenharmony_ci } 362d6aed566Sopenharmony_ci 363d6aed566Sopenharmony_ci head = GetTxFreeEntry(nic, add); 364d6aed566Sopenharmony_ci trans->desc[head].pAddr = u32_to_u64(VMM_TO_DMA_ADDR((PADDR_T)&nic->vnHdr)); 365d6aed566Sopenharmony_ci trans->desc[head].len = sizeof(struct VirtnetHdr); 366d6aed566Sopenharmony_ci idx = trans->desc[head].next; 367d6aed566Sopenharmony_ci tmp = head; 368d6aed566Sopenharmony_ci q = p; 369d6aed566Sopenharmony_ci while (q != NULL) { 370d6aed566Sopenharmony_ci tmp = trans->desc[tmp].next; 371d6aed566Sopenharmony_ci trans->desc[tmp].pAddr = u32_to_u64(VMM_TO_DMA_ADDR((PADDR_T)q->payload)); 372d6aed566Sopenharmony_ci trans->desc[tmp].len = q->len; 373d6aed566Sopenharmony_ci q = q->next; 374d6aed566Sopenharmony_ci } 375d6aed566Sopenharmony_ci 376d6aed566Sopenharmony_ci nic->tbufRec[idx].head = p; 377d6aed566Sopenharmony_ci nic->tbufRec[idx].count = add; 378d6aed566Sopenharmony_ci nic->tbufRec[idx].tail = tmp; 379d6aed566Sopenharmony_ci pbuf_ref(p); 380d6aed566Sopenharmony_ci 381d6aed566Sopenharmony_ci trans->avail->ring[trans->avail->index % trans->qsz] = head; 382d6aed566Sopenharmony_ci DSB; 383d6aed566Sopenharmony_ci trans->avail->index++; 384d6aed566Sopenharmony_ci FENCE_WRITE_UINT32(1, nic->dev.base + VIRTMMIO_REG_QUEUENOTIFY); 385d6aed566Sopenharmony_ci 386d6aed566Sopenharmony_ci#if ETH_PAD_SIZE 387d6aed566Sopenharmony_ci pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */ 388d6aed566Sopenharmony_ci#endif 389d6aed566Sopenharmony_ci 390d6aed566Sopenharmony_ci return ERR_OK; 391d6aed566Sopenharmony_ci} 392d6aed566Sopenharmony_ci 393d6aed566Sopenharmony_cistatic struct pbuf *LowLevelInput(const struct netif *netif, const struct VirtqUsedElem *e) 394d6aed566Sopenharmony_ci{ 395d6aed566Sopenharmony_ci struct VirtNetif *nic = netif->state; 396d6aed566Sopenharmony_ci struct pbuf *p = NULL; 397d6aed566Sopenharmony_ci uint16_t len; 398d6aed566Sopenharmony_ci VADDR_T payload; 399d6aed566Sopenharmony_ci 400d6aed566Sopenharmony_ci payload = DMA_TO_VMM_ADDR(nic->dev.vq[0].desc[e->id].pAddr) + sizeof(struct VirtnetHdr); 401d6aed566Sopenharmony_ci#if ETH_PAD_SIZE 402d6aed566Sopenharmony_ci payload -= ETH_PAD_SIZE; 403d6aed566Sopenharmony_ci#endif 404d6aed566Sopenharmony_ci pbuf_alloced_custom(PBUF_RAW, ETH_FRAME_LEN, PBUF_ROM | PBUF_ALLOC_FLAG_RX, 405d6aed566Sopenharmony_ci &nic->rbufRec[e->id].cbuf, (void *)payload, ETH_FRAME_LEN); 406d6aed566Sopenharmony_ci 407d6aed566Sopenharmony_ci len = e->len - sizeof(struct VirtnetHdr); 408d6aed566Sopenharmony_ci LOS_ASSERT(len <= ETH_FRAME_LEN); 409d6aed566Sopenharmony_ci#if ETH_PAD_SIZE 410d6aed566Sopenharmony_ci len += ETH_PAD_SIZE; 411d6aed566Sopenharmony_ci#endif 412d6aed566Sopenharmony_ci 413d6aed566Sopenharmony_ci p = &nic->rbufRec[e->id].cbuf.pbuf; 414d6aed566Sopenharmony_ci p->len = len; 415d6aed566Sopenharmony_ci p->tot_len = p->len; 416d6aed566Sopenharmony_ci return p; 417d6aed566Sopenharmony_ci} 418d6aed566Sopenharmony_ci 419d6aed566Sopenharmony_cistatic void VirtnetRxHandle(struct netif *netif) 420d6aed566Sopenharmony_ci{ 421d6aed566Sopenharmony_ci struct VirtNetif *nic = netif->state; 422d6aed566Sopenharmony_ci struct Virtq *q = &nic->dev.vq[0]; 423d6aed566Sopenharmony_ci struct pbuf *buf = NULL; 424d6aed566Sopenharmony_ci struct VirtqUsedElem *e = NULL; 425d6aed566Sopenharmony_ci 426d6aed566Sopenharmony_ci q->avail->flag = VIRTQ_AVAIL_F_NO_INTERRUPT; 427d6aed566Sopenharmony_ci while (1) { 428d6aed566Sopenharmony_ci if (q->last == q->used->index) { 429d6aed566Sopenharmony_ci q->avail->flag = 0; 430d6aed566Sopenharmony_ci /* recheck if new one come in between empty ring and enable interrupt */ 431d6aed566Sopenharmony_ci DSB; 432d6aed566Sopenharmony_ci if (q->last == q->used->index) { 433d6aed566Sopenharmony_ci break; 434d6aed566Sopenharmony_ci } 435d6aed566Sopenharmony_ci q->avail->flag = VIRTQ_AVAIL_F_NO_INTERRUPT; 436d6aed566Sopenharmony_ci } 437d6aed566Sopenharmony_ci 438d6aed566Sopenharmony_ci DSB; 439d6aed566Sopenharmony_ci e = &q->used->ring[q->last % q->qsz]; 440d6aed566Sopenharmony_ci buf = LowLevelInput(netif, e); 441d6aed566Sopenharmony_ci if (netif->input(buf, netif) != ERR_OK) { 442d6aed566Sopenharmony_ci LWIP_DEBUGF(NETIF_DEBUG, ("IP input error\n")); 443d6aed566Sopenharmony_ci ReleaseRxEntry(buf); 444d6aed566Sopenharmony_ci } 445d6aed566Sopenharmony_ci 446d6aed566Sopenharmony_ci q->last++; 447d6aed566Sopenharmony_ci } 448d6aed566Sopenharmony_ci} 449d6aed566Sopenharmony_ci 450d6aed566Sopenharmony_cistatic void VirtnetTxHandle(struct VirtNetif *nic) 451d6aed566Sopenharmony_ci{ 452d6aed566Sopenharmony_ci struct Virtq *q = &nic->dev.vq[1]; 453d6aed566Sopenharmony_ci struct VirtqUsedElem *e = NULL; 454d6aed566Sopenharmony_ci 455d6aed566Sopenharmony_ci /* Bypass recheck as VirtnetRxHandle */ 456d6aed566Sopenharmony_ci q->avail->flag = VIRTQ_AVAIL_F_NO_INTERRUPT; 457d6aed566Sopenharmony_ci while (q->last != q->used->index) { 458d6aed566Sopenharmony_ci DSB; 459d6aed566Sopenharmony_ci e = &q->used->ring[q->last % q->qsz]; 460d6aed566Sopenharmony_ci FreeTxEntry(nic, e->id); 461d6aed566Sopenharmony_ci q->last++; 462d6aed566Sopenharmony_ci } 463d6aed566Sopenharmony_ci q->avail->flag = 0; 464d6aed566Sopenharmony_ci} 465d6aed566Sopenharmony_ci 466d6aed566Sopenharmony_cistatic void VirtnetIRQhandle(void *param) 467d6aed566Sopenharmony_ci{ 468d6aed566Sopenharmony_ci struct netif *netif = (struct netif *)param; 469d6aed566Sopenharmony_ci struct VirtNetif *nic = netif->state; 470d6aed566Sopenharmony_ci 471d6aed566Sopenharmony_ci if (!(GET_UINT32(nic->dev.base + VIRTMMIO_REG_INTERRUPTSTATUS) & VIRTMMIO_IRQ_NOTIFY_USED)) { 472d6aed566Sopenharmony_ci return; 473d6aed566Sopenharmony_ci } 474d6aed566Sopenharmony_ci 475d6aed566Sopenharmony_ci VirtnetRxHandle(netif); 476d6aed566Sopenharmony_ci 477d6aed566Sopenharmony_ci VirtnetTxHandle(nic); 478d6aed566Sopenharmony_ci 479d6aed566Sopenharmony_ci FENCE_WRITE_UINT32(VIRTMMIO_IRQ_NOTIFY_USED, nic->dev.base + VIRTMMIO_REG_INTERRUPTACK); 480d6aed566Sopenharmony_ci} 481d6aed566Sopenharmony_ci 482d6aed566Sopenharmony_cistatic err_t LowLevelInit(struct netif *netif) 483d6aed566Sopenharmony_ci{ 484d6aed566Sopenharmony_ci struct VirtNetif *nic = netif->state; 485d6aed566Sopenharmony_ci int ret; 486d6aed566Sopenharmony_ci 487d6aed566Sopenharmony_ci if (!VirtmmioDiscover(VIRTMMIO_DEVICE_ID_NET, &nic->dev)) { 488d6aed566Sopenharmony_ci return ERR_IF; 489d6aed566Sopenharmony_ci } 490d6aed566Sopenharmony_ci 491d6aed566Sopenharmony_ci VirtmmioInitBegin(&nic->dev); 492d6aed566Sopenharmony_ci 493d6aed566Sopenharmony_ci if (!VirtmmioNegotiate(&nic->dev, Feature0, Feature1, netif)) { 494d6aed566Sopenharmony_ci ret = ERR_IF; 495d6aed566Sopenharmony_ci goto ERR_OUT; 496d6aed566Sopenharmony_ci } 497d6aed566Sopenharmony_ci 498d6aed566Sopenharmony_ci if ((ret = ConfigQueue(nic)) != ERR_OK) { 499d6aed566Sopenharmony_ci goto ERR_OUT; 500d6aed566Sopenharmony_ci } 501d6aed566Sopenharmony_ci 502d6aed566Sopenharmony_ci if (!VirtmmioRegisterIRQ(&nic->dev, (HWI_PROC_FUNC)VirtnetIRQhandle, netif, VIRTMMIO_NETIF_NAME)) { 503d6aed566Sopenharmony_ci ret = ERR_IF; 504d6aed566Sopenharmony_ci goto ERR_OUT; 505d6aed566Sopenharmony_ci } 506d6aed566Sopenharmony_ci 507d6aed566Sopenharmony_ci VritmmioInitEnd(&nic->dev); 508d6aed566Sopenharmony_ci 509d6aed566Sopenharmony_ci /* everything is ready, now notify device the receive buffer */ 510d6aed566Sopenharmony_ci nic->dev.vq[0].avail->index += nic->dev.vq[0].qsz; 511d6aed566Sopenharmony_ci FENCE_WRITE_UINT32(0, nic->dev.base + VIRTMMIO_REG_QUEUENOTIFY); 512d6aed566Sopenharmony_ci return ERR_OK; 513d6aed566Sopenharmony_ci 514d6aed566Sopenharmony_ciERR_OUT: 515d6aed566Sopenharmony_ci VirtmmioInitFailed(&nic->dev); 516d6aed566Sopenharmony_ci return ret; 517d6aed566Sopenharmony_ci} 518d6aed566Sopenharmony_ci 519d6aed566Sopenharmony_cistatic err_t EthernetIfInit(struct netif *netif) 520d6aed566Sopenharmony_ci{ 521d6aed566Sopenharmony_ci struct VirtNetif *nic = NULL; 522d6aed566Sopenharmony_ci 523d6aed566Sopenharmony_ci LWIP_ASSERT("netif != NULL", (netif != NULL)); 524d6aed566Sopenharmony_ci 525d6aed566Sopenharmony_ci nic = mem_calloc(1, sizeof(struct VirtNetif)); 526d6aed566Sopenharmony_ci if (nic == NULL) { 527d6aed566Sopenharmony_ci PRINT_ERR("alloc nic memory failed\n"); 528d6aed566Sopenharmony_ci return ERR_MEM; 529d6aed566Sopenharmony_ci } 530d6aed566Sopenharmony_ci netif->state = nic; 531d6aed566Sopenharmony_ci 532d6aed566Sopenharmony_ci#if LWIP_NETIF_HOSTNAME 533d6aed566Sopenharmony_ci netif->hostname = VIRTMMIO_NETIF_NAME; 534d6aed566Sopenharmony_ci#endif 535d6aed566Sopenharmony_ci 536d6aed566Sopenharmony_ci strncpy_s(netif->name, sizeof(netif->name), VIRTMMIO_NETIF_NICK, sizeof(netif->name)); 537d6aed566Sopenharmony_ci strncpy_s(netif->full_name, sizeof(netif->full_name), VIRTMMIO_NETIF_NICK, sizeof(netif->full_name)); 538d6aed566Sopenharmony_ci 539d6aed566Sopenharmony_ci netif->output = etharp_output; 540d6aed566Sopenharmony_ci netif->linkoutput = LowLevelOutput; 541d6aed566Sopenharmony_ci 542d6aed566Sopenharmony_ci netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP; 543d6aed566Sopenharmony_ci 544d6aed566Sopenharmony_ci return LowLevelInit(netif); 545d6aed566Sopenharmony_ci} 546d6aed566Sopenharmony_ci 547d6aed566Sopenharmony_cistatic void VirtnetDeInit(struct netif *netif) 548d6aed566Sopenharmony_ci{ 549d6aed566Sopenharmony_ci struct VirtNetif *nic = netif->state; 550d6aed566Sopenharmony_ci 551d6aed566Sopenharmony_ci if (nic && (nic->dev.irq & ~_IRQ_MASK)) { 552d6aed566Sopenharmony_ci LOS_HwiDelete(nic->dev.irq, NULL); 553d6aed566Sopenharmony_ci } 554d6aed566Sopenharmony_ci if (nic && nic->rbufRec) { 555d6aed566Sopenharmony_ci free(nic->rbufRec); 556d6aed566Sopenharmony_ci } 557d6aed566Sopenharmony_ci if (nic && nic->tbufRec) { 558d6aed566Sopenharmony_ci free(nic->tbufRec); 559d6aed566Sopenharmony_ci } 560d6aed566Sopenharmony_ci if (nic && nic->dev.vq[0].desc) { 561d6aed566Sopenharmony_ci free(nic->dev.vq[0].desc); 562d6aed566Sopenharmony_ci } 563d6aed566Sopenharmony_ci if (nic) { 564d6aed566Sopenharmony_ci mem_free(nic); 565d6aed566Sopenharmony_ci } 566d6aed566Sopenharmony_ci mem_free(netif); 567d6aed566Sopenharmony_ci} 568d6aed566Sopenharmony_ci 569d6aed566Sopenharmony_cistruct netif *VirtnetInit(void) 570d6aed566Sopenharmony_ci{ 571d6aed566Sopenharmony_ci ip4_addr_t ip, mask, gw; 572d6aed566Sopenharmony_ci struct netif *netif = NULL; 573d6aed566Sopenharmony_ci 574d6aed566Sopenharmony_ci netif = mem_calloc(1, sizeof(struct netif)); 575d6aed566Sopenharmony_ci if (netif == NULL) { 576d6aed566Sopenharmony_ci PRINT_ERR("alloc netif memory failed\n"); 577d6aed566Sopenharmony_ci return NULL; 578d6aed566Sopenharmony_ci } 579d6aed566Sopenharmony_ci 580d6aed566Sopenharmony_ci ip.addr = ipaddr_addr(VIRTMMIO_NETIF_DFT_IP); 581d6aed566Sopenharmony_ci mask.addr = ipaddr_addr(VIRTMMIO_NETIF_DFT_MASK); 582d6aed566Sopenharmony_ci gw.addr = ipaddr_addr(VIRTMMIO_NETIF_DFT_GW); 583d6aed566Sopenharmony_ci if (netif_add(netif, &ip, &mask, &gw, netif->state, 584d6aed566Sopenharmony_ci EthernetIfInit, tcpip_input) == NULL) { 585d6aed566Sopenharmony_ci PRINT_ERR("add virtio-mmio net device failed\n"); 586d6aed566Sopenharmony_ci VirtnetDeInit(netif); 587d6aed566Sopenharmony_ci return NULL; 588d6aed566Sopenharmony_ci } 589d6aed566Sopenharmony_ci 590d6aed566Sopenharmony_ci return netif; 591d6aed566Sopenharmony_ci} 592d6aed566Sopenharmony_ci 593