diff options
author | Kristian Høgsberg <krh@redhat.com> | 2007-03-07 12:12:55 -0500 |
---|---|---|
committer | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2007-03-09 16:03:14 -0500 |
commit | 473d28c730e2de888c24b226cfe4183868eacde2 (patch) | |
tree | 8653544f742c8c99d6076f881eb0eb0ef4b30904 /drivers | |
parent | 7c6e647da00883ec2208171d51537f23498dd669 (diff) |
firewire: Implement topology map and fix a couple of loopback bugs.
Signed-off-by: Kristian Høgsberg <krh@redhat.com>
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/firewire/fw-card.c | 2 | ||||
-rw-r--r-- | drivers/firewire/fw-ohci.c | 11 | ||||
-rw-r--r-- | drivers/firewire/fw-topology.c | 28 | ||||
-rw-r--r-- | drivers/firewire/fw-topology.h | 3 | ||||
-rw-r--r-- | drivers/firewire/fw-transaction.c | 52 | ||||
-rw-r--r-- | drivers/firewire/fw-transaction.h | 5 |
6 files changed, 85 insertions, 16 deletions
diff --git a/drivers/firewire/fw-card.c b/drivers/firewire/fw-card.c index b1deb5214bd4..d929eb6fef6a 100644 --- a/drivers/firewire/fw-card.c +++ b/drivers/firewire/fw-card.c | |||
@@ -30,7 +30,7 @@ | |||
30 | * polynomial, but we need the ITU-T (or CCITT) polynomial (0x1021). | 30 | * polynomial, but we need the ITU-T (or CCITT) polynomial (0x1021). |
31 | * The implementation below works on an array of host-endian u32 | 31 | * The implementation below works on an array of host-endian u32 |
32 | * words, assuming they'll be transmited msb first. */ | 32 | * words, assuming they'll be transmited msb first. */ |
33 | static u16 | 33 | u16 |
34 | crc16_itu_t(const u32 *buffer, size_t length) | 34 | crc16_itu_t(const u32 *buffer, size_t length) |
35 | { | 35 | { |
36 | int shift, i; | 36 | int shift, i; |
diff --git a/drivers/firewire/fw-ohci.c b/drivers/firewire/fw-ohci.c index 9e8a8f909303..a9e13468f60c 100644 --- a/drivers/firewire/fw-ohci.c +++ b/drivers/firewire/fw-ohci.c | |||
@@ -813,8 +813,10 @@ handle_local_request(struct context *ctx, struct fw_packet *packet) | |||
813 | u64 offset; | 813 | u64 offset; |
814 | u32 csr; | 814 | u32 csr; |
815 | 815 | ||
816 | packet->ack = ACK_PENDING; | 816 | if (ctx == &ctx->ohci->at_request_ctx) { |
817 | packet->callback(packet, &ctx->ohci->card, packet->ack); | 817 | packet->ack = ACK_PENDING; |
818 | packet->callback(packet, &ctx->ohci->card, packet->ack); | ||
819 | } | ||
818 | 820 | ||
819 | offset = | 821 | offset = |
820 | ((unsigned long long) | 822 | ((unsigned long long) |
@@ -839,6 +841,11 @@ handle_local_request(struct context *ctx, struct fw_packet *packet) | |||
839 | fw_core_handle_response(&ctx->ohci->card, packet); | 841 | fw_core_handle_response(&ctx->ohci->card, packet); |
840 | break; | 842 | break; |
841 | } | 843 | } |
844 | |||
845 | if (ctx == &ctx->ohci->at_response_ctx) { | ||
846 | packet->ack = ACK_COMPLETE; | ||
847 | packet->callback(packet, &ctx->ohci->card, packet->ack); | ||
848 | } | ||
842 | } | 849 | } |
843 | 850 | ||
844 | static void | 851 | static void |
diff --git a/drivers/firewire/fw-topology.c b/drivers/firewire/fw-topology.c index 36c9be75b025..7923463fdbf3 100644 --- a/drivers/firewire/fw-topology.c +++ b/drivers/firewire/fw-topology.c | |||
@@ -163,11 +163,12 @@ static void update_hop_count(struct fw_node *node) | |||
163 | * internally consistent. On succcess this funtions returns the | 163 | * internally consistent. On succcess this funtions returns the |
164 | * fw_node corresponding to the local card otherwise NULL. | 164 | * fw_node corresponding to the local card otherwise NULL. |
165 | */ | 165 | */ |
166 | static struct fw_node *build_tree(struct fw_card *card) | 166 | static struct fw_node *build_tree(struct fw_card *card, |
167 | u32 *sid, int self_id_count) | ||
167 | { | 168 | { |
168 | struct fw_node *node, *child, *local_node; | 169 | struct fw_node *node, *child, *local_node; |
169 | struct list_head stack, *h; | 170 | struct list_head stack, *h; |
170 | u32 *sid, *next_sid, *end, q; | 171 | u32 *next_sid, *end, q; |
171 | int i, port_count, child_port_count, phy_id, parent_count, stack_depth; | 172 | int i, port_count, child_port_count, phy_id, parent_count, stack_depth; |
172 | int gap_count, topology_type; | 173 | int gap_count, topology_type; |
173 | 174 | ||
@@ -175,8 +176,7 @@ static struct fw_node *build_tree(struct fw_card *card) | |||
175 | node = NULL; | 176 | node = NULL; |
176 | INIT_LIST_HEAD(&stack); | 177 | INIT_LIST_HEAD(&stack); |
177 | stack_depth = 0; | 178 | stack_depth = 0; |
178 | sid = card->self_ids; | 179 | end = sid + self_id_count; |
179 | end = sid + card->self_id_count; | ||
180 | phy_id = 0; | 180 | phy_id = 0; |
181 | card->irm_node = NULL; | 181 | card->irm_node = NULL; |
182 | gap_count = self_id_gap_count(*sid); | 182 | gap_count = self_id_gap_count(*sid); |
@@ -460,6 +460,20 @@ update_tree(struct fw_card *card, struct fw_node *root) | |||
460 | } | 460 | } |
461 | } | 461 | } |
462 | 462 | ||
463 | static void | ||
464 | update_topology_map(struct fw_card *card, u32 *self_ids, int self_id_count) | ||
465 | { | ||
466 | int node_count; | ||
467 | u32 crc; | ||
468 | |||
469 | card->topology_map[1]++; | ||
470 | node_count = (card->root_node->node_id & 0x3f) + 1; | ||
471 | card->topology_map[2] = (node_count << 16) | self_id_count; | ||
472 | crc = crc16_itu_t(card->topology_map + 1, self_id_count + 2); | ||
473 | card->topology_map[0] = ((self_id_count + 2) << 16) | crc; | ||
474 | memcpy(&card->topology_map[3], self_ids, self_id_count * 4); | ||
475 | } | ||
476 | |||
463 | void | 477 | void |
464 | fw_core_handle_bus_reset(struct fw_card *card, | 478 | fw_core_handle_bus_reset(struct fw_card *card, |
465 | int node_id, int generation, | 479 | int node_id, int generation, |
@@ -479,13 +493,13 @@ fw_core_handle_bus_reset(struct fw_card *card, | |||
479 | card->bm_retries = 0; | 493 | card->bm_retries = 0; |
480 | 494 | ||
481 | card->node_id = node_id; | 495 | card->node_id = node_id; |
482 | card->self_id_count = self_id_count; | ||
483 | card->generation = generation; | 496 | card->generation = generation; |
484 | memcpy(card->self_ids, self_ids, self_id_count * 4); | ||
485 | card->reset_jiffies = jiffies; | 497 | card->reset_jiffies = jiffies; |
486 | schedule_delayed_work(&card->work, 0); | 498 | schedule_delayed_work(&card->work, 0); |
487 | 499 | ||
488 | local_node = build_tree(card); | 500 | local_node = build_tree(card, self_ids, self_id_count); |
501 | |||
502 | update_topology_map(card, self_ids, self_id_count); | ||
489 | 503 | ||
490 | card->color++; | 504 | card->color++; |
491 | 505 | ||
diff --git a/drivers/firewire/fw-topology.h b/drivers/firewire/fw-topology.h index f2a575e05ae1..913bfe160882 100644 --- a/drivers/firewire/fw-topology.h +++ b/drivers/firewire/fw-topology.h | |||
@@ -88,4 +88,7 @@ fw_node_put(struct fw_node *node) | |||
88 | void | 88 | void |
89 | fw_destroy_nodes(struct fw_card *card); | 89 | fw_destroy_nodes(struct fw_card *card); |
90 | 90 | ||
91 | u16 | ||
92 | crc16_itu_t(const u32 *buffer, size_t length); | ||
93 | |||
91 | #endif /* __fw_topology_h */ | 94 | #endif /* __fw_topology_h */ |
diff --git a/drivers/firewire/fw-transaction.c b/drivers/firewire/fw-transaction.c index 3052698c13a6..38b286ed744f 100644 --- a/drivers/firewire/fw-transaction.c +++ b/drivers/firewire/fw-transaction.c | |||
@@ -140,7 +140,7 @@ transmit_complete_callback(struct fw_packet *packet, | |||
140 | 140 | ||
141 | static void | 141 | static void |
142 | fw_fill_request(struct fw_packet *packet, int tcode, int tlabel, | 142 | fw_fill_request(struct fw_packet *packet, int tcode, int tlabel, |
143 | int node_id, int generation, int speed, | 143 | int node_id, int source_id, int generation, int speed, |
144 | unsigned long long offset, void *payload, size_t length) | 144 | unsigned long long offset, void *payload, size_t length) |
145 | { | 145 | { |
146 | int ext_tcode; | 146 | int ext_tcode; |
@@ -157,7 +157,7 @@ fw_fill_request(struct fw_packet *packet, int tcode, int tlabel, | |||
157 | header_tcode(tcode) | | 157 | header_tcode(tcode) | |
158 | header_destination(node_id); | 158 | header_destination(node_id); |
159 | packet->header[1] = | 159 | packet->header[1] = |
160 | header_offset_high(offset >> 32) | header_source(0); | 160 | header_offset_high(offset >> 32) | header_source(source_id); |
161 | packet->header[2] = | 161 | packet->header[2] = |
162 | offset; | 162 | offset; |
163 | 163 | ||
@@ -241,7 +241,7 @@ fw_send_request(struct fw_card *card, struct fw_transaction *t, | |||
241 | fw_transaction_callback_t callback, void *callback_data) | 241 | fw_transaction_callback_t callback, void *callback_data) |
242 | { | 242 | { |
243 | unsigned long flags; | 243 | unsigned long flags; |
244 | int tlabel; | 244 | int tlabel, source; |
245 | 245 | ||
246 | /* Bump the flush timer up 100ms first of all so we | 246 | /* Bump the flush timer up 100ms first of all so we |
247 | * don't race with a flush timer callback. */ | 247 | * don't race with a flush timer callback. */ |
@@ -253,6 +253,7 @@ fw_send_request(struct fw_card *card, struct fw_transaction *t, | |||
253 | 253 | ||
254 | spin_lock_irqsave(&card->lock, flags); | 254 | spin_lock_irqsave(&card->lock, flags); |
255 | 255 | ||
256 | source = card->node_id; | ||
256 | tlabel = card->current_tlabel; | 257 | tlabel = card->current_tlabel; |
257 | if (card->tlabel_mask & (1 << tlabel)) { | 258 | if (card->tlabel_mask & (1 << tlabel)) { |
258 | spin_unlock_irqrestore(&card->lock, flags); | 259 | spin_unlock_irqrestore(&card->lock, flags); |
@@ -274,7 +275,8 @@ fw_send_request(struct fw_card *card, struct fw_transaction *t, | |||
274 | t->callback_data = callback_data; | 275 | t->callback_data = callback_data; |
275 | 276 | ||
276 | fw_fill_request(&t->packet, tcode, t->tlabel, | 277 | fw_fill_request(&t->packet, tcode, t->tlabel, |
277 | node_id, generation, speed, offset, payload, length); | 278 | node_id, source, generation, |
279 | speed, offset, payload, length); | ||
278 | t->packet.callback = transmit_complete_callback; | 280 | t->packet.callback = transmit_complete_callback; |
279 | 281 | ||
280 | card->driver->send_request(card, &t->packet); | 282 | card->driver->send_request(card, &t->packet); |
@@ -716,6 +718,44 @@ fw_core_handle_response(struct fw_card *card, struct fw_packet *p) | |||
716 | } | 718 | } |
717 | EXPORT_SYMBOL(fw_core_handle_response); | 719 | EXPORT_SYMBOL(fw_core_handle_response); |
718 | 720 | ||
721 | const struct fw_address_region topology_map_region = | ||
722 | { .start = 0xfffff0001000ull, .end = 0xfffff0001400ull, }; | ||
723 | |||
724 | static void | ||
725 | handle_topology_map(struct fw_card *card, struct fw_request *request, | ||
726 | int tcode, int destination, int source, | ||
727 | int generation, int speed, | ||
728 | unsigned long long offset, | ||
729 | void *payload, size_t length, void *callback_data) | ||
730 | { | ||
731 | int i, start, end; | ||
732 | u32 *map; | ||
733 | |||
734 | if (!TCODE_IS_READ_REQUEST(tcode)) { | ||
735 | fw_send_response(card, request, RCODE_TYPE_ERROR); | ||
736 | return; | ||
737 | } | ||
738 | |||
739 | if ((offset & 3) > 0 || (length & 3) > 0) { | ||
740 | fw_send_response(card, request, RCODE_ADDRESS_ERROR); | ||
741 | return; | ||
742 | } | ||
743 | |||
744 | start = (offset - topology_map_region.start) / 4; | ||
745 | end = start + length / 4; | ||
746 | map = payload; | ||
747 | |||
748 | for (i = 0; i < length / 4; i++) | ||
749 | map[i] = cpu_to_be32(card->topology_map[start + i]); | ||
750 | |||
751 | fw_send_response(card, request, RCODE_COMPLETE); | ||
752 | } | ||
753 | |||
754 | static struct fw_address_handler topology_map = { | ||
755 | .length = 0x400, | ||
756 | .address_callback = handle_topology_map, | ||
757 | }; | ||
758 | |||
719 | MODULE_AUTHOR("Kristian Hoegsberg <krh@bitplanet.net>"); | 759 | MODULE_AUTHOR("Kristian Hoegsberg <krh@bitplanet.net>"); |
720 | MODULE_DESCRIPTION("Core IEEE1394 transaction logic"); | 760 | MODULE_DESCRIPTION("Core IEEE1394 transaction logic"); |
721 | MODULE_LICENSE("GPL"); | 761 | MODULE_LICENSE("GPL"); |
@@ -767,6 +807,10 @@ static int __init fw_core_init(void) | |||
767 | return fw_cdev_major; | 807 | return fw_cdev_major; |
768 | } | 808 | } |
769 | 809 | ||
810 | retval = fw_core_add_address_handler(&topology_map, | ||
811 | &topology_map_region); | ||
812 | BUG_ON(retval < 0); | ||
813 | |||
770 | /* Add the vendor textual descriptor. */ | 814 | /* Add the vendor textual descriptor. */ |
771 | retval = fw_core_add_descriptor(&vendor_id_descriptor); | 815 | retval = fw_core_add_descriptor(&vendor_id_descriptor); |
772 | BUG_ON(retval < 0); | 816 | BUG_ON(retval < 0); |
diff --git a/drivers/firewire/fw-transaction.h b/drivers/firewire/fw-transaction.h index e7301b83f91e..a661afb9d68f 100644 --- a/drivers/firewire/fw-transaction.h +++ b/drivers/firewire/fw-transaction.h | |||
@@ -285,9 +285,10 @@ struct fw_card { | |||
285 | int link_speed; | 285 | int link_speed; |
286 | int config_rom_generation; | 286 | int config_rom_generation; |
287 | 287 | ||
288 | /* We need to store up to 4 self ID for a maximum of 63 devices. */ | 288 | /* We need to store up to 4 self ID for a maximum of 63 |
289 | * devices plus 3 words for the topology map header. */ | ||
289 | int self_id_count; | 290 | int self_id_count; |
290 | u32 self_ids[252]; | 291 | u32 topology_map[252 + 3]; |
291 | 292 | ||
292 | spinlock_t lock; /* Take this lock when handling the lists in | 293 | spinlock_t lock; /* Take this lock when handling the lists in |
293 | * this struct. */ | 294 | * this struct. */ |