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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <sys/machsystm.h> 27 #include <sys/cpu.h> 28 #include <sys/intreg.h> 29 #include <sys/machcpuvar.h> 30 #include <vm/hat_sfmmu.h> 31 #include <sys/error.h> 32 #include <sys/hypervisor_api.h> 33 34 void 35 cpu_intrq_register(struct cpu *cpu) 36 { 37 struct machcpu *mcpup = &cpu->cpu_m; 38 uint64_t ret; 39 40 ret = hv_cpu_qconf(INTR_CPU_Q, mcpup->cpu_q_base_pa, cpu_q_entries); 41 if (ret != H_EOK) 42 cmn_err(CE_PANIC, "cpu%d: cpu_mondo queue configuration " 43 "failed, error %lu", cpu->cpu_id, ret); 44 45 ret = hv_cpu_qconf(INTR_DEV_Q, mcpup->dev_q_base_pa, dev_q_entries); 46 if (ret != H_EOK) 47 cmn_err(CE_PANIC, "cpu%d: dev_mondo queue configuration " 48 "failed, error %lu", cpu->cpu_id, ret); 49 50 ret = hv_cpu_qconf(CPU_RQ, mcpup->cpu_rq_base_pa, cpu_rq_entries); 51 if (ret != H_EOK) 52 cmn_err(CE_PANIC, "cpu%d: resumable error queue configuration " 53 "failed, error %lu", cpu->cpu_id, ret); 54 55 ret = hv_cpu_qconf(CPU_NRQ, mcpup->cpu_nrq_base_pa, cpu_nrq_entries); 56 if (ret != H_EOK) 57 cmn_err(CE_PANIC, "cpu%d: non-resumable error queue " 58 "configuration failed, error %lu", cpu->cpu_id, ret); 59 } 60 61 int 62 cpu_intrq_setup(struct cpu *cpu) 63 { 64 struct machcpu *mcpup = &cpu->cpu_m; 65 size_t size; 66 67 /* 68 * This routine will return with an error return if any 69 * contig_mem_alloc() fails. It is expected that the caller will 70 * call cpu_intrq_cleanup() (or cleanup_cpu_common() which will). 71 * That will cleanly free only those blocks that were alloc'd. 72 */ 73 74 /* 75 * Allocate mondo data for xcalls. 76 */ 77 mcpup->mondo_data = contig_mem_alloc(INTR_REPORT_SIZE); 78 79 if (mcpup->mondo_data == NULL) { 80 cmn_err(CE_NOTE, "cpu%d: cpu mondo_data allocation failed", 81 cpu->cpu_id); 82 return (ENOMEM); 83 } 84 /* 85 * va_to_pa() is too expensive to call for every crosscall 86 * so we do it here at init time and save it in machcpu. 87 */ 88 mcpup->mondo_data_ra = va_to_pa(mcpup->mondo_data); 89 90 /* 91 * Allocate a per-cpu list of ncpu_guest_max for xcalls 92 */ 93 size = ncpu_guest_max * sizeof (uint16_t); 94 if (size < INTR_REPORT_SIZE) 95 size = INTR_REPORT_SIZE; 96 97 /* 98 * contig_mem_alloc() requires size to be a power of 2. 99 * Increase size to a power of 2 if necessary. 100 */ 101 if ((size & (size - 1)) != 0) { 102 size = 1 << highbit(size); 103 } 104 105 mcpup->cpu_list = contig_mem_alloc(size); 106 107 if (mcpup->cpu_list == NULL) { 108 cmn_err(CE_NOTE, "cpu%d: cpu cpu_list allocation failed", 109 cpu->cpu_id); 110 return (ENOMEM); 111 } 112 mcpup->cpu_list_ra = va_to_pa(mcpup->cpu_list); 113 114 /* 115 * Allocate sun4v interrupt and error queues. 116 */ 117 size = cpu_q_entries * INTR_REPORT_SIZE; 118 119 mcpup->cpu_q_va = contig_mem_alloc(size); 120 121 if (mcpup->cpu_q_va == NULL) { 122 cmn_err(CE_NOTE, "cpu%d: cpu intrq allocation failed", 123 cpu->cpu_id); 124 return (ENOMEM); 125 } 126 mcpup->cpu_q_base_pa = va_to_pa(mcpup->cpu_q_va); 127 mcpup->cpu_q_size = size; 128 129 /* 130 * Allocate device queues 131 */ 132 size = dev_q_entries * INTR_REPORT_SIZE; 133 134 mcpup->dev_q_va = contig_mem_alloc(size); 135 136 if (mcpup->dev_q_va == NULL) { 137 cmn_err(CE_NOTE, "cpu%d: dev intrq allocation failed", 138 cpu->cpu_id); 139 return (ENOMEM); 140 } 141 mcpup->dev_q_base_pa = va_to_pa(mcpup->dev_q_va); 142 mcpup->dev_q_size = size; 143 144 /* 145 * Allocate resumable queue and its kernel buffer 146 */ 147 size = cpu_rq_entries * Q_ENTRY_SIZE; 148 149 mcpup->cpu_rq_va = contig_mem_alloc(2 * size); 150 151 if (mcpup->cpu_rq_va == NULL) { 152 cmn_err(CE_NOTE, "cpu%d: resumable queue allocation failed", 153 cpu->cpu_id); 154 return (ENOMEM); 155 } 156 mcpup->cpu_rq_base_pa = va_to_pa(mcpup->cpu_rq_va); 157 mcpup->cpu_rq_size = size; 158 /* zero out the memory */ 159 bzero(mcpup->cpu_rq_va, 2 * size); 160 161 /* 162 * Allocate non-resumable queues 163 */ 164 size = cpu_nrq_entries * Q_ENTRY_SIZE; 165 166 mcpup->cpu_nrq_va = contig_mem_alloc(2 * size); 167 168 if (mcpup->cpu_nrq_va == NULL) { 169 cmn_err(CE_NOTE, "cpu%d: nonresumable queue allocation failed", 170 cpu->cpu_id); 171 return (ENOMEM); 172 } 173 mcpup->cpu_nrq_base_pa = va_to_pa(mcpup->cpu_nrq_va); 174 mcpup->cpu_nrq_size = size; 175 /* zero out the memory */ 176 bzero(mcpup->cpu_nrq_va, 2 * size); 177 178 return (0); 179 } 180 181 void 182 cpu_intrq_cleanup(struct cpu *cpu) 183 { 184 struct machcpu *mcpup = &cpu->cpu_m; 185 int cpu_list_size; 186 uint64_t cpu_q_size; 187 uint64_t dev_q_size; 188 uint64_t cpu_rq_size; 189 uint64_t cpu_nrq_size; 190 191 /* 192 * Free mondo data for xcalls. 193 */ 194 if (mcpup->mondo_data) { 195 contig_mem_free(mcpup->mondo_data, INTR_REPORT_SIZE); 196 mcpup->mondo_data = NULL; 197 mcpup->mondo_data_ra = NULL; 198 } 199 200 /* 201 * Free per-cpu list of ncpu_guest_max for xcalls 202 */ 203 cpu_list_size = ncpu_guest_max * sizeof (uint16_t); 204 if (cpu_list_size < INTR_REPORT_SIZE) 205 cpu_list_size = INTR_REPORT_SIZE; 206 207 /* 208 * contig_mem_alloc() requires size to be a power of 2. 209 * Increase size to a power of 2 if necessary. 210 */ 211 if ((cpu_list_size & (cpu_list_size - 1)) != 0) { 212 cpu_list_size = 1 << highbit(cpu_list_size); 213 } 214 215 if (mcpup->cpu_list) { 216 contig_mem_free(mcpup->cpu_list, cpu_list_size); 217 mcpup->cpu_list = NULL; 218 mcpup->cpu_list_ra = NULL; 219 } 220 221 /* 222 * Free sun4v interrupt and error queues. 223 */ 224 if (mcpup->cpu_q_va) { 225 cpu_q_size = cpu_q_entries * INTR_REPORT_SIZE; 226 contig_mem_free(mcpup->cpu_q_va, cpu_q_size); 227 mcpup->cpu_q_va = NULL; 228 mcpup->cpu_q_base_pa = NULL; 229 mcpup->cpu_q_size = 0; 230 } 231 232 if (mcpup->dev_q_va) { 233 dev_q_size = dev_q_entries * INTR_REPORT_SIZE; 234 contig_mem_free(mcpup->dev_q_va, dev_q_size); 235 mcpup->dev_q_va = NULL; 236 mcpup->dev_q_base_pa = NULL; 237 mcpup->dev_q_size = 0; 238 } 239 240 if (mcpup->cpu_rq_va) { 241 cpu_rq_size = cpu_rq_entries * Q_ENTRY_SIZE; 242 contig_mem_free(mcpup->cpu_rq_va, 2 * cpu_rq_size); 243 mcpup->cpu_rq_va = NULL; 244 mcpup->cpu_rq_base_pa = NULL; 245 mcpup->cpu_rq_size = 0; 246 } 247 248 if (mcpup->cpu_nrq_va) { 249 cpu_nrq_size = cpu_nrq_entries * Q_ENTRY_SIZE; 250 contig_mem_free(mcpup->cpu_nrq_va, 2 * cpu_nrq_size); 251 mcpup->cpu_nrq_va = NULL; 252 mcpup->cpu_nrq_base_pa = NULL; 253 mcpup->cpu_nrq_size = 0; 254 } 255 } 256