/[gxemul]/trunk/src/devices/bus_pci.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Annotation of /trunk/src/devices/bus_pci.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 34 - (hide annotations)
Mon Oct 8 16:21:17 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 36662 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1480 2007/02/19 01:34:42 debug Exp $
20061029	Changing usleep(1) calls in the debugger to usleep(10000)
20061107	Adding a new disk image option (-d o...) which sets the ISO9660
		filesystem base offset; also making some other hacks to allow
		NetBSD/dreamcast and homebrew demos/games to boot directly
		from a filesystem image.
		Moving Dreamcast-specific stuff in the documentation to its
		own page (dreamcast.html).
		Adding a border to the Dreamcast PVR framebuffer.
20061108	Adding a -T command line option (again?), for halting the
		emulator on unimplemented memory accesses.
20061109	Continuing on various SH4 and Dreamcast related things.
		The emulator should now halt on more unimplemented device
		accesses, instead of just printing a warning, forcing me to
		actually implement missing stuff :)
20061111	Continuing on SH4 and Dreamcast stuff.
		Adding a bogus Landisk (SH4) machine mode.
20061112	Implementing some parts of the Dreamcast GDROM device. With
		some ugly hacks, NetBSD can (barely) mount an ISO image.
20061113	NetBSD/dreamcast now starts booting from the Live CD image,
		but crashes randomly quite early on in the boot process.
20061122	Beginning on a skeleton interrupt.h and interrupt.c for the
		new interrupt subsystem.
20061124	Continuing on the new interrupt system; taking the first steps
		to attempt to connect CPUs (SuperH and MIPS) and devices
		(dev_cons and SH4 timer interrupts) to it. Many things will
		probably break from now on.
20061125	Converting dev_ns16550, dev_8253 to the new interrupt system.
		Attempting to begin to convert the ISA bus.
20061130	Incorporating a patch from Brian Foley for the configure
		script, which checks for X11 libs in /usr/X11R6/lib64 (which
		is used on some Linux systems).
20061227	Adding a note in the man page about booting from Dreamcast
		CDROM images (i.e. that no external kernel is needed).
20061229	Continuing on the interrupt system rewrite: beginning to
		convert more devices, adding abort() calls for legacy interrupt
		system calls so that everything now _has_ to be rewritten!
		Almost all machine modes are now completely broken.
20061230	More progress on removing old interrupt code, mostly related
		to the ISA bus + devices, the LCA bus (on AlphaBook1), and
		the Footbridge bus (for CATS). And some minor PCI stuff.
		Connecting the ARM cpu to the new interrupt system.
		The CATS, NetWinder, and QEMU_MIPS machine modes now work with
		the new interrupt system :)
20061231	Connecting PowerPC CPUs to the new interrupt system.
		Making PReP machines (IBM 6050) work again.
		Beginning to convert the GT PCI controller (for e.g. Malta
		and Cobalt emulation). Some things work, but not everything.
		Updating Copyright notices for 2007.
20070101	Converting dev_kn02 from legacy style to devinit; the 3max
		machine mode now works with the new interrupt system :-]
20070105	Beginning to convert the SGI O2 machine to the new interrupt
		system; finally converting O2 (IP32) devices to devinit, etc.
20070106	Continuing on the interrupt system redesign/rewrite; KN01
		(PMAX), KN230, and Dreamcast ASIC interrupts should work again,
		moving out stuff from machine.h and devices.h into the
		corresponding devices, beginning the rewrite of i80321
		interrupts, etc.
20070107	Beginning on the rewrite of Eagle interrupt stuff (PReP, etc).
20070117	Beginning the rewrite of Algor (V3) interrupts (finally
		changing dev_v3 into devinit style).
20070118	Removing the "bus" registry concept from machine.h, because
		it was practically meaningless.
		Continuing on the rewrite of Algor V3 ISA interrupts.
20070121	More work on Algor interrupts; they are now working again,
		well enough to run NetBSD/algor. :-)
20070122	Converting VR41xx (HPCmips) interrupts. NetBSD/hpcmips
		can be installed using the new interrupt system :-)
20070123	Making the testmips mode work with the new interrupt system.
20070127	Beginning to convert DEC5800 devices to devinit, and to the
		new interrupt system.
		Converting Playstation 2 devices to devinit, and converting
		the interrupt system. Also fixing a severe bug: the interrupt
		mask register on Playstation 2 is bitwise _toggled_ on writes.
20070128	Removing the dummy NetGear machine mode and the 8250 device
		(which was only used by the NetGear machine).
		Beginning to convert the MacPPC GC (Grand Central) interrupt
		controller to the new interrupt system.
		Converting Jazz interrupts (PICA61 etc.) to the new interrupt
		system. NetBSD/arc can be installed again :-)
		Fixing the JAZZ timer (hardcoding it at 100 Hz, works with
		NetBSD and it is better than a completely dummy timer as it
		was before).
		Converting dev_mp to the new interrupt system, although I
		haven't had time to actually test it yet.
		Completely removing src/machines/interrupts.c, cpu_interrupt
		and cpu_interrupt_ack in src/cpu.c, and
		src/include/machine_interrupts.h! Adding fatal error messages
		+ abort() in the few places that are left to fix.
		Converting dev_z8530 to the new interrupt system.
		FINALLY removing the md_int struct completely from the
		machine struct.
		SH4 fixes (adding a PADDR invalidation in the ITLB replacement
		code in memory_sh.c); the NetBSD/dreamcast LiveCD now runs
		all the way to the login prompt, and can be interacted with :-)
		Converting the CPC700 controller (PCI and interrupt controller
		for PM/PPC) to the new interrupt system.
20070129	Fixing MACE ISA interrupts (SGI IP32 emulation). Both NetBSD/
		sgimips' and OpenBSD/sgi's ramdisk kernels can now be
		interacted with again.
20070130	Moving out the MIPS multi_lw and _sw instruction combinations
		so that they are auto-generated at compile time instead.
20070131	Adding detection of amd64/x86_64 hosts in the configure script,
		for doing initial experiments (again :-) with native code
		generation.
		Adding a -k command line option to set the size of the dyntrans
		cache, and a -B command line option to disable native code
		generation, even if GXemul was compiled with support for
		native code generation for the specific host CPU architecture.
20070201	Experimenting with a skeleton for native code generation.
		Changing the default behaviour, so that native code generation
		is now disabled by default, and has to be enabled by using
		-b on the command line.
20070202	Continuing the native code generation experiments.
		Making PCI interrupts work for Footbridge again.
20070203	More native code generation experiments.
		Removing most of the native code generation experimental code,
		it does not make sense to include any quick hacks like this.
		Minor cleanup/removal of some more legacy MIPS interrupt code.
20070204	Making i80321 interrupts work again (for NetBSD/evbarm etc.),
		and fixing the timer at 100 Hz.
20070206	Experimenting with removing the wdc interrupt slowness hack.
20070207	Lowering the number of dyntrans TLB entries for MIPS from
		192 to 128, resulting in a minor speed improvement.
		Minor optimization to the code invalidation routine in
		cpu_dyntrans.c.
20070208	Increasing (experimentally) the nr of dyntrans instructions per
		loop from 60 to 120.
20070210	Commenting out (experimentally) the dyntrans_device_danger
		detection in memory_rw.c.
		Changing the testmips and baremips machines to use a revision 2
		MIPS64 CPU by default, instead of revision 1.
		Removing the dummy i960, IA64, x86, AVR32, and HP PA-RISC
		files, the PC bios emulation, and the Olivetti M700 (ARC) and
		db64360 emulation modes.
20070211	Adding an "mp" demo to the demos directory, which tests the
		SMP functionality of the testmips machine.
		Fixing PReP interrupts some more. NetBSD/prep now boots again.
20070216	Adding a "nop workaround" for booting Mach/PMAX to the
		documentation; thanks to Artur Bujdoso for the values.
		Converting more of the MacPPC interrupt stuff to the new
		system.
		Beginning to convert BeBox interrupts to the new system.
		PPC603e should NOT have the PPC_NO_DEC flag! Removing it.
		Correcting BeBox clock speed (it was set to 100 in the NetBSD
		bootinfo block, but should be 33000000/4), allowing NetBSD
		to start without using the (incorrect) PPC_NO_DEC hack.
20070217	Implementing (slow) AltiVec vector loads and stores, allowing
		NetBSD/macppc to finally boot using the GENERIC kernel :-)
		Updating the documentation with install instructions for
		NetBSD/macppc.
20070218-19	Regression testing for the release.

==============  RELEASE 0.4.4  ==============


1 dpavlin 4 /*
2 dpavlin 34 * Copyright (C) 2004-2007 Anders Gavare. All rights reserved.
3 dpavlin 4 *
4     * Redistribution and use in source and binary forms, with or without
5     * modification, are permitted provided that the following conditions are met:
6     *
7     * 1. Redistributions of source code must retain the above copyright
8     * notice, this list of conditions and the following disclaimer.
9     * 2. Redistributions in binary form must reproduce the above copyright
10     * notice, this list of conditions and the following disclaimer in the
11     * documentation and/or other materials provided with the distribution.
12     * 3. The name of the author may not be used to endorse or promote products
13     * derived from this software without specific prior written permission.
14     *
15     * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16     * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18     * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19     * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20     * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21     * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24     * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25     * SUCH DAMAGE.
26     *
27     *
28 dpavlin 34 * $Id: bus_pci.c,v 1.80 2007/02/11 10:03:55 debug Exp $
29 dpavlin 4 *
30 dpavlin 20 * Generic PCI bus framework. This is not a normal "device", but is used by
31     * individual PCI controllers and devices.
32 dpavlin 4 *
33 dpavlin 20 * See NetBSD's pcidevs.h for more PCI vendor and device identifiers.
34     *
35     * TODO:
36     *
37     * x) Allow guest OSes to do runtime address fixups (i.e. actually
38     * move a device from one address to another).
39     *
40     * x) Generalize the PCI and legacy ISA interrupt routing stuff.
41     *
42     * x) Make sure that pci_little_endian is used correctly everywhere.
43 dpavlin 4 */
44    
45     #include <stdio.h>
46     #include <stdlib.h>
47     #include <string.h>
48    
49 dpavlin 20 #define BUS_PCI_C
50    
51 dpavlin 34 #include "bus_isa.h"
52 dpavlin 20 #include "bus_pci.h"
53     #include "cpu.h"
54     #include "device.h"
55     #include "devices.h"
56     #include "diskimage.h"
57     #include "machine.h"
58 dpavlin 4 #include "memory.h"
59     #include "misc.h"
60    
61 dpavlin 30 #include "wdc.h"
62    
63 dpavlin 20 extern int verbose;
64 dpavlin 4
65 dpavlin 20
66 dpavlin 24 #ifdef UNSTABLE_DEVEL
67     #define debug fatal
68     #endif
69 dpavlin 4
70 dpavlin 14
71 dpavlin 22 /*
72     * bus_pci_decompose_1():
73     *
74     * Helper function for decomposing Mechanism 1 tags.
75     */
76     void bus_pci_decompose_1(uint32_t t, int *bus, int *dev, int *func, int *reg)
77 dpavlin 20 {
78 dpavlin 22 *bus = (t >> 16) & 0xff;
79     *dev = (t >> 11) & 0x1f;
80     *func = (t >> 8) & 0x7;
81     *reg = t & 0xff;
82    
83     /* Warn about unaligned register access: */
84     if (t & 3)
85     fatal("[ bus_pci_decompose_1: WARNING: reg = 0x%02x ]\n",
86     t & 0xff);
87 dpavlin 20 }
88    
89    
90 dpavlin 4 /*
91 dpavlin 20 * bus_pci_data_access():
92     *
93 dpavlin 22 * Reads from or writes to the PCI configuration registers of a device.
94 dpavlin 20 */
95 dpavlin 22 void bus_pci_data_access(struct cpu *cpu, struct pci_data *pci_data,
96     uint64_t *data, int len, int writeflag)
97 dpavlin 20 {
98     struct pci_device *dev;
99     unsigned char *cfg_base;
100     uint64_t x, idata = *data;
101 dpavlin 22 int i;
102 dpavlin 20
103     /* Scan through the list of pci_device entries. */
104     dev = pci_data->first_device;
105     while (dev != NULL) {
106 dpavlin 22 if (dev->bus == pci_data->cur_bus &&
107     dev->function == pci_data->cur_func &&
108     dev->device == pci_data->cur_device)
109 dpavlin 20 break;
110     dev = dev->next;
111     }
112    
113     /* No device? Then return emptiness. */
114     if (dev == NULL) {
115 dpavlin 22 if (writeflag == MEM_READ) {
116     if (pci_data->cur_reg == 0)
117     *data = -1;
118     else
119     *data = 0;
120     } else {
121     fatal("[ bus_pci_data_access(): write to non-existant"
122     " device? ]\n");
123     }
124 dpavlin 20 return;
125     }
126    
127     /* Return normal config data, or length data? */
128     if (pci_data->last_was_write_ffffffff &&
129 dpavlin 22 pci_data->cur_reg >= PCI_MAPREG_START &&
130     pci_data->cur_reg <= PCI_MAPREG_END - 4)
131 dpavlin 20 cfg_base = dev->cfg_mem_size;
132     else
133     cfg_base = dev->cfg_mem;
134    
135     /* Read data as little-endian: */
136     x = 0;
137 dpavlin 22 for (i=len-1; i>=0; i--) {
138     int ofs = pci_data->cur_reg + i;
139     x <<= 8;
140     x |= cfg_base[ofs & (PCI_CFG_MEM_SIZE - 1)];
141 dpavlin 20 }
142    
143     /* Register write: */
144     if (writeflag == MEM_WRITE) {
145 dpavlin 22 debug("[ bus_pci: write to PCI DATA: data = 0x%08llx ]\n",
146 dpavlin 20 (long long)idata);
147 dpavlin 22 if (idata == 0xffffffffULL &&
148     pci_data->cur_reg >= PCI_MAPREG_START &&
149     pci_data->cur_reg <= PCI_MAPREG_END - 4) {
150 dpavlin 20 pci_data->last_was_write_ffffffff = 1;
151     return;
152     }
153 dpavlin 30
154     if (dev->cfg_reg_write != NULL) {
155     dev->cfg_reg_write(dev, pci_data->cur_reg, *data);
156     } else {
157     /* Print a warning for unhandled writes: */
158 dpavlin 20 debug("[ bus_pci: write to PCI DATA: data = 0x%08llx"
159 dpavlin 30 " (current value = 0x%08llx); NOT YET"
160 dpavlin 20 " SUPPORTED. bus %i, device %i, function %i (%s)"
161     " register 0x%02x ]\n", (long long)idata,
162 dpavlin 22 (long long)x, pci_data->cur_bus,
163     pci_data->cur_device, pci_data->cur_func,
164     dev->name, pci_data->cur_reg);
165 dpavlin 30
166     /* Special warning, to detect if NetBSD's special
167     detection of PCI devices fails: */
168     if (pci_data->cur_reg == PCI_COMMAND_STATUS_REG
169     && !((*data) & PCI_COMMAND_IO_ENABLE)) {
170     fatal("\n[ NetBSD PCI detection stuff not"
171     " yet implemented for device '%s' ]\n",
172     dev->name);
173     }
174 dpavlin 20 }
175     return;
176     }
177    
178     /* Register read: */
179     *data = x;
180    
181     pci_data->last_was_write_ffffffff = 0;
182    
183 dpavlin 22 debug("[ bus_pci: read from PCI DATA, bus %i, device "
184 dpavlin 24 "%i, function %i (%s) register 0x%02x: (len=%i) 0x%08lx ]\n",
185     pci_data->cur_bus, pci_data->cur_device, pci_data->cur_func,
186     dev->name, pci_data->cur_reg, len, (long)*data);
187 dpavlin 20 }
188    
189    
190     /*
191 dpavlin 22 * bus_pci_setaddr():
192 dpavlin 4 *
193 dpavlin 22 * Sets the address in preparation for a PCI register transfer.
194 dpavlin 4 */
195 dpavlin 22 void bus_pci_setaddr(struct cpu *cpu, struct pci_data *pci_data,
196     int bus, int device, int function, int reg)
197 dpavlin 4 {
198 dpavlin 22 if (cpu == NULL || pci_data == NULL) {
199     fatal("bus_pci_setaddr(): NULL ptr\n");
200     exit(1);
201 dpavlin 4 }
202    
203 dpavlin 22 pci_data->cur_bus = bus;
204     pci_data->cur_device = device;
205     pci_data->cur_func = function;
206     pci_data->cur_reg = reg;
207 dpavlin 4 }
208    
209    
210     /*
211     * bus_pci_add():
212     *
213     * Add a PCI device to a bus_pci device.
214     */
215     void bus_pci_add(struct machine *machine, struct pci_data *pci_data,
216     struct memory *mem, int bus, int device, int function,
217 dpavlin 22 const char *name)
218 dpavlin 4 {
219 dpavlin 20 struct pci_device *pd;
220     int ofs;
221     void (*init)(struct machine *, struct memory *, struct pci_device *);
222 dpavlin 4
223 dpavlin 14 if (pci_data == NULL) {
224     fatal("bus_pci_add(): pci_data == NULL!\n");
225 dpavlin 34 abort();
226 dpavlin 14 }
227    
228 dpavlin 20 /* Find the PCI device: */
229     init = pci_lookup_initf(name);
230    
231 dpavlin 4 /* Make sure this bus/device/function number isn't already in use: */
232 dpavlin 20 pd = pci_data->first_device;
233     while (pd != NULL) {
234     if (pd->bus == bus && pd->device == device &&
235     pd->function == function) {
236 dpavlin 4 fatal("bus_pci_add(): (bus %i, device %i, function"
237     " %i) already in use\n", bus, device, function);
238 dpavlin 20 exit(1);
239 dpavlin 4 }
240 dpavlin 20 pd = pd->next;
241 dpavlin 4 }
242    
243 dpavlin 20 pd = malloc(sizeof(struct pci_device));
244     if (pd == NULL) {
245 dpavlin 4 fprintf(stderr, "out of memory\n");
246     exit(1);
247     }
248    
249 dpavlin 20 memset(pd, 0, sizeof(struct pci_device));
250 dpavlin 4
251     /* Add the new device first in the PCI bus' chain: */
252 dpavlin 20 pd->next = pci_data->first_device;
253     pci_data->first_device = pd;
254 dpavlin 4
255 dpavlin 20 pd->pcibus = pci_data;
256     pd->name = strdup(name);
257     pd->bus = bus;
258     pd->device = device;
259     pd->function = function;
260    
261     /*
262     * Initialize with some default values:
263     *
264 dpavlin 22 * TODO: The command status register is best to set up per device.
265     * The size registers should also be set up on a per-device basis.
266 dpavlin 20 */
267 dpavlin 22 PCI_SET_DATA(PCI_COMMAND_STATUS_REG,
268     PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE);
269 dpavlin 20 for (ofs = PCI_MAPREG_START; ofs < PCI_MAPREG_END; ofs += 4)
270 dpavlin 22 PCI_SET_DATA_SIZE(ofs, 0x00100000 - 1);
271 dpavlin 20
272     if (init == NULL) {
273     fatal("No init function for PCI device \"%s\"?\n", name);
274     exit(1);
275     }
276    
277 dpavlin 4 /* Call the PCI device' init function: */
278 dpavlin 20 init(machine, mem, pd);
279 dpavlin 4 }
280    
281    
282     /*
283 dpavlin 20 * allocate_device_space():
284     *
285     * Used by glue code (see below) to allocate space for a PCI device.
286     *
287     * The returned values in portp and memp are the actual (emulated) addresses
288     * that the device should use. (Normally only one of these is actually used.)
289     *
290     * TODO: PCI irqs?
291     */
292     static void allocate_device_space(struct pci_device *pd,
293     uint64_t portsize, uint64_t memsize,
294     uint64_t *portp, uint64_t *memp)
295     {
296     uint64_t port, mem;
297    
298     /* Calculate an aligned starting port: */
299     port = pd->pcibus->cur_pci_portbase;
300     if (portsize != 0) {
301     port = ((port - 1) | (portsize - 1)) + 1;
302     pd->pcibus->cur_pci_portbase = port;
303 dpavlin 22 PCI_SET_DATA(PCI_MAPREG_START + pd->cur_mapreg_offset,
304     port | PCI_MAPREG_TYPE_IO);
305     PCI_SET_DATA_SIZE(PCI_MAPREG_START + pd->cur_mapreg_offset,
306 dpavlin 24 ((portsize - 1) & ~0xf) | 0xd);
307 dpavlin 22 pd->cur_mapreg_offset += sizeof(uint32_t);
308 dpavlin 20 }
309    
310     /* Calculate an aligned starting memory location: */
311     mem = pd->pcibus->cur_pci_membase;
312     if (memsize != 0) {
313     mem = ((mem - 1) | (memsize - 1)) + 1;
314     pd->pcibus->cur_pci_membase = mem;
315 dpavlin 22 PCI_SET_DATA(PCI_MAPREG_START + pd->cur_mapreg_offset, mem);
316     PCI_SET_DATA_SIZE(PCI_MAPREG_START + pd->cur_mapreg_offset,
317 dpavlin 24 ((memsize - 1) & ~0xf) | 0x0);
318 dpavlin 22 pd->cur_mapreg_offset += sizeof(uint32_t);
319 dpavlin 20 }
320    
321     *portp = port + pd->pcibus->pci_actual_io_offset;
322     *memp = mem + pd->pcibus->pci_actual_mem_offset;
323    
324     if (verbose >= 2) {
325     debug("pci device '%s' at", pd->name);
326     if (portsize != 0)
327     debug(" port 0x%llx-0x%llx", (long long)pd->pcibus->
328     cur_pci_portbase, (long long)(pd->pcibus->
329     cur_pci_portbase + portsize - 1));
330     if (memsize != 0)
331     debug(" mem 0x%llx-0x%llx", (long long)pd->pcibus->
332     cur_pci_membase, (long long)(pd->pcibus->
333     cur_pci_membase + memsize - 1));
334     debug("\n");
335     }
336    
337     pd->pcibus->cur_pci_portbase += portsize;
338     pd->pcibus->cur_pci_membase += memsize;
339     }
340    
341    
342     /*
343 dpavlin 4 * bus_pci_init():
344     *
345     * This doesn't register a device, but instead returns a pointer to a struct
346 dpavlin 22 * which should be passed to other bus_pci functions when accessing the bus.
347 dpavlin 20 *
348 dpavlin 34 * irq_path is the interrupt path to the PCI controller.
349 dpavlin 20 *
350     * pci_portbase, pci_membase, and pci_irqbase are the port, memory, and
351     * interrupt bases for PCI devices (as found in the configuration registers).
352     *
353     * pci_actual_io_offset and pci_actual_mem_offset are the offset from
354     * the values in the configuration registers to the actual (emulated) device.
355     *
356     * isa_portbase, isa_membase, and isa_irqbase are the port, memory, and
357     * interrupt bases for legacy ISA devices.
358 dpavlin 4 */
359 dpavlin 34 struct pci_data *bus_pci_init(struct machine *machine, char *irq_path,
360 dpavlin 20 uint64_t pci_actual_io_offset, uint64_t pci_actual_mem_offset,
361 dpavlin 34 uint64_t pci_portbase, uint64_t pci_membase, char *pci_irqbase,
362     uint64_t isa_portbase, uint64_t isa_membase, char *isa_irqbase)
363 dpavlin 4 {
364     struct pci_data *d;
365    
366     d = malloc(sizeof(struct pci_data));
367     if (d == NULL) {
368     fprintf(stderr, "out of memory\n");
369     exit(1);
370     }
371     memset(d, 0, sizeof(struct pci_data));
372 dpavlin 34
373     d->irq_path = strdup(irq_path);
374     d->irq_path_isa = strdup(isa_irqbase);
375     d->irq_path_pci = strdup(pci_irqbase);
376    
377 dpavlin 20 d->pci_actual_io_offset = pci_actual_io_offset;
378     d->pci_actual_mem_offset = pci_actual_mem_offset;
379     d->pci_portbase = pci_portbase;
380     d->pci_membase = pci_membase;
381     d->isa_portbase = isa_portbase;
382     d->isa_membase = isa_membase;
383 dpavlin 4
384 dpavlin 20 /* Assume that the first 64KB could be used by legacy ISA devices: */
385     d->cur_pci_portbase = d->pci_portbase + 0x10000;
386     d->cur_pci_membase = d->pci_membase + 0x10000;
387    
388 dpavlin 4 return d;
389     }
390    
391 dpavlin 20
392    
393     /******************************************************************************
394 dpavlin 22 * *
395     * The following is glue code for PCI controllers and devices. The glue *
396     * code does the minimal stuff necessary to get an emulated OS to detect *
397     * the device (i.e. set up PCI configuration registers), and then if *
398     * necessary adds a "normal" device. *
399     * *
400 dpavlin 20 ******************************************************************************/
401    
402    
403    
404     /*
405 dpavlin 30 * Integraphics Systems "igsfb" Framebuffer (graphics) card, used in at
406     * least the NetWinder.
407 dpavlin 20 */
408    
409     #define PCI_VENDOR_INTEGRAPHICS 0x10ea
410    
411     PCIINIT(igsfb)
412     {
413 dpavlin 30 char tmpstr[200];
414    
415 dpavlin 20 PCI_SET_DATA(PCI_ID_REG,
416     PCI_ID_CODE(PCI_VENDOR_INTEGRAPHICS, 0x2010));
417    
418     PCI_SET_DATA(PCI_CLASS_REG,
419     PCI_CLASS_CODE(PCI_CLASS_DISPLAY,
420     PCI_SUBCLASS_DISPLAY_VGA, 0) + 0x01);
421    
422     /* TODO */
423 dpavlin 22 PCI_SET_DATA(0x10, 0x08000000);
424 dpavlin 20
425 dpavlin 30 snprintf(tmpstr, sizeof(tmpstr), "igsfb addr=0x%llx",
426     (long long)(pd->pcibus->isa_membase + 0x08000000));
427     device_add(machine, tmpstr);
428 dpavlin 20 }
429    
430    
431    
432     /*
433     * S3 ViRGE graphics.
434     *
435     * TODO: Only emulates a standard VGA card, so far.
436     */
437    
438     #define PCI_VENDOR_S3 0x5333
439     #define PCI_PRODUCT_S3_VIRGE 0x5631
440     #define PCI_PRODUCT_S3_VIRGE_DX 0x8a01
441    
442     PCIINIT(s3_virge)
443     {
444     PCI_SET_DATA(PCI_ID_REG,
445     PCI_ID_CODE(PCI_VENDOR_S3, PCI_PRODUCT_S3_VIRGE_DX));
446    
447     PCI_SET_DATA(PCI_CLASS_REG,
448     PCI_CLASS_CODE(PCI_CLASS_DISPLAY,
449     PCI_SUBCLASS_DISPLAY_VGA, 0) + 0x01);
450    
451     dev_vga_init(machine, mem, pd->pcibus->isa_membase + 0xa0000,
452     pd->pcibus->isa_portbase + 0x3c0, machine->machine_name);
453     }
454    
455    
456    
457     /*
458     * Acer Labs M5229 PCI-IDE (UDMA) controller.
459     * Acer Labs M1543 PCI->ISA bridge.
460     */
461    
462     #define PCI_VENDOR_ALI 0x10b9
463     #define PCI_PRODUCT_ALI_M1543 0x1533 /* NOTE: not 1543 */
464     #define PCI_PRODUCT_ALI_M5229 0x5229
465    
466     PCIINIT(ali_m1543)
467     {
468     PCI_SET_DATA(PCI_ID_REG,
469     PCI_ID_CODE(PCI_VENDOR_ALI, PCI_PRODUCT_ALI_M1543));
470    
471     PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_BRIDGE,
472     PCI_SUBCLASS_BRIDGE_ISA, 0) + 0xc3);
473    
474     PCI_SET_DATA(PCI_BHLC_REG,
475     PCI_BHLC_CODE(0,0, 1 /* multi-function */, 0x40,0));
476    
477     /* Linux uses these to detect which IRQ the IDE controller uses: */
478     PCI_SET_DATA(0x44, 0x0000000e);
479     PCI_SET_DATA(0x58, 0x00000003);
480 dpavlin 34
481     switch (machine->machine_type) {
482     case MACHINE_CATS:
483     bus_isa_init(machine, pd->pcibus->irq_path_isa,
484     BUS_ISA_PCKBC_FORCE_USE | BUS_ISA_PCKBC_NONPCSTYLE,
485     0x7c000000, 0x80000000);
486     break;
487     default:fatal("ali_m1543 init: unimplemented machine type\n");
488     exit(1);
489     }
490 dpavlin 20 }
491    
492     PCIINIT(ali_m5229)
493     {
494 dpavlin 34 char tmpstr[300], irqstr[300];
495 dpavlin 20
496     PCI_SET_DATA(PCI_ID_REG,
497     PCI_ID_CODE(PCI_VENDOR_ALI, PCI_PRODUCT_ALI_M5229));
498    
499     PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_MASS_STORAGE,
500     PCI_SUBCLASS_MASS_STORAGE_IDE, 0x60) + 0xc1);
501    
502 dpavlin 34 switch (machine->machine_type) {
503     case MACHINE_CATS:
504     /* CATS ISA interrupts are at footbridge irq 10: */
505     snprintf(irqstr, sizeof(irqstr), "%s.10.isa",
506     pd->pcibus->irq_path);
507     break;
508     default:fatal("ali_m5229 init: unimplemented machine type\n");
509     exit(1);
510     }
511    
512 dpavlin 20 if (diskimage_exist(machine, 0, DISKIMAGE_IDE) ||
513     diskimage_exist(machine, 1, DISKIMAGE_IDE)) {
514 dpavlin 34 snprintf(tmpstr, sizeof(tmpstr), "wdc addr=0x%llx irq=%s.%i",
515 dpavlin 20 (long long)(pd->pcibus->isa_portbase + 0x1f0),
516 dpavlin 34 irqstr, 14);
517 dpavlin 20 device_add(machine, tmpstr);
518     }
519    
520     /* The secondary channel is disabled. TODO: fix this. */
521     }
522    
523    
524    
525     /*
526     * Adaptec AHC SCSI controller.
527     */
528    
529     #define PCI_VENDOR_ADP 0x9004 /* Adaptec */
530     #define PCI_VENDOR_ADP2 0x9005 /* Adaptec (2nd PCI Vendor ID) */
531     #define PCI_PRODUCT_ADP_2940U 0x8178 /* AHA-2940 Ultra */
532     #define PCI_PRODUCT_ADP_2940UP 0x8778 /* AHA-2940 Ultra Pro */
533    
534     PCIINIT(ahc)
535     {
536     /* Numbers taken from a Adaptec 2940U: */
537     /* http://mail-index.netbsd.org/netbsd-bugs/2000/04/29/0000.html */
538    
539     PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_ADP,
540     PCI_PRODUCT_ADP_2940U));
541    
542     PCI_SET_DATA(PCI_COMMAND_STATUS_REG, 0x02900007);
543    
544     PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_MASS_STORAGE,
545     PCI_SUBCLASS_MASS_STORAGE_SCSI, 0) + 0x01);
546    
547     PCI_SET_DATA(PCI_BHLC_REG, 0x00004008);
548    
549     /* 1 = type i/o. 0x0000e801; address? */
550     /* second address reg = 0xf1002000? */
551     PCI_SET_DATA(PCI_MAPREG_START + 0x00, 0x00000001);
552     PCI_SET_DATA(PCI_MAPREG_START + 0x04, 0x00000000);
553    
554     PCI_SET_DATA(PCI_MAPREG_START + 0x08, 0x00000000);
555     PCI_SET_DATA(PCI_MAPREG_START + 0x0c, 0x00000000);
556     PCI_SET_DATA(PCI_MAPREG_START + 0x10, 0x00000000);
557     PCI_SET_DATA(PCI_MAPREG_START + 0x14, 0x00000000);
558     PCI_SET_DATA(PCI_MAPREG_START + 0x18, 0x00000000);
559    
560     /* Subsystem vendor ID? 0x78819004? */
561     PCI_SET_DATA(PCI_MAPREG_START + 0x1c, 0x00000000);
562    
563     PCI_SET_DATA(0x30, 0xef000000);
564     PCI_SET_DATA(PCI_CAPLISTPTR_REG, 0x000000dc);
565     PCI_SET_DATA(0x38, 0x00000000);
566     PCI_SET_DATA(PCI_INTERRUPT_REG, 0x08080109); /* interrupt pin A */
567    
568     /*
569     * TODO: this address is based on what NetBSD/sgimips uses
570     * on SGI IP32 (O2). Fix this!
571     */
572    
573     device_add(machine, "ahc addr=0x18000000");
574    
575     /* OpenBSD/sgi snapshots sometime between 2005-03-11 and
576     2005-04-04 changed to using 0x1a000000: */
577     dev_ram_init(machine, 0x1a000000, 0x2000000, DEV_RAM_MIRROR,
578     0x18000000);
579     }
580    
581    
582    
583     /*
584     * Galileo Technology GT-64xxx PCI controller.
585     *
586     * GT-64011 Used in Cobalt machines.
587     * GT-64120 Used in evbmips machines (Malta).
588     *
589     * NOTE: This works in the opposite way compared to other devices; the PCI
590     * device is added from the normal device instead of the other way around.
591     */
592    
593     #define PCI_VENDOR_GALILEO 0x11ab /* Galileo Technology */
594     #define PCI_PRODUCT_GALILEO_GT64011 0x4146 /* GT-64011 System Controller */
595     #define PCI_PRODUCT_GALILEO_GT64120 0x4620 /* GT-64120 */
596 dpavlin 22 #define PCI_PRODUCT_GALILEO_GT64260 0x6430 /* GT-64260 */
597 dpavlin 20
598     PCIINIT(gt64011)
599     {
600     PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_GALILEO,
601     PCI_PRODUCT_GALILEO_GT64011));
602    
603 dpavlin 22 PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_BRIDGE,
604 dpavlin 20 PCI_SUBCLASS_BRIDGE_HOST, 0) + 0x01); /* Revision 1 */
605     }
606    
607     PCIINIT(gt64120)
608     {
609     PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_GALILEO,
610     PCI_PRODUCT_GALILEO_GT64120));
611    
612     PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_BRIDGE,
613     PCI_SUBCLASS_BRIDGE_HOST, 0) + 0x02); /* Revision 2? */
614    
615     switch (machine->machine_type) {
616     case MACHINE_EVBMIPS:
617     PCI_SET_DATA(PCI_MAPREG_START + 0x10, 0x1be00000);
618     break;
619     }
620     }
621    
622 dpavlin 22 PCIINIT(gt64260)
623     {
624     PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_GALILEO,
625     PCI_PRODUCT_GALILEO_GT64260));
626 dpavlin 20
627 dpavlin 22 PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_BRIDGE,
628     PCI_SUBCLASS_BRIDGE_HOST, 0) + 0x01); /* Revision 1? */
629     }
630 dpavlin 20
631 dpavlin 22
632    
633 dpavlin 20 /*
634 dpavlin 30 * AMD PCnet Ethernet card.
635     *
636     * "Am79c970A PCnet-PCI II rev 0" or similar.
637     */
638    
639     #define PCI_VENDOR_AMD 0x1022 /* Advanced Micro Devices */
640     #define PCI_PRODUCT_AMD_PCNET_PCI 0x2000 /* PCnet-PCI Ethernet */
641    
642     PCIINIT(pcn)
643     {
644     int irq;
645    
646     PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_AMD,
647     PCI_PRODUCT_AMD_PCNET_PCI));
648    
649     PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_NETWORK,
650     PCI_SUBCLASS_NETWORK_ETHERNET, 0) + 0x00); /* Revision 0 */
651    
652     switch (machine->machine_type) {
653    
654     case MACHINE_EVBMIPS:
655     irq = (1 << 8) + 10; /* TODO */
656     break;
657    
658     default:fatal("pcn in non-implemented machine type %i\n",
659     machine->machine_type);
660     exit(1);
661     }
662    
663     PCI_SET_DATA(PCI_INTERRUPT_REG, 0x01100000 | irq);
664    
665     /*
666     * TODO: Add the pcn device here. The pcn device will need to work as
667     * a wrapper for dev_le + all the DMA magic and whatever is required.
668     * It's too much to implement right now.
669     */
670     }
671    
672    
673    
674     /*
675 dpavlin 22 * Intel 31244 Serial ATA Controller
676     * Intel 82371SB PIIX3 PCI-ISA bridge
677     * Intel 82371AB PIIX4 PCI-ISA bridge
678     * Intel 82371SB IDE controller
679     * Intel 82371AB IDE controller
680     * Intel 82378ZB System I/O controller.
681 dpavlin 20 */
682    
683     #define PCI_VENDOR_INTEL 0x8086
684 dpavlin 22 #define PCI_PRODUCT_INTEL_31244 0x3200
685     #define PCI_PRODUCT_INTEL_82371SB_ISA 0x7000
686     #define PCI_PRODUCT_INTEL_82371SB_IDE 0x7010
687 dpavlin 20 #define PCI_PRODUCT_INTEL_82371AB_ISA 0x7110
688     #define PCI_PRODUCT_INTEL_82371AB_IDE 0x7111
689     #define PCI_PRODUCT_INTEL_SIO 0x0484
690    
691 dpavlin 22 PCIINIT(i31244)
692 dpavlin 20 {
693 dpavlin 22 uint64_t port, memaddr;
694 dpavlin 24 int irq = 0;
695 dpavlin 22
696 dpavlin 20 PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_INTEL,
697 dpavlin 22 PCI_PRODUCT_INTEL_31244));
698    
699     PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_MASS_STORAGE,
700     PCI_SUBCLASS_MASS_STORAGE_IDE, 0x33) + 0x00);
701    
702     switch (machine->machine_type) {
703     case MACHINE_IQ80321:
704 dpavlin 24 /* S-PCI-X slot uses PCI IRQ A, int 29 */
705     irq = (1 << 8) + 29;
706 dpavlin 22 break;
707     default:fatal("i31244 in non-implemented machine type %i\n",
708     machine->machine_type);
709     exit(1);
710     }
711    
712 dpavlin 24 PCI_SET_DATA(PCI_INTERRUPT_REG, 0x01100000 | irq);
713 dpavlin 22
714 dpavlin 24 allocate_device_space(pd, 0x1000, 0, &port, &memaddr);
715     allocate_device_space(pd, 0x1000, 0, &port, &memaddr);
716 dpavlin 22
717     /* PCI IDE using dev_wdc: */
718     if (diskimage_exist(machine, 0, DISKIMAGE_IDE) ||
719     diskimage_exist(machine, 1, DISKIMAGE_IDE)) {
720     char tmpstr[150];
721 dpavlin 34 snprintf(tmpstr, sizeof(tmpstr), "wdc addr=0x%llx irq=%s.%i",
722 dpavlin 22 (long long)(pd->pcibus->pci_actual_io_offset + 0),
723 dpavlin 34 pd->pcibus->irq_path_pci, irq & 255);
724 dpavlin 22 device_add(machine, tmpstr);
725     }
726     }
727    
728     PCIINIT(piix3_isa)
729     {
730     PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_INTEL,
731     PCI_PRODUCT_INTEL_82371SB_ISA));
732    
733     PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_BRIDGE,
734     PCI_SUBCLASS_BRIDGE_ISA, 0) + 0x01); /* Rev 1 */
735    
736     PCI_SET_DATA(PCI_BHLC_REG,
737     PCI_BHLC_CODE(0,0, 1 /* multi-function */, 0x40,0));
738     }
739    
740     PCIINIT(piix4_isa)
741     {
742     PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_INTEL,
743 dpavlin 20 PCI_PRODUCT_INTEL_82371AB_ISA));
744    
745     PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_BRIDGE,
746     PCI_SUBCLASS_BRIDGE_ISA, 0) + 0x01); /* Rev 1 */
747    
748     PCI_SET_DATA(PCI_BHLC_REG,
749     PCI_BHLC_CODE(0,0, 1 /* multi-function */, 0x40,0));
750     }
751    
752     PCIINIT(i82378zb)
753     {
754     PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_INTEL,
755     PCI_PRODUCT_INTEL_SIO));
756    
757     PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_BRIDGE,
758     PCI_SUBCLASS_BRIDGE_ISA, 0) + 0x43);
759    
760     PCI_SET_DATA(PCI_BHLC_REG,
761     PCI_BHLC_CODE(0,0, 1 /* multi-function */, 0x40,0));
762 dpavlin 22
763     PCI_SET_DATA(0x40, 0x20);
764    
765     /* PIRQ[0]=10 PIRQ[1]=11 PIRQ[2]=14 PIRQ[3]=15 */
766     PCI_SET_DATA(0x60, 0x0f0e0b0a);
767 dpavlin 20 }
768    
769 dpavlin 30 struct piix_ide_extra {
770     void *wdc0;
771     void *wdc1;
772     };
773    
774     int piix_ide_cfg_reg_write(struct pci_device *pd, int reg, uint32_t value)
775     {
776     void *wdc0 = ((struct piix_ide_extra *)pd->extra)->wdc0;
777     void *wdc1 = ((struct piix_ide_extra *)pd->extra)->wdc1;
778     int enabled = 0;
779    
780     switch (reg) {
781     case PCI_COMMAND_STATUS_REG:
782     if (value & PCI_COMMAND_IO_ENABLE)
783     enabled = 1;
784     if (wdc0 != NULL)
785     wdc_set_io_enabled(wdc0, enabled);
786     if (wdc1 != NULL)
787     wdc_set_io_enabled(wdc1, enabled);
788     return 1;
789     }
790    
791     return 0;
792     }
793    
794 dpavlin 22 PCIINIT(piix3_ide)
795 dpavlin 20 {
796     char tmpstr[100];
797    
798     PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_INTEL,
799 dpavlin 22 PCI_PRODUCT_INTEL_82371SB_IDE));
800    
801     /* Possibly not correct: */
802     PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_MASS_STORAGE,
803     PCI_SUBCLASS_MASS_STORAGE_IDE, 0x00) + 0x00);
804    
805     /* PIIX_IDETIM (see NetBSD's pciide_piix_reg.h) */
806     /* channel 0 and 1 enabled as IDE */
807     PCI_SET_DATA(0x40, 0x80008000);
808    
809 dpavlin 30 pd->extra = malloc(sizeof(struct piix_ide_extra));
810     if (pd->extra == NULL) {
811     fatal("Out of memory.\n");
812     exit(1);
813     }
814     ((struct piix_ide_extra *)pd->extra)->wdc0 = NULL;
815     ((struct piix_ide_extra *)pd->extra)->wdc1 = NULL;
816    
817 dpavlin 22 if (diskimage_exist(machine, 0, DISKIMAGE_IDE) ||
818     diskimage_exist(machine, 1, DISKIMAGE_IDE)) {
819 dpavlin 34 snprintf(tmpstr, sizeof(tmpstr), "wdc addr=0x%llx "
820     "irq=%s.isa.%i", (long long)(pd->pcibus->isa_portbase +
821     0x1f0), pd->pcibus->irq_path_isa, 14);
822 dpavlin 30 ((struct piix_ide_extra *)pd->extra)->wdc0 =
823     device_add(machine, tmpstr);
824 dpavlin 22 }
825    
826     if (diskimage_exist(machine, 2, DISKIMAGE_IDE) ||
827     diskimage_exist(machine, 3, DISKIMAGE_IDE)) {
828 dpavlin 34 snprintf(tmpstr, sizeof(tmpstr), "wdc addr=0x%llx "
829     "irq=%s.isa.%i", (long long)(pd->pcibus->isa_portbase +
830     0x170), pd->pcibus->irq_path_isa, 15);
831 dpavlin 30 ((struct piix_ide_extra *)pd->extra)->wdc1 =
832     device_add(machine, tmpstr);
833 dpavlin 22 }
834 dpavlin 30
835     pd->cfg_reg_write = piix_ide_cfg_reg_write;
836 dpavlin 22 }
837    
838     PCIINIT(piix4_ide)
839     {
840     char tmpstr[100];
841    
842     PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_INTEL,
843 dpavlin 20 PCI_PRODUCT_INTEL_82371AB_IDE));
844    
845     /* Possibly not correct: */
846     PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_MASS_STORAGE,
847     PCI_SUBCLASS_MASS_STORAGE_IDE, 0x00) + 0x01);
848    
849     /* PIIX_IDETIM (see NetBSD's pciide_piix_reg.h) */
850     /* channel 0 and 1 enabled as IDE */
851     PCI_SET_DATA(0x40, 0x80008000);
852    
853 dpavlin 30 pd->extra = malloc(sizeof(struct piix_ide_extra));
854     if (pd->extra == NULL) {
855     fatal("Out of memory.\n");
856     exit(1);
857     }
858     ((struct piix_ide_extra *)pd->extra)->wdc0 = NULL;
859     ((struct piix_ide_extra *)pd->extra)->wdc1 = NULL;
860    
861 dpavlin 20 if (diskimage_exist(machine, 0, DISKIMAGE_IDE) ||
862     diskimage_exist(machine, 1, DISKIMAGE_IDE)) {
863 dpavlin 34 snprintf(tmpstr, sizeof(tmpstr), "wdc addr=0x%llx irq=%s."
864     "isa.%i", (long long)(pd->pcibus->isa_portbase + 0x1f0),
865     pd->pcibus->irq_path_isa, 14);
866 dpavlin 30 ((struct piix_ide_extra *)pd->extra)->wdc0 =
867     device_add(machine, tmpstr);
868 dpavlin 20 }
869    
870     if (diskimage_exist(machine, 2, DISKIMAGE_IDE) ||
871     diskimage_exist(machine, 3, DISKIMAGE_IDE)) {
872 dpavlin 34 snprintf(tmpstr, sizeof(tmpstr), "wdc addr=0x%llx irq=%s."
873     "isa.%i", (long long)(pd->pcibus->isa_portbase + 0x170),
874     pd->pcibus->irq_path_isa, 15);
875 dpavlin 30 ((struct piix_ide_extra *)pd->extra)->wdc1 =
876     device_add(machine, tmpstr);
877 dpavlin 20 }
878 dpavlin 30
879     pd->cfg_reg_write = piix_ide_cfg_reg_write;
880 dpavlin 20 }
881    
882    
883    
884     /*
885     * IBM ISA bridge (used by at least one PReP machine).
886     */
887    
888     #define PCI_VENDOR_IBM 0x1014
889     #define PCI_PRODUCT_IBM_ISABRIDGE 0x000a
890    
891     PCIINIT(ibm_isa)
892     {
893     PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_IBM,
894     PCI_PRODUCT_IBM_ISABRIDGE));
895    
896     PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_BRIDGE,
897     PCI_SUBCLASS_BRIDGE_ISA, 0) + 0x02);
898    
899     PCI_SET_DATA(PCI_BHLC_REG,
900     PCI_BHLC_CODE(0,0, 1 /* multi-function */, 0x40,0));
901     }
902    
903    
904    
905     /*
906     * Heuricon PCI host bridge for PM/PPC.
907     */
908    
909     #define PCI_VENDOR_HEURICON 0x1223
910     #define PCI_PRODUCT_HEURICON_PMPPC 0x000e
911    
912     PCIINIT(heuricon_pmppc)
913     {
914     PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_HEURICON,
915     PCI_PRODUCT_HEURICON_PMPPC));
916    
917     PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_BRIDGE,
918     PCI_SUBCLASS_BRIDGE_HOST, 0) + 0x00); /* Revision? */
919    
920     PCI_SET_DATA(PCI_BHLC_REG,
921     PCI_BHLC_CODE(0,0, 1 /* multi-function */, 0x40,0));
922     }
923    
924    
925    
926     /*
927     * VIATECH VT82C586 devices:
928     *
929     * vt82c586_isa PCI->ISA bridge
930     * vt82c586_ide IDE controller
931     *
932     * TODO: This more or less just a dummy device, so far.
933     */
934    
935     #define PCI_VENDOR_VIATECH 0x1106 /* VIA Technologies */
936     #define PCI_PRODUCT_VIATECH_VT82C586_IDE 0x1571 /* VT82C586 (Apollo VP)
937     IDE Controller */
938     #define PCI_PRODUCT_VIATECH_VT82C586_ISA 0x0586 /* VT82C586 (Apollo VP)
939     PCI-ISA Bridge */
940    
941     PCIINIT(vt82c586_isa)
942     {
943     PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_VIATECH,
944     PCI_PRODUCT_VIATECH_VT82C586_ISA));
945    
946     PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_BRIDGE,
947     PCI_SUBCLASS_BRIDGE_ISA, 0) + 0x39); /* Revision 37 or 39 */
948    
949     PCI_SET_DATA(PCI_BHLC_REG,
950     PCI_BHLC_CODE(0,0, 1 /* multi-function */, 0x40,0));
951     }
952    
953 dpavlin 30 struct vt82c586_ide_extra {
954     void *wdc0;
955     void *wdc1;
956     };
957    
958     int vt82c586_ide_cfg_reg_write(struct pci_device *pd, int reg, uint32_t value)
959     {
960     void *wdc0 = ((struct vt82c586_ide_extra *)pd->extra)->wdc0;
961     void *wdc1 = ((struct vt82c586_ide_extra *)pd->extra)->wdc1;
962     int enabled = 0;
963    
964     switch (reg) {
965     case PCI_COMMAND_STATUS_REG:
966     if (value & PCI_COMMAND_IO_ENABLE)
967     enabled = 1;
968     if (wdc0 != NULL)
969     wdc_set_io_enabled(wdc0, enabled);
970     if (wdc1 != NULL)
971     wdc_set_io_enabled(wdc1, enabled);
972     return 1;
973     }
974    
975     return 0;
976     }
977    
978 dpavlin 20 PCIINIT(vt82c586_ide)
979     {
980     char tmpstr[100];
981    
982     PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_VIATECH,
983     PCI_PRODUCT_VIATECH_VT82C586_IDE));
984    
985     /* Possibly not correct: */
986     PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_MASS_STORAGE,
987     PCI_SUBCLASS_MASS_STORAGE_IDE, 0x00) + 0x01);
988    
989     /* APO_IDECONF */
990     /* channel 0 and 1 enabled */
991     PCI_SET_DATA(0x40, 0x00000003);
992    
993 dpavlin 30 pd->extra = malloc(sizeof(struct vt82c586_ide_extra));
994     if (pd->extra == NULL) {
995     fatal("Out of memory.\n");
996     exit(1);
997     }
998     ((struct vt82c586_ide_extra *)pd->extra)->wdc0 = NULL;
999     ((struct vt82c586_ide_extra *)pd->extra)->wdc1 = NULL;
1000    
1001 dpavlin 20 if (diskimage_exist(machine, 0, DISKIMAGE_IDE) ||
1002     diskimage_exist(machine, 1, DISKIMAGE_IDE)) {
1003 dpavlin 34 snprintf(tmpstr, sizeof(tmpstr), "wdc addr=0x%llx irq=%s."
1004     "isa.%i", (long long)(pd->pcibus->isa_portbase + 0x1f0),
1005     pd->pcibus->irq_path_isa, 14);
1006 dpavlin 30 ((struct vt82c586_ide_extra *)pd->extra)->wdc0 =
1007     device_add(machine, tmpstr);
1008 dpavlin 20 }
1009    
1010     if (diskimage_exist(machine, 2, DISKIMAGE_IDE) ||
1011     diskimage_exist(machine, 3, DISKIMAGE_IDE)) {
1012 dpavlin 34 snprintf(tmpstr, sizeof(tmpstr), "wdc addr=0x%llx irq=%s."
1013     "isa.%i", (long long)(pd->pcibus->isa_portbase + 0x170),
1014     pd->pcibus->irq_path_isa, 15);
1015 dpavlin 30 ((struct vt82c586_ide_extra *)pd->extra)->wdc1 =
1016     device_add(machine, tmpstr);
1017 dpavlin 20 }
1018 dpavlin 30
1019     pd->cfg_reg_write = vt82c586_ide_cfg_reg_write;
1020 dpavlin 20 }
1021    
1022    
1023    
1024     /*
1025     * Symphony Labs 83C553 PCI->ISA bridge.
1026     * Symphony Labs 82C105 PCIIDE controller.
1027     */
1028    
1029     #define PCI_VENDOR_SYMPHONY 0x10ad
1030     #define PCI_PRODUCT_SYMPHONY_83C553 0x0565
1031     #define PCI_PRODUCT_SYMPHONY_82C105 0x0105
1032    
1033     PCIINIT(symphony_83c553)
1034     {
1035     PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_SYMPHONY,
1036     PCI_PRODUCT_SYMPHONY_83C553));
1037    
1038     PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_BRIDGE,
1039     PCI_SUBCLASS_BRIDGE_ISA, 0) + 0x10);
1040    
1041     PCI_SET_DATA(PCI_BHLC_REG,
1042     PCI_BHLC_CODE(0,0, 1 /* multi-function */, 0x40,0));
1043 dpavlin 34
1044     switch (machine->machine_type) {
1045     case MACHINE_NETWINDER:
1046     bus_isa_init(machine, pd->pcibus->irq_path_isa,
1047     0, 0x7c000000, 0x80000000);
1048     break;
1049     default:fatal("symphony_83c553 init: unimplemented machine type\n");
1050     exit(1);
1051     }
1052 dpavlin 20 }
1053    
1054 dpavlin 32 struct symphony_82c105_extra {
1055     void *wdc0;
1056     void *wdc1;
1057     };
1058    
1059     int symphony_82c105_cfg_reg_write(struct pci_device *pd, int reg,
1060     uint32_t value)
1061     {
1062     void *wdc0 = ((struct symphony_82c105_extra *)pd->extra)->wdc0;
1063     void *wdc1 = ((struct symphony_82c105_extra *)pd->extra)->wdc1;
1064     int enabled = 0;
1065    
1066     printf("reg = 0x%x\n", reg);
1067     switch (reg) {
1068     case PCI_COMMAND_STATUS_REG:
1069     if (value & PCI_COMMAND_IO_ENABLE)
1070     enabled = 1;
1071     printf(" value = 0x%"PRIx32"\n", value);
1072     if (wdc0 != NULL)
1073     wdc_set_io_enabled(wdc0, enabled);
1074     if (wdc1 != NULL)
1075     wdc_set_io_enabled(wdc1, enabled);
1076     /* Set all bits: */
1077     PCI_SET_DATA(reg, value);
1078     return 1;
1079     case PCI_MAPREG_START:
1080     case PCI_MAPREG_START + 4:
1081     case PCI_MAPREG_START + 8:
1082     case PCI_MAPREG_START + 12:
1083     case PCI_MAPREG_START + 16:
1084     case PCI_MAPREG_START + 20:
1085     PCI_SET_DATA(reg, value);
1086     return 1;
1087     }
1088    
1089     return 0;
1090     }
1091    
1092 dpavlin 20 PCIINIT(symphony_82c105)
1093     {
1094     char tmpstr[100];
1095    
1096     PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_SYMPHONY,
1097     PCI_PRODUCT_SYMPHONY_82C105));
1098    
1099     /* Possibly not correct: */
1100     PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_MASS_STORAGE,
1101     PCI_SUBCLASS_MASS_STORAGE_IDE, 0x00) + 0x05);
1102    
1103 dpavlin 32 /* TODO: Interrupt line: */
1104     /* PCI_SET_DATA(PCI_INTERRUPT_REG, 0x28140000); */
1105    
1106 dpavlin 20 /* APO_IDECONF */
1107     /* channel 0 and 1 enabled */
1108     PCI_SET_DATA(0x40, 0x00000003);
1109    
1110 dpavlin 32 pd->extra = malloc(sizeof(struct symphony_82c105_extra));
1111     if (pd->extra == NULL) {
1112     fatal("Out of memory.\n");
1113     exit(1);
1114     }
1115     ((struct symphony_82c105_extra *)pd->extra)->wdc0 = NULL;
1116     ((struct symphony_82c105_extra *)pd->extra)->wdc1 = NULL;
1117    
1118 dpavlin 20 if (diskimage_exist(machine, 0, DISKIMAGE_IDE) ||
1119     diskimage_exist(machine, 1, DISKIMAGE_IDE)) {
1120 dpavlin 34 snprintf(tmpstr, sizeof(tmpstr), "wdc addr=0x%llx irq=%s."
1121     "isa.%i", (long long)(pd->pcibus->isa_portbase + 0x1f0),
1122     pd->pcibus->irq_path_isa, 14);
1123 dpavlin 32 ((struct symphony_82c105_extra *)pd->extra)->wdc0 =
1124     device_add(machine, tmpstr);
1125 dpavlin 20 }
1126    
1127     if (diskimage_exist(machine, 2, DISKIMAGE_IDE) ||
1128     diskimage_exist(machine, 3, DISKIMAGE_IDE)) {
1129 dpavlin 34 snprintf(tmpstr, sizeof(tmpstr), "wdc addr=0x%llx irq=%s."
1130     "isa.%i", (long long)(pd->pcibus->isa_portbase + 0x170),
1131     pd->pcibus->irq_path_isa, 15);
1132 dpavlin 32 ((struct symphony_82c105_extra *)pd->extra)->wdc1 =
1133     device_add(machine, tmpstr);
1134 dpavlin 20 }
1135 dpavlin 32
1136     pd->cfg_reg_write = symphony_82c105_cfg_reg_write;
1137 dpavlin 20 }
1138    
1139    
1140    
1141     /*
1142     * DEC 21143 ("Tulip") PCI ethernet.
1143     */
1144    
1145     #define PCI_VENDOR_DEC 0x1011 /* Digital Equipment */
1146     #define PCI_PRODUCT_DEC_21142 0x0019 /* DECchip 21142/21143 10/100 Ethernet */
1147    
1148     PCIINIT(dec21143)
1149     {
1150     uint64_t port, memaddr;
1151 dpavlin 34 int pci_int_line = 0x101, irq = 0, isa = 0;
1152     char irqstr[200];
1153 dpavlin 20 char tmpstr[200];
1154    
1155     PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_DEC,
1156     PCI_PRODUCT_DEC_21142));
1157    
1158     PCI_SET_DATA(PCI_COMMAND_STATUS_REG, 0x02000017);
1159    
1160     PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_NETWORK,
1161     PCI_SUBCLASS_NETWORK_ETHERNET, 0x00) + 0x41);
1162    
1163     PCI_SET_DATA(PCI_BHLC_REG, PCI_BHLC_CODE(0,0,0, 0x40,0));
1164    
1165     switch (machine->machine_type) {
1166     case MACHINE_CATS:
1167 dpavlin 22 /* CATS int 18 = PCI. */
1168 dpavlin 20 irq = 18;
1169 dpavlin 22 pci_int_line = 0x101;
1170 dpavlin 20 break;
1171 dpavlin 22 case MACHINE_COBALT:
1172     /* On Cobalt, IRQ 7 = PCI. */
1173     irq = 8 + 7;
1174     pci_int_line = 0x407;
1175     break;
1176 dpavlin 20 case MACHINE_PREP:
1177 dpavlin 34 irq = 10;
1178     isa = 1;
1179 dpavlin 22 pci_int_line = 0x20a;
1180 dpavlin 20 break;
1181 dpavlin 22 case MACHINE_MVMEPPC:
1182     /* TODO */
1183 dpavlin 34 irq = 10;
1184 dpavlin 22 pci_int_line = 0x40a;
1185     break;
1186 dpavlin 20 case MACHINE_PMPPC:
1187 dpavlin 22 /* TODO, not working yet */
1188 dpavlin 20 irq = 31 - 21;
1189 dpavlin 22 pci_int_line = 0x201;
1190 dpavlin 20 break;
1191 dpavlin 22 case MACHINE_MACPPC:
1192     /* TODO, not working yet */
1193     irq = 25;
1194     pci_int_line = 0x101;
1195     break;
1196 dpavlin 20 }
1197    
1198 dpavlin 22 PCI_SET_DATA(PCI_INTERRUPT_REG, 0x28140000 | pci_int_line);
1199 dpavlin 20
1200     allocate_device_space(pd, 0x100, 0x100, &port, &memaddr);
1201    
1202 dpavlin 34 if (isa)
1203     snprintf(irqstr, sizeof(irqstr), "%s.isa.%i",
1204     pd->pcibus->irq_path_isa, irq);
1205     else
1206     snprintf(irqstr, sizeof(irqstr), "%s.%i",
1207     pd->pcibus->irq_path_pci, irq);
1208    
1209 dpavlin 20 snprintf(tmpstr, sizeof(tmpstr), "dec21143 addr=0x%llx addr2=0x%llx "
1210 dpavlin 34 "irq=%s pci_little_endian=1", (long long)port,
1211     (long long)memaddr, irqstr);
1212    
1213 dpavlin 20 device_add(machine, tmpstr);
1214     }
1215    
1216    
1217    
1218     /*
1219     * DEC 21030 "tga" graphics.
1220     */
1221    
1222     #define PCI_PRODUCT_DEC_21030 0x0004 /* DECchip 21030 ("TGA") */
1223    
1224     PCIINIT(dec21030)
1225     {
1226     uint64_t base = 0;
1227     char tmpstr[200];
1228    
1229     PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_DEC,
1230     PCI_PRODUCT_DEC_21030));
1231    
1232     PCI_SET_DATA(PCI_COMMAND_STATUS_REG, 0x02800087); /* TODO */
1233    
1234     PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_DISPLAY,
1235     PCI_SUBCLASS_DISPLAY_VGA, 0x00) + 0x03);
1236    
1237     /*
1238     * See http://mail-index.netbsd.org/port-arc/2001/08/13/0000.html
1239     * for more info.
1240     */
1241    
1242     PCI_SET_DATA(PCI_BHLC_REG, 0x0000ff00);
1243    
1244     /* 8 = prefetchable */
1245     PCI_SET_DATA(0x10, 0x00000008);
1246     PCI_SET_DATA(0x30, 0x08000001);
1247     PCI_SET_DATA(PCI_INTERRUPT_REG, 0x00000100); /* interrupt pin A? */
1248    
1249     /*
1250     * Experimental:
1251     *
1252     * TODO: Base address, pci_little_endian, ...
1253     */
1254    
1255     switch (machine->machine_type) {
1256     case MACHINE_ARC:
1257     base = 0x100000000ULL;
1258     break;
1259     default:fatal("dec21030 in non-implemented machine type %i\n",
1260     machine->machine_type);
1261     exit(1);
1262     }
1263    
1264     snprintf(tmpstr, sizeof(tmpstr), "dec21030 addr=0x%llx",
1265     (long long)(base));
1266     device_add(machine, tmpstr);
1267     }
1268    
1269    
1270 dpavlin 22
1271 dpavlin 20 /*
1272     * Motorola MPC105 "Eagle" Host Bridge
1273     *
1274     * Used in at least PReP and BeBox.
1275     */
1276    
1277     #define PCI_VENDOR_MOT 0x1057
1278     #define PCI_PRODUCT_MOT_MPC105 0x0001
1279    
1280     PCIINIT(eagle)
1281     {
1282     PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_MOT,
1283     PCI_PRODUCT_MOT_MPC105));
1284    
1285     PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_BRIDGE,
1286     PCI_SUBCLASS_BRIDGE_HOST, 0) + 0x24);
1287    
1288     PCI_SET_DATA(PCI_BHLC_REG,
1289     PCI_BHLC_CODE(0,0, 1 /* multi-function */, 0x40,0));
1290     }
1291    
1292 dpavlin 22
1293    
1294     /*
1295     * Apple (MacPPC) stuff:
1296     *
1297     * Grand Central (I/O controller)
1298     * Uni-North (PCI controller)
1299     */
1300    
1301     #define PCI_VENDOR_APPLE 0x106b
1302     #define PCI_PRODUCT_APPLE_GC 0x0002
1303     #define PCI_PRODUCT_APPLE_UNINORTH1 0x001e
1304    
1305     PCIINIT(gc_obio)
1306     {
1307     uint64_t port, memaddr;
1308    
1309     PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_APPLE,
1310     PCI_PRODUCT_APPLE_GC));
1311    
1312     /* TODO: */
1313     PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_SYSTEM,
1314     PCI_SUBCLASS_SYSTEM_PIC, 0) + 0x00);
1315    
1316     PCI_SET_DATA(PCI_BHLC_REG,
1317     PCI_BHLC_CODE(0,0, 1 /* multi-function */, 0x40,0));
1318    
1319     /* TODO */
1320     allocate_device_space(pd, 0x10000, 0x10000, &port, &memaddr);
1321     }
1322    
1323     PCIINIT(uninorth)
1324     {
1325     uint64_t port, memaddr;
1326    
1327     PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_APPLE,
1328     PCI_PRODUCT_APPLE_UNINORTH1));
1329    
1330     PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_BRIDGE,
1331     PCI_SUBCLASS_BRIDGE_HOST, 0) + 0xff);
1332    
1333     PCI_SET_DATA(PCI_BHLC_REG,
1334     PCI_BHLC_CODE(0,0, 1 /* multi-function */, 0x40,0));
1335    
1336     /* TODO */
1337     allocate_device_space(pd, 0x10000, 0x10000, &port, &memaddr);
1338     }
1339    
1340    
1341    
1342     /*
1343     * ATI graphics cards
1344     */
1345    
1346     #define PCI_VENDOR_ATI 0x1002
1347     #define PCI_PRODUCT_ATI_RADEON_9200_2 0x5962
1348    
1349     PCIINIT(ati_radeon_9200_2)
1350     {
1351     uint64_t port, memaddr;
1352    
1353     PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_ATI,
1354     PCI_PRODUCT_ATI_RADEON_9200_2));
1355    
1356     /* TODO: other subclass? */
1357     PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_DISPLAY,
1358     PCI_SUBCLASS_DISPLAY_VGA, 0) + 0x03);
1359    
1360     /* TODO */
1361     allocate_device_space(pd, 0x1000, 0x400000, &port, &memaddr);
1362     }
1363    

  ViewVC Help
Powered by ViewVC 1.1.26