~ubuntu-branches/ubuntu/utopic/xen/utopic

« back to all changes in this revision

Viewing changes to xen/drivers/passthrough/io.c

  • Committer: Bazaar Package Importer
  • Author(s): Bastian Blank
  • Date: 2010-05-06 15:47:38 UTC
  • mto: (1.3.1) (15.1.1 sid) (4.1.1 experimental)
  • mto: This revision was merged to the branch mainline in revision 3.
  • Revision ID: james.westby@ubuntu.com-20100506154738-agoz0rlafrh1fnq7
Tags: upstream-4.0.0
ImportĀ upstreamĀ versionĀ 4.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 2006, Intel Corporation.
 
3
 *
 
4
 * This program is free software; you can redistribute it and/or modify it
 
5
 * under the terms and conditions of the GNU General Public License,
 
6
 * version 2, as published by the Free Software Foundation.
 
7
 *
 
8
 * This program is distributed in the hope it will be useful, but WITHOUT
 
9
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 
10
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 
11
 * more details.
 
12
 *
 
13
 * You should have received a copy of the GNU General Public License along with
 
14
 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 
15
 * Place - Suite 330, Boston, MA 02111-1307 USA.
 
16
 *
 
17
 * Copyright (C) Allen Kay <allen.m.kay@intel.com>
 
18
 * Copyright (C) Xiaohui Xin <xiaohui.xin@intel.com>
 
19
 */
 
20
 
 
21
#include <xen/event.h>
 
22
#include <xen/iommu.h>
 
23
#include <asm/hvm/irq.h>
 
24
#include <asm/hvm/iommu.h>
 
25
#include <asm/hvm/support.h>
 
26
#include <xen/hvm/irq.h>
 
27
 
 
28
static void hvm_dirq_assist(unsigned long _d);
 
29
 
 
30
static int pt_irq_need_timer(uint32_t flags)
 
31
{
 
32
    return !(flags & (HVM_IRQ_DPCI_GUEST_MSI | HVM_IRQ_DPCI_TRANSLATE));
 
33
}
 
34
 
 
35
static void pt_irq_time_out(void *data)
 
36
{
 
37
    struct hvm_mirq_dpci_mapping *irq_map = data;
 
38
    unsigned int guest_gsi, machine_gsi = 0;
 
39
    struct hvm_irq_dpci *dpci = NULL;
 
40
    struct dev_intx_gsi_link *digl;
 
41
    struct hvm_girq_dpci_mapping *girq;
 
42
    uint32_t device, intx;
 
43
    unsigned int nr_pirqs = irq_map->dom->nr_pirqs;
 
44
    DECLARE_BITMAP(machine_gsi_map, nr_pirqs);
 
45
 
 
46
    bitmap_zero(machine_gsi_map, nr_pirqs);
 
47
 
 
48
    spin_lock(&irq_map->dom->event_lock);
 
49
 
 
50
    dpci = domain_get_irq_dpci(irq_map->dom);
 
51
    ASSERT(dpci);
 
52
    list_for_each_entry ( digl, &irq_map->digl_list, list )
 
53
    {
 
54
        guest_gsi = digl->gsi;
 
55
        list_for_each_entry ( girq, &dpci->girq[guest_gsi], list )
 
56
        {
 
57
            machine_gsi = girq->machine_gsi;
 
58
            set_bit(machine_gsi, machine_gsi_map);
 
59
        }
 
60
        device = digl->device;
 
61
        intx = digl->intx;
 
62
        hvm_pci_intx_deassert(irq_map->dom, device, intx);
 
63
    }
 
64
 
 
65
    for ( machine_gsi = find_first_bit(machine_gsi_map, nr_pirqs);
 
66
          machine_gsi < nr_pirqs;
 
67
          machine_gsi = find_next_bit(machine_gsi_map, nr_pirqs,
 
68
                                      machine_gsi + 1) )
 
69
    {
 
70
        clear_bit(machine_gsi, dpci->dirq_mask);
 
71
        dpci->mirq[machine_gsi].pending = 0;
 
72
    }
 
73
 
 
74
    spin_unlock(&irq_map->dom->event_lock);
 
75
 
 
76
    for ( machine_gsi = find_first_bit(machine_gsi_map, nr_pirqs);
 
77
          machine_gsi < nr_pirqs;
 
78
          machine_gsi = find_next_bit(machine_gsi_map, nr_pirqs,
 
79
                                      machine_gsi + 1) )
 
80
    {
 
81
        pirq_guest_eoi(irq_map->dom, machine_gsi);
 
82
    }
 
83
}
 
