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); 35394b701cSMatt Porter 36394b701cSMatt Porter /** 37394b701cSMatt Porter * rio_local_get_device_id - Get the base/extended device id for a port 38394b701cSMatt Porter * @port: RIO master port from which to get the deviceid 39394b701cSMatt Porter * 40394b701cSMatt Porter * Reads the base/extended device id from the local device 41394b701cSMatt Porter * implementing the master port. Returns the 8/16-bit device 42394b701cSMatt Porter * id. 43394b701cSMatt Porter */ 44394b701cSMatt Porter u16 rio_local_get_device_id(struct rio_mport *port) 45394b701cSMatt Porter { 46394b701cSMatt Porter u32 result; 47394b701cSMatt Porter 48394b701cSMatt Porter rio_local_read_config_32(port, RIO_DID_CSR, &result); 49394b701cSMatt Porter 50e0423236SZhang Wei return (RIO_GET_DID(port->sys_size, result)); 51394b701cSMatt Porter } 52394b701cSMatt Porter 53394b701cSMatt Porter /** 54394b701cSMatt Porter * rio_request_inb_mbox - request inbound mailbox service 55394b701cSMatt Porter * @mport: RIO master port from which to allocate the mailbox resource 566978bbc0SMatt Porter * @dev_id: Device specific pointer to pass on event 57394b701cSMatt Porter * @mbox: Mailbox number to claim 58394b701cSMatt Porter * @entries: Number of entries in inbound mailbox queue 59394b701cSMatt Porter * @minb: Callback to execute when inbound message is received 60394b701cSMatt Porter * 61394b701cSMatt Porter * Requests ownership of an inbound mailbox resource and binds 62394b701cSMatt Porter * a callback function to the resource. Returns %0 on success. 63394b701cSMatt Porter */ 64394b701cSMatt Porter int rio_request_inb_mbox(struct rio_mport *mport, 656978bbc0SMatt Porter void *dev_id, 66394b701cSMatt Porter int mbox, 67394b701cSMatt Porter int entries, 686978bbc0SMatt Porter void (*minb) (struct rio_mport * mport, void *dev_id, int mbox, 69394b701cSMatt Porter int slot)) 70394b701cSMatt Porter { 71394b701cSMatt Porter int rc = 0; 72394b701cSMatt Porter 73394b701cSMatt Porter struct resource *res = kmalloc(sizeof(struct resource), GFP_KERNEL); 74394b701cSMatt Porter 75394b701cSMatt Porter if (res) { 76394b701cSMatt Porter rio_init_mbox_res(res, mbox, mbox); 77394b701cSMatt Porter 78394b701cSMatt Porter /* Make sure this mailbox isn't in use */ 79394b701cSMatt Porter if ((rc = 80394b701cSMatt Porter request_resource(&mport->riores[RIO_INB_MBOX_RESOURCE], 81394b701cSMatt Porter res)) < 0) { 82394b701cSMatt Porter kfree(res); 83394b701cSMatt Porter goto out; 84394b701cSMatt Porter } 85394b701cSMatt Porter 86394b701cSMatt Porter mport->inb_msg[mbox].res = res; 87394b701cSMatt Porter 88394b701cSMatt Porter /* Hook the inbound message callback */ 89394b701cSMatt Porter mport->inb_msg[mbox].mcback = minb; 90394b701cSMatt Porter 916978bbc0SMatt Porter rc = rio_open_inb_mbox(mport, dev_id, mbox, entries); 92394b701cSMatt Porter } else 93394b701cSMatt Porter rc = -ENOMEM; 94394b701cSMatt Porter 95394b701cSMatt Porter out: 96394b701cSMatt Porter return rc; 97394b701cSMatt Porter } 98394b701cSMatt Porter 99394b701cSMatt Porter /** 100394b701cSMatt Porter * rio_release_inb_mbox - release inbound mailbox message service 101394b701cSMatt Porter * @mport: RIO master port from which to release the mailbox resource 102394b701cSMatt Porter * @mbox: Mailbox number to release 103394b701cSMatt Porter * 104394b701cSMatt Porter * Releases ownership of an inbound mailbox resource. Returns 0 105394b701cSMatt Porter * if the request has been satisfied. 106394b701cSMatt Porter */ 107394b701cSMatt Porter int rio_release_inb_mbox(struct rio_mport *mport, int mbox) 108394b701cSMatt Porter { 109394b701cSMatt Porter rio_close_inb_mbox(mport, mbox); 110394b701cSMatt Porter 111394b701cSMatt Porter /* Release the mailbox resource */ 112394b701cSMatt Porter return release_resource(mport->inb_msg[mbox].res); 113394b701cSMatt Porter } 114394b701cSMatt Porter 115394b701cSMatt Porter /** 116394b701cSMatt Porter * rio_request_outb_mbox - request outbound mailbox service 117394b701cSMatt Porter * @mport: RIO master port from which to allocate the mailbox resource 1186978bbc0SMatt Porter * @dev_id: Device specific pointer to pass on event 119394b701cSMatt Porter * @mbox: Mailbox number to claim 120394b701cSMatt Porter * @entries: Number of entries in outbound mailbox queue 121394b701cSMatt Porter * @moutb: Callback to execute when outbound message is sent 122394b701cSMatt Porter * 123394b701cSMatt Porter * Requests ownership of an outbound mailbox resource and binds 124394b701cSMatt Porter * a callback function to the resource. Returns 0 on success. 125394b701cSMatt Porter */ 126394b701cSMatt Porter int rio_request_outb_mbox(struct rio_mport *mport, 1276978bbc0SMatt Porter void *dev_id, 128394b701cSMatt Porter int mbox, 129394b701cSMatt Porter int entries, 1306978bbc0SMatt Porter void (*moutb) (struct rio_mport * mport, void *dev_id, int mbox, int slot)) 131394b701cSMatt Porter { 132394b701cSMatt Porter int rc = 0; 133394b701cSMatt Porter 134394b701cSMatt Porter struct resource *res = kmalloc(sizeof(struct resource), GFP_KERNEL); 135394b701cSMatt Porter 136394b701cSMatt Porter if (res) { 137394b701cSMatt Porter rio_init_mbox_res(res, mbox, mbox); 138394b701cSMatt Porter 139394b701cSMatt Porter /* Make sure this outbound mailbox isn't in use */ 140394b701cSMatt Porter if ((rc = 141394b701cSMatt Porter request_resource(&mport->riores[RIO_OUTB_MBOX_RESOURCE], 142394b701cSMatt Porter res)) < 0) { 143394b701cSMatt Porter kfree(res); 144394b701cSMatt Porter goto out; 145394b701cSMatt Porter } 146394b701cSMatt Porter 147394b701cSMatt Porter mport->outb_msg[mbox].res = res; 148394b701cSMatt Porter 149394b701cSMatt Porter /* Hook the inbound message callback */ 150394b701cSMatt Porter mport->outb_msg[mbox].mcback = moutb; 151394b701cSMatt Porter 1526978bbc0SMatt Porter rc = rio_open_outb_mbox(mport, dev_id, mbox, entries); 153394b701cSMatt Porter } else 154394b701cSMatt Porter rc = -ENOMEM; 155394b701cSMatt Porter 156394b701cSMatt Porter out: 157394b701cSMatt Porter return rc; 158394b701cSMatt Porter } 159394b701cSMatt Porter 160394b701cSMatt Porter /** 161394b701cSMatt Porter * rio_release_outb_mbox - release outbound mailbox message service 162394b701cSMatt Porter * @mport: RIO master port from which to release the mailbox resource 163394b701cSMatt Porter * @mbox: Mailbox number to release 164394b701cSMatt Porter * 165394b701cSMatt Porter * Releases ownership of an inbound mailbox resource. Returns 0 166394b701cSMatt Porter * if the request has been satisfied. 167394b701cSMatt Porter */ 168394b701cSMatt Porter int rio_release_outb_mbox(struct rio_mport *mport, int mbox) 169394b701cSMatt Porter { 170394b701cSMatt Porter rio_close_outb_mbox(mport, mbox); 171394b701cSMatt Porter 172394b701cSMatt Porter /* Release the mailbox resource */ 173394b701cSMatt Porter return release_resource(mport->outb_msg[mbox].res); 174394b701cSMatt Porter } 175394b701cSMatt Porter 176394b701cSMatt Porter /** 177394b701cSMatt Porter * rio_setup_inb_dbell - bind inbound doorbell callback 178394b701cSMatt Porter * @mport: RIO master port to bind the doorbell callback 1796978bbc0SMatt Porter * @dev_id: Device specific pointer to pass on event 180394b701cSMatt Porter * @res: Doorbell message resource 181394b701cSMatt Porter * @dinb: Callback to execute when doorbell is received 182394b701cSMatt Porter * 183394b701cSMatt Porter * Adds a doorbell resource/callback pair into a port's 184394b701cSMatt Porter * doorbell event list. Returns 0 if the request has been 185394b701cSMatt Porter * satisfied. 186394b701cSMatt Porter */ 187394b701cSMatt Porter static int 1886978bbc0SMatt Porter rio_setup_inb_dbell(struct rio_mport *mport, void *dev_id, struct resource *res, 1896978bbc0SMatt Porter void (*dinb) (struct rio_mport * mport, void *dev_id, u16 src, u16 dst, 190394b701cSMatt Porter u16 info)) 191394b701cSMatt Porter { 192394b701cSMatt Porter int rc = 0; 193394b701cSMatt Porter struct rio_dbell *dbell; 194394b701cSMatt Porter 195394b701cSMatt Porter if (!(dbell = kmalloc(sizeof(struct rio_dbell), GFP_KERNEL))) { 196394b701cSMatt Porter rc = -ENOMEM; 197394b701cSMatt Porter goto out; 198394b701cSMatt Porter } 199394b701cSMatt Porter 200394b701cSMatt Porter dbell->res = res; 201394b701cSMatt Porter dbell->dinb = dinb; 2026978bbc0SMatt Porter dbell->dev_id = dev_id; 203394b701cSMatt Porter 204394b701cSMatt Porter list_add_tail(&dbell->node, &mport->dbells); 205394b701cSMatt Porter 206394b701cSMatt Porter out: 207394b701cSMatt Porter return rc; 208394b701cSMatt Porter } 209394b701cSMatt Porter 210394b701cSMatt Porter /** 211394b701cSMatt Porter * rio_request_inb_dbell - request inbound doorbell message service 212394b701cSMatt Porter * @mport: RIO master port from which to allocate the doorbell resource 2136978bbc0SMatt Porter * @dev_id: Device specific pointer to pass on event 214394b701cSMatt Porter * @start: Doorbell info range start 215394b701cSMatt Porter * @end: Doorbell info range end 216394b701cSMatt Porter * @dinb: Callback to execute when doorbell is received 217394b701cSMatt Porter * 218394b701cSMatt Porter * Requests ownership of an inbound doorbell resource and binds 219394b701cSMatt Porter * a callback function to the resource. Returns 0 if the request 220394b701cSMatt Porter * has been satisfied. 221394b701cSMatt Porter */ 222394b701cSMatt Porter int rio_request_inb_dbell(struct rio_mport *mport, 2236978bbc0SMatt Porter void *dev_id, 224394b701cSMatt Porter u16 start, 225394b701cSMatt Porter u16 end, 2266978bbc0SMatt Porter void (*dinb) (struct rio_mport * mport, void *dev_id, u16 src, 227394b701cSMatt Porter u16 dst, u16 info)) 228394b701cSMatt Porter { 229394b701cSMatt Porter int rc = 0; 230394b701cSMatt Porter 231394b701cSMatt Porter struct resource *res = kmalloc(sizeof(struct resource), GFP_KERNEL); 232394b701cSMatt Porter 233394b701cSMatt Porter if (res) { 234394b701cSMatt Porter rio_init_dbell_res(res, start, end); 235394b701cSMatt Porter 236394b701cSMatt Porter /* Make sure these doorbells aren't in use */ 237394b701cSMatt Porter if ((rc = 238394b701cSMatt Porter request_resource(&mport->riores[RIO_DOORBELL_RESOURCE], 239394b701cSMatt Porter res)) < 0) { 240394b701cSMatt Porter kfree(res); 241394b701cSMatt Porter goto out; 242394b701cSMatt Porter } 243394b701cSMatt Porter 244394b701cSMatt Porter /* Hook the doorbell callback */ 2456978bbc0SMatt Porter rc = rio_setup_inb_dbell(mport, dev_id, res, dinb); 246394b701cSMatt Porter } else 247394b701cSMatt Porter rc = -ENOMEM; 248394b701cSMatt Porter 249394b701cSMatt Porter out: 250394b701cSMatt Porter return rc; 251394b701cSMatt Porter } 252394b701cSMatt Porter 253394b701cSMatt Porter /** 254394b701cSMatt Porter * rio_release_inb_dbell - release inbound doorbell message service 255394b701cSMatt Porter * @mport: RIO master port from which to release the doorbell resource 256394b701cSMatt Porter * @start: Doorbell info range start 257394b701cSMatt Porter * @end: Doorbell info range end 258394b701cSMatt Porter * 259394b701cSMatt Porter * Releases ownership of an inbound doorbell resource and removes 260394b701cSMatt Porter * callback from the doorbell event list. Returns 0 if the request 261394b701cSMatt Porter * has been satisfied. 262394b701cSMatt Porter */ 263394b701cSMatt Porter int rio_release_inb_dbell(struct rio_mport *mport, u16 start, u16 end) 264394b701cSMatt Porter { 265394b701cSMatt Porter int rc = 0, found = 0; 266394b701cSMatt Porter struct rio_dbell *dbell; 267394b701cSMatt Porter 268394b701cSMatt Porter list_for_each_entry(dbell, &mport->dbells, node) { 269394b701cSMatt Porter if ((dbell->res->start == start) && (dbell->res->end == end)) { 270394b701cSMatt Porter found = 1; 271394b701cSMatt Porter break; 272394b701cSMatt Porter } 273394b701cSMatt Porter } 274394b701cSMatt Porter 275394b701cSMatt Porter /* If we can't find an exact match, fail */ 276394b701cSMatt Porter if (!found) { 277394b701cSMatt Porter rc = -EINVAL; 278394b701cSMatt Porter goto out; 279394b701cSMatt Porter } 280394b701cSMatt Porter 281394b701cSMatt Porter /* Delete from list */ 282394b701cSMatt Porter list_del(&dbell->node); 283394b701cSMatt Porter 284394b701cSMatt Porter /* Release the doorbell resource */ 285394b701cSMatt Porter rc = release_resource(dbell->res); 286394b701cSMatt Porter 287394b701cSMatt Porter /* Free the doorbell event */ 288394b701cSMatt Porter kfree(dbell); 289394b701cSMatt Porter 290394b701cSMatt Porter out: 291394b701cSMatt Porter return rc; 292394b701cSMatt Porter } 293394b701cSMatt Porter 294394b701cSMatt Porter /** 295394b701cSMatt Porter * rio_request_outb_dbell - request outbound doorbell message range 296394b701cSMatt Porter * @rdev: RIO device from which to allocate the doorbell resource 297394b701cSMatt Porter * @start: Doorbell message range start 298394b701cSMatt Porter * @end: Doorbell message range end 299394b701cSMatt Porter * 300394b701cSMatt Porter * Requests ownership of a doorbell message range. Returns a resource 301394b701cSMatt Porter * if the request has been satisfied or %NULL on failure. 302394b701cSMatt Porter */ 303394b701cSMatt Porter struct resource *rio_request_outb_dbell(struct rio_dev *rdev, u16 start, 304394b701cSMatt Porter u16 end) 305394b701cSMatt Porter { 306394b701cSMatt Porter struct resource *res = kmalloc(sizeof(struct resource), GFP_KERNEL); 307394b701cSMatt Porter 308394b701cSMatt Porter if (res) { 309394b701cSMatt Porter rio_init_dbell_res(res, start, end); 310394b701cSMatt Porter 311394b701cSMatt Porter /* Make sure these doorbells aren't in use */ 312394b701cSMatt Porter if (request_resource(&rdev->riores[RIO_DOORBELL_RESOURCE], res) 313394b701cSMatt Porter < 0) { 314394b701cSMatt Porter kfree(res); 315394b701cSMatt Porter res = NULL; 316394b701cSMatt Porter } 317394b701cSMatt Porter } 318394b701cSMatt Porter 319394b701cSMatt Porter return res; 320394b701cSMatt Porter } 321394b701cSMatt Porter 322394b701cSMatt Porter /** 323394b701cSMatt Porter * rio_release_outb_dbell - release outbound doorbell message range 324394b701cSMatt Porter * @rdev: RIO device from which to release the doorbell resource 325394b701cSMatt Porter * @res: Doorbell resource to be freed 326394b701cSMatt Porter * 327394b701cSMatt Porter * Releases ownership of a doorbell message range. Returns 0 if the 328394b701cSMatt Porter * request has been satisfied. 329394b701cSMatt Porter */ 330394b701cSMatt Porter int rio_release_outb_dbell(struct rio_dev *rdev, struct resource *res) 331394b701cSMatt Porter { 332394b701cSMatt Porter int rc = release_resource(res); 333394b701cSMatt Porter 334394b701cSMatt Porter kfree(res); 335394b701cSMatt Porter 336394b701cSMatt Porter return rc; 337394b701cSMatt Porter } 338394b701cSMatt Porter 339394b701cSMatt Porter /** 340e5cabeb3SAlexandre Bounine * rio_request_inb_pwrite - request inbound port-write message service 34197ef6f74SRandy Dunlap * @rdev: RIO device to which register inbound port-write callback routine 342e5cabeb3SAlexandre Bounine * @pwcback: Callback routine to execute when port-write is received 343e5cabeb3SAlexandre Bounine * 344e5cabeb3SAlexandre Bounine * Binds a port-write callback function to the RapidIO device. 345e5cabeb3SAlexandre Bounine * Returns 0 if the request has been satisfied. 346e5cabeb3SAlexandre Bounine */ 347e5cabeb3SAlexandre Bounine int rio_request_inb_pwrite(struct rio_dev *rdev, 348e5cabeb3SAlexandre Bounine int (*pwcback)(struct rio_dev *rdev, union rio_pw_msg *msg, int step)) 349e5cabeb3SAlexandre Bounine { 350e5cabeb3SAlexandre Bounine int rc = 0; 351e5cabeb3SAlexandre Bounine 352e5cabeb3SAlexandre Bounine spin_lock(&rio_global_list_lock); 353e5cabeb3SAlexandre Bounine if (rdev->pwcback != NULL) 354e5cabeb3SAlexandre Bounine rc = -ENOMEM; 355e5cabeb3SAlexandre Bounine else 356e5cabeb3SAlexandre Bounine rdev->pwcback = pwcback; 357e5cabeb3SAlexandre Bounine 358e5cabeb3SAlexandre Bounine spin_unlock(&rio_global_list_lock); 359e5cabeb3SAlexandre Bounine return rc; 360e5cabeb3SAlexandre Bounine } 361e5cabeb3SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_request_inb_pwrite); 362e5cabeb3SAlexandre Bounine 363e5cabeb3SAlexandre Bounine /** 364e5cabeb3SAlexandre Bounine * rio_release_inb_pwrite - release inbound port-write message service 365e5cabeb3SAlexandre Bounine * @rdev: RIO device which registered for inbound port-write callback 366e5cabeb3SAlexandre Bounine * 367e5cabeb3SAlexandre Bounine * Removes callback from the rio_dev structure. Returns 0 if the request 368e5cabeb3SAlexandre Bounine * has been satisfied. 369e5cabeb3SAlexandre Bounine */ 370e5cabeb3SAlexandre Bounine int rio_release_inb_pwrite(struct rio_dev *rdev) 371e5cabeb3SAlexandre Bounine { 372e5cabeb3SAlexandre Bounine int rc = -ENOMEM; 373e5cabeb3SAlexandre Bounine 374e5cabeb3SAlexandre Bounine spin_lock(&rio_global_list_lock); 375e5cabeb3SAlexandre Bounine if (rdev->pwcback) { 376e5cabeb3SAlexandre Bounine rdev->pwcback = NULL; 377e5cabeb3SAlexandre Bounine rc = 0; 378e5cabeb3SAlexandre Bounine } 379e5cabeb3SAlexandre Bounine 380e5cabeb3SAlexandre Bounine spin_unlock(&rio_global_list_lock); 381e5cabeb3SAlexandre Bounine return rc; 382e5cabeb3SAlexandre Bounine } 383e5cabeb3SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_release_inb_pwrite); 384e5cabeb3SAlexandre Bounine 385e5cabeb3SAlexandre Bounine /** 386e5cabeb3SAlexandre Bounine * rio_mport_get_physefb - Helper function that returns register offset 387e5cabeb3SAlexandre Bounine * for Physical Layer Extended Features Block. 38897ef6f74SRandy Dunlap * @port: Master port to issue transaction 38997ef6f74SRandy Dunlap * @local: Indicate a local master port or remote device access 39097ef6f74SRandy Dunlap * @destid: Destination ID of the device 39197ef6f74SRandy Dunlap * @hopcount: Number of switch hops to the device 392e5cabeb3SAlexandre Bounine */ 393e5cabeb3SAlexandre Bounine u32 394e5cabeb3SAlexandre Bounine rio_mport_get_physefb(struct rio_mport *port, int local, 395e5cabeb3SAlexandre Bounine u16 destid, u8 hopcount) 396e5cabeb3SAlexandre Bounine { 397e5cabeb3SAlexandre Bounine u32 ext_ftr_ptr; 398e5cabeb3SAlexandre Bounine u32 ftr_header; 399e5cabeb3SAlexandre Bounine 400e5cabeb3SAlexandre Bounine ext_ftr_ptr = rio_mport_get_efb(port, local, destid, hopcount, 0); 401e5cabeb3SAlexandre Bounine 402e5cabeb3SAlexandre Bounine while (ext_ftr_ptr) { 403e5cabeb3SAlexandre Bounine if (local) 404e5cabeb3SAlexandre Bounine rio_local_read_config_32(port, ext_ftr_ptr, 405e5cabeb3SAlexandre Bounine &ftr_header); 406e5cabeb3SAlexandre Bounine else 407e5cabeb3SAlexandre Bounine rio_mport_read_config_32(port, destid, hopcount, 408e5cabeb3SAlexandre Bounine ext_ftr_ptr, &ftr_header); 409e5cabeb3SAlexandre Bounine 410e5cabeb3SAlexandre Bounine ftr_header = RIO_GET_BLOCK_ID(ftr_header); 411e5cabeb3SAlexandre Bounine switch (ftr_header) { 412e5cabeb3SAlexandre Bounine 413e5cabeb3SAlexandre Bounine case RIO_EFB_SER_EP_ID_V13P: 414e5cabeb3SAlexandre Bounine case RIO_EFB_SER_EP_REC_ID_V13P: 415e5cabeb3SAlexandre Bounine case RIO_EFB_SER_EP_FREE_ID_V13P: 416e5cabeb3SAlexandre Bounine case RIO_EFB_SER_EP_ID: 417e5cabeb3SAlexandre Bounine case RIO_EFB_SER_EP_REC_ID: 418e5cabeb3SAlexandre Bounine case RIO_EFB_SER_EP_FREE_ID: 419e5cabeb3SAlexandre Bounine case RIO_EFB_SER_EP_FREC_ID: 420e5cabeb3SAlexandre Bounine 421e5cabeb3SAlexandre Bounine return ext_ftr_ptr; 422e5cabeb3SAlexandre Bounine 423e5cabeb3SAlexandre Bounine default: 424e5cabeb3SAlexandre Bounine break; 425e5cabeb3SAlexandre Bounine } 426e5cabeb3SAlexandre Bounine 427e5cabeb3SAlexandre Bounine ext_ftr_ptr = rio_mport_get_efb(port, local, destid, 428e5cabeb3SAlexandre Bounine hopcount, ext_ftr_ptr); 429e5cabeb3SAlexandre Bounine } 430e5cabeb3SAlexandre Bounine 431e5cabeb3SAlexandre Bounine return ext_ftr_ptr; 432e5cabeb3SAlexandre Bounine } 433e5cabeb3SAlexandre Bounine 434e5cabeb3SAlexandre Bounine /** 435e5cabeb3SAlexandre Bounine * rio_get_comptag - Begin or continue searching for a RIO device by component tag 43697ef6f74SRandy Dunlap * @comp_tag: RIO component tag to match 437e5cabeb3SAlexandre Bounine * @from: Previous RIO device found in search, or %NULL for new search 438e5cabeb3SAlexandre Bounine * 439e5cabeb3SAlexandre Bounine * Iterates through the list of known RIO devices. If a RIO device is 440e5cabeb3SAlexandre Bounine * found with a matching @comp_tag, a pointer to its device 441e5cabeb3SAlexandre Bounine * structure is returned. Otherwise, %NULL is returned. A new search 442e5cabeb3SAlexandre Bounine * is initiated by passing %NULL to the @from argument. Otherwise, if 443e5cabeb3SAlexandre Bounine * @from is not %NULL, searches continue from next device on the global 444e5cabeb3SAlexandre Bounine * list. 445e5cabeb3SAlexandre Bounine */ 446af84ca38SAlexandre Bounine struct rio_dev *rio_get_comptag(u32 comp_tag, struct rio_dev *from) 447e5cabeb3SAlexandre Bounine { 448e5cabeb3SAlexandre Bounine struct list_head *n; 449e5cabeb3SAlexandre Bounine struct rio_dev *rdev; 450e5cabeb3SAlexandre Bounine 451e5cabeb3SAlexandre Bounine spin_lock(&rio_global_list_lock); 452e5cabeb3SAlexandre Bounine n = from ? from->global_list.next : rio_devices.next; 453e5cabeb3SAlexandre Bounine 454e5cabeb3SAlexandre Bounine while (n && (n != &rio_devices)) { 455e5cabeb3SAlexandre Bounine rdev = rio_dev_g(n); 456e5cabeb3SAlexandre Bounine if (rdev->comp_tag == comp_tag) 457e5cabeb3SAlexandre Bounine goto exit; 458e5cabeb3SAlexandre Bounine n = n->next; 459e5cabeb3SAlexandre Bounine } 460e5cabeb3SAlexandre Bounine rdev = NULL; 461e5cabeb3SAlexandre Bounine exit: 462e5cabeb3SAlexandre Bounine spin_unlock(&rio_global_list_lock); 463e5cabeb3SAlexandre Bounine return rdev; 464e5cabeb3SAlexandre Bounine } 465e5cabeb3SAlexandre Bounine 466e5cabeb3SAlexandre Bounine /** 467e5cabeb3SAlexandre Bounine * rio_set_port_lockout - Sets/clears LOCKOUT bit (RIO EM 1.3) for a switch port. 468e5cabeb3SAlexandre Bounine * @rdev: Pointer to RIO device control structure 469e5cabeb3SAlexandre Bounine * @pnum: Switch port number to set LOCKOUT bit 470e5cabeb3SAlexandre Bounine * @lock: Operation : set (=1) or clear (=0) 471e5cabeb3SAlexandre Bounine */ 472e5cabeb3SAlexandre Bounine int rio_set_port_lockout(struct rio_dev *rdev, u32 pnum, int lock) 473e5cabeb3SAlexandre Bounine { 474e5cabeb3SAlexandre Bounine u32 regval; 475e5cabeb3SAlexandre Bounine 476a93192a5SAlexandre Bounine rio_read_config_32(rdev, 477e5cabeb3SAlexandre Bounine rdev->phys_efptr + RIO_PORT_N_CTL_CSR(pnum), 478e5cabeb3SAlexandre Bounine ®val); 479e5cabeb3SAlexandre Bounine if (lock) 480e5cabeb3SAlexandre Bounine regval |= RIO_PORT_N_CTL_LOCKOUT; 481e5cabeb3SAlexandre Bounine else 482e5cabeb3SAlexandre Bounine regval &= ~RIO_PORT_N_CTL_LOCKOUT; 483e5cabeb3SAlexandre Bounine 484a93192a5SAlexandre Bounine rio_write_config_32(rdev, 485e5cabeb3SAlexandre Bounine rdev->phys_efptr + RIO_PORT_N_CTL_CSR(pnum), 486e5cabeb3SAlexandre Bounine regval); 487e5cabeb3SAlexandre Bounine return 0; 488e5cabeb3SAlexandre Bounine } 489e5cabeb3SAlexandre Bounine 490e5cabeb3SAlexandre Bounine /** 4916429cd49SAlexandre Bounine * rio_chk_dev_route - Validate route to the specified device. 4926429cd49SAlexandre Bounine * @rdev: RIO device failed to respond 4936429cd49SAlexandre Bounine * @nrdev: Last active device on the route to rdev 4946429cd49SAlexandre Bounine * @npnum: nrdev's port number on the route to rdev 4956429cd49SAlexandre Bounine * 4966429cd49SAlexandre Bounine * Follows a route to the specified RIO device to determine the last available 4976429cd49SAlexandre Bounine * device (and corresponding RIO port) on the route. 4986429cd49SAlexandre Bounine */ 4996429cd49SAlexandre Bounine static int 5006429cd49SAlexandre Bounine rio_chk_dev_route(struct rio_dev *rdev, struct rio_dev **nrdev, int *npnum) 5016429cd49SAlexandre Bounine { 5026429cd49SAlexandre Bounine u32 result; 503a93192a5SAlexandre Bounine int p_port, rc = -EIO; 5046429cd49SAlexandre Bounine struct rio_dev *prev = NULL; 5056429cd49SAlexandre Bounine 5066429cd49SAlexandre Bounine /* Find switch with failed RIO link */ 5076429cd49SAlexandre Bounine while (rdev->prev && (rdev->prev->pef & RIO_PEF_SWITCH)) { 5086429cd49SAlexandre Bounine if (!rio_read_config_32(rdev->prev, RIO_DEV_ID_CAR, &result)) { 5096429cd49SAlexandre Bounine prev = rdev->prev; 5106429cd49SAlexandre Bounine break; 5116429cd49SAlexandre Bounine } 5126429cd49SAlexandre Bounine rdev = rdev->prev; 5136429cd49SAlexandre Bounine } 5146429cd49SAlexandre Bounine 5156429cd49SAlexandre Bounine if (prev == NULL) 5166429cd49SAlexandre Bounine goto err_out; 5176429cd49SAlexandre Bounine 518a93192a5SAlexandre Bounine p_port = prev->rswitch->route_table[rdev->destid]; 5196429cd49SAlexandre Bounine 520af84ca38SAlexandre Bounine if (p_port != RIO_INVALID_ROUTE) { 5216429cd49SAlexandre Bounine pr_debug("RIO: link failed on [%s]-P%d\n", 5226429cd49SAlexandre Bounine rio_name(prev), p_port); 5236429cd49SAlexandre Bounine *nrdev = prev; 5246429cd49SAlexandre Bounine *npnum = p_port; 5256429cd49SAlexandre Bounine rc = 0; 5266429cd49SAlexandre Bounine } else 527af84ca38SAlexandre Bounine pr_debug("RIO: failed to trace route to %s\n", rio_name(rdev)); 5286429cd49SAlexandre Bounine err_out: 5296429cd49SAlexandre Bounine return rc; 5306429cd49SAlexandre Bounine } 5316429cd49SAlexandre Bounine 5326429cd49SAlexandre Bounine /** 5336429cd49SAlexandre Bounine * rio_mport_chk_dev_access - Validate access to the specified device. 5346429cd49SAlexandre Bounine * @mport: Master port to send transactions 5356429cd49SAlexandre Bounine * @destid: Device destination ID in network 5366429cd49SAlexandre Bounine * @hopcount: Number of hops into the network 5376429cd49SAlexandre Bounine */ 538e274e0edSAlexandre Bounine int 5396429cd49SAlexandre Bounine rio_mport_chk_dev_access(struct rio_mport *mport, u16 destid, u8 hopcount) 5406429cd49SAlexandre Bounine { 5416429cd49SAlexandre Bounine int i = 0; 5426429cd49SAlexandre Bounine u32 tmp; 5436429cd49SAlexandre Bounine 5446429cd49SAlexandre Bounine while (rio_mport_read_config_32(mport, destid, hopcount, 5456429cd49SAlexandre Bounine RIO_DEV_ID_CAR, &tmp)) { 5466429cd49SAlexandre Bounine i++; 5476429cd49SAlexandre Bounine if (i == RIO_MAX_CHK_RETRY) 5486429cd49SAlexandre Bounine return -EIO; 5496429cd49SAlexandre Bounine mdelay(1); 5506429cd49SAlexandre Bounine } 5516429cd49SAlexandre Bounine 5526429cd49SAlexandre Bounine return 0; 5536429cd49SAlexandre Bounine } 5546429cd49SAlexandre Bounine 5556429cd49SAlexandre Bounine /** 5566429cd49SAlexandre Bounine * rio_chk_dev_access - Validate access to the specified device. 5576429cd49SAlexandre Bounine * @rdev: Pointer to RIO device control structure 5586429cd49SAlexandre Bounine */ 5596429cd49SAlexandre Bounine static int rio_chk_dev_access(struct rio_dev *rdev) 5606429cd49SAlexandre Bounine { 561a93192a5SAlexandre Bounine return rio_mport_chk_dev_access(rdev->net->hport, 562a93192a5SAlexandre Bounine rdev->destid, rdev->hopcount); 5636429cd49SAlexandre Bounine } 5646429cd49SAlexandre Bounine 5656429cd49SAlexandre Bounine /** 566dd5648c9SAlexandre Bounine * rio_get_input_status - Sends a Link-Request/Input-Status control symbol and 567dd5648c9SAlexandre Bounine * returns link-response (if requested). 568dd5648c9SAlexandre Bounine * @rdev: RIO devive to issue Input-status command 569dd5648c9SAlexandre Bounine * @pnum: Device port number to issue the command 570dd5648c9SAlexandre Bounine * @lnkresp: Response from a link partner 571dd5648c9SAlexandre Bounine */ 572dd5648c9SAlexandre Bounine static int 573dd5648c9SAlexandre Bounine rio_get_input_status(struct rio_dev *rdev, int pnum, u32 *lnkresp) 574dd5648c9SAlexandre Bounine { 575dd5648c9SAlexandre Bounine u32 regval; 576dd5648c9SAlexandre Bounine int checkcount; 577dd5648c9SAlexandre Bounine 578dd5648c9SAlexandre Bounine if (lnkresp) { 579dd5648c9SAlexandre Bounine /* Read from link maintenance response register 580dd5648c9SAlexandre Bounine * to clear valid bit */ 581a93192a5SAlexandre Bounine rio_read_config_32(rdev, 582dd5648c9SAlexandre Bounine rdev->phys_efptr + RIO_PORT_N_MNT_RSP_CSR(pnum), 583dd5648c9SAlexandre Bounine ®val); 584dd5648c9SAlexandre Bounine udelay(50); 585dd5648c9SAlexandre Bounine } 586dd5648c9SAlexandre Bounine 587dd5648c9SAlexandre Bounine /* Issue Input-status command */ 588a93192a5SAlexandre Bounine rio_write_config_32(rdev, 589dd5648c9SAlexandre Bounine rdev->phys_efptr + RIO_PORT_N_MNT_REQ_CSR(pnum), 590dd5648c9SAlexandre Bounine RIO_MNT_REQ_CMD_IS); 591dd5648c9SAlexandre Bounine 592dd5648c9SAlexandre Bounine /* Exit if the response is not expected */ 593dd5648c9SAlexandre Bounine if (lnkresp == NULL) 594dd5648c9SAlexandre Bounine return 0; 595dd5648c9SAlexandre Bounine 596dd5648c9SAlexandre Bounine checkcount = 3; 597dd5648c9SAlexandre Bounine while (checkcount--) { 598dd5648c9SAlexandre Bounine udelay(50); 599a93192a5SAlexandre Bounine rio_read_config_32(rdev, 600dd5648c9SAlexandre Bounine rdev->phys_efptr + RIO_PORT_N_MNT_RSP_CSR(pnum), 601dd5648c9SAlexandre Bounine ®val); 602dd5648c9SAlexandre Bounine if (regval & RIO_PORT_N_MNT_RSP_RVAL) { 603dd5648c9SAlexandre Bounine *lnkresp = regval; 604dd5648c9SAlexandre Bounine return 0; 605dd5648c9SAlexandre Bounine } 606dd5648c9SAlexandre Bounine } 607dd5648c9SAlexandre Bounine 608dd5648c9SAlexandre Bounine return -EIO; 609dd5648c9SAlexandre Bounine } 610dd5648c9SAlexandre Bounine 611dd5648c9SAlexandre Bounine /** 612dd5648c9SAlexandre Bounine * rio_clr_err_stopped - Clears port Error-stopped states. 613dd5648c9SAlexandre Bounine * @rdev: Pointer to RIO device control structure 614dd5648c9SAlexandre Bounine * @pnum: Switch port number to clear errors 615dd5648c9SAlexandre Bounine * @err_status: port error status (if 0 reads register from device) 616dd5648c9SAlexandre Bounine */ 617dd5648c9SAlexandre Bounine static int rio_clr_err_stopped(struct rio_dev *rdev, u32 pnum, u32 err_status) 618dd5648c9SAlexandre Bounine { 619dd5648c9SAlexandre Bounine struct rio_dev *nextdev = rdev->rswitch->nextdev[pnum]; 620dd5648c9SAlexandre Bounine u32 regval; 621dd5648c9SAlexandre Bounine u32 far_ackid, far_linkstat, near_ackid; 622dd5648c9SAlexandre Bounine 623dd5648c9SAlexandre Bounine if (err_status == 0) 624a93192a5SAlexandre Bounine rio_read_config_32(rdev, 625dd5648c9SAlexandre Bounine rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(pnum), 626dd5648c9SAlexandre Bounine &err_status); 627dd5648c9SAlexandre Bounine 628dd5648c9SAlexandre Bounine if (err_status & RIO_PORT_N_ERR_STS_PW_OUT_ES) { 629dd5648c9SAlexandre Bounine pr_debug("RIO_EM: servicing Output Error-Stopped state\n"); 630dd5648c9SAlexandre Bounine /* 631dd5648c9SAlexandre Bounine * Send a Link-Request/Input-Status control symbol 632dd5648c9SAlexandre Bounine */ 633dd5648c9SAlexandre Bounine if (rio_get_input_status(rdev, pnum, ®val)) { 634dd5648c9SAlexandre Bounine pr_debug("RIO_EM: Input-status response timeout\n"); 635dd5648c9SAlexandre Bounine goto rd_err; 636dd5648c9SAlexandre Bounine } 637dd5648c9SAlexandre Bounine 638dd5648c9SAlexandre Bounine pr_debug("RIO_EM: SP%d Input-status response=0x%08x\n", 639dd5648c9SAlexandre Bounine pnum, regval); 640dd5648c9SAlexandre Bounine far_ackid = (regval & RIO_PORT_N_MNT_RSP_ASTAT) >> 5; 641dd5648c9SAlexandre Bounine far_linkstat = regval & RIO_PORT_N_MNT_RSP_LSTAT; 642a93192a5SAlexandre Bounine rio_read_config_32(rdev, 643dd5648c9SAlexandre Bounine rdev->phys_efptr + RIO_PORT_N_ACK_STS_CSR(pnum), 644dd5648c9SAlexandre Bounine ®val); 645dd5648c9SAlexandre Bounine pr_debug("RIO_EM: SP%d_ACK_STS_CSR=0x%08x\n", pnum, regval); 646dd5648c9SAlexandre Bounine near_ackid = (regval & RIO_PORT_N_ACK_INBOUND) >> 24; 647dd5648c9SAlexandre Bounine pr_debug("RIO_EM: SP%d far_ackID=0x%02x far_linkstat=0x%02x" \ 648dd5648c9SAlexandre Bounine " near_ackID=0x%02x\n", 649dd5648c9SAlexandre Bounine pnum, far_ackid, far_linkstat, near_ackid); 650dd5648c9SAlexandre Bounine 651dd5648c9SAlexandre Bounine /* 652dd5648c9SAlexandre Bounine * If required, synchronize ackIDs of near and 653dd5648c9SAlexandre Bounine * far sides. 654dd5648c9SAlexandre Bounine */ 655dd5648c9SAlexandre Bounine if ((far_ackid != ((regval & RIO_PORT_N_ACK_OUTSTAND) >> 8)) || 656dd5648c9SAlexandre Bounine (far_ackid != (regval & RIO_PORT_N_ACK_OUTBOUND))) { 657dd5648c9SAlexandre Bounine /* Align near outstanding/outbound ackIDs with 658dd5648c9SAlexandre Bounine * far inbound. 659dd5648c9SAlexandre Bounine */ 660a93192a5SAlexandre Bounine rio_write_config_32(rdev, 661a93192a5SAlexandre Bounine rdev->phys_efptr + RIO_PORT_N_ACK_STS_CSR(pnum), 662dd5648c9SAlexandre Bounine (near_ackid << 24) | 663dd5648c9SAlexandre Bounine (far_ackid << 8) | far_ackid); 664dd5648c9SAlexandre Bounine /* Align far outstanding/outbound ackIDs with 665dd5648c9SAlexandre Bounine * near inbound. 666dd5648c9SAlexandre Bounine */ 667dd5648c9SAlexandre Bounine far_ackid++; 668dd5648c9SAlexandre Bounine if (nextdev) 669dd5648c9SAlexandre Bounine rio_write_config_32(nextdev, 670dd5648c9SAlexandre Bounine nextdev->phys_efptr + 671dd5648c9SAlexandre Bounine RIO_PORT_N_ACK_STS_CSR(RIO_GET_PORT_NUM(nextdev->swpinfo)), 672dd5648c9SAlexandre Bounine (far_ackid << 24) | 673dd5648c9SAlexandre Bounine (near_ackid << 8) | near_ackid); 674dd5648c9SAlexandre Bounine else 675dd5648c9SAlexandre Bounine pr_debug("RIO_EM: Invalid nextdev pointer (NULL)\n"); 676dd5648c9SAlexandre Bounine } 677dd5648c9SAlexandre Bounine rd_err: 678a93192a5SAlexandre Bounine rio_read_config_32(rdev, 679dd5648c9SAlexandre Bounine rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(pnum), 680dd5648c9SAlexandre Bounine &err_status); 681dd5648c9SAlexandre Bounine pr_debug("RIO_EM: SP%d_ERR_STS_CSR=0x%08x\n", pnum, err_status); 682dd5648c9SAlexandre Bounine } 683dd5648c9SAlexandre Bounine 684dd5648c9SAlexandre Bounine if ((err_status & RIO_PORT_N_ERR_STS_PW_INP_ES) && nextdev) { 685dd5648c9SAlexandre Bounine pr_debug("RIO_EM: servicing Input Error-Stopped state\n"); 686dd5648c9SAlexandre Bounine rio_get_input_status(nextdev, 687dd5648c9SAlexandre Bounine RIO_GET_PORT_NUM(nextdev->swpinfo), NULL); 688dd5648c9SAlexandre Bounine udelay(50); 689dd5648c9SAlexandre Bounine 690a93192a5SAlexandre Bounine rio_read_config_32(rdev, 691dd5648c9SAlexandre Bounine rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(pnum), 692dd5648c9SAlexandre Bounine &err_status); 693dd5648c9SAlexandre Bounine pr_debug("RIO_EM: SP%d_ERR_STS_CSR=0x%08x\n", pnum, err_status); 694dd5648c9SAlexandre Bounine } 695dd5648c9SAlexandre Bounine 696dd5648c9SAlexandre Bounine return (err_status & (RIO_PORT_N_ERR_STS_PW_OUT_ES | 697dd5648c9SAlexandre Bounine RIO_PORT_N_ERR_STS_PW_INP_ES)) ? 1 : 0; 698dd5648c9SAlexandre Bounine } 699dd5648c9SAlexandre Bounine 700dd5648c9SAlexandre Bounine /** 701e5cabeb3SAlexandre Bounine * rio_inb_pwrite_handler - process inbound port-write message 702e5cabeb3SAlexandre Bounine * @pw_msg: pointer to inbound port-write message 703e5cabeb3SAlexandre Bounine * 704e5cabeb3SAlexandre Bounine * Processes an inbound port-write message. Returns 0 if the request 705e5cabeb3SAlexandre Bounine * has been satisfied. 706e5cabeb3SAlexandre Bounine */ 707e5cabeb3SAlexandre Bounine int rio_inb_pwrite_handler(union rio_pw_msg *pw_msg) 708e5cabeb3SAlexandre Bounine { 709e5cabeb3SAlexandre Bounine struct rio_dev *rdev; 710dd5648c9SAlexandre Bounine u32 err_status, em_perrdet, em_ltlerrdet; 711e5cabeb3SAlexandre Bounine int rc, portnum; 712e5cabeb3SAlexandre Bounine 713e5cabeb3SAlexandre Bounine rdev = rio_get_comptag(pw_msg->em.comptag, NULL); 714e5cabeb3SAlexandre Bounine if (rdev == NULL) { 7156429cd49SAlexandre Bounine /* Device removed or enumeration error */ 7166429cd49SAlexandre Bounine pr_debug("RIO: %s No matching device for CTag 0x%08x\n", 717e5cabeb3SAlexandre Bounine __func__, pw_msg->em.comptag); 718e5cabeb3SAlexandre Bounine return -EIO; 719e5cabeb3SAlexandre Bounine } 720e5cabeb3SAlexandre Bounine 721e5cabeb3SAlexandre Bounine pr_debug("RIO: Port-Write message from %s\n", rio_name(rdev)); 722e5cabeb3SAlexandre Bounine 723e5cabeb3SAlexandre Bounine #ifdef DEBUG_PW 724e5cabeb3SAlexandre Bounine { 725e5cabeb3SAlexandre Bounine u32 i; 726e5cabeb3SAlexandre Bounine for (i = 0; i < RIO_PW_MSG_SIZE/sizeof(u32);) { 727dd5648c9SAlexandre Bounine pr_debug("0x%02x: %08x %08x %08x %08x\n", 728e5cabeb3SAlexandre Bounine i*4, pw_msg->raw[i], pw_msg->raw[i + 1], 729e5cabeb3SAlexandre Bounine pw_msg->raw[i + 2], pw_msg->raw[i + 3]); 730e5cabeb3SAlexandre Bounine i += 4; 731e5cabeb3SAlexandre Bounine } 732e5cabeb3SAlexandre Bounine } 733e5cabeb3SAlexandre Bounine #endif 734e5cabeb3SAlexandre Bounine 735e5cabeb3SAlexandre Bounine /* Call an external service function (if such is registered 736e5cabeb3SAlexandre Bounine * for this device). This may be the service for endpoints that send 737e5cabeb3SAlexandre Bounine * device-specific port-write messages. End-point messages expected 738e5cabeb3SAlexandre Bounine * to be handled completely by EP specific device driver. 739e5cabeb3SAlexandre Bounine * For switches rc==0 signals that no standard processing required. 740e5cabeb3SAlexandre Bounine */ 741e5cabeb3SAlexandre Bounine if (rdev->pwcback != NULL) { 742e5cabeb3SAlexandre Bounine rc = rdev->pwcback(rdev, pw_msg, 0); 743e5cabeb3SAlexandre Bounine if (rc == 0) 744e5cabeb3SAlexandre Bounine return 0; 745e5cabeb3SAlexandre Bounine } 746e5cabeb3SAlexandre Bounine 7476429cd49SAlexandre Bounine portnum = pw_msg->em.is_port & 0xFF; 7486429cd49SAlexandre Bounine 7496429cd49SAlexandre Bounine /* Check if device and route to it are functional: 7506429cd49SAlexandre Bounine * Sometimes devices may send PW message(s) just before being 7516429cd49SAlexandre Bounine * powered down (or link being lost). 7526429cd49SAlexandre Bounine */ 7536429cd49SAlexandre Bounine if (rio_chk_dev_access(rdev)) { 7546429cd49SAlexandre Bounine pr_debug("RIO: device access failed - get link partner\n"); 7556429cd49SAlexandre Bounine /* Scan route to the device and identify failed link. 7566429cd49SAlexandre Bounine * This will replace device and port reported in PW message. 7576429cd49SAlexandre Bounine * PW message should not be used after this point. 7586429cd49SAlexandre Bounine */ 7596429cd49SAlexandre Bounine if (rio_chk_dev_route(rdev, &rdev, &portnum)) { 7606429cd49SAlexandre Bounine pr_err("RIO: Route trace for %s failed\n", 7616429cd49SAlexandre Bounine rio_name(rdev)); 7626429cd49SAlexandre Bounine return -EIO; 7636429cd49SAlexandre Bounine } 7646429cd49SAlexandre Bounine pw_msg = NULL; 7656429cd49SAlexandre Bounine } 7666429cd49SAlexandre Bounine 767e5cabeb3SAlexandre Bounine /* For End-point devices processing stops here */ 768e5cabeb3SAlexandre Bounine if (!(rdev->pef & RIO_PEF_SWITCH)) 769e5cabeb3SAlexandre Bounine return 0; 770e5cabeb3SAlexandre Bounine 771e5cabeb3SAlexandre Bounine if (rdev->phys_efptr == 0) { 772e5cabeb3SAlexandre Bounine pr_err("RIO_PW: Bad switch initialization for %s\n", 773e5cabeb3SAlexandre Bounine rio_name(rdev)); 774e5cabeb3SAlexandre Bounine return 0; 775e5cabeb3SAlexandre Bounine } 776e5cabeb3SAlexandre Bounine 777e5cabeb3SAlexandre Bounine /* 778e5cabeb3SAlexandre Bounine * Process the port-write notification from switch 779e5cabeb3SAlexandre Bounine */ 780e5cabeb3SAlexandre Bounine if (rdev->rswitch->em_handle) 781e5cabeb3SAlexandre Bounine rdev->rswitch->em_handle(rdev, portnum); 782e5cabeb3SAlexandre Bounine 783a93192a5SAlexandre Bounine rio_read_config_32(rdev, 784e5cabeb3SAlexandre Bounine rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(portnum), 785e5cabeb3SAlexandre Bounine &err_status); 786e5cabeb3SAlexandre Bounine pr_debug("RIO_PW: SP%d_ERR_STS_CSR=0x%08x\n", portnum, err_status); 787e5cabeb3SAlexandre Bounine 788dd5648c9SAlexandre Bounine if (err_status & RIO_PORT_N_ERR_STS_PORT_OK) { 789dd5648c9SAlexandre Bounine 790dd5648c9SAlexandre Bounine if (!(rdev->rswitch->port_ok & (1 << portnum))) { 791dd5648c9SAlexandre Bounine rdev->rswitch->port_ok |= (1 << portnum); 792dd5648c9SAlexandre Bounine rio_set_port_lockout(rdev, portnum, 0); 793dd5648c9SAlexandre Bounine /* Schedule Insertion Service */ 794dd5648c9SAlexandre Bounine pr_debug("RIO_PW: Device Insertion on [%s]-P%d\n", 795dd5648c9SAlexandre Bounine rio_name(rdev), portnum); 796e5cabeb3SAlexandre Bounine } 797e5cabeb3SAlexandre Bounine 798dd5648c9SAlexandre Bounine /* Clear error-stopped states (if reported). 799dd5648c9SAlexandre Bounine * Depending on the link partner state, two attempts 800dd5648c9SAlexandre Bounine * may be needed for successful recovery. 801dd5648c9SAlexandre Bounine */ 802dd5648c9SAlexandre Bounine if (err_status & (RIO_PORT_N_ERR_STS_PW_OUT_ES | 803dd5648c9SAlexandre Bounine RIO_PORT_N_ERR_STS_PW_INP_ES)) { 804dd5648c9SAlexandre Bounine if (rio_clr_err_stopped(rdev, portnum, err_status)) 805dd5648c9SAlexandre Bounine rio_clr_err_stopped(rdev, portnum, 0); 806e5cabeb3SAlexandre Bounine } 807dd5648c9SAlexandre Bounine } else { /* if (err_status & RIO_PORT_N_ERR_STS_PORT_UNINIT) */ 808e5cabeb3SAlexandre Bounine 809e5cabeb3SAlexandre Bounine if (rdev->rswitch->port_ok & (1 << portnum)) { 810e5cabeb3SAlexandre Bounine rdev->rswitch->port_ok &= ~(1 << portnum); 811e5cabeb3SAlexandre Bounine rio_set_port_lockout(rdev, portnum, 1); 812e5cabeb3SAlexandre Bounine 813a93192a5SAlexandre Bounine rio_write_config_32(rdev, 814e5cabeb3SAlexandre Bounine rdev->phys_efptr + 815e5cabeb3SAlexandre Bounine RIO_PORT_N_ACK_STS_CSR(portnum), 816e5cabeb3SAlexandre Bounine RIO_PORT_N_ACK_CLEAR); 817e5cabeb3SAlexandre Bounine 818e5cabeb3SAlexandre Bounine /* Schedule Extraction Service */ 819e5cabeb3SAlexandre Bounine pr_debug("RIO_PW: Device Extraction on [%s]-P%d\n", 820e5cabeb3SAlexandre Bounine rio_name(rdev), portnum); 821e5cabeb3SAlexandre Bounine } 822dd5648c9SAlexandre Bounine } 823e5cabeb3SAlexandre Bounine 824a93192a5SAlexandre Bounine rio_read_config_32(rdev, 825dd5648c9SAlexandre Bounine rdev->em_efptr + RIO_EM_PN_ERR_DETECT(portnum), &em_perrdet); 826dd5648c9SAlexandre Bounine if (em_perrdet) { 827dd5648c9SAlexandre Bounine pr_debug("RIO_PW: RIO_EM_P%d_ERR_DETECT=0x%08x\n", 828dd5648c9SAlexandre Bounine portnum, em_perrdet); 829dd5648c9SAlexandre Bounine /* Clear EM Port N Error Detect CSR */ 830a93192a5SAlexandre Bounine rio_write_config_32(rdev, 831dd5648c9SAlexandre Bounine rdev->em_efptr + RIO_EM_PN_ERR_DETECT(portnum), 0); 832e5cabeb3SAlexandre Bounine } 833dd5648c9SAlexandre Bounine 834a93192a5SAlexandre Bounine rio_read_config_32(rdev, 835dd5648c9SAlexandre Bounine rdev->em_efptr + RIO_EM_LTL_ERR_DETECT, &em_ltlerrdet); 836dd5648c9SAlexandre Bounine if (em_ltlerrdet) { 837dd5648c9SAlexandre Bounine pr_debug("RIO_PW: RIO_EM_LTL_ERR_DETECT=0x%08x\n", 838dd5648c9SAlexandre Bounine em_ltlerrdet); 839dd5648c9SAlexandre Bounine /* Clear EM L/T Layer Error Detect CSR */ 840a93192a5SAlexandre Bounine rio_write_config_32(rdev, 841dd5648c9SAlexandre Bounine rdev->em_efptr + RIO_EM_LTL_ERR_DETECT, 0); 842e5cabeb3SAlexandre Bounine } 843e5cabeb3SAlexandre Bounine 844388c45ccSAlexandre Bounine /* Clear remaining error bits and Port-Write Pending bit */ 845a93192a5SAlexandre Bounine rio_write_config_32(rdev, 846dd5648c9SAlexandre Bounine rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(portnum), 847388c45ccSAlexandre Bounine err_status); 848e5cabeb3SAlexandre Bounine 849e5cabeb3SAlexandre Bounine return 0; 850e5cabeb3SAlexandre Bounine } 851e5cabeb3SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_inb_pwrite_handler); 852e5cabeb3SAlexandre Bounine 853e5cabeb3SAlexandre Bounine /** 854e5cabeb3SAlexandre Bounine * rio_mport_get_efb - get pointer to next extended features block 855e5cabeb3SAlexandre Bounine * @port: Master port to issue transaction 856e5cabeb3SAlexandre Bounine * @local: Indicate a local master port or remote device access 857e5cabeb3SAlexandre Bounine * @destid: Destination ID of the device 858e5cabeb3SAlexandre Bounine * @hopcount: Number of switch hops to the device 859e5cabeb3SAlexandre Bounine * @from: Offset of current Extended Feature block header (if 0 starts 860e5cabeb3SAlexandre Bounine * from ExtFeaturePtr) 861e5cabeb3SAlexandre Bounine */ 862e5cabeb3SAlexandre Bounine u32 863e5cabeb3SAlexandre Bounine rio_mport_get_efb(struct rio_mport *port, int local, u16 destid, 864e5cabeb3SAlexandre Bounine u8 hopcount, u32 from) 865e5cabeb3SAlexandre Bounine { 866e5cabeb3SAlexandre Bounine u32 reg_val; 867e5cabeb3SAlexandre Bounine 868e5cabeb3SAlexandre Bounine if (from == 0) { 869e5cabeb3SAlexandre Bounine if (local) 870e5cabeb3SAlexandre Bounine rio_local_read_config_32(port, RIO_ASM_INFO_CAR, 871e5cabeb3SAlexandre Bounine ®_val); 872e5cabeb3SAlexandre Bounine else 873e5cabeb3SAlexandre Bounine rio_mport_read_config_32(port, destid, hopcount, 874e5cabeb3SAlexandre Bounine RIO_ASM_INFO_CAR, ®_val); 875e5cabeb3SAlexandre Bounine return reg_val & RIO_EXT_FTR_PTR_MASK; 876e5cabeb3SAlexandre Bounine } else { 877e5cabeb3SAlexandre Bounine if (local) 878e5cabeb3SAlexandre Bounine rio_local_read_config_32(port, from, ®_val); 879e5cabeb3SAlexandre Bounine else 880e5cabeb3SAlexandre Bounine rio_mport_read_config_32(port, destid, hopcount, 881e5cabeb3SAlexandre Bounine from, ®_val); 882e5cabeb3SAlexandre Bounine return RIO_GET_BLOCK_ID(reg_val); 883e5cabeb3SAlexandre Bounine } 884e5cabeb3SAlexandre Bounine } 885e5cabeb3SAlexandre Bounine 886e5cabeb3SAlexandre Bounine /** 887394b701cSMatt Porter * rio_mport_get_feature - query for devices' extended features 888394b701cSMatt Porter * @port: Master port to issue transaction 889394b701cSMatt Porter * @local: Indicate a local master port or remote device access 890394b701cSMatt Porter * @destid: Destination ID of the device 891394b701cSMatt Porter * @hopcount: Number of switch hops to the device 892394b701cSMatt Porter * @ftr: Extended feature code 893394b701cSMatt Porter * 894394b701cSMatt Porter * Tell if a device supports a given RapidIO capability. 895394b701cSMatt Porter * Returns the offset of the requested extended feature 896394b701cSMatt Porter * block within the device's RIO configuration space or 897394b701cSMatt Porter * 0 in case the device does not support it. Possible 898394b701cSMatt Porter * values for @ftr: 899394b701cSMatt Porter * 900394b701cSMatt Porter * %RIO_EFB_PAR_EP_ID LP/LVDS EP Devices 901394b701cSMatt Porter * 902394b701cSMatt Porter * %RIO_EFB_PAR_EP_REC_ID LP/LVDS EP Recovery Devices 903394b701cSMatt Porter * 904394b701cSMatt Porter * %RIO_EFB_PAR_EP_FREE_ID LP/LVDS EP Free Devices 905394b701cSMatt Porter * 906394b701cSMatt Porter * %RIO_EFB_SER_EP_ID LP/Serial EP Devices 907394b701cSMatt Porter * 908394b701cSMatt Porter * %RIO_EFB_SER_EP_REC_ID LP/Serial EP Recovery Devices 909394b701cSMatt Porter * 910394b701cSMatt Porter * %RIO_EFB_SER_EP_FREE_ID LP/Serial EP Free Devices 911394b701cSMatt Porter */ 912394b701cSMatt Porter u32 913394b701cSMatt Porter rio_mport_get_feature(struct rio_mport * port, int local, u16 destid, 914394b701cSMatt Porter u8 hopcount, int ftr) 915394b701cSMatt Porter { 916394b701cSMatt Porter u32 asm_info, ext_ftr_ptr, ftr_header; 917394b701cSMatt Porter 918394b701cSMatt Porter if (local) 919394b701cSMatt Porter rio_local_read_config_32(port, RIO_ASM_INFO_CAR, &asm_info); 920394b701cSMatt Porter else 921394b701cSMatt Porter rio_mport_read_config_32(port, destid, hopcount, 922394b701cSMatt Porter RIO_ASM_INFO_CAR, &asm_info); 923394b701cSMatt Porter 924394b701cSMatt Porter ext_ftr_ptr = asm_info & RIO_EXT_FTR_PTR_MASK; 925394b701cSMatt Porter 926394b701cSMatt Porter while (ext_ftr_ptr) { 927394b701cSMatt Porter if (local) 928394b701cSMatt Porter rio_local_read_config_32(port, ext_ftr_ptr, 929394b701cSMatt Porter &ftr_header); 930394b701cSMatt Porter else 931394b701cSMatt Porter rio_mport_read_config_32(port, destid, hopcount, 932394b701cSMatt Porter ext_ftr_ptr, &ftr_header); 933394b701cSMatt Porter if (RIO_GET_BLOCK_ID(ftr_header) == ftr) 934394b701cSMatt Porter return ext_ftr_ptr; 935394b701cSMatt Porter if (!(ext_ftr_ptr = RIO_GET_BLOCK_PTR(ftr_header))) 936394b701cSMatt Porter break; 937394b701cSMatt Porter } 938394b701cSMatt Porter 939394b701cSMatt Porter return 0; 940394b701cSMatt Porter } 941394b701cSMatt Porter 942394b701cSMatt Porter /** 943394b701cSMatt Porter * rio_get_asm - Begin or continue searching for a RIO device by vid/did/asm_vid/asm_did 944394b701cSMatt Porter * @vid: RIO vid to match or %RIO_ANY_ID to match all vids 945394b701cSMatt Porter * @did: RIO did to match or %RIO_ANY_ID to match all dids 946394b701cSMatt Porter * @asm_vid: RIO asm_vid to match or %RIO_ANY_ID to match all asm_vids 947394b701cSMatt Porter * @asm_did: RIO asm_did to match or %RIO_ANY_ID to match all asm_dids 948394b701cSMatt Porter * @from: Previous RIO device found in search, or %NULL for new search 949394b701cSMatt Porter * 950394b701cSMatt Porter * Iterates through the list of known RIO devices. If a RIO device is 951394b701cSMatt Porter * found with a matching @vid, @did, @asm_vid, @asm_did, the reference 952394b701cSMatt Porter * count to the device is incrememted and a pointer to its device 953394b701cSMatt Porter * structure is returned. Otherwise, %NULL is returned. A new search 954394b701cSMatt Porter * is initiated by passing %NULL to the @from argument. Otherwise, if 955394b701cSMatt Porter * @from is not %NULL, searches continue from next device on the global 956394b701cSMatt Porter * list. The reference count for @from is always decremented if it is 957394b701cSMatt Porter * not %NULL. 958394b701cSMatt Porter */ 959394b701cSMatt Porter struct rio_dev *rio_get_asm(u16 vid, u16 did, 960394b701cSMatt Porter u16 asm_vid, u16 asm_did, struct rio_dev *from) 961394b701cSMatt Porter { 962394b701cSMatt Porter struct list_head *n; 963394b701cSMatt Porter struct rio_dev *rdev; 964394b701cSMatt Porter 965394b701cSMatt Porter WARN_ON(in_interrupt()); 966394b701cSMatt Porter spin_lock(&rio_global_list_lock); 967394b701cSMatt Porter n = from ? from->global_list.next : rio_devices.next; 968394b701cSMatt Porter 969394b701cSMatt Porter while (n && (n != &rio_devices)) { 970394b701cSMatt Porter rdev = rio_dev_g(n); 971394b701cSMatt Porter if ((vid == RIO_ANY_ID || rdev->vid == vid) && 972394b701cSMatt Porter (did == RIO_ANY_ID || rdev->did == did) && 973394b701cSMatt Porter (asm_vid == RIO_ANY_ID || rdev->asm_vid == asm_vid) && 974394b701cSMatt Porter (asm_did == RIO_ANY_ID || rdev->asm_did == asm_did)) 975394b701cSMatt Porter goto exit; 976394b701cSMatt Porter n = n->next; 977394b701cSMatt Porter } 978394b701cSMatt Porter rdev = NULL; 979394b701cSMatt Porter exit: 980394b701cSMatt Porter rio_dev_put(from); 981394b701cSMatt Porter rdev = rio_dev_get(rdev); 982394b701cSMatt Porter spin_unlock(&rio_global_list_lock); 983394b701cSMatt Porter return rdev; 984394b701cSMatt Porter } 985394b701cSMatt Porter 986394b701cSMatt Porter /** 987394b701cSMatt Porter * rio_get_device - Begin or continue searching for a RIO device by vid/did 988394b701cSMatt Porter * @vid: RIO vid to match or %RIO_ANY_ID to match all vids 989394b701cSMatt Porter * @did: RIO did to match or %RIO_ANY_ID to match all dids 990394b701cSMatt Porter * @from: Previous RIO device found in search, or %NULL for new search 991394b701cSMatt Porter * 992394b701cSMatt Porter * Iterates through the list of known RIO devices. If a RIO device is 993394b701cSMatt Porter * found with a matching @vid and @did, the reference count to the 994394b701cSMatt Porter * device is incrememted and a pointer to its device structure is returned. 995394b701cSMatt Porter * Otherwise, %NULL is returned. A new search is initiated by passing %NULL 996394b701cSMatt Porter * to the @from argument. Otherwise, if @from is not %NULL, searches 997394b701cSMatt Porter * continue from next device on the global list. The reference count for 998394b701cSMatt Porter * @from is always decremented if it is not %NULL. 999394b701cSMatt Porter */ 1000394b701cSMatt Porter struct rio_dev *rio_get_device(u16 vid, u16 did, struct rio_dev *from) 1001394b701cSMatt Porter { 1002394b701cSMatt Porter return rio_get_asm(vid, did, RIO_ANY_ID, RIO_ANY_ID, from); 1003394b701cSMatt Porter } 1004394b701cSMatt Porter 100507590ff0SAlexandre Bounine /** 100607590ff0SAlexandre Bounine * rio_std_route_add_entry - Add switch route table entry using standard 100707590ff0SAlexandre Bounine * registers defined in RIO specification rev.1.3 100807590ff0SAlexandre Bounine * @mport: Master port to issue transaction 100907590ff0SAlexandre Bounine * @destid: Destination ID of the device 101007590ff0SAlexandre Bounine * @hopcount: Number of switch hops to the device 101107590ff0SAlexandre Bounine * @table: routing table ID (global or port-specific) 101207590ff0SAlexandre Bounine * @route_destid: destID entry in the RT 101307590ff0SAlexandre Bounine * @route_port: destination port for specified destID 101407590ff0SAlexandre Bounine */ 101507590ff0SAlexandre Bounine int rio_std_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount, 101607590ff0SAlexandre Bounine u16 table, u16 route_destid, u8 route_port) 101707590ff0SAlexandre Bounine { 101807590ff0SAlexandre Bounine if (table == RIO_GLOBAL_TABLE) { 101907590ff0SAlexandre Bounine rio_mport_write_config_32(mport, destid, hopcount, 102007590ff0SAlexandre Bounine RIO_STD_RTE_CONF_DESTID_SEL_CSR, 102107590ff0SAlexandre Bounine (u32)route_destid); 102207590ff0SAlexandre Bounine rio_mport_write_config_32(mport, destid, hopcount, 102307590ff0SAlexandre Bounine RIO_STD_RTE_CONF_PORT_SEL_CSR, 102407590ff0SAlexandre Bounine (u32)route_port); 102507590ff0SAlexandre Bounine } 1026e5cabeb3SAlexandre Bounine 102707590ff0SAlexandre Bounine udelay(10); 102807590ff0SAlexandre Bounine return 0; 102907590ff0SAlexandre Bounine } 103007590ff0SAlexandre Bounine 103107590ff0SAlexandre Bounine /** 103207590ff0SAlexandre Bounine * rio_std_route_get_entry - Read switch route table entry (port number) 1033638c5945SUwe Kleine-König * associated with specified destID using standard registers defined in RIO 103407590ff0SAlexandre Bounine * specification rev.1.3 103507590ff0SAlexandre Bounine * @mport: Master port to issue transaction 103607590ff0SAlexandre Bounine * @destid: Destination ID of the device 103707590ff0SAlexandre Bounine * @hopcount: Number of switch hops to the device 103807590ff0SAlexandre Bounine * @table: routing table ID (global or port-specific) 103907590ff0SAlexandre Bounine * @route_destid: destID entry in the RT 104007590ff0SAlexandre Bounine * @route_port: returned destination port for specified destID 104107590ff0SAlexandre Bounine */ 104207590ff0SAlexandre Bounine int rio_std_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount, 104307590ff0SAlexandre Bounine u16 table, u16 route_destid, u8 *route_port) 104407590ff0SAlexandre Bounine { 104507590ff0SAlexandre Bounine u32 result; 104607590ff0SAlexandre Bounine 104707590ff0SAlexandre Bounine if (table == RIO_GLOBAL_TABLE) { 104807590ff0SAlexandre Bounine rio_mport_write_config_32(mport, destid, hopcount, 104907590ff0SAlexandre Bounine RIO_STD_RTE_CONF_DESTID_SEL_CSR, route_destid); 105007590ff0SAlexandre Bounine rio_mport_read_config_32(mport, destid, hopcount, 105107590ff0SAlexandre Bounine RIO_STD_RTE_CONF_PORT_SEL_CSR, &result); 105207590ff0SAlexandre Bounine 105307590ff0SAlexandre Bounine *route_port = (u8)result; 105407590ff0SAlexandre Bounine } 105507590ff0SAlexandre Bounine 105607590ff0SAlexandre Bounine return 0; 105707590ff0SAlexandre Bounine } 105807590ff0SAlexandre Bounine 105907590ff0SAlexandre Bounine /** 106007590ff0SAlexandre Bounine * rio_std_route_clr_table - Clear swotch route table using standard registers 106107590ff0SAlexandre Bounine * defined in RIO specification rev.1.3. 106207590ff0SAlexandre Bounine * @mport: Master port to issue transaction 106307590ff0SAlexandre Bounine * @destid: Destination ID of the device 106407590ff0SAlexandre Bounine * @hopcount: Number of switch hops to the device 106507590ff0SAlexandre Bounine * @table: routing table ID (global or port-specific) 106607590ff0SAlexandre Bounine */ 106707590ff0SAlexandre Bounine int rio_std_route_clr_table(struct rio_mport *mport, u16 destid, u8 hopcount, 106807590ff0SAlexandre Bounine u16 table) 106907590ff0SAlexandre Bounine { 107007590ff0SAlexandre Bounine u32 max_destid = 0xff; 107107590ff0SAlexandre Bounine u32 i, pef, id_inc = 1, ext_cfg = 0; 107207590ff0SAlexandre Bounine u32 port_sel = RIO_INVALID_ROUTE; 107307590ff0SAlexandre Bounine 107407590ff0SAlexandre Bounine if (table == RIO_GLOBAL_TABLE) { 107507590ff0SAlexandre Bounine rio_mport_read_config_32(mport, destid, hopcount, 107607590ff0SAlexandre Bounine RIO_PEF_CAR, &pef); 107707590ff0SAlexandre Bounine 107807590ff0SAlexandre Bounine if (mport->sys_size) { 107907590ff0SAlexandre Bounine rio_mport_read_config_32(mport, destid, hopcount, 108007590ff0SAlexandre Bounine RIO_SWITCH_RT_LIMIT, 108107590ff0SAlexandre Bounine &max_destid); 108207590ff0SAlexandre Bounine max_destid &= RIO_RT_MAX_DESTID; 108307590ff0SAlexandre Bounine } 108407590ff0SAlexandre Bounine 108507590ff0SAlexandre Bounine if (pef & RIO_PEF_EXT_RT) { 108607590ff0SAlexandre Bounine ext_cfg = 0x80000000; 108707590ff0SAlexandre Bounine id_inc = 4; 108807590ff0SAlexandre Bounine port_sel = (RIO_INVALID_ROUTE << 24) | 108907590ff0SAlexandre Bounine (RIO_INVALID_ROUTE << 16) | 109007590ff0SAlexandre Bounine (RIO_INVALID_ROUTE << 8) | 109107590ff0SAlexandre Bounine RIO_INVALID_ROUTE; 109207590ff0SAlexandre Bounine } 109307590ff0SAlexandre Bounine 109407590ff0SAlexandre Bounine for (i = 0; i <= max_destid;) { 109507590ff0SAlexandre Bounine rio_mport_write_config_32(mport, destid, hopcount, 109607590ff0SAlexandre Bounine RIO_STD_RTE_CONF_DESTID_SEL_CSR, 109707590ff0SAlexandre Bounine ext_cfg | i); 109807590ff0SAlexandre Bounine rio_mport_write_config_32(mport, destid, hopcount, 109907590ff0SAlexandre Bounine RIO_STD_RTE_CONF_PORT_SEL_CSR, 110007590ff0SAlexandre Bounine port_sel); 110107590ff0SAlexandre Bounine i += id_inc; 110207590ff0SAlexandre Bounine } 110307590ff0SAlexandre Bounine } 110407590ff0SAlexandre Bounine 110507590ff0SAlexandre Bounine udelay(10); 110607590ff0SAlexandre Bounine return 0; 110707590ff0SAlexandre Bounine } 110807590ff0SAlexandre Bounine 1109394b701cSMatt Porter static void rio_fixup_device(struct rio_dev *dev) 1110394b701cSMatt Porter { 1111394b701cSMatt Porter } 1112394b701cSMatt Porter 1113394b701cSMatt Porter static int __devinit rio_init(void) 1114394b701cSMatt Porter { 1115394b701cSMatt Porter struct rio_dev *dev = NULL; 1116394b701cSMatt Porter 1117394b701cSMatt Porter while ((dev = rio_get_device(RIO_ANY_ID, RIO_ANY_ID, dev)) != NULL) { 1118394b701cSMatt Porter rio_fixup_device(dev); 1119394b701cSMatt Porter } 1120394b701cSMatt Porter return 0; 1121394b701cSMatt Porter } 1122394b701cSMatt Porter 1123394b701cSMatt Porter device_initcall(rio_init); 1124394b701cSMatt Porter 112537d33d15SAl Viro int __devinit rio_init_mports(void) 1126394b701cSMatt Porter { 1127394b701cSMatt Porter int rc = 0; 1128394b701cSMatt Porter struct rio_mport *port; 1129394b701cSMatt Porter 1130394b701cSMatt Porter list_for_each_entry(port, &rio_mports, node) { 1131394b701cSMatt Porter if (!request_mem_region(port->iores.start, 113288cf81fcSDan Carpenter resource_size(&port->iores), 1133394b701cSMatt Porter port->name)) { 1134394b701cSMatt Porter printk(KERN_ERR 11355febf1cdSKumar Gala "RIO: Error requesting master port region 0x%016llx-0x%016llx\n", 113688cf81fcSDan Carpenter (u64)port->iores.start, (u64)port->iores.end); 1137394b701cSMatt Porter rc = -ENOMEM; 1138394b701cSMatt Porter goto out; 1139394b701cSMatt Porter } 1140394b701cSMatt Porter 1141394b701cSMatt Porter if (port->host_deviceid >= 0) 1142394b701cSMatt Porter rio_enum_mport(port); 1143394b701cSMatt Porter else 1144394b701cSMatt Porter rio_disc_mport(port); 1145394b701cSMatt Porter } 1146394b701cSMatt Porter 1147394b701cSMatt Porter out: 1148394b701cSMatt Porter return rc; 1149394b701cSMatt Porter } 1150394b701cSMatt Porter 1151394b701cSMatt Porter void rio_register_mport(struct rio_mport *port) 1152394b701cSMatt Porter { 1153394b701cSMatt Porter list_add_tail(&port->node, &rio_mports); 1154394b701cSMatt Porter } 1155394b701cSMatt Porter 1156394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_local_get_device_id); 1157394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_get_device); 1158394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_get_asm); 1159394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_request_inb_dbell); 1160394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_release_inb_dbell); 1161394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_request_outb_dbell); 1162394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_release_outb_dbell); 1163394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_request_inb_mbox); 1164394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_release_inb_mbox); 1165394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_request_outb_mbox); 1166394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_release_outb_mbox); 1167