/**************************************************************************** * drivers/virtio/virtio-mmio.c * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. The * ASF licenses this file to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the * License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. * ****************************************************************************/ /**************************************************************************** * Included Files ****************************************************************************/ #include #include #include #include #include #include #include #ifdef CONFIG_DRIVERS_VIRTIO_NET # include "virtio-mmio-net.h" #endif /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ #define ptr_to_uint64(x) ((uint64_t)(uintptr_t)(x)) /**************************************************************************** * Private Functions ****************************************************************************/ /**************************************************************************** * Name: virtq_create ****************************************************************************/ FAR struct virtqueue *virtq_create(uint32_t len) { FAR struct virtqueue *virtq = (FAR struct virtqueue *) kmm_zalloc(sizeof(struct virtqueue)); ASSERT(virtq); virtq->len = len; /* See: 2.6 Split Virtqueues */ virtq->desc = (FAR struct virtqueue_desc *) kmm_memalign(16, 16 * len); ASSERT(virtq->desc); virtq->avail = (FAR struct virtqueue_avail *) kmm_memalign(2, 6 + 2 * len); ASSERT(virtq->avail); virtq->used = (FAR struct virtqueue_used *) kmm_memalign(4, 6 + 8 * len); ASSERT(virtq->used); virtq->desc_virt = (FAR void **) kmm_memalign(16, sizeof(FAR void *) * len); ASSERT(virtq->desc_virt); vrtinfo("virtq=%p (len=%" PRId32 ")\n", virtq, len); vrtinfo("virtq->desc=%p \n", virtq->desc); vrtinfo("virtq->avail=%p \n", virtq->avail); vrtinfo("virtq->used=%p \n", virtq->used); virtq->avail->idx = 0; virtq->used->idx = 0; virtq->last_used_idx = 0; return virtq; } /**************************************************************************** * Name: virtq_dev_init ****************************************************************************/ static int virtio_dev_init(uintptr_t virt, uint32_t irq) { FAR struct virtio_mmio_regs *regs = (FAR struct virtio_mmio_regs *)virt; int ret = -ENODEV; uint32_t val; vrtinfo("examine virtio at 0x%" PRIxPTR "\n", virt); val = virtio_getreg32(®s->magic_value); if (VIRTIO_MAGIC != val) { vrterr("error: virtio at 0x%" PRIxPTR " had wrong magic value 0x%" PRIx32 "\n", virt, val); return ret; } val = virtio_getreg32(®s->version); if (VIRTIO_VERSION != val) { vrterr("error: virtio at 0x%" PRIxPTR " had wrong version 0x%" PRIx32 "\n", virt, val); return ret; } /* Reset */ virtio_putreg32(0, ®s->status); virtio_mb(); /* Set ack */ val = virtio_getreg32(®s->status) | VIRTIO_STATUS_ACKNOWLEDGE; virtio_putreg32(val, ®s->status); virtio_mb(); /* Set driver */ val = virtio_getreg32(®s->status) | VIRTIO_STATUS_DRIVER; virtio_putreg32(val, ®s->status); virtio_mb(); /* Check the device_id */ val = virtio_getreg32(®s->device_id); switch (val) { #ifdef CONFIG_DRIVERS_VIRTIO_NET case VIRTIO_DEV_NET: ret = virtio_mmio_net_init(regs, irq); break; #endif default: vrtwarn("unsupported device_id 0x%" PRIx32 "\n", val); } return ret; } /**************************************************************************** * Public Functions ****************************************************************************/ /**************************************************************************** * Name: virtq_alloc_desc ****************************************************************************/ uint32_t virtq_alloc_desc(FAR struct virtqueue *virtq, uint32_t idx, FAR void *addr) { uint32_t id = idx % virtq->len; vrtinfo("virtq=%p, idx=%" PRId32 "\n", virtq, idx); virtq->desc[id].addr = (uintptr_t)addr; virtq->desc_virt[id] = addr; return id; } /**************************************************************************** * Name: virtq_add_to_mmio_device ****************************************************************************/ void virtq_add_to_mmio_device(FAR struct virtio_mmio_regs *regs, FAR struct virtqueue *virtq, uint32_t queue_sel) { vrtinfo("==== queue_sel=%" PRId32 ", virtq->len=%" PRId32 "\n", queue_sel, virtq->len); virtio_putreg32(queue_sel, ®s->queue_sel); virtio_mb(); virtio_putreg32(virtq->len, ®s->queue_num); virtio_putreg32((uint32_t)(ptr_to_uint64(virtq->desc)), ®s->queue_desc_low); virtio_putreg32((uint32_t)(ptr_to_uint64(virtq->desc) >> 32), ®s->queue_desc_high); virtio_putreg32((uint32_t)(ptr_to_uint64(virtq->avail)), ®s->queue_avail_low); virtio_putreg32((uint32_t)(ptr_to_uint64(virtq->avail) >> 32), ®s->queue_avail_high); virtio_putreg32((uint32_t)(ptr_to_uint64(virtq->used)), ®s->queue_used_low); virtio_putreg32((uint32_t)(ptr_to_uint64(virtq->used) >> 32), ®s->queue_used_high); virtio_mb(); virtio_putreg32(1, ®s->queue_ready); } /**************************************************************************** * Name: virtio_mmio_init ****************************************************************************/ void virtio_mmio_init(void) { uintptr_t virtio = (uintptr_t)CONFIG_DRIVERS_VIRTIO_MMIO_BASE; uint32_t irq = CONFIG_DRIVERS_VIRTIO_MMIO_IRQ; uint32_t size = CONFIG_DRIVERS_VIRTIO_MMIO_REGSIZE; uint32_t i; for (i = 0; i < CONFIG_DRIVERS_VIRTIO_MMIO_NUM; i++) { virtio_dev_init(virtio + size * i, irq + i); } }