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 33fdf90abcSAlexandre Bounine MODULE_DESCRIPTION("RapidIO Subsystem Core"); 34fdf90abcSAlexandre Bounine MODULE_AUTHOR("Matt Porter <mporter@kernel.crashing.org>"); 35fdf90abcSAlexandre Bounine MODULE_AUTHOR("Alexandre Bounine <alexandre.bounine@idt.com>"); 36fdf90abcSAlexandre Bounine MODULE_LICENSE("GPL"); 37fdf90abcSAlexandre Bounine 38fdf90abcSAlexandre Bounine static int hdid[RIO_MAX_MPORTS]; 39fdf90abcSAlexandre Bounine static int ids_num; 40fdf90abcSAlexandre Bounine module_param_array(hdid, int, &ids_num, 0); 41fdf90abcSAlexandre Bounine MODULE_PARM_DESC(hdid, 42fdf90abcSAlexandre Bounine "Destination ID assignment to local RapidIO controllers"); 43fdf90abcSAlexandre Bounine 44a11650e1SAlexandre Bounine static LIST_HEAD(rio_devices); 45a11650e1SAlexandre Bounine static DEFINE_SPINLOCK(rio_global_list_lock); 46a11650e1SAlexandre Bounine 47394b701cSMatt Porter static LIST_HEAD(rio_mports); 489edbc30bSAlexandre Bounine static LIST_HEAD(rio_scans); 49a11650e1SAlexandre Bounine static DEFINE_MUTEX(rio_mport_list_lock); 50569fccb6SAlexandre Bounine static unsigned char next_portid; 51da1589f0SAlexandre Bounine static DEFINE_SPINLOCK(rio_mmap_lock); 52394b701cSMatt Porter 53394b701cSMatt Porter /** 54394b701cSMatt Porter * rio_local_get_device_id - Get the base/extended device id for a port 55394b701cSMatt Porter * @port: RIO master port from which to get the deviceid 56394b701cSMatt Porter * 57394b701cSMatt Porter * Reads the base/extended device id from the local device 58394b701cSMatt Porter * implementing the master port. Returns the 8/16-bit device 59394b701cSMatt Porter * id. 60394b701cSMatt Porter */ 61394b701cSMatt Porter u16 rio_local_get_device_id(struct rio_mport *port) 62394b701cSMatt Porter { 63394b701cSMatt Porter u32 result; 64394b701cSMatt Porter 65394b701cSMatt Porter rio_local_read_config_32(port, RIO_DID_CSR, &result); 66394b701cSMatt Porter 67e0423236SZhang Wei return (RIO_GET_DID(port->sys_size, result)); 68394b701cSMatt Porter } 69394b701cSMatt Porter 70394b701cSMatt Porter /** 718b189fdbSAlexandre Bounine * rio_query_mport - Query mport device attributes 728b189fdbSAlexandre Bounine * @port: mport device to query 738b189fdbSAlexandre Bounine * @mport_attr: mport attributes data structure 748b189fdbSAlexandre Bounine * 758b189fdbSAlexandre Bounine * Returns attributes of specified mport through the 768b189fdbSAlexandre Bounine * pointer to attributes data structure. 778b189fdbSAlexandre Bounine */ 788b189fdbSAlexandre Bounine int rio_query_mport(struct rio_mport *port, 798b189fdbSAlexandre Bounine struct rio_mport_attr *mport_attr) 808b189fdbSAlexandre Bounine { 818b189fdbSAlexandre Bounine if (!port->ops->query_mport) 828b189fdbSAlexandre Bounine return -ENODATA; 838b189fdbSAlexandre Bounine return port->ops->query_mport(port, mport_attr); 848b189fdbSAlexandre Bounine } 858b189fdbSAlexandre Bounine EXPORT_SYMBOL(rio_query_mport); 868b189fdbSAlexandre Bounine 878b189fdbSAlexandre Bounine /** 88a11650e1SAlexandre Bounine * rio_add_device- Adds a RIO device to the device model 89a11650e1SAlexandre Bounine * @rdev: RIO device 90a11650e1SAlexandre Bounine * 91a11650e1SAlexandre Bounine * Adds the RIO device to the global device list and adds the RIO 92a11650e1SAlexandre Bounine * device to the RIO device list. Creates the generic sysfs nodes 93a11650e1SAlexandre Bounine * for an RIO device. 94a11650e1SAlexandre Bounine */ 95a11650e1SAlexandre Bounine int rio_add_device(struct rio_dev *rdev) 96a11650e1SAlexandre Bounine { 97a11650e1SAlexandre Bounine int err; 98a11650e1SAlexandre Bounine 99b74ec56eSAlexandre Bounine err = device_register(&rdev->dev); 100a11650e1SAlexandre Bounine if (err) 101a11650e1SAlexandre Bounine return err; 102a11650e1SAlexandre Bounine 103a11650e1SAlexandre Bounine spin_lock(&rio_global_list_lock); 104a11650e1SAlexandre Bounine list_add_tail(&rdev->global_list, &rio_devices); 105b74ec56eSAlexandre Bounine if (rdev->net) { 106b74ec56eSAlexandre Bounine list_add_tail(&rdev->net_list, &rdev->net->devices); 107b74ec56eSAlexandre Bounine if (rdev->pef & RIO_PEF_SWITCH) 108b74ec56eSAlexandre Bounine list_add_tail(&rdev->rswitch->node, 109b74ec56eSAlexandre Bounine &rdev->net->switches); 110b74ec56eSAlexandre Bounine } 111a11650e1SAlexandre Bounine spin_unlock(&rio_global_list_lock); 112a11650e1SAlexandre Bounine 113a11650e1SAlexandre Bounine rio_create_sysfs_dev_files(rdev); 114a11650e1SAlexandre Bounine 115a11650e1SAlexandre Bounine return 0; 116a11650e1SAlexandre Bounine } 117a11650e1SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_add_device); 118a11650e1SAlexandre Bounine 119b74ec56eSAlexandre Bounine /* 120b74ec56eSAlexandre Bounine * rio_del_device - removes a RIO device from the device model 121b74ec56eSAlexandre Bounine * @rdev: RIO device 122b74ec56eSAlexandre Bounine * 123b74ec56eSAlexandre Bounine * Removes the RIO device to the kernel device list and subsystem's device list. 124b74ec56eSAlexandre Bounine * Clears sysfs entries for the removed device. 125b74ec56eSAlexandre Bounine */ 126b74ec56eSAlexandre Bounine void rio_del_device(struct rio_dev *rdev) 127b74ec56eSAlexandre Bounine { 128b74ec56eSAlexandre Bounine pr_debug("RIO: %s: removing %s\n", __func__, rio_name(rdev)); 129b74ec56eSAlexandre Bounine spin_lock(&rio_global_list_lock); 130b74ec56eSAlexandre Bounine list_del(&rdev->global_list); 131b74ec56eSAlexandre Bounine if (rdev->net) { 132b74ec56eSAlexandre Bounine list_del(&rdev->net_list); 133b74ec56eSAlexandre Bounine if (rdev->pef & RIO_PEF_SWITCH) { 134b74ec56eSAlexandre Bounine list_del(&rdev->rswitch->node); 135b74ec56eSAlexandre Bounine kfree(rdev->rswitch->route_table); 136b74ec56eSAlexandre Bounine } 137b74ec56eSAlexandre Bounine } 138b74ec56eSAlexandre Bounine spin_unlock(&rio_global_list_lock); 139b74ec56eSAlexandre Bounine rio_remove_sysfs_dev_files(rdev); 140b74ec56eSAlexandre Bounine device_unregister(&rdev->dev); 141b74ec56eSAlexandre Bounine } 142b74ec56eSAlexandre Bounine EXPORT_SYMBOL_GPL(rio_del_device); 143b74ec56eSAlexandre Bounine 144a11650e1SAlexandre Bounine /** 145394b701cSMatt Porter * rio_request_inb_mbox - request inbound mailbox service 146394b701cSMatt Porter * @mport: RIO master port from which to allocate the mailbox resource 1476978bbc0SMatt Porter * @dev_id: Device specific pointer to pass on event 148394b701cSMatt Porter * @mbox: Mailbox number to claim 149394b701cSMatt Porter * @entries: Number of entries in inbound mailbox queue 150394b701cSMatt Porter * @minb: Callback to execute when inbound message is received 151394b701cSMatt Porter * 152394b701cSMatt Porter * Requests ownership of an inbound mailbox resource and binds 153394b701cSMatt Porter * a callback function to the resource. Returns %0 on success. 154394b701cSMatt Porter */ 155394b701cSMatt Porter int rio_request_inb_mbox(struct rio_mport *mport, 1566978bbc0SMatt Porter void *dev_id, 157394b701cSMatt Porter int mbox, 158394b701cSMatt Porter int entries, 1596978bbc0SMatt Porter void (*minb) (struct rio_mport * mport, void *dev_id, int mbox, 160394b701cSMatt Porter int slot)) 161394b701cSMatt Porter { 162f8f06269SAlexandre Bounine int rc = -ENOSYS; 163f8f06269SAlexandre Bounine struct resource *res; 164394b701cSMatt Porter 165f8f06269SAlexandre Bounine if (mport->ops->open_inb_mbox == NULL) 166f8f06269SAlexandre Bounine goto out; 167f8f06269SAlexandre Bounine 1689a975beeSToshi Kani res = kzalloc(sizeof(struct resource), GFP_KERNEL); 169394b701cSMatt Porter 170394b701cSMatt Porter if (res) { 171394b701cSMatt Porter rio_init_mbox_res(res, mbox, mbox); 172394b701cSMatt Porter 173394b701cSMatt Porter /* Make sure this mailbox isn't in use */ 174394b701cSMatt Porter if ((rc = 175394b701cSMatt Porter request_resource(&mport->riores[RIO_INB_MBOX_RESOURCE], 176394b701cSMatt Porter res)) < 0) { 177394b701cSMatt Porter kfree(res); 178394b701cSMatt Porter goto out; 179394b701cSMatt Porter } 180394b701cSMatt Porter 181394b701cSMatt Porter mport->inb_msg[mbox].res = res; 182394b701cSMatt Porter 183394b701cSMatt Porter /* Hook the inbound message callback */ 184394b701cSMatt Porter mport->inb_msg[mbox].mcback = minb; 185394b701cSMatt Porter 186f8f06269SAlexandre Bounine rc = mport->ops->open_inb_mbox(mport, dev_id, mbox, entries); 187394b701cSMatt Porter } else 188394b701cSMatt Porter rc = -ENOMEM; 189394b701cSMatt Porter 190394b701cSMatt Porter out: 191394b701cSMatt Porter return rc; 192394b701cSMatt Porter } 193394b701cSMatt Porter 194394b701cSMatt Porter /** 195394b701cSMatt Porter * rio_release_inb_mbox - release inbound mailbox message service 196394b701cSMatt Porter * @mport: RIO master port from which to release the mailbox resource 197394b701cSMatt Porter * @mbox: Mailbox number to release 198394b701cSMatt Porter * 199394b701cSMatt Porter * Releases ownership of an inbound mailbox resource. Returns 0 200394b701cSMatt Porter * if the request has been satisfied. 201394b701cSMatt Porter */ 202394b701cSMatt Porter int rio_release_inb_mbox(struct rio_mport *mport, int mbox) 203394b701cSMatt Porter { 204f8f06269SAlexandre Bounine if (mport->ops->close_inb_mbox) { 205f8f06269SAlexandre Bounine mport->ops->close_inb_mbox(mport, mbox); 206394b701cSMatt Porter 207394b701cSMatt Porter /* Release the mailbox resource */ 208394b701cSMatt Porter return release_resource(mport->inb_msg[mbox].res); 209f8f06269SAlexandre Bounine } else 210f8f06269SAlexandre Bounine return -ENOSYS; 211394b701cSMatt Porter } 212394b701cSMatt Porter 213394b701cSMatt Porter /** 214394b701cSMatt Porter * rio_request_outb_mbox - request outbound mailbox service 215394b701cSMatt Porter * @mport: RIO master port from which to allocate the mailbox resource 2166978bbc0SMatt Porter * @dev_id: Device specific pointer to pass on event 217394b701cSMatt Porter * @mbox: Mailbox number to claim 218394b701cSMatt Porter * @entries: Number of entries in outbound mailbox queue 219394b701cSMatt Porter * @moutb: Callback to execute when outbound message is sent 220394b701cSMatt Porter * 221394b701cSMatt Porter * Requests ownership of an outbound mailbox resource and binds 222394b701cSMatt Porter * a callback function to the resource. Returns 0 on success. 223394b701cSMatt Porter */ 224394b701cSMatt Porter int rio_request_outb_mbox(struct rio_mport *mport, 2256978bbc0SMatt Porter void *dev_id, 226394b701cSMatt Porter int mbox, 227394b701cSMatt Porter int entries, 2286978bbc0SMatt Porter void (*moutb) (struct rio_mport * mport, void *dev_id, int mbox, int slot)) 229394b701cSMatt Porter { 230f8f06269SAlexandre Bounine int rc = -ENOSYS; 231f8f06269SAlexandre Bounine struct resource *res; 232394b701cSMatt Porter 233f8f06269SAlexandre Bounine if (mport->ops->open_outb_mbox == NULL) 234f8f06269SAlexandre Bounine goto out; 235f8f06269SAlexandre Bounine 2369a975beeSToshi Kani res = kzalloc(sizeof(struct resource), GFP_KERNEL); 237394b701cSMatt Porter 238394b701cSMatt Porter if (res) { 239394b701cSMatt Porter rio_init_mbox_res(res, mbox, mbox); 240394b701cSMatt Porter 241394b701cSMatt Porter /* Make sure this outbound mailbox isn't in use */ 242394b701cSMatt Porter if ((rc = 243394b701cSMatt Porter request_resource(&mport->riores[RIO_OUTB_MBOX_RESOURCE], 244394b701cSMatt Porter res)) < 0) { 245394b701cSMatt Porter kfree(res); 246394b701cSMatt Porter goto out; 247394b701cSMatt Porter } 248394b701cSMatt Porter 249394b701cSMatt Porter mport->outb_msg[mbox].res = res; 250394b701cSMatt Porter 251394b701cSMatt Porter /* Hook the inbound message callback */ 252394b701cSMatt Porter mport->outb_msg[mbox].mcback = moutb; 253394b701cSMatt Porter 254f8f06269SAlexandre Bounine rc = mport->ops->open_outb_mbox(mport, dev_id, mbox, entries); 255394b701cSMatt Porter } else 256394b701cSMatt Porter rc = -ENOMEM; 257394b701cSMatt Porter 258394b701cSMatt Porter out: 259394b701cSMatt Porter return rc; 260394b701cSMatt Porter } 261394b701cSMatt Porter 262394b701cSMatt Porter /** 263394b701cSMatt Porter * rio_release_outb_mbox - release outbound mailbox message service 264394b701cSMatt Porter * @mport: RIO master port from which to release the mailbox resource 265394b701cSMatt Porter * @mbox: Mailbox number to release 266394b701cSMatt Porter * 267394b701cSMatt Porter * Releases ownership of an inbound mailbox resource. Returns 0 268394b701cSMatt Porter * if the request has been satisfied. 269394b701cSMatt Porter */ 270394b701cSMatt Porter int rio_release_outb_mbox(struct rio_mport *mport, int mbox) 271394b701cSMatt Porter { 272f8f06269SAlexandre Bounine if (mport->ops->close_outb_mbox) { 273f8f06269SAlexandre Bounine mport->ops->close_outb_mbox(mport, mbox); 274394b701cSMatt Porter 275394b701cSMatt Porter /* Release the mailbox resource */ 276394b701cSMatt Porter return release_resource(mport->outb_msg[mbox].res); 277f8f06269SAlexandre Bounine } else 278f8f06269SAlexandre Bounine return -ENOSYS; 279394b701cSMatt Porter } 280394b701cSMatt Porter 281394b701cSMatt Porter /** 282394b701cSMatt Porter * rio_setup_inb_dbell - bind inbound doorbell callback 283394b701cSMatt Porter * @mport: RIO master port to bind the doorbell callback 2846978bbc0SMatt Porter * @dev_id: Device specific pointer to pass on event 285394b701cSMatt Porter * @res: Doorbell message resource 286394b701cSMatt Porter * @dinb: Callback to execute when doorbell is received 287394b701cSMatt Porter * 288394b701cSMatt Porter * Adds a doorbell resource/callback pair into a port's 289394b701cSMatt Porter * doorbell event list. Returns 0 if the request has been 290394b701cSMatt Porter * satisfied. 291394b701cSMatt Porter */ 292394b701cSMatt Porter static int 2936978bbc0SMatt Porter rio_setup_inb_dbell(struct rio_mport *mport, void *dev_id, struct resource *res, 2946978bbc0SMatt Porter void (*dinb) (struct rio_mport * mport, void *dev_id, u16 src, u16 dst, 295394b701cSMatt Porter u16 info)) 296394b701cSMatt Porter { 297394b701cSMatt Porter int rc = 0; 298394b701cSMatt Porter struct rio_dbell *dbell; 299394b701cSMatt Porter 300394b701cSMatt Porter if (!(dbell = kmalloc(sizeof(struct rio_dbell), GFP_KERNEL))) { 301394b701cSMatt Porter rc = -ENOMEM; 302394b701cSMatt Porter goto out; 303394b701cSMatt Porter } 304394b701cSMatt Porter 305394b701cSMatt Porter dbell->res = res; 306394b701cSMatt Porter dbell->dinb = dinb; 3076978bbc0SMatt Porter dbell->dev_id = dev_id; 308394b701cSMatt Porter 309394b701cSMatt Porter list_add_tail(&dbell->node, &mport->dbells); 310394b701cSMatt Porter 311394b701cSMatt Porter out: 312394b701cSMatt Porter return rc; 313394b701cSMatt Porter } 314394b701cSMatt Porter 315394b701cSMatt Porter /** 316394b701cSMatt Porter * rio_request_inb_dbell - request inbound doorbell message service 317394b701cSMatt Porter * @mport: RIO master port from which to allocate the doorbell resource 3186978bbc0SMatt Porter * @dev_id: Device specific pointer to pass on event 319394b701cSMatt Porter * @start: Doorbell info range start 320394b701cSMatt Porter * @end: Doorbell info range end 321394b701cSMatt Porter * @dinb: Callback to execute when doorbell is received 322394b701cSMatt Porter * 323394b701cSMatt Porter * Requests ownership of an inbound doorbell resource and binds 324394b701cSMatt Porter * a callback function to the resource. Returns 0 if the request 325394b701cSMatt Porter * has been satisfied. 326394b701cSMatt Porter */ 327394b701cSMatt Porter int rio_request_inb_dbell(struct rio_mport *mport, 3286978bbc0SMatt Porter void *dev_id, 329394b701cSMatt Porter u16 start, 330394b701cSMatt Porter u16 end, 3316978bbc0SMatt Porter void (*dinb) (struct rio_mport * mport, void *dev_id, u16 src, 332394b701cSMatt Porter u16 dst, u16 info)) 333394b701cSMatt Porter { 334394b701cSMatt Porter int rc = 0; 335394b701cSMatt Porter 3369a975beeSToshi Kani struct resource *res = kzalloc(sizeof(struct resource), GFP_KERNEL); 337394b701cSMatt Porter 338394b701cSMatt Porter if (res) { 339394b701cSMatt Porter rio_init_dbell_res(res, start, end); 340394b701cSMatt Porter 341394b701cSMatt Porter /* Make sure these doorbells aren't in use */ 342394b701cSMatt Porter if ((rc = 343394b701cSMatt Porter request_resource(&mport->riores[RIO_DOORBELL_RESOURCE], 344394b701cSMatt Porter res)) < 0) { 345394b701cSMatt Porter kfree(res); 346394b701cSMatt Porter goto out; 347394b701cSMatt Porter } 348394b701cSMatt Porter 349394b701cSMatt Porter /* Hook the doorbell callback */ 3506978bbc0SMatt Porter rc = rio_setup_inb_dbell(mport, dev_id, res, dinb); 351394b701cSMatt Porter } else 352394b701cSMatt Porter rc = -ENOMEM; 353394b701cSMatt Porter 354394b701cSMatt Porter out: 355394b701cSMatt Porter return rc; 356394b701cSMatt Porter } 357394b701cSMatt Porter 358394b701cSMatt Porter /** 359394b701cSMatt Porter * rio_release_inb_dbell - release inbound doorbell message service 360394b701cSMatt Porter * @mport: RIO master port from which to release the doorbell resource 361394b701cSMatt Porter * @start: Doorbell info range start 362394b701cSMatt Porter * @end: Doorbell info range end 363394b701cSMatt Porter * 364394b701cSMatt Porter * Releases ownership of an inbound doorbell resource and removes 365394b701cSMatt Porter * callback from the doorbell event list. Returns 0 if the request 366394b701cSMatt Porter * has been satisfied. 367394b701cSMatt Porter */ 368394b701cSMatt Porter int rio_release_inb_dbell(struct rio_mport *mport, u16 start, u16 end) 369394b701cSMatt Porter { 370394b701cSMatt Porter int rc = 0, found = 0; 371394b701cSMatt Porter struct rio_dbell *dbell; 372394b701cSMatt Porter 373394b701cSMatt Porter list_for_each_entry(dbell, &mport->dbells, node) { 374394b701cSMatt Porter if ((dbell->res->start == start) && (dbell->res->end == end)) { 375394b701cSMatt Porter found = 1; 376394b701cSMatt Porter break; 377394b701cSMatt Porter } 378394b701cSMatt Porter } 379394b701cSMatt Porter 380394b701cSMatt Porter /* If we can't find an exact match, fail */ 381394b701cSMatt Porter if (!found) { 382394b701cSMatt Porter rc = -EINVAL; 383394b701cSMatt Porter goto out; 384394b701cSMatt Porter } 385394b701cSMatt Porter 386394b701cSMatt Porter /* Delete from list */ 387394b701cSMatt Porter list_del(&dbell->node); 388394b701cSMatt Porter 389394b701cSMatt Porter /* Release the doorbell resource */ 390394b701cSMatt Porter rc = release_resource(dbell->res); 391394b701cSMatt Porter 392394b701cSMatt Porter /* Free the doorbell event */ 393394b701cSMatt Porter kfree(dbell); 394394b701cSMatt Porter 395394b701cSMatt Porter out: 396394b701cSMatt Porter return rc; 397394b701cSMatt Porter } 398394b701cSMatt Porter 399394b701cSMatt Porter /** 400394b701cSMatt Porter * rio_request_outb_dbell - request outbound doorbell message range 401394b701cSMatt Porter * @rdev: RIO device from which to allocate the doorbell resource 402394b701cSMatt Porter * @start: Doorbell message range start 403394b701cSMatt Porter * @end: Doorbell message range end 404394b701cSMatt Porter * 405394b701cSMatt Porter * Requests ownership of a doorbell message range. Returns a resource 406394b701cSMatt Porter * if the request has been satisfied or %NULL on failure. 407394b701cSMatt Porter */ 408394b701cSMatt Porter struct resource *rio_request_outb_dbell(struct rio_dev *rdev, u16 start, 409394b701cSMatt Porter u16 end) 410394b701cSMatt Porter { 4119a975beeSToshi Kani struct resource *res = kzalloc(sizeof(struct resource), GFP_KERNEL); 412394b701cSMatt Porter 413394b701cSMatt Porter if (res) { 414394b701cSMatt Porter rio_init_dbell_res(res, start, end); 415394b701cSMatt Porter 416394b701cSMatt Porter /* Make sure these doorbells aren't in use */ 417394b701cSMatt Porter if (request_resource(&rdev->riores[RIO_DOORBELL_RESOURCE], res) 418394b701cSMatt Porter < 0) { 419394b701cSMatt Porter kfree(res); 420394b701cSMatt Porter res = NULL; 421394b701cSMatt Porter } 422394b701cSMatt Porter } 423394b701cSMatt Porter 424394b701cSMatt Porter return res; 425394b701cSMatt Porter } 426394b701cSMatt Porter 427394b701cSMatt Porter /** 428394b701cSMatt Porter * rio_release_outb_dbell - release outbound doorbell message range 429394b701cSMatt Porter * @rdev: RIO device from which to release the doorbell resource 430394b701cSMatt Porter * @res: Doorbell resource to be freed 431394b701cSMatt Porter * 432394b701cSMatt Porter * Releases ownership of a doorbell message range. Returns 0 if the 433394b701cSMatt Porter * request has been satisfied. 434394b701cSMatt Porter */ 435394b701cSMatt Porter int rio_release_outb_dbell(struct rio_dev *rdev, struct resource *res) 436394b701cSMatt Porter { 437394b701cSMatt Porter int rc = release_resource(res); 438394b701cSMatt Porter 439394b701cSMatt Porter kfree(res); 440394b701cSMatt Porter 441394b701cSMatt Porter return rc; 442394b701cSMatt Porter } 443394b701cSMatt Porter 444394b701cSMatt Porter /** 445e5cabeb3SAlexandre Bounine * rio_request_inb_pwrite - request inbound port-write message service 44697ef6f74SRandy Dunlap * @rdev: RIO device to which register inbound port-write callback routine 447e5cabeb3SAlexandre Bounine * @pwcback: Callback routine to execute when port-write is received 448e5cabeb3SAlexandre Bounine * 449e5cabeb3SAlexandre Bounine * Binds a port-write callback function to the RapidIO device. 450e5cabeb3SAlexandre Bounine * Returns 0 if the request has been satisfied. 451e5cabeb3SAlexandre Bounine */ 452e5cabeb3SAlexandre Bounine int rio_request_inb_pwrite(struct rio_dev *rdev, 453e5cabeb3SAlexandre Bounine int (*pwcback)(struct rio_dev *rdev, union rio_pw_msg *msg, int step)) 454e5cabeb3SAlexandre Bounine { 455e5cabeb3SAlexandre Bounine int rc = 0; 456e5cabeb3SAlexandre Bounine 457e5cabeb3SAlexandre Bounine spin_lock(&rio_global_list_lock); 458e5cabeb3SAlexandre Bounine if (rdev->pwcback != NULL) 459e5cabeb3SAlexandre Bounine rc = -ENOMEM; 460e5cabeb3SAlexandre Bounine else 461e5cabeb3SAlexandre Bounine rdev->pwcback = pwcback; 462e5cabeb3SAlexandre Bounine 463e5cabeb3SAlexandre Bounine spin_unlock(&rio_global_list_lock); 464e5cabeb3SAlexandre Bounine return rc; 465e5cabeb3SAlexandre Bounine } 466e5cabeb3SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_request_inb_pwrite); 467e5cabeb3SAlexandre Bounine 468e5cabeb3SAlexandre Bounine /** 469e5cabeb3SAlexandre Bounine * rio_release_inb_pwrite - release inbound port-write message service 470e5cabeb3SAlexandre Bounine * @rdev: RIO device which registered for inbound port-write callback 471e5cabeb3SAlexandre Bounine * 472e5cabeb3SAlexandre Bounine * Removes callback from the rio_dev structure. Returns 0 if the request 473e5cabeb3SAlexandre Bounine * has been satisfied. 474e5cabeb3SAlexandre Bounine */ 475e5cabeb3SAlexandre Bounine int rio_release_inb_pwrite(struct rio_dev *rdev) 476e5cabeb3SAlexandre Bounine { 477e5cabeb3SAlexandre Bounine int rc = -ENOMEM; 478e5cabeb3SAlexandre Bounine 479e5cabeb3SAlexandre Bounine spin_lock(&rio_global_list_lock); 480e5cabeb3SAlexandre Bounine if (rdev->pwcback) { 481e5cabeb3SAlexandre Bounine rdev->pwcback = NULL; 482e5cabeb3SAlexandre Bounine rc = 0; 483e5cabeb3SAlexandre Bounine } 484e5cabeb3SAlexandre Bounine 485e5cabeb3SAlexandre Bounine spin_unlock(&rio_global_list_lock); 486e5cabeb3SAlexandre Bounine return rc; 487e5cabeb3SAlexandre Bounine } 488e5cabeb3SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_release_inb_pwrite); 489e5cabeb3SAlexandre Bounine 490e5cabeb3SAlexandre Bounine /** 491da1589f0SAlexandre Bounine * rio_map_inb_region -- Map inbound memory region. 492da1589f0SAlexandre Bounine * @mport: Master port. 4932ca3cb50SRandy Dunlap * @local: physical address of memory region to be mapped 494da1589f0SAlexandre Bounine * @rbase: RIO base address assigned to this window 495da1589f0SAlexandre Bounine * @size: Size of the memory region 496da1589f0SAlexandre Bounine * @rflags: Flags for mapping. 497da1589f0SAlexandre Bounine * 498da1589f0SAlexandre Bounine * Return: 0 -- Success. 499da1589f0SAlexandre Bounine * 500da1589f0SAlexandre Bounine * This function will create the mapping from RIO space to local memory. 501da1589f0SAlexandre Bounine */ 502da1589f0SAlexandre Bounine int rio_map_inb_region(struct rio_mport *mport, dma_addr_t local, 503da1589f0SAlexandre Bounine u64 rbase, u32 size, u32 rflags) 504da1589f0SAlexandre Bounine { 505da1589f0SAlexandre Bounine int rc = 0; 506da1589f0SAlexandre Bounine unsigned long flags; 507da1589f0SAlexandre Bounine 508da1589f0SAlexandre Bounine if (!mport->ops->map_inb) 509da1589f0SAlexandre Bounine return -1; 510da1589f0SAlexandre Bounine spin_lock_irqsave(&rio_mmap_lock, flags); 511da1589f0SAlexandre Bounine rc = mport->ops->map_inb(mport, local, rbase, size, rflags); 512da1589f0SAlexandre Bounine spin_unlock_irqrestore(&rio_mmap_lock, flags); 513da1589f0SAlexandre Bounine return rc; 514da1589f0SAlexandre Bounine } 515da1589f0SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_map_inb_region); 516da1589f0SAlexandre Bounine 517da1589f0SAlexandre Bounine /** 518da1589f0SAlexandre Bounine * rio_unmap_inb_region -- Unmap the inbound memory region 519da1589f0SAlexandre Bounine * @mport: Master port 520da1589f0SAlexandre Bounine * @lstart: physical address of memory region to be unmapped 521da1589f0SAlexandre Bounine */ 522da1589f0SAlexandre Bounine void rio_unmap_inb_region(struct rio_mport *mport, dma_addr_t lstart) 523da1589f0SAlexandre Bounine { 524da1589f0SAlexandre Bounine unsigned long flags; 525da1589f0SAlexandre Bounine if (!mport->ops->unmap_inb) 526da1589f0SAlexandre Bounine return; 527da1589f0SAlexandre Bounine spin_lock_irqsave(&rio_mmap_lock, flags); 528da1589f0SAlexandre Bounine mport->ops->unmap_inb(mport, lstart); 529da1589f0SAlexandre Bounine spin_unlock_irqrestore(&rio_mmap_lock, flags); 530da1589f0SAlexandre Bounine } 531da1589f0SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_unmap_inb_region); 532da1589f0SAlexandre Bounine 533da1589f0SAlexandre Bounine /** 534e5cabeb3SAlexandre Bounine * rio_mport_get_physefb - Helper function that returns register offset 535e5cabeb3SAlexandre Bounine * for Physical Layer Extended Features Block. 53697ef6f74SRandy Dunlap * @port: Master port to issue transaction 53797ef6f74SRandy Dunlap * @local: Indicate a local master port or remote device access 53897ef6f74SRandy Dunlap * @destid: Destination ID of the device 53997ef6f74SRandy Dunlap * @hopcount: Number of switch hops to the device 540e5cabeb3SAlexandre Bounine */ 541e5cabeb3SAlexandre Bounine u32 542e5cabeb3SAlexandre Bounine rio_mport_get_physefb(struct rio_mport *port, int local, 543e5cabeb3SAlexandre Bounine u16 destid, u8 hopcount) 544e5cabeb3SAlexandre Bounine { 545e5cabeb3SAlexandre Bounine u32 ext_ftr_ptr; 546e5cabeb3SAlexandre Bounine u32 ftr_header; 547e5cabeb3SAlexandre Bounine 548e5cabeb3SAlexandre Bounine ext_ftr_ptr = rio_mport_get_efb(port, local, destid, hopcount, 0); 549e5cabeb3SAlexandre Bounine 550e5cabeb3SAlexandre Bounine while (ext_ftr_ptr) { 551e5cabeb3SAlexandre Bounine if (local) 552e5cabeb3SAlexandre Bounine rio_local_read_config_32(port, ext_ftr_ptr, 553e5cabeb3SAlexandre Bounine &ftr_header); 554e5cabeb3SAlexandre Bounine else 555e5cabeb3SAlexandre Bounine rio_mport_read_config_32(port, destid, hopcount, 556e5cabeb3SAlexandre Bounine ext_ftr_ptr, &ftr_header); 557e5cabeb3SAlexandre Bounine 558e5cabeb3SAlexandre Bounine ftr_header = RIO_GET_BLOCK_ID(ftr_header); 559e5cabeb3SAlexandre Bounine switch (ftr_header) { 560e5cabeb3SAlexandre Bounine 561e5cabeb3SAlexandre Bounine case RIO_EFB_SER_EP_ID_V13P: 562e5cabeb3SAlexandre Bounine case RIO_EFB_SER_EP_REC_ID_V13P: 563e5cabeb3SAlexandre Bounine case RIO_EFB_SER_EP_FREE_ID_V13P: 564e5cabeb3SAlexandre Bounine case RIO_EFB_SER_EP_ID: 565e5cabeb3SAlexandre Bounine case RIO_EFB_SER_EP_REC_ID: 566e5cabeb3SAlexandre Bounine case RIO_EFB_SER_EP_FREE_ID: 567e5cabeb3SAlexandre Bounine case RIO_EFB_SER_EP_FREC_ID: 568e5cabeb3SAlexandre Bounine 569e5cabeb3SAlexandre Bounine return ext_ftr_ptr; 570e5cabeb3SAlexandre Bounine 571e5cabeb3SAlexandre Bounine default: 572e5cabeb3SAlexandre Bounine break; 573e5cabeb3SAlexandre Bounine } 574e5cabeb3SAlexandre Bounine 575e5cabeb3SAlexandre Bounine ext_ftr_ptr = rio_mport_get_efb(port, local, destid, 576e5cabeb3SAlexandre Bounine hopcount, ext_ftr_ptr); 577e5cabeb3SAlexandre Bounine } 578e5cabeb3SAlexandre Bounine 579e5cabeb3SAlexandre Bounine return ext_ftr_ptr; 580e5cabeb3SAlexandre Bounine } 581a11650e1SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_mport_get_physefb); 582e5cabeb3SAlexandre Bounine 583e5cabeb3SAlexandre Bounine /** 584e5cabeb3SAlexandre Bounine * rio_get_comptag - Begin or continue searching for a RIO device by component tag 58597ef6f74SRandy Dunlap * @comp_tag: RIO component tag to match 586e5cabeb3SAlexandre Bounine * @from: Previous RIO device found in search, or %NULL for new search 587e5cabeb3SAlexandre Bounine * 588e5cabeb3SAlexandre Bounine * Iterates through the list of known RIO devices. If a RIO device is 589e5cabeb3SAlexandre Bounine * found with a matching @comp_tag, a pointer to its device 590e5cabeb3SAlexandre Bounine * structure is returned. Otherwise, %NULL is returned. A new search 591e5cabeb3SAlexandre Bounine * is initiated by passing %NULL to the @from argument. Otherwise, if 592e5cabeb3SAlexandre Bounine * @from is not %NULL, searches continue from next device on the global 593e5cabeb3SAlexandre Bounine * list. 594e5cabeb3SAlexandre Bounine */ 595af84ca38SAlexandre Bounine struct rio_dev *rio_get_comptag(u32 comp_tag, struct rio_dev *from) 596e5cabeb3SAlexandre Bounine { 597e5cabeb3SAlexandre Bounine struct list_head *n; 598e5cabeb3SAlexandre Bounine struct rio_dev *rdev; 599e5cabeb3SAlexandre Bounine 600e5cabeb3SAlexandre Bounine spin_lock(&rio_global_list_lock); 601e5cabeb3SAlexandre Bounine n = from ? from->global_list.next : rio_devices.next; 602e5cabeb3SAlexandre Bounine 603e5cabeb3SAlexandre Bounine while (n && (n != &rio_devices)) { 604e5cabeb3SAlexandre Bounine rdev = rio_dev_g(n); 605e5cabeb3SAlexandre Bounine if (rdev->comp_tag == comp_tag) 606e5cabeb3SAlexandre Bounine goto exit; 607e5cabeb3SAlexandre Bounine n = n->next; 608e5cabeb3SAlexandre Bounine } 609e5cabeb3SAlexandre Bounine rdev = NULL; 610e5cabeb3SAlexandre Bounine exit: 611e5cabeb3SAlexandre Bounine spin_unlock(&rio_global_list_lock); 612e5cabeb3SAlexandre Bounine return rdev; 613e5cabeb3SAlexandre Bounine } 614a11650e1SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_get_comptag); 615e5cabeb3SAlexandre Bounine 616e5cabeb3SAlexandre Bounine /** 617e5cabeb3SAlexandre Bounine * rio_set_port_lockout - Sets/clears LOCKOUT bit (RIO EM 1.3) for a switch port. 618e5cabeb3SAlexandre Bounine * @rdev: Pointer to RIO device control structure 619e5cabeb3SAlexandre Bounine * @pnum: Switch port number to set LOCKOUT bit 620e5cabeb3SAlexandre Bounine * @lock: Operation : set (=1) or clear (=0) 621e5cabeb3SAlexandre Bounine */ 622e5cabeb3SAlexandre Bounine int rio_set_port_lockout(struct rio_dev *rdev, u32 pnum, int lock) 623e5cabeb3SAlexandre Bounine { 624e5cabeb3SAlexandre Bounine u32 regval; 625e5cabeb3SAlexandre Bounine 626a93192a5SAlexandre Bounine rio_read_config_32(rdev, 627e5cabeb3SAlexandre Bounine rdev->phys_efptr + RIO_PORT_N_CTL_CSR(pnum), 628e5cabeb3SAlexandre Bounine ®val); 629e5cabeb3SAlexandre Bounine if (lock) 630e5cabeb3SAlexandre Bounine regval |= RIO_PORT_N_CTL_LOCKOUT; 631e5cabeb3SAlexandre Bounine else 632e5cabeb3SAlexandre Bounine regval &= ~RIO_PORT_N_CTL_LOCKOUT; 633e5cabeb3SAlexandre Bounine 634a93192a5SAlexandre Bounine rio_write_config_32(rdev, 635e5cabeb3SAlexandre Bounine rdev->phys_efptr + RIO_PORT_N_CTL_CSR(pnum), 636e5cabeb3SAlexandre Bounine regval); 637e5cabeb3SAlexandre Bounine return 0; 638e5cabeb3SAlexandre Bounine } 639a11650e1SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_set_port_lockout); 640a11650e1SAlexandre Bounine 641a11650e1SAlexandre Bounine /** 642a11650e1SAlexandre Bounine * rio_enable_rx_tx_port - enable input receiver and output transmitter of 643a11650e1SAlexandre Bounine * given port 644a11650e1SAlexandre Bounine * @port: Master port associated with the RIO network 645a11650e1SAlexandre Bounine * @local: local=1 select local port otherwise a far device is reached 646a11650e1SAlexandre Bounine * @destid: Destination ID of the device to check host bit 647a11650e1SAlexandre Bounine * @hopcount: Number of hops to reach the target 648a11650e1SAlexandre Bounine * @port_num: Port (-number on switch) to enable on a far end device 649a11650e1SAlexandre Bounine * 650a11650e1SAlexandre Bounine * Returns 0 or 1 from on General Control Command and Status Register 651a11650e1SAlexandre Bounine * (EXT_PTR+0x3C) 652a11650e1SAlexandre Bounine */ 653a11650e1SAlexandre Bounine int rio_enable_rx_tx_port(struct rio_mport *port, 654a11650e1SAlexandre Bounine int local, u16 destid, 655a11650e1SAlexandre Bounine u8 hopcount, u8 port_num) 656a11650e1SAlexandre Bounine { 657a11650e1SAlexandre Bounine #ifdef CONFIG_RAPIDIO_ENABLE_RX_TX_PORTS 658a11650e1SAlexandre Bounine u32 regval; 659a11650e1SAlexandre Bounine u32 ext_ftr_ptr; 660a11650e1SAlexandre Bounine 661a11650e1SAlexandre Bounine /* 662a11650e1SAlexandre Bounine * enable rx input tx output port 663a11650e1SAlexandre Bounine */ 664a11650e1SAlexandre Bounine pr_debug("rio_enable_rx_tx_port(local = %d, destid = %d, hopcount = " 665a11650e1SAlexandre Bounine "%d, port_num = %d)\n", local, destid, hopcount, port_num); 666a11650e1SAlexandre Bounine 667a11650e1SAlexandre Bounine ext_ftr_ptr = rio_mport_get_physefb(port, local, destid, hopcount); 668a11650e1SAlexandre Bounine 669a11650e1SAlexandre Bounine if (local) { 670a11650e1SAlexandre Bounine rio_local_read_config_32(port, ext_ftr_ptr + 671a11650e1SAlexandre Bounine RIO_PORT_N_CTL_CSR(0), 672a11650e1SAlexandre Bounine ®val); 673a11650e1SAlexandre Bounine } else { 674a11650e1SAlexandre Bounine if (rio_mport_read_config_32(port, destid, hopcount, 675a11650e1SAlexandre Bounine ext_ftr_ptr + RIO_PORT_N_CTL_CSR(port_num), ®val) < 0) 676a11650e1SAlexandre Bounine return -EIO; 677a11650e1SAlexandre Bounine } 678a11650e1SAlexandre Bounine 679a11650e1SAlexandre Bounine if (regval & RIO_PORT_N_CTL_P_TYP_SER) { 680a11650e1SAlexandre Bounine /* serial */ 681a11650e1SAlexandre Bounine regval = regval | RIO_PORT_N_CTL_EN_RX_SER 682a11650e1SAlexandre Bounine | RIO_PORT_N_CTL_EN_TX_SER; 683a11650e1SAlexandre Bounine } else { 684a11650e1SAlexandre Bounine /* parallel */ 685a11650e1SAlexandre Bounine regval = regval | RIO_PORT_N_CTL_EN_RX_PAR 686a11650e1SAlexandre Bounine | RIO_PORT_N_CTL_EN_TX_PAR; 687a11650e1SAlexandre Bounine } 688a11650e1SAlexandre Bounine 689a11650e1SAlexandre Bounine if (local) { 690a11650e1SAlexandre Bounine rio_local_write_config_32(port, ext_ftr_ptr + 691a11650e1SAlexandre Bounine RIO_PORT_N_CTL_CSR(0), regval); 692a11650e1SAlexandre Bounine } else { 693a11650e1SAlexandre Bounine if (rio_mport_write_config_32(port, destid, hopcount, 694a11650e1SAlexandre Bounine ext_ftr_ptr + RIO_PORT_N_CTL_CSR(port_num), regval) < 0) 695a11650e1SAlexandre Bounine return -EIO; 696a11650e1SAlexandre Bounine } 697a11650e1SAlexandre Bounine #endif 698a11650e1SAlexandre Bounine return 0; 699a11650e1SAlexandre Bounine } 700a11650e1SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_enable_rx_tx_port); 701a11650e1SAlexandre Bounine 702e5cabeb3SAlexandre Bounine 703e5cabeb3SAlexandre Bounine /** 7046429cd49SAlexandre Bounine * rio_chk_dev_route - Validate route to the specified device. 7056429cd49SAlexandre Bounine * @rdev: RIO device failed to respond 7066429cd49SAlexandre Bounine * @nrdev: Last active device on the route to rdev 7076429cd49SAlexandre Bounine * @npnum: nrdev's port number on the route to rdev 7086429cd49SAlexandre Bounine * 7096429cd49SAlexandre Bounine * Follows a route to the specified RIO device to determine the last available 7106429cd49SAlexandre Bounine * device (and corresponding RIO port) on the route. 7116429cd49SAlexandre Bounine */ 7126429cd49SAlexandre Bounine static int 7136429cd49SAlexandre Bounine rio_chk_dev_route(struct rio_dev *rdev, struct rio_dev **nrdev, int *npnum) 7146429cd49SAlexandre Bounine { 7156429cd49SAlexandre Bounine u32 result; 716a93192a5SAlexandre Bounine int p_port, rc = -EIO; 7176429cd49SAlexandre Bounine struct rio_dev *prev = NULL; 7186429cd49SAlexandre Bounine 7196429cd49SAlexandre Bounine /* Find switch with failed RIO link */ 7206429cd49SAlexandre Bounine while (rdev->prev && (rdev->prev->pef & RIO_PEF_SWITCH)) { 7216429cd49SAlexandre Bounine if (!rio_read_config_32(rdev->prev, RIO_DEV_ID_CAR, &result)) { 7226429cd49SAlexandre Bounine prev = rdev->prev; 7236429cd49SAlexandre Bounine break; 7246429cd49SAlexandre Bounine } 7256429cd49SAlexandre Bounine rdev = rdev->prev; 7266429cd49SAlexandre Bounine } 7276429cd49SAlexandre Bounine 7286429cd49SAlexandre Bounine if (prev == NULL) 7296429cd49SAlexandre Bounine goto err_out; 7306429cd49SAlexandre Bounine 731a93192a5SAlexandre Bounine p_port = prev->rswitch->route_table[rdev->destid]; 7326429cd49SAlexandre Bounine 733af84ca38SAlexandre Bounine if (p_port != RIO_INVALID_ROUTE) { 7346429cd49SAlexandre Bounine pr_debug("RIO: link failed on [%s]-P%d\n", 7356429cd49SAlexandre Bounine rio_name(prev), p_port); 7366429cd49SAlexandre Bounine *nrdev = prev; 7376429cd49SAlexandre Bounine *npnum = p_port; 7386429cd49SAlexandre Bounine rc = 0; 7396429cd49SAlexandre Bounine } else 740af84ca38SAlexandre Bounine pr_debug("RIO: failed to trace route to %s\n", rio_name(rdev)); 7416429cd49SAlexandre Bounine err_out: 7426429cd49SAlexandre Bounine return rc; 7436429cd49SAlexandre Bounine } 7446429cd49SAlexandre Bounine 7456429cd49SAlexandre Bounine /** 7466429cd49SAlexandre Bounine * rio_mport_chk_dev_access - Validate access to the specified device. 7476429cd49SAlexandre Bounine * @mport: Master port to send transactions 7486429cd49SAlexandre Bounine * @destid: Device destination ID in network 7496429cd49SAlexandre Bounine * @hopcount: Number of hops into the network 7506429cd49SAlexandre Bounine */ 751e274e0edSAlexandre Bounine int 7526429cd49SAlexandre Bounine rio_mport_chk_dev_access(struct rio_mport *mport, u16 destid, u8 hopcount) 7536429cd49SAlexandre Bounine { 7546429cd49SAlexandre Bounine int i = 0; 7556429cd49SAlexandre Bounine u32 tmp; 7566429cd49SAlexandre Bounine 7576429cd49SAlexandre Bounine while (rio_mport_read_config_32(mport, destid, hopcount, 7586429cd49SAlexandre Bounine RIO_DEV_ID_CAR, &tmp)) { 7596429cd49SAlexandre Bounine i++; 7606429cd49SAlexandre Bounine if (i == RIO_MAX_CHK_RETRY) 7616429cd49SAlexandre Bounine return -EIO; 7626429cd49SAlexandre Bounine mdelay(1); 7636429cd49SAlexandre Bounine } 7646429cd49SAlexandre Bounine 7656429cd49SAlexandre Bounine return 0; 7666429cd49SAlexandre Bounine } 767a11650e1SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_mport_chk_dev_access); 7686429cd49SAlexandre Bounine 7696429cd49SAlexandre Bounine /** 7706429cd49SAlexandre Bounine * rio_chk_dev_access - Validate access to the specified device. 7716429cd49SAlexandre Bounine * @rdev: Pointer to RIO device control structure 7726429cd49SAlexandre Bounine */ 7736429cd49SAlexandre Bounine static int rio_chk_dev_access(struct rio_dev *rdev) 7746429cd49SAlexandre Bounine { 775a93192a5SAlexandre Bounine return rio_mport_chk_dev_access(rdev->net->hport, 776a93192a5SAlexandre Bounine rdev->destid, rdev->hopcount); 7776429cd49SAlexandre Bounine } 7786429cd49SAlexandre Bounine 7796429cd49SAlexandre Bounine /** 780dd5648c9SAlexandre Bounine * rio_get_input_status - Sends a Link-Request/Input-Status control symbol and 781dd5648c9SAlexandre Bounine * returns link-response (if requested). 782dd5648c9SAlexandre Bounine * @rdev: RIO devive to issue Input-status command 783dd5648c9SAlexandre Bounine * @pnum: Device port number to issue the command 784dd5648c9SAlexandre Bounine * @lnkresp: Response from a link partner 785dd5648c9SAlexandre Bounine */ 786dd5648c9SAlexandre Bounine static int 787dd5648c9SAlexandre Bounine rio_get_input_status(struct rio_dev *rdev, int pnum, u32 *lnkresp) 788dd5648c9SAlexandre Bounine { 789dd5648c9SAlexandre Bounine u32 regval; 790dd5648c9SAlexandre Bounine int checkcount; 791dd5648c9SAlexandre Bounine 792dd5648c9SAlexandre Bounine if (lnkresp) { 793dd5648c9SAlexandre Bounine /* Read from link maintenance response register 794dd5648c9SAlexandre Bounine * to clear valid bit */ 795a93192a5SAlexandre Bounine rio_read_config_32(rdev, 796dd5648c9SAlexandre Bounine rdev->phys_efptr + RIO_PORT_N_MNT_RSP_CSR(pnum), 797dd5648c9SAlexandre Bounine ®val); 798dd5648c9SAlexandre Bounine udelay(50); 799dd5648c9SAlexandre Bounine } 800dd5648c9SAlexandre Bounine 801dd5648c9SAlexandre Bounine /* Issue Input-status command */ 802a93192a5SAlexandre Bounine rio_write_config_32(rdev, 803dd5648c9SAlexandre Bounine rdev->phys_efptr + RIO_PORT_N_MNT_REQ_CSR(pnum), 804dd5648c9SAlexandre Bounine RIO_MNT_REQ_CMD_IS); 805dd5648c9SAlexandre Bounine 806dd5648c9SAlexandre Bounine /* Exit if the response is not expected */ 807dd5648c9SAlexandre Bounine if (lnkresp == NULL) 808dd5648c9SAlexandre Bounine return 0; 809dd5648c9SAlexandre Bounine 810dd5648c9SAlexandre Bounine checkcount = 3; 811dd5648c9SAlexandre Bounine while (checkcount--) { 812dd5648c9SAlexandre Bounine udelay(50); 813a93192a5SAlexandre Bounine rio_read_config_32(rdev, 814dd5648c9SAlexandre Bounine rdev->phys_efptr + RIO_PORT_N_MNT_RSP_CSR(pnum), 815dd5648c9SAlexandre Bounine ®val); 816dd5648c9SAlexandre Bounine if (regval & RIO_PORT_N_MNT_RSP_RVAL) { 817dd5648c9SAlexandre Bounine *lnkresp = regval; 818dd5648c9SAlexandre Bounine return 0; 819dd5648c9SAlexandre Bounine } 820dd5648c9SAlexandre Bounine } 821dd5648c9SAlexandre Bounine 822dd5648c9SAlexandre Bounine return -EIO; 823dd5648c9SAlexandre Bounine } 824dd5648c9SAlexandre Bounine 825dd5648c9SAlexandre Bounine /** 826dd5648c9SAlexandre Bounine * rio_clr_err_stopped - Clears port Error-stopped states. 827dd5648c9SAlexandre Bounine * @rdev: Pointer to RIO device control structure 828dd5648c9SAlexandre Bounine * @pnum: Switch port number to clear errors 829dd5648c9SAlexandre Bounine * @err_status: port error status (if 0 reads register from device) 830dd5648c9SAlexandre Bounine */ 831dd5648c9SAlexandre Bounine static int rio_clr_err_stopped(struct rio_dev *rdev, u32 pnum, u32 err_status) 832dd5648c9SAlexandre Bounine { 833dd5648c9SAlexandre Bounine struct rio_dev *nextdev = rdev->rswitch->nextdev[pnum]; 834dd5648c9SAlexandre Bounine u32 regval; 835dd5648c9SAlexandre Bounine u32 far_ackid, far_linkstat, near_ackid; 836dd5648c9SAlexandre Bounine 837dd5648c9SAlexandre Bounine if (err_status == 0) 838a93192a5SAlexandre Bounine rio_read_config_32(rdev, 839dd5648c9SAlexandre Bounine rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(pnum), 840dd5648c9SAlexandre Bounine &err_status); 841dd5648c9SAlexandre Bounine 842dd5648c9SAlexandre Bounine if (err_status & RIO_PORT_N_ERR_STS_PW_OUT_ES) { 843dd5648c9SAlexandre Bounine pr_debug("RIO_EM: servicing Output Error-Stopped state\n"); 844dd5648c9SAlexandre Bounine /* 845dd5648c9SAlexandre Bounine * Send a Link-Request/Input-Status control symbol 846dd5648c9SAlexandre Bounine */ 847dd5648c9SAlexandre Bounine if (rio_get_input_status(rdev, pnum, ®val)) { 848dd5648c9SAlexandre Bounine pr_debug("RIO_EM: Input-status response timeout\n"); 849dd5648c9SAlexandre Bounine goto rd_err; 850dd5648c9SAlexandre Bounine } 851dd5648c9SAlexandre Bounine 852dd5648c9SAlexandre Bounine pr_debug("RIO_EM: SP%d Input-status response=0x%08x\n", 853dd5648c9SAlexandre Bounine pnum, regval); 854dd5648c9SAlexandre Bounine far_ackid = (regval & RIO_PORT_N_MNT_RSP_ASTAT) >> 5; 855dd5648c9SAlexandre Bounine far_linkstat = regval & RIO_PORT_N_MNT_RSP_LSTAT; 856a93192a5SAlexandre Bounine rio_read_config_32(rdev, 857dd5648c9SAlexandre Bounine rdev->phys_efptr + RIO_PORT_N_ACK_STS_CSR(pnum), 858dd5648c9SAlexandre Bounine ®val); 859dd5648c9SAlexandre Bounine pr_debug("RIO_EM: SP%d_ACK_STS_CSR=0x%08x\n", pnum, regval); 860dd5648c9SAlexandre Bounine near_ackid = (regval & RIO_PORT_N_ACK_INBOUND) >> 24; 861dd5648c9SAlexandre Bounine pr_debug("RIO_EM: SP%d far_ackID=0x%02x far_linkstat=0x%02x" \ 862dd5648c9SAlexandre Bounine " near_ackID=0x%02x\n", 863dd5648c9SAlexandre Bounine pnum, far_ackid, far_linkstat, near_ackid); 864dd5648c9SAlexandre Bounine 865dd5648c9SAlexandre Bounine /* 866dd5648c9SAlexandre Bounine * If required, synchronize ackIDs of near and 867dd5648c9SAlexandre Bounine * far sides. 868dd5648c9SAlexandre Bounine */ 869dd5648c9SAlexandre Bounine if ((far_ackid != ((regval & RIO_PORT_N_ACK_OUTSTAND) >> 8)) || 870dd5648c9SAlexandre Bounine (far_ackid != (regval & RIO_PORT_N_ACK_OUTBOUND))) { 871dd5648c9SAlexandre Bounine /* Align near outstanding/outbound ackIDs with 872dd5648c9SAlexandre Bounine * far inbound. 873dd5648c9SAlexandre Bounine */ 874a93192a5SAlexandre Bounine rio_write_config_32(rdev, 875a93192a5SAlexandre Bounine rdev->phys_efptr + RIO_PORT_N_ACK_STS_CSR(pnum), 876dd5648c9SAlexandre Bounine (near_ackid << 24) | 877dd5648c9SAlexandre Bounine (far_ackid << 8) | far_ackid); 878dd5648c9SAlexandre Bounine /* Align far outstanding/outbound ackIDs with 879dd5648c9SAlexandre Bounine * near inbound. 880dd5648c9SAlexandre Bounine */ 881dd5648c9SAlexandre Bounine far_ackid++; 882dd5648c9SAlexandre Bounine if (nextdev) 883dd5648c9SAlexandre Bounine rio_write_config_32(nextdev, 884dd5648c9SAlexandre Bounine nextdev->phys_efptr + 885dd5648c9SAlexandre Bounine RIO_PORT_N_ACK_STS_CSR(RIO_GET_PORT_NUM(nextdev->swpinfo)), 886dd5648c9SAlexandre Bounine (far_ackid << 24) | 887dd5648c9SAlexandre Bounine (near_ackid << 8) | near_ackid); 888dd5648c9SAlexandre Bounine else 889dd5648c9SAlexandre Bounine pr_debug("RIO_EM: Invalid nextdev pointer (NULL)\n"); 890dd5648c9SAlexandre Bounine } 891dd5648c9SAlexandre Bounine rd_err: 892a93192a5SAlexandre Bounine rio_read_config_32(rdev, 893dd5648c9SAlexandre Bounine rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(pnum), 894dd5648c9SAlexandre Bounine &err_status); 895dd5648c9SAlexandre Bounine pr_debug("RIO_EM: SP%d_ERR_STS_CSR=0x%08x\n", pnum, err_status); 896dd5648c9SAlexandre Bounine } 897dd5648c9SAlexandre Bounine 898dd5648c9SAlexandre Bounine if ((err_status & RIO_PORT_N_ERR_STS_PW_INP_ES) && nextdev) { 899dd5648c9SAlexandre Bounine pr_debug("RIO_EM: servicing Input Error-Stopped state\n"); 900dd5648c9SAlexandre Bounine rio_get_input_status(nextdev, 901dd5648c9SAlexandre Bounine RIO_GET_PORT_NUM(nextdev->swpinfo), NULL); 902dd5648c9SAlexandre Bounine udelay(50); 903dd5648c9SAlexandre Bounine 904a93192a5SAlexandre Bounine rio_read_config_32(rdev, 905dd5648c9SAlexandre Bounine rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(pnum), 906dd5648c9SAlexandre Bounine &err_status); 907dd5648c9SAlexandre Bounine pr_debug("RIO_EM: SP%d_ERR_STS_CSR=0x%08x\n", pnum, err_status); 908dd5648c9SAlexandre Bounine } 909dd5648c9SAlexandre Bounine 910dd5648c9SAlexandre Bounine return (err_status & (RIO_PORT_N_ERR_STS_PW_OUT_ES | 911dd5648c9SAlexandre Bounine RIO_PORT_N_ERR_STS_PW_INP_ES)) ? 1 : 0; 912dd5648c9SAlexandre Bounine } 913dd5648c9SAlexandre Bounine 914dd5648c9SAlexandre Bounine /** 915e5cabeb3SAlexandre Bounine * rio_inb_pwrite_handler - process inbound port-write message 916e5cabeb3SAlexandre Bounine * @pw_msg: pointer to inbound port-write message 917e5cabeb3SAlexandre Bounine * 918e5cabeb3SAlexandre Bounine * Processes an inbound port-write message. Returns 0 if the request 919e5cabeb3SAlexandre Bounine * has been satisfied. 920e5cabeb3SAlexandre Bounine */ 921e5cabeb3SAlexandre Bounine int rio_inb_pwrite_handler(union rio_pw_msg *pw_msg) 922e5cabeb3SAlexandre Bounine { 923e5cabeb3SAlexandre Bounine struct rio_dev *rdev; 924dd5648c9SAlexandre Bounine u32 err_status, em_perrdet, em_ltlerrdet; 925e5cabeb3SAlexandre Bounine int rc, portnum; 926e5cabeb3SAlexandre Bounine 927e6536927SAlexandre Bounine rdev = rio_get_comptag((pw_msg->em.comptag & RIO_CTAG_UDEVID), NULL); 928e5cabeb3SAlexandre Bounine if (rdev == NULL) { 9296429cd49SAlexandre Bounine /* Device removed or enumeration error */ 9306429cd49SAlexandre Bounine pr_debug("RIO: %s No matching device for CTag 0x%08x\n", 931e5cabeb3SAlexandre Bounine __func__, pw_msg->em.comptag); 932e5cabeb3SAlexandre Bounine return -EIO; 933e5cabeb3SAlexandre Bounine } 934e5cabeb3SAlexandre Bounine 935e5cabeb3SAlexandre Bounine pr_debug("RIO: Port-Write message from %s\n", rio_name(rdev)); 936e5cabeb3SAlexandre Bounine 937e5cabeb3SAlexandre Bounine #ifdef DEBUG_PW 938e5cabeb3SAlexandre Bounine { 939e5cabeb3SAlexandre Bounine u32 i; 940e5cabeb3SAlexandre Bounine for (i = 0; i < RIO_PW_MSG_SIZE/sizeof(u32);) { 941dd5648c9SAlexandre Bounine pr_debug("0x%02x: %08x %08x %08x %08x\n", 942e5cabeb3SAlexandre Bounine i*4, pw_msg->raw[i], pw_msg->raw[i + 1], 943e5cabeb3SAlexandre Bounine pw_msg->raw[i + 2], pw_msg->raw[i + 3]); 944e5cabeb3SAlexandre Bounine i += 4; 945e5cabeb3SAlexandre Bounine } 946e5cabeb3SAlexandre Bounine } 947e5cabeb3SAlexandre Bounine #endif 948e5cabeb3SAlexandre Bounine 949e5cabeb3SAlexandre Bounine /* Call an external service function (if such is registered 950e5cabeb3SAlexandre Bounine * for this device). This may be the service for endpoints that send 951e5cabeb3SAlexandre Bounine * device-specific port-write messages. End-point messages expected 952e5cabeb3SAlexandre Bounine * to be handled completely by EP specific device driver. 953e5cabeb3SAlexandre Bounine * For switches rc==0 signals that no standard processing required. 954e5cabeb3SAlexandre Bounine */ 955e5cabeb3SAlexandre Bounine if (rdev->pwcback != NULL) { 956e5cabeb3SAlexandre Bounine rc = rdev->pwcback(rdev, pw_msg, 0); 957e5cabeb3SAlexandre Bounine if (rc == 0) 958e5cabeb3SAlexandre Bounine return 0; 959e5cabeb3SAlexandre Bounine } 960e5cabeb3SAlexandre Bounine 9616429cd49SAlexandre Bounine portnum = pw_msg->em.is_port & 0xFF; 9626429cd49SAlexandre Bounine 9636429cd49SAlexandre Bounine /* Check if device and route to it are functional: 9646429cd49SAlexandre Bounine * Sometimes devices may send PW message(s) just before being 9656429cd49SAlexandre Bounine * powered down (or link being lost). 9666429cd49SAlexandre Bounine */ 9676429cd49SAlexandre Bounine if (rio_chk_dev_access(rdev)) { 9686429cd49SAlexandre Bounine pr_debug("RIO: device access failed - get link partner\n"); 9696429cd49SAlexandre Bounine /* Scan route to the device and identify failed link. 9706429cd49SAlexandre Bounine * This will replace device and port reported in PW message. 9716429cd49SAlexandre Bounine * PW message should not be used after this point. 9726429cd49SAlexandre Bounine */ 9736429cd49SAlexandre Bounine if (rio_chk_dev_route(rdev, &rdev, &portnum)) { 9746429cd49SAlexandre Bounine pr_err("RIO: Route trace for %s failed\n", 9756429cd49SAlexandre Bounine rio_name(rdev)); 9766429cd49SAlexandre Bounine return -EIO; 9776429cd49SAlexandre Bounine } 9786429cd49SAlexandre Bounine pw_msg = NULL; 9796429cd49SAlexandre Bounine } 9806429cd49SAlexandre Bounine 981e5cabeb3SAlexandre Bounine /* For End-point devices processing stops here */ 982e5cabeb3SAlexandre Bounine if (!(rdev->pef & RIO_PEF_SWITCH)) 983e5cabeb3SAlexandre Bounine return 0; 984e5cabeb3SAlexandre Bounine 985e5cabeb3SAlexandre Bounine if (rdev->phys_efptr == 0) { 986e5cabeb3SAlexandre Bounine pr_err("RIO_PW: Bad switch initialization for %s\n", 987e5cabeb3SAlexandre Bounine rio_name(rdev)); 988e5cabeb3SAlexandre Bounine return 0; 989e5cabeb3SAlexandre Bounine } 990e5cabeb3SAlexandre Bounine 991e5cabeb3SAlexandre Bounine /* 992e5cabeb3SAlexandre Bounine * Process the port-write notification from switch 993e5cabeb3SAlexandre Bounine */ 9942ec3ba69SAlexandre Bounine if (rdev->rswitch->ops && rdev->rswitch->ops->em_handle) 9952ec3ba69SAlexandre Bounine rdev->rswitch->ops->em_handle(rdev, portnum); 996e5cabeb3SAlexandre Bounine 997a93192a5SAlexandre Bounine rio_read_config_32(rdev, 998e5cabeb3SAlexandre Bounine rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(portnum), 999e5cabeb3SAlexandre Bounine &err_status); 1000e5cabeb3SAlexandre Bounine pr_debug("RIO_PW: SP%d_ERR_STS_CSR=0x%08x\n", portnum, err_status); 1001e5cabeb3SAlexandre Bounine 1002dd5648c9SAlexandre Bounine if (err_status & RIO_PORT_N_ERR_STS_PORT_OK) { 1003dd5648c9SAlexandre Bounine 1004dd5648c9SAlexandre Bounine if (!(rdev->rswitch->port_ok & (1 << portnum))) { 1005dd5648c9SAlexandre Bounine rdev->rswitch->port_ok |= (1 << portnum); 1006dd5648c9SAlexandre Bounine rio_set_port_lockout(rdev, portnum, 0); 1007dd5648c9SAlexandre Bounine /* Schedule Insertion Service */ 1008dd5648c9SAlexandre Bounine pr_debug("RIO_PW: Device Insertion on [%s]-P%d\n", 1009dd5648c9SAlexandre Bounine rio_name(rdev), portnum); 1010e5cabeb3SAlexandre Bounine } 1011e5cabeb3SAlexandre Bounine 1012dd5648c9SAlexandre Bounine /* Clear error-stopped states (if reported). 1013dd5648c9SAlexandre Bounine * Depending on the link partner state, two attempts 1014dd5648c9SAlexandre Bounine * may be needed for successful recovery. 1015dd5648c9SAlexandre Bounine */ 1016dd5648c9SAlexandre Bounine if (err_status & (RIO_PORT_N_ERR_STS_PW_OUT_ES | 1017dd5648c9SAlexandre Bounine RIO_PORT_N_ERR_STS_PW_INP_ES)) { 1018dd5648c9SAlexandre Bounine if (rio_clr_err_stopped(rdev, portnum, err_status)) 1019dd5648c9SAlexandre Bounine rio_clr_err_stopped(rdev, portnum, 0); 1020e5cabeb3SAlexandre Bounine } 1021dd5648c9SAlexandre Bounine } else { /* if (err_status & RIO_PORT_N_ERR_STS_PORT_UNINIT) */ 1022e5cabeb3SAlexandre Bounine 1023e5cabeb3SAlexandre Bounine if (rdev->rswitch->port_ok & (1 << portnum)) { 1024e5cabeb3SAlexandre Bounine rdev->rswitch->port_ok &= ~(1 << portnum); 1025e5cabeb3SAlexandre Bounine rio_set_port_lockout(rdev, portnum, 1); 1026e5cabeb3SAlexandre Bounine 1027a93192a5SAlexandre Bounine rio_write_config_32(rdev, 1028e5cabeb3SAlexandre Bounine rdev->phys_efptr + 1029e5cabeb3SAlexandre Bounine RIO_PORT_N_ACK_STS_CSR(portnum), 1030e5cabeb3SAlexandre Bounine RIO_PORT_N_ACK_CLEAR); 1031e5cabeb3SAlexandre Bounine 1032e5cabeb3SAlexandre Bounine /* Schedule Extraction Service */ 1033e5cabeb3SAlexandre Bounine pr_debug("RIO_PW: Device Extraction on [%s]-P%d\n", 1034e5cabeb3SAlexandre Bounine rio_name(rdev), portnum); 1035e5cabeb3SAlexandre Bounine } 1036dd5648c9SAlexandre Bounine } 1037e5cabeb3SAlexandre Bounine 1038a93192a5SAlexandre Bounine rio_read_config_32(rdev, 1039dd5648c9SAlexandre Bounine rdev->em_efptr + RIO_EM_PN_ERR_DETECT(portnum), &em_perrdet); 1040dd5648c9SAlexandre Bounine if (em_perrdet) { 1041dd5648c9SAlexandre Bounine pr_debug("RIO_PW: RIO_EM_P%d_ERR_DETECT=0x%08x\n", 1042dd5648c9SAlexandre Bounine portnum, em_perrdet); 1043dd5648c9SAlexandre Bounine /* Clear EM Port N Error Detect CSR */ 1044a93192a5SAlexandre Bounine rio_write_config_32(rdev, 1045dd5648c9SAlexandre Bounine rdev->em_efptr + RIO_EM_PN_ERR_DETECT(portnum), 0); 1046e5cabeb3SAlexandre Bounine } 1047dd5648c9SAlexandre Bounine 1048a93192a5SAlexandre Bounine rio_read_config_32(rdev, 1049dd5648c9SAlexandre Bounine rdev->em_efptr + RIO_EM_LTL_ERR_DETECT, &em_ltlerrdet); 1050dd5648c9SAlexandre Bounine if (em_ltlerrdet) { 1051dd5648c9SAlexandre Bounine pr_debug("RIO_PW: RIO_EM_LTL_ERR_DETECT=0x%08x\n", 1052dd5648c9SAlexandre Bounine em_ltlerrdet); 1053dd5648c9SAlexandre Bounine /* Clear EM L/T Layer Error Detect CSR */ 1054a93192a5SAlexandre Bounine rio_write_config_32(rdev, 1055dd5648c9SAlexandre Bounine rdev->em_efptr + RIO_EM_LTL_ERR_DETECT, 0); 1056e5cabeb3SAlexandre Bounine } 1057e5cabeb3SAlexandre Bounine 1058388c45ccSAlexandre Bounine /* Clear remaining error bits and Port-Write Pending bit */ 1059a93192a5SAlexandre Bounine rio_write_config_32(rdev, 1060dd5648c9SAlexandre Bounine rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(portnum), 1061388c45ccSAlexandre Bounine err_status); 1062e5cabeb3SAlexandre Bounine 1063e5cabeb3SAlexandre Bounine return 0; 1064e5cabeb3SAlexandre Bounine } 1065e5cabeb3SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_inb_pwrite_handler); 1066e5cabeb3SAlexandre Bounine 1067e5cabeb3SAlexandre Bounine /** 1068e5cabeb3SAlexandre Bounine * rio_mport_get_efb - get pointer to next extended features block 1069e5cabeb3SAlexandre Bounine * @port: Master port to issue transaction 1070e5cabeb3SAlexandre Bounine * @local: Indicate a local master port or remote device access 1071e5cabeb3SAlexandre Bounine * @destid: Destination ID of the device 1072e5cabeb3SAlexandre Bounine * @hopcount: Number of switch hops to the device 1073e5cabeb3SAlexandre Bounine * @from: Offset of current Extended Feature block header (if 0 starts 1074e5cabeb3SAlexandre Bounine * from ExtFeaturePtr) 1075e5cabeb3SAlexandre Bounine */ 1076e5cabeb3SAlexandre Bounine u32 1077e5cabeb3SAlexandre Bounine rio_mport_get_efb(struct rio_mport *port, int local, u16 destid, 1078e5cabeb3SAlexandre Bounine u8 hopcount, u32 from) 1079e5cabeb3SAlexandre Bounine { 1080e5cabeb3SAlexandre Bounine u32 reg_val; 1081e5cabeb3SAlexandre Bounine 1082e5cabeb3SAlexandre Bounine if (from == 0) { 1083e5cabeb3SAlexandre Bounine if (local) 1084e5cabeb3SAlexandre Bounine rio_local_read_config_32(port, RIO_ASM_INFO_CAR, 1085e5cabeb3SAlexandre Bounine ®_val); 1086e5cabeb3SAlexandre Bounine else 1087e5cabeb3SAlexandre Bounine rio_mport_read_config_32(port, destid, hopcount, 1088e5cabeb3SAlexandre Bounine RIO_ASM_INFO_CAR, ®_val); 1089e5cabeb3SAlexandre Bounine return reg_val & RIO_EXT_FTR_PTR_MASK; 1090e5cabeb3SAlexandre Bounine } else { 1091e5cabeb3SAlexandre Bounine if (local) 1092e5cabeb3SAlexandre Bounine rio_local_read_config_32(port, from, ®_val); 1093e5cabeb3SAlexandre Bounine else 1094e5cabeb3SAlexandre Bounine rio_mport_read_config_32(port, destid, hopcount, 1095e5cabeb3SAlexandre Bounine from, ®_val); 1096e5cabeb3SAlexandre Bounine return RIO_GET_BLOCK_ID(reg_val); 1097e5cabeb3SAlexandre Bounine } 1098e5cabeb3SAlexandre Bounine } 1099a11650e1SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_mport_get_efb); 1100e5cabeb3SAlexandre Bounine 1101e5cabeb3SAlexandre Bounine /** 1102394b701cSMatt Porter * rio_mport_get_feature - query for devices' extended features 1103394b701cSMatt Porter * @port: Master port to issue transaction 1104394b701cSMatt Porter * @local: Indicate a local master port or remote device access 1105394b701cSMatt Porter * @destid: Destination ID of the device 1106394b701cSMatt Porter * @hopcount: Number of switch hops to the device 1107394b701cSMatt Porter * @ftr: Extended feature code 1108394b701cSMatt Porter * 1109394b701cSMatt Porter * Tell if a device supports a given RapidIO capability. 1110394b701cSMatt Porter * Returns the offset of the requested extended feature 1111394b701cSMatt Porter * block within the device's RIO configuration space or 1112394b701cSMatt Porter * 0 in case the device does not support it. Possible 1113394b701cSMatt Porter * values for @ftr: 1114394b701cSMatt Porter * 1115394b701cSMatt Porter * %RIO_EFB_PAR_EP_ID LP/LVDS EP Devices 1116394b701cSMatt Porter * 1117394b701cSMatt Porter * %RIO_EFB_PAR_EP_REC_ID LP/LVDS EP Recovery Devices 1118394b701cSMatt Porter * 1119394b701cSMatt Porter * %RIO_EFB_PAR_EP_FREE_ID LP/LVDS EP Free Devices 1120394b701cSMatt Porter * 1121394b701cSMatt Porter * %RIO_EFB_SER_EP_ID LP/Serial EP Devices 1122394b701cSMatt Porter * 1123394b701cSMatt Porter * %RIO_EFB_SER_EP_REC_ID LP/Serial EP Recovery Devices 1124394b701cSMatt Porter * 1125394b701cSMatt Porter * %RIO_EFB_SER_EP_FREE_ID LP/Serial EP Free Devices 1126394b701cSMatt Porter */ 1127394b701cSMatt Porter u32 1128394b701cSMatt Porter rio_mport_get_feature(struct rio_mport * port, int local, u16 destid, 1129394b701cSMatt Porter u8 hopcount, int ftr) 1130394b701cSMatt Porter { 1131394b701cSMatt Porter u32 asm_info, ext_ftr_ptr, ftr_header; 1132394b701cSMatt Porter 1133394b701cSMatt Porter if (local) 1134394b701cSMatt Porter rio_local_read_config_32(port, RIO_ASM_INFO_CAR, &asm_info); 1135394b701cSMatt Porter else 1136394b701cSMatt Porter rio_mport_read_config_32(port, destid, hopcount, 1137394b701cSMatt Porter RIO_ASM_INFO_CAR, &asm_info); 1138394b701cSMatt Porter 1139394b701cSMatt Porter ext_ftr_ptr = asm_info & RIO_EXT_FTR_PTR_MASK; 1140394b701cSMatt Porter 1141394b701cSMatt Porter while (ext_ftr_ptr) { 1142394b701cSMatt Porter if (local) 1143394b701cSMatt Porter rio_local_read_config_32(port, ext_ftr_ptr, 1144394b701cSMatt Porter &ftr_header); 1145394b701cSMatt Porter else 1146394b701cSMatt Porter rio_mport_read_config_32(port, destid, hopcount, 1147394b701cSMatt Porter ext_ftr_ptr, &ftr_header); 1148394b701cSMatt Porter if (RIO_GET_BLOCK_ID(ftr_header) == ftr) 1149394b701cSMatt Porter return ext_ftr_ptr; 1150394b701cSMatt Porter if (!(ext_ftr_ptr = RIO_GET_BLOCK_PTR(ftr_header))) 1151394b701cSMatt Porter break; 1152394b701cSMatt Porter } 1153394b701cSMatt Porter 1154394b701cSMatt Porter return 0; 1155394b701cSMatt Porter } 1156a11650e1SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_mport_get_feature); 1157394b701cSMatt Porter 1158394b701cSMatt Porter /** 1159394b701cSMatt Porter * rio_get_asm - Begin or continue searching for a RIO device by vid/did/asm_vid/asm_did 1160394b701cSMatt Porter * @vid: RIO vid to match or %RIO_ANY_ID to match all vids 1161394b701cSMatt Porter * @did: RIO did to match or %RIO_ANY_ID to match all dids 1162394b701cSMatt Porter * @asm_vid: RIO asm_vid to match or %RIO_ANY_ID to match all asm_vids 1163394b701cSMatt Porter * @asm_did: RIO asm_did to match or %RIO_ANY_ID to match all asm_dids 1164394b701cSMatt Porter * @from: Previous RIO device found in search, or %NULL for new search 1165394b701cSMatt Porter * 1166394b701cSMatt Porter * Iterates through the list of known RIO devices. If a RIO device is 1167394b701cSMatt Porter * found with a matching @vid, @did, @asm_vid, @asm_did, the reference 1168394b701cSMatt Porter * count to the device is incrememted and a pointer to its device 1169394b701cSMatt Porter * structure is returned. Otherwise, %NULL is returned. A new search 1170394b701cSMatt Porter * is initiated by passing %NULL to the @from argument. Otherwise, if 1171394b701cSMatt Porter * @from is not %NULL, searches continue from next device on the global 1172394b701cSMatt Porter * list. The reference count for @from is always decremented if it is 1173394b701cSMatt Porter * not %NULL. 1174394b701cSMatt Porter */ 1175394b701cSMatt Porter struct rio_dev *rio_get_asm(u16 vid, u16 did, 1176394b701cSMatt Porter u16 asm_vid, u16 asm_did, struct rio_dev *from) 1177394b701cSMatt Porter { 1178394b701cSMatt Porter struct list_head *n; 1179394b701cSMatt Porter struct rio_dev *rdev; 1180394b701cSMatt Porter 1181394b701cSMatt Porter WARN_ON(in_interrupt()); 1182394b701cSMatt Porter spin_lock(&rio_global_list_lock); 1183394b701cSMatt Porter n = from ? from->global_list.next : rio_devices.next; 1184394b701cSMatt Porter 1185394b701cSMatt Porter while (n && (n != &rio_devices)) { 1186394b701cSMatt Porter rdev = rio_dev_g(n); 1187394b701cSMatt Porter if ((vid == RIO_ANY_ID || rdev->vid == vid) && 1188394b701cSMatt Porter (did == RIO_ANY_ID || rdev->did == did) && 1189394b701cSMatt Porter (asm_vid == RIO_ANY_ID || rdev->asm_vid == asm_vid) && 1190394b701cSMatt Porter (asm_did == RIO_ANY_ID || rdev->asm_did == asm_did)) 1191394b701cSMatt Porter goto exit; 1192394b701cSMatt Porter n = n->next; 1193394b701cSMatt Porter } 1194394b701cSMatt Porter rdev = NULL; 1195394b701cSMatt Porter exit: 1196394b701cSMatt Porter rio_dev_put(from); 1197394b701cSMatt Porter rdev = rio_dev_get(rdev); 1198394b701cSMatt Porter spin_unlock(&rio_global_list_lock); 1199394b701cSMatt Porter return rdev; 1200394b701cSMatt Porter } 1201394b701cSMatt Porter 1202394b701cSMatt Porter /** 1203394b701cSMatt Porter * rio_get_device - Begin or continue searching for a RIO device by vid/did 1204394b701cSMatt Porter * @vid: RIO vid to match or %RIO_ANY_ID to match all vids 1205394b701cSMatt Porter * @did: RIO did to match or %RIO_ANY_ID to match all dids 1206394b701cSMatt Porter * @from: Previous RIO device found in search, or %NULL for new search 1207394b701cSMatt Porter * 1208394b701cSMatt Porter * Iterates through the list of known RIO devices. If a RIO device is 1209394b701cSMatt Porter * found with a matching @vid and @did, the reference count to the 1210394b701cSMatt Porter * device is incrememted and a pointer to its device structure is returned. 1211394b701cSMatt Porter * Otherwise, %NULL is returned. A new search is initiated by passing %NULL 1212394b701cSMatt Porter * to the @from argument. Otherwise, if @from is not %NULL, searches 1213394b701cSMatt Porter * continue from next device on the global list. The reference count for 1214394b701cSMatt Porter * @from is always decremented if it is not %NULL. 1215394b701cSMatt Porter */ 1216394b701cSMatt Porter struct rio_dev *rio_get_device(u16 vid, u16 did, struct rio_dev *from) 1217394b701cSMatt Porter { 1218394b701cSMatt Porter return rio_get_asm(vid, did, RIO_ANY_ID, RIO_ANY_ID, from); 1219394b701cSMatt Porter } 1220394b701cSMatt Porter 122107590ff0SAlexandre Bounine /** 122207590ff0SAlexandre Bounine * rio_std_route_add_entry - Add switch route table entry using standard 122307590ff0SAlexandre Bounine * registers defined in RIO specification rev.1.3 122407590ff0SAlexandre Bounine * @mport: Master port to issue transaction 122507590ff0SAlexandre Bounine * @destid: Destination ID of the device 122607590ff0SAlexandre Bounine * @hopcount: Number of switch hops to the device 122707590ff0SAlexandre Bounine * @table: routing table ID (global or port-specific) 122807590ff0SAlexandre Bounine * @route_destid: destID entry in the RT 122907590ff0SAlexandre Bounine * @route_port: destination port for specified destID 123007590ff0SAlexandre Bounine */ 12312ec3ba69SAlexandre Bounine static int 12322ec3ba69SAlexandre Bounine rio_std_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount, 123307590ff0SAlexandre Bounine u16 table, u16 route_destid, u8 route_port) 123407590ff0SAlexandre Bounine { 123507590ff0SAlexandre Bounine if (table == RIO_GLOBAL_TABLE) { 123607590ff0SAlexandre Bounine rio_mport_write_config_32(mport, destid, hopcount, 123707590ff0SAlexandre Bounine RIO_STD_RTE_CONF_DESTID_SEL_CSR, 123807590ff0SAlexandre Bounine (u32)route_destid); 123907590ff0SAlexandre Bounine rio_mport_write_config_32(mport, destid, hopcount, 124007590ff0SAlexandre Bounine RIO_STD_RTE_CONF_PORT_SEL_CSR, 124107590ff0SAlexandre Bounine (u32)route_port); 124207590ff0SAlexandre Bounine } 1243e5cabeb3SAlexandre Bounine 124407590ff0SAlexandre Bounine udelay(10); 124507590ff0SAlexandre Bounine return 0; 124607590ff0SAlexandre Bounine } 124707590ff0SAlexandre Bounine 124807590ff0SAlexandre Bounine /** 124907590ff0SAlexandre Bounine * rio_std_route_get_entry - Read switch route table entry (port number) 1250638c5945SUwe Kleine-König * associated with specified destID using standard registers defined in RIO 125107590ff0SAlexandre Bounine * specification rev.1.3 125207590ff0SAlexandre Bounine * @mport: Master port to issue transaction 125307590ff0SAlexandre Bounine * @destid: Destination ID of the device 125407590ff0SAlexandre Bounine * @hopcount: Number of switch hops to the device 125507590ff0SAlexandre Bounine * @table: routing table ID (global or port-specific) 125607590ff0SAlexandre Bounine * @route_destid: destID entry in the RT 125707590ff0SAlexandre Bounine * @route_port: returned destination port for specified destID 125807590ff0SAlexandre Bounine */ 12592ec3ba69SAlexandre Bounine static int 12602ec3ba69SAlexandre Bounine rio_std_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount, 126107590ff0SAlexandre Bounine u16 table, u16 route_destid, u8 *route_port) 126207590ff0SAlexandre Bounine { 126307590ff0SAlexandre Bounine u32 result; 126407590ff0SAlexandre Bounine 126507590ff0SAlexandre Bounine if (table == RIO_GLOBAL_TABLE) { 126607590ff0SAlexandre Bounine rio_mport_write_config_32(mport, destid, hopcount, 126707590ff0SAlexandre Bounine RIO_STD_RTE_CONF_DESTID_SEL_CSR, route_destid); 126807590ff0SAlexandre Bounine rio_mport_read_config_32(mport, destid, hopcount, 126907590ff0SAlexandre Bounine RIO_STD_RTE_CONF_PORT_SEL_CSR, &result); 127007590ff0SAlexandre Bounine 127107590ff0SAlexandre Bounine *route_port = (u8)result; 127207590ff0SAlexandre Bounine } 127307590ff0SAlexandre Bounine 127407590ff0SAlexandre Bounine return 0; 127507590ff0SAlexandre Bounine } 127607590ff0SAlexandre Bounine 127707590ff0SAlexandre Bounine /** 127807590ff0SAlexandre Bounine * rio_std_route_clr_table - Clear swotch route table using standard registers 127907590ff0SAlexandre Bounine * defined in RIO specification rev.1.3. 128007590ff0SAlexandre Bounine * @mport: Master port to issue transaction 128107590ff0SAlexandre Bounine * @destid: Destination ID of the device 128207590ff0SAlexandre Bounine * @hopcount: Number of switch hops to the device 128307590ff0SAlexandre Bounine * @table: routing table ID (global or port-specific) 128407590ff0SAlexandre Bounine */ 12852ec3ba69SAlexandre Bounine static int 12862ec3ba69SAlexandre Bounine rio_std_route_clr_table(struct rio_mport *mport, u16 destid, u8 hopcount, 128707590ff0SAlexandre Bounine u16 table) 128807590ff0SAlexandre Bounine { 128907590ff0SAlexandre Bounine u32 max_destid = 0xff; 129007590ff0SAlexandre Bounine u32 i, pef, id_inc = 1, ext_cfg = 0; 129107590ff0SAlexandre Bounine u32 port_sel = RIO_INVALID_ROUTE; 129207590ff0SAlexandre Bounine 129307590ff0SAlexandre Bounine if (table == RIO_GLOBAL_TABLE) { 129407590ff0SAlexandre Bounine rio_mport_read_config_32(mport, destid, hopcount, 129507590ff0SAlexandre Bounine RIO_PEF_CAR, &pef); 129607590ff0SAlexandre Bounine 129707590ff0SAlexandre Bounine if (mport->sys_size) { 129807590ff0SAlexandre Bounine rio_mport_read_config_32(mport, destid, hopcount, 129907590ff0SAlexandre Bounine RIO_SWITCH_RT_LIMIT, 130007590ff0SAlexandre Bounine &max_destid); 130107590ff0SAlexandre Bounine max_destid &= RIO_RT_MAX_DESTID; 130207590ff0SAlexandre Bounine } 130307590ff0SAlexandre Bounine 130407590ff0SAlexandre Bounine if (pef & RIO_PEF_EXT_RT) { 130507590ff0SAlexandre Bounine ext_cfg = 0x80000000; 130607590ff0SAlexandre Bounine id_inc = 4; 130707590ff0SAlexandre Bounine port_sel = (RIO_INVALID_ROUTE << 24) | 130807590ff0SAlexandre Bounine (RIO_INVALID_ROUTE << 16) | 130907590ff0SAlexandre Bounine (RIO_INVALID_ROUTE << 8) | 131007590ff0SAlexandre Bounine RIO_INVALID_ROUTE; 131107590ff0SAlexandre Bounine } 131207590ff0SAlexandre Bounine 131307590ff0SAlexandre Bounine for (i = 0; i <= max_destid;) { 131407590ff0SAlexandre Bounine rio_mport_write_config_32(mport, destid, hopcount, 131507590ff0SAlexandre Bounine RIO_STD_RTE_CONF_DESTID_SEL_CSR, 131607590ff0SAlexandre Bounine ext_cfg | i); 131707590ff0SAlexandre Bounine rio_mport_write_config_32(mport, destid, hopcount, 131807590ff0SAlexandre Bounine RIO_STD_RTE_CONF_PORT_SEL_CSR, 131907590ff0SAlexandre Bounine port_sel); 132007590ff0SAlexandre Bounine i += id_inc; 132107590ff0SAlexandre Bounine } 132207590ff0SAlexandre Bounine } 132307590ff0SAlexandre Bounine 132407590ff0SAlexandre Bounine udelay(10); 132507590ff0SAlexandre Bounine return 0; 132607590ff0SAlexandre Bounine } 132707590ff0SAlexandre Bounine 13282ec3ba69SAlexandre Bounine /** 13292ec3ba69SAlexandre Bounine * rio_lock_device - Acquires host device lock for specified device 13302ec3ba69SAlexandre Bounine * @port: Master port to send transaction 13312ec3ba69SAlexandre Bounine * @destid: Destination ID for device/switch 13322ec3ba69SAlexandre Bounine * @hopcount: Hopcount to reach switch 13332ec3ba69SAlexandre Bounine * @wait_ms: Max wait time in msec (0 = no timeout) 13342ec3ba69SAlexandre Bounine * 13352ec3ba69SAlexandre Bounine * Attepts to acquire host device lock for specified device 13362ec3ba69SAlexandre Bounine * Returns 0 if device lock acquired or EINVAL if timeout expires. 13372ec3ba69SAlexandre Bounine */ 13382ec3ba69SAlexandre Bounine int rio_lock_device(struct rio_mport *port, u16 destid, 13392ec3ba69SAlexandre Bounine u8 hopcount, int wait_ms) 13402ec3ba69SAlexandre Bounine { 13412ec3ba69SAlexandre Bounine u32 result; 13422ec3ba69SAlexandre Bounine int tcnt = 0; 13432ec3ba69SAlexandre Bounine 13442ec3ba69SAlexandre Bounine /* Attempt to acquire device lock */ 13452ec3ba69SAlexandre Bounine rio_mport_write_config_32(port, destid, hopcount, 13462ec3ba69SAlexandre Bounine RIO_HOST_DID_LOCK_CSR, port->host_deviceid); 13472ec3ba69SAlexandre Bounine rio_mport_read_config_32(port, destid, hopcount, 13482ec3ba69SAlexandre Bounine RIO_HOST_DID_LOCK_CSR, &result); 13492ec3ba69SAlexandre Bounine 13502ec3ba69SAlexandre Bounine while (result != port->host_deviceid) { 13512ec3ba69SAlexandre Bounine if (wait_ms != 0 && tcnt == wait_ms) { 13522ec3ba69SAlexandre Bounine pr_debug("RIO: timeout when locking device %x:%x\n", 13532ec3ba69SAlexandre Bounine destid, hopcount); 13542ec3ba69SAlexandre Bounine return -EINVAL; 13552ec3ba69SAlexandre Bounine } 13562ec3ba69SAlexandre Bounine 13572ec3ba69SAlexandre Bounine /* Delay a bit */ 13582ec3ba69SAlexandre Bounine mdelay(1); 13592ec3ba69SAlexandre Bounine tcnt++; 13602ec3ba69SAlexandre Bounine /* Try to acquire device lock again */ 13612ec3ba69SAlexandre Bounine rio_mport_write_config_32(port, destid, 13622ec3ba69SAlexandre Bounine hopcount, 13632ec3ba69SAlexandre Bounine RIO_HOST_DID_LOCK_CSR, 13642ec3ba69SAlexandre Bounine port->host_deviceid); 13652ec3ba69SAlexandre Bounine rio_mport_read_config_32(port, destid, 13662ec3ba69SAlexandre Bounine hopcount, 13672ec3ba69SAlexandre Bounine RIO_HOST_DID_LOCK_CSR, &result); 13682ec3ba69SAlexandre Bounine } 13692ec3ba69SAlexandre Bounine 13702ec3ba69SAlexandre Bounine return 0; 13712ec3ba69SAlexandre Bounine } 13722ec3ba69SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_lock_device); 13732ec3ba69SAlexandre Bounine 13742ec3ba69SAlexandre Bounine /** 13752ec3ba69SAlexandre Bounine * rio_unlock_device - Releases host device lock for specified device 13762ec3ba69SAlexandre Bounine * @port: Master port to send transaction 13772ec3ba69SAlexandre Bounine * @destid: Destination ID for device/switch 13782ec3ba69SAlexandre Bounine * @hopcount: Hopcount to reach switch 13792ec3ba69SAlexandre Bounine * 13802ec3ba69SAlexandre Bounine * Returns 0 if device lock released or EINVAL if fails. 13812ec3ba69SAlexandre Bounine */ 13822ec3ba69SAlexandre Bounine int rio_unlock_device(struct rio_mport *port, u16 destid, u8 hopcount) 13832ec3ba69SAlexandre Bounine { 13842ec3ba69SAlexandre Bounine u32 result; 13852ec3ba69SAlexandre Bounine 13862ec3ba69SAlexandre Bounine /* Release device lock */ 13872ec3ba69SAlexandre Bounine rio_mport_write_config_32(port, destid, 13882ec3ba69SAlexandre Bounine hopcount, 13892ec3ba69SAlexandre Bounine RIO_HOST_DID_LOCK_CSR, 13902ec3ba69SAlexandre Bounine port->host_deviceid); 13912ec3ba69SAlexandre Bounine rio_mport_read_config_32(port, destid, hopcount, 13922ec3ba69SAlexandre Bounine RIO_HOST_DID_LOCK_CSR, &result); 13932ec3ba69SAlexandre Bounine if ((result & 0xffff) != 0xffff) { 13942ec3ba69SAlexandre Bounine pr_debug("RIO: badness when releasing device lock %x:%x\n", 13952ec3ba69SAlexandre Bounine destid, hopcount); 13962ec3ba69SAlexandre Bounine return -EINVAL; 13972ec3ba69SAlexandre Bounine } 13982ec3ba69SAlexandre Bounine 13992ec3ba69SAlexandre Bounine return 0; 14002ec3ba69SAlexandre Bounine } 14012ec3ba69SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_unlock_device); 14022ec3ba69SAlexandre Bounine 14032ec3ba69SAlexandre Bounine /** 14042ec3ba69SAlexandre Bounine * rio_route_add_entry- Add a route entry to a switch routing table 14052ec3ba69SAlexandre Bounine * @rdev: RIO device 14062ec3ba69SAlexandre Bounine * @table: Routing table ID 14072ec3ba69SAlexandre Bounine * @route_destid: Destination ID to be routed 14082ec3ba69SAlexandre Bounine * @route_port: Port number to be routed 14092ec3ba69SAlexandre Bounine * @lock: apply a hardware lock on switch device flag (1=lock, 0=no_lock) 14102ec3ba69SAlexandre Bounine * 14112ec3ba69SAlexandre Bounine * If available calls the switch specific add_entry() method to add a route 14122ec3ba69SAlexandre Bounine * entry into a switch routing table. Otherwise uses standard RT update method 14132ec3ba69SAlexandre Bounine * as defined by RapidIO specification. A specific routing table can be selected 14142ec3ba69SAlexandre Bounine * using the @table argument if a switch has per port routing tables or 14152ec3ba69SAlexandre Bounine * the standard (or global) table may be used by passing 14162ec3ba69SAlexandre Bounine * %RIO_GLOBAL_TABLE in @table. 14172ec3ba69SAlexandre Bounine * 14182ec3ba69SAlexandre Bounine * Returns %0 on success or %-EINVAL on failure. 14192ec3ba69SAlexandre Bounine */ 14202ec3ba69SAlexandre Bounine int rio_route_add_entry(struct rio_dev *rdev, 14212ec3ba69SAlexandre Bounine u16 table, u16 route_destid, u8 route_port, int lock) 14222ec3ba69SAlexandre Bounine { 14232ec3ba69SAlexandre Bounine int rc = -EINVAL; 14242ec3ba69SAlexandre Bounine struct rio_switch_ops *ops = rdev->rswitch->ops; 14252ec3ba69SAlexandre Bounine 14262ec3ba69SAlexandre Bounine if (lock) { 14272ec3ba69SAlexandre Bounine rc = rio_lock_device(rdev->net->hport, rdev->destid, 14282ec3ba69SAlexandre Bounine rdev->hopcount, 1000); 14292ec3ba69SAlexandre Bounine if (rc) 14302ec3ba69SAlexandre Bounine return rc; 14312ec3ba69SAlexandre Bounine } 14322ec3ba69SAlexandre Bounine 14332ec3ba69SAlexandre Bounine spin_lock(&rdev->rswitch->lock); 14342ec3ba69SAlexandre Bounine 14352ec3ba69SAlexandre Bounine if (ops == NULL || ops->add_entry == NULL) { 14362ec3ba69SAlexandre Bounine rc = rio_std_route_add_entry(rdev->net->hport, rdev->destid, 14372ec3ba69SAlexandre Bounine rdev->hopcount, table, 14382ec3ba69SAlexandre Bounine route_destid, route_port); 14392ec3ba69SAlexandre Bounine } else if (try_module_get(ops->owner)) { 14402ec3ba69SAlexandre Bounine rc = ops->add_entry(rdev->net->hport, rdev->destid, 14412ec3ba69SAlexandre Bounine rdev->hopcount, table, route_destid, 14422ec3ba69SAlexandre Bounine route_port); 14432ec3ba69SAlexandre Bounine module_put(ops->owner); 14442ec3ba69SAlexandre Bounine } 14452ec3ba69SAlexandre Bounine 14462ec3ba69SAlexandre Bounine spin_unlock(&rdev->rswitch->lock); 14472ec3ba69SAlexandre Bounine 14482ec3ba69SAlexandre Bounine if (lock) 14492ec3ba69SAlexandre Bounine rio_unlock_device(rdev->net->hport, rdev->destid, 14502ec3ba69SAlexandre Bounine rdev->hopcount); 14512ec3ba69SAlexandre Bounine 14522ec3ba69SAlexandre Bounine return rc; 14532ec3ba69SAlexandre Bounine } 14542ec3ba69SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_route_add_entry); 14552ec3ba69SAlexandre Bounine 14562ec3ba69SAlexandre Bounine /** 14572ec3ba69SAlexandre Bounine * rio_route_get_entry- Read an entry from a switch routing table 14582ec3ba69SAlexandre Bounine * @rdev: RIO device 14592ec3ba69SAlexandre Bounine * @table: Routing table ID 14602ec3ba69SAlexandre Bounine * @route_destid: Destination ID to be routed 14612ec3ba69SAlexandre Bounine * @route_port: Pointer to read port number into 14622ec3ba69SAlexandre Bounine * @lock: apply a hardware lock on switch device flag (1=lock, 0=no_lock) 14632ec3ba69SAlexandre Bounine * 14642ec3ba69SAlexandre Bounine * If available calls the switch specific get_entry() method to fetch a route 14652ec3ba69SAlexandre Bounine * entry from a switch routing table. Otherwise uses standard RT read method 14662ec3ba69SAlexandre Bounine * as defined by RapidIO specification. A specific routing table can be selected 14672ec3ba69SAlexandre Bounine * using the @table argument if a switch has per port routing tables or 14682ec3ba69SAlexandre Bounine * the standard (or global) table may be used by passing 14692ec3ba69SAlexandre Bounine * %RIO_GLOBAL_TABLE in @table. 14702ec3ba69SAlexandre Bounine * 14712ec3ba69SAlexandre Bounine * Returns %0 on success or %-EINVAL on failure. 14722ec3ba69SAlexandre Bounine */ 14732ec3ba69SAlexandre Bounine int rio_route_get_entry(struct rio_dev *rdev, u16 table, 14742ec3ba69SAlexandre Bounine u16 route_destid, u8 *route_port, int lock) 14752ec3ba69SAlexandre Bounine { 14762ec3ba69SAlexandre Bounine int rc = -EINVAL; 14772ec3ba69SAlexandre Bounine struct rio_switch_ops *ops = rdev->rswitch->ops; 14782ec3ba69SAlexandre Bounine 14792ec3ba69SAlexandre Bounine if (lock) { 14802ec3ba69SAlexandre Bounine rc = rio_lock_device(rdev->net->hport, rdev->destid, 14812ec3ba69SAlexandre Bounine rdev->hopcount, 1000); 14822ec3ba69SAlexandre Bounine if (rc) 14832ec3ba69SAlexandre Bounine return rc; 14842ec3ba69SAlexandre Bounine } 14852ec3ba69SAlexandre Bounine 14862ec3ba69SAlexandre Bounine spin_lock(&rdev->rswitch->lock); 14872ec3ba69SAlexandre Bounine 14882ec3ba69SAlexandre Bounine if (ops == NULL || ops->get_entry == NULL) { 14892ec3ba69SAlexandre Bounine rc = rio_std_route_get_entry(rdev->net->hport, rdev->destid, 14902ec3ba69SAlexandre Bounine rdev->hopcount, table, 14912ec3ba69SAlexandre Bounine route_destid, route_port); 14922ec3ba69SAlexandre Bounine } else if (try_module_get(ops->owner)) { 14932ec3ba69SAlexandre Bounine rc = ops->get_entry(rdev->net->hport, rdev->destid, 14942ec3ba69SAlexandre Bounine rdev->hopcount, table, route_destid, 14952ec3ba69SAlexandre Bounine route_port); 14962ec3ba69SAlexandre Bounine module_put(ops->owner); 14972ec3ba69SAlexandre Bounine } 14982ec3ba69SAlexandre Bounine 14992ec3ba69SAlexandre Bounine spin_unlock(&rdev->rswitch->lock); 15002ec3ba69SAlexandre Bounine 15012ec3ba69SAlexandre Bounine if (lock) 15022ec3ba69SAlexandre Bounine rio_unlock_device(rdev->net->hport, rdev->destid, 15032ec3ba69SAlexandre Bounine rdev->hopcount); 15042ec3ba69SAlexandre Bounine return rc; 15052ec3ba69SAlexandre Bounine } 15062ec3ba69SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_route_get_entry); 15072ec3ba69SAlexandre Bounine 15082ec3ba69SAlexandre Bounine /** 15092ec3ba69SAlexandre Bounine * rio_route_clr_table - Clear a switch routing table 15102ec3ba69SAlexandre Bounine * @rdev: RIO device 15112ec3ba69SAlexandre Bounine * @table: Routing table ID 15122ec3ba69SAlexandre Bounine * @lock: apply a hardware lock on switch device flag (1=lock, 0=no_lock) 15132ec3ba69SAlexandre Bounine * 15142ec3ba69SAlexandre Bounine * If available calls the switch specific clr_table() method to clear a switch 15152ec3ba69SAlexandre Bounine * routing table. Otherwise uses standard RT write method as defined by RapidIO 15162ec3ba69SAlexandre Bounine * specification. A specific routing table can be selected using the @table 15172ec3ba69SAlexandre Bounine * argument if a switch has per port routing tables or the standard (or global) 15182ec3ba69SAlexandre Bounine * table may be used by passing %RIO_GLOBAL_TABLE in @table. 15192ec3ba69SAlexandre Bounine * 15202ec3ba69SAlexandre Bounine * Returns %0 on success or %-EINVAL on failure. 15212ec3ba69SAlexandre Bounine */ 15222ec3ba69SAlexandre Bounine int rio_route_clr_table(struct rio_dev *rdev, u16 table, int lock) 15232ec3ba69SAlexandre Bounine { 15242ec3ba69SAlexandre Bounine int rc = -EINVAL; 15252ec3ba69SAlexandre Bounine struct rio_switch_ops *ops = rdev->rswitch->ops; 15262ec3ba69SAlexandre Bounine 15272ec3ba69SAlexandre Bounine if (lock) { 15282ec3ba69SAlexandre Bounine rc = rio_lock_device(rdev->net->hport, rdev->destid, 15292ec3ba69SAlexandre Bounine rdev->hopcount, 1000); 15302ec3ba69SAlexandre Bounine if (rc) 15312ec3ba69SAlexandre Bounine return rc; 15322ec3ba69SAlexandre Bounine } 15332ec3ba69SAlexandre Bounine 15342ec3ba69SAlexandre Bounine spin_lock(&rdev->rswitch->lock); 15352ec3ba69SAlexandre Bounine 15362ec3ba69SAlexandre Bounine if (ops == NULL || ops->clr_table == NULL) { 15372ec3ba69SAlexandre Bounine rc = rio_std_route_clr_table(rdev->net->hport, rdev->destid, 15382ec3ba69SAlexandre Bounine rdev->hopcount, table); 15392ec3ba69SAlexandre Bounine } else if (try_module_get(ops->owner)) { 15402ec3ba69SAlexandre Bounine rc = ops->clr_table(rdev->net->hport, rdev->destid, 15412ec3ba69SAlexandre Bounine rdev->hopcount, table); 15422ec3ba69SAlexandre Bounine 15432ec3ba69SAlexandre Bounine module_put(ops->owner); 15442ec3ba69SAlexandre Bounine } 15452ec3ba69SAlexandre Bounine 15462ec3ba69SAlexandre Bounine spin_unlock(&rdev->rswitch->lock); 15472ec3ba69SAlexandre Bounine 15482ec3ba69SAlexandre Bounine if (lock) 15492ec3ba69SAlexandre Bounine rio_unlock_device(rdev->net->hport, rdev->destid, 15502ec3ba69SAlexandre Bounine rdev->hopcount); 15512ec3ba69SAlexandre Bounine 15522ec3ba69SAlexandre Bounine return rc; 15532ec3ba69SAlexandre Bounine } 15542ec3ba69SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_route_clr_table); 15552ec3ba69SAlexandre Bounine 1556e42d98ebSAlexandre Bounine #ifdef CONFIG_RAPIDIO_DMA_ENGINE 1557e42d98ebSAlexandre Bounine 1558e42d98ebSAlexandre Bounine static bool rio_chan_filter(struct dma_chan *chan, void *arg) 1559e42d98ebSAlexandre Bounine { 15604aff1ce7SAlexandre Bounine struct rio_mport *mport = arg; 1561e42d98ebSAlexandre Bounine 1562e42d98ebSAlexandre Bounine /* Check that DMA device belongs to the right MPORT */ 15634aff1ce7SAlexandre Bounine return mport == container_of(chan->device, struct rio_mport, dma); 1564e42d98ebSAlexandre Bounine } 1565e42d98ebSAlexandre Bounine 1566e42d98ebSAlexandre Bounine /** 15674aff1ce7SAlexandre Bounine * rio_request_mport_dma - request RapidIO capable DMA channel associated 15684aff1ce7SAlexandre Bounine * with specified local RapidIO mport device. 15694aff1ce7SAlexandre Bounine * @mport: RIO mport to perform DMA data transfers 15704aff1ce7SAlexandre Bounine * 15714aff1ce7SAlexandre Bounine * Returns pointer to allocated DMA channel or NULL if failed. 15724aff1ce7SAlexandre Bounine */ 15734aff1ce7SAlexandre Bounine struct dma_chan *rio_request_mport_dma(struct rio_mport *mport) 15744aff1ce7SAlexandre Bounine { 15754aff1ce7SAlexandre Bounine dma_cap_mask_t mask; 15764aff1ce7SAlexandre Bounine 15774aff1ce7SAlexandre Bounine dma_cap_zero(mask); 15784aff1ce7SAlexandre Bounine dma_cap_set(DMA_SLAVE, mask); 15794aff1ce7SAlexandre Bounine return dma_request_channel(mask, rio_chan_filter, mport); 15804aff1ce7SAlexandre Bounine } 15814aff1ce7SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_request_mport_dma); 15824aff1ce7SAlexandre Bounine 15834aff1ce7SAlexandre Bounine /** 1584e42d98ebSAlexandre Bounine * rio_request_dma - request RapidIO capable DMA channel that supports 1585e42d98ebSAlexandre Bounine * specified target RapidIO device. 15864aff1ce7SAlexandre Bounine * @rdev: RIO device associated with DMA transfer 1587e42d98ebSAlexandre Bounine * 1588e42d98ebSAlexandre Bounine * Returns pointer to allocated DMA channel or NULL if failed. 1589e42d98ebSAlexandre Bounine */ 1590e42d98ebSAlexandre Bounine struct dma_chan *rio_request_dma(struct rio_dev *rdev) 1591e42d98ebSAlexandre Bounine { 15924aff1ce7SAlexandre Bounine return rio_request_mport_dma(rdev->net->hport); 1593e42d98ebSAlexandre Bounine } 1594e42d98ebSAlexandre Bounine EXPORT_SYMBOL_GPL(rio_request_dma); 1595e42d98ebSAlexandre Bounine 1596e42d98ebSAlexandre Bounine /** 1597e42d98ebSAlexandre Bounine * rio_release_dma - release specified DMA channel 1598e42d98ebSAlexandre Bounine * @dchan: DMA channel to release 1599e42d98ebSAlexandre Bounine */ 1600e42d98ebSAlexandre Bounine void rio_release_dma(struct dma_chan *dchan) 1601e42d98ebSAlexandre Bounine { 1602e42d98ebSAlexandre Bounine dma_release_channel(dchan); 1603e42d98ebSAlexandre Bounine } 1604e42d98ebSAlexandre Bounine EXPORT_SYMBOL_GPL(rio_release_dma); 1605e42d98ebSAlexandre Bounine 1606e42d98ebSAlexandre Bounine /** 16074aff1ce7SAlexandre Bounine * rio_dma_prep_xfer - RapidIO specific wrapper 16084aff1ce7SAlexandre Bounine * for device_prep_slave_sg callback defined by DMAENGINE. 16094aff1ce7SAlexandre Bounine * @dchan: DMA channel to configure 16104aff1ce7SAlexandre Bounine * @destid: target RapidIO device destination ID 16114aff1ce7SAlexandre Bounine * @data: RIO specific data descriptor 16124aff1ce7SAlexandre Bounine * @direction: DMA data transfer direction (TO or FROM the device) 16134aff1ce7SAlexandre Bounine * @flags: dmaengine defined flags 16144aff1ce7SAlexandre Bounine * 16154aff1ce7SAlexandre Bounine * Initializes RapidIO capable DMA channel for the specified data transfer. 16164aff1ce7SAlexandre Bounine * Uses DMA channel private extension to pass information related to remote 16174aff1ce7SAlexandre Bounine * target RIO device. 16184aff1ce7SAlexandre Bounine * Returns pointer to DMA transaction descriptor or NULL if failed. 16194aff1ce7SAlexandre Bounine */ 16204aff1ce7SAlexandre Bounine struct dma_async_tx_descriptor *rio_dma_prep_xfer(struct dma_chan *dchan, 16214aff1ce7SAlexandre Bounine u16 destid, struct rio_dma_data *data, 16224aff1ce7SAlexandre Bounine enum dma_transfer_direction direction, unsigned long flags) 16234aff1ce7SAlexandre Bounine { 16244aff1ce7SAlexandre Bounine struct rio_dma_ext rio_ext; 16254aff1ce7SAlexandre Bounine 16264aff1ce7SAlexandre Bounine if (dchan->device->device_prep_slave_sg == NULL) { 16274aff1ce7SAlexandre Bounine pr_err("%s: prep_rio_sg == NULL\n", __func__); 16284aff1ce7SAlexandre Bounine return NULL; 16294aff1ce7SAlexandre Bounine } 16304aff1ce7SAlexandre Bounine 16314aff1ce7SAlexandre Bounine rio_ext.destid = destid; 16324aff1ce7SAlexandre Bounine rio_ext.rio_addr_u = data->rio_addr_u; 16334aff1ce7SAlexandre Bounine rio_ext.rio_addr = data->rio_addr; 16344aff1ce7SAlexandre Bounine rio_ext.wr_type = data->wr_type; 16354aff1ce7SAlexandre Bounine 16364aff1ce7SAlexandre Bounine return dmaengine_prep_rio_sg(dchan, data->sg, data->sg_len, 16374aff1ce7SAlexandre Bounine direction, flags, &rio_ext); 16384aff1ce7SAlexandre Bounine } 16394aff1ce7SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_dma_prep_xfer); 16404aff1ce7SAlexandre Bounine 16414aff1ce7SAlexandre Bounine /** 1642e42d98ebSAlexandre Bounine * rio_dma_prep_slave_sg - RapidIO specific wrapper 1643e42d98ebSAlexandre Bounine * for device_prep_slave_sg callback defined by DMAENGINE. 1644e42d98ebSAlexandre Bounine * @rdev: RIO device control structure 1645e42d98ebSAlexandre Bounine * @dchan: DMA channel to configure 1646e42d98ebSAlexandre Bounine * @data: RIO specific data descriptor 1647e42d98ebSAlexandre Bounine * @direction: DMA data transfer direction (TO or FROM the device) 1648e42d98ebSAlexandre Bounine * @flags: dmaengine defined flags 1649e42d98ebSAlexandre Bounine * 1650e42d98ebSAlexandre Bounine * Initializes RapidIO capable DMA channel for the specified data transfer. 1651e42d98ebSAlexandre Bounine * Uses DMA channel private extension to pass information related to remote 1652e42d98ebSAlexandre Bounine * target RIO device. 1653e42d98ebSAlexandre Bounine * Returns pointer to DMA transaction descriptor or NULL if failed. 1654e42d98ebSAlexandre Bounine */ 1655e42d98ebSAlexandre Bounine struct dma_async_tx_descriptor *rio_dma_prep_slave_sg(struct rio_dev *rdev, 1656e42d98ebSAlexandre Bounine struct dma_chan *dchan, struct rio_dma_data *data, 1657e42d98ebSAlexandre Bounine enum dma_transfer_direction direction, unsigned long flags) 1658e42d98ebSAlexandre Bounine { 16594aff1ce7SAlexandre Bounine return rio_dma_prep_xfer(dchan, rdev->destid, data, direction, flags); 1660e42d98ebSAlexandre Bounine } 1661e42d98ebSAlexandre Bounine EXPORT_SYMBOL_GPL(rio_dma_prep_slave_sg); 1662e42d98ebSAlexandre Bounine 1663e42d98ebSAlexandre Bounine #endif /* CONFIG_RAPIDIO_DMA_ENGINE */ 1664e42d98ebSAlexandre Bounine 1665a11650e1SAlexandre Bounine /** 1666bc8fcfeaSAlexandre Bounine * rio_find_mport - find RIO mport by its ID 1667bc8fcfeaSAlexandre Bounine * @mport_id: number (ID) of mport device 1668bc8fcfeaSAlexandre Bounine * 1669bc8fcfeaSAlexandre Bounine * Given a RIO mport number, the desired mport is located 1670bc8fcfeaSAlexandre Bounine * in the global list of mports. If the mport is found, a pointer to its 1671bc8fcfeaSAlexandre Bounine * data structure is returned. If no mport is found, %NULL is returned. 1672bc8fcfeaSAlexandre Bounine */ 1673bc8fcfeaSAlexandre Bounine struct rio_mport *rio_find_mport(int mport_id) 1674bc8fcfeaSAlexandre Bounine { 1675bc8fcfeaSAlexandre Bounine struct rio_mport *port; 1676bc8fcfeaSAlexandre Bounine 1677bc8fcfeaSAlexandre Bounine mutex_lock(&rio_mport_list_lock); 1678bc8fcfeaSAlexandre Bounine list_for_each_entry(port, &rio_mports, node) { 1679bc8fcfeaSAlexandre Bounine if (port->id == mport_id) 1680bc8fcfeaSAlexandre Bounine goto found; 1681bc8fcfeaSAlexandre Bounine } 1682bc8fcfeaSAlexandre Bounine port = NULL; 1683bc8fcfeaSAlexandre Bounine found: 1684bc8fcfeaSAlexandre Bounine mutex_unlock(&rio_mport_list_lock); 1685bc8fcfeaSAlexandre Bounine 1686bc8fcfeaSAlexandre Bounine return port; 1687bc8fcfeaSAlexandre Bounine } 1688bc8fcfeaSAlexandre Bounine 1689bc8fcfeaSAlexandre Bounine /** 1690a11650e1SAlexandre Bounine * rio_register_scan - enumeration/discovery method registration interface 1691a11650e1SAlexandre Bounine * @mport_id: mport device ID for which fabric scan routine has to be set 1692a11650e1SAlexandre Bounine * (RIO_MPORT_ANY = set for all available mports) 16939edbc30bSAlexandre Bounine * @scan_ops: enumeration/discovery operations structure 1694a11650e1SAlexandre Bounine * 16959edbc30bSAlexandre Bounine * Registers enumeration/discovery operations with RapidIO subsystem and 16969edbc30bSAlexandre Bounine * attaches it to the specified mport device (or all available mports 16979edbc30bSAlexandre Bounine * if RIO_MPORT_ANY is specified). 16989edbc30bSAlexandre Bounine * 1699a11650e1SAlexandre Bounine * Returns error if the mport already has an enumerator attached to it. 17009edbc30bSAlexandre Bounine * In case of RIO_MPORT_ANY skips mports with valid scan routines (no error). 1701a11650e1SAlexandre Bounine */ 1702a11650e1SAlexandre Bounine int rio_register_scan(int mport_id, struct rio_scan *scan_ops) 1703a11650e1SAlexandre Bounine { 1704a11650e1SAlexandre Bounine struct rio_mport *port; 17059edbc30bSAlexandre Bounine struct rio_scan_node *scan; 17069edbc30bSAlexandre Bounine int rc = 0; 17079edbc30bSAlexandre Bounine 17089edbc30bSAlexandre Bounine pr_debug("RIO: %s for mport_id=%d\n", __func__, mport_id); 17099edbc30bSAlexandre Bounine 17109edbc30bSAlexandre Bounine if ((mport_id != RIO_MPORT_ANY && mport_id >= RIO_MAX_MPORTS) || 17119edbc30bSAlexandre Bounine !scan_ops) 17129edbc30bSAlexandre Bounine return -EINVAL; 1713a11650e1SAlexandre Bounine 1714a11650e1SAlexandre Bounine mutex_lock(&rio_mport_list_lock); 17159edbc30bSAlexandre Bounine 17169edbc30bSAlexandre Bounine /* 17179edbc30bSAlexandre Bounine * Check if there is another enumerator already registered for 17189edbc30bSAlexandre Bounine * the same mport ID (including RIO_MPORT_ANY). Multiple enumerators 17199edbc30bSAlexandre Bounine * for the same mport ID are not supported. 17209edbc30bSAlexandre Bounine */ 17219edbc30bSAlexandre Bounine list_for_each_entry(scan, &rio_scans, node) { 17229edbc30bSAlexandre Bounine if (scan->mport_id == mport_id) { 17239edbc30bSAlexandre Bounine rc = -EBUSY; 17249edbc30bSAlexandre Bounine goto err_out; 17259edbc30bSAlexandre Bounine } 17269edbc30bSAlexandre Bounine } 17279edbc30bSAlexandre Bounine 17289edbc30bSAlexandre Bounine /* 17299edbc30bSAlexandre Bounine * Allocate and initialize new scan registration node. 17309edbc30bSAlexandre Bounine */ 17319edbc30bSAlexandre Bounine scan = kzalloc(sizeof(*scan), GFP_KERNEL); 17329edbc30bSAlexandre Bounine if (!scan) { 17339edbc30bSAlexandre Bounine rc = -ENOMEM; 17349edbc30bSAlexandre Bounine goto err_out; 17359edbc30bSAlexandre Bounine } 17369edbc30bSAlexandre Bounine 17379edbc30bSAlexandre Bounine scan->mport_id = mport_id; 17389edbc30bSAlexandre Bounine scan->ops = scan_ops; 17399edbc30bSAlexandre Bounine 17409edbc30bSAlexandre Bounine /* 17419edbc30bSAlexandre Bounine * Traverse the list of registered mports to attach this new scan. 17429edbc30bSAlexandre Bounine * 17439edbc30bSAlexandre Bounine * The new scan with matching mport ID overrides any previously attached 17449edbc30bSAlexandre Bounine * scan assuming that old scan (if any) is the default one (based on the 17459edbc30bSAlexandre Bounine * enumerator registration check above). 17469edbc30bSAlexandre Bounine * If the new scan is the global one, it will be attached only to mports 17479edbc30bSAlexandre Bounine * that do not have their own individual operations already attached. 17489edbc30bSAlexandre Bounine */ 1749a11650e1SAlexandre Bounine list_for_each_entry(port, &rio_mports, node) { 17509edbc30bSAlexandre Bounine if (port->id == mport_id) { 1751a11650e1SAlexandre Bounine port->nscan = scan_ops; 1752a11650e1SAlexandre Bounine break; 17539edbc30bSAlexandre Bounine } else if (mport_id == RIO_MPORT_ANY && !port->nscan) 17549edbc30bSAlexandre Bounine port->nscan = scan_ops; 1755a11650e1SAlexandre Bounine } 17569edbc30bSAlexandre Bounine 17579edbc30bSAlexandre Bounine list_add_tail(&scan->node, &rio_scans); 17589edbc30bSAlexandre Bounine 17599edbc30bSAlexandre Bounine err_out: 1760a11650e1SAlexandre Bounine mutex_unlock(&rio_mport_list_lock); 1761a11650e1SAlexandre Bounine 1762a11650e1SAlexandre Bounine return rc; 1763a11650e1SAlexandre Bounine } 1764a11650e1SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_register_scan); 1765a11650e1SAlexandre Bounine 1766a11650e1SAlexandre Bounine /** 1767a11650e1SAlexandre Bounine * rio_unregister_scan - removes enumeration/discovery method from mport 1768a11650e1SAlexandre Bounine * @mport_id: mport device ID for which fabric scan routine has to be 17699edbc30bSAlexandre Bounine * unregistered (RIO_MPORT_ANY = apply to all mports that use 17709edbc30bSAlexandre Bounine * the specified scan_ops) 17719edbc30bSAlexandre Bounine * @scan_ops: enumeration/discovery operations structure 1772a11650e1SAlexandre Bounine * 1773a11650e1SAlexandre Bounine * Removes enumeration or discovery method assigned to the specified mport 17749edbc30bSAlexandre Bounine * device. If RIO_MPORT_ANY is specified, removes the specified operations from 17759edbc30bSAlexandre Bounine * all mports that have them attached. 1776a11650e1SAlexandre Bounine */ 17779edbc30bSAlexandre Bounine int rio_unregister_scan(int mport_id, struct rio_scan *scan_ops) 1778a11650e1SAlexandre Bounine { 1779a11650e1SAlexandre Bounine struct rio_mport *port; 17809edbc30bSAlexandre Bounine struct rio_scan_node *scan; 17819edbc30bSAlexandre Bounine 17829edbc30bSAlexandre Bounine pr_debug("RIO: %s for mport_id=%d\n", __func__, mport_id); 17839edbc30bSAlexandre Bounine 17849edbc30bSAlexandre Bounine if (mport_id != RIO_MPORT_ANY && mport_id >= RIO_MAX_MPORTS) 17859edbc30bSAlexandre Bounine return -EINVAL; 1786a11650e1SAlexandre Bounine 1787a11650e1SAlexandre Bounine mutex_lock(&rio_mport_list_lock); 17889edbc30bSAlexandre Bounine 17899edbc30bSAlexandre Bounine list_for_each_entry(port, &rio_mports, node) 17909edbc30bSAlexandre Bounine if (port->id == mport_id || 17919edbc30bSAlexandre Bounine (mport_id == RIO_MPORT_ANY && port->nscan == scan_ops)) 1792a11650e1SAlexandre Bounine port->nscan = NULL; 17939edbc30bSAlexandre Bounine 1794f93f3c4eSDan Carpenter list_for_each_entry(scan, &rio_scans, node) { 17959edbc30bSAlexandre Bounine if (scan->mport_id == mport_id) { 17969edbc30bSAlexandre Bounine list_del(&scan->node); 17979edbc30bSAlexandre Bounine kfree(scan); 1798f93f3c4eSDan Carpenter break; 1799f93f3c4eSDan Carpenter } 1800a11650e1SAlexandre Bounine } 18019edbc30bSAlexandre Bounine 1802a11650e1SAlexandre Bounine mutex_unlock(&rio_mport_list_lock); 1803a11650e1SAlexandre Bounine 1804a11650e1SAlexandre Bounine return 0; 1805a11650e1SAlexandre Bounine } 1806a11650e1SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_unregister_scan); 1807a11650e1SAlexandre Bounine 18089edbc30bSAlexandre Bounine /** 18099edbc30bSAlexandre Bounine * rio_mport_scan - execute enumeration/discovery on the specified mport 18109edbc30bSAlexandre Bounine * @mport_id: number (ID) of mport device 18119edbc30bSAlexandre Bounine */ 18129edbc30bSAlexandre Bounine int rio_mport_scan(int mport_id) 18139edbc30bSAlexandre Bounine { 18149edbc30bSAlexandre Bounine struct rio_mport *port = NULL; 18159edbc30bSAlexandre Bounine int rc; 18169edbc30bSAlexandre Bounine 18179edbc30bSAlexandre Bounine mutex_lock(&rio_mport_list_lock); 18189edbc30bSAlexandre Bounine list_for_each_entry(port, &rio_mports, node) { 18199edbc30bSAlexandre Bounine if (port->id == mport_id) 18209edbc30bSAlexandre Bounine goto found; 18219edbc30bSAlexandre Bounine } 18229edbc30bSAlexandre Bounine mutex_unlock(&rio_mport_list_lock); 18239edbc30bSAlexandre Bounine return -ENODEV; 18249edbc30bSAlexandre Bounine found: 18259edbc30bSAlexandre Bounine if (!port->nscan) { 18269edbc30bSAlexandre Bounine mutex_unlock(&rio_mport_list_lock); 18279edbc30bSAlexandre Bounine return -EINVAL; 18289edbc30bSAlexandre Bounine } 18299edbc30bSAlexandre Bounine 18309edbc30bSAlexandre Bounine if (!try_module_get(port->nscan->owner)) { 18319edbc30bSAlexandre Bounine mutex_unlock(&rio_mport_list_lock); 18329edbc30bSAlexandre Bounine return -ENODEV; 18339edbc30bSAlexandre Bounine } 18349edbc30bSAlexandre Bounine 18359edbc30bSAlexandre Bounine mutex_unlock(&rio_mport_list_lock); 18369edbc30bSAlexandre Bounine 18379edbc30bSAlexandre Bounine if (port->host_deviceid >= 0) 18389edbc30bSAlexandre Bounine rc = port->nscan->enumerate(port, 0); 18399edbc30bSAlexandre Bounine else 18409edbc30bSAlexandre Bounine rc = port->nscan->discover(port, RIO_SCAN_ENUM_NO_WAIT); 18419edbc30bSAlexandre Bounine 18429edbc30bSAlexandre Bounine module_put(port->nscan->owner); 18439edbc30bSAlexandre Bounine return rc; 18449edbc30bSAlexandre Bounine } 18459edbc30bSAlexandre Bounine 1846394b701cSMatt Porter static void rio_fixup_device(struct rio_dev *dev) 1847394b701cSMatt Porter { 1848394b701cSMatt Porter } 1849394b701cSMatt Porter 1850305c891eSBill Pemberton static int rio_init(void) 1851394b701cSMatt Porter { 1852394b701cSMatt Porter struct rio_dev *dev = NULL; 1853394b701cSMatt Porter 1854394b701cSMatt Porter while ((dev = rio_get_device(RIO_ANY_ID, RIO_ANY_ID, dev)) != NULL) { 1855394b701cSMatt Porter rio_fixup_device(dev); 1856394b701cSMatt Porter } 1857394b701cSMatt Porter return 0; 1858394b701cSMatt Porter } 1859394b701cSMatt Porter 1860005842efSAlexandre Bounine static struct workqueue_struct *rio_wq; 1861005842efSAlexandre Bounine 1862005842efSAlexandre Bounine struct rio_disc_work { 1863005842efSAlexandre Bounine struct work_struct work; 1864005842efSAlexandre Bounine struct rio_mport *mport; 1865005842efSAlexandre Bounine }; 1866005842efSAlexandre Bounine 1867305c891eSBill Pemberton static void disc_work_handler(struct work_struct *_work) 1868005842efSAlexandre Bounine { 1869005842efSAlexandre Bounine struct rio_disc_work *work; 1870005842efSAlexandre Bounine 1871005842efSAlexandre Bounine work = container_of(_work, struct rio_disc_work, work); 1872005842efSAlexandre Bounine pr_debug("RIO: discovery work for mport %d %s\n", 1873005842efSAlexandre Bounine work->mport->id, work->mport->name); 18749edbc30bSAlexandre Bounine if (try_module_get(work->mport->nscan->owner)) { 1875bc8fcfeaSAlexandre Bounine work->mport->nscan->discover(work->mport, 0); 18769edbc30bSAlexandre Bounine module_put(work->mport->nscan->owner); 18779edbc30bSAlexandre Bounine } 1878005842efSAlexandre Bounine } 1879005842efSAlexandre Bounine 1880305c891eSBill Pemberton int rio_init_mports(void) 1881394b701cSMatt Porter { 1882394b701cSMatt Porter struct rio_mport *port; 1883005842efSAlexandre Bounine struct rio_disc_work *work; 18842574740dSAlexandre Bounine int n = 0; 1885394b701cSMatt Porter 18862574740dSAlexandre Bounine if (!next_portid) 18872574740dSAlexandre Bounine return -ENODEV; 18882574740dSAlexandre Bounine 18892574740dSAlexandre Bounine /* 18902574740dSAlexandre Bounine * First, run enumerations and check if we need to perform discovery 18912574740dSAlexandre Bounine * on any of the registered mports. 18922574740dSAlexandre Bounine */ 1893a11650e1SAlexandre Bounine mutex_lock(&rio_mport_list_lock); 1894394b701cSMatt Porter list_for_each_entry(port, &rio_mports, node) { 1895a11650e1SAlexandre Bounine if (port->host_deviceid >= 0) { 18969edbc30bSAlexandre Bounine if (port->nscan && try_module_get(port->nscan->owner)) { 1897bc8fcfeaSAlexandre Bounine port->nscan->enumerate(port, 0); 18989edbc30bSAlexandre Bounine module_put(port->nscan->owner); 18999edbc30bSAlexandre Bounine } 1900a11650e1SAlexandre Bounine } else 19012574740dSAlexandre Bounine n++; 19022574740dSAlexandre Bounine } 1903a11650e1SAlexandre Bounine mutex_unlock(&rio_mport_list_lock); 19042574740dSAlexandre Bounine 19052574740dSAlexandre Bounine if (!n) 19062574740dSAlexandre Bounine goto no_disc; 19072574740dSAlexandre Bounine 19082574740dSAlexandre Bounine /* 19092574740dSAlexandre Bounine * If we have mports that require discovery schedule a discovery work 19102574740dSAlexandre Bounine * for each of them. If the code below fails to allocate needed 19112574740dSAlexandre Bounine * resources, exit without error to keep results of enumeration 19122574740dSAlexandre Bounine * process (if any). 19139edbc30bSAlexandre Bounine * TODO: Implement restart of discovery process for all or 19142574740dSAlexandre Bounine * individual discovering mports. 19152574740dSAlexandre Bounine */ 1916005842efSAlexandre Bounine rio_wq = alloc_workqueue("riodisc", 0, 0); 1917005842efSAlexandre Bounine if (!rio_wq) { 1918005842efSAlexandre Bounine pr_err("RIO: unable allocate rio_wq\n"); 19192574740dSAlexandre Bounine goto no_disc; 1920005842efSAlexandre Bounine } 1921005842efSAlexandre Bounine 19222574740dSAlexandre Bounine work = kcalloc(n, sizeof *work, GFP_KERNEL); 1923005842efSAlexandre Bounine if (!work) { 1924005842efSAlexandre Bounine pr_err("RIO: no memory for work struct\n"); 1925005842efSAlexandre Bounine destroy_workqueue(rio_wq); 19262574740dSAlexandre Bounine goto no_disc; 1927394b701cSMatt Porter } 1928394b701cSMatt Porter 19292574740dSAlexandre Bounine n = 0; 1930a11650e1SAlexandre Bounine mutex_lock(&rio_mport_list_lock); 19312574740dSAlexandre Bounine list_for_each_entry(port, &rio_mports, node) { 1932a11650e1SAlexandre Bounine if (port->host_deviceid < 0 && port->nscan) { 19332574740dSAlexandre Bounine work[n].mport = port; 19342574740dSAlexandre Bounine INIT_WORK(&work[n].work, disc_work_handler); 19352574740dSAlexandre Bounine queue_work(rio_wq, &work[n].work); 19362574740dSAlexandre Bounine n++; 19372574740dSAlexandre Bounine } 19382574740dSAlexandre Bounine } 19392574740dSAlexandre Bounine 19402574740dSAlexandre Bounine flush_workqueue(rio_wq); 19419edbc30bSAlexandre Bounine mutex_unlock(&rio_mport_list_lock); 19422574740dSAlexandre Bounine pr_debug("RIO: destroy discovery workqueue\n"); 19432574740dSAlexandre Bounine destroy_workqueue(rio_wq); 19442574740dSAlexandre Bounine kfree(work); 19452574740dSAlexandre Bounine 19462574740dSAlexandre Bounine no_disc: 19472f809985SAlexandre Bounine rio_init(); 19482f809985SAlexandre Bounine 1949c1256ebeSAlexandre Bounine return 0; 1950394b701cSMatt Porter } 1951394b701cSMatt Porter 1952569fccb6SAlexandre Bounine static int rio_get_hdid(int index) 1953569fccb6SAlexandre Bounine { 1954fdf90abcSAlexandre Bounine if (ids_num == 0 || ids_num <= index || index >= RIO_MAX_MPORTS) 1955569fccb6SAlexandre Bounine return -1; 1956569fccb6SAlexandre Bounine 1957fdf90abcSAlexandre Bounine return hdid[index]; 1958569fccb6SAlexandre Bounine } 1959569fccb6SAlexandre Bounine 196059f99965SAlexandre Bounine int rio_register_mport(struct rio_mport *port) 1961394b701cSMatt Porter { 19629edbc30bSAlexandre Bounine struct rio_scan_node *scan = NULL; 19632aaf308bSAlexandre Bounine int res = 0; 19649edbc30bSAlexandre Bounine 1965569fccb6SAlexandre Bounine if (next_portid >= RIO_MAX_MPORTS) { 1966569fccb6SAlexandre Bounine pr_err("RIO: reached specified max number of mports\n"); 196759f99965SAlexandre Bounine return 1; 1968569fccb6SAlexandre Bounine } 1969569fccb6SAlexandre Bounine 1970569fccb6SAlexandre Bounine port->id = next_portid++; 1971569fccb6SAlexandre Bounine port->host_deviceid = rio_get_hdid(port->id); 1972a11650e1SAlexandre Bounine port->nscan = NULL; 19739edbc30bSAlexandre Bounine 19742aaf308bSAlexandre Bounine dev_set_name(&port->dev, "rapidio%d", port->id); 19752aaf308bSAlexandre Bounine port->dev.class = &rio_mport_class; 19762aaf308bSAlexandre Bounine 19772aaf308bSAlexandre Bounine res = device_register(&port->dev); 19782aaf308bSAlexandre Bounine if (res) 19792aaf308bSAlexandre Bounine dev_err(&port->dev, "RIO: mport%d registration failed ERR=%d\n", 19802aaf308bSAlexandre Bounine port->id, res); 19812aaf308bSAlexandre Bounine else 19822aaf308bSAlexandre Bounine dev_dbg(&port->dev, "RIO: mport%d registered\n", port->id); 19832aaf308bSAlexandre Bounine 1984a11650e1SAlexandre Bounine mutex_lock(&rio_mport_list_lock); 1985394b701cSMatt Porter list_add_tail(&port->node, &rio_mports); 19869edbc30bSAlexandre Bounine 19879edbc30bSAlexandre Bounine /* 19889edbc30bSAlexandre Bounine * Check if there are any registered enumeration/discovery operations 19899edbc30bSAlexandre Bounine * that have to be attached to the added mport. 19909edbc30bSAlexandre Bounine */ 19919edbc30bSAlexandre Bounine list_for_each_entry(scan, &rio_scans, node) { 19929edbc30bSAlexandre Bounine if (port->id == scan->mport_id || 19939edbc30bSAlexandre Bounine scan->mport_id == RIO_MPORT_ANY) { 19949edbc30bSAlexandre Bounine port->nscan = scan->ops; 19959edbc30bSAlexandre Bounine if (port->id == scan->mport_id) 19969edbc30bSAlexandre Bounine break; 19979edbc30bSAlexandre Bounine } 19989edbc30bSAlexandre Bounine } 1999a11650e1SAlexandre Bounine mutex_unlock(&rio_mport_list_lock); 20009edbc30bSAlexandre Bounine 20019edbc30bSAlexandre Bounine pr_debug("RIO: %s %s id=%d\n", __func__, port->name, port->id); 200259f99965SAlexandre Bounine return 0; 2003394b701cSMatt Porter } 200494d9bd45SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_register_mport); 2005394b701cSMatt Porter 2006394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_local_get_device_id); 2007394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_get_device); 2008394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_get_asm); 2009394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_request_inb_dbell); 2010394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_release_inb_dbell); 2011394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_request_outb_dbell); 2012394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_release_outb_dbell); 2013394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_request_inb_mbox); 2014394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_release_inb_mbox); 2015394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_request_outb_mbox); 2016394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_release_outb_mbox); 2017a11650e1SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_init_mports); 2018