|
|
1.1 ! root 1: /* ! 2: * ACPI implementation ! 3: * ! 4: * Copyright (c) 2006 Fabrice Bellard ! 5: * ! 6: * This library is free software; you can redistribute it and/or ! 7: * modify it under the terms of the GNU Lesser General Public ! 8: * License version 2 as published by the Free Software Foundation. ! 9: * ! 10: * This library is distributed in the hope that it will be useful, ! 11: * but WITHOUT ANY WARRANTY; without even the implied warranty of ! 12: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ! 13: * Lesser General Public License for more details. ! 14: * ! 15: * You should have received a copy of the GNU Lesser General Public ! 16: * License along with this library; if not, see <http://www.gnu.org/licenses/> ! 17: */ ! 18: #include "hw.h" ! 19: #include "pc.h" ! 20: #include "apm.h" ! 21: #include "pm_smbus.h" ! 22: #include "pci.h" ! 23: #include "acpi.h" ! 24: #include "sysemu.h" ! 25: ! 26: //#define DEBUG ! 27: ! 28: #ifdef DEBUG ! 29: # define PIIX4_DPRINTF(format, ...) printf(format, ## __VA_ARGS__) ! 30: #else ! 31: # define PIIX4_DPRINTF(format, ...) do { } while (0) ! 32: #endif ! 33: ! 34: #define ACPI_DBG_IO_ADDR 0xb044 ! 35: ! 36: #define GPE_BASE 0xafe0 ! 37: #define PCI_BASE 0xae00 ! 38: #define PCI_EJ_BASE 0xae08 ! 39: ! 40: struct gpe_regs { ! 41: uint16_t sts; /* status */ ! 42: uint16_t en; /* enabled */ ! 43: }; ! 44: ! 45: struct pci_status { ! 46: uint32_t up; ! 47: uint32_t down; ! 48: }; ! 49: ! 50: typedef struct PIIX4PMState { ! 51: PCIDevice dev; ! 52: uint16_t pmsts; ! 53: uint16_t pmen; ! 54: uint16_t pmcntrl; ! 55: ! 56: APMState apm; ! 57: ! 58: QEMUTimer *tmr_timer; ! 59: int64_t tmr_overflow_time; ! 60: ! 61: PMSMBus smb; ! 62: uint32_t smb_io_base; ! 63: ! 64: qemu_irq irq; ! 65: qemu_irq cmos_s3; ! 66: qemu_irq smi_irq; ! 67: int kvm_enabled; ! 68: ! 69: /* for pci hotplug */ ! 70: struct gpe_regs gpe; ! 71: struct pci_status pci0_status; ! 72: } PIIX4PMState; ! 73: ! 74: static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s); ! 75: ! 76: #define ACPI_ENABLE 0xf1 ! 77: #define ACPI_DISABLE 0xf0 ! 78: ! 79: static uint32_t get_pmtmr(PIIX4PMState *s) ! 80: { ! 81: uint32_t d; ! 82: d = muldiv64(qemu_get_clock(vm_clock), PM_TIMER_FREQUENCY, get_ticks_per_sec()); ! 83: return d & 0xffffff; ! 84: } ! 85: ! 86: static int get_pmsts(PIIX4PMState *s) ! 87: { ! 88: int64_t d; ! 89: ! 90: d = muldiv64(qemu_get_clock(vm_clock), PM_TIMER_FREQUENCY, ! 91: get_ticks_per_sec()); ! 92: if (d >= s->tmr_overflow_time) ! 93: s->pmsts |= ACPI_BITMASK_TIMER_STATUS; ! 94: return s->pmsts; ! 95: } ! 96: ! 97: static void pm_update_sci(PIIX4PMState *s) ! 98: { ! 99: int sci_level, pmsts; ! 100: int64_t expire_time; ! 101: ! 102: pmsts = get_pmsts(s); ! 103: sci_level = (((pmsts & s->pmen) & ! 104: (ACPI_BITMASK_RT_CLOCK_ENABLE | ! 105: ACPI_BITMASK_POWER_BUTTON_ENABLE | ! 106: ACPI_BITMASK_GLOBAL_LOCK_ENABLE | ! 107: ACPI_BITMASK_TIMER_ENABLE)) != 0); ! 108: qemu_set_irq(s->irq, sci_level); ! 109: /* schedule a timer interruption if needed */ ! 110: if ((s->pmen & ACPI_BITMASK_TIMER_ENABLE) && ! 111: !(pmsts & ACPI_BITMASK_TIMER_STATUS)) { ! 112: expire_time = muldiv64(s->tmr_overflow_time, get_ticks_per_sec(), ! 113: PM_TIMER_FREQUENCY); ! 114: qemu_mod_timer(s->tmr_timer, expire_time); ! 115: } else { ! 116: qemu_del_timer(s->tmr_timer); ! 117: } ! 118: } ! 119: ! 120: static void pm_tmr_timer(void *opaque) ! 121: { ! 122: PIIX4PMState *s = opaque; ! 123: pm_update_sci(s); ! 124: } ! 125: ! 126: static void pm_ioport_writew(void *opaque, uint32_t addr, uint32_t val) ! 127: { ! 128: PIIX4PMState *s = opaque; ! 129: addr &= 0x3f; ! 130: switch(addr) { ! 131: case 0x00: ! 132: { ! 133: int64_t d; ! 134: int pmsts; ! 135: pmsts = get_pmsts(s); ! 136: if (pmsts & val & ACPI_BITMASK_TIMER_STATUS) { ! 137: /* if TMRSTS is reset, then compute the new overflow time */ ! 138: d = muldiv64(qemu_get_clock(vm_clock), PM_TIMER_FREQUENCY, ! 139: get_ticks_per_sec()); ! 140: s->tmr_overflow_time = (d + 0x800000LL) & ~0x7fffffLL; ! 141: } ! 142: s->pmsts &= ~val; ! 143: pm_update_sci(s); ! 144: } ! 145: break; ! 146: case 0x02: ! 147: s->pmen = val; ! 148: pm_update_sci(s); ! 149: break; ! 150: case 0x04: ! 151: { ! 152: int sus_typ; ! 153: s->pmcntrl = val & ~(ACPI_BITMASK_SLEEP_ENABLE); ! 154: if (val & ACPI_BITMASK_SLEEP_ENABLE) { ! 155: /* change suspend type */ ! 156: sus_typ = (val >> 10) & 7; ! 157: switch(sus_typ) { ! 158: case 0: /* soft power off */ ! 159: qemu_system_shutdown_request(); ! 160: break; ! 161: case 1: ! 162: /* ACPI_BITMASK_WAKE_STATUS should be set on resume. ! 163: Pretend that resume was caused by power button */ ! 164: s->pmsts |= (ACPI_BITMASK_WAKE_STATUS | ! 165: ACPI_BITMASK_POWER_BUTTON_STATUS); ! 166: qemu_system_reset_request(); ! 167: if (s->cmos_s3) { ! 168: qemu_irq_raise(s->cmos_s3); ! 169: } ! 170: default: ! 171: break; ! 172: } ! 173: } ! 174: } ! 175: break; ! 176: default: ! 177: break; ! 178: } ! 179: PIIX4_DPRINTF("PM writew port=0x%04x val=0x%04x\n", addr, val); ! 180: } ! 181: ! 182: static uint32_t pm_ioport_readw(void *opaque, uint32_t addr) ! 183: { ! 184: PIIX4PMState *s = opaque; ! 185: uint32_t val; ! 186: ! 187: addr &= 0x3f; ! 188: switch(addr) { ! 189: case 0x00: ! 190: val = get_pmsts(s); ! 191: break; ! 192: case 0x02: ! 193: val = s->pmen; ! 194: break; ! 195: case 0x04: ! 196: val = s->pmcntrl; ! 197: break; ! 198: default: ! 199: val = 0; ! 200: break; ! 201: } ! 202: PIIX4_DPRINTF("PM readw port=0x%04x val=0x%04x\n", addr, val); ! 203: return val; ! 204: } ! 205: ! 206: static void pm_ioport_writel(void *opaque, uint32_t addr, uint32_t val) ! 207: { ! 208: // PIIX4PMState *s = opaque; ! 209: PIIX4_DPRINTF("PM writel port=0x%04x val=0x%08x\n", addr & 0x3f, val); ! 210: } ! 211: ! 212: static uint32_t pm_ioport_readl(void *opaque, uint32_t addr) ! 213: { ! 214: PIIX4PMState *s = opaque; ! 215: uint32_t val; ! 216: ! 217: addr &= 0x3f; ! 218: switch(addr) { ! 219: case 0x08: ! 220: val = get_pmtmr(s); ! 221: break; ! 222: default: ! 223: val = 0; ! 224: break; ! 225: } ! 226: PIIX4_DPRINTF("PM readl port=0x%04x val=0x%08x\n", addr, val); ! 227: return val; ! 228: } ! 229: ! 230: static void apm_ctrl_changed(uint32_t val, void *arg) ! 231: { ! 232: PIIX4PMState *s = arg; ! 233: ! 234: /* ACPI specs 3.0, 4.7.2.5 */ ! 235: if (val == ACPI_ENABLE) { ! 236: s->pmcntrl |= ACPI_BITMASK_SCI_ENABLE; ! 237: } else if (val == ACPI_DISABLE) { ! 238: s->pmcntrl &= ~ACPI_BITMASK_SCI_ENABLE; ! 239: } ! 240: ! 241: if (s->dev.config[0x5b] & (1 << 1)) { ! 242: if (s->smi_irq) { ! 243: qemu_irq_raise(s->smi_irq); ! 244: } ! 245: } ! 246: } ! 247: ! 248: static void acpi_dbg_writel(void *opaque, uint32_t addr, uint32_t val) ! 249: { ! 250: PIIX4_DPRINTF("ACPI: DBG: 0x%08x\n", val); ! 251: } ! 252: ! 253: static void pm_io_space_update(PIIX4PMState *s) ! 254: { ! 255: uint32_t pm_io_base; ! 256: ! 257: if (s->dev.config[0x80] & 1) { ! 258: pm_io_base = le32_to_cpu(*(uint32_t *)(s->dev.config + 0x40)); ! 259: pm_io_base &= 0xffc0; ! 260: ! 261: /* XXX: need to improve memory and ioport allocation */ ! 262: PIIX4_DPRINTF("PM: mapping to 0x%x\n", pm_io_base); ! 263: register_ioport_write(pm_io_base, 64, 2, pm_ioport_writew, s); ! 264: register_ioport_read(pm_io_base, 64, 2, pm_ioport_readw, s); ! 265: register_ioport_write(pm_io_base, 64, 4, pm_ioport_writel, s); ! 266: register_ioport_read(pm_io_base, 64, 4, pm_ioport_readl, s); ! 267: } ! 268: } ! 269: ! 270: static void pm_write_config(PCIDevice *d, ! 271: uint32_t address, uint32_t val, int len) ! 272: { ! 273: pci_default_write_config(d, address, val, len); ! 274: if (range_covers_byte(address, len, 0x80)) ! 275: pm_io_space_update((PIIX4PMState *)d); ! 276: } ! 277: ! 278: static int vmstate_acpi_post_load(void *opaque, int version_id) ! 279: { ! 280: PIIX4PMState *s = opaque; ! 281: ! 282: pm_io_space_update(s); ! 283: return 0; ! 284: } ! 285: ! 286: static const VMStateDescription vmstate_gpe = { ! 287: .name = "gpe", ! 288: .version_id = 1, ! 289: .minimum_version_id = 1, ! 290: .minimum_version_id_old = 1, ! 291: .fields = (VMStateField []) { ! 292: VMSTATE_UINT16(sts, struct gpe_regs), ! 293: VMSTATE_UINT16(en, struct gpe_regs), ! 294: VMSTATE_END_OF_LIST() ! 295: } ! 296: }; ! 297: ! 298: static const VMStateDescription vmstate_pci_status = { ! 299: .name = "pci_status", ! 300: .version_id = 1, ! 301: .minimum_version_id = 1, ! 302: .minimum_version_id_old = 1, ! 303: .fields = (VMStateField []) { ! 304: VMSTATE_UINT32(up, struct pci_status), ! 305: VMSTATE_UINT32(down, struct pci_status), ! 306: VMSTATE_END_OF_LIST() ! 307: } ! 308: }; ! 309: ! 310: static const VMStateDescription vmstate_acpi = { ! 311: .name = "piix4_pm", ! 312: .version_id = 2, ! 313: .minimum_version_id = 1, ! 314: .minimum_version_id_old = 1, ! 315: .post_load = vmstate_acpi_post_load, ! 316: .fields = (VMStateField []) { ! 317: VMSTATE_PCI_DEVICE(dev, PIIX4PMState), ! 318: VMSTATE_UINT16(pmsts, PIIX4PMState), ! 319: VMSTATE_UINT16(pmen, PIIX4PMState), ! 320: VMSTATE_UINT16(pmcntrl, PIIX4PMState), ! 321: VMSTATE_STRUCT(apm, PIIX4PMState, 0, vmstate_apm, APMState), ! 322: VMSTATE_TIMER(tmr_timer, PIIX4PMState), ! 323: VMSTATE_INT64(tmr_overflow_time, PIIX4PMState), ! 324: VMSTATE_STRUCT(gpe, PIIX4PMState, 2, vmstate_gpe, struct gpe_regs), ! 325: VMSTATE_STRUCT(pci0_status, PIIX4PMState, 2, vmstate_pci_status, ! 326: struct pci_status), ! 327: VMSTATE_END_OF_LIST() ! 328: } ! 329: }; ! 330: ! 331: static void piix4_reset(void *opaque) ! 332: { ! 333: PIIX4PMState *s = opaque; ! 334: uint8_t *pci_conf = s->dev.config; ! 335: ! 336: pci_conf[0x58] = 0; ! 337: pci_conf[0x59] = 0; ! 338: pci_conf[0x5a] = 0; ! 339: pci_conf[0x5b] = 0; ! 340: ! 341: if (s->kvm_enabled) { ! 342: /* Mark SMM as already inited (until KVM supports SMM). */ ! 343: pci_conf[0x5B] = 0x02; ! 344: } ! 345: } ! 346: ! 347: static void piix4_powerdown(void *opaque, int irq, int power_failing) ! 348: { ! 349: PIIX4PMState *s = opaque; ! 350: ! 351: if (!s) { ! 352: qemu_system_shutdown_request(); ! 353: } else if (s->pmen & ACPI_BITMASK_POWER_BUTTON_ENABLE) { ! 354: s->pmsts |= ACPI_BITMASK_POWER_BUTTON_STATUS; ! 355: pm_update_sci(s); ! 356: } ! 357: } ! 358: ! 359: static int piix4_pm_initfn(PCIDevice *dev) ! 360: { ! 361: PIIX4PMState *s = DO_UPCAST(PIIX4PMState, dev, dev); ! 362: uint8_t *pci_conf; ! 363: ! 364: pci_conf = s->dev.config; ! 365: pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL); ! 366: pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82371AB_3); ! 367: pci_conf[0x06] = 0x80; ! 368: pci_conf[0x07] = 0x02; ! 369: pci_conf[0x08] = 0x03; // revision number ! 370: pci_conf[0x09] = 0x00; ! 371: pci_config_set_class(pci_conf, PCI_CLASS_BRIDGE_OTHER); ! 372: pci_conf[0x3d] = 0x01; // interrupt pin 1 ! 373: ! 374: pci_conf[0x40] = 0x01; /* PM io base read only bit */ ! 375: ! 376: /* APM */ ! 377: apm_init(&s->apm, apm_ctrl_changed, s); ! 378: ! 379: register_ioport_write(ACPI_DBG_IO_ADDR, 4, 4, acpi_dbg_writel, s); ! 380: ! 381: if (s->kvm_enabled) { ! 382: /* Mark SMM as already inited to prevent SMM from running. KVM does not ! 383: * support SMM mode. */ ! 384: pci_conf[0x5B] = 0x02; ! 385: } ! 386: ! 387: /* XXX: which specification is used ? The i82731AB has different ! 388: mappings */ ! 389: pci_conf[0x5f] = (parallel_hds[0] != NULL ? 0x80 : 0) | 0x10; ! 390: pci_conf[0x63] = 0x60; ! 391: pci_conf[0x67] = (serial_hds[0] != NULL ? 0x08 : 0) | ! 392: (serial_hds[1] != NULL ? 0x90 : 0); ! 393: ! 394: pci_conf[0x90] = s->smb_io_base | 1; ! 395: pci_conf[0x91] = s->smb_io_base >> 8; ! 396: pci_conf[0xd2] = 0x09; ! 397: register_ioport_write(s->smb_io_base, 64, 1, smb_ioport_writeb, &s->smb); ! 398: register_ioport_read(s->smb_io_base, 64, 1, smb_ioport_readb, &s->smb); ! 399: ! 400: s->tmr_timer = qemu_new_timer(vm_clock, pm_tmr_timer, s); ! 401: ! 402: qemu_system_powerdown = *qemu_allocate_irqs(piix4_powerdown, s, 1); ! 403: ! 404: pm_smbus_init(&s->dev.qdev, &s->smb); ! 405: qemu_register_reset(piix4_reset, s); ! 406: piix4_acpi_system_hot_add_init(dev->bus, s); ! 407: ! 408: return 0; ! 409: } ! 410: ! 411: i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base, ! 412: qemu_irq sci_irq, qemu_irq cmos_s3, qemu_irq smi_irq, ! 413: int kvm_enabled) ! 414: { ! 415: PCIDevice *dev; ! 416: PIIX4PMState *s; ! 417: ! 418: dev = pci_create(bus, devfn, "PIIX4_PM"); ! 419: qdev_prop_set_uint32(&dev->qdev, "smb_io_base", smb_io_base); ! 420: ! 421: s = DO_UPCAST(PIIX4PMState, dev, dev); ! 422: s->irq = sci_irq; ! 423: s->cmos_s3 = cmos_s3; ! 424: s->smi_irq = smi_irq; ! 425: s->kvm_enabled = kvm_enabled; ! 426: ! 427: qdev_init_nofail(&dev->qdev); ! 428: ! 429: return s->smb.smbus; ! 430: } ! 431: ! 432: static PCIDeviceInfo piix4_pm_info = { ! 433: .qdev.name = "PIIX4_PM", ! 434: .qdev.desc = "PM", ! 435: .qdev.size = sizeof(PIIX4PMState), ! 436: .qdev.vmsd = &vmstate_acpi, ! 437: .init = piix4_pm_initfn, ! 438: .config_write = pm_write_config, ! 439: .qdev.props = (Property[]) { ! 440: DEFINE_PROP_UINT32("smb_io_base", PIIX4PMState, smb_io_base, 0), ! 441: DEFINE_PROP_END_OF_LIST(), ! 442: } ! 443: }; ! 444: ! 445: static void piix4_pm_register(void) ! 446: { ! 447: pci_qdev_register(&piix4_pm_info); ! 448: } ! 449: ! 450: device_init(piix4_pm_register); ! 451: ! 452: static uint32_t gpe_read_val(uint16_t val, uint32_t addr) ! 453: { ! 454: if (addr & 1) ! 455: return (val >> 8) & 0xff; ! 456: return val & 0xff; ! 457: } ! 458: ! 459: static uint32_t gpe_readb(void *opaque, uint32_t addr) ! 460: { ! 461: uint32_t val = 0; ! 462: struct gpe_regs *g = opaque; ! 463: switch (addr) { ! 464: case GPE_BASE: ! 465: case GPE_BASE + 1: ! 466: val = gpe_read_val(g->sts, addr); ! 467: break; ! 468: case GPE_BASE + 2: ! 469: case GPE_BASE + 3: ! 470: val = gpe_read_val(g->en, addr); ! 471: break; ! 472: default: ! 473: break; ! 474: } ! 475: ! 476: PIIX4_DPRINTF("gpe read %x == %x\n", addr, val); ! 477: return val; ! 478: } ! 479: ! 480: static void gpe_write_val(uint16_t *cur, int addr, uint32_t val) ! 481: { ! 482: if (addr & 1) ! 483: *cur = (*cur & 0xff) | (val << 8); ! 484: else ! 485: *cur = (*cur & 0xff00) | (val & 0xff); ! 486: } ! 487: ! 488: static void gpe_reset_val(uint16_t *cur, int addr, uint32_t val) ! 489: { ! 490: uint16_t x1, x0 = val & 0xff; ! 491: int shift = (addr & 1) ? 8 : 0; ! 492: ! 493: x1 = (*cur >> shift) & 0xff; ! 494: ! 495: x1 = x1 & ~x0; ! 496: ! 497: *cur = (*cur & (0xff << (8 - shift))) | (x1 << shift); ! 498: } ! 499: ! 500: static void gpe_writeb(void *opaque, uint32_t addr, uint32_t val) ! 501: { ! 502: struct gpe_regs *g = opaque; ! 503: switch (addr) { ! 504: case GPE_BASE: ! 505: case GPE_BASE + 1: ! 506: gpe_reset_val(&g->sts, addr, val); ! 507: break; ! 508: case GPE_BASE + 2: ! 509: case GPE_BASE + 3: ! 510: gpe_write_val(&g->en, addr, val); ! 511: break; ! 512: default: ! 513: break; ! 514: } ! 515: ! 516: PIIX4_DPRINTF("gpe write %x <== %d\n", addr, val); ! 517: } ! 518: ! 519: static uint32_t pcihotplug_read(void *opaque, uint32_t addr) ! 520: { ! 521: uint32_t val = 0; ! 522: struct pci_status *g = opaque; ! 523: switch (addr) { ! 524: case PCI_BASE: ! 525: val = g->up; ! 526: break; ! 527: case PCI_BASE + 4: ! 528: val = g->down; ! 529: break; ! 530: default: ! 531: break; ! 532: } ! 533: ! 534: PIIX4_DPRINTF("pcihotplug read %x == %x\n", addr, val); ! 535: return val; ! 536: } ! 537: ! 538: static void pcihotplug_write(void *opaque, uint32_t addr, uint32_t val) ! 539: { ! 540: struct pci_status *g = opaque; ! 541: switch (addr) { ! 542: case PCI_BASE: ! 543: g->up = val; ! 544: break; ! 545: case PCI_BASE + 4: ! 546: g->down = val; ! 547: break; ! 548: } ! 549: ! 550: PIIX4_DPRINTF("pcihotplug write %x <== %d\n", addr, val); ! 551: } ! 552: ! 553: static uint32_t pciej_read(void *opaque, uint32_t addr) ! 554: { ! 555: PIIX4_DPRINTF("pciej read %x\n", addr); ! 556: return 0; ! 557: } ! 558: ! 559: static void pciej_write(void *opaque, uint32_t addr, uint32_t val) ! 560: { ! 561: BusState *bus = opaque; ! 562: DeviceState *qdev, *next; ! 563: PCIDevice *dev; ! 564: int slot = ffs(val) - 1; ! 565: ! 566: QLIST_FOREACH_SAFE(qdev, &bus->children, sibling, next) { ! 567: dev = DO_UPCAST(PCIDevice, qdev, qdev); ! 568: if (PCI_SLOT(dev->devfn) == slot) { ! 569: qdev_free(qdev); ! 570: } ! 571: } ! 572: ! 573: ! 574: PIIX4_DPRINTF("pciej write %x <== %d\n", addr, val); ! 575: } ! 576: ! 577: static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev, int state); ! 578: ! 579: static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s) ! 580: { ! 581: struct gpe_regs *gpe = &s->gpe; ! 582: struct pci_status *pci0_status = &s->pci0_status; ! 583: ! 584: register_ioport_write(GPE_BASE, 4, 1, gpe_writeb, gpe); ! 585: register_ioport_read(GPE_BASE, 4, 1, gpe_readb, gpe); ! 586: ! 587: register_ioport_write(PCI_BASE, 8, 4, pcihotplug_write, pci0_status); ! 588: register_ioport_read(PCI_BASE, 8, 4, pcihotplug_read, pci0_status); ! 589: ! 590: register_ioport_write(PCI_EJ_BASE, 4, 4, pciej_write, bus); ! 591: register_ioport_read(PCI_EJ_BASE, 4, 4, pciej_read, bus); ! 592: ! 593: pci_bus_hotplug(bus, piix4_device_hotplug, &s->dev.qdev); ! 594: } ! 595: ! 596: static void enable_device(PIIX4PMState *s, int slot) ! 597: { ! 598: s->gpe.sts |= 2; ! 599: s->pci0_status.up |= (1 << slot); ! 600: } ! 601: ! 602: static void disable_device(PIIX4PMState *s, int slot) ! 603: { ! 604: s->gpe.sts |= 2; ! 605: s->pci0_status.down |= (1 << slot); ! 606: } ! 607: ! 608: static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev, int state) ! 609: { ! 610: int slot = PCI_SLOT(dev->devfn); ! 611: PIIX4PMState *s = DO_UPCAST(PIIX4PMState, dev, ! 612: DO_UPCAST(PCIDevice, qdev, qdev)); ! 613: ! 614: s->pci0_status.up = 0; ! 615: s->pci0_status.down = 0; ! 616: if (state) { ! 617: enable_device(s, slot); ! 618: } else { ! 619: disable_device(s, slot); ! 620: } ! 621: if (s->gpe.en & 2) { ! 622: qemu_set_irq(s->irq, 1); ! 623: qemu_set_irq(s->irq, 0); ! 624: } ! 625: return 0; ! 626: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.