Skip to contentSkip to conversation

RapidIO support: core base

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

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

PATCH 1/5 RapidIO support: core base

[Updated with latest comments]

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

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

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

Documentation/DocBook/Makefile +1 -1
@@ -10,7 +10,7 @@ DOCBOOKS := wanbook.xml z8530book.xml mc
 	    kernel-hacking.xml kernel-locking.xml deviceiobook.xml \
 	    procfs-guide.xml writing_usb_driver.xml scsidrivers.xml \
 	    sis900.xml kernel-api.xml journal-api.xml lsm.xml usb.xml \
-	    gadget.xml libata.xml mtdnand.xml librs.xml
+	    gadget.xml libata.xml mtdnand.xml librs.xml rapidio.xml
 
 ###
 # The build process is as follows (targets):
Documentation/DocBook/rapidio.tmpl new file +160 -0

160 lines not on this page · raw message

drivers/Makefile +1 -0
@@ -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 new file +18 -0
new file mode 100644
@@ -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 new file +6 -0
new file mode 100644
@@ -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 new file +175 -0

175 lines not on this page · raw message

drivers/rio/rio-driver.c new file +229 -0

229 lines not on this page · raw message

drivers/rio/rio-sysfs.c new file +230 -0

230 lines not on this page · raw message

drivers/rio/rio.c new file +503 -0

503 lines not on this page · raw message

drivers/rio/rio.h new file +57 -0

57 lines not on this page · raw message

include/asm-generic/vmlinux.lds.h +7 -0
@@ -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 new file +311 -0
new file mode 100644
@@ -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=20
+ * @node: Node in global list of master ports
+ * @nnode: Node in network list of master ports
+ * @iores: I/O mem resource that this master port interface owns
+ * @riores: RIO resources that this master port interfaces owns
+ * @inb_msg: RIO inbound message event descriptors
+ * @outb_msg: RIO outbound message event descriptors
+ * @host_deviceid: Host device ID associated with this master port
+ * @ops: configuration space functions
+ * @id: Port ID, unique among all ports
+ * @index: Port index, unique among all port interfaces of the same type
+ * @name: Port name string
+ */
+struct rio_mport {
+	struct list_head dbells;	/* list of doorbell events */
+	struct list_head node;	/* node in global list of ports */
+	struct list_head nnode;	/* node in net list of ports */
+	struct resource iores;
+	struct resource riores[RIO_MAX_MPORT_RESOURCES];
+	struct rio_msg inb_msg[RIO_MAX_MBOX];
+	struct rio_msg outb_msg[RIO_MAX_MBOX];
+	int host_deviceid;	/* Host device ID */
+	struct rio_ops *ops;	/* maintenance transaction functions */
+	unsigned char id;	/* port ID, unique among all ports */
+	unsigned char index;	/* port index, unique among all port
+				   interfaces of the same type */
+	unsigned char name[40];
+};
+
+/**
+ * struct rio_net - RIO network info
+ * @node: Node in global list of RIO networks
+ * @devices: List of devices in this network
+ * @mports: List of master ports accessing this network
+ * @hport: Default port for accessing this network
+ * @id: RIO network ID
+ */
+struct rio_net {
+	struct list_head node;	/* node in list of networks */
+	struct list_head devices;	/* list of devices in this net */
+	struct list_head mports;	/* list of ports accessing net */
+	struct rio_mport *hport;	/* primary port for accessing net */
+	unsigned char id;	/* RIO network ID */
+};
+
+/**
+ * struct rio_switch - RIO switch info
+ * @node: Node in global list of switches
+ * @switchid: Switch ID that is unique across a network
+ * @hopcount: Hopcount to this switch
+ * @destid: Associated destid in the path
+ * @route_table: Copy of switch routing table
+ * @add_entry: Callback for switch-specific route add function
+ * @get_entry: Callback for switch-specific route get function
+ */
+struct rio_switch {
+	struct list_head node;
+	u16 switchid;
+	u16 hopcount;
+	u16 destid;
+	u8 route_table[RIO_MAX_ROUTE_ENTRIES];
+	int (*add_entry) (struct rio_mport * mport, u16 destid, u8 hopcount,
+			  u16 table, u16 route_destid, u8 route_port);
+	int (*get_entry) (struct rio_mport * mport, u16 destid, u8 hopcount,
+			  u16 table, u16 route_destid, u8 * route_port);
+};
+
+/* Low-level architecture-dependent routines */
+
+/**
+ * struct rio_ops - Low-level RIO configuration space operations
+ * @lcread: Callback to perform local (master port) read of config space.
+ * @lcwrite: Callback to perform local (master port) write of config space.
+ * @cread: Callback to perform network read of config space.
+ * @cwrite: Callback to perform network write of config space.
+ * @dsend: Callback to send a doorbell message.
+ */
+struct rio_ops {
+	int (*lcread) (int index, u32 offset, int len, u32 * data);
+	int (*lcwrite) (int index, u32 offset, int len, u32 data);
+	int (*cread) (int index, u16 destid, u8 hopcount, u32 offset, int len,
+		      u32 * data);
+	int (*cwrite) (int index, u16 destid, u8 hopcount, u32 offset, int len,
+		       u32 data);
+	int (*dsend) (int index, u16 destid, u16 data);
+};
+
+#define RIO_RESOURCE_MEM	0x00000100
+#define RIO_RESOURCE_DOORBELL	0x00000200
+#define RIO_RESOURCE_MAILBOX	0x00000400
+
+#define RIO_RESOURCE_CACHEABLE	0x00010000
+#define RIO_RESOURCE_PCI	0x00020000
+
+#define RIO_RESOURCE_BUSY	0x80000000
+
+/**
+ * struct rio_driver - RIO driver info
+ * @node: Node in list of drivers
+ * @name: RIO driver name
+ * @id_table: RIO device ids to be associated with this driver
+ * @probe: RIO device inserted
+ * @remove: RIO device removed
+ * @suspend: RIO device suspended
+ * @resume: RIO device awakened
+ * @enable_wake: RIO device enable wake event
+ * @driver: LDM driver struct
+ *
+ * Provides info on a RIO device driver for insertion/removal and
+ * power management purposes.
+ */
+struct rio_driver {
+	struct list_head node;
+	char *name;
+	const struct rio_device_id *id_table;
+	int (*probe) (struct rio_dev * dev, const struct rio_device_id * id);
+	void (*remove) (struct rio_dev * dev);
+	int (*suspend) (struct rio_dev * dev, u32 state);
+	int (*resume) (struct rio_dev * dev);
+	int (*enable_wake) (struct rio_dev * dev, u32 state, int enable);
+	struct device_driver driver;
+};
+
+#define	to_rio_driver(drv) container_of(drv,struct rio_driver, driver)
+
+/**
+ * struct rio_device_id - RIO device identifier
+ * @did: RIO device ID
+ * @vid: RIO vendor ID
+ * @asm_did: RIO assembly device ID
+ * @asm_vid: RIO assembly vendor ID
+ *
+ * Identifies a RIO device based on both the device/vendor IDs and
+ * the assembly device/vendor IDs.
+ */
+struct rio_device_id {
+	u16 did, vid;
+	u16 asm_did, asm_vid;
+};
+
+/**
+ * struct rio_route_ops - Per-switch route operations
+ * @vid: RIO vendor ID
+ * @did: RIO device ID
+ * @add_hook: Callback that adds a route entry
+ * @get_hook: Callback that gets a route entry
+ *
+ * Defines the operations that are necessary to manipulate the route
+ * tables for a particular RIO switch device.
+ */
+struct rio_route_ops {
+	u16 vid, did;
+	int (*add_hook) (struct rio_mport * mport, u16 destid, u8 hopcount,
+			 u16 table, u16 route_destid, u8 route_port);
+	int (*get_hook) (struct rio_mport * mport, u16 destid, u8 hopcount,
+			 u16 table, u16 route_destid, u8 * route_port);
+};
+
+/* Architecture and hardware-specific functions */
+extern int rio_init_mports(void);
+extern void rio_register_mport(struct rio_mport *);
+extern int rio_hw_add_outb_message(struct rio_mport *, struct rio_dev *, i=

nt,
+ void *, size_t);
+extern int rio_hw_add_inb_buffer(struct rio_mport *, int, void *); +extern void *rio_hw_get_inb_message(struct rio_mport *, int); +extern int rio_open_inb_mbox(struct rio_mport *, int, int); +extern void rio_close_inb_mbox(struct rio_mport *, int); +extern int rio_open_outb_mbox(struct rio_mport *, int, int); +extern void rio_close_outb_mbox(struct rio_mport *, int); +
+#endif /* __KERNEL__ */
+#endif /* LINUX_RIO_H */

include/linux/rio_drv.h new file +61 -0

61 lines not on this page · raw message

