mirror of https://gitee.com/openkylin/linux.git
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>
This commit is contained in:
parent
7c6e647da0
commit
473d28c730
|
@ -30,7 +30,7 @@
|
||||||
* polynomial, but we need the ITU-T (or CCITT) polynomial (0x1021).
|
* polynomial, but we need the ITU-T (or CCITT) polynomial (0x1021).
|
||||||
* The implementation below works on an array of host-endian u32
|
* The implementation below works on an array of host-endian u32
|
||||||
* words, assuming they'll be transmited msb first. */
|
* words, assuming they'll be transmited msb first. */
|
||||||
static u16
|
u16
|
||||||
crc16_itu_t(const u32 *buffer, size_t length)
|
crc16_itu_t(const u32 *buffer, size_t length)
|
||||||
{
|
{
|
||||||
int shift, i;
|
int shift, i;
|
||||||
|
|
|
@ -813,8 +813,10 @@ handle_local_request(struct context *ctx, struct fw_packet *packet)
|
||||||
u64 offset;
|
u64 offset;
|
||||||
u32 csr;
|
u32 csr;
|
||||||
|
|
||||||
|
if (ctx == &ctx->ohci->at_request_ctx) {
|
||||||
packet->ack = ACK_PENDING;
|
packet->ack = ACK_PENDING;
|
||||||
packet->callback(packet, &ctx->ohci->card, packet->ack);
|
packet->callback(packet, &ctx->ohci->card, packet->ack);
|
||||||
|
}
|
||||||
|
|
||||||
offset =
|
offset =
|
||||||
((unsigned long long)
|
((unsigned long long)
|
||||||
|
@ -839,6 +841,11 @@ handle_local_request(struct context *ctx, struct fw_packet *packet)
|
||||||
fw_core_handle_response(&ctx->ohci->card, packet);
|
fw_core_handle_response(&ctx->ohci->card, packet);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ctx == &ctx->ohci->at_response_ctx) {
|
||||||
|
packet->ack = ACK_COMPLETE;
|
||||||
|
packet->callback(packet, &ctx->ohci->card, packet->ack);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
|
@ -163,11 +163,12 @@ static void update_hop_count(struct fw_node *node)
|
||||||
* internally consistent. On succcess this funtions returns the
|
* internally consistent. On succcess this funtions returns the
|
||||||
* fw_node corresponding to the local card otherwise NULL.
|
* fw_node corresponding to the local card otherwise NULL.
|
||||||
*/
|
*/
|
||||||
static struct fw_node *build_tree(struct fw_card *card)
|
static struct fw_node *build_tree(struct fw_card *card,
|
||||||
|
u32 *sid, int self_id_count)
|
||||||
{
|
{
|
||||||
struct fw_node *node, *child, *local_node;
|
struct fw_node *node, *child, *local_node;
|
||||||
struct list_head stack, *h;
|
struct list_head stack, *h;
|
||||||
u32 *sid, *next_sid, *end, q;
|
u32 *next_sid, *end, q;
|
||||||
int i, port_count, child_port_count, phy_id, parent_count, stack_depth;
|
int i, port_count, child_port_count, phy_id, parent_count, stack_depth;
|
||||||
int gap_count, topology_type;
|
int gap_count, topology_type;
|
||||||
|
|
||||||
|
@ -175,8 +176,7 @@ static struct fw_node *build_tree(struct fw_card *card)
|
||||||
node = NULL;
|
node = NULL;
|
||||||
INIT_LIST_HEAD(&stack);
|
INIT_LIST_HEAD(&stack);
|
||||||
stack_depth = 0;
|
stack_depth = 0;
|
||||||
sid = card->self_ids;
|
end = sid + self_id_count;
|
||||||
end = sid + card->self_id_count;
|
|
||||||
phy_id = 0;
|
phy_id = 0;
|
||||||
card->irm_node = NULL;
|
card->irm_node = NULL;
|
||||||
gap_count = self_id_gap_count(*sid);
|
gap_count = self_id_gap_count(*sid);
|
||||||
|
@ -460,6 +460,20 @@ update_tree(struct fw_card *card, struct fw_node *root)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
update_topology_map(struct fw_card *card, u32 *self_ids, int self_id_count)
|
||||||
|
{
|
||||||
|
int node_count;
|
||||||
|
u32 crc;
|
||||||
|
|
||||||
|
card->topology_map[1]++;
|
||||||
|
node_count = (card->root_node->node_id & 0x3f) + 1;
|
||||||
|
card->topology_map[2] = (node_count << 16) | self_id_count;
|
||||||
|
crc = crc16_itu_t(card->topology_map + 1, self_id_count + 2);
|
||||||
|
card->topology_map[0] = ((self_id_count + 2) << 16) | crc;
|
||||||
|
memcpy(&card->topology_map[3], self_ids, self_id_count * 4);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
fw_core_handle_bus_reset(struct fw_card *card,
|
fw_core_handle_bus_reset(struct fw_card *card,
|
||||||
int node_id, int generation,
|
int node_id, int generation,
|
||||||
|
@ -479,13 +493,13 @@ fw_core_handle_bus_reset(struct fw_card *card,
|
||||||
card->bm_retries = 0;
|
card->bm_retries = 0;
|
||||||
|
|
||||||
card->node_id = node_id;
|
card->node_id = node_id;
|
||||||
card->self_id_count = self_id_count;
|
|
||||||
card->generation = generation;
|
card->generation = generation;
|
||||||
memcpy(card->self_ids, self_ids, self_id_count * 4);
|
|
||||||
card->reset_jiffies = jiffies;
|
card->reset_jiffies = jiffies;
|
||||||
schedule_delayed_work(&card->work, 0);
|
schedule_delayed_work(&card->work, 0);
|
||||||
|
|
||||||
local_node = build_tree(card);
|
local_node = build_tree(card, self_ids, self_id_count);
|
||||||
|
|
||||||
|
update_topology_map(card, self_ids, self_id_count);
|
||||||
|
|
||||||
card->color++;
|
card->color++;
|
||||||
|
|
||||||
|
|
|
@ -88,4 +88,7 @@ fw_node_put(struct fw_node *node)
|
||||||
void
|
void
|
||||||
fw_destroy_nodes(struct fw_card *card);
|
fw_destroy_nodes(struct fw_card *card);
|
||||||
|
|
||||||
|
u16
|
||||||
|
crc16_itu_t(const u32 *buffer, size_t length);
|
||||||
|
|
||||||
#endif /* __fw_topology_h */
|
#endif /* __fw_topology_h */
|
||||||
|
|
|
@ -140,7 +140,7 @@ transmit_complete_callback(struct fw_packet *packet,
|
||||||
|
|
||||||
static void
|
static void
|
||||||
fw_fill_request(struct fw_packet *packet, int tcode, int tlabel,
|
fw_fill_request(struct fw_packet *packet, int tcode, int tlabel,
|
||||||
int node_id, int generation, int speed,
|
int node_id, int source_id, int generation, int speed,
|
||||||
unsigned long long offset, void *payload, size_t length)
|
unsigned long long offset, void *payload, size_t length)
|
||||||
{
|
{
|
||||||
int ext_tcode;
|
int ext_tcode;
|
||||||
|
@ -157,7 +157,7 @@ fw_fill_request(struct fw_packet *packet, int tcode, int tlabel,
|
||||||
header_tcode(tcode) |
|
header_tcode(tcode) |
|
||||||
header_destination(node_id);
|
header_destination(node_id);
|
||||||
packet->header[1] =
|
packet->header[1] =
|
||||||
header_offset_high(offset >> 32) | header_source(0);
|
header_offset_high(offset >> 32) | header_source(source_id);
|
||||||
packet->header[2] =
|
packet->header[2] =
|
||||||
offset;
|
offset;
|
||||||
|
|
||||||
|
@ -241,7 +241,7 @@ fw_send_request(struct fw_card *card, struct fw_transaction *t,
|
||||||
fw_transaction_callback_t callback, void *callback_data)
|
fw_transaction_callback_t callback, void *callback_data)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int tlabel;
|
int tlabel, source;
|
||||||
|
|
||||||
/* Bump the flush timer up 100ms first of all so we
|
/* Bump the flush timer up 100ms first of all so we
|
||||||
* don't race with a flush timer callback. */
|
* don't race with a flush timer callback. */
|
||||||
|
@ -253,6 +253,7 @@ fw_send_request(struct fw_card *card, struct fw_transaction *t,
|
||||||
|
|
||||||
spin_lock_irqsave(&card->lock, flags);
|
spin_lock_irqsave(&card->lock, flags);
|
||||||
|
|
||||||
|
source = card->node_id;
|
||||||
tlabel = card->current_tlabel;
|
tlabel = card->current_tlabel;
|
||||||
if (card->tlabel_mask & (1 << tlabel)) {
|
if (card->tlabel_mask & (1 << tlabel)) {
|
||||||
spin_unlock_irqrestore(&card->lock, flags);
|
spin_unlock_irqrestore(&card->lock, flags);
|
||||||
|
@ -274,7 +275,8 @@ fw_send_request(struct fw_card *card, struct fw_transaction *t,
|
||||||
t->callback_data = callback_data;
|
t->callback_data = callback_data;
|
||||||
|
|
||||||
fw_fill_request(&t->packet, tcode, t->tlabel,
|
fw_fill_request(&t->packet, tcode, t->tlabel,
|
||||||
node_id, generation, speed, offset, payload, length);
|
node_id, source, generation,
|
||||||
|
speed, offset, payload, length);
|
||||||
t->packet.callback = transmit_complete_callback;
|
t->packet.callback = transmit_complete_callback;
|
||||||
|
|
||||||
card->driver->send_request(card, &t->packet);
|
card->driver->send_request(card, &t->packet);
|
||||||
|
@ -716,6 +718,44 @@ fw_core_handle_response(struct fw_card *card, struct fw_packet *p)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(fw_core_handle_response);
|
EXPORT_SYMBOL(fw_core_handle_response);
|
||||||
|
|
||||||
|
const struct fw_address_region topology_map_region =
|
||||||
|
{ .start = 0xfffff0001000ull, .end = 0xfffff0001400ull, };
|
||||||
|
|
||||||
|
static void
|
||||||
|
handle_topology_map(struct fw_card *card, struct fw_request *request,
|
||||||
|
int tcode, int destination, int source,
|
||||||
|
int generation, int speed,
|
||||||
|
unsigned long long offset,
|
||||||
|
void *payload, size_t length, void *callback_data)
|
||||||
|
{
|
||||||
|
int i, start, end;
|
||||||
|
u32 *map;
|
||||||
|
|
||||||
|
if (!TCODE_IS_READ_REQUEST(tcode)) {
|
||||||
|
fw_send_response(card, request, RCODE_TYPE_ERROR);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((offset & 3) > 0 || (length & 3) > 0) {
|
||||||
|
fw_send_response(card, request, RCODE_ADDRESS_ERROR);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
start = (offset - topology_map_region.start) / 4;
|
||||||
|
end = start + length / 4;
|
||||||
|
map = payload;
|
||||||
|
|
||||||
|
for (i = 0; i < length / 4; i++)
|
||||||
|
map[i] = cpu_to_be32(card->topology_map[start + i]);
|
||||||
|
|
||||||
|
fw_send_response(card, request, RCODE_COMPLETE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct fw_address_handler topology_map = {
|
||||||
|
.length = 0x400,
|
||||||
|
.address_callback = handle_topology_map,
|
||||||
|
};
|
||||||
|
|
||||||
MODULE_AUTHOR("Kristian Hoegsberg <krh@bitplanet.net>");
|
MODULE_AUTHOR("Kristian Hoegsberg <krh@bitplanet.net>");
|
||||||
MODULE_DESCRIPTION("Core IEEE1394 transaction logic");
|
MODULE_DESCRIPTION("Core IEEE1394 transaction logic");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
@ -767,6 +807,10 @@ static int __init fw_core_init(void)
|
||||||
return fw_cdev_major;
|
return fw_cdev_major;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
retval = fw_core_add_address_handler(&topology_map,
|
||||||
|
&topology_map_region);
|
||||||
|
BUG_ON(retval < 0);
|
||||||
|
|
||||||
/* Add the vendor textual descriptor. */
|
/* Add the vendor textual descriptor. */
|
||||||
retval = fw_core_add_descriptor(&vendor_id_descriptor);
|
retval = fw_core_add_descriptor(&vendor_id_descriptor);
|
||||||
BUG_ON(retval < 0);
|
BUG_ON(retval < 0);
|
||||||
|
|
|
@ -285,9 +285,10 @@ struct fw_card {
|
||||||
int link_speed;
|
int link_speed;
|
||||||
int config_rom_generation;
|
int config_rom_generation;
|
||||||
|
|
||||||
/* We need to store up to 4 self ID for a maximum of 63 devices. */
|
/* We need to store up to 4 self ID for a maximum of 63
|
||||||
|
* devices plus 3 words for the topology map header. */
|
||||||
int self_id_count;
|
int self_id_count;
|
||||||
u32 self_ids[252];
|
u32 topology_map[252 + 3];
|
||||||
|
|
||||||
spinlock_t lock; /* Take this lock when handling the lists in
|
spinlock_t lock; /* Take this lock when handling the lists in
|
||||||
* this struct. */
|
* this struct. */
|
||||||
|
|
Loading…
Reference in New Issue