84
 
 
85
void free_hvm_irq_dpci(struct hvm_irq_dpci *dpci)
 
86
{
 
87
    xfree(dpci->mirq);
 
88
    xfree(dpci->dirq_mask);
 
89
    xfree(dpci->mapping);
 
90
    xfree(dpci->hvm_timer);
 
91
    xfree(dpci);
 
92
}
 
93
 
 
94
int pt_irq_create_bind_vtd(
 
95
    struct domain *d, xen_domctl_bind_pt_irq_t *pt_irq_bind)
 
96
{
 
97
    struct hvm_irq_dpci *hvm_irq_dpci = NULL;
 
98
    uint32_t machine_gsi, guest_gsi;
 
99
    uint32_t device, intx, link;
 
100
    struct dev_intx_gsi_link *digl;
 
101
    struct hvm_girq_dpci_mapping *girq;
 
102
    int rc, pirq = pt_irq_bind->machine_irq;
 
103
 
 
104
    if ( pirq < 0 || pirq >= d->nr_pirqs )
 
105
        return -EINVAL;
 
106
 
 
107
    spin_lock(&d->event_lock);
 
108
 
 
109
    hvm_irq_dpci = domain_get_irq_dpci(d);
 
110
    if ( hvm_irq_dpci == NULL )
 
111
    {
 
112
        hvm_irq_dpci = xmalloc(struct hvm_irq_dpci);
 
113
        if ( hvm_irq_dpci == NULL )
 
114
        {
 
115
            spin_unlock(&d->event_lock);
 
116
            return -ENOMEM;
 
117
        }
 
118
        memset(hvm_irq_dpci, 0, sizeof(*hvm_irq_dpci));
 
119
        tasklet_init(&hvm_irq_dpci->dirq_tasklet,
 
120
                     hvm_dirq_assist, (unsigned long)d);
 
121
        hvm_irq_dpci->mirq = xmalloc_array(struct hvm_mirq_dpci_mapping,
 
122
                                           d->nr_pirqs);
 
123
        hvm_irq_dpci->dirq_mask = xmalloc_array(unsigned long,
 
124
                                                BITS_TO_LONGS(d->nr_pirqs));
 
125
        hvm_irq_dpci->mapping = xmalloc_array(unsigned long,
 
126
                                              BITS_TO_LONGS(d->nr_pirqs));
 
127
        hvm_irq_dpci->hvm_timer = xmalloc_array(struct timer, nr_irqs);
 
128
        if ( !hvm_irq_dpci->mirq ||
 
129
             !hvm_irq_dpci->dirq_mask ||
 
130
             !hvm_irq_dpci->mapping ||
 
131
             !hvm_irq_dpci->hvm_timer)
 
132
        {
 
133
            spin_unlock(&d->event_lock);
 
134
            free_hvm_irq_dpci(hvm_irq_dpci);
 
135
            return -ENOMEM;
 
136
        }
 
137
        memset(hvm_irq_dpci->mirq, 0,
 
138
               d->nr_pirqs * sizeof(*hvm_irq_dpci->mirq));
 
139
        bitmap_zero(hvm_irq_dpci->dirq_mask, d->nr_pirqs);
 
140
        bitmap_zero(hvm_irq_dpci->mapping, d->nr_pirqs);
 
141
        memset(hvm_irq_dpci->hvm_timer, 0,
 
142
                nr_irqs * sizeof(*hvm_irq_dpci->hvm_timer));
 
143
        for ( int i = 0; i < d->nr_pirqs; i++ ) {
 
144
            INIT_LIST_HEAD(&hvm_irq_dpci->mirq[i].digl_list);
 
145
            hvm_irq_dpci->mirq[i].gmsi.dest_vcpu_id = -1;
 
146
        }
 
147
        for ( int i = 0; i < NR_HVM_IRQS; i++ )
 
148
            INIT_LIST_HEAD(&hvm_irq_dpci->girq[i]);
 
149
 
 
150
        if ( domain_set_irq_dpci(d, hvm_irq_dpci) == 0 )
 
151
        {
 
152
            spin_unlock(&d->event_lock);
 
153
            free_hvm_irq_dpci(hvm_irq_dpci);
 
154
            return -EINVAL;
 
155
        }
 
156
    }
 
157
 
 
158
    if ( pt_irq_bind->irq_type == PT_IRQ_TYPE_MSI )
 
159
    {
 
160
        uint8_t dest, dest_mode;
 
161
        int dest_vcpu_id;
 
162
 
 
163
        if ( !test_and_set_bit(pirq, hvm_irq_dpci->mapping))
 
164
        {
 
165
            hvm_irq_dpci->mirq[pirq].flags = HVM_IRQ_DPCI_MACH_MSI |
 
166
                                             HVM_IRQ_DPCI_GUEST_MSI;
 
167
            hvm_irq_dpci->mirq[pirq].gmsi.gvec = pt_irq_bind->u.msi.gvec;
 
168
            hvm_irq_dpci->mirq[pirq].gmsi.gflags = pt_irq_bind->u.msi.gflags;
 
169
            /* bind after hvm_irq_dpci is setup to avoid race with irq handler*/
 
170
            rc = pirq_guest_bind(d->vcpu[0], pirq, 0);
 
171
            if ( rc == 0 && pt_irq_bind->u.msi.gtable )
 
172
            {
 
173
                rc = msixtbl_pt_register(d, pirq, pt_irq_bind->u.msi.gtable);
 
174
                if ( unlikely(rc) )
 
175
                    pirq_guest_unbind(d, pirq);
 
176
            }
 
177
            if ( unlikely(rc) )
 
178
            {
 
179
                hvm_irq_dpci->mirq[pirq].gmsi.gflags = 0;
 
180
                hvm_irq_dpci->mirq[pirq].gmsi.gvec = 0;
 
181
                hvm_irq_dpci->mirq[pirq].flags = 0;
 
182
                clear_bit(pirq, hvm_irq_dpci->mapping);
 
183
                spin_unlock(&d->event_lock);
 
184
                return rc;
 
185
            }
 
186
        }
 
187
        else
 
188
        {
 
189
            uint32_t mask = HVM_IRQ_DPCI_MACH_MSI | HVM_IRQ_DPCI_GUEST_MSI;
 
190
 
 
191
            if ( (hvm_irq_dpci->mirq[pirq].flags & mask) != mask)
 
192
            {
 
193
                    spin_unlock(&d->event_lock);
 
194
                    return -EBUSY;
 
195
            }
 
196
 
 
197
            /* if pirq is already mapped as vmsi, update the guest data/addr */
 
198
            if ( hvm_irq_dpci->mirq[pirq].gmsi.gvec != pt_irq_bind->u.msi.gvec ||
 
199
                    hvm_irq_dpci->mirq[pirq].gmsi.gflags != pt_irq_bind->u.msi.gflags) {
 
200
                /* Directly clear pending EOIs before enabling new MSI info. */
 
201
                pirq_guest_eoi(d, pirq);
 
202
 
 
203
                hvm_irq_dpci->mirq[pirq].gmsi.gvec = pt_irq_bind->u.msi.gvec;
 
204
                hvm_irq_dpci->mirq[pirq].gmsi.gflags = pt_irq_bind->u.msi.gflags;
 
205
            }
 
206
        }
 
207
        /* Caculate dest_vcpu_id for MSI-type pirq migration */
 
208
        dest = hvm_irq_dpci->mirq[pirq].gmsi.gflags & VMSI_DEST_ID_MASK;
 
209
        dest_mode = !!(hvm_irq_dpci->mirq[pirq].gmsi.gflags & VMSI_DM_MASK);
 
210
        dest_vcpu_id = hvm_girq_dest_2_vcpu_id(d, dest, dest_mode);
 
211
        hvm_irq_dpci->mirq[pirq].gmsi.dest_vcpu_id = dest_vcpu_id;
 
212
        spin_unlock(&d->event_lock);
 
213
        if ( dest_vcpu_id >= 0 )
 
214
            hvm_migrate_pirqs(d->vcpu[dest_vcpu_id]);
 
215
    }
 
216
    else
 
217
    {
 
218
        machine_gsi = pt_irq_bind->machine_irq;
 
219
        device = pt_irq_bind->u.pci.device;
 
220
        intx = pt_irq_bind->u.pci.intx;
 
221
        guest_gsi = hvm_pci_intx_gsi(device, intx);
 
222
        link = hvm_pci_intx_link(device, intx);
 
223
        hvm_irq_dpci->link_cnt[link]++;
 
224
 
 
225
        digl = xmalloc(struct dev_intx_gsi_link);
 
226
        if ( !digl )
 
227
        {
 
228
            spin_unlock(&d->event_lock);
 
229
            return -ENOMEM;
 
230
        }
 
231
 
 
232
        girq = xmalloc(struct hvm_girq_dpci_mapping);
 
233
        if ( !girq )
 
234
        {
 
235
            xfree(digl);
 
236
            spin_unlock(&d->event_lock);
 
237
            return -ENOMEM;
 
238
        }
 
239
 
 
240
        digl->device = device;
 
241
        digl->intx = intx;
 
242
        digl->gsi = guest_gsi;
 
243
        digl->link = link;
 
244
        list_add_tail(&digl->list,
 
245
                      &hvm_irq_dpci->mirq[machine_gsi].digl_list);
 
246
 
 
247
        girq->device = device;
 
248
        girq->intx = intx;
 
249
        girq->machine_gsi = machine_gsi;
 
250
        list_add_tail(&girq->list, &hvm_irq_dpci->girq[guest_gsi]);
 
251
 
 
252
        /* Bind the same mirq once in the same domain */
 
253
        if ( !test_and_set_bit(machine_gsi, hvm_irq_dpci->mapping))
 
254
        {
 
255
            unsigned int irq = domain_pirq_to_irq(d, machine_gsi);
 
256
            unsigned int share;
 
257
 
 
258
            hvm_irq_dpci->mirq[machine_gsi].dom = d;
 
259
            if ( pt_irq_bind->irq_type == PT_IRQ_TYPE_MSI_TRANSLATE )
 
260
            {
 
261
                hvm_irq_dpci->mirq[machine_gsi].flags = HVM_IRQ_DPCI_MACH_MSI |
 
262
                                                        HVM_IRQ_DPCI_GUEST_PCI |
 
263
                                                        HVM_IRQ_DPCI_TRANSLATE;
 
264
                share = 0;
 
265
            }
 
266
            else    /* PT_IRQ_TYPE_PCI */
 
267
            {
 
268
                hvm_irq_dpci->mirq[machine_gsi].flags = HVM_IRQ_DPCI_MACH_PCI |
 
269
                                                        HVM_IRQ_DPCI_GUEST_PCI;
 
270
                share = BIND_PIRQ__WILL_SHARE;
 
271
            }
 
272
 
 
273
            /* Init timer before binding */
 
274
            if ( pt_irq_need_timer(hvm_irq_dpci->mirq[machine_gsi].flags) )
 
275
                init_timer(&hvm_irq_dpci->hvm_timer[irq],
 
276
                           pt_irq_time_out, &hvm_irq_dpci->mirq[machine_gsi], 0);
 
277
            /* Deal with gsi for legacy devices */
 
278
            rc = pirq_guest_bind(d->vcpu[0], machine_gsi, share);
 
279
            if ( unlikely(rc) )
 
280
            {
 
281
                if ( pt_irq_need_timer(hvm_irq_dpci->mirq[machine_gsi].flags) )
 
282
                    kill_timer(&hvm_irq_dpci->hvm_timer[irq]);
 
283
                hvm_irq_dpci->mirq[machine_gsi].dom = NULL;
 
284
                clear_bit(machine_gsi, hvm_irq_dpci->mapping);
 
285
                list_del(&girq->list);
 
286
                xfree(girq);
 
287
                list_del(&digl->list);
 
288
                hvm_irq_dpci->link_cnt[link]--;
 
289
                spin_unlock(&d->event_lock);
 
290
                xfree(digl);
 
291
                return rc;
 
292
            }
 
293
        }
 
294
 
 
295
        spin_unlock(&d->event_lock);
 
296
 
 
297
        if ( iommu_verbose )
 
298
            dprintk(VTDPREFIX,
 
299
                    "d%d: bind: m_gsi=%u g_gsi=%u device=%u intx=%u\n",
 
300
                    d->domain_id, machine_gsi, guest_gsi, device, intx);
 
301
    }
 
302
    return 0;
 
303
}
 
