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> 34fa3dbaa0SAlexandre Bounine #include <linux/sched.h> 35de25968cSTim Schmielau #include <linux/jiffies.h> 36de25968cSTim Schmielau #include <linux/slab.h> 37eb188d0eSMatt Porter 38eb188d0eSMatt Porter #include "rio.h" 39eb188d0eSMatt Porter 40eb188d0eSMatt Porter LIST_HEAD(rio_devices); 41eb188d0eSMatt Porter 42e5cabeb3SAlexandre Bounine static void rio_init_em(struct rio_dev *rdev); 43e5cabeb3SAlexandre Bounine 44fa78cc51SMatt Porter DEFINE_SPINLOCK(rio_global_list_lock); 45fa78cc51SMatt Porter 46eb188d0eSMatt Porter static int next_destid = 0; 47af84ca38SAlexandre Bounine static int next_comptag = 1; 48eb188d0eSMatt Porter 49eb188d0eSMatt Porter static int rio_mport_phys_table[] = { 50eb188d0eSMatt Porter RIO_EFB_PAR_EP_ID, 51eb188d0eSMatt Porter RIO_EFB_PAR_EP_REC_ID, 52eb188d0eSMatt Porter RIO_EFB_SER_EP_ID, 53eb188d0eSMatt Porter RIO_EFB_SER_EP_REC_ID, 54eb188d0eSMatt Porter -1, 55eb188d0eSMatt Porter }; 56eb188d0eSMatt Porter 57de74e00aSAlexandre Bounine 58de74e00aSAlexandre Bounine /* 59de74e00aSAlexandre Bounine * rio_destid_alloc - Allocate next available destID for given network 60de74e00aSAlexandre Bounine * net: RIO network 61de74e00aSAlexandre Bounine * 62de74e00aSAlexandre Bounine * Returns next available device destination ID for the specified RIO network. 63de74e00aSAlexandre Bounine * Marks allocated ID as one in use. 64de74e00aSAlexandre Bounine * Returns RIO_INVALID_DESTID if new destID is not available. 65de74e00aSAlexandre Bounine */ 66de74e00aSAlexandre Bounine static u16 rio_destid_alloc(struct rio_net *net) 67de74e00aSAlexandre Bounine { 68de74e00aSAlexandre Bounine int destid; 69de74e00aSAlexandre Bounine struct rio_id_table *idtab = &net->destid_table; 70de74e00aSAlexandre Bounine 71de74e00aSAlexandre Bounine spin_lock(&idtab->lock); 72de74e00aSAlexandre Bounine destid = find_next_zero_bit(idtab->table, idtab->max, idtab->next); 73de74e00aSAlexandre Bounine if (destid >= idtab->max) 74de74e00aSAlexandre Bounine destid = find_first_zero_bit(idtab->table, idtab->max); 75de74e00aSAlexandre Bounine 76de74e00aSAlexandre Bounine if (destid < idtab->max) { 77de74e00aSAlexandre Bounine idtab->next = destid + 1; 78de74e00aSAlexandre Bounine if (idtab->next >= idtab->max) 79de74e00aSAlexandre Bounine idtab->next = 0; 80de74e00aSAlexandre Bounine set_bit(destid, idtab->table); 81de74e00aSAlexandre Bounine destid += idtab->start; 82de74e00aSAlexandre Bounine } else 83de74e00aSAlexandre Bounine destid = RIO_INVALID_DESTID; 84de74e00aSAlexandre Bounine 85de74e00aSAlexandre Bounine spin_unlock(&idtab->lock); 86de74e00aSAlexandre Bounine return (u16)destid; 87de74e00aSAlexandre Bounine } 88de74e00aSAlexandre Bounine 89de74e00aSAlexandre Bounine /* 90de74e00aSAlexandre Bounine * rio_destid_reserve - Reserve the specivied destID 91de74e00aSAlexandre Bounine * net: RIO network 92de74e00aSAlexandre Bounine * destid: destID to reserve 93de74e00aSAlexandre Bounine * 94de74e00aSAlexandre Bounine * Tries to reserve the specified destID. 95de74e00aSAlexandre Bounine * Returns 0 if successfull. 96de74e00aSAlexandre Bounine */ 97de74e00aSAlexandre Bounine static int rio_destid_reserve(struct rio_net *net, u16 destid) 98de74e00aSAlexandre Bounine { 99de74e00aSAlexandre Bounine int oldbit; 100de74e00aSAlexandre Bounine struct rio_id_table *idtab = &net->destid_table; 101de74e00aSAlexandre Bounine 102de74e00aSAlexandre Bounine destid -= idtab->start; 103de74e00aSAlexandre Bounine spin_lock(&idtab->lock); 104de74e00aSAlexandre Bounine oldbit = test_and_set_bit(destid, idtab->table); 105de74e00aSAlexandre Bounine spin_unlock(&idtab->lock); 106de74e00aSAlexandre Bounine return oldbit; 107de74e00aSAlexandre Bounine } 108de74e00aSAlexandre Bounine 109de74e00aSAlexandre Bounine /* 110de74e00aSAlexandre Bounine * rio_destid_free - free a previously allocated destID 111de74e00aSAlexandre Bounine * net: RIO network 112de74e00aSAlexandre Bounine * destid: destID to free 113de74e00aSAlexandre Bounine * 114de74e00aSAlexandre Bounine * Makes the specified destID available for use. 115de74e00aSAlexandre Bounine */ 116de74e00aSAlexandre Bounine static void rio_destid_free(struct rio_net *net, u16 destid) 117de74e00aSAlexandre Bounine { 118de74e00aSAlexandre Bounine struct rio_id_table *idtab = &net->destid_table; 119de74e00aSAlexandre Bounine 120de74e00aSAlexandre Bounine destid -= idtab->start; 121de74e00aSAlexandre Bounine spin_lock(&idtab->lock); 122de74e00aSAlexandre Bounine clear_bit(destid, idtab->table); 123de74e00aSAlexandre Bounine spin_unlock(&idtab->lock); 124de74e00aSAlexandre Bounine } 125de74e00aSAlexandre Bounine 126de74e00aSAlexandre Bounine /* 127de74e00aSAlexandre Bounine * rio_destid_first - return first destID in use 128de74e00aSAlexandre Bounine * net: RIO network 129de74e00aSAlexandre Bounine */ 130de74e00aSAlexandre Bounine static u16 rio_destid_first(struct rio_net *net) 131de74e00aSAlexandre Bounine { 132de74e00aSAlexandre Bounine int destid; 133de74e00aSAlexandre Bounine struct rio_id_table *idtab = &net->destid_table; 134de74e00aSAlexandre Bounine 135de74e00aSAlexandre Bounine spin_lock(&idtab->lock); 136de74e00aSAlexandre Bounine destid = find_first_bit(idtab->table, idtab->max); 137de74e00aSAlexandre Bounine if (destid >= idtab->max) 138de74e00aSAlexandre Bounine destid = RIO_INVALID_DESTID; 139de74e00aSAlexandre Bounine else 140de74e00aSAlexandre Bounine destid += idtab->start; 141de74e00aSAlexandre Bounine spin_unlock(&idtab->lock); 142de74e00aSAlexandre Bounine return (u16)destid; 143de74e00aSAlexandre Bounine } 144de74e00aSAlexandre Bounine 145de74e00aSAlexandre Bounine /* 146de74e00aSAlexandre Bounine * rio_destid_next - return next destID in use 147de74e00aSAlexandre Bounine * net: RIO network 148de74e00aSAlexandre Bounine * from: destination ID from which search shall continue 149de74e00aSAlexandre Bounine */ 150de74e00aSAlexandre Bounine static u16 rio_destid_next(struct rio_net *net, u16 from) 151de74e00aSAlexandre Bounine { 152de74e00aSAlexandre Bounine int destid; 153de74e00aSAlexandre Bounine struct rio_id_table *idtab = &net->destid_table; 154de74e00aSAlexandre Bounine 155de74e00aSAlexandre Bounine spin_lock(&idtab->lock); 156de74e00aSAlexandre Bounine destid = find_next_bit(idtab->table, idtab->max, from); 157de74e00aSAlexandre Bounine if (destid >= idtab->max) 158de74e00aSAlexandre Bounine destid = RIO_INVALID_DESTID; 159de74e00aSAlexandre Bounine else 160de74e00aSAlexandre Bounine destid += idtab->start; 161de74e00aSAlexandre Bounine spin_unlock(&idtab->lock); 162de74e00aSAlexandre Bounine return (u16)destid; 163de74e00aSAlexandre Bounine } 164de74e00aSAlexandre Bounine 165eb188d0eSMatt Porter /** 166eb188d0eSMatt Porter * rio_get_device_id - Get the base/extended device id for a device 167eb188d0eSMatt Porter * @port: RIO master port 168eb188d0eSMatt Porter * @destid: Destination ID of device 169eb188d0eSMatt Porter * @hopcount: Hopcount to device 170eb188d0eSMatt Porter * 171eb188d0eSMatt Porter * Reads the base/extended device id from a device. Returns the 172eb188d0eSMatt Porter * 8/16-bit device ID. 173eb188d0eSMatt Porter */ 174eb188d0eSMatt Porter static u16 rio_get_device_id(struct rio_mport *port, u16 destid, u8 hopcount) 175eb188d0eSMatt Porter { 176eb188d0eSMatt Porter u32 result; 177eb188d0eSMatt Porter 178eb188d0eSMatt Porter rio_mport_read_config_32(port, destid, hopcount, RIO_DID_CSR, &result); 179eb188d0eSMatt Porter 180e0423236SZhang Wei return RIO_GET_DID(port->sys_size, result); 181eb188d0eSMatt Porter } 182eb188d0eSMatt Porter 183eb188d0eSMatt Porter /** 184eb188d0eSMatt Porter * rio_set_device_id - Set the base/extended device id for a device 185eb188d0eSMatt Porter * @port: RIO master port 186eb188d0eSMatt Porter * @destid: Destination ID of device 187eb188d0eSMatt Porter * @hopcount: Hopcount to device 188eb188d0eSMatt Porter * @did: Device ID value to be written 189eb188d0eSMatt Porter * 190eb188d0eSMatt Porter * Writes the base/extended device id from a device. 191eb188d0eSMatt Porter */ 192fa78cc51SMatt Porter static void rio_set_device_id(struct rio_mport *port, u16 destid, u8 hopcount, u16 did) 193eb188d0eSMatt Porter { 194eb188d0eSMatt Porter rio_mport_write_config_32(port, destid, hopcount, RIO_DID_CSR, 195e0423236SZhang Wei RIO_SET_DID(port->sys_size, did)); 196eb188d0eSMatt Porter } 197eb188d0eSMatt Porter 198eb188d0eSMatt Porter /** 199eb188d0eSMatt Porter * rio_local_set_device_id - Set the base/extended device id for a port 200eb188d0eSMatt Porter * @port: RIO master port 201eb188d0eSMatt Porter * @did: Device ID value to be written 202eb188d0eSMatt Porter * 203eb188d0eSMatt Porter * Writes the base/extended device id from a device. 204eb188d0eSMatt Porter */ 205eb188d0eSMatt Porter static void rio_local_set_device_id(struct rio_mport *port, u16 did) 206eb188d0eSMatt Porter { 207e0423236SZhang Wei rio_local_write_config_32(port, RIO_DID_CSR, RIO_SET_DID(port->sys_size, 208e0423236SZhang Wei did)); 209eb188d0eSMatt Porter } 210eb188d0eSMatt Porter 211eb188d0eSMatt Porter /** 212eb188d0eSMatt Porter * rio_clear_locks- Release all host locks and signal enumeration complete 213a7071efcSAlexandre Bounine * @net: RIO network to run on 214eb188d0eSMatt Porter * 215eb188d0eSMatt Porter * Marks the component tag CSR on each device with the enumeration 216eb188d0eSMatt Porter * complete flag. When complete, it then release the host locks on 217eb188d0eSMatt Porter * each device. Returns 0 on success or %-EINVAL on failure. 218eb188d0eSMatt Porter */ 219a7071efcSAlexandre Bounine static int rio_clear_locks(struct rio_net *net) 220eb188d0eSMatt Porter { 221a7071efcSAlexandre Bounine struct rio_mport *port = net->hport; 222eb188d0eSMatt Porter struct rio_dev *rdev; 223eb188d0eSMatt Porter u32 result; 224eb188d0eSMatt Porter int ret = 0; 225eb188d0eSMatt Porter 226eb188d0eSMatt Porter /* Release host device id locks */ 227eb188d0eSMatt Porter rio_local_write_config_32(port, RIO_HOST_DID_LOCK_CSR, 228eb188d0eSMatt Porter port->host_deviceid); 229eb188d0eSMatt Porter rio_local_read_config_32(port, RIO_HOST_DID_LOCK_CSR, &result); 230eb188d0eSMatt Porter if ((result & 0xffff) != 0xffff) { 231eb188d0eSMatt Porter printk(KERN_INFO 232eb188d0eSMatt Porter "RIO: badness when releasing host lock on master port, result %8.8x\n", 233eb188d0eSMatt Porter result); 234eb188d0eSMatt Porter ret = -EINVAL; 235eb188d0eSMatt Porter } 236a7071efcSAlexandre Bounine list_for_each_entry(rdev, &net->devices, net_list) { 237eb188d0eSMatt Porter rio_write_config_32(rdev, RIO_HOST_DID_LOCK_CSR, 238eb188d0eSMatt Porter port->host_deviceid); 239eb188d0eSMatt Porter rio_read_config_32(rdev, RIO_HOST_DID_LOCK_CSR, &result); 240eb188d0eSMatt Porter if ((result & 0xffff) != 0xffff) { 241eb188d0eSMatt Porter printk(KERN_INFO 242eb188d0eSMatt Porter "RIO: badness when releasing host lock on vid %4.4x did %4.4x\n", 243eb188d0eSMatt Porter rdev->vid, rdev->did); 244eb188d0eSMatt Porter ret = -EINVAL; 245eb188d0eSMatt Porter } 246af84ca38SAlexandre Bounine 247af84ca38SAlexandre Bounine /* Mark device as discovered and enable master */ 248af84ca38SAlexandre Bounine rio_read_config_32(rdev, 249af84ca38SAlexandre Bounine rdev->phys_efptr + RIO_PORT_GEN_CTL_CSR, 250af84ca38SAlexandre Bounine &result); 251af84ca38SAlexandre Bounine result |= RIO_PORT_GEN_DISCOVERED | RIO_PORT_GEN_MASTER; 252af84ca38SAlexandre Bounine rio_write_config_32(rdev, 253af84ca38SAlexandre Bounine rdev->phys_efptr + RIO_PORT_GEN_CTL_CSR, 254af84ca38SAlexandre Bounine result); 255eb188d0eSMatt Porter } 256eb188d0eSMatt Porter 257eb188d0eSMatt Porter return ret; 258eb188d0eSMatt Porter } 259eb188d0eSMatt Porter 260eb188d0eSMatt Porter /** 261eb188d0eSMatt Porter * rio_enum_host- Set host lock and initialize host destination ID 262eb188d0eSMatt Porter * @port: Master port to issue transaction 263eb188d0eSMatt Porter * 264eb188d0eSMatt Porter * Sets the local host master port lock and destination ID register 265eb188d0eSMatt Porter * with the host device ID value. The host device ID value is provided 266eb188d0eSMatt Porter * by the platform. Returns %0 on success or %-1 on failure. 267eb188d0eSMatt Porter */ 268eb188d0eSMatt Porter static int rio_enum_host(struct rio_mport *port) 269eb188d0eSMatt Porter { 270eb188d0eSMatt Porter u32 result; 271eb188d0eSMatt Porter 272eb188d0eSMatt Porter /* Set master port host device id lock */ 273eb188d0eSMatt Porter rio_local_write_config_32(port, RIO_HOST_DID_LOCK_CSR, 274eb188d0eSMatt Porter port->host_deviceid); 275eb188d0eSMatt Porter 276eb188d0eSMatt Porter rio_local_read_config_32(port, RIO_HOST_DID_LOCK_CSR, &result); 277eb188d0eSMatt Porter if ((result & 0xffff) != port->host_deviceid) 278eb188d0eSMatt Porter return -1; 279eb188d0eSMatt Porter 280eb188d0eSMatt Porter /* Set master port destid and init destid ctr */ 281eb188d0eSMatt Porter rio_local_set_device_id(port, port->host_deviceid); 282eb188d0eSMatt Porter return 0; 283eb188d0eSMatt Porter } 284eb188d0eSMatt Porter 285eb188d0eSMatt Porter /** 286eb188d0eSMatt Porter * rio_device_has_destid- Test if a device contains a destination ID register 287eb188d0eSMatt Porter * @port: Master port to issue transaction 288eb188d0eSMatt Porter * @src_ops: RIO device source operations 289eb188d0eSMatt Porter * @dst_ops: RIO device destination operations 290eb188d0eSMatt Porter * 291eb188d0eSMatt Porter * Checks the provided @src_ops and @dst_ops for the necessary transaction 292eb188d0eSMatt Porter * capabilities that indicate whether or not a device will implement a 293eb188d0eSMatt Porter * destination ID register. Returns 1 if true or 0 if false. 294eb188d0eSMatt Porter */ 295eb188d0eSMatt Porter static int rio_device_has_destid(struct rio_mport *port, int src_ops, 296eb188d0eSMatt Porter int dst_ops) 297eb188d0eSMatt Porter { 298fa78cc51SMatt 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; 299fa78cc51SMatt Porter 300fa78cc51SMatt Porter return !!((src_ops | dst_ops) & mask); 301eb188d0eSMatt Porter } 302eb188d0eSMatt Porter 303eb188d0eSMatt Porter /** 304eb188d0eSMatt Porter * rio_release_dev- Frees a RIO device struct 305eb188d0eSMatt Porter * @dev: LDM device associated with a RIO device struct 306eb188d0eSMatt Porter * 307eb188d0eSMatt Porter * Gets the RIO device struct associated a RIO device struct. 308eb188d0eSMatt Porter * The RIO device struct is freed. 309eb188d0eSMatt Porter */ 310eb188d0eSMatt Porter static void rio_release_dev(struct device *dev) 311eb188d0eSMatt Porter { 312eb188d0eSMatt Porter struct rio_dev *rdev; 313eb188d0eSMatt Porter 314eb188d0eSMatt Porter rdev = to_rio_dev(dev); 315eb188d0eSMatt Porter kfree(rdev); 316eb188d0eSMatt Porter } 317eb188d0eSMatt Porter 318eb188d0eSMatt Porter /** 319eb188d0eSMatt Porter * rio_is_switch- Tests if a RIO device has switch capabilities 320eb188d0eSMatt Porter * @rdev: RIO device 321eb188d0eSMatt Porter * 322eb188d0eSMatt Porter * Gets the RIO device Processing Element Features register 323eb188d0eSMatt Porter * contents and tests for switch capabilities. Returns 1 if 324eb188d0eSMatt Porter * the device is a switch or 0 if it is not a switch. 325eb188d0eSMatt Porter * The RIO device struct is freed. 326eb188d0eSMatt Porter */ 327eb188d0eSMatt Porter static int rio_is_switch(struct rio_dev *rdev) 328eb188d0eSMatt Porter { 329eb188d0eSMatt Porter if (rdev->pef & RIO_PEF_SWITCH) 330eb188d0eSMatt Porter return 1; 331eb188d0eSMatt Porter return 0; 332eb188d0eSMatt Porter } 333eb188d0eSMatt Porter 334eb188d0eSMatt Porter /** 335058f88d6SAlexandre Bounine * rio_switch_init - Sets switch operations for a particular vendor switch 336eb188d0eSMatt Porter * @rdev: RIO device 337058f88d6SAlexandre Bounine * @do_enum: Enumeration/Discovery mode flag 338eb188d0eSMatt Porter * 339058f88d6SAlexandre Bounine * Searches the RIO switch ops table for known switch types. If the vid 340058f88d6SAlexandre Bounine * and did match a switch table entry, then call switch initialization 341058f88d6SAlexandre Bounine * routine to setup switch-specific routines. 342eb188d0eSMatt Porter */ 343058f88d6SAlexandre Bounine static void rio_switch_init(struct rio_dev *rdev, int do_enum) 344eb188d0eSMatt Porter { 345058f88d6SAlexandre Bounine struct rio_switch_ops *cur = __start_rio_switch_ops; 346058f88d6SAlexandre Bounine struct rio_switch_ops *end = __end_rio_switch_ops; 347eb188d0eSMatt Porter 348eb188d0eSMatt Porter while (cur < end) { 349eb188d0eSMatt Porter if ((cur->vid == rdev->vid) && (cur->did == rdev->did)) { 350058f88d6SAlexandre Bounine pr_debug("RIO: calling init routine for %s\n", 351058f88d6SAlexandre Bounine rio_name(rdev)); 352058f88d6SAlexandre Bounine cur->init_hook(rdev, do_enum); 35307590ff0SAlexandre Bounine break; 354eb188d0eSMatt Porter } 355eb188d0eSMatt Porter cur++; 356eb188d0eSMatt Porter } 357eb188d0eSMatt Porter 35807590ff0SAlexandre Bounine if ((cur >= end) && (rdev->pef & RIO_PEF_STD_RT)) { 35907590ff0SAlexandre Bounine pr_debug("RIO: adding STD routing ops for %s\n", 36007590ff0SAlexandre Bounine rio_name(rdev)); 36107590ff0SAlexandre Bounine rdev->rswitch->add_entry = rio_std_route_add_entry; 36207590ff0SAlexandre Bounine rdev->rswitch->get_entry = rio_std_route_get_entry; 36307590ff0SAlexandre Bounine rdev->rswitch->clr_table = rio_std_route_clr_table; 36407590ff0SAlexandre Bounine } 36507590ff0SAlexandre Bounine 366eb188d0eSMatt Porter if (!rdev->rswitch->add_entry || !rdev->rswitch->get_entry) 367eb188d0eSMatt Porter printk(KERN_ERR "RIO: missing routing ops for %s\n", 368eb188d0eSMatt Porter rio_name(rdev)); 369eb188d0eSMatt Porter } 370eb188d0eSMatt Porter 371eb188d0eSMatt Porter /** 372eb188d0eSMatt Porter * rio_add_device- Adds a RIO device to the device model 373eb188d0eSMatt Porter * @rdev: RIO device 374eb188d0eSMatt Porter * 375eb188d0eSMatt Porter * Adds the RIO device to the global device list and adds the RIO 376eb188d0eSMatt Porter * device to the RIO device list. Creates the generic sysfs nodes 377eb188d0eSMatt Porter * for an RIO device. 378eb188d0eSMatt Porter */ 3795f28c520SYang Li static int __devinit rio_add_device(struct rio_dev *rdev) 380eb188d0eSMatt Porter { 3815f28c520SYang Li int err; 3825f28c520SYang Li 3835f28c520SYang Li err = device_add(&rdev->dev); 3845f28c520SYang Li if (err) 3855f28c520SYang Li return err; 386eb188d0eSMatt Porter 387eb188d0eSMatt Porter spin_lock(&rio_global_list_lock); 388eb188d0eSMatt Porter list_add_tail(&rdev->global_list, &rio_devices); 389eb188d0eSMatt Porter spin_unlock(&rio_global_list_lock); 390eb188d0eSMatt Porter 391eb188d0eSMatt Porter rio_create_sysfs_dev_files(rdev); 3925f28c520SYang Li 3935f28c520SYang Li return 0; 394eb188d0eSMatt Porter } 395eb188d0eSMatt Porter 396eb188d0eSMatt Porter /** 39725985edcSLucas De Marchi * rio_enable_rx_tx_port - enable input receiver and output transmitter of 398933af4a6SThomas Moll * given port 399933af4a6SThomas Moll * @port: Master port associated with the RIO network 400933af4a6SThomas Moll * @local: local=1 select local port otherwise a far device is reached 401933af4a6SThomas Moll * @destid: Destination ID of the device to check host bit 402933af4a6SThomas Moll * @hopcount: Number of hops to reach the target 403933af4a6SThomas Moll * @port_num: Port (-number on switch) to enable on a far end device 404933af4a6SThomas Moll * 405933af4a6SThomas Moll * Returns 0 or 1 from on General Control Command and Status Register 406933af4a6SThomas Moll * (EXT_PTR+0x3C) 407933af4a6SThomas Moll */ 408933af4a6SThomas Moll inline int rio_enable_rx_tx_port(struct rio_mport *port, 409933af4a6SThomas Moll int local, u16 destid, 410933af4a6SThomas Moll u8 hopcount, u8 port_num) { 411933af4a6SThomas Moll #ifdef CONFIG_RAPIDIO_ENABLE_RX_TX_PORTS 412933af4a6SThomas Moll u32 regval; 413933af4a6SThomas Moll u32 ext_ftr_ptr; 414933af4a6SThomas Moll 415933af4a6SThomas Moll /* 416933af4a6SThomas Moll * enable rx input tx output port 417933af4a6SThomas Moll */ 418933af4a6SThomas Moll pr_debug("rio_enable_rx_tx_port(local = %d, destid = %d, hopcount = " 419933af4a6SThomas Moll "%d, port_num = %d)\n", local, destid, hopcount, port_num); 420933af4a6SThomas Moll 421933af4a6SThomas Moll ext_ftr_ptr = rio_mport_get_physefb(port, local, destid, hopcount); 422933af4a6SThomas Moll 423933af4a6SThomas Moll if (local) { 424933af4a6SThomas Moll rio_local_read_config_32(port, ext_ftr_ptr + 425933af4a6SThomas Moll RIO_PORT_N_CTL_CSR(0), 426933af4a6SThomas Moll ®val); 427933af4a6SThomas Moll } else { 428933af4a6SThomas Moll if (rio_mport_read_config_32(port, destid, hopcount, 429933af4a6SThomas Moll ext_ftr_ptr + RIO_PORT_N_CTL_CSR(port_num), ®val) < 0) 430933af4a6SThomas Moll return -EIO; 431933af4a6SThomas Moll } 432933af4a6SThomas Moll 433933af4a6SThomas Moll if (regval & RIO_PORT_N_CTL_P_TYP_SER) { 434933af4a6SThomas Moll /* serial */ 435933af4a6SThomas Moll regval = regval | RIO_PORT_N_CTL_EN_RX_SER 436933af4a6SThomas Moll | RIO_PORT_N_CTL_EN_TX_SER; 437933af4a6SThomas Moll } else { 438933af4a6SThomas Moll /* parallel */ 439933af4a6SThomas Moll regval = regval | RIO_PORT_N_CTL_EN_RX_PAR 440933af4a6SThomas Moll | RIO_PORT_N_CTL_EN_TX_PAR; 441933af4a6SThomas Moll } 442933af4a6SThomas Moll 443933af4a6SThomas Moll if (local) { 444933af4a6SThomas Moll rio_local_write_config_32(port, ext_ftr_ptr + 445933af4a6SThomas Moll RIO_PORT_N_CTL_CSR(0), regval); 446933af4a6SThomas Moll } else { 447933af4a6SThomas Moll if (rio_mport_write_config_32(port, destid, hopcount, 448933af4a6SThomas Moll ext_ftr_ptr + RIO_PORT_N_CTL_CSR(port_num), regval) < 0) 449933af4a6SThomas Moll return -EIO; 450933af4a6SThomas Moll } 451933af4a6SThomas Moll #endif 452933af4a6SThomas Moll return 0; 453933af4a6SThomas Moll } 454933af4a6SThomas Moll 455933af4a6SThomas Moll /** 456eb188d0eSMatt Porter * rio_setup_device- Allocates and sets up a RIO device 457eb188d0eSMatt Porter * @net: RIO network 458eb188d0eSMatt Porter * @port: Master port to send transactions 459eb188d0eSMatt Porter * @destid: Current destination ID 460eb188d0eSMatt Porter * @hopcount: Current hopcount 461eb188d0eSMatt Porter * @do_enum: Enumeration/Discovery mode flag 462eb188d0eSMatt Porter * 463eb188d0eSMatt Porter * Allocates a RIO device and configures fields based on configuration 464eb188d0eSMatt Porter * space contents. If device has a destination ID register, a destination 465eb188d0eSMatt Porter * ID is either assigned in enumeration mode or read from configuration 466eb188d0eSMatt Porter * space in discovery mode. If the device has switch capabilities, then 467eb188d0eSMatt Porter * a switch is allocated and configured appropriately. Returns a pointer 468eb188d0eSMatt Porter * to a RIO device on success or NULL on failure. 469eb188d0eSMatt Porter * 470eb188d0eSMatt Porter */ 471181a6ff0SLi Yang static struct rio_dev __devinit *rio_setup_device(struct rio_net *net, 472eb188d0eSMatt Porter struct rio_mport *port, u16 destid, 473eb188d0eSMatt Porter u8 hopcount, int do_enum) 474eb188d0eSMatt Porter { 4755f28c520SYang Li int ret = 0; 476eb188d0eSMatt Porter struct rio_dev *rdev; 4775f28c520SYang Li struct rio_switch *rswitch = NULL; 478eb188d0eSMatt Porter int result, rdid; 479ded05782SAlexandre Bounine size_t size; 480ded05782SAlexandre Bounine u32 swpinfo = 0; 481eb188d0eSMatt Porter 482ded05782SAlexandre Bounine size = sizeof(struct rio_dev); 483ded05782SAlexandre Bounine if (rio_mport_read_config_32(port, destid, hopcount, 484ded05782SAlexandre Bounine RIO_PEF_CAR, &result)) 485ded05782SAlexandre Bounine return NULL; 486ded05782SAlexandre Bounine 487ded05782SAlexandre Bounine if (result & (RIO_PEF_SWITCH | RIO_PEF_MULTIPORT)) { 488ded05782SAlexandre Bounine rio_mport_read_config_32(port, destid, hopcount, 489ded05782SAlexandre Bounine RIO_SWP_INFO_CAR, &swpinfo); 490ded05782SAlexandre Bounine if (result & RIO_PEF_SWITCH) { 491ded05782SAlexandre Bounine size += (RIO_GET_TOTAL_PORTS(swpinfo) * 492ded05782SAlexandre Bounine sizeof(rswitch->nextdev[0])) + sizeof(*rswitch); 493ded05782SAlexandre Bounine } 494ded05782SAlexandre Bounine } 495ded05782SAlexandre Bounine 496ded05782SAlexandre Bounine rdev = kzalloc(size, GFP_KERNEL); 497eb188d0eSMatt Porter if (!rdev) 4985f28c520SYang Li return NULL; 499eb188d0eSMatt Porter 500eb188d0eSMatt Porter rdev->net = net; 501ded05782SAlexandre Bounine rdev->pef = result; 502ded05782SAlexandre Bounine rdev->swpinfo = swpinfo; 503eb188d0eSMatt Porter rio_mport_read_config_32(port, destid, hopcount, RIO_DEV_ID_CAR, 504eb188d0eSMatt Porter &result); 505eb188d0eSMatt Porter rdev->did = result >> 16; 506eb188d0eSMatt Porter rdev->vid = result & 0xffff; 507eb188d0eSMatt Porter rio_mport_read_config_32(port, destid, hopcount, RIO_DEV_INFO_CAR, 508eb188d0eSMatt Porter &rdev->device_rev); 509eb188d0eSMatt Porter rio_mport_read_config_32(port, destid, hopcount, RIO_ASM_ID_CAR, 510eb188d0eSMatt Porter &result); 511eb188d0eSMatt Porter rdev->asm_did = result >> 16; 512eb188d0eSMatt Porter rdev->asm_vid = result & 0xffff; 513eb188d0eSMatt Porter rio_mport_read_config_32(port, destid, hopcount, RIO_ASM_INFO_CAR, 514eb188d0eSMatt Porter &result); 515eb188d0eSMatt Porter rdev->asm_rev = result >> 16; 516e5cabeb3SAlexandre Bounine if (rdev->pef & RIO_PEF_EXT_FEATURES) { 517eb188d0eSMatt Porter rdev->efptr = result & 0xffff; 518e5cabeb3SAlexandre Bounine rdev->phys_efptr = rio_mport_get_physefb(port, 0, destid, 519e5cabeb3SAlexandre Bounine hopcount); 520e5cabeb3SAlexandre Bounine 521e5cabeb3SAlexandre Bounine rdev->em_efptr = rio_mport_get_feature(port, 0, destid, 522e5cabeb3SAlexandre Bounine hopcount, RIO_EFB_ERR_MGMNT); 523e5cabeb3SAlexandre Bounine } 524eb188d0eSMatt Porter 525eb188d0eSMatt Porter rio_mport_read_config_32(port, destid, hopcount, RIO_SRC_OPS_CAR, 526eb188d0eSMatt Porter &rdev->src_ops); 527eb188d0eSMatt Porter rio_mport_read_config_32(port, destid, hopcount, RIO_DST_OPS_CAR, 528eb188d0eSMatt Porter &rdev->dst_ops); 529eb188d0eSMatt Porter 530af84ca38SAlexandre Bounine if (do_enum) { 531af84ca38SAlexandre Bounine /* Assign component tag to device */ 532af84ca38SAlexandre Bounine if (next_comptag >= 0x10000) { 533af84ca38SAlexandre Bounine pr_err("RIO: Component Tag Counter Overflow\n"); 534af84ca38SAlexandre Bounine goto cleanup; 535af84ca38SAlexandre Bounine } 536af84ca38SAlexandre Bounine rio_mport_write_config_32(port, destid, hopcount, 537af84ca38SAlexandre Bounine RIO_COMPONENT_TAG_CSR, next_comptag); 538af84ca38SAlexandre Bounine rdev->comp_tag = next_comptag++; 539558bda65SAlexandre Bounine } else { 540558bda65SAlexandre Bounine rio_mport_read_config_32(port, destid, hopcount, 541558bda65SAlexandre Bounine RIO_COMPONENT_TAG_CSR, 542558bda65SAlexandre Bounine &rdev->comp_tag); 543af84ca38SAlexandre Bounine } 544af84ca38SAlexandre Bounine 545c70555b0SAlexandre Bounine if (rio_device_has_destid(port, rdev->src_ops, rdev->dst_ops)) { 546c70555b0SAlexandre Bounine if (do_enum) { 547eb188d0eSMatt Porter rio_set_device_id(port, destid, hopcount, next_destid); 548de74e00aSAlexandre Bounine rdev->destid = next_destid; 549de74e00aSAlexandre Bounine next_destid = rio_destid_alloc(net); 550eb188d0eSMatt Porter } else 551eb188d0eSMatt Porter rdev->destid = rio_get_device_id(port, destid, hopcount); 552a93192a5SAlexandre Bounine 553a93192a5SAlexandre Bounine rdev->hopcount = 0xff; 554a93192a5SAlexandre Bounine } else { 555a93192a5SAlexandre Bounine /* Switch device has an associated destID which 556a93192a5SAlexandre Bounine * will be adjusted later 557a93192a5SAlexandre Bounine */ 558a93192a5SAlexandre Bounine rdev->destid = destid; 559a93192a5SAlexandre Bounine rdev->hopcount = hopcount; 560a93192a5SAlexandre Bounine } 561eb188d0eSMatt Porter 562eb188d0eSMatt Porter /* If a PE has both switch and other functions, show it as a switch */ 563eb188d0eSMatt Porter if (rio_is_switch(rdev)) { 564ded05782SAlexandre Bounine rswitch = rdev->rswitch; 565558bda65SAlexandre Bounine rswitch->switchid = rdev->comp_tag & RIO_CTAG_UDEVID; 566e5cabeb3SAlexandre Bounine rswitch->port_ok = 0; 567e0423236SZhang Wei rswitch->route_table = kzalloc(sizeof(u8)* 568e0423236SZhang Wei RIO_MAX_ROUTE_ENTRIES(port->sys_size), 569e0423236SZhang Wei GFP_KERNEL); 5705f28c520SYang Li if (!rswitch->route_table) 5715f28c520SYang Li goto cleanup; 572eb188d0eSMatt Porter /* Initialize switch route table */ 573e0423236SZhang Wei for (rdid = 0; rdid < RIO_MAX_ROUTE_ENTRIES(port->sys_size); 574e0423236SZhang Wei rdid++) 575eb188d0eSMatt Porter rswitch->route_table[rdid] = RIO_INVALID_ROUTE; 576b53c7583SKay Sievers dev_set_name(&rdev->dev, "%02x:s:%04x", rdev->net->id, 577ded05782SAlexandre Bounine rswitch->switchid); 578058f88d6SAlexandre Bounine rio_switch_init(rdev, do_enum); 579eb188d0eSMatt Porter 580ded05782SAlexandre Bounine if (do_enum && rswitch->clr_table) 581ded05782SAlexandre Bounine rswitch->clr_table(port, destid, hopcount, 58207590ff0SAlexandre Bounine RIO_GLOBAL_TABLE); 58307590ff0SAlexandre Bounine 584a7071efcSAlexandre Bounine list_add_tail(&rswitch->node, &net->switches); 585eb188d0eSMatt Porter 586933af4a6SThomas Moll } else { 587933af4a6SThomas Moll if (do_enum) 588933af4a6SThomas Moll /*Enable Input Output Port (transmitter reviever)*/ 589933af4a6SThomas Moll rio_enable_rx_tx_port(port, 0, destid, hopcount, 0); 590933af4a6SThomas Moll 591b53c7583SKay Sievers dev_set_name(&rdev->dev, "%02x:e:%04x", rdev->net->id, 592eb188d0eSMatt Porter rdev->destid); 593933af4a6SThomas Moll } 594eb188d0eSMatt Porter 595eb188d0eSMatt Porter rdev->dev.bus = &rio_bus_type; 5962c70f022SAlexandre Bounine rdev->dev.parent = &rio_bus; 597eb188d0eSMatt Porter 598eb188d0eSMatt Porter device_initialize(&rdev->dev); 599eb188d0eSMatt Porter rdev->dev.release = rio_release_dev; 600eb188d0eSMatt Porter rio_dev_get(rdev); 601eb188d0eSMatt Porter 602284901a9SYang Hongyang rdev->dma_mask = DMA_BIT_MASK(32); 603fa78cc51SMatt Porter rdev->dev.dma_mask = &rdev->dma_mask; 604284901a9SYang Hongyang rdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); 605eb188d0eSMatt Porter 606284fb68dSAlexandre Bounine if (rdev->dst_ops & RIO_DST_OPS_DOORBELL) 607eb188d0eSMatt Porter rio_init_dbell_res(&rdev->riores[RIO_DOORBELL_RESOURCE], 608eb188d0eSMatt Porter 0, 0xffff); 609eb188d0eSMatt Porter 6105f28c520SYang Li ret = rio_add_device(rdev); 6115f28c520SYang Li if (ret) 6125f28c520SYang Li goto cleanup; 613eb188d0eSMatt Porter 614eb188d0eSMatt Porter return rdev; 6155f28c520SYang Li 6165f28c520SYang Li cleanup: 617166c050bSAlexandre Bounine if (rswitch) 6185f28c520SYang Li kfree(rswitch->route_table); 619ded05782SAlexandre Bounine 6205f28c520SYang Li kfree(rdev); 6215f28c520SYang Li return NULL; 622eb188d0eSMatt Porter } 623eb188d0eSMatt Porter 624eb188d0eSMatt Porter /** 625eb188d0eSMatt Porter * rio_sport_is_active- Tests if a switch port has an active connection. 626eb188d0eSMatt Porter * @port: Master port to send transaction 627eb188d0eSMatt Porter * @destid: Associated destination ID for switch 628eb188d0eSMatt Porter * @hopcount: Hopcount to reach switch 629eb188d0eSMatt Porter * @sport: Switch port number 630eb188d0eSMatt Porter * 631eb188d0eSMatt Porter * Reads the port error status CSR for a particular switch port to 632eb188d0eSMatt Porter * determine if the port has an active link. Returns 633e5cabeb3SAlexandre Bounine * %RIO_PORT_N_ERR_STS_PORT_OK if the port is active or %0 if it is 634eb188d0eSMatt Porter * inactive. 635eb188d0eSMatt Porter */ 636eb188d0eSMatt Porter static int 637eb188d0eSMatt Porter rio_sport_is_active(struct rio_mport *port, u16 destid, u8 hopcount, int sport) 638eb188d0eSMatt Porter { 639e5cabeb3SAlexandre Bounine u32 result = 0; 640eb188d0eSMatt Porter u32 ext_ftr_ptr; 641eb188d0eSMatt Porter 642e5cabeb3SAlexandre Bounine ext_ftr_ptr = rio_mport_get_efb(port, 0, destid, hopcount, 0); 643eb188d0eSMatt Porter 644e5cabeb3SAlexandre Bounine while (ext_ftr_ptr) { 645e5cabeb3SAlexandre Bounine rio_mport_read_config_32(port, destid, hopcount, 646e5cabeb3SAlexandre Bounine ext_ftr_ptr, &result); 647e5cabeb3SAlexandre Bounine result = RIO_GET_BLOCK_ID(result); 648e5cabeb3SAlexandre Bounine if ((result == RIO_EFB_SER_EP_FREE_ID) || 649e5cabeb3SAlexandre Bounine (result == RIO_EFB_SER_EP_FREE_ID_V13P) || 650e5cabeb3SAlexandre Bounine (result == RIO_EFB_SER_EP_FREC_ID)) 651eb188d0eSMatt Porter break; 652e5cabeb3SAlexandre Bounine 653e5cabeb3SAlexandre Bounine ext_ftr_ptr = rio_mport_get_efb(port, 0, destid, hopcount, 654e5cabeb3SAlexandre Bounine ext_ftr_ptr); 655e5cabeb3SAlexandre Bounine } 656eb188d0eSMatt Porter 657eb188d0eSMatt Porter if (ext_ftr_ptr) 658eb188d0eSMatt Porter rio_mport_read_config_32(port, destid, hopcount, 659eb188d0eSMatt Porter ext_ftr_ptr + 660eb188d0eSMatt Porter RIO_PORT_N_ERR_STS_CSR(sport), 661eb188d0eSMatt Porter &result); 662eb188d0eSMatt Porter 663e5cabeb3SAlexandre Bounine return result & RIO_PORT_N_ERR_STS_PORT_OK; 664eb188d0eSMatt Porter } 665eb188d0eSMatt Porter 666eb188d0eSMatt Porter /** 667818a04a0SAlexandre Bounine * rio_lock_device - Acquires host device lock for specified device 668818a04a0SAlexandre Bounine * @port: Master port to send transaction 669818a04a0SAlexandre Bounine * @destid: Destination ID for device/switch 670818a04a0SAlexandre Bounine * @hopcount: Hopcount to reach switch 671818a04a0SAlexandre Bounine * @wait_ms: Max wait time in msec (0 = no timeout) 672818a04a0SAlexandre Bounine * 673818a04a0SAlexandre Bounine * Attepts to acquire host device lock for specified device 674818a04a0SAlexandre Bounine * Returns 0 if device lock acquired or EINVAL if timeout expires. 675818a04a0SAlexandre Bounine */ 676818a04a0SAlexandre Bounine static int 677818a04a0SAlexandre Bounine rio_lock_device(struct rio_mport *port, u16 destid, u8 hopcount, int wait_ms) 678818a04a0SAlexandre Bounine { 679818a04a0SAlexandre Bounine u32 result; 680818a04a0SAlexandre Bounine int tcnt = 0; 681818a04a0SAlexandre Bounine 682818a04a0SAlexandre Bounine /* Attempt to acquire device lock */ 683818a04a0SAlexandre Bounine rio_mport_write_config_32(port, destid, hopcount, 684818a04a0SAlexandre Bounine RIO_HOST_DID_LOCK_CSR, port->host_deviceid); 685818a04a0SAlexandre Bounine rio_mport_read_config_32(port, destid, hopcount, 686818a04a0SAlexandre Bounine RIO_HOST_DID_LOCK_CSR, &result); 687818a04a0SAlexandre Bounine 688818a04a0SAlexandre Bounine while (result != port->host_deviceid) { 689818a04a0SAlexandre Bounine if (wait_ms != 0 && tcnt == wait_ms) { 690818a04a0SAlexandre Bounine pr_debug("RIO: timeout when locking device %x:%x\n", 691818a04a0SAlexandre Bounine destid, hopcount); 692818a04a0SAlexandre Bounine return -EINVAL; 693818a04a0SAlexandre Bounine } 694818a04a0SAlexandre Bounine 695818a04a0SAlexandre Bounine /* Delay a bit */ 696818a04a0SAlexandre Bounine mdelay(1); 697818a04a0SAlexandre Bounine tcnt++; 698818a04a0SAlexandre Bounine /* Try to acquire device lock again */ 699818a04a0SAlexandre Bounine rio_mport_write_config_32(port, destid, 700818a04a0SAlexandre Bounine hopcount, 701818a04a0SAlexandre Bounine RIO_HOST_DID_LOCK_CSR, 702818a04a0SAlexandre Bounine port->host_deviceid); 703818a04a0SAlexandre Bounine rio_mport_read_config_32(port, destid, 704818a04a0SAlexandre Bounine hopcount, 705818a04a0SAlexandre Bounine RIO_HOST_DID_LOCK_CSR, &result); 706818a04a0SAlexandre Bounine } 707818a04a0SAlexandre Bounine 708818a04a0SAlexandre Bounine return 0; 709818a04a0SAlexandre Bounine } 710818a04a0SAlexandre Bounine 711818a04a0SAlexandre Bounine /** 712818a04a0SAlexandre Bounine * rio_unlock_device - Releases host device lock for specified device 713818a04a0SAlexandre Bounine * @port: Master port to send transaction 714818a04a0SAlexandre Bounine * @destid: Destination ID for device/switch 715818a04a0SAlexandre Bounine * @hopcount: Hopcount to reach switch 716818a04a0SAlexandre Bounine * 717818a04a0SAlexandre Bounine * Returns 0 if device lock released or EINVAL if fails. 718818a04a0SAlexandre Bounine */ 719818a04a0SAlexandre Bounine static int 720818a04a0SAlexandre Bounine rio_unlock_device(struct rio_mport *port, u16 destid, u8 hopcount) 721818a04a0SAlexandre Bounine { 722818a04a0SAlexandre Bounine u32 result; 723818a04a0SAlexandre Bounine 724818a04a0SAlexandre Bounine /* Release device lock */ 725818a04a0SAlexandre Bounine rio_mport_write_config_32(port, destid, 726818a04a0SAlexandre Bounine hopcount, 727818a04a0SAlexandre Bounine RIO_HOST_DID_LOCK_CSR, 728818a04a0SAlexandre Bounine port->host_deviceid); 729818a04a0SAlexandre Bounine rio_mport_read_config_32(port, destid, hopcount, 730818a04a0SAlexandre Bounine RIO_HOST_DID_LOCK_CSR, &result); 731818a04a0SAlexandre Bounine if ((result & 0xffff) != 0xffff) { 732818a04a0SAlexandre Bounine pr_debug("RIO: badness when releasing device lock %x:%x\n", 733818a04a0SAlexandre Bounine destid, hopcount); 734818a04a0SAlexandre Bounine return -EINVAL; 735818a04a0SAlexandre Bounine } 736818a04a0SAlexandre Bounine 737818a04a0SAlexandre Bounine return 0; 738818a04a0SAlexandre Bounine } 739818a04a0SAlexandre Bounine 740818a04a0SAlexandre Bounine /** 741eb188d0eSMatt Porter * rio_route_add_entry- Add a route entry to a switch routing table 742a93192a5SAlexandre Bounine * @rdev: RIO device 743eb188d0eSMatt Porter * @table: Routing table ID 744eb188d0eSMatt Porter * @route_destid: Destination ID to be routed 745eb188d0eSMatt Porter * @route_port: Port number to be routed 746818a04a0SAlexandre Bounine * @lock: lock switch device flag 747eb188d0eSMatt Porter * 748eb188d0eSMatt Porter * Calls the switch specific add_entry() method to add a route entry 749eb188d0eSMatt Porter * on a switch. The route table can be specified using the @table 750eb188d0eSMatt Porter * argument if a switch has per port routing tables or the normal 751eb188d0eSMatt Porter * use is to specific all tables (or the global table) by passing 752eb188d0eSMatt Porter * %RIO_GLOBAL_TABLE in @table. Returns %0 on success or %-EINVAL 753eb188d0eSMatt Porter * on failure. 754eb188d0eSMatt Porter */ 755818a04a0SAlexandre Bounine static int 756a93192a5SAlexandre Bounine rio_route_add_entry(struct rio_dev *rdev, 757818a04a0SAlexandre Bounine u16 table, u16 route_destid, u8 route_port, int lock) 758eb188d0eSMatt Porter { 759818a04a0SAlexandre Bounine int rc; 760818a04a0SAlexandre Bounine 761818a04a0SAlexandre Bounine if (lock) { 762a93192a5SAlexandre Bounine rc = rio_lock_device(rdev->net->hport, rdev->destid, 763a93192a5SAlexandre Bounine rdev->hopcount, 1000); 764818a04a0SAlexandre Bounine if (rc) 765818a04a0SAlexandre Bounine return rc; 766818a04a0SAlexandre Bounine } 767818a04a0SAlexandre Bounine 768a93192a5SAlexandre Bounine rc = rdev->rswitch->add_entry(rdev->net->hport, rdev->destid, 769a93192a5SAlexandre Bounine rdev->hopcount, table, 770eb188d0eSMatt Porter route_destid, route_port); 771818a04a0SAlexandre Bounine if (lock) 772a93192a5SAlexandre Bounine rio_unlock_device(rdev->net->hport, rdev->destid, 773a93192a5SAlexandre Bounine rdev->hopcount); 774818a04a0SAlexandre Bounine 775818a04a0SAlexandre Bounine return rc; 776eb188d0eSMatt Porter } 777eb188d0eSMatt Porter 778eb188d0eSMatt Porter /** 779eb188d0eSMatt Porter * rio_route_get_entry- Read a route entry in a switch routing table 780a93192a5SAlexandre Bounine * @rdev: RIO device 781eb188d0eSMatt Porter * @table: Routing table ID 782eb188d0eSMatt Porter * @route_destid: Destination ID to be routed 783eb188d0eSMatt Porter * @route_port: Pointer to read port number into 784818a04a0SAlexandre Bounine * @lock: lock switch device flag 785eb188d0eSMatt Porter * 786eb188d0eSMatt Porter * Calls the switch specific get_entry() method to read a route entry 787eb188d0eSMatt Porter * in a switch. The route table can be specified using the @table 788eb188d0eSMatt Porter * argument if a switch has per port routing tables or the normal 789eb188d0eSMatt Porter * use is to specific all tables (or the global table) by passing 790eb188d0eSMatt Porter * %RIO_GLOBAL_TABLE in @table. Returns %0 on success or %-EINVAL 791eb188d0eSMatt Porter * on failure. 792eb188d0eSMatt Porter */ 793eb188d0eSMatt Porter static int 794a93192a5SAlexandre Bounine rio_route_get_entry(struct rio_dev *rdev, u16 table, 795818a04a0SAlexandre Bounine u16 route_destid, u8 *route_port, int lock) 796eb188d0eSMatt Porter { 797818a04a0SAlexandre Bounine int rc; 798818a04a0SAlexandre Bounine 799818a04a0SAlexandre Bounine if (lock) { 800a93192a5SAlexandre Bounine rc = rio_lock_device(rdev->net->hport, rdev->destid, 801a93192a5SAlexandre Bounine rdev->hopcount, 1000); 802818a04a0SAlexandre Bounine if (rc) 803818a04a0SAlexandre Bounine return rc; 804818a04a0SAlexandre Bounine } 805818a04a0SAlexandre Bounine 806a93192a5SAlexandre Bounine rc = rdev->rswitch->get_entry(rdev->net->hport, rdev->destid, 807a93192a5SAlexandre Bounine rdev->hopcount, table, 808eb188d0eSMatt Porter route_destid, route_port); 809818a04a0SAlexandre Bounine if (lock) 810a93192a5SAlexandre Bounine rio_unlock_device(rdev->net->hport, rdev->destid, 811a93192a5SAlexandre Bounine rdev->hopcount); 812818a04a0SAlexandre Bounine 813818a04a0SAlexandre Bounine return rc; 814eb188d0eSMatt Porter } 815eb188d0eSMatt Porter 816eb188d0eSMatt Porter /** 817eb188d0eSMatt Porter * rio_get_host_deviceid_lock- Reads the Host Device ID Lock CSR on a device 818eb188d0eSMatt Porter * @port: Master port to send transaction 819eb188d0eSMatt Porter * @hopcount: Number of hops to the device 820eb188d0eSMatt Porter * 821eb188d0eSMatt Porter * Used during enumeration to read the Host Device ID Lock CSR on a 822eb188d0eSMatt Porter * RIO device. Returns the value of the lock register. 823eb188d0eSMatt Porter */ 824eb188d0eSMatt Porter static u16 rio_get_host_deviceid_lock(struct rio_mport *port, u8 hopcount) 825eb188d0eSMatt Porter { 826eb188d0eSMatt Porter u32 result; 827eb188d0eSMatt Porter 828e0423236SZhang Wei rio_mport_read_config_32(port, RIO_ANY_DESTID(port->sys_size), hopcount, 829eb188d0eSMatt Porter RIO_HOST_DID_LOCK_CSR, &result); 830eb188d0eSMatt Porter 831eb188d0eSMatt Porter return (u16) (result & 0xffff); 832eb188d0eSMatt Porter } 833eb188d0eSMatt Porter 834eb188d0eSMatt Porter /** 835eb188d0eSMatt Porter * rio_enum_peer- Recursively enumerate a RIO network through a master port 836eb188d0eSMatt Porter * @net: RIO network being enumerated 837eb188d0eSMatt Porter * @port: Master port to send transactions 838eb188d0eSMatt Porter * @hopcount: Number of hops into the network 83968fe4df5SAlexandre Bounine * @prev: Previous RIO device connected to the enumerated one 84068fe4df5SAlexandre Bounine * @prev_port: Port on previous RIO device 841eb188d0eSMatt Porter * 842eb188d0eSMatt Porter * Recursively enumerates a RIO network. Transactions are sent via the 843eb188d0eSMatt Porter * master port passed in @port. 844eb188d0eSMatt Porter */ 845181a6ff0SLi Yang static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port, 84668fe4df5SAlexandre Bounine u8 hopcount, struct rio_dev *prev, int prev_port) 847eb188d0eSMatt Porter { 848eb188d0eSMatt Porter struct rio_dev *rdev; 849af84ca38SAlexandre Bounine u32 regval; 850eb188d0eSMatt Porter int tmp; 851eb188d0eSMatt Porter 852e274e0edSAlexandre Bounine if (rio_mport_chk_dev_access(port, 853e274e0edSAlexandre Bounine RIO_ANY_DESTID(port->sys_size), hopcount)) { 854e274e0edSAlexandre Bounine pr_debug("RIO: device access check failed\n"); 855e274e0edSAlexandre Bounine return -1; 856e274e0edSAlexandre Bounine } 857e274e0edSAlexandre Bounine 858eb188d0eSMatt Porter if (rio_get_host_deviceid_lock(port, hopcount) == port->host_deviceid) { 859eb188d0eSMatt Porter pr_debug("RIO: PE already discovered by this host\n"); 860eb188d0eSMatt Porter /* 861eb188d0eSMatt Porter * Already discovered by this host. Add it as another 862af84ca38SAlexandre Bounine * link to the existing device. 863eb188d0eSMatt Porter */ 864af84ca38SAlexandre Bounine rio_mport_read_config_32(port, RIO_ANY_DESTID(port->sys_size), 865af84ca38SAlexandre Bounine hopcount, RIO_COMPONENT_TAG_CSR, ®val); 866af84ca38SAlexandre Bounine 867af84ca38SAlexandre Bounine if (regval) { 868af84ca38SAlexandre Bounine rdev = rio_get_comptag((regval & 0xffff), NULL); 869af84ca38SAlexandre Bounine 870af84ca38SAlexandre Bounine if (rdev && prev && rio_is_switch(prev)) { 871af84ca38SAlexandre Bounine pr_debug("RIO: redundant path to %s\n", 872af84ca38SAlexandre Bounine rio_name(rdev)); 873af84ca38SAlexandre Bounine prev->rswitch->nextdev[prev_port] = rdev; 874af84ca38SAlexandre Bounine } 875af84ca38SAlexandre Bounine } 876af84ca38SAlexandre Bounine 877eb188d0eSMatt Porter return 0; 878eb188d0eSMatt Porter } 879eb188d0eSMatt Porter 880eb188d0eSMatt Porter /* Attempt to acquire device lock */ 881e0423236SZhang Wei rio_mport_write_config_32(port, RIO_ANY_DESTID(port->sys_size), 882e0423236SZhang Wei hopcount, 883eb188d0eSMatt Porter RIO_HOST_DID_LOCK_CSR, port->host_deviceid); 884eb188d0eSMatt Porter while ((tmp = rio_get_host_deviceid_lock(port, hopcount)) 885eb188d0eSMatt Porter < port->host_deviceid) { 886eb188d0eSMatt Porter /* Delay a bit */ 887eb188d0eSMatt Porter mdelay(1); 888eb188d0eSMatt Porter /* Attempt to acquire device lock again */ 889e0423236SZhang Wei rio_mport_write_config_32(port, RIO_ANY_DESTID(port->sys_size), 890e0423236SZhang Wei hopcount, 891eb188d0eSMatt Porter RIO_HOST_DID_LOCK_CSR, 892eb188d0eSMatt Porter port->host_deviceid); 893eb188d0eSMatt Porter } 894eb188d0eSMatt Porter 895eb188d0eSMatt Porter if (rio_get_host_deviceid_lock(port, hopcount) > port->host_deviceid) { 896eb188d0eSMatt Porter pr_debug( 897eb188d0eSMatt Porter "RIO: PE locked by a higher priority host...retreating\n"); 898eb188d0eSMatt Porter return -1; 899eb188d0eSMatt Porter } 900eb188d0eSMatt Porter 901eb188d0eSMatt Porter /* Setup new RIO device */ 902e0423236SZhang Wei rdev = rio_setup_device(net, port, RIO_ANY_DESTID(port->sys_size), 903e0423236SZhang Wei hopcount, 1); 904e0423236SZhang Wei if (rdev) { 905eb188d0eSMatt Porter /* Add device to the global and bus/net specific list. */ 906eb188d0eSMatt Porter list_add_tail(&rdev->net_list, &net->devices); 90768fe4df5SAlexandre Bounine rdev->prev = prev; 90868fe4df5SAlexandre Bounine if (prev && rio_is_switch(prev)) 90968fe4df5SAlexandre Bounine prev->rswitch->nextdev[prev_port] = rdev; 910eb188d0eSMatt Porter } else 911eb188d0eSMatt Porter return -1; 912eb188d0eSMatt Porter 913eb188d0eSMatt Porter if (rio_is_switch(rdev)) { 914de74e00aSAlexandre Bounine int sw_destid; 915de74e00aSAlexandre Bounine int cur_destid; 916de74e00aSAlexandre Bounine int sw_inport; 917de74e00aSAlexandre Bounine u16 destid; 918de74e00aSAlexandre Bounine int port_num; 919de74e00aSAlexandre Bounine 920ae05cbd5SAlexandre Bounine sw_inport = RIO_GET_PORT_NUM(rdev->swpinfo); 921a93192a5SAlexandre Bounine rio_route_add_entry(rdev, RIO_GLOBAL_TABLE, 922818a04a0SAlexandre Bounine port->host_deviceid, sw_inport, 0); 923c70555b0SAlexandre Bounine rdev->rswitch->route_table[port->host_deviceid] = sw_inport; 924eb188d0eSMatt Porter 925de74e00aSAlexandre Bounine destid = rio_destid_first(net); 926de74e00aSAlexandre Bounine while (destid != RIO_INVALID_DESTID && destid < next_destid) { 927de74e00aSAlexandre Bounine if (destid != port->host_deviceid) { 928a93192a5SAlexandre Bounine rio_route_add_entry(rdev, RIO_GLOBAL_TABLE, 929818a04a0SAlexandre Bounine destid, sw_inport, 0); 930c70555b0SAlexandre Bounine rdev->rswitch->route_table[destid] = sw_inport; 931eb188d0eSMatt Porter } 932de74e00aSAlexandre Bounine destid = rio_destid_next(net, destid + 1); 933de74e00aSAlexandre Bounine } 934eb188d0eSMatt Porter pr_debug( 935eb188d0eSMatt Porter "RIO: found %s (vid %4.4x did %4.4x) with %d ports\n", 93668fe4df5SAlexandre Bounine rio_name(rdev), rdev->vid, rdev->did, 93768fe4df5SAlexandre Bounine RIO_GET_TOTAL_PORTS(rdev->swpinfo)); 938c70555b0SAlexandre Bounine sw_destid = next_destid; 93968fe4df5SAlexandre Bounine for (port_num = 0; 94068fe4df5SAlexandre Bounine port_num < RIO_GET_TOTAL_PORTS(rdev->swpinfo); 94168fe4df5SAlexandre Bounine port_num++) { 9428d4630dcSAlexandre Bounine if (sw_inport == port_num) { 943933af4a6SThomas Moll rio_enable_rx_tx_port(port, 0, 944933af4a6SThomas Moll RIO_ANY_DESTID(port->sys_size), 945933af4a6SThomas Moll hopcount, port_num); 946e5cabeb3SAlexandre Bounine rdev->rswitch->port_ok |= (1 << port_num); 947eb188d0eSMatt Porter continue; 948e5cabeb3SAlexandre Bounine } 949eb188d0eSMatt Porter 950eb188d0eSMatt Porter cur_destid = next_destid; 951eb188d0eSMatt Porter 952eb188d0eSMatt Porter if (rio_sport_is_active 953e0423236SZhang Wei (port, RIO_ANY_DESTID(port->sys_size), hopcount, 954e0423236SZhang Wei port_num)) { 955eb188d0eSMatt Porter pr_debug( 956eb188d0eSMatt Porter "RIO: scanning device on port %d\n", 957eb188d0eSMatt Porter port_num); 9588d4630dcSAlexandre Bounine rio_enable_rx_tx_port(port, 0, 9598d4630dcSAlexandre Bounine RIO_ANY_DESTID(port->sys_size), 9608d4630dcSAlexandre Bounine hopcount, port_num); 961e5cabeb3SAlexandre Bounine rdev->rswitch->port_ok |= (1 << port_num); 962a93192a5SAlexandre Bounine rio_route_add_entry(rdev, RIO_GLOBAL_TABLE, 963e0423236SZhang Wei RIO_ANY_DESTID(port->sys_size), 964818a04a0SAlexandre Bounine port_num, 0); 965eb188d0eSMatt Porter 96668fe4df5SAlexandre Bounine if (rio_enum_peer(net, port, hopcount + 1, 96768fe4df5SAlexandre Bounine rdev, port_num) < 0) 968eb188d0eSMatt Porter return -1; 969eb188d0eSMatt Porter 970eb188d0eSMatt Porter /* Update routing tables */ 971de74e00aSAlexandre Bounine destid = rio_destid_next(net, cur_destid + 1); 972de74e00aSAlexandre Bounine if (destid != RIO_INVALID_DESTID) { 973eb188d0eSMatt Porter for (destid = cur_destid; 974de74e00aSAlexandre Bounine destid < next_destid;) { 975de74e00aSAlexandre Bounine if (destid != port->host_deviceid) { 976a93192a5SAlexandre Bounine rio_route_add_entry(rdev, 977eb188d0eSMatt Porter RIO_GLOBAL_TABLE, 978eb188d0eSMatt Porter destid, 979818a04a0SAlexandre Bounine port_num, 980818a04a0SAlexandre Bounine 0); 981eb188d0eSMatt Porter rdev->rswitch-> 982eb188d0eSMatt Porter route_table[destid] = 983eb188d0eSMatt Porter port_num; 984eb188d0eSMatt Porter } 985de74e00aSAlexandre Bounine destid = rio_destid_next(net, 986de74e00aSAlexandre Bounine destid + 1); 987de74e00aSAlexandre Bounine } 988eb188d0eSMatt Porter } 989e5cabeb3SAlexandre Bounine } else { 990e5cabeb3SAlexandre Bounine /* If switch supports Error Management, 991e5cabeb3SAlexandre Bounine * set PORT_LOCKOUT bit for unused port 992e5cabeb3SAlexandre Bounine */ 993e5cabeb3SAlexandre Bounine if (rdev->em_efptr) 994e5cabeb3SAlexandre Bounine rio_set_port_lockout(rdev, port_num, 1); 995e5cabeb3SAlexandre Bounine 996e5cabeb3SAlexandre Bounine rdev->rswitch->port_ok &= ~(1 << port_num); 997eb188d0eSMatt Porter } 998eb188d0eSMatt Porter } 999c70555b0SAlexandre Bounine 1000e5cabeb3SAlexandre Bounine /* Direct Port-write messages to the enumeratiing host */ 1001e5cabeb3SAlexandre Bounine if ((rdev->src_ops & RIO_SRC_OPS_PORT_WRITE) && 1002e5cabeb3SAlexandre Bounine (rdev->em_efptr)) { 1003e5cabeb3SAlexandre Bounine rio_write_config_32(rdev, 1004e5cabeb3SAlexandre Bounine rdev->em_efptr + RIO_EM_PW_TGT_DEVID, 1005e5cabeb3SAlexandre Bounine (port->host_deviceid << 16) | 1006e5cabeb3SAlexandre Bounine (port->sys_size << 15)); 1007e5cabeb3SAlexandre Bounine } 1008e5cabeb3SAlexandre Bounine 1009e5cabeb3SAlexandre Bounine rio_init_em(rdev); 1010e5cabeb3SAlexandre Bounine 1011c70555b0SAlexandre Bounine /* Check for empty switch */ 1012de74e00aSAlexandre Bounine if (next_destid == sw_destid) 1013de74e00aSAlexandre Bounine next_destid = rio_destid_alloc(net); 1014c70555b0SAlexandre Bounine 1015a93192a5SAlexandre Bounine rdev->destid = sw_destid; 1016eb188d0eSMatt Porter } else 1017eb188d0eSMatt Porter pr_debug("RIO: found %s (vid %4.4x did %4.4x)\n", 1018eb188d0eSMatt Porter rio_name(rdev), rdev->vid, rdev->did); 1019eb188d0eSMatt Porter 1020eb188d0eSMatt Porter return 0; 1021eb188d0eSMatt Porter } 1022eb188d0eSMatt Porter 1023eb188d0eSMatt Porter /** 1024eb188d0eSMatt Porter * rio_enum_complete- Tests if enumeration of a network is complete 1025eb188d0eSMatt Porter * @port: Master port to send transaction 1026eb188d0eSMatt Porter * 1027a571259fSLiu Gang * Tests the PGCCSR discovered bit for non-zero value (enumeration 1028e5cabeb3SAlexandre Bounine * complete flag). Return %1 if enumeration is complete or %0 if 1029eb188d0eSMatt Porter * enumeration is incomplete. 1030eb188d0eSMatt Porter */ 1031eb188d0eSMatt Porter static int rio_enum_complete(struct rio_mport *port) 1032eb188d0eSMatt Porter { 1033af84ca38SAlexandre Bounine u32 regval; 1034eb188d0eSMatt Porter 1035af84ca38SAlexandre Bounine rio_local_read_config_32(port, port->phys_efptr + RIO_PORT_GEN_CTL_CSR, 1036af84ca38SAlexandre Bounine ®val); 1037a571259fSLiu Gang return (regval & RIO_PORT_GEN_DISCOVERED) ? 1 : 0; 1038eb188d0eSMatt Porter } 1039eb188d0eSMatt Porter 1040eb188d0eSMatt Porter /** 1041eb188d0eSMatt Porter * rio_disc_peer- Recursively discovers a RIO network through a master port 1042eb188d0eSMatt Porter * @net: RIO network being discovered 1043eb188d0eSMatt Porter * @port: Master port to send transactions 1044eb188d0eSMatt Porter * @destid: Current destination ID in network 1045eb188d0eSMatt Porter * @hopcount: Number of hops into the network 10469b310accSRandy Dunlap * @prev: previous rio_dev 10479b310accSRandy Dunlap * @prev_port: previous port number 1048eb188d0eSMatt Porter * 1049eb188d0eSMatt Porter * Recursively discovers a RIO network. Transactions are sent via the 1050eb188d0eSMatt Porter * master port passed in @port. 1051eb188d0eSMatt Porter */ 1052181a6ff0SLi Yang static int __devinit 1053eb188d0eSMatt Porter rio_disc_peer(struct rio_net *net, struct rio_mport *port, u16 destid, 105417e96205SAlexandre Bounine u8 hopcount, struct rio_dev *prev, int prev_port) 1055eb188d0eSMatt Porter { 1056eb188d0eSMatt Porter u8 port_num, route_port; 1057eb188d0eSMatt Porter struct rio_dev *rdev; 1058eb188d0eSMatt Porter u16 ndestid; 1059eb188d0eSMatt Porter 1060eb188d0eSMatt Porter /* Setup new RIO device */ 1061eb188d0eSMatt Porter if ((rdev = rio_setup_device(net, port, destid, hopcount, 0))) { 1062eb188d0eSMatt Porter /* Add device to the global and bus/net specific list. */ 1063eb188d0eSMatt Porter list_add_tail(&rdev->net_list, &net->devices); 106417e96205SAlexandre Bounine rdev->prev = prev; 106517e96205SAlexandre Bounine if (prev && rio_is_switch(prev)) 106617e96205SAlexandre Bounine prev->rswitch->nextdev[prev_port] = rdev; 1067eb188d0eSMatt Porter } else 1068eb188d0eSMatt Porter return -1; 1069eb188d0eSMatt Porter 1070eb188d0eSMatt Porter if (rio_is_switch(rdev)) { 1071eb188d0eSMatt Porter /* Associated destid is how we accessed this switch */ 1072a93192a5SAlexandre Bounine rdev->destid = destid; 1073eb188d0eSMatt Porter 1074eb188d0eSMatt Porter pr_debug( 1075eb188d0eSMatt Porter "RIO: found %s (vid %4.4x did %4.4x) with %d ports\n", 107668fe4df5SAlexandre Bounine rio_name(rdev), rdev->vid, rdev->did, 107768fe4df5SAlexandre Bounine RIO_GET_TOTAL_PORTS(rdev->swpinfo)); 107868fe4df5SAlexandre Bounine for (port_num = 0; 107968fe4df5SAlexandre Bounine port_num < RIO_GET_TOTAL_PORTS(rdev->swpinfo); 108068fe4df5SAlexandre Bounine port_num++) { 1081ae05cbd5SAlexandre Bounine if (RIO_GET_PORT_NUM(rdev->swpinfo) == port_num) 1082eb188d0eSMatt Porter continue; 1083eb188d0eSMatt Porter 1084eb188d0eSMatt Porter if (rio_sport_is_active 1085eb188d0eSMatt Porter (port, destid, hopcount, port_num)) { 1086eb188d0eSMatt Porter pr_debug( 1087eb188d0eSMatt Porter "RIO: scanning device on port %d\n", 1088eb188d0eSMatt Porter port_num); 1089818a04a0SAlexandre Bounine 1090818a04a0SAlexandre Bounine rio_lock_device(port, destid, hopcount, 1000); 1091818a04a0SAlexandre Bounine 1092e0423236SZhang Wei for (ndestid = 0; 1093e0423236SZhang Wei ndestid < RIO_ANY_DESTID(port->sys_size); 1094eb188d0eSMatt Porter ndestid++) { 1095a93192a5SAlexandre Bounine rio_route_get_entry(rdev, 1096eb188d0eSMatt Porter RIO_GLOBAL_TABLE, 1097eb188d0eSMatt Porter ndestid, 1098818a04a0SAlexandre Bounine &route_port, 0); 1099eb188d0eSMatt Porter if (route_port == port_num) 1100eb188d0eSMatt Porter break; 1101eb188d0eSMatt Porter } 1102eb188d0eSMatt Porter 1103af84ca38SAlexandre Bounine if (ndestid == RIO_ANY_DESTID(port->sys_size)) 1104af84ca38SAlexandre Bounine continue; 1105818a04a0SAlexandre Bounine rio_unlock_device(port, destid, hopcount); 110617e96205SAlexandre Bounine if (rio_disc_peer(net, port, ndestid, 110717e96205SAlexandre Bounine hopcount + 1, rdev, port_num) < 0) 1108eb188d0eSMatt Porter return -1; 1109eb188d0eSMatt Porter } 1110eb188d0eSMatt Porter } 1111eb188d0eSMatt Porter } else 1112eb188d0eSMatt Porter pr_debug("RIO: found %s (vid %4.4x did %4.4x)\n", 1113eb188d0eSMatt Porter rio_name(rdev), rdev->vid, rdev->did); 1114eb188d0eSMatt Porter 1115eb188d0eSMatt Porter return 0; 1116eb188d0eSMatt Porter } 1117eb188d0eSMatt Porter 1118eb188d0eSMatt Porter /** 1119eb188d0eSMatt Porter * rio_mport_is_active- Tests if master port link is active 1120eb188d0eSMatt Porter * @port: Master port to test 1121eb188d0eSMatt Porter * 1122eb188d0eSMatt Porter * Reads the port error status CSR for the master port to 1123eb188d0eSMatt Porter * determine if the port has an active link. Returns 1124e5cabeb3SAlexandre Bounine * %RIO_PORT_N_ERR_STS_PORT_OK if the master port is active 1125eb188d0eSMatt Porter * or %0 if it is inactive. 1126eb188d0eSMatt Porter */ 1127eb188d0eSMatt Porter static int rio_mport_is_active(struct rio_mport *port) 1128eb188d0eSMatt Porter { 1129eb188d0eSMatt Porter u32 result = 0; 1130eb188d0eSMatt Porter u32 ext_ftr_ptr; 1131eb188d0eSMatt Porter int *entry = rio_mport_phys_table; 1132eb188d0eSMatt Porter 1133eb188d0eSMatt Porter do { 1134eb188d0eSMatt Porter if ((ext_ftr_ptr = 1135eb188d0eSMatt Porter rio_mport_get_feature(port, 1, 0, 0, *entry))) 1136eb188d0eSMatt Porter break; 1137eb188d0eSMatt Porter } while (*++entry >= 0); 1138eb188d0eSMatt Porter 1139eb188d0eSMatt Porter if (ext_ftr_ptr) 1140eb188d0eSMatt Porter rio_local_read_config_32(port, 1141eb188d0eSMatt Porter ext_ftr_ptr + 1142eb188d0eSMatt Porter RIO_PORT_N_ERR_STS_CSR(port->index), 1143eb188d0eSMatt Porter &result); 1144eb188d0eSMatt Porter 1145e5cabeb3SAlexandre Bounine return result & RIO_PORT_N_ERR_STS_PORT_OK; 1146eb188d0eSMatt Porter } 1147eb188d0eSMatt Porter 1148eb188d0eSMatt Porter /** 1149eb188d0eSMatt Porter * rio_alloc_net- Allocate and configure a new RIO network 1150eb188d0eSMatt Porter * @port: Master port associated with the RIO network 1151de74e00aSAlexandre Bounine * @do_enum: Enumeration/Discovery mode flag 1152de74e00aSAlexandre Bounine * @start: logical minimal start id for new net 1153eb188d0eSMatt Porter * 1154eb188d0eSMatt Porter * Allocates a RIO network structure, initializes per-network 1155eb188d0eSMatt Porter * list heads, and adds the associated master port to the 1156eb188d0eSMatt Porter * network list of associated master ports. Returns a 1157eb188d0eSMatt Porter * RIO network pointer on success or %NULL on failure. 1158eb188d0eSMatt Porter */ 1159de74e00aSAlexandre Bounine static struct rio_net __devinit *rio_alloc_net(struct rio_mport *port, 1160de74e00aSAlexandre Bounine int do_enum, u16 start) 1161eb188d0eSMatt Porter { 1162eb188d0eSMatt Porter struct rio_net *net; 1163eb188d0eSMatt Porter 1164dd00cc48SYoann Padioleau net = kzalloc(sizeof(struct rio_net), GFP_KERNEL); 1165de74e00aSAlexandre Bounine if (net && do_enum) { 1166de74e00aSAlexandre Bounine net->destid_table.table = kzalloc( 1167de74e00aSAlexandre Bounine BITS_TO_LONGS(RIO_MAX_ROUTE_ENTRIES(port->sys_size)) * 1168de74e00aSAlexandre Bounine sizeof(long), 1169de74e00aSAlexandre Bounine GFP_KERNEL); 1170de74e00aSAlexandre Bounine 1171de74e00aSAlexandre Bounine if (net->destid_table.table == NULL) { 1172de74e00aSAlexandre Bounine pr_err("RIO: failed to allocate destID table\n"); 1173de74e00aSAlexandre Bounine kfree(net); 1174de74e00aSAlexandre Bounine net = NULL; 1175de74e00aSAlexandre Bounine } else { 1176de74e00aSAlexandre Bounine net->destid_table.start = start; 1177de74e00aSAlexandre Bounine net->destid_table.next = 0; 1178de74e00aSAlexandre Bounine net->destid_table.max = 1179de74e00aSAlexandre Bounine RIO_MAX_ROUTE_ENTRIES(port->sys_size); 1180de74e00aSAlexandre Bounine spin_lock_init(&net->destid_table.lock); 1181de74e00aSAlexandre Bounine } 1182de74e00aSAlexandre Bounine } 1183de74e00aSAlexandre Bounine 1184eb188d0eSMatt Porter if (net) { 1185eb188d0eSMatt Porter INIT_LIST_HEAD(&net->node); 1186eb188d0eSMatt Porter INIT_LIST_HEAD(&net->devices); 1187a7071efcSAlexandre Bounine INIT_LIST_HEAD(&net->switches); 1188eb188d0eSMatt Porter INIT_LIST_HEAD(&net->mports); 1189eb188d0eSMatt Porter list_add_tail(&port->nnode, &net->mports); 1190eb188d0eSMatt Porter net->hport = port; 1191005842efSAlexandre Bounine net->id = port->id; 1192eb188d0eSMatt Porter } 1193eb188d0eSMatt Porter return net; 1194eb188d0eSMatt Porter } 1195eb188d0eSMatt Porter 1196eb188d0eSMatt Porter /** 1197c70555b0SAlexandre Bounine * rio_update_route_tables- Updates route tables in switches 1198a7071efcSAlexandre Bounine * @net: RIO network to run update on 1199c70555b0SAlexandre Bounine * 1200c70555b0SAlexandre Bounine * For each enumerated device, ensure that each switch in a system 1201c70555b0SAlexandre Bounine * has correct routing entries. Add routes for devices that where 1202c70555b0SAlexandre Bounine * unknown dirung the first enumeration pass through the switch. 1203c70555b0SAlexandre Bounine */ 1204a7071efcSAlexandre Bounine static void rio_update_route_tables(struct rio_net *net) 1205c70555b0SAlexandre Bounine { 1206ded05782SAlexandre Bounine struct rio_dev *rdev, *swrdev; 1207c70555b0SAlexandre Bounine struct rio_switch *rswitch; 1208c70555b0SAlexandre Bounine u8 sport; 1209c70555b0SAlexandre Bounine u16 destid; 1210c70555b0SAlexandre Bounine 1211a7071efcSAlexandre Bounine list_for_each_entry(rdev, &net->devices, net_list) { 1212c70555b0SAlexandre Bounine 1213a93192a5SAlexandre Bounine destid = rdev->destid; 1214c70555b0SAlexandre Bounine 1215a7071efcSAlexandre Bounine list_for_each_entry(rswitch, &net->switches, node) { 1216c70555b0SAlexandre Bounine 1217c70555b0SAlexandre Bounine if (rio_is_switch(rdev) && (rdev->rswitch == rswitch)) 1218c70555b0SAlexandre Bounine continue; 1219c70555b0SAlexandre Bounine 1220c70555b0SAlexandre Bounine if (RIO_INVALID_ROUTE == rswitch->route_table[destid]) { 1221ded05782SAlexandre Bounine swrdev = sw_to_rio_dev(rswitch); 1222ded05782SAlexandre Bounine 122307590ff0SAlexandre Bounine /* Skip if destid ends in empty switch*/ 1224ded05782SAlexandre Bounine if (swrdev->destid == destid) 122507590ff0SAlexandre Bounine continue; 1226c70555b0SAlexandre Bounine 1227ded05782SAlexandre Bounine sport = RIO_GET_PORT_NUM(swrdev->swpinfo); 1228c70555b0SAlexandre Bounine 1229c70555b0SAlexandre Bounine if (rswitch->add_entry) { 1230ded05782SAlexandre Bounine rio_route_add_entry(swrdev, 1231818a04a0SAlexandre Bounine RIO_GLOBAL_TABLE, destid, 1232818a04a0SAlexandre Bounine sport, 0); 1233c70555b0SAlexandre Bounine rswitch->route_table[destid] = sport; 1234c70555b0SAlexandre Bounine } 1235c70555b0SAlexandre Bounine } 1236c70555b0SAlexandre Bounine } 1237c70555b0SAlexandre Bounine } 1238c70555b0SAlexandre Bounine } 1239c70555b0SAlexandre Bounine 1240c70555b0SAlexandre Bounine /** 1241e5cabeb3SAlexandre Bounine * rio_init_em - Initializes RIO Error Management (for switches) 124297ef6f74SRandy Dunlap * @rdev: RIO device 1243e5cabeb3SAlexandre Bounine * 1244e5cabeb3SAlexandre Bounine * For each enumerated switch, call device-specific error management 1245e5cabeb3SAlexandre Bounine * initialization routine (if supplied by the switch driver). 1246e5cabeb3SAlexandre Bounine */ 1247e5cabeb3SAlexandre Bounine static void rio_init_em(struct rio_dev *rdev) 1248e5cabeb3SAlexandre Bounine { 1249e5cabeb3SAlexandre Bounine if (rio_is_switch(rdev) && (rdev->em_efptr) && 1250e5cabeb3SAlexandre Bounine (rdev->rswitch->em_init)) { 1251e5cabeb3SAlexandre Bounine rdev->rswitch->em_init(rdev); 1252e5cabeb3SAlexandre Bounine } 1253e5cabeb3SAlexandre Bounine } 1254e5cabeb3SAlexandre Bounine 1255e5cabeb3SAlexandre Bounine /** 1256e5cabeb3SAlexandre Bounine * rio_pw_enable - Enables/disables port-write handling by a master port 1257e5cabeb3SAlexandre Bounine * @port: Master port associated with port-write handling 1258e5cabeb3SAlexandre Bounine * @enable: 1=enable, 0=disable 1259e5cabeb3SAlexandre Bounine */ 1260e5cabeb3SAlexandre Bounine static void rio_pw_enable(struct rio_mport *port, int enable) 1261e5cabeb3SAlexandre Bounine { 1262e5cabeb3SAlexandre Bounine if (port->ops->pwenable) 1263e5cabeb3SAlexandre Bounine port->ops->pwenable(port, enable); 1264e5cabeb3SAlexandre Bounine } 1265e5cabeb3SAlexandre Bounine 1266e5cabeb3SAlexandre Bounine /** 1267eb188d0eSMatt Porter * rio_enum_mport- Start enumeration through a master port 1268eb188d0eSMatt Porter * @mport: Master port to send transactions 1269eb188d0eSMatt Porter * 1270eb188d0eSMatt Porter * Starts the enumeration process. If somebody has enumerated our 1271eb188d0eSMatt Porter * master port device, then give up. If not and we have an active 1272eb188d0eSMatt Porter * link, then start recursive peer enumeration. Returns %0 if 1273eb188d0eSMatt Porter * enumeration succeeds or %-EBUSY if enumeration fails. 1274eb188d0eSMatt Porter */ 127537d33d15SAl Viro int __devinit rio_enum_mport(struct rio_mport *mport) 1276eb188d0eSMatt Porter { 1277eb188d0eSMatt Porter struct rio_net *net = NULL; 1278eb188d0eSMatt Porter int rc = 0; 1279eb188d0eSMatt Porter 1280eb188d0eSMatt Porter printk(KERN_INFO "RIO: enumerate master port %d, %s\n", mport->id, 1281eb188d0eSMatt Porter mport->name); 1282eb188d0eSMatt Porter /* If somebody else enumerated our master port device, bail. */ 1283eb188d0eSMatt Porter if (rio_enum_host(mport) < 0) { 1284eb188d0eSMatt Porter printk(KERN_INFO 1285eb188d0eSMatt Porter "RIO: master port %d device has been enumerated by a remote host\n", 1286eb188d0eSMatt Porter mport->id); 1287eb188d0eSMatt Porter rc = -EBUSY; 1288eb188d0eSMatt Porter goto out; 1289eb188d0eSMatt Porter } 1290eb188d0eSMatt Porter 1291eb188d0eSMatt Porter /* If master port has an active link, allocate net and enum peers */ 1292eb188d0eSMatt Porter if (rio_mport_is_active(mport)) { 1293de74e00aSAlexandre Bounine net = rio_alloc_net(mport, 1, 0); 1294de74e00aSAlexandre Bounine if (!net) { 1295eb188d0eSMatt Porter printk(KERN_ERR "RIO: failed to allocate new net\n"); 1296eb188d0eSMatt Porter rc = -ENOMEM; 1297eb188d0eSMatt Porter goto out; 1298eb188d0eSMatt Porter } 1299933af4a6SThomas Moll 1300de74e00aSAlexandre Bounine /* reserve mport destID in new net */ 1301de74e00aSAlexandre Bounine rio_destid_reserve(net, mport->host_deviceid); 1302de74e00aSAlexandre Bounine 1303933af4a6SThomas Moll /* Enable Input Output Port (transmitter reviever) */ 1304933af4a6SThomas Moll rio_enable_rx_tx_port(mport, 1, 0, 0, 0); 1305933af4a6SThomas Moll 1306af84ca38SAlexandre Bounine /* Set component tag for host */ 1307af84ca38SAlexandre Bounine rio_local_write_config_32(mport, RIO_COMPONENT_TAG_CSR, 1308af84ca38SAlexandre Bounine next_comptag++); 1309af84ca38SAlexandre Bounine 1310de74e00aSAlexandre Bounine next_destid = rio_destid_alloc(net); 1311de74e00aSAlexandre Bounine 131268fe4df5SAlexandre Bounine if (rio_enum_peer(net, mport, 0, NULL, 0) < 0) { 1313eb188d0eSMatt Porter /* A higher priority host won enumeration, bail. */ 1314eb188d0eSMatt Porter printk(KERN_INFO 1315eb188d0eSMatt Porter "RIO: master port %d device has lost enumeration to a remote host\n", 1316eb188d0eSMatt Porter mport->id); 1317a7071efcSAlexandre Bounine rio_clear_locks(net); 1318eb188d0eSMatt Porter rc = -EBUSY; 1319eb188d0eSMatt Porter goto out; 1320eb188d0eSMatt Porter } 1321de74e00aSAlexandre Bounine /* free the last allocated destID (unused) */ 1322de74e00aSAlexandre Bounine rio_destid_free(net, next_destid); 1323a7071efcSAlexandre Bounine rio_update_route_tables(net); 1324a7071efcSAlexandre Bounine rio_clear_locks(net); 1325e5cabeb3SAlexandre Bounine rio_pw_enable(mport, 1); 1326eb188d0eSMatt Porter } else { 1327eb188d0eSMatt Porter printk(KERN_INFO "RIO: master port %d link inactive\n", 1328eb188d0eSMatt Porter mport->id); 1329eb188d0eSMatt Porter rc = -EINVAL; 1330eb188d0eSMatt Porter } 1331eb188d0eSMatt Porter 1332eb188d0eSMatt Porter out: 1333eb188d0eSMatt Porter return rc; 1334eb188d0eSMatt Porter } 1335eb188d0eSMatt Porter 1336eb188d0eSMatt Porter /** 1337eb188d0eSMatt Porter * rio_build_route_tables- Generate route tables from switch route entries 1338a7071efcSAlexandre Bounine * @net: RIO network to run route tables scan on 1339eb188d0eSMatt Porter * 1340eb188d0eSMatt Porter * For each switch device, generate a route table by copying existing 1341eb188d0eSMatt Porter * route entries from the switch. 1342eb188d0eSMatt Porter */ 1343a7071efcSAlexandre Bounine static void rio_build_route_tables(struct rio_net *net) 1344eb188d0eSMatt Porter { 1345a7071efcSAlexandre Bounine struct rio_switch *rswitch; 1346eb188d0eSMatt Porter struct rio_dev *rdev; 1347eb188d0eSMatt Porter int i; 1348eb188d0eSMatt Porter u8 sport; 1349eb188d0eSMatt Porter 1350a7071efcSAlexandre Bounine list_for_each_entry(rswitch, &net->switches, node) { 1351a7071efcSAlexandre Bounine rdev = sw_to_rio_dev(rswitch); 1352a7071efcSAlexandre Bounine 1353a7071efcSAlexandre Bounine rio_lock_device(net->hport, rdev->destid, 1354a93192a5SAlexandre Bounine rdev->hopcount, 1000); 1355e0423236SZhang Wei for (i = 0; 1356a7071efcSAlexandre Bounine i < RIO_MAX_ROUTE_ENTRIES(net->hport->sys_size); 1357e0423236SZhang Wei i++) { 1358a7071efcSAlexandre Bounine if (rio_route_get_entry(rdev, RIO_GLOBAL_TABLE, 1359a7071efcSAlexandre Bounine i, &sport, 0) < 0) 1360eb188d0eSMatt Porter continue; 1361a7071efcSAlexandre Bounine rswitch->route_table[i] = sport; 1362eb188d0eSMatt Porter } 1363818a04a0SAlexandre Bounine 1364a7071efcSAlexandre Bounine rio_unlock_device(net->hport, rdev->destid, rdev->hopcount); 1365818a04a0SAlexandre Bounine } 1366eb188d0eSMatt Porter } 1367eb188d0eSMatt Porter 1368eb188d0eSMatt Porter /** 1369eb188d0eSMatt Porter * rio_disc_mport- Start discovery through a master port 1370eb188d0eSMatt Porter * @mport: Master port to send transactions 1371eb188d0eSMatt Porter * 1372eb188d0eSMatt Porter * Starts the discovery process. If we have an active link, 1373eb188d0eSMatt Porter * then wait for the signal that enumeration is complete. 1374eb188d0eSMatt Porter * When enumeration completion is signaled, start recursive 1375eb188d0eSMatt Porter * peer discovery. Returns %0 if discovery succeeds or %-EBUSY 1376eb188d0eSMatt Porter * on failure. 1377eb188d0eSMatt Porter */ 137837d33d15SAl Viro int __devinit rio_disc_mport(struct rio_mport *mport) 1379eb188d0eSMatt Porter { 1380eb188d0eSMatt Porter struct rio_net *net = NULL; 1381fa3dbaa0SAlexandre Bounine unsigned long to_end; 1382eb188d0eSMatt Porter 1383eb188d0eSMatt Porter printk(KERN_INFO "RIO: discover master port %d, %s\n", mport->id, 1384eb188d0eSMatt Porter mport->name); 1385eb188d0eSMatt Porter 1386eb188d0eSMatt Porter /* If master port has an active link, allocate net and discover peers */ 1387eb188d0eSMatt Porter if (rio_mport_is_active(mport)) { 1388fa3dbaa0SAlexandre Bounine pr_debug("RIO: wait for enumeration to complete...\n"); 1389fa3dbaa0SAlexandre Bounine 1390fa3dbaa0SAlexandre Bounine to_end = jiffies + CONFIG_RAPIDIO_DISC_TIMEOUT * HZ; 1391fa3dbaa0SAlexandre Bounine while (time_before(jiffies, to_end)) { 1392fa3dbaa0SAlexandre Bounine if (rio_enum_complete(mport)) 1393fa3dbaa0SAlexandre Bounine goto enum_done; 1394f4c9c0e8SAlexandre Bounine msleep(10); 1395fa3dbaa0SAlexandre Bounine } 1396fa3dbaa0SAlexandre Bounine 1397fa3dbaa0SAlexandre Bounine pr_debug("RIO: discovery timeout on mport %d %s\n", 1398fa3dbaa0SAlexandre Bounine mport->id, mport->name); 1399fa3dbaa0SAlexandre Bounine goto bail; 1400fa3dbaa0SAlexandre Bounine enum_done: 1401fa3dbaa0SAlexandre Bounine pr_debug("RIO: ... enumeration done\n"); 1402fa3dbaa0SAlexandre Bounine 1403de74e00aSAlexandre Bounine net = rio_alloc_net(mport, 0, 0); 1404fa3dbaa0SAlexandre Bounine if (!net) { 1405eb188d0eSMatt Porter printk(KERN_ERR "RIO: Failed to allocate new net\n"); 1406eb188d0eSMatt Porter goto bail; 1407eb188d0eSMatt Porter } 1408eb188d0eSMatt Porter 1409818a04a0SAlexandre Bounine /* Read DestID assigned by enumerator */ 1410818a04a0SAlexandre Bounine rio_local_read_config_32(mport, RIO_DID_CSR, 1411818a04a0SAlexandre Bounine &mport->host_deviceid); 1412818a04a0SAlexandre Bounine mport->host_deviceid = RIO_GET_DID(mport->sys_size, 1413818a04a0SAlexandre Bounine mport->host_deviceid); 1414818a04a0SAlexandre Bounine 1415e0423236SZhang Wei if (rio_disc_peer(net, mport, RIO_ANY_DESTID(mport->sys_size), 141617e96205SAlexandre Bounine 0, NULL, 0) < 0) { 1417eb188d0eSMatt Porter printk(KERN_INFO 1418eb188d0eSMatt Porter "RIO: master port %d device has failed discovery\n", 1419eb188d0eSMatt Porter mport->id); 1420eb188d0eSMatt Porter goto bail; 1421eb188d0eSMatt Porter } 1422eb188d0eSMatt Porter 1423a7071efcSAlexandre Bounine rio_build_route_tables(net); 1424eb188d0eSMatt Porter } 1425eb188d0eSMatt Porter 1426eb188d0eSMatt Porter return 0; 1427eb188d0eSMatt Porter bail: 1428eb188d0eSMatt Porter return -EBUSY; 1429eb188d0eSMatt Porter } 1430