Coverage Report

Created: 2017-10-25 09:10

/root/src/xen/xen/arch/x86/hvm/vmsi.c
Line
Count
Source (jump to first uncovered line)
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, see <http://www.gnu.org/licenses/>.
22
 *
23
 * Support for virtual MSI logic
24
 * Will be merged it with virtual IOAPIC logic, since most is the same
25
*/
26
27
#include <xen/types.h>
28
#include <xen/mm.h>
29
#include <xen/xmalloc.h>
30
#include <xen/lib.h>
31
#include <xen/errno.h>
32
#include <xen/sched.h>
33
#include <xen/irq.h>
34
#include <xen/vpci.h>
35
#include <public/hvm/ioreq.h>
36
#include <asm/hvm/io.h>
37
#include <asm/hvm/vpic.h>
38
#include <asm/hvm/vlapic.h>
39
#include <asm/hvm/support.h>
40
#include <asm/current.h>
41
#include <asm/event.h>
42
#include <asm/io_apic.h>
43
44
static void vmsi_inj_irq(
45
    struct vlapic *target,
46
    uint8_t vector,
47
    uint8_t trig_mode,
48
    uint8_t delivery_mode)
49
3.84k
{
50
3.84k
    HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "vmsi_inj_irq: vec %02x trig %d dm %d\n",
51
3.84k
                vector, trig_mode, delivery_mode);
52
3.84k
53
3.84k
    switch ( delivery_mode )
54
3.84k
    {
55
3.84k
    case dest_Fixed:
56
3.84k
    case dest_LowestPrio:
57
3.84k
        vlapic_set_irq(target, vector, trig_mode);
58
3.84k
        break;
59
0
    default:
60
0
        BUG();
61
3.84k
    }
62
3.84k
}
63
64
int vmsi_deliver(
65
    struct domain *d, int vector,
66
    uint8_t dest, uint8_t dest_mode,
67
    uint8_t delivery_mode, uint8_t trig_mode)
68
3.84k
{
69
3.84k
    struct vlapic *target;
70
3.84k
    struct vcpu *v;
71
3.84k
72
3.84k
    switch ( delivery_mode )
73
3.84k
    {
74
0
    case dest_LowestPrio:
75
0
        target = vlapic_lowest_prio(d, NULL, 0, dest, dest_mode);
76
0
        if ( target != NULL )
77
0
        {
78
0
            vmsi_inj_irq(target, vector, trig_mode, delivery_mode);
79
0
            break;
80
0
        }
81
0
        HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "null MSI round robin: vector=%02x\n",
82
0
                    vector);
83
0
        return -ESRCH;
84
0
85
3.84k
    case dest_Fixed:
86
3.84k
        for_each_vcpu ( d, v )
87
46.1k
            if ( vlapic_match_dest(vcpu_vlapic(v), NULL,
88
46.1k
                                   0, dest, dest_mode) )
89
3.84k
                vmsi_inj_irq(vcpu_vlapic(v), vector,
90
3.84k
                             trig_mode, delivery_mode);
91
3.84k
        break;
92
0
93
0
    default:
94
0
        printk(XENLOG_G_WARNING
95
0
               "%pv: Unsupported MSI delivery mode %d for Dom%d\n",
96
0
               current, delivery_mode, d->domain_id);
97
0
        return -EINVAL;
98
3.84k
    }
99
3.84k
100
3.84k
    return 0;
