*/
#include <linux/bitops.h>
+#include <linux/compiler.h>
+#include <linux/hardirq.h>
#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <linux/sched.h> /* because linux/wait.h is broken if CONFIG_SMP=n */
#include <linux/wait.h>
#include <asm/bug.h>
#include <asm/errno.h>
+#include <asm/system.h>
#include "ieee1394.h"
#include "ieee1394_types.h"
#ifndef HPSB_DEBUG_TLABELS
static
#endif
-spinlock_t hpsb_tlabel_lock = SPIN_LOCK_UNLOCKED;
+DEFINE_SPINLOCK(hpsb_tlabel_lock);
static DECLARE_WAIT_QUEUE_HEAD(tlabel_wq);
packet->expect_response = 1;
}
-static void fill_iso_packet(struct hpsb_packet *packet, int length, int channel,
- int tag, int sync)
-{
- packet->header[0] = (length << 16) | (tag << 14) | (channel << 8)
- | (TCODE_ISO_DATA << 4) | sync;
-
- packet->header_size = 4;
- packet->data_size = length;
- packet->type = hpsb_iso;
- packet->tcode = TCODE_ISO_DATA;
-}
-
static void fill_phy_packet(struct hpsb_packet *packet, quadlet_t data)
{
packet->header[0] = data;
wake_up_interruptible(&tlabel_wq);
}
+/**
+ * hpsb_packet_success - Make sense of the ack and reply codes
+ *
+ * Make sense of the ack and reply codes and return more convenient error codes:
+ * 0 = success. -%EBUSY = node is busy, try again. -%EAGAIN = error which can
+ * probably resolved by retry. -%EREMOTEIO = node suffers from an internal
+ * error. -%EACCES = this transaction is not allowed on requested address.
+ * -%EINVAL = invalid address at node.
+ */
int hpsb_packet_success(struct hpsb_packet *packet)
{
switch (packet->ack_code) {
packet->node_id);
return -EAGAIN;
}
- BUG();
case ACK_BUSY_X:
case ACK_BUSY_A:
packet->ack_code, packet->node_id, packet->tcode);
return -EAGAIN;
}
- BUG();
}
struct hpsb_packet *hpsb_make_readpacket(struct hpsb_host *host, nodeid_t node,
}
packet->host = host;
+ /* Because it is too difficult to determine all PHY speeds and link
+ * speeds here, we use S100... */
+ packet->speed_code = IEEE1394_SPEED_100;
+
+ /* ...and prevent hpsb_send_packet() from overriding it. */
+ packet->node_id = LOCAL_BUS | ALL_NODES;
+
if (hpsb_get_tlabel(packet)) {
hpsb_free_packet(packet);
return NULL;
return p;
}
-struct hpsb_packet *hpsb_make_isopacket(struct hpsb_host *host,
- int length, int channel,
- int tag, int sync)
-{
- struct hpsb_packet *p;
-
- p = hpsb_alloc_packet(length);
- if (!p)
- return NULL;
-
- p->host = host;
- fill_iso_packet(p, length, channel, tag, sync);
-
- p->generation = get_hpsb_generation(host);
-
- return p;
-}
-
/*
* FIXME - these functions should probably read from / write to user space to
* avoid in kernel buffers for user space callers
*/
+/**
+ * hpsb_read - generic read function
+ *
+ * Recognizes the local node ID and act accordingly. Automatically uses a
+ * quadlet read request if @length == 4 and and a block read request otherwise.
+ * It does not yet support lengths that are not a multiple of 4.
+ *
+ * You must explicitly specifiy the @generation for which the node ID is valid,
+ * to avoid sending packets to the wrong nodes when we race with a bus reset.
+ */
int hpsb_read(struct hpsb_host *host, nodeid_t node, unsigned int generation,
u64 addr, quadlet_t * buffer, size_t length)
{
return retval;
}
+/**
+ * hpsb_write - generic write function
+ *
+ * Recognizes the local node ID and act accordingly. Automatically uses a
+ * quadlet write request if @length == 4 and and a block write request
+ * otherwise. It does not yet support lengths that are not a multiple of 4.
+ *
+ * You must explicitly specifiy the @generation for which the node ID is valid,
+ * to avoid sending packets to the wrong nodes when we race with a bus reset.
+ */
int hpsb_write(struct hpsb_host *host, nodeid_t node, unsigned int generation,
u64 addr, quadlet_t * buffer, size_t length)
{