aboutsummaryrefslogtreecommitdiff
path: root/drivers/rapidio
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/rapidio')
-rw-r--r--drivers/rapidio/Kconfig5
-rw-r--r--drivers/rapidio/Makefile4
-rw-r--r--drivers/rapidio/devices/Kconfig2
-rw-r--r--drivers/rapidio/devices/Makefile7
-rw-r--r--drivers/rapidio/devices/tsi721.c9
-rw-r--r--drivers/rapidio/rio-driver.c18
-rw-r--r--drivers/rapidio/rio-scan.c181
-rw-r--r--drivers/rapidio/rio-sysfs.c31
-rw-r--r--drivers/rapidio/rio.c490
-rw-r--r--drivers/rapidio/rio.h44
-rw-r--r--drivers/rapidio/switches/Kconfig19
-rw-r--r--drivers/rapidio/switches/Makefile1
-rw-r--r--drivers/rapidio/switches/idt_gen2.c98
-rw-r--r--drivers/rapidio/switches/idtcps.c86
-rw-r--r--drivers/rapidio/switches/tsi500.c78
-rw-r--r--drivers/rapidio/switches/tsi568.c71
-rw-r--r--drivers/rapidio/switches/tsi57x.c81
17 files changed, 751 insertions, 474 deletions
diff --git a/drivers/rapidio/Kconfig b/drivers/rapidio/Kconfig
index 5ab056494bbe..3e3be57e9a1a 100644
--- a/drivers/rapidio/Kconfig
+++ b/drivers/rapidio/Kconfig
@@ -67,4 +67,9 @@ config RAPIDIO_ENUM_BASIC
endchoice
+menu "RapidIO Switch drivers"
+ depends on RAPIDIO
+
source "drivers/rapidio/switches/Kconfig"
+
+endmenu
diff --git a/drivers/rapidio/Makefile b/drivers/rapidio/Makefile
index 3036702ffe8b..6271ada6993f 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-sysfs.o
+obj-$(CONFIG_RAPIDIO) += rapidio.o
+rapidio-y := rio.o rio-access.o rio-driver.o rio-sysfs.o
+
obj-$(CONFIG_RAPIDIO_ENUM_BASIC) += rio-scan.o
obj-$(CONFIG_RAPIDIO) += switches/
diff --git a/drivers/rapidio/devices/Kconfig b/drivers/rapidio/devices/Kconfig
index 12a9d7f7040b..c4cb0877592b 100644
--- a/drivers/rapidio/devices/Kconfig
+++ b/drivers/rapidio/devices/Kconfig
@@ -3,7 +3,7 @@
#
config RAPIDIO_TSI721
- bool "IDT Tsi721 PCI Express SRIO Controller support"
+ tristate "IDT Tsi721 PCI Express SRIO Controller support"
depends on RAPIDIO && PCIEPORTBUS
default "n"
---help---
diff --git a/drivers/rapidio/devices/Makefile b/drivers/rapidio/devices/Makefile
index 7b62860f34f8..9432c494cf57 100644
--- a/drivers/rapidio/devices/Makefile
+++ b/drivers/rapidio/devices/Makefile
@@ -2,7 +2,6 @@
# Makefile for RapidIO devices
#
-obj-$(CONFIG_RAPIDIO_TSI721) += tsi721.o
-ifeq ($(CONFIG_RAPIDIO_DMA_ENGINE),y)
-obj-$(CONFIG_RAPIDIO_TSI721) += tsi721_dma.o
-endif
+obj-$(CONFIG_RAPIDIO_TSI721) += tsi721_mport.o
+tsi721_mport-y := tsi721.o
+tsi721_mport-$(CONFIG_RAPIDIO_DMA_ENGINE) += tsi721_dma.o
diff --git a/drivers/rapidio/devices/tsi721.c b/drivers/rapidio/devices/tsi721.c
index a8b2c23a7ef4..ff7cbf2d28e3 100644
--- a/drivers/rapidio/devices/tsi721.c
+++ b/drivers/rapidio/devices/tsi721.c
@@ -2515,9 +2515,8 @@ static int __init tsi721_init(void)
return pci_register_driver(&tsi721_driver);
}
-static void __exit tsi721_exit(void)
-{
- pci_unregister_driver(&tsi721_driver);
-}
-
device_initcall(tsi721_init);
+
+MODULE_DESCRIPTION("IDT Tsi721 PCIExpress-to-SRIO bridge driver");
+MODULE_AUTHOR("Integrated Device Technology, Inc.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rapidio/rio-driver.c b/drivers/rapidio/rio-driver.c
index a0c875563d76..3e9b6a78ad18 100644
--- a/drivers/rapidio/rio-driver.c
+++ b/drivers/rapidio/rio-driver.c
@@ -199,6 +199,23 @@ static int rio_match_bus(struct device *dev, struct device_driver *drv)
out:return 0;
}
+static int rio_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+ struct rio_dev *rdev;
+
+ if (!dev)
+ return -ENODEV;
+
+ rdev = to_rio_dev(dev);
+ if (!rdev)
+ return -ENODEV;
+
+ if (add_uevent_var(env, "MODALIAS=rapidio:v%04Xd%04Xav%04Xad%04X",
+ rdev->vid, rdev->did, rdev->asm_vid, rdev->asm_did))
+ return -ENOMEM;
+ return 0;
+}
+
struct device rio_bus = {
.init_name = "rapidio",
};
@@ -210,6 +227,7 @@ struct bus_type rio_bus_type = {
.bus_attrs = rio_bus_attrs,
.probe = rio_device_probe,
.remove = rio_device_remove,
+ .uevent = rio_uevent,
};
/**
diff --git a/drivers/rapidio/rio-scan.c b/drivers/rapidio/rio-scan.c
index 4c15dbf81087..d3a6539a77cc 100644
--- a/drivers/rapidio/rio-scan.c
+++ b/drivers/rapidio/rio-scan.c
@@ -406,6 +406,7 @@ static struct rio_dev *rio_setup_device(struct rio_net *net,
rio_mport_write_config_32(port, destid, hopcount,
RIO_COMPONENT_TAG_CSR, next_comptag);
rdev->comp_tag = next_comptag++;
+ rdev->do_enum = true;
} else {
rio_mport_read_config_32(port, destid, hopcount,
RIO_COMPONENT_TAG_CSR,
@@ -432,8 +433,8 @@ static struct rio_dev *rio_setup_device(struct rio_net *net,
/* If a PE has both switch and other functions, show it as a switch */
if (rio_is_switch(rdev)) {
rswitch = rdev->rswitch;
- rswitch->switchid = rdev->comp_tag & RIO_CTAG_UDEVID;
rswitch->port_ok = 0;
+ spin_lock_init(&rswitch->lock);
rswitch->route_table = kzalloc(sizeof(u8)*
RIO_MAX_ROUTE_ENTRIES(port->sys_size),
GFP_KERNEL);
@@ -444,12 +445,10 @@ static struct rio_dev *rio_setup_device(struct rio_net *net,
rdid++)
rswitch->route_table[rdid] = RIO_INVALID_ROUTE;
dev_set_name(&rdev->dev, "%02x:s:%04x", rdev->net->id,
- rswitch->switchid);
- rio_switch_init(rdev, do_enum);
+ rdev->comp_tag & RIO_CTAG_UDEVID);
- if (do_enum && rswitch->clr_table)
- rswitch->clr_table(port, destid, hopcount,
- RIO_GLOBAL_TABLE);
+ if (do_enum)
+ rio_route_clr_table(rdev, RIO_GLOBAL_TABLE, 0);
list_add_tail(&rswitch->node, &net->switches);
@@ -459,7 +458,7 @@ static struct rio_dev *rio_setup_device(struct rio_net *net,
rio_enable_rx_tx_port(port, 0, destid, hopcount, 0);
dev_set_name(&rdev->dev, "%02x:e:%04x", rdev->net->id,
- rdev->destid);
+ rdev->comp_tag & RIO_CTAG_UDEVID);
}
rio_attach_device(rdev);
@@ -533,156 +532,6 @@ rio_sport_is_active(struct rio_mport *port, u16 destid, u8 hopcount, int sport)
}
/**
- * rio_lock_device - Acquires host device lock for specified device
- * @port: Master port to send transaction
- * @destid: Destination ID for device/switch
- * @hopcount: Hopcount to reach switch
- * @wait_ms: Max wait time in msec (0 = no timeout)
- *
- * Attepts to acquire host device lock for specified device
- * Returns 0 if device lock acquired or EINVAL if timeout expires.
- */
-static int
-rio_lock_device(struct rio_mport *port, u16 destid, u8 hopcount, int wait_ms)
-{
- u32 result;
- int tcnt = 0;
-
- /* Attempt to acquire device lock */
- rio_mport_write_config_32(port, destid, hopcount,
- RIO_HOST_DID_LOCK_CSR, port->host_deviceid);
- rio_mport_read_config_32(port, destid, hopcount,
- RIO_HOST_DID_LOCK_CSR, &result);
-
- while (result != port->host_deviceid) {
- if (wait_ms != 0 && tcnt == wait_ms) {
- pr_debug("RIO: timeout when locking device %x:%x\n",
- destid, hopcount);
- return -EINVAL;
- }
-
- /* Delay a bit */
- mdelay(1);
- tcnt++;
- /* Try to acquire device lock again */
- rio_mport_write_config_32(port, destid,
- hopcount,
- RIO_HOST_DID_LOCK_CSR,
- port->host_deviceid);
- rio_mport_read_config_32(port, destid,
- hopcount,
- RIO_HOST_DID_LOCK_CSR, &result);
- }
-
- return 0;
-}
-
-/**
- * rio_unlock_device - Releases host device lock for specified device
- * @port: Master port to send transaction
- * @destid: Destination ID for device/switch
- * @hopcount: Hopcount to reach switch
- *
- * Returns 0 if device lock released or EINVAL if fails.
- */
-static int
-rio_unlock_device(struct rio_mport *port, u16 destid, u8 hopcount)
-{
- u32 result;
-
- /* Release device lock */
- rio_mport_write_config_32(port, destid,
- hopcount,
- RIO_HOST_DID_LOCK_CSR,
- port->host_deviceid);
- rio_mport_read_config_32(port, destid, hopcount,
- RIO_HOST_DID_LOCK_CSR, &result);
- if ((result & 0xffff) != 0xffff) {
- pr_debug("RIO: badness when releasing device lock %x:%x\n",
- destid, hopcount);
- return -EINVAL;
- }
-
- return 0;
-}
-
-/**
- * rio_route_add_entry- Add a route entry to a switch routing table
- * @rdev: RIO device
- * @table: Routing table ID
- * @route_destid: Destination ID to be routed
- * @route_port: Port number to be routed
- * @lock: lock switch device flag
- *
- * Calls the switch specific add_entry() method to add a route entry
- * on a switch. The route table can be specified using the @table
- * argument if a switch has per port routing tables or the normal
- * use is to specific all tables (or the global table) by passing
- * %RIO_GLOBAL_TABLE in @table. Returns %0 on success or %-EINVAL
- * on failure.
- */
-static int
-rio_route_add_entry(struct rio_dev *rdev,
- u16 table, u16 route_destid, u8 route_port, int lock)
-{
- int rc;
-
- if (lock) {
- rc = rio_lock_device(rdev->net->hport, rdev->destid,
- rdev->hopcount, 1000);
- if (rc)
- return rc;
- }
-
- rc = rdev->rswitch->add_entry(rdev->net->hport, rdev->destid,
- rdev->hopcount, table,
- route_destid, route_port);
- if (lock)
- rio_unlock_device(rdev->net->hport, rdev->destid,
- rdev->hopcount);
-
- return rc;
-}
-
-/**
- * rio_route_get_entry- Read a route entry in a switch routing table
- * @rdev: RIO device
- * @table: Routing table ID
- * @route_destid: Destination ID to be routed
- * @route_port: Pointer to read port number into
- * @lock: lock switch device flag
- *
- * Calls the switch specific get_entry() method to read a route entry
- * in a switch. The route table can be specified using the @table
- * argument if a switch has per port routing tables or the normal
- * use is to specific all tables (or the global table) by passing
- * %RIO_GLOBAL_TABLE in @table. Returns %0 on success or %-EINVAL
- * on failure.
- */
-static int
-rio_route_get_entry(struct rio_dev *rdev, u16 table,
- u16 route_destid, u8 *route_port, int lock)
-{
- int rc;
-
- if (lock) {
- rc = rio_lock_device(rdev->net->hport, rdev->destid,
- rdev->hopcount, 1000);
- if (rc)
- return rc;
- }
-
- rc = rdev->rswitch->get_entry(rdev->net->hport, rdev->destid,
- rdev->hopcount, table,
- route_destid, route_port);
- if (lock)
- rio_unlock_device(rdev->net->hport, rdev->destid,
- rdev->hopcount);
-
- return rc;
-}
-
-/**
* rio_get_host_deviceid_lock- Reads the Host Device ID Lock CSR on a device
* @port: Master port to send transaction
* @hopcount: Number of hops to the device
@@ -1094,12 +943,9 @@ static void rio_update_route_tables(struct rio_net *net)
sport = RIO_GET_PORT_NUM(swrdev->swpinfo);
- if (rswitch->add_entry) {
- rio_route_add_entry(swrdev,
- RIO_GLOBAL_TABLE, destid,
- sport, 0);
- rswitch->route_table[destid] = sport;
- }
+ rio_route_add_entry(swrdev, RIO_GLOBAL_TABLE,
+ destid, sport, 0);
+ rswitch->route_table[destid] = sport;
}
}
}
@@ -1115,8 +961,8 @@ static void rio_update_route_tables(struct rio_net *net)
static void rio_init_em(struct rio_dev *rdev)
{
if (rio_is_switch(rdev) && (rdev->em_efptr) &&
- (rdev->rswitch->em_init)) {
- rdev->rswitch->em_init(rdev);
+ rdev->rswitch->ops && rdev->rswitch->ops->em_init) {
+ rdev->rswitch->ops->em_init(rdev);
}
}
@@ -1141,7 +987,7 @@ static void rio_pw_enable(struct rio_mport *port, int enable)
* link, then start recursive peer enumeration. Returns %0 if
* enumeration succeeds or %-EBUSY if enumeration fails.
*/
-int rio_enum_mport(struct rio_mport *mport, u32 flags)
+static int rio_enum_mport(struct rio_mport *mport, u32 flags)
{
struct rio_net *net = NULL;
int rc = 0;
@@ -1256,7 +1102,7 @@ static void rio_build_route_tables(struct rio_net *net)
* peer discovery. Returns %0 if discovery succeeds or %-EBUSY
* on failure.
*/
-int rio_disc_mport(struct rio_mport *mport, u32 flags)
+static int rio_disc_mport(struct rio_mport *mport, u32 flags)
{
struct rio_net *net = NULL;
unsigned long to_end;
@@ -1315,6 +1161,7 @@ bail:
}
static struct rio_scan rio_scan_ops = {
+ .owner = THIS_MODULE,
.enumerate = rio_enum_mport,
.discover = rio_disc_mport,
};
diff --git a/drivers/rapidio/rio-sysfs.c b/drivers/rapidio/rio-sysfs.c
index 66d4acd5e18f..9331be646dc3 100644
--- a/drivers/rapidio/rio-sysfs.c
+++ b/drivers/rapidio/rio-sysfs.c
@@ -84,6 +84,15 @@ static ssize_t lnext_show(struct device *dev,
return str - buf;
}
+static ssize_t modalias_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct rio_dev *rdev = to_rio_dev(dev);
+
+ return sprintf(buf, "rapidio:v%04Xd%04Xav%04Xad%04X\n",
+ rdev->vid, rdev->did, rdev->asm_vid, rdev->asm_did);
+}
+
struct device_attribute rio_dev_attrs[] = {
__ATTR_RO(did),
__ATTR_RO(vid),
@@ -93,6 +102,7 @@ struct device_attribute rio_dev_attrs[] = {
__ATTR_RO(asm_rev),
__ATTR_RO(lprev),
__ATTR_RO(destid),
+ __ATTR_RO(modalias),
__ATTR_NULL,
};
@@ -257,8 +267,6 @@ 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);
- if (!err && rdev->rswitch->sw_sysfs)
- err = rdev->rswitch->sw_sysfs(rdev, RIO_SW_SYSFS_CREATE);
}
if (err)
@@ -281,8 +289,6 @@ 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);
}
}
@@ -290,7 +296,6 @@ static ssize_t bus_scan_store(struct bus_type *bus, const char *buf,
size_t count)
{
long val;
- struct rio_mport *port = NULL;
int rc;
if (kstrtol(buf, 0, &val) < 0)
@@ -304,21 +309,7 @@ static ssize_t bus_scan_store(struct bus_type *bus, const char *buf,
if (val < 0 || val >= RIO_MAX_MPORTS)
return -EINVAL;
- port = rio_find_mport((int)val);
-
- if (!port) {
- pr_debug("RIO: %s: mport_%d not available\n",
- __func__, (int)val);
- return -EINVAL;
- }
-
- if (!port->nscan)
- return -EINVAL;
-
- if (port->host_deviceid >= 0)
- rc = port->nscan->enumerate(port, 0);
- else
- rc = port->nscan->discover(port, RIO_SCAN_ENUM_NO_WAIT);
+ rc = rio_mport_scan((int)val);
exit:
if (!rc)
rc = count;
diff --git a/drivers/rapidio/rio.c b/drivers/rapidio/rio.c
index cb1c08996fbb..f4f30af2df68 100644
--- a/drivers/rapidio/rio.c
+++ b/drivers/rapidio/rio.c
@@ -5,9 +5,8 @@
* Copyright 2005 MontaVista Software, Inc.
* Matt Porter <mporter@kernel.crashing.org>
*
- * Copyright 2009 Integrated Device Technology, Inc.
+ * Copyright 2009 - 2013 Integrated Device Technology, Inc.
* Alex Bounine <alexandre.bounine@idt.com>
- * - Added Port-Write/Error Management initialization and handling
*
* 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
@@ -31,10 +30,22 @@
#include "rio.h"
+MODULE_DESCRIPTION("RapidIO Subsystem Core");
+MODULE_AUTHOR("Matt Porter <mporter@kernel.crashing.org>");
+MODULE_AUTHOR("Alexandre Bounine <alexandre.bounine@idt.com>");
+MODULE_LICENSE("GPL");
+
+static int hdid[RIO_MAX_MPORTS];
+static int ids_num;
+module_param_array(hdid, int, &ids_num, 0);
+MODULE_PARM_DESC(hdid,
+ "Destination ID assignment to local RapidIO controllers");
+
static LIST_HEAD(rio_devices);
static DEFINE_SPINLOCK(rio_global_list_lock);
static LIST_HEAD(rio_mports);
+static LIST_HEAD(rio_scans);
static DEFINE_MUTEX(rio_mport_list_lock);
static unsigned char next_portid;
static DEFINE_SPINLOCK(rio_mmap_lock);
@@ -580,44 +591,6 @@ int rio_set_port_lockout(struct rio_dev *rdev, u32 pnum, int lock)
EXPORT_SYMBOL_GPL(rio_set_port_lockout);
/**
- * rio_switch_init - Sets switch operations for a particular vendor switch
- * @rdev: RIO device
- * @do_enum: Enumeration/Discovery mode flag
- *
- * Searches the RIO switch ops table for known switch types. If the vid
- * and did match a switch table entry, then call switch initialization
- * routine to setup switch-specific routines.
- */
-void rio_switch_init(struct rio_dev *rdev, int do_enum)
-{
- struct rio_switch_ops *cur = __start_rio_switch_ops;
- struct rio_switch_ops *end = __end_rio_switch_ops;
-
- while (cur < end) {
- if ((cur->vid == rdev->vid) && (cur->did == rdev->did)) {
- pr_debug("RIO: calling init routine for %s\n",
- rio_name(rdev));
- cur->init_hook(rdev, do_enum);
- break;
- }
- cur++;
- }
-
- if ((cur >= end) && (rdev->pef & RIO_PEF_STD_RT)) {
- pr_debug("RIO: adding STD routing ops for %s\n",
- rio_name(rdev));
- rdev->rswitch->add_entry = rio_std_route_add_entry;
- rdev->rswitch->get_entry = rio_std_route_get_entry;
- rdev->rswitch->clr_table = rio_std_route_clr_table;
- }
-
- if (!rdev->rswitch->add_entry || !rdev->rswitch->get_entry)
- printk(KERN_ERR "RIO: missing routing ops for %s\n",
- rio_name(rdev));
-}
-EXPORT_SYMBOL_GPL(rio_switch_init);
-
-/**
* rio_enable_rx_tx_port - enable input receiver and output transmitter of
* given port
* @port: Master port associated with the RIO network
@@ -970,8 +943,8 @@ int rio_inb_pwrite_handler(union rio_pw_msg *pw_msg)
/*
* Process the port-write notification from switch
*/
- if (rdev->rswitch->em_handle)
- rdev->rswitch->em_handle(rdev, portnum);
+ if (rdev->rswitch->ops && rdev->rswitch->ops->em_handle)
+ rdev->rswitch->ops->em_handle(rdev, portnum);
rio_read_config_32(rdev,
rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(portnum),
@@ -1207,8 +1180,9 @@ struct rio_dev *rio_get_device(u16 vid, u16 did, struct rio_dev *from)
* @route_destid: destID entry in the RT
* @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)
+static int
+rio_std_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
+ u16 table, u16 route_destid, u8 route_port)
{
if (table == RIO_GLOBAL_TABLE) {
rio_mport_write_config_32(mport, destid, hopcount,
@@ -1234,8 +1208,9 @@ 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)
+static int
+rio_std_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
+ u16 table, u16 route_destid, u8 *route_port)
{
u32 result;
@@ -1259,8 +1234,9 @@ 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)
+static 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;
@@ -1301,6 +1277,234 @@ int rio_std_route_clr_table(struct rio_mport *mport, u16 destid, u8 hopcount,
return 0;
}
+/**
+ * rio_lock_device - Acquires host device lock for specified device
+ * @port: Master port to send transaction
+ * @destid: Destination ID for device/switch
+ * @hopcount: Hopcount to reach switch
+ * @wait_ms: Max wait time in msec (0 = no timeout)
+ *
+ * Attepts to acquire host device lock for specified device
+ * Returns 0 if device lock acquired or EINVAL if timeout expires.
+ */
+int rio_lock_device(struct rio_mport *port, u16 destid,
+ u8 hopcount, int wait_ms)
+{
+ u32 result;
+ int tcnt = 0;
+
+ /* Attempt to acquire device lock */
+ rio_mport_write_config_32(port, destid, hopcount,
+ RIO_HOST_DID_LOCK_CSR, port->host_deviceid);
+ rio_mport_read_config_32(port, destid, hopcount,
+ RIO_HOST_DID_LOCK_CSR, &result);
+
+ while (result != port->host_deviceid) {
+ if (wait_ms != 0 && tcnt == wait_ms) {
+ pr_debug("RIO: timeout when locking device %x:%x\n",
+ destid, hopcount);
+ return -EINVAL;
+ }
+
+ /* Delay a bit */
+ mdelay(1);
+ tcnt++;
+ /* Try to acquire device lock again */
+ rio_mport_write_config_32(port, destid,
+ hopcount,
+ RIO_HOST_DID_LOCK_CSR,
+ port->host_deviceid);
+ rio_mport_read_config_32(port, destid,
+ hopcount,
+ RIO_HOST_DID_LOCK_CSR, &result);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rio_lock_device);
+
+/**
+ * rio_unlock_device - Releases host device lock for specified device
+ * @port: Master port to send transaction
+ * @destid: Destination ID for device/switch
+ * @hopcount: Hopcount to reach switch
+ *
+ * Returns 0 if device lock released or EINVAL if fails.
+ */
+int rio_unlock_device(struct rio_mport *port, u16 destid, u8 hopcount)
+{
+ u32 result;
+
+ /* Release device lock */
+ rio_mport_write_config_32(port, destid,
+ hopcount,
+ RIO_HOST_DID_LOCK_CSR,
+ port->host_deviceid);
+ rio_mport_read_config_32(port, destid, hopcount,
+ RIO_HOST_DID_LOCK_CSR, &result);
+ if ((result & 0xffff) != 0xffff) {
+ pr_debug("RIO: badness when releasing device lock %x:%x\n",
+ destid, hopcount);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rio_unlock_device);
+
+/**
+ * rio_route_add_entry- Add a route entry to a switch routing table
+ * @rdev: RIO device
+ * @table: Routing table ID
+ * @route_destid: Destination ID to be routed
+ * @route_port: Port number to be routed
+ * @lock: apply a hardware lock on switch device flag (1=lock, 0=no_lock)
+ *
+ * If available calls the switch specific add_entry() method to add a route
+ * entry into a switch routing table. Otherwise uses standard RT update method
+ * as defined by RapidIO specification. A specific routing table can be selected
+ * using the @table argument if a switch has per port routing tables or
+ * the standard (or global) table may be used by passing
+ * %RIO_GLOBAL_TABLE in @table.
+ *
+ * Returns %0 on success or %-EINVAL on failure.
+ */
+int rio_route_add_entry(struct rio_dev *rdev,
+ u16 table, u16 route_destid, u8 route_port, int lock)
+{
+ int rc = -EINVAL;
+ struct rio_switch_ops *ops = rdev->rswitch->ops;
+
+ if (lock) {
+ rc = rio_lock_device(rdev->net->hport, rdev->destid,
+ rdev->hopcount, 1000);
+ if (rc)
+ return rc;
+ }
+
+ spin_lock(&rdev->rswitch->lock);
+
+ if (ops == NULL || ops->add_entry == NULL) {
+ rc = rio_std_route_add_entry(rdev->net->hport, rdev->destid,
+ rdev->hopcount, table,
+ route_destid, route_port);
+ } else if (try_module_get(ops->owner)) {
+ rc = ops->add_entry(rdev->net->hport, rdev->destid,
+ rdev->hopcount, table, route_destid,
+ route_port);
+ module_put(ops->owner);
+ }
+
+ spin_unlock(&rdev->rswitch->lock);
+
+ if (lock)
+ rio_unlock_device(rdev->net->hport, rdev->destid,
+ rdev->hopcount);
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(rio_route_add_entry);
+
+/**
+ * rio_route_get_entry- Read an entry from a switch routing table
+ * @rdev: RIO device
+ * @table: Routing table ID
+ * @route_destid: Destination ID to be routed
+ * @route_port: Pointer to read port number into
+ * @lock: apply a hardware lock on switch device flag (1=lock, 0=no_lock)
+ *
+ * If available calls the switch specific get_entry() method to fetch a route
+ * entry from a switch routing table. Otherwise uses standard RT read method
+ * as defined by RapidIO specification. A specific routing table can be selected
+ * using the @table argument if a switch has per port routing tables or
+ * the standard (or global) table may be used by passing
+ * %RIO_GLOBAL_TABLE in @table.
+ *
+ * Returns %0 on success or %-EINVAL on failure.
+ */
+int rio_route_get_entry(struct rio_dev *rdev, u16 table,
+ u16 route_destid, u8 *route_port, int lock)
+{
+ int rc = -EINVAL;
+ struct rio_switch_ops *ops = rdev->rswitch->ops;
+
+ if (lock) {
+ rc = rio_lock_device(rdev->net->hport, rdev->destid,
+ rdev->hopcount, 1000);
+ if (rc)
+ return rc;
+ }
+
+ spin_lock(&rdev->rswitch->lock);
+
+ if (ops == NULL || ops->get_entry == NULL) {
+ rc = rio_std_route_get_entry(rdev->net->hport, rdev->destid,
+ rdev->hopcount, table,
+ route_destid, route_port);
+ } else if (try_module_get(ops->owner)) {
+ rc = ops->get_entry(rdev->net->hport, rdev->destid,
+ rdev->hopcount, table, route_destid,
+ route_port);
+ module_put(ops->owner);
+ }
+
+ spin_unlock(&rdev->rswitch->lock);
+
+ if (lock)
+ rio_unlock_device(rdev->net->hport, rdev->destid,
+ rdev->hopcount);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(rio_route_get_entry);
+
+/**
+ * rio_route_clr_table - Clear a switch routing table
+ * @rdev: RIO device
+ * @table: Routing table ID
+ * @lock: apply a hardware lock on switch device flag (1=lock, 0=no_lock)
+ *
+ * If available calls the switch specific clr_table() method to clear a switch
+ * routing table. Otherwise uses standard RT write method as defined by RapidIO
+ * specification. A specific routing table can be selected using the @table
+ * argument if a switch has per port routing tables or the standard (or global)
+ * table may be used by passing %RIO_GLOBAL_TABLE in @table.
+ *
+ * Returns %0 on success or %-EINVAL on failure.
+ */
+int rio_route_clr_table(struct rio_dev *rdev, u16 table, int lock)
+{
+ int rc = -EINVAL;
+ struct rio_switch_ops *ops = rdev->rswitch->ops;
+
+ if (lock) {
+ rc = rio_lock_device(rdev->net->hport, rdev->destid,
+ rdev->hopcount, 1000);
+ if (rc)
+ return rc;
+ }
+
+ spin_lock(&rdev->rswitch->lock);
+
+ if (ops == NULL || ops->clr_table == NULL) {
+ rc = rio_std_route_clr_table(rdev->net->hport, rdev->destid,
+ rdev->hopcount, table);
+ } else if (try_module_get(ops->owner)) {
+ rc = ops->clr_table(rdev->net->hport, rdev->destid,
+ rdev->hopcount, table);
+
+ module_put(ops->owner);
+ }
+
+ spin_unlock(&rdev->rswitch->lock);
+
+ if (lock)
+ rio_unlock_device(rdev->net->hport, rdev->destid,
+ rdev->hopcount);
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(rio_route_clr_table);
+
#ifdef CONFIG_RAPIDIO_DMA_ENGINE
static bool rio_chan_filter(struct dma_chan *chan, void *arg)
@@ -1410,34 +1614,73 @@ found:
* rio_register_scan - enumeration/discovery method registration interface
* @mport_id: mport device ID for which fabric scan routine has to be set
* (RIO_MPORT_ANY = set for all available mports)
- * @scan_ops: enumeration/discovery control structure
+ * @scan_ops: enumeration/discovery operations structure
+ *
+ * Registers enumeration/discovery operations with RapidIO subsystem and
+ * attaches it to the specified mport device (or all available mports
+ * if RIO_MPORT_ANY is specified).
*
- * Assigns enumeration or discovery method to the specified mport device (or all
- * available mports if RIO_MPORT_ANY is specified).
* Returns error if the mport already has an enumerator attached to it.
- * In case of RIO_MPORT_ANY ignores ports with valid scan routines and returns
- * an error if was unable to find at least one available mport.
+ * In case of RIO_MPORT_ANY skips mports with valid scan routines (no error).
*/
int rio_register_scan(int mport_id, struct rio_scan *scan_ops)
{
struct rio_mport *port;
- int rc = -EBUSY;
+ struct rio_scan_node *scan;
+ int rc = 0;
- mutex_lock(&rio_mport_list_lock);
- list_for_each_entry(port, &rio_mports, node) {
- if (port->id == mport_id || mport_id == RIO_MPORT_ANY) {
- if (port->nscan && mport_id == RIO_MPORT_ANY)
- continue;
- else if (port->nscan)
- break;
+ pr_debug("RIO: %s for mport_id=%d\n", __func__, mport_id);
- port->nscan = scan_ops;
- rc = 0;
+ if ((mport_id != RIO_MPORT_ANY && mport_id >= RIO_MAX_MPORTS) ||
+ !scan_ops)
+ return -EINVAL;
- if (mport_id != RIO_MPORT_ANY)
- break;
+ mutex_lock(&rio_mport_list_lock);
+
+ /*
+ * Check if there is another enumerator already registered for
+ * the same mport ID (including RIO_MPORT_ANY). Multiple enumerators
+ * for the same mport ID are not supported.
+ */
+ list_for_each_entry(scan, &rio_scans, node) {
+ if (scan->mport_id == mport_id) {
+ rc = -EBUSY;
+ goto err_out;
}
}
+
+ /*
+ * Allocate and initialize new scan registration node.
+ */
+ scan = kzalloc(sizeof(*scan), GFP_KERNEL);
+ if (!scan) {
+ rc = -ENOMEM;
+ goto err_out;
+ }
+
+ scan->mport_id = mport_id;
+ scan->ops = scan_ops;
+
+ /*
+ * Traverse the list of registered mports to attach this new scan.
+ *
+ * The new scan with matching mport ID overrides any previously attached
+ * scan assuming that old scan (if any) is the default one (based on the
+ * enumerator registration check above).
+ * If the new scan is the global one, it will be attached only to mports
+ * that do not have their own individual operations already attached.
+ */
+ list_for_each_entry(port, &rio_mports, node) {
+ if (port->id == mport_id) {
+ port->nscan = scan_ops;
+ break;
+ } else if (mport_id == RIO_MPORT_ANY && !port->nscan)
+ port->nscan = scan_ops;
+ }
+
+ list_add_tail(&scan->node, &rio_scans);
+
+err_out:
mutex_unlock(&rio_mport_list_lock);
return rc;
@@ -1447,30 +1690,81 @@ EXPORT_SYMBOL_GPL(rio_register_scan);
/**
* rio_unregister_scan - removes enumeration/discovery method from mport
* @mport_id: mport device ID for which fabric scan routine has to be
- * unregistered (RIO_MPORT_ANY = set for all available mports)
+ * unregistered (RIO_MPORT_ANY = apply to all mports that use
+ * the specified scan_ops)
+ * @scan_ops: enumeration/discovery operations structure
*
* Removes enumeration or discovery method assigned to the specified mport
- * device (or all available mports if RIO_MPORT_ANY is specified).
+ * device. If RIO_MPORT_ANY is specified, removes the specified operations from
+ * all mports that have them attached.
*/
-int rio_unregister_scan(int mport_id)
+int rio_unregister_scan(int mport_id, struct rio_scan *scan_ops)
{
struct rio_mport *port;
+ struct rio_scan_node *scan;
+
+ pr_debug("RIO: %s for mport_id=%d\n", __func__, mport_id);
+
+ if (mport_id != RIO_MPORT_ANY && mport_id >= RIO_MAX_MPORTS)
+ return -EINVAL;
mutex_lock(&rio_mport_list_lock);
- list_for_each_entry(port, &rio_mports, node) {
- if (port->id == mport_id || mport_id == RIO_MPORT_ANY) {
- if (port->nscan)
- port->nscan = NULL;
- if (mport_id != RIO_MPORT_ANY)
- break;
+
+ list_for_each_entry(port, &rio_mports, node)
+ if (port->id == mport_id ||
+ (mport_id == RIO_MPORT_ANY && port->nscan == scan_ops))
+ port->nscan = NULL;
+
+ list_for_each_entry(scan, &rio_scans, node)
+ if (scan->mport_id == mport_id) {
+ list_del(&scan->node);
+ kfree(scan);
}
- }
+
mutex_unlock(&rio_mport_list_lock);
return 0;
}
EXPORT_SYMBOL_GPL(rio_unregister_scan);
+/**
+ * rio_mport_scan - execute enumeration/discovery on the specified mport
+ * @mport_id: number (ID) of mport device
+ */
+int rio_mport_scan(int mport_id)
+{
+ struct rio_mport *port = NULL;
+ int rc;
+
+ mutex_lock(&rio_mport_list_lock);
+ list_for_each_entry(port, &rio_mports, node) {
+ if (port->id == mport_id)
+ goto found;
+ }
+ mutex_unlock(&rio_mport_list_lock);
+ return -ENODEV;
+found:
+ if (!port->nscan) {
+ mutex_unlock(&rio_mport_list_lock);
+ return -EINVAL;
+ }
+
+ if (!try_module_get(port->nscan->owner)) {
+ mutex_unlock(&rio_mport_list_lock);
+ return -ENODEV;
+ }
+
+ mutex_unlock(&rio_mport_list_lock);
+
+ if (port->host_deviceid >= 0)
+ rc = port->nscan->enumerate(port, 0);
+ else
+ rc = port->nscan->discover(port, RIO_SCAN_ENUM_NO_WAIT);
+
+ module_put(port->nscan->owner);
+ return rc;
+}
+
static void rio_fixup_device(struct rio_dev *dev)
{
}
@@ -1499,7 +1793,10 @@ static void disc_work_handler(struct work_struct *_work)
work = container_of(_work, struct rio_disc_work, work);
pr_debug("RIO: discovery work for mport %d %s\n",
work->mport->id, work->mport->name);
- work->mport->nscan->discover(work->mport, 0);
+ if (try_module_get(work->mport->nscan->owner)) {
+ work->mport->nscan->discover(work->mport, 0);
+ module_put(work->mport->nscan->owner);
+ }
}
int rio_init_mports(void)
@@ -1518,8 +1815,10 @@ int rio_init_mports(void)
mutex_lock(&rio_mport_list_lock);
list_for_each_entry(port, &rio_mports, node) {
if (port->host_deviceid >= 0) {
- if (port->nscan)
+ if (port->nscan && try_module_get(port->nscan->owner)) {
port->nscan->enumerate(port, 0);
+ module_put(port->nscan->owner);
+ }
} else
n++;
}
@@ -1533,7 +1832,7 @@ int rio_init_mports(void)
* for each of them. If the code below fails to allocate needed
* resources, exit without error to keep results of enumeration
* process (if any).
- * TODO: Implement restart of dicovery process for all or
+ * TODO: Implement restart of discovery process for all or
* individual discovering mports.
*/
rio_wq = alloc_workqueue("riodisc", 0, 0);
@@ -1559,9 +1858,9 @@ int rio_init_mports(void)
n++;
}
}
- mutex_unlock(&rio_mport_list_lock);
flush_workqueue(rio_wq);
+ mutex_unlock(&rio_mport_list_lock);
pr_debug("RIO: destroy discovery workqueue\n");
destroy_workqueue(rio_wq);
kfree(work);
@@ -1572,26 +1871,18 @@ no_disc:
return 0;
}
-static int hdids[RIO_MAX_MPORTS + 1];
-
static int rio_get_hdid(int index)
{
- if (!hdids[0] || hdids[0] <= index || index >= RIO_MAX_MPORTS)
+ if (ids_num == 0 || ids_num <= index || index >= RIO_MAX_MPORTS)
return -1;
- return hdids[index + 1];
-}
-
-static int rio_hdid_setup(char *str)
-{
- (void)get_options(str, ARRAY_SIZE(hdids), hdids);
- return 1;
+ return hdid[index];
}
-__setup("riohdid=", rio_hdid_setup);
-
int rio_register_mport(struct rio_mport *port)
{
+ struct rio_scan_node *scan = NULL;
+
if (next_portid >= RIO_MAX_MPORTS) {
pr_err("RIO: reached specified max number of mports\n");
return 1;
@@ -1600,11 +1891,28 @@ int rio_register_mport(struct rio_mport *port)
port->id = next_portid++;
port->host_deviceid = rio_get_hdid(port->id);
port->nscan = NULL;
+
mutex_lock(&rio_mport_list_lock);
list_add_tail(&port->node, &rio_mports);
+
+ /*
+ * Check if there are any registered enumeration/discovery operations
+ * that have to be attached to the added mport.
+ */
+ list_for_each_entry(scan, &rio_scans, node) {
+ if (port->id == scan->mport_id ||
+ scan->mport_id == RIO_MPORT_ANY) {
+ port->nscan = scan->ops;
+ if (port->id == scan->mport_id)
+ break;
+ }
+ }
mutex_unlock(&rio_mport_list_lock);
+
+ pr_debug("RIO: %s %s id=%d\n", __func__, port->name, port->id);
return 0;
}
+EXPORT_SYMBOL_GPL(rio_register_mport);
EXPORT_SYMBOL_GPL(rio_local_get_device_id);
EXPORT_SYMBOL_GPL(rio_get_device);
diff --git a/drivers/rapidio/rio.h b/drivers/rapidio/rio.h
index c14f864dea5c..085215cd8502 100644
--- a/drivers/rapidio/rio.h
+++ b/drivers/rapidio/rio.h
@@ -28,52 +28,28 @@ extern u32 rio_mport_get_efb(struct rio_mport *port, int local, u16 destid,
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_std_route_add_entry(struct rio_mport *mport, u16 destid,
- u8 hopcount, u16 table, u16 route_destid,
- u8 route_port);
-extern int rio_std_route_get_entry(struct rio_mport *mport, u16 destid,
- u8 hopcount, u16 table, u16 route_destid,
- u8 *route_port);
-extern int rio_std_route_clr_table(struct rio_mport *mport, u16 destid,
- u8 hopcount, u16 table);
+extern int rio_lock_device(struct rio_mport *port, u16 destid,
+ u8 hopcount, int wait_ms);
+extern int rio_unlock_device(struct rio_mport *port, u16 destid, u8 hopcount);
+extern int rio_route_add_entry(struct rio_dev *rdev,
+ u16 table, u16 route_destid, u8 route_port, int lock);
+extern int rio_route_get_entry(struct rio_dev *rdev, u16 table,
+ u16 route_destid, u8 *route_port, int lock);
+extern int rio_route_clr_table(struct rio_dev *rdev, u16 table, int lock);
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 int rio_add_device(struct rio_dev *rdev);
-extern void rio_switch_init(struct rio_dev *rdev, int do_enum);
extern int rio_enable_rx_tx_port(struct rio_mport *port, int local, u16 destid,
u8 hopcount, u8 port_num);
extern int rio_register_scan(int mport_id, struct rio_scan *scan_ops);
-extern int rio_unregister_scan(int mport_id);
+extern int rio_unregister_scan(int mport_id, struct rio_scan *scan_ops);
extern void rio_attach_device(struct rio_dev *rdev);
extern struct rio_mport *rio_find_mport(int mport_id);
+extern int rio_mport_scan(int mport_id);
/* Structures internal to the RIO core code */
extern struct device_attribute rio_dev_attrs[];
extern struct bus_attribute rio_bus_attrs[];
-extern struct rio_switch_ops __start_rio_switch_ops[];
-extern struct rio_switch_ops __end_rio_switch_ops[];
-
-/* 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 \
- __section(section) = { vid, did, init_hook };
-
-/**
- * DECLARE_RIO_SWITCH_INIT - Registers switch initialization routine
- * @vid: RIO vendor ID
- * @did: RIO device ID
- * @init_hook: Callback that performs switch-specific initialization
- *
- * Manipulating switch route tables and error management in RIO
- * is switch specific. This registers a switch by vendor and device ID with
- * initialization callback for setting up switch operations and (if required)
- * hardware initialization. A &struct rio_switch_ops is initialized with
- * pointer to the init routine and placed into a RIO-specific kernel section.
- */
-#define DECLARE_RIO_SWITCH_INIT(vid, did, init_hook) \
- 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))
diff --git a/drivers/rapidio/switches/Kconfig b/drivers/rapidio/switches/Kconfig
index f47fee5d4563..345841562f95 100644
--- a/drivers/rapidio/switches/Kconfig
+++ b/drivers/rapidio/switches/Kconfig
@@ -2,34 +2,23 @@
# RapidIO switches configuration
#
config RAPIDIO_TSI57X
- bool "IDT Tsi57x SRIO switches support"
- depends on RAPIDIO
+ tristate "IDT Tsi57x SRIO switches support"
---help---
Includes support for IDT Tsi57x family of serial RapidIO switches.
config RAPIDIO_CPS_XX
- bool "IDT CPS-xx SRIO switches support"
- depends on RAPIDIO
+ tristate "IDT CPS-xx SRIO switches support"
---help---
Includes support for IDT CPS-16/12/10/8 serial RapidIO switches.
config RAPIDIO_TSI568
- bool "Tsi568 SRIO switch support"
- depends on RAPIDIO
+ tristate "Tsi568 SRIO switch support"
default n
---help---
Includes support for IDT Tsi568 serial RapidIO switch.
config RAPIDIO_CPS_GEN2
- bool "IDT CPS Gen.2 SRIO switch support"
- depends on RAPIDIO
+ tristate "IDT CPS Gen.2 SRIO switch support"
default n
---help---
Includes support for ITD CPS Gen.2 serial RapidIO switches.
-
-config RAPIDIO_TSI500
- bool "Tsi500 Parallel RapidIO switch support"
- depends on RAPIDIO
- default n
- ---help---
- Includes support for IDT Tsi500 parallel RapidIO switch.
diff --git a/drivers/rapidio/switches/Makefile b/drivers/rapidio/switches/Makefile
index c4d3acc3c715..051cc6b38188 100644
--- a/drivers/rapidio/switches/Makefile
+++ b/drivers/rapidio/switches/Makefile
@@ -5,5 +5,4 @@
obj-$(CONFIG_RAPIDIO_TSI57X) += tsi57x.o
obj-$(CONFIG_RAPIDIO_CPS_XX) += idtcps.o
obj-$(CONFIG_RAPIDIO_TSI568) += tsi568.o
-obj-$(CONFIG_RAPIDIO_TSI500) += tsi500.o
obj-$(CONFIG_RAPIDIO_CPS_GEN2) += idt_gen2.o
diff --git a/drivers/rapidio/switches/idt_gen2.c b/drivers/rapidio/switches/idt_gen2.c
index 5d3b0f014d35..9f7fe21580bb 100644
--- a/drivers/rapidio/switches/idt_gen2.c
+++ b/drivers/rapidio/switches/idt_gen2.c
@@ -11,6 +11,7 @@
*/
#include <linux/stat.h>
+#include <linux/module.h>
#include <linux/rio.h>
#include <linux/rio_drv.h>
#include <linux/rio_ids.h>
@@ -389,12 +390,12 @@ idtg2_show_errlog(struct device *dev, struct device_attribute *attr, char *buf)
static DEVICE_ATTR(errlog, S_IRUGO, idtg2_show_errlog, NULL);
-static int idtg2_sysfs(struct rio_dev *rdev, int create)
+static int idtg2_sysfs(struct rio_dev *rdev, bool create)
{
struct device *dev = &rdev->dev;
int err = 0;
- if (create == RIO_SW_SYSFS_CREATE) {
+ if (create) {
/* Initialize sysfs entries */
err = device_create_file(dev, &dev_attr_errlog);
if (err)
@@ -405,29 +406,90 @@ static int idtg2_sysfs(struct rio_dev *rdev, int create)
return err;
}
-static int idtg2_switch_init(struct rio_dev *rdev, int do_enum)
+static struct rio_switch_ops idtg2_switch_ops = {
+ .owner = THIS_MODULE,
+ .add_entry = idtg2_route_add_entry,
+ .get_entry = idtg2_route_get_entry,
+ .clr_table = idtg2_route_clr_table,
+ .set_domain = idtg2_set_domain,
+ .get_domain = idtg2_get_domain,
+ .em_init = idtg2_em_init,
+ .em_handle = idtg2_em_handler,
+};
+
+static int idtg2_probe(struct rio_dev *rdev, const struct rio_device_id *id)
{
pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev));
- rdev->rswitch->add_entry = idtg2_route_add_entry;
- rdev->rswitch->get_entry = idtg2_route_get_entry;
- rdev->rswitch->clr_table = idtg2_route_clr_table;
- rdev->rswitch->set_domain = idtg2_set_domain;
- rdev->rswitch->get_domain = idtg2_get_domain;
- rdev->rswitch->em_init = idtg2_em_init;
- rdev->rswitch->em_handle = idtg2_em_handler;
- rdev->rswitch->sw_sysfs = idtg2_sysfs;
-
- if (do_enum) {
+
+ spin_lock(&rdev->rswitch->lock);
+
+ if (rdev->rswitch->ops) {
+ spin_unlock(&rdev->rswitch->lock);
+ return -EINVAL;
+ }
+
+ rdev->rswitch->ops = &idtg2_switch_ops;
+
+ if (rdev->do_enum) {
/* Ensure that default routing is disabled on startup */
rio_write_config_32(rdev,
RIO_STD_RTE_DEFAULT_PORT, IDT_NO_ROUTE);
}
+ /* Create device-specific sysfs attributes */
+ idtg2_sysfs(rdev, true);
+
+ spin_unlock(&rdev->rswitch->lock);
return 0;
}
-DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTCPS1848, idtg2_switch_init);
-DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTCPS1616, idtg2_switch_init);
-DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTVPS1616, idtg2_switch_init);
-DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTSPS1616, idtg2_switch_init);
-DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTCPS1432, idtg2_switch_init);
+static void idtg2_remove(struct rio_dev *rdev)
+{
+ pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev));
+ spin_lock(&rdev->rswitch->lock);
+ if (rdev->rswitch->ops != &idtg2_switch_ops) {
+ spin_unlock(&rdev->rswitch->lock);
+ return;
+ }
+ rdev->rswitch->ops = NULL;
+
+ /* Remove device-specific sysfs attributes */
+ idtg2_sysfs(rdev, false);
+
+ spin_unlock(&rdev->rswitch->lock);
+}
+
+static struct rio_device_id idtg2_id_table[] = {
+ {RIO_DEVICE(RIO_DID_IDTCPS1848, RIO_VID_IDT)},
+ {RIO_DEVICE(RIO_DID_IDTCPS1616, RIO_VID_IDT)},
+ {RIO_DEVICE(RIO_DID_IDTVPS1616, RIO_VID_IDT)},
+ {RIO_DEVICE(RIO_DID_IDTSPS1616, RIO_VID_IDT)},
+ {RIO_DEVICE(RIO_DID_IDTCPS1432, RIO_VID_IDT)},
+ { 0, } /* terminate list */
+};
+
+static struct rio_driver idtg2_driver = {
+ .name = "idt_gen2",
+ .id_table = idtg2_id_table,
+ .probe = idtg2_probe,
+ .remove = idtg2_remove,
+};
+
+static int __init idtg2_init(void)
+{
+ return rio_register_driver(&idtg2_driver);
+}
+
+static void __exit idtg2_exit(void)
+{
+ pr_debug("RIO: %s\n", __func__);
+ rio_unregister_driver(&idtg2_driver);
+ pr_debug("RIO: %s done\n", __func__);
+}
+
+device_initcall(idtg2_init);
+module_exit(idtg2_exit);
+
+MODULE_DESCRIPTION("IDT CPS Gen.2 Serial RapidIO switch family driver");
+MODULE_AUTHOR("Integrated Device Technology, Inc.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rapidio/switches/idtcps.c b/drivers/rapidio/switches/idtcps.c
index d06ee2d44b44..7fbb60d31796 100644
--- a/drivers/rapidio/switches/idtcps.c
+++ b/drivers/rapidio/switches/idtcps.c
@@ -13,6 +13,7 @@
#include <linux/rio.h>
#include <linux/rio_drv.h>
#include <linux/rio_ids.h>
+#include <linux/module.h>
#include "../rio.h"
#define CPS_DEFAULT_ROUTE 0xde
@@ -118,18 +119,31 @@ idtcps_get_domain(struct rio_mport *mport, u16 destid, u8 hopcount,
return 0;
}
-static int idtcps_switch_init(struct rio_dev *rdev, int do_enum)
+static struct rio_switch_ops idtcps_switch_ops = {
+ .owner = THIS_MODULE,
+ .add_entry = idtcps_route_add_entry,
+ .get_entry = idtcps_route_get_entry,
+ .clr_table = idtcps_route_clr_table,
+ .set_domain = idtcps_set_domain,
+ .get_domain = idtcps_get_domain,
+ .em_init = NULL,
+ .em_handle = NULL,
+};
+
+static int idtcps_probe(struct rio_dev *rdev, const struct rio_device_id *id)
{
pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev));
- rdev->rswitch->add_entry = idtcps_route_add_entry;
- rdev->rswitch->get_entry = idtcps_route_get_entry;
- rdev->rswitch->clr_table = idtcps_route_clr_table;
- rdev->rswitch->set_domain = idtcps_set_domain;
- rdev->rswitch->get_domain = idtcps_get_domain;
- rdev->rswitch->em_init = NULL;
- rdev->rswitch->em_handle = NULL;
-
- if (do_enum) {
+
+ spin_lock(&rdev->rswitch->lock);
+
+ if (rdev->rswitch->ops) {
+ spin_unlock(&rdev->rswitch->lock);
+ return -EINVAL;
+ }
+
+ rdev->rswitch->ops = &idtcps_switch_ops;
+
+ if (rdev->do_enum) {
/* set TVAL = ~50us */
rio_write_config_32(rdev,
rdev->phys_efptr + RIO_PORT_LINKTO_CTL_CSR, 0x8e << 8);
@@ -138,12 +152,52 @@ static int idtcps_switch_init(struct rio_dev *rdev, int do_enum)
RIO_STD_RTE_DEFAULT_PORT, CPS_NO_ROUTE);
}
+ spin_unlock(&rdev->rswitch->lock);
return 0;
}
-DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTCPS6Q, idtcps_switch_init);
-DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTCPS8, idtcps_switch_init);
-DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTCPS10Q, idtcps_switch_init);
-DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTCPS12, idtcps_switch_init);
-DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTCPS16, idtcps_switch_init);
-DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDT70K200, idtcps_switch_init);
+static void idtcps_remove(struct rio_dev *rdev)
+{
+ pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev));
+ spin_lock(&rdev->rswitch->lock);
+ if (rdev->rswitch->ops != &idtcps_switch_ops) {
+ spin_unlock(&rdev->rswitch->lock);
+ return;
+ }
+ rdev->rswitch->ops = NULL;
+ spin_unlock(&rdev->rswitch->lock);
+}
+
+static struct rio_device_id idtcps_id_table[] = {
+ {RIO_DEVICE(RIO_DID_IDTCPS6Q, RIO_VID_IDT)},
+ {RIO_DEVICE(RIO_DID_IDTCPS8, RIO_VID_IDT)},
+ {RIO_DEVICE(RIO_DID_IDTCPS10Q, RIO_VID_IDT)},
+ {RIO_DEVICE(RIO_DID_IDTCPS12, RIO_VID_IDT)},
+ {RIO_DEVICE(RIO_DID_IDTCPS16, RIO_VID_IDT)},
+ {RIO_DEVICE(RIO_DID_IDT70K200, RIO_VID_IDT)},
+ { 0, } /* terminate list */
+};
+
+static struct rio_driver idtcps_driver = {
+ .name = "idtcps",
+ .id_table = idtcps_id_table,
+ .probe = idtcps_probe,
+ .remove = idtcps_remove,
+};
+
+static int __init idtcps_init(void)
+{
+ return rio_register_driver(&idtcps_driver);
+}
+
+static void __exit idtcps_exit(void)
+{
+ rio_unregister_driver(&idtcps_driver);
+}
+
+device_initcall(idtcps_init);
+module_exit(idtcps_exit);
+
+MODULE_DESCRIPTION("IDT CPS Gen.1 Serial RapidIO switch family driver");
+MODULE_AUTHOR("Integrated Device Technology, Inc.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rapidio/switches/tsi500.c b/drivers/rapidio/switches/tsi500.c
deleted file mode 100644
index 914eddd5aa42..000000000000
--- a/drivers/rapidio/switches/tsi500.c
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * RapidIO Tsi500 switch support
- *
- * Copyright 2009-2010 Integrated Device Technology, Inc.
- * Alexandre Bounine <alexandre.bounine@idt.com>
- * - Modified switch operations initialization.
- *
- * 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/rio_drv.h>
-#include <linux/rio_ids.h>
-#include "../rio.h"
-
-static int
-tsi500_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount, u16 table, u16 route_destid, u8 route_port)
-{
- int i;
- u32 offset = 0x10000 + 0xa00 + ((route_destid / 2)&~0x3);
- u32 result;
-
- if (table == 0xff) {
- rio_mport_read_config_32(mport, destid, hopcount, offset, &result);
- result &= ~(0xf << (4*(route_destid & 0x7)));
- for (i=0;i<4;i++)
- rio_mport_write_config_32(mport, destid, hopcount, offset + (0x20000*i), result | (route_port << (4*(route_destid & 0x7))));
- }
- else {
- rio_mport_read_config_32(mport, destid, hopcount, offset + (0x20000*table), &result);
- result &= ~(0xf << (4*(route_destid & 0x7)));
- rio_mport_write_config_32(mport, destid, hopcount, offset + (0x20000*table), result | (route_port << (4*(route_destid & 0x7))));
- }
-
- return 0;
-}
-
-static int
-tsi500_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount, u16 table, u16 route_destid, u8 *route_port)
-{
- int ret = 0;
- u32 offset = 0x10000 + 0xa00 + ((route_destid / 2)&~0x3);
- u32 result;
-
- if (table == 0xff)
- rio_mport_read_config_32(mport, destid, hopcount, offset, &result);
- else
- rio_mport_read_config_32(mport, destid, hopcount, offset + (0x20000*table), &result);
-
- result &= 0xf << (4*(route_destid & 0x7));
- *route_port = result >> (4*(route_destid & 0x7));
- if (*route_port > 3)
- ret = -1;
-
- return ret;
-}
-
-static int tsi500_switch_init(struct rio_dev *rdev, int do_enum)
-{
- pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev));
- rdev->rswitch->add_entry = tsi500_route_add_entry;
- rdev->rswitch->get_entry = tsi500_route_get_entry;
- rdev->rswitch->clr_table = NULL;
- rdev->rswitch->set_domain = NULL;
- rdev->rswitch->get_domain = NULL;
- rdev->rswitch->em_init = NULL;
- rdev->rswitch->em_handle = NULL;
-
- return 0;
-}
-
-DECLARE_RIO_SWITCH_INIT(RIO_VID_TUNDRA, RIO_DID_TSI500, tsi500_switch_init);
diff --git a/drivers/rapidio/switches/tsi568.c b/drivers/rapidio/switches/tsi568.c
index 3994c00aa01f..8a43561b9d17 100644
--- a/drivers/rapidio/switches/tsi568.c
+++ b/drivers/rapidio/switches/tsi568.c
@@ -19,6 +19,7 @@
#include <linux/rio_drv.h>
#include <linux/rio_ids.h>
#include <linux/delay.h>
+#include <linux/module.h>
#include "../rio.h"
/* Global (broadcast) route registers */
@@ -129,18 +130,70 @@ tsi568_em_init(struct rio_dev *rdev)
return 0;
}
-static int tsi568_switch_init(struct rio_dev *rdev, int do_enum)
+static struct rio_switch_ops tsi568_switch_ops = {
+ .owner = THIS_MODULE,
+ .add_entry = tsi568_route_add_entry,
+ .get_entry = tsi568_route_get_entry,
+ .clr_table = tsi568_route_clr_table,
+ .set_domain = NULL,
+ .get_domain = NULL,
+ .em_init = tsi568_em_init,
+ .em_handle = NULL,
+};
+
+static int tsi568_probe(struct rio_dev *rdev, const struct rio_device_id *id)
{
pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev));
- rdev->rswitch->add_entry = tsi568_route_add_entry;
- rdev->rswitch->get_entry = tsi568_route_get_entry;
- rdev->rswitch->clr_table = tsi568_route_clr_table;
- rdev->rswitch->set_domain = NULL;
- rdev->rswitch->get_domain = NULL;
- rdev->rswitch->em_init = tsi568_em_init;
- rdev->rswitch->em_handle = NULL;
+ spin_lock(&rdev->rswitch->lock);
+
+ if (rdev->rswitch->ops) {
+ spin_unlock(&rdev->rswitch->lock);
+ return -EINVAL;
+ }
+
+ rdev->rswitch->ops = &tsi568_switch_ops;
+ spin_unlock(&rdev->rswitch->lock);
return 0;
}
-DECLARE_RIO_SWITCH_INIT(RIO_VID_TUNDRA, RIO_DID_TSI568, tsi568_switch_init);
+static void tsi568_remove(struct rio_dev *rdev)
+{
+ pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev));
+ spin_lock(&rdev->rswitch->lock);
+ if (rdev->rswitch->ops != &tsi568_switch_ops) {
+ spin_unlock(&rdev->rswitch->lock);
+ return;
+ }
+ rdev->rswitch->ops = NULL;
+ spin_unlock(&rdev->rswitch->lock);
+}
+
+static struct rio_device_id tsi568_id_table[] = {
+ {RIO_DEVICE(RIO_DID_TSI568, RIO_VID_TUNDRA)},
+ { 0, } /* terminate list */
+};
+
+static struct rio_driver tsi568_driver = {
+ .name = "tsi568",
+ .id_table = tsi568_id_table,
+ .probe = tsi568_probe,
+ .remove = tsi568_remove,
+};
+
+static int __init tsi568_init(void)
+{
+ return rio_register_driver(&tsi568_driver);
+}
+
+static void __exit tsi568_exit(void)
+{
+ rio_unregister_driver(&tsi568_driver);
+}
+
+device_initcall(tsi568_init);
+module_exit(tsi568_exit);
+
+MODULE_DESCRIPTION("IDT Tsi568 Serial RapidIO switch driver");
+MODULE_AUTHOR("Integrated Device Technology, Inc.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rapidio/switches/tsi57x.c b/drivers/rapidio/switches/tsi57x.c
index db8b8028988d..42c8b014fe15 100644
--- a/drivers/rapidio/switches/tsi57x.c
+++ b/drivers/rapidio/switches/tsi57x.c
@@ -19,6 +19,7 @@
#include <linux/rio_drv.h>
#include <linux/rio_ids.h>
#include <linux/delay.h>
+#include <linux/module.h>
#include "../rio.h"
/* Global (broadcast) route registers */
@@ -292,27 +293,79 @@ exit_es:
return 0;
}
-static int tsi57x_switch_init(struct rio_dev *rdev, int do_enum)
+static struct rio_switch_ops tsi57x_switch_ops = {
+ .owner = THIS_MODULE,
+ .add_entry = tsi57x_route_add_entry,
+ .get_entry = tsi57x_route_get_entry,
+ .clr_table = tsi57x_route_clr_table,
+ .set_domain = tsi57x_set_domain,
+ .get_domain = tsi57x_get_domain,
+ .em_init = tsi57x_em_init,
+ .em_handle = tsi57x_em_handler,
+};
+
+static int tsi57x_probe(struct rio_dev *rdev, const struct rio_device_id *id)
{
pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev));
- rdev->rswitch->add_entry = tsi57x_route_add_entry;
- rdev->rswitch->get_entry = tsi57x_route_get_entry;
- rdev->rswitch->clr_table = tsi57x_route_clr_table;
- rdev->rswitch->set_domain = tsi57x_set_domain;
- rdev->rswitch->get_domain = tsi57x_get_domain;
- rdev->rswitch->em_init = tsi57x_em_init;
- rdev->rswitch->em_handle = tsi57x_em_handler;
-
- if (do_enum) {
+
+ spin_lock(&rdev->rswitch->lock);
+
+ if (rdev->rswitch->ops) {
+ spin_unlock(&rdev->rswitch->lock);
+ return -EINVAL;
+ }
+ rdev->rswitch->ops = &tsi57x_switch_ops;
+
+ if (rdev->do_enum) {
/* Ensure that default routing is disabled on startup */
rio_write_config_32(rdev, RIO_STD_RTE_DEFAULT_PORT,
RIO_INVALID_ROUTE);
}
+ spin_unlock(&rdev->rswitch->lock);
return 0;
}
-DECLARE_RIO_SWITCH_INIT(RIO_VID_TUNDRA, RIO_DID_TSI572, tsi57x_switch_init);
-DECLARE_RIO_SWITCH_INIT(RIO_VID_TUNDRA, RIO_DID_TSI574, tsi57x_switch_init);
-DECLARE_RIO_SWITCH_INIT(RIO_VID_TUNDRA, RIO_DID_TSI577, tsi57x_switch_init);
-DECLARE_RIO_SWITCH_INIT(RIO_VID_TUNDRA, RIO_DID_TSI578, tsi57x_switch_init);
+static void tsi57x_remove(struct rio_dev *rdev)
+{
+ pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev));
+ spin_lock(&rdev->rswitch->lock);
+ if (rdev->rswitch->ops != &tsi57x_switch_ops) {
+ spin_unlock(&rdev->rswitch->lock);
+ return;
+ }
+ rdev->rswitch->ops = NULL;
+ spin_unlock(&rdev->rswitch->lock);
+}
+
+static struct rio_device_id tsi57x_id_table[] = {
+ {RIO_DEVICE(RIO_DID_TSI572, RIO_VID_TUNDRA)},
+ {RIO_DEVICE(RIO_DID_TSI574, RIO_VID_TUNDRA)},
+ {RIO_DEVICE(RIO_DID_TSI577, RIO_VID_TUNDRA)},
+ {RIO_DEVICE(RIO_DID_TSI578, RIO_VID_TUNDRA)},
+ { 0, } /* terminate list */
+};
+
+static struct rio_driver tsi57x_driver = {
+ .name = "tsi57x",
+ .id_table = tsi57x_id_table,
+ .probe = tsi57x_probe,
+ .remove = tsi57x_remove,
+};
+
+static int __init tsi57x_init(void)
+{
+ return rio_register_driver(&tsi57x_driver);
+}
+
+static void __exit tsi57x_exit(void)
+{
+ rio_unregister_driver(&tsi57x_driver);
+}
+
+device_initcall(tsi57x_init);
+module_exit(tsi57x_exit);
+
+MODULE_DESCRIPTION("IDT Tsi57x Serial RapidIO switch family driver");
+MODULE_AUTHOR("Integrated Device Technology, Inc.");
+MODULE_LICENSE("GPL");