101
3.84k
}
102
103
void vmsi_deliver_pirq(struct domain *d, const struct hvm_pirq_dpci *pirq_dpci)
104
3.84k
{
105
3.84k
    uint32_t flags = pirq_dpci->gmsi.gflags;
106
3.84k
    int vector = pirq_dpci->gmsi.gvec;
107
3.84k
    uint8_t dest = (uint8_t)flags;
108
3.84k
    bool dest_mode = flags & XEN_DOMCTL_VMSI_X86_DM_MASK;
109
3.84k
    uint8_t delivery_mode = MASK_EXTR(flags, XEN_DOMCTL_VMSI_X86_DELIV_MASK);
110
3.84k
    bool trig_mode = flags & XEN_DOMCTL_VMSI_X86_TRIG_MASK;
111
3.84k
112
3.84k
    HVM_DBG_LOG(DBG_LEVEL_IOAPIC,
113
3.84k
                "msi: dest=%x dest_mode=%x delivery_mode=%x "
114
3.84k
                "vector=%x trig_mode=%x\n",
115
3.84k
                dest, dest_mode, delivery_mode, vector, trig_mode);
116
3.84k
117
3.84k
    ASSERT(pirq_dpci->flags & HVM_IRQ_DPCI_GUEST_MSI);
118
3.84k
119
3.84k
    vmsi_deliver(d, vector, dest, dest_mode, delivery_mode, trig_mode);
120
3.84k
}
121
122
/* Return value, -1 : multi-dests, non-negative value: dest_vcpu_id */
123
int hvm_girq_dest_2_vcpu_id(struct domain *d, uint8_t dest, uint8_t dest_mode)
124
42
{
125
42
    int dest_vcpu_id = -1, w = 0;
126
42
    struct vcpu *v;
127
42
    
128
42
    if ( d->max_vcpus == 1 )
129
0
        return 0;
130
42
 
131
42
    for_each_vcpu ( d, v )
132
504
    {
133
504
        if ( vlapic_match_dest(vcpu_vlapic(v), NULL, 0, dest, dest_mode) ) 
134
42
        {
135
42
            w++;
136
42
            dest_vcpu_id = v->vcpu_id;
137
42
        }
138
504
    }
139
42
    if ( w > 1 )
140
0
        return -1;
141
42
142
42
    return dest_vcpu_id;
143
42
}
144
145
/* MSI-X mask bit hypervisor interception */
146
struct msixtbl_entry
147
{
148
    struct list_head list;
149
    atomic_t refcnt;    /* how many bind_pt_irq called for the device */
150
151
    /* TODO: resolve the potential race by destruction of pdev */
152
    struct pci_dev *pdev;
153
    unsigned long gtable;       /* gpa of msix table */
154
    DECLARE_BITMAP(table_flags, MAX_MSIX_TABLE_ENTRIES);
155
0
#define MAX_MSIX_ACC_ENTRIES 3
156
    unsigned int table_len;
157
    struct { 
158
        uint32_t msi_ad[3]; /* Shadow of address low, high and data */
159
    } gentries[MAX_MSIX_ACC_ENTRIES];
160
    DECLARE_BITMAP(acc_valid, 3 * MAX_MSIX_ACC_ENTRIES);
161
#define acc_bit(what, ent, slot, idx) \
162
0
        what##_bit((slot) * 3 + (idx), (ent)->acc_valid)
163
    struct rcu_head rcu;
164
};
165
166
static DEFINE_RCU_READ_LOCK(msixtbl_rcu_lock);
167
168
/*
169
 * MSI-X table infrastructure is dynamically initialised when an MSI-X capable
170
 * device is passed through to a domain, rather than unconditionally for all
171
 * domains.
172
 */
173
static bool msixtbl_initialised(const struct domain *d)
174
0
{
175
0
    return !!d->arch.hvm_domain.msixtbl_list.next;
176
0
}
177
178
static struct msixtbl_entry *msixtbl_find_entry(
179
    struct vcpu *v, unsigned long addr)
180
0
{
181
0
    struct msixtbl_entry *entry;
182
0
    struct domain *d = v->domain;
183
0
184
0
    list_for_each_entry( entry, &d->arch.hvm_domain.msixtbl_list, list )
185
0
        if ( addr >= entry->gtable &&
186
0
             addr < entry->gtable + entry->table_len )
187
0
            return entry;
188
0
189
0
    return NULL;
190
0
}
191
192
static struct msi_desc *msixtbl_addr_to_desc(
193
    const struct msixtbl_entry *entry, unsigned long addr)
194
0
{
195
0
    unsigned int nr_entry;
196
0
    struct msi_desc *desc;
197
0
198
0
    if ( !entry || !entry->pdev )
199
0
        return NULL;
200
0
201
0
    nr_entry = (addr - entry->gtable) / PCI_MSIX_ENTRY_SIZE;
202
0
203
0
    list_for_each_entry( desc, &entry->pdev->msi_list, list )
204
0
        if ( desc->msi_attrib.type == PCI_CAP_ID_MSIX &&
205
0
             desc->msi_attrib.entry_nr == nr_entry )
206
0
            return desc;
207
0
208
0
    return NULL;
209
0
}
210
211
static int msixtbl_read(const struct hvm_io_handler *handler,
212
                        uint64_t address, uint32_t len, uint64_t *pval)
