12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
25a0015d6SChris Zankel /*
3f30c2269SUwe Zeisberger * arch/xtensa/kernel/pci.c
45a0015d6SChris Zankel *
55a0015d6SChris Zankel * PCI bios-type initialisation for PCI machines
65a0015d6SChris Zankel *
75a0015d6SChris Zankel * Copyright (C) 2001-2005 Tensilica Inc.
85a0015d6SChris Zankel *
95a0015d6SChris Zankel * Based largely on work from Cort (ppc/kernel/pci.c)
105a0015d6SChris Zankel * IO functions copied from sparc.
115a0015d6SChris Zankel *
125a0015d6SChris Zankel * Chris Zankel <chris@zankel.net>
135a0015d6SChris Zankel */
145a0015d6SChris Zankel
155a0015d6SChris Zankel #include <linux/kernel.h>
165a0015d6SChris Zankel #include <linux/pci.h>
175a0015d6SChris Zankel #include <linux/delay.h>
185a0015d6SChris Zankel #include <linux/string.h>
195a0015d6SChris Zankel #include <linux/init.h>
205a0015d6SChris Zankel #include <linux/sched.h>
215a0015d6SChris Zankel #include <linux/errno.h>
2257c8a661SMike Rapoport #include <linux/memblock.h>
235a0015d6SChris Zankel
245a0015d6SChris Zankel #include <asm/pci-bridge.h>
255a0015d6SChris Zankel #include <asm/platform.h>
265a0015d6SChris Zankel
275a0015d6SChris Zankel /*
285a0015d6SChris Zankel * We need to avoid collisions with `mirrored' VGA ports
295a0015d6SChris Zankel * and other strange ISA hardware, so we always want the
305a0015d6SChris Zankel * addresses to be allocated in the 0x000-0x0ff region
315a0015d6SChris Zankel * modulo 0x400.
325a0015d6SChris Zankel *
335a0015d6SChris Zankel * Why? Because some silly external IO cards only decode
345a0015d6SChris Zankel * the low 10 bits of the IO address. The 0x00-0xff region
355a0015d6SChris Zankel * is reserved for motherboard devices that decode all 16
365a0015d6SChris Zankel * bits, so it's ok to allocate at, say, 0x2800-0x28ff,
375a0015d6SChris Zankel * but we want to try to avoid allocating at 0x2900-0x2bff
385a0015d6SChris Zankel * which might have be mirrored at 0x0100-0x03ff..
395a0015d6SChris Zankel */
40b26b2d49SDominik Brodowski resource_size_t
pcibios_align_resource(void * data,const struct resource * res,resource_size_t size,resource_size_t align)413b7a17fcSDominik Brodowski pcibios_align_resource(void *data, const struct resource *res,
423b7a17fcSDominik Brodowski resource_size_t size, resource_size_t align)
435a0015d6SChris Zankel {
445a0015d6SChris Zankel struct pci_dev *dev = data;
45e31dd6e4SGreg Kroah-Hartman resource_size_t start = res->start;
465a0015d6SChris Zankel
47b26b2d49SDominik Brodowski if (res->flags & IORESOURCE_IO) {
485a0015d6SChris Zankel if (size > 0x100) {
49fd95ee73SMax Filippov pr_err("PCI: I/O Region %s/%d too large (%u bytes)\n",
50fd95ee73SMax Filippov pci_name(dev), dev->resource - res,
51fd95ee73SMax Filippov size);
525a0015d6SChris Zankel }
535a0015d6SChris Zankel
54b26b2d49SDominik Brodowski if (start & 0x300)
555a0015d6SChris Zankel start = (start + 0x3ff) & ~0x3ff;
565a0015d6SChris Zankel }
57b26b2d49SDominik Brodowski
58b26b2d49SDominik Brodowski return start;
595a0015d6SChris Zankel }
605a0015d6SChris Zankel
pcibios_fixup_bus(struct pci_bus * bus)61fd95ee73SMax Filippov void pcibios_fixup_bus(struct pci_bus *bus)
625a0015d6SChris Zankel {
63237865f1SBjorn Helgaas if (bus->parent) {
64237865f1SBjorn Helgaas /* This is a subordinate bridge */
65237865f1SBjorn Helgaas pci_read_bridge_bases(bus);
66237865f1SBjorn Helgaas }
675a0015d6SChris Zankel }
685a0015d6SChris Zankel
695a0015d6SChris Zankel /*
7046e15a2aSDavid Woodhouse * Platform support for /proc/bus/pci/X/Y mmap()s.
715a0015d6SChris Zankel * -- paulus.
725a0015d6SChris Zankel */
735a0015d6SChris Zankel
pci_iobar_pfn(struct pci_dev * pdev,int bar,struct vm_area_struct * vma)7446e15a2aSDavid Woodhouse int pci_iobar_pfn(struct pci_dev *pdev, int bar, struct vm_area_struct *vma)
755a0015d6SChris Zankel {
7646e15a2aSDavid Woodhouse struct pci_controller *pci_ctrl = (struct pci_controller*) pdev->sysdata;
7746e15a2aSDavid Woodhouse resource_size_t ioaddr = pci_resource_start(pdev, bar);
785a0015d6SChris Zankel
79*9aa44cd2SJiapeng Chong if (!pci_ctrl)
805a0015d6SChris Zankel return -EINVAL; /* should never happen */
815a0015d6SChris Zankel
8246e15a2aSDavid Woodhouse /* Convert to an offset within this PCI controller */
8346e15a2aSDavid Woodhouse ioaddr -= (unsigned long)pci_ctrl->io_space.base;
845a0015d6SChris Zankel
8546e15a2aSDavid Woodhouse vma->vm_pgoff += (ioaddr + pci_ctrl->io_space.start) >> PAGE_SHIFT;
865a0015d6SChris Zankel return 0;
875a0015d6SChris Zankel }
88