X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fieee1394%2Fieee1394_core.c;h=87233800372182916a51caaebbc3b06f89472963;hb=6c9ae016a8e2aff931391d3baa9ce6cb0ffa633c;hp=991c378496f89370e297038ebe41ba4f5529003f;hpb=8df4083c5291b3647e0381d3c69ab2196f5dd3b7;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/ieee1394/ieee1394_core.c b/drivers/ieee1394/ieee1394_core.c index 991c378..8723380 100644 --- a/drivers/ieee1394/ieee1394_core.c +++ b/drivers/ieee1394/ieee1394_core.c @@ -30,10 +30,13 @@ #include #include #include -#include +#include #include #include +#include +#include +#include #include #include "ieee1394_types.h" @@ -85,7 +88,7 @@ static void dump_packet(const char *text, quadlet_t *data, int size, int speed) printk("\n"); } #else -#define dump_packet(a,b,c,d) +#define dump_packet(a,b,c,d) do {} while (0) #endif static void abort_requests(struct hpsb_host *host); @@ -93,13 +96,15 @@ static void queue_packet_complete(struct hpsb_packet *packet); /** - * 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) @@ -112,12 +117,12 @@ void hpsb_set_packet_complete_task(struct hpsb_packet *packet, /** * 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 @@ -132,50 +137,49 @@ void hpsb_set_packet_complete_task(struct hpsb_packet *packet, */ 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) { @@ -186,12 +190,59 @@ int hpsb_reset_bus(struct hpsb_host *host, int type) } } +/** + * 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__); + __func__); return 1; } @@ -287,6 +338,7 @@ static void build_speed_map(struct hpsb_host *host, int nodecount) u8 cldcnt[nodecount]; 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; @@ -322,6 +374,8 @@ static void build_speed_map(struct hpsb_host *host, int nodecount) if (sid->port2 == SELFID_PORT_CHILD) cldcnt[n]++; speedcap[n] = sid->speed; + if (speedcap[n] > local_link_speed) + speedcap[n] = local_link_speed; n--; } } @@ -354,15 +408,22 @@ static void build_speed_map(struct hpsb_host *host, int nodecount) } } -#if SELFID_SPEED_UNKNOWN != IEEE1394_SPEED_MAX - /* assume maximum speed for 1394b PHYs, nodemgr will correct it */ - for (n = 0; n < nodecount; n++) - if (speedcap[n] == SELFID_SPEED_UNKNOWN) - speedcap[n] = IEEE1394_SPEED_MAX; -#endif + /* 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) { @@ -374,6 +435,15 @@ void hpsb_selfid_received(struct hpsb_host *host, quadlet_t sid) } } +/** + * 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) @@ -420,30 +490,41 @@ void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot) 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) { 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; } @@ -451,7 +532,7 @@ void hpsb_packet_sent(struct hpsb_host *host, struct hpsb_packet *packet, 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); } @@ -462,9 +543,10 @@ void hpsb_packet_sent(struct hpsb_host *host, struct hpsb_packet *packet, * @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) { @@ -525,12 +607,16 @@ int hpsb_send_packet(struct hpsb_packet *packet) 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) { @@ -579,6 +665,12 @@ static void complete_packet(void *data) 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; @@ -600,86 +692,97 @@ static void send_packet_nocare(struct hpsb_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; + struct hpsb_packet *packet; + int tlabel = (data[0] >> 10) & 0x3f; + size_t header_size; unsigned long flags; - tlabel = (data[0] >> 10) & 0x3f; - - spin_lock_irqsave(&host->pending_packet_queue.lock, flags); + spin_lock_irqsave(&pending_packets_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; - } + list_for_each_entry(packet, &host->pending_packets, queue) + if (packet->tlabel == tlabel && + packet->node_id == (data[1] >> 16)) + goto found; - packet = NULL; - } - - if (packet == NULL) { - HPSB_DEBUG("unsolicited response packet received - no tlabel match"); - dump_packet("contents", data, 16, -1); - spin_unlock_irqrestore(&host->pending_packet_queue.lock, flags); - return; - } + 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 (tcode != TCODE_WRITE_RESPONSE) + if (unlikely(tcode != TCODE_WRITE_RESPONSE)) break; - tcode_match = 1; - memcpy(packet->header, data, 12); - break; + header_size = 12; + size = 0; + goto dequeue; + case TCODE_READQ: - if (tcode != TCODE_READQ_RESPONSE) + if (unlikely(tcode != TCODE_READQ_RESPONSE)) break; - tcode_match = 1; - memcpy(packet->header, data, 16); - break; + header_size = 16; + size = 0; + goto dequeue; + case TCODE_READB: - if (tcode != TCODE_READB_RESPONSE) + 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; + header_size = 16; + size = packet_size_to_data_size(size, header_size, + packet->allocated_data_size, + tcode); + goto dequeue; + case TCODE_LOCK_REQUEST: - if (tcode != TCODE_LOCK_RESPONSE) + 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, -1); - 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, &host->pending_packet_queue); +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); } @@ -693,6 +796,7 @@ static struct hpsb_packet *create_reply_packet(struct hpsb_host *host, 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; } @@ -742,7 +846,6 @@ static void fill_async_readblock_resp(struct hpsb_packet *packet, int rcode, 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; } @@ -759,12 +862,9 @@ static void fill_async_lock_resp(struct hpsb_packet *packet, int rcode, int extc 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; @@ -774,74 +874,72 @@ static void handle_incoming_packet(struct hpsb_host *host, int tcode, u16 flags = (u16) data[0]; u64 addr; - /* big FIXME - no error checking is done for an out of bounds length */ + /* 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, + rcode = highlevel_write(host, source, dest, data + 3, addr, 4, 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; + 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); - - if (!write_acked - && (NODEID_TO_NODE(data[0] >> 16) != NODE_MASK) - && (rcode >= 0)) { - /* not a broadcast write, reply */ - PREP_REPLY_PACKET(0); + 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); } - break; + return; case TCODE_READQ: addr = (((u64)(data[1] & 0xffff)) << 32) | data[2]; rcode = highlevel_read(host, source, &buffer, addr, 4, flags); + if (rcode < 0) + return; - if (rcode >= 0) { - PREP_REPLY_PACKET(0); + packet = create_reply_packet(host, data, 0); + if (packet) { fill_async_readquad_resp(packet, rcode, buffer); send_packet_nocare(packet); } - break; + return; case TCODE_READB: length = data[3] >> 16; - PREP_REPLY_PACKET(length); + 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) { - fill_async_readblock_resp(packet, rcode, length); - send_packet_nocare(packet); - } else { + if (rcode < 0) { hpsb_free_packet(packet); + return; } - break; + 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]; - PREP_REPLY_PACKET(8); + packet = create_reply_packet(host, data, 8); + if (!packet) + return; - if ((extcode == 0) || (extcode >= 7)) { + if (extcode == 0 || extcode >= 7) { /* let switch default handle error */ length = 0; } @@ -849,12 +947,12 @@ static void handle_incoming_packet(struct hpsb_host *host, int tcode, switch (length) { case 4: rcode = highlevel_lock(host, source, packet->data, addr, - data[4], 0, extcode,flags); + 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)) { + if (extcode != EXTCODE_FETCH_ADD && + extcode != EXTCODE_LITTLE_ADD) { rcode = highlevel_lock(host, source, packet->data, addr, data[5], data[4], @@ -878,29 +976,38 @@ static void handle_incoming_packet(struct hpsb_host *host, int tcode, break; default: rcode = RCODE_TYPE_ERROR; - fill_async_lock_resp(packet, rcode, - extcode, 0); + fill_async_lock_resp(packet, rcode, extcode, 0); } - if (rcode >= 0) { - send_packet_nocare(packet); - } else { + if (rcode < 0) hpsb_free_packet(packet); - } - break; + else + send_packet_nocare(packet); + return; } - } -#undef PREP_REPLY_PACKET - +/** + * 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 tcode; - if (host->in_bus_reset) { - HPSB_INFO("received packet during reset; ignoring"); + if (unlikely(host->in_bus_reset)) { + HPSB_DEBUG("received packet during reset; ignoring"); return; } @@ -924,33 +1031,32 @@ void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size, 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); + 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); @@ -960,87 +1066,88 @@ static void abort_requests(struct hpsb_host *host) 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); - - while (!skb_queue_empty(&host->pending_packet_queue)) { - skb = skb_peek(&host->pending_packet_queue); - - packet = (struct hpsb_packet *)skb->data; + j = jiffies; + INIT_LIST_HEAD(&tmp); + spin_lock_irqsave(&pending_packets_lock, flags); - if (time_before(packet->sendtime + expire, jiffies)) { - __skb_unlink(skb, &host->pending_packet_queue); - 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 struct task_struct *khpsbpkt_thread; -static struct sk_buff_head hpsbpkt_queue; +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); + 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; - - current->flags |= PF_NOFREEZE; + struct hpsb_packet *packet, *p; + struct list_head tmp; + int may_schedule; while (!kthread_should_stop()) { - while ((skb = skb_dequeue(&hpsbpkt_queue)) != NULL) { - packet = (struct hpsb_packet *)skb->data; - - complete_routine = packet->complete_routine; - complete_data = packet->complete_data; - 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); } set_current_state(TASK_INTERRUPTIBLE); - if (!skb_peek(&hpsbpkt_queue)) + 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); } @@ -1051,8 +1158,6 @@ 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"); @@ -1170,7 +1275,7 @@ static void __exit ieee1394_cleanup(void) unregister_chrdev_region(IEEE1394_CORE_DEV, 256); } -fs_initcall(ieee1394_init); /* same as ohci1394 */ +fs_initcall(ieee1394_init); module_exit(ieee1394_cleanup); /* Exported symbols */ @@ -1178,6 +1283,7 @@ module_exit(ieee1394_cleanup); /** 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); @@ -1189,16 +1295,13 @@ EXPORT_SYMBOL(hpsb_alloc_packet); EXPORT_SYMBOL(hpsb_free_packet); EXPORT_SYMBOL(hpsb_send_packet); 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_packet_sent); EXPORT_SYMBOL(hpsb_packet_received); EXPORT_SYMBOL_GPL(hpsb_disable_irm); -#ifdef CONFIG_IEEE1394_EXPORT_FULL_API -EXPORT_SYMBOL(hpsb_send_phy_config); -EXPORT_SYMBOL(hpsb_send_packet_and_wait); -#endif /** ieee1394_transactions.c **/ EXPORT_SYMBOL(hpsb_get_tlabel); @@ -1209,9 +1312,9 @@ EXPORT_SYMBOL(hpsb_make_streampacket); 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 **/ @@ -1220,29 +1323,18 @@ EXPORT_SYMBOL(hpsb_unregister_highlevel); 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_host_reset); -#ifdef CONFIG_IEEE1394_EXPORT_FULL_API -EXPORT_SYMBOL(highlevel_add_host); -EXPORT_SYMBOL(highlevel_remove_host); -#endif /** 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); -#ifdef CONFIG_IEEE1394_EXPORT_FULL_API -EXPORT_SYMBOL(nodemgr_for_each_host); -#endif /** csr.c **/ EXPORT_SYMBOL(hpsb_update_config_rom); @@ -1279,21 +1371,10 @@ EXPORT_SYMBOL(hpsb_iso_wake); EXPORT_SYMBOL(hpsb_iso_recv_flush); /** csr1212.c **/ -EXPORT_SYMBOL(csr1212_new_directory); EXPORT_SYMBOL(csr1212_attach_keyval_to_directory); EXPORT_SYMBOL(csr1212_detach_keyval_from_directory); -EXPORT_SYMBOL(csr1212_release_keyval); -EXPORT_SYMBOL(csr1212_read); +EXPORT_SYMBOL(csr1212_get_keyval); +EXPORT_SYMBOL(csr1212_new_directory); EXPORT_SYMBOL(csr1212_parse_keyval); -EXPORT_SYMBOL(_csr1212_read_keyval); -EXPORT_SYMBOL(_csr1212_destroy_keyval); -#ifdef CONFIG_IEEE1394_EXPORT_FULL_API -EXPORT_SYMBOL(csr1212_create_csr); -EXPORT_SYMBOL(csr1212_init_local_csr); -EXPORT_SYMBOL(csr1212_new_immediate); -EXPORT_SYMBOL(csr1212_associate_keyval); -EXPORT_SYMBOL(csr1212_new_string_descriptor_leaf); -EXPORT_SYMBOL(csr1212_destroy_csr); -EXPORT_SYMBOL(csr1212_generate_csr_image); -EXPORT_SYMBOL(csr1212_parse_csr); -#endif +EXPORT_SYMBOL(csr1212_read); +EXPORT_SYMBOL(csr1212_release_keyval);