mirror of
https://github.com/torvalds/linux.git
synced 2026-03-07 23:04:33 +01:00
This was done entirely with mindless brute force, using
git grep -l '\<k[vmz]*alloc_objs*(.*, GFP_KERNEL)' |
xargs sed -i 's/\(alloc_objs*(.*\), GFP_KERNEL)/\1)/'
to convert the new alloc_obj() users that had a simple GFP_KERNEL
argument to just drop that argument.
Note that due to the extreme simplicity of the scripting, any slightly
more complex cases spread over multiple lines would not be triggered:
they definitely exist, but this covers the vast bulk of the cases, and
the resulting diff is also then easier to check automatically.
For the same reason the 'flex' versions will be done as a separate
conversion.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
321 lines
7.2 KiB
C
321 lines
7.2 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (C) 2021 Intel Corporation
|
|
* Author: Johannes Berg <johannes@sipsolutions.net>
|
|
*/
|
|
#include <linux/types.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/logic_iomem.h>
|
|
#include <asm/io.h>
|
|
|
|
struct logic_iomem_region {
|
|
const struct resource *res;
|
|
const struct logic_iomem_region_ops *ops;
|
|
struct list_head list;
|
|
};
|
|
|
|
struct logic_iomem_area {
|
|
const struct logic_iomem_ops *ops;
|
|
void *priv;
|
|
};
|
|
|
|
#define AREA_SHIFT 24
|
|
#define MAX_AREA_SIZE (1 << AREA_SHIFT)
|
|
#define MAX_AREAS ((1U << 31) / MAX_AREA_SIZE)
|
|
#define AREA_BITS ((MAX_AREAS - 1) << AREA_SHIFT)
|
|
#define AREA_MASK (MAX_AREA_SIZE - 1)
|
|
#ifdef CONFIG_64BIT
|
|
#define IOREMAP_BIAS 0xDEAD000000000000UL
|
|
#define IOREMAP_MASK 0xFFFFFFFF00000000UL
|
|
#else
|
|
#define IOREMAP_BIAS 0x80000000UL
|
|
#define IOREMAP_MASK 0x80000000UL
|
|
#endif
|
|
|
|
static DEFINE_MUTEX(regions_mtx);
|
|
static LIST_HEAD(regions_list);
|
|
static struct logic_iomem_area mapped_areas[MAX_AREAS];
|
|
|
|
int logic_iomem_add_region(struct resource *resource,
|
|
const struct logic_iomem_region_ops *ops)
|
|
{
|
|
struct logic_iomem_region *rreg;
|
|
int err;
|
|
|
|
if (WARN_ON(!resource || !ops))
|
|
return -EINVAL;
|
|
|
|
if (WARN_ON((resource->flags & IORESOURCE_TYPE_BITS) != IORESOURCE_MEM))
|
|
return -EINVAL;
|
|
|
|
rreg = kzalloc_obj(*rreg);
|
|
if (!rreg)
|
|
return -ENOMEM;
|
|
|
|
err = request_resource(&iomem_resource, resource);
|
|
if (err) {
|
|
kfree(rreg);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
mutex_lock(®ions_mtx);
|
|
rreg->res = resource;
|
|
rreg->ops = ops;
|
|
list_add_tail(&rreg->list, ®ions_list);
|
|
mutex_unlock(®ions_mtx);
|
|
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL(logic_iomem_add_region);
|
|
|
|
#ifndef CONFIG_INDIRECT_IOMEM_FALLBACK
|
|
static void __iomem *real_ioremap(phys_addr_t offset, size_t size)
|
|
{
|
|
WARN(1, "invalid ioremap(0x%llx, 0x%zx)\n",
|
|
(unsigned long long)offset, size);
|
|
return NULL;
|
|
}
|
|
|
|
static void real_iounmap(volatile void __iomem *addr)
|
|
{
|
|
WARN(1, "invalid iounmap for addr 0x%llx\n",
|
|
(unsigned long long)(uintptr_t __force)addr);
|
|
}
|
|
#endif /* CONFIG_INDIRECT_IOMEM_FALLBACK */
|
|
|
|
void __iomem *ioremap(phys_addr_t offset, size_t size)
|
|
{
|
|
void __iomem *ret = NULL;
|
|
struct logic_iomem_region *rreg, *found = NULL;
|
|
int i;
|
|
|
|
mutex_lock(®ions_mtx);
|
|
list_for_each_entry(rreg, ®ions_list, list) {
|
|
if (rreg->res->start > offset)
|
|
continue;
|
|
if (rreg->res->end < offset + size - 1)
|
|
continue;
|
|
found = rreg;
|
|
break;
|
|
}
|
|
|
|
if (!found)
|
|
goto out;
|
|
|
|
for (i = 0; i < MAX_AREAS; i++) {
|
|
long offs;
|
|
|
|
if (mapped_areas[i].ops)
|
|
continue;
|
|
|
|
offs = rreg->ops->map(offset - found->res->start,
|
|
size, &mapped_areas[i].ops,
|
|
&mapped_areas[i].priv);
|
|
if (offs < 0) {
|
|
mapped_areas[i].ops = NULL;
|
|
break;
|
|
}
|
|
|
|
if (WARN_ON(!mapped_areas[i].ops)) {
|
|
mapped_areas[i].ops = NULL;
|
|
break;
|
|
}
|
|
|
|
ret = (void __iomem *)(IOREMAP_BIAS + (i << AREA_SHIFT) + offs);
|
|
break;
|
|
}
|
|
out:
|
|
mutex_unlock(®ions_mtx);
|
|
if (ret)
|
|
return ret;
|
|
return real_ioremap(offset, size);
|
|
}
|
|
EXPORT_SYMBOL(ioremap);
|
|
|
|
static inline struct logic_iomem_area *
|
|
get_area(const volatile void __iomem *addr)
|
|
{
|
|
unsigned long a = (unsigned long)addr;
|
|
unsigned int idx;
|
|
|
|
if (WARN_ON((a & IOREMAP_MASK) != IOREMAP_BIAS))
|
|
return NULL;
|
|
|
|
idx = (a & AREA_BITS) >> AREA_SHIFT;
|
|
|
|
if (mapped_areas[idx].ops)
|
|
return &mapped_areas[idx];
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void iounmap(volatile void __iomem *addr)
|
|
{
|
|
struct logic_iomem_area *area = get_area(addr);
|
|
|
|
if (!area) {
|
|
real_iounmap(addr);
|
|
return;
|
|
}
|
|
|
|
if (area->ops->unmap)
|
|
area->ops->unmap(area->priv);
|
|
|
|
mutex_lock(®ions_mtx);
|
|
area->ops = NULL;
|
|
area->priv = NULL;
|
|
mutex_unlock(®ions_mtx);
|
|
}
|
|
EXPORT_SYMBOL(iounmap);
|
|
|
|
#ifndef CONFIG_INDIRECT_IOMEM_FALLBACK
|
|
#define MAKE_FALLBACK(op, sz) \
|
|
static u##sz real_raw_read ## op(const volatile void __iomem *addr) \
|
|
{ \
|
|
WARN(1, "Invalid read" #op " at address %llx\n", \
|
|
(unsigned long long)(uintptr_t __force)addr); \
|
|
return (u ## sz)~0ULL; \
|
|
} \
|
|
\
|
|
static void real_raw_write ## op(u ## sz val, \
|
|
volatile void __iomem *addr) \
|
|
{ \
|
|
WARN(1, "Invalid writeq" #op " of 0x%llx at address %llx\n", \
|
|
(unsigned long long)val, \
|
|
(unsigned long long)(uintptr_t __force)addr);\
|
|
} \
|
|
|
|
MAKE_FALLBACK(b, 8);
|
|
MAKE_FALLBACK(w, 16);
|
|
MAKE_FALLBACK(l, 32);
|
|
#ifdef CONFIG_64BIT
|
|
MAKE_FALLBACK(q, 64);
|
|
#endif
|
|
|
|
static void real_memset_io(volatile void __iomem *addr, int value, size_t size)
|
|
{
|
|
WARN(1, "Invalid memset_io at address 0x%llx\n",
|
|
(unsigned long long)(uintptr_t __force)addr);
|
|
}
|
|
|
|
static void real_memcpy_fromio(void *buffer, const volatile void __iomem *addr,
|
|
size_t size)
|
|
{
|
|
WARN(1, "Invalid memcpy_fromio at address 0x%llx\n",
|
|
(unsigned long long)(uintptr_t __force)addr);
|
|
|
|
memset(buffer, 0xff, size);
|
|
}
|
|
|
|
static void real_memcpy_toio(volatile void __iomem *addr, const void *buffer,
|
|
size_t size)
|
|
{
|
|
WARN(1, "Invalid memcpy_toio at address 0x%llx\n",
|
|
(unsigned long long)(uintptr_t __force)addr);
|
|
}
|
|
#endif /* CONFIG_INDIRECT_IOMEM_FALLBACK */
|
|
|
|
#define MAKE_OP(op, sz) \
|
|
u##sz __raw_read ## op(const volatile void __iomem *addr) \
|
|
{ \
|
|
struct logic_iomem_area *area = get_area(addr); \
|
|
\
|
|
if (!area) \
|
|
return real_raw_read ## op(addr); \
|
|
\
|
|
return (u ## sz) area->ops->read(area->priv, \
|
|
(unsigned long)addr & AREA_MASK,\
|
|
sz / 8); \
|
|
} \
|
|
EXPORT_SYMBOL(__raw_read ## op); \
|
|
\
|
|
void __raw_write ## op(u ## sz val, volatile void __iomem *addr) \
|
|
{ \
|
|
struct logic_iomem_area *area = get_area(addr); \
|
|
\
|
|
if (!area) { \
|
|
real_raw_write ## op(val, addr); \
|
|
return; \
|
|
} \
|
|
\
|
|
area->ops->write(area->priv, \
|
|
(unsigned long)addr & AREA_MASK, \
|
|
sz / 8, val); \
|
|
} \
|
|
EXPORT_SYMBOL(__raw_write ## op)
|
|
|
|
MAKE_OP(b, 8);
|
|
MAKE_OP(w, 16);
|
|
MAKE_OP(l, 32);
|
|
#ifdef CONFIG_64BIT
|
|
MAKE_OP(q, 64);
|
|
#endif
|
|
|
|
void memset_io(volatile void __iomem *addr, int value, size_t size)
|
|
{
|
|
struct logic_iomem_area *area = get_area(addr);
|
|
unsigned long offs, start;
|
|
|
|
if (!area) {
|
|
real_memset_io(addr, value, size);
|
|
return;
|
|
}
|
|
|
|
start = (unsigned long)addr & AREA_MASK;
|
|
|
|
if (area->ops->set) {
|
|
area->ops->set(area->priv, start, value, size);
|
|
return;
|
|
}
|
|
|
|
for (offs = 0; offs < size; offs++)
|
|
area->ops->write(area->priv, start + offs, 1, value);
|
|
}
|
|
EXPORT_SYMBOL(memset_io);
|
|
|
|
void memcpy_fromio(void *buffer, const volatile void __iomem *addr,
|
|
size_t size)
|
|
{
|
|
struct logic_iomem_area *area = get_area(addr);
|
|
u8 *buf = buffer;
|
|
unsigned long offs, start;
|
|
|
|
if (!area) {
|
|
real_memcpy_fromio(buffer, addr, size);
|
|
return;
|
|
}
|
|
|
|
start = (unsigned long)addr & AREA_MASK;
|
|
|
|
if (area->ops->copy_from) {
|
|
area->ops->copy_from(area->priv, buffer, start, size);
|
|
return;
|
|
}
|
|
|
|
for (offs = 0; offs < size; offs++)
|
|
buf[offs] = area->ops->read(area->priv, start + offs, 1);
|
|
}
|
|
EXPORT_SYMBOL(memcpy_fromio);
|
|
|
|
void memcpy_toio(volatile void __iomem *addr, const void *buffer, size_t size)
|
|
{
|
|
struct logic_iomem_area *area = get_area(addr);
|
|
const u8 *buf = buffer;
|
|
unsigned long offs, start;
|
|
|
|
if (!area) {
|
|
real_memcpy_toio(addr, buffer, size);
|
|
return;
|
|
}
|
|
|
|
start = (unsigned long)addr & AREA_MASK;
|
|
|
|
if (area->ops->copy_to) {
|
|
area->ops->copy_to(area->priv, start, buffer, size);
|
|
return;
|
|
}
|
|
|
|
for (offs = 0; offs < size; offs++)
|
|
area->ops->write(area->priv, start + offs, 1, buf[offs]);
|
|
}
|
|
EXPORT_SYMBOL(memcpy_toio);
|