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 { 113e6b585caSAlexandre Bounine struct rio_net *net; 114e6b585caSAlexandre Bounine 115e6b585caSAlexandre Bounine net = kzalloc(sizeof(struct rio_net), GFP_KERNEL); 116e6b585caSAlexandre Bounine if (net) { 117e6b585caSAlexandre Bounine INIT_LIST_HEAD(&net->node); 118e6b585caSAlexandre Bounine INIT_LIST_HEAD(&net->devices); 119e6b585caSAlexandre Bounine INIT_LIST_HEAD(&net->switches); 120e6b585caSAlexandre Bounine INIT_LIST_HEAD(&net->mports); 121e6b585caSAlexandre Bounine mport->net = net; 122e6b585caSAlexandre Bounine } 123e6b585caSAlexandre Bounine return net; 124e6b585caSAlexandre Bounine } 125e6b585caSAlexandre Bounine EXPORT_SYMBOL_GPL(rio_alloc_net); 126e6b585caSAlexandre Bounine 127e6b585caSAlexandre Bounine int rio_add_net(struct rio_net *net) 128e6b585caSAlexandre Bounine { 129e6b585caSAlexandre Bounine int err; 130e6b585caSAlexandre Bounine 131e6b585caSAlexandre Bounine err = device_register(&net->dev); 132e6b585caSAlexandre Bounine if (err) 133e6b585caSAlexandre Bounine return err; 134e6b585caSAlexandre Bounine spin_lock(&rio_global_list_lock); 135e6b585caSAlexandre Bounine list_add_tail(&net->node, &rio_nets); 136e6b585caSAlexandre Bounine spin_unlock(&rio_global_list_lock); 137e6b585caSAlexandre Bounine 138e6b585caSAlexandre Bounine return 0; 139e6b585caSAlexandre Bounine } 140e6b585caSAlexandre Bounine EXPORT_SYMBOL_GPL(rio_add_net); 141e6b585caSAlexandre Bounine 142e6b585caSAlexandre Bounine void rio_free_net(struct rio_net *net) 143e6b585caSAlexandre Bounine { 144e6b585caSAlexandre Bounine spin_lock(&rio_global_list_lock); 145e6b585caSAlexandre Bounine if (!list_empty(&net->node)) 146e6b585caSAlexandre Bounine list_del(&net->node); 147e6b585caSAlexandre Bounine spin_unlock(&rio_global_list_lock); 148e6b585caSAlexandre Bounine if (net->release) 149e6b585caSAlexandre Bounine net->release(net); 150e6b585caSAlexandre Bounine device_unregister(&net->dev); 151e6b585caSAlexandre Bounine } 152e6b585caSAlexandre Bounine EXPORT_SYMBOL_GPL(rio_free_net); 153e6b585caSAlexandre Bounine 154e6b585caSAlexandre Bounine /** 1555024622fSAlexandre Bounine * rio_local_set_device_id - Set the base/extended device id for a port 1565024622fSAlexandre Bounine * @port: RIO master port 1575024622fSAlexandre Bounine * @did: Device ID value to be written 1585024622fSAlexandre Bounine * 1595024622fSAlexandre Bounine * Writes the base/extended device id from a device. 1605024622fSAlexandre Bounine */ 1615024622fSAlexandre Bounine void rio_local_set_device_id(struct rio_mport *port, u16 did) 1625024622fSAlexandre Bounine { 1635024622fSAlexandre Bounine rio_local_write_config_32(port, RIO_DID_CSR, 1645024622fSAlexandre Bounine RIO_SET_DID(port->sys_size, did)); 1655024622fSAlexandre Bounine } 1665024622fSAlexandre Bounine EXPORT_SYMBOL_GPL(rio_local_set_device_id); 1675024622fSAlexandre Bounine 1685024622fSAlexandre Bounine /** 169a11650e1SAlexandre Bounine * rio_add_device- Adds a RIO device to the device model 170a11650e1SAlexandre Bounine * @rdev: RIO device 171a11650e1SAlexandre Bounine * 172a11650e1SAlexandre Bounine * Adds the RIO device to the global device list and adds the RIO 173a11650e1SAlexandre Bounine * device to the RIO device list. Creates the generic sysfs nodes 174a11650e1SAlexandre Bounine * for an RIO device. 175a11650e1SAlexandre Bounine */ 176a11650e1SAlexandre Bounine int rio_add_device(struct rio_dev *rdev) 177a11650e1SAlexandre Bounine { 178a11650e1SAlexandre Bounine int err; 179a11650e1SAlexandre Bounine 180b77a2030SAlexandre Bounine atomic_set(&rdev->state, RIO_DEVICE_RUNNING); 181b74ec56eSAlexandre Bounine err = device_register(&rdev->dev); 182a11650e1SAlexandre Bounine if (err) 183a11650e1SAlexandre Bounine return err; 184a11650e1SAlexandre Bounine 185a11650e1SAlexandre Bounine spin_lock(&rio_global_list_lock); 186a11650e1SAlexandre Bounine list_add_tail(&rdev->global_list, &rio_devices); 187b74ec56eSAlexandre Bounine if (rdev->net) { 188b74ec56eSAlexandre Bounine list_add_tail(&rdev->net_list, &rdev->net->devices); 189b74ec56eSAlexandre Bounine if (rdev->pef & RIO_PEF_SWITCH) 190b74ec56eSAlexandre Bounine list_add_tail(&rdev->rswitch->node, 191b74ec56eSAlexandre Bounine &rdev->net->switches); 192b74ec56eSAlexandre Bounine } 193a11650e1SAlexandre Bounine spin_unlock(&rio_global_list_lock); 194a11650e1SAlexandre Bounine 195a11650e1SAlexandre Bounine return 0; 196a11650e1SAlexandre Bounine } 197a11650e1SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_add_device); 198a11650e1SAlexandre Bounine 199b74ec56eSAlexandre Bounine /* 200b74ec56eSAlexandre Bounine * rio_del_device - removes a RIO device from the device model 201b74ec56eSAlexandre Bounine * @rdev: RIO device 202b77a2030SAlexandre Bounine * @state: device state to set during removal process 203b74ec56eSAlexandre Bounine * 204b74ec56eSAlexandre Bounine * Removes the RIO device to the kernel device list and subsystem's device list. 205b74ec56eSAlexandre Bounine * Clears sysfs entries for the removed device. 206b74ec56eSAlexandre Bounine */ 207b77a2030SAlexandre Bounine void rio_del_device(struct rio_dev *rdev, enum rio_device_state state) 208b74ec56eSAlexandre Bounine { 209b74ec56eSAlexandre Bounine pr_debug("RIO: %s: removing %s\n", __func__, rio_name(rdev)); 210b77a2030SAlexandre Bounine atomic_set(&rdev->state, state); 211b74ec56eSAlexandre Bounine spin_lock(&rio_global_list_lock); 212b74ec56eSAlexandre Bounine list_del(&rdev->global_list); 213b74ec56eSAlexandre Bounine if (rdev->net) { 214b74ec56eSAlexandre Bounine list_del(&rdev->net_list); 215b74ec56eSAlexandre Bounine if (rdev->pef & RIO_PEF_SWITCH) { 216b74ec56eSAlexandre Bounine list_del(&rdev->rswitch->node); 217b74ec56eSAlexandre Bounine kfree(rdev->rswitch->route_table); 218b74ec56eSAlexandre Bounine } 219b74ec56eSAlexandre Bounine } 220b74ec56eSAlexandre Bounine spin_unlock(&rio_global_list_lock); 221b74ec56eSAlexandre Bounine device_unregister(&rdev->dev); 222b74ec56eSAlexandre Bounine } 223b74ec56eSAlexandre Bounine EXPORT_SYMBOL_GPL(rio_del_device); 224b74ec56eSAlexandre Bounine 225a11650e1SAlexandre Bounine /** 226394b701cSMatt Porter * rio_request_inb_mbox - request inbound mailbox service 227394b701cSMatt Porter * @mport: RIO master port from which to allocate the mailbox resource 2286978bbc0SMatt Porter * @dev_id: Device specific pointer to pass on event 229394b701cSMatt Porter * @mbox: Mailbox number to claim 230394b701cSMatt Porter * @entries: Number of entries in inbound mailbox queue 231394b701cSMatt Porter * @minb: Callback to execute when inbound message is received 232394b701cSMatt Porter * 233394b701cSMatt Porter * Requests ownership of an inbound mailbox resource and binds 234394b701cSMatt Porter * a callback function to the resource. Returns %0 on success. 235394b701cSMatt Porter */ 236394b701cSMatt Porter int rio_request_inb_mbox(struct rio_mport *mport, 2376978bbc0SMatt Porter void *dev_id, 238394b701cSMatt Porter int mbox, 239394b701cSMatt Porter int entries, 2406978bbc0SMatt Porter void (*minb) (struct rio_mport * mport, void *dev_id, int mbox, 241394b701cSMatt Porter int slot)) 242394b701cSMatt Porter { 243f8f06269SAlexandre Bounine int rc = -ENOSYS; 244f8f06269SAlexandre Bounine struct resource *res; 245394b701cSMatt Porter 24693dd49afSMarkus Elfring if (!mport->ops->open_inb_mbox) 247f8f06269SAlexandre Bounine goto out; 248f8f06269SAlexandre Bounine 2499a975beeSToshi Kani res = kzalloc(sizeof(struct resource), GFP_KERNEL); 250394b701cSMatt Porter 251394b701cSMatt Porter if (res) { 252394b701cSMatt Porter rio_init_mbox_res(res, mbox, mbox); 253394b701cSMatt Porter 254394b701cSMatt Porter /* Make sure this mailbox isn't in use */ 255394b701cSMatt Porter if ((rc = 256394b701cSMatt Porter request_resource(&mport->riores[RIO_INB_MBOX_RESOURCE], 257394b701cSMatt Porter res)) < 0) { 258394b701cSMatt Porter kfree(res); 259394b701cSMatt Porter goto out; 260394b701cSMatt Porter } 261394b701cSMatt Porter 262394b701cSMatt Porter mport->inb_msg[mbox].res = res; 263394b701cSMatt Porter 264394b701cSMatt Porter /* Hook the inbound message callback */ 265394b701cSMatt Porter mport->inb_msg[mbox].mcback = minb; 266394b701cSMatt Porter 267f8f06269SAlexandre Bounine rc = mport->ops->open_inb_mbox(mport, dev_id, mbox, entries); 26806e1b249SAlexandre Bounine if (rc) { 26906e1b249SAlexandre Bounine mport->inb_msg[mbox].mcback = NULL; 27006e1b249SAlexandre Bounine mport->inb_msg[mbox].res = NULL; 27106e1b249SAlexandre Bounine release_resource(res); 27206e1b249SAlexandre Bounine kfree(res); 27306e1b249SAlexandre Bounine } 274394b701cSMatt Porter } else 275394b701cSMatt Porter rc = -ENOMEM; 276394b701cSMatt Porter 277394b701cSMatt Porter out: 278394b701cSMatt Porter return rc; 279394b701cSMatt Porter } 280394b701cSMatt Porter 281394b701cSMatt Porter /** 282394b701cSMatt Porter * rio_release_inb_mbox - release inbound mailbox message service 283394b701cSMatt Porter * @mport: RIO master port from which to release the mailbox resource 284394b701cSMatt Porter * @mbox: Mailbox number to release 285394b701cSMatt Porter * 286394b701cSMatt Porter * Releases ownership of an inbound mailbox resource. Returns 0 287394b701cSMatt Porter * if the request has been satisfied. 288394b701cSMatt Porter */ 289394b701cSMatt Porter int rio_release_inb_mbox(struct rio_mport *mport, int mbox) 290394b701cSMatt Porter { 29106e1b249SAlexandre Bounine int rc; 292394b701cSMatt Porter 29306e1b249SAlexandre Bounine if (!mport->ops->close_inb_mbox || !mport->inb_msg[mbox].res) 29406e1b249SAlexandre Bounine return -EINVAL; 29506e1b249SAlexandre Bounine 29606e1b249SAlexandre Bounine mport->ops->close_inb_mbox(mport, mbox); 29706e1b249SAlexandre Bounine mport->inb_msg[mbox].mcback = NULL; 29806e1b249SAlexandre Bounine 29906e1b249SAlexandre Bounine rc = release_resource(mport->inb_msg[mbox].res); 30006e1b249SAlexandre Bounine if (rc) 30106e1b249SAlexandre Bounine return rc; 30206e1b249SAlexandre Bounine 30306e1b249SAlexandre Bounine kfree(mport->inb_msg[mbox].res); 30406e1b249SAlexandre Bounine mport->inb_msg[mbox].res = NULL; 30506e1b249SAlexandre Bounine 30606e1b249SAlexandre Bounine return 0; 307394b701cSMatt Porter } 308394b701cSMatt Porter 309394b701cSMatt Porter /** 310394b701cSMatt Porter * rio_request_outb_mbox - request outbound mailbox service 311394b701cSMatt Porter * @mport: RIO master port from which to allocate the mailbox resource 3126978bbc0SMatt Porter * @dev_id: Device specific pointer to pass on event 313394b701cSMatt Porter * @mbox: Mailbox number to claim 314394b701cSMatt Porter * @entries: Number of entries in outbound mailbox queue 315394b701cSMatt Porter * @moutb: Callback to execute when outbound message is sent 316394b701cSMatt Porter * 317394b701cSMatt Porter * Requests ownership of an outbound mailbox resource and binds 318394b701cSMatt Porter * a callback function to the resource. Returns 0 on success. 319394b701cSMatt Porter */ 320394b701cSMatt Porter int rio_request_outb_mbox(struct rio_mport *mport, 3216978bbc0SMatt Porter void *dev_id, 322394b701cSMatt Porter int mbox, 323394b701cSMatt Porter int entries, 3246978bbc0SMatt Porter void (*moutb) (struct rio_mport * mport, void *dev_id, int mbox, int slot)) 325394b701cSMatt Porter { 326f8f06269SAlexandre Bounine int rc = -ENOSYS; 327f8f06269SAlexandre Bounine struct resource *res; 328394b701cSMatt Porter 32993dd49afSMarkus Elfring if (!mport->ops->open_outb_mbox) 330f8f06269SAlexandre Bounine goto out; 331f8f06269SAlexandre Bounine 3329a975beeSToshi Kani res = kzalloc(sizeof(struct resource), GFP_KERNEL); 333394b701cSMatt Porter 334394b701cSMatt Porter if (res) { 335394b701cSMatt Porter rio_init_mbox_res(res, mbox, mbox); 336394b701cSMatt Porter 337394b701cSMatt Porter /* Make sure this outbound mailbox isn't in use */ 338394b701cSMatt Porter if ((rc = 339394b701cSMatt Porter request_resource(&mport->riores[RIO_OUTB_MBOX_RESOURCE], 340394b701cSMatt Porter res)) < 0) { 341394b701cSMatt Porter kfree(res); 342394b701cSMatt Porter goto out; 343394b701cSMatt Porter } 344394b701cSMatt Porter 345394b701cSMatt Porter mport->outb_msg[mbox].res = res; 346394b701cSMatt Porter 347394b701cSMatt Porter /* Hook the inbound message callback */ 348394b701cSMatt Porter mport->outb_msg[mbox].mcback = moutb; 349394b701cSMatt Porter 350f8f06269SAlexandre Bounine rc = mport->ops->open_outb_mbox(mport, dev_id, mbox, entries); 35106e1b249SAlexandre Bounine if (rc) { 35206e1b249SAlexandre Bounine mport->outb_msg[mbox].mcback = NULL; 35306e1b249SAlexandre Bounine mport->outb_msg[mbox].res = NULL; 35406e1b249SAlexandre Bounine release_resource(res); 35506e1b249SAlexandre Bounine kfree(res); 35606e1b249SAlexandre Bounine } 357394b701cSMatt Porter } else 358394b701cSMatt Porter rc = -ENOMEM; 359394b701cSMatt Porter 360394b701cSMatt Porter out: 361394b701cSMatt Porter return rc; 362394b701cSMatt Porter } 363394b701cSMatt Porter 364394b701cSMatt Porter /** 365394b701cSMatt Porter * rio_release_outb_mbox - release outbound mailbox message service 366394b701cSMatt Porter * @mport: RIO master port from which to release the mailbox resource 367394b701cSMatt Porter * @mbox: Mailbox number to release 368394b701cSMatt Porter * 369394b701cSMatt Porter * Releases ownership of an inbound mailbox resource. Returns 0 370394b701cSMatt Porter * if the request has been satisfied. 371394b701cSMatt Porter */ 372394b701cSMatt Porter int rio_release_outb_mbox(struct rio_mport *mport, int mbox) 373394b701cSMatt Porter { 37406e1b249SAlexandre Bounine int rc; 375394b701cSMatt Porter 37606e1b249SAlexandre Bounine if (!mport->ops->close_outb_mbox || !mport->outb_msg[mbox].res) 37706e1b249SAlexandre Bounine return -EINVAL; 37806e1b249SAlexandre Bounine 37906e1b249SAlexandre Bounine mport->ops->close_outb_mbox(mport, mbox); 38006e1b249SAlexandre Bounine mport->outb_msg[mbox].mcback = NULL; 38106e1b249SAlexandre Bounine 38206e1b249SAlexandre Bounine rc = release_resource(mport->outb_msg[mbox].res); 38306e1b249SAlexandre Bounine if (rc) 38406e1b249SAlexandre Bounine return rc; 38506e1b249SAlexandre Bounine 38606e1b249SAlexandre Bounine kfree(mport->outb_msg[mbox].res); 38706e1b249SAlexandre Bounine mport->outb_msg[mbox].res = NULL; 38806e1b249SAlexandre Bounine 38906e1b249SAlexandre Bounine return 0; 390394b701cSMatt Porter } 391394b701cSMatt Porter 392394b701cSMatt Porter /** 393394b701cSMatt Porter * rio_setup_inb_dbell - bind inbound doorbell callback 394394b701cSMatt Porter * @mport: RIO master port to bind the doorbell callback 3956978bbc0SMatt Porter * @dev_id: Device specific pointer to pass on event 396394b701cSMatt Porter * @res: Doorbell message resource 397394b701cSMatt Porter * @dinb: Callback to execute when doorbell is received 398394b701cSMatt Porter * 399394b701cSMatt Porter * Adds a doorbell resource/callback pair into a port's 400394b701cSMatt Porter * doorbell event list. Returns 0 if the request has been 401394b701cSMatt Porter * satisfied. 402394b701cSMatt Porter */ 403394b701cSMatt Porter static int 4046978bbc0SMatt Porter rio_setup_inb_dbell(struct rio_mport *mport, void *dev_id, struct resource *res, 4056978bbc0SMatt Porter void (*dinb) (struct rio_mport * mport, void *dev_id, u16 src, u16 dst, 406394b701cSMatt Porter u16 info)) 407394b701cSMatt Porter { 408394b701cSMatt Porter int rc = 0; 409394b701cSMatt Porter struct rio_dbell *dbell; 410394b701cSMatt Porter 411394b701cSMatt Porter if (!(dbell = kmalloc(sizeof(struct rio_dbell), GFP_KERNEL))) { 412394b701cSMatt Porter rc = -ENOMEM; 413394b701cSMatt Porter goto out; 414394b701cSMatt Porter } 415394b701cSMatt Porter 416394b701cSMatt Porter dbell->res = res; 417394b701cSMatt Porter dbell->dinb = dinb; 4186978bbc0SMatt Porter dbell->dev_id = dev_id; 419394b701cSMatt Porter 420a7b4c636SAlexandre Bounine mutex_lock(&mport->lock); 421394b701cSMatt Porter list_add_tail(&dbell->node, &mport->dbells); 422a7b4c636SAlexandre Bounine mutex_unlock(&mport->lock); 423394b701cSMatt Porter 424394b701cSMatt Porter out: 425394b701cSMatt Porter return rc; 426394b701cSMatt Porter } 427394b701cSMatt Porter 428394b701cSMatt Porter /** 429394b701cSMatt Porter * rio_request_inb_dbell - request inbound doorbell message service 430394b701cSMatt Porter * @mport: RIO master port from which to allocate the doorbell resource 4316978bbc0SMatt Porter * @dev_id: Device specific pointer to pass on event 432394b701cSMatt Porter * @start: Doorbell info range start 433394b701cSMatt Porter * @end: Doorbell info range end 434394b701cSMatt Porter * @dinb: Callback to execute when doorbell is received 435394b701cSMatt Porter * 436394b701cSMatt Porter * Requests ownership of an inbound doorbell resource and binds 437394b701cSMatt Porter * a callback function to the resource. Returns 0 if the request 438394b701cSMatt Porter * has been satisfied. 439394b701cSMatt Porter */ 440394b701cSMatt Porter int rio_request_inb_dbell(struct rio_mport *mport, 4416978bbc0SMatt Porter void *dev_id, 442394b701cSMatt Porter u16 start, 443394b701cSMatt Porter u16 end, 4446978bbc0SMatt Porter void (*dinb) (struct rio_mport * mport, void *dev_id, u16 src, 445394b701cSMatt Porter u16 dst, u16 info)) 446394b701cSMatt Porter { 447394b701cSMatt Porter int rc = 0; 448394b701cSMatt Porter 4499a975beeSToshi Kani struct resource *res = kzalloc(sizeof(struct resource), GFP_KERNEL); 450394b701cSMatt Porter 451394b701cSMatt Porter if (res) { 452394b701cSMatt Porter rio_init_dbell_res(res, start, end); 453394b701cSMatt Porter 454394b701cSMatt Porter /* Make sure these doorbells aren't in use */ 455394b701cSMatt Porter if ((rc = 456394b701cSMatt Porter request_resource(&mport->riores[RIO_DOORBELL_RESOURCE], 457394b701cSMatt Porter res)) < 0) { 458394b701cSMatt Porter kfree(res); 459394b701cSMatt Porter goto out; 460394b701cSMatt Porter } 461394b701cSMatt Porter 462394b701cSMatt Porter /* Hook the doorbell callback */ 4636978bbc0SMatt Porter rc = rio_setup_inb_dbell(mport, dev_id, res, dinb); 464394b701cSMatt Porter } else 465394b701cSMatt Porter rc = -ENOMEM; 466394b701cSMatt Porter 467394b701cSMatt Porter out: 468394b701cSMatt Porter return rc; 469394b701cSMatt Porter } 470394b701cSMatt Porter 471394b701cSMatt Porter /** 472394b701cSMatt Porter * rio_release_inb_dbell - release inbound doorbell message service 473394b701cSMatt Porter * @mport: RIO master port from which to release the doorbell resource 474394b701cSMatt Porter * @start: Doorbell info range start 475394b701cSMatt Porter * @end: Doorbell info range end 476394b701cSMatt Porter * 477394b701cSMatt Porter * Releases ownership of an inbound doorbell resource and removes 478394b701cSMatt Porter * callback from the doorbell event list. Returns 0 if the request 479394b701cSMatt Porter * has been satisfied. 480394b701cSMatt Porter */ 481394b701cSMatt Porter int rio_release_inb_dbell(struct rio_mport *mport, u16 start, u16 end) 482394b701cSMatt Porter { 483394b701cSMatt Porter int rc = 0, found = 0; 484394b701cSMatt Porter struct rio_dbell *dbell; 485394b701cSMatt Porter 486a7b4c636SAlexandre Bounine mutex_lock(&mport->lock); 487394b701cSMatt Porter list_for_each_entry(dbell, &mport->dbells, node) { 488394b701cSMatt Porter if ((dbell->res->start == start) && (dbell->res->end == end)) { 489a7b4c636SAlexandre Bounine list_del(&dbell->node); 490394b701cSMatt Porter found = 1; 491394b701cSMatt Porter break; 492394b701cSMatt Porter } 493394b701cSMatt Porter } 494a7b4c636SAlexandre Bounine mutex_unlock(&mport->lock); 495394b701cSMatt Porter 496394b701cSMatt Porter /* If we can't find an exact match, fail */ 497394b701cSMatt Porter if (!found) { 498394b701cSMatt Porter rc = -EINVAL; 499394b701cSMatt Porter goto out; 500394b701cSMatt Porter } 501394b701cSMatt Porter 502394b701cSMatt Porter /* Release the doorbell resource */ 503394b701cSMatt Porter rc = release_resource(dbell->res); 504394b701cSMatt Porter 505394b701cSMatt Porter /* Free the doorbell event */ 506394b701cSMatt Porter kfree(dbell); 507394b701cSMatt Porter 508394b701cSMatt Porter out: 509394b701cSMatt Porter return rc; 510394b701cSMatt Porter } 511394b701cSMatt Porter 512394b701cSMatt Porter /** 513394b701cSMatt Porter * rio_request_outb_dbell - request outbound doorbell message range 514394b701cSMatt Porter * @rdev: RIO device from which to allocate the doorbell resource 515394b701cSMatt Porter * @start: Doorbell message range start 516394b701cSMatt Porter * @end: Doorbell message range end 517394b701cSMatt Porter * 518394b701cSMatt Porter * Requests ownership of a doorbell message range. Returns a resource 519394b701cSMatt Porter * if the request has been satisfied or %NULL on failure. 520394b701cSMatt Porter */ 521394b701cSMatt Porter struct resource *rio_request_outb_dbell(struct rio_dev *rdev, u16 start, 522394b701cSMatt Porter u16 end) 523394b701cSMatt Porter { 5249a975beeSToshi Kani struct resource *res = kzalloc(sizeof(struct resource), GFP_KERNEL); 525394b701cSMatt Porter 526394b701cSMatt Porter if (res) { 527394b701cSMatt Porter rio_init_dbell_res(res, start, end); 528394b701cSMatt Porter 529394b701cSMatt Porter /* Make sure these doorbells aren't in use */ 530394b701cSMatt Porter if (request_resource(&rdev->riores[RIO_DOORBELL_RESOURCE], res) 531394b701cSMatt Porter < 0) { 532394b701cSMatt Porter kfree(res); 533394b701cSMatt Porter res = NULL; 534394b701cSMatt Porter } 535394b701cSMatt Porter } 536394b701cSMatt Porter 537394b701cSMatt Porter return res; 538394b701cSMatt Porter } 539394b701cSMatt Porter 540394b701cSMatt Porter /** 541394b701cSMatt Porter * rio_release_outb_dbell - release outbound doorbell message range 542394b701cSMatt Porter * @rdev: RIO device from which to release the doorbell resource 543394b701cSMatt Porter * @res: Doorbell resource to be freed 544394b701cSMatt Porter * 545394b701cSMatt Porter * Releases ownership of a doorbell message range. Returns 0 if the 546394b701cSMatt Porter * request has been satisfied. 547394b701cSMatt Porter */ 548394b701cSMatt Porter int rio_release_outb_dbell(struct rio_dev *rdev, struct resource *res) 549394b701cSMatt Porter { 550394b701cSMatt Porter int rc = release_resource(res); 551394b701cSMatt Porter 552394b701cSMatt Porter kfree(res); 553394b701cSMatt Porter 554394b701cSMatt Porter return rc; 555394b701cSMatt Porter } 556394b701cSMatt Porter 557394b701cSMatt Porter /** 5589a0b0627SAlexandre Bounine * rio_add_mport_pw_handler - add port-write message handler into the list 5599a0b0627SAlexandre Bounine * of mport specific pw handlers 5609a0b0627SAlexandre Bounine * @mport: RIO master port to bind the portwrite callback 5619a0b0627SAlexandre Bounine * @context: Handler specific context to pass on event 5629a0b0627SAlexandre Bounine * @pwcback: Callback to execute when portwrite is received 5639a0b0627SAlexandre Bounine * 5649a0b0627SAlexandre Bounine * Returns 0 if the request has been satisfied. 5659a0b0627SAlexandre Bounine */ 5669a0b0627SAlexandre Bounine int rio_add_mport_pw_handler(struct rio_mport *mport, void *context, 5679a0b0627SAlexandre Bounine int (*pwcback)(struct rio_mport *mport, 5689a0b0627SAlexandre Bounine void *context, union rio_pw_msg *msg, int step)) 5699a0b0627SAlexandre Bounine { 5709a0b0627SAlexandre Bounine int rc = 0; 5719a0b0627SAlexandre Bounine struct rio_pwrite *pwrite; 5729a0b0627SAlexandre Bounine 5739a0b0627SAlexandre Bounine pwrite = kzalloc(sizeof(struct rio_pwrite), GFP_KERNEL); 5749a0b0627SAlexandre Bounine if (!pwrite) { 5759a0b0627SAlexandre Bounine rc = -ENOMEM; 5769a0b0627SAlexandre Bounine goto out; 5779a0b0627SAlexandre Bounine } 5789a0b0627SAlexandre Bounine 5799a0b0627SAlexandre Bounine pwrite->pwcback = pwcback; 5809a0b0627SAlexandre Bounine pwrite->context = context; 5819a0b0627SAlexandre Bounine mutex_lock(&mport->lock); 5829a0b0627SAlexandre Bounine list_add_tail(&pwrite->node, &mport->pwrites); 5839a0b0627SAlexandre Bounine mutex_unlock(&mport->lock); 5849a0b0627SAlexandre Bounine out: 5859a0b0627SAlexandre Bounine return rc; 5869a0b0627SAlexandre Bounine } 5879a0b0627SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_add_mport_pw_handler); 5889a0b0627SAlexandre Bounine 5899a0b0627SAlexandre Bounine /** 5909a0b0627SAlexandre Bounine * rio_del_mport_pw_handler - remove port-write message handler from the list 5919a0b0627SAlexandre Bounine * of mport specific pw handlers 5929a0b0627SAlexandre Bounine * @mport: RIO master port to bind the portwrite callback 5939a0b0627SAlexandre Bounine * @context: Registered handler specific context to pass on event 5949a0b0627SAlexandre Bounine * @pwcback: Registered callback function 5959a0b0627SAlexandre Bounine * 5969a0b0627SAlexandre Bounine * Returns 0 if the request has been satisfied. 5979a0b0627SAlexandre Bounine */ 5989a0b0627SAlexandre Bounine int rio_del_mport_pw_handler(struct rio_mport *mport, void *context, 5999a0b0627SAlexandre Bounine int (*pwcback)(struct rio_mport *mport, 6009a0b0627SAlexandre Bounine void *context, union rio_pw_msg *msg, int step)) 6019a0b0627SAlexandre Bounine { 6029a0b0627SAlexandre Bounine int rc = -EINVAL; 6039a0b0627SAlexandre Bounine struct rio_pwrite *pwrite; 6049a0b0627SAlexandre Bounine 6059a0b0627SAlexandre Bounine mutex_lock(&mport->lock); 6069a0b0627SAlexandre Bounine list_for_each_entry(pwrite, &mport->pwrites, node) { 6079a0b0627SAlexandre Bounine if (pwrite->pwcback == pwcback && pwrite->context == context) { 6089a0b0627SAlexandre Bounine list_del(&pwrite->node); 6099a0b0627SAlexandre Bounine kfree(pwrite); 6109a0b0627SAlexandre Bounine rc = 0; 6119a0b0627SAlexandre Bounine break; 6129a0b0627SAlexandre Bounine } 6139a0b0627SAlexandre Bounine } 6149a0b0627SAlexandre Bounine mutex_unlock(&mport->lock); 6159a0b0627SAlexandre Bounine 6169a0b0627SAlexandre Bounine return rc; 6179a0b0627SAlexandre Bounine } 6189a0b0627SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_del_mport_pw_handler); 6199a0b0627SAlexandre Bounine 6209a0b0627SAlexandre Bounine /** 6219a0b0627SAlexandre Bounine * rio_request_inb_pwrite - request inbound port-write message service for 6229a0b0627SAlexandre Bounine * specific RapidIO device 62397ef6f74SRandy Dunlap * @rdev: RIO device to which register inbound port-write callback routine 624e5cabeb3SAlexandre Bounine * @pwcback: Callback routine to execute when port-write is received 625e5cabeb3SAlexandre Bounine * 626e5cabeb3SAlexandre Bounine * Binds a port-write callback function to the RapidIO device. 627e5cabeb3SAlexandre Bounine * Returns 0 if the request has been satisfied. 628e5cabeb3SAlexandre Bounine */ 629e5cabeb3SAlexandre Bounine int rio_request_inb_pwrite(struct rio_dev *rdev, 630e5cabeb3SAlexandre Bounine int (*pwcback)(struct rio_dev *rdev, union rio_pw_msg *msg, int step)) 631e5cabeb3SAlexandre Bounine { 632e5cabeb3SAlexandre Bounine int rc = 0; 633e5cabeb3SAlexandre Bounine 634e5cabeb3SAlexandre Bounine spin_lock(&rio_global_list_lock); 63593dd49afSMarkus Elfring if (rdev->pwcback) 636e5cabeb3SAlexandre Bounine rc = -ENOMEM; 637e5cabeb3SAlexandre Bounine else 638e5cabeb3SAlexandre Bounine rdev->pwcback = pwcback; 639e5cabeb3SAlexandre Bounine 640e5cabeb3SAlexandre Bounine spin_unlock(&rio_global_list_lock); 641e5cabeb3SAlexandre Bounine return rc; 642e5cabeb3SAlexandre Bounine } 643e5cabeb3SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_request_inb_pwrite); 644e5cabeb3SAlexandre Bounine 645e5cabeb3SAlexandre Bounine /** 646e5cabeb3SAlexandre Bounine * rio_release_inb_pwrite - release inbound port-write message service 6479a0b0627SAlexandre Bounine * associated with specific RapidIO device 648e5cabeb3SAlexandre Bounine * @rdev: RIO device which registered for inbound port-write callback 649e5cabeb3SAlexandre Bounine * 650e5cabeb3SAlexandre Bounine * Removes callback from the rio_dev structure. Returns 0 if the request 651e5cabeb3SAlexandre Bounine * has been satisfied. 652e5cabeb3SAlexandre Bounine */ 653e5cabeb3SAlexandre Bounine int rio_release_inb_pwrite(struct rio_dev *rdev) 654e5cabeb3SAlexandre Bounine { 655e5cabeb3SAlexandre Bounine int rc = -ENOMEM; 656e5cabeb3SAlexandre Bounine 657e5cabeb3SAlexandre Bounine spin_lock(&rio_global_list_lock); 658e5cabeb3SAlexandre Bounine if (rdev->pwcback) { 659e5cabeb3SAlexandre Bounine rdev->pwcback = NULL; 660e5cabeb3SAlexandre Bounine rc = 0; 661e5cabeb3SAlexandre Bounine } 662e5cabeb3SAlexandre Bounine 663e5cabeb3SAlexandre Bounine spin_unlock(&rio_global_list_lock); 664e5cabeb3SAlexandre Bounine return rc; 665e5cabeb3SAlexandre Bounine } 666e5cabeb3SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_release_inb_pwrite); 667e5cabeb3SAlexandre Bounine 668e5cabeb3SAlexandre Bounine /** 669b6cb95e8SAlexandre Bounine * rio_pw_enable - Enables/disables port-write handling by a master port 670b6cb95e8SAlexandre Bounine * @mport: Master port associated with port-write handling 671b6cb95e8SAlexandre Bounine * @enable: 1=enable, 0=disable 672b6cb95e8SAlexandre Bounine */ 673b6cb95e8SAlexandre Bounine void rio_pw_enable(struct rio_mport *mport, int enable) 674b6cb95e8SAlexandre Bounine { 675b6cb95e8SAlexandre Bounine if (mport->ops->pwenable) { 676b6cb95e8SAlexandre Bounine mutex_lock(&mport->lock); 677b6cb95e8SAlexandre Bounine 678b6cb95e8SAlexandre Bounine if ((enable && ++mport->pwe_refcnt == 1) || 679b6cb95e8SAlexandre Bounine (!enable && mport->pwe_refcnt && --mport->pwe_refcnt == 0)) 680b6cb95e8SAlexandre Bounine mport->ops->pwenable(mport, enable); 681b6cb95e8SAlexandre Bounine mutex_unlock(&mport->lock); 682b6cb95e8SAlexandre Bounine } 683b6cb95e8SAlexandre Bounine } 684b6cb95e8SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_pw_enable); 685b6cb95e8SAlexandre Bounine 686b6cb95e8SAlexandre Bounine /** 687da1589f0SAlexandre Bounine * rio_map_inb_region -- Map inbound memory region. 688da1589f0SAlexandre Bounine * @mport: Master port. 6892ca3cb50SRandy Dunlap * @local: physical address of memory region to be mapped 690da1589f0SAlexandre Bounine * @rbase: RIO base address assigned to this window 691da1589f0SAlexandre Bounine * @size: Size of the memory region 692da1589f0SAlexandre Bounine * @rflags: Flags for mapping. 693da1589f0SAlexandre Bounine * 694da1589f0SAlexandre Bounine * Return: 0 -- Success. 695da1589f0SAlexandre Bounine * 696da1589f0SAlexandre Bounine * This function will create the mapping from RIO space to local memory. 697da1589f0SAlexandre Bounine */ 698da1589f0SAlexandre Bounine int rio_map_inb_region(struct rio_mport *mport, dma_addr_t local, 699da1589f0SAlexandre Bounine u64 rbase, u32 size, u32 rflags) 700da1589f0SAlexandre Bounine { 701da1589f0SAlexandre Bounine int rc = 0; 702da1589f0SAlexandre Bounine unsigned long flags; 703da1589f0SAlexandre Bounine 704da1589f0SAlexandre Bounine if (!mport->ops->map_inb) 705da1589f0SAlexandre Bounine return -1; 706da1589f0SAlexandre Bounine spin_lock_irqsave(&rio_mmap_lock, flags); 707da1589f0SAlexandre Bounine rc = mport->ops->map_inb(mport, local, rbase, size, rflags); 708da1589f0SAlexandre Bounine spin_unlock_irqrestore(&rio_mmap_lock, flags); 709da1589f0SAlexandre Bounine return rc; 710da1589f0SAlexandre Bounine } 711da1589f0SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_map_inb_region); 712da1589f0SAlexandre Bounine 713da1589f0SAlexandre Bounine /** 714da1589f0SAlexandre Bounine * rio_unmap_inb_region -- Unmap the inbound memory region 715da1589f0SAlexandre Bounine * @mport: Master port 716da1589f0SAlexandre Bounine * @lstart: physical address of memory region to be unmapped 717da1589f0SAlexandre Bounine */ 718da1589f0SAlexandre Bounine void rio_unmap_inb_region(struct rio_mport *mport, dma_addr_t lstart) 719da1589f0SAlexandre Bounine { 720da1589f0SAlexandre Bounine unsigned long flags; 721da1589f0SAlexandre Bounine if (!mport->ops->unmap_inb) 722da1589f0SAlexandre Bounine return; 723da1589f0SAlexandre Bounine spin_lock_irqsave(&rio_mmap_lock, flags); 724da1589f0SAlexandre Bounine mport->ops->unmap_inb(mport, lstart); 725da1589f0SAlexandre Bounine spin_unlock_irqrestore(&rio_mmap_lock, flags); 726da1589f0SAlexandre Bounine } 727da1589f0SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_unmap_inb_region); 728da1589f0SAlexandre Bounine 729da1589f0SAlexandre Bounine /** 73093bdaca5SAlexandre Bounine * rio_map_outb_region -- Map outbound memory region. 73193bdaca5SAlexandre Bounine * @mport: Master port. 73293bdaca5SAlexandre Bounine * @destid: destination id window points to 73393bdaca5SAlexandre Bounine * @rbase: RIO base address window translates to 73493bdaca5SAlexandre Bounine * @size: Size of the memory region 73593bdaca5SAlexandre Bounine * @rflags: Flags for mapping. 73693bdaca5SAlexandre Bounine * @local: physical address of memory region mapped 73793bdaca5SAlexandre Bounine * 73893bdaca5SAlexandre Bounine * Return: 0 -- Success. 73993bdaca5SAlexandre Bounine * 74093bdaca5SAlexandre Bounine * This function will create the mapping from RIO space to local memory. 74193bdaca5SAlexandre Bounine */ 74293bdaca5SAlexandre Bounine int rio_map_outb_region(struct rio_mport *mport, u16 destid, u64 rbase, 74393bdaca5SAlexandre Bounine u32 size, u32 rflags, dma_addr_t *local) 74493bdaca5SAlexandre Bounine { 74593bdaca5SAlexandre Bounine int rc = 0; 74693bdaca5SAlexandre Bounine unsigned long flags; 74793bdaca5SAlexandre Bounine 74893bdaca5SAlexandre Bounine if (!mport->ops->map_outb) 74993bdaca5SAlexandre Bounine return -ENODEV; 75093bdaca5SAlexandre Bounine 75193bdaca5SAlexandre Bounine spin_lock_irqsave(&rio_mmap_lock, flags); 75293bdaca5SAlexandre Bounine rc = mport->ops->map_outb(mport, destid, rbase, size, 75393bdaca5SAlexandre Bounine rflags, local); 75493bdaca5SAlexandre Bounine spin_unlock_irqrestore(&rio_mmap_lock, flags); 75593bdaca5SAlexandre Bounine 75693bdaca5SAlexandre Bounine return rc; 75793bdaca5SAlexandre Bounine } 75893bdaca5SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_map_outb_region); 75993bdaca5SAlexandre Bounine 76093bdaca5SAlexandre Bounine /** 76193bdaca5SAlexandre Bounine * rio_unmap_inb_region -- Unmap the inbound memory region 76293bdaca5SAlexandre Bounine * @mport: Master port 76393bdaca5SAlexandre Bounine * @destid: destination id mapping points to 76493bdaca5SAlexandre Bounine * @rstart: RIO base address window translates to 76593bdaca5SAlexandre Bounine */ 76693bdaca5SAlexandre Bounine void rio_unmap_outb_region(struct rio_mport *mport, u16 destid, u64 rstart) 76793bdaca5SAlexandre Bounine { 76893bdaca5SAlexandre Bounine unsigned long flags; 76993bdaca5SAlexandre Bounine 77093bdaca5SAlexandre Bounine if (!mport->ops->unmap_outb) 77193bdaca5SAlexandre Bounine return; 77293bdaca5SAlexandre Bounine 77393bdaca5SAlexandre Bounine spin_lock_irqsave(&rio_mmap_lock, flags); 77493bdaca5SAlexandre Bounine mport->ops->unmap_outb(mport, destid, rstart); 77593bdaca5SAlexandre Bounine spin_unlock_irqrestore(&rio_mmap_lock, flags); 77693bdaca5SAlexandre Bounine } 77793bdaca5SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_unmap_outb_region); 77893bdaca5SAlexandre Bounine 77993bdaca5SAlexandre Bounine /** 780e5cabeb3SAlexandre Bounine * rio_mport_get_physefb - Helper function that returns register offset 781e5cabeb3SAlexandre Bounine * for Physical Layer Extended Features Block. 78297ef6f74SRandy Dunlap * @port: Master port to issue transaction 78397ef6f74SRandy Dunlap * @local: Indicate a local master port or remote device access 78497ef6f74SRandy Dunlap * @destid: Destination ID of the device 78597ef6f74SRandy Dunlap * @hopcount: Number of switch hops to the device 7861ae842deSAlexandre Bounine * @rmap: pointer to location to store register map type info 787e5cabeb3SAlexandre Bounine */ 788e5cabeb3SAlexandre Bounine u32 789e5cabeb3SAlexandre Bounine rio_mport_get_physefb(struct rio_mport *port, int local, 7901ae842deSAlexandre Bounine u16 destid, u8 hopcount, u32 *rmap) 791e5cabeb3SAlexandre Bounine { 792e5cabeb3SAlexandre Bounine u32 ext_ftr_ptr; 793e5cabeb3SAlexandre Bounine u32 ftr_header; 794e5cabeb3SAlexandre Bounine 795e5cabeb3SAlexandre Bounine ext_ftr_ptr = rio_mport_get_efb(port, local, destid, hopcount, 0); 796e5cabeb3SAlexandre Bounine 797e5cabeb3SAlexandre Bounine while (ext_ftr_ptr) { 798e5cabeb3SAlexandre Bounine if (local) 799e5cabeb3SAlexandre Bounine rio_local_read_config_32(port, ext_ftr_ptr, 800e5cabeb3SAlexandre Bounine &ftr_header); 801e5cabeb3SAlexandre Bounine else 802e5cabeb3SAlexandre Bounine rio_mport_read_config_32(port, destid, hopcount, 803e5cabeb3SAlexandre Bounine ext_ftr_ptr, &ftr_header); 804e5cabeb3SAlexandre Bounine 805e5cabeb3SAlexandre Bounine ftr_header = RIO_GET_BLOCK_ID(ftr_header); 806e5cabeb3SAlexandre Bounine switch (ftr_header) { 807e5cabeb3SAlexandre Bounine 808e5cabeb3SAlexandre Bounine case RIO_EFB_SER_EP_ID: 809e5cabeb3SAlexandre Bounine case RIO_EFB_SER_EP_REC_ID: 810e5cabeb3SAlexandre Bounine case RIO_EFB_SER_EP_FREE_ID: 8111ae842deSAlexandre Bounine case RIO_EFB_SER_EP_M1_ID: 8121ae842deSAlexandre Bounine case RIO_EFB_SER_EP_SW_M1_ID: 8131ae842deSAlexandre Bounine case RIO_EFB_SER_EPF_M1_ID: 8141ae842deSAlexandre Bounine case RIO_EFB_SER_EPF_SW_M1_ID: 8151ae842deSAlexandre Bounine *rmap = 1; 8161ae842deSAlexandre Bounine return ext_ftr_ptr; 817e5cabeb3SAlexandre Bounine 8181ae842deSAlexandre Bounine case RIO_EFB_SER_EP_M2_ID: 8191ae842deSAlexandre Bounine case RIO_EFB_SER_EP_SW_M2_ID: 8201ae842deSAlexandre Bounine case RIO_EFB_SER_EPF_M2_ID: 8211ae842deSAlexandre Bounine case RIO_EFB_SER_EPF_SW_M2_ID: 8221ae842deSAlexandre Bounine *rmap = 2; 823e5cabeb3SAlexandre Bounine return ext_ftr_ptr; 824e5cabeb3SAlexandre Bounine 825e5cabeb3SAlexandre Bounine default: 826e5cabeb3SAlexandre Bounine break; 827e5cabeb3SAlexandre Bounine } 828e5cabeb3SAlexandre Bounine 829e5cabeb3SAlexandre Bounine ext_ftr_ptr = rio_mport_get_efb(port, local, destid, 830e5cabeb3SAlexandre Bounine hopcount, ext_ftr_ptr); 831e5cabeb3SAlexandre Bounine } 832e5cabeb3SAlexandre Bounine 833e5cabeb3SAlexandre Bounine return ext_ftr_ptr; 834e5cabeb3SAlexandre Bounine } 835a11650e1SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_mport_get_physefb); 836e5cabeb3SAlexandre Bounine 837e5cabeb3SAlexandre Bounine /** 838e5cabeb3SAlexandre Bounine * rio_get_comptag - Begin or continue searching for a RIO device by component tag 83997ef6f74SRandy Dunlap * @comp_tag: RIO component tag to match 840e5cabeb3SAlexandre Bounine * @from: Previous RIO device found in search, or %NULL for new search 841e5cabeb3SAlexandre Bounine * 842e5cabeb3SAlexandre Bounine * Iterates through the list of known RIO devices. If a RIO device is 843e5cabeb3SAlexandre Bounine * found with a matching @comp_tag, a pointer to its device 844e5cabeb3SAlexandre Bounine * structure is returned. Otherwise, %NULL is returned. A new search 845e5cabeb3SAlexandre Bounine * is initiated by passing %NULL to the @from argument. Otherwise, if 846e5cabeb3SAlexandre Bounine * @from is not %NULL, searches continue from next device on the global 847e5cabeb3SAlexandre Bounine * list. 848e5cabeb3SAlexandre Bounine */ 849af84ca38SAlexandre Bounine struct rio_dev *rio_get_comptag(u32 comp_tag, struct rio_dev *from) 850e5cabeb3SAlexandre Bounine { 851e5cabeb3SAlexandre Bounine struct list_head *n; 852e5cabeb3SAlexandre Bounine struct rio_dev *rdev; 853e5cabeb3SAlexandre Bounine 854e5cabeb3SAlexandre Bounine spin_lock(&rio_global_list_lock); 855e5cabeb3SAlexandre Bounine n = from ? from->global_list.next : rio_devices.next; 856e5cabeb3SAlexandre Bounine 857e5cabeb3SAlexandre Bounine while (n && (n != &rio_devices)) { 858e5cabeb3SAlexandre Bounine rdev = rio_dev_g(n); 859e5cabeb3SAlexandre Bounine if (rdev->comp_tag == comp_tag) 860e5cabeb3SAlexandre Bounine goto exit; 861e5cabeb3SAlexandre Bounine n = n->next; 862e5cabeb3SAlexandre Bounine } 863e5cabeb3SAlexandre Bounine rdev = NULL; 864e5cabeb3SAlexandre Bounine exit: 865e5cabeb3SAlexandre Bounine spin_unlock(&rio_global_list_lock); 866e5cabeb3SAlexandre Bounine return rdev; 867e5cabeb3SAlexandre Bounine } 868a11650e1SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_get_comptag); 869e5cabeb3SAlexandre Bounine 870e5cabeb3SAlexandre Bounine /** 871e5cabeb3SAlexandre Bounine * rio_set_port_lockout - Sets/clears LOCKOUT bit (RIO EM 1.3) for a switch port. 872e5cabeb3SAlexandre Bounine * @rdev: Pointer to RIO device control structure 873e5cabeb3SAlexandre Bounine * @pnum: Switch port number to set LOCKOUT bit 874e5cabeb3SAlexandre Bounine * @lock: Operation : set (=1) or clear (=0) 875e5cabeb3SAlexandre Bounine */ 876e5cabeb3SAlexandre Bounine int rio_set_port_lockout(struct rio_dev *rdev, u32 pnum, int lock) 877e5cabeb3SAlexandre Bounine { 878e5cabeb3SAlexandre Bounine u32 regval; 879e5cabeb3SAlexandre Bounine 880a93192a5SAlexandre Bounine rio_read_config_32(rdev, 8811ae842deSAlexandre Bounine RIO_DEV_PORT_N_CTL_CSR(rdev, pnum), 882e5cabeb3SAlexandre Bounine ®val); 883e5cabeb3SAlexandre Bounine if (lock) 884e5cabeb3SAlexandre Bounine regval |= RIO_PORT_N_CTL_LOCKOUT; 885e5cabeb3SAlexandre Bounine else 886e5cabeb3SAlexandre Bounine regval &= ~RIO_PORT_N_CTL_LOCKOUT; 887e5cabeb3SAlexandre Bounine 888a93192a5SAlexandre Bounine rio_write_config_32(rdev, 8891ae842deSAlexandre Bounine RIO_DEV_PORT_N_CTL_CSR(rdev, pnum), 890e5cabeb3SAlexandre Bounine regval); 891e5cabeb3SAlexandre Bounine return 0; 892e5cabeb3SAlexandre Bounine } 893a11650e1SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_set_port_lockout); 894a11650e1SAlexandre Bounine 895a11650e1SAlexandre Bounine /** 896a11650e1SAlexandre Bounine * rio_enable_rx_tx_port - enable input receiver and output transmitter of 897a11650e1SAlexandre Bounine * given port 898a11650e1SAlexandre Bounine * @port: Master port associated with the RIO network 899a11650e1SAlexandre Bounine * @local: local=1 select local port otherwise a far device is reached 900a11650e1SAlexandre Bounine * @destid: Destination ID of the device to check host bit 901a11650e1SAlexandre Bounine * @hopcount: Number of hops to reach the target 902a11650e1SAlexandre Bounine * @port_num: Port (-number on switch) to enable on a far end device 903a11650e1SAlexandre Bounine * 904a11650e1SAlexandre Bounine * Returns 0 or 1 from on General Control Command and Status Register 905a11650e1SAlexandre Bounine * (EXT_PTR+0x3C) 906a11650e1SAlexandre Bounine */ 907a11650e1SAlexandre Bounine int rio_enable_rx_tx_port(struct rio_mport *port, 908a11650e1SAlexandre Bounine int local, u16 destid, 909a11650e1SAlexandre Bounine u8 hopcount, u8 port_num) 910a11650e1SAlexandre Bounine { 911a11650e1SAlexandre Bounine #ifdef CONFIG_RAPIDIO_ENABLE_RX_TX_PORTS 912a11650e1SAlexandre Bounine u32 regval; 913a11650e1SAlexandre Bounine u32 ext_ftr_ptr; 9141ae842deSAlexandre Bounine u32 rmap; 915a11650e1SAlexandre Bounine 916a11650e1SAlexandre Bounine /* 917a11650e1SAlexandre Bounine * enable rx input tx output port 918a11650e1SAlexandre Bounine */ 919a11650e1SAlexandre Bounine pr_debug("rio_enable_rx_tx_port(local = %d, destid = %d, hopcount = " 920a11650e1SAlexandre Bounine "%d, port_num = %d)\n", local, destid, hopcount, port_num); 921a11650e1SAlexandre Bounine 9221ae842deSAlexandre Bounine ext_ftr_ptr = rio_mport_get_physefb(port, local, destid, 9231ae842deSAlexandre Bounine hopcount, &rmap); 924a11650e1SAlexandre Bounine 925a11650e1SAlexandre Bounine if (local) { 9261ae842deSAlexandre Bounine rio_local_read_config_32(port, 9271ae842deSAlexandre Bounine ext_ftr_ptr + RIO_PORT_N_CTL_CSR(0, rmap), 928a11650e1SAlexandre Bounine ®val); 929a11650e1SAlexandre Bounine } else { 930a11650e1SAlexandre Bounine if (rio_mport_read_config_32(port, destid, hopcount, 9311ae842deSAlexandre Bounine ext_ftr_ptr + RIO_PORT_N_CTL_CSR(port_num, rmap), 9321ae842deSAlexandre Bounine ®val) < 0) 933a11650e1SAlexandre Bounine return -EIO; 934a11650e1SAlexandre Bounine } 935a11650e1SAlexandre Bounine 9361ae842deSAlexandre Bounine regval = regval | RIO_PORT_N_CTL_EN_RX | RIO_PORT_N_CTL_EN_TX; 937a11650e1SAlexandre Bounine 938a11650e1SAlexandre Bounine if (local) { 9391ae842deSAlexandre Bounine rio_local_write_config_32(port, 9401ae842deSAlexandre Bounine ext_ftr_ptr + RIO_PORT_N_CTL_CSR(0, rmap), regval); 941a11650e1SAlexandre Bounine } else { 942a11650e1SAlexandre Bounine if (rio_mport_write_config_32(port, destid, hopcount, 9431ae842deSAlexandre Bounine ext_ftr_ptr + RIO_PORT_N_CTL_CSR(port_num, rmap), 9441ae842deSAlexandre Bounine regval) < 0) 945a11650e1SAlexandre Bounine return -EIO; 946a11650e1SAlexandre Bounine } 947a11650e1SAlexandre Bounine #endif 948a11650e1SAlexandre Bounine return 0; 949a11650e1SAlexandre Bounine } 950a11650e1SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_enable_rx_tx_port); 951a11650e1SAlexandre Bounine 952e5cabeb3SAlexandre Bounine 953e5cabeb3SAlexandre Bounine /** 9546429cd49SAlexandre Bounine * rio_chk_dev_route - Validate route to the specified device. 9556429cd49SAlexandre Bounine * @rdev: RIO device failed to respond 9566429cd49SAlexandre Bounine * @nrdev: Last active device on the route to rdev 9576429cd49SAlexandre Bounine * @npnum: nrdev's port number on the route to rdev 9586429cd49SAlexandre Bounine * 9596429cd49SAlexandre Bounine * Follows a route to the specified RIO device to determine the last available 9606429cd49SAlexandre Bounine * device (and corresponding RIO port) on the route. 9616429cd49SAlexandre Bounine */ 9626429cd49SAlexandre Bounine static int 9636429cd49SAlexandre Bounine rio_chk_dev_route(struct rio_dev *rdev, struct rio_dev **nrdev, int *npnum) 9646429cd49SAlexandre Bounine { 9656429cd49SAlexandre Bounine u32 result; 966a93192a5SAlexandre Bounine int p_port, rc = -EIO; 9676429cd49SAlexandre Bounine struct rio_dev *prev = NULL; 9686429cd49SAlexandre Bounine 9696429cd49SAlexandre Bounine /* Find switch with failed RIO link */ 9706429cd49SAlexandre Bounine while (rdev->prev && (rdev->prev->pef & RIO_PEF_SWITCH)) { 9716429cd49SAlexandre Bounine if (!rio_read_config_32(rdev->prev, RIO_DEV_ID_CAR, &result)) { 9726429cd49SAlexandre Bounine prev = rdev->prev; 9736429cd49SAlexandre Bounine break; 9746429cd49SAlexandre Bounine } 9756429cd49SAlexandre Bounine rdev = rdev->prev; 9766429cd49SAlexandre Bounine } 9776429cd49SAlexandre Bounine 97893dd49afSMarkus Elfring if (!prev) 9796429cd49SAlexandre Bounine goto err_out; 9806429cd49SAlexandre Bounine 981a93192a5SAlexandre Bounine p_port = prev->rswitch->route_table[rdev->destid]; 9826429cd49SAlexandre Bounine 983af84ca38SAlexandre Bounine if (p_port != RIO_INVALID_ROUTE) { 9846429cd49SAlexandre Bounine pr_debug("RIO: link failed on [%s]-P%d\n", 9856429cd49SAlexandre Bounine rio_name(prev), p_port); 9866429cd49SAlexandre Bounine *nrdev = prev; 9876429cd49SAlexandre Bounine *npnum = p_port; 9886429cd49SAlexandre Bounine rc = 0; 9896429cd49SAlexandre Bounine } else 990af84ca38SAlexandre Bounine pr_debug("RIO: failed to trace route to %s\n", rio_name(rdev)); 9916429cd49SAlexandre Bounine err_out: 9926429cd49SAlexandre Bounine return rc; 9936429cd49SAlexandre Bounine } 9946429cd49SAlexandre Bounine 9956429cd49SAlexandre Bounine /** 9966429cd49SAlexandre Bounine * rio_mport_chk_dev_access - Validate access to the specified device. 9976429cd49SAlexandre Bounine * @mport: Master port to send transactions 9986429cd49SAlexandre Bounine * @destid: Device destination ID in network 9996429cd49SAlexandre Bounine * @hopcount: Number of hops into the network 10006429cd49SAlexandre Bounine */ 1001e274e0edSAlexandre Bounine int 10026429cd49SAlexandre Bounine rio_mport_chk_dev_access(struct rio_mport *mport, u16 destid, u8 hopcount) 10036429cd49SAlexandre Bounine { 10046429cd49SAlexandre Bounine int i = 0; 10056429cd49SAlexandre Bounine u32 tmp; 10066429cd49SAlexandre Bounine 10076429cd49SAlexandre Bounine while (rio_mport_read_config_32(mport, destid, hopcount, 10086429cd49SAlexandre Bounine RIO_DEV_ID_CAR, &tmp)) { 10096429cd49SAlexandre Bounine i++; 10106429cd49SAlexandre Bounine if (i == RIO_MAX_CHK_RETRY) 10116429cd49SAlexandre Bounine return -EIO; 10126429cd49SAlexandre Bounine mdelay(1); 10136429cd49SAlexandre Bounine } 10146429cd49SAlexandre Bounine 10156429cd49SAlexandre Bounine return 0; 10166429cd49SAlexandre Bounine } 1017a11650e1SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_mport_chk_dev_access); 10186429cd49SAlexandre Bounine 10196429cd49SAlexandre Bounine /** 10206429cd49SAlexandre Bounine * rio_chk_dev_access - Validate access to the specified device. 10216429cd49SAlexandre Bounine * @rdev: Pointer to RIO device control structure 10226429cd49SAlexandre Bounine */ 10236429cd49SAlexandre Bounine static int rio_chk_dev_access(struct rio_dev *rdev) 10246429cd49SAlexandre Bounine { 1025a93192a5SAlexandre Bounine return rio_mport_chk_dev_access(rdev->net->hport, 1026a93192a5SAlexandre Bounine rdev->destid, rdev->hopcount); 10276429cd49SAlexandre Bounine } 10286429cd49SAlexandre Bounine 10296429cd49SAlexandre Bounine /** 1030dd5648c9SAlexandre Bounine * rio_get_input_status - Sends a Link-Request/Input-Status control symbol and 1031dd5648c9SAlexandre Bounine * returns link-response (if requested). 1032dd5648c9SAlexandre Bounine * @rdev: RIO devive to issue Input-status command 1033dd5648c9SAlexandre Bounine * @pnum: Device port number to issue the command 1034dd5648c9SAlexandre Bounine * @lnkresp: Response from a link partner 1035dd5648c9SAlexandre Bounine */ 1036dd5648c9SAlexandre Bounine static int 1037dd5648c9SAlexandre Bounine rio_get_input_status(struct rio_dev *rdev, int pnum, u32 *lnkresp) 1038dd5648c9SAlexandre Bounine { 1039dd5648c9SAlexandre Bounine u32 regval; 1040dd5648c9SAlexandre Bounine int checkcount; 1041dd5648c9SAlexandre Bounine 1042dd5648c9SAlexandre Bounine if (lnkresp) { 1043dd5648c9SAlexandre Bounine /* Read from link maintenance response register 1044dd5648c9SAlexandre Bounine * to clear valid bit */ 1045a93192a5SAlexandre Bounine rio_read_config_32(rdev, 10461ae842deSAlexandre Bounine RIO_DEV_PORT_N_MNT_RSP_CSR(rdev, pnum), 1047dd5648c9SAlexandre Bounine ®val); 1048dd5648c9SAlexandre Bounine udelay(50); 1049dd5648c9SAlexandre Bounine } 1050dd5648c9SAlexandre Bounine 1051dd5648c9SAlexandre Bounine /* Issue Input-status command */ 1052a93192a5SAlexandre Bounine rio_write_config_32(rdev, 10531ae842deSAlexandre Bounine RIO_DEV_PORT_N_MNT_REQ_CSR(rdev, pnum), 1054dd5648c9SAlexandre Bounine RIO_MNT_REQ_CMD_IS); 1055dd5648c9SAlexandre Bounine 1056dd5648c9SAlexandre Bounine /* Exit if the response is not expected */ 105793dd49afSMarkus Elfring if (!lnkresp) 1058dd5648c9SAlexandre Bounine return 0; 1059dd5648c9SAlexandre Bounine 1060dd5648c9SAlexandre Bounine checkcount = 3; 1061dd5648c9SAlexandre Bounine while (checkcount--) { 1062dd5648c9SAlexandre Bounine udelay(50); 1063a93192a5SAlexandre Bounine rio_read_config_32(rdev, 10641ae842deSAlexandre Bounine RIO_DEV_PORT_N_MNT_RSP_CSR(rdev, pnum), 1065dd5648c9SAlexandre Bounine ®val); 1066dd5648c9SAlexandre Bounine if (regval & RIO_PORT_N_MNT_RSP_RVAL) { 1067dd5648c9SAlexandre Bounine *lnkresp = regval; 1068dd5648c9SAlexandre Bounine return 0; 1069dd5648c9SAlexandre Bounine } 1070dd5648c9SAlexandre Bounine } 1071dd5648c9SAlexandre Bounine 1072dd5648c9SAlexandre Bounine return -EIO; 1073dd5648c9SAlexandre Bounine } 1074dd5648c9SAlexandre Bounine 1075dd5648c9SAlexandre Bounine /** 1076dd5648c9SAlexandre Bounine * rio_clr_err_stopped - Clears port Error-stopped states. 1077dd5648c9SAlexandre Bounine * @rdev: Pointer to RIO device control structure 1078dd5648c9SAlexandre Bounine * @pnum: Switch port number to clear errors 1079dd5648c9SAlexandre Bounine * @err_status: port error status (if 0 reads register from device) 10801ae842deSAlexandre Bounine * 10811ae842deSAlexandre Bounine * TODO: Currently this routine is not compatible with recovery process 10821ae842deSAlexandre Bounine * specified for idt_gen3 RapidIO switch devices. It has to be reviewed 10831ae842deSAlexandre Bounine * to implement universal recovery process that is compatible full range 10841ae842deSAlexandre Bounine * off available devices. 10851ae842deSAlexandre Bounine * IDT gen3 switch driver now implements HW-specific error handler that 10861ae842deSAlexandre Bounine * issues soft port reset to the port to reset ERR_STOP bits and ackIDs. 1087dd5648c9SAlexandre Bounine */ 1088dd5648c9SAlexandre Bounine static int rio_clr_err_stopped(struct rio_dev *rdev, u32 pnum, u32 err_status) 1089dd5648c9SAlexandre Bounine { 1090dd5648c9SAlexandre Bounine struct rio_dev *nextdev = rdev->rswitch->nextdev[pnum]; 1091dd5648c9SAlexandre Bounine u32 regval; 1092dd5648c9SAlexandre Bounine u32 far_ackid, far_linkstat, near_ackid; 1093dd5648c9SAlexandre Bounine 1094dd5648c9SAlexandre Bounine if (err_status == 0) 1095a93192a5SAlexandre Bounine rio_read_config_32(rdev, 10961ae842deSAlexandre Bounine RIO_DEV_PORT_N_ERR_STS_CSR(rdev, pnum), 1097dd5648c9SAlexandre Bounine &err_status); 1098dd5648c9SAlexandre Bounine 10991ae842deSAlexandre Bounine if (err_status & RIO_PORT_N_ERR_STS_OUT_ES) { 1100dd5648c9SAlexandre Bounine pr_debug("RIO_EM: servicing Output Error-Stopped state\n"); 1101dd5648c9SAlexandre Bounine /* 1102dd5648c9SAlexandre Bounine * Send a Link-Request/Input-Status control symbol 1103dd5648c9SAlexandre Bounine */ 1104dd5648c9SAlexandre Bounine if (rio_get_input_status(rdev, pnum, ®val)) { 1105dd5648c9SAlexandre Bounine pr_debug("RIO_EM: Input-status response timeout\n"); 1106dd5648c9SAlexandre Bounine goto rd_err; 1107dd5648c9SAlexandre Bounine } 1108dd5648c9SAlexandre Bounine 1109dd5648c9SAlexandre Bounine pr_debug("RIO_EM: SP%d Input-status response=0x%08x\n", 1110dd5648c9SAlexandre Bounine pnum, regval); 1111dd5648c9SAlexandre Bounine far_ackid = (regval & RIO_PORT_N_MNT_RSP_ASTAT) >> 5; 1112dd5648c9SAlexandre Bounine far_linkstat = regval & RIO_PORT_N_MNT_RSP_LSTAT; 1113a93192a5SAlexandre Bounine rio_read_config_32(rdev, 11141ae842deSAlexandre Bounine RIO_DEV_PORT_N_ACK_STS_CSR(rdev, pnum), 1115dd5648c9SAlexandre Bounine ®val); 1116dd5648c9SAlexandre Bounine pr_debug("RIO_EM: SP%d_ACK_STS_CSR=0x%08x\n", pnum, regval); 1117dd5648c9SAlexandre Bounine near_ackid = (regval & RIO_PORT_N_ACK_INBOUND) >> 24; 1118dd5648c9SAlexandre Bounine pr_debug("RIO_EM: SP%d far_ackID=0x%02x far_linkstat=0x%02x" \ 1119dd5648c9SAlexandre Bounine " near_ackID=0x%02x\n", 1120dd5648c9SAlexandre Bounine pnum, far_ackid, far_linkstat, near_ackid); 1121dd5648c9SAlexandre Bounine 1122dd5648c9SAlexandre Bounine /* 1123dd5648c9SAlexandre Bounine * If required, synchronize ackIDs of near and 1124dd5648c9SAlexandre Bounine * far sides. 1125dd5648c9SAlexandre Bounine */ 1126dd5648c9SAlexandre Bounine if ((far_ackid != ((regval & RIO_PORT_N_ACK_OUTSTAND) >> 8)) || 1127dd5648c9SAlexandre Bounine (far_ackid != (regval & RIO_PORT_N_ACK_OUTBOUND))) { 1128dd5648c9SAlexandre Bounine /* Align near outstanding/outbound ackIDs with 1129dd5648c9SAlexandre Bounine * far inbound. 1130dd5648c9SAlexandre Bounine */ 1131a93192a5SAlexandre Bounine rio_write_config_32(rdev, 11321ae842deSAlexandre Bounine RIO_DEV_PORT_N_ACK_STS_CSR(rdev, pnum), 1133dd5648c9SAlexandre Bounine (near_ackid << 24) | 1134dd5648c9SAlexandre Bounine (far_ackid << 8) | far_ackid); 1135dd5648c9SAlexandre Bounine /* Align far outstanding/outbound ackIDs with 1136dd5648c9SAlexandre Bounine * near inbound. 1137dd5648c9SAlexandre Bounine */ 1138dd5648c9SAlexandre Bounine far_ackid++; 11391ae842deSAlexandre Bounine if (!nextdev) { 11401ae842deSAlexandre Bounine pr_debug("RIO_EM: nextdev pointer == NULL\n"); 11411ae842deSAlexandre Bounine goto rd_err; 11421ae842deSAlexandre Bounine } 11431ae842deSAlexandre Bounine 1144dd5648c9SAlexandre Bounine rio_write_config_32(nextdev, 11451ae842deSAlexandre Bounine RIO_DEV_PORT_N_ACK_STS_CSR(nextdev, 11461ae842deSAlexandre Bounine RIO_GET_PORT_NUM(nextdev->swpinfo)), 1147dd5648c9SAlexandre Bounine (far_ackid << 24) | 1148dd5648c9SAlexandre Bounine (near_ackid << 8) | near_ackid); 1149dd5648c9SAlexandre Bounine } 1150dd5648c9SAlexandre Bounine rd_err: 11511ae842deSAlexandre Bounine rio_read_config_32(rdev, RIO_DEV_PORT_N_ERR_STS_CSR(rdev, pnum), 1152dd5648c9SAlexandre Bounine &err_status); 1153dd5648c9SAlexandre Bounine pr_debug("RIO_EM: SP%d_ERR_STS_CSR=0x%08x\n", pnum, err_status); 1154dd5648c9SAlexandre Bounine } 1155dd5648c9SAlexandre Bounine 11561ae842deSAlexandre Bounine if ((err_status & RIO_PORT_N_ERR_STS_INP_ES) && nextdev) { 1157dd5648c9SAlexandre Bounine pr_debug("RIO_EM: servicing Input Error-Stopped state\n"); 1158dd5648c9SAlexandre Bounine rio_get_input_status(nextdev, 1159dd5648c9SAlexandre Bounine RIO_GET_PORT_NUM(nextdev->swpinfo), NULL); 1160dd5648c9SAlexandre Bounine udelay(50); 1161dd5648c9SAlexandre Bounine 11621ae842deSAlexandre Bounine rio_read_config_32(rdev, RIO_DEV_PORT_N_ERR_STS_CSR(rdev, pnum), 1163dd5648c9SAlexandre Bounine &err_status); 1164dd5648c9SAlexandre Bounine pr_debug("RIO_EM: SP%d_ERR_STS_CSR=0x%08x\n", pnum, err_status); 1165dd5648c9SAlexandre Bounine } 1166dd5648c9SAlexandre Bounine 11671ae842deSAlexandre Bounine return (err_status & (RIO_PORT_N_ERR_STS_OUT_ES | 11681ae842deSAlexandre Bounine RIO_PORT_N_ERR_STS_INP_ES)) ? 1 : 0; 1169dd5648c9SAlexandre Bounine } 1170dd5648c9SAlexandre Bounine 1171dd5648c9SAlexandre Bounine /** 11729a0b0627SAlexandre Bounine * rio_inb_pwrite_handler - inbound port-write message handler 11739a0b0627SAlexandre Bounine * @mport: mport device associated with port-write 1174e5cabeb3SAlexandre Bounine * @pw_msg: pointer to inbound port-write message 1175e5cabeb3SAlexandre Bounine * 1176e5cabeb3SAlexandre Bounine * Processes an inbound port-write message. Returns 0 if the request 1177e5cabeb3SAlexandre Bounine * has been satisfied. 1178e5cabeb3SAlexandre Bounine */ 11799a0b0627SAlexandre Bounine int rio_inb_pwrite_handler(struct rio_mport *mport, union rio_pw_msg *pw_msg) 1180e5cabeb3SAlexandre Bounine { 1181e5cabeb3SAlexandre Bounine struct rio_dev *rdev; 1182dd5648c9SAlexandre Bounine u32 err_status, em_perrdet, em_ltlerrdet; 1183e5cabeb3SAlexandre Bounine int rc, portnum; 11849a0b0627SAlexandre Bounine struct rio_pwrite *pwrite; 1185e5cabeb3SAlexandre Bounine 1186e5cabeb3SAlexandre Bounine #ifdef DEBUG_PW 1187e5cabeb3SAlexandre Bounine { 1188e5cabeb3SAlexandre Bounine u32 i; 11899a0b0627SAlexandre Bounine 11909a0b0627SAlexandre Bounine pr_debug("%s: PW to mport_%d:\n", __func__, mport->id); 11919a0b0627SAlexandre Bounine for (i = 0; i < RIO_PW_MSG_SIZE / sizeof(u32); i = i + 4) { 1192dd5648c9SAlexandre Bounine pr_debug("0x%02x: %08x %08x %08x %08x\n", 1193e5cabeb3SAlexandre Bounine i * 4, pw_msg->raw[i], pw_msg->raw[i + 1], 1194e5cabeb3SAlexandre Bounine pw_msg->raw[i + 2], pw_msg->raw[i + 3]); 1195e5cabeb3SAlexandre Bounine } 1196e5cabeb3SAlexandre Bounine } 1197e5cabeb3SAlexandre Bounine #endif 1198e5cabeb3SAlexandre Bounine 11999a0b0627SAlexandre Bounine rdev = rio_get_comptag((pw_msg->em.comptag & RIO_CTAG_UDEVID), NULL); 12009a0b0627SAlexandre Bounine if (rdev) { 12019a0b0627SAlexandre Bounine pr_debug("RIO: Port-Write message from %s\n", rio_name(rdev)); 12029a0b0627SAlexandre Bounine } else { 12039a0b0627SAlexandre Bounine pr_debug("RIO: %s No matching device for CTag 0x%08x\n", 12049a0b0627SAlexandre Bounine __func__, pw_msg->em.comptag); 12059a0b0627SAlexandre Bounine } 12069a0b0627SAlexandre Bounine 12079a0b0627SAlexandre Bounine /* Call a device-specific handler (if it is registered for the device). 12089a0b0627SAlexandre Bounine * This may be the service for endpoints that send device-specific 12099a0b0627SAlexandre Bounine * port-write messages. End-point messages expected to be handled 12109a0b0627SAlexandre Bounine * completely by EP specific device driver. 1211e5cabeb3SAlexandre Bounine * For switches rc==0 signals that no standard processing required. 1212e5cabeb3SAlexandre Bounine */ 12139a0b0627SAlexandre Bounine if (rdev && rdev->pwcback) { 1214e5cabeb3SAlexandre Bounine rc = rdev->pwcback(rdev, pw_msg, 0); 1215e5cabeb3SAlexandre Bounine if (rc == 0) 1216e5cabeb3SAlexandre Bounine return 0; 1217e5cabeb3SAlexandre Bounine } 1218e5cabeb3SAlexandre Bounine 12199a0b0627SAlexandre Bounine mutex_lock(&mport->lock); 12209a0b0627SAlexandre Bounine list_for_each_entry(pwrite, &mport->pwrites, node) 12219a0b0627SAlexandre Bounine pwrite->pwcback(mport, pwrite->context, pw_msg, 0); 12229a0b0627SAlexandre Bounine mutex_unlock(&mport->lock); 12239a0b0627SAlexandre Bounine 12249a0b0627SAlexandre Bounine if (!rdev) 12259a0b0627SAlexandre Bounine return 0; 12269a0b0627SAlexandre Bounine 12279a0b0627SAlexandre Bounine /* 12289a0b0627SAlexandre Bounine * FIXME: The code below stays as it was before for now until we decide 12299a0b0627SAlexandre Bounine * how to do default PW handling in combination with per-mport callbacks 12309a0b0627SAlexandre Bounine */ 12319a0b0627SAlexandre Bounine 12326429cd49SAlexandre Bounine portnum = pw_msg->em.is_port & 0xFF; 12336429cd49SAlexandre Bounine 12346429cd49SAlexandre Bounine /* Check if device and route to it are functional: 12356429cd49SAlexandre Bounine * Sometimes devices may send PW message(s) just before being 12366429cd49SAlexandre Bounine * powered down (or link being lost). 12376429cd49SAlexandre Bounine */ 12386429cd49SAlexandre Bounine if (rio_chk_dev_access(rdev)) { 12396429cd49SAlexandre Bounine pr_debug("RIO: device access failed - get link partner\n"); 12406429cd49SAlexandre Bounine /* Scan route to the device and identify failed link. 12416429cd49SAlexandre Bounine * This will replace device and port reported in PW message. 12426429cd49SAlexandre Bounine * PW message should not be used after this point. 12436429cd49SAlexandre Bounine */ 12446429cd49SAlexandre Bounine if (rio_chk_dev_route(rdev, &rdev, &portnum)) { 12456429cd49SAlexandre Bounine pr_err("RIO: Route trace for %s failed\n", 12466429cd49SAlexandre Bounine rio_name(rdev)); 12476429cd49SAlexandre Bounine return -EIO; 12486429cd49SAlexandre Bounine } 12496429cd49SAlexandre Bounine pw_msg = NULL; 12506429cd49SAlexandre Bounine } 12516429cd49SAlexandre Bounine 1252e5cabeb3SAlexandre Bounine /* For End-point devices processing stops here */ 1253e5cabeb3SAlexandre Bounine if (!(rdev->pef & RIO_PEF_SWITCH)) 1254e5cabeb3SAlexandre Bounine return 0; 1255e5cabeb3SAlexandre Bounine 1256e5cabeb3SAlexandre Bounine if (rdev->phys_efptr == 0) { 1257e5cabeb3SAlexandre Bounine pr_err("RIO_PW: Bad switch initialization for %s\n", 1258e5cabeb3SAlexandre Bounine rio_name(rdev)); 1259e5cabeb3SAlexandre Bounine return 0; 1260e5cabeb3SAlexandre Bounine } 1261e5cabeb3SAlexandre Bounine 1262e5cabeb3SAlexandre Bounine /* 1263e5cabeb3SAlexandre Bounine * Process the port-write notification from switch 1264e5cabeb3SAlexandre Bounine */ 12652ec3ba69SAlexandre Bounine if (rdev->rswitch->ops && rdev->rswitch->ops->em_handle) 12662ec3ba69SAlexandre Bounine rdev->rswitch->ops->em_handle(rdev, portnum); 1267e5cabeb3SAlexandre Bounine 12681ae842deSAlexandre Bounine rio_read_config_32(rdev, RIO_DEV_PORT_N_ERR_STS_CSR(rdev, portnum), 1269e5cabeb3SAlexandre Bounine &err_status); 1270e5cabeb3SAlexandre Bounine pr_debug("RIO_PW: SP%d_ERR_STS_CSR=0x%08x\n", portnum, err_status); 1271e5cabeb3SAlexandre Bounine 1272dd5648c9SAlexandre Bounine if (err_status & RIO_PORT_N_ERR_STS_PORT_OK) { 1273dd5648c9SAlexandre Bounine 1274dd5648c9SAlexandre Bounine if (!(rdev->rswitch->port_ok & (1 << portnum))) { 1275dd5648c9SAlexandre Bounine rdev->rswitch->port_ok |= (1 << portnum); 1276dd5648c9SAlexandre Bounine rio_set_port_lockout(rdev, portnum, 0); 1277dd5648c9SAlexandre Bounine /* Schedule Insertion Service */ 1278dd5648c9SAlexandre Bounine pr_debug("RIO_PW: Device Insertion on [%s]-P%d\n", 1279dd5648c9SAlexandre Bounine rio_name(rdev), portnum); 1280e5cabeb3SAlexandre Bounine } 1281e5cabeb3SAlexandre Bounine 1282dd5648c9SAlexandre Bounine /* Clear error-stopped states (if reported). 1283dd5648c9SAlexandre Bounine * Depending on the link partner state, two attempts 1284dd5648c9SAlexandre Bounine * may be needed for successful recovery. 1285dd5648c9SAlexandre Bounine */ 12861ae842deSAlexandre Bounine if (err_status & (RIO_PORT_N_ERR_STS_OUT_ES | 12871ae842deSAlexandre Bounine RIO_PORT_N_ERR_STS_INP_ES)) { 1288dd5648c9SAlexandre Bounine if (rio_clr_err_stopped(rdev, portnum, err_status)) 1289dd5648c9SAlexandre Bounine rio_clr_err_stopped(rdev, portnum, 0); 1290e5cabeb3SAlexandre Bounine } 1291dd5648c9SAlexandre Bounine } else { /* if (err_status & RIO_PORT_N_ERR_STS_PORT_UNINIT) */ 1292e5cabeb3SAlexandre Bounine 1293e5cabeb3SAlexandre Bounine if (rdev->rswitch->port_ok & (1 << portnum)) { 1294e5cabeb3SAlexandre Bounine rdev->rswitch->port_ok &= ~(1 << portnum); 1295e5cabeb3SAlexandre Bounine rio_set_port_lockout(rdev, portnum, 1); 1296e5cabeb3SAlexandre Bounine 12971ae842deSAlexandre Bounine if (rdev->phys_rmap == 1) { 1298a93192a5SAlexandre Bounine rio_write_config_32(rdev, 12991ae842deSAlexandre Bounine RIO_DEV_PORT_N_ACK_STS_CSR(rdev, portnum), 1300e5cabeb3SAlexandre Bounine RIO_PORT_N_ACK_CLEAR); 13011ae842deSAlexandre Bounine } else { 13021ae842deSAlexandre Bounine rio_write_config_32(rdev, 13031ae842deSAlexandre Bounine RIO_DEV_PORT_N_OB_ACK_CSR(rdev, portnum), 13041ae842deSAlexandre Bounine RIO_PORT_N_OB_ACK_CLEAR); 13051ae842deSAlexandre Bounine rio_write_config_32(rdev, 13061ae842deSAlexandre Bounine RIO_DEV_PORT_N_IB_ACK_CSR(rdev, portnum), 13071ae842deSAlexandre Bounine 0); 13081ae842deSAlexandre Bounine } 1309e5cabeb3SAlexandre Bounine 1310e5cabeb3SAlexandre Bounine /* Schedule Extraction Service */ 1311e5cabeb3SAlexandre Bounine pr_debug("RIO_PW: Device Extraction on [%s]-P%d\n", 1312e5cabeb3SAlexandre Bounine rio_name(rdev), portnum); 1313e5cabeb3SAlexandre Bounine } 1314dd5648c9SAlexandre Bounine } 1315e5cabeb3SAlexandre Bounine 1316a93192a5SAlexandre Bounine rio_read_config_32(rdev, 1317dd5648c9SAlexandre Bounine rdev->em_efptr + RIO_EM_PN_ERR_DETECT(portnum), &em_perrdet); 1318dd5648c9SAlexandre Bounine if (em_perrdet) { 1319dd5648c9SAlexandre Bounine pr_debug("RIO_PW: RIO_EM_P%d_ERR_DETECT=0x%08x\n", 1320dd5648c9SAlexandre Bounine portnum, em_perrdet); 1321dd5648c9SAlexandre Bounine /* Clear EM Port N Error Detect CSR */ 1322a93192a5SAlexandre Bounine rio_write_config_32(rdev, 1323dd5648c9SAlexandre Bounine rdev->em_efptr + RIO_EM_PN_ERR_DETECT(portnum), 0); 1324e5cabeb3SAlexandre Bounine } 1325dd5648c9SAlexandre Bounine 1326a93192a5SAlexandre Bounine rio_read_config_32(rdev, 1327dd5648c9SAlexandre Bounine rdev->em_efptr + RIO_EM_LTL_ERR_DETECT, &em_ltlerrdet); 1328dd5648c9SAlexandre Bounine if (em_ltlerrdet) { 1329dd5648c9SAlexandre Bounine pr_debug("RIO_PW: RIO_EM_LTL_ERR_DETECT=0x%08x\n", 1330dd5648c9SAlexandre Bounine em_ltlerrdet); 1331dd5648c9SAlexandre Bounine /* Clear EM L/T Layer Error Detect CSR */ 1332a93192a5SAlexandre Bounine rio_write_config_32(rdev, 1333dd5648c9SAlexandre Bounine rdev->em_efptr + RIO_EM_LTL_ERR_DETECT, 0); 1334e5cabeb3SAlexandre Bounine } 1335e5cabeb3SAlexandre Bounine 1336388c45ccSAlexandre Bounine /* Clear remaining error bits and Port-Write Pending bit */ 13371ae842deSAlexandre Bounine rio_write_config_32(rdev, RIO_DEV_PORT_N_ERR_STS_CSR(rdev, portnum), 1338388c45ccSAlexandre Bounine err_status); 1339e5cabeb3SAlexandre Bounine 1340e5cabeb3SAlexandre Bounine return 0; 1341e5cabeb3SAlexandre Bounine } 1342e5cabeb3SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_inb_pwrite_handler); 1343e5cabeb3SAlexandre Bounine 1344e5cabeb3SAlexandre Bounine /** 1345e5cabeb3SAlexandre Bounine * rio_mport_get_efb - get pointer to next extended features block 1346e5cabeb3SAlexandre Bounine * @port: Master port to issue transaction 1347e5cabeb3SAlexandre Bounine * @local: Indicate a local master port or remote device access 1348e5cabeb3SAlexandre Bounine * @destid: Destination ID of the device 1349e5cabeb3SAlexandre Bounine * @hopcount: Number of switch hops to the device 1350e5cabeb3SAlexandre Bounine * @from: Offset of current Extended Feature block header (if 0 starts 1351e5cabeb3SAlexandre Bounine * from ExtFeaturePtr) 1352e5cabeb3SAlexandre Bounine */ 1353e5cabeb3SAlexandre Bounine u32 1354e5cabeb3SAlexandre Bounine rio_mport_get_efb(struct rio_mport *port, int local, u16 destid, 1355e5cabeb3SAlexandre Bounine u8 hopcount, u32 from) 1356e5cabeb3SAlexandre Bounine { 1357e5cabeb3SAlexandre Bounine u32 reg_val; 1358e5cabeb3SAlexandre Bounine 1359e5cabeb3SAlexandre Bounine if (from == 0) { 1360e5cabeb3SAlexandre Bounine if (local) 1361e5cabeb3SAlexandre Bounine rio_local_read_config_32(port, RIO_ASM_INFO_CAR, 1362e5cabeb3SAlexandre Bounine ®_val); 1363e5cabeb3SAlexandre Bounine else 1364e5cabeb3SAlexandre Bounine rio_mport_read_config_32(port, destid, hopcount, 1365e5cabeb3SAlexandre Bounine RIO_ASM_INFO_CAR, ®_val); 1366e5cabeb3SAlexandre Bounine return reg_val & RIO_EXT_FTR_PTR_MASK; 1367e5cabeb3SAlexandre Bounine } else { 1368e5cabeb3SAlexandre Bounine if (local) 1369e5cabeb3SAlexandre Bounine rio_local_read_config_32(port, from, ®_val); 1370e5cabeb3SAlexandre Bounine else 1371e5cabeb3SAlexandre Bounine rio_mport_read_config_32(port, destid, hopcount, 1372e5cabeb3SAlexandre Bounine from, ®_val); 1373e5cabeb3SAlexandre Bounine return RIO_GET_BLOCK_ID(reg_val); 1374e5cabeb3SAlexandre Bounine } 1375e5cabeb3SAlexandre Bounine } 1376a11650e1SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_mport_get_efb); 1377e5cabeb3SAlexandre Bounine 1378e5cabeb3SAlexandre Bounine /** 1379394b701cSMatt Porter * rio_mport_get_feature - query for devices' extended features 1380394b701cSMatt Porter * @port: Master port to issue transaction 1381394b701cSMatt Porter * @local: Indicate a local master port or remote device access 1382394b701cSMatt Porter * @destid: Destination ID of the device 1383394b701cSMatt Porter * @hopcount: Number of switch hops to the device 1384394b701cSMatt Porter * @ftr: Extended feature code 1385394b701cSMatt Porter * 1386394b701cSMatt Porter * Tell if a device supports a given RapidIO capability. 1387394b701cSMatt Porter * Returns the offset of the requested extended feature 1388394b701cSMatt Porter * block within the device's RIO configuration space or 13891ae842deSAlexandre Bounine * 0 in case the device does not support it. 1390394b701cSMatt Porter */ 1391394b701cSMatt Porter u32 1392394b701cSMatt Porter rio_mport_get_feature(struct rio_mport * port, int local, u16 destid, 1393394b701cSMatt Porter u8 hopcount, int ftr) 1394394b701cSMatt Porter { 1395394b701cSMatt Porter u32 asm_info, ext_ftr_ptr, ftr_header; 1396394b701cSMatt Porter 1397394b701cSMatt Porter if (local) 1398394b701cSMatt Porter rio_local_read_config_32(port, RIO_ASM_INFO_CAR, &asm_info); 1399394b701cSMatt Porter else 1400394b701cSMatt Porter rio_mport_read_config_32(port, destid, hopcount, 1401394b701cSMatt Porter RIO_ASM_INFO_CAR, &asm_info); 1402394b701cSMatt Porter 1403394b701cSMatt Porter ext_ftr_ptr = asm_info & RIO_EXT_FTR_PTR_MASK; 1404394b701cSMatt Porter 1405394b701cSMatt Porter while (ext_ftr_ptr) { 1406394b701cSMatt Porter if (local) 1407394b701cSMatt Porter rio_local_read_config_32(port, ext_ftr_ptr, 1408394b701cSMatt Porter &ftr_header); 1409394b701cSMatt Porter else 1410394b701cSMatt Porter rio_mport_read_config_32(port, destid, hopcount, 1411394b701cSMatt Porter ext_ftr_ptr, &ftr_header); 1412394b701cSMatt Porter if (RIO_GET_BLOCK_ID(ftr_header) == ftr) 1413394b701cSMatt Porter return ext_ftr_ptr; 1414394b701cSMatt Porter if (!(ext_ftr_ptr = RIO_GET_BLOCK_PTR(ftr_header))) 1415394b701cSMatt Porter break; 1416394b701cSMatt Porter } 1417394b701cSMatt Porter 1418394b701cSMatt Porter return 0; 1419394b701cSMatt Porter } 1420a11650e1SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_mport_get_feature); 1421394b701cSMatt Porter 1422394b701cSMatt Porter /** 1423394b701cSMatt Porter * rio_get_asm - Begin or continue searching for a RIO device by vid/did/asm_vid/asm_did 1424394b701cSMatt Porter * @vid: RIO vid to match or %RIO_ANY_ID to match all vids 1425394b701cSMatt Porter * @did: RIO did to match or %RIO_ANY_ID to match all dids 1426394b701cSMatt Porter * @asm_vid: RIO asm_vid to match or %RIO_ANY_ID to match all asm_vids 1427394b701cSMatt Porter * @asm_did: RIO asm_did to match or %RIO_ANY_ID to match all asm_dids 1428394b701cSMatt Porter * @from: Previous RIO device found in search, or %NULL for new search 1429394b701cSMatt Porter * 1430394b701cSMatt Porter * Iterates through the list of known RIO devices. If a RIO device is 1431394b701cSMatt Porter * found with a matching @vid, @did, @asm_vid, @asm_did, the reference 1432394b701cSMatt Porter * count to the device is incrememted and a pointer to its device 1433394b701cSMatt Porter * structure is returned. Otherwise, %NULL is returned. A new search 1434394b701cSMatt Porter * is initiated by passing %NULL to the @from argument. Otherwise, if 1435394b701cSMatt Porter * @from is not %NULL, searches continue from next device on the global 1436394b701cSMatt Porter * list. The reference count for @from is always decremented if it is 1437394b701cSMatt Porter * not %NULL. 1438394b701cSMatt Porter */ 1439394b701cSMatt Porter struct rio_dev *rio_get_asm(u16 vid, u16 did, 1440394b701cSMatt Porter u16 asm_vid, u16 asm_did, struct rio_dev *from) 1441394b701cSMatt Porter { 1442394b701cSMatt Porter struct list_head *n; 1443394b701cSMatt Porter struct rio_dev *rdev; 1444394b701cSMatt Porter 1445394b701cSMatt Porter WARN_ON(in_interrupt()); 1446394b701cSMatt Porter spin_lock(&rio_global_list_lock); 1447394b701cSMatt Porter n = from ? from->global_list.next : rio_devices.next; 1448394b701cSMatt Porter 1449394b701cSMatt Porter while (n && (n != &rio_devices)) { 1450394b701cSMatt Porter rdev = rio_dev_g(n); 1451394b701cSMatt Porter if ((vid == RIO_ANY_ID || rdev->vid == vid) && 1452394b701cSMatt Porter (did == RIO_ANY_ID || rdev->did == did) && 1453394b701cSMatt Porter (asm_vid == RIO_ANY_ID || rdev->asm_vid == asm_vid) && 1454394b701cSMatt Porter (asm_did == RIO_ANY_ID || rdev->asm_did == asm_did)) 1455394b701cSMatt Porter goto exit; 1456394b701cSMatt Porter n = n->next; 1457394b701cSMatt Porter } 1458394b701cSMatt Porter rdev = NULL; 1459394b701cSMatt Porter exit: 1460394b701cSMatt Porter rio_dev_put(from); 1461394b701cSMatt Porter rdev = rio_dev_get(rdev); 1462394b701cSMatt Porter spin_unlock(&rio_global_list_lock); 1463394b701cSMatt Porter return rdev; 1464394b701cSMatt Porter } 1465394b701cSMatt Porter 1466394b701cSMatt Porter /** 1467394b701cSMatt Porter * rio_get_device - Begin or continue searching for a RIO device by vid/did 1468394b701cSMatt Porter * @vid: RIO vid to match or %RIO_ANY_ID to match all vids 1469394b701cSMatt Porter * @did: RIO did to match or %RIO_ANY_ID to match all dids 1470394b701cSMatt Porter * @from: Previous RIO device found in search, or %NULL for new search 1471394b701cSMatt Porter * 1472394b701cSMatt Porter * Iterates through the list of known RIO devices. If a RIO device is 1473394b701cSMatt Porter * found with a matching @vid and @did, the reference count to the 1474394b701cSMatt Porter * device is incrememted and a pointer to its device structure is returned. 1475394b701cSMatt Porter * Otherwise, %NULL is returned. A new search is initiated by passing %NULL 1476394b701cSMatt Porter * to the @from argument. Otherwise, if @from is not %NULL, searches 1477394b701cSMatt Porter * continue from next device on the global list. The reference count for 1478394b701cSMatt Porter * @from is always decremented if it is not %NULL. 1479394b701cSMatt Porter */ 1480394b701cSMatt Porter struct rio_dev *rio_get_device(u16 vid, u16 did, struct rio_dev *from) 1481394b701cSMatt Porter { 1482394b701cSMatt Porter return rio_get_asm(vid, did, RIO_ANY_ID, RIO_ANY_ID, from); 1483394b701cSMatt Porter } 1484394b701cSMatt Porter 148507590ff0SAlexandre Bounine /** 148607590ff0SAlexandre Bounine * rio_std_route_add_entry - Add switch route table entry using standard 148707590ff0SAlexandre Bounine * registers defined in RIO specification rev.1.3 148807590ff0SAlexandre Bounine * @mport: Master port to issue transaction 148907590ff0SAlexandre Bounine * @destid: Destination ID of the device 149007590ff0SAlexandre Bounine * @hopcount: Number of switch hops to the device 149107590ff0SAlexandre Bounine * @table: routing table ID (global or port-specific) 149207590ff0SAlexandre Bounine * @route_destid: destID entry in the RT 149307590ff0SAlexandre Bounine * @route_port: destination port for specified destID 149407590ff0SAlexandre Bounine */ 14952ec3ba69SAlexandre Bounine static int 14962ec3ba69SAlexandre Bounine rio_std_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount, 149707590ff0SAlexandre Bounine u16 table, u16 route_destid, u8 route_port) 149807590ff0SAlexandre Bounine { 149907590ff0SAlexandre Bounine if (table == RIO_GLOBAL_TABLE) { 150007590ff0SAlexandre Bounine rio_mport_write_config_32(mport, destid, hopcount, 150107590ff0SAlexandre Bounine RIO_STD_RTE_CONF_DESTID_SEL_CSR, 150207590ff0SAlexandre Bounine (u32)route_destid); 150307590ff0SAlexandre Bounine rio_mport_write_config_32(mport, destid, hopcount, 150407590ff0SAlexandre Bounine RIO_STD_RTE_CONF_PORT_SEL_CSR, 150507590ff0SAlexandre Bounine (u32)route_port); 150607590ff0SAlexandre Bounine } 1507e5cabeb3SAlexandre Bounine 150807590ff0SAlexandre Bounine udelay(10); 150907590ff0SAlexandre Bounine return 0; 151007590ff0SAlexandre Bounine } 151107590ff0SAlexandre Bounine 151207590ff0SAlexandre Bounine /** 151307590ff0SAlexandre Bounine * rio_std_route_get_entry - Read switch route table entry (port number) 1514638c5945SUwe Kleine-König * associated with specified destID using standard registers defined in RIO 151507590ff0SAlexandre Bounine * specification rev.1.3 151607590ff0SAlexandre Bounine * @mport: Master port to issue transaction 151707590ff0SAlexandre Bounine * @destid: Destination ID of the device 151807590ff0SAlexandre Bounine * @hopcount: Number of switch hops to the device 151907590ff0SAlexandre Bounine * @table: routing table ID (global or port-specific) 152007590ff0SAlexandre Bounine * @route_destid: destID entry in the RT 152107590ff0SAlexandre Bounine * @route_port: returned destination port for specified destID 152207590ff0SAlexandre Bounine */ 15232ec3ba69SAlexandre Bounine static int 15242ec3ba69SAlexandre Bounine rio_std_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount, 152507590ff0SAlexandre Bounine u16 table, u16 route_destid, u8 *route_port) 152607590ff0SAlexandre Bounine { 152707590ff0SAlexandre Bounine u32 result; 152807590ff0SAlexandre Bounine 152907590ff0SAlexandre Bounine if (table == RIO_GLOBAL_TABLE) { 153007590ff0SAlexandre Bounine rio_mport_write_config_32(mport, destid, hopcount, 153107590ff0SAlexandre Bounine RIO_STD_RTE_CONF_DESTID_SEL_CSR, route_destid); 153207590ff0SAlexandre Bounine rio_mport_read_config_32(mport, destid, hopcount, 153307590ff0SAlexandre Bounine RIO_STD_RTE_CONF_PORT_SEL_CSR, &result); 153407590ff0SAlexandre Bounine 153507590ff0SAlexandre Bounine *route_port = (u8)result; 153607590ff0SAlexandre Bounine } 153707590ff0SAlexandre Bounine 153807590ff0SAlexandre Bounine return 0; 153907590ff0SAlexandre Bounine } 154007590ff0SAlexandre Bounine 154107590ff0SAlexandre Bounine /** 154207590ff0SAlexandre Bounine * rio_std_route_clr_table - Clear swotch route table using standard registers 154307590ff0SAlexandre Bounine * defined in RIO specification rev.1.3. 154407590ff0SAlexandre Bounine * @mport: Master port to issue transaction 154507590ff0SAlexandre Bounine * @destid: Destination ID of the device 154607590ff0SAlexandre Bounine * @hopcount: Number of switch hops to the device 154707590ff0SAlexandre Bounine * @table: routing table ID (global or port-specific) 154807590ff0SAlexandre Bounine */ 15492ec3ba69SAlexandre Bounine static int 15502ec3ba69SAlexandre Bounine rio_std_route_clr_table(struct rio_mport *mport, u16 destid, u8 hopcount, 155107590ff0SAlexandre Bounine u16 table) 155207590ff0SAlexandre Bounine { 155307590ff0SAlexandre Bounine u32 max_destid = 0xff; 155407590ff0SAlexandre Bounine u32 i, pef, id_inc = 1, ext_cfg = 0; 155507590ff0SAlexandre Bounine u32 port_sel = RIO_INVALID_ROUTE; 155607590ff0SAlexandre Bounine 155707590ff0SAlexandre Bounine if (table == RIO_GLOBAL_TABLE) { 155807590ff0SAlexandre Bounine rio_mport_read_config_32(mport, destid, hopcount, 155907590ff0SAlexandre Bounine RIO_PEF_CAR, &pef); 156007590ff0SAlexandre Bounine 156107590ff0SAlexandre Bounine if (mport->sys_size) { 156207590ff0SAlexandre Bounine rio_mport_read_config_32(mport, destid, hopcount, 156307590ff0SAlexandre Bounine RIO_SWITCH_RT_LIMIT, 156407590ff0SAlexandre Bounine &max_destid); 156507590ff0SAlexandre Bounine max_destid &= RIO_RT_MAX_DESTID; 156607590ff0SAlexandre Bounine } 156707590ff0SAlexandre Bounine 156807590ff0SAlexandre Bounine if (pef & RIO_PEF_EXT_RT) { 156907590ff0SAlexandre Bounine ext_cfg = 0x80000000; 157007590ff0SAlexandre Bounine id_inc = 4; 157107590ff0SAlexandre Bounine port_sel = (RIO_INVALID_ROUTE << 24) | 157207590ff0SAlexandre Bounine (RIO_INVALID_ROUTE << 16) | 157307590ff0SAlexandre Bounine (RIO_INVALID_ROUTE << 8) | 157407590ff0SAlexandre Bounine RIO_INVALID_ROUTE; 157507590ff0SAlexandre Bounine } 157607590ff0SAlexandre Bounine 157707590ff0SAlexandre Bounine for (i = 0; i <= max_destid;) { 157807590ff0SAlexandre Bounine rio_mport_write_config_32(mport, destid, hopcount, 157907590ff0SAlexandre Bounine RIO_STD_RTE_CONF_DESTID_SEL_CSR, 158007590ff0SAlexandre Bounine ext_cfg | i); 158107590ff0SAlexandre Bounine rio_mport_write_config_32(mport, destid, hopcount, 158207590ff0SAlexandre Bounine RIO_STD_RTE_CONF_PORT_SEL_CSR, 158307590ff0SAlexandre Bounine port_sel); 158407590ff0SAlexandre Bounine i += id_inc; 158507590ff0SAlexandre Bounine } 158607590ff0SAlexandre Bounine } 158707590ff0SAlexandre Bounine 158807590ff0SAlexandre Bounine udelay(10); 158907590ff0SAlexandre Bounine return 0; 159007590ff0SAlexandre Bounine } 159107590ff0SAlexandre Bounine 15922ec3ba69SAlexandre Bounine /** 15932ec3ba69SAlexandre Bounine * rio_lock_device - Acquires host device lock for specified device 15942ec3ba69SAlexandre Bounine * @port: Master port to send transaction 15952ec3ba69SAlexandre Bounine * @destid: Destination ID for device/switch 15962ec3ba69SAlexandre Bounine * @hopcount: Hopcount to reach switch 15972ec3ba69SAlexandre Bounine * @wait_ms: Max wait time in msec (0 = no timeout) 15982ec3ba69SAlexandre Bounine * 15992ec3ba69SAlexandre Bounine * Attepts to acquire host device lock for specified device 16002ec3ba69SAlexandre Bounine * Returns 0 if device lock acquired or EINVAL if timeout expires. 16012ec3ba69SAlexandre Bounine */ 16022ec3ba69SAlexandre Bounine int rio_lock_device(struct rio_mport *port, u16 destid, 16032ec3ba69SAlexandre Bounine u8 hopcount, int wait_ms) 16042ec3ba69SAlexandre Bounine { 16052ec3ba69SAlexandre Bounine u32 result; 16062ec3ba69SAlexandre Bounine int tcnt = 0; 16072ec3ba69SAlexandre Bounine 16082ec3ba69SAlexandre Bounine /* Attempt to acquire device lock */ 16092ec3ba69SAlexandre Bounine rio_mport_write_config_32(port, destid, hopcount, 16102ec3ba69SAlexandre Bounine RIO_HOST_DID_LOCK_CSR, port->host_deviceid); 16112ec3ba69SAlexandre Bounine rio_mport_read_config_32(port, destid, hopcount, 16122ec3ba69SAlexandre Bounine RIO_HOST_DID_LOCK_CSR, &result); 16132ec3ba69SAlexandre Bounine 16142ec3ba69SAlexandre Bounine while (result != port->host_deviceid) { 16152ec3ba69SAlexandre Bounine if (wait_ms != 0 && tcnt == wait_ms) { 16162ec3ba69SAlexandre Bounine pr_debug("RIO: timeout when locking device %x:%x\n", 16172ec3ba69SAlexandre Bounine destid, hopcount); 16182ec3ba69SAlexandre Bounine return -EINVAL; 16192ec3ba69SAlexandre Bounine } 16202ec3ba69SAlexandre Bounine 16212ec3ba69SAlexandre Bounine /* Delay a bit */ 16222ec3ba69SAlexandre Bounine mdelay(1); 16232ec3ba69SAlexandre Bounine tcnt++; 16242ec3ba69SAlexandre Bounine /* Try to acquire device lock again */ 16252ec3ba69SAlexandre Bounine rio_mport_write_config_32(port, destid, 16262ec3ba69SAlexandre Bounine hopcount, 16272ec3ba69SAlexandre Bounine RIO_HOST_DID_LOCK_CSR, 16282ec3ba69SAlexandre Bounine port->host_deviceid); 16292ec3ba69SAlexandre Bounine rio_mport_read_config_32(port, destid, 16302ec3ba69SAlexandre Bounine hopcount, 16312ec3ba69SAlexandre Bounine RIO_HOST_DID_LOCK_CSR, &result); 16322ec3ba69SAlexandre Bounine } 16332ec3ba69SAlexandre Bounine 16342ec3ba69SAlexandre Bounine return 0; 16352ec3ba69SAlexandre Bounine } 16362ec3ba69SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_lock_device); 16372ec3ba69SAlexandre Bounine 16382ec3ba69SAlexandre Bounine /** 16392ec3ba69SAlexandre Bounine * rio_unlock_device - Releases host device lock for specified device 16402ec3ba69SAlexandre Bounine * @port: Master port to send transaction 16412ec3ba69SAlexandre Bounine * @destid: Destination ID for device/switch 16422ec3ba69SAlexandre Bounine * @hopcount: Hopcount to reach switch 16432ec3ba69SAlexandre Bounine * 16442ec3ba69SAlexandre Bounine * Returns 0 if device lock released or EINVAL if fails. 16452ec3ba69SAlexandre Bounine */ 16462ec3ba69SAlexandre Bounine int rio_unlock_device(struct rio_mport *port, u16 destid, u8 hopcount) 16472ec3ba69SAlexandre Bounine { 16482ec3ba69SAlexandre Bounine u32 result; 16492ec3ba69SAlexandre Bounine 16502ec3ba69SAlexandre Bounine /* Release device lock */ 16512ec3ba69SAlexandre Bounine rio_mport_write_config_32(port, destid, 16522ec3ba69SAlexandre Bounine hopcount, 16532ec3ba69SAlexandre Bounine RIO_HOST_DID_LOCK_CSR, 16542ec3ba69SAlexandre Bounine port->host_deviceid); 16552ec3ba69SAlexandre Bounine rio_mport_read_config_32(port, destid, hopcount, 16562ec3ba69SAlexandre Bounine RIO_HOST_DID_LOCK_CSR, &result); 16572ec3ba69SAlexandre Bounine if ((result & 0xffff) != 0xffff) { 16582ec3ba69SAlexandre Bounine pr_debug("RIO: badness when releasing device lock %x:%x\n", 16592ec3ba69SAlexandre Bounine destid, hopcount); 16602ec3ba69SAlexandre Bounine return -EINVAL; 16612ec3ba69SAlexandre Bounine } 16622ec3ba69SAlexandre Bounine 16632ec3ba69SAlexandre Bounine return 0; 16642ec3ba69SAlexandre Bounine } 16652ec3ba69SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_unlock_device); 16662ec3ba69SAlexandre Bounine 16672ec3ba69SAlexandre Bounine /** 16682ec3ba69SAlexandre Bounine * rio_route_add_entry- Add a route entry to a switch routing table 16692ec3ba69SAlexandre Bounine * @rdev: RIO device 16702ec3ba69SAlexandre Bounine * @table: Routing table ID 16712ec3ba69SAlexandre Bounine * @route_destid: Destination ID to be routed 16722ec3ba69SAlexandre Bounine * @route_port: Port number to be routed 16732ec3ba69SAlexandre Bounine * @lock: apply a hardware lock on switch device flag (1=lock, 0=no_lock) 16742ec3ba69SAlexandre Bounine * 16752ec3ba69SAlexandre Bounine * If available calls the switch specific add_entry() method to add a route 16762ec3ba69SAlexandre Bounine * entry into a switch routing table. Otherwise uses standard RT update method 16772ec3ba69SAlexandre Bounine * as defined by RapidIO specification. A specific routing table can be selected 16782ec3ba69SAlexandre Bounine * using the @table argument if a switch has per port routing tables or 16792ec3ba69SAlexandre Bounine * the standard (or global) table may be used by passing 16802ec3ba69SAlexandre Bounine * %RIO_GLOBAL_TABLE in @table. 16812ec3ba69SAlexandre Bounine * 16822ec3ba69SAlexandre Bounine * Returns %0 on success or %-EINVAL on failure. 16832ec3ba69SAlexandre Bounine */ 16842ec3ba69SAlexandre Bounine int rio_route_add_entry(struct rio_dev *rdev, 16852ec3ba69SAlexandre Bounine u16 table, u16 route_destid, u8 route_port, int lock) 16862ec3ba69SAlexandre Bounine { 16872ec3ba69SAlexandre Bounine int rc = -EINVAL; 16882ec3ba69SAlexandre Bounine struct rio_switch_ops *ops = rdev->rswitch->ops; 16892ec3ba69SAlexandre Bounine 16902ec3ba69SAlexandre Bounine if (lock) { 16912ec3ba69SAlexandre Bounine rc = rio_lock_device(rdev->net->hport, rdev->destid, 16922ec3ba69SAlexandre Bounine rdev->hopcount, 1000); 16932ec3ba69SAlexandre Bounine if (rc) 16942ec3ba69SAlexandre Bounine return rc; 16952ec3ba69SAlexandre Bounine } 16962ec3ba69SAlexandre Bounine 16972ec3ba69SAlexandre Bounine spin_lock(&rdev->rswitch->lock); 16982ec3ba69SAlexandre Bounine 169993dd49afSMarkus Elfring if (!ops || !ops->add_entry) { 17002ec3ba69SAlexandre Bounine rc = rio_std_route_add_entry(rdev->net->hport, rdev->destid, 17012ec3ba69SAlexandre Bounine rdev->hopcount, table, 17022ec3ba69SAlexandre Bounine route_destid, route_port); 17032ec3ba69SAlexandre Bounine } else if (try_module_get(ops->owner)) { 17042ec3ba69SAlexandre Bounine rc = ops->add_entry(rdev->net->hport, rdev->destid, 17052ec3ba69SAlexandre Bounine rdev->hopcount, table, route_destid, 17062ec3ba69SAlexandre Bounine route_port); 17072ec3ba69SAlexandre Bounine module_put(ops->owner); 17082ec3ba69SAlexandre Bounine } 17092ec3ba69SAlexandre Bounine 17102ec3ba69SAlexandre Bounine spin_unlock(&rdev->rswitch->lock); 17112ec3ba69SAlexandre Bounine 17122ec3ba69SAlexandre Bounine if (lock) 17132ec3ba69SAlexandre Bounine rio_unlock_device(rdev->net->hport, rdev->destid, 17142ec3ba69SAlexandre Bounine rdev->hopcount); 17152ec3ba69SAlexandre Bounine 17162ec3ba69SAlexandre Bounine return rc; 17172ec3ba69SAlexandre Bounine } 17182ec3ba69SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_route_add_entry); 17192ec3ba69SAlexandre Bounine 17202ec3ba69SAlexandre Bounine /** 17212ec3ba69SAlexandre Bounine * rio_route_get_entry- Read an entry from a switch routing table 17222ec3ba69SAlexandre Bounine * @rdev: RIO device 17232ec3ba69SAlexandre Bounine * @table: Routing table ID 17242ec3ba69SAlexandre Bounine * @route_destid: Destination ID to be routed 17252ec3ba69SAlexandre Bounine * @route_port: Pointer to read port number into 17262ec3ba69SAlexandre Bounine * @lock: apply a hardware lock on switch device flag (1=lock, 0=no_lock) 17272ec3ba69SAlexandre Bounine * 17282ec3ba69SAlexandre Bounine * If available calls the switch specific get_entry() method to fetch a route 17292ec3ba69SAlexandre Bounine * entry from a switch routing table. Otherwise uses standard RT read method 17302ec3ba69SAlexandre Bounine * as defined by RapidIO specification. A specific routing table can be selected 17312ec3ba69SAlexandre Bounine * using the @table argument if a switch has per port routing tables or 17322ec3ba69SAlexandre Bounine * the standard (or global) table may be used by passing 17332ec3ba69SAlexandre Bounine * %RIO_GLOBAL_TABLE in @table. 17342ec3ba69SAlexandre Bounine * 17352ec3ba69SAlexandre Bounine * Returns %0 on success or %-EINVAL on failure. 17362ec3ba69SAlexandre Bounine */ 17372ec3ba69SAlexandre Bounine int rio_route_get_entry(struct rio_dev *rdev, u16 table, 17382ec3ba69SAlexandre Bounine u16 route_destid, u8 *route_port, int lock) 17392ec3ba69SAlexandre Bounine { 17402ec3ba69SAlexandre Bounine int rc = -EINVAL; 17412ec3ba69SAlexandre Bounine struct rio_switch_ops *ops = rdev->rswitch->ops; 17422ec3ba69SAlexandre Bounine 17432ec3ba69SAlexandre Bounine if (lock) { 17442ec3ba69SAlexandre Bounine rc = rio_lock_device(rdev->net->hport, rdev->destid, 17452ec3ba69SAlexandre Bounine rdev->hopcount, 1000); 17462ec3ba69SAlexandre Bounine if (rc) 17472ec3ba69SAlexandre Bounine return rc; 17482ec3ba69SAlexandre Bounine } 17492ec3ba69SAlexandre Bounine 17502ec3ba69SAlexandre Bounine spin_lock(&rdev->rswitch->lock); 17512ec3ba69SAlexandre Bounine 175293dd49afSMarkus Elfring if (!ops || !ops->get_entry) { 17532ec3ba69SAlexandre Bounine rc = rio_std_route_get_entry(rdev->net->hport, rdev->destid, 17542ec3ba69SAlexandre Bounine rdev->hopcount, table, 17552ec3ba69SAlexandre Bounine route_destid, route_port); 17562ec3ba69SAlexandre Bounine } else if (try_module_get(ops->owner)) { 17572ec3ba69SAlexandre Bounine rc = ops->get_entry(rdev->net->hport, rdev->destid, 17582ec3ba69SAlexandre Bounine rdev->hopcount, table, route_destid, 17592ec3ba69SAlexandre Bounine route_port); 17602ec3ba69SAlexandre Bounine module_put(ops->owner); 17612ec3ba69SAlexandre Bounine } 17622ec3ba69SAlexandre Bounine 17632ec3ba69SAlexandre Bounine spin_unlock(&rdev->rswitch->lock); 17642ec3ba69SAlexandre Bounine 17652ec3ba69SAlexandre Bounine if (lock) 17662ec3ba69SAlexandre Bounine rio_unlock_device(rdev->net->hport, rdev->destid, 17672ec3ba69SAlexandre Bounine rdev->hopcount); 17682ec3ba69SAlexandre Bounine return rc; 17692ec3ba69SAlexandre Bounine } 17702ec3ba69SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_route_get_entry); 17712ec3ba69SAlexandre Bounine 17722ec3ba69SAlexandre Bounine /** 17732ec3ba69SAlexandre Bounine * rio_route_clr_table - Clear a switch routing table 17742ec3ba69SAlexandre Bounine * @rdev: RIO device 17752ec3ba69SAlexandre Bounine * @table: Routing table ID 17762ec3ba69SAlexandre Bounine * @lock: apply a hardware lock on switch device flag (1=lock, 0=no_lock) 17772ec3ba69SAlexandre Bounine * 17782ec3ba69SAlexandre Bounine * If available calls the switch specific clr_table() method to clear a switch 17792ec3ba69SAlexandre Bounine * routing table. Otherwise uses standard RT write method as defined by RapidIO 17802ec3ba69SAlexandre Bounine * specification. A specific routing table can be selected using the @table 17812ec3ba69SAlexandre Bounine * argument if a switch has per port routing tables or the standard (or global) 17822ec3ba69SAlexandre Bounine * table may be used by passing %RIO_GLOBAL_TABLE in @table. 17832ec3ba69SAlexandre Bounine * 17842ec3ba69SAlexandre Bounine * Returns %0 on success or %-EINVAL on failure. 17852ec3ba69SAlexandre Bounine */ 17862ec3ba69SAlexandre Bounine int rio_route_clr_table(struct rio_dev *rdev, u16 table, int lock) 17872ec3ba69SAlexandre Bounine { 17882ec3ba69SAlexandre Bounine int rc = -EINVAL; 17892ec3ba69SAlexandre Bounine struct rio_switch_ops *ops = rdev->rswitch->ops; 17902ec3ba69SAlexandre Bounine 17912ec3ba69SAlexandre Bounine if (lock) { 17922ec3ba69SAlexandre Bounine rc = rio_lock_device(rdev->net->hport, rdev->destid, 17932ec3ba69SAlexandre Bounine rdev->hopcount, 1000); 17942ec3ba69SAlexandre Bounine if (rc) 17952ec3ba69SAlexandre Bounine return rc; 17962ec3ba69SAlexandre Bounine } 17972ec3ba69SAlexandre Bounine 17982ec3ba69SAlexandre Bounine spin_lock(&rdev->rswitch->lock); 17992ec3ba69SAlexandre Bounine 180093dd49afSMarkus Elfring if (!ops || !ops->clr_table) { 18012ec3ba69SAlexandre Bounine rc = rio_std_route_clr_table(rdev->net->hport, rdev->destid, 18022ec3ba69SAlexandre Bounine rdev->hopcount, table); 18032ec3ba69SAlexandre Bounine } else if (try_module_get(ops->owner)) { 18042ec3ba69SAlexandre Bounine rc = ops->clr_table(rdev->net->hport, rdev->destid, 18052ec3ba69SAlexandre Bounine rdev->hopcount, table); 18062ec3ba69SAlexandre Bounine 18072ec3ba69SAlexandre Bounine module_put(ops->owner); 18082ec3ba69SAlexandre Bounine } 18092ec3ba69SAlexandre Bounine 18102ec3ba69SAlexandre Bounine spin_unlock(&rdev->rswitch->lock); 18112ec3ba69SAlexandre Bounine 18122ec3ba69SAlexandre Bounine if (lock) 18132ec3ba69SAlexandre Bounine rio_unlock_device(rdev->net->hport, rdev->destid, 18142ec3ba69SAlexandre Bounine rdev->hopcount); 18152ec3ba69SAlexandre Bounine 18162ec3ba69SAlexandre Bounine return rc; 18172ec3ba69SAlexandre Bounine } 18182ec3ba69SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_route_clr_table); 18192ec3ba69SAlexandre Bounine 1820e42d98ebSAlexandre Bounine #ifdef CONFIG_RAPIDIO_DMA_ENGINE 1821e42d98ebSAlexandre Bounine 1822e42d98ebSAlexandre Bounine static bool rio_chan_filter(struct dma_chan *chan, void *arg) 1823e42d98ebSAlexandre Bounine { 18244aff1ce7SAlexandre Bounine struct rio_mport *mport = arg; 1825e42d98ebSAlexandre Bounine 1826e42d98ebSAlexandre Bounine /* Check that DMA device belongs to the right MPORT */ 18274aff1ce7SAlexandre Bounine return mport == container_of(chan->device, struct rio_mport, dma); 1828e42d98ebSAlexandre Bounine } 1829e42d98ebSAlexandre Bounine 1830e42d98ebSAlexandre Bounine /** 18314aff1ce7SAlexandre Bounine * rio_request_mport_dma - request RapidIO capable DMA channel associated 18324aff1ce7SAlexandre Bounine * with specified local RapidIO mport device. 18334aff1ce7SAlexandre Bounine * @mport: RIO mport to perform DMA data transfers 18344aff1ce7SAlexandre Bounine * 18354aff1ce7SAlexandre Bounine * Returns pointer to allocated DMA channel or NULL if failed. 18364aff1ce7SAlexandre Bounine */ 18374aff1ce7SAlexandre Bounine struct dma_chan *rio_request_mport_dma(struct rio_mport *mport) 18384aff1ce7SAlexandre Bounine { 18394aff1ce7SAlexandre Bounine dma_cap_mask_t mask; 18404aff1ce7SAlexandre Bounine 18414aff1ce7SAlexandre Bounine dma_cap_zero(mask); 18424aff1ce7SAlexandre Bounine dma_cap_set(DMA_SLAVE, mask); 18434aff1ce7SAlexandre Bounine return dma_request_channel(mask, rio_chan_filter, mport); 18444aff1ce7SAlexandre Bounine } 18454aff1ce7SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_request_mport_dma); 18464aff1ce7SAlexandre Bounine 18474aff1ce7SAlexandre Bounine /** 1848e42d98ebSAlexandre Bounine * rio_request_dma - request RapidIO capable DMA channel that supports 1849e42d98ebSAlexandre Bounine * specified target RapidIO device. 18504aff1ce7SAlexandre Bounine * @rdev: RIO device associated with DMA transfer 1851e42d98ebSAlexandre Bounine * 1852e42d98ebSAlexandre Bounine * Returns pointer to allocated DMA channel or NULL if failed. 1853e42d98ebSAlexandre Bounine */ 1854e42d98ebSAlexandre Bounine struct dma_chan *rio_request_dma(struct rio_dev *rdev) 1855e42d98ebSAlexandre Bounine { 18564aff1ce7SAlexandre Bounine return rio_request_mport_dma(rdev->net->hport); 1857e42d98ebSAlexandre Bounine } 1858e42d98ebSAlexandre Bounine EXPORT_SYMBOL_GPL(rio_request_dma); 1859e42d98ebSAlexandre Bounine 1860e42d98ebSAlexandre Bounine /** 1861e42d98ebSAlexandre Bounine * rio_release_dma - release specified DMA channel 1862e42d98ebSAlexandre Bounine * @dchan: DMA channel to release 1863e42d98ebSAlexandre Bounine */ 1864e42d98ebSAlexandre Bounine void rio_release_dma(struct dma_chan *dchan) 1865e42d98ebSAlexandre Bounine { 1866e42d98ebSAlexandre Bounine dma_release_channel(dchan); 1867e42d98ebSAlexandre Bounine } 1868e42d98ebSAlexandre Bounine EXPORT_SYMBOL_GPL(rio_release_dma); 1869e42d98ebSAlexandre Bounine 1870e42d98ebSAlexandre Bounine /** 18714aff1ce7SAlexandre Bounine * rio_dma_prep_xfer - RapidIO specific wrapper 18724aff1ce7SAlexandre Bounine * for device_prep_slave_sg callback defined by DMAENGINE. 18734aff1ce7SAlexandre Bounine * @dchan: DMA channel to configure 18744aff1ce7SAlexandre Bounine * @destid: target RapidIO device destination ID 18754aff1ce7SAlexandre Bounine * @data: RIO specific data descriptor 18764aff1ce7SAlexandre Bounine * @direction: DMA data transfer direction (TO or FROM the device) 18774aff1ce7SAlexandre Bounine * @flags: dmaengine defined flags 18784aff1ce7SAlexandre Bounine * 18794aff1ce7SAlexandre Bounine * Initializes RapidIO capable DMA channel for the specified data transfer. 18804aff1ce7SAlexandre Bounine * Uses DMA channel private extension to pass information related to remote 18814aff1ce7SAlexandre Bounine * target RIO device. 1882f8e3a68cSAlexandre Bounine * 1883f8e3a68cSAlexandre Bounine * Returns: pointer to DMA transaction descriptor if successful, 1884f8e3a68cSAlexandre Bounine * error-valued pointer or NULL if failed. 18854aff1ce7SAlexandre Bounine */ 18864aff1ce7SAlexandre Bounine struct dma_async_tx_descriptor *rio_dma_prep_xfer(struct dma_chan *dchan, 18874aff1ce7SAlexandre Bounine u16 destid, struct rio_dma_data *data, 18884aff1ce7SAlexandre Bounine enum dma_transfer_direction direction, unsigned long flags) 18894aff1ce7SAlexandre Bounine { 18904aff1ce7SAlexandre Bounine struct rio_dma_ext rio_ext; 18914aff1ce7SAlexandre Bounine 189293dd49afSMarkus Elfring if (!dchan->device->device_prep_slave_sg) { 18934aff1ce7SAlexandre Bounine pr_err("%s: prep_rio_sg == NULL\n", __func__); 18944aff1ce7SAlexandre Bounine return NULL; 18954aff1ce7SAlexandre Bounine } 18964aff1ce7SAlexandre Bounine 18974aff1ce7SAlexandre Bounine rio_ext.destid = destid; 18984aff1ce7SAlexandre Bounine rio_ext.rio_addr_u = data->rio_addr_u; 18994aff1ce7SAlexandre Bounine rio_ext.rio_addr = data->rio_addr; 19004aff1ce7SAlexandre Bounine rio_ext.wr_type = data->wr_type; 19014aff1ce7SAlexandre Bounine 19024aff1ce7SAlexandre Bounine return dmaengine_prep_rio_sg(dchan, data->sg, data->sg_len, 19034aff1ce7SAlexandre Bounine direction, flags, &rio_ext); 19044aff1ce7SAlexandre Bounine } 19054aff1ce7SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_dma_prep_xfer); 19064aff1ce7SAlexandre Bounine 19074aff1ce7SAlexandre Bounine /** 1908e42d98ebSAlexandre Bounine * rio_dma_prep_slave_sg - RapidIO specific wrapper 1909e42d98ebSAlexandre Bounine * for device_prep_slave_sg callback defined by DMAENGINE. 1910e42d98ebSAlexandre Bounine * @rdev: RIO device control structure 1911e42d98ebSAlexandre Bounine * @dchan: DMA channel to configure 1912e42d98ebSAlexandre Bounine * @data: RIO specific data descriptor 1913e42d98ebSAlexandre Bounine * @direction: DMA data transfer direction (TO or FROM the device) 1914e42d98ebSAlexandre Bounine * @flags: dmaengine defined flags 1915e42d98ebSAlexandre Bounine * 1916e42d98ebSAlexandre Bounine * Initializes RapidIO capable DMA channel for the specified data transfer. 1917e42d98ebSAlexandre Bounine * Uses DMA channel private extension to pass information related to remote 1918e42d98ebSAlexandre Bounine * target RIO device. 1919f8e3a68cSAlexandre Bounine * 1920f8e3a68cSAlexandre Bounine * Returns: pointer to DMA transaction descriptor if successful, 1921f8e3a68cSAlexandre Bounine * error-valued pointer or NULL if failed. 1922e42d98ebSAlexandre Bounine */ 1923e42d98ebSAlexandre Bounine struct dma_async_tx_descriptor *rio_dma_prep_slave_sg(struct rio_dev *rdev, 1924e42d98ebSAlexandre Bounine struct dma_chan *dchan, struct rio_dma_data *data, 1925e42d98ebSAlexandre Bounine enum dma_transfer_direction direction, unsigned long flags) 1926e42d98ebSAlexandre Bounine { 19274aff1ce7SAlexandre Bounine return rio_dma_prep_xfer(dchan, rdev->destid, data, direction, flags); 1928e42d98ebSAlexandre Bounine } 1929e42d98ebSAlexandre Bounine EXPORT_SYMBOL_GPL(rio_dma_prep_slave_sg); 1930e42d98ebSAlexandre Bounine 1931e42d98ebSAlexandre Bounine #endif /* CONFIG_RAPIDIO_DMA_ENGINE */ 1932e42d98ebSAlexandre Bounine 1933a11650e1SAlexandre Bounine /** 1934bc8fcfeaSAlexandre Bounine * rio_find_mport - find RIO mport by its ID 1935bc8fcfeaSAlexandre Bounine * @mport_id: number (ID) of mport device 1936bc8fcfeaSAlexandre Bounine * 1937bc8fcfeaSAlexandre Bounine * Given a RIO mport number, the desired mport is located 1938bc8fcfeaSAlexandre Bounine * in the global list of mports. If the mport is found, a pointer to its 1939bc8fcfeaSAlexandre Bounine * data structure is returned. If no mport is found, %NULL is returned. 1940bc8fcfeaSAlexandre Bounine */ 1941bc8fcfeaSAlexandre Bounine struct rio_mport *rio_find_mport(int mport_id) 1942bc8fcfeaSAlexandre Bounine { 1943bc8fcfeaSAlexandre Bounine struct rio_mport *port; 1944bc8fcfeaSAlexandre Bounine 1945bc8fcfeaSAlexandre Bounine mutex_lock(&rio_mport_list_lock); 1946bc8fcfeaSAlexandre Bounine list_for_each_entry(port, &rio_mports, node) { 1947bc8fcfeaSAlexandre Bounine if (port->id == mport_id) 1948bc8fcfeaSAlexandre Bounine goto found; 1949bc8fcfeaSAlexandre Bounine } 1950bc8fcfeaSAlexandre Bounine port = NULL; 1951bc8fcfeaSAlexandre Bounine found: 1952bc8fcfeaSAlexandre Bounine mutex_unlock(&rio_mport_list_lock); 1953bc8fcfeaSAlexandre Bounine 1954bc8fcfeaSAlexandre Bounine return port; 1955bc8fcfeaSAlexandre Bounine } 1956bc8fcfeaSAlexandre Bounine 1957bc8fcfeaSAlexandre Bounine /** 1958a11650e1SAlexandre Bounine * rio_register_scan - enumeration/discovery method registration interface 1959a11650e1SAlexandre Bounine * @mport_id: mport device ID for which fabric scan routine has to be set 1960a11650e1SAlexandre Bounine * (RIO_MPORT_ANY = set for all available mports) 19619edbc30bSAlexandre Bounine * @scan_ops: enumeration/discovery operations structure 1962a11650e1SAlexandre Bounine * 19639edbc30bSAlexandre Bounine * Registers enumeration/discovery operations with RapidIO subsystem and 19649edbc30bSAlexandre Bounine * attaches it to the specified mport device (or all available mports 19659edbc30bSAlexandre Bounine * if RIO_MPORT_ANY is specified). 19669edbc30bSAlexandre Bounine * 1967a11650e1SAlexandre Bounine * Returns error if the mport already has an enumerator attached to it. 19689edbc30bSAlexandre Bounine * In case of RIO_MPORT_ANY skips mports with valid scan routines (no error). 1969a11650e1SAlexandre Bounine */ 1970a11650e1SAlexandre Bounine int rio_register_scan(int mport_id, struct rio_scan *scan_ops) 1971a11650e1SAlexandre Bounine { 1972a11650e1SAlexandre Bounine struct rio_mport *port; 19739edbc30bSAlexandre Bounine struct rio_scan_node *scan; 19749edbc30bSAlexandre Bounine int rc = 0; 19759edbc30bSAlexandre Bounine 19769edbc30bSAlexandre Bounine pr_debug("RIO: %s for mport_id=%d\n", __func__, mport_id); 19779edbc30bSAlexandre Bounine 19789edbc30bSAlexandre Bounine if ((mport_id != RIO_MPORT_ANY && mport_id >= RIO_MAX_MPORTS) || 19799edbc30bSAlexandre Bounine !scan_ops) 19809edbc30bSAlexandre Bounine return -EINVAL; 1981a11650e1SAlexandre Bounine 1982a11650e1SAlexandre Bounine mutex_lock(&rio_mport_list_lock); 19839edbc30bSAlexandre Bounine 19849edbc30bSAlexandre Bounine /* 19859edbc30bSAlexandre Bounine * Check if there is another enumerator already registered for 19869edbc30bSAlexandre Bounine * the same mport ID (including RIO_MPORT_ANY). Multiple enumerators 19879edbc30bSAlexandre Bounine * for the same mport ID are not supported. 19889edbc30bSAlexandre Bounine */ 19899edbc30bSAlexandre Bounine list_for_each_entry(scan, &rio_scans, node) { 19909edbc30bSAlexandre Bounine if (scan->mport_id == mport_id) { 19919edbc30bSAlexandre Bounine rc = -EBUSY; 19929edbc30bSAlexandre Bounine goto err_out; 19939edbc30bSAlexandre Bounine } 19949edbc30bSAlexandre Bounine } 19959edbc30bSAlexandre Bounine 19969edbc30bSAlexandre Bounine /* 19979edbc30bSAlexandre Bounine * Allocate and initialize new scan registration node. 19989edbc30bSAlexandre Bounine */ 19999edbc30bSAlexandre Bounine scan = kzalloc(sizeof(*scan), GFP_KERNEL); 20009edbc30bSAlexandre Bounine if (!scan) { 20019edbc30bSAlexandre Bounine rc = -ENOMEM; 20029edbc30bSAlexandre Bounine goto err_out; 20039edbc30bSAlexandre Bounine } 20049edbc30bSAlexandre Bounine 20059edbc30bSAlexandre Bounine scan->mport_id = mport_id; 20069edbc30bSAlexandre Bounine scan->ops = scan_ops; 20079edbc30bSAlexandre Bounine 20089edbc30bSAlexandre Bounine /* 20099edbc30bSAlexandre Bounine * Traverse the list of registered mports to attach this new scan. 20109edbc30bSAlexandre Bounine * 20119edbc30bSAlexandre Bounine * The new scan with matching mport ID overrides any previously attached 20129edbc30bSAlexandre Bounine * scan assuming that old scan (if any) is the default one (based on the 20139edbc30bSAlexandre Bounine * enumerator registration check above). 20149edbc30bSAlexandre Bounine * If the new scan is the global one, it will be attached only to mports 20159edbc30bSAlexandre Bounine * that do not have their own individual operations already attached. 20169edbc30bSAlexandre Bounine */ 2017a11650e1SAlexandre Bounine list_for_each_entry(port, &rio_mports, node) { 20189edbc30bSAlexandre Bounine if (port->id == mport_id) { 2019a11650e1SAlexandre Bounine port->nscan = scan_ops; 2020a11650e1SAlexandre Bounine break; 20219edbc30bSAlexandre Bounine } else if (mport_id == RIO_MPORT_ANY && !port->nscan) 20229edbc30bSAlexandre Bounine port->nscan = scan_ops; 2023a11650e1SAlexandre Bounine } 20249edbc30bSAlexandre Bounine 20259edbc30bSAlexandre Bounine list_add_tail(&scan->node, &rio_scans); 20269edbc30bSAlexandre Bounine 20279edbc30bSAlexandre Bounine err_out: 2028a11650e1SAlexandre Bounine mutex_unlock(&rio_mport_list_lock); 2029a11650e1SAlexandre Bounine 2030a11650e1SAlexandre Bounine return rc; 2031a11650e1SAlexandre Bounine } 2032a11650e1SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_register_scan); 2033a11650e1SAlexandre Bounine 2034a11650e1SAlexandre Bounine /** 2035a11650e1SAlexandre Bounine * rio_unregister_scan - removes enumeration/discovery method from mport 2036a11650e1SAlexandre Bounine * @mport_id: mport device ID for which fabric scan routine has to be 20379edbc30bSAlexandre Bounine * unregistered (RIO_MPORT_ANY = apply to all mports that use 20389edbc30bSAlexandre Bounine * the specified scan_ops) 20399edbc30bSAlexandre Bounine * @scan_ops: enumeration/discovery operations structure 2040a11650e1SAlexandre Bounine * 2041a11650e1SAlexandre Bounine * Removes enumeration or discovery method assigned to the specified mport 20429edbc30bSAlexandre Bounine * device. If RIO_MPORT_ANY is specified, removes the specified operations from 20439edbc30bSAlexandre Bounine * all mports that have them attached. 2044a11650e1SAlexandre Bounine */ 20459edbc30bSAlexandre Bounine int rio_unregister_scan(int mport_id, struct rio_scan *scan_ops) 2046a11650e1SAlexandre Bounine { 2047a11650e1SAlexandre Bounine struct rio_mport *port; 20489edbc30bSAlexandre Bounine struct rio_scan_node *scan; 20499edbc30bSAlexandre Bounine 20509edbc30bSAlexandre Bounine pr_debug("RIO: %s for mport_id=%d\n", __func__, mport_id); 20519edbc30bSAlexandre Bounine 20529edbc30bSAlexandre Bounine if (mport_id != RIO_MPORT_ANY && mport_id >= RIO_MAX_MPORTS) 20539edbc30bSAlexandre Bounine return -EINVAL; 2054a11650e1SAlexandre Bounine 2055a11650e1SAlexandre Bounine mutex_lock(&rio_mport_list_lock); 20569edbc30bSAlexandre Bounine 20579edbc30bSAlexandre Bounine list_for_each_entry(port, &rio_mports, node) 20589edbc30bSAlexandre Bounine if (port->id == mport_id || 20599edbc30bSAlexandre Bounine (mport_id == RIO_MPORT_ANY && port->nscan == scan_ops)) 2060a11650e1SAlexandre Bounine port->nscan = NULL; 20619edbc30bSAlexandre Bounine 2062f93f3c4eSDan Carpenter list_for_each_entry(scan, &rio_scans, node) { 20639edbc30bSAlexandre Bounine if (scan->mport_id == mport_id) { 20649edbc30bSAlexandre Bounine list_del(&scan->node); 20659edbc30bSAlexandre Bounine kfree(scan); 2066f93f3c4eSDan Carpenter break; 2067f93f3c4eSDan Carpenter } 2068a11650e1SAlexandre Bounine } 20699edbc30bSAlexandre Bounine 2070a11650e1SAlexandre Bounine mutex_unlock(&rio_mport_list_lock); 2071a11650e1SAlexandre Bounine 2072a11650e1SAlexandre Bounine return 0; 2073a11650e1SAlexandre Bounine } 2074a11650e1SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_unregister_scan); 2075a11650e1SAlexandre Bounine 20769edbc30bSAlexandre Bounine /** 20779edbc30bSAlexandre Bounine * rio_mport_scan - execute enumeration/discovery on the specified mport 20789edbc30bSAlexandre Bounine * @mport_id: number (ID) of mport device 20799edbc30bSAlexandre Bounine */ 20809edbc30bSAlexandre Bounine int rio_mport_scan(int mport_id) 20819edbc30bSAlexandre Bounine { 20829edbc30bSAlexandre Bounine struct rio_mport *port = NULL; 20839edbc30bSAlexandre Bounine int rc; 20849edbc30bSAlexandre Bounine 20859edbc30bSAlexandre Bounine mutex_lock(&rio_mport_list_lock); 20869edbc30bSAlexandre Bounine list_for_each_entry(port, &rio_mports, node) { 20879edbc30bSAlexandre Bounine if (port->id == mport_id) 20889edbc30bSAlexandre Bounine goto found; 20899edbc30bSAlexandre Bounine } 20909edbc30bSAlexandre Bounine mutex_unlock(&rio_mport_list_lock); 20919edbc30bSAlexandre Bounine return -ENODEV; 20929edbc30bSAlexandre Bounine found: 20939edbc30bSAlexandre Bounine if (!port->nscan) { 20949edbc30bSAlexandre Bounine mutex_unlock(&rio_mport_list_lock); 20959edbc30bSAlexandre Bounine return -EINVAL; 20969edbc30bSAlexandre Bounine } 20979edbc30bSAlexandre Bounine 20989edbc30bSAlexandre Bounine if (!try_module_get(port->nscan->owner)) { 20999edbc30bSAlexandre Bounine mutex_unlock(&rio_mport_list_lock); 21009edbc30bSAlexandre Bounine return -ENODEV; 21019edbc30bSAlexandre Bounine } 21029edbc30bSAlexandre Bounine 21039edbc30bSAlexandre Bounine mutex_unlock(&rio_mport_list_lock); 21049edbc30bSAlexandre Bounine 21059edbc30bSAlexandre Bounine if (port->host_deviceid >= 0) 21069edbc30bSAlexandre Bounine rc = port->nscan->enumerate(port, 0); 21079edbc30bSAlexandre Bounine else 21089edbc30bSAlexandre Bounine rc = port->nscan->discover(port, RIO_SCAN_ENUM_NO_WAIT); 21099edbc30bSAlexandre Bounine 21109edbc30bSAlexandre Bounine module_put(port->nscan->owner); 21119edbc30bSAlexandre Bounine return rc; 21129edbc30bSAlexandre Bounine } 21139edbc30bSAlexandre Bounine 2114394b701cSMatt Porter static void rio_fixup_device(struct rio_dev *dev) 2115394b701cSMatt Porter { 2116394b701cSMatt Porter } 2117394b701cSMatt Porter 2118305c891eSBill Pemberton static int rio_init(void) 2119394b701cSMatt Porter { 2120394b701cSMatt Porter struct rio_dev *dev = NULL; 2121394b701cSMatt Porter 2122394b701cSMatt Porter while ((dev = rio_get_device(RIO_ANY_ID, RIO_ANY_ID, dev)) != NULL) { 2123394b701cSMatt Porter rio_fixup_device(dev); 2124394b701cSMatt Porter } 2125394b701cSMatt Porter return 0; 2126394b701cSMatt Porter } 2127394b701cSMatt Porter 2128005842efSAlexandre Bounine static struct workqueue_struct *rio_wq; 2129005842efSAlexandre Bounine 2130005842efSAlexandre Bounine struct rio_disc_work { 2131005842efSAlexandre Bounine struct work_struct work; 2132005842efSAlexandre Bounine struct rio_mport *mport; 2133005842efSAlexandre Bounine }; 2134005842efSAlexandre Bounine 2135305c891eSBill Pemberton static void disc_work_handler(struct work_struct *_work) 2136005842efSAlexandre Bounine { 2137005842efSAlexandre Bounine struct rio_disc_work *work; 2138005842efSAlexandre Bounine 2139005842efSAlexandre Bounine work = container_of(_work, struct rio_disc_work, work); 2140005842efSAlexandre Bounine pr_debug("RIO: discovery work for mport %d %s\n", 2141005842efSAlexandre Bounine work->mport->id, work->mport->name); 21429edbc30bSAlexandre Bounine if (try_module_get(work->mport->nscan->owner)) { 2143bc8fcfeaSAlexandre Bounine work->mport->nscan->discover(work->mport, 0); 21449edbc30bSAlexandre Bounine module_put(work->mport->nscan->owner); 21459edbc30bSAlexandre Bounine } 2146005842efSAlexandre Bounine } 2147005842efSAlexandre Bounine 2148305c891eSBill Pemberton int rio_init_mports(void) 2149394b701cSMatt Porter { 2150394b701cSMatt Porter struct rio_mport *port; 2151005842efSAlexandre Bounine struct rio_disc_work *work; 21522574740dSAlexandre Bounine int n = 0; 2153394b701cSMatt Porter 21542574740dSAlexandre Bounine if (!next_portid) 21552574740dSAlexandre Bounine return -ENODEV; 21562574740dSAlexandre Bounine 21572574740dSAlexandre Bounine /* 21582574740dSAlexandre Bounine * First, run enumerations and check if we need to perform discovery 21592574740dSAlexandre Bounine * on any of the registered mports. 21602574740dSAlexandre Bounine */ 2161a11650e1SAlexandre Bounine mutex_lock(&rio_mport_list_lock); 2162394b701cSMatt Porter list_for_each_entry(port, &rio_mports, node) { 2163a11650e1SAlexandre Bounine if (port->host_deviceid >= 0) { 21649edbc30bSAlexandre Bounine if (port->nscan && try_module_get(port->nscan->owner)) { 2165bc8fcfeaSAlexandre Bounine port->nscan->enumerate(port, 0); 21669edbc30bSAlexandre Bounine module_put(port->nscan->owner); 21679edbc30bSAlexandre Bounine } 2168a11650e1SAlexandre Bounine } else 21692574740dSAlexandre Bounine n++; 21702574740dSAlexandre Bounine } 2171a11650e1SAlexandre Bounine mutex_unlock(&rio_mport_list_lock); 21722574740dSAlexandre Bounine 21732574740dSAlexandre Bounine if (!n) 21742574740dSAlexandre Bounine goto no_disc; 21752574740dSAlexandre Bounine 21762574740dSAlexandre Bounine /* 21772574740dSAlexandre Bounine * If we have mports that require discovery schedule a discovery work 21782574740dSAlexandre Bounine * for each of them. If the code below fails to allocate needed 21792574740dSAlexandre Bounine * resources, exit without error to keep results of enumeration 21802574740dSAlexandre Bounine * process (if any). 21819edbc30bSAlexandre Bounine * TODO: Implement restart of discovery process for all or 21822574740dSAlexandre Bounine * individual discovering mports. 21832574740dSAlexandre Bounine */ 2184005842efSAlexandre Bounine rio_wq = alloc_workqueue("riodisc", 0, 0); 2185005842efSAlexandre Bounine if (!rio_wq) { 2186005842efSAlexandre Bounine pr_err("RIO: unable allocate rio_wq\n"); 21872574740dSAlexandre Bounine goto no_disc; 2188005842efSAlexandre Bounine } 2189005842efSAlexandre Bounine 21902574740dSAlexandre Bounine work = kcalloc(n, sizeof *work, GFP_KERNEL); 2191005842efSAlexandre Bounine if (!work) { 2192005842efSAlexandre Bounine destroy_workqueue(rio_wq); 21932574740dSAlexandre Bounine goto no_disc; 2194394b701cSMatt Porter } 2195394b701cSMatt Porter 21962574740dSAlexandre Bounine n = 0; 2197a11650e1SAlexandre Bounine mutex_lock(&rio_mport_list_lock); 21982574740dSAlexandre Bounine list_for_each_entry(port, &rio_mports, node) { 2199a11650e1SAlexandre Bounine if (port->host_deviceid < 0 && port->nscan) { 22002574740dSAlexandre Bounine work[n].mport = port; 22012574740dSAlexandre Bounine INIT_WORK(&work[n].work, disc_work_handler); 22022574740dSAlexandre Bounine queue_work(rio_wq, &work[n].work); 22032574740dSAlexandre Bounine n++; 22042574740dSAlexandre Bounine } 22052574740dSAlexandre Bounine } 22062574740dSAlexandre Bounine 22072574740dSAlexandre Bounine flush_workqueue(rio_wq); 22089edbc30bSAlexandre Bounine mutex_unlock(&rio_mport_list_lock); 22092574740dSAlexandre Bounine pr_debug("RIO: destroy discovery workqueue\n"); 22102574740dSAlexandre Bounine destroy_workqueue(rio_wq); 22112574740dSAlexandre Bounine kfree(work); 22122574740dSAlexandre Bounine 22132574740dSAlexandre Bounine no_disc: 22142f809985SAlexandre Bounine rio_init(); 22152f809985SAlexandre Bounine 2216c1256ebeSAlexandre Bounine return 0; 2217394b701cSMatt Porter } 2218394b701cSMatt Porter 2219569fccb6SAlexandre Bounine static int rio_get_hdid(int index) 2220569fccb6SAlexandre Bounine { 2221fdf90abcSAlexandre Bounine if (ids_num == 0 || ids_num <= index || index >= RIO_MAX_MPORTS) 2222569fccb6SAlexandre Bounine return -1; 2223569fccb6SAlexandre Bounine 2224fdf90abcSAlexandre Bounine return hdid[index]; 2225569fccb6SAlexandre Bounine } 2226569fccb6SAlexandre Bounine 2227b77a2030SAlexandre Bounine int rio_mport_initialize(struct rio_mport *mport) 2228b77a2030SAlexandre Bounine { 2229b77a2030SAlexandre Bounine if (next_portid >= RIO_MAX_MPORTS) { 2230b77a2030SAlexandre Bounine pr_err("RIO: reached specified max number of mports\n"); 2231b77a2030SAlexandre Bounine return -ENODEV; 2232b77a2030SAlexandre Bounine } 2233b77a2030SAlexandre Bounine 2234b77a2030SAlexandre Bounine atomic_set(&mport->state, RIO_DEVICE_INITIALIZING); 2235b77a2030SAlexandre Bounine mport->id = next_portid++; 2236b77a2030SAlexandre Bounine mport->host_deviceid = rio_get_hdid(mport->id); 2237b77a2030SAlexandre Bounine mport->nscan = NULL; 2238a7b4c636SAlexandre Bounine mutex_init(&mport->lock); 2239b6cb95e8SAlexandre Bounine mport->pwe_refcnt = 0; 22409a0b0627SAlexandre Bounine INIT_LIST_HEAD(&mport->pwrites); 2241b77a2030SAlexandre Bounine 2242b77a2030SAlexandre Bounine return 0; 2243b77a2030SAlexandre Bounine } 2244b77a2030SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_mport_initialize); 2245b77a2030SAlexandre Bounine 224659f99965SAlexandre Bounine int rio_register_mport(struct rio_mport *port) 2247394b701cSMatt Porter { 22489edbc30bSAlexandre Bounine struct rio_scan_node *scan = NULL; 22492aaf308bSAlexandre Bounine int res = 0; 22509edbc30bSAlexandre Bounine 2251a11650e1SAlexandre Bounine mutex_lock(&rio_mport_list_lock); 22529edbc30bSAlexandre Bounine 22539edbc30bSAlexandre Bounine /* 22549edbc30bSAlexandre Bounine * Check if there are any registered enumeration/discovery operations 22559edbc30bSAlexandre Bounine * that have to be attached to the added mport. 22569edbc30bSAlexandre Bounine */ 22579edbc30bSAlexandre Bounine list_for_each_entry(scan, &rio_scans, node) { 22589edbc30bSAlexandre Bounine if (port->id == scan->mport_id || 22599edbc30bSAlexandre Bounine scan->mport_id == RIO_MPORT_ANY) { 22609edbc30bSAlexandre Bounine port->nscan = scan->ops; 22619edbc30bSAlexandre Bounine if (port->id == scan->mport_id) 22629edbc30bSAlexandre Bounine break; 22639edbc30bSAlexandre Bounine } 22649edbc30bSAlexandre Bounine } 2265b77a2030SAlexandre Bounine 2266b77a2030SAlexandre Bounine list_add_tail(&port->node, &rio_mports); 2267a11650e1SAlexandre Bounine mutex_unlock(&rio_mport_list_lock); 22689edbc30bSAlexandre Bounine 2269b77a2030SAlexandre Bounine dev_set_name(&port->dev, "rapidio%d", port->id); 2270b77a2030SAlexandre Bounine port->dev.class = &rio_mport_class; 2271b77a2030SAlexandre Bounine atomic_set(&port->state, RIO_DEVICE_RUNNING); 2272b77a2030SAlexandre Bounine 2273b77a2030SAlexandre Bounine res = device_register(&port->dev); 2274b77a2030SAlexandre Bounine if (res) 2275b77a2030SAlexandre Bounine dev_err(&port->dev, "RIO: mport%d registration failed ERR=%d\n", 2276b77a2030SAlexandre Bounine port->id, res); 2277b77a2030SAlexandre Bounine else 2278b77a2030SAlexandre Bounine dev_dbg(&port->dev, "RIO: registered mport%d\n", port->id); 2279b77a2030SAlexandre Bounine 2280b77a2030SAlexandre Bounine return res; 2281394b701cSMatt Porter } 228294d9bd45SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_register_mport); 2283394b701cSMatt Porter 2284b77a2030SAlexandre Bounine static int rio_mport_cleanup_callback(struct device *dev, void *data) 2285b77a2030SAlexandre Bounine { 2286b77a2030SAlexandre Bounine struct rio_dev *rdev = to_rio_dev(dev); 2287b77a2030SAlexandre Bounine 2288b77a2030SAlexandre Bounine if (dev->bus == &rio_bus_type) 2289b77a2030SAlexandre Bounine rio_del_device(rdev, RIO_DEVICE_SHUTDOWN); 2290b77a2030SAlexandre Bounine return 0; 2291b77a2030SAlexandre Bounine } 2292b77a2030SAlexandre Bounine 2293b77a2030SAlexandre Bounine static int rio_net_remove_children(struct rio_net *net) 2294b77a2030SAlexandre Bounine { 2295b77a2030SAlexandre Bounine /* 2296b77a2030SAlexandre Bounine * Unregister all RapidIO devices residing on this net (this will 2297b77a2030SAlexandre Bounine * invoke notification of registered subsystem interfaces as well). 2298b77a2030SAlexandre Bounine */ 2299b77a2030SAlexandre Bounine device_for_each_child(&net->dev, NULL, rio_mport_cleanup_callback); 2300b77a2030SAlexandre Bounine return 0; 2301b77a2030SAlexandre Bounine } 2302b77a2030SAlexandre Bounine 2303b77a2030SAlexandre Bounine int rio_unregister_mport(struct rio_mport *port) 2304b77a2030SAlexandre Bounine { 2305b77a2030SAlexandre Bounine pr_debug("RIO: %s %s id=%d\n", __func__, port->name, port->id); 2306b77a2030SAlexandre Bounine 2307b77a2030SAlexandre Bounine /* Transition mport to the SHUTDOWN state */ 2308b77a2030SAlexandre Bounine if (atomic_cmpxchg(&port->state, 2309b77a2030SAlexandre Bounine RIO_DEVICE_RUNNING, 2310b77a2030SAlexandre Bounine RIO_DEVICE_SHUTDOWN) != RIO_DEVICE_RUNNING) { 2311b77a2030SAlexandre Bounine pr_err("RIO: %s unexpected state transition for mport %s\n", 2312b77a2030SAlexandre Bounine __func__, port->name); 2313b77a2030SAlexandre Bounine } 2314b77a2030SAlexandre Bounine 2315b77a2030SAlexandre Bounine if (port->net && port->net->hport == port) { 2316b77a2030SAlexandre Bounine rio_net_remove_children(port->net); 2317b77a2030SAlexandre Bounine rio_free_net(port->net); 2318b77a2030SAlexandre Bounine } 2319b77a2030SAlexandre Bounine 2320b77a2030SAlexandre Bounine /* 2321b77a2030SAlexandre Bounine * Unregister all RapidIO devices attached to this mport (this will 2322b77a2030SAlexandre Bounine * invoke notification of registered subsystem interfaces as well). 2323b77a2030SAlexandre Bounine */ 2324b77a2030SAlexandre Bounine mutex_lock(&rio_mport_list_lock); 2325b77a2030SAlexandre Bounine list_del(&port->node); 2326b77a2030SAlexandre Bounine mutex_unlock(&rio_mport_list_lock); 2327b77a2030SAlexandre Bounine device_unregister(&port->dev); 2328b77a2030SAlexandre Bounine 2329b77a2030SAlexandre Bounine return 0; 2330b77a2030SAlexandre Bounine } 2331b77a2030SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_unregister_mport); 2332b77a2030SAlexandre Bounine 2333394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_local_get_device_id); 2334394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_get_device); 2335394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_get_asm); 2336394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_request_inb_dbell); 2337394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_release_inb_dbell); 2338394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_request_outb_dbell); 2339394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_release_outb_dbell); 2340394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_request_inb_mbox); 2341394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_release_inb_mbox); 2342394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_request_outb_mbox); 2343394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_release_outb_mbox); 2344a11650e1SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_init_mports); 2345