213
0
{
214
0
    unsigned long offset;
215
0
    struct msixtbl_entry *entry;
216
0
    unsigned int nr_entry, index;
217
0
    int r = X86EMUL_UNHANDLEABLE;
218
0
219
0
    if ( (len != 4 && len != 8) || (address & (len - 1)) )
220
0
        return r;
221
0
222
0
    rcu_read_lock(&msixtbl_rcu_lock);
223
0
224
0
    entry = msixtbl_find_entry(current, address);
225
0
    if ( !entry )
226
0
        goto out;
227
0
    offset = address & (PCI_MSIX_ENTRY_SIZE - 1);
228
0
229
0
    if ( offset != PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET )
230
0
    {
231
0
        nr_entry = (address - entry->gtable) / PCI_MSIX_ENTRY_SIZE;
232
0
        index = offset / sizeof(uint32_t);
233
0
        if ( nr_entry >= MAX_MSIX_ACC_ENTRIES ||
234
0
             !acc_bit(test, entry, nr_entry, index) )
235
0
            goto out;
236
0
        *pval = entry->gentries[nr_entry].msi_ad[index];
237
0
        if ( len == 8 )
238
0
        {
239
0
            if ( index )
240
0
                offset = PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET;
241
0
            else if ( acc_bit(test, entry, nr_entry, 1) )
242
0
                *pval |= (u64)entry->gentries[nr_entry].msi_ad[1] << 32;
243
0
            else
244
0
                goto out;
245
0
        }
246
0
    }
247
0
    if ( offset == PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET )
248
0
    {
249
0
        const struct msi_desc *msi_desc = msixtbl_addr_to_desc(entry, address);
250
0
251
0
        if ( !msi_desc )
252
0
            goto out;
253
0
        if ( len == 4 )
254
0
            *pval = MASK_INSR(msi_desc->msi_attrib.guest_masked,
255
0
                              PCI_MSIX_VECTOR_BITMASK);
256
0
        else
257
0
            *pval |= (u64)MASK_INSR(msi_desc->msi_attrib.guest_masked,
258
0
                                    PCI_MSIX_VECTOR_BITMASK) << 32;
259
0
    }
260
0
    
261
0
    r = X86EMUL_OKAY;
262
0
out:
263
0
    rcu_read_unlock(&msixtbl_rcu_lock);
264
0
    return r;
265
0
}
266
267
static int msixtbl_write(struct vcpu *v, unsigned long address,
268
                         unsigned int len, unsigned long val)
269
0
{
270
0
    unsigned long offset;
271
0
    struct msixtbl_entry *entry;
272
0
    const struct msi_desc *msi_desc;
273
0
    unsigned int nr_entry, index;
274
0
    int r = X86EMUL_UNHANDLEABLE;
275
0
    unsigned long flags;
276
0
    struct irq_desc *desc;
277
0
278
0
    if ( (len != 4 && len != 8) || (address & (len - 1)) )
279
0
        return r;
280
0
281
0
    rcu_read_lock(&msixtbl_rcu_lock);
282
0
283
0
    entry = msixtbl_find_entry(v, address);
284
0
    if ( !entry )
285
0
        goto out;
286
0
    nr_entry = (address - entry->gtable) / PCI_MSIX_ENTRY_SIZE;
287
0
288
0
    offset = address & (PCI_MSIX_ENTRY_SIZE - 1);
289
0
    if ( offset != PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET )
290
0
    {
291
0
        index = offset / sizeof(uint32_t);
292
0
        if ( nr_entry < MAX_MSIX_ACC_ENTRIES ) 
293
0
        {
294
0
            entry->gentries[nr_entry].msi_ad[index] = val;
295
0
            acc_bit(set, entry, nr_entry, index);
296
0
            if ( len == 8 && !index )
297
0
            {
298
0
                entry->gentries[nr_entry].msi_ad[1] = val >> 32;
299
0
                acc_bit(set, entry, nr_entry, 1);
300
0
            }
301
0
        }
302
0
        set_bit(nr_entry, &entry->table_flags);
303
0
        if ( len != 8 || !index )
304
0
            goto out;
305
0
        val >>= 32;
306
0
        address += 4;
307
0
    }
308
0
309
0
    /* Exit to device model when unmasking and address/data got modified. */
310
0
    if ( !(val & PCI_MSIX_VECTOR_BITMASK) &&
311
0
         test_and_clear_bit(nr_entry, &entry->table_flags) )
312
0
    {
313
0
        v->arch.hvm_vcpu.hvm_io.msix_unmask_address = address;
314
0
        goto out;
315
0
    }
316
0
317
0
    msi_desc = msixtbl_addr_to_desc(entry, address);
318
0
    if ( !msi_desc || msi_desc->irq < 0 )
319
0
        goto out;
320
0
    
321
0
    desc = irq_to_desc(msi_desc->irq);
322
0
    if ( !desc )
323
0
        goto out;
324
0
325
0
    spin_lock_irqsave(&desc->lock, flags);
326
0
327
0
    if ( !desc->msi_desc )
328
0
        goto unlock;
329
0
330
0
    ASSERT(msi_desc == desc->msi_desc);
331
0
   
332
0
    guest_mask_msi_irq(desc, !!(val & PCI_MSIX_VECTOR_BITMASK));
333
0
334
0
unlock:
335
0
    spin_unlock_irqrestore(&desc->lock, flags);
336
0
    if ( len == 4 )
337
0
        r = X86EMUL_OKAY;
338
0
339
0
out:
340
0
    rcu_read_unlock(&msixtbl_rcu_lock);
341
0
    return r;
342
0
}
343
344
static int _msixtbl_write(const struct hvm_io_handler *handler,
345
                          uint64_t address, uint32_t len, uint64_t val)
