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 timer for split transaction

At present the parameters to compute timeout time for split transaction is
protected by card-wide spin lock, while it is not necessarily convenient
in a point to narrower critical section.

This commit adds and uses another spin lock specific for the purpose.

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

+57 -31
+6 -4
drivers/firewire/core-card.c
··· 550 550 INIT_LIST_HEAD(&card->transactions.list); 551 551 spin_lock_init(&card->transactions.lock); 552 552 553 - card->split_timeout_hi = DEFAULT_SPLIT_TIMEOUT / 8000; 554 - card->split_timeout_lo = (DEFAULT_SPLIT_TIMEOUT % 8000) << 19; 555 - card->split_timeout_cycles = DEFAULT_SPLIT_TIMEOUT; 556 - card->split_timeout_jiffies = isoc_cycles_to_jiffies(DEFAULT_SPLIT_TIMEOUT); 553 + card->split_timeout.hi = DEFAULT_SPLIT_TIMEOUT / 8000; 554 + card->split_timeout.lo = (DEFAULT_SPLIT_TIMEOUT % 8000) << 19; 555 + card->split_timeout.cycles = DEFAULT_SPLIT_TIMEOUT; 556 + card->split_timeout.jiffies = isoc_cycles_to_jiffies(DEFAULT_SPLIT_TIMEOUT); 557 + spin_lock_init(&card->split_timeout.lock); 558 + 557 559 card->color = 0; 558 560 card->broadcast_channel = BROADCAST_CHANNEL_INITIAL; 559 561
+42 -21
drivers/firewire/core-transaction.c
··· 137 137 static void start_split_transaction_timeout(struct fw_transaction *t, 138 138 struct fw_card *card) 139 139 { 140 - guard(spinlock_irqsave)(&card->lock); 140 + unsigned long delta; 141 141 142 142 if (list_empty(&t->link) || WARN_ON(t->is_split_transaction)) 143 143 return; 144 144 145 145 t->is_split_transaction = true; 146 - mod_timer(&t->split_timeout_timer, 147 - jiffies + card->split_timeout_jiffies); 146 + 147 + // NOTE: This can be without irqsave when we can guarantee that __fw_send_request() for 148 + // local destination never runs in any type of IRQ context. 149 + scoped_guard(spinlock_irqsave, &card->split_timeout.lock) 150 + delta = card->split_timeout.jiffies; 151 + mod_timer(&t->split_timeout_timer, jiffies + delta); 148 152 } 149 153 150 154 static u32 compute_split_timeout_timestamp(struct fw_card *card, u32 request_timestamp); ··· 168 164 break; 169 165 case ACK_PENDING: 170 166 { 171 - t->split_timeout_cycle = 172 - compute_split_timeout_timestamp(card, packet->timestamp) & 0xffff; 167 + // NOTE: This can be without irqsave when we can guarantee that __fw_send_request() for 168 + // local destination never runs in any type of IRQ context. 169 + scoped_guard(spinlock_irqsave, &card->split_timeout.lock) { 170 + t->split_timeout_cycle = 171 + compute_split_timeout_timestamp(card, packet->timestamp) & 0xffff; 172 + } 173 173 start_split_transaction_timeout(t, card); 174 174 break; 175 175 } ··· 798 790 799 791 static u32 compute_split_timeout_timestamp(struct fw_card *card, 800 792 u32 request_timestamp) 793 + __must_hold(&card->split_timeout.lock) 801 794 { 802 795 unsigned int cycles; 803 796 u32 timestamp; 804 797 805 - cycles = card->split_timeout_cycles; 798 + lockdep_assert_held(&card->split_timeout.lock); 799 + 800 + cycles = card->split_timeout.cycles; 806 801 cycles += request_timestamp & 0x1fff; 807 802 808 803 timestamp = request_timestamp & ~0x1fff; ··· 856 845 return NULL; 857 846 kref_init(&request->kref); 858 847 848 + // NOTE: This can be without irqsave when we can guarantee that __fw_send_request() for 849 + // local destination never runs in any type of IRQ context. 850 + scoped_guard(spinlock_irqsave, &card->split_timeout.lock) 851 + request->response.timestamp = compute_split_timeout_timestamp(card, p->timestamp); 852 + 859 853 request->response.speed = p->speed; 860 - request->response.timestamp = 861 - compute_split_timeout_timestamp(card, p->timestamp); 862 854 request->response.generation = p->generation; 863 855 request->response.ack = 0; 864 856 request->response.callback = free_response_callback; ··· 1242 1228 .end = CSR_REGISTER_BASE | CSR_CONFIG_ROM, }; 1243 1229 1244 1230 static void update_split_timeout(struct fw_card *card) 1231 + __must_hold(&card->split_timeout.lock) 1245 1232 { 1246 1233 unsigned int cycles; 1247 1234 1248 - cycles = card->split_timeout_hi * 8000 + (card->split_timeout_lo >> 19); 1235 + cycles = card->split_timeout.hi * 8000 + (card->split_timeout.lo >> 19); 1249 1236 1250 1237 /* minimum per IEEE 1394, maximum which doesn't overflow OHCI */ 1251 1238 cycles = clamp(cycles, 800u, 3u * 8000u); 1252 1239 1253 - card->split_timeout_cycles = cycles; 1254 - card->split_timeout_jiffies = isoc_cycles_to_jiffies(cycles); 1240 + card->split_timeout.cycles = cycles; 1241 + card->split_timeout.jiffies = isoc_cycles_to_jiffies(cycles); 1255 1242 } 1256 1243 1257 1244 static void handle_registers(struct fw_card *card, struct fw_request *request, ··· 1302 1287 1303 1288 case CSR_SPLIT_TIMEOUT_HI: 1304 1289 if (tcode == TCODE_READ_QUADLET_REQUEST) { 1305 - *data = cpu_to_be32(card->split_timeout_hi); 1290 + *data = cpu_to_be32(card->split_timeout.hi); 1306 1291 } else if (tcode == TCODE_WRITE_QUADLET_REQUEST) { 1307 - guard(spinlock_irqsave)(&card->lock); 1308 - 1309 - card->split_timeout_hi = be32_to_cpu(*data) & 7; 1310 - update_split_timeout(card); 1292 + // NOTE: This can be without irqsave when we can guarantee that 1293 + // __fw_send_request() for local destination never runs in any type of IRQ 1294 + // context. 1295 + scoped_guard(spinlock_irqsave, &card->split_timeout.lock) { 1296 + card->split_timeout.hi = be32_to_cpu(*data) & 7; 1297 + update_split_timeout(card); 1298 + } 1311 1299 } else { 1312 1300 rcode = RCODE_TYPE_ERROR; 1313 1301 } ··· 1318 1300 1319 1301 case CSR_SPLIT_TIMEOUT_LO: 1320 1302 if (tcode == TCODE_READ_QUADLET_REQUEST) { 1321 - *data = cpu_to_be32(card->split_timeout_lo); 1303 + *data = cpu_to_be32(card->split_timeout.lo); 1322 1304 } else if (tcode == TCODE_WRITE_QUADLET_REQUEST) { 1323 - guard(spinlock_irqsave)(&card->lock); 1324 - 1325 - card->split_timeout_lo = be32_to_cpu(*data) & 0xfff80000; 1326 - update_split_timeout(card); 1305 + // NOTE: This can be without irqsave when we can guarantee that 1306 + // __fw_send_request() for local destination never runs in any type of IRQ 1307 + // context. 1308 + scoped_guard(spinlock_irqsave, &card->split_timeout.lock) { 1309 + card->split_timeout.lo = be32_to_cpu(*data) & 0xfff80000; 1310 + update_split_timeout(card); 1311 + } 1327 1312 } else { 1328 1313 rcode = RCODE_TYPE_ERROR; 1329 1314 }
+9 -6
include/linux/firewire.h
··· 97 97 spinlock_t lock; 98 98 } transactions; 99 99 100 - u32 split_timeout_hi; 101 - u32 split_timeout_lo; 102 - unsigned int split_timeout_cycles; 103 - unsigned int split_timeout_jiffies; 100 + struct { 101 + u32 hi; 102 + u32 lo; 103 + unsigned int cycles; 104 + unsigned int jiffies; 105 + spinlock_t lock; 106 + } split_timeout; 104 107 105 108 unsigned long long guid; 106 109 unsigned max_receive; 107 110 int link_speed; 108 111 int config_rom_generation; 109 112 110 - spinlock_t lock; /* Take this lock when handling the lists in 111 - * this struct. */ 113 + spinlock_t lock; 114 + 112 115 struct fw_node *local_node; 113 116 struct fw_node *root_node; 114 117 struct fw_node *irm_node;