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 2005 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 /* 30 * PCI Control Block object 31 */ 32 #include <sys/types.h> 33 #include <sys/kmem.h> 34 #include <sys/systm.h> /* timeout() */ 35 #include <sys/async.h> 36 #include <sys/sunddi.h> 37 #include <sys/ddi_impldefs.h> 38 #include <sys/pci/pci_obj.h> 39 #include <sys/machsystm.h> 40 41 #ifdef _STARFIRE 42 #include <sys/starfire.h> 43 #endif /* _STARFIRE */ 44 45 /*LINTLIBRARY*/ 46 47 void 48 cb_create(pci_t *pci_p) 49 { 50 cb_t *cb_p = (cb_t *)kmem_zalloc(sizeof (cb_t), KM_SLEEP); 51 52 mutex_init(&cb_p->cb_intr_lock, NULL, MUTEX_DRIVER, NULL); 53 pci_p->pci_cb_p = cb_p; 54 cb_p->cb_pci_cmn_p = pci_p->pci_common_p; 55 56 pci_cb_setup(pci_p); 57 } 58 59 void 60 cb_destroy(pci_t *pci_p) 61 { 62 cb_t *cb_p = pci_p->pci_cb_p; 63 64 intr_dist_rem(cb_intr_dist, cb_p); 65 pci_cb_teardown(pci_p); 66 pci_p->pci_cb_p = NULL; 67 mutex_destroy(&cb_p->cb_intr_lock); 68 kmem_free(cb_p, sizeof (cb_t)); 69 } 70 71 static void 72 cb_set_nintr_reg(cb_t *cb_p, ib_ino_t ino, uint64_t value) 73 { 74 uint64_t pa = cb_ino_to_clr_pa(cb_p, ino); 75 76 DEBUG3(DBG_CB|DBG_CONT, NULL, 77 "pci-%x cb_set_nintr_reg: ino=%x PA=%016llx\n", 78 cb_p->cb_pci_cmn_p->pci_common_id, ino, pa); 79 80 stdphysio(pa, value); 81 (void) lddphysio(pa); /* flush the previous write */ 82 } 83 84 /* 85 * enable an internal interrupt source: 86 * if an interrupt is shared by both sides, record it in cb_inos[] and 87 * cb will own its distribution. 88 */ 89 void 90 cb_enable_nintr(pci_t *pci_p, enum cb_nintr_index idx) 91 { 92 cb_t *cb_p = pci_p->pci_cb_p; 93 ib_ino_t ino = IB_MONDO_TO_INO(pci_p->pci_inos[idx]); 94 ib_mondo_t mondo = CB_INO_TO_MONDO(cb_p, ino); 95 uint32_t cpu_id; 96 uint64_t reg, pa; 97 98 ASSERT(idx < CBNINTR_MAX); 99 pa = cb_ino_to_map_pa(cb_p, ino); 100 101 mutex_enter(&cb_p->cb_intr_lock); 102 cpu_id = intr_dist_cpuid(); 103 104 #ifdef _STARFIRE 105 cpu_id = pc_translate_tgtid(cb_p->cb_ittrans_cookie, cpu_id, 106 IB_GET_MAPREG_INO(ino)); 107 #endif /* _STARFIRE */ 108 109 reg = ib_get_map_reg(mondo, cpu_id); 110 stdphysio(pa, reg); 111 112 ASSERT(cb_p->cb_inos[idx] == 0); 113 cb_p->cb_inos[idx] = ino; 114 115 cb_set_nintr_reg(cb_p, ino, COMMON_CLEAR_INTR_REG_IDLE); 116 mutex_exit(&cb_p->cb_intr_lock); 117 118 DEBUG3(DBG_CB|DBG_CONT, NULL, 119 "pci-%x cb_enable_nintr: ino=%x cpu_id=%x\n", 120 pci_p->pci_id, ino, cpu_id); 121 DEBUG2(DBG_CB|DBG_CONT, NULL, "\tPA=%016llx data=%016llx\n", pa, reg); 122 } 123 124 static void 125 cb_disable_nintr_reg(cb_t *cb_p, ib_ino_t ino, int wait) 126 { 127 uint64_t tmp, map_reg_pa = cb_ino_to_map_pa(cb_p, ino); 128 ASSERT(MUTEX_HELD(&cb_p->cb_intr_lock)); 129 130 /* mark interrupt invalid in mapping register */ 131 tmp = lddphysio(map_reg_pa) & ~COMMON_INTR_MAP_REG_VALID; 132 stdphysio(map_reg_pa, tmp); 133 (void) lddphysio(map_reg_pa); /* flush previous write */ 134 135 if (wait) { 136 hrtime_t start_time; 137 uint64_t state_reg_pa = cb_p->cb_obsta_pa; 138 uint_t shift = (ino & 0x1f) << 1; 139 140 /* busy wait if there is interrupt being processed */ 141 /* unless panic or timeout for interrupt pending is reached */ 142 start_time = gethrtime(); 143 while ((((lddphysio(state_reg_pa) >> shift) & 144 COMMON_CLEAR_INTR_REG_MASK) == 145 COMMON_CLEAR_INTR_REG_PENDING) && !panicstr) { 146 if (gethrtime() - start_time > pci_intrpend_timeout) { 147 cmn_err(CE_WARN, 148 "pci@%x cb_disable_nintr_reg(%lx,%x) timeout", 149 cb_p->cb_pci_cmn_p->pci_common_id, 150 map_reg_pa, 151 CB_INO_TO_MONDO(cb_p, ino)); 152 break; 153 } 154 } 155 } 156 } 157 158 void 159 cb_disable_nintr(cb_t *cb_p, enum cb_nintr_index idx, int wait) 160 { 161 ib_ino_t ino = cb_p->cb_inos[idx]; 162 ASSERT(idx < CBNINTR_MAX); 163 ASSERT(ino); 164 165 mutex_enter(&cb_p->cb_intr_lock); 166 cb_disable_nintr_reg(cb_p, ino, wait); 167 cb_set_nintr_reg(cb_p, ino, COMMON_CLEAR_INTR_REG_PENDING); 168 cb_p->cb_inos[idx] = 0; 169 mutex_exit(&cb_p->cb_intr_lock); 170 #ifdef _STARFIRE 171 pc_ittrans_cleanup(cb_p->cb_ittrans_cookie, 172 (volatile uint64_t *)(uintptr_t)ino); 173 #endif /* _STARFIRE */ 174 } 175 176 void 177 cb_clear_nintr(cb_t *cb_p, enum cb_nintr_index idx) 178 { 179 ib_ino_t ino = cb_p->cb_inos[idx]; 180 ASSERT(idx < CBNINTR_MAX); 181 ASSERT(ino); 182 cb_set_nintr_reg(cb_p, ino, COMMON_CLEAR_INTR_REG_IDLE); 183 } 184 185 void 186 cb_intr_dist(void *arg) 187 { 188 int i; 189 cb_t *cb_p = (cb_t *)arg; 190 191 mutex_enter(&cb_p->cb_intr_lock); 192 for (i = 0; i < cb_p->cb_no_of_inos; i++) { 193 uint64_t mr_pa; 194 volatile uint64_t imr; 195 ib_mondo_t mondo; 196 uint32_t cpu_id; 197 198 ib_ino_t ino = cb_p->cb_inos[i]; 199 if (!ino) /* skip non-shared interrupts */ 200 continue; 201 202 mr_pa = cb_ino_to_map_pa(cb_p, ino); 203 imr = lddphysio(mr_pa); 204 if (!IB_INO_INTR_ISON(imr)) 205 continue; 206 207 mondo = CB_INO_TO_MONDO(cb_p, ino); 208 cpu_id = intr_dist_cpuid(); 209 #ifdef _STARFIRE 210 cpu_id = pc_translate_tgtid(cb_p->cb_ittrans_cookie, cpu_id, 211 IB_GET_MAPREG_INO(ino)); 212 #else 213 if (ib_map_reg_get_cpu(imr) == cpu_id) 214 continue; /* same cpu target, no re-program */ 215 #endif 216 cb_disable_nintr_reg(cb_p, ino, IB_INTR_WAIT); 217 stdphysio(mr_pa, ib_get_map_reg(mondo, cpu_id)); 218 (void) lddphysio(mr_pa); /* flush previous write */ 219 } 220 mutex_exit(&cb_p->cb_intr_lock); 221 } 222 223 void 224 cb_suspend(cb_t *cb_p) 225 { 226 int i, inos = cb_p->cb_no_of_inos; 227 ASSERT(!cb_p->cb_imr_save); 228 cb_p->cb_imr_save = kmem_alloc(inos * sizeof (uint64_t), KM_SLEEP); 229 230 /* 231 * save the internal interrupts' mapping registers content 232 * 233 * The PBM IMR really doesn't need to be saved, as it is 234 * different per side and is handled by pbm_suspend/resume. 235 * But it complicates the logic. 236 */ 237 for (i = 0; i < inos; i++) { 238 uint64_t pa; 239 ib_ino_t ino = cb_p->cb_inos[i]; 240 if (!ino) 241 continue; 242 pa = cb_ino_to_map_pa(cb_p, ino); 243 cb_p->cb_imr_save[i] = lddphysio(pa); 244 } 245 } 246 247 void 248 cb_resume(cb_t *cb_p) 249 { 250 int i; 251 for (i = 0; i < cb_p->cb_no_of_inos; i++) { 252 uint64_t pa; 253 ib_ino_t ino = cb_p->cb_inos[i]; 254 if (!ino) 255 continue; 256 pa = cb_ino_to_map_pa(cb_p, ino); 257 cb_set_nintr_reg(cb_p, ino, COMMON_CLEAR_INTR_REG_IDLE); 258 stdphysio(pa, cb_p->cb_imr_save[i]); /* restore IMR */ 259 } 260 kmem_free(cb_p->cb_imr_save, cb_p->cb_no_of_inos * sizeof (uint64_t)); 261 cb_p->cb_imr_save = NULL; 262 } 263