symbian-qemu-0.9.1-12/qemu-symbian-svp/hw/syborg_virtio.c
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 /*
       
     2  * Virtio Syborg bindings
       
     3  *
       
     4  * Copyright (c) 2008 CodeSourcery
       
     5  *
       
     6  * Permission is hereby granted, free of charge, to any person obtaining a copy
       
     7  * of this software and associated documentation files (the "Software"), to deal
       
     8  * in the Software without restriction, including without limitation the rights
       
     9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       
    10  * copies of the Software, and to permit persons to whom the Software is
       
    11  * furnished to do so, subject to the following conditions:
       
    12  *
       
    13  * The above copyright notice and this permission notice shall be included in
       
    14  * all copies or substantial portions of the Software.
       
    15  *
       
    16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
       
    17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
       
    18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
       
    19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
       
    20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
       
    21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
       
    22  * THE SOFTWARE.
       
    23  */
       
    24 
       
    25 #include "virtio.h"
       
    26 #include "syborg.h"
       
    27 #include "devtree.h"
       
    28 #include "virtio-net.h"
       
    29 #include "virtio-audio.h"
       
    30 #include "sysemu.h"
       
    31 
       
    32 //#define DEBUG_SYBORG_VIRTIO
       
    33 
       
    34 #ifdef DEBUG_SYBORG_VIRTIO
       
    35 #define DPRINTF(fmt, args...) \
       
    36 do { printf("syborg_virtio: " fmt , ##args); } while (0)
       
    37 #define BADF(fmt, args...) \
       
    38 do { fprintf(stderr, "syborg_virtio: error: " fmt , ##args); exit(1);} while (0)
       
    39 #else
       
    40 #define DPRINTF(fmt, args...) do {} while(0)
       
    41 #define BADF(fmt, args...) \
       
    42 do { fprintf(stderr, "syborg_virtio: error: " fmt , ##args);} while (0)
       
    43 #endif
       
    44 
       
    45 enum {
       
    46     SYBORG_VIRTIO_ID             = 0,
       
    47     SYBORG_VIRTIO_DEVTYPE        = 1,
       
    48     SYBORG_VIRTIO_HOST_FEATURES  = 2,
       
    49     SYBORG_VIRTIO_GUEST_FEATURES = 3,
       
    50     SYBORG_VIRTIO_QUEUE_BASE     = 4,
       
    51     SYBORG_VIRTIO_QUEUE_NUM      = 5,
       
    52     SYBORG_VIRTIO_QUEUE_SEL      = 6,
       
    53     SYBORG_VIRTIO_QUEUE_NOTIFY   = 7,
       
    54     SYBORG_VIRTIO_STATUS         = 8,
       
    55     SYBORG_VIRTIO_INT_ENABLE     = 9,
       
    56     SYBORG_VIRTIO_INT_STATUS     = 10
       
    57 };
       
    58 
       
    59 #define SYBORG_VIRTIO_CONFIG 0x100
       
    60 
       
    61 /* Device independent interface.  */
       
    62 
       
    63 typedef struct {
       
    64     QEMUDevice *qdev;
       
    65     VirtIODevice *vdev;
       
    66     uint32_t int_enable;
       
    67     qemu_irq irq;
       
    68     int id;
       
    69 } syborg_virtio_state;
       
    70 
       
    71 static void syborg_virtio_update_irq(VirtIODevice *vdev)
       
    72 {
       
    73     syborg_virtio_state *s = vdev->binding_dev;
       
    74     int level;
       
    75 
       
    76     level = s->int_enable & vdev->isr;
       
    77     DPRINTF("IRQ %d\n", level);
       
    78     qemu_set_irq(s->irq, level != 0);
       
    79 }
       
    80 
       
    81 static uint32_t syborg_virtio_readl(void *opaque, target_phys_addr_t offset)
       
    82 {
       
    83     syborg_virtio_state *s = (syborg_virtio_state *)opaque;
       
    84     VirtIODevice *vdev = s->vdev;
       
    85     uint32_t ret;
       
    86 
       
    87     DPRINTF("readl 0x%x\n", (int)offset);
       
    88     offset &= 0xfff;
       
    89     if (offset >= SYBORG_VIRTIO_CONFIG) {
       
    90         return virtio_config_readl(vdev, offset - SYBORG_VIRTIO_CONFIG);
       
    91     }
       
    92     switch(offset >> 2) {
       
    93     case SYBORG_VIRTIO_ID:
       
    94         ret = SYBORG_ID_VIRTIO;
       
    95         break;
       
    96     case SYBORG_VIRTIO_DEVTYPE:
       
    97         ret = s->id;
       
    98         break;
       
    99     case SYBORG_VIRTIO_HOST_FEATURES:
       
   100         ret = vdev->get_features(vdev);
       
   101         ret |= (1 << VIRTIO_F_NOTIFY_ON_EMPTY);
       
   102         break;
       
   103     case SYBORG_VIRTIO_GUEST_FEATURES:
       
   104         ret = vdev->features;
       
   105         break;
       
   106     case SYBORG_VIRTIO_QUEUE_BASE:
       
   107         ret = virtio_get_vring_pa(vdev, vdev->queue_sel);
       
   108         break;
       
   109     case SYBORG_VIRTIO_QUEUE_NUM:
       
   110         ret = virtio_get_vring_num(vdev, vdev->queue_sel);
       
   111         break;
       
   112     case SYBORG_VIRTIO_QUEUE_SEL:
       
   113         ret = vdev->queue_sel;
       
   114         break;
       
   115     case SYBORG_VIRTIO_STATUS:
       
   116         ret = vdev->status;
       
   117         break;
       
   118     case SYBORG_VIRTIO_INT_ENABLE:
       
   119         ret = s->int_enable;
       
   120         break;
       
   121     case SYBORG_VIRTIO_INT_STATUS:
       
   122         ret = vdev->isr;
       
   123         break;
       
   124     default:
       
   125         BADF("Bad read offset 0x%x\n", (int)offset);
       
   126         return 0;  
       
   127     }
       
   128     return ret;
       
   129 }
       
   130 
       
   131 static void syborg_virtio_writel(void *opaque, target_phys_addr_t offset,
       
   132                                  uint32_t value)
       
   133 {
       
   134     syborg_virtio_state *s = (syborg_virtio_state *)opaque;
       
   135     VirtIODevice *vdev = s->vdev;
       
   136 
       
   137     DPRINTF("writel 0x%x = 0x%x\n", (int)offset, value);
       
   138     offset &= 0xfff;
       
   139     if (offset >= SYBORG_VIRTIO_CONFIG) {
       
   140         return virtio_config_writel(vdev, offset - SYBORG_VIRTIO_CONFIG,
       
   141                                     value);
       
   142     }
       
   143     switch (offset >> 2) {
       
   144     case SYBORG_VIRTIO_GUEST_FEATURES:
       
   145         if (vdev->set_features)
       
   146             vdev->set_features(vdev, value);
       
   147         vdev->features = value;
       
   148         break;
       
   149     case SYBORG_VIRTIO_QUEUE_BASE:
       
   150         virtio_set_vring_addr(vdev, vdev->queue_sel, value);
       
   151         break;
       
   152     case SYBORG_VIRTIO_QUEUE_SEL:
       
   153         if (value < VIRTIO_PCI_QUEUE_MAX)
       
   154             vdev->queue_sel = value;
       
   155         break;
       
   156     case SYBORG_VIRTIO_QUEUE_NOTIFY:
       
   157         virtio_kick(vdev, value);
       
   158         break;
       
   159     case SYBORG_VIRTIO_STATUS:
       
   160         vdev->status = value & 0xFF;
       
   161         if (vdev->status == 0)
       
   162             virtio_reset(vdev);
       
   163         break;
       
   164     case SYBORG_VIRTIO_INT_ENABLE:
       
   165         s->int_enable = value;
       
   166         virtio_update_irq(vdev);
       
   167         break;
       
   168     case SYBORG_VIRTIO_INT_STATUS:
       
   169         vdev->isr &= ~value;
       
   170         virtio_update_irq(vdev);
       
   171         break;
       
   172     default:
       
   173         BADF("Bad write offset 0x%x\n", (int)offset);
       
   174         break;
       
   175     }
       
   176 }
       
   177 
       
   178 static uint32_t syborg_virtio_readw(void *opaque, target_phys_addr_t offset)
       
   179 {
       
   180     syborg_virtio_state *s = (syborg_virtio_state *)opaque;
       
   181     VirtIODevice *vdev = s->vdev;
       
   182 
       
   183     DPRINTF("readw 0x%x\n", (int)offset);
       
   184     offset &= 0xfff;
       
   185     if (offset >= SYBORG_VIRTIO_CONFIG) {
       
   186         return virtio_config_readw(vdev, offset - SYBORG_VIRTIO_CONFIG);
       
   187     }
       
   188     BADF("Bad halfword read offset 0x%x\n", (int)offset);
       
   189     return -1;
       
   190 }
       
   191 
       
   192 static void syborg_virtio_writew(void *opaque, target_phys_addr_t offset,
       
   193                                  uint32_t value)
       
   194 {
       
   195     syborg_virtio_state *s = (syborg_virtio_state *)opaque;
       
   196     VirtIODevice *vdev = s->vdev;
       
   197 
       
   198     DPRINTF("writew 0x%x = 0x%x\n", (int)offset, value);
       
   199     offset &= 0xfff;
       
   200     if (offset >= SYBORG_VIRTIO_CONFIG) {
       
   201         return virtio_config_writew(vdev, offset - SYBORG_VIRTIO_CONFIG,
       
   202                                     value);
       
   203     }
       
   204     BADF("Bad halfword write offset 0x%x\n", (int)offset);
       
   205 }
       
   206 
       
   207 static uint32_t syborg_virtio_readb(void *opaque, target_phys_addr_t offset)
       
   208 {
       
   209     syborg_virtio_state *s = (syborg_virtio_state *)opaque;
       
   210     VirtIODevice *vdev = s->vdev;
       
   211 
       
   212     DPRINTF("readb 0x%x\n", (int)offset);
       
   213     offset &= 0xfff;
       
   214     if (offset >= SYBORG_VIRTIO_CONFIG) {
       
   215         return virtio_config_readb(vdev, offset - SYBORG_VIRTIO_CONFIG);
       
   216     }
       
   217     BADF("Bad byte read offset 0x%x\n", (int)offset);
       
   218     return -1;
       
   219 }
       
   220 
       
   221 static void syborg_virtio_writeb(void *opaque, target_phys_addr_t offset,
       
   222                                  uint32_t value)
       
   223 {
       
   224     syborg_virtio_state *s = (syborg_virtio_state *)opaque;
       
   225     VirtIODevice *vdev = s->vdev;
       
   226 
       
   227     DPRINTF("writeb 0x%x = 0x%x\n", (int)offset, value);
       
   228     offset &= 0xfff;
       
   229     if (offset >= SYBORG_VIRTIO_CONFIG) {
       
   230         return virtio_config_writeb(vdev, offset - SYBORG_VIRTIO_CONFIG,
       
   231                                     value);
       
   232     }
       
   233     BADF("Bad byte write offset 0x%x\n", (int)offset);
       
   234 }
       
   235 
       
   236 static CPUReadMemoryFunc *syborg_virtio_readfn[] = {
       
   237      syborg_virtio_readb,
       
   238      syborg_virtio_readw,
       
   239      syborg_virtio_readl
       
   240 };
       
   241 
       
   242 static CPUWriteMemoryFunc *syborg_virtio_writefn[] = {
       
   243      syborg_virtio_writeb,
       
   244      syborg_virtio_writew,
       
   245      syborg_virtio_writel
       
   246 };
       
   247 
       
   248 static void syborg_virtio_save_binding(VirtIODevice *vdev, QEMUFile *f)
       
   249 {
       
   250     /* Nothing to do.  */
       
   251 }
       
   252 
       
   253 static void syborg_virtio_load_binding(VirtIODevice *vdev, QEMUFile *f)
       
   254 {
       
   255     /* Nothing to do.  */
       
   256 }
       
   257 
       
   258 typedef struct {
       
   259     QEMUDevice *qdev;
       
   260 }  VirtIOSyborgArgs;
       
   261 
       
   262 static VirtIODevice *syborg_virtio_create(void *args, const char *name,
       
   263                                           uint16_t vendor, uint16_t type,
       
   264                                           size_t config_size,
       
   265                                           size_t struct_size)
       
   266 {
       
   267     VirtIODevice *vdev;
       
   268     VirtIOSyborgArgs *p = args;
       
   269     syborg_virtio_state *s;
       
   270 
       
   271     s = (syborg_virtio_state *)qemu_mallocz(sizeof(syborg_virtio_state));
       
   272     s->qdev = p->qdev;
       
   273     qdev_set_opaque(s->qdev, s);
       
   274     s->id = ((uint32_t)vendor << 16) | type;
       
   275     qdev_get_irq(s->qdev, 0, &s->irq);
       
   276 
       
   277     vdev = virtio_init_common(name, config_size, struct_size);
       
   278     s->vdev = vdev;
       
   279 
       
   280     vdev->binding_dev = s;
       
   281     vdev->update_irq = syborg_virtio_update_irq;
       
   282     vdev->save_binding = syborg_virtio_save_binding;
       
   283     vdev->load_binding = syborg_virtio_load_binding;
       
   284 
       
   285     return vdev;
       
   286 }
       
   287 
       
   288 /* Device specific bindings.  */
       
   289 
       
   290 static void syborg_virtio_net_create(QEMUDevice *dev)
       
   291 {
       
   292     int nic = nb_nics;
       
   293     VirtIOSyborgArgs args;
       
   294     args.qdev = dev;
       
   295     /* FIXME: add net options.  */
       
   296     if (net_client_init("nic", "") < 0)
       
   297         return;
       
   298     nd_table[nic].model = "virtio-net";
       
   299     virtio_net_init(syborg_virtio_create, &args, &nd_table[nic]);
       
   300 }
       
   301 
       
   302 static AudioState *audio_state;
       
   303 
       
   304 static void syborg_virtio_audio_create(QEMUDevice *dev)
       
   305 {
       
   306     VirtIOSyborgArgs args;
       
   307     args.qdev = dev;
       
   308     if (!audio_state)
       
   309         audio_state = AUD_init();
       
   310     virtio_audio_init(syborg_virtio_create, &args, audio_state);
       
   311 }
       
   312 
       
   313 static QEMUDeviceClass *syborg_virtio_register_common(const char *name,
       
   314                                                       QDEVCreateFn create)
       
   315 {
       
   316     QEMUDeviceClass *dc;
       
   317     dc = qdev_new(name, create, 1);
       
   318     qdev_add_registers(dc, syborg_virtio_readfn, syborg_virtio_writefn,
       
   319                        0x1000);
       
   320     return dc;
       
   321 }
       
   322 
       
   323 void syborg_virtio_register(void)
       
   324 {
       
   325     QEMUDeviceClass *dc;
       
   326     dc = syborg_virtio_register_common("syborg,virtio-net",
       
   327                                        syborg_virtio_net_create);
       
   328     /* FIXME */
       
   329     //qdev_add_netdev(dc);
       
   330     dc = syborg_virtio_register_common("syborg,virtio-audio",
       
   331                                        syborg_virtio_audio_create);
       
   332 }