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

« back to all changes in this revision

Viewing changes to xen/drivers/passthrough/vtd/utils.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
 */
 
19
 
 
20
#include <xen/sched.h>
 
21
#include <xen/delay.h>
 
22
#include <xen/iommu.h>
 
23
#include <xen/time.h>
 
24
#include <xen/pci.h>
 
25
#include <xen/pci_regs.h>
 
26
#include "iommu.h"
 
27
#include "dmar.h"
 
28
#include "vtd.h"
 
29
#include "extern.h"
 
30
 
 
31
int is_usb_device(u8 bus, u8 devfn)
 
32
{
 
33
    u16 class = pci_conf_read16(bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
 
34
                                PCI_CLASS_DEVICE);
 
35
    return (class == 0xc03);
 
36
}
 
37
 
 
38
/* Disable vt-d protected memory registers. */
 
39
void disable_pmr(struct iommu *iommu)
 
40
{
 
41
    u32 val;
 
42
    unsigned long flags;
 
43
 
 
44
    val = dmar_readl(iommu->reg, DMAR_PMEN_REG);
 
45
    if ( !(val & DMA_PMEN_PRS) )
 
46
        return;
 
47
 
 
48
    spin_lock_irqsave(&iommu->register_lock, flags);
 
49
    dmar_writel(iommu->reg, DMAR_PMEN_REG, val & ~DMA_PMEN_EPM);
 
50
 
 
51
    IOMMU_WAIT_OP(iommu, DMAR_PMEN_REG, dmar_readl,
 
52
                  !(val & DMA_PMEN_PRS), val);
 
53
    spin_unlock_irqrestore(&iommu->register_lock, flags);
 
54
 
 
55
    dprintk(XENLOG_INFO VTDPREFIX,
 
56
            "Disabled protected memory registers\n");
 
57
}
 
58
 
 
59
void print_iommu_regs(struct acpi_drhd_unit *drhd)
 
60
{
 
61
    struct iommu *iommu = drhd->iommu;
 
62
    u64 cap;
 
63
 
 
64
    printk("---- print_iommu_regs ----\n");
 
65
    printk(" drhd->address = %"PRIx64"\n", drhd->address);
 
66
    printk(" VER = %x\n", dmar_readl(iommu->reg, DMAR_VER_REG));
 
67
    printk(" CAP = %"PRIx64"\n", cap = dmar_readq(iommu->reg, DMAR_CAP_REG));
 
68
    printk(" n_fault_reg = %"PRIx64"\n", cap_num_fault_regs(cap));
 
69
    printk(" fault_recording_offset = %"PRIx64"\n", cap_fault_reg_offset(cap));
 
70
    if ( cap_fault_reg_offset(cap) < PAGE_SIZE )
 
71
    {
 
72
        printk(" fault_recording_reg_l = %"PRIx64"\n",
 
73
               dmar_readq(iommu->reg, cap_fault_reg_offset(cap)));
 
74
        printk(" fault_recording_reg_h = %"PRIx64"\n",
 
75
               dmar_readq(iommu->reg, cap_fault_reg_offset(cap) + 8));
 
76
    }
 
77
    printk(" ECAP = %"PRIx64"\n", dmar_readq(iommu->reg, DMAR_ECAP_REG));
 
78
    printk(" GCMD = %x\n", dmar_readl(iommu->reg, DMAR_GCMD_REG));
 
79
    printk(" GSTS = %x\n", dmar_readl(iommu->reg, DMAR_GSTS_REG));
 
80
    printk(" RTADDR = %"PRIx64"\n", dmar_readq(iommu->reg,DMAR_RTADDR_REG));
 
81
    printk(" CCMD = %"PRIx64"\n", dmar_readq(iommu->reg, DMAR_CCMD_REG));
 
82
    printk(" FSTS = %x\n", dmar_readl(iommu->reg, DMAR_FSTS_REG));
 
83
    printk(" FECTL = %x\n", dmar_readl(iommu->reg, DMAR_FECTL_REG));
 
84
    printk(" FEDATA = %x\n", dmar_readl(iommu->reg, DMAR_FEDATA_REG));
 
85
    printk(" FEADDR = %x\n", dmar_readl(iommu->reg, DMAR_FEADDR_REG));
 
86
    printk(" FEUADDR = %x\n", dmar_readl(iommu->reg, DMAR_FEUADDR_REG));
 
87
}
 
