[PATCH][1/5] RapidIO support: core base

Subsystems: documentation, generic include/asm header files, the rest

STALE7738d

7 messages, 3 authors, 2005-06-08 · open the first message on its own page

[PATCH][1/5] RapidIO support: core base

From: Matt Porter <mporter@kernel.crashing.org>
Date: 2005-06-06 23:01:30

[Updated with latest comments]

Adds a RapidIO subsystem to the kernel. RIO is a switched
fabric interconnect used in higher-end embedded applications.
The curious can look at the specs over at http://www.rapidio.org

The core code implements enumeration/discovery, management of
devices/resources, and interfaces for RIO drivers.

There's a lot more to do to take advantages of all the hardware
features. However, this should provide a good base for folks
with RIO hardware to start contributing.

Signed-off-by: Matt Porter <mporter@kernel.crashing.org>
diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile
--- a/Documentation/DocBook/Makefile
+++ b/Documentation/DocBook/Makefile
@@ -10,7 +10,7 @@ DOCBOOKS :=3D wanbook.xml z8530book.xml mc
 	    kernel-hacking.xml kernel-locking.xml deviceiobook.xml \
 	    procfs-guide.xml writing_usb_driver.xml scsidrivers.xml \
 	    sis900.xml kernel-api.xml journal-api.xml lsm.xml usb.xml \
-	    gadget.xml libata.xml mtdnand.xml librs.xml
+	    gadget.xml libata.xml mtdnand.xml librs.xml rapidio.xml
=20
 ###
 # The build process is as follows (targets):
diff --git a/Documentation/DocBook/rapidio.tmpl b/Documentation/DocBook/rap=
idio.tmpl
new file mode 100644
--- /dev/null
+++ b/Documentation/DocBook/rapidio.tmpl
@@ -0,0 +1,160 @@
+<?xml version=3D"1.0" encoding=3D"UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+        "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
+	<!ENTITY rapidio SYSTEM "rapidio.xml">
+	]>
+
+<book id=3D"RapidIO-Guide">
+ <bookinfo>
+  <title>RapidIO Subsystem Guide</title>
+=20=20
+  <authorgroup>
+   <author>
+    <firstname>Matt</firstname>
+    <surname>Porter</surname>
+    <affiliation>
+     <address>
+      <email>mporter@kernel.crashing.org</email>
+      <email>mporter@mvista.com</email>
+     </address>
+    </affiliation>
+   </author>
+  </authorgroup>
+
+  <copyright>
+   <year>2005</year>
+   <holder>MontaVista Software, Inc.</holder>
+  </copyright>
+
+  <legalnotice>
+   <para>
+     This documentation is free software; you can redistribute
+     it and/or modify it under the terms of the GNU General Public
+     License version 2 as published by the Free Software Foundation.
+   </para>
+=20=20=20=20=20=20
+   <para>
+     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.
+   </para>
+=20=20=20=20=20=20
+   <para>
+     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
+   </para>
+=20=20=20=20=20=20
+   <para>
+     For more details see the file COPYING in the source
+     distribution of Linux.
+   </para>
+  </legalnotice>
+ </bookinfo>
+
+<toc></toc>
+
+  <chapter id=3D"intro">
+      <title>Introduction</title>
+  <para>
+	RapidIO is a high speed switched fabric interconnect with
+	features aimed at the embedded market.  RapidIO provides
+	support for memory-mapped I/O as well as message-based
+	transactions over the switched fabric network. RapidIO has
+	a standardized discovery mechanism not unlike the PCI bus
+	standard that allows simple detection of devices in a
+	network.
+  </para>
+  <para>
+  	This documentation is provided for developers intending
+	to support RapidIO on new architectures, write new drivers,
+	or to understand the subsystem internals.
+  </para>
+  </chapter>
+=20=20
+  <chapter id=3D"bugs">
+     <title>Known Bugs and Limitations</title>
+
+     <sect1>
+     	<title>Bugs</title>
+	  <para>None. ;)</para>
+     </sect1>
+     <sect1>
+     	<title>Limitations</title>
+	  <para>
+	    <orderedlist>
+	      <listitem><para>Access/management of RapidIO memory regions is not =
supported</para></listitem>
+	      <listitem><para>Multiple host enumeration is not supported</para></=
listitem>
+	    </orderedlist>
+	 </para>
+     </sect1>
+  </chapter>
+
+  <chapter id=3D"drivers">
+     	<title>RapidIO driver interface</title>
+	<para>
+		Drivers are provided a set of calls in order
+		to interface with the subsystem to gather info
+		on devices, request/map memory region resources,
+		and manage mailboxes/doorbells.
+	</para>
+	<sect1>
+		<title>Functions</title>
+!Iinclude/linux/rio_drv.h
+!Edrivers/rio/rio-driver.c
+!Edrivers/rio/rio.c
+	</sect1>
+  </chapter>=09
+
+  <chapter id=3D"internals">
+     <title>Internals</title>
+
+     <para>
+     This chapter contains the autogenerated documentation of the RapidIO
+     subsystem.
+     </para>
+
+     <sect1><title>Structures</title>
+!Iinclude/linux/rio.h
+     </sect1>
+     <sect1><title>Enumeration and Discovery</title>
+!Idrivers/rio/rio-scan.c
+     </sect1>
+     <sect1><title>Driver functionality</title>
+!Idrivers/rio/rio.c
+!Idrivers/rio/rio-access.c
+     </sect1>
+     <sect1><title>Device model support</title>
+!Idrivers/rio/rio-driver.c
+     </sect1>
+     <sect1><title>Sysfs support</title>
+!Idrivers/rio/rio-sysfs.c
+     </sect1>
+     <sect1><title>PPC32 support</title>
+!Iarch/ppc/kernel/rio.c
+!Earch/ppc/syslib/ppc85xx_rio.c
+!Iarch/ppc/syslib/ppc85xx_rio.c
+     </sect1>
+  </chapter>
+
+  <chapter id=3D"credits">
+     <title>Credits</title>
+	<para>
+		The following people have contributed to the RapidIO
+		subsystem directly or indirectly:
+		<orderedlist>
+			<listitem><para>Matt Porter<email>mporter@kernel.crashing.org</email></=
para></listitem>
+			<listitem><para>Randy Vinson<email>rvinson@mvista.com</email></para></l=
istitem>
+			<listitem><para>Dan Malek<email>dan@embeddedalley.com</email></para></l=
istitem>
+		</orderedlist>
+	</para>
+	<para>
+		The following people have contributed to this document:
+		<orderedlist>
+			<listitem><para>Matt Porter<email>mporter@kernel.crashing.org</email></=
para></listitem>
+		</orderedlist>
+	</para>
+  </chapter>
+</book>
diff --git a/drivers/Makefile b/drivers/Makefile
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -7,6 +7,7 @@
=20
 obj-$(CONFIG_PCI)		+=3D pci/
 obj-$(CONFIG_PARISC)		+=3D parisc/
+obj-$(CONFIG_RAPIDIO)		+=3D rio/
 obj-y				+=3D video/
 obj-$(CONFIG_ACPI_BOOT)		+=3D acpi/
 # PnP must come after ACPI since it will eventually need to check if acpi
