1 /* $NetBSD: pci_kn8ae.c,v 1.29 2014/03/21 16:39:29 christos Exp $ */ 2 3 /* 4 * Copyright (c) 1997 by Matthew Jacob 5 * NASA AMES Research Center. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice immediately at the beginning of the file, without modification, 13 * this list of conditions, and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. The name of the author 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 THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 24 * ANY 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 #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */ 34 35 __KERNEL_RCSID(0, "$NetBSD: pci_kn8ae.c,v 1.29 2014/03/21 16:39:29 christos Exp $"); 36 37 #include <sys/types.h> 38 #include <sys/param.h> 39 #include <sys/time.h> 40 #include <sys/systm.h> 41 #include <sys/errno.h> 42 #include <sys/malloc.h> 43 #include <sys/device.h> 44 #include <sys/syslog.h> 45 46 #include <machine/autoconf.h> 47 48 #include <dev/pci/pcireg.h> 49 #include <dev/pci/pcivar.h> 50 51 #include <alpha/pci/dwlpxreg.h> 52 #include <alpha/pci/dwlpxvar.h> 53 #include <alpha/pci/pci_kn8ae.h> 54 55 int dec_kn8ae_intr_map(const struct pci_attach_args *, 56 pci_intr_handle_t *); 57 const char *dec_kn8ae_intr_string(void *, pci_intr_handle_t, char *, size_t); 58 const struct evcnt *dec_kn8ae_intr_evcnt(void *, pci_intr_handle_t); 59 void *dec_kn8ae_intr_establish(void *, pci_intr_handle_t, 60 int, int (*func)(void *), void *); 61 void dec_kn8ae_intr_disestablish(void *, void *); 62 63 static uint32_t imaskcache[DWLPX_NIONODE][DWLPX_NHOSE][NHPC]; 64 65 void kn8ae_spurious(void *, u_long); 66 void kn8ae_enadis_intr(struct dwlpx_config *, pci_intr_handle_t, int); 67 68 void 69 pci_kn8ae_pickintr(struct dwlpx_config *ccp, int first) 70 { 71 int io, hose, dev; 72 pci_chipset_tag_t pc = &ccp->cc_pc; 73 74 pc->pc_intr_v = ccp; 75 pc->pc_intr_map = dec_kn8ae_intr_map; 76 pc->pc_intr_string = dec_kn8ae_intr_string; 77 pc->pc_intr_evcnt = dec_kn8ae_intr_evcnt; 78 pc->pc_intr_establish = dec_kn8ae_intr_establish; 79 pc->pc_intr_disestablish = dec_kn8ae_intr_disestablish; 80 81 /* Not supported on KN8AE. */ 82 pc->pc_pciide_compat_intr_establish = NULL; 83 84 if (!first) { 85 return; 86 } 87 88 for (io = 0; io < DWLPX_NIONODE; io++) { 89 for (hose = 0; hose < DWLPX_NHOSE; hose++) { 90 for (dev = 0; dev < NHPC; dev++) { 91 imaskcache[io][hose][dev] = DWLPX_IMASK_DFLT; 92 } 93 } 94 } 95 } 96 97 #define IH_MAKE(vec, dev, pin) \ 98 ((vec) | ((dev) << 16) | ((pin) << 24)) 99 100 #define IH_VEC(ih) ((ih) & 0xffff) 101 #define IH_DEV(ih) (((ih) >> 16) & 0xff) 102 #define IH_PIN(ih) (((ih) >> 24) & 0xff) 103 104 int 105 dec_kn8ae_intr_map(const struct pci_attach_args *pa, pci_intr_handle_t *ihp) 106 { 107 pcitag_t bustag = pa->pa_intrtag; 108 int buspin = pa->pa_intrpin; 109 pci_chipset_tag_t pc = pa->pa_pc; 110 int device; 111 u_long vec; 112 113 if (buspin == 0) { 114 /* No IRQ used. */ 115 return 1; 116 } 117 if (buspin > 4) { 118 printf("dec_kn8ae_intr_map: bad interrupt pin %d\n", buspin); 119 return 1; 120 } 121 pci_decompose_tag(pc, bustag, NULL, &device, NULL); 122 123 vec = scb_alloc(kn8ae_spurious, NULL); 124 if (vec == SCB_ALLOC_FAILED) { 125 printf("dec_kn8ae_intr_map: no vector available for " 126 "device %d pin %d\n", device, buspin); 127 return 1; 128 } 129 130 *ihp = IH_MAKE(vec, device, buspin); 131 132 return (0); 133 } 134 135 const char * 136 dec_kn8ae_intr_string(void *ccv, pci_intr_handle_t ih, char *buf, size_t len) 137 { 138 snprintf(buf, len, "vector 0x%lx", IH_VEC(ih)); 139 return buf; 140 } 141 142 const struct evcnt * 143 dec_kn8ae_intr_evcnt(void *ccv, pci_intr_handle_t ih) 144 { 145 146 /* XXX for now, no evcnt parent reported */ 147 return (NULL); 148 } 149 150 void * 151 dec_kn8ae_intr_establish( 152 void *ccv, 153 pci_intr_handle_t ih, 154 int level, 155 int (*func)(void *), 156 void *arg) 157 { 158 struct dwlpx_config *ccp = ccv; 159 void *cookie; 160 struct scbvec *scb; 161 u_long vec; 162 int pin, device, hpc; 163 164 device = IH_DEV(ih); 165 pin = IH_PIN(ih); 166 vec = IH_VEC(ih); 167 168 scb = &scb_iovectab[SCB_VECTOIDX(vec - SCB_IOVECBASE)]; 169 170 if (scb->scb_func != kn8ae_spurious) { 171 printf("dec_kn8ae_intr_establish: vector 0x%lx not mapped\n", 172 vec); 173 return (NULL); 174 } 175 176 /* 177 * NOTE: The PCIA hardware doesn't support interrupt sharing, 178 * so we don't have to worry about it (in theory, at least). 179 */ 180 181 scb->scb_arg = arg; 182 alpha_mb(); 183 scb->scb_func = (void (*)(void *, u_long))func; 184 alpha_mb(); 185 186 if (device < 4) { 187 hpc = 0; 188 } else if (device < 8) { 189 device -= 4; 190 hpc = 1; 191 } else { 192 device -= 8; 193 hpc = 2; 194 } 195 REGVAL(PCIA_DEVVEC(hpc, device, pin) + ccp->cc_sysbase) = vec; 196 197 kn8ae_enadis_intr(ccp, ih, 1); 198 199 cookie = (void *) ih; 200 201 return (cookie); 202 } 203 204 void 205 dec_kn8ae_intr_disestablish(void *ccv, void *cookie) 206 { 207 struct dwlpx_config *ccp = ccv; 208 pci_intr_handle_t ih = (u_long) cookie; 209 struct scbvec *scb; 210 u_long vec; 211 212 vec = IH_VEC(ih); 213 214 scb = &scb_iovectab[SCB_VECTOIDX(vec - SCB_IOVECBASE)]; 215 __USE(scb); 216 217 kn8ae_enadis_intr(ccp, ih, 0); 218 219 scb_free(vec); 220 } 221 222 void 223 kn8ae_spurious(void *arg, u_long vec) 224 { 225 printf("Spurious interrupt on temporary interrupt vector 0x%lx\n", vec); 226 } 227 228 void 229 kn8ae_enadis_intr(struct dwlpx_config *ccp, pci_intr_handle_t irq, int onoff) 230 { 231 struct dwlpx_softc *sc = ccp->cc_sc; 232 unsigned long paddr; 233 uint32_t val; 234 int ionode, hose, device, hpc, busp, s; 235 236 ionode = sc->dwlpx_node - 4; 237 hose = sc->dwlpx_hosenum; 238 239 device = IH_DEV(irq); 240 busp = (1 << (IH_PIN(irq) - 1)); 241 242 paddr = (1LL << 39); 243 paddr |= (unsigned long) ionode << 36; 244 paddr |= (unsigned long) hose << 34; 245 246 if (device < 4) { 247 hpc = 0; 248 } else if (device < 8) { 249 hpc = 1; 250 device -= 4; 251 } else { 252 hpc = 2; 253 device -= 8; 254 } 255 busp <<= (device << 2); 256 val = imaskcache[ionode][hose][hpc]; 257 if (onoff) 258 val |= busp; 259 else 260 val &= ~busp; 261 imaskcache[ionode][hose][hpc] = val; 262 #if 0 263 printf("kn8ae_%s_intr: irq %lx imsk 0x%x hpc %d TLSB node %d hose %d\n", 264 onoff? "enable" : "disable", irq, val, hpc, ionode + 4, hose); 265 #endif 266 s = splhigh(); 267 REGVAL(PCIA_IMASK(hpc) + paddr) = val; 268 alpha_mb(); 269 (void) splx(s); 270 } 271