[linux-yocto] [PATCH 03/30] drivers/rapidio: modified files
Bruce Ashfield
bruce.ashfield at windriver.com
Tue Apr 22 14:00:22 PDT 2014
On 14-04-17 10:36 PM, Charlie Paul wrote:
> From: Paul Butler <paul.butler at windriver.com>
I hate to sound like a broken record, but if you look back through my
other comments, this is the type of commit message that doesn't tell
us anything.
"modified files"
Since it's a patch, we'd assume there are modified files. What we want
to know is what the change does. Looks like it implements some rapid IO
DMA direct access.
Why isn't that in the commit log ?
Bruce
>
> Signed-off-by: Paul Butler <paul.butler at windriver.com>
> ---
> drivers/rapidio/Kconfig | 85 +++
> drivers/rapidio/Makefile | 4 +-
> drivers/rapidio/rio-access.c | 89 +--
> drivers/rapidio/rio-driver.c | 70 ++-
> drivers/rapidio/rio-sysfs.c | 218 ++++++-
> drivers/rapidio/rio.c | 1404 ++++++++++++++++++++++++++++++------------
> drivers/rapidio/rio.h | 59 +-
> 7 files changed, 1473 insertions(+), 456 deletions(-)
>
> diff --git a/drivers/rapidio/Kconfig b/drivers/rapidio/Kconfig
> index bc87192..20b86a5 100644
> --- a/drivers/rapidio/Kconfig
> +++ b/drivers/rapidio/Kconfig
> @@ -22,6 +22,91 @@ config RAPIDIO_ENABLE_RX_TX_PORTS
> ports for Input/Output direction to allow other traffic
> than Maintenance transfers.
>
> +config RAPIDIO_DIO_DMA
> + bool "Use DMA for direct I/O access"
> + depends on RAPIDIO
> + default n
> + select DMA_ENGINE
> + ---help---
> + Say Y here if you want the RapidIO driver to use DMA for direct I/O
> + data transfers.
> +
> +config RAPIDIO_ACCESS_ERR_LIMIT
> + int "Number of device access errors accepted during net configuration, before giving up."
> + depends on RAPIDIO
> + default 0
> + ---help---
> + RIO net setup will be aborted if the core driver discovers that
> + contact is lost to devices, which has previously been probed, during
> + final LUT setup phase.
> + Failed SRIO access attempts may result in machine check errors:
> + Depending on SRIO port controller, the SRIO driver may have the
> + ability to recover from such faults. If your port controller supports
> + MC recovery for SRIO access errors you may chose to tolerate a certain
> + number of faults.
> + MC fault recovery, however, take some time and the user is advised
> + not to set this value to high.
> +
> +config RAPIDIO_DYNAMIC_ROUTES
> + bool "Use dynamic routing (Experimental)"
> + depends on RAPIDIO
> + default n
> + ---help---
> + Say Y here if you want the RapidIO driver to use dynamic routing and
> + calculate and adopt to the cheapest path between nodes.
> +
> +config RAPIDIO_MULTICAST_PW
> + bool "Port Write Multicast (Experimental)"
> + depends on RAPIDIO
> + default n
> + ---help---
> + Say Y here if you want the RapidIO driver to enable multicast of
> + prot write messages.
> +
> +config RAPIDIO_HOTPLUG
> + bool "Support for RAPIDIO Hotplug"
> + depends on RAPIDIO && HOTPLUG && SYSFS
> + default n
> + ---help---
> + This allows you to add and remove RIO devices while the machine is
> + powered up and running.
> +
> + When in doubt, say N.
> +
> +config RAPIDIO_STATIC_DESTID
> + bool "Use static RIO device destID"
> + depends on RAPIDIO
> + default n
> + ---help---
> + The default enumeration mode in the rapidio driver is to assign destIDs
> + to RIO devices dynamically. If you say Y here, the rapidio driver allows
> + static or user defined numbering.
> +
> +config RAPIDIO_ENUM_DOMAIN
> + bool "Support multiple enumeration hosts in the RIO network (Experimental)"
> + depends on RAPIDIO && RAPIDIO_HOTPLUG && RAPIDIO_STATIC_DESTID
> + default n
> + ---help---
> + Support multiple enumeration hosts in the RIO network
> +
> +config RAPIDIO_SECOND_DEST_ID
> + hex "Add a second destination id to main RIO port"
> + depends on RAPIDIO_HOTPLUG
> + default "0xdc"
> + ---help---
> + Add a second destination id that will be recognized by the main RIO
> + port. Can for example be used to receive multicasts or equivalent
> + that has multiple recipients.
> +
> +config RAPIDIO_PW_MULTICAST_MASK_ID
> + int "Multicast mask id to use for multicast port writes in switches"
> + depends on RAPIDIO_HOTPLUG
> + default "1"
> + ---help---
> + When using domains we need to multicast all port writes to all
> + domains. For this we need to set up a multicast mask dedicated for
> + this on all switches. This is the number for that mask.
> +
> config RAPIDIO_DEBUG
> bool "RapidIO subsystem debug messages"
> depends on RAPIDIO
> diff --git a/drivers/rapidio/Makefile b/drivers/rapidio/Makefile
> index ec3fb81..66db244 100644
> --- a/drivers/rapidio/Makefile
> +++ b/drivers/rapidio/Makefile
> @@ -1,7 +1,9 @@
> #
> # Makefile for RapidIO interconnect services
> #
> -obj-y += rio.o rio-access.o rio-driver.o rio-scan.o rio-sysfs.o
> +#obj-y += rio.o rio-access.o rio-driver.o rio-scan.o rio-net.o rio-locks.o rio-sysfs.o rio-quirks.o rio-dio.o rio-destid.o rio-domain.o rio-hotplug.o rio-multicast.o rio-job.o
> +
> +obj-y += rio.o rio-access.o rio-driver.o rio-net2.o rio-locks.o rio-sysfs.o rio-quirks.o rio-dio.o rio-destid.o rio-hotplug.o rio-route.o
>
> obj-$(CONFIG_RAPIDIO) += switches/
> obj-$(CONFIG_RAPIDIO) += devices/
> diff --git a/drivers/rapidio/rio-access.c b/drivers/rapidio/rio-access.c
> index a3824ba..1e05d2a 100644
> --- a/drivers/rapidio/rio-access.c
> +++ b/drivers/rapidio/rio-access.c
> @@ -17,9 +17,11 @@
> * These interrupt-safe spinlocks protect all accesses to RIO
> * configuration space and doorbell access.
> */
> -static DEFINE_SPINLOCK(rio_config_lock);
> -static DEFINE_SPINLOCK(rio_doorbell_lock);
> +/* static DEFINE_SPINLOCK(rio_config_lock); */
> +/* static DEFINE_SPINLOCK(rio_doorbell_lock); */
>
> +static DEFINE_RAW_SPINLOCK(rio_config_lock);
> +static DEFINE_RAW_SPINLOCK(rio_doorbell_lock);
> /*
> * Wrappers for all RIO configuration access functions. They just check
> * alignment, do locking and call the low-level functions pointed to
> @@ -39,18 +41,19 @@ static DEFINE_SPINLOCK(rio_doorbell_lock);
> * 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 \
> +#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); \
> + if (RIO_##size##_BAD) \
> + return RIO_BAD_SIZE; \
> + raw_spin_lock_irqsave(&rio_config_lock, flags); \
> res = mport->ops->lcread(mport, mport->id, offset, len, &data); \
> *value = (type)data; \
> - spin_unlock_irqrestore(&rio_config_lock, flags); \
> + raw_spin_unlock_irqrestore(&rio_config_lock, flags); \
> return res; \
> }
>
> @@ -63,31 +66,31 @@ int __rio_local_read_config_##size \
> * 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 \
> +#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); \
> + if (RIO_##size##_BAD) \
> + return RIO_BAD_SIZE; \
> + raw_spin_lock_irqsave(&rio_config_lock, flags); \
> res = mport->ops->lcwrite(mport, mport->id, offset, len, value);\
> - spin_unlock_irqrestore(&rio_config_lock, flags); \
> + raw_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);
> +RIO_LOP_READ(16, u16, 2)
> EXPORT_SYMBOL_GPL(__rio_local_read_config_16);
> +RIO_LOP_READ(32, u32, 4)
> EXPORT_SYMBOL_GPL(__rio_local_read_config_32);
> +RIO_LOP_WRITE(8, u8, 1)
> EXPORT_SYMBOL_GPL(__rio_local_write_config_8);
> +RIO_LOP_WRITE(16, u16, 2)
> EXPORT_SYMBOL_GPL(__rio_local_write_config_16);
> +RIO_LOP_WRITE(32, u32, 4)
> EXPORT_SYMBOL_GPL(__rio_local_write_config_32);
>
> /**
> @@ -99,18 +102,21 @@ EXPORT_SYMBOL_GPL(__rio_local_write_config_32);
> * 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) \
> +#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, mport->id, destid, hopcount, offset, len, &data); \
> + if (RIO_##size##_BAD) \
> + return RIO_BAD_SIZE; \
> + raw_spin_lock_irqsave(&rio_config_lock, flags); \
> + res = mport->ops->cread(mport, mport->id, destid, \
> + hopcount, offset, len, &data); \
> *value = (type)data; \
> - spin_unlock_irqrestore(&rio_config_lock, flags); \
> + raw_spin_unlock_irqrestore(&rio_config_lock, flags); \
> return res; \
> }
>
> @@ -123,31 +129,33 @@ int rio_mport_read_config_##size \
> * 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) \
> +#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, mport->id, destid, hopcount, offset, len, value); \
> - spin_unlock_irqrestore(&rio_config_lock, flags); \
> + if (RIO_##size##_BAD) \
> + return RIO_BAD_SIZE; \
> + raw_spin_lock_irqsave(&rio_config_lock, flags); \
> + res = mport->ops->cwrite(mport, mport->id, destid, hopcount, \
> + offset, len, value); \
> + raw_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);
> +RIO_OP_READ(16, u16, 2)
> EXPORT_SYMBOL_GPL(rio_mport_read_config_16);
> +RIO_OP_READ(32, u32, 4)
> EXPORT_SYMBOL_GPL(rio_mport_read_config_32);
> +RIO_OP_WRITE(8, u8, 1)
> EXPORT_SYMBOL_GPL(rio_mport_write_config_8);
> +RIO_OP_WRITE(16, u16, 2)
> EXPORT_SYMBOL_GPL(rio_mport_write_config_16);
> +RIO_OP_WRITE(32, u32, 4)
> EXPORT_SYMBOL_GPL(rio_mport_write_config_32);
>
> /**
> @@ -165,11 +173,10 @@ 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);
> + raw_spin_lock_irqsave(&rio_doorbell_lock, flags);
> res = mport->ops->dsend(mport, mport->id, destid, data);
> - spin_unlock_irqrestore(&rio_doorbell_lock, flags);
> + raw_spin_unlock_irqrestore(&rio_doorbell_lock, flags);
>
> return res;
> }
> -
> EXPORT_SYMBOL_GPL(rio_mport_send_doorbell);
> diff --git a/drivers/rapidio/rio-driver.c b/drivers/rapidio/rio-driver.c
> index 0f4a53b..143b2ae 100644
> --- a/drivers/rapidio/rio-driver.c
> +++ b/drivers/rapidio/rio-driver.c
> @@ -14,6 +14,7 @@
> #include <linux/module.h>
> #include <linux/rio.h>
> #include <linux/rio_ids.h>
> +#include <linux/rio_drv.h>
>
> #include "rio.h"
>
> @@ -58,9 +59,9 @@ struct rio_dev *rio_dev_get(struct rio_dev *rdev)
> {
> if (rdev)
> get_device(&rdev->dev);
> -
> return rdev;
> }
> +EXPORT_SYMBOL_GPL(rio_dev_get);
>
> /**
> * rio_dev_put - Release a use of the RIO device structure
> @@ -76,9 +77,11 @@ void rio_dev_put(struct rio_dev *rdev)
> if (rdev)
> put_device(&rdev->dev);
> }
> +EXPORT_SYMBOL_GPL(rio_dev_put);
>
> /**
> - * rio_device_probe - Tell if a RIO device structure has a matching RIO device id structure
> + * rio_device_probe - Tell if a RIO device structure has a matching
> + * RIO device id structure
> * @dev: the RIO device structure to match against
> *
> * return 0 and set rio_dev->driver when drv claims rio_dev, else error
> @@ -98,10 +101,15 @@ static int rio_device_probe(struct device *dev)
> if (id)
> error = rdrv->probe(rdev, id);
> if (error >= 0) {
> + pr_debug("%s: for %s got driver %pF\n",
> + __func__, rio_name(rdev), rdrv->probe);
> rdev->driver = rdrv;
> error = 0;
> - } else
> + } else {
> + pr_debug("%s: for %s probe fail\n",
> + __func__, rio_name(rdev));
> rio_dev_put(rdev);
> + }
> }
> return error;
> }
> @@ -120,9 +128,16 @@ static int rio_device_remove(struct device *dev)
> struct rio_dev *rdev = to_rio_dev(dev);
> struct rio_driver *rdrv = rdev->driver;
>
> + pr_debug("device remove for %s\n", rio_name(rdev));
> if (rdrv) {
> - if (rdrv->remove)
> + if (rdrv->remove) {
> + pr_debug("driver remove for %s using %pF\n",
> + rio_name(rdev), rdrv->remove);
> rdrv->remove(rdev);
> + } else {
> + pr_debug("driver not registered for %s\n",
> + rio_name(rdev));
> + }
> rdev->driver = NULL;
> }
>
> @@ -142,13 +157,40 @@ static int rio_device_remove(struct device *dev)
> */
> int rio_register_driver(struct rio_driver *rdrv)
> {
> + int rc;
> +
> /* initialize common driver fields */
> rdrv->driver.name = rdrv->name;
> rdrv->driver.bus = &rio_bus_type;
> + rdrv->driver.owner = THIS_MODULE;
> + rdrv->driver.mod_name = KBUILD_MODNAME;
> +
> + spin_lock_init(&rdrv->dynids.lock);
> + INIT_LIST_HEAD(&rdrv->dynids.list);
>
> /* register with core */
> - return driver_register(&rdrv->driver);
> + rc = driver_register(&rdrv->driver);
> + if (rc)
> + goto out;
> +
> + rc = rio_create_newid_file(rdrv);
> + if (rc)
> + goto out_newid;
> +
> + rc = rio_create_removeid_file(rdrv);
> + if (rc)
> + goto out_removeid;
> +out:
> + return rc;
> +
> +out_removeid:
> + rio_remove_newid_file(rdrv);
> +out_newid:
> + driver_unregister(&rdrv->driver);
> + goto out;
> +
> }
> +EXPORT_SYMBOL_GPL(rio_register_driver);
>
> /**
> * rio_unregister_driver - unregister a RIO driver
> @@ -161,11 +203,15 @@ int rio_register_driver(struct rio_driver *rdrv)
> */
> void rio_unregister_driver(struct rio_driver *rdrv)
> {
> + rio_remove_removeid_file(rdrv);
> + rio_remove_newid_file(rdrv);
> driver_unregister(&rdrv->driver);
> }
> +EXPORT_SYMBOL_GPL(rio_unregister_driver);
>
> /**
> - * rio_match_bus - Tell if a RIO device structure has a matching RIO driver device id structure
> + * 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
> *
> @@ -189,7 +235,8 @@ static int rio_match_bus(struct device *dev, struct device_driver *drv)
> if (found_id)
> return 1;
>
> - out:return 0;
> +out:
> + return 0;
> }
>
> struct device rio_bus = {
> @@ -203,6 +250,7 @@ struct bus_type rio_bus_type = {
> .probe = rio_device_probe,
> .remove = rio_device_remove,
> };
> +EXPORT_SYMBOL_GPL(rio_bus_type);
>
> /**
> * rio_bus_init - Register the RapidIO bus with the device model
> @@ -213,14 +261,8 @@ struct bus_type rio_bus_type = {
> static int __init rio_bus_init(void)
> {
> if (device_register(&rio_bus) < 0)
> - printk("RIO: failed to register RIO bus device\n");
> + printk(KERN_ERR "RIO: failed to register RIO bus device\n");
> return bus_register(&rio_bus_type);
> }
>
> postcore_initcall(rio_bus_init);
> -
> -EXPORT_SYMBOL_GPL(rio_register_driver);
> -EXPORT_SYMBOL_GPL(rio_unregister_driver);
> -EXPORT_SYMBOL_GPL(rio_bus_type);
> -EXPORT_SYMBOL_GPL(rio_dev_get);
> -EXPORT_SYMBOL_GPL(rio_dev_put);
> diff --git a/drivers/rapidio/rio-sysfs.c b/drivers/rapidio/rio-sysfs.c
> index 4dbe360..288b014 100644
> --- a/drivers/rapidio/rio-sysfs.c
> +++ b/drivers/rapidio/rio-sysfs.c
> @@ -10,18 +10,23 @@
> * option) any later version.
> */
>
> +#include <linux/slab.h>
> +#include <linux/err.h>
> #include <linux/kernel.h>
> #include <linux/rio.h>
> #include <linux/rio_drv.h>
> #include <linux/stat.h>
> #include <linux/capability.h>
> +#ifdef NEW_STYLE
> +#include <linux/radix-tree.h>
> +#endif
>
> #include "rio.h"
>
> /* Sysfs support */
> -#define rio_config_attr(field, format_string) \
> +#define rio_config_attr(field, format_string) \
> static ssize_t \
> -field##_show(struct device *dev, struct device_attribute *attr, char *buf) \
> +field##_show(struct device *dev, struct device_attribute *attr, char *buf) \
> { \
> struct rio_dev *rdev = to_rio_dev(dev); \
> \
> @@ -37,24 +42,152 @@ rio_config_attr(asm_rev, "0x%04x\n");
> rio_config_attr(destid, "0x%04x\n");
> rio_config_attr(hopcount, "0x%02x\n");
>
> -static ssize_t routes_show(struct device *dev, struct device_attribute *attr, char *buf)
> +static ssize_t routes_show(struct device *dev,
> + struct device_attribute *attr, char *buf)
> {
> struct rio_dev *rdev = to_rio_dev(dev);
> char *str = buf;
> int i;
> + u8 port;
>
> - for (i = 0; i < RIO_MAX_ROUTE_ENTRIES(rdev->net->hport->sys_size);
> + if (rio_hw_lock_wait(rdev->hport, rdev->destid, rdev->hopcount, 1))
> + goto done;
> +
> + for (i = 0; i < RIO_MAX_ROUTE_ENTRIES(rdev->hport->sys_size);
> i++) {
> - if (rdev->rswitch->route_table[i] == RIO_INVALID_ROUTE)
> + if (rio_route_get_port(rdev, i, &port, 0))
> + continue;
> +
> + if (port == RIO_INVALID_ROUTE)
> continue;
> str +=
> - sprintf(str, "%04x %02x\n", i,
> - rdev->rswitch->route_table[i]);
> + sprintf(str, "%04x %02x\n", i, port);
> }
>
> - return (str - buf);
> + rio_hw_unlock(rdev->hport, rdev->destid, rdev->hopcount);
> +
> +done:
> + return str - buf;
> }
>
> +static ssize_t port_status_show(struct device *dev,
> + struct device_attribute *attr, char *buf)
> +{
> + struct rio_dev *rdev = to_rio_dev(dev);
> + char *str = buf;
> + int no_ports, port, rc, link_ok;
> + u32 value, status_reg, ctrl_reg;
> +
> + rc = rio_read_config_32(rdev, RIO_SWP_INFO_CAR, &value);
> + if (rc) {
> + pr_debug(
> + "RIO: (%s) Failed to read status reg addr=%08x result=%d\n",
> + __func__, RIO_SWP_INFO_CAR, rc);
> + goto done;
> + }
> + no_ports = (value & RIO_SWP_INFO_PORT_TOTAL_MASK) >> 8;
> +
> + str += sprintf(str, "\nPort\tLink\tPORT_N_ERR\tPORT_N_CTL\n");
> + str += sprintf(str, "------------------------------------------\n");
> +
> + for (port = 0; port < no_ports; port++) {
> + rc = rio_read_config_32(rdev,
> + rdev->phys_efptr +
> + RIO_PORT_N_ERR_STS_CSR(port),
> + &status_reg);
> + if (rc) {
> + pr_debug("RIO: (%s) Failed to read status reg addr=%08x result=%d\n",
> + __func__, rdev->phys_efptr +
> + RIO_PORT_N_ERR_STS_CSR(port), rc);
> + goto done;
> + }
> + rc = rio_read_config_32(rdev,
> + rdev->phys_efptr +
> + RIO_PORT_N_CTL_CSR(port),
> + &ctrl_reg);
> + if (rc) {
> + pr_debug("RIO: (%s) Failed to read control reg addr=%08x result=%d\n",
> + __func__, rdev->phys_efptr +
> + RIO_PORT_N_CTL_CSR(port), rc);
> + goto done;
> + }
> +
> + link_ok = ((status_reg & RIO_PORT_N_ERR_STS_PORT_OK) != 0);
> +
> + str += sprintf(str, "%3d\t%s\t0x%08x\t0x%08x\n",
> + port,
> + (link_ok) ? "OK" : "NOK",
> + status_reg,
> + ctrl_reg);
> + }
> + str += sprintf(str, "------------------------------------------\n\n");
> +
> +done:
> + return str - buf;
> +}
> +
> +static ssize_t lut_show(struct device *dev,
> + struct device_attribute *attr,
> + char *buf)
> +{
> + struct rio_dev *rdev = to_rio_dev(dev);
> + char *str = buf;
> + u16 destid;
> +
> + for (destid = 0;
> + destid < RIO_ANY_DESTID(rdev->hport->sys_size); destid++) {
> + u8 route_port;
> + rdev->rswitch->get_entry(rdev->hport, rdev->destid,
> + rdev->hopcount, RIO_GLOBAL_TABLE,
> + destid, &route_port);
> + if (route_port != RIO_INVALID_ROUTE)
> + str += sprintf(str, "%04x %02x\n", destid, route_port);
> + }
> + return str - buf;
> +}
> +
> +#ifdef NEW_STYLE
> +static ssize_t lprev_show(struct device *dev,
> + struct device_attribute *attr, char *buf)
> +{
> + struct rio_dev *rdev = to_rio_dev(dev);
> + struct rio_dev *prev;
> + ssize_t count;
> +
> + rcu_read_lock();
> + prev = radix_tree_lookup(&rdev->hport->net.dev_tree,
> + rdev->prev_destid);
> + count = sprintf(buf, "%s\n",
> + (prev) ? rio_name(prev) : "root");
> + rcu_read_unlock();
> + return count;
> +}
> +
> +static ssize_t lnext_show(struct device *dev,
> + struct device_attribute *attr, char *buf)
> +{
> + struct rio_dev *rdev = to_rio_dev(dev);
> + char *str = buf;
> + int i;
> +
> + if (rdev->pef & RIO_PEF_SWITCH) {
> + for (i = 0; i < RIO_GET_TOTAL_PORTS(rdev->swpinfo); i++) {
> + struct rio_dev *next = lookup_rdev_next(rdev, i);
> +
> + if (!IS_ERR(next)) {
> + str += sprintf(str, "%s\n",
> + rio_name(next));
> + rio_dev_put(next);
> + } else
> + str += sprintf(str, "null\n");
> + }
> + }
> +
> + return str - buf;
> +}
> +
> +#else
> +
> static ssize_t lprev_show(struct device *dev,
> struct device_attribute *attr, char *buf)
> {
> @@ -73,9 +206,9 @@ static ssize_t lnext_show(struct device *dev,
>
> if (rdev->pef & RIO_PEF_SWITCH) {
> for (i = 0; i < RIO_GET_TOTAL_PORTS(rdev->swpinfo); i++) {
> - if (rdev->rswitch->nextdev[i])
> + if (rdev->rswitch->port[i].rdev)
> str += sprintf(str, "%s\n",
> - rio_name(rdev->rswitch->nextdev[i]));
> + rio_name(rdev->rswitch->port[i].rdev));
> else
> str += sprintf(str, "null\n");
> }
> @@ -83,6 +216,7 @@ static ssize_t lnext_show(struct device *dev,
>
> return str - buf;
> }
> +#endif
>
> struct device_attribute rio_dev_attrs[] = {
> __ATTR_RO(did),
> @@ -99,6 +233,9 @@ struct device_attribute rio_dev_attrs[] = {
> static DEVICE_ATTR(routes, S_IRUGO, routes_show, NULL);
> static DEVICE_ATTR(lnext, S_IRUGO, lnext_show, NULL);
> static DEVICE_ATTR(hopcount, S_IRUGO, hopcount_show, NULL);
> +static DEVICE_ATTR(port_status, S_IRUGO, port_status_show, NULL);
> +static DEVICE_ATTR(lut, S_IRUGO, lut_show, NULL);
> +
>
> static ssize_t
> rio_read_config(struct file *filp, struct kobject *kobj,
> @@ -257,8 +394,12 @@ int rio_create_sysfs_dev_files(struct rio_dev *rdev)
> err |= device_create_file(&rdev->dev, &dev_attr_routes);
> err |= device_create_file(&rdev->dev, &dev_attr_lnext);
> err |= device_create_file(&rdev->dev, &dev_attr_hopcount);
> + err |= device_create_file(&rdev->dev, &dev_attr_port_status);
> + err |= device_create_file(&rdev->dev, &dev_attr_lut);
> +
> if (!err && rdev->rswitch->sw_sysfs)
> - err = rdev->rswitch->sw_sysfs(rdev, RIO_SW_SYSFS_CREATE);
> + err = rdev->rswitch->sw_sysfs(rdev,
> + RIO_SW_SYSFS_CREATE);
> }
>
> if (err)
> @@ -281,7 +422,62 @@ void rio_remove_sysfs_dev_files(struct rio_dev *rdev)
> device_remove_file(&rdev->dev, &dev_attr_routes);
> device_remove_file(&rdev->dev, &dev_attr_lnext);
> device_remove_file(&rdev->dev, &dev_attr_hopcount);
> +
> if (rdev->rswitch->sw_sysfs)
> rdev->rswitch->sw_sysfs(rdev, RIO_SW_SYSFS_REMOVE);
> }
> }
> +
> +#if defined(CONFIG_RAPIDIO_HOTPLUG) || defined(CONFIG_RAPIDIO_STATIC_DESTID)
> +static ssize_t rio_devices_show(struct device *dev,
> + struct device_attribute *attr, char *buf)
> +{
> + struct rio_mport *mport = container_of(dev, struct rio_mport, dev);
> + char *str = buf;
> + int i, num = 0;
> + struct rio_dev **dptr = NULL;
> +
> + if (!mport)
> + return -EINVAL;
> +
> + dptr = rio_get_all_devices(mport, &num);
> + if (!dptr)
> + return 0;
> +
> + if (IS_ERR(dptr))
> + return PTR_ERR(dptr);
> +
> + str += sprintf(str, "Device table:\n");
> + str += sprintf(str,
> + "name\t\tdid\tvid\tswpinfo\t\thops\thwlock\tlocal\n");
> + for (i = 0; i < num; i++) {
> + struct rio_dev *node = dptr[i];
> +
> + if (unlikely(!node))
> + continue;
> +
> + str += sprintf(str,
> + "%s\t%4.4x\t%4.4x\t%8.8x\t%d\t%d\t%d\n",
> + rio_name(node),
> + node->did,
> + node->vid,
> + node->swpinfo,
> + node->hopcount,
> + node->use_hw_lock,
> + node->local_domain);
> + rio_dev_put(node);
> + }
> + kfree(dptr);
> + return str - buf;
> +}
> +static DEVICE_ATTR(devices, S_IRUGO, rio_devices_show, NULL);
> +
> +int rio_sysfs_init(struct rio_mport *mport)
> +{
> + int rc = 0;
> +
> + rc |= device_create_file(&mport->dev, &dev_attr_devices);
> +
> + return rc;
> +}
> +#endif
> diff --git a/drivers/rapidio/rio.c b/drivers/rapidio/rio.c
> index 86c9a09..5312777 100644
> --- a/drivers/rapidio/rio.c
> +++ b/drivers/rapidio/rio.c
> @@ -28,12 +28,238 @@
> #include <linux/spinlock.h>
> #include <linux/slab.h>
> #include <linux/interrupt.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/hardirq.h>
> +#include <linux/semaphore.h>
>
> #include "rio.h"
> +#include "rio-job.h"
>
> -static LIST_HEAD(rio_mports);
> +LIST_HEAD(rio_mports);
> static unsigned char next_portid;
>
> +struct rio_dev **rio_get_tagged_devices(struct rio_mport *mport, int tag, int *n)
> +{
> + int items = atomic_read(&mport->net.rio_dev_num);
> + void **nptr = NULL;
> + struct rio_dev **dptr = NULL;
> + int i, num = 0;
> +
> + if (!items)
> + goto done;
> +
> + nptr = kzalloc(sizeof(void *) * items, GFP_KERNEL);
> + if (!nptr)
> + goto err;
> + dptr = kzalloc(sizeof(struct rio_dev *) * items, GFP_KERNEL);
> + if (!dptr)
> + goto err;
> +
> + rcu_read_lock();
> +retry:
> + num = radix_tree_gang_lookup_tag_slot(&mport->net.dev_tree, (void ***)nptr,
> + 0, items, tag);
> + if (num > 0) {
> + for (i = 0; i < num; i++) {
> + struct rio_dev *rdev = radix_tree_deref_slot((void **)nptr[i]);
> +
> + if (unlikely(!rdev)) {
> + dptr[i] = NULL;
> + continue;
> + }
> + if (radix_tree_deref_retry(rdev))
> + goto retry;
> + dptr[i] = rio_dev_get(rdev);
> + }
> + }
> + rcu_read_unlock();
> +done:
> + if (nptr != NULL)
> + kfree(nptr);
> + *n = num;
> + return dptr;
> +err:
> + if (dptr != NULL)
> + kfree(dptr);
> + dptr = ERR_PTR(-ENOMEM);
> + goto done;
> +}
> +
> +struct rio_dev **rio_get_all_devices(struct rio_mport *mport, int *n)
> +{
> + int items = atomic_read(&mport->net.rio_dev_num);
> + void **nptr = NULL;
> + struct rio_dev **dptr = NULL;
> + int i, num = 0;
> +
> + if (!items)
> + goto done;
> +
> + nptr = kzalloc(sizeof(void *) * items, GFP_KERNEL);
> + if (!nptr)
> + goto err;
> + dptr = kzalloc(sizeof(struct rio_dev *) * items, GFP_KERNEL);
> + if (!dptr)
> + goto err;
> +
> + rcu_read_lock();
> +retry:
> + num = radix_tree_gang_lookup_slot(&mport->net.dev_tree, (void ***)nptr,
> + NULL, 0, items);
> + if (num > 0) {
> + for (i = 0; i < num; i++) {
> + struct rio_dev *rdev = radix_tree_deref_slot((void **)nptr[i]);
> +
> + if (unlikely(!rdev)) {
> + dptr[i] = NULL;
> + continue;
> + }
> + if (radix_tree_deref_retry(rdev))
> + goto retry;
> +
> + dptr[i] = rio_dev_get(rdev);
> + }
> + }
> + rcu_read_unlock();
> +done:
> + if (nptr != NULL)
> + kfree(nptr);
> + *n = num;
> + return dptr;
> +err:
> + if (dptr != NULL)
> + kfree(dptr);
> + dptr = ERR_PTR(-ENOMEM);
> + goto done;
> +}
> +EXPORT_SYMBOL_GPL(rio_get_all_devices);
> +
> +int rio_get_err_and_status(struct rio_dev *rdev, int portnum, u32 *err_status)
> +{
> + int rc;
> + rc = rio_read_config_32(rdev,
> + rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(portnum), err_status);
> + if (rc)
> + pr_debug("RIO: Failed to read RIO_PORT_N_ERR_STS_CSR from device\n");
> + return rc;
> +}
> +
> +/**
> + * 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.
> + */
> +int rio_is_switch(struct rio_dev *rdev)
> +{
> + if (rdev->pef & RIO_PEF_SWITCH)
> + return 1;
> + return 0;
> +}
> +#ifdef NEW_STYLE
> +int rio_type_of_next(struct rio_dev *sw_curr, struct rio_dev *sw_next)
> +{
> + if (!sw_next)
> + return RIO_PORT_UNUSED;
> +
> + if (rio_is_switch(sw_next)) {
> + rcu_read_lock();
> + if (sw_next->prev_destid != sw_curr->destid
> + || sw_curr == sw_next) {
> + pr_debug("skip redundant path to %s\n", rio_name(sw_next));
> + rcu_read_unlock();
> + return RIO_REDUNDANT_PATH;
> + }
> + rcu_read_unlock();
> + return RIO_SWITCH;
> + }
> + return RIO_END_POINT;
> +}
> +#else
> +int rio_type_of_next(struct rio_dev *sw_curr, struct rio_dev *sw_next)
> +{
> + if (!sw_next)
> + return RIO_PORT_UNUSED;
> +
> + if (rio_is_switch(sw_next)) {
> + if (sw_next->prev != sw_curr || sw_curr == sw_next) {
> + pr_debug("skip redundant path to %s\n", rio_name(sw_next));
> + return RIO_REDUNDANT_PATH;
> + }
> + return RIO_SWITCH;
> + }
> + return RIO_END_POINT;
> +}
> +#endif
> +/**
> + * rio_map_outb_mem -- Mapping outbound memory.
> + * @mport: RapidIO master port
> + * @win: Outbound ATMU window for this access
> + * - obtained by calling fsl_rio_req_outb_region.
> + * @destid: Destination ID of transaction
> + * @offset: RapidIO space start address.
> + * @res: Mapping region phys and virt start address
> + *
> + * Return: 0 -- Success.
> + *
> + */
> +int rio_map_outb_mem(struct rio_mport *mport, u32 win,
> + u16 destid, u32 offset, u32 mflags,
> + struct rio_map_addr *res)
> +{
> + int rc = 0;
> +
> + if (!mport->mops)
> + return -1;
> + rc = mport->mops->map_outb(mport, win, destid, offset, mflags, res);
> + return rc;
> +}
> +EXPORT_SYMBOL_GPL(rio_map_outb_mem);
> +
> +/**
> + * rio_req_outb_region -- Request outbound region in the
> + * RapidIO bus address space.
> + * @mport: RapidIO master port
> + * @size: The mapping region size.
> + * @name: Resource name
> + * @flags: Flags for mapping. 0 for using default flags.
> + * @id: Allocated outbound ATMU window id
> + *
> + * Return: 0 -- Success.
> + *
> + * This function will reserve a memory region that may
> + * be used to create mappings from local iomem to rio space.
> + */
> +int rio_req_outb_region(struct rio_mport *mport,
> + resource_size_t size,
> + const char *name,
> + u32 mflags, u32 *win)
> +{
> + int rc = 0;
> +
> + if (!mport->mops)
> + return -1;
> + rc = mport->mops->req_outb(mport, size, name, mflags, win);
> + return rc;
> +}
> +EXPORT_SYMBOL_GPL(rio_req_outb_region);
> +
> +/**
> + * rio_release_outb_region -- Unreserve outbound memory region.
> + * @mport: RapidIO master port
> + * @win: Allocated outbound ATMU window id
> + */
> +void rio_release_outb_region(struct rio_mport *mport, u32 win)
> +{
> + if (!mport->mops)
> + return;
> + mport->mops->release_outb(mport, win);
> +}
> +EXPORT_SYMBOL_GPL(rio_release_outb_region);
> +
> /**
> * rio_local_get_device_id - Get the base/extended device id for a port
> * @port: RIO master port from which to get the deviceid
> @@ -46,10 +272,12 @@ u16 rio_local_get_device_id(struct rio_mport *port)
> {
> u32 result;
>
> - rio_local_read_config_32(port, RIO_DID_CSR, &result);
> + if (rio_local_read_config_32(port, RIO_DID_CSR, &result))
> + pr_debug("RIO: Failed to read RIO_DID_CSR\n");
>
> - return (RIO_GET_DID(port->sys_size, result));
> + return RIO_GET_DID(port->sys_size, result);
> }
> +EXPORT_SYMBOL_GPL(rio_local_get_device_id);
>
> /**
> * rio_request_inb_mbox - request inbound mailbox service
> @@ -66,7 +294,7 @@ int rio_request_inb_mbox(struct rio_mport *mport,
> void *dev_id,
> int mbox,
> int entries,
> - void (*minb) (struct rio_mport * mport, void *dev_id, int mbox,
> + void (*minb) (struct rio_mport *mport, void *dev_id, int mbox,
> int slot))
> {
> int rc = -ENOSYS;
> @@ -81,9 +309,8 @@ int rio_request_inb_mbox(struct rio_mport *mport,
> rio_init_mbox_res(res, mbox, mbox);
>
> /* Make sure this mailbox isn't in use */
> - if ((rc =
> - request_resource(&mport->riores[RIO_INB_MBOX_RESOURCE],
> - res)) < 0) {
> + rc = request_resource(&mport->riores[RIO_INB_MBOX_RESOURCE], res);
> + if (rc < 0) {
> kfree(res);
> goto out;
> }
> @@ -97,9 +324,10 @@ int rio_request_inb_mbox(struct rio_mport *mport,
> } else
> rc = -ENOMEM;
>
> - out:
> +out:
> return rc;
> }
> +EXPORT_SYMBOL_GPL(rio_request_inb_mbox);
>
> /**
> * rio_release_inb_mbox - release inbound mailbox message service
> @@ -119,6 +347,7 @@ int rio_release_inb_mbox(struct rio_mport *mport, int mbox)
> } else
> return -ENOSYS;
> }
> +EXPORT_SYMBOL_GPL(rio_release_inb_mbox);
>
> /**
> * rio_request_outb_mbox - request outbound mailbox service
> @@ -135,7 +364,9 @@ int rio_request_outb_mbox(struct rio_mport *mport,
> void *dev_id,
> int mbox,
> int entries,
> - void (*moutb) (struct rio_mport * mport, void *dev_id, int mbox, int slot))
> + int prio,
> + void (*moutb) (struct rio_mport *mport, void *dev_id,
> + int mbox, int slot, void *cookie))
> {
> int rc = -ENOSYS;
> struct resource *res;
> @@ -149,9 +380,8 @@ int rio_request_outb_mbox(struct rio_mport *mport,
> rio_init_mbox_res(res, mbox, mbox);
>
> /* Make sure this outbound mailbox isn't in use */
> - if ((rc =
> - request_resource(&mport->riores[RIO_OUTB_MBOX_RESOURCE],
> - res)) < 0) {
> + rc = request_resource(&mport->riores[RIO_OUTB_MBOX_RESOURCE], res);
> + if (rc < 0) {
> kfree(res);
> goto out;
> }
> @@ -161,13 +391,14 @@ int rio_request_outb_mbox(struct rio_mport *mport,
> /* Hook the inbound message callback */
> mport->outb_msg[mbox].mcback = moutb;
>
> - rc = mport->ops->open_outb_mbox(mport, dev_id, mbox, entries);
> + rc = mport->ops->open_outb_mbox(mport, dev_id, mbox, entries, prio);
> } else
> rc = -ENOMEM;
>
> - out:
> +out:
> return rc;
> }
> +EXPORT_SYMBOL_GPL(rio_request_outb_mbox);
>
> /**
> * rio_release_outb_mbox - release outbound mailbox message service
> @@ -187,6 +418,7 @@ int rio_release_outb_mbox(struct rio_mport *mport, int mbox)
> } else
> return -ENOSYS;
> }
> +EXPORT_SYMBOL_GPL(rio_release_outb_mbox);
>
> /**
> * rio_setup_inb_dbell - bind inbound doorbell callback
> @@ -201,13 +433,13 @@ int rio_release_outb_mbox(struct rio_mport *mport, int mbox)
> */
> static int
> rio_setup_inb_dbell(struct rio_mport *mport, void *dev_id, struct resource *res,
> - void (*dinb) (struct rio_mport * mport, void *dev_id, u16 src, u16 dst,
> + void (*dinb) (struct rio_mport *mport, void *dev_id, u16 src, u16 dst,
> u16 info))
> {
> int rc = 0;
> struct rio_dbell *dbell;
> -
> - if (!(dbell = kmalloc(sizeof(struct rio_dbell), GFP_KERNEL))) {
> + dbell = kmalloc(sizeof(struct rio_dbell), GFP_KERNEL);
> + if (!dbell) {
> rc = -ENOMEM;
> goto out;
> }
> @@ -218,7 +450,7 @@ rio_setup_inb_dbell(struct rio_mport *mport, void *dev_id, struct resource *res,
>
> list_add_tail(&dbell->node, &mport->dbells);
>
> - out:
> +out:
> return rc;
> }
>
> @@ -238,7 +470,7 @@ int rio_request_inb_dbell(struct rio_mport *mport,
> void *dev_id,
> u16 start,
> u16 end,
> - void (*dinb) (struct rio_mport * mport, void *dev_id, u16 src,
> + void (*dinb) (struct rio_mport *mport, void *dev_id, u16 src,
> u16 dst, u16 info))
> {
> int rc = 0;
> @@ -249,9 +481,10 @@ int rio_request_inb_dbell(struct rio_mport *mport,
> rio_init_dbell_res(res, start, end);
>
> /* Make sure these doorbells aren't in use */
> - if ((rc =
> - request_resource(&mport->riores[RIO_DOORBELL_RESOURCE],
> - res)) < 0) {
> + rc =
> + request_resource(&mport->riores[RIO_DOORBELL_RESOURCE],
> + res);
> + if (rc < 0) {
> kfree(res);
> goto out;
> }
> @@ -261,9 +494,10 @@ int rio_request_inb_dbell(struct rio_mport *mport,
> } else
> rc = -ENOMEM;
>
> - out:
> +out:
> return rc;
> }
> +EXPORT_SYMBOL_GPL(rio_request_inb_dbell);
>
> /**
> * rio_release_inb_dbell - release inbound doorbell message service
> @@ -302,9 +536,10 @@ int rio_release_inb_dbell(struct rio_mport *mport, u16 start, u16 end)
> /* Free the doorbell event */
> kfree(dbell);
>
> - out:
> +out:
> return rc;
> }
> +EXPORT_SYMBOL_GPL(rio_release_inb_dbell);
>
> /**
> * rio_request_outb_dbell - request outbound doorbell message range
> @@ -333,6 +568,7 @@ struct resource *rio_request_outb_dbell(struct rio_dev *rdev, u16 start,
>
> return res;
> }
> +EXPORT_SYMBOL_GPL(rio_request_outb_dbell);
>
> /**
> * rio_release_outb_dbell - release outbound doorbell message range
> @@ -350,6 +586,7 @@ int rio_release_outb_dbell(struct rio_dev *rdev, struct resource *res)
>
> return rc;
> }
> +EXPORT_SYMBOL_GPL(rio_release_outb_dbell);
>
> /**
> * rio_request_inb_pwrite - request inbound port-write message service
> @@ -360,7 +597,7 @@ int rio_release_outb_dbell(struct rio_dev *rdev, struct resource *res)
> * Returns 0 if the request has been satisfied.
> */
> int rio_request_inb_pwrite(struct rio_dev *rdev,
> - int (*pwcback)(struct rio_dev *rdev, union rio_pw_msg *msg, int step))
> + int (*pwcback)(struct rio_dev *rdev, union rio_pw_msg *msg, int step))
> {
> int rc = 0;
>
> @@ -405,22 +642,26 @@ EXPORT_SYMBOL_GPL(rio_release_inb_pwrite);
> * @destid: Destination ID of the device
> * @hopcount: Number of switch hops to the device
> */
> -u32
> -rio_mport_get_physefb(struct rio_mport *port, int local,
> - u16 destid, u8 hopcount)
> -{
> +int rio_mport_get_physefb(struct rio_mport *port, int local, u16 destid,
> + u8 hopcount, u32 *physefb) {
> u32 ext_ftr_ptr;
> u32 ftr_header;
> + int rc = 0;
> + rc = rio_mport_get_efb(port, local, destid, hopcount, 0, &ext_ftr_ptr);
> + if (rc)
> + goto done;
>
> - ext_ftr_ptr = rio_mport_get_efb(port, local, destid, hopcount, 0);
> -
> - while (ext_ftr_ptr) {
> - if (local)
> - rio_local_read_config_32(port, ext_ftr_ptr,
> - &ftr_header);
> - else
> - rio_mport_read_config_32(port, destid, hopcount,
> - ext_ftr_ptr, &ftr_header);
> + while (ext_ftr_ptr) {
> + if (local) {
> + rc = rio_local_read_config_32(port, ext_ftr_ptr, &ftr_header);
> + if (rc)
> + goto done;
> + } else {
> + rc = rio_mport_read_config_32(port, destid, hopcount,
> + ext_ftr_ptr, &ftr_header);
> + if (rc)
> + goto done;
> + }
>
> ftr_header = RIO_GET_BLOCK_ID(ftr_header);
> switch (ftr_header) {
> @@ -433,18 +674,22 @@ rio_mport_get_physefb(struct rio_mport *port, int local,
> case RIO_EFB_SER_EP_FREE_ID:
> case RIO_EFB_SER_EP_FREC_ID:
>
> - return ext_ftr_ptr;
> + goto done;
>
> default:
> break;
> }
> -
> - ext_ftr_ptr = rio_mport_get_efb(port, local, destid,
> - hopcount, ext_ftr_ptr);
> + rc = rio_mport_get_efb(port, local, destid, hopcount, ext_ftr_ptr,
> + &ext_ftr_ptr);
> + if (rc)
> + goto done;
> }
>
> - return ext_ftr_ptr;
> +done:
> + *physefb = ext_ftr_ptr;
> + return rc;
> }
> +EXPORT_SYMBOL_GPL(rio_mport_get_physefb);
>
> /**
> * rio_get_comptag - Begin or continue searching for a RIO device by component tag
> @@ -458,23 +703,39 @@ rio_mport_get_physefb(struct rio_mport *port, int local,
> * @from is not %NULL, searches continue from next device on the global
> * list.
> */
> -struct rio_dev *rio_get_comptag(u32 comp_tag, struct rio_dev *from)
> +struct rio_dev *rio_get_comptag(struct rio_mport *mport, u32 comp_tag)
> {
> - struct list_head *n;
> - struct rio_dev *rdev;
> -
> - spin_lock(&rio_global_list_lock);
> - n = from ? from->global_list.next : rio_devices.next;
> -
> - while (n && (n != &rio_devices)) {
> - rdev = rio_dev_g(n);
> - if (rdev->comp_tag == comp_tag)
> - goto exit;
> - n = n->next;
> + int items = atomic_read(&mport->net.rio_dev_num);
> + void **nptr = kzalloc(sizeof(void *) * items, GFP_KERNEL);
> + int i, num;
> + struct rio_dev *rdev = NULL;
> +
> + if (!nptr)
> + return NULL;
> +
> + rcu_read_lock();
> +retry:
> + num = radix_tree_gang_lookup_slot(&mport->net.dev_tree, (void ***)nptr,
> + NULL, 0, items);
> + if (num > 0) {
> + for (i = 0; i < num; i++) {
> + struct rio_dev *tmp = radix_tree_deref_slot((void **)nptr[i]);
> +
> + if (unlikely(!tmp))
> + continue;
> +
> + if (radix_tree_deref_retry(tmp))
> + goto retry;
> +
> + if (tmp->comp_tag == comp_tag) {
> + rdev = rio_dev_get(tmp);
> + goto done;
> + }
> + }
> }
> - rdev = NULL;
> -exit:
> - spin_unlock(&rio_global_list_lock);
> +done:
> + rcu_read_unlock();
> + kfree(nptr);
> return rdev;
> }
>
> @@ -484,66 +745,45 @@ exit:
> * @pnum: Switch port number to set LOCKOUT bit
> * @lock: Operation : set (=1) or clear (=0)
> */
> -int rio_set_port_lockout(struct rio_dev *rdev, u32 pnum, int lock)
> +static int
> +rio_set_port_lockout(struct rio_dev *rdev, u32 pnum, int lock, int do_lock)
> {
> + int rc = 0;
> u32 regval;
>
> - rio_read_config_32(rdev,
> - rdev->phys_efptr + RIO_PORT_N_CTL_CSR(pnum),
> - ®val);
> + if (do_lock)
> + rc = rio_hw_lock_wait(rdev->hport, rdev->destid, rdev->hopcount, 10);
> + if (rc)
> + goto done;
> + rc = rio_read_config_32(rdev,
> + rdev->phys_efptr + RIO_PORT_N_CTL_CSR(pnum), ®val);
> + if (rc)
> + goto rel_lock;
> +
> if (lock)
> regval |= RIO_PORT_N_CTL_LOCKOUT;
> else
> regval &= ~RIO_PORT_N_CTL_LOCKOUT;
>
> - rio_write_config_32(rdev,
> - rdev->phys_efptr + RIO_PORT_N_CTL_CSR(pnum),
> - regval);
> - return 0;
> -}
> + rc = rio_write_config_32(rdev, rdev->phys_efptr + RIO_PORT_N_CTL_CSR(pnum),
> + regval);
>
> -/**
> - * rio_chk_dev_route - Validate route to the specified device.
> - * @rdev: RIO device failed to respond
> - * @nrdev: Last active device on the route to rdev
> - * @npnum: nrdev's port number on the route to rdev
> - *
> - * Follows a route to the specified RIO device to determine the last available
> - * device (and corresponding RIO port) on the route.
> - */
> -static int
> -rio_chk_dev_route(struct rio_dev *rdev, struct rio_dev **nrdev, int *npnum)
> -{
> - u32 result;
> - int p_port, rc = -EIO;
> - struct rio_dev *prev = NULL;
> + pr_debug("RIO_EM: %s_port_lockout %s port %d addr %8.8x == %8.8x\n",
> + (lock ? "set" : "clear"), rio_name(rdev), pnum,
> + rdev->phys_efptr + RIO_PORT_N_CTL_CSR(pnum), regval);
>
> - /* Find switch with failed RIO link */
> - while (rdev->prev && (rdev->prev->pef & RIO_PEF_SWITCH)) {
> - if (!rio_read_config_32(rdev->prev, RIO_DEV_ID_CAR, &result)) {
> - prev = rdev->prev;
> - break;
> - }
> - rdev = rdev->prev;
> +rel_lock:
> + if (do_lock) {
> + if (rc)
> + rio_hw_unlock(rdev->hport, rdev->destid, rdev->hopcount);
> + else
> + rc = rio_hw_unlock(rdev->hport, rdev->destid, rdev->hopcount);
> }
> -
> - if (prev == NULL)
> - goto err_out;
> -
> - p_port = prev->rswitch->route_table[rdev->destid];
> -
> - if (p_port != RIO_INVALID_ROUTE) {
> - pr_debug("RIO: link failed on [%s]-P%d\n",
> - rio_name(prev), p_port);
> - *nrdev = prev;
> - *npnum = p_port;
> - rc = 0;
> - } else
> - pr_debug("RIO: failed to trace route to %s\n", rio_name(rdev));
> -err_out:
> +done:
> return rc;
> }
>
> +
> /**
> * rio_mport_chk_dev_access - Validate access to the specified device.
> * @mport: Master port to send transactions
> @@ -553,18 +793,10 @@ err_out:
> int
> rio_mport_chk_dev_access(struct rio_mport *mport, u16 destid, u8 hopcount)
> {
> - int i = 0;
> u32 tmp;
>
> - while (rio_mport_read_config_32(mport, destid, hopcount,
> - RIO_DEV_ID_CAR, &tmp)) {
> - i++;
> - if (i == RIO_MAX_CHK_RETRY)
> - return -EIO;
> - mdelay(1);
> - }
> -
> - return 0;
> + return rio_mport_read_config_32(mport, destid, hopcount,
> + RIO_DEV_ID_CAR, &tmp);
> }
>
> /**
> @@ -573,7 +805,7 @@ rio_mport_chk_dev_access(struct rio_mport *mport, u16 destid, u8 hopcount)
> */
> static int rio_chk_dev_access(struct rio_dev *rdev)
> {
> - return rio_mport_chk_dev_access(rdev->net->hport,
> + return rio_mport_chk_dev_access(rdev->hport,
> rdev->destid, rdev->hopcount);
> }
>
> @@ -585,42 +817,48 @@ static int rio_chk_dev_access(struct rio_dev *rdev)
> * @lnkresp: Response from a link partner
> */
> static int
> -rio_get_input_status(struct rio_dev *rdev, int pnum, u32 *lnkresp)
> +rio_get_input_status(struct rio_dev *rdev, int pnum, u32 request, u32 *lnkresp)
> {
> u32 regval;
> int checkcount;
> + int rc = 0;
>
> if (lnkresp) {
> /* Read from link maintenance response register
> * to clear valid bit */
> - rio_read_config_32(rdev,
> - rdev->phys_efptr + RIO_PORT_N_MNT_RSP_CSR(pnum),
> - ®val);
> + rc = rio_read_config_32(rdev,
> + rdev->phys_efptr + RIO_PORT_N_MNT_RSP_CSR(pnum), ®val);
> + if (rc)
> + goto done;
> udelay(50);
> }
>
> /* Issue Input-status command */
> - rio_write_config_32(rdev,
> - rdev->phys_efptr + RIO_PORT_N_MNT_REQ_CSR(pnum),
> - RIO_MNT_REQ_CMD_IS);
> + rc = rio_write_config_32(rdev,
> + rdev->phys_efptr + RIO_PORT_N_MNT_REQ_CSR(pnum), request);
> + if (rc)
> + goto done;
>
> /* Exit if the response is not expected */
> if (lnkresp == NULL)
> - return 0;
> + goto done;
>
> checkcount = 3;
> while (checkcount--) {
> udelay(50);
> - rio_read_config_32(rdev,
> - rdev->phys_efptr + RIO_PORT_N_MNT_RSP_CSR(pnum),
> - ®val);
> + rc = rio_read_config_32(rdev,
> + rdev->phys_efptr + RIO_PORT_N_MNT_RSP_CSR(pnum), ®val);
> + if (rc)
> + goto done;
> if (regval & RIO_PORT_N_MNT_RSP_RVAL) {
> *lnkresp = regval;
> - return 0;
> + goto done;
> }
> }
>
> - return -EIO;
> + rc = -EIO;
> +done:
> + return rc;
> }
>
> /**
> @@ -629,87 +867,443 @@ rio_get_input_status(struct rio_dev *rdev, int pnum, u32 *lnkresp)
> * @pnum: Switch port number to clear errors
> * @err_status: port error status (if 0 reads register from device)
> */
> -static int rio_clr_err_stopped(struct rio_dev *rdev, u32 pnum, u32 err_status)
> +int
> +rio_clr_err_stopped(struct rio_dev *rdev, u32 pnum, u32 err_status, int *success)
> {
> - struct rio_dev *nextdev = rdev->rswitch->nextdev[pnum];
> + struct rio_dev *nextdev;
> u32 regval;
> u32 far_ackid, far_linkstat, near_ackid;
> + int rc = 0;
>
> - if (err_status == 0)
> - rio_read_config_32(rdev,
> - rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(pnum),
> - &err_status);
> + nextdev = lookup_rdev_next(rdev, pnum);
> + if (IS_ERR(nextdev))
> + nextdev = NULL;
> + rc = rio_hw_lock_wait(rdev->hport, rdev->destid,
> + rdev->hopcount, 10);
> + if (rdev->use_hw_lock && (rc))
> + goto done;
> +
> + if (err_status == 0) {
> + rc = rio_get_err_and_status(rdev, pnum, &err_status);
> + if (rc)
> + goto err;
> + }
>
> if (err_status & RIO_PORT_N_ERR_STS_PW_OUT_ES) {
> pr_debug("RIO_EM: servicing Output Error-Stopped state\n");
> /*
> * Send a Link-Request/Input-Status control symbol
> */
> - if (rio_get_input_status(rdev, pnum, ®val)) {
> + rc = rio_get_input_status(rdev, pnum, RIO_MNT_REQ_CMD_IS, ®val);
> + if (rc == -EIO) {
> pr_debug("RIO_EM: Input-status response timeout\n");
> goto rd_err;
> + } else if (rc) {
> + goto err;
> }
>
> - pr_debug("RIO_EM: SP%d Input-status response=0x%08x\n",
> - pnum, regval);
> + pr_debug("RIO_EM: SP%d Input-status response=0x%08x\n", pnum, regval);
> far_ackid = (regval & RIO_PORT_N_MNT_RSP_ASTAT) >> 5;
> far_linkstat = regval & RIO_PORT_N_MNT_RSP_LSTAT;
> - rio_read_config_32(rdev,
> - rdev->phys_efptr + RIO_PORT_N_ACK_STS_CSR(pnum),
> - ®val);
> + rc = rio_read_config_32(rdev,
> + rdev->phys_efptr + RIO_PORT_N_ACK_STS_CSR(pnum), ®val);
> + if (rc)
> + goto err;
> pr_debug("RIO_EM: SP%d_ACK_STS_CSR=0x%08x\n", pnum, regval);
> near_ackid = (regval & RIO_PORT_N_ACK_INBOUND) >> 24;
> - pr_debug("RIO_EM: SP%d far_ackID=0x%02x far_linkstat=0x%02x" \
> - " near_ackID=0x%02x\n",
> - pnum, far_ackid, far_linkstat, near_ackid);
> + pr_debug("RIO_EM: SP%d far_ackID=0x%02x far_linkstat=0x%02x near_ackID=0x%02x\n",
> + pnum, far_ackid, far_linkstat, near_ackid);
>
> /*
> * If required, synchronize ackIDs of near and
> * far sides.
> */
> - if ((far_ackid != ((regval & RIO_PORT_N_ACK_OUTSTAND) >> 8)) ||
> - (far_ackid != (regval & RIO_PORT_N_ACK_OUTBOUND))) {
> + if ((far_ackid != ((regval & RIO_PORT_N_ACK_OUTSTAND) >> 8))
> + || (far_ackid != (regval & RIO_PORT_N_ACK_OUTBOUND))) {
> /* Align near outstanding/outbound ackIDs with
> * far inbound.
> */
> - rio_write_config_32(rdev,
> - rdev->phys_efptr + RIO_PORT_N_ACK_STS_CSR(pnum),
> - (near_ackid << 24) |
> - (far_ackid << 8) | far_ackid);
> + rc = rio_write_config_32(rdev,
> + rdev->phys_efptr + RIO_PORT_N_ACK_STS_CSR(pnum),
> + (near_ackid << 24) | (far_ackid << 8) | far_ackid);
> + if (rc)
> + goto err;
> /* Align far outstanding/outbound ackIDs with
> * near inbound.
> */
> far_ackid++;
> - if (nextdev)
> - rio_write_config_32(nextdev,
> - nextdev->phys_efptr +
> - RIO_PORT_N_ACK_STS_CSR(RIO_GET_PORT_NUM(nextdev->swpinfo)),
> - (far_ackid << 24) |
> - (near_ackid << 8) | near_ackid);
> - else
> + if (nextdev) {
> + rc = rio_write_config_32(nextdev,
> + nextdev->phys_efptr + RIO_PORT_N_ACK_STS_CSR(
> + RIO_GET_PORT_NUM(nextdev->swpinfo)),
> + (far_ackid << 24) | (near_ackid << 8) | near_ackid);
> + if ((rc))
> + goto err;
> + } else {
> pr_debug("RIO_EM: Invalid nextdev pointer (NULL)\n");
> + }
> }
> rd_err:
> - rio_read_config_32(rdev,
> - rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(pnum),
> - &err_status);
> + rc = rio_get_err_and_status(rdev, pnum, &err_status);
> + if (rc)
> + goto err;
> pr_debug("RIO_EM: SP%d_ERR_STS_CSR=0x%08x\n", pnum, err_status);
> }
>
> if ((err_status & RIO_PORT_N_ERR_STS_PW_INP_ES) && nextdev) {
> pr_debug("RIO_EM: servicing Input Error-Stopped state\n");
> - rio_get_input_status(nextdev,
> - RIO_GET_PORT_NUM(nextdev->swpinfo), NULL);
> + rio_get_input_status(nextdev, RIO_GET_PORT_NUM(nextdev->swpinfo),
> + RIO_MNT_REQ_CMD_IS, NULL);
> udelay(50);
> -
> - rio_read_config_32(rdev,
> - rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(pnum),
> - &err_status);
> + rc = rio_get_err_and_status(rdev, pnum, &err_status);
> + if (rc)
> + goto err;
> pr_debug("RIO_EM: SP%d_ERR_STS_CSR=0x%08x\n", pnum, err_status);
> }
>
> - return (err_status & (RIO_PORT_N_ERR_STS_PW_OUT_ES |
> - RIO_PORT_N_ERR_STS_PW_INP_ES)) ? 1 : 0;
> + *success = (err_status & (RIO_PORT_N_ERR_STS_PW_OUT_ES |
> + RIO_PORT_N_ERR_STS_PW_INP_ES)) ? 0 : 1;
> + goto rel_lock;
> +err:
> + pr_debug("RIO_EM: Read/Write Error\n");
> + *success = 0;
> +rel_lock:
> + if (rdev->use_hw_lock) {
> + if (rc)
> + rio_hw_unlock(rdev->hport, rdev->destid, rdev->hopcount);
> + else
> + rc = rio_hw_unlock(rdev->hport, rdev->destid, rdev->hopcount);
> + }
> +done:
> + if (nextdev)
> + rio_dev_put(nextdev);
> + return rc;
> +}
> +/**
> + * @brief Brute force sync ackid method
> + *
> + * Send link maint request to LP then configure
> + * near end so that inbound, outstanding and outbound
> + * ackid corresponds to far end next expected ackid.
> + *
> + * This will work as long as far end next expected
> + * inbound == outbound (which is usually the case)
> + *
> + * @note The proper is probably to first sync near
> + * end to far end next expected and then do maint
> + * request to LP to sync far en outbound to near end
> + * inbound. To do that, however, you'd need to know
> + * the phys extended feature ptr offset and the port
> + * number of the LP, and that information is hard to
> + * come by as long as near and far end ackid are not
> + * in sync
> + */
> +static int rio_ackid_sync(struct rio_dev *rdev, u32 pnum)
> +{
> + struct rio_dev *nextdev;
> + u32 regval;
> + u32 far_ackid, far_linkstat, near_ackid;
> + int rc = 0;
> +
> + nextdev = lookup_rdev_next(rdev, pnum);
> + if (IS_ERR(nextdev))
> + nextdev = NULL;
> + rc = rio_hw_lock_wait(rdev->hport, rdev->destid,
> + rdev->hopcount, 10);
> + if (rdev->use_hw_lock && (rc))
> + goto done;
> +
> + pr_debug("RIO_EM: Send link request\n");
> + /*
> + * Send a Link-Request/Input-Status control symbol
> + */
> + rc = rio_get_input_status(rdev, pnum, RIO_MNT_REQ_CMD_IS, ®val);
> + if (rc == -EIO) {
> + pr_warn("RIO_EM: Input-status response timeout\n");
> + goto rd_err;
> + } else if (rc) {
> + pr_warn("RIO_EM: Input-status response other err %d\n", rc);
> + goto err;
> + }
> +
> + pr_debug("RIO_EM: SP%d Input-status response=0x%08x\n", pnum, regval);
> + far_ackid = (regval & RIO_PORT_N_MNT_RSP_ASTAT) >> 5;
> + far_linkstat = regval & RIO_PORT_N_MNT_RSP_LSTAT;
> + rc = rio_read_config_32(rdev,
> + rdev->phys_efptr + RIO_PORT_N_ACK_STS_CSR(pnum), ®val);
> + if (rc)
> + goto err;
> +
> + pr_debug("RIO_EM: SP%d_ACK_STS_CSR=0x%08x\n", pnum, regval);
> + near_ackid = (regval & RIO_PORT_N_ACK_INBOUND) >> 24;
> + pr_debug("RIO_EM: SP%d far_ackID=0x%02x far_linkstat=0x%02x near_ackID=0x%02x\n",
> + pnum, far_ackid, far_linkstat, near_ackid);
> +
> + if (far_linkstat != 0x10) {
> + pr_warn("RIO_EM: LP link state 0x%08x\n", far_linkstat);
> + rc = -EIO;
> + goto err;
> + }
> + /*
> + * If required, synchronize ackIDs of near and
> + * far sides.
> + */
> + if ((far_ackid != ((regval & RIO_PORT_N_ACK_OUTSTAND) >> 8))
> + || (far_ackid != (regval & RIO_PORT_N_ACK_OUTBOUND))) {
> + /* Align near outstanding/outbound ackIDs with
> + * far inbound.
> + */
> + rc = rio_write_config_32(rdev,
> + rdev->phys_efptr + RIO_PORT_N_ACK_STS_CSR(pnum),
> + (far_ackid << 24) | (far_ackid << 8) | far_ackid);
> + if (rc)
> + goto err;
> + }
> + goto rel_lock;
> +rd_err:
> + rc = rio_get_err_and_status(rdev, pnum, ®val);
> + if (rc)
> + goto err;
> + pr_warn("RIO_EM: SP%d_ERR_STS_CSR=0x%08x\n", pnum, regval);
> + goto rel_lock;
> +err:
> + pr_warn("RIO_EM: Read/Write Error\n");
> +rel_lock:
> + if (rdev->use_hw_lock) {
> + if (rc)
> + rio_hw_unlock(rdev->hport, rdev->destid, rdev->hopcount);
> + else
> + rc = rio_hw_unlock(rdev->hport, rdev->destid, rdev->hopcount);
> + }
> +done:
> + if (nextdev)
> + rio_dev_put(nextdev);
> + return rc;
> +}
> +
> +static int
> +rio_pw_dump_msg(union rio_pw_msg *pw_msg)
> +{
> +#ifdef DEBUG_PW
> + u32 i;
> + for (i = 0; i < RIO_PW_MSG_SIZE/sizeof(u32);) {
> + pr_debug("0x%02x: %08x %08x %08x %08x\n",
> + i * 4, pw_msg->raw[i], pw_msg->raw[i + 1],
> + pw_msg->raw[i + 2], pw_msg->raw[i + 3]);
> + i += 4;
> + }
> +#endif
> + return 0;
> +}
> +
> +static int
> +rio_handle_local_domain(struct rio_dev *rdev, int portnum, u32 err_status)
> +{
> + int rc = 0;
> + u32 em_perrdet, em_ltlerrdet;
> +
> + if (rdev->local_domain) {
> + rc = rio_hw_lock_wait(rdev->hport, rdev->destid,
> + rdev->hopcount, 10);
> + if (rdev->use_hw_lock && (rc))
> + goto done;
> + rc = rio_read_config_32(rdev,
> + rdev->em_efptr + RIO_EM_PN_ERR_DETECT(portnum), &em_perrdet);
> + if (rc) {
> + pr_debug(
> + "RIO_PW: Failed to read RIO_EM_PN_ERR_DETECT from device\n");
> + goto rel_lock;
> + }
> + if (em_perrdet) {
> + /* Clear EM Port N Error Detect CSR */
> + rc = rio_write_config_32(rdev,
> + rdev->em_efptr + RIO_EM_PN_ERR_DETECT(portnum), 0);
> + if (rc) {
> + pr_debug(
> + "RIO_PW: Failed to write RIO_EM_PN_ERR_DETECT to device\n");
> + goto rel_lock;
> + }
> + }
> + rc = rio_read_config_32(rdev,
> + rdev->em_efptr + RIO_EM_LTL_ERR_DETECT, &em_ltlerrdet);
> + if (rc) {
> + pr_debug(
> + "RIO_PW: Failed to read RIO_EM_LTL_ERR_DETECT from device\n");
> + goto rel_lock;
> + }
> + if (em_ltlerrdet) {
> + /* Clear EM L/T Layer Error Detect CSR */
> + rc = rio_write_config_32(rdev,
> + rdev->em_efptr + RIO_EM_LTL_ERR_DETECT, 0);
> + if (rc) {
> + pr_debug(
> + "RIO_PW: Failed to write RIO_EM_LTL_ERR_DETECT to device\n");
> + goto rel_lock;
> + }
> + }
> + /* Clear remaining error bits and Port-Write Pending bit */
> + rc = rio_write_config_32(rdev,
> + rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(portnum), err_status);
> + if (rc) {
> + pr_debug(
> + "RIO_PW: Failed to write RIO_PORT_N_ERR_STS_CSR to device\n");
> + goto rel_lock;
> + }
> +rel_lock:
> + if (rdev->use_hw_lock) {
> + if (rc)
> + rio_hw_unlock(rdev->hport, rdev->destid, rdev->hopcount);
> + else
> + rc = rio_hw_unlock(rdev->hport, rdev->destid, rdev->hopcount);
> + }
> + }
> +done:
> + return rc;
> +}
> +
> +static int
> +rio_handle_events(struct rio_dev *rdev, int portnum, u32 err_status, int *event)
> +{
> + int rc = 0;
> + int success;
> +
> + rio_tree_write_lock();
> +
> + if (err_status & RIO_PORT_N_ERR_STS_PORT_OK) {
> + pr_debug("RIO: port OK\n");
> + if ((!(rdev->rswitch->port_init & (1 << portnum)))
> + || (!(rdev->rswitch->port_ok & (1 << portnum)))) {
> + rdev->rswitch->port_init |= (1 << portnum);
> + rdev->rswitch->port_ok |= (1 << portnum);
> + if (rdev->local_domain) {
> + rc = rio_set_port_lockout(rdev, portnum, 0, 1);
> + if (rc) {
> + pr_warn("RIO: Failed to set port lockout bit.\n");
> + goto done;
> + }
> + }
> + }
> + /* Schedule Insertion Service */
> + pr_debug("RIO: Device Insertion on [%s]-P%d\n", rio_name(rdev),
> + portnum);
> + *event = RIO_DEVICE_INSERTION;
> +
> + if (rdev->local_domain) {
> + /* Clear error-stopped states (if reported).
> + * Depending on the link partner state, two attempts
> + * may be needed for successful recovery.
> + */
> + if (err_status & (RIO_PORT_N_ERR_STS_PW_OUT_ES |
> + RIO_PORT_N_ERR_STS_PW_INP_ES)) {
> + rc = rio_clr_err_stopped(rdev, portnum, err_status, &success);
> + if (rc)
> + goto done;
> + if (!success) {
> + rc = rio_clr_err_stopped(rdev, portnum, 0, &success);
> + if (rc)
> + goto done;
> + }
> + }
> + }
> + } else { /* if (err_status & RIO_PORT_N_ERR_STS_PORT_UNINIT) */
> + if ((!(rdev->rswitch->port_init & (1 << portnum)))
> + || (rdev->rswitch->port_ok & (1 << portnum))) {
> + rdev->rswitch->port_init |= (1 << portnum);
> + rdev->rswitch->port_ok &= ~(1 << portnum);
> + if (rdev->local_domain) {
> + rc = rio_hw_lock_wait(rdev->hport, rdev->destid, rdev->hopcount,
> + 10);
> + if (rdev->use_hw_lock && (rc))
> + goto done;
> + rc = rio_set_port_lockout(rdev, portnum, 1, 0);
> + if (rc) {
> + pr_warn("RIO: Failed to set port lockout bit.\n");
> + if (rdev->use_hw_lock)
> + rio_hw_unlock(rdev->hport, rdev->destid,
> + rdev->hopcount);
> + goto done;
> + }
> + rc = rio_write_config_32(rdev,
> + rdev->phys_efptr + RIO_PORT_N_ACK_STS_CSR(portnum),
> + RIO_PORT_N_ACK_CLEAR);
> + if (rc) {
> + pr_warn(
> + "RIO: Failed to write to RIO_PORT_N_ACK_STS_CSR.\n");
> + if (rdev->use_hw_lock)
> + rio_hw_unlock(rdev->hport, rdev->destid,
> + rdev->hopcount);
> + goto done;
> + }
> + rc = rio_hw_unlock(rdev->hport, rdev->destid, rdev->hopcount);
> + if (rdev->use_hw_lock && (rc))
> + goto done;
> + }
> + }
> + /* Schedule Extraction Service */
> + pr_debug("RIO: Device Extraction on [%s]-P%d\n", rio_name(rdev),
> + portnum);
> + *event = RIO_DEVICE_EXTRACTION;
> + }
> +done:
> + rio_tree_write_unlock();
> + return rc;
> +}
> +static int __rio_setup_event(struct rio_dev *rdev, int portnum, int event)
> +{
> + int rc = 0;
> + int tmp_event = 0;
> + u32 err_status;
> +
> + rdev = rio_get_by_ptr(rdev);
> + if (!rdev)
> + goto done;
> +
> + if (rdev->local_domain) {
> + if (rdev->rswitch->em_handle) {
> + if ((!rdev->use_hw_lock)
> + || (!rio_hw_lock_wait(rdev->hport, rdev->destid,
> + rdev->hopcount, 10))) {
> + rdev->rswitch->em_handle(rdev, portnum);
> + if (rdev->use_hw_lock)
> + rio_hw_unlock(rdev->hport, rdev->destid, rdev->hopcount);
> + }
> + }
> + }
> + rc = rio_get_err_and_status(rdev, portnum, &err_status);
> + if (rc)
> + goto rel_dev;
> + pr_debug("port %d RIO_PORT_N_ERR_STS_CSR 0x%x\n", portnum, err_status);
> + rc = rio_handle_events(rdev, portnum, err_status, &tmp_event);
> + if (rc)
> + goto rel_dev;
> +
> + if (tmp_event != event) {
> + rc = 1;
> + if (event == RIO_DEVICE_EXTRACTION)
> + pr_err("RIO: Removal of not reseted device is not allowed.\n");
> + else
> + pr_err("RIO: Insertion of device on not ok port is not allowed.\n");
> + goto rel_dev;
> + }
> + rc = rio_handle_local_domain(rdev, portnum, err_status);
> + if (rc)
> + goto rel_dev;
> +
> +rel_dev:
> + rio_dev_put(rdev);
> +done:
> + return rc;
> +}
> +int rio_setup_event(struct rio_dev *rdev, int portnum, int event)
> +{
> + return __rio_setup_event(rdev, portnum, event);
> +}
> +int rio_setup_event_force(struct rio_dev *rdev, int portnum, int event)
> +{
> + int rc = __rio_setup_event(rdev, portnum, event);
> + if (!rc && (event == RIO_DEVICE_INSERTION))
> + rio_ackid_sync(rdev, portnum);
> + return rc;
> }
>
> /**
> @@ -719,33 +1313,26 @@ rd_err:
> * Processes an inbound port-write message. Returns 0 if the request
> * has been satisfied.
> */
> -int rio_inb_pwrite_handler(union rio_pw_msg *pw_msg)
> +int
> +rio_inb_pwrite_handler(struct rio_mport *mport, union rio_pw_msg *pw_msg)
> {
> struct rio_dev *rdev;
> - u32 err_status, em_perrdet, em_ltlerrdet;
> - int rc, portnum;
> + int rc = 0;
> + int portnum;
> +
> + pr_debug("RIO-EM: --- %s ---\n", __func__);
>
> - rdev = rio_get_comptag((pw_msg->em.comptag & RIO_CTAG_UDEVID), NULL);
> + rdev = rio_get_comptag(mport, (pw_msg->em.comptag & RIO_CTAG_UDEVID));
> if (rdev == NULL) {
> /* Device removed or enumeration error */
> - pr_debug("RIO: %s No matching device for CTag 0x%08x\n",
> - __func__, pw_msg->em.comptag);
> - return -EIO;
> + pr_debug("RIO_PW: %s No matching device for CTag 0x%08x\n", __func__,
> + pw_msg->em.comptag);
> + rc = -EIO;
> + goto done;
> }
> + pr_debug("RIO_PW: Port-Write message from %s\n", rio_name(rdev));
>
> - pr_debug("RIO: Port-Write message from %s\n", rio_name(rdev));
> -
> -#ifdef DEBUG_PW
> - {
> - u32 i;
> - for (i = 0; i < RIO_PW_MSG_SIZE/sizeof(u32);) {
> - pr_debug("0x%02x: %08x %08x %08x %08x\n",
> - i*4, pw_msg->raw[i], pw_msg->raw[i + 1],
> - pw_msg->raw[i + 2], pw_msg->raw[i + 3]);
> - i += 4;
> - }
> - }
> -#endif
> + rio_pw_dump_msg(pw_msg);
>
> /* Call an external service function (if such is registered
> * for this device). This may be the service for endpoints that send
> @@ -756,7 +1343,7 @@ int rio_inb_pwrite_handler(union rio_pw_msg *pw_msg)
> if (rdev->pwcback != NULL) {
> rc = rdev->pwcback(rdev, pw_msg, 0);
> if (rc == 0)
> - return 0;
> + goto rel_dev;
> }
>
> portnum = pw_msg->em.is_port & 0xFF;
> @@ -766,102 +1353,61 @@ int rio_inb_pwrite_handler(union rio_pw_msg *pw_msg)
> * powered down (or link being lost).
> */
> if (rio_chk_dev_access(rdev)) {
> - pr_debug("RIO: device access failed - get link partner\n");
> - /* Scan route to the device and identify failed link.
> - * This will replace device and port reported in PW message.
> - * PW message should not be used after this point.
> - */
> - if (rio_chk_dev_route(rdev, &rdev, &portnum)) {
> - pr_err("RIO: Route trace for %s failed\n",
> - rio_name(rdev));
> - return -EIO;
> - }
> - pw_msg = NULL;
> + pr_debug("RIO_PW: device access failed\n");
> + rc = -EIO;
> + goto rel_dev;
> }
>
> /* For End-point devices processing stops here */
> if (!(rdev->pef & RIO_PEF_SWITCH))
> - return 0;
> + goto rel_dev;
>
> - if (rdev->phys_efptr == 0) {
> - pr_err("RIO_PW: Bad switch initialization for %s\n",
> - rio_name(rdev));
> - return 0;
> + if (!rdev->phys_efptr) {
> + pr_err("RIO_PW: Bad switch initialization for %s\n", rio_name(rdev));
> + goto rel_dev;
> }
>
> - /*
> - * Process the port-write notification from switch
> - */
> - if (rdev->rswitch->em_handle)
> - rdev->rswitch->em_handle(rdev, portnum);
> -
> - rio_read_config_32(rdev,
> - rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(portnum),
> - &err_status);
> - pr_debug("RIO_PW: SP%d_ERR_STS_CSR=0x%08x\n", portnum, err_status);
> -
> - if (err_status & RIO_PORT_N_ERR_STS_PORT_OK) {
> -
> - if (!(rdev->rswitch->port_ok & (1 << portnum))) {
> - rdev->rswitch->port_ok |= (1 << portnum);
> - rio_set_port_lockout(rdev, portnum, 0);
> - /* Schedule Insertion Service */
> - pr_debug("RIO_PW: Device Insertion on [%s]-P%d\n",
> - rio_name(rdev), portnum);
> - }
> -
> - /* Clear error-stopped states (if reported).
> - * Depending on the link partner state, two attempts
> - * may be needed for successful recovery.
> + if (rdev->local_domain) {
> + /* Process the port-write notification from switch
> */
> - if (err_status & (RIO_PORT_N_ERR_STS_PW_OUT_ES |
> - RIO_PORT_N_ERR_STS_PW_INP_ES)) {
> - if (rio_clr_err_stopped(rdev, portnum, err_status))
> - rio_clr_err_stopped(rdev, portnum, 0);
> - }
> - } else { /* if (err_status & RIO_PORT_N_ERR_STS_PORT_UNINIT) */
> -
> - if (rdev->rswitch->port_ok & (1 << portnum)) {
> - rdev->rswitch->port_ok &= ~(1 << portnum);
> - rio_set_port_lockout(rdev, portnum, 1);
> -
> - rio_write_config_32(rdev,
> - rdev->phys_efptr +
> - RIO_PORT_N_ACK_STS_CSR(portnum),
> - RIO_PORT_N_ACK_CLEAR);
> -
> - /* Schedule Extraction Service */
> - pr_debug("RIO_PW: Device Extraction on [%s]-P%d\n",
> - rio_name(rdev), portnum);
> - }
> + if (rdev->rswitch->em_handle)
> + rdev->rswitch->em_handle(rdev, portnum);
> }
>
> - rio_read_config_32(rdev,
> - rdev->em_efptr + RIO_EM_PN_ERR_DETECT(portnum), &em_perrdet);
> - if (em_perrdet) {
> - pr_debug("RIO_PW: RIO_EM_P%d_ERR_DETECT=0x%08x\n",
> - portnum, em_perrdet);
> - /* Clear EM Port N Error Detect CSR */
> - rio_write_config_32(rdev,
> - rdev->em_efptr + RIO_EM_PN_ERR_DETECT(portnum), 0);
> - }
> +#if !defined(CONFIG_RAPIDIO_HOTPLUG)
> + /**
> + * FIXME!
> + * Temporary fix to make ulma booting on DUL work
> + * with the old version of the ulma driver for DUL
> + * which is not adopted to hotplug
> + * Maybe we should do this anyway if user don't define
> + * hotplug - to keep the same level of PW handling as
> + * in original RIO driver - i.e. call rio_setup_event,
> + * not the rest obviously.
> + */
> + {
> + u32 err_status;
> + int event = 0;
> + rc = rio_get_err_and_status(rdev, portnum, &err_status);
> + if (rc)
> + goto rel_dev;
> +
> + if (err_status & RIO_PORT_N_ERR_STS_PORT_OK)
> + event = RIO_DEVICE_INSERTION;
> + else
> + event = RIO_DEVICE_EXTRACTION;
>
> - rio_read_config_32(rdev,
> - rdev->em_efptr + RIO_EM_LTL_ERR_DETECT, &em_ltlerrdet);
> - if (em_ltlerrdet) {
> - pr_debug("RIO_PW: RIO_EM_LTL_ERR_DETECT=0x%08x\n",
> - em_ltlerrdet);
> - /* Clear EM L/T Layer Error Detect CSR */
> - rio_write_config_32(rdev,
> - rdev->em_efptr + RIO_EM_LTL_ERR_DETECT, 0);
> - }
> + rc = rio_setup_event(rdev, portnum, event);
>
> - /* Clear remaining error bits and Port-Write Pending bit */
> - rio_write_config_32(rdev,
> - rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(portnum),
> - err_status);
> + if (rdev->pwcback != NULL && rc == 0)
> + (void) rdev->pwcback(rdev, pw_msg, event);
> + }
> +#endif
>
> - return 0;
> +rel_dev:
> + rio_dev_put(rdev);
> +done:
> + return rc;
> }
> EXPORT_SYMBOL_GPL(rio_inb_pwrite_handler);
>
> @@ -874,28 +1420,31 @@ EXPORT_SYMBOL_GPL(rio_inb_pwrite_handler);
> * @from: Offset of current Extended Feature block header (if 0 starts
> * from ExtFeaturePtr)
> */
> -u32
> -rio_mport_get_efb(struct rio_mport *port, int local, u16 destid,
> - u8 hopcount, u32 from)
> -{
> +int rio_mport_get_efb(struct rio_mport *port, int local, u16 destid,
> + u8 hopcount, u32 from, u32 *ext_ftr_ptr) {
> u32 reg_val;
> + int rc = 0;
>
> if (from == 0) {
> if (local)
> - rio_local_read_config_32(port, RIO_ASM_INFO_CAR,
> - ®_val);
> + rc = rio_local_read_config_32(port, RIO_ASM_INFO_CAR, ®_val);
> else
> - rio_mport_read_config_32(port, destid, hopcount,
> - RIO_ASM_INFO_CAR, ®_val);
> - return reg_val & RIO_EXT_FTR_PTR_MASK;
> + rc = rio_mport_read_config_32(port, destid, hopcount,
> + RIO_ASM_INFO_CAR, ®_val);
> + if (!rc)
> + *ext_ftr_ptr = reg_val & RIO_EXT_FTR_PTR_MASK;
> } else {
> if (local)
> - rio_local_read_config_32(port, from, ®_val);
> + rc = rio_local_read_config_32(port, from, ®_val);
> else
> - rio_mport_read_config_32(port, destid, hopcount,
> - from, ®_val);
> - return RIO_GET_BLOCK_ID(reg_val);
> + rc = rio_mport_read_config_32(port, destid, hopcount, from,
> + ®_val);
> + if (!rc)
> + *ext_ftr_ptr = RIO_GET_BLOCK_ID(reg_val);
> }
> + if (rc)
> + *ext_ftr_ptr = 0;
> + return rc;
> }
>
> /**
> @@ -924,36 +1473,45 @@ rio_mport_get_efb(struct rio_mport *port, int local, u16 destid,
> *
> * %RIO_EFB_SER_EP_FREE_ID LP/Serial EP Free Devices
> */
> -u32
> -rio_mport_get_feature(struct rio_mport * port, int local, u16 destid,
> - u8 hopcount, int ftr)
> -{
> - u32 asm_info, ext_ftr_ptr, ftr_header;
> +int rio_mport_get_feature(struct rio_mport *port, int local, u16 destid,
> + u8 hopcount, int ftr, u32 *feature) {
> + u32 asm_info, ext_ftr_ptr = 0, ftr_header;
> + int rc = 0;
>
> - if (local)
> - rio_local_read_config_32(port, RIO_ASM_INFO_CAR, &asm_info);
> - else
> - rio_mport_read_config_32(port, destid, hopcount,
> - RIO_ASM_INFO_CAR, &asm_info);
> + if (local) {
> + rc = rio_local_read_config_32(port, RIO_ASM_INFO_CAR, &asm_info);
> + if (rc)
> + goto done;
> + } else {
> + rc = rio_mport_read_config_32(port, destid, hopcount,
> + RIO_ASM_INFO_CAR, &asm_info);
> + if (rc)
> + goto done;
> + }
>
> ext_ftr_ptr = asm_info & RIO_EXT_FTR_PTR_MASK;
>
> while (ext_ftr_ptr) {
> - if (local)
> - rio_local_read_config_32(port, ext_ftr_ptr,
> - &ftr_header);
> - else
> - rio_mport_read_config_32(port, destid, hopcount,
> - ext_ftr_ptr, &ftr_header);
> + if (local) {
> + rc = rio_local_read_config_32(port, ext_ftr_ptr, &ftr_header);
> + if (rc)
> + goto done;
> + } else {
> + rc = rio_mport_read_config_32(port, destid, hopcount,
> + ext_ftr_ptr, &ftr_header);
> + if (rc)
> + goto done;
> + }
> if (RIO_GET_BLOCK_ID(ftr_header) == ftr)
> - return ext_ftr_ptr;
> - if (!(ext_ftr_ptr = RIO_GET_BLOCK_PTR(ftr_header)))
> + goto done;
> + ext_ftr_ptr = RIO_GET_BLOCK_PTR(ftr_header);
> + if (!ext_ftr_ptr)
> break;
> }
> -
> - return 0;
> +done:
> + *feature = ext_ftr_ptr;
> + return rc;
> }
> -
> /**
> * rio_get_asm - Begin or continue searching for a RIO device by vid/did/asm_vid/asm_did
> * @vid: RIO vid to match or %RIO_ANY_ID to match all vids
> @@ -974,29 +1532,57 @@ rio_mport_get_feature(struct rio_mport * port, int local, u16 destid,
> struct rio_dev *rio_get_asm(u16 vid, u16 did,
> u16 asm_vid, u16 asm_did, struct rio_dev *from)
> {
> - struct list_head *n;
> - struct rio_dev *rdev;
> -
> - WARN_ON(in_interrupt());
> - spin_lock(&rio_global_list_lock);
> - n = from ? from->global_list.next : rio_devices.next;
> -
> - while (n && (n != &rio_devices)) {
> - rdev = rio_dev_g(n);
> - if ((vid == RIO_ANY_ID || rdev->vid == vid) &&
> - (did == RIO_ANY_ID || rdev->did == did) &&
> - (asm_vid == RIO_ANY_ID || rdev->asm_vid == asm_vid) &&
> - (asm_did == RIO_ANY_ID || rdev->asm_did == asm_did))
> - goto exit;
> - n = n->next;
> + struct rio_mport *mport = (from ? from->hport : rio_get_mport(RIO_ANY_ID, NULL));
> + int items;
> + void **nptr;
> + int i, num;
> + struct rio_dev *rdev = NULL;
> + unsigned long key = (from ? from->destid : 0);
> +
> + rcu_read_lock();
> + while (mport) {
> + items = atomic_read(&mport->net.rio_dev_num);
> + if (!items) {
> + rcu_read_unlock();
> + return NULL;
> + }
> + nptr = kzalloc(sizeof(void *) * items, GFP_KERNEL);
> + if (!nptr) {
> + rcu_read_unlock();
> + return NULL;
> + }
> +retry:
> + num = radix_tree_gang_lookup_slot(&mport->net.dev_tree, (void ***)nptr,
> + NULL, key, items);
> + if (num > 0) {
> + for (i = 0; i < num; i++) {
> + rdev = radix_tree_deref_slot((void **)nptr[i]);
> + if (unlikely(!rdev))
> + continue;
> + if (radix_tree_deref_retry(rdev))
> + goto retry;
> + if (rdev == from)
> + continue;
> + if ((vid == RIO_ANY_ID || rdev->vid == vid) &&
> + (did == RIO_ANY_ID || rdev->did == did) &&
> + (asm_vid == RIO_ANY_ID || rdev->asm_vid == asm_vid) &&
> + (asm_did == RIO_ANY_ID || rdev->asm_did == asm_did)) {
> + kfree(nptr);
> + goto done;
> + }
> + }
> + }
> + kfree(nptr);
> + mport = rio_get_mport(RIO_ANY_ID, mport);
> }
> rdev = NULL;
> - exit:
> +done:
> rio_dev_put(from);
> rdev = rio_dev_get(rdev);
> - spin_unlock(&rio_global_list_lock);
> + rcu_read_unlock();
> return rdev;
> }
> +EXPORT_SYMBOL_GPL(rio_get_asm);
>
> /**
> * rio_get_device - Begin or continue searching for a RIO device by vid/did
> @@ -1016,6 +1602,7 @@ struct rio_dev *rio_get_device(u16 vid, u16 did, struct rio_dev *from)
> {
> return rio_get_asm(vid, did, RIO_ANY_ID, RIO_ANY_ID, from);
> }
> +EXPORT_SYMBOL_GPL(rio_get_device);
>
> /**
> * rio_std_route_add_entry - Add switch route table entry using standard
> @@ -1028,19 +1615,22 @@ struct rio_dev *rio_get_device(u16 vid, u16 did, struct rio_dev *from)
> * @route_port: destination port for specified destID
> */
> int rio_std_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
> - u16 table, u16 route_destid, u8 route_port)
> -{
> + u16 table, u16 route_destid, u8 route_port) {
> + int rc = 0;
> if (table == RIO_GLOBAL_TABLE) {
> - rio_mport_write_config_32(mport, destid, hopcount,
> - RIO_STD_RTE_CONF_DESTID_SEL_CSR,
> - (u32)route_destid);
> - rio_mport_write_config_32(mport, destid, hopcount,
> - RIO_STD_RTE_CONF_PORT_SEL_CSR,
> - (u32)route_port);
> + rc = rio_mport_write_config_32(mport, destid, hopcount,
> + RIO_STD_RTE_CONF_DESTID_SEL_CSR, (u32) route_destid);
> + if (rc)
> + goto done;
> + rc = rio_mport_write_config_32(mport, destid, hopcount,
> + RIO_STD_RTE_CONF_PORT_SEL_CSR, (u32) route_port);
> + if (rc)
> + goto done;
> }
>
> udelay(10);
> - return 0;
> +done:
> + return rc;
> }
>
> /**
> @@ -1054,21 +1644,27 @@ int rio_std_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
> * @route_destid: destID entry in the RT
> * @route_port: returned destination port for specified destID
> */
> -int rio_std_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
> - u16 table, u16 route_destid, u8 *route_port)
> +int
> +rio_std_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
> + u16 table, u16 route_destid, u8 *route_port)
> {
> - u32 result;
> + u32 result = 0;
> + int rc = 0;
>
> if (table == RIO_GLOBAL_TABLE) {
> - rio_mport_write_config_32(mport, destid, hopcount,
> + rc = rio_mport_write_config_32(mport, destid, hopcount,
> RIO_STD_RTE_CONF_DESTID_SEL_CSR, route_destid);
> - rio_mport_read_config_32(mport, destid, hopcount,
> + if (rc)
> + goto done;
> + rc = rio_mport_read_config_32(mport, destid, hopcount,
> RIO_STD_RTE_CONF_PORT_SEL_CSR, &result);
> + if (rc)
> + goto done;
>
> - *route_port = (u8)result;
> + *route_port = (u8) result;
> }
> -
> - return 0;
> +done:
> + return rc;
> }
>
> /**
> @@ -1079,46 +1675,53 @@ int rio_std_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
> * @hopcount: Number of switch hops to the device
> * @table: routing table ID (global or port-specific)
> */
> -int rio_std_route_clr_table(struct rio_mport *mport, u16 destid, u8 hopcount,
> - u16 table)
> +int
> +rio_std_route_clr_table(struct rio_mport *mport, u16 destid,
> + u8 hopcount, u16 table)
> {
> u32 max_destid = 0xff;
> u32 i, pef, id_inc = 1, ext_cfg = 0;
> u32 port_sel = RIO_INVALID_ROUTE;
> + int rc = 0;
>
> if (table == RIO_GLOBAL_TABLE) {
> - rio_mport_read_config_32(mport, destid, hopcount,
> - RIO_PEF_CAR, &pef);
> + rc = rio_mport_read_config_32(mport, destid, hopcount,
> + RIO_PEF_CAR, &pef);
> + if (rc)
> + goto done;
>
> if (mport->sys_size) {
> - rio_mport_read_config_32(mport, destid, hopcount,
> - RIO_SWITCH_RT_LIMIT,
> - &max_destid);
> + rc = rio_mport_read_config_32(mport, destid, hopcount,
> + RIO_SWITCH_RT_LIMIT, &max_destid);
> + if (rc)
> + goto done;
> max_destid &= RIO_RT_MAX_DESTID;
> }
>
> if (pef & RIO_PEF_EXT_RT) {
> ext_cfg = 0x80000000;
> id_inc = 4;
> - port_sel = (RIO_INVALID_ROUTE << 24) |
> - (RIO_INVALID_ROUTE << 16) |
> - (RIO_INVALID_ROUTE << 8) |
> - RIO_INVALID_ROUTE;
> + port_sel = (RIO_INVALID_ROUTE << 24) | (RIO_INVALID_ROUTE << 16)
> + | (RIO_INVALID_ROUTE << 8) |
> + RIO_INVALID_ROUTE;
> }
>
> for (i = 0; i <= max_destid;) {
> - rio_mport_write_config_32(mport, destid, hopcount,
> - RIO_STD_RTE_CONF_DESTID_SEL_CSR,
> - ext_cfg | i);
> - rio_mport_write_config_32(mport, destid, hopcount,
> - RIO_STD_RTE_CONF_PORT_SEL_CSR,
> - port_sel);
> + rc = rio_mport_write_config_32(mport, destid, hopcount,
> + RIO_STD_RTE_CONF_DESTID_SEL_CSR, ext_cfg | i);
> + if (rc)
> + goto done;
> + rc = rio_mport_write_config_32(mport, destid, hopcount,
> + RIO_STD_RTE_CONF_PORT_SEL_CSR, port_sel);
> + if (rc)
> + goto done;
> i += id_inc;
> }
> }
>
> +done:
> udelay(10);
> - return 0;
> + return rc;
> }
>
> static void rio_fixup_device(struct rio_dev *dev)
> @@ -1129,21 +1732,20 @@ static int __devinit rio_init(void)
> {
> struct rio_dev *dev = NULL;
>
> - while ((dev = rio_get_device(RIO_ANY_ID, RIO_ANY_ID, dev)) != NULL) {
> + while ((dev = rio_get_device(RIO_ANY_ID, RIO_ANY_ID, dev)) != NULL)
> rio_fixup_device(dev);
> - }
> return 0;
> }
> -
> +/**
> + * @note No lock; Assuming this is used at boot time only,
> + * before start of user space
> + */
> int __devinit rio_init_mports(void)
> {
> struct rio_mport *port;
>
> list_for_each_entry(port, &rio_mports, node) {
> - if (port->host_deviceid >= 0)
> - rio_enum_mport(port);
> - else
> - rio_disc_mport(port);
> + rio_job_init(port, NULL, -1, 0, 1, RIO_DEVICE_INSERTION);
> }
>
> rio_init();
> @@ -1171,27 +1773,75 @@ static int rio_hdid_setup(char *str)
>
> __setup("riohdid=", rio_hdid_setup);
>
> +#if defined(CONFIG_RAPIDIO_STATIC_DESTID) || defined(CONFIG_RAPIDIO_HOTPLUG)
> +
> +static void rio_add_mport_device(struct rio_mport *mport)
> +{
> + dev_set_name(&mport->dev, "mport:%04x", mport->id);
> + mport->dev.bus = NULL;
> + mport->dev.parent = &rio_bus;
> +
> + if (device_register(&mport->dev))
> + pr_warn("RIO: mport device register failure\n");
> + else {
> + rio_destid_sysfs_init(mport);
> + rio_sysfs_init(mport);
> + }
> +}
> +#else
> +static inline void rio_add_mport_device(struct rio_mport *port) {}
> +#endif
> +
> +struct rio_net *rio_get_mport_net(struct rio_mport *port)
> +{
> + return &port->net;
> +}
> +
> +struct rio_mport *rio_get_mport(int hostid, struct rio_mport *from)
> +{
> + struct rio_mport *port;
> + struct list_head *n;
> +
> + if (list_empty(&rio_mports))
> + return NULL;
> +
> + n = from ? from->node.next : rio_mports.next;
> + while (n && (n != &rio_mports)) {
> + port = list_entry(n, struct rio_mport, node);
> + if (hostid == RIO_ANY_ID || hostid == port->host_deviceid)
> + return port;
> + n = n->next;
> + }
> + return NULL;
> +}
> +EXPORT_SYMBOL_GPL(rio_get_mport);
> +
> +
> int rio_register_mport(struct rio_mport *port)
> {
> if (next_portid >= RIO_MAX_MPORTS) {
> pr_err("RIO: reached specified max number of mports\n");
> return 1;
> }
> -
> port->id = next_portid++;
> port->host_deviceid = rio_get_hdid(port->id);
> +#ifndef CONFIG_RAPIDIO_STATIC_DESTID
> + if (port->host_deviceid == 0xb)
> + port->host_deviceid = RIO_ANY_ID;
> +#endif
> +
> +#ifdef NEW_STYLE
> + INIT_RADIX_TREE(&port->net.dev_tree, GFP_KERNEL);
> + INIT_RADIX_TREE(&port->net.dst_tree, GFP_KERNEL);
> + atomic_set(&port->net.rio_dev_num, 0);
> + atomic_set(&port->net.rio_dst_num, 0);
> + atomic_set(&port->net.rio_max_dest, 0);
> + spin_lock_init(&port->net.tree_lock);
> +#else
> + INIT_LIST_HEAD(&port->net.devices);
> +#endif
> + rio_add_mport_device(port);
> list_add_tail(&port->node, &rio_mports);
> return 0;
> }
> -
> -EXPORT_SYMBOL_GPL(rio_local_get_device_id);
> -EXPORT_SYMBOL_GPL(rio_get_device);
> -EXPORT_SYMBOL_GPL(rio_get_asm);
> -EXPORT_SYMBOL_GPL(rio_request_inb_dbell);
> -EXPORT_SYMBOL_GPL(rio_release_inb_dbell);
> -EXPORT_SYMBOL_GPL(rio_request_outb_dbell);
> -EXPORT_SYMBOL_GPL(rio_release_outb_dbell);
> -EXPORT_SYMBOL_GPL(rio_request_inb_mbox);
> -EXPORT_SYMBOL_GPL(rio_release_inb_mbox);
> -EXPORT_SYMBOL_GPL(rio_request_outb_mbox);
> -EXPORT_SYMBOL_GPL(rio_release_outb_mbox);
> +EXPORT_SYMBOL_GPL(rio_register_mport);
> diff --git a/drivers/rapidio/rio.h b/drivers/rapidio/rio.h
> index b1af414..6dceaa6 100644
> --- a/drivers/rapidio/rio.h
> +++ b/drivers/rapidio/rio.h
> @@ -11,24 +11,46 @@
> */
>
> #include <linux/device.h>
> +#include <linux/export.h>
> +#include <linux/rwsem.h>
> #include <linux/list.h>
> #include <linux/rio.h>
>
> +#include "rio-hotplug.h"
> +#include "rio-multicast.h"
> +#include "rio-destid.h"
> +#include "rio-job.h"
> +#include "rio-locks.h"
> +#include "rio-net.h"
> +#include "rio-route.h"
> +
> #define RIO_MAX_CHK_RETRY 3
>
> +#define RIO_PORT_UNUSED 0
> +#define RIO_REDUNDANT_PATH 1
> +#define RIO_END_POINT 2
> +#define RIO_SWITCH 3
> +
> /* Functions internal to the RIO core code */
> +extern struct rio_dev **rio_get_tagged_devices(struct rio_mport *mport,
> + int tag, int *n);
>
> -extern u32 rio_mport_get_feature(struct rio_mport *mport, int local, u16 destid,
> - u8 hopcount, int ftr);
> -extern u32 rio_mport_get_physefb(struct rio_mport *port, int local,
> - u16 destid, u8 hopcount);
> -extern u32 rio_mport_get_efb(struct rio_mport *port, int local, u16 destid,
> - u8 hopcount, u32 from);
> +extern int rio_type_of_next(struct rio_dev *sw_curr, struct rio_dev *sw_next);
> +extern int rio_is_switch(struct rio_dev *rdev);
> +extern int rio_get_err_and_status(struct rio_dev *rdev,
> + int portnum, u32 *err_status);
> +extern int rio_mport_get_feature(struct rio_mport *port,
> + int local, u16 destid,
> + u8 hopcount, int ftr, u32 *feature);
> +extern int rio_mport_get_physefb(struct rio_mport *port, int local,
> + u16 destid, u8 hopcount, u32 *physefb);
> +extern int rio_mport_get_efb(struct rio_mport *port, int local, u16 destid,
> + u8 hopcount, u32 from, u32 *ext_ftr_ptr);
> extern int rio_mport_chk_dev_access(struct rio_mport *mport, u16 destid,
> u8 hopcount);
> extern int rio_create_sysfs_dev_files(struct rio_dev *rdev);
> -extern int rio_enum_mport(struct rio_mport *mport);
> -extern int rio_disc_mport(struct rio_mport *mport);
> +extern void rio_remove_sysfs_dev_files(struct rio_dev *rdev);
> +extern int rio_sysfs_init(struct rio_mport *mport);
> extern int rio_std_route_add_entry(struct rio_mport *mport, u16 destid,
> u8 hopcount, u16 table, u16 route_destid,
> u8 route_port);
> @@ -37,16 +59,27 @@ extern int rio_std_route_get_entry(struct rio_mport *mport, u16 destid,
> u8 *route_port);
> extern int rio_std_route_clr_table(struct rio_mport *mport, u16 destid,
> u8 hopcount, u16 table);
> -extern int rio_set_port_lockout(struct rio_dev *rdev, u32 pnum, int lock);
> -extern struct rio_dev *rio_get_comptag(u32 comp_tag, struct rio_dev *from);
> +extern struct rio_dev *rio_get_comptag(struct rio_mport *mport, u32 comp_tag);
> +extern int rio_clr_err_stopped(struct rio_dev *rdev, u32 pnum,
> + u32 err_status, int *success);
> +extern struct rio_net *rio_get_mport_net(struct rio_mport *port);
> +/* extern int rio_setup_event(struct rio_dev *rdev, int portnum, int event);*/
>
> /* Structures internal to the RIO core code */
> +extern struct list_head rio_switches;
> +extern struct list_head rio_mports;
> extern struct device_attribute rio_dev_attrs[];
> extern spinlock_t rio_global_list_lock;
>
> extern struct rio_switch_ops __start_rio_switch_ops[];
> extern struct rio_switch_ops __end_rio_switch_ops[];
>
> +extern struct rio_dev_fixup __start_rio_dev_fixup_early[];
> +extern struct rio_dev_fixup __end_rio_dev_fixup_early[];
> +extern struct rio_dev_fixup __start_rio_dev_fixup_enable[];
> +extern struct rio_dev_fixup __end_rio_dev_fixup_enable[];
> +
> +
> /* Helpers internal to the RIO core code */
> #define DECLARE_RIO_SWITCH_SECTION(section, name, vid, did, init_hook) \
> static const struct rio_switch_ops __rio_switch_##name __used \
> @@ -68,5 +101,7 @@ extern struct rio_switch_ops __end_rio_switch_ops[];
> DECLARE_RIO_SWITCH_SECTION(.rio_switch_ops, vid##did, \
> vid, did, init_hook)
>
> -#define RIO_GET_DID(size, x) (size ? (x & 0xffff) : ((x & 0x00ff0000) >> 16))
> -#define RIO_SET_DID(size, x) (size ? (x & 0xffff) : ((x & 0x000000ff) << 16))
> +#define RIO_GET_DID(size, x) (size ? (x & 0xffff) : \
> + ((x & 0x00ff0000) >> 16))
> +#define RIO_SET_DID(size, x) (size ? (x & 0xffff) : \
> + ((x & 0x000000ff) << 16))
>
More information about the linux-yocto
mailing list