304
 
 
305
int pt_irq_destroy_bind_vtd(
 
306
    struct domain *d, xen_domctl_bind_pt_irq_t *pt_irq_bind)
 
307
{
 
308
    struct hvm_irq_dpci *hvm_irq_dpci = NULL;
 
309
    uint32_t machine_gsi, guest_gsi;
 
310
    uint32_t device, intx, link;
 
311
    struct list_head *digl_list, *tmp;
 
312
    struct dev_intx_gsi_link *digl;
 
313
    struct hvm_girq_dpci_mapping *girq;
 
314
 
 
315
    machine_gsi = pt_irq_bind->machine_irq;
 
316
    device = pt_irq_bind->u.pci.device;
 
317
    intx = pt_irq_bind->u.pci.intx;
 
318
    guest_gsi = hvm_pci_intx_gsi(device, intx);
 
319
    link = hvm_pci_intx_link(device, intx);
 
320
 
 
321
    if ( iommu_verbose )
 
322
        dprintk(VTDPREFIX,
 
323
                "d%d: unbind: m_gsi=%u g_gsi=%u device=%u intx=%u\n",
 
324
                d->domain_id, machine_gsi, guest_gsi, device, intx);
 
325
 
 
326
    spin_lock(&d->event_lock);
 
327
 
 
328
    hvm_irq_dpci = domain_get_irq_dpci(d);
 
329
 
 
330
    if ( hvm_irq_dpci == NULL )
 
331
    {
 
332
        spin_unlock(&d->event_lock);
 
333
        return -EINVAL;
 
334
    }
 
335
 
 
336
    hvm_irq_dpci->link_cnt[link]--;
 
337
 
 
338
    list_for_each_entry ( girq, &hvm_irq_dpci->girq[guest_gsi], list )
 
339
    {
 
340
        if ( girq->machine_gsi == machine_gsi )
 
341
        {
 
342
                list_del(&girq->list);
 
343
                xfree(girq);
 
344
                break;
 
345
        }
 
346
    }
 
347
 
 
348
    /* clear the mirq info */
 
349
    if ( test_bit(machine_gsi, hvm_irq_dpci->mapping))
 
350
    {
 
351
        list_for_each_safe ( digl_list, tmp,
 
352
                &hvm_irq_dpci->mirq[machine_gsi].digl_list )
 
353
        {
 
354
            digl = list_entry(digl_list,
 
355
                    struct dev_intx_gsi_link, list);
 
356
            if ( digl->device == device &&
 
357
                 digl->intx   == intx &&
 
358
                 digl->link   == link &&
 
359
                 digl->gsi    == guest_gsi )
 
360
            {
 
361
                list_del(&digl->list);
 
362
                xfree(digl);
 
363
            }
 
364
        }
 
365
 
 
366
        if ( list_empty(&hvm_irq_dpci->mirq[machine_gsi].digl_list) )
 
367
        {
 
368
            pirq_guest_unbind(d, machine_gsi);
 
369
            msixtbl_pt_unregister(d, machine_gsi);
 
370
            if ( pt_irq_need_timer(hvm_irq_dpci->mirq[machine_gsi].flags) )
 
371
                kill_timer(&hvm_irq_dpci->hvm_timer[domain_pirq_to_irq(d, machine_gsi)]);
 
372
            hvm_irq_dpci->mirq[machine_gsi].dom   = NULL;
 
373
            hvm_irq_dpci->mirq[machine_gsi].flags = 0;
 
374
            clear_bit(machine_gsi, hvm_irq_dpci->mapping);
 
375
        }
 
376
    }
 
377
    spin_unlock(&d->event_lock);
 
378
 
 
379
    if ( iommu_verbose )
 
380
        dprintk(VTDPREFIX,
 
381
                "d%d unmap: m_irq=%u device=%u intx=%u\n",
 
382
                d->domain_id, machine_gsi, device, intx);
 
383
 
 
384
    return 0;
 
385
}
 
