tizen 2.3.1 release
[external/qemu.git] / tests / libqos / pci-pc.c
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
13 #include "libqtest.h"
14 #include "libqos/pci-pc.h"
15
16 #include "hw/pci/pci_regs.h"
17
18 #include "qemu-common.h"
19 #include "qemu/host-utils.h"
20
21 #include <glib.h>
22
23 typedef struct QPCIBusPC
24 {
25     QPCIBus bus;
26
27     uint32_t pci_hole_start;
28     uint32_t pci_hole_size;
29     uint32_t pci_hole_alloc;
30
31     uint16_t pci_iohole_start;
32     uint16_t pci_iohole_size;
33     uint16_t pci_iohole_alloc;
34 } QPCIBusPC;
35
36 static uint8_t qpci_pc_io_readb(QPCIBus *bus, void *addr)
37 {
38     uintptr_t port = (uintptr_t)addr;
39     uint8_t value;
40
41     if (port < 0x10000) {
42         value = inb(port);
43     } else {
44         memread(port, &value, sizeof(value));
45     }
46
47     return value;
48 }
49
50 static uint16_t qpci_pc_io_readw(QPCIBus *bus, void *addr)
51 {
52     uintptr_t port = (uintptr_t)addr;
53     uint16_t value;
54
55     if (port < 0x10000) {
56         value = inw(port);
57     } else {
58         memread(port, &value, sizeof(value));
59     }
60
61     return value;
62 }
63
64 static uint32_t qpci_pc_io_readl(QPCIBus *bus, void *addr)
65 {
66     uintptr_t port = (uintptr_t)addr;
67     uint32_t value;
68
69     if (port < 0x10000) {
70         value = inl(port);
71     } else {
72         memread(port, &value, sizeof(value));
73     }
74
75     return value;
76 }
77
78 static void qpci_pc_io_writeb(QPCIBus *bus, void *addr, uint8_t value)
79 {
80     uintptr_t port = (uintptr_t)addr;
81
82     if (port < 0x10000) {
83         outb(port, value);
84     } else {
85         memwrite(port, &value, sizeof(value));
86     }
87 }
88
89 static void qpci_pc_io_writew(QPCIBus *bus, void *addr, uint16_t value)
90 {
91     uintptr_t port = (uintptr_t)addr;
92
93     if (port < 0x10000) {
94         outw(port, value);
95     } else {
96         memwrite(port, &value, sizeof(value));
97     }
98 }
99
100 static void qpci_pc_io_writel(QPCIBus *bus, void *addr, uint32_t value)
101 {
102     uintptr_t port = (uintptr_t)addr;
103
104     if (port < 0x10000) {
105         outl(port, value);
106     } else {
107         memwrite(port, &value, sizeof(value));
108     }
109 }
110
111 static uint8_t qpci_pc_config_readb(QPCIBus *bus, int devfn, uint8_t offset)
112 {
113     outl(0xcf8, (1 << 31) | (devfn << 8) | offset);
114     return inb(0xcfc);
115 }
116
117 static uint16_t qpci_pc_config_readw(QPCIBus *bus, int devfn, uint8_t offset)
118 {
119     outl(0xcf8, (1 << 31) | (devfn << 8) | offset);
120     return inw(0xcfc);
121 }
122
123 static uint32_t qpci_pc_config_readl(QPCIBus *bus, int devfn, uint8_t offset)
124 {
125     outl(0xcf8, (1 << 31) | (devfn << 8) | offset);
126     return inl(0xcfc);
127 }
128
129 static void qpci_pc_config_writeb(QPCIBus *bus, int devfn, uint8_t offset, uint8_t value)
130 {
131     outl(0xcf8, (1 << 31) | (devfn << 8) | offset);
132     outb(0xcfc, value);
133 }
134
135 static void qpci_pc_config_writew(QPCIBus *bus, int devfn, uint8_t offset, uint16_t value)
136 {
137     outl(0xcf8, (1 << 31) | (devfn << 8) | offset);
138     outw(0xcfc, value);
139 }
140
141 static void qpci_pc_config_writel(QPCIBus *bus, int devfn, uint8_t offset, uint32_t value)
142 {
143     outl(0xcf8, (1 << 31) | (devfn << 8) | offset);
144     outl(0xcfc, value);
145 }
146
147 static void *qpci_pc_iomap(QPCIBus *bus, QPCIDevice *dev, int barno)
148 {
149     QPCIBusPC *s = container_of(bus, QPCIBusPC, bus);
150     static const int bar_reg_map[] = {
151         PCI_BASE_ADDRESS_0, PCI_BASE_ADDRESS_1, PCI_BASE_ADDRESS_2,
152         PCI_BASE_ADDRESS_3, PCI_BASE_ADDRESS_4, PCI_BASE_ADDRESS_5,
153     };
154     int bar_reg;
155     uint32_t addr;
156     uint64_t size;
157     uint32_t io_type;
158
159     g_assert(barno >= 0 && barno <= 5);
160     bar_reg = bar_reg_map[barno];
161
162     qpci_config_writel(dev, bar_reg, 0xFFFFFFFF);
163     addr = qpci_config_readl(dev, bar_reg);
164
165     io_type = addr & PCI_BASE_ADDRESS_SPACE;
166     if (io_type == PCI_BASE_ADDRESS_SPACE_IO) {
167         addr &= PCI_BASE_ADDRESS_IO_MASK;
168     } else {
169         addr &= PCI_BASE_ADDRESS_MEM_MASK;
170     }
171
172     size = (1ULL << ctzl(addr));
173     if (size == 0) {
174         return NULL;
175     }
176
177     if (io_type == PCI_BASE_ADDRESS_SPACE_IO) {
178         uint16_t loc;
179
180         g_assert((s->pci_iohole_alloc + size) <= s->pci_iohole_size);
181         loc = s->pci_iohole_start + s->pci_iohole_alloc;
182         s->pci_iohole_alloc += size;
183
184         qpci_config_writel(dev, bar_reg, loc | PCI_BASE_ADDRESS_SPACE_IO);
185
186         return (void *)(intptr_t)loc;
187     } else {
188         uint64_t loc;
189
190         g_assert((s->pci_hole_alloc + size) <= s->pci_hole_size);
191         loc = s->pci_hole_start + s->pci_hole_alloc;
192         s->pci_hole_alloc += size;
193
194         qpci_config_writel(dev, bar_reg, loc);
195
196         return (void *)(intptr_t)loc;
197     }
198 }
199
200 static void qpci_pc_iounmap(QPCIBus *bus, void *data)
201 {
202     /* FIXME */
203 }
204
205 QPCIBus *qpci_init_pc(void)
206 {
207     QPCIBusPC *ret;
208
209     ret = g_malloc(sizeof(*ret));
210
211     ret->bus.io_readb = qpci_pc_io_readb;
212     ret->bus.io_readw = qpci_pc_io_readw;
213     ret->bus.io_readl = qpci_pc_io_readl;
214
215     ret->bus.io_writeb = qpci_pc_io_writeb;
216     ret->bus.io_writew = qpci_pc_io_writew;
217     ret->bus.io_writel = qpci_pc_io_writel;
218
219     ret->bus.config_readb = qpci_pc_config_readb;
220     ret->bus.config_readw = qpci_pc_config_readw;
221     ret->bus.config_readl = qpci_pc_config_readl;
222
223     ret->bus.config_writeb = qpci_pc_config_writeb;
224     ret->bus.config_writew = qpci_pc_config_writew;
225     ret->bus.config_writel = qpci_pc_config_writel;
226
227     ret->bus.iomap = qpci_pc_iomap;
228     ret->bus.iounmap = qpci_pc_iounmap;
229
230     ret->pci_hole_start = 0xE0000000;
231     ret->pci_hole_size = 0x20000000;
232     ret->pci_hole_alloc = 0;
233
234     ret->pci_iohole_start = 0xc000;
235     ret->pci_iohole_size = 0x4000;
236     ret->pci_iohole_alloc = 0;
237
238     return &ret->bus;
239 }