[MIPS] Iomap implementation.
This implementation has support for the concept of one separate ioport address space by PCI domain. A pointer to the virtual address where the port space of a domain has been mapped has been added to struct pci_controller and systems should be fixed to fill in this value. For single domain systems this will be the same value as passed to set_io_port_base(). Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
This commit is contained in:
parent
4c1569949a
commit
140c1729a2
6 changed files with 297 additions and 91 deletions
|
@ -5,7 +5,8 @@
|
|||
lib-y += csum_partial.o memcpy.o memset.o promlib.o \
|
||||
strlen_user.o strncpy_user.o strnlen_user.o uncached.o
|
||||
|
||||
obj-y += iomap.o
|
||||
obj-y += iomap.o
|
||||
obj-$(CONFIG_PCI) += iomap-pci.o
|
||||
|
||||
# libgcc-style stuff needed in the kernel
|
||||
lib-y += ashldi3.o ashrdi3.o lshrdi3.o
|
||||
|
|
74
arch/mips/lib/iomap-pci.c
Normal file
74
arch/mips/lib/iomap-pci.c
Normal file
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* Implement the default iomap interfaces
|
||||
*
|
||||
* (C) Copyright 2004 Linus Torvalds
|
||||
* (C) Copyright 2006 Ralf Baechle <ralf@linux-mips.org>
|
||||
* (C) Copyright 2007 MIPS Technologies, Inc.
|
||||
* written by Ralf Baechle <ralf@linux-mips.org>
|
||||
*/
|
||||
#include <linux/pci.h>
|
||||
#include <linux/module.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
static void __iomem *ioport_map_pci(struct pci_dev *dev,
|
||||
unsigned long port, unsigned int nr)
|
||||
{
|
||||
struct pci_controller *ctrl = dev->bus->sysdata;
|
||||
unsigned long base = ctrl->io_map_base;
|
||||
|
||||
/* This will eventually become a BUG_ON but for now be gentle */
|
||||
if (unlikely(!ctrl->io_map_base)) {
|
||||
struct pci_bus *bus = dev->bus;
|
||||
char name[8];
|
||||
|
||||
while (bus->parent)
|
||||
bus = bus->parent;
|
||||
|
||||
ctrl->io_map_base = base = mips_io_port_base;
|
||||
|
||||
sprintf(name, "%04x:%02x", pci_domain_nr(bus), bus->number);
|
||||
printk(KERN_WARNING "io_map_base of root PCI bus %s unset. "
|
||||
"Trying to continue but you better\nfix this issue or "
|
||||
"report it to linux-mips@linux-mips.org or your "
|
||||
"vendor.\n", name);
|
||||
#ifdef CONFIG_PCI_DOMAINS
|
||||
panic("To avoid data corruption io_map_base MUST be set with "
|
||||
"multiple PCI domains.");
|
||||
#endif
|
||||
}
|
||||
|
||||
return (void __iomem *) (ctrl->io_map_base + port);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a virtual mapping cookie for a PCI BAR (memory or IO)
|
||||
*/
|
||||
void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
|
||||
{
|
||||
unsigned long start = pci_resource_start(dev, bar);
|
||||
unsigned long len = pci_resource_len(dev, bar);
|
||||
unsigned long flags = pci_resource_flags(dev, bar);
|
||||
|
||||
if (!len || !start)
|
||||
return NULL;
|
||||
if (maxlen && len > maxlen)
|
||||
len = maxlen;
|
||||
if (flags & IORESOURCE_IO)
|
||||
return ioport_map_pci(dev, start, len);
|
||||
if (flags & IORESOURCE_MEM) {
|
||||
if (flags & IORESOURCE_CACHEABLE)
|
||||
return ioremap(start, len);
|
||||
return ioremap_nocache(start, len);
|
||||
}
|
||||
/* What? */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(pci_iomap);
|
||||
|
||||
void pci_iounmap(struct pci_dev *dev, void __iomem * addr)
|
||||
{
|
||||
iounmap(addr);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(pci_iounmap);
|
|
@ -1,78 +1,227 @@
|
|||
/*
|
||||
* iomap.c, Memory Mapped I/O routines for MIPS architecture.
|
||||
* Implement the default iomap interfaces
|
||||
*
|
||||
* This code is based on lib/iomap.c, by Linus Torvalds.
|
||||
*
|
||||
* Copyright (C) 2004-2005 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
* (C) Copyright 2004 Linus Torvalds
|
||||
* (C) Copyright 2006 Ralf Baechle <ralf@linux-mips.org>
|
||||
* (C) Copyright 2007 MIPS Technologies, Inc.
|
||||
* written by Ralf Baechle <ralf@linux-mips.org>
|
||||
*/
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
/*
|
||||
* Read/write from/to an (offsettable) iomem cookie. It might be a PIO
|
||||
* access or a MMIO access, these functions don't care. The info is
|
||||
* encoded in the hardware mapping set up by the mapping functions
|
||||
* (or the cookie itself, depending on implementation and hw).
|
||||
*
|
||||
* The generic routines don't assume any hardware mappings, and just
|
||||
* encode the PIO/MMIO as part of the cookie. They coldly assume that
|
||||
* the MMIO IO mappings are not in the low address range.
|
||||
*
|
||||
* Architectures for which this is not true can't use this generic
|
||||
* implementation and should do their own copy.
|
||||
*/
|
||||
|
||||
#define PIO_MASK 0x0ffffUL
|
||||
|
||||
unsigned int ioread8(void __iomem *addr)
|
||||
{
|
||||
return readb(addr);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(ioread8);
|
||||
|
||||
unsigned int ioread16(void __iomem *addr)
|
||||
{
|
||||
return readw(addr);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(ioread16);
|
||||
|
||||
unsigned int ioread16be(void __iomem *addr)
|
||||
{
|
||||
return be16_to_cpu(__raw_readw(addr));
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(ioread16be);
|
||||
|
||||
unsigned int ioread32(void __iomem *addr)
|
||||
{
|
||||
return readl(addr);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(ioread32);
|
||||
|
||||
unsigned int ioread32be(void __iomem *addr)
|
||||
{
|
||||
return be32_to_cpu(__raw_readl(addr));
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(ioread32be);
|
||||
|
||||
void iowrite8(u8 val, void __iomem *addr)
|
||||
{
|
||||
writeb(val, addr);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(iowrite8);
|
||||
|
||||
void iowrite16(u16 val, void __iomem *addr)
|
||||
{
|
||||
writew(val, addr);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(iowrite16);
|
||||
|
||||
void iowrite16be(u16 val, void __iomem *addr)
|
||||
{
|
||||
__raw_writew(cpu_to_be16(val), addr);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(iowrite16be);
|
||||
|
||||
void iowrite32(u32 val, void __iomem *addr)
|
||||
{
|
||||
writel(val, addr);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(iowrite32);
|
||||
|
||||
void iowrite32be(u32 val, void __iomem *addr)
|
||||
{
|
||||
__raw_writel(cpu_to_be32(val), addr);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(iowrite32be);
|
||||
|
||||
/*
|
||||
* These are the "repeat MMIO read/write" functions.
|
||||
* Note the "__raw" accesses, since we don't want to
|
||||
* convert to CPU byte order. We write in "IO byte
|
||||
* order" (we also don't have IO barriers).
|
||||
*/
|
||||
static inline void mmio_insb(void __iomem *addr, u8 *dst, int count)
|
||||
{
|
||||
while (--count >= 0) {
|
||||
u8 data = __raw_readb(addr);
|
||||
*dst = data;
|
||||
dst++;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void mmio_insw(void __iomem *addr, u16 *dst, int count)
|
||||
{
|
||||
while (--count >= 0) {
|
||||
u16 data = __raw_readw(addr);
|
||||
*dst = data;
|
||||
dst++;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void mmio_insl(void __iomem *addr, u32 *dst, int count)
|
||||
{
|
||||
while (--count >= 0) {
|
||||
u32 data = __raw_readl(addr);
|
||||
*dst = data;
|
||||
dst++;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void mmio_outsb(void __iomem *addr, const u8 *src, int count)
|
||||
{
|
||||
while (--count >= 0) {
|
||||
__raw_writeb(*src, addr);
|
||||
src++;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void mmio_outsw(void __iomem *addr, const u16 *src, int count)
|
||||
{
|
||||
while (--count >= 0) {
|
||||
__raw_writew(*src, addr);
|
||||
src++;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void mmio_outsl(void __iomem *addr, const u32 *src, int count)
|
||||
{
|
||||
while (--count >= 0) {
|
||||
__raw_writel(*src, addr);
|
||||
src++;
|
||||
}
|
||||
}
|
||||
|
||||
void ioread8_rep(void __iomem *addr, void *dst, unsigned long count)
|
||||
{
|
||||
mmio_insb(addr, dst, count);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(ioread8_rep);
|
||||
|
||||
void ioread16_rep(void __iomem *addr, void *dst, unsigned long count)
|
||||
{
|
||||
mmio_insw(addr, dst, count);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(ioread16_rep);
|
||||
|
||||
void ioread32_rep(void __iomem *addr, void *dst, unsigned long count)
|
||||
{
|
||||
mmio_insl(addr, dst, count);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(ioread32_rep);
|
||||
|
||||
void iowrite8_rep(void __iomem *addr, const void *src, unsigned long count)
|
||||
{
|
||||
mmio_outsb(addr, src, count);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(iowrite8_rep);
|
||||
|
||||
void iowrite16_rep(void __iomem *addr, const void *src, unsigned long count)
|
||||
{
|
||||
mmio_outsw(addr, src, count);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(iowrite16_rep);
|
||||
|
||||
void iowrite32_rep(void __iomem *addr, const void *src, unsigned long count)
|
||||
{
|
||||
mmio_outsl(addr, src, count);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(iowrite32_rep);
|
||||
|
||||
/*
|
||||
* Create a virtual mapping cookie for an IO port range
|
||||
*
|
||||
* This uses the same mapping are as the in/out family which has to be setup
|
||||
* by the platform initialization code.
|
||||
*
|
||||
* Just to make matters somewhat more interesting on MIPS systems with
|
||||
* multiple host bridge each will have it's own ioport address space.
|
||||
*/
|
||||
static void __iomem *ioport_map_legacy(unsigned long port, unsigned int nr)
|
||||
{
|
||||
return (void __iomem *) (mips_io_port_base + port);
|
||||
}
|
||||
|
||||
void __iomem *ioport_map(unsigned long port, unsigned int nr)
|
||||
{
|
||||
unsigned long end;
|
||||
|
||||
end = port + nr - 1UL;
|
||||
if (ioport_resource.start > port ||
|
||||
ioport_resource.end < end || port > end)
|
||||
if (port > PIO_MASK)
|
||||
return NULL;
|
||||
|
||||
return (void __iomem *)(mips_io_port_base + port);
|
||||
return ioport_map_legacy(port, nr);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(ioport_map);
|
||||
|
||||
void ioport_unmap(void __iomem *addr)
|
||||
{
|
||||
/* Nothing to do */
|
||||
}
|
||||
EXPORT_SYMBOL(ioport_map);
|
||||
|
||||
EXPORT_SYMBOL(ioport_unmap);
|
||||
|
||||
void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
|
||||
{
|
||||
unsigned long start, len, flags;
|
||||
|
||||
if (dev == NULL)
|
||||
return NULL;
|
||||
|
||||
start = pci_resource_start(dev, bar);
|
||||
len = pci_resource_len(dev, bar);
|
||||
if (!start || !len)
|
||||
return NULL;
|
||||
|
||||
if (maxlen != 0 && len > maxlen)
|
||||
len = maxlen;
|
||||
|
||||
flags = pci_resource_flags(dev, bar);
|
||||
if (flags & IORESOURCE_IO)
|
||||
return ioport_map(start, len);
|
||||
if (flags & IORESOURCE_MEM) {
|
||||
if (flags & IORESOURCE_CACHEABLE)
|
||||
return ioremap_cachable(start, len);
|
||||
return ioremap_nocache(start, len);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
|
||||
{
|
||||
iounmap(addr);
|
||||
}
|
||||
EXPORT_SYMBOL(pci_iomap);
|
||||
EXPORT_SYMBOL(pci_iounmap);
|
||||
|
|
|
@ -79,6 +79,14 @@ void __init register_pci_controller(struct pci_controller *hose)
|
|||
{
|
||||
*hose_tail = hose;
|
||||
hose_tail = &hose->next;
|
||||
|
||||
/*
|
||||
* Do not panic here but later - this might hapen before console init.
|
||||
*/
|
||||
if (!hose->io_map_base) {
|
||||
printk(KERN_WARNING
|
||||
"registering PCI controller with io_map_base unset\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* Most MIPS systems have straight-forward swizzling needs. */
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <asm/byteorder.h>
|
||||
#include <asm/cpu.h>
|
||||
#include <asm/cpu-features.h>
|
||||
#include <asm-generic/iomap.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/pgtable-bits.h>
|
||||
#include <asm/processor.h>
|
||||
|
@ -517,34 +518,6 @@ static inline void memcpy_toio(volatile void __iomem *dst, const void *src, int
|
|||
memcpy((void __force *) dst, src, count);
|
||||
}
|
||||
|
||||
/*
|
||||
* Memory Mapped I/O
|
||||
*/
|
||||
#define ioread8(addr) readb(addr)
|
||||
#define ioread16(addr) readw(addr)
|
||||
#define ioread32(addr) readl(addr)
|
||||
|
||||
#define iowrite8(b,addr) writeb(b,addr)
|
||||
#define iowrite16(w,addr) writew(w,addr)
|
||||
#define iowrite32(l,addr) writel(l,addr)
|
||||
|
||||
#define ioread8_rep(a,b,c) readsb(a,b,c)
|
||||
#define ioread16_rep(a,b,c) readsw(a,b,c)
|
||||
#define ioread32_rep(a,b,c) readsl(a,b,c)
|
||||
|
||||
#define iowrite8_rep(a,b,c) writesb(a,b,c)
|
||||
#define iowrite16_rep(a,b,c) writesw(a,b,c)
|
||||
#define iowrite32_rep(a,b,c) writesl(a,b,c)
|
||||
|
||||
/* Create a virtual mapping cookie for an IO port range */
|
||||
extern void __iomem *ioport_map(unsigned long port, unsigned int nr);
|
||||
extern void ioport_unmap(void __iomem *);
|
||||
|
||||
/* Create a virtual mapping cookie for a PCI BAR (memory or IO) */
|
||||
struct pci_dev;
|
||||
extern void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max);
|
||||
extern void pci_iounmap(struct pci_dev *dev, void __iomem *);
|
||||
|
||||
/*
|
||||
* ISA space is 'always mapped' on currently supported MIPS systems, no need
|
||||
* to explicitly ioremap() it. The fact that the ISA IO space is mapped
|
||||
|
|
|
@ -32,6 +32,7 @@ struct pci_controller {
|
|||
unsigned long mem_offset;
|
||||
struct resource *io_resource;
|
||||
unsigned long io_offset;
|
||||
unsigned long io_map_base;
|
||||
|
||||
unsigned int index;
|
||||
/* For compatibility with current (as of July 2003) pciutils
|
||||
|
|
Loading…
Reference in a new issue