386
 
 
387
int hvm_do_IRQ_dpci(struct domain *d, unsigned int mirq)
 
388
{
 
389
    struct hvm_irq_dpci *dpci = domain_get_irq_dpci(d);
 
390
 
 
391
    ASSERT(spin_is_locked(&irq_desc[domain_pirq_to_irq(d, mirq)].lock));
 
392
    if ( !iommu_enabled || (d == dom0) || !dpci ||
 
393
         !test_bit(mirq, dpci->mapping))
 
394
        return 0;
 
395
 
 
396
    set_bit(mirq, dpci->dirq_mask);
 
397
    tasklet_schedule(&dpci->dirq_tasklet);
 
398
    return 1;
 
399
}
 
400
 
 
401
#ifdef SUPPORT_MSI_REMAPPING
 
402
/* called with d->event_lock held */
 
403
static void __msi_pirq_eoi(struct domain *d, int pirq)
 
404
{
 
405
    struct hvm_irq_dpci *hvm_irq_dpci = d->arch.hvm_domain.irq.dpci;
 
406
    irq_desc_t *desc;
 
407
 
 
408
    if ( ( pirq >= 0 ) && ( pirq < d->nr_pirqs ) &&
 
409
         test_bit(pirq, hvm_irq_dpci->mapping) &&
 
410
         ( hvm_irq_dpci->mirq[pirq].flags & HVM_IRQ_DPCI_MACH_MSI) )
 
411
    {
 
412
         BUG_ON(!local_irq_is_enabled());
 
413
         desc = domain_spin_lock_irq_desc(d, pirq, NULL);
 
414
         if ( !desc )
 
415
            return;
 
416
 
 
417
         desc->status &= ~IRQ_INPROGRESS;
 
418
         spin_unlock_irq(&desc->lock);
 
419
 
 
420
         pirq_guest_eoi(d, pirq);
 
421
    }
 
422
}
 
