1/* $NetBSD$ */ 2/*- 3 * Copyright (c) 2001 Doug Rabson 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 * $FreeBSD: src/sys/ia64/ia64/sapic.c,v 1.15 2008/04/14 20:34:45 marcel Exp $ 28 */ 29 30#include "opt_ddb.h" 31 32#include <sys/param.h> 33#include <sys/malloc.h> 34#include <sys/kernel.h> 35#include <sys/systm.h> 36#include <sys/bus.h> 37#include <sys/lock.h> 38#include <sys/mutex.h> 39#include <sys/sysctl.h> 40 41#include <machine/intr.h> 42#include <machine/pal.h> 43#include <machine/sapicreg.h> 44#include <machine/sapicvar.h> 45 46 47static MALLOC_DEFINE(M_SAPIC, "sapic", "I/O SAPIC devices"); 48 49struct sapic *ia64_sapics[16]; /* XXX make this resizable */ 50static int ia64_sapic_count; 51 52uint64_t ia64_lapic_address = PAL_PIB_DEFAULT_ADDR; 53 54struct sapic_rte { 55 uint64_t rte_vector :8; 56 uint64_t rte_delivery_mode :3; 57 uint64_t rte_destination_mode :1; 58 uint64_t rte_delivery_status :1; 59 uint64_t rte_polarity :1; 60 uint64_t rte_rirr :1; 61 uint64_t rte_trigger_mode :1; 62 uint64_t rte_mask :1; 63 uint64_t rte_flushen :1; 64 uint64_t rte_reserved :30; 65 uint64_t rte_destination_eid :8; 66 uint64_t rte_destination_id :8; 67}; 68 69struct sapic * 70sapic_lookup(uint irq) 71{ 72 struct sapic *sa; 73 int i; 74 75 for (i = 0; i < ia64_sapic_count; i++) { 76 sa = ia64_sapics[i]; 77 if (irq >= sa->sa_base && irq <= sa->sa_limit) 78 return sa; 79 } 80 81 return NULL; 82} 83 84static __inline uint32_t 85sapic_read(struct sapic *sa, int which) 86{ 87 vaddr_t reg = sa->sa_registers; 88 89 *(volatile uint32_t *) (reg + SAPIC_IO_SELECT) = which; 90 ia64_mf(); 91 return *((volatile uint32_t *)(reg + SAPIC_IO_WINDOW)); 92} 93 94static __inline void 95sapic_write(struct sapic *sa, int which, uint32_t value) 96{ 97 vaddr_t reg = sa->sa_registers; 98 99 *(volatile uint32_t *) (reg + SAPIC_IO_SELECT) = which; 100 ia64_mf(); 101 *(volatile uint32_t *) (reg + SAPIC_IO_WINDOW) = value; 102 ia64_mf(); 103} 104 105static __inline void 106sapic_read_rte(struct sapic *sa, int which, struct sapic_rte *rte) 107{ 108 uint32_t *p = (uint32_t *) rte; 109 110 p[0] = sapic_read(sa, SAPIC_RTE_BASE + 2 * which); 111 p[1] = sapic_read(sa, SAPIC_RTE_BASE + 2 * which + 1); 112} 113 114static __inline void 115sapic_write_rte(struct sapic *sa, int which, struct sapic_rte *rte) 116{ 117 uint32_t *p = (uint32_t *) rte; 118 119 sapic_write(sa, SAPIC_RTE_BASE + 2 * which, p[0]); 120 sapic_write(sa, SAPIC_RTE_BASE + 2 * which + 1, p[1]); 121} 122 123int 124sapic_config_intr(u_int irq, int trigger) 125{ 126 struct sapic_rte rte; 127 struct sapic *sa; 128 129 sa = sapic_lookup(irq); 130 if (sa == NULL) 131 return EINVAL; 132 133 mutex_enter(&sa->sa_mtx); 134 sapic_read_rte(sa, irq - sa->sa_base, &rte); 135 rte.rte_trigger_mode = (trigger == IST_EDGE) ? 136 SAPIC_TRIGGER_EDGE : SAPIC_TRIGGER_LEVEL; 137 sapic_write_rte(sa, irq - sa->sa_base, &rte); 138 mutex_exit(&sa->sa_mtx); 139 return 0; 140} 141 142struct sapic * 143sapic_create(u_int id, u_int base, uint64_t address) 144{ 145 struct sapic_rte rte; 146 struct sapic *sa; 147 u_int i; 148 149 sa = malloc(sizeof(struct sapic), M_SAPIC, M_ZERO | M_NOWAIT); 150 if (sa == NULL) 151 return NULL; 152 153 sa->sa_id = id; 154 sa->sa_base = base; 155 sa->sa_registers = IA64_PHYS_TO_RR6(address); 156 157 mutex_init(&sa->sa_mtx, MUTEX_SPIN, IPL_HIGH); 158 159 sa->sa_limit = base + ((sapic_read(sa, SAPIC_VERSION) >> 16) & 0xff); 160 161 ia64_sapics[ia64_sapic_count++] = sa; 162 163 /* 164 * Initialize all RTEs with a default trigger mode and polarity. 165 * This may be changed later by calling sapic_config_intr(). We 166 * mask all interrupts by default. 167 */ 168 memset(&rte, 0, sizeof(rte)); 169 rte.rte_mask = 1; 170 for (i = base; i <= sa->sa_limit; i++) { 171 rte.rte_trigger_mode = (i < 16) ? SAPIC_TRIGGER_EDGE : 172 SAPIC_TRIGGER_LEVEL; 173 rte.rte_polarity = (i < 16) ? SAPIC_POLARITY_HIGH : 174 SAPIC_POLARITY_LOW; 175 sapic_write_rte(sa, i - base, &rte); 176 } 177 178 return sa; 179} 180 181int 182sapic_enable(struct sapic *sa, u_int irq, u_int vector) 183{ 184 struct sapic_rte rte; 185 uint64_t lid = ia64_get_lid(); 186 187 mutex_enter(&sa->sa_mtx); 188 sapic_read_rte(sa, irq - sa->sa_base, &rte); 189 rte.rte_destination_id = (lid >> 24) & 255; 190 rte.rte_destination_eid = (lid >> 16) & 255; 191 rte.rte_delivery_mode = SAPIC_DELMODE_FIXED; 192 rte.rte_vector = vector; 193 rte.rte_mask = 0; 194 sapic_write_rte(sa, irq - sa->sa_base, &rte); 195 mutex_exit(&sa->sa_mtx); 196 return 0; 197} 198 199void 200sapic_eoi(struct sapic *sa, u_int vector) 201{ 202 vaddr_t reg = sa->sa_registers; 203 204 *(volatile uint32_t *)(reg + SAPIC_APIC_EOI) = vector; 205 ia64_mf(); 206} 207 208/* Expected to be called with interrupts disabled. */ 209void 210sapic_mask(struct sapic *sa, u_int irq) 211{ 212 struct sapic_rte rte; 213 214 mutex_enter(&sa->sa_mtx); 215 sapic_read_rte(sa, irq - sa->sa_base, &rte); 216 rte.rte_mask = 1; 217 sapic_write_rte(sa, irq - sa->sa_base, &rte); 218 mutex_exit(&sa->sa_mtx); 219} 220 221/* Expected to be called with interrupts disabled. */ 222void 223sapic_unmask(struct sapic *sa, u_int irq) 224{ 225 struct sapic_rte rte; 226 227 mutex_enter(&sa->sa_mtx); 228 sapic_read_rte(sa, irq - sa->sa_base, &rte); 229 rte.rte_mask = 0; 230 sapic_write_rte(sa, irq - sa->sa_base, &rte); 231 mutex_exit(&sa->sa_mtx); 232} 233 234 235#ifdef DDB 236 237#include <ddb/ddb.h> 238 239void 240sapic_print(struct sapic *sa, u_int irq) 241{ 242 struct sapic_rte rte; 243 244 db_printf("sapic=%u, irq=%u: ", sa->sa_id, irq); 245 sapic_read_rte(sa, irq - sa->sa_base, &rte); 246 db_printf("%3d %x->%x:%x %d %s %s %s %s %s %s\n", rte.rte_vector, 247 rte.rte_delivery_mode, 248 rte.rte_destination_id, rte.rte_destination_eid, 249 rte.rte_destination_mode, 250 rte.rte_delivery_status ? "DS" : " ", 251 rte.rte_polarity ? "low-active " : "high-active", 252 rte.rte_rirr ? "RIRR" : " ", 253 rte.rte_trigger_mode ? "level" : "edge ", 254 rte.rte_flushen ? "F" : " ", 255 rte.rte_mask ? "(masked)" : ""); 256} 257 258#endif 259