Skip to contentSkip to conversation

RapidIO support: core

PATCH In review Matt Porter 3 participants 11 messages Jun 2, 2005 – Jun 3, 2005

Subsystems (4)
lore
Share & tools
lore
#0 lore raw

PATCH 1/5 RapidIO support: core

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

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

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

Documentation/DocBook/Makefile (mode:100644) +1 -1
Index: Documentation/DocBook/Makefile
===================================================================
@@ -10,7 +10,7 @@
 	    kernel-hacking.xml kernel-locking.xml deviceiobook.xml \
 	    procfs-guide.xml writing_usb_driver.xml scsidrivers.xml \
 	    sis900.xml kernel-api.xml journal-api.xml lsm.xml usb.xml \
-	    gadget.xml libata.xml mtdnand.xml librs.xml
+	    gadget.xml libata.xml mtdnand.xml librs.xml rapidio.xml
 
 ###
 # The build process is as follows (targets):
Documentation/DocBook/rapidio.tmpl (mode:100644) renamed from dev/null (tree:3c5e9440c6a37c3355b50608836a23c8fa4eec99) +160 -0

160 lines not on this page · raw message

drivers/Makefile (mode:100644) +1 -0
Index: drivers/Makefile
===================================================================
@@ -7,6 +7,7 @@
 
 obj-$(CONFIG_PCI)		+= pci/
 obj-$(CONFIG_PARISC)		+= parisc/
+obj-$(CONFIG_RAPIDIO)		+= rio/
 obj-y				+= video/
 obj-$(CONFIG_ACPI_BOOT)		+= acpi/
 # PnP must come after ACPI since it will eventually need to check if acpi
drivers/rio/Kconfig (mode:100644) renamed from dev/null (tree:3c5e9440c6a37c3355b50608836a23c8fa4eec99) +18 -0
Index: drivers/rio/Kconfig
===================================================================
@@ -0,0 +1,18 @@
+#
+# RapidIO configuration
+#
+config RAPIDIO_8_BIT_TRANSPORT
+	bool "8-bit transport addressing"
+	depends on RAPIDIO
+	---help---
+	  By default, the kernel assumes a 16-bit addressed RapidIO
+	  network. By selecting this option, the kernel will support
+	  an 8-bit addressed network.
+
+config RAPIDIO_DISC_TIMEOUT
+	int "Discovery timeout duration (seconds)"
+	depends on RAPIDIO
+	default "30"
+	---help---
+	  Amount of time a discovery node waits for a host to complete
+	  enumeration beforing giving up.
drivers/rio/Makefile (mode:100644) renamed from dev/null (tree:3c5e9440c6a37c3355b50608836a23c8fa4eec99) +6 -0
Index: drivers/rio/Makefile
===================================================================
@@ -0,0 +1,6 @@
+#
+# Makefile for RapidIO interconnect services
+#
+obj-y += rio.o rio-access.o rio-driver.o rio-scan.o rio-sysfs.o
+
+obj-$(CONFIG_RAPIDIO)		+= switches/
drivers/rio/rio-access.c (mode:100644) renamed from dev/null (tree:3c5e9440c6a37c3355b50608836a23c8fa4eec99) +175 -0

175 lines not on this page · raw message

drivers/rio/rio-driver.c (mode:100644) renamed from dev/null (tree:3c5e9440c6a37c3355b50608836a23c8fa4eec99) +229 -0

229 lines not on this page · raw message

drivers/rio/rio-sysfs.c (mode:100644) renamed from dev/null (tree:3c5e9440c6a37c3355b50608836a23c8fa4eec99) +196 -0

196 lines not on this page · raw message

drivers/rio/rio.c (mode:100644) renamed from dev/null (tree:3c5e9440c6a37c3355b50608836a23c8fa4eec99) +503 -0

503 lines not on this page · raw message

drivers/rio/rio.h (mode:100644) renamed from dev/null (tree:3c5e9440c6a37c3355b50608836a23c8fa4eec99) +57 -0

57 lines not on this page · raw message

include/asm-generic/vmlinux.lds.h (mode:100644) +7 -0
Index: include/asm-generic/vmlinux.lds.h
===================================================================
@@ -32,6 +32,13 @@
 		VMLINUX_SYMBOL(__end_pci_fixups_enable) = .;		\
 	}								\
 									\
