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 * 8e5cabeb3SAlexandre Bounine * Copyright 2009 Integrated Device Technology, Inc. 9e5cabeb3SAlexandre Bounine * Alex Bounine <alexandre.bounine@idt.com> 10e5cabeb3SAlexandre Bounine * - Added Port-Write/Error Management initialization and handling 11e5cabeb3SAlexandre Bounine * 12394b701cSMatt Porter * This program is free software; you can redistribute it and/or modify it 13394b701cSMatt Porter * under the terms of the GNU General Public License as published by the 14394b701cSMatt Porter * Free Software Foundation; either version 2 of the License, or (at your 15394b701cSMatt Porter * option) any later version. 16394b701cSMatt Porter */ 17394b701cSMatt Porter 18394b701cSMatt Porter #include <linux/types.h> 19394b701cSMatt Porter #include <linux/kernel.h> 20394b701cSMatt Porter 21394b701cSMatt Porter #include <linux/delay.h> 22394b701cSMatt Porter #include <linux/init.h> 23394b701cSMatt Porter #include <linux/rio.h> 24394b701cSMatt Porter #include <linux/rio_drv.h> 25394b701cSMatt Porter #include <linux/rio_ids.h> 26394b701cSMatt Porter #include <linux/rio_regs.h> 27394b701cSMatt Porter #include <linux/module.h> 28394b701cSMatt Porter #include <linux/spinlock.h> 29de25968cSTim Schmielau #include <linux/slab.h> 305febf1cdSKumar Gala #include <linux/interrupt.h> 31394b701cSMatt Porter 32394b701cSMatt Porter #include "rio.h" 33394b701cSMatt Porter 34394b701cSMatt Porter static LIST_HEAD(rio_mports); 35569fccb6SAlexandre Bounine static unsigned char next_portid; 36394b701cSMatt Porter 37394b701cSMatt Porter /** 38394b701cSMatt Porter * rio_local_get_device_id - Get the base/extended device id for a port 39394b701cSMatt Porter * @port: RIO master port from which to get the deviceid 40394b701cSMatt Porter * 41394b701cSMatt Porter * Reads the base/extended device id from the local device 42394b701cSMatt Porter * implementing the master port. Returns the 8/16-bit device 43394b701cSMatt Porter * id. 44394b701cSMatt Porter */ 45394b701cSMatt Porter u16 rio_local_get_device_id(struct rio_mport *port) 46394b701cSMatt Porter { 47394b701cSMatt Porter u32 result; 48394b701cSMatt Porter 49394b701cSMatt Porter rio_local_read_config_32(port, RIO_DID_CSR, &result); 50394b701cSMatt Porter 51e0423236SZhang Wei return (RIO_GET_DID(port->sys_size, result)); 52394b701cSMatt Porter } 53394b701cSMatt Porter 54394b701cSMatt Porter /** 55394b701cSMatt Porter * rio_request_inb_mbox - request inbound mailbox service 56394b701cSMatt Porter * @mport: RIO master port from which to allocate the mailbox resource 576978bbc0SMatt Porter * @dev_id: Device specific pointer to pass on event 58394b701cSMatt Porter * @mbox: Mailbox number to claim 59394b701cSMatt Porter * @entries: Number of entries in inbound mailbox queue 60394b701cSMatt Porter * @minb: Callback to execute when inbound message is received 61394b701cSMatt Porter * 62394b701cSMatt Porter * Requests ownership of an inbound mailbox resource and binds 63394b701cSMatt Porter * a callback function to the resource. Returns %0 on success. 64394b701cSMatt Porter */ 65394b701cSMatt Porter int rio_request_inb_mbox(struct rio_mport *mport, 666978bbc0SMatt Porter void *dev_id, 67394b701cSMatt Porter int mbox, 68394b701cSMatt Porter int entries, 696978bbc0SMatt Porter void (*minb) (struct rio_mport * mport, void *dev_id, int mbox, 70394b701cSMatt Porter int slot)) 71394b701cSMatt Porter { 72f8f06269SAlexandre Bounine int rc = -ENOSYS; 73f8f06269SAlexandre Bounine struct resource *res; 74394b701cSMatt Porter 75f8f06269SAlexandre Bounine if (mport->ops->open_inb_mbox == NULL) 76f8f06269SAlexandre Bounine goto out; 77f8f06269SAlexandre Bounine 78f8f06269SAlexandre Bounine res = kmalloc(sizeof(struct resource), GFP_KERNEL); 79394b701cSMatt Porter 80394b701cSMatt Porter if (res) { 81394b701cSMatt Porter rio_init_mbox_res(res, mbox, mbox); 82394b701cSMatt Porter 83394b701cSMatt Porter /* Make sure this mailbox isn't in use */ 84394b701cSMatt Porter if ((rc = 85394b701cSMatt Porter request_resource(&mport->riores[RIO_INB_MBOX_RESOURCE], 86394b701cSMatt Porter res)) < 0) { 87394b701cSMatt Porter kfree(res); 88394b701cSMatt Porter goto out; 89394b701cSMatt Porter } 90394b701cSMatt Porter 91394b701cSMatt Porter mport->inb_msg[mbox].res = res; 92394b701cSMatt Porter 93394b701cSMatt Porter /* Hook the inbound message callback */ 94394b701cSMatt Porter mport->inb_msg[mbox].mcback = minb; 95394b701cSMatt Porter 96f8f06269SAlexandre Bounine rc = mport->ops->open_inb_mbox(mport, dev_id, mbox, entries); 97394b701cSMatt Porter } else 98394b701cSMatt Porter rc = -ENOMEM; 99394b701cSMatt Porter 100394b701cSMatt Porter out: 101394b701cSMatt Porter return rc; 102394b701cSMatt Porter } 103394b701cSMatt Porter 104394b701cSMatt Porter /** 105394b701cSMatt Porter * rio_release_inb_mbox - release inbound mailbox message service 106394b701cSMatt Porter * @mport: RIO master port from which to release the mailbox resource 107394b701cSMatt Porter * @mbox: Mailbox number to release 108394b701cSMatt Porter * 109394b701cSMatt Porter * Releases ownership of an inbound mailbox resource. Returns 0 110394b701cSMatt Porter * if the request has been satisfied. 111394b701cSMatt Porter */ 112394b701cSMatt Porter int rio_release_inb_mbox(struct rio_mport *mport, int mbox) 113394b701cSMatt Porter { 114f8f06269SAlexandre Bounine if (mport->ops->close_inb_mbox) { 115f8f06269SAlexandre Bounine mport->ops->close_inb_mbox(mport, mbox); 116394b701cSMatt Porter 117394b701cSMatt Porter /* Release the mailbox resource */ 118394b701cSMatt Porter return release_resource(mport->inb_msg[mbox].res); 119f8f06269SAlexandre Bounine } else 120f8f06269SAlexandre Bounine return -ENOSYS; 121394b701cSMatt Porter } 122394b701cSMatt Porter 123394b701cSMatt Porter /** 124394b701cSMatt Porter * rio_request_outb_mbox - request outbound mailbox service 125394b701cSMatt Porter * @mport: RIO master port from which to allocate the mailbox resource 1266978bbc0SMatt Porter * @dev_id: Device specific pointer to pass on event 127394b701cSMatt Porter * @mbox: Mailbox number to claim 128394b701cSMatt Porter * @entries: Number of entries in outbound mailbox queue 129394b701cSMatt Porter * @moutb: Callback to execute when outbound message is sent 130394b701cSMatt Porter * 131394b701cSMatt Porter * Requests ownership of an outbound mailbox resource and binds 132394b701cSMatt Porter * a callback function to the resource. Returns 0 on success. 133394b701cSMatt Porter */ 134394b701cSMatt Porter int rio_request_outb_mbox(struct rio_mport *mport, 1356978bbc0SMatt Porter void *dev_id, 136394b701cSMatt Porter int mbox, 137394b701cSMatt Porter int entries, 1386978bbc0SMatt Porter void (*moutb) (struct rio_mport * mport, void *dev_id, int mbox, int slot)) 139394b701cSMatt Porter { 140f8f06269SAlexandre Bounine int rc = -ENOSYS; 141f8f06269SAlexandre Bounine struct resource *res; 142394b701cSMatt Porter 143f8f06269SAlexandre Bounine if (mport->ops->open_outb_mbox == NULL) 144f8f06269SAlexandre Bounine goto out; 145f8f06269SAlexandre Bounine 146f8f06269SAlexandre Bounine res = kmalloc(sizeof(struct resource), GFP_KERNEL); 147394b701cSMatt Porter 148394b701cSMatt Porter if (res) { 149394b701cSMatt Porter rio_init_mbox_res(res, mbox, mbox); 150394b701cSMatt Porter 151394b701cSMatt Porter /* Make sure this outbound mailbox isn't in use */ 152394b701cSMatt Porter if ((rc = 153394b701cSMatt Porter request_resource(&mport->riores[RIO_OUTB_MBOX_RESOURCE], 154394b701cSMatt Porter res)) < 0) { 155394b701cSMatt Porter kfree(res); 156394b701cSMatt Porter goto out; 157394b701cSMatt Porter } 158394b701cSMatt Porter 159394b701cSMatt Porter mport->outb_msg[mbox].res = res; 160394b701cSMatt Porter 161394b701cSMatt Porter /* Hook the inbound message callback */ 162394b701cSMatt Porter mport->outb_msg[mbox].mcback = moutb; 163394b701cSMatt Porter 164f8f06269SAlexandre Bounine rc = mport->ops->open_outb_mbox(mport, dev_id, mbox, entries); 165394b701cSMatt Porter } else 166394b701cSMatt Porter rc = -ENOMEM; 167394b701cSMatt Porter 168394b701cSMatt Porter out: 169394b701cSMatt Porter return rc; 170394b701cSMatt Porter } 171394b701cSMatt Porter 172394b701cSMatt Porter /** 173394b701cSMatt Porter * rio_release_outb_mbox - release outbound mailbox message service 174394b701cSMatt Porter * @mport: RIO master port from which to release the mailbox resource 175394b701cSMatt Porter * @mbox: Mailbox number to release 176394b701cSMatt Porter * 177394b701cSMatt Porter * Releases ownership of an inbound mailbox resource. Returns 0 178394b701cSMatt Porter * if the request has been satisfied. 179394b701cSMatt Porter */ 180394b701cSMatt Porter int rio_release_outb_mbox(struct rio_mport *mport, int mbox) 181394b701cSMatt Porter { 182f8f06269SAlexandre Bounine if (mport->ops->close_outb_mbox) { 183f8f06269SAlexandre Bounine mport->ops->close_outb_mbox(mport, mbox); 184394b701cSMatt Porter 185394b701cSMatt Porter /* Release the mailbox resource */ 186394b701cSMatt Porter return release_resource(mport->outb_msg[mbox].res); 187f8f06269SAlexandre Bounine } else 188f8f06269SAlexandre Bounine return -ENOSYS; 189394b701cSMatt Porter } 190394b701cSMatt Porter 191394b701cSMatt Porter /** 192394b701cSMatt Porter * rio_setup_inb_dbell - bind inbound doorbell callback 193394b701cSMatt Porter * @mport: RIO master port to bind the doorbell callback 1946978bbc0SMatt Porter * @dev_id: Device specific pointer to pass on event 195394b701cSMatt Porter * @res: Doorbell message resource 196394b701cSMatt Porter * @dinb: Callback to execute when doorbell is received 197394b701cSMatt Porter * 198394b701cSMatt Porter * Adds a doorbell resource/callback pair into a port's 199394b701cSMatt Porter * doorbell event list. Returns 0 if the request has been 200394b701cSMatt Porter * satisfied. 201394b701cSMatt Porter */ 202394b701cSMatt Porter static int 2036978bbc0SMatt Porter rio_setup_inb_dbell(struct rio_mport *mport, void *dev_id, struct resource *res, 2046978bbc0SMatt Porter void (*dinb) (struct rio_mport * mport, void *dev_id, u16 src, u16 dst, 205394b701cSMatt Porter u16 info)) 206394b701cSMatt Porter { 207394b701cSMatt Porter int rc = 0; 208394b701cSMatt Porter struct rio_dbell *dbell; 209394b701cSMatt Porter 210394b701cSMatt Porter if (!(dbell = kmalloc(sizeof(struct rio_dbell), GFP_KERNEL))) { 211394b701cSMatt Porter rc = -ENOMEM; 212394b701cSMatt Porter goto out; 213394b701cSMatt Porter } 214394b701cSMatt Porter 215394b701cSMatt Porter dbell->res = res; 216394b701cSMatt Porter dbell->dinb = dinb; 2176978bbc0SMatt Porter dbell->dev_id = dev_id; 218394b701cSMatt Porter 219394b701cSMatt Porter list_add_tail(&dbell->node, &mport->dbells); 220394b701cSMatt Porter 221394b701cSMatt Porter out: 222394b701cSMatt Porter return rc; 223394b701cSMatt Porter } 224394b701cSMatt Porter 225394b701cSMatt Porter /** 226394b701cSMatt Porter * rio_request_inb_dbell - request inbound doorbell message service 227394b701cSMatt Porter * @mport: RIO master port from which to allocate the doorbell resource 2286978bbc0SMatt Porter * @dev_id: Device specific pointer to pass on event 229394b701cSMatt Porter * @start: Doorbell info range start 230394b701cSMatt Porter * @end: Doorbell info range end 231394b701cSMatt Porter * @dinb: Callback to execute when doorbell is received 232394b701cSMatt Porter * 233394b701cSMatt Porter * Requests ownership of an inbound doorbell resource and binds 234394b701cSMatt Porter * a callback function to the resource. Returns 0 if the request 235394b701cSMatt Porter * has been satisfied. 236394b701cSMatt Porter */ 237394b701cSMatt Porter int rio_request_inb_dbell(struct rio_mport *mport, 2386978bbc0SMatt Porter void *dev_id, 239394b701cSMatt Porter u16 start, 240394b701cSMatt Porter u16 end, 2416978bbc0SMatt Porter void (*dinb) (struct rio_mport * mport, void *dev_id, u16 src, 242394b701cSMatt Porter u16 dst, u16 info)) 243394b701cSMatt Porter { 244394b701cSMatt Porter int rc = 0; 245394b701cSMatt Porter 246394b701cSMatt Porter struct resource *res = kmalloc(sizeof(struct resource), GFP_KERNEL); 247394b701cSMatt Porter 248394b701cSMatt Porter if (res) { 249394b701cSMatt Porter rio_init_dbell_res(res, start, end); 250394b701cSMatt Porter 251394b701cSMatt Porter /* Make sure these doorbells aren't in use */ 252394b701cSMatt Porter if ((rc = 253394b701cSMatt Porter request_resource(&mport->riores[RIO_DOORBELL_RESOURCE], 254394b701cSMatt Porter res)) < 0) { 255394b701cSMatt Porter kfree(res); 256394b701cSMatt Porter goto out; 257394b701cSMatt Porter } 258394b701cSMatt Porter 259394b701cSMatt Porter /* Hook the doorbell callback */ 2606978bbc0SMatt Porter rc = rio_setup_inb_dbell(mport, dev_id, res, dinb); 261394b701cSMatt Porter } else 262394b701cSMatt Porter rc = -ENOMEM; 263394b701cSMatt Porter 264394b701cSMatt Porter out: 265394b701cSMatt Porter return rc; 266394b701cSMatt Porter } 267394b701cSMatt Porter 268394b701cSMatt Porter /** 269394b701cSMatt Porter * rio_release_inb_dbell - release inbound doorbell message service 270394b701cSMatt Porter * @mport: RIO master port from which to release the doorbell resource 271394b701cSMatt Porter * @start: Doorbell info range start 272394b701cSMatt Porter * @end: Doorbell info range end 273394b701cSMatt Porter * 274394b701cSMatt Porter * Releases ownership of an inbound doorbell resource and removes 275394b701cSMatt Porter * callback from the doorbell event list. Returns 0 if the request 276394b701cSMatt Porter * has been satisfied. 277394b701cSMatt Porter */ 278394b701cSMatt Porter int rio_release_inb_dbell(struct rio_mport *mport, u16 start, u16 end) 279394b701cSMatt Porter { 280394b701cSMatt Porter int rc = 0, found = 0; 281394b701cSMatt Porter struct rio_dbell *dbell; 282394b701cSMatt Porter 283394b701cSMatt Porter list_for_each_entry(dbell, &mport->dbells, node) { 284394b701cSMatt Porter if ((dbell->res->start == start) && (dbell->res->end == end)) { 285394b701cSMatt Porter found = 1; 286394b701cSMatt Porter break; 287394b701cSMatt Porter } 288394b701cSMatt Porter } 289394b701cSMatt Porter 290394b701cSMatt Porter /* If we can't find an exact match, fail */ 291394b701cSMatt Porter if (!found) { 292394b701cSMatt Porter rc = -EINVAL; 293394b701cSMatt Porter goto out; 294394b701cSMatt Porter } 295394b701cSMatt Porter 296394b701cSMatt Porter /* Delete from list */ 297394b701cSMatt Porter list_del(&dbell->node); 298394b701cSMatt Porter 299394b701cSMatt Porter /* Release the doorbell resource */ 300394b701cSMatt Porter rc = release_resource(dbell->res); 301394b701cSMatt Porter 302394b701cSMatt Porter /* Free the doorbell event */ 303394b701cSMatt Porter kfree(dbell); 304394b701cSMatt Porter 305394b701cSMatt Porter out: 306394b701cSMatt Porter return rc; 307394b701cSMatt Porter } 308394b701cSMatt Porter 309394b701cSMatt Porter /** 310394b701cSMatt Porter * rio_request_outb_dbell - request outbound doorbell message range 311394b701cSMatt Porter * @rdev: RIO device from which to allocate the doorbell resource 312394b701cSMatt Porter * @start: Doorbell message range start 313394b701cSMatt Porter * @end: Doorbell message range end 314394b701cSMatt Porter * 315394b701cSMatt Porter * Requests ownership of a doorbell message range. Returns a resource 316394b701cSMatt Porter * if the request has been satisfied or %NULL on failure. 317394b701cSMatt Porter */ 318394b701cSMatt Porter struct resource *rio_request_outb_dbell(struct rio_dev *rdev, u16 start, 319394b701cSMatt Porter u16 end) 320394b701cSMatt Porter { 321394b701cSMatt Porter struct resource *res = kmalloc(sizeof(struct resource), GFP_KERNEL); 322394b701cSMatt Porter 323394b701cSMatt Porter if (res) { 324394b701cSMatt Porter rio_init_dbell_res(res, start, end); 325394b701cSMatt Porter 326394b701cSMatt Porter /* Make sure these doorbells aren't in use */ 327394b701cSMatt Porter if (request_resource(&rdev->riores[RIO_DOORBELL_RESOURCE], res) 328394b701cSMatt Porter < 0) { 329394b701cSMatt Porter kfree(res); 330394b701cSMatt Porter res = NULL; 331394b701cSMatt Porter } 332394b701cSMatt Porter } 333394b701cSMatt Porter 334394b701cSMatt Porter return res; 335394b701cSMatt Porter } 336394b701cSMatt Porter 337394b701cSMatt Porter /** 338394b701cSMatt Porter * rio_release_outb_dbell - release outbound doorbell message range 339394b701cSMatt Porter * @rdev: RIO device from which to release the doorbell resource 340394b701cSMatt Porter * @res: Doorbell resource to be freed 341394b701cSMatt Porter * 342394b701cSMatt Porter * Releases ownership of a doorbell message range. Returns 0 if the 343394b701cSMatt Porter * request has been satisfied. 344394b701cSMatt Porter */ 345394b701cSMatt Porter int rio_release_outb_dbell(struct rio_dev *rdev, struct resource *res) 346394b701cSMatt Porter { 347394b701cSMatt Porter int rc = release_resource(res); 348394b701cSMatt Porter 349394b701cSMatt Porter kfree(res); 350394b701cSMatt Porter 351394b701cSMatt Porter return rc; 352394b701cSMatt Porter } 353394b701cSMatt Porter 354394b701cSMatt Porter /** 355e5cabeb3SAlexandre Bounine * rio_request_inb_pwrite - request inbound port-write message service 35697ef6f74SRandy Dunlap * @rdev: RIO device to which register inbound port-write callback routine 357e5cabeb3SAlexandre Bounine * @pwcback: Callback routine to execute when port-write is received 358e5cabeb3SAlexandre Bounine * 359e5cabeb3SAlexandre Bounine * Binds a port-write callback function to the RapidIO device. 360e5cabeb3SAlexandre Bounine * Returns 0 if the request has been satisfied. 361e5cabeb3SAlexandre Bounine */ 362e5cabeb3SAlexandre Bounine int rio_request_inb_pwrite(struct rio_dev *rdev, 363e5cabeb3SAlexandre Bounine int (*pwcback)(struct rio_dev *rdev, union rio_pw_msg *msg, int step)) 364e5cabeb3SAlexandre Bounine { 365e5cabeb3SAlexandre Bounine int rc = 0; 366e5cabeb3SAlexandre Bounine 367e5cabeb3SAlexandre Bounine spin_lock(&rio_global_list_lock); 368e5cabeb3SAlexandre Bounine if (rdev->pwcback != NULL) 369e5cabeb3SAlexandre Bounine rc = -ENOMEM; 370e5cabeb3SAlexandre Bounine else 371e5cabeb3SAlexandre Bounine rdev->pwcback = pwcback; 372e5cabeb3SAlexandre Bounine 373e5cabeb3SAlexandre Bounine spin_unlock(&rio_global_list_lock); 374e5cabeb3SAlexandre Bounine return rc; 375e5cabeb3SAlexandre Bounine } 376e5cabeb3SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_request_inb_pwrite); 377e5cabeb3SAlexandre Bounine 378e5cabeb3SAlexandre Bounine /** 379e5cabeb3SAlexandre Bounine * rio_release_inb_pwrite - release inbound port-write message service 380e5cabeb3SAlexandre Bounine * @rdev: RIO device which registered for inbound port-write callback 381e5cabeb3SAlexandre Bounine * 382e5cabeb3SAlexandre Bounine * Removes callback from the rio_dev structure. Returns 0 if the request 383e5cabeb3SAlexandre Bounine * has been satisfied. 384e5cabeb3SAlexandre Bounine */ 385e5cabeb3SAlexandre Bounine int rio_release_inb_pwrite(struct rio_dev *rdev) 386e5cabeb3SAlexandre Bounine { 387e5cabeb3SAlexandre Bounine int rc = -ENOMEM; 388e5cabeb3SAlexandre Bounine 389e5cabeb3SAlexandre Bounine spin_lock(&rio_global_list_lock); 390e5cabeb3SAlexandre Bounine if (rdev->pwcback) { 391e5cabeb3SAlexandre Bounine rdev->pwcback = NULL; 392e5cabeb3SAlexandre Bounine rc = 0; 393e5cabeb3SAlexandre Bounine } 394e5cabeb3SAlexandre Bounine 395e5cabeb3SAlexandre Bounine spin_unlock(&rio_global_list_lock); 396e5cabeb3SAlexandre Bounine return rc; 397e5cabeb3SAlexandre Bounine } 398e5cabeb3SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_release_inb_pwrite); 399e5cabeb3SAlexandre Bounine 400e5cabeb3SAlexandre Bounine /** 401e5cabeb3SAlexandre Bounine * rio_mport_get_physefb - Helper function that returns register offset 402e5cabeb3SAlexandre Bounine * for Physical Layer Extended Features Block. 40397ef6f74SRandy Dunlap * @port: Master port to issue transaction 40497ef6f74SRandy Dunlap * @local: Indicate a local master port or remote device access 40597ef6f74SRandy Dunlap * @destid: Destination ID of the device 40697ef6f74SRandy Dunlap * @hopcount: Number of switch hops to the device 407e5cabeb3SAlexandre Bounine */ 408e5cabeb3SAlexandre Bounine u32 409e5cabeb3SAlexandre Bounine rio_mport_get_physefb(struct rio_mport *port, int local, 410e5cabeb3SAlexandre Bounine u16 destid, u8 hopcount) 411e5cabeb3SAlexandre Bounine { 412e5cabeb3SAlexandre Bounine u32 ext_ftr_ptr; 413e5cabeb3SAlexandre Bounine u32 ftr_header; 414e5cabeb3SAlexandre Bounine 415e5cabeb3SAlexandre Bounine ext_ftr_ptr = rio_mport_get_efb(port, local, destid, hopcount, 0); 416e5cabeb3SAlexandre Bounine 417e5cabeb3SAlexandre Bounine while (ext_ftr_ptr) { 418e5cabeb3SAlexandre Bounine if (local) 419e5cabeb3SAlexandre Bounine rio_local_read_config_32(port, ext_ftr_ptr, 420e5cabeb3SAlexandre Bounine &ftr_header); 421e5cabeb3SAlexandre Bounine else 422e5cabeb3SAlexandre Bounine rio_mport_read_config_32(port, destid, hopcount, 423e5cabeb3SAlexandre Bounine ext_ftr_ptr, &ftr_header); 424e5cabeb3SAlexandre Bounine 425e5cabeb3SAlexandre Bounine ftr_header = RIO_GET_BLOCK_ID(ftr_header); 426e5cabeb3SAlexandre Bounine switch (ftr_header) { 427e5cabeb3SAlexandre Bounine 428e5cabeb3SAlexandre Bounine case RIO_EFB_SER_EP_ID_V13P: 429e5cabeb3SAlexandre Bounine case RIO_EFB_SER_EP_REC_ID_V13P: 430e5cabeb3SAlexandre Bounine case RIO_EFB_SER_EP_FREE_ID_V13P: 431e5cabeb3SAlexandre Bounine case RIO_EFB_SER_EP_ID: 432e5cabeb3SAlexandre Bounine case RIO_EFB_SER_EP_REC_ID: 433e5cabeb3SAlexandre Bounine case RIO_EFB_SER_EP_FREE_ID: 434e5cabeb3SAlexandre Bounine case RIO_EFB_SER_EP_FREC_ID: 435e5cabeb3SAlexandre Bounine 436e5cabeb3SAlexandre Bounine return ext_ftr_ptr; 437e5cabeb3SAlexandre Bounine 438e5cabeb3SAlexandre Bounine default: 439e5cabeb3SAlexandre Bounine break; 440e5cabeb3SAlexandre Bounine } 441e5cabeb3SAlexandre Bounine 442e5cabeb3SAlexandre Bounine ext_ftr_ptr = rio_mport_get_efb(port, local, destid, 443e5cabeb3SAlexandre Bounine hopcount, ext_ftr_ptr); 444e5cabeb3SAlexandre Bounine } 445e5cabeb3SAlexandre Bounine 446e5cabeb3SAlexandre Bounine return ext_ftr_ptr; 447e5cabeb3SAlexandre Bounine } 448e5cabeb3SAlexandre Bounine 449e5cabeb3SAlexandre Bounine /** 450e5cabeb3SAlexandre Bounine * rio_get_comptag - Begin or continue searching for a RIO device by component tag 45197ef6f74SRandy Dunlap * @comp_tag: RIO component tag to match 452e5cabeb3SAlexandre Bounine * @from: Previous RIO device found in search, or %NULL for new search 453e5cabeb3SAlexandre Bounine * 454e5cabeb3SAlexandre Bounine * Iterates through the list of known RIO devices. If a RIO device is 455e5cabeb3SAlexandre Bounine * found with a matching @comp_tag, a pointer to its device 456e5cabeb3SAlexandre Bounine * structure is returned. Otherwise, %NULL is returned. A new search 457e5cabeb3SAlexandre Bounine * is initiated by passing %NULL to the @from argument. Otherwise, if 458e5cabeb3SAlexandre Bounine * @from is not %NULL, searches continue from next device on the global 459e5cabeb3SAlexandre Bounine * list. 460e5cabeb3SAlexandre Bounine */ 461af84ca38SAlexandre Bounine struct rio_dev *rio_get_comptag(u32 comp_tag, struct rio_dev *from) 462e5cabeb3SAlexandre Bounine { 463e5cabeb3SAlexandre Bounine struct list_head *n; 464e5cabeb3SAlexandre Bounine struct rio_dev *rdev; 465e5cabeb3SAlexandre Bounine 466e5cabeb3SAlexandre Bounine spin_lock(&rio_global_list_lock); 467e5cabeb3SAlexandre Bounine n = from ? from->global_list.next : rio_devices.next; 468e5cabeb3SAlexandre Bounine 469e5cabeb3SAlexandre Bounine while (n && (n != &rio_devices)) { 470e5cabeb3SAlexandre Bounine rdev = rio_dev_g(n); 471e5cabeb3SAlexandre Bounine if (rdev->comp_tag == comp_tag) 472e5cabeb3SAlexandre Bounine goto exit; 473e5cabeb3SAlexandre Bounine n = n->next; 474e5cabeb3SAlexandre Bounine } 475e5cabeb3SAlexandre Bounine rdev = NULL; 476e5cabeb3SAlexandre Bounine exit: 477e5cabeb3SAlexandre Bounine spin_unlock(&rio_global_list_lock); 478e5cabeb3SAlexandre Bounine return rdev; 479e5cabeb3SAlexandre Bounine } 480e5cabeb3SAlexandre Bounine 481e5cabeb3SAlexandre Bounine /** 482e5cabeb3SAlexandre Bounine * rio_set_port_lockout - Sets/clears LOCKOUT bit (RIO EM 1.3) for a switch port. 483e5cabeb3SAlexandre Bounine * @rdev: Pointer to RIO device control structure 484e5cabeb3SAlexandre Bounine * @pnum: Switch port number to set LOCKOUT bit 485e5cabeb3SAlexandre Bounine * @lock: Operation : set (=1) or clear (=0) 486e5cabeb3SAlexandre Bounine */ 487e5cabeb3SAlexandre Bounine int rio_set_port_lockout(struct rio_dev *rdev, u32 pnum, int lock) 488e5cabeb3SAlexandre Bounine { 489e5cabeb3SAlexandre Bounine u32 regval; 490e5cabeb3SAlexandre Bounine 491a93192a5SAlexandre Bounine rio_read_config_32(rdev, 492e5cabeb3SAlexandre Bounine rdev->phys_efptr + RIO_PORT_N_CTL_CSR(pnum), 493e5cabeb3SAlexandre Bounine ®val); 494e5cabeb3SAlexandre Bounine if (lock) 495e5cabeb3SAlexandre Bounine regval |= RIO_PORT_N_CTL_LOCKOUT; 496e5cabeb3SAlexandre Bounine else 497e5cabeb3SAlexandre Bounine regval &= ~RIO_PORT_N_CTL_LOCKOUT; 498e5cabeb3SAlexandre Bounine 499a93192a5SAlexandre Bounine rio_write_config_32(rdev, 500e5cabeb3SAlexandre Bounine rdev->phys_efptr + RIO_PORT_N_CTL_CSR(pnum), 501e5cabeb3SAlexandre Bounine regval); 502e5cabeb3SAlexandre Bounine return 0; 503e5cabeb3SAlexandre Bounine } 504e5cabeb3SAlexandre Bounine 505e5cabeb3SAlexandre Bounine /** 5066429cd49SAlexandre Bounine * rio_chk_dev_route - Validate route to the specified device. 5076429cd49SAlexandre Bounine * @rdev: RIO device failed to respond 5086429cd49SAlexandre Bounine * @nrdev: Last active device on the route to rdev 5096429cd49SAlexandre Bounine * @npnum: nrdev's port number on the route to rdev 5106429cd49SAlexandre Bounine * 5116429cd49SAlexandre Bounine * Follows a route to the specified RIO device to determine the last available 5126429cd49SAlexandre Bounine * device (and corresponding RIO port) on the route. 5136429cd49SAlexandre Bounine */ 5146429cd49SAlexandre Bounine static int 5156429cd49SAlexandre Bounine rio_chk_dev_route(struct rio_dev *rdev, struct rio_dev **nrdev, int *npnum) 5166429cd49SAlexandre Bounine { 5176429cd49SAlexandre Bounine u32 result; 518a93192a5SAlexandre Bounine int p_port, rc = -EIO; 5196429cd49SAlexandre Bounine struct rio_dev *prev = NULL; 5206429cd49SAlexandre Bounine 5216429cd49SAlexandre Bounine /* Find switch with failed RIO link */ 5226429cd49SAlexandre Bounine while (rdev->prev && (rdev->prev->pef & RIO_PEF_SWITCH)) { 5236429cd49SAlexandre Bounine if (!rio_read_config_32(rdev->prev, RIO_DEV_ID_CAR, &result)) { 5246429cd49SAlexandre Bounine prev = rdev->prev; 5256429cd49SAlexandre Bounine break; 5266429cd49SAlexandre Bounine } 5276429cd49SAlexandre Bounine rdev = rdev->prev; 5286429cd49SAlexandre Bounine } 5296429cd49SAlexandre Bounine 5306429cd49SAlexandre Bounine if (prev == NULL) 5316429cd49SAlexandre Bounine goto err_out; 5326429cd49SAlexandre Bounine 533a93192a5SAlexandre Bounine p_port = prev->rswitch->route_table[rdev->destid]; 5346429cd49SAlexandre Bounine 535af84ca38SAlexandre Bounine if (p_port != RIO_INVALID_ROUTE) { 5366429cd49SAlexandre Bounine pr_debug("RIO: link failed on [%s]-P%d\n", 5376429cd49SAlexandre Bounine rio_name(prev), p_port); 5386429cd49SAlexandre Bounine *nrdev = prev; 5396429cd49SAlexandre Bounine *npnum = p_port; 5406429cd49SAlexandre Bounine rc = 0; 5416429cd49SAlexandre Bounine } else 542af84ca38SAlexandre Bounine pr_debug("RIO: failed to trace route to %s\n", rio_name(rdev)); 5436429cd49SAlexandre Bounine err_out: 5446429cd49SAlexandre Bounine return rc; 5456429cd49SAlexandre Bounine } 5466429cd49SAlexandre Bounine 5476429cd49SAlexandre Bounine /** 5486429cd49SAlexandre Bounine * rio_mport_chk_dev_access - Validate access to the specified device. 5496429cd49SAlexandre Bounine * @mport: Master port to send transactions 5506429cd49SAlexandre Bounine * @destid: Device destination ID in network 5516429cd49SAlexandre Bounine * @hopcount: Number of hops into the network 5526429cd49SAlexandre Bounine */ 553e274e0edSAlexandre Bounine int 5546429cd49SAlexandre Bounine rio_mport_chk_dev_access(struct rio_mport *mport, u16 destid, u8 hopcount) 5556429cd49SAlexandre Bounine { 5566429cd49SAlexandre Bounine int i = 0; 5576429cd49SAlexandre Bounine u32 tmp; 5586429cd49SAlexandre Bounine 5596429cd49SAlexandre Bounine while (rio_mport_read_config_32(mport, destid, hopcount, 5606429cd49SAlexandre Bounine RIO_DEV_ID_CAR, &tmp)) { 5616429cd49SAlexandre Bounine i++; 5626429cd49SAlexandre Bounine if (i == RIO_MAX_CHK_RETRY) 5636429cd49SAlexandre Bounine return -EIO; 5646429cd49SAlexandre Bounine mdelay(1); 5656429cd49SAlexandre Bounine } 5666429cd49SAlexandre Bounine 5676429cd49SAlexandre Bounine return 0; 5686429cd49SAlexandre Bounine } 5696429cd49SAlexandre Bounine 5706429cd49SAlexandre Bounine /** 5716429cd49SAlexandre Bounine * rio_chk_dev_access - Validate access to the specified device. 5726429cd49SAlexandre Bounine * @rdev: Pointer to RIO device control structure 5736429cd49SAlexandre Bounine */ 5746429cd49SAlexandre Bounine static int rio_chk_dev_access(struct rio_dev *rdev) 5756429cd49SAlexandre Bounine { 576a93192a5SAlexandre Bounine return rio_mport_chk_dev_access(rdev->net->hport, 577a93192a5SAlexandre Bounine rdev->destid, rdev->hopcount); 5786429cd49SAlexandre Bounine } 5796429cd49SAlexandre Bounine 5806429cd49SAlexandre Bounine /** 581dd5648c9SAlexandre Bounine * rio_get_input_status - Sends a Link-Request/Input-Status control symbol and 582dd5648c9SAlexandre Bounine * returns link-response (if requested). 583dd5648c9SAlexandre Bounine * @rdev: RIO devive to issue Input-status command 584dd5648c9SAlexandre Bounine * @pnum: Device port number to issue the command 585dd5648c9SAlexandre Bounine * @lnkresp: Response from a link partner 586dd5648c9SAlexandre Bounine */ 587dd5648c9SAlexandre Bounine static int 588dd5648c9SAlexandre Bounine rio_get_input_status(struct rio_dev *rdev, int pnum, u32 *lnkresp) 589dd5648c9SAlexandre Bounine { 590dd5648c9SAlexandre Bounine u32 regval; 591dd5648c9SAlexandre Bounine int checkcount; 592dd5648c9SAlexandre Bounine 593dd5648c9SAlexandre Bounine if (lnkresp) { 594dd5648c9SAlexandre Bounine /* Read from link maintenance response register 595dd5648c9SAlexandre Bounine * to clear valid bit */ 596a93192a5SAlexandre Bounine rio_read_config_32(rdev, 597dd5648c9SAlexandre Bounine rdev->phys_efptr + RIO_PORT_N_MNT_RSP_CSR(pnum), 598dd5648c9SAlexandre Bounine ®val); 599dd5648c9SAlexandre Bounine udelay(50); 600dd5648c9SAlexandre Bounine } 601dd5648c9SAlexandre Bounine 602dd5648c9SAlexandre Bounine /* Issue Input-status command */ 603a93192a5SAlexandre Bounine rio_write_config_32(rdev, 604dd5648c9SAlexandre Bounine rdev->phys_efptr + RIO_PORT_N_MNT_REQ_CSR(pnum), 605dd5648c9SAlexandre Bounine RIO_MNT_REQ_CMD_IS); 606dd5648c9SAlexandre Bounine 607dd5648c9SAlexandre Bounine /* Exit if the response is not expected */ 608dd5648c9SAlexandre Bounine if (lnkresp == NULL) 609dd5648c9SAlexandre Bounine return 0; 610dd5648c9SAlexandre Bounine 611dd5648c9SAlexandre Bounine checkcount = 3; 612dd5648c9SAlexandre Bounine while (checkcount--) { 613dd5648c9SAlexandre Bounine udelay(50); 614a93192a5SAlexandre Bounine rio_read_config_32(rdev, 615dd5648c9SAlexandre Bounine rdev->phys_efptr + RIO_PORT_N_MNT_RSP_CSR(pnum), 616dd5648c9SAlexandre Bounine ®val); 617dd5648c9SAlexandre Bounine if (regval & RIO_PORT_N_MNT_RSP_RVAL) { 618dd5648c9SAlexandre Bounine *lnkresp = regval; 619dd5648c9SAlexandre Bounine return 0; 620dd5648c9SAlexandre Bounine } 621dd5648c9SAlexandre Bounine } 622dd5648c9SAlexandre Bounine 623dd5648c9SAlexandre Bounine return -EIO; 624dd5648c9SAlexandre Bounine } 625dd5648c9SAlexandre Bounine 626dd5648c9SAlexandre Bounine /** 627dd5648c9SAlexandre Bounine * rio_clr_err_stopped - Clears port Error-stopped states. 628dd5648c9SAlexandre Bounine * @rdev: Pointer to RIO device control structure 629dd5648c9SAlexandre Bounine * @pnum: Switch port number to clear errors 630dd5648c9SAlexandre Bounine * @err_status: port error status (if 0 reads register from device) 631dd5648c9SAlexandre Bounine */ 632dd5648c9SAlexandre Bounine static int rio_clr_err_stopped(struct rio_dev *rdev, u32 pnum, u32 err_status) 633dd5648c9SAlexandre Bounine { 634dd5648c9SAlexandre Bounine struct rio_dev *nextdev = rdev->rswitch->nextdev[pnum]; 635dd5648c9SAlexandre Bounine u32 regval; 636dd5648c9SAlexandre Bounine u32 far_ackid, far_linkstat, near_ackid; 637dd5648c9SAlexandre Bounine 638dd5648c9SAlexandre Bounine if (err_status == 0) 639a93192a5SAlexandre Bounine rio_read_config_32(rdev, 640dd5648c9SAlexandre Bounine rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(pnum), 641dd5648c9SAlexandre Bounine &err_status); 642dd5648c9SAlexandre Bounine 643dd5648c9SAlexandre Bounine if (err_status & RIO_PORT_N_ERR_STS_PW_OUT_ES) { 644dd5648c9SAlexandre Bounine pr_debug("RIO_EM: servicing Output Error-Stopped state\n"); 645dd5648c9SAlexandre Bounine /* 646dd5648c9SAlexandre Bounine * Send a Link-Request/Input-Status control symbol 647dd5648c9SAlexandre Bounine */ 648dd5648c9SAlexandre Bounine if (rio_get_input_status(rdev, pnum, ®val)) { 649dd5648c9SAlexandre Bounine pr_debug("RIO_EM: Input-status response timeout\n"); 650dd5648c9SAlexandre Bounine goto rd_err; 651dd5648c9SAlexandre Bounine } 652dd5648c9SAlexandre Bounine 653dd5648c9SAlexandre Bounine pr_debug("RIO_EM: SP%d Input-status response=0x%08x\n", 654dd5648c9SAlexandre Bounine pnum, regval); 655dd5648c9SAlexandre Bounine far_ackid = (regval & RIO_PORT_N_MNT_RSP_ASTAT) >> 5; 656dd5648c9SAlexandre Bounine far_linkstat = regval & RIO_PORT_N_MNT_RSP_LSTAT; 657a93192a5SAlexandre Bounine rio_read_config_32(rdev, 658dd5648c9SAlexandre Bounine rdev->phys_efptr + RIO_PORT_N_ACK_STS_CSR(pnum), 659dd5648c9SAlexandre Bounine ®val); 660dd5648c9SAlexandre Bounine pr_debug("RIO_EM: SP%d_ACK_STS_CSR=0x%08x\n", pnum, regval); 661dd5648c9SAlexandre Bounine near_ackid = (regval & RIO_PORT_N_ACK_INBOUND) >> 24; 662dd5648c9SAlexandre Bounine pr_debug("RIO_EM: SP%d far_ackID=0x%02x far_linkstat=0x%02x" \ 663dd5648c9SAlexandre Bounine " near_ackID=0x%02x\n", 664dd5648c9SAlexandre Bounine pnum, far_ackid, far_linkstat, near_ackid); 665dd5648c9SAlexandre Bounine 666dd5648c9SAlexandre Bounine /* 667dd5648c9SAlexandre Bounine * If required, synchronize ackIDs of near and 668dd5648c9SAlexandre Bounine * far sides. 669dd5648c9SAlexandre Bounine */ 670dd5648c9SAlexandre Bounine if ((far_ackid != ((regval & RIO_PORT_N_ACK_OUTSTAND) >> 8)) || 671dd5648c9SAlexandre Bounine (far_ackid != (regval & RIO_PORT_N_ACK_OUTBOUND))) { 672dd5648c9SAlexandre Bounine /* Align near outstanding/outbound ackIDs with 673dd5648c9SAlexandre Bounine * far inbound. 674dd5648c9SAlexandre Bounine */ 675a93192a5SAlexandre Bounine rio_write_config_32(rdev, 676a93192a5SAlexandre Bounine rdev->phys_efptr + RIO_PORT_N_ACK_STS_CSR(pnum), 677dd5648c9SAlexandre Bounine (near_ackid << 24) | 678dd5648c9SAlexandre Bounine (far_ackid << 8) | far_ackid); 679dd5648c9SAlexandre Bounine /* Align far outstanding/outbound ackIDs with 680dd5648c9SAlexandre Bounine * near inbound. 681dd5648c9SAlexandre Bounine */ 682dd5648c9SAlexandre Bounine far_ackid++; 683dd5648c9SAlexandre Bounine if (nextdev) 684dd5648c9SAlexandre Bounine rio_write_config_32(nextdev, 685dd5648c9SAlexandre Bounine nextdev->phys_efptr + 686dd5648c9SAlexandre Bounine RIO_PORT_N_ACK_STS_CSR(RIO_GET_PORT_NUM(nextdev->swpinfo)), 687dd5648c9SAlexandre Bounine (far_ackid << 24) | 688dd5648c9SAlexandre Bounine (near_ackid << 8) | near_ackid); 689dd5648c9SAlexandre Bounine else 690dd5648c9SAlexandre Bounine pr_debug("RIO_EM: Invalid nextdev pointer (NULL)\n"); 691dd5648c9SAlexandre Bounine } 692dd5648c9SAlexandre Bounine rd_err: 693a93192a5SAlexandre Bounine rio_read_config_32(rdev, 694dd5648c9SAlexandre Bounine rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(pnum), 695dd5648c9SAlexandre Bounine &err_status); 696dd5648c9SAlexandre Bounine pr_debug("RIO_EM: SP%d_ERR_STS_CSR=0x%08x\n", pnum, err_status); 697dd5648c9SAlexandre Bounine } 698dd5648c9SAlexandre Bounine 699dd5648c9SAlexandre Bounine if ((err_status & RIO_PORT_N_ERR_STS_PW_INP_ES) && nextdev) { 700dd5648c9SAlexandre Bounine pr_debug("RIO_EM: servicing Input Error-Stopped state\n"); 701dd5648c9SAlexandre Bounine rio_get_input_status(nextdev, 702dd5648c9SAlexandre Bounine RIO_GET_PORT_NUM(nextdev->swpinfo), NULL); 703dd5648c9SAlexandre Bounine udelay(50); 704dd5648c9SAlexandre Bounine 705a93192a5SAlexandre Bounine rio_read_config_32(rdev, 706dd5648c9SAlexandre Bounine rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(pnum), 707dd5648c9SAlexandre Bounine &err_status); 708dd5648c9SAlexandre Bounine pr_debug("RIO_EM: SP%d_ERR_STS_CSR=0x%08x\n", pnum, err_status); 709dd5648c9SAlexandre Bounine } 710dd5648c9SAlexandre Bounine 711dd5648c9SAlexandre Bounine return (err_status & (RIO_PORT_N_ERR_STS_PW_OUT_ES | 712dd5648c9SAlexandre Bounine RIO_PORT_N_ERR_STS_PW_INP_ES)) ? 1 : 0; 713dd5648c9SAlexandre Bounine } 714dd5648c9SAlexandre Bounine 715dd5648c9SAlexandre Bounine /** 716e5cabeb3SAlexandre Bounine * rio_inb_pwrite_handler - process inbound port-write message 717e5cabeb3SAlexandre Bounine * @pw_msg: pointer to inbound port-write message 718e5cabeb3SAlexandre Bounine * 719e5cabeb3SAlexandre Bounine * Processes an inbound port-write message. Returns 0 if the request 720e5cabeb3SAlexandre Bounine * has been satisfied. 721e5cabeb3SAlexandre Bounine */ 722e5cabeb3SAlexandre Bounine int rio_inb_pwrite_handler(union rio_pw_msg *pw_msg) 723e5cabeb3SAlexandre Bounine { 724e5cabeb3SAlexandre Bounine struct rio_dev *rdev; 725dd5648c9SAlexandre Bounine u32 err_status, em_perrdet, em_ltlerrdet; 726e5cabeb3SAlexandre Bounine int rc, portnum; 727e5cabeb3SAlexandre Bounine 728e6536927SAlexandre Bounine rdev = rio_get_comptag((pw_msg->em.comptag & RIO_CTAG_UDEVID), NULL); 729e5cabeb3SAlexandre Bounine if (rdev == NULL) { 7306429cd49SAlexandre Bounine /* Device removed or enumeration error */ 7316429cd49SAlexandre Bounine pr_debug("RIO: %s No matching device for CTag 0x%08x\n", 732e5cabeb3SAlexandre Bounine __func__, pw_msg->em.comptag); 733e5cabeb3SAlexandre Bounine return -EIO; 734e5cabeb3SAlexandre Bounine } 735e5cabeb3SAlexandre Bounine 736e5cabeb3SAlexandre Bounine pr_debug("RIO: Port-Write message from %s\n", rio_name(rdev)); 737e5cabeb3SAlexandre Bounine 738e5cabeb3SAlexandre Bounine #ifdef DEBUG_PW 739e5cabeb3SAlexandre Bounine { 740e5cabeb3SAlexandre Bounine u32 i; 741e5cabeb3SAlexandre Bounine for (i = 0; i < RIO_PW_MSG_SIZE/sizeof(u32);) { 742dd5648c9SAlexandre Bounine pr_debug("0x%02x: %08x %08x %08x %08x\n", 743e5cabeb3SAlexandre Bounine i*4, pw_msg->raw[i], pw_msg->raw[i + 1], 744e5cabeb3SAlexandre Bounine pw_msg->raw[i + 2], pw_msg->raw[i + 3]); 745e5cabeb3SAlexandre Bounine i += 4; 746e5cabeb3SAlexandre Bounine } 747e5cabeb3SAlexandre Bounine } 748e5cabeb3SAlexandre Bounine #endif 749e5cabeb3SAlexandre Bounine 750e5cabeb3SAlexandre Bounine /* Call an external service function (if such is registered 751e5cabeb3SAlexandre Bounine * for this device). This may be the service for endpoints that send 752e5cabeb3SAlexandre Bounine * device-specific port-write messages. End-point messages expected 753e5cabeb3SAlexandre Bounine * to be handled completely by EP specific device driver. 754e5cabeb3SAlexandre Bounine * For switches rc==0 signals that no standard processing required. 755e5cabeb3SAlexandre Bounine */ 756e5cabeb3SAlexandre Bounine if (rdev->pwcback != NULL) { 757e5cabeb3SAlexandre Bounine rc = rdev->pwcback(rdev, pw_msg, 0); 758e5cabeb3SAlexandre Bounine if (rc == 0) 759e5cabeb3SAlexandre Bounine return 0; 760e5cabeb3SAlexandre Bounine } 761e5cabeb3SAlexandre Bounine 7626429cd49SAlexandre Bounine portnum = pw_msg->em.is_port & 0xFF; 7636429cd49SAlexandre Bounine 7646429cd49SAlexandre Bounine /* Check if device and route to it are functional: 7656429cd49SAlexandre Bounine * Sometimes devices may send PW message(s) just before being 7666429cd49SAlexandre Bounine * powered down (or link being lost). 7676429cd49SAlexandre Bounine */ 7686429cd49SAlexandre Bounine if (rio_chk_dev_access(rdev)) { 7696429cd49SAlexandre Bounine pr_debug("RIO: device access failed - get link partner\n"); 7706429cd49SAlexandre Bounine /* Scan route to the device and identify failed link. 7716429cd49SAlexandre Bounine * This will replace device and port reported in PW message. 7726429cd49SAlexandre Bounine * PW message should not be used after this point. 7736429cd49SAlexandre Bounine */ 7746429cd49SAlexandre Bounine if (rio_chk_dev_route(rdev, &rdev, &portnum)) { 7756429cd49SAlexandre Bounine pr_err("RIO: Route trace for %s failed\n", 7766429cd49SAlexandre Bounine rio_name(rdev)); 7776429cd49SAlexandre Bounine return -EIO; 7786429cd49SAlexandre Bounine } 7796429cd49SAlexandre Bounine pw_msg = NULL; 7806429cd49SAlexandre Bounine } 7816429cd49SAlexandre Bounine 782e5cabeb3SAlexandre Bounine /* For End-point devices processing stops here */ 783e5cabeb3SAlexandre Bounine if (!(rdev->pef & RIO_PEF_SWITCH)) 784e5cabeb3SAlexandre Bounine return 0; 785e5cabeb3SAlexandre Bounine 786e5cabeb3SAlexandre Bounine if (rdev->phys_efptr == 0) { 787e5cabeb3SAlexandre Bounine pr_err("RIO_PW: Bad switch initialization for %s\n", 788e5cabeb3SAlexandre Bounine rio_name(rdev)); 789e5cabeb3SAlexandre Bounine return 0; 790e5cabeb3SAlexandre Bounine } 791e5cabeb3SAlexandre Bounine 792e5cabeb3SAlexandre Bounine /* 793e5cabeb3SAlexandre Bounine * Process the port-write notification from switch 794e5cabeb3SAlexandre Bounine */ 795e5cabeb3SAlexandre Bounine if (rdev->rswitch->em_handle) 796e5cabeb3SAlexandre Bounine rdev->rswitch->em_handle(rdev, portnum); 797e5cabeb3SAlexandre Bounine 798a93192a5SAlexandre Bounine rio_read_config_32(rdev, 799e5cabeb3SAlexandre Bounine rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(portnum), 800e5cabeb3SAlexandre Bounine &err_status); 801e5cabeb3SAlexandre Bounine pr_debug("RIO_PW: SP%d_ERR_STS_CSR=0x%08x\n", portnum, err_status); 802e5cabeb3SAlexandre Bounine 803dd5648c9SAlexandre Bounine if (err_status & RIO_PORT_N_ERR_STS_PORT_OK) { 804dd5648c9SAlexandre Bounine 805dd5648c9SAlexandre Bounine if (!(rdev->rswitch->port_ok & (1 << portnum))) { 806dd5648c9SAlexandre Bounine rdev->rswitch->port_ok |= (1 << portnum); 807dd5648c9SAlexandre Bounine rio_set_port_lockout(rdev, portnum, 0); 808dd5648c9SAlexandre Bounine /* Schedule Insertion Service */ 809dd5648c9SAlexandre Bounine pr_debug("RIO_PW: Device Insertion on [%s]-P%d\n", 810dd5648c9SAlexandre Bounine rio_name(rdev), portnum); 811e5cabeb3SAlexandre Bounine } 812e5cabeb3SAlexandre Bounine 813dd5648c9SAlexandre Bounine /* Clear error-stopped states (if reported). 814dd5648c9SAlexandre Bounine * Depending on the link partner state, two attempts 815dd5648c9SAlexandre Bounine * may be needed for successful recovery. 816dd5648c9SAlexandre Bounine */ 817dd5648c9SAlexandre Bounine if (err_status & (RIO_PORT_N_ERR_STS_PW_OUT_ES | 818dd5648c9SAlexandre Bounine RIO_PORT_N_ERR_STS_PW_INP_ES)) { 819dd5648c9SAlexandre Bounine if (rio_clr_err_stopped(rdev, portnum, err_status)) 820dd5648c9SAlexandre Bounine rio_clr_err_stopped(rdev, portnum, 0); 821e5cabeb3SAlexandre Bounine } 822dd5648c9SAlexandre Bounine } else { /* if (err_status & RIO_PORT_N_ERR_STS_PORT_UNINIT) */ 823e5cabeb3SAlexandre Bounine 824e5cabeb3SAlexandre Bounine if (rdev->rswitch->port_ok & (1 << portnum)) { 825e5cabeb3SAlexandre Bounine rdev->rswitch->port_ok &= ~(1 << portnum); 826e5cabeb3SAlexandre Bounine rio_set_port_lockout(rdev, portnum, 1); 827e5cabeb3SAlexandre Bounine 828a93192a5SAlexandre Bounine rio_write_config_32(rdev, 829e5cabeb3SAlexandre Bounine rdev->phys_efptr + 830e5cabeb3SAlexandre Bounine RIO_PORT_N_ACK_STS_CSR(portnum), 831e5cabeb3SAlexandre Bounine RIO_PORT_N_ACK_CLEAR); 832e5cabeb3SAlexandre Bounine 833e5cabeb3SAlexandre Bounine /* Schedule Extraction Service */ 834e5cabeb3SAlexandre Bounine pr_debug("RIO_PW: Device Extraction on [%s]-P%d\n", 835e5cabeb3SAlexandre Bounine rio_name(rdev), portnum); 836e5cabeb3SAlexandre Bounine } 837dd5648c9SAlexandre Bounine } 838e5cabeb3SAlexandre Bounine 839a93192a5SAlexandre Bounine rio_read_config_32(rdev, 840dd5648c9SAlexandre Bounine rdev->em_efptr + RIO_EM_PN_ERR_DETECT(portnum), &em_perrdet); 841dd5648c9SAlexandre Bounine if (em_perrdet) { 842dd5648c9SAlexandre Bounine pr_debug("RIO_PW: RIO_EM_P%d_ERR_DETECT=0x%08x\n", 843dd5648c9SAlexandre Bounine portnum, em_perrdet); 844dd5648c9SAlexandre Bounine /* Clear EM Port N Error Detect CSR */ 845a93192a5SAlexandre Bounine rio_write_config_32(rdev, 846dd5648c9SAlexandre Bounine rdev->em_efptr + RIO_EM_PN_ERR_DETECT(portnum), 0); 847e5cabeb3SAlexandre Bounine } 848dd5648c9SAlexandre Bounine 849a93192a5SAlexandre Bounine rio_read_config_32(rdev, 850dd5648c9SAlexandre Bounine rdev->em_efptr + RIO_EM_LTL_ERR_DETECT, &em_ltlerrdet); 851dd5648c9SAlexandre Bounine if (em_ltlerrdet) { 852dd5648c9SAlexandre Bounine pr_debug("RIO_PW: RIO_EM_LTL_ERR_DETECT=0x%08x\n", 853dd5648c9SAlexandre Bounine em_ltlerrdet); 854dd5648c9SAlexandre Bounine /* Clear EM L/T Layer Error Detect CSR */ 855a93192a5SAlexandre Bounine rio_write_config_32(rdev, 856dd5648c9SAlexandre Bounine rdev->em_efptr + RIO_EM_LTL_ERR_DETECT, 0); 857e5cabeb3SAlexandre Bounine } 858e5cabeb3SAlexandre Bounine 859388c45ccSAlexandre Bounine /* Clear remaining error bits and Port-Write Pending bit */ 860a93192a5SAlexandre Bounine rio_write_config_32(rdev, 861dd5648c9SAlexandre Bounine rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(portnum), 862388c45ccSAlexandre Bounine err_status); 863e5cabeb3SAlexandre Bounine 864e5cabeb3SAlexandre Bounine return 0; 865e5cabeb3SAlexandre Bounine } 866e5cabeb3SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_inb_pwrite_handler); 867e5cabeb3SAlexandre Bounine 868e5cabeb3SAlexandre Bounine /** 869e5cabeb3SAlexandre Bounine * rio_mport_get_efb - get pointer to next extended features block 870e5cabeb3SAlexandre Bounine * @port: Master port to issue transaction 871e5cabeb3SAlexandre Bounine * @local: Indicate a local master port or remote device access 872e5cabeb3SAlexandre Bounine * @destid: Destination ID of the device 873e5cabeb3SAlexandre Bounine * @hopcount: Number of switch hops to the device 874e5cabeb3SAlexandre Bounine * @from: Offset of current Extended Feature block header (if 0 starts 875e5cabeb3SAlexandre Bounine * from ExtFeaturePtr) 876e5cabeb3SAlexandre Bounine */ 877e5cabeb3SAlexandre Bounine u32 878e5cabeb3SAlexandre Bounine rio_mport_get_efb(struct rio_mport *port, int local, u16 destid, 879e5cabeb3SAlexandre Bounine u8 hopcount, u32 from) 880e5cabeb3SAlexandre Bounine { 881e5cabeb3SAlexandre Bounine u32 reg_val; 882e5cabeb3SAlexandre Bounine 883e5cabeb3SAlexandre Bounine if (from == 0) { 884e5cabeb3SAlexandre Bounine if (local) 885e5cabeb3SAlexandre Bounine rio_local_read_config_32(port, RIO_ASM_INFO_CAR, 886e5cabeb3SAlexandre Bounine ®_val); 887e5cabeb3SAlexandre Bounine else 888e5cabeb3SAlexandre Bounine rio_mport_read_config_32(port, destid, hopcount, 889e5cabeb3SAlexandre Bounine RIO_ASM_INFO_CAR, ®_val); 890e5cabeb3SAlexandre Bounine return reg_val & RIO_EXT_FTR_PTR_MASK; 891e5cabeb3SAlexandre Bounine } else { 892e5cabeb3SAlexandre Bounine if (local) 893e5cabeb3SAlexandre Bounine rio_local_read_config_32(port, from, ®_val); 894e5cabeb3SAlexandre Bounine else 895e5cabeb3SAlexandre Bounine rio_mport_read_config_32(port, destid, hopcount, 896e5cabeb3SAlexandre Bounine from, ®_val); 897e5cabeb3SAlexandre Bounine return RIO_GET_BLOCK_ID(reg_val); 898e5cabeb3SAlexandre Bounine } 899e5cabeb3SAlexandre Bounine } 900e5cabeb3SAlexandre Bounine 901e5cabeb3SAlexandre Bounine /** 902394b701cSMatt Porter * rio_mport_get_feature - query for devices' extended features 903394b701cSMatt Porter * @port: Master port to issue transaction 904394b701cSMatt Porter * @local: Indicate a local master port or remote device access 905394b701cSMatt Porter * @destid: Destination ID of the device 906394b701cSMatt Porter * @hopcount: Number of switch hops to the device 907394b701cSMatt Porter * @ftr: Extended feature code 908394b701cSMatt Porter * 909394b701cSMatt Porter * Tell if a device supports a given RapidIO capability. 910394b701cSMatt Porter * Returns the offset of the requested extended feature 911394b701cSMatt Porter * block within the device's RIO configuration space or 912394b701cSMatt Porter * 0 in case the device does not support it. Possible 913394b701cSMatt Porter * values for @ftr: 914394b701cSMatt Porter * 915394b701cSMatt Porter * %RIO_EFB_PAR_EP_ID LP/LVDS EP Devices 916394b701cSMatt Porter * 917394b701cSMatt Porter * %RIO_EFB_PAR_EP_REC_ID LP/LVDS EP Recovery Devices 918394b701cSMatt Porter * 919394b701cSMatt Porter * %RIO_EFB_PAR_EP_FREE_ID LP/LVDS EP Free Devices 920394b701cSMatt Porter * 921394b701cSMatt Porter * %RIO_EFB_SER_EP_ID LP/Serial EP Devices 922394b701cSMatt Porter * 923394b701cSMatt Porter * %RIO_EFB_SER_EP_REC_ID LP/Serial EP Recovery Devices 924394b701cSMatt Porter * 925394b701cSMatt Porter * %RIO_EFB_SER_EP_FREE_ID LP/Serial EP Free Devices 926394b701cSMatt Porter */ 927394b701cSMatt Porter u32 928394b701cSMatt Porter rio_mport_get_feature(struct rio_mport * port, int local, u16 destid, 929394b701cSMatt Porter u8 hopcount, int ftr) 930394b701cSMatt Porter { 931394b701cSMatt Porter u32 asm_info, ext_ftr_ptr, ftr_header; 932394b701cSMatt Porter 933394b701cSMatt Porter if (local) 934394b701cSMatt Porter rio_local_read_config_32(port, RIO_ASM_INFO_CAR, &asm_info); 935394b701cSMatt Porter else 936394b701cSMatt Porter rio_mport_read_config_32(port, destid, hopcount, 937394b701cSMatt Porter RIO_ASM_INFO_CAR, &asm_info); 938394b701cSMatt Porter 939394b701cSMatt Porter ext_ftr_ptr = asm_info & RIO_EXT_FTR_PTR_MASK; 940394b701cSMatt Porter 941394b701cSMatt Porter while (ext_ftr_ptr) { 942394b701cSMatt Porter if (local) 943394b701cSMatt Porter rio_local_read_config_32(port, ext_ftr_ptr, 944394b701cSMatt Porter &ftr_header); 945394b701cSMatt Porter else 946394b701cSMatt Porter rio_mport_read_config_32(port, destid, hopcount, 947394b701cSMatt Porter ext_ftr_ptr, &ftr_header); 948394b701cSMatt Porter if (RIO_GET_BLOCK_ID(ftr_header) == ftr) 949394b701cSMatt Porter return ext_ftr_ptr; 950394b701cSMatt Porter if (!(ext_ftr_ptr = RIO_GET_BLOCK_PTR(ftr_header))) 951394b701cSMatt Porter break; 952394b701cSMatt Porter } 953394b701cSMatt Porter 954394b701cSMatt Porter return 0; 955394b701cSMatt Porter } 956394b701cSMatt Porter 957394b701cSMatt Porter /** 958394b701cSMatt Porter * rio_get_asm - Begin or continue searching for a RIO device by vid/did/asm_vid/asm_did 959394b701cSMatt Porter * @vid: RIO vid to match or %RIO_ANY_ID to match all vids 960394b701cSMatt Porter * @did: RIO did to match or %RIO_ANY_ID to match all dids 961394b701cSMatt Porter * @asm_vid: RIO asm_vid to match or %RIO_ANY_ID to match all asm_vids 962394b701cSMatt Porter * @asm_did: RIO asm_did to match or %RIO_ANY_ID to match all asm_dids 963394b701cSMatt Porter * @from: Previous RIO device found in search, or %NULL for new search 964394b701cSMatt Porter * 965394b701cSMatt Porter * Iterates through the list of known RIO devices. If a RIO device is 966394b701cSMatt Porter * found with a matching @vid, @did, @asm_vid, @asm_did, the reference 967394b701cSMatt Porter * count to the device is incrememted and a pointer to its device 968394b701cSMatt Porter * structure is returned. Otherwise, %NULL is returned. A new search 969394b701cSMatt Porter * is initiated by passing %NULL to the @from argument. Otherwise, if 970394b701cSMatt Porter * @from is not %NULL, searches continue from next device on the global 971394b701cSMatt Porter * list. The reference count for @from is always decremented if it is 972394b701cSMatt Porter * not %NULL. 973394b701cSMatt Porter */ 974394b701cSMatt Porter struct rio_dev *rio_get_asm(u16 vid, u16 did, 975394b701cSMatt Porter u16 asm_vid, u16 asm_did, struct rio_dev *from) 976394b701cSMatt Porter { 977394b701cSMatt Porter struct list_head *n; 978394b701cSMatt Porter struct rio_dev *rdev; 979394b701cSMatt Porter 980394b701cSMatt Porter WARN_ON(in_interrupt()); 981394b701cSMatt Porter spin_lock(&rio_global_list_lock); 982394b701cSMatt Porter n = from ? from->global_list.next : rio_devices.next; 983394b701cSMatt Porter 984394b701cSMatt Porter while (n && (n != &rio_devices)) { 985394b701cSMatt Porter rdev = rio_dev_g(n); 986394b701cSMatt Porter if ((vid == RIO_ANY_ID || rdev->vid == vid) && 987394b701cSMatt Porter (did == RIO_ANY_ID || rdev->did == did) && 988394b701cSMatt Porter (asm_vid == RIO_ANY_ID || rdev->asm_vid == asm_vid) && 989394b701cSMatt Porter (asm_did == RIO_ANY_ID || rdev->asm_did == asm_did)) 990394b701cSMatt Porter goto exit; 991394b701cSMatt Porter n = n->next; 992394b701cSMatt Porter } 993394b701cSMatt Porter rdev = NULL; 994394b701cSMatt Porter exit: 995394b701cSMatt Porter rio_dev_put(from); 996394b701cSMatt Porter rdev = rio_dev_get(rdev); 997394b701cSMatt Porter spin_unlock(&rio_global_list_lock); 998394b701cSMatt Porter return rdev; 999394b701cSMatt Porter } 1000394b701cSMatt Porter 1001394b701cSMatt Porter /** 1002394b701cSMatt Porter * rio_get_device - Begin or continue searching for a RIO device by vid/did 1003394b701cSMatt Porter * @vid: RIO vid to match or %RIO_ANY_ID to match all vids 1004394b701cSMatt Porter * @did: RIO did to match or %RIO_ANY_ID to match all dids 1005394b701cSMatt Porter * @from: Previous RIO device found in search, or %NULL for new search 1006394b701cSMatt Porter * 1007394b701cSMatt Porter * Iterates through the list of known RIO devices. If a RIO device is 1008394b701cSMatt Porter * found with a matching @vid and @did, the reference count to the 1009394b701cSMatt Porter * device is incrememted and a pointer to its device structure is returned. 1010394b701cSMatt Porter * Otherwise, %NULL is returned. A new search is initiated by passing %NULL 1011394b701cSMatt Porter * to the @from argument. Otherwise, if @from is not %NULL, searches 1012394b701cSMatt Porter * continue from next device on the global list. The reference count for 1013394b701cSMatt Porter * @from is always decremented if it is not %NULL. 1014394b701cSMatt Porter */ 1015394b701cSMatt Porter struct rio_dev *rio_get_device(u16 vid, u16 did, struct rio_dev *from) 1016394b701cSMatt Porter { 1017394b701cSMatt Porter return rio_get_asm(vid, did, RIO_ANY_ID, RIO_ANY_ID, from); 1018394b701cSMatt Porter } 1019394b701cSMatt Porter 102007590ff0SAlexandre Bounine /** 102107590ff0SAlexandre Bounine * rio_std_route_add_entry - Add switch route table entry using standard 102207590ff0SAlexandre Bounine * registers defined in RIO specification rev.1.3 102307590ff0SAlexandre Bounine * @mport: Master port to issue transaction 102407590ff0SAlexandre Bounine * @destid: Destination ID of the device 102507590ff0SAlexandre Bounine * @hopcount: Number of switch hops to the device 102607590ff0SAlexandre Bounine * @table: routing table ID (global or port-specific) 102707590ff0SAlexandre Bounine * @route_destid: destID entry in the RT 102807590ff0SAlexandre Bounine * @route_port: destination port for specified destID 102907590ff0SAlexandre Bounine */ 103007590ff0SAlexandre Bounine int rio_std_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount, 103107590ff0SAlexandre Bounine u16 table, u16 route_destid, u8 route_port) 103207590ff0SAlexandre Bounine { 103307590ff0SAlexandre Bounine if (table == RIO_GLOBAL_TABLE) { 103407590ff0SAlexandre Bounine rio_mport_write_config_32(mport, destid, hopcount, 103507590ff0SAlexandre Bounine RIO_STD_RTE_CONF_DESTID_SEL_CSR, 103607590ff0SAlexandre Bounine (u32)route_destid); 103707590ff0SAlexandre Bounine rio_mport_write_config_32(mport, destid, hopcount, 103807590ff0SAlexandre Bounine RIO_STD_RTE_CONF_PORT_SEL_CSR, 103907590ff0SAlexandre Bounine (u32)route_port); 104007590ff0SAlexandre Bounine } 1041e5cabeb3SAlexandre Bounine 104207590ff0SAlexandre Bounine udelay(10); 104307590ff0SAlexandre Bounine return 0; 104407590ff0SAlexandre Bounine } 104507590ff0SAlexandre Bounine 104607590ff0SAlexandre Bounine /** 104707590ff0SAlexandre Bounine * rio_std_route_get_entry - Read switch route table entry (port number) 1048638c5945SUwe Kleine-König * associated with specified destID using standard registers defined in RIO 104907590ff0SAlexandre Bounine * specification rev.1.3 105007590ff0SAlexandre Bounine * @mport: Master port to issue transaction 105107590ff0SAlexandre Bounine * @destid: Destination ID of the device 105207590ff0SAlexandre Bounine * @hopcount: Number of switch hops to the device 105307590ff0SAlexandre Bounine * @table: routing table ID (global or port-specific) 105407590ff0SAlexandre Bounine * @route_destid: destID entry in the RT 105507590ff0SAlexandre Bounine * @route_port: returned destination port for specified destID 105607590ff0SAlexandre Bounine */ 105707590ff0SAlexandre Bounine int rio_std_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount, 105807590ff0SAlexandre Bounine u16 table, u16 route_destid, u8 *route_port) 105907590ff0SAlexandre Bounine { 106007590ff0SAlexandre Bounine u32 result; 106107590ff0SAlexandre Bounine 106207590ff0SAlexandre Bounine if (table == RIO_GLOBAL_TABLE) { 106307590ff0SAlexandre Bounine rio_mport_write_config_32(mport, destid, hopcount, 106407590ff0SAlexandre Bounine RIO_STD_RTE_CONF_DESTID_SEL_CSR, route_destid); 106507590ff0SAlexandre Bounine rio_mport_read_config_32(mport, destid, hopcount, 106607590ff0SAlexandre Bounine RIO_STD_RTE_CONF_PORT_SEL_CSR, &result); 106707590ff0SAlexandre Bounine 106807590ff0SAlexandre Bounine *route_port = (u8)result; 106907590ff0SAlexandre Bounine } 107007590ff0SAlexandre Bounine 107107590ff0SAlexandre Bounine return 0; 107207590ff0SAlexandre Bounine } 107307590ff0SAlexandre Bounine 107407590ff0SAlexandre Bounine /** 107507590ff0SAlexandre Bounine * rio_std_route_clr_table - Clear swotch route table using standard registers 107607590ff0SAlexandre Bounine * defined in RIO specification rev.1.3. 107707590ff0SAlexandre Bounine * @mport: Master port to issue transaction 107807590ff0SAlexandre Bounine * @destid: Destination ID of the device 107907590ff0SAlexandre Bounine * @hopcount: Number of switch hops to the device 108007590ff0SAlexandre Bounine * @table: routing table ID (global or port-specific) 108107590ff0SAlexandre Bounine */ 108207590ff0SAlexandre Bounine int rio_std_route_clr_table(struct rio_mport *mport, u16 destid, u8 hopcount, 108307590ff0SAlexandre Bounine u16 table) 108407590ff0SAlexandre Bounine { 108507590ff0SAlexandre Bounine u32 max_destid = 0xff; 108607590ff0SAlexandre Bounine u32 i, pef, id_inc = 1, ext_cfg = 0; 108707590ff0SAlexandre Bounine u32 port_sel = RIO_INVALID_ROUTE; 108807590ff0SAlexandre Bounine 108907590ff0SAlexandre Bounine if (table == RIO_GLOBAL_TABLE) { 109007590ff0SAlexandre Bounine rio_mport_read_config_32(mport, destid, hopcount, 109107590ff0SAlexandre Bounine RIO_PEF_CAR, &pef); 109207590ff0SAlexandre Bounine 109307590ff0SAlexandre Bounine if (mport->sys_size) { 109407590ff0SAlexandre Bounine rio_mport_read_config_32(mport, destid, hopcount, 109507590ff0SAlexandre Bounine RIO_SWITCH_RT_LIMIT, 109607590ff0SAlexandre Bounine &max_destid); 109707590ff0SAlexandre Bounine max_destid &= RIO_RT_MAX_DESTID; 109807590ff0SAlexandre Bounine } 109907590ff0SAlexandre Bounine 110007590ff0SAlexandre Bounine if (pef & RIO_PEF_EXT_RT) { 110107590ff0SAlexandre Bounine ext_cfg = 0x80000000; 110207590ff0SAlexandre Bounine id_inc = 4; 110307590ff0SAlexandre Bounine port_sel = (RIO_INVALID_ROUTE << 24) | 110407590ff0SAlexandre Bounine (RIO_INVALID_ROUTE << 16) | 110507590ff0SAlexandre Bounine (RIO_INVALID_ROUTE << 8) | 110607590ff0SAlexandre Bounine RIO_INVALID_ROUTE; 110707590ff0SAlexandre Bounine } 110807590ff0SAlexandre Bounine 110907590ff0SAlexandre Bounine for (i = 0; i <= max_destid;) { 111007590ff0SAlexandre Bounine rio_mport_write_config_32(mport, destid, hopcount, 111107590ff0SAlexandre Bounine RIO_STD_RTE_CONF_DESTID_SEL_CSR, 111207590ff0SAlexandre Bounine ext_cfg | i); 111307590ff0SAlexandre Bounine rio_mport_write_config_32(mport, destid, hopcount, 111407590ff0SAlexandre Bounine RIO_STD_RTE_CONF_PORT_SEL_CSR, 111507590ff0SAlexandre Bounine port_sel); 111607590ff0SAlexandre Bounine i += id_inc; 111707590ff0SAlexandre Bounine } 111807590ff0SAlexandre Bounine } 111907590ff0SAlexandre Bounine 112007590ff0SAlexandre Bounine udelay(10); 112107590ff0SAlexandre Bounine return 0; 112207590ff0SAlexandre Bounine } 112307590ff0SAlexandre Bounine 1124e42d98ebSAlexandre Bounine #ifdef CONFIG_RAPIDIO_DMA_ENGINE 1125e42d98ebSAlexandre Bounine 1126e42d98ebSAlexandre Bounine static bool rio_chan_filter(struct dma_chan *chan, void *arg) 1127e42d98ebSAlexandre Bounine { 1128e42d98ebSAlexandre Bounine struct rio_dev *rdev = arg; 1129e42d98ebSAlexandre Bounine 1130e42d98ebSAlexandre Bounine /* Check that DMA device belongs to the right MPORT */ 1131e42d98ebSAlexandre Bounine return (rdev->net->hport == 1132e42d98ebSAlexandre Bounine container_of(chan->device, struct rio_mport, dma)); 1133e42d98ebSAlexandre Bounine } 1134e42d98ebSAlexandre Bounine 1135e42d98ebSAlexandre Bounine /** 1136e42d98ebSAlexandre Bounine * rio_request_dma - request RapidIO capable DMA channel that supports 1137e42d98ebSAlexandre Bounine * specified target RapidIO device. 1138e42d98ebSAlexandre Bounine * @rdev: RIO device control structure 1139e42d98ebSAlexandre Bounine * 1140e42d98ebSAlexandre Bounine * Returns pointer to allocated DMA channel or NULL if failed. 1141e42d98ebSAlexandre Bounine */ 1142e42d98ebSAlexandre Bounine struct dma_chan *rio_request_dma(struct rio_dev *rdev) 1143e42d98ebSAlexandre Bounine { 1144e42d98ebSAlexandre Bounine dma_cap_mask_t mask; 1145e42d98ebSAlexandre Bounine struct dma_chan *dchan; 1146e42d98ebSAlexandre Bounine 1147e42d98ebSAlexandre Bounine dma_cap_zero(mask); 1148e42d98ebSAlexandre Bounine dma_cap_set(DMA_SLAVE, mask); 1149e42d98ebSAlexandre Bounine dchan = dma_request_channel(mask, rio_chan_filter, rdev); 1150e42d98ebSAlexandre Bounine 1151e42d98ebSAlexandre Bounine return dchan; 1152e42d98ebSAlexandre Bounine } 1153e42d98ebSAlexandre Bounine EXPORT_SYMBOL_GPL(rio_request_dma); 1154e42d98ebSAlexandre Bounine 1155e42d98ebSAlexandre Bounine /** 1156e42d98ebSAlexandre Bounine * rio_release_dma - release specified DMA channel 1157e42d98ebSAlexandre Bounine * @dchan: DMA channel to release 1158e42d98ebSAlexandre Bounine */ 1159e42d98ebSAlexandre Bounine void rio_release_dma(struct dma_chan *dchan) 1160e42d98ebSAlexandre Bounine { 1161e42d98ebSAlexandre Bounine dma_release_channel(dchan); 1162e42d98ebSAlexandre Bounine } 1163e42d98ebSAlexandre Bounine EXPORT_SYMBOL_GPL(rio_release_dma); 1164e42d98ebSAlexandre Bounine 1165e42d98ebSAlexandre Bounine /** 1166e42d98ebSAlexandre Bounine * rio_dma_prep_slave_sg - RapidIO specific wrapper 1167e42d98ebSAlexandre Bounine * for device_prep_slave_sg callback defined by DMAENGINE. 1168e42d98ebSAlexandre Bounine * @rdev: RIO device control structure 1169e42d98ebSAlexandre Bounine * @dchan: DMA channel to configure 1170e42d98ebSAlexandre Bounine * @data: RIO specific data descriptor 1171e42d98ebSAlexandre Bounine * @direction: DMA data transfer direction (TO or FROM the device) 1172e42d98ebSAlexandre Bounine * @flags: dmaengine defined flags 1173e42d98ebSAlexandre Bounine * 1174e42d98ebSAlexandre Bounine * Initializes RapidIO capable DMA channel for the specified data transfer. 1175e42d98ebSAlexandre Bounine * Uses DMA channel private extension to pass information related to remote 1176e42d98ebSAlexandre Bounine * target RIO device. 1177e42d98ebSAlexandre Bounine * Returns pointer to DMA transaction descriptor or NULL if failed. 1178e42d98ebSAlexandre Bounine */ 1179e42d98ebSAlexandre Bounine struct dma_async_tx_descriptor *rio_dma_prep_slave_sg(struct rio_dev *rdev, 1180e42d98ebSAlexandre Bounine struct dma_chan *dchan, struct rio_dma_data *data, 1181e42d98ebSAlexandre Bounine enum dma_transfer_direction direction, unsigned long flags) 1182e42d98ebSAlexandre Bounine { 1183e42d98ebSAlexandre Bounine struct dma_async_tx_descriptor *txd = NULL; 1184e42d98ebSAlexandre Bounine struct rio_dma_ext rio_ext; 1185e42d98ebSAlexandre Bounine 1186e42d98ebSAlexandre Bounine if (dchan->device->device_prep_slave_sg == NULL) { 1187e42d98ebSAlexandre Bounine pr_err("%s: prep_rio_sg == NULL\n", __func__); 1188e42d98ebSAlexandre Bounine return NULL; 1189e42d98ebSAlexandre Bounine } 1190e42d98ebSAlexandre Bounine 1191e42d98ebSAlexandre Bounine rio_ext.destid = rdev->destid; 1192e42d98ebSAlexandre Bounine rio_ext.rio_addr_u = data->rio_addr_u; 1193e42d98ebSAlexandre Bounine rio_ext.rio_addr = data->rio_addr; 1194e42d98ebSAlexandre Bounine rio_ext.wr_type = data->wr_type; 1195e42d98ebSAlexandre Bounine 1196e42d98ebSAlexandre Bounine txd = dmaengine_prep_rio_sg(dchan, data->sg, data->sg_len, 1197e42d98ebSAlexandre Bounine direction, flags, &rio_ext); 1198e42d98ebSAlexandre Bounine 1199e42d98ebSAlexandre Bounine return txd; 1200e42d98ebSAlexandre Bounine } 1201e42d98ebSAlexandre Bounine EXPORT_SYMBOL_GPL(rio_dma_prep_slave_sg); 1202e42d98ebSAlexandre Bounine 1203e42d98ebSAlexandre Bounine #endif /* CONFIG_RAPIDIO_DMA_ENGINE */ 1204e42d98ebSAlexandre Bounine 1205394b701cSMatt Porter static void rio_fixup_device(struct rio_dev *dev) 1206394b701cSMatt Porter { 1207394b701cSMatt Porter } 1208394b701cSMatt Porter 1209394b701cSMatt Porter static int __devinit rio_init(void) 1210394b701cSMatt Porter { 1211394b701cSMatt Porter struct rio_dev *dev = NULL; 1212394b701cSMatt Porter 1213394b701cSMatt Porter while ((dev = rio_get_device(RIO_ANY_ID, RIO_ANY_ID, dev)) != NULL) { 1214394b701cSMatt Porter rio_fixup_device(dev); 1215394b701cSMatt Porter } 1216394b701cSMatt Porter return 0; 1217394b701cSMatt Porter } 1218394b701cSMatt Porter 121937d33d15SAl Viro int __devinit rio_init_mports(void) 1220394b701cSMatt Porter { 1221394b701cSMatt Porter struct rio_mport *port; 1222394b701cSMatt Porter 1223394b701cSMatt Porter list_for_each_entry(port, &rio_mports, node) { 1224394b701cSMatt Porter if (port->host_deviceid >= 0) 1225394b701cSMatt Porter rio_enum_mport(port); 1226394b701cSMatt Porter else 1227394b701cSMatt Porter rio_disc_mport(port); 1228394b701cSMatt Porter } 1229394b701cSMatt Porter 12302f809985SAlexandre Bounine rio_init(); 12312f809985SAlexandre Bounine 1232c1256ebeSAlexandre Bounine return 0; 1233394b701cSMatt Porter } 1234394b701cSMatt Porter 12352f809985SAlexandre Bounine device_initcall_sync(rio_init_mports); 12362f809985SAlexandre Bounine 1237569fccb6SAlexandre Bounine static int hdids[RIO_MAX_MPORTS + 1]; 1238569fccb6SAlexandre Bounine 1239569fccb6SAlexandre Bounine static int rio_get_hdid(int index) 1240569fccb6SAlexandre Bounine { 1241569fccb6SAlexandre Bounine if (!hdids[0] || hdids[0] <= index || index >= RIO_MAX_MPORTS) 1242569fccb6SAlexandre Bounine return -1; 1243569fccb6SAlexandre Bounine 1244569fccb6SAlexandre Bounine return hdids[index + 1]; 1245569fccb6SAlexandre Bounine } 1246569fccb6SAlexandre Bounine 1247569fccb6SAlexandre Bounine static int rio_hdid_setup(char *str) 1248569fccb6SAlexandre Bounine { 1249569fccb6SAlexandre Bounine (void)get_options(str, ARRAY_SIZE(hdids), hdids); 1250569fccb6SAlexandre Bounine return 1; 1251569fccb6SAlexandre Bounine } 1252569fccb6SAlexandre Bounine 1253569fccb6SAlexandre Bounine __setup("riohdid=", rio_hdid_setup); 1254569fccb6SAlexandre Bounine 125559f99965SAlexandre Bounine int rio_register_mport(struct rio_mport *port) 1256394b701cSMatt Porter { 1257569fccb6SAlexandre Bounine if (next_portid >= RIO_MAX_MPORTS) { 1258569fccb6SAlexandre Bounine pr_err("RIO: reached specified max number of mports\n"); 125959f99965SAlexandre Bounine return 1; 1260569fccb6SAlexandre Bounine } 1261569fccb6SAlexandre Bounine 1262569fccb6SAlexandre Bounine port->id = next_portid++; 1263569fccb6SAlexandre Bounine port->host_deviceid = rio_get_hdid(port->id); 1264394b701cSMatt Porter list_add_tail(&port->node, &rio_mports); 126559f99965SAlexandre Bounine return 0; 1266394b701cSMatt Porter } 1267394b701cSMatt Porter 1268394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_local_get_device_id); 1269394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_get_device); 1270394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_get_asm); 1271394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_request_inb_dbell); 1272394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_release_inb_dbell); 1273394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_request_outb_dbell); 1274394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_release_outb_dbell); 1275394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_request_inb_mbox); 1276394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_release_inb_mbox); 1277394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_request_outb_mbox); 1278394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_release_outb_mbox); 1279