set,
+ u32 * data)
+{
+ return __rio_local_read_config_32(port, offset, data);
+}
+
+/**
+ * rio_local_write_config_32 - Write 32 bits to local configuration space
+ * @port: Master port
+ * @offset: Offset into local configuration space
+ * @data: Data to be written=20
+ *=20
+ * Writes 32 bits of data to the specified offset within the local
+ * device's configuration space.
+ */
+static inline int rio_local_write_config_32(struct rio_mport *port, u32 of= fset,
+ u32 data)
+{
+ return __rio_local_write_config_32(port, offset, data);
+}
+
+/**
+ * rio_local_read_config_16 - Read 16 bits from local configuration space
+ * @port: Master port
+ * @offset: Offset into local configuration space
+ * @data: Pointer to read data into
+ *=20
+ * Reads 16 bits of data from the specified offset within the local
+ * device's configuration space.
+ */
+static inline int rio_local_read_config_16(struct rio_mport *port, u32 off= set,
+ u16 * data)
+{
+ return __rio_local_read_config_16(port, offset, data);
+}
+
+/**
+ * rio_local_write_config_16 - Write 16 bits to local configuration space
+ * @port: Master port
+ * @offset: Offset into local configuration space
+ * @data: Data to be written=20
+ *=20
+ * Writes 16 bits of data to the specified offset within the local
+ * device's configuration space.
+ */
+
+static inline int rio_local_write_config_16(struct rio_mport *port, u32 of= fset,
+ u16 data)
+{
+ return __rio_local_write_config_16(port, offset, data);
+}
+
+/**
+ * rio_local_read_config_8 - Read 8 bits from local configuration space
+ * @port: Master port
+ * @offset: Offset into local configuration space
+ * @data: Pointer to read data into
+ *=20
+ * Reads 8 bits of data from the specified offset within the local
+ * device's configuration space.
+ */
+static inline int rio_local_read_config_8(struct rio_mport *port, u32 offs= et,
+ u8 * data)
+{
+ return __rio_local_read_config_8(port, offset, data);
+}
+
+/**
+ * rio_local_write_config_8 - Write 8 bits to local configuration space
+ * @port: Master port
+ * @offset: Offset into local configuration space
+ * @data: Data to be written=20
+ *=20
+ * Writes 8 bits of data to the specified offset within the local
+ * device's configuration space.
+ */
+static inline int rio_local_write_config_8(struct rio_mport *port, u32 off= set,
+ u8 data)
+{
+ return __rio_local_write_config_8(port, offset, data);
+}
+
+/**
+ * rio_read_config_32 - Read 32 bits from configuration space
+ * @rdev: RIO device
+ * @offset: Offset into device configuration space
+ * @data: Pointer to read data into
+ *=20
+ * Reads 32 bits of data from the specified offset within the
+ * RIO device's configuration space.
+ */
+static inline int rio_read_config_32(struct rio_dev *rdev, u32 offset,
+ u32 * data)
+{
+ u8 hopcount =3D 0xff;
+ u16 destid =3D rdev->destid;
+
+ if (rdev->rswitch) {
+ destid =3D rdev->rswitch->destid;
+ hopcount =3D rdev->rswitch->hopcount;
+ }
+
+ return rio_mport_read_config_32(rdev->net->hport, destid, hopcount,
+ offset, data);
+};
+
+/**
+ * rio_write_config_32 - Write 32 bits to configuration space
+ * @rdev: RIO device
+ * @offset: Offset into device configuration space
+ * @data: Data to be written
+ *=20
+ * Writes 32 bits of data to the specified offset within the
+ * RIO device's configuration space.
+ */
+static inline int rio_write_config_32(struct rio_dev *rdev, u32 offset,
+ u32 data)
+{
+ u8 hopcount =3D 0xff;
+ u16 destid =3D rdev->destid;
+
+ if (rdev->rswitch) {
+ destid =3D rdev->rswitch->destid;
+ hopcount =3D rdev->rswitch->hopcount;
+ }
+
+ return rio_mport_write_config_32(rdev->net->hport, destid, hopcount,
+ offset, data);
+};
+
+/**
+ * rio_read_config_16 - Read 16 bits from configuration space
+ * @rdev: RIO device
+ * @offset: Offset into device configuration space
+ * @data: Pointer to read data into
+ *=20
+ * Reads 16 bits of data from the specified offset within the
+ * RIO device's configuration space.
+ */
+static inline int rio_read_config_16(struct rio_dev *rdev, u32 offset,
+ u16 * data)
+{
+ u8 hopcount =3D 0xff;
+ u16 destid =3D rdev->destid;
+
+ if (rdev->rswitch) {
+ destid =3D rdev->rswitch->destid;
+ hopcount =3D rdev->rswitch->hopcount;
+ }
+
+ return rio_mport_read_config_16(rdev->net->hport, destid, hopcount,
+ offset, data);
+};
+
+/**
+ * rio_write_config_16 - Write 16 bits to configuration space
+ * @rdev: RIO device
+ * @offset: Offset into device configuration space
+ * @data: Data to be written
+ *=20
+ * Writes 16 bits of data to the specified offset within the
+ * RIO device's configuration space.
+ */
+static inline int rio_write_config_16(struct rio_dev *rdev, u32 offset,
+ u16 data)
+{
+ u8 hopcount =3D 0xff;
+ u16 destid =3D rdev->destid;
+
+ if (rdev->rswitch) {
+ destid =3D rdev->rswitch->destid;
+ hopcount =3D rdev->rswitch->hopcount;
+ }
+
+ return rio_mport_write_config_16(rdev->net->hport, destid, hopcount,
+ offset, data);
+};
+
+/**
+ * rio_read_config_8 - Read 8 bits from configuration space
+ * @rdev: RIO device
+ * @offset: Offset into device configuration space
+ * @data: Pointer to read data into
+ *=20
+ * Reads 8 bits of data from the specified offset within the
+ * RIO device's configuration space.
+ */
+static inline int rio_read_config_8(struct rio_dev *rdev, u32 offset, u8 *=
data)
+{
+ u8 hopcount =3D 0xff;
+ u16 destid =3D rdev->destid;
+
+ if (rdev->rswitch) {
+ destid =3D rdev->rswitch->destid;
+ hopcount =3D rdev->rswitch->hopcount;
+ }
+
+ return rio_mport_read_config_8(rdev->net->hport, destid, hopcount,
+ offset, data);
+};
+
+/**
+ * rio_write_config_8 - Write 8 bits to configuration space
+ * @rdev: RIO device
+ * @offset: Offset into device configuration space
+ * @data: Data to be written
+ *=20
+ * Writes 8 bits of data to the specified offset within the
+ * RIO device's configuration space.
+ */
+static inline int rio_write_config_8(struct rio_dev *rdev, u32 offset, u8 = data)
+{
+ u8 hopcount =3D 0xff;
+ u16 destid =3D rdev->destid;
+
+ if (rdev->rswitch) {
+ destid =3D rdev->rswitch->destid;
+ hopcount =3D rdev->rswitch->hopcount;
+ }
+
+ return rio_mport_write_config_8(rdev->net->hport, destid, hopcount,
+ offset, data);
+};
+
+extern int rio_mport_send_doorbell(struct rio_mport *mport, u16 destid,
+ u16 data);
+
+/**
+ * rio_send_doorbell - Send a doorbell message to a device
+ * @rdev: RIO device
+ * @data: Doorbell message data
+ *=20
+ * Send a doorbell message to a RIO device. The doorbell message
+ * has a 16-bit info field provided by the @data argument.
+ */
+static inline int rio_send_doorbell(struct rio_dev *rdev, u16 data) +{
+ return rio_mport_send_doorbell(rdev->net->hport, rdev->destid, data);
+};
+
+/**
+ * rio_init_mbox_res - Initialize a RIO mailbox resource
+ * @res: resource struct
+ * @start: start of mailbox range
+ * @end: end of mailbox range
+ *
+ * This function is used to initialize the fields of a resource
+ * for use as a mailbox resource. It initializes a range of
+ * mailboxes using the start and end arguments.
+ */
+static inline void rio_init_mbox_res(struct resource *res, int start, int = end)
+{
+ memset(res, 0, sizeof(struct resource));
+ res->start =3D start;
+ res->end =3D end;
+ res->flags =3D RIO_RESOURCE_MAILBOX;
+}
+
+/**
+ * rio_init_dbell_res - Initialize a RIO doorbell resource
+ * @res: resource struct
+ * @start: start of doorbell range
+ * @end: end of doorbell range
+ *
+ * This function is used to initialize the fields of a resource
+ * for use as a doorbell resource. It initializes a range of
+ * doorbell messages using the start and end arguments.
+ */
+static inline void rio_init_dbell_res(struct resource *res, u16 start, u16=
end)
+{
+ memset(res, 0, sizeof(struct resource));
+ res->start =3D start;
+ res->end =3D end;
+ res->flags =3D RIO_RESOURCE_DOORBELL;
+}
+
+/**
+ * RIO_DEVICE - macro used to describe a specific RIO device
+ * @vid: the 16 bit RIO vendor ID
+ * @did: the 16 bit RIO device ID
+ *
+ * This macro is used to create a struct rio_device_id that matches a
+ * specific device. The assembly vendor and assembly device fields
+ * will be set to %RIO_ANY_ID.
+ */
+#define RIO_DEVICE(dev,ven) \
+ .did =3D (dev), .vid =3D (ven), \
+ .asm_did =3D RIO_ANY_ID, .asm_vid =3D RIO_ANY_ID
+
+/* Mailbox management */
+extern int rio_request_outb_mbox(struct rio_mport *, int, int,
+ void (*)(struct rio_mport *, int, int));
+extern int rio_release_outb_mbox(struct rio_mport *, int);
+
+/**
+ * rio_add_outb_message - Add RIO message to an outbound mailbox queue
+ * @mport: RIO master port containing the outbound queue
+ * @rdev: RIO device the message is be sent to
+ * @mbox: The outbound mailbox queue
+ * @buffer: Pointer to the message buffer
+ * @len: Length of the message buffer
+ *
+ * Adds a RIO message buffer to an outbound mailbox queue for
+ * transmission. Returns 0 on success.
+ */
+static inline int rio_add_outb_message(struct rio_mport *mport,
+ struct rio_dev *rdev, int mbox,
+ void *buffer, size_t len)
+{
+ return rio_hw_add_outb_message(mport, rdev, mbox, buffer, len);
+}
+
+extern int rio_request_inb_mbox(struct rio_mport *, int, int,
+ void (*)(struct rio_mport *, int, int));
+extern int rio_release_inb_mbox(struct rio_mport *, int);
+
+/**
+ * rio_add_inb_buffer - Add buffer to an inbound mailbox queue
+ * @mport: Master port containing the inbound mailbox
+ * @mbox: The inbound mailbox number
+ * @buffer: Pointer to the message buffer
+ *
+ * Adds a buffer to an inbound mailbox queue for reception. Returns
+ * 0 on success.
+ */
+static inline int rio_add_inb_buffer(struct rio_mport *mport, int mbox,
+ void *buffer)
+{
+ return rio_hw_add_inb_buffer(mport, mbox, buffer);
+}
+
+/**
+ * rio_get_inb_message - Get A RIO message from an inbound mailbox queue
+ * @mport: Master port containing the inbound mailbox
+ * @mbox: The inbound mailbox number
+ * @buffer: Pointer to the message buffer
+ *
+ * Get a RIO message from an inbound mailbox queue. Returns 0 on success.
+ */
+static inline void *rio_get_inb_message(struct rio_mport *mport, int mbox) +{
+ return rio_hw_get_inb_message(mport, mbox);
+}
+
+/* Doorbell management */
+extern int rio_request_inb_dbell(struct rio_mport *, u16, u16,
+ void (*)(struct rio_mport *, u16, u16, u16));
+extern int rio_release_inb_dbell(struct rio_mport *, u16, u16); +extern struct resource *rio_request_outb_dbell(struct rio_dev *, u16, u16); +extern int rio_release_outb_dbell(struct rio_dev *, struct resource *); +
+/* Memory region management */
+int rio_claim_resource(struct rio_dev *, int);
+int rio_request_regions(struct rio_dev *, char *);
+void rio_release_regions(struct rio_dev *);
+int rio_request_region(struct rio_dev *, int, char *);
+void rio_release_region(struct rio_dev *, int);
+
+/* LDM support */
+int rio_register_driver(struct rio_driver *);
+void rio_unregister_driver(struct rio_driver *);
+struct rio_dev *rio_dev_get(struct rio_dev *);
+void rio_dev_put(struct rio_dev *);
+
+/**
+ * rio_name - Get the unique RIO device identifier
+ * @rdev: RIO device
+ *
+ * Get the unique RIO device identifier. Returns the device
+ * identifier string.
+ */
+static inline char *rio_name(struct rio_dev *rdev)
+{
+ return rdev->dev.bus_id;
+}
+
+/**
+ * rio_get_drvdata - Get RIO driver specific data
+ * @rdev: RIO device
+ *
+ * Get RIO driver specific data. Returns a pointer to the
+ * driver specific data.
+ */
+static inline void *rio_get_drvdata(struct rio_dev *rdev)
+{
+ return dev_get_drvdata(&rdev->dev);
+}
+
+/**
+ * rio_set_drvdata - Set RIO driver specific data
+ * @rdev: RIO device
+ * @data: Pointer to driver specific data
+ *
+ * Set RIO driver specific data. device struct driver data pointer
+ * is set to the @data argument.
+ */
+static inline void rio_set_drvdata(struct rio_dev *rdev, void *data) +{
+ dev_set_drvdata(&rdev->dev, data);
+}
+
+/* Misc driver helpers */
+extern u16 rio_local_get_device_id(struct rio_mport *port); +extern struct rio_dev *rio_get_device(u16 vid, u16 did, struct rio_dev *fr= om);
+extern struct rio_dev *rio_get_asm(u16 vid, u16 did, u16 asm_vid, u16 asm_= did,
+ struct rio_dev *from);
+
+#endif /* __KERNEL__ */
+#endif /* LINUX_RIO_DRV_H */

include/linux/rio_ids.h new file +24 -0
new file mode 100644
@@ -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 new file +49 -0

49 lines not on this page · raw message

rts */
+#define RIO_SWP_INFO_PORT_NUM_MASK 0x000000ff /* [I] Maintenance transact=
ion port number */
+#define RIO_GET_TOTAL_PORTS(x) ((x & RIO_SWP_INFO_PORT_TOTAL_MASK) >> 8)
+
+#define RIO_SRC_OPS_CAR 0x18 /* [I] Source Operations CAR */

+#define  RIO_SRC_OPS_READ		0x00008000	/* [I] Read op */
+#define  RIO_SRC_OPS_WRITE		0x00004000	/* [I] Write op */
+#define  RIO_SRC_OPS_STREAM_WRITE	0x00002000	/* [I] Str-write op */
+#define  RIO_SRC_OPS_WRITE_RESPONSE	0x00001000	/* [I] Write/resp op */
+#define  RIO_SRC_OPS_DATA_MSG		0x00000800	/* [II] Data msg op */
+#define  RIO_SRC_OPS_DOORBELL		0x00000400	/* [II] Doorbell op */
+#define  RIO_SRC_OPS_ATOMIC_TST_SWP	0x00000100	/* [I] Atomic TAS op */
+#define  RIO_SRC_OPS_ATOMIC_INC		0x00000080	/* [I] Atomic inc op */
+#define  RIO_SRC_OPS_ATOMIC_DEC		0x00000040	/* [I] Atomic dec op */
+#define  RIO_SRC_OPS_ATOMIC_SET		0x00000020	/* [I] Atomic set op */
+#define  RIO_SRC_OPS_ATOMIC_CLR		0x00000010	/* [I] Atomic clr op */
+#define  RIO_SRC_OPS_PORT_WRITE		0x00000004	/* [I] Port-write op */
+
+#define RIO_DST_OPS_CAR		0x1c	/* Destination Operations CAR */
+#define  RIO_DST_OPS_READ		0x00008000	/* [I] Read op */
+#define  RIO_DST_OPS_WRITE		0x00004000	/* [I] Write op */
+#define  RIO_DST_OPS_STREAM_WRITE	0x00002000	/* [I] Str-write op */
+#define  RIO_DST_OPS_WRITE_RESPONSE	0x00001000	/* [I] Write/resp op */
+#define  RIO_DST_OPS_DATA_MSG		0x00000800	/* [II] Data msg op */
+#define  RIO_DST_OPS_DOORBELL		0x00000400	/* [II] Doorbell op */
+#define  RIO_DST_OPS_ATOMIC_TST_SWP	0x00000100	/* [I] Atomic TAS op */
+#define  RIO_DST_OPS_ATOMIC_INC		0x00000080	/* [I] Atomic inc op */
+#define  RIO_DST_OPS_ATOMIC_DEC		0x00000040	/* [I] Atomic dec op */
+#define  RIO_DST_OPS_ATOMIC_SET		0x00000020	/* [I] Atomic set op */
+#define  RIO_DST_OPS_ATOMIC_CLR		0x00000010	/* [I] Atomic clr op */
+#define  RIO_DST_OPS_PORT_WRITE		0x00000004	/* [I] Port-write op */

