Home | History | Annotate | Line # | Download | only in pci
pci_6600.c revision 1.2
      1 /* $NetBSD: pci_6600.c,v 1.2 2000/03/19 02:25:29 thorpej Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 1999 by Ross Harvey.  All rights reserved.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  * 3. All advertising materials mentioning features or use of this software
     15  *    must display the following acknowledgement:
     16  *	This product includes software developed by Ross Harvey.
     17  * 4. The name of Ross Harvey may not be used to endorse or promote products
     18  *    derived from this software without specific prior written permission.
     19  *
     20  * THIS SOFTWARE IS PROVIDED BY ROSS HARVEY ``AS IS'' AND ANY EXPRESS
     21  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     22  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURP0SE
     23  * ARE DISCLAIMED.  IN NO EVENT SHALL ROSS HARVEY BE LIABLE FOR ANY
     24  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     30  * SUCH DAMAGE.
     31  *
     32  */
     33 
     34 #include <sys/cdefs.h>
     35 
     36 __KERNEL_RCSID(0, "$NetBSD: pci_6600.c,v 1.2 2000/03/19 02:25:29 thorpej Exp $");
     37 
     38 #include <sys/param.h>
     39 #include <sys/systm.h>
     40 #include <sys/kernel.h>
     41 #include <sys/device.h>
     42 #include <sys/malloc.h>
     43 #include <vm/vm.h>
     44 
     45 #include <machine/autoconf.h>
     46 #define _ALPHA_BUS_DMA_PRIVATE
     47 #include <machine/bus.h>
     48 #include <machine/rpb.h>
     49 #include <machine/intrcnt.h>
     50 #include <machine/alpha.h>
     51 
     52 #include <dev/pci/pcireg.h>
     53 #include <dev/pci/pcivar.h>
     54 #include <dev/pci/pciidereg.h>
     55 #include <dev/pci/pciidevar.h>
     56 
     57 #include <alpha/pci/tsreg.h>
     58 #include <alpha/pci/tsvar.h>
     59 #include <alpha/pci/pci_6600.h>
     60 
     61 #define pci_6600() { Generate ctags(1) key. }
     62 
     63 #include "sio.h"
     64 #if NSIO
     65 #include <alpha/pci/siovar.h>
     66 #endif
     67 
     68 #define	PCI_STRAY_MAX		5
     69 #define	DEC_6600_MAX_IRQ	INTRCNT_OTHER_LEN
     70 
     71 /*
     72  * Some Tsunami models have a PCI device (the USB controller) with interrupts
     73  * tied to ISA IRQ lines.  The IRQ is encoded as:
     74  *
     75  *	line = 0xe0 | isa_irq;
     76  */
     77 #define	DEC_6600_LINE_IS_ISA(line)	((line) >= 0xe0 && (line) <= 0xef)
     78 #define	DEC_6600_LINE_ISA_IRQ(line)	((line) & 0x0f)
     79 
     80 static char *irqtype = "6600 irq";
     81 static struct tsp_config *sioprimary;
     82 
     83 void dec_6600_intr_disestablish __P((void *, void *));
     84 void *dec_6600_intr_establish __P((
     85     void *, pci_intr_handle_t, int, int (*func)(void *), void *));
     86 const char *dec_6600_intr_string __P((void *, pci_intr_handle_t));
     87 int dec_6600_intr_map __P((void *, pcitag_t, int, int, pci_intr_handle_t *));
     88 void *dec_6600_pciide_compat_intr_establish __P((void *, struct device *,
     89     struct pci_attach_args *, int, int (*)(void *), void *));
     90 
     91 struct alpha_shared_intr *dec_6600_pci_intr;
     92 
     93 void dec_6600_iointr __P((void *framep, unsigned long vec));
     94 extern void dec_6600_intr_enable __P((int irq));
     95 extern void dec_6600_intr_disable __P((int irq));
     96 
     97 void
     98 pci_6600_pickintr(pcp)
     99 	struct tsp_config *pcp;
    100 {
    101 	bus_space_tag_t iot = &pcp->pc_iot;
    102 	pci_chipset_tag_t pc = &pcp->pc_pc;
    103 	int i;
    104 
    105         pc->pc_intr_v = pcp;
    106         pc->pc_intr_map = dec_6600_intr_map;
    107         pc->pc_intr_string = dec_6600_intr_string;
    108         pc->pc_intr_establish = dec_6600_intr_establish;
    109         pc->pc_intr_disestablish = dec_6600_intr_disestablish;
    110 	pc->pc_pciide_compat_intr_establish = NULL;
    111 
    112 	/*
    113 	 * System-wide and Pchip-0-only logic...
    114 	 */
    115 	if (dec_6600_pci_intr == NULL) {
    116 		sioprimary = pcp;
    117 		pc->pc_pciide_compat_intr_establish =
    118 		    dec_6600_pciide_compat_intr_establish;
    119 		dec_6600_pci_intr = alpha_shared_intr_alloc(DEC_6600_MAX_IRQ);
    120 		for (i = 0; i < DEC_6600_MAX_IRQ; i++) {
    121 			alpha_shared_intr_set_maxstrays(dec_6600_pci_intr, i,
    122 			    PCI_STRAY_MAX);
    123 			alpha_shared_intr_set_private(dec_6600_pci_intr, i,
    124 			    sioprimary);
    125 		}
    126 #if NSIO
    127 		sio_intr_setup(pc, iot);
    128 		dec_6600_intr_enable(55);	/* irq line for sio */
    129 #endif
    130 		set_iointr(dec_6600_iointr);
    131 	}
    132 }
    133 
    134 int
    135 dec_6600_intr_map(acv, bustag, buspin, line, ihp)
    136         void *acv;
    137         pcitag_t bustag;
    138         int buspin, line;
    139         pci_intr_handle_t *ihp;
    140 {
    141 	struct tsp_config *pcp = acv;
    142 	pci_chipset_tag_t pc = &pcp->pc_pc;
    143 	int bus, device, function;
    144 
    145 	if (buspin == 0) {
    146 		/* No IRQ used. */
    147 		return 1;
    148 	}
    149 	if (buspin > 4) {
    150 		printf("intr_map: bad interrupt pin %d\n", buspin);
    151 		return 1;
    152 	}
    153 
    154 	alpha_pci_decompose_tag(pc, bustag, &bus, &device, &function);
    155 
    156 	/*
    157 	 * The console places the interrupt mapping in the "line" value.
    158 	 * A value of (char)-1 indicates there is no mapping.
    159 	 */
    160 	if (line == 0xff) {
    161 		printf("dec_6600_intr_map: no mapping for %d/%d/%d\n",
    162 		    bus, device, function);
    163 		return (1);
    164 	}
    165 
    166 #if NSIO == 0
    167 	if (DEC_6600_LINE_IS_ISA(line)) {
    168 		printf("dec_6600_intr_map: ISA IRQ %d for %d/%d/%d\n",
    169 		    DEC_6600_LINE_ISA_IRQ(line), bus, device, function);
    170 		return (1);
    171 	}
    172 #endif
    173 
    174 	if (DEC_6600_LINE_IS_ISA(line) == 0 && line >= DEC_6600_MAX_IRQ)
    175 		panic("dec_6600_intr_map: dec 6600 irq too large (%d)\n",
    176 		    line);
    177 
    178 	*ihp = line;
    179 	return (0);
    180 }
    181 
    182 const char *
    183 dec_6600_intr_string(acv, ih)
    184 	void *acv;
    185 	pci_intr_handle_t ih;
    186 {
    187 
    188 	static const char irqfmt[] = "dec 6600 irq %ld";
    189 	static char irqstr[sizeof irqfmt];
    190 
    191 #if NSIO
    192 	if (DEC_6600_LINE_IS_ISA(ih))
    193 		return (sio_intr_string(NULL /*XXX*/,
    194 		    DEC_6600_LINE_ISA_IRQ(ih)));
    195 #endif
    196 
    197 	snprintf(irqstr, sizeof irqstr, irqfmt, ih);
    198 	return (irqstr);
    199 }
    200 
    201 void *
    202 dec_6600_intr_establish(acv, ih, level, func, arg)
    203         void *acv, *arg;
    204         pci_intr_handle_t ih;
    205         int level;
    206         int (*func) __P((void *));
    207 {
    208 	void *cookie;
    209 
    210 #if NSIO
    211 	if (DEC_6600_LINE_IS_ISA(ih))
    212 		return (sio_intr_establish(NULL /*XXX*/,
    213 		    DEC_6600_LINE_ISA_IRQ(ih), IST_LEVEL, level, func, arg));
    214 #endif
    215 
    216 	if (ih >= DEC_6600_MAX_IRQ)
    217 		panic("dec_6600_intr_establish: bogus dec 6600 IRQ 0x%lx\n",
    218 		    ih);
    219 
    220 	cookie = alpha_shared_intr_establish(dec_6600_pci_intr, ih, IST_LEVEL,
    221 	    level, func, arg, irqtype);
    222 
    223 	if (cookie != NULL && alpha_shared_intr_isactive(dec_6600_pci_intr, ih))
    224 		dec_6600_intr_enable(ih);
    225 	return (cookie);
    226 }
    227 
    228 void
    229 dec_6600_intr_disestablish(acv, cookie)
    230         void *acv, *cookie;
    231 {
    232 	struct alpha_shared_intrhand *ih = cookie;
    233 	unsigned int irq = ih->ih_num;
    234 	int s;
    235 
    236 #if NSIO
    237 	/*
    238 	 * We have to determine if this is an ISA IRQ or not!  We do this
    239 	 * by checking to see if the intrhand points back to an intrhead
    240 	 * that points to the sioprimary TSP.  If not, it's an ISA IRQ.
    241 	 * Pretty disgusting, eh?
    242 	 */
    243 	if (ih->ih_intrhead->intr_private != sioprimary) {
    244 		sio_intr_disestablish(NULL /*XXX*/, cookie);
    245 		return;
    246 	}
    247 #endif
    248 
    249 	s = splhigh();
    250 
    251 	alpha_shared_intr_disestablish(dec_6600_pci_intr, cookie, irqtype);
    252 	if (alpha_shared_intr_isactive(dec_6600_pci_intr, irq) == 0) {
    253 		dec_6600_intr_disable(irq);
    254 		alpha_shared_intr_set_dfltsharetype(dec_6600_pci_intr, irq,
    255 		    IST_NONE);
    256 	}
    257 
    258 	splx(s);
    259 }
    260 
    261 void
    262 dec_6600_iointr(framep, vec)
    263 	void *framep;
    264 	unsigned long vec;
    265 {
    266 	int irq;
    267 
    268 	if (vec >= 0x900) {
    269 		irq = (vec - 0x900) >> 4;
    270 
    271 		if(irq >= INTRCNT_OTHER_LEN)
    272 			panic("iointr: irq %d is too high", irq);
    273 		++intrcnt[INTRCNT_OTHER_BASE + irq];
    274 
    275 		if (!alpha_shared_intr_dispatch(dec_6600_pci_intr, irq)) {
    276 			alpha_shared_intr_stray(dec_6600_pci_intr, irq,
    277 			    irqtype);
    278 			if (ALPHA_SHARED_INTR_DISABLE(dec_6600_pci_intr, irq))
    279 				dec_6600_intr_disable(irq);
    280 		}
    281 		return;
    282 	}
    283 #if NSIO
    284 	if (vec >= 0x800) {
    285 		sio_iointr(framep, vec);
    286 		return;
    287 	}
    288 #endif
    289 	panic("iointr: weird vec 0x%lx\n", vec);
    290 }
    291 
    292 void
    293 dec_6600_intr_enable(irq)
    294 	int irq;
    295 {
    296 	alpha_mb();
    297 	STQP(TS_C_DIM0) |= 1UL << irq;
    298 	alpha_mb();
    299 }
    300 
    301 void
    302 dec_6600_intr_disable(irq)
    303 	int irq;
    304 {
    305 	alpha_mb();
    306 	STQP(TS_C_DIM0) &= ~(1UL << irq);
    307 	alpha_mb();
    308 }
    309 
    310 void *
    311 dec_6600_pciide_compat_intr_establish(v, dev, pa, chan, func, arg)
    312 	void *v;
    313 	struct device *dev;
    314 	struct pci_attach_args *pa;
    315 	int chan;
    316 	int (*func) __P((void *));
    317 	void *arg;
    318 {
    319 	pci_chipset_tag_t pc = pa->pa_pc;
    320 	void *cookie = NULL;
    321 	int bus, irq;
    322 
    323 	alpha_pci_decompose_tag(pc, pa->pa_tag, &bus, NULL, NULL);
    324 
    325 	/*
    326 	 * If this isn't PCI bus #0 on the TSP that holds the PCI-ISA
    327 	 * bridge, all bets are off.
    328 	 */
    329 	if (bus != 0 || pc->pc_intr_v != sioprimary)
    330 		return (NULL);
    331 
    332 	irq = PCIIDE_COMPAT_IRQ(chan);
    333 #if NSIO
    334 	cookie = sio_intr_establish(NULL /*XXX*/, irq, IST_EDGE, IPL_BIO,
    335 	    func, arg);
    336 #endif
    337 	return (cookie);
    338 }
    339