Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 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" |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 23 | #include "acpi.h" |
Markus Armbruster | 666daa6 | 2010-06-02 18:48:27 +0200 | [diff] [blame] | 24 | #include "sysemu.h" |
Blue Swirl | bf1b007 | 2010-09-18 05:53:14 +0000 | [diff] [blame] | 25 | #include "range.h" |
Paolo Bonzini | 6141dbf | 2011-07-15 17:10:15 +0200 | [diff] [blame] | 26 | #include "ioport.h" |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 27 | |
| 28 | //#define DEBUG |
| 29 | |
Isaku Yamahata | 50d8ff8 | 2010-05-14 16:29:22 +0900 | [diff] [blame] | 30 | #ifdef DEBUG |
| 31 | # define PIIX4_DPRINTF(format, ...) printf(format, ## __VA_ARGS__) |
| 32 | #else |
| 33 | # define PIIX4_DPRINTF(format, ...) do { } while (0) |
| 34 | #endif |
| 35 | |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 36 | #define ACPI_DBG_IO_ADDR 0xb044 |
| 37 | |
Isaku Yamahata | ac40409 | 2010-05-14 16:29:20 +0900 | [diff] [blame] | 38 | #define GPE_BASE 0xafe0 |
Isaku Yamahata | 23910d3 | 2011-03-25 19:54:41 +0900 | [diff] [blame] | 39 | #define GPE_LEN 4 |
Isaku Yamahata | ac40409 | 2010-05-14 16:29:20 +0900 | [diff] [blame] | 40 | #define PCI_BASE 0xae00 |
| 41 | #define PCI_EJ_BASE 0xae08 |
Marcelo Tosatti | 668643b | 2011-01-11 14:20:39 -0200 | [diff] [blame] | 42 | #define PCI_RMV_BASE 0xae0c |
Isaku Yamahata | ac40409 | 2010-05-14 16:29:20 +0900 | [diff] [blame] | 43 | |
Gleb Natapov | 4441a28 | 2010-10-17 11:45:24 +0200 | [diff] [blame] | 44 | #define PIIX4_PCI_HOTPLUG_STATUS 2 |
| 45 | |
Isaku Yamahata | ac40409 | 2010-05-14 16:29:20 +0900 | [diff] [blame] | 46 | struct pci_status { |
| 47 | uint32_t up; |
| 48 | uint32_t down; |
| 49 | }; |
| 50 | |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 51 | typedef struct PIIX4PMState { |
| 52 | PCIDevice dev; |
Avi Kivity | 2871a3f | 2010-11-17 11:50:10 +0200 | [diff] [blame] | 53 | IORange ioport; |
Isaku Yamahata | 04dc308 | 2011-03-25 19:54:39 +0900 | [diff] [blame] | 54 | ACPIPM1EVT pm1a; |
Isaku Yamahata | eaba51c | 2011-03-25 19:54:40 +0900 | [diff] [blame] | 55 | ACPIPM1CNT pm1_cnt; |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 56 | |
| 57 | APMState apm; |
| 58 | |
Isaku Yamahata | a54d41a | 2011-03-25 19:54:38 +0900 | [diff] [blame] | 59 | ACPIPMTimer tmr; |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 60 | |
| 61 | PMSMBus smb; |
Isaku Yamahata | e8ec057 | 2010-05-14 16:29:18 +0900 | [diff] [blame] | 62 | uint32_t smb_io_base; |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 63 | |
| 64 | qemu_irq irq; |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 65 | qemu_irq smi_irq; |
| 66 | int kvm_enabled; |
Paolo Bonzini | 6141dbf | 2011-07-15 17:10:15 +0200 | [diff] [blame] | 67 | Notifier machine_ready; |
Isaku Yamahata | ac40409 | 2010-05-14 16:29:20 +0900 | [diff] [blame] | 68 | |
| 69 | /* for pci hotplug */ |
Isaku Yamahata | 23910d3 | 2011-03-25 19:54:41 +0900 | [diff] [blame] | 70 | ACPIGPE gpe; |
Isaku Yamahata | ac40409 | 2010-05-14 16:29:20 +0900 | [diff] [blame] | 71 | struct pci_status pci0_status; |
Marcelo Tosatti | 668643b | 2011-01-11 14:20:39 -0200 | [diff] [blame] | 72 | uint32_t pci0_hotplug_enable; |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 73 | } PIIX4PMState; |
| 74 | |
Isaku Yamahata | ac40409 | 2010-05-14 16:29:20 +0900 | [diff] [blame] | 75 | static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s); |
| 76 | |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 77 | #define ACPI_ENABLE 0xf1 |
| 78 | #define ACPI_DISABLE 0xf0 |
| 79 | |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 80 | static void pm_update_sci(PIIX4PMState *s) |
| 81 | { |
| 82 | int sci_level, pmsts; |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 83 | |
Isaku Yamahata | 04dc308 | 2011-03-25 19:54:39 +0900 | [diff] [blame] | 84 | pmsts = acpi_pm1_evt_get_sts(&s->pm1a, s->tmr.overflow_time); |
| 85 | sci_level = (((pmsts & s->pm1a.en) & |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 86 | (ACPI_BITMASK_RT_CLOCK_ENABLE | |
| 87 | ACPI_BITMASK_POWER_BUTTON_ENABLE | |
| 88 | ACPI_BITMASK_GLOBAL_LOCK_ENABLE | |
Gleb Natapov | 633aa0a | 2010-10-17 11:45:25 +0200 | [diff] [blame] | 89 | ACPI_BITMASK_TIMER_ENABLE)) != 0) || |
Isaku Yamahata | 23910d3 | 2011-03-25 19:54:41 +0900 | [diff] [blame] | 90 | (((s->gpe.sts[0] & s->gpe.en[0]) & PIIX4_PCI_HOTPLUG_STATUS) != 0); |
Gleb Natapov | 633aa0a | 2010-10-17 11:45:25 +0200 | [diff] [blame] | 91 | |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 92 | qemu_set_irq(s->irq, sci_level); |
| 93 | /* schedule a timer interruption if needed */ |
Isaku Yamahata | 04dc308 | 2011-03-25 19:54:39 +0900 | [diff] [blame] | 94 | acpi_pm_tmr_update(&s->tmr, (s->pm1a.en & ACPI_BITMASK_TIMER_ENABLE) && |
Isaku Yamahata | a54d41a | 2011-03-25 19:54:38 +0900 | [diff] [blame] | 95 | !(pmsts & ACPI_BITMASK_TIMER_STATUS)); |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 96 | } |
| 97 | |
Isaku Yamahata | a54d41a | 2011-03-25 19:54:38 +0900 | [diff] [blame] | 98 | static void pm_tmr_timer(ACPIPMTimer *tmr) |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 99 | { |
Isaku Yamahata | a54d41a | 2011-03-25 19:54:38 +0900 | [diff] [blame] | 100 | PIIX4PMState *s = container_of(tmr, PIIX4PMState, tmr); |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 101 | pm_update_sci(s); |
| 102 | } |
| 103 | |
Avi Kivity | 2871a3f | 2010-11-17 11:50:10 +0200 | [diff] [blame] | 104 | static void pm_ioport_write(IORange *ioport, uint64_t addr, unsigned width, |
| 105 | uint64_t val) |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 106 | { |
Avi Kivity | 2871a3f | 2010-11-17 11:50:10 +0200 | [diff] [blame] | 107 | PIIX4PMState *s = container_of(ioport, PIIX4PMState, ioport); |
| 108 | |
| 109 | if (width != 2) { |
| 110 | PIIX4_DPRINTF("PM write port=0x%04x width=%d val=0x%08x\n", |
| 111 | (unsigned)addr, width, (unsigned)val); |
| 112 | } |
| 113 | |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 114 | switch(addr) { |
| 115 | case 0x00: |
Isaku Yamahata | 04dc308 | 2011-03-25 19:54:39 +0900 | [diff] [blame] | 116 | acpi_pm1_evt_write_sts(&s->pm1a, &s->tmr, val); |
| 117 | pm_update_sci(s); |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 118 | break; |
| 119 | case 0x02: |
Isaku Yamahata | 04dc308 | 2011-03-25 19:54:39 +0900 | [diff] [blame] | 120 | s->pm1a.en = val; |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 121 | pm_update_sci(s); |
| 122 | break; |
| 123 | case 0x04: |
Isaku Yamahata | eaba51c | 2011-03-25 19:54:40 +0900 | [diff] [blame] | 124 | acpi_pm1_cnt_write(&s->pm1a, &s->pm1_cnt, val); |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 125 | break; |
| 126 | default: |
| 127 | break; |
| 128 | } |
Wen Congyang | 59df4c1 | 2011-02-28 10:22:33 +0800 | [diff] [blame] | 129 | PIIX4_DPRINTF("PM writew port=0x%04x val=0x%04x\n", (unsigned int)addr, |
| 130 | (unsigned int)val); |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 131 | } |
| 132 | |
Avi Kivity | 2871a3f | 2010-11-17 11:50:10 +0200 | [diff] [blame] | 133 | static void pm_ioport_read(IORange *ioport, uint64_t addr, unsigned width, |
| 134 | uint64_t *data) |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 135 | { |
Avi Kivity | 2871a3f | 2010-11-17 11:50:10 +0200 | [diff] [blame] | 136 | PIIX4PMState *s = container_of(ioport, PIIX4PMState, ioport); |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 137 | uint32_t val; |
| 138 | |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 139 | switch(addr) { |
| 140 | case 0x00: |
Isaku Yamahata | 04dc308 | 2011-03-25 19:54:39 +0900 | [diff] [blame] | 141 | val = acpi_pm1_evt_get_sts(&s->pm1a, s->tmr.overflow_time); |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 142 | break; |
| 143 | case 0x02: |
Isaku Yamahata | 04dc308 | 2011-03-25 19:54:39 +0900 | [diff] [blame] | 144 | val = s->pm1a.en; |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 145 | break; |
| 146 | case 0x04: |
Isaku Yamahata | eaba51c | 2011-03-25 19:54:40 +0900 | [diff] [blame] | 147 | val = s->pm1_cnt.cnt; |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 148 | break; |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 149 | case 0x08: |
Isaku Yamahata | a54d41a | 2011-03-25 19:54:38 +0900 | [diff] [blame] | 150 | val = acpi_pm_tmr_get(&s->tmr); |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 151 | break; |
| 152 | default: |
| 153 | val = 0; |
| 154 | break; |
| 155 | } |
Wen Congyang | 59df4c1 | 2011-02-28 10:22:33 +0800 | [diff] [blame] | 156 | PIIX4_DPRINTF("PM readw port=0x%04x val=0x%04x\n", (unsigned int)addr, val); |
Avi Kivity | 2871a3f | 2010-11-17 11:50:10 +0200 | [diff] [blame] | 157 | *data = val; |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 158 | } |
| 159 | |
Avi Kivity | 2871a3f | 2010-11-17 11:50:10 +0200 | [diff] [blame] | 160 | static const IORangeOps pm_iorange_ops = { |
| 161 | .read = pm_ioport_read, |
| 162 | .write = pm_ioport_write, |
| 163 | }; |
| 164 | |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 165 | static void apm_ctrl_changed(uint32_t val, void *arg) |
| 166 | { |
| 167 | PIIX4PMState *s = arg; |
| 168 | |
| 169 | /* ACPI specs 3.0, 4.7.2.5 */ |
Isaku Yamahata | eaba51c | 2011-03-25 19:54:40 +0900 | [diff] [blame] | 170 | acpi_pm1_cnt_update(&s->pm1_cnt, val == ACPI_ENABLE, val == ACPI_DISABLE); |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 171 | |
| 172 | if (s->dev.config[0x5b] & (1 << 1)) { |
| 173 | if (s->smi_irq) { |
| 174 | qemu_irq_raise(s->smi_irq); |
| 175 | } |
| 176 | } |
| 177 | } |
| 178 | |
| 179 | static void acpi_dbg_writel(void *opaque, uint32_t addr, uint32_t val) |
| 180 | { |
Isaku Yamahata | 50d8ff8 | 2010-05-14 16:29:22 +0900 | [diff] [blame] | 181 | PIIX4_DPRINTF("ACPI: DBG: 0x%08x\n", val); |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 182 | } |
| 183 | |
| 184 | static void pm_io_space_update(PIIX4PMState *s) |
| 185 | { |
| 186 | uint32_t pm_io_base; |
| 187 | |
| 188 | if (s->dev.config[0x80] & 1) { |
| 189 | pm_io_base = le32_to_cpu(*(uint32_t *)(s->dev.config + 0x40)); |
| 190 | pm_io_base &= 0xffc0; |
| 191 | |
| 192 | /* XXX: need to improve memory and ioport allocation */ |
Isaku Yamahata | 50d8ff8 | 2010-05-14 16:29:22 +0900 | [diff] [blame] | 193 | PIIX4_DPRINTF("PM: mapping to 0x%x\n", pm_io_base); |
Avi Kivity | 2871a3f | 2010-11-17 11:50:10 +0200 | [diff] [blame] | 194 | iorange_init(&s->ioport, &pm_iorange_ops, pm_io_base, 64); |
| 195 | ioport_register(&s->ioport); |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 196 | } |
| 197 | } |
| 198 | |
| 199 | static void pm_write_config(PCIDevice *d, |
| 200 | uint32_t address, uint32_t val, int len) |
| 201 | { |
| 202 | pci_default_write_config(d, address, val, len); |
| 203 | if (range_covers_byte(address, len, 0x80)) |
| 204 | pm_io_space_update((PIIX4PMState *)d); |
| 205 | } |
| 206 | |
| 207 | static int vmstate_acpi_post_load(void *opaque, int version_id) |
| 208 | { |
| 209 | PIIX4PMState *s = opaque; |
| 210 | |
| 211 | pm_io_space_update(s); |
| 212 | return 0; |
| 213 | } |
| 214 | |
Isaku Yamahata | 23910d3 | 2011-03-25 19:54:41 +0900 | [diff] [blame] | 215 | #define VMSTATE_GPE_ARRAY(_field, _state) \ |
| 216 | { \ |
| 217 | .name = (stringify(_field)), \ |
| 218 | .version_id = 0, \ |
| 219 | .num = GPE_LEN, \ |
| 220 | .info = &vmstate_info_uint16, \ |
| 221 | .size = sizeof(uint16_t), \ |
| 222 | .flags = VMS_ARRAY | VMS_POINTER, \ |
| 223 | .offset = vmstate_offset_pointer(_state, _field, uint8_t), \ |
| 224 | } |
| 225 | |
Alex Williamson | 4cf3e6f | 2010-06-02 10:58:29 -0600 | [diff] [blame] | 226 | static const VMStateDescription vmstate_gpe = { |
| 227 | .name = "gpe", |
| 228 | .version_id = 1, |
| 229 | .minimum_version_id = 1, |
| 230 | .minimum_version_id_old = 1, |
| 231 | .fields = (VMStateField []) { |
Isaku Yamahata | 23910d3 | 2011-03-25 19:54:41 +0900 | [diff] [blame] | 232 | VMSTATE_GPE_ARRAY(sts, ACPIGPE), |
| 233 | VMSTATE_GPE_ARRAY(en, ACPIGPE), |
Alex Williamson | 4cf3e6f | 2010-06-02 10:58:29 -0600 | [diff] [blame] | 234 | VMSTATE_END_OF_LIST() |
| 235 | } |
| 236 | }; |
| 237 | |
| 238 | static const VMStateDescription vmstate_pci_status = { |
| 239 | .name = "pci_status", |
| 240 | .version_id = 1, |
| 241 | .minimum_version_id = 1, |
| 242 | .minimum_version_id_old = 1, |
| 243 | .fields = (VMStateField []) { |
| 244 | VMSTATE_UINT32(up, struct pci_status), |
| 245 | VMSTATE_UINT32(down, struct pci_status), |
| 246 | VMSTATE_END_OF_LIST() |
| 247 | } |
| 248 | }; |
| 249 | |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 250 | static const VMStateDescription vmstate_acpi = { |
| 251 | .name = "piix4_pm", |
Alex Williamson | 4cf3e6f | 2010-06-02 10:58:29 -0600 | [diff] [blame] | 252 | .version_id = 2, |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 253 | .minimum_version_id = 1, |
| 254 | .minimum_version_id_old = 1, |
| 255 | .post_load = vmstate_acpi_post_load, |
| 256 | .fields = (VMStateField []) { |
| 257 | VMSTATE_PCI_DEVICE(dev, PIIX4PMState), |
Isaku Yamahata | 04dc308 | 2011-03-25 19:54:39 +0900 | [diff] [blame] | 258 | VMSTATE_UINT16(pm1a.sts, PIIX4PMState), |
| 259 | VMSTATE_UINT16(pm1a.en, PIIX4PMState), |
Isaku Yamahata | eaba51c | 2011-03-25 19:54:40 +0900 | [diff] [blame] | 260 | VMSTATE_UINT16(pm1_cnt.cnt, PIIX4PMState), |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 261 | VMSTATE_STRUCT(apm, PIIX4PMState, 0, vmstate_apm, APMState), |
Isaku Yamahata | a54d41a | 2011-03-25 19:54:38 +0900 | [diff] [blame] | 262 | VMSTATE_TIMER(tmr.timer, PIIX4PMState), |
| 263 | VMSTATE_INT64(tmr.overflow_time, PIIX4PMState), |
Isaku Yamahata | 23910d3 | 2011-03-25 19:54:41 +0900 | [diff] [blame] | 264 | VMSTATE_STRUCT(gpe, PIIX4PMState, 2, vmstate_gpe, ACPIGPE), |
Alex Williamson | 4cf3e6f | 2010-06-02 10:58:29 -0600 | [diff] [blame] | 265 | VMSTATE_STRUCT(pci0_status, PIIX4PMState, 2, vmstate_pci_status, |
| 266 | struct pci_status), |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 267 | VMSTATE_END_OF_LIST() |
| 268 | } |
| 269 | }; |
| 270 | |
Marcelo Tosatti | 668643b | 2011-01-11 14:20:39 -0200 | [diff] [blame] | 271 | static void piix4_update_hotplug(PIIX4PMState *s) |
| 272 | { |
| 273 | PCIDevice *dev = &s->dev; |
| 274 | BusState *bus = qdev_get_parent_bus(&dev->qdev); |
| 275 | DeviceState *qdev, *next; |
| 276 | |
| 277 | s->pci0_hotplug_enable = ~0; |
| 278 | |
Paolo Bonzini | d8bb00d | 2011-09-14 09:28:06 +0200 | [diff] [blame] | 279 | QTAILQ_FOREACH_SAFE(qdev, &bus->children, sibling, next) { |
Marcelo Tosatti | 668643b | 2011-01-11 14:20:39 -0200 | [diff] [blame] | 280 | PCIDeviceInfo *info = container_of(qdev->info, PCIDeviceInfo, qdev); |
| 281 | PCIDevice *pdev = DO_UPCAST(PCIDevice, qdev, qdev); |
| 282 | int slot = PCI_SLOT(pdev->devfn); |
| 283 | |
| 284 | if (info->no_hotplug) { |
| 285 | s->pci0_hotplug_enable &= ~(1 << slot); |
| 286 | } |
| 287 | } |
| 288 | } |
| 289 | |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 290 | static void piix4_reset(void *opaque) |
| 291 | { |
| 292 | PIIX4PMState *s = opaque; |
| 293 | uint8_t *pci_conf = s->dev.config; |
| 294 | |
| 295 | pci_conf[0x58] = 0; |
| 296 | pci_conf[0x59] = 0; |
| 297 | pci_conf[0x5a] = 0; |
| 298 | pci_conf[0x5b] = 0; |
| 299 | |
| 300 | if (s->kvm_enabled) { |
| 301 | /* Mark SMM as already inited (until KVM supports SMM). */ |
| 302 | pci_conf[0x5B] = 0x02; |
| 303 | } |
Marcelo Tosatti | 668643b | 2011-01-11 14:20:39 -0200 | [diff] [blame] | 304 | piix4_update_hotplug(s); |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 305 | } |
| 306 | |
| 307 | static void piix4_powerdown(void *opaque, int irq, int power_failing) |
| 308 | { |
| 309 | PIIX4PMState *s = opaque; |
Isaku Yamahata | 04dc308 | 2011-03-25 19:54:39 +0900 | [diff] [blame] | 310 | ACPIPM1EVT *pm1a = s? &s->pm1a: NULL; |
| 311 | ACPIPMTimer *tmr = s? &s->tmr: NULL; |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 312 | |
Isaku Yamahata | 04dc308 | 2011-03-25 19:54:39 +0900 | [diff] [blame] | 313 | acpi_pm1_evt_power_down(pm1a, tmr); |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 314 | } |
| 315 | |
Jan Kiszka | 9e8dd45 | 2011-06-20 14:06:26 +0200 | [diff] [blame] | 316 | static void piix4_pm_machine_ready(Notifier *n, void *opaque) |
Paolo Bonzini | 6141dbf | 2011-07-15 17:10:15 +0200 | [diff] [blame] | 317 | { |
| 318 | PIIX4PMState *s = container_of(n, PIIX4PMState, machine_ready); |
| 319 | uint8_t *pci_conf; |
| 320 | |
| 321 | pci_conf = s->dev.config; |
| 322 | pci_conf[0x5f] = (isa_is_ioport_assigned(0x378) ? 0x80 : 0) | 0x10; |
| 323 | pci_conf[0x63] = 0x60; |
| 324 | pci_conf[0x67] = (isa_is_ioport_assigned(0x3f8) ? 0x08 : 0) | |
| 325 | (isa_is_ioport_assigned(0x2f8) ? 0x90 : 0); |
| 326 | |
| 327 | } |
| 328 | |
Isaku Yamahata | e8ec057 | 2010-05-14 16:29:18 +0900 | [diff] [blame] | 329 | static int piix4_pm_initfn(PCIDevice *dev) |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 330 | { |
Isaku Yamahata | e8ec057 | 2010-05-14 16:29:18 +0900 | [diff] [blame] | 331 | PIIX4PMState *s = DO_UPCAST(PIIX4PMState, dev, dev); |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 332 | uint8_t *pci_conf; |
| 333 | |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 334 | pci_conf = s->dev.config; |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 335 | pci_conf[0x06] = 0x80; |
| 336 | pci_conf[0x07] = 0x02; |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 337 | pci_conf[0x09] = 0x00; |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 338 | pci_conf[0x3d] = 0x01; // interrupt pin 1 |
| 339 | |
| 340 | pci_conf[0x40] = 0x01; /* PM io base read only bit */ |
| 341 | |
| 342 | /* APM */ |
| 343 | apm_init(&s->apm, apm_ctrl_changed, s); |
| 344 | |
| 345 | register_ioport_write(ACPI_DBG_IO_ADDR, 4, 4, acpi_dbg_writel, s); |
| 346 | |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 347 | if (s->kvm_enabled) { |
| 348 | /* Mark SMM as already inited to prevent SMM from running. KVM does not |
| 349 | * support SMM mode. */ |
| 350 | pci_conf[0x5B] = 0x02; |
| 351 | } |
| 352 | |
| 353 | /* XXX: which specification is used ? The i82731AB has different |
| 354 | mappings */ |
Isaku Yamahata | e8ec057 | 2010-05-14 16:29:18 +0900 | [diff] [blame] | 355 | pci_conf[0x90] = s->smb_io_base | 1; |
| 356 | pci_conf[0x91] = s->smb_io_base >> 8; |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 357 | pci_conf[0xd2] = 0x09; |
Isaku Yamahata | e8ec057 | 2010-05-14 16:29:18 +0900 | [diff] [blame] | 358 | register_ioport_write(s->smb_io_base, 64, 1, smb_ioport_writeb, &s->smb); |
| 359 | register_ioport_read(s->smb_io_base, 64, 1, smb_ioport_readb, &s->smb); |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 360 | |
Isaku Yamahata | a54d41a | 2011-03-25 19:54:38 +0900 | [diff] [blame] | 361 | acpi_pm_tmr_init(&s->tmr, pm_tmr_timer); |
Isaku Yamahata | 23910d3 | 2011-03-25 19:54:41 +0900 | [diff] [blame] | 362 | acpi_gpe_init(&s->gpe, GPE_LEN); |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 363 | |
| 364 | qemu_system_powerdown = *qemu_allocate_irqs(piix4_powerdown, s, 1); |
| 365 | |
Isaku Yamahata | e8ec057 | 2010-05-14 16:29:18 +0900 | [diff] [blame] | 366 | pm_smbus_init(&s->dev.qdev, &s->smb); |
Paolo Bonzini | 6141dbf | 2011-07-15 17:10:15 +0200 | [diff] [blame] | 367 | s->machine_ready.notify = piix4_pm_machine_ready; |
| 368 | qemu_add_machine_init_done_notifier(&s->machine_ready); |
Isaku Yamahata | e8ec057 | 2010-05-14 16:29:18 +0900 | [diff] [blame] | 369 | qemu_register_reset(piix4_reset, s); |
Isaku Yamahata | ac40409 | 2010-05-14 16:29:20 +0900 | [diff] [blame] | 370 | piix4_acpi_system_hot_add_init(dev->bus, s); |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 371 | |
Isaku Yamahata | e8ec057 | 2010-05-14 16:29:18 +0900 | [diff] [blame] | 372 | return 0; |
| 373 | } |
| 374 | |
| 375 | i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base, |
| 376 | qemu_irq sci_irq, qemu_irq cmos_s3, qemu_irq smi_irq, |
| 377 | int kvm_enabled) |
| 378 | { |
| 379 | PCIDevice *dev; |
| 380 | PIIX4PMState *s; |
| 381 | |
| 382 | dev = pci_create(bus, devfn, "PIIX4_PM"); |
| 383 | qdev_prop_set_uint32(&dev->qdev, "smb_io_base", smb_io_base); |
| 384 | |
| 385 | s = DO_UPCAST(PIIX4PMState, dev, dev); |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 386 | s->irq = sci_irq; |
Isaku Yamahata | eaba51c | 2011-03-25 19:54:40 +0900 | [diff] [blame] | 387 | acpi_pm1_cnt_init(&s->pm1_cnt, cmos_s3); |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 388 | s->smi_irq = smi_irq; |
Isaku Yamahata | e8ec057 | 2010-05-14 16:29:18 +0900 | [diff] [blame] | 389 | s->kvm_enabled = kvm_enabled; |
| 390 | |
| 391 | qdev_init_nofail(&dev->qdev); |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 392 | |
| 393 | return s->smb.smbus; |
| 394 | } |
| 395 | |
Isaku Yamahata | e8ec057 | 2010-05-14 16:29:18 +0900 | [diff] [blame] | 396 | static PCIDeviceInfo piix4_pm_info = { |
| 397 | .qdev.name = "PIIX4_PM", |
| 398 | .qdev.desc = "PM", |
| 399 | .qdev.size = sizeof(PIIX4PMState), |
| 400 | .qdev.vmsd = &vmstate_acpi, |
Gerd Hoffmann | 0965f12 | 2011-01-06 15:14:38 +0100 | [diff] [blame] | 401 | .qdev.no_user = 1, |
| 402 | .no_hotplug = 1, |
Isaku Yamahata | e8ec057 | 2010-05-14 16:29:18 +0900 | [diff] [blame] | 403 | .init = piix4_pm_initfn, |
| 404 | .config_write = pm_write_config, |
Isaku Yamahata | 580b729 | 2011-05-25 10:58:06 +0900 | [diff] [blame] | 405 | .vendor_id = PCI_VENDOR_ID_INTEL, |
| 406 | .device_id = PCI_DEVICE_ID_INTEL_82371AB_3, |
| 407 | .revision = 0x03, |
| 408 | .class_id = PCI_CLASS_BRIDGE_OTHER, |
Isaku Yamahata | e8ec057 | 2010-05-14 16:29:18 +0900 | [diff] [blame] | 409 | .qdev.props = (Property[]) { |
| 410 | DEFINE_PROP_UINT32("smb_io_base", PIIX4PMState, smb_io_base, 0), |
| 411 | DEFINE_PROP_END_OF_LIST(), |
| 412 | } |
| 413 | }; |
| 414 | |
| 415 | static void piix4_pm_register(void) |
| 416 | { |
| 417 | pci_qdev_register(&piix4_pm_info); |
| 418 | } |
| 419 | |
| 420 | device_init(piix4_pm_register); |
| 421 | |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 422 | static uint32_t gpe_readb(void *opaque, uint32_t addr) |
| 423 | { |
Gleb Natapov | 633aa0a | 2010-10-17 11:45:25 +0200 | [diff] [blame] | 424 | PIIX4PMState *s = opaque; |
Isaku Yamahata | 23910d3 | 2011-03-25 19:54:41 +0900 | [diff] [blame] | 425 | uint32_t val = acpi_gpe_ioport_readb(&s->gpe, addr); |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 426 | |
Isaku Yamahata | 50d8ff8 | 2010-05-14 16:29:22 +0900 | [diff] [blame] | 427 | PIIX4_DPRINTF("gpe read %x == %x\n", addr, val); |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 428 | return val; |
| 429 | } |
| 430 | |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 431 | static void gpe_writeb(void *opaque, uint32_t addr, uint32_t val) |
| 432 | { |
Gleb Natapov | 633aa0a | 2010-10-17 11:45:25 +0200 | [diff] [blame] | 433 | PIIX4PMState *s = opaque; |
Gleb Natapov | 633aa0a | 2010-10-17 11:45:25 +0200 | [diff] [blame] | 434 | |
Isaku Yamahata | 23910d3 | 2011-03-25 19:54:41 +0900 | [diff] [blame] | 435 | acpi_gpe_ioport_writeb(&s->gpe, addr, val); |
Gleb Natapov | 633aa0a | 2010-10-17 11:45:25 +0200 | [diff] [blame] | 436 | pm_update_sci(s); |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 437 | |
Isaku Yamahata | 50d8ff8 | 2010-05-14 16:29:22 +0900 | [diff] [blame] | 438 | PIIX4_DPRINTF("gpe write %x <== %d\n", addr, val); |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 439 | } |
| 440 | |
| 441 | static uint32_t pcihotplug_read(void *opaque, uint32_t addr) |
| 442 | { |
| 443 | uint32_t val = 0; |
| 444 | struct pci_status *g = opaque; |
| 445 | switch (addr) { |
| 446 | case PCI_BASE: |
| 447 | val = g->up; |
| 448 | break; |
| 449 | case PCI_BASE + 4: |
| 450 | val = g->down; |
| 451 | break; |
| 452 | default: |
| 453 | break; |
| 454 | } |
| 455 | |
Isaku Yamahata | 50d8ff8 | 2010-05-14 16:29:22 +0900 | [diff] [blame] | 456 | PIIX4_DPRINTF("pcihotplug read %x == %x\n", addr, val); |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 457 | return val; |
| 458 | } |
| 459 | |
| 460 | static void pcihotplug_write(void *opaque, uint32_t addr, uint32_t val) |
| 461 | { |
| 462 | struct pci_status *g = opaque; |
| 463 | switch (addr) { |
| 464 | case PCI_BASE: |
| 465 | g->up = val; |
| 466 | break; |
| 467 | case PCI_BASE + 4: |
| 468 | g->down = val; |
| 469 | break; |
| 470 | } |
| 471 | |
Isaku Yamahata | 50d8ff8 | 2010-05-14 16:29:22 +0900 | [diff] [blame] | 472 | PIIX4_DPRINTF("pcihotplug write %x <== %d\n", addr, val); |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 473 | } |
| 474 | |
| 475 | static uint32_t pciej_read(void *opaque, uint32_t addr) |
| 476 | { |
Isaku Yamahata | 50d8ff8 | 2010-05-14 16:29:22 +0900 | [diff] [blame] | 477 | PIIX4_DPRINTF("pciej read %x\n", addr); |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 478 | return 0; |
| 479 | } |
| 480 | |
| 481 | static void pciej_write(void *opaque, uint32_t addr, uint32_t val) |
| 482 | { |
| 483 | BusState *bus = opaque; |
| 484 | DeviceState *qdev, *next; |
| 485 | PCIDevice *dev; |
Gerd Hoffmann | 505597e | 2011-04-27 11:05:34 +0200 | [diff] [blame] | 486 | PCIDeviceInfo *info; |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 487 | int slot = ffs(val) - 1; |
| 488 | |
Paolo Bonzini | d8bb00d | 2011-09-14 09:28:06 +0200 | [diff] [blame] | 489 | QTAILQ_FOREACH_SAFE(qdev, &bus->children, sibling, next) { |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 490 | dev = DO_UPCAST(PCIDevice, qdev, qdev); |
Gerd Hoffmann | 505597e | 2011-04-27 11:05:34 +0200 | [diff] [blame] | 491 | info = container_of(qdev->info, PCIDeviceInfo, qdev); |
| 492 | if (PCI_SLOT(dev->devfn) == slot && !info->no_hotplug) { |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 493 | qdev_free(qdev); |
| 494 | } |
| 495 | } |
| 496 | |
| 497 | |
Isaku Yamahata | 50d8ff8 | 2010-05-14 16:29:22 +0900 | [diff] [blame] | 498 | PIIX4_DPRINTF("pciej write %x <== %d\n", addr, val); |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 499 | } |
| 500 | |
Marcelo Tosatti | 668643b | 2011-01-11 14:20:39 -0200 | [diff] [blame] | 501 | static uint32_t pcirmv_read(void *opaque, uint32_t addr) |
| 502 | { |
| 503 | PIIX4PMState *s = opaque; |
| 504 | |
| 505 | return s->pci0_hotplug_enable; |
| 506 | } |
| 507 | |
| 508 | static void pcirmv_write(void *opaque, uint32_t addr, uint32_t val) |
| 509 | { |
| 510 | return; |
| 511 | } |
| 512 | |
Michael S. Tsirkin | 4cff0a5 | 2010-11-12 16:21:35 +0900 | [diff] [blame] | 513 | static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev, |
| 514 | PCIHotplugState state); |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 515 | |
Isaku Yamahata | ac40409 | 2010-05-14 16:29:20 +0900 | [diff] [blame] | 516 | static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s) |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 517 | { |
Isaku Yamahata | ac40409 | 2010-05-14 16:29:20 +0900 | [diff] [blame] | 518 | struct pci_status *pci0_status = &s->pci0_status; |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 519 | |
Isaku Yamahata | 23910d3 | 2011-03-25 19:54:41 +0900 | [diff] [blame] | 520 | register_ioport_write(GPE_BASE, GPE_LEN, 1, gpe_writeb, s); |
| 521 | register_ioport_read(GPE_BASE, GPE_LEN, 1, gpe_readb, s); |
| 522 | acpi_gpe_blk(&s->gpe, GPE_BASE); |
Isaku Yamahata | ac40409 | 2010-05-14 16:29:20 +0900 | [diff] [blame] | 523 | |
| 524 | register_ioport_write(PCI_BASE, 8, 4, pcihotplug_write, pci0_status); |
| 525 | register_ioport_read(PCI_BASE, 8, 4, pcihotplug_read, pci0_status); |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 526 | |
| 527 | register_ioport_write(PCI_EJ_BASE, 4, 4, pciej_write, bus); |
| 528 | register_ioport_read(PCI_EJ_BASE, 4, 4, pciej_read, bus); |
| 529 | |
Marcelo Tosatti | 668643b | 2011-01-11 14:20:39 -0200 | [diff] [blame] | 530 | register_ioport_write(PCI_RMV_BASE, 4, 4, pcirmv_write, s); |
| 531 | register_ioport_read(PCI_RMV_BASE, 4, 4, pcirmv_read, s); |
| 532 | |
Isaku Yamahata | ac40409 | 2010-05-14 16:29:20 +0900 | [diff] [blame] | 533 | pci_bus_hotplug(bus, piix4_device_hotplug, &s->dev.qdev); |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 534 | } |
| 535 | |
Isaku Yamahata | ac40409 | 2010-05-14 16:29:20 +0900 | [diff] [blame] | 536 | static void enable_device(PIIX4PMState *s, int slot) |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 537 | { |
Isaku Yamahata | 23910d3 | 2011-03-25 19:54:41 +0900 | [diff] [blame] | 538 | s->gpe.sts[0] |= PIIX4_PCI_HOTPLUG_STATUS; |
Isaku Yamahata | ac40409 | 2010-05-14 16:29:20 +0900 | [diff] [blame] | 539 | s->pci0_status.up |= (1 << slot); |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 540 | } |
| 541 | |
Isaku Yamahata | ac40409 | 2010-05-14 16:29:20 +0900 | [diff] [blame] | 542 | static void disable_device(PIIX4PMState *s, int slot) |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 543 | { |
Isaku Yamahata | 23910d3 | 2011-03-25 19:54:41 +0900 | [diff] [blame] | 544 | s->gpe.sts[0] |= PIIX4_PCI_HOTPLUG_STATUS; |
Isaku Yamahata | ac40409 | 2010-05-14 16:29:20 +0900 | [diff] [blame] | 545 | s->pci0_status.down |= (1 << slot); |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 546 | } |
| 547 | |
Michael S. Tsirkin | 4cff0a5 | 2010-11-12 16:21:35 +0900 | [diff] [blame] | 548 | static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev, |
| 549 | PCIHotplugState state) |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 550 | { |
| 551 | int slot = PCI_SLOT(dev->devfn); |
Isaku Yamahata | ac40409 | 2010-05-14 16:29:20 +0900 | [diff] [blame] | 552 | PIIX4PMState *s = DO_UPCAST(PIIX4PMState, dev, |
| 553 | DO_UPCAST(PCIDevice, qdev, qdev)); |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 554 | |
Michael S. Tsirkin | 4cff0a5 | 2010-11-12 16:21:35 +0900 | [diff] [blame] | 555 | /* Don't send event when device is enabled during qemu machine creation: |
| 556 | * it is present on boot, no hotplug event is necessary. We do send an |
| 557 | * event when the device is disabled later. */ |
| 558 | if (state == PCI_COLDPLUG_ENABLED) { |
Isaku Yamahata | 5beb8ad | 2010-09-06 16:46:18 +0900 | [diff] [blame] | 559 | return 0; |
Michael S. Tsirkin | 4cff0a5 | 2010-11-12 16:21:35 +0900 | [diff] [blame] | 560 | } |
Isaku Yamahata | 5beb8ad | 2010-09-06 16:46:18 +0900 | [diff] [blame] | 561 | |
Isaku Yamahata | ac40409 | 2010-05-14 16:29:20 +0900 | [diff] [blame] | 562 | s->pci0_status.up = 0; |
| 563 | s->pci0_status.down = 0; |
Michael S. Tsirkin | 4cff0a5 | 2010-11-12 16:21:35 +0900 | [diff] [blame] | 564 | if (state == PCI_HOTPLUG_ENABLED) { |
Isaku Yamahata | ac40409 | 2010-05-14 16:29:20 +0900 | [diff] [blame] | 565 | enable_device(s, slot); |
| 566 | } else { |
| 567 | disable_device(s, slot); |
| 568 | } |
Gleb Natapov | 633aa0a | 2010-10-17 11:45:25 +0200 | [diff] [blame] | 569 | |
| 570 | pm_update_sci(s); |
| 571 | |
Isaku Yamahata | 93d89f6 | 2010-05-14 16:29:02 +0900 | [diff] [blame] | 572 | return 0; |
| 573 | } |