xref: /openbmc/linux/drivers/firewire/core-transaction.c (revision 2612e3bbc0386368a850140a6c9b990cd496a5ec)
11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2e71d31daSStefan Richter /*
3e71d31daSStefan Richter  * Core IEEE1394 transaction logic
4e71d31daSStefan Richter  *
5e71d31daSStefan Richter  * Copyright (C) 2004-2006 Kristian Hoegsberg <krh@bitplanet.net>
6e71d31daSStefan Richter  */
7e71d31daSStefan Richter 
8e71d31daSStefan Richter #include <linux/bug.h>
9e71d31daSStefan Richter #include <linux/completion.h>
10e71d31daSStefan Richter #include <linux/device.h>
11e71d31daSStefan Richter #include <linux/errno.h>
12e71d31daSStefan Richter #include <linux/firewire.h>
13e71d31daSStefan Richter #include <linux/firewire-constants.h>
14e71d31daSStefan Richter #include <linux/fs.h>
15e71d31daSStefan Richter #include <linux/init.h>
16e71d31daSStefan Richter #include <linux/idr.h>
17e71d31daSStefan Richter #include <linux/jiffies.h>
18e71d31daSStefan Richter #include <linux/kernel.h>
19e71d31daSStefan Richter #include <linux/list.h>
20e71d31daSStefan Richter #include <linux/module.h>
2135202f7dSPeter Hurley #include <linux/rculist.h>
22e71d31daSStefan Richter #include <linux/slab.h>
23e71d31daSStefan Richter #include <linux/spinlock.h>
24e71d31daSStefan Richter #include <linux/string.h>
25e71d31daSStefan Richter #include <linux/timer.h>
26e71d31daSStefan Richter #include <linux/types.h>
276ea9e7bbSStefan Richter #include <linux/workqueue.h>
28e71d31daSStefan Richter 
29e71d31daSStefan Richter #include <asm/byteorder.h>
30e71d31daSStefan Richter 
31e71d31daSStefan Richter #include "core.h"
32e71d31daSStefan Richter 
33e71d31daSStefan Richter #define HEADER_PRI(pri)			((pri) << 0)
34e71d31daSStefan Richter #define HEADER_TCODE(tcode)		((tcode) << 4)
35e71d31daSStefan Richter #define HEADER_RETRY(retry)		((retry) << 8)
36e71d31daSStefan Richter #define HEADER_TLABEL(tlabel)		((tlabel) << 10)
37e71d31daSStefan Richter #define HEADER_DESTINATION(destination)	((destination) << 16)
38e71d31daSStefan Richter #define HEADER_SOURCE(source)		((source) << 16)
39e71d31daSStefan Richter #define HEADER_RCODE(rcode)		((rcode) << 12)
40e71d31daSStefan Richter #define HEADER_OFFSET_HIGH(offset_high)	((offset_high) << 0)
41e71d31daSStefan Richter #define HEADER_DATA_LENGTH(length)	((length) << 16)
42e71d31daSStefan Richter #define HEADER_EXTENDED_TCODE(tcode)	((tcode) << 0)
43e71d31daSStefan Richter 
44e71d31daSStefan Richter #define HEADER_GET_TCODE(q)		(((q) >> 4) & 0x0f)
45e71d31daSStefan Richter #define HEADER_GET_TLABEL(q)		(((q) >> 10) & 0x3f)
46e71d31daSStefan Richter #define HEADER_GET_RCODE(q)		(((q) >> 12) & 0x0f)
47e71d31daSStefan Richter #define HEADER_GET_DESTINATION(q)	(((q) >> 16) & 0xffff)
48e71d31daSStefan Richter #define HEADER_GET_SOURCE(q)		(((q) >> 16) & 0xffff)
49e71d31daSStefan Richter #define HEADER_GET_OFFSET_HIGH(q)	(((q) >> 0) & 0xffff)
50e71d31daSStefan Richter #define HEADER_GET_DATA_LENGTH(q)	(((q) >> 16) & 0xffff)
51e71d31daSStefan Richter #define HEADER_GET_EXTENDED_TCODE(q)	(((q) >> 0) & 0xffff)
52e71d31daSStefan Richter 
53e71d31daSStefan Richter #define HEADER_DESTINATION_IS_BROADCAST(q) \
54e71d31daSStefan Richter 	(((q) & HEADER_DESTINATION(0x3f)) == HEADER_DESTINATION(0x3f))
55e71d31daSStefan Richter 
56e71d31daSStefan Richter #define PHY_PACKET_CONFIG	0x0
57e71d31daSStefan Richter #define PHY_PACKET_LINK_ON	0x1
58e71d31daSStefan Richter #define PHY_PACKET_SELF_ID	0x2
59e71d31daSStefan Richter 
60e71d31daSStefan Richter #define PHY_CONFIG_GAP_COUNT(gap_count)	(((gap_count) << 16) | (1 << 22))
61e71d31daSStefan Richter #define PHY_CONFIG_ROOT_ID(node_id)	((((node_id) & 0x3f) << 24) | (1 << 23))
62e71d31daSStefan Richter #define PHY_IDENTIFIER(id)		((id) << 30)
63e71d31daSStefan Richter 
64410cf2bdSClemens Ladisch /* returns 0 if the split timeout handler is already running */
try_cancel_split_timeout(struct fw_transaction * t)65410cf2bdSClemens Ladisch static int try_cancel_split_timeout(struct fw_transaction *t)
66410cf2bdSClemens Ladisch {
67410cf2bdSClemens Ladisch 	if (t->is_split_transaction)
68410cf2bdSClemens Ladisch 		return del_timer(&t->split_timeout_timer);
69410cf2bdSClemens Ladisch 	else
70410cf2bdSClemens Ladisch 		return 1;
71410cf2bdSClemens Ladisch }
72410cf2bdSClemens Ladisch 
close_transaction(struct fw_transaction * transaction,struct fw_card * card,int rcode,u32 response_tstamp)73dcadfd7fSTakashi Sakamoto static int close_transaction(struct fw_transaction *transaction, struct fw_card *card, int rcode,
74dcadfd7fSTakashi Sakamoto 			     u32 response_tstamp)
75e71d31daSStefan Richter {
7694239738SJakob Koschel 	struct fw_transaction *t = NULL, *iter;
77e71d31daSStefan Richter 	unsigned long flags;
78e71d31daSStefan Richter 
79e71d31daSStefan Richter 	spin_lock_irqsave(&card->lock, flags);
8094239738SJakob Koschel 	list_for_each_entry(iter, &card->transaction_list, link) {
8194239738SJakob Koschel 		if (iter == transaction) {
8294239738SJakob Koschel 			if (!try_cancel_split_timeout(iter)) {
832222bcb7SClemens Ladisch 				spin_unlock_irqrestore(&card->lock, flags);
842222bcb7SClemens Ladisch 				goto timed_out;
852222bcb7SClemens Ladisch 			}
8694239738SJakob Koschel 			list_del_init(&iter->link);
8794239738SJakob Koschel 			card->tlabel_mask &= ~(1ULL << iter->tlabel);
8894239738SJakob Koschel 			t = iter;
89e71d31daSStefan Richter 			break;
90e71d31daSStefan Richter 		}
91e71d31daSStefan Richter 	}
92e71d31daSStefan Richter 	spin_unlock_irqrestore(&card->lock, flags);
93e71d31daSStefan Richter 
9494239738SJakob Koschel 	if (t) {
95dcadfd7fSTakashi Sakamoto 		if (!t->with_tstamp) {
96dcadfd7fSTakashi Sakamoto 			t->callback.without_tstamp(card, rcode, NULL, 0, t->callback_data);
97dcadfd7fSTakashi Sakamoto 		} else {
98dcadfd7fSTakashi Sakamoto 			t->callback.with_tstamp(card, rcode, t->packet.timestamp, response_tstamp,
99dcadfd7fSTakashi Sakamoto 						NULL, 0, t->callback_data);
100dcadfd7fSTakashi Sakamoto 		}
101e71d31daSStefan Richter 		return 0;
102e71d31daSStefan Richter 	}
103e71d31daSStefan Richter 
1042222bcb7SClemens Ladisch  timed_out:
105e71d31daSStefan Richter 	return -ENOENT;
106e71d31daSStefan Richter }
107e71d31daSStefan Richter 
108e71d31daSStefan Richter /*
109e71d31daSStefan Richter  * Only valid for transactions that are potentially pending (ie have
110e71d31daSStefan Richter  * been sent).
111e71d31daSStefan Richter  */
fw_cancel_transaction(struct fw_card * card,struct fw_transaction * transaction)112e71d31daSStefan Richter int fw_cancel_transaction(struct fw_card *card,
113e71d31daSStefan Richter 			  struct fw_transaction *transaction)
114e71d31daSStefan Richter {
115dcadfd7fSTakashi Sakamoto 	u32 tstamp;
116dcadfd7fSTakashi Sakamoto 
117e71d31daSStefan Richter 	/*
118e71d31daSStefan Richter 	 * Cancel the packet transmission if it's still queued.  That
119e71d31daSStefan Richter 	 * will call the packet transmission callback which cancels
120e71d31daSStefan Richter 	 * the transaction.
121e71d31daSStefan Richter 	 */
122e71d31daSStefan Richter 
123e71d31daSStefan Richter 	if (card->driver->cancel_packet(card, &transaction->packet) == 0)
124e71d31daSStefan Richter 		return 0;
125e71d31daSStefan Richter 
126e71d31daSStefan Richter 	/*
127e71d31daSStefan Richter 	 * If the request packet has already been sent, we need to see
128e71d31daSStefan Richter 	 * if the transaction is still pending and remove it in that case.
129e71d31daSStefan Richter 	 */
130e71d31daSStefan Richter 
131dcadfd7fSTakashi Sakamoto 	if (transaction->packet.ack == 0) {
132dcadfd7fSTakashi Sakamoto 		// The timestamp is reused since it was just read now.
133dcadfd7fSTakashi Sakamoto 		tstamp = transaction->packet.timestamp;
134dcadfd7fSTakashi Sakamoto 	} else {
135dcadfd7fSTakashi Sakamoto 		u32 curr_cycle_time = 0;
136dcadfd7fSTakashi Sakamoto 
137dcadfd7fSTakashi Sakamoto 		(void)fw_card_read_cycle_time(card, &curr_cycle_time);
138dcadfd7fSTakashi Sakamoto 		tstamp = cycle_time_to_ohci_tstamp(curr_cycle_time);
139dcadfd7fSTakashi Sakamoto 	}
140dcadfd7fSTakashi Sakamoto 
141dcadfd7fSTakashi Sakamoto 	return close_transaction(transaction, card, RCODE_CANCELLED, tstamp);
142e71d31daSStefan Richter }
143e71d31daSStefan Richter EXPORT_SYMBOL(fw_cancel_transaction);
144e71d31daSStefan Richter 
split_transaction_timeout_callback(struct timer_list * timer)1459c6c273aSKees Cook static void split_transaction_timeout_callback(struct timer_list *timer)
1465c40cbfeSClemens Ladisch {
1479c6c273aSKees Cook 	struct fw_transaction *t = from_timer(t, timer, split_timeout_timer);
1485c40cbfeSClemens Ladisch 	struct fw_card *card = t->card;
1495c40cbfeSClemens Ladisch 	unsigned long flags;
1505c40cbfeSClemens Ladisch 
1515c40cbfeSClemens Ladisch 	spin_lock_irqsave(&card->lock, flags);
1525c40cbfeSClemens Ladisch 	if (list_empty(&t->link)) {
1535c40cbfeSClemens Ladisch 		spin_unlock_irqrestore(&card->lock, flags);
1545c40cbfeSClemens Ladisch 		return;
1555c40cbfeSClemens Ladisch 	}
1565c40cbfeSClemens Ladisch 	list_del(&t->link);
1575c40cbfeSClemens Ladisch 	card->tlabel_mask &= ~(1ULL << t->tlabel);
1585c40cbfeSClemens Ladisch 	spin_unlock_irqrestore(&card->lock, flags);
1595c40cbfeSClemens Ladisch 
160dcadfd7fSTakashi Sakamoto 	if (!t->with_tstamp) {
161dcadfd7fSTakashi Sakamoto 		t->callback.without_tstamp(card, RCODE_CANCELLED, NULL, 0, t->callback_data);
162dcadfd7fSTakashi Sakamoto 	} else {
163dcadfd7fSTakashi Sakamoto 		t->callback.with_tstamp(card, RCODE_CANCELLED, t->packet.timestamp,
164dcadfd7fSTakashi Sakamoto 					t->split_timeout_cycle, NULL, 0, t->callback_data);
165dcadfd7fSTakashi Sakamoto 	}
1665c40cbfeSClemens Ladisch }
1675c40cbfeSClemens Ladisch 
start_split_transaction_timeout(struct fw_transaction * t,struct fw_card * card)168410cf2bdSClemens Ladisch static void start_split_transaction_timeout(struct fw_transaction *t,
169410cf2bdSClemens Ladisch 					    struct fw_card *card)
170410cf2bdSClemens Ladisch {
171410cf2bdSClemens Ladisch 	unsigned long flags;
172410cf2bdSClemens Ladisch 
173410cf2bdSClemens Ladisch 	spin_lock_irqsave(&card->lock, flags);
174410cf2bdSClemens Ladisch 
175410cf2bdSClemens Ladisch 	if (list_empty(&t->link) || WARN_ON(t->is_split_transaction)) {
176410cf2bdSClemens Ladisch 		spin_unlock_irqrestore(&card->lock, flags);
177410cf2bdSClemens Ladisch 		return;
178410cf2bdSClemens Ladisch 	}
179410cf2bdSClemens Ladisch 
180410cf2bdSClemens Ladisch 	t->is_split_transaction = true;
181410cf2bdSClemens Ladisch 	mod_timer(&t->split_timeout_timer,
182410cf2bdSClemens Ladisch 		  jiffies + card->split_timeout_jiffies);
183410cf2bdSClemens Ladisch 
184410cf2bdSClemens Ladisch 	spin_unlock_irqrestore(&card->lock, flags);
185410cf2bdSClemens Ladisch }
186410cf2bdSClemens Ladisch 
187dcadfd7fSTakashi Sakamoto static u32 compute_split_timeout_timestamp(struct fw_card *card, u32 request_timestamp);
188dcadfd7fSTakashi Sakamoto 
transmit_complete_callback(struct fw_packet * packet,struct fw_card * card,int status)189e71d31daSStefan Richter static void transmit_complete_callback(struct fw_packet *packet,
190e71d31daSStefan Richter 				       struct fw_card *card, int status)
191e71d31daSStefan Richter {
192e71d31daSStefan Richter 	struct fw_transaction *t =
193e71d31daSStefan Richter 	    container_of(packet, struct fw_transaction, packet);
194e71d31daSStefan Richter 
195e71d31daSStefan Richter 	switch (status) {
196e71d31daSStefan Richter 	case ACK_COMPLETE:
197dcadfd7fSTakashi Sakamoto 		close_transaction(t, card, RCODE_COMPLETE, packet->timestamp);
198e71d31daSStefan Richter 		break;
199e71d31daSStefan Richter 	case ACK_PENDING:
200dcadfd7fSTakashi Sakamoto 	{
201dcadfd7fSTakashi Sakamoto 		t->split_timeout_cycle =
202dcadfd7fSTakashi Sakamoto 			compute_split_timeout_timestamp(card, packet->timestamp) & 0xffff;
203410cf2bdSClemens Ladisch 		start_split_transaction_timeout(t, card);
204e71d31daSStefan Richter 		break;
205dcadfd7fSTakashi Sakamoto 	}
206e71d31daSStefan Richter 	case ACK_BUSY_X:
207e71d31daSStefan Richter 	case ACK_BUSY_A:
208e71d31daSStefan Richter 	case ACK_BUSY_B:
209dcadfd7fSTakashi Sakamoto 		close_transaction(t, card, RCODE_BUSY, packet->timestamp);
210e71d31daSStefan Richter 		break;
211e71d31daSStefan Richter 	case ACK_DATA_ERROR:
212dcadfd7fSTakashi Sakamoto 		close_transaction(t, card, RCODE_DATA_ERROR, packet->timestamp);
213e71d31daSStefan Richter 		break;
214e71d31daSStefan Richter 	case ACK_TYPE_ERROR:
215dcadfd7fSTakashi Sakamoto 		close_transaction(t, card, RCODE_TYPE_ERROR, packet->timestamp);
216e71d31daSStefan Richter 		break;
217e71d31daSStefan Richter 	default:
218e71d31daSStefan Richter 		/*
219e71d31daSStefan Richter 		 * In this case the ack is really a juju specific
220e71d31daSStefan Richter 		 * rcode, so just forward that to the callback.
221e71d31daSStefan Richter 		 */
222dcadfd7fSTakashi Sakamoto 		close_transaction(t, card, status, packet->timestamp);
223e71d31daSStefan Richter 		break;
224e71d31daSStefan Richter 	}
225e71d31daSStefan Richter }
226e71d31daSStefan Richter 
fw_fill_request(struct fw_packet * packet,int tcode,int tlabel,int destination_id,int source_id,int generation,int speed,unsigned long long offset,void * payload,size_t length)227e71d31daSStefan Richter static void fw_fill_request(struct fw_packet *packet, int tcode, int tlabel,
228e71d31daSStefan Richter 		int destination_id, int source_id, int generation, int speed,
229e71d31daSStefan Richter 		unsigned long long offset, void *payload, size_t length)
230e71d31daSStefan Richter {
231e71d31daSStefan Richter 	int ext_tcode;
232e71d31daSStefan Richter 
233e71d31daSStefan Richter 	if (tcode == TCODE_STREAM_DATA) {
234e71d31daSStefan Richter 		packet->header[0] =
235e71d31daSStefan Richter 			HEADER_DATA_LENGTH(length) |
236e71d31daSStefan Richter 			destination_id |
237e71d31daSStefan Richter 			HEADER_TCODE(TCODE_STREAM_DATA);
238e71d31daSStefan Richter 		packet->header_length = 4;
239e71d31daSStefan Richter 		packet->payload = payload;
240e71d31daSStefan Richter 		packet->payload_length = length;
241e71d31daSStefan Richter 
242e71d31daSStefan Richter 		goto common;
243e71d31daSStefan Richter 	}
244e71d31daSStefan Richter 
245e71d31daSStefan Richter 	if (tcode > 0x10) {
246e71d31daSStefan Richter 		ext_tcode = tcode & ~0x10;
247e71d31daSStefan Richter 		tcode = TCODE_LOCK_REQUEST;
248e71d31daSStefan Richter 	} else
249e71d31daSStefan Richter 		ext_tcode = 0;
250e71d31daSStefan Richter 
251e71d31daSStefan Richter 	packet->header[0] =
252e71d31daSStefan Richter 		HEADER_RETRY(RETRY_X) |
253e71d31daSStefan Richter 		HEADER_TLABEL(tlabel) |
254e71d31daSStefan Richter 		HEADER_TCODE(tcode) |
255e71d31daSStefan Richter 		HEADER_DESTINATION(destination_id);
256e71d31daSStefan Richter 	packet->header[1] =
257e71d31daSStefan Richter 		HEADER_OFFSET_HIGH(offset >> 32) | HEADER_SOURCE(source_id);
258e71d31daSStefan Richter 	packet->header[2] =
259e71d31daSStefan Richter 		offset;
260e71d31daSStefan Richter 
261e71d31daSStefan Richter 	switch (tcode) {
262e71d31daSStefan Richter 	case TCODE_WRITE_QUADLET_REQUEST:
263e71d31daSStefan Richter 		packet->header[3] = *(u32 *)payload;
264e71d31daSStefan Richter 		packet->header_length = 16;
265e71d31daSStefan Richter 		packet->payload_length = 0;
266e71d31daSStefan Richter 		break;
267e71d31daSStefan Richter 
268e71d31daSStefan Richter 	case TCODE_LOCK_REQUEST:
269e71d31daSStefan Richter 	case TCODE_WRITE_BLOCK_REQUEST:
270e71d31daSStefan Richter 		packet->header[3] =
271e71d31daSStefan Richter 			HEADER_DATA_LENGTH(length) |
272e71d31daSStefan Richter 			HEADER_EXTENDED_TCODE(ext_tcode);
273e71d31daSStefan Richter 		packet->header_length = 16;
274e71d31daSStefan Richter 		packet->payload = payload;
275e71d31daSStefan Richter 		packet->payload_length = length;
276e71d31daSStefan Richter 		break;
277e71d31daSStefan Richter 
278e71d31daSStefan Richter 	case TCODE_READ_QUADLET_REQUEST:
279e71d31daSStefan Richter 		packet->header_length = 12;
280e71d31daSStefan Richter 		packet->payload_length = 0;
281e71d31daSStefan Richter 		break;
282e71d31daSStefan Richter 
283e71d31daSStefan Richter 	case TCODE_READ_BLOCK_REQUEST:
284e71d31daSStefan Richter 		packet->header[3] =
285e71d31daSStefan Richter 			HEADER_DATA_LENGTH(length) |
286e71d31daSStefan Richter 			HEADER_EXTENDED_TCODE(ext_tcode);
287e71d31daSStefan Richter 		packet->header_length = 16;
288e71d31daSStefan Richter 		packet->payload_length = 0;
289e71d31daSStefan Richter 		break;
2905b189bf3SStefan Richter 
2915b189bf3SStefan Richter 	default:
2925878730bSJoe Perches 		WARN(1, "wrong tcode %d\n", tcode);
293e71d31daSStefan Richter 	}
294e71d31daSStefan Richter  common:
295e71d31daSStefan Richter 	packet->speed = speed;
296e71d31daSStefan Richter 	packet->generation = generation;
297e71d31daSStefan Richter 	packet->ack = 0;
29819593ffdSStefan Richter 	packet->payload_mapped = false;
299e71d31daSStefan Richter }
300e71d31daSStefan Richter 
allocate_tlabel(struct fw_card * card)3017906054fSClemens Ladisch static int allocate_tlabel(struct fw_card *card)
3027906054fSClemens Ladisch {
3037906054fSClemens Ladisch 	int tlabel;
3047906054fSClemens Ladisch 
3057906054fSClemens Ladisch 	tlabel = card->current_tlabel;
3067906054fSClemens Ladisch 	while (card->tlabel_mask & (1ULL << tlabel)) {
3077906054fSClemens Ladisch 		tlabel = (tlabel + 1) & 0x3f;
3087906054fSClemens Ladisch 		if (tlabel == card->current_tlabel)
3097906054fSClemens Ladisch 			return -EBUSY;
3107906054fSClemens Ladisch 	}
3117906054fSClemens Ladisch 
3127906054fSClemens Ladisch 	card->current_tlabel = (tlabel + 1) & 0x3f;
3137906054fSClemens Ladisch 	card->tlabel_mask |= 1ULL << tlabel;
3147906054fSClemens Ladisch 
3157906054fSClemens Ladisch 	return tlabel;
3167906054fSClemens Ladisch }
3177906054fSClemens Ladisch 
318e71d31daSStefan Richter /**
319*39ce342cSTakashi Sakamoto  * __fw_send_request() - submit a request packet for transmission to generate callback for response
320*39ce342cSTakashi Sakamoto  *			 subaction with or without time stamp.
321656b7afdSStefan Richter  * @card:		interface to send the request at
322656b7afdSStefan Richter  * @t:			transaction instance to which the request belongs
323656b7afdSStefan Richter  * @tcode:		transaction code
324656b7afdSStefan Richter  * @destination_id:	destination node ID, consisting of bus_ID and phy_ID
325656b7afdSStefan Richter  * @generation:		bus generation in which request and response are valid
326656b7afdSStefan Richter  * @speed:		transmission speed
327656b7afdSStefan Richter  * @offset:		48bit wide offset into destination's address space
328656b7afdSStefan Richter  * @payload:		data payload for the request subaction
329656b7afdSStefan Richter  * @length:		length of the payload, in bytes
330*39ce342cSTakashi Sakamoto  * @callback:		union of two functions whether to receive time stamp or not for response
331*39ce342cSTakashi Sakamoto  *			subaction.
332*39ce342cSTakashi Sakamoto  * @with_tstamp:	Whether to receive time stamp or not for response subaction.
333656b7afdSStefan Richter  * @callback_data:	data to be passed to the transaction completion callback
334e71d31daSStefan Richter  *
335656b7afdSStefan Richter  * Submit a request packet into the asynchronous request transmission queue.
336656b7afdSStefan Richter  * Can be called from atomic context.  If you prefer a blocking API, use
337656b7afdSStefan Richter  * fw_run_transaction() in a context that can sleep.
338e71d31daSStefan Richter  *
339656b7afdSStefan Richter  * In case of lock requests, specify one of the firewire-core specific %TCODE_
340656b7afdSStefan Richter  * constants instead of %TCODE_LOCK_REQUEST in @tcode.
341e71d31daSStefan Richter  *
342656b7afdSStefan Richter  * Make sure that the value in @destination_id is not older than the one in
343656b7afdSStefan Richter  * @generation.  Otherwise the request is in danger to be sent to a wrong node.
344e71d31daSStefan Richter  *
345656b7afdSStefan Richter  * In case of asynchronous stream packets i.e. %TCODE_STREAM_DATA, the caller
346e71d31daSStefan Richter  * needs to synthesize @destination_id with fw_stream_packet_destination_id().
347656b7afdSStefan Richter  * It will contain tag, channel, and sy data instead of a node ID then.
348656b7afdSStefan Richter  *
349656b7afdSStefan Richter  * The payload buffer at @data is going to be DMA-mapped except in case of
350f30e6d3eSStefan Richter  * @length <= 8 or of local (loopback) requests.  Hence make sure that the
351f30e6d3eSStefan Richter  * buffer complies with the restrictions of the streaming DMA mapping API.
352656b7afdSStefan Richter  * @payload must not be freed before the @callback is called.
353656b7afdSStefan Richter  *
354656b7afdSStefan Richter  * In case of request types without payload, @data is NULL and @length is 0.
355656b7afdSStefan Richter  *
356656b7afdSStefan Richter  * After the transaction is completed successfully or unsuccessfully, the
357656b7afdSStefan Richter  * @callback will be called.  Among its parameters is the response code which
358656b7afdSStefan Richter  * is either one of the rcodes per IEEE 1394 or, in case of internal errors,
35918d0cdfdSStefan Richter  * the firewire-core specific %RCODE_SEND_ERROR.  The other firewire-core
36018d0cdfdSStefan Richter  * specific rcodes (%RCODE_CANCELLED, %RCODE_BUSY, %RCODE_GENERATION,
36118d0cdfdSStefan Richter  * %RCODE_NO_ACK) denote transaction timeout, busy responder, stale request
36218d0cdfdSStefan Richter  * generation, or missing ACK respectively.
363656b7afdSStefan Richter  *
364656b7afdSStefan Richter  * Note some timing corner cases:  fw_send_request() may complete much earlier
365656b7afdSStefan Richter  * than when the request packet actually hits the wire.  On the other hand,
366656b7afdSStefan Richter  * transaction completion and hence execution of @callback may happen even
367656b7afdSStefan Richter  * before fw_send_request() returns.
368e71d31daSStefan Richter  */
__fw_send_request(struct fw_card * card,struct fw_transaction * t,int tcode,int destination_id,int generation,int speed,unsigned long long offset,void * payload,size_t length,union fw_transaction_callback callback,bool with_tstamp,void * callback_data)369*39ce342cSTakashi Sakamoto void __fw_send_request(struct fw_card *card, struct fw_transaction *t, int tcode,
370*39ce342cSTakashi Sakamoto 		int destination_id, int generation, int speed, unsigned long long offset,
371*39ce342cSTakashi Sakamoto 		void *payload, size_t length, union fw_transaction_callback callback,
372*39ce342cSTakashi Sakamoto 		bool with_tstamp, void *callback_data)
373e71d31daSStefan Richter {
374e71d31daSStefan Richter 	unsigned long flags;
375e71d31daSStefan Richter 	int tlabel;
376e71d31daSStefan Richter 
377e71d31daSStefan Richter 	/*
378e71d31daSStefan Richter 	 * Allocate tlabel from the bitmap and put the transaction on
379e71d31daSStefan Richter 	 * the list while holding the card spinlock.
380e71d31daSStefan Richter 	 */
381e71d31daSStefan Richter 
382e71d31daSStefan Richter 	spin_lock_irqsave(&card->lock, flags);
383e71d31daSStefan Richter 
3847906054fSClemens Ladisch 	tlabel = allocate_tlabel(card);
3857906054fSClemens Ladisch 	if (tlabel < 0) {
386e71d31daSStefan Richter 		spin_unlock_irqrestore(&card->lock, flags);
387*39ce342cSTakashi Sakamoto 		if (!with_tstamp) {
388*39ce342cSTakashi Sakamoto 			callback.without_tstamp(card, RCODE_SEND_ERROR, NULL, 0, callback_data);
389*39ce342cSTakashi Sakamoto 		} else {
390*39ce342cSTakashi Sakamoto 			// Timestamping on behalf of hardware.
391*39ce342cSTakashi Sakamoto 			u32 curr_cycle_time = 0;
392*39ce342cSTakashi Sakamoto 			u32 tstamp;
393*39ce342cSTakashi Sakamoto 
394*39ce342cSTakashi Sakamoto 			(void)fw_card_read_cycle_time(card, &curr_cycle_time);
395*39ce342cSTakashi Sakamoto 			tstamp = cycle_time_to_ohci_tstamp(curr_cycle_time);
396*39ce342cSTakashi Sakamoto 
397*39ce342cSTakashi Sakamoto 			callback.with_tstamp(card, RCODE_SEND_ERROR, tstamp, tstamp, NULL, 0,
398*39ce342cSTakashi Sakamoto 					     callback_data);
399*39ce342cSTakashi Sakamoto 		}
400e71d31daSStefan Richter 		return;
401e71d31daSStefan Richter 	}
402e71d31daSStefan Richter 
403e71d31daSStefan Richter 	t->node_id = destination_id;
404e71d31daSStefan Richter 	t->tlabel = tlabel;
4055c40cbfeSClemens Ladisch 	t->card = card;
406410cf2bdSClemens Ladisch 	t->is_split_transaction = false;
407*39ce342cSTakashi Sakamoto 	timer_setup(&t->split_timeout_timer, split_transaction_timeout_callback, 0);
408*39ce342cSTakashi Sakamoto 	t->callback = callback;
409*39ce342cSTakashi Sakamoto 	t->with_tstamp = with_tstamp;
410e71d31daSStefan Richter 	t->callback_data = callback_data;
411e71d31daSStefan Richter 
412*39ce342cSTakashi Sakamoto 	fw_fill_request(&t->packet, tcode, t->tlabel, destination_id, card->node_id, generation,
413e71d31daSStefan Richter 			speed, offset, payload, length);
414e71d31daSStefan Richter 	t->packet.callback = transmit_complete_callback;
415e71d31daSStefan Richter 
416e71d31daSStefan Richter 	list_add_tail(&t->link, &card->transaction_list);
417e71d31daSStefan Richter 
418e71d31daSStefan Richter 	spin_unlock_irqrestore(&card->lock, flags);
419e71d31daSStefan Richter 
420e71d31daSStefan Richter 	card->driver->send_request(card, &t->packet);
421e71d31daSStefan Richter }
422*39ce342cSTakashi Sakamoto EXPORT_SYMBOL_GPL(__fw_send_request);
423e71d31daSStefan Richter 
424e71d31daSStefan Richter struct transaction_callback_data {
425e71d31daSStefan Richter 	struct completion done;
426e71d31daSStefan Richter 	void *payload;
427e71d31daSStefan Richter 	int rcode;
428e71d31daSStefan Richter };
429e71d31daSStefan Richter 
transaction_callback(struct fw_card * card,int rcode,void * payload,size_t length,void * data)430e71d31daSStefan Richter static void transaction_callback(struct fw_card *card, int rcode,
431e71d31daSStefan Richter 				 void *payload, size_t length, void *data)
432e71d31daSStefan Richter {
433e71d31daSStefan Richter 	struct transaction_callback_data *d = data;
434e71d31daSStefan Richter 
435e71d31daSStefan Richter 	if (rcode == RCODE_COMPLETE)
436e71d31daSStefan Richter 		memcpy(d->payload, payload, length);
437e71d31daSStefan Richter 	d->rcode = rcode;
438e71d31daSStefan Richter 	complete(&d->done);
439e71d31daSStefan Richter }
440e71d31daSStefan Richter 
441e71d31daSStefan Richter /**
442656b7afdSStefan Richter  * fw_run_transaction() - send request and sleep until transaction is completed
443226b18adSRandy Dunlap  * @card:		card interface for this request
444226b18adSRandy Dunlap  * @tcode:		transaction code
445226b18adSRandy Dunlap  * @destination_id:	destination node ID, consisting of bus_ID and phy_ID
446226b18adSRandy Dunlap  * @generation:		bus generation in which request and response are valid
447226b18adSRandy Dunlap  * @speed:		transmission speed
448226b18adSRandy Dunlap  * @offset:		48bit wide offset into destination's address space
449226b18adSRandy Dunlap  * @payload:		data payload for the request subaction
450226b18adSRandy Dunlap  * @length:		length of the payload, in bytes
451e71d31daSStefan Richter  *
452656b7afdSStefan Richter  * Returns the RCODE.  See fw_send_request() for parameter documentation.
453656b7afdSStefan Richter  * Unlike fw_send_request(), @data points to the payload of the request or/and
454f30e6d3eSStefan Richter  * to the payload of the response.  DMA mapping restrictions apply to outbound
455f30e6d3eSStefan Richter  * request payloads of >= 8 bytes but not to inbound response payloads.
456e71d31daSStefan Richter  */
fw_run_transaction(struct fw_card * card,int tcode,int destination_id,int generation,int speed,unsigned long long offset,void * payload,size_t length)457e71d31daSStefan Richter int fw_run_transaction(struct fw_card *card, int tcode, int destination_id,
458e71d31daSStefan Richter 		       int generation, int speed, unsigned long long offset,
459e71d31daSStefan Richter 		       void *payload, size_t length)
460e71d31daSStefan Richter {
461e71d31daSStefan Richter 	struct transaction_callback_data d;
462e71d31daSStefan Richter 	struct fw_transaction t;
463e71d31daSStefan Richter 
4649c6c273aSKees Cook 	timer_setup_on_stack(&t.split_timeout_timer, NULL, 0);
465e71d31daSStefan Richter 	init_completion(&d.done);
466e71d31daSStefan Richter 	d.payload = payload;
467e71d31daSStefan Richter 	fw_send_request(card, &t, tcode, destination_id, generation, speed,
468e71d31daSStefan Richter 			offset, payload, length, transaction_callback, &d);
469e71d31daSStefan Richter 	wait_for_completion(&d.done);
4705c40cbfeSClemens Ladisch 	destroy_timer_on_stack(&t.split_timeout_timer);
471e71d31daSStefan Richter 
472e71d31daSStefan Richter 	return d.rcode;
473e71d31daSStefan Richter }
474e71d31daSStefan Richter EXPORT_SYMBOL(fw_run_transaction);
475e71d31daSStefan Richter 
476e71d31daSStefan Richter static DEFINE_MUTEX(phy_config_mutex);
477e71d31daSStefan Richter static DECLARE_COMPLETION(phy_config_done);
478e71d31daSStefan Richter 
transmit_phy_packet_callback(struct fw_packet * packet,struct fw_card * card,int status)479e71d31daSStefan Richter static void transmit_phy_packet_callback(struct fw_packet *packet,
480e71d31daSStefan Richter 					 struct fw_card *card, int status)
481e71d31daSStefan Richter {
482e71d31daSStefan Richter 	complete(&phy_config_done);
483e71d31daSStefan Richter }
484e71d31daSStefan Richter 
485e71d31daSStefan Richter static struct fw_packet phy_config_packet = {
4865b06db16SClemens Ladisch 	.header_length	= 12,
4875b06db16SClemens Ladisch 	.header[0]	= TCODE_LINK_INTERNAL << 4,
488e71d31daSStefan Richter 	.payload_length	= 0,
489e71d31daSStefan Richter 	.speed		= SCODE_100,
490e71d31daSStefan Richter 	.callback	= transmit_phy_packet_callback,
491e71d31daSStefan Richter };
492e71d31daSStefan Richter 
fw_send_phy_config(struct fw_card * card,int node_id,int generation,int gap_count)493e71d31daSStefan Richter void fw_send_phy_config(struct fw_card *card,
494e71d31daSStefan Richter 			int node_id, int generation, int gap_count)
495e71d31daSStefan Richter {
496e71d31daSStefan Richter 	long timeout = DIV_ROUND_UP(HZ, 10);
49702d37bedSStefan Richter 	u32 data = PHY_IDENTIFIER(PHY_PACKET_CONFIG);
49802d37bedSStefan Richter 
49902d37bedSStefan Richter 	if (node_id != FW_PHY_CONFIG_NO_NODE_ID)
50002d37bedSStefan Richter 		data |= PHY_CONFIG_ROOT_ID(node_id);
50102d37bedSStefan Richter 
50202d37bedSStefan Richter 	if (gap_count == FW_PHY_CONFIG_CURRENT_GAP_COUNT) {
50302d37bedSStefan Richter 		gap_count = card->driver->read_phy_reg(card, 1);
50402d37bedSStefan Richter 		if (gap_count < 0)
50502d37bedSStefan Richter 			return;
50602d37bedSStefan Richter 
50702d37bedSStefan Richter 		gap_count &= 63;
50802d37bedSStefan Richter 		if (gap_count == 63)
50902d37bedSStefan Richter 			return;
51002d37bedSStefan Richter 	}
51102d37bedSStefan Richter 	data |= PHY_CONFIG_GAP_COUNT(gap_count);
512e71d31daSStefan Richter 
513e71d31daSStefan Richter 	mutex_lock(&phy_config_mutex);
514e71d31daSStefan Richter 
5155b06db16SClemens Ladisch 	phy_config_packet.header[1] = data;
5165b06db16SClemens Ladisch 	phy_config_packet.header[2] = ~data;
517e71d31daSStefan Richter 	phy_config_packet.generation = generation;
51816735d02SWolfram Sang 	reinit_completion(&phy_config_done);
519e71d31daSStefan Richter 
520e71d31daSStefan Richter 	card->driver->send_request(card, &phy_config_packet);
521e71d31daSStefan Richter 	wait_for_completion_timeout(&phy_config_done, timeout);
522e71d31daSStefan Richter 
523e71d31daSStefan Richter 	mutex_unlock(&phy_config_mutex);
524e71d31daSStefan Richter }
525e71d31daSStefan Richter 
lookup_overlapping_address_handler(struct list_head * list,unsigned long long offset,size_t length)526e71d31daSStefan Richter static struct fw_address_handler *lookup_overlapping_address_handler(
527e71d31daSStefan Richter 	struct list_head *list, unsigned long long offset, size_t length)
528e71d31daSStefan Richter {
529e71d31daSStefan Richter 	struct fw_address_handler *handler;
530e71d31daSStefan Richter 
53135202f7dSPeter Hurley 	list_for_each_entry_rcu(handler, list, link) {
532e71d31daSStefan Richter 		if (handler->offset < offset + length &&
533e71d31daSStefan Richter 		    offset < handler->offset + handler->length)
534e71d31daSStefan Richter 			return handler;
535e71d31daSStefan Richter 	}
536e71d31daSStefan Richter 
537e71d31daSStefan Richter 	return NULL;
538e71d31daSStefan Richter }
539e71d31daSStefan Richter 
is_enclosing_handler(struct fw_address_handler * handler,unsigned long long offset,size_t length)540db5d247aSClemens Ladisch static bool is_enclosing_handler(struct fw_address_handler *handler,
541db5d247aSClemens Ladisch 				 unsigned long long offset, size_t length)
542db5d247aSClemens Ladisch {
543db5d247aSClemens Ladisch 	return handler->offset <= offset &&
544db5d247aSClemens Ladisch 		offset + length <= handler->offset + handler->length;
545db5d247aSClemens Ladisch }
546db5d247aSClemens Ladisch 
lookup_enclosing_address_handler(struct list_head * list,unsigned long long offset,size_t length)547e71d31daSStefan Richter static struct fw_address_handler *lookup_enclosing_address_handler(
548e71d31daSStefan Richter 	struct list_head *list, unsigned long long offset, size_t length)
549e71d31daSStefan Richter {
550e71d31daSStefan Richter 	struct fw_address_handler *handler;
551e71d31daSStefan Richter 
55235202f7dSPeter Hurley 	list_for_each_entry_rcu(handler, list, link) {
553db5d247aSClemens Ladisch 		if (is_enclosing_handler(handler, offset, length))
554e71d31daSStefan Richter 			return handler;
555e71d31daSStefan Richter 	}
556e71d31daSStefan Richter 
557e71d31daSStefan Richter 	return NULL;
558e71d31daSStefan Richter }
559e71d31daSStefan Richter 
5604d50c443SStefan Richter static DEFINE_SPINLOCK(address_handler_list_lock);
561e71d31daSStefan Richter static LIST_HEAD(address_handler_list);
562e71d31daSStefan Richter 
563e71d31daSStefan Richter const struct fw_address_region fw_high_memory_region =
564fcd46b34SStefan Richter 	{ .start = FW_MAX_PHYSICAL_RANGE, .end = 0xffffe0000000ULL, };
565e71d31daSStefan Richter EXPORT_SYMBOL(fw_high_memory_region);
566e71d31daSStefan Richter 
567f07d42acSClemens Ladisch static const struct fw_address_region low_memory_region =
568fcd46b34SStefan Richter 	{ .start = 0x000000000000ULL, .end = FW_MAX_PHYSICAL_RANGE, };
569f07d42acSClemens Ladisch 
570f07d42acSClemens Ladisch #if 0
571e71d31daSStefan Richter const struct fw_address_region fw_private_region =
572e71d31daSStefan Richter 	{ .start = 0xffffe0000000ULL, .end = 0xfffff0000000ULL,  };
573e71d31daSStefan Richter const struct fw_address_region fw_csr_region =
574e71d31daSStefan Richter 	{ .start = CSR_REGISTER_BASE,
575e71d31daSStefan Richter 	  .end   = CSR_REGISTER_BASE | CSR_CONFIG_ROM_END,  };
576e71d31daSStefan Richter const struct fw_address_region fw_unit_space_region =
577e71d31daSStefan Richter 	{ .start = 0xfffff0000900ULL, .end = 0x1000000000000ULL, };
578e71d31daSStefan Richter #endif  /*  0  */
579e71d31daSStefan Richter 
580e71d31daSStefan Richter /**
581656b7afdSStefan Richter  * fw_core_add_address_handler() - register for incoming requests
582e71d31daSStefan Richter  * @handler:	callback
583e71d31daSStefan Richter  * @region:	region in the IEEE 1212 node space address range
584e71d31daSStefan Richter  *
585e71d31daSStefan Richter  * region->start, ->end, and handler->length have to be quadlet-aligned.
586e71d31daSStefan Richter  *
587e71d31daSStefan Richter  * When a request is received that falls within the specified address range,
588e71d31daSStefan Richter  * the specified callback is invoked.  The parameters passed to the callback
589e71d31daSStefan Richter  * give the details of the particular request.
590e71d31daSStefan Richter  *
5914d50c443SStefan Richter  * To be called in process context.
592e71d31daSStefan Richter  * Return value:  0 on success, non-zero otherwise.
593db5d247aSClemens Ladisch  *
594e71d31daSStefan Richter  * The start offset of the handler's address region is determined by
595e71d31daSStefan Richter  * fw_core_add_address_handler() and is returned in handler->offset.
596db5d247aSClemens Ladisch  *
597db5d247aSClemens Ladisch  * Address allocations are exclusive, except for the FCP registers.
598e71d31daSStefan Richter  */
fw_core_add_address_handler(struct fw_address_handler * handler,const struct fw_address_region * region)599e71d31daSStefan Richter int fw_core_add_address_handler(struct fw_address_handler *handler,
600e71d31daSStefan Richter 				const struct fw_address_region *region)
601e71d31daSStefan Richter {
602e71d31daSStefan Richter 	struct fw_address_handler *other;
603e71d31daSStefan Richter 	int ret = -EBUSY;
604e71d31daSStefan Richter 
605e71d31daSStefan Richter 	if (region->start & 0xffff000000000003ULL ||
606e71d31daSStefan Richter 	    region->start >= region->end ||
6070c9ae701SStefan Richter 	    region->end   > 0x0001000000000000ULL ||
608e71d31daSStefan Richter 	    handler->length & 3 ||
609e71d31daSStefan Richter 	    handler->length == 0)
610e71d31daSStefan Richter 		return -EINVAL;
611e71d31daSStefan Richter 
6124d50c443SStefan Richter 	spin_lock(&address_handler_list_lock);
613e71d31daSStefan Richter 
614e71d31daSStefan Richter 	handler->offset = region->start;
615e71d31daSStefan Richter 	while (handler->offset + handler->length <= region->end) {
616db5d247aSClemens Ladisch 		if (is_in_fcp_region(handler->offset, handler->length))
617db5d247aSClemens Ladisch 			other = NULL;
618db5d247aSClemens Ladisch 		else
619db5d247aSClemens Ladisch 			other = lookup_overlapping_address_handler
620db5d247aSClemens Ladisch 					(&address_handler_list,
621db5d247aSClemens Ladisch 					 handler->offset, handler->length);
622e71d31daSStefan Richter 		if (other != NULL) {
623e71d31daSStefan Richter 			handler->offset += other->length;
624e71d31daSStefan Richter 		} else {
62535202f7dSPeter Hurley 			list_add_tail_rcu(&handler->link, &address_handler_list);
626e71d31daSStefan Richter 			ret = 0;
627e71d31daSStefan Richter 			break;
628e71d31daSStefan Richter 		}
629e71d31daSStefan Richter 	}
630e71d31daSStefan Richter 
6314d50c443SStefan Richter 	spin_unlock(&address_handler_list_lock);
632e71d31daSStefan Richter 
633e71d31daSStefan Richter 	return ret;
634e71d31daSStefan Richter }
635e71d31daSStefan Richter EXPORT_SYMBOL(fw_core_add_address_handler);
636e71d31daSStefan Richter 
637e71d31daSStefan Richter /**
638656b7afdSStefan Richter  * fw_core_remove_address_handler() - unregister an address handler
639226b18adSRandy Dunlap  * @handler: callback
64090963f1cSStefan Richter  *
6414d50c443SStefan Richter  * To be called in process context.
6424d50c443SStefan Richter  *
64390963f1cSStefan Richter  * When fw_core_remove_address_handler() returns, @handler->callback() is
64490963f1cSStefan Richter  * guaranteed to not run on any CPU anymore.
645e71d31daSStefan Richter  */
fw_core_remove_address_handler(struct fw_address_handler * handler)646e71d31daSStefan Richter void fw_core_remove_address_handler(struct fw_address_handler *handler)
647e71d31daSStefan Richter {
6484d50c443SStefan Richter 	spin_lock(&address_handler_list_lock);
64935202f7dSPeter Hurley 	list_del_rcu(&handler->link);
6504d50c443SStefan Richter 	spin_unlock(&address_handler_list_lock);
65135202f7dSPeter Hurley 	synchronize_rcu();
652e71d31daSStefan Richter }
653e71d31daSStefan Richter EXPORT_SYMBOL(fw_core_remove_address_handler);
654e71d31daSStefan Richter 
655e71d31daSStefan Richter struct fw_request {
65613a55d6bSTakashi Sakamoto 	struct kref kref;
657e71d31daSStefan Richter 	struct fw_packet response;
658e71d31daSStefan Richter 	u32 request_header[4];
659e71d31daSStefan Richter 	int ack;
660b2405aa9STakashi Sakamoto 	u32 timestamp;
661e71d31daSStefan Richter 	u32 length;
662c38e7e21SGustavo A. R. Silva 	u32 data[];
663e71d31daSStefan Richter };
664e71d31daSStefan Richter 
fw_request_get(struct fw_request * request)66513a55d6bSTakashi Sakamoto void fw_request_get(struct fw_request *request)
66613a55d6bSTakashi Sakamoto {
66713a55d6bSTakashi Sakamoto 	kref_get(&request->kref);
66813a55d6bSTakashi Sakamoto }
66913a55d6bSTakashi Sakamoto 
release_request(struct kref * kref)67013a55d6bSTakashi Sakamoto static void release_request(struct kref *kref)
67113a55d6bSTakashi Sakamoto {
67213a55d6bSTakashi Sakamoto 	struct fw_request *request = container_of(kref, struct fw_request, kref);
67313a55d6bSTakashi Sakamoto 
67413a55d6bSTakashi Sakamoto 	kfree(request);
67513a55d6bSTakashi Sakamoto }
67613a55d6bSTakashi Sakamoto 
fw_request_put(struct fw_request * request)67713a55d6bSTakashi Sakamoto void fw_request_put(struct fw_request *request)
67813a55d6bSTakashi Sakamoto {
67913a55d6bSTakashi Sakamoto 	kref_put(&request->kref, release_request);
68013a55d6bSTakashi Sakamoto }
68113a55d6bSTakashi Sakamoto 
free_response_callback(struct fw_packet * packet,struct fw_card * card,int status)682e71d31daSStefan Richter static void free_response_callback(struct fw_packet *packet,
683e71d31daSStefan Richter 				   struct fw_card *card, int status)
684e71d31daSStefan Richter {
68513a55d6bSTakashi Sakamoto 	struct fw_request *request = container_of(packet, struct fw_request, response);
686e71d31daSStefan Richter 
68713a55d6bSTakashi Sakamoto 	// Decrease the reference count since not at in-flight.
68813a55d6bSTakashi Sakamoto 	fw_request_put(request);
68913a55d6bSTakashi Sakamoto 
69013a55d6bSTakashi Sakamoto 	// Decrease the reference count to release the object.
69113a55d6bSTakashi Sakamoto 	fw_request_put(request);
692e71d31daSStefan Richter }
693e71d31daSStefan Richter 
fw_get_response_length(struct fw_request * r)694a10c0ce7SClemens Ladisch int fw_get_response_length(struct fw_request *r)
695a10c0ce7SClemens Ladisch {
696a10c0ce7SClemens Ladisch 	int tcode, ext_tcode, data_length;
697a10c0ce7SClemens Ladisch 
698a10c0ce7SClemens Ladisch 	tcode = HEADER_GET_TCODE(r->request_header[0]);
699a10c0ce7SClemens Ladisch 
700a10c0ce7SClemens Ladisch 	switch (tcode) {
701a10c0ce7SClemens Ladisch 	case TCODE_WRITE_QUADLET_REQUEST:
702a10c0ce7SClemens Ladisch 	case TCODE_WRITE_BLOCK_REQUEST:
703a10c0ce7SClemens Ladisch 		return 0;
704a10c0ce7SClemens Ladisch 
705a10c0ce7SClemens Ladisch 	case TCODE_READ_QUADLET_REQUEST:
706a10c0ce7SClemens Ladisch 		return 4;
707a10c0ce7SClemens Ladisch 
708a10c0ce7SClemens Ladisch 	case TCODE_READ_BLOCK_REQUEST:
709a10c0ce7SClemens Ladisch 		data_length = HEADER_GET_DATA_LENGTH(r->request_header[3]);
710a10c0ce7SClemens Ladisch 		return data_length;
711a10c0ce7SClemens Ladisch 
712a10c0ce7SClemens Ladisch 	case TCODE_LOCK_REQUEST:
713a10c0ce7SClemens Ladisch 		ext_tcode = HEADER_GET_EXTENDED_TCODE(r->request_header[3]);
714a10c0ce7SClemens Ladisch 		data_length = HEADER_GET_DATA_LENGTH(r->request_header[3]);
715a10c0ce7SClemens Ladisch 		switch (ext_tcode) {
716a10c0ce7SClemens Ladisch 		case EXTCODE_FETCH_ADD:
717a10c0ce7SClemens Ladisch 		case EXTCODE_LITTLE_ADD:
718a10c0ce7SClemens Ladisch 			return data_length;
719a10c0ce7SClemens Ladisch 		default:
720a10c0ce7SClemens Ladisch 			return data_length / 2;
721a10c0ce7SClemens Ladisch 		}
722a10c0ce7SClemens Ladisch 
723a10c0ce7SClemens Ladisch 	default:
7245878730bSJoe Perches 		WARN(1, "wrong tcode %d\n", tcode);
725a10c0ce7SClemens Ladisch 		return 0;
726a10c0ce7SClemens Ladisch 	}
727a10c0ce7SClemens Ladisch }
728a10c0ce7SClemens Ladisch 
fw_fill_response(struct fw_packet * response,u32 * request_header,int rcode,void * payload,size_t length)729e71d31daSStefan Richter void fw_fill_response(struct fw_packet *response, u32 *request_header,
730e71d31daSStefan Richter 		      int rcode, void *payload, size_t length)
731e71d31daSStefan Richter {
732e71d31daSStefan Richter 	int tcode, tlabel, extended_tcode, source, destination;
733e71d31daSStefan Richter 
734e71d31daSStefan Richter 	tcode          = HEADER_GET_TCODE(request_header[0]);
735e71d31daSStefan Richter 	tlabel         = HEADER_GET_TLABEL(request_header[0]);
736e71d31daSStefan Richter 	source         = HEADER_GET_DESTINATION(request_header[0]);
737e71d31daSStefan Richter 	destination    = HEADER_GET_SOURCE(request_header[1]);
738e71d31daSStefan Richter 	extended_tcode = HEADER_GET_EXTENDED_TCODE(request_header[3]);
739e71d31daSStefan Richter 
740e71d31daSStefan Richter 	response->header[0] =
741e71d31daSStefan Richter 		HEADER_RETRY(RETRY_1) |
742e71d31daSStefan Richter 		HEADER_TLABEL(tlabel) |
743e71d31daSStefan Richter 		HEADER_DESTINATION(destination);
744e71d31daSStefan Richter 	response->header[1] =
745e71d31daSStefan Richter 		HEADER_SOURCE(source) |
746e71d31daSStefan Richter 		HEADER_RCODE(rcode);
747e71d31daSStefan Richter 	response->header[2] = 0;
748e71d31daSStefan Richter 
749e71d31daSStefan Richter 	switch (tcode) {
750e71d31daSStefan Richter 	case TCODE_WRITE_QUADLET_REQUEST:
751e71d31daSStefan Richter 	case TCODE_WRITE_BLOCK_REQUEST:
752e71d31daSStefan Richter 		response->header[0] |= HEADER_TCODE(TCODE_WRITE_RESPONSE);
753e71d31daSStefan Richter 		response->header_length = 12;
754e71d31daSStefan Richter 		response->payload_length = 0;
755e71d31daSStefan Richter 		break;
756e71d31daSStefan Richter 
757e71d31daSStefan Richter 	case TCODE_READ_QUADLET_REQUEST:
758e71d31daSStefan Richter 		response->header[0] |=
759e71d31daSStefan Richter 			HEADER_TCODE(TCODE_READ_QUADLET_RESPONSE);
760e71d31daSStefan Richter 		if (payload != NULL)
761e71d31daSStefan Richter 			response->header[3] = *(u32 *)payload;
762e71d31daSStefan Richter 		else
763e71d31daSStefan Richter 			response->header[3] = 0;
764e71d31daSStefan Richter 		response->header_length = 16;
765e71d31daSStefan Richter 		response->payload_length = 0;
766e71d31daSStefan Richter 		break;
767e71d31daSStefan Richter 
768e71d31daSStefan Richter 	case TCODE_READ_BLOCK_REQUEST:
769e71d31daSStefan Richter 	case TCODE_LOCK_REQUEST:
770e71d31daSStefan Richter 		response->header[0] |= HEADER_TCODE(tcode + 2);
771e71d31daSStefan Richter 		response->header[3] =
772e71d31daSStefan Richter 			HEADER_DATA_LENGTH(length) |
773e71d31daSStefan Richter 			HEADER_EXTENDED_TCODE(extended_tcode);
774e71d31daSStefan Richter 		response->header_length = 16;
775e71d31daSStefan Richter 		response->payload = payload;
776e71d31daSStefan Richter 		response->payload_length = length;
777e71d31daSStefan Richter 		break;
778e71d31daSStefan Richter 
779e71d31daSStefan Richter 	default:
7805878730bSJoe Perches 		WARN(1, "wrong tcode %d\n", tcode);
781e71d31daSStefan Richter 	}
782e71d31daSStefan Richter 
78319593ffdSStefan Richter 	response->payload_mapped = false;
784e71d31daSStefan Richter }
785e71d31daSStefan Richter EXPORT_SYMBOL(fw_fill_response);
786e71d31daSStefan Richter 
compute_split_timeout_timestamp(struct fw_card * card,u32 request_timestamp)7878e4b50f9SClemens Ladisch static u32 compute_split_timeout_timestamp(struct fw_card *card,
7888e4b50f9SClemens Ladisch 					   u32 request_timestamp)
7898e4b50f9SClemens Ladisch {
7908e4b50f9SClemens Ladisch 	unsigned int cycles;
7918e4b50f9SClemens Ladisch 	u32 timestamp;
7928e4b50f9SClemens Ladisch 
7938e4b50f9SClemens Ladisch 	cycles = card->split_timeout_cycles;
7948e4b50f9SClemens Ladisch 	cycles += request_timestamp & 0x1fff;
7958e4b50f9SClemens Ladisch 
7968e4b50f9SClemens Ladisch 	timestamp = request_timestamp & ~0x1fff;
7978e4b50f9SClemens Ladisch 	timestamp += (cycles / 8000) << 13;
7988e4b50f9SClemens Ladisch 	timestamp |= cycles % 8000;
7998e4b50f9SClemens Ladisch 
8008e4b50f9SClemens Ladisch 	return timestamp;
8018e4b50f9SClemens Ladisch }
8028e4b50f9SClemens Ladisch 
allocate_request(struct fw_card * card,struct fw_packet * p)8038e4b50f9SClemens Ladisch static struct fw_request *allocate_request(struct fw_card *card,
8048e4b50f9SClemens Ladisch 					   struct fw_packet *p)
805e71d31daSStefan Richter {
806e71d31daSStefan Richter 	struct fw_request *request;
807e71d31daSStefan Richter 	u32 *data, length;
8088e4b50f9SClemens Ladisch 	int request_tcode;
809e71d31daSStefan Richter 
810e71d31daSStefan Richter 	request_tcode = HEADER_GET_TCODE(p->header[0]);
811e71d31daSStefan Richter 	switch (request_tcode) {
812e71d31daSStefan Richter 	case TCODE_WRITE_QUADLET_REQUEST:
813e71d31daSStefan Richter 		data = &p->header[3];
814e71d31daSStefan Richter 		length = 4;
815e71d31daSStefan Richter 		break;
816e71d31daSStefan Richter 
817e71d31daSStefan Richter 	case TCODE_WRITE_BLOCK_REQUEST:
818e71d31daSStefan Richter 	case TCODE_LOCK_REQUEST:
819e71d31daSStefan Richter 		data = p->payload;
820e71d31daSStefan Richter 		length = HEADER_GET_DATA_LENGTH(p->header[3]);
821e71d31daSStefan Richter 		break;
822e71d31daSStefan Richter 
823e71d31daSStefan Richter 	case TCODE_READ_QUADLET_REQUEST:
824e71d31daSStefan Richter 		data = NULL;
825e71d31daSStefan Richter 		length = 4;
826e71d31daSStefan Richter 		break;
827e71d31daSStefan Richter 
828e71d31daSStefan Richter 	case TCODE_READ_BLOCK_REQUEST:
829e71d31daSStefan Richter 		data = NULL;
830e71d31daSStefan Richter 		length = HEADER_GET_DATA_LENGTH(p->header[3]);
831e71d31daSStefan Richter 		break;
832e71d31daSStefan Richter 
833e71d31daSStefan Richter 	default:
83426b4950dSStefan Richter 		fw_notice(card, "ERROR - corrupt request received - %08x %08x %08x\n",
835e71d31daSStefan Richter 			 p->header[0], p->header[1], p->header[2]);
836e71d31daSStefan Richter 		return NULL;
837e71d31daSStefan Richter 	}
838e71d31daSStefan Richter 
839e71d31daSStefan Richter 	request = kmalloc(sizeof(*request) + length, GFP_ATOMIC);
840e71d31daSStefan Richter 	if (request == NULL)
841e71d31daSStefan Richter 		return NULL;
84213a55d6bSTakashi Sakamoto 	kref_init(&request->kref);
843e71d31daSStefan Richter 
844e71d31daSStefan Richter 	request->response.speed = p->speed;
8458e4b50f9SClemens Ladisch 	request->response.timestamp =
8468e4b50f9SClemens Ladisch 			compute_split_timeout_timestamp(card, p->timestamp);
847e71d31daSStefan Richter 	request->response.generation = p->generation;
848e71d31daSStefan Richter 	request->response.ack = 0;
849e71d31daSStefan Richter 	request->response.callback = free_response_callback;
850e71d31daSStefan Richter 	request->ack = p->ack;
851b2405aa9STakashi Sakamoto 	request->timestamp = p->timestamp;
852e71d31daSStefan Richter 	request->length = length;
853e71d31daSStefan Richter 	if (data)
854e71d31daSStefan Richter 		memcpy(request->data, data, length);
855e71d31daSStefan Richter 
856e71d31daSStefan Richter 	memcpy(request->request_header, p->header, sizeof(p->header));
857e71d31daSStefan Richter 
858e71d31daSStefan Richter 	return request;
859e71d31daSStefan Richter }
860e71d31daSStefan Richter 
861e6996002STakashi Sakamoto /**
862e6996002STakashi Sakamoto  * fw_send_response: - send response packet for asynchronous transaction.
863e6996002STakashi Sakamoto  * @card:	interface to send the response at.
864e6996002STakashi Sakamoto  * @request:	firewire request data for the transaction.
865e6996002STakashi Sakamoto  * @rcode:	response code to send.
866e6996002STakashi Sakamoto  *
867e6996002STakashi Sakamoto  * Submit a response packet into the asynchronous response transmission queue. The @request
868e6996002STakashi Sakamoto  * is going to be released when the transmission successfully finishes later.
869e6996002STakashi Sakamoto  */
fw_send_response(struct fw_card * card,struct fw_request * request,int rcode)870e71d31daSStefan Richter void fw_send_response(struct fw_card *card,
871e71d31daSStefan Richter 		      struct fw_request *request, int rcode)
872e71d31daSStefan Richter {
873e71d31daSStefan Richter 	/* unified transaction or broadcast transaction: don't respond */
874e71d31daSStefan Richter 	if (request->ack != ACK_PENDING ||
875e71d31daSStefan Richter 	    HEADER_DESTINATION_IS_BROADCAST(request->request_header[0])) {
87613a55d6bSTakashi Sakamoto 		fw_request_put(request);
877e71d31daSStefan Richter 		return;
878e71d31daSStefan Richter 	}
879e71d31daSStefan Richter 
880e71d31daSStefan Richter 	if (rcode == RCODE_COMPLETE)
881e71d31daSStefan Richter 		fw_fill_response(&request->response, request->request_header,
882a10c0ce7SClemens Ladisch 				 rcode, request->data,
883a10c0ce7SClemens Ladisch 				 fw_get_response_length(request));
884e71d31daSStefan Richter 	else
885e71d31daSStefan Richter 		fw_fill_response(&request->response, request->request_header,
886e71d31daSStefan Richter 				 rcode, NULL, 0);
887e71d31daSStefan Richter 
88813a55d6bSTakashi Sakamoto 	// Increase the reference count so that the object is kept during in-flight.
88913a55d6bSTakashi Sakamoto 	fw_request_get(request);
89013a55d6bSTakashi Sakamoto 
891e71d31daSStefan Richter 	card->driver->send_response(card, &request->response);
892e71d31daSStefan Richter }
893e71d31daSStefan Richter EXPORT_SYMBOL(fw_send_response);
894e71d31daSStefan Richter 
895253d9237SChris Boot /**
896253d9237SChris Boot  * fw_get_request_speed() - returns speed at which the @request was received
897226b18adSRandy Dunlap  * @request: firewire request data
898253d9237SChris Boot  */
fw_get_request_speed(struct fw_request * request)899253d9237SChris Boot int fw_get_request_speed(struct fw_request *request)
900253d9237SChris Boot {
901253d9237SChris Boot 	return request->response.speed;
902253d9237SChris Boot }
903253d9237SChris Boot EXPORT_SYMBOL(fw_get_request_speed);
904253d9237SChris Boot 
905b2405aa9STakashi Sakamoto /**
906b2405aa9STakashi Sakamoto  * fw_request_get_timestamp: Get timestamp of the request.
907b2405aa9STakashi Sakamoto  * @request: The opaque pointer to request structure.
908b2405aa9STakashi Sakamoto  *
909b2405aa9STakashi Sakamoto  * Get timestamp when 1394 OHCI controller receives the asynchronous request subaction. The
910b2405aa9STakashi Sakamoto  * timestamp consists of the low order 3 bits of second field and the full 13 bits of count
911b2405aa9STakashi Sakamoto  * field of isochronous cycle time register.
912b2405aa9STakashi Sakamoto  *
913b2405aa9STakashi Sakamoto  * Returns: timestamp of the request.
914b2405aa9STakashi Sakamoto  */
fw_request_get_timestamp(const struct fw_request * request)915b2405aa9STakashi Sakamoto u32 fw_request_get_timestamp(const struct fw_request *request)
916b2405aa9STakashi Sakamoto {
917b2405aa9STakashi Sakamoto 	return request->timestamp;
918b2405aa9STakashi Sakamoto }
919b2405aa9STakashi Sakamoto EXPORT_SYMBOL_GPL(fw_request_get_timestamp);
920b2405aa9STakashi Sakamoto 
handle_exclusive_region_request(struct fw_card * card,struct fw_packet * p,struct fw_request * request,unsigned long long offset)921db5d247aSClemens Ladisch static void handle_exclusive_region_request(struct fw_card *card,
922db5d247aSClemens Ladisch 					    struct fw_packet *p,
923db5d247aSClemens Ladisch 					    struct fw_request *request,
924db5d247aSClemens Ladisch 					    unsigned long long offset)
925e71d31daSStefan Richter {
926e71d31daSStefan Richter 	struct fw_address_handler *handler;
927e71d31daSStefan Richter 	int tcode, destination, source;
928e71d31daSStefan Richter 
929e71d31daSStefan Richter 	destination = HEADER_GET_DESTINATION(p->header[0]);
930e71d31daSStefan Richter 	source      = HEADER_GET_SOURCE(p->header[1]);
931c82f91f2SJay Fenlason 	tcode       = HEADER_GET_TCODE(p->header[0]);
932c82f91f2SJay Fenlason 	if (tcode == TCODE_LOCK_REQUEST)
933c82f91f2SJay Fenlason 		tcode = 0x10 + HEADER_GET_EXTENDED_TCODE(p->header[3]);
934e71d31daSStefan Richter 
93535202f7dSPeter Hurley 	rcu_read_lock();
936e71d31daSStefan Richter 	handler = lookup_enclosing_address_handler(&address_handler_list,
937e71d31daSStefan Richter 						   offset, request->length);
93890963f1cSStefan Richter 	if (handler)
939e71d31daSStefan Richter 		handler->address_callback(card, request,
940e71d31daSStefan Richter 					  tcode, destination, source,
94133e553feSStefan Richter 					  p->generation, offset,
942e71d31daSStefan Richter 					  request->data, request->length,
943e71d31daSStefan Richter 					  handler->callback_data);
94435202f7dSPeter Hurley 	rcu_read_unlock();
94590963f1cSStefan Richter 
94690963f1cSStefan Richter 	if (!handler)
94790963f1cSStefan Richter 		fw_send_response(card, request, RCODE_ADDRESS_ERROR);
948e71d31daSStefan Richter }
949db5d247aSClemens Ladisch 
handle_fcp_region_request(struct fw_card * card,struct fw_packet * p,struct fw_request * request,unsigned long long offset)950db5d247aSClemens Ladisch static void handle_fcp_region_request(struct fw_card *card,
951db5d247aSClemens Ladisch 				      struct fw_packet *p,
952db5d247aSClemens Ladisch 				      struct fw_request *request,
953db5d247aSClemens Ladisch 				      unsigned long long offset)
954db5d247aSClemens Ladisch {
955db5d247aSClemens Ladisch 	struct fw_address_handler *handler;
956db5d247aSClemens Ladisch 	int tcode, destination, source;
957db5d247aSClemens Ladisch 
958db5d247aSClemens Ladisch 	if ((offset != (CSR_REGISTER_BASE | CSR_FCP_COMMAND) &&
959db5d247aSClemens Ladisch 	     offset != (CSR_REGISTER_BASE | CSR_FCP_RESPONSE)) ||
960db5d247aSClemens Ladisch 	    request->length > 0x200) {
961db5d247aSClemens Ladisch 		fw_send_response(card, request, RCODE_ADDRESS_ERROR);
962db5d247aSClemens Ladisch 
963db5d247aSClemens Ladisch 		return;
964db5d247aSClemens Ladisch 	}
965db5d247aSClemens Ladisch 
966db5d247aSClemens Ladisch 	tcode       = HEADER_GET_TCODE(p->header[0]);
967db5d247aSClemens Ladisch 	destination = HEADER_GET_DESTINATION(p->header[0]);
968db5d247aSClemens Ladisch 	source      = HEADER_GET_SOURCE(p->header[1]);
969db5d247aSClemens Ladisch 
970db5d247aSClemens Ladisch 	if (tcode != TCODE_WRITE_QUADLET_REQUEST &&
971db5d247aSClemens Ladisch 	    tcode != TCODE_WRITE_BLOCK_REQUEST) {
972db5d247aSClemens Ladisch 		fw_send_response(card, request, RCODE_TYPE_ERROR);
973db5d247aSClemens Ladisch 
974db5d247aSClemens Ladisch 		return;
975db5d247aSClemens Ladisch 	}
976db5d247aSClemens Ladisch 
97735202f7dSPeter Hurley 	rcu_read_lock();
97835202f7dSPeter Hurley 	list_for_each_entry_rcu(handler, &address_handler_list, link) {
979db5d247aSClemens Ladisch 		if (is_enclosing_handler(handler, offset, request->length))
980e6996002STakashi Sakamoto 			handler->address_callback(card, request, tcode,
981db5d247aSClemens Ladisch 						  destination, source,
98233e553feSStefan Richter 						  p->generation, offset,
98333e553feSStefan Richter 						  request->data,
984db5d247aSClemens Ladisch 						  request->length,
985db5d247aSClemens Ladisch 						  handler->callback_data);
986db5d247aSClemens Ladisch 	}
98735202f7dSPeter Hurley 	rcu_read_unlock();
988db5d247aSClemens Ladisch 
989db5d247aSClemens Ladisch 	fw_send_response(card, request, RCODE_COMPLETE);
990db5d247aSClemens Ladisch }
991db5d247aSClemens Ladisch 
fw_core_handle_request(struct fw_card * card,struct fw_packet * p)992db5d247aSClemens Ladisch void fw_core_handle_request(struct fw_card *card, struct fw_packet *p)
993db5d247aSClemens Ladisch {
994db5d247aSClemens Ladisch 	struct fw_request *request;
995db5d247aSClemens Ladisch 	unsigned long long offset;
996db5d247aSClemens Ladisch 
997db5d247aSClemens Ladisch 	if (p->ack != ACK_PENDING && p->ack != ACK_COMPLETE)
998db5d247aSClemens Ladisch 		return;
999db5d247aSClemens Ladisch 
1000bf54e146SStefan Richter 	if (TCODE_IS_LINK_INTERNAL(HEADER_GET_TCODE(p->header[0]))) {
1001bf54e146SStefan Richter 		fw_cdev_handle_phy_packet(card, p);
1002bf54e146SStefan Richter 		return;
1003bf54e146SStefan Richter 	}
1004bf54e146SStefan Richter 
10058e4b50f9SClemens Ladisch 	request = allocate_request(card, p);
1006db5d247aSClemens Ladisch 	if (request == NULL) {
1007db5d247aSClemens Ladisch 		/* FIXME: send statically allocated busy packet. */
1008db5d247aSClemens Ladisch 		return;
1009db5d247aSClemens Ladisch 	}
1010db5d247aSClemens Ladisch 
1011db5d247aSClemens Ladisch 	offset = ((u64)HEADER_GET_OFFSET_HIGH(p->header[1]) << 32) |
1012db5d247aSClemens Ladisch 		p->header[2];
1013db5d247aSClemens Ladisch 
1014db5d247aSClemens Ladisch 	if (!is_in_fcp_region(offset, request->length))
1015db5d247aSClemens Ladisch 		handle_exclusive_region_request(card, p, request, offset);
1016db5d247aSClemens Ladisch 	else
1017db5d247aSClemens Ladisch 		handle_fcp_region_request(card, p, request, offset);
1018db5d247aSClemens Ladisch 
1019db5d247aSClemens Ladisch }
1020e71d31daSStefan Richter EXPORT_SYMBOL(fw_core_handle_request);
1021e71d31daSStefan Richter 
fw_core_handle_response(struct fw_card * card,struct fw_packet * p)1022e71d31daSStefan Richter void fw_core_handle_response(struct fw_card *card, struct fw_packet *p)
1023e71d31daSStefan Richter {
102494239738SJakob Koschel 	struct fw_transaction *t = NULL, *iter;
1025e71d31daSStefan Richter 	unsigned long flags;
1026e71d31daSStefan Richter 	u32 *data;
1027e71d31daSStefan Richter 	size_t data_length;
1028ae86e81eSStefan Richter 	int tcode, tlabel, source, rcode;
1029e71d31daSStefan Richter 
1030e71d31daSStefan Richter 	tcode	= HEADER_GET_TCODE(p->header[0]);
1031e71d31daSStefan Richter 	tlabel	= HEADER_GET_TLABEL(p->header[0]);
1032e71d31daSStefan Richter 	source	= HEADER_GET_SOURCE(p->header[1]);
1033e71d31daSStefan Richter 	rcode	= HEADER_GET_RCODE(p->header[1]);
1034e71d31daSStefan Richter 
1035e71d31daSStefan Richter 	spin_lock_irqsave(&card->lock, flags);
103694239738SJakob Koschel 	list_for_each_entry(iter, &card->transaction_list, link) {
103794239738SJakob Koschel 		if (iter->node_id == source && iter->tlabel == tlabel) {
103894239738SJakob Koschel 			if (!try_cancel_split_timeout(iter)) {
10392222bcb7SClemens Ladisch 				spin_unlock_irqrestore(&card->lock, flags);
10402222bcb7SClemens Ladisch 				goto timed_out;
10412222bcb7SClemens Ladisch 			}
104294239738SJakob Koschel 			list_del_init(&iter->link);
104394239738SJakob Koschel 			card->tlabel_mask &= ~(1ULL << iter->tlabel);
104494239738SJakob Koschel 			t = iter;
1045e71d31daSStefan Richter 			break;
1046e71d31daSStefan Richter 		}
1047e71d31daSStefan Richter 	}
1048e71d31daSStefan Richter 	spin_unlock_irqrestore(&card->lock, flags);
1049e71d31daSStefan Richter 
105094239738SJakob Koschel 	if (!t) {
10512222bcb7SClemens Ladisch  timed_out:
105226b4950dSStefan Richter 		fw_notice(card, "unsolicited response (source %x, tlabel %x)\n",
1053e71d31daSStefan Richter 			  source, tlabel);
1054e71d31daSStefan Richter 		return;
1055e71d31daSStefan Richter 	}
1056e71d31daSStefan Richter 
1057e71d31daSStefan Richter 	/*
1058e71d31daSStefan Richter 	 * FIXME: sanity check packet, is length correct, does tcodes
1059e71d31daSStefan Richter 	 * and addresses match.
1060e71d31daSStefan Richter 	 */
1061e71d31daSStefan Richter 
1062e71d31daSStefan Richter 	switch (tcode) {
1063e71d31daSStefan Richter 	case TCODE_READ_QUADLET_RESPONSE:
1064e71d31daSStefan Richter 		data = (u32 *) &p->header[3];
1065e71d31daSStefan Richter 		data_length = 4;
1066e71d31daSStefan Richter 		break;
1067e71d31daSStefan Richter 
1068e71d31daSStefan Richter 	case TCODE_WRITE_RESPONSE:
1069e71d31daSStefan Richter 		data = NULL;
1070e71d31daSStefan Richter 		data_length = 0;
1071e71d31daSStefan Richter 		break;
1072e71d31daSStefan Richter 
1073e71d31daSStefan Richter 	case TCODE_READ_BLOCK_RESPONSE:
1074e71d31daSStefan Richter 	case TCODE_LOCK_RESPONSE:
1075e71d31daSStefan Richter 		data = p->payload;
1076e71d31daSStefan Richter 		data_length = HEADER_GET_DATA_LENGTH(p->header[3]);
1077e71d31daSStefan Richter 		break;
1078e71d31daSStefan Richter 
1079e71d31daSStefan Richter 	default:
1080e71d31daSStefan Richter 		/* Should never happen, this is just to shut up gcc. */
1081e71d31daSStefan Richter 		data = NULL;
1082e71d31daSStefan Richter 		data_length = 0;
1083e71d31daSStefan Richter 		break;
1084e71d31daSStefan Richter 	}
1085e71d31daSStefan Richter 
1086e71d31daSStefan Richter 	/*
1087e71d31daSStefan Richter 	 * The response handler may be executed while the request handler
1088e71d31daSStefan Richter 	 * is still pending.  Cancel the request handler.
1089e71d31daSStefan Richter 	 */
1090e71d31daSStefan Richter 	card->driver->cancel_packet(card, &t->packet);
1091e71d31daSStefan Richter 
1092dcadfd7fSTakashi Sakamoto 	if (!t->with_tstamp) {
1093dcadfd7fSTakashi Sakamoto 		t->callback.without_tstamp(card, rcode, data, data_length, t->callback_data);
1094dcadfd7fSTakashi Sakamoto 	} else {
1095dcadfd7fSTakashi Sakamoto 		t->callback.with_tstamp(card, rcode, t->packet.timestamp, p->timestamp, data,
1096dcadfd7fSTakashi Sakamoto 					data_length, t->callback_data);
1097dcadfd7fSTakashi Sakamoto 	}
1098e71d31daSStefan Richter }
1099e71d31daSStefan Richter EXPORT_SYMBOL(fw_core_handle_response);
1100e71d31daSStefan Richter 
11017bdbff67SClemens Ladisch /**
11027bdbff67SClemens Ladisch  * fw_rcode_string - convert a firewire result code to an error description
11037bdbff67SClemens Ladisch  * @rcode: the result code
11047bdbff67SClemens Ladisch  */
fw_rcode_string(int rcode)11057bdbff67SClemens Ladisch const char *fw_rcode_string(int rcode)
11067bdbff67SClemens Ladisch {
11077bdbff67SClemens Ladisch 	static const char *const names[] = {
11087bdbff67SClemens Ladisch 		[RCODE_COMPLETE]       = "no error",
11097bdbff67SClemens Ladisch 		[RCODE_CONFLICT_ERROR] = "conflict error",
11107bdbff67SClemens Ladisch 		[RCODE_DATA_ERROR]     = "data error",
11117bdbff67SClemens Ladisch 		[RCODE_TYPE_ERROR]     = "type error",
11127bdbff67SClemens Ladisch 		[RCODE_ADDRESS_ERROR]  = "address error",
11137bdbff67SClemens Ladisch 		[RCODE_SEND_ERROR]     = "send error",
11147bdbff67SClemens Ladisch 		[RCODE_CANCELLED]      = "timeout",
11157bdbff67SClemens Ladisch 		[RCODE_BUSY]           = "busy",
11167bdbff67SClemens Ladisch 		[RCODE_GENERATION]     = "bus reset",
11177bdbff67SClemens Ladisch 		[RCODE_NO_ACK]         = "no ack",
11187bdbff67SClemens Ladisch 	};
11197bdbff67SClemens Ladisch 
11207bdbff67SClemens Ladisch 	if ((unsigned int)rcode < ARRAY_SIZE(names) && names[rcode])
11217bdbff67SClemens Ladisch 		return names[rcode];
11227bdbff67SClemens Ladisch 	else
11237bdbff67SClemens Ladisch 		return "unknown";
11247bdbff67SClemens Ladisch }
11257bdbff67SClemens Ladisch EXPORT_SYMBOL(fw_rcode_string);
11267bdbff67SClemens Ladisch 
1127e71d31daSStefan Richter static const struct fw_address_region topology_map_region =
1128e71d31daSStefan Richter 	{ .start = CSR_REGISTER_BASE | CSR_TOPOLOGY_MAP,
1129e71d31daSStefan Richter 	  .end   = CSR_REGISTER_BASE | CSR_TOPOLOGY_MAP_END, };
1130e71d31daSStefan Richter 
handle_topology_map(struct fw_card * card,struct fw_request * request,int tcode,int destination,int source,int generation,unsigned long long offset,void * payload,size_t length,void * callback_data)1131e71d31daSStefan Richter static void handle_topology_map(struct fw_card *card, struct fw_request *request,
1132e71d31daSStefan Richter 		int tcode, int destination, int source, int generation,
113333e553feSStefan Richter 		unsigned long long offset, void *payload, size_t length,
113433e553feSStefan Richter 		void *callback_data)
1135e71d31daSStefan Richter {
1136cb7c96daSStefan Richter 	int start;
1137e71d31daSStefan Richter 
1138e71d31daSStefan Richter 	if (!TCODE_IS_READ_REQUEST(tcode)) {
1139e71d31daSStefan Richter 		fw_send_response(card, request, RCODE_TYPE_ERROR);
1140e71d31daSStefan Richter 		return;
1141e71d31daSStefan Richter 	}
1142e71d31daSStefan Richter 
1143e71d31daSStefan Richter 	if ((offset & 3) > 0 || (length & 3) > 0) {
1144e71d31daSStefan Richter 		fw_send_response(card, request, RCODE_ADDRESS_ERROR);
1145e71d31daSStefan Richter 		return;
1146e71d31daSStefan Richter 	}
1147e71d31daSStefan Richter 
1148e71d31daSStefan Richter 	start = (offset - topology_map_region.start) / 4;
1149cb7c96daSStefan Richter 	memcpy(payload, &card->topology_map[start], length);
1150e71d31daSStefan Richter 
1151e71d31daSStefan Richter 	fw_send_response(card, request, RCODE_COMPLETE);
1152e71d31daSStefan Richter }
1153e71d31daSStefan Richter 
1154e71d31daSStefan Richter static struct fw_address_handler topology_map = {
115585cb9b68SStefan Richter 	.length			= 0x400,
1156e71d31daSStefan Richter 	.address_callback	= handle_topology_map,
1157e71d31daSStefan Richter };
1158e71d31daSStefan Richter 
1159e71d31daSStefan Richter static const struct fw_address_region registers_region =
1160e71d31daSStefan Richter 	{ .start = CSR_REGISTER_BASE,
1161e71d31daSStefan Richter 	  .end   = CSR_REGISTER_BASE | CSR_CONFIG_ROM, };
1162e71d31daSStefan Richter 
update_split_timeout(struct fw_card * card)11638e4b50f9SClemens Ladisch static void update_split_timeout(struct fw_card *card)
11648e4b50f9SClemens Ladisch {
11658e4b50f9SClemens Ladisch 	unsigned int cycles;
11668e4b50f9SClemens Ladisch 
11678e4b50f9SClemens Ladisch 	cycles = card->split_timeout_hi * 8000 + (card->split_timeout_lo >> 19);
11688e4b50f9SClemens Ladisch 
11694ec4a67aSStefan Richter 	/* minimum per IEEE 1394, maximum which doesn't overflow OHCI */
11704ec4a67aSStefan Richter 	cycles = clamp(cycles, 800u, 3u * 8000u);
11718e4b50f9SClemens Ladisch 
11728e4b50f9SClemens Ladisch 	card->split_timeout_cycles = cycles;
11738e4b50f9SClemens Ladisch 	card->split_timeout_jiffies = DIV_ROUND_UP(cycles * HZ, 8000);
11748e4b50f9SClemens Ladisch }
11758e4b50f9SClemens Ladisch 
handle_registers(struct fw_card * card,struct fw_request * request,int tcode,int destination,int source,int generation,unsigned long long offset,void * payload,size_t length,void * callback_data)1176e71d31daSStefan Richter static void handle_registers(struct fw_card *card, struct fw_request *request,
1177e71d31daSStefan Richter 		int tcode, int destination, int source, int generation,
117833e553feSStefan Richter 		unsigned long long offset, void *payload, size_t length,
117933e553feSStefan Richter 		void *callback_data)
1180e71d31daSStefan Richter {
1181e71d31daSStefan Richter 	int reg = offset & ~CSR_REGISTER_BASE;
1182e71d31daSStefan Richter 	__be32 *data = payload;
1183e71d31daSStefan Richter 	int rcode = RCODE_COMPLETE;
11848e4b50f9SClemens Ladisch 	unsigned long flags;
1185e71d31daSStefan Richter 
1186e71d31daSStefan Richter 	switch (reg) {
1187b384cf18SStefan Richter 	case CSR_PRIORITY_BUDGET:
1188b384cf18SStefan Richter 		if (!card->priority_budget_implemented) {
1189b384cf18SStefan Richter 			rcode = RCODE_ADDRESS_ERROR;
11903e07ec0eSClemens Ladisch 			break;
1191b384cf18SStefan Richter 		}
1192df561f66SGustavo A. R. Silva 		fallthrough;
11933e07ec0eSClemens Ladisch 
1194506f1a31SClemens Ladisch 	case CSR_NODE_IDS:
119565b2742aSStefan Richter 		/*
119665b2742aSStefan Richter 		 * per IEEE 1394-2008 8.3.22.3, not IEEE 1394.1-2004 3.2.8
119765b2742aSStefan Richter 		 * and 9.6, but interoperable with IEEE 1394.1-2004 bridges
119865b2742aSStefan Richter 		 */
1199df561f66SGustavo A. R. Silva 		fallthrough;
1200b384cf18SStefan Richter 
1201b384cf18SStefan Richter 	case CSR_STATE_CLEAR:
1202b384cf18SStefan Richter 	case CSR_STATE_SET:
1203b384cf18SStefan Richter 	case CSR_CYCLE_TIME:
1204b384cf18SStefan Richter 	case CSR_BUS_TIME:
1205b384cf18SStefan Richter 	case CSR_BUSY_TIMEOUT:
1206506f1a31SClemens Ladisch 		if (tcode == TCODE_READ_QUADLET_REQUEST)
12070fcff4e3SStefan Richter 			*data = cpu_to_be32(card->driver->read_csr(card, reg));
1208506f1a31SClemens Ladisch 		else if (tcode == TCODE_WRITE_QUADLET_REQUEST)
12090fcff4e3SStefan Richter 			card->driver->write_csr(card, reg, be32_to_cpu(*data));
1210506f1a31SClemens Ladisch 		else
1211506f1a31SClemens Ladisch 			rcode = RCODE_TYPE_ERROR;
1212506f1a31SClemens Ladisch 		break;
1213506f1a31SClemens Ladisch 
1214446eba0dSClemens Ladisch 	case CSR_RESET_START:
12157e0e314fSClemens Ladisch 		if (tcode == TCODE_WRITE_QUADLET_REQUEST)
12160fcff4e3SStefan Richter 			card->driver->write_csr(card, CSR_STATE_CLEAR,
1217c8a94dedSStefan Richter 						CSR_STATE_BIT_ABDICATE);
12187e0e314fSClemens Ladisch 		else
1219446eba0dSClemens Ladisch 			rcode = RCODE_TYPE_ERROR;
1220446eba0dSClemens Ladisch 		break;
1221446eba0dSClemens Ladisch 
12228e4b50f9SClemens Ladisch 	case CSR_SPLIT_TIMEOUT_HI:
12238e4b50f9SClemens Ladisch 		if (tcode == TCODE_READ_QUADLET_REQUEST) {
12248e4b50f9SClemens Ladisch 			*data = cpu_to_be32(card->split_timeout_hi);
12258e4b50f9SClemens Ladisch 		} else if (tcode == TCODE_WRITE_QUADLET_REQUEST) {
12268e4b50f9SClemens Ladisch 			spin_lock_irqsave(&card->lock, flags);
12278e4b50f9SClemens Ladisch 			card->split_timeout_hi = be32_to_cpu(*data) & 7;
12288e4b50f9SClemens Ladisch 			update_split_timeout(card);
12298e4b50f9SClemens Ladisch 			spin_unlock_irqrestore(&card->lock, flags);
12308e4b50f9SClemens Ladisch 		} else {
12318e4b50f9SClemens Ladisch 			rcode = RCODE_TYPE_ERROR;
12328e4b50f9SClemens Ladisch 		}
12338e4b50f9SClemens Ladisch 		break;
12348e4b50f9SClemens Ladisch 
12358e4b50f9SClemens Ladisch 	case CSR_SPLIT_TIMEOUT_LO:
12368e4b50f9SClemens Ladisch 		if (tcode == TCODE_READ_QUADLET_REQUEST) {
12378e4b50f9SClemens Ladisch 			*data = cpu_to_be32(card->split_timeout_lo);
12388e4b50f9SClemens Ladisch 		} else if (tcode == TCODE_WRITE_QUADLET_REQUEST) {
12398e4b50f9SClemens Ladisch 			spin_lock_irqsave(&card->lock, flags);
12408e4b50f9SClemens Ladisch 			card->split_timeout_lo =
12418e4b50f9SClemens Ladisch 					be32_to_cpu(*data) & 0xfff80000;
12428e4b50f9SClemens Ladisch 			update_split_timeout(card);
12438e4b50f9SClemens Ladisch 			spin_unlock_irqrestore(&card->lock, flags);
12448e4b50f9SClemens Ladisch 		} else {
12458e4b50f9SClemens Ladisch 			rcode = RCODE_TYPE_ERROR;
12468e4b50f9SClemens Ladisch 		}
12478e4b50f9SClemens Ladisch 		break;
12488e4b50f9SClemens Ladisch 
12493d1f46ebSClemens Ladisch 	case CSR_MAINT_UTILITY:
12503d1f46ebSClemens Ladisch 		if (tcode == TCODE_READ_QUADLET_REQUEST)
12513d1f46ebSClemens Ladisch 			*data = card->maint_utility_register;
12523d1f46ebSClemens Ladisch 		else if (tcode == TCODE_WRITE_QUADLET_REQUEST)
12533d1f46ebSClemens Ladisch 			card->maint_utility_register = *data;
12543d1f46ebSClemens Ladisch 		else
12553d1f46ebSClemens Ladisch 			rcode = RCODE_TYPE_ERROR;
12563d1f46ebSClemens Ladisch 		break;
12573d1f46ebSClemens Ladisch 
1258e71d31daSStefan Richter 	case CSR_BROADCAST_CHANNEL:
1259e71d31daSStefan Richter 		if (tcode == TCODE_READ_QUADLET_REQUEST)
1260e71d31daSStefan Richter 			*data = cpu_to_be32(card->broadcast_channel);
1261e71d31daSStefan Richter 		else if (tcode == TCODE_WRITE_QUADLET_REQUEST)
1262e71d31daSStefan Richter 			card->broadcast_channel =
1263e71d31daSStefan Richter 			    (be32_to_cpu(*data) & BROADCAST_CHANNEL_VALID) |
1264e71d31daSStefan Richter 			    BROADCAST_CHANNEL_INITIAL;
1265e71d31daSStefan Richter 		else
1266e71d31daSStefan Richter 			rcode = RCODE_TYPE_ERROR;
1267e71d31daSStefan Richter 		break;
1268e71d31daSStefan Richter 
1269e71d31daSStefan Richter 	case CSR_BUS_MANAGER_ID:
1270e71d31daSStefan Richter 	case CSR_BANDWIDTH_AVAILABLE:
1271e71d31daSStefan Richter 	case CSR_CHANNELS_AVAILABLE_HI:
1272e71d31daSStefan Richter 	case CSR_CHANNELS_AVAILABLE_LO:
1273e71d31daSStefan Richter 		/*
1274e71d31daSStefan Richter 		 * FIXME: these are handled by the OHCI hardware and
1275e71d31daSStefan Richter 		 * the stack never sees these request. If we add
1276e71d31daSStefan Richter 		 * support for a new type of controller that doesn't
1277e71d31daSStefan Richter 		 * handle this in hardware we need to deal with these
1278e71d31daSStefan Richter 		 * transactions.
1279e71d31daSStefan Richter 		 */
1280e71d31daSStefan Richter 		BUG();
1281e71d31daSStefan Richter 		break;
1282e71d31daSStefan Richter 
1283e71d31daSStefan Richter 	default:
1284e71d31daSStefan Richter 		rcode = RCODE_ADDRESS_ERROR;
1285e71d31daSStefan Richter 		break;
1286e71d31daSStefan Richter 	}
1287e71d31daSStefan Richter 
1288e71d31daSStefan Richter 	fw_send_response(card, request, rcode);
1289e71d31daSStefan Richter }
1290e71d31daSStefan Richter 
1291e71d31daSStefan Richter static struct fw_address_handler registers = {
1292e71d31daSStefan Richter 	.length			= 0x400,
1293e71d31daSStefan Richter 	.address_callback	= handle_registers,
1294e71d31daSStefan Richter };
1295e71d31daSStefan Richter 
handle_low_memory(struct fw_card * card,struct fw_request * request,int tcode,int destination,int source,int generation,unsigned long long offset,void * payload,size_t length,void * callback_data)1296f07d42acSClemens Ladisch static void handle_low_memory(struct fw_card *card, struct fw_request *request,
1297f07d42acSClemens Ladisch 		int tcode, int destination, int source, int generation,
1298f07d42acSClemens Ladisch 		unsigned long long offset, void *payload, size_t length,
1299f07d42acSClemens Ladisch 		void *callback_data)
1300f07d42acSClemens Ladisch {
1301f07d42acSClemens Ladisch 	/*
1302f07d42acSClemens Ladisch 	 * This catches requests not handled by the physical DMA unit,
1303f07d42acSClemens Ladisch 	 * i.e., wrong transaction types or unauthorized source nodes.
1304f07d42acSClemens Ladisch 	 */
1305f07d42acSClemens Ladisch 	fw_send_response(card, request, RCODE_TYPE_ERROR);
1306f07d42acSClemens Ladisch }
1307f07d42acSClemens Ladisch 
1308f07d42acSClemens Ladisch static struct fw_address_handler low_memory = {
1309fcd46b34SStefan Richter 	.length			= FW_MAX_PHYSICAL_RANGE,
1310f07d42acSClemens Ladisch 	.address_callback	= handle_low_memory,
1311f07d42acSClemens Ladisch };
1312f07d42acSClemens Ladisch 
1313e71d31daSStefan Richter MODULE_AUTHOR("Kristian Hoegsberg <krh@bitplanet.net>");
1314e71d31daSStefan Richter MODULE_DESCRIPTION("Core IEEE1394 transaction logic");
1315e71d31daSStefan Richter MODULE_LICENSE("GPL");
1316e71d31daSStefan Richter 
1317e71d31daSStefan Richter static const u32 vendor_textual_descriptor[] = {
1318e71d31daSStefan Richter 	/* textual descriptor leaf () */
1319e71d31daSStefan Richter 	0x00060000,
1320e71d31daSStefan Richter 	0x00000000,
1321e71d31daSStefan Richter 	0x00000000,
1322e71d31daSStefan Richter 	0x4c696e75,		/* L i n u */
1323e71d31daSStefan Richter 	0x78204669,		/* x   F i */
1324e71d31daSStefan Richter 	0x72657769,		/* r e w i */
1325e71d31daSStefan Richter 	0x72650000,		/* r e     */
1326e71d31daSStefan Richter };
1327e71d31daSStefan Richter 
1328e71d31daSStefan Richter static const u32 model_textual_descriptor[] = {
1329e71d31daSStefan Richter 	/* model descriptor leaf () */
1330e71d31daSStefan Richter 	0x00030000,
1331e71d31daSStefan Richter 	0x00000000,
1332e71d31daSStefan Richter 	0x00000000,
1333e71d31daSStefan Richter 	0x4a756a75,		/* J u j u */
1334e71d31daSStefan Richter };
1335e71d31daSStefan Richter 
1336e71d31daSStefan Richter static struct fw_descriptor vendor_id_descriptor = {
1337e71d31daSStefan Richter 	.length = ARRAY_SIZE(vendor_textual_descriptor),
1338d71e6a11SClemens Ladisch 	.immediate = 0x03001f11,
1339e71d31daSStefan Richter 	.key = 0x81000000,
1340e71d31daSStefan Richter 	.data = vendor_textual_descriptor,
1341e71d31daSStefan Richter };
1342e71d31daSStefan Richter 
1343e71d31daSStefan Richter static struct fw_descriptor model_id_descriptor = {
1344e71d31daSStefan Richter 	.length = ARRAY_SIZE(model_textual_descriptor),
1345d71e6a11SClemens Ladisch 	.immediate = 0x17023901,
1346e71d31daSStefan Richter 	.key = 0x81000000,
1347e71d31daSStefan Richter 	.data = model_textual_descriptor,
1348e71d31daSStefan Richter };
1349e71d31daSStefan Richter 
fw_core_init(void)1350e71d31daSStefan Richter static int __init fw_core_init(void)
1351e71d31daSStefan Richter {
1352e71d31daSStefan Richter 	int ret;
1353e71d31daSStefan Richter 
13544e6b9319STejun Heo 	fw_workqueue = alloc_workqueue("firewire", WQ_MEM_RECLAIM, 0);
1355105e53f8SStefan Richter 	if (!fw_workqueue)
13566ea9e7bbSStefan Richter 		return -ENOMEM;
13576ea9e7bbSStefan Richter 
1358e71d31daSStefan Richter 	ret = bus_register(&fw_bus_type);
13596ea9e7bbSStefan Richter 	if (ret < 0) {
1360105e53f8SStefan Richter 		destroy_workqueue(fw_workqueue);
1361e71d31daSStefan Richter 		return ret;
13626ea9e7bbSStefan Richter 	}
1363e71d31daSStefan Richter 
1364e71d31daSStefan Richter 	fw_cdev_major = register_chrdev(0, "firewire", &fw_device_ops);
1365e71d31daSStefan Richter 	if (fw_cdev_major < 0) {
1366e71d31daSStefan Richter 		bus_unregister(&fw_bus_type);
1367105e53f8SStefan Richter 		destroy_workqueue(fw_workqueue);
1368e71d31daSStefan Richter 		return fw_cdev_major;
1369e71d31daSStefan Richter 	}
1370e71d31daSStefan Richter 
1371e71d31daSStefan Richter 	fw_core_add_address_handler(&topology_map, &topology_map_region);
1372e71d31daSStefan Richter 	fw_core_add_address_handler(&registers, &registers_region);
1373f07d42acSClemens Ladisch 	fw_core_add_address_handler(&low_memory, &low_memory_region);
1374e71d31daSStefan Richter 	fw_core_add_descriptor(&vendor_id_descriptor);
1375e71d31daSStefan Richter 	fw_core_add_descriptor(&model_id_descriptor);
1376e71d31daSStefan Richter 
1377e71d31daSStefan Richter 	return 0;
1378e71d31daSStefan Richter }
1379e71d31daSStefan Richter 
fw_core_cleanup(void)1380e71d31daSStefan Richter static void __exit fw_core_cleanup(void)
1381e71d31daSStefan Richter {
1382e71d31daSStefan Richter 	unregister_chrdev(fw_cdev_major, "firewire");
1383e71d31daSStefan Richter 	bus_unregister(&fw_bus_type);
1384105e53f8SStefan Richter 	destroy_workqueue(fw_workqueue);
1385e71d31daSStefan Richter 	idr_destroy(&fw_device_idr);
1386e71d31daSStefan Richter }
1387e71d31daSStefan Richter 
1388e71d31daSStefan Richter module_init(fw_core_init);
1389e71d31daSStefan Richter module_exit(fw_core_cleanup);
1390