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