]>
Commit | Line | Data |
---|---|---|
a72bd606 | 1 | /* |
18092598 | 2 | * HP-PARISC Dino PCI chipset emulation, as in B160L and similiar machines |
a72bd606 | 3 | * |
18092598 | 4 | * (C) 2017-2019 by Helge Deller <deller@gmx.de> |
a72bd606 HD |
5 | * |
6 | * This work is licensed under the GNU GPL license version 2 or later. | |
7 | * | |
8 | * Documentation available at: | |
9 | * https://parisc.wiki.kernel.org/images-parisc/9/91/Dino_ers.pdf | |
10 | * https://parisc.wiki.kernel.org/images-parisc/7/70/Dino_3_1_Errata.pdf | |
11 | */ | |
12 | ||
13 | #include "qemu/osdep.h" | |
0b8fa32f | 14 | #include "qemu/module.h" |
c108cc59 | 15 | #include "qemu/units.h" |
a72bd606 | 16 | #include "qapi/error.h" |
64552b6b | 17 | #include "hw/irq.h" |
a72bd606 HD |
18 | #include "hw/pci/pci.h" |
19 | #include "hw/pci/pci_bus.h" | |
270b2958 | 20 | #include "hw/qdev-properties.h" |
0db9350e | 21 | #include "hw/pci-host/dino.h" |
d6454270 | 22 | #include "migration/vmstate.h" |
18092598 | 23 | #include "trace.h" |
db1015e9 | 24 | #include "qom/object.h" |
a72bd606 HD |
25 | |
26 | ||
a72bd606 HD |
27 | /* |
28 | * Dino can forward memory accesses from the CPU in the range between | |
29 | * 0xf0800000 and 0xff000000 to the PCI bus. | |
30 | */ | |
31 | static void gsc_to_pci_forwarding(DinoState *s) | |
32 | { | |
33 | uint32_t io_addr_en, tmp; | |
34 | int enabled, i; | |
35 | ||
36 | tmp = extract32(s->io_control, 7, 2); | |
37 | enabled = (tmp == 0x01); | |
38 | io_addr_en = s->io_addr_en; | |
18092598 HD |
39 | /* Mask out first (=firmware) and last (=Dino) areas. */ |
40 | io_addr_en &= ~(BIT(31) | BIT(0)); | |
a72bd606 HD |
41 | |
42 | memory_region_transaction_begin(); | |
43 | for (i = 1; i < 31; i++) { | |
44 | MemoryRegion *mem = &s->pci_mem_alias[i]; | |
45 | if (enabled && (io_addr_en & (1U << i))) { | |
46 | if (!memory_region_is_mapped(mem)) { | |
47 | uint32_t addr = 0xf0000000 + i * DINO_MEM_CHUNK_SIZE; | |
48 | memory_region_add_subregion(get_system_memory(), addr, mem); | |
49 | } | |
50 | } else if (memory_region_is_mapped(mem)) { | |
51 | memory_region_del_subregion(get_system_memory(), mem); | |
52 | } | |
53 | } | |
54 | memory_region_transaction_commit(); | |
55 | } | |
56 | ||
57 | static bool dino_chip_mem_valid(void *opaque, hwaddr addr, | |
8372d383 PM |
58 | unsigned size, bool is_write, |
59 | MemTxAttrs attrs) | |
a72bd606 | 60 | { |
18092598 HD |
61 | bool ret = false; |
62 | ||
a72bd606 HD |
63 | switch (addr) { |
64 | case DINO_IAR0: | |
65 | case DINO_IAR1: | |
66 | case DINO_IRR0: | |
67 | case DINO_IRR1: | |
68 | case DINO_IMR: | |
69 | case DINO_IPR: | |
70 | case DINO_ICR: | |
71 | case DINO_ILR: | |
72 | case DINO_IO_CONTROL: | |
18092598 | 73 | case DINO_IO_FBB_EN: |
a72bd606 HD |
74 | case DINO_IO_ADDR_EN: |
75 | case DINO_PCI_IO_DATA: | |
18092598 | 76 | case DINO_TOC_ADDR: |
90e94c05 PMD |
77 | case DINO_GMASK ... DINO_PCISTS: |
78 | case DINO_MLTIM ... DINO_PCIWOR: | |
79 | case DINO_TLTIM: | |
18092598 HD |
80 | ret = true; |
81 | break; | |
a72bd606 | 82 | case DINO_PCI_IO_DATA + 2: |
18092598 HD |
83 | ret = (size <= 2); |
84 | break; | |
a72bd606 HD |
85 | case DINO_PCI_IO_DATA + 1: |
86 | case DINO_PCI_IO_DATA + 3: | |
18092598 | 87 | ret = (size == 1); |
a72bd606 | 88 | } |
18092598 HD |
89 | trace_dino_chip_mem_valid(addr, ret); |
90 | return ret; | |
a72bd606 HD |
91 | } |
92 | ||
93 | static MemTxResult dino_chip_read_with_attrs(void *opaque, hwaddr addr, | |
94 | uint64_t *data, unsigned size, | |
95 | MemTxAttrs attrs) | |
96 | { | |
97 | DinoState *s = opaque; | |
ee313d5a | 98 | PCIHostState *phb = PCI_HOST_BRIDGE(s); |
a72bd606 HD |
99 | MemTxResult ret = MEMTX_OK; |
100 | AddressSpace *io; | |
101 | uint16_t ioaddr; | |
102 | uint32_t val; | |
103 | ||
104 | switch (addr) { | |
105 | case DINO_PCI_IO_DATA ... DINO_PCI_IO_DATA + 3: | |
106 | /* Read from PCI IO space. */ | |
107 | io = &address_space_io; | |
ee313d5a | 108 | ioaddr = phb->config_reg + (addr & 3); |
a72bd606 HD |
109 | switch (size) { |
110 | case 1: | |
111 | val = address_space_ldub(io, ioaddr, attrs, &ret); | |
112 | break; | |
113 | case 2: | |
114 | val = address_space_lduw_be(io, ioaddr, attrs, &ret); | |
115 | break; | |
116 | case 4: | |
117 | val = address_space_ldl_be(io, ioaddr, attrs, &ret); | |
118 | break; | |
119 | default: | |
120 | g_assert_not_reached(); | |
121 | } | |
122 | break; | |
123 | ||
18092598 HD |
124 | case DINO_IO_FBB_EN: |
125 | val = s->io_fbb_en; | |
126 | break; | |
a72bd606 HD |
127 | case DINO_IO_ADDR_EN: |
128 | val = s->io_addr_en; | |
129 | break; | |
130 | case DINO_IO_CONTROL: | |
131 | val = s->io_control; | |
132 | break; | |
133 | ||
134 | case DINO_IAR0: | |
135 | val = s->iar0; | |
136 | break; | |
137 | case DINO_IAR1: | |
138 | val = s->iar1; | |
139 | break; | |
140 | case DINO_IMR: | |
141 | val = s->imr; | |
142 | break; | |
143 | case DINO_ICR: | |
144 | val = s->icr; | |
145 | break; | |
146 | case DINO_IPR: | |
147 | val = s->ipr; | |
148 | /* Any read to IPR clears the register. */ | |
149 | s->ipr = 0; | |
150 | break; | |
151 | case DINO_ILR: | |
152 | val = s->ilr; | |
153 | break; | |
154 | case DINO_IRR0: | |
155 | val = s->ilr & s->imr & ~s->icr; | |
156 | break; | |
157 | case DINO_IRR1: | |
158 | val = s->ilr & s->imr & s->icr; | |
159 | break; | |
18092598 HD |
160 | case DINO_TOC_ADDR: |
161 | val = s->toc_addr; | |
162 | break; | |
163 | case DINO_GMASK ... DINO_TLTIM: | |
164 | val = s->reg800[(addr - DINO_GMASK) / 4]; | |
165 | if (addr == DINO_PAMR) { | |
166 | val &= ~0x01; /* LSB is hardwired to 0 */ | |
167 | } | |
168 | if (addr == DINO_MLTIM) { | |
169 | val &= ~0x07; /* 3 LSB are hardwired to 0 */ | |
170 | } | |
171 | if (addr == DINO_BRDG_FEAT) { | |
172 | val &= ~(0x10710E0ul | 8); /* bits 5-7, 24 & 15 reserved */ | |
173 | } | |
174 | break; | |
a72bd606 HD |
175 | |
176 | default: | |
177 | /* Controlled by dino_chip_mem_valid above. */ | |
178 | g_assert_not_reached(); | |
179 | } | |
180 | ||
18092598 | 181 | trace_dino_chip_read(addr, val); |
a72bd606 HD |
182 | *data = val; |
183 | return ret; | |
184 | } | |
185 | ||
186 | static MemTxResult dino_chip_write_with_attrs(void *opaque, hwaddr addr, | |
187 | uint64_t val, unsigned size, | |
188 | MemTxAttrs attrs) | |
189 | { | |
190 | DinoState *s = opaque; | |
ee313d5a | 191 | PCIHostState *phb = PCI_HOST_BRIDGE(s); |
a72bd606 HD |
192 | AddressSpace *io; |
193 | MemTxResult ret; | |
194 | uint16_t ioaddr; | |
18092598 HD |
195 | int i; |
196 | ||
197 | trace_dino_chip_write(addr, val); | |
a72bd606 HD |
198 | |
199 | switch (addr) { | |
200 | case DINO_IO_DATA ... DINO_PCI_IO_DATA + 3: | |
201 | /* Write into PCI IO space. */ | |
202 | io = &address_space_io; | |
ee313d5a | 203 | ioaddr = phb->config_reg + (addr & 3); |
a72bd606 HD |
204 | switch (size) { |
205 | case 1: | |
206 | address_space_stb(io, ioaddr, val, attrs, &ret); | |
207 | break; | |
208 | case 2: | |
209 | address_space_stw_be(io, ioaddr, val, attrs, &ret); | |
210 | break; | |
211 | case 4: | |
212 | address_space_stl_be(io, ioaddr, val, attrs, &ret); | |
213 | break; | |
214 | default: | |
215 | g_assert_not_reached(); | |
216 | } | |
217 | return ret; | |
218 | ||
18092598 HD |
219 | case DINO_IO_FBB_EN: |
220 | s->io_fbb_en = val & 0x03; | |
221 | break; | |
a72bd606 | 222 | case DINO_IO_ADDR_EN: |
18092598 | 223 | s->io_addr_en = val; |
a72bd606 HD |
224 | gsc_to_pci_forwarding(s); |
225 | break; | |
226 | case DINO_IO_CONTROL: | |
227 | s->io_control = val; | |
228 | gsc_to_pci_forwarding(s); | |
229 | break; | |
230 | ||
231 | case DINO_IAR0: | |
232 | s->iar0 = val; | |
233 | break; | |
234 | case DINO_IAR1: | |
235 | s->iar1 = val; | |
236 | break; | |
237 | case DINO_IMR: | |
238 | s->imr = val; | |
239 | break; | |
240 | case DINO_ICR: | |
241 | s->icr = val; | |
242 | break; | |
243 | case DINO_IPR: | |
244 | /* Any write to IPR clears the register. */ | |
245 | s->ipr = 0; | |
246 | break; | |
18092598 HD |
247 | case DINO_TOC_ADDR: |
248 | /* IO_COMMAND of CPU with client_id bits */ | |
249 | s->toc_addr = 0xFFFA0030 | (val & 0x1e000); | |
250 | break; | |
a72bd606 HD |
251 | |
252 | case DINO_ILR: | |
253 | case DINO_IRR0: | |
254 | case DINO_IRR1: | |
255 | /* These registers are read-only. */ | |
256 | break; | |
257 | ||
18092598 HD |
258 | case DINO_GMASK ... DINO_TLTIM: |
259 | i = (addr - DINO_GMASK) / 4; | |
260 | val &= reg800_keep_bits[i]; | |
261 | s->reg800[i] = val; | |
262 | break; | |
263 | ||
a72bd606 HD |
264 | default: |
265 | /* Controlled by dino_chip_mem_valid above. */ | |
266 | g_assert_not_reached(); | |
267 | } | |
268 | return MEMTX_OK; | |
269 | } | |
270 | ||
271 | static const MemoryRegionOps dino_chip_ops = { | |
272 | .read_with_attrs = dino_chip_read_with_attrs, | |
273 | .write_with_attrs = dino_chip_write_with_attrs, | |
274 | .endianness = DEVICE_BIG_ENDIAN, | |
275 | .valid = { | |
276 | .min_access_size = 1, | |
277 | .max_access_size = 4, | |
278 | .accepts = dino_chip_mem_valid, | |
279 | }, | |
280 | .impl = { | |
281 | .min_access_size = 1, | |
282 | .max_access_size = 4, | |
283 | }, | |
284 | }; | |
285 | ||
286 | static const VMStateDescription vmstate_dino = { | |
287 | .name = "Dino", | |
18092598 | 288 | .version_id = 2, |
a72bd606 HD |
289 | .minimum_version_id = 1, |
290 | .fields = (VMStateField[]) { | |
291 | VMSTATE_UINT32(iar0, DinoState), | |
292 | VMSTATE_UINT32(iar1, DinoState), | |
293 | VMSTATE_UINT32(imr, DinoState), | |
294 | VMSTATE_UINT32(ipr, DinoState), | |
295 | VMSTATE_UINT32(icr, DinoState), | |
296 | VMSTATE_UINT32(ilr, DinoState), | |
18092598 | 297 | VMSTATE_UINT32(io_fbb_en, DinoState), |
a72bd606 HD |
298 | VMSTATE_UINT32(io_addr_en, DinoState), |
299 | VMSTATE_UINT32(io_control, DinoState), | |
18092598 | 300 | VMSTATE_UINT32(toc_addr, DinoState), |
a72bd606 HD |
301 | VMSTATE_END_OF_LIST() |
302 | } | |
303 | }; | |
304 | ||
a72bd606 HD |
305 | /* Unlike pci_config_data_le_ops, no check of high bit set in config_reg. */ |
306 | ||
307 | static uint64_t dino_config_data_read(void *opaque, hwaddr addr, unsigned len) | |
308 | { | |
309 | PCIHostState *s = opaque; | |
310 | return pci_data_read(s->bus, s->config_reg | (addr & 3), len); | |
311 | } | |
312 | ||
313 | static void dino_config_data_write(void *opaque, hwaddr addr, | |
314 | uint64_t val, unsigned len) | |
315 | { | |
316 | PCIHostState *s = opaque; | |
317 | pci_data_write(s->bus, s->config_reg | (addr & 3), val, len); | |
318 | } | |
319 | ||
320 | static const MemoryRegionOps dino_config_data_ops = { | |
321 | .read = dino_config_data_read, | |
322 | .write = dino_config_data_write, | |
323 | .endianness = DEVICE_LITTLE_ENDIAN, | |
324 | }; | |
325 | ||
368bec88 SS |
326 | static uint64_t dino_config_addr_read(void *opaque, hwaddr addr, unsigned len) |
327 | { | |
18092598 HD |
328 | DinoState *s = opaque; |
329 | return s->config_reg_dino; | |
368bec88 SS |
330 | } |
331 | ||
332 | static void dino_config_addr_write(void *opaque, hwaddr addr, | |
333 | uint64_t val, unsigned len) | |
334 | { | |
335 | PCIHostState *s = opaque; | |
18092598 HD |
336 | DinoState *ds = opaque; |
337 | ds->config_reg_dino = val; /* keep a copy of original value */ | |
368bec88 SS |
338 | s->config_reg = val & ~3U; |
339 | } | |
340 | ||
341 | static const MemoryRegionOps dino_config_addr_ops = { | |
342 | .read = dino_config_addr_read, | |
343 | .write = dino_config_addr_write, | |
344 | .valid.min_access_size = 4, | |
345 | .valid.max_access_size = 4, | |
346 | .endianness = DEVICE_BIG_ENDIAN, | |
347 | }; | |
348 | ||
a72bd606 HD |
349 | static AddressSpace *dino_pcihost_set_iommu(PCIBus *bus, void *opaque, |
350 | int devfn) | |
351 | { | |
352 | DinoState *s = opaque; | |
353 | ||
354 | return &s->bm_as; | |
355 | } | |
356 | ||
357 | /* | |
358 | * Dino interrupts are connected as shown on Page 78, Table 23 | |
359 | * (Little-endian bit numbers) | |
360 | * 0 PCI INTA | |
361 | * 1 PCI INTB | |
362 | * 2 PCI INTC | |
363 | * 3 PCI INTD | |
364 | * 4 PCI INTE | |
365 | * 5 PCI INTF | |
366 | * 6 GSC External Interrupt | |
367 | * 7 Bus Error for "less than fatal" mode | |
368 | * 8 PS2 | |
369 | * 9 Unused | |
370 | * 10 RS232 | |
371 | */ | |
372 | ||
373 | static void dino_set_irq(void *opaque, int irq, int level) | |
374 | { | |
375 | DinoState *s = opaque; | |
376 | uint32_t bit = 1u << irq; | |
377 | uint32_t old_ilr = s->ilr; | |
378 | ||
379 | if (level) { | |
380 | uint32_t ena = bit & ~old_ilr; | |
381 | s->ipr |= ena; | |
382 | s->ilr = old_ilr | bit; | |
383 | if (ena & s->imr) { | |
384 | uint32_t iar = (ena & s->icr ? s->iar1 : s->iar0); | |
385 | stl_be_phys(&address_space_memory, iar & -32, iar & 31); | |
386 | } | |
387 | } else { | |
388 | s->ilr = old_ilr & ~bit; | |
389 | } | |
390 | } | |
391 | ||
392 | static int dino_pci_map_irq(PCIDevice *d, int irq_num) | |
393 | { | |
8d40def6 | 394 | int slot = PCI_SLOT(d->devfn); |
a72bd606 HD |
395 | |
396 | assert(irq_num >= 0 && irq_num <= 3); | |
397 | ||
4a4ff4c5 | 398 | return slot & 0x03; |
a72bd606 HD |
399 | } |
400 | ||
98d168f3 MCA |
401 | static void dino_pcihost_reset(DeviceState *dev) |
402 | { | |
403 | DinoState *s = DINO_PCI_HOST_BRIDGE(dev); | |
404 | ||
2fb11c7c | 405 | s->iar0 = s->iar1 = 0xFFFB0000 + 3; /* CPU_HPA + 3 */ |
98d168f3 MCA |
406 | s->toc_addr = 0xFFFA0030; /* IO_COMMAND of CPU */ |
407 | } | |
408 | ||
9cf69f44 MCA |
409 | static void dino_pcihost_realize(DeviceState *dev, Error **errp) |
410 | { | |
411 | DinoState *s = DINO_PCI_HOST_BRIDGE(dev); | |
412 | ||
a72bd606 | 413 | /* Set up PCI view of memory: Bus master address space. */ |
94c1253e | 414 | memory_region_init(&s->bm, OBJECT(s), "bm-dino", 4 * GiB); |
a72bd606 | 415 | memory_region_init_alias(&s->bm_ram_alias, OBJECT(s), |
9cf69f44 | 416 | "bm-system", s->memory_as, 0, |
a72bd606 HD |
417 | 0xf0000000 + DINO_MEM_CHUNK_SIZE); |
418 | memory_region_init_alias(&s->bm_pci_alias, OBJECT(s), | |
419 | "bm-pci", &s->pci_mem, | |
420 | 0xf0000000 + DINO_MEM_CHUNK_SIZE, | |
cb82c572 SS |
421 | 30 * DINO_MEM_CHUNK_SIZE); |
422 | memory_region_init_alias(&s->bm_cpu_alias, OBJECT(s), | |
9cf69f44 | 423 | "bm-cpu", s->memory_as, 0xfff00000, |
cb82c572 | 424 | 0xfffff); |
a72bd606 HD |
425 | memory_region_add_subregion(&s->bm, 0, |
426 | &s->bm_ram_alias); | |
427 | memory_region_add_subregion(&s->bm, | |
428 | 0xf0000000 + DINO_MEM_CHUNK_SIZE, | |
429 | &s->bm_pci_alias); | |
cb82c572 SS |
430 | memory_region_add_subregion(&s->bm, 0xfff00000, |
431 | &s->bm_cpu_alias); | |
9cf69f44 | 432 | |
a72bd606 | 433 | address_space_init(&s->bm_as, &s->bm, "pci-bm"); |
9cf69f44 | 434 | } |
a72bd606 | 435 | |
9cf69f44 MCA |
436 | static void dino_pcihost_unrealize(DeviceState *dev) |
437 | { | |
438 | DinoState *s = DINO_PCI_HOST_BRIDGE(dev); | |
a72bd606 | 439 | |
9cf69f44 | 440 | address_space_destroy(&s->bm_as); |
a72bd606 HD |
441 | } |
442 | ||
7cdfa941 MCA |
443 | static void dino_pcihost_init(Object *obj) |
444 | { | |
445 | DinoState *s = DINO_PCI_HOST_BRIDGE(obj); | |
446 | PCIHostState *phb = PCI_HOST_BRIDGE(obj); | |
447 | SysBusDevice *sbd = SYS_BUS_DEVICE(obj); | |
cc363c4a | 448 | int i; |
7cdfa941 MCA |
449 | |
450 | /* Dino PCI access from main memory. */ | |
451 | memory_region_init_io(&s->this_mem, OBJECT(s), &dino_chip_ops, | |
452 | s, "dino", 4096); | |
453 | ||
454 | /* Dino PCI config. */ | |
455 | memory_region_init_io(&phb->conf_mem, OBJECT(phb), | |
456 | &dino_config_addr_ops, DEVICE(s), | |
457 | "pci-conf-idx", 4); | |
458 | memory_region_init_io(&phb->data_mem, OBJECT(phb), | |
459 | &dino_config_data_ops, DEVICE(s), | |
460 | "pci-conf-data", 4); | |
461 | memory_region_add_subregion(&s->this_mem, DINO_PCI_CONFIG_ADDR, | |
462 | &phb->conf_mem); | |
463 | memory_region_add_subregion(&s->this_mem, DINO_CONFIG_DATA, | |
464 | &phb->data_mem); | |
465 | ||
63901b6c MCA |
466 | /* Dino PCI bus memory. */ |
467 | memory_region_init(&s->pci_mem, OBJECT(s), "pci-memory", 4 * GiB); | |
468 | ||
469 | phb->bus = pci_register_root_bus(DEVICE(s), "pci", | |
470 | dino_set_irq, dino_pci_map_irq, s, | |
471 | &s->pci_mem, get_system_io(), | |
472 | PCI_DEVFN(0, 0), 32, TYPE_PCI_BUS); | |
473 | ||
cc363c4a MCA |
474 | /* Set up windows into PCI bus memory. */ |
475 | for (i = 1; i < 31; i++) { | |
476 | uint32_t addr = 0xf0000000 + i * DINO_MEM_CHUNK_SIZE; | |
477 | char *name = g_strdup_printf("PCI Outbound Window %d", i); | |
478 | memory_region_init_alias(&s->pci_mem_alias[i], OBJECT(s), | |
479 | name, &s->pci_mem, addr, | |
480 | DINO_MEM_CHUNK_SIZE); | |
481 | g_free(name); | |
482 | } | |
483 | ||
5ac6c43c MCA |
484 | pci_setup_iommu(phb->bus, dino_pcihost_set_iommu, s); |
485 | ||
7cdfa941 | 486 | sysbus_init_mmio(sbd, &s->this_mem); |
4b5faaf9 MCA |
487 | |
488 | qdev_init_gpio_in(DEVICE(obj), dino_set_irq, DINO_IRQS); | |
7cdfa941 MCA |
489 | } |
490 | ||
270b2958 MCA |
491 | static Property dino_pcihost_properties[] = { |
492 | DEFINE_PROP_LINK("memory-as", DinoState, memory_as, TYPE_MEMORY_REGION, | |
493 | MemoryRegion *), | |
494 | DEFINE_PROP_END_OF_LIST(), | |
495 | }; | |
496 | ||
a72bd606 HD |
497 | static void dino_pcihost_class_init(ObjectClass *klass, void *data) |
498 | { | |
a72bd606 HD |
499 | DeviceClass *dc = DEVICE_CLASS(klass); |
500 | ||
98d168f3 | 501 | dc->reset = dino_pcihost_reset; |
9cf69f44 MCA |
502 | dc->realize = dino_pcihost_realize; |
503 | dc->unrealize = dino_pcihost_unrealize; | |
270b2958 | 504 | device_class_set_props(dc, dino_pcihost_properties); |
a72bd606 HD |
505 | dc->vmsd = &vmstate_dino; |
506 | } | |
507 | ||
508 | static const TypeInfo dino_pcihost_info = { | |
509 | .name = TYPE_DINO_PCI_HOST_BRIDGE, | |
510 | .parent = TYPE_PCI_HOST_BRIDGE, | |
7cdfa941 | 511 | .instance_init = dino_pcihost_init, |
a72bd606 HD |
512 | .instance_size = sizeof(DinoState), |
513 | .class_init = dino_pcihost_class_init, | |
514 | }; | |
515 | ||
516 | static void dino_register_types(void) | |
517 | { | |
518 | type_register_static(&dino_pcihost_info); | |
519 | } | |
520 | ||
521 | type_init(dino_register_types) |