blob: 6f07cd8835a30e983f762366156f267e4bf8a2f0 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * IEEE 1394 for Linux
3 *
4 * Transaction support.
5 *
6 * Copyright (C) 1999 Andreas E. Bombe
7 *
8 * This code is licensed under the GPL. See the file COPYING in the root
9 * directory of the kernel sources for details.
10 */
11
Linus Torvalds1da177e2005-04-16 15:20:36 -070012#include <linux/bitops.h>
Stefan Richter99519032006-07-02 14:17:00 +020013#include <linux/spinlock.h>
14#include <linux/wait.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070015
Stefan Richterd83e7d82006-07-03 12:02:31 -040016#include <asm/bug.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070017#include <asm/errno.h>
18
19#include "ieee1394.h"
20#include "ieee1394_types.h"
21#include "hosts.h"
22#include "ieee1394_core.h"
Adrian Bunke27d3012005-11-19 21:23:48 -050023#include "ieee1394_transactions.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070024
Linus Torvalds1da177e2005-04-16 15:20:36 -070025#define PREP_ASYNC_HEAD_ADDRESS(tc) \
26 packet->tcode = tc; \
27 packet->header[0] = (packet->node_id << 16) | (packet->tlabel << 10) \
28 | (1 << 8) | (tc << 4); \
29 packet->header[1] = (packet->host->node_id << 16) | (addr >> 32); \
30 packet->header[2] = addr & 0xffffffff
31
Stefan Richter99519032006-07-02 14:17:00 +020032#ifndef HPSB_DEBUG_TLABELS
33static
34#endif
35spinlock_t hpsb_tlabel_lock = SPIN_LOCK_UNLOCKED;
36
37static DECLARE_WAIT_QUEUE_HEAD(tlabel_wq);
38
Linus Torvalds1da177e2005-04-16 15:20:36 -070039static void fill_async_readquad(struct hpsb_packet *packet, u64 addr)
40{
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -050041 PREP_ASYNC_HEAD_ADDRESS(TCODE_READQ);
42 packet->header_size = 12;
43 packet->data_size = 0;
44 packet->expect_response = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070045}
46
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -050047static void fill_async_readblock(struct hpsb_packet *packet, u64 addr,
48 int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -070049{
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -050050 PREP_ASYNC_HEAD_ADDRESS(TCODE_READB);
51 packet->header[3] = length << 16;
52 packet->header_size = 16;
53 packet->data_size = 0;
54 packet->expect_response = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070055}
56
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -050057static void fill_async_writequad(struct hpsb_packet *packet, u64 addr,
58 quadlet_t data)
Linus Torvalds1da177e2005-04-16 15:20:36 -070059{
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -050060 PREP_ASYNC_HEAD_ADDRESS(TCODE_WRITEQ);
61 packet->header[3] = data;
62 packet->header_size = 16;
63 packet->data_size = 0;
64 packet->expect_response = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070065}
66
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -050067static void fill_async_writeblock(struct hpsb_packet *packet, u64 addr,
68 int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -070069{
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -050070 PREP_ASYNC_HEAD_ADDRESS(TCODE_WRITEB);
71 packet->header[3] = length << 16;
72 packet->header_size = 16;
73 packet->expect_response = 1;
74 packet->data_size = length + (length % 4 ? 4 - (length % 4) : 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070075}
76
77static void fill_async_lock(struct hpsb_packet *packet, u64 addr, int extcode,
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -050078 int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -070079{
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -050080 PREP_ASYNC_HEAD_ADDRESS(TCODE_LOCK_REQUEST);
81 packet->header[3] = (length << 16) | extcode;
82 packet->header_size = 16;
83 packet->data_size = length;
84 packet->expect_response = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070085}
86
87static void fill_iso_packet(struct hpsb_packet *packet, int length, int channel,
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -050088 int tag, int sync)
Linus Torvalds1da177e2005-04-16 15:20:36 -070089{
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -050090 packet->header[0] = (length << 16) | (tag << 14) | (channel << 8)
91 | (TCODE_ISO_DATA << 4) | sync;
Linus Torvalds1da177e2005-04-16 15:20:36 -070092
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -050093 packet->header_size = 4;
94 packet->data_size = length;
95 packet->type = hpsb_iso;
96 packet->tcode = TCODE_ISO_DATA;
Linus Torvalds1da177e2005-04-16 15:20:36 -070097}
98
99static void fill_phy_packet(struct hpsb_packet *packet, quadlet_t data)
100{
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500101 packet->header[0] = data;
102 packet->header[1] = ~data;
103 packet->header_size = 8;
104 packet->data_size = 0;
105 packet->expect_response = 0;
106 packet->type = hpsb_raw; /* No CRC added */
107 packet->speed_code = IEEE1394_SPEED_100; /* Force speed to be 100Mbps */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108}
109
110static void fill_async_stream_packet(struct hpsb_packet *packet, int length,
111 int channel, int tag, int sync)
112{
113 packet->header[0] = (length << 16) | (tag << 14) | (channel << 8)
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500114 | (TCODE_STREAM_DATA << 4) | sync;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115
116 packet->header_size = 4;
117 packet->data_size = length;
118 packet->type = hpsb_async;
119 packet->tcode = TCODE_ISO_DATA;
120}
121
Stefan Richter99519032006-07-02 14:17:00 +0200122/* same as hpsb_get_tlabel, except that it returns immediately */
123static int hpsb_get_tlabel_atomic(struct hpsb_packet *packet)
124{
125 unsigned long flags, *tp;
126 u8 *next;
127 int tlabel, n = NODEID_TO_NODE(packet->node_id);
128
129 /* Broadcast transactions are complete once the request has been sent.
130 * Use the same transaction label for all broadcast transactions. */
131 if (unlikely(n == ALL_NODES)) {
132 packet->tlabel = 0;
133 return 0;
134 }
135 tp = packet->host->tl_pool[n].map;
136 next = &packet->host->next_tl[n];
137
138 spin_lock_irqsave(&hpsb_tlabel_lock, flags);
139 tlabel = find_next_zero_bit(tp, 64, *next);
140 if (tlabel > 63)
141 tlabel = find_first_zero_bit(tp, 64);
142 if (tlabel > 63) {
143 spin_unlock_irqrestore(&hpsb_tlabel_lock, flags);
144 return -EAGAIN;
145 }
146 __set_bit(tlabel, tp);
147 *next = (tlabel + 1) & 63;
148 spin_unlock_irqrestore(&hpsb_tlabel_lock, flags);
149
150 packet->tlabel = tlabel;
151 return 0;
152}
153
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154/**
155 * hpsb_get_tlabel - allocate a transaction label
Stefan Richter99519032006-07-02 14:17:00 +0200156 * @packet: the packet whose tlabel and tl_pool we set
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157 *
158 * Every asynchronous transaction on the 1394 bus needs a transaction
159 * label to match the response to the request. This label has to be
160 * different from any other transaction label in an outstanding request to
161 * the same node to make matching possible without ambiguity.
162 *
163 * There are 64 different tlabels, so an allocated tlabel has to be freed
164 * with hpsb_free_tlabel() after the transaction is complete (unless it's
165 * reused again for the same target node).
166 *
167 * Return value: Zero on success, otherwise non-zero. A non-zero return
168 * generally means there are no available tlabels. If this is called out
169 * of interrupt or atomic context, then it will sleep until can return a
Stefan Richter99519032006-07-02 14:17:00 +0200170 * tlabel or a signal is received.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171 */
172int hpsb_get_tlabel(struct hpsb_packet *packet)
173{
Stefan Richter99519032006-07-02 14:17:00 +0200174 if (irqs_disabled() || in_atomic())
175 return hpsb_get_tlabel_atomic(packet);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176
Stefan Richter99519032006-07-02 14:17:00 +0200177 /* NB: The macro wait_event_interruptible() is called with a condition
178 * argument with side effect. This is only possible because the side
179 * effect does not occur until the condition became true, and
180 * wait_event_interruptible() won't evaluate the condition again after
181 * that. */
182 return wait_event_interruptible(tlabel_wq,
183 !hpsb_get_tlabel_atomic(packet));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184}
185
186/**
187 * hpsb_free_tlabel - free an allocated transaction label
Stefan Richter99519032006-07-02 14:17:00 +0200188 * @packet: packet whose tlabel and tl_pool needs to be cleared
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189 *
190 * Frees the transaction label allocated with hpsb_get_tlabel(). The
191 * tlabel has to be freed after the transaction is complete (i.e. response
192 * was received for a split transaction or packet was sent for a unified
193 * transaction).
194 *
195 * A tlabel must not be freed twice.
196 */
197void hpsb_free_tlabel(struct hpsb_packet *packet)
198{
Stefan Richter99519032006-07-02 14:17:00 +0200199 unsigned long flags, *tp;
200 int tlabel, n = NODEID_TO_NODE(packet->node_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201
Ben Collinseaf88452006-06-12 18:12:49 -0400202 if (unlikely(n == ALL_NODES))
203 return;
Stefan Richter99519032006-07-02 14:17:00 +0200204 tp = packet->host->tl_pool[n].map;
205 tlabel = packet->tlabel;
206 BUG_ON(tlabel > 63 || tlabel < 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207
Stefan Richter99519032006-07-02 14:17:00 +0200208 spin_lock_irqsave(&hpsb_tlabel_lock, flags);
209 BUG_ON(!__test_and_clear_bit(tlabel, tp));
210 spin_unlock_irqrestore(&hpsb_tlabel_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211
Stefan Richter99519032006-07-02 14:17:00 +0200212 wake_up_interruptible(&tlabel_wq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213}
214
Stefan Richterafd65462007-03-05 03:06:23 +0100215/**
216 * hpsb_packet_success - Make sense of the ack and reply codes
217 *
218 * Make sense of the ack and reply codes and return more convenient error codes:
219 * 0 = success. -%EBUSY = node is busy, try again. -%EAGAIN = error which can
220 * probably resolved by retry. -%EREMOTEIO = node suffers from an internal
221 * error. -%EACCES = this transaction is not allowed on requested address.
222 * -%EINVAL = invalid address at node.
223 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224int hpsb_packet_success(struct hpsb_packet *packet)
225{
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500226 switch (packet->ack_code) {
227 case ACK_PENDING:
228 switch ((packet->header[1] >> 12) & 0xf) {
229 case RCODE_COMPLETE:
230 return 0;
231 case RCODE_CONFLICT_ERROR:
232 return -EAGAIN;
233 case RCODE_DATA_ERROR:
234 return -EREMOTEIO;
235 case RCODE_TYPE_ERROR:
236 return -EACCES;
237 case RCODE_ADDRESS_ERROR:
238 return -EINVAL;
239 default:
240 HPSB_ERR("received reserved rcode %d from node %d",
241 (packet->header[1] >> 12) & 0xf,
242 packet->node_id);
243 return -EAGAIN;
244 }
Stefan Richterd83e7d82006-07-03 12:02:31 -0400245 BUG();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500247 case ACK_BUSY_X:
248 case ACK_BUSY_A:
249 case ACK_BUSY_B:
250 return -EBUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500252 case ACK_TYPE_ERROR:
253 return -EACCES;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500255 case ACK_COMPLETE:
256 if (packet->tcode == TCODE_WRITEQ
257 || packet->tcode == TCODE_WRITEB) {
258 return 0;
259 } else {
260 HPSB_ERR("impossible ack_complete from node %d "
261 "(tcode %d)", packet->node_id, packet->tcode);
262 return -EAGAIN;
263 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500265 case ACK_DATA_ERROR:
266 if (packet->tcode == TCODE_WRITEB
267 || packet->tcode == TCODE_LOCK_REQUEST) {
268 return -EAGAIN;
269 } else {
270 HPSB_ERR("impossible ack_data_error from node %d "
271 "(tcode %d)", packet->node_id, packet->tcode);
272 return -EAGAIN;
273 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500275 case ACK_ADDRESS_ERROR:
276 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500278 case ACK_TARDY:
279 case ACK_CONFLICT_ERROR:
280 case ACKX_NONE:
281 case ACKX_SEND_ERROR:
282 case ACKX_ABORTED:
283 case ACKX_TIMEOUT:
284 /* error while sending */
285 return -EAGAIN;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500287 default:
288 HPSB_ERR("got invalid ack %d from node %d (tcode %d)",
289 packet->ack_code, packet->node_id, packet->tcode);
290 return -EAGAIN;
291 }
Stefan Richterd83e7d82006-07-03 12:02:31 -0400292 BUG();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293}
294
295struct hpsb_packet *hpsb_make_readpacket(struct hpsb_host *host, nodeid_t node,
296 u64 addr, size_t length)
297{
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500298 struct hpsb_packet *packet;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299
300 if (length == 0)
301 return NULL;
302
303 packet = hpsb_alloc_packet(length);
304 if (!packet)
305 return NULL;
306
307 packet->host = host;
308 packet->node_id = node;
309
310 if (hpsb_get_tlabel(packet)) {
311 hpsb_free_packet(packet);
312 return NULL;
313 }
314
315 if (length == 4)
316 fill_async_readquad(packet, addr);
317 else
318 fill_async_readblock(packet, addr, length);
319
320 return packet;
321}
322
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500323struct hpsb_packet *hpsb_make_writepacket(struct hpsb_host *host, nodeid_t node,
324 u64 addr, quadlet_t * buffer,
325 size_t length)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326{
327 struct hpsb_packet *packet;
328
329 if (length == 0)
330 return NULL;
331
332 packet = hpsb_alloc_packet(length);
333 if (!packet)
334 return NULL;
335
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500336 if (length % 4) { /* zero padding bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 packet->data[length >> 2] = 0;
338 }
339 packet->host = host;
340 packet->node_id = node;
341
342 if (hpsb_get_tlabel(packet)) {
343 hpsb_free_packet(packet);
344 return NULL;
345 }
346
347 if (length == 4) {
348 fill_async_writequad(packet, addr, buffer ? *buffer : 0);
349 } else {
350 fill_async_writeblock(packet, addr, length);
351 if (buffer)
352 memcpy(packet->data, buffer, length);
353 }
354
355 return packet;
356}
357
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500358struct hpsb_packet *hpsb_make_streampacket(struct hpsb_host *host, u8 * buffer,
359 int length, int channel, int tag,
360 int sync)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361{
362 struct hpsb_packet *packet;
363
364 if (length == 0)
365 return NULL;
366
367 packet = hpsb_alloc_packet(length);
368 if (!packet)
369 return NULL;
370
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500371 if (length % 4) { /* zero padding bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 packet->data[length >> 2] = 0;
373 }
374 packet->host = host;
375
376 if (hpsb_get_tlabel(packet)) {
377 hpsb_free_packet(packet);
378 return NULL;
379 }
380
381 fill_async_stream_packet(packet, length, channel, tag, sync);
382 if (buffer)
383 memcpy(packet->data, buffer, length);
384
385 return packet;
386}
387
388struct hpsb_packet *hpsb_make_lockpacket(struct hpsb_host *host, nodeid_t node,
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500389 u64 addr, int extcode,
390 quadlet_t * data, quadlet_t arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391{
392 struct hpsb_packet *p;
393 u32 length;
394
395 p = hpsb_alloc_packet(8);
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500396 if (!p)
397 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398
399 p->host = host;
400 p->node_id = node;
401 if (hpsb_get_tlabel(p)) {
402 hpsb_free_packet(p);
403 return NULL;
404 }
405
406 switch (extcode) {
407 case EXTCODE_FETCH_ADD:
408 case EXTCODE_LITTLE_ADD:
409 length = 4;
410 if (data)
411 p->data[0] = *data;
412 break;
413 default:
414 length = 8;
415 if (data) {
416 p->data[0] = arg;
417 p->data[1] = *data;
418 }
419 break;
420 }
421 fill_async_lock(p, addr, extcode, length);
422
423 return p;
424}
425
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500426struct hpsb_packet *hpsb_make_lock64packet(struct hpsb_host *host,
427 nodeid_t node, u64 addr, int extcode,
428 octlet_t * data, octlet_t arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429{
430 struct hpsb_packet *p;
431 u32 length;
432
433 p = hpsb_alloc_packet(16);
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500434 if (!p)
435 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436
437 p->host = host;
438 p->node_id = node;
439 if (hpsb_get_tlabel(p)) {
440 hpsb_free_packet(p);
441 return NULL;
442 }
443
444 switch (extcode) {
445 case EXTCODE_FETCH_ADD:
446 case EXTCODE_LITTLE_ADD:
447 length = 8;
448 if (data) {
449 p->data[0] = *data >> 32;
450 p->data[1] = *data & 0xffffffff;
451 }
452 break;
453 default:
454 length = 16;
455 if (data) {
456 p->data[0] = arg >> 32;
457 p->data[1] = arg & 0xffffffff;
458 p->data[2] = *data >> 32;
459 p->data[3] = *data & 0xffffffff;
460 }
461 break;
462 }
463 fill_async_lock(p, addr, extcode, length);
464
465 return p;
466}
467
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500468struct hpsb_packet *hpsb_make_phypacket(struct hpsb_host *host, quadlet_t data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469{
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500470 struct hpsb_packet *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500472 p = hpsb_alloc_packet(0);
473 if (!p)
474 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500476 p->host = host;
477 fill_phy_packet(p, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500479 return p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480}
481
482struct hpsb_packet *hpsb_make_isopacket(struct hpsb_host *host,
483 int length, int channel,
484 int tag, int sync)
485{
486 struct hpsb_packet *p;
487
488 p = hpsb_alloc_packet(length);
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500489 if (!p)
490 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491
492 p->host = host;
493 fill_iso_packet(p, length, channel, tag, sync);
494
495 p->generation = get_hpsb_generation(host);
496
497 return p;
498}
499
500/*
501 * FIXME - these functions should probably read from / write to user space to
502 * avoid in kernel buffers for user space callers
503 */
504
Stefan Richterafd65462007-03-05 03:06:23 +0100505/**
506 * hpsb_read - generic read function
507 *
508 * Recognizes the local node ID and act accordingly. Automatically uses a
509 * quadlet read request if @length == 4 and and a block read request otherwise.
510 * It does not yet support lengths that are not a multiple of 4.
511 *
512 * You must explicitly specifiy the @generation for which the node ID is valid,
513 * to avoid sending packets to the wrong nodes when we race with a bus reset.
514 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515int hpsb_read(struct hpsb_host *host, nodeid_t node, unsigned int generation,
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500516 u64 addr, quadlet_t * buffer, size_t length)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517{
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500518 struct hpsb_packet *packet;
519 int retval = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500521 if (length == 0)
522 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500524 BUG_ON(in_interrupt()); // We can't be called in an interrupt, yet
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525
526 packet = hpsb_make_readpacket(host, node, addr, length);
527
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500528 if (!packet) {
529 return -ENOMEM;
530 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531
532 packet->generation = generation;
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500533 retval = hpsb_send_packet_and_wait(packet);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534 if (retval < 0)
535 goto hpsb_read_fail;
536
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500537 retval = hpsb_packet_success(packet);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500539 if (retval == 0) {
540 if (length == 4) {
541 *buffer = packet->header[3];
542 } else {
543 memcpy(buffer, packet->data, length);
544 }
545 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500547 hpsb_read_fail:
548 hpsb_free_tlabel(packet);
549 hpsb_free_packet(packet);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500551 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552}
553
Stefan Richterafd65462007-03-05 03:06:23 +0100554/**
555 * hpsb_write - generic write function
556 *
557 * Recognizes the local node ID and act accordingly. Automatically uses a
558 * quadlet write request if @length == 4 and and a block write request
559 * otherwise. It does not yet support lengths that are not a multiple of 4.
560 *
561 * You must explicitly specifiy the @generation for which the node ID is valid,
562 * to avoid sending packets to the wrong nodes when we race with a bus reset.
563 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564int hpsb_write(struct hpsb_host *host, nodeid_t node, unsigned int generation,
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500565 u64 addr, quadlet_t * buffer, size_t length)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566{
567 struct hpsb_packet *packet;
568 int retval;
569
570 if (length == 0)
571 return -EINVAL;
572
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500573 BUG_ON(in_interrupt()); // We can't be called in an interrupt, yet
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500575 packet = hpsb_make_writepacket(host, node, addr, buffer, length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576
577 if (!packet)
578 return -ENOMEM;
579
580 packet->generation = generation;
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500581 retval = hpsb_send_packet_and_wait(packet);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 if (retval < 0)
583 goto hpsb_write_fail;
584
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500585 retval = hpsb_packet_success(packet);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500587 hpsb_write_fail:
588 hpsb_free_tlabel(packet);
589 hpsb_free_packet(packet);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500591 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592}
593
Jody McIntyre9ac485d2005-05-16 21:54:00 -0700594#if 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595
596int hpsb_lock(struct hpsb_host *host, nodeid_t node, unsigned int generation,
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500597 u64 addr, int extcode, quadlet_t * data, quadlet_t arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598{
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500599 struct hpsb_packet *packet;
600 int retval = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500602 BUG_ON(in_interrupt()); // We can't be called in an interrupt, yet
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603
604 packet = hpsb_make_lockpacket(host, node, addr, extcode, data, arg);
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500605 if (!packet)
606 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607
608 packet->generation = generation;
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500609 retval = hpsb_send_packet_and_wait(packet);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 if (retval < 0)
611 goto hpsb_lock_fail;
612
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500613 retval = hpsb_packet_success(packet);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500615 if (retval == 0) {
616 *data = packet->data[0];
617 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500619 hpsb_lock_fail:
620 hpsb_free_tlabel(packet);
621 hpsb_free_packet(packet);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500623 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624}
625
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626int hpsb_send_gasp(struct hpsb_host *host, int channel, unsigned int generation,
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500627 quadlet_t * buffer, size_t length, u32 specifier_id,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628 unsigned int version)
629{
630 struct hpsb_packet *packet;
631 int retval = 0;
632 u16 specifier_id_hi = (specifier_id & 0x00ffff00) >> 8;
633 u8 specifier_id_lo = specifier_id & 0xff;
634
635 HPSB_VERBOSE("Send GASP: channel = %d, length = %Zd", channel, length);
636
637 length += 8;
638
639 packet = hpsb_make_streampacket(host, NULL, length, channel, 3, 0);
640 if (!packet)
641 return -ENOMEM;
642
643 packet->data[0] = cpu_to_be32((host->node_id << 16) | specifier_id_hi);
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500644 packet->data[1] =
645 cpu_to_be32((specifier_id_lo << 24) | (version & 0x00ffffff));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646
647 memcpy(&(packet->data[2]), buffer, length - 8);
648
649 packet->generation = generation;
650
651 packet->no_waiter = 1;
652
653 retval = hpsb_send_packet(packet);
654 if (retval < 0)
655 hpsb_free_packet(packet);
656
657 return retval;
658}
Jody McIntyre9ac485d2005-05-16 21:54:00 -0700659
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500660#endif /* 0 */