+	/* RapidIO route ops */						\
+	.rio_route        : AT(ADDR(.rio_route) - LOAD_OFFSET) {	\
+		VMLINUX_SYMBOL(__start_rio_route_ops) = .;		\
+		*(.rio_route_ops)					\
+		VMLINUX_SYMBOL(__end_rio_route_ops) = .;		\
+	}								\
+									\
 	/* Kernel symbol table: Normal symbols */			\
 	__ksymtab         : AT(ADDR(__ksymtab) - LOAD_OFFSET) {		\
 		VMLINUX_SYMBOL(__start___ksymtab) = .;			\
#1 lore raw

PATCH 2/5 RapidIO support: core includes

Add RapidIO core include files.

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

include/linux/rio.h (mode:100644) renamed from dev/null (tree:ca27a54444320b5c022df402fce5cab0f3d9ea94) +321 -0
Index: include/linux/rio.h
===================================================================
@@ -0,0 +1,321 @@
+/*
+ * RapidIO interconnect services
+ * (RapidIO Interconnect Specification, http://www.rapidio.org)
+ *
+ * Copyright 2005 MontaVista Software, Inc.
+ * Matt Porter <[email protected]>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#ifndef LINUX_RIO_H
+#define LINUX_RIO_H
+
+#ifdef __KERNEL__
+
+#include <linux/types.h>
+#include <linux/config.h>
+#include <linux/ioport.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/device.h>
+#include <linux/rio_regs.h>
+
+#define RIO_ANY_DESTID		0xff
+#define RIO_NO_HOPCOUNT		-1
+
+#define RIO_MAX_MPORT_RESOURCES	16
+#define RIO_MAX_DEV_RESOURCES	16
+
+#define RIO_GLOBAL_TABLE	0xff	/* Indicates access of a switch's
+					   global routing table if it
+					   has multiple (or per port)
+					   tables */
+
+#define RIO_INVALID_ROUTE	0xff	/* Indicates that a route table
+					   entry is invalid (no route
+					   exists for the device ID) */
+
+#ifdef CONFIG_RAPIDIO_8_BIT_TRANSPORT
+#define RIO_MAX_ROUTE_ENTRIES	(1 << 8)
+#else
+#define RIO_MAX_ROUTE_ENTRIES	(1 << 16)
+#endif
+
+#define RIO_MAX_MBOX		4
+#define RIO_MAX_MSG_SIZE	0x1000
+
+/*
+ * Error values that may be returned by RIO functions.
+ */
+#define RIO_SUCCESSFUL			0x00
+#define RIO_BAD_SIZE			0x81
+
+/*
+ * For RIO devices, the region numbers are assigned this way:
+ *
+ *	0	RapidIO outbound doorbells
+ *      1-15	RapidIO memory regions
+ *
+ * For RIO master ports, the region number are assigned this way:
+ *
+ *	0	RapidIO inbound doorbells
+ *	1	RapidIO inbound mailboxes
+ *	1	RapidIO outbound mailboxes
+ */
+#define RIO_DOORBELL_RESOURCE	0
+#define RIO_INB_MBOX_RESOURCE	1
+#define RIO_OUTB_MBOX_RESOURCE	2
+
+extern struct bus_type rio_bus_type;
+extern struct list_head rio_devices;	/* list of all devices */
+
+struct rio_mport;
+
+/**
+ * struct rio_dev - RIO device info
+ * @global_list: Node in list of all RIO devices
+ * @net_list: Node in list of RIO devices in a network
+ * @net: Network this device is a part of
+ * @did: Device ID
+ * @vid: Vendor ID
+ * @device_rev: Device revision
+ * @asm_did: Assembly device ID
+ * @asm_vid: Assembly vendor ID
+ * @asm_rev: Assembly revision
+ * @efptr: Extended feature pointer
+ * @pef: Processing element features
+ * @swpinfo: Switch port info
+ * @src_ops: Source operation capabilities
+ * @dst_ops: Destination operation capabilities
+ * @rswitch: Pointer to &struct rio_switch if valid for this device
+ * @driver: Driver claiming this device
+ * @dev: Device model device
+ * @riores: RIO resources this device owns
+ * @destid: Network destination ID
+ */
+struct rio_dev {
+	struct list_head global_list;	/* node in list of all RIO devices */
+	struct list_head net_list;	/* node in per net list */
+	struct rio_net *net;	/* RIO net this device resides in */
+	u16 did;
+	u16 vid;
+	u32 device_rev;
+	u16 asm_did;
+	u16 asm_vid;
+	u16 asm_rev;
+	u16 efptr;
+	u32 pef;
+	u32 swpinfo;		/* Only used for switches */
+	u32 src_ops;
+	u32 dst_ops;
+	struct rio_switch *rswitch;	/* RIO switch info */
+	struct rio_driver *driver;	/* RIO driver claiming this device */
+	struct device dev;	/* LDM device structure */
+	struct resource riores[RIO_MAX_DEV_RESOURCES];
+	u16 destid;
+};
+
+#define rio_dev_g(n) list_entry(n, struct rio_dev, global_list)
+#define rio_dev_f(n) list_entry(n, struct rio_dev, net_list)
+#define	to_rio_dev(n) container_of(n, struct rio_dev, dev)
+
+/**
+ * struct rio_msg - RIO message event
+ * @res: Mailbox resource
+ * @mcback: Message event callback
+ */
+struct rio_msg {
+	struct resource *res;
+	void (*mcback) (struct rio_mport * mport, int mbox, int slot);
+};
+
+/**
+ * struct rio_dbell - RIO doorbell event
+ * @node: Node in list of doorbell events
+ * @res: Doorbell resource
+ * @dinb: Doorbell event callback
+ */
+struct rio_dbell {
+	struct list_head node;
+	struct resource *res;
+	void (*dinb) (struct rio_mport * mport, u16 src, u16 dst, u16 info);
+};
+
+/**
+ * struct rio_mport - RIO master port info
+ * @dbells: List of doorbell events 
+ * @node: Node in global list of master ports
+ * @nnode: Node in network list of master ports
+ * @iores: I/O mem resource that this master port interface owns
+ * @riores: RIO resources that this master port interfaces owns
+ * @inb_msg: RIO inbound message event descriptors
+ * @outb_msg: RIO outbound message event descriptors
+ * @host_deviceid: Host device ID associated with this master port
+ * @ops: configuration space functions
+ * @id: Port ID, unique among all ports
+ * @index: Port index, unique among all port interfaces of the same type
+ * @name: Port name string
+ */
+struct rio_mport {
+	struct list_head dbells;	/* list of doorbell events */
+	struct list_head node;	/* node in global list of ports */
+	struct list_head nnode;	/* node in net list of ports */
+	struct resource iores;
+	struct resource riores[RIO_MAX_MPORT_RESOURCES];
+	struct rio_msg inb_msg[RIO_MAX_MBOX];
+	struct rio_msg outb_msg[RIO_MAX_MBOX];
+	int host_deviceid;	/* Host device ID */
+	struct rio_ops *ops;	/* maintenance transaction functions */
+	unsigned char id;	/* port ID, unique among all ports */
+	unsigned char index;	/* port index, unique among all port
+				   interfaces of the same type */
+	unsigned char name[40];
+};
+
+/**
+ * struct rio_net - RIO network info
+ * @node: Node in global list of RIO networks
+ * @devices: List of devices in this network
+ * @mports: List of master ports accessing this network
+ * @hport: Default port for accessing this network
+ * @id: RIO network ID
+ */
+struct rio_net {
+	struct list_head node;	/* node in list of networks */
+	struct list_head devices;	/* list of devices in this net */
+	struct list_head mports;	/* list of ports accessing net */
+	struct rio_mport *hport;	/* primary port for accessing net */
+	unsigned char id;	/* RIO network ID */
+};
+
+/**
+ * struct rio_switch - RIO switch info
+ * @node: Node in global list of switches
+ * @switchid: Switch ID that is unique across a network
+ * @hopcount: Hopcount to this switch
+ * @destid: Associated destid in the path
+ * @route_table: Copy of switch routing table
+ * @add_entry: Callback for switch-specific route add function
+ * @get_entry: Callback for switch-specific route get function
+ */
+struct rio_switch {
+	struct list_head node;
+	u16 switchid;
+	u16 hopcount;
+	u16 destid;
+	u8 route_table[RIO_MAX_ROUTE_ENTRIES];
+	int (*add_entry) (struct rio_mport * mport, u16 destid, u8 hopcount,
+			  u16 table, u16 route_destid, u8 route_port);
+	int (*get_entry) (struct rio_mport * mport, u16 destid, u8 hopcount,
+			  u16 table, u16 route_destid, u8 * route_port);
+};
+
+/* Low-level architecture-dependent routines */
+
+/**
+ * struct rio_ops - Low-level RIO configuration space operations
+ * @lcread: Callback to perform local (master port) read of config space.
+ * @lcwrite: Callback to perform local (master port) write of config space.
+ * @cread: Callback to perform network read of config space.
+ * @cwrite: Callback to perform network write of config space.
+ * @dsend: Callback to send a doorbell message.
+ */
+struct rio_ops {
+	int (*lcread) (int index, u32 offset, int len, u32 * data);
+	int (*lcwrite) (int index, u32 offset, int len, u32 data);
+	int (*cread) (int index, u16 destid, u8 hopcount, u32 offset, int len,
+		      u32 * data);
+	int (*cwrite) (int index, u16 destid, u8 hopcount, u32 offset, int len,
+		       u32 data);
+	int (*dsend) (int index, u16 destid, u16 data);
+};
+
+#define RIO_RESOURCE_MEM	0x00000100
+#define RIO_RESOURCE_DOORBELL	0x00000200
+#define RIO_RESOURCE_MAILBOX	0x00000400
+
+#define RIO_RESOURCE_CACHEABLE	0x00010000
+#define RIO_RESOURCE_PCI	0x00020000
+
+#define RIO_RESOURCE_BUSY	0x80000000
+
+/**
+ * struct rio_driver - RIO driver info
+ * @node: Node in list of drivers
+ * @name: RIO driver name
+ * @id_table: RIO device ids to be associated with this driver
+ * @probe: RIO device inserted
+ * @remove: RIO device removed
+ * @suspend: RIO device suspended
+ * @resume: RIO device awakened
+ * @enable_wake: RIO device enable wake event
+ * @driver: LDM driver struct
+ *
+ * Provides info on a RIO device driver for insertion/removal and
+ * power management purposes.
+ */
+struct rio_driver {
+	struct list_head node;
+	char *name;
+	const struct rio_device_id *id_table;
+	int (*probe) (struct rio_dev * dev, const struct rio_device_id * id);
+	void (*remove) (struct rio_dev * dev);
+	int (*suspend) (struct rio_dev * dev, u32 state);
+	int (*resume) (struct rio_dev * dev);
+	int (*enable_wake) (struct rio_dev * dev, u32 state, int enable);
+	struct device_driver driver;
+};
+
+#define	to_rio_driver(drv) container_of(drv,struct rio_driver, driver)
+
+/**
+ * struct rio_device_id - RIO device identifier
+ * @did: RIO device ID
+ * @vid: RIO vendor ID
+ * @asm_did: RIO assembly device ID
+ * @asm_vid: RIO assembly vendor ID
+ *
+ * Identifies a RIO device based on both the device/vendor IDs and
+ * the assembly device/vendor IDs.
+ */
+struct rio_device_id {
+	u16 did, vid;
+	u16 asm_did, asm_vid;
+};
+
+/**
+ * struct rio_route_ops - Per-switch route operations
+ * @vid: RIO vendor ID
+ * @did: RIO device ID
+ * @add_hook: Callback that adds a route entry
+ * @get_hook: Callback that gets a route entry
+ *
+ * Defines the operations that are necessary to manipulate the route
+ * tables for a particular RIO switch device.
+ */
+struct rio_route_ops {
+	u16 vid, did;
+	int (*add_hook) (struct rio_mport * mport, u16 destid, u8 hopcount,
+			 u16 table, u16 route_destid, u8 route_port);
+	int (*get_hook) (struct rio_mport * mport, u16 destid, u8 hopcount,
+			 u16 table, u16 route_destid, u8 * route_port);
+};
+
+/* Architecture and hardware-specific functions */
+extern int rio_init_mports(void);
+extern void rio_register_mport(struct rio_mport *);
+extern int rio_hw_add_outb_message(struct rio_mport *, struct rio_dev *, int,
+				   void *, size_t);
+extern int rio_hw_add_inb_buffer(struct rio_mport *, int, void *);
+extern void *rio_hw_get_inb_message(struct rio_mport *, int);
+extern int rio_open_inb_mbox(struct rio_mport *, int, int);
+extern void rio_close_inb_mbox(struct rio_mport *, int);
+extern int rio_open_outb_mbox(struct rio_mport *, int, int);
+extern void rio_close_outb_mbox(struct rio_mport *, int);
+
+#endif				/* __KERNEL__ */
+#endif				/* LINUX_RIO_H */
include/linux/rio_drv.h (mode:100644) renamed from dev/null (tree:ca27a54444320b5c022df402fce5cab0f3d9ea94) +469 -0

469 lines not on this page · raw message

include/linux/rio_ids.h (mode:100644) renamed from dev/null (tree:ca27a54444320b5c022df402fce5cab0f3d9ea94) +24 -0
Index: include/linux/rio_ids.h
===================================================================
@@ -0,0 +1,24 @@
+/*
+ * RapidIO devices
+ *
+ * Copyright 2005 MontaVista Software, Inc.
+ * Matt Porter <[email protected]>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#ifndef LINUX_RIO_IDS_H
+#define LINUX_RIO_IDS_H
+
+#define RIO_ANY_ID			0xffff
+
+#define RIO_VID_FREESCALE		0x0002
+#define RIO_DID_MPC8560			0x0003
+
+#define RIO_VID_TUNDRA			0x000d
+#define RIO_DID_TSI500			0x0500
+
+#endif				/* LINUX_RIO_IDS_H */
include/linux/rio_regs.h (mode:100644) renamed from dev/null (tree:ca27a54444320b5c022df402fce5cab0f3d9ea94) +202 -0

202 lines not on this page · raw message

#2 lore raw

PATCH 3/5 RapidIO support: enumeration

Adds RapidIO enumeration/discovery.

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

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

60 lines not on this page · raw message

#3 lore raw

PATCH 4/5 RapidIO support: ppc32

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

arch/ppc/Kconfig (mode:100644) +8 -0
Index: arch/ppc/Kconfig
===================================================================
@@ -1177,6 +1177,14 @@
 
 source "drivers/pcmcia/Kconfig"
 
+config RAPIDIO
+	bool "RapidIO support" if MPC8540 || MPC8560
+	help
+	  If you say Y here, the kernel will include drivers and
+	  infrastructure code to support RapidIO interconnect devices.
+
+source "drivers/rio/Kconfig"
+
 endmenu
 
 menu "Advanced setup"
arch/ppc/configs/stx_gp3_defconfig (mode:100644) +52 -34

284 lines not on this page · raw message

arch/ppc/kernel/Makefile (mode:100644) +1 -0
Index: arch/ppc/kernel/Makefile
===================================================================
@@ -22,6 +22,7 @@
 obj-$(CONFIG_MODULES)		+= module.o ppc_ksyms.o
 obj-$(CONFIG_NOT_COHERENT_CACHE)	+= dma-mapping.o
 obj-$(CONFIG_PCI)		+= pci.o
+obj-$(CONFIG_RAPIDIO)		+= rio.o
 obj-$(CONFIG_KGDB)		+= ppc-stub.o
 obj-$(CONFIG_SMP)		+= smp.o smp-tbsync.o
 obj-$(CONFIG_TAU)		+= temp.o
arch/ppc/kernel/rio.c (mode:100644) renamed from dev/null (tree:b4a27e4c90f11413fa6828321141c43cb9ad6c12) +52 -0

52 lines not on this page · raw message

arch/ppc/platforms/85xx/stx_gp3.c (mode:100644) +14 -1
Index: arch/ppc/platforms/85xx/stx_gp3.c
===================================================================
@@ -38,6 +38,7 @@
 #include <linux/module.h>
 #include <linux/fsl_devices.h>
 #include <linux/interrupt.h>
+#include <linux/rio.h>
 
 #include <asm/system.h>
 #include <asm/pgtable.h>
@@ -59,6 +60,7 @@
 
 #include <syslib/cpm2_pic.h>
 #include <syslib/ppc85xx_common.h>
+#include <syslib/ppc85xx_rio.h>
 
 extern void cpm2_reset(void);
 
@@ -200,7 +202,6 @@
 static void __init
 gp3_init_IRQ(void)
 {
-	int i;
 	bd_t *binfo = (bd_t *) __res;
 
 	/*
@@ -297,6 +298,18 @@
 }
 #endif /* CONFIG_PCI */
 
+#ifdef CONFIG_RAPIDIO
+void
+platform_rio_init(void)
+{
+	/*
+	 * The STx firmware configures the RapidIO Local Access Window
+	 * at 0xc0000000 with a size of 512MB.
+	 */
+	mpc85xx_rio_setup(0xc0000000, 0x20000000);
+}
+#endif /* CONFIG_RAPIDIO */
+
 void __init
 platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
 	      unsigned long r6, unsigned long r7)
arch/ppc/syslib/Makefile (mode:100644) +1 -0
Index: arch/ppc/syslib/Makefile
===================================================================
@@ -101,6 +101,7 @@
 					mpc85xx_devices.o
 ifeq ($(CONFIG_85xx),y)
 obj-$(CONFIG_PCI)		+= indirect_pci.o pci_auto.o
+obj-$(CONFIG_RAPIDIO)		+= ppc85xx_rio.o
 endif
 obj-$(CONFIG_83xx)		+= ipic.o ppc83xx_setup.o ppc_sys.o \
 					mpc83xx_sys.o mpc83xx_devices.o
arch/ppc/syslib/ppc85xx_rio.c (mode:100644) renamed from dev/null (tree:b4a27e4c90f11413fa6828321141c43cb9ad6c12) +867 -0

867 lines not on this page · raw message

arch/ppc/syslib/ppc85xx_rio.h (mode:100644) renamed from dev/null (tree:b4a27e4c90f11413fa6828321141c43cb9ad6c12) +21 -0
Index: arch/ppc/syslib/ppc85xx_rio.h
===================================================================
@@ -0,0 +1,21 @@
+/*
+ * MPC85xx RapidIO definitions
+ *
+ * Copyright 2005 MontaVista Software, Inc.
+ * Matt Porter <[email protected]>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __PPC_SYSLIB_PPC85XX_RIO_H
+#define __PPC_SYSLIB_PPC85XX_RIO_H
+
+#include <linux/config.h>
+#include <linux/init.h>
+
+extern void mpc85xx_rio_setup(int law_start, int law_size);
+
+#endif				/* __PPC_SYSLIB_PPC85XX_RIO_H */
include/asm-ppc/rio.h (mode:100644) renamed from dev/null (tree:b4a27e4c90f11413fa6828321141c43cb9ad6c12) +18 -0
Index: include/asm-ppc/rio.h
===================================================================
@@ -0,0 +1,18 @@
+/*
+ * RapidIO architecture support
+ *
+ * Copyright 2005 MontaVista Software, Inc.
+ * Matt Porter <[email protected]>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#ifndef ASM_PPC_RIO_H
+#define ASM_PPC_RIO_H
+
+extern void platform_rio_init(void);
+
+#endif				/* ASM_PPC_RIO_H */
#4 lore raw

PATCH 5/5 RapidIO support: net driver over messaging

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

drivers/net/Kconfig (mode:100644) +14 -0
Index: drivers/net/Kconfig
===================================================================
@@ -2185,6 +2185,20 @@
 	tristate "iSeries Virtual Ethernet driver support"
 	depends on NETDEVICES && PPC_ISERIES
 
+config RIONET
+	tristate "RapidIO Ethernet over messaging driver support"
+	depends on NETDEVICES && RAPIDIO
+
+config RIONET_TX_SIZE
+	int "Number of outbound queue entries"
+	depends on RIONET
+	default "128"
+
+config RIONET_RX_SIZE
+	int "Number of inbound queue entries"
+	depends on RIONET
+	default "128"
+
 config FDDI
 	bool "FDDI driver support"
 	depends on NETDEVICES && (PCI || EISA)
drivers/net/Makefile (mode:100644) +1 -0
Index: drivers/net/Makefile
===================================================================
@@ -58,6 +58,7 @@
 obj-$(CONFIG_VIA_RHINE) += via-rhine.o
 obj-$(CONFIG_VIA_VELOCITY) += via-velocity.o
 obj-$(CONFIG_ADAPTEC_STARFIRE) += starfire.o
+obj-$(CONFIG_RIONET) += rionet.o
 
 #
 # end link order section
drivers/net/rionet.c (mode:100644) renamed from dev/null (tree:711ec47634f5d5ded866eaa965a0f7dadcbc65f4) +622 -0

622 lines not on this page · raw message

#5 lore raw

Re: [PATCH][5/5] RapidIO support: net driver over messaging

How much is this like ethernet? does it still do ARP? Can it do promiscious receive?

Quoted 1 line

+LIST_HEAD(rionet_peers);

Does this have to be global?

Not sure about the locking of this stuff, are you
relying on the RTNL?

drivers/net/rionet.c (mode:100644) line 240

Quoted 11 lines
drivers/net/rionet.c (mode:100644) renamed from dev/null (tree:711ec47634f5d5ded866eaa965a0f7dadcbc65f4) +11 -0
+
+static int rionet_change_mtu(struct net_device *ndev, int new_mtu)
+{
+	struct rionet_private *rnet = ndev->priv;
+
+	if (netif_msg_drv(rnet))
+		printk(KERN_WARNING
+		       "%s: rionet_change_mtu(): not implemented\n", DRV_NAME);
+
+	return 0;
+}

If you can allow any mtu then don't need this at all. Or if you are limited then better return an error for bad values.

drivers/net/rionet.c (mode:100644) line 250

Quoted 9 lines
drivers/net/rionet.c (mode:100644) renamed from dev/null (tree:711ec47634f5d5ded866eaa965a0f7dadcbc65f4) +9 -0
+static void rionet_set_multicast_list(struct net_device *ndev)
+{
+	struct rionet_private *rnet = ndev->priv;
+
+	if (netif_msg_drv(rnet))
+		printk(KERN_WARNING
+		       "%s: rionet_set_multicast_list(): not implemented\n",
+		       DRV_NAME);
+}

If you can't handle it then just leave dev->set_multicast_list as NULL and all attempts to add or delete will get -EINVAL

Quoted 8 lines
drivers/net/rionet.c (mode:100644) renamed from dev/null (tree:711ec47634f5d5ded866eaa965a0f7dadcbc65f4) +6 -0
+
+static int rionet_open(struct net_device *ndev)
+{
 
 
+	/* Initialize inbound message ring */
+	for (i = 0; i < RIONET_RX_RING_SIZE; i++)
+		rnet->rx_skb[i] = NULL;

drivers/net/rionet.c (mode:100644) line 363

Quoted 10 lines
drivers/net/rionet.c (mode:100644) renamed from dev/null (tree:711ec47634f5d5ded866eaa965a0f7dadcbc65f4) +10 -0
+	rnet->rx_slot = 0;
+	rionet_rx_fill(ndev, 0);
+
+	rnet->tx_slot = 0;
+	rnet->tx_cnt = 0;
+	rnet->ack_slot = 0;
+
+	spin_lock_init(&rnet->lock);
+
+	rnet->msg_enable = RIONET_DEFAULT_MSGLEVEL;

Better to do all initialization of the per device data in the place it is allocated (rio_setup_netdev)

drivers/net/rionet.c (mode:100644) line 440

Quoted 5 lines
drivers/net/rionet.c (mode:100644) renamed from dev/null (tree:711ec47634f5d5ded866eaa965a0f7dadcbc65f4) +5 -0
+
+static int rionet_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
+{
+	return -EOPNOTSUPP;
+}

Unneeded, if dev->do_ioctl is NULL, then all private ioctl's will return -EINVAL that is what you want.

drivers/net/rionet.c (mode:100644) line 470

Quoted 5 lines
drivers/net/rionet.c (mode:100644) renamed from dev/null (tree:711ec47634f5d5ded866eaa965a0f7dadcbc65f4) +5 -0
+
+static u32 rionet_get_link(struct net_device *ndev)
+{
+	return netif_carrier_ok(ndev);
+}

Use ethtool_op_get_link

Quoted 41 lines
drivers/net/rionet.c (mode:100644) renamed from dev/null (tree:711ec47634f5d5ded866eaa965a0f7dadcbc65f4) +41 -0
+
+static int rionet_setup_netdev(struct rio_mport *mport)
+{
+	int rc = 0;
+	struct net_device *ndev = NULL;
+	struct rionet_private *rnet;
+	u16 device_id;
+
+	/* Allocate our net_device structure */
+	ndev = alloc_etherdev(sizeof(struct rionet_private));
+	if (ndev == NULL) {
+		printk(KERN_INFO "%s: could not allocate ethernet device.\n",
+		       DRV_NAME);
+		rc = -ENOMEM;
+		goto out;
+	}
+
+	/*
+	 * XXX hack, store point a static at ndev so we can get it...
+	 * Perhaps need an array of these that the handler can
+	 * index via the mbox number.
+	 */
+	sndev = ndev;
+
+	/* Set up private area */
+	rnet = (struct rionet_private *)ndev->priv;
+	rnet->mport = mport;
+
+	/* Set the default MAC address */
+	device_id = rio_local_get_device_id(mport);
+	ndev->dev_addr[0] = 0x00;
+	ndev->dev_addr[1] = 0x01;
+	ndev->dev_addr[2] = 0x00;
+	ndev->dev_addr[3] = 0x01;
+	ndev->dev_addr[4] = device_id >> 8;
+	ndev->dev_addr[5] = device_id & 0xff;
+
+	/* Fill in the driver function table */
+	ndev->open = &rionet_open;
+	ndev->hard_start_xmit = &rionet_start_xmit;
+	ndev->stop = &rionet_close;

drivers/net/rionet.c (mode:100644) line 528

Quoted 10 lines
drivers/net/rionet.c (mode:100644) renamed from dev/null (tree:711ec47634f5d5ded866eaa965a0f7dadcbc65f4) +10 -0
+	ndev->get_stats = &rionet_stats;
+	ndev->change_mtu = &rionet_change_mtu;
+	ndev->set_mac_address = &rionet_set_mac_address;
+	ndev->set_multicast_list = &rionet_set_multicast_list;
+	ndev->do_ioctl = &rionet_ioctl;
+	SET_ETHTOOL_OPS(ndev, &rionet_ethtool_ops);
+
+	ndev->mtu = RIO_MAX_MSG_SIZE - 14;
+
+	SET_MODULE_OWNER(ndev);

Can you set any ndev->features to get better performance.
Can you take >32bit data addresses? then set HIGHDMA You are doing your on locking, can you use LLTX? Does the hardware support scatter gather?

#6 lore raw

Re: [PATCH][5/5] RapidIO support: net driver over messaging

Quoted 1 line · Stephen Hemminger

How much is this like ethernet? does it still do ARP?

It's nothing like Ethernet, the only relation is that an Ethernet network driver is easy to implement over top of raw message ports on a switched fabric network. It gives easy access to RIO messaging from userspace without inventing a new interface.

ARP works by the driver emulating a broadcast over RIO by sending the same ARP packet to each node that is participating in the rionet. Nodes join/leave the rionet by sending RIO-specific doorbell messages to potential participants on the switched fabric. A table is kept to flag active participants such that a fast lookup can be made to translate the dst MAC address to a RIO device struct that is used to actually send the Ethernet packet encapsulated into a standard RIO message to the appropriate node(s).

Quoted 1 line

Can it do promiscious receive?

No.

Quoted 3 lines
Quoted 1 line

+LIST_HEAD(rionet_peers);

Does this have to be global?

Nope, should be static. Fixing.

Quoted 2 lines

Not sure about the locking of this stuff, are you
relying on the RTNL?

Yes, last I looked that was sufficient for all the entry points. I protect the driver-specific data (tx skb rings, etc.) with a private lock.

Quoted 6 lines
Quoted 6 lines
drivers/net/rionet.c (mode:100644) renamed from dev/null (tree:711ec47634f5d5ded866eaa965a0f7dadcbc65f4) +6 -0
+
+static int rionet_change_mtu(struct net_device *ndev, int new_mtu)
+{
+	struct rionet_private *rnet = ndev->priv;
+
+	if (netif_msg_drv(rnet))
Quoted 8 lines

drivers/net/rionet.c (mode:100644) line 240

Quoted 5 lines
drivers/net/rionet.c (mode:100644) renamed from dev/null (tree:711ec47634f5d5ded866eaa965a0f7dadcbc65f4) +5 -0
+		printk(KERN_WARNING
+		       "%s: rionet_change_mtu(): not implemented\n", DRV_NAME);
+
+	return 0;
+}

If you can allow any mtu then don't need this at all. Or if you are limited then better return an error for bad values.

Ok, I do have a upper limit of 4082 as the RIO messages have a max 4096 byte payload. That's the default on open as well. I'll fix this up.

Quoted 4 lines
Quoted 4 lines
drivers/net/rionet.c (mode:100644) renamed from dev/null (tree:711ec47634f5d5ded866eaa965a0f7dadcbc65f4) +4 -0
+static void rionet_set_multicast_list(struct net_device *ndev)
+{
+	struct rionet_private *rnet = ndev->priv;
+
Quoted 8 lines

drivers/net/rionet.c (mode:100644) line 250

Quoted 5 lines
drivers/net/rionet.c (mode:100644) renamed from dev/null (tree:711ec47634f5d5ded866eaa965a0f7dadcbc65f4) +5 -0
+	if (netif_msg_drv(rnet))
+		printk(KERN_WARNING
+		       "%s: rionet_set_multicast_list(): not implemented\n",
+		       DRV_NAME);
+}

If you can't handle it then just leave dev->set_multicast_list as NULL and all attempts to add or delete will get -EINVAL

Will do. It was a placeholder at one point when I thought I might emulate multicast in the driver...it's fallen down my priority list.

Quoted 5 lines
Quoted 3 lines
drivers/net/rionet.c (mode:100644) renamed from dev/null (tree:711ec47634f5d5ded866eaa965a0f7dadcbc65f4) +3 -0
+
+static int rionet_open(struct net_device *ndev)
+{
Quoted 16 lines

drivers/net/rionet.c (mode:100644) line 363

Quoted 13 lines
drivers/net/rionet.c (mode:100644) renamed from dev/null (tree:711ec47634f5d5ded866eaa965a0f7dadcbc65f4) +13 -0
+	/* Initialize inbound message ring */
+	for (i = 0; i < RIONET_RX_RING_SIZE; i++)
+		rnet->rx_skb[i] = NULL;
+	rnet->rx_slot = 0;
+	rionet_rx_fill(ndev, 0);
+
+	rnet->tx_slot = 0;
+	rnet->tx_cnt = 0;
+	rnet->ack_slot = 0;
+
+	spin_lock_init(&rnet->lock);
+
+	rnet->msg_enable = RIONET_DEFAULT_MSGLEVEL;

Better to do all initialization of the per device data in the place it is allocated (rio_setup_netdev)

Right, will do.

Quoted 7 lines

drivers/net/rionet.c (mode:100644) line 440

Quoted 4 lines
drivers/net/rionet.c (mode:100644) renamed from dev/null (tree:711ec47634f5d5ded866eaa965a0f7dadcbc65f4) +4 -0
+static int rionet_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
+{
+	return -EOPNOTSUPP;
+}

Unneeded, if dev->do_ioctl is NULL, then all private ioctl's will return -EINVAL that is what you want.

Ah, ok. Good, none of the MII stuff applies in this case.

Quoted 6 lines

drivers/net/rionet.c (mode:100644) line 470

Quoted 4 lines
drivers/net/rionet.c (mode:100644) renamed from dev/null (tree:711ec47634f5d5ded866eaa965a0f7dadcbc65f4) +4 -0
+static u32 rionet_get_link(struct net_device *ndev)
+{
+	return netif_carrier_ok(ndev);
+}

Use ethtool_op_get_link

Ok

<snip>

Quoted 11 lines
Quoted 11 lines
drivers/net/rionet.c (mode:100644) renamed from dev/null (tree:711ec47634f5d5ded866eaa965a0f7dadcbc65f4) +11 -0
+	/* Fill in the driver function table */
+	ndev->open = &rionet_open;
+	ndev->hard_start_xmit = &rionet_start_xmit;
+	ndev->stop = &rionet_close;
+	ndev->get_stats = &rionet_stats;
+	ndev->change_mtu = &rionet_change_mtu;
+	ndev->set_mac_address = &rionet_set_mac_address;
+	ndev->set_multicast_list = &rionet_set_multicast_list;
+	ndev->do_ioctl = &rionet_ioctl;
+	SET_ETHTOOL_OPS(ndev, &rionet_ethtool_ops);
+
Quoted 8 lines

drivers/net/rionet.c (mode:100644) line 528

Quoted 3 lines
drivers/net/rionet.c (mode:100644) renamed from dev/null (tree:711ec47634f5d5ded866eaa965a0f7dadcbc65f4) +3 -0
+	ndev->mtu = RIO_MAX_MSG_SIZE - 14;
+
+	SET_MODULE_OWNER(ndev);

Can you set any ndev->features to get better performance.
Can you take >32bit data addresses? then set HIGHDMA You are doing your on locking, can you use LLTX? Does the hardware support scatter gather?

Some of these get tricky. In general, rionet could support SG and with driver help we can flag IP_CSUM. In practice, the current generation MPC85xx HW on my development system have some problems with their message port dma queues. In short, their implementation is such that the arch-specific code is forced to do a copy of the skb on both tx and rx. Because of this, adding SG/IP_CSUM doesn't have any value yet...it'll make sense to add the addtional features once we get a platform with better messaging hardware. HIGHDMA may not be suitable on all platforms. Since rionet sits on top of a hardware abstraction, it doesn't have full knowledge of the DMA capabilities of the hardware. We can eventually have some interfaces to the arch code to learn that info, but it's not there yet. I have to look into LLTX, I know what it stands for, but I'm not sure of the details. Do you have a good LLTX example reference?

That said, my goal is to enable as many features as possible when we have hw to take advantage of them.

-Matt

#7 lore raw
In reply to Matt Porter

drivers/rio/rio-access.c (mode:100644) line 91

Quoted 13 lines · Matt Porter
drivers/rio/rio-access.c (mode:100644) renamed from dev/null (tree:3c5e9440c6a37c3355b50608836a23c8fa4eec99) +13 -0
+RIO_LOP_READ(8, u8, 1)
+    RIO_LOP_READ(16, u16, 2)
+    RIO_LOP_READ(32, u32, 4)
+    RIO_LOP_WRITE(8, u8, 1)
+    RIO_LOP_WRITE(16, u16, 2)
+    RIO_LOP_WRITE(32, u32, 4)
+
+    EXPORT_SYMBOL(__rio_local_read_config_8);
+EXPORT_SYMBOL(__rio_local_read_config_16);
+EXPORT_SYMBOL(__rio_local_read_config_32);
+EXPORT_SYMBOL(__rio_local_write_config_8);
+EXPORT_SYMBOL(__rio_local_write_config_16);
+EXPORT_SYMBOL(__rio_local_write_config_32);

Odd indenting here.

And why the __rio* stuff for public functions? You should drop the "__" part.

drivers/rio/rio-access.c (mode:100644) line 151

Quoted 13 lines
drivers/rio/rio-access.c (mode:100644) renamed from dev/null (tree:3c5e9440c6a37c3355b50608836a23c8fa4eec99) +13 -0
+RIO_OP_READ(8, u8, 1)
+    RIO_OP_READ(16, u16, 2)
+    RIO_OP_READ(32, u32, 4)
+    RIO_OP_WRITE(8, u8, 1)
+    RIO_OP_WRITE(16, u16, 2)
+    RIO_OP_WRITE(32, u32, 4)
+
+    EXPORT_SYMBOL(rio_mport_read_config_8);
+EXPORT_SYMBOL(rio_mport_read_config_16);
+EXPORT_SYMBOL(rio_mport_read_config_32);
+EXPORT_SYMBOL(rio_mport_write_config_8);
+EXPORT_SYMBOL(rio_mport_write_config_16);
+EXPORT_SYMBOL(rio_mport_write_config_32);

Again the odd indenting.

Quoted 1 line

+EXPORT_SYMBOL(rio_mport_send_doorbell);

Just a question, should these be EXPORT_SYMBOL_GPL() as this is GPL code? Just to be explicit that is.

drivers/rio/rio-sysfs.c (mode:100644) line 71

Quoted 2 lines
drivers/rio/rio-sysfs.c (mode:100644) renamed from dev/null (tree:3c5e9440c6a37c3355b50608836a23c8fa4eec99) +2 -0
+static ssize_t
+rio_read_config(struct kobject *kobj, char *buf, loff_t off, size_t count)

<snip>

You might want to compare this to the recent changes in the 2.6.12-rc kernels in the pci sysfs config code. There were some 64 and endian issues fixed up there that you might want to make sure are also done properly here.

drivers/rio/rio-sysfs.c (mode:100644) line 172

Quoted 10 lines
drivers/rio/rio-sysfs.c (mode:100644) renamed from dev/null (tree:3c5e9440c6a37c3355b50608836a23c8fa4eec99) +10 -0
+static struct bin_attribute rio_config_attr = {
+	.attr = {
+		 .name = "config",
+		 .mode = S_IRUGO | S_IWUSR,
+		 .owner = THIS_MODULE,
+		 },
+	.size = 0x200000,
+	.read = rio_read_config,
+	.write = rio_write_config,
+};

Wow, that's a huge config space (just a comment, not an issue...)

thanks,

greg k-h

#8 lore raw
Quoted 16 lines · Greg KH

drivers/rio/rio-access.c (mode:100644) line 91

Quoted 13 lines · Matt Porter
drivers/rio/rio-access.c (mode:100644) renamed from dev/null (tree:3c5e9440c6a37c3355b50608836a23c8fa4eec99) +13 -0
+RIO_LOP_READ(8, u8, 1)
+    RIO_LOP_READ(16, u16, 2)
+    RIO_LOP_READ(32, u32, 4)
+    RIO_LOP_WRITE(8, u8, 1)
+    RIO_LOP_WRITE(16, u16, 2)
+    RIO_LOP_WRITE(32, u32, 4)
+
+    EXPORT_SYMBOL(__rio_local_read_config_8);
+EXPORT_SYMBOL(__rio_local_read_config_16);
+EXPORT_SYMBOL(__rio_local_read_config_32);
+EXPORT_SYMBOL(__rio_local_write_config_8);
+EXPORT_SYMBOL(__rio_local_write_config_16);
+EXPORT_SYMBOL(__rio_local_write_config_32);

Odd indenting here.

Lindent got me here. I didn't doublecheck its munging on this file. Updated that.

Quoted 2 lines

And why the __rio* stuff for public functions? You should drop the "__" part.

This may seem silly but I was trying to have the automagic DocBook stuff pick up the complete set of kernel interfaces without have to duplicate anything in the DocBook template. Since these functions are macro-generated I could have a comment block for each one that the docs stuff would pick up. So, I put rio_local_*() up in include/linux/rio_drv.h as inline wrappers around these implementations.

Too ugly to live? Maybe there's a better way to make this work, it would nice to have it autogenerate the docs.

<snip>

Quoted 4 lines
Quoted 1 line

+EXPORT_SYMBOL(rio_mport_send_doorbell);

Just a question, should these be EXPORT_SYMBOL_GPL() as this is GPL code? Just to be explicit that is.

Good point. I'm going to go through and make all RIO interfaces EXPORT_SYMBOL_GPL(). Embedded folks need the extra encouragement to do the right thing when writing drivers.

Quoted 9 lines

drivers/rio/rio-sysfs.c (mode:100644) line 71

Quoted 2 lines
drivers/rio/rio-sysfs.c (mode:100644) renamed from dev/null (tree:3c5e9440c6a37c3355b50608836a23c8fa4eec99) +2 -0
+static ssize_t
+rio_read_config(struct kobject *kobj, char *buf, loff_t off, size_t count)

<snip>

You might want to compare this to the recent changes in the 2.6.12-rc kernels in the pci sysfs config code. There were some 64 and endian issues fixed up there that you might want to make sure are also done properly here.

I see that in the current git tree. I think some of it applies (note that RIO is a big-endian system, not surprising since it originates from Motorola/Fscale), I'll look more closely and add the appropriate fixes into the next patch. Since Andrew took these into -mm I will just post patches against -mm.

Quoted 4 lines
Quoted 4 lines
drivers/rio/rio-sysfs.c (mode:100644) renamed from dev/null (tree:3c5e9440c6a37c3355b50608836a23c8fa4eec99) +4 -0
+static struct bin_attribute rio_config_attr = {
+	.attr = {
+		 .name = "config",
+		 .mode = S_IRUGO | S_IWUSR,
Quoted 8 lines

drivers/rio/rio-sysfs.c (mode:100644) line 172

Quoted 6 lines
drivers/rio/rio-sysfs.c (mode:100644) renamed from dev/null (tree:3c5e9440c6a37c3355b50608836a23c8fa4eec99) +6 -0
+		 .owner = THIS_MODULE,
+		 },
+	.size = 0x200000,
+	.read = rio_read_config,
+	.write = rio_write_config,
+};

Wow, that's a huge config space (just a comment, not an issue...)

Heh, yes. The "maintenance packets" that are used to access config space on RIO devices have a 21-bit offset field. I guess the spec guys didn't want to run out of config space too quickly. :)

-Matt

#9 lore raw
In reply to Matt Porter

drivers/rio/rio-driver.c (mode:100644) line 202

Quoted 3 lines · Matt Porter
drivers/rio/rio-driver.c (mode:100644) renamed from dev/null (tree:3c5e9440c6a37c3355b50608836a23c8fa4eec99) +3 -0
+static struct device rio_bus = {
+	.bus_id = "rapidio",
+};

Why do you need this device? You shouldn't have a static struct device to start with. Or you just don't like having your root rio device showing up in /sys/devices/ ?
If so, just create a kobject and put it there, and then base your devices off of it, no need for a real device.

Oh wait, that's what the platform and system code does. bah, nevermind...

thanks,

greg k-h

#10 lore raw
Quoted 8 lines · Greg KH

drivers/rio/rio-driver.c (mode:100644) line 202

Quoted 3 lines · Matt Porter
drivers/rio/rio-driver.c (mode:100644) renamed from dev/null (tree:3c5e9440c6a37c3355b50608836a23c8fa4eec99) +3 -0
+static struct device rio_bus = {
+	.bus_id = "rapidio",
+};

Why do you need this device? You shouldn't have a static struct device to start with. Or you just don't like having your root rio device showing up in /sys/devices/ ?

Exactly. There's no hierarchy in this interconnect. So it seemed that having a static rio_bus device made the most sense. Everything exists as peers since it works more like a network than a hierarchical bus like PCI. Right now, you can't see the endpoint which actually implements your port into the switch fabric...there's no device created for it. I'm still trying to determine if that should change but it's not critical to usability with the current generation hardware.

One argument I have _for_ it is that it would be easy to show and manipulate a network from userspace if all nodes had a device associated with them. That's not a real world problem yet so I decided not to complicate things yet.

Quoted 5 lines

If so, just create a kobject and put it there, and then base your devices off of it, no need for a real device.

Oh wait, that's what the platform and system code does. bah, nevermind...

Ok. I did pull this part right from the platform code, in fact.

-Matt