346
0
{
347
0
    return msixtbl_write(current, address, len, val);
348
0
}
349
350
static bool_t msixtbl_range(const struct hvm_io_handler *handler,
351
                            const ioreq_t *r)
352
0
{
353
0
    struct vcpu *curr = current;
354
0
    unsigned long addr = r->addr;
355
0
    const struct msi_desc *desc;
356
0
357
0
    ASSERT(r->type == IOREQ_TYPE_COPY);
358
0
359
0
    rcu_read_lock(&msixtbl_rcu_lock);
360
0
    desc = msixtbl_addr_to_desc(msixtbl_find_entry(curr, addr), addr);
361
0
    rcu_read_unlock(&msixtbl_rcu_lock);
362
0
363
0
    if ( desc )
364
0
        return 1;
365
0
366
0
    if ( r->state == STATE_IOREQ_READY && r->dir == IOREQ_WRITE )
367
0
    {
368
0
        unsigned int size = r->size;
369
0
370
0
        if ( !r->data_is_ptr )
371
0
        {
372
0
            uint64_t data = r->data;
373
0
374
0
            if ( size == 8 )
375
0
            {
376
0
                BUILD_BUG_ON(!(PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET & 4));
377
0
                data >>= 32;
378
0
                addr += size = 4;
379
0
            }
380
0
            if ( size == 4 &&
381
0
                 ((addr & (PCI_MSIX_ENTRY_SIZE - 1)) ==
382
0
                  PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET) &&
383
0
                 !(data & PCI_MSIX_VECTOR_BITMASK) )
384
0
            {
385
0
                curr->arch.hvm_vcpu.hvm_io.msix_snoop_address = addr;
386
0
                curr->arch.hvm_vcpu.hvm_io.msix_snoop_gpa = 0;
387
0
            }
388
0
        }
389
0
        else if ( (size == 4 || size == 8) &&
390
0
                  /* Only support forward REP MOVS for now. */
391
0
                  !r->df &&
392
0
                  /*
393
0
                   * Only fully support accesses to a single table entry for
394
0
                   * now (if multiple ones get written to in one go, only the
395
0
                   * final one gets dealt with).
396
0
                   */
397
0
                  r->count && r->count <= PCI_MSIX_ENTRY_SIZE / size &&
398
0
                  !((addr + (size * r->count)) & (PCI_MSIX_ENTRY_SIZE - 1)) )
399
0
        {
400
0
            BUILD_BUG_ON((PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET + 4) &
401
0
                         (PCI_MSIX_ENTRY_SIZE - 1));
402
0
403
0
            curr->arch.hvm_vcpu.hvm_io.msix_snoop_address =
404
0
                addr + size * r->count - 4;
405
0
            curr->arch.hvm_vcpu.hvm_io.msix_snoop_gpa =
406
0
                r->data + size * r->count - 4;
407
0
        }
408
0
    }
409
0
410
0
    return 0;
411
0
}
412
413
static const struct hvm_io_ops msixtbl_mmio_ops = {
414
    .accept = msixtbl_range,
415
    .read = msixtbl_read,
416
    .write = _msixtbl_write,
417
};
418
419
static void add_msixtbl_entry(struct domain *d,
420
                              struct pci_dev *pdev,
421
                              uint64_t gtable,
422
                              struct msixtbl_entry *entry)
