1 1.34 thorpej /* $NetBSD: pci_kn8ae.c,v 1.34 2021/07/04 22:42:36 thorpej Exp $ */ 2 1.1 cgd 3 1.1 cgd /* 4 1.2 cgd * Copyright (c) 1997 by Matthew Jacob 5 1.1 cgd * NASA AMES Research Center. 6 1.1 cgd * All rights reserved. 7 1.1 cgd * 8 1.1 cgd * Redistribution and use in source and binary forms, with or without 9 1.1 cgd * modification, are permitted provided that the following conditions 10 1.1 cgd * are met: 11 1.1 cgd * 1. Redistributions of source code must retain the above copyright 12 1.1 cgd * notice immediately at the beginning of the file, without modification, 13 1.1 cgd * this list of conditions, and the following disclaimer. 14 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 15 1.1 cgd * notice, this list of conditions and the following disclaimer in the 16 1.1 cgd * documentation and/or other materials provided with the distribution. 17 1.1 cgd * 3. The name of the author may not be used to endorse or promote products 18 1.1 cgd * derived from this software without specific prior written permission. 19 1.1 cgd * 20 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 24 1.1 cgd * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 1.1 cgd * SUCH DAMAGE. 31 1.1 cgd */ 32 1.3 cgd 33 1.4 cgd #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */ 34 1.4 cgd 35 1.34 thorpej __KERNEL_RCSID(0, "$NetBSD: pci_kn8ae.c,v 1.34 2021/07/04 22:42:36 thorpej Exp $"); 36 1.1 cgd 37 1.1 cgd #include <sys/types.h> 38 1.1 cgd #include <sys/param.h> 39 1.1 cgd #include <sys/time.h> 40 1.1 cgd #include <sys/systm.h> 41 1.1 cgd #include <sys/errno.h> 42 1.1 cgd #include <sys/device.h> 43 1.31 thorpej #include <sys/cpu.h> 44 1.1 cgd #include <sys/syslog.h> 45 1.32 thorpej #include <sys/once.h> 46 1.1 cgd 47 1.1 cgd #include <machine/autoconf.h> 48 1.33 thorpej #include <machine/rpb.h> 49 1.1 cgd 50 1.1 cgd #include <dev/pci/pcireg.h> 51 1.1 cgd #include <dev/pci/pcivar.h> 52 1.1 cgd 53 1.1 cgd #include <alpha/pci/dwlpxreg.h> 54 1.1 cgd #include <alpha/pci/dwlpxvar.h> 55 1.1 cgd 56 1.30 thorpej static int dec_kn8ae_intr_map(const struct pci_attach_args *, 57 1.30 thorpej pci_intr_handle_t *); 58 1.30 thorpej static const char *dec_kn8ae_intr_string(pci_chipset_tag_t, pci_intr_handle_t, 59 1.30 thorpej char *, size_t); 60 1.30 thorpej static const struct evcnt *dec_kn8ae_intr_evcnt(pci_chipset_tag_t, 61 1.30 thorpej pci_intr_handle_t); 62 1.30 thorpej static void *dec_kn8ae_intr_establish(pci_chipset_tag_t, pci_intr_handle_t, 63 1.30 thorpej int, int (*func)(void *), void *); 64 1.30 thorpej static void dec_kn8ae_intr_disestablish(pci_chipset_tag_t, void *); 65 1.1 cgd 66 1.27 matt static uint32_t imaskcache[DWLPX_NIONODE][DWLPX_NHOSE][NHPC]; 67 1.1 cgd 68 1.30 thorpej static void kn8ae_spurious(void *, u_long); 69 1.30 thorpej static void kn8ae_enadis_intr(struct dwlpx_config *, pci_intr_handle_t, 70 1.30 thorpej int); 71 1.30 thorpej 72 1.30 thorpej struct kn8ae_wrapped_pci_intr { 73 1.30 thorpej int (*ih_fn)(void *); 74 1.30 thorpej }; 75 1.30 thorpej 76 1.30 thorpej static struct kn8ae_wrapped_pci_intr 77 1.30 thorpej kn8ae_wrapped_pci_intrs[SCB_VECTOIDX(SCB_SIZE - SCB_IOVECBASE)] 78 1.30 thorpej __read_mostly; 79 1.30 thorpej 80 1.30 thorpej static void 81 1.30 thorpej kn8ae_intr_wrapper(void *arg, u_long vec) 82 1.30 thorpej { 83 1.30 thorpej const u_long idx = SCB_VECTOIDX(vec - SCB_IOVECBASE); 84 1.30 thorpej 85 1.30 thorpej KERNEL_LOCK(1, NULL); 86 1.30 thorpej kn8ae_wrapped_pci_intrs[idx].ih_fn(arg); 87 1.30 thorpej KERNEL_UNLOCK_ONE(NULL); 88 1.30 thorpej } 89 1.1 cgd 90 1.32 thorpej static ONCE_DECL(pci_kn8ae_once); 91 1.32 thorpej 92 1.32 thorpej static int 93 1.32 thorpej pci_kn8ae_init_imaskcache(void) 94 1.32 thorpej { 95 1.32 thorpej int io, hose, dev; 96 1.32 thorpej 97 1.32 thorpej for (io = 0; io < DWLPX_NIONODE; io++) { 98 1.32 thorpej for (hose = 0; hose < DWLPX_NHOSE; hose++) { 99 1.32 thorpej for (dev = 0; dev < NHPC; dev++) { 100 1.32 thorpej imaskcache[io][hose][dev] = DWLPX_IMASK_DFLT; 101 1.32 thorpej } 102 1.32 thorpej } 103 1.32 thorpej } 104 1.32 thorpej 105 1.32 thorpej return 0; 106 1.32 thorpej } 107 1.32 thorpej 108 1.33 thorpej static void 109 1.33 thorpej pci_kn8ae_pickintr(void *core, bus_space_tag_t iot, bus_space_tag_t memt, 110 1.33 thorpej pci_chipset_tag_t pc) 111 1.1 cgd { 112 1.1 cgd 113 1.33 thorpej pc->pc_intr_v = core; 114 1.27 matt pc->pc_intr_map = dec_kn8ae_intr_map; 115 1.27 matt pc->pc_intr_string = dec_kn8ae_intr_string; 116 1.15 cgd pc->pc_intr_evcnt = dec_kn8ae_intr_evcnt; 117 1.27 matt pc->pc_intr_establish = dec_kn8ae_intr_establish; 118 1.27 matt pc->pc_intr_disestablish = dec_kn8ae_intr_disestablish; 119 1.11 thorpej 120 1.12 mjacob /* Not supported on KN8AE. */ 121 1.11 thorpej pc->pc_pciide_compat_intr_establish = NULL; 122 1.1 cgd 123 1.32 thorpej RUN_ONCE(&pci_kn8ae_once, pci_kn8ae_init_imaskcache); 124 1.1 cgd } 125 1.33 thorpej ALPHA_PCI_INTR_INIT(ST_DEC_21000, pci_kn8ae_pickintr) 126 1.1 cgd 127 1.19 thorpej #define IH_MAKE(vec, dev, pin) \ 128 1.19 thorpej ((vec) | ((dev) << 16) | ((pin) << 24)) 129 1.19 thorpej 130 1.19 thorpej #define IH_VEC(ih) ((ih) & 0xffff) 131 1.19 thorpej #define IH_DEV(ih) (((ih) >> 16) & 0xff) 132 1.19 thorpej #define IH_PIN(ih) (((ih) >> 24) & 0xff) 133 1.19 thorpej 134 1.30 thorpej static int 135 1.26 dyoung dec_kn8ae_intr_map(const struct pci_attach_args *pa, pci_intr_handle_t *ihp) 136 1.1 cgd { 137 1.18 sommerfe pcitag_t bustag = pa->pa_intrtag; 138 1.18 sommerfe int buspin = pa->pa_intrpin; 139 1.18 sommerfe pci_chipset_tag_t pc = pa->pa_pc; 140 1.19 thorpej int device; 141 1.19 thorpej u_long vec; 142 1.1 cgd 143 1.13 thorpej if (buspin == 0) { 144 1.13 thorpej /* No IRQ used. */ 145 1.13 thorpej return 1; 146 1.13 thorpej } 147 1.30 thorpej if (buspin < 0 || buspin > 4) { 148 1.13 thorpej printf("dec_kn8ae_intr_map: bad interrupt pin %d\n", buspin); 149 1.13 thorpej return 1; 150 1.13 thorpej } 151 1.21 thorpej pci_decompose_tag(pc, bustag, NULL, &device, NULL); 152 1.1 cgd 153 1.31 thorpej mutex_enter(&cpu_lock); 154 1.19 thorpej vec = scb_alloc(kn8ae_spurious, NULL); 155 1.31 thorpej mutex_exit(&cpu_lock); 156 1.19 thorpej if (vec == SCB_ALLOC_FAILED) { 157 1.19 thorpej printf("dec_kn8ae_intr_map: no vector available for " 158 1.19 thorpej "device %d pin %d\n", device, buspin); 159 1.19 thorpej return 1; 160 1.19 thorpej } 161 1.19 thorpej 162 1.30 thorpej alpha_pci_intr_handle_init(ihp, IH_MAKE(vec, device, buspin), 0); 163 1.19 thorpej 164 1.1 cgd return (0); 165 1.1 cgd } 166 1.1 cgd 167 1.30 thorpej static const char * 168 1.30 thorpej dec_kn8ae_intr_string(pci_chipset_tag_t const pc __unused, 169 1.30 thorpej pci_intr_handle_t const ih, char * const buf, size_t const len) 170 1.1 cgd { 171 1.30 thorpej const u_int ihv = alpha_pci_intr_handle_get_irq(&ih); 172 1.30 thorpej 173 1.30 thorpej snprintf(buf, len, "vector 0x%x", IH_VEC(ihv)); 174 1.29 christos return buf; 175 1.15 cgd } 176 1.15 cgd 177 1.30 thorpej static const struct evcnt * 178 1.30 thorpej dec_kn8ae_intr_evcnt(pci_chipset_tag_t const pc __unused, 179 1.30 thorpej pci_intr_handle_t const ih __unused) 180 1.15 cgd { 181 1.15 cgd 182 1.15 cgd /* XXX for now, no evcnt parent reported */ 183 1.15 cgd return (NULL); 184 1.1 cgd } 185 1.1 cgd 186 1.30 thorpej static void * 187 1.27 matt dec_kn8ae_intr_establish( 188 1.30 thorpej pci_chipset_tag_t const pc, 189 1.30 thorpej pci_intr_handle_t const ih, 190 1.30 thorpej int const level, 191 1.27 matt int (*func)(void *), 192 1.27 matt void *arg) 193 1.27 matt { 194 1.30 thorpej struct dwlpx_config * const ccp = pc->pc_intr_v; 195 1.19 thorpej void *cookie; 196 1.19 thorpej struct scbvec *scb; 197 1.19 thorpej u_long vec; 198 1.19 thorpej int pin, device, hpc; 199 1.31 thorpej void (*scb_func)(void *, u_long); 200 1.30 thorpej const u_int ihv = alpha_pci_intr_handle_get_irq(&ih); 201 1.30 thorpej const u_int flags = alpha_pci_intr_handle_get_flags(&ih); 202 1.19 thorpej 203 1.30 thorpej device = IH_DEV(ihv); 204 1.30 thorpej pin = IH_PIN(ihv); 205 1.30 thorpej vec = IH_VEC(ihv); 206 1.19 thorpej 207 1.31 thorpej mutex_enter(&cpu_lock); 208 1.31 thorpej 209 1.20 mjacob scb = &scb_iovectab[SCB_VECTOIDX(vec - SCB_IOVECBASE)]; 210 1.19 thorpej 211 1.19 thorpej if (scb->scb_func != kn8ae_spurious) { 212 1.31 thorpej mutex_exit(&cpu_lock); 213 1.19 thorpej printf("dec_kn8ae_intr_establish: vector 0x%lx not mapped\n", 214 1.19 thorpej vec); 215 1.19 thorpej return (NULL); 216 1.19 thorpej } 217 1.1 cgd 218 1.19 thorpej /* 219 1.19 thorpej * NOTE: The PCIA hardware doesn't support interrupt sharing, 220 1.19 thorpej * so we don't have to worry about it (in theory, at least). 221 1.19 thorpej */ 222 1.19 thorpej 223 1.30 thorpej if (flags & ALPHA_INTR_MPSAFE) { 224 1.31 thorpej scb_func = (void (*)(void *, u_long))func; 225 1.30 thorpej } else { 226 1.30 thorpej kn8ae_wrapped_pci_intrs[ 227 1.30 thorpej SCB_VECTOIDX(vec - SCB_IOVECBASE)].ih_fn = func; 228 1.31 thorpej scb_func = kn8ae_intr_wrapper; 229 1.30 thorpej } 230 1.31 thorpej 231 1.31 thorpej scb_set(vec, scb_func, arg); 232 1.19 thorpej 233 1.19 thorpej if (device < 4) { 234 1.19 thorpej hpc = 0; 235 1.19 thorpej } else if (device < 8) { 236 1.19 thorpej device -= 4; 237 1.19 thorpej hpc = 1; 238 1.19 thorpej } else { 239 1.19 thorpej device -= 8; 240 1.19 thorpej hpc = 2; 241 1.1 cgd } 242 1.31 thorpej 243 1.19 thorpej REGVAL(PCIA_DEVVEC(hpc, device, pin) + ccp->cc_sysbase) = vec; 244 1.31 thorpej kn8ae_enadis_intr(ccp, ih, 1); 245 1.19 thorpej 246 1.31 thorpej mutex_exit(&cpu_lock); 247 1.1 cgd 248 1.30 thorpej cookie = (void *) ih.value; 249 1.1 cgd 250 1.1 cgd return (cookie); 251 1.1 cgd } 252 1.1 cgd 253 1.30 thorpej static void 254 1.30 thorpej dec_kn8ae_intr_disestablish(pci_chipset_tag_t const pc, void * const cookie) 255 1.1 cgd { 256 1.30 thorpej struct dwlpx_config * const ccp = pc->pc_intr_v; 257 1.30 thorpej const u_long ihv = (u_long) cookie; 258 1.30 thorpej pci_intr_handle_t ih = { .value = ihv }; 259 1.19 thorpej u_long vec; 260 1.19 thorpej 261 1.30 thorpej vec = IH_VEC(ihv); 262 1.19 thorpej 263 1.31 thorpej mutex_enter(&cpu_lock); 264 1.1 cgd 265 1.19 thorpej kn8ae_enadis_intr(ccp, ih, 0); 266 1.1 cgd 267 1.19 thorpej scb_free(vec); 268 1.31 thorpej 269 1.31 thorpej mutex_exit(&cpu_lock); 270 1.9 mjacob } 271 1.9 mjacob 272 1.30 thorpej static void 273 1.30 thorpej kn8ae_spurious(void * const arg __unused, u_long const vec) 274 1.1 cgd { 275 1.20 mjacob printf("Spurious interrupt on temporary interrupt vector 0x%lx\n", vec); 276 1.1 cgd } 277 1.1 cgd 278 1.30 thorpej static void 279 1.30 thorpej kn8ae_enadis_intr(struct dwlpx_config *ccp, pci_intr_handle_t ih, int onoff) 280 1.1 cgd { 281 1.19 thorpej struct dwlpx_softc *sc = ccp->cc_sc; 282 1.30 thorpej const u_int ihv = alpha_pci_intr_handle_get_irq(&ih); 283 1.1 cgd unsigned long paddr; 284 1.27 matt uint32_t val; 285 1.31 thorpej int ionode, hose, device, hpc, busp; 286 1.1 cgd 287 1.19 thorpej ionode = sc->dwlpx_node - 4; 288 1.19 thorpej hose = sc->dwlpx_hosenum; 289 1.19 thorpej 290 1.30 thorpej device = IH_DEV(ihv); 291 1.30 thorpej busp = (1 << (IH_PIN(ihv) - 1)); 292 1.19 thorpej 293 1.1 cgd paddr = (1LL << 39); 294 1.1 cgd paddr |= (unsigned long) ionode << 36; 295 1.1 cgd paddr |= (unsigned long) hose << 34; 296 1.19 thorpej 297 1.1 cgd if (device < 4) { 298 1.1 cgd hpc = 0; 299 1.1 cgd } else if (device < 8) { 300 1.1 cgd hpc = 1; 301 1.1 cgd device -= 4; 302 1.1 cgd } else { 303 1.1 cgd hpc = 2; 304 1.1 cgd device -= 8; 305 1.1 cgd } 306 1.1 cgd busp <<= (device << 2); 307 1.1 cgd val = imaskcache[ionode][hose][hpc]; 308 1.1 cgd if (onoff) 309 1.1 cgd val |= busp; 310 1.1 cgd else 311 1.1 cgd val &= ~busp; 312 1.1 cgd imaskcache[ionode][hose][hpc] = val; 313 1.1 cgd #if 0 314 1.30 thorpej printf("kn8ae_%s_intr: ihv %x imsk 0x%x hpc %d TLSB node %d hose %d\n", 315 1.30 thorpej onoff? "enable" : "disable", ihv, val, hpc, ionode + 4, hose); 316 1.1 cgd #endif 317 1.31 thorpej const u_long psl = alpha_pal_swpipl(ALPHA_PSL_IPL_HIGH); 318 1.1 cgd REGVAL(PCIA_IMASK(hpc) + paddr) = val; 319 1.1 cgd alpha_mb(); 320 1.31 thorpej alpha_pal_swpipl(psl); 321 1.1 cgd } 322