diff --git a/drivers/rio/Kconfig b/drivers/rio/Kconfig
new file mode 100644
--- /dev/null
+++ b/drivers/rio/Kconfig
@@ -0,0 +1,18 @@
+#
+# RapidIO configuration
+#
+config RAPIDIO_8_BIT_TRANSPORT
+	bool "8-bit transport addressing"
+	depends on RAPIDIO
+	---help---
+	  By default, the kernel assumes a 16-bit addressed RapidIO
+	  network. By selecting this option, the kernel will support
+	  an 8-bit addressed network.
+
+config RAPIDIO_DISC_TIMEOUT
+	int "Discovery timeout duration (seconds)"
+	depends on RAPIDIO
+	default "30"
+	---help---
+	  Amount of time a discovery node waits for a host to complete
+	  enumeration beforing giving up.
diff --git a/drivers/rio/Makefile b/drivers/rio/Makefile
new file mode 100644
--- /dev/null
+++ b/drivers/rio/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for RapidIO interconnect services
+#
+obj-y +=3D rio.o rio-access.o rio-driver.o rio-scan.o rio-sysfs.o
+
+obj-$(CONFIG_RAPIDIO)		+=3D switches/
diff --git a/drivers/rio/rio-access.c b/drivers/rio/rio-access.c
new file mode 100644
--- /dev/null
+++ b/drivers/rio/rio-access.c
@@ -0,0 +1,175 @@
+/*
+ * RapidIO configuration space access support
+ *
+ * Copyright 2005 MontaVista Software, Inc.
+ * Matt Porter <mporter@kernel.crashing.org>
+ *
+ * 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.
+ */
+
+#include <linux/rio.h>
+#include <linux/module.h>
+
+/*
+ * These interrupt-safe spinlocks protect all accesses to RIO
+ * configuration space and doorbell access.
+ */
+static spinlock_t rio_config_lock =3D SPIN_LOCK_UNLOCKED;
+static spinlock_t rio_doorbell_lock =3D SPIN_LOCK_UNLOCKED;
+
+/*
+ *  Wrappers for all RIO configuration access functions.  They just check
+ *  alignment, do locking and call the low-level functions pointed to
+ *  by rio_mport->ops.
+ */
+
+#define RIO_8_BAD 0
+#define RIO_16_BAD (offset & 1)
+#define RIO_32_BAD (offset & 3)
+
+/**
+ * RIO_LOP_READ - Generate rio_local_read_config_* functions
+ * @size: Size of configuration space read (8, 16, 32 bits)
+ * @type: C type of value argument
+ * @len: Length of configuration space read (1, 2, 4 bytes)
+ *
+ * Generates rio_local_read_config_* functions used to access
+ * configuration space registers on the local device.
+ */
+#define RIO_LOP_READ(size,type,len) \
+int __rio_local_read_config_##size \
+	(struct rio_mport *mport, u32 offset, type *value)		\
+{									\
+	int res;							\
+	unsigned long flags;						\
+	u32 data =3D 0;							\
+	if (RIO_##size##_BAD) return RIO_BAD_SIZE;			\
+	spin_lock_irqsave(&rio_config_lock, flags);			\
+	res =3D mport->ops->lcread(mport->id, offset, len, &data);	\
+	*value =3D (type)data;						\
+	spin_unlock_irqrestore(&rio_config_lock, flags);		\
+	return res;							\
+}
+
+/**
+ * RIO_LOP_WRITE - Generate rio_local_write_config_* functions
+ * @size: Size of configuration space write (8, 16, 32 bits)
+ * @type: C type of value argument
+ * @len: Length of configuration space write (1, 2, 4 bytes)
+ *
+ * Generates rio_local_write_config_* functions used to access
+ * configuration space registers on the local device.
+ */
+#define RIO_LOP_WRITE(size,type,len) \
+int __rio_local_write_config_##size \
+	(struct rio_mport *mport, u32 offset, type value)		\
+{									\
+	int res;							\
+	unsigned long flags;						\
+	if (RIO_##size##_BAD) return RIO_BAD_SIZE;			\
+	spin_lock_irqsave(&rio_config_lock, flags);			\
+	res =3D mport->ops->lcwrite(mport->id, offset, len, value);	\
+	spin_unlock_irqrestore(&rio_config_lock, flags);		\
+	return res;							\
+}
+
+RIO_LOP_READ(8, u8, 1)
+RIO_LOP_READ(16, u16, 2)
+RIO_LOP_READ(32, u32, 4)
+RIO_LOP_WRITE(8, u8, 1)
+RIO_LOP_WRITE(16, u16, 2)
+RIO_LOP_WRITE(32, u32, 4)
+
+EXPORT_SYMBOL_GPL(__rio_local_read_config_8);
+EXPORT_SYMBOL_GPL(__rio_local_read_config_16);
+EXPORT_SYMBOL_GPL(__rio_local_read_config_32);
+EXPORT_SYMBOL_GPL(__rio_local_write_config_8);
+EXPORT_SYMBOL_GPL(__rio_local_write_config_16);
+EXPORT_SYMBOL_GPL(__rio_local_write_config_32);
+
+/**
+ * RIO_OP_READ - Generate rio_mport_read_config_* functions
+ * @size: Size of configuration space read (8, 16, 32 bits)
+ * @type: C type of value argument
+ * @len: Length of configuration space read (1, 2, 4 bytes)
+ *
+ * Generates rio_mport_read_config_* functions used to access
+ * configuration space registers on the local device.
+ */
+#define RIO_OP_READ(size,type,len) \
+int rio_mport_read_config_##size \
+	(struct rio_mport *mport, u16 destid, u8 hopcount, u32 offset, type *valu=
e)	\
+{									\
+	int res;							\
+	unsigned long flags;						\
+	u32 data =3D 0;							\
+	if (RIO_##size##_BAD) return RIO_BAD_SIZE;			\
+	spin_lock_irqsave(&rio_config_lock, flags);			\
+	res =3D mport->ops->cread(mport->id, destid, hopcount, offset, len, &data=
); \
+	*value =3D (type)data;						\
+	spin_unlock_irqrestore(&rio_config_lock, flags);		\
+	return res;							\
+}
+
+/**
+ * RIO_OP_WRITE - Generate rio_mport_write_config_* functions
+ * @size: Size of configuration space write (8, 16, 32 bits)
+ * @type: C type of value argument
+ * @len: Length of configuration space write (1, 2, 4 bytes)
+ *
+ * Generates rio_mport_write_config_* functions used to access
+ * configuration space registers on the local device.
+ */
+#define RIO_OP_WRITE(size,type,len) \
+int rio_mport_write_config_##size \
+	(struct rio_mport *mport, u16 destid, u8 hopcount, u32 offset, type value=
)	\
+{									\
+	int res;							\
+	unsigned long flags;						\
+	if (RIO_##size##_BAD) return RIO_BAD_SIZE;			\
+	spin_lock_irqsave(&rio_config_lock, flags);			\
+	res =3D mport->ops->cwrite(mport->id, destid, hopcount, offset, len, valu=
e); \
+	spin_unlock_irqrestore(&rio_config_lock, flags);		\
+	return res;							\
+}
+
+RIO_OP_READ(8, u8, 1)
+RIO_OP_READ(16, u16, 2)
+RIO_OP_READ(32, u32, 4)
+RIO_OP_WRITE(8, u8, 1)
+RIO_OP_WRITE(16, u16, 2)
+RIO_OP_WRITE(32, u32, 4)
+
+EXPORT_SYMBOL_GPL(rio_mport_read_config_8);
+EXPORT_SYMBOL_GPL(rio_mport_read_config_16);
+EXPORT_SYMBOL_GPL(rio_mport_read_config_32);
+EXPORT_SYMBOL_GPL(rio_mport_write_config_8);
+EXPORT_SYMBOL_GPL(rio_mport_write_config_16);
+EXPORT_SYMBOL_GPL(rio_mport_write_config_32);
+
+/**
+ * rio_mport_send_doorbell - Send a doorbell message
+ *
+ * @mport: RIO master port
+ * @destid: RIO device destination ID
+ * @data: Doorbell message data
+ *
+ * Send a doorbell message to a RIO device. The doorbell message
+ * has a 16-bit info field provided by the data argument.
+ */
+int rio_mport_send_doorbell(struct rio_mport *mport, u16 destid, u16 data)
+{
+	int res;
+	unsigned long flags;
+
+	spin_lock_irqsave(&rio_doorbell_lock, flags);
+	res =3D mport->ops->dsend(mport->id, destid, data);
+	spin_unlock_irqrestore(&rio_doorbell_lock, flags);
+
+	return res;
+}
+
+EXPORT_SYMBOL_GPL(rio_mport_send_doorbell);
diff --git a/drivers/rio/rio-driver.c b/drivers/rio/rio-driver.c
new file mode 100644
--- /dev/null
+++ b/drivers/rio/rio-driver.c
@@ -0,0 +1,229 @@
+/*
+ * RapidIO driver support
+ *
+ * Copyright 2005 MontaVista Software, Inc.
+ * Matt Porter <mporter@kernel.crashing.org>
+ *
+ * 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.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/rio.h>
+#include <linux/rio_ids.h>
+
+#include "rio.h"
+
+/**
+ *  rio_match_device - Tell if a RIO device has a matching RIO device id s=
tructure
+ *  @id: the RIO device id structure to match against
+ *  @rdev: the RIO device structure to match against
+ *
+ *  Used from driver probe and bus matching to check whether a RIO device
+ *  matches a device id structure provided by a RIO driver. Returns the
+ *  matching &struct rio_device_id or %NULL if there is no match.
+ */
+static const struct rio_device_id *rio_match_device(const struct rio_devic=
e_id
+						    *id,
+						    const struct rio_dev *rdev)
+{
+	while (id->vid || id->asm_vid) {
+		if (((id->vid =3D=3D RIO_ANY_ID) || (id->vid =3D=3D rdev->vid)) &&
+		    ((id->did =3D=3D RIO_ANY_ID) || (id->did =3D=3D rdev->did)) &&
+		    ((id->asm_vid =3D=3D RIO_ANY_ID)
+		     || (id->asm_vid =3D=3D rdev->asm_vid))
+		    && ((id->asm_did =3D=3D RIO_ANY_ID)
+			|| (id->asm_did =3D=3D rdev->asm_did)))
+			return id;
+		id++;
+	}
+	return NULL;
+}
+
+/**
+ * rio_dev_get - Increments the reference count of the RIO device structure
+ *
+ * @rdev: RIO device being referenced
+ *
+ * Each live reference to a device should be refcounted.
+ *
+ * Drivers for RIO devices should normally record such references in
+ * their probe() methods, when they bind to a device, and release
+ * them by calling rio_dev_put(), in their disconnect() methods.
+ */
+struct rio_dev *rio_dev_get(struct rio_dev *rdev)
+{
+	if (rdev)
+		get_device(&rdev->dev);
+
+	return rdev;
+}
+
+/**
+ * rio_dev_put - Release a use of the RIO device structure
+ *
+ * @rdev: RIO device being disconnected
+ *
+ * Must be called when a user of a device is finished with it.
+ * When the last user of the device calls this function, the
+ * memory of the device is freed.
+ */
+void rio_dev_put(struct rio_dev *rdev)
+{
+	if (rdev)
+		put_device(&rdev->dev);
+}
+
+/**
+ *  rio_device_probe - Tell if a RIO device structure has a matching RIO
+ *                     device id structure
+ *  @id: the RIO device id structure to match against
+ *  @dev: the RIO device structure to match against
+ *
+ * return 0 and set rio_dev->driver when drv claims rio_dev, else error
+ */
+static int rio_device_probe(struct device *dev)
+{
+	struct rio_driver *rdrv =3D to_rio_driver(dev->driver);
+	struct rio_dev *rdev =3D to_rio_dev(dev);
+	int error =3D -ENODEV;
+	const struct rio_device_id *id;
+
+	if (!rdev->driver && rdrv->probe) {
+		if (!rdrv->id_table)
+			return error;
+		id =3D rio_match_device(rdrv->id_table, rdev);
+		rio_dev_get(rdev);
+		if (id)
+			error =3D rdrv->probe(rdev, id);
+		if (error >=3D 0) {
+			rdev->driver =3D rdrv;
+			error =3D 0;
+			rio_dev_put(rdev);
+		}
+	}
+	return error;
+}
+
+/**
+ *  rio_device_remove - Remove a RIO device from the system
+ *
+ *  @dev: the RIO device structure to match against
+ *
+ * Remove a RIO device from the system. If it has an associated
+ * driver, then run the driver remove() method.  Then update
+ * the reference count.
+ */
+static int rio_device_remove(struct device *dev)
+{
+	struct rio_dev *rdev =3D to_rio_dev(dev);
+	struct rio_driver *rdrv =3D rdev->driver;
+
+	if (rdrv) {
+		if (rdrv->remove)
+			rdrv->remove(rdev);
+		rdev->driver =3D NULL;
+	}
+
+	rio_dev_put(rdev);
+
+	return 0;
+}
+
+/**
+ *  rio_register_driver - register a new RIO driver
+ *  @rdrv: the RIO driver structure to register
+ *
+ *  Adds a &struct rio_driver to the list of registered drivers
+ *  Returns a negative value on error, otherwise 0. If no error
+ *  occurred, the driver remains registered even if no device
+ *  was claimed during registration.
+ */
+int rio_register_driver(struct rio_driver *rdrv)
+{
+	/* initialize common driver fields */
+	rdrv->driver.name =3D rdrv->name;
+	rdrv->driver.bus =3D &rio_bus_type;
+	rdrv->driver.probe =3D rio_device_probe;
+	rdrv->driver.remove =3D rio_device_remove;
+
+	/* register with core */
+	return driver_register(&rdrv->driver);
+}
+
+/**
+ *  rio_unregister_driver - unregister a RIO driver
+ *  @rdrv: the RIO driver structure to unregister
+ *
+ *  Deletes the &struct rio_driver from the list of registered RIO
+ *  drivers, gives it a chance to clean up by calling its remove()
+ *  function for each device it was responsible for, and marks those
+ *  devices as driverless.
+ */
+void rio_unregister_driver(struct rio_driver *rdrv)
+{
+	driver_unregister(&rdrv->driver);
+}
+
+/**
+ *  rio_match_bus - Tell if a RIO device structure has a matching RIO
+ *                  driver device id structure
+ *  @dev: the standard device structure to match against
+ *  @drv: the standard driver structure containing the ids to match against
+ *
+ *  Used by a driver to check whether a RIO device present in the
+ *  system is in its list of supported devices. Returns 1 if
+ *  there is a matching &struct rio_device_id or 0 if there is
+ *  no match.
+ */
+static int rio_match_bus(struct device *dev, struct device_driver *drv)
+{
+	struct rio_dev *rdev =3D to_rio_dev(dev);
+	struct rio_driver *rdrv =3D to_rio_driver(drv);
+	const struct rio_device_id *id =3D rdrv->id_table;
+	const struct rio_device_id *found_id;
+
+	if (!id)
+		goto out;
+
+	found_id =3D rio_match_device(id, rdev);
+
+	if (found_id)
+		return 1;
+
+      out:return 0;
+}
+
+static struct device rio_bus =3D {
+	.bus_id =3D "rapidio",
+};
+
+struct bus_type rio_bus_type =3D {
+	.name =3D "rapidio",
+	.match =3D rio_match_bus,
+	.dev_attrs =3D rio_dev_attrs
+};
+
+/**
+ *  rio_bus_init - Register the RapidIO bus with the device model
+ *
+ *  Registers the RIO bus device and RIO bus type with the Linux
+ *  device model.
+ */
+static int __init rio_bus_init(void)
+{
+	if (device_register(&rio_bus) < 0)
+		printk("RIO: failed to register RIO bus device\n");
+	return bus_register(&rio_bus_type);
+}
+
+postcore_initcall(rio_bus_init);
+
+EXPORT_SYMBOL_GPL(rio_register_driver);
+EXPORT_SYMBOL_GPL(rio_unregister_driver);
+EXPORT_SYMBOL_GPL(rio_bus_type);
+EXPORT_SYMBOL_GPL(rio_dev_get);
+EXPORT_SYMBOL_GPL(rio_dev_put);
diff --git a/drivers/rio/rio-sysfs.c b/drivers/rio/rio-sysfs.c
new file mode 100644
--- /dev/null
+++ b/drivers/rio/rio-sysfs.c
@@ -0,0 +1,230 @@
+/*
+ * RapidIO sysfs attributes and support
+ *
+ * Copyright 2005 MontaVista Software, Inc.
+ * Matt Porter <mporter@kernel.crashing.org>
+ *
+ * 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.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/rio.h>
+#include <linux/rio_drv.h>
+#include <linux/stat.h>
+
+#include "rio.h"
+
+/* Sysfs support */
+#define rio_config_attr(field, format_string)					\
+static ssize_t								\
+	field##_show(struct device *dev, char *buf)			\
+{									\
+	struct rio_dev *rdev =3D to_rio_dev(dev);				\
+									\
+	return sprintf(buf, format_string, rdev->field);		\
+}									\
+
+rio_config_attr(did, "0x%04x\n");
+rio_config_attr(vid, "0x%04x\n");
+rio_config_attr(device_rev, "0x%08x\n");
+rio_config_attr(asm_did, "0x%04x\n");
+rio_config_attr(asm_vid, "0x%04x\n");
+rio_config_attr(asm_rev, "0x%04x\n");
+
+static ssize_t routes_show(struct device *dev, char *buf)
+{
+	struct rio_dev *rdev =3D to_rio_dev(dev);
+	char *str =3D buf;
+	int i;
+
+	if (!rdev->rswitch)
+		goto out;
+
+	for (i =3D 0; i < RIO_MAX_ROUTE_ENTRIES; i++) {
+		if (rdev->rswitch->route_table[i] =3D=3D RIO_INVALID_ROUTE)
+			continue;
+		str +=3D
+		    sprintf(str, "%04x %02x\n", i,
+			    rdev->rswitch->route_table[i]);
+	}
+
+      out:
+	return (str - buf);
+}
+
+struct device_attribute rio_dev_attrs[] =3D {
+	__ATTR_RO(did),
+	__ATTR_RO(vid),
+	__ATTR_RO(device_rev),
+	__ATTR_RO(asm_did),
+	__ATTR_RO(asm_vid),
+	__ATTR_RO(asm_rev),
+	__ATTR_RO(routes),
+	__ATTR_NULL,
+};
+
+static ssize_t
+rio_read_config(struct kobject *kobj, char *buf, loff_t off, size_t count)
+{
+	struct rio_dev *dev =3D
+	    to_rio_dev(container_of(kobj, struct device, kobj));
+	unsigned int size =3D 0x100;
+	loff_t init_off =3D off;
+	u8 *data =3D (u8 *) buf;
+
+	/* Several chips lock up trying to read undefined config space */
+	if (capable(CAP_SYS_ADMIN))
+		size =3D 0x200000;
+
+	if (off > size)
+		return 0;
+	if (off + count > size) {
+		size -=3D off;
+		count =3D size;
+	} else {
+		size =3D count;
+	}
+
+	if ((off & 1) && size) {
+		u8 val;
+		rio_read_config_8(dev, off, &val);
+		data[off - init_off] =3D val;
+		off++;
+		size--;
+	}
+
+	if ((off & 3) && size > 2) {
+		u16 val;
+		rio_read_config_16(dev, off, &val);
+		data[off - init_off] =3D (val >> 8) & 0xff;
+		data[off - init_off + 1] =3D val & 0xff;
+		off +=3D 2;
+		size -=3D 2;
+	}
+
+	while (size > 3) {
+		u32 val;
+		rio_read_config_32(dev, off, &val);
+		data[off - init_off] =3D (val >> 24) & 0xff;
+		data[off - init_off + 1] =3D (val >> 16) & 0xff;
+		data[off - init_off + 2] =3D (val >> 8) & 0xff;
+		data[off - init_off + 3] =3D val & 0xff;
+		off +=3D 4;
+		size -=3D 4;
+	}
+
+	if (size >=3D 2) {
+		u16 val;
+		rio_read_config_16(dev, off, &val);
+		data[off - init_off] =3D (val >> 8) & 0xff;
+		data[off - init_off + 1] =3D val & 0xff;
+		off +=3D 2;
+		size -=3D 2;
+	}
+
+	if (size > 0) {
+		u8 val;
+		rio_read_config_8(dev, off, &val);
+		data[off - init_off] =3D val;
+		off++;
+		--size;
+	}
+
+	return count;
+}
+
+static ssize_t
+rio_write_config(struct kobject *kobj, char *buf, loff_t off, size_t count)
+{
+	struct rio_dev *dev =3D
+	    to_rio_dev(container_of(kobj, struct device, kobj));
+	unsigned int size =3D count;
+	loff_t init_off =3D off;
+	u8 *data =3D (u8 *) buf;
+
+	if (off > 0x200000)
+		return 0;
+	if (off + count > 0x200000) {
+		size =3D 0x200000 - off;
+		count =3D size;
+	}
+
+	if ((off & 1) && size) {
+		rio_write_config_8(dev, off, data[off - init_off]);
+		off++;
+		size--;
+	}
+
+	if ((off & 3) && (size > 2)) {
+		u16 val =3D data[off - init_off + 1];
+		val |=3D (u16) data[off - init_off] << 8;
+		rio_write_config_16(dev, off, val);
+		off +=3D 2;
+		size -=3D 2;
+	}
+
+	while (size > 3) {
+		u32 val =3D data[off - init_off + 3];
+		val |=3D (u32) data[off - init_off + 2] << 8;
+		val |=3D (u32) data[off - init_off + 1] << 16;
+		val |=3D (u32) data[off - init_off] << 24;
+		rio_write_config_32(dev, off, val);
+		off +=3D 4;
+		size -=3D 4;
+	}
+
+	if (size >=3D 2) {
+		u16 val =3D data[off - init_off + 1];
+		val |=3D (u16) data[off - init_off] << 8;
+		rio_write_config_16(dev, off, val);
+		off +=3D 2;
+		size -=3D 2;
+	}
+
+	if (size) {
+		rio_write_config_8(dev, off, data[off - init_off]);
+		off++;
+		--size;
+	}
+
+	return count;
+}
+
+static struct bin_attribute rio_config_attr =3D {
+	.attr =3D {
+		 .name =3D "config",
+		 .mode =3D S_IRUGO | S_IWUSR,
+		 .owner =3D THIS_MODULE,
+		 },
+	.size =3D 0x200000,
+	.read =3D rio_read_config,
+	.write =3D rio_write_config,
+};
+
+/**
+ * rio_create_sysfs_dev_files - create RIO specific sysfs files
+ * @rdev: device whose entries should be created
+ *
+ * Create files when @rdev is added to sysfs.
+ */
+int rio_create_sysfs_dev_files(struct rio_dev *rdev)
+{
+	sysfs_create_bin_file(&rdev->dev.kobj, &rio_config_attr);
+
+	return 0;
+}
+
+/**
+ * rio_remove_sysfs_dev_files - cleanup RIO specific sysfs files
+ * @rdev: device whose entries we should free
+ *
+ * Cleanup when @rdev is removed from sysfs.
+ */
+void rio_remove_sysfs_dev_files(struct rio_dev *rdev)
+{
+	sysfs_remove_bin_file(&rdev->dev.kobj, &rio_config_attr);
+}
diff --git a/drivers/rio/rio.c b/drivers/rio/rio.c
new file mode 100644
--- /dev/null
+++ b/drivers/rio/rio.c
@@ -0,0 +1,503 @@
+/*
+ * RapidIO interconnect services
+ * (RapidIO Interconnect Specification, http://www.rapidio.org)
+ *
+ * Copyright 2005 MontaVista Software, Inc.
+ * Matt Porter <mporter@kernel.crashing.org>
+ *
+ * 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.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/rio.h>
+#include <linux/rio_drv.h>
+#include <linux/rio_ids.h>
+#include <linux/rio_regs.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+
+#include "rio.h"
+
+static LIST_HEAD(rio_mports);
+
+/**
+ * rio_local_get_device_id - Get the base/extended device id for a port
+ * @port: RIO master port from which to get the deviceid
+ *
+ * Reads the base/extended device id from the local device
+ * implementing the master port. Returns the 8/16-bit device
+ * id.
+ */
+u16 rio_local_get_device_id(struct rio_mport *port)
+{
+	u32 result;
+
+	rio_local_read_config_32(port, RIO_DID_CSR, &result);
+
+	return (RIO_GET_DID(result));
+}
+
+/**
+ * rio_request_inb_mbox - request inbound mailbox service
+ * @mport: RIO master port from which to allocate the mailbox resource
+ * @mbox: Mailbox number to claim
+ * @entries: Number of entries in inbound mailbox queue=20
+ * @minb: Callback to execute when inbound message is received
+ *
+ * Requests ownership of an inbound mailbox resource and binds
+ * a callback function to the resource. Returns %0 on success.
+ */
+int rio_request_inb_mbox(struct rio_mport *mport,
+			 int mbox,
+			 int entries,
+			 void (*minb) (struct rio_mport * mport, int mbox,
+				       int slot))
+{
+	int rc =3D 0;
+
+	struct resource *res =3D kmalloc(sizeof(struct resource), GFP_KERNEL);
+
+	if (res) {
+		rio_init_mbox_res(res, mbox, mbox);
+
+		/* Make sure this mailbox isn't in use */
+		if ((rc =3D
+		     request_resource(&mport->riores[RIO_INB_MBOX_RESOURCE],
+				      res)) < 0) {
+			kfree(res);
+			goto out;
+		}
+
+		mport->inb_msg[mbox].res =3D res;
+
+		/* Hook the inbound message callback */
+		mport->inb_msg[mbox].mcback =3D minb;
+
+		rc =3D rio_open_inb_mbox(mport, mbox, entries);
+	} else
+		rc =3D -ENOMEM;
+
+      out:
+	return rc;
+}
+
+/**
+ * rio_release_inb_mbox - release inbound mailbox message service
+ * @mport: RIO master port from which to release the mailbox resource
+ * @mbox: Mailbox number to release
+ *
+ * Releases ownership of an inbound mailbox resource. Returns 0
+ * if the request has been satisfied.
+ */
+int rio_release_inb_mbox(struct rio_mport *mport, int mbox)
+{
+	rio_close_inb_mbox(mport, mbox);
+
+	/* Release the mailbox resource */
+	return release_resource(mport->inb_msg[mbox].res);
+}
+
+/**
+ * rio_request_outb_mbox - request outbound mailbox service
+ * @mport: RIO master port from which to allocate the mailbox resource
+ * @mbox: Mailbox number to claim
+ * @entries: Number of entries in outbound mailbox queue=20
+ * @moutb: Callback to execute when outbound message is sent
+ *
+ * Requests ownership of an outbound mailbox resource and binds
+ * a callback function to the resource. Returns 0 on success.
+ */
+int rio_request_outb_mbox(struct rio_mport *mport,
+			  int mbox,
+			  int entries,
+			  void (*moutb) (struct rio_mport * mport, int mbox,
+					 int slot))
+{
+	int rc =3D 0;
+
+	struct resource *res =3D kmalloc(sizeof(struct resource), GFP_KERNEL);
+
+	if (res) {
+		rio_init_mbox_res(res, mbox, mbox);
+
+		/* Make sure this outbound mailbox isn't in use */
+		if ((rc =3D
+		     request_resource(&mport->riores[RIO_OUTB_MBOX_RESOURCE],
+				      res)) < 0) {
+			kfree(res);
+			goto out;
+		}
+
+		mport->outb_msg[mbox].res =3D res;
+
+		/* Hook the inbound message callback */
+		mport->outb_msg[mbox].mcback =3D moutb;
+
+		rc =3D rio_open_outb_mbox(mport, mbox, entries);
+	} else
+		rc =3D -ENOMEM;
+
+      out:
+	return rc;
+}
+
+/**
+ * rio_release_outb_mbox - release outbound mailbox message service
+ * @mport: RIO master port from which to release the mailbox resource
+ * @mbox: Mailbox number to release
+ *
+ * Releases ownership of an inbound mailbox resource. Returns 0
+ * if the request has been satisfied.
+ */
+int rio_release_outb_mbox(struct rio_mport *mport, int mbox)
+{
+	rio_close_outb_mbox(mport, mbox);
+
+	/* Release the mailbox resource */
+	return release_resource(mport->outb_msg[mbox].res);
+}
+
+/**
+ * rio_setup_inb_dbell - bind inbound doorbell callback
+ * @mport: RIO master port to bind the doorbell callback
+ * @res: Doorbell message resource
+ * @dinb: Callback to execute when doorbell is received
+ *
+ * Adds a doorbell resource/callback pair into a port's
+ * doorbell event list. Returns 0 if the request has been
+ * satisfied.
+ */
+static int
+rio_setup_inb_dbell(struct rio_mport *mport, struct resource *res,
+		    void (*dinb) (struct rio_mport * mport, u16 src, u16 dst,
+				  u16 info))
+{
+	int rc =3D 0;
+	struct rio_dbell *dbell;
+
+	if (!(dbell =3D kmalloc(sizeof(struct rio_dbell), GFP_KERNEL))) {
+		rc =3D -ENOMEM;
+		goto out;
+	}
+
+	dbell->res =3D res;
+	dbell->dinb =3D dinb;
+
+	list_add_tail(&dbell->node, &mport->dbells);
+
+      out:
+	return rc;
+}
+
+/**
+ * rio_request_inb_dbell - request inbound doorbell message service
+ * @mport: RIO master port from which to allocate the doorbell resource
+ * @start: Doorbell info range start
+ * @end: Doorbell info range end
+ * @dinb: Callback to execute when doorbell is received
+ *
+ * Requests ownership of an inbound doorbell resource and binds
+ * a callback function to the resource. Returns 0 if the request
+ * has been satisfied.
+ */
+int rio_request_inb_dbell(struct rio_mport *mport,
+			  u16 start,
+			  u16 end,
+			  void (*dinb) (struct rio_mport * mport, u16 src,
+					u16 dst, u16 info))
+{
+	int rc =3D 0;
+
+	struct resource *res =3D kmalloc(sizeof(struct resource), GFP_KERNEL);
+
+	if (res) {
+		rio_init_dbell_res(res, start, end);
+
+		/* Make sure these doorbells aren't in use */
+		if ((rc =3D
+		     request_resource(&mport->riores[RIO_DOORBELL_RESOURCE],
+				      res)) < 0) {
+			kfree(res);
+			goto out;
+		}
+
+		/* Hook the doorbell callback */
+		rc =3D rio_setup_inb_dbell(mport, res, dinb);
+	} else
+		rc =3D -ENOMEM;
+
+      out:
+	return rc;
+}
+
+/**
+ * rio_release_inb_dbell - release inbound doorbell message service
+ * @mport: RIO master port from which to release the doorbell resource
+ * @start: Doorbell info range start
+ * @end: Doorbell info range end
+ *
+ * Releases ownership of an inbound doorbell resource and removes
+ * callback from the doorbell event list. Returns 0 if the request
+ * has been satisfied.
+ */
+int rio_release_inb_dbell(struct rio_mport *mport, u16 start, u16 end)
+{
+	int rc =3D 0, found =3D 0;
+	struct rio_dbell *dbell;
+
+	list_for_each_entry(dbell, &mport->dbells, node) {
+		if ((dbell->res->start =3D=3D start) && (dbell->res->end =3D=3D end)) {
+			found =3D 1;
+			break;
+		}
+	}
+
+	/* If we can't find an exact match, fail */
+	if (!found) {
+		rc =3D -EINVAL;
+		goto out;
+	}
+
+	/* Delete from list */
+	list_del(&dbell->node);
+
+	/* Release the doorbell resource */
+	rc =3D release_resource(dbell->res);
+
+	/* Free the doorbell event */
+	kfree(dbell);
+
+      out:
+	return rc;
+}
+
+/**
+ * rio_request_outb_dbell - request outbound doorbell message range
+ * @rdev: RIO device from which to allocate the doorbell resource
+ * @start: Doorbell message range start
+ * @end: Doorbell message range end
+ *
+ * Requests ownership of a doorbell message range. Returns a resource
+ * if the request has been satisfied or %NULL on failure.
+ */
+struct resource *rio_request_outb_dbell(struct rio_dev *rdev, u16 start,
+					u16 end)
+{
+	struct resource *res =3D kmalloc(sizeof(struct resource), GFP_KERNEL);
+
+	if (res) {
+		rio_init_dbell_res(res, start, end);
+
+		/* Make sure these doorbells aren't in use */
+		if (request_resource(&rdev->riores[RIO_DOORBELL_RESOURCE], res)
+		    < 0) {
+			kfree(res);
+			res =3D NULL;
+		}
+	}
+
+	return res;
+}
+
+/**
+ * rio_release_outb_dbell - release outbound doorbell message range
+ * @rdev: RIO device from which to release the doorbell resource
+ * @res: Doorbell resource to be freed
+ *
+ * Releases ownership of a doorbell message range. Returns 0 if the
+ * request has been satisfied.
+ */
+int rio_release_outb_dbell(struct rio_dev *rdev, struct resource *res)
+{
+	int rc =3D release_resource(res);
+
+	kfree(res);
+
+	return rc;
+}
+
+/**
+ * rio_mport_get_feature - query for devices' extended features
+ * @port: Master port to issue transaction
+ * @local: Indicate a local master port or remote device access
+ * @destid: Destination ID of the device
+ * @hopcount: Number of switch hops to the device
+ * @ftr: Extended feature code
+ *
+ * Tell if a device supports a given RapidIO capability.
+ * Returns the offset of the requested extended feature
+ * block within the device's RIO configuration space or
+ * 0 in case the device does not support it.  Possible
+ * values for @ftr:
+ *
+ * %RIO_EFB_PAR_EP_ID		LP/LVDS EP Devices
+ *
+ * %RIO_EFB_PAR_EP_REC_ID	LP/LVDS EP Recovery Devices
+ *
+ * %RIO_EFB_PAR_EP_FREE_ID	LP/LVDS EP Free Devices
+ *
+ * %RIO_EFB_SER_EP_ID		LP/Serial EP Devices
+ *
+ * %RIO_EFB_SER_EP_REC_ID	LP/Serial EP Recovery Devices
+ *
+ * %RIO_EFB_SER_EP_FREE_ID	LP/Serial EP Free Devices
+ */
+u32
+rio_mport_get_feature(struct rio_mport * port, int local, u16 destid,
+		      u8 hopcount, int ftr)
+{
+	u32 asm_info, ext_ftr_ptr, ftr_header;
+
+	if (local)
+		rio_local_read_config_32(port, RIO_ASM_INFO_CAR, &asm_info);
+	else
+		rio_mport_read_config_32(port, destid, hopcount,
+					 RIO_ASM_INFO_CAR, &asm_info);
+
+	ext_ftr_ptr =3D asm_info & RIO_EXT_FTR_PTR_MASK;
+
+	while (ext_ftr_ptr) {
+		if (local)
+			rio_local_read_config_32(port, ext_ftr_ptr,
+						 &ftr_header);
+		else
+			rio_mport_read_config_32(port, destid, hopcount,
+						 ext_ftr_ptr, &ftr_header);
+		if (RIO_GET_BLOCK_ID(ftr_header) =3D=3D ftr)
+			return ext_ftr_ptr;
+		if (!(ext_ftr_ptr =3D RIO_GET_BLOCK_PTR(ftr_header)))
+			break;
+	}
+
+	return 0;
+}
+
+/**
+ * rio_get_asm - Begin or continue searching for a RIO device by vid/did/a=
sm_vid/asm_did
+ * @vid: RIO vid to match or %RIO_ANY_ID to match all vids
+ * @did: RIO did to match or %RIO_ANY_ID to match all dids
+ * @asm_vid: RIO asm_vid to match or %RIO_ANY_ID to match all asm_vids
+ * @asm_did: RIO asm_did to match or %RIO_ANY_ID to match all asm_dids
+ * @from: Previous RIO device found in search, or %NULL for new search
+ *
+ * Iterates through the list of known RIO devices. If a RIO device is
+ * found with a matching @vid, @did, @asm_vid, @asm_did, the reference
+ * count to the device is incrememted and a pointer to its device
+ * structure is returned. Otherwise, %NULL is returned. A new search
+ * is initiated by passing %NULL to the @from argument. Otherwise, if
+ * @from is not %NULL, searches continue from next device on the global
+ * list. The reference count for @from is always decremented if it is
+ * not %NULL.
+ */
+struct rio_dev *rio_get_asm(u16 vid, u16 did,
+			    u16 asm_vid, u16 asm_did, struct rio_dev *from)
+{
+	struct list_head *n;
+	struct rio_dev *rdev;
+
+	WARN_ON(in_interrupt());
+	spin_lock(&rio_global_list_lock);
+	n =3D from ? from->global_list.next : rio_devices.next;
+
+	while (n && (n !=3D &rio_devices)) {
+		rdev =3D rio_dev_g(n);
+		if ((vid =3D=3D RIO_ANY_ID || rdev->vid =3D=3D vid) &&
+		    (did =3D=3D RIO_ANY_ID || rdev->did =3D=3D did) &&
+		    (asm_vid =3D=3D RIO_ANY_ID || rdev->asm_vid =3D=3D asm_vid) &&
+		    (asm_did =3D=3D RIO_ANY_ID || rdev->asm_did =3D=3D asm_did))
+			goto exit;
+		n =3D n->next;
+	}
+	rdev =3D NULL;
+      exit:
+	rio_dev_put(from);
+	rdev =3D rio_dev_get(rdev);
+	spin_unlock(&rio_global_list_lock);
+	return rdev;
+}
+
+/**
+ * rio_get_device - Begin or continue searching for a RIO device by vid/did
+ * @vid: RIO vid to match or %RIO_ANY_ID to match all vids
+ * @did: RIO did to match or %RIO_ANY_ID to match all dids
+ * @from: Previous RIO device found in search, or %NULL for new search
+ *
+ * Iterates through the list of known RIO devices. If a RIO device is
+ * found with a matching @vid and @did, the reference count to the
+ * device is incrememted and a pointer to its device structure is returned.
+ * Otherwise, %NULL is returned. A new search is initiated by passing %NULL
+ * to the @from argument. Otherwise, if @from is not %NULL, searches
+ * continue from next device on the global list. The reference count for
+ * @from is always decremented if it is not %NULL.
+ */
+struct rio_dev *rio_get_device(u16 vid, u16 did, struct rio_dev *from)
+{
+	return rio_get_asm(vid, did, RIO_ANY_ID, RIO_ANY_ID, from);
+}
+
+static void rio_fixup_device(struct rio_dev *dev)
+{
+}
+
+static int __devinit rio_init(void)
+{
+	struct rio_dev *dev =3D NULL;
+
+	while ((dev =3D rio_get_device(RIO_ANY_ID, RIO_ANY_ID, dev)) !=3D NULL) {
+		rio_fixup_device(dev);
+	}
+	return 0;
+}
+
+device_initcall(rio_init);
+
+int rio_init_mports(void)
+{
+	int rc =3D 0;
+	struct rio_mport *port;
+
+	list_for_each_entry(port, &rio_mports, node) {
+		if (!request_mem_region(port->iores.start,
+					port->iores.end - port->iores.start,
+					port->name)) {
+			printk(KERN_ERR
+			       "RIO: Error requesting master port region %8.8lx-%8.8lx\n",
+			       port->iores.start, port->iores.end - 1);
+			rc =3D -ENOMEM;
+			goto out;
+		}
+
+		if (port->host_deviceid >=3D 0)
+			rio_enum_mport(port);
+		else
+			rio_disc_mport(port);
+	}
+
+      out:
+	return rc;
+}
+
+void rio_register_mport(struct rio_mport *port)
+{
+	list_add_tail(&port->node, &rio_mports);
+}
+
+EXPORT_SYMBOL_GPL(rio_local_get_device_id);
+EXPORT_SYMBOL_GPL(rio_get_device);
+EXPORT_SYMBOL_GPL(rio_get_asm);
+EXPORT_SYMBOL_GPL(rio_request_inb_dbell);
+EXPORT_SYMBOL_GPL(rio_release_inb_dbell);
+EXPORT_SYMBOL_GPL(rio_request_outb_dbell);
+EXPORT_SYMBOL_GPL(rio_release_outb_dbell);
+EXPORT_SYMBOL_GPL(rio_request_inb_mbox);
+EXPORT_SYMBOL_GPL(rio_release_inb_mbox);
+EXPORT_SYMBOL_GPL(rio_request_outb_mbox);
+EXPORT_SYMBOL_GPL(rio_release_outb_mbox);
diff --git a/drivers/rio/rio.h b/drivers/rio/rio.h
new file mode 100644
--- /dev/null
+++ b/drivers/rio/rio.h
@@ -0,0 +1,57 @@
+/*
+ * RapidIO interconnect services
+ *
+ * Copyright 2005 MontaVista Software, Inc.
+ * Matt Porter <mporter@kernel.crashing.org>
+ *
+ * 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.
+ */
+
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/rio.h>
+
+/* Functions internal to the RIO core code */
+
+extern u32 rio_mport_get_feature(struct rio_mport *mport, int local, u16 d=
estid,
+				 u8 hopcount, int ftr);
+extern int rio_create_sysfs_dev_files(struct rio_dev *rdev);
+extern int rio_enum_mport(struct rio_mport *mport);
+extern int rio_disc_mport(struct rio_mport *mport);
+
+/* Structures internal to the RIO core code */
+extern struct device_attribute rio_dev_attrs[];
+extern spinlock_t rio_global_list_lock;
+
+/* Helpers internal to the RIO core code */
+#define DECLARE_RIO_ROUTE_SECTION(section, vid, did, add_hook, get_hook)  \
+        static struct rio_route_ops __rio_route_ops __attribute_used__   \
+	        __attribute__((__section__(#section))) =3D { vid, did, add_hook, =
get_hook };
+
+/**
+ * DECLARE_RIO_ROUTE_OPS - Registers switch routing operations
+ * @vid: RIO vendor ID
+ * @did: RIO device ID
+ * @add_hook: Callback that adds a route entry
+ * @get_hook: Callback that gets a route entry
+ *
+ * Manipulating switch route tables in RIO is switch specific. This
+ * registers a switch by vendor and device ID with two callbacks for
+ * modifying and retrieving route entries in a switch. A &struct
+ * rio_route_ops is initialized with the ops and placed into a
+ * RIO-specific kernel section.
+ */
+#define DECLARE_RIO_ROUTE_OPS(vid, did, add_hook, get_hook)		\
+	DECLARE_RIO_ROUTE_SECTION(.rio_route_ops,			\
+			vid, did, add_hook, get_hook)
+
+#ifdef CONFIG_RAPIDIO_8_BIT_TRANSPORT
+#define RIO_GET_DID(x)	((x & 0x00ff0000) >> 16)
+#define RIO_SET_DID(x)	((x & 0x000000ff) << 16)
+#else
+#define RIO_GET_DID(x)	(x & 0xffff)
+#define RIO_SET_DID(x)	(x & 0xffff)
+#endif
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinu=
x.lds.h
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -32,6 +32,13 @@
 		VMLINUX_SYMBOL(__end_pci_fixups_enable) =3D .;		\
 	}								\
 									\
+	/* RapidIO route ops */						\
+	.rio_route        : AT(ADDR(.rio_route) - LOAD_OFFSET) {	\
+		VMLINUX_SYMBOL(__start_rio_route_ops) =3D .;		\
+		*(.rio_route_ops)					\
+		VMLINUX_SYMBOL(__end_rio_route_ops) =3D .;		\
+	}								\
+									\
 	/* Kernel symbol table: Normal symbols */			\
 	__ksymtab         : AT(ADDR(__ksymtab) - LOAD_OFFSET) {		\
 		VMLINUX_SYMBOL(__start___ksymtab) =3D .;			\

[PATCH][5/5] RapidIO support: net driver

From: Matt Porter <mporter@kernel.crashing.org>
Date: 2005-06-06 22:47:55

Adds an "Ethernet" driver which sends Ethernet packets over the
standard RapidIO messaging. This depends on the core RIO
patch for mailbox/doorbell access.

Signed-off-by: Matt Porter <mporter@kernel.crashing.org>
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -2185,6 +2185,20 @@ config ISERIES_VETH
 	tristate "iSeries Virtual Ethernet driver support"
 	depends on NETDEVICES && PPC_ISERIES
=20
+config RIONET
+	tristate "RapidIO Ethernet over messaging driver support"
+	depends on NETDEVICES && RAPIDIO
+
+config RIONET_TX_SIZE
+	int "Number of outbound queue entries"
+	depends on RIONET
+	default "128"
+
+config RIONET_RX_SIZE
+	int "Number of inbound queue entries"
+	depends on RIONET
+	default "128"
+
 config FDDI
 	bool "FDDI driver support"
 	depends on NETDEVICES && (PCI || EISA)
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -58,6 +58,7 @@ obj-$(CONFIG_SKFP) +=3D skfp/
 obj-$(CONFIG_VIA_RHINE) +=3D via-rhine.o
 obj-$(CONFIG_VIA_VELOCITY) +=3D via-velocity.o
 obj-$(CONFIG_ADAPTEC_STARFIRE) +=3D starfire.o
+obj-$(CONFIG_RIONET) +=3D rionet.o
=20
 #
 # end link order section
diff --git a/drivers/net/rionet.c b/drivers/net/rionet.c
new file mode 100644
--- /dev/null
+++ b/drivers/net/rionet.c
@@ -0,0 +1,597 @@
+/*
+ * rionet - Ethernet driver over RapidIO messaging services
+ *
+ * Copyright 2005 MontaVista Software, Inc.
+ * Matt Porter <mporter@kernel.crashing.org>
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/rio.h>
+#include <linux/rio_drv.h>
+#include <linux/rio_ids.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/crc32.h>
+#include <linux/ethtool.h>
+
+#define DRV_NAME        "rionet"
+#define DRV_VERSION     "0.1"
+#define DRV_AUTHOR      "Matt Porter <mporter@kernel.crashing.org>"
+#define DRV_DESC        "Ethernet over RapidIO"
+
+MODULE_AUTHOR(DRV_AUTHOR);
+MODULE_DESCRIPTION(DRV_DESC);
+MODULE_LICENSE("GPL");
+
+#define RIONET_DEFAULT_MSGLEVEL	0
+#define RIONET_DOORBELL_JOIN	0x1000
+#define RIONET_DOORBELL_LEAVE	0x1001
+
+#define RIONET_MAILBOX		0
+
+#define RIONET_TX_RING_SIZE	CONFIG_RIONET_TX_SIZE
+#define RIONET_RX_RING_SIZE	CONFIG_RIONET_RX_SIZE
+
+static LIST_HEAD(rionet_peers);
+
+struct rionet_private {
+	struct rio_mport *mport;
+	struct sk_buff *rx_skb[RIONET_RX_RING_SIZE];
+	struct sk_buff *tx_skb[RIONET_TX_RING_SIZE];
+	struct net_device_stats stats;
+	int rx_slot;
+	int tx_slot;
+	int tx_cnt;
+	int ack_slot;
+	spinlock_t lock;
+	spinlock_t tx_lock;
+	u32 msg_enable;
+};
+
+struct rionet_peer {
+	struct list_head node;
+	struct rio_dev *rdev;
+	struct resource *res;
+};
+
+static int rionet_check =3D 0;
+static int rionet_capable =3D 1;
+static struct net_device *sndev =3D NULL;
+
+/*
+ * This is a fast lookup table for for translating TX
+ * Ethernet packets into a destination RIO device. It
+ * could be made into a hash table to save memory depending
+ * on system trade-offs.
+ */
+static struct rio_dev *rionet_active[RIO_MAX_ROUTE_ENTRIES];
+
+#define is_rionet_capable(pef, src_ops, dst_ops)		\
+			((pef & RIO_PEF_INB_MBOX) &&		\
+			 (pef & RIO_PEF_INB_DOORBELL) &&	\
+			 (src_ops & RIO_SRC_OPS_DOORBELL) &&	\
+			 (dst_ops & RIO_DST_OPS_DOORBELL))
+#define dev_rionet_capable(dev) \
+	is_rionet_capable(dev->pef, dev->src_ops, dev->dst_ops)
+
+#define RIONET_MAC_MATCH(x)	(*(u32 *)x =3D=3D 0x00010001)
+#define RIONET_GET_DESTID(x)	(*(u16 *)(x + 4))
+
+static struct net_device_stats *rionet_stats(struct net_device *ndev)
+{
+	struct rionet_private *rnet =3D ndev->priv;
+	return &rnet->stats;
+}
+
+static int rionet_rx_clean(struct net_device *ndev)
+{
+	int i;
+	int error =3D 0;
+	struct rionet_private *rnet =3D ndev->priv;
+	void *data;
+
+	i =3D rnet->rx_slot;
+
+	do {
+		if (!rnet->rx_skb[i]) {
+			rnet->stats.rx_dropped++;
+			continue;
+		}
+
+		if (!(data =3D rio_get_inb_message(rnet->mport, RIONET_MAILBOX)))
+			break;
+
+		rnet->rx_skb[i]->data =3D data;
+		skb_put(rnet->rx_skb[i], RIO_MAX_MSG_SIZE);
+		rnet->rx_skb[i]->dev =3D ndev;
+		rnet->rx_skb[i]->protocol =3D
+		    eth_type_trans(rnet->rx_skb[i], ndev);
+		error =3D netif_rx(rnet->rx_skb[i]);
+
+		if (error =3D=3D NET_RX_DROP) {
+			rnet->stats.rx_dropped++;
+		} else if (error =3D=3D NET_RX_BAD) {
+			if (netif_msg_rx_err(rnet))
+				printk(KERN_WARNING "%s: bad rx packet\n",
+				       DRV_NAME);
+			rnet->stats.rx_errors++;
+		} else {
+			rnet->stats.rx_packets++;
+			rnet->stats.rx_bytes +=3D RIO_MAX_MSG_SIZE;
+		}
+
+	} while ((i =3D (i + 1) % RIONET_RX_RING_SIZE) !=3D rnet->rx_slot);
+
+	return i;
+}
+
+static void rionet_rx_fill(struct net_device *ndev, int end)
+{
+	int i;
+	struct rionet_private *rnet =3D ndev->priv;
+
+	i =3D rnet->rx_slot;
+	do {
+		rnet->rx_skb[i] =3D dev_alloc_skb(RIO_MAX_MSG_SIZE);
+
+		if (!rnet->rx_skb[i])
+			break;
+
+		rio_add_inb_buffer(rnet->mport, RIONET_MAILBOX,
+				   rnet->rx_skb[i]->data);
+	} while ((i =3D (i + 1) % RIONET_RX_RING_SIZE) !=3D end);
+
+	rnet->rx_slot =3D i;
+}
+
+static int rionet_queue_tx_msg(struct sk_buff *skb, struct net_device *nde=
v,
+			       struct rio_dev *rdev)
+{
+	struct rionet_private *rnet =3D ndev->priv;
+
+	rio_add_outb_message(rnet->mport, rdev, 0, skb->data, skb->len);
+	rnet->tx_skb[rnet->tx_slot] =3D skb;
+
+	rnet->stats.tx_packets++;
+	rnet->stats.tx_bytes +=3D skb->len;
+
+	if (++rnet->tx_cnt =3D=3D RIONET_TX_RING_SIZE)
+		netif_stop_queue(ndev);
+
+	if (++rnet->tx_slot =3D=3D RIONET_TX_RING_SIZE)
+		rnet->tx_slot =3D 0;
+
+	if (netif_msg_tx_queued(rnet))
+		printk(KERN_INFO "%s: queued skb %8.8x len %8.8x\n", DRV_NAME,
+		       (u32) skb, skb->len);
+
+	return 0;
+}
+
+static int rionet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
+{
+	int i;
+	struct rionet_private *rnet =3D ndev->priv;
+	struct ethhdr *eth =3D (struct ethhdr *)skb->data;
+	u16 destid;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	if (!spin_trylock(&rnet->tx_lock)) {
+		local_irq_restore(flags);
+		return NETDEV_TX_LOCKED;
+	}
+=09
+	if ((rnet->tx_cnt + 1) > RIONET_TX_RING_SIZE) {
+		netif_stop_queue(ndev);
+		spin_unlock_irqrestore(&rnet->tx_lock, flags);
+		printk(KERN_ERR "%s: BUG! Tx Ring full when queue awake!\n",
+		       ndev->name);
+		return NETDEV_TX_BUSY;
+	}
+
+	if (eth->h_dest[0] & 0x01) {
+		/*
+		 * XXX Need to delay queuing if ring max is reached,
+		 * flush additional packets in tx_event() before
+		 * awakening the queue. We can easily exceed ring
+		 * size with a large number of nodes or even a
+		 * small number where the ring is relatively full
+		 * on entrance to hard_start_xmit.
+		 */
+		for (i =3D 0; i < RIO_MAX_ROUTE_ENTRIES; i++)
+			if (rionet_active[i])
+				rionet_queue_tx_msg(skb, ndev,
+						    rionet_active[i]);
+	} else if (RIONET_MAC_MATCH(eth->h_dest)) {
+		destid =3D RIONET_GET_DESTID(eth->h_dest);
+		if (rionet_active[destid])
+			rionet_queue_tx_msg(skb, ndev, rionet_active[destid]);
+	}
+
+	spin_unlock_irqrestore(&rnet->tx_lock, flags);
+
+	return 0;
+}
+
+static int rionet_set_mac_address(struct net_device *ndev, void *p)
+{
+	struct sockaddr *addr =3D p;
+
+	if (!is_valid_ether_addr(addr->sa_data))
+		return -EADDRNOTAVAIL;
+
+	memcpy(ndev->dev_addr, addr->sa_data, ndev->addr_len);
+
+	return 0;
+}
+
+static void rionet_dbell_event(struct rio_mport *mport, u16 sid, u16 tid,
+			       u16 info)
+{
+	struct net_device *ndev =3D sndev;
+	struct rionet_private *rnet =3D ndev->priv;
+	struct rionet_peer *peer;
+
+	if (netif_msg_intr(rnet))
+		printk(KERN_INFO "%s: doorbell sid %4.4x tid %4.4x info %4.4x",
+		       DRV_NAME, sid, tid, info);
+	if (info =3D=3D RIONET_DOORBELL_JOIN) {
+		if (!rionet_active[sid]) {
+			list_for_each_entry(peer, &rionet_peers, node) {
+				if (peer->rdev->destid =3D=3D sid)
+					rionet_active[sid] =3D peer->rdev;
+			}
+			rio_mport_send_doorbell(mport, sid,
+						RIONET_DOORBELL_JOIN);
+		}
+	} else if (info =3D=3D RIONET_DOORBELL_LEAVE) {
+		rionet_active[sid] =3D NULL;
+	} else {
+		if (netif_msg_intr(rnet))
+			printk(KERN_WARNING "%s: unhandled doorbell\n",
+			       DRV_NAME);
+	}
+}
+
+static void rionet_inb_msg_event(struct rio_mport *mport, int mbox, int sl=
ot)
+{
+	int n;
+	struct net_device *ndev =3D sndev;
+	struct rionet_private *rnet =3D (struct rionet_private *)ndev->priv;
+
+	if (netif_msg_intr(rnet))
+		printk(KERN_INFO "%s: inbound message event, mbox %d slot %d\n",
+		       DRV_NAME, mbox, slot);
+
+	spin_lock(&rnet->lock);
+	if ((n =3D rionet_rx_clean(ndev)) !=3D rnet->rx_slot)
+		rionet_rx_fill(ndev, n);
+	spin_unlock(&rnet->lock);
+}
+
+static void rionet_outb_msg_event(struct rio_mport *mport, int mbox, int s=
lot)
+{
+	struct net_device *ndev =3D sndev;
+	struct rionet_private *rnet =3D ndev->priv;
+
+	spin_lock(&rnet->lock);
+
+	if (netif_msg_intr(rnet))
+		printk(KERN_INFO
+		       "%s: outbound message event, mbox %d slot %d\n",
+		       DRV_NAME, mbox, slot);
+
+	while (rnet->tx_cnt && (rnet->ack_slot !=3D slot)) {
+		/* dma unmap single */
+		dev_kfree_skb_irq(rnet->tx_skb[rnet->ack_slot]);
+		rnet->tx_skb[rnet->ack_slot] =3D NULL;
+		if (++rnet->ack_slot =3D=3D RIONET_TX_RING_SIZE)
+			rnet->ack_slot =3D 0;
+		rnet->tx_cnt--;
+	}
+
+	if (rnet->tx_cnt < RIONET_TX_RING_SIZE)
+		netif_wake_queue(ndev);
+
+	spin_unlock(&rnet->lock);
+}
+
+static int rionet_open(struct net_device *ndev)
+{
+	int i, rc =3D 0;
+	struct rionet_peer *peer, *tmp;
+	u32 pwdcsr;
+	struct rionet_private *rnet =3D ndev->priv;
+
+	if (netif_msg_ifup(rnet))
+		printk(KERN_INFO "%s: open\n", DRV_NAME);
+
+	if ((rc =3D rio_request_inb_dbell(rnet->mport,
+					RIONET_DOORBELL_JOIN,
+					RIONET_DOORBELL_LEAVE,
+					rionet_dbell_event)) < 0)
+		goto out;
+
+	if ((rc =3D rio_request_inb_mbox(rnet->mport,
+				       RIONET_MAILBOX,
+				       RIONET_RX_RING_SIZE,
+				       rionet_inb_msg_event)) < 0)
+		goto out;
+
+	if ((rc =3D rio_request_outb_mbox(rnet->mport,
+					RIONET_MAILBOX,
+					RIONET_TX_RING_SIZE,
+					rionet_outb_msg_event)) < 0)
+		goto out;
+
+	/* Initialize inbound message ring */
+	for (i =3D 0; i < RIONET_RX_RING_SIZE; i++)
+		rnet->rx_skb[i] =3D NULL;
+	rnet->rx_slot =3D 0;
+	rionet_rx_fill(ndev, 0);
+
+	rnet->tx_slot =3D 0;
+	rnet->tx_cnt =3D 0;
+	rnet->ack_slot =3D 0;
+
+	netif_carrier_on(ndev);
+	netif_start_queue(ndev);
+
+	list_for_each_entry_safe(peer, tmp, &rionet_peers, node) {
+		if (!(peer->res =3D rio_request_outb_dbell(peer->rdev,
+							 RIONET_DOORBELL_JOIN,
+							 RIONET_DOORBELL_LEAVE)))
+		{
+			printk(KERN_ERR "%s: error requesting doorbells\n",
+			       DRV_NAME);
+			continue;
+		}
+
+		/*
+		 * If device has initialized inbound doorbells,
+		 * send a join message
+		 */
+		rio_read_config_32(peer->rdev, RIO_WRITE_PORT_CSR, &pwdcsr);
+		if (pwdcsr & RIO_DOORBELL_AVAIL)
+			rio_send_doorbell(peer->rdev, RIONET_DOORBELL_JOIN);
+	}
+
+      out:
+	return rc;
+}
+
+static int rionet_close(struct net_device *ndev)
+{
+	struct rionet_private *rnet =3D (struct rionet_private *)ndev->priv;
+	struct rionet_peer *peer, *tmp;
+	int i;
+
+	if (netif_msg_ifup(rnet))
+		printk(KERN_INFO "%s: close\n", DRV_NAME);
+
+	netif_stop_queue(ndev);
+	netif_carrier_off(ndev);
+
+	for (i =3D 0; i < RIONET_RX_RING_SIZE; i++)
+		if (rnet->rx_skb[i])
+			kfree_skb(rnet->rx_skb[i]);
+
+	list_for_each_entry_safe(peer, tmp, &rionet_peers, node) {
+		if (rionet_active[peer->rdev->destid]) {
+			rio_send_doorbell(peer->rdev, RIONET_DOORBELL_LEAVE);
+			rionet_active[peer->rdev->destid] =3D NULL;
+		}
+		rio_release_outb_dbell(peer->rdev, peer->res);
+	}
+
+	rio_release_inb_dbell(rnet->mport, RIONET_DOORBELL_JOIN,
+			      RIONET_DOORBELL_LEAVE);
+	rio_release_inb_mbox(rnet->mport, RIONET_MAILBOX);
+	rio_release_outb_mbox(rnet->mport, RIONET_MAILBOX);
+
+	return 0;
+}
+
+static void rionet_remove(struct rio_dev *rdev)
+{
+	struct net_device *ndev =3D NULL;
+	struct rionet_peer *peer, *tmp;
+
+	unregister_netdev(ndev);
+	kfree(ndev);
+
+	list_for_each_entry_safe(peer, tmp, &rionet_peers, node) {
+		list_del(&peer->node);
+		kfree(peer);
+	}
+}
+
+static void rionet_get_drvinfo(struct net_device *ndev,
+			       struct ethtool_drvinfo *info)
+{
+	struct rionet_private *rnet =3D ndev->priv;
+
+	strcpy(info->driver, DRV_NAME);
+	strcpy(info->version, DRV_VERSION);
+	strcpy(info->fw_version, "n/a");
+	sprintf(info->bus_info, "RIO master port %d", rnet->mport->id);
+}
+
+static u32 rionet_get_msglevel(struct net_device *ndev)
+{
+	struct rionet_private *rnet =3D ndev->priv;
+
+	return rnet->msg_enable;
+}
+
+static void rionet_set_msglevel(struct net_device *ndev, u32 value)
+{
+	struct rionet_private *rnet =3D ndev->priv;
+
+	rnet->msg_enable =3D value;
+}
+
+static struct ethtool_ops rionet_ethtool_ops =3D {
+	.get_drvinfo =3D rionet_get_drvinfo,
+	.get_msglevel =3D rionet_get_msglevel,
+	.set_msglevel =3D rionet_set_msglevel,
+	.get_link =3D ethtool_op_get_link,
+};
+
+static int rionet_setup_netdev(struct rio_mport *mport)
+{
+	int rc =3D 0;
+	struct net_device *ndev =3D NULL;
+	struct rionet_private *rnet;
+	u16 device_id;
+
+	/* Allocate our net_device structure */
+	ndev =3D alloc_etherdev(sizeof(struct rionet_private));
+	if (ndev =3D=3D NULL) {
+		printk(KERN_INFO "%s: could not allocate ethernet device.\n",
+		       DRV_NAME);
+		rc =3D -ENOMEM;
+		goto out;
+	}
+
+	/*
+	 * XXX hack, store point a static at ndev so we can get it...
+	 * Perhaps need an array of these that the handler can
+	 * index via the mbox number.
+	 */
+	sndev =3D ndev;
+
+	/* Set up private area */
+	rnet =3D (struct rionet_private *)ndev->priv;
+	rnet->mport =3D mport;
+
+	/* Set the default MAC address */
+	device_id =3D rio_local_get_device_id(mport);
+	ndev->dev_addr[0] =3D 0x00;
+	ndev->dev_addr[1] =3D 0x01;
+	ndev->dev_addr[2] =3D 0x00;
+	ndev->dev_addr[3] =3D 0x01;
+	ndev->dev_addr[4] =3D device_id >> 8;
+	ndev->dev_addr[5] =3D device_id & 0xff;
+
+	/* Fill in the driver function table */
+	ndev->open =3D &rionet_open;
+	ndev->hard_start_xmit =3D &rionet_start_xmit;
+	ndev->stop =3D &rionet_close;
+	ndev->get_stats =3D &rionet_stats;
+	ndev->set_mac_address =3D &rionet_set_mac_address;
+	ndev->mtu =3D RIO_MAX_MSG_SIZE - 14;
+	ndev->features =3D NETIF_F_LLTX;
+	SET_ETHTOOL_OPS(ndev, &rionet_ethtool_ops);
+
+	SET_MODULE_OWNER(ndev);
+
+	spin_lock_init(&rnet->lock);
+	spin_lock_init(&rnet->tx_lock);
+
+	rnet->msg_enable =3D RIONET_DEFAULT_MSGLEVEL;
+
+	rc =3D register_netdev(ndev);
+	if (rc !=3D 0)
+		goto out;
+
+	printk("%s: %s %s Version %s, MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+	       ndev->name,
+	       DRV_NAME,
+	       DRV_DESC,
+	       DRV_VERSION,
+	       ndev->dev_addr[0], ndev->dev_addr[1], ndev->dev_addr[2],
+	       ndev->dev_addr[3], ndev->dev_addr[4], ndev->dev_addr[5]);
+
+      out:
+	return rc;
+}
+
+/*
+ * XXX Make multi-net safe
+ */
+static int rionet_probe(struct rio_dev *rdev, const struct rio_device_id *=
id)
+{
+	int rc =3D -ENODEV;
+	u32 lpef, lsrc_ops, ldst_ops;
+	struct rionet_peer *peer;
+
+	/* If local device is not rionet capable, give up quickly */
+	if (!rionet_capable)
+		goto out;
+
+	/*
+	 * First time through, make sure local device is rionet
+	 * capable, setup netdev,  and set flags so this is skipped
+	 * on later probes
+	 */
+	if (!rionet_check) {
+		rio_local_read_config_32(rdev->net->hport, RIO_PEF_CAR, &lpef);
+		rio_local_read_config_32(rdev->net->hport, RIO_SRC_OPS_CAR,
+					 &lsrc_ops);
+		rio_local_read_config_32(rdev->net->hport, RIO_DST_OPS_CAR,
+					 &ldst_ops);
+		if (!is_rionet_capable(lpef, lsrc_ops, ldst_ops)) {
+			printk(KERN_ERR
+			       "%s: local device is not network capable\n",
+			       DRV_NAME);
+			rionet_check =3D 1;
+			rionet_capable =3D 0;
+			goto out;
+		}
+
+		rc =3D rionet_setup_netdev(rdev->net->hport);
+		rionet_check =3D 1;
+	}
+
+	/*
+	 * If the remote device has mailbox/doorbell capabilities,
+	 * add it to the peer list.
+	 */
+	if (dev_rionet_capable(rdev)) {
+		if (!(peer =3D kmalloc(sizeof(struct rionet_peer), GFP_KERNEL))) {
+			rc =3D -ENOMEM;
+			goto out;
+		}
+		peer->rdev =3D rdev;
+		list_add_tail(&peer->node, &rionet_peers);
+	}
+
+      out:
+	return rc;
+}
+
+static struct rio_device_id rionet_id_table[] =3D {
+	{RIO_DEVICE(RIO_ANY_ID, RIO_ANY_ID)}
+};
+
+static struct rio_driver rionet_driver =3D {
+	.name =3D "rionet",
+	.id_table =3D rionet_id_table,
+	.probe =3D rionet_probe,
+	.remove =3D rionet_remove,
+};
+
+static int __init rionet_init(void)
+{
+	return rio_register_driver(&rionet_driver);
+}
+
+static void __exit rionet_exit(void)
+{
+	rio_unregister_driver(&rionet_driver);
+}
+
+module_init(rionet_init);
+module_exit(rionet_exit);

[PATCH][3/5] RapidIO support: core enum

From: Matt Porter <mporter@kernel.crashing.org>
Date: 2005-06-06 22:53:41

Adds RapidIO enumeration/discovery.

The core code implements enumeration/discovery, management of
devices/resources, and interfaces for RIO drivers.

Signed-off-by: Matt Porter <mporter@kernel.crashing.org>
diff --git a/drivers/rio/rio-scan.c b/drivers/rio/rio-scan.c
new file mode 100644
--- /dev/null
+++ b/drivers/rio/rio-scan.c
@@ -0,0 +1,960 @@
+/*
+ * RapidIO enumeration and discovery support
+ *
+ * Copyright 2005 MontaVista Software, Inc.
+ * Matt Porter <mporter@kernel.crashing.org>
+ *
+ * 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.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/rio.h>
+#include <linux/rio_drv.h>
+#include <linux/rio_ids.h>
+#include <linux/rio_regs.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/timer.h>
+
+#include "rio.h"
+
+LIST_HEAD(rio_devices);
+static LIST_HEAD(rio_switches);
+
+#define RIO_ENUM_CMPL_MAGIC	0xdeadbeef
+
+static void rio_enum_timeout(unsigned long);
+
+spinlock_t rio_global_list_lock =3D SPIN_LOCK_UNLOCKED;
+static int next_destid =3D 0;
+static int next_switchid =3D 0;
+static int next_net =3D 0;
+
+static struct timer_list rio_enum_timer =3D
+TIMER_INITIALIZER(rio_enum_timeout, 0, 0);
+
+static int rio_mport_phys_table[] =3D {
+	RIO_EFB_PAR_EP_ID,
+	RIO_EFB_PAR_EP_REC_ID,
+	RIO_EFB_SER_EP_ID,
+	RIO_EFB_SER_EP_REC_ID,
+	-1,
+};
+
+static int rio_sport_phys_table[] =3D {
+	RIO_EFB_PAR_EP_FREE_ID,
+	RIO_EFB_SER_EP_FREE_ID,
+	-1,
+};
+
+extern struct rio_route_ops __start_rio_route_ops[];
+extern struct rio_route_ops __end_rio_route_ops[];
+
+/**
+ * rio_get_device_id - Get the base/extended device id for a device
+ * @port: RIO master port=20
+ * @destid: Destination ID of device
+ * @hopcount: Hopcount to device
+ *
+ * Reads the base/extended device id from a device. Returns the
+ * 8/16-bit device ID.
+ */
+static u16 rio_get_device_id(struct rio_mport *port, u16 destid, u8 hopcou=
nt)
+{
+	u32 result;
+
+	rio_mport_read_config_32(port, destid, hopcount, RIO_DID_CSR, &result);
+
+	return RIO_GET_DID(result);
+}
+
+/**
+ * rio_set_device_id - Set the base/extended device id for a device
+ * @port: RIO master port=20
+ * @destid: Destination ID of device
+ * @hopcount: Hopcount to device
+ * @did: Device ID value to be written
+ *
+ * Writes the base/extended device id from a device.
+ */
+static void
+rio_set_device_id(struct rio_mport *port, u16 destid, u8 hopcount, u16 did)
+{
+	rio_mport_write_config_32(port, destid, hopcount, RIO_DID_CSR,
+				  RIO_SET_DID(did));
+}
+
+/**
+ * rio_local_set_device_id - Set the base/extended device id for a port
+ * @port: RIO master port=20
+ * @did: Device ID value to be written
+ *
+ * Writes the base/extended device id from a device.
+ */
+static void rio_local_set_device_id(struct rio_mport *port, u16 did)
+{
+	rio_local_write_config_32(port, RIO_DID_CSR, RIO_SET_DID(did));
+}
+
+/**
+ * rio_clear_locks- Release all host locks and signal enumeration complete
+ * @port: Master port to issue transaction
+ *
+ * Marks the component tag CSR on each device with the enumeration
+ * complete flag. When complete, it then release the host locks on
+ * each device. Returns 0 on success or %-EINVAL on failure.
+ */
+static int rio_clear_locks(struct rio_mport *port)
+{
+	struct rio_dev *rdev;
+	u32 result;
+	int ret =3D 0;
+
+	/* Write component tag CSR magic complete value */
+	rio_local_write_config_32(port, RIO_COMPONENT_TAG_CSR,
+				  RIO_ENUM_CMPL_MAGIC);
+	list_for_each_entry(rdev, &rio_devices, global_list)
+	    rio_write_config_32(rdev, RIO_COMPONENT_TAG_CSR,
+				RIO_ENUM_CMPL_MAGIC);
+
+	/* Release host device id locks */
+	rio_local_write_config_32(port, RIO_HOST_DID_LOCK_CSR,
+				  port->host_deviceid);
+	rio_local_read_config_32(port, RIO_HOST_DID_LOCK_CSR, &result);
+	if ((result & 0xffff) !=3D 0xffff) {
+		printk(KERN_INFO
+		       "RIO: badness when releasing host lock on master port, result %8.=
8x\n",
+		       result);
+		ret =3D -EINVAL;
+	}
+	list_for_each_entry(rdev, &rio_devices, global_list) {
+		rio_write_config_32(rdev, RIO_HOST_DID_LOCK_CSR,
+				    port->host_deviceid);
+		rio_read_config_32(rdev, RIO_HOST_DID_LOCK_CSR, &result);
+		if ((result & 0xffff) !=3D 0xffff) {
+			printk(KERN_INFO
+			       "RIO: badness when releasing host lock on vid %4.4x did %4.4x\n",
+			       rdev->vid, rdev->did);
+			ret =3D -EINVAL;
+		}
+	}
+
+	return ret;
+}
+
+/**
+ * rio_enum_host- Set host lock and initialize host destination ID
+ * @port: Master port to issue transaction
+ *
+ * Sets the local host master port lock and destination ID register
+ * with the host device ID value. The host device ID value is provided
+ * by the platform. Returns %0 on success or %-1 on failure.
+ */
+static int rio_enum_host(struct rio_mport *port)
+{
+	u32 result;
+
+	/* Set master port host device id lock */
+	rio_local_write_config_32(port, RIO_HOST_DID_LOCK_CSR,
+				  port->host_deviceid);
+
+	rio_local_read_config_32(port, RIO_HOST_DID_LOCK_CSR, &result);
+	if ((result & 0xffff) !=3D port->host_deviceid)
+		return -1;
+
+	/* Set master port destid and init destid ctr */
+	rio_local_set_device_id(port, port->host_deviceid);
+
+	if (next_destid =3D=3D port->host_deviceid)
+		next_destid++;
+
+	return 0;
+}
+
+/**
+ * rio_device_has_destid- Test if a device contains a destination ID regis=
ter
+ * @port: Master port to issue transaction
+ * @src_ops: RIO device source operations
+ * @dst_ops: RIO device destination operations
+ *
+ * Checks the provided @src_ops and @dst_ops for the necessary transaction
+ * capabilities that indicate whether or not a device will implement a
+ * destination ID register. Returns 1 if true or 0 if false.
+ */
+static int rio_device_has_destid(struct rio_mport *port, int src_ops,
+				 int dst_ops)
+{
+	if (((src_ops & RIO_SRC_OPS_READ) ||
+	     (src_ops & RIO_SRC_OPS_WRITE) ||
+	     (src_ops & RIO_SRC_OPS_ATOMIC_TST_SWP) ||
+	     (src_ops & RIO_SRC_OPS_ATOMIC_INC) ||
+	     (src_ops & RIO_SRC_OPS_ATOMIC_DEC) ||
+	     (src_ops & RIO_SRC_OPS_ATOMIC_SET) ||
+	     (src_ops & RIO_SRC_OPS_ATOMIC_CLR)) &&
+	    ((dst_ops & RIO_DST_OPS_READ) ||
+	     (dst_ops & RIO_DST_OPS_WRITE) ||
+	     (dst_ops & RIO_DST_OPS_ATOMIC_TST_SWP) ||
+	     (dst_ops & RIO_DST_OPS_ATOMIC_INC) ||
+	     (dst_ops & RIO_DST_OPS_ATOMIC_DEC) ||
+	     (dst_ops & RIO_DST_OPS_ATOMIC_SET) ||
+	     (dst_ops & RIO_DST_OPS_ATOMIC_CLR))) {
+		return 1;
+	} else
+		return 0;
+}
+
+/**
+ * rio_release_dev- Frees a RIO device struct
+ * @dev: LDM device associated with a RIO device struct
+ *
+ * Gets the RIO device struct associated a RIO device struct.
+ * The RIO device struct is freed.
+ */
+static void rio_release_dev(struct device *dev)
+{
+	struct rio_dev *rdev;
+
+	rdev =3D to_rio_dev(dev);
+	kfree(rdev);
+}
+
+/**
+ * rio_is_switch- Tests if a RIO device has switch capabilities
+ * @rdev: RIO device
+ *
+ * Gets the RIO device Processing Element Features register
+ * contents and tests for switch capabilities. Returns 1 if
+ * the device is a switch or 0 if it is not a switch.
+ * The RIO device struct is freed.
+ */
+static int rio_is_switch(struct rio_dev *rdev)
+{
+	if (rdev->pef & RIO_PEF_SWITCH)
+		return 1;
+	return 0;
+}
+
+/**
+ * rio_route_set_ops- Sets routing operations for a particular vendor swit=
ch
+ * @rdev: RIO device
+ *
+ * Searches the RIO route ops table for known switch types. If the vid
+ * and did match a switch table entry, then set the add_entry() and
+ * get_entry() ops to the table entry values.
+ */
+static void rio_route_set_ops(struct rio_dev *rdev)
+{
+	struct rio_route_ops *cur =3D __start_rio_route_ops;
+	struct rio_route_ops *end =3D __end_rio_route_ops;
+
+	while (cur < end) {
+		if ((cur->vid =3D=3D rdev->vid) && (cur->did =3D=3D rdev->did)) {
+			pr_debug("RIO: adding routing ops for %s\n", rio_name(rdev));
+			rdev->rswitch->add_entry =3D cur->add_hook;
+			rdev->rswitch->get_entry =3D cur->get_hook;
+		}
+		cur++;
+	}
+
+	if (!rdev->rswitch->add_entry || !rdev->rswitch->get_entry)
+		printk(KERN_ERR "RIO: missing routing ops for %s\n",
+		       rio_name(rdev));
+}
+
+/**
+ * rio_add_device- Adds a RIO device to the device model
+ * @rdev: RIO device
+ *
+ * Adds the RIO device to the global device list and adds the RIO
+ * device to the RIO device list.  Creates the generic sysfs nodes
+ * for an RIO device.
+ */
+static void __devinit rio_add_device(struct rio_dev *rdev)
+{
+	device_add(&rdev->dev);
+
+	spin_lock(&rio_global_list_lock);
+	list_add_tail(&rdev->global_list, &rio_devices);
+	spin_unlock(&rio_global_list_lock);
+
+	rio_create_sysfs_dev_files(rdev);
+}
+
+/**
+ * rio_setup_device- Allocates and sets up a RIO device
+ * @net: RIO network
+ * @port: Master port to send transactions
+ * @destid: Current destination ID
+ * @hopcount: Current hopcount
+ * @do_enum: Enumeration/Discovery mode flag
+ *
+ * Allocates a RIO device and configures fields based on configuration
+ * space contents. If device has a destination ID register, a destination
+ * ID is either assigned in enumeration mode or read from configuration
+ * space in discovery mode.  If the device has switch capabilities, then
+ * a switch is allocated and configured appropriately. Returns a pointer
+ * to a RIO device on success or NULL on failure.
+ *
+ */
+static struct rio_dev *rio_setup_device(struct rio_net *net,
+					struct rio_mport *port, u16 destid,
+					u8 hopcount, int do_enum)
+{
+	struct rio_dev *rdev;
+	struct rio_switch *rswitch;
+	int result, rdid;
+
+	rdev =3D kmalloc(sizeof(struct rio_dev), GFP_KERNEL);
+	if (!rdev)
+		goto out;
+
+	memset(rdev, 0, sizeof(struct rio_dev));
+	rdev->net =3D net;
+	rio_mport_read_config_32(port, destid, hopcount, RIO_DEV_ID_CAR,
+				 &result);
+	rdev->did =3D result >> 16;
+	rdev->vid =3D result & 0xffff;
+	rio_mport_read_config_32(port, destid, hopcount, RIO_DEV_INFO_CAR,
+				 &rdev->device_rev);
+	rio_mport_read_config_32(port, destid, hopcount, RIO_ASM_ID_CAR,
+				 &result);
+	rdev->asm_did =3D result >> 16;
+	rdev->asm_vid =3D result & 0xffff;
+	rio_mport_read_config_32(port, destid, hopcount, RIO_ASM_INFO_CAR,
+				 &result);
+	rdev->asm_rev =3D result >> 16;
+	rio_mport_read_config_32(port, destid, hopcount, RIO_PEF_CAR,
+				 &rdev->pef);
+	if (rdev->pef & RIO_PEF_EXT_FEATURES)
+		rdev->efptr =3D result & 0xffff;
+
+	rio_mport_read_config_32(port, destid, hopcount, RIO_SRC_OPS_CAR,
+				 &rdev->src_ops);
+	rio_mport_read_config_32(port, destid, hopcount, RIO_DST_OPS_CAR,
+				 &rdev->dst_ops);
+
+	if (rio_device_has_destid(port, rdev->src_ops, rdev->dst_ops)
+	    && do_enum) {
+		rio_set_device_id(port, destid, hopcount, next_destid);
+		rdev->destid =3D next_destid++;
+		if (next_destid =3D=3D port->host_deviceid)
+			next_destid++;
+	} else
+		rdev->destid =3D rio_get_device_id(port, destid, hopcount);
+
+	/* If a PE has both switch and other functions, show it as a switch */
+	if (rio_is_switch(rdev)) {
+		rio_mport_read_config_32(port, destid, hopcount,
+					 RIO_SWP_INFO_CAR, &rdev->swpinfo);
+		rswitch =3D kmalloc(sizeof(struct rio_switch), GFP_KERNEL);
+		if (!rswitch) {
+			kfree(rdev);
+			rdev =3D NULL;
+			goto out;
+		}
+		rswitch->switchid =3D next_switchid;
+		rswitch->hopcount =3D hopcount;
+		rswitch->destid =3D 0xffff;
+		/* Initialize switch route table */
+		for (rdid =3D 0; rdid < RIO_MAX_ROUTE_ENTRIES; rdid++)
+			rswitch->route_table[rdid] =3D RIO_INVALID_ROUTE;
+		rdev->rswitch =3D rswitch;
+		sprintf(rio_name(rdev), "%02x:s:%04x", rdev->net->id,
+			rdev->rswitch->switchid);
+		rio_route_set_ops(rdev);
+
+		list_add_tail(&rswitch->node, &rio_switches);
+
+	} else
+		sprintf(rio_name(rdev), "%02x:e:%04x", rdev->net->id,
+			rdev->destid);
+
+	rdev->dev.bus =3D &rio_bus_type;
+
+	device_initialize(&rdev->dev);
+	rdev->dev.release =3D rio_release_dev;
+	rio_dev_get(rdev);
+
+	rdev->dev.dma_mask =3D (u64 *) 0xffffffff;
+	rdev->dev.coherent_dma_mask =3D 0xffffffffULL;
+
+	if ((rdev->pef & RIO_PEF_INB_DOORBELL) &&
+	    (rdev->dst_ops & RIO_DST_OPS_DOORBELL))
+		rio_init_dbell_res(&rdev->riores[RIO_DOORBELL_RESOURCE],
+				   0, 0xffff);
+
+	rio_add_device(rdev);
+
+      out:
+	return rdev;
+}
+
+/**
+ * rio_sport_is_active- Tests if a switch port has an active connection.
+ * @port: Master port to send transaction
+ * @destid: Associated destination ID for switch
+ * @hopcount: Hopcount to reach switch
+ * @sport: Switch port number
+ *
+ * Reads the port error status CSR for a particular switch port to
+ * determine if the port has an active link.  Returns
+ * %PORT_N_ERR_STS_PORT_OK if the port is active or %0 if it is
+ * inactive.
+ */
+static int
+rio_sport_is_active(struct rio_mport *port, u16 destid, u8 hopcount, int s=
port)
+{
+	u32 result;
+	u32 ext_ftr_ptr;
+
+	int *entry =3D rio_sport_phys_table;
+
+	do {
+		if ((ext_ftr_ptr =3D
+		     rio_mport_get_feature(port, 0, destid, hopcount, *entry)))
+
+			break;
+	} while (*++entry >=3D 0);
+
+	if (ext_ftr_ptr)
+		rio_mport_read_config_32(port, destid, hopcount,
+					 ext_ftr_ptr +
+					 RIO_PORT_N_ERR_STS_CSR(sport),
+					 &result);
+
+	return (result & PORT_N_ERR_STS_PORT_OK);
+}
+
+/**
+ * rio_route_add_entry- Add a route entry to a switch routing table
+ * @mport: Master port to send transaction
+ * @rdev: Switch device
+ * @table: Routing table ID
+ * @route_destid: Destination ID to be routed
+ * @route_port: Port number to be routed
+ *
+ * Calls the switch specific add_entry() method to add a route entry
+ * on a switch. The route table can be specified using the @table
+ * argument if a switch has per port routing tables or the normal
+ * use is to specific all tables (or the global table) by passing
+ * %RIO_GLOBAL_TABLE in @table. Returns %0 on success or %-EINVAL
+ * on failure.
+ */
+static int rio_route_add_entry(struct rio_mport *mport, struct rio_dev *rd=
ev,
+			       u16 table, u16 route_destid, u8 route_port)
+{
+	return rdev->rswitch->add_entry(mport, rdev->rswitch->destid,
+					rdev->rswitch->hopcount, table,
+					route_destid, route_port);
+}
+
+/**
+ * rio_route_get_entry- Read a route entry in a switch routing table
+ * @mport: Master port to send transaction
+ * @rdev: Switch device
+ * @table: Routing table ID
+ * @route_destid: Destination ID to be routed
+ * @route_port: Pointer to read port number into
+ *
+ * Calls the switch specific get_entry() method to read a route entry
+ * in a switch. The route table can be specified using the @table
+ * argument if a switch has per port routing tables or the normal
+ * use is to specific all tables (or the global table) by passing
+ * %RIO_GLOBAL_TABLE in @table. Returns %0 on success or %-EINVAL
+ * on failure.
+ */
+static int
+rio_route_get_entry(struct rio_mport *mport, struct rio_dev *rdev, u16 tab=
le,
+		    u16 route_destid, u8 * route_port)
+{
+	return rdev->rswitch->get_entry(mport, rdev->rswitch->destid,
+					rdev->rswitch->hopcount, table,
+					route_destid, route_port);
+}
+
+/**
+ * rio_get_host_deviceid_lock- Reads the Host Device ID Lock CSR on a devi=
ce
+ * @port: Master port to send transaction
+ * @hopcount: Number of hops to the device
+ *
+ * Used during enumeration to read the Host Device ID Lock CSR on a
+ * RIO device. Returns the value of the lock register.
+ */
+static u16 rio_get_host_deviceid_lock(struct rio_mport *port, u8 hopcount)
+{
+	u32 result;
+
+	rio_mport_read_config_32(port, RIO_ANY_DESTID, hopcount,
+				 RIO_HOST_DID_LOCK_CSR, &result);
+
+	return (u16) (result & 0xffff);
+}
+
+/**
+ * rio_get_swpinfo_inport- Gets the ingress port number=20
+ * @mport: Master port to send transaction
+ * @destid: Destination ID associated with the switch
+ * @hopcount: Number of hops to the device
+ *
+ * Returns port number being used to access the switch device.
+ */
+static u8
+rio_get_swpinfo_inport(struct rio_mport *mport, u16 destid, u8 hopcount)
+{
+	u32 result;
+
+	rio_mport_read_config_32(mport, destid, hopcount, RIO_SWP_INFO_CAR,
+				 &result);
+
+	return (u8) (result & 0xff);
+}
+
+/**
+ * rio_get_swpinfo_tports- Gets total number of ports on the switch
+ * @mport: Master port to send transaction
+ * @destid: Destination ID associated with the switch
+ * @hopcount: Number of hops to the device
+ *
+ * Returns total numbers of ports implemented by the switch device.
+ */
+static u8 rio_get_swpinfo_tports(struct rio_mport *mport, u16 destid,
+				 u8 hopcount)
+{
+	u32 result;
+
+	rio_mport_read_config_32(mport, destid, hopcount, RIO_SWP_INFO_CAR,
+				 &result);
+
+	return RIO_GET_TOTAL_PORTS(result);
+}
+
+/**
+ * rio_net_add_mport- Add a master port to a RIO network
+ * @net: RIO network
+ * @port: Master port to add
+ *
+ * Adds a master port to the network list of associated master
+ * ports..
+ */
+static void rio_net_add_mport(struct rio_net *net, struct rio_mport *port)
+{
+	spin_lock(&rio_global_list_lock);
+	list_add_tail(&port->nnode, &net->mports);
+	spin_unlock(&rio_global_list_lock);
+}
+
+/**
+ * rio_enum_peer- Recursively enumerate a RIO network through a master port
+ * @net: RIO network being enumerated
+ * @port: Master port to send transactions
+ * @hopcount: Number of hops into the network
+ *
+ * Recursively enumerates a RIO network.  Transactions are sent via the
+ * master port passed in @port.
+ */
+static int rio_enum_peer(struct rio_net *net, struct rio_mport *port,
+			 u8 hopcount)
+{
+	int port_num;
+	int num_ports;
+	int cur_destid;
+	struct rio_dev *rdev;
+	u16 destid;
+	int tmp;
+
+	if (rio_get_host_deviceid_lock(port, hopcount) =3D=3D port->host_deviceid=
) {
+		pr_debug("RIO: PE already discovered by this host\n");
+		/*
+		 * Already discovered by this host. Add it as another
+		 * master port for the current network.
+		 */
+		rio_net_add_mport(net, port);
+		return 0;
+	}
+
+	/* Attempt to acquire device lock */
+	rio_mport_write_config_32(port, RIO_ANY_DESTID, hopcount,
+				  RIO_HOST_DID_LOCK_CSR, port->host_deviceid);
+	while ((tmp =3D rio_get_host_deviceid_lock(port, hopcount))
+	       < port->host_deviceid) {
+		/* Delay a bit */
+		mdelay(1);
+		/* Attempt to acquire device lock again */
+		rio_mport_write_config_32(port, RIO_ANY_DESTID, hopcount,
+					  RIO_HOST_DID_LOCK_CSR,
+					  port->host_deviceid);
+	}
+
+	if (rio_get_host_deviceid_lock(port, hopcount) > port->host_deviceid) {
+		pr_debug(
+		    "RIO: PE locked by a higher priority host...retreating\n");
+		return -1;
+	}
+
+	/* Setup new RIO device */
+	if ((rdev =3D rio_setup_device(net, port, RIO_ANY_DESTID, hopcount, 1))) {
+		/* Add device to the global and bus/net specific list. */
+		list_add_tail(&rdev->net_list, &net->devices);
+	} else
+		return -1;
+
+	if (rio_is_switch(rdev)) {
+		next_switchid++;
+
+		for (destid =3D 0; destid < next_destid; destid++) {
+			rio_route_add_entry(port, rdev, RIO_GLOBAL_TABLE,
+					    destid, rio_get_swpinfo_inport(port,
+									   RIO_ANY_DESTID,
+									   hopcount));
+			rdev->rswitch->route_table[destid] =3D
+			    rio_get_swpinfo_inport(port, RIO_ANY_DESTID,
+						   hopcount);
+		}
+
+		num_ports =3D
+		    rio_get_swpinfo_tports(port, RIO_ANY_DESTID, hopcount);
+		pr_debug(
+		    "RIO: found %s (vid %4.4x did %4.4x) with %d ports\n",
+		    rio_name(rdev), rdev->vid, rdev->did, num_ports);
+		for (port_num =3D 0; port_num < num_ports; port_num++) {
+			if (rio_get_swpinfo_inport
+			    (port, RIO_ANY_DESTID, hopcount) =3D=3D port_num)
+				continue;
+
+			cur_destid =3D next_destid;
+
+			if (rio_sport_is_active
+			    (port, RIO_ANY_DESTID, hopcount, port_num)) {
+				pr_debug(
+				    "RIO: scanning device on port %d\n",
+				    port_num);
+				rio_route_add_entry(port, rdev,
+						    RIO_GLOBAL_TABLE,
+						    RIO_ANY_DESTID, port_num);
+
+				if (rio_enum_peer(net, port, hopcount + 1) < 0)
+					return -1;
+
+				/* Update routing tables */
+				if (next_destid > cur_destid) {
+					for (destid =3D cur_destid;
+					     destid < next_destid; destid++) {
+						rio_route_add_entry(port, rdev,
+								    RIO_GLOBAL_TABLE,
+								    destid,
+								    port_num);
+						rdev->rswitch->
+						    route_table[destid] =3D
+						    port_num;
+					}
+					rdev->rswitch->destid =3D cur_destid;
+				}
+			}
+		}
+	} else
+		pr_debug("RIO: found %s (vid %4.4x did %4.4x)\n",
+		    rio_name(rdev), rdev->vid, rdev->did);
+
+	return 0;
+}
+
+/**
+ * rio_enum_complete- Tests if enumeration of a network is complete
+ * @port: Master port to send transaction
+ *
+ * Tests the Component Tag CSR for presence of the magic enumeration
+ * complete flag. Return %1 if enumeration is complete or %0 if
+ * enumeration is incomplete.
+ */
+static int rio_enum_complete(struct rio_mport *port)
+{
+	u32 tag_csr;
+	int ret =3D 0;
+
+	rio_local_read_config_32(port, RIO_COMPONENT_TAG_CSR, &tag_csr);
+
+	if (tag_csr =3D=3D RIO_ENUM_CMPL_MAGIC)
+		ret =3D 1;
+
+	return ret;
+}
+
+/**
+ * rio_disc_peer- Recursively discovers a RIO network through a master port
+ * @net: RIO network being discovered
+ * @port: Master port to send transactions
+ * @destid: Current destination ID in network
+ * @hopcount: Number of hops into the network
+ *
+ * Recursively discovers a RIO network.  Transactions are sent via the
+ * master port passed in @port.
+ */
+static int
+rio_disc_peer(struct rio_net *net, struct rio_mport *port, u16 destid,
+	      u8 hopcount)
+{
+	u8 port_num, route_port;
+	int num_ports;
+	struct rio_dev *rdev;
+	u16 ndestid;
+
+	/* Setup new RIO device */
+	if ((rdev =3D rio_setup_device(net, port, destid, hopcount, 0))) {
+		/* Add device to the global and bus/net specific list. */
+		list_add_tail(&rdev->net_list, &net->devices);
+	} else
+		return -1;
+
+	if (rio_is_switch(rdev)) {
+		next_switchid++;
+
+		/* Associated destid is how we accessed this switch */
+		rdev->rswitch->destid =3D destid;
+
+		num_ports =3D rio_get_swpinfo_tports(port, destid, hopcount);
+		pr_debug(
+		    "RIO: found %s (vid %4.4x did %4.4x) with %d ports\n",
+		    rio_name(rdev), rdev->vid, rdev->did, num_ports);
+		for (port_num =3D 0; port_num < num_ports; port_num++) {
+			if (rio_get_swpinfo_inport(port, destid, hopcount) =3D=3D
+			    port_num)
+				continue;
+
+			if (rio_sport_is_active
+			    (port, destid, hopcount, port_num)) {
+				pr_debug(
+				    "RIO: scanning device on port %d\n",
+				    port_num);
+				for (ndestid =3D 0; ndestid < RIO_ANY_DESTID;
+				     ndestid++) {
+					rio_route_get_entry(port, rdev,
+							    RIO_GLOBAL_TABLE,
+							    ndestid,
+							    &route_port);
+					if (route_port =3D=3D port_num)
+						break;
+				}
+
+				if (rio_disc_peer
+				    (net, port, ndestid, hopcount + 1) < 0)
+					return -1;
+			}
+		}
+	} else
+		pr_debug("RIO: found %s (vid %4.4x did %4.4x)\n",
+		    rio_name(rdev), rdev->vid, rdev->did);
+
+	return 0;
+}
+
+/**
+ * rio_mport_is_active- Tests if master port link is active
+ * @port: Master port to test
+ *
+ * Reads the port error status CSR for the master port to
+ * determine if the port has an active link.  Returns
+ * %PORT_N_ERR_STS_PORT_OK if the  master port is active
+ * or %0 if it is inactive.
+ */
+static int rio_mport_is_active(struct rio_mport *port)
+{
+	u32 result =3D 0;
+	u32 ext_ftr_ptr;
+	int *entry =3D rio_mport_phys_table;
+
+	do {
+		if ((ext_ftr_ptr =3D
+		     rio_mport_get_feature(port, 1, 0, 0, *entry)))
+			break;
+	} while (*++entry >=3D 0);
+
+	if (ext_ftr_ptr)
+		rio_local_read_config_32(port,
+					 ext_ftr_ptr +
+					 RIO_PORT_N_ERR_STS_CSR(port->index),
+					 &result);
+
+	return (result & PORT_N_ERR_STS_PORT_OK);
+}
+
+/**
+ * rio_alloc_net- Allocate and configure a new RIO network
+ * @port: Master port associated with the RIO network
+ *
+ * Allocates a RIO network structure, initializes per-network
+ * list heads, and adds the associated master port to the
+ * network list of associated master ports. Returns a
+ * RIO network pointer on success or %NULL on failure.
+ */
+static struct rio_net __devinit *rio_alloc_net(struct rio_mport *port)
+{
+	struct rio_net *net;
+
+	net =3D kmalloc(sizeof(struct rio_net), GFP_KERNEL);
+	if (net) {
+		memset(net, 0, sizeof(struct rio_net));
+		INIT_LIST_HEAD(&net->node);
+		INIT_LIST_HEAD(&net->devices);
+		INIT_LIST_HEAD(&net->mports);
+		list_add_tail(&port->nnode, &net->mports);
+		net->hport =3D port;
+		net->id =3D next_net++;
+	}
+	return net;
+}
+
+/**
+ * rio_enum_mport- Start enumeration through a master port
+ * @mport: Master port to send transactions
+ *
+ * Starts the enumeration process. If somebody has enumerated our
+ * master port device, then give up. If not and we have an active
+ * link, then start recursive peer enumeration. Returns %0 if
+ * enumeration succeeds or %-EBUSY if enumeration fails.
+ */
+int rio_enum_mport(struct rio_mport *mport)
+{
+	struct rio_net *net =3D NULL;
+	int rc =3D 0;
+
+	printk(KERN_INFO "RIO: enumerate master port %d, %s\n", mport->id,
+	       mport->name);
+	/* If somebody else enumerated our master port device, bail. */
+	if (rio_enum_host(mport) < 0) {
+		printk(KERN_INFO
+		       "RIO: master port %d device has been enumerated by a remote host\=
n",
+		       mport->id);
+		rc =3D -EBUSY;
+		goto out;
+	}
+
+	/* If master port has an active link, allocate net and enum peers */
+	if (rio_mport_is_active(mport)) {
+		if (!(net =3D rio_alloc_net(mport))) {
+			printk(KERN_ERR "RIO: failed to allocate new net\n");
+			rc =3D -ENOMEM;
+			goto out;
+		}
+		if (rio_enum_peer(net, mport, 0) < 0) {
+			/* A higher priority host won enumeration, bail. */
+			printk(KERN_INFO
+			       "RIO: master port %d device has lost enumeration to a remote hos=
t\n",
+			       mport->id);
+			rio_clear_locks(mport);
+			rc =3D -EBUSY;
+			goto out;
+		}
+		rio_clear_locks(mport);
+	} else {
+		printk(KERN_INFO "RIO: master port %d link inactive\n",
+		       mport->id);
+		rc =3D -EINVAL;
+	}
+
+      out:
+	return rc;
+}
+
+/**
+ * rio_build_route_tables- Generate route tables from switch route entries
+ *
+ * For each switch device, generate a route table by copying existing
+ * route entries from the switch.
+ */
+static void rio_build_route_tables(void)
+{
+	struct rio_dev *rdev;
+	int i;
+	u8 sport;
+
+	list_for_each_entry(rdev, &rio_devices, global_list)
+	    if (rio_is_switch(rdev))
+		for (i =3D 0; i < RIO_MAX_ROUTE_ENTRIES; i++) {
+			if (rio_route_get_entry
+			    (rdev->net->hport, rdev, RIO_GLOBAL_TABLE, i,
+			     &sport) < 0)
+				continue;
+			rdev->rswitch->route_table[i] =3D sport;
+		}
+}
+
+/**
+ * rio_enum_timeout- Signal that enumeration timed out
+ * @data: Address of timeout flag.
+ *
+ * When the enumeration complete timer expires, set a flag that
+ * signals to the discovery process that enumeration did not
+ * complete in a sane amount of time.
+ */
+static void rio_enum_timeout(unsigned long data)
+{
+	/* Enumeration timed out, set flag */
+	*(int *)data =3D 1;
+}
+
+/**
+ * rio_disc_mport- Start discovery through a master port
+ * @mport: Master port to send transactions
+ *
+ * Starts the discovery process. If we have an active link,
+ * then wait for the signal that enumeration is complete.
+ * When enumeration completion is signaled, start recursive
+ * peer discovery. Returns %0 if discovery succeeds or %-EBUSY
+ * on failure.
+ */
+int rio_disc_mport(struct rio_mport *mport)
+{
+	struct rio_net *net =3D NULL;
+	int enum_timeout_flag =3D 0;
+
+	printk(KERN_INFO "RIO: discover master port %d, %s\n", mport->id,
+	       mport->name);
+
+	/* If master port has an active link, allocate net and discover peers */
+	if (rio_mport_is_active(mport)) {
+		if (!(net =3D rio_alloc_net(mport))) {
+			printk(KERN_ERR "RIO: Failed to allocate new net\n");
+			goto bail;
+		}
+
+		pr_debug("RIO: wait for enumeration complete...");
+
+		rio_enum_timer.expires =3D
+		    jiffies + CONFIG_RAPIDIO_DISC_TIMEOUT * HZ;
+		rio_enum_timer.data =3D (unsigned long)&enum_timeout_flag;
+		add_timer(&rio_enum_timer);
+		while (!rio_enum_complete(mport)) {
+			mdelay(1);
+			if (enum_timeout_flag) {
+				del_timer_sync(&rio_enum_timer);
+				goto timeout;
+			}
+		}
+		del_timer_sync(&rio_enum_timer);
+
+		pr_debug("done\n");
+		if (rio_disc_peer(net, mport, RIO_ANY_DESTID, 0) < 0) {
+			printk(KERN_INFO
+			       "RIO: master port %d device has failed discovery\n",
+			       mport->id);
+			goto bail;
+		}
+
+		rio_build_route_tables();
+	}
+
+	return 0;
+
+      timeout:
+	pr_debug("timeout\n");
+      bail:
+	return -EBUSY;
+}
diff --git a/drivers/rio/switches/Makefile b/drivers/rio/switches/Makefile
new file mode 100644
--- /dev/null
+++ b/drivers/rio/switches/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for RIO switches
+#
+
+obj-$(CONFIG_RAPIDIO)	+=3D tsi500.o
diff --git a/drivers/rio/switches/tsi500.c b/drivers/rio/switches/tsi500.c
new file mode 100644
--- /dev/null
+++ b/drivers/rio/switches/tsi500.c
@@ -0,0 +1,60 @@
+/*
+ * RapidIO Tsi500 switch support
+ *
+ * Copyright 2005 MontaVista Software, Inc.
+ * Matt Porter <mporter@kernel.crashing.org>
+ *
+ * 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.
+ */
+
+#include <linux/rio.h>
+#include <linux/rio_drv.h>
+#include <linux/rio_ids.h>
+#include "../rio.h"
+
+static int
+tsi500_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount, u=
16 table, u16 route_destid, u8 route_port)
+{
+	int i;
+	u32 offset =3D 0x10000 + 0xa00 + ((route_destid / 2)&~0x3);
+	u32 result;
+
+	if (table =3D=3D 0xff) {
+		rio_mport_read_config_32(mport, destid, hopcount, offset, &result);
+		result &=3D ~(0xf << (4*(route_destid & 0x7)));
+		for (i=3D0;i<4;i++)
+			rio_mport_write_config_32(mport, destid, hopcount, offset + (0x20000*i)=
, result | (route_port << (4*(route_destid & 0x7))));
+	}
+	else {
+		rio_mport_read_config_32(mport, destid, hopcount, offset + (0x20000*tabl=
e), &result);
+		result &=3D ~(0xf << (4*(route_destid & 0x7)));
+		rio_mport_write_config_32(mport, destid, hopcount, offset + (0x20000*tab=
le), result | (route_port << (4*(route_destid & 0x7))));
+	}
+
+	return 0;
+}
+
+static int
+tsi500_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount, u=
16 table, u16 route_destid, u8 *route_port)
+{
+	int ret =3D 0;
+	u32 offset =3D 0x10000 + 0xa00 + ((route_destid / 2)&~0x3);
+	u32 result;
+
+	if (table =3D=3D 0xff)
+		rio_mport_read_config_32(mport, destid, hopcount, offset, &result);
+	else
+		rio_mport_read_config_32(mport, destid, hopcount, offset + (0x20000*tabl=
e), &result);
+
+	result &=3D 0xf << (4*(route_destid & 0x7));
+	*route_port =3D result >> (4*(route_destid & 0x7));
+	if (*route_port > 3)
+		ret =3D -1;
+
+	return ret;
+}
+
+DECLARE_RIO_ROUTE_OPS(RIO_VID_TUNDRA, RIO_DID_TSI500, tsi500_route_add_ent=
ry, tsi500_route_get_entry);

[PATCH][4/5] RapidIO support: ppc32

From: Matt Porter <mporter@kernel.crashing.org>
Date: 2005-06-06 23:09:42

Adds PPC32 RIO support.  Init code for the MPC85xx RIO ports
and glue for the STx GP3 board to use it.

Signed-off-by: Matt Porter <mporter@kernel.crashing.org>
diff --git a/arch/ppc/Kconfig b/arch/ppc/Kconfig
--- a/arch/ppc/Kconfig
+++ b/arch/ppc/Kconfig
@@ -1177,6 +1177,14 @@ source "drivers/pci/Kconfig"
=20
 source "drivers/pcmcia/Kconfig"
=20
+config RAPIDIO
+	bool "RapidIO support" if MPC8540 || MPC8560
+	help
+	  If you say Y here, the kernel will include drivers and
+	  infrastructure code to support RapidIO interconnect devices.
+
+source "drivers/rio/Kconfig"
+
 endmenu
=20
 menu "Advanced setup"
diff --git a/arch/ppc/configs/stx_gp3_defconfig b/arch/ppc/configs/stx_gp3_=
defconfig
--- a/arch/ppc/configs/stx_gp3_defconfig
+++ b/arch/ppc/configs/stx_gp3_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.11-rc2
-# Wed Jan 26 14:32:58 2005
+# Linux kernel version: 2.6.12-rc4
+# Tue May 24 18:11:04 2005
 #
 CONFIG_MMU=3Dy
 CONFIG_GENERIC_HARDIRQS=3Dy
@@ -11,6 +11,7 @@ CONFIG_HAVE_DEC_LOCK=3Dy
 CONFIG_PPC=3Dy
 CONFIG_PPC32=3Dy
 CONFIG_GENERIC_NVRAM=3Dy
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=3Dy
=20
 #
 # Code maturity level options
@@ -18,6 +19,7 @@ CONFIG_GENERIC_NVRAM=3Dy
 CONFIG_EXPERIMENTAL=3Dy
 CONFIG_CLEAN_COMPILE=3Dy
 CONFIG_BROKEN_ON_SMP=3Dy
+CONFIG_INIT_ENV_ARG_LIMIT=3D32
=20
 #
 # General setup
@@ -29,7 +31,6 @@ CONFIG_SYSVIPC=3Dy
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=3Dy
 # CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=3D14
 CONFIG_HOTPLUG=3Dy
 CONFIG_KOBJECT_UEVENT=3Dy
 # CONFIG_IKCONFIG is not set
@@ -37,6 +38,9 @@ CONFIG_EMBEDDED=3Dy
 CONFIG_KALLSYMS=3Dy
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=3Dy
+CONFIG_BUG=3Dy
+CONFIG_BASE_FULL=3Dy
 CONFIG_FUTEX=3Dy
 CONFIG_EPOLL=3Dy
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
@@ -46,6 +50,7 @@ CONFIG_CC_ALIGN_LABELS=3D0
 CONFIG_CC_ALIGN_LOOPS=3D0
 CONFIG_CC_ALIGN_JUMPS=3D0
 # CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=3D0
=20
 #
 # Loadable module support
@@ -69,9 +74,11 @@ CONFIG_KMOD=3Dy
 CONFIG_E500=3Dy
 CONFIG_BOOKE=3Dy
 CONFIG_FSL_BOOKE=3Dy
+# CONFIG_PHYS_64BIT is not set
 # CONFIG_SPE is not set
 CONFIG_MATH_EMULATION=3Dy
 # CONFIG_CPU_FREQ is not set
+# CONFIG_PM is not set
 CONFIG_85xx=3Dy
 CONFIG_PPC_INDIRECT_PCI_BE=3Dy
=20
@@ -96,6 +103,7 @@ CONFIG_HIGHMEM=3Dy
 CONFIG_BINFMT_ELF=3Dy
 CONFIG_BINFMT_MISC=3Dm
 # CONFIG_CMDLINE_BOOL is not set
+CONFIG_ISA_DMA_API=3Dy
=20
 #
 # Bus options
@@ -104,15 +112,15 @@ CONFIG_PCI=3Dy
 CONFIG_PCI_DOMAINS=3Dy
 # CONFIG_PCI_LEGACY_PROC is not set
 # CONFIG_PCI_NAMES is not set
+# CONFIG_PCI_DEBUG is not set
=20
 #
 # PCCARD (PCMCIA/CardBus) support
 #
 # CONFIG_PCCARD is not set
-
-#
-# PC-card bridges
-#
+CONFIG_RAPIDIO=3Dy
+CONFIG_RAPIDIO_8_BIT_TRANSPORT=3Dy
+CONFIG_RAPIDIO_DISC_TIMEOUT=3D30
=20
 #
 # Advanced setup
@@ -152,7 +160,7 @@ CONFIG_PARPORT=3Dm
 CONFIG_PARPORT_PC=3Dm
 # CONFIG_PARPORT_PC_FIFO is not set
 # CONFIG_PARPORT_PC_SUPERIO is not set
-# CONFIG_PARPORT_OTHER is not set
+# CONFIG_PARPORT_GSC is not set
 # CONFIG_PARPORT_1284 is not set
=20
 #
@@ -264,7 +272,6 @@ CONFIG_SCSI_CONSTANTS=3Dy
 # CONFIG_SCSI_BUSLOGIC is not set
 # CONFIG_SCSI_DMX3191D is not set
 # CONFIG_SCSI_EATA is not set
-# CONFIG_SCSI_EATA_PIO is not set
 # CONFIG_SCSI_FUTURE_DOMAIN is not set
 # CONFIG_SCSI_GDTH is not set
 # CONFIG_SCSI_IPS is not set
@@ -274,7 +281,6 @@ CONFIG_SCSI_CONSTANTS=3Dy
 # CONFIG_SCSI_IMM is not set
 # CONFIG_SCSI_SYM53C8XX_2 is not set
 # CONFIG_SCSI_IPR is not set
-# CONFIG_SCSI_QLOGIC_ISP is not set
 # CONFIG_SCSI_QLOGIC_FC is not set
 # CONFIG_SCSI_QLOGIC_1280 is not set
 CONFIG_SCSI_QLA2XXX=3Dm
@@ -283,6 +289,7 @@ CONFIG_SCSI_QLA2XXX=3Dm
 # CONFIG_SCSI_QLA2300 is not set
 # CONFIG_SCSI_QLA2322 is not set
 # CONFIG_SCSI_QLA6312 is not set
+# CONFIG_SCSI_LPFC is not set
 # CONFIG_SCSI_DC395x is not set
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_NSP32 is not set
@@ -322,7 +329,6 @@ CONFIG_NET=3Dy
 #
 CONFIG_PACKET=3Dy
 # CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK_DEV is not set
 CONFIG_UNIX=3Dy
 # CONFIG_NET_KEY is not set
 CONFIG_INET=3Dy
@@ -431,7 +437,7 @@ CONFIG_IP_NF_NAT_FTP=3Dm
 #
 # Network testing
 #
-# CONFIG_NET_PKTGEN is not set
+CONFIG_NET_PKTGEN=3Dy
 # CONFIG_NETPOLL is not set
 # CONFIG_NET_POLL_CONTROLLER is not set
 # CONFIG_HAMRADIO is not set
@@ -499,6 +505,7 @@ CONFIG_GFAR_NAPI=3Dy
 # Wan interfaces
 #
 # CONFIG_WAN is not set
+CONFIG_RIONET=3Dy
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
 # CONFIG_PLIP is not set
@@ -536,20 +543,6 @@ CONFIG_INPUT_EVDEV=3Dm
 # CONFIG_INPUT_EVBUG is not set
=20
 #
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=3Dy
-CONFIG_SERIO=3Dy
-CONFIG_SERIO_I8042=3Dy
-CONFIG_SERIO_SERPORT=3Dy
-# CONFIG_SERIO_CT82C710 is not set
-# CONFIG_SERIO_PARKBD is not set
-# CONFIG_SERIO_PCIPS2 is not set
-CONFIG_SERIO_LIBPS2=3Dy
-# CONFIG_SERIO_RAW is not set
-
-#
 # Input Device Drivers
 #
 CONFIG_INPUT_KEYBOARD=3Dy
@@ -567,6 +560,19 @@ CONFIG_MOUSE_PS2=3Dy
 # CONFIG_INPUT_MISC is not set
=20
 #
+# Hardware I/O ports
+#
+CONFIG_SERIO=3Dy
+CONFIG_SERIO_I8042=3Dy
+CONFIG_SERIO_SERPORT=3Dy
+# CONFIG_SERIO_PARKBD is not set
+# CONFIG_SERIO_PCIPS2 is not set
+CONFIG_SERIO_LIBPS2=3Dy
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=3Dy
+
+#
 # Character devices
 #
 # CONFIG_VT is not set
@@ -590,6 +596,7 @@ CONFIG_SERIAL_CPM_SCC2=3Dy
 # CONFIG_SERIAL_CPM_SCC4 is not set
 # CONFIG_SERIAL_CPM_SMC1 is not set
 # CONFIG_SERIAL_CPM_SMC2 is not set
+# CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=3Dy
 CONFIG_LEGACY_PTYS=3Dy
 CONFIG_LEGACY_PTY_COUNT=3D256
@@ -626,6 +633,11 @@ CONFIG_DRM=3Dm
 # CONFIG_RAW_DRIVER is not set
=20
 #
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
 # I2C support
 #
 CONFIG_I2C=3Dm
@@ -648,12 +660,12 @@ CONFIG_I2C_ALGOBIT=3Dm
 # CONFIG_I2C_AMD8111 is not set
 # CONFIG_I2C_I801 is not set
 # CONFIG_I2C_I810 is not set
+# CONFIG_I2C_PIIX4 is not set
 # CONFIG_I2C_ISA is not set
 # CONFIG_I2C_MPC is not set
 # CONFIG_I2C_NFORCE2 is not set
 # CONFIG_I2C_PARPORT is not set
 # CONFIG_I2C_PARPORT_LIGHT is not set
-# CONFIG_I2C_PIIX4 is not set
 # CONFIG_I2C_PROSAVAGE is not set
 # CONFIG_I2C_SAVAGE4 is not set
 # CONFIG_SCx200_ACB is not set
@@ -677,7 +689,9 @@ CONFIG_I2C_ALGOBIT=3Dm
 # CONFIG_SENSORS_ASB100 is not set
 # CONFIG_SENSORS_DS1621 is not set
 # CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
 # CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
 # CONFIG_SENSORS_IT87 is not set
 # CONFIG_SENSORS_LM63 is not set
 # CONFIG_SENSORS_LM75 is not set
@@ -688,9 +702,11 @@ CONFIG_I2C_ALGOBIT=3Dm
 # CONFIG_SENSORS_LM85 is not set
 # CONFIG_SENSORS_LM87 is not set
 # CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
 # CONFIG_SENSORS_MAX1619 is not set
 # CONFIG_SENSORS_PC87360 is not set
 # CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_SIS5595 is not set
 # CONFIG_SENSORS_SMSC47M1 is not set
 # CONFIG_SENSORS_VIA686A is not set
 # CONFIG_SENSORS_W83781D is not set
@@ -700,10 +716,12 @@ CONFIG_I2C_ALGOBIT=3Dm
 #
 # Other I2C Chip support
 #
+# CONFIG_SENSORS_DS1337 is not set
 # CONFIG_SENSORS_EEPROM is not set
 # CONFIG_SENSORS_PCF8574 is not set
 # CONFIG_SENSORS_PCF8591 is not set
 # CONFIG_SENSORS_RTC8564 is not set
+# CONFIG_SENSORS_M41T00 is not set
 # CONFIG_I2C_DEBUG_CORE is not set
 # CONFIG_I2C_DEBUG_ALGO is not set
 # CONFIG_I2C_DEBUG_BUS is not set
@@ -732,7 +750,6 @@ CONFIG_I2C_ALGOBIT=3Dm
 # Graphics support
 #
 # CONFIG_FB is not set
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
=20
 #
 # Sound
@@ -752,13 +769,9 @@ CONFIG_SOUND=3Dm
 #
 # USB support
 #
-# CONFIG_USB is not set
 CONFIG_USB_ARCH_HAS_HCD=3Dy
 CONFIG_USB_ARCH_HAS_OHCI=3Dy
-
-#
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be need=
ed; see USB_STORAGE Help for more information
-#
+# CONFIG_USB is not set
=20
 #
 # USB Gadget Support
@@ -789,6 +802,10 @@ CONFIG_JBD_DEBUG=3Dy
 CONFIG_FS_MBCACHE=3Dy
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
 # CONFIG_XFS_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
@@ -859,7 +876,6 @@ CONFIG_NFS_V3=3Dy
 CONFIG_ROOT_NFS=3Dy
 CONFIG_LOCKD=3Dy
 CONFIG_LOCKD_V4=3Dy
-# CONFIG_EXPORTFS is not set
 CONFIG_SUNRPC=3Dy
 # CONFIG_RPCSEC_GSS_KRB5 is not set
 # CONFIG_RPCSEC_GSS_SPKM3 is not set
@@ -942,8 +958,10 @@ CONFIG_ZLIB_INFLATE=3Dm
 #
 # Kernel hacking
 #
+# CONFIG_PRINTK_TIME is not set
 CONFIG_DEBUG_KERNEL=3Dy
 # CONFIG_MAGIC_SYSRQ is not set
+CONFIG_LOG_BUF_SHIFT=3D14
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_DEBUG_SLAB is not set
 # CONFIG_DEBUG_SPINLOCK is not set
diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile
--- a/arch/ppc/kernel/Makefile
+++ b/arch/ppc/kernel/Makefile
@@ -22,6 +22,7 @@ obj-$(CONFIG_POWER4)		+=3D cpu_setup_power
 obj-$(CONFIG_MODULES)		+=3D module.o ppc_ksyms.o
 obj-$(CONFIG_NOT_COHERENT_CACHE)	+=3D dma-mapping.o
 obj-$(CONFIG_PCI)		+=3D pci.o
+obj-$(CONFIG_RAPIDIO)		+=3D rio.o
 obj-$(CONFIG_KGDB)		+=3D ppc-stub.o
 obj-$(CONFIG_SMP)		+=3D smp.o smp-tbsync.o
 obj-$(CONFIG_TAU)		+=3D temp.o
diff --git a/arch/ppc/kernel/rio.c b/arch/ppc/kernel/rio.c
new file mode 100644
--- /dev/null
+++ b/arch/ppc/kernel/rio.c
@@ -0,0 +1,52 @@
+/*
+ * RapidIO PPC32 support
+ *
+ * Copyright 2005 MontaVista Software, Inc.
+ * Matt Porter <mporter@kernel.crashing.org>
+ *
+ * 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.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/rio.h>
+
+#include <asm/rio.h>
+
+/**
+ * platform_rio_init - Do platform specific RIO init
+ *
+ * Any platform specific initialization of RapdIO
+ * hardware is done here as well as registration
+ * of any active master ports in the system.
+ */
+void __attribute__ ((weak))
+    platform_rio_init(void)
+{
+	printk(KERN_WARNING "RIO: No platform_rio_init() present\n");
+}
+
+/**
+ * ppc_rio_init - Do PPC32 RIO init
+ *
+ * Calls platform-specific RIO init code and then calls
+ * rio_init_mports() to initialize any master ports that
+ * have been registered with the RIO subsystem.
+ */
+static int __init ppc_rio_init(void)
+{
+	printk(KERN_INFO "RIO: RapidIO init\n");
+
+	/* Platform specific initialization */
+	platform_rio_init();
+
+	/* Enumerate all registered ports */
+	rio_init_mports();
+
+	return 0;
+}
+
+subsys_initcall(ppc_rio_init);
diff --git a/arch/ppc/platforms/85xx/stx_gp3.c b/arch/ppc/platforms/85xx/st=
x_gp3.c
--- a/arch/ppc/platforms/85xx/stx_gp3.c
+++ b/arch/ppc/platforms/85xx/stx_gp3.c
@@ -38,6 +38,7 @@
 #include <linux/module.h>
 #include <linux/fsl_devices.h>
 #include <linux/interrupt.h>
+#include <linux/rio.h>
=20
 #include <asm/system.h>
 #include <asm/pgtable.h>
@@ -59,6 +60,7 @@
=20
 #include <syslib/cpm2_pic.h>
 #include <syslib/ppc85xx_common.h>
+#include <syslib/ppc85xx_rio.h>
=20
 extern void cpm2_reset(void);
=20
@@ -200,7 +202,6 @@ static struct irqaction cpm2_irqaction =3D
 static void __init
 gp3_init_IRQ(void)
 {
-	int i;
 	bd_t *binfo =3D (bd_t *) __res;
=20
 	/*
@@ -297,6 +298,18 @@ int mpc85xx_exclude_device(u_char bus, u
 }
 #endif /* CONFIG_PCI */
=20
+#ifdef CONFIG_RAPIDIO
+void
+platform_rio_init(void)
+{
+	/*
+	 * The STx firmware configures the RapidIO Local Access Window
+	 * at 0xc0000000 with a size of 512MB.
+	 */
+	mpc85xx_rio_setup(0xc0000000, 0x20000000);
+}
+#endif /* CONFIG_RAPIDIO */
+
 void __init
 platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
 	      unsigned long r6, unsigned long r7)
diff --git a/arch/ppc/syslib/Makefile b/arch/ppc/syslib/Makefile
--- a/arch/ppc/syslib/Makefile
+++ b/arch/ppc/syslib/Makefile
@@ -101,6 +101,7 @@ obj-$(CONFIG_85xx)		+=3D open_pic.o ppc85x
 					mpc85xx_devices.o
 ifeq ($(CONFIG_85xx),y)
 obj-$(CONFIG_PCI)		+=3D indirect_pci.o pci_auto.o
+obj-$(CONFIG_RAPIDIO)		+=3D ppc85xx_rio.o
 endif
 obj-$(CONFIG_83xx)		+=3D ipic.o ppc83xx_setup.o ppc_sys.o \
 					mpc83xx_sys.o mpc83xx_devices.o
diff --git a/arch/ppc/syslib/ppc85xx_rio.c b/arch/ppc/syslib/ppc85xx_rio.c
new file mode 100644
--- /dev/null
+++ b/arch/ppc/syslib/ppc85xx_rio.c
@@ -0,0 +1,867 @@
+/*
+ * MPC85xx RapidIO support
+ *
+ * Copyright 2005 MontaVista Software, Inc.
+ * Matt Porter <mporter@kernel.crashing.org>
+ *
+ * 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.
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/rio.h>
+#include <linux/rio_drv.h>
+
+#include <asm/io.h>
+
+#define RIO_REGS_BASE		(CCSRBAR + 0xc0000)
+#define RIO_ATMU_REGS_OFFSET	0x10c00
+#define RIO_MSG_REGS_OFFSET	0x11000
+#define RIO_MAINT_WIN_SIZE	0x400000
+#define RIO_DBELL_WIN_SIZE	0x1000
+
+#define RIO_MSG_OMR_MUI		0x00000002
+#define RIO_MSG_OSR_TE		0x00000080
+#define RIO_MSG_OSR_QOI		0x00000020
+#define RIO_MSG_OSR_QFI		0x00000010
+#define RIO_MSG_OSR_MUB		0x00000004
+#define RIO_MSG_OSR_EOMI	0x00000002
+#define RIO_MSG_OSR_QEI		0x00000001
+
+#define RIO_MSG_IMR_MI		0x00000002
+#define RIO_MSG_ISR_TE		0x00000080
+#define RIO_MSG_ISR_QFI		0x00000010
+#define RIO_MSG_ISR_DIQI	0x00000001
+
+#define RIO_MSG_DESC_SIZE	32
+#define RIO_MIN_TX_RING_SIZE	2
+#define RIO_MAX_TX_RING_SIZE	2048
+#define RIO_MIN_RX_RING_SIZE	2
+#define RIO_MAX_RX_RING_SIZE	2048
+
+#define DOORBELL_DMR_DI		0x00000002
+#define DOORBELL_DSR_TE		0x00000080
+#define DOORBELL_DSR_QFI	0x00000010
+#define DOORBELL_DSR_DIQI	0x00000001
+#define DOORBELL_TID_OFFSET	0x03
+#define DOORBELL_SID_OFFSET	0x05
+#define DOORBELL_INFO_OFFSET	0x06
+
+#define DOORBELL_MESSAGE_SIZE	0x08
+#define DBELL_SID(x)		(*(u8 *)(x + DOORBELL_SID_OFFSET))
+#define DBELL_TID(x)		(*(u8 *)(x + DOORBELL_TID_OFFSET))
+#define DBELL_INF(x)		(*(u16 *)(x + DOORBELL_INFO_OFFSET))
+
+#define is_power_of_2(x)	(((x) & ((x) - 1)) =3D=3D 0)
+
+struct rio_atmu_regs {
+	u32 rowtar;
+	u32 pad1;
+	u32 rowbar;
+	u32 pad2;
+	u32 rowar;
+	u32 pad3[3];
+};
+
+struct rio_msg_regs {
+	u32 omr;
+	u32 osr;
+	u32 pad1;
+	u32 odqdpar;
+	u32 pad2;
+	u32 osar;
+	u32 odpr;
+	u32 odatr;
+	u32 odcr;
+	u32 pad3;
+	u32 odqepar;
+	u32 pad4[13];
+	u32 imr;
+	u32 isr;
+	u32 pad5;
+	u32 ifqdpar;
+	u32 pad6;
+	u32 ifqepar;
+	u32 pad7[250];
+	u32 dmr;
+	u32 dsr;
+	u32 pad8;
+	u32 dqdpar;
+	u32 pad9;
+	u32 dqepar;
+	u32 pad10[26];
+	u32 pwmr;
+	u32 pwsr;
+	u32 pad11;
+	u32 pwqbar;
+};
+
+struct rio_tx_desc {
+	u32 res1;
+	u32 saddr;
+	u32 dport;
+	u32 dattr;
+	u32 res2;
+	u32 res3;
+	u32 dwcnt;
+	u32 res4;
+};
+
+static u32 regs_win;
+static struct rio_atmu_regs *atmu_regs;
+static struct rio_atmu_regs *maint_atmu_regs;
+static struct rio_atmu_regs *dbell_atmu_regs;
+static u32 dbell_win;
+static u32 maint_win;
+static struct rio_msg_regs *msg_regs;
+
+static struct rio_dbell_ring {
+	void *virt;
+	dma_addr_t phys;
+} dbell_ring;
+
+static struct rio_msg_tx_ring {
+	void *virt;
+	dma_addr_t phys;
+	void *virt_buffer[RIO_MAX_TX_RING_SIZE];
+	dma_addr_t phys_buffer[RIO_MAX_TX_RING_SIZE];
+	int tx_slot;
+	int size;
+} msg_tx_ring;
+
+static struct rio_msg_rx_ring {
+	void *virt;
+	dma_addr_t phys;
+	void *virt_buffer[RIO_MAX_RX_RING_SIZE];
+	int rx_slot;
+	int size;
+} msg_rx_ring;
+
+/**
+ * mpc85xx_rio_doorbell_send - Send a MPC85xx doorbell message
+ * @index: ID of RapidIO interface
+ * @destid: Destination ID of target device
+ * @data: 16-bit info field of RapidIO doorbell message
+ *
+ * Sends a MPC85xx doorbell message. Returns %0 on success or
+ * %-EINVAL on failure.
+ */
+static int mpc85xx_rio_doorbell_send(int index, u16 destid, u16 data)
+{
+	pr_debug("mpc85xx_doorbell_send: index %d destid %4.4x data %4.4x\n",
+		 index, destid, data);
+	out_be32((void *)&dbell_atmu_regs->rowtar, destid << 22);
+	out_be16((void *)(dbell_win), data);
+
+	return 0;
+}
+
+/**
+ * mpc85xx_local_config_read - Generate a MPC85xx local config space read
+ * @index: ID of RapdiIO interface
+ * @offset: Offset into configuration space
+ * @len: Length (in bytes) of the maintenance transaction
+ * @data: Value to be read into
+ *
+ * Generates a MPC85xx local configuration space read. Returns %0 on
+ * success or %-EINVAL on failure.
+ */
+static int mpc85xx_local_config_read(int index, u32 offset, int len, u32 *=
 data)
+{
+	pr_debug("mpc85xx_local_config_read: index %d offset %8.8x\n", index,
+		 offset);
+	*data =3D in_be32((void *)(regs_win + offset));
+
+	return 0;
+}
+
+/**
+ * mpc85xx_local_config_write - Generate a MPC85xx local config space write
+ * @index: ID of RapdiIO interface
+ * @offset: Offset into configuration space
+ * @len: Length (in bytes) of the maintenance transaction
+ * @data: Value to be written
+ *
+ * Generates a MPC85xx local configuration space write. Returns %0 on
+ * success or %-EINVAL on failure.
+ */
+static int mpc85xx_local_config_write(int index, u32 offset, int len, u32 =
data)
+{
+	pr_debug
+	    ("mpc85xx_local_config_write: index %d offset %8.8x data %8.8x\n",
+	     index, offset, data);
+	out_be32((void *)(regs_win + offset), data);
+
+	return 0;
+}
+
+/**
+ * mpc85xx_rio_config_read - Generate a MPC85xx read maintenance transacti=
on
+ * @index: ID of RapdiIO interface
+ * @destid: Destination ID of transaction
+ * @hopcount: Number of hops to target device
+ * @offset: Offset into configuration space
+ * @len: Length (in bytes) of the maintenance transaction
+ * @val: Location to be read into
+ *
+ * Generates a MPC85xx read maintenance transaction. Returns %0 on
+ * success or %-EINVAL on failure.
+ */
+static int
+mpc85xx_rio_config_read(int index, u16 destid, u8 hopcount, u32 offset, in=
t len,
+			u32 * val)
+{
+	u8 *data;
+
+	pr_debug
+	    ("mpc85xx_rio_config_read: index %d destid %d hopcount %d offset %8.8=
x len %d\n",
+	     index, destid, hopcount, offset, len);
+	out_be32((void *)&maint_atmu_regs->rowtar,
+		 (destid << 22) | (hopcount << 12) | ((offset & ~0x3) >> 9));
+
+	data =3D (u8 *) maint_win + offset;
+	switch (len) {
+	case 1:
+		*val =3D in_8((u8 *) data);
+		break;
+	case 2:
+		*val =3D in_be16((u16 *) data);
+		break;
+	default:
+		*val =3D in_be32((u32 *) data);
+		break;
+	}
+
+	return 0;
+}
+
+/**
+ * mpc85xx_rio_config_write - Generate a MPC85xx write maintenance transac=
tion
+ * @index: ID of RapdiIO interface
+ * @destid: Destination ID of transaction
+ * @hopcount: Number of hops to target device
+ * @offset: Offset into configuration space
+ * @len: Length (in bytes) of the maintenance transaction
+ * @val: Value to be written
+ *
+ * Generates an MPC85xx write maintenance transaction. Returns %0 on
+ * success or %-EINVAL on failure.
+ */
+static int
+mpc85xx_rio_config_write(int index, u16 destid, u8 hopcount, u32 offset,
+			 int len, u32 val)
+{
+	u8 *data;
+	pr_debug
+	    ("mpc85xx_rio_config_write: index %d destid %d hopcount %d offset %8.=
8x len %d val %8.8x\n",
+	     index, destid, hopcount, offset, len, val);
+	out_be32((void *)&maint_atmu_regs->rowtar,
+		 (destid << 22) | (hopcount << 12) | ((offset & ~0x3) >> 9));
+
+	data =3D (u8 *) maint_win + offset;
+	switch (len) {
+	case 1:
+		out_8((u8 *) data, val);
+		break;
+	case 2:
+		out_be16((u16 *) data, val);
+		break;
+	default:
+		out_be32((u32 *) data, val);
+		break;
+	}
+
+	return 0;
+}
+
+/**
+ * rio_hw_add_outb_message - Add message to the MPC85xx outbound message q=
ueue
+ * @mport: Master port with outbound message queue
+ * @rdev: Target of outbound message
+ * @mbox: Outbound mailbox
+ * @buffer: Message to add to outbound queue
+ * @len: Length of message
+ *
+ * Adds the @buffer message to the MPC85xx outbound message queue. Returns
+ * %0 on success or %-EINVAL on failure.
+ */
+int
+rio_hw_add_outb_message(struct rio_mport *mport, struct rio_dev *rdev, int=
 mbox,
+			void *buffer, size_t len)
+{
+	u32 omr;
+	struct rio_tx_desc *desc =3D
+	    (struct rio_tx_desc *)msg_tx_ring.virt + msg_tx_ring.tx_slot;
+	int ret =3D 0;
+
+	pr_debug(KERN_INFO
+		 "RIO: rio_hw_add_outb_message(): destid %4.4x mbox %d buffer %8.8x len =
%8.8x\n",
+		 rdev->destid, mbox, (int)buffer, len);
+
+	if ((len < 8) || (len > RIO_MAX_MSG_SIZE)) {
+		ret =3D -EINVAL;
+		goto out;
+	}
+
+	/* Copy and clear rest of buffer */
+	memcpy(msg_tx_ring.virt_buffer[msg_tx_ring.tx_slot], buffer, len);
+	if (len < (RIO_MAX_MSG_SIZE - 4))
+		memset((void *)((u32) msg_tx_ring.
+				virt_buffer[msg_tx_ring.tx_slot] + len), 0,
+		       RIO_MAX_MSG_SIZE - len);
+
+	/* Set mbox field for message */
+	desc->dport =3D mbox & 0x3;
+
+	/* Enable EOMI interrupt, set priority, and set destid */
+	desc->dattr =3D 0x28000000 | (rdev->destid << 2);
+
+	/* Set transfer size aligned to next power of 2 (in double words) */
+	desc->dwcnt =3D is_power_of_2(len) ? len : 1 << get_bitmask_order(len);
+
+	/* Set snooping and source buffer address */
+	desc->saddr =3D 0x00000004 | msg_tx_ring.phys_buffer[msg_tx_ring.tx_slot];
+
+	/* Increment enqueue pointer */
+	omr =3D in_be32((void *)&msg_regs->omr);
+	out_be32((void *)&msg_regs->omr, omr | RIO_MSG_OMR_MUI);
+
+	/* Go to next descriptor */
+	if (++msg_tx_ring.tx_slot =3D=3D msg_tx_ring.size)
+		msg_tx_ring.tx_slot =3D 0;
+
+      out:
+	return ret;
+}
+
+EXPORT_SYMBOL_GPL(rio_hw_add_outb_message);
+
+/**
+ * mpc85xx_rio_tx_handler - MPC85xx outbound message interrupt handler
+ * @irq: Linux interrupt number
+ * @dev_instance: Pointer to interrupt-specific data
+ * @regs: Register context
+ *
+ * Handles outbound message interrupts. Executes a register outbound
+ * mailbox event handler and acks the interrupt occurence.
+ */
+static irqreturn_t
+mpc85xx_rio_tx_handler(int irq, void *dev_instance, struct pt_regs *regs)
+{
+	int osr;
+	struct rio_mport *port =3D (struct rio_mport *)dev_instance;
+
+	osr =3D in_be32((void *)&msg_regs->osr);
+
+	if (osr & RIO_MSG_OSR_TE) {
+		printk(KERN_INFO "RIO: outbound message transmission error\n");
+		out_be32((void *)&msg_regs->osr, RIO_MSG_OSR_TE);
+		goto out;
+	}
+
+	if (osr & RIO_MSG_OSR_QOI) {
+		printk(KERN_INFO "RIO: outbound message queue overflow\n");
+		out_be32((void *)&msg_regs->osr, RIO_MSG_OSR_QOI);
+		goto out;
+	}
+
+	if (osr & RIO_MSG_OSR_EOMI) {
+		u32 dqp =3D in_be32((void *)&msg_regs->odqdpar);
+		int slot =3D (dqp - msg_tx_ring.phys) >> 5;
+		port->outb_msg[0].mcback(port, -1, slot);
+
+		/* Ack the end-of-message interrupt */
+		out_be32((void *)&msg_regs->osr, RIO_MSG_OSR_EOMI);
+	}
+
+      out:
+	return IRQ_HANDLED;
+}
+
+/**
+ * rio_open_outb_mbox - Initialize MPC85xx outbound mailbox
+ * @mport: Master port implementing the outbound message unit
+ * @mbox: Mailbox to open
+ * @entries: Number of entries in the outbound mailbox ring
+ *
+ * Initializes buffer ring, request the outbound message interrupt,
+ * and enables the outbound message unit. Returns %0 on success or
+ * %-EINVAL on failure.
+ */
+int rio_open_outb_mbox(struct rio_mport *mport, int mbox, int entries)
+{
+	int i, rc =3D 0;
+
+	if ((entries < RIO_MIN_TX_RING_SIZE) ||
+	    (entries > RIO_MAX_TX_RING_SIZE) || (!is_power_of_2(entries))) {
+		rc =3D -EINVAL;
+		goto out;
+	}
+
+	/* Initialize shadow copy ring */
+	msg_tx_ring.size =3D entries;
+
+	for (i =3D 0; i < msg_tx_ring.size; i++) {
+		msg_tx_ring.virt_buffer[i] =3D
+		    (void *)__get_free_page(GFP_KERNEL);
+		msg_tx_ring.phys_buffer[i] =3D
+		    (dma_addr_t) __pa(msg_tx_ring.virt_buffer[i]);
+	}
+
+	/* Initialize outbound message descriptor ring */
+	msg_tx_ring.virt =3D dma_alloc_coherent(NULL,
+					      msg_tx_ring.size *
+					      RIO_MSG_DESC_SIZE,
+					      &msg_tx_ring.phys, GFP_KERNEL);
+	memset(msg_tx_ring.virt, 0, msg_tx_ring.size * RIO_MSG_DESC_SIZE);
+	msg_tx_ring.tx_slot =3D 0;
+
+	/* Point dequeue/enqueue pointers at first entry in ring */
+	out_be32((void *)&msg_regs->odqdpar, msg_tx_ring.phys);
+	out_be32((void *)&msg_regs->odqepar, msg_tx_ring.phys);
+
+	/* Configure for snooping */
+	out_be32((void *)&msg_regs->osar, 0x00000004);
+
+	/* Clear interrupt status */
+	out_be32((void *)&msg_regs->osr, 0x000000b3);
+
+	/* Hook up outbound message handler */
+	request_irq(MPC85xx_IRQ_RIO_TX, mpc85xx_rio_tx_handler, 0, "msg_tx",
+		    (void *)mport);
+
+	/*
+	 * Configure outbound message unit
+	 *      Snooping
+	 *      Interrupts (all enabled, except QEIE)
+	 *      Chaining mode
+	 *      Disable
+	 */
+	out_be32((void *)&msg_regs->omr, 0x00100220);
+
+	/* Set number of entries */
+	out_be32((void *)&msg_regs->omr,
+		 in_be32((void *)&msg_regs->omr) |
+		 ((get_bitmask_order(entries) - 2) << 12));
+
+	/* Now enable the unit */
+	out_be32((void *)&msg_regs->omr, in_be32((void *)&msg_regs->omr) | 0x1);
+
+      out:
+	return rc;
+}
+
+/**
+ * rio_close_outb_mbox - Shut down MPC85xx outbound mailbox
+ * @mport: Master port implementing the outbound message unit
+ * @mbox: Mailbox to close
+ *
+ * Disables the outbound message unit, free all buffers, and
+ * frees the outbound message interrupt.
+ */
+void rio_close_outb_mbox(struct rio_mport *mport, int mbox)
+{
+	/* Disable inbound message unit */
+	out_be32((void *)&msg_regs->omr, 0);
+
+	/* Free ring */
+	dma_free_coherent(NULL, msg_tx_ring.size * RIO_MSG_DESC_SIZE,
+			  msg_tx_ring.virt, msg_tx_ring.phys);
+
+	/* Free interrupt */
+	free_irq(MPC85xx_IRQ_RIO_TX, (void *)mport);
+}
+
+/**
+ * mpc85xx_rio_rx_handler - MPC85xx inbound message interrupt handler
+ * @irq: Linux interrupt number
+ * @dev_instance: Pointer to interrupt-specific data
+ * @regs: Register context
+ *
+ * Handles inbound message interrupts. Executes a registered inbound
+ * mailbox event handler and acks the interrupt occurence.
+ */
+static irqreturn_t
+mpc85xx_rio_rx_handler(int irq, void *dev_instance, struct pt_regs *regs)
+{
+	int isr;
+	struct rio_mport *port =3D (struct rio_mport *)dev_instance;
+
+	isr =3D in_be32((void *)&msg_regs->isr);
+
+	if (isr & RIO_MSG_ISR_TE) {
+		printk(KERN_INFO "RIO: inbound message reception error\n");
+		out_be32((void *)&msg_regs->isr, RIO_MSG_ISR_TE);
+		goto out;
+	}
+
+	/* XXX Need to check/dispatch until queue empty */
+	if (isr & RIO_MSG_ISR_DIQI) {
+		/*
+		 * We implement *only* mailbox 0, but can receive messages
+		 * for any mailbox/letter to that mailbox destination. So,
+		 * make the callback with an unknown/invalid mailbox number
+		 * argument.
+		 */
+		port->inb_msg[0].mcback(port, -1, -1);
+
+		/* Ack the queueing interrupt */
+		out_be32((void *)&msg_regs->isr, RIO_MSG_ISR_DIQI);
+	}
+
+      out:
+	return IRQ_HANDLED;
+}
+
+/**
+ * rio_open_inb_mbox - Initialize MPC85xx inbound mailbox
+ * @mport: Master port implementing the inbound message unit
+ * @mbox: Mailbox to open
+ * @entries: Number of entries in the inbound mailbox ring
+ *
+ * Initializes buffer ring, request the inbound message interrupt,
+ * and enables the inbound message unit. Returns %0 on success
+ * or %-EINVAL on failure.
+ */
+int rio_open_inb_mbox(struct rio_mport *mport, int mbox, int entries)
+{
+	int i, rc =3D 0;
+
+	if ((entries < RIO_MIN_RX_RING_SIZE) ||
+	    (entries > RIO_MAX_RX_RING_SIZE) || (!is_power_of_2(entries))) {
+		rc =3D -EINVAL;
+		goto out;
+	}
+
+	/* Initialize client buffer ring */
+	msg_rx_ring.size =3D entries;
+	msg_rx_ring.rx_slot =3D 0;
+	for (i =3D 0; i < msg_rx_ring.size; i++)
+		msg_rx_ring.virt_buffer[i] =3D NULL;
+
+	/* Initialize inbound message ring */
+	msg_rx_ring.virt =3D dma_alloc_coherent(NULL,
+					      msg_rx_ring.size *
+					      RIO_MAX_MSG_SIZE,
+					      &msg_rx_ring.phys, GFP_KERNEL);
+
+	/* Point dequeue/enqueue pointers at first entry in ring */
+	out_be32((void *)&msg_regs->ifqdpar, (u32) msg_rx_ring.phys);
+	out_be32((void *)&msg_regs->ifqepar, (u32) msg_rx_ring.phys);
+
+	/* Clear interrupt status */
+	out_be32((void *)&msg_regs->isr, 0x00000091);
+
+	/* Hook up inbound message handler */
+	request_irq(MPC85xx_IRQ_RIO_RX, mpc85xx_rio_rx_handler, 0, "msg_rx",
+		    (void *)mport);
+
+	/*
+	 * Configure inbound message unit:
+	 *      Snooping
+	 *      4KB max message size
+	 *      Unmask all interrupt sources
+	 *      Disable
+	 */
+	out_be32((void *)&msg_regs->imr, 0x001b0060);
+
+	/* Set number of queue entries */
+	out_be32((void *)&msg_regs->imr,
+		 in_be32((void *)&msg_regs->imr) |
+		 ((get_bitmask_order(entries) - 2) << 12));
+
+	/* Now enable the unit */
+	out_be32((void *)&msg_regs->imr, in_be32((void *)&msg_regs->imr) | 0x1);
+
+      out:
+	return rc;
+}
+
+/**
+ * rio_close_inb_mbox - Shut down MPC85xx inbound mailbox
+ * @mport: Master port implementing the inbound message unit
+ * @mbox: Mailbox to close
+ *
+ * Disables the inbound message unit, free all buffers, and
+ * frees the inbound message interrupt.
+ */
+void rio_close_inb_mbox(struct rio_mport *mport, int mbox)
+{
+	/* Disable inbound message unit */
+	out_be32((void *)&msg_regs->imr, 0);
+
+	/* Free ring */
+	dma_free_coherent(NULL, msg_rx_ring.size * RIO_MAX_MSG_SIZE,
+			  msg_rx_ring.virt, msg_rx_ring.phys);
+
+	/* Free interrupt */
+	free_irq(MPC85xx_IRQ_RIO_RX, (void *)mport);
+}
+
+/**
+ * rio_hw_add_inb_buffer - Add buffer to the MPC85xx inbound message queue
+ * @mport: Master port implementing the inbound message unit
+ * @mbox: Inbound mailbox number
+ * @buf: Buffer to add to inbound queue
+ *
+ * Adds the @buf buffer to the MPC85xx inbound message queue. Returns
+ * %0 on success or %-EINVAL on failure.
+ */
+int rio_hw_add_inb_buffer(struct rio_mport *mport, int mbox, void *buf)
+{
+	int rc =3D 0;
+
+	pr_debug("RIO: rio_hw_add_inb_buffer(), msg_rx_ring.rx_slot %d\n",
+		 msg_rx_ring.rx_slot);
+
+	if (msg_rx_ring.virt_buffer[msg_rx_ring.rx_slot]) {
+		printk(KERN_ERR
+		       "RIO: error adding inbound buffer %d, buffer exists\n",
+		       msg_rx_ring.rx_slot);
+		rc =3D -EINVAL;
+		goto out;
+	}
+
+	msg_rx_ring.virt_buffer[msg_rx_ring.rx_slot] =3D buf;
+	if (++msg_rx_ring.rx_slot =3D=3D msg_rx_ring.size)
+		msg_rx_ring.rx_slot =3D 0;
+
+      out:
+	return rc;
+}
+
+EXPORT_SYMBOL_GPL(rio_hw_add_inb_buffer);
+
+/**
+ * rio_hw_get_inb_message - Fetch inbound message from the MPC85xx message=
 unit
+ * @mport: Master port implementing the inbound message unit
+ * @mbox: Inbound mailbox number
+ *
+ * Gets the next available inbound message from the inbound message queue.
+ * A pointer to the message is returned on success or NULL on failure.
+ */
+void *rio_hw_get_inb_message(struct rio_mport *mport, int mbox)
+{
+	u32 imr;
+	u32 phys_buf, virt_buf;
+	void *buf =3D NULL;
+	int buf_idx;
+
+	phys_buf =3D in_be32((void *)&msg_regs->ifqdpar);
+
+	/* If no more messages, then bail out */
+	if (phys_buf =3D=3D in_be32((void *)&msg_regs->ifqepar))
+		goto out2;
+
+	virt_buf =3D (u32) msg_rx_ring.virt + (phys_buf - msg_rx_ring.phys);
+	buf_idx =3D (phys_buf - msg_rx_ring.phys) / RIO_MAX_MSG_SIZE;
+	buf =3D msg_rx_ring.virt_buffer[buf_idx];
+
+	if (!buf) {
+		pr_debug(KERN_ERR
+			 "RIO: inbound message copy failed, no buffers\n");
+		goto out1;
+	}
+
+	/* Copy max message size, caller is expected to allocate that big */
+	memcpy(buf, (void *)virt_buf, RIO_MAX_MSG_SIZE);
+
+	/* Clear the available buffer */
+	msg_rx_ring.virt_buffer[buf_idx] =3D NULL;
+
+      out1:
+	imr =3D in_be32((void *)&msg_regs->imr);
+	out_be32((void *)&msg_regs->imr, imr | RIO_MSG_IMR_MI);
+
+      out2:
+	return buf;
+}
+
+EXPORT_SYMBOL_GPL(rio_hw_get_inb_message);
+
+/**
+ * mpc85xx_rio_dbell_handler - MPC85xx doorbell interrupt handler
+ * @irq: Linux interrupt number
+ * @dev_instance: Pointer to interrupt-specific data
+ * @regs: Register context
+ *
+ * Handles doorbell interrupts. Parses a list of registered
+ * doorbell event handlers and executes a matching event handler.
+ */
+static irqreturn_t
+mpc85xx_rio_dbell_handler(int irq, void *dev_instance, struct pt_regs *reg=
s)
+{
+	int dsr;
+	struct rio_mport *port =3D (struct rio_mport *)dev_instance;
+
+	dsr =3D in_be32((void *)&msg_regs->dsr);
+
+	if (dsr & DOORBELL_DSR_TE) {
+		printk(KERN_INFO "RIO: doorbell reception error\n");
+		out_be32((void *)&msg_regs->dsr, DOORBELL_DSR_TE);
+		goto out;
+	}
+
+	if (dsr & DOORBELL_DSR_QFI) {
+		printk(KERN_INFO "RIO: doorbell queue full\n");
+		out_be32((void *)&msg_regs->dsr, DOORBELL_DSR_QFI);
+		goto out;
+	}
+
+	/* XXX Need to check/dispatch until queue empty */
+	if (dsr & DOORBELL_DSR_DIQI) {
+		u32 dmsg =3D
+		    (u32) dbell_ring.virt +
+		    (in_be32((void *)&msg_regs->dqdpar) & 0xfff);
+		u32 dmr;
+		struct rio_dbell *dbell;
+		int found =3D 0;
+
+		pr_debug(KERN_INFO
+			 "RIO: processing doorbell, sid %2.2x tid %2.2x info %4.4x\n",
+			 DBELL_SID(dmsg), DBELL_TID(dmsg), DBELL_INF(dmsg));
+
+		list_for_each_entry(dbell, &port->dbells, node) {
+			if ((dbell->res->start <=3D DBELL_INF(dmsg)) &&
+			    (dbell->res->end >=3D DBELL_INF(dmsg))) {
+				found =3D 1;
+				break;
+			}
+		}
+		if (found) {
+			dbell->dinb(port, DBELL_SID(dmsg), DBELL_TID(dmsg),
+				    DBELL_INF(dmsg));
+		} else {
+			pr_debug(KERN_INFO
+				 "RIO: spurious doorbell, sid %2.2x tid %2.2x info %4.4x\n",
+				 DBELL_SID(dmsg), DBELL_TID(dmsg),
+				 DBELL_INF(dmsg));
+		}
+		dmr =3D in_be32((void *)&msg_regs->dmr);
+		out_be32((void *)&msg_regs->dmr, dmr | DOORBELL_DMR_DI);
+		out_be32((void *)&msg_regs->dsr, DOORBELL_DSR_DIQI);
+	}
+
+      out:
+	return IRQ_HANDLED;
+}
+
+/**
+ * mpc85xx_rio_doorbell_init - MPC85xx doorbell interface init
+ * @mport: Master port implementing the inbound doorbell unit
+ *
+ * Initializes doorbell unit hardware and inbound DMA buffer
+ * ring. Called from mpc85xx_rio_setup().
+ */
+static void mpc85xx_rio_doorbell_init(struct rio_mport *mport)
+{
+	/* Map outbound doorbell window immediately after maintenance window */
+	dbell_win =3D
+	    (u32) ioremap(mport->iores.start + RIO_MAINT_WIN_SIZE,
+			  RIO_DBELL_WIN_SIZE);
+
+	/* Initialize inbound doorbells */
+	dbell_ring.virt =3D dma_alloc_coherent(NULL,
+					     512 * DOORBELL_MESSAGE_SIZE,
+					     &dbell_ring.phys, GFP_KERNEL);
+
+	/* Point dequeue/enqueue pointers at first entry in ring */
+	out_be32((void *)&msg_regs->dqdpar, (u32) dbell_ring.phys);
+	out_be32((void *)&msg_regs->dqepar, (u32) dbell_ring.phys);
+
+	/* Clear interrupt status */
+	out_be32((void *)&msg_regs->dsr, 0x00000091);
+
+	/* Hook up doorbell handler */
+	request_irq(MPC85xx_IRQ_RIO_BELL, mpc85xx_rio_dbell_handler, 0,
+		    "dbell_rx", (void *)mport);
+
+	/* Configure doorbells for snooping, 512 entries, and enable */
+	out_be32((void *)&msg_regs->dmr, 0x00108161);
+}
+
+static char *cmdline =3D NULL;
+
+static int mpc85xx_rio_get_hdid(int index)
+{
+	/* XXX Need to parse multiple entries in some format */
+	if (!cmdline)
+		return -1;
+
+	return simple_strtol(cmdline, NULL, 0);
+}
+
+static int mpc85xx_rio_get_cmdline(char *s)
+{
+	if (!s)
+		return 0;
+
+	cmdline =3D s;
+	return 1;
+}
+
+__setup("riohdid=3D", mpc85xx_rio_get_cmdline);
+
+/**
+ * mpc85xx_rio_setup - Setup MPC85xx RapidIO interface
+ * @law_start: Starting physical address of RapidIO LAW
+ * @law_size: Size of RapidIO LAW
+ *
+ * Initializes MPC85xx RapidIO hardware interface, configures
+ * master port with system-specific info, and registers the
+ * master port with the RapidIO subsystem.
+ */
+void mpc85xx_rio_setup(int law_start, int law_size)
+{
+	struct rio_ops *ops;
+	struct rio_mport *port;
+
+	ops =3D kmalloc(sizeof(struct rio_ops), GFP_KERNEL);
+	ops->lcread =3D mpc85xx_local_config_read;
+	ops->lcwrite =3D mpc85xx_local_config_write;
+	ops->cread =3D mpc85xx_rio_config_read;
+	ops->cwrite =3D mpc85xx_rio_config_write;
+	ops->dsend =3D mpc85xx_rio_doorbell_send;
+
+	port =3D kmalloc(sizeof(struct rio_mport), GFP_KERNEL);
+	port->id =3D 0;
+	port->index =3D 0;
+	INIT_LIST_HEAD(&port->dbells);
+	port->iores.start =3D law_start;
+	port->iores.end =3D law_start + law_size;
+	port->iores.flags =3D IORESOURCE_MEM;
+
+	rio_init_dbell_res(&port->riores[RIO_DOORBELL_RESOURCE], 0, 0xffff);
+	rio_init_mbox_res(&port->riores[RIO_INB_MBOX_RESOURCE], 0, 0);
+	rio_init_mbox_res(&port->riores[RIO_OUTB_MBOX_RESOURCE], 0, 0);
+	strcpy(port->name, "RIO0 mport");
+
+	port->ops =3D ops;
+	port->host_deviceid =3D mpc85xx_rio_get_hdid(port->id);
+
+	rio_register_mport(port);
+
+	regs_win =3D (u32) ioremap(RIO_REGS_BASE, 0x20000);
+	atmu_regs =3D (struct rio_atmu_regs *)(regs_win + RIO_ATMU_REGS_OFFSET);
+	maint_atmu_regs =3D atmu_regs + 1;
+	dbell_atmu_regs =3D atmu_regs + 2;
+	msg_regs =3D (struct rio_msg_regs *)(regs_win + RIO_MSG_REGS_OFFSET);
+
+	/* Configure maintenance transaction window */
+	out_be32((void *)&maint_atmu_regs->rowbar, 0x000c0000);
+	out_be32((void *)&maint_atmu_regs->rowar, 0x80077015);
+
+	maint_win =3D (u32) ioremap(law_start, RIO_MAINT_WIN_SIZE);
+
+	/* Configure outbound doorbell window */
+	out_be32((void *)&dbell_atmu_regs->rowbar, 0x000c0400);
+	out_be32((void *)&dbell_atmu_regs->rowar, 0x8004200b);
+	mpc85xx_rio_doorbell_init(port);
+}
diff --git a/arch/ppc/syslib/ppc85xx_rio.h b/arch/ppc/syslib/ppc85xx_rio.h
new file mode 100644
--- /dev/null
+++ b/arch/ppc/syslib/ppc85xx_rio.h
@@ -0,0 +1,21 @@
+/*
+ * MPC85xx RapidIO definitions
+ *
+ * Copyright 2005 MontaVista Software, Inc.
+ * Matt Porter <mporter@kernel.crashing.org>
+ *
+ * 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.
+ */
+
+#ifndef __PPC_SYSLIB_PPC85XX_RIO_H
+#define __PPC_SYSLIB_PPC85XX_RIO_H
+
+#include <linux/config.h>
+#include <linux/init.h>
+
+extern void mpc85xx_rio_setup(int law_start, int law_size);
+
+#endif				/* __PPC_SYSLIB_PPC85XX_RIO_H */
diff --git a/include/asm-ppc/rio.h b/include/asm-ppc/rio.h
new file mode 100644
--- /dev/null
+++ b/include/asm-ppc/rio.h
@@ -0,0 +1,18 @@
+/*
+ * RapidIO architecture support
+ *
+ * Copyright 2005 MontaVista Software, Inc.
+ * Matt Porter <mporter@kernel.crashing.org>
+ *
+ * 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.
+ */
+
+#ifndef ASM_PPC_RIO_H
+#define ASM_PPC_RIO_H
+
+extern void platform_rio_init(void);
+
+#endif				/* ASM_PPC_RIO_H */

[PATCH][2/5] RapidIO support: core includes

From: Matt Porter <mporter@kernel.crashing.org>
Date: 2005-06-06 23:14:53

Add RapidIO core include files.

The core code implements enumeration/discovery, management of
devices/resources, and interfaces for RIO drivers.

Signed-off-by: Matt Porter <mporter@kernel.crashing.org>
diff --git a/include/linux/rio.h b/include/linux/rio.h
new file mode 100644
--- /dev/null
+++ b/include/linux/rio.h
@@ -0,0 +1,321 @@
+/*
+ * RapidIO interconnect services
+ * (RapidIO Interconnect Specification, http://www.rapidio.org)
+ *
+ * Copyright 2005 MontaVista Software, Inc.
+ * Matt Porter <mporter@kernel.crashing.org>
+ *
+ * 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.
+ */
+
+#ifndef LINUX_RIO_H
+#define LINUX_RIO_H
+
+#ifdef __KERNEL__
+
+#include <linux/types.h>
+#include <linux/config.h>
+#include <linux/ioport.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/device.h>
+#include <linux/rio_regs.h>
+
+#define RIO_ANY_DESTID		0xff
+#define RIO_NO_HOPCOUNT		-1
+
+#define RIO_MAX_MPORT_RESOURCES	16
+#define RIO_MAX_DEV_RESOURCES	16
+
+#define RIO_GLOBAL_TABLE	0xff	/* Indicates access of a switch's
+					   global routing table if it
+					   has multiple (or per port)
+					   tables */
+
+#define RIO_INVALID_ROUTE	0xff	/* Indicates that a route table
+					   entry is invalid (no route
+					   exists for the device ID) */
+
+#ifdef CONFIG_RAPIDIO_8_BIT_TRANSPORT
+#define RIO_MAX_ROUTE_ENTRIES	(1 << 8)
+#else
+#define RIO_MAX_ROUTE_ENTRIES	(1 << 16)
+#endif
+
+#define RIO_MAX_MBOX		4
+#define RIO_MAX_MSG_SIZE	0x1000
+
+/*
+ * Error values that may be returned by RIO functions.
+ */
+#define RIO_SUCCESSFUL			0x00
+#define RIO_BAD_SIZE			0x81
+
+/*
+ * For RIO devices, the region numbers are assigned this way:
+ *
+ *	0	RapidIO outbound doorbells
+ *      1-15	RapidIO memory regions
+ *
+ * For RIO master ports, the region number are assigned this way:
+ *
+ *	0	RapidIO inbound doorbells
+ *	1	RapidIO inbound mailboxes
+ *	1	RapidIO outbound mailboxes
+ */
+#define RIO_DOORBELL_RESOURCE	0
+#define RIO_INB_MBOX_RESOURCE	1
+#define RIO_OUTB_MBOX_RESOURCE	2
+
+extern struct bus_type rio_bus_type;
+extern struct list_head rio_devices;	/* list of all devices */
+
+struct rio_mport;
+
+/**
+ * struct rio_dev - RIO device info
+ * @global_list: Node in list of all RIO devices
+ * @net_list: Node in list of RIO devices in a network
+ * @net: Network this device is a part of
+ * @did: Device ID
+ * @vid: Vendor ID
+ * @device_rev: Device revision
+ * @asm_did: Assembly device ID
+ * @asm_vid: Assembly vendor ID
+ * @asm_rev: Assembly revision
+ * @efptr: Extended feature pointer
+ * @pef: Processing element features
+ * @swpinfo: Switch port info
+ * @src_ops: Source operation capabilities
+ * @dst_ops: Destination operation capabilities
+ * @rswitch: Pointer to &struct rio_switch if valid for this device
+ * @driver: Driver claiming this device
+ * @dev: Device model device
+ * @riores: RIO resources this device owns
+ * @destid: Network destination ID
+ */
+struct rio_dev {
+	struct list_head global_list;	/* node in list of all RIO devices */
+	struct list_head net_list;	/* node in per net list */
+	struct rio_net *net;	/* RIO net this device resides in */
+	u16 did;
+	u16 vid;
+	u32 device_rev;
+	u16 asm_did;
+	u16 asm_vid;
+	u16 asm_rev;
+	u16 efptr;
+	u32 pef;
+	u32 swpinfo;		/* Only used for switches */
+	u32 src_ops;
+	u32 dst_ops;
+	struct rio_switch *rswitch;	/* RIO switch info */
+	struct rio_driver *driver;	/* RIO driver claiming this device */
+	struct device dev;	/* LDM device structure */
+	struct resource riores[RIO_MAX_DEV_RESOURCES];
+	u16 destid;
+};
+
+#define rio_dev_g(n) list_entry(n, struct rio_dev, global_list)
+#define rio_dev_f(n) list_entry(n, struct rio_dev, net_list)
+#define	to_rio_dev(n) container_of(n, struct rio_dev, dev)
+
+/**
+ * struct rio_msg - RIO message event
+ * @res: Mailbox resource
+ * @mcback: Message event callback
+ */
+struct rio_msg {
+	struct resource *res;
+	void (*mcback) (struct rio_mport * mport, int mbox, int slot);
+};
+
+/**
+ * struct rio_dbell - RIO doorbell event
+ * @node: Node in list of doorbell events
+ * @res: Doorbell resource
+ * @dinb: Doorbell event callback
+ */
+struct rio_dbell {
+	struct list_head node;
+	struct resource *res;
+	void (*dinb) (struct rio_mport * mport, u16 src, u16 dst, u16 info);
+};
+
+/**
+ * struct rio_mport - RIO master port info
+ * @dbells: List of doorbell events=20
+ * @node: Node in global list of master ports
+ * @nnode: Node in network list of master ports
+ * @iores: I/O mem resource that this master port interface owns
+ * @riores: RIO resources that this master port interfaces owns
+ * @inb_msg: RIO inbound message event descriptors
+ * @outb_msg: RIO outbound message event descriptors
+ * @host_deviceid: Host device ID associated with this master port
+ * @ops: configuration space functions
+ * @id: Port ID, unique among all ports
+ * @index: Port index, unique among all port interfaces of the same type
+ * @name: Port name string
+ */
+struct rio_mport {
+	struct list_head dbells;	/* list of doorbell events */
+	struct list_head node;	/* node in global list of ports */
+	struct list_head nnode;	/* node in net list of ports */
+	struct resource iores;
+	struct resource riores[RIO_MAX_MPORT_RESOURCES];
+	struct rio_msg inb_msg[RIO_MAX_MBOX];
+	struct rio_msg outb_msg[RIO_MAX_MBOX];
+	int host_deviceid;	/* Host device ID */
+	struct rio_ops *ops;	/* maintenance transaction functions */
+	unsigned char id;	/* port ID, unique among all ports */
+	unsigned char index;	/* port index, unique among all port
+				   interfaces of the same type */
+	unsigned char name[40];
+};
+
+/**
+ * struct rio_net - RIO network info
+ * @node: Node in global list of RIO networks
+ * @devices: List of devices in this network
+ * @mports: List of master ports accessing this network
+ * @hport: Default port for accessing this network
+ * @id: RIO network ID
+ */
+struct rio_net {
+	struct list_head node;	/* node in list of networks */
+	struct list_head devices;	/* list of devices in this net */
+	struct list_head mports;	/* list of ports accessing net */
+	struct rio_mport *hport;	/* primary port for accessing net */
+	unsigned char id;	/* RIO network ID */
+};
+
+/**
+ * struct rio_switch - RIO switch info
+ * @node: Node in global list of switches
+ * @switchid: Switch ID that is unique across a network
+ * @hopcount: Hopcount to this switch
+ * @destid: Associated destid in the path
+ * @route_table: Copy of switch routing table
+ * @add_entry: Callback for switch-specific route add function
+ * @get_entry: Callback for switch-specific route get function
+ */
+struct rio_switch {
+	struct list_head node;
+	u16 switchid;
+	u16 hopcount;
+	u16 destid;
+	u8 route_table[RIO_MAX_ROUTE_ENTRIES];
+	int (*add_entry) (struct rio_mport * mport, u16 destid, u8 hopcount,
+			  u16 table, u16 route_destid, u8 route_port);
+	int (*get_entry) (struct rio_mport * mport, u16 destid, u8 hopcount,
+			  u16 table, u16 route_destid, u8 * route_port);
+};
+
+/* Low-level architecture-dependent routines */
+
+/**
+ * struct rio_ops - Low-level RIO configuration space operations
+ * @lcread: Callback to perform local (master port) read of config space.
+ * @lcwrite: Callback to perform local (master port) write of config space.
+ * @cread: Callback to perform network read of config space.
+ * @cwrite: Callback to perform network write of config space.
+ * @dsend: Callback to send a doorbell message.
+ */
+struct rio_ops {
+	int (*lcread) (int index, u32 offset, int len, u32 * data);
+	int (*lcwrite) (int index, u32 offset, int len, u32 data);
+	int (*cread) (int index, u16 destid, u8 hopcount, u32 offset, int len,
+		      u32 * data);
+	int (*cwrite) (int index, u16 destid, u8 hopcount, u32 offset, int len,
+		       u32 data);
+	int (*dsend) (int index, u16 destid, u16 data);
+};
+
+#define RIO_RESOURCE_MEM	0x00000100
+#define RIO_RESOURCE_DOORBELL	0x00000200
+#define RIO_RESOURCE_MAILBOX	0x00000400
+
+#define RIO_RESOURCE_CACHEABLE	0x00010000
+#define RIO_RESOURCE_PCI	0x00020000
+
+#define RIO_RESOURCE_BUSY	0x80000000
+
+/**
+ * struct rio_driver - RIO driver info
+ * @node: Node in list of drivers
+ * @name: RIO driver name
+ * @id_table: RIO device ids to be associated with this driver
+ * @probe: RIO device inserted
+ * @remove: RIO device removed
+ * @suspend: RIO device suspended
+ * @resume: RIO device awakened
+ * @enable_wake: RIO device enable wake event
+ * @driver: LDM driver struct
+ *
+ * Provides info on a RIO device driver for insertion/removal and
+ * power management purposes.
+ */
+struct rio_driver {
+	struct list_head node;
+	char *name;
+	const struct rio_device_id *id_table;
+	int (*probe) (struct rio_dev * dev, const struct rio_device_id * id);
+	void (*remove) (struct rio_dev * dev);
+	int (*suspend) (struct rio_dev * dev, u32 state);
+	int (*resume) (struct rio_dev * dev);
+	int (*enable_wake) (struct rio_dev * dev, u32 state, int enable);
+	struct device_driver driver;
+};
+
+#define	to_rio_driver(drv) container_of(drv,struct rio_driver, driver)
+
+/**
+ * struct rio_device_id - RIO device identifier
+ * @did: RIO device ID
+ * @vid: RIO vendor ID
+ * @asm_did: RIO assembly device ID
+ * @asm_vid: RIO assembly vendor ID
+ *
+ * Identifies a RIO device based on both the device/vendor IDs and
+ * the assembly device/vendor IDs.
+ */
+struct rio_device_id {
+	u16 did, vid;
+	u16 asm_did, asm_vid;
+};
+
+/**
+ * struct rio_route_ops - Per-switch route operations
+ * @vid: RIO vendor ID
+ * @did: RIO device ID
+ * @add_hook: Callback that adds a route entry
+ * @get_hook: Callback that gets a route entry
+ *
+ * Defines the operations that are necessary to manipulate the route
+ * tables for a particular RIO switch device.
+ */
+struct rio_route_ops {
+	u16 vid, did;
+	int (*add_hook) (struct rio_mport * mport, u16 destid, u8 hopcount,
+			 u16 table, u16 route_destid, u8 route_port);
+	int (*get_hook) (struct rio_mport * mport, u16 destid, u8 hopcount,
+			 u16 table, u16 route_destid, u8 * route_port);
+};
+
+/* Architecture and hardware-specific functions */
+extern int rio_init_mports(void);
+extern void rio_register_mport(struct rio_mport *);
+extern int rio_hw_add_outb_message(struct rio_mport *, struct rio_dev *, i=
nt,
+				   void *, size_t);
+extern int rio_hw_add_inb_buffer(struct rio_mport *, int, void *);
+extern void *rio_hw_get_inb_message(struct rio_mport *, int);
+extern int rio_open_inb_mbox(struct rio_mport *, int, int);
+extern void rio_close_inb_mbox(struct rio_mport *, int);
+extern int rio_open_outb_mbox(struct rio_mport *, int, int);
+extern void rio_close_outb_mbox(struct rio_mport *, int);
+
+#endif				/* __KERNEL__ */
+#endif				/* LINUX_RIO_H */
diff --git a/include/linux/rio_drv.h b/include/linux/rio_drv.h
new file mode 100644
--- /dev/null
+++ b/include/linux/rio_drv.h
@@ -0,0 +1,469 @@
+/*
+ * RapidIO driver services
+ *
+ * Copyright 2005 MontaVista Software, Inc.
+ * Matt Porter <mporter@kernel.crashing.org>
+ *
+ * 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.
+ */
+
+#ifndef LINUX_RIO_DRV_H
+#define LINUX_RIO_DRV_H
+
+#ifdef __KERNEL__
+
+#include <linux/types.h>
+#include <linux/config.h>
+#include <linux/ioport.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/device.h>
+#include <linux/rio.h>
+
+extern int __rio_local_read_config_32(struct rio_mport *port, u32 offset,
+				      u32 * data);
+extern int __rio_local_write_config_32(struct rio_mport *port, u32 offset,
+				       u32 data);
+extern int __rio_local_read_config_16(struct rio_mport *port, u32 offset,
+				      u16 * data);
+extern int __rio_local_write_config_16(struct rio_mport *port, u32 offset,
+				       u16 data);
+extern int __rio_local_read_config_8(struct rio_mport *port, u32 offset,
+				     u8 * data);
+extern int __rio_local_write_config_8(struct rio_mport *port, u32 offset,
+				      u8 data);
+
+extern int rio_mport_read_config_32(struct rio_mport *port, u16 destid,
+				    u8 hopcount, u32 offset, u32 * data);
+extern int rio_mport_write_config_32(struct rio_mport *port, u16 destid,
+				     u8 hopcount, u32 offset, u32 data);
+extern int rio_mport_read_config_16(struct rio_mport *port, u16 destid,
+				    u8 hopcount, u32 offset, u16 * data);
+extern int rio_mport_write_config_16(struct rio_mport *port, u16 destid,
+				     u8 hopcount, u32 offset, u16 data);
+extern int rio_mport_read_config_8(struct rio_mport *port, u16 destid,
+				   u8 hopcount, u32 offset, u8 * data);
+extern int rio_mport_write_config_8(struct rio_mport *port, u16 destid,
+				    u8 hopcount, u32 offset, u8 data);
+
+/**
+ * rio_local_read_config_32 - Read 32 bits from local configuration space
+ * @port: Master port
+ * @offset: Offset into local configuration space
+ * @data: Pointer to read data into
+ *=20
+ * Reads 32 bits of data from the specified offset within the local
+ * device's configuration space.
+ */
+static inline int rio_local_read_config_32(struct rio_mport *port, u32 off=
set,
+					   u32 * data)
+{
+	return __rio_local_read_config_32(port, offset, data);
+}
+
+/**
+ * rio_local_write_config_32 - Write 32 bits to local configuration space
+ * @port: Master port
+ * @offset: Offset into local configuration space
+ * @data: Data to be written=20
+ *=20
+ * Writes 32 bits of data to the specified offset within the local
+ * device's configuration space.
+ */
+static inline int rio_local_write_config_32(struct rio_mport *port, u32 of=
fset,
+					    u32 data)
+{
+	return __rio_local_write_config_32(port, offset, data);
+}
+
+/**
+ * rio_local_read_config_16 - Read 16 bits from local configuration space
+ * @port: Master port
+ * @offset: Offset into local configuration space
+ * @data: Pointer to read data into
+ *=20
+ * Reads 16 bits of data from the specified offset within the local
+ * device's configuration space.
+ */
+static inline int rio_local_read_config_16(struct rio_mport *port, u32 off=
set,
+					   u16 * data)
+{
+	return __rio_local_read_config_16(port, offset, data);
+}
+
+/**
+ * rio_local_write_config_16 - Write 16 bits to local configuration space
+ * @port: Master port
+ * @offset: Offset into local configuration space
+ * @data: Data to be written=20
+ *=20
+ * Writes 16 bits of data to the specified offset within the local
+ * device's configuration space.
+ */
+
+static inline int rio_local_write_config_16(struct rio_mport *port, u32 of=
fset,
+					    u16 data)
+{
+	return __rio_local_write_config_16(port, offset, data);
+}
+
+/**
+ * rio_local_read_config_8 - Read 8 bits from local configuration space
+ * @port: Master port
+ * @offset: Offset into local configuration space
+ * @data: Pointer to read data into
+ *=20
+ * Reads 8 bits of data from the specified offset within the local
+ * device's configuration space.
+ */
+static inline int rio_local_read_config_8(struct rio_mport *port, u32 offs=
et,
+					  u8 * data)
+{
+	return __rio_local_read_config_8(port, offset, data);
+}
+
+/**
+ * rio_local_write_config_8 - Write 8 bits to local configuration space
+ * @port: Master port
+ * @offset: Offset into local configuration space
+ * @data: Data to be written=20
+ *=20
+ * Writes 8 bits of data to the specified offset within the local
+ * device's configuration space.
+ */
+static inline int rio_local_write_config_8(struct rio_mport *port, u32 off=
set,
+					   u8 data)
+{
+	return __rio_local_write_config_8(port, offset, data);
+}
+
+/**
+ * rio_read_config_32 - Read 32 bits from configuration space
+ * @rdev: RIO device
+ * @offset: Offset into device configuration space
+ * @data: Pointer to read data into
+ *=20
+ * Reads 32 bits of data from the specified offset within the
+ * RIO device's configuration space.
+ */
+static inline int rio_read_config_32(struct rio_dev *rdev, u32 offset,
+				     u32 * data)
+{
+	u8 hopcount =3D 0xff;
+	u16 destid =3D rdev->destid;
+
+	if (rdev->rswitch) {
+		destid =3D rdev->rswitch->destid;
+		hopcount =3D rdev->rswitch->hopcount;
+	}
+
+	return rio_mport_read_config_32(rdev->net->hport, destid, hopcount,
+					offset, data);
+};
+
+/**
+ * rio_write_config_32 - Write 32 bits to configuration space
+ * @rdev: RIO device
+ * @offset: Offset into device configuration space
+ * @data: Data to be written
+ *=20
+ * Writes 32 bits of data to the specified offset within the
+ * RIO device's configuration space.
+ */
+static inline int rio_write_config_32(struct rio_dev *rdev, u32 offset,
+				      u32 data)
+{
+	u8 hopcount =3D 0xff;
+	u16 destid =3D rdev->destid;
+
+	if (rdev->rswitch) {
+		destid =3D rdev->rswitch->destid;
+		hopcount =3D rdev->rswitch->hopcount;
+	}
+
+	return rio_mport_write_config_32(rdev->net->hport, destid, hopcount,
+					 offset, data);
+};
+
+/**
+ * rio_read_config_16 - Read 16 bits from configuration space
+ * @rdev: RIO device
+ * @offset: Offset into device configuration space
+ * @data: Pointer to read data into
+ *=20
+ * Reads 16 bits of data from the specified offset within the
+ * RIO device's configuration space.
+ */
+static inline int rio_read_config_16(struct rio_dev *rdev, u32 offset,
+				     u16 * data)
+{
+	u8 hopcount =3D 0xff;
+	u16 destid =3D rdev->destid;
+
+	if (rdev->rswitch) {
+		destid =3D rdev->rswitch->destid;
+		hopcount =3D rdev->rswitch->hopcount;
+	}
+
+	return rio_mport_read_config_16(rdev->net->hport, destid, hopcount,
+					offset, data);
+};
+
+/**
+ * rio_write_config_16 - Write 16 bits to configuration space
+ * @rdev: RIO device
+ * @offset: Offset into device configuration space
+ * @data: Data to be written
+ *=20
+ * Writes 16 bits of data to the specified offset within the
+ * RIO device's configuration space.
+ */
+static inline int rio_write_config_16(struct rio_dev *rdev, u32 offset,
+				      u16 data)
+{
+	u8 hopcount =3D 0xff;
+	u16 destid =3D rdev->destid;
+
+	if (rdev->rswitch) {
+		destid =3D rdev->rswitch->destid;
+		hopcount =3D rdev->rswitch->hopcount;
+	}
+
+	return rio_mport_write_config_16(rdev->net->hport, destid, hopcount,
+					 offset, data);
+};
+
+/**
+ * rio_read_config_8 - Read 8 bits from configuration space
+ * @rdev: RIO device
+ * @offset: Offset into device configuration space
+ * @data: Pointer to read data into
+ *=20
+ * Reads 8 bits of data from the specified offset within the
+ * RIO device's configuration space.
+ */
+static inline int rio_read_config_8(struct rio_dev *rdev, u32 offset, u8 *=
 data)
+{
+	u8 hopcount =3D 0xff;
+	u16 destid =3D rdev->destid;
+
+	if (rdev->rswitch) {
+		destid =3D rdev->rswitch->destid;
+		hopcount =3D rdev->rswitch->hopcount;
+	}
+
+	return rio_mport_read_config_8(rdev->net->hport, destid, hopcount,
+				       offset, data);
+};
+
+/**
+ * rio_write_config_8 - Write 8 bits to configuration space
+ * @rdev: RIO device
+ * @offset: Offset into device configuration space
+ * @data: Data to be written
+ *=20
+ * Writes 8 bits of data to the specified offset within the
+ * RIO device's configuration space.
+ */
+static inline int rio_write_config_8(struct rio_dev *rdev, u32 offset, u8 =
data)
+{
+	u8 hopcount =3D 0xff;
+	u16 destid =3D rdev->destid;
+
+	if (rdev->rswitch) {
+		destid =3D rdev->rswitch->destid;
+		hopcount =3D rdev->rswitch->hopcount;
+	}
+
+	return rio_mport_write_config_8(rdev->net->hport, destid, hopcount,
+					offset, data);
+};
+
+extern int rio_mport_send_doorbell(struct rio_mport *mport, u16 destid,
+				   u16 data);
+
+/**
+ * rio_send_doorbell - Send a doorbell message to a device
+ * @rdev: RIO device
+ * @data: Doorbell message data
+ *=20
+ * Send a doorbell message to a RIO device. The doorbell message
+ * has a 16-bit info field provided by the @data argument.
+ */
+static inline int rio_send_doorbell(struct rio_dev *rdev, u16 data)
+{
+	return rio_mport_send_doorbell(rdev->net->hport, rdev->destid, data);
+};
+
+/**
+ * rio_init_mbox_res - Initialize a RIO mailbox resource
+ * @res: resource struct
+ * @start: start of mailbox range
+ * @end: end of mailbox range
+ *
+ * This function is used to initialize the fields of a resource
+ * for use as a mailbox resource.  It initializes a range of
+ * mailboxes using the start and end arguments.
+ */
+static inline void rio_init_mbox_res(struct resource *res, int start, int =
end)
+{
+	memset(res, 0, sizeof(struct resource));
+	res->start =3D start;
+	res->end =3D end;
+	res->flags =3D RIO_RESOURCE_MAILBOX;
+}
+
+/**
+ * rio_init_dbell_res - Initialize a RIO doorbell resource
+ * @res: resource struct
+ * @start: start of doorbell range
+ * @end: end of doorbell range
+ *
+ * This function is used to initialize the fields of a resource
+ * for use as a doorbell resource.  It initializes a range of
+ * doorbell messages using the start and end arguments.
+ */
+static inline void rio_init_dbell_res(struct resource *res, u16 start, u16=
 end)
+{
+	memset(res, 0, sizeof(struct resource));
+	res->start =3D start;
+	res->end =3D end;
+	res->flags =3D RIO_RESOURCE_DOORBELL;
+}
+
+/**
+ * RIO_DEVICE - macro used to describe a specific RIO device
+ * @vid: the 16 bit RIO vendor ID
+ * @did: the 16 bit RIO device ID
+ *
+ * This macro is used to create a struct rio_device_id that matches a
+ * specific device.  The assembly vendor and assembly device fields
+ * will be set to %RIO_ANY_ID.
+ */
+#define RIO_DEVICE(dev,ven) \
+	.did =3D (dev), .vid =3D (ven), \
+	.asm_did =3D RIO_ANY_ID, .asm_vid =3D RIO_ANY_ID
+
+/* Mailbox management */
+extern int rio_request_outb_mbox(struct rio_mport *, int, int,
+				 void (*)(struct rio_mport *, int, int));
+extern int rio_release_outb_mbox(struct rio_mport *, int);
+
+/**
+ * rio_add_outb_message - Add RIO message to an outbound mailbox queue
+ * @mport: RIO master port containing the outbound queue
+ * @rdev: RIO device the message is be sent to
+ * @mbox: The outbound mailbox queue
+ * @buffer: Pointer to the message buffer
+ * @len: Length of the message buffer
+ *
+ * Adds a RIO message buffer to an outbound mailbox queue for
+ * transmission. Returns 0 on success.
+ */
+static inline int rio_add_outb_message(struct rio_mport *mport,
+				       struct rio_dev *rdev, int mbox,
+				       void *buffer, size_t len)
+{
+	return rio_hw_add_outb_message(mport, rdev, mbox, buffer, len);
+}
+
+extern int rio_request_inb_mbox(struct rio_mport *, int, int,
+				void (*)(struct rio_mport *, int, int));
+extern int rio_release_inb_mbox(struct rio_mport *, int);
+
+/**
+ * rio_add_inb_buffer - Add buffer to an inbound mailbox queue
+ * @mport: Master port containing the inbound mailbox
+ * @mbox: The inbound mailbox number
+ * @buffer: Pointer to the message buffer
+ *
+ * Adds a buffer to an inbound mailbox queue for reception. Returns
+ * 0 on success.
+ */
+static inline int rio_add_inb_buffer(struct rio_mport *mport, int mbox,
+				     void *buffer)
+{
+	return rio_hw_add_inb_buffer(mport, mbox, buffer);
+}
+
+/**
+ * rio_get_inb_message - Get A RIO message from an inbound mailbox queue
+ * @mport: Master port containing the inbound mailbox
+ * @mbox: The inbound mailbox number
+ * @buffer: Pointer to the message buffer
+ *
+ * Get a RIO message from an inbound mailbox queue. Returns 0 on success.
+ */
+static inline void *rio_get_inb_message(struct rio_mport *mport, int mbox)
+{
+	return rio_hw_get_inb_message(mport, mbox);
+}
+
+/* Doorbell management */
+extern int rio_request_inb_dbell(struct rio_mport *, u16, u16,
+				 void (*)(struct rio_mport *, u16, u16, u16));
+extern int rio_release_inb_dbell(struct rio_mport *, u16, u16);
+extern struct resource *rio_request_outb_dbell(struct rio_dev *, u16, u16);
+extern int rio_release_outb_dbell(struct rio_dev *, struct resource *);
+
+/* Memory region management */
+int rio_claim_resource(struct rio_dev *, int);
+int rio_request_regions(struct rio_dev *, char *);
+void rio_release_regions(struct rio_dev *);
+int rio_request_region(struct rio_dev *, int, char *);
+void rio_release_region(struct rio_dev *, int);
+
+/* LDM support */
+int rio_register_driver(struct rio_driver *);
+void rio_unregister_driver(struct rio_driver *);
+struct rio_dev *rio_dev_get(struct rio_dev *);
+void rio_dev_put(struct rio_dev *);
+
+/**
+ * rio_name - Get the unique RIO device identifier
+ * @rdev: RIO device
+ *
+ * Get the unique RIO device identifier. Returns the device
+ * identifier string.
+ */
+static inline char *rio_name(struct rio_dev *rdev)
+{
+	return rdev->dev.bus_id;
+}
+
+/**
+ * rio_get_drvdata - Get RIO driver specific data
+ * @rdev: RIO device
+ *
+ * Get RIO driver specific data. Returns a pointer to the
+ * driver specific data.
+ */
+static inline void *rio_get_drvdata(struct rio_dev *rdev)
+{
+	return dev_get_drvdata(&rdev->dev);
+}
+
+/**
+ * rio_set_drvdata - Set RIO driver specific data
+ * @rdev: RIO device
+ * @data: Pointer to driver specific data
+ *
+ * Set RIO driver specific data. device struct driver data pointer
+ * is set to the @data argument.
+ */
+static inline void rio_set_drvdata(struct rio_dev *rdev, void *data)
+{
+	dev_set_drvdata(&rdev->dev, data);
+}
+
+/* Misc driver helpers */
+extern u16 rio_local_get_device_id(struct rio_mport *port);
+extern struct rio_dev *rio_get_device(u16 vid, u16 did, struct rio_dev *fr=
om);
+extern struct rio_dev *rio_get_asm(u16 vid, u16 did, u16 asm_vid, u16 asm_=
did,
+				   struct rio_dev *from);
+
+#endif				/* __KERNEL__ */
+#endif				/* LINUX_RIO_DRV_H */
diff --git a/include/linux/rio_ids.h b/include/linux/rio_ids.h
new file mode 100644
--- /dev/null
+++ b/include/linux/rio_ids.h
@@ -0,0 +1,24 @@
+/*
+ * RapidIO devices
+ *
+ * Copyright 2005 MontaVista Software, Inc.
+ * Matt Porter <mporter@kernel.crashing.org>
+ *
+ * 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.
+ */
+
+#ifndef LINUX_RIO_IDS_H
+#define LINUX_RIO_IDS_H
+
+#define RIO_ANY_ID			0xffff
+
+#define RIO_VID_FREESCALE		0x0002
+#define RIO_DID_MPC8560			0x0003
+
+#define RIO_VID_TUNDRA			0x000d
+#define RIO_DID_TSI500			0x0500
+
+#endif				/* LINUX_RIO_IDS_H */
diff --git a/include/linux/rio_regs.h b/include/linux/rio_regs.h
new file mode 100644
--- /dev/null
+++ b/include/linux/rio_regs.h
@@ -0,0 +1,202 @@
+/*
+ * RapidIO register definitions
+ *
+ * Copyright 2005 MontaVista Software, Inc.
+ * Matt Porter <mporter@kernel.crashing.org>
+ *
+ * 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.
+ */
+
+#ifndef LINUX_RIO_REGS_H
+#define LINUX_RIO_REGS_H
+
+/*
+ * In RapidIO, each device has a 2MB configuration space that is
+ * accessed via maintenance transactions.  Portions of configuration
+ * space are standardized and/or reserved.
+ */
+#define RIO_DEV_ID_CAR		0x00	/* [I] Device Identity CAR */
+#define RIO_DEV_INFO_CAR	0x04	/* [I] Device Information CAR */
+#define RIO_ASM_ID_CAR		0x08	/* [I] Assembly Identity CAR */
+#define  RIO_ASM_ID_MASK		0xffff0000	/* [I] Asm ID Mask */
+#define  RIO_ASM_VEN_ID_MASK		0x0000ffff	/* [I] Asm Vend Mask */
+
+#define RIO_ASM_INFO_CAR	0x0c	/* [I] Assembly Information CAR */
+#define  RIO_ASM_REV_MASK		0xffff0000	/* [I] Asm Rev Mask */
+#define  RIO_EXT_FTR_PTR_MASK		0x0000ffff	/* [I] EF_PTR Mask */
+
+#define RIO_PEF_CAR		0x10	/* [I] Processing Element Features CAR */
+#define  RIO_PEF_BRIDGE			0x80000000	/* [I] Bridge */
+#define  RIO_PEF_MEMORY			0x40000000	/* [I] MMIO */
+#define  RIO_PEF_PROCESSOR		0x20000000	/* [I] Processor */
+#define  RIO_PEF_SWITCH			0x10000000	/* [I] Switch */
+#define  RIO_PEF_INB_MBOX		0x00f00000	/* [II] Mailboxes */
+#define  RIO_PEF_INB_MBOX0		0x00800000	/* [II] Mailbox 0 */
+#define  RIO_PEF_INB_MBOX1		0x00400000	/* [II] Mailbox 1 */
+#define  RIO_PEF_INB_MBOX2		0x00200000	/* [II] Mailbox 2 */
+#define  RIO_PEF_INB_MBOX3		0x00100000	/* [II] Mailbox 3 */
+#define  RIO_PEF_INB_DOORBELL		0x00080000	/* [II] Doorbells */
+#define  RIO_PEF_CTLS			0x00000010	/* [III] CTLS */
+#define  RIO_PEF_EXT_FEATURES		0x00000008	/* [I] EFT_PTR valid */
+#define  RIO_PEF_ADDR_66		0x00000004	/* [I] 66 bits */
+#define  RIO_PEF_ADDR_50		0x00000002	/* [I] 50 bits */
+#define  RIO_PEF_ADDR_34		0x00000001	/* [I] 34 bits */
+
+#define RIO_SWP_INFO_CAR	0x14	/* [I] Switch Port Information CAR */
+#define  RIO_SWP_INFO_PORT_TOTAL_MASK	0x0000ff00	/* [I] Total number of po=
rts */
+#define  RIO_SWP_INFO_PORT_NUM_MASK	0x000000ff	/* [I] Maintenance transact=
ion port number */
+#define  RIO_GET_TOTAL_PORTS(x)		((x & RIO_SWP_INFO_PORT_TOTAL_MASK) >> 8)
+
+#define RIO_SRC_OPS_CAR		0x18	/* [I] Source Operations CAR */
+#define  RIO_SRC_OPS_READ		0x00008000	/* [I] Read op */
+#define  RIO_SRC_OPS_WRITE		0x00004000	/* [I] Write op */
+#define  RIO_SRC_OPS_STREAM_WRITE	0x00002000	/* [I] Str-write op */
+#define  RIO_SRC_OPS_WRITE_RESPONSE	0x00001000	/* [I] Write/resp op */
+#define  RIO_SRC_OPS_DATA_MSG		0x00000800	/* [II] Data msg op */
+#define  RIO_SRC_OPS_DOORBELL		0x00000400	/* [II] Doorbell op */
+#define  RIO_SRC_OPS_ATOMIC_TST_SWP	0x00000100	/* [I] Atomic TAS op */
+#define  RIO_SRC_OPS_ATOMIC_INC		0x00000080	/* [I] Atomic inc op */
+#define  RIO_SRC_OPS_ATOMIC_DEC		0x00000040	/* [I] Atomic dec op */
+#define  RIO_SRC_OPS_ATOMIC_SET		0x00000020	/* [I] Atomic set op */
+#define  RIO_SRC_OPS_ATOMIC_CLR		0x00000010	/* [I] Atomic clr op */
+#define  RIO_SRC_OPS_PORT_WRITE		0x00000004	/* [I] Port-write op */
+
+#define RIO_DST_OPS_CAR		0x1c	/* Destination Operations CAR */
+#define  RIO_DST_OPS_READ		0x00008000	/* [I] Read op */
+#define  RIO_DST_OPS_WRITE		0x00004000	/* [I] Write op */
+#define  RIO_DST_OPS_STREAM_WRITE	0x00002000	/* [I] Str-write op */
+#define  RIO_DST_OPS_WRITE_RESPONSE	0x00001000	/* [I] Write/resp op */
+#define  RIO_DST_OPS_DATA_MSG		0x00000800	/* [II] Data msg op */
+#define  RIO_DST_OPS_DOORBELL		0x00000400	/* [II] Doorbell op */
+#define  RIO_DST_OPS_ATOMIC_TST_SWP	0x00000100	/* [I] Atomic TAS op */
+#define  RIO_DST_OPS_ATOMIC_INC		0x00000080	/* [I] Atomic inc op */
+#define  RIO_DST_OPS_ATOMIC_DEC		0x00000040	/* [I] Atomic dec op */
+#define  RIO_DST_OPS_ATOMIC_SET		0x00000020	/* [I] Atomic set op */
+#define  RIO_DST_OPS_ATOMIC_CLR		0x00000010	/* [I] Atomic clr op */
+#define  RIO_DST_OPS_PORT_WRITE		0x00000004	/* [I] Port-write op */
+
+					/* 0x20-0x3c *//* Reserved */
+
+#define RIO_MBOX_CSR		0x40	/* [II] Mailbox CSR */
+#define  RIO_MBOX0_AVAIL		0x80000000	/* [II] Mbox 0 avail */
+#define  RIO_MBOX0_FULL			0x40000000	/* [II] Mbox 0 full */
+#define  RIO_MBOX0_EMPTY		0x20000000	/* [II] Mbox 0 empty */
+#define  RIO_MBOX0_BUSY			0x10000000	/* [II] Mbox 0 busy */
+#define  RIO_MBOX0_FAIL			0x08000000	/* [II] Mbox 0 fail */
+#define  RIO_MBOX0_ERROR		0x04000000	/* [II] Mbox 0 error */
+#define  RIO_MBOX1_AVAIL		0x00800000	/* [II] Mbox 1 avail */
+#define  RIO_MBOX1_FULL			0x00200000	/* [II] Mbox 1 full */
+#define  RIO_MBOX1_EMPTY		0x00200000	/* [II] Mbox 1 empty */
+#define  RIO_MBOX1_BUSY			0x00100000	/* [II] Mbox 1 busy */
+#define  RIO_MBOX1_FAIL			0x00080000	/* [II] Mbox 1 fail */
+#define  RIO_MBOX1_ERROR		0x00040000	/* [II] Mbox 1 error */
+#define  RIO_MBOX2_AVAIL		0x00008000	/* [II] Mbox 2 avail */
+#define  RIO_MBOX2_FULL			0x00004000	/* [II] Mbox 2 full */
+#define  RIO_MBOX2_EMPTY		0x00002000	/* [II] Mbox 2 empty */
+#define  RIO_MBOX2_BUSY			0x00001000	/* [II] Mbox 2 busy */
+#define  RIO_MBOX2_FAIL			0x00000800	/* [II] Mbox 2 fail */
+#define  RIO_MBOX2_ERROR		0x00000400	/* [II] Mbox 2 error */
+#define  RIO_MBOX3_AVAIL		0x00000080	/* [II] Mbox 3 avail */
+#define  RIO_MBOX3_FULL			0x00000040	/* [II] Mbox 3 full */
+#define  RIO_MBOX3_EMPTY		0x00000020	/* [II] Mbox 3 empty */
+#define  RIO_MBOX3_BUSY			0x00000010	/* [II] Mbox 3 busy */
+#define  RIO_MBOX3_FAIL			0x00000008	/* [II] Mbox 3 fail */
+#define  RIO_MBOX3_ERROR		0x00000004	/* [II] Mbox 3 error */
+
+#define RIO_WRITE_PORT_CSR	0x44	/* [I] Write Port CSR */
+#define RIO_DOORBELL_CSR	0x44	/* [II] Doorbell CSR */
+#define  RIO_DOORBELL_AVAIL		0x80000000	/* [II] Doorbell avail */
+#define  RIO_DOORBELL_FULL		0x40000000	/* [II] Doorbell full */
+#define  RIO_DOORBELL_EMPTY		0x20000000	/* [II] Doorbell empty */
+#define  RIO_DOORBELL_BUSY		0x10000000	/* [II] Doorbell busy */
+#define  RIO_DOORBELL_FAILED		0x08000000	/* [II] Doorbell failed */
+#define  RIO_DOORBELL_ERROR		0x04000000	/* [II] Doorbell error */
+#define  RIO_WRITE_PORT_AVAILABLE	0x00000080	/* [I] Write Port Available */
+#define  RIO_WRITE_PORT_FULL		0x00000040	/* [I] Write Port Full */
+#define  RIO_WRITE_PORT_EMPTY		0x00000020	/* [I] Write Port Empty */
+#define  RIO_WRITE_PORT_BUSY		0x00000010	/* [I] Write Port Busy */
+#define  RIO_WRITE_PORT_FAILED		0x00000008	/* [I] Write Port Failed */
+#define  RIO_WRITE_PORT_ERROR		0x00000004	/* [I] Write Port Error */
+
+					/* 0x48 *//* Reserved */
+
+#define RIO_PELL_CTRL_CSR	0x4c	/* [I] PE Logical Layer Control CSR */
+#define   RIO_PELL_ADDR_66		0x00000004	/* [I] 66-bit addr */
+#define   RIO_PELL_ADDR_50		0x00000002	/* [I] 50-bit addr */
+#define   RIO_PELL_ADDR_34		0x00000001	/* [I] 34-bit addr */
+
+					/* 0x50-0x54 *//* Reserved */
+
+#define RIO_LCSH_BA		0x58	/* [I] LCS High Base Address */
+#define RIO_LCSL_BA		0x5c	/* [I] LCS Base Address */
+
+#define RIO_DID_CSR		0x60	/* [III] Base Device ID CSR */
+
+					/* 0x64 *//* Reserved */
+
+#define RIO_HOST_DID_LOCK_CSR	0x68	/* [III] Host Base Device ID Lock CSR */
+#define RIO_COMPONENT_TAG_CSR	0x6c	/* [III] Component Tag CSR */
+
+					/* 0x70-0xf8 *//* Reserved */
+					/* 0x100-0xfff8 *//* [I] Extended Features Space */
+					/* 0x10000-0xfffff8 *//* [I] Implementation-defined Space */
+
+/*
+ * Extended Features Space is a configuration space area where
+ * functionality is mapped into extended feature blocks via a
+ * singly linked list of extended feature pointers (EFT_PTR).
+ *
+ * Each extended feature block can be identified/located in
+ * Extended Features Space by walking the extended feature
+ * list starting with the Extended Feature Pointer located
+ * in the Assembly Information CAR.
+ *
+ * Extended Feature Blocks (EFBs) are identified with an assigned
+ * EFB ID. Extended feature block offsets in the definitions are
+ * relative to the offset of the EFB within the  Extended Features
+ * Space.
+ */
+
+/* Helper macros to parse the Extended Feature Block header */
+#define RIO_EFB_PTR_MASK	0xffff0000
+#define RIO_EFB_ID_MASK		0x0000ffff
+#define RIO_GET_BLOCK_PTR(x)	((x & RIO_EFB_PTR_MASK) >> 16)
+#define RIO_GET_BLOCK_ID(x)	(x & RIO_EFB_ID_MASK)
+
+/* Extended Feature Block IDs */
+#define RIO_EFB_PAR_EP_ID	0x0001	/* [IV] LP/LVDS EP Devices */
+#define RIO_EFB_PAR_EP_REC_ID	0x0002	/* [IV] LP/LVDS EP Recovery Devices */
+#define RIO_EFB_PAR_EP_FREE_ID	0x0003	/* [IV] LP/LVDS EP Free Devices */
+#define RIO_EFB_SER_EP_ID	0x0004	/* [VI] LP/Serial EP Devices */
+#define RIO_EFB_SER_EP_REC_ID	0x0005	/* [VI] LP/Serial EP Recovery Devices=
 */
+#define RIO_EFB_SER_EP_FREE_ID	0x0006	/* [VI] LP/Serial EP Free Devices */
+
+/*
+ * Physical 8/16 LP-LVDS
+ * ID=3D0x0001, Generic End Point Devices
+ * ID=3D0x0002, Generic End Point Devices, software assisted recovery opti=
on
+ * ID=3D0x0003, Generic End Point Free Devices
+ *
+ * Physical LP-Serial
+ * ID=3D0x0004, Generic End Point Devices
+ * ID=3D0x0005, Generic End Point Devices, software assisted recovery opti=
on
+ * ID=3D0x0006, Generic End Point Free Devices
+ */
+#define RIO_PORT_MNT_HEADER		0x0000
+#define RIO_PORT_REQ_CTL_CSR		0x0020
+#define RIO_PORT_RSP_CTL_CSR		0x0024	/* 0x0001/0x0002 */
+#define RIO_PORT_GEN_CTL_CSR		0x003c
+#define  RIO_PORT_GEN_HOST		0x80000000
+#define  RIO_PORT_GEN_MASTER		0x40000000
+#define  RIO_PORT_GEN_DISCOVERED	0x20000000
+#define RIO_PORT_N_MNT_REQ_CSR(x)	(0x0040 + x*0x20)	/* 0x0002 */
+#define RIO_PORT_N_MNT_RSP_CSR(x)	(0x0044 + x*0x20)	/* 0x0002 */
+#define RIO_PORT_N_ACK_STS_CSR(x)	(0x0048 + x*0x20)	/* 0x0002 */
+#define RIO_PORT_N_ERR_STS_CSR(x)	(0x58 + x*0x20)
+#define PORT_N_ERR_STS_PORT_OK	0x00000002
+#define RIO_PORT_N_CTL_CSR(x)		(0x5c + x*0x20)
+
+#endif				/* LINUX_RIO_REGS_H */

Re: [PATCH][3/5] RapidIO support: core enum

From: Zwane Mwaikambo <hidden>
Date: 2005-06-07 05:16:39

On Mon, 6 Jun 2005, Matt Porter wrote:
+spinlock_t rio_global_list_lock = SPIN_LOCK_UNLOCKED;
spin_lock_init?
+extern struct rio_route_ops __start_rio_route_ops[];
+extern struct rio_route_ops __end_rio_route_ops[];
rio.h?
+static void
+rio_set_device_id(struct rio_mport *port, u16 destid, u8 hopcount, u16 did)
Shouldn't those be on the same line?
+static int rio_device_has_destid(struct rio_mport *port, int src_ops,
+				 int dst_ops)
+{
+	if (((src_ops & RIO_SRC_OPS_READ) ||
+	     (src_ops & RIO_SRC_OPS_WRITE) ||
+	     (src_ops & RIO_SRC_OPS_ATOMIC_TST_SWP) ||
+	     (src_ops & RIO_SRC_OPS_ATOMIC_INC) ||
+	     (src_ops & RIO_SRC_OPS_ATOMIC_DEC) ||
+	     (src_ops & RIO_SRC_OPS_ATOMIC_SET) ||
+	     (src_ops & RIO_SRC_OPS_ATOMIC_CLR)) &&
+	    ((dst_ops & RIO_DST_OPS_READ) ||
+	     (dst_ops & RIO_DST_OPS_WRITE) ||
+	     (dst_ops & RIO_DST_OPS_ATOMIC_TST_SWP) ||
+	     (dst_ops & RIO_DST_OPS_ATOMIC_INC) ||
+	     (dst_ops & RIO_DST_OPS_ATOMIC_DEC) ||
+	     (dst_ops & RIO_DST_OPS_ATOMIC_SET) ||
+	     (dst_ops & RIO_DST_OPS_ATOMIC_CLR))) {
+		return 1;
Why not just;

mask = (RIO_DST_OPS_READ | RIO_DST_OPS_WRITE....)
return !!((dst_ops & mask) && (src_ops & mask))

+	rdev->dev.dma_mask = (u64 *) 0xffffffff;
+	rdev->dev.coherent_dma_mask = 0xffffffffULL;
Shouldn't that be dma_set_mask?

	Zwane

Re: [PATCH][4/5] RapidIO support: ppc32

From: Kumar Gala <hidden>
Date: 2005-06-08 04:46:10

Two questions:
1. how well does will all of this handle > 32-bit phys addr?
2. can we make any of this a platform driver?

I would prefer if we could have the memory offsets and irq's not be 
straight from the #define's

- kumar

On Jun 6, 2005, at 5:40 PM, Matt Porter wrote:
quoted hunk
Adds PPC32 RIO support.  Init code for the MPC85xx RIO ports
and glue for the STx GP3 board to use it.

Signed-off-by: Matt Porter <mporter@kernel.crashing.org>
diff --git a/arch/ppc/Kconfig b/arch/ppc/Kconfig
--- a/arch/ppc/Kconfig
+++ b/arch/ppc/Kconfig
@@ -1177,6 +1177,14 @@ source "drivers/pci/Kconfig"

 source "drivers/pcmcia/Kconfig"

+config RAPIDIO
+	bool "RapidIO support" if MPC8540 || MPC8560
+	help
+	  If you say Y here, the kernel will include drivers and
+	  infrastructure code to support RapidIO interconnect devices.
+
+source "drivers/rio/Kconfig"
+
 endmenu

 menu "Advanced setup"
diff --git a/arch/ppc/configs/stx_gp3_defconfig 
b/arch/ppc/configs/stx_gp3_defconfig
--- a/arch/ppc/configs/stx_gp3_defconfig
+++ b/arch/ppc/configs/stx_gp3_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.11-rc2
-# Wed Jan 26 14:32:58 2005
+# Linux kernel version: 2.6.12-rc4
+# Tue May 24 18:11:04 2005
 #
 CONFIG_MMU=y
 CONFIG_GENERIC_HARDIRQS=y
@@ -11,6 +11,7 @@ CONFIG_HAVE_DEC_LOCK=y
 CONFIG_PPC=y
 CONFIG_PPC32=y
 CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y

 #
 # Code maturity level options
@@ -18,6 +19,7 @@ CONFIG_GENERIC_NVRAM=y
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
 CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32

 #
 # General setup
@@ -29,7 +31,6 @@ CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
 CONFIG_HOTPLUG=y
 CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
@@ -37,6 +38,9 @@ CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
@@ -46,6 +50,7 @@ CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
 # CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0

 #
 # Loadable module support
@@ -69,9 +74,11 @@ CONFIG_KMOD=y
 CONFIG_E500=y
 CONFIG_BOOKE=y
 CONFIG_FSL_BOOKE=y
+# CONFIG_PHYS_64BIT is not set
 # CONFIG_SPE is not set
 CONFIG_MATH_EMULATION=y
 # CONFIG_CPU_FREQ is not set
+# CONFIG_PM is not set
 CONFIG_85xx=y
 CONFIG_PPC_INDIRECT_PCI_BE=y
@@ -96,6 +103,7 @@ CONFIG_HIGHMEM=y
 CONFIG_BINFMT_ELF=y
 CONFIG_BINFMT_MISC=m
 # CONFIG_CMDLINE_BOOL is not set
+CONFIG_ISA_DMA_API=y

 #
 # Bus options
@@ -104,15 +112,15 @@ CONFIG_PCI=y
 CONFIG_PCI_DOMAINS=y
 # CONFIG_PCI_LEGACY_PROC is not set
 # CONFIG_PCI_NAMES is not set
+# CONFIG_PCI_DEBUG is not set

 #
 # PCCARD (PCMCIA/CardBus) support
 #
 # CONFIG_PCCARD is not set
-
-#
-# PC-card bridges
-#
+CONFIG_RAPIDIO=y
+CONFIG_RAPIDIO_8_BIT_TRANSPORT=y
+CONFIG_RAPIDIO_DISC_TIMEOUT=30

 #
 # Advanced setup
@@ -152,7 +160,7 @@ CONFIG_PARPORT=m
 CONFIG_PARPORT_PC=m
 # CONFIG_PARPORT_PC_FIFO is not set
 # CONFIG_PARPORT_PC_SUPERIO is not set
-# CONFIG_PARPORT_OTHER is not set
+# CONFIG_PARPORT_GSC is not set
 # CONFIG_PARPORT_1284 is not set

 #
@@ -264,7 +272,6 @@ CONFIG_SCSI_CONSTANTS=y
 # CONFIG_SCSI_BUSLOGIC is not set
 # CONFIG_SCSI_DMX3191D is not set
 # CONFIG_SCSI_EATA is not set
-# CONFIG_SCSI_EATA_PIO is not set
 # CONFIG_SCSI_FUTURE_DOMAIN is not set
 # CONFIG_SCSI_GDTH is not set
 # CONFIG_SCSI_IPS is not set
@@ -274,7 +281,6 @@ CONFIG_SCSI_CONSTANTS=y
 # CONFIG_SCSI_IMM is not set
 # CONFIG_SCSI_SYM53C8XX_2 is not set
 # CONFIG_SCSI_IPR is not set
-# CONFIG_SCSI_QLOGIC_ISP is not set
 # CONFIG_SCSI_QLOGIC_FC is not set
 # CONFIG_SCSI_QLOGIC_1280 is not set
 CONFIG_SCSI_QLA2XXX=m
@@ -283,6 +289,7 @@ CONFIG_SCSI_QLA2XXX=m
 # CONFIG_SCSI_QLA2300 is not set
 # CONFIG_SCSI_QLA2322 is not set
 # CONFIG_SCSI_QLA6312 is not set
+# CONFIG_SCSI_LPFC is not set
 # CONFIG_SCSI_DC395x is not set
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_NSP32 is not set
@@ -322,7 +329,6 @@ CONFIG_NET=y
 #
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK_DEV is not set
 CONFIG_UNIX=y
 # CONFIG_NET_KEY is not set
 CONFIG_INET=y
@@ -431,7 +437,7 @@ CONFIG_IP_NF_NAT_FTP=m
 #
 # Network testing
 #
-# CONFIG_NET_PKTGEN is not set
+CONFIG_NET_PKTGEN=y
 # CONFIG_NETPOLL is not set
 # CONFIG_NET_POLL_CONTROLLER is not set
 # CONFIG_HAMRADIO is not set
@@ -499,6 +505,7 @@ CONFIG_GFAR_NAPI=y
 # Wan interfaces
 #
 # CONFIG_WAN is not set
+CONFIG_RIONET=y
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
 # CONFIG_PLIP is not set
@@ -536,20 +543,6 @@ CONFIG_INPUT_EVDEV=m
 # CONFIG_INPUT_EVBUG is not set

 #
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=y
-CONFIG_SERIO_I8042=y
-CONFIG_SERIO_SERPORT=y
-# CONFIG_SERIO_CT82C710 is not set
-# CONFIG_SERIO_PARKBD is not set
-# CONFIG_SERIO_PCIPS2 is not set
-CONFIG_SERIO_LIBPS2=y
-# CONFIG_SERIO_RAW is not set
-
-#
 # Input Device Drivers
 #
 CONFIG_INPUT_KEYBOARD=y
@@ -567,6 +560,19 @@ CONFIG_MOUSE_PS2=y
 # CONFIG_INPUT_MISC is not set

 #
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_I8042=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_PARKBD is not set
+# CONFIG_SERIO_PCIPS2 is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+
+#
 # Character devices
 #
 # CONFIG_VT is not set
@@ -590,6 +596,7 @@ CONFIG_SERIAL_CPM_SCC2=y
 # CONFIG_SERIAL_CPM_SCC4 is not set
 # CONFIG_SERIAL_CPM_SMC1 is not set
 # CONFIG_SERIAL_CPM_SMC2 is not set
+# CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -626,6 +633,11 @@ CONFIG_DRM=m
 # CONFIG_RAW_DRIVER is not set

 #
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
 # I2C support
 #
 CONFIG_I2C=m
@@ -648,12 +660,12 @@ CONFIG_I2C_ALGOBIT=m
 # CONFIG_I2C_AMD8111 is not set
 # CONFIG_I2C_I801 is not set
 # CONFIG_I2C_I810 is not set
+# CONFIG_I2C_PIIX4 is not set
 # CONFIG_I2C_ISA is not set
 # CONFIG_I2C_MPC is not set
 # CONFIG_I2C_NFORCE2 is not set
 # CONFIG_I2C_PARPORT is not set
 # CONFIG_I2C_PARPORT_LIGHT is not set
-# CONFIG_I2C_PIIX4 is not set
 # CONFIG_I2C_PROSAVAGE is not set
 # CONFIG_I2C_SAVAGE4 is not set
 # CONFIG_SCx200_ACB is not set
@@ -677,7 +689,9 @@ CONFIG_I2C_ALGOBIT=m
 # CONFIG_SENSORS_ASB100 is not set
 # CONFIG_SENSORS_DS1621 is not set
 # CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
 # CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
 # CONFIG_SENSORS_IT87 is not set
 # CONFIG_SENSORS_LM63 is not set
 # CONFIG_SENSORS_LM75 is not set
@@ -688,9 +702,11 @@ CONFIG_I2C_ALGOBIT=m
 # CONFIG_SENSORS_LM85 is not set
 # CONFIG_SENSORS_LM87 is not set
 # CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
 # CONFIG_SENSORS_MAX1619 is not set
 # CONFIG_SENSORS_PC87360 is not set
 # CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_SIS5595 is not set
 # CONFIG_SENSORS_SMSC47M1 is not set
 # CONFIG_SENSORS_VIA686A is not set
 # CONFIG_SENSORS_W83781D is not set
@@ -700,10 +716,12 @@ CONFIG_I2C_ALGOBIT=m
 #
 # Other I2C Chip support
 #
+# CONFIG_SENSORS_DS1337 is not set
 # CONFIG_SENSORS_EEPROM is not set
 # CONFIG_SENSORS_PCF8574 is not set
 # CONFIG_SENSORS_PCF8591 is not set
 # CONFIG_SENSORS_RTC8564 is not set
+# CONFIG_SENSORS_M41T00 is not set
 # CONFIG_I2C_DEBUG_CORE is not set
 # CONFIG_I2C_DEBUG_ALGO is not set
 # CONFIG_I2C_DEBUG_BUS is not set
@@ -732,7 +750,6 @@ CONFIG_I2C_ALGOBIT=m
 # Graphics support
 #
 # CONFIG_FB is not set
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set

 #
 # Sound
@@ -752,13 +769,9 @@ CONFIG_SOUND=m
 #
 # USB support
 #
-# CONFIG_USB is not set
 CONFIG_USB_ARCH_HAS_HCD=y
 CONFIG_USB_ARCH_HAS_OHCI=y
-
-#
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be 
needed; see USB_STORAGE Help for more information
-#
+# CONFIG_USB is not set

 #
 # USB Gadget Support
@@ -789,6 +802,10 @@ CONFIG_JBD_DEBUG=y
 CONFIG_FS_MBCACHE=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
 # CONFIG_XFS_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
@@ -859,7 +876,6 @@ CONFIG_NFS_V3=y
 CONFIG_ROOT_NFS=y
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
-# CONFIG_EXPORTFS is not set
 CONFIG_SUNRPC=y
 # CONFIG_RPCSEC_GSS_KRB5 is not set
 # CONFIG_RPCSEC_GSS_SPKM3 is not set
@@ -942,8 +958,10 @@ CONFIG_ZLIB_INFLATE=m
 #
 # Kernel hacking
 #
+# CONFIG_PRINTK_TIME is not set
 CONFIG_DEBUG_KERNEL=y
 # CONFIG_MAGIC_SYSRQ is not set
+CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_DEBUG_SLAB is not set
 # CONFIG_DEBUG_SPINLOCK is not set
diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile
--- a/arch/ppc/kernel/Makefile
+++ b/arch/ppc/kernel/Makefile
@@ -22,6 +22,7 @@ obj-$(CONFIG_POWER4)		+= cpu_setup_power
 obj-$(CONFIG_MODULES)		+= module.o ppc_ksyms.o
 obj-$(CONFIG_NOT_COHERENT_CACHE)	+= dma-mapping.o
 obj-$(CONFIG_PCI)		+= pci.o
+obj-$(CONFIG_RAPIDIO)		+= rio.o
 obj-$(CONFIG_KGDB)		+= ppc-stub.o
 obj-$(CONFIG_SMP)		+= smp.o smp-tbsync.o
 obj-$(CONFIG_TAU)		+= temp.o
diff --git a/arch/ppc/kernel/rio.c b/arch/ppc/kernel/rio.c
new file mode 100644
--- /dev/null
+++ b/arch/ppc/kernel/rio.c
@@ -0,0 +1,52 @@
+/*
+ * RapidIO PPC32 support
+ *
+ * Copyright 2005 MontaVista Software, Inc.
+ * Matt Porter <mporter@kernel.crashing.org>
+ *
+ * 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.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/rio.h>
+
+#include <asm/rio.h>
+
+/**
+ * platform_rio_init - Do platform specific RIO init
+ *
+ * Any platform specific initialization of RapdIO
+ * hardware is done here as well as registration
+ * of any active master ports in the system.
+ */
+void __attribute__ ((weak))
+    platform_rio_init(void)
+{
+	printk(KERN_WARNING "RIO: No platform_rio_init() present\n");
+}
+
+/**
+ * ppc_rio_init - Do PPC32 RIO init
+ *
+ * Calls platform-specific RIO init code and then calls
+ * rio_init_mports() to initialize any master ports that
+ * have been registered with the RIO subsystem.
+ */
+static int __init ppc_rio_init(void)
+{
+	printk(KERN_INFO "RIO: RapidIO init\n");
+
+	/* Platform specific initialization */
+	platform_rio_init();
+
+	/* Enumerate all registered ports */
+	rio_init_mports();
+
+	return 0;
+}
+
+subsys_initcall(ppc_rio_init);
diff --git a/arch/ppc/platforms/85xx/stx_gp3.c 
b/arch/ppc/platforms/85xx/stx_gp3.c
--- a/arch/ppc/platforms/85xx/stx_gp3.c
+++ b/arch/ppc/platforms/85xx/stx_gp3.c
@@ -38,6 +38,7 @@
 #include <linux/module.h>
 #include <linux/fsl_devices.h>
 #include <linux/interrupt.h>
+#include <linux/rio.h>

 #include <asm/system.h>
 #include <asm/pgtable.h>
@@ -59,6 +60,7 @@

 #include <syslib/cpm2_pic.h>
 #include <syslib/ppc85xx_common.h>
+#include <syslib/ppc85xx_rio.h>

 extern void cpm2_reset(void);
@@ -200,7 +202,6 @@ static struct irqaction cpm2_irqaction =
 static void __init
 gp3_init_IRQ(void)
 {
-	int i;
 	bd_t *binfo = (bd_t *) __res;

 	/*
@@ -297,6 +298,18 @@ int mpc85xx_exclude_device(u_char bus, u
 }
 #endif /* CONFIG_PCI */

+#ifdef CONFIG_RAPIDIO
+void
+platform_rio_init(void)
+{
+	/*
+	 * The STx firmware configures the RapidIO Local Access Window
+	 * at 0xc0000000 with a size of 512MB.
+	 */
+	mpc85xx_rio_setup(0xc0000000, 0x20000000);
+}
+#endif /* CONFIG_RAPIDIO */
+
 void __init
 platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
 	      unsigned long r6, unsigned long r7)
diff --git a/arch/ppc/syslib/Makefile b/arch/ppc/syslib/Makefile
--- a/arch/ppc/syslib/Makefile
+++ b/arch/ppc/syslib/Makefile
@@ -101,6 +101,7 @@ obj-$(CONFIG_85xx)		+= open_pic.o ppc85x
 					mpc85xx_devices.o
 ifeq ($(CONFIG_85xx),y)
 obj-$(CONFIG_PCI)		+= indirect_pci.o pci_auto.o
+obj-$(CONFIG_RAPIDIO)		+= ppc85xx_rio.o
 endif
 obj-$(CONFIG_83xx)		+= ipic.o ppc83xx_setup.o ppc_sys.o \
 					mpc83xx_sys.o mpc83xx_devices.o
diff --git a/arch/ppc/syslib/ppc85xx_rio.c 
b/arch/ppc/syslib/ppc85xx_rio.c
new file mode 100644
--- /dev/null
+++ b/arch/ppc/syslib/ppc85xx_rio.c
@@ -0,0 +1,867 @@
+/*
+ * MPC85xx RapidIO support
+ *
+ * Copyright 2005 MontaVista Software, Inc.
+ * Matt Porter <mporter@kernel.crashing.org>
+ *
+ * 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.
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/rio.h>
+#include <linux/rio_drv.h>
+
+#include <asm/io.h>
+
+#define RIO_REGS_BASE		(CCSRBAR + 0xc0000)
+#define RIO_ATMU_REGS_OFFSET	0x10c00
+#define RIO_MSG_REGS_OFFSET	0x11000
+#define RIO_MAINT_WIN_SIZE	0x400000
+#define RIO_DBELL_WIN_SIZE	0x1000
+
+#define RIO_MSG_OMR_MUI		0x00000002
+#define RIO_MSG_OSR_TE		0x00000080
+#define RIO_MSG_OSR_QOI		0x00000020
+#define RIO_MSG_OSR_QFI		0x00000010
+#define RIO_MSG_OSR_MUB		0x00000004
+#define RIO_MSG_OSR_EOMI	0x00000002
+#define RIO_MSG_OSR_QEI		0x00000001
+
+#define RIO_MSG_IMR_MI		0x00000002
+#define RIO_MSG_ISR_TE		0x00000080
+#define RIO_MSG_ISR_QFI		0x00000010
+#define RIO_MSG_ISR_DIQI	0x00000001
+
+#define RIO_MSG_DESC_SIZE	32
+#define RIO_MIN_TX_RING_SIZE	2
+#define RIO_MAX_TX_RING_SIZE	2048
+#define RIO_MIN_RX_RING_SIZE	2
+#define RIO_MAX_RX_RING_SIZE	2048
+
+#define DOORBELL_DMR_DI		0x00000002
+#define DOORBELL_DSR_TE		0x00000080
+#define DOORBELL_DSR_QFI	0x00000010
+#define DOORBELL_DSR_DIQI	0x00000001
+#define DOORBELL_TID_OFFSET	0x03
+#define DOORBELL_SID_OFFSET	0x05
+#define DOORBELL_INFO_OFFSET	0x06
+
+#define DOORBELL_MESSAGE_SIZE	0x08
+#define DBELL_SID(x)		(*(u8 *)(x + DOORBELL_SID_OFFSET))
+#define DBELL_TID(x)		(*(u8 *)(x + DOORBELL_TID_OFFSET))
+#define DBELL_INF(x)		(*(u16 *)(x + DOORBELL_INFO_OFFSET))
+
+#define is_power_of_2(x)	(((x) & ((x) - 1)) == 0)
+
+struct rio_atmu_regs {
+	u32 rowtar;
+	u32 pad1;
+	u32 rowbar;
+	u32 pad2;
+	u32 rowar;
+	u32 pad3[3];
+};
+
+struct rio_msg_regs {
+	u32 omr;
+	u32 osr;
+	u32 pad1;
+	u32 odqdpar;
+	u32 pad2;
+	u32 osar;
+	u32 odpr;
+	u32 odatr;
+	u32 odcr;
+	u32 pad3;
+	u32 odqepar;
+	u32 pad4[13];
+	u32 imr;
+	u32 isr;
+	u32 pad5;
+	u32 ifqdpar;
+	u32 pad6;
+	u32 ifqepar;
+	u32 pad7[250];
+	u32 dmr;
+	u32 dsr;
+	u32 pad8;
+	u32 dqdpar;
+	u32 pad9;
+	u32 dqepar;
+	u32 pad10[26];
+	u32 pwmr;
+	u32 pwsr;
+	u32 pad11;
+	u32 pwqbar;
+};
+
+struct rio_tx_desc {
+	u32 res1;
+	u32 saddr;
+	u32 dport;
+	u32 dattr;
+	u32 res2;
+	u32 res3;
+	u32 dwcnt;
+	u32 res4;
+};
+
+static u32 regs_win;
+static struct rio_atmu_regs *atmu_regs;
+static struct rio_atmu_regs *maint_atmu_regs;
+static struct rio_atmu_regs *dbell_atmu_regs;
+static u32 dbell_win;
+static u32 maint_win;
+static struct rio_msg_regs *msg_regs;
+
+static struct rio_dbell_ring {
+	void *virt;
+	dma_addr_t phys;
+} dbell_ring;
+
+static struct rio_msg_tx_ring {
+	void *virt;
+	dma_addr_t phys;
+	void *virt_buffer[RIO_MAX_TX_RING_SIZE];
+	dma_addr_t phys_buffer[RIO_MAX_TX_RING_SIZE];
+	int tx_slot;
+	int size;
+} msg_tx_ring;
+
+static struct rio_msg_rx_ring {
+	void *virt;
+	dma_addr_t phys;
+	void *virt_buffer[RIO_MAX_RX_RING_SIZE];
+	int rx_slot;
+	int size;
+} msg_rx_ring;
+
+/**
+ * mpc85xx_rio_doorbell_send - Send a MPC85xx doorbell message
+ * @index: ID of RapidIO interface
+ * @destid: Destination ID of target device
+ * @data: 16-bit info field of RapidIO doorbell message
+ *
+ * Sends a MPC85xx doorbell message. Returns %0 on success or
+ * %-EINVAL on failure.
+ */
+static int mpc85xx_rio_doorbell_send(int index, u16 destid, u16 data)
+{
+	pr_debug("mpc85xx_doorbell_send: index %d destid %4.4x data %4.4x\n",
+		 index, destid, data);
+	out_be32((void *)&dbell_atmu_regs->rowtar, destid << 22);
+	out_be16((void *)(dbell_win), data);
+
+	return 0;
+}
+
+/**
+ * mpc85xx_local_config_read - Generate a MPC85xx local config space 
read
+ * @index: ID of RapdiIO interface
+ * @offset: Offset into configuration space
+ * @len: Length (in bytes) of the maintenance transaction
+ * @data: Value to be read into
+ *
+ * Generates a MPC85xx local configuration space read. Returns %0 on
+ * success or %-EINVAL on failure.
+ */
+static int mpc85xx_local_config_read(int index, u32 offset, int len, 
u32 * data)
+{
+	pr_debug("mpc85xx_local_config_read: index %d offset %8.8x\n", index,
+		 offset);
+	*data = in_be32((void *)(regs_win + offset));
+
+	return 0;
+}
+
+/**
+ * mpc85xx_local_config_write - Generate a MPC85xx local config space 
write
+ * @index: ID of RapdiIO interface
+ * @offset: Offset into configuration space
+ * @len: Length (in bytes) of the maintenance transaction
+ * @data: Value to be written
+ *
+ * Generates a MPC85xx local configuration space write. Returns %0 on
+ * success or %-EINVAL on failure.
+ */
+static int mpc85xx_local_config_write(int index, u32 offset, int len, 
u32 data)
+{
+	pr_debug
+	    ("mpc85xx_local_config_write: index %d offset %8.8x data 
%8.8x\n",
+	     index, offset, data);
+	out_be32((void *)(regs_win + offset), data);
+
+	return 0;
+}
+
+/**
+ * mpc85xx_rio_config_read - Generate a MPC85xx read maintenance 
transaction
+ * @index: ID of RapdiIO interface
+ * @destid: Destination ID of transaction
+ * @hopcount: Number of hops to target device
+ * @offset: Offset into configuration space
+ * @len: Length (in bytes) of the maintenance transaction
+ * @val: Location to be read into
+ *
+ * Generates a MPC85xx read maintenance transaction. Returns %0 on
+ * success or %-EINVAL on failure.
+ */
+static int
+mpc85xx_rio_config_read(int index, u16 destid, u8 hopcount, u32 
offset, int len,
+			u32 * val)
+{
+	u8 *data;
+
+	pr_debug
+	    ("mpc85xx_rio_config_read: index %d destid %d hopcount %d offset 
%8.8x len %d\n",
+	     index, destid, hopcount, offset, len);
+	out_be32((void *)&maint_atmu_regs->rowtar,
+		 (destid << 22) | (hopcount << 12) | ((offset & ~0x3) >> 9));
+
+	data = (u8 *) maint_win + offset;
+	switch (len) {
+	case 1:
+		*val = in_8((u8 *) data);
+		break;
+	case 2:
+		*val = in_be16((u16 *) data);
+		break;
+	default:
+		*val = in_be32((u32 *) data);
+		break;
+	}
+
+	return 0;
+}
+
+/**
+ * mpc85xx_rio_config_write - Generate a MPC85xx write maintenance 
transaction
+ * @index: ID of RapdiIO interface
+ * @destid: Destination ID of transaction
+ * @hopcount: Number of hops to target device
+ * @offset: Offset into configuration space
+ * @len: Length (in bytes) of the maintenance transaction
+ * @val: Value to be written
+ *
+ * Generates an MPC85xx write maintenance transaction. Returns %0 on
+ * success or %-EINVAL on failure.
+ */
+static int
+mpc85xx_rio_config_write(int index, u16 destid, u8 hopcount, u32 
offset,
+			 int len, u32 val)
+{
+	u8 *data;
+	pr_debug
+	    ("mpc85xx_rio_config_write: index %d destid %d hopcount %d 
offset %8.8x len %d val %8.8x\n",
+	     index, destid, hopcount, offset, len, val);
+	out_be32((void *)&maint_atmu_regs->rowtar,
+		 (destid << 22) | (hopcount << 12) | ((offset & ~0x3) >> 9));
+
+	data = (u8 *) maint_win + offset;
+	switch (len) {
+	case 1:
+		out_8((u8 *) data, val);
+		break;
+	case 2:
+		out_be16((u16 *) data, val);
+		break;
+	default:
+		out_be32((u32 *) data, val);
+		break;
+	}
+
+	return 0;
+}
+
+/**
+ * rio_hw_add_outb_message - Add message to the MPC85xx outbound 
message queue
+ * @mport: Master port with outbound message queue
+ * @rdev: Target of outbound message
+ * @mbox: Outbound mailbox
+ * @buffer: Message to add to outbound queue
+ * @len: Length of message
+ *
+ * Adds the @buffer message to the MPC85xx outbound message queue. 
Returns
+ * %0 on success or %-EINVAL on failure.
+ */
+int
+rio_hw_add_outb_message(struct rio_mport *mport, struct rio_dev 
*rdev, int mbox,
+			void *buffer, size_t len)
+{
+	u32 omr;
+	struct rio_tx_desc *desc =
+	    (struct rio_tx_desc *)msg_tx_ring.virt + msg_tx_ring.tx_slot;
+	int ret = 0;
+
+	pr_debug(KERN_INFO
+		 "RIO: rio_hw_add_outb_message(): destid %4.4x mbox %d buffer %8.8x 
len %8.8x\n",
+		 rdev->destid, mbox, (int)buffer, len);
+
+	if ((len < 8) || (len > RIO_MAX_MSG_SIZE)) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	/* Copy and clear rest of buffer */
+	memcpy(msg_tx_ring.virt_buffer[msg_tx_ring.tx_slot], buffer, len);
+	if (len < (RIO_MAX_MSG_SIZE - 4))
+		memset((void *)((u32) msg_tx_ring.
+				virt_buffer[msg_tx_ring.tx_slot] + len), 0,
+		       RIO_MAX_MSG_SIZE - len);
+
+	/* Set mbox field for message */
+	desc->dport = mbox & 0x3;
+
+	/* Enable EOMI interrupt, set priority, and set destid */
+	desc->dattr = 0x28000000 | (rdev->destid << 2);
+
+	/* Set transfer size aligned to next power of 2 (in double words) */
+	desc->dwcnt = is_power_of_2(len) ? len : 1 << get_bitmask_order(len);
+
+	/* Set snooping and source buffer address */
+	desc->saddr = 0x00000004 | 
msg_tx_ring.phys_buffer[msg_tx_ring.tx_slot];
+
+	/* Increment enqueue pointer */
+	omr = in_be32((void *)&msg_regs->omr);
+	out_be32((void *)&msg_regs->omr, omr | RIO_MSG_OMR_MUI);
+
+	/* Go to next descriptor */
+	if (++msg_tx_ring.tx_slot == msg_tx_ring.size)
+		msg_tx_ring.tx_slot = 0;
+
+      out:
+	return ret;
+}
+
+EXPORT_SYMBOL_GPL(rio_hw_add_outb_message);
+
+/**
+ * mpc85xx_rio_tx_handler - MPC85xx outbound message interrupt handler
+ * @irq: Linux interrupt number
+ * @dev_instance: Pointer to interrupt-specific data
+ * @regs: Register context
+ *
+ * Handles outbound message interrupts. Executes a register outbound
+ * mailbox event handler and acks the interrupt occurence.
+ */
+static irqreturn_t
+mpc85xx_rio_tx_handler(int irq, void *dev_instance, struct pt_regs 
*regs)
+{
+	int osr;
+	struct rio_mport *port = (struct rio_mport *)dev_instance;
+
+	osr = in_be32((void *)&msg_regs->osr);
+
+	if (osr & RIO_MSG_OSR_TE) {
+		printk(KERN_INFO "RIO: outbound message transmission error\n");
+		out_be32((void *)&msg_regs->osr, RIO_MSG_OSR_TE);
+		goto out;
+	}
+
+	if (osr & RIO_MSG_OSR_QOI) {
+		printk(KERN_INFO "RIO: outbound message queue overflow\n");
+		out_be32((void *)&msg_regs->osr, RIO_MSG_OSR_QOI);
+		goto out;
+	}
+
+	if (osr & RIO_MSG_OSR_EOMI) {
+		u32 dqp = in_be32((void *)&msg_regs->odqdpar);
+		int slot = (dqp - msg_tx_ring.phys) >> 5;
+		port->outb_msg[0].mcback(port, -1, slot);
+
+		/* Ack the end-of-message interrupt */
+		out_be32((void *)&msg_regs->osr, RIO_MSG_OSR_EOMI);
+	}
+
+      out:
+	return IRQ_HANDLED;
+}
+
+/**
+ * rio_open_outb_mbox - Initialize MPC85xx outbound mailbox
+ * @mport: Master port implementing the outbound message unit
+ * @mbox: Mailbox to open
+ * @entries: Number of entries in the outbound mailbox ring
+ *
+ * Initializes buffer ring, request the outbound message interrupt,
+ * and enables the outbound message unit. Returns %0 on success or
+ * %-EINVAL on failure.
+ */
+int rio_open_outb_mbox(struct rio_mport *mport, int mbox, int entries)
+{
+	int i, rc = 0;
+
+	if ((entries < RIO_MIN_TX_RING_SIZE) ||
+	    (entries > RIO_MAX_TX_RING_SIZE) || (!is_power_of_2(entries))) {
+		rc = -EINVAL;
+		goto out;
+	}
+
+	/* Initialize shadow copy ring */
+	msg_tx_ring.size = entries;
+
+	for (i = 0; i < msg_tx_ring.size; i++) {
+		msg_tx_ring.virt_buffer[i] =
+		    (void *)__get_free_page(GFP_KERNEL);
+		msg_tx_ring.phys_buffer[i] =
+		    (dma_addr_t) __pa(msg_tx_ring.virt_buffer[i]);
+	}
+
+	/* Initialize outbound message descriptor ring */
+	msg_tx_ring.virt = dma_alloc_coherent(NULL,
+					      msg_tx_ring.size *
+					      RIO_MSG_DESC_SIZE,
+					      &msg_tx_ring.phys, GFP_KERNEL);
+	memset(msg_tx_ring.virt, 0, msg_tx_ring.size * RIO_MSG_DESC_SIZE);
+	msg_tx_ring.tx_slot = 0;
+
+	/* Point dequeue/enqueue pointers at first entry in ring */
+	out_be32((void *)&msg_regs->odqdpar, msg_tx_ring.phys);
+	out_be32((void *)&msg_regs->odqepar, msg_tx_ring.phys);
+
+	/* Configure for snooping */
+	out_be32((void *)&msg_regs->osar, 0x00000004);
+
+	/* Clear interrupt status */
+	out_be32((void *)&msg_regs->osr, 0x000000b3);
+
+	/* Hook up outbound message handler */
+	request_irq(MPC85xx_IRQ_RIO_TX, mpc85xx_rio_tx_handler, 0, "msg_tx",
+		    (void *)mport);
+
+	/*
+	 * Configure outbound message unit
+	 *      Snooping
+	 *      Interrupts (all enabled, except QEIE)
+	 *      Chaining mode
+	 *      Disable
+	 */
+	out_be32((void *)&msg_regs->omr, 0x00100220);
+
+	/* Set number of entries */
+	out_be32((void *)&msg_regs->omr,
+		 in_be32((void *)&msg_regs->omr) |
+		 ((get_bitmask_order(entries) - 2) << 12));
+
+	/* Now enable the unit */
+	out_be32((void *)&msg_regs->omr, in_be32((void *)&msg_regs->omr) | 
0x1);
+
+      out:
+	return rc;
+}
+
+/**
+ * rio_close_outb_mbox - Shut down MPC85xx outbound mailbox
+ * @mport: Master port implementing the outbound message unit
+ * @mbox: Mailbox to close
+ *
+ * Disables the outbound message unit, free all buffers, and
+ * frees the outbound message interrupt.
+ */
+void rio_close_outb_mbox(struct rio_mport *mport, int mbox)
+{
+	/* Disable inbound message unit */
+	out_be32((void *)&msg_regs->omr, 0);
+
+	/* Free ring */
+	dma_free_coherent(NULL, msg_tx_ring.size * RIO_MSG_DESC_SIZE,
+			  msg_tx_ring.virt, msg_tx_ring.phys);
+
+	/* Free interrupt */
+	free_irq(MPC85xx_IRQ_RIO_TX, (void *)mport);
+}
+
+/**
+ * mpc85xx_rio_rx_handler - MPC85xx inbound message interrupt handler
+ * @irq: Linux interrupt number
+ * @dev_instance: Pointer to interrupt-specific data
+ * @regs: Register context
+ *
+ * Handles inbound message interrupts. Executes a registered inbound
+ * mailbox event handler and acks the interrupt occurence.
+ */
+static irqreturn_t
+mpc85xx_rio_rx_handler(int irq, void *dev_instance, struct pt_regs 
*regs)
+{
+	int isr;
+	struct rio_mport *port = (struct rio_mport *)dev_instance;
+
+	isr = in_be32((void *)&msg_regs->isr);
+
+	if (isr & RIO_MSG_ISR_TE) {
+		printk(KERN_INFO "RIO: inbound message reception error\n");
+		out_be32((void *)&msg_regs->isr, RIO_MSG_ISR_TE);
+		goto out;
+	}
+
+	/* XXX Need to check/dispatch until queue empty */
+	if (isr & RIO_MSG_ISR_DIQI) {
+		/*
+		 * We implement *only* mailbox 0, but can receive messages
+		 * for any mailbox/letter to that mailbox destination. So,
+		 * make the callback with an unknown/invalid mailbox number
+		 * argument.
+		 */
+		port->inb_msg[0].mcback(port, -1, -1);
+
+		/* Ack the queueing interrupt */
+		out_be32((void *)&msg_regs->isr, RIO_MSG_ISR_DIQI);
+	}
+
+      out:
+	return IRQ_HANDLED;
+}
+
+/**
+ * rio_open_inb_mbox - Initialize MPC85xx inbound mailbox
+ * @mport: Master port implementing the inbound message unit
+ * @mbox: Mailbox to open
+ * @entries: Number of entries in the inbound mailbox ring
+ *
+ * Initializes buffer ring, request the inbound message interrupt,
+ * and enables the inbound message unit. Returns %0 on success
+ * or %-EINVAL on failure.
+ */
+int rio_open_inb_mbox(struct rio_mport *mport, int mbox, int entries)
+{
+	int i, rc = 0;
+
+	if ((entries < RIO_MIN_RX_RING_SIZE) ||
+	    (entries > RIO_MAX_RX_RING_SIZE) || (!is_power_of_2(entries))) {
+		rc = -EINVAL;
+		goto out;
+	}
+
+	/* Initialize client buffer ring */
+	msg_rx_ring.size = entries;
+	msg_rx_ring.rx_slot = 0;
+	for (i = 0; i < msg_rx_ring.size; i++)
+		msg_rx_ring.virt_buffer[i] = NULL;
+
+	/* Initialize inbound message ring */
+	msg_rx_ring.virt = dma_alloc_coherent(NULL,
+					      msg_rx_ring.size *
+					      RIO_MAX_MSG_SIZE,
+					      &msg_rx_ring.phys, GFP_KERNEL);
+
+	/* Point dequeue/enqueue pointers at first entry in ring */
+	out_be32((void *)&msg_regs->ifqdpar, (u32) msg_rx_ring.phys);
+	out_be32((void *)&msg_regs->ifqepar, (u32) msg_rx_ring.phys);
+
+	/* Clear interrupt status */
+	out_be32((void *)&msg_regs->isr, 0x00000091);
+
+	/* Hook up inbound message handler */
+	request_irq(MPC85xx_IRQ_RIO_RX, mpc85xx_rio_rx_handler, 0, "msg_rx",
+		    (void *)mport);
+
+	/*
+	 * Configure inbound message unit:
+	 *      Snooping
+	 *      4KB max message size
+	 *      Unmask all interrupt sources
+	 *      Disable
+	 */
+	out_be32((void *)&msg_regs->imr, 0x001b0060);
+
+	/* Set number of queue entries */
+	out_be32((void *)&msg_regs->imr,
+		 in_be32((void *)&msg_regs->imr) |
+		 ((get_bitmask_order(entries) - 2) << 12));
+
+	/* Now enable the unit */
+	out_be32((void *)&msg_regs->imr, in_be32((void *)&msg_regs->imr) | 
0x1);
+
+      out:
+	return rc;
+}
+
+/**
+ * rio_close_inb_mbox - Shut down MPC85xx inbound mailbox
+ * @mport: Master port implementing the inbound message unit
+ * @mbox: Mailbox to close
+ *
+ * Disables the inbound message unit, free all buffers, and
+ * frees the inbound message interrupt.
+ */
+void rio_close_inb_mbox(struct rio_mport *mport, int mbox)
+{
+	/* Disable inbound message unit */
+	out_be32((void *)&msg_regs->imr, 0);
+
+	/* Free ring */
+	dma_free_coherent(NULL, msg_rx_ring.size * RIO_MAX_MSG_SIZE,
+			  msg_rx_ring.virt, msg_rx_ring.phys);
+
+	/* Free interrupt */
+	free_irq(MPC85xx_IRQ_RIO_RX, (void *)mport);
+}
+
+/**
+ * rio_hw_add_inb_buffer - Add buffer to the MPC85xx inbound message 
queue
+ * @mport: Master port implementing the inbound message unit
+ * @mbox: Inbound mailbox number
+ * @buf: Buffer to add to inbound queue
+ *
+ * Adds the @buf buffer to the MPC85xx inbound message queue. Returns
+ * %0 on success or %-EINVAL on failure.
+ */
+int rio_hw_add_inb_buffer(struct rio_mport *mport, int mbox, void 
*buf)
+{
+	int rc = 0;
+
+	pr_debug("RIO: rio_hw_add_inb_buffer(), msg_rx_ring.rx_slot %d\n",
+		 msg_rx_ring.rx_slot);
+
+	if (msg_rx_ring.virt_buffer[msg_rx_ring.rx_slot]) {
+		printk(KERN_ERR
+		       "RIO: error adding inbound buffer %d, buffer exists\n",
+		       msg_rx_ring.rx_slot);
+		rc = -EINVAL;
+		goto out;
+	}
+
+	msg_rx_ring.virt_buffer[msg_rx_ring.rx_slot] = buf;
+	if (++msg_rx_ring.rx_slot == msg_rx_ring.size)
+		msg_rx_ring.rx_slot = 0;
+
+      out:
+	return rc;
+}
+
+EXPORT_SYMBOL_GPL(rio_hw_add_inb_buffer);
+
+/**
+ * rio_hw_get_inb_message - Fetch inbound message from the MPC85xx 
message unit
+ * @mport: Master port implementing the inbound message unit
+ * @mbox: Inbound mailbox number
+ *
+ * Gets the next available inbound message from the inbound message 
queue.
+ * A pointer to the message is returned on success or NULL on failure.
+ */
+void *rio_hw_get_inb_message(struct rio_mport *mport, int mbox)
+{
+	u32 imr;
+	u32 phys_buf, virt_buf;
+	void *buf = NULL;
+	int buf_idx;
+
+	phys_buf = in_be32((void *)&msg_regs->ifqdpar);
+
+	/* If no more messages, then bail out */
+	if (phys_buf == in_be32((void *)&msg_regs->ifqepar))
+		goto out2;
+
+	virt_buf = (u32) msg_rx_ring.virt + (phys_buf - msg_rx_ring.phys);
+	buf_idx = (phys_buf - msg_rx_ring.phys) / RIO_MAX_MSG_SIZE;
+	buf = msg_rx_ring.virt_buffer[buf_idx];
+
+	if (!buf) {
+		pr_debug(KERN_ERR
+			 "RIO: inbound message copy failed, no buffers\n");
+		goto out1;
+	}
+
+	/* Copy max message size, caller is expected to allocate that big */
+	memcpy(buf, (void *)virt_buf, RIO_MAX_MSG_SIZE);
+
+	/* Clear the available buffer */
+	msg_rx_ring.virt_buffer[buf_idx] = NULL;
+
+      out1:
+	imr = in_be32((void *)&msg_regs->imr);
+	out_be32((void *)&msg_regs->imr, imr | RIO_MSG_IMR_MI);
+
+      out2:
+	return buf;
+}
+
+EXPORT_SYMBOL_GPL(rio_hw_get_inb_message);
+
+/**
+ * mpc85xx_rio_dbell_handler - MPC85xx doorbell interrupt handler
+ * @irq: Linux interrupt number
+ * @dev_instance: Pointer to interrupt-specific data
+ * @regs: Register context
+ *
+ * Handles doorbell interrupts. Parses a list of registered
+ * doorbell event handlers and executes a matching event handler.
+ */
+static irqreturn_t
+mpc85xx_rio_dbell_handler(int irq, void *dev_instance, struct pt_regs 
*regs)
+{
+	int dsr;
+	struct rio_mport *port = (struct rio_mport *)dev_instance;
+
+	dsr = in_be32((void *)&msg_regs->dsr);
+
+	if (dsr & DOORBELL_DSR_TE) {
+		printk(KERN_INFO "RIO: doorbell reception error\n");
+		out_be32((void *)&msg_regs->dsr, DOORBELL_DSR_TE);
+		goto out;
+	}
+
+	if (dsr & DOORBELL_DSR_QFI) {
+		printk(KERN_INFO "RIO: doorbell queue full\n");
+		out_be32((void *)&msg_regs->dsr, DOORBELL_DSR_QFI);
+		goto out;
+	}
+
+	/* XXX Need to check/dispatch until queue empty */
+	if (dsr & DOORBELL_DSR_DIQI) {
+		u32 dmsg =
+		    (u32) dbell_ring.virt +
+		    (in_be32((void *)&msg_regs->dqdpar) & 0xfff);
+		u32 dmr;
+		struct rio_dbell *dbell;
+		int found = 0;
+
+		pr_debug(KERN_INFO
+			 "RIO: processing doorbell, sid %2.2x tid %2.2x info %4.4x\n",
+			 DBELL_SID(dmsg), DBELL_TID(dmsg), DBELL_INF(dmsg));
+
+		list_for_each_entry(dbell, &port->dbells, node) {
+			if ((dbell->res->start <= DBELL_INF(dmsg)) &&
+			    (dbell->res->end >= DBELL_INF(dmsg))) {
+				found = 1;
+				break;
+			}
+		}
+		if (found) {
+			dbell->dinb(port, DBELL_SID(dmsg), DBELL_TID(dmsg),
+				    DBELL_INF(dmsg));
+		} else {
+			pr_debug(KERN_INFO
+				 "RIO: spurious doorbell, sid %2.2x tid %2.2x info %4.4x\n",
+				 DBELL_SID(dmsg), DBELL_TID(dmsg),
+				 DBELL_INF(dmsg));
+		}
+		dmr = in_be32((void *)&msg_regs->dmr);
+		out_be32((void *)&msg_regs->dmr, dmr | DOORBELL_DMR_DI);
+		out_be32((void *)&msg_regs->dsr, DOORBELL_DSR_DIQI);
+	}
+
+      out:
+	return IRQ_HANDLED;
+}
+
+/**
+ * mpc85xx_rio_doorbell_init - MPC85xx doorbell interface init
+ * @mport: Master port implementing the inbound doorbell unit
+ *
+ * Initializes doorbell unit hardware and inbound DMA buffer
+ * ring. Called from mpc85xx_rio_setup().
+ */
+static void mpc85xx_rio_doorbell_init(struct rio_mport *mport)
+{
+	/* Map outbound doorbell window immediately after maintenance window 
*/
+	dbell_win =
+	    (u32) ioremap(mport->iores.start + RIO_MAINT_WIN_SIZE,
+			  RIO_DBELL_WIN_SIZE);
+
+	/* Initialize inbound doorbells */
+	dbell_ring.virt = dma_alloc_coherent(NULL,
+					     512 * DOORBELL_MESSAGE_SIZE,
+					     &dbell_ring.phys, GFP_KERNEL);
+
+	/* Point dequeue/enqueue pointers at first entry in ring */
+	out_be32((void *)&msg_regs->dqdpar, (u32) dbell_ring.phys);
+	out_be32((void *)&msg_regs->dqepar, (u32) dbell_ring.phys);
+
+	/* Clear interrupt status */
+	out_be32((void *)&msg_regs->dsr, 0x00000091);
+
+	/* Hook up doorbell handler */
+	request_irq(MPC85xx_IRQ_RIO_BELL, mpc85xx_rio_dbell_handler, 0,
+		    "dbell_rx", (void *)mport);
+
+	/* Configure doorbells for snooping, 512 entries, and enable */
+	out_be32((void *)&msg_regs->dmr, 0x00108161);
+}
+
+static char *cmdline = NULL;
+
+static int mpc85xx_rio_get_hdid(int index)
+{
+	/* XXX Need to parse multiple entries in some format */
+	if (!cmdline)
+		return -1;
+
+	return simple_strtol(cmdline, NULL, 0);
+}
+
+static int mpc85xx_rio_get_cmdline(char *s)
+{
+	if (!s)
+		return 0;
+
+	cmdline = s;
+	return 1;
+}
+
+__setup("riohdid=", mpc85xx_rio_get_cmdline);
+
+/**
+ * mpc85xx_rio_setup - Setup MPC85xx RapidIO interface
+ * @law_start: Starting physical address of RapidIO LAW
+ * @law_size: Size of RapidIO LAW
+ *
+ * Initializes MPC85xx RapidIO hardware interface, configures
+ * master port with system-specific info, and registers the
+ * master port with the RapidIO subsystem.
+ */
+void mpc85xx_rio_setup(int law_start, int law_size)
+{
+	struct rio_ops *ops;
+	struct rio_mport *port;
+
+	ops = kmalloc(sizeof(struct rio_ops), GFP_KERNEL);
+	ops->lcread = mpc85xx_local_config_read;
+	ops->lcwrite = mpc85xx_local_config_write;
+	ops->cread = mpc85xx_rio_config_read;
+	ops->cwrite = mpc85xx_rio_config_write;
+	ops->dsend = mpc85xx_rio_doorbell_send;
+
+	port = kmalloc(sizeof(struct rio_mport), GFP_KERNEL);
+	port->id = 0;
+	port->index = 0;
+	INIT_LIST_HEAD(&port->dbells);
+	port->iores.start = law_start;
+	port->iores.end = law_start + law_size;
+	port->iores.flags = IORESOURCE_MEM;
+
+	rio_init_dbell_res(&port->riores[RIO_DOORBELL_RESOURCE], 0, 0xffff);
+	rio_init_mbox_res(&port->riores[RIO_INB_MBOX_RESOURCE], 0, 0);
+	rio_init_mbox_res(&port->riores[RIO_OUTB_MBOX_RESOURCE], 0, 0);
+	strcpy(port->name, "RIO0 mport");
+
+	port->ops = ops;
+	port->host_deviceid = mpc85xx_rio_get_hdid(port->id);
+
+	rio_register_mport(port);
+
+	regs_win = (u32) ioremap(RIO_REGS_BASE, 0x20000);
+	atmu_regs = (struct rio_atmu_regs *)(regs_win + 
RIO_ATMU_REGS_OFFSET);
+	maint_atmu_regs = atmu_regs + 1;
+	dbell_atmu_regs = atmu_regs + 2;
+	msg_regs = (struct rio_msg_regs *)(regs_win + RIO_MSG_REGS_OFFSET);
+
+	/* Configure maintenance transaction window */
+	out_be32((void *)&maint_atmu_regs->rowbar, 0x000c0000);
+	out_be32((void *)&maint_atmu_regs->rowar, 0x80077015);
+
+	maint_win = (u32) ioremap(law_start, RIO_MAINT_WIN_SIZE);
+
+	/* Configure outbound doorbell window */
+	out_be32((void *)&dbell_atmu_regs->rowbar, 0x000c0400);
+	out_be32((void *)&dbell_atmu_regs->rowar, 0x8004200b);
+	mpc85xx_rio_doorbell_init(port);
+}
diff --git a/arch/ppc/syslib/ppc85xx_rio.h 
b/arch/ppc/syslib/ppc85xx_rio.h
new file mode 100644
--- /dev/null
+++ b/arch/ppc/syslib/ppc85xx_rio.h
@@ -0,0 +1,21 @@
+/*
+ * MPC85xx RapidIO definitions
+ *
+ * Copyright 2005 MontaVista Software, Inc.
+ * Matt Porter <mporter@kernel.crashing.org>
+ *
+ * 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.
+ */
+
+#ifndef __PPC_SYSLIB_PPC85XX_RIO_H
+#define __PPC_SYSLIB_PPC85XX_RIO_H
+
+#include <linux/config.h>
+#include <linux/init.h>
+
+extern void mpc85xx_rio_setup(int law_start, int law_size);
+
+#endif				/* __PPC_SYSLIB_PPC85XX_RIO_H */
diff --git a/include/asm-ppc/rio.h b/include/asm-ppc/rio.h
new file mode 100644
--- /dev/null
+++ b/include/asm-ppc/rio.h
@@ -0,0 +1,18 @@
+/*
+ * RapidIO architecture support
+ *
+ * Copyright 2005 MontaVista Software, Inc.
+ * Matt Porter <mporter@kernel.crashing.org>
+ *
+ * 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.
+ */
+
+#ifndef ASM_PPC_RIO_H
+#define ASM_PPC_RIO_H
+
+extern void platform_rio_init(void);
+
+#endif				/* ASM_PPC_RIO_H */

_______________________________________________
Linuxppc-embedded mailing list
Linuxppc-embedded@ozlabs.org
https://ozlabs.org/mailman/listinfo/linuxppc-embedded
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help