423
 
 
424
void hvm_dpci_msi_eoi(struct domain *d, int vector)
 
425
{
 
426
    int pirq, dest, dest_mode;
 
427
    struct hvm_irq_dpci *hvm_irq_dpci = d->arch.hvm_domain.irq.dpci;
 
428
 
 
429
    if ( !iommu_enabled || (hvm_irq_dpci == NULL) )
 
430
       return;
 
431
 
 
432
    spin_lock(&d->event_lock);
 
433
    for ( pirq = find_first_bit(hvm_irq_dpci->mapping, d->nr_pirqs);
 
434
          pirq < d->nr_pirqs;
 
435
          pirq = find_next_bit(hvm_irq_dpci->mapping, d->nr_pirqs, pirq + 1) )
 
436
    {
 
437
        if ( (!(hvm_irq_dpci->mirq[pirq].flags & HVM_IRQ_DPCI_MACH_MSI)) ||
 
438
                (hvm_irq_dpci->mirq[pirq].gmsi.gvec != vector) )
 
439
            continue;
 
440
 
 
441
        dest = hvm_irq_dpci->mirq[pirq].gmsi.gflags & VMSI_DEST_ID_MASK;
 
442
        dest_mode = !!(hvm_irq_dpci->mirq[pirq].gmsi.gflags & VMSI_DM_MASK);
 
443
        if ( vlapic_match_dest(vcpu_vlapic(current), NULL, 0, dest, dest_mode) )
 
444
            break;
 
445
    }
 
446
    if ( pirq < d->nr_pirqs )
 
447
        __msi_pirq_eoi(d, pirq);
 
448
    spin_unlock(&d->event_lock);
 
449
}
 
