diff options
Diffstat (limited to 'drivers/rapidio')
-rw-r--r-- | drivers/rapidio/Kconfig | 5 | ||||
-rw-r--r-- | drivers/rapidio/Makefile | 4 | ||||
-rw-r--r-- | drivers/rapidio/devices/Kconfig | 2 | ||||
-rw-r--r-- | drivers/rapidio/devices/Makefile | 7 | ||||
-rw-r--r-- | drivers/rapidio/devices/tsi721.c | 9 | ||||
-rw-r--r-- | drivers/rapidio/rio-driver.c | 18 | ||||
-rw-r--r-- | drivers/rapidio/rio-scan.c | 181 | ||||
-rw-r--r-- | drivers/rapidio/rio-sysfs.c | 31 | ||||
-rw-r--r-- | drivers/rapidio/rio.c | 490 | ||||
-rw-r--r-- | drivers/rapidio/rio.h | 44 | ||||
-rw-r--r-- | drivers/rapidio/switches/Kconfig | 19 | ||||
-rw-r--r-- | drivers/rapidio/switches/Makefile | 1 | ||||
-rw-r--r-- | drivers/rapidio/switches/idt_gen2.c | 98 | ||||
-rw-r--r-- | drivers/rapidio/switches/idtcps.c | 86 | ||||
-rw-r--r-- | drivers/rapidio/switches/tsi500.c | 78 | ||||
-rw-r--r-- | drivers/rapidio/switches/tsi568.c | 71 | ||||
-rw-r--r-- | drivers/rapidio/switches/tsi57x.c | 81 |
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 809b7a3336ba..00a71ebb5cac 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> @@ -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 <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"); |