1/*- 2 * Copyright (c) 2001 Doug Rabson 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD: releng/10.3/sys/ia64/ia64/sapic.c 227293 2011-11-07 06:44:47Z ed $ 27 */ 28 29#include "opt_ddb.h" 30 31#include <sys/param.h> 32#include <sys/malloc.h> 33#include <sys/kernel.h> 34#include <sys/systm.h> 35#include <sys/bus.h> 36#include <sys/lock.h> 37#include <sys/mutex.h> 38#include <sys/pcpu.h> 39#include <sys/sysctl.h> 40 41#include <machine/intr.h> 42#include <machine/pal.h> 43 44#include <vm/vm.h> 45#include <vm/pmap.h> 46 47/* 48 * Offsets from the SAPIC base in memory. Most registers are accessed 49 * by indexing using the SAPIC_IO_SELECT register. 50 */ 51#define SAPIC_IO_SELECT 0x00 52#define SAPIC_IO_WINDOW 0x10 53#define SAPIC_APIC_EOI 0x40 54 55/* 56 * Indexed registers. 57 */ 58#define SAPIC_ID 0x00 59#define SAPIC_VERSION 0x01 60#define SAPIC_ARBITRATION_ID 0x02 61#define SAPIC_RTE_BASE 0x10 62 63/* Interrupt polarity. */ 64#define SAPIC_POLARITY_HIGH 0 65#define SAPIC_POLARITY_LOW 1 66 67/* Interrupt trigger. */ 68#define SAPIC_TRIGGER_EDGE 0 69#define SAPIC_TRIGGER_LEVEL 1 70 71/* Interrupt delivery mode. */ 72#define SAPIC_DELMODE_FIXED 0 73#define SAPIC_DELMODE_LOWPRI 1 74#define SAPIC_DELMODE_PMI 2 75#define SAPIC_DELMODE_NMI 4 76#define SAPIC_DELMODE_INIT 5 77#define SAPIC_DELMODE_EXTINT 7 78 79struct sapic { 80 struct mtx sa_mtx; 81 uint64_t sa_registers; /* virtual address of sapic */ 82 u_int sa_id; /* I/O SAPIC Id */ 83 u_int sa_base; /* ACPI vector base */ 84 u_int sa_limit; /* last ACPI vector handled here */ 85}; 86 87struct sapic_rte { 88 uint64_t rte_vector :8; 89 uint64_t rte_delivery_mode :3; 90 uint64_t rte_destination_mode :1; 91 uint64_t rte_delivery_status :1; 92 uint64_t rte_polarity :1; 93 uint64_t rte_rirr :1; 94 uint64_t rte_trigger_mode :1; 95 uint64_t rte_mask :1; 96 uint64_t rte_flushen :1; 97 uint64_t rte_reserved :30; 98 uint64_t rte_destination_eid :8; 99 uint64_t rte_destination_id :8; 100}; 101 102static MALLOC_DEFINE(M_SAPIC, "sapic", "I/O SAPIC devices"); 103 104struct sapic *ia64_sapics[16]; /* XXX make this resizable */ 105int ia64_sapic_count; 106 107static int sysctl_machdep_apic(SYSCTL_HANDLER_ARGS); 108 109SYSCTL_OID(_machdep, OID_AUTO, apic, CTLTYPE_STRING|CTLFLAG_RD, 110 NULL, 0, sysctl_machdep_apic, "A", "(x)APIC redirection table entries"); 111 112static __inline uint32_t 113sapic_read(struct sapic *sa, int which) 114{ 115 uint32_t value; 116 117 ia64_st4((void *)(sa->sa_registers + SAPIC_IO_SELECT), which); 118 ia64_mf_a(); 119 value = ia64_ld4((void *)(sa->sa_registers + SAPIC_IO_WINDOW)); 120 return (value); 121} 122 123static __inline void 124sapic_write(struct sapic *sa, int which, uint32_t value) 125{ 126 127 ia64_st4((void *)(sa->sa_registers + SAPIC_IO_SELECT), which); 128 ia64_mf_a(); 129 ia64_st4((void *)(sa->sa_registers + SAPIC_IO_WINDOW), value); 130 ia64_mf_a(); 131} 132 133static __inline void 134sapic_read_rte(struct sapic *sa, int which, struct sapic_rte *rte) 135{ 136 uint32_t *p = (uint32_t *) rte; 137 138 p[0] = sapic_read(sa, SAPIC_RTE_BASE + 2 * which); 139 p[1] = sapic_read(sa, SAPIC_RTE_BASE + 2 * which + 1); 140} 141 142static __inline void 143sapic_write_rte(struct sapic *sa, int which, struct sapic_rte *rte) 144{ 145 uint32_t *p = (uint32_t *) rte; 146 147 sapic_write(sa, SAPIC_RTE_BASE + 2 * which, p[0]); 148 sapic_write(sa, SAPIC_RTE_BASE + 2 * which + 1, p[1]); 149} 150 151struct sapic * 152sapic_lookup(u_int irq, u_int *vecp) 153{ 154 struct sapic_rte rte; 155 struct sapic *sa; 156 int i; 157 158 for (i = 0; i < ia64_sapic_count; i++) { 159 sa = ia64_sapics[i]; 160 if (irq >= sa->sa_base && irq <= sa->sa_limit) { 161 if (vecp != NULL) { 162 mtx_lock_spin(&sa->sa_mtx); 163 sapic_read_rte(sa, irq - sa->sa_base, &rte); 164 mtx_unlock_spin(&sa->sa_mtx); 165 *vecp = rte.rte_vector; 166 } 167 return (sa); 168 } 169 } 170 171 return (NULL); 172} 173 174 175int 176sapic_bind_intr(u_int irq, struct pcpu *pc) 177{ 178 struct sapic_rte rte; 179 struct sapic *sa; 180 181 sa = sapic_lookup(irq, NULL); 182 if (sa == NULL) 183 return (EINVAL); 184 185 mtx_lock_spin(&sa->sa_mtx); 186 sapic_read_rte(sa, irq - sa->sa_base, &rte); 187 rte.rte_destination_id = (pc->pc_md.lid >> 24) & 255; 188 rte.rte_destination_eid = (pc->pc_md.lid >> 16) & 255; 189 rte.rte_delivery_mode = SAPIC_DELMODE_FIXED; 190 sapic_write_rte(sa, irq - sa->sa_base, &rte); 191 mtx_unlock_spin(&sa->sa_mtx); 192 return (0); 193} 194 195int 196sapic_config_intr(u_int irq, enum intr_trigger trig, enum intr_polarity pol) 197{ 198 struct sapic_rte rte; 199 struct sapic *sa; 200 201 sa = sapic_lookup(irq, NULL); 202 if (sa == NULL) 203 return (EINVAL); 204 205 mtx_lock_spin(&sa->sa_mtx); 206 sapic_read_rte(sa, irq - sa->sa_base, &rte); 207 if (trig != INTR_TRIGGER_CONFORM) 208 rte.rte_trigger_mode = (trig == INTR_TRIGGER_EDGE) ? 209 SAPIC_TRIGGER_EDGE : SAPIC_TRIGGER_LEVEL; 210 else 211 rte.rte_trigger_mode = (irq < 16) ? SAPIC_TRIGGER_EDGE : 212 SAPIC_TRIGGER_LEVEL; 213 if (pol != INTR_POLARITY_CONFORM) 214 rte.rte_polarity = (pol == INTR_POLARITY_HIGH) ? 215 SAPIC_POLARITY_HIGH : SAPIC_POLARITY_LOW; 216 else 217 rte.rte_polarity = (irq < 16) ? SAPIC_POLARITY_HIGH : 218 SAPIC_POLARITY_LOW; 219 sapic_write_rte(sa, irq - sa->sa_base, &rte); 220 mtx_unlock_spin(&sa->sa_mtx); 221 return (0); 222} 223 224struct sapic * 225sapic_create(u_int id, u_int base, uint64_t address) 226{ 227 struct sapic_rte rte; 228 struct sapic *sa; 229 u_int i, max; 230 231 sa = malloc(sizeof(struct sapic), M_SAPIC, M_ZERO | M_NOWAIT); 232 if (sa == NULL) 233 return (NULL); 234 235 sa->sa_id = id; 236 sa->sa_base = base; 237 sa->sa_registers = (uintptr_t)pmap_mapdev(address, 1048576); 238 239 mtx_init(&sa->sa_mtx, "I/O SAPIC lock", NULL, MTX_SPIN); 240 241 max = (sapic_read(sa, SAPIC_VERSION) >> 16) & 0xff; 242 sa->sa_limit = base + max; 243 244 ia64_sapics[ia64_sapic_count++] = sa; 245 246 /* 247 * Initialize all RTEs with a default trigger mode and polarity. 248 * This may be changed later by calling sapic_config_intr(). We 249 * mask all interrupts by default. 250 */ 251 bzero(&rte, sizeof(rte)); 252 rte.rte_mask = 1; 253 for (i = base; i <= sa->sa_limit; i++) { 254 rte.rte_trigger_mode = (i < 16) ? SAPIC_TRIGGER_EDGE : 255 SAPIC_TRIGGER_LEVEL; 256 rte.rte_polarity = (i < 16) ? SAPIC_POLARITY_HIGH : 257 SAPIC_POLARITY_LOW; 258 sapic_write_rte(sa, i - base, &rte); 259 } 260 261 return (sa); 262} 263 264int 265sapic_enable(struct sapic *sa, u_int irq, u_int vector) 266{ 267 struct sapic_rte rte; 268 uint64_t lid = ia64_get_lid(); 269 270 mtx_lock_spin(&sa->sa_mtx); 271 sapic_read_rte(sa, irq - sa->sa_base, &rte); 272 rte.rte_destination_id = (lid >> 24) & 255; 273 rte.rte_destination_eid = (lid >> 16) & 255; 274 rte.rte_delivery_mode = SAPIC_DELMODE_FIXED; 275 rte.rte_vector = vector; 276 rte.rte_mask = 0; 277 sapic_write_rte(sa, irq - sa->sa_base, &rte); 278 mtx_unlock_spin(&sa->sa_mtx); 279 return (0); 280} 281 282void 283sapic_eoi(struct sapic *sa, u_int vector) 284{ 285 286 ia64_st4((void *)(sa->sa_registers + SAPIC_APIC_EOI), vector); 287 ia64_mf_a(); 288} 289 290/* Expected to be called with interrupts disabled. */ 291void 292sapic_mask(struct sapic *sa, u_int irq) 293{ 294 struct sapic_rte rte; 295 296 mtx_lock_spin(&sa->sa_mtx); 297 sapic_read_rte(sa, irq - sa->sa_base, &rte); 298 rte.rte_mask = 1; 299 sapic_write_rte(sa, irq - sa->sa_base, &rte); 300 mtx_unlock_spin(&sa->sa_mtx); 301} 302 303/* Expected to be called with interrupts disabled. */ 304void 305sapic_unmask(struct sapic *sa, u_int irq) 306{ 307 struct sapic_rte rte; 308 309 mtx_lock_spin(&sa->sa_mtx); 310 sapic_read_rte(sa, irq - sa->sa_base, &rte); 311 rte.rte_mask = 0; 312 sapic_write_rte(sa, irq - sa->sa_base, &rte); 313 mtx_unlock_spin(&sa->sa_mtx); 314} 315 316static int 317sysctl_machdep_apic(SYSCTL_HANDLER_ARGS) 318{ 319 char buf[80]; 320 struct sapic_rte rte; 321 struct sapic *sa; 322 int apic, count, error, index, len; 323 324 len = sprintf(buf, "\n APIC Idx: Id,EId : RTE\n"); 325 error = SYSCTL_OUT(req, buf, len); 326 if (error) 327 return (error); 328 329 for (apic = 0; apic < ia64_sapic_count; apic++) { 330 sa = ia64_sapics[apic]; 331 count = sa->sa_limit - sa->sa_base + 1; 332 for (index = 0; index < count; index++) { 333 mtx_lock_spin(&sa->sa_mtx); 334 sapic_read_rte(sa, index, &rte); 335 mtx_unlock_spin(&sa->sa_mtx); 336 if (rte.rte_vector == 0) 337 continue; 338 len = sprintf(buf, 339 " 0x%02x %3d: (%02x,%02x): %3d %d %d %s %s %s %s %s\n", 340 sa->sa_id, index, 341 rte.rte_destination_id, rte.rte_destination_eid, 342 rte.rte_vector, rte.rte_delivery_mode, 343 rte.rte_destination_mode, 344 rte.rte_delivery_status ? "DS" : " ", 345 rte.rte_polarity ? "low-active " : "high-active", 346 rte.rte_rirr ? "RIRR" : " ", 347 rte.rte_trigger_mode ? "level" : "edge ", 348 rte.rte_flushen ? "F" : " "); 349 error = SYSCTL_OUT(req, buf, len); 350 if (error) 351 return (error); 352 } 353 } 354 355 return (0); 356} 357 358#ifdef DDB 359 360#include <ddb/ddb.h> 361 362void 363sapic_print(struct sapic *sa, u_int irq) 364{ 365 struct sapic_rte rte; 366 367 db_printf("sapic=%u, irq=%u: ", sa->sa_id, irq); 368 sapic_read_rte(sa, irq - sa->sa_base, &rte); 369 db_printf("%3d %x->%x:%x %d %s %s %s %s %s %s\n", rte.rte_vector, 370 rte.rte_delivery_mode, 371 rte.rte_destination_id, rte.rte_destination_eid, 372 rte.rte_destination_mode, 373 rte.rte_delivery_status ? "DS" : " ", 374 rte.rte_polarity ? "low-active " : "high-active", 375 rte.rte_rirr ? "RIRR" : " ", 376 rte.rte_trigger_mode ? "level" : "edge ", 377 rte.rte_flushen ? "F" : " ", 378 rte.rte_mask ? "(masked)" : ""); 379} 380 381#endif 382