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 40e5cabeb3SAlexandre Bounine static void rio_init_em(struct rio_dev *rdev); 41e5cabeb3SAlexandre Bounine 42e6b585caSAlexandre Bounine struct rio_id_table { 43e6b585caSAlexandre Bounine u16 start; /* logical minimal id */ 44e6b585caSAlexandre Bounine u32 max; /* max number of IDs in table */ 45e6b585caSAlexandre Bounine spinlock_t lock; 46e6b585caSAlexandre Bounine unsigned long table[0]; 47e6b585caSAlexandre Bounine }; 48e6b585caSAlexandre Bounine 49eb188d0eSMatt Porter static int next_destid = 0; 50af84ca38SAlexandre Bounine static int next_comptag = 1; 51eb188d0eSMatt Porter 524ed134beSAlexandre Bounine /** 53de74e00aSAlexandre Bounine * rio_destid_alloc - Allocate next available destID for given network 544ed134beSAlexandre Bounine * @net: RIO network 55de74e00aSAlexandre Bounine * 56de74e00aSAlexandre Bounine * Returns next available device destination ID for the specified RIO network. 57de74e00aSAlexandre Bounine * Marks allocated ID as one in use. 58de74e00aSAlexandre Bounine * Returns RIO_INVALID_DESTID if new destID is not available. 59de74e00aSAlexandre Bounine */ 60de74e00aSAlexandre Bounine static u16 rio_destid_alloc(struct rio_net *net) 61de74e00aSAlexandre Bounine { 62de74e00aSAlexandre Bounine int destid; 63e6b585caSAlexandre Bounine struct rio_id_table *idtab = (struct rio_id_table *)net->enum_data; 64de74e00aSAlexandre Bounine 65de74e00aSAlexandre Bounine spin_lock(&idtab->lock); 66de74e00aSAlexandre Bounine destid = find_first_zero_bit(idtab->table, idtab->max); 67de74e00aSAlexandre Bounine 68de74e00aSAlexandre Bounine if (destid < idtab->max) { 69de74e00aSAlexandre Bounine set_bit(destid, idtab->table); 70de74e00aSAlexandre Bounine destid += idtab->start; 71de74e00aSAlexandre Bounine } else 72de74e00aSAlexandre Bounine destid = RIO_INVALID_DESTID; 73de74e00aSAlexandre Bounine 74de74e00aSAlexandre Bounine spin_unlock(&idtab->lock); 75de74e00aSAlexandre Bounine return (u16)destid; 76de74e00aSAlexandre Bounine } 77de74e00aSAlexandre Bounine 784ed134beSAlexandre Bounine /** 79b94bb1f6SVasyl Gomonovych * rio_destid_reserve - Reserve the specified destID 804ed134beSAlexandre Bounine * @net: RIO network 814ed134beSAlexandre Bounine * @destid: destID to reserve 82de74e00aSAlexandre Bounine * 83de74e00aSAlexandre Bounine * Tries to reserve the specified destID. 8476679286SMasanari Iida * Returns 0 if successful. 85de74e00aSAlexandre Bounine */ 86de74e00aSAlexandre Bounine static int rio_destid_reserve(struct rio_net *net, u16 destid) 87de74e00aSAlexandre Bounine { 88de74e00aSAlexandre Bounine int oldbit; 89e6b585caSAlexandre Bounine struct rio_id_table *idtab = (struct rio_id_table *)net->enum_data; 90de74e00aSAlexandre Bounine 91de74e00aSAlexandre Bounine destid -= idtab->start; 92de74e00aSAlexandre Bounine spin_lock(&idtab->lock); 93de74e00aSAlexandre Bounine oldbit = test_and_set_bit(destid, idtab->table); 94de74e00aSAlexandre Bounine spin_unlock(&idtab->lock); 95de74e00aSAlexandre Bounine return oldbit; 96de74e00aSAlexandre Bounine } 97de74e00aSAlexandre Bounine 984ed134beSAlexandre Bounine /** 99de74e00aSAlexandre Bounine * rio_destid_free - free a previously allocated destID 1004ed134beSAlexandre Bounine * @net: RIO network 1014ed134beSAlexandre Bounine * @destid: destID to free 102de74e00aSAlexandre Bounine * 103de74e00aSAlexandre Bounine * Makes the specified destID available for use. 104de74e00aSAlexandre Bounine */ 105de74e00aSAlexandre Bounine static void rio_destid_free(struct rio_net *net, u16 destid) 106de74e00aSAlexandre Bounine { 107e6b585caSAlexandre Bounine struct rio_id_table *idtab = (struct rio_id_table *)net->enum_data; 108de74e00aSAlexandre Bounine 109de74e00aSAlexandre Bounine destid -= idtab->start; 110de74e00aSAlexandre Bounine spin_lock(&idtab->lock); 111de74e00aSAlexandre Bounine clear_bit(destid, idtab->table); 112de74e00aSAlexandre Bounine spin_unlock(&idtab->lock); 113de74e00aSAlexandre Bounine } 114de74e00aSAlexandre Bounine 1154ed134beSAlexandre Bounine /** 116de74e00aSAlexandre Bounine * rio_destid_first - return first destID in use 1174ed134beSAlexandre Bounine * @net: RIO network 118de74e00aSAlexandre Bounine */ 119de74e00aSAlexandre Bounine static u16 rio_destid_first(struct rio_net *net) 120de74e00aSAlexandre Bounine { 121de74e00aSAlexandre Bounine int destid; 122e6b585caSAlexandre Bounine struct rio_id_table *idtab = (struct rio_id_table *)net->enum_data; 123de74e00aSAlexandre Bounine 124de74e00aSAlexandre Bounine spin_lock(&idtab->lock); 125de74e00aSAlexandre Bounine destid = find_first_bit(idtab->table, idtab->max); 126de74e00aSAlexandre Bounine if (destid >= idtab->max) 127de74e00aSAlexandre Bounine destid = RIO_INVALID_DESTID; 128de74e00aSAlexandre Bounine else 129de74e00aSAlexandre Bounine destid += idtab->start; 130de74e00aSAlexandre Bounine spin_unlock(&idtab->lock); 131de74e00aSAlexandre Bounine return (u16)destid; 132de74e00aSAlexandre Bounine } 133de74e00aSAlexandre Bounine 1344ed134beSAlexandre Bounine /** 135de74e00aSAlexandre Bounine * rio_destid_next - return next destID in use 1364ed134beSAlexandre Bounine * @net: RIO network 1374ed134beSAlexandre Bounine * @from: destination ID from which search shall continue 138de74e00aSAlexandre Bounine */ 139de74e00aSAlexandre Bounine static u16 rio_destid_next(struct rio_net *net, u16 from) 140de74e00aSAlexandre Bounine { 141de74e00aSAlexandre Bounine int destid; 142e6b585caSAlexandre Bounine struct rio_id_table *idtab = (struct rio_id_table *)net->enum_data; 143de74e00aSAlexandre Bounine 144de74e00aSAlexandre Bounine spin_lock(&idtab->lock); 145de74e00aSAlexandre Bounine destid = find_next_bit(idtab->table, idtab->max, from); 146de74e00aSAlexandre Bounine if (destid >= idtab->max) 147de74e00aSAlexandre Bounine destid = RIO_INVALID_DESTID; 148de74e00aSAlexandre Bounine else 149de74e00aSAlexandre Bounine destid += idtab->start; 150de74e00aSAlexandre Bounine spin_unlock(&idtab->lock); 151de74e00aSAlexandre Bounine return (u16)destid; 152de74e00aSAlexandre Bounine } 153de74e00aSAlexandre Bounine 154eb188d0eSMatt Porter /** 155eb188d0eSMatt Porter * rio_get_device_id - Get the base/extended device id for a device 156eb188d0eSMatt Porter * @port: RIO master port 157eb188d0eSMatt Porter * @destid: Destination ID of device 158eb188d0eSMatt Porter * @hopcount: Hopcount to device 159eb188d0eSMatt Porter * 160eb188d0eSMatt Porter * Reads the base/extended device id from a device. Returns the 161eb188d0eSMatt Porter * 8/16-bit device ID. 162eb188d0eSMatt Porter */ 163eb188d0eSMatt Porter static u16 rio_get_device_id(struct rio_mport *port, u16 destid, u8 hopcount) 164eb188d0eSMatt Porter { 165eb188d0eSMatt Porter u32 result; 166eb188d0eSMatt Porter 167eb188d0eSMatt Porter rio_mport_read_config_32(port, destid, hopcount, RIO_DID_CSR, &result); 168eb188d0eSMatt Porter 169e0423236SZhang Wei return RIO_GET_DID(port->sys_size, result); 170eb188d0eSMatt Porter } 171eb188d0eSMatt Porter 172eb188d0eSMatt Porter /** 173eb188d0eSMatt Porter * rio_set_device_id - Set the base/extended device id for a device 174eb188d0eSMatt Porter * @port: RIO master port 175eb188d0eSMatt Porter * @destid: Destination ID of device 176eb188d0eSMatt Porter * @hopcount: Hopcount to device 177eb188d0eSMatt Porter * @did: Device ID value to be written 178eb188d0eSMatt Porter * 179eb188d0eSMatt Porter * Writes the base/extended device id from a device. 180eb188d0eSMatt Porter */ 181fa78cc51SMatt Porter static void rio_set_device_id(struct rio_mport *port, u16 destid, u8 hopcount, u16 did) 182eb188d0eSMatt Porter { 183eb188d0eSMatt Porter rio_mport_write_config_32(port, destid, hopcount, RIO_DID_CSR, 184e0423236SZhang Wei RIO_SET_DID(port->sys_size, did)); 185eb188d0eSMatt Porter } 186eb188d0eSMatt Porter 187eb188d0eSMatt Porter /** 188eb188d0eSMatt Porter * rio_clear_locks- Release all host locks and signal enumeration complete 189a7071efcSAlexandre Bounine * @net: RIO network to run on 190eb188d0eSMatt Porter * 191eb188d0eSMatt Porter * Marks the component tag CSR on each device with the enumeration 192eb188d0eSMatt Porter * complete flag. When complete, it then release the host locks on 193eb188d0eSMatt Porter * each device. Returns 0 on success or %-EINVAL on failure. 194eb188d0eSMatt Porter */ 195a7071efcSAlexandre Bounine static int rio_clear_locks(struct rio_net *net) 196eb188d0eSMatt Porter { 197a7071efcSAlexandre Bounine struct rio_mport *port = net->hport; 198eb188d0eSMatt Porter struct rio_dev *rdev; 199eb188d0eSMatt Porter u32 result; 200eb188d0eSMatt Porter int ret = 0; 201eb188d0eSMatt Porter 202eb188d0eSMatt Porter /* Release host device id locks */ 203eb188d0eSMatt Porter rio_local_write_config_32(port, RIO_HOST_DID_LOCK_CSR, 204eb188d0eSMatt Porter port->host_deviceid); 205eb188d0eSMatt Porter rio_local_read_config_32(port, RIO_HOST_DID_LOCK_CSR, &result); 206eb188d0eSMatt Porter if ((result & 0xffff) != 0xffff) { 207eb188d0eSMatt Porter printk(KERN_INFO 208eb188d0eSMatt Porter "RIO: badness when releasing host lock on master port, result %8.8x\n", 209eb188d0eSMatt Porter result); 210eb188d0eSMatt Porter ret = -EINVAL; 211eb188d0eSMatt Porter } 212a7071efcSAlexandre Bounine list_for_each_entry(rdev, &net->devices, net_list) { 213eb188d0eSMatt Porter rio_write_config_32(rdev, RIO_HOST_DID_LOCK_CSR, 214eb188d0eSMatt Porter port->host_deviceid); 215eb188d0eSMatt Porter rio_read_config_32(rdev, RIO_HOST_DID_LOCK_CSR, &result); 216eb188d0eSMatt Porter if ((result & 0xffff) != 0xffff) { 217eb188d0eSMatt Porter printk(KERN_INFO 218eb188d0eSMatt Porter "RIO: badness when releasing host lock on vid %4.4x did %4.4x\n", 219eb188d0eSMatt Porter rdev->vid, rdev->did); 220eb188d0eSMatt Porter ret = -EINVAL; 221eb188d0eSMatt Porter } 222af84ca38SAlexandre Bounine 223af84ca38SAlexandre Bounine /* Mark device as discovered and enable master */ 224af84ca38SAlexandre Bounine rio_read_config_32(rdev, 225af84ca38SAlexandre Bounine rdev->phys_efptr + RIO_PORT_GEN_CTL_CSR, 226af84ca38SAlexandre Bounine &result); 227af84ca38SAlexandre Bounine result |= RIO_PORT_GEN_DISCOVERED | RIO_PORT_GEN_MASTER; 228af84ca38SAlexandre Bounine rio_write_config_32(rdev, 229af84ca38SAlexandre Bounine rdev->phys_efptr + RIO_PORT_GEN_CTL_CSR, 230af84ca38SAlexandre Bounine result); 231eb188d0eSMatt Porter } 232eb188d0eSMatt Porter 233eb188d0eSMatt Porter return ret; 234eb188d0eSMatt Porter } 235eb188d0eSMatt Porter 236eb188d0eSMatt Porter /** 237eb188d0eSMatt Porter * rio_enum_host- Set host lock and initialize host destination ID 238eb188d0eSMatt Porter * @port: Master port to issue transaction 239eb188d0eSMatt Porter * 240eb188d0eSMatt Porter * Sets the local host master port lock and destination ID register 241eb188d0eSMatt Porter * with the host device ID value. The host device ID value is provided 242eb188d0eSMatt Porter * by the platform. Returns %0 on success or %-1 on failure. 243eb188d0eSMatt Porter */ 244eb188d0eSMatt Porter static int rio_enum_host(struct rio_mport *port) 245eb188d0eSMatt Porter { 246eb188d0eSMatt Porter u32 result; 247eb188d0eSMatt Porter 248eb188d0eSMatt Porter /* Set master port host device id lock */ 249eb188d0eSMatt Porter rio_local_write_config_32(port, RIO_HOST_DID_LOCK_CSR, 250eb188d0eSMatt Porter port->host_deviceid); 251eb188d0eSMatt Porter 252eb188d0eSMatt Porter rio_local_read_config_32(port, RIO_HOST_DID_LOCK_CSR, &result); 253eb188d0eSMatt Porter if ((result & 0xffff) != port->host_deviceid) 254eb188d0eSMatt Porter return -1; 255eb188d0eSMatt Porter 256eb188d0eSMatt Porter /* Set master port destid and init destid ctr */ 257eb188d0eSMatt Porter rio_local_set_device_id(port, port->host_deviceid); 258eb188d0eSMatt Porter return 0; 259eb188d0eSMatt Porter } 260eb188d0eSMatt Porter 261eb188d0eSMatt Porter /** 262eb188d0eSMatt Porter * rio_device_has_destid- Test if a device contains a destination ID register 263eb188d0eSMatt Porter * @port: Master port to issue transaction 264eb188d0eSMatt Porter * @src_ops: RIO device source operations 265eb188d0eSMatt Porter * @dst_ops: RIO device destination operations 266eb188d0eSMatt Porter * 267eb188d0eSMatt Porter * Checks the provided @src_ops and @dst_ops for the necessary transaction 268eb188d0eSMatt Porter * capabilities that indicate whether or not a device will implement a 269eb188d0eSMatt Porter * destination ID register. Returns 1 if true or 0 if false. 270eb188d0eSMatt Porter */ 271eb188d0eSMatt Porter static int rio_device_has_destid(struct rio_mport *port, int src_ops, 272eb188d0eSMatt Porter int dst_ops) 273eb188d0eSMatt Porter { 274fa78cc51SMatt 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; 275fa78cc51SMatt Porter 276fa78cc51SMatt Porter return !!((src_ops | dst_ops) & mask); 277eb188d0eSMatt Porter } 278eb188d0eSMatt Porter 279eb188d0eSMatt Porter /** 280eb188d0eSMatt Porter * rio_release_dev- Frees a RIO device struct 281eb188d0eSMatt Porter * @dev: LDM device associated with a RIO device struct 282eb188d0eSMatt Porter * 283eb188d0eSMatt Porter * Gets the RIO device struct associated a RIO device struct. 284eb188d0eSMatt Porter * The RIO device struct is freed. 285eb188d0eSMatt Porter */ 286eb188d0eSMatt Porter static void rio_release_dev(struct device *dev) 287eb188d0eSMatt Porter { 288eb188d0eSMatt Porter struct rio_dev *rdev; 289eb188d0eSMatt Porter 290eb188d0eSMatt Porter rdev = to_rio_dev(dev); 291eb188d0eSMatt Porter kfree(rdev); 292eb188d0eSMatt Porter } 293eb188d0eSMatt Porter 294eb188d0eSMatt Porter /** 295eb188d0eSMatt Porter * rio_is_switch- Tests if a RIO device has switch capabilities 296eb188d0eSMatt Porter * @rdev: RIO device 297eb188d0eSMatt Porter * 298eb188d0eSMatt Porter * Gets the RIO device Processing Element Features register 299eb188d0eSMatt Porter * contents and tests for switch capabilities. Returns 1 if 300eb188d0eSMatt Porter * the device is a switch or 0 if it is not a switch. 301eb188d0eSMatt Porter * The RIO device struct is freed. 302eb188d0eSMatt Porter */ 303eb188d0eSMatt Porter static int rio_is_switch(struct rio_dev *rdev) 304eb188d0eSMatt Porter { 305eb188d0eSMatt Porter if (rdev->pef & RIO_PEF_SWITCH) 306eb188d0eSMatt Porter return 1; 307eb188d0eSMatt Porter return 0; 308eb188d0eSMatt Porter } 309eb188d0eSMatt Porter 310eb188d0eSMatt Porter /** 311eb188d0eSMatt Porter * rio_setup_device- Allocates and sets up a RIO device 312eb188d0eSMatt Porter * @net: RIO network 313eb188d0eSMatt Porter * @port: Master port to send transactions 314eb188d0eSMatt Porter * @destid: Current destination ID 315eb188d0eSMatt Porter * @hopcount: Current hopcount 316eb188d0eSMatt Porter * @do_enum: Enumeration/Discovery mode flag 317eb188d0eSMatt Porter * 318eb188d0eSMatt Porter * Allocates a RIO device and configures fields based on configuration 319eb188d0eSMatt Porter * space contents. If device has a destination ID register, a destination 320eb188d0eSMatt Porter * ID is either assigned in enumeration mode or read from configuration 321eb188d0eSMatt Porter * space in discovery mode. If the device has switch capabilities, then 322eb188d0eSMatt Porter * a switch is allocated and configured appropriately. Returns a pointer 323eb188d0eSMatt Porter * to a RIO device on success or NULL on failure. 324eb188d0eSMatt Porter * 325eb188d0eSMatt Porter */ 326305c891eSBill Pemberton static struct rio_dev *rio_setup_device(struct rio_net *net, 327eb188d0eSMatt Porter struct rio_mport *port, u16 destid, 328eb188d0eSMatt Porter u8 hopcount, int do_enum) 329eb188d0eSMatt Porter { 3305f28c520SYang Li int ret = 0; 331eb188d0eSMatt Porter struct rio_dev *rdev; 3325f28c520SYang Li struct rio_switch *rswitch = NULL; 333eb188d0eSMatt Porter int result, rdid; 334ded05782SAlexandre Bounine size_t size; 335ded05782SAlexandre Bounine u32 swpinfo = 0; 336eb188d0eSMatt Porter 337ded05782SAlexandre Bounine size = sizeof(struct rio_dev); 338ded05782SAlexandre Bounine if (rio_mport_read_config_32(port, destid, hopcount, 339ded05782SAlexandre Bounine RIO_PEF_CAR, &result)) 340ded05782SAlexandre Bounine return NULL; 341ded05782SAlexandre Bounine 342ded05782SAlexandre Bounine if (result & (RIO_PEF_SWITCH | RIO_PEF_MULTIPORT)) { 343ded05782SAlexandre Bounine rio_mport_read_config_32(port, destid, hopcount, 344ded05782SAlexandre Bounine RIO_SWP_INFO_CAR, &swpinfo); 345ded05782SAlexandre Bounine if (result & RIO_PEF_SWITCH) { 346ded05782SAlexandre Bounine size += (RIO_GET_TOTAL_PORTS(swpinfo) * 347ded05782SAlexandre Bounine sizeof(rswitch->nextdev[0])) + sizeof(*rswitch); 348ded05782SAlexandre Bounine } 349ded05782SAlexandre Bounine } 350ded05782SAlexandre Bounine 351ded05782SAlexandre Bounine rdev = kzalloc(size, GFP_KERNEL); 352eb188d0eSMatt Porter if (!rdev) 3535f28c520SYang Li return NULL; 354eb188d0eSMatt Porter 355eb188d0eSMatt Porter rdev->net = net; 356ded05782SAlexandre Bounine rdev->pef = result; 357ded05782SAlexandre Bounine rdev->swpinfo = swpinfo; 358eb188d0eSMatt Porter rio_mport_read_config_32(port, destid, hopcount, RIO_DEV_ID_CAR, 359eb188d0eSMatt Porter &result); 360eb188d0eSMatt Porter rdev->did = result >> 16; 361eb188d0eSMatt Porter rdev->vid = result & 0xffff; 362eb188d0eSMatt Porter rio_mport_read_config_32(port, destid, hopcount, RIO_DEV_INFO_CAR, 363eb188d0eSMatt Porter &rdev->device_rev); 364eb188d0eSMatt Porter rio_mport_read_config_32(port, destid, hopcount, RIO_ASM_ID_CAR, 365eb188d0eSMatt Porter &result); 366eb188d0eSMatt Porter rdev->asm_did = result >> 16; 367eb188d0eSMatt Porter rdev->asm_vid = result & 0xffff; 368eb188d0eSMatt Porter rio_mport_read_config_32(port, destid, hopcount, RIO_ASM_INFO_CAR, 369eb188d0eSMatt Porter &result); 370eb188d0eSMatt Porter rdev->asm_rev = result >> 16; 371e5cabeb3SAlexandre Bounine if (rdev->pef & RIO_PEF_EXT_FEATURES) { 372eb188d0eSMatt Porter rdev->efptr = result & 0xffff; 373e5cabeb3SAlexandre Bounine rdev->phys_efptr = rio_mport_get_physefb(port, 0, destid, 3741ae842deSAlexandre Bounine hopcount, &rdev->phys_rmap); 3751ae842deSAlexandre Bounine pr_debug("RIO: %s Register Map %d device\n", 3761ae842deSAlexandre Bounine __func__, rdev->phys_rmap); 377e5cabeb3SAlexandre Bounine 378e5cabeb3SAlexandre Bounine rdev->em_efptr = rio_mport_get_feature(port, 0, destid, 379e5cabeb3SAlexandre Bounine hopcount, RIO_EFB_ERR_MGMNT); 3801ae842deSAlexandre Bounine if (!rdev->em_efptr) 3811ae842deSAlexandre Bounine rdev->em_efptr = rio_mport_get_feature(port, 0, destid, 3821ae842deSAlexandre Bounine hopcount, RIO_EFB_ERR_MGMNT_HS); 383e5cabeb3SAlexandre Bounine } 384eb188d0eSMatt Porter 385eb188d0eSMatt Porter rio_mport_read_config_32(port, destid, hopcount, RIO_SRC_OPS_CAR, 386eb188d0eSMatt Porter &rdev->src_ops); 387eb188d0eSMatt Porter rio_mport_read_config_32(port, destid, hopcount, RIO_DST_OPS_CAR, 388eb188d0eSMatt Porter &rdev->dst_ops); 389eb188d0eSMatt Porter 390af84ca38SAlexandre Bounine if (do_enum) { 391af84ca38SAlexandre Bounine /* Assign component tag to device */ 392af84ca38SAlexandre Bounine if (next_comptag >= 0x10000) { 393af84ca38SAlexandre Bounine pr_err("RIO: Component Tag Counter Overflow\n"); 394af84ca38SAlexandre Bounine goto cleanup; 395af84ca38SAlexandre Bounine } 396af84ca38SAlexandre Bounine rio_mport_write_config_32(port, destid, hopcount, 397af84ca38SAlexandre Bounine RIO_COMPONENT_TAG_CSR, next_comptag); 398af84ca38SAlexandre Bounine rdev->comp_tag = next_comptag++; 3992ec3ba69SAlexandre Bounine rdev->do_enum = true; 400558bda65SAlexandre Bounine } else { 401558bda65SAlexandre Bounine rio_mport_read_config_32(port, destid, hopcount, 402558bda65SAlexandre Bounine RIO_COMPONENT_TAG_CSR, 403558bda65SAlexandre Bounine &rdev->comp_tag); 404af84ca38SAlexandre Bounine } 405af84ca38SAlexandre Bounine 406c70555b0SAlexandre Bounine if (rio_device_has_destid(port, rdev->src_ops, rdev->dst_ops)) { 407c70555b0SAlexandre Bounine if (do_enum) { 408eb188d0eSMatt Porter rio_set_device_id(port, destid, hopcount, next_destid); 409de74e00aSAlexandre Bounine rdev->destid = next_destid; 410de74e00aSAlexandre Bounine next_destid = rio_destid_alloc(net); 411eb188d0eSMatt Porter } else 412eb188d0eSMatt Porter rdev->destid = rio_get_device_id(port, destid, hopcount); 413a93192a5SAlexandre Bounine 414a93192a5SAlexandre Bounine rdev->hopcount = 0xff; 415a93192a5SAlexandre Bounine } else { 416a93192a5SAlexandre Bounine /* Switch device has an associated destID which 417a93192a5SAlexandre Bounine * will be adjusted later 418a93192a5SAlexandre Bounine */ 419a93192a5SAlexandre Bounine rdev->destid = destid; 420a93192a5SAlexandre Bounine rdev->hopcount = hopcount; 421a93192a5SAlexandre Bounine } 422eb188d0eSMatt Porter 423eb188d0eSMatt Porter /* If a PE has both switch and other functions, show it as a switch */ 424eb188d0eSMatt Porter if (rio_is_switch(rdev)) { 425ded05782SAlexandre Bounine rswitch = rdev->rswitch; 426e5cabeb3SAlexandre Bounine rswitch->port_ok = 0; 4272ec3ba69SAlexandre Bounine spin_lock_init(&rswitch->lock); 428e0423236SZhang Wei rswitch->route_table = kzalloc(sizeof(u8)* 429e0423236SZhang Wei RIO_MAX_ROUTE_ENTRIES(port->sys_size), 430e0423236SZhang Wei GFP_KERNEL); 4315f28c520SYang Li if (!rswitch->route_table) 4325f28c520SYang Li goto cleanup; 433eb188d0eSMatt Porter /* Initialize switch route table */ 434e0423236SZhang Wei for (rdid = 0; rdid < RIO_MAX_ROUTE_ENTRIES(port->sys_size); 435e0423236SZhang Wei rdid++) 436eb188d0eSMatt Porter rswitch->route_table[rdid] = RIO_INVALID_ROUTE; 437b53c7583SKay Sievers dev_set_name(&rdev->dev, "%02x:s:%04x", rdev->net->id, 4386ca40c25SAlexandre Bounine rdev->comp_tag & RIO_CTAG_UDEVID); 439eb188d0eSMatt Porter 4402ec3ba69SAlexandre Bounine if (do_enum) 4412ec3ba69SAlexandre Bounine rio_route_clr_table(rdev, RIO_GLOBAL_TABLE, 0); 442933af4a6SThomas Moll } else { 443933af4a6SThomas Moll if (do_enum) 4441ae842deSAlexandre Bounine /*Enable Input Output Port (transmitter receiver)*/ 445933af4a6SThomas Moll rio_enable_rx_tx_port(port, 0, destid, hopcount, 0); 446933af4a6SThomas Moll 447b53c7583SKay Sievers dev_set_name(&rdev->dev, "%02x:e:%04x", rdev->net->id, 4486ca40c25SAlexandre Bounine rdev->comp_tag & RIO_CTAG_UDEVID); 449933af4a6SThomas Moll } 450eb188d0eSMatt Porter 451e6b585caSAlexandre Bounine rdev->dev.parent = &net->dev; 452a11650e1SAlexandre Bounine rio_attach_device(rdev); 453eb188d0eSMatt Porter rdev->dev.release = rio_release_dev; 454284901a9SYang Hongyang rdev->dma_mask = DMA_BIT_MASK(32); 455fa78cc51SMatt Porter rdev->dev.dma_mask = &rdev->dma_mask; 456284901a9SYang Hongyang rdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); 457eb188d0eSMatt Porter 458284fb68dSAlexandre Bounine if (rdev->dst_ops & RIO_DST_OPS_DOORBELL) 459eb188d0eSMatt Porter rio_init_dbell_res(&rdev->riores[RIO_DOORBELL_RESOURCE], 460eb188d0eSMatt Porter 0, 0xffff); 461eb188d0eSMatt Porter 4625f28c520SYang Li ret = rio_add_device(rdev); 4635f28c520SYang Li if (ret) 4645f28c520SYang Li goto cleanup; 465eb188d0eSMatt Porter 466b74ec56eSAlexandre Bounine rio_dev_get(rdev); 467b74ec56eSAlexandre Bounine 468eb188d0eSMatt Porter return rdev; 4695f28c520SYang Li 4705f28c520SYang Li cleanup: 471166c050bSAlexandre Bounine if (rswitch) 4725f28c520SYang Li kfree(rswitch->route_table); 473ded05782SAlexandre Bounine 4745f28c520SYang Li kfree(rdev); 4755f28c520SYang Li return NULL; 476eb188d0eSMatt Porter } 477eb188d0eSMatt Porter 478eb188d0eSMatt Porter /** 479eb188d0eSMatt Porter * rio_sport_is_active- Tests if a switch port has an active connection. 4801ae842deSAlexandre Bounine * @rdev: RapidIO device object 4811ae842deSAlexandre Bounine * @sp: Switch port number 482eb188d0eSMatt Porter * 483eb188d0eSMatt Porter * Reads the port error status CSR for a particular switch port to 484eb188d0eSMatt Porter * determine if the port has an active link. Returns 485e5cabeb3SAlexandre Bounine * %RIO_PORT_N_ERR_STS_PORT_OK if the port is active or %0 if it is 486eb188d0eSMatt Porter * inactive. 487eb188d0eSMatt Porter */ 488eb188d0eSMatt Porter static int 4891ae842deSAlexandre Bounine rio_sport_is_active(struct rio_dev *rdev, int sp) 490eb188d0eSMatt Porter { 491e5cabeb3SAlexandre Bounine u32 result = 0; 492eb188d0eSMatt Porter 4931ae842deSAlexandre Bounine rio_read_config_32(rdev, RIO_DEV_PORT_N_ERR_STS_CSR(rdev, sp), 494eb188d0eSMatt Porter &result); 495eb188d0eSMatt Porter 496e5cabeb3SAlexandre Bounine return result & RIO_PORT_N_ERR_STS_PORT_OK; 497eb188d0eSMatt Porter } 498eb188d0eSMatt Porter 499eb188d0eSMatt Porter /** 500eb188d0eSMatt Porter * rio_get_host_deviceid_lock- Reads the Host Device ID Lock CSR on a device 501eb188d0eSMatt Porter * @port: Master port to send transaction 502eb188d0eSMatt Porter * @hopcount: Number of hops to the device 503eb188d0eSMatt Porter * 504eb188d0eSMatt Porter * Used during enumeration to read the Host Device ID Lock CSR on a 505eb188d0eSMatt Porter * RIO device. Returns the value of the lock register. 506eb188d0eSMatt Porter */ 507eb188d0eSMatt Porter static u16 rio_get_host_deviceid_lock(struct rio_mport *port, u8 hopcount) 508eb188d0eSMatt Porter { 509eb188d0eSMatt Porter u32 result; 510eb188d0eSMatt Porter 511e0423236SZhang Wei rio_mport_read_config_32(port, RIO_ANY_DESTID(port->sys_size), hopcount, 512eb188d0eSMatt Porter RIO_HOST_DID_LOCK_CSR, &result); 513eb188d0eSMatt Porter 514eb188d0eSMatt Porter return (u16) (result & 0xffff); 515eb188d0eSMatt Porter } 516eb188d0eSMatt Porter 517eb188d0eSMatt Porter /** 518eb188d0eSMatt Porter * rio_enum_peer- Recursively enumerate a RIO network through a master port 519eb188d0eSMatt Porter * @net: RIO network being enumerated 520eb188d0eSMatt Porter * @port: Master port to send transactions 521eb188d0eSMatt Porter * @hopcount: Number of hops into the network 52268fe4df5SAlexandre Bounine * @prev: Previous RIO device connected to the enumerated one 52368fe4df5SAlexandre Bounine * @prev_port: Port on previous RIO device 524eb188d0eSMatt Porter * 525eb188d0eSMatt Porter * Recursively enumerates a RIO network. Transactions are sent via the 526eb188d0eSMatt Porter * master port passed in @port. 527eb188d0eSMatt Porter */ 528305c891eSBill Pemberton static int rio_enum_peer(struct rio_net *net, struct rio_mport *port, 52968fe4df5SAlexandre Bounine u8 hopcount, struct rio_dev *prev, int prev_port) 530eb188d0eSMatt Porter { 531eb188d0eSMatt Porter struct rio_dev *rdev; 532af84ca38SAlexandre Bounine u32 regval; 533eb188d0eSMatt Porter int tmp; 534eb188d0eSMatt Porter 535e274e0edSAlexandre Bounine if (rio_mport_chk_dev_access(port, 536e274e0edSAlexandre Bounine RIO_ANY_DESTID(port->sys_size), hopcount)) { 537e274e0edSAlexandre Bounine pr_debug("RIO: device access check failed\n"); 538e274e0edSAlexandre Bounine return -1; 539e274e0edSAlexandre Bounine } 540e274e0edSAlexandre Bounine 541eb188d0eSMatt Porter if (rio_get_host_deviceid_lock(port, hopcount) == port->host_deviceid) { 542eb188d0eSMatt Porter pr_debug("RIO: PE already discovered by this host\n"); 543eb188d0eSMatt Porter /* 544eb188d0eSMatt Porter * Already discovered by this host. Add it as another 545af84ca38SAlexandre Bounine * link to the existing device. 546eb188d0eSMatt Porter */ 547af84ca38SAlexandre Bounine rio_mport_read_config_32(port, RIO_ANY_DESTID(port->sys_size), 548af84ca38SAlexandre Bounine hopcount, RIO_COMPONENT_TAG_CSR, ®val); 549af84ca38SAlexandre Bounine 550af84ca38SAlexandre Bounine if (regval) { 551af84ca38SAlexandre Bounine rdev = rio_get_comptag((regval & 0xffff), NULL); 552af84ca38SAlexandre Bounine 553af84ca38SAlexandre Bounine if (rdev && prev && rio_is_switch(prev)) { 554af84ca38SAlexandre Bounine pr_debug("RIO: redundant path to %s\n", 555af84ca38SAlexandre Bounine rio_name(rdev)); 556af84ca38SAlexandre Bounine prev->rswitch->nextdev[prev_port] = rdev; 557af84ca38SAlexandre Bounine } 558af84ca38SAlexandre Bounine } 559af84ca38SAlexandre Bounine 560eb188d0eSMatt Porter return 0; 561eb188d0eSMatt Porter } 562eb188d0eSMatt Porter 563eb188d0eSMatt Porter /* Attempt to acquire device lock */ 564e0423236SZhang Wei rio_mport_write_config_32(port, RIO_ANY_DESTID(port->sys_size), 565e0423236SZhang Wei hopcount, 566eb188d0eSMatt Porter RIO_HOST_DID_LOCK_CSR, port->host_deviceid); 567eb188d0eSMatt Porter while ((tmp = rio_get_host_deviceid_lock(port, hopcount)) 568eb188d0eSMatt Porter < port->host_deviceid) { 569eb188d0eSMatt Porter /* Delay a bit */ 570eb188d0eSMatt Porter mdelay(1); 571eb188d0eSMatt Porter /* Attempt to acquire device lock again */ 572e0423236SZhang Wei rio_mport_write_config_32(port, RIO_ANY_DESTID(port->sys_size), 573e0423236SZhang Wei hopcount, 574eb188d0eSMatt Porter RIO_HOST_DID_LOCK_CSR, 575eb188d0eSMatt Porter port->host_deviceid); 576eb188d0eSMatt Porter } 577eb188d0eSMatt Porter 578eb188d0eSMatt Porter if (rio_get_host_deviceid_lock(port, hopcount) > port->host_deviceid) { 579eb188d0eSMatt Porter pr_debug( 580eb188d0eSMatt Porter "RIO: PE locked by a higher priority host...retreating\n"); 581eb188d0eSMatt Porter return -1; 582eb188d0eSMatt Porter } 583eb188d0eSMatt Porter 584eb188d0eSMatt Porter /* Setup new RIO device */ 585e0423236SZhang Wei rdev = rio_setup_device(net, port, RIO_ANY_DESTID(port->sys_size), 586e0423236SZhang Wei hopcount, 1); 587e0423236SZhang Wei if (rdev) { 58868fe4df5SAlexandre Bounine rdev->prev = prev; 58968fe4df5SAlexandre Bounine if (prev && rio_is_switch(prev)) 59068fe4df5SAlexandre Bounine prev->rswitch->nextdev[prev_port] = rdev; 591eb188d0eSMatt Porter } else 592eb188d0eSMatt Porter return -1; 593eb188d0eSMatt Porter 594eb188d0eSMatt Porter if (rio_is_switch(rdev)) { 595de74e00aSAlexandre Bounine int sw_destid; 596de74e00aSAlexandre Bounine int cur_destid; 597de74e00aSAlexandre Bounine int sw_inport; 598de74e00aSAlexandre Bounine u16 destid; 599de74e00aSAlexandre Bounine int port_num; 600de74e00aSAlexandre Bounine 601ae05cbd5SAlexandre Bounine sw_inport = RIO_GET_PORT_NUM(rdev->swpinfo); 602a93192a5SAlexandre Bounine rio_route_add_entry(rdev, RIO_GLOBAL_TABLE, 603818a04a0SAlexandre Bounine port->host_deviceid, sw_inport, 0); 604c70555b0SAlexandre Bounine rdev->rswitch->route_table[port->host_deviceid] = sw_inport; 605eb188d0eSMatt Porter 606de74e00aSAlexandre Bounine destid = rio_destid_first(net); 607de74e00aSAlexandre Bounine while (destid != RIO_INVALID_DESTID && destid < next_destid) { 608de74e00aSAlexandre Bounine if (destid != port->host_deviceid) { 609a93192a5SAlexandre Bounine rio_route_add_entry(rdev, RIO_GLOBAL_TABLE, 610818a04a0SAlexandre Bounine destid, sw_inport, 0); 611c70555b0SAlexandre Bounine rdev->rswitch->route_table[destid] = sw_inport; 612eb188d0eSMatt Porter } 613de74e00aSAlexandre Bounine destid = rio_destid_next(net, destid + 1); 614de74e00aSAlexandre Bounine } 615eb188d0eSMatt Porter pr_debug( 616eb188d0eSMatt Porter "RIO: found %s (vid %4.4x did %4.4x) with %d ports\n", 61768fe4df5SAlexandre Bounine rio_name(rdev), rdev->vid, rdev->did, 61868fe4df5SAlexandre Bounine RIO_GET_TOTAL_PORTS(rdev->swpinfo)); 619c70555b0SAlexandre Bounine sw_destid = next_destid; 62068fe4df5SAlexandre Bounine for (port_num = 0; 62168fe4df5SAlexandre Bounine port_num < RIO_GET_TOTAL_PORTS(rdev->swpinfo); 62268fe4df5SAlexandre Bounine port_num++) { 6238d4630dcSAlexandre Bounine if (sw_inport == port_num) { 624933af4a6SThomas Moll rio_enable_rx_tx_port(port, 0, 625933af4a6SThomas Moll RIO_ANY_DESTID(port->sys_size), 626933af4a6SThomas Moll hopcount, port_num); 627e5cabeb3SAlexandre Bounine rdev->rswitch->port_ok |= (1 << port_num); 628eb188d0eSMatt Porter continue; 629e5cabeb3SAlexandre Bounine } 630eb188d0eSMatt Porter 631eb188d0eSMatt Porter cur_destid = next_destid; 632eb188d0eSMatt Porter 6331ae842deSAlexandre Bounine if (rio_sport_is_active(rdev, port_num)) { 634eb188d0eSMatt Porter pr_debug( 635eb188d0eSMatt Porter "RIO: scanning device on port %d\n", 636eb188d0eSMatt Porter port_num); 6378d4630dcSAlexandre Bounine rio_enable_rx_tx_port(port, 0, 6388d4630dcSAlexandre Bounine RIO_ANY_DESTID(port->sys_size), 6398d4630dcSAlexandre Bounine hopcount, port_num); 640e5cabeb3SAlexandre Bounine rdev->rswitch->port_ok |= (1 << port_num); 641a93192a5SAlexandre Bounine rio_route_add_entry(rdev, RIO_GLOBAL_TABLE, 642e0423236SZhang Wei RIO_ANY_DESTID(port->sys_size), 643818a04a0SAlexandre Bounine port_num, 0); 644eb188d0eSMatt Porter 64568fe4df5SAlexandre Bounine if (rio_enum_peer(net, port, hopcount + 1, 64668fe4df5SAlexandre Bounine rdev, port_num) < 0) 647eb188d0eSMatt Porter return -1; 648eb188d0eSMatt Porter 649eb188d0eSMatt Porter /* Update routing tables */ 650de74e00aSAlexandre Bounine destid = rio_destid_next(net, cur_destid + 1); 651de74e00aSAlexandre Bounine if (destid != RIO_INVALID_DESTID) { 652eb188d0eSMatt Porter for (destid = cur_destid; 653de74e00aSAlexandre Bounine destid < next_destid;) { 654de74e00aSAlexandre Bounine if (destid != port->host_deviceid) { 655a93192a5SAlexandre Bounine rio_route_add_entry(rdev, 656eb188d0eSMatt Porter RIO_GLOBAL_TABLE, 657eb188d0eSMatt Porter destid, 658818a04a0SAlexandre Bounine port_num, 659818a04a0SAlexandre Bounine 0); 660eb188d0eSMatt Porter rdev->rswitch-> 661eb188d0eSMatt Porter route_table[destid] = 662eb188d0eSMatt Porter port_num; 663eb188d0eSMatt Porter } 664de74e00aSAlexandre Bounine destid = rio_destid_next(net, 665de74e00aSAlexandre Bounine destid + 1); 666de74e00aSAlexandre Bounine } 667eb188d0eSMatt Porter } 668e5cabeb3SAlexandre Bounine } else { 669e5cabeb3SAlexandre Bounine /* If switch supports Error Management, 670e5cabeb3SAlexandre Bounine * set PORT_LOCKOUT bit for unused port 671e5cabeb3SAlexandre Bounine */ 672e5cabeb3SAlexandre Bounine if (rdev->em_efptr) 673e5cabeb3SAlexandre Bounine rio_set_port_lockout(rdev, port_num, 1); 674e5cabeb3SAlexandre Bounine 675e5cabeb3SAlexandre Bounine rdev->rswitch->port_ok &= ~(1 << port_num); 676eb188d0eSMatt Porter } 677eb188d0eSMatt Porter } 678c70555b0SAlexandre Bounine 679e5cabeb3SAlexandre Bounine /* Direct Port-write messages to the enumeratiing host */ 680e5cabeb3SAlexandre Bounine if ((rdev->src_ops & RIO_SRC_OPS_PORT_WRITE) && 681e5cabeb3SAlexandre Bounine (rdev->em_efptr)) { 682e5cabeb3SAlexandre Bounine rio_write_config_32(rdev, 683e5cabeb3SAlexandre Bounine rdev->em_efptr + RIO_EM_PW_TGT_DEVID, 684e5cabeb3SAlexandre Bounine (port->host_deviceid << 16) | 685e5cabeb3SAlexandre Bounine (port->sys_size << 15)); 686e5cabeb3SAlexandre Bounine } 687e5cabeb3SAlexandre Bounine 688e5cabeb3SAlexandre Bounine rio_init_em(rdev); 689e5cabeb3SAlexandre Bounine 690c70555b0SAlexandre Bounine /* Check for empty switch */ 691de74e00aSAlexandre Bounine if (next_destid == sw_destid) 692de74e00aSAlexandre Bounine next_destid = rio_destid_alloc(net); 693c70555b0SAlexandre Bounine 694a93192a5SAlexandre Bounine rdev->destid = sw_destid; 695eb188d0eSMatt Porter } else 696eb188d0eSMatt Porter pr_debug("RIO: found %s (vid %4.4x did %4.4x)\n", 697eb188d0eSMatt Porter rio_name(rdev), rdev->vid, rdev->did); 698eb188d0eSMatt Porter 699eb188d0eSMatt Porter return 0; 700eb188d0eSMatt Porter } 701eb188d0eSMatt Porter 702eb188d0eSMatt Porter /** 703eb188d0eSMatt Porter * rio_enum_complete- Tests if enumeration of a network is complete 704eb188d0eSMatt Porter * @port: Master port to send transaction 705eb188d0eSMatt Porter * 706a571259fSLiu Gang * Tests the PGCCSR discovered bit for non-zero value (enumeration 707e5cabeb3SAlexandre Bounine * complete flag). Return %1 if enumeration is complete or %0 if 708eb188d0eSMatt Porter * enumeration is incomplete. 709eb188d0eSMatt Porter */ 710eb188d0eSMatt Porter static int rio_enum_complete(struct rio_mport *port) 711eb188d0eSMatt Porter { 712af84ca38SAlexandre Bounine u32 regval; 713eb188d0eSMatt Porter 714af84ca38SAlexandre Bounine rio_local_read_config_32(port, port->phys_efptr + RIO_PORT_GEN_CTL_CSR, 715af84ca38SAlexandre Bounine ®val); 716a571259fSLiu Gang return (regval & RIO_PORT_GEN_DISCOVERED) ? 1 : 0; 717eb188d0eSMatt Porter } 718eb188d0eSMatt Porter 719eb188d0eSMatt Porter /** 720eb188d0eSMatt Porter * rio_disc_peer- Recursively discovers a RIO network through a master port 721eb188d0eSMatt Porter * @net: RIO network being discovered 722eb188d0eSMatt Porter * @port: Master port to send transactions 723eb188d0eSMatt Porter * @destid: Current destination ID in network 724eb188d0eSMatt Porter * @hopcount: Number of hops into the network 7259b310accSRandy Dunlap * @prev: previous rio_dev 7269b310accSRandy Dunlap * @prev_port: previous port number 727eb188d0eSMatt Porter * 728eb188d0eSMatt Porter * Recursively discovers a RIO network. Transactions are sent via the 729eb188d0eSMatt Porter * master port passed in @port. 730eb188d0eSMatt Porter */ 731305c891eSBill Pemberton static int 732eb188d0eSMatt Porter rio_disc_peer(struct rio_net *net, struct rio_mport *port, u16 destid, 73317e96205SAlexandre Bounine u8 hopcount, struct rio_dev *prev, int prev_port) 734eb188d0eSMatt Porter { 735eb188d0eSMatt Porter u8 port_num, route_port; 736eb188d0eSMatt Porter struct rio_dev *rdev; 737eb188d0eSMatt Porter u16 ndestid; 738eb188d0eSMatt Porter 739eb188d0eSMatt Porter /* Setup new RIO device */ 740eb188d0eSMatt Porter if ((rdev = rio_setup_device(net, port, destid, hopcount, 0))) { 74117e96205SAlexandre Bounine rdev->prev = prev; 74217e96205SAlexandre Bounine if (prev && rio_is_switch(prev)) 74317e96205SAlexandre Bounine prev->rswitch->nextdev[prev_port] = rdev; 744eb188d0eSMatt Porter } else 745eb188d0eSMatt Porter return -1; 746eb188d0eSMatt Porter 747eb188d0eSMatt Porter if (rio_is_switch(rdev)) { 748eb188d0eSMatt Porter /* Associated destid is how we accessed this switch */ 749a93192a5SAlexandre Bounine rdev->destid = destid; 750eb188d0eSMatt Porter 751eb188d0eSMatt Porter pr_debug( 752eb188d0eSMatt Porter "RIO: found %s (vid %4.4x did %4.4x) with %d ports\n", 75368fe4df5SAlexandre Bounine rio_name(rdev), rdev->vid, rdev->did, 75468fe4df5SAlexandre Bounine RIO_GET_TOTAL_PORTS(rdev->swpinfo)); 75568fe4df5SAlexandre Bounine for (port_num = 0; 75668fe4df5SAlexandre Bounine port_num < RIO_GET_TOTAL_PORTS(rdev->swpinfo); 75768fe4df5SAlexandre Bounine port_num++) { 758ae05cbd5SAlexandre Bounine if (RIO_GET_PORT_NUM(rdev->swpinfo) == port_num) 759eb188d0eSMatt Porter continue; 760eb188d0eSMatt Porter 7611ae842deSAlexandre Bounine if (rio_sport_is_active(rdev, port_num)) { 762eb188d0eSMatt Porter pr_debug( 763eb188d0eSMatt Porter "RIO: scanning device on port %d\n", 764eb188d0eSMatt Porter port_num); 765818a04a0SAlexandre Bounine 766818a04a0SAlexandre Bounine rio_lock_device(port, destid, hopcount, 1000); 767818a04a0SAlexandre Bounine 768e0423236SZhang Wei for (ndestid = 0; 769e0423236SZhang Wei ndestid < RIO_ANY_DESTID(port->sys_size); 770eb188d0eSMatt Porter ndestid++) { 771a93192a5SAlexandre Bounine rio_route_get_entry(rdev, 772eb188d0eSMatt Porter RIO_GLOBAL_TABLE, 773eb188d0eSMatt Porter ndestid, 774818a04a0SAlexandre Bounine &route_port, 0); 775eb188d0eSMatt Porter if (route_port == port_num) 776eb188d0eSMatt Porter break; 777eb188d0eSMatt Porter } 778eb188d0eSMatt Porter 779af84ca38SAlexandre Bounine if (ndestid == RIO_ANY_DESTID(port->sys_size)) 780af84ca38SAlexandre Bounine continue; 781818a04a0SAlexandre Bounine rio_unlock_device(port, destid, hopcount); 78217e96205SAlexandre Bounine if (rio_disc_peer(net, port, ndestid, 78317e96205SAlexandre Bounine hopcount + 1, rdev, port_num) < 0) 784eb188d0eSMatt Porter return -1; 785eb188d0eSMatt Porter } 786eb188d0eSMatt Porter } 787eb188d0eSMatt Porter } else 788eb188d0eSMatt Porter pr_debug("RIO: found %s (vid %4.4x did %4.4x)\n", 789eb188d0eSMatt Porter rio_name(rdev), rdev->vid, rdev->did); 790eb188d0eSMatt Porter 791eb188d0eSMatt Porter return 0; 792eb188d0eSMatt Porter } 793eb188d0eSMatt Porter 794eb188d0eSMatt Porter /** 795eb188d0eSMatt Porter * rio_mport_is_active- Tests if master port link is active 796eb188d0eSMatt Porter * @port: Master port to test 797eb188d0eSMatt Porter * 798eb188d0eSMatt Porter * Reads the port error status CSR for the master port to 799eb188d0eSMatt Porter * determine if the port has an active link. Returns 800e5cabeb3SAlexandre Bounine * %RIO_PORT_N_ERR_STS_PORT_OK if the master port is active 801eb188d0eSMatt Porter * or %0 if it is inactive. 802eb188d0eSMatt Porter */ 803eb188d0eSMatt Porter static int rio_mport_is_active(struct rio_mport *port) 804eb188d0eSMatt Porter { 805eb188d0eSMatt Porter u32 result = 0; 806eb188d0eSMatt Porter 807eb188d0eSMatt Porter rio_local_read_config_32(port, 8081ae842deSAlexandre Bounine port->phys_efptr + 8091ae842deSAlexandre Bounine RIO_PORT_N_ERR_STS_CSR(port->index, port->phys_rmap), 810eb188d0eSMatt Porter &result); 811e5cabeb3SAlexandre Bounine return result & RIO_PORT_N_ERR_STS_PORT_OK; 812eb188d0eSMatt Porter } 813eb188d0eSMatt Porter 814e6b585caSAlexandre Bounine static void rio_scan_release_net(struct rio_net *net) 815e6b585caSAlexandre Bounine { 816e6b585caSAlexandre Bounine pr_debug("RIO-SCAN: %s: net_%d\n", __func__, net->id); 817e6b585caSAlexandre Bounine kfree(net->enum_data); 818e6b585caSAlexandre Bounine } 819e6b585caSAlexandre Bounine 820e6b585caSAlexandre Bounine static void rio_scan_release_dev(struct device *dev) 821e6b585caSAlexandre Bounine { 822e6b585caSAlexandre Bounine struct rio_net *net; 823e6b585caSAlexandre Bounine 824e6b585caSAlexandre Bounine net = to_rio_net(dev); 825e6b585caSAlexandre Bounine pr_debug("RIO-SCAN: %s: net_%d\n", __func__, net->id); 826e6b585caSAlexandre Bounine kfree(net); 827e6b585caSAlexandre Bounine } 828e6b585caSAlexandre Bounine 829e6b585caSAlexandre Bounine /* 830e6b585caSAlexandre Bounine * rio_scan_alloc_net - Allocate and configure a new RIO network 831e6b585caSAlexandre Bounine * @mport: Master port associated with the RIO network 832de74e00aSAlexandre Bounine * @do_enum: Enumeration/Discovery mode flag 833de74e00aSAlexandre Bounine * @start: logical minimal start id for new net 834eb188d0eSMatt Porter * 835e6b585caSAlexandre Bounine * Allocates a new RIO network structure and initializes enumerator-specific 836e6b585caSAlexandre Bounine * part of it (if required). 837e6b585caSAlexandre Bounine * Returns a RIO network pointer on success or %NULL on failure. 838eb188d0eSMatt Porter */ 839e6b585caSAlexandre Bounine static struct rio_net *rio_scan_alloc_net(struct rio_mport *mport, 840de74e00aSAlexandre Bounine int do_enum, u16 start) 841eb188d0eSMatt Porter { 842eb188d0eSMatt Porter struct rio_net *net; 843eb188d0eSMatt Porter 844e6b585caSAlexandre Bounine net = rio_alloc_net(mport); 845de74e00aSAlexandre Bounine 846e6b585caSAlexandre Bounine if (net && do_enum) { 847e6b585caSAlexandre Bounine struct rio_id_table *idtab; 848e6b585caSAlexandre Bounine size_t size; 849e6b585caSAlexandre Bounine 850e6b585caSAlexandre Bounine size = sizeof(struct rio_id_table) + 851e6b585caSAlexandre Bounine BITS_TO_LONGS( 852e6b585caSAlexandre Bounine RIO_MAX_ROUTE_ENTRIES(mport->sys_size) 853e6b585caSAlexandre Bounine ) * sizeof(long); 854e6b585caSAlexandre Bounine 855e6b585caSAlexandre Bounine idtab = kzalloc(size, GFP_KERNEL); 856e6b585caSAlexandre Bounine 857e6b585caSAlexandre Bounine if (idtab == NULL) { 858de74e00aSAlexandre Bounine pr_err("RIO: failed to allocate destID table\n"); 859e6b585caSAlexandre Bounine rio_free_net(net); 860de74e00aSAlexandre Bounine net = NULL; 861de74e00aSAlexandre Bounine } else { 862e6b585caSAlexandre Bounine net->enum_data = idtab; 863e6b585caSAlexandre Bounine net->release = rio_scan_release_net; 864e6b585caSAlexandre Bounine idtab->start = start; 865e6b585caSAlexandre Bounine idtab->max = RIO_MAX_ROUTE_ENTRIES(mport->sys_size); 866e6b585caSAlexandre Bounine spin_lock_init(&idtab->lock); 867de74e00aSAlexandre Bounine } 868de74e00aSAlexandre Bounine } 869de74e00aSAlexandre Bounine 870eb188d0eSMatt Porter if (net) { 871e6b585caSAlexandre Bounine net->id = mport->id; 872e6b585caSAlexandre Bounine net->hport = mport; 873e6b585caSAlexandre Bounine dev_set_name(&net->dev, "rnet_%d", net->id); 874e6b585caSAlexandre Bounine net->dev.parent = &mport->dev; 875e6b585caSAlexandre Bounine net->dev.release = rio_scan_release_dev; 876e6b585caSAlexandre Bounine rio_add_net(net); 877eb188d0eSMatt Porter } 878e6b585caSAlexandre Bounine 879eb188d0eSMatt Porter return net; 880eb188d0eSMatt Porter } 881eb188d0eSMatt Porter 882eb188d0eSMatt Porter /** 883c70555b0SAlexandre Bounine * rio_update_route_tables- Updates route tables in switches 884a7071efcSAlexandre Bounine * @net: RIO network to run update on 885c70555b0SAlexandre Bounine * 886c70555b0SAlexandre Bounine * For each enumerated device, ensure that each switch in a system 887c70555b0SAlexandre Bounine * has correct routing entries. Add routes for devices that where 888b94bb1f6SVasyl Gomonovych * unknown during the first enumeration pass through the switch. 889c70555b0SAlexandre Bounine */ 890a7071efcSAlexandre Bounine static void rio_update_route_tables(struct rio_net *net) 891c70555b0SAlexandre Bounine { 892ded05782SAlexandre Bounine struct rio_dev *rdev, *swrdev; 893c70555b0SAlexandre Bounine struct rio_switch *rswitch; 894c70555b0SAlexandre Bounine u8 sport; 895c70555b0SAlexandre Bounine u16 destid; 896c70555b0SAlexandre Bounine 897a7071efcSAlexandre Bounine list_for_each_entry(rdev, &net->devices, net_list) { 898c70555b0SAlexandre Bounine 899a93192a5SAlexandre Bounine destid = rdev->destid; 900c70555b0SAlexandre Bounine 901a7071efcSAlexandre Bounine list_for_each_entry(rswitch, &net->switches, node) { 902c70555b0SAlexandre Bounine 903c70555b0SAlexandre Bounine if (rio_is_switch(rdev) && (rdev->rswitch == rswitch)) 904c70555b0SAlexandre Bounine continue; 905c70555b0SAlexandre Bounine 906c70555b0SAlexandre Bounine if (RIO_INVALID_ROUTE == rswitch->route_table[destid]) { 907ded05782SAlexandre Bounine swrdev = sw_to_rio_dev(rswitch); 908ded05782SAlexandre Bounine 90907590ff0SAlexandre Bounine /* Skip if destid ends in empty switch*/ 910ded05782SAlexandre Bounine if (swrdev->destid == destid) 91107590ff0SAlexandre Bounine continue; 912c70555b0SAlexandre Bounine 913ded05782SAlexandre Bounine sport = RIO_GET_PORT_NUM(swrdev->swpinfo); 914c70555b0SAlexandre Bounine 9152ec3ba69SAlexandre Bounine rio_route_add_entry(swrdev, RIO_GLOBAL_TABLE, 9162ec3ba69SAlexandre Bounine destid, sport, 0); 917c70555b0SAlexandre Bounine rswitch->route_table[destid] = sport; 918c70555b0SAlexandre Bounine } 919c70555b0SAlexandre Bounine } 920c70555b0SAlexandre Bounine } 921c70555b0SAlexandre Bounine } 922c70555b0SAlexandre Bounine 923c70555b0SAlexandre Bounine /** 924e5cabeb3SAlexandre Bounine * rio_init_em - Initializes RIO Error Management (for switches) 92597ef6f74SRandy Dunlap * @rdev: RIO device 926e5cabeb3SAlexandre Bounine * 927e5cabeb3SAlexandre Bounine * For each enumerated switch, call device-specific error management 928e5cabeb3SAlexandre Bounine * initialization routine (if supplied by the switch driver). 929e5cabeb3SAlexandre Bounine */ 930e5cabeb3SAlexandre Bounine static void rio_init_em(struct rio_dev *rdev) 931e5cabeb3SAlexandre Bounine { 932e5cabeb3SAlexandre Bounine if (rio_is_switch(rdev) && (rdev->em_efptr) && 9332ec3ba69SAlexandre Bounine rdev->rswitch->ops && rdev->rswitch->ops->em_init) { 9342ec3ba69SAlexandre Bounine rdev->rswitch->ops->em_init(rdev); 935e5cabeb3SAlexandre Bounine } 936e5cabeb3SAlexandre Bounine } 937e5cabeb3SAlexandre Bounine 938e5cabeb3SAlexandre Bounine /** 939eb188d0eSMatt Porter * rio_enum_mport- Start enumeration through a master port 940eb188d0eSMatt Porter * @mport: Master port to send transactions 941bc8fcfeaSAlexandre Bounine * @flags: Enumeration control flags 942eb188d0eSMatt Porter * 943eb188d0eSMatt Porter * Starts the enumeration process. If somebody has enumerated our 944eb188d0eSMatt Porter * master port device, then give up. If not and we have an active 945eb188d0eSMatt Porter * link, then start recursive peer enumeration. Returns %0 if 946eb188d0eSMatt Porter * enumeration succeeds or %-EBUSY if enumeration fails. 947eb188d0eSMatt Porter */ 94836f0efbbSWu Fengguang static int rio_enum_mport(struct rio_mport *mport, u32 flags) 949eb188d0eSMatt Porter { 950eb188d0eSMatt Porter struct rio_net *net = NULL; 951eb188d0eSMatt Porter int rc = 0; 952eb188d0eSMatt Porter 953eb188d0eSMatt Porter printk(KERN_INFO "RIO: enumerate master port %d, %s\n", mport->id, 954eb188d0eSMatt Porter mport->name); 955bc8fcfeaSAlexandre Bounine 956bc8fcfeaSAlexandre Bounine /* 957bc8fcfeaSAlexandre Bounine * To avoid multiple start requests (repeat enumeration is not supported 958bc8fcfeaSAlexandre Bounine * by this method) check if enumeration/discovery was performed for this 959bc8fcfeaSAlexandre Bounine * mport: if mport was added into the list of mports for a net exit 960bc8fcfeaSAlexandre Bounine * with error. 961bc8fcfeaSAlexandre Bounine */ 962bc8fcfeaSAlexandre Bounine if (mport->nnode.next || mport->nnode.prev) 963bc8fcfeaSAlexandre Bounine return -EBUSY; 964bc8fcfeaSAlexandre Bounine 965eb188d0eSMatt Porter /* If somebody else enumerated our master port device, bail. */ 966eb188d0eSMatt Porter if (rio_enum_host(mport) < 0) { 967eb188d0eSMatt Porter printk(KERN_INFO 968eb188d0eSMatt Porter "RIO: master port %d device has been enumerated by a remote host\n", 969eb188d0eSMatt Porter mport->id); 970eb188d0eSMatt Porter rc = -EBUSY; 971eb188d0eSMatt Porter goto out; 972eb188d0eSMatt Porter } 973eb188d0eSMatt Porter 974eb188d0eSMatt Porter /* If master port has an active link, allocate net and enum peers */ 975eb188d0eSMatt Porter if (rio_mport_is_active(mport)) { 976e6b585caSAlexandre Bounine net = rio_scan_alloc_net(mport, 1, 0); 977de74e00aSAlexandre Bounine if (!net) { 978eb188d0eSMatt Porter printk(KERN_ERR "RIO: failed to allocate new net\n"); 979eb188d0eSMatt Porter rc = -ENOMEM; 980eb188d0eSMatt Porter goto out; 981eb188d0eSMatt Porter } 982933af4a6SThomas Moll 983de74e00aSAlexandre Bounine /* reserve mport destID in new net */ 984de74e00aSAlexandre Bounine rio_destid_reserve(net, mport->host_deviceid); 985de74e00aSAlexandre Bounine 986b94bb1f6SVasyl Gomonovych /* Enable Input Output Port (transmitter receiver) */ 987933af4a6SThomas Moll rio_enable_rx_tx_port(mport, 1, 0, 0, 0); 988933af4a6SThomas Moll 989af84ca38SAlexandre Bounine /* Set component tag for host */ 990af84ca38SAlexandre Bounine rio_local_write_config_32(mport, RIO_COMPONENT_TAG_CSR, 991af84ca38SAlexandre Bounine next_comptag++); 992af84ca38SAlexandre Bounine 993de74e00aSAlexandre Bounine next_destid = rio_destid_alloc(net); 994de74e00aSAlexandre Bounine 99568fe4df5SAlexandre Bounine if (rio_enum_peer(net, mport, 0, NULL, 0) < 0) { 996eb188d0eSMatt Porter /* A higher priority host won enumeration, bail. */ 997eb188d0eSMatt Porter printk(KERN_INFO 998eb188d0eSMatt Porter "RIO: master port %d device has lost enumeration to a remote host\n", 999eb188d0eSMatt Porter mport->id); 1000a7071efcSAlexandre Bounine rio_clear_locks(net); 1001eb188d0eSMatt Porter rc = -EBUSY; 1002eb188d0eSMatt Porter goto out; 1003eb188d0eSMatt Porter } 1004de74e00aSAlexandre Bounine /* free the last allocated destID (unused) */ 1005de74e00aSAlexandre Bounine rio_destid_free(net, next_destid); 1006a7071efcSAlexandre Bounine rio_update_route_tables(net); 1007a7071efcSAlexandre Bounine rio_clear_locks(net); 1008e5cabeb3SAlexandre Bounine rio_pw_enable(mport, 1); 1009eb188d0eSMatt Porter } else { 1010eb188d0eSMatt Porter printk(KERN_INFO "RIO: master port %d link inactive\n", 1011eb188d0eSMatt Porter mport->id); 1012eb188d0eSMatt Porter rc = -EINVAL; 1013eb188d0eSMatt Porter } 1014eb188d0eSMatt Porter 1015eb188d0eSMatt Porter out: 1016eb188d0eSMatt Porter return rc; 1017eb188d0eSMatt Porter } 1018eb188d0eSMatt Porter 1019eb188d0eSMatt Porter /** 1020eb188d0eSMatt Porter * rio_build_route_tables- Generate route tables from switch route entries 1021a7071efcSAlexandre Bounine * @net: RIO network to run route tables scan on 1022eb188d0eSMatt Porter * 1023eb188d0eSMatt Porter * For each switch device, generate a route table by copying existing 1024eb188d0eSMatt Porter * route entries from the switch. 1025eb188d0eSMatt Porter */ 1026a7071efcSAlexandre Bounine static void rio_build_route_tables(struct rio_net *net) 1027eb188d0eSMatt Porter { 1028a7071efcSAlexandre Bounine struct rio_switch *rswitch; 1029eb188d0eSMatt Porter struct rio_dev *rdev; 1030eb188d0eSMatt Porter int i; 1031eb188d0eSMatt Porter u8 sport; 1032eb188d0eSMatt Porter 1033a7071efcSAlexandre Bounine list_for_each_entry(rswitch, &net->switches, node) { 1034a7071efcSAlexandre Bounine rdev = sw_to_rio_dev(rswitch); 1035a7071efcSAlexandre Bounine 1036a7071efcSAlexandre Bounine rio_lock_device(net->hport, rdev->destid, 1037a93192a5SAlexandre Bounine rdev->hopcount, 1000); 1038e0423236SZhang Wei for (i = 0; 1039a7071efcSAlexandre Bounine i < RIO_MAX_ROUTE_ENTRIES(net->hport->sys_size); 1040e0423236SZhang Wei i++) { 1041a7071efcSAlexandre Bounine if (rio_route_get_entry(rdev, RIO_GLOBAL_TABLE, 1042a7071efcSAlexandre Bounine i, &sport, 0) < 0) 1043eb188d0eSMatt Porter continue; 1044a7071efcSAlexandre Bounine rswitch->route_table[i] = sport; 1045eb188d0eSMatt Porter } 1046818a04a0SAlexandre Bounine 1047a7071efcSAlexandre Bounine rio_unlock_device(net->hport, rdev->destid, rdev->hopcount); 1048818a04a0SAlexandre Bounine } 1049eb188d0eSMatt Porter } 1050eb188d0eSMatt Porter 1051eb188d0eSMatt Porter /** 1052eb188d0eSMatt Porter * rio_disc_mport- Start discovery through a master port 1053eb188d0eSMatt Porter * @mport: Master port to send transactions 1054bc8fcfeaSAlexandre Bounine * @flags: discovery control flags 1055eb188d0eSMatt Porter * 1056eb188d0eSMatt Porter * Starts the discovery process. If we have an active link, 1057bc8fcfeaSAlexandre Bounine * then wait for the signal that enumeration is complete (if wait 1058bc8fcfeaSAlexandre Bounine * is allowed). 1059eb188d0eSMatt Porter * When enumeration completion is signaled, start recursive 1060eb188d0eSMatt Porter * peer discovery. Returns %0 if discovery succeeds or %-EBUSY 1061eb188d0eSMatt Porter * on failure. 1062eb188d0eSMatt Porter */ 106336f0efbbSWu Fengguang static int rio_disc_mport(struct rio_mport *mport, u32 flags) 1064eb188d0eSMatt Porter { 1065eb188d0eSMatt Porter struct rio_net *net = NULL; 1066fa3dbaa0SAlexandre Bounine unsigned long to_end; 1067eb188d0eSMatt Porter 1068eb188d0eSMatt Porter printk(KERN_INFO "RIO: discover master port %d, %s\n", mport->id, 1069eb188d0eSMatt Porter mport->name); 1070eb188d0eSMatt Porter 1071eb188d0eSMatt Porter /* If master port has an active link, allocate net and discover peers */ 1072eb188d0eSMatt Porter if (rio_mport_is_active(mport)) { 1073bc8fcfeaSAlexandre Bounine if (rio_enum_complete(mport)) 1074bc8fcfeaSAlexandre Bounine goto enum_done; 1075bc8fcfeaSAlexandre Bounine else if (flags & RIO_SCAN_ENUM_NO_WAIT) 1076bc8fcfeaSAlexandre Bounine return -EAGAIN; 1077bc8fcfeaSAlexandre Bounine 1078fa3dbaa0SAlexandre Bounine pr_debug("RIO: wait for enumeration to complete...\n"); 1079fa3dbaa0SAlexandre Bounine 1080fa3dbaa0SAlexandre Bounine to_end = jiffies + CONFIG_RAPIDIO_DISC_TIMEOUT * HZ; 1081fa3dbaa0SAlexandre Bounine while (time_before(jiffies, to_end)) { 1082fa3dbaa0SAlexandre Bounine if (rio_enum_complete(mport)) 1083fa3dbaa0SAlexandre Bounine goto enum_done; 1084f4c9c0e8SAlexandre Bounine msleep(10); 1085fa3dbaa0SAlexandre Bounine } 1086fa3dbaa0SAlexandre Bounine 1087fa3dbaa0SAlexandre Bounine pr_debug("RIO: discovery timeout on mport %d %s\n", 1088fa3dbaa0SAlexandre Bounine mport->id, mport->name); 1089fa3dbaa0SAlexandre Bounine goto bail; 1090fa3dbaa0SAlexandre Bounine enum_done: 1091fa3dbaa0SAlexandre Bounine pr_debug("RIO: ... enumeration done\n"); 1092fa3dbaa0SAlexandre Bounine 1093e6b585caSAlexandre Bounine net = rio_scan_alloc_net(mport, 0, 0); 1094fa3dbaa0SAlexandre Bounine if (!net) { 1095eb188d0eSMatt Porter printk(KERN_ERR "RIO: Failed to allocate new net\n"); 1096eb188d0eSMatt Porter goto bail; 1097eb188d0eSMatt Porter } 1098eb188d0eSMatt Porter 1099818a04a0SAlexandre Bounine /* Read DestID assigned by enumerator */ 1100818a04a0SAlexandre Bounine rio_local_read_config_32(mport, RIO_DID_CSR, 1101818a04a0SAlexandre Bounine &mport->host_deviceid); 1102818a04a0SAlexandre Bounine mport->host_deviceid = RIO_GET_DID(mport->sys_size, 1103818a04a0SAlexandre Bounine mport->host_deviceid); 1104818a04a0SAlexandre Bounine 1105e0423236SZhang Wei if (rio_disc_peer(net, mport, RIO_ANY_DESTID(mport->sys_size), 110617e96205SAlexandre Bounine 0, NULL, 0) < 0) { 1107eb188d0eSMatt Porter printk(KERN_INFO 1108eb188d0eSMatt Porter "RIO: master port %d device has failed discovery\n", 1109eb188d0eSMatt Porter mport->id); 1110eb188d0eSMatt Porter goto bail; 1111eb188d0eSMatt Porter } 1112eb188d0eSMatt Porter 1113a7071efcSAlexandre Bounine rio_build_route_tables(net); 1114eb188d0eSMatt Porter } 1115eb188d0eSMatt Porter 1116eb188d0eSMatt Porter return 0; 1117eb188d0eSMatt Porter bail: 1118eb188d0eSMatt Porter return -EBUSY; 1119eb188d0eSMatt Porter } 1120a11650e1SAlexandre Bounine 1121a11650e1SAlexandre Bounine static struct rio_scan rio_scan_ops = { 11229edbc30bSAlexandre Bounine .owner = THIS_MODULE, 1123a11650e1SAlexandre Bounine .enumerate = rio_enum_mport, 1124a11650e1SAlexandre Bounine .discover = rio_disc_mport, 1125a11650e1SAlexandre Bounine }; 1126a11650e1SAlexandre Bounine 1127a11650e1SAlexandre Bounine static bool scan; 1128a11650e1SAlexandre Bounine module_param(scan, bool, 0); 1129a11650e1SAlexandre Bounine MODULE_PARM_DESC(scan, "Start RapidIO network enumeration/discovery " 1130a11650e1SAlexandre Bounine "(default = 0)"); 1131a11650e1SAlexandre Bounine 1132a11650e1SAlexandre Bounine /** 1133a11650e1SAlexandre Bounine * rio_basic_attach: 1134a11650e1SAlexandre Bounine * 1135a11650e1SAlexandre Bounine * When this enumeration/discovery method is loaded as a module this function 1136a11650e1SAlexandre Bounine * registers its specific enumeration and discover routines for all available 1137a11650e1SAlexandre Bounine * RapidIO mport devices. The "scan" command line parameter controls ability of 1138a11650e1SAlexandre Bounine * the module to start RapidIO enumeration/discovery automatically. 1139a11650e1SAlexandre Bounine * 1140a11650e1SAlexandre Bounine * Returns 0 for success or -EIO if unable to register itself. 1141a11650e1SAlexandre Bounine * 1142a11650e1SAlexandre Bounine * This enumeration/discovery method cannot be unloaded and therefore does not 1143a11650e1SAlexandre Bounine * provide a matching cleanup_module routine. 1144a11650e1SAlexandre Bounine */ 1145a11650e1SAlexandre Bounine 1146a11650e1SAlexandre Bounine static int __init rio_basic_attach(void) 1147a11650e1SAlexandre Bounine { 1148a11650e1SAlexandre Bounine if (rio_register_scan(RIO_MPORT_ANY, &rio_scan_ops)) 1149a11650e1SAlexandre Bounine return -EIO; 1150a11650e1SAlexandre Bounine if (scan) 1151a11650e1SAlexandre Bounine rio_init_mports(); 1152a11650e1SAlexandre Bounine return 0; 1153a11650e1SAlexandre Bounine } 1154a11650e1SAlexandre Bounine 1155a11650e1SAlexandre Bounine late_initcall(rio_basic_attach); 1156a11650e1SAlexandre Bounine 1157a11650e1SAlexandre Bounine MODULE_DESCRIPTION("Basic RapidIO enumeration/discovery"); 1158a11650e1SAlexandre Bounine MODULE_LICENSE("GPL"); 1159