Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 140c1729 authored by Ralf Baechle's avatar Ralf Baechle
Browse files

[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: default avatarRalf Baechle <ralf@linux-mips.org>
parent 4c156994
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -6,6 +6,7 @@ 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-$(CONFIG_PCI)	+= iomap-pci.o

# libgcc-style stuff needed in the kernel
lib-y += ashldi3.o ashrdi3.o lshrdi3.o
+74 −0
Original line number Diff line number Diff line
/*
 * 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);
+201 −52
Original line number Diff line number Diff line
/*
 *  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.
 * (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>

/*
 * 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).
 *
 *  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.
 * 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.
 *
 *  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
 * Architectures for which this is not true can't use this generic
 * implementation and should do their own copy.
 */
#include <linux/ioport.h>
#include <linux/module.h>
#include <linux/pci.h>

#include <asm/io.h>
#define PIO_MASK	0x0ffffUL

void __iomem *ioport_map(unsigned long port, unsigned int nr)
unsigned int ioread8(void __iomem *addr)
{
	unsigned long end;
	return readb(addr);
}

	end = port + nr - 1UL;
	if (ioport_resource.start > port ||
	    ioport_resource.end < end || port > end)
		return NULL;
EXPORT_SYMBOL(ioread8);

	return (void __iomem *)(mips_io_port_base + port);
unsigned int ioread16(void __iomem *addr)
{
	return readw(addr);
}

void ioport_unmap(void __iomem *addr)
EXPORT_SYMBOL(ioread16);

unsigned int ioread16be(void __iomem *addr)
{
	return be16_to_cpu(__raw_readw(addr));
}
EXPORT_SYMBOL(ioport_map);
EXPORT_SYMBOL(ioport_unmap);

void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
EXPORT_SYMBOL(ioread16be);

unsigned int ioread32(void __iomem *addr)
{
	unsigned long start, len, flags;
	return readl(addr);
}

	if (dev == NULL)
		return NULL;
EXPORT_SYMBOL(ioread32);

	start = pci_resource_start(dev, bar);
	len = pci_resource_len(dev, bar);
	if (!start || !len)
		return NULL;
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++;
	}
}

	if (maxlen != 0 && len > maxlen)
		len = maxlen;
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);

	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);
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)
{
	if (port > PIO_MASK)
		return NULL;

	return ioport_map_legacy(port, nr);
}

void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
EXPORT_SYMBOL(ioport_map);

void ioport_unmap(void __iomem *addr)
{
	iounmap(addr);
	/* Nothing to do */
}
EXPORT_SYMBOL(pci_iomap);
EXPORT_SYMBOL(pci_iounmap);

EXPORT_SYMBOL(ioport_unmap);
+8 −0
Original line number Diff line number Diff line
@@ -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.  */
+1 −28
Original line number Diff line number Diff line
@@ -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
Loading