[linux-yocto] [PATCH 02/30] drivers/rapidio: new files

Charlie Paul cpaul.windriver at gmail.com
Thu May 1 08:20:37 PDT 2014


From: Paul Butler <paul.butler at windriver.com>

These files are the initial files for the rapidio driver.

They include: Hotplug,net,routing,locks and distination ids.

Signed-off-by: Paul Butler <paul.butler at windriver.com>
---
 drivers/rapidio/rio-destid.c    | 1550 +++++++++++++++++++++++++++++
 drivers/rapidio/rio-destid.h    |   85 ++
 drivers/rapidio/rio-dio.c       |  872 +++++++++++++++++
 drivers/rapidio/rio-hotplug.c   |  138 +++
 drivers/rapidio/rio-hotplug.h   |   34 +
 drivers/rapidio/rio-job.h       |   31 +
 drivers/rapidio/rio-locks.c     |  713 ++++++++++++++
 drivers/rapidio/rio-locks.h     |   67 ++
 drivers/rapidio/rio-multicast.h |   28 +
 drivers/rapidio/rio-net.h       |   26 +
 drivers/rapidio/rio-net2.c      | 2033 +++++++++++++++++++++++++++++++++++++++
 drivers/rapidio/rio-quirks.c    |   59 ++
 drivers/rapidio/rio-route.c     |  290 ++++++
 drivers/rapidio/rio-route.h     |   31 +
 14 files changed, 5957 insertions(+)
 create mode 100644 drivers/rapidio/rio-destid.c
 create mode 100644 drivers/rapidio/rio-destid.h
 create mode 100644 drivers/rapidio/rio-dio.c
 create mode 100644 drivers/rapidio/rio-hotplug.c
 create mode 100644 drivers/rapidio/rio-hotplug.h
 create mode 100644 drivers/rapidio/rio-job.h
 create mode 100644 drivers/rapidio/rio-locks.c
 create mode 100644 drivers/rapidio/rio-locks.h
 create mode 100644 drivers/rapidio/rio-multicast.h
 create mode 100644 drivers/rapidio/rio-net.h
 create mode 100644 drivers/rapidio/rio-net2.c
 create mode 100644 drivers/rapidio/rio-quirks.c
 create mode 100644 drivers/rapidio/rio-route.c
 create mode 100644 drivers/rapidio/rio-route.h

