xref: /titanic_41/usr/src/uts/sun4v/os/intrq.c (revision 4001936ee6565d82b01da4c3755d63fcf692de34)
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