450
 
 
451
extern int vmsi_deliver(struct domain *d, int pirq);
 
452
static int hvm_pci_msi_assert(struct domain *d, int pirq)
 
453
{
 
454
    return vmsi_deliver(d, pirq);
 
455
}
 
456
#endif
 
457
 
 
458
static void hvm_dirq_assist(unsigned long _d)
 
459
{
 
460
    unsigned int pirq;
 
461
    uint32_t device, intx;
 
462
    struct domain *d = (struct domain *)_d;
 
463
    struct hvm_irq_dpci *hvm_irq_dpci = d->arch.hvm_domain.irq.dpci;
 
464
    struct dev_intx_gsi_link *digl;
 
465
 
 
466
    ASSERT(hvm_irq_dpci);
 
467
 
 
468
    for ( pirq = find_first_bit(hvm_irq_dpci->dirq_mask, d->nr_pirqs);
 
469
          pirq < d->nr_pirqs;
 
470
          pirq = find_next_bit(hvm_irq_dpci->dirq_mask, d->nr_pirqs, pirq + 1) )
 
471
    {
 
472
        if ( !test_and_clear_bit(pirq, hvm_irq_dpci->dirq_mask) )
 
473
            continue;
 
474
 
 
475
        spin_lock(&d->event_lock);
 
476
#ifdef SUPPORT_MSI_REMAPPING
 
477
        if ( hvm_irq_dpci->mirq[pirq].flags & HVM_IRQ_DPCI_GUEST_MSI )
 
478
        {
 
479
            hvm_pci_msi_assert(d, pirq);
 
480
            spin_unlock(&d->event_lock);
 
481
            continue;
 
482
        }
 
483
#endif
 
484
        list_for_each_entry ( digl, &hvm_irq_dpci->mirq[pirq].digl_list, list )
 
485
        {
 
486
            device = digl->device;
 
487
            intx = digl->intx;
 
488
            hvm_pci_intx_assert(d, device, intx);
 
489
            hvm_irq_dpci->mirq[pirq].pending++;
 
490
 
 
491
#ifdef SUPPORT_MSI_REMAPPING
 
492
            if ( hvm_irq_dpci->mirq[pirq].flags & HVM_IRQ_DPCI_TRANSLATE )
 
493
            {
 
494
                /* for translated MSI to INTx interrupt, eoi as early as possible */
 
495
                __msi_pirq_eoi(d, pirq);
 
496
            }
 
497
#endif
 
498
        }
 
499
 
 
500
        /*
 
501
         * Set a timer to see if the guest can finish the interrupt or not. For
 
502
         * example, the guest OS may unmask the PIC during boot, before the
 
503
         * guest driver is loaded. hvm_pci_intx_assert() may succeed, but the
 
504
         * guest will never deal with the irq, then the physical interrupt line
 
505
         * will never be deasserted.
 
506
         */
 
507
        if ( pt_irq_need_timer(hvm_irq_dpci->mirq[pirq].flags) )
 
508
            set_timer(&hvm_irq_dpci->hvm_timer[domain_pirq_to_irq(d, pirq)],
 
509
                      NOW() + PT_IRQ_TIME_OUT);
 
510
        spin_unlock(&d->event_lock);
 
511
    }
 
512
}
 