88
 
 
89
static u32 get_level_index(unsigned long gmfn, int level)
 
90
{
 
91
    while ( --level )
 
92
        gmfn = gmfn >> LEVEL_STRIDE;
 
93
 
 
94
    return gmfn & LEVEL_MASK;
 
95
}
 
96
 
 
97
void print_vtd_entries(struct iommu *iommu, int bus, int devfn, u64 gmfn)
 
98
{
 
99
    struct context_entry *ctxt_entry;
 
100
    struct root_entry *root_entry;
 
101
    struct dma_pte pte;
 
102
    u64 *l;
 
103
    u32 l_index, level;
 
104
 
 
105
    printk("print_vtd_entries: iommu = %p bdf = %x:%x.%x gmfn = %"PRIx64"\n",
 
106
           iommu, bus, PCI_SLOT(devfn), PCI_FUNC(devfn), gmfn);
 
107
 
 
108
    if ( iommu->root_maddr == 0 )
 
109
    {
 
110
        printk("    iommu->root_maddr = 0\n");
 
111
        return;
 
112
    }
 
113
 
 
114
    root_entry = (struct root_entry *)map_vtd_domain_page(iommu->root_maddr);
 
115
 
 
116
    printk("    root_entry = %p\n", root_entry);
 
117
    printk("    root_entry[%x] = %"PRIx64"\n", bus, root_entry[bus].val);
 
118
    if ( !root_present(root_entry[bus]) )
 
119
    {
 
120
        unmap_vtd_domain_page(root_entry);
 
121
        printk("    root_entry[%x] not present\n", bus);
 
122
        return;
 
123
    }
 
124
 
 
125
    ctxt_entry =
 
126
        (struct context_entry *)map_vtd_domain_page(root_entry[bus].val);
 
127
    if ( ctxt_entry == NULL )
 
128
    {
 
129
        unmap_vtd_domain_page(root_entry);
 
130
        printk("    ctxt_entry == NULL\n");
 
131
        return;
 
132
    }
 
133
 
 
134
    printk("    context = %p\n", ctxt_entry);
 
135
    printk("    context[%x] = %"PRIx64"_%"PRIx64"\n",
 
136
           devfn, ctxt_entry[devfn].hi, ctxt_entry[devfn].lo);
 
137
    if ( !context_present(ctxt_entry[devfn]) )
 
138
    {
 
139
        unmap_vtd_domain_page(ctxt_entry);
 
140
        unmap_vtd_domain_page(root_entry);
 
141
        printk("    ctxt_entry[%x] not present\n", devfn);
 
142
        return;
 
143
    }
 
144
 
 
145
    level = agaw_to_level(context_address_width(ctxt_entry[devfn]));
 
146
    if ( level != VTD_PAGE_TABLE_LEVEL_3 &&
 
147
         level != VTD_PAGE_TABLE_LEVEL_4)
 
148
    {
 
149
        unmap_vtd_domain_page(ctxt_entry);
 
150
        unmap_vtd_domain_page(root_entry);
 
151
        printk("Unsupported VTD page table level (%d)!\n", level);
 
152
    }
 
153
 
 
154
    l = maddr_to_virt(ctxt_entry[devfn].lo);
 
155
    do
 
156
    {
 
157
        l = (u64*)(((unsigned long)l >> PAGE_SHIFT_4K) << PAGE_SHIFT_4K);
 
158
        printk("    l%d = %p\n", level, l);
 
159
        if ( l == NULL )
 
160
        {
 
161
            unmap_vtd_domain_page(ctxt_entry);
 
162
            unmap_vtd_domain_page(root_entry);
 
163
            printk("    l%d == NULL\n", level);
 
164
            break;
 
165
        }
 
166
        l_index = get_level_index(gmfn, level);
 
167
        printk("    l%d_index = %x\n", level, l_index);
 
168
        printk("    l%d[%x] = %"PRIx64"\n", level, l_index, l[l_index]);
 
169
 
 
170
        pte.val = l[l_index];
 
171
        if ( !dma_pte_present(pte) )
 
172
        {
 
173
            unmap_vtd_domain_page(ctxt_entry);
 
174
            unmap_vtd_domain_page(root_entry);
 
175
            printk("    l%d[%x] not present\n", level, l_index);
 
176
            break;
 
177
        }
 
178
 
 
179
        l = maddr_to_virt(l[l_index]);
 
180
    } while ( --level );
 
181
}
 
