1 | /* |
2 | * QEMU ICH9 Emulation |
3 | * |
4 | * Copyright (c) 2006 Fabrice Bellard |
5 | * Copyright (c) 2009, 2010, 2011 |
6 | * Isaku Yamahata <yamahata at valinux co jp> |
7 | * VA Linux Systems Japan K.K. |
8 | * Copyright (C) 2012 Jason Baron <jbaron@redhat.com> |
9 | * |
10 | * This is based on piix.c, but heavily modified. |
11 | * |
12 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
13 | * of this software and associated documentation files (the "Software"), to deal |
14 | * in the Software without restriction, including without limitation the rights |
15 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
16 | * copies of the Software, and to permit persons to whom the Software is |
17 | * furnished to do so, subject to the following conditions: |
18 | * |
19 | * The above copyright notice and this permission notice shall be included in |
20 | * all copies or substantial portions of the Software. |
21 | * |
22 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
23 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
24 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
25 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
26 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
27 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
28 | * THE SOFTWARE. |
29 | */ |
30 | |
31 | #include "qemu/osdep.h" |
32 | #include "cpu.h" |
33 | #include "qapi/visitor.h" |
34 | #include "qemu/range.h" |
35 | #include "hw/isa/isa.h" |
36 | #include "hw/sysbus.h" |
37 | #include "migration/vmstate.h" |
38 | #include "hw/i386/pc.h" |
39 | #include "hw/irq.h" |
40 | #include "hw/isa/apm.h" |
41 | #include "hw/i386/ioapic.h" |
42 | #include "hw/pci/pci.h" |
43 | #include "hw/pci/pci_bridge.h" |
44 | #include "hw/i386/ich9.h" |
45 | #include "hw/acpi/acpi.h" |
46 | #include "hw/acpi/ich9.h" |
47 | #include "hw/pci/pci_bus.h" |
48 | #include "hw/qdev-properties.h" |
49 | #include "exec/address-spaces.h" |
50 | #include "sysemu/runstate.h" |
51 | #include "sysemu/sysemu.h" |
52 | #include "hw/core/cpu.h" |
53 | #include "hw/nvram/fw_cfg.h" |
54 | #include "qemu/cutils.h" |
55 | |
56 | /*****************************************************************************/ |
57 | /* ICH9 LPC PCI to ISA bridge */ |
58 | |
59 | static void ich9_lpc_reset(DeviceState *qdev); |
60 | |
61 | /* chipset configuration register |
62 | * to access chipset configuration registers, pci_[sg]et_{byte, word, long} |
63 | * are used. |
64 | * Although it's not pci configuration space, it's little endian as Intel. |
65 | */ |
66 | |
67 | static void ich9_cc_update_ir(uint8_t irr[PCI_NUM_PINS], uint16_t ir) |
68 | { |
69 | int intx; |
70 | for (intx = 0; intx < PCI_NUM_PINS; intx++) { |
71 | irr[intx] = (ir >> (intx * ICH9_CC_DIR_SHIFT)) & ICH9_CC_DIR_MASK; |
72 | } |
73 | } |
74 | |
75 | static void ich9_cc_update(ICH9LPCState *lpc) |
76 | { |
77 | int slot; |
78 | int pci_intx; |
79 | |
80 | const int reg_offsets[] = { |
81 | ICH9_CC_D25IR, |
82 | ICH9_CC_D26IR, |
83 | ICH9_CC_D27IR, |
84 | ICH9_CC_D28IR, |
85 | ICH9_CC_D29IR, |
86 | ICH9_CC_D30IR, |
87 | ICH9_CC_D31IR, |
88 | }; |
89 | const int *offset; |
90 | |
91 | /* D{25 - 31}IR, but D30IR is read only to 0. */ |
92 | for (slot = 25, offset = reg_offsets; slot < 32; slot++, offset++) { |
93 | if (slot == 30) { |
94 | continue; |
95 | } |
96 | ich9_cc_update_ir(lpc->irr[slot], |
97 | pci_get_word(lpc->chip_config + *offset)); |
98 | } |
99 | |
100 | /* |
101 | * D30: DMI2PCI bridge |
102 | * It is arbitrarily decided how INTx lines of PCI devices behind |
103 | * the bridge are connected to pirq lines. Our choice is PIRQ[E-H]. |
104 | * INT[A-D] are connected to PIRQ[E-H] |
105 | */ |
106 | for (pci_intx = 0; pci_intx < PCI_NUM_PINS; pci_intx++) { |
107 | lpc->irr[30][pci_intx] = pci_intx + 4; |
108 | } |
109 | } |
110 | |
111 | static void ich9_cc_init(ICH9LPCState *lpc) |
112 | { |
113 | int slot; |
114 | int intx; |
115 | |
116 | /* the default irq routing is arbitrary as long as it matches with |
117 | * acpi irq routing table. |
118 | * The one that is incompatible with piix_pci(= bochs) one is |
119 | * intentionally chosen to let the users know that the different |
120 | * board is used. |
121 | * |
122 | * int[A-D] -> pirq[E-F] |
123 | * avoid pirq A-D because they are used for pci express port |
124 | */ |
125 | for (slot = 0; slot < PCI_SLOT_MAX; slot++) { |
126 | for (intx = 0; intx < PCI_NUM_PINS; intx++) { |
127 | lpc->irr[slot][intx] = (slot + intx) % 4 + 4; |
128 | } |
129 | } |
130 | ich9_cc_update(lpc); |
131 | } |
132 | |
133 | static void ich9_cc_reset(ICH9LPCState *lpc) |
134 | { |
135 | uint8_t *c = lpc->chip_config; |
136 | |
137 | memset(lpc->chip_config, 0, sizeof(lpc->chip_config)); |
138 | |
139 | pci_set_long(c + ICH9_CC_D31IR, ICH9_CC_DIR_DEFAULT); |
140 | pci_set_long(c + ICH9_CC_D30IR, ICH9_CC_D30IR_DEFAULT); |
141 | pci_set_long(c + ICH9_CC_D29IR, ICH9_CC_DIR_DEFAULT); |
142 | pci_set_long(c + ICH9_CC_D28IR, ICH9_CC_DIR_DEFAULT); |
143 | pci_set_long(c + ICH9_CC_D27IR, ICH9_CC_DIR_DEFAULT); |
144 | pci_set_long(c + ICH9_CC_D26IR, ICH9_CC_DIR_DEFAULT); |
145 | pci_set_long(c + ICH9_CC_D25IR, ICH9_CC_DIR_DEFAULT); |
146 | pci_set_long(c + ICH9_CC_GCS, ICH9_CC_GCS_DEFAULT); |
147 | |
148 | ich9_cc_update(lpc); |
149 | } |
150 | |
151 | static void ich9_cc_addr_len(uint64_t *addr, unsigned *len) |
152 | { |
153 | *addr &= ICH9_CC_ADDR_MASK; |
154 | if (*addr + *len >= ICH9_CC_SIZE) { |
155 | *len = ICH9_CC_SIZE - *addr; |
156 | } |
157 | } |
158 | |
159 | /* val: little endian */ |
160 | static void ich9_cc_write(void *opaque, hwaddr addr, |
161 | uint64_t val, unsigned len) |
162 | { |
163 | ICH9LPCState *lpc = (ICH9LPCState *)opaque; |
164 | |
165 | ich9_cc_addr_len(&addr, &len); |
166 | memcpy(lpc->chip_config + addr, &val, len); |
167 | pci_bus_fire_intx_routing_notifier(pci_get_bus(&lpc->d)); |
168 | ich9_cc_update(lpc); |
169 | } |
170 | |
171 | /* return value: little endian */ |
172 | static uint64_t ich9_cc_read(void *opaque, hwaddr addr, |
173 | unsigned len) |
174 | { |
175 | ICH9LPCState *lpc = (ICH9LPCState *)opaque; |
176 | |
177 | uint32_t val = 0; |
178 | ich9_cc_addr_len(&addr, &len); |
179 | memcpy(&val, lpc->chip_config + addr, len); |
180 | return val; |
181 | } |
182 | |
183 | /* IRQ routing */ |
184 | /* */ |
185 | static void ich9_lpc_rout(uint8_t pirq_rout, int *pic_irq, int *pic_dis) |
186 | { |
187 | *pic_irq = pirq_rout & ICH9_LPC_PIRQ_ROUT_MASK; |
188 | *pic_dis = pirq_rout & ICH9_LPC_PIRQ_ROUT_IRQEN; |
189 | } |
190 | |
191 | static void ich9_lpc_pic_irq(ICH9LPCState *lpc, int pirq_num, |
192 | int *pic_irq, int *pic_dis) |
193 | { |
194 | switch (pirq_num) { |
195 | case 0 ... 3: /* A-D */ |
196 | ich9_lpc_rout(lpc->d.config[ICH9_LPC_PIRQA_ROUT + pirq_num], |
197 | pic_irq, pic_dis); |
198 | return; |
199 | case 4 ... 7: /* E-H */ |
200 | ich9_lpc_rout(lpc->d.config[ICH9_LPC_PIRQE_ROUT + (pirq_num - 4)], |
201 | pic_irq, pic_dis); |
202 | return; |
203 | default: |
204 | break; |
205 | } |
206 | abort(); |
207 | } |
208 | |
209 | /* gsi: i8259+ioapic irq 0-15, otherwise assert */ |
210 | static void ich9_lpc_update_pic(ICH9LPCState *lpc, int gsi) |
211 | { |
212 | int i, pic_level; |
213 | |
214 | assert(gsi < ICH9_LPC_PIC_NUM_PINS); |
215 | |
216 | /* The pic level is the logical OR of all the PCI irqs mapped to it */ |
217 | pic_level = 0; |
218 | for (i = 0; i < ICH9_LPC_NB_PIRQS; i++) { |
219 | int tmp_irq; |
220 | int tmp_dis; |
221 | ich9_lpc_pic_irq(lpc, i, &tmp_irq, &tmp_dis); |
222 | if (!tmp_dis && tmp_irq == gsi) { |
223 | pic_level |= pci_bus_get_irq_level(pci_get_bus(&lpc->d), i); |
224 | } |
225 | } |
226 | if (gsi == lpc->sci_gsi) { |
227 | pic_level |= lpc->sci_level; |
228 | } |
229 | |
230 | qemu_set_irq(lpc->gsi[gsi], pic_level); |
231 | } |
232 | |
233 | /* APIC mode: GSIx: PIRQ[A-H] -> GSI 16, ... no pirq shares same APIC pins. */ |
234 | static int ich9_pirq_to_gsi(int pirq) |
235 | { |
236 | return pirq + ICH9_LPC_PIC_NUM_PINS; |
237 | } |
238 | |
239 | static int ich9_gsi_to_pirq(int gsi) |
240 | { |
241 | return gsi - ICH9_LPC_PIC_NUM_PINS; |
242 | } |
243 | |
244 | /* gsi: ioapic irq 16-23, otherwise assert */ |
245 | static void ich9_lpc_update_apic(ICH9LPCState *lpc, int gsi) |
246 | { |
247 | int level = 0; |
248 | |
249 | assert(gsi >= ICH9_LPC_PIC_NUM_PINS); |
250 | |
251 | level |= pci_bus_get_irq_level(pci_get_bus(&lpc->d), ich9_gsi_to_pirq(gsi)); |
252 | if (gsi == lpc->sci_gsi) { |
253 | level |= lpc->sci_level; |
254 | } |
255 | |
256 | qemu_set_irq(lpc->gsi[gsi], level); |
257 | } |
258 | |
259 | void ich9_lpc_set_irq(void *opaque, int pirq, int level) |
260 | { |
261 | ICH9LPCState *lpc = opaque; |
262 | int pic_irq, pic_dis; |
263 | |
264 | assert(0 <= pirq); |
265 | assert(pirq < ICH9_LPC_NB_PIRQS); |
266 | |
267 | ich9_lpc_update_apic(lpc, ich9_pirq_to_gsi(pirq)); |
268 | ich9_lpc_pic_irq(lpc, pirq, &pic_irq, &pic_dis); |
269 | ich9_lpc_update_pic(lpc, pic_irq); |
270 | } |
271 | |
272 | /* return the pirq number (PIRQ[A-H]:0-7) corresponding to |
273 | * a given device irq pin. |
274 | */ |
275 | int ich9_lpc_map_irq(PCIDevice *pci_dev, int intx) |
276 | { |
277 | BusState *bus = qdev_get_parent_bus(&pci_dev->qdev); |
278 | PCIBus *pci_bus = PCI_BUS(bus); |
279 | PCIDevice *lpc_pdev = |
280 | pci_bus->devices[PCI_DEVFN(ICH9_LPC_DEV, ICH9_LPC_FUNC)]; |
281 | ICH9LPCState *lpc = ICH9_LPC_DEVICE(lpc_pdev); |
282 | |
283 | return lpc->irr[PCI_SLOT(pci_dev->devfn)][intx]; |
284 | } |
285 | |
286 | PCIINTxRoute ich9_route_intx_pin_to_irq(void *opaque, int pirq_pin) |
287 | { |
288 | ICH9LPCState *lpc = opaque; |
289 | PCIINTxRoute route; |
290 | int pic_irq; |
291 | int pic_dis; |
292 | |
293 | assert(0 <= pirq_pin); |
294 | assert(pirq_pin < ICH9_LPC_NB_PIRQS); |
295 | |
296 | route.mode = PCI_INTX_ENABLED; |
297 | ich9_lpc_pic_irq(lpc, pirq_pin, &pic_irq, &pic_dis); |
298 | if (!pic_dis) { |
299 | if (pic_irq < ICH9_LPC_PIC_NUM_PINS) { |
300 | route.irq = pic_irq; |
301 | } else { |
302 | route.mode = PCI_INTX_DISABLED; |
303 | route.irq = -1; |
304 | } |
305 | } else { |
306 | route.irq = ich9_pirq_to_gsi(pirq_pin); |
307 | } |
308 | |
309 | return route; |
310 | } |
311 | |
312 | void ich9_generate_smi(void) |
313 | { |
314 | cpu_interrupt(first_cpu, CPU_INTERRUPT_SMI); |
315 | } |
316 | |
317 | static int ich9_lpc_sci_irq(ICH9LPCState *lpc) |
318 | { |
319 | switch (lpc->d.config[ICH9_LPC_ACPI_CTRL] & |
320 | ICH9_LPC_ACPI_CTRL_SCI_IRQ_SEL_MASK) { |
321 | case ICH9_LPC_ACPI_CTRL_9: |
322 | return 9; |
323 | case ICH9_LPC_ACPI_CTRL_10: |
324 | return 10; |
325 | case ICH9_LPC_ACPI_CTRL_11: |
326 | return 11; |
327 | case ICH9_LPC_ACPI_CTRL_20: |
328 | return 20; |
329 | case ICH9_LPC_ACPI_CTRL_21: |
330 | return 21; |
331 | default: |
332 | /* reserved */ |
333 | break; |
334 | } |
335 | return -1; |
336 | } |
337 | |
338 | static void ich9_set_sci(void *opaque, int irq_num, int level) |
339 | { |
340 | ICH9LPCState *lpc = opaque; |
341 | int irq; |
342 | |
343 | assert(irq_num == 0); |
344 | level = !!level; |
345 | if (level == lpc->sci_level) { |
346 | return; |
347 | } |
348 | lpc->sci_level = level; |
349 | |
350 | irq = lpc->sci_gsi; |
351 | if (irq < 0) { |
352 | return; |
353 | } |
354 | |
355 | if (irq >= ICH9_LPC_PIC_NUM_PINS) { |
356 | ich9_lpc_update_apic(lpc, irq); |
357 | } else { |
358 | ich9_lpc_update_pic(lpc, irq); |
359 | } |
360 | } |
361 | |
362 | static void smi_features_ok_callback(void *opaque) |
363 | { |
364 | ICH9LPCState *lpc = opaque; |
365 | uint64_t guest_features; |
366 | |
367 | if (lpc->smi_features_ok) { |
368 | /* negotiation already complete, features locked */ |
369 | return; |
370 | } |
371 | |
372 | memcpy(&guest_features, lpc->smi_guest_features_le, sizeof guest_features); |
373 | le64_to_cpus(&guest_features); |
374 | if (guest_features & ~lpc->smi_host_features) { |
375 | /* guest requests invalid features, leave @features_ok at zero */ |
376 | return; |
377 | } |
378 | |
379 | /* valid feature subset requested, lock it down, report success */ |
380 | lpc->smi_negotiated_features = guest_features; |
381 | lpc->smi_features_ok = 1; |
382 | } |
383 | |
384 | void ich9_lpc_pm_init(PCIDevice *lpc_pci, bool smm_enabled) |
385 | { |
386 | ICH9LPCState *lpc = ICH9_LPC_DEVICE(lpc_pci); |
387 | qemu_irq sci_irq; |
388 | FWCfgState *fw_cfg = fw_cfg_find(); |
389 | |
390 | sci_irq = qemu_allocate_irq(ich9_set_sci, lpc, 0); |
391 | ich9_pm_init(lpc_pci, &lpc->pm, smm_enabled, sci_irq); |
392 | |
393 | if (lpc->smi_host_features && fw_cfg) { |
394 | uint64_t host_features_le; |
395 | |
396 | host_features_le = cpu_to_le64(lpc->smi_host_features); |
397 | memcpy(lpc->smi_host_features_le, &host_features_le, |
398 | sizeof host_features_le); |
399 | fw_cfg_add_file(fw_cfg, "etc/smi/supported-features" , |
400 | lpc->smi_host_features_le, |
401 | sizeof lpc->smi_host_features_le); |
402 | |
403 | /* The other two guest-visible fields are cleared on device reset, we |
404 | * just link them into fw_cfg here. |
405 | */ |
406 | fw_cfg_add_file_callback(fw_cfg, "etc/smi/requested-features" , |
407 | NULL, NULL, NULL, |
408 | lpc->smi_guest_features_le, |
409 | sizeof lpc->smi_guest_features_le, |
410 | false); |
411 | fw_cfg_add_file_callback(fw_cfg, "etc/smi/features-ok" , |
412 | smi_features_ok_callback, NULL, lpc, |
413 | &lpc->smi_features_ok, |
414 | sizeof lpc->smi_features_ok, |
415 | true); |
416 | } |
417 | |
418 | ich9_lpc_reset(DEVICE(lpc)); |
419 | } |
420 | |
421 | /* APM */ |
422 | |
423 | static void ich9_apm_ctrl_changed(uint32_t val, void *arg) |
424 | { |
425 | ICH9LPCState *lpc = arg; |
426 | |
427 | /* ACPI specs 3.0, 4.7.2.5 */ |
428 | acpi_pm1_cnt_update(&lpc->pm.acpi_regs, |
429 | val == ICH9_APM_ACPI_ENABLE, |
430 | val == ICH9_APM_ACPI_DISABLE); |
431 | if (val == ICH9_APM_ACPI_ENABLE || val == ICH9_APM_ACPI_DISABLE) { |
432 | return; |
433 | } |
434 | |
435 | /* SMI_EN = PMBASE + 30. SMI control and enable register */ |
436 | if (lpc->pm.smi_en & ICH9_PMIO_SMI_EN_APMC_EN) { |
437 | if (lpc->smi_negotiated_features & |
438 | (UINT64_C(1) << ICH9_LPC_SMI_F_BROADCAST_BIT)) { |
439 | CPUState *cs; |
440 | CPU_FOREACH(cs) { |
441 | cpu_interrupt(cs, CPU_INTERRUPT_SMI); |
442 | } |
443 | } else { |
444 | cpu_interrupt(current_cpu, CPU_INTERRUPT_SMI); |
445 | } |
446 | } |
447 | } |
448 | |
449 | /* config:PMBASE */ |
450 | static void |
451 | ich9_lpc_pmbase_sci_update(ICH9LPCState *lpc) |
452 | { |
453 | uint32_t pm_io_base = pci_get_long(lpc->d.config + ICH9_LPC_PMBASE); |
454 | uint8_t acpi_cntl = pci_get_long(lpc->d.config + ICH9_LPC_ACPI_CTRL); |
455 | uint8_t new_gsi; |
456 | |
457 | if (acpi_cntl & ICH9_LPC_ACPI_CTRL_ACPI_EN) { |
458 | pm_io_base &= ICH9_LPC_PMBASE_BASE_ADDRESS_MASK; |
459 | } else { |
460 | pm_io_base = 0; |
461 | } |
462 | |
463 | ich9_pm_iospace_update(&lpc->pm, pm_io_base); |
464 | |
465 | new_gsi = ich9_lpc_sci_irq(lpc); |
466 | if (lpc->sci_level && new_gsi != lpc->sci_gsi) { |
467 | qemu_set_irq(lpc->pm.irq, 0); |
468 | lpc->sci_gsi = new_gsi; |
469 | qemu_set_irq(lpc->pm.irq, 1); |
470 | } |
471 | lpc->sci_gsi = new_gsi; |
472 | } |
473 | |
474 | /* config:RCBA */ |
475 | static void ich9_lpc_rcba_update(ICH9LPCState *lpc, uint32_t rcba_old) |
476 | { |
477 | uint32_t rcba = pci_get_long(lpc->d.config + ICH9_LPC_RCBA); |
478 | |
479 | if (rcba_old & ICH9_LPC_RCBA_EN) { |
480 | memory_region_del_subregion(get_system_memory(), &lpc->rcrb_mem); |
481 | } |
482 | if (rcba & ICH9_LPC_RCBA_EN) { |
483 | memory_region_add_subregion_overlap(get_system_memory(), |
484 | rcba & ICH9_LPC_RCBA_BA_MASK, |
485 | &lpc->rcrb_mem, 1); |
486 | } |
487 | } |
488 | |
489 | /* config:GEN_PMCON* */ |
490 | static void |
491 | ich9_lpc_pmcon_update(ICH9LPCState *lpc) |
492 | { |
493 | uint16_t gen_pmcon_1 = pci_get_word(lpc->d.config + ICH9_LPC_GEN_PMCON_1); |
494 | uint16_t wmask; |
495 | |
496 | if (gen_pmcon_1 & ICH9_LPC_GEN_PMCON_1_SMI_LOCK) { |
497 | wmask = pci_get_word(lpc->d.wmask + ICH9_LPC_GEN_PMCON_1); |
498 | wmask &= ~ICH9_LPC_GEN_PMCON_1_SMI_LOCK; |
499 | pci_set_word(lpc->d.wmask + ICH9_LPC_GEN_PMCON_1, wmask); |
500 | lpc->pm.smi_en_wmask &= ~1; |
501 | } |
502 | } |
503 | |
504 | static int ich9_lpc_post_load(void *opaque, int version_id) |
505 | { |
506 | ICH9LPCState *lpc = opaque; |
507 | |
508 | ich9_lpc_pmbase_sci_update(lpc); |
509 | ich9_lpc_rcba_update(lpc, 0 /* disabled ICH9_LPC_RCBA_EN */); |
510 | ich9_lpc_pmcon_update(lpc); |
511 | return 0; |
512 | } |
513 | |
514 | static void ich9_lpc_config_write(PCIDevice *d, |
515 | uint32_t addr, uint32_t val, int len) |
516 | { |
517 | ICH9LPCState *lpc = ICH9_LPC_DEVICE(d); |
518 | uint32_t rcba_old = pci_get_long(d->config + ICH9_LPC_RCBA); |
519 | |
520 | pci_default_write_config(d, addr, val, len); |
521 | if (ranges_overlap(addr, len, ICH9_LPC_PMBASE, 4) || |
522 | ranges_overlap(addr, len, ICH9_LPC_ACPI_CTRL, 1)) { |
523 | ich9_lpc_pmbase_sci_update(lpc); |
524 | } |
525 | if (ranges_overlap(addr, len, ICH9_LPC_RCBA, 4)) { |
526 | ich9_lpc_rcba_update(lpc, rcba_old); |
527 | } |
528 | if (ranges_overlap(addr, len, ICH9_LPC_PIRQA_ROUT, 4)) { |
529 | pci_bus_fire_intx_routing_notifier(pci_get_bus(&lpc->d)); |
530 | } |
531 | if (ranges_overlap(addr, len, ICH9_LPC_PIRQE_ROUT, 4)) { |
532 | pci_bus_fire_intx_routing_notifier(pci_get_bus(&lpc->d)); |
533 | } |
534 | if (ranges_overlap(addr, len, ICH9_LPC_GEN_PMCON_1, 8)) { |
535 | ich9_lpc_pmcon_update(lpc); |
536 | } |
537 | } |
538 | |
539 | static void ich9_lpc_reset(DeviceState *qdev) |
540 | { |
541 | PCIDevice *d = PCI_DEVICE(qdev); |
542 | ICH9LPCState *lpc = ICH9_LPC_DEVICE(d); |
543 | uint32_t rcba_old = pci_get_long(d->config + ICH9_LPC_RCBA); |
544 | int i; |
545 | |
546 | for (i = 0; i < 4; i++) { |
547 | pci_set_byte(d->config + ICH9_LPC_PIRQA_ROUT + i, |
548 | ICH9_LPC_PIRQ_ROUT_DEFAULT); |
549 | } |
550 | for (i = 0; i < 4; i++) { |
551 | pci_set_byte(d->config + ICH9_LPC_PIRQE_ROUT + i, |
552 | ICH9_LPC_PIRQ_ROUT_DEFAULT); |
553 | } |
554 | pci_set_byte(d->config + ICH9_LPC_ACPI_CTRL, ICH9_LPC_ACPI_CTRL_DEFAULT); |
555 | |
556 | pci_set_long(d->config + ICH9_LPC_PMBASE, ICH9_LPC_PMBASE_DEFAULT); |
557 | pci_set_long(d->config + ICH9_LPC_RCBA, ICH9_LPC_RCBA_DEFAULT); |
558 | |
559 | ich9_cc_reset(lpc); |
560 | |
561 | ich9_lpc_pmbase_sci_update(lpc); |
562 | ich9_lpc_rcba_update(lpc, rcba_old); |
563 | |
564 | lpc->sci_level = 0; |
565 | lpc->rst_cnt = 0; |
566 | |
567 | memset(lpc->smi_guest_features_le, 0, sizeof lpc->smi_guest_features_le); |
568 | lpc->smi_features_ok = 0; |
569 | lpc->smi_negotiated_features = 0; |
570 | } |
571 | |
572 | /* root complex register block is mapped into memory space */ |
573 | static const MemoryRegionOps rcrb_mmio_ops = { |
574 | .read = ich9_cc_read, |
575 | .write = ich9_cc_write, |
576 | .endianness = DEVICE_LITTLE_ENDIAN, |
577 | }; |
578 | |
579 | static void ich9_lpc_machine_ready(Notifier *n, void *opaque) |
580 | { |
581 | ICH9LPCState *s = container_of(n, ICH9LPCState, machine_ready); |
582 | MemoryRegion *io_as = pci_address_space_io(&s->d); |
583 | uint8_t *pci_conf; |
584 | |
585 | pci_conf = s->d.config; |
586 | if (memory_region_present(io_as, 0x3f8)) { |
587 | /* com1 */ |
588 | pci_conf[0x82] |= 0x01; |
589 | } |
590 | if (memory_region_present(io_as, 0x2f8)) { |
591 | /* com2 */ |
592 | pci_conf[0x82] |= 0x02; |
593 | } |
594 | if (memory_region_present(io_as, 0x378)) { |
595 | /* lpt */ |
596 | pci_conf[0x82] |= 0x04; |
597 | } |
598 | if (memory_region_present(io_as, 0x3f2)) { |
599 | /* floppy */ |
600 | pci_conf[0x82] |= 0x08; |
601 | } |
602 | } |
603 | |
604 | /* reset control */ |
605 | static void ich9_rst_cnt_write(void *opaque, hwaddr addr, uint64_t val, |
606 | unsigned len) |
607 | { |
608 | ICH9LPCState *lpc = opaque; |
609 | |
610 | if (val & 4) { |
611 | qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); |
612 | return; |
613 | } |
614 | lpc->rst_cnt = val & 0xA; /* keep FULL_RST (bit 3) and SYS_RST (bit 1) */ |
615 | } |
616 | |
617 | static uint64_t ich9_rst_cnt_read(void *opaque, hwaddr addr, unsigned len) |
618 | { |
619 | ICH9LPCState *lpc = opaque; |
620 | |
621 | return lpc->rst_cnt; |
622 | } |
623 | |
624 | static const MemoryRegionOps ich9_rst_cnt_ops = { |
625 | .read = ich9_rst_cnt_read, |
626 | .write = ich9_rst_cnt_write, |
627 | .endianness = DEVICE_LITTLE_ENDIAN |
628 | }; |
629 | |
630 | static void ich9_lpc_get_sci_int(Object *obj, Visitor *v, const char *name, |
631 | void *opaque, Error **errp) |
632 | { |
633 | ICH9LPCState *lpc = ICH9_LPC_DEVICE(obj); |
634 | uint32_t value = lpc->sci_gsi; |
635 | |
636 | visit_type_uint32(v, name, &value, errp); |
637 | } |
638 | |
639 | static void ich9_lpc_add_properties(ICH9LPCState *lpc) |
640 | { |
641 | static const uint8_t acpi_enable_cmd = ICH9_APM_ACPI_ENABLE; |
642 | static const uint8_t acpi_disable_cmd = ICH9_APM_ACPI_DISABLE; |
643 | |
644 | object_property_add(OBJECT(lpc), ACPI_PM_PROP_SCI_INT, "uint32" , |
645 | ich9_lpc_get_sci_int, |
646 | NULL, NULL, NULL, NULL); |
647 | object_property_add_uint8_ptr(OBJECT(lpc), ACPI_PM_PROP_ACPI_ENABLE_CMD, |
648 | &acpi_enable_cmd, NULL); |
649 | object_property_add_uint8_ptr(OBJECT(lpc), ACPI_PM_PROP_ACPI_DISABLE_CMD, |
650 | &acpi_disable_cmd, NULL); |
651 | |
652 | ich9_pm_add_properties(OBJECT(lpc), &lpc->pm, NULL); |
653 | } |
654 | |
655 | static void ich9_lpc_initfn(Object *obj) |
656 | { |
657 | ICH9LPCState *lpc = ICH9_LPC_DEVICE(obj); |
658 | |
659 | ich9_lpc_add_properties(lpc); |
660 | } |
661 | |
662 | static void ich9_lpc_realize(PCIDevice *d, Error **errp) |
663 | { |
664 | ICH9LPCState *lpc = ICH9_LPC_DEVICE(d); |
665 | DeviceState *dev = DEVICE(d); |
666 | ISABus *isa_bus; |
667 | |
668 | isa_bus = isa_bus_new(DEVICE(d), get_system_memory(), get_system_io(), |
669 | errp); |
670 | if (!isa_bus) { |
671 | return; |
672 | } |
673 | |
674 | pci_set_long(d->wmask + ICH9_LPC_PMBASE, |
675 | ICH9_LPC_PMBASE_BASE_ADDRESS_MASK); |
676 | pci_set_byte(d->wmask + ICH9_LPC_PMBASE, |
677 | ICH9_LPC_ACPI_CTRL_ACPI_EN | |
678 | ICH9_LPC_ACPI_CTRL_SCI_IRQ_SEL_MASK); |
679 | |
680 | memory_region_init_io(&lpc->rcrb_mem, OBJECT(d), &rcrb_mmio_ops, lpc, |
681 | "lpc-rcrb-mmio" , ICH9_CC_SIZE); |
682 | |
683 | lpc->isa_bus = isa_bus; |
684 | |
685 | ich9_cc_init(lpc); |
686 | apm_init(d, &lpc->apm, ich9_apm_ctrl_changed, lpc); |
687 | |
688 | lpc->machine_ready.notify = ich9_lpc_machine_ready; |
689 | qemu_add_machine_init_done_notifier(&lpc->machine_ready); |
690 | |
691 | memory_region_init_io(&lpc->rst_cnt_mem, OBJECT(d), &ich9_rst_cnt_ops, lpc, |
692 | "lpc-reset-control" , 1); |
693 | memory_region_add_subregion_overlap(pci_address_space_io(d), |
694 | ICH9_RST_CNT_IOPORT, &lpc->rst_cnt_mem, |
695 | 1); |
696 | |
697 | qdev_init_gpio_out_named(dev, lpc->gsi, ICH9_GPIO_GSI, GSI_NUM_PINS); |
698 | |
699 | isa_bus_irqs(isa_bus, lpc->gsi); |
700 | } |
701 | |
702 | static bool ich9_rst_cnt_needed(void *opaque) |
703 | { |
704 | ICH9LPCState *lpc = opaque; |
705 | |
706 | return (lpc->rst_cnt != 0); |
707 | } |
708 | |
709 | static const VMStateDescription vmstate_ich9_rst_cnt = { |
710 | .name = "ICH9LPC/rst_cnt" , |
711 | .version_id = 1, |
712 | .minimum_version_id = 1, |
713 | .needed = ich9_rst_cnt_needed, |
714 | .fields = (VMStateField[]) { |
715 | VMSTATE_UINT8(rst_cnt, ICH9LPCState), |
716 | VMSTATE_END_OF_LIST() |
717 | } |
718 | }; |
719 | |
720 | static bool ich9_smi_feat_needed(void *opaque) |
721 | { |
722 | ICH9LPCState *lpc = opaque; |
723 | |
724 | return !buffer_is_zero(lpc->smi_guest_features_le, |
725 | sizeof lpc->smi_guest_features_le) || |
726 | lpc->smi_features_ok; |
727 | } |
728 | |
729 | static const VMStateDescription vmstate_ich9_smi_feat = { |
730 | .name = "ICH9LPC/smi_feat" , |
731 | .version_id = 1, |
732 | .minimum_version_id = 1, |
733 | .needed = ich9_smi_feat_needed, |
734 | .fields = (VMStateField[]) { |
735 | VMSTATE_UINT8_ARRAY(smi_guest_features_le, ICH9LPCState, |
736 | sizeof(uint64_t)), |
737 | VMSTATE_UINT8(smi_features_ok, ICH9LPCState), |
738 | VMSTATE_UINT64(smi_negotiated_features, ICH9LPCState), |
739 | VMSTATE_END_OF_LIST() |
740 | } |
741 | }; |
742 | |
743 | static const VMStateDescription vmstate_ich9_lpc = { |
744 | .name = "ICH9LPC" , |
745 | .version_id = 1, |
746 | .minimum_version_id = 1, |
747 | .post_load = ich9_lpc_post_load, |
748 | .fields = (VMStateField[]) { |
749 | VMSTATE_PCI_DEVICE(d, ICH9LPCState), |
750 | VMSTATE_STRUCT(apm, ICH9LPCState, 0, vmstate_apm, APMState), |
751 | VMSTATE_STRUCT(pm, ICH9LPCState, 0, vmstate_ich9_pm, ICH9LPCPMRegs), |
752 | VMSTATE_UINT8_ARRAY(chip_config, ICH9LPCState, ICH9_CC_SIZE), |
753 | VMSTATE_UINT32(sci_level, ICH9LPCState), |
754 | VMSTATE_END_OF_LIST() |
755 | }, |
756 | .subsections = (const VMStateDescription*[]) { |
757 | &vmstate_ich9_rst_cnt, |
758 | &vmstate_ich9_smi_feat, |
759 | NULL |
760 | } |
761 | }; |
762 | |
763 | static Property ich9_lpc_properties[] = { |
764 | DEFINE_PROP_BOOL("noreboot" , ICH9LPCState, pin_strap.spkr_hi, true), |
765 | DEFINE_PROP_BIT64("x-smi-broadcast" , ICH9LPCState, smi_host_features, |
766 | ICH9_LPC_SMI_F_BROADCAST_BIT, true), |
767 | DEFINE_PROP_END_OF_LIST(), |
768 | }; |
769 | |
770 | static void ich9_send_gpe(AcpiDeviceIf *adev, AcpiEventStatusBits ev) |
771 | { |
772 | ICH9LPCState *s = ICH9_LPC_DEVICE(adev); |
773 | |
774 | acpi_send_gpe_event(&s->pm.acpi_regs, s->pm.irq, ev); |
775 | } |
776 | |
777 | static void ich9_lpc_class_init(ObjectClass *klass, void *data) |
778 | { |
779 | DeviceClass *dc = DEVICE_CLASS(klass); |
780 | PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); |
781 | HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass); |
782 | AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_CLASS(klass); |
783 | |
784 | set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); |
785 | dc->reset = ich9_lpc_reset; |
786 | k->realize = ich9_lpc_realize; |
787 | dc->vmsd = &vmstate_ich9_lpc; |
788 | dc->props = ich9_lpc_properties; |
789 | k->config_write = ich9_lpc_config_write; |
790 | dc->desc = "ICH9 LPC bridge" ; |
791 | k->vendor_id = PCI_VENDOR_ID_INTEL; |
792 | k->device_id = PCI_DEVICE_ID_INTEL_ICH9_8; |
793 | k->revision = ICH9_A2_LPC_REVISION; |
794 | k->class_id = PCI_CLASS_BRIDGE_ISA; |
795 | /* |
796 | * Reason: part of ICH9 southbridge, needs to be wired up by |
797 | * pc_q35_init() |
798 | */ |
799 | dc->user_creatable = false; |
800 | hc->pre_plug = ich9_pm_device_pre_plug_cb; |
801 | hc->plug = ich9_pm_device_plug_cb; |
802 | hc->unplug_request = ich9_pm_device_unplug_request_cb; |
803 | hc->unplug = ich9_pm_device_unplug_cb; |
804 | adevc->ospm_status = ich9_pm_ospm_status; |
805 | adevc->send_event = ich9_send_gpe; |
806 | adevc->madt_cpu = pc_madt_cpu_entry; |
807 | } |
808 | |
809 | static const TypeInfo ich9_lpc_info = { |
810 | .name = TYPE_ICH9_LPC_DEVICE, |
811 | .parent = TYPE_PCI_DEVICE, |
812 | .instance_size = sizeof(struct ICH9LPCState), |
813 | .instance_init = ich9_lpc_initfn, |
814 | .class_init = ich9_lpc_class_init, |
815 | .interfaces = (InterfaceInfo[]) { |
816 | { TYPE_HOTPLUG_HANDLER }, |
817 | { TYPE_ACPI_DEVICE_IF }, |
818 | { INTERFACE_CONVENTIONAL_PCI_DEVICE }, |
819 | { } |
820 | } |
821 | }; |
822 | |
823 | static void ich9_lpc_register(void) |
824 | { |
825 | type_register_static(&ich9_lpc_info); |
826 | } |
827 | |
828 | type_init(ich9_lpc_register); |
829 | |