1 /* 2 * RapidIO interconnect services 3 * (RapidIO Interconnect Specification, http://www.rapidio.org) 4 * 5 * Copyright 2005 MontaVista Software, Inc. 6 * Matt Porter <mporter@kernel.crashing.org> 7 * 8 * This program is free software; you can redistribute it and/or modify it 9 * under the terms of the GNU General Public License as published by the 10 * Free Software Foundation; either version 2 of the License, or (at your 11 * option) any later version. 12 */ 13 14 #include <linux/types.h> 15 #include <linux/kernel.h> 16 17 #include <linux/delay.h> 18 #include <linux/init.h> 19 #include <linux/rio.h> 20 #include <linux/rio_drv.h> 21 #include <linux/rio_ids.h> 22 #include <linux/rio_regs.h> 23 #include <linux/module.h> 24 #include <linux/spinlock.h> 25 #include <linux/slab.h> 26 27 #include "rio.h" 28 29 static LIST_HEAD(rio_mports); 30 31 /** 32 * rio_local_get_device_id - Get the base/extended device id for a port 33 * @port: RIO master port from which to get the deviceid 34 * 35 * Reads the base/extended device id from the local device 36 * implementing the master port. Returns the 8/16-bit device 37 * id. 38 */ 39 u16 rio_local_get_device_id(struct rio_mport *port) 40 { 41 u32 result; 42 43 rio_local_read_config_32(port, RIO_DID_CSR, &result); 44 45 return (RIO_GET_DID(result)); 46 } 47 48 /** 49 * rio_request_inb_mbox - request inbound mailbox service 50 * @mport: RIO master port from which to allocate the mailbox resource 51 * @dev_id: Device specific pointer to pass on event 52 * @mbox: Mailbox number to claim 53 * @entries: Number of entries in inbound mailbox queue 54 * @minb: Callback to execute when inbound message is received 55 * 56 * Requests ownership of an inbound mailbox resource and binds 57 * a callback function to the resource. Returns %0 on success. 58 */ 59 int rio_request_inb_mbox(struct rio_mport *mport, 60 void *dev_id, 61 int mbox, 62 int entries, 63 void (*minb) (struct rio_mport * mport, void *dev_id, int mbox, 64 int slot)) 65 { 66 int rc = 0; 67 68 struct resource *res = kmalloc(sizeof(struct resource), GFP_KERNEL); 69 70 if (res) { 71 rio_init_mbox_res(res, mbox, mbox); 72 73 /* Make sure this mailbox isn't in use */ 74 if ((rc = 75 request_resource(&mport->riores[RIO_INB_MBOX_RESOURCE], 76 res)) < 0) { 77 kfree(res); 78 goto out; 79 } 80 81 mport->inb_msg[mbox].res = res; 82 83 /* Hook the inbound message callback */ 84 mport->inb_msg[mbox].mcback = minb; 85 86 rc = rio_open_inb_mbox(mport, dev_id, mbox, entries); 87 } else 88 rc = -ENOMEM; 89 90 out: 91 return rc; 92 } 93 94 /** 95 * rio_release_inb_mbox - release inbound mailbox message service 96 * @mport: RIO master port from which to release the mailbox resource 97 * @mbox: Mailbox number to release 98 * 99 * Releases ownership of an inbound mailbox resource. Returns 0 100 * if the request has been satisfied. 101 */ 102 int rio_release_inb_mbox(struct rio_mport *mport, int mbox) 103 { 104 rio_close_inb_mbox(mport, mbox); 105 106 /* Release the mailbox resource */ 107 return release_resource(mport->inb_msg[mbox].res); 108 } 109 110 /** 111 * rio_request_outb_mbox - request outbound mailbox service 112 * @mport: RIO master port from which to allocate the mailbox resource 113 * @dev_id: Device specific pointer to pass on event 114 * @mbox: Mailbox number to claim 115 * @entries: Number of entries in outbound mailbox queue 116 * @moutb: Callback to execute when outbound message is sent 117 * 118 * Requests ownership of an outbound mailbox resource and binds 119 * a callback function to the resource. Returns 0 on success. 120 */ 121 int rio_request_outb_mbox(struct rio_mport *mport, 122 void *dev_id, 123 int mbox, 124 int entries, 125 void (*moutb) (struct rio_mport * mport, void *dev_id, int mbox, int slot)) 126 { 127 int rc = 0; 128 129 struct resource *res = kmalloc(sizeof(struct resource), GFP_KERNEL); 130 131 if (res) { 132 rio_init_mbox_res(res, mbox, mbox); 133 134 /* Make sure this outbound mailbox isn't in use */ 135 if ((rc = 136 request_resource(&mport->riores[RIO_OUTB_MBOX_RESOURCE], 137 res)) < 0) { 138 kfree(res); 139 goto out; 140 } 141 142 mport->outb_msg[mbox].res = res; 143 144 /* Hook the inbound message callback */ 145 mport->outb_msg[mbox].mcback = moutb; 146 147 rc = rio_open_outb_mbox(mport, dev_id, mbox, entries); 148 } else 149 rc = -ENOMEM; 150 151 out: 152 return rc; 153 } 154 155 /** 156 * rio_release_outb_mbox - release outbound mailbox message service 157 * @mport: RIO master port from which to release the mailbox resource 158 * @mbox: Mailbox number to release 159 * 160 * Releases ownership of an inbound mailbox resource. Returns 0 161 * if the request has been satisfied. 162 */ 163 int rio_release_outb_mbox(struct rio_mport *mport, int mbox) 164 { 165 rio_close_outb_mbox(mport, mbox); 166 167 /* Release the mailbox resource */ 168 return release_resource(mport->outb_msg[mbox].res); 169 } 170 171 /** 172 * rio_setup_inb_dbell - bind inbound doorbell callback 173 * @mport: RIO master port to bind the doorbell callback 174 * @dev_id: Device specific pointer to pass on event 175 * @res: Doorbell message resource 176 * @dinb: Callback to execute when doorbell is received 177 * 178 * Adds a doorbell resource/callback pair into a port's 179 * doorbell event list. Returns 0 if the request has been 180 * satisfied. 181 */ 182 static int 183 rio_setup_inb_dbell(struct rio_mport *mport, void *dev_id, struct resource *res, 184 void (*dinb) (struct rio_mport * mport, void *dev_id, u16 src, u16 dst, 185 u16 info)) 186 { 187 int rc = 0; 188 struct rio_dbell *dbell; 189 190 if (!(dbell = kmalloc(sizeof(struct rio_dbell), GFP_KERNEL))) { 191 rc = -ENOMEM; 192 goto out; 193 } 194 195 dbell->res = res; 196 dbell->dinb = dinb; 197 dbell->dev_id = dev_id; 198 199 list_add_tail(&dbell->node, &mport->dbells); 200 201 out: 202 return rc; 203 } 204 205 /** 206 * rio_request_inb_dbell - request inbound doorbell message service 207 * @mport: RIO master port from which to allocate the doorbell resource 208 * @dev_id: Device specific pointer to pass on event 209 * @start: Doorbell info range start 210 * @end: Doorbell info range end 211 * @dinb: Callback to execute when doorbell is received 212 * 213 * Requests ownership of an inbound doorbell resource and binds 214 * a callback function to the resource. Returns 0 if the request 215 * has been satisfied. 216 */ 217 int rio_request_inb_dbell(struct rio_mport *mport, 218 void *dev_id, 219 u16 start, 220 u16 end, 221 void (*dinb) (struct rio_mport * mport, void *dev_id, u16 src, 222 u16 dst, u16 info)) 223 { 224 int rc = 0; 225 226 struct resource *res = kmalloc(sizeof(struct resource), GFP_KERNEL); 227 228 if (res) { 229 rio_init_dbell_res(res, start, end); 230 231 /* Make sure these doorbells aren't in use */ 232 if ((rc = 233 request_resource(&mport->riores[RIO_DOORBELL_RESOURCE], 234 res)) < 0) { 235 kfree(res); 236 goto out; 237 } 238 239 /* Hook the doorbell callback */ 240 rc = rio_setup_inb_dbell(mport, dev_id, res, dinb); 241 } else 242 rc = -ENOMEM; 243 244 out: 245 return rc; 246 } 247 248 /** 249 * rio_release_inb_dbell - release inbound doorbell message service 250 * @mport: RIO master port from which to release the doorbell resource 251 * @start: Doorbell info range start 252 * @end: Doorbell info range end 253 * 254 * Releases ownership of an inbound doorbell resource and removes 255 * callback from the doorbell event list. Returns 0 if the request 256 * has been satisfied. 257 */ 258 int rio_release_inb_dbell(struct rio_mport *mport, u16 start, u16 end) 259 { 260 int rc = 0, found = 0; 261 struct rio_dbell *dbell; 262 263 list_for_each_entry(dbell, &mport->dbells, node) { 264 if ((dbell->res->start == start) && (dbell->res->end == end)) { 265 found = 1; 266 break; 267 } 268 } 269 270 /* If we can't find an exact match, fail */ 271 if (!found) { 272 rc = -EINVAL; 273 goto out; 274 } 275 276 /* Delete from list */ 277 list_del(&dbell->node); 278 279 /* Release the doorbell resource */ 280 rc = release_resource(dbell->res); 281 282 /* Free the doorbell event */ 283 kfree(dbell); 284 285 out: 286 return rc; 287 } 288 289 /** 290 * rio_request_outb_dbell - request outbound doorbell message range 291 * @rdev: RIO device from which to allocate the doorbell resource 292 * @start: Doorbell message range start 293 * @end: Doorbell message range end 294 * 295 * Requests ownership of a doorbell message range. Returns a resource 296 * if the request has been satisfied or %NULL on failure. 297 */ 298 struct resource *rio_request_outb_dbell(struct rio_dev *rdev, u16 start, 299 u16 end) 300 { 301 struct resource *res = kmalloc(sizeof(struct resource), GFP_KERNEL); 302 303 if (res) { 304 rio_init_dbell_res(res, start, end); 305 306 /* Make sure these doorbells aren't in use */ 307 if (request_resource(&rdev->riores[RIO_DOORBELL_RESOURCE], res) 308 < 0) { 309 kfree(res); 310 res = NULL; 311 } 312 } 313 314 return res; 315 } 316 317 /** 318 * rio_release_outb_dbell - release outbound doorbell message range 319 * @rdev: RIO device from which to release the doorbell resource 320 * @res: Doorbell resource to be freed 321 * 322 * Releases ownership of a doorbell message range. Returns 0 if the 323 * request has been satisfied. 324 */ 325 int rio_release_outb_dbell(struct rio_dev *rdev, struct resource *res) 326 { 327 int rc = release_resource(res); 328 329 kfree(res); 330 331 return rc; 332 } 333 334 /** 335 * rio_mport_get_feature - query for devices' extended features 336 * @port: Master port to issue transaction 337 * @local: Indicate a local master port or remote device access 338 * @destid: Destination ID of the device 339 * @hopcount: Number of switch hops to the device 340 * @ftr: Extended feature code 341 * 342 * Tell if a device supports a given RapidIO capability. 343 * Returns the offset of the requested extended feature 344 * block within the device's RIO configuration space or 345 * 0 in case the device does not support it. Possible 346 * values for @ftr: 347 * 348 * %RIO_EFB_PAR_EP_ID LP/LVDS EP Devices 349 * 350 * %RIO_EFB_PAR_EP_REC_ID LP/LVDS EP Recovery Devices 351 * 352 * %RIO_EFB_PAR_EP_FREE_ID LP/LVDS EP Free Devices 353 * 354 * %RIO_EFB_SER_EP_ID LP/Serial EP Devices 355 * 356 * %RIO_EFB_SER_EP_REC_ID LP/Serial EP Recovery Devices 357 * 358 * %RIO_EFB_SER_EP_FREE_ID LP/Serial EP Free Devices 359 */ 360 u32 361 rio_mport_get_feature(struct rio_mport * port, int local, u16 destid, 362 u8 hopcount, int ftr) 363 { 364 u32 asm_info, ext_ftr_ptr, ftr_header; 365 366 if (local) 367 rio_local_read_config_32(port, RIO_ASM_INFO_CAR, &asm_info); 368 else 369 rio_mport_read_config_32(port, destid, hopcount, 370 RIO_ASM_INFO_CAR, &asm_info); 371 372 ext_ftr_ptr = asm_info & RIO_EXT_FTR_PTR_MASK; 373 374 while (ext_ftr_ptr) { 375 if (local) 376 rio_local_read_config_32(port, ext_ftr_ptr, 377 &ftr_header); 378 else 379 rio_mport_read_config_32(port, destid, hopcount, 380 ext_ftr_ptr, &ftr_header); 381 if (RIO_GET_BLOCK_ID(ftr_header) == ftr) 382 return ext_ftr_ptr; 383 if (!(ext_ftr_ptr = RIO_GET_BLOCK_PTR(ftr_header))) 384 break; 385 } 386 387 return 0; 388 } 389 390 /** 391 * rio_get_asm - Begin or continue searching for a RIO device by vid/did/asm_vid/asm_did 392 * @vid: RIO vid to match or %RIO_ANY_ID to match all vids 393 * @did: RIO did to match or %RIO_ANY_ID to match all dids 394 * @asm_vid: RIO asm_vid to match or %RIO_ANY_ID to match all asm_vids 395 * @asm_did: RIO asm_did to match or %RIO_ANY_ID to match all asm_dids 396 * @from: Previous RIO device found in search, or %NULL for new search 397 * 398 * Iterates through the list of known RIO devices. If a RIO device is 399 * found with a matching @vid, @did, @asm_vid, @asm_did, the reference 400 * count to the device is incrememted and a pointer to its device 401 * structure is returned. Otherwise, %NULL is returned. A new search 402 * is initiated by passing %NULL to the @from argument. Otherwise, if 403 * @from is not %NULL, searches continue from next device on the global 404 * list. The reference count for @from is always decremented if it is 405 * not %NULL. 406 */ 407 struct rio_dev *rio_get_asm(u16 vid, u16 did, 408 u16 asm_vid, u16 asm_did, struct rio_dev *from) 409 { 410 struct list_head *n; 411 struct rio_dev *rdev; 412 413 WARN_ON(in_interrupt()); 414 spin_lock(&rio_global_list_lock); 415 n = from ? from->global_list.next : rio_devices.next; 416 417 while (n && (n != &rio_devices)) { 418 rdev = rio_dev_g(n); 419 if ((vid == RIO_ANY_ID || rdev->vid == vid) && 420 (did == RIO_ANY_ID || rdev->did == did) && 421 (asm_vid == RIO_ANY_ID || rdev->asm_vid == asm_vid) && 422 (asm_did == RIO_ANY_ID || rdev->asm_did == asm_did)) 423 goto exit; 424 n = n->next; 425 } 426 rdev = NULL; 427 exit: 428 rio_dev_put(from); 429 rdev = rio_dev_get(rdev); 430 spin_unlock(&rio_global_list_lock); 431 return rdev; 432 } 433 434 /** 435 * rio_get_device - Begin or continue searching for a RIO device by vid/did 436 * @vid: RIO vid to match or %RIO_ANY_ID to match all vids 437 * @did: RIO did to match or %RIO_ANY_ID to match all dids 438 * @from: Previous RIO device found in search, or %NULL for new search 439 * 440 * Iterates through the list of known RIO devices. If a RIO device is 441 * found with a matching @vid and @did, the reference count to the 442 * device is incrememted and a pointer to its device structure is returned. 443 * Otherwise, %NULL is returned. A new search is initiated by passing %NULL 444 * to the @from argument. Otherwise, if @from is not %NULL, searches 445 * continue from next device on the global list. The reference count for 446 * @from is always decremented if it is not %NULL. 447 */ 448 struct rio_dev *rio_get_device(u16 vid, u16 did, struct rio_dev *from) 449 { 450 return rio_get_asm(vid, did, RIO_ANY_ID, RIO_ANY_ID, from); 451 } 452 453 static void rio_fixup_device(struct rio_dev *dev) 454 { 455 } 456 457 static int __devinit rio_init(void) 458 { 459 struct rio_dev *dev = NULL; 460 461 while ((dev = rio_get_device(RIO_ANY_ID, RIO_ANY_ID, dev)) != NULL) { 462 rio_fixup_device(dev); 463 } 464 return 0; 465 } 466 467 device_initcall(rio_init); 468 469 int rio_init_mports(void) 470 { 471 int rc = 0; 472 struct rio_mport *port; 473 474 list_for_each_entry(port, &rio_mports, node) { 475 if (!request_mem_region(port->iores.start, 476 port->iores.end - port->iores.start, 477 port->name)) { 478 printk(KERN_ERR 479 "RIO: Error requesting master port region %8.8lx-%8.8lx\n", 480 port->iores.start, port->iores.end - 1); 481 rc = -ENOMEM; 482 goto out; 483 } 484 485 if (port->host_deviceid >= 0) 486 rio_enum_mport(port); 487 else 488 rio_disc_mport(port); 489 } 490 491 out: 492 return rc; 493 } 494 495 void rio_register_mport(struct rio_mport *port) 496 { 497 list_add_tail(&port->node, &rio_mports); 498 } 499 500 EXPORT_SYMBOL_GPL(rio_local_get_device_id); 501 EXPORT_SYMBOL_GPL(rio_get_device); 502 EXPORT_SYMBOL_GPL(rio_get_asm); 503 EXPORT_SYMBOL_GPL(rio_request_inb_dbell); 504 EXPORT_SYMBOL_GPL(rio_release_inb_dbell); 505 EXPORT_SYMBOL_GPL(rio_request_outb_dbell); 506 EXPORT_SYMBOL_GPL(rio_release_outb_dbell); 507 EXPORT_SYMBOL_GPL(rio_request_inb_mbox); 508 EXPORT_SYMBOL_GPL(rio_release_inb_mbox); 509 EXPORT_SYMBOL_GPL(rio_request_outb_mbox); 510 EXPORT_SYMBOL_GPL(rio_release_outb_mbox); 511