182
 
 
183
static void dump_iommu_info(unsigned char key)
 
184
{
 
185
#if defined(__i386__) || defined(__x86_64__)
 
186
    struct acpi_drhd_unit *drhd;
 
187
    struct iommu *iommu;
 
188
    int i;
 
189
 
 
190
    for_each_drhd_unit ( drhd )
 
191
    {
 
192
        u32 status = 0;
 
193
 
 
194
        iommu = drhd->iommu;
 
195
        printk("\niommu %x: nr_pt_levels = %x.\n", iommu->index,
 
196
            iommu->nr_pt_levels);
 
197
 
 
198
        if ( ecap_queued_inval(iommu->ecap) ||  ecap_intr_remap(iommu->ecap) )
 
199
            status = dmar_readl(iommu->reg, DMAR_GSTS_REG);
 
200
 
 
201
        printk("  Queued Invalidation: %ssupported%s.\n",
 
202
            ecap_queued_inval(iommu->ecap) ? "" : "not ",
 
203
           (status & DMA_GSTS_QIES) ? " and enabled" : "" );
 
204
 
 
205
 
 
206
        printk("  Interrupt Remapping: %ssupported%s.\n",
 
207
            ecap_intr_remap(iommu->ecap) ? "" : "not ",
 
208
            (status & DMA_GSTS_IRES) ? " and enabled" : "" );
 
209
 
 
210
        if ( status & DMA_GSTS_IRES )
 
211
        {
 
212
            /* Dump interrupt remapping table. */
 
213
            u64 iremap_maddr = dmar_readq(iommu->reg, DMAR_IRTA_REG);
 
214
            int nr_entry = 1 << ((iremap_maddr & 0xF) + 1);
 
215
            struct iremap_entry *iremap_entries = NULL;
 
216
            int print_cnt = 0;
 
217
 
 
218
            printk("  Interrupt remapping table (nr_entry=0x%x. "
 
219
                "Only dump P=1 entries here):\n", nr_entry);
 
220
            printk("       SVT  SQ   SID      DST  V  AVL DLM TM RH DM "
 
221
                   "FPD P\n");
 
222
            for ( i = 0; i < nr_entry; i++ )
 
223
            {
 
224
                struct iremap_entry *p;
 
225
                if ( i % (1 << IREMAP_ENTRY_ORDER) == 0 )
 
226
                {
 
227
                    /* This entry across page boundry */
 
228
                    if ( iremap_entries )
 
229
                        unmap_vtd_domain_page(iremap_entries);
 
230
 
 
231
                    GET_IREMAP_ENTRY(iremap_maddr, i,
 
232
                                     iremap_entries, p);
 
233
                }
 
234
                else
 
235
                    p = &iremap_entries[i % (1 << IREMAP_ENTRY_ORDER)];
 
236
 
 
237
                if ( !p->lo.p )
 
238
                    continue;
 
239
                printk("  %04x:  %x   %x  %04x %08x %02x    %x   %x  %x  %x  %x"
 
240
                    "   %x %x\n", i,
 
241
                    (u32)p->hi.svt, (u32)p->hi.sq, (u32)p->hi.sid,
 
242
                    (u32)p->lo.dst, (u32)p->lo.vector, (u32)p->lo.avail,
 
243
                    (u32)p->lo.dlm, (u32)p->lo.tm, (u32)p->lo.rh,
 
244
                    (u32)p->lo.dm, (u32)p->lo.fpd, (u32)p->lo.p);
 
245
                print_cnt++;
 
246
            }
 
247
            if ( iremap_entries )
 
248
                unmap_vtd_domain_page(iremap_entries);
 
249
            if ( iommu_ir_ctrl(iommu)->iremap_num != print_cnt )
 
250
                printk("Warning: Print %d IRTE (actually have %d)!\n",
 
251
                        print_cnt, iommu_ir_ctrl(iommu)->iremap_num);
 
252
 
 
253
        }
 
254
    }
 
255
 
 
256
    /* Dump the I/O xAPIC redirection table(s). */
 
257
    if ( iommu_enabled )
 
258
    {
 
259
        int apic, reg;
 
260
        union IO_APIC_reg_01 reg_01;
 
261
        struct IO_APIC_route_entry rte = { 0 };
 
262
        struct IO_APIC_route_remap_entry *remap;
 
263
        struct ir_ctrl *ir_ctrl;
 
264
 
 
265
        for ( apic = 0; apic < nr_ioapics; apic++ )
 
266
        {
 
267
            iommu = ioapic_to_iommu(mp_ioapics[apic].mpc_apicid);
 
268
            ir_ctrl = iommu_ir_ctrl(iommu);
 
269
            if ( !iommu || !ir_ctrl || ir_ctrl->iremap_maddr == 0 ||
 
270
                ir_ctrl->iremap_num == 0 )
 
271
                continue;
 
272
 
 
273
            printk( "\nRedirection table of IOAPIC %x:\n", apic);
 
274
 
 
275
            reg = 1; /* IO xAPIC Version Register. */
 
276
            *IO_APIC_BASE(apic) = reg;
 
277
            reg_01.raw = *(IO_APIC_BASE(apic)+4);
 
278
 
 
279
            printk("  #entry IDX FMT MASK TRIG IRR POL STAT DELI  VECTOR\n");
 
280
            for ( i = 0; i <= reg_01.bits.entries; i++ )
 
281
            {
 
282
                reg = 0x10 + i*2;
 
283
                *IO_APIC_BASE(apic) = reg;
 
284
                *(((u32 *)&rte) + 0) = *(IO_APIC_BASE(apic)+4);
 
285
 
 
286
                *IO_APIC_BASE(apic) = reg + 1;
 
287
                *(((u32 *)&rte) + 1) = *(IO_APIC_BASE(apic)+4);
 
288
 
 
289
                remap = (struct IO_APIC_route_remap_entry *) &rte;
 
290
                if ( !remap->format )
 
291
                    continue;
 
292
 
 
293
                printk("   %02x:  %04x   %x    %x   %x   %x   %x    %x"
 
294
                    "    %x     %02x\n", i,
 
295
                    (u32)remap->index_0_14 | ((u32)remap->index_15 << 15),
 
296
                    (u32)remap->format, (u32)remap->mask, (u32)remap->trigger,
 
297
                    (u32)remap->irr, (u32)remap->polarity,
 
298
                    (u32)remap->delivery_status, (u32)remap->delivery_mode,
 
299
                    (u32)remap->vector);
 
300
            }
 
301
        }
 
302
    }
 
303
#else
 
304
    printk("%s: not implemnted on IA64 for now.\n", __func__);
 
305
    /* ia64: TODO */
 
306
#endif
 
307
}
 
308
 
 
309
struct keyhandler dump_iommu_info_keyhandler = {
 
310
    .diagnostic = 1,
 
311
    .u.fn = dump_iommu_info,
 
312
    .desc = "dump iommu info"
 
313
};
 
314
 
 
315
/*
 
316
 * Local variables:
 
317
 * mode: C
 
318
 * c-set-style: "BSD"
 
319
 * c-basic-offset: 4
 
320
 * indent-tabs-mode: nil
 
321
 * End:
 
322
 */