Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

firewire: core: use spin lock specific to transaction

The list of instance for asynchronous transaction to wait for response
subaction is maintained as a member of fw_card structure. The card-wide
spinlock is used at present for any operation over the list, however it
is not necessarily suited for the purpose.

This commit adds and uses the spin lock specific to maintain the list.

Link: https://lore.kernel.org/r/20250915234747.915922-5-o-takashi@sakamocchi.jp
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>

+51 -30
+8 -4
drivers/firewire/core-card.c
··· 544 544 card->index = atomic_inc_return(&index); 545 545 card->driver = driver; 546 546 card->device = device; 547 - card->current_tlabel = 0; 548 - card->tlabel_mask = 0; 547 + 548 + card->transactions.current_tlabel = 0; 549 + card->transactions.tlabel_mask = 0; 550 + INIT_LIST_HEAD(&card->transactions.list); 551 + spin_lock_init(&card->transactions.lock); 552 + 549 553 card->split_timeout_hi = DEFAULT_SPLIT_TIMEOUT / 8000; 550 554 card->split_timeout_lo = (DEFAULT_SPLIT_TIMEOUT % 8000) << 19; 551 555 card->split_timeout_cycles = DEFAULT_SPLIT_TIMEOUT; ··· 559 555 560 556 kref_init(&card->kref); 561 557 init_completion(&card->done); 562 - INIT_LIST_HEAD(&card->transaction_list); 558 + 563 559 spin_lock_init(&card->lock); 564 560 565 561 card->local_node = NULL; ··· 776 772 destroy_workqueue(card->isoc_wq); 777 773 destroy_workqueue(card->async_wq); 778 774 779 - WARN_ON(!list_empty(&card->transaction_list)); 775 + WARN_ON(!list_empty(&card->transactions.list)); 780 776 } 781 777 EXPORT_SYMBOL(fw_core_remove_card); 782 778
+36 -23
drivers/firewire/core-transaction.c
··· 49 49 { 50 50 struct fw_transaction *t = NULL, *iter; 51 51 52 - scoped_guard(spinlock_irqsave, &card->lock) { 53 - list_for_each_entry(iter, &card->transaction_list, link) { 52 + // NOTE: This can be without irqsave when we can guarantee that __fw_send_request() for 53 + // local destination never runs in any type of IRQ context. 54 + scoped_guard(spinlock_irqsave, &card->transactions.lock) { 55 + list_for_each_entry(iter, &card->transactions.list, link) { 54 56 if (iter == transaction) { 55 57 if (try_cancel_split_timeout(iter)) { 56 58 list_del_init(&iter->link); 57 - card->tlabel_mask &= ~(1ULL << iter->tlabel); 59 + card->transactions.tlabel_mask &= ~(1ULL << iter->tlabel); 58 60 t = iter; 59 61 } 60 62 break; ··· 119 117 struct fw_transaction *t = timer_container_of(t, timer, split_timeout_timer); 120 118 struct fw_card *card = t->card; 121 119 122 - scoped_guard(spinlock_irqsave, &card->lock) { 120 + scoped_guard(spinlock_irqsave, &card->transactions.lock) { 123 121 if (list_empty(&t->link)) 124 122 return; 125 123 list_del(&t->link); 126 - card->tlabel_mask &= ~(1ULL << t->tlabel); 124 + card->transactions.tlabel_mask &= ~(1ULL << t->tlabel); 127 125 } 128 126 129 127 if (!t->with_tstamp) { ··· 261 259 } 262 260 263 261 static int allocate_tlabel(struct fw_card *card) 262 + __must_hold(&card->transactions_lock) 264 263 { 265 264 int tlabel; 266 265 267 - tlabel = card->current_tlabel; 268 - while (card->tlabel_mask & (1ULL << tlabel)) { 266 + lockdep_assert_held(&card->transactions.lock); 267 + 268 + tlabel = card->transactions.current_tlabel; 269 + while (card->transactions.tlabel_mask & (1ULL << tlabel)) { 269 270 tlabel = (tlabel + 1) & 0x3f; 270 - if (tlabel == card->current_tlabel) 271 + if (tlabel == card->transactions.current_tlabel) 271 272 return -EBUSY; 272 273 } 273 274 274 - card->current_tlabel = (tlabel + 1) & 0x3f; 275 - card->tlabel_mask |= 1ULL << tlabel; 275 + card->transactions.current_tlabel = (tlabel + 1) & 0x3f; 276 + card->transactions.tlabel_mask |= 1ULL << tlabel; 276 277 277 278 return tlabel; 278 279 } ··· 336 331 void *payload, size_t length, union fw_transaction_callback callback, 337 332 bool with_tstamp, void *callback_data) 338 333 { 339 - unsigned long flags; 340 334 int tlabel; 341 335 342 336 /* ··· 343 339 * the list while holding the card spinlock. 344 340 */ 345 341 346 - spin_lock_irqsave(&card->lock, flags); 347 - 348 - tlabel = allocate_tlabel(card); 342 + // NOTE: This can be without irqsave when we can guarantee that __fw_send_request() for 343 + // local destination never runs in any type of IRQ context. 344 + scoped_guard(spinlock_irqsave, &card->transactions.lock) 345 + tlabel = allocate_tlabel(card); 349 346 if (tlabel < 0) { 350 - spin_unlock_irqrestore(&card->lock, flags); 351 347 if (!with_tstamp) { 352 348 callback.without_tstamp(card, RCODE_SEND_ERROR, NULL, 0, callback_data); 353 349 } else { ··· 372 368 t->callback = callback; 373 369 t->with_tstamp = with_tstamp; 374 370 t->callback_data = callback_data; 375 - 376 - fw_fill_request(&t->packet, tcode, t->tlabel, destination_id, card->node_id, generation, 377 - speed, offset, payload, length); 378 371 t->packet.callback = transmit_complete_callback; 379 372 380 - list_add_tail(&t->link, &card->transaction_list); 373 + // NOTE: This can be without irqsave when we can guarantee that __fw_send_request() for 374 + // local destination never runs in any type of IRQ context. 375 + scoped_guard(spinlock_irqsave, &card->lock) { 376 + // The node_id field of fw_card can be updated when handling SelfIDComplete. 377 + fw_fill_request(&t->packet, tcode, t->tlabel, destination_id, card->node_id, 378 + generation, speed, offset, payload, length); 379 + } 381 380 382 - spin_unlock_irqrestore(&card->lock, flags); 381 + // NOTE: This can be without irqsave when we can guarantee that __fw_send_request() for 382 + // local destination never runs in any type of IRQ context. 383 + scoped_guard(spinlock_irqsave, &card->transactions.lock) 384 + list_add_tail(&t->link, &card->transactions.list); 383 385 386 + // Safe with no lock, since the index field of fw_card is immutable once assigned. 384 387 trace_async_request_outbound_initiate((uintptr_t)t, card->index, generation, speed, 385 388 t->packet.header, payload, 386 389 tcode_is_read_request(tcode) ? 0 : length / 4); ··· 1122 1111 break; 1123 1112 } 1124 1113 1125 - scoped_guard(spinlock_irqsave, &card->lock) { 1126 - list_for_each_entry(iter, &card->transaction_list, link) { 1114 + // NOTE: This can be without irqsave when we can guarantee that __fw_send_request() for 1115 + // local destination never runs in any type of IRQ context. 1116 + scoped_guard(spinlock_irqsave, &card->transactions.lock) { 1117 + list_for_each_entry(iter, &card->transactions.list, link) { 1127 1118 if (iter->node_id == source && iter->tlabel == tlabel) { 1128 1119 if (try_cancel_split_timeout(iter)) { 1129 1120 list_del_init(&iter->link); 1130 - card->tlabel_mask &= ~(1ULL << iter->tlabel); 1121 + card->transactions.tlabel_mask &= ~(1ULL << iter->tlabel); 1131 1122 t = iter; 1132 1123 } 1133 1124 break;
+7 -3
include/linux/firewire.h
··· 88 88 89 89 int node_id; 90 90 int generation; 91 - int current_tlabel; 92 - u64 tlabel_mask; 93 - struct list_head transaction_list; 94 91 u64 reset_jiffies; 92 + 93 + struct { 94 + int current_tlabel; 95 + u64 tlabel_mask; 96 + struct list_head list; 97 + spinlock_t lock; 98 + } transactions; 95 99 96 100 u32 split_timeout_hi; 97 101 u32 split_timeout_lo;