1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 1990-2002 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/types.h> 30 #include <sys/cmn_err.h> 31 #include <sys/kmem.h> 32 #include <sys/debug.h> 33 #include <sys/machsystm.h> 34 #include <sys/starfire.h> 35 36 /* 37 * Interrupt target translation data for 38 * Starfire's Port controller asics 39 */ 40 struct pc_ittrans_data { 41 kmutex_t ittrans_lock; /* lock for ITTR array */ 42 volatile uint64_t *ittrans_mondovec[32]; /* mondovecreg addr array */ 43 uint64_t ittransreg_physaddr[32]; /* ITTREG physaddr array */ 44 }; 45 46 /* 47 * Setup and initialize the soft table that 48 * represent the Starfire interrupt target translation 49 * registers in the Port controller asics. There is one 50 * for each sysio/pci instance. 51 */ 52 void 53 pc_ittrans_init(int upa_id, caddr_t *ittptr_cookie) 54 { 55 int i; 56 uint64_t physaddr; 57 struct pc_ittrans_data *tmpptr; 58 59 ASSERT(ittptr_cookie != NULL); 60 61 /* 62 * Allocate the data structure to support starfire's 63 * interrupt target translations 64 */ 65 tmpptr = (struct pc_ittrans_data *) 66 kmem_zalloc(sizeof (struct pc_ittrans_data), 67 KM_SLEEP); 68 69 /* Initialize the ittrans lock */ 70 mutex_init(&tmpptr->ittrans_lock, NULL, MUTEX_DEFAULT, NULL); 71 72 /* 73 * Construct the base physical address of the 74 * ITTR registers associated with this PC asics 75 */ 76 physaddr = STARFIRE_UPAID2UPS(upa_id); 77 physaddr |= (STARFIRE_PSI_BASE | STARFIRE_PSI_PCREG_OFF | 78 STARFIRE_PC_INT_MAP); 79 80 /* 81 * Initialize the ITTR table 82 * This soft table is used to represent the interrupt 83 * target translation hardware registers in the Starfire's 84 * PC asics. There are 32 slots and each slot consists of 85 * a mondovec regaddr entry and the physical address of 86 * the that ITT register. A empty slot is one whose 87 * mondovec entry is null. To reserve/use a slot for a 88 * particular intr mapping reg, we simply find 89 * a empty slot and write in the mondovec mapping 90 * regaddr into the mondovec field. 91 */ 92 for (i = 0; i < 32; i++) { 93 tmpptr->ittrans_mondovec[i] = NULL; 94 tmpptr->ittransreg_physaddr[i] = physaddr + i*16; 95 } 96 97 *ittptr_cookie = (caddr_t)tmpptr; 98 } 99 100 void 101 pc_ittrans_uninit(caddr_t ittr_cookie) 102 { 103 struct pc_ittrans_data *tmpptr; 104 105 ASSERT(ittr_cookie != NULL); 106 107 tmpptr = (struct pc_ittrans_data *)ittr_cookie; 108 109 mutex_destroy(&tmpptr->ittrans_lock); 110 kmem_free((int *)ittr_cookie, sizeof (struct pc_ittrans_data)); 111 } 112 113 /* 114 * This routine searches for a slot in the soft ITTR table 115 * that was reserved earlier by matching the mondovec 116 * mapping regaddr argument with the corresponding field in 117 * the table. Note that the soft ITTR table mirrors the 118 * corresponding hw table in the starfire port controller(PC) 119 * asics. A new slot will be obtained if the slot cannot 120 * be found. (not reserved previously). The routine then programs 121 * in the target cpu id into the PC ITTR hardware, updates the 122 * soft table and return the index to this slot as the target 123 * id cookie. 124 */ 125 int 126 pc_translate_tgtid(caddr_t ittr_cookie, int cpu_id, 127 volatile uint64_t *mondovec_addr) 128 { 129 struct pc_ittrans_data *ittptr; 130 int i; 131 int foundslot = -1; 132 133 ASSERT(ittr_cookie != NULL); 134 135 ittptr = (struct pc_ittrans_data *)ittr_cookie; 136 137 mutex_enter(&ittptr->ittrans_lock); 138 139 /* 140 * Search the mondovec addrlist to see if we 141 * already reserved/used a slot for this particular 142 * mondovec mapping regaddr. 143 */ 144 for (i = 0; i < 32; i++) { 145 if (mondovec_addr == ittptr->ittrans_mondovec[i]) { 146 /* 147 * found the slot that matches the 148 * mondo vec in question 149 */ 150 foundslot = i; 151 break; 152 } 153 if (foundslot == -1 && ittptr->ittrans_mondovec[i] == NULL) 154 /* keep track of a empty slot */ 155 foundslot = i; 156 } 157 158 if (foundslot != -1) { 159 /* We found a slot for this mondo vec, let's use it */ 160 stphysio(ittptr->ittransreg_physaddr[foundslot], 161 STARFIRE_UPAID2HWMID(cpu_id)); 162 ittptr->ittrans_mondovec[foundslot] = mondovec_addr; 163 } else { 164 cmn_err(CE_PANIC, "No more ITTR slots!!"); 165 } 166 167 mutex_exit(&ittptr->ittrans_lock); 168 return (foundslot); 169 } 170 171 /* 172 * This routine searches the interrupt target translation table 173 * (if exists) for a slot that was reserved/used earlier by 174 * matching the mondovec_addr input argument with the mondovec 175 * field in the table. The routine then free the found slot by 176 * resetting it to zero. 177 */ 178 void 179 pc_ittrans_cleanup(caddr_t ittr_cookie, 180 volatile uint64_t *mondovec_addr) 181 { 182 183 struct pc_ittrans_data *ittptr; 184 int i; 185 int foundslot = -1; 186 187 ASSERT(ittr_cookie != NULL); 188 189 ittptr = (struct pc_ittrans_data *)ittr_cookie; 190 191 mutex_enter(&ittptr->ittrans_lock); 192 193 /* 194 * Search the mondovec addrlist for the reserved/used 195 * slot associated with this particular mondo vector. 196 */ 197 for (i = 0; i < 32; i++) { 198 if (mondovec_addr == ittptr->ittrans_mondovec[i]) { 199 /* 200 * found the slot that matches the 201 * mondo vec in question 202 */ 203 foundslot = i; 204 break; 205 } 206 } 207 208 if (foundslot != -1) { 209 /* We found a slot for this mondo vec, clear it */ 210 ittptr->ittrans_mondovec[foundslot] = 0; 211 } 212 213 mutex_exit(&ittptr->ittrans_lock); 214 } 215 216 int 217 pc_madr_add(int lboard, int rboard, int proc, uint_t madr) 218 { 219 register int i; 220 uint_t madr_rd, madr_off; 221 uint64_t pc_madr_addr; 222 223 pc_madr_addr = STARFIRE_PC_MADR_ADDR(lboard, rboard, proc); 224 225 /* 226 * First write with Presence bit disabled 227 * and then with it enabled. 228 */ 229 madr_off = madr & ~STARFIRE_MC_MEM_PRESENT_MASK; 230 stphysio(pc_madr_addr, madr_off); 231 232 for (i = 0; i < 20; i++) { 233 madr_rd = ldphysio(pc_madr_addr); 234 if (madr_off == madr_rd) 235 break; 236 } 237 if (madr_off != madr_rd) { 238 cmn_err(CE_WARN, 239 "pc_madr_add: (1) failed to update " 240 "PC MADR (%d, %d, %d, 0x%x)\n", 241 lboard, rboard, proc, madr); 242 return (-1); 243 } 244 if (madr == madr_off) { 245 /* 246 * Caller wanted to write value out there 247 * with presence bit turned off, which is 248 * what we just completed. So, we're finished. 249 */ 250 return (0); 251 } 252 /* 253 * Now write with Presence bit enabled. 254 */ 255 stphysio(pc_madr_addr, madr); 256 257 for (i = 0; i < 20; i++) { 258 madr_rd = ldphysio(pc_madr_addr); 259 if (madr == madr_rd) 260 break; 261 } 262 if (madr != madr_rd) { 263 cmn_err(CE_WARN, 264 "pc_madr_add: (2) failed to update " 265 "PC MADR (%d, %d, %d, 0x%x)\n", 266 lboard, rboard, proc, madr); 267 return (-1); 268 } 269 270 return (0); 271 } 272