423
0
{
424
0
    INIT_LIST_HEAD(&entry->list);
425
0
    INIT_RCU_HEAD(&entry->rcu);
426
0
    atomic_set(&entry->refcnt, 0);
427
0
428
0
    entry->table_len = pdev->msix->nr_entries * PCI_MSIX_ENTRY_SIZE;
429
0
    entry->pdev = pdev;
430
0
    entry->gtable = (unsigned long) gtable;
431
0
432
0
    list_add_rcu(&entry->list, &d->arch.hvm_domain.msixtbl_list);
433
0
}
434
435
static void free_msixtbl_entry(struct rcu_head *rcu)
436
0
{
437
0
    struct msixtbl_entry *entry;
438
0
439
0
    entry = container_of (rcu, struct msixtbl_entry, rcu);
440
0
441
0
    xfree(entry);
442
0
}
443
444
static void del_msixtbl_entry(struct msixtbl_entry *entry)
445
0
{
446
0
    list_del_rcu(&entry->list);
447
0
    call_rcu(&entry->rcu, free_msixtbl_entry);
448
0
}
449
450
int msixtbl_pt_register(struct domain *d, struct pirq *pirq, uint64_t gtable)
451
0
{
452
0
    struct irq_desc *irq_desc;
453
0
    struct msi_desc *msi_desc;
454
0
    struct pci_dev *pdev;
455
0
    struct msixtbl_entry *entry, *new_entry;
456
0
    int r = -EINVAL;
457
0
458
0
    ASSERT(pcidevs_locked());
459
0
    ASSERT(spin_is_locked(&d->event_lock));
460
0
461
0
    if ( !msixtbl_initialised(d) )
462
0
        return -ENODEV;
463
0
464
0
    /*
465
0
     * xmalloc() with irq_disabled causes the failure of check_lock() 
466
0
     * for xenpool->lock. So we allocate an entry beforehand.
467
0
     */
468
0
    new_entry = xzalloc(struct msixtbl_entry);
469
0
    if ( !new_entry )
470
0
        return -ENOMEM;
471
0
472
0
    irq_desc = pirq_spin_lock_irq_desc(pirq, NULL);
473
0
    if ( !irq_desc )
474
0
    {
475
0
        xfree(new_entry);
476
0
        return r;
477
0
    }
478
0
479
0
    msi_desc = irq_desc->msi_desc;
480
0
    if ( !msi_desc )
481
0
        goto out;
482
0
483
0
    pdev = msi_desc->dev;
484
0
485
0
    list_for_each_entry( entry, &d->arch.hvm_domain.msixtbl_list, list )
486
0
        if ( pdev == entry->pdev )
487
0
            goto found;
488
0
489
0
    entry = new_entry;
490
0
    new_entry = NULL;
491
0
    add_msixtbl_entry(d, pdev, gtable, entry);
492
0
493
0
found:
494
0
    atomic_inc(&entry->refcnt);
495
0
    r = 0;
496
0
497
0
out:
498
0
    spin_unlock_irq(&irq_desc->lock);
499
0
    xfree(new_entry);
500
0
501
0
    if ( !r )
502
0
    {
503
0
        struct vcpu *v;
504
0
505
0
        for_each_vcpu ( d, v )
506
0
        {
507
0
            if ( (v->pause_flags & VPF_blocked_in_xen) &&
508
0
                 !v->arch.hvm_vcpu.hvm_io.msix_snoop_gpa &&
509
0
                 v->arch.hvm_vcpu.hvm_io.msix_snoop_address ==
510
0
                 (gtable + msi_desc->msi_attrib.entry_nr *
511
0
                           PCI_MSIX_ENTRY_SIZE +
512
0
                  PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET) )
513
0
                v->arch.hvm_vcpu.hvm_io.msix_unmask_address =
514
0
                    v->arch.hvm_vcpu.hvm_io.msix_snoop_address;
515
0
        }
516
0
    }
517
0
518
0
    return r;
519
0
}
520
521
void msixtbl_pt_unregister(struct domain *d, struct pirq *pirq)
522
0
{
523
0
    struct irq_desc *irq_desc;
524
0
    struct msi_desc *msi_desc;
525
0
    struct pci_dev *pdev;
526
0
    struct msixtbl_entry *entry;
527
0
528
0
    ASSERT(pcidevs_locked());
529
0
    ASSERT(spin_is_locked(&d->event_lock));
530
0
531
0
    if ( !msixtbl_initialised(d) )
532
0
        return;
533
0
534
0
    irq_desc = pirq_spin_lock_irq_desc(pirq, NULL);
535
0
    if ( !irq_desc )
536
0
        return;
537
0
538
0
    msi_desc = irq_desc->msi_desc;
539
0
    if ( !msi_desc )
540
0
        goto out;
541
0
542
0
    pdev = msi_desc->dev;
543
0
544
0
    list_for_each_entry( entry, &d->arch.hvm_domain.msixtbl_list, list )
545
0
        if ( pdev == entry->pdev )
546
0
            goto found;
547
0
548
0
out:
549
0
    spin_unlock_irq(&irq_desc->lock);
550
0
    return;
551
0
552
0
found:
553
0
    if ( !atomic_dec_and_test(&entry->refcnt) )
554
0
        del_msixtbl_entry(entry);
555
0
556
0
    spin_unlock_irq(&irq_desc->lock);
557
0
}
558
559
void msixtbl_init(struct domain *d)
560
0
{
561
0
    struct hvm_io_handler *handler;
562
0
563
0
    if ( !is_hvm_domain(d) || !has_vlapic(d) || msixtbl_initialised(d) )
564
0
        return;
565
0
566
0
    INIT_LIST_HEAD(&d->arch.hvm_domain.msixtbl_list);
567
0
568
0
    handler = hvm_next_io_handler(d);
569
0
    if ( handler )
570
0
    {
571
0
        handler->type = IOREQ_TYPE_COPY;
572
0
        handler->ops = &msixtbl_mmio_ops;
573
0
    }
574
0
}
575
576
void msixtbl_pt_cleanup(struct domain *d)
577
0
{
578
0
    struct msixtbl_entry *entry, *temp;
579
0
580
0
    if ( !msixtbl_initialised(d) )
581
0
        return;
582
0
583
0
    spin_lock(&d->event_lock);
584
0
585
0
    list_for_each_entry_safe( entry, temp,
586
0
                              &d->arch.hvm_domain.msixtbl_list, list )
587
0
        del_msixtbl_entry(entry);
588
0
589
0
    spin_unlock(&d->event_lock);
590
0
}
591
592
void msix_write_completion(struct vcpu *v)
593
0
{
594
0
    unsigned long ctrl_address = v->arch.hvm_vcpu.hvm_io.msix_unmask_address;
595
0
    unsigned long snoop_addr = v->arch.hvm_vcpu.hvm_io.msix_snoop_address;
596
0
597
0
    v->arch.hvm_vcpu.hvm_io.msix_snoop_address = 0;
598
0
599
0
    if ( !ctrl_address && snoop_addr &&
600
0
         v->arch.hvm_vcpu.hvm_io.msix_snoop_gpa )
601
0
    {
602
0
        const struct msi_desc *desc;
603
0
        uint32_t data;
604
0
605
0
        rcu_read_lock(&msixtbl_rcu_lock);
606
0
        desc = msixtbl_addr_to_desc(msixtbl_find_entry(v, snoop_addr),
607
0
                                    snoop_addr);
608
0
        rcu_read_unlock(&msixtbl_rcu_lock);
609
0
610
0
        if ( desc &&
611
0
             hvm_copy_from_guest_phys(&data,
612
0
                                      v->arch.hvm_vcpu.hvm_io.msix_snoop_gpa,
613
0
                                      sizeof(data)) == HVMTRANS_okay &&
614
0
             !(data & PCI_MSIX_VECTOR_BITMASK) )
615
0
            ctrl_address = snoop_addr;
616
0
    }
617
0
618
0
    if ( !ctrl_address )
619
0
        return;
620
0
621
0
    v->arch.hvm_vcpu.hvm_io.msix_unmask_address = 0;
622
0
    if ( msixtbl_write(v, ctrl_address, 4, 0) != X86EMUL_OKAY )
623
0
        gdprintk(XENLOG_WARNING, "MSI-X write completion failure\n");
624
0
}
625
626
static unsigned int msi_gflags(uint16_t data, uint64_t addr)
627
42
{
628
42
    /*
629
42
     * We need to use the DOMCTL constants here because the output of this
630
42
     * function is used as input to pt_irq_create_bind, which also takes the
631
42
     * input from the DOMCTL itself.
632
42
     */
633
42
    return MASK_INSR(MASK_EXTR(addr, MSI_ADDR_DEST_ID_MASK),
634
42
                     XEN_DOMCTL_VMSI_X86_DEST_ID_MASK) |
635
42
           MASK_INSR(MASK_EXTR(addr, MSI_ADDR_REDIRECTION_MASK),
636
42
                     XEN_DOMCTL_VMSI_X86_RH_MASK) |
637
42
           MASK_INSR(MASK_EXTR(addr, MSI_ADDR_DESTMODE_MASK),
638
42
                     XEN_DOMCTL_VMSI_X86_DM_MASK) |
639
42
           MASK_INSR(MASK_EXTR(data, MSI_DATA_DELIVERY_MODE_MASK),
640
42
                     XEN_DOMCTL_VMSI_X86_DELIV_MASK) |
641
42
           MASK_INSR(MASK_EXTR(data, MSI_DATA_TRIGGER_MASK),
642
42
                     XEN_DOMCTL_VMSI_X86_TRIG_MASK);
643
42
}
644
645
static void vpci_mask_pirq(struct domain *d, int pirq, bool mask)
646
36
{
647
36
    unsigned long flags;
648
36
    struct irq_desc *desc = domain_spin_lock_irq_desc(d, pirq, &flags);
649
36
650
36
    if ( !desc )
651
0
        return;
652
36
    guest_mask_msi_irq(desc, mask);
653
36
    spin_unlock_irqrestore(&desc->lock, flags);
654
36
}
655
656
void vpci_msi_arch_mask(struct vpci_msi *msi, const struct pci_dev *pdev,
657
                        unsigned int entry, bool mask)
