blob: d1a0d3cb97d01f8e13e9de7b2a54bdb482db1934 [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 Richter7fb9add2007-03-11 22:49:05 +010013#include <linux/hardirq.h>
Stefan Richter99519032006-07-02 14:17:00 +020014#include <linux/spinlock.h>
15#include <linux/wait.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070016
Stefan Richterd83e7d82006-07-03 12:02:31 -040017#include <asm/bug.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070018#include <asm/errno.h>
19
20#include "ieee1394.h"
21#include "ieee1394_types.h"
22#include "hosts.h"
23#include "ieee1394_core.h"
Adrian Bunke27d3012005-11-19 21:23:48 -050024#include "ieee1394_transactions.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070025
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#define PREP_ASYNC_HEAD_ADDRESS(tc) \
27 packet->tcode = tc; \
28 packet->header[0] = (packet->node_id << 16) | (packet->tlabel << 10) \
29 | (1 << 8) | (tc << 4); \
30 packet->header[1] = (packet->host->node_id << 16) | (addr >> 32); \
31 packet->header[2] = addr & 0xffffffff
32
Stefan Richter99519032006-07-02 14:17:00 +020033#ifndef HPSB_DEBUG_TLABELS
34static
35#endif
36spinlock_t hpsb_tlabel_lock = SPIN_LOCK_UNLOCKED;
37
38static DECLARE_WAIT_QUEUE_HEAD(tlabel_wq);
39
Linus Torvalds1da177e2005-04-16 15:20:36 -070040static void fill_async_readquad(struct hpsb_packet *packet, u64 addr)
41{
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -050042 PREP_ASYNC_HEAD_ADDRESS(TCODE_READQ);
43 packet->header_size = 12;
44 packet->data_size = 0;
45 packet->expect_response = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070046}
47
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -050048static void fill_async_readblock(struct hpsb_packet *packet, u64 addr,
49 int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -070050{
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -050051 PREP_ASYNC_HEAD_ADDRESS(TCODE_READB);
52 packet->header[3] = length << 16;
53 packet->header_size = 16;
54 packet->data_size = 0;
55 packet->expect_response = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070056}
57
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -050058static void fill_async_writequad(struct hpsb_packet *packet, u64 addr,
59 quadlet_t data)
Linus Torvalds1da177e2005-04-16 15:20:36 -070060{
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -050061 PREP_ASYNC_HEAD_ADDRESS(TCODE_WRITEQ);
62 packet->header[3] = data;
63 packet->header_size = 16;
64 packet->data_size = 0;
65 packet->expect_response = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070066}
67
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -050068static void fill_async_writeblock(struct hpsb_packet *packet, u64 addr,
69 int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -070070{
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -050071 PREP_ASYNC_HEAD_ADDRESS(TCODE_WRITEB);
72 packet->header[3] = length << 16;
73 packet->header_size = 16;
74 packet->expect_response = 1;
75 packet->data_size = length + (length % 4 ? 4 - (length % 4) : 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070076}
77
78static void fill_async_lock(struct hpsb_packet *packet, u64 addr, int extcode,
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -050079 int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -070080{
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -050081 PREP_ASYNC_HEAD_ADDRESS(TCODE_LOCK_REQUEST);
82 packet->header[3] = (length << 16) | extcode;
83 packet->header_size = 16;
84 packet->data_size = length;
85 packet->expect_response = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070086}
87
88static void fill_iso_packet(struct hpsb_packet *packet, int length, int channel,
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -050089 int tag, int sync)
Linus Torvalds1da177e2005-04-16 15:20:36 -070090{
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -050091 packet->header[0] = (length << 16) | (tag << 14) | (channel << 8)
92 | (TCODE_ISO_DATA << 4) | sync;
Linus Torvalds1da177e2005-04-16 15:20:36 -070093
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -050094 packet->header_size = 4;
95 packet->data_size = length;
96 packet->type = hpsb_iso;
97 packet->tcode = TCODE_ISO_DATA;
Linus Torvalds1da177e2005-04-16 15:20:36 -070098}
99
100static void fill_phy_packet(struct hpsb_packet *packet, quadlet_t data)
101{
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500102 packet->header[0] = data;
103 packet->header[1] = ~data;
104 packet->header_size = 8;
105 packet->data_size = 0;
106 packet->expect_response = 0;
107 packet->type = hpsb_raw; /* No CRC added */
108 packet->speed_code = IEEE1394_SPEED_100; /* Force speed to be 100Mbps */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109}
110
111static void fill_async_stream_packet(struct hpsb_packet *packet, int length,
112 int channel, int tag, int sync)
113{
114 packet->header[0] = (length << 16) | (tag << 14) | (channel << 8)
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500115 | (TCODE_STREAM_DATA << 4) | sync;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116
117 packet->header_size = 4;
118 packet->data_size = length;
119 packet->type = hpsb_async;
120 packet->tcode = TCODE_ISO_DATA;
121}
122
Stefan Richter99519032006-07-02 14:17:00 +0200123/* same as hpsb_get_tlabel, except that it returns immediately */
124static int hpsb_get_tlabel_atomic(struct hpsb_packet *packet)
125{
126 unsigned long flags, *tp;
127 u8 *next;
128 int tlabel, n = NODEID_TO_NODE(packet->node_id);
129
130 /* Broadcast transactions are complete once the request has been sent.
131 * Use the same transaction label for all broadcast transactions. */
132 if (unlikely(n == ALL_NODES)) {
133 packet->tlabel = 0;
134 return 0;
135 }
136 tp = packet->host->tl_pool[n].map;
137 next = &packet->host->next_tl[n];
138
139 spin_lock_irqsave(&hpsb_tlabel_lock, flags);
140 tlabel = find_next_zero_bit(tp, 64, *next);
141 if (tlabel > 63)
142 tlabel = find_first_zero_bit(tp, 64);
143 if (tlabel > 63) {
144 spin_unlock_irqrestore(&hpsb_tlabel_lock, flags);
145 return -EAGAIN;
146 }
147 __set_bit(tlabel, tp);
148 *next = (tlabel + 1) & 63;
149 spin_unlock_irqrestore(&hpsb_tlabel_lock, flags);
150
151 packet->tlabel = tlabel;
152 return 0;
153}
154
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155/**
156 * hpsb_get_tlabel - allocate a transaction label
Stefan Richter99519032006-07-02 14:17:00 +0200157 * @packet: the packet whose tlabel and tl_pool we set
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158 *
159 * Every asynchronous transaction on the 1394 bus needs a transaction
160 * label to match the response to the request. This label has to be
161 * different from any other transaction label in an outstanding request to
162 * the same node to make matching possible without ambiguity.
163 *
164 * There are 64 different tlabels, so an allocated tlabel has to be freed
165 * with hpsb_free_tlabel() after the transaction is complete (unless it's
166 * reused again for the same target node).
167 *
168 * Return value: Zero on success, otherwise non-zero. A non-zero return
169 * generally means there are no available tlabels. If this is called out
170 * of interrupt or atomic context, then it will sleep until can return a
Stefan Richter99519032006-07-02 14:17:00 +0200171 * tlabel or a signal is received.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 */
173int hpsb_get_tlabel(struct hpsb_packet *packet)
174{
Stefan Richter99519032006-07-02 14:17:00 +0200175 if (irqs_disabled() || in_atomic())
176 return hpsb_get_tlabel_atomic(packet);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177
Stefan Richter99519032006-07-02 14:17:00 +0200178 /* NB: The macro wait_event_interruptible() is called with a condition
179 * argument with side effect. This is only possible because the side
180 * effect does not occur until the condition became true, and
181 * wait_event_interruptible() won't evaluate the condition again after
182 * that. */
183 return wait_event_interruptible(tlabel_wq,
184 !hpsb_get_tlabel_atomic(packet));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185}
186
187/**
188 * hpsb_free_tlabel - free an allocated transaction label
Stefan Richter99519032006-07-02 14:17:00 +0200189 * @packet: packet whose tlabel and tl_pool needs to be cleared
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190 *
191 * Frees the transaction label allocated with hpsb_get_tlabel(). The
192 * tlabel has to be freed after the transaction is complete (i.e. response
193 * was received for a split transaction or packet was sent for a unified
194 * transaction).
195 *
196 * A tlabel must not be freed twice.
197 */
198void hpsb_free_tlabel(struct hpsb_packet *packet)
199{
Stefan Richter99519032006-07-02 14:17:00 +0200200 unsigned long flags, *tp;
201 int tlabel, n = NODEID_TO_NODE(packet->node_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202
Ben Collinseaf88452006-06-12 18:12:49 -0400203 if (unlikely(n == ALL_NODES))
204 return;
Stefan Richter99519032006-07-02 14:17:00 +0200205 tp = packet->host->tl_pool[n].map;
206 tlabel = packet->tlabel;
207 BUG_ON(tlabel > 63 || tlabel < 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208
Stefan Richter99519032006-07-02 14:17:00 +0200209 spin_lock_irqsave(&hpsb_tlabel_lock, flags);
210 BUG_ON(!__test_and_clear_bit(tlabel, tp));
211 spin_unlock_irqrestore(&hpsb_tlabel_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212
Stefan Richter99519032006-07-02 14:17:00 +0200213 wake_up_interruptible(&tlabel_wq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214}
215
Stefan Richterafd65462007-03-05 03:06:23 +0100216/**
217 * hpsb_packet_success - Make sense of the ack and reply codes
218 *
219 * Make sense of the ack and reply codes and return more convenient error codes:
220 * 0 = success. -%EBUSY = node is busy, try again. -%EAGAIN = error which can
221 * probably resolved by retry. -%EREMOTEIO = node suffers from an internal
222 * error. -%EACCES = this transaction is not allowed on requested address.
223 * -%EINVAL = invalid address at node.
224 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225int hpsb_packet_success(struct hpsb_packet *packet)
226{
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500227 switch (packet->ack_code) {
228 case ACK_PENDING:
229 switch ((packet->header[1] >> 12) & 0xf) {
230 case RCODE_COMPLETE:
231 return 0;
232 case RCODE_CONFLICT_ERROR:
233 return -EAGAIN;
234 case RCODE_DATA_ERROR:
235 return -EREMOTEIO;
236 case RCODE_TYPE_ERROR:
237 return -EACCES;
238 case RCODE_ADDRESS_ERROR:
239 return -EINVAL;
240 default:
241 HPSB_ERR("received reserved rcode %d from node %d",
242 (packet->header[1] >> 12) & 0xf,
243 packet->node_id);
244 return -EAGAIN;
245 }
Stefan Richterd83e7d82006-07-03 12:02:31 -0400246 BUG();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500248 case ACK_BUSY_X:
249 case ACK_BUSY_A:
250 case ACK_BUSY_B:
251 return -EBUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500253 case ACK_TYPE_ERROR:
254 return -EACCES;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500256 case ACK_COMPLETE:
257 if (packet->tcode == TCODE_WRITEQ
258 || packet->tcode == TCODE_WRITEB) {
259 return 0;
260 } else {
261 HPSB_ERR("impossible ack_complete from node %d "
262 "(tcode %d)", packet->node_id, packet->tcode);
263 return -EAGAIN;
264 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500266 case ACK_DATA_ERROR:
267 if (packet->tcode == TCODE_WRITEB
268 || packet->tcode == TCODE_LOCK_REQUEST) {
269 return -EAGAIN;
270 } else {
271 HPSB_ERR("impossible ack_data_error from node %d "
272 "(tcode %d)", packet->node_id, packet->tcode);
273 return -EAGAIN;
274 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500276 case ACK_ADDRESS_ERROR:
277 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500279 case ACK_TARDY:
280 case ACK_CONFLICT_ERROR:
281 case ACKX_NONE:
282 case ACKX_SEND_ERROR:
283 case ACKX_ABORTED:
284 case ACKX_TIMEOUT:
285 /* error while sending */
286 return -EAGAIN;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500288 default:
289 HPSB_ERR("got invalid ack %d from node %d (tcode %d)",
290 packet->ack_code, packet->node_id, packet->tcode);
291 return -EAGAIN;
292 }
Stefan Richterd83e7d82006-07-03 12:02:31 -0400293 BUG();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294}
295
296struct hpsb_packet *hpsb_make_readpacket(struct hpsb_host *host, nodeid_t node,
297 u64 addr, size_t length)
298{
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500299 struct hpsb_packet *packet;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300
301 if (length == 0)
302 return NULL;
303
304 packet = hpsb_alloc_packet(length);
305 if (!packet)
306 return NULL;
307
308 packet->host = host;
309 packet->node_id = node;
310
311 if (hpsb_get_tlabel(packet)) {
312 hpsb_free_packet(packet);
313 return NULL;
314 }
315
316 if (length == 4)
317 fill_async_readquad(packet, addr);
318 else
319 fill_async_readblock(packet, addr, length);
320
321 return packet;
322}
323
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500324struct hpsb_packet *hpsb_make_writepacket(struct hpsb_host *host, nodeid_t node,
325 u64 addr, quadlet_t * buffer,
326 size_t length)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327{
328 struct hpsb_packet *packet;
329
330 if (length == 0)
331 return NULL;
332
333 packet = hpsb_alloc_packet(length);
334 if (!packet)
335 return NULL;
336
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500337 if (length % 4) { /* zero padding bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 packet->data[length >> 2] = 0;
339 }
340 packet->host = host;
341 packet->node_id = node;
342
343 if (hpsb_get_tlabel(packet)) {
344 hpsb_free_packet(packet);
345 return NULL;
346 }
347
348 if (length == 4) {
349 fill_async_writequad(packet, addr, buffer ? *buffer : 0);
350 } else {
351 fill_async_writeblock(packet, addr, length);
352 if (buffer)
353 memcpy(packet->data, buffer, length);
354 }
355
356 return packet;
357}
358
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500359struct hpsb_packet *hpsb_make_streampacket(struct hpsb_host *host, u8 * buffer,
360 int length, int channel, int tag,
361 int sync)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362{
363 struct hpsb_packet *packet;
364
365 if (length == 0)
366 return NULL;
367
368 packet = hpsb_alloc_packet(length);
369 if (!packet)
370 return NULL;
371
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500372 if (length % 4) { /* zero padding bytes */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 packet->data[length >> 2] = 0;
374 }
375 packet->host = host;
376
377 if (hpsb_get_tlabel(packet)) {
378 hpsb_free_packet(packet);
379 return NULL;
380 }
381
382 fill_async_stream_packet(packet, length, channel, tag, sync);
383 if (buffer)
384 memcpy(packet->data, buffer, length);
385
386 return packet;
387}
388
389struct hpsb_packet *hpsb_make_lockpacket(struct hpsb_host *host, nodeid_t node,
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500390 u64 addr, int extcode,
391 quadlet_t * data, quadlet_t arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392{
393 struct hpsb_packet *p;
394 u32 length;
395
396 p = hpsb_alloc_packet(8);
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500397 if (!p)
398 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399
400 p->host = host;
401 p->node_id = node;
402 if (hpsb_get_tlabel(p)) {
403 hpsb_free_packet(p);
404 return NULL;
405 }
406
407 switch (extcode) {
408 case EXTCODE_FETCH_ADD:
409 case EXTCODE_LITTLE_ADD:
410 length = 4;
411 if (data)
412 p->data[0] = *data;
413 break;
414 default:
415 length = 8;
416 if (data) {
417 p->data[0] = arg;
418 p->data[1] = *data;
419 }
420 break;
421 }
422 fill_async_lock(p, addr, extcode, length);
423
424 return p;
425}
426
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500427struct hpsb_packet *hpsb_make_lock64packet(struct hpsb_host *host,
428 nodeid_t node, u64 addr, int extcode,
429 octlet_t * data, octlet_t arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430{
431 struct hpsb_packet *p;
432 u32 length;
433
434 p = hpsb_alloc_packet(16);
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500435 if (!p)
436 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437
438 p->host = host;
439 p->node_id = node;
440 if (hpsb_get_tlabel(p)) {
441 hpsb_free_packet(p);
442 return NULL;
443 }
444
445 switch (extcode) {
446 case EXTCODE_FETCH_ADD:
447 case EXTCODE_LITTLE_ADD:
448 length = 8;
449 if (data) {
450 p->data[0] = *data >> 32;
451 p->data[1] = *data & 0xffffffff;
452 }
453 break;
454 default:
455 length = 16;
456 if (data) {
457 p->data[0] = arg >> 32;
458 p->data[1] = arg & 0xffffffff;
459 p->data[2] = *data >> 32;
460 p->data[3] = *data & 0xffffffff;
461 }
462 break;
463 }
464 fill_async_lock(p, addr, extcode, length);
465
466 return p;
467}
468
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500469struct hpsb_packet *hpsb_make_phypacket(struct hpsb_host *host, quadlet_t data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470{
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500471 struct hpsb_packet *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500473 p = hpsb_alloc_packet(0);
474 if (!p)
475 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500477 p->host = host;
478 fill_phy_packet(p, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500480 return p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481}
482
483struct hpsb_packet *hpsb_make_isopacket(struct hpsb_host *host,
484 int length, int channel,
485 int tag, int sync)
486{
487 struct hpsb_packet *p;
488
489 p = hpsb_alloc_packet(length);
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500490 if (!p)
491 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492
493 p->host = host;
494 fill_iso_packet(p, length, channel, tag, sync);
495
496 p->generation = get_hpsb_generation(host);
497
498 return p;
499}
500
501/*
502 * FIXME - these functions should probably read from / write to user space to
503 * avoid in kernel buffers for user space callers
504 */
505
Stefan Richterafd65462007-03-05 03:06:23 +0100506/**
507 * hpsb_read - generic read function
508 *
509 * Recognizes the local node ID and act accordingly. Automatically uses a
510 * quadlet read request if @length == 4 and and a block read request otherwise.
511 * It does not yet support lengths that are not a multiple of 4.
512 *
513 * You must explicitly specifiy the @generation for which the node ID is valid,
514 * to avoid sending packets to the wrong nodes when we race with a bus reset.
515 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516int hpsb_read(struct hpsb_host *host, nodeid_t node, unsigned int generation,
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500517 u64 addr, quadlet_t * buffer, size_t length)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518{
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500519 struct hpsb_packet *packet;
520 int retval = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500522 if (length == 0)
523 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500525 BUG_ON(in_interrupt()); // We can't be called in an interrupt, yet
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526
527 packet = hpsb_make_readpacket(host, node, addr, length);
528
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500529 if (!packet) {
530 return -ENOMEM;
531 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532
533 packet->generation = generation;
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500534 retval = hpsb_send_packet_and_wait(packet);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 if (retval < 0)
536 goto hpsb_read_fail;
537
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500538 retval = hpsb_packet_success(packet);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500540 if (retval == 0) {
541 if (length == 4) {
542 *buffer = packet->header[3];
543 } else {
544 memcpy(buffer, packet->data, length);
545 }
546 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500548 hpsb_read_fail:
549 hpsb_free_tlabel(packet);
550 hpsb_free_packet(packet);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500552 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553}
554
Stefan Richterafd65462007-03-05 03:06:23 +0100555/**
556 * hpsb_write - generic write function
557 *
558 * Recognizes the local node ID and act accordingly. Automatically uses a
559 * quadlet write request if @length == 4 and and a block write request
560 * otherwise. It does not yet support lengths that are not a multiple of 4.
561 *
562 * You must explicitly specifiy the @generation for which the node ID is valid,
563 * to avoid sending packets to the wrong nodes when we race with a bus reset.
564 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565int hpsb_write(struct hpsb_host *host, nodeid_t node, unsigned int generation,
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500566 u64 addr, quadlet_t * buffer, size_t length)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567{
568 struct hpsb_packet *packet;
569 int retval;
570
571 if (length == 0)
572 return -EINVAL;
573
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500574 BUG_ON(in_interrupt()); // We can't be called in an interrupt, yet
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500576 packet = hpsb_make_writepacket(host, node, addr, buffer, length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577
578 if (!packet)
579 return -ENOMEM;
580
581 packet->generation = generation;
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500582 retval = hpsb_send_packet_and_wait(packet);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 if (retval < 0)
584 goto hpsb_write_fail;
585
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500586 retval = hpsb_packet_success(packet);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500588 hpsb_write_fail:
589 hpsb_free_tlabel(packet);
590 hpsb_free_packet(packet);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500592 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593}
594
Jody McIntyre9ac485d2005-05-16 21:54:00 -0700595#if 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596
597int hpsb_lock(struct hpsb_host *host, nodeid_t node, unsigned int generation,
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500598 u64 addr, int extcode, quadlet_t * data, quadlet_t arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599{
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500600 struct hpsb_packet *packet;
601 int retval = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500603 BUG_ON(in_interrupt()); // We can't be called in an interrupt, yet
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604
605 packet = hpsb_make_lockpacket(host, node, addr, extcode, data, arg);
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500606 if (!packet)
607 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608
609 packet->generation = generation;
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500610 retval = hpsb_send_packet_and_wait(packet);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 if (retval < 0)
612 goto hpsb_lock_fail;
613
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500614 retval = hpsb_packet_success(packet);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500616 if (retval == 0) {
617 *data = packet->data[0];
618 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500620 hpsb_lock_fail:
621 hpsb_free_tlabel(packet);
622 hpsb_free_packet(packet);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500624 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625}
626
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627int hpsb_send_gasp(struct hpsb_host *host, int channel, unsigned int generation,
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500628 quadlet_t * buffer, size_t length, u32 specifier_id,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 unsigned int version)
630{
631 struct hpsb_packet *packet;
632 int retval = 0;
633 u16 specifier_id_hi = (specifier_id & 0x00ffff00) >> 8;
634 u8 specifier_id_lo = specifier_id & 0xff;
635
636 HPSB_VERBOSE("Send GASP: channel = %d, length = %Zd", channel, length);
637
638 length += 8;
639
640 packet = hpsb_make_streampacket(host, NULL, length, channel, 3, 0);
641 if (!packet)
642 return -ENOMEM;
643
644 packet->data[0] = cpu_to_be32((host->node_id << 16) | specifier_id_hi);
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500645 packet->data[1] =
646 cpu_to_be32((specifier_id_lo << 24) | (version & 0x00ffffff));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647
648 memcpy(&(packet->data[2]), buffer, length - 8);
649
650 packet->generation = generation;
651
652 packet->no_waiter = 1;
653
654 retval = hpsb_send_packet(packet);
655 if (retval < 0)
656 hpsb_free_packet(packet);
657
658 return retval;
659}
Jody McIntyre9ac485d2005-05-16 21:54:00 -0700660
Jens-Michael Hoffmann16c333a2005-11-22 12:34:16 -0500661#endif /* 0 */