~ressu/+junk/xen-debian

« back to all changes in this revision

Viewing changes to xen/drivers/acpi/apei/apei-io.c

  • Committer: sami at haahtinen
  • Author(s): Bastian Blank
  • Date: 2011-03-17 14:12:45 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: sami@haahtinen.name-20110317141245-owgqox0l0p3g5857
Tags: 4.1.0~rc6-1
* New upstream release candidate.
* Build documentation using pdflatex.
* Use python 2.6. (closes: #596545)
* Fix lintian override.
* Install new tools: xl, xenpaging.
* Enable blktap2.
  - Use own md5 implementation.
  - Fix includes.
  - Fix linking of blktap2 binaries.
  - Remove optimization setting.
* Temporarily disable hvmloader, wants to download ipxe.
* Remove xenstored pid check from xl.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * apei-io.c - APEI IO memory pre-mapping/post-unmapping and access
 
3
 *
 
4
 * Copyright (C) 2009-2010, Intel Corp.
 
5
 *      Author: Huang Ying <ying.huang@intel.com>
 
6
 *      Ported by: Liu, Jinsong <jinsong.liu@intel.com>
 
7
 *
 
8
 * This program is free software; you can redistribute it and/or
 
9
 * modify it under the terms of the GNU General Public License version
 
10
 * 2 as published by the Free Software Foundation.
 
11
 *
 
12
 * This program is distributed in the hope that it will be useful,
 
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
 * GNU General Public License for more details.
 
16
 *
 
17
 * You should have received a copy of the GNU General Public License
 
18
 * along with this program; if not, write to the Free Software
 
19
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
20
 */
 
21
 
 
22
#include <xen/kernel.h>
 
23
#include <xen/errno.h>
 
24
#include <xen/delay.h>
 
25
#include <xen/string.h>
 
26
#include <xen/xmalloc.h>
 
27
#include <xen/types.h>
 
28
#include <xen/spinlock.h>
 
29
#include <xen/list.h>
 
30
#include <xen/cper.h>
 
31
#include <xen/prefetch.h>
 
32
#include <asm/fixmap.h>
 
33
#include <asm/io.h>
 
34
#include <acpi/acpi.h>
 
35
#include <acpi/apei.h>
 
36
 
 
37
static LIST_HEAD(apei_iomaps);
 
38
/*
 
39
 * Used for mutual exclusion between writers of apei_iomaps list, for
 
40
 * synchronization between readers and writer.
 
41
 */
 
42
static DEFINE_SPINLOCK(apei_iomaps_lock);
 
43
 
 
44
struct apei_iomap {
 
45
        struct list_head list;
 
46
        void __iomem *vaddr;
 
47
        unsigned long size;
 
48
        paddr_t paddr;
 
49
};
 
50
 
 
51
static struct apei_iomap *__apei_find_iomap(paddr_t paddr,
 
52
                                            unsigned long size)
 
53
{
 
54
        struct apei_iomap *map;
 
55
 
 
56
        list_for_each_entry(map, &apei_iomaps, list) {
 
57
                if (map->paddr + map->size >= paddr + size &&
 
58
                    map->paddr <= paddr)
 
59
                        return map;
 
60
        }
 
61
        return NULL;
 
62
}
 
63
 
 
64
static void __iomem *__apei_ioremap_fast(paddr_t paddr,
 
65
                                         unsigned long size)
 
66
{
 
67
        struct apei_iomap *map;
 
68
 
 
69
        map = __apei_find_iomap(paddr, size);
 
70
        if (map)
 
71
                return map->vaddr + (paddr - map->paddr);
 
72
        else
 
73
                return NULL;
 
74
}
 
75
 
 
76
static int apei_range_nr;
 
77
 
 
78
static void __iomem *__init apei_range_map(paddr_t paddr, unsigned long size)
 
79
{
 
80
        int i, pg;
 
81
        int start_nr, cur_nr;
 
82
 
 
83
        pg = ((((paddr + size -1) & PAGE_MASK)
 
84
                 - (paddr & PAGE_MASK)) >> PAGE_SHIFT) + 1;
 
85
        if (apei_range_nr + pg > FIX_APEI_RANGE_MAX)
 
86
                return NULL;
 
87
 
 
88
        start_nr = apei_range_nr + pg -1;
 
89
        for (i = 0; i < pg; i++) {
 
90
                cur_nr = start_nr - i;
 
91
                set_fixmap_nocache(FIX_APEI_RANGE_BASE + cur_nr,
 
92
                                        paddr + (i << PAGE_SHIFT));
 
93
                apei_range_nr++;
 
94
        }
 
95
 
 
96
        return (void __iomem *)fix_to_virt(FIX_APEI_RANGE_BASE + start_nr);
 
97
}
 
98
 
 
99
/*
 
100
 * Used to pre-map the specified IO memory area. First try to find
 
101
 * whether the area is already pre-mapped, if it is, return; otherwise,
 
102
 * do the real map, and add the mapping into apei_iomaps list.
 
103
 */
 
104
void __iomem *__init apei_pre_map(paddr_t paddr, unsigned long size)
 
105
{
 
106
        void __iomem *vaddr;
 
107
        struct apei_iomap *map;
 
108
        unsigned long flags;
 
109
 
 
110
        spin_lock_irqsave(&apei_iomaps_lock, flags);
 
111
        vaddr = __apei_ioremap_fast(paddr, size);
 
112
        spin_unlock_irqrestore(&apei_iomaps_lock, flags);
 
113
        if (vaddr)
 
114
                return vaddr;
 
115
 
 
116
        map = xmalloc(struct apei_iomap);
 
117
        if (!map)
 
118
                return NULL;
 
119
 
 
120
        vaddr = apei_range_map(paddr, size);
 
121
        if (!vaddr) {
 
122
                xfree(map);
 
123
                return NULL;
 
124
        }
 
125
 
 
126
        INIT_LIST_HEAD(&map->list);
 
127
        map->paddr = paddr & PAGE_MASK;
 
128
        map->size = (((paddr + size + PAGE_SIZE -1) & PAGE_MASK)
 
129
                                         - (paddr & PAGE_MASK));
 
130
        map->vaddr = vaddr;
 
131
 
 
132
        spin_lock_irqsave(&apei_iomaps_lock, flags);
 
133
        list_add_tail(&map->list, &apei_iomaps);
 
134
        spin_unlock_irqrestore(&apei_iomaps_lock, flags);
 
135
 
 
136
        return map->vaddr + (paddr - map->paddr);
 
137
}
 
138
 
 
139
/*
 
140
 * Used to post-unmap the specified IO memory area.
 
141
 */
 
142
static void __init apei_post_unmap(paddr_t paddr, unsigned long size)
 
143
{
 
144
        struct apei_iomap *map;
 
145
        unsigned long flags;
 
146
 
 
147
        spin_lock_irqsave(&apei_iomaps_lock, flags);
 
148
        map = __apei_find_iomap(paddr, size);
 
149
        if (!map)
 
150
                return;
 
151
 
 
152
        list_del(&map->list);
 
153
        spin_unlock_irqrestore(&apei_iomaps_lock, flags);
 
154
 
 
155
        xfree(map);
 
156
}
 
157
 
 
158
/* In NMI handler, should set silent = 1 */
 
159
static int apei_check_gar(struct acpi_generic_address *reg,
 
160
                          u64 *paddr, int silent)
 
161
{
 
162
        u32 width, space_id;
 
163
 
 
164
        width = reg->bit_width;
 
165
        space_id = reg->space_id;
 
166
        /* Handle possible alignment issues */
 
167
        memcpy(paddr, &reg->address, sizeof(*paddr));
 
168
        if (!*paddr) {
 
169
                if (!silent)
 
170
                        printk(KERN_WARNING
 
171
                        "Invalid physical address in GAR\n");
 
172
                return -EINVAL;
 
173
        }
 
174
 
 
175
        if ((width != 8) && (width != 16) && (width != 32) && (width != 64)) {
 
176
                if (!silent)
 
177
                        printk(KERN_WARNING
 
178
                        "Invalid bit width in GAR\n");
 
179
                return -EINVAL;
 
180
        }
 
181
 
 
182
        if (space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY &&
 
183
            space_id != ACPI_ADR_SPACE_SYSTEM_IO) {
 
184
                if (!silent)
 
185
                        printk(KERN_WARNING
 
186
                        "Invalid address space type in GAR\n");
 
187
                return -EINVAL;
 
188
        }
 
189
 
 
190
        return 0;
 
191
}
 
192
 
 
193
/* Pre-map, working on GAR */
 
194
int __init apei_pre_map_gar(struct acpi_generic_address *reg)
 
195
{
 
196
        u64 paddr;
 
197
        void __iomem *vaddr;
 
198
        int rc;
 
199
 
 
200
        if (reg->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY)
 
201
                return 0;
 
202
 
 
203
        rc = apei_check_gar(reg, &paddr, 0);
 
204
        if (rc)
 
205
                return rc;
 
206
 
 
207
        vaddr = apei_pre_map(paddr, reg->bit_width / 8);
 
208
        if (!vaddr)
 
209
                return -EIO;
 
210
 
 
211
        return 0;
 
212
}
 
213
 
 
214
/* Post-unmap, working on GAR */
 
215
int __init apei_post_unmap_gar(struct acpi_generic_address *reg)
 
216
{
 
217
        u64 paddr;
 
218
        int rc;
 
219
 
 
220
        if (reg->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY)
 
221
                return 0;
 
222
 
 
223
        rc = apei_check_gar(reg, &paddr, 0);
 
224
        if (rc)
 
225
                return rc;
 
226
 
 
227
        apei_post_unmap(paddr, reg->bit_width / 8);
 
228
 
 
229
        return 0;
 
230
}
 
231
 
 
232
static int apei_read_mem(u64 paddr, u64 *val, u32 width)
 
233
{
 
234
        void __iomem *addr;
 
235
        u64 tmpval;
 
236
 
 
237
        addr = __apei_ioremap_fast(paddr, width);
 
238
        switch (width) {
 
239
        case 8:
 
240
                *val = readb(addr);
 
241
                break;
 
242
        case 16:
 
243
                *val = readw(addr);
 
244
                break;
 
245
        case 32:
 
246
                *val = readl(addr);
 
247
                break;
 
248
        case 64:
 
249
                tmpval = (u64)readl(addr);
 
250
                tmpval |= ((u64)readl(addr+4)) << 32;
 
251
                *val = tmpval;
 
252
                break;
 
253
        default:
 
254
                return -EINVAL;
 
255
        }
 
256
 
 
257
        return 0;
 
258
}
 
259
 
 
260
static int apei_write_mem(u64 paddr, u64 val, u32 width)
 
261
{
 
262
        void __iomem *addr;
 
263
        u32 tmpval;
 
264
 
 
265
        addr = __apei_ioremap_fast(paddr, width);
 
266
        switch (width) {
 
267
        case 8:
 
268
                writeb(val, addr);
 
269
                break;
 
270
        case 16:
 
271
                writew(val, addr);
 
272
                break;
 
273
        case 32:
 
274
                writel(val, addr);
 
275
                break;
 
276
        case 64:
 
277
                tmpval = (u32)val;
 
278
                writel(tmpval, addr);
 
279
                tmpval = (u32)(val >> 32);
 
280
                writel(tmpval, addr+4);
 
281
                break;
 
282
        default:
 
283
                return -EINVAL;
 
284
        }
 
285
 
 
286
        return 0;
 
287
}
 
288
 
 
289
int apei_read(u64 *val, struct acpi_generic_address *reg)
 
290
{
 
291
        u64 paddr;
 
292
        int rc;
 
293
 
 
294
        rc = apei_check_gar(reg, &paddr, 1);
 
295
        if (rc)
 
296
                return rc;
 
297
 
 
298
        *val = 0;
 
299
 
 
300
        /* currently all erst implementation take bit_width as real range */
 
301
        switch (reg->space_id) {
 
302
        case ACPI_ADR_SPACE_SYSTEM_MEMORY:
 
303
                return apei_read_mem(paddr, val, reg->bit_width);
 
304
        case ACPI_ADR_SPACE_SYSTEM_IO:
 
305
                return acpi_os_read_port(paddr, (u32 *)val, reg->bit_width);
 
306
        default:
 
307
                return -EINVAL;
 
308
        }
 
309
}
 
310
 
 
311
int apei_write(u64 val, struct acpi_generic_address *reg)
 
312
{
 
313
        u64 paddr;
 
314
        int rc;
 
315
 
 
316
        rc = apei_check_gar(reg, &paddr, 1);
 
317
        if (rc)
 
318
                return rc;
 
319
 
 
320
        switch (reg->space_id) {
 
321
        case ACPI_ADR_SPACE_SYSTEM_MEMORY:
 
322
                return apei_write_mem(paddr, val, reg->bit_width);
 
323
        case ACPI_ADR_SPACE_SYSTEM_IO:
 
324
                return acpi_os_write_port(paddr, val, reg->bit_width);
 
325
        default:
 
326
                return -EINVAL;
 
327
        }
 
328
}