513
 
 
514
static void __hvm_dpci_eoi(struct domain *d,
 
515
                           struct hvm_irq_dpci *hvm_irq_dpci,
 
516
                           struct hvm_girq_dpci_mapping *girq,
 
517
                           union vioapic_redir_entry *ent)
 
518
{
 
519
    uint32_t device, intx, machine_gsi;
 
520
 
 
521
    device = girq->device;
 
522
    intx = girq->intx;
 
523
    hvm_pci_intx_deassert(d, device, intx);
 
524
 
 
525
    machine_gsi = girq->machine_gsi;
 
526
 
 
527
    /*
 
528
     * No need to get vector lock for timer
 
529
     * since interrupt is still not EOIed
 
530
     */
 
531
    if ( --hvm_irq_dpci->mirq[machine_gsi].pending ||
 
532
         ( ent && ent->fields.mask ) ||
 
533
         ! pt_irq_need_timer(hvm_irq_dpci->mirq[machine_gsi].flags) )
 
534
        return;
 
535
 
 
536
    stop_timer(&hvm_irq_dpci->hvm_timer[domain_pirq_to_irq(d, machine_gsi)]);
 
537
    pirq_guest_eoi(d, machine_gsi);
 
538
}
 
539
 
 
540
void hvm_dpci_eoi(struct domain *d, unsigned int guest_gsi,
 
541
                  union vioapic_redir_entry *ent)
 
542
{
 
543
    struct hvm_irq_dpci *hvm_irq_dpci;
 
544
    struct hvm_girq_dpci_mapping *girq;
 
545
 
 
546
    if ( !iommu_enabled )
 
547
        return;
 
548
 
 
549
    if ( guest_gsi < NR_ISAIRQS )
 
550
    {
 
551
        hvm_dpci_isairq_eoi(d, guest_gsi);
 
552
        return;
 
553
    }
 
554
 
 
555
    spin_lock(&d->event_lock);
 
556
    hvm_irq_dpci = domain_get_irq_dpci(d);
 
557
 
 
558
    if ( !hvm_irq_dpci )
 
559
        goto unlock;
 
560
 
 
561
    list_for_each_entry ( girq, &hvm_irq_dpci->girq[guest_gsi], list )
 
562
        __hvm_dpci_eoi(d, hvm_irq_dpci, girq, ent);
 
563
 
 
564
unlock:
 
565
    spin_unlock(&d->event_lock);
 
566
}