debuggers.hg

view xen/arch/ia64/vmx/viosapic.c @ 0:7d21f7218375

Exact replica of unstable on 051908 + README-this
author Mukesh Rathor
date Mon May 19 15:34:57 2008 -0700 (2008-05-19)
parents
children f875aaa791f0
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;
53 ASSERT(spin_is_locked(&viosapic->lock));
55 if (vlsapic_deliver_int(viosapic_domain (viosapic),
56 dest, delivery_mode, vector) < 0)
57 gdprintk(XENLOG_WARNING,
58 "viosapic: can't deliver int %u to %u (dm=%u)\n",
59 vector, dest, delivery_mode);
60 }
63 static int iosapic_get_highest_irq(struct viosapic *viosapic)
64 {
65 uint64_t irqs = viosapic->irr & ~viosapic->isr ;
67 if (irqs)
68 return ia64_fls(irqs);
70 return -1;
71 }
74 /* XXX If level interrupt, use vector->irq table for performance */
75 static int get_redir_num(struct viosapic *viosapic, int vector)
76 {
77 int i;
79 ASSERT(spin_is_locked(&viosapic->lock));
80 for ( i = 0; i < VIOSAPIC_NUM_PINS; i++ )
81 if ( viosapic->redirtbl[i].vector == vector )
82 return i;
84 return -1;
85 }
88 static void service_iosapic(struct viosapic *viosapic)
89 {
90 int irq;
92 while ( (irq = iosapic_get_highest_irq(viosapic)) != -1 )
93 {
94 if ( viosapic->redirtbl[irq].trig_mode == SAPIC_LEVEL )
95 viosapic->isr |= (1UL << irq);
97 viosapic_deliver(viosapic, irq);
99 viosapic->irr &= ~(1UL << irq);
100 }
101 }
104 static void viosapic_update_EOI(struct viosapic *viosapic, int vector)
105 {
106 int redir_num;
108 spin_lock(&viosapic->lock);
109 if ( (redir_num = get_redir_num(viosapic, vector)) == -1 )
110 {
111 spin_unlock(&viosapic->lock);
112 gdprintk(XENLOG_WARNING, "Can't find redir item for %d EOI\n", vector);
113 return;
114 }
116 if ( !test_and_clear_bit(redir_num, &viosapic->isr) )
117 {
118 spin_unlock(&viosapic->lock);
119 if ( viosapic->redirtbl[redir_num].trig_mode == SAPIC_LEVEL )
120 gdprintk(XENLOG_WARNING, "redir %d not set for %d EOI\n",
121 redir_num, vector);
122 return;
123 }
124 service_iosapic(viosapic);
125 spin_unlock(&viosapic->lock);
126 }
129 static unsigned long viosapic_read_indirect(struct viosapic *viosapic,
130 unsigned long addr,
131 unsigned long length)
132 {
133 unsigned long result = 0;
135 switch ( viosapic->ioregsel )
136 {
137 case VIOSAPIC_VERSION:
138 result = ((((VIOSAPIC_NUM_PINS - 1) & 0xff) << 16)
139 | (VIOSAPIC_VERSION_ID & 0xff));
140 break;
142 default:
143 {
144 /* ioregsel might be written at the same time. copy it before use. */
145 uint32_t ioregsel = viosapic->ioregsel;
146 uint32_t redir_index;
147 uint64_t redir_content;
149 redir_index = (ioregsel - 0x10) >> 1;
150 if ( redir_index >= VIOSAPIC_NUM_PINS )
151 {
152 gdprintk(XENLOG_WARNING, "viosapic_read_indirect:undefined "
153 "ioregsel %x\n", ioregsel);
154 break;
155 }
157 redir_content = viosapic->redirtbl[redir_index].bits;
158 result = (ioregsel & 0x1) ?
159 (redir_content >> 32) & 0xffffffff :
160 redir_content & 0xffffffff;
161 break;
162 }
163 }
165 return result;
166 }
169 unsigned long viosapic_read(struct vcpu *v,
170 unsigned long addr,
171 unsigned long length)
172 {
173 struct viosapic *viosapic = vcpu_viosapic(v);
174 uint32_t result;
176 addr &= 0xff;
178 switch ( addr )
179 {
180 case VIOSAPIC_REG_SELECT:
181 result = viosapic->ioregsel;
182 break;
184 case VIOSAPIC_WINDOW:
185 result = viosapic_read_indirect(viosapic, addr, length);
186 break;
188 default:
189 result = 0;
190 break;
191 }
193 return result;
194 }
197 static void viosapic_write_indirect(struct viosapic *viosapic,
198 unsigned long addr,
199 unsigned long length,
200 unsigned long val)
201 {
202 switch ( viosapic->ioregsel )
203 {
204 case VIOSAPIC_VERSION:
205 /* Writes are ignored. */
206 break;
208 default:
209 {
210 /* ioregsel might be written at the same time. copy it before use. */
211 uint32_t ioregsel = viosapic->ioregsel;
212 uint32_t redir_index;
213 uint64_t redir_content;
215 redir_index = (ioregsel - 0x10) >> 1;
216 if ( redir_index >= VIOSAPIC_NUM_PINS )
217 {
218 gdprintk(XENLOG_WARNING, "viosapic_write_indirect "
219 "error register %x\n", viosapic->ioregsel);
220 break;
221 }
223 spin_lock(&viosapic->lock);
224 redir_content = viosapic->redirtbl[redir_index].bits;
226 if ( ioregsel & 0x1 )
227 {
228 redir_content = (((uint64_t)val & 0xffffffff) << 32) |
229 (redir_content & 0xffffffff);
230 }
231 else
232 {
233 redir_content = ((redir_content >> 32) << 32) |
234 (val & 0xffffffff);
235 }
236 viosapic->redirtbl[redir_index].bits = redir_content;
237 spin_unlock(&viosapic->lock);
238 break;
239 }
240 } /* switch */
241 }
244 void viosapic_write(struct vcpu *v,
245 unsigned long addr,
246 unsigned long length,
247 unsigned long val)
248 {
249 struct viosapic *viosapic = vcpu_viosapic(v);
251 addr &= 0xff;
253 switch ( addr )
254 {
255 case VIOSAPIC_REG_SELECT:
256 viosapic->ioregsel = val;
257 break;
259 case VIOSAPIC_WINDOW:
260 viosapic_write_indirect(viosapic, addr, length, val);
261 break;
263 case VIOSAPIC_EOI:
264 viosapic_update_EOI(viosapic, val);
265 break;
267 default:
268 break;
269 }
270 }
273 static void viosapic_reset(struct viosapic *viosapic)
274 {
275 int i;
277 memset(viosapic, 0, sizeof(*viosapic));
279 for ( i = 0; i < VIOSAPIC_NUM_PINS; i++ )
280 {
281 viosapic->redirtbl[i].mask = 0x1;
282 }
283 spin_lock_init(&viosapic->lock);
284 }
286 void viosapic_set_irq(struct domain *d, int irq, int level)
287 {
288 struct viosapic *viosapic = domain_viosapic(d);
289 uint64_t bit;
291 spin_lock(&viosapic->lock);
292 if ( (irq < 0) || (irq >= VIOSAPIC_NUM_PINS) )
293 goto out;
295 if ( viosapic->redirtbl[irq].mask )
296 goto out;
298 bit = 1UL << irq;
299 if ( viosapic->redirtbl[irq].trig_mode == SAPIC_LEVEL )
300 {
301 if ( level )
302 viosapic->irr |= bit;
303 else
304 viosapic->irr &= ~bit;
305 }
306 else
307 {
308 if ( level )
309 /* XXX No irr clear for edge interrupt */
310 viosapic->irr |= bit;
311 }
313 service_iosapic(viosapic);
314 out:
315 spin_unlock(&viosapic->lock);
316 }
318 #define hvm_pci_intx_gsi(dev, intx) \
319 (((((dev) << 2) + ((dev) >> 3) + (intx)) & 31) + 16)
322 void viosapic_set_pci_irq(struct domain *d, int device, int intx, int level)
323 {
324 int irq;
325 irq = hvm_pci_intx_gsi(device, intx);
327 viosapic_set_irq(d, irq, level);
328 }
330 void viosapic_init(struct domain *d)
331 {
332 struct viosapic *viosapic = domain_viosapic(d);
334 viosapic_reset(viosapic);
336 viosapic->lowest_vcpu = NULL;
338 viosapic->base_address = VIOSAPIC_DEFAULT_BASE_ADDRESS;
339 }
341 #define VIOSAPIC_INVALID_VCPU_ID (-1UL)
342 static int viosapic_save(struct domain *d, hvm_domain_context_t *h)
343 {
344 struct viosapic *viosapic = domain_viosapic(d);
345 struct hvm_hw_ia64_viosapic viosapic_save;
346 int i;
348 memset(&viosapic_save, 0, sizeof(viosapic_save));
350 spin_lock(&viosapic->lock);
351 viosapic_save.irr = viosapic->irr;
352 viosapic_save.isr = viosapic->isr;
353 viosapic_save.ioregsel = viosapic->ioregsel;
354 if (viosapic->lowest_vcpu != NULL)
355 viosapic_save.lowest_vcpu_id = viosapic->lowest_vcpu->vcpu_id;
356 else
357 viosapic_save.lowest_vcpu_id = VIOSAPIC_INVALID_VCPU_ID;
358 viosapic_save.base_address = viosapic->base_address;
360 for (i = 0; i < VIOSAPIC_NUM_PINS; i++)
361 viosapic_save.redirtbl[i] = viosapic->redirtbl[i];
362 spin_unlock(&viosapic->lock);
364 return hvm_save_entry(VIOSAPIC, 0, h, &viosapic_save);
365 }
367 static int viosapic_load(struct domain *d, hvm_domain_context_t *h)
368 {
369 struct viosapic *viosapic = domain_viosapic(d);
370 struct hvm_hw_ia64_viosapic viosapic_load;
371 struct vcpu *lowest_vcpu;
372 int i;
374 if (hvm_load_entry(VIOSAPIC, h, &viosapic_load))
375 return -EINVAL;
377 lowest_vcpu = NULL;
378 if (viosapic_load.lowest_vcpu_id < MAX_VIRT_CPUS)
379 lowest_vcpu = d->vcpu[viosapic_load.lowest_vcpu_id];
380 else if (viosapic_load.lowest_vcpu_id != VIOSAPIC_INVALID_VCPU_ID)
381 return -EINVAL;
383 if (viosapic_load.base_address != VIOSAPIC_DEFAULT_BASE_ADDRESS)
384 return -EINVAL;
386 spin_lock(&viosapic->lock);
387 viosapic->irr = viosapic_load.irr;
388 viosapic->isr = viosapic_load.isr;
389 viosapic->ioregsel = viosapic_load.ioregsel;
391 viosapic->lowest_vcpu = lowest_vcpu;
393 viosapic->base_address = viosapic_load.base_address;
395 for (i = 0; i < VIOSAPIC_NUM_PINS; i++)
396 viosapic->redirtbl[i] = viosapic_load.redirtbl[i];
398 service_iosapic(viosapic);//XXX
399 spin_unlock(&viosapic->lock);
401 return 0;
402 }
404 HVM_REGISTER_SAVE_RESTORE(VIOSAPIC, viosapic_save, viosapic_load,
405 1, HVMSR_PER_DOM);