xref: /openbmc/linux/arch/xtensa/kernel/pci.c (revision 8be98d2f2a0a262f8bf8a0bc1fdf522b3c7aab17)
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