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