Commit e4c8b801 authored by Takashi Sakamoto's avatar Takashi Sakamoto

firewire: ohci: use guard macro to serialize operations for isochronous contexts

The 1394 OHCI driver uses spinlock to serialize operations for
isochronous contexts.

This commit uses guard macro to maintain the spinlock.

Link: https://lore.kernel.org/r/20240805085408.251763-18-o-takashi@sakamocchi.jpSigned-off-by: default avatarTakashi Sakamoto <o-takashi@sakamocchi.jp>
parent 86baade9
...@@ -1173,13 +1173,11 @@ static void context_tasklet(unsigned long data) ...@@ -1173,13 +1173,11 @@ static void context_tasklet(unsigned long data)
break; break;
if (old_desc != desc) { if (old_desc != desc) {
/* If we've advanced to the next buffer, move the // If we've advanced to the next buffer, move the previous buffer to the
* previous buffer to the free list. */ // free list.
unsigned long flags;
old_desc->used = 0; old_desc->used = 0;
spin_lock_irqsave(&ctx->ohci->lock, flags); guard(spinlock_irqsave)(&ctx->ohci->lock);
list_move_tail(&old_desc->list, &ctx->buffer_list); list_move_tail(&old_desc->list, &ctx->buffer_list);
spin_unlock_irqrestore(&ctx->ohci->lock, flags);
} }
ctx->last = last; ctx->last = last;
} }
...@@ -2122,14 +2120,12 @@ static void bus_reset_work(struct work_struct *work) ...@@ -2122,14 +2120,12 @@ static void bus_reset_work(struct work_struct *work)
return; return;
} }
/* FIXME: Document how the locking works. */ // FIXME: Document how the locking works.
spin_lock_irq(&ohci->lock); scoped_guard(spinlock_irq, &ohci->lock) {
ohci->generation = -1; // prevent AT packet queueing
ohci->generation = -1; /* prevent AT packet queueing */ context_stop(&ohci->at_request_ctx);
context_stop(&ohci->at_request_ctx); context_stop(&ohci->at_response_ctx);
context_stop(&ohci->at_response_ctx); }
spin_unlock_irq(&ohci->lock);
/* /*
* Per OHCI 1.2 draft, clause 7.2.3.3, hardware may leave unsent * Per OHCI 1.2 draft, clause 7.2.3.3, hardware may leave unsent
...@@ -2704,7 +2700,6 @@ static int ohci_enable_phys_dma(struct fw_card *card, ...@@ -2704,7 +2700,6 @@ static int ohci_enable_phys_dma(struct fw_card *card,
int node_id, int generation) int node_id, int generation)
{ {
struct fw_ohci *ohci = fw_ohci(card); struct fw_ohci *ohci = fw_ohci(card);
unsigned long flags;
int n, ret = 0; int n, ret = 0;
if (param_remote_dma) if (param_remote_dma)
...@@ -2715,12 +2710,10 @@ static int ohci_enable_phys_dma(struct fw_card *card, ...@@ -2715,12 +2710,10 @@ static int ohci_enable_phys_dma(struct fw_card *card,
* interrupt bit. Clear physReqResourceAllBuses on bus reset. * interrupt bit. Clear physReqResourceAllBuses on bus reset.
*/ */
spin_lock_irqsave(&ohci->lock, flags); guard(spinlock_irqsave)(&ohci->lock);
if (ohci->generation != generation) { if (ohci->generation != generation)
ret = -ESTALE; return -ESTALE;
goto out;
}
/* /*
* Note, if the node ID contains a non-local bus ID, physical DMA is * Note, if the node ID contains a non-local bus ID, physical DMA is
...@@ -2734,8 +2727,6 @@ static int ohci_enable_phys_dma(struct fw_card *card, ...@@ -2734,8 +2727,6 @@ static int ohci_enable_phys_dma(struct fw_card *card,
reg_write(ohci, OHCI1394_PhyReqFilterHiSet, 1 << (n - 32)); reg_write(ohci, OHCI1394_PhyReqFilterHiSet, 1 << (n - 32));
flush_writes(ohci); flush_writes(ohci);
out:
spin_unlock_irqrestore(&ohci->lock, flags);
return ret; return ret;
} }
...@@ -3076,55 +3067,53 @@ static struct fw_iso_context *ohci_allocate_iso_context(struct fw_card *card, ...@@ -3076,55 +3067,53 @@ static struct fw_iso_context *ohci_allocate_iso_context(struct fw_card *card,
u32 *mask, regs; u32 *mask, regs;
int index, ret = -EBUSY; int index, ret = -EBUSY;
spin_lock_irq(&ohci->lock); scoped_guard(spinlock_irq, &ohci->lock) {
switch (type) {
case FW_ISO_CONTEXT_TRANSMIT:
mask = &ohci->it_context_mask;
callback = handle_it_packet;
index = ffs(*mask) - 1;
if (index >= 0) {
*mask &= ~(1 << index);
regs = OHCI1394_IsoXmitContextBase(index);
ctx = &ohci->it_context_list[index];
}
break;
switch (type) { case FW_ISO_CONTEXT_RECEIVE:
case FW_ISO_CONTEXT_TRANSMIT: channels = &ohci->ir_context_channels;
mask = &ohci->it_context_mask; mask = &ohci->ir_context_mask;
callback = handle_it_packet; callback = handle_ir_packet_per_buffer;
index = ffs(*mask) - 1; index = *channels & 1ULL << channel ? ffs(*mask) - 1 : -1;
if (index >= 0) { if (index >= 0) {
*mask &= ~(1 << index); *channels &= ~(1ULL << channel);
regs = OHCI1394_IsoXmitContextBase(index); *mask &= ~(1 << index);
ctx = &ohci->it_context_list[index]; regs = OHCI1394_IsoRcvContextBase(index);
} ctx = &ohci->ir_context_list[index];
break; }
break;
case FW_ISO_CONTEXT_RECEIVE: case FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL:
channels = &ohci->ir_context_channels; mask = &ohci->ir_context_mask;
mask = &ohci->ir_context_mask; callback = handle_ir_buffer_fill;
callback = handle_ir_packet_per_buffer; index = !ohci->mc_allocated ? ffs(*mask) - 1 : -1;
index = *channels & 1ULL << channel ? ffs(*mask) - 1 : -1; if (index >= 0) {
if (index >= 0) { ohci->mc_allocated = true;
*channels &= ~(1ULL << channel); *mask &= ~(1 << index);
*mask &= ~(1 << index); regs = OHCI1394_IsoRcvContextBase(index);
regs = OHCI1394_IsoRcvContextBase(index); ctx = &ohci->ir_context_list[index];
ctx = &ohci->ir_context_list[index]; }
} break;
break;
case FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL: default:
mask = &ohci->ir_context_mask; index = -1;
callback = handle_ir_buffer_fill; ret = -ENOSYS;
index = !ohci->mc_allocated ? ffs(*mask) - 1 : -1;
if (index >= 0) {
ohci->mc_allocated = true;
*mask &= ~(1 << index);
regs = OHCI1394_IsoRcvContextBase(index);
ctx = &ohci->ir_context_list[index];
} }
break;
default: if (index < 0)
index = -1; return ERR_PTR(ret);
ret = -ENOSYS;
} }
spin_unlock_irq(&ohci->lock);
if (index < 0)
return ERR_PTR(ret);
memset(ctx, 0, sizeof(*ctx)); memset(ctx, 0, sizeof(*ctx));
ctx->header_length = 0; ctx->header_length = 0;
ctx->header = (void *) __get_free_page(GFP_KERNEL); ctx->header = (void *) __get_free_page(GFP_KERNEL);
...@@ -3146,20 +3135,18 @@ static struct fw_iso_context *ohci_allocate_iso_context(struct fw_card *card, ...@@ -3146,20 +3135,18 @@ static struct fw_iso_context *ohci_allocate_iso_context(struct fw_card *card,
out_with_header: out_with_header:
free_page((unsigned long)ctx->header); free_page((unsigned long)ctx->header);
out: out:
spin_lock_irq(&ohci->lock); scoped_guard(spinlock_irq, &ohci->lock) {
switch (type) {
switch (type) { case FW_ISO_CONTEXT_RECEIVE:
case FW_ISO_CONTEXT_RECEIVE: *channels |= 1ULL << channel;
*channels |= 1ULL << channel; break;
break;
case FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL: case FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL:
ohci->mc_allocated = false; ohci->mc_allocated = false;
break; break;
}
*mask |= 1 << index;
} }
*mask |= 1 << index;
spin_unlock_irq(&ohci->lock);
return ERR_PTR(ret); return ERR_PTR(ret);
} }
...@@ -3243,14 +3230,13 @@ static void ohci_free_iso_context(struct fw_iso_context *base) ...@@ -3243,14 +3230,13 @@ static void ohci_free_iso_context(struct fw_iso_context *base)
{ {
struct fw_ohci *ohci = fw_ohci(base->card); struct fw_ohci *ohci = fw_ohci(base->card);
struct iso_context *ctx = container_of(base, struct iso_context, base); struct iso_context *ctx = container_of(base, struct iso_context, base);
unsigned long flags;
int index; int index;
ohci_stop_iso(base); ohci_stop_iso(base);
context_release(&ctx->context); context_release(&ctx->context);
free_page((unsigned long)ctx->header); free_page((unsigned long)ctx->header);
spin_lock_irqsave(&ohci->lock, flags); guard(spinlock_irqsave)(&ohci->lock);
switch (base->type) { switch (base->type) {
case FW_ISO_CONTEXT_TRANSMIT: case FW_ISO_CONTEXT_TRANSMIT:
...@@ -3272,38 +3258,29 @@ static void ohci_free_iso_context(struct fw_iso_context *base) ...@@ -3272,38 +3258,29 @@ static void ohci_free_iso_context(struct fw_iso_context *base)
ohci->mc_allocated = false; ohci->mc_allocated = false;
break; break;
} }
spin_unlock_irqrestore(&ohci->lock, flags);
} }
static int ohci_set_iso_channels(struct fw_iso_context *base, u64 *channels) static int ohci_set_iso_channels(struct fw_iso_context *base, u64 *channels)
{ {
struct fw_ohci *ohci = fw_ohci(base->card); struct fw_ohci *ohci = fw_ohci(base->card);
unsigned long flags;
int ret;
switch (base->type) { switch (base->type) {
case FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL: case FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL:
{
guard(spinlock_irqsave)(&ohci->lock);
spin_lock_irqsave(&ohci->lock, flags); // Don't allow multichannel to grab other contexts' channels.
/* Don't allow multichannel to grab other contexts' channels. */
if (~ohci->ir_context_channels & ~ohci->mc_channels & *channels) { if (~ohci->ir_context_channels & ~ohci->mc_channels & *channels) {
*channels = ohci->ir_context_channels; *channels = ohci->ir_context_channels;
ret = -EBUSY; return -EBUSY;
} else { } else {
set_multichannel_mask(ohci, *channels); set_multichannel_mask(ohci, *channels);
ret = 0; return 0;
} }
}
spin_unlock_irqrestore(&ohci->lock, flags);
break;
default: default:
ret = -EINVAL; return -EINVAL;
} }
return ret;
} }
#ifdef CONFIG_PM #ifdef CONFIG_PM
...@@ -3573,24 +3550,19 @@ static int ohci_queue_iso(struct fw_iso_context *base, ...@@ -3573,24 +3550,19 @@ static int ohci_queue_iso(struct fw_iso_context *base,
unsigned long payload) unsigned long payload)
{ {
struct iso_context *ctx = container_of(base, struct iso_context, base); struct iso_context *ctx = container_of(base, struct iso_context, base);
unsigned long flags;
int ret = -ENOSYS;
spin_lock_irqsave(&ctx->context.ohci->lock, flags); guard(spinlock_irqsave)(&ctx->context.ohci->lock);
switch (base->type) { switch (base->type) {
case FW_ISO_CONTEXT_TRANSMIT: case FW_ISO_CONTEXT_TRANSMIT:
ret = queue_iso_transmit(ctx, packet, buffer, payload); return queue_iso_transmit(ctx, packet, buffer, payload);
break;
case FW_ISO_CONTEXT_RECEIVE: case FW_ISO_CONTEXT_RECEIVE:
ret = queue_iso_packet_per_buffer(ctx, packet, buffer, payload); return queue_iso_packet_per_buffer(ctx, packet, buffer, payload);
break;
case FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL: case FW_ISO_CONTEXT_RECEIVE_MULTICHANNEL:
ret = queue_iso_buffer_fill(ctx, packet, buffer, payload); return queue_iso_buffer_fill(ctx, packet, buffer, payload);
break; default:
return -ENOSYS;
} }
spin_unlock_irqrestore(&ctx->context.ohci->lock, flags);
return ret;
} }
static void ohci_flush_queue_iso(struct fw_iso_context *base) static void ohci_flush_queue_iso(struct fw_iso_context *base)
......
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