diff options
Diffstat (limited to 'drivers/rapidio/rio-scan.c')
-rw-r--r-- | drivers/rapidio/rio-scan.c | 424 |
1 files changed, 356 insertions, 68 deletions
diff --git a/drivers/rapidio/rio-scan.c b/drivers/rapidio/rio-scan.c index 45415096c294..8070e074c739 100644 --- a/drivers/rapidio/rio-scan.c +++ b/drivers/rapidio/rio-scan.c | |||
@@ -4,6 +4,14 @@ | |||
4 | * Copyright 2005 MontaVista Software, Inc. | 4 | * Copyright 2005 MontaVista Software, Inc. |
5 | * Matt Porter <mporter@kernel.crashing.org> | 5 | * Matt Porter <mporter@kernel.crashing.org> |
6 | * | 6 | * |
7 | * Copyright 2009 Integrated Device Technology, Inc. | ||
8 | * Alex Bounine <alexandre.bounine@idt.com> | ||
9 | * - Added Port-Write/Error Management initialization and handling | ||
10 | * | ||
11 | * Copyright 2009 Sysgo AG | ||
12 | * Thomas Moll <thomas.moll@sysgo.com> | ||
13 | * - Added Input- Output- enable functionality, to allow full communication | ||
14 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | 15 | * This program is free software; you can redistribute it and/or modify it |
8 | * under the terms of the GNU General Public License as published by the | 16 | * under the terms of the GNU General Public License as published by the |
9 | * Free Software Foundation; either version 2 of the License, or (at your | 17 | * Free Software Foundation; either version 2 of the License, or (at your |
@@ -31,15 +39,16 @@ | |||
31 | LIST_HEAD(rio_devices); | 39 | LIST_HEAD(rio_devices); |
32 | static LIST_HEAD(rio_switches); | 40 | static LIST_HEAD(rio_switches); |
33 | 41 | ||
34 | #define RIO_ENUM_CMPL_MAGIC 0xdeadbeef | ||
35 | |||
36 | static void rio_enum_timeout(unsigned long); | 42 | static void rio_enum_timeout(unsigned long); |
37 | 43 | ||
44 | static void rio_init_em(struct rio_dev *rdev); | ||
45 | |||
38 | DEFINE_SPINLOCK(rio_global_list_lock); | 46 | DEFINE_SPINLOCK(rio_global_list_lock); |
39 | 47 | ||
40 | static int next_destid = 0; | 48 | static int next_destid = 0; |
41 | static int next_switchid = 0; | 49 | static int next_switchid = 0; |
42 | static int next_net = 0; | 50 | static int next_net = 0; |
51 | static int next_comptag; | ||
43 | 52 | ||
44 | static struct timer_list rio_enum_timer = | 53 | static struct timer_list rio_enum_timer = |
45 | TIMER_INITIALIZER(rio_enum_timeout, 0, 0); | 54 | TIMER_INITIALIZER(rio_enum_timeout, 0, 0); |
@@ -52,12 +61,6 @@ static int rio_mport_phys_table[] = { | |||
52 | -1, | 61 | -1, |
53 | }; | 62 | }; |
54 | 63 | ||
55 | static int rio_sport_phys_table[] = { | ||
56 | RIO_EFB_PAR_EP_FREE_ID, | ||
57 | RIO_EFB_SER_EP_FREE_ID, | ||
58 | -1, | ||
59 | }; | ||
60 | |||
61 | /** | 64 | /** |
62 | * rio_get_device_id - Get the base/extended device id for a device | 65 | * rio_get_device_id - Get the base/extended device id for a device |
63 | * @port: RIO master port | 66 | * @port: RIO master port |
@@ -118,12 +121,26 @@ static int rio_clear_locks(struct rio_mport *port) | |||
118 | u32 result; | 121 | u32 result; |
119 | int ret = 0; | 122 | int ret = 0; |
120 | 123 | ||
121 | /* Write component tag CSR magic complete value */ | 124 | /* Assign component tag to all devices */ |
122 | rio_local_write_config_32(port, RIO_COMPONENT_TAG_CSR, | 125 | next_comptag = 1; |
123 | RIO_ENUM_CMPL_MAGIC); | 126 | rio_local_write_config_32(port, RIO_COMPONENT_TAG_CSR, next_comptag++); |
124 | list_for_each_entry(rdev, &rio_devices, global_list) | 127 | |
125 | rio_write_config_32(rdev, RIO_COMPONENT_TAG_CSR, | 128 | list_for_each_entry(rdev, &rio_devices, global_list) { |
126 | RIO_ENUM_CMPL_MAGIC); | 129 | /* Mark device as discovered */ |
130 | rio_read_config_32(rdev, | ||
131 | rdev->phys_efptr + RIO_PORT_GEN_CTL_CSR, | ||
132 | &result); | ||
133 | rio_write_config_32(rdev, | ||
134 | rdev->phys_efptr + RIO_PORT_GEN_CTL_CSR, | ||
135 | result | RIO_PORT_GEN_DISCOVERED); | ||
136 | |||
137 | rio_write_config_32(rdev, RIO_COMPONENT_TAG_CSR, next_comptag); | ||
138 | rdev->comp_tag = next_comptag++; | ||
139 | if (next_comptag >= 0x10000) { | ||
140 | pr_err("RIO: Component Tag Counter Overflow\n"); | ||
141 | break; | ||
142 | } | ||
143 | } | ||
127 | 144 | ||
128 | /* Release host device id locks */ | 145 | /* Release host device id locks */ |
129 | rio_local_write_config_32(port, RIO_HOST_DID_LOCK_CSR, | 146 | rio_local_write_config_32(port, RIO_HOST_DID_LOCK_CSR, |
@@ -229,27 +246,37 @@ static int rio_is_switch(struct rio_dev *rdev) | |||
229 | } | 246 | } |
230 | 247 | ||
231 | /** | 248 | /** |
232 | * rio_route_set_ops- Sets routing operations for a particular vendor switch | 249 | * rio_switch_init - Sets switch operations for a particular vendor switch |
233 | * @rdev: RIO device | 250 | * @rdev: RIO device |
251 | * @do_enum: Enumeration/Discovery mode flag | ||
234 | * | 252 | * |
235 | * Searches the RIO route ops table for known switch types. If the vid | 253 | * Searches the RIO switch ops table for known switch types. If the vid |
236 | * and did match a switch table entry, then set the add_entry() and | 254 | * and did match a switch table entry, then call switch initialization |
237 | * get_entry() ops to the table entry values. | 255 | * routine to setup switch-specific routines. |
238 | */ | 256 | */ |
239 | static void rio_route_set_ops(struct rio_dev *rdev) | 257 | static void rio_switch_init(struct rio_dev *rdev, int do_enum) |
240 | { | 258 | { |
241 | struct rio_route_ops *cur = __start_rio_route_ops; | 259 | struct rio_switch_ops *cur = __start_rio_switch_ops; |
242 | struct rio_route_ops *end = __end_rio_route_ops; | 260 | struct rio_switch_ops *end = __end_rio_switch_ops; |
243 | 261 | ||
244 | while (cur < end) { | 262 | while (cur < end) { |
245 | if ((cur->vid == rdev->vid) && (cur->did == rdev->did)) { | 263 | if ((cur->vid == rdev->vid) && (cur->did == rdev->did)) { |
246 | pr_debug("RIO: adding routing ops for %s\n", rio_name(rdev)); | 264 | pr_debug("RIO: calling init routine for %s\n", |
247 | rdev->rswitch->add_entry = cur->add_hook; | 265 | rio_name(rdev)); |
248 | rdev->rswitch->get_entry = cur->get_hook; | 266 | cur->init_hook(rdev, do_enum); |
267 | break; | ||
249 | } | 268 | } |
250 | cur++; | 269 | cur++; |
251 | } | 270 | } |
252 | 271 | ||
272 | if ((cur >= end) && (rdev->pef & RIO_PEF_STD_RT)) { | ||
273 | pr_debug("RIO: adding STD routing ops for %s\n", | ||
274 | rio_name(rdev)); | ||
275 | rdev->rswitch->add_entry = rio_std_route_add_entry; | ||
276 | rdev->rswitch->get_entry = rio_std_route_get_entry; | ||
277 | rdev->rswitch->clr_table = rio_std_route_clr_table; | ||
278 | } | ||
279 | |||
253 | if (!rdev->rswitch->add_entry || !rdev->rswitch->get_entry) | 280 | if (!rdev->rswitch->add_entry || !rdev->rswitch->get_entry) |
254 | printk(KERN_ERR "RIO: missing routing ops for %s\n", | 281 | printk(KERN_ERR "RIO: missing routing ops for %s\n", |
255 | rio_name(rdev)); | 282 | rio_name(rdev)); |
@@ -281,6 +308,65 @@ static int __devinit rio_add_device(struct rio_dev *rdev) | |||
281 | } | 308 | } |
282 | 309 | ||
283 | /** | 310 | /** |
311 | * rio_enable_rx_tx_port - enable input reciever and output transmitter of | ||
312 | * given port | ||
313 | * @port: Master port associated with the RIO network | ||
314 | * @local: local=1 select local port otherwise a far device is reached | ||
315 | * @destid: Destination ID of the device to check host bit | ||
316 | * @hopcount: Number of hops to reach the target | ||
317 | * @port_num: Port (-number on switch) to enable on a far end device | ||
318 | * | ||
319 | * Returns 0 or 1 from on General Control Command and Status Register | ||
320 | * (EXT_PTR+0x3C) | ||
321 | */ | ||
322 | inline int rio_enable_rx_tx_port(struct rio_mport *port, | ||
323 | int local, u16 destid, | ||
324 | u8 hopcount, u8 port_num) { | ||
325 | #ifdef CONFIG_RAPIDIO_ENABLE_RX_TX_PORTS | ||
326 | u32 regval; | ||
327 | u32 ext_ftr_ptr; | ||
328 | |||
329 | /* | ||
330 | * enable rx input tx output port | ||
331 | */ | ||
332 | pr_debug("rio_enable_rx_tx_port(local = %d, destid = %d, hopcount = " | ||
333 | "%d, port_num = %d)\n", local, destid, hopcount, port_num); | ||
334 | |||
335 | ext_ftr_ptr = rio_mport_get_physefb(port, local, destid, hopcount); | ||
336 | |||
337 | if (local) { | ||
338 | rio_local_read_config_32(port, ext_ftr_ptr + | ||
339 | RIO_PORT_N_CTL_CSR(0), | ||
340 | ®val); | ||
341 | } else { | ||
342 | if (rio_mport_read_config_32(port, destid, hopcount, | ||
343 | ext_ftr_ptr + RIO_PORT_N_CTL_CSR(port_num), ®val) < 0) | ||
344 | return -EIO; | ||
345 | } | ||
346 | |||
347 | if (regval & RIO_PORT_N_CTL_P_TYP_SER) { | ||
348 | /* serial */ | ||
349 | regval = regval | RIO_PORT_N_CTL_EN_RX_SER | ||
350 | | RIO_PORT_N_CTL_EN_TX_SER; | ||
351 | } else { | ||
352 | /* parallel */ | ||
353 | regval = regval | RIO_PORT_N_CTL_EN_RX_PAR | ||
354 | | RIO_PORT_N_CTL_EN_TX_PAR; | ||
355 | } | ||
356 | |||
357 | if (local) { | ||
358 | rio_local_write_config_32(port, ext_ftr_ptr + | ||
359 | RIO_PORT_N_CTL_CSR(0), regval); | ||
360 | } else { | ||
361 | if (rio_mport_write_config_32(port, destid, hopcount, | ||
362 | ext_ftr_ptr + RIO_PORT_N_CTL_CSR(port_num), regval) < 0) | ||
363 | return -EIO; | ||
364 | } | ||
365 | #endif | ||
366 | return 0; | ||
367 | } | ||
368 | |||
369 | /** | ||
284 | * rio_setup_device- Allocates and sets up a RIO device | 370 | * rio_setup_device- Allocates and sets up a RIO device |
285 | * @net: RIO network | 371 | * @net: RIO network |
286 | * @port: Master port to send transactions | 372 | * @port: Master port to send transactions |
@@ -325,8 +411,14 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net, | |||
325 | rdev->asm_rev = result >> 16; | 411 | rdev->asm_rev = result >> 16; |
326 | rio_mport_read_config_32(port, destid, hopcount, RIO_PEF_CAR, | 412 | rio_mport_read_config_32(port, destid, hopcount, RIO_PEF_CAR, |
327 | &rdev->pef); | 413 | &rdev->pef); |
328 | if (rdev->pef & RIO_PEF_EXT_FEATURES) | 414 | if (rdev->pef & RIO_PEF_EXT_FEATURES) { |
329 | rdev->efptr = result & 0xffff; | 415 | rdev->efptr = result & 0xffff; |
416 | rdev->phys_efptr = rio_mport_get_physefb(port, 0, destid, | ||
417 | hopcount); | ||
418 | |||
419 | rdev->em_efptr = rio_mport_get_feature(port, 0, destid, | ||
420 | hopcount, RIO_EFB_ERR_MGMNT); | ||
421 | } | ||
330 | 422 | ||
331 | rio_mport_read_config_32(port, destid, hopcount, RIO_SRC_OPS_CAR, | 423 | rio_mport_read_config_32(port, destid, hopcount, RIO_SRC_OPS_CAR, |
332 | &rdev->src_ops); | 424 | &rdev->src_ops); |
@@ -349,12 +441,13 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net, | |||
349 | if (rio_is_switch(rdev)) { | 441 | if (rio_is_switch(rdev)) { |
350 | rio_mport_read_config_32(port, destid, hopcount, | 442 | rio_mport_read_config_32(port, destid, hopcount, |
351 | RIO_SWP_INFO_CAR, &rdev->swpinfo); | 443 | RIO_SWP_INFO_CAR, &rdev->swpinfo); |
352 | rswitch = kmalloc(sizeof(struct rio_switch), GFP_KERNEL); | 444 | rswitch = kzalloc(sizeof(struct rio_switch), GFP_KERNEL); |
353 | if (!rswitch) | 445 | if (!rswitch) |
354 | goto cleanup; | 446 | goto cleanup; |
355 | rswitch->switchid = next_switchid; | 447 | rswitch->switchid = next_switchid; |
356 | rswitch->hopcount = hopcount; | 448 | rswitch->hopcount = hopcount; |
357 | rswitch->destid = destid; | 449 | rswitch->destid = destid; |
450 | rswitch->port_ok = 0; | ||
358 | rswitch->route_table = kzalloc(sizeof(u8)* | 451 | rswitch->route_table = kzalloc(sizeof(u8)* |
359 | RIO_MAX_ROUTE_ENTRIES(port->sys_size), | 452 | RIO_MAX_ROUTE_ENTRIES(port->sys_size), |
360 | GFP_KERNEL); | 453 | GFP_KERNEL); |
@@ -367,13 +460,22 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net, | |||
367 | rdev->rswitch = rswitch; | 460 | rdev->rswitch = rswitch; |
368 | dev_set_name(&rdev->dev, "%02x:s:%04x", rdev->net->id, | 461 | dev_set_name(&rdev->dev, "%02x:s:%04x", rdev->net->id, |
369 | rdev->rswitch->switchid); | 462 | rdev->rswitch->switchid); |
370 | rio_route_set_ops(rdev); | 463 | rio_switch_init(rdev, do_enum); |
464 | |||
465 | if (do_enum && rdev->rswitch->clr_table) | ||
466 | rdev->rswitch->clr_table(port, destid, hopcount, | ||
467 | RIO_GLOBAL_TABLE); | ||
371 | 468 | ||
372 | list_add_tail(&rswitch->node, &rio_switches); | 469 | list_add_tail(&rswitch->node, &rio_switches); |
373 | 470 | ||
374 | } else | 471 | } else { |
472 | if (do_enum) | ||
473 | /*Enable Input Output Port (transmitter reviever)*/ | ||
474 | rio_enable_rx_tx_port(port, 0, destid, hopcount, 0); | ||
475 | |||
375 | dev_set_name(&rdev->dev, "%02x:e:%04x", rdev->net->id, | 476 | dev_set_name(&rdev->dev, "%02x:e:%04x", rdev->net->id, |
376 | rdev->destid); | 477 | rdev->destid); |
478 | } | ||
377 | 479 | ||
378 | rdev->dev.bus = &rio_bus_type; | 480 | rdev->dev.bus = &rio_bus_type; |
379 | 481 | ||
@@ -414,23 +516,29 @@ cleanup: | |||
414 | * | 516 | * |
415 | * Reads the port error status CSR for a particular switch port to | 517 | * Reads the port error status CSR for a particular switch port to |
416 | * determine if the port has an active link. Returns | 518 | * determine if the port has an active link. Returns |
417 | * %PORT_N_ERR_STS_PORT_OK if the port is active or %0 if it is | 519 | * %RIO_PORT_N_ERR_STS_PORT_OK if the port is active or %0 if it is |
418 | * inactive. | 520 | * inactive. |
419 | */ | 521 | */ |
420 | static int | 522 | static int |
421 | rio_sport_is_active(struct rio_mport *port, u16 destid, u8 hopcount, int sport) | 523 | rio_sport_is_active(struct rio_mport *port, u16 destid, u8 hopcount, int sport) |
422 | { | 524 | { |
423 | u32 result; | 525 | u32 result = 0; |
424 | u32 ext_ftr_ptr; | 526 | u32 ext_ftr_ptr; |
425 | 527 | ||
426 | int *entry = rio_sport_phys_table; | 528 | ext_ftr_ptr = rio_mport_get_efb(port, 0, destid, hopcount, 0); |
427 | |||
428 | do { | ||
429 | if ((ext_ftr_ptr = | ||
430 | rio_mport_get_feature(port, 0, destid, hopcount, *entry))) | ||
431 | 529 | ||
530 | while (ext_ftr_ptr) { | ||
531 | rio_mport_read_config_32(port, destid, hopcount, | ||
532 | ext_ftr_ptr, &result); | ||
533 | result = RIO_GET_BLOCK_ID(result); | ||
534 | if ((result == RIO_EFB_SER_EP_FREE_ID) || | ||
535 | (result == RIO_EFB_SER_EP_FREE_ID_V13P) || | ||
536 | (result == RIO_EFB_SER_EP_FREC_ID)) | ||
432 | break; | 537 | break; |
433 | } while (*++entry >= 0); | 538 | |
539 | ext_ftr_ptr = rio_mport_get_efb(port, 0, destid, hopcount, | ||
540 | ext_ftr_ptr); | ||
541 | } | ||
434 | 542 | ||
435 | if (ext_ftr_ptr) | 543 | if (ext_ftr_ptr) |
436 | rio_mport_read_config_32(port, destid, hopcount, | 544 | rio_mport_read_config_32(port, destid, hopcount, |
@@ -438,7 +546,81 @@ rio_sport_is_active(struct rio_mport *port, u16 destid, u8 hopcount, int sport) | |||
438 | RIO_PORT_N_ERR_STS_CSR(sport), | 546 | RIO_PORT_N_ERR_STS_CSR(sport), |
439 | &result); | 547 | &result); |
440 | 548 | ||
441 | return (result & PORT_N_ERR_STS_PORT_OK); | 549 | return result & RIO_PORT_N_ERR_STS_PORT_OK; |
550 | } | ||
551 | |||
552 | /** | ||
553 | * rio_lock_device - Acquires host device lock for specified device | ||
554 | * @port: Master port to send transaction | ||
555 | * @destid: Destination ID for device/switch | ||
556 | * @hopcount: Hopcount to reach switch | ||
557 | * @wait_ms: Max wait time in msec (0 = no timeout) | ||
558 | * | ||
559 | * Attepts to acquire host device lock for specified device | ||
560 | * Returns 0 if device lock acquired or EINVAL if timeout expires. | ||
561 | */ | ||
562 | static int | ||
563 | rio_lock_device(struct rio_mport *port, u16 destid, u8 hopcount, int wait_ms) | ||
564 | { | ||
565 | u32 result; | ||
566 | int tcnt = 0; | ||
567 | |||
568 | /* Attempt to acquire device lock */ | ||
569 | rio_mport_write_config_32(port, destid, hopcount, | ||
570 | RIO_HOST_DID_LOCK_CSR, port->host_deviceid); | ||
571 | rio_mport_read_config_32(port, destid, hopcount, | ||
572 | RIO_HOST_DID_LOCK_CSR, &result); | ||
573 | |||
574 | while (result != port->host_deviceid) { | ||
575 | if (wait_ms != 0 && tcnt == wait_ms) { | ||
576 | pr_debug("RIO: timeout when locking device %x:%x\n", | ||
577 | destid, hopcount); | ||
578 | return -EINVAL; | ||
579 | } | ||
580 | |||
581 | /* Delay a bit */ | ||
582 | mdelay(1); | ||
583 | tcnt++; | ||
584 | /* Try to acquire device lock again */ | ||
585 | rio_mport_write_config_32(port, destid, | ||
586 | hopcount, | ||
587 | RIO_HOST_DID_LOCK_CSR, | ||
588 | port->host_deviceid); | ||
589 | rio_mport_read_config_32(port, destid, | ||
590 | hopcount, | ||
591 | RIO_HOST_DID_LOCK_CSR, &result); | ||
592 | } | ||
593 | |||
594 | return 0; | ||
595 | } | ||
596 | |||
597 | /** | ||
598 | * rio_unlock_device - Releases host device lock for specified device | ||
599 | * @port: Master port to send transaction | ||
600 | * @destid: Destination ID for device/switch | ||
601 | * @hopcount: Hopcount to reach switch | ||
602 | * | ||
603 | * Returns 0 if device lock released or EINVAL if fails. | ||
604 | */ | ||
605 | static int | ||
606 | rio_unlock_device(struct rio_mport *port, u16 destid, u8 hopcount) | ||
607 | { | ||
608 | u32 result; | ||
609 | |||
610 | /* Release device lock */ | ||
611 | rio_mport_write_config_32(port, destid, | ||
612 | hopcount, | ||
613 | RIO_HOST_DID_LOCK_CSR, | ||
614 | port->host_deviceid); | ||
615 | rio_mport_read_config_32(port, destid, hopcount, | ||
616 | RIO_HOST_DID_LOCK_CSR, &result); | ||
617 | if ((result & 0xffff) != 0xffff) { | ||
618 | pr_debug("RIO: badness when releasing device lock %x:%x\n", | ||
619 | destid, hopcount); | ||
620 | return -EINVAL; | ||
621 | } | ||
622 | |||
623 | return 0; | ||
442 | } | 624 | } |
443 | 625 | ||
444 | /** | 626 | /** |
@@ -448,6 +630,7 @@ rio_sport_is_active(struct rio_mport *port, u16 destid, u8 hopcount, int sport) | |||
448 | * @table: Routing table ID | 630 | * @table: Routing table ID |
449 | * @route_destid: Destination ID to be routed | 631 | * @route_destid: Destination ID to be routed |
450 | * @route_port: Port number to be routed | 632 | * @route_port: Port number to be routed |
633 | * @lock: lock switch device flag | ||
451 | * | 634 | * |
452 | * Calls the switch specific add_entry() method to add a route entry | 635 | * Calls the switch specific add_entry() method to add a route entry |
453 | * on a switch. The route table can be specified using the @table | 636 | * on a switch. The route table can be specified using the @table |
@@ -456,12 +639,26 @@ rio_sport_is_active(struct rio_mport *port, u16 destid, u8 hopcount, int sport) | |||
456 | * %RIO_GLOBAL_TABLE in @table. Returns %0 on success or %-EINVAL | 639 | * %RIO_GLOBAL_TABLE in @table. Returns %0 on success or %-EINVAL |
457 | * on failure. | 640 | * on failure. |
458 | */ | 641 | */ |
459 | static int rio_route_add_entry(struct rio_mport *mport, struct rio_switch *rswitch, | 642 | static int |
460 | u16 table, u16 route_destid, u8 route_port) | 643 | rio_route_add_entry(struct rio_mport *mport, struct rio_switch *rswitch, |
644 | u16 table, u16 route_destid, u8 route_port, int lock) | ||
461 | { | 645 | { |
462 | return rswitch->add_entry(mport, rswitch->destid, | 646 | int rc; |
647 | |||
648 | if (lock) { | ||
649 | rc = rio_lock_device(mport, rswitch->destid, | ||
650 | rswitch->hopcount, 1000); | ||
651 | if (rc) | ||
652 | return rc; | ||
653 | } | ||
654 | |||
655 | rc = rswitch->add_entry(mport, rswitch->destid, | ||
463 | rswitch->hopcount, table, | 656 | rswitch->hopcount, table, |
464 | route_destid, route_port); | 657 | route_destid, route_port); |
658 | if (lock) | ||
659 | rio_unlock_device(mport, rswitch->destid, rswitch->hopcount); | ||
660 | |||
661 | return rc; | ||
465 | } | 662 | } |
466 | 663 | ||
467 | /** | 664 | /** |
@@ -471,6 +668,7 @@ static int rio_route_add_entry(struct rio_mport *mport, struct rio_switch *rswit | |||
471 | * @table: Routing table ID | 668 | * @table: Routing table ID |
472 | * @route_destid: Destination ID to be routed | 669 | * @route_destid: Destination ID to be routed |
473 | * @route_port: Pointer to read port number into | 670 | * @route_port: Pointer to read port number into |
671 | * @lock: lock switch device flag | ||
474 | * | 672 | * |
475 | * Calls the switch specific get_entry() method to read a route entry | 673 | * Calls the switch specific get_entry() method to read a route entry |
476 | * in a switch. The route table can be specified using the @table | 674 | * in a switch. The route table can be specified using the @table |
@@ -481,11 +679,24 @@ static int rio_route_add_entry(struct rio_mport *mport, struct rio_switch *rswit | |||
481 | */ | 679 | */ |
482 | static int | 680 | static int |
483 | rio_route_get_entry(struct rio_mport *mport, struct rio_switch *rswitch, u16 table, | 681 | rio_route_get_entry(struct rio_mport *mport, struct rio_switch *rswitch, u16 table, |
484 | u16 route_destid, u8 * route_port) | 682 | u16 route_destid, u8 *route_port, int lock) |
485 | { | 683 | { |
486 | return rswitch->get_entry(mport, rswitch->destid, | 684 | int rc; |
685 | |||
686 | if (lock) { | ||
687 | rc = rio_lock_device(mport, rswitch->destid, | ||
688 | rswitch->hopcount, 1000); | ||
689 | if (rc) | ||
690 | return rc; | ||
691 | } | ||
692 | |||
693 | rc = rswitch->get_entry(mport, rswitch->destid, | ||
487 | rswitch->hopcount, table, | 694 | rswitch->hopcount, table, |
488 | route_destid, route_port); | 695 | route_destid, route_port); |
696 | if (lock) | ||
697 | rio_unlock_device(mport, rswitch->destid, rswitch->hopcount); | ||
698 | |||
699 | return rc; | ||
489 | } | 700 | } |
490 | 701 | ||
491 | /** | 702 | /** |
@@ -625,14 +836,14 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port, | |||
625 | sw_inport = rio_get_swpinfo_inport(port, | 836 | sw_inport = rio_get_swpinfo_inport(port, |
626 | RIO_ANY_DESTID(port->sys_size), hopcount); | 837 | RIO_ANY_DESTID(port->sys_size), hopcount); |
627 | rio_route_add_entry(port, rdev->rswitch, RIO_GLOBAL_TABLE, | 838 | rio_route_add_entry(port, rdev->rswitch, RIO_GLOBAL_TABLE, |
628 | port->host_deviceid, sw_inport); | 839 | port->host_deviceid, sw_inport, 0); |
629 | rdev->rswitch->route_table[port->host_deviceid] = sw_inport; | 840 | rdev->rswitch->route_table[port->host_deviceid] = sw_inport; |
630 | 841 | ||
631 | for (destid = 0; destid < next_destid; destid++) { | 842 | for (destid = 0; destid < next_destid; destid++) { |
632 | if (destid == port->host_deviceid) | 843 | if (destid == port->host_deviceid) |
633 | continue; | 844 | continue; |
634 | rio_route_add_entry(port, rdev->rswitch, RIO_GLOBAL_TABLE, | 845 | rio_route_add_entry(port, rdev->rswitch, RIO_GLOBAL_TABLE, |
635 | destid, sw_inport); | 846 | destid, sw_inport, 0); |
636 | rdev->rswitch->route_table[destid] = sw_inport; | 847 | rdev->rswitch->route_table[destid] = sw_inport; |
637 | } | 848 | } |
638 | 849 | ||
@@ -644,8 +855,15 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port, | |||
644 | rio_name(rdev), rdev->vid, rdev->did, num_ports); | 855 | rio_name(rdev), rdev->vid, rdev->did, num_ports); |
645 | sw_destid = next_destid; | 856 | sw_destid = next_destid; |
646 | for (port_num = 0; port_num < num_ports; port_num++) { | 857 | for (port_num = 0; port_num < num_ports; port_num++) { |
647 | if (sw_inport == port_num) | 858 | /*Enable Input Output Port (transmitter reviever)*/ |
859 | rio_enable_rx_tx_port(port, 0, | ||
860 | RIO_ANY_DESTID(port->sys_size), | ||
861 | hopcount, port_num); | ||
862 | |||
863 | if (sw_inport == port_num) { | ||
864 | rdev->rswitch->port_ok |= (1 << port_num); | ||
648 | continue; | 865 | continue; |
866 | } | ||
649 | 867 | ||
650 | cur_destid = next_destid; | 868 | cur_destid = next_destid; |
651 | 869 | ||
@@ -655,10 +873,11 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port, | |||
655 | pr_debug( | 873 | pr_debug( |
656 | "RIO: scanning device on port %d\n", | 874 | "RIO: scanning device on port %d\n", |
657 | port_num); | 875 | port_num); |
876 | rdev->rswitch->port_ok |= (1 << port_num); | ||
658 | rio_route_add_entry(port, rdev->rswitch, | 877 | rio_route_add_entry(port, rdev->rswitch, |
659 | RIO_GLOBAL_TABLE, | 878 | RIO_GLOBAL_TABLE, |
660 | RIO_ANY_DESTID(port->sys_size), | 879 | RIO_ANY_DESTID(port->sys_size), |
661 | port_num); | 880 | port_num, 0); |
662 | 881 | ||
663 | if (rio_enum_peer(net, port, hopcount + 1) < 0) | 882 | if (rio_enum_peer(net, port, hopcount + 1) < 0) |
664 | return -1; | 883 | return -1; |
@@ -672,15 +891,35 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port, | |||
672 | rio_route_add_entry(port, rdev->rswitch, | 891 | rio_route_add_entry(port, rdev->rswitch, |
673 | RIO_GLOBAL_TABLE, | 892 | RIO_GLOBAL_TABLE, |
674 | destid, | 893 | destid, |
675 | port_num); | 894 | port_num, |
895 | 0); | ||
676 | rdev->rswitch-> | 896 | rdev->rswitch-> |
677 | route_table[destid] = | 897 | route_table[destid] = |
678 | port_num; | 898 | port_num; |
679 | } | 899 | } |
680 | } | 900 | } |
901 | } else { | ||
902 | /* If switch supports Error Management, | ||
903 | * set PORT_LOCKOUT bit for unused port | ||
904 | */ | ||
905 | if (rdev->em_efptr) | ||
906 | rio_set_port_lockout(rdev, port_num, 1); | ||
907 | |||
908 | rdev->rswitch->port_ok &= ~(1 << port_num); | ||
681 | } | 909 | } |
682 | } | 910 | } |
683 | 911 | ||
912 | /* Direct Port-write messages to the enumeratiing host */ | ||
913 | if ((rdev->src_ops & RIO_SRC_OPS_PORT_WRITE) && | ||
914 | (rdev->em_efptr)) { | ||
915 | rio_write_config_32(rdev, | ||
916 | rdev->em_efptr + RIO_EM_PW_TGT_DEVID, | ||
917 | (port->host_deviceid << 16) | | ||
918 | (port->sys_size << 15)); | ||
919 | } | ||
920 | |||
921 | rio_init_em(rdev); | ||
922 | |||
684 | /* Check for empty switch */ | 923 | /* Check for empty switch */ |
685 | if (next_destid == sw_destid) { | 924 | if (next_destid == sw_destid) { |
686 | next_destid++; | 925 | next_destid++; |
@@ -700,21 +939,16 @@ static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port, | |||
700 | * rio_enum_complete- Tests if enumeration of a network is complete | 939 | * rio_enum_complete- Tests if enumeration of a network is complete |
701 | * @port: Master port to send transaction | 940 | * @port: Master port to send transaction |
702 | * | 941 | * |
703 | * Tests the Component Tag CSR for presence of the magic enumeration | 942 | * Tests the Component Tag CSR for non-zero value (enumeration |
704 | * complete flag. Return %1 if enumeration is complete or %0 if | 943 | * complete flag). Return %1 if enumeration is complete or %0 if |
705 | * enumeration is incomplete. | 944 | * enumeration is incomplete. |
706 | */ | 945 | */ |
707 | static int rio_enum_complete(struct rio_mport *port) | 946 | static int rio_enum_complete(struct rio_mport *port) |
708 | { | 947 | { |
709 | u32 tag_csr; | 948 | u32 tag_csr; |
710 | int ret = 0; | ||
711 | 949 | ||
712 | rio_local_read_config_32(port, RIO_COMPONENT_TAG_CSR, &tag_csr); | 950 | rio_local_read_config_32(port, RIO_COMPONENT_TAG_CSR, &tag_csr); |
713 | 951 | return (tag_csr & 0xffff) ? 1 : 0; | |
714 | if (tag_csr == RIO_ENUM_CMPL_MAGIC) | ||
715 | ret = 1; | ||
716 | |||
717 | return ret; | ||
718 | } | 952 | } |
719 | 953 | ||
720 | /** | 954 | /** |
@@ -763,17 +997,21 @@ rio_disc_peer(struct rio_net *net, struct rio_mport *port, u16 destid, | |||
763 | pr_debug( | 997 | pr_debug( |
764 | "RIO: scanning device on port %d\n", | 998 | "RIO: scanning device on port %d\n", |
765 | port_num); | 999 | port_num); |
1000 | |||
1001 | rio_lock_device(port, destid, hopcount, 1000); | ||
1002 | |||
766 | for (ndestid = 0; | 1003 | for (ndestid = 0; |
767 | ndestid < RIO_ANY_DESTID(port->sys_size); | 1004 | ndestid < RIO_ANY_DESTID(port->sys_size); |
768 | ndestid++) { | 1005 | ndestid++) { |
769 | rio_route_get_entry(port, rdev->rswitch, | 1006 | rio_route_get_entry(port, rdev->rswitch, |
770 | RIO_GLOBAL_TABLE, | 1007 | RIO_GLOBAL_TABLE, |
771 | ndestid, | 1008 | ndestid, |
772 | &route_port); | 1009 | &route_port, 0); |
773 | if (route_port == port_num) | 1010 | if (route_port == port_num) |
774 | break; | 1011 | break; |
775 | } | 1012 | } |
776 | 1013 | ||
1014 | rio_unlock_device(port, destid, hopcount); | ||
777 | if (rio_disc_peer | 1015 | if (rio_disc_peer |
778 | (net, port, ndestid, hopcount + 1) < 0) | 1016 | (net, port, ndestid, hopcount + 1) < 0) |
779 | return -1; | 1017 | return -1; |
@@ -792,7 +1030,7 @@ rio_disc_peer(struct rio_net *net, struct rio_mport *port, u16 destid, | |||
792 | * | 1030 | * |
793 | * Reads the port error status CSR for the master port to | 1031 | * Reads the port error status CSR for the master port to |
794 | * determine if the port has an active link. Returns | 1032 | * determine if the port has an active link. Returns |
795 | * %PORT_N_ERR_STS_PORT_OK if the master port is active | 1033 | * %RIO_PORT_N_ERR_STS_PORT_OK if the master port is active |
796 | * or %0 if it is inactive. | 1034 | * or %0 if it is inactive. |
797 | */ | 1035 | */ |
798 | static int rio_mport_is_active(struct rio_mport *port) | 1036 | static int rio_mport_is_active(struct rio_mport *port) |
@@ -813,7 +1051,7 @@ static int rio_mport_is_active(struct rio_mport *port) | |||
813 | RIO_PORT_N_ERR_STS_CSR(port->index), | 1051 | RIO_PORT_N_ERR_STS_CSR(port->index), |
814 | &result); | 1052 | &result); |
815 | 1053 | ||
816 | return (result & PORT_N_ERR_STS_PORT_OK); | 1054 | return result & RIO_PORT_N_ERR_STS_PORT_OK; |
817 | } | 1055 | } |
818 | 1056 | ||
819 | /** | 1057 | /** |
@@ -866,12 +1104,17 @@ static void rio_update_route_tables(struct rio_mport *port) | |||
866 | continue; | 1104 | continue; |
867 | 1105 | ||
868 | if (RIO_INVALID_ROUTE == rswitch->route_table[destid]) { | 1106 | if (RIO_INVALID_ROUTE == rswitch->route_table[destid]) { |
1107 | /* Skip if destid ends in empty switch*/ | ||
1108 | if (rswitch->destid == destid) | ||
1109 | continue; | ||
869 | 1110 | ||
870 | sport = rio_get_swpinfo_inport(port, | 1111 | sport = rio_get_swpinfo_inport(port, |
871 | rswitch->destid, rswitch->hopcount); | 1112 | rswitch->destid, rswitch->hopcount); |
872 | 1113 | ||
873 | if (rswitch->add_entry) { | 1114 | if (rswitch->add_entry) { |
874 | rio_route_add_entry(port, rswitch, RIO_GLOBAL_TABLE, destid, sport); | 1115 | rio_route_add_entry(port, rswitch, |
1116 | RIO_GLOBAL_TABLE, destid, | ||
1117 | sport, 0); | ||
875 | rswitch->route_table[destid] = sport; | 1118 | rswitch->route_table[destid] = sport; |
876 | } | 1119 | } |
877 | } | 1120 | } |
@@ -880,6 +1123,32 @@ static void rio_update_route_tables(struct rio_mport *port) | |||
880 | } | 1123 | } |
881 | 1124 | ||
882 | /** | 1125 | /** |
1126 | * rio_init_em - Initializes RIO Error Management (for switches) | ||
1127 | * @rdev: RIO device | ||
1128 | * | ||
1129 | * For each enumerated switch, call device-specific error management | ||
1130 | * initialization routine (if supplied by the switch driver). | ||
1131 | */ | ||
1132 | static void rio_init_em(struct rio_dev *rdev) | ||
1133 | { | ||
1134 | if (rio_is_switch(rdev) && (rdev->em_efptr) && | ||
1135 | (rdev->rswitch->em_init)) { | ||
1136 | rdev->rswitch->em_init(rdev); | ||
1137 | } | ||
1138 | } | ||
1139 | |||
1140 | /** | ||
1141 | * rio_pw_enable - Enables/disables port-write handling by a master port | ||
1142 | * @port: Master port associated with port-write handling | ||
1143 | * @enable: 1=enable, 0=disable | ||
1144 | */ | ||
1145 | static void rio_pw_enable(struct rio_mport *port, int enable) | ||
1146 | { | ||
1147 | if (port->ops->pwenable) | ||
1148 | port->ops->pwenable(port, enable); | ||
1149 | } | ||
1150 | |||
1151 | /** | ||
883 | * rio_enum_mport- Start enumeration through a master port | 1152 | * rio_enum_mport- Start enumeration through a master port |
884 | * @mport: Master port to send transactions | 1153 | * @mport: Master port to send transactions |
885 | * | 1154 | * |
@@ -911,6 +1180,10 @@ int __devinit rio_enum_mport(struct rio_mport *mport) | |||
911 | rc = -ENOMEM; | 1180 | rc = -ENOMEM; |
912 | goto out; | 1181 | goto out; |
913 | } | 1182 | } |
1183 | |||
1184 | /* Enable Input Output Port (transmitter reviever) */ | ||
1185 | rio_enable_rx_tx_port(mport, 1, 0, 0, 0); | ||
1186 | |||
914 | if (rio_enum_peer(net, mport, 0) < 0) { | 1187 | if (rio_enum_peer(net, mport, 0) < 0) { |
915 | /* A higher priority host won enumeration, bail. */ | 1188 | /* A higher priority host won enumeration, bail. */ |
916 | printk(KERN_INFO | 1189 | printk(KERN_INFO |
@@ -922,6 +1195,7 @@ int __devinit rio_enum_mport(struct rio_mport *mport) | |||
922 | } | 1195 | } |
923 | rio_update_route_tables(mport); | 1196 | rio_update_route_tables(mport); |
924 | rio_clear_locks(mport); | 1197 | rio_clear_locks(mport); |
1198 | rio_pw_enable(mport, 1); | ||
925 | } else { | 1199 | } else { |
926 | printk(KERN_INFO "RIO: master port %d link inactive\n", | 1200 | printk(KERN_INFO "RIO: master port %d link inactive\n", |
927 | mport->id); | 1201 | mport->id); |
@@ -945,15 +1219,22 @@ static void rio_build_route_tables(void) | |||
945 | u8 sport; | 1219 | u8 sport; |
946 | 1220 | ||
947 | list_for_each_entry(rdev, &rio_devices, global_list) | 1221 | list_for_each_entry(rdev, &rio_devices, global_list) |
948 | if (rio_is_switch(rdev)) | 1222 | if (rio_is_switch(rdev)) { |
949 | for (i = 0; | 1223 | rio_lock_device(rdev->net->hport, rdev->rswitch->destid, |
950 | i < RIO_MAX_ROUTE_ENTRIES(rdev->net->hport->sys_size); | 1224 | rdev->rswitch->hopcount, 1000); |
951 | i++) { | 1225 | for (i = 0; |
952 | if (rio_route_get_entry | 1226 | i < RIO_MAX_ROUTE_ENTRIES(rdev->net->hport->sys_size); |
953 | (rdev->net->hport, rdev->rswitch, RIO_GLOBAL_TABLE, | 1227 | i++) { |
954 | i, &sport) < 0) | 1228 | if (rio_route_get_entry |
955 | continue; | 1229 | (rdev->net->hport, rdev->rswitch, |
956 | rdev->rswitch->route_table[i] = sport; | 1230 | RIO_GLOBAL_TABLE, i, &sport, 0) < 0) |
1231 | continue; | ||
1232 | rdev->rswitch->route_table[i] = sport; | ||
1233 | } | ||
1234 | |||
1235 | rio_unlock_device(rdev->net->hport, | ||
1236 | rdev->rswitch->destid, | ||
1237 | rdev->rswitch->hopcount); | ||
957 | } | 1238 | } |
958 | } | 1239 | } |
959 | 1240 | ||
@@ -1012,6 +1293,13 @@ int __devinit rio_disc_mport(struct rio_mport *mport) | |||
1012 | del_timer_sync(&rio_enum_timer); | 1293 | del_timer_sync(&rio_enum_timer); |
1013 | 1294 | ||
1014 | pr_debug("done\n"); | 1295 | pr_debug("done\n"); |
1296 | |||
1297 | /* Read DestID assigned by enumerator */ | ||
1298 | rio_local_read_config_32(mport, RIO_DID_CSR, | ||
1299 | &mport->host_deviceid); | ||
1300 | mport->host_deviceid = RIO_GET_DID(mport->sys_size, | ||
1301 | mport->host_deviceid); | ||
1302 | |||
1015 | if (rio_disc_peer(net, mport, RIO_ANY_DESTID(mport->sys_size), | 1303 | if (rio_disc_peer(net, mport, RIO_ANY_DESTID(mport->sys_size), |
1016 | 0) < 0) { | 1304 | 0) < 0) { |
1017 | printk(KERN_INFO | 1305 | printk(KERN_INFO |