Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 473d28c7 authored by Kristian Høgsberg's avatar Kristian Høgsberg Committed by Stefan Richter
Browse files

firewire: Implement topology map and fix a couple of loopback bugs.

parent 7c6e647d
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -30,7 +30,7 @@
 * polynomial, but we need the ITU-T (or CCITT) polynomial (0x1021).
 * The implementation below works on an array of host-endian u32
 * words, assuming they'll be transmited msb first. */
static u16
u16
crc16_itu_t(const u32 *buffer, size_t length)
{
	int shift, i;
+9 −2
Original line number Diff line number Diff line
@@ -813,8 +813,10 @@ handle_local_request(struct context *ctx, struct fw_packet *packet)
	u64 offset;
	u32 csr;

	if (ctx == &ctx->ohci->at_request_ctx) {
		packet->ack = ACK_PENDING;
		packet->callback(packet, &ctx->ohci->card, packet->ack);
	}

	offset =
		((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);
		break;
	}

	if (ctx == &ctx->ohci->at_response_ctx) {
		packet->ack = ACK_COMPLETE;
		packet->callback(packet, &ctx->ohci->card, packet->ack);
	}
}

static void
+21 −7
Original line number Diff line number Diff line
@@ -163,11 +163,12 @@ static void update_hop_count(struct fw_node *node)
 * internally consistent.  On succcess this funtions returns the
 * 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 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 gap_count, topology_type;

@@ -175,8 +176,7 @@ static struct fw_node *build_tree(struct fw_card *card)
	node = NULL;
	INIT_LIST_HEAD(&stack);
	stack_depth = 0;
	sid = card->self_ids;
	end = sid + card->self_id_count;
	end = sid + self_id_count;
	phy_id = 0;
	card->irm_node = NULL;
	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
fw_core_handle_bus_reset(struct fw_card *card,
			 int node_id, int generation,
@@ -479,13 +493,13 @@ fw_core_handle_bus_reset(struct fw_card *card,
		card->bm_retries = 0;

	card->node_id = node_id;
	card->self_id_count = self_id_count;
	card->generation = generation;
	memcpy(card->self_ids, self_ids, self_id_count * 4);
	card->reset_jiffies = jiffies;
	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++;

+3 −0
Original line number Diff line number Diff line
@@ -88,4 +88,7 @@ fw_node_put(struct fw_node *node)
void
fw_destroy_nodes(struct fw_card *card);

u16
crc16_itu_t(const u32 *buffer, size_t length);

#endif /* __fw_topology_h */
+48 −4
Original line number Diff line number Diff line
@@ -140,7 +140,7 @@ transmit_complete_callback(struct fw_packet *packet,

static void
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)
{
	int ext_tcode;
@@ -157,7 +157,7 @@ fw_fill_request(struct fw_packet *packet, int tcode, int tlabel,
		header_tcode(tcode) |
		header_destination(node_id);
	packet->header[1] =
		header_offset_high(offset >> 32) | header_source(0);
		header_offset_high(offset >> 32) | header_source(source_id);
	packet->header[2] =
		offset;

@@ -241,7 +241,7 @@ fw_send_request(struct fw_card *card, struct fw_transaction *t,
		fw_transaction_callback_t callback, void *callback_data)
{
	unsigned long flags;
	int tlabel;
	int tlabel, source;

	/* Bump the flush timer up 100ms first of all so we
	 * 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);

	source = card->node_id;
	tlabel = card->current_tlabel;
	if (card->tlabel_mask & (1 << tlabel)) {
		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;

	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;

	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);

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_DESCRIPTION("Core IEEE1394 transaction logic");
MODULE_LICENSE("GPL");
@@ -767,6 +807,10 @@ static int __init fw_core_init(void)
		return fw_cdev_major;
	}

	retval = fw_core_add_address_handler(&topology_map,
					     &topology_map_region);
	BUG_ON(retval < 0);

	/* Add the vendor textual descriptor. */
	retval = fw_core_add_descriptor(&vendor_id_descriptor);
	BUG_ON(retval < 0);
Loading