658
0
{
659
0
    vpci_mask_pirq(pdev->domain, msi->arch.pirq + entry, mask);
660
0
}
661
662
static int vpci_msi_enable(const struct pci_dev *pdev, uint32_t data,
663
                           uint64_t address, unsigned int nr,
664
                           paddr_t table_base)
665
42
{
666
42
    struct msi_info msi_info = {
667
42
        .seg = pdev->seg,
668
42
        .bus = pdev->bus,
669
42
        .devfn = pdev->devfn,
670
42
        .table_base = table_base,
671
42
        .entry_nr = nr,
672
42
    };
673
36
    unsigned int i, vectors = table_base ? 1 : nr;
674
42
    int rc, pirq = INVALID_PIRQ;
675
42
676
42
    /* Get a PIRQ. */
677
42
    rc = allocate_and_map_msi_pirq(pdev->domain, -1, &pirq,
678
36
                                   table_base ? MAP_PIRQ_TYPE_MSI
679
6
                                              : MAP_PIRQ_TYPE_MULTI_MSI,
680
42
                                   &msi_info);
681
42
    if ( rc )
682
0
    {
683
0
        gdprintk(XENLOG_ERR, "%04x:%02x:%02x.%u: failed to map PIRQ: %d\n",
684
0
                 pdev->seg, pdev->bus, PCI_SLOT(pdev->devfn),
685
0
                 PCI_FUNC(pdev->devfn), rc);
686
0
        return rc;
687
0
    }
688
42
689
84
    for ( i = 0; i < vectors; i++ )
690
42
    {
691
42
        uint8_t vector = MASK_EXTR(data, MSI_DATA_VECTOR_MASK);
692
42
        uint8_t vector_mask = 0xff >> (8 - fls(vectors) + 1);
693
42
        struct xen_domctl_bind_pt_irq bind = {
694
42
            .machine_irq = pirq + i,
695
42
            .irq_type = PT_IRQ_TYPE_MSI,
696
42
            .u.msi.gvec = (vector & ~vector_mask) |
697
42
                          ((vector + i) & vector_mask),
698
42
            .u.msi.gflags = msi_gflags(data, address),
699
42
        };
700
42
701
42
        pcidevs_lock();
702
42
        rc = pt_irq_create_bind(pdev->domain, &bind);
703
42
        if ( rc )
704
0
        {
705
0
            gdprintk(XENLOG_ERR,
706
0
                     "%04x:%02x:%02x.%u: failed to bind PIRQ %u: %d\n",
707
0
                     pdev->seg, pdev->bus, PCI_SLOT(pdev->devfn),
708
0
                     PCI_FUNC(pdev->devfn), pirq + i, rc);
709
0
            while ( bind.machine_irq-- )
710
0
                pt_irq_destroy_bind(pdev->domain, &bind);
711
0
            spin_lock(&pdev->domain->event_lock);
712
0
            unmap_domain_pirq(pdev->domain, pirq);
713
0
            spin_unlock(&pdev->domain->event_lock);
714
0
            pcidevs_unlock();
715
0
            return rc;
716
0
        }
717
42
        pcidevs_unlock();
718
42
    }
719
42
720
42
    return pirq;
721
42
}
722
723
int vpci_msi_arch_enable(struct vpci_msi *msi, const struct pci_dev *pdev,
724
                         unsigned int vectors)
