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 * 11933af4a6SThomas Moll * Copyright 2009 Sysgo AG 12933af4a6SThomas Moll * Thomas Moll <thomas.moll@sysgo.com> 13933af4a6SThomas Moll * - Added Input- Output- enable functionality, to allow full communication 14933af4a6SThomas Moll * 15eb188d0eSMatt Porter * This program is free software; you can redistribute it and/or modify it 16eb188d0eSMatt Porter * under the terms of the GNU General Public License as published by the 17eb188d0eSMatt Porter * Free Software Foundation; either version 2 of the License, or (at your 18eb188d0eSMatt Porter * option) any later version. 19eb188d0eSMatt Porter */ 20eb188d0eSMatt Porter 21eb188d0eSMatt Porter #include <linux/types.h> 22eb188d0eSMatt Porter #include <linux/kernel.h> 23eb188d0eSMatt Porter 24eb188d0eSMatt Porter #include <linux/delay.h> 25fa78cc51SMatt Porter #include <linux/dma-mapping.h> 26eb188d0eSMatt Porter #include <linux/init.h> 27eb188d0eSMatt Porter #include <linux/rio.h> 28eb188d0eSMatt Porter #include <linux/rio_drv.h> 29eb188d0eSMatt Porter #include <linux/rio_ids.h> 30eb188d0eSMatt Porter #include <linux/rio_regs.h> 31eb188d0eSMatt Porter #include <linux/module.h> 32eb188d0eSMatt Porter #include <linux/spinlock.h> 33eb188d0eSMatt Porter #include <linux/timer.h> 34de25968cSTim Schmielau #include <linux/jiffies.h> 35de25968cSTim Schmielau #include <linux/slab.h> 36eb188d0eSMatt Porter 37eb188d0eSMatt Porter #include "rio.h" 38eb188d0eSMatt Porter 39eb188d0eSMatt Porter LIST_HEAD(rio_devices); 40eb188d0eSMatt Porter static LIST_HEAD(rio_switches); 41eb188d0eSMatt Porter 42eb188d0eSMatt Porter static void rio_enum_timeout(unsigned long); 43eb188d0eSMatt Porter 44e5cabeb3SAlexandre Bounine static void rio_init_em(struct rio_dev *rdev); 45e5cabeb3SAlexandre Bounine 46fa78cc51SMatt Porter DEFINE_SPINLOCK(rio_global_list_lock); 47fa78cc51SMatt Porter 48eb188d0eSMatt Porter static int next_destid = 0; 49eb188d0eSMatt Porter static int next_switchid = 0; 50eb188d0eSMatt Porter static int next_net = 0; 51e5cabeb3SAlexandre Bounine static int next_comptag; 52eb188d0eSMatt Porter 53eb188d0eSMatt Porter static struct timer_list rio_enum_timer = 54eb188d0eSMatt Porter TIMER_INITIALIZER(rio_enum_timeout, 0, 0); 55eb188d0eSMatt Porter 56eb188d0eSMatt Porter static int rio_mport_phys_table[] = { 57eb188d0eSMatt Porter RIO_EFB_PAR_EP_ID, 58eb188d0eSMatt Porter RIO_EFB_PAR_EP_REC_ID, 59eb188d0eSMatt Porter RIO_EFB_SER_EP_ID, 60eb188d0eSMatt Porter RIO_EFB_SER_EP_REC_ID, 61eb188d0eSMatt Porter -1, 62eb188d0eSMatt Porter }; 63eb188d0eSMatt Porter 64eb188d0eSMatt Porter /** 65eb188d0eSMatt Porter * rio_get_device_id - Get the base/extended device id for a device 66eb188d0eSMatt Porter * @port: RIO master port 67eb188d0eSMatt Porter * @destid: Destination ID of device 68eb188d0eSMatt Porter * @hopcount: Hopcount to device 69eb188d0eSMatt Porter * 70eb188d0eSMatt Porter * Reads the base/extended device id from a device. Returns the 71eb188d0eSMatt Porter * 8/16-bit device ID. 72eb188d0eSMatt Porter */ 73eb188d0eSMatt Porter static u16 rio_get_device_id(struct rio_mport *port, u16 destid, u8 hopcount) 74eb188d0eSMatt Porter { 75eb188d0eSMatt Porter u32 result; 76eb188d0eSMatt Porter 77eb188d0eSMatt Porter rio_mport_read_config_32(port, destid, hopcount, RIO_DID_CSR, &result); 78eb188d0eSMatt Porter 79e0423236SZhang Wei return RIO_GET_DID(port->sys_size, result); 80eb188d0eSMatt Porter } 81eb188d0eSMatt Porter 82eb188d0eSMatt Porter /** 83eb188d0eSMatt Porter * rio_set_device_id - Set the base/extended device id for a device 84eb188d0eSMatt Porter * @port: RIO master port 85eb188d0eSMatt Porter * @destid: Destination ID of device 86eb188d0eSMatt Porter * @hopcount: Hopcount to device 87eb188d0eSMatt Porter * @did: Device ID value to be written 88eb188d0eSMatt Porter * 89eb188d0eSMatt Porter * Writes the base/extended device id from a device. 90eb188d0eSMatt Porter */ 91fa78cc51SMatt Porter static void rio_set_device_id(struct rio_mport *port, u16 destid, u8 hopcount, u16 did) 92eb188d0eSMatt Porter { 93eb188d0eSMatt Porter rio_mport_write_config_32(port, destid, hopcount, RIO_DID_CSR, 94e0423236SZhang Wei RIO_SET_DID(port->sys_size, did)); 95eb188d0eSMatt Porter } 96eb188d0eSMatt Porter 97eb188d0eSMatt Porter /** 98eb188d0eSMatt Porter * rio_local_set_device_id - Set the base/extended device id for a port 99eb188d0eSMatt Porter * @port: RIO master port 100eb188d0eSMatt Porter * @did: Device ID value to be written 101eb188d0eSMatt Porter * 102eb188d0eSMatt Porter * Writes the base/extended device id from a device. 103eb188d0eSMatt Porter */ 104eb188d0eSMatt Porter static void rio_local_set_device_id(struct rio_mport *port, u16 did) 105eb188d0eSMatt Porter { 106e0423236SZhang Wei rio_local_write_config_32(port, RIO_DID_CSR, RIO_SET_DID(port->sys_size, 107e0423236SZhang Wei did)); 108eb188d0eSMatt Porter } 109eb188d0eSMatt Porter 110eb188d0eSMatt Porter /** 111eb188d0eSMatt Porter * rio_clear_locks- Release all host locks and signal enumeration complete 112eb188d0eSMatt Porter * @port: Master port to issue transaction 113eb188d0eSMatt Porter * 114eb188d0eSMatt Porter * Marks the component tag CSR on each device with the enumeration 115eb188d0eSMatt Porter * complete flag. When complete, it then release the host locks on 116eb188d0eSMatt Porter * each device. Returns 0 on success or %-EINVAL on failure. 117eb188d0eSMatt Porter */ 118eb188d0eSMatt Porter static int rio_clear_locks(struct rio_mport *port) 119eb188d0eSMatt Porter { 120eb188d0eSMatt Porter struct rio_dev *rdev; 121eb188d0eSMatt Porter u32 result; 122eb188d0eSMatt Porter int ret = 0; 123eb188d0eSMatt Porter 124e5cabeb3SAlexandre Bounine /* Assign component tag to all devices */ 125e5cabeb3SAlexandre Bounine next_comptag = 1; 126e5cabeb3SAlexandre Bounine rio_local_write_config_32(port, RIO_COMPONENT_TAG_CSR, next_comptag++); 127e5cabeb3SAlexandre Bounine 128e5cabeb3SAlexandre Bounine list_for_each_entry(rdev, &rio_devices, global_list) { 129e5cabeb3SAlexandre Bounine /* Mark device as discovered */ 130e5cabeb3SAlexandre Bounine rio_read_config_32(rdev, 131e5cabeb3SAlexandre Bounine rdev->phys_efptr + RIO_PORT_GEN_CTL_CSR, 132e5cabeb3SAlexandre Bounine &result); 133e5cabeb3SAlexandre Bounine rio_write_config_32(rdev, 134e5cabeb3SAlexandre Bounine rdev->phys_efptr + RIO_PORT_GEN_CTL_CSR, 135e5cabeb3SAlexandre Bounine result | RIO_PORT_GEN_DISCOVERED); 136e5cabeb3SAlexandre Bounine 137e5cabeb3SAlexandre Bounine rio_write_config_32(rdev, RIO_COMPONENT_TAG_CSR, next_comptag); 138e5cabeb3SAlexandre Bounine rdev->comp_tag = next_comptag++; 139e5cabeb3SAlexandre Bounine if (next_comptag >= 0x10000) { 140e5cabeb3SAlexandre Bounine pr_err("RIO: Component Tag Counter Overflow\n"); 141e5cabeb3SAlexandre Bounine break; 142e5cabeb3SAlexandre Bounine } 143e5cabeb3SAlexandre Bounine } 144eb188d0eSMatt Porter 145eb188d0eSMatt Porter /* Release host device id locks */ 146eb188d0eSMatt Porter rio_local_write_config_32(port, RIO_HOST_DID_LOCK_CSR, 147eb188d0eSMatt Porter port->host_deviceid); 148eb188d0eSMatt Porter rio_local_read_config_32(port, RIO_HOST_DID_LOCK_CSR, &result); 149eb188d0eSMatt Porter if ((result & 0xffff) != 0xffff) { 150eb188d0eSMatt Porter printk(KERN_INFO 151eb188d0eSMatt Porter "RIO: badness when releasing host lock on master port, result %8.8x\n", 152eb188d0eSMatt Porter result); 153eb188d0eSMatt Porter ret = -EINVAL; 154eb188d0eSMatt Porter } 155eb188d0eSMatt Porter list_for_each_entry(rdev, &rio_devices, global_list) { 156eb188d0eSMatt Porter rio_write_config_32(rdev, RIO_HOST_DID_LOCK_CSR, 157eb188d0eSMatt Porter port->host_deviceid); 158eb188d0eSMatt Porter rio_read_config_32(rdev, RIO_HOST_DID_LOCK_CSR, &result); 159eb188d0eSMatt Porter if ((result & 0xffff) != 0xffff) { 160eb188d0eSMatt Porter printk(KERN_INFO 161eb188d0eSMatt Porter "RIO: badness when releasing host lock on vid %4.4x did %4.4x\n", 162eb188d0eSMatt Porter rdev->vid, rdev->did); 163eb188d0eSMatt Porter ret = -EINVAL; 164eb188d0eSMatt Porter } 165eb188d0eSMatt Porter } 166eb188d0eSMatt Porter 167eb188d0eSMatt Porter return ret; 168eb188d0eSMatt Porter } 169eb188d0eSMatt Porter 170eb188d0eSMatt Porter /** 171eb188d0eSMatt Porter * rio_enum_host- Set host lock and initialize host destination ID 172eb188d0eSMatt Porter * @port: Master port to issue transaction 173eb188d0eSMatt Porter * 174eb188d0eSMatt Porter * Sets the local host master port lock and destination ID register 175eb188d0eSMatt Porter * with the host device ID value. The host device ID value is provided 176eb188d0eSMatt Porter * by the platform. Returns %0 on success or %-1 on failure. 177eb188d0eSMatt Porter */ 178eb188d0eSMatt Porter static int rio_enum_host(struct rio_mport *port) 179eb188d0eSMatt Porter { 180eb188d0eSMatt Porter u32 result; 181eb188d0eSMatt Porter 182eb188d0eSMatt Porter /* Set master port host device id lock */ 183eb188d0eSMatt Porter rio_local_write_config_32(port, RIO_HOST_DID_LOCK_CSR, 184eb188d0eSMatt Porter port->host_deviceid); 185eb188d0eSMatt Porter 186eb188d0eSMatt Porter rio_local_read_config_32(port, RIO_HOST_DID_LOCK_CSR, &result); 187eb188d0eSMatt Porter if ((result & 0xffff) != port->host_deviceid) 188eb188d0eSMatt Porter return -1; 189eb188d0eSMatt Porter 190eb188d0eSMatt Porter /* Set master port destid and init destid ctr */ 191eb188d0eSMatt Porter rio_local_set_device_id(port, port->host_deviceid); 192eb188d0eSMatt Porter 193eb188d0eSMatt Porter if (next_destid == port->host_deviceid) 194eb188d0eSMatt Porter next_destid++; 195eb188d0eSMatt Porter 196eb188d0eSMatt Porter return 0; 197eb188d0eSMatt Porter } 198eb188d0eSMatt Porter 199eb188d0eSMatt Porter /** 200eb188d0eSMatt Porter * rio_device_has_destid- Test if a device contains a destination ID register 201eb188d0eSMatt Porter * @port: Master port to issue transaction 202eb188d0eSMatt Porter * @src_ops: RIO device source operations 203eb188d0eSMatt Porter * @dst_ops: RIO device destination operations 204eb188d0eSMatt Porter * 205eb188d0eSMatt Porter * Checks the provided @src_ops and @dst_ops for the necessary transaction 206eb188d0eSMatt Porter * capabilities that indicate whether or not a device will implement a 207eb188d0eSMatt Porter * destination ID register. Returns 1 if true or 0 if false. 208eb188d0eSMatt Porter */ 209eb188d0eSMatt Porter static int rio_device_has_destid(struct rio_mport *port, int src_ops, 210eb188d0eSMatt Porter int dst_ops) 211eb188d0eSMatt Porter { 212fa78cc51SMatt 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; 213fa78cc51SMatt Porter 214fa78cc51SMatt Porter return !!((src_ops | dst_ops) & mask); 215eb188d0eSMatt Porter } 216eb188d0eSMatt Porter 217eb188d0eSMatt Porter /** 218eb188d0eSMatt Porter * rio_release_dev- Frees a RIO device struct 219eb188d0eSMatt Porter * @dev: LDM device associated with a RIO device struct 220eb188d0eSMatt Porter * 221eb188d0eSMatt Porter * Gets the RIO device struct associated a RIO device struct. 222eb188d0eSMatt Porter * The RIO device struct is freed. 223eb188d0eSMatt Porter */ 224eb188d0eSMatt Porter static void rio_release_dev(struct device *dev) 225eb188d0eSMatt Porter { 226eb188d0eSMatt Porter struct rio_dev *rdev; 227eb188d0eSMatt Porter 228eb188d0eSMatt Porter rdev = to_rio_dev(dev); 229eb188d0eSMatt Porter kfree(rdev); 230eb188d0eSMatt Porter } 231eb188d0eSMatt Porter 232eb188d0eSMatt Porter /** 233eb188d0eSMatt Porter * rio_is_switch- Tests if a RIO device has switch capabilities 234eb188d0eSMatt Porter * @rdev: RIO device 235eb188d0eSMatt Porter * 236eb188d0eSMatt Porter * Gets the RIO device Processing Element Features register 237eb188d0eSMatt Porter * contents and tests for switch capabilities. Returns 1 if 238eb188d0eSMatt Porter * the device is a switch or 0 if it is not a switch. 239eb188d0eSMatt Porter * The RIO device struct is freed. 240eb188d0eSMatt Porter */ 241eb188d0eSMatt Porter static int rio_is_switch(struct rio_dev *rdev) 242eb188d0eSMatt Porter { 243eb188d0eSMatt Porter if (rdev->pef & RIO_PEF_SWITCH) 244eb188d0eSMatt Porter return 1; 245eb188d0eSMatt Porter return 0; 246eb188d0eSMatt Porter } 247eb188d0eSMatt Porter 248eb188d0eSMatt Porter /** 249058f88d6SAlexandre Bounine * rio_switch_init - Sets switch operations for a particular vendor switch 250eb188d0eSMatt Porter * @rdev: RIO device 251058f88d6SAlexandre Bounine * @do_enum: Enumeration/Discovery mode flag 252eb188d0eSMatt Porter * 253058f88d6SAlexandre Bounine * Searches the RIO switch ops table for known switch types. If the vid 254058f88d6SAlexandre Bounine * and did match a switch table entry, then call switch initialization 255058f88d6SAlexandre Bounine * routine to setup switch-specific routines. 256eb188d0eSMatt Porter */ 257058f88d6SAlexandre Bounine static void rio_switch_init(struct rio_dev *rdev, int do_enum) 258eb188d0eSMatt Porter { 259058f88d6SAlexandre Bounine struct rio_switch_ops *cur = __start_rio_switch_ops; 260058f88d6SAlexandre Bounine struct rio_switch_ops *end = __end_rio_switch_ops; 261eb188d0eSMatt Porter 262eb188d0eSMatt Porter while (cur < end) { 263eb188d0eSMatt Porter if ((cur->vid == rdev->vid) && (cur->did == rdev->did)) { 264058f88d6SAlexandre Bounine pr_debug("RIO: calling init routine for %s\n", 265058f88d6SAlexandre Bounine rio_name(rdev)); 266058f88d6SAlexandre Bounine cur->init_hook(rdev, do_enum); 26707590ff0SAlexandre Bounine break; 268eb188d0eSMatt Porter } 269eb188d0eSMatt Porter cur++; 270eb188d0eSMatt Porter } 271eb188d0eSMatt Porter 27207590ff0SAlexandre Bounine if ((cur >= end) && (rdev->pef & RIO_PEF_STD_RT)) { 27307590ff0SAlexandre Bounine pr_debug("RIO: adding STD routing ops for %s\n", 27407590ff0SAlexandre Bounine rio_name(rdev)); 27507590ff0SAlexandre Bounine rdev->rswitch->add_entry = rio_std_route_add_entry; 27607590ff0SAlexandre Bounine rdev->rswitch->get_entry = rio_std_route_get_entry; 27707590ff0SAlexandre Bounine rdev->rswitch->clr_table = rio_std_route_clr_table; 27807590ff0SAlexandre Bounine } 27907590ff0SAlexandre Bounine 280eb188d0eSMatt Porter if (!rdev->rswitch->add_entry || !rdev->rswitch->get_entry) 281eb188d0eSMatt Porter printk(KERN_ERR "RIO: missing routing ops for %s\n", 282eb188d0eSMatt Porter rio_name(rdev)); 283eb188d0eSMatt Porter } 284eb188d0eSMatt Porter 285eb188d0eSMatt Porter /** 286eb188d0eSMatt Porter * rio_add_device- Adds a RIO device to the device model 287eb188d0eSMatt Porter * @rdev: RIO device 288eb188d0eSMatt Porter * 289eb188d0eSMatt Porter * Adds the RIO device to the global device list and adds the RIO 290eb188d0eSMatt Porter * device to the RIO device list. Creates the generic sysfs nodes 291eb188d0eSMatt Porter * for an RIO device. 292eb188d0eSMatt Porter */ 2935f28c520SYang Li static int __devinit rio_add_device(struct rio_dev *rdev) 294eb188d0eSMatt Porter { 2955f28c520SYang Li int err; 2965f28c520SYang Li 2975f28c520SYang Li err = device_add(&rdev->dev); 2985f28c520SYang Li if (err) 2995f28c520SYang Li return err; 300eb188d0eSMatt Porter 301eb188d0eSMatt Porter spin_lock(&rio_global_list_lock); 302eb188d0eSMatt Porter list_add_tail(&rdev->global_list, &rio_devices); 303eb188d0eSMatt Porter spin_unlock(&rio_global_list_lock); 304eb188d0eSMatt Porter 305eb188d0eSMatt Porter rio_create_sysfs_dev_files(rdev); 3065f28c520SYang Li 3075f28c520SYang Li return 0; 308eb188d0eSMatt Porter } 309eb188d0eSMatt Porter 310eb188d0eSMatt Porter /** 311933af4a6SThomas Moll * rio_enable_rx_tx_port - enable input reciever and output transmitter of 312933af4a6SThomas Moll * given port 313933af4a6SThomas Moll * @port: Master port associated with the RIO network 314933af4a6SThomas Moll * @local: local=1 select local port otherwise a far device is reached 315933af4a6SThomas Moll * @destid: Destination ID of the device to check host bit 316933af4a6SThomas Moll * @hopcount: Number of hops to reach the target 317933af4a6SThomas Moll * @port_num: Port (-number on switch) to enable on a far end device 318933af4a6SThomas Moll * 319933af4a6SThomas Moll * Returns 0 or 1 from on General Control Command and Status Register 320933af4a6SThomas Moll * (EXT_PTR+0x3C) 321933af4a6SThomas Moll */ 322933af4a6SThomas Moll inline int rio_enable_rx_tx_port(struct rio_mport *port, 323933af4a6SThomas Moll int local, u16 destid, 324933af4a6SThomas Moll u8 hopcount, u8 port_num) { 325933af4a6SThomas Moll #ifdef CONFIG_RAPIDIO_ENABLE_RX_TX_PORTS 326933af4a6SThomas Moll u32 regval; 327933af4a6SThomas Moll u32 ext_ftr_ptr; 328933af4a6SThomas Moll 329933af4a6SThomas Moll /* 330933af4a6SThomas Moll * enable rx input tx output port 331933af4a6SThomas Moll */ 332933af4a6SThomas Moll pr_debug("rio_enable_rx_tx_port(local = %d, destid = %d, hopcount = " 333933af4a6SThomas Moll "%d, port_num = %d)\n", local, destid, hopcount, port_num); 334933af4a6SThomas Moll 335933af4a6SThomas Moll ext_ftr_ptr = rio_mport_get_physefb(port, local, destid, hopcount); 336933af4a6SThomas Moll 337933af4a6SThomas Moll if (local) { 338933af4a6SThomas Moll rio_local_read_config_32(port, ext_ftr_ptr + 339933af4a6SThomas Moll RIO_PORT_N_CTL_CSR(0), 340933af4a6SThomas Moll ®val); 341933af4a6SThomas Moll } else { 342933af4a6SThomas Moll if (rio_mport_read_config_32(port, destid, hopcount, 343933af4a6SThomas Moll ext_ftr_ptr + RIO_PORT_N_CTL_CSR(port_num), ®val) < 0) 344933af4a6SThomas Moll return -EIO; 345933af4a6SThomas Moll } 346933af4a6SThomas Moll 347933af4a6SThomas Moll if (regval & RIO_PORT_N_CTL_P_TYP_SER) { 348933af4a6SThomas Moll /* serial */ 349933af4a6SThomas Moll regval = regval | RIO_PORT_N_CTL_EN_RX_SER 350933af4a6SThomas Moll | RIO_PORT_N_CTL_EN_TX_SER; 351933af4a6SThomas Moll } else { 352933af4a6SThomas Moll /* parallel */ 353933af4a6SThomas Moll regval = regval | RIO_PORT_N_CTL_EN_RX_PAR 354933af4a6SThomas Moll | RIO_PORT_N_CTL_EN_TX_PAR; 355933af4a6SThomas Moll } 356933af4a6SThomas Moll 357933af4a6SThomas Moll if (local) { 358933af4a6SThomas Moll rio_local_write_config_32(port, ext_ftr_ptr + 359933af4a6SThomas Moll RIO_PORT_N_CTL_CSR(0), regval); 360933af4a6SThomas Moll } else { 361933af4a6SThomas Moll if (rio_mport_write_config_32(port, destid, hopcount, 362933af4a6SThomas Moll ext_ftr_ptr + RIO_PORT_N_CTL_CSR(port_num), regval) < 0) 363933af4a6SThomas Moll return -EIO; 364933af4a6SThomas Moll } 365933af4a6SThomas Moll #endif 366933af4a6SThomas Moll return 0; 367933af4a6SThomas Moll } 368933af4a6SThomas Moll 369933af4a6SThomas Moll /** 370eb188d0eSMatt Porter * rio_setup_device- Allocates and sets up a RIO device 371eb188d0eSMatt Porter * @net: RIO network 372eb188d0eSMatt Porter * @port: Master port to send transactions 373eb188d0eSMatt Porter * @destid: Current destination ID 374eb188d0eSMatt Porter * @hopcount: Current hopcount 375eb188d0eSMatt Porter * @do_enum: Enumeration/Discovery mode flag 376eb188d0eSMatt Porter * 377eb188d0eSMatt Porter * Allocates a RIO device and configures fields based on configuration 378eb188d0eSMatt Porter * space contents. If device has a destination ID register, a destination 379eb188d0eSMatt Porter * ID is either assigned in enumeration mode or read from configuration 380eb188d0eSMatt Porter * space in discovery mode. If the device has switch capabilities, then 381eb188d0eSMatt Porter * a switch is allocated and configured appropriately. Returns a pointer 382eb188d0eSMatt Porter * to a RIO device on success or NULL on failure. 383eb188d0eSMatt Porter * 384eb188d0eSMatt Porter */ 385181a6ff0SLi Yang static struct rio_dev __devinit *rio_setup_device(struct rio_net *net, 386eb188d0eSMatt Porter struct rio_mport *port, u16 destid, 387eb188d0eSMatt Porter u8 hopcount, int do_enum) 388eb188d0eSMatt Porter { 3895f28c520SYang Li int ret = 0; 390eb188d0eSMatt Porter struct rio_dev *rdev; 3915f28c520SYang Li struct rio_switch *rswitch = NULL; 392eb188d0eSMatt Porter int result, rdid; 393eb188d0eSMatt Porter 394dd00cc48SYoann Padioleau rdev = kzalloc(sizeof(struct rio_dev), GFP_KERNEL); 395eb188d0eSMatt Porter if (!rdev) 3965f28c520SYang Li return NULL; 397eb188d0eSMatt Porter 398eb188d0eSMatt Porter rdev->net = net; 399eb188d0eSMatt Porter rio_mport_read_config_32(port, destid, hopcount, RIO_DEV_ID_CAR, 400eb188d0eSMatt Porter &result); 401eb188d0eSMatt Porter rdev->did = result >> 16; 402eb188d0eSMatt Porter rdev->vid = result & 0xffff; 403eb188d0eSMatt Porter rio_mport_read_config_32(port, destid, hopcount, RIO_DEV_INFO_CAR, 404eb188d0eSMatt Porter &rdev->device_rev); 405eb188d0eSMatt Porter rio_mport_read_config_32(port, destid, hopcount, RIO_ASM_ID_CAR, 406eb188d0eSMatt Porter &result); 407eb188d0eSMatt Porter rdev->asm_did = result >> 16; 408eb188d0eSMatt Porter rdev->asm_vid = result & 0xffff; 409eb188d0eSMatt Porter rio_mport_read_config_32(port, destid, hopcount, RIO_ASM_INFO_CAR, 410eb188d0eSMatt Porter &result); 411eb188d0eSMatt Porter rdev->asm_rev = result >> 16; 412eb188d0eSMatt Porter rio_mport_read_config_32(port, destid, hopcount, RIO_PEF_CAR, 413eb188d0eSMatt Porter &rdev->pef); 414e5cabeb3SAlexandre Bounine if (rdev->pef & RIO_PEF_EXT_FEATURES) { 415eb188d0eSMatt Porter rdev->efptr = result & 0xffff; 416e5cabeb3SAlexandre Bounine rdev->phys_efptr = rio_mport_get_physefb(port, 0, destid, 417e5cabeb3SAlexandre Bounine hopcount); 418e5cabeb3SAlexandre Bounine 419e5cabeb3SAlexandre Bounine rdev->em_efptr = rio_mport_get_feature(port, 0, destid, 420e5cabeb3SAlexandre Bounine hopcount, RIO_EFB_ERR_MGMNT); 421e5cabeb3SAlexandre Bounine } 422eb188d0eSMatt Porter 423eb188d0eSMatt Porter rio_mport_read_config_32(port, destid, hopcount, RIO_SRC_OPS_CAR, 424eb188d0eSMatt Porter &rdev->src_ops); 425eb188d0eSMatt Porter rio_mport_read_config_32(port, destid, hopcount, RIO_DST_OPS_CAR, 426eb188d0eSMatt Porter &rdev->dst_ops); 427eb188d0eSMatt Porter 428c70555b0SAlexandre Bounine if (rio_device_has_destid(port, rdev->src_ops, rdev->dst_ops)) { 429c70555b0SAlexandre Bounine if (do_enum) { 430eb188d0eSMatt Porter rio_set_device_id(port, destid, hopcount, next_destid); 431eb188d0eSMatt Porter rdev->destid = next_destid++; 432eb188d0eSMatt Porter if (next_destid == port->host_deviceid) 433eb188d0eSMatt Porter next_destid++; 434eb188d0eSMatt Porter } else 435eb188d0eSMatt Porter rdev->destid = rio_get_device_id(port, destid, hopcount); 436c70555b0SAlexandre Bounine } else 437c70555b0SAlexandre Bounine /* Switch device has an associated destID */ 438c70555b0SAlexandre Bounine rdev->destid = RIO_INVALID_DESTID; 439eb188d0eSMatt Porter 440eb188d0eSMatt Porter /* If a PE has both switch and other functions, show it as a switch */ 441eb188d0eSMatt Porter if (rio_is_switch(rdev)) { 442eb188d0eSMatt Porter rio_mport_read_config_32(port, destid, hopcount, 443eb188d0eSMatt Porter RIO_SWP_INFO_CAR, &rdev->swpinfo); 44407590ff0SAlexandre Bounine rswitch = kzalloc(sizeof(struct rio_switch), GFP_KERNEL); 4455f28c520SYang Li if (!rswitch) 4465f28c520SYang Li goto cleanup; 447eb188d0eSMatt Porter rswitch->switchid = next_switchid; 448eb188d0eSMatt Porter rswitch->hopcount = hopcount; 449c70555b0SAlexandre Bounine rswitch->destid = destid; 450e5cabeb3SAlexandre Bounine rswitch->port_ok = 0; 451e0423236SZhang Wei rswitch->route_table = kzalloc(sizeof(u8)* 452e0423236SZhang Wei RIO_MAX_ROUTE_ENTRIES(port->sys_size), 453e0423236SZhang Wei GFP_KERNEL); 4545f28c520SYang Li if (!rswitch->route_table) 4555f28c520SYang Li goto cleanup; 456eb188d0eSMatt Porter /* Initialize switch route table */ 457e0423236SZhang Wei for (rdid = 0; rdid < RIO_MAX_ROUTE_ENTRIES(port->sys_size); 458e0423236SZhang Wei rdid++) 459eb188d0eSMatt Porter rswitch->route_table[rdid] = RIO_INVALID_ROUTE; 460eb188d0eSMatt Porter rdev->rswitch = rswitch; 461b53c7583SKay Sievers dev_set_name(&rdev->dev, "%02x:s:%04x", rdev->net->id, 462eb188d0eSMatt Porter rdev->rswitch->switchid); 463058f88d6SAlexandre Bounine rio_switch_init(rdev, do_enum); 464eb188d0eSMatt Porter 46507590ff0SAlexandre Bounine if (do_enum && rdev->rswitch->clr_table) 46607590ff0SAlexandre Bounine rdev->rswitch->clr_table(port, destid, hopcount, 46707590ff0SAlexandre Bounine RIO_GLOBAL_TABLE); 46807590ff0SAlexandre Bounine 469eb188d0eSMatt Porter list_add_tail(&rswitch->node, &rio_switches); 470eb188d0eSMatt Porter 471933af4a6SThomas Moll } else { 472933af4a6SThomas Moll if (do_enum) 473933af4a6SThomas Moll /*Enable Input Output Port (transmitter reviever)*/ 474933af4a6SThomas Moll rio_enable_rx_tx_port(port, 0, destid, hopcount, 0); 475933af4a6SThomas Moll 476b53c7583SKay Sievers dev_set_name(&rdev->dev, "%02x:e:%04x", rdev->net->id, 477eb188d0eSMatt Porter rdev->destid); 478933af4a6SThomas Moll } 479eb188d0eSMatt Porter 480eb188d0eSMatt Porter rdev->dev.bus = &rio_bus_type; 481eb188d0eSMatt Porter 482eb188d0eSMatt Porter device_initialize(&rdev->dev); 483eb188d0eSMatt Porter rdev->dev.release = rio_release_dev; 484eb188d0eSMatt Porter rio_dev_get(rdev); 485eb188d0eSMatt Porter 486284901a9SYang Hongyang rdev->dma_mask = DMA_BIT_MASK(32); 487fa78cc51SMatt Porter rdev->dev.dma_mask = &rdev->dma_mask; 488284901a9SYang Hongyang rdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); 489eb188d0eSMatt Porter 490eb188d0eSMatt Porter if ((rdev->pef & RIO_PEF_INB_DOORBELL) && 491eb188d0eSMatt Porter (rdev->dst_ops & RIO_DST_OPS_DOORBELL)) 492eb188d0eSMatt Porter rio_init_dbell_res(&rdev->riores[RIO_DOORBELL_RESOURCE], 493eb188d0eSMatt Porter 0, 0xffff); 494eb188d0eSMatt Porter 4955f28c520SYang Li ret = rio_add_device(rdev); 4965f28c520SYang Li if (ret) 4975f28c520SYang Li goto cleanup; 498eb188d0eSMatt Porter 499eb188d0eSMatt Porter return rdev; 5005f28c520SYang Li 5015f28c520SYang Li cleanup: 5025f28c520SYang Li if (rswitch) { 5035f28c520SYang Li kfree(rswitch->route_table); 5045f28c520SYang Li kfree(rswitch); 5055f28c520SYang Li } 5065f28c520SYang Li kfree(rdev); 5075f28c520SYang Li return NULL; 508eb188d0eSMatt Porter } 509eb188d0eSMatt Porter 510eb188d0eSMatt Porter /** 511eb188d0eSMatt Porter * rio_sport_is_active- Tests if a switch port has an active connection. 512eb188d0eSMatt Porter * @port: Master port to send transaction 513eb188d0eSMatt Porter * @destid: Associated destination ID for switch 514eb188d0eSMatt Porter * @hopcount: Hopcount to reach switch 515eb188d0eSMatt Porter * @sport: Switch port number 516eb188d0eSMatt Porter * 517eb188d0eSMatt Porter * Reads the port error status CSR for a particular switch port to 518eb188d0eSMatt Porter * determine if the port has an active link. Returns 519e5cabeb3SAlexandre Bounine * %RIO_PORT_N_ERR_STS_PORT_OK if the port is active or %0 if it is 520eb188d0eSMatt Porter * inactive. 521eb188d0eSMatt Porter */ 522eb188d0eSMatt Porter static int 523eb188d0eSMatt Porter rio_sport_is_active(struct rio_mport *port, u16 destid, u8 hopcount, int sport) 524eb188d0eSMatt Porter { 525e5cabeb3SAlexandre Bounine u32 result = 0; 526eb188d0eSMatt Porter u32 ext_ftr_ptr; 527eb188d0eSMatt Porter 528e5cabeb3SAlexandre Bounine ext_ftr_ptr = rio_mport_get_efb(port, 0, destid, hopcount, 0); 529eb188d0eSMatt Porter 530e5cabeb3SAlexandre Bounine while (ext_ftr_ptr) { 531e5cabeb3SAlexandre Bounine rio_mport_read_config_32(port, destid, hopcount, 532e5cabeb3SAlexandre Bounine ext_ftr_ptr, &result); 533e5cabeb3SAlexandre Bounine result = RIO_GET_BLOCK_ID(result); 534e5cabeb3SAlexandre Bounine if ((result == RIO_EFB_SER_EP_FREE_ID) || 535e5cabeb3SAlexandre Bounine (result == RIO_EFB_SER_EP_FREE_ID_V13P) || 536e5cabeb3SAlexandre Bounine (result == RIO_EFB_SER_EP_FREC_ID)) 537eb188d0eSMatt Porter break; 538e5cabeb3SAlexandre Bounine 539e5cabeb3SAlexandre Bounine ext_ftr_ptr = rio_mport_get_efb(port, 0, destid, hopcount, 540e5cabeb3SAlexandre Bounine ext_ftr_ptr); 541e5cabeb3SAlexandre Bounine } 542eb188d0eSMatt Porter 543eb188d0eSMatt Porter if (ext_ftr_ptr) 544eb188d0eSMatt Porter rio_mport_read_config_32(port, destid, hopcount, 545eb188d0eSMatt Porter ext_ftr_ptr + 546eb188d0eSMatt Porter RIO_PORT_N_ERR_STS_CSR(sport), 547eb188d0eSMatt Porter &result); 548eb188d0eSMatt Porter 549e5cabeb3SAlexandre Bounine return result & RIO_PORT_N_ERR_STS_PORT_OK; 550eb188d0eSMatt Porter } 551eb188d0eSMatt Porter 552eb188d0eSMatt Porter /** 553818a04a0SAlexandre Bounine * rio_lock_device - Acquires host device lock for specified device 554818a04a0SAlexandre Bounine * @port: Master port to send transaction 555818a04a0SAlexandre Bounine * @destid: Destination ID for device/switch 556818a04a0SAlexandre Bounine * @hopcount: Hopcount to reach switch 557818a04a0SAlexandre Bounine * @wait_ms: Max wait time in msec (0 = no timeout) 558818a04a0SAlexandre Bounine * 559818a04a0SAlexandre Bounine * Attepts to acquire host device lock for specified device 560818a04a0SAlexandre Bounine * Returns 0 if device lock acquired or EINVAL if timeout expires. 561818a04a0SAlexandre Bounine */ 562818a04a0SAlexandre Bounine static int 563818a04a0SAlexandre Bounine rio_lock_device(struct rio_mport *port, u16 destid, u8 hopcount, int wait_ms) 564818a04a0SAlexandre Bounine { 565818a04a0SAlexandre Bounine u32 result; 566818a04a0SAlexandre Bounine int tcnt = 0; 567818a04a0SAlexandre Bounine 568818a04a0SAlexandre Bounine /* Attempt to acquire device lock */ 569818a04a0SAlexandre Bounine rio_mport_write_config_32(port, destid, hopcount, 570818a04a0SAlexandre Bounine RIO_HOST_DID_LOCK_CSR, port->host_deviceid); 571818a04a0SAlexandre Bounine rio_mport_read_config_32(port, destid, hopcount, 572818a04a0SAlexandre Bounine RIO_HOST_DID_LOCK_CSR, &result); 573818a04a0SAlexandre Bounine 574818a04a0SAlexandre Bounine while (result != port->host_deviceid) { 575818a04a0SAlexandre Bounine if (wait_ms != 0 && tcnt == wait_ms) { 576818a04a0SAlexandre Bounine pr_debug("RIO: timeout when locking device %x:%x\n", 577818a04a0SAlexandre Bounine destid, hopcount); 578818a04a0SAlexandre Bounine return -EINVAL; 579818a04a0SAlexandre Bounine } 580818a04a0SAlexandre Bounine 581818a04a0SAlexandre Bounine /* Delay a bit */ 582818a04a0SAlexandre Bounine mdelay(1); 583818a04a0SAlexandre Bounine tcnt++; 584818a04a0SAlexandre Bounine /* Try to acquire device lock again */ 585818a04a0SAlexandre Bounine rio_mport_write_config_32(port, destid, 586818a04a0SAlexandre Bounine hopcount, 587818a04a0SAlexandre Bounine RIO_HOST_DID_LOCK_CSR, 588818a04a0SAlexandre Bounine port->host_deviceid); 589818a04a0SAlexandre Bounine rio_mport_read_config_32(port, destid, 590818a04a0SAlexandre Bounine hopcount, 591818a04a0SAlexandre Bounine RIO_HOST_DID_LOCK_CSR, &result); 592818a04a0SAlexandre Bounine } 593818a04a0SAlexandre Bounine 594818a04a0SAlexandre Bounine return 0; 595818a04a0SAlexandre Bounine } 596818a04a0SAlexandre Bounine 597818a04a0SAlexandre Bounine /** 598818a04a0SAlexandre Bounine * rio_unlock_device - Releases host device lock for specified device 599818a04a0SAlexandre Bounine * @port: Master port to send transaction 600818a04a0SAlexandre Bounine * @destid: Destination ID for device/switch 601818a04a0SAlexandre Bounine * @hopcount: Hopcount to reach switch 602818a04a0SAlexandre Bounine * 603818a04a0SAlexandre Bounine * Returns 0 if device lock released or EINVAL if fails. 604818a04a0SAlexandre Bounine */ 605818a04a0SAlexandre Bounine static int 606818a04a0SAlexandre Bounine rio_unlock_device(struct rio_mport *port, u16 destid, u8 hopcount) 607818a04a0SAlexandre Bounine { 608818a04a0SAlexandre Bounine u32 result; 609818a04a0SAlexandre Bounine 610818a04a0SAlexandre Bounine /* Release device lock */ 611818a04a0SAlexandre Bounine rio_mport_write_config_32(port, destid, 612818a04a0SAlexandre Bounine hopcount, 613818a04a0SAlexandre Bounine RIO_HOST_DID_LOCK_CSR, 614818a04a0SAlexandre Bounine port->host_deviceid); 615818a04a0SAlexandre Bounine rio_mport_read_config_32(port, destid, hopcount, 616818a04a0SAlexandre Bounine RIO_HOST_DID_LOCK_CSR, &result); 617818a04a0SAlexandre Bounine if ((result & 0xffff) != 0xffff) { 618818a04a0SAlexandre Bounine pr_debug("RIO: badness when releasing device lock %x:%x\n", 619818a04a0SAlexandre Bounine destid, hopcount); 620818a04a0SAlexandre Bounine return -EINVAL; 621818a04a0SAlexandre Bounine } 622818a04a0SAlexandre Bounine 623818a04a0SAlexandre Bounine return 0; 624818a04a0SAlexandre Bounine } 625818a04a0SAlexandre Bounine 626818a04a0SAlexandre Bounine /** 627eb188d0eSMatt Porter * rio_route_add_entry- Add a route entry to a switch routing table 628eb188d0eSMatt Porter * @mport: Master port to send transaction 629c70555b0SAlexandre Bounine * @rswitch: Switch device 630eb188d0eSMatt Porter * @table: Routing table ID 631eb188d0eSMatt Porter * @route_destid: Destination ID to be routed 632eb188d0eSMatt Porter * @route_port: Port number to be routed 633818a04a0SAlexandre Bounine * @lock: lock switch device flag 634eb188d0eSMatt Porter * 635eb188d0eSMatt Porter * Calls the switch specific add_entry() method to add a route entry 636eb188d0eSMatt Porter * on a switch. The route table can be specified using the @table 637eb188d0eSMatt Porter * argument if a switch has per port routing tables or the normal 638eb188d0eSMatt Porter * use is to specific all tables (or the global table) by passing 639eb188d0eSMatt Porter * %RIO_GLOBAL_TABLE in @table. Returns %0 on success or %-EINVAL 640eb188d0eSMatt Porter * on failure. 641eb188d0eSMatt Porter */ 642818a04a0SAlexandre Bounine static int 643818a04a0SAlexandre Bounine rio_route_add_entry(struct rio_mport *mport, struct rio_switch *rswitch, 644818a04a0SAlexandre Bounine u16 table, u16 route_destid, u8 route_port, int lock) 645eb188d0eSMatt Porter { 646818a04a0SAlexandre Bounine int rc; 647818a04a0SAlexandre Bounine 648818a04a0SAlexandre Bounine if (lock) { 649818a04a0SAlexandre Bounine rc = rio_lock_device(mport, rswitch->destid, 650818a04a0SAlexandre Bounine rswitch->hopcount, 1000); 651818a04a0SAlexandre Bounine if (rc) 652818a04a0SAlexandre Bounine return rc; 653818a04a0SAlexandre Bounine } 654818a04a0SAlexandre Bounine 655818a04a0SAlexandre Bounine rc = rswitch->add_entry(mport, rswitch->destid, 656c70555b0SAlexandre Bounine rswitch->hopcount, table, 657eb188d0eSMatt Porter route_destid, route_port); 658818a04a0SAlexandre Bounine if (lock) 659818a04a0SAlexandre Bounine rio_unlock_device(mport, rswitch->destid, rswitch->hopcount); 660818a04a0SAlexandre Bounine 661818a04a0SAlexandre Bounine return rc; 662eb188d0eSMatt Porter } 663eb188d0eSMatt Porter 664eb188d0eSMatt Porter /** 665eb188d0eSMatt Porter * rio_route_get_entry- Read a route entry in a switch routing table 666eb188d0eSMatt Porter * @mport: Master port to send transaction 667c70555b0SAlexandre Bounine * @rswitch: Switch device 668eb188d0eSMatt Porter * @table: Routing table ID 669eb188d0eSMatt Porter * @route_destid: Destination ID to be routed 670eb188d0eSMatt Porter * @route_port: Pointer to read port number into 671818a04a0SAlexandre Bounine * @lock: lock switch device flag 672eb188d0eSMatt Porter * 673eb188d0eSMatt Porter * Calls the switch specific get_entry() method to read a route entry 674eb188d0eSMatt Porter * in a switch. The route table can be specified using the @table 675eb188d0eSMatt Porter * argument if a switch has per port routing tables or the normal 676eb188d0eSMatt Porter * use is to specific all tables (or the global table) by passing 677eb188d0eSMatt Porter * %RIO_GLOBAL_TABLE in @table. Returns %0 on success or %-EINVAL 678eb188d0eSMatt Porter * on failure. 679eb188d0eSMatt Porter */ 680eb188d0eSMatt Porter static int 681c70555b0SAlexandre Bounine rio_route_get_entry(struct rio_mport *mport, struct rio_switch *rswitch, u16 table, 682818a04a0SAlexandre Bounine u16 route_destid, u8 *route_port, int lock) 683eb188d0eSMatt Porter { 684818a04a0SAlexandre Bounine int rc; 685818a04a0SAlexandre Bounine 686818a04a0SAlexandre Bounine if (lock) { 687818a04a0SAlexandre Bounine rc = rio_lock_device(mport, rswitch->destid, 688818a04a0SAlexandre Bounine rswitch->hopcount, 1000); 689818a04a0SAlexandre Bounine if (rc) 690818a04a0SAlexandre Bounine return rc; 691818a04a0SAlexandre Bounine } 692818a04a0SAlexandre Bounine 693818a04a0SAlexandre Bounine rc = rswitch->get_entry(mport, rswitch->destid, 694c70555b0SAlexandre Bounine rswitch->hopcount, table, 695eb188d0eSMatt Porter route_destid, route_port); 696818a04a0SAlexandre Bounine if (lock) 697818a04a0SAlexandre Bounine rio_unlock_device(mport, rswitch->destid, rswitch->hopcount); 698818a04a0SAlexandre Bounine 699818a04a0SAlexandre Bounine return rc; 700eb188d0eSMatt Porter } 701eb188d0eSMatt Porter 702eb188d0eSMatt Porter /** 703eb188d0eSMatt Porter * rio_get_host_deviceid_lock- Reads the Host Device ID Lock CSR on a device 704eb188d0eSMatt Porter * @port: Master port to send transaction 705eb188d0eSMatt Porter * @hopcount: Number of hops to the device 706eb188d0eSMatt Porter * 707eb188d0eSMatt Porter * Used during enumeration to read the Host Device ID Lock CSR on a 708eb188d0eSMatt Porter * RIO device. Returns the value of the lock register. 709eb188d0eSMatt Porter */ 710eb188d0eSMatt Porter static u16 rio_get_host_deviceid_lock(struct rio_mport *port, u8 hopcount) 711eb188d0eSMatt Porter { 712eb188d0eSMatt Porter u32 result; 713eb188d0eSMatt Porter 714e0423236SZhang Wei rio_mport_read_config_32(port, RIO_ANY_DESTID(port->sys_size), hopcount, 715eb188d0eSMatt Porter RIO_HOST_DID_LOCK_CSR, &result); 716eb188d0eSMatt Porter 717eb188d0eSMatt Porter return (u16) (result & 0xffff); 718eb188d0eSMatt Porter } 719eb188d0eSMatt Porter 720eb188d0eSMatt Porter /** 721eb188d0eSMatt Porter * rio_get_swpinfo_inport- Gets the ingress port number 722eb188d0eSMatt Porter * @mport: Master port to send transaction 723eb188d0eSMatt Porter * @destid: Destination ID associated with the switch 724eb188d0eSMatt Porter * @hopcount: Number of hops to the device 725eb188d0eSMatt Porter * 726eb188d0eSMatt Porter * Returns port number being used to access the switch device. 727eb188d0eSMatt Porter */ 728eb188d0eSMatt Porter static u8 729eb188d0eSMatt Porter rio_get_swpinfo_inport(struct rio_mport *mport, u16 destid, u8 hopcount) 730eb188d0eSMatt Porter { 731eb188d0eSMatt Porter u32 result; 732eb188d0eSMatt Porter 733eb188d0eSMatt Porter rio_mport_read_config_32(mport, destid, hopcount, RIO_SWP_INFO_CAR, 734eb188d0eSMatt Porter &result); 735eb188d0eSMatt Porter 736eb188d0eSMatt Porter return (u8) (result & 0xff); 737eb188d0eSMatt Porter } 738eb188d0eSMatt Porter 739eb188d0eSMatt Porter /** 740eb188d0eSMatt Porter * rio_get_swpinfo_tports- Gets total number of ports on the switch 741eb188d0eSMatt Porter * @mport: Master port to send transaction 742eb188d0eSMatt Porter * @destid: Destination ID associated with the switch 743eb188d0eSMatt Porter * @hopcount: Number of hops to the device 744eb188d0eSMatt Porter * 745eb188d0eSMatt Porter * Returns total numbers of ports implemented by the switch device. 746eb188d0eSMatt Porter */ 747eb188d0eSMatt Porter static u8 rio_get_swpinfo_tports(struct rio_mport *mport, u16 destid, 748eb188d0eSMatt Porter u8 hopcount) 749eb188d0eSMatt Porter { 750eb188d0eSMatt Porter u32 result; 751eb188d0eSMatt Porter 752eb188d0eSMatt Porter rio_mport_read_config_32(mport, destid, hopcount, RIO_SWP_INFO_CAR, 753eb188d0eSMatt Porter &result); 754eb188d0eSMatt Porter 755eb188d0eSMatt Porter return RIO_GET_TOTAL_PORTS(result); 756eb188d0eSMatt Porter } 757eb188d0eSMatt Porter 758eb188d0eSMatt Porter /** 759eb188d0eSMatt Porter * rio_net_add_mport- Add a master port to a RIO network 760eb188d0eSMatt Porter * @net: RIO network 761eb188d0eSMatt Porter * @port: Master port to add 762eb188d0eSMatt Porter * 763eb188d0eSMatt Porter * Adds a master port to the network list of associated master 764eb188d0eSMatt Porter * ports.. 765eb188d0eSMatt Porter */ 766eb188d0eSMatt Porter static void rio_net_add_mport(struct rio_net *net, struct rio_mport *port) 767eb188d0eSMatt Porter { 768eb188d0eSMatt Porter spin_lock(&rio_global_list_lock); 769eb188d0eSMatt Porter list_add_tail(&port->nnode, &net->mports); 770eb188d0eSMatt Porter spin_unlock(&rio_global_list_lock); 771eb188d0eSMatt Porter } 772eb188d0eSMatt Porter 773eb188d0eSMatt Porter /** 774eb188d0eSMatt Porter * rio_enum_peer- Recursively enumerate a RIO network through a master port 775eb188d0eSMatt Porter * @net: RIO network being enumerated 776eb188d0eSMatt Porter * @port: Master port to send transactions 777eb188d0eSMatt Porter * @hopcount: Number of hops into the network 778eb188d0eSMatt Porter * 779eb188d0eSMatt Porter * Recursively enumerates a RIO network. Transactions are sent via the 780eb188d0eSMatt Porter * master port passed in @port. 781eb188d0eSMatt Porter */ 782181a6ff0SLi Yang static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port, 783eb188d0eSMatt Porter u8 hopcount) 784eb188d0eSMatt Porter { 785eb188d0eSMatt Porter int port_num; 786eb188d0eSMatt Porter int num_ports; 787eb188d0eSMatt Porter int cur_destid; 788c70555b0SAlexandre Bounine int sw_destid; 789c70555b0SAlexandre Bounine int sw_inport; 790eb188d0eSMatt Porter struct rio_dev *rdev; 791eb188d0eSMatt Porter u16 destid; 792eb188d0eSMatt Porter int tmp; 793eb188d0eSMatt Porter 794eb188d0eSMatt Porter if (rio_get_host_deviceid_lock(port, hopcount) == port->host_deviceid) { 795eb188d0eSMatt Porter pr_debug("RIO: PE already discovered by this host\n"); 796eb188d0eSMatt Porter /* 797eb188d0eSMatt Porter * Already discovered by this host. Add it as another 798eb188d0eSMatt Porter * master port for the current network. 799eb188d0eSMatt Porter */ 800eb188d0eSMatt Porter rio_net_add_mport(net, port); 801eb188d0eSMatt Porter return 0; 802eb188d0eSMatt Porter } 803eb188d0eSMatt Porter 804eb188d0eSMatt Porter /* Attempt to acquire device lock */ 805e0423236SZhang Wei rio_mport_write_config_32(port, RIO_ANY_DESTID(port->sys_size), 806e0423236SZhang Wei hopcount, 807eb188d0eSMatt Porter RIO_HOST_DID_LOCK_CSR, port->host_deviceid); 808eb188d0eSMatt Porter while ((tmp = rio_get_host_deviceid_lock(port, hopcount)) 809eb188d0eSMatt Porter < port->host_deviceid) { 810eb188d0eSMatt Porter /* Delay a bit */ 811eb188d0eSMatt Porter mdelay(1); 812eb188d0eSMatt Porter /* Attempt to acquire device lock again */ 813e0423236SZhang Wei rio_mport_write_config_32(port, RIO_ANY_DESTID(port->sys_size), 814e0423236SZhang Wei hopcount, 815eb188d0eSMatt Porter RIO_HOST_DID_LOCK_CSR, 816eb188d0eSMatt Porter port->host_deviceid); 817eb188d0eSMatt Porter } 818eb188d0eSMatt Porter 819eb188d0eSMatt Porter if (rio_get_host_deviceid_lock(port, hopcount) > port->host_deviceid) { 820eb188d0eSMatt Porter pr_debug( 821eb188d0eSMatt Porter "RIO: PE locked by a higher priority host...retreating\n"); 822eb188d0eSMatt Porter return -1; 823eb188d0eSMatt Porter } 824eb188d0eSMatt Porter 825eb188d0eSMatt Porter /* Setup new RIO device */ 826e0423236SZhang Wei rdev = rio_setup_device(net, port, RIO_ANY_DESTID(port->sys_size), 827e0423236SZhang Wei hopcount, 1); 828e0423236SZhang Wei if (rdev) { 829eb188d0eSMatt Porter /* Add device to the global and bus/net specific list. */ 830eb188d0eSMatt Porter list_add_tail(&rdev->net_list, &net->devices); 831eb188d0eSMatt Porter } else 832eb188d0eSMatt Porter return -1; 833eb188d0eSMatt Porter 834eb188d0eSMatt Porter if (rio_is_switch(rdev)) { 835eb188d0eSMatt Porter next_switchid++; 836e0423236SZhang Wei sw_inport = rio_get_swpinfo_inport(port, 837e0423236SZhang Wei RIO_ANY_DESTID(port->sys_size), hopcount); 838c70555b0SAlexandre Bounine rio_route_add_entry(port, rdev->rswitch, RIO_GLOBAL_TABLE, 839818a04a0SAlexandre Bounine port->host_deviceid, sw_inport, 0); 840c70555b0SAlexandre Bounine rdev->rswitch->route_table[port->host_deviceid] = sw_inport; 841eb188d0eSMatt Porter 842eb188d0eSMatt Porter for (destid = 0; destid < next_destid; destid++) { 843c70555b0SAlexandre Bounine if (destid == port->host_deviceid) 844c70555b0SAlexandre Bounine continue; 845c70555b0SAlexandre Bounine rio_route_add_entry(port, rdev->rswitch, RIO_GLOBAL_TABLE, 846818a04a0SAlexandre Bounine destid, sw_inport, 0); 847c70555b0SAlexandre Bounine rdev->rswitch->route_table[destid] = sw_inport; 848eb188d0eSMatt Porter } 849eb188d0eSMatt Porter 850eb188d0eSMatt Porter num_ports = 851e0423236SZhang Wei rio_get_swpinfo_tports(port, RIO_ANY_DESTID(port->sys_size), 852e0423236SZhang Wei hopcount); 853eb188d0eSMatt Porter pr_debug( 854eb188d0eSMatt Porter "RIO: found %s (vid %4.4x did %4.4x) with %d ports\n", 855eb188d0eSMatt Porter rio_name(rdev), rdev->vid, rdev->did, num_ports); 856c70555b0SAlexandre Bounine sw_destid = next_destid; 857eb188d0eSMatt Porter for (port_num = 0; port_num < num_ports; port_num++) { 858933af4a6SThomas Moll /*Enable Input Output Port (transmitter reviever)*/ 859933af4a6SThomas Moll rio_enable_rx_tx_port(port, 0, 860933af4a6SThomas Moll RIO_ANY_DESTID(port->sys_size), 861933af4a6SThomas Moll hopcount, port_num); 862933af4a6SThomas Moll 863e5cabeb3SAlexandre Bounine if (sw_inport == port_num) { 864e5cabeb3SAlexandre Bounine rdev->rswitch->port_ok |= (1 << port_num); 865eb188d0eSMatt Porter continue; 866e5cabeb3SAlexandre Bounine } 867eb188d0eSMatt Porter 868eb188d0eSMatt Porter cur_destid = next_destid; 869eb188d0eSMatt Porter 870eb188d0eSMatt Porter if (rio_sport_is_active 871e0423236SZhang Wei (port, RIO_ANY_DESTID(port->sys_size), hopcount, 872e0423236SZhang Wei port_num)) { 873eb188d0eSMatt Porter pr_debug( 874eb188d0eSMatt Porter "RIO: scanning device on port %d\n", 875eb188d0eSMatt Porter port_num); 876e5cabeb3SAlexandre Bounine rdev->rswitch->port_ok |= (1 << port_num); 877c70555b0SAlexandre Bounine rio_route_add_entry(port, rdev->rswitch, 878eb188d0eSMatt Porter RIO_GLOBAL_TABLE, 879e0423236SZhang Wei RIO_ANY_DESTID(port->sys_size), 880818a04a0SAlexandre Bounine port_num, 0); 881eb188d0eSMatt Porter 882eb188d0eSMatt Porter if (rio_enum_peer(net, port, hopcount + 1) < 0) 883eb188d0eSMatt Porter return -1; 884eb188d0eSMatt Porter 885eb188d0eSMatt Porter /* Update routing tables */ 886eb188d0eSMatt Porter if (next_destid > cur_destid) { 887eb188d0eSMatt Porter for (destid = cur_destid; 888eb188d0eSMatt Porter destid < next_destid; destid++) { 889c70555b0SAlexandre Bounine if (destid == port->host_deviceid) 890c70555b0SAlexandre Bounine continue; 891c70555b0SAlexandre Bounine rio_route_add_entry(port, rdev->rswitch, 892eb188d0eSMatt Porter RIO_GLOBAL_TABLE, 893eb188d0eSMatt Porter destid, 894818a04a0SAlexandre Bounine port_num, 895818a04a0SAlexandre Bounine 0); 896eb188d0eSMatt Porter rdev->rswitch-> 897eb188d0eSMatt Porter route_table[destid] = 898eb188d0eSMatt Porter port_num; 899eb188d0eSMatt Porter } 900eb188d0eSMatt Porter } 901e5cabeb3SAlexandre Bounine } else { 902e5cabeb3SAlexandre Bounine /* If switch supports Error Management, 903e5cabeb3SAlexandre Bounine * set PORT_LOCKOUT bit for unused port 904e5cabeb3SAlexandre Bounine */ 905e5cabeb3SAlexandre Bounine if (rdev->em_efptr) 906e5cabeb3SAlexandre Bounine rio_set_port_lockout(rdev, port_num, 1); 907e5cabeb3SAlexandre Bounine 908e5cabeb3SAlexandre Bounine rdev->rswitch->port_ok &= ~(1 << port_num); 909eb188d0eSMatt Porter } 910eb188d0eSMatt Porter } 911c70555b0SAlexandre Bounine 912e5cabeb3SAlexandre Bounine /* Direct Port-write messages to the enumeratiing host */ 913e5cabeb3SAlexandre Bounine if ((rdev->src_ops & RIO_SRC_OPS_PORT_WRITE) && 914e5cabeb3SAlexandre Bounine (rdev->em_efptr)) { 915e5cabeb3SAlexandre Bounine rio_write_config_32(rdev, 916e5cabeb3SAlexandre Bounine rdev->em_efptr + RIO_EM_PW_TGT_DEVID, 917e5cabeb3SAlexandre Bounine (port->host_deviceid << 16) | 918e5cabeb3SAlexandre Bounine (port->sys_size << 15)); 919e5cabeb3SAlexandre Bounine } 920e5cabeb3SAlexandre Bounine 921e5cabeb3SAlexandre Bounine rio_init_em(rdev); 922e5cabeb3SAlexandre Bounine 923c70555b0SAlexandre Bounine /* Check for empty switch */ 924c70555b0SAlexandre Bounine if (next_destid == sw_destid) { 925c70555b0SAlexandre Bounine next_destid++; 926c70555b0SAlexandre Bounine if (next_destid == port->host_deviceid) 927c70555b0SAlexandre Bounine next_destid++; 928c70555b0SAlexandre Bounine } 929c70555b0SAlexandre Bounine 930c70555b0SAlexandre Bounine rdev->rswitch->destid = sw_destid; 931eb188d0eSMatt Porter } else 932eb188d0eSMatt Porter pr_debug("RIO: found %s (vid %4.4x did %4.4x)\n", 933eb188d0eSMatt Porter rio_name(rdev), rdev->vid, rdev->did); 934eb188d0eSMatt Porter 935eb188d0eSMatt Porter return 0; 936eb188d0eSMatt Porter } 937eb188d0eSMatt Porter 938eb188d0eSMatt Porter /** 939eb188d0eSMatt Porter * rio_enum_complete- Tests if enumeration of a network is complete 940eb188d0eSMatt Porter * @port: Master port to send transaction 941eb188d0eSMatt Porter * 942e5cabeb3SAlexandre Bounine * Tests the Component Tag CSR for non-zero value (enumeration 943e5cabeb3SAlexandre Bounine * complete flag). Return %1 if enumeration is complete or %0 if 944eb188d0eSMatt Porter * enumeration is incomplete. 945eb188d0eSMatt Porter */ 946eb188d0eSMatt Porter static int rio_enum_complete(struct rio_mport *port) 947eb188d0eSMatt Porter { 948eb188d0eSMatt Porter u32 tag_csr; 949eb188d0eSMatt Porter 950eb188d0eSMatt Porter rio_local_read_config_32(port, RIO_COMPONENT_TAG_CSR, &tag_csr); 951e5cabeb3SAlexandre Bounine return (tag_csr & 0xffff) ? 1 : 0; 952eb188d0eSMatt Porter } 953eb188d0eSMatt Porter 954eb188d0eSMatt Porter /** 955eb188d0eSMatt Porter * rio_disc_peer- Recursively discovers a RIO network through a master port 956eb188d0eSMatt Porter * @net: RIO network being discovered 957eb188d0eSMatt Porter * @port: Master port to send transactions 958eb188d0eSMatt Porter * @destid: Current destination ID in network 959eb188d0eSMatt Porter * @hopcount: Number of hops into the network 960eb188d0eSMatt Porter * 961eb188d0eSMatt Porter * Recursively discovers a RIO network. Transactions are sent via the 962eb188d0eSMatt Porter * master port passed in @port. 963eb188d0eSMatt Porter */ 964181a6ff0SLi Yang static int __devinit 965eb188d0eSMatt Porter rio_disc_peer(struct rio_net *net, struct rio_mport *port, u16 destid, 966eb188d0eSMatt Porter u8 hopcount) 967eb188d0eSMatt Porter { 968eb188d0eSMatt Porter u8 port_num, route_port; 969eb188d0eSMatt Porter int num_ports; 970eb188d0eSMatt Porter struct rio_dev *rdev; 971eb188d0eSMatt Porter u16 ndestid; 972eb188d0eSMatt Porter 973eb188d0eSMatt Porter /* Setup new RIO device */ 974eb188d0eSMatt Porter if ((rdev = rio_setup_device(net, port, destid, hopcount, 0))) { 975eb188d0eSMatt Porter /* Add device to the global and bus/net specific list. */ 976eb188d0eSMatt Porter list_add_tail(&rdev->net_list, &net->devices); 977eb188d0eSMatt Porter } else 978eb188d0eSMatt Porter return -1; 979eb188d0eSMatt Porter 980eb188d0eSMatt Porter if (rio_is_switch(rdev)) { 981eb188d0eSMatt Porter next_switchid++; 982eb188d0eSMatt Porter 983eb188d0eSMatt Porter /* Associated destid is how we accessed this switch */ 984eb188d0eSMatt Porter rdev->rswitch->destid = destid; 985eb188d0eSMatt Porter 986eb188d0eSMatt Porter num_ports = rio_get_swpinfo_tports(port, destid, hopcount); 987eb188d0eSMatt Porter pr_debug( 988eb188d0eSMatt Porter "RIO: found %s (vid %4.4x did %4.4x) with %d ports\n", 989eb188d0eSMatt Porter rio_name(rdev), rdev->vid, rdev->did, num_ports); 990eb188d0eSMatt Porter for (port_num = 0; port_num < num_ports; port_num++) { 991eb188d0eSMatt Porter if (rio_get_swpinfo_inport(port, destid, hopcount) == 992eb188d0eSMatt Porter port_num) 993eb188d0eSMatt Porter continue; 994eb188d0eSMatt Porter 995eb188d0eSMatt Porter if (rio_sport_is_active 996eb188d0eSMatt Porter (port, destid, hopcount, port_num)) { 997eb188d0eSMatt Porter pr_debug( 998eb188d0eSMatt Porter "RIO: scanning device on port %d\n", 999eb188d0eSMatt Porter port_num); 1000818a04a0SAlexandre Bounine 1001818a04a0SAlexandre Bounine rio_lock_device(port, destid, hopcount, 1000); 1002818a04a0SAlexandre Bounine 1003e0423236SZhang Wei for (ndestid = 0; 1004e0423236SZhang Wei ndestid < RIO_ANY_DESTID(port->sys_size); 1005eb188d0eSMatt Porter ndestid++) { 1006c70555b0SAlexandre Bounine rio_route_get_entry(port, rdev->rswitch, 1007eb188d0eSMatt Porter RIO_GLOBAL_TABLE, 1008eb188d0eSMatt Porter ndestid, 1009818a04a0SAlexandre Bounine &route_port, 0); 1010eb188d0eSMatt Porter if (route_port == port_num) 1011eb188d0eSMatt Porter break; 1012eb188d0eSMatt Porter } 1013eb188d0eSMatt Porter 1014818a04a0SAlexandre Bounine rio_unlock_device(port, destid, hopcount); 1015eb188d0eSMatt Porter if (rio_disc_peer 1016eb188d0eSMatt Porter (net, port, ndestid, hopcount + 1) < 0) 1017eb188d0eSMatt Porter return -1; 1018eb188d0eSMatt Porter } 1019eb188d0eSMatt Porter } 1020eb188d0eSMatt Porter } else 1021eb188d0eSMatt Porter pr_debug("RIO: found %s (vid %4.4x did %4.4x)\n", 1022eb188d0eSMatt Porter rio_name(rdev), rdev->vid, rdev->did); 1023eb188d0eSMatt Porter 1024eb188d0eSMatt Porter return 0; 1025eb188d0eSMatt Porter } 1026eb188d0eSMatt Porter 1027eb188d0eSMatt Porter /** 1028eb188d0eSMatt Porter * rio_mport_is_active- Tests if master port link is active 1029eb188d0eSMatt Porter * @port: Master port to test 1030eb188d0eSMatt Porter * 1031eb188d0eSMatt Porter * Reads the port error status CSR for the master port to 1032eb188d0eSMatt Porter * determine if the port has an active link. Returns 1033e5cabeb3SAlexandre Bounine * %RIO_PORT_N_ERR_STS_PORT_OK if the master port is active 1034eb188d0eSMatt Porter * or %0 if it is inactive. 1035eb188d0eSMatt Porter */ 1036eb188d0eSMatt Porter static int rio_mport_is_active(struct rio_mport *port) 1037eb188d0eSMatt Porter { 1038eb188d0eSMatt Porter u32 result = 0; 1039eb188d0eSMatt Porter u32 ext_ftr_ptr; 1040eb188d0eSMatt Porter int *entry = rio_mport_phys_table; 1041eb188d0eSMatt Porter 1042eb188d0eSMatt Porter do { 1043eb188d0eSMatt Porter if ((ext_ftr_ptr = 1044eb188d0eSMatt Porter rio_mport_get_feature(port, 1, 0, 0, *entry))) 1045eb188d0eSMatt Porter break; 1046eb188d0eSMatt Porter } while (*++entry >= 0); 1047eb188d0eSMatt Porter 1048eb188d0eSMatt Porter if (ext_ftr_ptr) 1049eb188d0eSMatt Porter rio_local_read_config_32(port, 1050eb188d0eSMatt Porter ext_ftr_ptr + 1051eb188d0eSMatt Porter RIO_PORT_N_ERR_STS_CSR(port->index), 1052eb188d0eSMatt Porter &result); 1053eb188d0eSMatt Porter 1054e5cabeb3SAlexandre Bounine return result & RIO_PORT_N_ERR_STS_PORT_OK; 1055eb188d0eSMatt Porter } 1056eb188d0eSMatt Porter 1057eb188d0eSMatt Porter /** 1058eb188d0eSMatt Porter * rio_alloc_net- Allocate and configure a new RIO network 1059eb188d0eSMatt Porter * @port: Master port associated with the RIO network 1060eb188d0eSMatt Porter * 1061eb188d0eSMatt Porter * Allocates a RIO network structure, initializes per-network 1062eb188d0eSMatt Porter * list heads, and adds the associated master port to the 1063eb188d0eSMatt Porter * network list of associated master ports. Returns a 1064eb188d0eSMatt Porter * RIO network pointer on success or %NULL on failure. 1065eb188d0eSMatt Porter */ 1066eb188d0eSMatt Porter static struct rio_net __devinit *rio_alloc_net(struct rio_mport *port) 1067eb188d0eSMatt Porter { 1068eb188d0eSMatt Porter struct rio_net *net; 1069eb188d0eSMatt Porter 1070dd00cc48SYoann Padioleau net = kzalloc(sizeof(struct rio_net), GFP_KERNEL); 1071eb188d0eSMatt Porter if (net) { 1072eb188d0eSMatt Porter INIT_LIST_HEAD(&net->node); 1073eb188d0eSMatt Porter INIT_LIST_HEAD(&net->devices); 1074eb188d0eSMatt Porter INIT_LIST_HEAD(&net->mports); 1075eb188d0eSMatt Porter list_add_tail(&port->nnode, &net->mports); 1076eb188d0eSMatt Porter net->hport = port; 1077eb188d0eSMatt Porter net->id = next_net++; 1078eb188d0eSMatt Porter } 1079eb188d0eSMatt Porter return net; 1080eb188d0eSMatt Porter } 1081eb188d0eSMatt Porter 1082eb188d0eSMatt Porter /** 1083c70555b0SAlexandre Bounine * rio_update_route_tables- Updates route tables in switches 1084c70555b0SAlexandre Bounine * @port: Master port associated with the RIO network 1085c70555b0SAlexandre Bounine * 1086c70555b0SAlexandre Bounine * For each enumerated device, ensure that each switch in a system 1087c70555b0SAlexandre Bounine * has correct routing entries. Add routes for devices that where 1088c70555b0SAlexandre Bounine * unknown dirung the first enumeration pass through the switch. 1089c70555b0SAlexandre Bounine */ 1090c70555b0SAlexandre Bounine static void rio_update_route_tables(struct rio_mport *port) 1091c70555b0SAlexandre Bounine { 1092c70555b0SAlexandre Bounine struct rio_dev *rdev; 1093c70555b0SAlexandre Bounine struct rio_switch *rswitch; 1094c70555b0SAlexandre Bounine u8 sport; 1095c70555b0SAlexandre Bounine u16 destid; 1096c70555b0SAlexandre Bounine 1097c70555b0SAlexandre Bounine list_for_each_entry(rdev, &rio_devices, global_list) { 1098c70555b0SAlexandre Bounine 1099c70555b0SAlexandre Bounine destid = (rio_is_switch(rdev))?rdev->rswitch->destid:rdev->destid; 1100c70555b0SAlexandre Bounine 1101c70555b0SAlexandre Bounine list_for_each_entry(rswitch, &rio_switches, node) { 1102c70555b0SAlexandre Bounine 1103c70555b0SAlexandre Bounine if (rio_is_switch(rdev) && (rdev->rswitch == rswitch)) 1104c70555b0SAlexandre Bounine continue; 1105c70555b0SAlexandre Bounine 1106c70555b0SAlexandre Bounine if (RIO_INVALID_ROUTE == rswitch->route_table[destid]) { 110707590ff0SAlexandre Bounine /* Skip if destid ends in empty switch*/ 110807590ff0SAlexandre Bounine if (rswitch->destid == destid) 110907590ff0SAlexandre Bounine continue; 1110c70555b0SAlexandre Bounine 1111c70555b0SAlexandre Bounine sport = rio_get_swpinfo_inport(port, 1112c70555b0SAlexandre Bounine rswitch->destid, rswitch->hopcount); 1113c70555b0SAlexandre Bounine 1114c70555b0SAlexandre Bounine if (rswitch->add_entry) { 1115818a04a0SAlexandre Bounine rio_route_add_entry(port, rswitch, 1116818a04a0SAlexandre Bounine RIO_GLOBAL_TABLE, destid, 1117818a04a0SAlexandre Bounine sport, 0); 1118c70555b0SAlexandre Bounine rswitch->route_table[destid] = sport; 1119c70555b0SAlexandre Bounine } 1120c70555b0SAlexandre Bounine } 1121c70555b0SAlexandre Bounine } 1122c70555b0SAlexandre Bounine } 1123c70555b0SAlexandre Bounine } 1124c70555b0SAlexandre Bounine 1125c70555b0SAlexandre Bounine /** 1126e5cabeb3SAlexandre Bounine * rio_init_em - Initializes RIO Error Management (for switches) 1127e5cabeb3SAlexandre Bounine * @port: Master port associated with the RIO network 1128e5cabeb3SAlexandre Bounine * 1129e5cabeb3SAlexandre Bounine * For each enumerated switch, call device-specific error management 1130e5cabeb3SAlexandre Bounine * initialization routine (if supplied by the switch driver). 1131e5cabeb3SAlexandre Bounine */ 1132e5cabeb3SAlexandre Bounine static void rio_init_em(struct rio_dev *rdev) 1133e5cabeb3SAlexandre Bounine { 1134e5cabeb3SAlexandre Bounine if (rio_is_switch(rdev) && (rdev->em_efptr) && 1135e5cabeb3SAlexandre Bounine (rdev->rswitch->em_init)) { 1136e5cabeb3SAlexandre Bounine rdev->rswitch->em_init(rdev); 1137e5cabeb3SAlexandre Bounine } 1138e5cabeb3SAlexandre Bounine } 1139e5cabeb3SAlexandre Bounine 1140e5cabeb3SAlexandre Bounine /** 1141e5cabeb3SAlexandre Bounine * rio_pw_enable - Enables/disables port-write handling by a master port 1142e5cabeb3SAlexandre Bounine * @port: Master port associated with port-write handling 1143e5cabeb3SAlexandre Bounine * @enable: 1=enable, 0=disable 1144e5cabeb3SAlexandre Bounine */ 1145e5cabeb3SAlexandre Bounine static void rio_pw_enable(struct rio_mport *port, int enable) 1146e5cabeb3SAlexandre Bounine { 1147e5cabeb3SAlexandre Bounine if (port->ops->pwenable) 1148e5cabeb3SAlexandre Bounine port->ops->pwenable(port, enable); 1149e5cabeb3SAlexandre Bounine } 1150e5cabeb3SAlexandre Bounine 1151e5cabeb3SAlexandre Bounine /** 1152eb188d0eSMatt Porter * rio_enum_mport- Start enumeration through a master port 1153eb188d0eSMatt Porter * @mport: Master port to send transactions 1154eb188d0eSMatt Porter * 1155eb188d0eSMatt Porter * Starts the enumeration process. If somebody has enumerated our 1156eb188d0eSMatt Porter * master port device, then give up. If not and we have an active 1157eb188d0eSMatt Porter * link, then start recursive peer enumeration. Returns %0 if 1158eb188d0eSMatt Porter * enumeration succeeds or %-EBUSY if enumeration fails. 1159eb188d0eSMatt Porter */ 116037d33d15SAl Viro int __devinit rio_enum_mport(struct rio_mport *mport) 1161eb188d0eSMatt Porter { 1162eb188d0eSMatt Porter struct rio_net *net = NULL; 1163eb188d0eSMatt Porter int rc = 0; 1164eb188d0eSMatt Porter 1165eb188d0eSMatt Porter printk(KERN_INFO "RIO: enumerate master port %d, %s\n", mport->id, 1166eb188d0eSMatt Porter mport->name); 1167eb188d0eSMatt Porter /* If somebody else enumerated our master port device, bail. */ 1168eb188d0eSMatt Porter if (rio_enum_host(mport) < 0) { 1169eb188d0eSMatt Porter printk(KERN_INFO 1170eb188d0eSMatt Porter "RIO: master port %d device has been enumerated by a remote host\n", 1171eb188d0eSMatt Porter mport->id); 1172eb188d0eSMatt Porter rc = -EBUSY; 1173eb188d0eSMatt Porter goto out; 1174eb188d0eSMatt Porter } 1175eb188d0eSMatt Porter 1176eb188d0eSMatt Porter /* If master port has an active link, allocate net and enum peers */ 1177eb188d0eSMatt Porter if (rio_mport_is_active(mport)) { 1178eb188d0eSMatt Porter if (!(net = rio_alloc_net(mport))) { 1179eb188d0eSMatt Porter printk(KERN_ERR "RIO: failed to allocate new net\n"); 1180eb188d0eSMatt Porter rc = -ENOMEM; 1181eb188d0eSMatt Porter goto out; 1182eb188d0eSMatt Porter } 1183933af4a6SThomas Moll 1184933af4a6SThomas Moll /* Enable Input Output Port (transmitter reviever) */ 1185933af4a6SThomas Moll rio_enable_rx_tx_port(mport, 1, 0, 0, 0); 1186933af4a6SThomas Moll 1187eb188d0eSMatt Porter if (rio_enum_peer(net, mport, 0) < 0) { 1188eb188d0eSMatt Porter /* A higher priority host won enumeration, bail. */ 1189eb188d0eSMatt Porter printk(KERN_INFO 1190eb188d0eSMatt Porter "RIO: master port %d device has lost enumeration to a remote host\n", 1191eb188d0eSMatt Porter mport->id); 1192eb188d0eSMatt Porter rio_clear_locks(mport); 1193eb188d0eSMatt Porter rc = -EBUSY; 1194eb188d0eSMatt Porter goto out; 1195eb188d0eSMatt Porter } 1196c70555b0SAlexandre Bounine rio_update_route_tables(mport); 1197eb188d0eSMatt Porter rio_clear_locks(mport); 1198e5cabeb3SAlexandre Bounine rio_pw_enable(mport, 1); 1199eb188d0eSMatt Porter } else { 1200eb188d0eSMatt Porter printk(KERN_INFO "RIO: master port %d link inactive\n", 1201eb188d0eSMatt Porter mport->id); 1202eb188d0eSMatt Porter rc = -EINVAL; 1203eb188d0eSMatt Porter } 1204eb188d0eSMatt Porter 1205eb188d0eSMatt Porter out: 1206eb188d0eSMatt Porter return rc; 1207eb188d0eSMatt Porter } 1208eb188d0eSMatt Porter 1209eb188d0eSMatt Porter /** 1210eb188d0eSMatt Porter * rio_build_route_tables- Generate route tables from switch route entries 1211eb188d0eSMatt Porter * 1212eb188d0eSMatt Porter * For each switch device, generate a route table by copying existing 1213eb188d0eSMatt Porter * route entries from the switch. 1214eb188d0eSMatt Porter */ 1215eb188d0eSMatt Porter static void rio_build_route_tables(void) 1216eb188d0eSMatt Porter { 1217eb188d0eSMatt Porter struct rio_dev *rdev; 1218eb188d0eSMatt Porter int i; 1219eb188d0eSMatt Porter u8 sport; 1220eb188d0eSMatt Porter 1221eb188d0eSMatt Porter list_for_each_entry(rdev, &rio_devices, global_list) 1222818a04a0SAlexandre Bounine if (rio_is_switch(rdev)) { 1223818a04a0SAlexandre Bounine rio_lock_device(rdev->net->hport, rdev->rswitch->destid, 1224818a04a0SAlexandre Bounine rdev->rswitch->hopcount, 1000); 1225e0423236SZhang Wei for (i = 0; 1226e0423236SZhang Wei i < RIO_MAX_ROUTE_ENTRIES(rdev->net->hport->sys_size); 1227e0423236SZhang Wei i++) { 1228eb188d0eSMatt Porter if (rio_route_get_entry 1229818a04a0SAlexandre Bounine (rdev->net->hport, rdev->rswitch, 1230818a04a0SAlexandre Bounine RIO_GLOBAL_TABLE, i, &sport, 0) < 0) 1231eb188d0eSMatt Porter continue; 1232eb188d0eSMatt Porter rdev->rswitch->route_table[i] = sport; 1233eb188d0eSMatt Porter } 1234818a04a0SAlexandre Bounine 1235818a04a0SAlexandre Bounine rio_unlock_device(rdev->net->hport, 1236818a04a0SAlexandre Bounine rdev->rswitch->destid, 1237818a04a0SAlexandre Bounine rdev->rswitch->hopcount); 1238818a04a0SAlexandre Bounine } 1239eb188d0eSMatt Porter } 1240eb188d0eSMatt Porter 1241eb188d0eSMatt Porter /** 1242eb188d0eSMatt Porter * rio_enum_timeout- Signal that enumeration timed out 1243eb188d0eSMatt Porter * @data: Address of timeout flag. 1244eb188d0eSMatt Porter * 1245eb188d0eSMatt Porter * When the enumeration complete timer expires, set a flag that 1246eb188d0eSMatt Porter * signals to the discovery process that enumeration did not 1247eb188d0eSMatt Porter * complete in a sane amount of time. 1248eb188d0eSMatt Porter */ 1249eb188d0eSMatt Porter static void rio_enum_timeout(unsigned long data) 1250eb188d0eSMatt Porter { 1251eb188d0eSMatt Porter /* Enumeration timed out, set flag */ 1252eb188d0eSMatt Porter *(int *)data = 1; 1253eb188d0eSMatt Porter } 1254eb188d0eSMatt Porter 1255eb188d0eSMatt Porter /** 1256eb188d0eSMatt Porter * rio_disc_mport- Start discovery through a master port 1257eb188d0eSMatt Porter * @mport: Master port to send transactions 1258eb188d0eSMatt Porter * 1259eb188d0eSMatt Porter * Starts the discovery process. If we have an active link, 1260eb188d0eSMatt Porter * then wait for the signal that enumeration is complete. 1261eb188d0eSMatt Porter * When enumeration completion is signaled, start recursive 1262eb188d0eSMatt Porter * peer discovery. Returns %0 if discovery succeeds or %-EBUSY 1263eb188d0eSMatt Porter * on failure. 1264eb188d0eSMatt Porter */ 126537d33d15SAl Viro int __devinit rio_disc_mport(struct rio_mport *mport) 1266eb188d0eSMatt Porter { 1267eb188d0eSMatt Porter struct rio_net *net = NULL; 1268eb188d0eSMatt Porter int enum_timeout_flag = 0; 1269eb188d0eSMatt Porter 1270eb188d0eSMatt Porter printk(KERN_INFO "RIO: discover master port %d, %s\n", mport->id, 1271eb188d0eSMatt Porter mport->name); 1272eb188d0eSMatt Porter 1273eb188d0eSMatt Porter /* If master port has an active link, allocate net and discover peers */ 1274eb188d0eSMatt Porter if (rio_mport_is_active(mport)) { 1275eb188d0eSMatt Porter if (!(net = rio_alloc_net(mport))) { 1276eb188d0eSMatt Porter printk(KERN_ERR "RIO: Failed to allocate new net\n"); 1277eb188d0eSMatt Porter goto bail; 1278eb188d0eSMatt Porter } 1279eb188d0eSMatt Porter 1280eb188d0eSMatt Porter pr_debug("RIO: wait for enumeration complete..."); 1281eb188d0eSMatt Porter 1282eb188d0eSMatt Porter rio_enum_timer.expires = 1283eb188d0eSMatt Porter jiffies + CONFIG_RAPIDIO_DISC_TIMEOUT * HZ; 1284eb188d0eSMatt Porter rio_enum_timer.data = (unsigned long)&enum_timeout_flag; 1285eb188d0eSMatt Porter add_timer(&rio_enum_timer); 1286eb188d0eSMatt Porter while (!rio_enum_complete(mport)) { 1287eb188d0eSMatt Porter mdelay(1); 1288eb188d0eSMatt Porter if (enum_timeout_flag) { 1289eb188d0eSMatt Porter del_timer_sync(&rio_enum_timer); 1290eb188d0eSMatt Porter goto timeout; 1291eb188d0eSMatt Porter } 1292eb188d0eSMatt Porter } 1293eb188d0eSMatt Porter del_timer_sync(&rio_enum_timer); 1294eb188d0eSMatt Porter 1295eb188d0eSMatt Porter pr_debug("done\n"); 1296818a04a0SAlexandre Bounine 1297818a04a0SAlexandre Bounine /* Read DestID assigned by enumerator */ 1298818a04a0SAlexandre Bounine rio_local_read_config_32(mport, RIO_DID_CSR, 1299818a04a0SAlexandre Bounine &mport->host_deviceid); 1300818a04a0SAlexandre Bounine mport->host_deviceid = RIO_GET_DID(mport->sys_size, 1301818a04a0SAlexandre Bounine mport->host_deviceid); 1302818a04a0SAlexandre Bounine 1303e0423236SZhang Wei if (rio_disc_peer(net, mport, RIO_ANY_DESTID(mport->sys_size), 1304e0423236SZhang Wei 0) < 0) { 1305eb188d0eSMatt Porter printk(KERN_INFO 1306eb188d0eSMatt Porter "RIO: master port %d device has failed discovery\n", 1307eb188d0eSMatt Porter mport->id); 1308eb188d0eSMatt Porter goto bail; 1309eb188d0eSMatt Porter } 1310eb188d0eSMatt Porter 1311eb188d0eSMatt Porter rio_build_route_tables(); 1312eb188d0eSMatt Porter } 1313eb188d0eSMatt Porter 1314eb188d0eSMatt Porter return 0; 1315eb188d0eSMatt Porter 1316eb188d0eSMatt Porter timeout: 1317eb188d0eSMatt Porter pr_debug("timeout\n"); 1318eb188d0eSMatt Porter bail: 1319eb188d0eSMatt Porter return -EBUSY; 1320eb188d0eSMatt Porter } 1321