1b30934cbSJiri Slaby /* 2b30934cbSJiri Slaby * QEMU educational PCI device 3b30934cbSJiri Slaby * 4b30934cbSJiri Slaby * Copyright (c) 2012-2015 Jiri Slaby 5b30934cbSJiri Slaby * 6b30934cbSJiri Slaby * Permission is hereby granted, free of charge, to any person obtaining a 7b30934cbSJiri Slaby * copy of this software and associated documentation files (the "Software"), 8b30934cbSJiri Slaby * to deal in the Software without restriction, including without limitation 9b30934cbSJiri Slaby * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10b30934cbSJiri Slaby * and/or sell copies of the Software, and to permit persons to whom the 11b30934cbSJiri Slaby * Software is furnished to do so, subject to the following conditions: 12b30934cbSJiri Slaby * 13b30934cbSJiri Slaby * The above copyright notice and this permission notice shall be included in 14b30934cbSJiri Slaby * all copies or substantial portions of the Software. 15b30934cbSJiri Slaby * 16b30934cbSJiri Slaby * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17b30934cbSJiri Slaby * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18b30934cbSJiri Slaby * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19b30934cbSJiri Slaby * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20b30934cbSJiri Slaby * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21b30934cbSJiri Slaby * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22b30934cbSJiri Slaby * DEALINGS IN THE SOFTWARE. 23b30934cbSJiri Slaby */ 24b30934cbSJiri Slaby 250d1c9782SPeter Maydell #include "qemu/osdep.h" 267b608e5dSChris Friedt #include "qemu/log.h" 27de9b602eSPhilippe Mathieu-Daudé #include "qemu/units.h" 28b30934cbSJiri Slaby #include "hw/pci/pci.h" 29eabb5782SPeter Xu #include "hw/pci/msi.h" 30b30934cbSJiri Slaby #include "qemu/timer.h" 31db1015e9SEduardo Habkost #include "qom/object.h" 32b30934cbSJiri Slaby #include "qemu/main-loop.h" /* iothread mutex */ 330b8fa32fSMarkus Armbruster #include "qemu/module.h" 34b30934cbSJiri Slaby #include "qapi/visitor.h" 35b30934cbSJiri Slaby 368371158bSLi Qiang #define TYPE_PCI_EDU_DEVICE "edu" 37db1015e9SEduardo Habkost typedef struct EduState EduState; 388110fa1dSEduardo Habkost DECLARE_INSTANCE_CHECKER(EduState, EDU, 398110fa1dSEduardo Habkost TYPE_PCI_EDU_DEVICE) 40b30934cbSJiri Slaby 41b30934cbSJiri Slaby #define FACT_IRQ 0x00000001 42b30934cbSJiri Slaby #define DMA_IRQ 0x00000100 43b30934cbSJiri Slaby 44b30934cbSJiri Slaby #define DMA_START 0x40000 45b30934cbSJiri Slaby #define DMA_SIZE 4096 46b30934cbSJiri Slaby 47db1015e9SEduardo Habkost struct EduState { 48b30934cbSJiri Slaby PCIDevice pdev; 49b30934cbSJiri Slaby MemoryRegion mmio; 50b30934cbSJiri Slaby 51b30934cbSJiri Slaby QemuThread thread; 52b30934cbSJiri Slaby QemuMutex thr_mutex; 53b30934cbSJiri Slaby QemuCond thr_cond; 54b30934cbSJiri Slaby bool stopping; 55b30934cbSJiri Slaby 56b30934cbSJiri Slaby uint32_t addr4; 57b30934cbSJiri Slaby uint32_t fact; 58b30934cbSJiri Slaby #define EDU_STATUS_COMPUTING 0x01 59b30934cbSJiri Slaby #define EDU_STATUS_IRQFACT 0x80 60b30934cbSJiri Slaby uint32_t status; 61b30934cbSJiri Slaby 62b30934cbSJiri Slaby uint32_t irq_status; 63b30934cbSJiri Slaby 64b30934cbSJiri Slaby #define EDU_DMA_RUN 0x1 65b30934cbSJiri Slaby #define EDU_DMA_DIR(cmd) (((cmd) & 0x2) >> 1) 66b30934cbSJiri Slaby # define EDU_DMA_FROM_PCI 0 67b30934cbSJiri Slaby # define EDU_DMA_TO_PCI 1 68b30934cbSJiri Slaby #define EDU_DMA_IRQ 0x4 69b30934cbSJiri Slaby struct dma_state { 70b30934cbSJiri Slaby dma_addr_t src; 71b30934cbSJiri Slaby dma_addr_t dst; 72b30934cbSJiri Slaby dma_addr_t cnt; 73b30934cbSJiri Slaby dma_addr_t cmd; 74b30934cbSJiri Slaby } dma; 75b30934cbSJiri Slaby QEMUTimer dma_timer; 76b30934cbSJiri Slaby char dma_buf[DMA_SIZE]; 77b30934cbSJiri Slaby uint64_t dma_mask; 78db1015e9SEduardo Habkost }; 79b30934cbSJiri Slaby 80eabb5782SPeter Xu static bool edu_msi_enabled(EduState *edu) 81eabb5782SPeter Xu { 82eabb5782SPeter Xu return msi_enabled(&edu->pdev); 83eabb5782SPeter Xu } 84eabb5782SPeter Xu 85b30934cbSJiri Slaby static void edu_raise_irq(EduState *edu, uint32_t val) 86b30934cbSJiri Slaby { 87b30934cbSJiri Slaby edu->irq_status |= val; 88b30934cbSJiri Slaby if (edu->irq_status) { 89eabb5782SPeter Xu if (edu_msi_enabled(edu)) { 90eabb5782SPeter Xu msi_notify(&edu->pdev, 0); 91eabb5782SPeter Xu } else { 92b30934cbSJiri Slaby pci_set_irq(&edu->pdev, 1); 93b30934cbSJiri Slaby } 94b30934cbSJiri Slaby } 95eabb5782SPeter Xu } 96b30934cbSJiri Slaby 97b30934cbSJiri Slaby static void edu_lower_irq(EduState *edu, uint32_t val) 98b30934cbSJiri Slaby { 99b30934cbSJiri Slaby edu->irq_status &= ~val; 100b30934cbSJiri Slaby 101eabb5782SPeter Xu if (!edu->irq_status && !edu_msi_enabled(edu)) { 102b30934cbSJiri Slaby pci_set_irq(&edu->pdev, 0); 103b30934cbSJiri Slaby } 104b30934cbSJiri Slaby } 105b30934cbSJiri Slaby 1063e64d7d7SChris Friedt static void edu_check_range(uint64_t xfer_start, uint64_t xfer_size, 1073e64d7d7SChris Friedt uint64_t dma_start, uint64_t dma_size) 108b30934cbSJiri Slaby { 1093e64d7d7SChris Friedt uint64_t xfer_end = xfer_start + xfer_size; 1103e64d7d7SChris Friedt uint64_t dma_end = dma_start + dma_size; 111b30934cbSJiri Slaby 11269826741SChris Friedt /* 11369826741SChris Friedt * 1. ensure we aren't overflowing 1143e64d7d7SChris Friedt * 2. ensure that xfer is within dma address range 11569826741SChris Friedt */ 1163e64d7d7SChris Friedt if (dma_end >= dma_start && xfer_end >= xfer_start && 1173e64d7d7SChris Friedt xfer_start >= dma_start && xfer_end <= dma_end) { 118b30934cbSJiri Slaby return; 119b30934cbSJiri Slaby } 120b30934cbSJiri Slaby 1217b608e5dSChris Friedt qemu_log_mask(LOG_GUEST_ERROR, 1227b608e5dSChris Friedt "EDU: DMA range 0x%016"PRIx64"-0x%016"PRIx64 1237fca21c8SLi Qiang " out of bounds (0x%016"PRIx64"-0x%016"PRIx64")!", 1243e64d7d7SChris Friedt xfer_start, xfer_end - 1, dma_start, dma_end - 1); 125b30934cbSJiri Slaby } 126b30934cbSJiri Slaby 127b30934cbSJiri Slaby static dma_addr_t edu_clamp_addr(const EduState *edu, dma_addr_t addr) 128b30934cbSJiri Slaby { 129b30934cbSJiri Slaby dma_addr_t res = addr & edu->dma_mask; 130b30934cbSJiri Slaby 131b30934cbSJiri Slaby if (addr != res) { 1327b608e5dSChris Friedt qemu_log_mask(LOG_GUEST_ERROR, 1337b608e5dSChris Friedt "EDU: clamping DMA 0x%016"PRIx64" to 0x%016"PRIx64"!", 1347b608e5dSChris Friedt addr, res); 135b30934cbSJiri Slaby } 136b30934cbSJiri Slaby 137b30934cbSJiri Slaby return res; 138b30934cbSJiri Slaby } 139b30934cbSJiri Slaby 140b30934cbSJiri Slaby static void edu_dma_timer(void *opaque) 141b30934cbSJiri Slaby { 142b30934cbSJiri Slaby EduState *edu = opaque; 143b30934cbSJiri Slaby bool raise_irq = false; 144b30934cbSJiri Slaby 145b30934cbSJiri Slaby if (!(edu->dma.cmd & EDU_DMA_RUN)) { 146b30934cbSJiri Slaby return; 147b30934cbSJiri Slaby } 148b30934cbSJiri Slaby 149b30934cbSJiri Slaby if (EDU_DMA_DIR(edu->dma.cmd) == EDU_DMA_FROM_PCI) { 1507fca21c8SLi Qiang uint64_t dst = edu->dma.dst; 151b30934cbSJiri Slaby edu_check_range(dst, edu->dma.cnt, DMA_START, DMA_SIZE); 152b30934cbSJiri Slaby dst -= DMA_START; 153b30934cbSJiri Slaby pci_dma_read(&edu->pdev, edu_clamp_addr(edu, edu->dma.src), 154b30934cbSJiri Slaby edu->dma_buf + dst, edu->dma.cnt); 155b30934cbSJiri Slaby } else { 1567fca21c8SLi Qiang uint64_t src = edu->dma.src; 157b30934cbSJiri Slaby edu_check_range(src, edu->dma.cnt, DMA_START, DMA_SIZE); 158b30934cbSJiri Slaby src -= DMA_START; 159b30934cbSJiri Slaby pci_dma_write(&edu->pdev, edu_clamp_addr(edu, edu->dma.dst), 160b30934cbSJiri Slaby edu->dma_buf + src, edu->dma.cnt); 161b30934cbSJiri Slaby } 162b30934cbSJiri Slaby 163b30934cbSJiri Slaby edu->dma.cmd &= ~EDU_DMA_RUN; 164b30934cbSJiri Slaby if (edu->dma.cmd & EDU_DMA_IRQ) { 165b30934cbSJiri Slaby raise_irq = true; 166b30934cbSJiri Slaby } 167b30934cbSJiri Slaby 168b30934cbSJiri Slaby if (raise_irq) { 169b30934cbSJiri Slaby edu_raise_irq(edu, DMA_IRQ); 170b30934cbSJiri Slaby } 171b30934cbSJiri Slaby } 172b30934cbSJiri Slaby 173b30934cbSJiri Slaby static void dma_rw(EduState *edu, bool write, dma_addr_t *val, dma_addr_t *dma, 174b30934cbSJiri Slaby bool timer) 175b30934cbSJiri Slaby { 176b30934cbSJiri Slaby if (write && (edu->dma.cmd & EDU_DMA_RUN)) { 177b30934cbSJiri Slaby return; 178b30934cbSJiri Slaby } 179b30934cbSJiri Slaby 180b30934cbSJiri Slaby if (write) { 181b30934cbSJiri Slaby *dma = *val; 182b30934cbSJiri Slaby } else { 183b30934cbSJiri Slaby *val = *dma; 184b30934cbSJiri Slaby } 185b30934cbSJiri Slaby 186b30934cbSJiri Slaby if (timer) { 187b30934cbSJiri Slaby timer_mod(&edu->dma_timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 100); 188b30934cbSJiri Slaby } 189b30934cbSJiri Slaby } 190b30934cbSJiri Slaby 191b30934cbSJiri Slaby static uint64_t edu_mmio_read(void *opaque, hwaddr addr, unsigned size) 192b30934cbSJiri Slaby { 193b30934cbSJiri Slaby EduState *edu = opaque; 194b30934cbSJiri Slaby uint64_t val = ~0ULL; 195b30934cbSJiri Slaby 196c45eb53aSLi Qiang if (addr < 0x80 && size != 4) { 197c45eb53aSLi Qiang return val; 198c45eb53aSLi Qiang } 199c45eb53aSLi Qiang 200c45eb53aSLi Qiang if (addr >= 0x80 && size != 4 && size != 8) { 201b30934cbSJiri Slaby return val; 202b30934cbSJiri Slaby } 203b30934cbSJiri Slaby 204b30934cbSJiri Slaby switch (addr) { 205b30934cbSJiri Slaby case 0x00: 206b30934cbSJiri Slaby val = 0x010000edu; 207b30934cbSJiri Slaby break; 208b30934cbSJiri Slaby case 0x04: 209b30934cbSJiri Slaby val = edu->addr4; 210b30934cbSJiri Slaby break; 211b30934cbSJiri Slaby case 0x08: 212b30934cbSJiri Slaby qemu_mutex_lock(&edu->thr_mutex); 213b30934cbSJiri Slaby val = edu->fact; 214b30934cbSJiri Slaby qemu_mutex_unlock(&edu->thr_mutex); 215b30934cbSJiri Slaby break; 216b30934cbSJiri Slaby case 0x20: 217d73415a3SStefan Hajnoczi val = qatomic_read(&edu->status); 218b30934cbSJiri Slaby break; 219b30934cbSJiri Slaby case 0x24: 220b30934cbSJiri Slaby val = edu->irq_status; 221b30934cbSJiri Slaby break; 222b30934cbSJiri Slaby case 0x80: 223b30934cbSJiri Slaby dma_rw(edu, false, &val, &edu->dma.src, false); 224b30934cbSJiri Slaby break; 225b30934cbSJiri Slaby case 0x88: 226b30934cbSJiri Slaby dma_rw(edu, false, &val, &edu->dma.dst, false); 227b30934cbSJiri Slaby break; 228b30934cbSJiri Slaby case 0x90: 229b30934cbSJiri Slaby dma_rw(edu, false, &val, &edu->dma.cnt, false); 230b30934cbSJiri Slaby break; 231b30934cbSJiri Slaby case 0x98: 232b30934cbSJiri Slaby dma_rw(edu, false, &val, &edu->dma.cmd, false); 233b30934cbSJiri Slaby break; 234b30934cbSJiri Slaby } 235b30934cbSJiri Slaby 236b30934cbSJiri Slaby return val; 237b30934cbSJiri Slaby } 238b30934cbSJiri Slaby 239b30934cbSJiri Slaby static void edu_mmio_write(void *opaque, hwaddr addr, uint64_t val, 240b30934cbSJiri Slaby unsigned size) 241b30934cbSJiri Slaby { 242b30934cbSJiri Slaby EduState *edu = opaque; 243b30934cbSJiri Slaby 244b30934cbSJiri Slaby if (addr < 0x80 && size != 4) { 245b30934cbSJiri Slaby return; 246b30934cbSJiri Slaby } 247b30934cbSJiri Slaby 248b30934cbSJiri Slaby if (addr >= 0x80 && size != 4 && size != 8) { 249b30934cbSJiri Slaby return; 250b30934cbSJiri Slaby } 251b30934cbSJiri Slaby 252b30934cbSJiri Slaby switch (addr) { 253b30934cbSJiri Slaby case 0x04: 254b30934cbSJiri Slaby edu->addr4 = ~val; 255b30934cbSJiri Slaby break; 256b30934cbSJiri Slaby case 0x08: 257d73415a3SStefan Hajnoczi if (qatomic_read(&edu->status) & EDU_STATUS_COMPUTING) { 258b30934cbSJiri Slaby break; 259b30934cbSJiri Slaby } 260b30934cbSJiri Slaby /* EDU_STATUS_COMPUTING cannot go 0->1 concurrently, because it is only 261b30934cbSJiri Slaby * set in this function and it is under the iothread mutex. 262b30934cbSJiri Slaby */ 263b30934cbSJiri Slaby qemu_mutex_lock(&edu->thr_mutex); 264b30934cbSJiri Slaby edu->fact = val; 265d73415a3SStefan Hajnoczi qatomic_or(&edu->status, EDU_STATUS_COMPUTING); 266b30934cbSJiri Slaby qemu_cond_signal(&edu->thr_cond); 267b30934cbSJiri Slaby qemu_mutex_unlock(&edu->thr_mutex); 268b30934cbSJiri Slaby break; 269b30934cbSJiri Slaby case 0x20: 270b30934cbSJiri Slaby if (val & EDU_STATUS_IRQFACT) { 271d73415a3SStefan Hajnoczi qatomic_or(&edu->status, EDU_STATUS_IRQFACT); 2722482aeeaSPaolo Bonzini /* Order check of the COMPUTING flag after setting IRQFACT. */ 2732482aeeaSPaolo Bonzini smp_mb__after_rmw(); 274b30934cbSJiri Slaby } else { 275d73415a3SStefan Hajnoczi qatomic_and(&edu->status, ~EDU_STATUS_IRQFACT); 276b30934cbSJiri Slaby } 277b30934cbSJiri Slaby break; 278b30934cbSJiri Slaby case 0x60: 279b30934cbSJiri Slaby edu_raise_irq(edu, val); 280b30934cbSJiri Slaby break; 281b30934cbSJiri Slaby case 0x64: 282b30934cbSJiri Slaby edu_lower_irq(edu, val); 283b30934cbSJiri Slaby break; 284b30934cbSJiri Slaby case 0x80: 285b30934cbSJiri Slaby dma_rw(edu, true, &val, &edu->dma.src, false); 286b30934cbSJiri Slaby break; 287b30934cbSJiri Slaby case 0x88: 288b30934cbSJiri Slaby dma_rw(edu, true, &val, &edu->dma.dst, false); 289b30934cbSJiri Slaby break; 290b30934cbSJiri Slaby case 0x90: 291b30934cbSJiri Slaby dma_rw(edu, true, &val, &edu->dma.cnt, false); 292b30934cbSJiri Slaby break; 293b30934cbSJiri Slaby case 0x98: 294b30934cbSJiri Slaby if (!(val & EDU_DMA_RUN)) { 295b30934cbSJiri Slaby break; 296b30934cbSJiri Slaby } 297b30934cbSJiri Slaby dma_rw(edu, true, &val, &edu->dma.cmd, true); 298b30934cbSJiri Slaby break; 299b30934cbSJiri Slaby } 300b30934cbSJiri Slaby } 301b30934cbSJiri Slaby 302b30934cbSJiri Slaby static const MemoryRegionOps edu_mmio_ops = { 303b30934cbSJiri Slaby .read = edu_mmio_read, 304b30934cbSJiri Slaby .write = edu_mmio_write, 305b30934cbSJiri Slaby .endianness = DEVICE_NATIVE_ENDIAN, 30620fb3105SLi Qiang .valid = { 30720fb3105SLi Qiang .min_access_size = 4, 30820fb3105SLi Qiang .max_access_size = 8, 30920fb3105SLi Qiang }, 31020fb3105SLi Qiang .impl = { 31120fb3105SLi Qiang .min_access_size = 4, 31220fb3105SLi Qiang .max_access_size = 8, 31320fb3105SLi Qiang }, 31420fb3105SLi Qiang 315b30934cbSJiri Slaby }; 316b30934cbSJiri Slaby 317b30934cbSJiri Slaby /* 318631b22eaSStefan Weil * We purposely use a thread, so that users are forced to wait for the status 319b30934cbSJiri Slaby * register. 320b30934cbSJiri Slaby */ 321b30934cbSJiri Slaby static void *edu_fact_thread(void *opaque) 322b30934cbSJiri Slaby { 323b30934cbSJiri Slaby EduState *edu = opaque; 324b30934cbSJiri Slaby 325b30934cbSJiri Slaby while (1) { 326b30934cbSJiri Slaby uint32_t val, ret = 1; 327b30934cbSJiri Slaby 328b30934cbSJiri Slaby qemu_mutex_lock(&edu->thr_mutex); 329d73415a3SStefan Hajnoczi while ((qatomic_read(&edu->status) & EDU_STATUS_COMPUTING) == 0 && 330b30934cbSJiri Slaby !edu->stopping) { 331b30934cbSJiri Slaby qemu_cond_wait(&edu->thr_cond, &edu->thr_mutex); 332b30934cbSJiri Slaby } 333b30934cbSJiri Slaby 334b30934cbSJiri Slaby if (edu->stopping) { 335b30934cbSJiri Slaby qemu_mutex_unlock(&edu->thr_mutex); 336b30934cbSJiri Slaby break; 337b30934cbSJiri Slaby } 338b30934cbSJiri Slaby 339b30934cbSJiri Slaby val = edu->fact; 340b30934cbSJiri Slaby qemu_mutex_unlock(&edu->thr_mutex); 341b30934cbSJiri Slaby 342b30934cbSJiri Slaby while (val > 0) { 343b30934cbSJiri Slaby ret *= val--; 344b30934cbSJiri Slaby } 345b30934cbSJiri Slaby 346b30934cbSJiri Slaby /* 347b30934cbSJiri Slaby * We should sleep for a random period here, so that students are 348b30934cbSJiri Slaby * forced to check the status properly. 349b30934cbSJiri Slaby */ 350b30934cbSJiri Slaby 351b30934cbSJiri Slaby qemu_mutex_lock(&edu->thr_mutex); 352b30934cbSJiri Slaby edu->fact = ret; 353b30934cbSJiri Slaby qemu_mutex_unlock(&edu->thr_mutex); 354d73415a3SStefan Hajnoczi qatomic_and(&edu->status, ~EDU_STATUS_COMPUTING); 355b30934cbSJiri Slaby 3562482aeeaSPaolo Bonzini /* Clear COMPUTING flag before checking IRQFACT. */ 3572482aeeaSPaolo Bonzini smp_mb__after_rmw(); 3582482aeeaSPaolo Bonzini 359d73415a3SStefan Hajnoczi if (qatomic_read(&edu->status) & EDU_STATUS_IRQFACT) { 360195801d7SStefan Hajnoczi bql_lock(); 361b30934cbSJiri Slaby edu_raise_irq(edu, FACT_IRQ); 362195801d7SStefan Hajnoczi bql_unlock(); 363b30934cbSJiri Slaby } 364b30934cbSJiri Slaby } 365b30934cbSJiri Slaby 366b30934cbSJiri Slaby return NULL; 367b30934cbSJiri Slaby } 368b30934cbSJiri Slaby 369f922254cSCao jin static void pci_edu_realize(PCIDevice *pdev, Error **errp) 370b30934cbSJiri Slaby { 371a519e389SLi Qiang EduState *edu = EDU(pdev); 372b30934cbSJiri Slaby uint8_t *pci_conf = pdev->config; 373b30934cbSJiri Slaby 374c25a67f0SPaolo Bonzini pci_config_set_interrupt_pin(pci_conf, 1); 375c25a67f0SPaolo Bonzini 376c25a67f0SPaolo Bonzini if (msi_init(pdev, 0, 1, true, false, errp)) { 377c25a67f0SPaolo Bonzini return; 378c25a67f0SPaolo Bonzini } 379c25a67f0SPaolo Bonzini 380b30934cbSJiri Slaby timer_init_ms(&edu->dma_timer, QEMU_CLOCK_VIRTUAL, edu_dma_timer, edu); 381b30934cbSJiri Slaby 382b30934cbSJiri Slaby qemu_mutex_init(&edu->thr_mutex); 383b30934cbSJiri Slaby qemu_cond_init(&edu->thr_cond); 384b30934cbSJiri Slaby qemu_thread_create(&edu->thread, "edu", edu_fact_thread, 385b30934cbSJiri Slaby edu, QEMU_THREAD_JOINABLE); 386b30934cbSJiri Slaby 387b30934cbSJiri Slaby memory_region_init_io(&edu->mmio, OBJECT(edu), &edu_mmio_ops, edu, 388de9b602eSPhilippe Mathieu-Daudé "edu-mmio", 1 * MiB); 389b30934cbSJiri Slaby pci_register_bar(pdev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &edu->mmio); 390b30934cbSJiri Slaby } 391b30934cbSJiri Slaby 392b30934cbSJiri Slaby static void pci_edu_uninit(PCIDevice *pdev) 393b30934cbSJiri Slaby { 394a519e389SLi Qiang EduState *edu = EDU(pdev); 395b30934cbSJiri Slaby 396b30934cbSJiri Slaby qemu_mutex_lock(&edu->thr_mutex); 397b30934cbSJiri Slaby edu->stopping = true; 398b30934cbSJiri Slaby qemu_mutex_unlock(&edu->thr_mutex); 399b30934cbSJiri Slaby qemu_cond_signal(&edu->thr_cond); 400b30934cbSJiri Slaby qemu_thread_join(&edu->thread); 401b30934cbSJiri Slaby 402b30934cbSJiri Slaby qemu_cond_destroy(&edu->thr_cond); 403b30934cbSJiri Slaby qemu_mutex_destroy(&edu->thr_mutex); 404b30934cbSJiri Slaby 405b30934cbSJiri Slaby timer_del(&edu->dma_timer); 406812e710aSFei Li msi_uninit(pdev); 407b30934cbSJiri Slaby } 408b30934cbSJiri Slaby 409b30934cbSJiri Slaby static void edu_instance_init(Object *obj) 410b30934cbSJiri Slaby { 411b30934cbSJiri Slaby EduState *edu = EDU(obj); 412b30934cbSJiri Slaby 413b30934cbSJiri Slaby edu->dma_mask = (1UL << 28) - 1; 41464a7b8deSFelipe Franciosi object_property_add_uint64_ptr(obj, "dma_mask", 415d2623129SMarkus Armbruster &edu->dma_mask, OBJ_PROP_FLAG_READWRITE); 416b30934cbSJiri Slaby } 417b30934cbSJiri Slaby 418*12d1a768SPhilippe Mathieu-Daudé static void edu_class_init(ObjectClass *class, const void *data) 419b30934cbSJiri Slaby { 420aae04907Skumar sourav DeviceClass *dc = DEVICE_CLASS(class); 421b30934cbSJiri Slaby PCIDeviceClass *k = PCI_DEVICE_CLASS(class); 422b30934cbSJiri Slaby 423f922254cSCao jin k->realize = pci_edu_realize; 424b30934cbSJiri Slaby k->exit = pci_edu_uninit; 425b30934cbSJiri Slaby k->vendor_id = PCI_VENDOR_ID_QEMU; 426b30934cbSJiri Slaby k->device_id = 0x11e8; 427b30934cbSJiri Slaby k->revision = 0x10; 428b30934cbSJiri Slaby k->class_id = PCI_CLASS_OTHERS; 429aae04907Skumar sourav set_bit(DEVICE_CATEGORY_MISC, dc->categories); 430b30934cbSJiri Slaby } 431b30934cbSJiri Slaby 432fbb23135SPhilippe Mathieu-Daudé static const TypeInfo edu_types[] = { 433b30934cbSJiri Slaby { 4348371158bSLi Qiang .name = TYPE_PCI_EDU_DEVICE, 435b30934cbSJiri Slaby .parent = TYPE_PCI_DEVICE, 436b30934cbSJiri Slaby .instance_size = sizeof(EduState), 437b30934cbSJiri Slaby .instance_init = edu_instance_init, 438b30934cbSJiri Slaby .class_init = edu_class_init, 439fbb23135SPhilippe Mathieu-Daudé .interfaces = (InterfaceInfo[]) { 440fbb23135SPhilippe Mathieu-Daudé { INTERFACE_CONVENTIONAL_PCI_DEVICE }, 441fbb23135SPhilippe Mathieu-Daudé { }, 442fbb23135SPhilippe Mathieu-Daudé }, 443fbb23135SPhilippe Mathieu-Daudé } 444b30934cbSJiri Slaby }; 445b30934cbSJiri Slaby 446fbb23135SPhilippe Mathieu-Daudé DEFINE_TYPES(edu_types) 447