162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Implement the default iomap interfaces
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * (C) Copyright 2004 Linus Torvalds
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci#include <linux/pci.h>
862306a36Sopenharmony_ci#include <linux/io.h>
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/export.h>
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#ifdef CONFIG_PCI
1362306a36Sopenharmony_ci/**
1462306a36Sopenharmony_ci * pci_iomap_range - create a virtual mapping cookie for a PCI BAR
1562306a36Sopenharmony_ci * @dev: PCI device that owns the BAR
1662306a36Sopenharmony_ci * @bar: BAR number
1762306a36Sopenharmony_ci * @offset: map memory at the given offset in BAR
1862306a36Sopenharmony_ci * @maxlen: max length of the memory to map
1962306a36Sopenharmony_ci *
2062306a36Sopenharmony_ci * Using this function you will get a __iomem address to your device BAR.
2162306a36Sopenharmony_ci * You can access it using ioread*() and iowrite*(). These functions hide
2262306a36Sopenharmony_ci * the details if this is a MMIO or PIO address space and will just do what
2362306a36Sopenharmony_ci * you expect from them in the correct way.
2462306a36Sopenharmony_ci *
2562306a36Sopenharmony_ci * @maxlen specifies the maximum length to map. If you want to get access to
2662306a36Sopenharmony_ci * the complete BAR from offset to the end, pass %0 here.
2762306a36Sopenharmony_ci * */
2862306a36Sopenharmony_civoid __iomem *pci_iomap_range(struct pci_dev *dev,
2962306a36Sopenharmony_ci			      int bar,
3062306a36Sopenharmony_ci			      unsigned long offset,
3162306a36Sopenharmony_ci			      unsigned long maxlen)
3262306a36Sopenharmony_ci{
3362306a36Sopenharmony_ci	resource_size_t start = pci_resource_start(dev, bar);
3462306a36Sopenharmony_ci	resource_size_t len = pci_resource_len(dev, bar);
3562306a36Sopenharmony_ci	unsigned long flags = pci_resource_flags(dev, bar);
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci	if (len <= offset || !start)
3862306a36Sopenharmony_ci		return NULL;
3962306a36Sopenharmony_ci	len -= offset;
4062306a36Sopenharmony_ci	start += offset;
4162306a36Sopenharmony_ci	if (maxlen && len > maxlen)
4262306a36Sopenharmony_ci		len = maxlen;
4362306a36Sopenharmony_ci	if (flags & IORESOURCE_IO)
4462306a36Sopenharmony_ci		return __pci_ioport_map(dev, start, len);
4562306a36Sopenharmony_ci	if (flags & IORESOURCE_MEM)
4662306a36Sopenharmony_ci		return ioremap(start, len);
4762306a36Sopenharmony_ci	/* What? */
4862306a36Sopenharmony_ci	return NULL;
4962306a36Sopenharmony_ci}
5062306a36Sopenharmony_ciEXPORT_SYMBOL(pci_iomap_range);
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci/**
5362306a36Sopenharmony_ci * pci_iomap_wc_range - create a virtual WC mapping cookie for a PCI BAR
5462306a36Sopenharmony_ci * @dev: PCI device that owns the BAR
5562306a36Sopenharmony_ci * @bar: BAR number
5662306a36Sopenharmony_ci * @offset: map memory at the given offset in BAR
5762306a36Sopenharmony_ci * @maxlen: max length of the memory to map
5862306a36Sopenharmony_ci *
5962306a36Sopenharmony_ci * Using this function you will get a __iomem address to your device BAR.
6062306a36Sopenharmony_ci * You can access it using ioread*() and iowrite*(). These functions hide
6162306a36Sopenharmony_ci * the details if this is a MMIO or PIO address space and will just do what
6262306a36Sopenharmony_ci * you expect from them in the correct way. When possible write combining
6362306a36Sopenharmony_ci * is used.
6462306a36Sopenharmony_ci *
6562306a36Sopenharmony_ci * @maxlen specifies the maximum length to map. If you want to get access to
6662306a36Sopenharmony_ci * the complete BAR from offset to the end, pass %0 here.
6762306a36Sopenharmony_ci * */
6862306a36Sopenharmony_civoid __iomem *pci_iomap_wc_range(struct pci_dev *dev,
6962306a36Sopenharmony_ci				 int bar,
7062306a36Sopenharmony_ci				 unsigned long offset,
7162306a36Sopenharmony_ci				 unsigned long maxlen)
7262306a36Sopenharmony_ci{
7362306a36Sopenharmony_ci	resource_size_t start = pci_resource_start(dev, bar);
7462306a36Sopenharmony_ci	resource_size_t len = pci_resource_len(dev, bar);
7562306a36Sopenharmony_ci	unsigned long flags = pci_resource_flags(dev, bar);
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	if (flags & IORESOURCE_IO)
7962306a36Sopenharmony_ci		return NULL;
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	if (len <= offset || !start)
8262306a36Sopenharmony_ci		return NULL;
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	len -= offset;
8562306a36Sopenharmony_ci	start += offset;
8662306a36Sopenharmony_ci	if (maxlen && len > maxlen)
8762306a36Sopenharmony_ci		len = maxlen;
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	if (flags & IORESOURCE_MEM)
9062306a36Sopenharmony_ci		return ioremap_wc(start, len);
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	/* What? */
9362306a36Sopenharmony_ci	return NULL;
9462306a36Sopenharmony_ci}
9562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_iomap_wc_range);
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci/**
9862306a36Sopenharmony_ci * pci_iomap - create a virtual mapping cookie for a PCI BAR
9962306a36Sopenharmony_ci * @dev: PCI device that owns the BAR
10062306a36Sopenharmony_ci * @bar: BAR number
10162306a36Sopenharmony_ci * @maxlen: length of the memory to map
10262306a36Sopenharmony_ci *
10362306a36Sopenharmony_ci * Using this function you will get a __iomem address to your device BAR.
10462306a36Sopenharmony_ci * You can access it using ioread*() and iowrite*(). These functions hide
10562306a36Sopenharmony_ci * the details if this is a MMIO or PIO address space and will just do what
10662306a36Sopenharmony_ci * you expect from them in the correct way.
10762306a36Sopenharmony_ci *
10862306a36Sopenharmony_ci * @maxlen specifies the maximum length to map. If you want to get access to
10962306a36Sopenharmony_ci * the complete BAR without checking for its length first, pass %0 here.
11062306a36Sopenharmony_ci * */
11162306a36Sopenharmony_civoid __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
11262306a36Sopenharmony_ci{
11362306a36Sopenharmony_ci	return pci_iomap_range(dev, bar, 0, maxlen);
11462306a36Sopenharmony_ci}
11562306a36Sopenharmony_ciEXPORT_SYMBOL(pci_iomap);
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci/**
11862306a36Sopenharmony_ci * pci_iomap_wc - create a virtual WC mapping cookie for a PCI BAR
11962306a36Sopenharmony_ci * @dev: PCI device that owns the BAR
12062306a36Sopenharmony_ci * @bar: BAR number
12162306a36Sopenharmony_ci * @maxlen: length of the memory to map
12262306a36Sopenharmony_ci *
12362306a36Sopenharmony_ci * Using this function you will get a __iomem address to your device BAR.
12462306a36Sopenharmony_ci * You can access it using ioread*() and iowrite*(). These functions hide
12562306a36Sopenharmony_ci * the details if this is a MMIO or PIO address space and will just do what
12662306a36Sopenharmony_ci * you expect from them in the correct way. When possible write combining
12762306a36Sopenharmony_ci * is used.
12862306a36Sopenharmony_ci *
12962306a36Sopenharmony_ci * @maxlen specifies the maximum length to map. If you want to get access to
13062306a36Sopenharmony_ci * the complete BAR without checking for its length first, pass %0 here.
13162306a36Sopenharmony_ci * */
13262306a36Sopenharmony_civoid __iomem *pci_iomap_wc(struct pci_dev *dev, int bar, unsigned long maxlen)
13362306a36Sopenharmony_ci{
13462306a36Sopenharmony_ci	return pci_iomap_wc_range(dev, bar, 0, maxlen);
13562306a36Sopenharmony_ci}
13662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_iomap_wc);
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci/*
13962306a36Sopenharmony_ci * pci_iounmap() somewhat illogically comes from lib/iomap.c for the
14062306a36Sopenharmony_ci * CONFIG_GENERIC_IOMAP case, because that's the code that knows about
14162306a36Sopenharmony_ci * the different IOMAP ranges.
14262306a36Sopenharmony_ci *
14362306a36Sopenharmony_ci * But if the architecture does not use the generic iomap code, and if
14462306a36Sopenharmony_ci * it has _not_ defined it's own private pci_iounmap function, we define
14562306a36Sopenharmony_ci * it here.
14662306a36Sopenharmony_ci *
14762306a36Sopenharmony_ci * NOTE! This default implementation assumes that if the architecture
14862306a36Sopenharmony_ci * support ioport mapping (HAS_IOPORT_MAP), the ioport mapping will
14962306a36Sopenharmony_ci * be fixed to the range [ PCI_IOBASE, PCI_IOBASE+IO_SPACE_LIMIT [,
15062306a36Sopenharmony_ci * and does not need unmapping with 'ioport_unmap()'.
15162306a36Sopenharmony_ci *
15262306a36Sopenharmony_ci * If you have different rules for your architecture, you need to
15362306a36Sopenharmony_ci * implement your own pci_iounmap() that knows the rules for where
15462306a36Sopenharmony_ci * and how IO vs MEM get mapped.
15562306a36Sopenharmony_ci *
15662306a36Sopenharmony_ci * This code is odd, and the ARCH_HAS/ARCH_WANTS #define logic comes
15762306a36Sopenharmony_ci * from legacy <asm-generic/io.h> header file behavior. In particular,
15862306a36Sopenharmony_ci * it would seem to make sense to do the iounmap(p) for the non-IO-space
15962306a36Sopenharmony_ci * case here regardless, but that's not what the old header file code
16062306a36Sopenharmony_ci * did. Probably incorrectly, but this is meant to be bug-for-bug
16162306a36Sopenharmony_ci * compatible.
16262306a36Sopenharmony_ci */
16362306a36Sopenharmony_ci#if defined(ARCH_WANTS_GENERIC_PCI_IOUNMAP)
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_civoid pci_iounmap(struct pci_dev *dev, void __iomem *p)
16662306a36Sopenharmony_ci{
16762306a36Sopenharmony_ci#ifdef ARCH_HAS_GENERIC_IOPORT_MAP
16862306a36Sopenharmony_ci	uintptr_t start = (uintptr_t) PCI_IOBASE;
16962306a36Sopenharmony_ci	uintptr_t addr = (uintptr_t) p;
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	if (addr >= start && addr < start + IO_SPACE_LIMIT)
17262306a36Sopenharmony_ci		return;
17362306a36Sopenharmony_ci#endif
17462306a36Sopenharmony_ci	iounmap(p);
17562306a36Sopenharmony_ci}
17662306a36Sopenharmony_ciEXPORT_SYMBOL(pci_iounmap);
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci#endif /* ARCH_WANTS_GENERIC_PCI_IOUNMAP */
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci#endif /* CONFIG_PCI */
181