+
+ /* 0x20-0x3c *//* Reserved */
+
+#define RIO_MBOX_CSR 0x40 /* [II] Mailbox CSR */

+#define  RIO_MBOX0_AVAIL		0x80000000	/* [II] Mbox 0 avail */
+#define  RIO_MBOX0_FULL			0x40000000	/* [II] Mbox 0 full */
+#define  RIO_MBOX0_EMPTY		0x20000000	/* [II] Mbox 0 empty */
+#define  RIO_MBOX0_BUSY			0x10000000	/* [II] Mbox 0 busy */
+#define  RIO_MBOX0_FAIL			0x08000000	/* [II] Mbox 0 fail */
+#define  RIO_MBOX0_ERROR		0x04000000	/* [II] Mbox 0 error */
+#define  RIO_MBOX1_AVAIL		0x00800000	/* [II] Mbox 1 avail */
+#define  RIO_MBOX1_FULL			0x00200000	/* [II] Mbox 1 full */
+#define  RIO_MBOX1_EMPTY		0x00200000	/* [II] Mbox 1 empty */
+#define  RIO_MBOX1_BUSY			0x00100000	/* [II] Mbox 1 busy */
+#define  RIO_MBOX1_FAIL			0x00080000	/* [II] Mbox 1 fail */
+#define  RIO_MBOX1_ERROR		0x00040000	/* [II] Mbox 1 error */
+#define  RIO_MBOX2_AVAIL		0x00008000	/* [II] Mbox 2 avail */
+#define  RIO_MBOX2_FULL			0x00004000	/* [II] Mbox 2 full */
+#define  RIO_MBOX2_EMPTY		0x00002000	/* [II] Mbox 2 empty */
+#define  RIO_MBOX2_BUSY			0x00001000	/* [II] Mbox 2 busy */
+#define  RIO_MBOX2_FAIL			0x00000800	/* [II] Mbox 2 fail */
+#define  RIO_MBOX2_ERROR		0x00000400	/* [II] Mbox 2 error */
+#define  RIO_MBOX3_AVAIL		0x00000080	/* [II] Mbox 3 avail */
+#define  RIO_MBOX3_FULL			0x00000040	/* [II] Mbox 3 full */
+#define  RIO_MBOX3_EMPTY		0x00000020	/* [II] Mbox 3 empty */
+#define  RIO_MBOX3_BUSY			0x00000010	/* [II] Mbox 3 busy */
+#define  RIO_MBOX3_FAIL			0x00000008	/* [II] Mbox 3 fail */
+#define  RIO_MBOX3_ERROR		0x00000004	/* [II] Mbox 3 error */
+
+#define RIO_WRITE_PORT_CSR	0x44	/* [I] Write Port CSR */
+#define RIO_DOORBELL_CSR	0x44	/* [II] Doorbell CSR */
+#define  RIO_DOORBELL_AVAIL		0x80000000	/* [II] Doorbell avail */
+#define  RIO_DOORBELL_FULL		0x40000000	/* [II] Doorbell full */
+#define  RIO_DOORBELL_EMPTY		0x20000000	/* [II] Doorbell empty */
+#define  RIO_DOORBELL_BUSY		0x10000000	/* [II] Doorbell busy */
+#define  RIO_DOORBELL_FAILED		0x08000000	/* [II] Doorbell failed */
+#define  RIO_DOORBELL_ERROR		0x04000000	/* [II] Doorbell error */
+#define  RIO_WRITE_PORT_AVAILABLE	0x00000080	/* [I] Write Port Available */
+#define  RIO_WRITE_PORT_FULL		0x00000040	/* [I] Write Port Full */
+#define  RIO_WRITE_PORT_EMPTY		0x00000020	/* [I] Write Port Empty */
+#define  RIO_WRITE_PORT_BUSY		0x00000010	/* [I] Write Port Busy */
+#define  RIO_WRITE_PORT_FAILED		0x00000008	/* [I] Write Port Failed */
+#define  RIO_WRITE_PORT_ERROR		0x00000004	/* [I] Write Port Error */

+
+ /* 0x48 *//* Reserved */
+
+#define RIO_PELL_CTRL_CSR 0x4c /* [I] PE Logical Layer Control CSR */

+#define   RIO_PELL_ADDR_66		0x00000004	/* [I] 66-bit addr */
+#define   RIO_PELL_ADDR_50		0x00000002	/* [I] 50-bit addr */
+#define   RIO_PELL_ADDR_34		0x00000001	/* [I] 34-bit addr */

+
+ /* 0x50-0x54 *//* Reserved */
+
+#define RIO_LCSH_BA 0x58 /* [I] LCS High Base Address */
+#define RIO_LCSL_BA 0x5c /* [I] LCS Base Address */
+
+#define RIO_DID_CSR 0x60 /* [III] Base Device ID CSR */
+
+ /* 0x64 *//* Reserved */
+
+#define RIO_HOST_DID_LOCK_CSR 0x68 /* [III] Host Base Device ID Lock CSR */
+#define RIO_COMPONENT_TAG_CSR 0x6c /* [III] Component Tag CSR */
+
+ /* 0x70-0xf8 *//* Reserved */
+ /* 0x100-0xfff8 *//* [I] Extended Features Space */
+ /* 0x10000-0xfffff8 *//* [I] Implementation-defined Space */
+
+/*
+ * Extended Features Space is a configuration space area where
+ * functionality is mapped into extended feature blocks via a
+ * singly linked list of extended feature pointers (EFT_PTR).
+ *
+ * Each extended feature block can be identified/located in
+ * Extended Features Space by walking the extended feature
+ * list starting with the Extended Feature Pointer located
+ * in the Assembly Information CAR.
+ *
+ * Extended Feature Blocks (EFBs) are identified with an assigned
+ * EFB ID. Extended feature block offsets in the definitions are
+ * relative to the offset of the EFB within the Extended Features
+ * Space.
+ */
+
+/* Helper macros to parse the Extended Feature Block header */
+#define RIO_EFB_PTR_MASK 0xffff0000
+#define RIO_EFB_ID_MASK 0x0000ffff
+#define RIO_GET_BLOCK_PTR(x) ((x & RIO_EFB_PTR_MASK) >> 16)
+#define RIO_GET_BLOCK_ID(x) (x & RIO_EFB_ID_MASK)
+
+/* Extended Feature Block IDs */
+#define RIO_EFB_PAR_EP_ID 0x0001 /* [IV] LP/LVDS EP Devices */
+#define RIO_EFB_PAR_EP_REC_ID 0x0002 /* [IV] LP/LVDS EP Recovery Devices */
+#define RIO_EFB_PAR_EP_FREE_ID 0x0003 /* [IV] LP/LVDS EP Free Devices */
+#define RIO_EFB_SER_EP_ID 0x0004 /* [VI] LP/Serial EP Devices */
+#define RIO_EFB_SER_EP_REC_ID 0x0005 /* [VI] LP/Serial EP Recovery Devices=
*/
+#define RIO_EFB_SER_EP_FREE_ID 0x0006 /* [VI] LP/Serial EP Free Devices */
+
+/*
+ * Physical 8/16 LP-LVDS
+ * ID=3D0x0001, Generic End Point Devices
+ * ID=3D0x0002, Generic End Point Devices, software assisted recovery opti= on
+ * ID=3D0x0003, Generic End Point Free Devices
+ *
+ * Physical LP-Serial
+ * ID=3D0x0004, Generic End Point Devices
+ * ID=3D0x0005, Generic End Point Devices, software assisted recovery opti= on
+ * ID=3D0x0006, Generic End Point Free Devices
+ */
+#define RIO_PORT_MNT_HEADER 0x0000
+#define RIO_PORT_REQ_CTL_CSR 0x0020
+#define RIO_PORT_RSP_CTL_CSR 0x0024 /* 0x0001/0x0002 */
+#define RIO_PORT_GEN_CTL_CSR 0x003c

+#define  RIO_PORT_GEN_HOST		0x80000000
+#define  RIO_PORT_GEN_MASTER		0x40000000
+#define  RIO_PORT_GEN_DISCOVERED	0x20000000

+#define RIO_PORT_N_MNT_REQ_CSR(x) (0x0040 + x*0x20) /* 0x0002 */
+#define RIO_PORT_N_MNT_RSP_CSR(x) (0x0044 + x*0x20) /* 0x0002 */
+#define RIO_PORT_N_ACK_STS_CSR(x) (0x0048 + x*0x20) /* 0x0002 */
+#define RIO_PORT_N_ERR_STS_CSR(x) (0x58 + x*0x20)
+#define PORT_N_ERR_STS_PORT_OK 0x00000002
+#define RIO_PORT_N_CTL_CSR(x) (0x5c + x*0x20)
+
+#endif /* LINUX_RIO_REGS_H */

#2 lore raw

PATCH 3/5 RapidIO support: core enum

Adds RapidIO enumeration/discovery.

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

drivers/rio/rio-scan.c new file +960 -0
new file mode 100644
@@ -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 new file +5 -0
new file mode 100644
@@ -0,0 +1,5 @@
+#
+# Makefile for RIO switches
+#
+
+obj-$(CONFIG_RAPIDIO)	+= tsi500.o
drivers/rio/switches/tsi500.c new file +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 +8 -0
@@ -1177,6 +1177,14 @@ source "drivers/pci/Kconfig"
 
 source "drivers/pcmcia/Kconfig"
 
+config RAPIDIO
+	bool "RapidIO support" if MPC8540 || MPC8560
+	help
+	  If you say Y here, the kernel will include drivers and
+	  infrastructure code to support RapidIO interconnect devices.
+
+source "drivers/rio/Kconfig"
+
 endmenu
 
 menu "Advanced setup"
arch/ppc/configs/stx_gp3_defconfig +52 -34

284 lines not on this page · raw message

arch/ppc/kernel/Makefile +1 -0
@@ -22,6 +22,7 @@ obj-$(CONFIG_POWER4)		+= cpu_setup_power
 obj-$(CONFIG_MODULES)		+= module.o ppc_ksyms.o
 obj-$(CONFIG_NOT_COHERENT_CACHE)	+= dma-mapping.o
 obj-$(CONFIG_PCI)		+= pci.o
+obj-$(CONFIG_RAPIDIO)		+= rio.o
 obj-$(CONFIG_KGDB)		+= ppc-stub.o
 obj-$(CONFIG_SMP)		+= smp.o smp-tbsync.o
 obj-$(CONFIG_TAU)		+= temp.o
arch/ppc/kernel/rio.c new file +52 -0

52 lines not on this page · raw message

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

867 lines not on this page · raw message

arch/ppc/syslib/ppc85xx_rio.h new file +21 -0
new file mode 100644
@@ -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 new file +18 -0
new file mode 100644
@@ -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

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 +14 -0
@@ -2185,6 +2185,20 @@ config ISERIES_VETH
 	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 +1 -0
@@ -58,6 +58,7 @@ obj-$(CONFIG_SKFP) += skfp/
 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 new file +597 -0

597 lines not on this page · raw message

#5 lore raw

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

In reply to Matt Porter

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

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

- kumar

Quoted 1,430 lines · Matt Porter

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

