aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKristian Høgsberg <krh@redhat.com>2007-03-07 12:12:55 -0500
committerStefan Richter <stefanr@s5r6.in-berlin.de>2007-03-09 16:03:14 -0500
commit473d28c730e2de888c24b226cfe4183868eacde2 (patch)
tree8653544f742c8c99d6076f881eb0eb0ef4b30904
parent7c6e647da00883ec2208171d51537f23498dd669 (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>
-rw-r--r--drivers/firewire/fw-card.c2
-rw-r--r--drivers/firewire/fw-ohci.c11
-rw-r--r--drivers/firewire/fw-topology.c28
-rw-r--r--drivers/firewire/fw-topology.h3
-rw-r--r--drivers/firewire/fw-transaction.c52
-rw-r--r--drivers/firewire/fw-transaction.h5
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. */
33static u16 33u16
34crc16_itu_t(const u32 *buffer, size_t length) 34crc16_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
844static void 851static 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 */
166static struct fw_node *build_tree(struct fw_card *card) 166static 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
463static void
464update_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
463void 477void
464fw_core_handle_bus_reset(struct fw_card *card, 478fw_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)
88void 88void
89fw_destroy_nodes(struct fw_card *card); 89fw_destroy_nodes(struct fw_card *card);
90 90
91u16
92crc16_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
141static void 141static void
142fw_fill_request(struct fw_packet *packet, int tcode, int tlabel, 142fw_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}
717EXPORT_SYMBOL(fw_core_handle_response); 719EXPORT_SYMBOL(fw_core_handle_response);
718 720
721const struct fw_address_region topology_map_region =
722 { .start = 0xfffff0001000ull, .end = 0xfffff0001400ull, };
723
724static void
725handle_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
754static struct fw_address_handler topology_map = {
755 .length = 0x400,
756 .address_callback = handle_topology_map,
757};
758
719MODULE_AUTHOR("Kristian Hoegsberg <krh@bitplanet.net>"); 759MODULE_AUTHOR("Kristian Hoegsberg <krh@bitplanet.net>");
720MODULE_DESCRIPTION("Core IEEE1394 transaction logic"); 760MODULE_DESCRIPTION("Core IEEE1394 transaction logic");
721MODULE_LICENSE("GPL"); 761MODULE_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. */