/[linux-patches]/genpatches-2.6/trunk/2.6.30/2300_alpha-add-pci-resources.patch
Gentoo

Contents of /genpatches-2.6/trunk/2.6.30/2300_alpha-add-pci-resources.patch

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1572 - (show annotations) (download) (as text)
Fri Jun 5 16:26:11 2009 UTC (11 years, 6 months ago) by mpagano
File MIME type: text/x-diff
File size: 14787 byte(s)
Creating 2.6.30 branch from 2.6.29
1 From: Ivan Kokshaysky <ink@jurassic.park.msu.ru>
2 Date: Tue, 17 Feb 2009 10:46:53 +0000 (+0300)
3 Subject: PCI/alpha: pci sysfs resources
4 X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Faxboe%2Flinux-2.6-block.git;a=commitdiff_plain;h=10a0ef39fbd1d484c2bbc1ffd83d57ecef209140
5
6 PCI/alpha: pci sysfs resources
7
8 This closes http://bugzilla.kernel.org/show_bug.cgi?id=10893
9 which is a showstopper for X development on alpha.
10
11 The generic HAVE_PCI_MMAP code (drivers/pci-sysfs.c) is not
12 very useful since we have to deal with three different types
13 of MMIO address spaces: sparse and dense mappings for old
14 ev4/ev5 machines and "normal" 1:1 MMIO space (bwx) for ev56 and
15 later.
16 Also "write combine" mappings are meaningless on alpha - roughly
17 speaking, alpha does write combining, IO reordering and other
18 optimizations by default, unless user splits IO accesses
19 with memory barriers.
20
21 I think the cleanest way to deal with resource files on alpha
22 is to convert the default no-op pci_create_resource_files() and
23 pci_remove_resource_files() for !HAVE_PCI_MMAP case into __weak
24 functions and override them with alpha specific ones.
25
26 Another alpha hook is needed for "legacy_" resource files
27 to handle sparse addressing (pci_adjust_legacy_attr).
28
29 With the "standard" resourceN files on ev56/ev6 libpciaccess
30 works "out of the box". Handling of resourceN_sparse/resourceN_dense
31 files on older machines obviously requires some userland work.
32
33 Sparse/dense stuff has been tested on sx164 (pca56/pyxis, normally
34 uses bwx IO) with the kernel hacked into "cia compatible" mode.
35
36 Signed-off-by: Ivan Kokshaysky <ink@jurassic.park.msu.ru>
37 Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
38 ---
39
40 diff --git a/arch/alpha/include/asm/pci.h b/arch/alpha/include/asm/pci.h
41 index 2a14302..cb04eaa 100644
42 --- a/arch/alpha/include/asm/pci.h
43 +++ b/arch/alpha/include/asm/pci.h
44 @@ -273,4 +273,18 @@ struct pci_dev *alpha_gendev_to_pci(struct device *dev);
45
46 extern struct pci_dev *isa_bridge;
47
48 +extern int pci_legacy_read(struct pci_bus *bus, loff_t port, u32 *val,
49 + size_t count);
50 +extern int pci_legacy_write(struct pci_bus *bus, loff_t port, u32 val,
51 + size_t count);
52 +extern int pci_mmap_legacy_page_range(struct pci_bus *bus,
53 + struct vm_area_struct *vma,
54 + enum pci_mmap_state mmap_state);
55 +extern void pci_adjust_legacy_attr(struct pci_bus *bus,
56 + enum pci_mmap_state mmap_type);
57 +#define HAVE_PCI_LEGACY 1
58 +
59 +extern int pci_create_resource_files(struct pci_dev *dev);
60 +extern void pci_remove_resource_files(struct pci_dev *dev);
61 +
62 #endif /* __ALPHA_PCI_H */
63 diff --git a/arch/alpha/kernel/Makefile b/arch/alpha/kernel/Makefile
64 index b469775..a427538 100644
65 --- a/arch/alpha/kernel/Makefile
66 +++ b/arch/alpha/kernel/Makefile
67 @@ -12,7 +12,7 @@ obj-y := entry.o traps.o process.o init_task.o osf_sys.o irq.o \
68
69 obj-$(CONFIG_VGA_HOSE) += console.o
70 obj-$(CONFIG_SMP) += smp.o
71 -obj-$(CONFIG_PCI) += pci.o pci_iommu.o
72 +obj-$(CONFIG_PCI) += pci.o pci_iommu.o pci-sysfs.o
73 obj-$(CONFIG_SRM_ENV) += srm_env.o
74 obj-$(CONFIG_MODULES) += module.o
75
76 diff --git a/arch/alpha/kernel/pci-sysfs.c b/arch/alpha/kernel/pci-sysfs.c
77 new file mode 100644
78 index 0000000..6ea822e
79 --- /dev/null
80 +++ b/arch/alpha/kernel/pci-sysfs.c
81 @@ -0,0 +1,366 @@
82 +/*
83 + * arch/alpha/kernel/pci-sysfs.c
84 + *
85 + * Copyright (C) 2009 Ivan Kokshaysky
86 + *
87 + * Alpha PCI resource files.
88 + *
89 + * Loosely based on generic HAVE_PCI_MMAP implementation in
90 + * drivers/pci/pci-sysfs.c
91 + */
92 +
93 +#include <linux/sched.h>
94 +#include <linux/pci.h>
95 +
96 +static int hose_mmap_page_range(struct pci_controller *hose,
97 + struct vm_area_struct *vma,
98 + enum pci_mmap_state mmap_type, int sparse)
99 +{
100 + unsigned long base;
101 +
102 + if (mmap_type == pci_mmap_mem)
103 + base = sparse ? hose->sparse_mem_base : hose->dense_mem_base;
104 + else
105 + base = sparse ? hose->sparse_io_base : hose->dense_io_base;
106 +
107 + vma->vm_pgoff += base >> PAGE_SHIFT;
108 + vma->vm_flags |= (VM_IO | VM_RESERVED);
109 +
110 + return io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
111 + vma->vm_end - vma->vm_start,
112 + vma->vm_page_prot);
113 +}
114 +
115 +static int __pci_mmap_fits(struct pci_dev *pdev, int num,
116 + struct vm_area_struct *vma, int sparse)
117 +{
118 + unsigned long nr, start, size;
119 + int shift = sparse ? 5 : 0;
120 +
121 + nr = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
122 + start = vma->vm_pgoff;
123 + size = ((pci_resource_len(pdev, num) - 1) >> (PAGE_SHIFT - shift)) + 1;
124 +
125 + if (start < size && size - start >= nr)
126 + return 1;
127 + WARN(1, "process \"%s\" tried to map%s 0x%08lx-0x%08lx on %s BAR %d "
128 + "(size 0x%08lx)\n",
129 + current->comm, sparse ? " sparse" : "", start, start + nr,
130 + pci_name(pdev), num, size);
131 + return 0;
132 +}
133 +
134 +/**
135 + * pci_mmap_resource - map a PCI resource into user memory space
136 + * @kobj: kobject for mapping
137 + * @attr: struct bin_attribute for the file being mapped
138 + * @vma: struct vm_area_struct passed into the mmap
139 + * @sparse: address space type
140 + *
141 + * Use the bus mapping routines to map a PCI resource into userspace.
142 + */
143 +static int pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr,
144 + struct vm_area_struct *vma, int sparse)
145 +{
146 + struct pci_dev *pdev = to_pci_dev(container_of(kobj,
147 + struct device, kobj));
148 + struct resource *res = (struct resource *)attr->private;
149 + enum pci_mmap_state mmap_type;
150 + struct pci_bus_region bar;
151 + int i;
152 +
153 + for (i = 0; i < PCI_ROM_RESOURCE; i++)
154 + if (res == &pdev->resource[i])
155 + break;
156 + if (i >= PCI_ROM_RESOURCE)
157 + return -ENODEV;
158 +
159 + if (!__pci_mmap_fits(pdev, i, vma, sparse))
160 + return -EINVAL;
161 +
162 + if (iomem_is_exclusive(res->start))
163 + return -EINVAL;
164 +
165 + pcibios_resource_to_bus(pdev, &bar, res);
166 + vma->vm_pgoff += bar.start >> (PAGE_SHIFT - (sparse ? 5 : 0));
167 + mmap_type = res->flags & IORESOURCE_MEM ? pci_mmap_mem : pci_mmap_io;
168 +
169 + return hose_mmap_page_range(pdev->sysdata, vma, mmap_type, sparse);
170 +}
171 +
172 +static int pci_mmap_resource_sparse(struct kobject *kobj,
173 + struct bin_attribute *attr,
174 + struct vm_area_struct *vma)
175 +{
176 + return pci_mmap_resource(kobj, attr, vma, 1);
177 +}
178 +
179 +static int pci_mmap_resource_dense(struct kobject *kobj,
180 + struct bin_attribute *attr,
181 + struct vm_area_struct *vma)
182 +{
183 + return pci_mmap_resource(kobj, attr, vma, 0);
184 +}
185 +
186 +/**
187 + * pci_remove_resource_files - cleanup resource files
188 + * @dev: dev to cleanup
189 + *
190 + * If we created resource files for @dev, remove them from sysfs and
191 + * free their resources.
192 + */
193 +void pci_remove_resource_files(struct pci_dev *pdev)
194 +{
195 + int i;
196 +
197 + for (i = 0; i < PCI_ROM_RESOURCE; i++) {
198 + struct bin_attribute *res_attr;
199 +
200 + res_attr = pdev->res_attr[i];
201 + if (res_attr) {
202 + sysfs_remove_bin_file(&pdev->dev.kobj, res_attr);
203 + kfree(res_attr);
204 + }
205 +
206 + res_attr = pdev->res_attr_wc[i];
207 + if (res_attr) {
208 + sysfs_remove_bin_file(&pdev->dev.kobj, res_attr);
209 + kfree(res_attr);
210 + }
211 + }
212 +}
213 +
214 +static int sparse_mem_mmap_fits(struct pci_dev *pdev, int num)
215 +{
216 + struct pci_bus_region bar;
217 + struct pci_controller *hose = pdev->sysdata;
218 + long dense_offset;
219 + unsigned long sparse_size;
220 +
221 + pcibios_resource_to_bus(pdev, &bar, &pdev->resource[num]);
222 +
223 + /* All core logic chips have 4G sparse address space, except
224 + CIA which has 16G (see xxx_SPARSE_MEM and xxx_DENSE_MEM
225 + definitions in asm/core_xxx.h files). This corresponds
226 + to 128M or 512M of the bus space. */
227 + dense_offset = (long)(hose->dense_mem_base - hose->sparse_mem_base);
228 + sparse_size = dense_offset >= 0x400000000UL ? 0x20000000 : 0x8000000;
229 +
230 + return bar.end < sparse_size;
231 +}
232 +
233 +static int pci_create_one_attr(struct pci_dev *pdev, int num, char *name,
234 + char *suffix, struct bin_attribute *res_attr,
235 + unsigned long sparse)
236 +{
237 + size_t size = pci_resource_len(pdev, num);
238 +
239 + sprintf(name, "resource%d%s", num, suffix);
240 + res_attr->mmap = sparse ? pci_mmap_resource_sparse :
241 + pci_mmap_resource_dense;
242 + res_attr->attr.name = name;
243 + res_attr->attr.mode = S_IRUSR | S_IWUSR;
244 + res_attr->size = sparse ? size << 5 : size;
245 + res_attr->private = &pdev->resource[num];
246 + return sysfs_create_bin_file(&pdev->dev.kobj, res_attr);
247 +}
248 +
249 +static int pci_create_attr(struct pci_dev *pdev, int num)
250 +{
251 + /* allocate attribute structure, piggyback attribute name */
252 + int retval, nlen1, nlen2 = 0, res_count = 1;
253 + unsigned long sparse_base, dense_base;
254 + struct bin_attribute *attr;
255 + struct pci_controller *hose = pdev->sysdata;
256 + char *suffix, *attr_name;
257 +
258 + suffix = ""; /* Assume bwx machine, normal resourceN files. */
259 + nlen1 = 10;
260 +
261 + if (pdev->resource[num].flags & IORESOURCE_MEM) {
262 + sparse_base = hose->sparse_mem_base;
263 + dense_base = hose->dense_mem_base;
264 + if (sparse_base && !sparse_mem_mmap_fits(pdev, num)) {
265 + sparse_base = 0;
266 + suffix = "_dense";
267 + nlen1 = 16; /* resourceN_dense */
268 + }
269 + } else {
270 + sparse_base = hose->sparse_io_base;
271 + dense_base = hose->dense_io_base;
272 + }
273 +
274 + if (sparse_base) {
275 + suffix = "_sparse";
276 + nlen1 = 17;
277 + if (dense_base) {
278 + nlen2 = 16; /* resourceN_dense */
279 + res_count = 2;
280 + }
281 + }
282 +
283 + attr = kzalloc(sizeof(*attr) * res_count + nlen1 + nlen2, GFP_ATOMIC);
284 + if (!attr)
285 + return -ENOMEM;
286 +
287 + /* Create bwx, sparse or single dense file */
288 + attr_name = (char *)(attr + res_count);
289 + pdev->res_attr[num] = attr;
290 + retval = pci_create_one_attr(pdev, num, attr_name, suffix, attr,
291 + sparse_base);
292 + if (retval || res_count == 1)
293 + return retval;
294 +
295 + /* Create dense file */
296 + attr_name += nlen1;
297 + attr++;
298 + pdev->res_attr_wc[num] = attr;
299 + return pci_create_one_attr(pdev, num, attr_name, "_dense", attr, 0);
300 +}
301 +
302 +/**
303 + * pci_create_resource_files - create resource files in sysfs for @dev
304 + * @dev: dev in question
305 + *
306 + * Walk the resources in @dev creating files for each resource available.
307 + */
308 +int pci_create_resource_files(struct pci_dev *pdev)
309 +{
310 + int i;
311 + int retval;
312 +
313 + /* Expose the PCI resources from this device as files */
314 + for (i = 0; i < PCI_ROM_RESOURCE; i++) {
315 +
316 + /* skip empty resources */
317 + if (!pci_resource_len(pdev, i))
318 + continue;
319 +
320 + retval = pci_create_attr(pdev, i);
321 + if (retval) {
322 + pci_remove_resource_files(pdev);
323 + return retval;
324 + }
325 + }
326 + return 0;
327 +}
328 +
329 +/* Legacy I/O bus mapping stuff. */
330 +
331 +static int __legacy_mmap_fits(struct pci_controller *hose,
332 + struct vm_area_struct *vma,
333 + unsigned long res_size, int sparse)
334 +{
335 + unsigned long nr, start, size;
336 +
337 + nr = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
338 + start = vma->vm_pgoff;
339 + size = ((res_size - 1) >> PAGE_SHIFT) + 1;
340 +
341 + if (start < size && size - start >= nr)
342 + return 1;
343 + WARN(1, "process \"%s\" tried to map%s 0x%08lx-0x%08lx on hose %d "
344 + "(size 0x%08lx)\n",
345 + current->comm, sparse ? " sparse" : "", start, start + nr,
346 + hose->index, size);
347 + return 0;
348 +}
349 +
350 +static inline int has_sparse(struct pci_controller *hose,
351 + enum pci_mmap_state mmap_type)
352 +{
353 + unsigned long base;
354 +
355 + base = (mmap_type == pci_mmap_mem) ? hose->sparse_mem_base :
356 + hose->sparse_io_base;
357 +
358 + return base != 0;
359 +}
360 +
361 +int pci_mmap_legacy_page_range(struct pci_bus *bus, struct vm_area_struct *vma,
362 + enum pci_mmap_state mmap_type)
363 +{
364 + struct pci_controller *hose = bus->sysdata;
365 + int sparse = has_sparse(hose, mmap_type);
366 + unsigned long res_size;
367 +
368 + res_size = (mmap_type == pci_mmap_mem) ? bus->legacy_mem->size :
369 + bus->legacy_io->size;
370 + if (!__legacy_mmap_fits(hose, vma, res_size, sparse))
371 + return -EINVAL;
372 +
373 + return hose_mmap_page_range(hose, vma, mmap_type, sparse);
374 +}
375 +
376 +/**
377 + * pci_adjust_legacy_attr - adjustment of legacy file attributes
378 + * @b: bus to create files under
379 + * @mmap_type: I/O port or memory
380 + *
381 + * Adjust file name and size for sparse mappings.
382 + */
383 +void pci_adjust_legacy_attr(struct pci_bus *bus, enum pci_mmap_state mmap_type)
384 +{
385 + struct pci_controller *hose = bus->sysdata;
386 +
387 + if (!has_sparse(hose, mmap_type))
388 + return;
389 +
390 + if (mmap_type == pci_mmap_mem) {
391 + bus->legacy_mem->attr.name = "legacy_mem_sparse";
392 + bus->legacy_mem->size <<= 5;
393 + } else {
394 + bus->legacy_io->attr.name = "legacy_io_sparse";
395 + bus->legacy_io->size <<= 5;
396 + }
397 + return;
398 +}
399 +
400 +/* Legacy I/O bus read/write functions */
401 +int pci_legacy_read(struct pci_bus *bus, loff_t port, u32 *val, size_t size)
402 +{
403 + struct pci_controller *hose = bus->sysdata;
404 +
405 + port += hose->io_space->start;
406 +
407 + switch(size) {
408 + case 1:
409 + *((u8 *)val) = inb(port);
410 + return 1;
411 + case 2:
412 + if (port & 1)
413 + return -EINVAL;
414 + *((u16 *)val) = inw(port);
415 + return 2;
416 + case 4:
417 + if (port & 3)
418 + return -EINVAL;
419 + *((u32 *)val) = inl(port);
420 + return 4;
421 + }
422 + return -EINVAL;
423 +}
424 +
425 +int pci_legacy_write(struct pci_bus *bus, loff_t port, u32 val, size_t size)
426 +{
427 + struct pci_controller *hose = bus->sysdata;
428 +
429 + port += hose->io_space->start;
430 +
431 + switch(size) {
432 + case 1:
433 + outb(port, val);
434 + return 1;
435 + case 2:
436 + if (port & 1)
437 + return -EINVAL;
438 + outw(port, val);
439 + return 2;
440 + case 4:
441 + if (port & 3)
442 + return -EINVAL;
443 + outl(port, val);
444 + return 4;
445 + }
446 + return -EINVAL;
447 +}
448 diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
449 index dfc4e0d..1c89298 100644
450 --- a/drivers/pci/pci-sysfs.c
451 +++ b/drivers/pci/pci-sysfs.c
452 @@ -493,6 +493,19 @@ pci_mmap_legacy_io(struct kobject *kobj, struct bin_attribute *attr,
453 }
454
455 /**
456 + * pci_adjust_legacy_attr - adjustment of legacy file attributes
457 + * @b: bus to create files under
458 + * @mmap_type: I/O port or memory
459 + *
460 + * Stub implementation. Can be overridden by arch if necessary.
461 + */
462 +void __weak
463 +pci_adjust_legacy_attr(struct pci_bus *b, enum pci_mmap_state mmap_type)
464 +{
465 + return;
466 +}
467 +
468 +/**
469 * pci_create_legacy_files - create legacy I/O port and memory files
470 * @b: bus to create files under
471 *
472 @@ -518,6 +531,7 @@ void pci_create_legacy_files(struct pci_bus *b)
473 b->legacy_io->read = pci_read_legacy_io;
474 b->legacy_io->write = pci_write_legacy_io;
475 b->legacy_io->mmap = pci_mmap_legacy_io;
476 + pci_adjust_legacy_attr(b, pci_mmap_io);
477 error = device_create_bin_file(&b->dev, b->legacy_io);
478 if (error)
479 goto legacy_io_err;
480 @@ -528,6 +542,7 @@ void pci_create_legacy_files(struct pci_bus *b)
481 b->legacy_mem->size = 1024*1024;
482 b->legacy_mem->attr.mode = S_IRUSR | S_IWUSR;
483 b->legacy_mem->mmap = pci_mmap_legacy_mem;
484 + pci_adjust_legacy_attr(b, pci_mmap_mem);
485 error = device_create_bin_file(&b->dev, b->legacy_mem);
486 if (error)
487 goto legacy_mem_err;
488 @@ -719,8 +734,8 @@ static int pci_create_resource_files(struct pci_dev *pdev)
489 return 0;
490 }
491 #else /* !HAVE_PCI_MMAP */
492 -static inline int pci_create_resource_files(struct pci_dev *dev) { return 0; }
493 -static inline void pci_remove_resource_files(struct pci_dev *dev) { return; }
494 +int __weak pci_create_resource_files(struct pci_dev *dev) { return 0; }
495 +void __weak pci_remove_resource_files(struct pci_dev *dev) { return; }
496 #endif /* HAVE_PCI_MMAP */
497
498 /**
499

  ViewVC Help
Powered by ViewVC 1.1.20