arch/ppc/Kconfig +8 -0
@@ -1177,6 +1177,14 @@ source "drivers/pci/Kconfig"
 
 source "drivers/pcmcia/Kconfig"
 
+config RAPIDIO
+	bool "RapidIO support" if MPC8540 || MPC8560
+	help
+	  If you say Y here, the kernel will include drivers and
+	  infrastructure code to support RapidIO interconnect devices.
+
+source "drivers/rio/Kconfig"
+
 endmenu
 
 menu "Advanced setup"
arch/ppc/configs/stx_gp3_defconfig +45 -32
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.11-rc2
-# Wed Jan 26 14:32:58 2005
+# Linux kernel version: 2.6.12-rc4
+# Tue May 24 18:11:04 2005
 #
 CONFIG_MMU=y
 CONFIG_GENERIC_HARDIRQS=y
@@ -11,6 +11,7 @@ CONFIG_HAVE_DEC_LOCK=y
 CONFIG_PPC=y
 CONFIG_PPC32=y
 CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
 
 #
 # Code maturity level options
@@ -18,6 +19,7 @@ CONFIG_GENERIC_NVRAM=y
 CONFIG_EXPERIMENTAL=y
 CONFIG_CLEAN_COMPILE=y
 CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
 
 #
 # General setup
@@ -29,7 +31,6 @@ CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
 CONFIG_HOTPLUG=y
 CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
@@ -37,6 +38,9 @@ CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
 # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
@@ -46,6 +50,7 @@ CONFIG_CC_ALIGN_LABELS=0
 CONFIG_CC_ALIGN_LOOPS=0
 CONFIG_CC_ALIGN_JUMPS=0
 # CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
 
 #
 # Loadable module support
@@ -69,9 +74,11 @@ CONFIG_KMOD=y
 CONFIG_E500=y
 CONFIG_BOOKE=y
 CONFIG_FSL_BOOKE=y
+# CONFIG_PHYS_64BIT is not set
 # CONFIG_SPE is not set
 CONFIG_MATH_EMULATION=y
 # CONFIG_CPU_FREQ is not set
+# CONFIG_PM is not set
 CONFIG_85xx=y
 CONFIG_PPC_INDIRECT_PCI_BE=y
 
@@ -96,6 +103,7 @@ CONFIG_HIGHMEM=y
 CONFIG_BINFMT_ELF=y
 CONFIG_BINFMT_MISC=m
 # CONFIG_CMDLINE_BOOL is not set
+CONFIG_ISA_DMA_API=y
 
 #
 # Bus options
@@ -104,15 +112,15 @@ CONFIG_PCI=y
 CONFIG_PCI_DOMAINS=y
 # CONFIG_PCI_LEGACY_PROC is not set
 # CONFIG_PCI_NAMES is not set
+# CONFIG_PCI_DEBUG is not set
 
 #
 # PCCARD (PCMCIA/CardBus) support
 #
 # CONFIG_PCCARD is not set
-
-#
-# PC-card bridges
-#
+CONFIG_RAPIDIO=y
+CONFIG_RAPIDIO_8_BIT_TRANSPORT=y
+CONFIG_RAPIDIO_DISC_TIMEOUT=30
 
 #
 # Advanced setup
@@ -152,7 +160,7 @@ CONFIG_PARPORT=m
 CONFIG_PARPORT_PC=m
 # CONFIG_PARPORT_PC_FIFO is not set
 # CONFIG_PARPORT_PC_SUPERIO is not set
-# CONFIG_PARPORT_OTHER is not set
+# CONFIG_PARPORT_GSC is not set
 # CONFIG_PARPORT_1284 is not set
 
 #
@@ -264,7 +272,6 @@ CONFIG_SCSI_CONSTANTS=y
 # CONFIG_SCSI_BUSLOGIC is not set
 # CONFIG_SCSI_DMX3191D is not set
 # CONFIG_SCSI_EATA is not set
-# CONFIG_SCSI_EATA_PIO is not set
 # CONFIG_SCSI_FUTURE_DOMAIN is not set
 # CONFIG_SCSI_GDTH is not set
 # CONFIG_SCSI_IPS is not set
@@ -274,7 +281,6 @@ CONFIG_SCSI_CONSTANTS=y
 # CONFIG_SCSI_IMM is not set
 # CONFIG_SCSI_SYM53C8XX_2 is not set
 # CONFIG_SCSI_IPR is not set
-# CONFIG_SCSI_QLOGIC_ISP is not set
 # CONFIG_SCSI_QLOGIC_FC is not set
 # CONFIG_SCSI_QLOGIC_1280 is not set
 CONFIG_SCSI_QLA2XXX=m
@@ -283,6 +289,7 @@ CONFIG_SCSI_QLA2XXX=m
 # CONFIG_SCSI_QLA2300 is not set
 # CONFIG_SCSI_QLA2322 is not set
 # CONFIG_SCSI_QLA6312 is not set
+# CONFIG_SCSI_LPFC is not set
 # CONFIG_SCSI_DC395x is not set
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_NSP32 is not set
@@ -322,7 +329,6 @@ CONFIG_NET=y
 #
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK_DEV is not set
 CONFIG_UNIX=y
 # CONFIG_NET_KEY is not set
 CONFIG_INET=y
@@ -431,7 +437,7 @@ CONFIG_IP_NF_NAT_FTP=m
 #
 # Network testing
 #
-# CONFIG_NET_PKTGEN is not set
+CONFIG_NET_PKTGEN=y
 # CONFIG_NETPOLL is not set
 # CONFIG_NET_POLL_CONTROLLER is not set
 # CONFIG_HAMRADIO is not set
@@ -499,6 +505,7 @@ CONFIG_GFAR_NAPI=y
 # Wan interfaces
 #
 # CONFIG_WAN is not set
+CONFIG_RIONET=y
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
 # CONFIG_PLIP is not set
@@ -536,20 +543,6 @@ CONFIG_INPUT_EVDEV=m
 # CONFIG_INPUT_EVBUG is not set
 
 #
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=y
-CONFIG_SERIO_I8042=y
-CONFIG_SERIO_SERPORT=y
-# CONFIG_SERIO_CT82C710 is not set
-# CONFIG_SERIO_PARKBD is not set
-# CONFIG_SERIO_PCIPS2 is not set
-CONFIG_SERIO_LIBPS2=y
-# CONFIG_SERIO_RAW is not set
-
-#
 # Input Device Drivers
 #
 CONFIG_INPUT_KEYBOARD=y
@@ -567,6 +560,19 @@ CONFIG_MOUSE_PS2=y
 # CONFIG_INPUT_MISC is not set
 
 #
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_I8042=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_PARKBD is not set
+# CONFIG_SERIO_PCIPS2 is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+
+#
 # Character devices
 #
 # CONFIG_VT is not set
@@ -590,6 +596,7 @@ CONFIG_SERIAL_CPM_SCC2=y
 # CONFIG_SERIAL_CPM_SCC4 is not set
 # CONFIG_SERIAL_CPM_SMC1 is not set
 # CONFIG_SERIAL_CPM_SMC2 is not set
+# CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
@@ -626,6 +633,11 @@ CONFIG_DRM=m
 # CONFIG_RAW_DRIVER is not set
 
 #
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
 # I2C support
 #
 CONFIG_I2C=m
@@ -648,12 +660,12 @@ CONFIG_I2C_ALGOBIT=m
 # CONFIG_I2C_AMD8111 is not set
 # CONFIG_I2C_I801 is not set
 # CONFIG_I2C_I810 is not set
+# CONFIG_I2C_PIIX4 is not set
 # CONFIG_I2C_ISA is not set
 # CONFIG_I2C_MPC is not set
 # CONFIG_I2C_NFORCE2 is not set
 # CONFIG_I2C_PARPORT is not set
 # CONFIG_I2C_PARPORT_LIGHT is not set
-# CONFIG_I2C_PIIX4 is not set
 # CONFIG_I2C_PROSAVAGE is not set
 # CONFIG_I2C_SAVAGE4 is not set
 # CONFIG_SCx200_ACB is not set
@@ -677,7 +689,9 @@ CONFIG_I2C_ALGOBIT=m
 # CONFIG_SENSORS_ASB100 is not set
 # CONFIG_SENSORS_DS1621 is not set
 # CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
 # CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
 # CONFIG_SENSORS_IT87 is not set
 # CONFIG_SENSORS_LM63 is not set
 # CONFIG_SENSORS_LM75 is not set
@@ -688,9 +702,11 @@ CONFIG_I2C_ALGOBIT=m
 # CONFIG_SENSORS_LM85 is not set
 # CONFIG_SENSORS_LM87 is not set
 # CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
 # CONFIG_SENSORS_MAX1619 is not set
 # CONFIG_SENSORS_PC87360 is not set
 # CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_SIS5595 is not set
 # CONFIG_SENSORS_SMSC47M1 is not set
 # CONFIG_SENSORS_VIA686A is not set
 # CONFIG_SENSORS_W83781D is not set
@@ -700,10 +716,12 @@ CONFIG_I2C_ALGOBIT=m
 #
 # Other I2C Chip support
 #
+# CONFIG_SENSORS_DS1337 is not set
 # CONFIG_SENSORS_EEPROM is not set
 # CONFIG_SENSORS_PCF8574 is not set
 # CONFIG_SENSORS_PCF8591 is not set
 # CONFIG_SENSORS_RTC8564 is not set
+# CONFIG_SENSORS_M41T00 is not set
 # CONFIG_I2C_DEBUG_CORE is not set
 # CONFIG_I2C_DEBUG_ALGO is not set
 # CONFIG_I2C_DEBUG_BUS is not set
@@ -732,7 +750,6 @@ CONFIG_I2C_ALGOBIT=m
 # Graphics support
 #
 # CONFIG_FB is not set
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
 # Sound
@@ -752,13 +769,9 @@ CONFIG_SOUND=m
 #
 # USB support
 #
-# CONFIG_USB is not set
 CONFIG_USB_ARCH_HAS_HCD=y
 CONFIG_USB_ARCH_HAS_OHCI=y
-
-#
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be 

needed; see USB_STORAGE Help for more information

arch/ppc/configs/stx_gp3_defconfig +7 -2
-#
+# CONFIG_USB is not set
 
 #
 # USB Gadget Support
@@ -789,6 +802,10 @@ CONFIG_JBD_DEBUG=y
 CONFIG_FS_MBCACHE=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
 # CONFIG_XFS_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
@@ -859,7 +876,6 @@ CONFIG_NFS_V3=y
 CONFIG_ROOT_NFS=y
 CONFIG_LOCKD=y
 CONFIG_LOCKD_V4=y
-# CONFIG_EXPORTFS is not set
 CONFIG_SUNRPC=y
 # CONFIG_RPCSEC_GSS_KRB5 is not set
 # CONFIG_RPCSEC_GSS_SPKM3 is not set
@@ -942,8 +958,10 @@ CONFIG_ZLIB_INFLATE=m
 #
 # Kernel hacking
 #
+# CONFIG_PRINTK_TIME is not set
 CONFIG_DEBUG_KERNEL=y
 # CONFIG_MAGIC_SYSRQ is not set
+CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_DEBUG_SLAB is not set
 # CONFIG_DEBUG_SPINLOCK is not set
arch/ppc/kernel/Makefile +1 -0
@@ -22,6 +22,7 @@ obj-$(CONFIG_POWER4)		+= cpu_setup_power
 obj-$(CONFIG_MODULES)		+= module.o ppc_ksyms.o
 obj-$(CONFIG_NOT_COHERENT_CACHE)	+= dma-mapping.o
 obj-$(CONFIG_PCI)		+= pci.o
+obj-$(CONFIG_RAPIDIO)		+= rio.o
 obj-$(CONFIG_KGDB)		+= ppc-stub.o
 obj-$(CONFIG_SMP)		+= smp.o smp-tbsync.o
 obj-$(CONFIG_TAU)		+= temp.o
arch/ppc/kernel/rio.c new file +7 -0
new file mode 100644
@@ -0,0 +1,52 @@
+/*
+ * RapidIO PPC32 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.
+ */

