Print this page
XXXX introduce drv_sectohz
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/i86xpv/cpu/generic_cpu/gcpu_poll_xpv.c
+++ new/usr/src/uts/i86xpv/cpu/generic_cpu/gcpu_poll_xpv.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 25 */
26 26
27 27 /*
28 28 * "Polled" MCA events in an i86xpv dom0. A timeout runs in the hypervisor
29 29 * and checks MCA state. If it observes valid MCA state in a bank and if
30 30 * it sees that dom0 has registered a handler for the VIRQ_MCA then it
31 31 * raises that VIRQ to dom0. The interrupt handler performs a
32 32 * hypercall to retrieve the polled telemetry and then pushes that telemetry
33 33 * into the MSR interpose hash and calls the generic logout code which
34 34 * will then find the provided interposed MSR values when it performs
35 35 * cmi_hdl_rdmsr so logout code works unchanged for native or i86xpv dom0.
36 36 */
37 37
38 38 #include <sys/types.h>
39 39 #include <sys/conf.h>
40 40 #include <sys/x86_archext.h>
41 41 #include <sys/mca_x86.h>
42 42 #include <sys/ddi.h>
43 43 #include <sys/spl.h>
44 44 #include <sys/sunddi.h>
45 45 #include <sys/evtchn_impl.h>
46 46 #include <sys/hypervisor.h>
47 47
48 48 #include "../../i86pc/cpu/generic_cpu/gcpu.h"
49 49
50 50 extern int *gcpu_xpv_telem_read(mc_info_t *, int, uint64_t *);
51 51 extern void gcpu_xpv_telem_ack(int, uint64_t);
52 52 extern void gcpu_xpv_mci_process(mc_info_t *, int, cmi_mca_regs_t *, size_t);
53 53
54 54 int gcpu_xpv_mch_poll_interval_secs = 10;
55 55 int gcpu_xpv_virq_level = 3;
56 56
57 57 static timeout_id_t gcpu_xpv_mch_poll_timeoutid;
58 58
59 59 static int gcpu_xpv_virq_vect = -1;
60 60
61 61 static mc_info_t gcpu_xpv_polldata;
62 62 static kmutex_t gcpu_xpv_polldata_lock;
63 63
64 64 static cmi_mca_regs_t *gcpu_xpv_poll_bankregs;
65 65 static size_t gcpu_xpv_poll_bankregs_sz;
66 66
67 67 static uint32_t gcpu_xpv_intr_unclaimed;
68 68 static uint32_t gcpu_xpv_mca_hcall_busy;
69 69
70 70 static gcpu_poll_trace_ctl_t gcpu_xpv_poll_trace_ctl;
71 71
72 72 #define GCPU_XPV_ARCH_NREGS 3
73 73 #define GCPU_XPV_MCH_POLL_REARM ((void *)1)
74 74 #define GCPU_XPV_MCH_POLL_NO_REARM NULL
75 75
76 76 static uint_t
77 77 gcpu_xpv_virq_intr(void)
78 78 {
79 79 int types[] = { XEN_MC_URGENT, XEN_MC_NONURGENT };
80 80 uint64_t fetch_id;
81 81 int count = 0;
82 82 int i;
83 83
84 84 if (gcpu_xpv_virq_vect == -1 || gcpu_xpv_poll_bankregs_sz == 0) {
85 85 gcpu_xpv_intr_unclaimed++;
86 86 return (DDI_INTR_UNCLAIMED);
87 87 }
88 88
89 89 if (!mutex_tryenter(&gcpu_xpv_polldata_lock)) {
90 90 gcpu_xpv_mca_hcall_busy++;
91 91 return (DDI_INTR_CLAIMED);
92 92 }
93 93
94 94 for (i = 0; i < sizeof (types) / sizeof (types[0]); i++) {
95 95 while (gcpu_xpv_telem_read(&gcpu_xpv_polldata, types[i],
96 96 &fetch_id)) {
97 97 gcpu_poll_trace(&gcpu_xpv_poll_trace_ctl,
98 98 GCPU_MPT_WHAT_XPV_VIRQ,
99 99 x86_mcinfo_nentries(&gcpu_xpv_polldata));
100 100 gcpu_xpv_mci_process(&gcpu_xpv_polldata, types[i],
101 101 gcpu_xpv_poll_bankregs, gcpu_xpv_poll_bankregs_sz);
102 102 gcpu_xpv_telem_ack(types[i], fetch_id);
103 103 count++;
104 104 }
105 105 }
106 106
107 107 mutex_exit(&gcpu_xpv_polldata_lock);
108 108
109 109 return (DDI_INTR_CLAIMED);
110 110 }
111 111
112 112 static void
113 113 gcpu_xpv_mch_poll(void *arg)
114 114 {
115 115 cmi_hdl_t hdl = cmi_hdl_any();
↓ open down ↓ |
115 lines elided |
↑ open up ↑ |
116 116
117 117 if (hdl != NULL) {
118 118 cmi_mc_logout(hdl, 0, 0);
119 119 cmi_hdl_rele(hdl);
120 120 }
121 121
122 122 if (arg == GCPU_XPV_MCH_POLL_REARM &&
123 123 gcpu_xpv_mch_poll_interval_secs != 0) {
124 124 gcpu_xpv_mch_poll_timeoutid = timeout(gcpu_xpv_mch_poll,
125 125 GCPU_XPV_MCH_POLL_REARM,
126 - drv_usectohz(gcpu_xpv_mch_poll_interval_secs * MICROSEC));
126 + drv_sectohz(gcpu_xpv_mch_poll_interval_secs));
127 127 }
128 128 }
129 129
130 130 /*
131 131 * gcpu_mca_poll_init is called from gcpu_mca_init for each cpu handle
132 132 * that we initialize for. It should prepare for polling by allocating
133 133 * control structures and the like, but must not kick polling off yet.
134 134 *
135 135 * Since we initialize all cpus in a serialized loop there is no race
136 136 * on allocating the bankregs structure, nor in free'ing and enlarging
137 137 * it if we find the number of MCA banks is not uniform in the system
138 138 * (unlikely) since polling is only started post mp startup.
139 139 */
140 140
141 141 void
142 142 gcpu_mca_poll_init(cmi_hdl_t hdl)
143 143 {
144 144 gcpu_data_t *gcpu = cmi_hdl_getcmidata(hdl);
145 145 int nbanks = gcpu->gcpu_mca.gcpu_mca_nbanks;
146 146 size_t sz = nbanks * GCPU_XPV_ARCH_NREGS * sizeof (cmi_mca_regs_t);
147 147
148 148 ASSERT(cmi_hdl_class(hdl) == CMI_HDL_SOLARIS_xVM_MCA);
149 149
150 150 if (gcpu_xpv_poll_bankregs == NULL || sz > gcpu_xpv_poll_bankregs_sz) {
151 151 if (gcpu_xpv_poll_bankregs != NULL) {
152 152 kmem_free(gcpu_xpv_poll_bankregs,
153 153 gcpu_xpv_poll_bankregs_sz);
154 154 } else {
155 155 gcpu_poll_trace_init(&gcpu_xpv_poll_trace_ctl);
156 156 }
157 157
158 158 gcpu_xpv_poll_bankregs_sz = sz;
159 159 gcpu_xpv_poll_bankregs = kmem_zalloc(sz, KM_SLEEP);
160 160
161 161 }
162 162 }
163 163
164 164 /* deconfigure gcpu_mca_poll_init() */
165 165 void
166 166 gcpu_mca_poll_fini(cmi_hdl_t hdl)
167 167 {
168 168 }
169 169
170 170 void
171 171 gcpu_mca_poll_start(cmi_hdl_t hdl)
172 172 {
173 173 ASSERT(cmi_hdl_class(hdl) == CMI_HDL_SOLARIS_xVM_MCA);
174 174 /*
175 175 * We are on the boot cpu (cpu 0), called at the end of its
↓ open down ↓ |
39 lines elided |
↑ open up ↑ |
176 176 * multiprocessor startup.
177 177 */
178 178 if (gcpu_xpv_poll_bankregs_sz != 0 && gcpu_xpv_virq_vect == -1) {
179 179 /*
180 180 * The hypervisor will poll MCA state for us, but it cannot
181 181 * poll MCH state so we do that via a timeout.
182 182 */
183 183 if (gcpu_xpv_mch_poll_interval_secs != 0) {
184 184 gcpu_xpv_mch_poll_timeoutid =
185 185 timeout(gcpu_xpv_mch_poll, GCPU_XPV_MCH_POLL_REARM,
186 - drv_usectohz(gcpu_xpv_mch_poll_interval_secs *
187 - MICROSEC));
186 + drv_sectohz(gcpu_xpv_mch_poll_interval_secs));
188 187 }
189 188
190 189 /*
191 190 * Register handler for VIRQ_MCA; once this is in place
192 191 * the hypervisor will begin to forward polled MCA observations
193 192 * to us.
194 193 */
195 194 gcpu_xpv_virq_vect = ec_bind_virq_to_irq(VIRQ_MCA, 0);
196 195 (void) add_avintr(NULL, gcpu_xpv_virq_level,
197 196 (avfunc)gcpu_xpv_virq_intr, "MCA", gcpu_xpv_virq_vect,
198 197 NULL, NULL, NULL, NULL);
199 198 }
200 199 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX