blob: 564319e29bd5bd593d47fab73ca8953529b8fe2b [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * pci.c - Low-Level PCI Access in IA-64
3 *
4 * Derived from bios32.c of i386 tree.
5 *
6 * (c) Copyright 2002, 2005 Hewlett-Packard Development Company, L.P.
7 * David Mosberger-Tang <davidm@hpl.hp.com>
8 * Bjorn Helgaas <bjorn.helgaas@hp.com>
9 * Copyright (C) 2004 Silicon Graphics, Inc.
10 *
11 * Note: Above list of copyright holders is incomplete...
12 */
13#include <linux/config.h>
14
15#include <linux/acpi.h>
16#include <linux/types.h>
17#include <linux/kernel.h>
18#include <linux/pci.h>
19#include <linux/init.h>
20#include <linux/ioport.h>
21#include <linux/slab.h>
22#include <linux/smp_lock.h>
23#include <linux/spinlock.h>
24
25#include <asm/machvec.h>
26#include <asm/page.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070027#include <asm/system.h>
28#include <asm/io.h>
29#include <asm/sal.h>
30#include <asm/smp.h>
31#include <asm/irq.h>
32#include <asm/hw_irq.h>
33
34
Linus Torvalds1da177e2005-04-16 15:20:36 -070035/*
36 * Low-level SAL-based PCI configuration access functions. Note that SAL
37 * calls are already serialized (via sal_lock), so we don't need another
38 * synchronization mechanism here.
39 */
40
41#define PCI_SAL_ADDRESS(seg, bus, devfn, reg) \
42 (((u64) seg << 24) | (bus << 16) | (devfn << 8) | (reg))
43
44/* SAL 3.2 adds support for extended config space. */
45
46#define PCI_SAL_EXT_ADDRESS(seg, bus, devfn, reg) \
47 (((u64) seg << 28) | (bus << 20) | (devfn << 12) | (reg))
48
49static int
50pci_sal_read (unsigned int seg, unsigned int bus, unsigned int devfn,
51 int reg, int len, u32 *value)
52{
53 u64 addr, data = 0;
54 int mode, result;
55
56 if (!value || (seg > 65535) || (bus > 255) || (devfn > 255) || (reg > 4095))
57 return -EINVAL;
58
59 if ((seg | reg) <= 255) {
60 addr = PCI_SAL_ADDRESS(seg, bus, devfn, reg);
61 mode = 0;
62 } else {
63 addr = PCI_SAL_EXT_ADDRESS(seg, bus, devfn, reg);
64 mode = 1;
65 }
66 result = ia64_sal_pci_config_read(addr, mode, len, &data);
67 if (result != 0)
68 return -EINVAL;
69
70 *value = (u32) data;
71 return 0;
72}
73
74static int
75pci_sal_write (unsigned int seg, unsigned int bus, unsigned int devfn,
76 int reg, int len, u32 value)
77{
78 u64 addr;
79 int mode, result;
80
81 if ((seg > 65535) || (bus > 255) || (devfn > 255) || (reg > 4095))
82 return -EINVAL;
83
84 if ((seg | reg) <= 255) {
85 addr = PCI_SAL_ADDRESS(seg, bus, devfn, reg);
86 mode = 0;
87 } else {
88 addr = PCI_SAL_EXT_ADDRESS(seg, bus, devfn, reg);
89 mode = 1;
90 }
91 result = ia64_sal_pci_config_write(addr, mode, len, value);
92 if (result != 0)
93 return -EINVAL;
94 return 0;
95}
96
97static struct pci_raw_ops pci_sal_ops = {
98 .read = pci_sal_read,
99 .write = pci_sal_write
100};
101
102struct pci_raw_ops *raw_pci_ops = &pci_sal_ops;
103
104static int
105pci_read (struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value)
106{
107 return raw_pci_ops->read(pci_domain_nr(bus), bus->number,
108 devfn, where, size, value);
109}
110
111static int
112pci_write (struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value)
113{
114 return raw_pci_ops->write(pci_domain_nr(bus), bus->number,
115 devfn, where, size, value);
116}
117
118struct pci_ops pci_root_ops = {
119 .read = pci_read,
120 .write = pci_write,
121};
122
123#ifdef CONFIG_NUMA
124extern acpi_status acpi_map_iosapic(acpi_handle, u32, void *, void **);
125static void acpi_map_iosapics(void)
126{
127 acpi_get_devices(NULL, acpi_map_iosapic, NULL, NULL);
128}
129#else
130static void acpi_map_iosapics(void)
131{
132 return;
133}
134#endif /* CONFIG_NUMA */
135
136static int __init
137pci_acpi_init (void)
138{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139 acpi_map_iosapics();
140
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141 return 0;
142}
143
144subsys_initcall(pci_acpi_init);
145
146/* Called by ACPI when it finds a new root bus. */
147
148static struct pci_controller * __devinit
149alloc_pci_controller (int seg)
150{
151 struct pci_controller *controller;
152
153 controller = kmalloc(sizeof(*controller), GFP_KERNEL);
154 if (!controller)
155 return NULL;
156
157 memset(controller, 0, sizeof(*controller));
158 controller->segment = seg;
Christoph Lameter514604c2005-07-07 16:59:00 -0700159 controller->node = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160 return controller;
161}
162
163static u64 __devinit
164add_io_space (struct acpi_resource_address64 *addr)
165{
166 u64 offset;
167 int sparse = 0;
168 int i;
169
170 if (addr->address_translation_offset == 0)
171 return IO_SPACE_BASE(0); /* part of legacy IO space */
172
173 if (addr->attribute.io.translation_attribute == ACPI_SPARSE_TRANSLATION)
174 sparse = 1;
175
176 offset = (u64) ioremap(addr->address_translation_offset, 0);
177 for (i = 0; i < num_io_spaces; i++)
178 if (io_space[i].mmio_base == offset &&
179 io_space[i].sparse == sparse)
180 return IO_SPACE_BASE(i);
181
182 if (num_io_spaces == MAX_IO_SPACES) {
183 printk("Too many IO port spaces\n");
184 return ~0;
185 }
186
187 i = num_io_spaces++;
188 io_space[i].mmio_base = offset;
189 io_space[i].sparse = sparse;
190
191 return IO_SPACE_BASE(i);
192}
193
Bjorn Helgaas463eb292005-09-23 11:39:07 -0600194static acpi_status __devinit resource_to_window(struct acpi_resource *resource,
195 struct acpi_resource_address64 *addr)
196{
197 acpi_status status;
198
199 /*
200 * We're only interested in _CRS descriptors that are
201 * - address space descriptors for memory or I/O space
202 * - non-zero size
203 * - producers, i.e., the address space is routed downstream,
204 * not consumed by the bridge itself
205 */
206 status = acpi_resource_to_address64(resource, addr);
207 if (ACPI_SUCCESS(status) &&
208 (addr->resource_type == ACPI_MEMORY_RANGE ||
209 addr->resource_type == ACPI_IO_RANGE) &&
210 addr->address_length &&
211 addr->producer_consumer == ACPI_PRODUCER)
212 return AE_OK;
213
214 return AE_ERROR;
215}
216
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217static acpi_status __devinit
218count_window (struct acpi_resource *resource, void *data)
219{
220 unsigned int *windows = (unsigned int *) data;
221 struct acpi_resource_address64 addr;
222 acpi_status status;
223
Bjorn Helgaas463eb292005-09-23 11:39:07 -0600224 status = resource_to_window(resource, &addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 if (ACPI_SUCCESS(status))
Bjorn Helgaas463eb292005-09-23 11:39:07 -0600226 (*windows)++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227
228 return AE_OK;
229}
230
231struct pci_root_info {
232 struct pci_controller *controller;
233 char *name;
234};
235
236static __devinit acpi_status add_window(struct acpi_resource *res, void *data)
237{
238 struct pci_root_info *info = data;
239 struct pci_window *window;
240 struct acpi_resource_address64 addr;
241 acpi_status status;
242 unsigned long flags, offset = 0;
243 struct resource *root;
244
Bjorn Helgaas463eb292005-09-23 11:39:07 -0600245 /* Return AE_OK for non-window resources to keep scanning for more */
246 status = resource_to_window(res, &addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247 if (!ACPI_SUCCESS(status))
248 return AE_OK;
249
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250 if (addr.resource_type == ACPI_MEMORY_RANGE) {
251 flags = IORESOURCE_MEM;
252 root = &iomem_resource;
253 offset = addr.address_translation_offset;
254 } else if (addr.resource_type == ACPI_IO_RANGE) {
255 flags = IORESOURCE_IO;
256 root = &ioport_resource;
257 offset = add_io_space(&addr);
258 if (offset == ~0)
259 return AE_OK;
260 } else
261 return AE_OK;
262
263 window = &info->controller->window[info->controller->windows++];
264 window->resource.name = info->name;
265 window->resource.flags = flags;
266 window->resource.start = addr.min_address_range + offset;
267 window->resource.end = addr.max_address_range + offset;
268 window->resource.child = NULL;
269 window->offset = offset;
270
271 if (insert_resource(root, &window->resource)) {
272 printk(KERN_ERR "alloc 0x%lx-0x%lx from %s for %s failed\n",
273 window->resource.start, window->resource.end,
274 root->name, info->name);
275 }
276
277 return AE_OK;
278}
279
280static void __devinit
281pcibios_setup_root_windows(struct pci_bus *bus, struct pci_controller *ctrl)
282{
283 int i, j;
284
285 j = 0;
286 for (i = 0; i < ctrl->windows; i++) {
287 struct resource *res = &ctrl->window[i].resource;
288 /* HP's firmware has a hack to work around a Windows bug.
289 * Ignore these tiny memory ranges */
290 if ((res->flags & IORESOURCE_MEM) &&
291 (res->end - res->start < 16))
292 continue;
293 if (j >= PCI_BUS_NUM_RESOURCES) {
294 printk("Ignoring range [%lx-%lx] (%lx)\n", res->start,
295 res->end, res->flags);
296 continue;
297 }
298 bus->resource[j++] = res;
299 }
300}
301
302struct pci_bus * __devinit
303pci_acpi_scan_root(struct acpi_device *device, int domain, int bus)
304{
305 struct pci_root_info info;
306 struct pci_controller *controller;
307 unsigned int windows = 0;
308 struct pci_bus *pbus;
309 char *name;
Christoph Lameter514604c2005-07-07 16:59:00 -0700310 int pxm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311
312 controller = alloc_pci_controller(domain);
313 if (!controller)
314 goto out1;
315
316 controller->acpi_handle = device->handle;
317
Christoph Lameter514604c2005-07-07 16:59:00 -0700318 pxm = acpi_get_pxm(controller->acpi_handle);
319#ifdef CONFIG_NUMA
320 if (pxm >= 0)
321 controller->node = pxm_to_nid_map[pxm];
322#endif
323
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324 acpi_walk_resources(device->handle, METHOD_NAME__CRS, count_window,
325 &windows);
Christoph Lameter514604c2005-07-07 16:59:00 -0700326 controller->window = kmalloc_node(sizeof(*controller->window) * windows,
327 GFP_KERNEL, controller->node);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328 if (!controller->window)
329 goto out2;
330
331 name = kmalloc(16, GFP_KERNEL);
332 if (!name)
333 goto out3;
334
335 sprintf(name, "PCI Bus %04x:%02x", domain, bus);
336 info.controller = controller;
337 info.name = name;
338 acpi_walk_resources(device->handle, METHOD_NAME__CRS, add_window,
339 &info);
340
Rajesh Shahc431ada2005-04-28 00:25:45 -0700341 pbus = pci_scan_bus_parented(NULL, bus, &pci_root_ops, controller);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 if (pbus)
343 pcibios_setup_root_windows(pbus, controller);
344
345 return pbus;
346
347out3:
348 kfree(controller->window);
349out2:
350 kfree(controller);
351out1:
352 return NULL;
353}
354
355void pcibios_resource_to_bus(struct pci_dev *dev,
356 struct pci_bus_region *region, struct resource *res)
357{
358 struct pci_controller *controller = PCI_CONTROLLER(dev);
359 unsigned long offset = 0;
360 int i;
361
362 for (i = 0; i < controller->windows; i++) {
363 struct pci_window *window = &controller->window[i];
364 if (!(window->resource.flags & res->flags))
365 continue;
366 if (window->resource.start > res->start)
367 continue;
368 if (window->resource.end < res->end)
369 continue;
370 offset = window->offset;
371 break;
372 }
373
374 region->start = res->start - offset;
375 region->end = res->end - offset;
376}
377EXPORT_SYMBOL(pcibios_resource_to_bus);
378
379void pcibios_bus_to_resource(struct pci_dev *dev,
380 struct resource *res, struct pci_bus_region *region)
381{
382 struct pci_controller *controller = PCI_CONTROLLER(dev);
383 unsigned long offset = 0;
384 int i;
385
386 for (i = 0; i < controller->windows; i++) {
387 struct pci_window *window = &controller->window[i];
388 if (!(window->resource.flags & res->flags))
389 continue;
390 if (window->resource.start - window->offset > region->start)
391 continue;
392 if (window->resource.end - window->offset < region->end)
393 continue;
394 offset = window->offset;
395 break;
396 }
397
398 res->start = region->start + offset;
399 res->end = region->end + offset;
400}
Keith Owens41290c12005-08-24 16:06:25 +1000401EXPORT_SYMBOL(pcibios_bus_to_resource);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402
Rajesh Shah71c35112005-04-28 00:25:46 -0700403static int __devinit is_valid_resource(struct pci_dev *dev, int idx)
404{
405 unsigned int i, type_mask = IORESOURCE_IO | IORESOURCE_MEM;
406 struct resource *devr = &dev->resource[idx];
407
408 if (!dev->bus)
409 return 0;
410 for (i=0; i<PCI_BUS_NUM_RESOURCES; i++) {
411 struct resource *busr = dev->bus->resource[i];
412
413 if (!busr || ((busr->flags ^ devr->flags) & type_mask))
414 continue;
415 if ((devr->start) && (devr->start >= busr->start) &&
416 (devr->end <= busr->end))
417 return 1;
418 }
419 return 0;
420}
421
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422static void __devinit pcibios_fixup_device_resources(struct pci_dev *dev)
423{
424 struct pci_bus_region region;
425 int i;
426 int limit = (dev->hdr_type == PCI_HEADER_TYPE_NORMAL) ? \
427 PCI_BRIDGE_RESOURCES : PCI_NUM_RESOURCES;
428
429 for (i = 0; i < limit; i++) {
430 if (!dev->resource[i].flags)
431 continue;
432 region.start = dev->resource[i].start;
433 region.end = dev->resource[i].end;
434 pcibios_bus_to_resource(dev, &dev->resource[i], &region);
Rajesh Shah71c35112005-04-28 00:25:46 -0700435 if ((is_valid_resource(dev, i)))
436 pci_claim_resource(dev, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 }
438}
439
440/*
441 * Called after each bus is probed, but before its children are examined.
442 */
443void __devinit
444pcibios_fixup_bus (struct pci_bus *b)
445{
446 struct pci_dev *dev;
447
Rajesh Shahf7d473d2005-04-28 00:25:51 -0700448 if (b->self) {
449 pci_read_bridge_bases(b);
450 pcibios_fixup_device_resources(b->self);
451 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 list_for_each_entry(dev, &b->devices, bus_list)
453 pcibios_fixup_device_resources(dev);
454
455 return;
456}
457
458void __devinit
459pcibios_update_irq (struct pci_dev *dev, int irq)
460{
461 pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
462
463 /* ??? FIXME -- record old value for shutdown. */
464}
465
466static inline int
467pcibios_enable_resources (struct pci_dev *dev, int mask)
468{
469 u16 cmd, old_cmd;
470 int idx;
471 struct resource *r;
Rajesh Shahfab3fb02005-04-28 00:25:45 -0700472 unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473
474 if (!dev)
475 return -EINVAL;
476
477 pci_read_config_word(dev, PCI_COMMAND, &cmd);
478 old_cmd = cmd;
Rajesh Shahfab3fb02005-04-28 00:25:45 -0700479 for (idx=0; idx<PCI_NUM_RESOURCES; idx++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 /* Only set up the desired resources. */
481 if (!(mask & (1 << idx)))
482 continue;
483
484 r = &dev->resource[idx];
Rajesh Shahfab3fb02005-04-28 00:25:45 -0700485 if (!(r->flags & type_mask))
486 continue;
487 if ((idx == PCI_ROM_RESOURCE) &&
488 (!(r->flags & IORESOURCE_ROM_ENABLE)))
489 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 if (!r->start && r->end) {
491 printk(KERN_ERR
492 "PCI: Device %s not available because of resource collisions\n",
493 pci_name(dev));
494 return -EINVAL;
495 }
496 if (r->flags & IORESOURCE_IO)
497 cmd |= PCI_COMMAND_IO;
498 if (r->flags & IORESOURCE_MEM)
499 cmd |= PCI_COMMAND_MEMORY;
500 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 if (cmd != old_cmd) {
502 printk("PCI: Enabling device %s (%04x -> %04x)\n", pci_name(dev), old_cmd, cmd);
503 pci_write_config_word(dev, PCI_COMMAND, cmd);
504 }
505 return 0;
506}
507
508int
509pcibios_enable_device (struct pci_dev *dev, int mask)
510{
511 int ret;
512
513 ret = pcibios_enable_resources(dev, mask);
514 if (ret < 0)
515 return ret;
516
517 return acpi_pci_irq_enable(dev);
518}
519
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520void
521pcibios_disable_device (struct pci_dev *dev)
522{
523 acpi_pci_irq_disable(dev);
524}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525
526void
527pcibios_align_resource (void *data, struct resource *res,
528 unsigned long size, unsigned long align)
529{
530}
531
532/*
533 * PCI BIOS setup, always defaults to SAL interface
534 */
535char * __init
536pcibios_setup (char *str)
537{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 return NULL;
539}
540
541int
542pci_mmap_page_range (struct pci_dev *dev, struct vm_area_struct *vma,
543 enum pci_mmap_state mmap_state, int write_combine)
544{
545 /*
546 * I/O space cannot be accessed via normal processor loads and
547 * stores on this platform.
548 */
549 if (mmap_state == pci_mmap_io)
550 /*
551 * XXX we could relax this for I/O spaces for which ACPI
552 * indicates that the space is 1-to-1 mapped. But at the
553 * moment, we don't support multiple PCI address spaces and
554 * the legacy I/O space is not 1-to-1 mapped, so this is moot.
555 */
556 return -EINVAL;
557
558 /*
559 * Leave vm_pgoff as-is, the PCI space address is the physical
560 * address on this platform.
561 */
562 vma->vm_flags |= (VM_SHM | VM_RESERVED | VM_IO);
563
564 if (write_combine && efi_range_is_wc(vma->vm_start,
565 vma->vm_end - vma->vm_start))
566 vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
567 else
568 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
569
570 if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
571 vma->vm_end - vma->vm_start, vma->vm_page_prot))
572 return -EAGAIN;
573
574 return 0;
575}
576
577/**
578 * ia64_pci_get_legacy_mem - generic legacy mem routine
579 * @bus: bus to get legacy memory base address for
580 *
581 * Find the base of legacy memory for @bus. This is typically the first
582 * megabyte of bus address space for @bus or is simply 0 on platforms whose
583 * chipsets support legacy I/O and memory routing. Returns the base address
584 * or an error pointer if an error occurred.
585 *
586 * This is the ia64 generic version of this routine. Other platforms
587 * are free to override it with a machine vector.
588 */
589char *ia64_pci_get_legacy_mem(struct pci_bus *bus)
590{
591 return (char *)__IA64_UNCACHED_OFFSET;
592}
593
594/**
595 * pci_mmap_legacy_page_range - map legacy memory space to userland
596 * @bus: bus whose legacy space we're mapping
597 * @vma: vma passed in by mmap
598 *
599 * Map legacy memory space for this device back to userspace using a machine
600 * vector to get the base address.
601 */
602int
603pci_mmap_legacy_page_range(struct pci_bus *bus, struct vm_area_struct *vma)
604{
605 char *addr;
606
607 addr = pci_get_legacy_mem(bus);
608 if (IS_ERR(addr))
609 return PTR_ERR(addr);
610
611 vma->vm_pgoff += (unsigned long)addr >> PAGE_SHIFT;
612 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
613 vma->vm_flags |= (VM_SHM | VM_RESERVED | VM_IO);
614
615 if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
616 vma->vm_end - vma->vm_start, vma->vm_page_prot))
617 return -EAGAIN;
618
619 return 0;
620}
621
622/**
623 * ia64_pci_legacy_read - read from legacy I/O space
624 * @bus: bus to read
625 * @port: legacy port value
626 * @val: caller allocated storage for returned value
627 * @size: number of bytes to read
628 *
629 * Simply reads @size bytes from @port and puts the result in @val.
630 *
631 * Again, this (and the write routine) are generic versions that can be
632 * overridden by the platform. This is necessary on platforms that don't
633 * support legacy I/O routing or that hard fail on legacy I/O timeouts.
634 */
635int ia64_pci_legacy_read(struct pci_bus *bus, u16 port, u32 *val, u8 size)
636{
637 int ret = size;
638
639 switch (size) {
640 case 1:
641 *val = inb(port);
642 break;
643 case 2:
644 *val = inw(port);
645 break;
646 case 4:
647 *val = inl(port);
648 break;
649 default:
650 ret = -EINVAL;
651 break;
652 }
653
654 return ret;
655}
656
657/**
658 * ia64_pci_legacy_write - perform a legacy I/O write
659 * @bus: bus pointer
660 * @port: port to write
661 * @val: value to write
662 * @size: number of bytes to write from @val
663 *
664 * Simply writes @size bytes of @val to @port.
665 */
666int ia64_pci_legacy_write(struct pci_dev *bus, u16 port, u32 val, u8 size)
667{
668 int ret = 0;
669
670 switch (size) {
671 case 1:
672 outb(val, port);
673 break;
674 case 2:
675 outw(val, port);
676 break;
677 case 4:
678 outl(val, port);
679 break;
680 default:
681 ret = -EINVAL;
682 break;
683 }
684
685 return ret;
686}
687
688/**
689 * pci_cacheline_size - determine cacheline size for PCI devices
690 * @dev: void
691 *
692 * We want to use the line-size of the outer-most cache. We assume
693 * that this line-size is the same for all CPUs.
694 *
695 * Code mostly taken from arch/ia64/kernel/palinfo.c:cache_info().
696 *
697 * RETURNS: An appropriate -ERRNO error value on eror, or zero for success.
698 */
699static unsigned long
700pci_cacheline_size (void)
701{
702 u64 levels, unique_caches;
703 s64 status;
704 pal_cache_config_info_t cci;
705 static u8 cacheline_size;
706
707 if (cacheline_size)
708 return cacheline_size;
709
710 status = ia64_pal_cache_summary(&levels, &unique_caches);
711 if (status != 0) {
712 printk(KERN_ERR "%s: ia64_pal_cache_summary() failed (status=%ld)\n",
713 __FUNCTION__, status);
714 return SMP_CACHE_BYTES;
715 }
716
717 status = ia64_pal_cache_config_info(levels - 1, /* cache_type (data_or_unified)= */ 2,
718 &cci);
719 if (status != 0) {
720 printk(KERN_ERR "%s: ia64_pal_cache_config_info() failed (status=%ld)\n",
721 __FUNCTION__, status);
722 return SMP_CACHE_BYTES;
723 }
724 cacheline_size = 1 << cci.pcci_line_size;
725 return cacheline_size;
726}
727
728/**
729 * pcibios_prep_mwi - helper function for drivers/pci/pci.c:pci_set_mwi()
730 * @dev: the PCI device for which MWI is enabled
731 *
732 * For ia64, we can get the cacheline sizes from PAL.
733 *
734 * RETURNS: An appropriate -ERRNO error value on eror, or zero for success.
735 */
736int
737pcibios_prep_mwi (struct pci_dev *dev)
738{
739 unsigned long desired_linesize, current_linesize;
740 int rc = 0;
741 u8 pci_linesize;
742
743 desired_linesize = pci_cacheline_size();
744
745 pci_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &pci_linesize);
746 current_linesize = 4 * pci_linesize;
747 if (desired_linesize != current_linesize) {
748 printk(KERN_WARNING "PCI: slot %s has incorrect PCI cache line size of %lu bytes,",
749 pci_name(dev), current_linesize);
750 if (current_linesize > desired_linesize) {
751 printk(" expected %lu bytes instead\n", desired_linesize);
752 rc = -EINVAL;
753 } else {
754 printk(" correcting to %lu\n", desired_linesize);
755 pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, desired_linesize / 4);
756 }
757 }
758 return rc;
759}
760
761int pci_vector_resources(int last, int nr_released)
762{
763 int count = nr_released;
764
765 count += (IA64_LAST_DEVICE_VECTOR - last);
766
767 return count;
768}