Home | History | Annotate | Line # | Download | only in pci
pci_550.c revision 1.2
      1 /* $NetBSD: pci_550.c,v 1.2 1998/06/05 03:34:27 ross Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 1998 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Andrew Gallatin and Jason R. Thorpe.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  * 3. All advertising materials mentioning features or use of this software
     19  *    must display the following acknowledgement:
     20  *	This product includes software developed by the NetBSD
     21  *	Foundation, Inc. and its contributors.
     22  * 4. Neither the name of The NetBSD Foundation nor the names of its
     23  *    contributors may be used to endorse or promote products derived
     24  *    from this software without specific prior written permission.
     25  *
     26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     36  * POSSIBILITY OF SUCH DAMAGE.
     37  */
     38 
     39 /*
     40  * Copyright (c) 1995, 1996 Carnegie-Mellon University.
     41  * All rights reserved.
     42  *
     43  * Author: Chris G. Demetriou
     44  *
     45  * Permission to use, copy, modify and distribute this software and
     46  * its documentation is hereby granted, provided that both the copyright
     47  * notice and this permission notice appear in all copies of the
     48  * software, derivative works or modified versions, and any portions
     49  * thereof, and that both notices appear in supporting documentation.
     50  *
     51  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
     52  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
     53  * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
     54  *
     55  * Carnegie Mellon requests users of this software to return to
     56  *
     57  *  Software Distribution Coordinator  or  Software.Distribution (at) CS.CMU.EDU
     58  *  School of Computer Science
     59  *  Carnegie Mellon University
     60  *  Pittsburgh PA 15213-3890
     61  *
     62  * any improvements or extensions that they make and grant Carnegie the
     63  * rights to redistribute these changes.
     64  */
     65 
     66 #include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
     67 
     68 __KERNEL_RCSID(0, "$NetBSD: pci_550.c,v 1.2 1998/06/05 03:34:27 ross Exp $");
     69 
     70 #include <sys/types.h>
     71 #include <sys/param.h>
     72 #include <sys/time.h>
     73 #include <sys/systm.h>
     74 #include <sys/errno.h>
     75 #include <sys/malloc.h>
     76 #include <sys/device.h>
     77 #include <sys/syslog.h>
     78 
     79 #include <vm/vm.h>
     80 
     81 #include <machine/autoconf.h>
     82 
     83 #include <dev/pci/pcireg.h>
     84 #include <dev/pci/pcivar.h>
     85 #include <dev/pci/pciidereg.h>
     86 #include <dev/pci/pciidevar.h>
     87 
     88 #include <alpha/pci/ciareg.h>
     89 #include <alpha/pci/ciavar.h>
     90 
     91 #include <alpha/pci/pci_550.h>
     92 
     93 #ifndef EVCNT_COUNTERS
     94 #include <machine/intrcnt.h>
     95 #endif
     96 
     97 #include "sio.h"
     98 #if NSIO
     99 #include <alpha/pci/siovar.h>
    100 #endif
    101 
    102 int	dec_550_intr_map __P((void *, pcitag_t, int, int,
    103 	    pci_intr_handle_t *));
    104 const char *dec_550_intr_string __P((void *, pci_intr_handle_t));
    105 void	*dec_550_intr_establish __P((void *, pci_intr_handle_t,
    106 	    int, int (*func)(void *), void *));
    107 void	dec_550_intr_disestablish __P((void *, void *));
    108 
    109 void	*dec_550_pciide_compat_intr_establish __P((void *, struct device *,
    110 	    struct pci_attach_args *, int, int (*)(void *), void *));
    111 
    112 #define	DEC_550_PCI_IRQ_BEGIN	8
    113 #define	DEC_550_MAX_IRQ		48
    114 #define	PCI_STRAY_MAX		5
    115 
    116 struct alpha_shared_intr *dec_550_pci_intr;
    117 #ifdef EVCNT_COUNTERS
    118 struct evcnt dec_550_intr_evcnt;
    119 #endif
    120 
    121 void	dec_550_iointr __P((void *framep, unsigned long vec));
    122 void	dec_550_intr_enable __P((int irq));
    123 void	dec_550_intr_disable __P((int irq));
    124 
    125 u_int64_t *dec_550_int_mask_reg;
    126 
    127 void
    128 pci_550_pickintr(ccp)
    129 	struct cia_config *ccp;
    130 {
    131 	bus_space_tag_t iot = &ccp->cc_iot;
    132 	pci_chipset_tag_t pc = &ccp->cc_pc;
    133 	int i;
    134 
    135         pc->pc_intr_v = ccp;
    136         pc->pc_intr_map = dec_550_intr_map;
    137         pc->pc_intr_string = dec_550_intr_string;
    138         pc->pc_intr_establish = dec_550_intr_establish;
    139         pc->pc_intr_disestablish = dec_550_intr_disestablish;
    140 
    141 	pc->pc_pciide_compat_intr_establish =
    142 	    dec_550_pciide_compat_intr_establish;
    143 
    144 	/*
    145 	 * DEC 550's interrupts are enabled via the Pyxis interrupt
    146 	 * mask register.
    147 	 */
    148 	dec_550_int_mask_reg =
    149 	    (u_int64_t *)ALPHA_PHYS_TO_K0SEG(PYXIS_INT_MASK);
    150 
    151 	for (i = DEC_550_PCI_IRQ_BEGIN; i < DEC_550_MAX_IRQ; i++)
    152 		dec_550_intr_disable(i);
    153 
    154 	dec_550_pci_intr = alpha_shared_intr_alloc(DEC_550_MAX_IRQ);
    155 	for (i = 0; i < DEC_550_MAX_IRQ; i++)
    156 		alpha_shared_intr_set_maxstrays(dec_550_pci_intr, i,
    157 			PCI_STRAY_MAX);
    158 
    159 #if NSIO
    160 	sio_intr_setup(pc, iot);
    161 #endif
    162 
    163 	set_iointr(dec_550_iointr);
    164 }
    165 
    166 int
    167 dec_550_intr_map(ccv, bustag, buspin, line, ihp)
    168         void *ccv;
    169         pcitag_t bustag;
    170         int buspin, line;
    171         pci_intr_handle_t *ihp;
    172 {
    173 	struct cia_config *ccp = ccv;
    174 	pci_chipset_tag_t pc = &ccp->cc_pc;
    175 	int bus, device, function;
    176 
    177 	if (buspin == 0) {
    178 		/* No IRQ used. */
    179 		return 1;
    180 	}
    181 	if (buspin > 4) {
    182 		printf("dec_550_intr_map: bad interrupt pin %d\n", buspin);
    183 		return 1;
    184 	}
    185 
    186 	alpha_pci_decompose_tag(pc, bustag, &bus, &device, &function);
    187 
    188 	/*
    189 	 * The PCI-ISA bridge lives on device 7 of bus 0.  On the MiataGL
    190 	 * this is a Cypress chip with PCI IDE wired to compatibility
    191 	 * mode on functions 1 and 2.  There will be no interrupt mapping
    192 	 * for this device, so just bail out now.
    193 	 */
    194 	if (bus == 0 && device == 7) {
    195 		if (function == 0)
    196 			panic("dec_550_intr_map: SIO device");
    197 	}
    198 
    199 	/*
    200 	 * The console places the interrupt mapping in the "line" value.
    201 	 * A value of (char)-1 indicates there is no mapping.
    202 	 */
    203 	if (line == 0xff) {
    204 		printf("dec_550_intr_map: no mapping for %d/%d/%d\n",
    205 		    bus, device, function);
    206 		return (1);
    207 	}
    208 
    209 	/* Account for the PCI interrupt offset. */
    210 	line += DEC_550_PCI_IRQ_BEGIN;
    211 
    212 	if (line >= DEC_550_MAX_IRQ)
    213 		panic("dec_550_intr_map: dec 550 irq too large (%d)\n",
    214 		    line);
    215 
    216 	*ihp = line;
    217 	return (0);
    218 }
    219 
    220 const char *
    221 dec_550_intr_string(ccv, ih)
    222 	void *ccv;
    223 	pci_intr_handle_t ih;
    224 {
    225 #if 0
    226 	struct cia_config *ccp = ccv;
    227 #endif
    228 	static char irqstr[16];		/* 12 + 2 + NULL + sanity */
    229 
    230 	if (ih >= DEC_550_MAX_IRQ)
    231 		panic("dec_550_intr_string: bogus 550 IRQ 0x%x\n", ih);
    232 	sprintf(irqstr, "dec 550 irq %d", ih);
    233 	return (irqstr);
    234 }
    235 
    236 void *
    237 dec_550_intr_establish(ccv, ih, level, func, arg)
    238 	void *ccv, *arg;
    239 	pci_intr_handle_t ih;
    240 	int level;
    241 	int (*func) __P((void *));
    242 {
    243 #if 0
    244 	struct cia_config *ccp = ccv;
    245 #endif
    246 	void *cookie;
    247 
    248 	if (ih >= DEC_550_MAX_IRQ)
    249 		panic("dec_550_intr_establish: bogus dec 550 IRQ 0x%x\n", ih);
    250 
    251 	cookie = alpha_shared_intr_establish(dec_550_pci_intr, ih, IST_LEVEL,
    252 	    level, func, arg, "dec 550 irq");
    253 
    254 	if (cookie != NULL && alpha_shared_intr_isactive(dec_550_pci_intr, ih))
    255 		dec_550_intr_enable(ih);
    256 	return (cookie);
    257 }
    258 
    259 void
    260 dec_550_intr_disestablish(ccv, cookie)
    261         void *ccv, *cookie;
    262 {
    263 #if 0
    264 	struct cia_config *ccp = ccv;
    265 #endif
    266 
    267 	panic("dec_550_intr_disestablish not implemented"); /* XXX */
    268 }
    269 
    270 void *
    271 dec_550_pciide_compat_intr_establish(v, dev, pa, chan, func, arg)
    272 	void *v;
    273 	struct device *dev;
    274 	struct pci_attach_args *pa;
    275 	int chan;
    276 	int (*func) __P((void *));
    277 	void *arg;
    278 {
    279 	pci_chipset_tag_t pc = pa->pa_pc;
    280 	void *cookie = NULL;
    281 	int bus, irq;
    282 
    283 	alpha_pci_decompose_tag(pc, pa->pa_tag, &bus, NULL, NULL);
    284 
    285 	/*
    286 	 * If this isn't PCI bus #0, all bets are off.
    287 	 */
    288 	if (bus != 0)
    289 		return (NULL);
    290 
    291 	irq = PCIIDE_COMPAT_IRQ(chan);
    292 #if NSIO
    293 	cookie = sio_intr_establish(NULL /*XXX*/, irq, IST_EDGE, IPL_BIO,
    294 	    func, arg);
    295 #endif
    296 	return (cookie);
    297 }
    298 
    299 void
    300 dec_550_iointr(framep, vec)
    301 	void *framep;
    302 	unsigned long vec;
    303 {
    304 	int irq;
    305 
    306 	if (vec >= 0x900) {
    307 		irq = ((vec - 0x900) >> 4) + DEC_550_PCI_IRQ_BEGIN;
    308 
    309 		if (irq >= DEC_550_MAX_IRQ)
    310 			panic("550_iointr: vec 0x%x out of range\n", vec);
    311 
    312 #ifdef EVCNT_COUNTERS
    313 		dec_550_intr_evcnt.ev_count++;
    314 #else
    315 		if (DEC_550_MAX_IRQ != INTRCNT_DEC_550_IRQ_LEN)
    316 			panic("dec_550 interrupt counter sizes inconsistent");
    317 		intrcnt[INTRCNT_DEC_550_IRQ + irq]++;
    318 #endif
    319 
    320 		if (!alpha_shared_intr_dispatch(dec_550_pci_intr, irq)) {
    321 			alpha_shared_intr_stray(dec_550_pci_intr, irq,
    322 			    "dec 550 irq");
    323 			if (dec_550_pci_intr[irq].intr_nstrays ==
    324 			    dec_550_pci_intr[irq].intr_maxstrays)
    325 				dec_550_intr_disable(irq);
    326 		}
    327 		return;
    328 	}
    329 #if NSIO
    330 	if (vec >= 0x800) {
    331 		sio_iointr(framep, vec);
    332 		return;
    333 	}
    334 #endif
    335 	panic("dec_550_iointr: weird vec 0x%x\n", vec);
    336 }
    337 
    338 void
    339 dec_550_intr_enable(irq)
    340 	int irq;
    341 {
    342 	u_int64_t imask;
    343 	int s;
    344 
    345 #if 1
    346 	printf("dec_550_intr_enable: enabling %d\n", irq);
    347 #endif
    348 
    349 	s = splhigh();
    350 	alpha_mb();
    351 	imask = *dec_550_int_mask_reg;
    352 	imask |= (1UL << irq);
    353 	*dec_550_int_mask_reg = imask;
    354 	alpha_mb();
    355 	splx(s);
    356 }
    357 
    358 void
    359 dec_550_intr_disable(irq)
    360 	int irq;
    361 {
    362 	u_int64_t imask;
    363 	int s;
    364 
    365 #if 1
    366 	printf("dec_550_intr_disable: disabling %d\n", irq);
    367 #endif
    368 
    369 	s = splhigh();
    370 	alpha_mb();
    371 	imask = *dec_550_int_mask_reg;
    372 	imask &= ~(1UL << irq);
    373 	*dec_550_int_mask_reg = imask;
    374 	alpha_mb();
    375 	splx(s);
    376 }
    377