diff options
author | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2007-06-10 15:31:36 -0400 |
---|---|---|
committer | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2007-07-09 18:07:43 -0400 |
commit | f1397490017e337446c6a8b0562b584679a604a6 (patch) | |
tree | 073c65b0fe78e02b529285ec1bffe5a5c7612e69 | |
parent | 24d40125f1f59a6de9d9e6e046676bd60532596c (diff) |
firewire: support S100B...S400B and link slower than PHY
Use a speed probe to determine the speed over 1394b buses and of nodes
which report a link speed less than their PHY speed.
Log the effective maximum speed of newly created nodes in dmesg.
Also, read the config ROM (except bus info block) at the maximum speed
rather than S100. This isn't a real optimization though because we
still only use quadlet read requests for the entire ROM.
The patch also adds support for S1600 and S3200, although such hardware
does not exist yet.
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Signed-off-by: Kristian Høgsberg <krh@redhat.com>
-rw-r--r-- | drivers/firewire/fw-cdev.c | 2 | ||||
-rw-r--r-- | drivers/firewire/fw-device.c | 38 | ||||
-rw-r--r-- | drivers/firewire/fw-device.h | 1 | ||||
-rw-r--r-- | drivers/firewire/fw-sbp2.c | 7 | ||||
-rw-r--r-- | drivers/firewire/fw-topology.h | 13 |
5 files changed, 45 insertions, 16 deletions
diff --git a/drivers/firewire/fw-cdev.c b/drivers/firewire/fw-cdev.c index dbb76427d529..75388641a7d3 100644 --- a/drivers/firewire/fw-cdev.c +++ b/drivers/firewire/fw-cdev.c | |||
@@ -397,7 +397,7 @@ static int ioctl_send_request(struct client *client, void *buffer) | |||
397 | request->tcode & 0x1f, | 397 | request->tcode & 0x1f, |
398 | device->node->node_id, | 398 | device->node->node_id, |
399 | request->generation, | 399 | request->generation, |
400 | device->node->max_speed, | 400 | device->max_speed, |
401 | request->offset, | 401 | request->offset, |
402 | response->response.data, request->length, | 402 | response->response.data, request->length, |
403 | complete_transaction, response); | 403 | complete_transaction, response); |
diff --git a/drivers/firewire/fw-device.c b/drivers/firewire/fw-device.c index c1ce465d9710..2b6586341635 100644 --- a/drivers/firewire/fw-device.c +++ b/drivers/firewire/fw-device.c | |||
@@ -401,8 +401,7 @@ static int read_rom(struct fw_device *device, int index, u32 * data) | |||
401 | 401 | ||
402 | offset = 0xfffff0000400ULL + index * 4; | 402 | offset = 0xfffff0000400ULL + index * 4; |
403 | fw_send_request(device->card, &t, TCODE_READ_QUADLET_REQUEST, | 403 | fw_send_request(device->card, &t, TCODE_READ_QUADLET_REQUEST, |
404 | device->node_id, | 404 | device->node_id, device->generation, device->max_speed, |
405 | device->generation, SCODE_100, | ||
406 | offset, NULL, 4, complete_transaction, &callback_data); | 405 | offset, NULL, 4, complete_transaction, &callback_data); |
407 | 406 | ||
408 | wait_for_completion(&callback_data.done); | 407 | wait_for_completion(&callback_data.done); |
@@ -418,6 +417,8 @@ static int read_bus_info_block(struct fw_device *device) | |||
418 | u32 stack[16], sp, key; | 417 | u32 stack[16], sp, key; |
419 | int i, end, length; | 418 | int i, end, length; |
420 | 419 | ||
420 | device->max_speed = SCODE_100; | ||
421 | |||
421 | /* First read the bus info block. */ | 422 | /* First read the bus info block. */ |
422 | for (i = 0; i < 5; i++) { | 423 | for (i = 0; i < 5; i++) { |
423 | if (read_rom(device, i, &rom[i]) != RCODE_COMPLETE) | 424 | if (read_rom(device, i, &rom[i]) != RCODE_COMPLETE) |
@@ -434,6 +435,33 @@ static int read_bus_info_block(struct fw_device *device) | |||
434 | return -1; | 435 | return -1; |
435 | } | 436 | } |
436 | 437 | ||
438 | device->max_speed = device->node->max_speed; | ||
439 | |||
440 | /* | ||
441 | * Determine the speed of | ||
442 | * - devices with link speed less than PHY speed, | ||
443 | * - devices with 1394b PHY (unless only connected to 1394a PHYs), | ||
444 | * - all devices if there are 1394b repeaters. | ||
445 | * Note, we cannot use the bus info block's link_spd as starting point | ||
446 | * because some buggy firmwares set it lower than necessary and because | ||
447 | * 1394-1995 nodes do not have the field. | ||
448 | */ | ||
449 | if ((rom[2] & 0x7) < device->max_speed || | ||
450 | device->max_speed == SCODE_BETA || | ||
451 | device->card->beta_repeaters_present) { | ||
452 | u32 dummy; | ||
453 | |||
454 | /* for S1600 and S3200 */ | ||
455 | if (device->max_speed == SCODE_BETA) | ||
456 | device->max_speed = device->card->link_speed; | ||
457 | |||
458 | while (device->max_speed > SCODE_100) { | ||
459 | if (read_rom(device, 0, &dummy) == RCODE_COMPLETE) | ||
460 | break; | ||
461 | device->max_speed--; | ||
462 | } | ||
463 | } | ||
464 | |||
437 | /* | 465 | /* |
438 | * Now parse the config rom. The config rom is a recursive | 466 | * Now parse the config rom. The config rom is a recursive |
439 | * directory structure so we parse it using a stack of | 467 | * directory structure so we parse it using a stack of |
@@ -680,8 +708,10 @@ static void fw_device_init(struct work_struct *work) | |||
680 | FW_DEVICE_RUNNING) == FW_DEVICE_SHUTDOWN) | 708 | FW_DEVICE_RUNNING) == FW_DEVICE_SHUTDOWN) |
681 | fw_device_shutdown(&device->work.work); | 709 | fw_device_shutdown(&device->work.work); |
682 | else | 710 | else |
683 | fw_notify("created new fw device %s (%d config rom retries)\n", | 711 | fw_notify("created new fw device %s " |
684 | device->device.bus_id, device->config_rom_retries); | 712 | "(%d config rom retries, S%d00)\n", |
713 | device->device.bus_id, device->config_rom_retries, | ||
714 | 1 << device->max_speed); | ||
685 | 715 | ||
686 | /* | 716 | /* |
687 | * Reschedule the IRM work if we just finished reading the | 717 | * Reschedule the IRM work if we just finished reading the |
diff --git a/drivers/firewire/fw-device.h b/drivers/firewire/fw-device.h index af1723eae4ba..d13e6a69707f 100644 --- a/drivers/firewire/fw-device.h +++ b/drivers/firewire/fw-device.h | |||
@@ -40,6 +40,7 @@ struct fw_device { | |||
40 | struct fw_node *node; | 40 | struct fw_node *node; |
41 | int node_id; | 41 | int node_id; |
42 | int generation; | 42 | int generation; |
43 | unsigned max_speed; | ||
43 | struct fw_card *card; | 44 | struct fw_card *card; |
44 | struct device device; | 45 | struct device device; |
45 | struct list_head link; | 46 | struct list_head link; |
diff --git a/drivers/firewire/fw-sbp2.c b/drivers/firewire/fw-sbp2.c index 16e942f72e48..851c2da060d2 100644 --- a/drivers/firewire/fw-sbp2.c +++ b/drivers/firewire/fw-sbp2.c | |||
@@ -346,8 +346,7 @@ sbp2_send_orb(struct sbp2_orb *orb, struct fw_unit *unit, | |||
346 | spin_unlock_irqrestore(&device->card->lock, flags); | 346 | spin_unlock_irqrestore(&device->card->lock, flags); |
347 | 347 | ||
348 | fw_send_request(device->card, &orb->t, TCODE_WRITE_BLOCK_REQUEST, | 348 | fw_send_request(device->card, &orb->t, TCODE_WRITE_BLOCK_REQUEST, |
349 | node_id, generation, | 349 | node_id, generation, device->max_speed, offset, |
350 | device->node->max_speed, offset, | ||
351 | &orb->pointer, sizeof(orb->pointer), | 350 | &orb->pointer, sizeof(orb->pointer), |
352 | complete_transaction, orb); | 351 | complete_transaction, orb); |
353 | } | 352 | } |
@@ -1018,8 +1017,8 @@ static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done) | |||
1018 | * if we set this to max_speed + 7, we get the right value. | 1017 | * if we set this to max_speed + 7, we get the right value. |
1019 | */ | 1018 | */ |
1020 | orb->request.misc = | 1019 | orb->request.misc = |
1021 | COMMAND_ORB_MAX_PAYLOAD(device->node->max_speed + 7) | | 1020 | COMMAND_ORB_MAX_PAYLOAD(device->max_speed + 7) | |
1022 | COMMAND_ORB_SPEED(device->node->max_speed) | | 1021 | COMMAND_ORB_SPEED(device->max_speed) | |
1023 | COMMAND_ORB_NOTIFY; | 1022 | COMMAND_ORB_NOTIFY; |
1024 | 1023 | ||
1025 | if (cmd->sc_data_direction == DMA_FROM_DEVICE) | 1024 | if (cmd->sc_data_direction == DMA_FROM_DEVICE) |
diff --git a/drivers/firewire/fw-topology.h b/drivers/firewire/fw-topology.h index aced9f7db358..da61ec09183e 100644 --- a/drivers/firewire/fw-topology.h +++ b/drivers/firewire/fw-topology.h | |||
@@ -29,19 +29,18 @@ enum { | |||
29 | 29 | ||
30 | struct fw_port { | 30 | struct fw_port { |
31 | struct fw_node *node; | 31 | struct fw_node *node; |
32 | unsigned speed : 3; /* S100, S200, ... S3200 */ | ||
33 | }; | 32 | }; |
34 | 33 | ||
35 | struct fw_node { | 34 | struct fw_node { |
36 | u16 node_id; | 35 | u16 node_id; |
37 | u8 color; | 36 | u8 color; |
38 | u8 port_count; | 37 | u8 port_count; |
39 | unsigned link_on : 1; | 38 | u8 link_on : 1; |
40 | unsigned initiated_reset : 1; | 39 | u8 initiated_reset : 1; |
41 | unsigned b_path : 1; | 40 | u8 b_path : 1; |
42 | u8 phy_speed : 3; /* As in the self ID packet. */ | 41 | u8 phy_speed : 2; /* As in the self ID packet. */ |
43 | u8 max_speed : 5; /* Minimum of all phy-speeds and port speeds on | 42 | u8 max_speed : 2; /* Minimum of all phy-speeds on the path from the |
44 | * the path from the local node to this node. */ | 43 | * local node to this node. */ |
45 | u8 max_depth : 4; /* Maximum depth to any leaf node */ | 44 | u8 max_depth : 4; /* Maximum depth to any leaf node */ |
46 | u8 max_hops : 4; /* Max hops in this sub tree */ | 45 | u8 max_hops : 4; /* Max hops in this sub tree */ |
47 | atomic_t ref_count; | 46 | atomic_t ref_count; |