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 { 71f8f06269SAlexandre Bounine int rc = -ENOSYS; 72f8f06269SAlexandre Bounine struct resource *res; 73394b701cSMatt Porter 74f8f06269SAlexandre Bounine if (mport->ops->open_inb_mbox == NULL) 75f8f06269SAlexandre Bounine goto out; 76f8f06269SAlexandre Bounine 77f8f06269SAlexandre Bounine res = kmalloc(sizeof(struct resource), GFP_KERNEL); 78394b701cSMatt Porter 79394b701cSMatt Porter if (res) { 80394b701cSMatt Porter rio_init_mbox_res(res, mbox, mbox); 81394b701cSMatt Porter 82394b701cSMatt Porter /* Make sure this mailbox isn't in use */ 83394b701cSMatt Porter if ((rc = 84394b701cSMatt Porter request_resource(&mport->riores[RIO_INB_MBOX_RESOURCE], 85394b701cSMatt Porter res)) < 0) { 86394b701cSMatt Porter kfree(res); 87394b701cSMatt Porter goto out; 88394b701cSMatt Porter } 89394b701cSMatt Porter 90394b701cSMatt Porter mport->inb_msg[mbox].res = res; 91394b701cSMatt Porter 92394b701cSMatt Porter /* Hook the inbound message callback */ 93394b701cSMatt Porter mport->inb_msg[mbox].mcback = minb; 94394b701cSMatt Porter 95f8f06269SAlexandre Bounine rc = mport->ops->open_inb_mbox(mport, dev_id, mbox, entries); 96394b701cSMatt Porter } else 97394b701cSMatt Porter rc = -ENOMEM; 98394b701cSMatt Porter 99394b701cSMatt Porter out: 100394b701cSMatt Porter return rc; 101394b701cSMatt Porter } 102394b701cSMatt Porter 103394b701cSMatt Porter /** 104394b701cSMatt Porter * rio_release_inb_mbox - release inbound mailbox message service 105394b701cSMatt Porter * @mport: RIO master port from which to release the mailbox resource 106394b701cSMatt Porter * @mbox: Mailbox number to release 107394b701cSMatt Porter * 108394b701cSMatt Porter * Releases ownership of an inbound mailbox resource. Returns 0 109394b701cSMatt Porter * if the request has been satisfied. 110394b701cSMatt Porter */ 111394b701cSMatt Porter int rio_release_inb_mbox(struct rio_mport *mport, int mbox) 112394b701cSMatt Porter { 113f8f06269SAlexandre Bounine if (mport->ops->close_inb_mbox) { 114f8f06269SAlexandre Bounine mport->ops->close_inb_mbox(mport, mbox); 115394b701cSMatt Porter 116394b701cSMatt Porter /* Release the mailbox resource */ 117394b701cSMatt Porter return release_resource(mport->inb_msg[mbox].res); 118f8f06269SAlexandre Bounine } else 119f8f06269SAlexandre Bounine return -ENOSYS; 120394b701cSMatt Porter } 121394b701cSMatt Porter 122394b701cSMatt Porter /** 123394b701cSMatt Porter * rio_request_outb_mbox - request outbound mailbox service 124394b701cSMatt Porter * @mport: RIO master port from which to allocate the mailbox resource 1256978bbc0SMatt Porter * @dev_id: Device specific pointer to pass on event 126394b701cSMatt Porter * @mbox: Mailbox number to claim 127394b701cSMatt Porter * @entries: Number of entries in outbound mailbox queue 128394b701cSMatt Porter * @moutb: Callback to execute when outbound message is sent 129394b701cSMatt Porter * 130394b701cSMatt Porter * Requests ownership of an outbound mailbox resource and binds 131394b701cSMatt Porter * a callback function to the resource. Returns 0 on success. 132394b701cSMatt Porter */ 133394b701cSMatt Porter int rio_request_outb_mbox(struct rio_mport *mport, 1346978bbc0SMatt Porter void *dev_id, 135394b701cSMatt Porter int mbox, 136394b701cSMatt Porter int entries, 1376978bbc0SMatt Porter void (*moutb) (struct rio_mport * mport, void *dev_id, int mbox, int slot)) 138394b701cSMatt Porter { 139f8f06269SAlexandre Bounine int rc = -ENOSYS; 140f8f06269SAlexandre Bounine struct resource *res; 141394b701cSMatt Porter 142f8f06269SAlexandre Bounine if (mport->ops->open_outb_mbox == NULL) 143f8f06269SAlexandre Bounine goto out; 144f8f06269SAlexandre Bounine 145f8f06269SAlexandre Bounine res = kmalloc(sizeof(struct resource), GFP_KERNEL); 146394b701cSMatt Porter 147394b701cSMatt Porter if (res) { 148394b701cSMatt Porter rio_init_mbox_res(res, mbox, mbox); 149394b701cSMatt Porter 150394b701cSMatt Porter /* Make sure this outbound mailbox isn't in use */ 151394b701cSMatt Porter if ((rc = 152394b701cSMatt Porter request_resource(&mport->riores[RIO_OUTB_MBOX_RESOURCE], 153394b701cSMatt Porter res)) < 0) { 154394b701cSMatt Porter kfree(res); 155394b701cSMatt Porter goto out; 156394b701cSMatt Porter } 157394b701cSMatt Porter 158394b701cSMatt Porter mport->outb_msg[mbox].res = res; 159394b701cSMatt Porter 160394b701cSMatt Porter /* Hook the inbound message callback */ 161394b701cSMatt Porter mport->outb_msg[mbox].mcback = moutb; 162394b701cSMatt Porter 163f8f06269SAlexandre Bounine rc = mport->ops->open_outb_mbox(mport, dev_id, mbox, entries); 164394b701cSMatt Porter } else 165394b701cSMatt Porter rc = -ENOMEM; 166394b701cSMatt Porter 167394b701cSMatt Porter out: 168394b701cSMatt Porter return rc; 169394b701cSMatt Porter } 170394b701cSMatt Porter 171394b701cSMatt Porter /** 172394b701cSMatt Porter * rio_release_outb_mbox - release outbound mailbox message service 173394b701cSMatt Porter * @mport: RIO master port from which to release the mailbox resource 174394b701cSMatt Porter * @mbox: Mailbox number to release 175394b701cSMatt Porter * 176394b701cSMatt Porter * Releases ownership of an inbound mailbox resource. Returns 0 177394b701cSMatt Porter * if the request has been satisfied. 178394b701cSMatt Porter */ 179394b701cSMatt Porter int rio_release_outb_mbox(struct rio_mport *mport, int mbox) 180394b701cSMatt Porter { 181f8f06269SAlexandre Bounine if (mport->ops->close_outb_mbox) { 182f8f06269SAlexandre Bounine mport->ops->close_outb_mbox(mport, mbox); 183394b701cSMatt Porter 184394b701cSMatt Porter /* Release the mailbox resource */ 185394b701cSMatt Porter return release_resource(mport->outb_msg[mbox].res); 186f8f06269SAlexandre Bounine } else 187f8f06269SAlexandre Bounine return -ENOSYS; 188394b701cSMatt Porter } 189394b701cSMatt Porter 190394b701cSMatt Porter /** 191394b701cSMatt Porter * rio_setup_inb_dbell - bind inbound doorbell callback 192394b701cSMatt Porter * @mport: RIO master port to bind the doorbell callback 1936978bbc0SMatt Porter * @dev_id: Device specific pointer to pass on event 194394b701cSMatt Porter * @res: Doorbell message resource 195394b701cSMatt Porter * @dinb: Callback to execute when doorbell is received 196394b701cSMatt Porter * 197394b701cSMatt Porter * Adds a doorbell resource/callback pair into a port's 198394b701cSMatt Porter * doorbell event list. Returns 0 if the request has been 199394b701cSMatt Porter * satisfied. 200394b701cSMatt Porter */ 201394b701cSMatt Porter static int 2026978bbc0SMatt Porter rio_setup_inb_dbell(struct rio_mport *mport, void *dev_id, struct resource *res, 2036978bbc0SMatt Porter void (*dinb) (struct rio_mport * mport, void *dev_id, u16 src, u16 dst, 204394b701cSMatt Porter u16 info)) 205394b701cSMatt Porter { 206394b701cSMatt Porter int rc = 0; 207394b701cSMatt Porter struct rio_dbell *dbell; 208394b701cSMatt Porter 209394b701cSMatt Porter if (!(dbell = kmalloc(sizeof(struct rio_dbell), GFP_KERNEL))) { 210394b701cSMatt Porter rc = -ENOMEM; 211394b701cSMatt Porter goto out; 212394b701cSMatt Porter } 213394b701cSMatt Porter 214394b701cSMatt Porter dbell->res = res; 215394b701cSMatt Porter dbell->dinb = dinb; 2166978bbc0SMatt Porter dbell->dev_id = dev_id; 217394b701cSMatt Porter 218394b701cSMatt Porter list_add_tail(&dbell->node, &mport->dbells); 219394b701cSMatt Porter 220394b701cSMatt Porter out: 221394b701cSMatt Porter return rc; 222394b701cSMatt Porter } 223394b701cSMatt Porter 224394b701cSMatt Porter /** 225394b701cSMatt Porter * rio_request_inb_dbell - request inbound doorbell message service 226394b701cSMatt Porter * @mport: RIO master port from which to allocate the doorbell resource 2276978bbc0SMatt Porter * @dev_id: Device specific pointer to pass on event 228394b701cSMatt Porter * @start: Doorbell info range start 229394b701cSMatt Porter * @end: Doorbell info range end 230394b701cSMatt Porter * @dinb: Callback to execute when doorbell is received 231394b701cSMatt Porter * 232394b701cSMatt Porter * Requests ownership of an inbound doorbell resource and binds 233394b701cSMatt Porter * a callback function to the resource. Returns 0 if the request 234394b701cSMatt Porter * has been satisfied. 235394b701cSMatt Porter */ 236394b701cSMatt Porter int rio_request_inb_dbell(struct rio_mport *mport, 2376978bbc0SMatt Porter void *dev_id, 238394b701cSMatt Porter u16 start, 239394b701cSMatt Porter u16 end, 2406978bbc0SMatt Porter void (*dinb) (struct rio_mport * mport, void *dev_id, u16 src, 241394b701cSMatt Porter u16 dst, u16 info)) 242394b701cSMatt Porter { 243394b701cSMatt Porter int rc = 0; 244394b701cSMatt Porter 245394b701cSMatt Porter struct resource *res = kmalloc(sizeof(struct resource), GFP_KERNEL); 246394b701cSMatt Porter 247394b701cSMatt Porter if (res) { 248394b701cSMatt Porter rio_init_dbell_res(res, start, end); 249394b701cSMatt Porter 250394b701cSMatt Porter /* Make sure these doorbells aren't in use */ 251394b701cSMatt Porter if ((rc = 252394b701cSMatt Porter request_resource(&mport->riores[RIO_DOORBELL_RESOURCE], 253394b701cSMatt Porter res)) < 0) { 254394b701cSMatt Porter kfree(res); 255394b701cSMatt Porter goto out; 256394b701cSMatt Porter } 257394b701cSMatt Porter 258394b701cSMatt Porter /* Hook the doorbell callback */ 2596978bbc0SMatt Porter rc = rio_setup_inb_dbell(mport, dev_id, res, dinb); 260394b701cSMatt Porter } else 261394b701cSMatt Porter rc = -ENOMEM; 262394b701cSMatt Porter 263394b701cSMatt Porter out: 264394b701cSMatt Porter return rc; 265394b701cSMatt Porter } 266394b701cSMatt Porter 267394b701cSMatt Porter /** 268394b701cSMatt Porter * rio_release_inb_dbell - release inbound doorbell message service 269394b701cSMatt Porter * @mport: RIO master port from which to release the doorbell resource 270394b701cSMatt Porter * @start: Doorbell info range start 271394b701cSMatt Porter * @end: Doorbell info range end 272394b701cSMatt Porter * 273394b701cSMatt Porter * Releases ownership of an inbound doorbell resource and removes 274394b701cSMatt Porter * callback from the doorbell event list. Returns 0 if the request 275394b701cSMatt Porter * has been satisfied. 276394b701cSMatt Porter */ 277394b701cSMatt Porter int rio_release_inb_dbell(struct rio_mport *mport, u16 start, u16 end) 278394b701cSMatt Porter { 279394b701cSMatt Porter int rc = 0, found = 0; 280394b701cSMatt Porter struct rio_dbell *dbell; 281394b701cSMatt Porter 282394b701cSMatt Porter list_for_each_entry(dbell, &mport->dbells, node) { 283394b701cSMatt Porter if ((dbell->res->start == start) && (dbell->res->end == end)) { 284394b701cSMatt Porter found = 1; 285394b701cSMatt Porter break; 286394b701cSMatt Porter } 287394b701cSMatt Porter } 288394b701cSMatt Porter 289394b701cSMatt Porter /* If we can't find an exact match, fail */ 290394b701cSMatt Porter if (!found) { 291394b701cSMatt Porter rc = -EINVAL; 292394b701cSMatt Porter goto out; 293394b701cSMatt Porter } 294394b701cSMatt Porter 295394b701cSMatt Porter /* Delete from list */ 296394b701cSMatt Porter list_del(&dbell->node); 297394b701cSMatt Porter 298394b701cSMatt Porter /* Release the doorbell resource */ 299394b701cSMatt Porter rc = release_resource(dbell->res); 300394b701cSMatt Porter 301394b701cSMatt Porter /* Free the doorbell event */ 302394b701cSMatt Porter kfree(dbell); 303394b701cSMatt Porter 304394b701cSMatt Porter out: 305394b701cSMatt Porter return rc; 306394b701cSMatt Porter } 307394b701cSMatt Porter 308394b701cSMatt Porter /** 309394b701cSMatt Porter * rio_request_outb_dbell - request outbound doorbell message range 310394b701cSMatt Porter * @rdev: RIO device from which to allocate the doorbell resource 311394b701cSMatt Porter * @start: Doorbell message range start 312394b701cSMatt Porter * @end: Doorbell message range end 313394b701cSMatt Porter * 314394b701cSMatt Porter * Requests ownership of a doorbell message range. Returns a resource 315394b701cSMatt Porter * if the request has been satisfied or %NULL on failure. 316394b701cSMatt Porter */ 317394b701cSMatt Porter struct resource *rio_request_outb_dbell(struct rio_dev *rdev, u16 start, 318394b701cSMatt Porter u16 end) 319394b701cSMatt Porter { 320394b701cSMatt Porter struct resource *res = kmalloc(sizeof(struct resource), GFP_KERNEL); 321394b701cSMatt Porter 322394b701cSMatt Porter if (res) { 323394b701cSMatt Porter rio_init_dbell_res(res, start, end); 324394b701cSMatt Porter 325394b701cSMatt Porter /* Make sure these doorbells aren't in use */ 326394b701cSMatt Porter if (request_resource(&rdev->riores[RIO_DOORBELL_RESOURCE], res) 327394b701cSMatt Porter < 0) { 328394b701cSMatt Porter kfree(res); 329394b701cSMatt Porter res = NULL; 330394b701cSMatt Porter } 331394b701cSMatt Porter } 332394b701cSMatt Porter 333394b701cSMatt Porter return res; 334394b701cSMatt Porter } 335394b701cSMatt Porter 336394b701cSMatt Porter /** 337394b701cSMatt Porter * rio_release_outb_dbell - release outbound doorbell message range 338394b701cSMatt Porter * @rdev: RIO device from which to release the doorbell resource 339394b701cSMatt Porter * @res: Doorbell resource to be freed 340394b701cSMatt Porter * 341394b701cSMatt Porter * Releases ownership of a doorbell message range. Returns 0 if the 342394b701cSMatt Porter * request has been satisfied. 343394b701cSMatt Porter */ 344394b701cSMatt Porter int rio_release_outb_dbell(struct rio_dev *rdev, struct resource *res) 345394b701cSMatt Porter { 346394b701cSMatt Porter int rc = release_resource(res); 347394b701cSMatt Porter 348394b701cSMatt Porter kfree(res); 349394b701cSMatt Porter 350394b701cSMatt Porter return rc; 351394b701cSMatt Porter } 352394b701cSMatt Porter 353394b701cSMatt Porter /** 354e5cabeb3SAlexandre Bounine * rio_request_inb_pwrite - request inbound port-write message service 35597ef6f74SRandy Dunlap * @rdev: RIO device to which register inbound port-write callback routine 356e5cabeb3SAlexandre Bounine * @pwcback: Callback routine to execute when port-write is received 357e5cabeb3SAlexandre Bounine * 358e5cabeb3SAlexandre Bounine * Binds a port-write callback function to the RapidIO device. 359e5cabeb3SAlexandre Bounine * Returns 0 if the request has been satisfied. 360e5cabeb3SAlexandre Bounine */ 361e5cabeb3SAlexandre Bounine int rio_request_inb_pwrite(struct rio_dev *rdev, 362e5cabeb3SAlexandre Bounine int (*pwcback)(struct rio_dev *rdev, union rio_pw_msg *msg, int step)) 363e5cabeb3SAlexandre Bounine { 364e5cabeb3SAlexandre Bounine int rc = 0; 365e5cabeb3SAlexandre Bounine 366e5cabeb3SAlexandre Bounine spin_lock(&rio_global_list_lock); 367e5cabeb3SAlexandre Bounine if (rdev->pwcback != NULL) 368e5cabeb3SAlexandre Bounine rc = -ENOMEM; 369e5cabeb3SAlexandre Bounine else 370e5cabeb3SAlexandre Bounine rdev->pwcback = pwcback; 371e5cabeb3SAlexandre Bounine 372e5cabeb3SAlexandre Bounine spin_unlock(&rio_global_list_lock); 373e5cabeb3SAlexandre Bounine return rc; 374e5cabeb3SAlexandre Bounine } 375e5cabeb3SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_request_inb_pwrite); 376e5cabeb3SAlexandre Bounine 377e5cabeb3SAlexandre Bounine /** 378e5cabeb3SAlexandre Bounine * rio_release_inb_pwrite - release inbound port-write message service 379e5cabeb3SAlexandre Bounine * @rdev: RIO device which registered for inbound port-write callback 380e5cabeb3SAlexandre Bounine * 381e5cabeb3SAlexandre Bounine * Removes callback from the rio_dev structure. Returns 0 if the request 382e5cabeb3SAlexandre Bounine * has been satisfied. 383e5cabeb3SAlexandre Bounine */ 384e5cabeb3SAlexandre Bounine int rio_release_inb_pwrite(struct rio_dev *rdev) 385e5cabeb3SAlexandre Bounine { 386e5cabeb3SAlexandre Bounine int rc = -ENOMEM; 387e5cabeb3SAlexandre Bounine 388e5cabeb3SAlexandre Bounine spin_lock(&rio_global_list_lock); 389e5cabeb3SAlexandre Bounine if (rdev->pwcback) { 390e5cabeb3SAlexandre Bounine rdev->pwcback = NULL; 391e5cabeb3SAlexandre Bounine rc = 0; 392e5cabeb3SAlexandre Bounine } 393e5cabeb3SAlexandre Bounine 394e5cabeb3SAlexandre Bounine spin_unlock(&rio_global_list_lock); 395e5cabeb3SAlexandre Bounine return rc; 396e5cabeb3SAlexandre Bounine } 397e5cabeb3SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_release_inb_pwrite); 398e5cabeb3SAlexandre Bounine 399e5cabeb3SAlexandre Bounine /** 400e5cabeb3SAlexandre Bounine * rio_mport_get_physefb - Helper function that returns register offset 401e5cabeb3SAlexandre Bounine * for Physical Layer Extended Features Block. 40297ef6f74SRandy Dunlap * @port: Master port to issue transaction 40397ef6f74SRandy Dunlap * @local: Indicate a local master port or remote device access 40497ef6f74SRandy Dunlap * @destid: Destination ID of the device 40597ef6f74SRandy Dunlap * @hopcount: Number of switch hops to the device 406e5cabeb3SAlexandre Bounine */ 407e5cabeb3SAlexandre Bounine u32 408e5cabeb3SAlexandre Bounine rio_mport_get_physefb(struct rio_mport *port, int local, 409e5cabeb3SAlexandre Bounine u16 destid, u8 hopcount) 410e5cabeb3SAlexandre Bounine { 411e5cabeb3SAlexandre Bounine u32 ext_ftr_ptr; 412e5cabeb3SAlexandre Bounine u32 ftr_header; 413e5cabeb3SAlexandre Bounine 414e5cabeb3SAlexandre Bounine ext_ftr_ptr = rio_mport_get_efb(port, local, destid, hopcount, 0); 415e5cabeb3SAlexandre Bounine 416e5cabeb3SAlexandre Bounine while (ext_ftr_ptr) { 417e5cabeb3SAlexandre Bounine if (local) 418e5cabeb3SAlexandre Bounine rio_local_read_config_32(port, ext_ftr_ptr, 419e5cabeb3SAlexandre Bounine &ftr_header); 420e5cabeb3SAlexandre Bounine else 421e5cabeb3SAlexandre Bounine rio_mport_read_config_32(port, destid, hopcount, 422e5cabeb3SAlexandre Bounine ext_ftr_ptr, &ftr_header); 423e5cabeb3SAlexandre Bounine 424e5cabeb3SAlexandre Bounine ftr_header = RIO_GET_BLOCK_ID(ftr_header); 425e5cabeb3SAlexandre Bounine switch (ftr_header) { 426e5cabeb3SAlexandre Bounine 427e5cabeb3SAlexandre Bounine case RIO_EFB_SER_EP_ID_V13P: 428e5cabeb3SAlexandre Bounine case RIO_EFB_SER_EP_REC_ID_V13P: 429e5cabeb3SAlexandre Bounine case RIO_EFB_SER_EP_FREE_ID_V13P: 430e5cabeb3SAlexandre Bounine case RIO_EFB_SER_EP_ID: 431e5cabeb3SAlexandre Bounine case RIO_EFB_SER_EP_REC_ID: 432e5cabeb3SAlexandre Bounine case RIO_EFB_SER_EP_FREE_ID: 433e5cabeb3SAlexandre Bounine case RIO_EFB_SER_EP_FREC_ID: 434e5cabeb3SAlexandre Bounine 435e5cabeb3SAlexandre Bounine return ext_ftr_ptr; 436e5cabeb3SAlexandre Bounine 437e5cabeb3SAlexandre Bounine default: 438e5cabeb3SAlexandre Bounine break; 439e5cabeb3SAlexandre Bounine } 440e5cabeb3SAlexandre Bounine 441e5cabeb3SAlexandre Bounine ext_ftr_ptr = rio_mport_get_efb(port, local, destid, 442e5cabeb3SAlexandre Bounine hopcount, ext_ftr_ptr); 443e5cabeb3SAlexandre Bounine } 444e5cabeb3SAlexandre Bounine 445e5cabeb3SAlexandre Bounine return ext_ftr_ptr; 446e5cabeb3SAlexandre Bounine } 447e5cabeb3SAlexandre Bounine 448e5cabeb3SAlexandre Bounine /** 449e5cabeb3SAlexandre Bounine * rio_get_comptag - Begin or continue searching for a RIO device by component tag 45097ef6f74SRandy Dunlap * @comp_tag: RIO component tag to match 451e5cabeb3SAlexandre Bounine * @from: Previous RIO device found in search, or %NULL for new search 452e5cabeb3SAlexandre Bounine * 453e5cabeb3SAlexandre Bounine * Iterates through the list of known RIO devices. If a RIO device is 454e5cabeb3SAlexandre Bounine * found with a matching @comp_tag, a pointer to its device 455e5cabeb3SAlexandre Bounine * structure is returned. Otherwise, %NULL is returned. A new search 456e5cabeb3SAlexandre Bounine * is initiated by passing %NULL to the @from argument. Otherwise, if 457e5cabeb3SAlexandre Bounine * @from is not %NULL, searches continue from next device on the global 458e5cabeb3SAlexandre Bounine * list. 459e5cabeb3SAlexandre Bounine */ 460af84ca38SAlexandre Bounine struct rio_dev *rio_get_comptag(u32 comp_tag, struct rio_dev *from) 461e5cabeb3SAlexandre Bounine { 462e5cabeb3SAlexandre Bounine struct list_head *n; 463e5cabeb3SAlexandre Bounine struct rio_dev *rdev; 464e5cabeb3SAlexandre Bounine 465e5cabeb3SAlexandre Bounine spin_lock(&rio_global_list_lock); 466e5cabeb3SAlexandre Bounine n = from ? from->global_list.next : rio_devices.next; 467e5cabeb3SAlexandre Bounine 468e5cabeb3SAlexandre Bounine while (n && (n != &rio_devices)) { 469e5cabeb3SAlexandre Bounine rdev = rio_dev_g(n); 470e5cabeb3SAlexandre Bounine if (rdev->comp_tag == comp_tag) 471e5cabeb3SAlexandre Bounine goto exit; 472e5cabeb3SAlexandre Bounine n = n->next; 473e5cabeb3SAlexandre Bounine } 474e5cabeb3SAlexandre Bounine rdev = NULL; 475e5cabeb3SAlexandre Bounine exit: 476e5cabeb3SAlexandre Bounine spin_unlock(&rio_global_list_lock); 477e5cabeb3SAlexandre Bounine return rdev; 478e5cabeb3SAlexandre Bounine } 479e5cabeb3SAlexandre Bounine 480e5cabeb3SAlexandre Bounine /** 481e5cabeb3SAlexandre Bounine * rio_set_port_lockout - Sets/clears LOCKOUT bit (RIO EM 1.3) for a switch port. 482e5cabeb3SAlexandre Bounine * @rdev: Pointer to RIO device control structure 483e5cabeb3SAlexandre Bounine * @pnum: Switch port number to set LOCKOUT bit 484e5cabeb3SAlexandre Bounine * @lock: Operation : set (=1) or clear (=0) 485e5cabeb3SAlexandre Bounine */ 486e5cabeb3SAlexandre Bounine int rio_set_port_lockout(struct rio_dev *rdev, u32 pnum, int lock) 487e5cabeb3SAlexandre Bounine { 488e5cabeb3SAlexandre Bounine u32 regval; 489e5cabeb3SAlexandre Bounine 490a93192a5SAlexandre Bounine rio_read_config_32(rdev, 491e5cabeb3SAlexandre Bounine rdev->phys_efptr + RIO_PORT_N_CTL_CSR(pnum), 492e5cabeb3SAlexandre Bounine ®val); 493e5cabeb3SAlexandre Bounine if (lock) 494e5cabeb3SAlexandre Bounine regval |= RIO_PORT_N_CTL_LOCKOUT; 495e5cabeb3SAlexandre Bounine else 496e5cabeb3SAlexandre Bounine regval &= ~RIO_PORT_N_CTL_LOCKOUT; 497e5cabeb3SAlexandre Bounine 498a93192a5SAlexandre Bounine rio_write_config_32(rdev, 499e5cabeb3SAlexandre Bounine rdev->phys_efptr + RIO_PORT_N_CTL_CSR(pnum), 500e5cabeb3SAlexandre Bounine regval); 501e5cabeb3SAlexandre Bounine return 0; 502e5cabeb3SAlexandre Bounine } 503e5cabeb3SAlexandre Bounine 504e5cabeb3SAlexandre Bounine /** 5056429cd49SAlexandre Bounine * rio_chk_dev_route - Validate route to the specified device. 5066429cd49SAlexandre Bounine * @rdev: RIO device failed to respond 5076429cd49SAlexandre Bounine * @nrdev: Last active device on the route to rdev 5086429cd49SAlexandre Bounine * @npnum: nrdev's port number on the route to rdev 5096429cd49SAlexandre Bounine * 5106429cd49SAlexandre Bounine * Follows a route to the specified RIO device to determine the last available 5116429cd49SAlexandre Bounine * device (and corresponding RIO port) on the route. 5126429cd49SAlexandre Bounine */ 5136429cd49SAlexandre Bounine static int 5146429cd49SAlexandre Bounine rio_chk_dev_route(struct rio_dev *rdev, struct rio_dev **nrdev, int *npnum) 5156429cd49SAlexandre Bounine { 5166429cd49SAlexandre Bounine u32 result; 517a93192a5SAlexandre Bounine int p_port, rc = -EIO; 5186429cd49SAlexandre Bounine struct rio_dev *prev = NULL; 5196429cd49SAlexandre Bounine 5206429cd49SAlexandre Bounine /* Find switch with failed RIO link */ 5216429cd49SAlexandre Bounine while (rdev->prev && (rdev->prev->pef & RIO_PEF_SWITCH)) { 5226429cd49SAlexandre Bounine if (!rio_read_config_32(rdev->prev, RIO_DEV_ID_CAR, &result)) { 5236429cd49SAlexandre Bounine prev = rdev->prev; 5246429cd49SAlexandre Bounine break; 5256429cd49SAlexandre Bounine } 5266429cd49SAlexandre Bounine rdev = rdev->prev; 5276429cd49SAlexandre Bounine } 5286429cd49SAlexandre Bounine 5296429cd49SAlexandre Bounine if (prev == NULL) 5306429cd49SAlexandre Bounine goto err_out; 5316429cd49SAlexandre Bounine 532a93192a5SAlexandre Bounine p_port = prev->rswitch->route_table[rdev->destid]; 5336429cd49SAlexandre Bounine 534af84ca38SAlexandre Bounine if (p_port != RIO_INVALID_ROUTE) { 5356429cd49SAlexandre Bounine pr_debug("RIO: link failed on [%s]-P%d\n", 5366429cd49SAlexandre Bounine rio_name(prev), p_port); 5376429cd49SAlexandre Bounine *nrdev = prev; 5386429cd49SAlexandre Bounine *npnum = p_port; 5396429cd49SAlexandre Bounine rc = 0; 5406429cd49SAlexandre Bounine } else 541af84ca38SAlexandre Bounine pr_debug("RIO: failed to trace route to %s\n", rio_name(rdev)); 5426429cd49SAlexandre Bounine err_out: 5436429cd49SAlexandre Bounine return rc; 5446429cd49SAlexandre Bounine } 5456429cd49SAlexandre Bounine 5466429cd49SAlexandre Bounine /** 5476429cd49SAlexandre Bounine * rio_mport_chk_dev_access - Validate access to the specified device. 5486429cd49SAlexandre Bounine * @mport: Master port to send transactions 5496429cd49SAlexandre Bounine * @destid: Device destination ID in network 5506429cd49SAlexandre Bounine * @hopcount: Number of hops into the network 5516429cd49SAlexandre Bounine */ 552e274e0edSAlexandre Bounine int 5536429cd49SAlexandre Bounine rio_mport_chk_dev_access(struct rio_mport *mport, u16 destid, u8 hopcount) 5546429cd49SAlexandre Bounine { 5556429cd49SAlexandre Bounine int i = 0; 5566429cd49SAlexandre Bounine u32 tmp; 5576429cd49SAlexandre Bounine 5586429cd49SAlexandre Bounine while (rio_mport_read_config_32(mport, destid, hopcount, 5596429cd49SAlexandre Bounine RIO_DEV_ID_CAR, &tmp)) { 5606429cd49SAlexandre Bounine i++; 5616429cd49SAlexandre Bounine if (i == RIO_MAX_CHK_RETRY) 5626429cd49SAlexandre Bounine return -EIO; 5636429cd49SAlexandre Bounine mdelay(1); 5646429cd49SAlexandre Bounine } 5656429cd49SAlexandre Bounine 5666429cd49SAlexandre Bounine return 0; 5676429cd49SAlexandre Bounine } 5686429cd49SAlexandre Bounine 5696429cd49SAlexandre Bounine /** 5706429cd49SAlexandre Bounine * rio_chk_dev_access - Validate access to the specified device. 5716429cd49SAlexandre Bounine * @rdev: Pointer to RIO device control structure 5726429cd49SAlexandre Bounine */ 5736429cd49SAlexandre Bounine static int rio_chk_dev_access(struct rio_dev *rdev) 5746429cd49SAlexandre Bounine { 575a93192a5SAlexandre Bounine return rio_mport_chk_dev_access(rdev->net->hport, 576a93192a5SAlexandre Bounine rdev->destid, rdev->hopcount); 5776429cd49SAlexandre Bounine } 5786429cd49SAlexandre Bounine 5796429cd49SAlexandre Bounine /** 580dd5648c9SAlexandre Bounine * rio_get_input_status - Sends a Link-Request/Input-Status control symbol and 581dd5648c9SAlexandre Bounine * returns link-response (if requested). 582dd5648c9SAlexandre Bounine * @rdev: RIO devive to issue Input-status command 583dd5648c9SAlexandre Bounine * @pnum: Device port number to issue the command 584dd5648c9SAlexandre Bounine * @lnkresp: Response from a link partner 585dd5648c9SAlexandre Bounine */ 586dd5648c9SAlexandre Bounine static int 587dd5648c9SAlexandre Bounine rio_get_input_status(struct rio_dev *rdev, int pnum, u32 *lnkresp) 588dd5648c9SAlexandre Bounine { 589dd5648c9SAlexandre Bounine u32 regval; 590dd5648c9SAlexandre Bounine int checkcount; 591dd5648c9SAlexandre Bounine 592dd5648c9SAlexandre Bounine if (lnkresp) { 593dd5648c9SAlexandre Bounine /* Read from link maintenance response register 594dd5648c9SAlexandre Bounine * to clear valid bit */ 595a93192a5SAlexandre Bounine rio_read_config_32(rdev, 596dd5648c9SAlexandre Bounine rdev->phys_efptr + RIO_PORT_N_MNT_RSP_CSR(pnum), 597dd5648c9SAlexandre Bounine ®val); 598dd5648c9SAlexandre Bounine udelay(50); 599dd5648c9SAlexandre Bounine } 600dd5648c9SAlexandre Bounine 601dd5648c9SAlexandre Bounine /* Issue Input-status command */ 602a93192a5SAlexandre Bounine rio_write_config_32(rdev, 603dd5648c9SAlexandre Bounine rdev->phys_efptr + RIO_PORT_N_MNT_REQ_CSR(pnum), 604dd5648c9SAlexandre Bounine RIO_MNT_REQ_CMD_IS); 605dd5648c9SAlexandre Bounine 606dd5648c9SAlexandre Bounine /* Exit if the response is not expected */ 607dd5648c9SAlexandre Bounine if (lnkresp == NULL) 608dd5648c9SAlexandre Bounine return 0; 609dd5648c9SAlexandre Bounine 610dd5648c9SAlexandre Bounine checkcount = 3; 611dd5648c9SAlexandre Bounine while (checkcount--) { 612dd5648c9SAlexandre Bounine udelay(50); 613a93192a5SAlexandre Bounine rio_read_config_32(rdev, 614dd5648c9SAlexandre Bounine rdev->phys_efptr + RIO_PORT_N_MNT_RSP_CSR(pnum), 615dd5648c9SAlexandre Bounine ®val); 616dd5648c9SAlexandre Bounine if (regval & RIO_PORT_N_MNT_RSP_RVAL) { 617dd5648c9SAlexandre Bounine *lnkresp = regval; 618dd5648c9SAlexandre Bounine return 0; 619dd5648c9SAlexandre Bounine } 620dd5648c9SAlexandre Bounine } 621dd5648c9SAlexandre Bounine 622dd5648c9SAlexandre Bounine return -EIO; 623dd5648c9SAlexandre Bounine } 624dd5648c9SAlexandre Bounine 625dd5648c9SAlexandre Bounine /** 626dd5648c9SAlexandre Bounine * rio_clr_err_stopped - Clears port Error-stopped states. 627dd5648c9SAlexandre Bounine * @rdev: Pointer to RIO device control structure 628dd5648c9SAlexandre Bounine * @pnum: Switch port number to clear errors 629dd5648c9SAlexandre Bounine * @err_status: port error status (if 0 reads register from device) 630dd5648c9SAlexandre Bounine */ 631dd5648c9SAlexandre Bounine static int rio_clr_err_stopped(struct rio_dev *rdev, u32 pnum, u32 err_status) 632dd5648c9SAlexandre Bounine { 633dd5648c9SAlexandre Bounine struct rio_dev *nextdev = rdev->rswitch->nextdev[pnum]; 634dd5648c9SAlexandre Bounine u32 regval; 635dd5648c9SAlexandre Bounine u32 far_ackid, far_linkstat, near_ackid; 636dd5648c9SAlexandre Bounine 637dd5648c9SAlexandre Bounine if (err_status == 0) 638a93192a5SAlexandre Bounine rio_read_config_32(rdev, 639dd5648c9SAlexandre Bounine rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(pnum), 640dd5648c9SAlexandre Bounine &err_status); 641dd5648c9SAlexandre Bounine 642dd5648c9SAlexandre Bounine if (err_status & RIO_PORT_N_ERR_STS_PW_OUT_ES) { 643dd5648c9SAlexandre Bounine pr_debug("RIO_EM: servicing Output Error-Stopped state\n"); 644dd5648c9SAlexandre Bounine /* 645dd5648c9SAlexandre Bounine * Send a Link-Request/Input-Status control symbol 646dd5648c9SAlexandre Bounine */ 647dd5648c9SAlexandre Bounine if (rio_get_input_status(rdev, pnum, ®val)) { 648dd5648c9SAlexandre Bounine pr_debug("RIO_EM: Input-status response timeout\n"); 649dd5648c9SAlexandre Bounine goto rd_err; 650dd5648c9SAlexandre Bounine } 651dd5648c9SAlexandre Bounine 652dd5648c9SAlexandre Bounine pr_debug("RIO_EM: SP%d Input-status response=0x%08x\n", 653dd5648c9SAlexandre Bounine pnum, regval); 654dd5648c9SAlexandre Bounine far_ackid = (regval & RIO_PORT_N_MNT_RSP_ASTAT) >> 5; 655dd5648c9SAlexandre Bounine far_linkstat = regval & RIO_PORT_N_MNT_RSP_LSTAT; 656a93192a5SAlexandre Bounine rio_read_config_32(rdev, 657dd5648c9SAlexandre Bounine rdev->phys_efptr + RIO_PORT_N_ACK_STS_CSR(pnum), 658dd5648c9SAlexandre Bounine ®val); 659dd5648c9SAlexandre Bounine pr_debug("RIO_EM: SP%d_ACK_STS_CSR=0x%08x\n", pnum, regval); 660dd5648c9SAlexandre Bounine near_ackid = (regval & RIO_PORT_N_ACK_INBOUND) >> 24; 661dd5648c9SAlexandre Bounine pr_debug("RIO_EM: SP%d far_ackID=0x%02x far_linkstat=0x%02x" \ 662dd5648c9SAlexandre Bounine " near_ackID=0x%02x\n", 663dd5648c9SAlexandre Bounine pnum, far_ackid, far_linkstat, near_ackid); 664dd5648c9SAlexandre Bounine 665dd5648c9SAlexandre Bounine /* 666dd5648c9SAlexandre Bounine * If required, synchronize ackIDs of near and 667dd5648c9SAlexandre Bounine * far sides. 668dd5648c9SAlexandre Bounine */ 669dd5648c9SAlexandre Bounine if ((far_ackid != ((regval & RIO_PORT_N_ACK_OUTSTAND) >> 8)) || 670dd5648c9SAlexandre Bounine (far_ackid != (regval & RIO_PORT_N_ACK_OUTBOUND))) { 671dd5648c9SAlexandre Bounine /* Align near outstanding/outbound ackIDs with 672dd5648c9SAlexandre Bounine * far inbound. 673dd5648c9SAlexandre Bounine */ 674a93192a5SAlexandre Bounine rio_write_config_32(rdev, 675a93192a5SAlexandre Bounine rdev->phys_efptr + RIO_PORT_N_ACK_STS_CSR(pnum), 676dd5648c9SAlexandre Bounine (near_ackid << 24) | 677dd5648c9SAlexandre Bounine (far_ackid << 8) | far_ackid); 678dd5648c9SAlexandre Bounine /* Align far outstanding/outbound ackIDs with 679dd5648c9SAlexandre Bounine * near inbound. 680dd5648c9SAlexandre Bounine */ 681dd5648c9SAlexandre Bounine far_ackid++; 682dd5648c9SAlexandre Bounine if (nextdev) 683dd5648c9SAlexandre Bounine rio_write_config_32(nextdev, 684dd5648c9SAlexandre Bounine nextdev->phys_efptr + 685dd5648c9SAlexandre Bounine RIO_PORT_N_ACK_STS_CSR(RIO_GET_PORT_NUM(nextdev->swpinfo)), 686dd5648c9SAlexandre Bounine (far_ackid << 24) | 687dd5648c9SAlexandre Bounine (near_ackid << 8) | near_ackid); 688dd5648c9SAlexandre Bounine else 689dd5648c9SAlexandre Bounine pr_debug("RIO_EM: Invalid nextdev pointer (NULL)\n"); 690dd5648c9SAlexandre Bounine } 691dd5648c9SAlexandre Bounine rd_err: 692a93192a5SAlexandre Bounine rio_read_config_32(rdev, 693dd5648c9SAlexandre Bounine rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(pnum), 694dd5648c9SAlexandre Bounine &err_status); 695dd5648c9SAlexandre Bounine pr_debug("RIO_EM: SP%d_ERR_STS_CSR=0x%08x\n", pnum, err_status); 696dd5648c9SAlexandre Bounine } 697dd5648c9SAlexandre Bounine 698dd5648c9SAlexandre Bounine if ((err_status & RIO_PORT_N_ERR_STS_PW_INP_ES) && nextdev) { 699dd5648c9SAlexandre Bounine pr_debug("RIO_EM: servicing Input Error-Stopped state\n"); 700dd5648c9SAlexandre Bounine rio_get_input_status(nextdev, 701dd5648c9SAlexandre Bounine RIO_GET_PORT_NUM(nextdev->swpinfo), NULL); 702dd5648c9SAlexandre Bounine udelay(50); 703dd5648c9SAlexandre Bounine 704a93192a5SAlexandre Bounine rio_read_config_32(rdev, 705dd5648c9SAlexandre Bounine rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(pnum), 706dd5648c9SAlexandre Bounine &err_status); 707dd5648c9SAlexandre Bounine pr_debug("RIO_EM: SP%d_ERR_STS_CSR=0x%08x\n", pnum, err_status); 708dd5648c9SAlexandre Bounine } 709dd5648c9SAlexandre Bounine 710dd5648c9SAlexandre Bounine return (err_status & (RIO_PORT_N_ERR_STS_PW_OUT_ES | 711dd5648c9SAlexandre Bounine RIO_PORT_N_ERR_STS_PW_INP_ES)) ? 1 : 0; 712dd5648c9SAlexandre Bounine } 713dd5648c9SAlexandre Bounine 714dd5648c9SAlexandre Bounine /** 715e5cabeb3SAlexandre Bounine * rio_inb_pwrite_handler - process inbound port-write message 716e5cabeb3SAlexandre Bounine * @pw_msg: pointer to inbound port-write message 717e5cabeb3SAlexandre Bounine * 718e5cabeb3SAlexandre Bounine * Processes an inbound port-write message. Returns 0 if the request 719e5cabeb3SAlexandre Bounine * has been satisfied. 720e5cabeb3SAlexandre Bounine */ 721e5cabeb3SAlexandre Bounine int rio_inb_pwrite_handler(union rio_pw_msg *pw_msg) 722e5cabeb3SAlexandre Bounine { 723e5cabeb3SAlexandre Bounine struct rio_dev *rdev; 724dd5648c9SAlexandre Bounine u32 err_status, em_perrdet, em_ltlerrdet; 725e5cabeb3SAlexandre Bounine int rc, portnum; 726e5cabeb3SAlexandre Bounine 727e6536927SAlexandre Bounine rdev = rio_get_comptag((pw_msg->em.comptag & RIO_CTAG_UDEVID), NULL); 728e5cabeb3SAlexandre Bounine if (rdev == NULL) { 7296429cd49SAlexandre Bounine /* Device removed or enumeration error */ 7306429cd49SAlexandre Bounine pr_debug("RIO: %s No matching device for CTag 0x%08x\n", 731e5cabeb3SAlexandre Bounine __func__, pw_msg->em.comptag); 732e5cabeb3SAlexandre Bounine return -EIO; 733e5cabeb3SAlexandre Bounine } 734e5cabeb3SAlexandre Bounine 735e5cabeb3SAlexandre Bounine pr_debug("RIO: Port-Write message from %s\n", rio_name(rdev)); 736e5cabeb3SAlexandre Bounine 737e5cabeb3SAlexandre Bounine #ifdef DEBUG_PW 738e5cabeb3SAlexandre Bounine { 739e5cabeb3SAlexandre Bounine u32 i; 740e5cabeb3SAlexandre Bounine for (i = 0; i < RIO_PW_MSG_SIZE/sizeof(u32);) { 741dd5648c9SAlexandre Bounine pr_debug("0x%02x: %08x %08x %08x %08x\n", 742e5cabeb3SAlexandre Bounine i*4, pw_msg->raw[i], pw_msg->raw[i + 1], 743e5cabeb3SAlexandre Bounine pw_msg->raw[i + 2], pw_msg->raw[i + 3]); 744e5cabeb3SAlexandre Bounine i += 4; 745e5cabeb3SAlexandre Bounine } 746e5cabeb3SAlexandre Bounine } 747e5cabeb3SAlexandre Bounine #endif 748e5cabeb3SAlexandre Bounine 749e5cabeb3SAlexandre Bounine /* Call an external service function (if such is registered 750e5cabeb3SAlexandre Bounine * for this device). This may be the service for endpoints that send 751e5cabeb3SAlexandre Bounine * device-specific port-write messages. End-point messages expected 752e5cabeb3SAlexandre Bounine * to be handled completely by EP specific device driver. 753e5cabeb3SAlexandre Bounine * For switches rc==0 signals that no standard processing required. 754e5cabeb3SAlexandre Bounine */ 755e5cabeb3SAlexandre Bounine if (rdev->pwcback != NULL) { 756e5cabeb3SAlexandre Bounine rc = rdev->pwcback(rdev, pw_msg, 0); 757e5cabeb3SAlexandre Bounine if (rc == 0) 758e5cabeb3SAlexandre Bounine return 0; 759e5cabeb3SAlexandre Bounine } 760e5cabeb3SAlexandre Bounine 7616429cd49SAlexandre Bounine portnum = pw_msg->em.is_port & 0xFF; 7626429cd49SAlexandre Bounine 7636429cd49SAlexandre Bounine /* Check if device and route to it are functional: 7646429cd49SAlexandre Bounine * Sometimes devices may send PW message(s) just before being 7656429cd49SAlexandre Bounine * powered down (or link being lost). 7666429cd49SAlexandre Bounine */ 7676429cd49SAlexandre Bounine if (rio_chk_dev_access(rdev)) { 7686429cd49SAlexandre Bounine pr_debug("RIO: device access failed - get link partner\n"); 7696429cd49SAlexandre Bounine /* Scan route to the device and identify failed link. 7706429cd49SAlexandre Bounine * This will replace device and port reported in PW message. 7716429cd49SAlexandre Bounine * PW message should not be used after this point. 7726429cd49SAlexandre Bounine */ 7736429cd49SAlexandre Bounine if (rio_chk_dev_route(rdev, &rdev, &portnum)) { 7746429cd49SAlexandre Bounine pr_err("RIO: Route trace for %s failed\n", 7756429cd49SAlexandre Bounine rio_name(rdev)); 7766429cd49SAlexandre Bounine return -EIO; 7776429cd49SAlexandre Bounine } 7786429cd49SAlexandre Bounine pw_msg = NULL; 7796429cd49SAlexandre Bounine } 7806429cd49SAlexandre Bounine 781e5cabeb3SAlexandre Bounine /* For End-point devices processing stops here */ 782e5cabeb3SAlexandre Bounine if (!(rdev->pef & RIO_PEF_SWITCH)) 783e5cabeb3SAlexandre Bounine return 0; 784e5cabeb3SAlexandre Bounine 785e5cabeb3SAlexandre Bounine if (rdev->phys_efptr == 0) { 786e5cabeb3SAlexandre Bounine pr_err("RIO_PW: Bad switch initialization for %s\n", 787e5cabeb3SAlexandre Bounine rio_name(rdev)); 788e5cabeb3SAlexandre Bounine return 0; 789e5cabeb3SAlexandre Bounine } 790e5cabeb3SAlexandre Bounine 791e5cabeb3SAlexandre Bounine /* 792e5cabeb3SAlexandre Bounine * Process the port-write notification from switch 793e5cabeb3SAlexandre Bounine */ 794e5cabeb3SAlexandre Bounine if (rdev->rswitch->em_handle) 795e5cabeb3SAlexandre Bounine rdev->rswitch->em_handle(rdev, portnum); 796e5cabeb3SAlexandre Bounine 797a93192a5SAlexandre Bounine rio_read_config_32(rdev, 798e5cabeb3SAlexandre Bounine rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(portnum), 799e5cabeb3SAlexandre Bounine &err_status); 800e5cabeb3SAlexandre Bounine pr_debug("RIO_PW: SP%d_ERR_STS_CSR=0x%08x\n", portnum, err_status); 801e5cabeb3SAlexandre Bounine 802dd5648c9SAlexandre Bounine if (err_status & RIO_PORT_N_ERR_STS_PORT_OK) { 803dd5648c9SAlexandre Bounine 804dd5648c9SAlexandre Bounine if (!(rdev->rswitch->port_ok & (1 << portnum))) { 805dd5648c9SAlexandre Bounine rdev->rswitch->port_ok |= (1 << portnum); 806dd5648c9SAlexandre Bounine rio_set_port_lockout(rdev, portnum, 0); 807dd5648c9SAlexandre Bounine /* Schedule Insertion Service */ 808dd5648c9SAlexandre Bounine pr_debug("RIO_PW: Device Insertion on [%s]-P%d\n", 809dd5648c9SAlexandre Bounine rio_name(rdev), portnum); 810e5cabeb3SAlexandre Bounine } 811e5cabeb3SAlexandre Bounine 812dd5648c9SAlexandre Bounine /* Clear error-stopped states (if reported). 813dd5648c9SAlexandre Bounine * Depending on the link partner state, two attempts 814dd5648c9SAlexandre Bounine * may be needed for successful recovery. 815dd5648c9SAlexandre Bounine */ 816dd5648c9SAlexandre Bounine if (err_status & (RIO_PORT_N_ERR_STS_PW_OUT_ES | 817dd5648c9SAlexandre Bounine RIO_PORT_N_ERR_STS_PW_INP_ES)) { 818dd5648c9SAlexandre Bounine if (rio_clr_err_stopped(rdev, portnum, err_status)) 819dd5648c9SAlexandre Bounine rio_clr_err_stopped(rdev, portnum, 0); 820e5cabeb3SAlexandre Bounine } 821dd5648c9SAlexandre Bounine } else { /* if (err_status & RIO_PORT_N_ERR_STS_PORT_UNINIT) */ 822e5cabeb3SAlexandre Bounine 823e5cabeb3SAlexandre Bounine if (rdev->rswitch->port_ok & (1 << portnum)) { 824e5cabeb3SAlexandre Bounine rdev->rswitch->port_ok &= ~(1 << portnum); 825e5cabeb3SAlexandre Bounine rio_set_port_lockout(rdev, portnum, 1); 826e5cabeb3SAlexandre Bounine 827a93192a5SAlexandre Bounine rio_write_config_32(rdev, 828e5cabeb3SAlexandre Bounine rdev->phys_efptr + 829e5cabeb3SAlexandre Bounine RIO_PORT_N_ACK_STS_CSR(portnum), 830e5cabeb3SAlexandre Bounine RIO_PORT_N_ACK_CLEAR); 831e5cabeb3SAlexandre Bounine 832e5cabeb3SAlexandre Bounine /* Schedule Extraction Service */ 833e5cabeb3SAlexandre Bounine pr_debug("RIO_PW: Device Extraction on [%s]-P%d\n", 834e5cabeb3SAlexandre Bounine rio_name(rdev), portnum); 835e5cabeb3SAlexandre Bounine } 836dd5648c9SAlexandre Bounine } 837e5cabeb3SAlexandre Bounine 838a93192a5SAlexandre Bounine rio_read_config_32(rdev, 839dd5648c9SAlexandre Bounine rdev->em_efptr + RIO_EM_PN_ERR_DETECT(portnum), &em_perrdet); 840dd5648c9SAlexandre Bounine if (em_perrdet) { 841dd5648c9SAlexandre Bounine pr_debug("RIO_PW: RIO_EM_P%d_ERR_DETECT=0x%08x\n", 842dd5648c9SAlexandre Bounine portnum, em_perrdet); 843dd5648c9SAlexandre Bounine /* Clear EM Port N Error Detect CSR */ 844a93192a5SAlexandre Bounine rio_write_config_32(rdev, 845dd5648c9SAlexandre Bounine rdev->em_efptr + RIO_EM_PN_ERR_DETECT(portnum), 0); 846e5cabeb3SAlexandre Bounine } 847dd5648c9SAlexandre Bounine 848a93192a5SAlexandre Bounine rio_read_config_32(rdev, 849dd5648c9SAlexandre Bounine rdev->em_efptr + RIO_EM_LTL_ERR_DETECT, &em_ltlerrdet); 850dd5648c9SAlexandre Bounine if (em_ltlerrdet) { 851dd5648c9SAlexandre Bounine pr_debug("RIO_PW: RIO_EM_LTL_ERR_DETECT=0x%08x\n", 852dd5648c9SAlexandre Bounine em_ltlerrdet); 853dd5648c9SAlexandre Bounine /* Clear EM L/T Layer Error Detect CSR */ 854a93192a5SAlexandre Bounine rio_write_config_32(rdev, 855dd5648c9SAlexandre Bounine rdev->em_efptr + RIO_EM_LTL_ERR_DETECT, 0); 856e5cabeb3SAlexandre Bounine } 857e5cabeb3SAlexandre Bounine 858388c45ccSAlexandre Bounine /* Clear remaining error bits and Port-Write Pending bit */ 859a93192a5SAlexandre Bounine rio_write_config_32(rdev, 860dd5648c9SAlexandre Bounine rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(portnum), 861388c45ccSAlexandre Bounine err_status); 862e5cabeb3SAlexandre Bounine 863e5cabeb3SAlexandre Bounine return 0; 864e5cabeb3SAlexandre Bounine } 865e5cabeb3SAlexandre Bounine EXPORT_SYMBOL_GPL(rio_inb_pwrite_handler); 866e5cabeb3SAlexandre Bounine 867e5cabeb3SAlexandre Bounine /** 868e5cabeb3SAlexandre Bounine * rio_mport_get_efb - get pointer to next extended features block 869e5cabeb3SAlexandre Bounine * @port: Master port to issue transaction 870e5cabeb3SAlexandre Bounine * @local: Indicate a local master port or remote device access 871e5cabeb3SAlexandre Bounine * @destid: Destination ID of the device 872e5cabeb3SAlexandre Bounine * @hopcount: Number of switch hops to the device 873e5cabeb3SAlexandre Bounine * @from: Offset of current Extended Feature block header (if 0 starts 874e5cabeb3SAlexandre Bounine * from ExtFeaturePtr) 875e5cabeb3SAlexandre Bounine */ 876e5cabeb3SAlexandre Bounine u32 877e5cabeb3SAlexandre Bounine rio_mport_get_efb(struct rio_mport *port, int local, u16 destid, 878e5cabeb3SAlexandre Bounine u8 hopcount, u32 from) 879e5cabeb3SAlexandre Bounine { 880e5cabeb3SAlexandre Bounine u32 reg_val; 881e5cabeb3SAlexandre Bounine 882e5cabeb3SAlexandre Bounine if (from == 0) { 883e5cabeb3SAlexandre Bounine if (local) 884e5cabeb3SAlexandre Bounine rio_local_read_config_32(port, RIO_ASM_INFO_CAR, 885e5cabeb3SAlexandre Bounine ®_val); 886e5cabeb3SAlexandre Bounine else 887e5cabeb3SAlexandre Bounine rio_mport_read_config_32(port, destid, hopcount, 888e5cabeb3SAlexandre Bounine RIO_ASM_INFO_CAR, ®_val); 889e5cabeb3SAlexandre Bounine return reg_val & RIO_EXT_FTR_PTR_MASK; 890e5cabeb3SAlexandre Bounine } else { 891e5cabeb3SAlexandre Bounine if (local) 892e5cabeb3SAlexandre Bounine rio_local_read_config_32(port, from, ®_val); 893e5cabeb3SAlexandre Bounine else 894e5cabeb3SAlexandre Bounine rio_mport_read_config_32(port, destid, hopcount, 895e5cabeb3SAlexandre Bounine from, ®_val); 896e5cabeb3SAlexandre Bounine return RIO_GET_BLOCK_ID(reg_val); 897e5cabeb3SAlexandre Bounine } 898e5cabeb3SAlexandre Bounine } 899e5cabeb3SAlexandre Bounine 900e5cabeb3SAlexandre Bounine /** 901394b701cSMatt Porter * rio_mport_get_feature - query for devices' extended features 902394b701cSMatt Porter * @port: Master port to issue transaction 903394b701cSMatt Porter * @local: Indicate a local master port or remote device access 904394b701cSMatt Porter * @destid: Destination ID of the device 905394b701cSMatt Porter * @hopcount: Number of switch hops to the device 906394b701cSMatt Porter * @ftr: Extended feature code 907394b701cSMatt Porter * 908394b701cSMatt Porter * Tell if a device supports a given RapidIO capability. 909394b701cSMatt Porter * Returns the offset of the requested extended feature 910394b701cSMatt Porter * block within the device's RIO configuration space or 911394b701cSMatt Porter * 0 in case the device does not support it. Possible 912394b701cSMatt Porter * values for @ftr: 913394b701cSMatt Porter * 914394b701cSMatt Porter * %RIO_EFB_PAR_EP_ID LP/LVDS EP Devices 915394b701cSMatt Porter * 916394b701cSMatt Porter * %RIO_EFB_PAR_EP_REC_ID LP/LVDS EP Recovery Devices 917394b701cSMatt Porter * 918394b701cSMatt Porter * %RIO_EFB_PAR_EP_FREE_ID LP/LVDS EP Free Devices 919394b701cSMatt Porter * 920394b701cSMatt Porter * %RIO_EFB_SER_EP_ID LP/Serial EP Devices 921394b701cSMatt Porter * 922394b701cSMatt Porter * %RIO_EFB_SER_EP_REC_ID LP/Serial EP Recovery Devices 923394b701cSMatt Porter * 924394b701cSMatt Porter * %RIO_EFB_SER_EP_FREE_ID LP/Serial EP Free Devices 925394b701cSMatt Porter */ 926394b701cSMatt Porter u32 927394b701cSMatt Porter rio_mport_get_feature(struct rio_mport * port, int local, u16 destid, 928394b701cSMatt Porter u8 hopcount, int ftr) 929394b701cSMatt Porter { 930394b701cSMatt Porter u32 asm_info, ext_ftr_ptr, ftr_header; 931394b701cSMatt Porter 932394b701cSMatt Porter if (local) 933394b701cSMatt Porter rio_local_read_config_32(port, RIO_ASM_INFO_CAR, &asm_info); 934394b701cSMatt Porter else 935394b701cSMatt Porter rio_mport_read_config_32(port, destid, hopcount, 936394b701cSMatt Porter RIO_ASM_INFO_CAR, &asm_info); 937394b701cSMatt Porter 938394b701cSMatt Porter ext_ftr_ptr = asm_info & RIO_EXT_FTR_PTR_MASK; 939394b701cSMatt Porter 940394b701cSMatt Porter while (ext_ftr_ptr) { 941394b701cSMatt Porter if (local) 942394b701cSMatt Porter rio_local_read_config_32(port, ext_ftr_ptr, 943394b701cSMatt Porter &ftr_header); 944394b701cSMatt Porter else 945394b701cSMatt Porter rio_mport_read_config_32(port, destid, hopcount, 946394b701cSMatt Porter ext_ftr_ptr, &ftr_header); 947394b701cSMatt Porter if (RIO_GET_BLOCK_ID(ftr_header) == ftr) 948394b701cSMatt Porter return ext_ftr_ptr; 949394b701cSMatt Porter if (!(ext_ftr_ptr = RIO_GET_BLOCK_PTR(ftr_header))) 950394b701cSMatt Porter break; 951394b701cSMatt Porter } 952394b701cSMatt Porter 953394b701cSMatt Porter return 0; 954394b701cSMatt Porter } 955394b701cSMatt Porter 956394b701cSMatt Porter /** 957394b701cSMatt Porter * rio_get_asm - Begin or continue searching for a RIO device by vid/did/asm_vid/asm_did 958394b701cSMatt Porter * @vid: RIO vid to match or %RIO_ANY_ID to match all vids 959394b701cSMatt Porter * @did: RIO did to match or %RIO_ANY_ID to match all dids 960394b701cSMatt Porter * @asm_vid: RIO asm_vid to match or %RIO_ANY_ID to match all asm_vids 961394b701cSMatt Porter * @asm_did: RIO asm_did to match or %RIO_ANY_ID to match all asm_dids 962394b701cSMatt Porter * @from: Previous RIO device found in search, or %NULL for new search 963394b701cSMatt Porter * 964394b701cSMatt Porter * Iterates through the list of known RIO devices. If a RIO device is 965394b701cSMatt Porter * found with a matching @vid, @did, @asm_vid, @asm_did, the reference 966394b701cSMatt Porter * count to the device is incrememted and a pointer to its device 967394b701cSMatt Porter * structure is returned. Otherwise, %NULL is returned. A new search 968394b701cSMatt Porter * is initiated by passing %NULL to the @from argument. Otherwise, if 969394b701cSMatt Porter * @from is not %NULL, searches continue from next device on the global 970394b701cSMatt Porter * list. The reference count for @from is always decremented if it is 971394b701cSMatt Porter * not %NULL. 972394b701cSMatt Porter */ 973394b701cSMatt Porter struct rio_dev *rio_get_asm(u16 vid, u16 did, 974394b701cSMatt Porter u16 asm_vid, u16 asm_did, struct rio_dev *from) 975394b701cSMatt Porter { 976394b701cSMatt Porter struct list_head *n; 977394b701cSMatt Porter struct rio_dev *rdev; 978394b701cSMatt Porter 979394b701cSMatt Porter WARN_ON(in_interrupt()); 980394b701cSMatt Porter spin_lock(&rio_global_list_lock); 981394b701cSMatt Porter n = from ? from->global_list.next : rio_devices.next; 982394b701cSMatt Porter 983394b701cSMatt Porter while (n && (n != &rio_devices)) { 984394b701cSMatt Porter rdev = rio_dev_g(n); 985394b701cSMatt Porter if ((vid == RIO_ANY_ID || rdev->vid == vid) && 986394b701cSMatt Porter (did == RIO_ANY_ID || rdev->did == did) && 987394b701cSMatt Porter (asm_vid == RIO_ANY_ID || rdev->asm_vid == asm_vid) && 988394b701cSMatt Porter (asm_did == RIO_ANY_ID || rdev->asm_did == asm_did)) 989394b701cSMatt Porter goto exit; 990394b701cSMatt Porter n = n->next; 991394b701cSMatt Porter } 992394b701cSMatt Porter rdev = NULL; 993394b701cSMatt Porter exit: 994394b701cSMatt Porter rio_dev_put(from); 995394b701cSMatt Porter rdev = rio_dev_get(rdev); 996394b701cSMatt Porter spin_unlock(&rio_global_list_lock); 997394b701cSMatt Porter return rdev; 998394b701cSMatt Porter } 999394b701cSMatt Porter 1000394b701cSMatt Porter /** 1001394b701cSMatt Porter * rio_get_device - Begin or continue searching for a RIO device by vid/did 1002394b701cSMatt Porter * @vid: RIO vid to match or %RIO_ANY_ID to match all vids 1003394b701cSMatt Porter * @did: RIO did to match or %RIO_ANY_ID to match all dids 1004394b701cSMatt Porter * @from: Previous RIO device found in search, or %NULL for new search 1005394b701cSMatt Porter * 1006394b701cSMatt Porter * Iterates through the list of known RIO devices. If a RIO device is 1007394b701cSMatt Porter * found with a matching @vid and @did, the reference count to the 1008394b701cSMatt Porter * device is incrememted and a pointer to its device structure is returned. 1009394b701cSMatt Porter * Otherwise, %NULL is returned. A new search is initiated by passing %NULL 1010394b701cSMatt Porter * to the @from argument. Otherwise, if @from is not %NULL, searches 1011394b701cSMatt Porter * continue from next device on the global list. The reference count for 1012394b701cSMatt Porter * @from is always decremented if it is not %NULL. 1013394b701cSMatt Porter */ 1014394b701cSMatt Porter struct rio_dev *rio_get_device(u16 vid, u16 did, struct rio_dev *from) 1015394b701cSMatt Porter { 1016394b701cSMatt Porter return rio_get_asm(vid, did, RIO_ANY_ID, RIO_ANY_ID, from); 1017394b701cSMatt Porter } 1018394b701cSMatt Porter 101907590ff0SAlexandre Bounine /** 102007590ff0SAlexandre Bounine * rio_std_route_add_entry - Add switch route table entry using standard 102107590ff0SAlexandre Bounine * registers defined in RIO specification rev.1.3 102207590ff0SAlexandre Bounine * @mport: Master port to issue transaction 102307590ff0SAlexandre Bounine * @destid: Destination ID of the device 102407590ff0SAlexandre Bounine * @hopcount: Number of switch hops to the device 102507590ff0SAlexandre Bounine * @table: routing table ID (global or port-specific) 102607590ff0SAlexandre Bounine * @route_destid: destID entry in the RT 102707590ff0SAlexandre Bounine * @route_port: destination port for specified destID 102807590ff0SAlexandre Bounine */ 102907590ff0SAlexandre Bounine int rio_std_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount, 103007590ff0SAlexandre Bounine u16 table, u16 route_destid, u8 route_port) 103107590ff0SAlexandre Bounine { 103207590ff0SAlexandre Bounine if (table == RIO_GLOBAL_TABLE) { 103307590ff0SAlexandre Bounine rio_mport_write_config_32(mport, destid, hopcount, 103407590ff0SAlexandre Bounine RIO_STD_RTE_CONF_DESTID_SEL_CSR, 103507590ff0SAlexandre Bounine (u32)route_destid); 103607590ff0SAlexandre Bounine rio_mport_write_config_32(mport, destid, hopcount, 103707590ff0SAlexandre Bounine RIO_STD_RTE_CONF_PORT_SEL_CSR, 103807590ff0SAlexandre Bounine (u32)route_port); 103907590ff0SAlexandre Bounine } 1040e5cabeb3SAlexandre Bounine 104107590ff0SAlexandre Bounine udelay(10); 104207590ff0SAlexandre Bounine return 0; 104307590ff0SAlexandre Bounine } 104407590ff0SAlexandre Bounine 104507590ff0SAlexandre Bounine /** 104607590ff0SAlexandre Bounine * rio_std_route_get_entry - Read switch route table entry (port number) 1047638c5945SUwe Kleine-König * associated with specified destID using standard registers defined in RIO 104807590ff0SAlexandre Bounine * specification rev.1.3 104907590ff0SAlexandre Bounine * @mport: Master port to issue transaction 105007590ff0SAlexandre Bounine * @destid: Destination ID of the device 105107590ff0SAlexandre Bounine * @hopcount: Number of switch hops to the device 105207590ff0SAlexandre Bounine * @table: routing table ID (global or port-specific) 105307590ff0SAlexandre Bounine * @route_destid: destID entry in the RT 105407590ff0SAlexandre Bounine * @route_port: returned destination port for specified destID 105507590ff0SAlexandre Bounine */ 105607590ff0SAlexandre Bounine int rio_std_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount, 105707590ff0SAlexandre Bounine u16 table, u16 route_destid, u8 *route_port) 105807590ff0SAlexandre Bounine { 105907590ff0SAlexandre Bounine u32 result; 106007590ff0SAlexandre Bounine 106107590ff0SAlexandre Bounine if (table == RIO_GLOBAL_TABLE) { 106207590ff0SAlexandre Bounine rio_mport_write_config_32(mport, destid, hopcount, 106307590ff0SAlexandre Bounine RIO_STD_RTE_CONF_DESTID_SEL_CSR, route_destid); 106407590ff0SAlexandre Bounine rio_mport_read_config_32(mport, destid, hopcount, 106507590ff0SAlexandre Bounine RIO_STD_RTE_CONF_PORT_SEL_CSR, &result); 106607590ff0SAlexandre Bounine 106707590ff0SAlexandre Bounine *route_port = (u8)result; 106807590ff0SAlexandre Bounine } 106907590ff0SAlexandre Bounine 107007590ff0SAlexandre Bounine return 0; 107107590ff0SAlexandre Bounine } 107207590ff0SAlexandre Bounine 107307590ff0SAlexandre Bounine /** 107407590ff0SAlexandre Bounine * rio_std_route_clr_table - Clear swotch route table using standard registers 107507590ff0SAlexandre Bounine * defined in RIO specification rev.1.3. 107607590ff0SAlexandre Bounine * @mport: Master port to issue transaction 107707590ff0SAlexandre Bounine * @destid: Destination ID of the device 107807590ff0SAlexandre Bounine * @hopcount: Number of switch hops to the device 107907590ff0SAlexandre Bounine * @table: routing table ID (global or port-specific) 108007590ff0SAlexandre Bounine */ 108107590ff0SAlexandre Bounine int rio_std_route_clr_table(struct rio_mport *mport, u16 destid, u8 hopcount, 108207590ff0SAlexandre Bounine u16 table) 108307590ff0SAlexandre Bounine { 108407590ff0SAlexandre Bounine u32 max_destid = 0xff; 108507590ff0SAlexandre Bounine u32 i, pef, id_inc = 1, ext_cfg = 0; 108607590ff0SAlexandre Bounine u32 port_sel = RIO_INVALID_ROUTE; 108707590ff0SAlexandre Bounine 108807590ff0SAlexandre Bounine if (table == RIO_GLOBAL_TABLE) { 108907590ff0SAlexandre Bounine rio_mport_read_config_32(mport, destid, hopcount, 109007590ff0SAlexandre Bounine RIO_PEF_CAR, &pef); 109107590ff0SAlexandre Bounine 109207590ff0SAlexandre Bounine if (mport->sys_size) { 109307590ff0SAlexandre Bounine rio_mport_read_config_32(mport, destid, hopcount, 109407590ff0SAlexandre Bounine RIO_SWITCH_RT_LIMIT, 109507590ff0SAlexandre Bounine &max_destid); 109607590ff0SAlexandre Bounine max_destid &= RIO_RT_MAX_DESTID; 109707590ff0SAlexandre Bounine } 109807590ff0SAlexandre Bounine 109907590ff0SAlexandre Bounine if (pef & RIO_PEF_EXT_RT) { 110007590ff0SAlexandre Bounine ext_cfg = 0x80000000; 110107590ff0SAlexandre Bounine id_inc = 4; 110207590ff0SAlexandre Bounine port_sel = (RIO_INVALID_ROUTE << 24) | 110307590ff0SAlexandre Bounine (RIO_INVALID_ROUTE << 16) | 110407590ff0SAlexandre Bounine (RIO_INVALID_ROUTE << 8) | 110507590ff0SAlexandre Bounine RIO_INVALID_ROUTE; 110607590ff0SAlexandre Bounine } 110707590ff0SAlexandre Bounine 110807590ff0SAlexandre Bounine for (i = 0; i <= max_destid;) { 110907590ff0SAlexandre Bounine rio_mport_write_config_32(mport, destid, hopcount, 111007590ff0SAlexandre Bounine RIO_STD_RTE_CONF_DESTID_SEL_CSR, 111107590ff0SAlexandre Bounine ext_cfg | i); 111207590ff0SAlexandre Bounine rio_mport_write_config_32(mport, destid, hopcount, 111307590ff0SAlexandre Bounine RIO_STD_RTE_CONF_PORT_SEL_CSR, 111407590ff0SAlexandre Bounine port_sel); 111507590ff0SAlexandre Bounine i += id_inc; 111607590ff0SAlexandre Bounine } 111707590ff0SAlexandre Bounine } 111807590ff0SAlexandre Bounine 111907590ff0SAlexandre Bounine udelay(10); 112007590ff0SAlexandre Bounine return 0; 112107590ff0SAlexandre Bounine } 112207590ff0SAlexandre Bounine 1123394b701cSMatt Porter static void rio_fixup_device(struct rio_dev *dev) 1124394b701cSMatt Porter { 1125394b701cSMatt Porter } 1126394b701cSMatt Porter 1127394b701cSMatt Porter static int __devinit rio_init(void) 1128394b701cSMatt Porter { 1129394b701cSMatt Porter struct rio_dev *dev = NULL; 1130394b701cSMatt Porter 1131394b701cSMatt Porter while ((dev = rio_get_device(RIO_ANY_ID, RIO_ANY_ID, dev)) != NULL) { 1132394b701cSMatt Porter rio_fixup_device(dev); 1133394b701cSMatt Porter } 1134394b701cSMatt Porter return 0; 1135394b701cSMatt Porter } 1136394b701cSMatt Porter 113737d33d15SAl Viro int __devinit rio_init_mports(void) 1138394b701cSMatt Porter { 1139394b701cSMatt Porter int rc = 0; 1140394b701cSMatt Porter struct rio_mport *port; 1141394b701cSMatt Porter 1142394b701cSMatt Porter list_for_each_entry(port, &rio_mports, node) { 1143394b701cSMatt Porter if (!request_mem_region(port->iores.start, 114488cf81fcSDan Carpenter resource_size(&port->iores), 1145394b701cSMatt Porter port->name)) { 1146394b701cSMatt Porter printk(KERN_ERR 11475febf1cdSKumar Gala "RIO: Error requesting master port region 0x%016llx-0x%016llx\n", 114888cf81fcSDan Carpenter (u64)port->iores.start, (u64)port->iores.end); 1149394b701cSMatt Porter rc = -ENOMEM; 1150394b701cSMatt Porter goto out; 1151394b701cSMatt Porter } 1152394b701cSMatt Porter 1153394b701cSMatt Porter if (port->host_deviceid >= 0) 1154394b701cSMatt Porter rio_enum_mport(port); 1155394b701cSMatt Porter else 1156394b701cSMatt Porter rio_disc_mport(port); 1157394b701cSMatt Porter } 1158394b701cSMatt Porter 11592f809985SAlexandre Bounine rio_init(); 11602f809985SAlexandre Bounine 1161394b701cSMatt Porter out: 1162394b701cSMatt Porter return rc; 1163394b701cSMatt Porter } 1164394b701cSMatt Porter 11652f809985SAlexandre Bounine device_initcall_sync(rio_init_mports); 11662f809985SAlexandre Bounine 1167394b701cSMatt Porter void rio_register_mport(struct rio_mport *port) 1168394b701cSMatt Porter { 1169394b701cSMatt Porter list_add_tail(&port->node, &rio_mports); 1170394b701cSMatt Porter } 1171394b701cSMatt Porter 1172394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_local_get_device_id); 1173394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_get_device); 1174394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_get_asm); 1175394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_request_inb_dbell); 1176394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_release_inb_dbell); 1177394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_request_outb_dbell); 1178394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_release_outb_dbell); 1179394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_request_inb_mbox); 1180394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_release_inb_mbox); 1181394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_request_outb_mbox); 1182394b701cSMatt Porter EXPORT_SYMBOL_GPL(rio_release_outb_mbox); 1183