Commit 09d714d5 authored by Ben Collins's avatar Ben Collins

IEEE1394(r1165): Better pending packet handling, patch from Steve.

parent a33161f5
......@@ -142,10 +142,9 @@ struct hpsb_packet *hpsb_alloc_packet(size_t data_size)
}
INIT_LIST_HEAD(&packet->list);
packet->complete_routine = NULL;
packet->complete_data = NULL;
packet->state = hpsb_unused;
packet->generation = -1;
atomic_set(&packet->refcnt, 1);
return packet;
}
......@@ -160,10 +159,10 @@ struct hpsb_packet *hpsb_alloc_packet(size_t data_size)
*/
void hpsb_free_packet(struct hpsb_packet *packet)
{
if (!packet) return;
if (packet && atomic_dec_and_test(&packet->refcnt)) {
kfree(packet->data);
kmem_cache_free(hpsb_packet_cache, packet);
}
}
......@@ -402,8 +401,6 @@ void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot)
void hpsb_packet_sent(struct hpsb_host *host, struct hpsb_packet *packet,
int ackcode)
{
unsigned long flags;
packet->ack_code = ackcode;
if (packet->no_waiter) {
......@@ -413,18 +410,22 @@ void hpsb_packet_sent(struct hpsb_host *host, struct hpsb_packet *packet,
}
if (ackcode != ACK_PENDING || !packet->expect_response) {
atomic_dec(&packet->refcnt);
list_del(&packet->list);
packet->state = hpsb_complete;
queue_packet_complete(packet);
return;
}
if (packet->state == hpsb_complete) {
hpsb_free_packet(packet);
return;
}
atomic_dec(&packet->refcnt);
packet->state = hpsb_pending;
packet->sendtime = jiffies;
spin_lock_irqsave(&host->pending_pkt_lock, flags);
list_add_tail(&packet->list, &host->pending_packets);
spin_unlock_irqrestore(&host->pending_pkt_lock, flags);
mod_timer(&host->timeout, jiffies + host->timeout_interval);
}
......@@ -502,6 +503,15 @@ int hpsb_send_packet(struct hpsb_packet *packet)
packet->state = hpsb_queued;
if (!packet->no_waiter || packet->expect_response) {
unsigned long flags;
atomic_inc(&packet->refcnt);
spin_lock_irqsave(&host->pending_pkt_lock, flags);
list_add_tail(&packet->list, &host->pending_packets);
spin_unlock_irqrestore(&host->pending_pkt_lock, flags);
}
if (packet->node_id == host->node_id)
{ /* it is a local request, so handle it locally */
quadlet_t *data;
......@@ -658,6 +668,11 @@ void handle_packet_response(struct hpsb_host *host, int tcode, quadlet_t *data,
break;
}
if (packet->state == hpsb_queued) {
packet->sendtime = jiffies;
packet->ack_code = ACK_PENDING;
}
packet->state = hpsb_complete;
queue_packet_complete(packet);
}
......
......@@ -4,6 +4,7 @@
#include <linux/slab.h>
#include <linux/devfs_fs_kernel.h>
#include <asm/atomic.h>
#include <asm/semaphore.h>
#include "hosts.h"
......@@ -59,6 +60,8 @@ struct hpsb_packet {
struct hpsb_host *host;
unsigned int generation;
atomic_t refcnt;
/* Function (and possible data to pass to it) to call when this
* packet is completed. */
void (*complete_routine)(void *);
......
......@@ -2376,10 +2376,6 @@ static irqreturn_t ohci_irq_handler(int irq, void *dev_id,
event &= ~OHCI1394_busReset;
}
/* XXX: We need a way to also queue the OHCI1394_reqTxComplete,
* but for right now we simply run it upon reception, to make sure
* we get sent acks before response packets. This sucks mainly
* because it halts the interrupt handler. */
if (event & OHCI1394_reqTxComplete) {
struct dma_trm_ctx *d = &ohci->at_req_context;
DBGMSG(ohci->id, "Got reqTxComplete interrupt "
......@@ -2388,7 +2384,7 @@ static irqreturn_t ohci_irq_handler(int irq, void *dev_id,
ohci1394_stop_context(ohci, d->ctrlClear,
"reqTxComplete");
else
dma_trm_tasklet ((unsigned long)d);
tasklet_schedule(&d->task);
event &= ~OHCI1394_reqTxComplete;
}
if (event & OHCI1394_respTxComplete) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment