Blame view

drivers/firewire/core-transaction.c 35.4 KB
c781c06d1   Kristian Høgsberg   firewire: Clean u...
1
2
  /*
   * Core IEEE1394 transaction logic
3038e353c   Kristian Høgsberg   firewire: Add cor...
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
   *
   * Copyright (C) 2004-2006 Kristian Hoegsberg <krh@bitplanet.net>
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License, or
   * (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software Foundation,
   * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
   */
e8ca97021   Stefan Richter   firewire: clean u...
20
  #include <linux/bug.h>
2a0a25904   Stefan Richter   firewire: wait un...
21
  #include <linux/completion.h>
e8ca97021   Stefan Richter   firewire: clean u...
22
23
  #include <linux/device.h>
  #include <linux/errno.h>
77c9a5daa   Stefan Richter   firewire: reorgan...
24
  #include <linux/firewire.h>
e8ca97021   Stefan Richter   firewire: clean u...
25
26
27
  #include <linux/firewire-constants.h>
  #include <linux/fs.h>
  #include <linux/init.h>
d6053e08f   Stefan Richter   firewire: fix sma...
28
  #include <linux/idr.h>
e8ca97021   Stefan Richter   firewire: clean u...
29
  #include <linux/jiffies.h>
3038e353c   Kristian Høgsberg   firewire: Add cor...
30
  #include <linux/kernel.h>
3038e353c   Kristian Høgsberg   firewire: Add cor...
31
  #include <linux/list.h>
e8ca97021   Stefan Richter   firewire: clean u...
32
  #include <linux/module.h>
35202f7d8   Peter Hurley   firewire: remove ...
33
  #include <linux/rculist.h>
e8ca97021   Stefan Richter   firewire: clean u...
34
35
36
37
38
  #include <linux/slab.h>
  #include <linux/spinlock.h>
  #include <linux/string.h>
  #include <linux/timer.h>
  #include <linux/types.h>
6ea9e7bbf   Stefan Richter   firewire: core: u...
39
  #include <linux/workqueue.h>
e8ca97021   Stefan Richter   firewire: clean u...
40
41
  
  #include <asm/byteorder.h>
3038e353c   Kristian Høgsberg   firewire: Add cor...
42

77c9a5daa   Stefan Richter   firewire: reorgan...
43
  #include "core.h"
3038e353c   Kristian Høgsberg   firewire: Add cor...
44

a77754a75   Kristian Høgsberg   firewire: Upperca...
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
  #define HEADER_PRI(pri)			((pri) << 0)
  #define HEADER_TCODE(tcode)		((tcode) << 4)
  #define HEADER_RETRY(retry)		((retry) << 8)
  #define HEADER_TLABEL(tlabel)		((tlabel) << 10)
  #define HEADER_DESTINATION(destination)	((destination) << 16)
  #define HEADER_SOURCE(source)		((source) << 16)
  #define HEADER_RCODE(rcode)		((rcode) << 12)
  #define HEADER_OFFSET_HIGH(offset_high)	((offset_high) << 0)
  #define HEADER_DATA_LENGTH(length)	((length) << 16)
  #define HEADER_EXTENDED_TCODE(tcode)	((tcode) << 0)
  
  #define HEADER_GET_TCODE(q)		(((q) >> 4) & 0x0f)
  #define HEADER_GET_TLABEL(q)		(((q) >> 10) & 0x3f)
  #define HEADER_GET_RCODE(q)		(((q) >> 12) & 0x0f)
  #define HEADER_GET_DESTINATION(q)	(((q) >> 16) & 0xffff)
  #define HEADER_GET_SOURCE(q)		(((q) >> 16) & 0xffff)
  #define HEADER_GET_OFFSET_HIGH(q)	(((q) >> 0) & 0xffff)
  #define HEADER_GET_DATA_LENGTH(q)	(((q) >> 16) & 0xffff)
  #define HEADER_GET_EXTENDED_TCODE(q)	(((q) >> 0) & 0xffff)
a7ea67823   Stefan Richter   firewire: don't r...
64
65
  #define HEADER_DESTINATION_IS_BROADCAST(q) \
  	(((q) & HEADER_DESTINATION(0x3f)) == HEADER_DESTINATION(0x3f))
77c9a5daa   Stefan Richter   firewire: reorgan...
66
67
68
  #define PHY_PACKET_CONFIG	0x0
  #define PHY_PACKET_LINK_ON	0x1
  #define PHY_PACKET_SELF_ID	0x2
a77754a75   Kristian Høgsberg   firewire: Upperca...
69
70
71
  #define PHY_CONFIG_GAP_COUNT(gap_count)	(((gap_count) << 16) | (1 << 22))
  #define PHY_CONFIG_ROOT_ID(node_id)	((((node_id) & 0x3f) << 24) | (1 << 23))
  #define PHY_IDENTIFIER(id)		((id) << 30)
3038e353c   Kristian Høgsberg   firewire: Add cor...
72

410cf2bd3   Clemens Ladisch   firewire: use spl...
73
74
75
76
77
78
79
80
  /* returns 0 if the split timeout handler is already running */
  static int try_cancel_split_timeout(struct fw_transaction *t)
  {
  	if (t->is_split_transaction)
  		return del_timer(&t->split_timeout_timer);
  	else
  		return 1;
  }
53dca5117   Stefan Richter   firewire: remove ...
81
  static int close_transaction(struct fw_transaction *transaction,
a38a00fde   Stefan Richter   firewire: core: d...
82
  			     struct fw_card *card, int rcode)
3038e353c   Kristian Høgsberg   firewire: Add cor...
83
  {
730c32f58   Kristian Høgsberg   firewire: Impleme...
84
  	struct fw_transaction *t;
3038e353c   Kristian Høgsberg   firewire: Add cor...
85
86
87
  	unsigned long flags;
  
  	spin_lock_irqsave(&card->lock, flags);
730c32f58   Kristian Høgsberg   firewire: Impleme...
88
89
  	list_for_each_entry(t, &card->transaction_list, link) {
  		if (t == transaction) {
410cf2bd3   Clemens Ladisch   firewire: use spl...
90
  			if (!try_cancel_split_timeout(t)) {
2222bcb76   Clemens Ladisch   firewire: core: d...
91
92
93
  				spin_unlock_irqrestore(&card->lock, flags);
  				goto timed_out;
  			}
5c40cbfef   Clemens Ladisch   firewire: core: u...
94
  			list_del_init(&t->link);
1e626fdce   Stefan Richter   firewire: core: u...
95
  			card->tlabel_mask &= ~(1ULL << t->tlabel);
730c32f58   Kristian Høgsberg   firewire: Impleme...
96
97
98
  			break;
  		}
  	}
3038e353c   Kristian Høgsberg   firewire: Add cor...
99
  	spin_unlock_irqrestore(&card->lock, flags);
730c32f58   Kristian Høgsberg   firewire: Impleme...
100
  	if (&t->link != &card->transaction_list) {
a38a00fde   Stefan Richter   firewire: core: d...
101
  		t->callback(card, rcode, NULL, 0, t->callback_data);
730c32f58   Kristian Høgsberg   firewire: Impleme...
102
103
  		return 0;
  	}
2222bcb76   Clemens Ladisch   firewire: core: d...
104
   timed_out:
730c32f58   Kristian Høgsberg   firewire: Impleme...
105
  	return -ENOENT;
3038e353c   Kristian Høgsberg   firewire: Add cor...
106
  }
c781c06d1   Kristian Høgsberg   firewire: Clean u...
107
108
109
110
  /*
   * Only valid for transactions that are potentially pending (ie have
   * been sent).
   */
53dca5117   Stefan Richter   firewire: remove ...
111
112
  int fw_cancel_transaction(struct fw_card *card,
  			  struct fw_transaction *transaction)
730c32f58   Kristian Høgsberg   firewire: Impleme...
113
  {
c781c06d1   Kristian Høgsberg   firewire: Clean u...
114
115
  	/*
  	 * Cancel the packet transmission if it's still queued.  That
730c32f58   Kristian Høgsberg   firewire: Impleme...
116
  	 * will call the packet transmission callback which cancels
c781c06d1   Kristian Høgsberg   firewire: Clean u...
117
118
  	 * the transaction.
  	 */
730c32f58   Kristian Høgsberg   firewire: Impleme...
119
120
121
  
  	if (card->driver->cancel_packet(card, &transaction->packet) == 0)
  		return 0;
c781c06d1   Kristian Høgsberg   firewire: Clean u...
122
123
124
125
  	/*
  	 * If the request packet has already been sent, we need to see
  	 * if the transaction is still pending and remove it in that case.
  	 */
730c32f58   Kristian Høgsberg   firewire: Impleme...
126

a38a00fde   Stefan Richter   firewire: core: d...
127
  	return close_transaction(transaction, card, RCODE_CANCELLED);
730c32f58   Kristian Høgsberg   firewire: Impleme...
128
129
  }
  EXPORT_SYMBOL(fw_cancel_transaction);
5c40cbfef   Clemens Ladisch   firewire: core: u...
130
131
132
133
134
135
136
137
138
139
140
141
142
143
  static void split_transaction_timeout_callback(unsigned long data)
  {
  	struct fw_transaction *t = (struct fw_transaction *)data;
  	struct fw_card *card = t->card;
  	unsigned long flags;
  
  	spin_lock_irqsave(&card->lock, flags);
  	if (list_empty(&t->link)) {
  		spin_unlock_irqrestore(&card->lock, flags);
  		return;
  	}
  	list_del(&t->link);
  	card->tlabel_mask &= ~(1ULL << t->tlabel);
  	spin_unlock_irqrestore(&card->lock, flags);
5c40cbfef   Clemens Ladisch   firewire: core: u...
144
145
  	t->callback(card, RCODE_CANCELLED, NULL, 0, t->callback_data);
  }
410cf2bd3   Clemens Ladisch   firewire: use spl...
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
  static void start_split_transaction_timeout(struct fw_transaction *t,
  					    struct fw_card *card)
  {
  	unsigned long flags;
  
  	spin_lock_irqsave(&card->lock, flags);
  
  	if (list_empty(&t->link) || WARN_ON(t->is_split_transaction)) {
  		spin_unlock_irqrestore(&card->lock, flags);
  		return;
  	}
  
  	t->is_split_transaction = true;
  	mod_timer(&t->split_timeout_timer,
  		  jiffies + card->split_timeout_jiffies);
  
  	spin_unlock_irqrestore(&card->lock, flags);
  }
53dca5117   Stefan Richter   firewire: remove ...
164
165
  static void transmit_complete_callback(struct fw_packet *packet,
  				       struct fw_card *card, int status)
3038e353c   Kristian Høgsberg   firewire: Add cor...
166
167
168
169
170
171
  {
  	struct fw_transaction *t =
  	    container_of(packet, struct fw_transaction, packet);
  
  	switch (status) {
  	case ACK_COMPLETE:
a38a00fde   Stefan Richter   firewire: core: d...
172
  		close_transaction(t, card, RCODE_COMPLETE);
3038e353c   Kristian Høgsberg   firewire: Add cor...
173
174
  		break;
  	case ACK_PENDING:
410cf2bd3   Clemens Ladisch   firewire: use spl...
175
  		start_split_transaction_timeout(t, card);
3038e353c   Kristian Høgsberg   firewire: Add cor...
176
177
178
179
  		break;
  	case ACK_BUSY_X:
  	case ACK_BUSY_A:
  	case ACK_BUSY_B:
a38a00fde   Stefan Richter   firewire: core: d...
180
  		close_transaction(t, card, RCODE_BUSY);
3038e353c   Kristian Høgsberg   firewire: Add cor...
181
182
  		break;
  	case ACK_DATA_ERROR:
a38a00fde   Stefan Richter   firewire: core: d...
183
  		close_transaction(t, card, RCODE_DATA_ERROR);
e5f49c3b8   Kristian Høgsberg   firewire: Sanitiz...
184
  		break;
3038e353c   Kristian Høgsberg   firewire: Add cor...
185
  	case ACK_TYPE_ERROR:
a38a00fde   Stefan Richter   firewire: core: d...
186
  		close_transaction(t, card, RCODE_TYPE_ERROR);
3038e353c   Kristian Høgsberg   firewire: Add cor...
187
188
  		break;
  	default:
c781c06d1   Kristian Høgsberg   firewire: Clean u...
189
190
191
192
  		/*
  		 * In this case the ack is really a juju specific
  		 * rcode, so just forward that to the callback.
  		 */
a38a00fde   Stefan Richter   firewire: core: d...
193
  		close_transaction(t, card, status);
3038e353c   Kristian Høgsberg   firewire: Add cor...
194
195
196
  		break;
  	}
  }
53dca5117   Stefan Richter   firewire: remove ...
197
  static void fw_fill_request(struct fw_packet *packet, int tcode, int tlabel,
b9549bc68   Stefan Richter   firewire: small f...
198
  		int destination_id, int source_id, int generation, int speed,
36bfe49d0   Kristian Høgsberg   firewire: Clean u...
199
  		unsigned long long offset, void *payload, size_t length)
3038e353c   Kristian Høgsberg   firewire: Add cor...
200
201
  {
  	int ext_tcode;
18e9b10fc   Stefan Richter   firewire: cdev: a...
202
203
204
205
206
207
208
209
210
211
212
  	if (tcode == TCODE_STREAM_DATA) {
  		packet->header[0] =
  			HEADER_DATA_LENGTH(length) |
  			destination_id |
  			HEADER_TCODE(TCODE_STREAM_DATA);
  		packet->header_length = 4;
  		packet->payload = payload;
  		packet->payload_length = length;
  
  		goto common;
  	}
3038e353c   Kristian Høgsberg   firewire: Add cor...
213
  	if (tcode > 0x10) {
8f9f963e5   Jarod Wilson   firewire: replace...
214
  		ext_tcode = tcode & ~0x10;
3038e353c   Kristian Høgsberg   firewire: Add cor...
215
216
217
218
219
  		tcode = TCODE_LOCK_REQUEST;
  	} else
  		ext_tcode = 0;
  
  	packet->header[0] =
a77754a75   Kristian Høgsberg   firewire: Upperca...
220
221
222
  		HEADER_RETRY(RETRY_X) |
  		HEADER_TLABEL(tlabel) |
  		HEADER_TCODE(tcode) |
b9549bc68   Stefan Richter   firewire: small f...
223
  		HEADER_DESTINATION(destination_id);
3038e353c   Kristian Høgsberg   firewire: Add cor...
224
  	packet->header[1] =
a77754a75   Kristian Høgsberg   firewire: Upperca...
225
  		HEADER_OFFSET_HIGH(offset >> 32) | HEADER_SOURCE(source_id);
3038e353c   Kristian Høgsberg   firewire: Add cor...
226
227
228
229
230
231
232
233
234
235
236
237
238
  	packet->header[2] =
  		offset;
  
  	switch (tcode) {
  	case TCODE_WRITE_QUADLET_REQUEST:
  		packet->header[3] = *(u32 *)payload;
  		packet->header_length = 16;
  		packet->payload_length = 0;
  		break;
  
  	case TCODE_LOCK_REQUEST:
  	case TCODE_WRITE_BLOCK_REQUEST:
  		packet->header[3] =
a77754a75   Kristian Høgsberg   firewire: Upperca...
239
240
  			HEADER_DATA_LENGTH(length) |
  			HEADER_EXTENDED_TCODE(ext_tcode);
3038e353c   Kristian Høgsberg   firewire: Add cor...
241
242
243
244
245
246
247
248
249
250
251
252
  		packet->header_length = 16;
  		packet->payload = payload;
  		packet->payload_length = length;
  		break;
  
  	case TCODE_READ_QUADLET_REQUEST:
  		packet->header_length = 12;
  		packet->payload_length = 0;
  		break;
  
  	case TCODE_READ_BLOCK_REQUEST:
  		packet->header[3] =
a77754a75   Kristian Høgsberg   firewire: Upperca...
253
254
  			HEADER_DATA_LENGTH(length) |
  			HEADER_EXTENDED_TCODE(ext_tcode);
3038e353c   Kristian Høgsberg   firewire: Add cor...
255
256
257
  		packet->header_length = 16;
  		packet->payload_length = 0;
  		break;
5b189bf36   Stefan Richter   firewire: core: W...
258
259
  
  	default:
5878730be   Joe Perches   firewire: core: U...
260
261
  		WARN(1, "wrong tcode %d
  ", tcode);
3038e353c   Kristian Høgsberg   firewire: Add cor...
262
  	}
18e9b10fc   Stefan Richter   firewire: cdev: a...
263
   common:
3038e353c   Kristian Høgsberg   firewire: Add cor...
264
265
  	packet->speed = speed;
  	packet->generation = generation;
730c32f58   Kristian Høgsberg   firewire: Impleme...
266
  	packet->ack = 0;
19593ffdb   Stefan Richter   firewire: ohci: 0...
267
  	packet->payload_mapped = false;
3038e353c   Kristian Høgsberg   firewire: Add cor...
268
  }
7906054f0   Clemens Ladisch   firewire: core: m...
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
  static int allocate_tlabel(struct fw_card *card)
  {
  	int tlabel;
  
  	tlabel = card->current_tlabel;
  	while (card->tlabel_mask & (1ULL << tlabel)) {
  		tlabel = (tlabel + 1) & 0x3f;
  		if (tlabel == card->current_tlabel)
  			return -EBUSY;
  	}
  
  	card->current_tlabel = (tlabel + 1) & 0x3f;
  	card->tlabel_mask |= 1ULL << tlabel;
  
  	return tlabel;
  }
3038e353c   Kristian Høgsberg   firewire: Add cor...
285
  /**
656b7afd4   Stefan Richter   firewire: core: f...
286
287
288
289
290
291
292
293
294
295
296
297
   * fw_send_request() - submit a request packet for transmission
   * @card:		interface to send the request at
   * @t:			transaction instance to which the request belongs
   * @tcode:		transaction code
   * @destination_id:	destination node ID, consisting of bus_ID and phy_ID
   * @generation:		bus generation in which request and response are valid
   * @speed:		transmission speed
   * @offset:		48bit wide offset into destination's address space
   * @payload:		data payload for the request subaction
   * @length:		length of the payload, in bytes
   * @callback:		function to be called when the transaction is completed
   * @callback_data:	data to be passed to the transaction completion callback
3038e353c   Kristian Høgsberg   firewire: Add cor...
298
   *
656b7afd4   Stefan Richter   firewire: core: f...
299
300
301
   * Submit a request packet into the asynchronous request transmission queue.
   * Can be called from atomic context.  If you prefer a blocking API, use
   * fw_run_transaction() in a context that can sleep.
3038e353c   Kristian Høgsberg   firewire: Add cor...
302
   *
656b7afd4   Stefan Richter   firewire: core: f...
303
304
   * In case of lock requests, specify one of the firewire-core specific %TCODE_
   * constants instead of %TCODE_LOCK_REQUEST in @tcode.
3038e353c   Kristian Høgsberg   firewire: Add cor...
305
   *
656b7afd4   Stefan Richter   firewire: core: f...
306
307
   * Make sure that the value in @destination_id is not older than the one in
   * @generation.  Otherwise the request is in danger to be sent to a wrong node.
3038e353c   Kristian Høgsberg   firewire: Add cor...
308
   *
656b7afd4   Stefan Richter   firewire: core: f...
309
   * In case of asynchronous stream packets i.e. %TCODE_STREAM_DATA, the caller
18e9b10fc   Stefan Richter   firewire: cdev: a...
310
   * needs to synthesize @destination_id with fw_stream_packet_destination_id().
656b7afd4   Stefan Richter   firewire: core: f...
311
312
313
   * It will contain tag, channel, and sy data instead of a node ID then.
   *
   * The payload buffer at @data is going to be DMA-mapped except in case of
f30e6d3e4   Stefan Richter   firewire: octlet ...
314
315
   * @length <= 8 or of local (loopback) requests.  Hence make sure that the
   * buffer complies with the restrictions of the streaming DMA mapping API.
656b7afd4   Stefan Richter   firewire: core: f...
316
317
318
319
320
321
322
   * @payload must not be freed before the @callback is called.
   *
   * In case of request types without payload, @data is NULL and @length is 0.
   *
   * After the transaction is completed successfully or unsuccessfully, the
   * @callback will be called.  Among its parameters is the response code which
   * is either one of the rcodes per IEEE 1394 or, in case of internal errors,
18d0cdfd1   Stefan Richter   firewire: normali...
323
324
325
326
   * the firewire-core specific %RCODE_SEND_ERROR.  The other firewire-core
   * specific rcodes (%RCODE_CANCELLED, %RCODE_BUSY, %RCODE_GENERATION,
   * %RCODE_NO_ACK) denote transaction timeout, busy responder, stale request
   * generation, or missing ACK respectively.
656b7afd4   Stefan Richter   firewire: core: f...
327
328
329
330
331
   *
   * Note some timing corner cases:  fw_send_request() may complete much earlier
   * than when the request packet actually hits the wire.  On the other hand,
   * transaction completion and hence execution of @callback may happen even
   * before fw_send_request() returns.
3038e353c   Kristian Høgsberg   firewire: Add cor...
332
   */
53dca5117   Stefan Richter   firewire: remove ...
333
334
335
336
  void 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,
  		     fw_transaction_callback_t callback, void *callback_data)
3038e353c   Kristian Høgsberg   firewire: Add cor...
337
338
  {
  	unsigned long flags;
b9549bc68   Stefan Richter   firewire: small f...
339
  	int tlabel;
3038e353c   Kristian Høgsberg   firewire: Add cor...
340

c781c06d1   Kristian Høgsberg   firewire: Clean u...
341
  	/*
c781c06d1   Kristian Høgsberg   firewire: Clean u...
342
343
344
  	 * Allocate tlabel from the bitmap and put the transaction on
  	 * the list while holding the card spinlock.
  	 */
3038e353c   Kristian Høgsberg   firewire: Add cor...
345
346
  
  	spin_lock_irqsave(&card->lock, flags);
7906054f0   Clemens Ladisch   firewire: core: m...
347
348
  	tlabel = allocate_tlabel(card);
  	if (tlabel < 0) {
3038e353c   Kristian Høgsberg   firewire: Add cor...
349
350
351
352
  		spin_unlock_irqrestore(&card->lock, flags);
  		callback(card, RCODE_SEND_ERROR, NULL, 0, callback_data);
  		return;
  	}
1e119fa99   Jay Fenlason   firewire: fw_send...
353
  	t->node_id = destination_id;
3038e353c   Kristian Høgsberg   firewire: Add cor...
354
  	t->tlabel = tlabel;
5c40cbfef   Clemens Ladisch   firewire: core: u...
355
  	t->card = card;
410cf2bd3   Clemens Ladisch   firewire: use spl...
356
  	t->is_split_transaction = false;
5c40cbfef   Clemens Ladisch   firewire: core: u...
357
358
  	setup_timer(&t->split_timeout_timer,
  		    split_transaction_timeout_callback, (unsigned long)t);
3038e353c   Kristian Høgsberg   firewire: Add cor...
359
360
  	t->callback = callback;
  	t->callback_data = callback_data;
1e119fa99   Jay Fenlason   firewire: fw_send...
361
362
363
  	fw_fill_request(&t->packet, tcode, t->tlabel,
  			destination_id, card->node_id, generation,
  			speed, offset, payload, length);
3038e353c   Kristian Høgsberg   firewire: Add cor...
364
  	t->packet.callback = transmit_complete_callback;
e9aeb46c9   Stefan Richter   firewire: fully i...
365
366
367
  	list_add_tail(&t->link, &card->transaction_list);
  
  	spin_unlock_irqrestore(&card->lock, flags);
3038e353c   Kristian Høgsberg   firewire: Add cor...
368
369
370
  	card->driver->send_request(card, &t->packet);
  }
  EXPORT_SYMBOL(fw_send_request);
1e119fa99   Jay Fenlason   firewire: fw_send...
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
  struct transaction_callback_data {
  	struct completion done;
  	void *payload;
  	int rcode;
  };
  
  static void transaction_callback(struct fw_card *card, int rcode,
  				 void *payload, size_t length, void *data)
  {
  	struct transaction_callback_data *d = data;
  
  	if (rcode == RCODE_COMPLETE)
  		memcpy(d->payload, payload, length);
  	d->rcode = rcode;
  	complete(&d->done);
  }
  
  /**
656b7afd4   Stefan Richter   firewire: core: f...
389
   * fw_run_transaction() - send request and sleep until transaction is completed
1e119fa99   Jay Fenlason   firewire: fw_send...
390
   *
656b7afd4   Stefan Richter   firewire: core: f...
391
392
   * Returns the RCODE.  See fw_send_request() for parameter documentation.
   * Unlike fw_send_request(), @data points to the payload of the request or/and
f30e6d3e4   Stefan Richter   firewire: octlet ...
393
394
   * to the payload of the response.  DMA mapping restrictions apply to outbound
   * request payloads of >= 8 bytes but not to inbound response payloads.
1e119fa99   Jay Fenlason   firewire: fw_send...
395
396
   */
  int fw_run_transaction(struct fw_card *card, int tcode, int destination_id,
53dca5117   Stefan Richter   firewire: remove ...
397
  		       int generation, int speed, unsigned long long offset,
ba27e1f7b   Stefan Richter   firewire: core: n...
398
  		       void *payload, size_t length)
1e119fa99   Jay Fenlason   firewire: fw_send...
399
400
401
  {
  	struct transaction_callback_data d;
  	struct fw_transaction t;
5c40cbfef   Clemens Ladisch   firewire: core: u...
402
  	init_timer_on_stack(&t.split_timeout_timer);
1e119fa99   Jay Fenlason   firewire: fw_send...
403
  	init_completion(&d.done);
ba27e1f7b   Stefan Richter   firewire: core: n...
404
  	d.payload = payload;
1e119fa99   Jay Fenlason   firewire: fw_send...
405
  	fw_send_request(card, &t, tcode, destination_id, generation, speed,
ba27e1f7b   Stefan Richter   firewire: core: n...
406
  			offset, payload, length, transaction_callback, &d);
1e119fa99   Jay Fenlason   firewire: fw_send...
407
  	wait_for_completion(&d.done);
5c40cbfef   Clemens Ladisch   firewire: core: u...
408
  	destroy_timer_on_stack(&t.split_timeout_timer);
1e119fa99   Jay Fenlason   firewire: fw_send...
409
410
411
412
  
  	return d.rcode;
  }
  EXPORT_SYMBOL(fw_run_transaction);
c0220d686   Stefan Richter   firewire: avoid m...
413
414
  static DEFINE_MUTEX(phy_config_mutex);
  static DECLARE_COMPLETION(phy_config_done);
ae1e53557   Stefan Richter   firewire: deadlin...
415
416
417
  
  static void transmit_phy_packet_callback(struct fw_packet *packet,
  					 struct fw_card *card, int status)
3038e353c   Kristian Høgsberg   firewire: Add cor...
418
  {
c0220d686   Stefan Richter   firewire: avoid m...
419
  	complete(&phy_config_done);
3038e353c   Kristian Høgsberg   firewire: Add cor...
420
  }
c0220d686   Stefan Richter   firewire: avoid m...
421
  static struct fw_packet phy_config_packet = {
5b06db166   Clemens Ladisch   firewire: make PH...
422
423
  	.header_length	= 12,
  	.header[0]	= TCODE_LINK_INTERNAL << 4,
c0220d686   Stefan Richter   firewire: avoid m...
424
425
426
427
  	.payload_length	= 0,
  	.speed		= SCODE_100,
  	.callback	= transmit_phy_packet_callback,
  };
83db801ce   Kristian Høgsberg   firewire: Impleme...
428
429
  void fw_send_phy_config(struct fw_card *card,
  			int node_id, int generation, int gap_count)
3038e353c   Kristian Høgsberg   firewire: Add cor...
430
  {
ae1e53557   Stefan Richter   firewire: deadlin...
431
  	long timeout = DIV_ROUND_UP(HZ, 10);
02d37bed1   Stefan Richter   firewire: core: i...
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
  	u32 data = PHY_IDENTIFIER(PHY_PACKET_CONFIG);
  
  	if (node_id != FW_PHY_CONFIG_NO_NODE_ID)
  		data |= PHY_CONFIG_ROOT_ID(node_id);
  
  	if (gap_count == FW_PHY_CONFIG_CURRENT_GAP_COUNT) {
  		gap_count = card->driver->read_phy_reg(card, 1);
  		if (gap_count < 0)
  			return;
  
  		gap_count &= 63;
  		if (gap_count == 63)
  			return;
  	}
  	data |= PHY_CONFIG_GAP_COUNT(gap_count);
2a0a25904   Stefan Richter   firewire: wait un...
447

c0220d686   Stefan Richter   firewire: avoid m...
448
  	mutex_lock(&phy_config_mutex);
5b06db166   Clemens Ladisch   firewire: make PH...
449
450
  	phy_config_packet.header[1] = data;
  	phy_config_packet.header[2] = ~data;
c0220d686   Stefan Richter   firewire: avoid m...
451
  	phy_config_packet.generation = generation;
16735d022   Wolfram Sang   tree-wide: use re...
452
  	reinit_completion(&phy_config_done);
c0220d686   Stefan Richter   firewire: avoid m...
453
454
455
  
  	card->driver->send_request(card, &phy_config_packet);
  	wait_for_completion_timeout(&phy_config_done, timeout);
ae1e53557   Stefan Richter   firewire: deadlin...
456

c0220d686   Stefan Richter   firewire: avoid m...
457
  	mutex_unlock(&phy_config_mutex);
3038e353c   Kristian Høgsberg   firewire: Add cor...
458
  }
53dca5117   Stefan Richter   firewire: remove ...
459
460
  static struct fw_address_handler *lookup_overlapping_address_handler(
  	struct list_head *list, unsigned long long offset, size_t length)
3038e353c   Kristian Høgsberg   firewire: Add cor...
461
462
  {
  	struct fw_address_handler *handler;
35202f7d8   Peter Hurley   firewire: remove ...
463
  	list_for_each_entry_rcu(handler, list, link) {
3038e353c   Kristian Høgsberg   firewire: Add cor...
464
465
466
467
468
469
470
  		if (handler->offset < offset + length &&
  		    offset < handler->offset + handler->length)
  			return handler;
  	}
  
  	return NULL;
  }
db5d247ae   Clemens Ladisch   firewire: fix use...
471
472
473
474
475
476
  static bool is_enclosing_handler(struct fw_address_handler *handler,
  				 unsigned long long offset, size_t length)
  {
  	return handler->offset <= offset &&
  		offset + length <= handler->offset + handler->length;
  }
53dca5117   Stefan Richter   firewire: remove ...
477
478
  static struct fw_address_handler *lookup_enclosing_address_handler(
  	struct list_head *list, unsigned long long offset, size_t length)
3038e353c   Kristian Høgsberg   firewire: Add cor...
479
480
  {
  	struct fw_address_handler *handler;
35202f7d8   Peter Hurley   firewire: remove ...
481
  	list_for_each_entry_rcu(handler, list, link) {
db5d247ae   Clemens Ladisch   firewire: fix use...
482
  		if (is_enclosing_handler(handler, offset, length))
3038e353c   Kristian Høgsberg   firewire: Add cor...
483
484
485
486
487
  			return handler;
  	}
  
  	return NULL;
  }
4d50c4438   Stefan Richter   firewire: addendu...
488
  static DEFINE_SPINLOCK(address_handler_list_lock);
3038e353c   Kristian Høgsberg   firewire: Add cor...
489
  static LIST_HEAD(address_handler_list);
21ebcd122   Stefan Richter   firewire: mark so...
490
  const struct fw_address_region fw_high_memory_region =
fcd46b344   Stefan Richter   firewire: Enable ...
491
  	{ .start = FW_MAX_PHYSICAL_RANGE, .end = 0xffffe0000000ULL, };
db8be076c   Adrian Bunk   firewire: cleanups
492
  EXPORT_SYMBOL(fw_high_memory_region);
f07d42ac7   Clemens Ladisch   firewire: core: a...
493
  static const struct fw_address_region low_memory_region =
fcd46b344   Stefan Richter   firewire: Enable ...
494
  	{ .start = 0x000000000000ULL, .end = FW_MAX_PHYSICAL_RANGE, };
f07d42ac7   Clemens Ladisch   firewire: core: a...
495
496
  
  #if 0
21ebcd122   Stefan Richter   firewire: mark so...
497
  const struct fw_address_region fw_private_region =
5af4e5eab   Stefan Richter   firewire: comma a...
498
  	{ .start = 0xffffe0000000ULL, .end = 0xfffff0000000ULL,  };
21ebcd122   Stefan Richter   firewire: mark so...
499
  const struct fw_address_region fw_csr_region =
cca609771   Jarod Wilson   firewire: replace...
500
501
  	{ .start = CSR_REGISTER_BASE,
  	  .end   = CSR_REGISTER_BASE | CSR_CONFIG_ROM_END,  };
21ebcd122   Stefan Richter   firewire: mark so...
502
  const struct fw_address_region fw_unit_space_region =
5af4e5eab   Stefan Richter   firewire: comma a...
503
  	{ .start = 0xfffff0000900ULL, .end = 0x1000000000000ULL, };
db8be076c   Adrian Bunk   firewire: cleanups
504
  #endif  /*  0  */
3038e353c   Kristian Høgsberg   firewire: Add cor...
505

db5d247ae   Clemens Ladisch   firewire: fix use...
506
507
508
509
510
  static bool is_in_fcp_region(u64 offset, size_t length)
  {
  	return offset >= (CSR_REGISTER_BASE | CSR_FCP_COMMAND) &&
  		offset + length <= (CSR_REGISTER_BASE | CSR_FCP_END);
  }
3038e353c   Kristian Høgsberg   firewire: Add cor...
511
  /**
656b7afd4   Stefan Richter   firewire: core: f...
512
513
514
   * fw_core_add_address_handler() - register for incoming requests
   * @handler:	callback
   * @region:	region in the IEEE 1212 node space address range
3e0b5f0d7   Stefan Richter   firewire: cdev: a...
515
516
517
518
519
520
   *
   * region->start, ->end, and handler->length have to be quadlet-aligned.
   *
   * When a request is received that falls within the specified address range,
   * the specified callback is invoked.  The parameters passed to the callback
   * give the details of the particular request.
1415d9189   Stefan Richter   firewire: optimiz...
521
   *
4d50c4438   Stefan Richter   firewire: addendu...
522
   * To be called in process context.
1415d9189   Stefan Richter   firewire: optimiz...
523
   * Return value:  0 on success, non-zero otherwise.
db5d247ae   Clemens Ladisch   firewire: fix use...
524
   *
1415d9189   Stefan Richter   firewire: optimiz...
525
526
   * The start offset of the handler's address region is determined by
   * fw_core_add_address_handler() and is returned in handler->offset.
db5d247ae   Clemens Ladisch   firewire: fix use...
527
528
   *
   * Address allocations are exclusive, except for the FCP registers.
3038e353c   Kristian Høgsberg   firewire: Add cor...
529
   */
53dca5117   Stefan Richter   firewire: remove ...
530
531
  int fw_core_add_address_handler(struct fw_address_handler *handler,
  				const struct fw_address_region *region)
3038e353c   Kristian Høgsberg   firewire: Add cor...
532
533
  {
  	struct fw_address_handler *other;
3038e353c   Kristian Høgsberg   firewire: Add cor...
534
  	int ret = -EBUSY;
3e0b5f0d7   Stefan Richter   firewire: cdev: a...
535
  	if (region->start & 0xffff000000000003ULL ||
3e0b5f0d7   Stefan Richter   firewire: cdev: a...
536
  	    region->start >= region->end ||
0c9ae701a   Stefan Richter   firewire: core: f...
537
  	    region->end   > 0x0001000000000000ULL ||
3e0b5f0d7   Stefan Richter   firewire: cdev: a...
538
539
540
  	    handler->length & 3 ||
  	    handler->length == 0)
  		return -EINVAL;
4d50c4438   Stefan Richter   firewire: addendu...
541
  	spin_lock(&address_handler_list_lock);
3038e353c   Kristian Høgsberg   firewire: Add cor...
542

3e0b5f0d7   Stefan Richter   firewire: cdev: a...
543
  	handler->offset = region->start;
3038e353c   Kristian Høgsberg   firewire: Add cor...
544
  	while (handler->offset + handler->length <= region->end) {
db5d247ae   Clemens Ladisch   firewire: fix use...
545
546
547
548
549
550
  		if (is_in_fcp_region(handler->offset, handler->length))
  			other = NULL;
  		else
  			other = lookup_overlapping_address_handler
  					(&address_handler_list,
  					 handler->offset, handler->length);
3038e353c   Kristian Høgsberg   firewire: Add cor...
551
  		if (other != NULL) {
3e0b5f0d7   Stefan Richter   firewire: cdev: a...
552
  			handler->offset += other->length;
3038e353c   Kristian Høgsberg   firewire: Add cor...
553
  		} else {
35202f7d8   Peter Hurley   firewire: remove ...
554
  			list_add_tail_rcu(&handler->link, &address_handler_list);
3038e353c   Kristian Høgsberg   firewire: Add cor...
555
556
557
558
  			ret = 0;
  			break;
  		}
  	}
4d50c4438   Stefan Richter   firewire: addendu...
559
  	spin_unlock(&address_handler_list_lock);
3038e353c   Kristian Høgsberg   firewire: Add cor...
560
561
562
  
  	return ret;
  }
3038e353c   Kristian Høgsberg   firewire: Add cor...
563
564
565
  EXPORT_SYMBOL(fw_core_add_address_handler);
  
  /**
656b7afd4   Stefan Richter   firewire: core: f...
566
   * fw_core_remove_address_handler() - unregister an address handler
90963f1cd   Stefan Richter   firewire: core: f...
567
   *
4d50c4438   Stefan Richter   firewire: addendu...
568
569
   * To be called in process context.
   *
90963f1cd   Stefan Richter   firewire: core: f...
570
571
   * When fw_core_remove_address_handler() returns, @handler->callback() is
   * guaranteed to not run on any CPU anymore.
3038e353c   Kristian Høgsberg   firewire: Add cor...
572
   */
3038e353c   Kristian Høgsberg   firewire: Add cor...
573
574
  void fw_core_remove_address_handler(struct fw_address_handler *handler)
  {
4d50c4438   Stefan Richter   firewire: addendu...
575
  	spin_lock(&address_handler_list_lock);
35202f7d8   Peter Hurley   firewire: remove ...
576
  	list_del_rcu(&handler->link);
4d50c4438   Stefan Richter   firewire: addendu...
577
  	spin_unlock(&address_handler_list_lock);
35202f7d8   Peter Hurley   firewire: remove ...
578
  	synchronize_rcu();
3038e353c   Kristian Høgsberg   firewire: Add cor...
579
  }
3038e353c   Kristian Høgsberg   firewire: Add cor...
580
581
582
583
  EXPORT_SYMBOL(fw_core_remove_address_handler);
  
  struct fw_request {
  	struct fw_packet response;
36bfe49d0   Kristian Høgsberg   firewire: Clean u...
584
  	u32 request_header[4];
3038e353c   Kristian Høgsberg   firewire: Add cor...
585
586
587
588
  	int ack;
  	u32 length;
  	u32 data[0];
  };
53dca5117   Stefan Richter   firewire: remove ...
589
590
  static void free_response_callback(struct fw_packet *packet,
  				   struct fw_card *card, int status)
3038e353c   Kristian Høgsberg   firewire: Add cor...
591
592
593
594
595
596
  {
  	struct fw_request *request;
  
  	request = container_of(packet, struct fw_request, response);
  	kfree(request);
  }
