*
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/string.h>
#include <linux/moduleparam.h>
#include <linux/bitops.h>
#include <linux/kdev_t.h>
-#include <linux/skbuff.h>
+#include <linux/freezer.h>
#include <linux/suspend.h>
+#include <linux/kthread.h>
+#include <linux/preempt.h>
+#include <linux/time.h>
+#include <asm/system.h>
#include <asm/byteorder.h>
-#include <asm/semaphore.h>
#include "ieee1394_types.h"
#include "ieee1394.h"
/*
* Disable the nodemgr detection and config rom reading functionality.
*/
-static int disable_nodemgr = 0;
+static int disable_nodemgr;
module_param(disable_nodemgr, int, 0444);
MODULE_PARM_DESC(disable_nodemgr, "Disable nodemgr functionality.");
/* Disable Isochronous Resource Manager functionality */
int hpsb_disable_irm = 0;
-module_param_named(disable_irm, hpsb_disable_irm, bool, 0);
+module_param_named(disable_irm, hpsb_disable_irm, bool, 0444);
MODULE_PARM_DESC(disable_irm,
"Disable Isochronous Resource Manager functionality.");
struct class *hpsb_protocol_class;
#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
-static void dump_packet(const char *text, quadlet_t *data, int size)
+static void dump_packet(const char *text, quadlet_t *data, int size, int speed)
{
int i;
size = (size > 4 ? 4 : size);
printk(KERN_DEBUG "ieee1394: %s", text);
+ if (speed > -1 && speed < 6)
+ printk(" at %s", hpsb_speedto_str[speed]);
+ printk(":");
for (i = 0; i < size; i++)
printk(" %08x", data[i]);
printk("\n");
}
#else
-#define dump_packet(x,y,z)
+#define dump_packet(a,b,c,d) do {} while (0)
#endif
static void abort_requests(struct hpsb_host *host);
/**
- * hpsb_set_packet_complete_task - set the task that runs when a packet
- * completes. You cannot call this more than once on a single packet
- * before it is sent.
- *
+ * hpsb_set_packet_complete_task - set task that runs when a packet completes
* @packet: the packet whose completion we want the task added to
* @routine: function to call
* @data: data (if any) to pass to the above function
+ *
+ * Set the task that runs when a packet completes. You cannot call this more
+ * than once on a single packet before it is sent.
+ *
+ * Typically, the complete @routine is responsible to call hpsb_free_packet().
*/
void hpsb_set_packet_complete_task(struct hpsb_packet *packet,
void (*routine)(void *), void *data)
/**
* hpsb_alloc_packet - allocate new packet structure
- * @data_size: size of the data block to be allocated
+ * @data_size: size of the data block to be allocated, in bytes
*
* This function allocates, initializes and returns a new &struct hpsb_packet.
- * It can be used in interrupt context. A header block is always included, its
- * size is big enough to contain all possible 1394 headers. The data block is
- * only allocated when @data_size is not zero.
+ * It can be used in interrupt context. A header block is always included and
+ * initialized with zeros. Its size is big enough to contain all possible 1394
+ * headers. The data block is only allocated if @data_size is not zero.
*
* For packets for which responses will be received the @data_size has to be big
* enough to contain the response's data block since no further allocation
*/
struct hpsb_packet *hpsb_alloc_packet(size_t data_size)
{
- struct hpsb_packet *packet = NULL;
- struct sk_buff *skb;
+ struct hpsb_packet *packet;
data_size = ((data_size + 3) & ~3);
- skb = alloc_skb(data_size + sizeof(*packet), GFP_ATOMIC);
- if (skb == NULL)
+ packet = kzalloc(sizeof(*packet) + data_size, GFP_ATOMIC);
+ if (!packet)
return NULL;
- memset(skb->data, 0, data_size + sizeof(*packet));
-
- packet = (struct hpsb_packet *)skb->data;
- packet->skb = skb;
-
- packet->header = packet->embedded_header;
packet->state = hpsb_unused;
packet->generation = -1;
INIT_LIST_HEAD(&packet->driver_list);
+ INIT_LIST_HEAD(&packet->queue);
atomic_set(&packet->refcnt, 1);
if (data_size) {
- packet->data = (quadlet_t *)(skb->data + sizeof(*packet));
- packet->data_size = data_size;
+ packet->data = packet->embedded_data;
+ packet->allocated_data_size = data_size;
}
-
return packet;
}
-
/**
* hpsb_free_packet - free packet and data associated with it
* @packet: packet to free (is NULL safe)
*
- * This function will free packet->data and finally the packet itself.
+ * Frees @packet->data only if it was allocated through hpsb_alloc_packet().
*/
void hpsb_free_packet(struct hpsb_packet *packet)
{
if (packet && atomic_dec_and_test(&packet->refcnt)) {
- BUG_ON(!list_empty(&packet->driver_list));
- kfree_skb(packet->skb);
+ BUG_ON(!list_empty(&packet->driver_list) ||
+ !list_empty(&packet->queue));
+ kfree(packet);
}
}
-
+/**
+ * hpsb_reset_bus - initiate bus reset on the given host
+ * @host: host controller whose bus to reset
+ * @type: one of enum reset_types
+ *
+ * Returns 1 if bus reset already in progress, 0 otherwise.
+ */
int hpsb_reset_bus(struct hpsb_host *host, int type)
{
- if (!host->in_bus_reset) {
- host->driver->devctl(host, RESET_BUS, type);
- return 0;
- } else {
- return 1;
- }
+ if (!host->in_bus_reset) {
+ host->driver->devctl(host, RESET_BUS, type);
+ return 0;
+ } else {
+ return 1;
+ }
}
+/**
+ * hpsb_read_cycle_timer - read cycle timer register and system time
+ * @host: host whose isochronous cycle timer register is read
+ * @cycle_timer: address of bitfield to return the register contents
+ * @local_time: address to return the system time
+ *
+ * The format of * @cycle_timer, is described in OHCI 1.1 clause 5.13. This
+ * format is also read from non-OHCI controllers. * @local_time contains the
+ * system time in microseconds since the Epoch, read at the moment when the
+ * cycle timer was read.
+ *
+ * Return value: 0 for success or error number otherwise.
+ */
+int hpsb_read_cycle_timer(struct hpsb_host *host, u32 *cycle_timer,
+ u64 *local_time)
+{
+ int ctr;
+ struct timeval tv;
+ unsigned long flags;
+
+ if (!host || !cycle_timer || !local_time)
+ return -EINVAL;
+
+ preempt_disable();
+ local_irq_save(flags);
+
+ ctr = host->driver->devctl(host, GET_CYCLE_COUNTER, 0);
+ if (ctr)
+ do_gettimeofday(&tv);
+
+ local_irq_restore(flags);
+ preempt_enable();
+ if (!ctr)
+ return -EIO;
+ *cycle_timer = ctr;
+ *local_time = tv.tv_sec * 1000000ULL + tv.tv_usec;
+ return 0;
+}
+
+/**
+ * hpsb_bus_reset - notify a bus reset to the core
+ *
+ * For host driver module usage. Safe to use in interrupt context, although
+ * quite complex; so you may want to run it in the bottom rather than top half.
+ *
+ * Returns 1 if bus reset already in progress, 0 otherwise.
+ */
int hpsb_bus_reset(struct hpsb_host *host)
{
- if (host->in_bus_reset) {
- HPSB_NOTICE("%s called while bus reset already in progress",
- __FUNCTION__);
- return 1;
- }
-
- abort_requests(host);
- host->in_bus_reset = 1;
- host->irm_id = -1;
+ if (host->in_bus_reset) {
+ HPSB_NOTICE("%s called while bus reset already in progress",
+ __func__);
+ return 1;
+ }
+
+ abort_requests(host);
+ host->in_bus_reset = 1;
+ host->irm_id = -1;
host->is_irm = 0;
- host->busmgr_id = -1;
+ host->busmgr_id = -1;
host->is_busmgr = 0;
host->is_cycmst = 0;
- host->node_count = 0;
- host->selfid_count = 0;
+ host->node_count = 0;
+ host->selfid_count = 0;
- return 0;
+ return 0;
}
*/
static int check_selfids(struct hpsb_host *host)
{
- int nodeid = -1;
- int rest_of_selfids = host->selfid_count;
- struct selfid *sid = (struct selfid *)host->topology_map;
- struct ext_selfid *esid;
- int esid_seq = 23;
+ int nodeid = -1;
+ int rest_of_selfids = host->selfid_count;
+ struct selfid *sid = (struct selfid *)host->topology_map;
+ struct ext_selfid *esid;
+ int esid_seq = 23;
host->nodes_active = 0;
- while (rest_of_selfids--) {
- if (!sid->extended) {
- nodeid++;
- esid_seq = 0;
+ while (rest_of_selfids--) {
+ if (!sid->extended) {
+ nodeid++;
+ esid_seq = 0;
- if (sid->phy_id != nodeid) {
- HPSB_INFO("SelfIDs failed monotony check with "
- "%d", sid->phy_id);
- return 0;
- }
+ if (sid->phy_id != nodeid) {
+ HPSB_INFO("SelfIDs failed monotony check with "
+ "%d", sid->phy_id);
+ return 0;
+ }
if (sid->link_active) {
host->nodes_active++;
if (sid->contender)
host->irm_id = LOCAL_BUS | sid->phy_id;
}
- } else {
- esid = (struct ext_selfid *)sid;
-
- if ((esid->phy_id != nodeid)
- || (esid->seq_nr != esid_seq)) {
- HPSB_INFO("SelfIDs failed monotony check with "
- "%d/%d", esid->phy_id, esid->seq_nr);
- return 0;
- }
- esid_seq++;
- }
- sid++;
- }
-
- esid = (struct ext_selfid *)(sid - 1);
- while (esid->extended) {
- if ((esid->porta == 0x2) || (esid->portb == 0x2)
- || (esid->portc == 0x2) || (esid->portd == 0x2)
- || (esid->porte == 0x2) || (esid->portf == 0x2)
- || (esid->portg == 0x2) || (esid->porth == 0x2)) {
+ } else {
+ esid = (struct ext_selfid *)sid;
+
+ if ((esid->phy_id != nodeid)
+ || (esid->seq_nr != esid_seq)) {
+ HPSB_INFO("SelfIDs failed monotony check with "
+ "%d/%d", esid->phy_id, esid->seq_nr);
+ return 0;
+ }
+ esid_seq++;
+ }
+ sid++;
+ }
+
+ esid = (struct ext_selfid *)(sid - 1);
+ while (esid->extended) {
+ if ((esid->porta == SELFID_PORT_PARENT) ||
+ (esid->portb == SELFID_PORT_PARENT) ||
+ (esid->portc == SELFID_PORT_PARENT) ||
+ (esid->portd == SELFID_PORT_PARENT) ||
+ (esid->porte == SELFID_PORT_PARENT) ||
+ (esid->portf == SELFID_PORT_PARENT) ||
+ (esid->portg == SELFID_PORT_PARENT) ||
+ (esid->porth == SELFID_PORT_PARENT)) {
HPSB_INFO("SelfIDs failed root check on "
"extended SelfID");
return 0;
- }
- esid--;
- }
+ }
+ esid--;
+ }
- sid = (struct selfid *)esid;
- if ((sid->port0 == 0x2) || (sid->port1 == 0x2) || (sid->port2 == 0x2)) {
+ sid = (struct selfid *)esid;
+ if ((sid->port0 == SELFID_PORT_PARENT) ||
+ (sid->port1 == SELFID_PORT_PARENT) ||
+ (sid->port2 == SELFID_PORT_PARENT)) {
HPSB_INFO("SelfIDs failed root check");
return 0;
- }
+ }
host->node_count = nodeid + 1;
- return 1;
+ return 1;
}
static void build_speed_map(struct hpsb_host *host, int nodecount)
{
- u8 speedcap[nodecount];
u8 cldcnt[nodecount];
- u8 *map = host->speed_map;
- struct selfid *sid;
- struct ext_selfid *esid;
- int i, j, n;
-
- for (i = 0; i < (nodecount * 64); i += 64) {
- for (j = 0; j < nodecount; j++) {
- map[i+j] = IEEE1394_SPEED_MAX;
- }
- }
-
- for (i = 0; i < nodecount; i++) {
- cldcnt[i] = 0;
- }
-
- /* find direct children count and speed */
- for (sid = (struct selfid *)&host->topology_map[host->selfid_count-1],
- n = nodecount - 1;
- (void *)sid >= (void *)host->topology_map; sid--) {
- if (sid->extended) {
- esid = (struct ext_selfid *)sid;
-
- if (esid->porta == 0x3) cldcnt[n]++;
- if (esid->portb == 0x3) cldcnt[n]++;
- if (esid->portc == 0x3) cldcnt[n]++;
- if (esid->portd == 0x3) cldcnt[n]++;
- if (esid->porte == 0x3) cldcnt[n]++;
- if (esid->portf == 0x3) cldcnt[n]++;
- if (esid->portg == 0x3) cldcnt[n]++;
- if (esid->porth == 0x3) cldcnt[n]++;
+ u8 *map = host->speed_map;
+ u8 *speedcap = host->speed;
+ u8 local_link_speed = host->csr.lnk_spd;
+ struct selfid *sid;
+ struct ext_selfid *esid;
+ int i, j, n;
+
+ for (i = 0; i < (nodecount * 64); i += 64) {
+ for (j = 0; j < nodecount; j++) {
+ map[i+j] = IEEE1394_SPEED_MAX;
+ }
+ }
+
+ for (i = 0; i < nodecount; i++) {
+ cldcnt[i] = 0;
+ }
+
+ /* find direct children count and speed */
+ for (sid = (struct selfid *)&host->topology_map[host->selfid_count-1],
+ n = nodecount - 1;
+ (void *)sid >= (void *)host->topology_map; sid--) {
+ if (sid->extended) {
+ esid = (struct ext_selfid *)sid;
+
+ if (esid->porta == SELFID_PORT_CHILD) cldcnt[n]++;
+ if (esid->portb == SELFID_PORT_CHILD) cldcnt[n]++;
+ if (esid->portc == SELFID_PORT_CHILD) cldcnt[n]++;
+ if (esid->portd == SELFID_PORT_CHILD) cldcnt[n]++;
+ if (esid->porte == SELFID_PORT_CHILD) cldcnt[n]++;
+ if (esid->portf == SELFID_PORT_CHILD) cldcnt[n]++;
+ if (esid->portg == SELFID_PORT_CHILD) cldcnt[n]++;
+ if (esid->porth == SELFID_PORT_CHILD) cldcnt[n]++;
} else {
- if (sid->port0 == 0x3) cldcnt[n]++;
- if (sid->port1 == 0x3) cldcnt[n]++;
- if (sid->port2 == 0x3) cldcnt[n]++;
-
- speedcap[n] = sid->speed;
- n--;
- }
- }
-
- /* set self mapping */
- for (i = 0; i < nodecount; i++) {
- map[64*i + i] = speedcap[i];
- }
-
- /* fix up direct children count to total children count;
- * also fix up speedcaps for sibling and parent communication */
- for (i = 1; i < nodecount; i++) {
- for (j = cldcnt[i], n = i - 1; j > 0; j--) {
- cldcnt[i] += cldcnt[n];
- speedcap[n] = min(speedcap[n], speedcap[i]);
- n -= cldcnt[n] + 1;
- }
- }
-
- for (n = 0; n < nodecount; n++) {
- for (i = n - cldcnt[n]; i <= n; i++) {
- for (j = 0; j < (n - cldcnt[n]); j++) {
- map[j*64 + i] = map[i*64 + j] =
- min(map[i*64 + j], speedcap[n]);
- }
- for (j = n + 1; j < nodecount; j++) {
- map[j*64 + i] = map[i*64 + j] =
- min(map[i*64 + j], speedcap[n]);
- }
- }
- }
+ if (sid->port0 == SELFID_PORT_CHILD) cldcnt[n]++;
+ if (sid->port1 == SELFID_PORT_CHILD) cldcnt[n]++;
+ if (sid->port2 == SELFID_PORT_CHILD) cldcnt[n]++;
+
+ speedcap[n] = sid->speed;
+ if (speedcap[n] > local_link_speed)
+ speedcap[n] = local_link_speed;
+ n--;
+ }
+ }
+
+ /* set self mapping */
+ for (i = 0; i < nodecount; i++) {
+ map[64*i + i] = speedcap[i];
+ }
+
+ /* fix up direct children count to total children count;
+ * also fix up speedcaps for sibling and parent communication */
+ for (i = 1; i < nodecount; i++) {
+ for (j = cldcnt[i], n = i - 1; j > 0; j--) {
+ cldcnt[i] += cldcnt[n];
+ speedcap[n] = min(speedcap[n], speedcap[i]);
+ n -= cldcnt[n] + 1;
+ }
+ }
+
+ for (n = 0; n < nodecount; n++) {
+ for (i = n - cldcnt[n]; i <= n; i++) {
+ for (j = 0; j < (n - cldcnt[n]); j++) {
+ map[j*64 + i] = map[i*64 + j] =
+ min(map[i*64 + j], speedcap[n]);
+ }
+ for (j = n + 1; j < nodecount; j++) {
+ map[j*64 + i] = map[i*64 + j] =
+ min(map[i*64 + j], speedcap[n]);
+ }
+ }
+ }
+
+ /* assume a maximum speed for 1394b PHYs, nodemgr will correct it */
+ if (local_link_speed > SELFID_SPEED_UNKNOWN)
+ for (i = 0; i < nodecount; i++)
+ if (speedcap[i] == SELFID_SPEED_UNKNOWN)
+ speedcap[i] = local_link_speed;
}
+/**
+ * hpsb_selfid_received - hand over received selfid packet to the core
+ *
+ * For host driver module usage. Safe to use in interrupt context.
+ *
+ * The host driver should have done a successful complement check (second
+ * quadlet is complement of first) beforehand.
+ */
void hpsb_selfid_received(struct hpsb_host *host, quadlet_t sid)
{
- if (host->in_bus_reset) {
- HPSB_VERBOSE("Including SelfID 0x%x", sid);
- host->topology_map[host->selfid_count++] = sid;
- } else {
- HPSB_NOTICE("Spurious SelfID packet (0x%08x) received from bus %d",
+ if (host->in_bus_reset) {
+ HPSB_VERBOSE("Including SelfID 0x%x", sid);
+ host->topology_map[host->selfid_count++] = sid;
+ } else {
+ HPSB_NOTICE("Spurious SelfID packet (0x%08x) received from bus %d",
sid, NODEID_TO_BUS(host->node_id));
- }
+ }
}
+/**
+ * hpsb_selfid_complete - notify completion of SelfID stage to the core
+ *
+ * For host driver module usage. Safe to use in interrupt context, although
+ * quite complex; so you may want to run it in the bottom rather than top half.
+ *
+ * Notify completion of SelfID stage to the core and report new physical ID
+ * and whether host is root now.
+ */
void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot)
{
if (!host->in_bus_reset)
HPSB_NOTICE("SelfID completion called outside of bus reset!");
- host->node_id = LOCAL_BUS | phyid;
- host->is_root = isroot;
+ host->node_id = LOCAL_BUS | phyid;
+ host->is_root = isroot;
- if (!check_selfids(host)) {
- if (host->reset_retries++ < 20) {
- /* selfid stage did not complete without error */
- HPSB_NOTICE("Error in SelfID stage, resetting");
+ if (!check_selfids(host)) {
+ if (host->reset_retries++ < 20) {
+ /* selfid stage did not complete without error */
+ HPSB_NOTICE("Error in SelfID stage, resetting");
host->in_bus_reset = 0;
/* this should work from ohci1394 now... */
- hpsb_reset_bus(host, LONG_RESET);
- return;
- } else {
- HPSB_NOTICE("Stopping out-of-control reset loop");
- HPSB_NOTICE("Warning - topology map and speed map will not be valid");
+ hpsb_reset_bus(host, LONG_RESET);
+ return;
+ } else {
+ HPSB_NOTICE("Stopping out-of-control reset loop");
+ HPSB_NOTICE("Warning - topology map and speed map will not be valid");
host->reset_retries = 0;
- }
- } else {
+ }
+ } else {
host->reset_retries = 0;
- build_speed_map(host, host->node_count);
- }
+ build_speed_map(host, host->node_count);
+ }
HPSB_VERBOSE("selfid_complete called with successful SelfID stage "
"... irm_id: 0x%X node_id: 0x%X",host->irm_id,host->node_id);
- /* irm_id is kept up to date by check_selfids() */
- if (host->irm_id == host->node_id) {
- host->is_irm = 1;
- } else {
- host->is_busmgr = 0;
- host->is_irm = 0;
- }
+ /* irm_id is kept up to date by check_selfids() */
+ if (host->irm_id == host->node_id) {
+ host->is_irm = 1;
+ } else {
+ host->is_busmgr = 0;
+ host->is_irm = 0;
+ }
- if (isroot) {
+ if (isroot) {
host->driver->devctl(host, ACT_CYCLE_MASTER, 1);
host->is_cycmst = 1;
}
atomic_inc(&host->generation);
host->in_bus_reset = 0;
- highlevel_host_reset(host);
+ highlevel_host_reset(host);
}
+static DEFINE_SPINLOCK(pending_packets_lock);
+/**
+ * hpsb_packet_sent - notify core of sending a packet
+ *
+ * For host driver module usage. Safe to call from within a transmit packet
+ * routine.
+ *
+ * Notify core of sending a packet. Ackcode is the ack code returned for async
+ * transmits or ACKX_SEND_ERROR if the transmission failed completely; ACKX_NONE
+ * for other cases (internal errors that don't justify a panic).
+ */
void hpsb_packet_sent(struct hpsb_host *host, struct hpsb_packet *packet,
- int ackcode)
+ int ackcode)
{
unsigned long flags;
- spin_lock_irqsave(&host->pending_packet_queue.lock, flags);
+ spin_lock_irqsave(&pending_packets_lock, flags);
packet->ack_code = ackcode;
if (packet->no_waiter || packet->state == hpsb_complete) {
/* if packet->no_waiter, must not have a tlabel allocated */
- spin_unlock_irqrestore(&host->pending_packet_queue.lock, flags);
+ spin_unlock_irqrestore(&pending_packets_lock, flags);
hpsb_free_packet(packet);
return;
}
atomic_dec(&packet->refcnt); /* drop HC's reference */
- /* here the packet must be on the host->pending_packet_queue */
+ /* here the packet must be on the host->pending_packets queue */
if (ackcode != ACK_PENDING || !packet->expect_response) {
packet->state = hpsb_complete;
- __skb_unlink(packet->skb, &host->pending_packet_queue);
- spin_unlock_irqrestore(&host->pending_packet_queue.lock, flags);
+ list_del_init(&packet->queue);
+ spin_unlock_irqrestore(&pending_packets_lock, flags);
queue_packet_complete(packet);
return;
}
packet->state = hpsb_pending;
packet->sendtime = jiffies;
- spin_unlock_irqrestore(&host->pending_packet_queue.lock, flags);
+ spin_unlock_irqrestore(&pending_packets_lock, flags);
mod_timer(&host->timeout, jiffies + host->timeout_interval);
}
* @rootid: root whose force_root bit should get set (-1 = don't set force_root)
* @gapcnt: gap count value to set (-1 = don't set gap count)
*
- * This function sends a PHY config packet on the bus through the specified host.
+ * This function sends a PHY config packet on the bus through the specified
+ * host.
*
- * Return value: 0 for success or error number otherwise.
+ * Return value: 0 for success or negative error number otherwise.
*/
int hpsb_send_phy_config(struct hpsb_host *host, int rootid, int gapcnt)
{
struct hpsb_packet *packet;
+ quadlet_t d = 0;
int retval = 0;
if (rootid >= ALL_NODES || rootid < -1 || gapcnt > 0x3f || gapcnt < -1 ||
return -EINVAL;
}
- packet = hpsb_alloc_packet(0);
- if (!packet)
- return -ENOMEM;
-
- packet->host = host;
- packet->header_size = 8;
- packet->data_size = 0;
- packet->expect_response = 0;
- packet->no_waiter = 0;
- packet->type = hpsb_raw;
- packet->header[0] = 0;
if (rootid != -1)
- packet->header[0] |= rootid << 24 | 1 << 23;
+ d |= PHYPACKET_PHYCONFIG_R | rootid << PHYPACKET_PORT_SHIFT;
if (gapcnt != -1)
- packet->header[0] |= gapcnt << 16 | 1 << 22;
+ d |= PHYPACKET_PHYCONFIG_T | gapcnt << PHYPACKET_GAPCOUNT_SHIFT;
- packet->header[1] = ~packet->header[0];
+ packet = hpsb_make_phypacket(host, d);
+ if (!packet)
+ return -ENOMEM;
packet->generation = get_hpsb_generation(host);
-
retval = hpsb_send_packet_and_wait(packet);
hpsb_free_packet(packet);
{
struct hpsb_host *host = packet->host;
- if (host->is_shutdown)
+ if (host->is_shutdown)
return -EINVAL;
if (host->in_bus_reset ||
(packet->generation != get_hpsb_generation(host)))
- return -EAGAIN;
+ return -EAGAIN;
- packet->state = hpsb_queued;
+ packet->state = hpsb_queued;
/* This just seems silly to me */
WARN_ON(packet->no_waiter && packet->expect_response);
if (!packet->no_waiter || packet->expect_response) {
+ unsigned long flags;
+
atomic_inc(&packet->refcnt);
+ /* Set the initial "sendtime" to 10 seconds from now, to
+ prevent premature expiry. If a packet takes more than
+ 10 seconds to hit the wire, we have bigger problems :) */
packet->sendtime = jiffies + 10 * HZ;
- skb_queue_tail(&host->pending_packet_queue, packet->skb);
+ spin_lock_irqsave(&pending_packets_lock, flags);
+ list_add_tail(&packet->queue, &host->pending_packets);
+ spin_unlock_irqrestore(&pending_packets_lock, flags);
}
- if (packet->node_id == host->node_id) {
+ if (packet->node_id == host->node_id) {
/* it is a local request, so handle it locally */
- quadlet_t *data;
- size_t size = packet->data_size + packet->header_size;
+ quadlet_t *data;
+ size_t size = packet->data_size + packet->header_size;
- data = kmalloc(size, GFP_ATOMIC);
- if (!data) {
- HPSB_ERR("unable to allocate memory for concatenating header and data");
- return -ENOMEM;
- }
+ data = kmalloc(size, GFP_ATOMIC);
+ if (!data) {
+ HPSB_ERR("unable to allocate memory for concatenating header and data");
+ return -ENOMEM;
+ }
- memcpy(data, packet->header, packet->header_size);
+ memcpy(data, packet->header, packet->header_size);
- if (packet->data_size)
+ if (packet->data_size)
memcpy(((u8*)data) + packet->header_size, packet->data, packet->data_size);
- dump_packet("send packet local:", packet->header,
- packet->header_size);
+ dump_packet("send packet local", packet->header, packet->header_size, -1);
- hpsb_packet_sent(host, packet, packet->expect_response ? ACK_PENDING : ACK_COMPLETE);
- hpsb_packet_received(host, data, size, 0);
+ hpsb_packet_sent(host, packet, packet->expect_response ? ACK_PENDING : ACK_COMPLETE);
+ hpsb_packet_received(host, data, size, 0);
- kfree(data);
+ kfree(data);
- return 0;
- }
+ return 0;
+ }
- if (packet->type == hpsb_async && packet->node_id != ALL_NODES) {
- packet->speed_code =
- host->speed_map[NODEID_TO_NODE(host->node_id) * 64
- + NODEID_TO_NODE(packet->node_id)];
- }
+ if (packet->type == hpsb_async &&
+ NODEID_TO_NODE(packet->node_id) != ALL_NODES)
+ packet->speed_code =
+ host->speed[NODEID_TO_NODE(packet->node_id)];
-#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
- switch (packet->speed_code) {
- case 2:
- dump_packet("send packet 400:", packet->header,
- packet->header_size);
- break;
- case 1:
- dump_packet("send packet 200:", packet->header,
- packet->header_size);
- break;
- default:
- dump_packet("send packet 100:", packet->header,
- packet->header_size);
- }
-#endif
+ dump_packet("send packet", packet->header, packet->header_size, packet->speed_code);
- return host->driver->transmit_packet(host, packet);
+ return host->driver->transmit_packet(host, packet);
}
/* We could just use complete() directly as the packet complete
complete((struct completion *) data);
}
+/**
+ * hpsb_send_packet_and_wait - enqueue packet, block until transaction completes
+ * @packet: packet to send
+ *
+ * Return value: 0 on success, negative errno on failure.
+ */
int hpsb_send_packet_and_wait(struct hpsb_packet *packet)
{
struct completion done;
static void send_packet_nocare(struct hpsb_packet *packet)
{
- if (hpsb_send_packet(packet) < 0) {
- hpsb_free_packet(packet);
- }
+ if (hpsb_send_packet(packet) < 0) {
+ hpsb_free_packet(packet);
+ }
}
+static size_t packet_size_to_data_size(size_t packet_size, size_t header_size,
+ size_t buffer_size, int tcode)
+{
+ size_t ret = packet_size <= header_size ? 0 : packet_size - header_size;
+
+ if (unlikely(ret > buffer_size))
+ ret = buffer_size;
+
+ if (unlikely(ret + header_size != packet_size))
+ HPSB_ERR("unexpected packet size %zd (tcode %d), bug?",
+ packet_size, tcode);
+ return ret;
+}
static void handle_packet_response(struct hpsb_host *host, int tcode,
quadlet_t *data, size_t size)
{
- struct hpsb_packet *packet = NULL;
- struct sk_buff *skb;
- int tcode_match = 0;
- int tlabel;
- unsigned long flags;
-
- tlabel = (data[0] >> 10) & 0x3f;
-
- spin_lock_irqsave(&host->pending_packet_queue.lock, flags);
-
- skb_queue_walk(&host->pending_packet_queue, skb) {
- packet = (struct hpsb_packet *)skb->data;
- if ((packet->tlabel == tlabel)
- && (packet->node_id == (data[1] >> 16))){
- break;
- }
-
- packet = NULL;
- }
-
- if (packet == NULL) {
- HPSB_DEBUG("unsolicited response packet received - no tlabel match");
- dump_packet("contents:", data, 16);
- spin_unlock_irqrestore(&host->pending_packet_queue.lock, flags);
- return;
- }
-
- switch (packet->tcode) {
- case TCODE_WRITEQ:
- case TCODE_WRITEB:
- if (tcode != TCODE_WRITE_RESPONSE)
+ struct hpsb_packet *packet;
+ int tlabel = (data[0] >> 10) & 0x3f;
+ size_t header_size;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pending_packets_lock, flags);
+
+ list_for_each_entry(packet, &host->pending_packets, queue)
+ if (packet->tlabel == tlabel &&
+ packet->node_id == (data[1] >> 16))
+ goto found;
+
+ spin_unlock_irqrestore(&pending_packets_lock, flags);
+ HPSB_DEBUG("unsolicited response packet received - %s",
+ "no tlabel match");
+ dump_packet("contents", data, 16, -1);
+ return;
+
+found:
+ switch (packet->tcode) {
+ case TCODE_WRITEQ:
+ case TCODE_WRITEB:
+ if (unlikely(tcode != TCODE_WRITE_RESPONSE))
break;
- tcode_match = 1;
- memcpy(packet->header, data, 12);
- break;
- case TCODE_READQ:
- if (tcode != TCODE_READQ_RESPONSE)
+ header_size = 12;
+ size = 0;
+ goto dequeue;
+
+ case TCODE_READQ:
+ if (unlikely(tcode != TCODE_READQ_RESPONSE))
break;
- tcode_match = 1;
- memcpy(packet->header, data, 16);
- break;
- case TCODE_READB:
- if (tcode != TCODE_READB_RESPONSE)
+ header_size = 16;
+ size = 0;
+ goto dequeue;
+
+ case TCODE_READB:
+ if (unlikely(tcode != TCODE_READB_RESPONSE))
break;
- tcode_match = 1;
- BUG_ON(packet->skb->len - sizeof(*packet) < size - 16);
- memcpy(packet->header, data, 16);
- memcpy(packet->data, data + 4, size - 16);
- break;
- case TCODE_LOCK_REQUEST:
- if (tcode != TCODE_LOCK_RESPONSE)
+ header_size = 16;
+ size = packet_size_to_data_size(size, header_size,
+ packet->allocated_data_size,
+ tcode);
+ goto dequeue;
+
+ case TCODE_LOCK_REQUEST:
+ if (unlikely(tcode != TCODE_LOCK_RESPONSE))
break;
- tcode_match = 1;
- size = min((size - 16), (size_t)8);
- BUG_ON(packet->skb->len - sizeof(*packet) < size);
- memcpy(packet->header, data, 16);
- memcpy(packet->data, data + 4, size);
- break;
- }
+ header_size = 16;
+ size = packet_size_to_data_size(min(size, (size_t)(16 + 8)),
+ header_size,
+ packet->allocated_data_size,
+ tcode);
+ goto dequeue;
+ }
- if (!tcode_match) {
- spin_unlock_irqrestore(&host->pending_packet_queue.lock, flags);
- HPSB_INFO("unsolicited response packet received - tcode mismatch");
- dump_packet("contents:", data, 16);
- return;
- }
+ spin_unlock_irqrestore(&pending_packets_lock, flags);
+ HPSB_DEBUG("unsolicited response packet received - %s",
+ "tcode mismatch");
+ dump_packet("contents", data, 16, -1);
+ return;
- __skb_unlink(skb, skb->list);
+dequeue:
+ list_del_init(&packet->queue);
+ spin_unlock_irqrestore(&pending_packets_lock, flags);
if (packet->state == hpsb_queued) {
packet->sendtime = jiffies;
packet->ack_code = ACK_PENDING;
}
-
packet->state = hpsb_complete;
- spin_unlock_irqrestore(&host->pending_packet_queue.lock, flags);
+
+ memcpy(packet->header, data, header_size);
+ if (size)
+ memcpy(packet->data, data + 4, size);
queue_packet_complete(packet);
}
static struct hpsb_packet *create_reply_packet(struct hpsb_host *host,
quadlet_t *data, size_t dsize)
{
- struct hpsb_packet *p;
+ struct hpsb_packet *p;
- p = hpsb_alloc_packet(dsize);
- if (unlikely(p == NULL)) {
- /* FIXME - send data_error response */
- return NULL;
- }
+ p = hpsb_alloc_packet(dsize);
+ if (unlikely(p == NULL)) {
+ /* FIXME - send data_error response */
+ HPSB_ERR("out of memory, cannot send response packet");
+ return NULL;
+ }
- p->type = hpsb_async;
- p->state = hpsb_unused;
- p->host = host;
- p->node_id = data[1] >> 16;
- p->tlabel = (data[0] >> 10) & 0x3f;
- p->no_waiter = 1;
+ p->type = hpsb_async;
+ p->state = hpsb_unused;
+ p->host = host;
+ p->node_id = data[1] >> 16;
+ p->tlabel = (data[0] >> 10) & 0x3f;
+ p->no_waiter = 1;
p->generation = get_hpsb_generation(host);
if (dsize % 4)
p->data[dsize / 4] = 0;
- return p;
+ return p;
}
#define PREP_ASYNC_HEAD_RCODE(tc) \
packet->header[2] = 0
static void fill_async_readquad_resp(struct hpsb_packet *packet, int rcode,
- quadlet_t data)
+ quadlet_t data)
{
PREP_ASYNC_HEAD_RCODE(TCODE_READQ_RESPONSE);
packet->header[3] = data;
}
static void fill_async_readblock_resp(struct hpsb_packet *packet, int rcode,
- int length)
+ int length)
{
if (rcode != RCODE_COMPLETE)
length = 0;
static void fill_async_write_resp(struct hpsb_packet *packet, int rcode)
{
PREP_ASYNC_HEAD_RCODE(TCODE_WRITE_RESPONSE);
- packet->header[2] = 0;
packet->header_size = 12;
packet->data_size = 0;
}
static void fill_async_lock_resp(struct hpsb_packet *packet, int rcode, int extcode,
- int length)
+ int length)
{
if (rcode != RCODE_COMPLETE)
length = 0;
packet->data_size = length;
}
-#define PREP_REPLY_PACKET(length) \
- packet = create_reply_packet(host, data, length); \
- if (packet == NULL) break
-
static void handle_incoming_packet(struct hpsb_host *host, int tcode,
- quadlet_t *data, size_t size, int write_acked)
+ quadlet_t *data, size_t size,
+ int write_acked)
{
- struct hpsb_packet *packet;
- int length, rcode, extcode;
- quadlet_t buffer;
- nodeid_t source = data[1] >> 16;
- nodeid_t dest = data[0] >> 16;
- u16 flags = (u16) data[0];
- u64 addr;
-
- /* big FIXME - no error checking is done for an out of bounds length */
-
- switch (tcode) {
- case TCODE_WRITEQ:
- addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
- rcode = highlevel_write(host, source, dest, data+3,
+ struct hpsb_packet *packet;
+ int length, rcode, extcode;
+ quadlet_t buffer;
+ nodeid_t source = data[1] >> 16;
+ nodeid_t dest = data[0] >> 16;
+ u16 flags = (u16) data[0];
+ u64 addr;
+
+ /* FIXME?
+ * Out-of-bounds lengths are left for highlevel_read|write to cap. */
+
+ switch (tcode) {
+ case TCODE_WRITEQ:
+ addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
+ rcode = highlevel_write(host, source, dest, data + 3,
addr, 4, flags);
+ goto handle_write_request;
+
+ case TCODE_WRITEB:
+ addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
+ rcode = highlevel_write(host, source, dest, data + 4,
+ addr, data[3] >> 16, flags);
+handle_write_request:
+ if (rcode < 0 || write_acked ||
+ NODEID_TO_NODE(data[0] >> 16) == NODE_MASK)
+ return;
+ /* not a broadcast write, reply */
+ packet = create_reply_packet(host, data, 0);
+ if (packet) {
+ fill_async_write_resp(packet, rcode);
+ send_packet_nocare(packet);
+ }
+ return;
- if (!write_acked
- && (NODEID_TO_NODE(data[0] >> 16) != NODE_MASK)
- && (rcode >= 0)) {
- /* not a broadcast write, reply */
- PREP_REPLY_PACKET(0);
- fill_async_write_resp(packet, rcode);
- send_packet_nocare(packet);
- }
- break;
-
- case TCODE_WRITEB:
- addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
- rcode = highlevel_write(host, source, dest, data+4,
- addr, data[3]>>16, flags);
-
- if (!write_acked
- && (NODEID_TO_NODE(data[0] >> 16) != NODE_MASK)
- && (rcode >= 0)) {
- /* not a broadcast write, reply */
- PREP_REPLY_PACKET(0);
- fill_async_write_resp(packet, rcode);
- send_packet_nocare(packet);
- }
- break;
-
- case TCODE_READQ:
- addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
- rcode = highlevel_read(host, source, &buffer, addr, 4, flags);
-
- if (rcode >= 0) {
- PREP_REPLY_PACKET(0);
- fill_async_readquad_resp(packet, rcode, buffer);
- send_packet_nocare(packet);
- }
- break;
-
- case TCODE_READB:
- length = data[3] >> 16;
- PREP_REPLY_PACKET(length);
-
- addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
- rcode = highlevel_read(host, source, packet->data, addr,
- length, flags);
-
- if (rcode >= 0) {
- fill_async_readblock_resp(packet, rcode, length);
- send_packet_nocare(packet);
- } else {
- hpsb_free_packet(packet);
- }
- break;
-
- case TCODE_LOCK_REQUEST:
- length = data[3] >> 16;
- extcode = data[3] & 0xffff;
- addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
-
- PREP_REPLY_PACKET(8);
-
- if ((extcode == 0) || (extcode >= 7)) {
- /* let switch default handle error */
- length = 0;
- }
-
- switch (length) {
- case 4:
- rcode = highlevel_lock(host, source, packet->data, addr,
- data[4], 0, extcode,flags);
- fill_async_lock_resp(packet, rcode, extcode, 4);
- break;
- case 8:
- if ((extcode != EXTCODE_FETCH_ADD)
- && (extcode != EXTCODE_LITTLE_ADD)) {
- rcode = highlevel_lock(host, source,
- packet->data, addr,
- data[5], data[4],
- extcode, flags);
- fill_async_lock_resp(packet, rcode, extcode, 4);
- } else {
- rcode = highlevel_lock64(host, source,
- (octlet_t *)packet->data, addr,
- *(octlet_t *)(data + 4), 0ULL,
- extcode, flags);
- fill_async_lock_resp(packet, rcode, extcode, 8);
- }
- break;
- case 16:
- rcode = highlevel_lock64(host, source,
- (octlet_t *)packet->data, addr,
- *(octlet_t *)(data + 6),
- *(octlet_t *)(data + 4),
- extcode, flags);
- fill_async_lock_resp(packet, rcode, extcode, 8);
- break;
- default:
- rcode = RCODE_TYPE_ERROR;
- fill_async_lock_resp(packet, rcode,
- extcode, 0);
- }
-
- if (rcode >= 0) {
- send_packet_nocare(packet);
- } else {
- hpsb_free_packet(packet);
- }
- break;
- }
+ case TCODE_READQ:
+ addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
+ rcode = highlevel_read(host, source, &buffer, addr, 4, flags);
+ if (rcode < 0)
+ return;
-}
-#undef PREP_REPLY_PACKET
+ packet = create_reply_packet(host, data, 0);
+ if (packet) {
+ fill_async_readquad_resp(packet, rcode, buffer);
+ send_packet_nocare(packet);
+ }
+ return;
+
+ case TCODE_READB:
+ length = data[3] >> 16;
+ packet = create_reply_packet(host, data, length);
+ if (!packet)
+ return;
+
+ addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
+ rcode = highlevel_read(host, source, packet->data, addr,
+ length, flags);
+ if (rcode < 0) {
+ hpsb_free_packet(packet);
+ return;
+ }
+ fill_async_readblock_resp(packet, rcode, length);
+ send_packet_nocare(packet);
+ return;
+
+ case TCODE_LOCK_REQUEST:
+ length = data[3] >> 16;
+ extcode = data[3] & 0xffff;
+ addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
+
+ packet = create_reply_packet(host, data, 8);
+ if (!packet)
+ return;
+
+ if (extcode == 0 || extcode >= 7) {
+ /* let switch default handle error */
+ length = 0;
+ }
+
+ switch (length) {
+ case 4:
+ rcode = highlevel_lock(host, source, packet->data, addr,
+ data[4], 0, extcode, flags);
+ fill_async_lock_resp(packet, rcode, extcode, 4);
+ break;
+ case 8:
+ if (extcode != EXTCODE_FETCH_ADD &&
+ extcode != EXTCODE_LITTLE_ADD) {
+ rcode = highlevel_lock(host, source,
+ packet->data, addr,
+ data[5], data[4],
+ extcode, flags);
+ fill_async_lock_resp(packet, rcode, extcode, 4);
+ } else {
+ rcode = highlevel_lock64(host, source,
+ (octlet_t *)packet->data, addr,
+ *(octlet_t *)(data + 4), 0ULL,
+ extcode, flags);
+ fill_async_lock_resp(packet, rcode, extcode, 8);
+ }
+ break;
+ case 16:
+ rcode = highlevel_lock64(host, source,
+ (octlet_t *)packet->data, addr,
+ *(octlet_t *)(data + 6),
+ *(octlet_t *)(data + 4),
+ extcode, flags);
+ fill_async_lock_resp(packet, rcode, extcode, 8);
+ break;
+ default:
+ rcode = RCODE_TYPE_ERROR;
+ fill_async_lock_resp(packet, rcode, extcode, 0);
+ }
+ if (rcode < 0)
+ hpsb_free_packet(packet);
+ else
+ send_packet_nocare(packet);
+ return;
+ }
+}
+/**
+ * hpsb_packet_received - hand over received packet to the core
+ *
+ * For host driver module usage.
+ *
+ * The contents of data are expected to be the full packet but with the CRCs
+ * left out (data block follows header immediately), with the header (i.e. the
+ * first four quadlets) in machine byte order and the data block in big endian.
+ * *@data can be safely overwritten after this call.
+ *
+ * If the packet is a write request, @write_acked is to be set to true if it was
+ * ack_complete'd already, false otherwise. This argument is ignored for any
+ * other packet type.
+ */
void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size,
- int write_acked)
+ int write_acked)
{
- int tcode;
-
- if (host->in_bus_reset) {
- HPSB_INFO("received packet during reset; ignoring");
- return;
- }
-
- dump_packet("received packet:", data, size);
-
- tcode = (data[0] >> 4) & 0xf;
-
- switch (tcode) {
- case TCODE_WRITE_RESPONSE:
- case TCODE_READQ_RESPONSE:
- case TCODE_READB_RESPONSE:
- case TCODE_LOCK_RESPONSE:
- handle_packet_response(host, tcode, data, size);
- break;
-
- case TCODE_WRITEQ:
- case TCODE_WRITEB:
- case TCODE_READQ:
- case TCODE_READB:
- case TCODE_LOCK_REQUEST:
- handle_incoming_packet(host, tcode, data, size, write_acked);
- break;
-
-
- case TCODE_ISO_DATA:
- highlevel_iso_receive(host, data, size);
- break;
-
- case TCODE_CYCLE_START:
- /* simply ignore this packet if it is passed on */
- break;
-
- default:
- HPSB_NOTICE("received packet with bogus transaction code %d",
- tcode);
- break;
- }
-}
+ int tcode;
+ if (unlikely(host->in_bus_reset)) {
+ HPSB_DEBUG("received packet during reset; ignoring");
+ return;
+ }
+
+ dump_packet("received packet", data, size, -1);
+
+ tcode = (data[0] >> 4) & 0xf;
+
+ switch (tcode) {
+ case TCODE_WRITE_RESPONSE:
+ case TCODE_READQ_RESPONSE:
+ case TCODE_READB_RESPONSE:
+ case TCODE_LOCK_RESPONSE:
+ handle_packet_response(host, tcode, data, size);
+ break;
+
+ case TCODE_WRITEQ:
+ case TCODE_WRITEB:
+ case TCODE_READQ:
+ case TCODE_READB:
+ case TCODE_LOCK_REQUEST:
+ handle_incoming_packet(host, tcode, data, size, write_acked);
+ break;
+
+ case TCODE_CYCLE_START:
+ /* simply ignore this packet if it is passed on */
+ break;
+
+ default:
+ HPSB_DEBUG("received packet with bogus transaction code %d",
+ tcode);
+ break;
+ }
+}
static void abort_requests(struct hpsb_host *host)
{
- struct hpsb_packet *packet;
- struct sk_buff *skb;
+ struct hpsb_packet *packet, *p;
+ struct list_head tmp;
+ unsigned long flags;
host->driver->devctl(host, CANCEL_REQUESTS, 0);
- while ((skb = skb_dequeue(&host->pending_packet_queue)) != NULL) {
- packet = (struct hpsb_packet *)skb->data;
+ INIT_LIST_HEAD(&tmp);
+ spin_lock_irqsave(&pending_packets_lock, flags);
+ list_splice_init(&host->pending_packets, &tmp);
+ spin_unlock_irqrestore(&pending_packets_lock, flags);
+ list_for_each_entry_safe(packet, p, &tmp, queue) {
+ list_del_init(&packet->queue);
packet->state = hpsb_complete;
packet->ack_code = ACKX_ABORTED;
queue_packet_complete(packet);
void abort_timedouts(unsigned long __opaque)
{
struct hpsb_host *host = (struct hpsb_host *)__opaque;
- unsigned long flags;
- struct hpsb_packet *packet;
- struct sk_buff *skb;
- unsigned long expire;
+ struct hpsb_packet *packet, *p;
+ struct list_head tmp;
+ unsigned long flags, expire, j;
spin_lock_irqsave(&host->csr.lock, flags);
expire = host->csr.expire;
spin_unlock_irqrestore(&host->csr.lock, flags);
- /* Hold the lock around this, since we aren't dequeuing all
- * packets, just ones we need. */
- spin_lock_irqsave(&host->pending_packet_queue.lock, flags);
+ j = jiffies;
+ INIT_LIST_HEAD(&tmp);
+ spin_lock_irqsave(&pending_packets_lock, flags);
- while (!skb_queue_empty(&host->pending_packet_queue)) {
- skb = skb_peek(&host->pending_packet_queue);
-
- packet = (struct hpsb_packet *)skb->data;
-
- if (time_before(packet->sendtime + expire, jiffies)) {
- __skb_unlink(skb, skb->list);
- packet->state = hpsb_complete;
- packet->ack_code = ACKX_TIMEOUT;
- queue_packet_complete(packet);
- } else {
+ list_for_each_entry_safe(packet, p, &host->pending_packets, queue) {
+ if (time_before(packet->sendtime + expire, j))
+ list_move_tail(&packet->queue, &tmp);
+ else
/* Since packets are added to the tail, the oldest
* ones are first, always. When we get to one that
* isn't timed out, the rest aren't either. */
break;
- }
}
+ if (!list_empty(&host->pending_packets))
+ mod_timer(&host->timeout, j + host->timeout_interval);
- if (!skb_queue_empty(&host->pending_packet_queue))
- mod_timer(&host->timeout, jiffies + host->timeout_interval);
+ spin_unlock_irqrestore(&pending_packets_lock, flags);
- spin_unlock_irqrestore(&host->pending_packet_queue.lock, flags);
+ list_for_each_entry_safe(packet, p, &tmp, queue) {
+ list_del_init(&packet->queue);
+ packet->state = hpsb_complete;
+ packet->ack_code = ACKX_TIMEOUT;
+ queue_packet_complete(packet);
+ }
}
-
-/* Kernel thread and vars, which handles packets that are completed. Only
- * packets that have a "complete" function are sent here. This way, the
- * completion is run out of kernel context, and doesn't block the rest of
- * the stack. */
-static int khpsbpkt_pid = -1, khpsbpkt_kill;
-static DECLARE_COMPLETION(khpsbpkt_complete);
-static struct sk_buff_head hpsbpkt_queue;
-static DECLARE_MUTEX_LOCKED(khpsbpkt_sig);
-
+static struct task_struct *khpsbpkt_thread;
+static LIST_HEAD(hpsbpkt_queue);
static void queue_packet_complete(struct hpsb_packet *packet)
{
+ unsigned long flags;
+
if (packet->no_waiter) {
hpsb_free_packet(packet);
return;
}
if (packet->complete_routine != NULL) {
- skb_queue_tail(&hpsbpkt_queue, packet->skb);
-
- /* Signal the kernel thread to handle this */
- up(&khpsbpkt_sig);
+ spin_lock_irqsave(&pending_packets_lock, flags);
+ list_add_tail(&packet->queue, &hpsbpkt_queue);
+ spin_unlock_irqrestore(&pending_packets_lock, flags);
+ wake_up_process(khpsbpkt_thread);
}
return;
}
+/*
+ * Kernel thread which handles packets that are completed. This way the
+ * packet's "complete" function is asynchronously run in process context.
+ * Only packets which have a "complete" function may be sent here.
+ */
static int hpsbpkt_thread(void *__hi)
{
- struct sk_buff *skb;
- struct hpsb_packet *packet;
- void (*complete_routine)(void*);
- void *complete_data;
-
- daemonize("khpsbpkt");
+ struct hpsb_packet *packet, *p;
+ struct list_head tmp;
+ int may_schedule;
- while (1) {
- if (down_interruptible(&khpsbpkt_sig)) {
- if (current->flags & PF_FREEZE) {
- refrigerator(0);
- continue;
- }
- printk("khpsbpkt: received unexpected signal?!\n" );
- break;
- }
-
- if (khpsbpkt_kill)
- break;
-
- while ((skb = skb_dequeue(&hpsbpkt_queue)) != NULL) {
- packet = (struct hpsb_packet *)skb->data;
-
- complete_routine = packet->complete_routine;
- complete_data = packet->complete_data;
+ while (!kthread_should_stop()) {
- packet->complete_routine = packet->complete_data = NULL;
+ INIT_LIST_HEAD(&tmp);
+ spin_lock_irq(&pending_packets_lock);
+ list_splice_init(&hpsbpkt_queue, &tmp);
+ spin_unlock_irq(&pending_packets_lock);
- complete_routine(complete_data);
+ list_for_each_entry_safe(packet, p, &tmp, queue) {
+ list_del_init(&packet->queue);
+ packet->complete_routine(packet->complete_data);
}
- }
- complete_and_exit(&khpsbpkt_complete, 0);
+ set_current_state(TASK_INTERRUPTIBLE);
+ spin_lock_irq(&pending_packets_lock);
+ may_schedule = list_empty(&hpsbpkt_queue);
+ spin_unlock_irq(&pending_packets_lock);
+ if (may_schedule)
+ schedule();
+ __set_current_state(TASK_RUNNING);
+ }
+ return 0;
}
static int __init ieee1394_init(void)
{
int i, ret;
- skb_queue_head_init(&hpsbpkt_queue);
-
/* non-fatal error */
if (hpsb_init_config_roms()) {
HPSB_ERR("Failed to initialize some config rom entries.\n");
HPSB_ERR("Some features may not be available\n");
}
- khpsbpkt_pid = kernel_thread(hpsbpkt_thread, NULL, CLONE_KERNEL);
- if (khpsbpkt_pid < 0) {
+ khpsbpkt_thread = kthread_run(hpsbpkt_thread, NULL, "khpsbpkt");
+ if (IS_ERR(khpsbpkt_thread)) {
HPSB_ERR("Failed to start hpsbpkt thread!\n");
- ret = -ENOMEM;
+ ret = PTR_ERR(khpsbpkt_thread);
goto exit_cleanup_config_roms;
}
goto exit_release_kernel_thread;
}
- /* actually this is a non-fatal error */
- ret = devfs_mk_dir("ieee1394");
- if (ret < 0) {
- HPSB_ERR("unable to make devfs dir for device major %d!\n", IEEE1394_MAJOR);
- goto release_chrdev;
- }
-
ret = bus_register(&ieee1394_bus_type);
if (ret < 0) {
HPSB_INFO("bus register failed");
- goto release_devfs;
+ goto release_chrdev;
}
for (i = 0; fw_bus_attrs[i]; i++) {
fw_bus_attrs[i--]);
}
bus_unregister(&ieee1394_bus_type);
- goto release_devfs;
+ goto release_chrdev;
}
}
nodemgr implements functionality required of ieee1394a-2000
IRMs */
hpsb_disable_irm = 1;
-
+
return 0;
}
for (i = 0; fw_bus_attrs[i]; i++)
bus_remove_file(&ieee1394_bus_type, fw_bus_attrs[i]);
bus_unregister(&ieee1394_bus_type);
-release_devfs:
- devfs_remove("ieee1394");
release_chrdev:
unregister_chrdev_region(IEEE1394_CORE_DEV, 256);
exit_release_kernel_thread:
- if (khpsbpkt_pid >= 0) {
- kill_proc(khpsbpkt_pid, SIGTERM, 1);
- wait_for_completion(&khpsbpkt_complete);
- }
+ kthread_stop(khpsbpkt_thread);
exit_cleanup_config_roms:
hpsb_cleanup_config_roms();
return ret;
bus_remove_file(&ieee1394_bus_type, fw_bus_attrs[i]);
bus_unregister(&ieee1394_bus_type);
- if (khpsbpkt_pid >= 0) {
- khpsbpkt_kill = 1;
- mb();
- up(&khpsbpkt_sig);
- wait_for_completion(&khpsbpkt_complete);
- }
+ kthread_stop(khpsbpkt_thread);
hpsb_cleanup_config_roms();
unregister_chrdev_region(IEEE1394_CORE_DEV, 256);
- devfs_remove("ieee1394");
}
-module_init(ieee1394_init);
+fs_initcall(ieee1394_init);
module_exit(ieee1394_cleanup);
/* Exported symbols */
/** hosts.c **/
EXPORT_SYMBOL(hpsb_alloc_host);
EXPORT_SYMBOL(hpsb_add_host);
+EXPORT_SYMBOL(hpsb_resume_host);
EXPORT_SYMBOL(hpsb_remove_host);
EXPORT_SYMBOL(hpsb_update_config_rom_image);
EXPORT_SYMBOL(hpsb_set_packet_complete_task);
EXPORT_SYMBOL(hpsb_alloc_packet);
EXPORT_SYMBOL(hpsb_free_packet);
-EXPORT_SYMBOL(hpsb_send_phy_config);
EXPORT_SYMBOL(hpsb_send_packet);
-EXPORT_SYMBOL(hpsb_send_packet_and_wait);
EXPORT_SYMBOL(hpsb_reset_bus);
+EXPORT_SYMBOL(hpsb_read_cycle_timer);
EXPORT_SYMBOL(hpsb_bus_reset);
EXPORT_SYMBOL(hpsb_selfid_received);
EXPORT_SYMBOL(hpsb_selfid_complete);
EXPORT_SYMBOL(hpsb_make_lockpacket);
EXPORT_SYMBOL(hpsb_make_lock64packet);
EXPORT_SYMBOL(hpsb_make_phypacket);
-EXPORT_SYMBOL(hpsb_make_isopacket);
EXPORT_SYMBOL(hpsb_read);
EXPORT_SYMBOL(hpsb_write);
+EXPORT_SYMBOL(hpsb_lock);
EXPORT_SYMBOL(hpsb_packet_success);
/** highlevel.c **/
EXPORT_SYMBOL(hpsb_register_addrspace);
EXPORT_SYMBOL(hpsb_unregister_addrspace);
EXPORT_SYMBOL(hpsb_allocate_and_register_addrspace);
-EXPORT_SYMBOL(hpsb_listen_channel);
-EXPORT_SYMBOL(hpsb_unlisten_channel);
EXPORT_SYMBOL(hpsb_get_hostinfo);
EXPORT_SYMBOL(hpsb_create_hostinfo);
EXPORT_SYMBOL(hpsb_destroy_hostinfo);
EXPORT_SYMBOL(hpsb_set_hostinfo_key);
EXPORT_SYMBOL(hpsb_get_hostinfo_bykey);
EXPORT_SYMBOL(hpsb_set_hostinfo);
-EXPORT_SYMBOL(highlevel_add_host);
-EXPORT_SYMBOL(highlevel_remove_host);
-EXPORT_SYMBOL(highlevel_host_reset);
/** nodemgr.c **/
EXPORT_SYMBOL(hpsb_node_fill_packet);
EXPORT_SYMBOL(hpsb_node_write);
-EXPORT_SYMBOL(hpsb_register_protocol);
+EXPORT_SYMBOL(__hpsb_register_protocol);
EXPORT_SYMBOL(hpsb_unregister_protocol);
-EXPORT_SYMBOL(ieee1394_bus_type);
-EXPORT_SYMBOL(nodemgr_for_each_host);
/** csr.c **/
EXPORT_SYMBOL(hpsb_update_config_rom);
EXPORT_SYMBOL(hpsb_iso_recv_flush);
/** csr1212.c **/
-EXPORT_SYMBOL(csr1212_create_csr);
-EXPORT_SYMBOL(csr1212_init_local_csr);
-EXPORT_SYMBOL(csr1212_new_immediate);
-EXPORT_SYMBOL(csr1212_new_directory);
-EXPORT_SYMBOL(csr1212_associate_keyval);
EXPORT_SYMBOL(csr1212_attach_keyval_to_directory);
-EXPORT_SYMBOL(csr1212_new_string_descriptor_leaf);
EXPORT_SYMBOL(csr1212_detach_keyval_from_directory);
-EXPORT_SYMBOL(csr1212_release_keyval);
-EXPORT_SYMBOL(csr1212_destroy_csr);
-EXPORT_SYMBOL(csr1212_read);
-EXPORT_SYMBOL(csr1212_generate_csr_image);
+EXPORT_SYMBOL(csr1212_get_keyval);
+EXPORT_SYMBOL(csr1212_new_directory);
EXPORT_SYMBOL(csr1212_parse_keyval);
-EXPORT_SYMBOL(csr1212_parse_csr);
-EXPORT_SYMBOL(_csr1212_read_keyval);
-EXPORT_SYMBOL(_csr1212_destroy_keyval);
+EXPORT_SYMBOL(csr1212_read);
+EXPORT_SYMBOL(csr1212_release_keyval);