]>
Commit | Line | Data |
---|---|---|
c4efe1ca AL |
1 | /* |
2 | * libqos PCI bindings for PC | |
3 | * | |
4 | * Copyright IBM, Corp. 2012-2013 | |
5 | * | |
6 | * Authors: | |
7 | * Anthony Liguori <aliguori@us.ibm.com> | |
8 | * | |
9 | * This work is licensed under the terms of the GNU GPL, version 2 or later. | |
10 | * See the COPYING file in the top-level directory. | |
11 | */ | |
12 | ||
681c28a3 | 13 | #include "qemu/osdep.h" |
c4efe1ca AL |
14 | #include "libqtest.h" |
15 | #include "libqos/pci-pc.h" | |
16 | ||
17 | #include "hw/pci/pci_regs.h" | |
18 | ||
19 | #include "qemu-common.h" | |
c4efe1ca | 20 | |
c4efe1ca | 21 | |
2f8b2767 IM |
22 | #define ACPI_PCIHP_ADDR 0xae00 |
23 | #define PCI_EJ_BASE 0x0008 | |
24 | ||
c4efe1ca AL |
25 | typedef struct QPCIBusPC |
26 | { | |
27 | QPCIBus bus; | |
c4efe1ca AL |
28 | } QPCIBusPC; |
29 | ||
a795fc08 | 30 | static uint8_t qpci_pc_pio_readb(QPCIBus *bus, uint32_t addr) |
c4efe1ca | 31 | { |
a795fc08 | 32 | return inb(addr); |
c4efe1ca AL |
33 | } |
34 | ||
a795fc08 DG |
35 | static void qpci_pc_pio_writeb(QPCIBus *bus, uint32_t addr, uint8_t val) |
36 | { | |
37 | outb(addr, val); | |
c4efe1ca AL |
38 | } |
39 | ||
a795fc08 DG |
40 | static uint16_t qpci_pc_pio_readw(QPCIBus *bus, uint32_t addr) |
41 | { | |
42 | return inw(addr); | |
43 | } | |
c4efe1ca | 44 | |
a795fc08 | 45 | static void qpci_pc_pio_writew(QPCIBus *bus, uint32_t addr, uint16_t val) |
c4efe1ca | 46 | { |
a795fc08 DG |
47 | outw(addr, val); |
48 | } | |
c4efe1ca | 49 | |
a795fc08 | 50 | static uint32_t qpci_pc_pio_readl(QPCIBus *bus, uint32_t addr) |
c4efe1ca | 51 | { |
a795fc08 DG |
52 | return inl(addr); |
53 | } | |
c4efe1ca | 54 | |
a795fc08 | 55 | static void qpci_pc_pio_writel(QPCIBus *bus, uint32_t addr, uint32_t val) |
c4efe1ca | 56 | { |
a795fc08 DG |
57 | outl(addr, val); |
58 | } | |
c4efe1ca | 59 | |
9a84f889 DG |
60 | static void qpci_pc_memread(QPCIBus *bus, uint32_t addr, void *buf, size_t len) |
61 | { | |
62 | memread(addr, buf, len); | |
63 | } | |
64 | ||
65 | static void qpci_pc_memwrite(QPCIBus *bus, uint32_t addr, | |
66 | const void *buf, size_t len) | |
67 | { | |
68 | memwrite(addr, buf, len); | |
69 | } | |
70 | ||
c4efe1ca AL |
71 | static uint8_t qpci_pc_config_readb(QPCIBus *bus, int devfn, uint8_t offset) |
72 | { | |
a879125b | 73 | outl(0xcf8, (1U << 31) | (devfn << 8) | offset); |
c4efe1ca AL |
74 | return inb(0xcfc); |
75 | } | |
76 | ||
77 | static uint16_t qpci_pc_config_readw(QPCIBus *bus, int devfn, uint8_t offset) | |
78 | { | |
a879125b | 79 | outl(0xcf8, (1U << 31) | (devfn << 8) | offset); |
c4efe1ca AL |
80 | return inw(0xcfc); |
81 | } | |
82 | ||
83 | static uint32_t qpci_pc_config_readl(QPCIBus *bus, int devfn, uint8_t offset) | |
84 | { | |
a879125b | 85 | outl(0xcf8, (1U << 31) | (devfn << 8) | offset); |
c4efe1ca AL |
86 | return inl(0xcfc); |
87 | } | |
88 | ||
89 | static void qpci_pc_config_writeb(QPCIBus *bus, int devfn, uint8_t offset, uint8_t value) | |
90 | { | |
a879125b | 91 | outl(0xcf8, (1U << 31) | (devfn << 8) | offset); |
c4efe1ca AL |
92 | outb(0xcfc, value); |
93 | } | |
94 | ||
95 | static void qpci_pc_config_writew(QPCIBus *bus, int devfn, uint8_t offset, uint16_t value) | |
96 | { | |
a879125b | 97 | outl(0xcf8, (1U << 31) | (devfn << 8) | offset); |
c4efe1ca AL |
98 | outw(0xcfc, value); |
99 | } | |
100 | ||
101 | static void qpci_pc_config_writel(QPCIBus *bus, int devfn, uint8_t offset, uint32_t value) | |
102 | { | |
a879125b | 103 | outl(0xcf8, (1U << 31) | (devfn << 8) | offset); |
c4efe1ca AL |
104 | outl(0xcfc, value); |
105 | } | |
106 | ||
2ecd7e2f | 107 | QPCIBus *qpci_init_pc(QGuestAllocator *alloc) |
c4efe1ca AL |
108 | { |
109 | QPCIBusPC *ret; | |
110 | ||
111 | ret = g_malloc(sizeof(*ret)); | |
112 | ||
a795fc08 DG |
113 | ret->bus.pio_readb = qpci_pc_pio_readb; |
114 | ret->bus.pio_readw = qpci_pc_pio_readw; | |
115 | ret->bus.pio_readl = qpci_pc_pio_readl; | |
116 | ||
117 | ret->bus.pio_writeb = qpci_pc_pio_writeb; | |
118 | ret->bus.pio_writew = qpci_pc_pio_writew; | |
119 | ret->bus.pio_writel = qpci_pc_pio_writel; | |
120 | ||
9a84f889 DG |
121 | ret->bus.memread = qpci_pc_memread; |
122 | ret->bus.memwrite = qpci_pc_memwrite; | |
123 | ||
c4efe1ca AL |
124 | ret->bus.config_readb = qpci_pc_config_readb; |
125 | ret->bus.config_readw = qpci_pc_config_readw; | |
126 | ret->bus.config_readl = qpci_pc_config_readl; | |
127 | ||
128 | ret->bus.config_writeb = qpci_pc_config_writeb; | |
129 | ret->bus.config_writew = qpci_pc_config_writew; | |
130 | ret->bus.config_writel = qpci_pc_config_writel; | |
131 | ||
b8cc4d02 DG |
132 | ret->bus.pio_alloc_ptr = 0xc000; |
133 | ret->bus.mmio_alloc_ptr = 0xE0000000; | |
134 | ret->bus.mmio_limit = 0x100000000ULL; | |
c4efe1ca AL |
135 | |
136 | return &ret->bus; | |
137 | } | |
7f2a5ae6 JS |
138 | |
139 | void qpci_free_pc(QPCIBus *bus) | |
140 | { | |
141 | QPCIBusPC *s = container_of(bus, QPCIBusPC, bus); | |
142 | ||
143 | g_free(s); | |
144 | } | |
2f8b2767 | 145 | |
2f8b2767 IM |
146 | void qpci_unplug_acpi_device_test(const char *id, uint8_t slot) |
147 | { | |
148 | QDict *response; | |
149 | char *cmd; | |
150 | ||
151 | cmd = g_strdup_printf("{'execute': 'device_del'," | |
152 | " 'arguments': {" | |
153 | " 'id': '%s'" | |
154 | "}}", id); | |
155 | response = qmp(cmd); | |
156 | g_free(cmd); | |
157 | g_assert(response); | |
158 | g_assert(!qdict_haskey(response, "error")); | |
159 | QDECREF(response); | |
160 | ||
161 | outb(ACPI_PCIHP_ADDR + PCI_EJ_BASE, 1 << slot); | |
162 | ||
163 | response = qmp(""); | |
164 | g_assert(response); | |
165 | g_assert(qdict_haskey(response, "event")); | |
166 | g_assert(!strcmp(qdict_get_str(response, "event"), "DEVICE_DELETED")); | |
167 | QDECREF(response); | |
168 | } |