725
6
{
726
6
    int rc;
727
6
728
6
    ASSERT(msi->arch.pirq == INVALID_PIRQ);
729
6
    rc = vpci_msi_enable(pdev, msi->data, msi->address, vectors, 0);
730
6
    if ( rc >= 0 )
731
6
    {
732
6
        msi->arch.pirq = rc;
733
6
        rc = 0;
734
6
    }
735
6
736
6
    return rc;
737
6
}
738
739
static void vpci_msi_disable(const struct pci_dev *pdev, int pirq,
740
                             unsigned int nr)
741
0
{
742
0
    unsigned int i;
743
0
744
0
    ASSERT(pirq != INVALID_PIRQ);
745
0
746
0
    pcidevs_lock();
747
0
    for ( i = 0; i < nr; i++ )
748
0
    {
749
0
        struct xen_domctl_bind_pt_irq bind = {
750
0
            .machine_irq = pirq + i,
751
0
            .irq_type = PT_IRQ_TYPE_MSI,
752
0
        };
753
0
        int rc;
754
0
755
0
        rc = pt_irq_destroy_bind(pdev->domain, &bind);
756
0
        ASSERT(!rc);
757
0
    }
758
0
759
0
    spin_lock(&pdev->domain->event_lock);
760
0
    unmap_domain_pirq(pdev->domain, pirq);
761
0
    spin_unlock(&pdev->domain->event_lock);
762
0
    pcidevs_unlock();
763
0
}
764
765
void vpci_msi_arch_disable(struct vpci_msi *msi, const struct pci_dev *pdev)
766
0
{
767
0
    vpci_msi_disable(pdev, msi->arch.pirq, msi->vectors);
768
0
    msi->arch.pirq = INVALID_PIRQ;
769
0
}
770
771
void vpci_msi_arch_init(struct vpci_msi *msi)
772
21
{
773
21
    msi->arch.pirq = INVALID_PIRQ;
774
21
}
775
776
void vpci_msi_arch_print(const struct vpci_msi *msi)
777
0
{
778
0
    printk("vec=%#02x%7s%6s%3sassert%5s%7s dest_id=%lu pirq: %d\n",
779
0
           MASK_EXTR(msi->data, MSI_DATA_VECTOR_MASK),
780
0
           msi->data & MSI_DATA_DELIVERY_LOWPRI ? "lowest" : "fixed",
781
0
           msi->data & MSI_DATA_TRIGGER_LEVEL ? "level" : "edge",
782
0
           msi->data & MSI_DATA_LEVEL_ASSERT ? "" : "de",
783
0
           msi->address & MSI_ADDR_DESTMODE_LOGIC ? "log" : "phys",
784
0
           msi->address & MSI_ADDR_REDIRECTION_LOWPRI ? "lowest" : "fixed",
785
0
           MASK_EXTR(msi->address, MSI_ADDR_DEST_ID_MASK),
786
0
           msi->arch.pirq);
787
0
}
788
789
void vpci_msix_arch_mask_entry(struct vpci_msix_entry *entry,
790
                               const struct pci_dev *pdev, bool mask)
