17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 51ae08745Sheppo * Common Development and Distribution License (the "License"). 61ae08745Sheppo * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*4001936eSAnthony Yznaga * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #include <sys/machsystm.h> 277c478bd9Sstevel@tonic-gate #include <sys/cpu.h> 287c478bd9Sstevel@tonic-gate #include <sys/intreg.h> 297c478bd9Sstevel@tonic-gate #include <sys/machcpuvar.h> 307c478bd9Sstevel@tonic-gate #include <vm/hat_sfmmu.h> 317c478bd9Sstevel@tonic-gate #include <sys/error.h> 327c478bd9Sstevel@tonic-gate #include <sys/hypervisor_api.h> 337c478bd9Sstevel@tonic-gate 347c478bd9Sstevel@tonic-gate void 357c478bd9Sstevel@tonic-gate cpu_intrq_register(struct cpu *cpu) 367c478bd9Sstevel@tonic-gate { 377c478bd9Sstevel@tonic-gate struct machcpu *mcpup = &cpu->cpu_m; 387c478bd9Sstevel@tonic-gate uint64_t ret; 397c478bd9Sstevel@tonic-gate 407c478bd9Sstevel@tonic-gate ret = hv_cpu_qconf(INTR_CPU_Q, mcpup->cpu_q_base_pa, cpu_q_entries); 417c478bd9Sstevel@tonic-gate if (ret != H_EOK) 427c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, "cpu%d: cpu_mondo queue configuration " 437c478bd9Sstevel@tonic-gate "failed, error %lu", cpu->cpu_id, ret); 447c478bd9Sstevel@tonic-gate 457c478bd9Sstevel@tonic-gate ret = hv_cpu_qconf(INTR_DEV_Q, mcpup->dev_q_base_pa, dev_q_entries); 467c478bd9Sstevel@tonic-gate if (ret != H_EOK) 477c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, "cpu%d: dev_mondo queue configuration " 487c478bd9Sstevel@tonic-gate "failed, error %lu", cpu->cpu_id, ret); 497c478bd9Sstevel@tonic-gate 501ae08745Sheppo ret = hv_cpu_qconf(CPU_RQ, mcpup->cpu_rq_base_pa, cpu_rq_entries); 517c478bd9Sstevel@tonic-gate if (ret != H_EOK) 527c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, "cpu%d: resumable error queue configuration " 537c478bd9Sstevel@tonic-gate "failed, error %lu", cpu->cpu_id, ret); 547c478bd9Sstevel@tonic-gate 551ae08745Sheppo ret = hv_cpu_qconf(CPU_NRQ, mcpup->cpu_nrq_base_pa, cpu_nrq_entries); 567c478bd9Sstevel@tonic-gate if (ret != H_EOK) 577c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, "cpu%d: non-resumable error queue " 587c478bd9Sstevel@tonic-gate "configuration failed, error %lu", cpu->cpu_id, ret); 597c478bd9Sstevel@tonic-gate } 607c478bd9Sstevel@tonic-gate 61982b9107Sjb145095 int 627c478bd9Sstevel@tonic-gate cpu_intrq_setup(struct cpu *cpu) 637c478bd9Sstevel@tonic-gate { 647c478bd9Sstevel@tonic-gate struct machcpu *mcpup = &cpu->cpu_m; 65982b9107Sjb145095 size_t size; 66982b9107Sjb145095 67982b9107Sjb145095 /* 68982b9107Sjb145095 * This routine will return with an error return if any 69982b9107Sjb145095 * contig_mem_alloc() fails. It is expected that the caller will 70982b9107Sjb145095 * call cpu_intrq_cleanup() (or cleanup_cpu_common() which will). 71982b9107Sjb145095 * That will cleanly free only those blocks that were alloc'd. 72982b9107Sjb145095 */ 737c478bd9Sstevel@tonic-gate 747c478bd9Sstevel@tonic-gate /* 757c478bd9Sstevel@tonic-gate * Allocate mondo data for xcalls. 767c478bd9Sstevel@tonic-gate */ 777c478bd9Sstevel@tonic-gate mcpup->mondo_data = contig_mem_alloc(INTR_REPORT_SIZE); 78982b9107Sjb145095 79982b9107Sjb145095 if (mcpup->mondo_data == NULL) { 80982b9107Sjb145095 cmn_err(CE_NOTE, "cpu%d: cpu mondo_data allocation failed", 817c478bd9Sstevel@tonic-gate cpu->cpu_id); 82982b9107Sjb145095 return (ENOMEM); 83982b9107Sjb145095 } 847c478bd9Sstevel@tonic-gate /* 857c478bd9Sstevel@tonic-gate * va_to_pa() is too expensive to call for every crosscall 867c478bd9Sstevel@tonic-gate * so we do it here at init time and save it in machcpu. 877c478bd9Sstevel@tonic-gate */ 887c478bd9Sstevel@tonic-gate mcpup->mondo_data_ra = va_to_pa(mcpup->mondo_data); 897c478bd9Sstevel@tonic-gate 907c478bd9Sstevel@tonic-gate /* 91*4001936eSAnthony Yznaga * Allocate a per-cpu list of ncpu_guest_max for xcalls 92982b9107Sjb145095 */ 93*4001936eSAnthony Yznaga size = ncpu_guest_max * sizeof (uint16_t); 94982b9107Sjb145095 if (size < INTR_REPORT_SIZE) 95982b9107Sjb145095 size = INTR_REPORT_SIZE; 96982b9107Sjb145095 97*4001936eSAnthony Yznaga /* 98*4001936eSAnthony Yznaga * contig_mem_alloc() requires size to be a power of 2. 99*4001936eSAnthony Yznaga * Increase size to a power of 2 if necessary. 100*4001936eSAnthony Yznaga */ 101*4001936eSAnthony Yznaga if ((size & (size - 1)) != 0) { 102*4001936eSAnthony Yznaga size = 1 << highbit(size); 103*4001936eSAnthony Yznaga } 104*4001936eSAnthony Yznaga 105982b9107Sjb145095 mcpup->cpu_list = contig_mem_alloc(size); 106982b9107Sjb145095 107982b9107Sjb145095 if (mcpup->cpu_list == NULL) { 108982b9107Sjb145095 cmn_err(CE_NOTE, "cpu%d: cpu cpu_list allocation failed", 109982b9107Sjb145095 cpu->cpu_id); 110982b9107Sjb145095 return (ENOMEM); 111982b9107Sjb145095 } 112982b9107Sjb145095 mcpup->cpu_list_ra = va_to_pa(mcpup->cpu_list); 113982b9107Sjb145095 114982b9107Sjb145095 /* 1157c478bd9Sstevel@tonic-gate * Allocate sun4v interrupt and error queues. 1167c478bd9Sstevel@tonic-gate */ 117982b9107Sjb145095 size = cpu_q_entries * INTR_REPORT_SIZE; 118982b9107Sjb145095 119982b9107Sjb145095 mcpup->cpu_q_va = contig_mem_alloc(size); 120982b9107Sjb145095 121982b9107Sjb145095 if (mcpup->cpu_q_va == NULL) { 122982b9107Sjb145095 cmn_err(CE_NOTE, "cpu%d: cpu intrq allocation failed", 1237c478bd9Sstevel@tonic-gate cpu->cpu_id); 124982b9107Sjb145095 return (ENOMEM); 125982b9107Sjb145095 } 1267c478bd9Sstevel@tonic-gate mcpup->cpu_q_base_pa = va_to_pa(mcpup->cpu_q_va); 127982b9107Sjb145095 mcpup->cpu_q_size = size; 1287c478bd9Sstevel@tonic-gate 129982b9107Sjb145095 /* 130982b9107Sjb145095 * Allocate device queues 131982b9107Sjb145095 */ 132982b9107Sjb145095 size = dev_q_entries * INTR_REPORT_SIZE; 133982b9107Sjb145095 134982b9107Sjb145095 mcpup->dev_q_va = contig_mem_alloc(size); 135982b9107Sjb145095 136982b9107Sjb145095 if (mcpup->dev_q_va == NULL) { 137982b9107Sjb145095 cmn_err(CE_NOTE, "cpu%d: dev intrq allocation failed", 1387c478bd9Sstevel@tonic-gate cpu->cpu_id); 139982b9107Sjb145095 return (ENOMEM); 140982b9107Sjb145095 } 1417c478bd9Sstevel@tonic-gate mcpup->dev_q_base_pa = va_to_pa(mcpup->dev_q_va); 142982b9107Sjb145095 mcpup->dev_q_size = size; 1437c478bd9Sstevel@tonic-gate 144982b9107Sjb145095 /* 145982b9107Sjb145095 * Allocate resumable queue and its kernel buffer 146982b9107Sjb145095 */ 147982b9107Sjb145095 size = cpu_rq_entries * Q_ENTRY_SIZE; 148982b9107Sjb145095 149982b9107Sjb145095 mcpup->cpu_rq_va = contig_mem_alloc(2 * size); 150982b9107Sjb145095 151982b9107Sjb145095 if (mcpup->cpu_rq_va == NULL) { 152982b9107Sjb145095 cmn_err(CE_NOTE, "cpu%d: resumable queue allocation failed", 1537c478bd9Sstevel@tonic-gate cpu->cpu_id); 154982b9107Sjb145095 return (ENOMEM); 155982b9107Sjb145095 } 1567c478bd9Sstevel@tonic-gate mcpup->cpu_rq_base_pa = va_to_pa(mcpup->cpu_rq_va); 157982b9107Sjb145095 mcpup->cpu_rq_size = size; 1587c478bd9Sstevel@tonic-gate /* zero out the memory */ 159982b9107Sjb145095 bzero(mcpup->cpu_rq_va, 2 * size); 1607c478bd9Sstevel@tonic-gate 161982b9107Sjb145095 /* 162982b9107Sjb145095 * Allocate non-resumable queues 163982b9107Sjb145095 */ 164982b9107Sjb145095 size = cpu_nrq_entries * Q_ENTRY_SIZE; 165982b9107Sjb145095 166982b9107Sjb145095 mcpup->cpu_nrq_va = contig_mem_alloc(2 * size); 167982b9107Sjb145095 168982b9107Sjb145095 if (mcpup->cpu_nrq_va == NULL) { 169982b9107Sjb145095 cmn_err(CE_NOTE, "cpu%d: nonresumable queue allocation failed", 170982b9107Sjb145095 cpu->cpu_id); 171982b9107Sjb145095 return (ENOMEM); 172982b9107Sjb145095 } 1737c478bd9Sstevel@tonic-gate mcpup->cpu_nrq_base_pa = va_to_pa(mcpup->cpu_nrq_va); 174982b9107Sjb145095 mcpup->cpu_nrq_size = size; 1757c478bd9Sstevel@tonic-gate /* zero out the memory */ 176982b9107Sjb145095 bzero(mcpup->cpu_nrq_va, 2 * size); 177982b9107Sjb145095 178982b9107Sjb145095 return (0); 1791ae08745Sheppo } 1807c478bd9Sstevel@tonic-gate 1811ae08745Sheppo void 1821ae08745Sheppo cpu_intrq_cleanup(struct cpu *cpu) 1831ae08745Sheppo { 1841ae08745Sheppo struct machcpu *mcpup = &cpu->cpu_m; 1851ae08745Sheppo int cpu_list_size; 1861ae08745Sheppo uint64_t cpu_q_size; 1871ae08745Sheppo uint64_t dev_q_size; 1881ae08745Sheppo uint64_t cpu_rq_size; 1891ae08745Sheppo uint64_t cpu_nrq_size; 1901ae08745Sheppo 1911ae08745Sheppo /* 1921ae08745Sheppo * Free mondo data for xcalls. 1931ae08745Sheppo */ 1941ae08745Sheppo if (mcpup->mondo_data) { 1951ae08745Sheppo contig_mem_free(mcpup->mondo_data, INTR_REPORT_SIZE); 1961ae08745Sheppo mcpup->mondo_data = NULL; 1971ae08745Sheppo mcpup->mondo_data_ra = NULL; 1981ae08745Sheppo } 1991ae08745Sheppo 2001ae08745Sheppo /* 201*4001936eSAnthony Yznaga * Free per-cpu list of ncpu_guest_max for xcalls 2021ae08745Sheppo */ 203*4001936eSAnthony Yznaga cpu_list_size = ncpu_guest_max * sizeof (uint16_t); 2041ae08745Sheppo if (cpu_list_size < INTR_REPORT_SIZE) 2051ae08745Sheppo cpu_list_size = INTR_REPORT_SIZE; 2061ae08745Sheppo 207*4001936eSAnthony Yznaga /* 208*4001936eSAnthony Yznaga * contig_mem_alloc() requires size to be a power of 2. 209*4001936eSAnthony Yznaga * Increase size to a power of 2 if necessary. 210*4001936eSAnthony Yznaga */ 211*4001936eSAnthony Yznaga if ((cpu_list_size & (cpu_list_size - 1)) != 0) { 212*4001936eSAnthony Yznaga cpu_list_size = 1 << highbit(cpu_list_size); 213*4001936eSAnthony Yznaga } 214*4001936eSAnthony Yznaga 2151ae08745Sheppo if (mcpup->cpu_list) { 2161ae08745Sheppo contig_mem_free(mcpup->cpu_list, cpu_list_size); 2171ae08745Sheppo mcpup->cpu_list = NULL; 2181ae08745Sheppo mcpup->cpu_list_ra = NULL; 2191ae08745Sheppo } 2201ae08745Sheppo 2211ae08745Sheppo /* 2221ae08745Sheppo * Free sun4v interrupt and error queues. 2231ae08745Sheppo */ 2241ae08745Sheppo if (mcpup->cpu_q_va) { 2251ae08745Sheppo cpu_q_size = cpu_q_entries * INTR_REPORT_SIZE; 2261ae08745Sheppo contig_mem_free(mcpup->cpu_q_va, cpu_q_size); 2271ae08745Sheppo mcpup->cpu_q_va = NULL; 2281ae08745Sheppo mcpup->cpu_q_base_pa = NULL; 2291ae08745Sheppo mcpup->cpu_q_size = 0; 2301ae08745Sheppo } 2311ae08745Sheppo 2321ae08745Sheppo if (mcpup->dev_q_va) { 2331ae08745Sheppo dev_q_size = dev_q_entries * INTR_REPORT_SIZE; 2341ae08745Sheppo contig_mem_free(mcpup->dev_q_va, dev_q_size); 2351ae08745Sheppo mcpup->dev_q_va = NULL; 2361ae08745Sheppo mcpup->dev_q_base_pa = NULL; 2371ae08745Sheppo mcpup->dev_q_size = 0; 2381ae08745Sheppo } 2391ae08745Sheppo 2401ae08745Sheppo if (mcpup->cpu_rq_va) { 2411ae08745Sheppo cpu_rq_size = cpu_rq_entries * Q_ENTRY_SIZE; 2421ae08745Sheppo contig_mem_free(mcpup->cpu_rq_va, 2 * cpu_rq_size); 2431ae08745Sheppo mcpup->cpu_rq_va = NULL; 2441ae08745Sheppo mcpup->cpu_rq_base_pa = NULL; 2451ae08745Sheppo mcpup->cpu_rq_size = 0; 2461ae08745Sheppo } 2471ae08745Sheppo 2481ae08745Sheppo if (mcpup->cpu_nrq_va) { 2491ae08745Sheppo cpu_nrq_size = cpu_nrq_entries * Q_ENTRY_SIZE; 2501ae08745Sheppo contig_mem_free(mcpup->cpu_nrq_va, 2 * cpu_nrq_size); 2511ae08745Sheppo mcpup->cpu_nrq_va = NULL; 2521ae08745Sheppo mcpup->cpu_nrq_base_pa = NULL; 2531ae08745Sheppo mcpup->cpu_nrq_size = 0; 2541ae08745Sheppo } 2557c478bd9Sstevel@tonic-gate } 256