Skip to content
Permalink
Browse files
asm-generic/io.h: Add a non-posted variant of ioremap()
ARM64 currently defaults to posted MMIO (nGnRnE), but some devices
require the use of non-posted MMIO (nGnRE). Introduce a new ioremap()
variant to handle this case. ioremap_np() is aliased to ioremap() by
default on arches that do not implement this variant.

This adds the IORESOURCE_MEM_NONPOSTED flag, which maps to this
variant and marks a given resource as requiring non-posted mappings.
This is implemented in the resource system because it is a SoC-level
requirement, so existing drivers do not need special-case code to pick
this ioremap variant.

Then this is implemented in devres by introducing devm_ioremap_np(),
and making devm_ioremap_resource() automatically select this variant
when the resource has the IORESOURCE_MEM_NONPOSTED flag set.

Signed-off-by: Hector Martin <marcan@marcan.st>
  • Loading branch information
marcan authored and intel-lab-lkp committed Feb 15, 2021
1 parent d65dc88 commit 9785be3c8ec6cb8530d72cff794f5c22414f5a3e
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 1 deletion.
@@ -942,7 +942,9 @@ static inline void *phys_to_virt(unsigned long address)
*
* ioremap_wc() and ioremap_wt() can provide more relaxed caching attributes
* for specific drivers if the architecture choses to implement them. If they
* are not implemented we fall back to plain ioremap.
* are not implemented we fall back to plain ioremap. Conversely, ioremap_np()
* can provide stricter non-posted write semantics if the architecture
* implements them.
*/
#ifndef CONFIG_MMU
#ifndef ioremap
@@ -980,6 +982,10 @@ static inline void __iomem *ioremap(phys_addr_t addr, size_t size)
#define ioremap_wt ioremap
#endif

#ifndef ioremap_np
#define ioremap_np ioremap
#endif

/*
* ioremap_uc is special in that we do require an explicit architecture
* implementation. In general you do not want to use this function in a
@@ -68,6 +68,8 @@ void __iomem *devm_ioremap_uc(struct device *dev, resource_size_t offset,
resource_size_t size);
void __iomem *devm_ioremap_wc(struct device *dev, resource_size_t offset,
resource_size_t size);
void __iomem *devm_ioremap_np(struct device *dev, resource_size_t offset,
resource_size_t size);
void devm_iounmap(struct device *dev, void __iomem *addr);
int check_signature(const volatile void __iomem *io_addr,
const unsigned char *signature, int length);
@@ -108,6 +108,7 @@ struct resource {
#define IORESOURCE_MEM_32BIT (3<<3)
#define IORESOURCE_MEM_SHADOWABLE (1<<5) /* dup: IORESOURCE_SHADOWABLE */
#define IORESOURCE_MEM_EXPANSIONROM (1<<6)
#define IORESOURCE_MEM_NONPOSTED (1<<7)

/* PnP I/O specific bits (IORESOURCE_BITS) */
#define IORESOURCE_IO_16BIT_ADDR (1<<0)
@@ -10,6 +10,7 @@ enum devm_ioremap_type {
DEVM_IOREMAP = 0,
DEVM_IOREMAP_UC,
DEVM_IOREMAP_WC,
DEVM_IOREMAP_NP,
};

void devm_ioremap_release(struct device *dev, void *res)
@@ -42,6 +43,9 @@ static void __iomem *__devm_ioremap(struct device *dev, resource_size_t offset,
case DEVM_IOREMAP_WC:
addr = ioremap_wc(offset, size);
break;
case DEVM_IOREMAP_NP:
addr = ioremap_np(offset, size);
break;
}

if (addr) {
@@ -98,6 +102,21 @@ void __iomem *devm_ioremap_wc(struct device *dev, resource_size_t offset,
}
EXPORT_SYMBOL(devm_ioremap_wc);

/**
* devm_ioremap_np - Managed ioremap_np()
* @dev: Generic device to remap IO address for
* @offset: Resource address to map
* @size: Size of map
*
* Managed ioremap_np(). Map is automatically unmapped on driver detach.
*/
void __iomem *devm_ioremap_np(struct device *dev, resource_size_t offset,
resource_size_t size)
{
return __devm_ioremap(dev, offset, size, DEVM_IOREMAP_NP);
}
EXPORT_SYMBOL(devm_ioremap_np);

/**
* devm_iounmap - Managed iounmap()
* @dev: Generic device to unmap for
@@ -128,6 +147,9 @@ __devm_ioremap_resource(struct device *dev, const struct resource *res,
return IOMEM_ERR_PTR(-EINVAL);
}

if (type == DEVM_IOREMAP && res->flags & IORESOURCE_MEM_NONPOSTED)
type = DEVM_IOREMAP_NP;

size = resource_size(res);

if (res->name)

0 comments on commit 9785be3

Please sign in to comment.