184543Sdfr/*- 284543Sdfr * Copyright (c) 2001 Doug Rabson 384543Sdfr * All rights reserved. 484543Sdfr * 584543Sdfr * Redistribution and use in source and binary forms, with or without 684543Sdfr * modification, are permitted provided that the following conditions 784543Sdfr * are met: 884543Sdfr * 1. Redistributions of source code must retain the above copyright 984543Sdfr * notice, this list of conditions and the following disclaimer. 1084543Sdfr * 2. Redistributions in binary form must reproduce the above copyright 1184543Sdfr * notice, this list of conditions and the following disclaimer in the 1284543Sdfr * documentation and/or other materials provided with the distribution. 1384543Sdfr * 1484543Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1584543Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1684543Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1784543Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1884543Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1984543Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2084543Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2184543Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2284543Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2384543Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2484543Sdfr * SUCH DAMAGE. 2584543Sdfr * 2684543Sdfr * $FreeBSD$ 2784543Sdfr */ 2884543Sdfr 2992267Sdfr#include "opt_ddb.h" 3092267Sdfr 3184543Sdfr#include <sys/param.h> 3284543Sdfr#include <sys/malloc.h> 3384543Sdfr#include <sys/kernel.h> 3484543Sdfr#include <sys/systm.h> 3592668Speter#include <sys/bus.h> 36171664Smarcel#include <sys/lock.h> 37171664Smarcel#include <sys/mutex.h> 38205726Smarcel#include <sys/pcpu.h> 39119970Smarcel#include <sys/sysctl.h> 40119970Smarcel 4192668Speter#include <machine/intr.h> 42108737Smarcel#include <machine/pal.h> 4384543Sdfr 44203883Smarcel#include <vm/vm.h> 45203883Smarcel#include <vm/pmap.h> 46203883Smarcel 47204425Smarcel/* 48204425Smarcel * Offsets from the SAPIC base in memory. Most registers are accessed 49204425Smarcel * by indexing using the SAPIC_IO_SELECT register. 50204425Smarcel */ 51204425Smarcel#define SAPIC_IO_SELECT 0x00 52204425Smarcel#define SAPIC_IO_WINDOW 0x10 53204425Smarcel#define SAPIC_APIC_EOI 0x40 5484543Sdfr 55204425Smarcel/* 56204425Smarcel * Indexed registers. 57204425Smarcel */ 58204425Smarcel#define SAPIC_ID 0x00 59204425Smarcel#define SAPIC_VERSION 0x01 60204425Smarcel#define SAPIC_ARBITRATION_ID 0x02 61204425Smarcel#define SAPIC_RTE_BASE 0x10 62108759Smarcel 63204425Smarcel/* Interrupt polarity. */ 64204425Smarcel#define SAPIC_POLARITY_HIGH 0 65204425Smarcel#define SAPIC_POLARITY_LOW 1 66108759Smarcel 67204425Smarcel/* Interrupt trigger. */ 68204425Smarcel#define SAPIC_TRIGGER_EDGE 0 69204425Smarcel#define SAPIC_TRIGGER_LEVEL 1 70108759Smarcel 71204425Smarcel/* Interrupt delivery mode. */ 72204425Smarcel#define SAPIC_DELMODE_FIXED 0 73204425Smarcel#define SAPIC_DELMODE_LOWPRI 1 74204425Smarcel#define SAPIC_DELMODE_PMI 2 75204425Smarcel#define SAPIC_DELMODE_NMI 4 76204425Smarcel#define SAPIC_DELMODE_INIT 5 77204425Smarcel#define SAPIC_DELMODE_EXTINT 7 78204425Smarcel 79204425Smarcelstruct sapic { 80204425Smarcel struct mtx sa_mtx; 81204425Smarcel uint64_t sa_registers; /* virtual address of sapic */ 82204425Smarcel u_int sa_id; /* I/O SAPIC Id */ 83204425Smarcel u_int sa_base; /* ACPI vector base */ 84204425Smarcel u_int sa_limit; /* last ACPI vector handled here */ 85204425Smarcel}; 86204425Smarcel 8784543Sdfrstruct sapic_rte { 88204425Smarcel uint64_t rte_vector :8; 89204425Smarcel uint64_t rte_delivery_mode :3; 90204425Smarcel uint64_t rte_destination_mode :1; 91204425Smarcel uint64_t rte_delivery_status :1; 92204425Smarcel uint64_t rte_polarity :1; 93204425Smarcel uint64_t rte_rirr :1; 94204425Smarcel uint64_t rte_trigger_mode :1; 95204425Smarcel uint64_t rte_mask :1; 96204425Smarcel uint64_t rte_flushen :1; 97204425Smarcel uint64_t rte_reserved :30; 98204425Smarcel uint64_t rte_destination_eid :8; 99204425Smarcel uint64_t rte_destination_id :8; 10084543Sdfr}; 10184543Sdfr 102249132Smavstatic MALLOC_DEFINE(M_SAPIC, "sapic", "I/O SAPIC devices"); 103171664Smarcel 104204425Smarcelstruct sapic *ia64_sapics[16]; /* XXX make this resizable */ 105204425Smarcelint ia64_sapic_count; 106171664Smarcel 107204425Smarcelstatic int sysctl_machdep_apic(SYSCTL_HANDLER_ARGS); 108171664Smarcel 109204425SmarcelSYSCTL_OID(_machdep, OID_AUTO, apic, CTLTYPE_STRING|CTLFLAG_RD, 110204425Smarcel NULL, 0, sysctl_machdep_apic, "A", "(x)APIC redirection table entries"); 111204425Smarcel 112204425Smarcelstatic __inline uint32_t 11384543Sdfrsapic_read(struct sapic *sa, int which) 11484543Sdfr{ 115204425Smarcel uint32_t value; 11684543Sdfr 117204425Smarcel ia64_st4((void *)(sa->sa_registers + SAPIC_IO_SELECT), which); 118204425Smarcel ia64_mf_a(); 119204425Smarcel value = ia64_ld4((void *)(sa->sa_registers + SAPIC_IO_WINDOW)); 120204425Smarcel return (value); 12184543Sdfr} 12284543Sdfr 123171664Smarcelstatic __inline void 124204425Smarcelsapic_write(struct sapic *sa, int which, uint32_t value) 12584543Sdfr{ 12684543Sdfr 127204425Smarcel ia64_st4((void *)(sa->sa_registers + SAPIC_IO_SELECT), which); 128204425Smarcel ia64_mf_a(); 129204425Smarcel ia64_st4((void *)(sa->sa_registers + SAPIC_IO_WINDOW), value); 130204425Smarcel ia64_mf_a(); 13184543Sdfr} 13284543Sdfr 133171664Smarcelstatic __inline void 134108759Smarcelsapic_read_rte(struct sapic *sa, int which, struct sapic_rte *rte) 13584543Sdfr{ 136204425Smarcel uint32_t *p = (uint32_t *) rte; 13792782Sdfr 138171664Smarcel p[0] = sapic_read(sa, SAPIC_RTE_BASE + 2 * which); 139171664Smarcel p[1] = sapic_read(sa, SAPIC_RTE_BASE + 2 * which + 1); 14084543Sdfr} 14184543Sdfr 142171664Smarcelstatic __inline void 143119970Smarcelsapic_write_rte(struct sapic *sa, int which, struct sapic_rte *rte) 14484543Sdfr{ 145204425Smarcel uint32_t *p = (uint32_t *) rte; 14692782Sdfr 147204425Smarcel sapic_write(sa, SAPIC_RTE_BASE + 2 * which, p[0]); 148204425Smarcel sapic_write(sa, SAPIC_RTE_BASE + 2 * which + 1, p[1]); 14984543Sdfr} 15084543Sdfr 151204425Smarcelstruct sapic * 152204425Smarcelsapic_lookup(u_int irq, u_int *vecp) 153204425Smarcel{ 154204425Smarcel struct sapic_rte rte; 155204425Smarcel struct sapic *sa; 156204425Smarcel int i; 157204425Smarcel 158204425Smarcel for (i = 0; i < ia64_sapic_count; i++) { 159204425Smarcel sa = ia64_sapics[i]; 160204425Smarcel if (irq >= sa->sa_base && irq <= sa->sa_limit) { 161204425Smarcel if (vecp != NULL) { 162204425Smarcel mtx_lock_spin(&sa->sa_mtx); 163204425Smarcel sapic_read_rte(sa, irq - sa->sa_base, &rte); 164204425Smarcel mtx_unlock_spin(&sa->sa_mtx); 165204425Smarcel *vecp = rte.rte_vector; 166204425Smarcel } 167204425Smarcel return (sa); 168204425Smarcel } 169204425Smarcel } 170204425Smarcel 171204425Smarcel return (NULL); 172204425Smarcel} 173204425Smarcel 174204425Smarcel 175119970Smarcelint 176205726Smarcelsapic_bind_intr(u_int irq, struct pcpu *pc) 177205726Smarcel{ 178205726Smarcel struct sapic_rte rte; 179205726Smarcel struct sapic *sa; 180205726Smarcel 181205726Smarcel sa = sapic_lookup(irq, NULL); 182205726Smarcel if (sa == NULL) 183205726Smarcel return (EINVAL); 184205726Smarcel 185205726Smarcel mtx_lock_spin(&sa->sa_mtx); 186205726Smarcel sapic_read_rte(sa, irq - sa->sa_base, &rte); 187205726Smarcel rte.rte_destination_id = (pc->pc_md.lid >> 24) & 255; 188205726Smarcel rte.rte_destination_eid = (pc->pc_md.lid >> 16) & 255; 189205726Smarcel rte.rte_delivery_mode = SAPIC_DELMODE_FIXED; 190205726Smarcel sapic_write_rte(sa, irq - sa->sa_base, &rte); 191205726Smarcel mtx_unlock_spin(&sa->sa_mtx); 192205726Smarcel return (0); 193205726Smarcel} 194205726Smarcel 195205726Smarcelint 196171664Smarcelsapic_config_intr(u_int irq, enum intr_trigger trig, enum intr_polarity pol) 197119970Smarcel{ 198119970Smarcel struct sapic_rte rte; 199119970Smarcel struct sapic *sa; 200119970Smarcel 201204425Smarcel sa = sapic_lookup(irq, NULL); 202171664Smarcel if (sa == NULL) 203171664Smarcel return (EINVAL); 204119970Smarcel 205171664Smarcel mtx_lock_spin(&sa->sa_mtx); 206171664Smarcel sapic_read_rte(sa, irq - sa->sa_base, &rte); 207171664Smarcel if (trig != INTR_TRIGGER_CONFORM) 208171664Smarcel rte.rte_trigger_mode = (trig == INTR_TRIGGER_EDGE) ? 209171664Smarcel SAPIC_TRIGGER_EDGE : SAPIC_TRIGGER_LEVEL; 210171664Smarcel else 211171664Smarcel rte.rte_trigger_mode = (irq < 16) ? SAPIC_TRIGGER_EDGE : 212171664Smarcel SAPIC_TRIGGER_LEVEL; 213171664Smarcel if (pol != INTR_POLARITY_CONFORM) 214171664Smarcel rte.rte_polarity = (pol == INTR_POLARITY_HIGH) ? 215171664Smarcel SAPIC_POLARITY_HIGH : SAPIC_POLARITY_LOW; 216171664Smarcel else 217171664Smarcel rte.rte_polarity = (irq < 16) ? SAPIC_POLARITY_HIGH : 218171664Smarcel SAPIC_POLARITY_LOW; 219171664Smarcel sapic_write_rte(sa, irq - sa->sa_base, &rte); 220171664Smarcel mtx_unlock_spin(&sa->sa_mtx); 221171664Smarcel return (0); 222119970Smarcel} 223119970Smarcel 22484543Sdfrstruct sapic * 225204425Smarcelsapic_create(u_int id, u_int base, uint64_t address) 22684543Sdfr{ 227119970Smarcel struct sapic_rte rte; 22884543Sdfr struct sapic *sa; 229171664Smarcel u_int i, max; 23084543Sdfr 231171664Smarcel sa = malloc(sizeof(struct sapic), M_SAPIC, M_ZERO | M_NOWAIT); 232171664Smarcel if (sa == NULL) 233171664Smarcel return (NULL); 23484543Sdfr 23584543Sdfr sa->sa_id = id; 23684543Sdfr sa->sa_base = base; 237203883Smarcel sa->sa_registers = (uintptr_t)pmap_mapdev(address, 1048576); 23884543Sdfr 239171664Smarcel mtx_init(&sa->sa_mtx, "I/O SAPIC lock", NULL, MTX_SPIN); 240171664Smarcel 24184543Sdfr max = (sapic_read(sa, SAPIC_VERSION) >> 16) & 0xff; 24284543Sdfr sa->sa_limit = base + max; 24384543Sdfr 244108759Smarcel ia64_sapics[ia64_sapic_count++] = sa; 24584543Sdfr 246119970Smarcel /* 247119970Smarcel * Initialize all RTEs with a default trigger mode and polarity. 248119970Smarcel * This may be changed later by calling sapic_config_intr(). We 249119970Smarcel * mask all interrupts by default. 250119970Smarcel */ 251119970Smarcel bzero(&rte, sizeof(rte)); 252119970Smarcel rte.rte_mask = 1; 253119970Smarcel for (i = base; i <= sa->sa_limit; i++) { 254119970Smarcel rte.rte_trigger_mode = (i < 16) ? SAPIC_TRIGGER_EDGE : 255119970Smarcel SAPIC_TRIGGER_LEVEL; 256119970Smarcel rte.rte_polarity = (i < 16) ? SAPIC_POLARITY_HIGH : 257119970Smarcel SAPIC_POLARITY_LOW; 258119970Smarcel sapic_write_rte(sa, i - base, &rte); 259119970Smarcel } 260119970Smarcel 261119970Smarcel return (sa); 26284543Sdfr} 26384543Sdfr 264119970Smarcelint 265171664Smarcelsapic_enable(struct sapic *sa, u_int irq, u_int vector) 26684543Sdfr{ 26784543Sdfr struct sapic_rte rte; 268119970Smarcel uint64_t lid = ia64_get_lid(); 26984543Sdfr 270171664Smarcel mtx_lock_spin(&sa->sa_mtx); 271171664Smarcel sapic_read_rte(sa, irq - sa->sa_base, &rte); 272171664Smarcel rte.rte_destination_id = (lid >> 24) & 255; 273171664Smarcel rte.rte_destination_eid = (lid >> 16) & 255; 274178206Smarcel rte.rte_delivery_mode = SAPIC_DELMODE_FIXED; 275171664Smarcel rte.rte_vector = vector; 276171664Smarcel rte.rte_mask = 0; 277171664Smarcel sapic_write_rte(sa, irq - sa->sa_base, &rte); 278171664Smarcel mtx_unlock_spin(&sa->sa_mtx); 279171664Smarcel return (0); 28084543Sdfr} 28184543Sdfr 28284543Sdfrvoid 283171664Smarcelsapic_eoi(struct sapic *sa, u_int vector) 28484543Sdfr{ 28584543Sdfr 286204425Smarcel ia64_st4((void *)(sa->sa_registers + SAPIC_APIC_EOI), vector); 287204425Smarcel ia64_mf_a(); 28884543Sdfr} 28984543Sdfr 290171664Smarcel/* Expected to be called with interrupts disabled. */ 291171664Smarcelvoid 292171664Smarcelsapic_mask(struct sapic *sa, u_int irq) 293171664Smarcel{ 294171664Smarcel struct sapic_rte rte; 295171664Smarcel 296171664Smarcel mtx_lock_spin(&sa->sa_mtx); 297171664Smarcel sapic_read_rte(sa, irq - sa->sa_base, &rte); 298171664Smarcel rte.rte_mask = 1; 299171664Smarcel sapic_write_rte(sa, irq - sa->sa_base, &rte); 300171664Smarcel mtx_unlock_spin(&sa->sa_mtx); 301171664Smarcel} 302171664Smarcel 303171664Smarcel/* Expected to be called with interrupts disabled. */ 304171664Smarcelvoid 305171664Smarcelsapic_unmask(struct sapic *sa, u_int irq) 306171664Smarcel{ 307171664Smarcel struct sapic_rte rte; 308171664Smarcel 309171664Smarcel mtx_lock_spin(&sa->sa_mtx); 310171664Smarcel sapic_read_rte(sa, irq - sa->sa_base, &rte); 311171664Smarcel rte.rte_mask = 0; 312171664Smarcel sapic_write_rte(sa, irq - sa->sa_base, &rte); 313171664Smarcel mtx_unlock_spin(&sa->sa_mtx); 314171664Smarcel} 315171664Smarcel 316108759Smarcelstatic int 317108759Smarcelsysctl_machdep_apic(SYSCTL_HANDLER_ARGS) 318108759Smarcel{ 319108759Smarcel char buf[80]; 320108759Smarcel struct sapic_rte rte; 321108759Smarcel struct sapic *sa; 322108759Smarcel int apic, count, error, index, len; 323108759Smarcel 324108759Smarcel len = sprintf(buf, "\n APIC Idx: Id,EId : RTE\n"); 325108759Smarcel error = SYSCTL_OUT(req, buf, len); 326108759Smarcel if (error) 327108759Smarcel return (error); 328108759Smarcel 329108759Smarcel for (apic = 0; apic < ia64_sapic_count; apic++) { 330108759Smarcel sa = ia64_sapics[apic]; 331108759Smarcel count = sa->sa_limit - sa->sa_base + 1; 332108759Smarcel for (index = 0; index < count; index++) { 333171664Smarcel mtx_lock_spin(&sa->sa_mtx); 334108759Smarcel sapic_read_rte(sa, index, &rte); 335171664Smarcel mtx_unlock_spin(&sa->sa_mtx); 336171664Smarcel if (rte.rte_vector == 0) 337108759Smarcel continue; 338108759Smarcel len = sprintf(buf, 339108759Smarcel " 0x%02x %3d: (%02x,%02x): %3d %d %d %s %s %s %s %s\n", 340108759Smarcel sa->sa_id, index, 341108759Smarcel rte.rte_destination_id, rte.rte_destination_eid, 342108759Smarcel rte.rte_vector, rte.rte_delivery_mode, 343108759Smarcel rte.rte_destination_mode, 344108759Smarcel rte.rte_delivery_status ? "DS" : " ", 345108759Smarcel rte.rte_polarity ? "low-active " : "high-active", 346108759Smarcel rte.rte_rirr ? "RIRR" : " ", 347108759Smarcel rte.rte_trigger_mode ? "level" : "edge ", 348108759Smarcel rte.rte_flushen ? "F" : " "); 349108759Smarcel error = SYSCTL_OUT(req, buf, len); 350108759Smarcel if (error) 351108759Smarcel return (error); 352108759Smarcel } 353108759Smarcel } 354108759Smarcel 355108759Smarcel return (0); 356108759Smarcel} 357108759Smarcel 35892267Sdfr#ifdef DDB 35992267Sdfr 36092267Sdfr#include <ddb/ddb.h> 36192267Sdfr 36292267Sdfrvoid 363171664Smarcelsapic_print(struct sapic *sa, u_int irq) 36492267Sdfr{ 36592267Sdfr struct sapic_rte rte; 36692267Sdfr 367171664Smarcel db_printf("sapic=%u, irq=%u: ", sa->sa_id, irq); 368171664Smarcel sapic_read_rte(sa, irq - sa->sa_base, &rte); 369171664Smarcel db_printf("%3d %x->%x:%x %d %s %s %s %s %s %s\n", rte.rte_vector, 370171664Smarcel rte.rte_delivery_mode, 371171664Smarcel rte.rte_destination_id, rte.rte_destination_eid, 372171664Smarcel rte.rte_destination_mode, 373171664Smarcel rte.rte_delivery_status ? "DS" : " ", 374171664Smarcel rte.rte_polarity ? "low-active " : "high-active", 375171664Smarcel rte.rte_rirr ? "RIRR" : " ", 376171664Smarcel rte.rte_trigger_mode ? "level" : "edge ", 377171664Smarcel rte.rte_flushen ? "F" : " ", 378171664Smarcel rte.rte_mask ? "(masked)" : ""); 37992267Sdfr} 38092267Sdfr 38192267Sdfr#endif 382