diff options
Diffstat (limited to 'drivers/rapidio/rio-scan.c')
-rw-r--r-- | drivers/rapidio/rio-scan.c | 59 |
1 files changed, 32 insertions, 27 deletions
diff --git a/drivers/rapidio/rio-scan.c b/drivers/rapidio/rio-scan.c index 51f0af241eb7..45d14cd6b356 100644 --- a/drivers/rapidio/rio-scan.c +++ b/drivers/rapidio/rio-scan.c | |||
@@ -378,12 +378,30 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net, | |||
378 | struct rio_dev *rdev; | 378 | struct rio_dev *rdev; |
379 | struct rio_switch *rswitch = NULL; | 379 | struct rio_switch *rswitch = NULL; |
380 | int result, rdid; | 380 | int result, rdid; |
381 | size_t size; | ||
382 | u32 swpinfo = 0; | ||
381 | 383 | ||
382 | rdev = kzalloc(sizeof(struct rio_dev), GFP_KERNEL); | 384 | size = sizeof(struct rio_dev); |
385 | if (rio_mport_read_config_32(port, destid, hopcount, | ||
386 | RIO_PEF_CAR, &result)) | ||
387 | return NULL; | ||
388 | |||
389 | if (result & (RIO_PEF_SWITCH | RIO_PEF_MULTIPORT)) { | ||
390 | rio_mport_read_config_32(port, destid, hopcount, | ||
391 | RIO_SWP_INFO_CAR, &swpinfo); | ||
392 | if (result & RIO_PEF_SWITCH) { | ||
393 | size += (RIO_GET_TOTAL_PORTS(swpinfo) * | ||
394 | sizeof(rswitch->nextdev[0])) + sizeof(*rswitch); | ||
395 | } | ||
396 | } | ||
397 | |||
398 | rdev = kzalloc(size, GFP_KERNEL); | ||
383 | if (!rdev) | 399 | if (!rdev) |
384 | return NULL; | 400 | return NULL; |
385 | 401 | ||
386 | rdev->net = net; | 402 | rdev->net = net; |
403 | rdev->pef = result; | ||
404 | rdev->swpinfo = swpinfo; | ||
387 | rio_mport_read_config_32(port, destid, hopcount, RIO_DEV_ID_CAR, | 405 | rio_mport_read_config_32(port, destid, hopcount, RIO_DEV_ID_CAR, |
388 | &result); | 406 | &result); |
389 | rdev->did = result >> 16; | 407 | rdev->did = result >> 16; |
@@ -397,8 +415,6 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net, | |||
397 | rio_mport_read_config_32(port, destid, hopcount, RIO_ASM_INFO_CAR, | 415 | rio_mport_read_config_32(port, destid, hopcount, RIO_ASM_INFO_CAR, |
398 | &result); | 416 | &result); |
399 | rdev->asm_rev = result >> 16; | 417 | rdev->asm_rev = result >> 16; |
400 | rio_mport_read_config_32(port, destid, hopcount, RIO_PEF_CAR, | ||
401 | &rdev->pef); | ||
402 | if (rdev->pef & RIO_PEF_EXT_FEATURES) { | 418 | if (rdev->pef & RIO_PEF_EXT_FEATURES) { |
403 | rdev->efptr = result & 0xffff; | 419 | rdev->efptr = result & 0xffff; |
404 | rdev->phys_efptr = rio_mport_get_physefb(port, 0, destid, | 420 | rdev->phys_efptr = rio_mport_get_physefb(port, 0, destid, |
@@ -408,11 +424,6 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net, | |||
408 | hopcount, RIO_EFB_ERR_MGMNT); | 424 | hopcount, RIO_EFB_ERR_MGMNT); |
409 | } | 425 | } |
410 | 426 | ||
411 | if (rdev->pef & (RIO_PEF_SWITCH | RIO_PEF_MULTIPORT)) { | ||
412 | rio_mport_read_config_32(port, destid, hopcount, | ||
413 | RIO_SWP_INFO_CAR, &rdev->swpinfo); | ||
414 | } | ||
415 | |||
416 | rio_mport_read_config_32(port, destid, hopcount, RIO_SRC_OPS_CAR, | 427 | rio_mport_read_config_32(port, destid, hopcount, RIO_SRC_OPS_CAR, |
417 | &rdev->src_ops); | 428 | &rdev->src_ops); |
418 | rio_mport_read_config_32(port, destid, hopcount, RIO_DST_OPS_CAR, | 429 | rio_mport_read_config_32(port, destid, hopcount, RIO_DST_OPS_CAR, |
@@ -449,12 +460,7 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net, | |||
449 | 460 | ||
450 | /* If a PE has both switch and other functions, show it as a switch */ | 461 | /* If a PE has both switch and other functions, show it as a switch */ |
451 | if (rio_is_switch(rdev)) { | 462 | if (rio_is_switch(rdev)) { |
452 | rswitch = kzalloc(sizeof(*rswitch) + | 463 | rswitch = rdev->rswitch; |
453 | RIO_GET_TOTAL_PORTS(rdev->swpinfo) * | ||
454 | sizeof(rswitch->nextdev[0]), | ||
455 | GFP_KERNEL); | ||
456 | if (!rswitch) | ||
457 | goto cleanup; | ||
458 | rswitch->switchid = next_switchid; | 464 | rswitch->switchid = next_switchid; |
459 | rswitch->port_ok = 0; | 465 | rswitch->port_ok = 0; |
460 | rswitch->route_table = kzalloc(sizeof(u8)* | 466 | rswitch->route_table = kzalloc(sizeof(u8)* |
@@ -466,15 +472,13 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net, | |||
466 | for (rdid = 0; rdid < RIO_MAX_ROUTE_ENTRIES(port->sys_size); | 472 | for (rdid = 0; rdid < RIO_MAX_ROUTE_ENTRIES(port->sys_size); |
467 | rdid++) | 473 | rdid++) |
468 | rswitch->route_table[rdid] = RIO_INVALID_ROUTE; | 474 | rswitch->route_table[rdid] = RIO_INVALID_ROUTE; |
469 | rdev->rswitch = rswitch; | ||
470 | rswitch->rdev = rdev; | ||
471 | dev_set_name(&rdev->dev, "%02x:s:%04x", rdev->net->id, | 475 | dev_set_name(&rdev->dev, "%02x:s:%04x", rdev->net->id, |
472 | rdev->rswitch->switchid); | 476 | rswitch->switchid); |
473 | rio_switch_init(rdev, do_enum); | 477 | rio_switch_init(rdev, do_enum); |
474 | 478 | ||
475 | if (do_enum && rdev->rswitch->clr_table) | 479 | if (do_enum && rswitch->clr_table) |
476 | rdev->rswitch->clr_table(port, destid, hopcount, | 480 | rswitch->clr_table(port, destid, hopcount, |
477 | RIO_GLOBAL_TABLE); | 481 | RIO_GLOBAL_TABLE); |
478 | 482 | ||
479 | list_add_tail(&rswitch->node, &rio_switches); | 483 | list_add_tail(&rswitch->node, &rio_switches); |
480 | 484 | ||
@@ -510,10 +514,9 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net, | |||
510 | return rdev; | 514 | return rdev; |
511 | 515 | ||
512 | cleanup: | 516 | cleanup: |
513 | if (rswitch) { | 517 | if (rswitch->route_table) |
514 | kfree(rswitch->route_table); | 518 | kfree(rswitch->route_table); |
515 | kfree(rswitch); | 519 | |
516 | } | ||
517 | kfree(rdev); | 520 | kfree(rdev); |
518 | return NULL; | 521 | return NULL; |
519 | } | 522 | } |
@@ -1072,7 +1075,7 @@ static struct rio_net __devinit *rio_alloc_net(struct rio_mport *port) | |||
1072 | */ | 1075 | */ |
1073 | static void rio_update_route_tables(struct rio_mport *port) | 1076 | static void rio_update_route_tables(struct rio_mport *port) |
1074 | { | 1077 | { |
1075 | struct rio_dev *rdev; | 1078 | struct rio_dev *rdev, *swrdev; |
1076 | struct rio_switch *rswitch; | 1079 | struct rio_switch *rswitch; |
1077 | u8 sport; | 1080 | u8 sport; |
1078 | u16 destid; | 1081 | u16 destid; |
@@ -1087,14 +1090,16 @@ static void rio_update_route_tables(struct rio_mport *port) | |||
1087 | continue; | 1090 | continue; |
1088 | 1091 | ||
1089 | if (RIO_INVALID_ROUTE == rswitch->route_table[destid]) { | 1092 | if (RIO_INVALID_ROUTE == rswitch->route_table[destid]) { |
1093 | swrdev = sw_to_rio_dev(rswitch); | ||
1094 | |||
1090 | /* Skip if destid ends in empty switch*/ | 1095 | /* Skip if destid ends in empty switch*/ |
1091 | if (rswitch->rdev->destid == destid) | 1096 | if (swrdev->destid == destid) |
1092 | continue; | 1097 | continue; |
1093 | 1098 | ||
1094 | sport = RIO_GET_PORT_NUM(rswitch->rdev->swpinfo); | 1099 | sport = RIO_GET_PORT_NUM(swrdev->swpinfo); |
1095 | 1100 | ||
1096 | if (rswitch->add_entry) { | 1101 | if (rswitch->add_entry) { |
1097 | rio_route_add_entry(rswitch->rdev, | 1102 | rio_route_add_entry(swrdev, |
1098 | RIO_GLOBAL_TABLE, destid, | 1103 | RIO_GLOBAL_TABLE, destid, |
1099 | sport, 0); | 1104 | sport, 0); |
1100 | rswitch->route_table[destid] = sport; | 1105 | rswitch->route_table[destid] = sport; |