a10c0ce76   Clemens Ladisch   firewire: check c...
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
  int fw_get_response_length(struct fw_request *r)
  {
  	int tcode, ext_tcode, data_length;
  
  	tcode = HEADER_GET_TCODE(r->request_header[0]);
  
  	switch (tcode) {
  	case TCODE_WRITE_QUADLET_REQUEST:
  	case TCODE_WRITE_BLOCK_REQUEST:
  		return 0;
  
  	case TCODE_READ_QUADLET_REQUEST:
  		return 4;
  
  	case TCODE_READ_BLOCK_REQUEST:
  		data_length = HEADER_GET_DATA_LENGTH(r->request_header[3]);
  		return data_length;
  
  	case TCODE_LOCK_REQUEST:
  		ext_tcode = HEADER_GET_EXTENDED_TCODE(r->request_header[3]);
  		data_length = HEADER_GET_DATA_LENGTH(r->request_header[3]);
  		switch (ext_tcode) {
  		case EXTCODE_FETCH_ADD:
  		case EXTCODE_LITTLE_ADD:
  			return data_length;
  		default:
  			return data_length / 2;
  		}
  
  	default:
5878730be   Joe Perches   firewire: core: U...
627
628
  		WARN(1, "wrong tcode %d
  ", tcode);
a10c0ce76   Clemens Ladisch   firewire: check c...
629
630
631
  		return 0;
  	}
  }
53dca5117   Stefan Richter   firewire: remove ...
632
633
  void fw_fill_response(struct fw_packet *response, u32 *request_header,
  		      int rcode, void *payload, size_t length)
3038e353c   Kristian Høgsberg   firewire: Add cor...
634
635
  {
  	int tcode, tlabel, extended_tcode, source, destination;
a77754a75   Kristian Høgsberg   firewire: Upperca...
636
637
638
639
640
  	tcode          = HEADER_GET_TCODE(request_header[0]);
  	tlabel         = HEADER_GET_TLABEL(request_header[0]);
  	source         = HEADER_GET_DESTINATION(request_header[0]);
  	destination    = HEADER_GET_SOURCE(request_header[1]);
  	extended_tcode = HEADER_GET_EXTENDED_TCODE(request_header[3]);
3038e353c   Kristian Høgsberg   firewire: Add cor...
641
642
  
  	response->header[0] =
a77754a75   Kristian Høgsberg   firewire: Upperca...
643
644
645
  		HEADER_RETRY(RETRY_1) |
  		HEADER_TLABEL(tlabel) |
  		HEADER_DESTINATION(destination);
36bfe49d0   Kristian Høgsberg   firewire: Clean u...
646
  	response->header[1] =
a77754a75   Kristian Høgsberg   firewire: Upperca...
647
648
  		HEADER_SOURCE(source) |
  		HEADER_RCODE(rcode);
3038e353c   Kristian Høgsberg   firewire: Add cor...
649
650
651
652
653
  	response->header[2] = 0;
  
  	switch (tcode) {
  	case TCODE_WRITE_QUADLET_REQUEST:
  	case TCODE_WRITE_BLOCK_REQUEST:
a77754a75   Kristian Høgsberg   firewire: Upperca...
654
  		response->header[0] |= HEADER_TCODE(TCODE_WRITE_RESPONSE);
3038e353c   Kristian Høgsberg   firewire: Add cor...
655
656
657
658
659
660
  		response->header_length = 12;
  		response->payload_length = 0;
  		break;
  
  	case TCODE_READ_QUADLET_REQUEST:
  		response->header[0] |=
a77754a75   Kristian Høgsberg   firewire: Upperca...
661
  			HEADER_TCODE(TCODE_READ_QUADLET_RESPONSE);
93c4cceb9   Kristian Høgsberg   firewire: Handle ...
662
663
664
665
  		if (payload != NULL)
  			response->header[3] = *(u32 *)payload;
  		else
  			response->header[3] = 0;
3038e353c   Kristian Høgsberg   firewire: Add cor...
666
667
668
669
670
671
  		response->header_length = 16;
  		response->payload_length = 0;
  		break;
  
  	case TCODE_READ_BLOCK_REQUEST:
  	case TCODE_LOCK_REQUEST:
a77754a75   Kristian Høgsberg   firewire: Upperca...
672
  		response->header[0] |= HEADER_TCODE(tcode + 2);
3038e353c   Kristian Høgsberg   firewire: Add cor...
673
  		response->header[3] =
a77754a75   Kristian Høgsberg   firewire: Upperca...
674
675
  			HEADER_DATA_LENGTH(length) |
  			HEADER_EXTENDED_TCODE(extended_tcode);
3038e353c   Kristian Høgsberg   firewire: Add cor...
676
  		response->header_length = 16;
36bfe49d0   Kristian Høgsberg   firewire: Clean u...
677
678
  		response->payload = payload;
  		response->payload_length = length;
3038e353c   Kristian Høgsberg   firewire: Add cor...
679
680
681
  		break;
  
  	default:
5878730be   Joe Perches   firewire: core: U...
682
683
  		WARN(1, "wrong tcode %d
  ", tcode);
3038e353c   Kristian Høgsberg   firewire: Add cor...
684
  	}
1d1dc5e83   Stefan Richter   firewire: fw-ohci...
685

19593ffdb   Stefan Richter   firewire: ohci: 0...
686
  	response->payload_mapped = false;
3038e353c   Kristian Høgsberg   firewire: Add cor...
687
  }
93c4cceb9   Kristian Høgsberg   firewire: Handle ...
688
  EXPORT_SYMBOL(fw_fill_response);
3038e353c   Kristian Høgsberg   firewire: Add cor...
689

8e4b50f94   Clemens Ladisch   firewire: core: a...
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
  static u32 compute_split_timeout_timestamp(struct fw_card *card,
  					   u32 request_timestamp)
  {
  	unsigned int cycles;
  	u32 timestamp;
  
  	cycles = card->split_timeout_cycles;
  	cycles += request_timestamp & 0x1fff;
  
  	timestamp = request_timestamp & ~0x1fff;
  	timestamp += (cycles / 8000) << 13;
  	timestamp |= cycles % 8000;
  
  	return timestamp;
  }
  
  static struct fw_request *allocate_request(struct fw_card *card,
  					   struct fw_packet *p)
3038e353c   Kristian Høgsberg   firewire: Add cor...
708
709
710
  {
  	struct fw_request *request;
  	u32 *data, length;
8e4b50f94   Clemens Ladisch   firewire: core: a...
711
  	int request_tcode;
3038e353c   Kristian Høgsberg   firewire: Add cor...
712

a77754a75   Kristian Høgsberg   firewire: Upperca...
713
  	request_tcode = HEADER_GET_TCODE(p->header[0]);
3038e353c   Kristian Høgsberg   firewire: Add cor...
714
715
  	switch (request_tcode) {
  	case TCODE_WRITE_QUADLET_REQUEST:
2639a6fb2   Kristian Høgsberg   firewire: Use str...
716
  		data = &p->header[3];
3038e353c   Kristian Høgsberg   firewire: Add cor...
717
718
719
720
721
  		length = 4;
  		break;
  
  	case TCODE_WRITE_BLOCK_REQUEST:
  	case TCODE_LOCK_REQUEST:
2639a6fb2   Kristian Høgsberg   firewire: Use str...
722
  		data = p->payload;
a77754a75   Kristian Høgsberg   firewire: Upperca...
723
  		length = HEADER_GET_DATA_LENGTH(p->header[3]);
3038e353c   Kristian Høgsberg   firewire: Add cor...
724
725
726
727
728
729
730
731
732
  		break;
  
  	case TCODE_READ_QUADLET_REQUEST:
  		data = NULL;
  		length = 4;
  		break;
  
  	case TCODE_READ_BLOCK_REQUEST:
  		data = NULL;
a77754a75   Kristian Høgsberg   firewire: Upperca...
733
  		length = HEADER_GET_DATA_LENGTH(p->header[3]);
3038e353c   Kristian Høgsberg   firewire: Add cor...
734
735
736
  		break;
  
  	default:
26b4950de   Stefan Richter   firewire: core: p...
737
738
  		fw_notice(card, "ERROR - corrupt request received - %08x %08x %08x
  ",
0bf607c5b   Stefan Richter   firewire: don't p...
739
  			 p->header[0], p->header[1], p->header[2]);
3038e353c   Kristian Høgsberg   firewire: Add cor...
740
741
  		return NULL;
  	}
2d826cc5c   Kristian Høgsberg   firewire: Always ...
742
  	request = kmalloc(sizeof(*request) + length, GFP_ATOMIC);
3038e353c   Kristian Høgsberg   firewire: Add cor...
743
744
  	if (request == NULL)
  		return NULL;
2639a6fb2   Kristian Høgsberg   firewire: Use str...
745
  	request->response.speed = p->speed;
8e4b50f94   Clemens Ladisch   firewire: core: a...
746
747
  	request->response.timestamp =
  			compute_split_timeout_timestamp(card, p->timestamp);
2639a6fb2   Kristian Høgsberg   firewire: Use str...
748
  	request->response.generation = p->generation;
730c32f58   Kristian Høgsberg   firewire: Impleme...
749
  	request->response.ack = 0;
3038e353c   Kristian Høgsberg   firewire: Add cor...
750
  	request->response.callback = free_response_callback;
2639a6fb2   Kristian Høgsberg   firewire: Use str...
751
  	request->ack = p->ack;
93c4cceb9   Kristian Høgsberg   firewire: Handle ...
752
  	request->length = length;
3038e353c   Kristian Høgsberg   firewire: Add cor...
753
  	if (data)
6e2e8424d   Kristian Høgsberg   firewire: Use cor...
754
  		memcpy(request->data, data, length);
3038e353c   Kristian Høgsberg   firewire: Add cor...
755

2d826cc5c   Kristian Høgsberg   firewire: Always ...
756
  	memcpy(request->request_header, p->header, sizeof(p->header));
3038e353c   Kristian Høgsberg   firewire: Add cor...
757
758
759
  
  	return request;
  }
53dca5117   Stefan Richter   firewire: remove ...
760
761
  void fw_send_response(struct fw_card *card,
  		      struct fw_request *request, int rcode)
3038e353c   Kristian Høgsberg   firewire: Add cor...
762
  {
db5d247ae   Clemens Ladisch   firewire: fix use...
763
764
  	if (WARN_ONCE(!request, "invalid for FCP address handlers"))
  		return;
a7ea67823   Stefan Richter   firewire: don't r...
765
766
767
  	/* unified transaction or broadcast transaction: don't respond */
  	if (request->ack != ACK_PENDING ||
  	    HEADER_DESTINATION_IS_BROADCAST(request->request_header[0])) {
9c9bdf4d5   Stefan Richter   firewire: fix mem...
768
  		kfree(request);
3038e353c   Kristian Høgsberg   firewire: Add cor...
769
  		return;
9c9bdf4d5   Stefan Richter   firewire: fix mem...
770
  	}
3038e353c   Kristian Høgsberg   firewire: Add cor...
771

36bfe49d0   Kristian Høgsberg   firewire: Clean u...
772
773
  	if (rcode == RCODE_COMPLETE)
  		fw_fill_response(&request->response, request->request_header,
a10c0ce76   Clemens Ladisch   firewire: check c...
774
775
  				 rcode, request->data,
  				 fw_get_response_length(request));
36bfe49d0   Kristian Høgsberg   firewire: Clean u...
776
777
778
  	else
  		fw_fill_response(&request->response, request->request_header,
  				 rcode, NULL, 0);
3038e353c   Kristian Høgsberg   firewire: Add cor...
779
780
781
  
  	card->driver->send_response(card, &request->response);
  }
3038e353c   Kristian Høgsberg   firewire: Add cor...
782
  EXPORT_SYMBOL(fw_send_response);
253d92371   Chris Boot   firewire: Add fun...
783
784
785
786
787
788
789
790
  /**
   * fw_get_request_speed() - returns speed at which the @request was received
   */
  int fw_get_request_speed(struct fw_request *request)
  {
  	return request->response.speed;
  }
  EXPORT_SYMBOL(fw_get_request_speed);
db5d247ae   Clemens Ladisch   firewire: fix use...
791
792
793
794
  static void handle_exclusive_region_request(struct fw_card *card,
  					    struct fw_packet *p,
  					    struct fw_request *request,
  					    unsigned long long offset)
3038e353c   Kristian Høgsberg   firewire: Add cor...
795
796
  {
  	struct fw_address_handler *handler;
2639a6fb2   Kristian Høgsberg   firewire: Use str...
797
  	int tcode, destination, source;
3038e353c   Kristian Høgsberg   firewire: Add cor...
798

a77754a75   Kristian Høgsberg   firewire: Upperca...
799
  	destination = HEADER_GET_DESTINATION(p->header[0]);
478b233ed   Rabin Vincent   firewire: Fix ext...
800
  	source      = HEADER_GET_SOURCE(p->header[1]);
c82f91f26   Jay Fenlason   firewire: expose ...
801
802
803
  	tcode       = HEADER_GET_TCODE(p->header[0]);
  	if (tcode == TCODE_LOCK_REQUEST)
  		tcode = 0x10 + HEADER_GET_EXTENDED_TCODE(p->header[3]);
3038e353c   Kristian Høgsberg   firewire: Add cor...
804

35202f7d8   Peter Hurley   firewire: remove ...
805
  	rcu_read_lock();
3038e353c   Kristian Høgsberg   firewire: Add cor...
806
807
  	handler = lookup_enclosing_address_handler(&address_handler_list,
  						   offset, request->length);
90963f1cd   Stefan Richter   firewire: core: f...
808
  	if (handler)
3038e353c   Kristian Høgsberg   firewire: Add cor...
809
810
  		handler->address_callback(card, request,
  					  tcode, destination, source,
33e553fe2   Stefan Richter   firewire: remove ...
811
  					  p->generation, offset,
3038e353c   Kristian Høgsberg   firewire: Add cor...
812
813
  					  request->data, request->length,
  					  handler->callback_data);
35202f7d8   Peter Hurley   firewire: remove ...
814
  	rcu_read_unlock();
90963f1cd   Stefan Richter   firewire: core: f...
815
816
817
  
  	if (!handler)
  		fw_send_response(card, request, RCODE_ADDRESS_ERROR);
3038e353c   Kristian Høgsberg   firewire: Add cor...
818
  }
db5d247ae   Clemens Ladisch   firewire: fix use...
819
820
821
822
823
824
825
  
  static void handle_fcp_region_request(struct fw_card *card,
  				      struct fw_packet *p,
  				      struct fw_request *request,
  				      unsigned long long offset)
  {
  	struct fw_address_handler *handler;
db5d247ae   Clemens Ladisch   firewire: fix use...
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
  	int tcode, destination, source;
  
  	if ((offset != (CSR_REGISTER_BASE | CSR_FCP_COMMAND) &&
  	     offset != (CSR_REGISTER_BASE | CSR_FCP_RESPONSE)) ||
  	    request->length > 0x200) {
  		fw_send_response(card, request, RCODE_ADDRESS_ERROR);
  
  		return;
  	}
  
  	tcode       = HEADER_GET_TCODE(p->header[0]);
  	destination = HEADER_GET_DESTINATION(p->header[0]);
  	source      = HEADER_GET_SOURCE(p->header[1]);
  
  	if (tcode != TCODE_WRITE_QUADLET_REQUEST &&
  	    tcode != TCODE_WRITE_BLOCK_REQUEST) {
  		fw_send_response(card, request, RCODE_TYPE_ERROR);
  
  		return;
  	}
35202f7d8   Peter Hurley   firewire: remove ...
846
847
  	rcu_read_lock();
  	list_for_each_entry_rcu(handler, &address_handler_list, link) {
db5d247ae   Clemens Ladisch   firewire: fix use...
848
849
850
  		if (is_enclosing_handler(handler, offset, request->length))
  			handler->address_callback(card, NULL, tcode,
  						  destination, source,
33e553fe2   Stefan Richter   firewire: remove ...
851
852
  						  p->generation, offset,
  						  request->data,
db5d247ae   Clemens Ladisch   firewire: fix use...
853
854
855
  						  request->length,
  						  handler->callback_data);
  	}
35202f7d8   Peter Hurley   firewire: remove ...
856
  	rcu_read_unlock();
db5d247ae   Clemens Ladisch   firewire: fix use...
857
858
859
860
861
862
863
864
865
866
867
  
  	fw_send_response(card, request, RCODE_COMPLETE);
  }
  
  void fw_core_handle_request(struct fw_card *card, struct fw_packet *p)
  {
  	struct fw_request *request;
  	unsigned long long offset;
  
  	if (p->ack != ACK_PENDING && p->ack != ACK_COMPLETE)
  		return;
bf54e1462   Stefan Richter   firewire: cdev: a...
868
869
870
871
  	if (TCODE_IS_LINK_INTERNAL(HEADER_GET_TCODE(p->header[0]))) {
  		fw_cdev_handle_phy_packet(card, p);
  		return;
  	}
8e4b50f94   Clemens Ladisch   firewire: core: a...
872
  	request = allocate_request(card, p);
db5d247ae   Clemens Ladisch   firewire: fix use...
873
874
875
876
877
878
879
880
881
882
883
884
885
886
  	if (request == NULL) {
  		/* FIXME: send statically allocated busy packet. */
  		return;
  	}
  
  	offset = ((u64)HEADER_GET_OFFSET_HIGH(p->header[1]) << 32) |
  		p->header[2];
  
  	if (!is_in_fcp_region(offset, request->length))
  		handle_exclusive_region_request(card, p, request, offset);
  	else
  		handle_fcp_region_request(card, p, request, offset);
  
  }
3038e353c   Kristian Høgsberg   firewire: Add cor...
887
  EXPORT_SYMBOL(fw_core_handle_request);
53dca5117   Stefan Richter   firewire: remove ...
888
  void fw_core_handle_response(struct fw_card *card, struct fw_packet *p)
3038e353c   Kristian Høgsberg   firewire: Add cor...
889
890
891
892
893
  {
  	struct fw_transaction *t;
  	unsigned long flags;
  	u32 *data;
  	size_t data_length;
ae86e81e4   Stefan Richter   firewire: core: r...
894
  	int tcode, tlabel, source, rcode;
3038e353c   Kristian Høgsberg   firewire: Add cor...
895

ae86e81e4   Stefan Richter   firewire: core: r...
896
897
898
899
  	tcode	= HEADER_GET_TCODE(p->header[0]);
  	tlabel	= HEADER_GET_TLABEL(p->header[0]);
  	source	= HEADER_GET_SOURCE(p->header[1]);
  	rcode	= HEADER_GET_RCODE(p->header[1]);
3038e353c   Kristian Høgsberg   firewire: Add cor...
900
901
902
903
  
  	spin_lock_irqsave(&card->lock, flags);
  	list_for_each_entry(t, &card->transaction_list, link) {
  		if (t->node_id == source && t->tlabel == tlabel) {
410cf2bd3   Clemens Ladisch   firewire: use spl...
904
  			if (!try_cancel_split_timeout(t)) {
2222bcb76   Clemens Ladisch   firewire: core: d...
905
906
907
  				spin_unlock_irqrestore(&card->lock, flags);
  				goto timed_out;
  			}
5c40cbfef   Clemens Ladisch   firewire: core: u...
908
  			list_del_init(&t->link);
753a8970f   Peter Hurley   firewire: core: F...
909
  			card->tlabel_mask &= ~(1ULL << t->tlabel);
3038e353c   Kristian Høgsberg   firewire: Add cor...
910
911
912
913
914
915
  			break;
  		}
  	}
  	spin_unlock_irqrestore(&card->lock, flags);
  
  	if (&t->link == &card->transaction_list) {
2222bcb76   Clemens Ladisch   firewire: core: d...
916
   timed_out:
26b4950de   Stefan Richter   firewire: core: p...
917
918
  		fw_notice(card, "unsolicited response (source %x, tlabel %x)
  ",
32b46093a   Kristian Høgsberg   firewire: Rework ...
919
  			  source, tlabel);
3038e353c   Kristian Høgsberg   firewire: Add cor...
920
921
  		return;
  	}
c781c06d1   Kristian Høgsberg   firewire: Clean u...
922
923
924
925
  	/*
  	 * FIXME: sanity check packet, is length correct, does tcodes
  	 * and addresses match.
  	 */
3038e353c   Kristian Høgsberg   firewire: Add cor...
926
927
928
  
  	switch (tcode) {
  	case TCODE_READ_QUADLET_RESPONSE:
2639a6fb2   Kristian Høgsberg   firewire: Use str...
929
  		data = (u32 *) &p->header[3];
3038e353c   Kristian Høgsberg   firewire: Add cor...
930
931
932
933
934
935
936
937
938
939
  		data_length = 4;
  		break;
  
  	case TCODE_WRITE_RESPONSE:
  		data = NULL;
  		data_length = 0;
  		break;
  
  	case TCODE_READ_BLOCK_RESPONSE:
  	case TCODE_LOCK_RESPONSE:
93c4cceb9   Kristian Høgsberg   firewire: Handle ...
940
  		data = p->payload;
a77754a75   Kristian Høgsberg   firewire: Upperca...
941
  		data_length = HEADER_GET_DATA_LENGTH(p->header[3]);
3038e353c   Kristian Høgsberg   firewire: Add cor...
942
943
944
945
946
947
948
949
  		break;
  
  	default:
  		/* Should never happen, this is just to shut up gcc. */
  		data = NULL;
  		data_length = 0;
  		break;
  	}
10a4c7355   Stefan Richter   firewire: fix pan...
950
951
952
953
954
  	/*
  	 * The response handler may be executed while the request handler
  	 * is still pending.  Cancel the request handler.
  	 */
  	card->driver->cancel_packet(card, &t->packet);
3038e353c   Kristian Høgsberg   firewire: Add cor...
955
956
  	t->callback(card, rcode, data, data_length, t->callback_data);
  }
3038e353c   Kristian Høgsberg   firewire: Add cor...
957
  EXPORT_SYMBOL(fw_core_handle_response);
7bdbff676   Clemens Ladisch   firewire: move rc...
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
  /**
   * fw_rcode_string - convert a firewire result code to an error description
   * @rcode: the result code
   */
  const char *fw_rcode_string(int rcode)
  {
  	static const char *const names[] = {
  		[RCODE_COMPLETE]       = "no error",
  		[RCODE_CONFLICT_ERROR] = "conflict error",
  		[RCODE_DATA_ERROR]     = "data error",
  		[RCODE_TYPE_ERROR]     = "type error",
  		[RCODE_ADDRESS_ERROR]  = "address error",
  		[RCODE_SEND_ERROR]     = "send error",
  		[RCODE_CANCELLED]      = "timeout",
  		[RCODE_BUSY]           = "busy",
  		[RCODE_GENERATION]     = "bus reset",
  		[RCODE_NO_ACK]         = "no ack",
  	};
  
  	if ((unsigned int)rcode < ARRAY_SIZE(names) && names[rcode])
  		return names[rcode];
  	else
  		return "unknown";
  }
  EXPORT_SYMBOL(fw_rcode_string);
ae57988f6   Stefan Richter   firewire: fw-core...
983
  static const struct fw_address_region topology_map_region =
cca609771   Jarod Wilson   firewire: replace...
984
985
  	{ .start = CSR_REGISTER_BASE | CSR_TOPOLOGY_MAP,
  	  .end   = CSR_REGISTER_BASE | CSR_TOPOLOGY_MAP_END, };
473d28c73   Kristian Høgsberg   firewire: Impleme...
986

53dca5117   Stefan Richter   firewire: remove ...
987
988
  static void handle_topology_map(struct fw_card *card, struct fw_request *request,
  		int tcode, int destination, int source, int generation,
33e553fe2   Stefan Richter   firewire: remove ...
989
990
  		unsigned long long offset, void *payload, size_t length,
  		void *callback_data)
473d28c73   Kristian Høgsberg   firewire: Impleme...
991
  {
cb7c96da3   Stefan Richter   firewire: core: o...
992
  	int start;
473d28c73   Kristian Høgsberg   firewire: Impleme...
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
  
  	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;
cb7c96da3   Stefan Richter   firewire: core: o...
1005
  	memcpy(payload, &card->topology_map[start], length);
473d28c73   Kristian Høgsberg   firewire: Impleme...
1006
1007
1008
1009
1010
  
  	fw_send_response(card, request, RCODE_COMPLETE);
  }
  
  static struct fw_address_handler topology_map = {
85cb9b686   Stefan Richter   firewire: core: f...
1011
  	.length			= 0x400,
473d28c73   Kristian Høgsberg   firewire: Impleme...
1012
1013
  	.address_callback	= handle_topology_map,
  };
ae57988f6   Stefan Richter   firewire: fw-core...
1014
  static const struct fw_address_region registers_region =
cca609771   Jarod Wilson   firewire: replace...
1015
1016
  	{ .start = CSR_REGISTER_BASE,
  	  .end   = CSR_REGISTER_BASE | CSR_CONFIG_ROM, };
d60d7f1d5   Kristian Høgsberg   firewire: Impleme...
1017

8e4b50f94   Clemens Ladisch   firewire: core: a...
1018
1019
1020
1021
1022
  static void update_split_timeout(struct fw_card *card)
  {
  	unsigned int cycles;
  
  	cycles = card->split_timeout_hi * 8000 + (card->split_timeout_lo >> 19);
4ec4a67aa   Stefan Richter   firewire: use cla...
1023
1024
  	/* minimum per IEEE 1394, maximum which doesn't overflow OHCI */
  	cycles = clamp(cycles, 800u, 3u * 8000u);
8e4b50f94   Clemens Ladisch   firewire: core: a...
1025
1026
1027
1028
  
  	card->split_timeout_cycles = cycles;
  	card->split_timeout_jiffies = DIV_ROUND_UP(cycles * HZ, 8000);
  }
53dca5117   Stefan Richter   firewire: remove ...
1029
1030
  static void handle_registers(struct fw_card *card, struct fw_request *request,
  		int tcode, int destination, int source, int generation,
33e553fe2   Stefan Richter   firewire: remove ...
1031
1032
  		unsigned long long offset, void *payload, size_t length,
  		void *callback_data)
d60d7f1d5   Kristian Høgsberg   firewire: Impleme...
1033
  {
15f0d833f   Jarod Wilson   firewire: use bit...
1034
  	int reg = offset & ~CSR_REGISTER_BASE;
d60d7f1d5   Kristian Høgsberg   firewire: Impleme...
1035
  	__be32 *data = payload;
e534fe16b   Stefan Richter   firewire: impleme...
1036
  	int rcode = RCODE_COMPLETE;
8e4b50f94   Clemens Ladisch   firewire: core: a...
1037
  	unsigned long flags;
d60d7f1d5   Kristian Høgsberg   firewire: Impleme...
1038
1039
  
  	switch (reg) {
b384cf188   Stefan Richter   firewire: core: c...
1040
1041
1042
1043
1044
1045
  	case CSR_PRIORITY_BUDGET:
  		if (!card->priority_budget_implemented) {
  			rcode = RCODE_ADDRESS_ERROR;
  			break;
  		}
  		/* else fall through */
3e07ec0ee   Clemens Ladisch   firewire: core: a...
1046

506f1a319   Clemens Ladisch   firewire: add CSR...
1047
  	case CSR_NODE_IDS:
65b2742ac   Stefan Richter   firewire: 'add CS...
1048
1049
1050
1051
  		/*
  		 * per IEEE 1394-2008 8.3.22.3, not IEEE 1394.1-2004 3.2.8
  		 * and 9.6, but interoperable with IEEE 1394.1-2004 bridges
  		 */
b384cf188   Stefan Richter   firewire: core: c...
1052
1053
1054
1055
1056
1057
1058
  		/* fall through */
  
  	case CSR_STATE_CLEAR:
  	case CSR_STATE_SET:
  	case CSR_CYCLE_TIME:
  	case CSR_BUS_TIME:
  	case CSR_BUSY_TIMEOUT:
506f1a319   Clemens Ladisch   firewire: add CSR...
1059
  		if (tcode == TCODE_READ_QUADLET_REQUEST)
0fcff4e39   Stefan Richter   firewire: rename ...
1060
  			*data = cpu_to_be32(card->driver->read_csr(card, reg));
506f1a319   Clemens Ladisch   firewire: add CSR...
1061
  		else if (tcode == TCODE_WRITE_QUADLET_REQUEST)
0fcff4e39   Stefan Richter   firewire: rename ...
1062
  			card->driver->write_csr(card, reg, be32_to_cpu(*data));
506f1a319   Clemens Ladisch   firewire: add CSR...
1063
1064
1065
  		else
  			rcode = RCODE_TYPE_ERROR;
  		break;
446eba0d6   Clemens Ladisch   firewire: core: a...
1066
  	case CSR_RESET_START:
7e0e314f1   Clemens Ladisch   firewire: core: a...
1067
  		if (tcode == TCODE_WRITE_QUADLET_REQUEST)
0fcff4e39   Stefan Richter   firewire: rename ...
1068
1069
  			card->driver->write_csr(card, CSR_STATE_CLEAR,
  						CSR_STATE_BIT_ABDICATE);
7e0e314f1   Clemens Ladisch   firewire: core: a...
1070
  		else
446eba0d6   Clemens Ladisch   firewire: core: a...
1071
1072
  			rcode = RCODE_TYPE_ERROR;
  		break;
8e4b50f94   Clemens Ladisch   firewire: core: a...
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
  	case CSR_SPLIT_TIMEOUT_HI:
  		if (tcode == TCODE_READ_QUADLET_REQUEST) {
  			*data = cpu_to_be32(card->split_timeout_hi);
  		} else if (tcode == TCODE_WRITE_QUADLET_REQUEST) {
  			spin_lock_irqsave(&card->lock, flags);
  			card->split_timeout_hi = be32_to_cpu(*data) & 7;
  			update_split_timeout(card);
  			spin_unlock_irqrestore(&card->lock, flags);
  		} else {
  			rcode = RCODE_TYPE_ERROR;
  		}
  		break;
  
  	case CSR_SPLIT_TIMEOUT_LO:
  		if (tcode == TCODE_READ_QUADLET_REQUEST) {
  			*data = cpu_to_be32(card->split_timeout_lo);
  		} else if (tcode == TCODE_WRITE_QUADLET_REQUEST) {
  			spin_lock_irqsave(&card->lock, flags);
  			card->split_timeout_lo =
  					be32_to_cpu(*data) & 0xfff80000;
  			update_split_timeout(card);
  			spin_unlock_irqrestore(&card->lock, flags);
  		} else {
  			rcode = RCODE_TYPE_ERROR;
  		}
  		break;
3d1f46eb6   Clemens Ladisch   firewire: core: a...
1099
1100
1101
1102
1103
1104
1105
1106
  	case CSR_MAINT_UTILITY:
  		if (tcode == TCODE_READ_QUADLET_REQUEST)
  			*data = card->maint_utility_register;
  		else if (tcode == TCODE_WRITE_QUADLET_REQUEST)
  			card->maint_utility_register = *data;
  		else
  			rcode = RCODE_TYPE_ERROR;
  		break;
e534fe16b   Stefan Richter   firewire: impleme...
1107
1108
1109
1110
1111
1112
1113
1114
1115
  	case CSR_BROADCAST_CHANNEL:
  		if (tcode == TCODE_READ_QUADLET_REQUEST)
  			*data = cpu_to_be32(card->broadcast_channel);
  		else if (tcode == TCODE_WRITE_QUADLET_REQUEST)
  			card->broadcast_channel =
  			    (be32_to_cpu(*data) & BROADCAST_CHANNEL_VALID) |
  			    BROADCAST_CHANNEL_INITIAL;
  		else
  			rcode = RCODE_TYPE_ERROR;
d60d7f1d5   Kristian Høgsberg   firewire: Impleme...
1116
1117
1118
1119
1120
1121
  		break;
  
  	case CSR_BUS_MANAGER_ID:
  	case CSR_BANDWIDTH_AVAILABLE:
  	case CSR_CHANNELS_AVAILABLE_HI:
  	case CSR_CHANNELS_AVAILABLE_LO:
c781c06d1   Kristian Høgsberg   firewire: Clean u...
1122
1123
  		/*
  		 * FIXME: these are handled by the OHCI hardware and
d60d7f1d5   Kristian Høgsberg   firewire: Impleme...
1124
1125
1126
  		 * the stack never sees these request. If we add
  		 * support for a new type of controller that doesn't
  		 * handle this in hardware we need to deal with these
c781c06d1   Kristian Høgsberg   firewire: Clean u...
1127
1128
  		 * transactions.
  		 */
d60d7f1d5   Kristian Høgsberg   firewire: Impleme...
1129
1130
  		BUG();
  		break;
d60d7f1d5   Kristian Høgsberg   firewire: Impleme...
1131
  	default:
e534fe16b   Stefan Richter   firewire: impleme...
1132
  		rcode = RCODE_ADDRESS_ERROR;
d60d7f1d5   Kristian Høgsberg   firewire: Impleme...
1133
1134
  		break;
  	}
e534fe16b   Stefan Richter   firewire: impleme...
1135
1136
  
  	fw_send_response(card, request, rcode);
d60d7f1d5   Kristian Høgsberg   firewire: Impleme...
1137
1138
1139
1140
1141
1142
  }
  
  static struct fw_address_handler registers = {
  	.length			= 0x400,
  	.address_callback	= handle_registers,
  };
f07d42ac7   Clemens Ladisch   firewire: core: a...
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
  static void 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)
  {
  	/*
  	 * This catches requests not handled by the physical DMA unit,
  	 * i.e., wrong transaction types or unauthorized source nodes.
  	 */
  	fw_send_response(card, request, RCODE_TYPE_ERROR);
  }
  
  static struct fw_address_handler low_memory = {
fcd46b344   Stefan Richter   firewire: Enable ...
1156
  	.length			= FW_MAX_PHYSICAL_RANGE,
f07d42ac7   Clemens Ladisch   firewire: core: a...
1157
1158
  	.address_callback	= handle_low_memory,
  };
3038e353c   Kristian Høgsberg   firewire: Add cor...
1159
1160
1161
  MODULE_AUTHOR("Kristian Hoegsberg <krh@bitplanet.net>");
  MODULE_DESCRIPTION("Core IEEE1394 transaction logic");
  MODULE_LICENSE("GPL");
937f68796   Kristian Høgsberg   firewire: Let an ...
1162
  static const u32 vendor_textual_descriptor[] = {
3038e353c   Kristian Høgsberg   firewire: Add cor...
1163
  	/* textual descriptor leaf () */
937f68796   Kristian Høgsberg   firewire: Let an ...
1164
  	0x00060000,
3038e353c   Kristian Høgsberg   firewire: Add cor...
1165
1166
1167
1168
1169
  	0x00000000,
  	0x00000000,
  	0x4c696e75,		/* L i n u */
  	0x78204669,		/* x   F i */
  	0x72657769,		/* r e w i */
937f68796   Kristian Høgsberg   firewire: Let an ...
1170
  	0x72650000,		/* r e     */
3038e353c   Kristian Høgsberg   firewire: Add cor...
1171
  };
937f68796   Kristian Høgsberg   firewire: Let an ...
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
  static const u32 model_textual_descriptor[] = {
  	/* model descriptor leaf () */
  	0x00030000,
  	0x00000000,
  	0x00000000,
  	0x4a756a75,		/* J u j u */
  };
  
  static struct fw_descriptor vendor_id_descriptor = {
  	.length = ARRAY_SIZE(vendor_textual_descriptor),
d71e6a117   Clemens Ladisch   firewire: core: u...
1182
  	.immediate = 0x03001f11,
3038e353c   Kristian Høgsberg   firewire: Add cor...
1183
  	.key = 0x81000000,
937f68796   Kristian Høgsberg   firewire: Let an ...
1184
1185
1186
1187
1188
  	.data = vendor_textual_descriptor,
  };
  
  static struct fw_descriptor model_id_descriptor = {
  	.length = ARRAY_SIZE(model_textual_descriptor),
d71e6a117   Clemens Ladisch   firewire: core: u...
1189
  	.immediate = 0x17023901,
937f68796   Kristian Høgsberg   firewire: Let an ...
1190
1191
  	.key = 0x81000000,
  	.data = model_textual_descriptor,
3038e353c   Kristian Høgsberg   firewire: Add cor...
1192
  };
3038e353c   Kristian Høgsberg   firewire: Add cor...
1193
1194
  static int __init fw_core_init(void)
  {
2dbd7d7e2   Stefan Richter   firewire: standar...
1195
  	int ret;
3038e353c   Kristian Høgsberg   firewire: Add cor...
1196

4e6b9319b   Tejun Heo   firewire: WQ_NON_...
1197
  	fw_workqueue = alloc_workqueue("firewire", WQ_MEM_RECLAIM, 0);
105e53f86   Stefan Richter   firewire: sbp2: p...
1198
  	if (!fw_workqueue)
6ea9e7bbf   Stefan Richter   firewire: core: u...
1199
  		return -ENOMEM;
2dbd7d7e2   Stefan Richter   firewire: standar...
1200
  	ret = bus_register(&fw_bus_type);
6ea9e7bbf   Stefan Richter   firewire: core: u...
1201
  	if (ret < 0) {
105e53f86   Stefan Richter   firewire: sbp2: p...
1202
  		destroy_workqueue(fw_workqueue);
2dbd7d7e2   Stefan Richter   firewire: standar...
1203
  		return ret;
6ea9e7bbf   Stefan Richter   firewire: core: u...
1204
  	}
3038e353c   Kristian Høgsberg   firewire: Add cor...
1205

a3aca3dab   Kristian Høgsberg   firewire: Switch ...
1206
1207
1208
  	fw_cdev_major = register_chrdev(0, "firewire", &fw_device_ops);
  	if (fw_cdev_major < 0) {
  		bus_unregister(&fw_bus_type);
105e53f86   Stefan Richter   firewire: sbp2: p...
1209
  		destroy_workqueue(fw_workqueue);
a3aca3dab   Kristian Høgsberg   firewire: Switch ...
1210
1211
  		return fw_cdev_major;
  	}
c490a6dec   Stefan Richter   firewire: core: r...
1212
1213
  	fw_core_add_address_handler(&topology_map, &topology_map_region);
  	fw_core_add_address_handler(&registers, &registers_region);
f07d42ac7   Clemens Ladisch   firewire: core: a...
1214
  	fw_core_add_address_handler(&low_memory, &low_memory_region);
c490a6dec   Stefan Richter   firewire: core: r...
1215
1216
  	fw_core_add_descriptor(&vendor_id_descriptor);
  	fw_core_add_descriptor(&model_id_descriptor);
3038e353c   Kristian Høgsberg   firewire: Add cor...
1217
1218
1219
1220
1221
1222
  
  	return 0;
  }
  
  static void __exit fw_core_cleanup(void)
  {
a3aca3dab   Kristian Høgsberg   firewire: Switch ...
1223
  	unregister_chrdev(fw_cdev_major, "firewire");
3038e353c   Kristian Høgsberg   firewire: Add cor...
1224
  	bus_unregister(&fw_bus_type);
105e53f86   Stefan Richter   firewire: sbp2: p...
1225
  	destroy_workqueue(fw_workqueue);
d6053e08f   Stefan Richter   firewire: fix sma...
1226
  	idr_destroy(&fw_device_idr);
3038e353c   Kristian Høgsberg   firewire: Add cor...
1227
1228
1229
1230
  }
  
  module_init(fw_core_init);
  module_exit(fw_core_cleanup);