ia64/xen-unstable

view xen/arch/ia64/vmx/viosapic.c @ 16171:e7d7a4adf357

[IA64] vti domain save/restore: implement hvm_save/load. work in progress.

Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
author Alex Williamson <alex.williamson@hp.com>
date Sun Oct 21 14:39:07 2007 -0600 (2007-10-21)
parents ab89a931f94f
children d5bcf03596cc
line source
1 /*
2 * Copyright (C) 2001 MandrakeSoft S.A.
3 *
4 * MandrakeSoft S.A.
5 * 43, rue d'Aboukir
6 * 75002 Paris - France
7 * http://www.linux-mandrake.com/
8 * http://www.mandrakesoft.com/
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 *
24 * Yunhong Jiang <yunhong.jiang@intel.com>
25 * Ported to xen by using virtual IRQ line.
26 *
27 * Copyright (C) 2007 VA Linux Systems Japan K.K.
28 * Isaku Yamahata <yamahata at valinux co jp>
29 * SMP support
30 * xen save/restore support
31 */
33 #include <xen/config.h>
34 #include <xen/types.h>
35 #include <xen/mm.h>
36 #include <xen/xmalloc.h>
37 #include <xen/lib.h>
38 #include <xen/errno.h>
39 #include <public/hvm/ioreq.h>
40 #include <asm/vlsapic.h>
41 #include <asm/viosapic.h>
42 #include <asm/current.h>
43 #include <asm/event.h>
44 #include <asm/hvm/support.h>
45 #include <public/hvm/save.h>
47 static void viosapic_deliver(struct viosapic *viosapic, int irq)
48 {
49 uint16_t dest = viosapic->redirtbl[irq].dest_id;
50 uint8_t delivery_mode = viosapic->redirtbl[irq].delivery_mode;
51 uint8_t vector = viosapic->redirtbl[irq].vector;
52 struct vcpu *v;
54 ASSERT(spin_is_locked(&viosapic->lock));
55 switch ( delivery_mode )
56 {
57 case SAPIC_FIXED:
58 {
59 v = vlsapic_lid_to_vcpu(viosapic_domain(viosapic), dest);
60 vlsapic_set_irq(v, vector);
61 vcpu_kick(v);
62 break;
63 }
64 case SAPIC_LOWEST_PRIORITY:
65 {
66 v = vlsapic_lid_to_vcpu(viosapic_domain(viosapic), dest);
67 if (viosapic->lowest_vcpu)
68 v = viosapic->lowest_vcpu;
69 vlsapic_set_irq(v, vector);
70 vcpu_kick(v);
71 break;
72 }
73 case SAPIC_PMI:
74 case SAPIC_NMI:
75 case SAPIC_INIT:
76 case SAPIC_EXTINT:
77 default:
78 gdprintk(XENLOG_WARNING, "Unsupported delivery mode %d\n",
79 delivery_mode);
80 break;
81 }
82 }
85 static int iosapic_get_highest_irq(struct viosapic *viosapic)
86 {
87 uint64_t irqs = viosapic->irr & ~viosapic->isr ;
89 if (irqs)
90 return ia64_fls(irqs);
92 return -1;
93 }
96 /* XXX If level interrupt, use vector->irq table for performance */
97 static int get_redir_num(struct viosapic *viosapic, int vector)
98 {
99 int i;
101 ASSERT(spin_is_locked(&viosapic->lock));
102 for ( i = 0; i < VIOSAPIC_NUM_PINS; i++ )
103 if ( viosapic->redirtbl[i].vector == vector )
104 return i;
106 return -1;
107 }
110 static void service_iosapic(struct viosapic *viosapic)
111 {
112 int irq;
114 while ( (irq = iosapic_get_highest_irq(viosapic)) != -1 )
115 {
116 if ( viosapic->redirtbl[irq].trig_mode == SAPIC_LEVEL )
117 viosapic->isr |= (1UL << irq);
119 viosapic_deliver(viosapic, irq);
121 viosapic->irr &= ~(1UL << irq);
122 }
123 }
126 static void viosapic_update_EOI(struct viosapic *viosapic, int vector)
127 {
128 int redir_num;
130 spin_lock(&viosapic->lock);
131 if ( (redir_num = get_redir_num(viosapic, vector)) == -1 )
132 {
133 spin_unlock(&viosapic->lock);
134 gdprintk(XENLOG_WARNING, "Can't find redir item for %d EOI\n", vector);
135 return;
136 }
138 if ( !test_and_clear_bit(redir_num, &viosapic->isr) )
139 {
140 spin_unlock(&viosapic->lock);
141 if ( viosapic->redirtbl[redir_num].trig_mode == SAPIC_LEVEL )
142 gdprintk(XENLOG_WARNING, "redir %d not set for %d EOI\n",
143 redir_num, vector);
144 return;
145 }
146 service_iosapic(viosapic);
147 spin_unlock(&viosapic->lock);
148 }
151 static unsigned long viosapic_read_indirect(struct viosapic *viosapic,
152 unsigned long addr,
153 unsigned long length)
154 {
155 unsigned long result = 0;
157 switch ( viosapic->ioregsel )
158 {
159 case VIOSAPIC_VERSION:
160 result = ((((VIOSAPIC_NUM_PINS - 1) & 0xff) << 16)
161 | (VIOSAPIC_VERSION_ID & 0xff));
162 break;
164 default:
165 {
166 /* ioregsel might be written at the same time. copy it before use. */
167 uint32_t ioregsel = viosapic->ioregsel;
168 uint32_t redir_index;
169 uint64_t redir_content;
171 redir_index = (ioregsel - 0x10) >> 1;
172 if ( redir_index >= VIOSAPIC_NUM_PINS )
173 {
174 gdprintk(XENLOG_WARNING, "viosapic_read_indirect:undefined "
175 "ioregsel %x\n", ioregsel);
176 break;
177 }
179 redir_content = viosapic->redirtbl[redir_index].bits;
180 result = (ioregsel & 0x1) ?
181 (redir_content >> 32) & 0xffffffff :
182 redir_content & 0xffffffff;
183 break;
184 }
185 }
187 return result;
188 }
191 unsigned long viosapic_read(struct vcpu *v,
192 unsigned long addr,
193 unsigned long length)
194 {
195 struct viosapic *viosapic = vcpu_viosapic(v);
196 uint32_t result;
198 addr &= 0xff;
200 switch ( addr )
201 {
202 case VIOSAPIC_REG_SELECT:
203 result = viosapic->ioregsel;
204 break;
206 case VIOSAPIC_WINDOW:
207 result = viosapic_read_indirect(viosapic, addr, length);
208 break;
210 default:
211 result = 0;
212 break;
213 }
215 return result;
216 }
219 static void viosapic_write_indirect(struct viosapic *viosapic,
220 unsigned long addr,
221 unsigned long length,
222 unsigned long val)
223 {
224 switch ( viosapic->ioregsel )
225 {
226 case VIOSAPIC_VERSION:
227 /* Writes are ignored. */
228 break;
230 default:
231 {
232 /* ioregsel might be written at the same time. copy it before use. */
233 uint32_t ioregsel = viosapic->ioregsel;
234 uint32_t redir_index;
235 uint64_t redir_content;
237 redir_index = (ioregsel - 0x10) >> 1;
238 if ( redir_index >= VIOSAPIC_NUM_PINS )
239 {
240 gdprintk(XENLOG_WARNING, "viosapic_write_indirect "
241 "error register %x\n", viosapic->ioregsel);
242 break;
243 }
245 spin_lock(&viosapic->lock);
246 redir_content = viosapic->redirtbl[redir_index].bits;
248 if ( ioregsel & 0x1 )
249 {
250 redir_content = (((uint64_t)val & 0xffffffff) << 32) |
251 (redir_content & 0xffffffff);
252 }
253 else
254 {
255 redir_content = ((redir_content >> 32) << 32) |
256 (val & 0xffffffff);
257 }
258 viosapic->redirtbl[redir_index].bits = redir_content;
259 spin_unlock(&viosapic->lock);
260 break;
261 }
262 } /* switch */
263 }
266 void viosapic_write(struct vcpu *v,
267 unsigned long addr,
268 unsigned long length,
269 unsigned long val)
270 {
271 struct viosapic *viosapic = vcpu_viosapic(v);
273 addr &= 0xff;
275 switch ( addr )
276 {
277 case VIOSAPIC_REG_SELECT:
278 viosapic->ioregsel = val;
279 break;
281 case VIOSAPIC_WINDOW:
282 viosapic_write_indirect(viosapic, addr, length, val);
283 break;
285 case VIOSAPIC_EOI:
286 viosapic_update_EOI(viosapic, val);
287 break;
289 default:
290 break;
291 }
292 }
295 static void viosapic_reset(struct viosapic *viosapic)
296 {
297 int i;
299 memset(viosapic, 0, sizeof(*viosapic));
301 for ( i = 0; i < VIOSAPIC_NUM_PINS; i++ )
302 {
303 viosapic->redirtbl[i].mask = 0x1;
304 }
305 spin_lock_init(&viosapic->lock);
306 }
308 void viosapic_set_irq(struct domain *d, int irq, int level)
309 {
310 struct viosapic *viosapic = domain_viosapic(d);
311 uint64_t bit;
313 spin_lock(&viosapic->lock);
314 if ( (irq < 0) || (irq >= VIOSAPIC_NUM_PINS) )
315 goto out;
317 if ( viosapic->redirtbl[irq].mask )
318 goto out;
320 bit = 1UL << irq;
321 if ( viosapic->redirtbl[irq].trig_mode == SAPIC_LEVEL )
322 {
323 if ( level )
324 viosapic->irr |= bit;
325 else
326 viosapic->irr &= ~bit;
327 }
328 else
329 {
330 if ( level )
331 /* XXX No irr clear for edge interrupt */
332 viosapic->irr |= bit;
333 }
335 service_iosapic(viosapic);
336 out:
337 spin_unlock(&viosapic->lock);
338 }
340 #define hvm_pci_intx_gsi(dev, intx) \
341 (((((dev) << 2) + ((dev) >> 3) + (intx)) & 31) + 16)
344 void viosapic_set_pci_irq(struct domain *d, int device, int intx, int level)
345 {
346 int irq;
347 irq = hvm_pci_intx_gsi(device, intx);
349 viosapic_set_irq(d, irq, level);
350 }
352 void viosapic_init(struct domain *d)
353 {
354 struct viosapic *viosapic = domain_viosapic(d);
356 viosapic_reset(viosapic);
358 viosapic->lowest_vcpu = NULL;
360 viosapic->base_address = VIOSAPIC_DEFAULT_BASE_ADDRESS;
361 }
363 #define VIOSAPIC_INVALID_VCPU_ID (-1UL)
364 static int viosapic_save(struct domain *d, hvm_domain_context_t *h)
365 {
366 struct viosapic *viosapic = domain_viosapic(d);
367 struct hvm_hw_ia64_viosapic viosapic_save;
368 int i;
370 memset(&viosapic_save, 0, sizeof(viosapic_save));
372 spin_lock(&viosapic->lock);
373 viosapic_save.irr = viosapic->irr;
374 viosapic_save.isr = viosapic->isr;
375 viosapic_save.ioregsel = viosapic->ioregsel;
376 if (viosapic->lowest_vcpu != NULL)
377 viosapic_save.lowest_vcpu_id = viosapic->lowest_vcpu->vcpu_id;
378 else
379 viosapic_save.lowest_vcpu_id = VIOSAPIC_INVALID_VCPU_ID;
380 viosapic_save.base_address = viosapic->base_address;
382 for (i = 0; i < VIOSAPIC_NUM_PINS; i++)
383 viosapic_save.redirtbl[i] = viosapic->redirtbl[i];
384 spin_unlock(&viosapic->lock);
386 return hvm_save_entry(VIOSAPIC, 0, h, &viosapic_save);
387 }
389 static int viosapic_load(struct domain *d, hvm_domain_context_t *h)
390 {
391 struct viosapic *viosapic = domain_viosapic(d);
392 struct hvm_hw_ia64_viosapic viosapic_load;
393 struct vcpu *lowest_vcpu;
394 int i;
396 if (hvm_load_entry(VIOSAPIC, h, &viosapic_load))
397 return -EINVAL;
399 lowest_vcpu = NULL;
400 if (viosapic_load.lowest_vcpu_id < MAX_VIRT_CPUS)
401 lowest_vcpu = d->vcpu[viosapic_load.lowest_vcpu_id];
402 else if (viosapic_load.lowest_vcpu_id != VIOSAPIC_INVALID_VCPU_ID)
403 return -EINVAL;
405 if (viosapic_load.base_address != VIOSAPIC_DEFAULT_BASE_ADDRESS)
406 return -EINVAL;
408 spin_lock(&viosapic->lock);
409 viosapic->irr = viosapic_load.irr;
410 viosapic->isr = viosapic_load.isr;
411 viosapic->ioregsel = viosapic_load.ioregsel;
413 viosapic->lowest_vcpu = lowest_vcpu;
415 viosapic->base_address = viosapic_load.base_address;
417 for (i = 0; i < VIOSAPIC_NUM_PINS; i++)
418 viosapic->redirtbl[i] = viosapic_load.redirtbl[i];
420 service_iosapic(viosapic);//XXX
421 spin_unlock(&viosapic->lock);
423 return 0;
424 }
426 HVM_REGISTER_SAVE_RESTORE(VIOSAPIC, viosapic_save, viosapic_load,
427 1, HVMSR_PER_DOM);