From 27f62b9f294b7e2019c94c385abda43a0af6bb8b Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 13 Jun 2013 02:45:53 +0200 Subject: RAPIDIO: IDT_GEN2: Fix build error. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CC drivers/rapidio/switches/idt_gen2.o drivers/rapidio/switches/idt_gen2.c: In function ‘idtg2_show_errlog’: drivers/rapidio/switches/idt_gen2.c:379:30: error: ‘PAGE_SIZE’ undeclared (first use in this function) drivers/rapidio/switches/idt_gen2.c:379:30: note: each undeclared identifier is reported only once for each function it appears in Signed-off-by: Ralf Baechle Acked-by: Alexandre Bounine --- drivers/rapidio/switches/idt_gen2.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/rapidio') diff --git a/drivers/rapidio/switches/idt_gen2.c b/drivers/rapidio/switches/idt_gen2.c index 809b7a3336ba..5d3b0f014d35 100644 --- a/drivers/rapidio/switches/idt_gen2.c +++ b/drivers/rapidio/switches/idt_gen2.c @@ -15,6 +15,8 @@ #include #include #include + +#include #include "../rio.h" #define LOCAL_RTE_CONF_DESTID_SEL 0x010070 -- cgit v1.2.3 From e350cd1d9308b67363ebb870a678a1fd807df1a6 Mon Sep 17 00:00:00 2001 From: Alexandre Bounine Date: Wed, 3 Jul 2013 15:08:48 -0700 Subject: rapidio/switches: remove tsi500 driver Remove the driver for Tsi500 Parallel RapidIO switch because this device has not been available for several years. Since the first introduction of Tsi500, the parallel RapidIO interface was replaced by the serial RapidIO (sRIO) and therefore there is no value in keeping this driver. Signed-off-by: Alexandre Bounine Cc: Matt Porter Cc: Li Yang Cc: Kumar Gala Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rapidio/switches/Kconfig | 7 ---- drivers/rapidio/switches/Makefile | 1 - drivers/rapidio/switches/tsi500.c | 78 --------------------------------------- 3 files changed, 86 deletions(-) delete mode 100644 drivers/rapidio/switches/tsi500.c (limited to 'drivers/rapidio') diff --git a/drivers/rapidio/switches/Kconfig b/drivers/rapidio/switches/Kconfig index f47fee5d4563..62d4a065230f 100644 --- a/drivers/rapidio/switches/Kconfig +++ b/drivers/rapidio/switches/Kconfig @@ -26,10 +26,3 @@ config RAPIDIO_CPS_GEN2 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/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 - * - Modified switch operations initialization. - * - * Copyright 2005 MontaVista Software, Inc. - * Matt Porter - * - * 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 -#include -#include -#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); -- cgit v1.2.3 From 36f0efbbe8e21c153dfc2f94c91f89ab06fd64c5 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Wed, 3 Jul 2013 15:08:49 -0700 Subject: drivers/rapidio/rio-scan.c: make functions static sparse warnings: drivers/rapidio/rio-scan.c:1143:5: sparse: symbol 'rio_enum_mport' was not declared. Should it be static? drivers/rapidio/rio-scan.c:1246:5: sparse: symbol 'rio_disc_mport' was not declared. Should it be static? Signed-off-by: Fengguang Wu Cc: "Bounine, Alexandre" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rapidio/rio-scan.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/rapidio') diff --git a/drivers/rapidio/rio-scan.c b/drivers/rapidio/rio-scan.c index 4c15dbf81087..4b9b15ee8596 100644 --- a/drivers/rapidio/rio-scan.c +++ b/drivers/rapidio/rio-scan.c @@ -1141,7 +1141,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 +1256,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; -- cgit v1.2.3 From 2ec3ba69faf301fb599e3651515e808e8efa533e Mon Sep 17 00:00:00 2001 From: Alexandre Bounine Date: Wed, 3 Jul 2013 15:08:50 -0700 Subject: rapidio: convert switch drivers to modules Rework RapidIO switch drivers to add an option to build them as loadable kernel modules. This patch removes RapidIO-specific vmlinux section and converts switch drivers to be compatible with LDM driver registration method. To simplify registration of device-specific callback routines this patch introduces rio_switch_ops data structure. The sw_sysfs() callback is removed from the list of device-specific operations because under the new structure its functions can be handled by switch driver's probe() and remove() routines. If a specific switch device driver is not loaded the RapidIO subsystem core will use default standard-based operations to configure a switch. Because the current implementation of RapidIO enumeration/discovery method relies on availability of device-specific operations for error management, switch device drivers must be loaded before the RapidIO enumeration/discovery starts. This patch also moves several common routines from enumeration/discovery module into the RapidIO core code to make switch-specific operations accessible to all components of RapidIO subsystem. Signed-off-by: Alexandre Bounine Cc: Matt Porter Cc: Li Yang Cc: Kumar Gala Cc: Andre van Herk Cc: Micha Nelissen Cc: Stef van Os Cc: Jean Delvare Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rapidio/Kconfig | 5 + drivers/rapidio/rio-scan.c | 171 ++------------------- drivers/rapidio/rio-sysfs.c | 4 - drivers/rapidio/rio.c | 286 ++++++++++++++++++++++++++++++------ drivers/rapidio/rio.h | 41 +----- drivers/rapidio/switches/Kconfig | 12 +- drivers/rapidio/switches/idt_gen2.c | 98 +++++++++--- drivers/rapidio/switches/idtcps.c | 86 +++++++++-- drivers/rapidio/switches/tsi568.c | 71 +++++++-- drivers/rapidio/switches/tsi57x.c | 81 ++++++++-- include/asm-generic/vmlinux.lds.h | 7 - include/linux/rio.h | 51 +++---- 12 files changed, 568 insertions(+), 345 deletions(-) (limited to 'drivers/rapidio') 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/rio-scan.c b/drivers/rapidio/rio-scan.c index 4b9b15ee8596..913950212605 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, @@ -434,6 +435,7 @@ static struct rio_dev *rio_setup_device(struct rio_net *net, 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); @@ -445,11 +447,9 @@ static struct rio_dev *rio_setup_device(struct rio_net *net, 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); - 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); @@ -532,156 +532,6 @@ rio_sport_is_active(struct rio_mport *port, u16 destid, u8 hopcount, int sport) return result & RIO_PORT_N_ERR_STS_PORT_OK; } -/** - * 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 @@ -1094,12 +944,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 +962,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); } } diff --git a/drivers/rapidio/rio-sysfs.c b/drivers/rapidio/rio-sysfs.c index 66d4acd5e18f..864e52f193e1 100644 --- a/drivers/rapidio/rio-sysfs.c +++ b/drivers/rapidio/rio-sysfs.c @@ -257,8 +257,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 +279,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); } } diff --git a/drivers/rapidio/rio.c b/drivers/rapidio/rio.c index cb1c08996fbb..b17d5218005e 100644 --- a/drivers/rapidio/rio.c +++ b/drivers/rapidio/rio.c @@ -7,7 +7,6 @@ * * Copyright 2009 Integrated Device Technology, Inc. * Alex Bounine - * - 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 @@ -579,44 +578,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 @@ -970,8 +931,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 +1168,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 +1196,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 +1222,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 +1265,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) diff --git a/drivers/rapidio/rio.h b/drivers/rapidio/rio.h index c14f864dea5c..d59587762c76 100644 --- a/drivers/rapidio/rio.h +++ b/drivers/rapidio/rio.h @@ -28,18 +28,17 @@ 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); @@ -51,29 +50,5 @@ extern struct rio_mport *rio_find_mport(int mport_id); 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 62d4a065230f..345841562f95 100644 --- a/drivers/rapidio/switches/Kconfig +++ b/drivers/rapidio/switches/Kconfig @@ -2,27 +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. diff --git a/drivers/rapidio/switches/idt_gen2.c b/drivers/rapidio/switches/idt_gen2.c index 809b7a3336ba..00a71ebb5cac 100644 --- a/drivers/rapidio/switches/idt_gen2.c +++ b/drivers/rapidio/switches/idt_gen2.c @@ -11,6 +11,7 @@ */ #include +#include #include #include #include @@ -387,12 +388,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) @@ -403,29 +404,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 #include #include +#include #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/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 #include #include +#include #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 #include #include +#include #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"); diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 4f2737208c42..c74d88baea60 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -275,13 +275,6 @@ VMLINUX_SYMBOL(__end_builtin_fw) = .; \ } \ \ - /* RapidIO route ops */ \ - .rio_ops : AT(ADDR(.rio_ops) - LOAD_OFFSET) { \ - VMLINUX_SYMBOL(__start_rio_switch_ops) = .; \ - *(.rio_switch_ops) \ - VMLINUX_SYMBOL(__end_rio_switch_ops) = .; \ - } \ - \ TRACEDATA \ \ /* Kernel symbol table: Normal symbols */ \ diff --git a/include/linux/rio.h b/include/linux/rio.h index 18e099342e6f..fcd492e7aff4 100644 --- a/include/linux/rio.h +++ b/include/linux/rio.h @@ -94,6 +94,23 @@ union rio_pw_msg; * @switchid: Switch ID that is unique across a network * @route_table: Copy of switch routing table * @port_ok: Status of each port (one bit per port) - OK=1 or UNINIT=0 + * @ops: pointer to switch-specific operations + * @lock: lock to serialize operations updates + * @nextdev: Array of per-port pointers to the next attached device + */ +struct rio_switch { + struct list_head node; + u16 switchid; + u8 *route_table; + u32 port_ok; + struct rio_switch_ops *ops; + spinlock_t lock; + struct rio_dev *nextdev[0]; +}; + +/** + * struct rio_switch_ops - Per-switch operations + * @owner: The module owner of this structure * @add_entry: Callback for switch-specific route add function * @get_entry: Callback for switch-specific route get function * @clr_table: Callback for switch-specific clear route table function @@ -101,14 +118,12 @@ union rio_pw_msg; * @get_domain: Callback for switch-specific domain get function * @em_init: Callback for switch-specific error management init function * @em_handle: Callback for switch-specific error management handler function - * @sw_sysfs: Callback that initializes switch-specific sysfs attributes - * @nextdev: Array of per-port pointers to the next attached device + * + * Defines the operations that are necessary to initialize/control + * a particular RIO switch device. */ -struct rio_switch { - struct list_head node; - u16 switchid; - u8 *route_table; - u32 port_ok; +struct rio_switch_ops { + struct module *owner; int (*add_entry) (struct rio_mport *mport, u16 destid, u8 hopcount, u16 table, u16 route_destid, u8 route_port); int (*get_entry) (struct rio_mport *mport, u16 destid, u8 hopcount, @@ -121,8 +136,6 @@ struct rio_switch { u8 *sw_domain); int (*em_init) (struct rio_dev *dev); int (*em_handle) (struct rio_dev *dev, u8 swport); - int (*sw_sysfs) (struct rio_dev *dev, int create); - struct rio_dev *nextdev[0]; }; /** @@ -130,6 +143,7 @@ struct rio_switch { * @global_list: Node in list of all RIO devices * @net_list: Node in list of RIO devices in a network * @net: Network this device is a part of + * @do_enum: Enumeration flag * @did: Device ID * @vid: Vendor ID * @device_rev: Device revision @@ -158,6 +172,7 @@ struct rio_dev { struct list_head global_list; /* node in list of all RIO devices */ struct list_head net_list; /* node in per net list */ struct rio_net *net; /* RIO net this device resides in */ + bool do_enum; u16 did; u16 vid; u32 device_rev; @@ -297,10 +312,6 @@ struct rio_net { struct rio_id_table destid_table; /* destID allocation table */ }; -/* Definitions used by switch sysfs initialization callback */ -#define RIO_SW_SYSFS_CREATE 1 /* Create switch attributes */ -#define RIO_SW_SYSFS_REMOVE 0 /* Remove switch attributes */ - /* Low-level architecture-dependent routines */ /** @@ -400,20 +411,6 @@ struct rio_device_id { u16 asm_did, asm_vid; }; -/** - * struct rio_switch_ops - Per-switch operations - * @vid: RIO vendor ID - * @did: RIO device ID - * @init_hook: Callback that performs switch device initialization - * - * Defines the operations that are necessary to initialize/control - * a particular RIO switch device. - */ -struct rio_switch_ops { - u16 vid, did; - int (*init_hook) (struct rio_dev *rdev, int do_enum); -}; - union rio_pw_msg { struct { u32 comptag; /* Component Tag CSR */ -- cgit v1.2.3 From 9edbc30b434f56258d03faac5daf37a555384db3 Mon Sep 17 00:00:00 2001 From: Alexandre Bounine Date: Wed, 3 Jul 2013 15:08:53 -0700 Subject: rapidio: update enumerator registration mechanism Update enumeration/discovery method registration mechanism to allow loading enumeration/discovery methods before all mports are registered. Existing statically linked RapidIO subsystem expects that all available RapidIO mport devices are initialized and registered before the enumeration/discovery method is registered. Switching to loadable mport device drivers creates situation when mport device driver can be loaded after enumeration/discovery method is attached (e.g., loadable mport driver in a system with statically linked RapidIO core and enumerator). This also will happen in a system with hot-pluggable RapidIO controllers. To remove the dependency on the initialization/registration order this patch introduces enumeration/discovery registration mechanism that supports arbitrary registration order of mports and enumerator/discovery methods. The following registration rules are implemented: - only one enumeration/discovery method can be registered for given mport ID (including RIO_MPORT_ANY); - when new enumeration/discovery methods tries to attach to the registered mport device, method with matching mport ID will replace a default method previously registered for given mport (if any); - enumeration/discovery method with target ID=RIO_MPORT_ANY will be attached only to mports that do not have another enumerator attached to them; - when new mport device is registered with RapidIO subsystem, registration routine searches for the enumeration/discovery method with the best matching mport ID; Signed-off-by: Alexandre Bounine Cc: Matt Porter Cc: Li Yang Cc: Kumar Gala Cc: Andre van Herk Cc: Micha Nelissen Cc: Stef van Os Cc: Jean Delvare Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rapidio/rio-scan.c | 1 + drivers/rapidio/rio-sysfs.c | 17 +---- drivers/rapidio/rio.c | 176 ++++++++++++++++++++++++++++++++++++-------- drivers/rapidio/rio.h | 3 +- include/linux/rio.h | 15 ++++ 5 files changed, 164 insertions(+), 48 deletions(-) (limited to 'drivers/rapidio') diff --git a/drivers/rapidio/rio-scan.c b/drivers/rapidio/rio-scan.c index 913950212605..ab837fdb2383 100644 --- a/drivers/rapidio/rio-scan.c +++ b/drivers/rapidio/rio-scan.c @@ -1162,6 +1162,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 864e52f193e1..0c4473e54f86 100644 --- a/drivers/rapidio/rio-sysfs.c +++ b/drivers/rapidio/rio-sysfs.c @@ -286,7 +286,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) @@ -300,21 +299,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 b17d5218005e..5eb727cd0652 100644 --- a/drivers/rapidio/rio.c +++ b/drivers/rapidio/rio.c @@ -34,6 +34,7 @@ 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); @@ -1602,34 +1603,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; @@ -1639,30 +1679,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) { } @@ -1691,7 +1782,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) @@ -1710,8 +1804,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++; } @@ -1725,7 +1821,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); @@ -1751,9 +1847,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); @@ -1784,6 +1880,8 @@ __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; @@ -1792,9 +1890,25 @@ 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; } diff --git a/drivers/rapidio/rio.h b/drivers/rapidio/rio.h index d59587762c76..085215cd8502 100644 --- a/drivers/rapidio/rio.h +++ b/drivers/rapidio/rio.h @@ -42,9 +42,10 @@ extern int rio_add_device(struct rio_dev *rdev); 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[]; diff --git a/include/linux/rio.h b/include/linux/rio.h index fcd492e7aff4..8d3db1b7b998 100644 --- a/include/linux/rio.h +++ b/include/linux/rio.h @@ -465,14 +465,29 @@ static inline struct rio_mport *dma_to_mport(struct dma_device *ddev) /** * struct rio_scan - RIO enumeration and discovery operations + * @owner: The module owner of this structure * @enumerate: Callback to perform RapidIO fabric enumeration. * @discover: Callback to perform RapidIO fabric discovery. */ struct rio_scan { + struct module *owner; int (*enumerate)(struct rio_mport *mport, u32 flags); int (*discover)(struct rio_mport *mport, u32 flags); }; +/** + * struct rio_scan_node - list node to register RapidIO enumeration and + * discovery methods with RapidIO core. + * @mport_id: ID of an mport (net) serviced by this enumerator + * @node: node in global list of registered enumerators + * @ops: RIO enumeration and discovery operations + */ +struct rio_scan_node { + int mport_id; + struct list_head node; + struct rio_scan *ops; +}; + /* Architecture and hardware-specific functions */ extern int rio_register_mport(struct rio_mport *); extern int rio_open_inb_mbox(struct rio_mport *, void *, int, int); -- cgit v1.2.3 From 94d9bd4576fcd340c344bffbbe0526227535a95f Mon Sep 17 00:00:00 2001 From: Alexandre Bounine Date: Wed, 3 Jul 2013 15:08:55 -0700 Subject: rapidio/tsi721: convert to modular mport driver This patch adds an option to build device driver for Tsi721 PCIe-to-SRIO bridge device as a kernel module. Currently this module cannot be unloaded because the existing RapidIO subsystem code does not support dynamic removal of local RapidIO controllers (TODO). Signed-off-by: Alexandre Bounine Cc: Matt Porter Cc: Li Yang Cc: Kumar Gala Cc: Andre van Herk Cc: Micha Nelissen Cc: Stef van Os Cc: Jean Delvare Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rapidio/devices/Kconfig | 2 +- drivers/rapidio/devices/Makefile | 7 +++---- drivers/rapidio/devices/tsi721.c | 9 ++++----- drivers/rapidio/rio.c | 1 + 4 files changed, 9 insertions(+), 10 deletions(-) (limited to 'drivers/rapidio') 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.c b/drivers/rapidio/rio.c index 5eb727cd0652..2054b6208823 100644 --- a/drivers/rapidio/rio.c +++ b/drivers/rapidio/rio.c @@ -1911,6 +1911,7 @@ int rio_register_mport(struct rio_mport *port) 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); -- cgit v1.2.3 From fdf90abc00979fb2d61dbdba9e855200e236142b Mon Sep 17 00:00:00 2001 From: Alexandre Bounine Date: Wed, 3 Jul 2013 15:08:56 -0700 Subject: rapidio: add modular build option for the subsystem core Add a configuration option to build RapidIO subsystem core code as a loadable kernel module. Currently this option is available only for x86-based platforms, with the additional patch for PowerPC planned to be provided later. This patch replaces kernel command line parameter "riohdid=" with its module-specific analog "rapidio.hdid=". Signed-off-by: Alexandre Bounine Cc: Matt Porter Cc: Li Yang Cc: Kumar Gala Cc: Andre van Herk Cc: Micha Nelissen Cc: Stef van Os Cc: Jean Delvare Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/x86/Kconfig | 4 ++-- drivers/rapidio/Makefile | 4 +++- drivers/rapidio/rio.c | 27 ++++++++++++++------------- 3 files changed, 19 insertions(+), 16 deletions(-) (limited to 'drivers/rapidio') diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 10764a3d62cc..2775023a0744 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -2259,11 +2259,11 @@ source "drivers/pcmcia/Kconfig" source "drivers/pci/hotplug/Kconfig" config RAPIDIO - bool "RapidIO support" + tristate "RapidIO support" depends on PCI default n help - If you say Y here, the kernel will include drivers and + If enabled this option will include drivers and the core infrastructure code to support RapidIO interconnect devices. source "drivers/rapidio/Kconfig" 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/rio.c b/drivers/rapidio/rio.c index 2054b6208823..f4f30af2df68 100644 --- a/drivers/rapidio/rio.c +++ b/drivers/rapidio/rio.c @@ -5,7 +5,7 @@ * Copyright 2005 MontaVista Software, Inc. * Matt Porter * - * Copyright 2009 Integrated Device Technology, Inc. + * Copyright 2009 - 2013 Integrated Device Technology, Inc. * Alex Bounine * * This program is free software; you can redistribute it and/or modify it @@ -30,6 +30,17 @@ #include "rio.h" +MODULE_DESCRIPTION("RapidIO Subsystem Core"); +MODULE_AUTHOR("Matt Porter "); +MODULE_AUTHOR("Alexandre Bounine "); +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); @@ -1860,24 +1871,14 @@ 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]; + return hdid[index]; } -static int rio_hdid_setup(char *str) -{ - (void)get_options(str, ARRAY_SIZE(hdids), hdids); - return 1; -} - -__setup("riohdid=", rio_hdid_setup); - int rio_register_mport(struct rio_mport *port) { struct rio_scan_node *scan = NULL; -- cgit v1.2.3 From 3bdbb62fe97537252b22f700009863eeb51aa750 Mon Sep 17 00:00:00 2001 From: Alexandre Bounine Date: Wed, 3 Jul 2013 15:08:58 -0700 Subject: rapidio: add udev notification Add RapidIO-specific modalias generation to enable udev notifications about RapidIO-specific events. The RapidIO modalias string format is shown below: "rapidio:vNNNNdNNNNavNNNNadNNNN" Where: v - Device Vendor ID (16 bit), d - Device ID (16 bit), av - Assembly Vendor ID (16 bit), ad - Assembly ID (16 bit), as they are reported in corresponding Capability Registers (CARs) of each RapidIO device. Signed-off-by: Alexandre Bounine Cc: Matt Porter Cc: Li Yang Cc: Kumar Gala Cc: Andre van Herk Cc: Micha Nelissen Cc: Stef van Os Cc: Jean Delvare Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rapidio/rio-driver.c | 18 ++++++++++++++++++ drivers/rapidio/rio-sysfs.c | 10 ++++++++++ include/linux/mod_devicetable.h | 19 +++++++++++++++++++ include/linux/rio.h | 16 +--------------- include/linux/rio_ids.h | 2 -- scripts/mod/devicetable-offsets.c | 6 ++++++ scripts/mod/file2alias.c | 20 ++++++++++++++++++++ 7 files changed, 74 insertions(+), 17 deletions(-) (limited to 'drivers/rapidio') 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-sysfs.c b/drivers/rapidio/rio-sysfs.c index 0c4473e54f86..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, }; diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h index b3bd7e737e8b..b62d4af6c667 100644 --- a/include/linux/mod_devicetable.h +++ b/include/linux/mod_devicetable.h @@ -579,4 +579,23 @@ struct mei_cl_device_id { kernel_ulong_t driver_info; }; +/* RapidIO */ + +#define RIO_ANY_ID 0xffff + +/** + * struct rio_device_id - RIO device identifier + * @did: RapidIO device ID + * @vid: RapidIO vendor ID + * @asm_did: RapidIO assembly device ID + * @asm_vid: RapidIO assembly vendor ID + * + * Identifies a RapidIO device based on both the device/vendor IDs and + * the assembly device/vendor IDs. + */ +struct rio_device_id { + __u16 did, vid; + __u16 asm_did, asm_vid; +}; + #endif /* LINUX_MOD_DEVICETABLE_H */ diff --git a/include/linux/rio.h b/include/linux/rio.h index 8d3db1b7b998..e2faf7b8fe80 100644 --- a/include/linux/rio.h +++ b/include/linux/rio.h @@ -20,6 +20,7 @@ #include #include #include +#include #ifdef CONFIG_RAPIDIO_DMA_ENGINE #include #endif @@ -396,21 +397,6 @@ struct rio_driver { #define to_rio_driver(drv) container_of(drv,struct rio_driver, driver) -/** - * struct rio_device_id - RIO device identifier - * @did: RIO device ID - * @vid: RIO vendor ID - * @asm_did: RIO assembly device ID - * @asm_vid: RIO assembly vendor ID - * - * Identifies a RIO device based on both the device/vendor IDs and - * the assembly device/vendor IDs. - */ -struct rio_device_id { - u16 did, vid; - u16 asm_did, asm_vid; -}; - union rio_pw_msg { struct { u32 comptag; /* Component Tag CSR */ diff --git a/include/linux/rio_ids.h b/include/linux/rio_ids.h index b66d13d1bdc0..2543bc163d54 100644 --- a/include/linux/rio_ids.h +++ b/include/linux/rio_ids.h @@ -13,8 +13,6 @@ #ifndef LINUX_RIO_IDS_H #define LINUX_RIO_IDS_H -#define RIO_ANY_ID 0xffff - #define RIO_VID_FREESCALE 0x0002 #define RIO_DID_MPC8560 0x0003 diff --git a/scripts/mod/devicetable-offsets.c b/scripts/mod/devicetable-offsets.c index e66d4d258e1a..bb5d115ca671 100644 --- a/scripts/mod/devicetable-offsets.c +++ b/scripts/mod/devicetable-offsets.c @@ -177,5 +177,11 @@ int main(void) DEVID(mei_cl_device_id); DEVID_FIELD(mei_cl_device_id, name); + DEVID(rio_device_id); + DEVID_FIELD(rio_device_id, did); + DEVID_FIELD(rio_device_id, vid); + DEVID_FIELD(rio_device_id, asm_did); + DEVID_FIELD(rio_device_id, asm_vid); + return 0; } diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index 45f9a3377dcd..d9e67b719f08 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -1145,6 +1145,26 @@ static int do_mei_entry(const char *filename, void *symval, } ADD_TO_DEVTABLE("mei", mei_cl_device_id, do_mei_entry); +/* Looks like: rapidio:vNdNavNadN */ +static int do_rio_entry(const char *filename, + void *symval, char *alias) +{ + DEF_FIELD(symval, rio_device_id, did); + DEF_FIELD(symval, rio_device_id, vid); + DEF_FIELD(symval, rio_device_id, asm_did); + DEF_FIELD(symval, rio_device_id, asm_vid); + + strcpy(alias, "rapidio:"); + ADD(alias, "v", vid != RIO_ANY_ID, vid); + ADD(alias, "d", did != RIO_ANY_ID, did); + ADD(alias, "av", asm_vid != RIO_ANY_ID, asm_vid); + ADD(alias, "ad", asm_did != RIO_ANY_ID, asm_did); + + add_wildcard(alias); + return 1; +} +ADD_TO_DEVTABLE("rapidio", rio_device_id, do_rio_entry); + /* Does namelen bytes of name exactly match the symbol? */ static bool sym_is(const char *name, unsigned namelen, const char *symbol) { -- cgit v1.2.3 From 6ca40c2565fc617534d20d10a5848b626213608c Mon Sep 17 00:00:00 2001 From: Alexandre Bounine Date: Wed, 3 Jul 2013 15:09:01 -0700 Subject: rapidio: change endpoint device name format Change endpoint device name format to use a component tag value instead of device destination ID. RapidIO specification defines a component tag to be a unique identifier for devices in a network. RapidIO switches already use component tag as part of their device name and also use it for device identification when processing error management event notifications. Forming an endpoint's device name using its component tag instead of destination ID allows to keep sysfs device directories unchanged in case if a routing process dynamically changes endpoint's destination ID as a result of route optimization. This change should not affect any existing users because a valid device destination ID always should be obtained by reading "destid" attribute and not by parsing device name. This patch also removes switchid member from struct rio_switch because it simply duplicates the component tag and does not have other use than in device name generation. Signed-off-by: Alexandre Bounine Cc: Matt Porter Cc: Li Yang Cc: Kumar Gala Cc: Andre van Herk Cc: Micha Nelissen Cc: Stef van Os Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rapidio/rio-scan.c | 5 ++--- include/linux/rio.h | 2 -- 2 files changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers/rapidio') diff --git a/drivers/rapidio/rio-scan.c b/drivers/rapidio/rio-scan.c index ab837fdb2383..d3a6539a77cc 100644 --- a/drivers/rapidio/rio-scan.c +++ b/drivers/rapidio/rio-scan.c @@ -433,7 +433,6 @@ 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)* @@ -446,7 +445,7 @@ 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); + rdev->comp_tag & RIO_CTAG_UDEVID); if (do_enum) rio_route_clr_table(rdev, RIO_GLOBAL_TABLE, 0); @@ -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); diff --git a/include/linux/rio.h b/include/linux/rio.h index e2faf7b8fe80..b71d5738e683 100644 --- a/include/linux/rio.h +++ b/include/linux/rio.h @@ -92,7 +92,6 @@ union rio_pw_msg; /** * struct rio_switch - RIO switch info * @node: Node in global list of switches - * @switchid: Switch ID that is unique across a network * @route_table: Copy of switch routing table * @port_ok: Status of each port (one bit per port) - OK=1 or UNINIT=0 * @ops: pointer to switch-specific operations @@ -101,7 +100,6 @@ union rio_pw_msg; */ struct rio_switch { struct list_head node; - u16 switchid; u8 *route_table; u32 port_ok; struct rio_switch_ops *ops; -- cgit v1.2.3