sh: Integrate the SH-5 onchip_remap() more coherently.

Presently this is special-cased for early initialization. While there are
situations where these static early initializations are still necessary,
with minor changes it is possible to use this for the regular ioremap
implementation as well. This allows us to kill off the special-casing for
the remap completely and to start tidying up all of the SH-5
special-casing in drivers.

Signed-off-by: Paul Mundt <lethal@linux-sh.org>
This commit is contained in:
Paul Mundt 2009-05-07 18:10:27 +09:00
parent ae318a148e
commit 0fb849b9d7
12 changed files with 150 additions and 191 deletions

View File

@ -161,7 +161,7 @@ void init_cayman_irq(void)
{ {
int i; int i;
epld_virt = onchip_remap(EPLD_BASE, 1024, "EPLD"); epld_virt = (unsigned long)ioremap_nocache(EPLD_BASE, 1024);
if (!epld_virt) { if (!epld_virt) {
printk(KERN_ERR "Cayman IRQ: Unable to remap EPLD\n"); printk(KERN_ERR "Cayman IRQ: Unable to remap EPLD\n");
return; return;

View File

@ -102,7 +102,7 @@ static int __init smsc_superio_setup(void)
{ {
unsigned char devid, devrev; unsigned char devid, devrev;
smsc_superio_virt = onchip_remap(SMSC_SUPERIO_BASE, 1024, "SMSC SuperIO"); smsc_superio_virt = (unsigned long)ioremap_nocache(SMSC_SUPERIO_BASE, 1024);
if (!smsc_superio_virt) { if (!smsc_superio_virt) {
panic("Unable to remap SMSC SuperIO\n"); panic("Unable to remap SMSC SuperIO\n");
} }

View File

@ -119,12 +119,12 @@ static int __init sh5pci_init(void)
return -EINVAL; return -EINVAL;
} }
pcicr_virt = onchip_remap(SH5PCI_ICR_BASE, 1024, "PCICR"); pcicr_virt = (unsigned long)ioremap_nocache(SH5PCI_ICR_BASE, 1024);
if (!pcicr_virt) { if (!pcicr_virt) {
panic("Unable to remap PCICR\n"); panic("Unable to remap PCICR\n");
} }
PCI_IO_AREA = onchip_remap(SH5PCI_IO_BASE, 0x10000, "PCIIO"); PCI_IO_AREA = (unsigned long)ioremap_nocache(SH5PCI_IO_BASE, 0x10000);
if (!PCI_IO_AREA) { if (!PCI_IO_AREA) {
panic("Unable to remap PCIIO\n"); panic("Unable to remap PCIIO\n");
} }

View File

@ -224,11 +224,6 @@ void __iomem *__ioremap(unsigned long offset, unsigned long size,
unsigned long flags); unsigned long flags);
void __iounmap(void __iomem *addr); void __iounmap(void __iomem *addr);
/* arch/sh/mm/ioremap_64.c */
unsigned long onchip_remap(unsigned long addr, unsigned long size,
const char *name);
extern void onchip_unmap(unsigned long vaddr);
static inline void __iomem * static inline void __iomem *
__ioremap_mode(unsigned long offset, unsigned long size, unsigned long flags) __ioremap_mode(unsigned long offset, unsigned long size, unsigned long flags)
{ {
@ -263,8 +258,6 @@ __ioremap_mode(unsigned long offset, unsigned long size, unsigned long flags)
return __ioremap(offset, size, flags); return __ioremap(offset, size, flags);
} }
#else #else
#define onchip_remap(addr, size, name) (addr)
#define onchip_unmap(addr) do { } while (0)
#define __ioremap_mode(offset, size, flags) ((void __iomem *)(offset)) #define __ioremap_mode(offset, size, flags) ((void __iomem *)(offset))
#define __iounmap(addr) do { } while (0) #define __iounmap(addr) do { } while (0)
#endif /* CONFIG_MMU */ #endif /* CONFIG_MMU */

View File

@ -188,7 +188,7 @@ void __init plat_irq_setup(void)
unsigned long reg; unsigned long reg;
int i; int i;
intc_virt = onchip_remap(INTC_BASE, 1024, "INTC"); intc_virt = (unsigned long)ioremap_nocache(INTC_BASE, 1024);
if (!intc_virt) { if (!intc_virt) {
panic("Unable to remap INTC\n"); panic("Unable to remap INTC\n");
} }

View File

@ -6,6 +6,9 @@ obj-y := entry.o probe.o switchto.o
obj-$(CONFIG_SH_FPU) += fpu.o obj-$(CONFIG_SH_FPU) += fpu.o
obj-$(CONFIG_KALLSYMS) += unwind.o obj-$(CONFIG_KALLSYMS) += unwind.o
# CPU subtype setup
obj-$(CONFIG_CPU_SH5) += setup-sh5.o
# Primary on-chip clocks (common) # Primary on-chip clocks (common)
clock-$(CONFIG_CPU_SH5) := clock-sh5.o clock-$(CONFIG_CPU_SH5) := clock-sh5.o

View File

@ -71,7 +71,7 @@ static struct clk_ops *sh5_clk_ops[] = {
void __init arch_init_clk_ops(struct clk_ops **ops, int idx) void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
{ {
cprc_base = onchip_remap(CPRC_BASE, 1024, "CPRC"); cprc_base = (unsigned long)ioremap_nocache(CPRC_BASE, 1024);
BUG_ON(!cprc_base); BUG_ON(!cprc_base);
if (idx < ARRAY_SIZE(sh5_clk_ops)) if (idx < ARRAY_SIZE(sh5_clk_ops))

View File

@ -1410,8 +1410,8 @@ peek_real_address_q:
r2(out) : result quadword r2(out) : result quadword
This is provided as a cheapskate way of manipulating device This is provided as a cheapskate way of manipulating device
registers for debugging (to avoid the need to onchip_remap the debug registers for debugging (to avoid the need to ioremap the debug
module, and to avoid the need to onchip_remap the watchpoint module, and to avoid the need to ioremap the watchpoint
controller in a way that identity maps sufficient bits to avoid the controller in a way that identity maps sufficient bits to avoid the
SH5-101 cut2 silicon defect). SH5-101 cut2 silicon defect).
@ -1459,8 +1459,8 @@ poke_real_address_q:
r3 : quadword value to write. r3 : quadword value to write.
This is provided as a cheapskate way of manipulating device This is provided as a cheapskate way of manipulating device
registers for debugging (to avoid the need to onchip_remap the debug registers for debugging (to avoid the need to ioremap the debug
module, and to avoid the need to onchip_remap the watchpoint module, and to avoid the need to ioremap the watchpoint
controller in a way that identity maps sufficient bits to avoid the controller in a way that identity maps sufficient bits to avoid the
SH5-101 cut2 silicon defect). SH5-101 cut2 silicon defect).

View File

@ -0,0 +1,46 @@
/*
* SH5-101/SH5-103 CPU Setup
*
* Copyright (C) 2009 Paul Mundt
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*/
#include <linux/platform_device.h>
#include <linux/init.h>
#include <linux/serial.h>
#include <linux/serial_sci.h>
#include <linux/io.h>
#include <linux/mm.h>
#include <asm/addrspace.h>
static struct plat_sci_port sci_platform_data[] = {
{
.mapbase = PHYS_PERIPHERAL_BLOCK + 0x01030000,
.flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP,
.type = PORT_SCIF,
.irqs = { 39, 40, 42, 0 },
}, {
.flags = 0,
}
};
static struct platform_device sci_device = {
.name = "sh-sci",
.id = -1,
.dev = {
.platform_data = sci_platform_data,
},
};
static struct platform_device *sh5_devices[] __initdata = {
&sci_device,
};
static int __init sh5_devices_setup(void)
{
return platform_add_devices(sh5_devices,
ARRAY_SIZE(sh5_devices));
}
__initcall(sh5_devices_setup);

View File

@ -243,12 +243,12 @@ void __init time_init(void)
unsigned long interval; unsigned long interval;
struct clk *clk; struct clk *clk;
tmu_base = onchip_remap(TMU_BASE, 1024, "TMU"); tmu_base = (unsigned long)ioremap_nocache(TMU_BASE, 1024);
if (!tmu_base) { if (!tmu_base) {
panic("Unable to remap TMU\n"); panic("Unable to remap TMU\n");
} }
rtc_base = onchip_remap(RTC_BASE, 1024, "RTC"); rtc_base = (unsigned long)ioremap_nocache(RTC_BASE, 1024);
if (!rtc_base) { if (!rtc_base) {
panic("Unable to remap RTC\n"); panic("Unable to remap RTC\n");
} }

View File

@ -27,88 +27,17 @@
#include <asm/tlbflush.h> #include <asm/tlbflush.h>
#include <asm/mmu.h> #include <asm/mmu.h>
static void shmedia_mapioaddr(unsigned long, unsigned long);
static unsigned long shmedia_ioremap(struct resource *, u32, int);
/*
* Generic mapping function (not visible outside):
*/
/*
* Remap an arbitrary physical address space into the kernel virtual
* address space. Needed when the kernel wants to access high addresses
* directly.
*
* NOTE! We need to allow non-page-aligned mappings too: we will obviously
* 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 * addr;
struct vm_struct * area;
unsigned long offset, last_addr;
pgprot_t pgprot;
/* Don't allow wraparound or zero size */
last_addr = phys_addr + size - 1;
if (!size || last_addr < phys_addr)
return NULL;
pgprot = __pgprot(_PAGE_PRESENT | _PAGE_READ |
_PAGE_WRITE | _PAGE_DIRTY |
_PAGE_ACCESSED | _PAGE_SHARED | flags);
/*
* Mappings have to be page-aligned
*/
offset = phys_addr & ~PAGE_MASK;
phys_addr &= PAGE_MASK;
size = PAGE_ALIGN(last_addr + 1) - phys_addr;
/*
* Ok, go for it..
*/
area = get_vm_area(size, VM_IOREMAP);
if (!area)
return NULL;
pr_debug("Get vm_area returns %p addr %p\n", area, area->addr);
area->phys_addr = phys_addr;
addr = area->addr;
if (ioremap_page_range((unsigned long)addr, (unsigned long)addr + size,
phys_addr, pgprot)) {
vunmap(addr);
return NULL;
}
return (void *) (offset + (char *)addr);
}
EXPORT_SYMBOL(__ioremap);
void __iounmap(void *addr)
{
struct vm_struct *area;
vfree((void *) (PAGE_MASK & (unsigned long) addr));
area = remove_vm_area((void *) (PAGE_MASK & (unsigned long) addr));
if (!area) {
printk(KERN_ERR "iounmap: bad address %p\n", addr);
return;
}
kfree(area);
}
EXPORT_SYMBOL(__iounmap);
static struct resource shmedia_iomap = { static struct resource shmedia_iomap = {
.name = "shmedia_iomap", .name = "shmedia_iomap",
.start = IOBASE_VADDR + PAGE_SIZE, .start = IOBASE_VADDR + PAGE_SIZE,
.end = IOBASE_END - 1, .end = IOBASE_END - 1,
}; };
static void shmedia_mapioaddr(unsigned long pa, unsigned long va); static void shmedia_mapioaddr(unsigned long pa, unsigned long va,
unsigned long flags);
static void shmedia_unmapioaddr(unsigned long vaddr); static void shmedia_unmapioaddr(unsigned long vaddr);
static unsigned long shmedia_ioremap(struct resource *res, u32 pa, int sz); static void __iomem *shmedia_ioremap(struct resource *res, u32 pa,
int sz, unsigned long flags);
/* /*
* We have the same problem as the SPARC, so lets have the same comment: * We have the same problem as the SPARC, so lets have the same comment:
@ -130,18 +59,18 @@ static struct xresource xresv[XNRES];
static struct xresource *xres_alloc(void) static struct xresource *xres_alloc(void)
{ {
struct xresource *xrp; struct xresource *xrp;
int n; int n;
xrp = xresv; xrp = xresv;
for (n = 0; n < XNRES; n++) { for (n = 0; n < XNRES; n++) {
if (xrp->xflag == 0) { if (xrp->xflag == 0) {
xrp->xflag = 1; xrp->xflag = 1;
return xrp; return xrp;
} }
xrp++; xrp++;
} }
return NULL; return NULL;
} }
static void xres_free(struct xresource *xrp) static void xres_free(struct xresource *xrp)
@ -161,76 +90,71 @@ static struct resource *shmedia_find_resource(struct resource *root,
return NULL; return NULL;
} }
static unsigned long shmedia_alloc_io(unsigned long phys, unsigned long size, static void __iomem *shmedia_alloc_io(unsigned long phys, unsigned long size,
const char *name) const char *name, unsigned long flags)
{ {
static int printed_full = 0; static int printed_full;
struct xresource *xres; struct xresource *xres;
struct resource *res; struct resource *res;
char *tack; char *tack;
int tlen; int tlen;
if (name == NULL) name = "???"; if (name == NULL)
name = "???";
if ((xres = xres_alloc()) != 0) { xres = xres_alloc();
tack = xres->xname; if (xres != 0) {
res = &xres->xres; tack = xres->xname;
} else { res = &xres->xres;
if (!printed_full) { } else {
printk("%s: done with statics, switching to kmalloc\n", if (!printed_full) {
__func__); printk(KERN_NOTICE "%s: done with statics, "
printed_full = 1; "switching to kmalloc\n", __func__);
} printed_full = 1;
tlen = strlen(name); }
tack = kmalloc(sizeof (struct resource) + tlen + 1, GFP_KERNEL); tlen = strlen(name);
if (!tack) tack = kmalloc(sizeof(struct resource) + tlen + 1, GFP_KERNEL);
return -ENOMEM; if (!tack)
memset(tack, 0, sizeof(struct resource)); return NULL;
res = (struct resource *) tack; memset(tack, 0, sizeof(struct resource));
tack += sizeof (struct resource); res = (struct resource *) tack;
} tack += sizeof(struct resource);
}
strncpy(tack, name, XNMLN); strncpy(tack, name, XNMLN);
tack[XNMLN] = 0; tack[XNMLN] = 0;
res->name = tack; res->name = tack;
return shmedia_ioremap(res, phys, size); return shmedia_ioremap(res, phys, size, flags);
} }
static unsigned long shmedia_ioremap(struct resource *res, u32 pa, int sz) static void __iomem *shmedia_ioremap(struct resource *res, u32 pa, int sz,
unsigned long flags)
{ {
unsigned long offset = ((unsigned long) pa) & (~PAGE_MASK); unsigned long offset = ((unsigned long) pa) & (~PAGE_MASK);
unsigned long round_sz = (offset + sz + PAGE_SIZE-1) & PAGE_MASK; unsigned long round_sz = (offset + sz + PAGE_SIZE-1) & PAGE_MASK;
unsigned long va; unsigned long va;
unsigned int psz; unsigned int psz;
if (allocate_resource(&shmedia_iomap, res, round_sz, if (allocate_resource(&shmedia_iomap, res, round_sz,
shmedia_iomap.start, shmedia_iomap.end, shmedia_iomap.start, shmedia_iomap.end,
PAGE_SIZE, NULL, NULL) != 0) { PAGE_SIZE, NULL, NULL) != 0) {
panic("alloc_io_res(%s): cannot occupy\n", panic("alloc_io_res(%s): cannot occupy\n",
(res->name != NULL)? res->name: "???"); (res->name != NULL) ? res->name : "???");
} }
va = res->start; va = res->start;
pa &= PAGE_MASK; pa &= PAGE_MASK;
psz = (res->end - res->start + (PAGE_SIZE - 1)) / PAGE_SIZE; psz = (res->end - res->start + (PAGE_SIZE - 1)) / PAGE_SIZE;
/* log at boot time ... */ for (psz = res->end - res->start + 1; psz != 0; psz -= PAGE_SIZE) {
printk("mapioaddr: %6s [%2d page%s] va 0x%08lx pa 0x%08x\n", shmedia_mapioaddr(pa, va, flags);
((res->name != NULL) ? res->name : "???"), va += PAGE_SIZE;
psz, psz == 1 ? " " : "s", va, pa); pa += PAGE_SIZE;
}
for (psz = res->end - res->start + 1; psz != 0; psz -= PAGE_SIZE) { return (void __iomem *)(unsigned long)(res->start + offset);
shmedia_mapioaddr(pa, va);
va += PAGE_SIZE;
pa += PAGE_SIZE;
}
res->start += offset;
res->end = res->start + sz - 1; /* not strictly necessary.. */
return res->start;
} }
static void shmedia_free_io(struct resource *res) static void shmedia_free_io(struct resource *res)
@ -249,14 +173,12 @@ static void shmedia_free_io(struct resource *res)
static __init_refok void *sh64_get_page(void) static __init_refok void *sh64_get_page(void)
{ {
extern int after_bootmem;
void *page; void *page;
if (after_bootmem) { if (after_bootmem)
page = (void *)get_zeroed_page(GFP_ATOMIC); page = (void *)get_zeroed_page(GFP_KERNEL);
} else { else
page = alloc_bootmem_pages(PAGE_SIZE); page = alloc_bootmem_pages(PAGE_SIZE);
}
if (!page || ((unsigned long)page & ~PAGE_MASK)) if (!page || ((unsigned long)page & ~PAGE_MASK))
panic("sh64_get_page: Out of memory already?\n"); panic("sh64_get_page: Out of memory already?\n");
@ -264,17 +186,20 @@ static __init_refok void *sh64_get_page(void)
return page; return page;
} }
static void shmedia_mapioaddr(unsigned long pa, unsigned long va) static void shmedia_mapioaddr(unsigned long pa, unsigned long va,
unsigned long flags)
{ {
pgd_t *pgdp; pgd_t *pgdp;
pud_t *pudp; pud_t *pudp;
pmd_t *pmdp; pmd_t *pmdp;
pte_t *ptep, pte; pte_t *ptep, pte;
pgprot_t prot; pgprot_t prot;
unsigned long flags = 1; /* 1 = CB0-1 device */
pr_debug("shmedia_mapiopage pa %08lx va %08lx\n", pa, va); pr_debug("shmedia_mapiopage pa %08lx va %08lx\n", pa, va);
if (!flags)
flags = 1; /* 1 = CB0-1 device */
pgdp = pgd_offset_k(va); pgdp = pgd_offset_k(va);
if (pgd_none(*pgdp) || !pgd_present(*pgdp)) { if (pgd_none(*pgdp) || !pgd_present(*pgdp)) {
pudp = (pud_t *)sh64_get_page(); pudp = (pud_t *)sh64_get_page();
@ -288,7 +213,7 @@ static void shmedia_mapioaddr(unsigned long pa, unsigned long va)
} }
pmdp = pmd_offset(pudp, va); pmdp = pmd_offset(pudp, va);
if (pmd_none(*pmdp) || !pmd_present(*pmdp) ) { if (pmd_none(*pmdp) || !pmd_present(*pmdp)) {
ptep = (pte_t *)sh64_get_page(); ptep = (pte_t *)sh64_get_page();
set_pmd(pmdp, __pmd((unsigned long)ptep + _PAGE_TABLE)); set_pmd(pmdp, __pmd((unsigned long)ptep + _PAGE_TABLE));
} }
@ -336,17 +261,19 @@ static void shmedia_unmapioaddr(unsigned long vaddr)
pte_clear(&init_mm, vaddr, ptep); pte_clear(&init_mm, vaddr, ptep);
} }
unsigned long onchip_remap(unsigned long phys, unsigned long size, const char *name) void __iomem *__ioremap(unsigned long offset, unsigned long size,
unsigned long flags)
{ {
if (size < PAGE_SIZE) char name[14];
size = PAGE_SIZE;
return shmedia_alloc_io(phys, size, name); sprintf(name, "phys_%08x", (u32)offset);
return shmedia_alloc_io(offset, size, name, flags);
} }
EXPORT_SYMBOL(onchip_remap); EXPORT_SYMBOL(__ioremap);
void onchip_unmap(unsigned long vaddr) void __iounmap(void __iomem *virtual)
{ {
unsigned long vaddr = (unsigned long)virtual & PAGE_MASK;
struct resource *res; struct resource *res;
unsigned int psz; unsigned int psz;
@ -357,10 +284,7 @@ void onchip_unmap(unsigned long vaddr)
return; return;
} }
psz = (res->end - res->start + (PAGE_SIZE - 1)) / PAGE_SIZE; psz = (res->end - res->start + (PAGE_SIZE - 1)) / PAGE_SIZE;
printk(KERN_DEBUG "unmapioaddr: %6s [%2d page%s] freed\n",
res->name, psz, psz == 1 ? " " : "s");
shmedia_free_io(res); shmedia_free_io(res);
@ -371,9 +295,8 @@ void onchip_unmap(unsigned long vaddr)
kfree(res); kfree(res);
} }
} }
EXPORT_SYMBOL(onchip_unmap); EXPORT_SYMBOL(__iounmap);
#ifdef CONFIG_PROC_FS
static int static int
ioremap_proc_info(char *buf, char **start, off_t fpos, int length, int *eof, ioremap_proc_info(char *buf, char **start, off_t fpos, int length, int *eof,
void *data) void *data)
@ -385,7 +308,10 @@ ioremap_proc_info(char *buf, char **start, off_t fpos, int length, int *eof,
for (r = ((struct resource *)data)->child; r != NULL; r = r->sibling) { for (r = ((struct resource *)data)->child; r != NULL; r = r->sibling) {
if (p + 32 >= e) /* Better than nothing */ if (p + 32 >= e) /* Better than nothing */
break; break;
if ((nm = r->name) == 0) nm = "???"; nm = r->name;
if (nm == NULL)
nm = "???";
p += sprintf(p, "%08lx-%08lx: %s\n", p += sprintf(p, "%08lx-%08lx: %s\n",
(unsigned long)r->start, (unsigned long)r->start,
(unsigned long)r->end, nm); (unsigned long)r->end, nm);
@ -393,14 +319,11 @@ ioremap_proc_info(char *buf, char **start, off_t fpos, int length, int *eof,
return p-buf; return p-buf;
} }
#endif /* CONFIG_PROC_FS */
static int __init register_proc_onchip(void) static int __init register_proc_onchip(void)
{ {
#ifdef CONFIG_PROC_FS create_proc_read_entry("io_map", 0, 0, ioremap_proc_info,
create_proc_read_entry("io_map",0,0, ioremap_proc_info, &shmedia_iomap); &shmedia_iomap);
#endif
return 0; return 0;
} }
late_initcall(register_proc_onchip);
__initcall(register_proc_onchip);

View File

@ -985,13 +985,7 @@ static void sci_config_port(struct uart_port *port, int flags)
port->type = s->type; port->type = s->type;
if (port->flags & UPF_IOREMAP && !port->membase) { if (port->flags & UPF_IOREMAP && !port->membase) {
#if defined(CONFIG_SUPERH64)
port->mapbase = onchip_remap(SCIF_ADDR_SH5, 1024, "SCIF");
port->membase = (void __iomem *)port->mapbase;
#else
port->membase = ioremap_nocache(port->mapbase, 0x40); port->membase = ioremap_nocache(port->mapbase, 0x40);
#endif
dev_err(port->dev, "can't remap port#%d\n", port->line); dev_err(port->dev, "can't remap port#%d\n", port->line);
} }
} }