1 /* $NetBSD: isa_machdep.c,v 1.15 2009/08/19 15:01:07 dyoung Exp $ */
4 * Copyright (c) 1996-1998 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Mark Brinicombe, Charles M. Hannum and by Jason R. Thorpe of the
9 * Numerical Aerospace Simulation Facility, NASA Ames Research Center.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
34 * Copyright (c) 1991 The Regents of the University of California.
35 * All rights reserved.
37 * This code is derived from software contributed to Berkeley by
40 * Redistribution and use in source and binary forms, with or without
41 * modification, are permitted provided that the following conditions
43 * 1. Redistributions of source code must retain the above copyright
44 * notice, this list of conditions and the following disclaimer.
45 * 2. Redistributions in binary form must reproduce the above copyright
46 * notice, this list of conditions and the following disclaimer in the
47 * documentation and/or other materials provided with the distribution.
48 * 3. Neither the name of the University nor the names of its contributors
49 * may be used to endorse or promote products derived from this software
50 * without specific prior written permission.
52 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
56 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
64 * @(#)isa.c 7.2 (Berkeley) 5/13/91
67 #include <sys/cdefs.h>
68 __KERNEL_RCSID(0, "$NetBSD: isa_machdep.c,v 1.15 2009/08/19 15:01:07 dyoung Exp $");
70 #include "opt_irqstats.h"
72 #include <sys/param.h>
73 #include <sys/systm.h>
74 #include <sys/kernel.h>
75 #include <sys/syslog.h>
76 #include <sys/device.h>
77 #include <sys/malloc.h>
80 #define _ARM32_BUS_DMA_PRIVATE
81 #include <machine/bus.h>
83 #include <machine/intr.h>
84 #include <machine/pio.h>
85 #include <machine/bootconfig.h>
86 #include <machine/isa_machdep.h>
88 #include <dev/isa/isareg.h>
89 #include <dev/isa/isavar.h>
90 #include <dev/isa/isadmareg.h>
91 #include <dev/isa/isadmavar.h>
92 #include <arm/footbridge/isa/icu.h>
93 #include <arm/footbridge/dc21285reg.h>
94 #include <arm/footbridge/dc21285mem.h>
96 #include <uvm/uvm_extern.h>
101 static void isa_icu_init(void);
103 struct arm32_isa_chipset isa_chipset_tag
;
105 void isa_strayintr(int);
106 void intr_calculatemasks(void);
107 int fakeintr(void *);
109 int isa_irqdispatch(void *arg
);
118 * Fill in default interrupt table (in case of spuruious interrupt
119 * during configuration of kernel, setup interrupt control unit
124 /* initialize 8259's */
125 outb(IO_ICU1
, 0x11); /* reset; program device, four bytes */
126 outb(IO_ICU1
+1, ICU_OFFSET
); /* starting at this vector index */
127 outb(IO_ICU1
+1, 1 << IRQ_SLAVE
); /* slave on line 2 */
129 outb(IO_ICU1
+1, 2 | 1); /* auto EOI, 8086 mode */
131 outb(IO_ICU1
+1, 1); /* 8086 mode */
133 outb(IO_ICU1
+1, 0xff); /* leave interrupts masked */
134 outb(IO_ICU1
, 0x68); /* special mask mode (if available) */
135 outb(IO_ICU1
, 0x0a); /* Read IRR by default. */
137 outb(IO_ICU1
, 0xc0 | (3 - 1)); /* pri order 3-7, 0-2 (com2 first) */
140 outb(IO_ICU2
, 0x11); /* reset; program device, four bytes */
141 outb(IO_ICU2
+1, ICU_OFFSET
+8); /* staring at this vector index */
142 outb(IO_ICU2
+1, IRQ_SLAVE
);
144 outb(IO_ICU2
+1, 2 | 1); /* auto EOI, 8086 mode */
146 outb(IO_ICU2
+1, 1); /* 8086 mode */
148 outb(IO_ICU2
+1, 0xff); /* leave interrupts masked */
149 outb(IO_ICU2
, 0x68); /* special mask mode (if available) */
150 outb(IO_ICU2
, 0x0a); /* Read IRR by default. */
154 * Caught a stray interrupt, notify
157 isa_strayintr(int irq
)
159 static u_long strays
;
162 * Stray interrupts on irq 7 occur when an interrupt line is raised
163 * and then lowered before the CPU acknowledges it. This generally
164 * means either the device is screwed or something is cli'ing too
165 * long and it's timing out.
168 log(LOG_ERR
, "stray interrupt %d%s\n", irq
,
169 strays
>= 5 ? "; stopped logging" : "");
172 static struct intrq isa_intrq
[ICU_LEN
];
175 * Recalculate the interrupt masks from scratch.
176 * We could code special registry and deregistry versions of this function that
177 * would be faster, but the code would be nastier, and we don't expect this to
178 * happen very much anyway.
181 intr_calculatemasks(void)
187 /* First, figure out which levels each IRQ uses. */
188 for (irq
= 0; irq
< ICU_LEN
; irq
++) {
190 iq
= &isa_intrq
[irq
];
191 for (ih
= TAILQ_FIRST(&iq
->iq_list
); ih
!= NULL
;
192 ih
= TAILQ_NEXT(ih
, ih_list
))
193 levels
|= (1U << ih
->ih_ipl
);
194 iq
->iq_levels
= levels
;
197 /* Then figure out which IRQs use each level. */
198 for (level
= 0; level
< NIPL
; level
++) {
200 for (irq
= 0; irq
< ICU_LEN
; irq
++)
201 if (isa_intrq
[irq
].iq_levels
& (1U << level
))
207 imask
[IPL_SOFTCLOCK
] |= imask
[IPL_NONE
];
208 imask
[IPL_SOFTBIO
] |= imask
[IPL_SOFTCLOCK
];
209 imask
[IPL_SOFTNET
] |= imask
[IPL_SOFTBIO
];
210 imask
[IPL_SOFTSERIAL
] |= imask
[IPL_SOFTNET
];
211 imask
[IPL_VM
] |= imask
[IPL_SOFTSERIAL
];
212 imask
[IPL_SCHED
] |= imask
[IPL_VM
];
213 imask
[IPL_HIGH
] |= imask
[IPL_SCHED
];
215 /* And eventually calculate the complete masks. */
216 for (irq
= 0; irq
< ICU_LEN
; irq
++) {
218 iq
= &isa_intrq
[irq
];
219 for (ih
= TAILQ_FIRST(&iq
->iq_list
); ih
!= NULL
;
220 ih
= TAILQ_NEXT(ih
, ih_list
))
221 irqs
|= imask
[ih
->ih_ipl
];
225 /* Lastly, determine which IRQs are actually in use. */
228 for (irq
= 0; irq
< ICU_LEN
; irq
++)
229 if (!TAILQ_EMPTY(&isa_intrq
[irq
].iq_list
))
231 if (irqs
>= 0x100) /* any IRQs >= 8 in use */
232 irqs
|= 1 << IRQ_SLAVE
;
237 printf("type\tmask\tlevel\thand\n");
238 for (irq
= 0; irq
< ICU_LEN
; irq
++) {
239 printf("%x\t%04x\t%x\t%p\n", intrtype
[irq
], intrmask
[irq
],
240 intrlevel
[irq
], intrhand
[irq
]);
242 for (level
= 0; level
< IPL_LEVELS
; ++level
)
243 printf("%d: %08x\n", level
, imask
[level
]);
254 #define LEGAL_IRQ(x) ((x) >= 0 && (x) < ICU_LEN && (x) != 2)
257 isa_intr_alloc(isa_chipset_tag_t ic
, int mask
, int type
, int *irq
)
259 int i
, tmp
, bestirq
, count
;
263 if (type
== IST_NONE
)
264 panic("intr_alloc: bogus type");
269 /* some interrupts should never be dynamically allocated */
273 * XXX some interrupts will be used later (6 for fdc, 12 for pms).
274 * the right answer is to do "breadth-first" searching of devices.
278 for (i
= 0; i
< ICU_LEN
; i
++) {
279 if (LEGAL_IRQ(i
) == 0 || (mask
& (1<<i
)) == 0)
286 * if nothing's using the irq, just return it
293 if (type
!= iq
->iq_ist
)
296 * if the irq is shareable, count the number of other
297 * handlers, and if it's smaller than the last irq like
300 * XXX We should probably also consider the
301 * interrupt level and stick IPL_TTY with other
305 TAILQ_FOREACH(ih
, &(iq
->iq_list
), ih_list
)
307 if ((bestirq
== -1) || (count
> tmp
)) {
314 /* this just isn't shareable */
328 isa_intr_evcnt(isa_chipset_tag_t ic
, int irq
)
330 return &isa_intrq
[irq
].iq_ev
;
334 * Set up an interrupt handler to start being called.
335 * XXX PRONE TO RACE CONDITIONS, UGLY, 'INTERESTING' INSERTION ALGORITHM.
338 isa_intr_establish(isa_chipset_tag_t ic
, int irq
, int type
, int level
, int (*ih_fun
)(void *), void *ih_arg
)
345 printf("isa_intr_establish(%d, %d, %d)\n", irq
, type
, level
);
347 /* no point in sleeping unless someone can free memory. */
348 ih
= malloc(sizeof *ih
, M_DEVBUF
, cold
? M_NOWAIT
: M_WAITOK
);
352 if (!LEGAL_IRQ(irq
) || type
== IST_NONE
)
353 panic("intr_establish: bogus irq or type");
355 iq
= &isa_intrq
[irq
];
357 switch (iq
->iq_ist
) {
361 printf("Setting irq %d to type %d - ", irq
, type
);
364 outb(0x4d0, (inb(0x4d0) & ~(1 << irq
))
365 | ((type
== IST_LEVEL
) ? (1 << irq
) : 0));
366 /* printf("%02x\n", inb(0x4d0));*/
368 outb(0x4d1, (inb(0x4d1) & ~(1 << irq
))
369 | ((type
== IST_LEVEL
) ? (1 << irq
) : 0));
370 /* printf("%02x\n", inb(0x4d1));*/
375 if (iq
->iq_ist
== type
)
378 if (type
!= IST_NONE
)
379 panic("intr_establish: can't share %s with %s",
380 isa_intr_typename(iq
->iq_ist
),
381 isa_intr_typename(type
));
385 ih
->ih_func
= ih_fun
;
391 oldirqstate
= disable_interrupts(I32_bit
);
393 TAILQ_INSERT_TAIL(&iq
->iq_list
, ih
, ih_list
);
395 intr_calculatemasks();
396 restore_interrupts(oldirqstate
);
402 * Deregister an interrupt handler.
405 isa_intr_disestablish(isa_chipset_tag_t ic
, void *arg
)
407 struct intrhand
*ih
= arg
;
408 struct intrq
*iq
= &isa_intrq
[ih
->ih_irq
];
409 int irq
= ih
->ih_irq
;
413 panic("intr_disestablish: bogus irq");
415 oldirqstate
= disable_interrupts(I32_bit
);
417 TAILQ_REMOVE(&iq
->iq_list
, ih
, ih_list
);
419 intr_calculatemasks();
421 restore_interrupts(oldirqstate
);
425 if (TAILQ_EMPTY(&(iq
->iq_list
)))
426 iq
->iq_ist
= IST_NONE
;
432 * Initialise the ISA ICU and attach an ISA interrupt handler to the
433 * ISA interrupt line on the footbridge.
443 * should get the parent here, but initialisation order being so
444 * strange I need to check if it's available
446 for (i
= 0; i
< ICU_LEN
; i
++) {
448 TAILQ_INIT(&iq
->iq_list
);
450 sprintf(iq
->iq_name
, "irq %d", i
);
451 evcnt_attach_dynamic(&iq
->iq_ev
, EVCNT_TYPE_INTR
,
452 NULL
, "isa", iq
->iq_name
);
456 intr_calculatemasks();
457 /* something to break the build in an informative way */
458 #ifndef ISA_FOOTBRIDGE_IRQ
459 #warning Before using isa with footbridge you must define ISA_FOOTBRIDGE_IRQ
461 isa_ih
= footbridge_intr_claim(ISA_FOOTBRIDGE_IRQ
, IPL_BIO
, "isabus",
462 isa_irqdispatch
, NULL
);
466 /* Static array of ISA DMA segments. We only have one on CATS */
468 struct arm32_dma_range machdep_isa_dma_ranges
[1];
472 isa_footbridge_init(u_int iobase
, u_int membase
)
475 extern struct arm32_dma_range
*footbridge_isa_dma_ranges
;
476 extern int footbridge_isa_dma_nranges
;
478 machdep_isa_dma_ranges
[0].dr_sysbase
= bootconfig
.dram
[0].address
;
479 machdep_isa_dma_ranges
[0].dr_busbase
= bootconfig
.dram
[0].address
;
480 machdep_isa_dma_ranges
[0].dr_len
= (16 * 1024 * 1024);
482 footbridge_isa_dma_ranges
= machdep_isa_dma_ranges
;
483 footbridge_isa_dma_nranges
= 1;
486 isa_io_init(iobase
, membase
);
490 isa_attach_hook(struct device
*parent
, struct device
*self
, struct isabus_attach_args
*iba
)
493 * Since we can only have one ISA bus, we just use a single
494 * statically allocated ISA chipset structure. Pass it up
497 iba
->iba_ic
= &isa_chipset_tag
;
504 isa_detach_hook(isa_chipset_tag_t ic
, device_t self
)
512 isa_irqdispatch(void *arg
)
514 struct clockframe
*frame
= arg
;
521 iack
= *((u_int
*)(DC21285_PCI_IACK_VBASE
));
523 if (iack
< 0x20 || iack
> 0x2f) {
524 printf("isa_irqdispatch: %x\n", iack
);
529 iq
= &isa_intrq
[irq
];
530 iq
->iq_ev
.ev_count
++;
531 for (ih
= TAILQ_FIRST(&iq
->iq_list
); res
!= 1 && ih
!= NULL
;
532 ih
= TAILQ_NEXT(ih
, ih_list
)) {
533 res
= (*ih
->ih_func
)(ih
->ih_arg
? ih
->ih_arg
: frame
);
540 isa_fillw(u_int val
, void *addr
, size_t len
)
542 if ((u_int
)addr
>= isa_mem_data_vaddr()
543 && (u_int
)addr
< isa_mem_data_vaddr() + 0x100000) {
544 bus_size_t offset
= ((u_int
)addr
) & 0xfffff;
545 bus_space_set_region_2(&isa_mem_bs_tag
,
546 (bus_space_handle_t
)isa_mem_bs_tag
.bs_cookie
, offset
,