123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313 |
- /*
- * Virtio Syborg bindings
- *
- * Copyright (c) 2009 CodeSourcery
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
- #include "syborg.h"
- #include "sysbus.h"
- #include "virtio.h"
- #include "virtio-net.h"
- //#define DEBUG_SYBORG_VIRTIO
- #ifdef DEBUG_SYBORG_VIRTIO
- #define DPRINTF(fmt, ...) \
- do { printf("syborg_virtio: " fmt , ## __VA_ARGS__); } while (0)
- #define BADF(fmt, ...) \
- do { fprintf(stderr, "syborg_virtio: error: " fmt , ## __VA_ARGS__); \
- exit(1);} while (0)
- #else
- #define DPRINTF(fmt, ...) do {} while(0)
- #define BADF(fmt, ...) \
- do { fprintf(stderr, "syborg_virtio: error: " fmt , ## __VA_ARGS__);} while (0)
- #endif
- enum {
- SYBORG_VIRTIO_ID = 0,
- SYBORG_VIRTIO_DEVTYPE = 1,
- SYBORG_VIRTIO_HOST_FEATURES = 2,
- SYBORG_VIRTIO_GUEST_FEATURES = 3,
- SYBORG_VIRTIO_QUEUE_BASE = 4,
- SYBORG_VIRTIO_QUEUE_NUM = 5,
- SYBORG_VIRTIO_QUEUE_SEL = 6,
- SYBORG_VIRTIO_QUEUE_NOTIFY = 7,
- SYBORG_VIRTIO_STATUS = 8,
- SYBORG_VIRTIO_INT_ENABLE = 9,
- SYBORG_VIRTIO_INT_STATUS = 10
- };
- #define SYBORG_VIRTIO_CONFIG 0x100
- /* Device independent interface. */
- typedef struct {
- SysBusDevice busdev;
- VirtIODevice *vdev;
- qemu_irq irq;
- uint32_t int_enable;
- uint32_t id;
- NICConf nic;
- uint32_t host_features;
- virtio_net_conf net;
- } SyborgVirtIOProxy;
- static uint32_t syborg_virtio_readl(void *opaque, target_phys_addr_t offset)
- {
- SyborgVirtIOProxy *s = opaque;
- VirtIODevice *vdev = s->vdev;
- uint32_t ret;
- DPRINTF("readl 0x%x\n", (int)offset);
- if (offset >= SYBORG_VIRTIO_CONFIG) {
- return virtio_config_readl(vdev, offset - SYBORG_VIRTIO_CONFIG);
- }
- switch(offset >> 2) {
- case SYBORG_VIRTIO_ID:
- ret = SYBORG_ID_VIRTIO;
- break;
- case SYBORG_VIRTIO_DEVTYPE:
- ret = s->id;
- break;
- case SYBORG_VIRTIO_HOST_FEATURES:
- ret = s->host_features;
- break;
- case SYBORG_VIRTIO_GUEST_FEATURES:
- ret = vdev->guest_features;
- break;
- case SYBORG_VIRTIO_QUEUE_BASE:
- ret = virtio_queue_get_addr(vdev, vdev->queue_sel);
- break;
- case SYBORG_VIRTIO_QUEUE_NUM:
- ret = virtio_queue_get_num(vdev, vdev->queue_sel);
- break;
- case SYBORG_VIRTIO_QUEUE_SEL:
- ret = vdev->queue_sel;
- break;
- case SYBORG_VIRTIO_STATUS:
- ret = vdev->status;
- break;
- case SYBORG_VIRTIO_INT_ENABLE:
- ret = s->int_enable;
- break;
- case SYBORG_VIRTIO_INT_STATUS:
- ret = vdev->isr;
- break;
- default:
- BADF("Bad read offset 0x%x\n", (int)offset);
- return 0;
- }
- return ret;
- }
- static void syborg_virtio_writel(void *opaque, target_phys_addr_t offset,
- uint32_t value)
- {
- SyborgVirtIOProxy *s = opaque;
- VirtIODevice *vdev = s->vdev;
- DPRINTF("writel 0x%x = 0x%x\n", (int)offset, value);
- if (offset >= SYBORG_VIRTIO_CONFIG) {
- return virtio_config_writel(vdev, offset - SYBORG_VIRTIO_CONFIG,
- value);
- }
- switch (offset >> 2) {
- case SYBORG_VIRTIO_GUEST_FEATURES:
- virtio_set_features(vdev, value);
- break;
- case SYBORG_VIRTIO_QUEUE_BASE:
- if (value == 0)
- virtio_reset(vdev);
- else
- virtio_queue_set_addr(vdev, vdev->queue_sel, value);
- break;
- case SYBORG_VIRTIO_QUEUE_SEL:
- if (value < VIRTIO_PCI_QUEUE_MAX)
- vdev->queue_sel = value;
- break;
- case SYBORG_VIRTIO_QUEUE_NOTIFY:
- if (value < VIRTIO_PCI_QUEUE_MAX) {
- virtio_queue_notify(vdev, value);
- }
- break;
- case SYBORG_VIRTIO_STATUS:
- virtio_set_status(vdev, value & 0xFF);
- if (vdev->status == 0)
- virtio_reset(vdev);
- break;
- case SYBORG_VIRTIO_INT_ENABLE:
- s->int_enable = value;
- virtio_update_irq(vdev);
- break;
- case SYBORG_VIRTIO_INT_STATUS:
- vdev->isr &= ~value;
- virtio_update_irq(vdev);
- break;
- default:
- BADF("Bad write offset 0x%x\n", (int)offset);
- break;
- }
- }
- static uint32_t syborg_virtio_readw(void *opaque, target_phys_addr_t offset)
- {
- SyborgVirtIOProxy *s = opaque;
- VirtIODevice *vdev = s->vdev;
- DPRINTF("readw 0x%x\n", (int)offset);
- if (offset >= SYBORG_VIRTIO_CONFIG) {
- return virtio_config_readw(vdev, offset - SYBORG_VIRTIO_CONFIG);
- }
- BADF("Bad halfword read offset 0x%x\n", (int)offset);
- return -1;
- }
- static void syborg_virtio_writew(void *opaque, target_phys_addr_t offset,
- uint32_t value)
- {
- SyborgVirtIOProxy *s = opaque;
- VirtIODevice *vdev = s->vdev;
- DPRINTF("writew 0x%x = 0x%x\n", (int)offset, value);
- if (offset >= SYBORG_VIRTIO_CONFIG) {
- return virtio_config_writew(vdev, offset - SYBORG_VIRTIO_CONFIG,
- value);
- }
- BADF("Bad halfword write offset 0x%x\n", (int)offset);
- }
- static uint32_t syborg_virtio_readb(void *opaque, target_phys_addr_t offset)
- {
- SyborgVirtIOProxy *s = opaque;
- VirtIODevice *vdev = s->vdev;
- DPRINTF("readb 0x%x\n", (int)offset);
- if (offset >= SYBORG_VIRTIO_CONFIG) {
- return virtio_config_readb(vdev, offset - SYBORG_VIRTIO_CONFIG);
- }
- BADF("Bad byte read offset 0x%x\n", (int)offset);
- return -1;
- }
- static void syborg_virtio_writeb(void *opaque, target_phys_addr_t offset,
- uint32_t value)
- {
- SyborgVirtIOProxy *s = opaque;
- VirtIODevice *vdev = s->vdev;
- DPRINTF("writeb 0x%x = 0x%x\n", (int)offset, value);
- if (offset >= SYBORG_VIRTIO_CONFIG) {
- return virtio_config_writeb(vdev, offset - SYBORG_VIRTIO_CONFIG,
- value);
- }
- BADF("Bad byte write offset 0x%x\n", (int)offset);
- }
- static CPUReadMemoryFunc * const syborg_virtio_readfn[] = {
- syborg_virtio_readb,
- syborg_virtio_readw,
- syborg_virtio_readl
- };
- static CPUWriteMemoryFunc * const syborg_virtio_writefn[] = {
- syborg_virtio_writeb,
- syborg_virtio_writew,
- syborg_virtio_writel
- };
- static void syborg_virtio_update_irq(void *opaque, uint16_t vector)
- {
- SyborgVirtIOProxy *proxy = opaque;
- int level;
- level = proxy->int_enable & proxy->vdev->isr;
- DPRINTF("IRQ %d\n", level);
- qemu_set_irq(proxy->irq, level != 0);
- }
- static unsigned syborg_virtio_get_features(void *opaque)
- {
- SyborgVirtIOProxy *proxy = opaque;
- return proxy->host_features;
- }
- static VirtIOBindings syborg_virtio_bindings = {
- .notify = syborg_virtio_update_irq,
- .get_features = syborg_virtio_get_features,
- };
- static int syborg_virtio_init(SyborgVirtIOProxy *proxy, VirtIODevice *vdev)
- {
- int iomemtype;
- proxy->vdev = vdev;
- /* Don't support multiple vectors */
- proxy->vdev->nvectors = 0;
- sysbus_init_irq(&proxy->busdev, &proxy->irq);
- iomemtype = cpu_register_io_memory(syborg_virtio_readfn,
- syborg_virtio_writefn, proxy,
- DEVICE_NATIVE_ENDIAN);
- sysbus_init_mmio(&proxy->busdev, 0x1000, iomemtype);
- proxy->id = ((uint32_t)0x1af4 << 16) | vdev->device_id;
- qemu_register_reset(virtio_reset, vdev);
- virtio_bind_device(vdev, &syborg_virtio_bindings, proxy);
- proxy->host_features |= (0x1 << VIRTIO_F_NOTIFY_ON_EMPTY);
- proxy->host_features = vdev->get_features(vdev, proxy->host_features);
- return 0;
- }
- /* Device specific bindings. */
- static int syborg_virtio_net_init(SysBusDevice *dev)
- {
- VirtIODevice *vdev;
- SyborgVirtIOProxy *proxy = FROM_SYSBUS(SyborgVirtIOProxy, dev);
- vdev = virtio_net_init(&dev->qdev, &proxy->nic, &proxy->net);
- return syborg_virtio_init(proxy, vdev);
- }
- static SysBusDeviceInfo syborg_virtio_net_info = {
- .init = syborg_virtio_net_init,
- .qdev.name = "syborg,virtio-net",
- .qdev.size = sizeof(SyborgVirtIOProxy),
- .qdev.props = (Property[]) {
- DEFINE_NIC_PROPERTIES(SyborgVirtIOProxy, nic),
- DEFINE_VIRTIO_NET_FEATURES(SyborgVirtIOProxy, host_features),
- DEFINE_PROP_UINT32("x-txtimer", SyborgVirtIOProxy,
- net.txtimer, TX_TIMER_INTERVAL),
- DEFINE_PROP_INT32("x-txburst", SyborgVirtIOProxy,
- net.txburst, TX_BURST),
- DEFINE_PROP_STRING("tx", SyborgVirtIOProxy, net.tx),
- DEFINE_PROP_END_OF_LIST(),
- }
- };
- static void syborg_virtio_register_devices(void)
- {
- sysbus_register_withprop(&syborg_virtio_net_info);
- }
- device_init(syborg_virtio_register_devices)
|