arch/ppc/kernel/rio.c new file +41 -0
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/rio.h>
+
+#include <asm/rio.h>
+
+/**
+ * platform_rio_init - Do platform specific RIO init
+ *
+ * Any platform specific initialization of RapdIO
+ * hardware is done here as well as registration
+ * of any active master ports in the system.
+ */
+void __attribute__ ((weak))
+    platform_rio_init(void)
+{
+	printk(KERN_WARNING "RIO: No platform_rio_init() present\n");
+}
+
+/**
+ * ppc_rio_init - Do PPC32 RIO init
+ *
+ * Calls platform-specific RIO init code and then calls
+ * rio_init_mports() to initialize any master ports that
+ * have been registered with the RIO subsystem.
+ */
+static int __init ppc_rio_init(void)
+{
+	printk(KERN_INFO "RIO: RapidIO init\n");
+
+	/* Platform specific initialization */
+	platform_rio_init();
+
+	/* Enumerate all registered ports */
+	rio_init_mports();
+
+	return 0;
+}
+
+subsys_initcall(ppc_rio_init);
arch/ppc/platforms/85xx/stx_gp3.c +14 -1
@@ -38,6 +38,7 @@
 #include <linux/module.h>
 #include <linux/fsl_devices.h>
 #include <linux/interrupt.h>
+#include <linux/rio.h>
 
 #include <asm/system.h>
 #include <asm/pgtable.h>
@@ -59,6 +60,7 @@
 
 #include <syslib/cpm2_pic.h>
 #include <syslib/ppc85xx_common.h>
+#include <syslib/ppc85xx_rio.h>
 
 extern void cpm2_reset(void);
 
@@ -200,7 +202,6 @@ static struct irqaction cpm2_irqaction =
 static void __init
 gp3_init_IRQ(void)
 {
-	int i;
 	bd_t *binfo = (bd_t *) __res;
 
 	/*
@@ -297,6 +298,18 @@ int mpc85xx_exclude_device(u_char bus, u
 }
 #endif /* CONFIG_PCI */
 
+#ifdef CONFIG_RAPIDIO
+void
+platform_rio_init(void)
+{
+	/*
+	 * The STx firmware configures the RapidIO Local Access Window
+	 * at 0xc0000000 with a size of 512MB.
+	 */
+	mpc85xx_rio_setup(0xc0000000, 0x20000000);
+}
+#endif /* CONFIG_RAPIDIO */
+
 void __init
 platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
 	      unsigned long r6, unsigned long r7)
arch/ppc/syslib/Makefile +1 -0
@@ -101,6 +101,7 @@ obj-$(CONFIG_85xx)		+= open_pic.o ppc85x
 					mpc85xx_devices.o
 ifeq ($(CONFIG_85xx),y)
 obj-$(CONFIG_PCI)		+= indirect_pci.o pci_auto.o
+obj-$(CONFIG_RAPIDIO)		+= ppc85xx_rio.o
 endif
 obj-$(CONFIG_83xx)		+= ipic.o ppc83xx_setup.o ppc_sys.o \
 					mpc83xx_sys.o mpc83xx_devices.o
arch/ppc/syslib/ppc85xx_rio.c new file +7 -0
new file mode 100644
@@ -0,0 +1,867 @@
+/*
+ * MPC85xx RapidIO 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.
+ */

arch/ppc/syslib/ppc85xx_rio.c new file +156 -0
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/rio.h>
+#include <linux/rio_drv.h>
+
+#include <asm/io.h>
+
+#define RIO_REGS_BASE		(CCSRBAR + 0xc0000)
+#define RIO_ATMU_REGS_OFFSET	0x10c00
+#define RIO_MSG_REGS_OFFSET	0x11000
+#define RIO_MAINT_WIN_SIZE	0x400000
+#define RIO_DBELL_WIN_SIZE	0x1000
+
+#define RIO_MSG_OMR_MUI		0x00000002
+#define RIO_MSG_OSR_TE		0x00000080
+#define RIO_MSG_OSR_QOI		0x00000020
+#define RIO_MSG_OSR_QFI		0x00000010
+#define RIO_MSG_OSR_MUB		0x00000004
+#define RIO_MSG_OSR_EOMI	0x00000002
+#define RIO_MSG_OSR_QEI		0x00000001
+
+#define RIO_MSG_IMR_MI		0x00000002
+#define RIO_MSG_ISR_TE		0x00000080
+#define RIO_MSG_ISR_QFI		0x00000010
+#define RIO_MSG_ISR_DIQI	0x00000001
+
+#define RIO_MSG_DESC_SIZE	32
+#define RIO_MIN_TX_RING_SIZE	2
+#define RIO_MAX_TX_RING_SIZE	2048
+#define RIO_MIN_RX_RING_SIZE	2
+#define RIO_MAX_RX_RING_SIZE	2048
+
+#define DOORBELL_DMR_DI		0x00000002
+#define DOORBELL_DSR_TE		0x00000080
+#define DOORBELL_DSR_QFI	0x00000010
+#define DOORBELL_DSR_DIQI	0x00000001
+#define DOORBELL_TID_OFFSET	0x03
+#define DOORBELL_SID_OFFSET	0x05
+#define DOORBELL_INFO_OFFSET	0x06
+
+#define DOORBELL_MESSAGE_SIZE	0x08
+#define DBELL_SID(x)		(*(u8 *)(x + DOORBELL_SID_OFFSET))
+#define DBELL_TID(x)		(*(u8 *)(x + DOORBELL_TID_OFFSET))
+#define DBELL_INF(x)		(*(u16 *)(x + DOORBELL_INFO_OFFSET))
+
+#define is_power_of_2(x)	(((x) & ((x) - 1)) == 0)
+
+struct rio_atmu_regs {
+	u32 rowtar;
+	u32 pad1;
+	u32 rowbar;
+	u32 pad2;
+	u32 rowar;
+	u32 pad3[3];
+};
+
+struct rio_msg_regs {
+	u32 omr;
+	u32 osr;
+	u32 pad1;
+	u32 odqdpar;
+	u32 pad2;
+	u32 osar;
+	u32 odpr;
+	u32 odatr;
+	u32 odcr;
+	u32 pad3;
+	u32 odqepar;
+	u32 pad4[13];
+	u32 imr;
+	u32 isr;
+	u32 pad5;
+	u32 ifqdpar;
+	u32 pad6;
+	u32 ifqepar;
+	u32 pad7[250];
+	u32 dmr;
+	u32 dsr;
+	u32 pad8;
+	u32 dqdpar;
+	u32 pad9;
+	u32 dqepar;
+	u32 pad10[26];
+	u32 pwmr;
+	u32 pwsr;
+	u32 pad11;
+	u32 pwqbar;
+};
+
+struct rio_tx_desc {
+	u32 res1;
+	u32 saddr;
+	u32 dport;
+	u32 dattr;
+	u32 res2;
+	u32 res3;
+	u32 dwcnt;
+	u32 res4;
+};
+
+static u32 regs_win;
+static struct rio_atmu_regs *atmu_regs;
+static struct rio_atmu_regs *maint_atmu_regs;
+static struct rio_atmu_regs *dbell_atmu_regs;
+static u32 dbell_win;
+static u32 maint_win;
+static struct rio_msg_regs *msg_regs;
+
+static struct rio_dbell_ring {
+	void *virt;
+	dma_addr_t phys;
+} dbell_ring;
+
+static struct rio_msg_tx_ring {
+	void *virt;
+	dma_addr_t phys;
+	void *virt_buffer[RIO_MAX_TX_RING_SIZE];
+	dma_addr_t phys_buffer[RIO_MAX_TX_RING_SIZE];
+	int tx_slot;
+	int size;
+} msg_tx_ring;
+
+static struct rio_msg_rx_ring {
+	void *virt;
+	dma_addr_t phys;
+	void *virt_buffer[RIO_MAX_RX_RING_SIZE];
+	int rx_slot;
+	int size;
+} msg_rx_ring;
+
+/**
+ * mpc85xx_rio_doorbell_send - Send a MPC85xx doorbell message
+ * @index: ID of RapidIO interface
+ * @destid: Destination ID of target device
+ * @data: 16-bit info field of RapidIO doorbell message
+ *
+ * Sends a MPC85xx doorbell message. Returns %0 on success or
+ * %-EINVAL on failure.
+ */
+static int mpc85xx_rio_doorbell_send(int index, u16 destid, u16 data)
+{
+	pr_debug("mpc85xx_doorbell_send: index %d destid %4.4x data %4.4x\n",
+		 index, destid, data);
+	out_be32((void *)&dbell_atmu_regs->rowtar, destid << 22);
+	out_be16((void *)(dbell_win), data);
+
+	return 0;
+}
+
+/**
+ * mpc85xx_local_config_read - Generate a MPC85xx local config space 

read
+ * @index: ID of RapdiIO interface
+ * @offset: Offset into configuration space
+ * @len: Length (in bytes) of the maintenance transaction
+ * @data: Value to be read into
+ *
+ * Generates a MPC85xx local configuration space read. Returns %0 on
+ * success or %-EINVAL on failure.
+ */
+static int mpc85xx_local_config_read(int index, u32 offset, int len, u32 * data)

arch/ppc/syslib/ppc85xx_rio.c new file +10 -0
+{
+	pr_debug("mpc85xx_local_config_read: index %d offset %8.8x\n", index,
+		 offset);
+	*data = in_be32((void *)(regs_win + offset));
+
+	return 0;
+}
+
+/**
+ * mpc85xx_local_config_write - Generate a MPC85xx local config space 

write
+ * @index: ID of RapdiIO interface
+ * @offset: Offset into configuration space
+ * @len: Length (in bytes) of the maintenance transaction
+ * @data: Value to be written
+ *
+ * Generates a MPC85xx local configuration space write. Returns %0 on
+ * success or %-EINVAL on failure.
+ */
+static int mpc85xx_local_config_write(int index, u32 offset, int len, u32 data)

arch/ppc/syslib/ppc85xx_rio.c new file +3 -0
+{
+	pr_debug
+	    ("mpc85xx_local_config_write: index %d offset %8.8x data 

%8.8x\n",

arch/ppc/syslib/ppc85xx_rio.c new file +8 -0
+	     index, offset, data);
+	out_be32((void *)(regs_win + offset), data);
+
+	return 0;
+}
+
+/**
+ * mpc85xx_rio_config_read - Generate a MPC85xx read maintenance 

transaction
+ * @index: ID of RapdiIO interface
+ * @destid: Destination ID of transaction
+ * @hopcount: Number of hops to target device
+ * @offset: Offset into configuration space
+ * @len: Length (in bytes) of the maintenance transaction
+ * @val: Location to be read into
+ *
+ * Generates a MPC85xx read maintenance transaction. Returns %0 on
+ * success or %-EINVAL on failure.
+ */

arch/ppc/syslib/ppc85xx_rio.c new file +2 -0
+static int
+mpc85xx_rio_config_read(int index, u16 destid, u8 hopcount, u32 

offset, int len,

arch/ppc/syslib/ppc85xx_rio.c new file +6 -0
+			u32 * val)
+{
+	u8 *data;
+
+	pr_debug
+	    ("mpc85xx_rio_config_read: index %d destid %d hopcount %d offset 

%8.8x len %d\n",

arch/ppc/syslib/ppc85xx_rio.c new file +22 -0
+	     index, destid, hopcount, offset, len);
+	out_be32((void *)&maint_atmu_regs->rowtar,
+		 (destid << 22) | (hopcount << 12) | ((offset & ~0x3) >> 9));
+
+	data = (u8 *) maint_win + offset;
+	switch (len) {
+	case 1:
+		*val = in_8((u8 *) data);
+		break;
+	case 2:
+		*val = in_be16((u16 *) data);
+		break;
+	default:
+		*val = in_be32((u32 *) data);
+		break;
+	}
+
+	return 0;
+}
+
+/**
+ * mpc85xx_rio_config_write - Generate a MPC85xx write maintenance 

transaction
+ * @index: ID of RapdiIO interface
+ * @destid: Destination ID of transaction
+ * @hopcount: Number of hops to target device
+ * @offset: Offset into configuration space
+ * @len: Length (in bytes) of the maintenance transaction
+ * @val: Value to be written
+ *
+ * Generates an MPC85xx write maintenance transaction. Returns %0 on
+ * success or %-EINVAL on failure.
+ */

arch/ppc/syslib/ppc85xx_rio.c new file +2 -0
+static int
+mpc85xx_rio_config_write(int index, u16 destid, u8 hopcount, u32 

offset,

arch/ppc/syslib/ppc85xx_rio.c new file +5 -0
+			 int len, u32 val)
+{
+	u8 *data;
+	pr_debug
+	    ("mpc85xx_rio_config_write: index %d destid %d hopcount %d 

offset %8.8x len %d val %8.8x\n",

arch/ppc/syslib/ppc85xx_rio.c new file +22 -0
+	     index, destid, hopcount, offset, len, val);
+	out_be32((void *)&maint_atmu_regs->rowtar,
+		 (destid << 22) | (hopcount << 12) | ((offset & ~0x3) >> 9));
+
+	data = (u8 *) maint_win + offset;
+	switch (len) {
+	case 1:
+		out_8((u8 *) data, val);
+		break;
+	case 2:
+		out_be16((u16 *) data, val);
+		break;
+	default:
+		out_be32((u32 *) data, val);
+		break;
+	}
+
+	return 0;
+}
+
+/**
+ * rio_hw_add_outb_message - Add message to the MPC85xx outbound 

message queue
+ * @mport: Master port with outbound message queue
+ * @rdev: Target of outbound message
+ * @mbox: Outbound mailbox
+ * @buffer: Message to add to outbound queue
+ * @len: Length of message
+ *
+ * Adds the @buffer message to the MPC85xx outbound message queue. Returns
+ * %0 on success or %-EINVAL on failure.
+ */

arch/ppc/syslib/ppc85xx_rio.c new file +2 -0
+int
+rio_hw_add_outb_message(struct rio_mport *mport, struct rio_dev 

*rdev, int mbox,

arch/ppc/syslib/ppc85xx_rio.c new file +9 -0
+			void *buffer, size_t len)
+{
+	u32 omr;
+	struct rio_tx_desc *desc =
+	    (struct rio_tx_desc *)msg_tx_ring.virt + msg_tx_ring.tx_slot;
+	int ret = 0;
+
+	pr_debug(KERN_INFO
+		 "RIO: rio_hw_add_outb_message(): destid %4.4x mbox %d buffer %8.8x 

len %8.8x\n",

arch/ppc/syslib/ppc85xx_rio.c new file +25 -0
+		 rdev->destid, mbox, (int)buffer, len);
+
+	if ((len < 8) || (len > RIO_MAX_MSG_SIZE)) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	/* Copy and clear rest of buffer */
+	memcpy(msg_tx_ring.virt_buffer[msg_tx_ring.tx_slot], buffer, len);
+	if (len < (RIO_MAX_MSG_SIZE - 4))
+		memset((void *)((u32) msg_tx_ring.
+				virt_buffer[msg_tx_ring.tx_slot] + len), 0,
+		       RIO_MAX_MSG_SIZE - len);
+
+	/* Set mbox field for message */
+	desc->dport = mbox & 0x3;
+
+	/* Enable EOMI interrupt, set priority, and set destid */
+	desc->dattr = 0x28000000 | (rdev->destid << 2);
+
+	/* Set transfer size aligned to next power of 2 (in double words) */
+	desc->dwcnt = is_power_of_2(len) ? len : 1 << get_bitmask_order(len);
+
+	/* Set snooping and source buffer address */
+	desc->saddr = 0x00000004 | 

msg_tx_ring.phys_buffer[msg_tx_ring.tx_slot];

arch/ppc/syslib/ppc85xx_rio.c new file +26 -0
+
+	/* Increment enqueue pointer */
+	omr = in_be32((void *)&msg_regs->omr);
+	out_be32((void *)&msg_regs->omr, omr | RIO_MSG_OMR_MUI);
+
+	/* Go to next descriptor */
+	if (++msg_tx_ring.tx_slot == msg_tx_ring.size)
+		msg_tx_ring.tx_slot = 0;
+
+      out:
+	return ret;
+}
+
+EXPORT_SYMBOL_GPL(rio_hw_add_outb_message);
+
+/**
+ * mpc85xx_rio_tx_handler - MPC85xx outbound message interrupt handler
+ * @irq: Linux interrupt number
+ * @dev_instance: Pointer to interrupt-specific data
+ * @regs: Register context
+ *
+ * Handles outbound message interrupts. Executes a register outbound
+ * mailbox event handler and acks the interrupt occurence.
+ */
+static irqreturn_t
+mpc85xx_rio_tx_handler(int irq, void *dev_instance, struct pt_regs 

*regs)

arch/ppc/syslib/ppc85xx_rio.c new file +99 -0
+{
+	int osr;
+	struct rio_mport *port = (struct rio_mport *)dev_instance;
+
+	osr = in_be32((void *)&msg_regs->osr);
+
+	if (osr & RIO_MSG_OSR_TE) {
+		printk(KERN_INFO "RIO: outbound message transmission error\n");
+		out_be32((void *)&msg_regs->osr, RIO_MSG_OSR_TE);
+		goto out;
+	}
+
+	if (osr & RIO_MSG_OSR_QOI) {
+		printk(KERN_INFO "RIO: outbound message queue overflow\n");
+		out_be32((void *)&msg_regs->osr, RIO_MSG_OSR_QOI);
+		goto out;
+	}
+
+	if (osr & RIO_MSG_OSR_EOMI) {
+		u32 dqp = in_be32((void *)&msg_regs->odqdpar);
+		int slot = (dqp - msg_tx_ring.phys) >> 5;
+		port->outb_msg[0].mcback(port, -1, slot);
+
+		/* Ack the end-of-message interrupt */
+		out_be32((void *)&msg_regs->osr, RIO_MSG_OSR_EOMI);
+	}
+
+      out:
+	return IRQ_HANDLED;
+}
+
+/**
+ * rio_open_outb_mbox - Initialize MPC85xx outbound mailbox
+ * @mport: Master port implementing the outbound message unit
+ * @mbox: Mailbox to open
+ * @entries: Number of entries in the outbound mailbox ring
+ *
+ * Initializes buffer ring, request the outbound message interrupt,
+ * and enables the outbound message unit. Returns %0 on success or
+ * %-EINVAL on failure.
+ */
+int rio_open_outb_mbox(struct rio_mport *mport, int mbox, int entries)
+{
+	int i, rc = 0;
+
+	if ((entries < RIO_MIN_TX_RING_SIZE) ||
+	    (entries > RIO_MAX_TX_RING_SIZE) || (!is_power_of_2(entries))) {
+		rc = -EINVAL;
+		goto out;
+	}
+
+	/* Initialize shadow copy ring */
+	msg_tx_ring.size = entries;
+
+	for (i = 0; i < msg_tx_ring.size; i++) {
+		msg_tx_ring.virt_buffer[i] =
+		    (void *)__get_free_page(GFP_KERNEL);
+		msg_tx_ring.phys_buffer[i] =
+		    (dma_addr_t) __pa(msg_tx_ring.virt_buffer[i]);
+	}
+
+	/* Initialize outbound message descriptor ring */
+	msg_tx_ring.virt = dma_alloc_coherent(NULL,
+					      msg_tx_ring.size *
+					      RIO_MSG_DESC_SIZE,
+					      &msg_tx_ring.phys, GFP_KERNEL);
+	memset(msg_tx_ring.virt, 0, msg_tx_ring.size * RIO_MSG_DESC_SIZE);
+	msg_tx_ring.tx_slot = 0;
+
+	/* Point dequeue/enqueue pointers at first entry in ring */
+	out_be32((void *)&msg_regs->odqdpar, msg_tx_ring.phys);
+	out_be32((void *)&msg_regs->odqepar, msg_tx_ring.phys);
+
+	/* Configure for snooping */
+	out_be32((void *)&msg_regs->osar, 0x00000004);
+
+	/* Clear interrupt status */
+	out_be32((void *)&msg_regs->osr, 0x000000b3);
+
+	/* Hook up outbound message handler */
+	request_irq(MPC85xx_IRQ_RIO_TX, mpc85xx_rio_tx_handler, 0, "msg_tx",
+		    (void *)mport);
+
+	/*
+	 * Configure outbound message unit
+	 *      Snooping
+	 *      Interrupts (all enabled, except QEIE)
+	 *      Chaining mode
+	 *      Disable
+	 */
+	out_be32((void *)&msg_regs->omr, 0x00100220);
+
+	/* Set number of entries */
+	out_be32((void *)&msg_regs->omr,
+		 in_be32((void *)&msg_regs->omr) |
+		 ((get_bitmask_order(entries) - 2) << 12));
+
+	/* Now enable the unit */
+	out_be32((void *)&msg_regs->omr, in_be32((void *)&msg_regs->omr) | 

0x1);

arch/ppc/syslib/ppc85xx_rio.c new file +37 -0
+
+      out:
+	return rc;
+}
+
+/**
+ * rio_close_outb_mbox - Shut down MPC85xx outbound mailbox
+ * @mport: Master port implementing the outbound message unit
+ * @mbox: Mailbox to close
+ *
+ * Disables the outbound message unit, free all buffers, and
+ * frees the outbound message interrupt.
+ */
+void rio_close_outb_mbox(struct rio_mport *mport, int mbox)
+{
+	/* Disable inbound message unit */
+	out_be32((void *)&msg_regs->omr, 0);
+
+	/* Free ring */
+	dma_free_coherent(NULL, msg_tx_ring.size * RIO_MSG_DESC_SIZE,
+			  msg_tx_ring.virt, msg_tx_ring.phys);
+
+	/* Free interrupt */
+	free_irq(MPC85xx_IRQ_RIO_TX, (void *)mport);
+}
+
+/**
+ * mpc85xx_rio_rx_handler - MPC85xx inbound message interrupt handler
+ * @irq: Linux interrupt number
+ * @dev_instance: Pointer to interrupt-specific data
+ * @regs: Register context
+ *
+ * Handles inbound message interrupts. Executes a registered inbound
+ * mailbox event handler and acks the interrupt occurence.
+ */
+static irqreturn_t
+mpc85xx_rio_rx_handler(int irq, void *dev_instance, struct pt_regs 

*regs)

arch/ppc/syslib/ppc85xx_rio.c new file +89 -0
+{
+	int isr;
+	struct rio_mport *port = (struct rio_mport *)dev_instance;
+
+	isr = in_be32((void *)&msg_regs->isr);
+
+	if (isr & RIO_MSG_ISR_TE) {
+		printk(KERN_INFO "RIO: inbound message reception error\n");
+		out_be32((void *)&msg_regs->isr, RIO_MSG_ISR_TE);
+		goto out;
+	}
+
+	/* XXX Need to check/dispatch until queue empty */
+	if (isr & RIO_MSG_ISR_DIQI) {
+		/*
+		 * We implement *only* mailbox 0, but can receive messages
+		 * for any mailbox/letter to that mailbox destination. So,
+		 * make the callback with an unknown/invalid mailbox number
+		 * argument.
+		 */
+		port->inb_msg[0].mcback(port, -1, -1);
+
+		/* Ack the queueing interrupt */
+		out_be32((void *)&msg_regs->isr, RIO_MSG_ISR_DIQI);
+	}
+
+      out:
+	return IRQ_HANDLED;
+}
+
+/**
+ * rio_open_inb_mbox - Initialize MPC85xx inbound mailbox
+ * @mport: Master port implementing the inbound message unit
+ * @mbox: Mailbox to open
+ * @entries: Number of entries in the inbound mailbox ring
+ *
+ * Initializes buffer ring, request the inbound message interrupt,
+ * and enables the inbound message unit. Returns %0 on success
+ * or %-EINVAL on failure.
+ */
+int rio_open_inb_mbox(struct rio_mport *mport, int mbox, int entries)
+{
+	int i, rc = 0;
+
+	if ((entries < RIO_MIN_RX_RING_SIZE) ||
+	    (entries > RIO_MAX_RX_RING_SIZE) || (!is_power_of_2(entries))) {
+		rc = -EINVAL;
+		goto out;
+	}
+
+	/* Initialize client buffer ring */
+	msg_rx_ring.size = entries;
+	msg_rx_ring.rx_slot = 0;
+	for (i = 0; i < msg_rx_ring.size; i++)
+		msg_rx_ring.virt_buffer[i] = NULL;
+
+	/* Initialize inbound message ring */
+	msg_rx_ring.virt = dma_alloc_coherent(NULL,
+					      msg_rx_ring.size *
+					      RIO_MAX_MSG_SIZE,
+					      &msg_rx_ring.phys, GFP_KERNEL);
+
+	/* Point dequeue/enqueue pointers at first entry in ring */
+	out_be32((void *)&msg_regs->ifqdpar, (u32) msg_rx_ring.phys);
+	out_be32((void *)&msg_regs->ifqepar, (u32) msg_rx_ring.phys);
+
+	/* Clear interrupt status */
+	out_be32((void *)&msg_regs->isr, 0x00000091);
+
+	/* Hook up inbound message handler */
+	request_irq(MPC85xx_IRQ_RIO_RX, mpc85xx_rio_rx_handler, 0, "msg_rx",
+		    (void *)mport);
+
+	/*
+	 * Configure inbound message unit:
+	 *      Snooping
+	 *      4KB max message size
+	 *      Unmask all interrupt sources
+	 *      Disable
+	 */
+	out_be32((void *)&msg_regs->imr, 0x001b0060);
+
+	/* Set number of queue entries */
+	out_be32((void *)&msg_regs->imr,
+		 in_be32((void *)&msg_regs->imr) |
+		 ((get_bitmask_order(entries) - 2) << 12));
+
+	/* Now enable the unit */
+	out_be32((void *)&msg_regs->imr, in_be32((void *)&msg_regs->imr) | 

0x1);

arch/ppc/syslib/ppc85xx_rio.c new file +28 -0
+
+      out:
+	return rc;
+}
+
+/**
+ * rio_close_inb_mbox - Shut down MPC85xx inbound mailbox
+ * @mport: Master port implementing the inbound message unit
+ * @mbox: Mailbox to close
+ *
+ * Disables the inbound message unit, free all buffers, and
+ * frees the inbound message interrupt.
+ */
+void rio_close_inb_mbox(struct rio_mport *mport, int mbox)
+{
+	/* Disable inbound message unit */
+	out_be32((void *)&msg_regs->imr, 0);
+
+	/* Free ring */
+	dma_free_coherent(NULL, msg_rx_ring.size * RIO_MAX_MSG_SIZE,
+			  msg_rx_ring.virt, msg_rx_ring.phys);
+
+	/* Free interrupt */
+	free_irq(MPC85xx_IRQ_RIO_RX, (void *)mport);
+}
+
+/**
+ * rio_hw_add_inb_buffer - Add buffer to the MPC85xx inbound message 

queue
+ * @mport: Master port implementing the inbound message unit
+ * @mbox: Inbound mailbox number
+ * @buf: Buffer to add to inbound queue
+ *
+ * Adds the @buf buffer to the MPC85xx inbound message queue. Returns
+ * %0 on success or %-EINVAL on failure.
+ */
+int rio_hw_add_inb_buffer(struct rio_mport *mport, int mbox, void *buf)

arch/ppc/syslib/ppc85xx_rio.c new file +26 -0
+{
+	int rc = 0;
+
+	pr_debug("RIO: rio_hw_add_inb_buffer(), msg_rx_ring.rx_slot %d\n",
+		 msg_rx_ring.rx_slot);
+
+	if (msg_rx_ring.virt_buffer[msg_rx_ring.rx_slot]) {
+		printk(KERN_ERR
+		       "RIO: error adding inbound buffer %d, buffer exists\n",
+		       msg_rx_ring.rx_slot);
+		rc = -EINVAL;
+		goto out;
+	}
+
+	msg_rx_ring.virt_buffer[msg_rx_ring.rx_slot] = buf;
+	if (++msg_rx_ring.rx_slot == msg_rx_ring.size)
+		msg_rx_ring.rx_slot = 0;
+
+      out:
+	return rc;
+}
+
+EXPORT_SYMBOL_GPL(rio_hw_add_inb_buffer);
+
+/**
+ * rio_hw_get_inb_message - Fetch inbound message from the MPC85xx 

message unit
+ * @mport: Master port implementing the inbound message unit
+ * @mbox: Inbound mailbox number
+ *
+ * Gets the next available inbound message from the inbound message queue.
+ * A pointer to the message is returned on success or NULL on failure.
+ */

arch/ppc/syslib/ppc85xx_rio.c new file +50 -0
+void *rio_hw_get_inb_message(struct rio_mport *mport, int mbox)
+{
+	u32 imr;
+	u32 phys_buf, virt_buf;
+	void *buf = NULL;
+	int buf_idx;
+
+	phys_buf = in_be32((void *)&msg_regs->ifqdpar);
+
+	/* If no more messages, then bail out */
+	if (phys_buf == in_be32((void *)&msg_regs->ifqepar))
+		goto out2;
+
+	virt_buf = (u32) msg_rx_ring.virt + (phys_buf - msg_rx_ring.phys);
+	buf_idx = (phys_buf - msg_rx_ring.phys) / RIO_MAX_MSG_SIZE;
+	buf = msg_rx_ring.virt_buffer[buf_idx];
+
+	if (!buf) {
+		pr_debug(KERN_ERR
+			 "RIO: inbound message copy failed, no buffers\n");
+		goto out1;
+	}
+
+	/* Copy max message size, caller is expected to allocate that big */
+	memcpy(buf, (void *)virt_buf, RIO_MAX_MSG_SIZE);
+
+	/* Clear the available buffer */
+	msg_rx_ring.virt_buffer[buf_idx] = NULL;
+
+      out1:
+	imr = in_be32((void *)&msg_regs->imr);
+	out_be32((void *)&msg_regs->imr, imr | RIO_MSG_IMR_MI);
+
+      out2:
+	return buf;
+}
+
+EXPORT_SYMBOL_GPL(rio_hw_get_inb_message);
+
+/**
+ * mpc85xx_rio_dbell_handler - MPC85xx doorbell interrupt handler
+ * @irq: Linux interrupt number
+ * @dev_instance: Pointer to interrupt-specific data
+ * @regs: Register context
+ *
+ * Handles doorbell interrupts. Parses a list of registered
+ * doorbell event handlers and executes a matching event handler.
+ */
+static irqreturn_t
+mpc85xx_rio_dbell_handler(int irq, void *dev_instance, struct pt_regs 

*regs)

arch/ppc/syslib/ppc85xx_rio.c new file +66 -0
+{
+	int dsr;
+	struct rio_mport *port = (struct rio_mport *)dev_instance;
+
+	dsr = in_be32((void *)&msg_regs->dsr);
+
+	if (dsr & DOORBELL_DSR_TE) {
+		printk(KERN_INFO "RIO: doorbell reception error\n");
+		out_be32((void *)&msg_regs->dsr, DOORBELL_DSR_TE);
+		goto out;
+	}
+
+	if (dsr & DOORBELL_DSR_QFI) {
+		printk(KERN_INFO "RIO: doorbell queue full\n");
+		out_be32((void *)&msg_regs->dsr, DOORBELL_DSR_QFI);
+		goto out;
+	}
+
+	/* XXX Need to check/dispatch until queue empty */
+	if (dsr & DOORBELL_DSR_DIQI) {
+		u32 dmsg =
+		    (u32) dbell_ring.virt +
+		    (in_be32((void *)&msg_regs->dqdpar) & 0xfff);
+		u32 dmr;
+		struct rio_dbell *dbell;
+		int found = 0;
+
+		pr_debug(KERN_INFO
+			 "RIO: processing doorbell, sid %2.2x tid %2.2x info %4.4x\n",
+			 DBELL_SID(dmsg), DBELL_TID(dmsg), DBELL_INF(dmsg));
+
+		list_for_each_entry(dbell, &port->dbells, node) {
+			if ((dbell->res->start <= DBELL_INF(dmsg)) &&
+			    (dbell->res->end >= DBELL_INF(dmsg))) {
+				found = 1;
+				break;
+			}
+		}
+		if (found) {
+			dbell->dinb(port, DBELL_SID(dmsg), DBELL_TID(dmsg),
+				    DBELL_INF(dmsg));
+		} else {
+			pr_debug(KERN_INFO
+				 "RIO: spurious doorbell, sid %2.2x tid %2.2x info %4.4x\n",
+				 DBELL_SID(dmsg), DBELL_TID(dmsg),
+				 DBELL_INF(dmsg));
+		}
+		dmr = in_be32((void *)&msg_regs->dmr);
+		out_be32((void *)&msg_regs->dmr, dmr | DOORBELL_DMR_DI);
+		out_be32((void *)&msg_regs->dsr, DOORBELL_DSR_DIQI);
+	}
+
+      out:
+	return IRQ_HANDLED;
+}
+
+/**
+ * mpc85xx_rio_doorbell_init - MPC85xx doorbell interface init
+ * @mport: Master port implementing the inbound doorbell unit
+ *
+ * Initializes doorbell unit hardware and inbound DMA buffer
+ * ring. Called from mpc85xx_rio_setup().
+ */
+static void mpc85xx_rio_doorbell_init(struct rio_mport *mport)
+{
+	/* Map outbound doorbell window immediately after maintenance window 

*/

arch/ppc/syslib/ppc85xx_rio.c new file +87 -0
+	dbell_win =
+	    (u32) ioremap(mport->iores.start + RIO_MAINT_WIN_SIZE,
+			  RIO_DBELL_WIN_SIZE);
+
+	/* Initialize inbound doorbells */
+	dbell_ring.virt = dma_alloc_coherent(NULL,
+					     512 * DOORBELL_MESSAGE_SIZE,
+					     &dbell_ring.phys, GFP_KERNEL);
+
+	/* Point dequeue/enqueue pointers at first entry in ring */
+	out_be32((void *)&msg_regs->dqdpar, (u32) dbell_ring.phys);
+	out_be32((void *)&msg_regs->dqepar, (u32) dbell_ring.phys);
+
+	/* Clear interrupt status */
+	out_be32((void *)&msg_regs->dsr, 0x00000091);
+
+	/* Hook up doorbell handler */
+	request_irq(MPC85xx_IRQ_RIO_BELL, mpc85xx_rio_dbell_handler, 0,
+		    "dbell_rx", (void *)mport);
+
+	/* Configure doorbells for snooping, 512 entries, and enable */
+	out_be32((void *)&msg_regs->dmr, 0x00108161);
+}
+
+static char *cmdline = NULL;
+
+static int mpc85xx_rio_get_hdid(int index)
+{
+	/* XXX Need to parse multiple entries in some format */
+	if (!cmdline)
+		return -1;
+
+	return simple_strtol(cmdline, NULL, 0);
+}
+
+static int mpc85xx_rio_get_cmdline(char *s)
+{
+	if (!s)
+		return 0;
+
+	cmdline = s;
+	return 1;
+}
+
+__setup("riohdid=", mpc85xx_rio_get_cmdline);
+
+/**
+ * mpc85xx_rio_setup - Setup MPC85xx RapidIO interface
+ * @law_start: Starting physical address of RapidIO LAW
+ * @law_size: Size of RapidIO LAW
+ *
+ * Initializes MPC85xx RapidIO hardware interface, configures
+ * master port with system-specific info, and registers the
+ * master port with the RapidIO subsystem.
+ */
+void mpc85xx_rio_setup(int law_start, int law_size)
+{
+	struct rio_ops *ops;
+	struct rio_mport *port;
+
+	ops = kmalloc(sizeof(struct rio_ops), GFP_KERNEL);
+	ops->lcread = mpc85xx_local_config_read;
+	ops->lcwrite = mpc85xx_local_config_write;
+	ops->cread = mpc85xx_rio_config_read;
+	ops->cwrite = mpc85xx_rio_config_write;
+	ops->dsend = mpc85xx_rio_doorbell_send;
+
+	port = kmalloc(sizeof(struct rio_mport), GFP_KERNEL);
+	port->id = 0;
+	port->index = 0;
+	INIT_LIST_HEAD(&port->dbells);
+	port->iores.start = law_start;
+	port->iores.end = law_start + law_size;
+	port->iores.flags = IORESOURCE_MEM;
+
+	rio_init_dbell_res(&port->riores[RIO_DOORBELL_RESOURCE], 0, 0xffff);
+	rio_init_mbox_res(&port->riores[RIO_INB_MBOX_RESOURCE], 0, 0);
+	rio_init_mbox_res(&port->riores[RIO_OUTB_MBOX_RESOURCE], 0, 0);
+	strcpy(port->name, "RIO0 mport");
+
+	port->ops = ops;
+	port->host_deviceid = mpc85xx_rio_get_hdid(port->id);
+
+	rio_register_mport(port);
+
+	regs_win = (u32) ioremap(RIO_REGS_BASE, 0x20000);
+	atmu_regs = (struct rio_atmu_regs *)(regs_win + 

RIO_ATMU_REGS_OFFSET);

arch/ppc/syslib/ppc85xx_rio.c new file +15 -0
+	maint_atmu_regs = atmu_regs + 1;
+	dbell_atmu_regs = atmu_regs + 2;
+	msg_regs = (struct rio_msg_regs *)(regs_win + RIO_MSG_REGS_OFFSET);
+
+	/* Configure maintenance transaction window */
+	out_be32((void *)&maint_atmu_regs->rowbar, 0x000c0000);
+	out_be32((void *)&maint_atmu_regs->rowar, 0x80077015);
+
+	maint_win = (u32) ioremap(law_start, RIO_MAINT_WIN_SIZE);
+
+	/* Configure outbound doorbell window */
+	out_be32((void *)&dbell_atmu_regs->rowbar, 0x000c0400);
+	out_be32((void *)&dbell_atmu_regs->rowar, 0x8004200b);
+	mpc85xx_rio_doorbell_init(port);
+}
arch/ppc/syslib/ppc85xx_rio.h new file +7 -0
new file mode 100644
@@ -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.
+ */

arch/ppc/syslib/ppc85xx_rio.h new file +10 -0
+
+#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 new file +7 -0
new file mode 100644
@@ -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.
+ */

include/asm-ppc/rio.h new file +7 -0
+
+#ifndef ASM_PPC_RIO_H
+#define ASM_PPC_RIO_H
+
+extern void platform_rio_init(void);
+
+#endif				/* ASM_PPC_RIO_H */

_______________________________________________
Linuxppc-embedded mailing list
[email protected]
https://ozlabs.org/mailman/listinfo/linuxppc-embedded

#6 lore raw

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

Quoted 2 lines · Kumar Gala

Two questions:
1. how well does will all of this handle > 32-bit phys addr?

It does and it doesn't handle > 32-bit phys addr. It depends on which configuration you are talking about. If you are talking about I/O

Quoted 1 line

32-bit, it's no problem. If you are talking about handling DMA >32-bit,

then we need to handle a 64-bit DMA addr in the ppc32 implementations and also extend the arch messaging interface to let callers know when an implementation can handle high DMA (system memory >4GB). This is all pretty easy to handle once we need to support such a processor. So far, nothing is available publicly. :)

For RIO MMIO purposes (which is functionality I'm working on now), it has the similar issues that PCI memory space has on processors with I/O above 4GB. However, on RIO our resources hold a bus address since a physical address doesn't make sense since address spaces our per-device. If we ever support a 66-bit address space device on 32-bit processor, we might need a u64 resource.

Quoted 1 line

2. can we make any of this a platform driver?

Hrm, so you would rather see RIO host bridges look like a driver on another "bus"? I have seen them as a component just like PCI host bridges. That is, they are instantiated by arch-code and then initialized by a subsys initcall. This does mean that we will be enumerating much later (during driver initcalls), but it might be a better model if we ever see a rumored PCIE->RIO bridge. Supporting that as a RIO master port would require driver time init of the RIO fabric. There's some ordering issues that we'd have to see about working out. None of this is needed right now, though.

Quoted 2 lines

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

I think this and #2 are separate issues. We can pass the mpc85xx rio init code some parameters to abstract things to different parts. This is similar to how we init different SoC's PCI host bridges with some common code on PPC32 (marvell, 85xx, etc).

I was just looking at doing this to support RIO on the 8548. At the time I wrote this 85xx support there wasn't any info on the 8548 available, but it's an easy thing to extend.

-Matt

#7 lore raw

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

Quoted 6 lines · Matt Porter
Quoted 2 lines · Kumar Gala

Two questions:
1. how well does will all of this handle > 32-bit phys addr?

It does and it doesn't handle > 32-bit phys addr. It depends on which configuration you are talking about. If you are talking about I/O

Quoted 8 lines
Quoted 2 lines

32-bit, it's no problem. If you are talking about handling DMA 32-bit,

then we need to handle a 64-bit DMA addr in the ppc32 implementations and
also extend the arch messaging interface to let callers know when an implementation can handle high DMA (system memory >4GB). This is all pretty easy to handle once we need to support such a processor. So far, nothing is available publicly. :)

Well 8548 is semi-public :)

Quoted 7 lines

For RIO MMIO purposes (which is functionality I'm working on now), it has the similar issues that PCI memory space has on processors with I/O above 4GB. However, on RIO our resources hold a bus address since a physical address doesn't make sense since address spaces our per-device.
If we ever support a 66-bit address space device on 32-bit processor, we might need a u64 resource.

I assume you mean 36-bit, what would one do with 66-bit addresses :)

Quoted 16 lines
Quoted 1 line

2. can we make any of this a platform driver?

Hrm, so you would rather see RIO host bridges look like a driver on another "bus"? I have seen them as a component just like PCI host bridges. That is, they are instantiated by arch-code and then initialized by a subsys initcall. This does mean that we will be enumerating much later (during driver initcalls), but it might be a better model if we ever see a rumored PCIE->RIO bridge. Supporting that as a RIO master port would require driver time init of the RIO fabric. There's some ordering issues that we'd have to see about working out. None of this is needed right now, though.

Quoted 2 lines

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

Quoted 8 lines

I think this and #2 are separate issues. We can pass the mpc85xx rio init code some parameters to abstract things to different parts. This is similar to how we init different SoC's PCI host bridges with some common code on PPC32 (marvell, 85xx, etc).

I was just looking at doing this to support RIO on the 8548. At the time I wrote this 85xx support there wasn't any info on the 8548 available, but it's an easy thing to extend.

Agreed, they are separate issues, I'm cool on waiting to see what happens with RIO <-> PCIE bridges in the future. For now if you can look at abstracting the offset, irq info that would be good (especially since 8548 does msg'g a bit differently).

- kumar

#8 lore raw

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

Quoted 11 lines · Kumar Gala
Quoted 8 lines · Matt Porter
Quoted 2 lines · Kumar Gala

Two questions:
1. how well does will all of this handle > 32-bit phys addr?

It does and it doesn't handle > 32-bit phys addr. It depends on which configuration you are talking about. If you are talking about I/O

Quoted 2 lines

32-bit, it's no problem. If you are talking about handling DMA 32-bit,

Quoted 8 lines
Quoted 6 lines

then we need to handle a 64-bit DMA addr in the ppc32 implementations and
also extend the arch messaging interface to let callers know when an implementation can handle high DMA (system memory >4GB). This is all pretty easy to handle once we need to support such a processor. So far, nothing is available publicly. :)

Well 8548 is semi-public :)

Heh, well my definition is when Fscale has the reference manual downloadable from the main website...as of last night that wasn't the case for 8548. :)

<snip>

Quoted 8 lines
Quoted 8 lines
Quoted 2 lines

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

I think this and #2 are separate issues. We can pass the mpc85xx rio init code some parameters to abstract things to different parts. This is similar to how we init different SoC's PCI host bridges with some common code on PPC32 (marvell, 85xx, etc).

Quoted 8 lines
Quoted 3 lines

I was just looking at doing this to support RIO on the 8548. At the time I wrote this 85xx support there wasn't any info on the 8548 available, but it's an easy thing to extend.

Agreed, they are separate issues, I'm cool on waiting to see what happens with RIO <-> PCIE bridges in the future. For now if you can look at abstracting the offset, irq info that would be good (especially since 8548 does msg'g a bit differently).

No problem. The first "ppc85xx_rio.c" was only intended to work on the 8540/8560 stuff where I had hardware. From my look at 8548, it shouldn't take much work.

-Matt

#9 lore raw

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

In reply to Matt Porter
Quoted 1 line · Matt Porter

+spinlock_t rio_global_list_lock = SPIN_LOCK_UNLOCKED;

spin_lock_init?

drivers/rio/rio-scan.c line 59

Quoted 2 lines
drivers/rio/rio-scan.c new file +2 -0
+extern struct rio_route_ops __start_rio_route_ops[];
+extern struct rio_route_ops __end_rio_route_ops[];

rio.h?

drivers/rio/rio-scan.c line 89

Quoted 2 lines
drivers/rio/rio-scan.c new file +2 -0
+static void
+rio_set_device_id(struct rio_mport *port, u16 destid, u8 hopcount, u16 did)

Shouldn't those be on the same line?

Quoted 8 lines
drivers/rio/rio-scan.c new file +8 -0
+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) ||

drivers/rio/rio-scan.c line 209

Quoted 10 lines
drivers/rio/rio-scan.c new file +10 -0
+	     (src_ops & RIO_SRC_OPS_ATOMIC_SET) ||
+	     (src_ops & RIO_SRC_OPS_ATOMIC_CLR)) &&
+	    ((dst_ops & RIO_DST_OPS_READ) ||
+	     (dst_ops & RIO_DST_OPS_WRITE) ||
+	     (dst_ops & RIO_DST_OPS_ATOMIC_TST_SWP) ||
+	     (dst_ops & RIO_DST_OPS_ATOMIC_INC) ||
+	     (dst_ops & RIO_DST_OPS_ATOMIC_DEC) ||
+	     (dst_ops & RIO_DST_OPS_ATOMIC_SET) ||
+	     (dst_ops & RIO_DST_OPS_ATOMIC_CLR))) {
+		return 1;

Why not just;

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

drivers/rio/rio-scan.c line 387

Quoted 2 lines
drivers/rio/rio-scan.c new file +2 -0
+	rdev->dev.dma_mask = (u64 *) 0xffffffff;
+	rdev->dev.coherent_dma_mask = 0xffffffffULL;

Shouldn't that be dma_set_mask?

Zwane

#10 lore raw

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

Quoted 5 lines · Zwane Mwaikambo
Quoted 1 line · Matt Porter

+spinlock_t rio_global_list_lock = SPIN_LOCK_UNLOCKED;

spin_lock_init?

How about DEFINE_SPINLOCK() as they do the same thing (except the difference in amount of babble)? This is what PCI is doing, for example. I use the same init method in the static locks found in rio-access.c, FWIW.

Quoted 4 lines

drivers/rio/rio-scan.c line 59

Quoted 2 lines
drivers/rio/rio-scan.c new file +2 -0
+extern struct rio_route_ops __start_rio_route_ops[];
+extern struct rio_route_ops __end_rio_route_ops[];

rio.h?

Yep, will move.

Quoted 4 lines

drivers/rio/rio-scan.c line 89

Quoted 2 lines
drivers/rio/rio-scan.c new file +2 -0
+static void
+rio_set_device_id(struct rio_mport *port, u16 destid, u8 hopcount, u16 did)

Shouldn't those be on the same line?

Yes, will fix.

Quoted 21 lines
Quoted 8 lines
drivers/rio/rio-scan.c new file +8 -0
+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) ||

drivers/rio/rio-scan.c line 209

Quoted 10 lines
drivers/rio/rio-scan.c new file +10 -0
+	     (src_ops & RIO_SRC_OPS_ATOMIC_SET) ||
+	     (src_ops & RIO_SRC_OPS_ATOMIC_CLR)) &&
+	    ((dst_ops & RIO_DST_OPS_READ) ||
+	     (dst_ops & RIO_DST_OPS_WRITE) ||
+	     (dst_ops & RIO_DST_OPS_ATOMIC_TST_SWP) ||
+	     (dst_ops & RIO_DST_OPS_ATOMIC_INC) ||
+	     (dst_ops & RIO_DST_OPS_ATOMIC_DEC) ||
+	     (dst_ops & RIO_DST_OPS_ATOMIC_SET) ||
+	     (dst_ops & RIO_DST_OPS_ATOMIC_CLR))) {
+		return 1;

Why not just;

Quoted 2 lines

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

Yes, that's good. I already had that comment from an IRC discussion and neglected to address it in the last updates. Will do.

Quoted 4 lines

drivers/rio/rio-scan.c line 387

Quoted 2 lines
drivers/rio/rio-scan.c new file +2 -0
+	rdev->dev.dma_mask = (u64 *) 0xffffffff;
+	rdev->dev.coherent_dma_mask = 0xffffffffULL;

Shouldn't that be dma_set_mask?

There is a problem there, yes, but it shouldn't use dma_set_mask(). dma_set_mask() needs [struct device]->dma_mask to be non-zero (initialized to something) to do anything in all the copied implementations I've seen. I need to do something like the following to initialize the struct device dma_mask properly:

	rdev->dma_mask = 0xffffffffULL;
	rdev->dev.dma_mask = &rdev->dma_mask;

-Matt