diff --git a/drivers/rapidio/rio-destid.c b/drivers/rapidio/rio-destid.c
new file mode 100644
index 0000000..08aacd6
--- /dev/null
+++ b/drivers/rapidio/rio-destid.c
@@ -0,0 +1,1550 @@
+/*
+ * RapidIO device destination ID assingment support
+ *
+ * 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/types.h>
+#include <linux/kernel.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/slab.h>
+#include <linux/radix-tree.h>
+#include <linux/hardirq.h>
+#include <linux/err.h>
+
+#include "rio.h"
+
+struct rio_net_node {
+	struct kref kref;
+	u16 destid;
+	u16 comptag;
+	u8  lock_hw;
+	u8  lut_update;
+	u8  return_port;
+	u8  pinned;
+#if defined(CONFIG_RAPIDIO_STATIC_DESTID)
+	struct radix_tree_root route_tree;
+	atomic_t rio_route_num;
+#endif
+};
+
+struct rio_net_id {
+	struct list_head node;
+	struct kref kref;
+	u16 destid;
+	u16 comptag;
+	int net_id;
+	int pinned;
+};
+
+static LIST_HEAD(rio_net);
+static DEFINE_SPINLOCK(rio_net_lock);
+
+#define RIO_DESTID_KEY(h, pp, pd) (		\
+		(u8)((h) & 0xff) << 24 |	\
+		(u8)((pp) & 0xff) << 16 |	\
+		(u16)((pd) & 0xffff))
+
+#define RIO_GET_PARENT_DEST(key) ((u16)((key) & 0xffff))
+#define RIO_GET_PARENT_PORT(key) ((u8)(((key) & 0xff0000) >> 16))
+#define RIO_GET_DEVICE_HOP(key) ((u8)(((key) & 0xff000000) >> 24))
+
+#define RIO_DESTID_ONE_WAY_TAG (0)
+#define RIO_DESTID_LEGACY_TAG (1)
+#define RIO_DESTID_REDUNDANT_TAG (2)
+
+struct rio_dest {
+	u16 destid;
+	u16 comptag;
+	u16 flags;
+	u16 return_port;
+};
+
+#define RIO_HW_LOCK_ENABLE    (1)
+#define RIO_UPDATE_LUT_ENABLE (1 << 1)
+#define RIO_ONE_WAY_ENABLE    (1 << 2)
+#define RIO_LEGACY_ENABLE     (1 << 3)
+#define RIO_REDUNDANT_ENABLE  (1 << 4)
+#define RIO_DEFAULT_FLAGS     ((u16)(RIO_HW_LOCK_ENABLE | \
+				RIO_UPDATE_LUT_ENABLE))
+
+#define RIO_FLAG_GET(p, flag) (((p)->flags & flag) ? 1 : 0)
+#define RIO_FLAG_ADD(p, flag) ((p)->flags |= (u16)(flag))
+#define RIO_DEF_FLAGS_SET(p)  ((p)->flags = RIO_DEFAULT_FLAGS)
+
+#define WARN_MSG \
+	"Operation aborted - Node destid tables are only probed during boot\n"
+
+/**
+ * RIO destid internal
+ */
+static void rio_net_release(struct kref *kref)
+{
+	struct rio_net_id *net = container_of(kref, struct rio_net_id, kref);
+
+	pr_info("RIO: kfree net id %d\n", net->net_id);
+	kfree(net);
+}
+
+static struct rio_net_id *rio_net_get(struct rio_net_id *net)
+{
+	if (net)
+		kref_get(&net->kref);
+
+	return net;
+}
+
+static void rio_net_put(struct rio_net_id *net)
+{
+	if (net)
+		kref_put(&net->kref, rio_net_release);
+}
+
+static int __rio_add_netid(u16 mport_destid, int net_id, u16 comptag)
+{
+	struct rio_net_id *net = kzalloc(sizeof(*net), GFP_KERNEL);
+
+	if (!net)
+		return -ENOMEM;
+
+	net->destid = mport_destid;
+	net->net_id = net_id;
+	INIT_LIST_HEAD(&net->node);
+	kref_init(&net->kref);
+	net->pinned = 0;
+	spin_lock(&rio_net_lock);
+	list_add_tail(&net->node, &rio_net);
+	spin_unlock(&rio_net_lock);
+
+	return 0;
+}
+static int __rio_remove_netid(u16 mport_destid, int net_id)
+{
+	struct rio_net_id *net, *next;
+	int rc = -ENODEV;
+
+	spin_lock(&rio_net_lock);
+	list_for_each_entry_safe(net, next, &rio_net, node) {
+		if (net->destid == mport_destid && net->net_id == net_id) {
+			if (!net->pinned) {
+				pr_info("RIO: removing net id %d\n",
+					net->net_id);
+				list_del_init(&net->node);
+				rio_net_put(net);
+				rc = 0;
+			} else {
+				pr_warn("RIO: Not removing Net id %d -in use\n",
+					net->net_id);
+				rc = -EBUSY;
+			}
+			goto done;
+		}
+	}
+done:
+	spin_unlock(&rio_net_lock);
+	return rc;
+}
+
+static struct rio_net_id *find_rio_net_id(u16 mport_destid,
+					  struct rio_net_id *from)
+{
+	struct rio_net_id *net;
+	struct list_head *n;
+
+	spin_lock(&rio_net_lock);
+
+	n = from ? from->node.next : rio_net.next;
+
+	while (n && (n != &rio_net)) {
+		net = list_entry(n, struct rio_net_id, node);
+		if (net->destid == mport_destid)
+			goto exit;
+		n = n->next;
+	}
+	net = NULL;
+exit:
+	rio_net_put(from);
+	net = rio_net_get(net);
+	spin_unlock(&rio_net_lock);
+	return net;
+}
+
+int rio_pin_netid(u16 host_deviceid, int net_id)
+{
+	struct rio_net_id *net, *next;
+
+	spin_lock(&rio_net_lock);
+	list_for_each_entry_safe(net, next, &rio_net, node) {
+		if (net->destid == host_deviceid && net->net_id == net_id) {
+			net->pinned++;
+			pr_info("RIO: pinn net id %d\n", net->net_id);
+			spin_unlock(&rio_net_lock);
+			return 0;
+		}
+	}
+	spin_unlock(&rio_net_lock);
+	return -ENODEV;
+}
+
+int rio_unlock_netid(u16 host_deviceid, int net_id)
+{
+	struct rio_net_id *net, *next;
+
+	spin_lock(&rio_net_lock);
+	list_for_each_entry_safe(net, next, &rio_net, node) {
+		if (net->destid == host_deviceid && net->net_id == net_id) {
+			net->pinned--;
+			pr_info("RIO: unlocknet id %d\n", net->net_id);
+			spin_unlock(&rio_net_lock);
+			return 0;
+		}
+	}
+	spin_unlock(&rio_net_lock);
+	return -ENODEV;
+}
+
+static void rio_node_release(struct kref *kref)
+{
+	struct rio_net_node *node = container_of(kref,
+						 struct rio_net_node,
+						 kref);
+	kfree(node);
+}
+
+static struct rio_net_node *rio_node_get(struct rio_net_node *node)
+{
+	if (node)
+		kref_get(&node->kref);
+
+	return node;
+}
+
+static void rio_node_put(struct rio_net_node *node)
+{
+	if (node)
+		kref_put(&node->kref, rio_node_release);
+}
+
+static int __rio_add_destid(struct rio_mport *mport,
+			    u16 parent_destid, int parent_port,
+			    int hopcount, struct rio_dest *dest)
+{
+	unsigned long key = RIO_DESTID_KEY(hopcount,
+					   parent_port,
+					   parent_destid);
+	struct rio_net_node *node = NULL;
+	int rc;
+
+	rcu_read_lock();
+	node = radix_tree_lookup(&mport->net.dst_tree, key);
+	rcu_read_unlock();
+	if (node)
+		return -EBUSY;
+	node = kzalloc(sizeof(*node), GFP_KERNEL);
+	if (!node)
+		return -ENOMEM;
+
+	node->destid = dest->destid;
+	node->comptag = dest->comptag;
+	if (RIO_FLAG_GET(dest, RIO_ONE_WAY_ENABLE))
+		node->return_port = dest->return_port;
+	if (RIO_FLAG_GET(dest, RIO_HW_LOCK_ENABLE))
+		node->lock_hw = 1;
+	if (RIO_FLAG_GET(dest, RIO_UPDATE_LUT_ENABLE))
+		node->lut_update = 1;
+#if defined(CONFIG_RAPIDIO_STATIC_DESTID)
+	INIT_RADIX_TREE(&node->route_tree, GFP_KERNEL);
+	atomic_set(&node->rio_route_num, 0);
+#endif
+	kref_init(&node->kref);
+	spin_lock(&mport->net.tree_lock);
+	rc = radix_tree_insert(&mport->net.dst_tree, key, node);
+	if (rc) {
+		rio_node_put(node);
+	} else {
+		struct rio_net_node *tmp = NULL;
+
+		if (RIO_FLAG_GET(dest, RIO_LEGACY_ENABLE)) {
+			tmp = radix_tree_tag_set(&mport->net.dst_tree,
+						 key, RIO_DESTID_LEGACY_TAG);
+			BUG_ON(tmp != node);
+		}
+		if (RIO_FLAG_GET(dest, RIO_REDUNDANT_ENABLE)) {
+			tmp = radix_tree_tag_set(&mport->net.dst_tree,
+						 key, RIO_DESTID_REDUNDANT_TAG);
+			BUG_ON(tmp != node);
+		}
+		if (RIO_FLAG_GET(dest, RIO_ONE_WAY_ENABLE)) {
+			tmp = radix_tree_tag_set(&mport->net.dst_tree,
+						 key, RIO_DESTID_ONE_WAY_TAG);
+			BUG_ON(tmp != node);
+		}
+		atomic_inc(&mport->net.rio_dst_num);
+		if (dest->destid > atomic_read(&mport->net.rio_max_dest))
+			atomic_set(&mport->net.rio_max_dest, dest->destid);
+	}
+	spin_unlock(&mport->net.tree_lock);
+	return rc;
+}
+
+static struct rio_net_node *rio_get_net_node(struct rio_mport *mport,
+					     u16 parent_destid,
+					     int parent_port,
+					     int hopcount)
+{
+	struct rio_net_node *node = NULL;
+	unsigned long key = RIO_DESTID_KEY(hopcount,
+					   parent_port,
+					   parent_destid);
+
+	rcu_read_lock();
+	node = radix_tree_lookup(&mport->net.dst_tree, key);
+	if (node)
+		node = rio_node_get(node);
+	rcu_read_unlock();
+	return node;
+}
+
+static int get_destid_tag(struct rio_mport *mport, u16 parent_destid,
+			  int parent_port, int hopcount, unsigned int tag)
+{
+	unsigned long key = RIO_DESTID_KEY(hopcount,
+					   parent_port,
+					   parent_destid);
+	int set;
+
+	rcu_read_lock();
+	set = radix_tree_tag_get(&mport->net.dst_tree, key, tag);
+	rcu_read_unlock();
+
+	return set;
+}
+
+#if defined(CONFIG_RAPIDIO_STATIC_DESTID)
+
+static int __remove_static_routes_for_node(struct rio_mport *mport,
+					   struct rio_net_node *node, int items)
+{
+	unsigned long *keys = NULL;
+	void **nptr = NULL;
+	int i, num, rc = -ENOMEM;
+
+	if (items <= 0)
+		return 0;
+
+	keys = kmalloc(sizeof(*keys) * items, GFP_KERNEL);
+	if (!keys)
+		goto done_keys;
+
+	nptr = kzalloc(sizeof(void *) * items, GFP_KERNEL);
+	if (!nptr)
+		goto done_nptr;
+
+	spin_lock(&mport->net.tree_lock);
+
+	num = radix_tree_gang_lookup_slot(&node->route_tree,
+					  (void ***)nptr,
+					  keys, 0, items);
+	for (i = 0; i < num; i++) {
+		u8 *curr_port = radix_tree_deref_slot((void **)nptr[i]);
+
+		if (unlikely(!curr_port))
+			continue;
+
+		curr_port = radix_tree_delete(&node->route_tree, keys[i]);
+		atomic_dec(&node->rio_route_num);
+	}
+	spin_unlock(&mport->net.tree_lock);
+
+	synchronize_rcu();
+
+	rc = (atomic_read(&node->rio_route_num) == 0 ? 0 : -EFAULT);
+
+	kfree(nptr);
+done_nptr:
+	kfree(keys);
+done_keys:
+	if (rc)
+		pr_warn("RIO: (%s) destid %hx rc %d\n",
+			__func__, node->destid, rc);
+	return rc;
+}
+#endif
+
+static int __rio_release_destid(struct rio_mport *mport, u16 parent_destid,
+				int parent_port, int hopcount)
+{
+	struct rio_net_node *node = NULL;
+	unsigned long key = RIO_DESTID_KEY(hopcount,
+					   parent_port,
+					   parent_destid);
+
+	spin_lock(&mport->net.tree_lock);
+	node = radix_tree_lookup(&mport->net.dst_tree, key);
+	if (node && node->pinned) {
+		spin_unlock(&mport->net.tree_lock);
+		return -EBUSY;
+	}
+	node = radix_tree_delete(&mport->net.dst_tree, key);
+	spin_unlock(&mport->net.tree_lock);
+	if (node) {
+		synchronize_rcu();
+#if defined(CONFIG_RAPIDIO_STATIC_DESTID)
+		/* remove static routes if added */
+		__remove_static_routes_for_node(mport, node,
+					     atomic_read(&node->rio_route_num));
+#endif
+		rio_node_put(node);
+		atomic_dec(&mport->net.rio_dst_num);
+	}
+	return 0;
+}
+
+int rio_pin_destid(struct rio_mport *mport, u16 parent_destid, int parent_port,
+		   int hopcount)
+{
+	struct rio_net_node *node = NULL;
+	unsigned long key = RIO_DESTID_KEY(hopcount,
+					   parent_port,
+					   parent_destid);
+	int rc = 0;
+
+	spin_lock(&mport->net.tree_lock);
+	node = radix_tree_lookup(&mport->net.dst_tree, key);
+	if (node)
+		node->pinned++;
+	else
+		rc = -ENODEV;
+	spin_unlock(&mport->net.tree_lock);
+	return rc;
+}
+
+int rio_unlock_destid(struct rio_mport *mport, u16 parent_destid,
+		      int parent_port, int hopcount)
+{
+	struct rio_net_node *node = NULL;
+	unsigned long key = RIO_DESTID_KEY(hopcount,
+					   parent_port,
+					   parent_destid);
+	int rc = 0;
+
+	spin_lock(&mport->net.tree_lock);
+	node = radix_tree_lookup(&mport->net.dst_tree, key);
+	if (node && node->pinned)
+		node->pinned--;
+	else
+		rc = -ENODEV;
+	spin_unlock(&mport->net.tree_lock);
+	return rc;
+}
+
+#if defined(CONFIG_RAPIDIO_STATIC_DESTID)
+
+int __rio_release_node_table(struct rio_mport *mport)
+{
+	int parent_port, hopcount;
+	u16 parent_destid;
+	struct rio_net_node *mp_node;
+	int rc = 0;
+
+	if (!mport)
+		return -EINVAL;
+
+	mp_node = rio_get_net_node(mport, -1, -1, -1);
+	if (mp_node) {
+		rc = __rio_release_destid(mport, -1, -1, -1);
+		rio_node_put(mp_node);
+		if (rc)
+			return rc;
+	}
+	for (hopcount = 0; hopcount < 256; hopcount++) {
+		for (parent_port = -1;; parent_port++) {
+
+			if (parent_port > 20)
+				break;
+			for (parent_destid = 0;
+			     parent_destid <=
+				atomic_read(&mport->net.rio_max_dest);
+			     parent_destid++) {
+
+				struct rio_net_node *node =
+					rio_get_net_node(mport,
+							 parent_destid,
+							 parent_port,
+							 hopcount);
+				if (node) {
+					rc = __rio_release_destid(mport,
+								  parent_destid,
+								  parent_port,
+								  hopcount);
+					rio_node_put(node);
+					if (rc)
+						return rc;
+				}
+			}
+		}
+	}
+	return rc;
+}
+
+struct rio_route {
+	unsigned long key;
+	u8  *port;
+};
+
+static int __lookup_static_route(struct rio_mport *mport,
+				 unsigned long node_key,
+				 struct rio_static_route *sroute,
+				 int num)
+{
+	int rc = 0;
+	struct rio_net_node *node = NULL;
+
+	rcu_read_lock();
+	node = radix_tree_lookup(&mport->net.dst_tree, node_key);
+	if (node) {
+		int i;
+		for (i = 0; i < num; i++) {
+			u8 *curr_port = NULL;
+			unsigned long key = sroute[i].sw_destid;
+			curr_port = radix_tree_lookup(&node->route_tree, key);
+			if (curr_port)
+				sroute[i].sw_port = *curr_port;
+		}
+	} else {
+		rc = -ENODEV;
+	}
+	rcu_read_unlock();
+	return rc;
+}
+
+static int __static_route_table(struct rio_mport *mport, unsigned long node_key,
+				struct rio_static_route *sroute, int items)
+{
+	int rc = 0;
+	unsigned long *keys = kmalloc(sizeof(*keys) * items, GFP_KERNEL);
+	void **nptr = NULL;
+	struct rio_net_node *node = NULL;
+
+	if (!keys)
+		return -ENOMEM;
+
+	nptr = kzalloc(sizeof(void *) * items, GFP_KERNEL);
+	if (!nptr) {
+		kfree(keys);
+		return -ENOMEM;
+	}
+
+	rcu_read_lock();
+	node = radix_tree_lookup(&mport->net.dst_tree, node_key);
+	if (node) {
+		int i;
+		int num;
+retry:
+		num = radix_tree_gang_lookup_slot(&node->route_tree,
+						  (void ***)nptr,
+						  keys, 0, items);
+		for (i = 0; i < num; i++) {
+			u8 *curr_port = radix_tree_deref_slot((void **)nptr[i]);
+
+			if (unlikely(!curr_port)) {
+				sroute[i].sw_destid = RIO_INVALID_DESTID;
+				sroute[i].sw_port = RIO_INVALID_ROUTE;
+				continue;
+			}
+			if (radix_tree_deref_retry(curr_port))
+				goto retry;
+
+			sroute[i].sw_destid = keys[i];
+			sroute[i].sw_port = *curr_port;
+		}
+		for (; i < items; i++) {
+			sroute[i].sw_destid = RIO_INVALID_DESTID;
+			sroute[i].sw_port = RIO_INVALID_ROUTE;
+		}
+	} else
+		rc = -ENODEV;
+
+	rcu_read_unlock();
+
+	kfree(keys);
+	kfree(nptr);
+
+	return rc;
+}
+
+static int __remove_static_route(struct rio_mport *mport,
+				 unsigned long node_key,
+				 struct rio_route *route)
+{
+	struct rio_net_node *node = NULL;
+	int rc = -ENODEV;
+
+	spin_lock(&mport->net.tree_lock);
+	node = radix_tree_lookup(&mport->net.dst_tree, node_key);
+	if (node) {
+		if (node->pinned) {
+			rc = -EBUSY;
+			goto done;
+		}
+		while (route->key != RIO_INVALID_DESTID) {
+			u8 *curr_port = NULL;
+			curr_port = radix_tree_lookup(&node->route_tree,
+						      route->key);
+			if (curr_port) {
+				curr_port = radix_tree_delete(&node->route_tree,
+							      route->key);
+				route->port = curr_port;
+				atomic_dec(&node->rio_route_num);
+			} else {
+				rc = -ENODEV;
+				goto done;
+			}
+			route++;
+		}
+	}
+done:
+	spin_unlock(&mport->net.tree_lock);
+	return rc;
+}
+
+static int __add_static_route(struct rio_mport *mport, unsigned long node_key,
+			      struct rio_route *route, int update)
+{
+	struct rio_net_node *node = NULL;
+	int rc = -ENODEV;
+
+	spin_lock(&mport->net.tree_lock);
+	node = radix_tree_lookup(&mport->net.dst_tree, node_key);
+	if (node) {
+		if (node->pinned) {
+			rc = -EBUSY;
+			goto done;
+		}
+		while (route->port) {
+			void **rp = NULL;
+			u8 *curr_port = NULL;
+			rp = radix_tree_lookup_slot(&node->route_tree,
+						    route->key);
+			if (rp) {
+				if (update) {
+					curr_port = radix_tree_deref_slot(rp);
+					if (unlikely(!curr_port))
+						goto next;
+					radix_tree_replace_slot(rp,
+								route->port);
+					route->port = curr_port;
+				} else {
+					rc = -EBUSY;
+					goto done;
+				}
+			} else {
+				rc = radix_tree_insert(&node->route_tree,
+						       route->key, route->port);
+				if (rc)
+					goto done;
+				atomic_inc(&node->rio_route_num);
+				route->port = NULL;
+			}
+next:
+			route++;
+		}
+	}
+done:
+	spin_unlock(&mport->net.tree_lock);
+	return rc;
+}
+
+static struct rio_route *__alloc_route_table(struct rio_static_route *route,
+					     int num_routes, int add)
+{
+	struct rio_route *rp;
+	int i;
+
+	rp = kzalloc(sizeof(*rp) * (num_routes + 1), GFP_KERNEL);
+	if (!rp)
+		return ERR_PTR(-ENOMEM);
+	for (i = 0; i < num_routes; i++) {
+		if (add) {
+			rp[i].port = kmalloc(sizeof(u8), GFP_KERNEL);
+			if (!rp[i].port)
+				goto cleanup;
+
+			*rp[i].port = route[i].sw_port;
+		} else
+			rp[i].port = NULL;
+
+		rp[i].key = route[i].sw_destid;
+	}
+	rp[i].port = NULL;
+	rp[i].key = RIO_INVALID_DESTID;
+	return rp;
+
+cleanup:
+	for (i = 0; i < num_routes; i++) {
+		if (rp[i].port != NULL)
+			kfree(rp[i].port);
+	}
+	kfree(rp);
+	return ERR_PTR(-ENOMEM);
+}
+
+static int add_static_route(struct rio_mport *mport, u16 parent_destid,
+			    int parent_port, int hopcount,
+			    struct rio_static_route *route,
+			    int num_routes, int update)
+{
+	struct rio_route *rp;
+	int i, rc = -ENOMEM;
+
+#if !defined(CONFIG_RAPIDIO_HOTPLUG)
+	if (WARN(system_state != SYSTEM_BOOTING, WARN_MSG))
+		return -EINVAL;
+#endif
+	BUG_ON(!mport || !route || !num_routes);
+
+	rp = __alloc_route_table(route, num_routes, 1);
+	if (IS_ERR(rp))
+		return PTR_ERR(rp);
+
+	rc = __add_static_route(mport,
+				RIO_DESTID_KEY(hopcount,
+					       parent_port,
+					       parent_destid),
+				&rp[0],
+				update);
+	if (update)
+		synchronize_rcu();
+
+	for (i = 0; i < num_routes; i++) {
+		if (rp[i].port != NULL)
+			kfree(rp[i].port);
+	}
+	kfree(rp);
+
+	return rc;
+}
+
+int rio_remove_static_route(struct rio_mport *mport, u16 parent_destid,
+			int parent_port, int hopcount,
+			struct rio_static_route *route, int num_routes)
+{
+	struct rio_route *rp;
+	int i, rc = -ENOMEM;
+
+#if !defined(CONFIG_RAPIDIO_HOTPLUG)
+	if (WARN(system_state != SYSTEM_BOOTING, WARN_MSG))
+		return -EINVAL;
+#endif
+	BUG_ON(!mport || !route || !num_routes);
+
+	rp = __alloc_route_table(route, num_routes, 0);
+	if (IS_ERR(rp))
+		return PTR_ERR(rp);
+
+	rc = __remove_static_route(mport,
+				   RIO_DESTID_KEY(hopcount,
+						  parent_port,
+						  parent_destid),
+				   &rp[0]);
+	synchronize_rcu();
+
+	for (i = 0; i < num_routes; i++) {
+		if (rp[i].port) {
+			pr_debug("RIO: removed %lx %hhu from static route table\n",
+				 rp[i].key, *rp[i].port);
+			kfree(rp[i].port);
+		}
+	}
+	kfree(rp);
+
+	return rc;
+}
+EXPORT_SYMBOL(rio_remove_static_route);
+
+int rio_add_static_route(struct rio_mport *mport, u16 parent_destid,
+			 int parent_port, int hopcount,
+			 struct rio_static_route *route, int num_routes)
+{
+	return add_static_route(mport, parent_destid, parent_port,
+				hopcount, route, num_routes, 0);
+}
+EXPORT_SYMBOL(rio_add_static_route);
+
+int rio_update_static_route(struct rio_mport *mport, u16 parent_destid,
+			    int parent_port, int hopcount,
+			    struct rio_static_route *route, int num_routes)
+{
+	return add_static_route(mport, parent_destid, parent_port,
+				hopcount, route, num_routes, 1);
+}
+EXPORT_SYMBOL(rio_update_static_route);
+
+int rio_lookup_static_route(struct rio_dev *rdev, u16 sw_dest, u8 *route_port)
+{
+	struct rio_static_route sroute = { sw_dest, RIO_INVALID_ROUTE };
+	int rc;
+
+	rc = __lookup_static_route(rdev->hport,
+				   RIO_DESTID_KEY(rdev->hopcount,
+						  rdev->prev_port,
+						  rdev->prev_destid),
+				   &sroute, 1);
+
+	*route_port = sroute.sw_port;
+	return rc;
+}
+EXPORT_SYMBOL(rio_lookup_static_route);
+
+int rio_lookup_static_routes(struct rio_mport *mport, u16 parent_destid,
+			     int parent_port, int hopcount,
+			     struct rio_static_route *sroute, int num_routes)
+{
+	return __lookup_static_route(mport,
+				     RIO_DESTID_KEY(hopcount,
+						    parent_port,
+						    parent_destid),
+				     sroute, num_routes);
+}
+EXPORT_SYMBOL(rio_lookup_static_routes);
+
+struct rio_static_route *rio_static_route_table(struct rio_mport *mport,
+						u16 parent_destid,
+						int parent_port, int hopcount,
+						u16 *destid,
+						int *n)
+{
+	struct rio_net_node *node = rio_get_net_node(mport, parent_destid,
+						     parent_port, hopcount);
+	struct rio_static_route *sroute = NULL;
+	int num = (node ? atomic_read(&node->rio_route_num) : 0);
+	int rc;
+
+	if (!node)
+		return ERR_PTR(-ENODEV);
+
+	*destid = node->destid;
+	*n = num;
+	rio_node_put(node);
+	if (!num)
+		return NULL;
+
+	sroute = kzalloc(sizeof(*sroute) * num, GFP_KERNEL);
+	if (!sroute)
+		return ERR_PTR(-ENOMEM);
+
+	rc = __static_route_table(mport,
+				  RIO_DESTID_KEY(hopcount,
+						 parent_port,
+						 parent_destid),
+				  sroute, num);
+	if (rc) {
+		kfree(sroute);
+		return ERR_PTR(rc);
+	}
+	return sroute;
+}
+EXPORT_SYMBOL(rio_static_route_table);
+
+/**
+ * RIO static destid support - Exported KAPI
+ */
+
+int rio_get_next_destid(struct rio_mport *mport, u16 parent_destid,
+			int port_num, u8 hopcount, u16 *id, int *comptag)
+{
+	struct rio_net_node *node = NULL;
+
+	node = rio_get_net_node(mport, parent_destid, port_num, hopcount);
+
+	if (node) {
+		pr_debug("Assign destid %4.4x to device\n"
+			 "At hopcount %u port %d parent destid %4.4x\n",
+			 node->destid, hopcount,
+			 port_num, parent_destid);
+		*comptag = node->comptag;
+		*id = node->destid;
+		rio_node_put(node);
+		return 0;
+	}
+	return -EINVAL;
+}
+
+int rio_get_next_netid(u16 host_deviceid, int *net_id, int *comptag)
+{
+	struct rio_net_id *net = NULL;
+
+	net = find_rio_net_id(host_deviceid, net);
+
+	if (net) {
+		pr_debug("Assign DUS net_id %d to mport %4.4x net\n",
+			 net->net_id, host_deviceid);
+		*net_id = net->net_id;
+		*comptag = net->comptag;
+		rio_net_put(net);
+		return 0;
+	}
+	return -EINVAL;
+}
+
+#else
+
+/** Provide dynamic destid assignment **/
+
+static int next_destid;
+static int next_netid;
+
+int rio_get_next_destid(struct rio_mport *mport, u16 parent_destid,
+			int port_num, u8 hopcount, u16 *id, int *comptag)
+{
+	struct rio_net_node *node = NULL;
+	int rc = 0;
+
+	node = rio_get_net_node(mport, parent_destid, port_num, hopcount);
+
+	if (node) {
+		*comptag = node->comptag;
+		*id = node->destid;
+		rio_node_put(node);
+	} else {
+		struct rio_dest dest = {0};
+		if (next_destid == mport->host_deviceid)
+			next_destid++;
+		RIO_DEF_FLAGS_SET(&dest);
+		dest.destid = next_destid;
+		dest.comptag = next_destid;
+
+		rc = __rio_add_destid(mport, parent_destid, port_num,
+				      hopcount, &dest);
+		if (rc)
+			goto done;
+		*comptag = next_destid;
+		*id = next_destid;
+		next_destid++;
+	}
+	pr_debug("Assign destid %4.4x to device\n"
+		 "At hopcount %u port %d parent destid %4.4x\n",
+		 *id, hopcount, port_num, parent_destid);
+
+done:
+	return rc;
+}
+
+int rio_get_next_netid(u16 host_deviceid, int *net_id, int *comptag)
+{
+	struct rio_net_id *net = NULL;
+	int rc = 0;
+
+	net = find_rio_net_id(host_deviceid, net);
+
+	if (net) {
+		*net_id = net->net_id;
+		*comptag = net->comptag;
+		rio_net_put(net);
+	} else {
+		rc = __rio_add_netid(host_deviceid, next_netid, next_destid);
+		if (rc)
+			goto done;
+		*net_id = next_netid;
+		*comptag = next_destid;
+		next_netid++;
+		next_destid++;
+	}
+	pr_debug("Assign net_id %d to mport %4.4x net\n",
+		 *net_id, host_deviceid);
+
+done:
+	return rc;
+}
+#endif
+
+
+#if defined(CONFIG_RAPIDIO_HOTPLUG) || defined(CONFIG_RAPIDIO_STATIC_DESTID)
+
+static int dump_node(char *buf, struct rio_mport *mport,
+		     struct rio_net_node *node, unsigned long key)
+{
+	char *str = buf;
+	int rd_tag, st_tag, ow_tag;
+
+	rcu_read_lock();
+	rd_tag = radix_tree_tag_get(&mport->net.dst_tree, key,
+				    RIO_DESTID_REDUNDANT_TAG);
+	st_tag = radix_tree_tag_get(&mport->net.dst_tree, key,
+				    RIO_DESTID_LEGACY_TAG);
+	ow_tag = radix_tree_tag_get(&mport->net.dst_tree, key,
+				    RIO_DESTID_ONE_WAY_TAG);
+	rcu_read_unlock();
+	str += sprintf(str,
+		       "%4.4x\t%d\t%d\t%4.4x\t%4.4x\t%s",
+		       RIO_GET_PARENT_DEST(key),
+		       RIO_GET_PARENT_PORT(key),
+		       RIO_GET_DEVICE_HOP(key),
+		       node->destid,
+		       node->comptag,
+		       (rd_tag ? "BLOCKED" : \
+			(st_tag ? "LEGACY" : \
+			 (ow_tag ? "ONE-WAY" : "DEFAULT"))));
+	if (st_tag)
+		str += sprintf(str,
+			       "\t(lock=%d, lut_update=%d)",
+			       node->lock_hw,
+			       node->lut_update);
+	if (ow_tag)
+		str += sprintf(str,
+			       "\t(ret_port=%d)",
+			       node->return_port);
+	str += sprintf(str, "\n");
+
+	return str - buf;
+}
+
+static ssize_t __rio_net_nodes_show(struct rio_mport *mport, char *buf)
+{
+	char *str = buf;
+	int parent_port, hopcount;
+	u16 parent_destid;
+	struct rio_net_node *mp_node;
+
+	if (atomic_read(&mport->net.rio_dst_num))
+		str += sprintf(str,
+			       "parent\tparent\n"
+			       "id\tport\thop\tdestid\tcomptag\ttag\n");
+
+	mp_node = rio_get_net_node(mport, -1, -1, -1);
+	if (mp_node) {
+		str += dump_node(str, mport, mp_node,
+				 RIO_DESTID_KEY(-1, -1, -1));
+		rio_node_put(mp_node);
+	}
+	for (hopcount = 0; hopcount < 256; hopcount++) {
+		for (parent_port = -1;; parent_port++) {
+
+			if (parent_port > 20)
+				break;
+			for (parent_destid = 0;
+			     parent_destid <=
+				 atomic_read(&mport->net.rio_max_dest);
+			     parent_destid++) {
+
+				struct rio_net_node *node =
+					rio_get_net_node(mport,
+							 parent_destid,
+							 parent_port,
+							 hopcount);
+				if (node) {
+					str +=
+					  dump_node(str, mport, node,
+						 RIO_DESTID_KEY(hopcount,
+								parent_port,
+								parent_destid));
+					rio_node_put(node);
+				}
+			}
+		}
+	}
+	return str - buf;
+}
+
+#endif
+
+
+int rio_destid_sysfs_init(struct rio_mport *mport)
+{
+/*	return sysfs_create_group(&mport->dev.kobj, &rio_attribute_group); */
+	return 0;
+}
+
+
+int rio_lookup_next_destid(struct rio_mport *mport, u16 parent_destid,
+			   int port_num, u8 hopcount, u16 *id)
+{
+	struct rio_net_node *node = NULL;
+
+	node = rio_get_net_node(mport, parent_destid, port_num, hopcount);
+
+	if (node) {
+		*id = node->destid;
+		rio_node_put(node);
+		return 0;
+	}
+	return -ENODEV;
+}
+EXPORT_SYMBOL(rio_lookup_next_destid);
+
+int rio_dest_is_redundant(struct rio_mport *mport, u16 parent_destid,
+			  int parent_port, int hopcount)
+{
+	return get_destid_tag(mport, parent_destid, parent_port, hopcount,
+			      RIO_DESTID_REDUNDANT_TAG);
+}
+
+int rio_dest_is_legacy(struct rio_mport *mport, u16 parent_destid,
+		       int parent_port,
+		       int hopcount)
+{
+	return get_destid_tag(mport, parent_destid, parent_port, hopcount,
+			      RIO_DESTID_LEGACY_TAG);
+}
+
+int rio_dest_is_one_way(struct rio_mport *mport, u16 parent_destid,
+			int parent_port,
+		       int hopcount)
+{
+	return get_destid_tag(mport, parent_destid, parent_port, hopcount,
+			      RIO_DESTID_ONE_WAY_TAG);
+}
+
+int rio_get_return_port(struct rio_mport *mport, u16 parent_destid,
+			int parent_port,
+			int hopcount, u8 *rport)
+{
+	struct rio_net_node *node = NULL;
+
+	node = rio_get_net_node(mport, parent_destid, parent_port, hopcount);
+
+	if (node) {
+		*rport = node->return_port;
+		rio_node_put(node);
+		return 0;
+	}
+	return -ENODEV;
+}
+
+int rio_get_legacy_properties(struct rio_mport *mport, u16 parent_destid,
+			      int parent_port, int hopcount, u8 *lock_hw,
+			      u8 *lut_update)
+{
+	struct rio_net_node *node = NULL;
+
+	node = rio_get_net_node(mport, parent_destid, parent_port, hopcount);
+
+	if (node) {
+		*lock_hw = node->lock_hw;
+		*lut_update = node->lut_update;
+		rio_node_put(node);
+		return 0;
+	}
+	return -ENODEV;
+}
+
+int rio_eval_destid(struct rio_dev *new_rdev)
+{
+	struct rio_dev *rdev = NULL;
+	int rc = 0;
+
+	rcu_read_lock();
+	rdev = radix_tree_lookup(&new_rdev->hport->net.dev_tree,
+				 new_rdev->destid);
+	if (rdev) {
+		pr_warn("RIO: Duplicate DestID %hx found - New device is not added\n"
+			"Possible causes:"
+			"- You have found a BUG in the rio driver\n"
+			"- You made a mistake when defining destid tables?\n",
+			rdev->destid);
+		rc = -EBUSY;
+	}
+	rcu_read_unlock();
+
+	return rc;
+}
+
+/**
+ * rio_get_destid - Get the base/extended device id for a device
+ * @port: RIO master port
+ * @destid: Destination ID of device
+ * @hopcount: Hopcount to device
+ *
+ * Reads the base/extended device id from a device.
+ * Returns success or failure.
+ */
+int rio_get_destid(struct rio_mport *mport, u16 destid,
+		   u8 hopcount, u16 *res_destid)
+{
+	int rc = 0;
+	u32 result;
+
+	rc = rio_mport_read_config_32(mport, destid, hopcount,
+				      RIO_DID_CSR, &result);
+	*res_destid = RIO_GET_DID(mport->sys_size, result);
+	return rc;
+}
+
+/**
+ * rio_read_comptag - Get the comptag for a device
+ * @port: RIO master port
+ * @destid: Destination ID of device
+ * @hopcount: Hopcount to device
+ *
+ * Reads the comptag from a device.
+ * Returns success or failure.
+ */
+int rio_read_comptag(struct rio_mport *mport, u16 destid,
+		     u8 hopcount, u32 *comptag)
+{
+	int rc = 0;
+	u32 regval;
+
+	rc = rio_mport_read_config_32(mport, destid, hopcount,
+				      RIO_COMPONENT_TAG_CSR, &regval);
+	*comptag = regval & 0xffff;
+
+	return rc;
+}
+
+/**
+ * rio_local_set_device_id - Set the base/extended device id for a port
+ * @port: RIO master port
+ * @did: Device ID value to be written
+ *
+ * Writes the base/extended device id from a device.
+ */
+int rio_set_master_destid(struct rio_mport *mport, u16 did)
+{
+	return rio_local_write_config_32(mport, RIO_DID_CSR,
+					 RIO_SET_DID(mport->sys_size, did));
+}
+
+/**
+ * rio_device_has_destid- Test if a device contains a destination ID register
+ * @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.
+ */
+int rio_has_destid(int src_ops,
+		   int dst_ops)
+{
+	u32 mask = RIO_OPS_READ | RIO_OPS_WRITE | RIO_OPS_ATOMIC_TST_SWP |
+		   RIO_OPS_ATOMIC_INC | RIO_OPS_ATOMIC_DEC |
+		   RIO_OPS_ATOMIC_SET | RIO_OPS_ATOMIC_CLR;
+
+	return !!((src_ops | dst_ops) & mask);
+}
+
+/**
+ * rio_set_device_id - Set the base/extended device id for a device
+ * @port: RIO master port
+ * @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.
+ */
+int rio_set_device_id(struct rio_mport *mport, u16 destid, u8 hopcount, u16 did)
+{
+	return rio_mport_write_config_32(mport, destid, hopcount, RIO_DID_CSR,
+					 RIO_SET_DID(mport->sys_size, did));
+}
+
+int rio_assign_destid(struct rio_dev *rdev, struct rio_mport *mport, u16 destid,
+		      int hopcount, u16 *id)
+{
+	int rc = 0;
+	if (rio_is_switch(rdev)) {
+		rdev->destid = rdev->comp_tag;
+	} else {
+		rc = rio_set_device_id(mport, destid, hopcount, *id);
+		if (rc)
+			goto done;
+		rdev->destid = *id;
+	}
+done:
+	return rc;
+}
+
+int rio_add_netid(u16 mport_destid, int net_id, int comptag)
+{
+#if !defined(CONFIG_RAPIDIO_HOTPLUG)
+	if (WARN(system_state != SYSTEM_BOOTING, WARN_MSG))
+		return -EINVAL;
+#endif
+	return __rio_add_netid(mport_destid, net_id, comptag);
+}
+
+#ifdef CONFIG_RAPIDIO_STATIC_DESTID
+EXPORT_SYMBOL(rio_add_netid);
+#endif
+
+int rio_remove_netid(u16 mport_destid, int net_id)
+{
+#if !defined(CONFIG_RAPIDIO_HOTPLUG)
+	if (WARN(system_state != SYSTEM_BOOTING, WARN_MSG))
+		return -EINVAL;
+#endif
+	return __rio_remove_netid(mport_destid, net_id);
+}
+
+#ifdef CONFIG_RAPIDIO_STATIC_DESTID
+EXPORT_SYMBOL(rio_remove_netid);
+#endif
+
+int rio_find_netid(u16 mport_destid, int *net_id)
+{
+	struct rio_net_id *net = NULL;
+
+#if !defined(CONFIG_RAPIDIO_HOTPLUG)
+	if (WARN(system_state != SYSTEM_BOOTING, WARN_MSG))
+		return -EINVAL;
+#endif
+	net = find_rio_net_id(mport_destid, net);
+	if (net) {
+		*net_id = net->net_id;
+		rio_net_put(net);
+		return 0;
+	} else {
+		return -ENODEV;
+	}
+}
+
+#ifdef CONFIG_RAPIDIO_STATIC_DESTID
+EXPORT_SYMBOL(rio_find_netid);
+#endif
+
+/**
+ * rio_add_destid - Add destid lookup entry with default properties
+ *
+ * @mport: Master port from which this device can be reached
+ * @parent_destid: device ID of switch/master port that routes/connects
+ *                 to this device
+ * @parent_port: Switch port that shall be used in parent device to
+ *               reach the device (-1 if parent is master port)
+ * @hopcount: Number of hops, starting from @mport to reach this device
+ * @destid: device ID that shall be assigned to this device
+ * @comtag: device comptag that will be assigned to this device.
+ *
+ * This is a standard device meaning that:
+ * - It is assumed that this device shall be used and that the same route
+ *   shall be used for transmit to device as shall be used for transmit
+ *   from device.
+ * - If the device is a switch, the lut table will be configured with HW locks
+ *   taken. The in-port will be used for return route setup. In single
+ *   enumeration host mode, only the enum host will modify lut setup but
+ *   discovery nodes will still claim the device HW lock while testing
+ *   for enum completed flag. In multiple enumeration domain mode, discovery
+ *   nodes will update the lut when adding domain return paths and they will
+ *   do so with the HW lock taken.
+ */
+
+int rio_add_destid(struct rio_mport *mport,
+		   u16 parent_destid, int parent_port,
+		   int hopcount, u16 destid, u16 comptag)
+{
+	struct rio_dest dest = {0};
+
+#if !defined(CONFIG_RAPIDIO_HOTPLUG)
+	if (WARN(system_state != SYSTEM_BOOTING, WARN_MSG))
+		return -EINVAL;
+#endif
+	RIO_DEF_FLAGS_SET(&dest);
+	dest.destid = destid;
+	dest.comptag = comptag;
+
+	return __rio_add_destid(mport, parent_destid, parent_port,
+				hopcount, &dest);
+}
+
+#ifdef CONFIG_RAPIDIO_STATIC_DESTID
+EXPORT_SYMBOL(rio_add_destid);
+#endif
+/**
+ * rio_block_destid_route - Add destid lookup entry which blocks routing
+ *                          to device trough this path.
+ *
+ * @mport: Master port from which this device can be reached
+ * @parent_destid: device ID of switch/master port that connects
+ *                 to this device
+ * @parent_port: Switch port that shall is used in parent device to
+ *               reach the device.
+ * @hopcount: Number of hops, starting from @mport to reach this device
+ * @destid: device ID
+ * @comtag: device comptag
+ *
+ * When blocking a route:
+ *   It is assumed that this device shall not be used/or at least not
+ *   be reachable trough this path. The device ID will not be added to
+ *   the @parent_port in parent switch device lut.
+ * NOTE:
+ *   It is also assumed that the parent device is a switch and not the
+ *   @mport itself.
+ *   It is an error to add the first switch in a @mport net as a blocked
+ *   device. If the master port shall not be used then the master port
+ *   /first switch should not be enabled in the first place.
+ */
+int rio_block_destid_route(struct rio_mport *mport,
+			   u16 parent_destid, int parent_port,
+			   int hopcount, u16 destid, u16 comptag)
+{
+	struct rio_dest dest = {0};
+
+#if !defined(CONFIG_RAPIDIO_HOTPLUG)
+	if (WARN(system_state != SYSTEM_BOOTING, WARN_MSG))
+		return -EINVAL;
+#endif
+	RIO_DEF_FLAGS_SET(&dest);
+	RIO_FLAG_ADD(&dest, RIO_REDUNDANT_ENABLE);
+	dest.destid = destid;
+	dest.comptag = comptag;
+
+	return __rio_add_destid(mport, parent_destid, parent_port,
+				hopcount, &dest);
+}
+
+#ifdef CONFIG_RAPIDIO_STATIC_DESTID
+EXPORT_SYMBOL(rio_block_destid_route);
+#endif
+
+/**
+ * rio_split_destid_route - Add destid lookup entry with separat transmit
+ *                          and return paths.
+ *
+ * @mport: Master port from which this device can be reached
+ * @parent_destid: device ID of switch/master port that routes/connects
+ *                 to this device
+ * @parent_port: Switch port that shall be used in parent device to
+ *               reach the device.
+ * @hopcount: Number of hops, starting from @mport to reach this device
+ * @destid: device ID that shall be assigned to this device
+ * @comtag: device comptag that will be assigned to this device.
+ * @return_port: port used in device for routing traffic back to parent device
+ *
+ * Split routes:
+ *   If you have redundant connections between switches you may use
+ *   use split routes to prevent network loops. In that case links are
+ *   used in one-way mode and lut tables are setup so that one link,
+ *   the @parent_port, is used for all traffic from the parent device
+ *   to the @destid device, while all traffic from the @destid device to
+ *   the parent device will use the @return_port.
+ *
+ *   All other properties, e.g. lut updates, hw_locking, etc. is handled
+ *   in the same way as it is for standard devices.
+ *
+ * NOTE:
+ * Adding a split route is only supported when both parent and destid
+ * are switches.
+ */
+int rio_split_destid_route(struct rio_mport *mport,
+			   u16 parent_destid, int parent_port,
+			   int hopcount, u16 destid, u16 comptag,
+			   u8 return_port)
+{
+	struct rio_dest dest = {0};
+
+#if !defined(CONFIG_RAPIDIO_HOTPLUG)
+	if (WARN(system_state != SYSTEM_BOOTING, WARN_MSG))
+		return -EINVAL;
+#endif
+	RIO_DEF_FLAGS_SET(&dest);
+	RIO_FLAG_ADD(&dest, RIO_ONE_WAY_ENABLE);
+	dest.destid = destid;
+	dest.comptag = comptag;
+	dest.return_port = return_port;
+
+	return __rio_add_destid(mport, parent_destid, parent_port,
+				hopcount, &dest);
+}
+
+#ifdef CONFIG_RAPIDIO_STATIC_DESTID
+EXPORT_SYMBOL(rio_split_destid_route);
+#endif
+/**
+ * rio_legacy_destid_route - Add destid lookup entry for devices
+ *                           reciding in domains handled by non-linux
+ *                           hosts.
+ *
+ * @mport: Master port from which this device can be reached
+ * @parent_destid: device ID of switch/master port that routes/connects
+ *                 to this device
+ * @parent_port: Switch port that shall be used in parent device to
+ *               reach the device.
+ * @hopcount: Number of hops, starting from @mport to reach this device
+ * @destid: device ID
+ * @comtag: device comptag
+ * @lock_hw: HW locks may be taken on device
+ * @lut_update: Device lut table may be updated
+ *
+ * Split routes:
+ *   ???
+ *
+ * NOTE:
+ *   ???
+ */
+int rio_legacy_destid_route(struct rio_mport *mport,
+			    u16 parent_destid, int parent_port,
+			    int hopcount, u16 destid, u16 comptag,
+			    u8 lock_hw, u8 lut_update)
+{
+	struct rio_dest dest = {0};
+
+#if !defined(CONFIG_RAPIDIO_HOTPLUG)
+	if (WARN(system_state != SYSTEM_BOOTING, WARN_MSG))
+		return -EINVAL;
+#endif
+	if (lock_hw)
+		RIO_FLAG_ADD(&dest, RIO_HW_LOCK_ENABLE);
+	if (lut_update)
+		RIO_FLAG_ADD(&dest, RIO_UPDATE_LUT_ENABLE);
+
+	RIO_FLAG_ADD(&dest, RIO_LEGACY_ENABLE);
+
+	dest.destid = destid;
+	dest.comptag = comptag;
+
+	return __rio_add_destid(mport, parent_destid, parent_port,
+				hopcount, &dest);
+}
+
+#ifdef CONFIG_RAPIDIO_STATIC_DESTID
+EXPORT_SYMBOL(rio_legacy_destid_route);
+#endif
+
+void rio_release_destid(struct rio_mport *mport, u16 parent_destid,
+			int parent_port, int hopcount)
+{
+#if !defined(CONFIG_RAPIDIO_HOTPLUG)
+	if (WARN(system_state != SYSTEM_BOOTING, WARN_MSG))
+		return;
+#endif
+	__rio_release_destid(mport, parent_destid, parent_port,
+			     hopcount);
+}
+
+#ifdef CONFIG_RAPIDIO_STATIC_DESTID
+EXPORT_SYMBOL(rio_release_destid);
+#endif
+
+#ifdef CONFIG_RAPIDIO_STATIC_DESTID
+int rio_release_node_table(struct rio_mport *mport)
+{
+#if !defined(CONFIG_RAPIDIO_HOTPLUG)
+	if (WARN(system_state != SYSTEM_BOOTING, WARN_MSG))
+		return -EINVAL;
+#endif
+
+	return __rio_release_node_table(mport);
+}
+EXPORT_SYMBOL(rio_release_node_table);
+#endif
+
+#if defined(CONFIG_RAPIDIO_HOTPLUG) || defined(CONFIG_RAPIDIO_STATIC_DESTID)
+
+/**
+ * debug helper
+ */
+ssize_t rio_net_nodes_show(struct rio_mport *mport, char *buf)
+{
+	return __rio_net_nodes_show(mport, buf);
+}
+EXPORT_SYMBOL(rio_net_nodes_show);
+#endif
diff --git a/drivers/rapidio/rio-destid.h b/drivers/rapidio/rio-destid.h
new file mode 100644
index 0000000..caa0b9f
--- /dev/null
+++ b/drivers/rapidio/rio-destid.h
@@ -0,0 +1,85 @@
+#ifndef RIO_DESTID_H
+#define RIO_DESTID_H
+
+/*
+ * RapidIO interconnect services
+ *
+ * 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>
+
+extern int rio_pin_destid(struct rio_mport *mport, u16 parent_destid,
+			  int parent_port, int hopcount);
+extern int rio_unlock_destid(struct rio_mport *mport, u16 parent_destid,
+			     int parent_port, int hopcount);
+
+extern int rio_set_device_id(struct rio_mport *mport, u16 destid,
+			     u8 hopcount, u16 did);
+extern int rio_assign_destid(struct rio_dev *rdev, struct rio_mport *port,
+			     u16 destid, int hopcount, u16 *id);
+extern int rio_get_next_destid(struct rio_mport *mport, u16 parent_destid,
+			       int port_num, u8 hopcount,
+			       u16 *id, int *comptag);
+extern int rio_get_next_netid(u16 host_deviceid, int *net_id, int *comptag);
+
+extern int rio_pin_netid(u16 host_deviceid, int net_id);
+extern int rio_unlock_netid(u16 host_deviceid, int net_id);
+
+extern int rio_dest_is_redundant(struct rio_mport *mport, u16 parent_destid,
+				 int parent_port, int hopcount);
+extern int rio_dest_is_legacy(struct rio_mport *mport, u16 parent_destid,
+			      int parent_port, int hopcount);
+extern int rio_dest_is_one_way(struct rio_mport *mport, u16 parent_destid,
+			       int parent_port, int hopcount);
+
+extern int rio_eval_destid(struct rio_dev *new_rdev);
+extern int rio_get_destid(struct rio_mport *mport, u16 destid, u8 hopcount,
+			  u16 *res_destid);
+extern int rio_read_comptag(struct rio_mport *mport, u16 destid, u8 hopcount,
+			    u32 *comptag);
+extern int rio_set_master_destid(struct rio_mport *mport, u16 did);
+extern int rio_has_destid(int src_ops, int dst_ops);
+extern int rio_destid_sysfs_init(struct rio_mport *mport);
+extern int rio_get_return_port(struct rio_mport *mport, u16 parent_destid,
+			       int parent_port, int hopcount, u8 *rport);
+extern int rio_get_legacy_properties(struct rio_mport *mport,
+				     u16 parent_destid, int parent_port,
+				     int hopcount, u8 *lock_hw,
+				     u8 *lut_update);
+extern int rio_destid_get_parent_port(struct rio_mport *mport,
+				      u16 destid, u8 *port);
+
+#if !defined(CONFIG_RAPIDIO_STATIC_DESTID)
+
+extern int rio_add_netid(u16 mport_destid, int net_id, int comptag);
+
+extern int rio_add_destid(struct rio_mport *mport,
+			  u16 parent_destid, int parent_port,
+			  int hopcount, u16 destid, u16 comptag);
+extern int rio_block_destid_route(struct rio_mport *mport,
+				  u16 parent_destid, int parent_port,
+				  int hopcount, u16 destid, u16 comptag);
+extern int rio_split_destid_route(struct rio_mport *mport,
+				  u16 parent_destid, int parent_port,
+				  int hopcount, u16 destid, u16 comptag,
+				  u8 return_port);
+extern int rio_legacy_destid_route(struct rio_mport *mport,
+				   u16 parent_destid, int parent_port,
+				   int hopcount, u16 destid, u16 comptag,
+				   u8 lock_hw, u8 lut_update);
+extern void rio_release_destid(struct rio_mport *mport, u16 parent_destid,
+			       int parent_port, int hopcount);
+#else
+
+extern int rio_lookup_static_route(struct rio_dev *rdev, u16 sw_dest,
+				   u8 *route_port);
+
+#endif
+
+#endif
diff --git a/drivers/rapidio/rio-dio.c b/drivers/rapidio/rio-dio.c
new file mode 100644
index 0000000..272fc41
--- /dev/null
+++ b/drivers/rapidio/rio-dio.c
@@ -0,0 +1,872 @@
+/*
+ * RapidIO Direct I/O driver
+ *
+ * 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/gfp.h>
+#include <linux/export.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/rio_dio.h>
+
+static LIST_HEAD(io_wins);
+static LIST_HEAD(dio_channels);
+static DEFINE_SPINLOCK(rio_dio_lock);
+
+#if defined(CONFIG_RAPIDIO_DIO_DMA)
+
+struct rio_dio_dma {
+	struct list_head node;
+	struct dma_chan *txdmachan;
+	enum dma_ctrl_flags flags;
+	struct dma_device *txdmadev;
+	struct kref kref;
+};
+
+/**
+ * __dma_register
+ *
+ * Allocate and initialize a direct I/O channel for
+ * DMA transfers. Initialize reference counting
+ * and ad  channel to rio_dio global channel
+ * list.
+ *
+ * Returns: On success - Pointer to I/O channel data
+ *          On failure - NULL
+ */
+static struct rio_dio_dma *__dma_register(void)
+{
+	dma_cap_mask_t mask;
+	unsigned long flags;
+	struct rio_dio_dma *dma = kzalloc(sizeof(*dma),
+					  GFP_KERNEL);
+	if (!dma)
+		return NULL;
+
+	dma_cap_zero(mask);
+	dma_cap_set(DMA_MEMCPY, mask);
+	dma->txdmachan = dma_request_channel(mask, NULL, NULL);
+	if (!dma->txdmachan) {
+		kfree(dma);
+		return NULL;
+	}
+	dma->flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
+	dma->txdmadev = dma->txdmachan->device;
+	kref_init(&dma->kref);
+	spin_lock_irqsave(&rio_dio_lock, flags);
+	list_add_tail(&dma->node, &dio_channels);
+	spin_unlock_irqrestore(&rio_dio_lock, flags);
+	dev_dbg(dma->txdmadev->dev,
+		"rio_dio Register DMA channel\n");
+	return dma;
+}
+/**
+ * __rio_dio_method_setup
+ *
+ * @dio_channel: RIO direct I/O method data.
+ *
+ * DMA version of generic method
+ *
+ * Returns: On success - 0
+ *          On failure != 0
+ */
+static int __rio_dio_method_setup(void **dio_channel)
+{
+	*dio_channel = __dma_register();
+	if (!*dio_channel)
+		return -EFAULT;
+	return 0;
+}
+
+/**
+ * __dma_get
+ *
+ * @dio_dma: RIO direct I/O method data.
+ *
+ * Increment reference count if @dio_dma is a valid
+ * method data pointer, i.e. if it is found in the
+ * rio_dio global channel list.
+ *
+ * Returns: On success - @dio_dma
+ *          On failure - NULL
+ */
+static inline struct rio_dio_dma *__dma_get(struct rio_dio_dma *dio_dma)
+{
+	struct rio_dio_dma *entry, *next, *ret = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&rio_dio_lock, flags);
+	list_for_each_entry_safe(entry, next, &dio_channels, node) {
+		if (dio_dma && dio_dma == entry) {
+			kref_get(&dio_dma->kref);
+			ret = entry;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&rio_dio_lock, flags);
+	return ret;
+}
+
+/**
+ * __rio_dio_method_get
+ *
+ * @dio_channel: RIO direct I/O method data.
+ *
+ * DMA version of generic method
+ *
+ * Returns: On success - @dio_channel
+ *          On failure - NULL
+ */
+static void *__rio_dio_method_get(void *dio_channel)
+{
+	struct rio_dio_dma *dio_dma = (struct rio_dio_dma *)dio_channel;
+
+	return __dma_get(dio_dma);
+}
+/**
+ * __dma_release
+ *
+ * @kref:
+ *
+ * Remove dio_channel from the rio_dio global channel list.
+ * Release DMA channel and free direct I/O channel data
+ *
+ */
+
+static void __dma_release(struct kref *kref)
+{
+	struct rio_dio_dma *dio_dma = container_of(kref,
+						   struct rio_dio_dma, kref);
+	unsigned long flags;
+
+	spin_lock_irqsave(&rio_dio_lock, flags);
+	list_del(&dio_dma->node);
+	spin_unlock_irqrestore(&rio_dio_lock, flags);
+
+	dev_dbg(dio_dma->txdmadev->dev,
+		"rio_dio Release DMA channel\n");
+	dma_release_channel(dio_dma->txdmachan);
+	kfree(dio_dma);
+}
+
+/**
+ * __rio_dio_method_put
+ *
+ * @dio_channel: RIO direct I/O method data.
+ *
+ * DMA version of generic method
+ *
+ */
+
+static void __rio_dio_method_put(void *dio_channel)
+{
+	struct rio_dio_dma *dio_dma = (struct rio_dio_dma *)dio_channel;
+
+	if (dio_dma)
+		kref_put(&dio_dma->kref, __dma_release);
+}
+
+/**
+ * __dma_callback
+ *
+ * @completion: DMA semaphore
+ *
+ * Used by the DMA driver to signal that a transfer is done
+ *
+ */
+
+static void __dma_callback(void *completion)
+{
+	complete(completion);
+}
+/**
+ * __dma_cpy
+ *
+ * @dio_dma: RIO direct I/O method data.
+ * @phys: Physical (SRIO device) read/write address
+ * @buf: Pointer from/to where data shall be read/written
+ * @len: Number of bytes to read/write
+ * @dir: Transfer direction to/from SRIO device
+ *
+ * Setup DMA transfer and wait for it to finish
+ * There may be multiple threads running this function
+ * in parallel for a single channel, and multiple channels
+ * may be used in parallel.
+ *
+ * Returns: On success - 0
+ *          On failure != 0
+ */
+
+static int __dma_cpy(struct rio_dio_dma *dio_dma,
+		     resource_size_t phys,
+		     void *buf, u32 len,
+		     enum dma_data_direction dir)
+{
+	struct dma_async_tx_descriptor *tx;
+	struct dma_slave_config config;
+	dma_addr_t dma_src, dma_dst, dma_map;
+	dma_cookie_t cookie;
+	unsigned long tmo = msecs_to_jiffies(3000);
+	struct completion cmp;
+	enum dma_status status = DMA_ERROR;
+	enum dma_ctrl_flags eflag;
+	u8 align;
+	char *message = NULL;
+
+	if (!__rio_dio_method_get(dio_dma))
+		return -EFAULT;
+
+	align = dio_dma->txdmadev->copy_align;
+	if (1 << align > len) {
+		message = "DMA Buffer alignment error";
+		goto out_err;
+	}
+	config.direction = dir;
+
+	if (dir == DMA_TO_DEVICE) {
+		config.dst_addr_width = 16;
+		config.dst_maxburst = 16;
+		dma_map = dma_src = dma_map_single(dio_dma->txdmadev->dev,
+						   buf, len, dir);
+		dma_dst = (dma_addr_t)phys;
+		eflag = DMA_COMPL_SKIP_DEST_UNMAP;
+	} else {
+		config.src_addr_width = 16;
+		config.src_maxburst = 16;
+		dma_src = (dma_addr_t)phys;
+		dma_map = dma_dst = dma_map_single(dio_dma->txdmadev->dev,
+						   buf, len, dir);
+		eflag = DMA_COMPL_SKIP_SRC_UNMAP;
+	}
+	dmaengine_slave_config(dio_dma->txdmachan, &config);
+
+	tx = dio_dma->txdmadev->device_prep_dma_memcpy(dio_dma->txdmachan,
+						       dma_dst,
+						       dma_src,
+						       len,
+						       dio_dma->flags | eflag);
+	if (!tx) {
+		message = "DMA channel prepare error";
+		goto out_prep;
+	}
+	init_completion(&cmp);
+	tx->callback = __dma_callback;
+	tx->callback_param = &cmp;
+	cookie = tx->tx_submit(tx);
+	if (dma_submit_error(cookie)) {
+		message = "DMA channel submit error";
+		goto out_submit;
+	}
+	dma_async_issue_pending(dio_dma->txdmachan);
+	tmo = wait_for_completion_timeout(&cmp, tmo);
+	status = dma_async_is_tx_complete(dio_dma->txdmachan,
+					  cookie, NULL, NULL);
+	if (!tmo) {
+		message = "DMA transfer timeout";
+		status = -ETIME;
+		dmaengine_terminate_all(dio_dma->txdmachan);
+		goto out_err;
+	}
+	goto out;
+
+out_prep:
+out_submit:
+	dma_unmap_single(dio_dma->txdmadev->dev, dma_map, len, dir);
+
+out_err:
+	dev_info(dio_dma->txdmadev->dev, "%s\n", message);
+
+out:
+	__rio_dio_method_put(dio_dma);
+	if (status != DMA_SUCCESS)
+		return status == -ETIME ? status : -EFAULT;
+	return 0;
+
+}
+/**
+ * __rio_dio
+ *
+ * @dio_channel: RIO direct I/O method data.
+ * @res: RapidIO mapping region phys and virt start address
+ * @buf: Pointer from/to where data shall be read/written
+ * @len: Number of bytes to read/write
+ * @dir: Transfer direction to/from SRIO device
+ *
+ * DMA version of generic method
+ *
+ */
+
+static inline int __rio_dio(void *dio_channel,
+			    struct rio_map_addr *res,
+			    void *buf,
+			    u32 len,
+			    enum dma_data_direction dir)
+{
+	struct rio_dio_dma *dio_dma = (struct rio_dio_dma *)dio_channel;
+
+	return __dma_cpy(dio_dma, (resource_size_t)res->phys,
+			 buf, len, dir);
+}
+
+#else
+
+/**
+ * __rio_dio_method_setup
+ *
+ * @dio_channel: NULL.
+ *
+ * memcpy version of generic method
+ *
+ * Returns: 0
+ */
+
+static int __rio_dio_method_setup(void **dio_channel)
+{
+	*dio_channel = NULL;
+	return 0;
+}
+/**
+ * __rio_dio_method_get
+ *
+ * @dio_channel: NULL
+ *
+ * memcpy version of generic method
+ *
+ * Returns: NULL
+ */
+
+static void *__rio_dio_method_get(void *dio_channel)
+{
+	return NULL;
+}
+/**
+ * __rio_dio_method_put
+ *
+ * @dio_channel: NULL
+ *
+ * memcpy version of generic method
+ *
+ */
+
+static void __rio_dio_method_put(void *dio_channel)
+{
+}
+/**
+ * __rio_dio
+ *
+ * @dio_channel: RIO direct I/O method data.
+ * @res: RapidIO mapping region phys and virt start address
+ * @buf: Pointer from/to where data shall be read/written
+ * @len: Number of bytes to read/write
+ * @dir: Transfer direction to/from SRIO device
+ *
+ * memcpy version of generic method
+ *
+ */
+
+static inline int __rio_dio(void *dio_channel,
+			    struct rio_map_addr *res,
+			    void *buf,
+			    u32 len,
+			    enum dma_data_direction dir)
+{
+	u8 *src, *dst;
+	int rc = 0;
+
+	if (dir == DMA_FROM_DEVICE) {
+		int size = len;
+
+		dst = (u8 *)buf;
+		src = (u8 *)res->va;
+
+		while (size > 0 && !rc) {
+			int tsize = (size > 3 ? 4 : (size < 2 ? 1 : 2));
+			switch (tsize) {
+			case 1:
+				rc = rio_in_8(dst, (u8 __iomem *)src);
+				break;
+			case 2:
+				rc = rio_in_be16((u16 *)dst,
+						 (u16 __iomem *)src);
+				break;
+			case 4:
+				rc = rio_in_be32((u32 *)dst,
+						 (u32 __iomem *)src);
+				break;
+			default:
+				pr_warn("(%s): illegal read tsize %d\n",
+					__func__, tsize);
+				rc = -EINVAL;
+			}
+			src += tsize;
+			dst += tsize;
+			size -= tsize;
+		}
+	} else {
+		dst = (u8 *)res->va;
+		src = (u8 *)buf;
+		memcpy(dst, src, len);
+	}
+
+	return rc;
+}
+
+#endif
+/**
+ * __rio_dio_release_region
+ *
+ * @kref:
+ *
+ * Remove @io_win from the rio_dio global io window list.
+ * Give up reference to @dio_channel
+ * Free outbound RapidIO bus region and io_win data.
+ *
+ */
+
+static void __rio_dio_release_region(struct kref *kref)
+{
+	struct rio_dio_win *io_win = container_of(kref,
+						 struct rio_dio_win,
+						 kref);
+	unsigned long flags;
+
+	spin_lock_irqsave(&rio_dio_lock, flags);
+	list_del(&io_win->node);
+	spin_unlock_irqrestore(&rio_dio_lock, flags);
+
+	pr_debug("RIO: Return ATMU window %u\n", io_win->outb_win);
+	rio_release_outb_region(io_win->rdev->hport, io_win->outb_win);
+	__rio_dio_method_put(io_win->dio_channel);
+
+	kfree(io_win);
+}
+/**
+ * __rio_dio_region_get
+ *
+ * @io_win: RIO I/O window data.
+ *
+ * Increment reference count if @io_win is a valid
+ * pointer, i.e. if it is found in the
+ * rio_dio global I/O window list.
+ *
+ * Returns: On success - @io_win
+ *          On failure - NULL
+ */
+
+static inline
+struct rio_dio_win *__rio_dio_region_get(struct rio_dio_win *io_win)
+{
+	struct rio_dio_win *entry, *next, *ret = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&rio_dio_lock, flags);
+	list_for_each_entry_safe(entry, next, &io_wins, node) {
+		if (io_win == entry) {
+			kref_get(&io_win->kref);
+			ret = entry;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&rio_dio_lock, flags);
+	return ret;
+}
+
+/**
+ * __rio_dio_write
+ *
+ * @io_win: RIO I/O window data.
+ * @offset: Offset into device direct I/O memory space
+ * @buf: Pointer from where data shall be read
+ * @len: Number of bytes to write
+ *
+ * Create mapping from local iomem to rio space
+ * and write data to device.
+ *
+ * Returns: On success - 0
+ *          On failure != 0
+ *
+ */
+
+static int __rio_dio_write(struct rio_dio_win *io_win,
+			   u32 offset, void *buf, u32 mflags, u32 len)
+{
+	struct rio_map_addr res;
+	u8 *dst;
+	int rc;
+
+	if (!__rio_dio_region_get(io_win))
+		return -ENODEV;
+
+	rc = rio_map_outb_mem(io_win->rdev->hport,
+			      io_win->outb_win,
+			      io_win->rdev->destid,
+			      offset,
+			      mflags,
+			      &res);
+	if (rc)
+		goto out;
+
+	dst = (u8 *)res.va;
+	switch (len) {
+	case 1:
+		out_8(dst, *((u8 *)buf));
+		break;
+	case 2:
+		out_be16((u16 *)dst, *((u16 *)buf));
+		break;
+	default:
+			rc = __rio_dio(io_win->dio_channel,
+				       &res,
+				       buf,
+				       len,
+				       DMA_TO_DEVICE);
+	}
+out:
+	rio_dio_region_put(io_win);
+	return rc;
+}
+
+
+/**
+ * __rio_dio_read
+ *
+ * @io_win: RIO I/O window data.
+ * @offset: Offset into device direct I/O memory space
+ * @buf: Pointer to where data shall be stored
+ * @len: Number of bytes to read
+ *
+ * Create mapping from local iomem to rio space
+ * and read data from device.
+ *
+ * Returns: On success - 0
+ *          On failure != 0
+ *
+ */
+
+static int __rio_dio_read(struct rio_dio_win *io_win,
+			  u32 offset, void *buf, u32 mflags, u32 len)
+{
+	struct rio_map_addr res;
+	int rc;
+
+	if (!__rio_dio_region_get(io_win))
+		return -ENODEV;
+
+	rc = rio_map_outb_mem(io_win->rdev->hport,
+			      io_win->outb_win,
+			      io_win->rdev->destid,
+			      offset,
+			      mflags,
+			      &res);
+
+	if (rc)
+		goto out;
+
+	switch (len) {
+	case 1:
+		rc = rio_in_8((u8 *)buf, res.va);
+		break;
+	case 2:
+		rc = rio_in_be16((u16 *)buf, res.va);
+		break;
+	default:
+		rc = __rio_dio(io_win->dio_channel,
+			       &res,
+			       buf,
+			       len,
+			       DMA_FROM_DEVICE);
+	}
+out:
+	rio_dio_region_put(io_win);
+	return rc;
+}
+#define RIO_DIO_8_BAD 0
+#define RIO_DIO_16_BAD (offset & 1)
+#define RIO_DIO_32_BAD (offset & 3)
+#define RIO_DIO_BUFF_BAD (len > io_win->win_size)
+
+/**
+ * RIO_DIO_READ - Generate rio_dio_read_* functions
+ *
+ * @size: Size of direct I/O space read (8, 16, 32 bit)
+ * @type: C type of value argument
+ * @len: Length of direct I/O space read in bytes
+ *
+ * Generates rio_dio_read_* functions used for direct I/O access
+ * to end-point device.
+ *
+ * Returns: 0 on success and != 0 on failure
+ *
+ * NOTE: With regard to @io_win, these functions are not re-entrant.
+ * It is assumed that the user provides proper synchronization
+ * methods assuring that calls, pertaining to the same @io_win,
+ * are serialized.
+ *
+ */
+#define RIO_DIO_READ(size, type, len)					\
+	int rio_dio_read_##size						\
+	(struct rio_dio_win *io_win, u32 offset, u32 mflags, type *value) \
+	{								\
+		int rc;							\
+		u32 dst;						\
+									\
+		if (RIO_DIO_##size##_BAD)				\
+			return RIO_BAD_SIZE;				\
+									\
+		rc = __rio_dio_read(io_win, offset, &dst, mflags, len);	\
+		*value = (type)dst;					\
+		return rc;						\
+	}
+
+/**
+ * RIO_DIO_WRITE - Generate rio_dio_write_* functions
+ *
+ * @size: Size of direct I/O space write (8, 16, 32 bits)
+ * @type: C type of value argument
+ * @len: Length of direct I/O space write in bytes
+ *
+ * Generates rio_dio_write_* functions used for direct I/O access
+ * to end-point device.
+ *
+ * Returns: 0 on success and != 0 on failure
+ *
+ * NOTE: With regard to @io_win, these function are not re-entrant.
+ * It is assumed that the user provides proper synchronization
+ * methods assuring that calls, pertaining to the same @io_win,
+ * are serialized.
+ *
+ */
+#define RIO_DIO_WRITE(size, type, len)					\
+	int rio_dio_write_##size					\
+	(struct rio_dio_win *io_win, u32 offset, u32 mflags, type *src)	\
+	{								\
+		int rc;							\
+									\
+		if (RIO_DIO_##size##_BAD)				\
+			return RIO_BAD_SIZE;				\
+									\
+		rc = __rio_dio_write(io_win, offset, src, mflags, len);	\
+		return rc;						\
+	}
+
+RIO_DIO_READ(8, u8, 1)
+EXPORT_SYMBOL_GPL(rio_dio_read_8);
+RIO_DIO_READ(16, u16, 2)
+EXPORT_SYMBOL_GPL(rio_dio_read_16);
+RIO_DIO_READ(32, u32, 4)
+EXPORT_SYMBOL_GPL(rio_dio_read_32);
+RIO_DIO_WRITE(8, u8, 1)
+EXPORT_SYMBOL_GPL(rio_dio_write_8);
+RIO_DIO_WRITE(16, u16, 2)
+EXPORT_SYMBOL_GPL(rio_dio_write_16);
+RIO_DIO_WRITE(32, u32, 4)
+EXPORT_SYMBOL_GPL(rio_dio_write_32);
+
+/**
+ * rio_dio_read_buff
+ *
+ * @io_win: RIO I/O window data.
+ * @offset: Offset into device direct I/O memory space
+ * @dst: Pointer where read data will be stored
+ * @len: Length of direct I/O space read in bytes
+ *
+ * used for direct I/O access
+ * to end-point device.
+ *
+ * Returns: 0 on success and != 0 on failure
+ *
+ * NOTE: With regard to @io_win, this function is not re-entrant.
+ * It is assumed that the user provides proper synchronization
+ * methods assuring that calls, pertaining to the same @io_win,
+ * are serialized.
+ *
+ */
+int rio_dio_read_buff(struct rio_dio_win *io_win, u32 offset,
+		      u8 *dst, u32 mflags, u32 len)
+{
+	if (RIO_DIO_BUFF_BAD)
+		return RIO_BAD_SIZE;
+
+	return __rio_dio_read(io_win, offset, dst, mflags, len);
+}
+EXPORT_SYMBOL_GPL(rio_dio_read_buff);
+/**
+ * rio_dio_write_buff
+ *
+ * @io_win: RIO I/O window data.
+ * @offset: Offset into device direct I/O memory space
+ * @dst: Data to be written
+ * @len: Length of direct I/O space read in bytes
+ *
+ * used for direct I/O access
+ * to end-point device.
+ *
+ * Returns: 0 on success and != 0 on failure
+ *
+ * NOTE: With regard to @io_win, this function is not re-entrant.
+ * It is assumed that the user provides proper synchronization
+ * methods assuring that calls, pertaining to the same @io_win,
+ * are serialized.
+ *
+ */
+int rio_dio_write_buff(struct rio_dio_win *io_win, u32 offset,
+		       u8 *src, u32 mflags, u32 len)
+{
+	if (RIO_DIO_BUFF_BAD)
+		return RIO_BAD_SIZE;
+
+	return __rio_dio_write(io_win, offset, src, mflags, len);
+}
+EXPORT_SYMBOL_GPL(rio_dio_write_buff);
+
+int rio_dio_const_win(struct rio_dio_win *io_win,
+		      void *buf, u32 len,
+		      enum dma_data_direction dir,
+		      struct rio_map_addr *res)
+{
+	int rc;
+
+	if (!__rio_dio_region_get(io_win))
+		return -ENODEV;
+
+	rc = __rio_dio(io_win->dio_channel,
+		       res,
+		       buf,
+		       len,
+		       dir);
+
+	rio_dio_region_put(io_win);
+	return rc;
+}
+EXPORT_SYMBOL_GPL(rio_dio_const_win);
+
+/**
+ * rio_dio_req_region
+ *
+ * @dio_channel: Direct I/O mode, must be allocated prior to
+ *            this call using rio_dio_method_setup().
+ * @rdev: RIO device
+ * @size: Size of ATMU window
+ * @transaction_type: Flags for mapping. 0 for using default
+ *                     (NREAD/NWRITE) transaction type.
+ *
+ * Allocate and initialize a RIO direct I/O ATMU window.
+ * Reserves an outbound region in the RapidIO bus address space.
+ * The reserved region may be used to create mappings from local
+ * iomem to rio space.
+ *
+ * Returns: On success - Pointer to RIO I/O window data.
+ *          On failure - NULL
+ *
+ * NOTE: Once you have called this function, use rio_dio_region_put()
+ *       to give up your reference instead of freeing the
+ *       RIO I/O window data structure directly.
+ */
+struct rio_dio_win *rio_dio_req_region(void *dio_channel,
+				       struct rio_dev *rdev,
+				       resource_size_t size,
+				       u32 transaction_type)
+{
+	unsigned long flags;
+	struct rio_dio_win *io_win = kzalloc(sizeof(*io_win), GFP_KERNEL);
+	char *message = NULL;
+
+	if (!io_win) {
+		message = "Out of memory";
+		goto out_err;
+	}
+	io_win->rdev = rdev;
+	io_win->dio_channel = __rio_dio_method_get(dio_channel);
+	io_win->win_size = size;
+	/* Setup outbound ATMU I/O window
+	 */
+	if (rio_req_outb_region(rdev->hport, size, rdev->dev.init_name,
+				transaction_type, &io_win->outb_win)) {
+		message = "Mapping outbound ATMU window failed";
+		goto out_map;
+	}
+	kref_init(&io_win->kref);
+	spin_lock_irqsave(&rio_dio_lock, flags);
+	list_add_tail(&io_win->node, &io_wins);
+	spin_unlock_irqrestore(&rio_dio_lock, flags);
+	pr_debug("RIO: Alloc ATMU window %u\n", io_win->outb_win);
+	goto out;
+
+out_map:
+	__rio_dio_method_put(dio_channel);
+	kfree(io_win);
+	io_win = NULL;
+out_err:
+	pr_warn("RIO: %s\n", message);
+out:
+	return io_win;
+}
+EXPORT_SYMBOL_GPL(rio_dio_req_region);
+
+/**
+ * rio_dio_region_put - decrement reference count.
+ *
+ * @io_win: RIO I/O window in question.
+ *
+ * Frees outbound RapidIO bus region and io_win data
+ * when the reference count drops to zero
+ */
+
+void rio_dio_region_put(struct rio_dio_win *io_win)
+{
+	if (io_win)
+		kref_put(&io_win->kref, __rio_dio_release_region);
+}
+EXPORT_SYMBOL_GPL(rio_dio_region_put);
+
+/**
+ * rio_dio_method_setup
+ *
+ * @dio_channel: RIO direct I/O method data.
+ *
+ * Allocate and initialize a direct I/O channel.
+ * The I/O method used for RapidIO transfers > 4 bytes
+ * is configurable at kernel build time. If DMA is choosen
+ * a successful method setup implies that a DMA channel has
+ * been allocated. The default option is to use memcpy, in
+ * which case not particular setup is required and the method
+ * data ptr will be set to NULL.
+ * It is, regardless of selected method, entirely possible to
+ * use the same @dio_channel in multiple I/O windows.
+ *
+ * RapidIO transfers <= 4 bytes will use the standar io.h in_*
+ * and out_* access functions, this is not configurable.
+ *
+ * Returns: On success - 0
+ *          On failure != 0
+ *
+ * NOTE: Once you have called this function, use rio_dio_method_put()
+ *       to give up your reference instead of freeing the
+ *       RIO direct I/O method data structure directly.
+ */
+
+int rio_dio_method_setup(void **dio_channel)
+{
+	return __rio_dio_method_setup(dio_channel);
+}
+EXPORT_SYMBOL_GPL(rio_dio_method_setup);
+
+/**
+ * rio_dio_method_put - decrement reference count.
+ *
+ * @dio_channel: RIO direct I/O channel in question.
+ *
+ * Frees direct I/O channel when the reference count
+ * drops to zero
+ */
+
+void rio_dio_method_put(void *dio_channel)
+{
+	__rio_dio_method_put(dio_channel);
+}
+EXPORT_SYMBOL_GPL(rio_dio_method_put);
diff --git a/drivers/rapidio/rio-hotplug.c b/drivers/rapidio/rio-hotplug.c
new file mode 100644
index 0000000..14115d0
--- /dev/null
+++ b/drivers/rapidio/rio-hotplug.c
@@ -0,0 +1,138 @@
+/*
+ * RapidIO hotplug support
+ *
+ * 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.
+ */
+
+/* #define DEBUG */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+
+#include <linux/delay.h>
+#include <linux/dma-mapping.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 <linux/jiffies.h>
+#include <linux/slab.h>
+
+#include "rio.h"
+#include "rio-hotplug.h"
+
+
+#ifdef CONFIG_RAPIDIO_HOTPLUG
+/**
+ * Hotplug API internal to RIO driver - pw-event driven.
+ */
+/**
+ * store_new_id - sysfs frontend to rio_add_dynid()
+ * @driver: target device driver
+ * @buf: buffer for scanning device ID data
+ * @count: input size
+ *
+ * Allow RIO IDs to be added to an existing driver via sysfs.
+ */
+static ssize_t
+store_new_id(struct device_driver *driver, const char *buf, size_t count)
+{
+	return count;
+}
+static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id);
+
+/**
+ * store_remove_id - remove a RIO device ID from this driver
+ * @driver: target device driver
+ * @buf: buffer for scanning device ID data
+ * @count: input size
+ *
+ * Removes a dynamic RIO device ID to this driver.
+ */
+static ssize_t
+store_remove_id(struct device_driver *driver, const char *buf, size_t count)
+{
+	return count;
+}
+static DRIVER_ATTR(remove_id, S_IWUSR, NULL, store_remove_id);
+
+int rio_create_newid_file(struct rio_driver *drv)
+{
+	int error = 0;
+	if (drv->probe != NULL)
+		error = driver_create_file(&drv->driver, &driver_attr_new_id);
+	return error;
+}
+
+void rio_remove_newid_file(struct rio_driver *drv)
+{
+	driver_remove_file(&drv->driver, &driver_attr_new_id);
+}
+
+int rio_create_removeid_file(struct rio_driver *drv)
+{
+	int error = 0;
+	if (drv->probe != NULL)
+		error = driver_create_file(&drv->driver,
+					   &driver_attr_remove_id);
+	return error;
+}
+
+void rio_remove_removeid_file(struct rio_driver *drv)
+{
+	driver_remove_file(&drv->driver, &driver_attr_remove_id);
+}
+
+/**
+ * Hotplug API exported
+ */
+
+void rio_remove_mport_net(struct rio_mport *port, int hw_access)
+{
+	rio_job_init(port, NULL, -1, 0, hw_access, RIO_DEVICE_EXTRACTION);
+}
+EXPORT_SYMBOL_GPL(rio_remove_mport_net);
+void rio_rescan_mport(struct rio_mport *port)
+{
+	rio_job_init(port, NULL, -1, 0, 1, RIO_DEVICE_INSERTION);
+}
+EXPORT_SYMBOL_GPL(rio_rescan_mport);
+
+#endif
+
+/*
+ * FIXME!!! - remove as soon as hp is fixed on DUL
+ */
+
+/**
+ * rio_init_device - sets up a RIO device
+ * @port: Master port to send transactions
+ * @rdev:
+ * @hopcount: Current hopcount
+ *
+ */
+int rio_init_device(struct rio_dev *rdev)
+{
+	struct rio_mport *port = rdev->hport;
+	u8 hopcount = rdev->hopcount;
+	u16 destid = rdev->destid;
+
+	if (rio_has_destid(rdev->src_ops, rdev->dst_ops)) {
+		rio_assign_destid(rdev, port, rdev->destid, rdev->hopcount,
+				  &rdev->destid);
+	}
+	rio_fixup_dev(rio_fixup_early, rdev, destid, hopcount);
+	/* Assign component tag to device */
+	rio_mport_write_config_32(port, destid, hopcount,
+				  RIO_COMPONENT_TAG_CSR, rdev->comp_tag);
+
+	return 0;
+}
+EXPORT_SYMBOL(rio_init_device);
diff --git a/drivers/rapidio/rio-hotplug.h b/drivers/rapidio/rio-hotplug.h
new file mode 100644
index 0000000..8d1260f
--- /dev/null
+++ b/drivers/rapidio/rio-hotplug.h
@@ -0,0 +1,34 @@
+#ifndef RIO_HOTPLUG_H
+#define RIO_HOTPLUG_H
+
+/*
+ * RapidIO interconnect services
+ *
+ * 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>
+
+
+#if defined(CONFIG_RAPIDIO_HOTPLUG)
+
+extern int rio_create_newid_file(struct rio_driver *drv);
+extern void rio_remove_newid_file(struct rio_driver *drv);
+extern int rio_create_removeid_file(struct rio_driver *drv);
+extern void rio_remove_removeid_file(struct rio_driver *drv);
+
+#else
+
+static inline int rio_create_newid_file(struct rio_driver *drv) { return 0; }
+static inline void rio_remove_newid_file(struct rio_driver *drv) {}
+static inline int rio_create_removeid_file(struct rio_driver *drv) { return 0; }
+static inline void rio_remove_removeid_file(struct rio_driver *drv) {}
+
+#endif
+
+#endif
diff --git a/drivers/rapidio/rio-job.h b/drivers/rapidio/rio-job.h
new file mode 100644
index 0000000..3aaca9c
--- /dev/null
+++ b/drivers/rapidio/rio-job.h
@@ -0,0 +1,31 @@
+#ifndef _RIO_JOB_H
+#define _RIO_JOB_H
+
+/*
+ * RapidIO job support
+ *
+ * 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>
+
+#define RIO_JOB_STATE_GO      0
+#define RIO_JOB_STATE_INIT    1
+#define RIO_JOB_STATE_PENDING 2
+#define RIO_JOB_STATE_ABORT   3
+
+struct rio_job {
+	struct rio_mport *mport;
+	struct rio_dev *rdev;
+	int port;
+	int event;
+	u32 flags;
+	int srio_down;
+};
+
+#endif
diff --git a/drivers/rapidio/rio-locks.c b/drivers/rapidio/rio-locks.c
new file mode 100644
index 0000000..02c4e89
--- /dev/null
+++ b/drivers/rapidio/rio-locks.c
@@ -0,0 +1,713 @@
+/*
+ * RapidIO enumeration and discovery support
+ *
+ * Copyright 2005 MontaVista Software, Inc.
+ * Matt Porter <mporter at kernel.crashing.org>
+ *
+ * Copyright 2009 Integrated Device Technology, Inc.
+ * Alex Bounine <alexandre.bounine at idt.com>
+ * - Added Port-Write/Error Management initialization and handling
+ *
+ * Copyright 2009 Sysgo AG
+ * Thomas Moll <thomas.moll at sysgo.com>
+ * - Added Input- Output- enable functionality, to allow full communication
+ *
+ * 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.
+ */
+
+/* #define DEBUG */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+
+#include <linux/delay.h>
+#include <linux/dma-mapping.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 <linux/jiffies.h>
+#include <linux/slab.h>
+#include <linux/radix-tree.h>
+
+#include "rio.h"
+
+DECLARE_RWSEM(rio_tree_sem);
+DEFINE_SPINLOCK(rio_lock_lock);
+
+/* #define RIO_LOCK_DEBUG */
+
+struct rio_dev *lookup_rdev(struct rio_mport *mport, u16 destid)
+{
+	struct rio_dev *rdev;
+
+	rcu_read_lock();
+	rdev = radix_tree_lookup(&mport->net.dev_tree, destid);
+	if (rdev)
+		rdev = rio_dev_get(rdev);
+	rcu_read_unlock();
+	return rdev;
+}
+
+struct rio_dev *lookup_rdev_next(struct rio_dev *rdev, int port_num)
+{
+	struct rio_dev *next = NULL;
+	struct rio_mport *mport = rdev->hport;
+	int rc;
+	u16 device_destid;
+
+	rc = rio_lookup_next_destid(mport, rdev->destid,
+				    port_num, rdev->hopcount + 1,
+				    &device_destid);
+	if (rc)
+		return ERR_PTR(rc);
+
+	next = lookup_rdev(mport, device_destid);
+	if (!next)
+		return ERR_PTR(-ENODEV);
+
+	return next;
+}
+
+/**
+ * rio_set_host_lock - Sets the Host Device ID Lock CSR on a device
+ * @port: Master port to send transaction
+ * @destid: Destination ID of device
+ * @hopcount: Number of hops to the device
+ * @lock: Lock to be set on device
+ *
+ * Used during enumeration to set the Host Device ID Lock CSR on a
+ * RIO device. Returns success of write.
+ */
+static int rio_set_host_lock(struct rio_mport *port, u16 destid, u8 hopcount)
+{
+	int rc;
+
+	if (destid == port->host_deviceid) {
+		rc = rio_local_write_config_32(port, RIO_HOST_DID_LOCK_CSR,
+				port->host_deviceid);
+	} else
+		rc = rio_mport_write_config_32(port, destid, hopcount,
+		RIO_HOST_DID_LOCK_CSR, port->host_deviceid);
+	if (rc)
+		pr_debug("RIO:(%s) destid %hu hopcount %d - Write error\n",
+			 __func__, destid, hopcount);
+	return rc;
+}
+
+/**
+ * rio_hw_lock - Acquires host device lock for specified device
+ * @port: Master port to send transaction
+ * @destid: Destination ID for device/switch
+ * @hopcount: Hopcount to reach switch
+ *
+ * Attepts to acquire host device lock for specified device
+ * Returns 0 if device lock acquired or ETIME if timeout expires.
+ */
+static int rio_hw_lock(struct rio_mport *port, u16 destid, u8 hopcount)
+{
+	u16 lock;
+	int rc = 0;
+
+	spin_lock(&rio_lock_lock);
+
+	rc = rio_get_host_lock(port, destid, hopcount, &lock);
+	if (rc)
+		goto done;
+
+	if (lock == port->host_deviceid)
+		goto lock_err;
+	/* Attempt to acquire device lock */
+	rc = rio_set_host_lock(port, destid, hopcount);
+	if (rc)
+		goto done;
+	rc = rio_get_host_lock(port, destid, hopcount, &lock);
+	if (rc)
+		goto done;
+
+	if (lock != port->host_deviceid)
+		goto to_err;
+
+#if defined(RIO_LOCK_DEBUG)
+	pr_debug("RIO: Device destid 0x%x hopcount %hhu locked by 0x%x\n",
+		 destid, hopcount, lock);
+#endif
+done:
+	spin_unlock(&rio_lock_lock);
+	return rc;
+
+to_err:
+	pr_debug("RIO: timeout when locking device %hx:%hhu lock owned by %hu\n",
+		 destid, hopcount, lock);
+	rc = -ETIME;
+	goto done;
+lock_err:
+	pr_debug("RIO: Device destid %hx hopcount %hhu is already locked by %hx\n",
+		 destid, hopcount, port->host_deviceid);
+	rc = -EFAULT;
+	goto done;
+
+}
+
+
+static int __rio_clear_locks(struct rio_dev *from, struct rio_dev *to)
+{
+	struct rio_dev *prev, *curr;
+	int rc = 0;
+
+	if (!from)
+		return 0;
+
+	if (!to)
+		return 0;
+
+	if (to->use_hw_lock) {
+		rc = rio_hw_unlock(to->hport, to->destid, to->hopcount);
+		if (rc)
+			goto done;
+	}
+
+	pr_debug("RIO: Unlocked %s\n", rio_name(to));
+
+	curr = to;
+
+	rcu_read_lock();
+	while (curr) {
+		prev = radix_tree_lookup(&curr->hport->net.dev_tree,
+					 curr->prev_destid);
+		if (prev) {
+			if (prev->use_hw_lock) {
+				rc = rio_hw_unlock(prev->hport, prev->destid,
+						   prev->hopcount);
+				if (rc) {
+					pr_debug("RIO: Failed to unlock %s\n",
+						 rio_name(prev));
+					rcu_read_unlock();
+					goto done;
+				}
+			}
+			pr_debug("RIO: Unlocked %s\n", rio_name(prev));
+			if (prev == from) {
+				rcu_read_unlock();
+				goto done;
+			}
+		}
+		curr = prev;
+	}
+	rcu_read_unlock();
+
+done:
+	return rc;
+}
+static int __rio_take_locks(struct rio_dev *from, struct rio_dev *to)
+{
+	struct rio_dev *prev, *curr;
+	int rc = 0;
+
+	if (!from)
+		return 0;
+	if (!to)
+		return 0;
+
+	if (to->use_hw_lock) {
+		rc = rio_hw_lock(to->hport, to->destid, to->hopcount);
+		if (rc)
+			goto done;
+	}
+
+	pr_debug("RIO: Add lock to %s\n", rio_name(to));
+
+	curr = to;
+
+	rcu_read_lock();
+	while (curr) {
+		prev = radix_tree_lookup(&curr->hport->net.dev_tree,
+					 curr->prev_destid);
+		if (prev) {
+			if (prev->use_hw_lock)
+				rc = rio_hw_lock(prev->hport, prev->destid,
+						 prev->hopcount);
+				if (rc) {
+					rcu_read_unlock();
+					goto unlock;
+				}
+			pr_debug("RIO: Add lock to %s\n", rio_name(prev));
+			if (prev == from) {
+				rcu_read_unlock();
+				goto done;
+			}
+		}
+		curr = prev;
+	}
+	rcu_read_unlock();
+done:
+	return rc;
+
+unlock:
+	__rio_clear_locks(curr, to);
+	goto done;
+}
+static int rio_hw_lock_devices(struct rio_mport *mport, struct rio_dev *from,
+			       struct rio_dev *to)
+{
+	return __rio_take_locks(from, to);
+}
+
+static void rio_timeout(unsigned long data)
+{
+	/* timed out, set flag */
+	*(int *)data = 1;
+}
+
+/**
+ * rio_job_hw_lock_wait - Tries to take the @host_device_lock on a RIO device
+ *			  or a group of RIO devices in a RIO network. A number
+ *			  of attempts will be made to take the lock/locks.
+ *			  Before each attempt, RIO job status GO is verified
+ *			  and after each unsuccessful attempt the
+ *			  rio_hw_lock() return status and timeout status is
+ *			  checked. As long as the @tmo is not up and the
+ *			  rio_hw_lock() return status indicates that
+ *                        someone else owns the lock, the caller will be put
+ *			  to sleep for a period of 10 ms.
+ *
+ * @job: RIO Job description
+ * @from: Root Device to start locking from - set to @NULL if not applicable
+ * @to: Last device to take lock on - set to @NULL if not applicable
+ * @destid: Destination ID of device
+ * @hopcount: Number of hops to the device
+ * @tmo: Max time to wait in units of seconds
+ *
+ * If @from is defined it is assumed that the user have incremented the
+ * @from reference count before calling rio_job_hw_lock_wait()
+ *
+ * Returns 0 at success and != 0 at failure
+ *
+ * In any case, the @from reference count is always consumed
+ * if @from was defined.
+ */
+int rio_job_hw_lock_wait(struct rio_job *job, struct rio_dev *from,
+			 struct rio_dev *to,
+			 u16 destid, u8 hopcount, int tmo)
+{
+	int rc = 0;
+	int timeout_flag = 0;
+	struct timer_list rio_timer =
+		TIMER_INITIALIZER(rio_timeout, 0, 0);
+
+	rio_timer.expires = jiffies + tmo * HZ;
+	rio_timer.data = (unsigned long)&timeout_flag;
+	add_timer(&rio_timer);
+
+	do {
+		if (from)
+			rc = rio_hw_lock_devices(job->mport, from, to);
+		else
+			rc = rio_hw_lock(job->mport, destid, hopcount);
+
+		if (rc != -ETIME)
+			goto done;
+
+		msleep(10);
+
+	} while (!timeout_flag);
+done:
+	del_timer_sync(&rio_timer);
+	return rc;
+}
+
+/**
+ * rio_job_hw_lock_wait_cond - Tries to take the @host_device_lock on a
+ *			       RIO device. A number of attempts will be made
+ *			       to take the lock. Before each attempt, RIO job
+ *			       status GO is verified and after each
+ *			       unsuccessful attempt the rio_hw_lock() return
+ *			       status and timeout status is checked. As long
+ *			       as the @tmo is not up and the rio_hw_lock()
+ *			       return status indicates that someone else owns
+ *			       the lock, the caller will be put to sleep
+ *                             for a period of 50 ms. When the
+ *			       @host_device_lock is set a user defined function
+ *                             is invoked. A != 0 return value from this
+ *			       function will terminate
+*			       rio_job_hw_lock_wait_cond() otherwise the
+ *                             @host_device_lock is relead and the wait
+ *			       loop continues.
+ *
+ * @job: RIO Job description
+ * @destid: Destination ID of device
+ * @hopcount: Number of hops to the device
+ * @tmo: Max time to wait in units of seconds
+ *
+ * Returns 0 at success and != 0 at failure
+ */
+int rio_job_hw_lock_wait_cond(struct rio_job *job, u16 destid,
+			      u8 hopcount, int tmo, int lock,
+			      int (*cond)(struct rio_mport *, u16, u8))
+{
+	int rc = 0;
+	int timeout_flag = 0;
+	struct timer_list rio_timer =
+		TIMER_INITIALIZER(rio_timeout, 0, 0);
+
+	rio_timer.expires = jiffies + tmo * HZ;
+	rio_timer.data = (unsigned long)&timeout_flag;
+	add_timer(&rio_timer);
+
+	do {
+		rc = rio_hw_lock(job->mport, destid, hopcount);
+		if ((!lock) || (rc == 0)) {
+			rc = cond(job->mport, destid, hopcount);
+			if (rc == 0)
+				goto done;
+			rio_hw_unlock(job->mport, destid, hopcount);
+		}
+		if (rc != -ETIME)
+			goto done;
+		if (timeout_flag)
+			break;
+		msleep(50);
+
+	} while (!timeout_flag);
+done:
+	del_timer_sync(&rio_timer);
+	return rc;
+}
+
+int rio_job_hw_wait_cond(struct rio_job *job, u16 destid,
+			 u8 hopcount, int tmo,
+			 int (*cond)(struct rio_mport *, u16, u8))
+{
+	int rc = 0;
+	int timeout_flag = 0;
+	struct timer_list rio_timer =
+		TIMER_INITIALIZER(rio_timeout, 0, 0);
+
+	rio_timer.expires = jiffies + tmo * HZ;
+	rio_timer.data = (unsigned long)&timeout_flag;
+	add_timer(&rio_timer);
+
+	do {
+		rc = cond(job->mport, destid, hopcount);
+		if (rc == 1)
+			goto done;
+		if (timeout_flag)
+			break;
+		msleep(100);
+
+	} while (!timeout_flag);
+done:
+	del_timer_sync(&rio_timer);
+	return rc;
+}
+
+/**
+ * rio_hw_busy_lock_wait - Tries to take the @host_device_lock on a RIO device.
+ *                         A number of attempts will be made to take the lock.
+ *                         After each unsuccessful attempt the rio_hw_lock()
+ *			   return status and timeout status is checked. As
+			   long as the @wait_ms is not up and the
+			   rio_hw_lock() return status indicates that
+ *                         someone else owns the lock, the caller will be
+ *			   delayed in a busy loop for a period of 1 ms.
+ *
+ * @mport: Master port to send transaction
+ * @destid: Destination ID of device
+ * @hopcount: Number of hops to the device
+ * @wait_ms: Max time to wait in units of milli seconds
+ *
+ * Returns 0 at success and != 0 at failure
+ */
+int rio_hw_lock_busy_wait(struct rio_mport *mport, u16 destid,
+			  u8 hopcount, int wait_ms)
+{
+	int tcnt = 0;
+	int rc = rio_hw_lock(mport, destid, hopcount);
+
+	while (rc == -ETIME) {
+		if (tcnt >= wait_ms)
+			break;
+		mdelay(1);
+		tcnt++;
+		rc = rio_hw_lock(mport, destid, hopcount);
+	}
+	return rc;
+}
+
+/**
+ * rio_hw_lock_wait - Tries to take the @host_device_lock on a RIO device.
+ *                    A number of attempts will be made to take the lock.
+ *                    After each unsuccessful attempt the rio_hw_lock() return
+ *		      status and timeout status is checked. As long as the
+ *		      @tmo is not up and the rio_hw_lock() return status
+ *		      indicates that someone else owns the lock, the caller
+ *		      will be put to sleep for a period of 10 ms.
+ *
+ * @mport: Master port to send transaction
+ * @destid: Destination ID of device
+ * @hopcount: Number of hops to the device
+ * @tmo: Max time to wait in units of seconds
+ *
+ * Returns 0 at success and != 0 at failure
+ */
+int rio_hw_lock_wait(struct rio_mport *mport, u16 destid, u8 hopcount, int tmo)
+{
+	int rc = 0;
+	int timeout_flag = 0;
+	struct timer_list rio_timer =
+		TIMER_INITIALIZER(rio_timeout, 0, 0);
+
+	rio_timer.expires = jiffies + tmo * HZ;
+	rio_timer.data = (unsigned long)&timeout_flag;
+	add_timer(&rio_timer);
+
+	do {
+		rc = rio_hw_lock(mport, destid, hopcount);
+
+		if (rc != -ETIME)
+			goto done;
+
+		msleep(10);
+
+	} while (!timeout_flag);
+done:
+	del_timer_sync(&rio_timer);
+	return rc;
+}
+
+/**
+ * rio_get_by_ptr - search for a matching device in the global list
+ *
+ * @rdev: RIO device
+ *
+ * Increments rdev reference counter and returns rdev pointer
+ * if a matching device pointer is found in the global list.
+ * Users are responsible to decrement the reference count, i.e.
+ * rio_dev_put() when done with the device.
+ *
+ * Returns NULL if RIO device doesn't exist in the global list.
+ */
+struct rio_dev *rio_get_by_ptr(struct rio_dev *rdev)
+{
+	struct rio_dev *tmp = NULL;
+
+	if (!rdev)
+		return NULL;
+
+	while ((tmp = rio_get_device(RIO_ANY_ID, RIO_ANY_ID, tmp)) != NULL) {
+		if (tmp == rdev)
+			return tmp;
+	}
+	return NULL;
+}
+
+/**
+ * rio_get_root_node - Find switch connected to local master port
+ *                     in a RIO network.
+ *
+ * @mport: Local master port
+ *
+ * Increments switch reference counter and returns switch rdev pointer
+ * if a matching switch device is found in the global list.
+ * Users are responsible to decrement the reference count, i.e.
+ * rio_dev_put() when done with the device.
+ *
+ * Returns NULL if a root switch doesn't exist in the global list.
+ */
+struct rio_dev *rio_get_root_node(struct rio_mport *mport)
+{
+	int rc;
+	u16 device_destid;
+	struct rio_dev *rdev = NULL;
+
+	BUG_ON(!mport);
+
+	rc = rio_lookup_next_destid(mport, mport->host_deviceid,
+				    -1, 0, &device_destid);
+	if (rc)
+		return ERR_PTR(rc);
+
+	rdev = lookup_rdev(mport, device_destid);
+	if (!rdev)
+		return ERR_PTR(-ENODEV);
+
+	return rdev;
+}
+
+/**
+ * rio_get_host_lock - Reads the Host Device ID Lock CSR on a device
+ * @port: Master port to send transaction
+ * @destid: Destination ID of device
+ * @hopcount: Number of hops to the device
+ * @result: Location where ID lock is stored
+ *
+ * Returns the RIO device access status.
+ */
+int rio_get_host_lock(struct rio_mport *port, u16 destid,
+		      u8 hopcount, u16 *result)
+{
+	u32 regval;
+	int rc;
+
+	if (destid == port->host_deviceid) {
+		rc = rio_local_read_config_32(port,
+					      RIO_HOST_DID_LOCK_CSR, &regval);
+	} else {
+		rc = rio_mport_read_config_32(port, destid, hopcount,
+					      RIO_HOST_DID_LOCK_CSR, &regval);
+	}
+	*result = regval & 0xffff;
+
+	if (rc)
+		pr_debug("RIO:(%s) destid %hx hopcount %d - Read error\n",
+			 __func__, destid, hopcount);
+	return rc;
+}
+
+/**
+ * rio_clear_host_lock - Clear @lockid on a device
+ * @port: Master port to send transaction
+ * @destid: Destination ID of device
+ * @hopcount: Number of hops to the device
+ * @lockid: Device ID Lock to be cleared
+ *
+ * Returns 0 if the @lockid is cleared
+ *
+ * Returns < 0 if:
+ * - At RIO device access faults
+ * - If @lockid was not set on the device
+ * - If the device was not unlocked
+ */
+
+int rio_clear_host_lock(struct rio_mport *port, u16 destid,
+			u8 hopcount, u16 lockid)
+{
+	int rc;
+	u16 result;
+
+	spin_lock(&rio_lock_lock);
+	rc = rio_get_host_lock(port, destid, hopcount, &result);
+	if (rc)
+		goto done;
+	if (result != lockid) {
+		pr_debug("RIO: device lock on %hx:%hhu is owned by %hu\n",
+			 destid, hopcount, result);
+		rc = -EINVAL;
+		goto done;
+	}
+	if (destid == port->host_deviceid) {
+		rc = rio_local_write_config_32(port, RIO_HOST_DID_LOCK_CSR,
+					       lockid);
+	} else
+		rc = rio_mport_write_config_32(port, destid, hopcount,
+					       RIO_HOST_DID_LOCK_CSR,
+					       lockid);
+	if (rc) {
+		pr_debug("RIO: destid %hu hopcount %d - Write error\n",
+			 destid, hopcount);
+		goto done;
+	}
+	rc = rio_get_host_lock(port, destid, hopcount, &result);
+	if (rc)
+		goto done;
+
+	if (result != 0xffff) {
+		pr_debug("RIO: badness when releasing device lock %hx:%hhu\n",
+			 destid, hopcount);
+		rc = -EINVAL;
+	}
+done:
+	spin_unlock(&rio_lock_lock);
+	return rc;
+
+}
+
+/**
+ * rio_unlock - Releases @host_device_lock for specified device
+ *
+ * @port: Master port to send transaction
+ * @destid: Destination ID for device/switch
+ * @hopcount: Hopcount to reach switch
+ *
+ * Returns 0 if the @host_device_lock is cleared
+ *
+ * Returns < 0 if:
+ * - At RIO device access faults
+ * - If @host_device_lock was not set on the device
+ * - If the device was not unlocked
+ */
+int rio_hw_unlock(struct rio_mport *port, u16 destid, u8 hopcount)
+{
+	u16 lock;
+	int rc = 0;
+
+	spin_lock(&rio_lock_lock);
+	/* Release device lock */
+	rc = rio_get_host_lock(port, destid, hopcount, &lock);
+	if (rc)
+		goto done;
+
+	if (lock != port->host_deviceid)
+		goto lock_err;
+
+	rc = rio_set_host_lock(port, destid, hopcount);
+	if (rc)
+		goto done;
+
+	rc = rio_get_host_lock(port, destid, hopcount, &lock);
+	if (rc)
+		goto done;
+
+	if (lock != 0xffff)
+		goto unlock_err;
+#if defined(RIO_LOCK_DEBUG)
+	pr_debug("RIO: Device destid %hx hopcount %hhu is unlocked by %hx\n",
+		 destid, hopcount, port->host_deviceid);
+#endif
+done:
+	spin_unlock(&rio_lock_lock);
+	return rc;
+lock_err:
+	pr_debug("RIO: release lock err - lock is not taken, destid %hx, hopcount %hhu, lock 0x%x",
+		 destid, hopcount, lock);
+	rc = -EINVAL;
+	goto done;
+unlock_err:
+	pr_debug("RIO: badness when releasing device lock %hx:%hhu\n",
+		 destid, hopcount);
+	rc = -EINVAL;
+	goto done;
+}
+
+/**
+ * rio_job_hw_unlock_devices -	Releases @host_device_lock for a group
+ *				of RIO devices. If the job description defines
+ *				@rdev, locks are released on all devices
+ *				between and including the switch connected
+ *				to local master port and the job @rdev.
+ *				The master port device ID Lock is
+ *				always released.
+ * @job: RIO Job description
+ *
+ */
+void rio_job_hw_unlock_devices(struct rio_job *job)
+{
+	struct rio_dev *from = NULL;
+	struct rio_dev *to = job->rdev;
+
+	if (job->rdev)
+		from = rio_get_root_node(job->mport);
+	if (from && !IS_ERR(from)) {
+		pr_debug("RIO: clear locks from %s to %s\n",
+			 rio_name(from), rio_name(to));
+		__rio_clear_locks(from, to);
+		rio_dev_put(from);
+	}
+}
diff --git a/drivers/rapidio/rio-locks.h b/drivers/rapidio/rio-locks.h
new file mode 100644
index 0000000..d0cc151
--- /dev/null
+++ b/drivers/rapidio/rio-locks.h
@@ -0,0 +1,67 @@
+#ifndef _RIO_LOCK_H
+#define _RIO_LOCK_H
+
+/*
+ * RapidIO job support
+ *
+ * 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.
+ */
+
+extern struct rw_semaphore rio_tree_sem;
+
+static inline void rio_tree_read_lock(void)
+{
+	down_read(&rio_tree_sem);
+#if defined(RIO_LOCK_DEBUG)
+	pr_debug("RIO: PID %u got the rio_tree_read_lock\n", current->pid);
+#endif
+}
+static inline void rio_tree_read_unlock(void)
+{
+#if defined(RIO_LOCK_DEBUG)
+	pr_debug("RIO: PID %u release the rio_tree_read_lock\n", current->pid);
+#endif
+	up_read(&rio_tree_sem);
+}
+static inline void rio_tree_write_lock(void)
+{
+	down_write(&rio_tree_sem);
+#if defined(RIO_LOCK_DEBUG)
+	pr_debug("RIO: PID %u got the rio_tree_write_lock\n", current->pid);
+#endif
+}
+static inline void rio_tree_write_unlock(void)
+{
+#if defined(RIO_LOCK_DEBUG)
+	pr_debug("RIO: PID %u release the rio_tree_write_lock\n",
+		 current->pid);
+#endif
+	up_write(&rio_tree_sem);
+}
+extern struct rio_dev *lookup_rdev_next(struct rio_dev *rdev, int port_num);
+extern struct rio_dev *rio_get_by_ptr(struct rio_dev *rdev);
+extern int rio_get_host_lock(struct rio_mport *port, u16 destid, u8 hopcount,
+			     u16 *result);
+extern int rio_clear_host_lock(struct rio_mport *port, u16 destid,
+			       u8 hopcount, u16 lockid);
+extern int rio_hw_unlock(struct rio_mport *port, u16 destid, u8 hopcount);
+extern void rio_job_hw_unlock_devices(struct rio_job *job);
+extern int rio_hw_lock_busy_wait(struct rio_mport *port, u16 destid,
+				 u8 hopcount, int wait_ms);
+extern int rio_job_hw_lock_wait(struct rio_job *job, struct rio_dev *from,
+				struct rio_dev *to,
+				u16 destid, u8 hopcount, int tmo);
+extern int rio_job_hw_lock_wait_cond(struct rio_job *job, u16 destid,
+				     u8 hopcount, int tmo, int lock,
+				     int (*unlock)(struct rio_mport *,
+						   u16, u8));
+
+extern int rio_hw_lock_wait(struct rio_mport *mport, u16 destid,
+			    u8 hopcount, int tmo);
+extern int rio_job_hw_wait_cond(struct rio_job *job, u16 destid,
+				u8 hopcount, int tmo,
+				int (*cond)(struct rio_mport *, u16, u8));
+#endif
diff --git a/drivers/rapidio/rio-multicast.h b/drivers/rapidio/rio-multicast.h
new file mode 100644
index 0000000..78887db
--- /dev/null
+++ b/drivers/rapidio/rio-multicast.h
@@ -0,0 +1,28 @@
+#ifndef RIO_MULTICAST_H
+#define RIO_MULTICAST_H
+
+/*
+ * RapidIO multicast
+ *
+ * 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>
+
+extern int rio_multicast_del_all_ports(struct rio_dev *rdev, int maskId);
+extern int rio_multicast_add_port(struct rio_dev *rdev,
+				  int maskId, int port_num);
+extern int rio_multicast_add_assoc(struct rio_dev *rdev,
+				   int maskId, int destId);
+extern int rio_multicast_del_port(struct rio_dev *rdev,
+				  int maskId, int port_num);
+
+extern int rio_init_switch_pw(struct rio_dev *rdev);
+extern int rio_update_pw(struct rio_dev *rdev, int sw_port,
+			 int add, int lock);
+
+
+#endif
diff --git a/drivers/rapidio/rio-net.h b/drivers/rapidio/rio-net.h
new file mode 100644
index 0000000..d8fafe6
--- /dev/null
+++ b/drivers/rapidio/rio-net.h
@@ -0,0 +1,26 @@
+#ifndef RIO_NET_H
+#define RIO_NET_H
+
+/*
+ * RapidIO interconnect services
+ *
+ * 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>
+
+#define RIO_DEV_NOT_ADDED (0)
+#define RIO_DEV_IS_SWITCH (1)
+#define RIO_DEV_DISABLED (2)
+
+
+extern int rio_device_enable(struct rio_dev *rdev);
+extern int rio_device_disable(struct rio_dev *rdev);
+extern int rio_switch_port_is_active(struct rio_dev *rdev, int sport);
+
+#endif
diff --git a/drivers/rapidio/rio-net2.c b/drivers/rapidio/rio-net2.c
new file mode 100644
index 0000000..f9a8b1c
--- /dev/null
+++ b/drivers/rapidio/rio-net2.c
@@ -0,0 +1,2033 @@
+/*
+ * RapidIO enumeration and discovery support
+ *
+ * Copyright 2005 MontaVista Software, Inc.
+ * Matt Porter <mporter at kernel.crashing.org>
+ *
+ * Copyright 2009 Integrated Device Technology, Inc.
+ * Alex Bounine <alexandre.bounine at idt.com>
+ * - Added Port-Write/Error Management initialization and handling
+ *
+ * Copyright 2009 Sysgo AG
+ * Thomas Moll <thomas.moll at sysgo.com>
+ * - Added Input- Output- enable functionality, to allow full communication
+ *
+ * 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/types.h>
+#include <linux/kernel.h>
+
+#include <linux/delay.h>
+#include <linux/dma-mapping.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 <linux/jiffies.h>
+#include <linux/slab.h>
+#include <linux/radix-tree.h>
+#include <linux/hardirq.h>
+
+#include "rio.h"
+
+DEFINE_SPINLOCK(rio_global_list_lock);
+
+static int rio_mport_phys_table[] = {
+	RIO_EFB_PAR_EP_ID,
+	RIO_EFB_PAR_EP_REC_ID,
+	RIO_EFB_SER_EP_ID,
+	RIO_EFB_SER_EP_REC_ID,
+	-1,
+};
+
+/**
+ * rio_mport_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
+ * %RIO_PORT_N_ERR_STS_PORT_OK if the  master port is active
+ * or %0 if it is inactive.
+ */
+static int rio_mport_active(struct rio_mport *port)
+{
+	u32 result = 0;
+	u32 ext_ftr_ptr;
+	int *entry = rio_mport_phys_table;
+	int rc;
+
+	do {
+		rc = rio_mport_get_feature(port, 1, 0, 0, *entry, &ext_ftr_ptr);
+		if (rc)
+			return 0;
+		if (ext_ftr_ptr)
+			break;
+	} while (*++entry >= 0);
+
+	if (ext_ftr_ptr)
+		rc = rio_local_read_config_32(port,
+			ext_ftr_ptr + RIO_PORT_N_ERR_STS_CSR(port->index),
+			&result);
+
+	return  rc ? 0 : result & RIO_PORT_N_ERR_STS_PORT_OK;
+}
+
+static int rio_update_dst_tree(struct rio_mport *mport, u16 parent_destid,
+			       int parent_port, int hopcount,
+			       u16 destid, u16 comptag, int redundant)
+{
+	u16 tmp_dst;
+
+	int rc = rio_lookup_next_destid(mport, parent_destid, parent_port,
+					hopcount, &tmp_dst);
+
+	if (!rc) {
+		pr_debug("RIO:(%s) Not adding new device dest %hx\n",
+			 __func__, destid);
+		pr_debug("RIO:(%s) found pdest %hx pport %d hop %d dest %hx\n",
+			 __func__, parent_destid, parent_port, hopcount,
+			 tmp_dst);
+		return rc;
+	}
+	if (redundant)
+		return rio_block_destid_route(mport, parent_destid,
+					      parent_port, hopcount,
+					      destid, comptag);
+	else
+		return rio_add_destid(mport, parent_destid,
+				      parent_port, hopcount,
+				      destid, comptag);
+}
+
+static int add_new_dev2tree(struct rio_dev *rdev,
+			    struct rio_dev *prev,
+			    u16 prev_dest,
+			    int prev_port)
+{
+	int rc;
+	struct rio_mport *mport = rdev->hport;
+	struct rio_dev *tmp;
+
+	rc = rio_pin_destid(mport, prev_dest, prev_port, rdev->hopcount);
+	if (unlikely(rc))
+		return rc;
+
+	spin_lock(&mport->net.tree_lock);
+
+	rc = radix_tree_insert(&mport->net.dev_tree, rdev->destid, rdev);
+	if (unlikely(rc)) {
+		spin_unlock(&mport->net.tree_lock);
+		return rc;
+	}
+	tmp = radix_tree_tag_set(&mport->net.dev_tree,
+				 rdev->destid,
+				 RIO_DEV_NOT_ADDED);
+	BUG_ON(tmp != rdev);
+	atomic_inc(&mport->net.rio_dev_num);
+
+	if (rio_is_switch(rdev)) {
+		tmp = radix_tree_tag_set(&mport->net.dev_tree,
+					 rdev->destid,
+					 RIO_DEV_IS_SWITCH);
+		BUG_ON(tmp != rdev);
+	}
+	if (rdev->local_domain) {
+		tmp = radix_tree_tag_set(&mport->net.dev_tree,
+					 rdev->destid,
+					 RIO_DEV_DISABLED);
+		BUG_ON(tmp != rdev);
+	}
+	/*
+	 * Ensure that rdev is kept in circulation
+	 * until enum/disc is done
+	 */
+	rdev = rio_dev_get(rdev);
+
+	spin_unlock(&mport->net.tree_lock);
+
+	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 = to_rio_dev(dev);
+	pr_debug("last call for %s\n", rio_name(rdev));
+
+	kfree(rdev);
+}
+
+/**
+ * rio_release_device - clear enumeration
+ *		      complete flag
+ * @rdev: rio_device
+ *
+ * Returns 0 on success or %-EINVAL on failure.
+ */
+static int rio_release_device(struct rio_dev *rdev)
+{
+	u32 result;
+	int rc;
+
+	/* Un-claim device */
+	rc = rio_read_config_32(rdev,
+				rdev->phys_efptr + RIO_PORT_GEN_CTL_CSR,
+				&result);
+	if (rc)
+		return rc;
+
+	result &= ~(RIO_PORT_GEN_DISCOVERED | RIO_PORT_GEN_MASTER);
+	rc = rio_write_config_32(rdev,
+				 rdev->phys_efptr + RIO_PORT_GEN_CTL_CSR,
+				 result);
+	return rc;
+}
+
+static inline int rdev_is_mport(struct rio_dev *rdev)
+{
+	return (rdev->hport->host_deviceid == rdev->destid);
+}
+
+static void __rio_remove_device(struct rio_dev *rdev,
+				int dev_access,
+				int srio_down)
+{
+	int rio_access = (srio_down ? 0 : rio_mport_active(rdev->hport));
+	struct rio_mport *mport = rdev->hport;
+	int device_lock = 0;
+	int not_added;
+
+	pr_debug("Removing rio device %s from lists\n", rio_name(rdev));
+
+	rio_tree_write_lock();
+
+	spin_lock(&mport->net.tree_lock);
+	/*
+	 * Remove device ref. from global list and mport net list
+	 */
+	not_added = radix_tree_tag_get(&mport->net.dev_tree, rdev->destid,
+				       RIO_DEV_NOT_ADDED);
+	rdev = radix_tree_delete(&mport->net.dev_tree, rdev->destid);
+	if (!rdev) {
+		pr_warn("device %s not found in glb tree\n", rio_name(rdev));
+		spin_unlock(&mport->net.tree_lock);
+		return;
+	}
+	atomic_dec(&mport->net.rio_dev_num);
+
+	spin_unlock(&mport->net.tree_lock);
+	synchronize_rcu();
+
+	rio_tree_write_unlock();
+
+	WARN(rio_unlock_destid(mport, rdev->prev_destid,
+			       rdev->prev_port, rdev->hopcount),
+	     "RIO: Destid table entry pinned after removing device %s",
+	     rio_name(rdev));
+
+	if (!rdev_is_mport(rdev) && rio_access &&
+	 dev_access && rdev->local_domain) {
+		/* try lock device */
+		pr_debug("try lock %s\n", rio_name(rdev));
+		if (rdev->use_hw_lock) {
+			if (rio_hw_lock_busy_wait(rdev->hport, rdev->destid,
+						  rdev->hopcount, 10)) {
+				pr_warn("Can not claim device ID lock, HW release not possible");
+			} else {
+				pr_debug("Got %s device ID lock\n",
+					 rio_name(rdev));
+				device_lock = 1;
+			}
+		} else {
+			device_lock = 1;
+		}
+	}
+	if (not_added) {
+		pr_warn("rio device %s is not added - skip remove!\n",
+			rio_name(rdev));
+	} else {
+		pr_debug("rio device %s is added - remove!\n", rio_name(rdev));
+		/*
+		 * sysfs cleanup
+		 */
+		rio_remove_sysfs_dev_files(rdev);
+		/*
+		 * Remove device from kernel global device list
+		 * If a driver has claimed the device its release
+		 * function will be called.
+		 */
+		device_del(&rdev->dev);
+	}
+	rio_dev_put(rdev);
+	if (device_lock) {
+		/* Disable device and clear enum flag */
+		pr_debug("Release %s HW\n", rio_name(rdev));
+		rio_release_device(rdev);
+		if (rdev->use_hw_lock)
+			rio_hw_unlock(rdev->hport,
+				      rdev->destid,
+				      rdev->hopcount);
+	}
+	/*
+	 * Cleanup-up routing tables
+	 */
+	if (!rdev_is_mport(rdev) && rio_access) {
+		pr_debug("Remove route to %s\n", rio_name(rdev));
+		rio_remove_route_for_destid(rdev->hport, rdev->destid, 1);
+	}
+	/*
+	 * Give up last ref to device - the rio_release_dev
+	 * function will do the final cleanup
+	 */
+	rio_dev_put(rdev);
+}
+
+/**
+ * rio_remove_devices - remove device node and, if node is switch,
+ *		      recursively remove all devices reached through
+ *		      node
+ *
+ * @rdev: RIO device node
+ * @rio_access: Cleanup RIO device HW
+ *
+ */
+static void rio_remove_devices(struct rio_dev *rdev, int dev_access,
+			       int srio_down)
+{
+	int i;
+	dev_access = 0;
+	if (rio_is_switch(rdev)) {
+		pr_debug("found switch %s - check ports\n", rio_name(rdev));
+		for (i = 0; i < RIO_GET_TOTAL_PORTS(rdev->swpinfo); i++) {
+			struct rio_dev *next = lookup_rdev_next(rdev, i);
+			int type = (IS_ERR(next) ?
+			 RIO_PORT_UNUSED : rio_type_of_next(rdev, next));
+			if (IS_ERR(next))
+				next = NULL;
+
+			switch (type) {
+			case RIO_SWITCH:
+				rio_remove_devices(next, dev_access, srio_down);
+				break;
+			case RIO_END_POINT:
+				pr_debug("remove endpoint %s from switch %s\n",
+					 rio_name(next), rio_name(rdev));
+				__rio_remove_device(next,
+						    dev_access,
+						    srio_down);
+				rio_dev_put(next);
+				break;
+			case RIO_PORT_UNUSED:
+			default:
+				rio_dev_put(next);
+				break;
+			}
+		}
+	}
+	pr_debug("Remove %s %s\n",
+		 (rio_is_switch(rdev) ? "switch" : "endpoint"),
+		 rio_name(rdev));
+	__rio_remove_device(rdev, dev_access, 0);
+}
+
+/**
+ * rio_switch_init - Sets switch operations for a particular vendor switch
+ * @rdev: RIO device
+ * @do_enum: Enumeration/Discovery mode flag
+ *
+ * Searches the RIO switch ops table for known switch types. If the vid
+ * and did match a switch table entry, then call switch initialization
+ * routine to setup switch-specific routines.
+ */
+static void rio_switch_init(struct rio_dev *rdev, int do_enum)
+{
+	struct rio_switch_ops *cur = __start_rio_switch_ops;
+	struct rio_switch_ops *end = __end_rio_switch_ops;
+
+	while (cur < end) {
+		if ((cur->vid == rdev->vid) && (cur->did == rdev->did)) {
+			cur->init_hook(rdev, do_enum);
+			break;
+		}
+		cur++;
+	}
+
+	if ((cur >= end) && (rdev->pef & RIO_PEF_STD_RT)) {
+		pr_debug("RIO: adding STD routing ops for %s\n",
+			 rio_name(rdev));
+		rdev->rswitch->add_entry = rio_std_route_add_entry;
+		rdev->rswitch->get_entry = rio_std_route_get_entry;
+		rdev->rswitch->clr_table = rio_std_route_clr_table;
+	}
+
+	if (!rdev->rswitch->add_entry || !rdev->rswitch->get_entry)
+		pr_warn("RIO: missing routing ops for %s\n",
+			rio_name(rdev));
+}
+
+static int init_switch_pw(struct rio_dev *rdev)
+{
+	if ((rdev->src_ops & RIO_SRC_OPS_PORT_WRITE) &&
+	    (rdev->em_efptr)) {
+		return rio_write_config_32(rdev,
+					   rdev->em_efptr + RIO_EM_PW_TGT_DEVID,
+					   (rdev->hport->host_deviceid << 16) |
+					   (rdev->hport->sys_size << 15));
+	} else {
+		return 0;
+	}
+}
+
+/**
+ * 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 int rio_add_device(struct rio_dev *rdev)
+{
+	int err;
+	pr_debug("RIO: %s %s\n", __func__, rio_name(rdev));
+	err = device_add(&rdev->dev);
+	if (err)
+		return err;
+
+	rio_create_sysfs_dev_files(rdev);
+
+	return 0;
+}
+
+/**
+ * rio_enable_rx_tx_port - enable input receiver and output transmitter of
+ * given port
+ * @port: Master port associated with the RIO network
+ * @local: local=1 select local port otherwise a far device is reached
+ * @destid: Destination ID of the device to check host bit
+ * @hopcount: Number of hops to reach the target
+ * @port_num: Port (-number on switch) to enable on a far end device
+ *
+ * Returns 0 or 1 from on General Control Command and Status Register
+ * (EXT_PTR+0x3C)
+ */
+static int rio_enable_dio(struct rio_mport *port,
+			  int local, u16 destid,
+			  u8 hopcount, u8 port_num)
+{
+	int rc = 0;
+
+#ifdef CONFIG_RAPIDIO_ENABLE_RX_TX_PORTS
+	u32 regval;
+	u32 ext_ftr_ptr;
+
+
+	rc = rio_mport_get_physefb(port, local, destid, hopcount, &ext_ftr_ptr);
+	if (rc)
+		goto done;
+	if (local)
+		rc = rio_local_read_config_32(port, ext_ftr_ptr +
+					      RIO_PORT_N_CTL_CSR(0),
+					      &regval);
+	else
+		rc = rio_mport_read_config_32(port, destid, hopcount,
+					      ext_ftr_ptr +
+						RIO_PORT_N_CTL_CSR(port_num),
+					      &regval);
+	if (rc)
+		goto done;
+
+	if (regval & RIO_PORT_N_CTL_P_TYP_SER)
+		/* serial */
+		regval = regval | RIO_PORT_N_CTL_EN_RX_SER
+			| RIO_PORT_N_CTL_EN_TX_SER;
+	else
+		/* parallel */
+		regval = regval | RIO_PORT_N_CTL_EN_RX_PAR
+			| RIO_PORT_N_CTL_EN_TX_PAR;
+
+	if (local)
+		rc = rio_local_write_config_32(port, ext_ftr_ptr +
+					       RIO_PORT_N_CTL_CSR(0), regval);
+	else
+		rc = rio_mport_write_config_32(port, destid, hopcount,
+					       ext_ftr_ptr +
+						RIO_PORT_N_CTL_CSR(port_num),
+					       regval);
+done:
+#endif
+	return rc;
+}
+
+static int switch_port_is_active(struct rio_dev *rdev, int sport, u8 *active)
+{
+	u32 result = 0;
+	u32 ext_ftr_ptr;
+	int rc;
+
+	rc = rio_mport_get_efb(rdev->hport, 0,
+			       rdev->destid, rdev->hopcount,
+			       0, &ext_ftr_ptr);
+	if (rc)
+		goto access_err;
+	while (ext_ftr_ptr) {
+		rc = rio_read_config_32(rdev, ext_ftr_ptr, &result);
+		if (rc)
+			goto access_err;
+
+		result = RIO_GET_BLOCK_ID(result);
+		if ((result == RIO_EFB_SER_EP_FREE_ID) ||
+		    (result == RIO_EFB_SER_EP_FREE_ID_V13P) ||
+		    (result == RIO_EFB_SER_EP_FREC_ID))
+			break;
+
+		rc = rio_mport_get_efb(rdev->hport, 0, rdev->destid,
+				       rdev->hopcount, ext_ftr_ptr,
+				       &ext_ftr_ptr);
+		if (rc)
+			goto access_err;
+	}
+
+	if (ext_ftr_ptr) {
+		rc = rio_get_err_and_status(rdev, sport, &result);
+		if (rc)
+			goto access_err;
+	}
+	*active = (result & RIO_PORT_N_ERR_STS_PORT_OK ? 1 : 0);
+done:
+	return rc;
+access_err:
+	pr_warn("RIO:(%s) Access err at destid %hu hop %d\n",
+		__func__, rdev->destid, rdev->hopcount);
+	goto done;
+}
+
+static int rio_disc_switch_port(struct rio_job *job, struct rio_dev *rdev,
+				int port_num, u16 *destid, int tmo)
+{
+	int rc;
+	u8 route_port;
+	u16 tmp_dst;
+
+	rc = rio_job_hw_lock_wait(job, NULL, NULL, rdev->destid,
+				  rdev->hopcount, tmo);
+	if ((rdev->use_hw_lock) && (rc != 0))
+		goto done;
+
+	for (tmp_dst = 0;
+	     tmp_dst < RIO_ANY_DESTID(job->mport->sys_size);
+	     tmp_dst++) {
+		rc = rdev->rswitch->get_entry(rdev->hport, rdev->destid,
+					      rdev->hopcount, RIO_GLOBAL_TABLE,
+					      tmp_dst, &route_port);
+		if (rc)
+			goto unlock;
+
+		if (route_port == port_num) {
+			if (tmp_dst != RIO_ANY_DESTID(job->mport->sys_size)) {
+				*destid = tmp_dst;
+				break;
+			}
+		}
+	}
+unlock:
+	if (rdev->use_hw_lock)
+		rio_hw_unlock(job->mport, rdev->destid, rdev->hopcount);
+done:
+	return rc;
+}
+
+static int rio_get_enum_boundary(struct rio_dev *rdev, int port_num, u8 *remote)
+{
+	u32 regval;
+	int rc;
+
+	rc = rio_mport_read_config_32(rdev->hport, rdev->destid,
+				      rdev->hopcount,
+				      rdev->phys_efptr +
+				      RIO_PORT_N_CTL_CSR(port_num),
+				      &regval);
+	if (rc)
+		return rc;
+
+	*remote = (regval & RIO_PORT_N_CTL_ENUM_BOUNDARY ? 1 : 0);
+	pr_debug("RIO: %s port %d (%8.8x) links to %s\n",
+		 rio_name(rdev), port_num, regval,
+		 (*remote ? "enum boundary" : "local domain"));
+	return rc;
+}
+
+static int rio_is_remote_domain(struct rio_dev *rdev, int port_num, u8 *remote)
+{
+	int rc = 0;
+
+	if (!rdev->local_domain)
+		*remote = 1;
+	else
+		rc = rio_get_enum_boundary(rdev, port_num, remote);
+
+	return rc;
+}
+static u8 __get_lock_mode(struct rio_mport *mport,
+			  u16 parent_destid, int prev_port,
+			  u8 hopcount)
+{
+	u8 lock_hw = 1, tmp;
+
+	if (rio_dest_is_legacy(mport, parent_destid, prev_port, hopcount)) {
+		if ((rio_get_legacy_properties(mport, parent_destid, prev_port,
+					       hopcount, &lock_hw,
+					       &tmp)))
+			return 1;
+	}
+	return lock_hw;
+}
+static int rio_enum_start(struct rio_job *job)
+{
+	int rc = -EFAULT;
+	struct rio_dev *from = NULL;
+	struct rio_dev *to = job->rdev;
+
+	if (job->rdev) {
+		from = rio_get_root_node(job->mport);
+		if (IS_ERR(from))
+			return 0;
+		pr_debug("RIO: lock net from %s to %s\n",
+			 rio_name(from), rio_name(to));
+		rc = rio_job_hw_lock_wait(job, from, to, 0, 0, 10);
+		rio_dev_put(from);
+	} else {
+		u8 lock_mode = __get_lock_mode(job->mport, -1, -1, -1);
+
+		if (lock_mode) {
+			pr_debug("RIO: lock master port\n");
+			rc = rio_job_hw_lock_wait(job, NULL, NULL,
+						  job->mport->host_deviceid,
+						  0, 10);
+		} else {
+			rc = 0;
+		}
+	}
+	return rc;
+}
+
+static int rio_enum_complete(struct rio_mport *mport, u16 destid, u8 hopcount)
+{
+	u32 phys_efptr = 0;
+	u32 result;
+	int rc;
+
+	rc = rio_mport_get_physefb(mport, 0, destid, hopcount, &phys_efptr);
+	if (rc)
+		return rc;
+
+	rc = rio_mport_read_config_32(mport, destid, hopcount,
+					   phys_efptr + RIO_PORT_GEN_CTL_CSR,
+					   &result);
+	if (rc < 0)
+		return rc;
+
+	if (result & RIO_PORT_GEN_DISCOVERED) {
+		pr_debug("RIO: dest %hu hop %hhu Domain enumeration completed %8.8x\n",
+			 destid, hopcount, result);
+		return 0;
+	} else {
+		pr_debug("RIO: dest %hu hop %hhu Domain enumeration NOT completed %8.8x\n",
+			 destid, hopcount, result);
+		return -ETIME;
+	}
+}
+
+/**
+ * rio_mport_enum_complete- Tests if enumeration of a network is complete
+ * @port: Master port to send transaction
+ *
+ * Tests the Component Tag CSR for non-zero value (enumeration
+ * complete flag). Return %1 if enumeration is complete or %0 if
+ * enumeration is incomplete.
+ */
+static int rio_mport_enum_complete(struct rio_mport *port, u16 destid,
+				   u8 hopcount)
+{
+	u32 regval;
+
+	rio_local_read_config_32(port, port->phys_efptr + RIO_PORT_GEN_CTL_CSR,
+				 &regval);
+
+	return (regval & RIO_PORT_GEN_DISCOVERED) ? 1 : 0;
+}
+
+static int rio_init_net(struct rio_mport *mport, int *comptag)
+{
+	int net_id = 0;
+	int rc = 0;
+
+	spin_lock(&mport->net.tree_lock);
+
+	if (atomic_read(&mport->net.rio_dev_num) != 0)
+		goto err_unlock;
+
+	spin_unlock(&mport->net.tree_lock);
+
+	rc = rio_get_next_netid(mport->host_deviceid, &net_id, comptag);
+	if (rc) {
+		pr_warn("RIO: Failed to get net id\n");
+		goto done;
+	}
+	rc = rio_pin_netid(mport->host_deviceid, net_id);
+	if (rc) {
+		pr_warn("RIO: Failed to lock net id\n");
+		goto done;
+	}
+	mport->net.id = net_id;
+
+done:
+	return rc;
+
+err_unlock:
+	spin_unlock(&mport->net.tree_lock);
+	pr_warn("RIO: Master port net is not empty\n");
+	rc = -EINVAL;
+	goto done;
+}
+
+/**
+ * rio_init_em - Initializes RIO Error Management (for switches)
+ * @rdev: RIO device
+ *
+ * For each enumerated switch, call device-specific error management
+ * initialization routine (if supplied by the switch driver).
+ */
+static void rio_init_em(struct rio_dev *rdev)
+{
+	if (rio_is_switch(rdev) && (rdev->em_efptr) && (rdev->rswitch->em_init))
+		rdev->rswitch->em_init(rdev);
+}
+static void rio_net_register_devices(struct rio_mport *mport)
+{
+	int i, num_dev = 0;
+	int cleanup_all = 0;
+	struct rio_dev *tmp;
+	struct rio_dev **dptr = rio_get_tagged_devices(mport,
+						       RIO_DEV_NOT_ADDED,
+						       &num_dev);
+
+	if (!dptr) {
+		pr_info("RIO: No new deviced detected when scanning net\n");
+		return;
+	}
+	if (IS_ERR(dptr)) {
+		pr_warn("RIO: Out of memory - detected devices are not added\n");
+		return;
+	}
+	if (rio_update_routes(mport, dptr, num_dev)) {
+		cleanup_all = 1;
+		pr_warn("RIO: update routes failed\n");
+	}
+	for (i = 0; i < num_dev; i++) {
+		struct rio_dev *rdev = dptr[i];
+		int disabled, access = 1;
+
+		if (unlikely(!rdev))
+			continue;
+
+		if (cleanup_all)
+			goto cleanup;
+
+		spin_lock(&mport->net.tree_lock);
+		disabled = radix_tree_tag_get(&mport->net.dev_tree,
+					      rdev->destid,
+					      RIO_DEV_DISABLED);
+		if (disabled) {
+			if ((rio_device_enable(rdev))) {
+				spin_unlock(&mport->net.tree_lock);
+				pr_warn("RIO: Error when enabling device %s\n",
+					rio_name(rdev));
+				goto cleanup;
+			}
+			tmp = radix_tree_tag_clear(&mport->net.dev_tree,
+						   rdev->destid,
+						   RIO_DEV_DISABLED);
+			if (tmp != rdev) {
+				pr_warn("RIO: Error when clearing tag %i form device %s\n",
+					RIO_DEV_DISABLED, rio_name(rdev));
+				goto cleanup;
+			}
+		}
+		spin_unlock(&mport->net.tree_lock);
+		rio_tree_write_lock();
+		if (rio_add_device(rdev)) {
+			pr_warn("RIO: Error when adding device %s to kernel model\n",
+				rio_name(rdev));
+			rio_tree_write_unlock();
+			goto cleanup;
+		} else {
+			spin_lock(&mport->net.tree_lock);
+			tmp = radix_tree_tag_clear(&mport->net.dev_tree,
+						   rdev->destid,
+						   RIO_DEV_NOT_ADDED);
+			spin_unlock(&mport->net.tree_lock);
+			if (tmp != rdev) {
+				pr_warn("RIO: Error when clearing tag %i form device %s\n",
+					RIO_DEV_NOT_ADDED, rio_name(rdev));
+				rio_tree_write_unlock();
+				goto cleanup;
+			}
+		}
+		rio_tree_write_unlock();
+		rio_dev_put(rdev);
+		continue;
+cleanup:
+		__rio_remove_device(rdev, access, 0);
+		rio_dev_put(rdev);
+	}
+	kfree(dptr);
+}
+
+static int rio_redundant_path(struct rio_mport *mport,
+			      struct rio_dev *prev, int prev_port,
+			      u16 destid, u8 hopcount, u8 lock_mode,
+			      u8 *redundant)
+{
+	u16 lock;
+	u32 comptag;
+	int rc = 0;
+
+	BUG_ON(!prev);
+
+	*redundant = rio_dest_is_redundant(mport, prev->destid,
+					   prev_port, hopcount);
+	if (*redundant)
+		goto out;
+
+	if (rdev_is_mport(prev))
+		goto out;
+
+	rc = rio_get_host_lock(prev->hport, destid, hopcount, &lock);
+	if (rc)
+		goto access_err;
+
+	if (lock == prev->hport->host_deviceid || !lock_mode) {
+		struct rio_dev *rdev;
+
+		rc = rio_read_comptag(prev->hport, destid, hopcount, &comptag);
+		if (rc)
+			goto access_err;
+
+		rdev = rio_get_comptag(mport, (u32)comptag);
+
+		if (rdev) {
+			rio_update_dst_tree(mport, prev->destid,
+					    prev_port, hopcount,
+					    rdev->destid,
+					    rdev->comp_tag, 1);
+
+			pr_debug("RIO: redundant path to %s\n",
+				 rio_name(rdev));
+			rio_dev_put(rdev);
+			*redundant = 1;
+		} else {
+			if (lock_mode)
+				goto lock_fault;
+		}
+	}
+out:
+	return rc;
+
+access_err:
+	pr_warn("RIO: Access fault at port %d destid %hu hopcount %d\n",
+		prev_port, destid, hopcount);
+	goto out;
+
+lock_fault:
+	pr_warn("RIO: %hu Unexpectedly owns lock on destid %hu hopcount %d\n",
+		lock, destid, hopcount);
+	rc = -EFAULT;
+	goto out;
+}
+
+int rio_device_enable(struct rio_dev *rdev)
+{
+	u32 result;
+	int rc = 0;
+
+	BUG_ON(!rdev->local_domain);
+
+	pr_debug("RIO: Enable device %s\n", rio_name(rdev));
+
+	/* Mark device as discovered and enable master */
+	rc = rio_read_config_32(rdev,
+				rdev->phys_efptr + RIO_PORT_GEN_CTL_CSR,
+				&result);
+	if (rc != 0)
+		goto abort;
+
+	result |= RIO_PORT_GEN_DISCOVERED | RIO_PORT_GEN_MASTER;
+	rc = rio_write_config_32(rdev,
+				 rdev->phys_efptr + RIO_PORT_GEN_CTL_CSR,
+				 result);
+	if (rc != 0)
+		goto abort;
+
+	if (rdev->use_hw_lock)
+		rc = rio_hw_unlock(rdev->hport, rdev->destid, rdev->hopcount);
+done:
+	return rc;
+abort:
+	pr_warn("RIO:(%s) RIO_PORT_GEN_CTL_CSR access fault\n",
+		__func__);
+	goto done;
+}
+
+int rio_device_disable(struct rio_dev *rdev)
+{
+	/* Mark device as undiscovered */
+	return rio_write_config_32(rdev,
+				   rdev->phys_efptr + RIO_PORT_GEN_CTL_CSR,
+				   0);
+}
+
+static int rio_enum_unlock(struct rio_mport *mport, struct rio_dev *rdev,
+			   u16 destid, u8 hopcount)
+{
+	u16 dest = (rdev ? rdev->destid : destid);
+	u8 hop = (rdev ? rdev->hopcount : hopcount);
+	int rc;
+
+	rc = rio_mport_chk_dev_access(mport, dest, hop);
+	if (rc)
+		return rc;
+	return rio_hw_unlock(mport, dest, hop);
+}
+
+static void do_port_cleanup(struct rio_dev *rdev, int port_num)
+{
+	struct rio_dev *next = lookup_rdev_next(rdev, port_num);
+
+	if (!IS_ERR(next)) {
+		rio_remove_devices(next, 0, 0);
+		rio_dev_put(next);
+	}
+	return;
+}
+
+static int rio_add_enum_device(struct rio_dev *prev, int prev_port,
+			       struct rio_dev *rdev, u16 tmp_destid)
+{
+	struct rio_mport *mport = rdev->hport;
+	int rc = 0;
+
+	BUG_ON(!prev);
+
+	if ((lookup_rdev(mport, rdev->destid)) == rdev)
+		return rc;
+
+	rc = rio_add_route_for_destid(mport, prev->destid,
+				      prev_port, rdev->destid, 0);
+	if (rc)
+		goto abort;
+
+	if (rio_is_switch(rdev)) {
+		rio_init_em(rdev);
+		rc = init_switch_pw(rdev);
+		if (rc)
+			goto cleanup;
+
+		rc = rio_init_lut(rdev, 0);
+		if (rc)
+			goto cleanup;
+
+	} else {
+		/* Enable Input Output Port (transmitter reviever) */
+		rio_enable_dio(mport, 0, rdev->destid, rdev->hopcount, 0);
+	}
+
+	rc = add_new_dev2tree(rdev, prev, prev->destid, prev_port);
+	if (rc)
+		goto cleanup;
+
+done:
+	return rc;
+cleanup:
+	rio_remove_route_for_destid(mport, rdev->destid, 0);
+
+abort:
+	pr_warn("RIO: bail and release lock on destid %hu at hp %d\n",
+		tmp_destid, rdev->hopcount);
+	if (rdev->use_hw_lock)
+		rio_enum_unlock(mport, NULL, tmp_destid, rdev->hopcount);
+	goto done;
+}
+
+static struct rio_dev *rio_alloc_new_device(struct rio_mport *mport,
+					    u16 destid, u8 hopcount,
+					    u16 parent_destid, int prev_port)
+{
+	struct rio_dev *rdev = NULL;
+	struct rio_switch *rswitch = NULL;
+	int rc;
+	size_t size;
+	u32 result, swpinfo = 0;
+
+	size = sizeof(struct rio_dev);
+
+	rc = rio_mport_read_config_32(mport, destid, hopcount,
+				      RIO_PEF_CAR, &result);
+	if (rc)
+		goto access_err;
+
+	if (result & (RIO_PEF_SWITCH | RIO_PEF_MULTIPORT)) {
+		rc = rio_mport_read_config_32(mport, destid, hopcount,
+					      RIO_SWP_INFO_CAR, &swpinfo);
+		if (rc)
+			goto access_err;
+
+		if (result & RIO_PEF_SWITCH)
+			size += sizeof(*rswitch);
+	}
+	rdev = kzalloc(size, GFP_KERNEL);
+	if (!rdev)
+		return ERR_PTR(-ENOMEM);
+
+	rdev->hport = mport;
+	rdev->pef = result;
+	rdev->swpinfo = swpinfo;
+	rdev->prev_port = prev_port;
+	rdev->prev_destid = parent_destid;
+
+	rc = rio_mport_read_config_32(mport, destid, hopcount,
+				      RIO_DEV_ID_CAR, &result);
+	if (rc)
+		goto access_err;
+
+	rdev->did = result >> 16;
+	rdev->vid = result & 0xffff;
+	rc = rio_mport_read_config_32(mport, destid, hopcount,
+				      RIO_DEV_INFO_CAR, &rdev->device_rev);
+	if (rc)
+		goto access_err;
+
+	rc = rio_mport_read_config_32(mport, destid, hopcount,
+				      RIO_ASM_ID_CAR, &result);
+	if (rc)
+		goto access_err;
+
+	rdev->asm_did = result >> 16;
+	rdev->asm_vid = result & 0xffff;
+	rc = rio_mport_read_config_32(mport, destid, hopcount,
+				      RIO_ASM_INFO_CAR, &result);
+	if (rc)
+		goto access_err;
+
+	rdev->asm_rev = result >> 16;
+	if (rdev->pef & RIO_PEF_EXT_FEATURES) {
+		rdev->efptr = result & 0xffff;
+		rc = rio_mport_get_physefb(mport, 0, destid,
+					   hopcount, &rdev->phys_efptr);
+		if (rc)
+			goto access_err;
+
+		rc = rio_mport_get_feature(mport, 0, destid,
+					   hopcount, RIO_EFB_ERR_MGMNT,
+					   &rdev->em_efptr);
+		if (rc)
+			goto access_err;
+	}
+
+	rc = rio_mport_read_config_32(mport, destid, hopcount,
+				      RIO_SRC_OPS_CAR, &rdev->src_ops);
+	if (rc)
+		goto access_err;
+
+	rc = rio_mport_read_config_32(mport, destid, hopcount,
+				      RIO_DST_OPS_CAR, &rdev->dst_ops);
+	if (rc)
+		goto access_err;
+
+	return rdev;
+
+access_err:
+	pr_warn("RIO: RIO:(%s) destid %hx hopcount %d - ACCESS ERROR\n",
+		__func__, destid, hopcount);
+
+	if (rdev && !IS_ERR(rdev))
+		kfree(rdev);
+
+	return ERR_PTR(rc);
+}
+
+static struct rio_dev *rio_alloc_mport_device(struct rio_mport *mport)
+{
+	struct rio_dev *rdev = NULL;
+	int rc;
+	size_t size;
+	u32 result;
+
+	size = sizeof(struct rio_dev);
+
+	rc = rio_local_read_config_32(mport, RIO_PEF_CAR, &result);
+	if (rc)
+		goto access_err;
+
+	rdev = kzalloc(size, GFP_KERNEL);
+	if (!rdev)
+		return ERR_PTR(-ENOMEM);
+
+	rdev->hport = mport;
+	rdev->pef = result;
+	rdev->swpinfo = 0;
+	rdev->prev_destid = RIO_INVALID_DESTID;
+	rdev->prev_port = -1;
+
+	rc = rio_local_read_config_32(mport, RIO_DEV_ID_CAR, &result);
+	if (rc)
+		goto access_err;
+
+	rdev->did = result >> 16;
+	rdev->vid = result & 0xffff;
+	rc = rio_local_read_config_32(mport, RIO_DEV_INFO_CAR,
+				      &rdev->device_rev);
+	if (rc)
+		goto access_err;
+
+	rc = rio_local_read_config_32(mport, RIO_ASM_ID_CAR, &result);
+	if (rc)
+		goto access_err;
+
+	rdev->asm_did = result >> 16;
+	rdev->asm_vid = result & 0xffff;
+	rc = rio_local_read_config_32(mport, RIO_ASM_INFO_CAR, &result);
+	if (rc)
+		goto access_err;
+
+	rdev->asm_rev = result >> 16;
+	if (rdev->pef & RIO_PEF_EXT_FEATURES) {
+		rdev->efptr = result & 0xffff;
+		rc = rio_mport_get_physefb(mport, 1, mport->host_deviceid,
+					   0, &rdev->phys_efptr);
+		if (rc)
+			goto access_err;
+
+		rc = rio_mport_get_feature(mport, 1, mport->host_deviceid,
+					   0 , RIO_EFB_ERR_MGMNT,
+					   &rdev->em_efptr);
+		if (rc)
+			goto access_err;
+	}
+
+	rc = rio_local_read_config_32(mport, RIO_SRC_OPS_CAR, &rdev->src_ops);
+	if (rc)
+		goto access_err;
+
+	rc = rio_local_read_config_32(mport, RIO_DST_OPS_CAR, &rdev->dst_ops);
+	if (rc)
+		goto access_err;
+
+	rc = rio_local_read_config_32(mport, RIO_COMPONENT_TAG_CSR,
+				      &rdev->comp_tag);
+	if (rc)
+		goto access_err;
+
+	return rdev;
+
+access_err:
+	pr_warn("RIO: RIO:(%s) destid %hx - ACCESS ERROR\n",
+		__func__, mport->host_deviceid);
+	kfree(rdev);
+
+	return ERR_PTR(rc);
+}
+
+static void rio_dev_init(struct rio_dev *rdev)
+{
+	rdev->dev.bus = &rio_bus_type;
+	rdev->dev.parent = &rio_bus;
+
+	device_initialize(&rdev->dev);
+	rdev->dev.release = rio_release_dev;
+	rio_dev_get(rdev);
+
+	rdev->dma_mask = DMA_BIT_MASK(32);
+	rdev->dev.dma_mask = &rdev->dma_mask;
+	rdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+
+	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);
+}
+
+static struct rio_dev *rio_setup_disc_mport(struct rio_mport *mport,
+					    int do_enum)
+{
+	struct rio_dev *rdev = rio_alloc_mport_device(mport);
+	u8 lock_hw = 1, dummy;
+	int rc;
+
+	if (IS_ERR(rdev))
+		return rdev;
+
+	if (rio_dest_is_legacy(mport, -1, -1, -1)) {
+		rc = rio_get_legacy_properties(mport, -1, -1, -1,
+					       &lock_hw, &dummy);
+		if (rc)
+			goto cleanup;
+	} else {
+		pr_debug("RIO: Failed to lookup destid info for mport, using default flags\n");
+		rc = rio_update_dst_tree(mport, -1, -1, -1,
+					 mport->host_deviceid,
+					 mport->host_deviceid, 0);
+		if (rc)
+			goto cleanup;
+	}
+	rdev->local_domain = do_enum;
+	rdev->destid = mport->host_deviceid;
+	rdev->hopcount = 0xff;
+	rdev->use_hw_lock = lock_hw;
+
+	if (rio_eval_destid(rdev)) {
+		rc = -EINVAL;
+		goto cleanup;
+	}
+	dev_set_name(&rdev->dev, "%02x:m:%04x", rdev->hport->net.id,
+		     rdev->destid);
+	rio_dev_init(rdev);
+	return rdev;
+
+cleanup:
+	kfree(rdev);
+	return ERR_PTR(rc);
+}
+
+static struct rio_dev *rio_setup_enum_device(struct rio_mport *mport,
+					     u16 prev_destid, int prev_port,
+					     u16 destid, u8 hopcount)
+{
+	struct rio_dev *rdev;
+	int device_comptag;
+	u16 device_destid;
+	u8 lock_hw = 1, lut_update = 1;
+	int rc;
+
+	rc = rio_get_next_destid(mport, prev_destid,
+				 prev_port, hopcount,
+				 &device_destid, &device_comptag);
+	if (rc) {
+		pr_warn("RIO: Failed to get destid\n");
+		return ERR_PTR(rc);
+	}
+
+	rdev = lookup_rdev(mport, device_destid);
+	if (rdev)
+		/* dev is already known and added - return ptr */
+		return rdev;
+
+	rdev = rio_alloc_new_device(mport, destid, hopcount,
+				    prev_destid, prev_port);
+	if (IS_ERR(rdev))
+		return rdev;
+
+	rdev->local_domain = 1;
+	if (rio_dest_is_legacy(mport, prev_destid, prev_port, hopcount)) {
+		rc = rio_get_legacy_properties(mport, prev_destid, prev_port,
+					       hopcount, &lock_hw,
+					       &lut_update);
+		if (rc)
+			goto cleanup;
+	}
+	rdev->use_hw_lock = lock_hw;
+
+	rio_fixup_dev(rio_fixup_early, rdev, destid, hopcount);
+	/* Assign component tag to device */
+	if (device_comptag >= 0x10000) {
+		pr_warn("RIO: Component Tag Counter Overflow\n");
+		rc = -EFAULT;
+		goto cleanup;
+	}
+	rio_mport_write_config_32(mport, destid, hopcount,
+				  RIO_COMPONENT_TAG_CSR, device_comptag);
+	rdev->comp_tag = device_comptag;
+	rdev->hopcount = hopcount;
+	rio_assign_destid(rdev, mport, destid, hopcount, &device_destid);
+	if (rio_eval_destid(rdev)) {
+		rc = -EINVAL;
+		goto cleanup;
+	}
+	if (rio_is_switch(rdev)) {
+		rdev->return_port = RIO_GET_PORT_NUM(rdev->swpinfo);
+
+		if (rio_dest_is_one_way(mport, prev_destid,
+					prev_port, hopcount)) {
+			rc = rio_get_return_port(mport, prev_destid, prev_port,
+						 hopcount, &rdev->return_port);
+			if (rc)
+				goto cleanup;
+		}
+
+		rdev->rswitch->switchid = rdev->comp_tag & RIO_CTAG_UDEVID;
+		rdev->rswitch->update_lut = lut_update;
+
+		dev_set_name(&rdev->dev, "%02x:s:%04x", rdev->hport->net.id,
+			     rdev->rswitch->switchid);
+		rio_switch_init(rdev, 1);
+		if (rdev->rswitch->clr_table)
+			rdev->rswitch->clr_table(mport, destid, hopcount,
+						 RIO_GLOBAL_TABLE);
+	} else {
+		dev_set_name(&rdev->dev, "%02x:e:%04x", rdev->hport->net.id,
+			     rdev->destid);
+	}
+	rio_dev_init(rdev);
+	return rdev;
+
+cleanup:
+	kfree(rdev);
+
+	return ERR_PTR(rc);
+}
+static int rio_enum(struct rio_job *job,
+		    struct rio_dev *prev,
+		    u16 prev_destid, int prev_port,
+		    u8 hopcount)
+{
+	int rc = 0;
+	struct rio_mport *mport = job->mport;
+	struct rio_dev *rdev = NULL;
+	u8 lock_mode = __get_lock_mode(mport, prev_destid, prev_port, hopcount);
+	u8 redundant;
+
+	pr_debug("RIO: rio_enum prev_dest %hx, prev_port %d hop %hhu\n",
+		 prev_destid, prev_port, hopcount);
+
+	rc = rio_redundant_path(mport, prev, prev_port,
+				RIO_ANY_DESTID(job->mport->sys_size),
+				hopcount, lock_mode, &redundant);
+	if (rc || redundant)
+		goto done;
+
+	if (lock_mode) {
+		rc = rio_job_hw_lock_wait(job, NULL, NULL,
+					  RIO_ANY_DESTID(job->mport->sys_size),
+					  hopcount, 1);
+		if (unlikely(rc))
+			goto done;
+	}
+
+	rdev = rio_setup_enum_device(mport, prev_destid, prev_port,
+				     RIO_ANY_DESTID(job->mport->sys_size),
+				     hopcount);
+
+	if (unlikely(IS_ERR(rdev))) {
+		rc = PTR_ERR(rdev);
+		goto unlock;
+	}
+	rc = rio_add_enum_device(prev, prev_port, rdev,
+				 RIO_ANY_DESTID(job->mport->sys_size));
+	if (unlikely(rc))
+		goto done;
+
+	if (rio_is_switch(rdev)) {
+		int port_num;
+		int sw_inport;
+		int num_ports;
+
+		sw_inport = RIO_GET_PORT_NUM(rdev->swpinfo);
+		num_ports = RIO_GET_TOTAL_PORTS(rdev->swpinfo);
+
+		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 = 0; port_num < num_ports; port_num++) {
+			u8 remote = 0, active = 0;
+			if (lock_mode)
+				rc = rio_enable_dio(rdev->hport, 0,
+						    rdev->destid,
+						    rdev->hopcount,
+						    port_num);
+				if (rc < 0)
+					goto unlock;
+			if (sw_inport == port_num) {
+				if (rdev_is_mport(prev)) {
+					rio_update_dst_tree(job->mport,
+							    rdev->destid,
+							    port_num,
+							    hopcount + 1,
+							    prev->destid,
+							    prev->comp_tag,
+							    0);
+				}
+				continue;
+			}
+			rc = switch_port_is_active(rdev, port_num, &active);
+			if (rc < 0)
+				goto unlock;
+			if (!active) {
+				do_port_cleanup(rdev, port_num);
+				continue;
+			}
+
+			rc = rio_get_enum_boundary(rdev, port_num, &remote);
+			if (rc < 0)
+				goto unlock;
+
+			if (remote)
+				continue;
+
+			rc = rio_route_add(rdev, RIO_GLOBAL_TABLE,
+					   RIO_ANY_DESTID(mport->sys_size),
+					   port_num, 0);
+			if (rc < 0)
+				goto unlock;
+
+			rc = rio_enum(job, rdev, rdev->destid, port_num,
+				      hopcount + 1);
+			if (rc)
+				return rc;
+		}
+	} else {
+		pr_debug("RIO: found ep %s (vid %4.4x did %4.4x)\n",
+			 rio_name(rdev), rdev->vid, rdev->did);
+	}
+
+	/* final fixup pass for device */
+	rio_fixup_dev(rio_fixup_enable, rdev, rdev->destid, rdev->hopcount);
+done:
+	if (rdev && !IS_ERR(rdev))
+		rio_dev_put(rdev);
+	if (rc != RIO_JOB_STATE_ABORT)
+		return 0;
+	return rc;
+unlock:
+	if (IS_ERR(rdev))
+		rdev = NULL;
+	if (lock_mode)
+		rio_enum_unlock(mport, rdev,
+				RIO_ANY_DESTID(job->mport->sys_size),
+				hopcount);
+	goto done;
+}
+
+static int __rio_mport_net_empty(struct rio_mport *mport)
+{
+	int empty = 0;
+
+	spin_lock(&mport->net.tree_lock);
+	if (atomic_read(&mport->net.rio_dev_num) != 0) {
+		pr_debug("RIO: Master port Net devices - list not empty\n");
+	} else {
+		pr_debug("RIO: Master port Net devices - list empty\n");
+		empty = 1;
+	}
+	spin_unlock(&mport->net.tree_lock);
+	return empty;
+}
+
+static int rio_dev_local(struct rio_job *job, u8 *remote)
+{
+	int rc = 0;
+
+	if (job->rdev) {
+		rc = rio_is_remote_domain(job->rdev, job->port, remote);
+		if (rc < 0)
+			return rc; /* access fault */
+
+		pr_debug("RIO: Insertion at port %d in %s domain\n",
+			 job->port, (*remote ? "remote" : "local"));
+	} else {
+		*remote = (job->mport->enum_host ? 0 : 1);
+		pr_debug("RIO: %s Master port - %s\n",
+			 (*remote ? "Discover" : "Enum"),
+			 (__rio_mport_net_empty(job->mport) ?
+			  "net empty" : "net exists"));
+	}
+
+	return rc;
+}
+
+static struct rio_dev *rio_enum_master_port(struct rio_job *job)
+{
+	struct rio_dev *rdev = NULL;
+	int comptag = 1;
+	int rc;
+
+	printk(KERN_INFO "RIO: enumerate master port %d, %s\n", job->mport->id,
+	       job->mport->name);
+
+	if (!rio_mport_active(job->mport)) {
+		pr_warn("RIO: master port %d link inactive\n",
+			job->mport->id);
+		return ERR_PTR(-ENODEV);
+	}
+	/* If master port has an active link, allocate net and enum peers */
+	rc = rio_init_net(job->mport, &comptag);
+	if (rc < 0) {
+		pr_warn("RIO: failed to init new net\n");
+		return ERR_PTR(rc);
+	}
+	pr_debug("RIO:(%s) set master destid %hu\n",
+		 __func__, job->mport->host_deviceid);
+	/* Set master port destid and init destid ctr */
+	rio_set_master_destid(job->mport, job->mport->host_deviceid);
+	pr_debug("RIO:(%s) set master comptag %d\n", __func__,
+		 job->mport->host_deviceid);
+	/* Set component tag for host */
+	rio_local_write_config_32(job->mport, RIO_COMPONENT_TAG_CSR,
+				  job->mport->host_deviceid);
+	pr_debug("RIO:(%s) enable master DIO\n", __func__);
+	/* Enable Input Output Port (transmitter reviever) */
+	rio_enable_dio(job->mport, 1, 0, 0, 0);
+	rdev = rio_setup_disc_mport(job->mport, 1);
+
+	return rdev;
+}
+
+static int rio_add_device_local(struct rio_job *job)
+{
+	int rc;
+	struct rio_dev *rdev = job->rdev;
+	struct rio_mport *mport = job->mport;
+	int port_num;
+	u8 hopcount;
+
+	pr_debug("RIO: Handle job in local domain\n");
+	rc = rio_enum_start(job);
+	if (rc)
+		return rc;
+
+	if (!rdev) {
+		rdev = rio_enum_master_port(job);
+
+		if (unlikely(IS_ERR(rdev))) {
+			rc = PTR_ERR(rdev);
+			rdev = NULL;
+			goto mport_unlock;
+		}
+		rc = add_new_dev2tree(rdev, NULL, RIO_INVALID_DESTID, -1);
+		if (rc) {
+			pr_warn("RIO: add master port to tree failed\n");
+			goto mport_unlock;
+		}
+		if (job->mport->ops->pwenable)
+			job->mport->ops->pwenable(job->mport, 1);
+
+		port_num = -1;
+		hopcount = 0;
+	} else {
+		u8 port_active;
+
+		port_num = job->port;
+		hopcount = rdev->hopcount + 1;
+
+		rc = switch_port_is_active(rdev, port_num, &port_active);
+		if (rc < 0)
+			goto unlock;
+
+		if (!port_active)
+			goto unlock;
+
+		rc = rio_add_route_for_destid(mport, rdev->destid, port_num,
+					      RIO_ANY_DESTID(mport->sys_size),
+					      0);
+		if (rc < 0)
+			goto unlock;
+
+	}
+
+	rc = rio_enum(job, rdev, rdev->destid, port_num, hopcount);
+
+done:
+	if (rdev && rdev_is_mport(rdev))
+		rio_dev_put(rdev);
+unlock:
+	rio_job_hw_unlock_devices(job);
+	return rc;
+mport_unlock:
+	rio_hw_unlock(job->mport, job->mport->host_deviceid, 0);
+	goto done;
+}
+
+static int rio_add_disc_device(struct rio_dev *prev, int prev_port,
+			       struct rio_dev *rdev, u16 tmp_destid)
+{
+	struct rio_mport *mport = rdev->hport;
+	int rc = 0;
+
+	BUG_ON(!prev);
+
+	if ((lookup_rdev(mport, rdev->destid)) == rdev)
+		return rc;
+
+	if (rdev->destid != tmp_destid) {
+		rc = rio_add_route_for_destid(mport, prev->destid, prev_port,
+					      rdev->destid, 1);
+		if (rc < 0)
+			goto cleanup;
+	}
+
+	if (rio_is_switch(rdev)) {
+		rc = rio_init_lut(rdev, 1);
+		if (rc)
+			goto cleanup;
+	}
+
+	rc = add_new_dev2tree(rdev, prev, prev->destid, prev_port);
+	if (rc)
+		goto cleanup;
+done:
+	return rc;
+cleanup:
+	rio_remove_route_for_destid(mport, rdev->destid, 0);
+	pr_warn("RIO: bail on destid %hu at hp %d\n",
+		tmp_destid, rdev->hopcount);
+	goto done;
+}
+
+static struct rio_dev *rio_setup_disc_device(struct rio_mport *mport,
+					     u16 parent_destid, int prev_port,
+					     u16 destid, u8 hopcount)
+{
+	struct rio_dev *rdev = rio_alloc_new_device(mport, destid, hopcount,
+						    parent_destid, prev_port);
+	u8 lock_hw = 1, lut_update = 1;
+	int rc;
+
+	if (IS_ERR(rdev))
+		return rdev;
+
+	rdev->local_domain = 0;
+	rc = rio_read_comptag(mport, destid, hopcount, &rdev->comp_tag);
+	if (rc)
+		goto access_err;
+
+	if (rio_has_destid(rdev->src_ops, rdev->dst_ops)) {
+		rc = rio_get_destid(mport, destid, hopcount, &rdev->destid);
+		if (rc)
+			goto access_err;
+	} else {
+		rdev->destid = rdev->comp_tag;
+	}
+	rdev->hopcount = hopcount;
+	if (rio_eval_destid(rdev)) {
+		rc = -EINVAL;
+		goto cleanup;
+	}
+	rc = rio_update_dst_tree(mport, parent_destid, prev_port,
+				 rdev->hopcount, rdev->destid,
+				 rdev->comp_tag, 0);
+	if (rc)
+		goto cleanup;
+
+	if (rio_dest_is_legacy(mport, parent_destid,
+			       prev_port, rdev->hopcount)) {
+		rc = rio_get_legacy_properties(mport, parent_destid, prev_port,
+					       rdev->hopcount, &lock_hw,
+					       &lut_update);
+		if (rc)
+			goto cleanup;
+	}
+	rdev->use_hw_lock = lock_hw;
+
+	if (rio_is_switch(rdev)) {
+		rdev->return_port = RIO_GET_PORT_NUM(rdev->swpinfo);
+
+		if (rio_dest_is_one_way(mport, parent_destid,
+					prev_port, hopcount)) {
+			rc = rio_get_return_port(mport, parent_destid,
+						 prev_port, hopcount,
+						 &rdev->return_port);
+			if (rc)
+				goto cleanup;
+		}
+
+		rdev->rswitch->switchid = rdev->comp_tag & RIO_CTAG_UDEVID;
+		rdev->rswitch->update_lut = lut_update;
+
+		dev_set_name(&rdev->dev, "%02x:s:%04x", rdev->hport->net.id,
+			     rdev->rswitch->switchid);
+
+		rio_switch_init(rdev, 0);
+	} else {
+		dev_set_name(&rdev->dev, "%02x:e:%04x", rdev->hport->net.id,
+			     rdev->destid);
+	}
+	rio_dev_init(rdev);
+	return rdev;
+access_err:
+	pr_warn("RIO: RIO:(%s) destid %hx hopcount %d - ACCESS ERROR\n",
+		__func__, destid, hopcount);
+cleanup:
+	kfree(rdev);
+	return ERR_PTR(rc);
+}
+
+static int rio_disc(struct rio_job *job, struct rio_dev *prev,
+		    int prev_port, u16 destid, u8 hopcount,
+		    int tmo)
+{
+	int rc = 0;
+	struct rio_mport *mport = job->mport;
+	struct rio_dev *rdev = NULL;
+	u8 lock_mode = __get_lock_mode(mport, prev->destid,
+				       prev_port, hopcount);
+
+	pr_debug("RIO: do_disc prev %s, prev port %d, destid 0x%x, hop %hhu\n",
+		 rio_name(prev), prev_port, destid, hopcount);
+
+	if (job->flags & RIO_JOB_FLAG_STATIC) {
+		u16 tmp_dst;
+		/* destid node required if discover static */
+		if (rio_lookup_next_destid(mport, prev->destid, prev_port,
+					   hopcount, &tmp_dst)) {
+			pr_debug("RIO: No static destid found for device\n");
+			goto done;
+		}
+	}
+	rc = rio_job_hw_lock_wait_cond(job, destid, hopcount,
+				       tmo, lock_mode,
+				       rio_enum_complete);
+	if (unlikely(rc)) {
+		u32 tmp = 0;
+
+		rio_read_comptag(prev->hport, destid,
+				 hopcount, &tmp);
+		pr_warn("RIO: lock fail comptag %x\n", tmp);
+		goto done;
+	}
+	tmo = 1;
+	rdev = rio_setup_disc_device(mport, prev->destid,
+				     prev_port, destid, hopcount);
+	if (lock_mode)
+		rc = rio_hw_unlock(job->mport, destid, hopcount);
+
+	if (unlikely(IS_ERR(rdev)))
+		rc = PTR_ERR(rdev);
+
+	if (rc)
+		goto done;
+
+	rc = rio_add_disc_device(prev, prev_port, rdev, destid);
+	if (unlikely(rc))
+		goto done;
+
+	if (rio_is_switch(rdev)) {
+		int port_num;
+		int sw_inport;
+		int num_ports;
+
+		sw_inport = RIO_GET_PORT_NUM(rdev->swpinfo);
+		num_ports = RIO_GET_TOTAL_PORTS(rdev->swpinfo);
+
+		pr_debug("RIO: disc %s (vid %4.4x did %4.4x) with %d ports\n",
+			 rio_name(rdev), rdev->vid, rdev->did, num_ports);
+
+		for (port_num = 0;
+		     port_num < num_ports;
+		     port_num++) {
+			u8 active = 0;
+			u8 remote = 0;
+			u16 ndestid = RIO_ANY_DESTID(job->mport->sys_size);
+			u16 result = 0;
+
+			if (sw_inport == port_num) {
+				if (rdev_is_mport(prev)) {
+					rio_update_dst_tree(job->mport,
+							    rdev->destid,
+							    port_num,
+							    hopcount + 1,
+							    prev->destid,
+							    prev->comp_tag,
+							    0);
+				}
+				continue;
+			}
+			rc = switch_port_is_active(rdev, port_num, &active);
+			if (rc < 0)
+				goto done; /* switch fault during disc ?*/
+
+			if (!active) {
+				do_port_cleanup(rdev, port_num);
+				continue;
+			}
+			rc = rio_get_enum_boundary(rdev, port_num, &remote);
+			if (rc < 0)
+				goto done;
+
+			if (remote)
+				continue;
+
+			rc = rio_disc_switch_port(job, rdev, port_num,
+						  &ndestid, tmo);
+			if (rc < 0)
+				goto done; /* switch fault during disc ?*/
+
+			result = RIO_ANY_DESTID(job->mport->sys_size);
+			if (ndestid == result) {
+				pr_debug("RIO: No destid setup at active port %d\n",
+					 port_num);
+				continue;
+			}
+			rc = rio_add_route_for_destid(mport, rdev->destid,
+						      port_num, ndestid, 1);
+			if (rc != 0)
+				goto done; /* switch fault during disc ?*/
+
+			rc = rio_disc(job, rdev, port_num,
+				      ndestid, hopcount + 1, tmo);
+			if (rc)
+				return rc;
+		}
+	} else
+		pr_debug("RIO: disc ep %s (vid %4.4x did %4.4x)\n",
+			 rio_name(rdev), rdev->vid, rdev->did);
+done:
+	if (rdev && !IS_ERR(rdev))
+		rio_dev_put(rdev);
+
+	if (rc != RIO_JOB_STATE_ABORT)
+		return 0;
+	pr_debug("RIO: do_disc done rc %d\n", rc);
+	return rc;
+}
+
+static struct rio_dev *rio_disc_master_port(struct rio_job *job)
+{
+	struct rio_dev *rdev = NULL;
+	int comptag = 1;
+	int rc;
+
+	pr_debug("RIO: discover master port %d, %s\n", job->mport->id,
+		job->mport->name);
+
+	if (!rio_mport_active(job->mport))
+		goto link_fault;
+
+	if ((rio_job_hw_wait_cond(job, job->mport->host_deviceid, 0,
+				  CONFIG_RAPIDIO_DISC_TIMEOUT,
+				  rio_mport_enum_complete)) <= 0)
+		goto enum_to;
+
+	rio_local_read_config_32(job->mport, RIO_DID_CSR,
+				 &job->mport->host_deviceid);
+
+	job->mport->host_deviceid = RIO_GET_DID(job->mport->sys_size,
+						job->mport->host_deviceid);
+
+	if (rio_job_hw_lock_wait(job, NULL, NULL, job->mport->host_deviceid,
+				 0, CONFIG_RAPIDIO_DISC_TIMEOUT))
+		goto enum_to;
+
+	rc = rio_init_net(job->mport, &comptag);
+	if (rc < 0)
+		goto err_net;
+
+	rdev = rio_setup_disc_mport(job->mport, 0);
+unlock:
+	rio_hw_unlock(job->mport, job->mport->host_deviceid, 0);
+done:
+	return rdev;
+
+link_fault:
+	pr_warn("RIO: master port %d link inactive\n",
+		job->mport->id);
+	rdev = ERR_PTR(-ENODEV);
+	goto done;
+enum_to:
+	pr_warn("RIO: timeout waiting for enumeration complete\n");
+	job->mport->host_deviceid = RIO_ANY_ID;
+	rdev = ERR_PTR(-ETIME);
+	goto done;
+err_net:
+	pr_warn("RIO: failed to init new net\n");
+	job->mport->host_deviceid = RIO_ANY_ID;
+	rdev = ERR_PTR(rc);
+	goto unlock;
+}
+
+static int rio_add_device_remote(struct rio_job *job)
+{
+	int rc = RIO_JOB_STATE_ABORT;
+	struct rio_dev *rdev = job->rdev;
+	struct rio_mport *mport = job->mport;
+	int port_num;
+	u8 hopcount;
+	u16 destid = RIO_ANY_DESTID(job->mport->sys_size);
+	int tmo;
+
+	pr_debug("RIO: Insertion in remote domains\n");
+	if (!rdev) {
+		rdev = rio_disc_master_port(job);
+
+		if (unlikely(IS_ERR(rdev)))
+			return PTR_ERR(rdev);
+
+		rc = add_new_dev2tree(rdev, NULL, RIO_INVALID_DESTID, -1);
+		if (rc != 0)
+			goto done;
+
+		if (job->mport->ops->pwenable)
+			job->mport->ops->pwenable(job->mport, 1);
+
+		port_num = -1;
+		hopcount = 0;
+		tmo = 1;
+	} else {
+		u8 port_active;
+		port_num = job->port;
+		hopcount = rdev->hopcount + 1;
+		tmo = CONFIG_RAPIDIO_DISC_TIMEOUT;
+
+		rc = switch_port_is_active(rdev, port_num, &port_active);
+		if (rc < 0)
+			goto done;
+
+		if (!port_active)
+			goto done;
+		if (rdev->local_domain) {
+			rc = rio_add_route_for_destid(mport,
+						      rdev->destid,
+						      port_num,
+						      destid, 1);
+			if (rc != 0)
+				goto done;
+		} else {
+			rc = rio_disc_switch_port(job, rdev,
+						  port_num,
+						  &destid, tmo);
+			if (rc < 0)
+				goto done;
+			if (destid == RIO_ANY_DESTID(job->mport->sys_size))
+				goto done;
+			rc = rio_add_route_for_destid(mport,
+						      rdev->destid,
+						      port_num,
+						      destid, 1);
+			if (rc != 0)
+				goto done;
+		}
+	}
+	rc = rio_disc(job, rdev, port_num, destid, hopcount, tmo);
+done:
+	if (rdev_is_mport(rdev))
+		rio_dev_put(rdev);
+	return rc;
+}
+
+static int rio_remove(struct rio_job *job, struct rio_dev *rdev)
+{
+	int dev_access = (job->rdev ? 0 : 1);
+	int rc = 0;
+
+	rio_remove_devices(rdev, dev_access, job->srio_down);
+
+	return rc;
+}
+
+struct rio_dev *rio_remove_device_root(struct rio_job *job)
+{
+	struct rio_mport *mport = job->mport;
+	struct rio_dev *rdev = NULL;
+
+	BUG_ON(!mport);
+
+	if (!job->rdev)
+		rdev = rio_get_root_node(job->mport);
+	else
+		rdev = lookup_rdev_next(job->rdev, job->port);
+
+	if (!rdev || IS_ERR(rdev))
+		return ERR_PTR(-ENODEV);
+
+	return rdev;
+}
+
+static int rio_job_add_device(struct rio_job *job)
+{
+	int rc;
+	u8 remote = 0;
+
+	rc = rio_dev_local(job, &remote);
+	if (rc < 0) {
+		pr_warn("RIO: Can not handle job request\n");
+		return rc;
+	}
+	if (!remote) {
+		pr_debug("Handle local job\n");
+		rc = rio_add_device_local(job);
+	} else {
+		pr_debug("Handle remote job\n");
+		rc = rio_add_device_remote(job);
+	}
+	if (rc)
+		pr_warn("RIO: Job aborted rc %d\n", rc);
+
+	rio_net_register_devices(job->mport);
+	return rc;
+}
+
+static int rio_job_remove_device(struct rio_job *job)
+{
+	int rc;
+	struct rio_dev *rdev = NULL;
+
+	pr_debug("RIO: remove job\n");
+
+	rdev = rio_remove_device_root(job);
+	if (IS_ERR(rdev)) {
+		rc = PTR_ERR(rdev);
+		goto done;
+	}
+
+	rc = rio_remove(job, rdev);
+	rio_dev_put(rdev);
+
+	if (!rc) {
+		if (__rio_mport_net_empty(job->mport)) {
+			if (job->mport->ops->pwenable)
+				job->mport->ops->pwenable(job->mport, 0);
+			iosync();
+			if (rio_unlock_netid(job->mport->host_deviceid,
+					     job->mport->net.id))
+				pr_warn("RIO: Fail to unlock mport net_id %d\n",
+					job->mport->net.id);
+		}
+	}
+done:
+	if (rc)
+		pr_warn("RIO: remove job aborted rc %d\n", rc);
+	return rc;
+}
+
+int rio_job_init(struct rio_mport *mport, struct rio_dev *rdev,
+		 int port, u32 flags, int hw_access, int event)
+{
+	struct rio_job job;
+
+	job.rdev = rdev;
+	job.mport = mport;
+	job.flags = flags;
+	job.srio_down = (hw_access ? 0 : 1);
+	job.port = port;
+
+	if (event == RIO_DEVICE_INSERTION)
+		return rio_job_add_device(&job);
+	else if (event == RIO_DEVICE_EXTRACTION)
+		return rio_job_remove_device(&job);
+	else
+		return -EINVAL;
+}
diff --git a/drivers/rapidio/rio-quirks.c b/drivers/rapidio/rio-quirks.c
new file mode 100644
index 0000000..0a155f3
--- /dev/null
+++ b/drivers/rapidio/rio-quirks.c
@@ -0,0 +1,59 @@
+/*
+ * RapidIO quirk support - heavily inspired by drivers/pci/quirks.c
+ *
+ * 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/types.h>
+#include <linux/kernel.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 "rio.h"
+
+static void rio_dev_do_fixups(struct rio_dev *rdev,
+			      u16 destid,
+			      u8 hopcount,
+			      struct rio_dev_fixup *f,
+			      struct rio_dev_fixup *end)
+{
+	while (f < end) {
+		if ((f->vid == rdev->vid) && (f->did == rdev->did)) {
+			pr_debug("RIO: calling %pF\n", f->fixup_hook);
+			f->fixup_hook(rdev, destid, hopcount);
+		}
+		f++;
+	}
+}
+
+void rio_fixup_dev(enum rio_fixup_pass pass,
+		   struct rio_dev *rdev,
+		   u16 destid,
+		   u8 hopcount)
+{
+	struct rio_dev_fixup *start, *end;
+
+	switch (pass) {
+	case rio_fixup_early:
+		start = __start_rio_dev_fixup_early;
+		end = __end_rio_dev_fixup_early;
+		break;
+
+	case rio_fixup_enable:
+		start = __start_rio_dev_fixup_enable;
+		end = __end_rio_dev_fixup_enable;
+		break;
+
+	default:
+		return;
+	}
+	rio_dev_do_fixups(rdev, destid, hopcount, start, end);
+}
+EXPORT_SYMBOL(rio_fixup_dev);
diff --git a/drivers/rapidio/rio-route.c b/drivers/rapidio/rio-route.c
new file mode 100644
index 0000000..c0f3d9d
--- /dev/null
+++ b/drivers/rapidio/rio-route.c
@@ -0,0 +1,290 @@
+/*
+ * RapidIO route support
+ *
+ * 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/types.h>
+#include <linux/kernel.h>
+
+#include <linux/delay.h>
+#include <linux/dma-mapping.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 <linux/jiffies.h>
+#include <linux/slab.h>
+#include <linux/radix-tree.h>
+
+#include "rio.h"
+
+/**
+ * rio_route_add - Add a route entry to a switch routing table
+ * @rdev: RIO device
+ * @table: Routing table ID
+ * @route_destid: Destination ID to be routed
+ * @route_port: Port number to be routed
+ * @lock: lock switch device flag
+ *
+ * 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.
+ */
+int rio_route_add(struct rio_dev *rdev, u16 table, u16 route_destid,
+u8 route_port, int lock)
+{
+	int err = 0;
+	int rc = 0;
+
+	if (!(rdev->rswitch->update_lut))
+		return rc;
+
+	if (lock && rdev->use_hw_lock) {
+		rc = rio_hw_lock_wait(rdev->hport, rdev->destid,
+				      rdev->hopcount, 1);
+		if (rc)
+			return rc;
+	}
+
+	err = rdev->rswitch->add_entry(rdev->hport, rdev->destid,
+				       rdev->hopcount, table,
+				       route_destid, route_port);
+
+	if (lock && rdev->use_hw_lock)
+		rc = rio_hw_unlock(rdev->hport, rdev->destid,
+				   rdev->hopcount);
+
+	return err ? err : rc;
+}
+
+int rio_route_get_port(struct rio_dev *rdev, u16 destid, u8 *port, int lock)
+{
+	int rc = 0;
+
+	if (lock && rdev->use_hw_lock) {
+		rc = rio_hw_lock_wait(rdev->hport, rdev->destid,
+				      rdev->hopcount, 1);
+		if (rc)
+			return rc;
+	}
+
+	rdev->rswitch->get_entry(rdev->hport, rdev->destid,
+				 rdev->hopcount, RIO_GLOBAL_TABLE,
+				 destid, port);
+
+	if (lock && rdev->use_hw_lock)
+		rc = rio_hw_unlock(rdev->hport, rdev->destid,
+				   rdev->hopcount);
+
+	return rc;
+}
+
+int rio_add_route_for_destid(struct rio_mport *mport,
+			     u16 parent_dest, u8 port_num,
+			     u16 destid, int lock)
+{
+	struct rio_dev *curr;
+	u8 sport = port_num;
+	u16 curr_dest = parent_dest;
+	int rc = 0;
+
+	do {
+		curr = lookup_rdev(mport, curr_dest);
+		if (!curr)
+			break;
+
+		if (!rio_is_switch(curr) || !curr->rswitch->update_lut) {
+			rio_dev_put(curr);
+			break;
+		}
+		if (curr->local_domain) {
+
+			pr_debug("RIO: add route for %hhu in %s at port %d\n",
+				 destid, rio_name(curr), sport);
+
+			rc = rio_route_add(curr, RIO_GLOBAL_TABLE,
+					   destid,
+					   sport, lock);
+			if (rc < 0) {
+				rio_dev_put(curr);
+				break;
+			}
+		}
+		curr_dest = curr->prev_destid;
+		sport = curr->prev_port;
+		rio_dev_put(curr);
+
+	} while (curr_dest != RIO_INVALID_DESTID);
+
+	return rc;
+}
+int rio_remove_route_for_destid(struct rio_mport *mport, u16 destid, int lock)
+{
+	int i, num = 0, rc = 0;
+	struct rio_dev **dptr = rio_get_tagged_devices(mport,
+						       RIO_DEV_IS_SWITCH,
+						       &num);
+
+	if (!dptr)
+		return 0;
+	if (IS_ERR(dptr))
+		return PTR_ERR(dptr);
+
+	for (i = 0; i < num; i++) {
+		struct rio_dev *tmp = dptr[i];
+		if (unlikely(!tmp))
+			continue;
+		if (!tmp->local_domain || !tmp->rswitch->update_lut) {
+			rio_dev_put(tmp);
+			continue;
+		}
+		pr_debug("RIO:%s remove route for %hu in %s\n",
+			 __func__, destid, rio_name(tmp));
+
+		rc = rio_route_add(tmp, RIO_GLOBAL_TABLE,
+				   destid, RIO_INVALID_ROUTE, lock);
+		if (rc)
+			tmp->rswitch->update_lut = 0;
+		rio_dev_put(tmp);
+	}
+	if (dptr != NULL)
+		kfree(dptr);
+	return rc;
+}
+
+int rio_update_routes(struct rio_mport *mport, struct rio_dev **rptr, int rnum)
+{
+	int d, i, num = 0, rio_fault = 0, rc = 0;
+	struct rio_dev **dptr = rio_get_tagged_devices(mport,
+						       RIO_DEV_IS_SWITCH,
+						       &num);
+
+	if (!dptr)
+		return 0;
+	if (IS_ERR(dptr))
+		return PTR_ERR(dptr);
+
+	for (d = 0; d < rnum; d++) {
+		u16 destid;
+		u32 result;
+		if (rio_fault)
+			break;
+		if (!rptr[d])
+			continue;
+		destid = rptr[d]->destid;
+		for (i = 0; i < num; i++) {
+			u8 port, static_port = RIO_INVALID_ROUTE;
+			int disabled;
+			struct rio_dev *tmp = dptr[i];
+
+			if (!tmp)
+				continue;
+			if (tmp->destid == destid ||
+			    !tmp->local_domain ||
+			    !tmp->rswitch->update_lut)
+				continue;
+
+			rcu_read_lock();
+			disabled = radix_tree_tag_get(&mport->net.dev_tree,
+						      tmp->destid,
+						      RIO_DEV_DISABLED);
+			rcu_read_unlock();
+
+			rc = rio_route_get_port(tmp, destid, &port,
+						(disabled ? 0 : 1));
+			if (rc) {
+				if (++rio_fault >
+					CONFIG_RAPIDIO_ACCESS_ERR_LIMIT)
+					break;
+				continue;
+			}
+#ifdef CONFIG_RAPIDIO_STATIC_DESTID
+			rio_lookup_static_route(rptr[d], tmp->destid,
+						&static_port);
+#endif
+			pr_debug("RIO: Check route for destid %hx in %s static port %hhu\n",
+				 destid, rio_name(tmp), static_port);
+			if ((port == RIO_INVALID_ROUTE)  ||
+			    ((static_port != RIO_INVALID_ROUTE) &&
+			     (static_port != port))) {
+				u8 sw_port = tmp->return_port;
+
+				if (static_port != RIO_INVALID_ROUTE)
+					sw_port = static_port;
+				pr_debug("RIO: Add route for destid %hx at port %d in %s\n",
+					 destid, sw_port, rio_name(tmp));
+				rc = rio_route_add(tmp, RIO_GLOBAL_TABLE,
+						   destid, sw_port,
+						   (disabled ? 0 : 1));
+				if (rc) {
+					if (++rio_fault >
+					    CONFIG_RAPIDIO_ACCESS_ERR_LIMIT)
+						break;
+				}
+			}
+		}
+		/* verify dev access after route update */
+		rc = rio_read_config_32(rptr[d],
+					rptr[d]->phys_efptr +
+					RIO_PORT_GEN_CTL_CSR,
+					&result);
+		if (rc != 0) {
+			if (++rio_fault > CONFIG_RAPIDIO_ACCESS_ERR_LIMIT)
+				break;
+		}
+	}
+	for (i = 0; i < num; i++) {
+		if (dptr[i])
+			rio_dev_put(dptr[i]);
+	}
+	kfree(dptr);
+	return (rio_fault > CONFIG_RAPIDIO_ACCESS_ERR_LIMIT ? rc : 0);
+}
+
+int rio_init_lut(struct rio_dev *rdev, int lock)
+{
+	struct rio_mport *mport = rdev->hport;
+	int i, num = 0, rio_fault = 0, rc = 0;
+	struct rio_dev **dptr = NULL;
+
+	if (!rdev->rswitch->update_lut)
+		return 0;
+
+	dptr = rio_get_all_devices(mport, &num);
+	if (!dptr)
+		return 0;
+	if (IS_ERR(dptr))
+		return PTR_ERR(dptr);
+
+	for (i = 0; i < num; i++) {
+		struct rio_dev *tmp = dptr[i];
+
+		if (unlikely(!tmp))
+			continue;
+		if (rio_fault || (!tmp->local_domain && !rdev->local_domain)) {
+			rio_dev_put(tmp);
+			continue;
+		}
+		pr_debug("RIO:%s add %hhu to %s at port %d\n",
+			 __func__, tmp->destid, rio_name(rdev),
+			 rdev->return_port);
+		rc = rio_route_add(rdev, RIO_GLOBAL_TABLE,
+				   tmp->destid, rdev->return_port, lock);
+		rio_dev_put(tmp);
+		if (rc)
+			rio_fault++;
+	}
+	kfree(dptr);
+	return rc;
+}
diff --git a/drivers/rapidio/rio-route.h b/drivers/rapidio/rio-route.h
new file mode 100644
index 0000000..9156808
--- /dev/null
+++ b/drivers/rapidio/rio-route.h
@@ -0,0 +1,31 @@
+#ifndef _RIO_ROUTE_H
+#define _RIO_ROUTE_H
+
+/*
+ * RapidIO job support
+ *
+ * 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/rio.h>
+
+extern int rio_route_add(struct rio_dev *rdev, u16 table, u16 route_destid,
+			 u8 route_port, int lock);
+extern int rio_route_get_port(struct rio_dev *rdev,
+			      u16 destid, u8 *port, int lock);
+extern int rio_add_route_for_destid(struct rio_mport *mport,
+				    u16 parent_dest, u8 port_num,
+				    u16 destid, int lock);
+extern int rio_remove_route_for_destid(struct rio_mport *mport,
+				       u16 destid, int lock);
+extern int rio_update_route_for_destid(struct rio_mport *mport,
+				       u16 destid, int lock);
+extern int rio_init_lut(struct rio_dev *rdev, int lock);
+extern int rio_update_routes(struct rio_mport *mport,
+			     struct rio_dev **rptr, int rnum);
+
+#endif
-- 
1.7.9.5



More information about the linux-yocto mailing list