1 /* $NetBSD: sapic.c,v 1.3 2019/10/15 00:13:52 chs Exp $ */ 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/kmem.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 47 struct sapic *ia64_sapics[16]; /* XXX make this resizable */ 48 static int ia64_sapic_count; 49 50 uint64_t ia64_lapic_address = PAL_PIB_DEFAULT_ADDR; 51 52 struct sapic_rte { 53 uint64_t rte_vector :8; 54 uint64_t rte_delivery_mode :3; 55 uint64_t rte_destination_mode :1; 56 uint64_t rte_delivery_status :1; 57 uint64_t rte_polarity :1; 58 uint64_t rte_rirr :1; 59 uint64_t rte_trigger_mode :1; 60 uint64_t rte_mask :1; 61 uint64_t rte_flushen :1; 62 uint64_t rte_reserved :30; 63 uint64_t rte_destination_eid :8; 64 uint64_t rte_destination_id :8; 65 }; 66 67 struct sapic * 68 sapic_lookup(uint irq) 69 { 70 struct sapic *sa; 71 int i; 72 73 for (i = 0; i < ia64_sapic_count; i++) { 74 sa = ia64_sapics[i]; 75 if (irq >= sa->sa_base && irq <= sa->sa_limit) 76 return sa; 77 } 78 79 return NULL; 80 } 81 82 static __inline uint32_t 83 sapic_read(struct sapic *sa, int which) 84 { 85 vaddr_t reg = sa->sa_registers; 86 87 *(volatile uint32_t *) (reg + SAPIC_IO_SELECT) = which; 88 ia64_mf(); 89 return *((volatile uint32_t *)(reg + SAPIC_IO_WINDOW)); 90 } 91 92 static __inline void 93 sapic_write(struct sapic *sa, int which, uint32_t value) 94 { 95 vaddr_t reg = sa->sa_registers; 96 97 *(volatile uint32_t *) (reg + SAPIC_IO_SELECT) = which; 98 ia64_mf(); 99 *(volatile uint32_t *) (reg + SAPIC_IO_WINDOW) = value; 100 ia64_mf(); 101 } 102 103 static __inline void 104 sapic_read_rte(struct sapic *sa, int which, struct sapic_rte *rte) 105 { 106 uint32_t *p = (uint32_t *) rte; 107 108 p[0] = sapic_read(sa, SAPIC_RTE_BASE + 2 * which); 109 p[1] = sapic_read(sa, SAPIC_RTE_BASE + 2 * which + 1); 110 } 111 112 static __inline void 113 sapic_write_rte(struct sapic *sa, int which, struct sapic_rte *rte) 114 { 115 uint32_t *p = (uint32_t *) rte; 116 117 sapic_write(sa, SAPIC_RTE_BASE + 2 * which, p[0]); 118 sapic_write(sa, SAPIC_RTE_BASE + 2 * which + 1, p[1]); 119 } 120 121 int 122 sapic_config_intr(u_int irq, int trigger) 123 { 124 struct sapic_rte rte; 125 struct sapic *sa; 126 127 sa = sapic_lookup(irq); 128 if (sa == NULL) 129 return EINVAL; 130 131 mutex_enter(&sa->sa_mtx); 132 sapic_read_rte(sa, irq - sa->sa_base, &rte); 133 rte.rte_trigger_mode = (trigger == IST_EDGE) ? 134 SAPIC_TRIGGER_EDGE : SAPIC_TRIGGER_LEVEL; 135 sapic_write_rte(sa, irq - sa->sa_base, &rte); 136 mutex_exit(&sa->sa_mtx); 137 return 0; 138 } 139 140 struct sapic * 141 sapic_create(u_int id, u_int base, uint64_t address) 142 { 143 struct sapic_rte rte; 144 struct sapic *sa; 145 u_int i; 146 147 sa = kmem_zalloc(sizeof(struct sapic), KM_SLEEP); 148 sa->sa_id = id; 149 sa->sa_base = base; 150 sa->sa_registers = IA64_PHYS_TO_RR6(address); 151 152 mutex_init(&sa->sa_mtx, MUTEX_SPIN, IPL_HIGH); 153 154 sa->sa_limit = base + ((sapic_read(sa, SAPIC_VERSION) >> 16) & 0xff); 155 156 ia64_sapics[ia64_sapic_count++] = sa; 157 158 /* 159 * Initialize all RTEs with a default trigger mode and polarity. 160 * This may be changed later by calling sapic_config_intr(). We 161 * mask all interrupts by default. 162 */ 163 memset(&rte, 0, sizeof(rte)); 164 rte.rte_mask = 1; 165 for (i = base; i <= sa->sa_limit; i++) { 166 rte.rte_trigger_mode = (i < 16) ? SAPIC_TRIGGER_EDGE : 167 SAPIC_TRIGGER_LEVEL; 168 rte.rte_polarity = (i < 16) ? SAPIC_POLARITY_HIGH : 169 SAPIC_POLARITY_LOW; 170 sapic_write_rte(sa, i - base, &rte); 171 } 172 173 return sa; 174 } 175 176 int 177 sapic_enable(struct sapic *sa, u_int irq, u_int vector) 178 { 179 struct sapic_rte rte; 180 uint64_t lid = ia64_get_lid(); 181 182 mutex_enter(&sa->sa_mtx); 183 sapic_read_rte(sa, irq - sa->sa_base, &rte); 184 rte.rte_destination_id = (lid >> 24) & 255; 185 rte.rte_destination_eid = (lid >> 16) & 255; 186 rte.rte_delivery_mode = SAPIC_DELMODE_FIXED; 187 rte.rte_vector = vector; 188 rte.rte_mask = 0; 189 sapic_write_rte(sa, irq - sa->sa_base, &rte); 190 mutex_exit(&sa->sa_mtx); 191 return 0; 192 } 193 194 void 195 sapic_eoi(struct sapic *sa, u_int vector) 196 { 197 vaddr_t reg = sa->sa_registers; 198 199 *(volatile uint32_t *)(reg + SAPIC_APIC_EOI) = vector; 200 ia64_mf(); 201 } 202 203 /* Expected to be called with interrupts disabled. */ 204 void 205 sapic_mask(struct sapic *sa, u_int irq) 206 { 207 struct sapic_rte rte; 208 209 mutex_enter(&sa->sa_mtx); 210 sapic_read_rte(sa, irq - sa->sa_base, &rte); 211 rte.rte_mask = 1; 212 sapic_write_rte(sa, irq - sa->sa_base, &rte); 213 mutex_exit(&sa->sa_mtx); 214 } 215 216 /* Expected to be called with interrupts disabled. */ 217 void 218 sapic_unmask(struct sapic *sa, u_int irq) 219 { 220 struct sapic_rte rte; 221 222 mutex_enter(&sa->sa_mtx); 223 sapic_read_rte(sa, irq - sa->sa_base, &rte); 224 rte.rte_mask = 0; 225 sapic_write_rte(sa, irq - sa->sa_base, &rte); 226 mutex_exit(&sa->sa_mtx); 227 } 228 229 230 #ifdef DDB 231 232 #include <ddb/ddb.h> 233 234 void 235 sapic_print(struct sapic *sa, u_int irq) 236 { 237 struct sapic_rte rte; 238 239 db_printf("sapic=%u, irq=%u: ", sa->sa_id, irq); 240 sapic_read_rte(sa, irq - sa->sa_base, &rte); 241 db_printf("%3d %x->%x:%x %d %s %s %s %s %s %s\n", rte.rte_vector, 242 rte.rte_delivery_mode, 243 rte.rte_destination_id, rte.rte_destination_eid, 244 rte.rte_destination_mode, 245 rte.rte_delivery_status ? "DS" : " ", 246 rte.rte_polarity ? "low-active " : "high-active", 247 rte.rte_rirr ? "RIRR" : " ", 248 rte.rte_trigger_mode ? "level" : "edge ", 249 rte.rte_flushen ? "F" : " ", 250 rte.rte_mask ? "(masked)" : ""); 251 } 252 253 #endif 254