Blame view
drivers/firewire/core-transaction.c
34.1 KB
c781c06d1 firewire: Clean u... |
1 2 |
/* * Core IEEE1394 transaction logic |
3038e353c 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 firewire: clean u... |
20 |
#include <linux/bug.h> |
2a0a25904 firewire: wait un... |
21 |
#include <linux/completion.h> |
e8ca97021 firewire: clean u... |
22 23 |
#include <linux/device.h> #include <linux/errno.h> |
77c9a5daa firewire: reorgan... |
24 |
#include <linux/firewire.h> |
e8ca97021 firewire: clean u... |
25 26 27 |
#include <linux/firewire-constants.h> #include <linux/fs.h> #include <linux/init.h> |
d6053e08f firewire: fix sma... |
28 |
#include <linux/idr.h> |
e8ca97021 firewire: clean u... |
29 |
#include <linux/jiffies.h> |
3038e353c firewire: Add cor... |
30 |
#include <linux/kernel.h> |
3038e353c firewire: Add cor... |
31 |
#include <linux/list.h> |
e8ca97021 firewire: clean u... |
32 33 34 35 36 37 |
#include <linux/module.h> #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/string.h> #include <linux/timer.h> #include <linux/types.h> |
6ea9e7bbf firewire: core: u... |
38 |
#include <linux/workqueue.h> |
e8ca97021 firewire: clean u... |
39 40 |
#include <asm/byteorder.h> |
3038e353c firewire: Add cor... |
41 |
|
77c9a5daa firewire: reorgan... |
42 |
#include "core.h" |
3038e353c firewire: Add cor... |
43 |
|
a77754a75 firewire: Upperca... |
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
#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 firewire: don't r... |
63 64 |
#define HEADER_DESTINATION_IS_BROADCAST(q) \ (((q) & HEADER_DESTINATION(0x3f)) == HEADER_DESTINATION(0x3f)) |
77c9a5daa firewire: reorgan... |
65 66 67 |
#define PHY_PACKET_CONFIG 0x0 #define PHY_PACKET_LINK_ON 0x1 #define PHY_PACKET_SELF_ID 0x2 |
a77754a75 firewire: Upperca... |
68 69 70 |
#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 firewire: Add cor... |
71 |
|
410cf2bd3 firewire: use spl... |
72 73 74 75 76 77 78 79 |
/* 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 firewire: remove ... |
80 |
static int close_transaction(struct fw_transaction *transaction, |
a38a00fde firewire: core: d... |
81 |
struct fw_card *card, int rcode) |
3038e353c firewire: Add cor... |
82 |
{ |
730c32f58 firewire: Impleme... |
83 |
struct fw_transaction *t; |
3038e353c firewire: Add cor... |
84 85 86 |
unsigned long flags; spin_lock_irqsave(&card->lock, flags); |
730c32f58 firewire: Impleme... |
87 88 |
list_for_each_entry(t, &card->transaction_list, link) { if (t == transaction) { |
410cf2bd3 firewire: use spl... |
89 |
if (!try_cancel_split_timeout(t)) { |
2222bcb76 firewire: core: d... |
90 91 92 |
spin_unlock_irqrestore(&card->lock, flags); goto timed_out; } |
5c40cbfef firewire: core: u... |
93 |
list_del_init(&t->link); |
1e626fdce firewire: core: u... |
94 |
card->tlabel_mask &= ~(1ULL << t->tlabel); |
730c32f58 firewire: Impleme... |
95 96 97 |
break; } } |
3038e353c firewire: Add cor... |
98 |
spin_unlock_irqrestore(&card->lock, flags); |
730c32f58 firewire: Impleme... |
99 |
if (&t->link != &card->transaction_list) { |
a38a00fde firewire: core: d... |
100 |
t->callback(card, rcode, NULL, 0, t->callback_data); |
730c32f58 firewire: Impleme... |
101 102 |
return 0; } |
2222bcb76 firewire: core: d... |
103 |
timed_out: |
730c32f58 firewire: Impleme... |
104 |
return -ENOENT; |
3038e353c firewire: Add cor... |
105 |
} |
c781c06d1 firewire: Clean u... |
106 107 108 109 |
/* * Only valid for transactions that are potentially pending (ie have * been sent). */ |
53dca5117 firewire: remove ... |
110 111 |
int fw_cancel_transaction(struct fw_card *card, struct fw_transaction *transaction) |
730c32f58 firewire: Impleme... |
112 |
{ |
c781c06d1 firewire: Clean u... |
113 114 |
/* * Cancel the packet transmission if it's still queued. That |
730c32f58 firewire: Impleme... |
115 |
* will call the packet transmission callback which cancels |
c781c06d1 firewire: Clean u... |
116 117 |
* the transaction. */ |
730c32f58 firewire: Impleme... |
118 119 120 |
if (card->driver->cancel_packet(card, &transaction->packet) == 0) return 0; |
c781c06d1 firewire: Clean u... |
121 122 123 124 |
/* * 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 firewire: Impleme... |
125 |
|
a38a00fde firewire: core: d... |
126 |
return close_transaction(transaction, card, RCODE_CANCELLED); |
730c32f58 firewire: Impleme... |
127 128 |
} EXPORT_SYMBOL(fw_cancel_transaction); |
5c40cbfef firewire: core: u... |
129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
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 firewire: core: u... |
143 144 |
t->callback(card, RCODE_CANCELLED, NULL, 0, t->callback_data); } |
410cf2bd3 firewire: use spl... |
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 |
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 firewire: remove ... |
163 164 |
static void transmit_complete_callback(struct fw_packet *packet, struct fw_card *card, int status) |
3038e353c firewire: Add cor... |
165 166 167 168 169 170 |
{ struct fw_transaction *t = container_of(packet, struct fw_transaction, packet); switch (status) { case ACK_COMPLETE: |
a38a00fde firewire: core: d... |
171 |
close_transaction(t, card, RCODE_COMPLETE); |
3038e353c firewire: Add cor... |
172 173 |
break; case ACK_PENDING: |
410cf2bd3 firewire: use spl... |
174 |
start_split_transaction_timeout(t, card); |
3038e353c firewire: Add cor... |
175 176 177 178 |
break; case ACK_BUSY_X: case ACK_BUSY_A: case ACK_BUSY_B: |
a38a00fde firewire: core: d... |
179 |
close_transaction(t, card, RCODE_BUSY); |
3038e353c firewire: Add cor... |
180 181 |
break; case ACK_DATA_ERROR: |
a38a00fde firewire: core: d... |
182 |
close_transaction(t, card, RCODE_DATA_ERROR); |
e5f49c3b8 firewire: Sanitiz... |
183 |
break; |
3038e353c firewire: Add cor... |
184 |
case ACK_TYPE_ERROR: |
a38a00fde firewire: core: d... |
185 |
close_transaction(t, card, RCODE_TYPE_ERROR); |
3038e353c firewire: Add cor... |
186 187 |
break; default: |
c781c06d1 firewire: Clean u... |
188 189 190 191 |
/* * In this case the ack is really a juju specific * rcode, so just forward that to the callback. */ |
a38a00fde firewire: core: d... |
192 |
close_transaction(t, card, status); |
3038e353c firewire: Add cor... |
193 194 195 |
break; } } |
53dca5117 firewire: remove ... |
196 |
static void fw_fill_request(struct fw_packet *packet, int tcode, int tlabel, |
b9549bc68 firewire: small f... |
197 |
int destination_id, int source_id, int generation, int speed, |
36bfe49d0 firewire: Clean u... |
198 |
unsigned long long offset, void *payload, size_t length) |
3038e353c firewire: Add cor... |
199 200 |
{ int ext_tcode; |
18e9b10fc firewire: cdev: a... |
201 202 203 204 205 206 207 208 209 210 211 |
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 firewire: Add cor... |
212 |
if (tcode > 0x10) { |
8f9f963e5 firewire: replace... |
213 |
ext_tcode = tcode & ~0x10; |
3038e353c firewire: Add cor... |
214 215 216 217 218 |
tcode = TCODE_LOCK_REQUEST; } else ext_tcode = 0; packet->header[0] = |
a77754a75 firewire: Upperca... |
219 220 221 |
HEADER_RETRY(RETRY_X) | HEADER_TLABEL(tlabel) | HEADER_TCODE(tcode) | |
b9549bc68 firewire: small f... |
222 |
HEADER_DESTINATION(destination_id); |
3038e353c firewire: Add cor... |
223 |
packet->header[1] = |
a77754a75 firewire: Upperca... |
224 |
HEADER_OFFSET_HIGH(offset >> 32) | HEADER_SOURCE(source_id); |
3038e353c firewire: Add cor... |
225 226 227 228 229 230 231 232 233 234 235 236 237 |
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 firewire: Upperca... |
238 239 |
HEADER_DATA_LENGTH(length) | HEADER_EXTENDED_TCODE(ext_tcode); |
3038e353c firewire: Add cor... |
240 241 242 243 244 245 246 247 248 249 250 251 |
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 firewire: Upperca... |
252 253 |
HEADER_DATA_LENGTH(length) | HEADER_EXTENDED_TCODE(ext_tcode); |
3038e353c firewire: Add cor... |
254 255 256 |
packet->header_length = 16; packet->payload_length = 0; break; |
5b189bf36 firewire: core: W... |
257 258 |
default: |
5878730be firewire: core: U... |
259 260 |
WARN(1, "wrong tcode %d ", tcode); |
3038e353c firewire: Add cor... |
261 |
} |
18e9b10fc firewire: cdev: a... |
262 |
common: |
3038e353c firewire: Add cor... |
263 264 |
packet->speed = speed; packet->generation = generation; |
730c32f58 firewire: Impleme... |
265 |
packet->ack = 0; |
19593ffdb firewire: ohci: 0... |
266 |
packet->payload_mapped = false; |
3038e353c firewire: Add cor... |
267 |
} |
7906054f0 firewire: core: m... |
268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 |
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 firewire: Add cor... |
284 |
/** |
656b7afd4 firewire: core: f... |
285 286 287 288 289 290 291 292 293 294 295 296 |
* 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 firewire: Add cor... |
297 |
* |
656b7afd4 firewire: core: f... |
298 299 300 |
* 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 firewire: Add cor... |
301 |
* |
656b7afd4 firewire: core: f... |
302 303 |
* In case of lock requests, specify one of the firewire-core specific %TCODE_ * constants instead of %TCODE_LOCK_REQUEST in @tcode. |
3038e353c firewire: Add cor... |
304 |
* |
656b7afd4 firewire: core: f... |
305 306 |
* 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 firewire: Add cor... |
307 |
* |
656b7afd4 firewire: core: f... |
308 |
* In case of asynchronous stream packets i.e. %TCODE_STREAM_DATA, the caller |
18e9b10fc firewire: cdev: a... |
309 |
* needs to synthesize @destination_id with fw_stream_packet_destination_id(). |
656b7afd4 firewire: core: f... |
310 311 312 |
* 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 firewire: octlet ... |
313 314 |
* @length <= 8 or of local (loopback) requests. Hence make sure that the * buffer complies with the restrictions of the streaming DMA mapping API. |
656b7afd4 firewire: core: f... |
315 316 317 318 319 320 321 |
* @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 firewire: normali... |
322 323 324 325 |
* 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 firewire: core: f... |
326 327 328 329 330 |
* * 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 firewire: Add cor... |
331 |
*/ |
53dca5117 firewire: remove ... |
332 333 334 335 |
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 firewire: Add cor... |
336 337 |
{ unsigned long flags; |
b9549bc68 firewire: small f... |
338 |
int tlabel; |
3038e353c firewire: Add cor... |
339 |
|
c781c06d1 firewire: Clean u... |
340 |
/* |
c781c06d1 firewire: Clean u... |
341 342 343 |
* Allocate tlabel from the bitmap and put the transaction on * the list while holding the card spinlock. */ |
3038e353c firewire: Add cor... |
344 345 |
spin_lock_irqsave(&card->lock, flags); |
7906054f0 firewire: core: m... |
346 347 |
tlabel = allocate_tlabel(card); if (tlabel < 0) { |
3038e353c firewire: Add cor... |
348 349 350 351 |
spin_unlock_irqrestore(&card->lock, flags); callback(card, RCODE_SEND_ERROR, NULL, 0, callback_data); return; } |
1e119fa99 firewire: fw_send... |
352 |
t->node_id = destination_id; |
3038e353c firewire: Add cor... |
353 |
t->tlabel = tlabel; |
5c40cbfef firewire: core: u... |
354 |
t->card = card; |
410cf2bd3 firewire: use spl... |
355 |
t->is_split_transaction = false; |
5c40cbfef firewire: core: u... |
356 357 |
setup_timer(&t->split_timeout_timer, split_transaction_timeout_callback, (unsigned long)t); |
3038e353c firewire: Add cor... |
358 359 |
t->callback = callback; t->callback_data = callback_data; |
1e119fa99 firewire: fw_send... |
360 361 362 |
fw_fill_request(&t->packet, tcode, t->tlabel, destination_id, card->node_id, generation, speed, offset, payload, length); |
3038e353c firewire: Add cor... |
363 |
t->packet.callback = transmit_complete_callback; |
e9aeb46c9 firewire: fully i... |
364 365 366 |
list_add_tail(&t->link, &card->transaction_list); spin_unlock_irqrestore(&card->lock, flags); |
3038e353c firewire: Add cor... |
367 368 369 |
card->driver->send_request(card, &t->packet); } EXPORT_SYMBOL(fw_send_request); |
1e119fa99 firewire: fw_send... |
370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 |
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 firewire: core: f... |
388 |
* fw_run_transaction() - send request and sleep until transaction is completed |
1e119fa99 firewire: fw_send... |
389 |
* |
656b7afd4 firewire: core: f... |
390 391 |
* 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 firewire: octlet ... |
392 393 |
* to the payload of the response. DMA mapping restrictions apply to outbound * request payloads of >= 8 bytes but not to inbound response payloads. |
1e119fa99 firewire: fw_send... |
394 395 |
*/ int fw_run_transaction(struct fw_card *card, int tcode, int destination_id, |
53dca5117 firewire: remove ... |
396 |
int generation, int speed, unsigned long long offset, |
ba27e1f7b firewire: core: n... |
397 |
void *payload, size_t length) |
1e119fa99 firewire: fw_send... |
398 399 400 |
{ struct transaction_callback_data d; struct fw_transaction t; |
5c40cbfef firewire: core: u... |
401 |
init_timer_on_stack(&t.split_timeout_timer); |
1e119fa99 firewire: fw_send... |
402 |
init_completion(&d.done); |
ba27e1f7b firewire: core: n... |
403 |
d.payload = payload; |
1e119fa99 firewire: fw_send... |
404 |
fw_send_request(card, &t, tcode, destination_id, generation, speed, |
ba27e1f7b firewire: core: n... |
405 |
offset, payload, length, transaction_callback, &d); |
1e119fa99 firewire: fw_send... |
406 |
wait_for_completion(&d.done); |
5c40cbfef firewire: core: u... |
407 |
destroy_timer_on_stack(&t.split_timeout_timer); |
1e119fa99 firewire: fw_send... |
408 409 410 411 |
return d.rcode; } EXPORT_SYMBOL(fw_run_transaction); |
c0220d686 firewire: avoid m... |
412 413 |
static DEFINE_MUTEX(phy_config_mutex); static DECLARE_COMPLETION(phy_config_done); |
ae1e53557 firewire: deadlin... |
414 415 416 |
static void transmit_phy_packet_callback(struct fw_packet *packet, struct fw_card *card, int status) |
3038e353c firewire: Add cor... |
417 |
{ |
c0220d686 firewire: avoid m... |
418 |
complete(&phy_config_done); |
3038e353c firewire: Add cor... |
419 |
} |
c0220d686 firewire: avoid m... |
420 |
static struct fw_packet phy_config_packet = { |
5b06db166 firewire: make PH... |
421 422 |
.header_length = 12, .header[0] = TCODE_LINK_INTERNAL << 4, |
c0220d686 firewire: avoid m... |
423 424 425 426 |
.payload_length = 0, .speed = SCODE_100, .callback = transmit_phy_packet_callback, }; |
83db801ce firewire: Impleme... |
427 428 |
void fw_send_phy_config(struct fw_card *card, int node_id, int generation, int gap_count) |
3038e353c firewire: Add cor... |
429 |
{ |
ae1e53557 firewire: deadlin... |
430 |
long timeout = DIV_ROUND_UP(HZ, 10); |
02d37bed1 firewire: core: i... |
431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 |
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 firewire: wait un... |
446 |
|
c0220d686 firewire: avoid m... |
447 |
mutex_lock(&phy_config_mutex); |
5b06db166 firewire: make PH... |
448 449 |
phy_config_packet.header[1] = data; phy_config_packet.header[2] = ~data; |
c0220d686 firewire: avoid m... |
450 451 452 453 454 |
phy_config_packet.generation = generation; INIT_COMPLETION(phy_config_done); card->driver->send_request(card, &phy_config_packet); wait_for_completion_timeout(&phy_config_done, timeout); |
ae1e53557 firewire: deadlin... |
455 |
|
c0220d686 firewire: avoid m... |
456 |
mutex_unlock(&phy_config_mutex); |
3038e353c firewire: Add cor... |
457 |
} |
53dca5117 firewire: remove ... |
458 459 |
static struct fw_address_handler *lookup_overlapping_address_handler( struct list_head *list, unsigned long long offset, size_t length) |
3038e353c firewire: Add cor... |
460 461 462 463 464 465 466 467 468 469 470 |
{ struct fw_address_handler *handler; list_for_each_entry(handler, list, link) { if (handler->offset < offset + length && offset < handler->offset + handler->length) return handler; } return NULL; } |
db5d247ae 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 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 firewire: Add cor... |
479 480 481 482 |
{ struct fw_address_handler *handler; list_for_each_entry(handler, list, link) { |
db5d247ae firewire: fix use... |
483 |
if (is_enclosing_handler(handler, offset, length)) |
3038e353c firewire: Add cor... |
484 485 486 487 488 489 490 491 |
return handler; } return NULL; } static DEFINE_SPINLOCK(address_handler_lock); static LIST_HEAD(address_handler_list); |
21ebcd122 firewire: mark so... |
492 |
const struct fw_address_region fw_high_memory_region = |
5af4e5eab firewire: comma a... |
493 |
{ .start = 0x000100000000ULL, .end = 0xffffe0000000ULL, }; |
db8be076c firewire: cleanups |
494 495 496 497 498 |
EXPORT_SYMBOL(fw_high_memory_region); #if 0 const struct fw_address_region fw_low_memory_region = { .start = 0x000000000000ULL, .end = 0x000100000000ULL, }; |
21ebcd122 firewire: mark so... |
499 |
const struct fw_address_region fw_private_region = |
5af4e5eab firewire: comma a... |
500 |
{ .start = 0xffffe0000000ULL, .end = 0xfffff0000000ULL, }; |
21ebcd122 firewire: mark so... |
501 |
const struct fw_address_region fw_csr_region = |
cca609771 firewire: replace... |
502 503 |
{ .start = CSR_REGISTER_BASE, .end = CSR_REGISTER_BASE | CSR_CONFIG_ROM_END, }; |
21ebcd122 firewire: mark so... |
504 |
const struct fw_address_region fw_unit_space_region = |
5af4e5eab firewire: comma a... |
505 |
{ .start = 0xfffff0000900ULL, .end = 0x1000000000000ULL, }; |
db8be076c firewire: cleanups |
506 |
#endif /* 0 */ |
3038e353c firewire: Add cor... |
507 |
|
db5d247ae firewire: fix use... |
508 509 510 511 512 |
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 firewire: Add cor... |
513 |
/** |
656b7afd4 firewire: core: f... |
514 515 516 |
* fw_core_add_address_handler() - register for incoming requests * @handler: callback * @region: region in the IEEE 1212 node space address range |
3e0b5f0d7 firewire: cdev: a... |
517 518 519 520 521 522 |
* * 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 firewire: optimiz... |
523 524 |
* * Return value: 0 on success, non-zero otherwise. |
db5d247ae firewire: fix use... |
525 |
* |
1415d9189 firewire: optimiz... |
526 527 |
* The start offset of the handler's address region is determined by * fw_core_add_address_handler() and is returned in handler->offset. |
db5d247ae firewire: fix use... |
528 529 |
* * Address allocations are exclusive, except for the FCP registers. |
3038e353c firewire: Add cor... |
530 |
*/ |
53dca5117 firewire: remove ... |
531 532 |
int fw_core_add_address_handler(struct fw_address_handler *handler, const struct fw_address_region *region) |
3038e353c firewire: Add cor... |
533 534 535 536 |
{ struct fw_address_handler *other; unsigned long flags; int ret = -EBUSY; |
3e0b5f0d7 firewire: cdev: a... |
537 |
if (region->start & 0xffff000000000003ULL || |
3e0b5f0d7 firewire: cdev: a... |
538 |
region->start >= region->end || |
0c9ae701a firewire: core: f... |
539 |
region->end > 0x0001000000000000ULL || |
3e0b5f0d7 firewire: cdev: a... |
540 541 542 |
handler->length & 3 || handler->length == 0) return -EINVAL; |
3038e353c firewire: Add cor... |
543 |
spin_lock_irqsave(&address_handler_lock, flags); |
3e0b5f0d7 firewire: cdev: a... |
544 |
handler->offset = region->start; |
3038e353c firewire: Add cor... |
545 |
while (handler->offset + handler->length <= region->end) { |
db5d247ae firewire: fix use... |
546 547 548 549 550 551 |
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 firewire: Add cor... |
552 |
if (other != NULL) { |
3e0b5f0d7 firewire: cdev: a... |
553 |
handler->offset += other->length; |
3038e353c firewire: Add cor... |
554 555 556 557 558 559 560 561 562 563 564 |
} else { list_add_tail(&handler->link, &address_handler_list); ret = 0; break; } } spin_unlock_irqrestore(&address_handler_lock, flags); return ret; } |
3038e353c firewire: Add cor... |
565 566 567 |
EXPORT_SYMBOL(fw_core_add_address_handler); /** |
656b7afd4 firewire: core: f... |
568 |
* fw_core_remove_address_handler() - unregister an address handler |
3038e353c firewire: Add cor... |
569 |
*/ |
3038e353c firewire: Add cor... |
570 571 572 573 574 575 576 577 |
void fw_core_remove_address_handler(struct fw_address_handler *handler) { unsigned long flags; spin_lock_irqsave(&address_handler_lock, flags); list_del(&handler->link); spin_unlock_irqrestore(&address_handler_lock, flags); } |
3038e353c firewire: Add cor... |
578 579 580 581 |
EXPORT_SYMBOL(fw_core_remove_address_handler); struct fw_request { struct fw_packet response; |
36bfe49d0 firewire: Clean u... |
582 |
u32 request_header[4]; |
3038e353c firewire: Add cor... |
583 584 585 586 |
int ack; u32 length; u32 data[0]; }; |
53dca5117 firewire: remove ... |
587 588 |
static void free_response_callback(struct fw_packet *packet, struct fw_card *card, int status) |
3038e353c firewire: Add cor... |
589 590 591 592 593 594 |
{ struct fw_request *request; request = container_of(packet, struct fw_request, response); kfree(request); } |
a10c0ce76 firewire: check c... |
595 596 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 |
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 firewire: core: U... |
625 626 |
WARN(1, "wrong tcode %d ", tcode); |
a10c0ce76 firewire: check c... |
627 628 629 |
return 0; } } |
53dca5117 firewire: remove ... |
630 631 |
void fw_fill_response(struct fw_packet *response, u32 *request_header, int rcode, void *payload, size_t length) |
3038e353c firewire: Add cor... |
632 633 |
{ int tcode, tlabel, extended_tcode, source, destination; |
a77754a75 firewire: Upperca... |
634 635 636 637 638 |
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 firewire: Add cor... |
639 640 |
response->header[0] = |
a77754a75 firewire: Upperca... |
641 642 643 |
HEADER_RETRY(RETRY_1) | HEADER_TLABEL(tlabel) | HEADER_DESTINATION(destination); |
36bfe49d0 firewire: Clean u... |
644 |
response->header[1] = |
a77754a75 firewire: Upperca... |
645 646 |
HEADER_SOURCE(source) | HEADER_RCODE(rcode); |
3038e353c firewire: Add cor... |
647 648 649 650 651 |
response->header[2] = 0; switch (tcode) { case TCODE_WRITE_QUADLET_REQUEST: case TCODE_WRITE_BLOCK_REQUEST: |
a77754a75 firewire: Upperca... |
652 |
response->header[0] |= HEADER_TCODE(TCODE_WRITE_RESPONSE); |
3038e353c firewire: Add cor... |
653 654 655 656 657 658 |
response->header_length = 12; response->payload_length = 0; break; case TCODE_READ_QUADLET_REQUEST: response->header[0] |= |
a77754a75 firewire: Upperca... |
659 |
HEADER_TCODE(TCODE_READ_QUADLET_RESPONSE); |
93c4cceb9 firewire: Handle ... |
660 661 662 663 |
if (payload != NULL) response->header[3] = *(u32 *)payload; else response->header[3] = 0; |
3038e353c firewire: Add cor... |
664 665 666 667 668 669 |
response->header_length = 16; response->payload_length = 0; break; case TCODE_READ_BLOCK_REQUEST: case TCODE_LOCK_REQUEST: |
a77754a75 firewire: Upperca... |
670 |
response->header[0] |= HEADER_TCODE(tcode + 2); |
3038e353c firewire: Add cor... |
671 |
response->header[3] = |
a77754a75 firewire: Upperca... |
672 673 |
HEADER_DATA_LENGTH(length) | HEADER_EXTENDED_TCODE(extended_tcode); |
3038e353c firewire: Add cor... |
674 |
response->header_length = 16; |
36bfe49d0 firewire: Clean u... |
675 676 |
response->payload = payload; response->payload_length = length; |
3038e353c firewire: Add cor... |
677 678 679 |
break; default: |
5878730be firewire: core: U... |
680 681 |
WARN(1, "wrong tcode %d ", tcode); |
3038e353c firewire: Add cor... |
682 |
} |
1d1dc5e83 firewire: fw-ohci... |
683 |
|
19593ffdb firewire: ohci: 0... |
684 |
response->payload_mapped = false; |
3038e353c firewire: Add cor... |
685 |
} |
93c4cceb9 firewire: Handle ... |
686 |
EXPORT_SYMBOL(fw_fill_response); |
3038e353c firewire: Add cor... |
687 |
|
8e4b50f94 firewire: core: a... |
688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 |
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 firewire: Add cor... |
706 707 708 |
{ struct fw_request *request; u32 *data, length; |
8e4b50f94 firewire: core: a... |
709 |
int request_tcode; |
3038e353c firewire: Add cor... |
710 |
|
a77754a75 firewire: Upperca... |
711 |
request_tcode = HEADER_GET_TCODE(p->header[0]); |
3038e353c firewire: Add cor... |
712 713 |
switch (request_tcode) { case TCODE_WRITE_QUADLET_REQUEST: |
2639a6fb2 firewire: Use str... |
714 |
data = &p->header[3]; |
3038e353c firewire: Add cor... |
715 716 717 718 719 |
length = 4; break; case TCODE_WRITE_BLOCK_REQUEST: case TCODE_LOCK_REQUEST: |
2639a6fb2 firewire: Use str... |
720 |
data = p->payload; |
a77754a75 firewire: Upperca... |
721 |
length = HEADER_GET_DATA_LENGTH(p->header[3]); |
3038e353c firewire: Add cor... |
722 723 724 725 726 727 728 729 730 |
break; case TCODE_READ_QUADLET_REQUEST: data = NULL; length = 4; break; case TCODE_READ_BLOCK_REQUEST: data = NULL; |
a77754a75 firewire: Upperca... |
731 |
length = HEADER_GET_DATA_LENGTH(p->header[3]); |
3038e353c firewire: Add cor... |
732 733 734 |
break; default: |
0bf607c5b firewire: don't p... |
735 736 737 |
fw_error("ERROR - corrupt request received - %08x %08x %08x ", p->header[0], p->header[1], p->header[2]); |
3038e353c firewire: Add cor... |
738 739 |
return NULL; } |
2d826cc5c firewire: Always ... |
740 |
request = kmalloc(sizeof(*request) + length, GFP_ATOMIC); |
3038e353c firewire: Add cor... |
741 742 |
if (request == NULL) return NULL; |
2639a6fb2 firewire: Use str... |
743 |
request->response.speed = p->speed; |
8e4b50f94 firewire: core: a... |
744 745 |
request->response.timestamp = compute_split_timeout_timestamp(card, p->timestamp); |
2639a6fb2 firewire: Use str... |
746 |
request->response.generation = p->generation; |
730c32f58 firewire: Impleme... |
747 |
request->response.ack = 0; |
3038e353c firewire: Add cor... |
748 |
request->response.callback = free_response_callback; |
2639a6fb2 firewire: Use str... |
749 |
request->ack = p->ack; |
93c4cceb9 firewire: Handle ... |
750 |
request->length = length; |
3038e353c firewire: Add cor... |
751 |
if (data) |
6e2e8424d firewire: Use cor... |
752 |
memcpy(request->data, data, length); |
3038e353c firewire: Add cor... |
753 |
|
2d826cc5c firewire: Always ... |
754 |
memcpy(request->request_header, p->header, sizeof(p->header)); |
3038e353c firewire: Add cor... |
755 756 757 |
return request; } |
53dca5117 firewire: remove ... |
758 759 |
void fw_send_response(struct fw_card *card, struct fw_request *request, int rcode) |
3038e353c firewire: Add cor... |
760 |
{ |
db5d247ae firewire: fix use... |
761 762 |
if (WARN_ONCE(!request, "invalid for FCP address handlers")) return; |
a7ea67823 firewire: don't r... |
763 764 765 |
/* unified transaction or broadcast transaction: don't respond */ if (request->ack != ACK_PENDING || HEADER_DESTINATION_IS_BROADCAST(request->request_header[0])) { |
9c9bdf4d5 firewire: fix mem... |
766 |
kfree(request); |
3038e353c firewire: Add cor... |
767 |
return; |
9c9bdf4d5 firewire: fix mem... |
768 |
} |
3038e353c firewire: Add cor... |
769 |
|
36bfe49d0 firewire: Clean u... |
770 771 |
if (rcode == RCODE_COMPLETE) fw_fill_response(&request->response, request->request_header, |
a10c0ce76 firewire: check c... |
772 773 |
rcode, request->data, fw_get_response_length(request)); |
36bfe49d0 firewire: Clean u... |
774 775 776 |
else fw_fill_response(&request->response, request->request_header, rcode, NULL, 0); |
3038e353c firewire: Add cor... |
777 778 779 |
card->driver->send_response(card, &request->response); } |
3038e353c firewire: Add cor... |
780 |
EXPORT_SYMBOL(fw_send_response); |
db5d247ae firewire: fix use... |
781 782 783 784 |
static void handle_exclusive_region_request(struct fw_card *card, struct fw_packet *p, struct fw_request *request, unsigned long long offset) |
3038e353c firewire: Add cor... |
785 786 |
{ struct fw_address_handler *handler; |
3038e353c firewire: Add cor... |
787 |
unsigned long flags; |
2639a6fb2 firewire: Use str... |
788 |
int tcode, destination, source; |
3038e353c firewire: Add cor... |
789 |
|
a77754a75 firewire: Upperca... |
790 |
destination = HEADER_GET_DESTINATION(p->header[0]); |
478b233ed firewire: Fix ext... |
791 |
source = HEADER_GET_SOURCE(p->header[1]); |
c82f91f26 firewire: expose ... |
792 793 794 |
tcode = HEADER_GET_TCODE(p->header[0]); if (tcode == TCODE_LOCK_REQUEST) tcode = 0x10 + HEADER_GET_EXTENDED_TCODE(p->header[3]); |
3038e353c firewire: Add cor... |
795 796 797 798 799 |
spin_lock_irqsave(&address_handler_lock, flags); handler = lookup_enclosing_address_handler(&address_handler_list, offset, request->length); spin_unlock_irqrestore(&address_handler_lock, flags); |
c781c06d1 firewire: Clean u... |
800 801 |
/* * FIXME: lookup the fw_node corresponding to the sender of |
3038e353c firewire: Add cor... |
802 803 804 |
* this request and pass that to the address handler instead * of the node ID. We may also want to move the address * allocations to fw_node so we only do this callback if the |
c781c06d1 firewire: Clean u... |
805 806 |
* upper layers registered it for this node. */ |
3038e353c firewire: Add cor... |
807 808 809 810 811 812 |
if (handler == NULL) fw_send_response(card, request, RCODE_ADDRESS_ERROR); else handler->address_callback(card, request, tcode, destination, source, |
33e553fe2 firewire: remove ... |
813 |
p->generation, offset, |
3038e353c firewire: Add cor... |
814 815 816 |
request->data, request->length, handler->callback_data); } |
db5d247ae firewire: fix use... |
817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 |
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; unsigned long flags; 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; } spin_lock_irqsave(&address_handler_lock, flags); list_for_each_entry(handler, &address_handler_list, link) { if (is_enclosing_handler(handler, offset, request->length)) handler->address_callback(card, NULL, tcode, destination, source, |
33e553fe2 firewire: remove ... |
851 852 |
p->generation, offset, request->data, |
db5d247ae firewire: fix use... |
853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 |
request->length, handler->callback_data); } spin_unlock_irqrestore(&address_handler_lock, flags); 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 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 firewire: core: a... |
872 |
request = allocate_request(card, p); |
db5d247ae 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 firewire: Add cor... |
887 |
EXPORT_SYMBOL(fw_core_handle_request); |
53dca5117 firewire: remove ... |
888 |
void fw_core_handle_response(struct fw_card *card, struct fw_packet *p) |
3038e353c firewire: Add cor... |
889 890 891 892 893 |
{ struct fw_transaction *t; unsigned long flags; u32 *data; size_t data_length; |
ae86e81e4 firewire: core: r... |
894 |
int tcode, tlabel, source, rcode; |
3038e353c firewire: Add cor... |
895 |
|
ae86e81e4 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 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 firewire: use spl... |
904 |
if (!try_cancel_split_timeout(t)) { |
2222bcb76 firewire: core: d... |
905 906 907 |
spin_unlock_irqrestore(&card->lock, flags); goto timed_out; } |
5c40cbfef firewire: core: u... |
908 |
list_del_init(&t->link); |
753a8970f firewire: core: F... |
909 |
card->tlabel_mask &= ~(1ULL << t->tlabel); |
3038e353c firewire: Add cor... |
910 911 912 913 914 915 |
break; } } spin_unlock_irqrestore(&card->lock, flags); if (&t->link == &card->transaction_list) { |
2222bcb76 firewire: core: d... |
916 |
timed_out: |
32b46093a firewire: Rework ... |
917 918 919 |
fw_notify("Unsolicited response (source %x, tlabel %x) ", source, tlabel); |
3038e353c firewire: Add cor... |
920 921 |
return; } |
c781c06d1 firewire: Clean u... |
922 923 924 925 |
/* * FIXME: sanity check packet, is length correct, does tcodes * and addresses match. */ |
3038e353c firewire: Add cor... |
926 927 928 |
switch (tcode) { case TCODE_READ_QUADLET_RESPONSE: |
2639a6fb2 firewire: Use str... |
929 |
data = (u32 *) &p->header[3]; |
3038e353c 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 firewire: Handle ... |
940 |
data = p->payload; |
a77754a75 firewire: Upperca... |
941 |
data_length = HEADER_GET_DATA_LENGTH(p->header[3]); |
3038e353c 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 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 firewire: Add cor... |
955 956 |
t->callback(card, rcode, data, data_length, t->callback_data); } |
3038e353c firewire: Add cor... |
957 |
EXPORT_SYMBOL(fw_core_handle_response); |
ae57988f6 firewire: fw-core... |
958 |
static const struct fw_address_region topology_map_region = |
cca609771 firewire: replace... |
959 960 |
{ .start = CSR_REGISTER_BASE | CSR_TOPOLOGY_MAP, .end = CSR_REGISTER_BASE | CSR_TOPOLOGY_MAP_END, }; |
473d28c73 firewire: Impleme... |
961 |
|
53dca5117 firewire: remove ... |
962 963 |
static void handle_topology_map(struct fw_card *card, struct fw_request *request, int tcode, int destination, int source, int generation, |
33e553fe2 firewire: remove ... |
964 965 |
unsigned long long offset, void *payload, size_t length, void *callback_data) |
473d28c73 firewire: Impleme... |
966 |
{ |
cb7c96da3 firewire: core: o... |
967 |
int start; |
473d28c73 firewire: Impleme... |
968 969 970 971 972 973 974 975 976 977 978 979 |
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 firewire: core: o... |
980 |
memcpy(payload, &card->topology_map[start], length); |
473d28c73 firewire: Impleme... |
981 982 983 984 985 |
fw_send_response(card, request, RCODE_COMPLETE); } static struct fw_address_handler topology_map = { |
85cb9b686 firewire: core: f... |
986 |
.length = 0x400, |
473d28c73 firewire: Impleme... |
987 988 |
.address_callback = handle_topology_map, }; |
ae57988f6 firewire: fw-core... |
989 |
static const struct fw_address_region registers_region = |
cca609771 firewire: replace... |
990 991 |
{ .start = CSR_REGISTER_BASE, .end = CSR_REGISTER_BASE | CSR_CONFIG_ROM, }; |
d60d7f1d5 firewire: Impleme... |
992 |
|
8e4b50f94 firewire: core: a... |
993 994 995 996 997 |
static void update_split_timeout(struct fw_card *card) { unsigned int cycles; cycles = card->split_timeout_hi * 8000 + (card->split_timeout_lo >> 19); |
4ec4a67aa firewire: use cla... |
998 999 |
/* minimum per IEEE 1394, maximum which doesn't overflow OHCI */ cycles = clamp(cycles, 800u, 3u * 8000u); |
8e4b50f94 firewire: core: a... |
1000 1001 1002 1003 |
card->split_timeout_cycles = cycles; card->split_timeout_jiffies = DIV_ROUND_UP(cycles * HZ, 8000); } |
53dca5117 firewire: remove ... |
1004 1005 |
static void handle_registers(struct fw_card *card, struct fw_request *request, int tcode, int destination, int source, int generation, |
33e553fe2 firewire: remove ... |
1006 1007 |
unsigned long long offset, void *payload, size_t length, void *callback_data) |
d60d7f1d5 firewire: Impleme... |
1008 |
{ |
15f0d833f firewire: use bit... |
1009 |
int reg = offset & ~CSR_REGISTER_BASE; |
d60d7f1d5 firewire: Impleme... |
1010 |
__be32 *data = payload; |
e534fe16b firewire: impleme... |
1011 |
int rcode = RCODE_COMPLETE; |
8e4b50f94 firewire: core: a... |
1012 |
unsigned long flags; |
d60d7f1d5 firewire: Impleme... |
1013 1014 |
switch (reg) { |
b384cf188 firewire: core: c... |
1015 1016 1017 1018 1019 1020 |
case CSR_PRIORITY_BUDGET: if (!card->priority_budget_implemented) { rcode = RCODE_ADDRESS_ERROR; break; } /* else fall through */ |
3e07ec0ee firewire: core: a... |
1021 |
|
506f1a319 firewire: add CSR... |
1022 |
case CSR_NODE_IDS: |
65b2742ac firewire: 'add CS... |
1023 1024 1025 1026 |
/* * 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 firewire: core: c... |
1027 1028 1029 1030 1031 1032 1033 |
/* fall through */ case CSR_STATE_CLEAR: case CSR_STATE_SET: case CSR_CYCLE_TIME: case CSR_BUS_TIME: case CSR_BUSY_TIMEOUT: |
506f1a319 firewire: add CSR... |
1034 |
if (tcode == TCODE_READ_QUADLET_REQUEST) |
0fcff4e39 firewire: rename ... |
1035 |
*data = cpu_to_be32(card->driver->read_csr(card, reg)); |
506f1a319 firewire: add CSR... |
1036 |
else if (tcode == TCODE_WRITE_QUADLET_REQUEST) |
0fcff4e39 firewire: rename ... |
1037 |
card->driver->write_csr(card, reg, be32_to_cpu(*data)); |
506f1a319 firewire: add CSR... |
1038 1039 1040 |
else rcode = RCODE_TYPE_ERROR; break; |
446eba0d6 firewire: core: a... |
1041 |
case CSR_RESET_START: |
7e0e314f1 firewire: core: a... |
1042 |
if (tcode == TCODE_WRITE_QUADLET_REQUEST) |
0fcff4e39 firewire: rename ... |
1043 1044 |
card->driver->write_csr(card, CSR_STATE_CLEAR, CSR_STATE_BIT_ABDICATE); |
7e0e314f1 firewire: core: a... |
1045 |
else |
446eba0d6 firewire: core: a... |
1046 1047 |
rcode = RCODE_TYPE_ERROR; break; |
8e4b50f94 firewire: core: a... |
1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 |
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 firewire: core: a... |
1074 1075 1076 1077 1078 1079 1080 1081 |
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 firewire: impleme... |
1082 1083 1084 1085 1086 1087 1088 1089 1090 |
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 firewire: Impleme... |
1091 1092 1093 1094 1095 1096 |
break; case CSR_BUS_MANAGER_ID: case CSR_BANDWIDTH_AVAILABLE: case CSR_CHANNELS_AVAILABLE_HI: case CSR_CHANNELS_AVAILABLE_LO: |
c781c06d1 firewire: Clean u... |
1097 1098 |
/* * FIXME: these are handled by the OHCI hardware and |
d60d7f1d5 firewire: Impleme... |
1099 1100 1101 |
* 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 firewire: Clean u... |
1102 1103 |
* transactions. */ |
d60d7f1d5 firewire: Impleme... |
1104 1105 |
BUG(); break; |
d60d7f1d5 firewire: Impleme... |
1106 |
default: |
e534fe16b firewire: impleme... |
1107 |
rcode = RCODE_ADDRESS_ERROR; |
d60d7f1d5 firewire: Impleme... |
1108 1109 |
break; } |
e534fe16b firewire: impleme... |
1110 1111 |
fw_send_response(card, request, rcode); |
d60d7f1d5 firewire: Impleme... |
1112 1113 1114 1115 1116 1117 |
} static struct fw_address_handler registers = { .length = 0x400, .address_callback = handle_registers, }; |
3038e353c firewire: Add cor... |
1118 1119 1120 |
MODULE_AUTHOR("Kristian Hoegsberg <krh@bitplanet.net>"); MODULE_DESCRIPTION("Core IEEE1394 transaction logic"); MODULE_LICENSE("GPL"); |
937f68796 firewire: Let an ... |
1121 |
static const u32 vendor_textual_descriptor[] = { |
3038e353c firewire: Add cor... |
1122 |
/* textual descriptor leaf () */ |
937f68796 firewire: Let an ... |
1123 |
0x00060000, |
3038e353c firewire: Add cor... |
1124 1125 1126 1127 1128 |
0x00000000, 0x00000000, 0x4c696e75, /* L i n u */ 0x78204669, /* x F i */ 0x72657769, /* r e w i */ |
937f68796 firewire: Let an ... |
1129 |
0x72650000, /* r e */ |
3038e353c firewire: Add cor... |
1130 |
}; |
937f68796 firewire: Let an ... |
1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 |
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), .immediate = 0x03d00d1e, |
3038e353c firewire: Add cor... |
1142 |
.key = 0x81000000, |
937f68796 firewire: Let an ... |
1143 1144 1145 1146 1147 1148 1149 1150 |
.data = vendor_textual_descriptor, }; static struct fw_descriptor model_id_descriptor = { .length = ARRAY_SIZE(model_textual_descriptor), .immediate = 0x17000001, .key = 0x81000000, .data = model_textual_descriptor, |
3038e353c firewire: Add cor... |
1151 |
}; |
3038e353c firewire: Add cor... |
1152 1153 |
static int __init fw_core_init(void) { |
2dbd7d7e2 firewire: standar... |
1154 |
int ret; |
3038e353c firewire: Add cor... |
1155 |
|
105e53f86 firewire: sbp2: p... |
1156 1157 1158 |
fw_workqueue = alloc_workqueue("firewire", WQ_NON_REENTRANT | WQ_MEM_RECLAIM, 0); if (!fw_workqueue) |
6ea9e7bbf firewire: core: u... |
1159 |
return -ENOMEM; |
2dbd7d7e2 firewire: standar... |
1160 |
ret = bus_register(&fw_bus_type); |
6ea9e7bbf firewire: core: u... |
1161 |
if (ret < 0) { |
105e53f86 firewire: sbp2: p... |
1162 |
destroy_workqueue(fw_workqueue); |
2dbd7d7e2 firewire: standar... |
1163 |
return ret; |
6ea9e7bbf firewire: core: u... |
1164 |
} |
3038e353c firewire: Add cor... |
1165 |
|
a3aca3dab firewire: Switch ... |
1166 1167 1168 |
fw_cdev_major = register_chrdev(0, "firewire", &fw_device_ops); if (fw_cdev_major < 0) { bus_unregister(&fw_bus_type); |
105e53f86 firewire: sbp2: p... |
1169 |
destroy_workqueue(fw_workqueue); |
a3aca3dab firewire: Switch ... |
1170 1171 |
return fw_cdev_major; } |
c490a6dec firewire: core: r... |
1172 1173 1174 1175 |
fw_core_add_address_handler(&topology_map, &topology_map_region); fw_core_add_address_handler(®isters, ®isters_region); fw_core_add_descriptor(&vendor_id_descriptor); fw_core_add_descriptor(&model_id_descriptor); |
3038e353c firewire: Add cor... |
1176 1177 1178 1179 1180 1181 |
return 0; } static void __exit fw_core_cleanup(void) { |
a3aca3dab firewire: Switch ... |
1182 |
unregister_chrdev(fw_cdev_major, "firewire"); |
3038e353c firewire: Add cor... |
1183 |
bus_unregister(&fw_bus_type); |
105e53f86 firewire: sbp2: p... |
1184 |
destroy_workqueue(fw_workqueue); |
d6053e08f firewire: fix sma... |
1185 |
idr_destroy(&fw_device_idr); |
3038e353c firewire: Add cor... |
1186 1187 1188 1189 |
} module_init(fw_core_init); module_exit(fw_core_cleanup); |