1394b701cSMatt Porter /* 2394b701cSMatt Porter * RapidIO interconnect services 3394b701cSMatt Porter * (RapidIO Interconnect Specification, http://www.rapidio.org) 4394b701cSMatt Porter * 5394b701cSMatt Porter * Copyright 2005 MontaVista Software, Inc. 6394b701cSMatt Porter * Matt Porter <mporter@kernel.crashing.org> 7394b701cSMatt Porter * 8fdf90abcSAlexandre Bounine * Copyright 2009 - 2013 Integrated Device Technology, Inc. 9e5cabeb3SAlexandre Bounine * Alex Bounine <alexandre.bounine@idt.com> 10e5cabeb3SAlexandre Bounine * 11394b701cSMatt Porter * This program is free software; you can redistribute it and/or modify it 12394b701cSMatt Porter * under the terms of the GNU General Public License as published by the 13394b701cSMatt Porter * Free Software Foundation; either version 2 of the License, or (at your 14394b701cSMatt Porter * option) any later version. 15394b701cSMatt Porter */ 16394b701cSMatt Porter 17394b701cSMatt Porter #include <linux/types.h> 18394b701cSMatt Porter #include <linux/kernel.h> 19394b701cSMatt Porter 20394b701cSMatt Porter #include <linux/delay.h> 21394b701cSMatt Porter #include <linux/init.h> 22394b701cSMatt Porter #include <linux/rio.h> 23394b701cSMatt Porter #include <linux/rio_drv.h> 24394b701cSMatt Porter #include <linux/rio_ids.h> 25394b701cSMatt Porter #include <linux/rio_regs.h> 26394b701cSMatt Porter #include <linux/module.h> 27394b701cSMatt Porter #include <linux/spinlock.h> 28de25968cSTim Schmielau #include <linux/slab.h> 295febf1cdSKumar Gala #include <linux/interrupt.h> 30394b701cSMatt Porter 31394b701cSMatt Porter #include "rio.h" 32394b701cSMatt Porter 339a0b0627SAlexandre Bounine /* 349a0b0627SAlexandre Bounine * struct rio_pwrite - RIO portwrite event 359a0b0627SAlexandre Bounine * @node: Node in list of doorbell events 369a0b0627SAlexandre Bounine * @pwcback: Doorbell event callback 379a0b0627SAlexandre Bounine * @context: Handler specific context to pass on event 389a0b0627SAlexandre Bounine */ 399a0b0627SAlexandre Bounine struct rio_pwrite { 409a0b0627SAlexandre Bounine struct list_head node; 419a0b0627SAlexandre Bounine 429a0b0627SAlexandre Bounine int (*pwcback)(struct rio_mport *mport, void *context, 439a0b0627SAlexandre Bounine union rio_pw_msg *msg, int step); 449a0b0627SAlexandre Bounine void *context; 459a0b0627SAlexandre Bounine }; 469a0b0627SAlexandre Bounine 47fdf90abcSAlexandre Bounine MODULE_DESCRIPTION("RapidIO Subsystem Core"); 48fdf90abcSAlexandre Bounine MODULE_AUTHOR("Matt Porter <mporter@kernel.crashing.org>"); 49fdf90abcSAlexandre Bounine MODULE_AUTHOR("Alexandre Bounine <alexandre.bounine@idt.com>"); 50fdf90abcSAlexandre Bounine MODULE_LICENSE("GPL"); 51fdf90abcSAlexandre Bounine 52fdf90abcSAlexandre Bounine static int hdid[RIO_MAX_MPORTS]; 53fdf90abcSAlexandre Bounine static int ids_num; 54fdf90abcSAlexandre Bounine module_param_array(hdid, int, &ids_num, 0); 55fdf90abcSAlexandre Bounine MODULE_PARM_DESC(hdid, 56fdf90abcSAlexandre Bounine "Destination ID assignment to local RapidIO controllers"); 57fdf90abcSAlexandre Bounine 58a11650e1SAlexandre Bounine static LIST_HEAD(rio_devices); 59e6b585caSAlexandre Bounine static LIST_HEAD(rio_nets); 60a11650e1SAlexandre Bounine static DEFINE_SPINLOCK(rio_global_list_lock); 61a11650e1SAlexandre Bounine 62394b701cSMatt Porter static LIST_HEAD(rio_mports); 639edbc30bSAlexandre Bounine static LIST_HEAD(rio_scans); 64a11650e1SAlexandre Bounine static DEFINE_MUTEX(rio_mport_list_lock); 65569fccb6SAlexandre Bounine static unsigned char next_portid; 66da1589f0SAlexandre Bounine static DEFINE_SPINLOCK(rio_mmap_lock); 67394b701cSMatt Porter 68394b701cSMatt Porter /** 69394b701cSMatt Porter * rio_local_get_device_id - Get the base/extended device id for a port 70394b701cSMatt Porter * @port: RIO master port from which to get the deviceid 71394b701cSMatt Porter * 72394b701cSMatt Porter * Reads the base/extended device id from the local device 73394b701cSMatt Porter * implementing the master port. Returns the 8/16-bit device 74394b701cSMatt Porter * id. 75394b701cSMatt Porter */ 76394b701cSMatt Porter u16 rio_local_get_device_id(struct rio_mport *port) 77394b701cSMatt Porter { 78394b701cSMatt Porter u32 result; 79394b701cSMatt Porter 80394b701cSMatt Porter rio_local_read_config_32(port, RIO_DID_CSR, &result); 81394b701cSMatt Porter 82e0423236SZhang Wei return (RIO_GET_DID(port->sys_size, result)); 83394b701cSMatt Porter } 84394b701cSMatt Porter 85394b701cSMatt Porter /** 868b189fdbSAlexandre Bounine * rio_query_mport - Query mport device attributes 878b189fdbSAlexandre Bounine * @port: mport device to query 888b189fdbSAlexandre Bounine * @mport_attr: mport attributes data structure 898b189fdbSAlexandre Bounine * 908b189fdbSAlexandre Bounine * Returns attributes of specified mport through the 918b189fdbSAlexandre Bounine * pointer to attributes data structure. 928b189fdbSAlexandre Bounine */ 938b189fdbSAlexandre Bounine int rio_query_mport(struct rio_mport *port, 948b189fdbSAlexandre Bounine struct rio_mport_attr *mport_attr) 958b189fdbSAlexandre Bounine { 968b189fdbSAlexandre Bounine if (!port->ops->query_mport) 978b189fdbSAlexandre Bounine return -ENODATA; 988b189fdbSAlexandre Bounine return port->ops->query_mport(port, mport_attr); 998b189fdbSAlexandre Bounine } 1008b189fdbSAlexandre Bounine EXPORT_SYMBOL(rio_query_mport); 1018b189fdbSAlexandre Bounine 1028b189fdbSAlexandre Bounine /** 103e6b585caSAlexandre Bounine * rio_alloc_net- Allocate and initialize a new RIO network data structure 104e6b585caSAlexandre Bounine * @mport: Master port associated with the RIO network 105e6b585caSAlexandre Bounine * 106e6b585caSAlexandre Bounine * Allocates a RIO network structure, initializes per-network 107e6b585caSAlexandre Bounine * list heads, and adds the associated master port to the 108e6b585caSAlexandre Bounine * network list of associated master ports. Returns a 109e6b585caSAlexandre Bounine * RIO network pointer on success or %NULL on failure. 110e6b585caSAlexandre Bounine */ 111e6b585caSAlexandre Bounine struct rio_net *rio_alloc_net(struct rio_mport *mport) 112e6b585caSAlexandre Bounine { 113d1509c09SMarkus Elfring struct rio_net *net = kzalloc(sizeof(*net), GFP_KERNEL); 114e6b585caSAlexandre Bounine 115e6b585caSAlexandre Bounine if (net) { 116e6b585caSAlexandre Bounine INIT_LIST_HEAD(&net->node); 117e6b585caSAlexandre Bounine INIT_LIST_HEAD(&net->devices); 118e6b585caSAlexandre Bounine INIT_LIST_HEAD(&net->switches); 119e6b585caSAlexandre Bounine INIT_LIST_HEAD(&net->mports); 120e6b585caSAlexandre Bounine mport->net = net; 121e6b585caSAlexandre Bounine } 122e6b585caSAlexandre Bounine return net; 123e6b585caSAlexandre Bounine } 124e6b585caSAlexandre Bounine EXPORT_SYMBOL_GPL(rio_alloc_net); 125e6b585caSAlexandre Bounine 126e6b585caSAlexandre Bounine int rio_add_net(struct rio_net *net) 127e6b585caSAlexandre Bounine { 128e6b585caSAlexandre Bounine int err; 129e6b585caSAlexandre Bounine 130e6b585caSAlexandre Bounine err = device_register(&net->dev); 131e6b585caSAlexandre Bounine if (err) 132e6b585caSAlexandre Bounine return err; 133e6b585caSAlexandre Bounine spin_lock(&rio_global_list_lock); 134e6b585caSAlexandre Bounine list_add_tail(&net->node, &rio_nets); 135e6b585caSAlexandre Bounine spin_unlock(&rio_global_list_lock); 136e6b585caSAlexandre Bounine 137e6b585caSAlexandre Bounine return 0; 138e6b585caSAlexandre Bounine } 139e6b585caSAlexandre Bounine EXPORT_SYMBOL_GPL(rio_add_net); 140e6b585caSAlexandre Bounine 141e6b585caSAlexandre Bounine void rio_free_net(struct rio_net *net) 142e6b585caSAlexandre Bounine { 143e6b585caSAlexandre Bounine spin_lock(&rio_global_list_lock); 144e6b585caSAlexandre Bounine if (!list_empty(&net->node)) 145e6b585caSAlexandre Bounine list_del(&net->node); 146e6b585caSAlexandre Bounine spin_unlock(&rio_global_list_lock); 147e6b585caSAlexandre Bounine if (net->release) 148e6b585caSAlexandre Bounine net->release(net); 149e6b585caSAlexandre Bounine device_unregister(&net->dev); 150e6b585caSAlexandre Bounine } 151e6b585caSAlexandre Bounine EXPORT_SYMBOL_GPL(rio_free_net); 152e6b585caSAlexandre Bounine 153e6b585caSAlexandre Bounine /** 1545024622fSAlexandre Bounine * rio_local_set_device_id - Set the base/extended device id for a port 1555024622fSAlexandre Bounine * @port: RIO master port 1565024622fSAlexandre Bounine * @did: Device ID value to be written 1575024622fSAlexandre Bounine * 1585024622fSAlexandre Bounine * Writes the base/extended device id from a device. 1595024622fSAlexandre Bounine */ 1605024622fSAlexandre Bounine void rio_local_set_device_id(struct rio_mport *port, u16 did) 1615024622fSAlexandre Bounine { 1625024622fSAlexandre Bounine rio_local_write_config_32(port, RIO_DID_CSR, 1635024622fSAlexandre Bounine RIO_SET_DID(port->sys_size, did)); 1645024622fSAlexandre Bounine } 1655024622fSAlexandre Bounine EXPORT_SYMBOL_GPL(rio_local_set_device_id); 1665024622fSAlexandre Bounine 1675024622fSAlexandre Bounine /** 168a11650e1SAlexandre Bounine * rio_add_device- Adds a RIO device to the device model 169a11650e1SAlexandre Bounine * @rdev: RIO device 170a11650e1SAlexandre Bounine * 171a11650e1SAlexandre Bounine * Adds the RIO device to the global device list and adds the RIO 172a11650e1SAlexandre Bounine * device to the RIO device list. Creates the generic sysfs nodes 173a11650e1SAlexandre Bounine * for an RIO device. 174a11650e1SAlexandre Bounine */ 175a11650e1SAlexandre Bounine int rio_add_device(struct rio_dev *rdev) 176a11650e1SAlexandre Bounine { 177a11650e1SAlexandre Bounine int err; 178a11650e1SAlexandre Bounine 179b77a2030SAlexandre Bounine atomic_set(&rdev->state, RIO_DEVICE_RUNNING); 180b74ec56eSAlexandre Bounine err = device_register(&rdev->dev); 181a11650e1SAlexandre Bounine if (err) 182a11650e1SAlexandre Bounine return err; 183a11650e1SAlexandre Bounine 184a11650e1SAlexandre Bounine spin_lock(&rio_global_list_lock); 185a11650e1SAlexandre Bounine list_add_tail(&rdev->global_list, &rio_devices); 186b74ec56eSAlexandre Bounine if (rdev->net) { 187b74ec56eSAlexandre Bounine list_add_tail(&rdev->net_list, &rdev->net->devices); 188b74ec56eSAlexandre Bounine if (rdev->pef & RIO_PEF_SWITCH) 189b74ec56eSAlexandre Bounine list_add_tail(&rdev->rswitch->node, 190b74ec56eSAlexandre Bounine &rdev->net->switches); 191b74ec56eSAlexandre Bounine } 192a11650e1SAlexandre Bounine spin_unlock(&rio_global_list_lock); 193a11650e1SAlexandre Bounine 194a11650e1SAlexandre Bounine return 0; 195a11650e1SAlexandre Bounine } 196a11650e1SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_add_device); 197a11650e1SAlexandre Bounine 198b74ec56eSAlexandre Bounine /* 199b74ec56eSAlexandre Bounine * rio_del_device - removes a RIO device from the device model 200b74ec56eSAlexandre Bounine * @rdev: RIO device 201b77a2030SAlexandre Bounine * @state: device state to set during removal process 202b74ec56eSAlexandre Bounine * 203b74ec56eSAlexandre Bounine * Removes the RIO device to the kernel device list and subsystem's device list. 204b74ec56eSAlexandre Bounine * Clears sysfs entries for the removed device. 205b74ec56eSAlexandre Bounine */ 206b77a2030SAlexandre Bounine void rio_del_device(struct rio_dev *rdev, enum rio_device_state state) 207b74ec56eSAlexandre Bounine { 208b74ec56eSAlexandre Bounine pr_debug("RIO: %s: removing %s\n", __func__, rio_name(rdev)); 209b77a2030SAlexandre Bounine atomic_set(&rdev->state, state); 210b74ec56eSAlexandre Bounine spin_lock(&rio_global_list_lock); 211b74ec56eSAlexandre Bounine list_del(&rdev->global_list); 212b74ec56eSAlexandre Bounine if (rdev->net) { 213b74ec56eSAlexandre Bounine list_del(&rdev->net_list); 214b74ec56eSAlexandre Bounine if (rdev->pef & RIO_PEF_SWITCH) { 215b74ec56eSAlexandre Bounine list_del(&rdev->rswitch->node); 216b74ec56eSAlexandre Bounine kfree(rdev->rswitch->route_table); 217b74ec56eSAlexandre Bounine } 218b74ec56eSAlexandre Bounine } 219b74ec56eSAlexandre Bounine spin_unlock(&rio_global_list_lock); 220b74ec56eSAlexandre Bounine device_unregister(&rdev->dev); 221b74ec56eSAlexandre Bounine } 222b74ec56eSAlexandre Bounine EXPORT_SYMBOL_GPL(rio_del_device); 223b74ec56eSAlexandre Bounine 224a11650e1SAlexandre Bounine /** 225394b701cSMatt Porter * rio_request_inb_mbox - request inbound mailbox service 226394b701cSMatt Porter * @mport: RIO master port from which to allocate the mailbox resource 2276978bbc0SMatt Porter * @dev_id: Device specific pointer to pass on event 228394b701cSMatt Porter * @mbox: Mailbox number to claim 229394b701cSMatt Porter * @entries: Number of entries in inbound mailbox queue 230394b701cSMatt Porter * @minb: Callback to execute when inbound message is received 231394b701cSMatt Porter * 232394b701cSMatt Porter * Requests ownership of an inbound mailbox resource and binds 233394b701cSMatt Porter * a callback function to the resource. Returns %0 on success. 234394b701cSMatt Porter */ 235394b701cSMatt Porter int rio_request_inb_mbox(struct rio_mport *mport, 2366978bbc0SMatt Porter void *dev_id, 237394b701cSMatt Porter int mbox, 238394b701cSMatt Porter int entries, 2396978bbc0SMatt Porter void (*minb) (struct rio_mport * mport, void *dev_id, int mbox, 240394b701cSMatt Porter int slot)) 241394b701cSMatt Porter { 242f8f06269SAlexandre Bounine int rc = -ENOSYS; 243f8f06269SAlexandre Bounine struct resource *res; 244394b701cSMatt Porter 24593dd49afSMarkus Elfring if (!mport->ops->open_inb_mbox) 246f8f06269SAlexandre Bounine goto out; 247f8f06269SAlexandre Bounine 248d1509c09SMarkus Elfring res = kzalloc(sizeof(*res), GFP_KERNEL); 249394b701cSMatt Porter if (res) { 250394b701cSMatt Porter rio_init_mbox_res(res, mbox, mbox); 251394b701cSMatt Porter 252394b701cSMatt Porter /* Make sure this mailbox isn't in use */ 253e1d66d04SMarkus Elfring rc = request_resource(&mport->riores[RIO_INB_MBOX_RESOURCE], 254e1d66d04SMarkus Elfring res); 255e1d66d04SMarkus Elfring if (rc < 0) { 256394b701cSMatt Porter kfree(res); 257394b701cSMatt Porter goto out; 258394b701cSMatt Porter } 259394b701cSMatt Porter 260394b701cSMatt Porter mport->inb_msg[mbox].res = res; 261394b701cSMatt Porter 262394b701cSMatt Porter /* Hook the inbound message callback */ 263394b701cSMatt Porter mport->inb_msg[mbox].mcback = minb; 264394b701cSMatt Porter 265f8f06269SAlexandre Bounine rc = mport->ops->open_inb_mbox(mport, dev_id, mbox, entries); 26606e1b249SAlexandre Bounine if (rc) { 26706e1b249SAlexandre Bounine mport->inb_msg[mbox].mcback = NULL; 26806e1b249SAlexandre Bounine mport->inb_msg[mbox].res = NULL; 26906e1b249SAlexandre Bounine release_resource(res); 27006e1b249SAlexandre Bounine kfree(res); 27106e1b249SAlexandre Bounine } 272394b701cSMatt Porter } else 273394b701cSMatt Porter rc = -ENOMEM; 274394b701cSMatt Porter 275394b701cSMatt Porter out: 276394b701cSMatt Porter return rc; 277394b701cSMatt Porter } 278394b701cSMatt Porter 279394b701cSMatt Porter /** 280394b701cSMatt Porter * rio_release_inb_mbox - release inbound mailbox message service 281394b701cSMatt Porter * @mport: RIO master port from which to release the mailbox resource 282394b701cSMatt Porter * @mbox: Mailbox number to release 283394b701cSMatt Porter * 284394b701cSMatt Porter * Releases ownership of an inbound mailbox resource. Returns 0 285394b701cSMatt Porter * if the request has been satisfied. 286394b701cSMatt Porter */ 287394b701cSMatt Porter int rio_release_inb_mbox(struct rio_mport *mport, int mbox) 288394b701cSMatt Porter { 28906e1b249SAlexandre Bounine int rc; 290394b701cSMatt Porter 29106e1b249SAlexandre Bounine if (!mport->ops->close_inb_mbox || !mport->inb_msg[mbox].res) 29206e1b249SAlexandre Bounine return -EINVAL; 29306e1b249SAlexandre Bounine 29406e1b249SAlexandre Bounine mport->ops->close_inb_mbox(mport, mbox); 29506e1b249SAlexandre Bounine mport->inb_msg[mbox].mcback = NULL; 29606e1b249SAlexandre Bounine 29706e1b249SAlexandre Bounine rc = release_resource(mport->inb_msg[mbox].res); 29806e1b249SAlexandre Bounine if (rc) 29906e1b249SAlexandre Bounine return rc; 30006e1b249SAlexandre Bounine 30106e1b249SAlexandre Bounine kfree(mport->inb_msg[mbox].res); 30206e1b249SAlexandre Bounine mport->inb_msg[mbox].res = NULL; 30306e1b249SAlexandre Bounine 30406e1b249SAlexandre Bounine return 0; 305394b701cSMatt Porter } 306394b701cSMatt Porter 307394b701cSMatt Porter /** 308394b701cSMatt Porter * rio_request_outb_mbox - request outbound mailbox service 309394b701cSMatt Porter * @mport: RIO master port from which to allocate the mailbox resource 3106978bbc0SMatt Porter * @dev_id: Device specific pointer to pass on event 311394b701cSMatt Porter * @mbox: Mailbox number to claim 312394b701cSMatt Porter * @entries: Number of entries in outbound mailbox queue 313394b701cSMatt Porter * @moutb: Callback to execute when outbound message is sent 314394b701cSMatt Porter * 315394b701cSMatt Porter * Requests ownership of an outbound mailbox resource and binds 316394b701cSMatt Porter * a callback function to the resource. Returns 0 on success. 317394b701cSMatt Porter */ 318394b701cSMatt Porter int rio_request_outb_mbox(struct rio_mport *mport, 3196978bbc0SMatt Porter void *dev_id, 320394b701cSMatt Porter int mbox, 321394b701cSMatt Porter int entries, 3226978bbc0SMatt Porter void (*moutb) (struct rio_mport * mport, void *dev_id, int mbox, int slot)) 323394b701cSMatt Porter { 324f8f06269SAlexandre Bounine int rc = -ENOSYS; 325f8f06269SAlexandre Bounine struct resource *res; 326394b701cSMatt Porter 32793dd49afSMarkus Elfring if (!mport->ops->open_outb_mbox) 328f8f06269SAlexandre Bounine goto out; 329f8f06269SAlexandre Bounine 330d1509c09SMarkus Elfring res = kzalloc(sizeof(*res), GFP_KERNEL); 331394b701cSMatt Porter if (res) { 332394b701cSMatt Porter rio_init_mbox_res(res, mbox, mbox); 333394b701cSMatt Porter 334394b701cSMatt Porter /* Make sure this outbound mailbox isn't in use */ 335e1d66d04SMarkus Elfring rc = request_resource(&mport->riores[RIO_OUTB_MBOX_RESOURCE], 336e1d66d04SMarkus Elfring res); 337e1d66d04SMarkus Elfring if (rc < 0) { 338394b701cSMatt Porter kfree(res); 339394b701cSMatt Porter goto out; 340394b701cSMatt Porter } 341394b701cSMatt Porter 342394b701cSMatt Porter mport->outb_msg[mbox].res = res; 343394b701cSMatt Porter 344394b701cSMatt Porter /* Hook the inbound message callback */ 345394b701cSMatt Porter mport->outb_msg[mbox].mcback = moutb; 346394b701cSMatt Porter 347f8f06269SAlexandre Bounine rc = mport->ops->open_outb_mbox(mport, dev_id, mbox, entries); 34806e1b249SAlexandre Bounine if (rc) { 34906e1b249SAlexandre Bounine mport->outb_msg[mbox].mcback = NULL; 35006e1b249SAlexandre Bounine mport->outb_msg[mbox].res = NULL; 35106e1b249SAlexandre Bounine release_resource(res); 35206e1b249SAlexandre Bounine kfree(res); 35306e1b249SAlexandre Bounine } 354394b701cSMatt Porter } else 355394b701cSMatt Porter rc = -ENOMEM; 356394b701cSMatt Porter 357394b701cSMatt Porter out: 358394b701cSMatt Porter return rc; 359394b701cSMatt Porter } 360394b701cSMatt Porter 361394b701cSMatt Porter /** 362394b701cSMatt Porter * rio_release_outb_mbox - release outbound mailbox message service 363394b701cSMatt Porter * @mport: RIO master port from which to release the mailbox resource 364394b701cSMatt Porter * @mbox: Mailbox number to release 365394b701cSMatt Porter * 366394b701cSMatt Porter * Releases ownership of an inbound mailbox resource. Returns 0 367394b701cSMatt Porter * if the request has been satisfied. 368394b701cSMatt Porter */ 369394b701cSMatt Porter int rio_release_outb_mbox(struct rio_mport *mport, int mbox) 370394b701cSMatt Porter { 37106e1b249SAlexandre Bounine int rc; 372394b701cSMatt Porter 37306e1b249SAlexandre Bounine if (!mport->ops->close_outb_mbox || !mport->outb_msg[mbox].res) 37406e1b249SAlexandre Bounine return -EINVAL; 37506e1b249SAlexandre Bounine 37606e1b249SAlexandre Bounine mport->ops->close_outb_mbox(mport, mbox); 37706e1b249SAlexandre Bounine mport->outb_msg[mbox].mcback = NULL; 37806e1b249SAlexandre Bounine 37906e1b249SAlexandre Bounine rc = release_resource(mport->outb_msg[mbox].res); 38006e1b249SAlexandre Bounine if (rc) 38106e1b249SAlexandre Bounine return rc; 38206e1b249SAlexandre Bounine 38306e1b249SAlexandre Bounine kfree(mport->outb_msg[mbox].res); 38406e1b249SAlexandre Bounine mport->outb_msg[mbox].res = NULL; 38506e1b249SAlexandre Bounine 38606e1b249SAlexandre Bounine return 0; 387394b701cSMatt Porter } 388394b701cSMatt Porter 389394b701cSMatt Porter /** 390394b701cSMatt Porter * rio_setup_inb_dbell - bind inbound doorbell callback 391394b701cSMatt Porter * @mport: RIO master port to bind the doorbell callback 3926978bbc0SMatt Porter * @dev_id: Device specific pointer to pass on event 393394b701cSMatt Porter * @res: Doorbell message resource 394394b701cSMatt Porter * @dinb: Callback to execute when doorbell is received 395394b701cSMatt Porter * 396394b701cSMatt Porter * Adds a doorbell resource/callback pair into a port's 397394b701cSMatt Porter * doorbell event list. Returns 0 if the request has been 398394b701cSMatt Porter * satisfied. 399394b701cSMatt Porter */ 400394b701cSMatt Porter static int 4016978bbc0SMatt Porter rio_setup_inb_dbell(struct rio_mport *mport, void *dev_id, struct resource *res, 4026978bbc0SMatt Porter void (*dinb) (struct rio_mport * mport, void *dev_id, u16 src, u16 dst, 403394b701cSMatt Porter u16 info)) 404394b701cSMatt Porter { 405394b701cSMatt Porter int rc = 0; 406e1d66d04SMarkus Elfring struct rio_dbell *dbell = kmalloc(sizeof(*dbell), GFP_KERNEL); 407394b701cSMatt Porter 408e1d66d04SMarkus Elfring if (!dbell) { 409394b701cSMatt Porter rc = -ENOMEM; 410394b701cSMatt Porter goto out; 411394b701cSMatt Porter } 412394b701cSMatt Porter 413394b701cSMatt Porter dbell->res = res; 414394b701cSMatt Porter dbell->dinb = dinb; 4156978bbc0SMatt Porter dbell->dev_id = dev_id; 416394b701cSMatt Porter 417a7b4c636SAlexandre Bounine mutex_lock(&mport->lock); 418394b701cSMatt Porter list_add_tail(&dbell->node, &mport->dbells); 419a7b4c636SAlexandre Bounine mutex_unlock(&mport->lock); 420394b701cSMatt Porter 421394b701cSMatt Porter out: 422394b701cSMatt Porter return rc; 423394b701cSMatt Porter } 424394b701cSMatt Porter 425394b701cSMatt Porter /** 426394b701cSMatt Porter * rio_request_inb_dbell - request inbound doorbell message service 427394b701cSMatt Porter * @mport: RIO master port from which to allocate the doorbell resource 4286978bbc0SMatt Porter * @dev_id: Device specific pointer to pass on event 429394b701cSMatt Porter * @start: Doorbell info range start 430394b701cSMatt Porter * @end: Doorbell info range end 431394b701cSMatt Porter * @dinb: Callback to execute when doorbell is received 432394b701cSMatt Porter * 433394b701cSMatt Porter * Requests ownership of an inbound doorbell resource and binds 434394b701cSMatt Porter * a callback function to the resource. Returns 0 if the request 435394b701cSMatt Porter * has been satisfied. 436394b701cSMatt Porter */ 437394b701cSMatt Porter int rio_request_inb_dbell(struct rio_mport *mport, 4386978bbc0SMatt Porter void *dev_id, 439394b701cSMatt Porter u16 start, 440394b701cSMatt Porter u16 end, 4416978bbc0SMatt Porter void (*dinb) (struct rio_mport * mport, void *dev_id, u16 src, 442394b701cSMatt Porter u16 dst, u16 info)) 443394b701cSMatt Porter { 444394b701cSMatt Porter int rc = 0; 445d1509c09SMarkus Elfring struct resource *res = kzalloc(sizeof(*res), GFP_KERNEL); 446394b701cSMatt Porter 447394b701cSMatt Porter if (res) { 448394b701cSMatt Porter rio_init_dbell_res(res, start, end); 449394b701cSMatt Porter 450394b701cSMatt Porter /* Make sure these doorbells aren't in use */ 451e1d66d04SMarkus Elfring rc = request_resource(&mport->riores[RIO_DOORBELL_RESOURCE], 452e1d66d04SMarkus Elfring res); 453e1d66d04SMarkus Elfring if (rc < 0) { 454394b701cSMatt Porter kfree(res); 455394b701cSMatt Porter goto out; 456394b701cSMatt Porter } 457394b701cSMatt Porter 458394b701cSMatt Porter /* Hook the doorbell callback */ 4596978bbc0SMatt Porter rc = rio_setup_inb_dbell(mport, dev_id, res, dinb); 460394b701cSMatt Porter } else 461394b701cSMatt Porter rc = -ENOMEM; 462394b701cSMatt Porter 463394b701cSMatt Porter out: 464394b701cSMatt Porter return rc; 465394b701cSMatt Porter } 466394b701cSMatt Porter 467394b701cSMatt Porter /** 468394b701cSMatt Porter * rio_release_inb_dbell - release inbound doorbell message service 469394b701cSMatt Porter * @mport: RIO master port from which to release the doorbell resource 470394b701cSMatt Porter * @start: Doorbell info range start 471394b701cSMatt Porter * @end: Doorbell info range end 472394b701cSMatt Porter * 473394b701cSMatt Porter * Releases ownership of an inbound doorbell resource and removes 474394b701cSMatt Porter * callback from the doorbell event list. Returns 0 if the request 475394b701cSMatt Porter * has been satisfied. 476394b701cSMatt Porter */ 477394b701cSMatt Porter int rio_release_inb_dbell(struct rio_mport *mport, u16 start, u16 end) 478394b701cSMatt Porter { 479394b701cSMatt Porter int rc = 0, found = 0; 480394b701cSMatt Porter struct rio_dbell *dbell; 481394b701cSMatt Porter 482a7b4c636SAlexandre Bounine mutex_lock(&mport->lock); 483394b701cSMatt Porter list_for_each_entry(dbell, &mport->dbells, node) { 484394b701cSMatt Porter if ((dbell->res->start == start) && (dbell->res->end == end)) { 485a7b4c636SAlexandre Bounine list_del(&dbell->node); 486394b701cSMatt Porter found = 1; 487394b701cSMatt Porter break; 488394b701cSMatt Porter } 489394b701cSMatt Porter } 490a7b4c636SAlexandre Bounine mutex_unlock(&mport->lock); 491394b701cSMatt Porter 492394b701cSMatt Porter /* If we can't find an exact match, fail */ 493394b701cSMatt Porter if (!found) { 494394b701cSMatt Porter rc = -EINVAL; 495394b701cSMatt Porter goto out; 496394b701cSMatt Porter } 497394b701cSMatt Porter 498394b701cSMatt Porter /* Release the doorbell resource */ 499394b701cSMatt Porter rc = release_resource(dbell->res); 500394b701cSMatt Porter 501394b701cSMatt Porter /* Free the doorbell event */ 502394b701cSMatt Porter kfree(dbell); 503394b701cSMatt Porter 504394b701cSMatt Porter out: 505394b701cSMatt Porter return rc; 506394b701cSMatt Porter } 507394b701cSMatt Porter 508394b701cSMatt Porter /** 509394b701cSMatt Porter * rio_request_outb_dbell - request outbound doorbell message range 510394b701cSMatt Porter * @rdev: RIO device from which to allocate the doorbell resource 511394b701cSMatt Porter * @start: Doorbell message range start 512394b701cSMatt Porter * @end: Doorbell message range end 513394b701cSMatt Porter * 514394b701cSMatt Porter * Requests ownership of a doorbell message range. Returns a resource 515394b701cSMatt Porter * if the request has been satisfied or %NULL on failure. 516394b701cSMatt Porter */ 517394b701cSMatt Porter struct resource *rio_request_outb_dbell(struct rio_dev *rdev, u16 start, 518394b701cSMatt Porter u16 end) 519394b701cSMatt Porter { 5209a975beeSToshi Kani struct resource *res = kzalloc(sizeof(struct resource), GFP_KERNEL); 521394b701cSMatt Porter 522394b701cSMatt Porter if (res) { 523394b701cSMatt Porter rio_init_dbell_res(res, start, end); 524394b701cSMatt Porter 525394b701cSMatt Porter /* Make sure these doorbells aren't in use */ 526394b701cSMatt Porter if (request_resource(&rdev->riores[RIO_DOORBELL_RESOURCE], res) 527394b701cSMatt Porter < 0) { 528394b701cSMatt Porter kfree(res); 529394b701cSMatt Porter res = NULL; 530394b701cSMatt Porter } 531394b701cSMatt Porter } 532394b701cSMatt Porter 533394b701cSMatt Porter return res; 534394b701cSMatt Porter } 535394b701cSMatt Porter 536394b701cSMatt Porter /** 537394b701cSMatt Porter * rio_release_outb_dbell - release outbound doorbell message range 538394b701cSMatt Porter * @rdev: RIO device from which to release the doorbell resource 539394b701cSMatt Porter * @res: Doorbell resource to be freed 540394b701cSMatt Porter * 541394b701cSMatt Porter * Releases ownership of a doorbell message range. Returns 0 if the 542394b701cSMatt Porter * request has been satisfied. 543394b701cSMatt Porter */ 544394b701cSMatt Porter int rio_release_outb_dbell(struct rio_dev *rdev, struct resource *res) 545394b701cSMatt Porter { 546394b701cSMatt Porter int rc = release_resource(res); 547394b701cSMatt Porter 548394b701cSMatt Porter kfree(res); 549394b701cSMatt Porter 550394b701cSMatt Porter return rc; 551394b701cSMatt Porter } 552394b701cSMatt Porter 553394b701cSMatt Porter /** 5549a0b0627SAlexandre Bounine * rio_add_mport_pw_handler - add port-write message handler into the list 5559a0b0627SAlexandre Bounine * of mport specific pw handlers 5569a0b0627SAlexandre Bounine * @mport: RIO master port to bind the portwrite callback 5579a0b0627SAlexandre Bounine * @context: Handler specific context to pass on event 5589a0b0627SAlexandre Bounine * @pwcback: Callback to execute when portwrite is received 5599a0b0627SAlexandre Bounine * 5609a0b0627SAlexandre Bounine * Returns 0 if the request has been satisfied. 5619a0b0627SAlexandre Bounine */ 5629a0b0627SAlexandre Bounine int rio_add_mport_pw_handler(struct rio_mport *mport, void *context, 5639a0b0627SAlexandre Bounine int (*pwcback)(struct rio_mport *mport, 5649a0b0627SAlexandre Bounine void *context, union rio_pw_msg *msg, int step)) 5659a0b0627SAlexandre Bounine { 5669a0b0627SAlexandre Bounine int rc = 0; 567d1509c09SMarkus Elfring struct rio_pwrite *pwrite = kzalloc(sizeof(*pwrite), GFP_KERNEL); 5689a0b0627SAlexandre Bounine 5699a0b0627SAlexandre Bounine if (!pwrite) { 5709a0b0627SAlexandre Bounine rc = -ENOMEM; 5719a0b0627SAlexandre Bounine goto out; 5729a0b0627SAlexandre Bounine } 5739a0b0627SAlexandre Bounine 5749a0b0627SAlexandre Bounine pwrite->pwcback = pwcback; 5759a0b0627SAlexandre Bounine pwrite->context = context; 5769a0b0627SAlexandre Bounine mutex_lock(&mport->lock); 5779a0b0627SAlexandre Bounine list_add_tail(&pwrite->node, &mport->pwrites); 5789a0b0627SAlexandre Bounine mutex_unlock(&mport->lock); 5799a0b0627SAlexandre Bounine out: 5809a0b0627SAlexandre Bounine return rc; 5819a0b0627SAlexandre Bounine } 5829a0b0627SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_add_mport_pw_handler); 5839a0b0627SAlexandre Bounine 5849a0b0627SAlexandre Bounine /** 5859a0b0627SAlexandre Bounine * rio_del_mport_pw_handler - remove port-write message handler from the list 5869a0b0627SAlexandre Bounine * of mport specific pw handlers 5879a0b0627SAlexandre Bounine * @mport: RIO master port to bind the portwrite callback 5889a0b0627SAlexandre Bounine * @context: Registered handler specific context to pass on event 5899a0b0627SAlexandre Bounine * @pwcback: Registered callback function 5909a0b0627SAlexandre Bounine * 5919a0b0627SAlexandre Bounine * Returns 0 if the request has been satisfied. 5929a0b0627SAlexandre Bounine */ 5939a0b0627SAlexandre Bounine int rio_del_mport_pw_handler(struct rio_mport *mport, void *context, 5949a0b0627SAlexandre Bounine int (*pwcback)(struct rio_mport *mport, 5959a0b0627SAlexandre Bounine void *context, union rio_pw_msg *msg, int step)) 5969a0b0627SAlexandre Bounine { 5979a0b0627SAlexandre Bounine int rc = -EINVAL; 5989a0b0627SAlexandre Bounine struct rio_pwrite *pwrite; 5999a0b0627SAlexandre Bounine 6009a0b0627SAlexandre Bounine mutex_lock(&mport->lock); 6019a0b0627SAlexandre Bounine list_for_each_entry(pwrite, &mport->pwrites, node) { 6029a0b0627SAlexandre Bounine if (pwrite->pwcback == pwcback && pwrite->context == context) { 6039a0b0627SAlexandre Bounine list_del(&pwrite->node); 6049a0b0627SAlexandre Bounine kfree(pwrite); 6059a0b0627SAlexandre Bounine rc = 0; 6069a0b0627SAlexandre Bounine break; 6079a0b0627SAlexandre Bounine } 6089a0b0627SAlexandre Bounine } 6099a0b0627SAlexandre Bounine mutex_unlock(&mport->lock); 6109a0b0627SAlexandre Bounine 6119a0b0627SAlexandre Bounine return rc; 6129a0b0627SAlexandre Bounine } 6139a0b0627SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_del_mport_pw_handler); 6149a0b0627SAlexandre Bounine 6159a0b0627SAlexandre Bounine /** 6169a0b0627SAlexandre Bounine * rio_request_inb_pwrite - request inbound port-write message service for 6179a0b0627SAlexandre Bounine * specific RapidIO device 61897ef6f74SRandy Dunlap * @rdev: RIO device to which register inbound port-write callback routine 619e5cabeb3SAlexandre Bounine * @pwcback: Callback routine to execute when port-write is received 620e5cabeb3SAlexandre Bounine * 621e5cabeb3SAlexandre Bounine * Binds a port-write callback function to the RapidIO device. 622e5cabeb3SAlexandre Bounine * Returns 0 if the request has been satisfied. 623e5cabeb3SAlexandre Bounine */ 624e5cabeb3SAlexandre Bounine int rio_request_inb_pwrite(struct rio_dev *rdev, 625e5cabeb3SAlexandre Bounine int (*pwcback)(struct rio_dev *rdev, union rio_pw_msg *msg, int step)) 626e5cabeb3SAlexandre Bounine { 627e5cabeb3SAlexandre Bounine int rc = 0; 628e5cabeb3SAlexandre Bounine 629e5cabeb3SAlexandre Bounine spin_lock(&rio_global_list_lock); 63093dd49afSMarkus Elfring if (rdev->pwcback) 631e5cabeb3SAlexandre Bounine rc = -ENOMEM; 632e5cabeb3SAlexandre Bounine else 633e5cabeb3SAlexandre Bounine rdev->pwcback = pwcback; 634e5cabeb3SAlexandre Bounine 635e5cabeb3SAlexandre Bounine spin_unlock(&rio_global_list_lock); 636e5cabeb3SAlexandre Bounine return rc; 637e5cabeb3SAlexandre Bounine } 638e5cabeb3SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_request_inb_pwrite); 639e5cabeb3SAlexandre Bounine 640e5cabeb3SAlexandre Bounine /** 641e5cabeb3SAlexandre Bounine * rio_release_inb_pwrite - release inbound port-write message service 6429a0b0627SAlexandre Bounine * associated with specific RapidIO device 643e5cabeb3SAlexandre Bounine * @rdev: RIO device which registered for inbound port-write callback 644e5cabeb3SAlexandre Bounine * 645e5cabeb3SAlexandre Bounine * Removes callback from the rio_dev structure. Returns 0 if the request 646e5cabeb3SAlexandre Bounine * has been satisfied. 647e5cabeb3SAlexandre Bounine */ 648e5cabeb3SAlexandre Bounine int rio_release_inb_pwrite(struct rio_dev *rdev) 649e5cabeb3SAlexandre Bounine { 650e5cabeb3SAlexandre Bounine int rc = -ENOMEM; 651e5cabeb3SAlexandre Bounine 652e5cabeb3SAlexandre Bounine spin_lock(&rio_global_list_lock); 653e5cabeb3SAlexandre Bounine if (rdev->pwcback) { 654e5cabeb3SAlexandre Bounine rdev->pwcback = NULL; 655e5cabeb3SAlexandre Bounine rc = 0; 656e5cabeb3SAlexandre Bounine } 657e5cabeb3SAlexandre Bounine 658e5cabeb3SAlexandre Bounine spin_unlock(&rio_global_list_lock); 659e5cabeb3SAlexandre Bounine return rc; 660e5cabeb3SAlexandre Bounine } 661e5cabeb3SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_release_inb_pwrite); 662e5cabeb3SAlexandre Bounine 663e5cabeb3SAlexandre Bounine /** 664b6cb95e8SAlexandre Bounine * rio_pw_enable - Enables/disables port-write handling by a master port 665b6cb95e8SAlexandre Bounine * @mport: Master port associated with port-write handling 666b6cb95e8SAlexandre Bounine * @enable: 1=enable, 0=disable 667b6cb95e8SAlexandre Bounine */ 668b6cb95e8SAlexandre Bounine void rio_pw_enable(struct rio_mport *mport, int enable) 669b6cb95e8SAlexandre Bounine { 670b6cb95e8SAlexandre Bounine if (mport->ops->pwenable) { 671b6cb95e8SAlexandre Bounine mutex_lock(&mport->lock); 672b6cb95e8SAlexandre Bounine 673b6cb95e8SAlexandre Bounine if ((enable && ++mport->pwe_refcnt == 1) || 674b6cb95e8SAlexandre Bounine (!enable && mport->pwe_refcnt && --mport->pwe_refcnt == 0)) 675b6cb95e8SAlexandre Bounine mport->ops->pwenable(mport, enable); 676b6cb95e8SAlexandre Bounine mutex_unlock(&mport->lock); 677b6cb95e8SAlexandre Bounine } 678b6cb95e8SAlexandre Bounine } 679b6cb95e8SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_pw_enable); 680b6cb95e8SAlexandre Bounine 681b6cb95e8SAlexandre Bounine /** 682da1589f0SAlexandre Bounine * rio_map_inb_region -- Map inbound memory region. 683da1589f0SAlexandre Bounine * @mport: Master port. 6842ca3cb50SRandy Dunlap * @local: physical address of memory region to be mapped 685da1589f0SAlexandre Bounine * @rbase: RIO base address assigned to this window 686da1589f0SAlexandre Bounine * @size: Size of the memory region 687da1589f0SAlexandre Bounine * @rflags: Flags for mapping. 688da1589f0SAlexandre Bounine * 689da1589f0SAlexandre Bounine * Return: 0 -- Success. 690da1589f0SAlexandre Bounine * 691da1589f0SAlexandre Bounine * This function will create the mapping from RIO space to local memory. 692da1589f0SAlexandre Bounine */ 693da1589f0SAlexandre Bounine int rio_map_inb_region(struct rio_mport *mport, dma_addr_t local, 694da1589f0SAlexandre Bounine u64 rbase, u32 size, u32 rflags) 695da1589f0SAlexandre Bounine { 696da1589f0SAlexandre Bounine int rc = 0; 697da1589f0SAlexandre Bounine unsigned long flags; 698da1589f0SAlexandre Bounine 699da1589f0SAlexandre Bounine if (!mport->ops->map_inb) 700da1589f0SAlexandre Bounine return -1; 701da1589f0SAlexandre Bounine spin_lock_irqsave(&rio_mmap_lock, flags); 702da1589f0SAlexandre Bounine rc = mport->ops->map_inb(mport, local, rbase, size, rflags); 703da1589f0SAlexandre Bounine spin_unlock_irqrestore(&rio_mmap_lock, flags); 704da1589f0SAlexandre Bounine return rc; 705da1589f0SAlexandre Bounine } 706da1589f0SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_map_inb_region); 707da1589f0SAlexandre Bounine 708da1589f0SAlexandre Bounine /** 709da1589f0SAlexandre Bounine * rio_unmap_inb_region -- Unmap the inbound memory region 710da1589f0SAlexandre Bounine * @mport: Master port 711da1589f0SAlexandre Bounine * @lstart: physical address of memory region to be unmapped 712da1589f0SAlexandre Bounine */ 713da1589f0SAlexandre Bounine void rio_unmap_inb_region(struct rio_mport *mport, dma_addr_t lstart) 714da1589f0SAlexandre Bounine { 715da1589f0SAlexandre Bounine unsigned long flags; 716da1589f0SAlexandre Bounine if (!mport->ops->unmap_inb) 717da1589f0SAlexandre Bounine return; 718da1589f0SAlexandre Bounine spin_lock_irqsave(&rio_mmap_lock, flags); 719da1589f0SAlexandre Bounine mport->ops->unmap_inb(mport, lstart); 720da1589f0SAlexandre Bounine spin_unlock_irqrestore(&rio_mmap_lock, flags); 721da1589f0SAlexandre Bounine } 722da1589f0SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_unmap_inb_region); 723da1589f0SAlexandre Bounine 724da1589f0SAlexandre Bounine /** 72593bdaca5SAlexandre Bounine * rio_map_outb_region -- Map outbound memory region. 72693bdaca5SAlexandre Bounine * @mport: Master port. 72793bdaca5SAlexandre Bounine * @destid: destination id window points to 72893bdaca5SAlexandre Bounine * @rbase: RIO base address window translates to 72993bdaca5SAlexandre Bounine * @size: Size of the memory region 73093bdaca5SAlexandre Bounine * @rflags: Flags for mapping. 73193bdaca5SAlexandre Bounine * @local: physical address of memory region mapped 73293bdaca5SAlexandre Bounine * 73393bdaca5SAlexandre Bounine * Return: 0 -- Success. 73493bdaca5SAlexandre Bounine * 73593bdaca5SAlexandre Bounine * This function will create the mapping from RIO space to local memory. 73693bdaca5SAlexandre Bounine */ 73793bdaca5SAlexandre Bounine int rio_map_outb_region(struct rio_mport *mport, u16 destid, u64 rbase, 73893bdaca5SAlexandre Bounine u32 size, u32 rflags, dma_addr_t *local) 73993bdaca5SAlexandre Bounine { 74093bdaca5SAlexandre Bounine int rc = 0; 74193bdaca5SAlexandre Bounine unsigned long flags; 74293bdaca5SAlexandre Bounine 74393bdaca5SAlexandre Bounine if (!mport->ops->map_outb) 74493bdaca5SAlexandre Bounine return -ENODEV; 74593bdaca5SAlexandre Bounine 74693bdaca5SAlexandre Bounine spin_lock_irqsave(&rio_mmap_lock, flags); 74793bdaca5SAlexandre Bounine rc = mport->ops->map_outb(mport, destid, rbase, size, 74893bdaca5SAlexandre Bounine rflags, local); 74993bdaca5SAlexandre Bounine spin_unlock_irqrestore(&rio_mmap_lock, flags); 75093bdaca5SAlexandre Bounine 75193bdaca5SAlexandre Bounine return rc; 75293bdaca5SAlexandre Bounine } 75393bdaca5SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_map_outb_region); 75493bdaca5SAlexandre Bounine 75593bdaca5SAlexandre Bounine /** 75693bdaca5SAlexandre Bounine * rio_unmap_inb_region -- Unmap the inbound memory region 75793bdaca5SAlexandre Bounine * @mport: Master port 75893bdaca5SAlexandre Bounine * @destid: destination id mapping points to 75993bdaca5SAlexandre Bounine * @rstart: RIO base address window translates to 76093bdaca5SAlexandre Bounine */ 76193bdaca5SAlexandre Bounine void rio_unmap_outb_region(struct rio_mport *mport, u16 destid, u64 rstart) 76293bdaca5SAlexandre Bounine { 76393bdaca5SAlexandre Bounine unsigned long flags; 76493bdaca5SAlexandre Bounine 76593bdaca5SAlexandre Bounine if (!mport->ops->unmap_outb) 76693bdaca5SAlexandre Bounine return; 76793bdaca5SAlexandre Bounine 76893bdaca5SAlexandre Bounine spin_lock_irqsave(&rio_mmap_lock, flags); 76993bdaca5SAlexandre Bounine mport->ops->unmap_outb(mport, destid, rstart); 77093bdaca5SAlexandre Bounine spin_unlock_irqrestore(&rio_mmap_lock, flags); 77193bdaca5SAlexandre Bounine } 77293bdaca5SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_unmap_outb_region); 77393bdaca5SAlexandre Bounine 77493bdaca5SAlexandre Bounine /** 775e5cabeb3SAlexandre Bounine * rio_mport_get_physefb - Helper function that returns register offset 776e5cabeb3SAlexandre Bounine * for Physical Layer Extended Features Block. 77797ef6f74SRandy Dunlap * @port: Master port to issue transaction 77897ef6f74SRandy Dunlap * @local: Indicate a local master port or remote device access 77997ef6f74SRandy Dunlap * @destid: Destination ID of the device 78097ef6f74SRandy Dunlap * @hopcount: Number of switch hops to the device 7811ae842deSAlexandre Bounine * @rmap: pointer to location to store register map type info 782e5cabeb3SAlexandre Bounine */ 783e5cabeb3SAlexandre Bounine u32 784e5cabeb3SAlexandre Bounine rio_mport_get_physefb(struct rio_mport *port, int local, 7851ae842deSAlexandre Bounine u16 destid, u8 hopcount, u32 *rmap) 786e5cabeb3SAlexandre Bounine { 787e5cabeb3SAlexandre Bounine u32 ext_ftr_ptr; 788e5cabeb3SAlexandre Bounine u32 ftr_header; 789e5cabeb3SAlexandre Bounine 790e5cabeb3SAlexandre Bounine ext_ftr_ptr = rio_mport_get_efb(port, local, destid, hopcount, 0); 791e5cabeb3SAlexandre Bounine 792e5cabeb3SAlexandre Bounine while (ext_ftr_ptr) { 793e5cabeb3SAlexandre Bounine if (local) 794e5cabeb3SAlexandre Bounine rio_local_read_config_32(port, ext_ftr_ptr, 795e5cabeb3SAlexandre Bounine &ftr_header); 796e5cabeb3SAlexandre Bounine else 797e5cabeb3SAlexandre Bounine rio_mport_read_config_32(port, destid, hopcount, 798e5cabeb3SAlexandre Bounine ext_ftr_ptr, &ftr_header); 799e5cabeb3SAlexandre Bounine 800e5cabeb3SAlexandre Bounine ftr_header = RIO_GET_BLOCK_ID(ftr_header); 801e5cabeb3SAlexandre Bounine switch (ftr_header) { 802e5cabeb3SAlexandre Bounine 803e5cabeb3SAlexandre Bounine case RIO_EFB_SER_EP_ID: 804e5cabeb3SAlexandre Bounine case RIO_EFB_SER_EP_REC_ID: 805e5cabeb3SAlexandre Bounine case RIO_EFB_SER_EP_FREE_ID: 8061ae842deSAlexandre Bounine case RIO_EFB_SER_EP_M1_ID: 8071ae842deSAlexandre Bounine case RIO_EFB_SER_EP_SW_M1_ID: 8081ae842deSAlexandre Bounine case RIO_EFB_SER_EPF_M1_ID: 8091ae842deSAlexandre Bounine case RIO_EFB_SER_EPF_SW_M1_ID: 8101ae842deSAlexandre Bounine *rmap = 1; 8111ae842deSAlexandre Bounine return ext_ftr_ptr; 812e5cabeb3SAlexandre Bounine 8131ae842deSAlexandre Bounine case RIO_EFB_SER_EP_M2_ID: 8141ae842deSAlexandre Bounine case RIO_EFB_SER_EP_SW_M2_ID: 8151ae842deSAlexandre Bounine case RIO_EFB_SER_EPF_M2_ID: 8161ae842deSAlexandre Bounine case RIO_EFB_SER_EPF_SW_M2_ID: 8171ae842deSAlexandre Bounine *rmap = 2; 818e5cabeb3SAlexandre Bounine return ext_ftr_ptr; 819e5cabeb3SAlexandre Bounine 820e5cabeb3SAlexandre Bounine default: 821e5cabeb3SAlexandre Bounine break; 822e5cabeb3SAlexandre Bounine } 823e5cabeb3SAlexandre Bounine 824e5cabeb3SAlexandre Bounine ext_ftr_ptr = rio_mport_get_efb(port, local, destid, 825e5cabeb3SAlexandre Bounine hopcount, ext_ftr_ptr); 826e5cabeb3SAlexandre Bounine } 827e5cabeb3SAlexandre Bounine 828e5cabeb3SAlexandre Bounine return ext_ftr_ptr; 829e5cabeb3SAlexandre Bounine } 830a11650e1SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_mport_get_physefb); 831e5cabeb3SAlexandre Bounine 832e5cabeb3SAlexandre Bounine /** 833e5cabeb3SAlexandre Bounine * rio_get_comptag - Begin or continue searching for a RIO device by component tag 83497ef6f74SRandy Dunlap * @comp_tag: RIO component tag to match 835e5cabeb3SAlexandre Bounine * @from: Previous RIO device found in search, or %NULL for new search 836e5cabeb3SAlexandre Bounine * 837e5cabeb3SAlexandre Bounine * Iterates through the list of known RIO devices. If a RIO device is 838e5cabeb3SAlexandre Bounine * found with a matching @comp_tag, a pointer to its device 839e5cabeb3SAlexandre Bounine * structure is returned. Otherwise, %NULL is returned. A new search 840e5cabeb3SAlexandre Bounine * is initiated by passing %NULL to the @from argument. Otherwise, if 841e5cabeb3SAlexandre Bounine * @from is not %NULL, searches continue from next device on the global 842e5cabeb3SAlexandre Bounine * list. 843e5cabeb3SAlexandre Bounine */ 844af84ca38SAlexandre Bounine struct rio_dev *rio_get_comptag(u32 comp_tag, struct rio_dev *from) 845e5cabeb3SAlexandre Bounine { 846e5cabeb3SAlexandre Bounine struct list_head *n; 847e5cabeb3SAlexandre Bounine struct rio_dev *rdev; 848e5cabeb3SAlexandre Bounine 849e5cabeb3SAlexandre Bounine spin_lock(&rio_global_list_lock); 850e5cabeb3SAlexandre Bounine n = from ? from->global_list.next : rio_devices.next; 851e5cabeb3SAlexandre Bounine 852e5cabeb3SAlexandre Bounine while (n && (n != &rio_devices)) { 853e5cabeb3SAlexandre Bounine rdev = rio_dev_g(n); 854e5cabeb3SAlexandre Bounine if (rdev->comp_tag == comp_tag) 855e5cabeb3SAlexandre Bounine goto exit; 856e5cabeb3SAlexandre Bounine n = n->next; 857e5cabeb3SAlexandre Bounine } 858e5cabeb3SAlexandre Bounine rdev = NULL; 859e5cabeb3SAlexandre Bounine exit: 860e5cabeb3SAlexandre Bounine spin_unlock(&rio_global_list_lock); 861e5cabeb3SAlexandre Bounine return rdev; 862e5cabeb3SAlexandre Bounine } 863a11650e1SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_get_comptag); 864e5cabeb3SAlexandre Bounine 865e5cabeb3SAlexandre Bounine /** 866e5cabeb3SAlexandre Bounine * rio_set_port_lockout - Sets/clears LOCKOUT bit (RIO EM 1.3) for a switch port. 867e5cabeb3SAlexandre Bounine * @rdev: Pointer to RIO device control structure 868e5cabeb3SAlexandre Bounine * @pnum: Switch port number to set LOCKOUT bit 869e5cabeb3SAlexandre Bounine * @lock: Operation : set (=1) or clear (=0) 870e5cabeb3SAlexandre Bounine */ 871e5cabeb3SAlexandre Bounine int rio_set_port_lockout(struct rio_dev *rdev, u32 pnum, int lock) 872e5cabeb3SAlexandre Bounine { 873e5cabeb3SAlexandre Bounine u32 regval; 874e5cabeb3SAlexandre Bounine 875a93192a5SAlexandre Bounine rio_read_config_32(rdev, 8761ae842deSAlexandre Bounine RIO_DEV_PORT_N_CTL_CSR(rdev, pnum), 877e5cabeb3SAlexandre Bounine ®val); 878e5cabeb3SAlexandre Bounine if (lock) 879e5cabeb3SAlexandre Bounine regval |= RIO_PORT_N_CTL_LOCKOUT; 880e5cabeb3SAlexandre Bounine else 881e5cabeb3SAlexandre Bounine regval &= ~RIO_PORT_N_CTL_LOCKOUT; 882e5cabeb3SAlexandre Bounine 883a93192a5SAlexandre Bounine rio_write_config_32(rdev, 8841ae842deSAlexandre Bounine RIO_DEV_PORT_N_CTL_CSR(rdev, pnum), 885e5cabeb3SAlexandre Bounine regval); 886e5cabeb3SAlexandre Bounine return 0; 887e5cabeb3SAlexandre Bounine } 888a11650e1SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_set_port_lockout); 889a11650e1SAlexandre Bounine 890a11650e1SAlexandre Bounine /** 891a11650e1SAlexandre Bounine * rio_enable_rx_tx_port - enable input receiver and output transmitter of 892a11650e1SAlexandre Bounine * given port 893a11650e1SAlexandre Bounine * @port: Master port associated with the RIO network 894a11650e1SAlexandre Bounine * @local: local=1 select local port otherwise a far device is reached 895a11650e1SAlexandre Bounine * @destid: Destination ID of the device to check host bit 896a11650e1SAlexandre Bounine * @hopcount: Number of hops to reach the target 897a11650e1SAlexandre Bounine * @port_num: Port (-number on switch) to enable on a far end device 898a11650e1SAlexandre Bounine * 899a11650e1SAlexandre Bounine * Returns 0 or 1 from on General Control Command and Status Register 900a11650e1SAlexandre Bounine * (EXT_PTR+0x3C) 901a11650e1SAlexandre Bounine */ 902a11650e1SAlexandre Bounine int rio_enable_rx_tx_port(struct rio_mport *port, 903a11650e1SAlexandre Bounine int local, u16 destid, 904a11650e1SAlexandre Bounine u8 hopcount, u8 port_num) 905a11650e1SAlexandre Bounine { 906a11650e1SAlexandre Bounine #ifdef CONFIG_RAPIDIO_ENABLE_RX_TX_PORTS 907a11650e1SAlexandre Bounine u32 regval; 908a11650e1SAlexandre Bounine u32 ext_ftr_ptr; 9091ae842deSAlexandre Bounine u32 rmap; 910a11650e1SAlexandre Bounine 911a11650e1SAlexandre Bounine /* 912a11650e1SAlexandre Bounine * enable rx input tx output port 913a11650e1SAlexandre Bounine */ 914a11650e1SAlexandre Bounine pr_debug("rio_enable_rx_tx_port(local = %d, destid = %d, hopcount = " 915a11650e1SAlexandre Bounine "%d, port_num = %d)\n", local, destid, hopcount, port_num); 916a11650e1SAlexandre Bounine 9171ae842deSAlexandre Bounine ext_ftr_ptr = rio_mport_get_physefb(port, local, destid, 9181ae842deSAlexandre Bounine hopcount, &rmap); 919a11650e1SAlexandre Bounine 920a11650e1SAlexandre Bounine if (local) { 9211ae842deSAlexandre Bounine rio_local_read_config_32(port, 9221ae842deSAlexandre Bounine ext_ftr_ptr + RIO_PORT_N_CTL_CSR(0, rmap), 923a11650e1SAlexandre Bounine ®val); 924a11650e1SAlexandre Bounine } else { 925a11650e1SAlexandre Bounine if (rio_mport_read_config_32(port, destid, hopcount, 9261ae842deSAlexandre Bounine ext_ftr_ptr + RIO_PORT_N_CTL_CSR(port_num, rmap), 9271ae842deSAlexandre Bounine ®val) < 0) 928a11650e1SAlexandre Bounine return -EIO; 929a11650e1SAlexandre Bounine } 930a11650e1SAlexandre Bounine 9311ae842deSAlexandre Bounine regval = regval | RIO_PORT_N_CTL_EN_RX | RIO_PORT_N_CTL_EN_TX; 932a11650e1SAlexandre Bounine 933a11650e1SAlexandre Bounine if (local) { 9341ae842deSAlexandre Bounine rio_local_write_config_32(port, 9351ae842deSAlexandre Bounine ext_ftr_ptr + RIO_PORT_N_CTL_CSR(0, rmap), regval); 936a11650e1SAlexandre Bounine } else { 937a11650e1SAlexandre Bounine if (rio_mport_write_config_32(port, destid, hopcount, 9381ae842deSAlexandre Bounine ext_ftr_ptr + RIO_PORT_N_CTL_CSR(port_num, rmap), 9391ae842deSAlexandre Bounine regval) < 0) 940a11650e1SAlexandre Bounine return -EIO; 941a11650e1SAlexandre Bounine } 942a11650e1SAlexandre Bounine #endif 943a11650e1SAlexandre Bounine return 0; 944a11650e1SAlexandre Bounine } 945a11650e1SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_enable_rx_tx_port); 946a11650e1SAlexandre Bounine 947e5cabeb3SAlexandre Bounine 948e5cabeb3SAlexandre Bounine /** 9496429cd49SAlexandre Bounine * rio_chk_dev_route - Validate route to the specified device. 9506429cd49SAlexandre Bounine * @rdev: RIO device failed to respond 9516429cd49SAlexandre Bounine * @nrdev: Last active device on the route to rdev 9526429cd49SAlexandre Bounine * @npnum: nrdev's port number on the route to rdev 9536429cd49SAlexandre Bounine * 9546429cd49SAlexandre Bounine * Follows a route to the specified RIO device to determine the last available 9556429cd49SAlexandre Bounine * device (and corresponding RIO port) on the route. 9566429cd49SAlexandre Bounine */ 9576429cd49SAlexandre Bounine static int 9586429cd49SAlexandre Bounine rio_chk_dev_route(struct rio_dev *rdev, struct rio_dev **nrdev, int *npnum) 9596429cd49SAlexandre Bounine { 9606429cd49SAlexandre Bounine u32 result; 961a93192a5SAlexandre Bounine int p_port, rc = -EIO; 9626429cd49SAlexandre Bounine struct rio_dev *prev = NULL; 9636429cd49SAlexandre Bounine 9646429cd49SAlexandre Bounine /* Find switch with failed RIO link */ 9656429cd49SAlexandre Bounine while (rdev->prev && (rdev->prev->pef & RIO_PEF_SWITCH)) { 9666429cd49SAlexandre Bounine if (!rio_read_config_32(rdev->prev, RIO_DEV_ID_CAR, &result)) { 9676429cd49SAlexandre Bounine prev = rdev->prev; 9686429cd49SAlexandre Bounine break; 9696429cd49SAlexandre Bounine } 9706429cd49SAlexandre Bounine rdev = rdev->prev; 9716429cd49SAlexandre Bounine } 9726429cd49SAlexandre Bounine 97393dd49afSMarkus Elfring if (!prev) 9746429cd49SAlexandre Bounine goto err_out; 9756429cd49SAlexandre Bounine 976a93192a5SAlexandre Bounine p_port = prev->rswitch->route_table[rdev->destid]; 9776429cd49SAlexandre Bounine 978af84ca38SAlexandre Bounine if (p_port != RIO_INVALID_ROUTE) { 9796429cd49SAlexandre Bounine pr_debug("RIO: link failed on [%s]-P%d\n", 9806429cd49SAlexandre Bounine rio_name(prev), p_port); 9816429cd49SAlexandre Bounine *nrdev = prev; 9826429cd49SAlexandre Bounine *npnum = p_port; 9836429cd49SAlexandre Bounine rc = 0; 9846429cd49SAlexandre Bounine } else 985af84ca38SAlexandre Bounine pr_debug("RIO: failed to trace route to %s\n", rio_name(rdev)); 9866429cd49SAlexandre Bounine err_out: 9876429cd49SAlexandre Bounine return rc; 9886429cd49SAlexandre Bounine } 9896429cd49SAlexandre Bounine 9906429cd49SAlexandre Bounine /** 9916429cd49SAlexandre Bounine * rio_mport_chk_dev_access - Validate access to the specified device. 9926429cd49SAlexandre Bounine * @mport: Master port to send transactions 9936429cd49SAlexandre Bounine * @destid: Device destination ID in network 9946429cd49SAlexandre Bounine * @hopcount: Number of hops into the network 9956429cd49SAlexandre Bounine */ 996e274e0edSAlexandre Bounine int 9976429cd49SAlexandre Bounine rio_mport_chk_dev_access(struct rio_mport *mport, u16 destid, u8 hopcount) 9986429cd49SAlexandre Bounine { 9996429cd49SAlexandre Bounine int i = 0; 10006429cd49SAlexandre Bounine u32 tmp; 10016429cd49SAlexandre Bounine 10026429cd49SAlexandre Bounine while (rio_mport_read_config_32(mport, destid, hopcount, 10036429cd49SAlexandre Bounine RIO_DEV_ID_CAR, &tmp)) { 10046429cd49SAlexandre Bounine i++; 10056429cd49SAlexandre Bounine if (i == RIO_MAX_CHK_RETRY) 10066429cd49SAlexandre Bounine return -EIO; 10076429cd49SAlexandre Bounine mdelay(1); 10086429cd49SAlexandre Bounine } 10096429cd49SAlexandre Bounine 10106429cd49SAlexandre Bounine return 0; 10116429cd49SAlexandre Bounine } 1012a11650e1SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_mport_chk_dev_access); 10136429cd49SAlexandre Bounine 10146429cd49SAlexandre Bounine /** 10156429cd49SAlexandre Bounine * rio_chk_dev_access - Validate access to the specified device. 10166429cd49SAlexandre Bounine * @rdev: Pointer to RIO device control structure 10176429cd49SAlexandre Bounine */ 10186429cd49SAlexandre Bounine static int rio_chk_dev_access(struct rio_dev *rdev) 10196429cd49SAlexandre Bounine { 1020a93192a5SAlexandre Bounine return rio_mport_chk_dev_access(rdev->net->hport, 1021a93192a5SAlexandre Bounine rdev->destid, rdev->hopcount); 10226429cd49SAlexandre Bounine } 10236429cd49SAlexandre Bounine 10246429cd49SAlexandre Bounine /** 1025dd5648c9SAlexandre Bounine * rio_get_input_status - Sends a Link-Request/Input-Status control symbol and 1026dd5648c9SAlexandre Bounine * returns link-response (if requested). 1027dd5648c9SAlexandre Bounine * @rdev: RIO devive to issue Input-status command 1028dd5648c9SAlexandre Bounine * @pnum: Device port number to issue the command 1029dd5648c9SAlexandre Bounine * @lnkresp: Response from a link partner 1030dd5648c9SAlexandre Bounine */ 1031dd5648c9SAlexandre Bounine static int 1032dd5648c9SAlexandre Bounine rio_get_input_status(struct rio_dev *rdev, int pnum, u32 *lnkresp) 1033dd5648c9SAlexandre Bounine { 1034dd5648c9SAlexandre Bounine u32 regval; 1035dd5648c9SAlexandre Bounine int checkcount; 1036dd5648c9SAlexandre Bounine 1037dd5648c9SAlexandre Bounine if (lnkresp) { 1038dd5648c9SAlexandre Bounine /* Read from link maintenance response register 1039dd5648c9SAlexandre Bounine * to clear valid bit */ 1040a93192a5SAlexandre Bounine rio_read_config_32(rdev, 10411ae842deSAlexandre Bounine RIO_DEV_PORT_N_MNT_RSP_CSR(rdev, pnum), 1042dd5648c9SAlexandre Bounine ®val); 1043dd5648c9SAlexandre Bounine udelay(50); 1044dd5648c9SAlexandre Bounine } 1045dd5648c9SAlexandre Bounine 1046dd5648c9SAlexandre Bounine /* Issue Input-status command */ 1047a93192a5SAlexandre Bounine rio_write_config_32(rdev, 10481ae842deSAlexandre Bounine RIO_DEV_PORT_N_MNT_REQ_CSR(rdev, pnum), 1049dd5648c9SAlexandre Bounine RIO_MNT_REQ_CMD_IS); 1050dd5648c9SAlexandre Bounine 1051dd5648c9SAlexandre Bounine /* Exit if the response is not expected */ 105293dd49afSMarkus Elfring if (!lnkresp) 1053dd5648c9SAlexandre Bounine return 0; 1054dd5648c9SAlexandre Bounine 1055dd5648c9SAlexandre Bounine checkcount = 3; 1056dd5648c9SAlexandre Bounine while (checkcount--) { 1057dd5648c9SAlexandre Bounine udelay(50); 1058a93192a5SAlexandre Bounine rio_read_config_32(rdev, 10591ae842deSAlexandre Bounine RIO_DEV_PORT_N_MNT_RSP_CSR(rdev, pnum), 1060dd5648c9SAlexandre Bounine ®val); 1061dd5648c9SAlexandre Bounine if (regval & RIO_PORT_N_MNT_RSP_RVAL) { 1062dd5648c9SAlexandre Bounine *lnkresp = regval; 1063dd5648c9SAlexandre Bounine return 0; 1064dd5648c9SAlexandre Bounine } 1065dd5648c9SAlexandre Bounine } 1066dd5648c9SAlexandre Bounine 1067dd5648c9SAlexandre Bounine return -EIO; 1068dd5648c9SAlexandre Bounine } 1069dd5648c9SAlexandre Bounine 1070dd5648c9SAlexandre Bounine /** 1071dd5648c9SAlexandre Bounine * rio_clr_err_stopped - Clears port Error-stopped states. 1072dd5648c9SAlexandre Bounine * @rdev: Pointer to RIO device control structure 1073dd5648c9SAlexandre Bounine * @pnum: Switch port number to clear errors 1074dd5648c9SAlexandre Bounine * @err_status: port error status (if 0 reads register from device) 10751ae842deSAlexandre Bounine * 10761ae842deSAlexandre Bounine * TODO: Currently this routine is not compatible with recovery process 10771ae842deSAlexandre Bounine * specified for idt_gen3 RapidIO switch devices. It has to be reviewed 10781ae842deSAlexandre Bounine * to implement universal recovery process that is compatible full range 10791ae842deSAlexandre Bounine * off available devices. 10801ae842deSAlexandre Bounine * IDT gen3 switch driver now implements HW-specific error handler that 10811ae842deSAlexandre Bounine * issues soft port reset to the port to reset ERR_STOP bits and ackIDs. 1082dd5648c9SAlexandre Bounine */ 1083dd5648c9SAlexandre Bounine static int rio_clr_err_stopped(struct rio_dev *rdev, u32 pnum, u32 err_status) 1084dd5648c9SAlexandre Bounine { 1085dd5648c9SAlexandre Bounine struct rio_dev *nextdev = rdev->rswitch->nextdev[pnum]; 1086dd5648c9SAlexandre Bounine u32 regval; 1087dd5648c9SAlexandre Bounine u32 far_ackid, far_linkstat, near_ackid; 1088dd5648c9SAlexandre Bounine 1089dd5648c9SAlexandre Bounine if (err_status == 0) 1090a93192a5SAlexandre Bounine rio_read_config_32(rdev, 10911ae842deSAlexandre Bounine RIO_DEV_PORT_N_ERR_STS_CSR(rdev, pnum), 1092dd5648c9SAlexandre Bounine &err_status); 1093dd5648c9SAlexandre Bounine 10941ae842deSAlexandre Bounine if (err_status & RIO_PORT_N_ERR_STS_OUT_ES) { 1095dd5648c9SAlexandre Bounine pr_debug("RIO_EM: servicing Output Error-Stopped state\n"); 1096dd5648c9SAlexandre Bounine /* 1097dd5648c9SAlexandre Bounine * Send a Link-Request/Input-Status control symbol 1098dd5648c9SAlexandre Bounine */ 1099dd5648c9SAlexandre Bounine if (rio_get_input_status(rdev, pnum, ®val)) { 1100dd5648c9SAlexandre Bounine pr_debug("RIO_EM: Input-status response timeout\n"); 1101dd5648c9SAlexandre Bounine goto rd_err; 1102dd5648c9SAlexandre Bounine } 1103dd5648c9SAlexandre Bounine 1104dd5648c9SAlexandre Bounine pr_debug("RIO_EM: SP%d Input-status response=0x%08x\n", 1105dd5648c9SAlexandre Bounine pnum, regval); 1106dd5648c9SAlexandre Bounine far_ackid = (regval & RIO_PORT_N_MNT_RSP_ASTAT) >> 5; 1107dd5648c9SAlexandre Bounine far_linkstat = regval & RIO_PORT_N_MNT_RSP_LSTAT; 1108a93192a5SAlexandre Bounine rio_read_config_32(rdev, 11091ae842deSAlexandre Bounine RIO_DEV_PORT_N_ACK_STS_CSR(rdev, pnum), 1110dd5648c9SAlexandre Bounine ®val); 1111dd5648c9SAlexandre Bounine pr_debug("RIO_EM: SP%d_ACK_STS_CSR=0x%08x\n", pnum, regval); 1112dd5648c9SAlexandre Bounine near_ackid = (regval & RIO_PORT_N_ACK_INBOUND) >> 24; 1113dd5648c9SAlexandre Bounine pr_debug("RIO_EM: SP%d far_ackID=0x%02x far_linkstat=0x%02x" \ 1114dd5648c9SAlexandre Bounine " near_ackID=0x%02x\n", 1115dd5648c9SAlexandre Bounine pnum, far_ackid, far_linkstat, near_ackid); 1116dd5648c9SAlexandre Bounine 1117dd5648c9SAlexandre Bounine /* 1118dd5648c9SAlexandre Bounine * If required, synchronize ackIDs of near and 1119dd5648c9SAlexandre Bounine * far sides. 1120dd5648c9SAlexandre Bounine */ 1121dd5648c9SAlexandre Bounine if ((far_ackid != ((regval & RIO_PORT_N_ACK_OUTSTAND) >> 8)) || 1122dd5648c9SAlexandre Bounine (far_ackid != (regval & RIO_PORT_N_ACK_OUTBOUND))) { 1123dd5648c9SAlexandre Bounine /* Align near outstanding/outbound ackIDs with 1124dd5648c9SAlexandre Bounine * far inbound. 1125dd5648c9SAlexandre Bounine */ 1126a93192a5SAlexandre Bounine rio_write_config_32(rdev, 11271ae842deSAlexandre Bounine RIO_DEV_PORT_N_ACK_STS_CSR(rdev, pnum), 1128dd5648c9SAlexandre Bounine (near_ackid << 24) | 1129dd5648c9SAlexandre Bounine (far_ackid << 8) | far_ackid); 1130dd5648c9SAlexandre Bounine /* Align far outstanding/outbound ackIDs with 1131dd5648c9SAlexandre Bounine * near inbound. 1132dd5648c9SAlexandre Bounine */ 1133dd5648c9SAlexandre Bounine far_ackid++; 11341ae842deSAlexandre Bounine if (!nextdev) { 11351ae842deSAlexandre Bounine pr_debug("RIO_EM: nextdev pointer == NULL\n"); 11361ae842deSAlexandre Bounine goto rd_err; 11371ae842deSAlexandre Bounine } 11381ae842deSAlexandre Bounine 1139dd5648c9SAlexandre Bounine rio_write_config_32(nextdev, 11401ae842deSAlexandre Bounine RIO_DEV_PORT_N_ACK_STS_CSR(nextdev, 11411ae842deSAlexandre Bounine RIO_GET_PORT_NUM(nextdev->swpinfo)), 1142dd5648c9SAlexandre Bounine (far_ackid << 24) | 1143dd5648c9SAlexandre Bounine (near_ackid << 8) | near_ackid); 1144dd5648c9SAlexandre Bounine } 1145dd5648c9SAlexandre Bounine rd_err: 11461ae842deSAlexandre Bounine rio_read_config_32(rdev, RIO_DEV_PORT_N_ERR_STS_CSR(rdev, pnum), 1147dd5648c9SAlexandre Bounine &err_status); 1148dd5648c9SAlexandre Bounine pr_debug("RIO_EM: SP%d_ERR_STS_CSR=0x%08x\n", pnum, err_status); 1149dd5648c9SAlexandre Bounine } 1150dd5648c9SAlexandre Bounine 11511ae842deSAlexandre Bounine if ((err_status & RIO_PORT_N_ERR_STS_INP_ES) && nextdev) { 1152dd5648c9SAlexandre Bounine pr_debug("RIO_EM: servicing Input Error-Stopped state\n"); 1153dd5648c9SAlexandre Bounine rio_get_input_status(nextdev, 1154dd5648c9SAlexandre Bounine RIO_GET_PORT_NUM(nextdev->swpinfo), NULL); 1155dd5648c9SAlexandre Bounine udelay(50); 1156dd5648c9SAlexandre Bounine 11571ae842deSAlexandre Bounine rio_read_config_32(rdev, RIO_DEV_PORT_N_ERR_STS_CSR(rdev, pnum), 1158dd5648c9SAlexandre Bounine &err_status); 1159dd5648c9SAlexandre Bounine pr_debug("RIO_EM: SP%d_ERR_STS_CSR=0x%08x\n", pnum, err_status); 1160dd5648c9SAlexandre Bounine } 1161dd5648c9SAlexandre Bounine 11621ae842deSAlexandre Bounine return (err_status & (RIO_PORT_N_ERR_STS_OUT_ES | 11631ae842deSAlexandre Bounine RIO_PORT_N_ERR_STS_INP_ES)) ? 1 : 0; 1164dd5648c9SAlexandre Bounine } 1165dd5648c9SAlexandre Bounine 1166dd5648c9SAlexandre Bounine /** 11679a0b0627SAlexandre Bounine * rio_inb_pwrite_handler - inbound port-write message handler 11689a0b0627SAlexandre Bounine * @mport: mport device associated with port-write 1169e5cabeb3SAlexandre Bounine * @pw_msg: pointer to inbound port-write message 1170e5cabeb3SAlexandre Bounine * 1171e5cabeb3SAlexandre Bounine * Processes an inbound port-write message. Returns 0 if the request 1172e5cabeb3SAlexandre Bounine * has been satisfied. 1173e5cabeb3SAlexandre Bounine */ 11749a0b0627SAlexandre Bounine int rio_inb_pwrite_handler(struct rio_mport *mport, union rio_pw_msg *pw_msg) 1175e5cabeb3SAlexandre Bounine { 1176e5cabeb3SAlexandre Bounine struct rio_dev *rdev; 1177dd5648c9SAlexandre Bounine u32 err_status, em_perrdet, em_ltlerrdet; 1178e5cabeb3SAlexandre Bounine int rc, portnum; 11799a0b0627SAlexandre Bounine struct rio_pwrite *pwrite; 1180e5cabeb3SAlexandre Bounine 1181e5cabeb3SAlexandre Bounine #ifdef DEBUG_PW 1182e5cabeb3SAlexandre Bounine { 1183e5cabeb3SAlexandre Bounine u32 i; 11849a0b0627SAlexandre Bounine 11859a0b0627SAlexandre Bounine pr_debug("%s: PW to mport_%d:\n", __func__, mport->id); 11869a0b0627SAlexandre Bounine for (i = 0; i < RIO_PW_MSG_SIZE / sizeof(u32); i = i + 4) { 1187dd5648c9SAlexandre Bounine pr_debug("0x%02x: %08x %08x %08x %08x\n", 1188e5cabeb3SAlexandre Bounine i * 4, pw_msg->raw[i], pw_msg->raw[i + 1], 1189e5cabeb3SAlexandre Bounine pw_msg->raw[i + 2], pw_msg->raw[i + 3]); 1190e5cabeb3SAlexandre Bounine } 1191e5cabeb3SAlexandre Bounine } 1192e5cabeb3SAlexandre Bounine #endif 1193e5cabeb3SAlexandre Bounine 11949a0b0627SAlexandre Bounine rdev = rio_get_comptag((pw_msg->em.comptag & RIO_CTAG_UDEVID), NULL); 11959a0b0627SAlexandre Bounine if (rdev) { 11969a0b0627SAlexandre Bounine pr_debug("RIO: Port-Write message from %s\n", rio_name(rdev)); 11979a0b0627SAlexandre Bounine } else { 11989a0b0627SAlexandre Bounine pr_debug("RIO: %s No matching device for CTag 0x%08x\n", 11999a0b0627SAlexandre Bounine __func__, pw_msg->em.comptag); 12009a0b0627SAlexandre Bounine } 12019a0b0627SAlexandre Bounine 12029a0b0627SAlexandre Bounine /* Call a device-specific handler (if it is registered for the device). 12039a0b0627SAlexandre Bounine * This may be the service for endpoints that send device-specific 12049a0b0627SAlexandre Bounine * port-write messages. End-point messages expected to be handled 12059a0b0627SAlexandre Bounine * completely by EP specific device driver. 1206e5cabeb3SAlexandre Bounine * For switches rc==0 signals that no standard processing required. 1207e5cabeb3SAlexandre Bounine */ 12089a0b0627SAlexandre Bounine if (rdev && rdev->pwcback) { 1209e5cabeb3SAlexandre Bounine rc = rdev->pwcback(rdev, pw_msg, 0); 1210e5cabeb3SAlexandre Bounine if (rc == 0) 1211e5cabeb3SAlexandre Bounine return 0; 1212e5cabeb3SAlexandre Bounine } 1213e5cabeb3SAlexandre Bounine 12149a0b0627SAlexandre Bounine mutex_lock(&mport->lock); 12159a0b0627SAlexandre Bounine list_for_each_entry(pwrite, &mport->pwrites, node) 12169a0b0627SAlexandre Bounine pwrite->pwcback(mport, pwrite->context, pw_msg, 0); 12179a0b0627SAlexandre Bounine mutex_unlock(&mport->lock); 12189a0b0627SAlexandre Bounine 12199a0b0627SAlexandre Bounine if (!rdev) 12209a0b0627SAlexandre Bounine return 0; 12219a0b0627SAlexandre Bounine 12229a0b0627SAlexandre Bounine /* 12239a0b0627SAlexandre Bounine * FIXME: The code below stays as it was before for now until we decide 12249a0b0627SAlexandre Bounine * how to do default PW handling in combination with per-mport callbacks 12259a0b0627SAlexandre Bounine */ 12269a0b0627SAlexandre Bounine 12276429cd49SAlexandre Bounine portnum = pw_msg->em.is_port & 0xFF; 12286429cd49SAlexandre Bounine 12296429cd49SAlexandre Bounine /* Check if device and route to it are functional: 12306429cd49SAlexandre Bounine * Sometimes devices may send PW message(s) just before being 12316429cd49SAlexandre Bounine * powered down (or link being lost). 12326429cd49SAlexandre Bounine */ 12336429cd49SAlexandre Bounine if (rio_chk_dev_access(rdev)) { 12346429cd49SAlexandre Bounine pr_debug("RIO: device access failed - get link partner\n"); 12356429cd49SAlexandre Bounine /* Scan route to the device and identify failed link. 12366429cd49SAlexandre Bounine * This will replace device and port reported in PW message. 12376429cd49SAlexandre Bounine * PW message should not be used after this point. 12386429cd49SAlexandre Bounine */ 12396429cd49SAlexandre Bounine if (rio_chk_dev_route(rdev, &rdev, &portnum)) { 12406429cd49SAlexandre Bounine pr_err("RIO: Route trace for %s failed\n", 12416429cd49SAlexandre Bounine rio_name(rdev)); 12426429cd49SAlexandre Bounine return -EIO; 12436429cd49SAlexandre Bounine } 12446429cd49SAlexandre Bounine pw_msg = NULL; 12456429cd49SAlexandre Bounine } 12466429cd49SAlexandre Bounine 1247e5cabeb3SAlexandre Bounine /* For End-point devices processing stops here */ 1248e5cabeb3SAlexandre Bounine if (!(rdev->pef & RIO_PEF_SWITCH)) 1249e5cabeb3SAlexandre Bounine return 0; 1250e5cabeb3SAlexandre Bounine 1251e5cabeb3SAlexandre Bounine if (rdev->phys_efptr == 0) { 1252e5cabeb3SAlexandre Bounine pr_err("RIO_PW: Bad switch initialization for %s\n", 1253e5cabeb3SAlexandre Bounine rio_name(rdev)); 1254e5cabeb3SAlexandre Bounine return 0; 1255e5cabeb3SAlexandre Bounine } 1256e5cabeb3SAlexandre Bounine 1257e5cabeb3SAlexandre Bounine /* 1258e5cabeb3SAlexandre Bounine * Process the port-write notification from switch 1259e5cabeb3SAlexandre Bounine */ 12602ec3ba69SAlexandre Bounine if (rdev->rswitch->ops && rdev->rswitch->ops->em_handle) 12612ec3ba69SAlexandre Bounine rdev->rswitch->ops->em_handle(rdev, portnum); 1262e5cabeb3SAlexandre Bounine 12631ae842deSAlexandre Bounine rio_read_config_32(rdev, RIO_DEV_PORT_N_ERR_STS_CSR(rdev, portnum), 1264e5cabeb3SAlexandre Bounine &err_status); 1265e5cabeb3SAlexandre Bounine pr_debug("RIO_PW: SP%d_ERR_STS_CSR=0x%08x\n", portnum, err_status); 1266e5cabeb3SAlexandre Bounine 1267dd5648c9SAlexandre Bounine if (err_status & RIO_PORT_N_ERR_STS_PORT_OK) { 1268dd5648c9SAlexandre Bounine 1269dd5648c9SAlexandre Bounine if (!(rdev->rswitch->port_ok & (1 << portnum))) { 1270dd5648c9SAlexandre Bounine rdev->rswitch->port_ok |= (1 << portnum); 1271dd5648c9SAlexandre Bounine rio_set_port_lockout(rdev, portnum, 0); 1272dd5648c9SAlexandre Bounine /* Schedule Insertion Service */ 1273dd5648c9SAlexandre Bounine pr_debug("RIO_PW: Device Insertion on [%s]-P%d\n", 1274dd5648c9SAlexandre Bounine rio_name(rdev), portnum); 1275e5cabeb3SAlexandre Bounine } 1276e5cabeb3SAlexandre Bounine 1277dd5648c9SAlexandre Bounine /* Clear error-stopped states (if reported). 1278dd5648c9SAlexandre Bounine * Depending on the link partner state, two attempts 1279dd5648c9SAlexandre Bounine * may be needed for successful recovery. 1280dd5648c9SAlexandre Bounine */ 12811ae842deSAlexandre Bounine if (err_status & (RIO_PORT_N_ERR_STS_OUT_ES | 12821ae842deSAlexandre Bounine RIO_PORT_N_ERR_STS_INP_ES)) { 1283dd5648c9SAlexandre Bounine if (rio_clr_err_stopped(rdev, portnum, err_status)) 1284dd5648c9SAlexandre Bounine rio_clr_err_stopped(rdev, portnum, 0); 1285e5cabeb3SAlexandre Bounine } 1286dd5648c9SAlexandre Bounine } else { /* if (err_status & RIO_PORT_N_ERR_STS_PORT_UNINIT) */ 1287e5cabeb3SAlexandre Bounine 1288e5cabeb3SAlexandre Bounine if (rdev->rswitch->port_ok & (1 << portnum)) { 1289e5cabeb3SAlexandre Bounine rdev->rswitch->port_ok &= ~(1 << portnum); 1290e5cabeb3SAlexandre Bounine rio_set_port_lockout(rdev, portnum, 1); 1291e5cabeb3SAlexandre Bounine 12921ae842deSAlexandre Bounine if (rdev->phys_rmap == 1) { 1293a93192a5SAlexandre Bounine rio_write_config_32(rdev, 12941ae842deSAlexandre Bounine RIO_DEV_PORT_N_ACK_STS_CSR(rdev, portnum), 1295e5cabeb3SAlexandre Bounine RIO_PORT_N_ACK_CLEAR); 12961ae842deSAlexandre Bounine } else { 12971ae842deSAlexandre Bounine rio_write_config_32(rdev, 12981ae842deSAlexandre Bounine RIO_DEV_PORT_N_OB_ACK_CSR(rdev, portnum), 12991ae842deSAlexandre Bounine RIO_PORT_N_OB_ACK_CLEAR); 13001ae842deSAlexandre Bounine rio_write_config_32(rdev, 13011ae842deSAlexandre Bounine RIO_DEV_PORT_N_IB_ACK_CSR(rdev, portnum), 13021ae842deSAlexandre Bounine 0); 13031ae842deSAlexandre Bounine } 1304e5cabeb3SAlexandre Bounine 1305e5cabeb3SAlexandre Bounine /* Schedule Extraction Service */ 1306e5cabeb3SAlexandre Bounine pr_debug("RIO_PW: Device Extraction on [%s]-P%d\n", 1307e5cabeb3SAlexandre Bounine rio_name(rdev), portnum); 1308e5cabeb3SAlexandre Bounine } 1309dd5648c9SAlexandre Bounine } 1310e5cabeb3SAlexandre Bounine 1311a93192a5SAlexandre Bounine rio_read_config_32(rdev, 1312dd5648c9SAlexandre Bounine rdev->em_efptr + RIO_EM_PN_ERR_DETECT(portnum), &em_perrdet); 1313dd5648c9SAlexandre Bounine if (em_perrdet) { 1314dd5648c9SAlexandre Bounine pr_debug("RIO_PW: RIO_EM_P%d_ERR_DETECT=0x%08x\n", 1315dd5648c9SAlexandre Bounine portnum, em_perrdet); 1316dd5648c9SAlexandre Bounine /* Clear EM Port N Error Detect CSR */ 1317a93192a5SAlexandre Bounine rio_write_config_32(rdev, 1318dd5648c9SAlexandre Bounine rdev->em_efptr + RIO_EM_PN_ERR_DETECT(portnum), 0); 1319e5cabeb3SAlexandre Bounine } 1320dd5648c9SAlexandre Bounine 1321a93192a5SAlexandre Bounine rio_read_config_32(rdev, 1322dd5648c9SAlexandre Bounine rdev->em_efptr + RIO_EM_LTL_ERR_DETECT, &em_ltlerrdet); 1323dd5648c9SAlexandre Bounine if (em_ltlerrdet) { 1324dd5648c9SAlexandre Bounine pr_debug("RIO_PW: RIO_EM_LTL_ERR_DETECT=0x%08x\n", 1325dd5648c9SAlexandre Bounine em_ltlerrdet); 1326dd5648c9SAlexandre Bounine /* Clear EM L/T Layer Error Detect CSR */ 1327a93192a5SAlexandre Bounine rio_write_config_32(rdev, 1328dd5648c9SAlexandre Bounine rdev->em_efptr + RIO_EM_LTL_ERR_DETECT, 0); 1329e5cabeb3SAlexandre Bounine } 1330e5cabeb3SAlexandre Bounine 1331388c45ccSAlexandre Bounine /* Clear remaining error bits and Port-Write Pending bit */ 13321ae842deSAlexandre Bounine rio_write_config_32(rdev, RIO_DEV_PORT_N_ERR_STS_CSR(rdev, portnum), 1333388c45ccSAlexandre Bounine err_status); 1334e5cabeb3SAlexandre Bounine 1335e5cabeb3SAlexandre Bounine return 0; 1336e5cabeb3SAlexandre Bounine } 1337e5cabeb3SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_inb_pwrite_handler); 1338e5cabeb3SAlexandre Bounine 1339e5cabeb3SAlexandre Bounine /** 1340e5cabeb3SAlexandre Bounine * rio_mport_get_efb - get pointer to next extended features block 1341e5cabeb3SAlexandre Bounine * @port: Master port to issue transaction 1342e5cabeb3SAlexandre Bounine * @local: Indicate a local master port or remote device access 1343e5cabeb3SAlexandre Bounine * @destid: Destination ID of the device 1344e5cabeb3SAlexandre Bounine * @hopcount: Number of switch hops to the device 1345e5cabeb3SAlexandre Bounine * @from: Offset of current Extended Feature block header (if 0 starts 1346e5cabeb3SAlexandre Bounine * from ExtFeaturePtr) 1347e5cabeb3SAlexandre Bounine */ 1348e5cabeb3SAlexandre Bounine u32 1349e5cabeb3SAlexandre Bounine rio_mport_get_efb(struct rio_mport *port, int local, u16 destid, 1350e5cabeb3SAlexandre Bounine u8 hopcount, u32 from) 1351e5cabeb3SAlexandre Bounine { 1352e5cabeb3SAlexandre Bounine u32 reg_val; 1353e5cabeb3SAlexandre Bounine 1354e5cabeb3SAlexandre Bounine if (from == 0) { 1355e5cabeb3SAlexandre Bounine if (local) 1356e5cabeb3SAlexandre Bounine rio_local_read_config_32(port, RIO_ASM_INFO_CAR, 1357e5cabeb3SAlexandre Bounine ®_val); 1358e5cabeb3SAlexandre Bounine else 1359e5cabeb3SAlexandre Bounine rio_mport_read_config_32(port, destid, hopcount, 1360e5cabeb3SAlexandre Bounine RIO_ASM_INFO_CAR, ®_val); 1361e5cabeb3SAlexandre Bounine return reg_val & RIO_EXT_FTR_PTR_MASK; 1362e5cabeb3SAlexandre Bounine } else { 1363e5cabeb3SAlexandre Bounine if (local) 1364e5cabeb3SAlexandre Bounine rio_local_read_config_32(port, from, ®_val); 1365e5cabeb3SAlexandre Bounine else 1366e5cabeb3SAlexandre Bounine rio_mport_read_config_32(port, destid, hopcount, 1367e5cabeb3SAlexandre Bounine from, ®_val); 1368e5cabeb3SAlexandre Bounine return RIO_GET_BLOCK_ID(reg_val); 1369e5cabeb3SAlexandre Bounine } 1370e5cabeb3SAlexandre Bounine } 1371a11650e1SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_mport_get_efb); 1372e5cabeb3SAlexandre Bounine 1373e5cabeb3SAlexandre Bounine /** 1374394b701cSMatt Porter * rio_mport_get_feature - query for devices' extended features 1375394b701cSMatt Porter * @port: Master port to issue transaction 1376394b701cSMatt Porter * @local: Indicate a local master port or remote device access 1377394b701cSMatt Porter * @destid: Destination ID of the device 1378394b701cSMatt Porter * @hopcount: Number of switch hops to the device 1379394b701cSMatt Porter * @ftr: Extended feature code 1380394b701cSMatt Porter * 1381394b701cSMatt Porter * Tell if a device supports a given RapidIO capability. 1382394b701cSMatt Porter * Returns the offset of the requested extended feature 1383394b701cSMatt Porter * block within the device's RIO configuration space or 13841ae842deSAlexandre Bounine * 0 in case the device does not support it. 1385394b701cSMatt Porter */ 1386394b701cSMatt Porter u32 1387394b701cSMatt Porter rio_mport_get_feature(struct rio_mport * port, int local, u16 destid, 1388394b701cSMatt Porter u8 hopcount, int ftr) 1389394b701cSMatt Porter { 1390394b701cSMatt Porter u32 asm_info, ext_ftr_ptr, ftr_header; 1391394b701cSMatt Porter 1392394b701cSMatt Porter if (local) 1393394b701cSMatt Porter rio_local_read_config_32(port, RIO_ASM_INFO_CAR, &asm_info); 1394394b701cSMatt Porter else 1395394b701cSMatt Porter rio_mport_read_config_32(port, destid, hopcount, 1396394b701cSMatt Porter RIO_ASM_INFO_CAR, &asm_info); 1397394b701cSMatt Porter 1398394b701cSMatt Porter ext_ftr_ptr = asm_info & RIO_EXT_FTR_PTR_MASK; 1399394b701cSMatt Porter 1400394b701cSMatt Porter while (ext_ftr_ptr) { 1401394b701cSMatt Porter if (local) 1402394b701cSMatt Porter rio_local_read_config_32(port, ext_ftr_ptr, 1403394b701cSMatt Porter &ftr_header); 1404394b701cSMatt Porter else 1405394b701cSMatt Porter rio_mport_read_config_32(port, destid, hopcount, 1406394b701cSMatt Porter ext_ftr_ptr, &ftr_header); 1407394b701cSMatt Porter if (RIO_GET_BLOCK_ID(ftr_header) == ftr) 1408394b701cSMatt Porter return ext_ftr_ptr; 1409e1d66d04SMarkus Elfring 1410e1d66d04SMarkus Elfring ext_ftr_ptr = RIO_GET_BLOCK_PTR(ftr_header); 1411e1d66d04SMarkus Elfring if (!ext_ftr_ptr) 1412394b701cSMatt Porter break; 1413394b701cSMatt Porter } 1414394b701cSMatt Porter 1415394b701cSMatt Porter return 0; 1416394b701cSMatt Porter } 1417a11650e1SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_mport_get_feature); 1418394b701cSMatt Porter 1419394b701cSMatt Porter /** 1420394b701cSMatt Porter * rio_get_asm - Begin or continue searching for a RIO device by vid/did/asm_vid/asm_did 1421394b701cSMatt Porter * @vid: RIO vid to match or %RIO_ANY_ID to match all vids 1422394b701cSMatt Porter * @did: RIO did to match or %RIO_ANY_ID to match all dids 1423394b701cSMatt Porter * @asm_vid: RIO asm_vid to match or %RIO_ANY_ID to match all asm_vids 1424394b701cSMatt Porter * @asm_did: RIO asm_did to match or %RIO_ANY_ID to match all asm_dids 1425394b701cSMatt Porter * @from: Previous RIO device found in search, or %NULL for new search 1426394b701cSMatt Porter * 1427394b701cSMatt Porter * Iterates through the list of known RIO devices. If a RIO device is 1428394b701cSMatt Porter * found with a matching @vid, @did, @asm_vid, @asm_did, the reference 1429394b701cSMatt Porter * count to the device is incrememted and a pointer to its device 1430394b701cSMatt Porter * structure is returned. Otherwise, %NULL is returned. A new search 1431394b701cSMatt Porter * is initiated by passing %NULL to the @from argument. Otherwise, if 1432394b701cSMatt Porter * @from is not %NULL, searches continue from next device on the global 1433394b701cSMatt Porter * list. The reference count for @from is always decremented if it is 1434394b701cSMatt Porter * not %NULL. 1435394b701cSMatt Porter */ 1436394b701cSMatt Porter struct rio_dev *rio_get_asm(u16 vid, u16 did, 1437394b701cSMatt Porter u16 asm_vid, u16 asm_did, struct rio_dev *from) 1438394b701cSMatt Porter { 1439394b701cSMatt Porter struct list_head *n; 1440394b701cSMatt Porter struct rio_dev *rdev; 1441394b701cSMatt Porter 1442394b701cSMatt Porter WARN_ON(in_interrupt()); 1443394b701cSMatt Porter spin_lock(&rio_global_list_lock); 1444394b701cSMatt Porter n = from ? from->global_list.next : rio_devices.next; 1445394b701cSMatt Porter 1446394b701cSMatt Porter while (n && (n != &rio_devices)) { 1447394b701cSMatt Porter rdev = rio_dev_g(n); 1448394b701cSMatt Porter if ((vid == RIO_ANY_ID || rdev->vid == vid) && 1449394b701cSMatt Porter (did == RIO_ANY_ID || rdev->did == did) && 1450394b701cSMatt Porter (asm_vid == RIO_ANY_ID || rdev->asm_vid == asm_vid) && 1451394b701cSMatt Porter (asm_did == RIO_ANY_ID || rdev->asm_did == asm_did)) 1452394b701cSMatt Porter goto exit; 1453394b701cSMatt Porter n = n->next; 1454394b701cSMatt Porter } 1455394b701cSMatt Porter rdev = NULL; 1456394b701cSMatt Porter exit: 1457394b701cSMatt Porter rio_dev_put(from); 1458394b701cSMatt Porter rdev = rio_dev_get(rdev); 1459394b701cSMatt Porter spin_unlock(&rio_global_list_lock); 1460394b701cSMatt Porter return rdev; 1461394b701cSMatt Porter } 1462394b701cSMatt Porter 1463394b701cSMatt Porter /** 1464394b701cSMatt Porter * rio_get_device - Begin or continue searching for a RIO device by vid/did 1465394b701cSMatt Porter * @vid: RIO vid to match or %RIO_ANY_ID to match all vids 1466394b701cSMatt Porter * @did: RIO did to match or %RIO_ANY_ID to match all dids 1467394b701cSMatt Porter * @from: Previous RIO device found in search, or %NULL for new search 1468394b701cSMatt Porter * 1469394b701cSMatt Porter * Iterates through the list of known RIO devices. If a RIO device is 1470394b701cSMatt Porter * found with a matching @vid and @did, the reference count to the 1471394b701cSMatt Porter * device is incrememted and a pointer to its device structure is returned. 1472394b701cSMatt Porter * Otherwise, %NULL is returned. A new search is initiated by passing %NULL 1473394b701cSMatt Porter * to the @from argument. Otherwise, if @from is not %NULL, searches 1474394b701cSMatt Porter * continue from next device on the global list. The reference count for 1475394b701cSMatt Porter * @from is always decremented if it is not %NULL. 1476394b701cSMatt Porter */ 1477394b701cSMatt Porter struct rio_dev *rio_get_device(u16 vid, u16 did, struct rio_dev *from) 1478394b701cSMatt Porter { 1479394b701cSMatt Porter return rio_get_asm(vid, did, RIO_ANY_ID, RIO_ANY_ID, from); 1480394b701cSMatt Porter } 1481394b701cSMatt Porter 148207590ff0SAlexandre Bounine /** 148307590ff0SAlexandre Bounine * rio_std_route_add_entry - Add switch route table entry using standard 148407590ff0SAlexandre Bounine * registers defined in RIO specification rev.1.3 148507590ff0SAlexandre Bounine * @mport: Master port to issue transaction 148607590ff0SAlexandre Bounine * @destid: Destination ID of the device 148707590ff0SAlexandre Bounine * @hopcount: Number of switch hops to the device 148807590ff0SAlexandre Bounine * @table: routing table ID (global or port-specific) 148907590ff0SAlexandre Bounine * @route_destid: destID entry in the RT 149007590ff0SAlexandre Bounine * @route_port: destination port for specified destID 149107590ff0SAlexandre Bounine */ 14922ec3ba69SAlexandre Bounine static int 14932ec3ba69SAlexandre Bounine rio_std_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount, 149407590ff0SAlexandre Bounine u16 table, u16 route_destid, u8 route_port) 149507590ff0SAlexandre Bounine { 149607590ff0SAlexandre Bounine if (table == RIO_GLOBAL_TABLE) { 149707590ff0SAlexandre Bounine rio_mport_write_config_32(mport, destid, hopcount, 149807590ff0SAlexandre Bounine RIO_STD_RTE_CONF_DESTID_SEL_CSR, 149907590ff0SAlexandre Bounine (u32)route_destid); 150007590ff0SAlexandre Bounine rio_mport_write_config_32(mport, destid, hopcount, 150107590ff0SAlexandre Bounine RIO_STD_RTE_CONF_PORT_SEL_CSR, 150207590ff0SAlexandre Bounine (u32)route_port); 150307590ff0SAlexandre Bounine } 1504e5cabeb3SAlexandre Bounine 150507590ff0SAlexandre Bounine udelay(10); 150607590ff0SAlexandre Bounine return 0; 150707590ff0SAlexandre Bounine } 150807590ff0SAlexandre Bounine 150907590ff0SAlexandre Bounine /** 151007590ff0SAlexandre Bounine * rio_std_route_get_entry - Read switch route table entry (port number) 1511638c5945SUwe Kleine-König * associated with specified destID using standard registers defined in RIO 151207590ff0SAlexandre Bounine * specification rev.1.3 151307590ff0SAlexandre Bounine * @mport: Master port to issue transaction 151407590ff0SAlexandre Bounine * @destid: Destination ID of the device 151507590ff0SAlexandre Bounine * @hopcount: Number of switch hops to the device 151607590ff0SAlexandre Bounine * @table: routing table ID (global or port-specific) 151707590ff0SAlexandre Bounine * @route_destid: destID entry in the RT 151807590ff0SAlexandre Bounine * @route_port: returned destination port for specified destID 151907590ff0SAlexandre Bounine */ 15202ec3ba69SAlexandre Bounine static int 15212ec3ba69SAlexandre Bounine rio_std_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount, 152207590ff0SAlexandre Bounine u16 table, u16 route_destid, u8 *route_port) 152307590ff0SAlexandre Bounine { 152407590ff0SAlexandre Bounine u32 result; 152507590ff0SAlexandre Bounine 152607590ff0SAlexandre Bounine if (table == RIO_GLOBAL_TABLE) { 152707590ff0SAlexandre Bounine rio_mport_write_config_32(mport, destid, hopcount, 152807590ff0SAlexandre Bounine RIO_STD_RTE_CONF_DESTID_SEL_CSR, route_destid); 152907590ff0SAlexandre Bounine rio_mport_read_config_32(mport, destid, hopcount, 153007590ff0SAlexandre Bounine RIO_STD_RTE_CONF_PORT_SEL_CSR, &result); 153107590ff0SAlexandre Bounine 153207590ff0SAlexandre Bounine *route_port = (u8)result; 153307590ff0SAlexandre Bounine } 153407590ff0SAlexandre Bounine 153507590ff0SAlexandre Bounine return 0; 153607590ff0SAlexandre Bounine } 153707590ff0SAlexandre Bounine 153807590ff0SAlexandre Bounine /** 153907590ff0SAlexandre Bounine * rio_std_route_clr_table - Clear swotch route table using standard registers 154007590ff0SAlexandre Bounine * defined in RIO specification rev.1.3. 154107590ff0SAlexandre Bounine * @mport: Master port to issue transaction 154207590ff0SAlexandre Bounine * @destid: Destination ID of the device 154307590ff0SAlexandre Bounine * @hopcount: Number of switch hops to the device 154407590ff0SAlexandre Bounine * @table: routing table ID (global or port-specific) 154507590ff0SAlexandre Bounine */ 15462ec3ba69SAlexandre Bounine static int 15472ec3ba69SAlexandre Bounine rio_std_route_clr_table(struct rio_mport *mport, u16 destid, u8 hopcount, 154807590ff0SAlexandre Bounine u16 table) 154907590ff0SAlexandre Bounine { 155007590ff0SAlexandre Bounine u32 max_destid = 0xff; 155107590ff0SAlexandre Bounine u32 i, pef, id_inc = 1, ext_cfg = 0; 155207590ff0SAlexandre Bounine u32 port_sel = RIO_INVALID_ROUTE; 155307590ff0SAlexandre Bounine 155407590ff0SAlexandre Bounine if (table == RIO_GLOBAL_TABLE) { 155507590ff0SAlexandre Bounine rio_mport_read_config_32(mport, destid, hopcount, 155607590ff0SAlexandre Bounine RIO_PEF_CAR, &pef); 155707590ff0SAlexandre Bounine 155807590ff0SAlexandre Bounine if (mport->sys_size) { 155907590ff0SAlexandre Bounine rio_mport_read_config_32(mport, destid, hopcount, 156007590ff0SAlexandre Bounine RIO_SWITCH_RT_LIMIT, 156107590ff0SAlexandre Bounine &max_destid); 156207590ff0SAlexandre Bounine max_destid &= RIO_RT_MAX_DESTID; 156307590ff0SAlexandre Bounine } 156407590ff0SAlexandre Bounine 156507590ff0SAlexandre Bounine if (pef & RIO_PEF_EXT_RT) { 156607590ff0SAlexandre Bounine ext_cfg = 0x80000000; 156707590ff0SAlexandre Bounine id_inc = 4; 156807590ff0SAlexandre Bounine port_sel = (RIO_INVALID_ROUTE << 24) | 156907590ff0SAlexandre Bounine (RIO_INVALID_ROUTE << 16) | 157007590ff0SAlexandre Bounine (RIO_INVALID_ROUTE << 8) | 157107590ff0SAlexandre Bounine RIO_INVALID_ROUTE; 157207590ff0SAlexandre Bounine } 157307590ff0SAlexandre Bounine 157407590ff0SAlexandre Bounine for (i = 0; i <= max_destid;) { 157507590ff0SAlexandre Bounine rio_mport_write_config_32(mport, destid, hopcount, 157607590ff0SAlexandre Bounine RIO_STD_RTE_CONF_DESTID_SEL_CSR, 157707590ff0SAlexandre Bounine ext_cfg | i); 157807590ff0SAlexandre Bounine rio_mport_write_config_32(mport, destid, hopcount, 157907590ff0SAlexandre Bounine RIO_STD_RTE_CONF_PORT_SEL_CSR, 158007590ff0SAlexandre Bounine port_sel); 158107590ff0SAlexandre Bounine i += id_inc; 158207590ff0SAlexandre Bounine } 158307590ff0SAlexandre Bounine } 158407590ff0SAlexandre Bounine 158507590ff0SAlexandre Bounine udelay(10); 158607590ff0SAlexandre Bounine return 0; 158707590ff0SAlexandre Bounine } 158807590ff0SAlexandre Bounine 15892ec3ba69SAlexandre Bounine /** 15902ec3ba69SAlexandre Bounine * rio_lock_device - Acquires host device lock for specified device 15912ec3ba69SAlexandre Bounine * @port: Master port to send transaction 15922ec3ba69SAlexandre Bounine * @destid: Destination ID for device/switch 15932ec3ba69SAlexandre Bounine * @hopcount: Hopcount to reach switch 15942ec3ba69SAlexandre Bounine * @wait_ms: Max wait time in msec (0 = no timeout) 15952ec3ba69SAlexandre Bounine * 15962ec3ba69SAlexandre Bounine * Attepts to acquire host device lock for specified device 15972ec3ba69SAlexandre Bounine * Returns 0 if device lock acquired or EINVAL if timeout expires. 15982ec3ba69SAlexandre Bounine */ 15992ec3ba69SAlexandre Bounine int rio_lock_device(struct rio_mport *port, u16 destid, 16002ec3ba69SAlexandre Bounine u8 hopcount, int wait_ms) 16012ec3ba69SAlexandre Bounine { 16022ec3ba69SAlexandre Bounine u32 result; 16032ec3ba69SAlexandre Bounine int tcnt = 0; 16042ec3ba69SAlexandre Bounine 16052ec3ba69SAlexandre Bounine /* Attempt to acquire device lock */ 16062ec3ba69SAlexandre Bounine rio_mport_write_config_32(port, destid, hopcount, 16072ec3ba69SAlexandre Bounine RIO_HOST_DID_LOCK_CSR, port->host_deviceid); 16082ec3ba69SAlexandre Bounine rio_mport_read_config_32(port, destid, hopcount, 16092ec3ba69SAlexandre Bounine RIO_HOST_DID_LOCK_CSR, &result); 16102ec3ba69SAlexandre Bounine 16112ec3ba69SAlexandre Bounine while (result != port->host_deviceid) { 16122ec3ba69SAlexandre Bounine if (wait_ms != 0 && tcnt == wait_ms) { 16132ec3ba69SAlexandre Bounine pr_debug("RIO: timeout when locking device %x:%x\n", 16142ec3ba69SAlexandre Bounine destid, hopcount); 16152ec3ba69SAlexandre Bounine return -EINVAL; 16162ec3ba69SAlexandre Bounine } 16172ec3ba69SAlexandre Bounine 16182ec3ba69SAlexandre Bounine /* Delay a bit */ 16192ec3ba69SAlexandre Bounine mdelay(1); 16202ec3ba69SAlexandre Bounine tcnt++; 16212ec3ba69SAlexandre Bounine /* Try to acquire device lock again */ 16222ec3ba69SAlexandre Bounine rio_mport_write_config_32(port, destid, 16232ec3ba69SAlexandre Bounine hopcount, 16242ec3ba69SAlexandre Bounine RIO_HOST_DID_LOCK_CSR, 16252ec3ba69SAlexandre Bounine port->host_deviceid); 16262ec3ba69SAlexandre Bounine rio_mport_read_config_32(port, destid, 16272ec3ba69SAlexandre Bounine hopcount, 16282ec3ba69SAlexandre Bounine RIO_HOST_DID_LOCK_CSR, &result); 16292ec3ba69SAlexandre Bounine } 16302ec3ba69SAlexandre Bounine 16312ec3ba69SAlexandre Bounine return 0; 16322ec3ba69SAlexandre Bounine } 16332ec3ba69SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_lock_device); 16342ec3ba69SAlexandre Bounine 16352ec3ba69SAlexandre Bounine /** 16362ec3ba69SAlexandre Bounine * rio_unlock_device - Releases host device lock for specified device 16372ec3ba69SAlexandre Bounine * @port: Master port to send transaction 16382ec3ba69SAlexandre Bounine * @destid: Destination ID for device/switch 16392ec3ba69SAlexandre Bounine * @hopcount: Hopcount to reach switch 16402ec3ba69SAlexandre Bounine * 16412ec3ba69SAlexandre Bounine * Returns 0 if device lock released or EINVAL if fails. 16422ec3ba69SAlexandre Bounine */ 16432ec3ba69SAlexandre Bounine int rio_unlock_device(struct rio_mport *port, u16 destid, u8 hopcount) 16442ec3ba69SAlexandre Bounine { 16452ec3ba69SAlexandre Bounine u32 result; 16462ec3ba69SAlexandre Bounine 16472ec3ba69SAlexandre Bounine /* Release device lock */ 16482ec3ba69SAlexandre Bounine rio_mport_write_config_32(port, destid, 16492ec3ba69SAlexandre Bounine hopcount, 16502ec3ba69SAlexandre Bounine RIO_HOST_DID_LOCK_CSR, 16512ec3ba69SAlexandre Bounine port->host_deviceid); 16522ec3ba69SAlexandre Bounine rio_mport_read_config_32(port, destid, hopcount, 16532ec3ba69SAlexandre Bounine RIO_HOST_DID_LOCK_CSR, &result); 16542ec3ba69SAlexandre Bounine if ((result & 0xffff) != 0xffff) { 16552ec3ba69SAlexandre Bounine pr_debug("RIO: badness when releasing device lock %x:%x\n", 16562ec3ba69SAlexandre Bounine destid, hopcount); 16572ec3ba69SAlexandre Bounine return -EINVAL; 16582ec3ba69SAlexandre Bounine } 16592ec3ba69SAlexandre Bounine 16602ec3ba69SAlexandre Bounine return 0; 16612ec3ba69SAlexandre Bounine } 16622ec3ba69SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_unlock_device); 16632ec3ba69SAlexandre Bounine 16642ec3ba69SAlexandre Bounine /** 16652ec3ba69SAlexandre Bounine * rio_route_add_entry- Add a route entry to a switch routing table 16662ec3ba69SAlexandre Bounine * @rdev: RIO device 16672ec3ba69SAlexandre Bounine * @table: Routing table ID 16682ec3ba69SAlexandre Bounine * @route_destid: Destination ID to be routed 16692ec3ba69SAlexandre Bounine * @route_port: Port number to be routed 16702ec3ba69SAlexandre Bounine * @lock: apply a hardware lock on switch device flag (1=lock, 0=no_lock) 16712ec3ba69SAlexandre Bounine * 16722ec3ba69SAlexandre Bounine * If available calls the switch specific add_entry() method to add a route 16732ec3ba69SAlexandre Bounine * entry into a switch routing table. Otherwise uses standard RT update method 16742ec3ba69SAlexandre Bounine * as defined by RapidIO specification. A specific routing table can be selected 16752ec3ba69SAlexandre Bounine * using the @table argument if a switch has per port routing tables or 16762ec3ba69SAlexandre Bounine * the standard (or global) table may be used by passing 16772ec3ba69SAlexandre Bounine * %RIO_GLOBAL_TABLE in @table. 16782ec3ba69SAlexandre Bounine * 16792ec3ba69SAlexandre Bounine * Returns %0 on success or %-EINVAL on failure. 16802ec3ba69SAlexandre Bounine */ 16812ec3ba69SAlexandre Bounine int rio_route_add_entry(struct rio_dev *rdev, 16822ec3ba69SAlexandre Bounine u16 table, u16 route_destid, u8 route_port, int lock) 16832ec3ba69SAlexandre Bounine { 16842ec3ba69SAlexandre Bounine int rc = -EINVAL; 16852ec3ba69SAlexandre Bounine struct rio_switch_ops *ops = rdev->rswitch->ops; 16862ec3ba69SAlexandre Bounine 16872ec3ba69SAlexandre Bounine if (lock) { 16882ec3ba69SAlexandre Bounine rc = rio_lock_device(rdev->net->hport, rdev->destid, 16892ec3ba69SAlexandre Bounine rdev->hopcount, 1000); 16902ec3ba69SAlexandre Bounine if (rc) 16912ec3ba69SAlexandre Bounine return rc; 16922ec3ba69SAlexandre Bounine } 16932ec3ba69SAlexandre Bounine 16942ec3ba69SAlexandre Bounine spin_lock(&rdev->rswitch->lock); 16952ec3ba69SAlexandre Bounine 169693dd49afSMarkus Elfring if (!ops || !ops->add_entry) { 16972ec3ba69SAlexandre Bounine rc = rio_std_route_add_entry(rdev->net->hport, rdev->destid, 16982ec3ba69SAlexandre Bounine rdev->hopcount, table, 16992ec3ba69SAlexandre Bounine route_destid, route_port); 17002ec3ba69SAlexandre Bounine } else if (try_module_get(ops->owner)) { 17012ec3ba69SAlexandre Bounine rc = ops->add_entry(rdev->net->hport, rdev->destid, 17022ec3ba69SAlexandre Bounine rdev->hopcount, table, route_destid, 17032ec3ba69SAlexandre Bounine route_port); 17042ec3ba69SAlexandre Bounine module_put(ops->owner); 17052ec3ba69SAlexandre Bounine } 17062ec3ba69SAlexandre Bounine 17072ec3ba69SAlexandre Bounine spin_unlock(&rdev->rswitch->lock); 17082ec3ba69SAlexandre Bounine 17092ec3ba69SAlexandre Bounine if (lock) 17102ec3ba69SAlexandre Bounine rio_unlock_device(rdev->net->hport, rdev->destid, 17112ec3ba69SAlexandre Bounine rdev->hopcount); 17122ec3ba69SAlexandre Bounine 17132ec3ba69SAlexandre Bounine return rc; 17142ec3ba69SAlexandre Bounine } 17152ec3ba69SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_route_add_entry); 17162ec3ba69SAlexandre Bounine 17172ec3ba69SAlexandre Bounine /** 17182ec3ba69SAlexandre Bounine * rio_route_get_entry- Read an entry from a switch routing table 17192ec3ba69SAlexandre Bounine * @rdev: RIO device 17202ec3ba69SAlexandre Bounine * @table: Routing table ID 17212ec3ba69SAlexandre Bounine * @route_destid: Destination ID to be routed 17222ec3ba69SAlexandre Bounine * @route_port: Pointer to read port number into 17232ec3ba69SAlexandre Bounine * @lock: apply a hardware lock on switch device flag (1=lock, 0=no_lock) 17242ec3ba69SAlexandre Bounine * 17252ec3ba69SAlexandre Bounine * If available calls the switch specific get_entry() method to fetch a route 17262ec3ba69SAlexandre Bounine * entry from a switch routing table. Otherwise uses standard RT read method 17272ec3ba69SAlexandre Bounine * as defined by RapidIO specification. A specific routing table can be selected 17282ec3ba69SAlexandre Bounine * using the @table argument if a switch has per port routing tables or 17292ec3ba69SAlexandre Bounine * the standard (or global) table may be used by passing 17302ec3ba69SAlexandre Bounine * %RIO_GLOBAL_TABLE in @table. 17312ec3ba69SAlexandre Bounine * 17322ec3ba69SAlexandre Bounine * Returns %0 on success or %-EINVAL on failure. 17332ec3ba69SAlexandre Bounine */ 17342ec3ba69SAlexandre Bounine int rio_route_get_entry(struct rio_dev *rdev, u16 table, 17352ec3ba69SAlexandre Bounine u16 route_destid, u8 *route_port, int lock) 17362ec3ba69SAlexandre Bounine { 17372ec3ba69SAlexandre Bounine int rc = -EINVAL; 17382ec3ba69SAlexandre Bounine struct rio_switch_ops *ops = rdev->rswitch->ops; 17392ec3ba69SAlexandre Bounine 17402ec3ba69SAlexandre Bounine if (lock) { 17412ec3ba69SAlexandre Bounine rc = rio_lock_device(rdev->net->hport, rdev->destid, 17422ec3ba69SAlexandre Bounine rdev->hopcount, 1000); 17432ec3ba69SAlexandre Bounine if (rc) 17442ec3ba69SAlexandre Bounine return rc; 17452ec3ba69SAlexandre Bounine } 17462ec3ba69SAlexandre Bounine 17472ec3ba69SAlexandre Bounine spin_lock(&rdev->rswitch->lock); 17482ec3ba69SAlexandre Bounine 174993dd49afSMarkus Elfring if (!ops || !ops->get_entry) { 17502ec3ba69SAlexandre Bounine rc = rio_std_route_get_entry(rdev->net->hport, rdev->destid, 17512ec3ba69SAlexandre Bounine rdev->hopcount, table, 17522ec3ba69SAlexandre Bounine route_destid, route_port); 17532ec3ba69SAlexandre Bounine } else if (try_module_get(ops->owner)) { 17542ec3ba69SAlexandre Bounine rc = ops->get_entry(rdev->net->hport, rdev->destid, 17552ec3ba69SAlexandre Bounine rdev->hopcount, table, route_destid, 17562ec3ba69SAlexandre Bounine route_port); 17572ec3ba69SAlexandre Bounine module_put(ops->owner); 17582ec3ba69SAlexandre Bounine } 17592ec3ba69SAlexandre Bounine 17602ec3ba69SAlexandre Bounine spin_unlock(&rdev->rswitch->lock); 17612ec3ba69SAlexandre Bounine 17622ec3ba69SAlexandre Bounine if (lock) 17632ec3ba69SAlexandre Bounine rio_unlock_device(rdev->net->hport, rdev->destid, 17642ec3ba69SAlexandre Bounine rdev->hopcount); 17652ec3ba69SAlexandre Bounine return rc; 17662ec3ba69SAlexandre Bounine } 17672ec3ba69SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_route_get_entry); 17682ec3ba69SAlexandre Bounine 17692ec3ba69SAlexandre Bounine /** 17702ec3ba69SAlexandre Bounine * rio_route_clr_table - Clear a switch routing table 17712ec3ba69SAlexandre Bounine * @rdev: RIO device 17722ec3ba69SAlexandre Bounine * @table: Routing table ID 17732ec3ba69SAlexandre Bounine * @lock: apply a hardware lock on switch device flag (1=lock, 0=no_lock) 17742ec3ba69SAlexandre Bounine * 17752ec3ba69SAlexandre Bounine * If available calls the switch specific clr_table() method to clear a switch 17762ec3ba69SAlexandre Bounine * routing table. Otherwise uses standard RT write method as defined by RapidIO 17772ec3ba69SAlexandre Bounine * specification. A specific routing table can be selected using the @table 17782ec3ba69SAlexandre Bounine * argument if a switch has per port routing tables or the standard (or global) 17792ec3ba69SAlexandre Bounine * table may be used by passing %RIO_GLOBAL_TABLE in @table. 17802ec3ba69SAlexandre Bounine * 17812ec3ba69SAlexandre Bounine * Returns %0 on success or %-EINVAL on failure. 17822ec3ba69SAlexandre Bounine */ 17832ec3ba69SAlexandre Bounine int rio_route_clr_table(struct rio_dev *rdev, u16 table, int lock) 17842ec3ba69SAlexandre Bounine { 17852ec3ba69SAlexandre Bounine int rc = -EINVAL; 17862ec3ba69SAlexandre Bounine struct rio_switch_ops *ops = rdev->rswitch->ops; 17872ec3ba69SAlexandre Bounine 17882ec3ba69SAlexandre Bounine if (lock) { 17892ec3ba69SAlexandre Bounine rc = rio_lock_device(rdev->net->hport, rdev->destid, 17902ec3ba69SAlexandre Bounine rdev->hopcount, 1000); 17912ec3ba69SAlexandre Bounine if (rc) 17922ec3ba69SAlexandre Bounine return rc; 17932ec3ba69SAlexandre Bounine } 17942ec3ba69SAlexandre Bounine 17952ec3ba69SAlexandre Bounine spin_lock(&rdev->rswitch->lock); 17962ec3ba69SAlexandre Bounine 179793dd49afSMarkus Elfring if (!ops || !ops->clr_table) { 17982ec3ba69SAlexandre Bounine rc = rio_std_route_clr_table(rdev->net->hport, rdev->destid, 17992ec3ba69SAlexandre Bounine rdev->hopcount, table); 18002ec3ba69SAlexandre Bounine } else if (try_module_get(ops->owner)) { 18012ec3ba69SAlexandre Bounine rc = ops->clr_table(rdev->net->hport, rdev->destid, 18022ec3ba69SAlexandre Bounine rdev->hopcount, table); 18032ec3ba69SAlexandre Bounine 18042ec3ba69SAlexandre Bounine module_put(ops->owner); 18052ec3ba69SAlexandre Bounine } 18062ec3ba69SAlexandre Bounine 18072ec3ba69SAlexandre Bounine spin_unlock(&rdev->rswitch->lock); 18082ec3ba69SAlexandre Bounine 18092ec3ba69SAlexandre Bounine if (lock) 18102ec3ba69SAlexandre Bounine rio_unlock_device(rdev->net->hport, rdev->destid, 18112ec3ba69SAlexandre Bounine rdev->hopcount); 18122ec3ba69SAlexandre Bounine 18132ec3ba69SAlexandre Bounine return rc; 18142ec3ba69SAlexandre Bounine } 18152ec3ba69SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_route_clr_table); 18162ec3ba69SAlexandre Bounine 1817e42d98ebSAlexandre Bounine #ifdef CONFIG_RAPIDIO_DMA_ENGINE 1818e42d98ebSAlexandre Bounine 1819e42d98ebSAlexandre Bounine static bool rio_chan_filter(struct dma_chan *chan, void *arg) 1820e42d98ebSAlexandre Bounine { 18214aff1ce7SAlexandre Bounine struct rio_mport *mport = arg; 1822e42d98ebSAlexandre Bounine 1823e42d98ebSAlexandre Bounine /* Check that DMA device belongs to the right MPORT */ 18244aff1ce7SAlexandre Bounine return mport == container_of(chan->device, struct rio_mport, dma); 1825e42d98ebSAlexandre Bounine } 1826e42d98ebSAlexandre Bounine 1827e42d98ebSAlexandre Bounine /** 18284aff1ce7SAlexandre Bounine * rio_request_mport_dma - request RapidIO capable DMA channel associated 18294aff1ce7SAlexandre Bounine * with specified local RapidIO mport device. 18304aff1ce7SAlexandre Bounine * @mport: RIO mport to perform DMA data transfers 18314aff1ce7SAlexandre Bounine * 18324aff1ce7SAlexandre Bounine * Returns pointer to allocated DMA channel or NULL if failed. 18334aff1ce7SAlexandre Bounine */ 18344aff1ce7SAlexandre Bounine struct dma_chan *rio_request_mport_dma(struct rio_mport *mport) 18354aff1ce7SAlexandre Bounine { 18364aff1ce7SAlexandre Bounine dma_cap_mask_t mask; 18374aff1ce7SAlexandre Bounine 18384aff1ce7SAlexandre Bounine dma_cap_zero(mask); 18394aff1ce7SAlexandre Bounine dma_cap_set(DMA_SLAVE, mask); 18404aff1ce7SAlexandre Bounine return dma_request_channel(mask, rio_chan_filter, mport); 18414aff1ce7SAlexandre Bounine } 18424aff1ce7SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_request_mport_dma); 18434aff1ce7SAlexandre Bounine 18444aff1ce7SAlexandre Bounine /** 1845e42d98ebSAlexandre Bounine * rio_request_dma - request RapidIO capable DMA channel that supports 1846e42d98ebSAlexandre Bounine * specified target RapidIO device. 18474aff1ce7SAlexandre Bounine * @rdev: RIO device associated with DMA transfer 1848e42d98ebSAlexandre Bounine * 1849e42d98ebSAlexandre Bounine * Returns pointer to allocated DMA channel or NULL if failed. 1850e42d98ebSAlexandre Bounine */ 1851e42d98ebSAlexandre Bounine struct dma_chan *rio_request_dma(struct rio_dev *rdev) 1852e42d98ebSAlexandre Bounine { 18534aff1ce7SAlexandre Bounine return rio_request_mport_dma(rdev->net->hport); 1854e42d98ebSAlexandre Bounine } 1855e42d98ebSAlexandre Bounine EXPORT_SYMBOL_GPL(rio_request_dma); 1856e42d98ebSAlexandre Bounine 1857e42d98ebSAlexandre Bounine /** 1858e42d98ebSAlexandre Bounine * rio_release_dma - release specified DMA channel 1859e42d98ebSAlexandre Bounine * @dchan: DMA channel to release 1860e42d98ebSAlexandre Bounine */ 1861e42d98ebSAlexandre Bounine void rio_release_dma(struct dma_chan *dchan) 1862e42d98ebSAlexandre Bounine { 1863e42d98ebSAlexandre Bounine dma_release_channel(dchan); 1864e42d98ebSAlexandre Bounine } 1865e42d98ebSAlexandre Bounine EXPORT_SYMBOL_GPL(rio_release_dma); 1866e42d98ebSAlexandre Bounine 1867e42d98ebSAlexandre Bounine /** 18684aff1ce7SAlexandre Bounine * rio_dma_prep_xfer - RapidIO specific wrapper 18694aff1ce7SAlexandre Bounine * for device_prep_slave_sg callback defined by DMAENGINE. 18704aff1ce7SAlexandre Bounine * @dchan: DMA channel to configure 18714aff1ce7SAlexandre Bounine * @destid: target RapidIO device destination ID 18724aff1ce7SAlexandre Bounine * @data: RIO specific data descriptor 18734aff1ce7SAlexandre Bounine * @direction: DMA data transfer direction (TO or FROM the device) 18744aff1ce7SAlexandre Bounine * @flags: dmaengine defined flags 18754aff1ce7SAlexandre Bounine * 18764aff1ce7SAlexandre Bounine * Initializes RapidIO capable DMA channel for the specified data transfer. 18774aff1ce7SAlexandre Bounine * Uses DMA channel private extension to pass information related to remote 18784aff1ce7SAlexandre Bounine * target RIO device. 1879f8e3a68cSAlexandre Bounine * 1880f8e3a68cSAlexandre Bounine * Returns: pointer to DMA transaction descriptor if successful, 1881f8e3a68cSAlexandre Bounine * error-valued pointer or NULL if failed. 18824aff1ce7SAlexandre Bounine */ 18834aff1ce7SAlexandre Bounine struct dma_async_tx_descriptor *rio_dma_prep_xfer(struct dma_chan *dchan, 18844aff1ce7SAlexandre Bounine u16 destid, struct rio_dma_data *data, 18854aff1ce7SAlexandre Bounine enum dma_transfer_direction direction, unsigned long flags) 18864aff1ce7SAlexandre Bounine { 18874aff1ce7SAlexandre Bounine struct rio_dma_ext rio_ext; 18884aff1ce7SAlexandre Bounine 188993dd49afSMarkus Elfring if (!dchan->device->device_prep_slave_sg) { 18904aff1ce7SAlexandre Bounine pr_err("%s: prep_rio_sg == NULL\n", __func__); 18914aff1ce7SAlexandre Bounine return NULL; 18924aff1ce7SAlexandre Bounine } 18934aff1ce7SAlexandre Bounine 18944aff1ce7SAlexandre Bounine rio_ext.destid = destid; 18954aff1ce7SAlexandre Bounine rio_ext.rio_addr_u = data->rio_addr_u; 18964aff1ce7SAlexandre Bounine rio_ext.rio_addr = data->rio_addr; 18974aff1ce7SAlexandre Bounine rio_ext.wr_type = data->wr_type; 18984aff1ce7SAlexandre Bounine 18994aff1ce7SAlexandre Bounine return dmaengine_prep_rio_sg(dchan, data->sg, data->sg_len, 19004aff1ce7SAlexandre Bounine direction, flags, &rio_ext); 19014aff1ce7SAlexandre Bounine } 19024aff1ce7SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_dma_prep_xfer); 19034aff1ce7SAlexandre Bounine 19044aff1ce7SAlexandre Bounine /** 1905e42d98ebSAlexandre Bounine * rio_dma_prep_slave_sg - RapidIO specific wrapper 1906e42d98ebSAlexandre Bounine * for device_prep_slave_sg callback defined by DMAENGINE. 1907e42d98ebSAlexandre Bounine * @rdev: RIO device control structure 1908e42d98ebSAlexandre Bounine * @dchan: DMA channel to configure 1909e42d98ebSAlexandre Bounine * @data: RIO specific data descriptor 1910e42d98ebSAlexandre Bounine * @direction: DMA data transfer direction (TO or FROM the device) 1911e42d98ebSAlexandre Bounine * @flags: dmaengine defined flags 1912e42d98ebSAlexandre Bounine * 1913e42d98ebSAlexandre Bounine * Initializes RapidIO capable DMA channel for the specified data transfer. 1914e42d98ebSAlexandre Bounine * Uses DMA channel private extension to pass information related to remote 1915e42d98ebSAlexandre Bounine * target RIO device. 1916f8e3a68cSAlexandre Bounine * 1917f8e3a68cSAlexandre Bounine * Returns: pointer to DMA transaction descriptor if successful, 1918f8e3a68cSAlexandre Bounine * error-valued pointer or NULL if failed. 1919e42d98ebSAlexandre Bounine */ 1920e42d98ebSAlexandre Bounine struct dma_async_tx_descriptor *rio_dma_prep_slave_sg(struct rio_dev *rdev, 1921e42d98ebSAlexandre Bounine struct dma_chan *dchan, struct rio_dma_data *data, 1922e42d98ebSAlexandre Bounine enum dma_transfer_direction direction, unsigned long flags) 1923e42d98ebSAlexandre Bounine { 19244aff1ce7SAlexandre Bounine return rio_dma_prep_xfer(dchan, rdev->destid, data, direction, flags); 1925e42d98ebSAlexandre Bounine } 1926e42d98ebSAlexandre Bounine EXPORT_SYMBOL_GPL(rio_dma_prep_slave_sg); 1927e42d98ebSAlexandre Bounine 1928e42d98ebSAlexandre Bounine #endif /* CONFIG_RAPIDIO_DMA_ENGINE */ 1929e42d98ebSAlexandre Bounine 1930a11650e1SAlexandre Bounine /** 1931bc8fcfeaSAlexandre Bounine * rio_find_mport - find RIO mport by its ID 1932bc8fcfeaSAlexandre Bounine * @mport_id: number (ID) of mport device 1933bc8fcfeaSAlexandre Bounine * 1934bc8fcfeaSAlexandre Bounine * Given a RIO mport number, the desired mport is located 1935bc8fcfeaSAlexandre Bounine * in the global list of mports. If the mport is found, a pointer to its 1936bc8fcfeaSAlexandre Bounine * data structure is returned. If no mport is found, %NULL is returned. 1937bc8fcfeaSAlexandre Bounine */ 1938bc8fcfeaSAlexandre Bounine struct rio_mport *rio_find_mport(int mport_id) 1939bc8fcfeaSAlexandre Bounine { 1940bc8fcfeaSAlexandre Bounine struct rio_mport *port; 1941bc8fcfeaSAlexandre Bounine 1942bc8fcfeaSAlexandre Bounine mutex_lock(&rio_mport_list_lock); 1943bc8fcfeaSAlexandre Bounine list_for_each_entry(port, &rio_mports, node) { 1944bc8fcfeaSAlexandre Bounine if (port->id == mport_id) 1945bc8fcfeaSAlexandre Bounine goto found; 1946bc8fcfeaSAlexandre Bounine } 1947bc8fcfeaSAlexandre Bounine port = NULL; 1948bc8fcfeaSAlexandre Bounine found: 1949bc8fcfeaSAlexandre Bounine mutex_unlock(&rio_mport_list_lock); 1950bc8fcfeaSAlexandre Bounine 1951bc8fcfeaSAlexandre Bounine return port; 1952bc8fcfeaSAlexandre Bounine } 1953bc8fcfeaSAlexandre Bounine 1954bc8fcfeaSAlexandre Bounine /** 1955a11650e1SAlexandre Bounine * rio_register_scan - enumeration/discovery method registration interface 1956a11650e1SAlexandre Bounine * @mport_id: mport device ID for which fabric scan routine has to be set 1957a11650e1SAlexandre Bounine * (RIO_MPORT_ANY = set for all available mports) 19589edbc30bSAlexandre Bounine * @scan_ops: enumeration/discovery operations structure 1959a11650e1SAlexandre Bounine * 19609edbc30bSAlexandre Bounine * Registers enumeration/discovery operations with RapidIO subsystem and 19619edbc30bSAlexandre Bounine * attaches it to the specified mport device (or all available mports 19629edbc30bSAlexandre Bounine * if RIO_MPORT_ANY is specified). 19639edbc30bSAlexandre Bounine * 1964a11650e1SAlexandre Bounine * Returns error if the mport already has an enumerator attached to it. 19659edbc30bSAlexandre Bounine * In case of RIO_MPORT_ANY skips mports with valid scan routines (no error). 1966a11650e1SAlexandre Bounine */ 1967a11650e1SAlexandre Bounine int rio_register_scan(int mport_id, struct rio_scan *scan_ops) 1968a11650e1SAlexandre Bounine { 1969a11650e1SAlexandre Bounine struct rio_mport *port; 19709edbc30bSAlexandre Bounine struct rio_scan_node *scan; 19719edbc30bSAlexandre Bounine int rc = 0; 19729edbc30bSAlexandre Bounine 19739edbc30bSAlexandre Bounine pr_debug("RIO: %s for mport_id=%d\n", __func__, mport_id); 19749edbc30bSAlexandre Bounine 19759edbc30bSAlexandre Bounine if ((mport_id != RIO_MPORT_ANY && mport_id >= RIO_MAX_MPORTS) || 19769edbc30bSAlexandre Bounine !scan_ops) 19779edbc30bSAlexandre Bounine return -EINVAL; 1978a11650e1SAlexandre Bounine 1979a11650e1SAlexandre Bounine mutex_lock(&rio_mport_list_lock); 19809edbc30bSAlexandre Bounine 19819edbc30bSAlexandre Bounine /* 19829edbc30bSAlexandre Bounine * Check if there is another enumerator already registered for 19839edbc30bSAlexandre Bounine * the same mport ID (including RIO_MPORT_ANY). Multiple enumerators 19849edbc30bSAlexandre Bounine * for the same mport ID are not supported. 19859edbc30bSAlexandre Bounine */ 19869edbc30bSAlexandre Bounine list_for_each_entry(scan, &rio_scans, node) { 19879edbc30bSAlexandre Bounine if (scan->mport_id == mport_id) { 19889edbc30bSAlexandre Bounine rc = -EBUSY; 19899edbc30bSAlexandre Bounine goto err_out; 19909edbc30bSAlexandre Bounine } 19919edbc30bSAlexandre Bounine } 19929edbc30bSAlexandre Bounine 19939edbc30bSAlexandre Bounine /* 19949edbc30bSAlexandre Bounine * Allocate and initialize new scan registration node. 19959edbc30bSAlexandre Bounine */ 19969edbc30bSAlexandre Bounine scan = kzalloc(sizeof(*scan), GFP_KERNEL); 19979edbc30bSAlexandre Bounine if (!scan) { 19989edbc30bSAlexandre Bounine rc = -ENOMEM; 19999edbc30bSAlexandre Bounine goto err_out; 20009edbc30bSAlexandre Bounine } 20019edbc30bSAlexandre Bounine 20029edbc30bSAlexandre Bounine scan->mport_id = mport_id; 20039edbc30bSAlexandre Bounine scan->ops = scan_ops; 20049edbc30bSAlexandre Bounine 20059edbc30bSAlexandre Bounine /* 20069edbc30bSAlexandre Bounine * Traverse the list of registered mports to attach this new scan. 20079edbc30bSAlexandre Bounine * 20089edbc30bSAlexandre Bounine * The new scan with matching mport ID overrides any previously attached 20099edbc30bSAlexandre Bounine * scan assuming that old scan (if any) is the default one (based on the 20109edbc30bSAlexandre Bounine * enumerator registration check above). 20119edbc30bSAlexandre Bounine * If the new scan is the global one, it will be attached only to mports 20129edbc30bSAlexandre Bounine * that do not have their own individual operations already attached. 20139edbc30bSAlexandre Bounine */ 2014a11650e1SAlexandre Bounine list_for_each_entry(port, &rio_mports, node) { 20159edbc30bSAlexandre Bounine if (port->id == mport_id) { 2016a11650e1SAlexandre Bounine port->nscan = scan_ops; 2017a11650e1SAlexandre Bounine break; 20189edbc30bSAlexandre Bounine } else if (mport_id == RIO_MPORT_ANY && !port->nscan) 20199edbc30bSAlexandre Bounine port->nscan = scan_ops; 2020a11650e1SAlexandre Bounine } 20219edbc30bSAlexandre Bounine 20229edbc30bSAlexandre Bounine list_add_tail(&scan->node, &rio_scans); 20239edbc30bSAlexandre Bounine 20249edbc30bSAlexandre Bounine err_out: 2025a11650e1SAlexandre Bounine mutex_unlock(&rio_mport_list_lock); 2026a11650e1SAlexandre Bounine 2027a11650e1SAlexandre Bounine return rc; 2028a11650e1SAlexandre Bounine } 2029a11650e1SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_register_scan); 2030a11650e1SAlexandre Bounine 2031a11650e1SAlexandre Bounine /** 2032a11650e1SAlexandre Bounine * rio_unregister_scan - removes enumeration/discovery method from mport 2033a11650e1SAlexandre Bounine * @mport_id: mport device ID for which fabric scan routine has to be 20349edbc30bSAlexandre Bounine * unregistered (RIO_MPORT_ANY = apply to all mports that use 20359edbc30bSAlexandre Bounine * the specified scan_ops) 20369edbc30bSAlexandre Bounine * @scan_ops: enumeration/discovery operations structure 2037a11650e1SAlexandre Bounine * 2038a11650e1SAlexandre Bounine * Removes enumeration or discovery method assigned to the specified mport 20399edbc30bSAlexandre Bounine * device. If RIO_MPORT_ANY is specified, removes the specified operations from 20409edbc30bSAlexandre Bounine * all mports that have them attached. 2041a11650e1SAlexandre Bounine */ 20429edbc30bSAlexandre Bounine int rio_unregister_scan(int mport_id, struct rio_scan *scan_ops) 2043a11650e1SAlexandre Bounine { 2044a11650e1SAlexandre Bounine struct rio_mport *port; 20459edbc30bSAlexandre Bounine struct rio_scan_node *scan; 20469edbc30bSAlexandre Bounine 20479edbc30bSAlexandre Bounine pr_debug("RIO: %s for mport_id=%d\n", __func__, mport_id); 20489edbc30bSAlexandre Bounine 20499edbc30bSAlexandre Bounine if (mport_id != RIO_MPORT_ANY && mport_id >= RIO_MAX_MPORTS) 20509edbc30bSAlexandre Bounine return -EINVAL; 2051a11650e1SAlexandre Bounine 2052a11650e1SAlexandre Bounine mutex_lock(&rio_mport_list_lock); 20539edbc30bSAlexandre Bounine 20549edbc30bSAlexandre Bounine list_for_each_entry(port, &rio_mports, node) 20559edbc30bSAlexandre Bounine if (port->id == mport_id || 20569edbc30bSAlexandre Bounine (mport_id == RIO_MPORT_ANY && port->nscan == scan_ops)) 2057a11650e1SAlexandre Bounine port->nscan = NULL; 20589edbc30bSAlexandre Bounine 2059f93f3c4eSDan Carpenter list_for_each_entry(scan, &rio_scans, node) { 20609edbc30bSAlexandre Bounine if (scan->mport_id == mport_id) { 20619edbc30bSAlexandre Bounine list_del(&scan->node); 20629edbc30bSAlexandre Bounine kfree(scan); 2063f93f3c4eSDan Carpenter break; 2064f93f3c4eSDan Carpenter } 2065a11650e1SAlexandre Bounine } 20669edbc30bSAlexandre Bounine 2067a11650e1SAlexandre Bounine mutex_unlock(&rio_mport_list_lock); 2068a11650e1SAlexandre Bounine 2069a11650e1SAlexandre Bounine return 0; 2070a11650e1SAlexandre Bounine } 2071a11650e1SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_unregister_scan); 2072a11650e1SAlexandre Bounine 20739edbc30bSAlexandre Bounine /** 20749edbc30bSAlexandre Bounine * rio_mport_scan - execute enumeration/discovery on the specified mport 20759edbc30bSAlexandre Bounine * @mport_id: number (ID) of mport device 20769edbc30bSAlexandre Bounine */ 20779edbc30bSAlexandre Bounine int rio_mport_scan(int mport_id) 20789edbc30bSAlexandre Bounine { 20799edbc30bSAlexandre Bounine struct rio_mport *port = NULL; 20809edbc30bSAlexandre Bounine int rc; 20819edbc30bSAlexandre Bounine 20829edbc30bSAlexandre Bounine mutex_lock(&rio_mport_list_lock); 20839edbc30bSAlexandre Bounine list_for_each_entry(port, &rio_mports, node) { 20849edbc30bSAlexandre Bounine if (port->id == mport_id) 20859edbc30bSAlexandre Bounine goto found; 20869edbc30bSAlexandre Bounine } 20879edbc30bSAlexandre Bounine mutex_unlock(&rio_mport_list_lock); 20889edbc30bSAlexandre Bounine return -ENODEV; 20899edbc30bSAlexandre Bounine found: 20909edbc30bSAlexandre Bounine if (!port->nscan) { 20919edbc30bSAlexandre Bounine mutex_unlock(&rio_mport_list_lock); 20929edbc30bSAlexandre Bounine return -EINVAL; 20939edbc30bSAlexandre Bounine } 20949edbc30bSAlexandre Bounine 20959edbc30bSAlexandre Bounine if (!try_module_get(port->nscan->owner)) { 20969edbc30bSAlexandre Bounine mutex_unlock(&rio_mport_list_lock); 20979edbc30bSAlexandre Bounine return -ENODEV; 20989edbc30bSAlexandre Bounine } 20999edbc30bSAlexandre Bounine 21009edbc30bSAlexandre Bounine mutex_unlock(&rio_mport_list_lock); 21019edbc30bSAlexandre Bounine 21029edbc30bSAlexandre Bounine if (port->host_deviceid >= 0) 21039edbc30bSAlexandre Bounine rc = port->nscan->enumerate(port, 0); 21049edbc30bSAlexandre Bounine else 21059edbc30bSAlexandre Bounine rc = port->nscan->discover(port, RIO_SCAN_ENUM_NO_WAIT); 21069edbc30bSAlexandre Bounine 21079edbc30bSAlexandre Bounine module_put(port->nscan->owner); 21089edbc30bSAlexandre Bounine return rc; 21099edbc30bSAlexandre Bounine } 21109edbc30bSAlexandre Bounine 2111394b701cSMatt Porter static void rio_fixup_device(struct rio_dev *dev) 2112394b701cSMatt Porter { 2113394b701cSMatt Porter } 2114394b701cSMatt Porter 2115305c891eSBill Pemberton static int rio_init(void) 2116394b701cSMatt Porter { 2117394b701cSMatt Porter struct rio_dev *dev = NULL; 2118394b701cSMatt Porter 2119394b701cSMatt Porter while ((dev = rio_get_device(RIO_ANY_ID, RIO_ANY_ID, dev)) != NULL) { 2120394b701cSMatt Porter rio_fixup_device(dev); 2121394b701cSMatt Porter } 2122394b701cSMatt Porter return 0; 2123394b701cSMatt Porter } 2124394b701cSMatt Porter 2125005842efSAlexandre Bounine static struct workqueue_struct *rio_wq; 2126005842efSAlexandre Bounine 2127005842efSAlexandre Bounine struct rio_disc_work { 2128005842efSAlexandre Bounine struct work_struct work; 2129005842efSAlexandre Bounine struct rio_mport *mport; 2130005842efSAlexandre Bounine }; 2131005842efSAlexandre Bounine 2132305c891eSBill Pemberton static void disc_work_handler(struct work_struct *_work) 2133005842efSAlexandre Bounine { 2134005842efSAlexandre Bounine struct rio_disc_work *work; 2135005842efSAlexandre Bounine 2136005842efSAlexandre Bounine work = container_of(_work, struct rio_disc_work, work); 2137005842efSAlexandre Bounine pr_debug("RIO: discovery work for mport %d %s\n", 2138005842efSAlexandre Bounine work->mport->id, work->mport->name); 21399edbc30bSAlexandre Bounine if (try_module_get(work->mport->nscan->owner)) { 2140bc8fcfeaSAlexandre Bounine work->mport->nscan->discover(work->mport, 0); 21419edbc30bSAlexandre Bounine module_put(work->mport->nscan->owner); 21429edbc30bSAlexandre Bounine } 2143005842efSAlexandre Bounine } 2144005842efSAlexandre Bounine 2145305c891eSBill Pemberton int rio_init_mports(void) 2146394b701cSMatt Porter { 2147394b701cSMatt Porter struct rio_mport *port; 2148005842efSAlexandre Bounine struct rio_disc_work *work; 21492574740dSAlexandre Bounine int n = 0; 2150394b701cSMatt Porter 21512574740dSAlexandre Bounine if (!next_portid) 21522574740dSAlexandre Bounine return -ENODEV; 21532574740dSAlexandre Bounine 21542574740dSAlexandre Bounine /* 21552574740dSAlexandre Bounine * First, run enumerations and check if we need to perform discovery 21562574740dSAlexandre Bounine * on any of the registered mports. 21572574740dSAlexandre Bounine */ 2158a11650e1SAlexandre Bounine mutex_lock(&rio_mport_list_lock); 2159394b701cSMatt Porter list_for_each_entry(port, &rio_mports, node) { 2160a11650e1SAlexandre Bounine if (port->host_deviceid >= 0) { 21619edbc30bSAlexandre Bounine if (port->nscan && try_module_get(port->nscan->owner)) { 2162bc8fcfeaSAlexandre Bounine port->nscan->enumerate(port, 0); 21639edbc30bSAlexandre Bounine module_put(port->nscan->owner); 21649edbc30bSAlexandre Bounine } 2165a11650e1SAlexandre Bounine } else 21662574740dSAlexandre Bounine n++; 21672574740dSAlexandre Bounine } 2168a11650e1SAlexandre Bounine mutex_unlock(&rio_mport_list_lock); 21692574740dSAlexandre Bounine 21702574740dSAlexandre Bounine if (!n) 21712574740dSAlexandre Bounine goto no_disc; 21722574740dSAlexandre Bounine 21732574740dSAlexandre Bounine /* 21742574740dSAlexandre Bounine * If we have mports that require discovery schedule a discovery work 21752574740dSAlexandre Bounine * for each of them. If the code below fails to allocate needed 21762574740dSAlexandre Bounine * resources, exit without error to keep results of enumeration 21772574740dSAlexandre Bounine * process (if any). 21789edbc30bSAlexandre Bounine * TODO: Implement restart of discovery process for all or 21792574740dSAlexandre Bounine * individual discovering mports. 21802574740dSAlexandre Bounine */ 2181005842efSAlexandre Bounine rio_wq = alloc_workqueue("riodisc", 0, 0); 2182005842efSAlexandre Bounine if (!rio_wq) { 2183005842efSAlexandre Bounine pr_err("RIO: unable allocate rio_wq\n"); 21842574740dSAlexandre Bounine goto no_disc; 2185005842efSAlexandre Bounine } 2186005842efSAlexandre Bounine 21872574740dSAlexandre Bounine work = kcalloc(n, sizeof *work, GFP_KERNEL); 2188005842efSAlexandre Bounine if (!work) { 2189005842efSAlexandre Bounine destroy_workqueue(rio_wq); 21902574740dSAlexandre Bounine goto no_disc; 2191394b701cSMatt Porter } 2192394b701cSMatt Porter 21932574740dSAlexandre Bounine n = 0; 2194a11650e1SAlexandre Bounine mutex_lock(&rio_mport_list_lock); 21952574740dSAlexandre Bounine list_for_each_entry(port, &rio_mports, node) { 2196a11650e1SAlexandre Bounine if (port->host_deviceid < 0 && port->nscan) { 21972574740dSAlexandre Bounine work[n].mport = port; 21982574740dSAlexandre Bounine INIT_WORK(&work[n].work, disc_work_handler); 21992574740dSAlexandre Bounine queue_work(rio_wq, &work[n].work); 22002574740dSAlexandre Bounine n++; 22012574740dSAlexandre Bounine } 22022574740dSAlexandre Bounine } 22032574740dSAlexandre Bounine 22042574740dSAlexandre Bounine flush_workqueue(rio_wq); 22059edbc30bSAlexandre Bounine mutex_unlock(&rio_mport_list_lock); 22062574740dSAlexandre Bounine pr_debug("RIO: destroy discovery workqueue\n"); 22072574740dSAlexandre Bounine destroy_workqueue(rio_wq); 22082574740dSAlexandre Bounine kfree(work); 22092574740dSAlexandre Bounine 22102574740dSAlexandre Bounine no_disc: 22112f809985SAlexandre Bounine rio_init(); 22122f809985SAlexandre Bounine 2213c1256ebeSAlexandre Bounine return 0; 2214394b701cSMatt Porter } 2215394b701cSMatt Porter 2216569fccb6SAlexandre Bounine static int rio_get_hdid(int index) 2217569fccb6SAlexandre Bounine { 2218fdf90abcSAlexandre Bounine if (ids_num == 0 || ids_num <= index || index >= RIO_MAX_MPORTS) 2219569fccb6SAlexandre Bounine return -1; 2220569fccb6SAlexandre Bounine 2221fdf90abcSAlexandre Bounine return hdid[index]; 2222569fccb6SAlexandre Bounine } 2223569fccb6SAlexandre Bounine 2224b77a2030SAlexandre Bounine int rio_mport_initialize(struct rio_mport *mport) 2225b77a2030SAlexandre Bounine { 2226b77a2030SAlexandre Bounine if (next_portid >= RIO_MAX_MPORTS) { 2227b77a2030SAlexandre Bounine pr_err("RIO: reached specified max number of mports\n"); 2228b77a2030SAlexandre Bounine return -ENODEV; 2229b77a2030SAlexandre Bounine } 2230b77a2030SAlexandre Bounine 2231b77a2030SAlexandre Bounine atomic_set(&mport->state, RIO_DEVICE_INITIALIZING); 2232b77a2030SAlexandre Bounine mport->id = next_portid++; 2233b77a2030SAlexandre Bounine mport->host_deviceid = rio_get_hdid(mport->id); 2234b77a2030SAlexandre Bounine mport->nscan = NULL; 2235a7b4c636SAlexandre Bounine mutex_init(&mport->lock); 2236b6cb95e8SAlexandre Bounine mport->pwe_refcnt = 0; 22379a0b0627SAlexandre Bounine INIT_LIST_HEAD(&mport->pwrites); 2238b77a2030SAlexandre Bounine 2239b77a2030SAlexandre Bounine return 0; 2240b77a2030SAlexandre Bounine } 2241b77a2030SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_mport_initialize); 2242b77a2030SAlexandre Bounine 224359f99965SAlexandre Bounine int rio_register_mport(struct rio_mport *port) 2244394b701cSMatt Porter { 22459edbc30bSAlexandre Bounine struct rio_scan_node *scan = NULL; 22462aaf308bSAlexandre Bounine int res = 0; 22479edbc30bSAlexandre Bounine 2248a11650e1SAlexandre Bounine mutex_lock(&rio_mport_list_lock); 22499edbc30bSAlexandre Bounine 22509edbc30bSAlexandre Bounine /* 22519edbc30bSAlexandre Bounine * Check if there are any registered enumeration/discovery operations 22529edbc30bSAlexandre Bounine * that have to be attached to the added mport. 22539edbc30bSAlexandre Bounine */ 22549edbc30bSAlexandre Bounine list_for_each_entry(scan, &rio_scans, node) { 22559edbc30bSAlexandre Bounine if (port->id == scan->mport_id || 22569edbc30bSAlexandre Bounine scan->mport_id == RIO_MPORT_ANY) { 22579edbc30bSAlexandre Bounine port->nscan = scan->ops; 22589edbc30bSAlexandre Bounine if (port->id == scan->mport_id) 22599edbc30bSAlexandre Bounine break; 22609edbc30bSAlexandre Bounine } 22619edbc30bSAlexandre Bounine } 2262b77a2030SAlexandre Bounine 2263b77a2030SAlexandre Bounine list_add_tail(&port->node, &rio_mports); 2264a11650e1SAlexandre Bounine mutex_unlock(&rio_mport_list_lock); 22659edbc30bSAlexandre Bounine 2266b77a2030SAlexandre Bounine dev_set_name(&port->dev, "rapidio%d", port->id); 2267b77a2030SAlexandre Bounine port->dev.class = &rio_mport_class; 2268b77a2030SAlexandre Bounine atomic_set(&port->state, RIO_DEVICE_RUNNING); 2269b77a2030SAlexandre Bounine 2270b77a2030SAlexandre Bounine res = device_register(&port->dev); 2271b77a2030SAlexandre Bounine if (res) 2272b77a2030SAlexandre Bounine dev_err(&port->dev, "RIO: mport%d registration failed ERR=%d\n", 2273b77a2030SAlexandre Bounine port->id, res); 2274b77a2030SAlexandre Bounine else 2275b77a2030SAlexandre Bounine dev_dbg(&port->dev, "RIO: registered mport%d\n", port->id); 2276b77a2030SAlexandre Bounine 2277b77a2030SAlexandre Bounine return res; 2278394b701cSMatt Porter } 227994d9bd45SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_register_mport); 2280394b701cSMatt Porter 2281b77a2030SAlexandre Bounine static int rio_mport_cleanup_callback(struct device *dev, void *data) 2282b77a2030SAlexandre Bounine { 2283b77a2030SAlexandre Bounine struct rio_dev *rdev = to_rio_dev(dev); 2284b77a2030SAlexandre Bounine 2285b77a2030SAlexandre Bounine if (dev->bus == &rio_bus_type) 2286b77a2030SAlexandre Bounine rio_del_device(rdev, RIO_DEVICE_SHUTDOWN); 2287b77a2030SAlexandre Bounine return 0; 2288b77a2030SAlexandre Bounine } 2289b77a2030SAlexandre Bounine 2290b77a2030SAlexandre Bounine static int rio_net_remove_children(struct rio_net *net) 2291b77a2030SAlexandre Bounine { 2292b77a2030SAlexandre Bounine /* 2293b77a2030SAlexandre Bounine * Unregister all RapidIO devices residing on this net (this will 2294b77a2030SAlexandre Bounine * invoke notification of registered subsystem interfaces as well). 2295b77a2030SAlexandre Bounine */ 2296b77a2030SAlexandre Bounine device_for_each_child(&net->dev, NULL, rio_mport_cleanup_callback); 2297b77a2030SAlexandre Bounine return 0; 2298b77a2030SAlexandre Bounine } 2299b77a2030SAlexandre Bounine 2300b77a2030SAlexandre Bounine int rio_unregister_mport(struct rio_mport *port) 2301b77a2030SAlexandre Bounine { 2302b77a2030SAlexandre Bounine pr_debug("RIO: %s %s id=%d\n", __func__, port->name, port->id); 2303b77a2030SAlexandre Bounine 2304b77a2030SAlexandre Bounine /* Transition mport to the SHUTDOWN state */ 2305b77a2030SAlexandre Bounine if (atomic_cmpxchg(&port->state, 2306b77a2030SAlexandre Bounine RIO_DEVICE_RUNNING, 2307b77a2030SAlexandre Bounine RIO_DEVICE_SHUTDOWN) != RIO_DEVICE_RUNNING) { 2308b77a2030SAlexandre Bounine pr_err("RIO: %s unexpected state transition for mport %s\n", 2309b77a2030SAlexandre Bounine __func__, port->name); 2310b77a2030SAlexandre Bounine } 2311b77a2030SAlexandre Bounine 2312b77a2030SAlexandre Bounine if (port->net && port->net->hport == port) { 2313b77a2030SAlexandre Bounine rio_net_remove_children(port->net); 2314b77a2030SAlexandre Bounine rio_free_net(port->net); 2315b77a2030SAlexandre Bounine } 2316b77a2030SAlexandre Bounine 2317b77a2030SAlexandre Bounine /* 2318b77a2030SAlexandre Bounine * Unregister all RapidIO devices attached to this mport (this will 2319b77a2030SAlexandre Bounine * invoke notification of registered subsystem interfaces as well). 2320b77a2030SAlexandre Bounine */ 2321b77a2030SAlexandre Bounine mutex_lock(&rio_mport_list_lock); 2322b77a2030SAlexandre Bounine list_del(&port->node); 2323b77a2030SAlexandre Bounine mutex_unlock(&rio_mport_list_lock); 2324b77a2030SAlexandre Bounine device_unregister(&port->dev); 2325b77a2030SAlexandre Bounine 2326b77a2030SAlexandre Bounine return 0; 2327b77a2030SAlexandre Bounine } 2328b77a2030SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_unregister_mport); 2329b77a2030SAlexandre Bounine 2330394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_local_get_device_id); 2331394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_get_device); 2332394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_get_asm); 2333394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_request_inb_dbell); 2334394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_release_inb_dbell); 2335394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_request_outb_dbell); 2336394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_release_outb_dbell); 2337394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_request_inb_mbox); 2338394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_release_inb_mbox); 2339394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_request_outb_mbox); 2340394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_release_outb_mbox); 2341a11650e1SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_init_mports); 2342