mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-09-18 22:14:16 +00:00
firewire: ohci: use workqueue to handle events of AT request/response contexts
This commit adds a work item to handle events of 1394 OHCI AT request/response contexts, and queues the item to the specific workqueue. The call of struct fw_packet.callbaqck() is done in the workqueue when receiving acknowledgement to the asynchronous packet transferred to remote node. Link: https://lore.kernel.org/r/20250615133253.433057-4-o-takashi@sakamocchi.jp Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
This commit is contained in:
parent
57e6d9f85f
commit
aef6bcc0f2
3 changed files with 35 additions and 20 deletions
|
@ -1007,7 +1007,7 @@ static int fwnet_send_packet(struct fwnet_packet_task *ptask)
|
||||||
|
|
||||||
spin_lock_irqsave(&dev->lock, flags);
|
spin_lock_irqsave(&dev->lock, flags);
|
||||||
|
|
||||||
/* If the AT tasklet already ran, we may be last user. */
|
/* If the AT work item already ran, we may be last user. */
|
||||||
free = (ptask->outstanding_pkts == 0 && !ptask->enqueued);
|
free = (ptask->outstanding_pkts == 0 && !ptask->enqueued);
|
||||||
if (!free)
|
if (!free)
|
||||||
ptask->enqueued = true;
|
ptask->enqueued = true;
|
||||||
|
@ -1026,7 +1026,7 @@ static int fwnet_send_packet(struct fwnet_packet_task *ptask)
|
||||||
|
|
||||||
spin_lock_irqsave(&dev->lock, flags);
|
spin_lock_irqsave(&dev->lock, flags);
|
||||||
|
|
||||||
/* If the AT tasklet already ran, we may be last user. */
|
/* If the AT work item already ran, we may be last user. */
|
||||||
free = (ptask->outstanding_pkts == 0 && !ptask->enqueued);
|
free = (ptask->outstanding_pkts == 0 && !ptask->enqueued);
|
||||||
if (!free)
|
if (!free)
|
||||||
ptask->enqueued = true;
|
ptask->enqueued = true;
|
||||||
|
|
|
@ -158,7 +158,7 @@ struct context {
|
||||||
|
|
||||||
descriptor_callback_t callback;
|
descriptor_callback_t callback;
|
||||||
|
|
||||||
struct tasklet_struct tasklet;
|
struct work_struct work;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct iso_context {
|
struct iso_context {
|
||||||
|
@ -1176,9 +1176,9 @@ static void context_retire_descriptors(struct context *ctx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void context_tasklet(unsigned long data)
|
static void ohci_at_context_work(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct context *ctx = (struct context *) data;
|
struct context *ctx = from_work(ctx, work, work);
|
||||||
|
|
||||||
context_retire_descriptors(ctx);
|
context_retire_descriptors(ctx);
|
||||||
}
|
}
|
||||||
|
@ -1243,7 +1243,6 @@ static int context_init(struct context *ctx, struct fw_ohci *ohci,
|
||||||
ctx->buffer_tail = list_entry(ctx->buffer_list.next,
|
ctx->buffer_tail = list_entry(ctx->buffer_list.next,
|
||||||
struct descriptor_buffer, list);
|
struct descriptor_buffer, list);
|
||||||
|
|
||||||
tasklet_init(&ctx->tasklet, context_tasklet, (unsigned long)ctx);
|
|
||||||
ctx->callback = callback;
|
ctx->callback = callback;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1524,13 +1523,17 @@ static int at_context_queue_packet(struct context *ctx,
|
||||||
|
|
||||||
static void at_context_flush(struct context *ctx)
|
static void at_context_flush(struct context *ctx)
|
||||||
{
|
{
|
||||||
tasklet_disable(&ctx->tasklet);
|
// Avoid dead lock due to programming mistake.
|
||||||
|
if (WARN_ON_ONCE(current_work() == &ctx->work))
|
||||||
|
return;
|
||||||
|
|
||||||
ctx->flushing = true;
|
disable_work_sync(&ctx->work);
|
||||||
context_tasklet((unsigned long)ctx);
|
|
||||||
ctx->flushing = false;
|
|
||||||
|
|
||||||
tasklet_enable(&ctx->tasklet);
|
WRITE_ONCE(ctx->flushing, true);
|
||||||
|
ohci_at_context_work(&ctx->work);
|
||||||
|
WRITE_ONCE(ctx->flushing, false);
|
||||||
|
|
||||||
|
enable_work(&ctx->work);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int handle_at_packet(struct context *context,
|
static int handle_at_packet(struct context *context,
|
||||||
|
@ -1542,7 +1545,7 @@ static int handle_at_packet(struct context *context,
|
||||||
struct fw_ohci *ohci = context->ohci;
|
struct fw_ohci *ohci = context->ohci;
|
||||||
int evt;
|
int evt;
|
||||||
|
|
||||||
if (last->transfer_status == 0 && !context->flushing)
|
if (last->transfer_status == 0 && !READ_ONCE(context->flushing))
|
||||||
/* This descriptor isn't done yet, stop iteration. */
|
/* This descriptor isn't done yet, stop iteration. */
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -1576,7 +1579,7 @@ static int handle_at_packet(struct context *context,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OHCI1394_evt_missing_ack:
|
case OHCI1394_evt_missing_ack:
|
||||||
if (context->flushing)
|
if (READ_ONCE(context->flushing))
|
||||||
packet->ack = RCODE_GENERATION;
|
packet->ack = RCODE_GENERATION;
|
||||||
else {
|
else {
|
||||||
/*
|
/*
|
||||||
|
@ -1598,7 +1601,7 @@ static int handle_at_packet(struct context *context,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OHCI1394_evt_no_status:
|
case OHCI1394_evt_no_status:
|
||||||
if (context->flushing) {
|
if (READ_ONCE(context->flushing)) {
|
||||||
packet->ack = RCODE_GENERATION;
|
packet->ack = RCODE_GENERATION;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -2239,10 +2242,10 @@ static irqreturn_t irq_handler(int irq, void *data)
|
||||||
queue_work(ohci->card.async_wq, &ohci->ar_response_ctx.work);
|
queue_work(ohci->card.async_wq, &ohci->ar_response_ctx.work);
|
||||||
|
|
||||||
if (event & OHCI1394_reqTxComplete)
|
if (event & OHCI1394_reqTxComplete)
|
||||||
tasklet_schedule(&ohci->at_request_ctx.tasklet);
|
queue_work(ohci->card.async_wq, &ohci->at_request_ctx.work);
|
||||||
|
|
||||||
if (event & OHCI1394_respTxComplete)
|
if (event & OHCI1394_respTxComplete)
|
||||||
tasklet_schedule(&ohci->at_response_ctx.tasklet);
|
queue_work(ohci->card.async_wq, &ohci->at_response_ctx.work);
|
||||||
|
|
||||||
if (event & OHCI1394_isochRx) {
|
if (event & OHCI1394_isochRx) {
|
||||||
iso_event = reg_read(ohci, OHCI1394_IsoRecvIntEventClear);
|
iso_event = reg_read(ohci, OHCI1394_IsoRecvIntEventClear);
|
||||||
|
@ -2684,7 +2687,10 @@ static int ohci_cancel_packet(struct fw_card *card, struct fw_packet *packet)
|
||||||
struct driver_data *driver_data = packet->driver_data;
|
struct driver_data *driver_data = packet->driver_data;
|
||||||
int ret = -ENOENT;
|
int ret = -ENOENT;
|
||||||
|
|
||||||
tasklet_disable_in_atomic(&ctx->tasklet);
|
// Avoid dead lock due to programming mistake.
|
||||||
|
if (WARN_ON_ONCE(current_work() == &ctx->work))
|
||||||
|
return 0;
|
||||||
|
disable_work_sync(&ctx->work);
|
||||||
|
|
||||||
if (packet->ack != 0)
|
if (packet->ack != 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -2703,7 +2709,7 @@ static int ohci_cancel_packet(struct fw_card *card, struct fw_packet *packet)
|
||||||
packet->callback(packet, &ohci->card, packet->ack);
|
packet->callback(packet, &ohci->card, packet->ack);
|
||||||
ret = 0;
|
ret = 0;
|
||||||
out:
|
out:
|
||||||
tasklet_enable(&ctx->tasklet);
|
enable_work(&ctx->work);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -3765,11 +3771,13 @@ static int pci_probe(struct pci_dev *dev,
|
||||||
OHCI1394_AsReqTrContextControlSet, handle_at_packet);
|
OHCI1394_AsReqTrContextControlSet, handle_at_packet);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
INIT_WORK(&ohci->at_request_ctx.work, ohci_at_context_work);
|
||||||
|
|
||||||
err = context_init(&ohci->at_response_ctx, ohci,
|
err = context_init(&ohci->at_response_ctx, ohci,
|
||||||
OHCI1394_AsRspTrContextControlSet, handle_at_packet);
|
OHCI1394_AsRspTrContextControlSet, handle_at_packet);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
INIT_WORK(&ohci->at_response_ctx.work, ohci_at_context_work);
|
||||||
|
|
||||||
reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, ~0);
|
reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, ~0);
|
||||||
ohci->ir_context_channels = ~0ULL;
|
ohci->ir_context_channels = ~0ULL;
|
||||||
|
|
|
@ -308,8 +308,7 @@ struct fw_packet {
|
||||||
* For successful transmission, the status code is the ack received
|
* For successful transmission, the status code is the ack received
|
||||||
* from the destination. Otherwise it is one of the juju-specific
|
* from the destination. Otherwise it is one of the juju-specific
|
||||||
* rcodes: RCODE_SEND_ERROR, _CANCELLED, _BUSY, _GENERATION, _NO_ACK.
|
* rcodes: RCODE_SEND_ERROR, _CANCELLED, _BUSY, _GENERATION, _NO_ACK.
|
||||||
* The callback can be called from tasklet context and thus
|
* The callback can be called from workqueue and thus must never block.
|
||||||
* must never block.
|
|
||||||
*/
|
*/
|
||||||
fw_packet_callback_t callback;
|
fw_packet_callback_t callback;
|
||||||
int ack;
|
int ack;
|
||||||
|
@ -382,6 +381,10 @@ void __fw_send_request(struct fw_card *card, struct fw_transaction *t, int tcode
|
||||||
*
|
*
|
||||||
* A variation of __fw_send_request() to generate callback for response subaction without time
|
* A variation of __fw_send_request() to generate callback for response subaction without time
|
||||||
* stamp.
|
* stamp.
|
||||||
|
*
|
||||||
|
* The callback is invoked in the workqueue context in most cases. However, if an error is detected
|
||||||
|
* before queueing or the destination address refers to the local node, it is invoked in the
|
||||||
|
* current context instead.
|
||||||
*/
|
*/
|
||||||
static inline void fw_send_request(struct fw_card *card, struct fw_transaction *t, int tcode,
|
static inline void fw_send_request(struct fw_card *card, struct fw_transaction *t, int tcode,
|
||||||
int destination_id, int generation, int speed,
|
int destination_id, int generation, int speed,
|
||||||
|
@ -411,6 +414,10 @@ static inline void fw_send_request(struct fw_card *card, struct fw_transaction *
|
||||||
* @callback_data: data to be passed to the transaction completion callback
|
* @callback_data: data to be passed to the transaction completion callback
|
||||||
*
|
*
|
||||||
* A variation of __fw_send_request() to generate callback for response subaction with time stamp.
|
* A variation of __fw_send_request() to generate callback for response subaction with time stamp.
|
||||||
|
*
|
||||||
|
* The callback is invoked in the workqueue context in most cases. However, if an error is detected
|
||||||
|
* before queueing or the destination address refers to the local node, it is invoked in the current
|
||||||
|
* context instead.
|
||||||
*/
|
*/
|
||||||
static inline void fw_send_request_with_tstamp(struct fw_card *card, struct fw_transaction *t,
|
static inline void fw_send_request_with_tstamp(struct fw_card *card, struct fw_transaction *t,
|
||||||
int tcode, int destination_id, int generation, int speed, unsigned long long offset,
|
int tcode, int destination_id, int generation, int speed, unsigned long long offset,
|
||||||
|
|
Loading…
Add table
Reference in a new issue