Commit 5d9cb4db authored by Linus Torvalds's avatar Linus Torvalds

Add sparse "__iomem" infrastructure to check PCI address usage

There's tons of mis-use of PCI memory-mapped IO that is used
as if it was regular memory. That fails disastrously on a number
of architectures, and it doesn't help that it just happens to
work on regular x86 boxes.

This makes makes us do much stricter type-checking. Some of it
visible to the regular compiler, but the bulk of it is for sparse.
parent 3f63a8d2
......@@ -110,9 +110,9 @@ static int remap_area_pages(unsigned long address, unsigned long phys_addr,
* have to convert them into an offset in a page-aligned mapping, but the
* caller shouldn't need to know that small detail.
*/
void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags)
void __iomem * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags)
{
void * addr;
void __iomem * addr;
struct vm_struct * area;
unsigned long offset, last_addr;
......@@ -125,7 +125,7 @@ void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flag
* Don't remap the low PCI/ISA area, it's always mapped..
*/
if (phys_addr >= 0xA0000 && last_addr < 0x100000)
return phys_to_virt(phys_addr);
return (void __iomem *) phys_to_virt(phys_addr);
/*
* Don't allow anybody to remap normal RAM that we're using..
......@@ -156,12 +156,12 @@ void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flag
if (!area)
return NULL;
area->phys_addr = phys_addr;
addr = area->addr;
addr = (void __iomem *) area->addr;
if (remap_area_pages((unsigned long) addr, phys_addr, size, flags)) {
vunmap(addr);
vunmap((void __force *) addr);
return NULL;
}
return (void *) (offset + (char *)addr);
return (void __iomem *) (offset + (char __iomem *)addr);
}
......@@ -187,10 +187,10 @@ void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flag
* Must be freed with iounmap.
*/
void *ioremap_nocache (unsigned long phys_addr, unsigned long size)
void __iomem *ioremap_nocache (unsigned long phys_addr, unsigned long size)
{
unsigned long last_addr;
void *p = __ioremap(phys_addr, size, _PAGE_PCD);
void __iomem *p = __ioremap(phys_addr, size, _PAGE_PCD);
if (!p)
return p;
......@@ -221,12 +221,12 @@ void *ioremap_nocache (unsigned long phys_addr, unsigned long size)
return p;
}
void iounmap(void *addr)
void iounmap(volatile void __iomem *addr)
{
struct vm_struct *p;
if (addr <= high_memory)
if ((void __force *) addr <= high_memory)
return;
p = remove_vm_area((void *) (PAGE_MASK & (unsigned long) addr));
p = remove_vm_area((void *) (PAGE_MASK & (unsigned long __force) addr));
if (!p) {
printk("__iounmap: bad address %p\n", addr);
return;
......
......@@ -2,6 +2,8 @@
#define _ASM_IO_H
#include <linux/config.h>
#include <linux/string.h>
#include <linux/compiler.h>
/*
* This file contains the definitions for the x86 IO instructions
......@@ -86,7 +88,7 @@ static inline void * phys_to_virt(unsigned long address)
*/
#define page_to_phys(page) ((dma_addr_t)page_to_pfn(page) << PAGE_SHIFT)
extern void * __ioremap(unsigned long offset, unsigned long size, unsigned long flags);
extern void __iomem * __ioremap(unsigned long offset, unsigned long size, unsigned long flags);
/**
* ioremap - map bus memory into CPU space
......@@ -100,13 +102,13 @@ extern void * __ioremap(unsigned long offset, unsigned long size, unsigned long
* address.
*/
static inline void * ioremap (unsigned long offset, unsigned long size)
static inline void __iomem * ioremap(unsigned long offset, unsigned long size)
{
return __ioremap(offset, size, 0);
}
extern void * ioremap_nocache (unsigned long offset, unsigned long size);
extern void iounmap(void *addr);
extern void __iomem * ioremap_nocache(unsigned long offset, unsigned long size);
extern void iounmap(volatile void __iomem *addr);
/*
* bt_ioremap() and bt_iounmap() are for temporary early boot-time
......@@ -139,9 +141,18 @@ extern void bt_iounmap(void *addr, unsigned long size);
* memory location directly.
*/
#define readb(addr) (*(volatile unsigned char *) (addr))
#define readw(addr) (*(volatile unsigned short *) (addr))
#define readl(addr) (*(volatile unsigned int *) (addr))
static inline unsigned char readb(const volatile void __iomem *addr)
{
return *(volatile unsigned char __force *) addr;
}
static inline unsigned short readw(const volatile void __iomem *addr)
{
return *(volatile unsigned short __force *) addr;
}
static inline unsigned int readl(const volatile void __iomem *addr)
{
return *(volatile unsigned int __force *) addr;
}
#define readb_relaxed(addr) readb(addr)
#define readw_relaxed(addr) readw(addr)
#define readl_relaxed(addr) readl(addr)
......@@ -149,16 +160,34 @@ extern void bt_iounmap(void *addr, unsigned long size);
#define __raw_readw readw
#define __raw_readl readl
#define writeb(b,addr) (*(volatile unsigned char *) (addr) = (b))
#define writew(b,addr) (*(volatile unsigned short *) (addr) = (b))
#define writel(b,addr) (*(volatile unsigned int *) (addr) = (b))
static inline void writeb(unsigned char b, volatile void __iomem *addr)
{
*(volatile unsigned char __force *) addr = b;
}
static inline void writew(unsigned short b, volatile void __iomem *addr)
{
*(volatile unsigned short __force *) addr = b;
}
static inline void writel(unsigned int b, volatile void __iomem *addr)
{
*(volatile unsigned int __force *) addr = b;
}
#define __raw_writeb writeb
#define __raw_writew writew
#define __raw_writel writel
#define memset_io(a,b,c) memset((void *)(a),(b),(c))
#define memcpy_fromio(a,b,c) __memcpy((a),(void *)(b),(c))
#define memcpy_toio(a,b,c) __memcpy((void *)(a),(b),(c))
static inline void memset_io(volatile void __iomem *addr, unsigned char val, int count)
{
memset((void __force *) addr, val, count);
}
static inline void memcpy_fromio(void *dst, volatile void __iomem *src, int count)
{
__memcpy(dst, (void __force *) src, count);
}
static inline void memcpy_toio(volatile void __iomem *dst, void *src, int count)
{
__memcpy((void __force *) dst, src, count);
}
/*
* ISA space is 'always mapped' on a typical x86 system, no need to
......@@ -168,7 +197,7 @@ extern void bt_iounmap(void *addr, unsigned long size);
* used as the IO-area pointer (it can be iounmapped as well, so the
* analogy with PCI is quite large):
*/
#define __ISA_IO_base ((char *)(PAGE_OFFSET))
#define __ISA_IO_base ((char __iomem *)(PAGE_OFFSET))
#define isa_readb(a) readb(__ISA_IO_base + (a))
#define isa_readw(a) readw(__ISA_IO_base + (a))
......@@ -185,8 +214,8 @@ extern void bt_iounmap(void *addr, unsigned long size);
* Again, i386 does not require mem IO specific function.
*/
#define eth_io_copy_and_sum(a,b,c,d) eth_copy_and_sum((a),(void *)(b),(c),(d))
#define isa_eth_io_copy_and_sum(a,b,c,d) eth_copy_and_sum((a),(void *)(__ISA_IO_base + (b)),(c),(d))
#define eth_io_copy_and_sum(a,b,c,d) eth_copy_and_sum((a),(void __force *)(b),(c),(d))
#define isa_eth_io_copy_and_sum(a,b,c,d) eth_copy_and_sum((a),(void __force *)(__ISA_IO_base + (b)),(c),(d))
/**
* check_signature - find BIOS signatures
......@@ -199,7 +228,7 @@ extern void bt_iounmap(void *addr, unsigned long size);
* Returns 1 on a match.
*/
static inline int check_signature(unsigned long io_addr,
static inline int check_signature(volatile void __iomem * io_addr,
const unsigned char *signature, int length)
{
int retval = 0;
......
......@@ -6,13 +6,17 @@
# define __kernel /* default address space */
# define __safe __attribute__((safe))
# define __force __attribute__((force))
# define __iomem __attribute__((noderef, address_space(2)))
extern void __chk_user_ptr(void __user *);
extern void __chk_io_ptr(void __iomem *);
#else
# define __user
# define __kernel
# define __safe
# define __force
# define __iomem
# define __chk_user_ptr(x) (void)0
# define __chk_io_ptr(x) (void)0
#endif
#ifdef __KERNEL__
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment