Commit 394b701c authored by Matt Porter's avatar Matt Porter Committed by Linus Torvalds

[PATCH] RapidIO support: core base

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

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

There's a lot more to do to take advantages of all the hardware features.
However, this should provide a good base for folks with RIO hardware to start
contributing.
Signed-off-by: default avatarMatt Porter <mporter@kernel.crashing.org>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent d217d545
......@@ -10,7 +10,7 @@ DOCBOOKS := wanbook.xml z8530book.xml mcabook.xml videobook.xml \
kernel-hacking.xml kernel-locking.xml deviceiobook.xml \
procfs-guide.xml writing_usb_driver.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):
......
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
<!ENTITY rapidio SYSTEM "rapidio.xml">
]>
<book id="RapidIO-Guide">
<bookinfo>
<title>RapidIO Subsystem Guide</title>
<authorgroup>
<author>
<firstname>Matt</firstname>
<surname>Porter</surname>
<affiliation>
<address>
<email>mporter@kernel.crashing.org</email>
<email>mporter@mvista.com</email>
</address>
</affiliation>
</author>
</authorgroup>
<copyright>
<year>2005</year>
<holder>MontaVista Software, Inc.</holder>
</copyright>
<legalnotice>
<para>
This documentation is free software; you can redistribute
it and/or modify it under the terms of the GNU General Public
License version 2 as published by the Free Software Foundation.
</para>
<para>
This program is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
</para>
<para>
You should have received a copy of the GNU General Public
License along with this program; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
MA 02111-1307 USA
</para>
<para>
For more details see the file COPYING in the source
distribution of Linux.
</para>
</legalnotice>
</bookinfo>
<toc></toc>
<chapter id="intro">
<title>Introduction</title>
<para>
RapidIO is a high speed switched fabric interconnect with
features aimed at the embedded market. RapidIO provides
support for memory-mapped I/O as well as message-based
transactions over the switched fabric network. RapidIO has
a standardized discovery mechanism not unlike the PCI bus
standard that allows simple detection of devices in a
network.
</para>
<para>
This documentation is provided for developers intending
to support RapidIO on new architectures, write new drivers,
or to understand the subsystem internals.
</para>
</chapter>
<chapter id="bugs">
<title>Known Bugs and Limitations</title>
<sect1>
<title>Bugs</title>
<para>None. ;)</para>
</sect1>
<sect1>
<title>Limitations</title>
<para>
<orderedlist>
<listitem><para>Access/management of RapidIO memory regions is not supported</para></listitem>
<listitem><para>Multiple host enumeration is not supported</para></listitem>
</orderedlist>
</para>
</sect1>
</chapter>
<chapter id="drivers">
<title>RapidIO driver interface</title>
<para>
Drivers are provided a set of calls in order
to interface with the subsystem to gather info
on devices, request/map memory region resources,
and manage mailboxes/doorbells.
</para>
<sect1>
<title>Functions</title>
!Iinclude/linux/rio_drv.h
!Edrivers/rapidio/rio-driver.c
!Edrivers/rapidio/rio.c
</sect1>
</chapter>
<chapter id="internals">
<title>Internals</title>
<para>
This chapter contains the autogenerated documentation of the RapidIO
subsystem.
</para>
<sect1><title>Structures</title>
!Iinclude/linux/rio.h
</sect1>
<sect1><title>Enumeration and Discovery</title>
!Idrivers/rapidio/rio-scan.c
</sect1>
<sect1><title>Driver functionality</title>
!Idrivers/rapidio/rio.c
!Idrivers/rapidio/rio-access.c
</sect1>
<sect1><title>Device model support</title>
!Idrivers/rapidio/rio-driver.c
</sect1>
<sect1><title>Sysfs support</title>
!Idrivers/rapidio/rio-sysfs.c
</sect1>
<sect1><title>PPC32 support</title>
!Iarch/ppc/kernel/rio.c
!Earch/ppc/syslib/ppc85xx_rio.c
!Iarch/ppc/syslib/ppc85xx_rio.c
</sect1>
</chapter>
<chapter id="credits">
<title>Credits</title>
<para>
The following people have contributed to the RapidIO
subsystem directly or indirectly:
<orderedlist>
<listitem><para>Matt Porter<email>mporter@kernel.crashing.org</email></para></listitem>
<listitem><para>Randy Vinson<email>rvinson@mvista.com</email></para></listitem>
<listitem><para>Dan Malek<email>dan@embeddedalley.com</email></para></listitem>
</orderedlist>
</para>
<para>
The following people have contributed to this document:
<orderedlist>
<listitem><para>Matt Porter<email>mporter@kernel.crashing.org</email></para></listitem>
</orderedlist>
</para>
</chapter>
</book>
......@@ -2071,6 +2071,12 @@ P: Matt Mackall
M: mpm@selenic.com
S: Maintained
RAPIDIO SUBSYSTEM
P: Matt Porter
M: mporter@kernel.crashing.org
L: linux-kernel@vger.kernel.org
S: Maintained
REAL TIME CLOCK DRIVER
P: Paul Gortmaker
M: p_gortmaker@yahoo.com
......
......@@ -7,6 +7,7 @@
obj-$(CONFIG_PCI) += pci/ usb/
obj-$(CONFIG_PARISC) += parisc/
obj-$(CONFIG_RAPIDIO) += rapidio/
obj-y += video/
obj-$(CONFIG_ACPI) += acpi/
# PnP must come after ACPI since it will eventually need to check if acpi
......
#
# 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.
#
# 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/
/*
* RapidIO configuration space access support
*
* Copyright 2005 MontaVista Software, Inc.
* Matt Porter <mporter@kernel.crashing.org>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <linux/rio.h>
#include <linux/module.h>
/*
* These interrupt-safe spinlocks protect all accesses to RIO
* configuration space and doorbell access.
*/
static spinlock_t rio_config_lock = SPIN_LOCK_UNLOCKED;
static spinlock_t rio_doorbell_lock = SPIN_LOCK_UNLOCKED;
/*
* Wrappers for all RIO configuration access functions. They just check
* alignment, do locking and call the low-level functions pointed to
* by rio_mport->ops.
*/
#define RIO_8_BAD 0
#define RIO_16_BAD (offset & 1)
#define RIO_32_BAD (offset & 3)
/**
* RIO_LOP_READ - Generate rio_local_read_config_* functions
* @size: Size of configuration space read (8, 16, 32 bits)
* @type: C type of value argument
* @len: Length of configuration space read (1, 2, 4 bytes)
*
* Generates rio_local_read_config_* functions used to access
* configuration space registers on the local device.
*/
#define RIO_LOP_READ(size,type,len) \
int __rio_local_read_config_##size \
(struct rio_mport *mport, u32 offset, type *value) \
{ \
int res; \
unsigned long flags; \
u32 data = 0; \
if (RIO_##size##_BAD) return RIO_BAD_SIZE; \
spin_lock_irqsave(&rio_config_lock, flags); \
res = mport->ops->lcread(mport->id, offset, len, &data); \
*value = (type)data; \
spin_unlock_irqrestore(&rio_config_lock, flags); \
return res; \
}
/**
* RIO_LOP_WRITE - Generate rio_local_write_config_* functions
* @size: Size of configuration space write (8, 16, 32 bits)
* @type: C type of value argument
* @len: Length of configuration space write (1, 2, 4 bytes)
*
* Generates rio_local_write_config_* functions used to access
* configuration space registers on the local device.
*/
#define RIO_LOP_WRITE(size,type,len) \
int __rio_local_write_config_##size \
(struct rio_mport *mport, u32 offset, type value) \
{ \
int res; \
unsigned long flags; \
if (RIO_##size##_BAD) return RIO_BAD_SIZE; \
spin_lock_irqsave(&rio_config_lock, flags); \
res = mport->ops->lcwrite(mport->id, offset, len, value); \
spin_unlock_irqrestore(&rio_config_lock, flags); \
return res; \
}
RIO_LOP_READ(8, u8, 1)
RIO_LOP_READ(16, u16, 2)
RIO_LOP_READ(32, u32, 4)
RIO_LOP_WRITE(8, u8, 1)
RIO_LOP_WRITE(16, u16, 2)
RIO_LOP_WRITE(32, u32, 4)
EXPORT_SYMBOL_GPL(__rio_local_read_config_8);
EXPORT_SYMBOL_GPL(__rio_local_read_config_16);
EXPORT_SYMBOL_GPL(__rio_local_read_config_32);
EXPORT_SYMBOL_GPL(__rio_local_write_config_8);
EXPORT_SYMBOL_GPL(__rio_local_write_config_16);
EXPORT_SYMBOL_GPL(__rio_local_write_config_32);
/**
* RIO_OP_READ - Generate rio_mport_read_config_* functions
* @size: Size of configuration space read (8, 16, 32 bits)
* @type: C type of value argument
* @len: Length of configuration space read (1, 2, 4 bytes)
*
* Generates rio_mport_read_config_* functions used to access
* configuration space registers on the local device.
*/
#define RIO_OP_READ(size,type,len) \
int rio_mport_read_config_##size \
(struct rio_mport *mport, u16 destid, u8 hopcount, u32 offset, type *value) \
{ \
int res; \
unsigned long flags; \
u32 data = 0; \
if (RIO_##size##_BAD) return RIO_BAD_SIZE; \
spin_lock_irqsave(&rio_config_lock, flags); \
res = mport->ops->cread(mport->id, destid, hopcount, offset, len, &data); \
*value = (type)data; \
spin_unlock_irqrestore(&rio_config_lock, flags); \
return res; \
}
/**
* RIO_OP_WRITE - Generate rio_mport_write_config_* functions
* @size: Size of configuration space write (8, 16, 32 bits)
* @type: C type of value argument
* @len: Length of configuration space write (1, 2, 4 bytes)
*
* Generates rio_mport_write_config_* functions used to access
* configuration space registers on the local device.
*/
#define RIO_OP_WRITE(size,type,len) \
int rio_mport_write_config_##size \
(struct rio_mport *mport, u16 destid, u8 hopcount, u32 offset, type value) \
{ \
int res; \
unsigned long flags; \
if (RIO_##size##_BAD) return RIO_BAD_SIZE; \
spin_lock_irqsave(&rio_config_lock, flags); \
res = mport->ops->cwrite(mport->id, destid, hopcount, offset, len, value); \
spin_unlock_irqrestore(&rio_config_lock, flags); \
return res; \
}
RIO_OP_READ(8, u8, 1)
RIO_OP_READ(16, u16, 2)
RIO_OP_READ(32, u32, 4)
RIO_OP_WRITE(8, u8, 1)
RIO_OP_WRITE(16, u16, 2)
RIO_OP_WRITE(32, u32, 4)
EXPORT_SYMBOL_GPL(rio_mport_read_config_8);
EXPORT_SYMBOL_GPL(rio_mport_read_config_16);
EXPORT_SYMBOL_GPL(rio_mport_read_config_32);
EXPORT_SYMBOL_GPL(rio_mport_write_config_8);
EXPORT_SYMBOL_GPL(rio_mport_write_config_16);
EXPORT_SYMBOL_GPL(rio_mport_write_config_32);
/**
* rio_mport_send_doorbell - Send a doorbell message
*
* @mport: RIO master port
* @destid: RIO device destination ID
* @data: Doorbell message data
*
* Send a doorbell message to a RIO device. The doorbell message
* has a 16-bit info field provided by the data argument.
*/
int rio_mport_send_doorbell(struct rio_mport *mport, u16 destid, u16 data)
{
int res;
unsigned long flags;
spin_lock_irqsave(&rio_doorbell_lock, flags);
res = mport->ops->dsend(mport->id, destid, data);
spin_unlock_irqrestore(&rio_doorbell_lock, flags);
return res;
}
EXPORT_SYMBOL_GPL(rio_mport_send_doorbell);
/*
* RapidIO driver support
*
* Copyright 2005 MontaVista Software, Inc.
* Matt Porter <mporter@kernel.crashing.org>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/rio.h>
#include <linux/rio_ids.h>
#include "rio.h"
/**
* rio_match_device - Tell if a RIO device has a matching RIO device id structure
* @id: the RIO device id structure to match against
* @rdev: the RIO device structure to match against
*
* Used from driver probe and bus matching to check whether a RIO device
* matches a device id structure provided by a RIO driver. Returns the
* matching &struct rio_device_id or %NULL if there is no match.
*/
static const struct rio_device_id *rio_match_device(const struct rio_device_id
*id,
const struct rio_dev *rdev)
{
while (id->vid || id->asm_vid) {
if (((id->vid == RIO_ANY_ID) || (id->vid == rdev->vid)) &&
((id->did == RIO_ANY_ID) || (id->did == rdev->did)) &&
((id->asm_vid == RIO_ANY_ID)
|| (id->asm_vid == rdev->asm_vid))
&& ((id->asm_did == RIO_ANY_ID)
|| (id->asm_did == rdev->asm_did)))
return id;
id++;
}
return NULL;
}
/**
* rio_dev_get - Increments the reference count of the RIO device structure
*
* @rdev: RIO device being referenced
*
* Each live reference to a device should be refcounted.
*
* Drivers for RIO devices should normally record such references in
* their probe() methods, when they bind to a device, and release
* them by calling rio_dev_put(), in their disconnect() methods.
*/
struct rio_dev *rio_dev_get(struct rio_dev *rdev)
{
if (rdev)
get_device(&rdev->dev);
return rdev;
}
/**
* rio_dev_put - Release a use of the RIO device structure
*
* @rdev: RIO device being disconnected
*
* Must be called when a user of a device is finished with it.
* When the last user of the device calls this function, the
* memory of the device is freed.
*/
void rio_dev_put(struct rio_dev *rdev)
{
if (rdev)
put_device(&rdev->dev);
}
/**
* rio_device_probe - Tell if a RIO device structure has a matching RIO
* device id structure
* @id: the RIO device id structure to match against
* @dev: the RIO device structure to match against
*
* return 0 and set rio_dev->driver when drv claims rio_dev, else error
*/
static int rio_device_probe(struct device *dev)
{
struct rio_driver *rdrv = to_rio_driver(dev->driver);
struct rio_dev *rdev = to_rio_dev(dev);
int error = -ENODEV;
const struct rio_device_id *id;
if (!rdev->driver && rdrv->probe) {
if (!rdrv->id_table)
return error;
id = rio_match_device(rdrv->id_table, rdev);
rio_dev_get(rdev);
if (id)
error = rdrv->probe(rdev, id);
if (error >= 0) {
rdev->driver = rdrv;
error = 0;
rio_dev_put(rdev);
}
}
return error;
}
/**
* rio_device_remove - Remove a RIO device from the system
*
* @dev: the RIO device structure to match against
*
* Remove a RIO device from the system. If it has an associated
* driver, then run the driver remove() method. Then update
* the reference count.
*/
static int rio_device_remove(struct device *dev)
{
struct rio_dev *rdev = to_rio_dev(dev);
struct rio_driver *rdrv = rdev->driver;
if (rdrv) {
if (rdrv->remove)
rdrv->remove(rdev);
rdev->driver = NULL;
}
rio_dev_put(rdev);
return 0;
}
/**
* rio_register_driver - register a new RIO driver
* @rdrv: the RIO driver structure to register
*
* Adds a &struct rio_driver to the list of registered drivers
* Returns a negative value on error, otherwise 0. If no error
* occurred, the driver remains registered even if no device
* was claimed during registration.
*/
int rio_register_driver(struct rio_driver *rdrv)
{
/* initialize common driver fields */
rdrv->driver.name = rdrv->name;
rdrv->driver.bus = &rio_bus_type;
rdrv->driver.probe = rio_device_probe;
rdrv->driver.remove = rio_device_remove;
/* register with core */
return driver_register(&rdrv->driver);
}
/**
* rio_unregister_driver - unregister a RIO driver
* @rdrv: the RIO driver structure to unregister
*
* Deletes the &struct rio_driver from the list of registered RIO
* drivers, gives it a chance to clean up by calling its remove()
* function for each device it was responsible for, and marks those
* devices as driverless.
*/
void rio_unregister_driver(struct rio_driver *rdrv)
{
driver_unregister(&rdrv->driver);
}
/**
* rio_match_bus - Tell if a RIO device structure has a matching RIO
* driver device id structure
* @dev: the standard device structure to match against
* @drv: the standard driver structure containing the ids to match against
*
* Used by a driver to check whether a RIO device present in the
* system is in its list of supported devices. Returns 1 if
* there is a matching &struct rio_device_id or 0 if there is
* no match.
*/
static int rio_match_bus(struct device *dev, struct device_driver *drv)
{
struct rio_dev *rdev = to_rio_dev(dev);
struct rio_driver *rdrv = to_rio_driver(drv);
const struct rio_device_id *id = rdrv->id_table;
const struct rio_device_id *found_id;
if (!id)
goto out;
found_id = rio_match_device(id, rdev);
if (found_id)
return 1;
out:return 0;
}
static struct device rio_bus = {
.bus_id = "rapidio",
};
struct bus_type rio_bus_type = {
.name = "rapidio",
.match = rio_match_bus,
.dev_attrs = rio_dev_attrs
};
/**
* rio_bus_init - Register the RapidIO bus with the device model
*
* Registers the RIO bus device and RIO bus type with the Linux
* device model.
*/
static int __init rio_bus_init(void)
{
if (device_register(&rio_bus) < 0)
printk("RIO: failed to register RIO bus device\n");
return bus_register(&rio_bus_type);
}
postcore_initcall(rio_bus_init);
EXPORT_SYMBOL_GPL(rio_register_driver);
EXPORT_SYMBOL_GPL(rio_unregister_driver);
EXPORT_SYMBOL_GPL(rio_bus_type);
EXPORT_SYMBOL_GPL(rio_dev_get);
EXPORT_SYMBOL_GPL(rio_dev_put);
/*
* RapidIO sysfs attributes and support
*
* Copyright 2005 MontaVista Software, Inc.
* Matt Porter <mporter@kernel.crashing.org>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/rio.h>
#include <linux/rio_drv.h>
#include <linux/stat.h>
#include "rio.h"
/* Sysfs support */
#define rio_config_attr(field, format_string) \
static ssize_t \
field##_show(struct device *dev, char *buf) \
{ \
struct rio_dev *rdev = to_rio_dev(dev); \
\
return sprintf(buf, format_string, rdev->field); \
} \
rio_config_attr(did, "0x%04x\n");
rio_config_attr(vid, "0x%04x\n");
rio_config_attr(device_rev, "0x%08x\n");
rio_config_attr(