1eb188d0eSMatt Porter /* 2eb188d0eSMatt Porter * RapidIO enumeration and discovery support 3eb188d0eSMatt Porter * 4eb188d0eSMatt Porter * Copyright 2005 MontaVista Software, Inc. 5eb188d0eSMatt Porter * Matt Porter <mporter@kernel.crashing.org> 6eb188d0eSMatt Porter * 7e5cabeb3SAlexandre Bounine * Copyright 2009 Integrated Device Technology, Inc. 8e5cabeb3SAlexandre Bounine * Alex Bounine <alexandre.bounine@idt.com> 9e5cabeb3SAlexandre Bounine * - Added Port-Write/Error Management initialization and handling 10e5cabeb3SAlexandre Bounine * 11eb188d0eSMatt Porter * This program is free software; you can redistribute it and/or modify it 12eb188d0eSMatt Porter * under the terms of the GNU General Public License as published by the 13eb188d0eSMatt Porter * Free Software Foundation; either version 2 of the License, or (at your 14eb188d0eSMatt Porter * option) any later version. 15eb188d0eSMatt Porter */ 16eb188d0eSMatt Porter 17eb188d0eSMatt Porter #include <linux/types.h> 18eb188d0eSMatt Porter #include <linux/kernel.h> 19eb188d0eSMatt Porter 20eb188d0eSMatt Porter #include <linux/delay.h> 21fa78cc51SMatt Porter #include <linux/dma-mapping.h> 22eb188d0eSMatt Porter #include <linux/init.h> 23eb188d0eSMatt Porter #include <linux/rio.h> 24eb188d0eSMatt Porter #include <linux/rio_drv.h> 25eb188d0eSMatt Porter #include <linux/rio_ids.h> 26eb188d0eSMatt Porter #include <linux/rio_regs.h> 27eb188d0eSMatt Porter #include <linux/module.h> 28eb188d0eSMatt Porter #include <linux/spinlock.h> 29eb188d0eSMatt Porter #include <linux/timer.h> 30de25968cSTim Schmielau #include <linux/jiffies.h> 31de25968cSTim Schmielau #include <linux/slab.h> 32eb188d0eSMatt Porter 33eb188d0eSMatt Porter #include "rio.h" 34eb188d0eSMatt Porter 35eb188d0eSMatt Porter LIST_HEAD(rio_devices); 36eb188d0eSMatt Porter static LIST_HEAD(rio_switches); 37eb188d0eSMatt Porter 38eb188d0eSMatt Porter static void rio_enum_timeout(unsigned long); 39eb188d0eSMatt Porter 40e5cabeb3SAlexandre Bounine static void rio_init_em(struct rio_dev *rdev); 41e5cabeb3SAlexandre Bounine 42fa78cc51SMatt Porter DEFINE_SPINLOCK(rio_global_list_lock); 43fa78cc51SMatt Porter 44eb188d0eSMatt Porter static int next_destid = 0; 45eb188d0eSMatt Porter static int next_switchid = 0; 46eb188d0eSMatt Porter static int next_net = 0; 47e5cabeb3SAlexandre Bounine static int next_comptag; 48eb188d0eSMatt Porter 49eb188d0eSMatt Porter static struct timer_list rio_enum_timer = 50eb188d0eSMatt Porter TIMER_INITIALIZER(rio_enum_timeout, 0, 0); 51eb188d0eSMatt Porter 52eb188d0eSMatt Porter static int rio_mport_phys_table[] = { 53eb188d0eSMatt Porter RIO_EFB_PAR_EP_ID, 54eb188d0eSMatt Porter RIO_EFB_PAR_EP_REC_ID, 55eb188d0eSMatt Porter RIO_EFB_SER_EP_ID, 56eb188d0eSMatt Porter RIO_EFB_SER_EP_REC_ID, 57eb188d0eSMatt Porter -1, 58eb188d0eSMatt Porter }; 59eb188d0eSMatt Porter 60eb188d0eSMatt Porter /** 61eb188d0eSMatt Porter * rio_get_device_id - Get the base/extended device id for a device 62eb188d0eSMatt Porter * @port: RIO master port 63eb188d0eSMatt Porter * @destid: Destination ID of device 64eb188d0eSMatt Porter * @hopcount: Hopcount to device 65eb188d0eSMatt Porter * 66eb188d0eSMatt Porter * Reads the base/extended device id from a device. Returns the 67eb188d0eSMatt Porter * 8/16-bit device ID. 68eb188d0eSMatt Porter */ 69eb188d0eSMatt Porter static u16 rio_get_device_id(struct rio_mport *port, u16 destid, u8 hopcount) 70eb188d0eSMatt Porter { 71eb188d0eSMatt Porter u32 result; 72eb188d0eSMatt Porter 73eb188d0eSMatt Porter rio_mport_read_config_32(port, destid, hopcount, RIO_DID_CSR, &result); 74eb188d0eSMatt Porter 75e0423236SZhang Wei return RIO_GET_DID(port->sys_size, result); 76eb188d0eSMatt Porter } 77eb188d0eSMatt Porter 78eb188d0eSMatt Porter /** 79eb188d0eSMatt Porter * rio_set_device_id - Set the base/extended device id for a device 80eb188d0eSMatt Porter * @port: RIO master port 81eb188d0eSMatt Porter * @destid: Destination ID of device 82eb188d0eSMatt Porter * @hopcount: Hopcount to device 83eb188d0eSMatt Porter * @did: Device ID value to be written 84eb188d0eSMatt Porter * 85eb188d0eSMatt Porter * Writes the base/extended device id from a device. 86eb188d0eSMatt Porter */ 87fa78cc51SMatt Porter static void rio_set_device_id(struct rio_mport *port, u16 destid, u8 hopcount, u16 did) 88eb188d0eSMatt Porter { 89eb188d0eSMatt Porter rio_mport_write_config_32(port, destid, hopcount, RIO_DID_CSR, 90e0423236SZhang Wei RIO_SET_DID(port->sys_size, did)); 91eb188d0eSMatt Porter } 92eb188d0eSMatt Porter 93eb188d0eSMatt Porter /** 94eb188d0eSMatt Porter * rio_local_set_device_id - Set the base/extended device id for a port 95eb188d0eSMatt Porter * @port: RIO master port 96eb188d0eSMatt Porter * @did: Device ID value to be written 97eb188d0eSMatt Porter * 98eb188d0eSMatt Porter * Writes the base/extended device id from a device. 99eb188d0eSMatt Porter */ 100eb188d0eSMatt Porter static void rio_local_set_device_id(struct rio_mport *port, u16 did) 101eb188d0eSMatt Porter { 102e0423236SZhang Wei rio_local_write_config_32(port, RIO_DID_CSR, RIO_SET_DID(port->sys_size, 103e0423236SZhang Wei did)); 104eb188d0eSMatt Porter } 105eb188d0eSMatt Porter 106eb188d0eSMatt Porter /** 107eb188d0eSMatt Porter * rio_clear_locks- Release all host locks and signal enumeration complete 108eb188d0eSMatt Porter * @port: Master port to issue transaction 109eb188d0eSMatt Porter * 110eb188d0eSMatt Porter * Marks the component tag CSR on each device with the enumeration 111eb188d0eSMatt Porter * complete flag. When complete, it then release the host locks on 112eb188d0eSMatt Porter * each device. Returns 0 on success or %-EINVAL on failure. 113eb188d0eSMatt Porter */ 114eb188d0eSMatt Porter static int rio_clear_locks(struct rio_mport *port) 115eb188d0eSMatt Porter { 116eb188d0eSMatt Porter struct rio_dev *rdev; 117eb188d0eSMatt Porter u32 result; 118eb188d0eSMatt Porter int ret = 0; 119eb188d0eSMatt Porter 120e5cabeb3SAlexandre Bounine /* Assign component tag to all devices */ 121e5cabeb3SAlexandre Bounine next_comptag = 1; 122e5cabeb3SAlexandre Bounine rio_local_write_config_32(port, RIO_COMPONENT_TAG_CSR, next_comptag++); 123e5cabeb3SAlexandre Bounine 124e5cabeb3SAlexandre Bounine list_for_each_entry(rdev, &rio_devices, global_list) { 125e5cabeb3SAlexandre Bounine /* Mark device as discovered */ 126e5cabeb3SAlexandre Bounine rio_read_config_32(rdev, 127e5cabeb3SAlexandre Bounine rdev->phys_efptr + RIO_PORT_GEN_CTL_CSR, 128e5cabeb3SAlexandre Bounine &result); 129e5cabeb3SAlexandre Bounine rio_write_config_32(rdev, 130e5cabeb3SAlexandre Bounine rdev->phys_efptr + RIO_PORT_GEN_CTL_CSR, 131e5cabeb3SAlexandre Bounine result | RIO_PORT_GEN_DISCOVERED); 132e5cabeb3SAlexandre Bounine 133e5cabeb3SAlexandre Bounine rio_write_config_32(rdev, RIO_COMPONENT_TAG_CSR, next_comptag); 134e5cabeb3SAlexandre Bounine rdev->comp_tag = next_comptag++; 135e5cabeb3SAlexandre Bounine if (next_comptag >= 0x10000) { 136e5cabeb3SAlexandre Bounine pr_err("RIO: Component Tag Counter Overflow\n"); 137e5cabeb3SAlexandre Bounine break; 138e5cabeb3SAlexandre Bounine } 139e5cabeb3SAlexandre Bounine } 140eb188d0eSMatt Porter 141eb188d0eSMatt Porter /* Release host device id locks */ 142eb188d0eSMatt Porter rio_local_write_config_32(port, RIO_HOST_DID_LOCK_CSR, 143eb188d0eSMatt Porter port->host_deviceid); 144eb188d0eSMatt Porter rio_local_read_config_32(port, RIO_HOST_DID_LOCK_CSR, &result); 145eb188d0eSMatt Porter if ((result & 0xffff) != 0xffff) { 146eb188d0eSMatt Porter printk(KERN_INFO 147eb188d0eSMatt Porter "RIO: badness when releasing host lock on master port, result %8.8x\n", 148eb188d0eSMatt Porter result); 149eb188d0eSMatt Porter ret = -EINVAL; 150eb188d0eSMatt Porter } 151eb188d0eSMatt Porter list_for_each_entry(rdev, &rio_devices, global_list) { 152eb188d0eSMatt Porter rio_write_config_32(rdev, RIO_HOST_DID_LOCK_CSR, 153eb188d0eSMatt Porter port->host_deviceid); 154eb188d0eSMatt Porter rio_read_config_32(rdev, RIO_HOST_DID_LOCK_CSR, &result); 155eb188d0eSMatt Porter if ((result & 0xffff) != 0xffff) { 156eb188d0eSMatt Porter printk(KERN_INFO 157eb188d0eSMatt Porter "RIO: badness when releasing host lock on vid %4.4x did %4.4x\n", 158eb188d0eSMatt Porter rdev->vid, rdev->did); 159eb188d0eSMatt Porter ret = -EINVAL; 160eb188d0eSMatt Porter } 161eb188d0eSMatt Porter } 162eb188d0eSMatt Porter 163eb188d0eSMatt Porter return ret; 164eb188d0eSMatt Porter } 165eb188d0eSMatt Porter 166eb188d0eSMatt Porter /** 167eb188d0eSMatt Porter * rio_enum_host- Set host lock and initialize host destination ID 168eb188d0eSMatt Porter * @port: Master port to issue transaction 169eb188d0eSMatt Porter * 170eb188d0eSMatt Porter * Sets the local host master port lock and destination ID register 171eb188d0eSMatt Porter * with the host device ID value. The host device ID value is provided 172eb188d0eSMatt Porter * by the platform. Returns %0 on success or %-1 on failure. 173eb188d0eSMatt Porter */ 174eb188d0eSMatt Porter static int rio_enum_host(struct rio_mport *port) 175eb188d0eSMatt Porter { 176eb188d0eSMatt Porter u32 result; 177eb188d0eSMatt Porter 178eb188d0eSMatt Porter /* Set master port host device id lock */ 179eb188d0eSMatt Porter rio_local_write_config_32(port, RIO_HOST_DID_LOCK_CSR, 180eb188d0eSMatt Porter port->host_deviceid); 181eb188d0eSMatt Porter 182eb188d0eSMatt Porter rio_local_read_config_32(port, RIO_HOST_DID_LOCK_CSR, &result); 183eb188d0eSMatt Porter if ((result & 0xffff) != port->host_deviceid) 184eb188d0eSMatt Porter return -1; 185eb188d0eSMatt Porter 186eb188d0eSMatt Porter /* Set master port destid and init destid ctr */ 187eb188d0eSMatt Porter rio_local_set_device_id(port, port->host_deviceid); 188eb188d0eSMatt Porter 189eb188d0eSMatt Porter if (next_destid == port->host_deviceid) 190eb188d0eSMatt Porter next_destid++; 191eb188d0eSMatt Porter 192eb188d0eSMatt Porter return 0; 193eb188d0eSMatt Porter } 194eb188d0eSMatt Porter 195eb188d0eSMatt Porter /** 196eb188d0eSMatt Porter * rio_device_has_destid- Test if a device contains a destination ID register 197eb188d0eSMatt Porter * @port: Master port to issue transaction 198eb188d0eSMatt Porter * @src_ops: RIO device source operations 199eb188d0eSMatt Porter * @dst_ops: RIO device destination operations 200eb188d0eSMatt Porter * 201eb188d0eSMatt Porter * Checks the provided @src_ops and @dst_ops for the necessary transaction 202eb188d0eSMatt Porter * capabilities that indicate whether or not a device will implement a 203eb188d0eSMatt Porter * destination ID register. Returns 1 if true or 0 if false. 204eb188d0eSMatt Porter */ 205eb188d0eSMatt Porter static int rio_device_has_destid(struct rio_mport *port, int src_ops, 206eb188d0eSMatt Porter int dst_ops) 207eb188d0eSMatt Porter { 208fa78cc51SMatt Porter u32 mask = RIO_OPS_READ | RIO_OPS_WRITE | RIO_OPS_ATOMIC_TST_SWP | RIO_OPS_ATOMIC_INC | RIO_OPS_ATOMIC_DEC | RIO_OPS_ATOMIC_SET | RIO_OPS_ATOMIC_CLR; 209fa78cc51SMatt Porter 210fa78cc51SMatt Porter return !!((src_ops | dst_ops) & mask); 211eb188d0eSMatt Porter } 212eb188d0eSMatt Porter 213eb188d0eSMatt Porter /** 214eb188d0eSMatt Porter * rio_release_dev- Frees a RIO device struct 215eb188d0eSMatt Porter * @dev: LDM device associated with a RIO device struct 216eb188d0eSMatt Porter * 217eb188d0eSMatt Porter * Gets the RIO device struct associated a RIO device struct. 218eb188d0eSMatt Porter * The RIO device struct is freed. 219eb188d0eSMatt Porter */ 220eb188d0eSMatt Porter static void rio_release_dev(struct device *dev) 221eb188d0eSMatt Porter { 222eb188d0eSMatt Porter struct rio_dev *rdev; 223eb188d0eSMatt Porter 224eb188d0eSMatt Porter rdev = to_rio_dev(dev); 225eb188d0eSMatt Porter kfree(rdev); 226eb188d0eSMatt Porter } 227eb188d0eSMatt Porter 228eb188d0eSMatt Porter /** 229eb188d0eSMatt Porter * rio_is_switch- Tests if a RIO device has switch capabilities 230eb188d0eSMatt Porter * @rdev: RIO device 231eb188d0eSMatt Porter * 232eb188d0eSMatt Porter * Gets the RIO device Processing Element Features register 233eb188d0eSMatt Porter * contents and tests for switch capabilities. Returns 1 if 234eb188d0eSMatt Porter * the device is a switch or 0 if it is not a switch. 235eb188d0eSMatt Porter * The RIO device struct is freed. 236eb188d0eSMatt Porter */ 237eb188d0eSMatt Porter static int rio_is_switch(struct rio_dev *rdev) 238eb188d0eSMatt Porter { 239eb188d0eSMatt Porter if (rdev->pef & RIO_PEF_SWITCH) 240eb188d0eSMatt Porter return 1; 241eb188d0eSMatt Porter return 0; 242eb188d0eSMatt Porter } 243eb188d0eSMatt Porter 244eb188d0eSMatt Porter /** 245eb188d0eSMatt Porter * rio_route_set_ops- Sets routing operations for a particular vendor switch 246eb188d0eSMatt Porter * @rdev: RIO device 247eb188d0eSMatt Porter * 248eb188d0eSMatt Porter * Searches the RIO route ops table for known switch types. If the vid 249eb188d0eSMatt Porter * and did match a switch table entry, then set the add_entry() and 250eb188d0eSMatt Porter * get_entry() ops to the table entry values. 251eb188d0eSMatt Porter */ 252eb188d0eSMatt Porter static void rio_route_set_ops(struct rio_dev *rdev) 253eb188d0eSMatt Porter { 254eb188d0eSMatt Porter struct rio_route_ops *cur = __start_rio_route_ops; 255eb188d0eSMatt Porter struct rio_route_ops *end = __end_rio_route_ops; 256eb188d0eSMatt Porter 257eb188d0eSMatt Porter while (cur < end) { 258eb188d0eSMatt Porter if ((cur->vid == rdev->vid) && (cur->did == rdev->did)) { 259eb188d0eSMatt Porter pr_debug("RIO: adding routing ops for %s\n", rio_name(rdev)); 260eb188d0eSMatt Porter rdev->rswitch->add_entry = cur->add_hook; 261eb188d0eSMatt Porter rdev->rswitch->get_entry = cur->get_hook; 26207590ff0SAlexandre Bounine rdev->rswitch->clr_table = cur->clr_hook; 26307590ff0SAlexandre Bounine break; 264eb188d0eSMatt Porter } 265eb188d0eSMatt Porter cur++; 266eb188d0eSMatt Porter } 267eb188d0eSMatt Porter 26807590ff0SAlexandre Bounine if ((cur >= end) && (rdev->pef & RIO_PEF_STD_RT)) { 26907590ff0SAlexandre Bounine pr_debug("RIO: adding STD routing ops for %s\n", 27007590ff0SAlexandre Bounine rio_name(rdev)); 27107590ff0SAlexandre Bounine rdev->rswitch->add_entry = rio_std_route_add_entry; 27207590ff0SAlexandre Bounine rdev->rswitch->get_entry = rio_std_route_get_entry; 27307590ff0SAlexandre Bounine rdev->rswitch->clr_table = rio_std_route_clr_table; 27407590ff0SAlexandre Bounine } 27507590ff0SAlexandre Bounine 276eb188d0eSMatt Porter if (!rdev->rswitch->add_entry || !rdev->rswitch->get_entry) 277eb188d0eSMatt Porter printk(KERN_ERR "RIO: missing routing ops for %s\n", 278eb188d0eSMatt Porter rio_name(rdev)); 279eb188d0eSMatt Porter } 280eb188d0eSMatt Porter 281eb188d0eSMatt Porter /** 282e5cabeb3SAlexandre Bounine * rio_em_set_ops- Sets Error Managment operations for a particular vendor switch 283e5cabeb3SAlexandre Bounine * @rdev: RIO device 284e5cabeb3SAlexandre Bounine * 285e5cabeb3SAlexandre Bounine * Searches the RIO EM ops table for known switch types. If the vid 286e5cabeb3SAlexandre Bounine * and did match a switch table entry, then set the em_init() and 287e5cabeb3SAlexandre Bounine * em_handle() ops to the table entry values. 288e5cabeb3SAlexandre Bounine */ 289e5cabeb3SAlexandre Bounine static void rio_em_set_ops(struct rio_dev *rdev) 290e5cabeb3SAlexandre Bounine { 291e5cabeb3SAlexandre Bounine struct rio_em_ops *cur = __start_rio_em_ops; 292e5cabeb3SAlexandre Bounine struct rio_em_ops *end = __end_rio_em_ops; 293e5cabeb3SAlexandre Bounine 294e5cabeb3SAlexandre Bounine while (cur < end) { 295e5cabeb3SAlexandre Bounine if ((cur->vid == rdev->vid) && (cur->did == rdev->did)) { 296e5cabeb3SAlexandre Bounine pr_debug("RIO: adding EM ops for %s\n", rio_name(rdev)); 297e5cabeb3SAlexandre Bounine rdev->rswitch->em_init = cur->init_hook; 298e5cabeb3SAlexandre Bounine rdev->rswitch->em_handle = cur->handler_hook; 299e5cabeb3SAlexandre Bounine break; 300e5cabeb3SAlexandre Bounine } 301e5cabeb3SAlexandre Bounine cur++; 302e5cabeb3SAlexandre Bounine } 303e5cabeb3SAlexandre Bounine } 304e5cabeb3SAlexandre Bounine 305e5cabeb3SAlexandre Bounine /** 306eb188d0eSMatt Porter * rio_add_device- Adds a RIO device to the device model 307eb188d0eSMatt Porter * @rdev: RIO device 308eb188d0eSMatt Porter * 309eb188d0eSMatt Porter * Adds the RIO device to the global device list and adds the RIO 310eb188d0eSMatt Porter * device to the RIO device list. Creates the generic sysfs nodes 311eb188d0eSMatt Porter * for an RIO device. 312eb188d0eSMatt Porter */ 3135f28c520SYang Li static int __devinit rio_add_device(struct rio_dev *rdev) 314eb188d0eSMatt Porter { 3155f28c520SYang Li int err; 3165f28c520SYang Li 3175f28c520SYang Li err = device_add(&rdev->dev); 3185f28c520SYang Li if (err) 3195f28c520SYang Li return err; 320eb188d0eSMatt Porter 321eb188d0eSMatt Porter spin_lock(&rio_global_list_lock); 322eb188d0eSMatt Porter list_add_tail(&rdev->global_list, &rio_devices); 323eb188d0eSMatt Porter spin_unlock(&rio_global_list_lock); 324eb188d0eSMatt Porter 325eb188d0eSMatt Porter rio_create_sysfs_dev_files(rdev); 3265f28c520SYang Li 3275f28c520SYang Li return 0; 328eb188d0eSMatt Porter } 329eb188d0eSMatt Porter 330eb188d0eSMatt Porter /** 331eb188d0eSMatt Porter * rio_setup_device- Allocates and sets up a RIO device 332eb188d0eSMatt Porter * @net: RIO network 333eb188d0eSMatt Porter * @port: Master port to send transactions 334eb188d0eSMatt Porter * @destid: Current destination ID 335eb188d0eSMatt Porter * @hopcount: Current hopcount 336eb188d0eSMatt Porter * @do_enum: Enumeration/Discovery mode flag 337eb188d0eSMatt Porter * 338eb188d0eSMatt Porter * Allocates a RIO device and configures fields based on configuration 339eb188d0eSMatt Porter * space contents. If device has a destination ID register, a destination 340eb188d0eSMatt Porter * ID is either assigned in enumeration mode or read from configuration 341eb188d0eSMatt Porter * space in discovery mode. If the device has switch capabilities, then 342eb188d0eSMatt Porter * a switch is allocated and configured appropriately. Returns a pointer 343eb188d0eSMatt Porter * to a RIO device on success or NULL on failure. 344eb188d0eSMatt Porter * 345eb188d0eSMatt Porter */ 346181a6ff0SLi Yang static struct rio_dev __devinit *rio_setup_device(struct rio_net *net, 347eb188d0eSMatt Porter struct rio_mport *port, u16 destid, 348eb188d0eSMatt Porter u8 hopcount, int do_enum) 349eb188d0eSMatt Porter { 3505f28c520SYang Li int ret = 0; 351eb188d0eSMatt Porter struct rio_dev *rdev; 3525f28c520SYang Li struct rio_switch *rswitch = NULL; 353eb188d0eSMatt Porter int result, rdid; 354eb188d0eSMatt Porter 355dd00cc48SYoann Padioleau rdev = kzalloc(sizeof(struct rio_dev), GFP_KERNEL); 356eb188d0eSMatt Porter if (!rdev) 3575f28c520SYang Li return NULL; 358eb188d0eSMatt Porter 359eb188d0eSMatt Porter rdev->net = net; 360eb188d0eSMatt Porter rio_mport_read_config_32(port, destid, hopcount, RIO_DEV_ID_CAR, 361eb188d0eSMatt Porter &result); 362eb188d0eSMatt Porter rdev->did = result >> 16; 363eb188d0eSMatt Porter rdev->vid = result & 0xffff; 364eb188d0eSMatt Porter rio_mport_read_config_32(port, destid, hopcount, RIO_DEV_INFO_CAR, 365eb188d0eSMatt Porter &rdev->device_rev); 366eb188d0eSMatt Porter rio_mport_read_config_32(port, destid, hopcount, RIO_ASM_ID_CAR, 367eb188d0eSMatt Porter &result); 368eb188d0eSMatt Porter rdev->asm_did = result >> 16; 369eb188d0eSMatt Porter rdev->asm_vid = result & 0xffff; 370eb188d0eSMatt Porter rio_mport_read_config_32(port, destid, hopcount, RIO_ASM_INFO_CAR, 371eb188d0eSMatt Porter &result); 372eb188d0eSMatt Porter rdev->asm_rev = result >> 16; 373eb188d0eSMatt Porter rio_mport_read_config_32(port, destid, hopcount, RIO_PEF_CAR, 374eb188d0eSMatt Porter &rdev->pef); 375e5cabeb3SAlexandre Bounine if (rdev->pef & RIO_PEF_EXT_FEATURES) { 376eb188d0eSMatt Porter rdev->efptr = result & 0xffff; 377e5cabeb3SAlexandre Bounine rdev->phys_efptr = rio_mport_get_physefb(port, 0, destid, 378e5cabeb3SAlexandre Bounine hopcount); 379e5cabeb3SAlexandre Bounine 380e5cabeb3SAlexandre Bounine rdev->em_efptr = rio_mport_get_feature(port, 0, destid, 381e5cabeb3SAlexandre Bounine hopcount, RIO_EFB_ERR_MGMNT); 382e5cabeb3SAlexandre Bounine } 383eb188d0eSMatt Porter 384eb188d0eSMatt Porter rio_mport_read_config_32(port, destid, hopcount, RIO_SRC_OPS_CAR, 385eb188d0eSMatt Porter &rdev->src_ops); 386eb188d0eSMatt Porter rio_mport_read_config_32(port, destid, hopcount, RIO_DST_OPS_CAR, 387eb188d0eSMatt Porter &rdev->dst_ops); 388eb188d0eSMatt Porter 389c70555b0SAlexandre Bounine if (rio_device_has_destid(port, rdev->src_ops, rdev->dst_ops)) { 390c70555b0SAlexandre Bounine if (do_enum) { 391eb188d0eSMatt Porter rio_set_device_id(port, destid, hopcount, next_destid); 392eb188d0eSMatt Porter rdev->destid = next_destid++; 393eb188d0eSMatt Porter if (next_destid == port->host_deviceid) 394eb188d0eSMatt Porter next_destid++; 395eb188d0eSMatt Porter } else 396eb188d0eSMatt Porter rdev->destid = rio_get_device_id(port, destid, hopcount); 397c70555b0SAlexandre Bounine } else 398c70555b0SAlexandre Bounine /* Switch device has an associated destID */ 399c70555b0SAlexandre Bounine rdev->destid = RIO_INVALID_DESTID; 400eb188d0eSMatt Porter 401eb188d0eSMatt Porter /* If a PE has both switch and other functions, show it as a switch */ 402eb188d0eSMatt Porter if (rio_is_switch(rdev)) { 403eb188d0eSMatt Porter rio_mport_read_config_32(port, destid, hopcount, 404eb188d0eSMatt Porter RIO_SWP_INFO_CAR, &rdev->swpinfo); 40507590ff0SAlexandre Bounine rswitch = kzalloc(sizeof(struct rio_switch), GFP_KERNEL); 4065f28c520SYang Li if (!rswitch) 4075f28c520SYang Li goto cleanup; 408eb188d0eSMatt Porter rswitch->switchid = next_switchid; 409eb188d0eSMatt Porter rswitch->hopcount = hopcount; 410c70555b0SAlexandre Bounine rswitch->destid = destid; 411e5cabeb3SAlexandre Bounine rswitch->port_ok = 0; 412e0423236SZhang Wei rswitch->route_table = kzalloc(sizeof(u8)* 413e0423236SZhang Wei RIO_MAX_ROUTE_ENTRIES(port->sys_size), 414e0423236SZhang Wei GFP_KERNEL); 4155f28c520SYang Li if (!rswitch->route_table) 4165f28c520SYang Li goto cleanup; 417eb188d0eSMatt Porter /* Initialize switch route table */ 418e0423236SZhang Wei for (rdid = 0; rdid < RIO_MAX_ROUTE_ENTRIES(port->sys_size); 419e0423236SZhang Wei rdid++) 420eb188d0eSMatt Porter rswitch->route_table[rdid] = RIO_INVALID_ROUTE; 421eb188d0eSMatt Porter rdev->rswitch = rswitch; 422b53c7583SKay Sievers dev_set_name(&rdev->dev, "%02x:s:%04x", rdev->net->id, 423eb188d0eSMatt Porter rdev->rswitch->switchid); 424eb188d0eSMatt Porter rio_route_set_ops(rdev); 425e5cabeb3SAlexandre Bounine rio_em_set_ops(rdev); 426eb188d0eSMatt Porter 42707590ff0SAlexandre Bounine if (do_enum && rdev->rswitch->clr_table) 42807590ff0SAlexandre Bounine rdev->rswitch->clr_table(port, destid, hopcount, 42907590ff0SAlexandre Bounine RIO_GLOBAL_TABLE); 43007590ff0SAlexandre Bounine 431eb188d0eSMatt Porter list_add_tail(&rswitch->node, &rio_switches); 432eb188d0eSMatt Porter 433eb188d0eSMatt Porter } else 434b53c7583SKay Sievers dev_set_name(&rdev->dev, "%02x:e:%04x", rdev->net->id, 435eb188d0eSMatt Porter rdev->destid); 436eb188d0eSMatt Porter 437eb188d0eSMatt Porter rdev->dev.bus = &rio_bus_type; 438eb188d0eSMatt Porter 439eb188d0eSMatt Porter device_initialize(&rdev->dev); 440eb188d0eSMatt Porter rdev->dev.release = rio_release_dev; 441eb188d0eSMatt Porter rio_dev_get(rdev); 442eb188d0eSMatt Porter 443284901a9SYang Hongyang rdev->dma_mask = DMA_BIT_MASK(32); 444fa78cc51SMatt Porter rdev->dev.dma_mask = &rdev->dma_mask; 445284901a9SYang Hongyang rdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); 446eb188d0eSMatt Porter 447eb188d0eSMatt Porter if ((rdev->pef & RIO_PEF_INB_DOORBELL) && 448eb188d0eSMatt Porter (rdev->dst_ops & RIO_DST_OPS_DOORBELL)) 449eb188d0eSMatt Porter rio_init_dbell_res(&rdev->riores[RIO_DOORBELL_RESOURCE], 450eb188d0eSMatt Porter 0, 0xffff); 451eb188d0eSMatt Porter 4525f28c520SYang Li ret = rio_add_device(rdev); 4535f28c520SYang Li if (ret) 4545f28c520SYang Li goto cleanup; 455eb188d0eSMatt Porter 456eb188d0eSMatt Porter return rdev; 4575f28c520SYang Li 4585f28c520SYang Li cleanup: 4595f28c520SYang Li if (rswitch) { 4605f28c520SYang Li kfree(rswitch->route_table); 4615f28c520SYang Li kfree(rswitch); 4625f28c520SYang Li } 4635f28c520SYang Li kfree(rdev); 4645f28c520SYang Li return NULL; 465eb188d0eSMatt Porter } 466eb188d0eSMatt Porter 467eb188d0eSMatt Porter /** 468eb188d0eSMatt Porter * rio_sport_is_active- Tests if a switch port has an active connection. 469eb188d0eSMatt Porter * @port: Master port to send transaction 470eb188d0eSMatt Porter * @destid: Associated destination ID for switch 471eb188d0eSMatt Porter * @hopcount: Hopcount to reach switch 472eb188d0eSMatt Porter * @sport: Switch port number 473eb188d0eSMatt Porter * 474eb188d0eSMatt Porter * Reads the port error status CSR for a particular switch port to 475eb188d0eSMatt Porter * determine if the port has an active link. Returns 476e5cabeb3SAlexandre Bounine * %RIO_PORT_N_ERR_STS_PORT_OK if the port is active or %0 if it is 477eb188d0eSMatt Porter * inactive. 478eb188d0eSMatt Porter */ 479eb188d0eSMatt Porter static int 480eb188d0eSMatt Porter rio_sport_is_active(struct rio_mport *port, u16 destid, u8 hopcount, int sport) 481eb188d0eSMatt Porter { 482e5cabeb3SAlexandre Bounine u32 result = 0; 483eb188d0eSMatt Porter u32 ext_ftr_ptr; 484eb188d0eSMatt Porter 485e5cabeb3SAlexandre Bounine ext_ftr_ptr = rio_mport_get_efb(port, 0, destid, hopcount, 0); 486eb188d0eSMatt Porter 487e5cabeb3SAlexandre Bounine while (ext_ftr_ptr) { 488e5cabeb3SAlexandre Bounine rio_mport_read_config_32(port, destid, hopcount, 489e5cabeb3SAlexandre Bounine ext_ftr_ptr, &result); 490e5cabeb3SAlexandre Bounine result = RIO_GET_BLOCK_ID(result); 491e5cabeb3SAlexandre Bounine if ((result == RIO_EFB_SER_EP_FREE_ID) || 492e5cabeb3SAlexandre Bounine (result == RIO_EFB_SER_EP_FREE_ID_V13P) || 493e5cabeb3SAlexandre Bounine (result == RIO_EFB_SER_EP_FREC_ID)) 494eb188d0eSMatt Porter break; 495e5cabeb3SAlexandre Bounine 496e5cabeb3SAlexandre Bounine ext_ftr_ptr = rio_mport_get_efb(port, 0, destid, hopcount, 497e5cabeb3SAlexandre Bounine ext_ftr_ptr); 498e5cabeb3SAlexandre Bounine } 499eb188d0eSMatt Porter 500eb188d0eSMatt Porter if (ext_ftr_ptr) 501eb188d0eSMatt Porter rio_mport_read_config_32(port, destid, hopcount, 502eb188d0eSMatt Porter ext_ftr_ptr + 503eb188d0eSMatt Porter RIO_PORT_N_ERR_STS_CSR(sport), 504eb188d0eSMatt Porter &result); 505eb188d0eSMatt Porter 506e5cabeb3SAlexandre Bounine return result & RIO_PORT_N_ERR_STS_PORT_OK; 507eb188d0eSMatt Porter } 508eb188d0eSMatt Porter 509eb188d0eSMatt Porter /** 510818a04a0SAlexandre Bounine * rio_lock_device - Acquires host device lock for specified device 511818a04a0SAlexandre Bounine * @port: Master port to send transaction 512818a04a0SAlexandre Bounine * @destid: Destination ID for device/switch 513818a04a0SAlexandre Bounine * @hopcount: Hopcount to reach switch 514818a04a0SAlexandre Bounine * @wait_ms: Max wait time in msec (0 = no timeout) 515818a04a0SAlexandre Bounine * 516818a04a0SAlexandre Bounine * Attepts to acquire host device lock for specified device 517818a04a0SAlexandre Bounine * Returns 0 if device lock acquired or EINVAL if timeout expires. 518818a04a0SAlexandre Bounine */ 519818a04a0SAlexandre Bounine static int 520818a04a0SAlexandre Bounine rio_lock_device(struct rio_mport *port, u16 destid, u8 hopcount, int wait_ms) 521818a04a0SAlexandre Bounine { 522818a04a0SAlexandre Bounine u32 result; 523818a04a0SAlexandre Bounine int tcnt = 0; 524818a04a0SAlexandre Bounine 525818a04a0SAlexandre Bounine /* Attempt to acquire device lock */ 526818a04a0SAlexandre Bounine rio_mport_write_config_32(port, destid, hopcount, 527818a04a0SAlexandre Bounine RIO_HOST_DID_LOCK_CSR, port->host_deviceid); 528818a04a0SAlexandre Bounine rio_mport_read_config_32(port, destid, hopcount, 529818a04a0SAlexandre Bounine RIO_HOST_DID_LOCK_CSR, &result); 530818a04a0SAlexandre Bounine 531818a04a0SAlexandre Bounine while (result != port->host_deviceid) { 532818a04a0SAlexandre Bounine if (wait_ms != 0 && tcnt == wait_ms) { 533818a04a0SAlexandre Bounine pr_debug("RIO: timeout when locking device %x:%x\n", 534818a04a0SAlexandre Bounine destid, hopcount); 535818a04a0SAlexandre Bounine return -EINVAL; 536818a04a0SAlexandre Bounine } 537818a04a0SAlexandre Bounine 538818a04a0SAlexandre Bounine /* Delay a bit */ 539818a04a0SAlexandre Bounine mdelay(1); 540818a04a0SAlexandre Bounine tcnt++; 541818a04a0SAlexandre Bounine /* Try to acquire device lock again */ 542818a04a0SAlexandre Bounine rio_mport_write_config_32(port, destid, 543818a04a0SAlexandre Bounine hopcount, 544818a04a0SAlexandre Bounine RIO_HOST_DID_LOCK_CSR, 545818a04a0SAlexandre Bounine port->host_deviceid); 546818a04a0SAlexandre Bounine rio_mport_read_config_32(port, destid, 547818a04a0SAlexandre Bounine hopcount, 548818a04a0SAlexandre Bounine RIO_HOST_DID_LOCK_CSR, &result); 549818a04a0SAlexandre Bounine } 550818a04a0SAlexandre Bounine 551818a04a0SAlexandre Bounine return 0; 552818a04a0SAlexandre Bounine } 553818a04a0SAlexandre Bounine 554818a04a0SAlexandre Bounine /** 555818a04a0SAlexandre Bounine * rio_unlock_device - Releases host device lock for specified device 556818a04a0SAlexandre Bounine * @port: Master port to send transaction 557818a04a0SAlexandre Bounine * @destid: Destination ID for device/switch 558818a04a0SAlexandre Bounine * @hopcount: Hopcount to reach switch 559818a04a0SAlexandre Bounine * 560818a04a0SAlexandre Bounine * Returns 0 if device lock released or EINVAL if fails. 561818a04a0SAlexandre Bounine */ 562818a04a0SAlexandre Bounine static int 563818a04a0SAlexandre Bounine rio_unlock_device(struct rio_mport *port, u16 destid, u8 hopcount) 564818a04a0SAlexandre Bounine { 565818a04a0SAlexandre Bounine u32 result; 566818a04a0SAlexandre Bounine 567818a04a0SAlexandre Bounine /* Release device lock */ 568818a04a0SAlexandre Bounine rio_mport_write_config_32(port, destid, 569818a04a0SAlexandre Bounine hopcount, 570818a04a0SAlexandre Bounine RIO_HOST_DID_LOCK_CSR, 571818a04a0SAlexandre Bounine port->host_deviceid); 572818a04a0SAlexandre Bounine rio_mport_read_config_32(port, destid, hopcount, 573818a04a0SAlexandre Bounine RIO_HOST_DID_LOCK_CSR, &result); 574818a04a0SAlexandre Bounine if ((result & 0xffff) != 0xffff) { 575818a04a0SAlexandre Bounine pr_debug("RIO: badness when releasing device lock %x:%x\n", 576818a04a0SAlexandre Bounine destid, hopcount); 577818a04a0SAlexandre Bounine return -EINVAL; 578818a04a0SAlexandre Bounine } 579818a04a0SAlexandre Bounine 580818a04a0SAlexandre Bounine return 0; 581818a04a0SAlexandre Bounine } 582818a04a0SAlexandre Bounine 583818a04a0SAlexandre Bounine /** 584eb188d0eSMatt Porter * rio_route_add_entry- Add a route entry to a switch routing table 585eb188d0eSMatt Porter * @mport: Master port to send transaction 586c70555b0SAlexandre Bounine * @rswitch: Switch device 587eb188d0eSMatt Porter * @table: Routing table ID 588eb188d0eSMatt Porter * @route_destid: Destination ID to be routed 589eb188d0eSMatt Porter * @route_port: Port number to be routed 590818a04a0SAlexandre Bounine * @lock: lock switch device flag 591eb188d0eSMatt Porter * 592eb188d0eSMatt Porter * Calls the switch specific add_entry() method to add a route entry 593eb188d0eSMatt Porter * on a switch. The route table can be specified using the @table 594eb188d0eSMatt Porter * argument if a switch has per port routing tables or the normal 595eb188d0eSMatt Porter * use is to specific all tables (or the global table) by passing 596eb188d0eSMatt Porter * %RIO_GLOBAL_TABLE in @table. Returns %0 on success or %-EINVAL 597eb188d0eSMatt Porter * on failure. 598eb188d0eSMatt Porter */ 599818a04a0SAlexandre Bounine static int 600818a04a0SAlexandre Bounine rio_route_add_entry(struct rio_mport *mport, struct rio_switch *rswitch, 601818a04a0SAlexandre Bounine u16 table, u16 route_destid, u8 route_port, int lock) 602eb188d0eSMatt Porter { 603818a04a0SAlexandre Bounine int rc; 604818a04a0SAlexandre Bounine 605818a04a0SAlexandre Bounine if (lock) { 606818a04a0SAlexandre Bounine rc = rio_lock_device(mport, rswitch->destid, 607818a04a0SAlexandre Bounine rswitch->hopcount, 1000); 608818a04a0SAlexandre Bounine if (rc) 609818a04a0SAlexandre Bounine return rc; 610818a04a0SAlexandre Bounine } 611818a04a0SAlexandre Bounine 612818a04a0SAlexandre Bounine rc = rswitch->add_entry(mport, rswitch->destid, 613c70555b0SAlexandre Bounine rswitch->hopcount, table, 614eb188d0eSMatt Porter route_destid, route_port); 615818a04a0SAlexandre Bounine if (lock) 616818a04a0SAlexandre Bounine rio_unlock_device(mport, rswitch->destid, rswitch->hopcount); 617818a04a0SAlexandre Bounine 618818a04a0SAlexandre Bounine return rc; 619eb188d0eSMatt Porter } 620eb188d0eSMatt Porter 621eb188d0eSMatt Porter /** 622eb188d0eSMatt Porter * rio_route_get_entry- Read a route entry in a switch routing table 623eb188d0eSMatt Porter * @mport: Master port to send transaction 624c70555b0SAlexandre Bounine * @rswitch: Switch device 625eb188d0eSMatt Porter * @table: Routing table ID 626eb188d0eSMatt Porter * @route_destid: Destination ID to be routed 627eb188d0eSMatt Porter * @route_port: Pointer to read port number into 628818a04a0SAlexandre Bounine * @lock: lock switch device flag 629eb188d0eSMatt Porter * 630eb188d0eSMatt Porter * Calls the switch specific get_entry() method to read a route entry 631eb188d0eSMatt Porter * in a switch. The route table can be specified using the @table 632eb188d0eSMatt Porter * argument if a switch has per port routing tables or the normal 633eb188d0eSMatt Porter * use is to specific all tables (or the global table) by passing 634eb188d0eSMatt Porter * %RIO_GLOBAL_TABLE in @table. Returns %0 on success or %-EINVAL 635eb188d0eSMatt Porter * on failure. 636eb188d0eSMatt Porter */ 637eb188d0eSMatt Porter static int 638c70555b0SAlexandre Bounine rio_route_get_entry(struct rio_mport *mport, struct rio_switch *rswitch, u16 table, 639818a04a0SAlexandre Bounine u16 route_destid, u8 *route_port, int lock) 640eb188d0eSMatt Porter { 641818a04a0SAlexandre Bounine int rc; 642818a04a0SAlexandre Bounine 643818a04a0SAlexandre Bounine if (lock) { 644818a04a0SAlexandre Bounine rc = rio_lock_device(mport, rswitch->destid, 645818a04a0SAlexandre Bounine rswitch->hopcount, 1000); 646818a04a0SAlexandre Bounine if (rc) 647818a04a0SAlexandre Bounine return rc; 648818a04a0SAlexandre Bounine } 649818a04a0SAlexandre Bounine 650818a04a0SAlexandre Bounine rc = rswitch->get_entry(mport, rswitch->destid, 651c70555b0SAlexandre Bounine rswitch->hopcount, table, 652eb188d0eSMatt Porter route_destid, route_port); 653818a04a0SAlexandre Bounine if (lock) 654818a04a0SAlexandre Bounine rio_unlock_device(mport, rswitch->destid, rswitch->hopcount); 655818a04a0SAlexandre Bounine 656818a04a0SAlexandre Bounine return rc; 657eb188d0eSMatt Porter } 658eb188d0eSMatt Porter 659eb188d0eSMatt Porter /** 660eb188d0eSMatt Porter * rio_get_host_deviceid_lock- Reads the Host Device ID Lock CSR on a device 661eb188d0eSMatt Porter * @port: Master port to send transaction 662eb188d0eSMatt Porter * @hopcount: Number of hops to the device 663eb188d0eSMatt Porter * 664eb188d0eSMatt Porter * Used during enumeration to read the Host Device ID Lock CSR on a 665eb188d0eSMatt Porter * RIO device. Returns the value of the lock register. 666eb188d0eSMatt Porter */ 667eb188d0eSMatt Porter static u16 rio_get_host_deviceid_lock(struct rio_mport *port, u8 hopcount) 668eb188d0eSMatt Porter { 669eb188d0eSMatt Porter u32 result; 670eb188d0eSMatt Porter 671e0423236SZhang Wei rio_mport_read_config_32(port, RIO_ANY_DESTID(port->sys_size), hopcount, 672eb188d0eSMatt Porter RIO_HOST_DID_LOCK_CSR, &result); 673eb188d0eSMatt Porter 674eb188d0eSMatt Porter return (u16) (result & 0xffff); 675eb188d0eSMatt Porter } 676eb188d0eSMatt Porter 677eb188d0eSMatt Porter /** 678eb188d0eSMatt Porter * rio_get_swpinfo_inport- Gets the ingress port number 679eb188d0eSMatt Porter * @mport: Master port to send transaction 680eb188d0eSMatt Porter * @destid: Destination ID associated with the switch 681eb188d0eSMatt Porter * @hopcount: Number of hops to the device 682eb188d0eSMatt Porter * 683eb188d0eSMatt Porter * Returns port number being used to access the switch device. 684eb188d0eSMatt Porter */ 685eb188d0eSMatt Porter static u8 686eb188d0eSMatt Porter rio_get_swpinfo_inport(struct rio_mport *mport, u16 destid, u8 hopcount) 687eb188d0eSMatt Porter { 688eb188d0eSMatt Porter u32 result; 689eb188d0eSMatt Porter 690eb188d0eSMatt Porter rio_mport_read_config_32(mport, destid, hopcount, RIO_SWP_INFO_CAR, 691eb188d0eSMatt Porter &result); 692eb188d0eSMatt Porter 693eb188d0eSMatt Porter return (u8) (result & 0xff); 694eb188d0eSMatt Porter } 695eb188d0eSMatt Porter 696eb188d0eSMatt Porter /** 697eb188d0eSMatt Porter * rio_get_swpinfo_tports- Gets total number of ports on the switch 698eb188d0eSMatt Porter * @mport: Master port to send transaction 699eb188d0eSMatt Porter * @destid: Destination ID associated with the switch 700eb188d0eSMatt Porter * @hopcount: Number of hops to the device 701eb188d0eSMatt Porter * 702eb188d0eSMatt Porter * Returns total numbers of ports implemented by the switch device. 703eb188d0eSMatt Porter */ 704eb188d0eSMatt Porter static u8 rio_get_swpinfo_tports(struct rio_mport *mport, u16 destid, 705eb188d0eSMatt Porter u8 hopcount) 706eb188d0eSMatt Porter { 707eb188d0eSMatt Porter u32 result; 708eb188d0eSMatt Porter 709eb188d0eSMatt Porter rio_mport_read_config_32(mport, destid, hopcount, RIO_SWP_INFO_CAR, 710eb188d0eSMatt Porter &result); 711eb188d0eSMatt Porter 712eb188d0eSMatt Porter return RIO_GET_TOTAL_PORTS(result); 713eb188d0eSMatt Porter } 714eb188d0eSMatt Porter 715eb188d0eSMatt Porter /** 716eb188d0eSMatt Porter * rio_net_add_mport- Add a master port to a RIO network 717eb188d0eSMatt Porter * @net: RIO network 718eb188d0eSMatt Porter * @port: Master port to add 719eb188d0eSMatt Porter * 720eb188d0eSMatt Porter * Adds a master port to the network list of associated master 721eb188d0eSMatt Porter * ports.. 722eb188d0eSMatt Porter */ 723eb188d0eSMatt Porter static void rio_net_add_mport(struct rio_net *net, struct rio_mport *port) 724eb188d0eSMatt Porter { 725eb188d0eSMatt Porter spin_lock(&rio_global_list_lock); 726eb188d0eSMatt Porter list_add_tail(&port->nnode, &net->mports); 727eb188d0eSMatt Porter spin_unlock(&rio_global_list_lock); 728eb188d0eSMatt Porter } 729eb188d0eSMatt Porter 730eb188d0eSMatt Porter /** 731eb188d0eSMatt Porter * rio_enum_peer- Recursively enumerate a RIO network through a master port 732eb188d0eSMatt Porter * @net: RIO network being enumerated 733eb188d0eSMatt Porter * @port: Master port to send transactions 734eb188d0eSMatt Porter * @hopcount: Number of hops into the network 735eb188d0eSMatt Porter * 736eb188d0eSMatt Porter * Recursively enumerates a RIO network. Transactions are sent via the 737eb188d0eSMatt Porter * master port passed in @port. 738eb188d0eSMatt Porter */ 739181a6ff0SLi Yang static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port, 740eb188d0eSMatt Porter u8 hopcount) 741eb188d0eSMatt Porter { 742eb188d0eSMatt Porter int port_num; 743eb188d0eSMatt Porter int num_ports; 744eb188d0eSMatt Porter int cur_destid; 745c70555b0SAlexandre Bounine int sw_destid; 746c70555b0SAlexandre Bounine int sw_inport; 747eb188d0eSMatt Porter struct rio_dev *rdev; 748eb188d0eSMatt Porter u16 destid; 749eb188d0eSMatt Porter int tmp; 750eb188d0eSMatt Porter 751eb188d0eSMatt Porter if (rio_get_host_deviceid_lock(port, hopcount) == port->host_deviceid) { 752eb188d0eSMatt Porter pr_debug("RIO: PE already discovered by this host\n"); 753eb188d0eSMatt Porter /* 754eb188d0eSMatt Porter * Already discovered by this host. Add it as another 755eb188d0eSMatt Porter * master port for the current network. 756eb188d0eSMatt Porter */ 757eb188d0eSMatt Porter rio_net_add_mport(net, port); 758eb188d0eSMatt Porter return 0; 759eb188d0eSMatt Porter } 760eb188d0eSMatt Porter 761eb188d0eSMatt Porter /* Attempt to acquire device lock */ 762e0423236SZhang Wei rio_mport_write_config_32(port, RIO_ANY_DESTID(port->sys_size), 763e0423236SZhang Wei hopcount, 764eb188d0eSMatt Porter RIO_HOST_DID_LOCK_CSR, port->host_deviceid); 765eb188d0eSMatt Porter while ((tmp = rio_get_host_deviceid_lock(port, hopcount)) 766eb188d0eSMatt Porter < port->host_deviceid) { 767eb188d0eSMatt Porter /* Delay a bit */ 768eb188d0eSMatt Porter mdelay(1); 769eb188d0eSMatt Porter /* Attempt to acquire device lock again */ 770e0423236SZhang Wei rio_mport_write_config_32(port, RIO_ANY_DESTID(port->sys_size), 771e0423236SZhang Wei hopcount, 772eb188d0eSMatt Porter RIO_HOST_DID_LOCK_CSR, 773eb188d0eSMatt Porter port->host_deviceid); 774eb188d0eSMatt Porter } 775eb188d0eSMatt Porter 776eb188d0eSMatt Porter if (rio_get_host_deviceid_lock(port, hopcount) > port->host_deviceid) { 777eb188d0eSMatt Porter pr_debug( 778eb188d0eSMatt Porter "RIO: PE locked by a higher priority host...retreating\n"); 779eb188d0eSMatt Porter return -1; 780eb188d0eSMatt Porter } 781eb188d0eSMatt Porter 782eb188d0eSMatt Porter /* Setup new RIO device */ 783e0423236SZhang Wei rdev = rio_setup_device(net, port, RIO_ANY_DESTID(port->sys_size), 784e0423236SZhang Wei hopcount, 1); 785e0423236SZhang Wei if (rdev) { 786eb188d0eSMatt Porter /* Add device to the global and bus/net specific list. */ 787eb188d0eSMatt Porter list_add_tail(&rdev->net_list, &net->devices); 788eb188d0eSMatt Porter } else 789eb188d0eSMatt Porter return -1; 790eb188d0eSMatt Porter 791eb188d0eSMatt Porter if (rio_is_switch(rdev)) { 792eb188d0eSMatt Porter next_switchid++; 793e0423236SZhang Wei sw_inport = rio_get_swpinfo_inport(port, 794e0423236SZhang Wei RIO_ANY_DESTID(port->sys_size), hopcount); 795c70555b0SAlexandre Bounine rio_route_add_entry(port, rdev->rswitch, RIO_GLOBAL_TABLE, 796818a04a0SAlexandre Bounine port->host_deviceid, sw_inport, 0); 797c70555b0SAlexandre Bounine rdev->rswitch->route_table[port->host_deviceid] = sw_inport; 798eb188d0eSMatt Porter 799eb188d0eSMatt Porter for (destid = 0; destid < next_destid; destid++) { 800c70555b0SAlexandre Bounine if (destid == port->host_deviceid) 801c70555b0SAlexandre Bounine continue; 802c70555b0SAlexandre Bounine rio_route_add_entry(port, rdev->rswitch, RIO_GLOBAL_TABLE, 803818a04a0SAlexandre Bounine destid, sw_inport, 0); 804c70555b0SAlexandre Bounine rdev->rswitch->route_table[destid] = sw_inport; 805eb188d0eSMatt Porter } 806eb188d0eSMatt Porter 807eb188d0eSMatt Porter num_ports = 808e0423236SZhang Wei rio_get_swpinfo_tports(port, RIO_ANY_DESTID(port->sys_size), 809e0423236SZhang Wei hopcount); 810eb188d0eSMatt Porter pr_debug( 811eb188d0eSMatt Porter "RIO: found %s (vid %4.4x did %4.4x) with %d ports\n", 812eb188d0eSMatt Porter rio_name(rdev), rdev->vid, rdev->did, num_ports); 813c70555b0SAlexandre Bounine sw_destid = next_destid; 814eb188d0eSMatt Porter for (port_num = 0; port_num < num_ports; port_num++) { 815e5cabeb3SAlexandre Bounine if (sw_inport == port_num) { 816e5cabeb3SAlexandre Bounine rdev->rswitch->port_ok |= (1 << port_num); 817eb188d0eSMatt Porter continue; 818e5cabeb3SAlexandre Bounine } 819eb188d0eSMatt Porter 820eb188d0eSMatt Porter cur_destid = next_destid; 821eb188d0eSMatt Porter 822eb188d0eSMatt Porter if (rio_sport_is_active 823e0423236SZhang Wei (port, RIO_ANY_DESTID(port->sys_size), hopcount, 824e0423236SZhang Wei port_num)) { 825eb188d0eSMatt Porter pr_debug( 826eb188d0eSMatt Porter "RIO: scanning device on port %d\n", 827eb188d0eSMatt Porter port_num); 828e5cabeb3SAlexandre Bounine rdev->rswitch->port_ok |= (1 << port_num); 829c70555b0SAlexandre Bounine rio_route_add_entry(port, rdev->rswitch, 830eb188d0eSMatt Porter RIO_GLOBAL_TABLE, 831e0423236SZhang Wei RIO_ANY_DESTID(port->sys_size), 832818a04a0SAlexandre Bounine port_num, 0); 833eb188d0eSMatt Porter 834eb188d0eSMatt Porter if (rio_enum_peer(net, port, hopcount + 1) < 0) 835eb188d0eSMatt Porter return -1; 836eb188d0eSMatt Porter 837eb188d0eSMatt Porter /* Update routing tables */ 838eb188d0eSMatt Porter if (next_destid > cur_destid) { 839eb188d0eSMatt Porter for (destid = cur_destid; 840eb188d0eSMatt Porter destid < next_destid; destid++) { 841c70555b0SAlexandre Bounine if (destid == port->host_deviceid) 842c70555b0SAlexandre Bounine continue; 843c70555b0SAlexandre Bounine rio_route_add_entry(port, rdev->rswitch, 844eb188d0eSMatt Porter RIO_GLOBAL_TABLE, 845eb188d0eSMatt Porter destid, 846818a04a0SAlexandre Bounine port_num, 847818a04a0SAlexandre Bounine 0); 848eb188d0eSMatt Porter rdev->rswitch-> 849eb188d0eSMatt Porter route_table[destid] = 850eb188d0eSMatt Porter port_num; 851eb188d0eSMatt Porter } 852eb188d0eSMatt Porter } 853e5cabeb3SAlexandre Bounine } else { 854e5cabeb3SAlexandre Bounine /* If switch supports Error Management, 855e5cabeb3SAlexandre Bounine * set PORT_LOCKOUT bit for unused port 856e5cabeb3SAlexandre Bounine */ 857e5cabeb3SAlexandre Bounine if (rdev->em_efptr) 858e5cabeb3SAlexandre Bounine rio_set_port_lockout(rdev, port_num, 1); 859e5cabeb3SAlexandre Bounine 860e5cabeb3SAlexandre Bounine rdev->rswitch->port_ok &= ~(1 << port_num); 861eb188d0eSMatt Porter } 862eb188d0eSMatt Porter } 863c70555b0SAlexandre Bounine 864e5cabeb3SAlexandre Bounine /* Direct Port-write messages to the enumeratiing host */ 865e5cabeb3SAlexandre Bounine if ((rdev->src_ops & RIO_SRC_OPS_PORT_WRITE) && 866e5cabeb3SAlexandre Bounine (rdev->em_efptr)) { 867e5cabeb3SAlexandre Bounine rio_write_config_32(rdev, 868e5cabeb3SAlexandre Bounine rdev->em_efptr + RIO_EM_PW_TGT_DEVID, 869e5cabeb3SAlexandre Bounine (port->host_deviceid << 16) | 870e5cabeb3SAlexandre Bounine (port->sys_size << 15)); 871e5cabeb3SAlexandre Bounine } 872e5cabeb3SAlexandre Bounine 873e5cabeb3SAlexandre Bounine rio_init_em(rdev); 874e5cabeb3SAlexandre Bounine 875c70555b0SAlexandre Bounine /* Check for empty switch */ 876c70555b0SAlexandre Bounine if (next_destid == sw_destid) { 877c70555b0SAlexandre Bounine next_destid++; 878c70555b0SAlexandre Bounine if (next_destid == port->host_deviceid) 879c70555b0SAlexandre Bounine next_destid++; 880c70555b0SAlexandre Bounine } 881c70555b0SAlexandre Bounine 882c70555b0SAlexandre Bounine rdev->rswitch->destid = sw_destid; 883eb188d0eSMatt Porter } else 884eb188d0eSMatt Porter pr_debug("RIO: found %s (vid %4.4x did %4.4x)\n", 885eb188d0eSMatt Porter rio_name(rdev), rdev->vid, rdev->did); 886eb188d0eSMatt Porter 887eb188d0eSMatt Porter return 0; 888eb188d0eSMatt Porter } 889eb188d0eSMatt Porter 890eb188d0eSMatt Porter /** 891eb188d0eSMatt Porter * rio_enum_complete- Tests if enumeration of a network is complete 892eb188d0eSMatt Porter * @port: Master port to send transaction 893eb188d0eSMatt Porter * 894e5cabeb3SAlexandre Bounine * Tests the Component Tag CSR for non-zero value (enumeration 895e5cabeb3SAlexandre Bounine * complete flag). Return %1 if enumeration is complete or %0 if 896eb188d0eSMatt Porter * enumeration is incomplete. 897eb188d0eSMatt Porter */ 898eb188d0eSMatt Porter static int rio_enum_complete(struct rio_mport *port) 899eb188d0eSMatt Porter { 900eb188d0eSMatt Porter u32 tag_csr; 901eb188d0eSMatt Porter 902eb188d0eSMatt Porter rio_local_read_config_32(port, RIO_COMPONENT_TAG_CSR, &tag_csr); 903e5cabeb3SAlexandre Bounine return (tag_csr & 0xffff) ? 1 : 0; 904eb188d0eSMatt Porter } 905eb188d0eSMatt Porter 906eb188d0eSMatt Porter /** 907eb188d0eSMatt Porter * rio_disc_peer- Recursively discovers a RIO network through a master port 908eb188d0eSMatt Porter * @net: RIO network being discovered 909eb188d0eSMatt Porter * @port: Master port to send transactions 910eb188d0eSMatt Porter * @destid: Current destination ID in network 911eb188d0eSMatt Porter * @hopcount: Number of hops into the network 912eb188d0eSMatt Porter * 913eb188d0eSMatt Porter * Recursively discovers a RIO network. Transactions are sent via the 914eb188d0eSMatt Porter * master port passed in @port. 915eb188d0eSMatt Porter */ 916181a6ff0SLi Yang static int __devinit 917eb188d0eSMatt Porter rio_disc_peer(struct rio_net *net, struct rio_mport *port, u16 destid, 918eb188d0eSMatt Porter u8 hopcount) 919eb188d0eSMatt Porter { 920eb188d0eSMatt Porter u8 port_num, route_port; 921eb188d0eSMatt Porter int num_ports; 922eb188d0eSMatt Porter struct rio_dev *rdev; 923eb188d0eSMatt Porter u16 ndestid; 924eb188d0eSMatt Porter 925eb188d0eSMatt Porter /* Setup new RIO device */ 926eb188d0eSMatt Porter if ((rdev = rio_setup_device(net, port, destid, hopcount, 0))) { 927eb188d0eSMatt Porter /* Add device to the global and bus/net specific list. */ 928eb188d0eSMatt Porter list_add_tail(&rdev->net_list, &net->devices); 929eb188d0eSMatt Porter } else 930eb188d0eSMatt Porter return -1; 931eb188d0eSMatt Porter 932eb188d0eSMatt Porter if (rio_is_switch(rdev)) { 933eb188d0eSMatt Porter next_switchid++; 934eb188d0eSMatt Porter 935eb188d0eSMatt Porter /* Associated destid is how we accessed this switch */ 936eb188d0eSMatt Porter rdev->rswitch->destid = destid; 937eb188d0eSMatt Porter 938eb188d0eSMatt Porter num_ports = rio_get_swpinfo_tports(port, destid, hopcount); 939eb188d0eSMatt Porter pr_debug( 940eb188d0eSMatt Porter "RIO: found %s (vid %4.4x did %4.4x) with %d ports\n", 941eb188d0eSMatt Porter rio_name(rdev), rdev->vid, rdev->did, num_ports); 942eb188d0eSMatt Porter for (port_num = 0; port_num < num_ports; port_num++) { 943eb188d0eSMatt Porter if (rio_get_swpinfo_inport(port, destid, hopcount) == 944eb188d0eSMatt Porter port_num) 945eb188d0eSMatt Porter continue; 946eb188d0eSMatt Porter 947eb188d0eSMatt Porter if (rio_sport_is_active 948eb188d0eSMatt Porter (port, destid, hopcount, port_num)) { 949eb188d0eSMatt Porter pr_debug( 950eb188d0eSMatt Porter "RIO: scanning device on port %d\n", 951eb188d0eSMatt Porter port_num); 952818a04a0SAlexandre Bounine 953818a04a0SAlexandre Bounine rio_lock_device(port, destid, hopcount, 1000); 954818a04a0SAlexandre Bounine 955e0423236SZhang Wei for (ndestid = 0; 956e0423236SZhang Wei ndestid < RIO_ANY_DESTID(port->sys_size); 957eb188d0eSMatt Porter ndestid++) { 958c70555b0SAlexandre Bounine rio_route_get_entry(port, rdev->rswitch, 959eb188d0eSMatt Porter RIO_GLOBAL_TABLE, 960eb188d0eSMatt Porter ndestid, 961818a04a0SAlexandre Bounine &route_port, 0); 962eb188d0eSMatt Porter if (route_port == port_num) 963eb188d0eSMatt Porter break; 964eb188d0eSMatt Porter } 965eb188d0eSMatt Porter 966818a04a0SAlexandre Bounine rio_unlock_device(port, destid, hopcount); 967eb188d0eSMatt Porter if (rio_disc_peer 968eb188d0eSMatt Porter (net, port, ndestid, hopcount + 1) < 0) 969eb188d0eSMatt Porter return -1; 970eb188d0eSMatt Porter } 971eb188d0eSMatt Porter } 972eb188d0eSMatt Porter } else 973eb188d0eSMatt Porter pr_debug("RIO: found %s (vid %4.4x did %4.4x)\n", 974eb188d0eSMatt Porter rio_name(rdev), rdev->vid, rdev->did); 975eb188d0eSMatt Porter 976eb188d0eSMatt Porter return 0; 977eb188d0eSMatt Porter } 978eb188d0eSMatt Porter 979eb188d0eSMatt Porter /** 980eb188d0eSMatt Porter * rio_mport_is_active- Tests if master port link is active 981eb188d0eSMatt Porter * @port: Master port to test 982eb188d0eSMatt Porter * 983eb188d0eSMatt Porter * Reads the port error status CSR for the master port to 984eb188d0eSMatt Porter * determine if the port has an active link. Returns 985e5cabeb3SAlexandre Bounine * %RIO_PORT_N_ERR_STS_PORT_OK if the master port is active 986eb188d0eSMatt Porter * or %0 if it is inactive. 987eb188d0eSMatt Porter */ 988eb188d0eSMatt Porter static int rio_mport_is_active(struct rio_mport *port) 989eb188d0eSMatt Porter { 990eb188d0eSMatt Porter u32 result = 0; 991eb188d0eSMatt Porter u32 ext_ftr_ptr; 992eb188d0eSMatt Porter int *entry = rio_mport_phys_table; 993eb188d0eSMatt Porter 994eb188d0eSMatt Porter do { 995eb188d0eSMatt Porter if ((ext_ftr_ptr = 996eb188d0eSMatt Porter rio_mport_get_feature(port, 1, 0, 0, *entry))) 997eb188d0eSMatt Porter break; 998eb188d0eSMatt Porter } while (*++entry >= 0); 999eb188d0eSMatt Porter 1000eb188d0eSMatt Porter if (ext_ftr_ptr) 1001eb188d0eSMatt Porter rio_local_read_config_32(port, 1002eb188d0eSMatt Porter ext_ftr_ptr + 1003eb188d0eSMatt Porter RIO_PORT_N_ERR_STS_CSR(port->index), 1004eb188d0eSMatt Porter &result); 1005eb188d0eSMatt Porter 1006e5cabeb3SAlexandre Bounine return result & RIO_PORT_N_ERR_STS_PORT_OK; 1007eb188d0eSMatt Porter } 1008eb188d0eSMatt Porter 1009eb188d0eSMatt Porter /** 1010eb188d0eSMatt Porter * rio_alloc_net- Allocate and configure a new RIO network 1011eb188d0eSMatt Porter * @port: Master port associated with the RIO network 1012eb188d0eSMatt Porter * 1013eb188d0eSMatt Porter * Allocates a RIO network structure, initializes per-network 1014eb188d0eSMatt Porter * list heads, and adds the associated master port to the 1015eb188d0eSMatt Porter * network list of associated master ports. Returns a 1016eb188d0eSMatt Porter * RIO network pointer on success or %NULL on failure. 1017eb188d0eSMatt Porter */ 1018eb188d0eSMatt Porter static struct rio_net __devinit *rio_alloc_net(struct rio_mport *port) 1019eb188d0eSMatt Porter { 1020eb188d0eSMatt Porter struct rio_net *net; 1021eb188d0eSMatt Porter 1022dd00cc48SYoann Padioleau net = kzalloc(sizeof(struct rio_net), GFP_KERNEL); 1023eb188d0eSMatt Porter if (net) { 1024eb188d0eSMatt Porter INIT_LIST_HEAD(&net->node); 1025eb188d0eSMatt Porter INIT_LIST_HEAD(&net->devices); 1026eb188d0eSMatt Porter INIT_LIST_HEAD(&net->mports); 1027eb188d0eSMatt Porter list_add_tail(&port->nnode, &net->mports); 1028eb188d0eSMatt Porter net->hport = port; 1029eb188d0eSMatt Porter net->id = next_net++; 1030eb188d0eSMatt Porter } 1031eb188d0eSMatt Porter return net; 1032eb188d0eSMatt Porter } 1033eb188d0eSMatt Porter 1034eb188d0eSMatt Porter /** 1035c70555b0SAlexandre Bounine * rio_update_route_tables- Updates route tables in switches 1036c70555b0SAlexandre Bounine * @port: Master port associated with the RIO network 1037c70555b0SAlexandre Bounine * 1038c70555b0SAlexandre Bounine * For each enumerated device, ensure that each switch in a system 1039c70555b0SAlexandre Bounine * has correct routing entries. Add routes for devices that where 1040c70555b0SAlexandre Bounine * unknown dirung the first enumeration pass through the switch. 1041c70555b0SAlexandre Bounine */ 1042c70555b0SAlexandre Bounine static void rio_update_route_tables(struct rio_mport *port) 1043c70555b0SAlexandre Bounine { 1044c70555b0SAlexandre Bounine struct rio_dev *rdev; 1045c70555b0SAlexandre Bounine struct rio_switch *rswitch; 1046c70555b0SAlexandre Bounine u8 sport; 1047c70555b0SAlexandre Bounine u16 destid; 1048c70555b0SAlexandre Bounine 1049c70555b0SAlexandre Bounine list_for_each_entry(rdev, &rio_devices, global_list) { 1050c70555b0SAlexandre Bounine 1051c70555b0SAlexandre Bounine destid = (rio_is_switch(rdev))?rdev->rswitch->destid:rdev->destid; 1052c70555b0SAlexandre Bounine 1053c70555b0SAlexandre Bounine list_for_each_entry(rswitch, &rio_switches, node) { 1054c70555b0SAlexandre Bounine 1055c70555b0SAlexandre Bounine if (rio_is_switch(rdev) && (rdev->rswitch == rswitch)) 1056c70555b0SAlexandre Bounine continue; 1057c70555b0SAlexandre Bounine 1058c70555b0SAlexandre Bounine if (RIO_INVALID_ROUTE == rswitch->route_table[destid]) { 105907590ff0SAlexandre Bounine /* Skip if destid ends in empty switch*/ 106007590ff0SAlexandre Bounine if (rswitch->destid == destid) 106107590ff0SAlexandre Bounine continue; 1062c70555b0SAlexandre Bounine 1063c70555b0SAlexandre Bounine sport = rio_get_swpinfo_inport(port, 1064c70555b0SAlexandre Bounine rswitch->destid, rswitch->hopcount); 1065c70555b0SAlexandre Bounine 1066c70555b0SAlexandre Bounine if (rswitch->add_entry) { 1067818a04a0SAlexandre Bounine rio_route_add_entry(port, rswitch, 1068818a04a0SAlexandre Bounine RIO_GLOBAL_TABLE, destid, 1069818a04a0SAlexandre Bounine sport, 0); 1070c70555b0SAlexandre Bounine rswitch->route_table[destid] = sport; 1071c70555b0SAlexandre Bounine } 1072c70555b0SAlexandre Bounine } 1073c70555b0SAlexandre Bounine } 1074c70555b0SAlexandre Bounine } 1075c70555b0SAlexandre Bounine } 1076c70555b0SAlexandre Bounine 1077c70555b0SAlexandre Bounine /** 1078e5cabeb3SAlexandre Bounine * rio_init_em - Initializes RIO Error Management (for switches) 1079e5cabeb3SAlexandre Bounine * @port: Master port associated with the RIO network 1080e5cabeb3SAlexandre Bounine * 1081e5cabeb3SAlexandre Bounine * For each enumerated switch, call device-specific error management 1082e5cabeb3SAlexandre Bounine * initialization routine (if supplied by the switch driver). 1083e5cabeb3SAlexandre Bounine */ 1084e5cabeb3SAlexandre Bounine static void rio_init_em(struct rio_dev *rdev) 1085e5cabeb3SAlexandre Bounine { 1086e5cabeb3SAlexandre Bounine if (rio_is_switch(rdev) && (rdev->em_efptr) && 1087e5cabeb3SAlexandre Bounine (rdev->rswitch->em_init)) { 1088e5cabeb3SAlexandre Bounine rdev->rswitch->em_init(rdev); 1089e5cabeb3SAlexandre Bounine } 1090e5cabeb3SAlexandre Bounine } 1091e5cabeb3SAlexandre Bounine 1092e5cabeb3SAlexandre Bounine /** 1093e5cabeb3SAlexandre Bounine * rio_pw_enable - Enables/disables port-write handling by a master port 1094e5cabeb3SAlexandre Bounine * @port: Master port associated with port-write handling 1095e5cabeb3SAlexandre Bounine * @enable: 1=enable, 0=disable 1096e5cabeb3SAlexandre Bounine */ 1097e5cabeb3SAlexandre Bounine static void rio_pw_enable(struct rio_mport *port, int enable) 1098e5cabeb3SAlexandre Bounine { 1099e5cabeb3SAlexandre Bounine if (port->ops->pwenable) 1100e5cabeb3SAlexandre Bounine port->ops->pwenable(port, enable); 1101e5cabeb3SAlexandre Bounine } 1102e5cabeb3SAlexandre Bounine 1103e5cabeb3SAlexandre Bounine /** 1104eb188d0eSMatt Porter * rio_enum_mport- Start enumeration through a master port 1105eb188d0eSMatt Porter * @mport: Master port to send transactions 1106eb188d0eSMatt Porter * 1107eb188d0eSMatt Porter * Starts the enumeration process. If somebody has enumerated our 1108eb188d0eSMatt Porter * master port device, then give up. If not and we have an active 1109eb188d0eSMatt Porter * link, then start recursive peer enumeration. Returns %0 if 1110eb188d0eSMatt Porter * enumeration succeeds or %-EBUSY if enumeration fails. 1111eb188d0eSMatt Porter */ 111237d33d15SAl Viro int __devinit rio_enum_mport(struct rio_mport *mport) 1113eb188d0eSMatt Porter { 1114eb188d0eSMatt Porter struct rio_net *net = NULL; 1115eb188d0eSMatt Porter int rc = 0; 1116eb188d0eSMatt Porter 1117eb188d0eSMatt Porter printk(KERN_INFO "RIO: enumerate master port %d, %s\n", mport->id, 1118eb188d0eSMatt Porter mport->name); 1119eb188d0eSMatt Porter /* If somebody else enumerated our master port device, bail. */ 1120eb188d0eSMatt Porter if (rio_enum_host(mport) < 0) { 1121eb188d0eSMatt Porter printk(KERN_INFO 1122eb188d0eSMatt Porter "RIO: master port %d device has been enumerated by a remote host\n", 1123eb188d0eSMatt Porter mport->id); 1124eb188d0eSMatt Porter rc = -EBUSY; 1125eb188d0eSMatt Porter goto out; 1126eb188d0eSMatt Porter } 1127eb188d0eSMatt Porter 1128eb188d0eSMatt Porter /* If master port has an active link, allocate net and enum peers */ 1129eb188d0eSMatt Porter if (rio_mport_is_active(mport)) { 1130eb188d0eSMatt Porter if (!(net = rio_alloc_net(mport))) { 1131eb188d0eSMatt Porter printk(KERN_ERR "RIO: failed to allocate new net\n"); 1132eb188d0eSMatt Porter rc = -ENOMEM; 1133eb188d0eSMatt Porter goto out; 1134eb188d0eSMatt Porter } 1135eb188d0eSMatt Porter if (rio_enum_peer(net, mport, 0) < 0) { 1136eb188d0eSMatt Porter /* A higher priority host won enumeration, bail. */ 1137eb188d0eSMatt Porter printk(KERN_INFO 1138eb188d0eSMatt Porter "RIO: master port %d device has lost enumeration to a remote host\n", 1139eb188d0eSMatt Porter mport->id); 1140eb188d0eSMatt Porter rio_clear_locks(mport); 1141eb188d0eSMatt Porter rc = -EBUSY; 1142eb188d0eSMatt Porter goto out; 1143eb188d0eSMatt Porter } 1144c70555b0SAlexandre Bounine rio_update_route_tables(mport); 1145eb188d0eSMatt Porter rio_clear_locks(mport); 1146e5cabeb3SAlexandre Bounine rio_pw_enable(mport, 1); 1147eb188d0eSMatt Porter } else { 1148eb188d0eSMatt Porter printk(KERN_INFO "RIO: master port %d link inactive\n", 1149eb188d0eSMatt Porter mport->id); 1150eb188d0eSMatt Porter rc = -EINVAL; 1151eb188d0eSMatt Porter } 1152eb188d0eSMatt Porter 1153eb188d0eSMatt Porter out: 1154eb188d0eSMatt Porter return rc; 1155eb188d0eSMatt Porter } 1156eb188d0eSMatt Porter 1157eb188d0eSMatt Porter /** 1158eb188d0eSMatt Porter * rio_build_route_tables- Generate route tables from switch route entries 1159eb188d0eSMatt Porter * 1160eb188d0eSMatt Porter * For each switch device, generate a route table by copying existing 1161eb188d0eSMatt Porter * route entries from the switch. 1162eb188d0eSMatt Porter */ 1163eb188d0eSMatt Porter static void rio_build_route_tables(void) 1164eb188d0eSMatt Porter { 1165eb188d0eSMatt Porter struct rio_dev *rdev; 1166eb188d0eSMatt Porter int i; 1167eb188d0eSMatt Porter u8 sport; 1168eb188d0eSMatt Porter 1169eb188d0eSMatt Porter list_for_each_entry(rdev, &rio_devices, global_list) 1170818a04a0SAlexandre Bounine if (rio_is_switch(rdev)) { 1171818a04a0SAlexandre Bounine rio_lock_device(rdev->net->hport, rdev->rswitch->destid, 1172818a04a0SAlexandre Bounine rdev->rswitch->hopcount, 1000); 1173e0423236SZhang Wei for (i = 0; 1174e0423236SZhang Wei i < RIO_MAX_ROUTE_ENTRIES(rdev->net->hport->sys_size); 1175e0423236SZhang Wei i++) { 1176eb188d0eSMatt Porter if (rio_route_get_entry 1177818a04a0SAlexandre Bounine (rdev->net->hport, rdev->rswitch, 1178818a04a0SAlexandre Bounine RIO_GLOBAL_TABLE, i, &sport, 0) < 0) 1179eb188d0eSMatt Porter continue; 1180eb188d0eSMatt Porter rdev->rswitch->route_table[i] = sport; 1181eb188d0eSMatt Porter } 1182818a04a0SAlexandre Bounine 1183818a04a0SAlexandre Bounine rio_unlock_device(rdev->net->hport, 1184818a04a0SAlexandre Bounine rdev->rswitch->destid, 1185818a04a0SAlexandre Bounine rdev->rswitch->hopcount); 1186818a04a0SAlexandre Bounine } 1187eb188d0eSMatt Porter } 1188eb188d0eSMatt Porter 1189eb188d0eSMatt Porter /** 1190eb188d0eSMatt Porter * rio_enum_timeout- Signal that enumeration timed out 1191eb188d0eSMatt Porter * @data: Address of timeout flag. 1192eb188d0eSMatt Porter * 1193eb188d0eSMatt Porter * When the enumeration complete timer expires, set a flag that 1194eb188d0eSMatt Porter * signals to the discovery process that enumeration did not 1195eb188d0eSMatt Porter * complete in a sane amount of time. 1196eb188d0eSMatt Porter */ 1197eb188d0eSMatt Porter static void rio_enum_timeout(unsigned long data) 1198eb188d0eSMatt Porter { 1199eb188d0eSMatt Porter /* Enumeration timed out, set flag */ 1200eb188d0eSMatt Porter *(int *)data = 1; 1201eb188d0eSMatt Porter } 1202eb188d0eSMatt Porter 1203eb188d0eSMatt Porter /** 1204eb188d0eSMatt Porter * rio_disc_mport- Start discovery through a master port 1205eb188d0eSMatt Porter * @mport: Master port to send transactions 1206eb188d0eSMatt Porter * 1207eb188d0eSMatt Porter * Starts the discovery process. If we have an active link, 1208eb188d0eSMatt Porter * then wait for the signal that enumeration is complete. 1209eb188d0eSMatt Porter * When enumeration completion is signaled, start recursive 1210eb188d0eSMatt Porter * peer discovery. Returns %0 if discovery succeeds or %-EBUSY 1211eb188d0eSMatt Porter * on failure. 1212eb188d0eSMatt Porter */ 121337d33d15SAl Viro int __devinit rio_disc_mport(struct rio_mport *mport) 1214eb188d0eSMatt Porter { 1215eb188d0eSMatt Porter struct rio_net *net = NULL; 1216eb188d0eSMatt Porter int enum_timeout_flag = 0; 1217eb188d0eSMatt Porter 1218eb188d0eSMatt Porter printk(KERN_INFO "RIO: discover master port %d, %s\n", mport->id, 1219eb188d0eSMatt Porter mport->name); 1220eb188d0eSMatt Porter 1221eb188d0eSMatt Porter /* If master port has an active link, allocate net and discover peers */ 1222eb188d0eSMatt Porter if (rio_mport_is_active(mport)) { 1223eb188d0eSMatt Porter if (!(net = rio_alloc_net(mport))) { 1224eb188d0eSMatt Porter printk(KERN_ERR "RIO: Failed to allocate new net\n"); 1225eb188d0eSMatt Porter goto bail; 1226eb188d0eSMatt Porter } 1227eb188d0eSMatt Porter 1228eb188d0eSMatt Porter pr_debug("RIO: wait for enumeration complete..."); 1229eb188d0eSMatt Porter 1230eb188d0eSMatt Porter rio_enum_timer.expires = 1231eb188d0eSMatt Porter jiffies + CONFIG_RAPIDIO_DISC_TIMEOUT * HZ; 1232eb188d0eSMatt Porter rio_enum_timer.data = (unsigned long)&enum_timeout_flag; 1233eb188d0eSMatt Porter add_timer(&rio_enum_timer); 1234eb188d0eSMatt Porter while (!rio_enum_complete(mport)) { 1235eb188d0eSMatt Porter mdelay(1); 1236eb188d0eSMatt Porter if (enum_timeout_flag) { 1237eb188d0eSMatt Porter del_timer_sync(&rio_enum_timer); 1238eb188d0eSMatt Porter goto timeout; 1239eb188d0eSMatt Porter } 1240eb188d0eSMatt Porter } 1241eb188d0eSMatt Porter del_timer_sync(&rio_enum_timer); 1242eb188d0eSMatt Porter 1243eb188d0eSMatt Porter pr_debug("done\n"); 1244818a04a0SAlexandre Bounine 1245818a04a0SAlexandre Bounine /* Read DestID assigned by enumerator */ 1246818a04a0SAlexandre Bounine rio_local_read_config_32(mport, RIO_DID_CSR, 1247818a04a0SAlexandre Bounine &mport->host_deviceid); 1248818a04a0SAlexandre Bounine mport->host_deviceid = RIO_GET_DID(mport->sys_size, 1249818a04a0SAlexandre Bounine mport->host_deviceid); 1250818a04a0SAlexandre Bounine 1251e0423236SZhang Wei if (rio_disc_peer(net, mport, RIO_ANY_DESTID(mport->sys_size), 1252e0423236SZhang Wei 0) < 0) { 1253eb188d0eSMatt Porter printk(KERN_INFO 1254eb188d0eSMatt Porter "RIO: master port %d device has failed discovery\n", 1255eb188d0eSMatt Porter mport->id); 1256eb188d0eSMatt Porter goto bail; 1257eb188d0eSMatt Porter } 1258eb188d0eSMatt Porter 1259eb188d0eSMatt Porter rio_build_route_tables(); 1260eb188d0eSMatt Porter } 1261eb188d0eSMatt Porter 1262eb188d0eSMatt Porter return 0; 1263eb188d0eSMatt Porter 1264eb188d0eSMatt Porter timeout: 1265eb188d0eSMatt Porter pr_debug("timeout\n"); 1266eb188d0eSMatt Porter bail: 1267eb188d0eSMatt Porter return -EBUSY; 1268eb188d0eSMatt Porter } 1269