791
36
{
792
36
    ASSERT(entry->arch.pirq != INVALID_PIRQ);
793
36
    vpci_mask_pirq(pdev->domain, entry->arch.pirq, mask);
794
36
}
795
796
int vpci_msix_arch_enable_entry(struct vpci_msix_entry *entry,
797
                                const struct pci_dev *pdev, paddr_t table_base)
798
36
{
799
36
    int rc;
800
36
801
36
    ASSERT(entry->arch.pirq == INVALID_PIRQ);
802
36
    rc = vpci_msi_enable(pdev, entry->data, entry->addr,
803
36
                         VMSIX_ENTRY_NR(pdev->vpci->msix, entry),
804
36
                         table_base);
805
36
    if ( rc >= 0 )
806
36
    {
807
36
        entry->arch.pirq = rc;
808
36
        rc = 0;
809
36
    }
810
36
811
36
    return rc;
812
36
}
813
814
int vpci_msix_arch_disable_entry(struct vpci_msix_entry *entry,
815
                                 const struct pci_dev *pdev)
816
36
{
817
36
    if ( entry->arch.pirq == INVALID_PIRQ )
818
36
        return -ENOENT;
819
36
820
0
    vpci_msi_disable(pdev, entry->arch.pirq, 1);
821
0
    entry->arch.pirq = INVALID_PIRQ;
822
0
823
0
    return 0;
824
36
}
825
826
void vpci_msix_arch_init_entry(struct vpci_msix_entry *entry)
827
48
{
828
48
    entry->arch.pirq = INVALID_PIRQ;
829
48
}
830
831
void vpci_msix_arch_print_entry(const struct vpci_msix_entry *entry)
832
0
{
833
0
    printk("vec=%#02x%7s%6s%3sassert%5s%7s dest_id=%lu mask=%u pirq: %d\n",
834
0
           MASK_EXTR(entry->data, MSI_DATA_VECTOR_MASK),
835
0
           entry->data & MSI_DATA_DELIVERY_LOWPRI ? "lowest" : "fixed",
836
0
           entry->data & MSI_DATA_TRIGGER_LEVEL ? "level" : "edge",
837
0
           entry->data & MSI_DATA_LEVEL_ASSERT ? "" : "de",
838
0
           entry->addr & MSI_ADDR_DESTMODE_LOGIC ? "log" : "phys",
839
0
           entry->addr & MSI_ADDR_REDIRECTION_LOWPRI ? "lowest" : "fixed",
840
0
           MASK_EXTR(entry->addr, MSI_ADDR_DEST_ID_MASK),
841
0
           entry->masked, entry->arch.pirq);
842
0
}