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 /*
224001936eSAnthony Yznaga * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
237c478bd9Sstevel@tonic-gate * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate */
257c478bd9Sstevel@tonic-gate
26*79a77829SJosef 'Jeff' Sipek #include <sys/sysmacros.h>
277c478bd9Sstevel@tonic-gate #include <sys/machsystm.h>
287c478bd9Sstevel@tonic-gate #include <sys/cpu.h>
297c478bd9Sstevel@tonic-gate #include <sys/intreg.h>
307c478bd9Sstevel@tonic-gate #include <sys/machcpuvar.h>
317c478bd9Sstevel@tonic-gate #include <vm/hat_sfmmu.h>
327c478bd9Sstevel@tonic-gate #include <sys/error.h>
337c478bd9Sstevel@tonic-gate #include <sys/hypervisor_api.h>
347c478bd9Sstevel@tonic-gate
357c478bd9Sstevel@tonic-gate void
cpu_intrq_register(struct cpu * cpu)367c478bd9Sstevel@tonic-gate cpu_intrq_register(struct cpu *cpu)
377c478bd9Sstevel@tonic-gate {
387c478bd9Sstevel@tonic-gate struct machcpu *mcpup = &cpu->cpu_m;
397c478bd9Sstevel@tonic-gate uint64_t ret;
407c478bd9Sstevel@tonic-gate
417c478bd9Sstevel@tonic-gate ret = hv_cpu_qconf(INTR_CPU_Q, mcpup->cpu_q_base_pa, cpu_q_entries);
427c478bd9Sstevel@tonic-gate if (ret != H_EOK)
437c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, "cpu%d: cpu_mondo queue configuration "
447c478bd9Sstevel@tonic-gate "failed, error %lu", cpu->cpu_id, ret);
457c478bd9Sstevel@tonic-gate
467c478bd9Sstevel@tonic-gate ret = hv_cpu_qconf(INTR_DEV_Q, mcpup->dev_q_base_pa, dev_q_entries);
477c478bd9Sstevel@tonic-gate if (ret != H_EOK)
487c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, "cpu%d: dev_mondo queue configuration "
497c478bd9Sstevel@tonic-gate "failed, error %lu", cpu->cpu_id, ret);
507c478bd9Sstevel@tonic-gate
511ae08745Sheppo ret = hv_cpu_qconf(CPU_RQ, mcpup->cpu_rq_base_pa, cpu_rq_entries);
527c478bd9Sstevel@tonic-gate if (ret != H_EOK)
537c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, "cpu%d: resumable error queue configuration "
547c478bd9Sstevel@tonic-gate "failed, error %lu", cpu->cpu_id, ret);
557c478bd9Sstevel@tonic-gate
561ae08745Sheppo ret = hv_cpu_qconf(CPU_NRQ, mcpup->cpu_nrq_base_pa, cpu_nrq_entries);
577c478bd9Sstevel@tonic-gate if (ret != H_EOK)
587c478bd9Sstevel@tonic-gate cmn_err(CE_PANIC, "cpu%d: non-resumable error queue "
597c478bd9Sstevel@tonic-gate "configuration failed, error %lu", cpu->cpu_id, ret);
607c478bd9Sstevel@tonic-gate }
617c478bd9Sstevel@tonic-gate
62982b9107Sjb145095 int
cpu_intrq_setup(struct cpu * cpu)637c478bd9Sstevel@tonic-gate cpu_intrq_setup(struct cpu *cpu)
647c478bd9Sstevel@tonic-gate {
657c478bd9Sstevel@tonic-gate struct machcpu *mcpup = &cpu->cpu_m;
66982b9107Sjb145095 size_t size;
67982b9107Sjb145095
68982b9107Sjb145095 /*
69982b9107Sjb145095 * This routine will return with an error return if any
70982b9107Sjb145095 * contig_mem_alloc() fails. It is expected that the caller will
71982b9107Sjb145095 * call cpu_intrq_cleanup() (or cleanup_cpu_common() which will).
72982b9107Sjb145095 * That will cleanly free only those blocks that were alloc'd.
73982b9107Sjb145095 */
747c478bd9Sstevel@tonic-gate
757c478bd9Sstevel@tonic-gate /*
767c478bd9Sstevel@tonic-gate * Allocate mondo data for xcalls.
777c478bd9Sstevel@tonic-gate */
787c478bd9Sstevel@tonic-gate mcpup->mondo_data = contig_mem_alloc(INTR_REPORT_SIZE);
79982b9107Sjb145095
80982b9107Sjb145095 if (mcpup->mondo_data == NULL) {
81982b9107Sjb145095 cmn_err(CE_NOTE, "cpu%d: cpu mondo_data allocation failed",
827c478bd9Sstevel@tonic-gate cpu->cpu_id);
83982b9107Sjb145095 return (ENOMEM);
84982b9107Sjb145095 }
857c478bd9Sstevel@tonic-gate /*
867c478bd9Sstevel@tonic-gate * va_to_pa() is too expensive to call for every crosscall
877c478bd9Sstevel@tonic-gate * so we do it here at init time and save it in machcpu.
887c478bd9Sstevel@tonic-gate */
897c478bd9Sstevel@tonic-gate mcpup->mondo_data_ra = va_to_pa(mcpup->mondo_data);
907c478bd9Sstevel@tonic-gate
917c478bd9Sstevel@tonic-gate /*
924001936eSAnthony Yznaga * Allocate a per-cpu list of ncpu_guest_max for xcalls
93982b9107Sjb145095 */
944001936eSAnthony Yznaga size = ncpu_guest_max * sizeof (uint16_t);
95982b9107Sjb145095 if (size < INTR_REPORT_SIZE)
96982b9107Sjb145095 size = INTR_REPORT_SIZE;
97982b9107Sjb145095
984001936eSAnthony Yznaga /*
994001936eSAnthony Yznaga * contig_mem_alloc() requires size to be a power of 2.
1004001936eSAnthony Yznaga * Increase size to a power of 2 if necessary.
1014001936eSAnthony Yznaga */
102*79a77829SJosef 'Jeff' Sipek if (!ISP2(size)) {
1034001936eSAnthony Yznaga size = 1 << highbit(size);
1044001936eSAnthony Yznaga }
1054001936eSAnthony Yznaga
106982b9107Sjb145095 mcpup->cpu_list = contig_mem_alloc(size);
107982b9107Sjb145095
108982b9107Sjb145095 if (mcpup->cpu_list == NULL) {
109982b9107Sjb145095 cmn_err(CE_NOTE, "cpu%d: cpu cpu_list allocation failed",
110982b9107Sjb145095 cpu->cpu_id);
111982b9107Sjb145095 return (ENOMEM);
112982b9107Sjb145095 }
113982b9107Sjb145095 mcpup->cpu_list_ra = va_to_pa(mcpup->cpu_list);
114982b9107Sjb145095
115982b9107Sjb145095 /*
1167c478bd9Sstevel@tonic-gate * Allocate sun4v interrupt and error queues.
1177c478bd9Sstevel@tonic-gate */
118982b9107Sjb145095 size = cpu_q_entries * INTR_REPORT_SIZE;
119982b9107Sjb145095
120982b9107Sjb145095 mcpup->cpu_q_va = contig_mem_alloc(size);
121982b9107Sjb145095
122982b9107Sjb145095 if (mcpup->cpu_q_va == NULL) {
123982b9107Sjb145095 cmn_err(CE_NOTE, "cpu%d: cpu intrq allocation failed",
1247c478bd9Sstevel@tonic-gate cpu->cpu_id);
125982b9107Sjb145095 return (ENOMEM);
126982b9107Sjb145095 }
1277c478bd9Sstevel@tonic-gate mcpup->cpu_q_base_pa = va_to_pa(mcpup->cpu_q_va);
128982b9107Sjb145095 mcpup->cpu_q_size = size;
1297c478bd9Sstevel@tonic-gate
130982b9107Sjb145095 /*
131982b9107Sjb145095 * Allocate device queues
132982b9107Sjb145095 */
133982b9107Sjb145095 size = dev_q_entries * INTR_REPORT_SIZE;
134982b9107Sjb145095
135982b9107Sjb145095 mcpup->dev_q_va = contig_mem_alloc(size);
136982b9107Sjb145095
137982b9107Sjb145095 if (mcpup->dev_q_va == NULL) {
138982b9107Sjb145095 cmn_err(CE_NOTE, "cpu%d: dev intrq allocation failed",
1397c478bd9Sstevel@tonic-gate cpu->cpu_id);
140982b9107Sjb145095 return (ENOMEM);
141982b9107Sjb145095 }
1427c478bd9Sstevel@tonic-gate mcpup->dev_q_base_pa = va_to_pa(mcpup->dev_q_va);
143982b9107Sjb145095 mcpup->dev_q_size = size;
1447c478bd9Sstevel@tonic-gate
145982b9107Sjb145095 /*
146982b9107Sjb145095 * Allocate resumable queue and its kernel buffer
147982b9107Sjb145095 */
148982b9107Sjb145095 size = cpu_rq_entries * Q_ENTRY_SIZE;
149982b9107Sjb145095
150982b9107Sjb145095 mcpup->cpu_rq_va = contig_mem_alloc(2 * size);
151982b9107Sjb145095
152982b9107Sjb145095 if (mcpup->cpu_rq_va == NULL) {
153982b9107Sjb145095 cmn_err(CE_NOTE, "cpu%d: resumable queue allocation failed",
1547c478bd9Sstevel@tonic-gate cpu->cpu_id);
155982b9107Sjb145095 return (ENOMEM);
156982b9107Sjb145095 }
1577c478bd9Sstevel@tonic-gate mcpup->cpu_rq_base_pa = va_to_pa(mcpup->cpu_rq_va);
158982b9107Sjb145095 mcpup->cpu_rq_size = size;
1597c478bd9Sstevel@tonic-gate /* zero out the memory */
160982b9107Sjb145095 bzero(mcpup->cpu_rq_va, 2 * size);
1617c478bd9Sstevel@tonic-gate
162982b9107Sjb145095 /*
163982b9107Sjb145095 * Allocate non-resumable queues
164982b9107Sjb145095 */
165982b9107Sjb145095 size = cpu_nrq_entries * Q_ENTRY_SIZE;
166982b9107Sjb145095
167982b9107Sjb145095 mcpup->cpu_nrq_va = contig_mem_alloc(2 * size);
168982b9107Sjb145095
169982b9107Sjb145095 if (mcpup->cpu_nrq_va == NULL) {
170982b9107Sjb145095 cmn_err(CE_NOTE, "cpu%d: nonresumable queue allocation failed",
171982b9107Sjb145095 cpu->cpu_id);
172982b9107Sjb145095 return (ENOMEM);
173982b9107Sjb145095 }
1747c478bd9Sstevel@tonic-gate mcpup->cpu_nrq_base_pa = va_to_pa(mcpup->cpu_nrq_va);
175982b9107Sjb145095 mcpup->cpu_nrq_size = size;
1767c478bd9Sstevel@tonic-gate /* zero out the memory */
177982b9107Sjb145095 bzero(mcpup->cpu_nrq_va, 2 * size);
178982b9107Sjb145095
179982b9107Sjb145095 return (0);
1801ae08745Sheppo }
1817c478bd9Sstevel@tonic-gate
1821ae08745Sheppo void
cpu_intrq_cleanup(struct cpu * cpu)1831ae08745Sheppo cpu_intrq_cleanup(struct cpu *cpu)
1841ae08745Sheppo {
1851ae08745Sheppo struct machcpu *mcpup = &cpu->cpu_m;
1861ae08745Sheppo int cpu_list_size;
1871ae08745Sheppo uint64_t cpu_q_size;
1881ae08745Sheppo uint64_t dev_q_size;
1891ae08745Sheppo uint64_t cpu_rq_size;
1901ae08745Sheppo uint64_t cpu_nrq_size;
1911ae08745Sheppo
1921ae08745Sheppo /*
1931ae08745Sheppo * Free mondo data for xcalls.
1941ae08745Sheppo */
1951ae08745Sheppo if (mcpup->mondo_data) {
1961ae08745Sheppo contig_mem_free(mcpup->mondo_data, INTR_REPORT_SIZE);
1971ae08745Sheppo mcpup->mondo_data = NULL;
1981ae08745Sheppo mcpup->mondo_data_ra = NULL;
1991ae08745Sheppo }
2001ae08745Sheppo
2011ae08745Sheppo /*
2024001936eSAnthony Yznaga * Free per-cpu list of ncpu_guest_max for xcalls
2031ae08745Sheppo */
2044001936eSAnthony Yznaga cpu_list_size = ncpu_guest_max * sizeof (uint16_t);
2051ae08745Sheppo if (cpu_list_size < INTR_REPORT_SIZE)
2061ae08745Sheppo cpu_list_size = INTR_REPORT_SIZE;
2071ae08745Sheppo
2084001936eSAnthony Yznaga /*
2094001936eSAnthony Yznaga * contig_mem_alloc() requires size to be a power of 2.
2104001936eSAnthony Yznaga * Increase size to a power of 2 if necessary.
2114001936eSAnthony Yznaga */
212*79a77829SJosef 'Jeff' Sipek if (!ISP2(cpu_list_size)) {
2134001936eSAnthony Yznaga cpu_list_size = 1 << highbit(cpu_list_size);
2144001936eSAnthony Yznaga }
2154001936eSAnthony Yznaga
2161ae08745Sheppo if (mcpup->cpu_list) {
2171ae08745Sheppo contig_mem_free(mcpup->cpu_list, cpu_list_size);
2181ae08745Sheppo mcpup->cpu_list = NULL;
2191ae08745Sheppo mcpup->cpu_list_ra = NULL;
2201ae08745Sheppo }
2211ae08745Sheppo
2221ae08745Sheppo /*
2231ae08745Sheppo * Free sun4v interrupt and error queues.
2241ae08745Sheppo */
2251ae08745Sheppo if (mcpup->cpu_q_va) {
2261ae08745Sheppo cpu_q_size = cpu_q_entries * INTR_REPORT_SIZE;
2271ae08745Sheppo contig_mem_free(mcpup->cpu_q_va, cpu_q_size);
2281ae08745Sheppo mcpup->cpu_q_va = NULL;
2291ae08745Sheppo mcpup->cpu_q_base_pa = NULL;
2301ae08745Sheppo mcpup->cpu_q_size = 0;
2311ae08745Sheppo }
2321ae08745Sheppo
2331ae08745Sheppo if (mcpup->dev_q_va) {
2341ae08745Sheppo dev_q_size = dev_q_entries * INTR_REPORT_SIZE;
2351ae08745Sheppo contig_mem_free(mcpup->dev_q_va, dev_q_size);
2361ae08745Sheppo mcpup->dev_q_va = NULL;
2371ae08745Sheppo mcpup->dev_q_base_pa = NULL;
2381ae08745Sheppo mcpup->dev_q_size = 0;
2391ae08745Sheppo }
2401ae08745Sheppo
2411ae08745Sheppo if (mcpup->cpu_rq_va) {
2421ae08745Sheppo cpu_rq_size = cpu_rq_entries * Q_ENTRY_SIZE;
2431ae08745Sheppo contig_mem_free(mcpup->cpu_rq_va, 2 * cpu_rq_size);
2441ae08745Sheppo mcpup->cpu_rq_va = NULL;
2451ae08745Sheppo mcpup->cpu_rq_base_pa = NULL;
2461ae08745Sheppo mcpup->cpu_rq_size = 0;
2471ae08745Sheppo }
2481ae08745Sheppo
2491ae08745Sheppo if (mcpup->cpu_nrq_va) {
2501ae08745Sheppo cpu_nrq_size = cpu_nrq_entries * Q_ENTRY_SIZE;
2511ae08745Sheppo contig_mem_free(mcpup->cpu_nrq_va, 2 * cpu_nrq_size);
2521ae08745Sheppo mcpup->cpu_nrq_va = NULL;
2531ae08745Sheppo mcpup->cpu_nrq_base_pa = NULL;
2541ae08745Sheppo mcpup->cpu_nrq_size = 0;
2551ae08745Sheppo }
2567c478bd9Sstevel@tonic-gate }
257