linux1394-devel Mailing List for IEEE 1394 for Linux
Brought to you by:
aeb,
bencollins
You can subscribe to this list here.
2000 |
Jan
|
Feb
|
Mar
(39) |
Apr
(154) |
May
(172) |
Jun
(237) |
Jul
(127) |
Aug
(135) |
Sep
(193) |
Oct
(175) |
Nov
(173) |
Dec
(148) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2001 |
Jan
(161) |
Feb
(225) |
Mar
(193) |
Apr
(158) |
May
(179) |
Jun
(292) |
Jul
(146) |
Aug
(134) |
Sep
(185) |
Oct
(190) |
Nov
(149) |
Dec
(161) |
2002 |
Jan
(186) |
Feb
(236) |
Mar
(254) |
Apr
(207) |
May
(189) |
Jun
(182) |
Jul
(202) |
Aug
(155) |
Sep
(149) |
Oct
(449) |
Nov
(191) |
Dec
(108) |
2003 |
Jan
(174) |
Feb
(242) |
Mar
(243) |
Apr
(255) |
May
(202) |
Jun
(290) |
Jul
(237) |
Aug
(178) |
Sep
(101) |
Oct
(153) |
Nov
(144) |
Dec
(95) |
2004 |
Jan
(162) |
Feb
(278) |
Mar
(282) |
Apr
(152) |
May
(127) |
Jun
(138) |
Jul
(94) |
Aug
(63) |
Sep
(64) |
Oct
(150) |
Nov
(102) |
Dec
(197) |
2005 |
Jan
(102) |
Feb
(172) |
Mar
(89) |
Apr
(158) |
May
(139) |
Jun
(160) |
Jul
(288) |
Aug
(89) |
Sep
(201) |
Oct
(92) |
Nov
(190) |
Dec
(139) |
2006 |
Jan
(121) |
Feb
(204) |
Mar
(133) |
Apr
(134) |
May
(91) |
Jun
(226) |
Jul
(122) |
Aug
(101) |
Sep
(144) |
Oct
(141) |
Nov
|
Dec
|
2023 |
Jan
(19) |
Feb
(1) |
Mar
(5) |
Apr
(5) |
May
(33) |
Jun
(17) |
Jul
|
Aug
|
Sep
(3) |
Oct
(1) |
Nov
(5) |
Dec
(40) |
2024 |
Jan
(26) |
Feb
(14) |
Mar
(26) |
Apr
(46) |
May
(17) |
Jun
(47) |
Jul
(23) |
Aug
(72) |
Sep
(42) |
Oct
(6) |
Nov
(2) |
Dec
(1) |
2025 |
Jan
(2) |
Feb
(1) |
Mar
(4) |
Apr
(2) |
May
|
Jun
(25) |
Jul
(12) |
Aug
(19) |
Sep
(69) |
Oct
|
Nov
|
Dec
|
From: Takashi S. <o-t...@sa...> - 2025-09-29 13:46:55
|
Hi Linus, Please accept the changes for FireWire subsystem to your tree. This update may appear to include many changes, but most of them are code refactoring. Except for the removal of firewire-ohci module parameter, there are only a few notable changes. The following changes since commit c17b750b3ad9f45f2b6f7e6f7f4679844244f0b9: Linux 6.17-rc2 (2025-08-17 15:22:10 -0700) are available in the Git repository at: git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394.git tags/firewire-updates-6.18 for you to fetch changes up to 40d4c761200b796a44bf2c7675ae09c87b17d4af: firewire: core: fix undefined reference error in ARM EABI (2025-09-28 10:20:30 +0900) ---------------------------------------------------------------- firewire updates for v6.18 This update includes the following changes: - Removal of the deprecated debug parameter from firewire-ohci module - Replacement of the module-local workqueue in 1394 OHCI PCI driver with a companion IRQ thread - Refactoring of bus management code - Additional minor code cleanup The existing tracepoints serve as an alternative to the removed debug parameter. The use of IRQ thread is experimental, as it handles 1394 OHCI SelfIDComplete event only. It may be replaced in the future releases with another approach; e.g. by providing workqueue from core functionality ---------------------------------------------------------------- Takashi Sakamoto (42): firewire: ohci: remove obsolete debug logging for IRQ events firewire: ohci: remove obsolete debug logging for selfID sequence firewire: ohci: remove obsolete debug logging for AT/AR results firewire: ohci: remove obsolete module-level debug parameter firewire: ohci: move self_id_complete tracepoint after validating register firewire: ohci: use threaded IRQ handler to handle SelfIDComplete event firewire: ohci: remove module-local workqueue firewire: ohci: use kcalloc() variant for array allocation firewire: core: utilize cleanup function to release workqueue in error path firewire: ohci: use return value from fw_node_get() firewire: core: add helper functions to access to fw_device data in fw_node structure firewire: core: use cleanup function in bm_work firewire: ohci: localize transaction data and rcode per condition branch firewire: core: code refactoring to evaluate transaction result to CSR_BUS_MANAGER_ID firewire: core: refer fw_card member to initiate bus reset under acquiring lock firewire: core: code refactoring to detect both IEEE 1394:1995 IRM and Canon MV5i firewire: core: code refactoring to investigate root node for bus manager firewire: core: code refactoring whether root node is cycle master capable firewire: core: remove useless lockdep_assert_held() firewire: core: use macro expression for gap count mismatch firewire: core: use macro expression for not-registered state of BUS_MANAGER_ID firewire: core: use helper macros instead of direct access to HZ firewire: core: use helper macro to compare against current jiffies firewire: core: use scoped_guard() to manage critical section to update topology firewire: core: maintain phy packet receivers locally in cdev layer firewire: core: use spin lock specific to topology map firewire: core: use spin lock specific to transaction firewire: core: use spin lock specific to timer for split transaction firewire: core: annotate fw_destroy_nodes with must-hold-lock firewire: core: schedule bm_work item outside of spin lock firewire: core: disable bus management work temporarily during updating topology firewire: core: shrink critical section of fw_card spinlock in bm_work firewire: core: remove useless generation check firewire: core: use switch statement to evaluate transaction result to CSR_BUS_MANAGER_ID firewire: core: code refactoring for the case of generation mismatch firewire: core: code refactoring to split contention procedure for bus manager firewire: core; eliminate pick_me goto label firewire: core: minor code refactoring to delete useless local variable firewire: core: suppress overflow warning when computing jiffies from isochronous cycle Revert "firewire: core: shrink critical section of fw_card spinlock in bm_work" Revert "firewire: core: disable bus management work temporarily during updating topology" firewire: core: fix undefined reference error in ARM EABI Thorsten Blum (1): firewire: core: use struct_size and flex_array_size in ioctl_add_descriptor drivers/firewire/core-card.c | 490 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------------------------------------------------------------------------- drivers/firewire/core-cdev.c | 36 ++++++++++----- drivers/firewire/core-device.c | 27 ++++++----- drivers/firewire/core-topology.c | 91 +++++++++++++++++++------------------ drivers/firewire/core-transaction.c | 130 ++++++++++++++++++++++++++++++++++------------------- drivers/firewire/core.h | 22 ++++++++- drivers/firewire/ohci.c | 316 +++++++++++++++++++------------------------------------------------------------------------------------------------------------- include/linux/firewire.h | 33 +++++++++----- 8 files changed, 518 insertions(+), 627 deletions(-) Regards Takashi Sakamoto |
From: Takashi S. <o-t...@sa...> - 2025-09-28 01:19:28
|
For ARM EABI, GCC generates a reference to __aeabi_uldivmod when compiling a division of 64-bit integer with 32-bit integer. This function is not available in Linux kernel. In such cases, helper macros are defined in include/linux/math64.h. This commit replaces the division with div_u64(). Fixes: 8ec6a8ec23b9 ("firewire: core: suppress overflow warning when computing jiffies from isochronous cycle") Reported-by: kernel test robot <lk...@in...> Closes: https://lore.kernel.org/oe-kbuild-all/202...@in.../ Signed-off-by: Takashi Sakamoto <o-t...@sa...> --- drivers/firewire/core.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/firewire/core.h b/drivers/firewire/core.h index 2dd715a580ac..e67395ce26b5 100644 --- a/drivers/firewire/core.h +++ b/drivers/firewire/core.h @@ -30,7 +30,7 @@ struct fw_packet; // This is the arbitrary value we use to indicate a mismatched gap count. #define GAP_COUNT_MISMATCHED 0 -#define isoc_cycles_to_jiffies(cycles) usecs_to_jiffies((u32)((u64)(cycles) * USEC_PER_SEC / 8000)) +#define isoc_cycles_to_jiffies(cycles) usecs_to_jiffies((u32)div_u64((u64)cycles * USEC_PER_SEC, 8000)) extern __printf(2, 3) void fw_err(const struct fw_card *card, const char *fmt, ...); -- 2.48.1 |
From: Takashi S. <o-t...@sa...> - 2025-09-25 13:54:04
|
On Wed, Sep 24, 2025 at 10:18:21PM +0900, Takashi Sakamoto wrote: > Hi, > > The patchset that serialized bm_work() and fw_core_handle_bus_reset() > was merged without sufficient consideration of the race condition during > fw_card removal. > > This patchset reverts some commits and restores the acquisition of the > fw_card spin lock. > > [1] https://lore.kernel.org/lkml/202...@sa.../ > > Changes from v1: > * Fulfill cover-letter title > > Takashi Sakamoto (2): > Revert "firewire: core: shrink critical section of fw_card spinlock in > bm_work" > Revert "firewire: core: disable bus management work temporarily during > updating topology" > > drivers/firewire/core-card.c | 38 +++++++++++++++++++++++++------- > drivers/firewire/core-topology.c | 8 ------- > 2 files changed, 30 insertions(+), 16 deletions(-) Applied to for-next branch. Regards Takashi Sakamoto |
From: Takashi S. <o-t...@sa...> - 2025-09-25 13:53:37
|
On Wed, Sep 24, 2025 at 10:11:40PM +0900, Takashi Sakamoto wrote: > The multiplication by USEC_PER_SEC (=1000000L) may trigger an overflow > warning with 32 bit storage. In the case of the subsystem the input value > ranges between 800 and 16000, thus the result always fits within 32 bit > storage. > > This commit suppresses the warning by using widening conversion to 64 bit > storage before multiplication, then using narrowing conversion to 32 bit > storage. > > Reported-by: kernel test robot <lk...@in...> > Closes: https://lore.kernel.org/oe-kbuild-all/202...@in.../ > Fixes: 379b870c28c6 ("firewire: core: use helper macros instead of direct access to HZ") > Signed-off-by: Takashi Sakamoto <o-t...@sa...> > --- > drivers/firewire/core.h | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) Applied to for-next branch. Regards Takashi Sakamoto |
From: Takashi S. <o-t...@sa...> - 2025-09-24 13:18:38
|
Hi, The patchset that serialized bm_work() and fw_core_handle_bus_reset() was merged without sufficient consideration of the race condition during fw_card removal. This patchset reverts some commits and restores the acquisition of the fw_card spin lock. [1] https://lore.kernel.org/lkml/202...@sa.../ Changes from v1: * Fulfill cover-letter title Takashi Sakamoto (2): Revert "firewire: core: shrink critical section of fw_card spinlock in bm_work" Revert "firewire: core: disable bus management work temporarily during updating topology" drivers/firewire/core-card.c | 38 +++++++++++++++++++++++++------- drivers/firewire/core-topology.c | 8 ------- 2 files changed, 30 insertions(+), 16 deletions(-) base-commit: 19e73f65940d3d3357c637f3d7e19a59305a748f -- 2.48.1 |
From: Takashi S. <o-t...@sa...> - 2025-09-24 13:18:35
|
This reverts commit abe7159125702c734e851bc0c52b51cd446298a5. The bus manager work item acquires the spin lock of fw_card again, thus no need to serialize it against fw_core_handle_bus_reset(). Signed-off-by: Takashi Sakamoto <o-t...@sa...> --- drivers/firewire/core-topology.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/firewire/core-topology.c b/drivers/firewire/core-topology.c index 90b988035a2a..2f73bcd5696f 100644 --- a/drivers/firewire/core-topology.c +++ b/drivers/firewire/core-topology.c @@ -460,14 +460,8 @@ void fw_core_handle_bus_reset(struct fw_card *card, int node_id, int generation, { struct fw_node *local_node; - might_sleep(); - trace_bus_reset_handle(card->index, generation, node_id, bm_abdicate, self_ids, self_id_count); - // Disable bus management work during updating the cache of bus topology, since the work - // accesses to some members of fw_card. - disable_delayed_work_sync(&card->bm_work); - scoped_guard(spinlock, &card->lock) { // If the selfID buffer is not the immediate successor of the // previously processed one, we cannot reliably compare the @@ -501,8 +495,6 @@ void fw_core_handle_bus_reset(struct fw_card *card, int node_id, int generation, } } - enable_delayed_work(&card->bm_work); - fw_schedule_bm_work(card, 0); // Just used by transaction layer. -- 2.48.1 |
From: Takashi S. <o-t...@sa...> - 2025-09-24 13:18:35
|
This reverts commit 582310376d6e9a8d261b682178713cdc4b251af6. The bus manager work has the race condition against fw_destroy_nodes() called by fw_core_remove_card(). The acquition of spin lock of fw_card is left as is again. Signed-off-by: Takashi Sakamoto <o-t...@sa...> --- drivers/firewire/core-card.c | 38 ++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/drivers/firewire/core-card.c b/drivers/firewire/core-card.c index 4a5459696093..e5e0174a0335 100644 --- a/drivers/firewire/core-card.c +++ b/drivers/firewire/core-card.c @@ -299,6 +299,7 @@ enum bm_contention_outcome { }; static enum bm_contention_outcome contend_for_bm(struct fw_card *card) +__must_hold(&card->lock) { int generation = card->generation; int local_id = card->local_node->node_id; @@ -311,8 +312,11 @@ static enum bm_contention_outcome contend_for_bm(struct fw_card *card) bool keep_this_irm = false; struct fw_node *irm_node; struct fw_device *irm_device; + int irm_node_id; int rcode; + lockdep_assert_held(&card->lock); + if (!grace) { if (!is_next_generation(generation, card->bm_generation) || card->bm_abdicate) return BM_CONTENTION_OUTCOME_WITHIN_WINDOW; @@ -338,10 +342,16 @@ static enum bm_contention_outcome contend_for_bm(struct fw_card *card) return BM_CONTENTION_OUTCOME_IRM_COMPLIES_1394_1995_ONLY; } - rcode = fw_run_transaction(card, TCODE_LOCK_COMPARE_SWAP, irm_node->node_id, generation, + irm_node_id = irm_node->node_id; + + spin_unlock_irq(&card->lock); + + rcode = fw_run_transaction(card, TCODE_LOCK_COMPARE_SWAP, irm_node_id, generation, SCODE_100, CSR_REGISTER_BASE + CSR_BUS_MANAGER_ID, data, sizeof(data)); + spin_lock_irq(&card->lock); + switch (rcode) { case RCODE_GENERATION: return BM_CONTENTION_OUTCOME_AT_NEW_GENERATION; @@ -352,12 +362,10 @@ static enum bm_contention_outcome contend_for_bm(struct fw_card *card) int bm_id = be32_to_cpu(data[0]); // Used by cdev layer for "struct fw_cdev_event_bus_reset". - scoped_guard(spinlock, &card->lock) { - if (bm_id != BUS_MANAGER_ID_NOT_REGISTERED) - card->bm_node_id = 0xffc0 & bm_id; - else - card->bm_node_id = local_id; - } + if (bm_id != BUS_MANAGER_ID_NOT_REGISTERED) + card->bm_node_id = 0xffc0 & bm_id; + else + card->bm_node_id = local_id; if (bm_id != BUS_MANAGER_ID_NOT_REGISTERED) return BM_CONTENTION_OUTCOME_IRM_HOLDS_ANOTHER_NODE_AS_BM; @@ -389,8 +397,12 @@ static void bm_work(struct work_struct *work) int expected_gap_count, generation; bool stand_for_root = false; - if (card->local_node == NULL) + spin_lock_irq(&card->lock); + + if (card->local_node == NULL) { + spin_unlock_irq(&card->lock); return; + } generation = card->generation; @@ -405,6 +417,7 @@ static void bm_work(struct work_struct *work) switch (result) { case BM_CONTENTION_OUTCOME_WITHIN_WINDOW: + spin_unlock_irq(&card->lock); fw_schedule_bm_work(card, msecs_to_jiffies(125)); return; case BM_CONTENTION_OUTCOME_IRM_HAS_LINK_OFF: @@ -415,10 +428,12 @@ static void bm_work(struct work_struct *work) break; case BM_CONTENTION_OUTCOME_AT_NEW_GENERATION: // BM work has been rescheduled. + spin_unlock_irq(&card->lock); return; case BM_CONTENTION_OUTCOME_LOCAL_PROBLEM_AT_TRANSACTION: // Let's try again later and hope that the local problem has gone away by // then. + spin_unlock_irq(&card->lock); fw_schedule_bm_work(card, msecs_to_jiffies(125)); return; case BM_CONTENTION_OUTCOME_IRM_IS_NOT_CAPABLE_FOR_IRM: @@ -428,7 +443,9 @@ static void bm_work(struct work_struct *work) case BM_CONTENTION_OUTCOME_IRM_HOLDS_ANOTHER_NODE_AS_BM: if (local_id == irm_id) { // Only acts as IRM. + spin_unlock_irq(&card->lock); allocate_broadcast_channel(card, generation); + spin_lock_irq(&card->lock); } fallthrough; case BM_CONTENTION_OUTCOME_IRM_HOLDS_LOCAL_NODE_AS_BM: @@ -469,6 +486,7 @@ static void bm_work(struct work_struct *work) if (!root_device_is_running) { // If we haven't probed this device yet, bail out now // and let's try again once that's done. + spin_unlock_irq(&card->lock); return; } else if (!root_device->cmc) { // Current root has an active link layer and we @@ -504,6 +522,8 @@ static void bm_work(struct work_struct *work) if (card->bm_retries++ < 5 && (card->gap_count != expected_gap_count || new_root_id != root_id)) { int card_gap_count = card->gap_count; + spin_unlock_irq(&card->lock); + fw_notice(card, "phy config: new root=%x, gap_count=%d\n", new_root_id, expected_gap_count); fw_send_phy_config(card, new_root_id, generation, expected_gap_count); @@ -524,6 +544,8 @@ static void bm_work(struct work_struct *work) } else { struct fw_device *root_device = fw_node_get_device(root_node); + spin_unlock_irq(&card->lock); + if (root_device && root_device->cmc) { // Make sure that the cycle master sends cycle start packets. __be32 data = cpu_to_be32(CSR_STATE_BIT_CMSTR); -- 2.48.1 |
From: Takashi S. <o-t...@sa...> - 2025-09-24 13:11:51
|
The multiplication by USEC_PER_SEC (=1000000L) may trigger an overflow warning with 32 bit storage. In the case of the subsystem the input value ranges between 800 and 16000, thus the result always fits within 32 bit storage. This commit suppresses the warning by using widening conversion to 64 bit storage before multiplication, then using narrowing conversion to 32 bit storage. Reported-by: kernel test robot <lk...@in...> Closes: https://lore.kernel.org/oe-kbuild-all/202...@in.../ Fixes: 379b870c28c6 ("firewire: core: use helper macros instead of direct access to HZ") Signed-off-by: Takashi Sakamoto <o-t...@sa...> --- drivers/firewire/core.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/firewire/core.h b/drivers/firewire/core.h index 7f2ca93406ce..2dd715a580ac 100644 --- a/drivers/firewire/core.h +++ b/drivers/firewire/core.h @@ -30,7 +30,7 @@ struct fw_packet; // This is the arbitrary value we use to indicate a mismatched gap count. #define GAP_COUNT_MISMATCHED 0 -#define isoc_cycles_to_jiffies(cycles) usecs_to_jiffies(cycles * USEC_PER_SEC / 8000) +#define isoc_cycles_to_jiffies(cycles) usecs_to_jiffies((u32)((u64)(cycles) * USEC_PER_SEC / 8000)) extern __printf(2, 3) void fw_err(const struct fw_card *card, const char *fmt, ...); base-commit: 19e73f65940d3d3357c637f3d7e19a59305a748f -- 2.48.1 |
From: Takashi S. <o-t...@sa...> - 2025-09-24 12:42:28
|
This reverts commit 582310376d6e9a8d261b682178713cdc4b251af6. The bus manager work has the race condition against fw_destroy_nodes() called by fw_core_remove_card(). The acquisition of spin lock of fw_card is left as is again. Signed-off-by: Takashi Sakamoto <o-t...@sa...> --- drivers/firewire/core-card.c | 38 ++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/drivers/firewire/core-card.c b/drivers/firewire/core-card.c index 4a5459696093..e5e0174a0335 100644 --- a/drivers/firewire/core-card.c +++ b/drivers/firewire/core-card.c @@ -299,6 +299,7 @@ enum bm_contention_outcome { }; static enum bm_contention_outcome contend_for_bm(struct fw_card *card) +__must_hold(&card->lock) { int generation = card->generation; int local_id = card->local_node->node_id; @@ -311,8 +312,11 @@ static enum bm_contention_outcome contend_for_bm(struct fw_card *card) bool keep_this_irm = false; struct fw_node *irm_node; struct fw_device *irm_device; + int irm_node_id; int rcode; + lockdep_assert_held(&card->lock); + if (!grace) { if (!is_next_generation(generation, card->bm_generation) || card->bm_abdicate) return BM_CONTENTION_OUTCOME_WITHIN_WINDOW; @@ -338,10 +342,16 @@ static enum bm_contention_outcome contend_for_bm(struct fw_card *card) return BM_CONTENTION_OUTCOME_IRM_COMPLIES_1394_1995_ONLY; } - rcode = fw_run_transaction(card, TCODE_LOCK_COMPARE_SWAP, irm_node->node_id, generation, + irm_node_id = irm_node->node_id; + + spin_unlock_irq(&card->lock); + + rcode = fw_run_transaction(card, TCODE_LOCK_COMPARE_SWAP, irm_node_id, generation, SCODE_100, CSR_REGISTER_BASE + CSR_BUS_MANAGER_ID, data, sizeof(data)); + spin_lock_irq(&card->lock); + switch (rcode) { case RCODE_GENERATION: return BM_CONTENTION_OUTCOME_AT_NEW_GENERATION; @@ -352,12 +362,10 @@ static enum bm_contention_outcome contend_for_bm(struct fw_card *card) int bm_id = be32_to_cpu(data[0]); // Used by cdev layer for "struct fw_cdev_event_bus_reset". - scoped_guard(spinlock, &card->lock) { - if (bm_id != BUS_MANAGER_ID_NOT_REGISTERED) - card->bm_node_id = 0xffc0 & bm_id; - else - card->bm_node_id = local_id; - } + if (bm_id != BUS_MANAGER_ID_NOT_REGISTERED) + card->bm_node_id = 0xffc0 & bm_id; + else + card->bm_node_id = local_id; if (bm_id != BUS_MANAGER_ID_NOT_REGISTERED) return BM_CONTENTION_OUTCOME_IRM_HOLDS_ANOTHER_NODE_AS_BM; @@ -389,8 +397,12 @@ static void bm_work(struct work_struct *work) int expected_gap_count, generation; bool stand_for_root = false; - if (card->local_node == NULL) + spin_lock_irq(&card->lock); + + if (card->local_node == NULL) { + spin_unlock_irq(&card->lock); return; + } generation = card->generation; @@ -405,6 +417,7 @@ static void bm_work(struct work_struct *work) switch (result) { case BM_CONTENTION_OUTCOME_WITHIN_WINDOW: + spin_unlock_irq(&card->lock); fw_schedule_bm_work(card, msecs_to_jiffies(125)); return; case BM_CONTENTION_OUTCOME_IRM_HAS_LINK_OFF: @@ -415,10 +428,12 @@ static void bm_work(struct work_struct *work) break; case BM_CONTENTION_OUTCOME_AT_NEW_GENERATION: // BM work has been rescheduled. + spin_unlock_irq(&card->lock); return; case BM_CONTENTION_OUTCOME_LOCAL_PROBLEM_AT_TRANSACTION: // Let's try again later and hope that the local problem has gone away by // then. + spin_unlock_irq(&card->lock); fw_schedule_bm_work(card, msecs_to_jiffies(125)); return; case BM_CONTENTION_OUTCOME_IRM_IS_NOT_CAPABLE_FOR_IRM: @@ -428,7 +443,9 @@ static void bm_work(struct work_struct *work) case BM_CONTENTION_OUTCOME_IRM_HOLDS_ANOTHER_NODE_AS_BM: if (local_id == irm_id) { // Only acts as IRM. + spin_unlock_irq(&card->lock); allocate_broadcast_channel(card, generation); + spin_lock_irq(&card->lock); } fallthrough; case BM_CONTENTION_OUTCOME_IRM_HOLDS_LOCAL_NODE_AS_BM: @@ -469,6 +486,7 @@ static void bm_work(struct work_struct *work) if (!root_device_is_running) { // If we haven't probed this device yet, bail out now // and let's try again once that's done. + spin_unlock_irq(&card->lock); return; } else if (!root_device->cmc) { // Current root has an active link layer and we @@ -504,6 +522,8 @@ static void bm_work(struct work_struct *work) if (card->bm_retries++ < 5 && (card->gap_count != expected_gap_count || new_root_id != root_id)) { int card_gap_count = card->gap_count; + spin_unlock_irq(&card->lock); + fw_notice(card, "phy config: new root=%x, gap_count=%d\n", new_root_id, expected_gap_count); fw_send_phy_config(card, new_root_id, generation, expected_gap_count); @@ -524,6 +544,8 @@ static void bm_work(struct work_struct *work) } else { struct fw_device *root_device = fw_node_get_device(root_node); + spin_unlock_irq(&card->lock); + if (root_device && root_device->cmc) { // Make sure that the cycle master sends cycle start packets. __be32 data = cpu_to_be32(CSR_STATE_BIT_CMSTR); -- 2.48.1 |
From: Takashi S. <o-t...@sa...> - 2025-09-24 12:42:27
|
Hi, The patchset that serialized bm_work() and fw_core_handle_bus_reset() was merged without sufficient consideration of the race condition during fw_card removal. This patchset reverts some commits and restores the acquisition of the fw_card spin lock. [1] https://lore.kernel.org/lkml/202...@sa.../ Takashi Sakamoto (2): Revert "firewire: core: shrink critical section of fw_card spinlock in bm_work" Revert "firewire: core: disable bus management work temporarily during updating topology" drivers/firewire/core-card.c | 38 +++++++++++++++++++++++++------- drivers/firewire/core-topology.c | 8 ------- 2 files changed, 30 insertions(+), 16 deletions(-) base-commit: 19e73f65940d3d3357c637f3d7e19a59305a748f -- 2.48.1 |
From: Takashi S. <o-t...@sa...> - 2025-09-24 12:42:26
|
This reverts commit abe7159125702c734e851bc0c52b51cd446298a5. The bus manager work item acquires the spin lock of fw_card again, thus no need to serialize it against fw_core_handle_bus_reset(). Signed-off-by: Takashi Sakamoto <o-t...@sa...> --- drivers/firewire/core-topology.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/firewire/core-topology.c b/drivers/firewire/core-topology.c index 90b988035a2a..2f73bcd5696f 100644 --- a/drivers/firewire/core-topology.c +++ b/drivers/firewire/core-topology.c @@ -460,14 +460,8 @@ void fw_core_handle_bus_reset(struct fw_card *card, int node_id, int generation, { struct fw_node *local_node; - might_sleep(); - trace_bus_reset_handle(card->index, generation, node_id, bm_abdicate, self_ids, self_id_count); - // Disable bus management work during updating the cache of bus topology, since the work - // accesses to some members of fw_card. - disable_delayed_work_sync(&card->bm_work); - scoped_guard(spinlock, &card->lock) { // If the selfID buffer is not the immediate successor of the // previously processed one, we cannot reliably compare the @@ -501,8 +495,6 @@ void fw_core_handle_bus_reset(struct fw_card *card, int node_id, int generation, } } - enable_delayed_work(&card->bm_work); - fw_schedule_bm_work(card, 0); // Just used by transaction layer. -- 2.48.1 |
From: Takashi S. <o-t...@sa...> - 2025-09-21 01:23:09
|
Hi Linus, Please accept a single patch from FireWire subsystem to your tree. It includes a fix to enable userspace applications to recognize the functions added in v6.5 kernel as available. This change should also be applied to existing stable and longterm releases. The following changes since commit f83ec76bf285bea5727f478a68b894f5543ca76e: Linux 6.17-rc6 (2025-09-14 14:21:14 -0700) are available in the Git repository at: git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394.git tags/firewire-fixes-6.17-rc7 for you to fetch changes up to 853a57ba263adfecf4430b936d6862bc475b4bb5: firewire: core: fix overlooked update of subsystem ABI version (2025-09-20 12:17:50 +0900) ---------------------------------------------------------------- firewire fixes for v6.17-rc7 When new structures and events were added to UAPI in v6.5 kernel, the required update to the subsystem ABI version returned to userspace client was overlooked. The version is now updated. ---------------------------------------------------------------- Takashi Sakamoto (1): firewire: core: fix overlooked update of subsystem ABI version drivers/firewire/core-cdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) Thanks Takashi Sakamoto |
From: Takashi S. <o-t...@sa...> - 2025-09-21 01:01:50
|
On Sat, Sep 20, 2025 at 11:51:48AM +0900, Takashi Sakamoto wrote: > In kernel v6.5, several functions were added to the cdev layer. This > required updating the default version of subsystem ABI up to 6, but > this requirement was overlooked. > > This commit updates the version accordingly. > > Fixes: 6add87e9764d ("firewire: cdev: add new version of ABI to notify time stamp at request/response subaction of transaction#") > Signed-off-by: Takashi Sakamoto <o-t...@sa...> > --- > drivers/firewire/core-cdev.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c > index 78b10c6ef7fe..2e93189d7142 100644 > --- a/drivers/firewire/core-cdev.c > +++ b/drivers/firewire/core-cdev.c > @@ -41,7 +41,7 @@ > /* > * ABI version history is documented in linux/firewire-cdev.h. > */ > -#define FW_CDEV_KERNEL_VERSION 5 > +#define FW_CDEV_KERNEL_VERSION 6 > #define FW_CDEV_VERSION_EVENT_REQUEST2 4 > #define FW_CDEV_VERSION_ALLOCATE_REGION_END 4 > #define FW_CDEV_VERSION_AUTO_FLUSH_ISO_OVERFLOW 5 Applied to for-linus branch. Regards Takashi Sakamoto |
From: Takashi S. <o-t...@sa...> - 2025-09-20 02:52:03
|
In kernel v6.5, several functions were added to the cdev layer. This required updating the default version of subsystem ABI up to 6, but this requirement was overlooked. This commit updates the version accordingly. Fixes: 6add87e9764d ("firewire: cdev: add new version of ABI to notify time stamp at request/response subaction of transaction#") Signed-off-by: Takashi Sakamoto <o-t...@sa...> --- drivers/firewire/core-cdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c index 78b10c6ef7fe..2e93189d7142 100644 --- a/drivers/firewire/core-cdev.c +++ b/drivers/firewire/core-cdev.c @@ -41,7 +41,7 @@ /* * ABI version history is documented in linux/firewire-cdev.h. */ -#define FW_CDEV_KERNEL_VERSION 5 +#define FW_CDEV_KERNEL_VERSION 6 #define FW_CDEV_VERSION_EVENT_REQUEST2 4 #define FW_CDEV_VERSION_ALLOCATE_REGION_END 4 #define FW_CDEV_VERSION_AUTO_FLUSH_ISO_OVERFLOW 5 base-commit: f83ec76bf285bea5727f478a68b894f5543ca76e -- 2.48.1 |
From: Takashi S. <o-t...@sa...> - 2025-09-20 01:54:28
|
On Fri, Sep 19, 2025 at 08:54:42AM +0900, Takashi Sakamoto wrote: > Hi, > > This patchset is the revised version of my previous one: > https://lore.kernel.org/lkml/202...@sa.../ > > Changes from v1: > * Ensure to initialize local variable > > Takashi Sakamoto (6): > firewire: core: remove useless generation check > firewire: core: use switch statement to evaluate transaction result to > CSR_BUS_MANAGER_ID > firewire: core: code refactoring for the case of generation mismatch > firewire: core: code refactoring to split contention procedure for bus > manager > firewire: core; eliminate pick_me goto label > firewire: core: minor code refactoring to delete useless local > variable > > drivers/firewire/core-card.c | 335 ++++++++++++++++++----------------- > 1 file changed, 177 insertions(+), 158 deletions(-) Applied to for-next branch. Regards Takashi Sakamoto |
From: Takashi S. <o-t...@sa...> - 2025-09-18 23:55:12
|
The do_reset local variable has less merit. Let's remove it. Signed-off-by: Takashi Sakamoto <o-t...@sa...> --- drivers/firewire/core-card.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/drivers/firewire/core-card.c b/drivers/firewire/core-card.c index 58d1f58a4a0f..4a5459696093 100644 --- a/drivers/firewire/core-card.c +++ b/drivers/firewire/core-card.c @@ -387,7 +387,6 @@ static void bm_work(struct work_struct *work) struct fw_node *root_node __free(node_unref) = NULL; int root_id, new_root_id, irm_id, local_id; int expected_gap_count, generation; - bool do_reset = false; bool stand_for_root = false; if (card->local_node == NULL) @@ -499,16 +498,10 @@ static void bm_work(struct work_struct *work) else expected_gap_count = 63; - /* - * Finally, figure out if we should do a reset or not. If we have - * done less than 5 resets with the same physical topology and we - * have either a new root or a new gap count setting, let's do it. - */ - - if (card->bm_retries++ < 5 && (card->gap_count != expected_gap_count || new_root_id != root_id)) - do_reset = true; - - if (do_reset) { + // Finally, figure out if we should do a reset or not. If we have done less than 5 resets + // with the same physical topology and we have either a new root or a new gap count + // setting, let's do it. + if (card->bm_retries++ < 5 && (card->gap_count != expected_gap_count || new_root_id != root_id)) { int card_gap_count = card->gap_count; fw_notice(card, "phy config: new root=%x, gap_count=%d\n", -- 2.48.1 |
From: Takashi S. <o-t...@sa...> - 2025-09-18 23:55:09
|
The precedure to contend for bus manager has much code. It is better to split it into a helper function. This commit refactors in the point. Signed-off-by: Takashi Sakamoto <o-t...@sa...> --- drivers/firewire/core-card.c | 223 ++++++++++++++++++++--------------- 1 file changed, 127 insertions(+), 96 deletions(-) diff --git a/drivers/firewire/core-card.c b/drivers/firewire/core-card.c index 02058af705cc..6268b595d4fa 100644 --- a/drivers/firewire/core-card.c +++ b/drivers/firewire/core-card.c @@ -279,6 +279,102 @@ void fw_schedule_bm_work(struct fw_card *card, unsigned long delay) fw_card_put(card); } +enum bm_contention_outcome { + // The bus management contention window is not expired. + BM_CONTENTION_OUTCOME_WITHIN_WINDOW = 0, + // The IRM node has link off. + BM_CONTENTION_OUTCOME_IRM_HAS_LINK_OFF, + // The IRM node complies IEEE 1394:1994 only. + BM_CONTENTION_OUTCOME_IRM_COMPLIES_1394_1995_ONLY, + // Another bus reset, BM work has been rescheduled. + BM_CONTENTION_OUTCOME_AT_NEW_GENERATION, + // We have been unable to send the lock request to IRM node due to some local problem. + BM_CONTENTION_OUTCOME_LOCAL_PROBLEM_AT_TRANSACTION, + // The lock request failed, maybe the IRM isn't really IRM capable after all. + BM_CONTENTION_OUTCOME_IRM_IS_NOT_CAPABLE_FOR_IRM, + // Somebody else is BM. + BM_CONTENTION_OUTCOME_IRM_HOLDS_ANOTHER_NODE_AS_BM, + // The local node succeeds after contending for bus manager. + BM_CONTENTION_OUTCOME_IRM_HOLDS_LOCAL_NODE_AS_BM, +}; + +static enum bm_contention_outcome contend_for_bm(struct fw_card *card) +{ + int generation = card->generation; + int local_id = card->local_node->node_id; + __be32 data[2] = { + cpu_to_be32(BUS_MANAGER_ID_NOT_REGISTERED), + cpu_to_be32(local_id), + }; + bool grace = time_is_before_jiffies64(card->reset_jiffies + msecs_to_jiffies(125)); + bool irm_is_1394_1995_only = false; + bool keep_this_irm = false; + struct fw_node *irm_node; + struct fw_device *irm_device; + int rcode; + + if (!grace) { + if (!is_next_generation(generation, card->bm_generation) || card->bm_abdicate) + return BM_CONTENTION_OUTCOME_WITHIN_WINDOW; + } + + irm_node = card->irm_node; + if (!irm_node->link_on) { + fw_notice(card, "IRM has link off, making local node (%02x) root\n", local_id); + return BM_CONTENTION_OUTCOME_IRM_HAS_LINK_OFF; + } + + irm_device = fw_node_get_device(irm_node); + if (irm_device && irm_device->config_rom) { + irm_is_1394_1995_only = (irm_device->config_rom[2] & 0x000000f0) == 0; + + // Canon MV5i works unreliably if it is not root node. + keep_this_irm = irm_device->config_rom[3] >> 8 == CANON_OUI; + } + + if (irm_is_1394_1995_only && !keep_this_irm) { + fw_notice(card, "IRM is not 1394a compliant, making local node (%02x) root\n", + local_id); + return BM_CONTENTION_OUTCOME_IRM_COMPLIES_1394_1995_ONLY; + } + + rcode = fw_run_transaction(card, TCODE_LOCK_COMPARE_SWAP, irm_node->node_id, generation, + SCODE_100, CSR_REGISTER_BASE + CSR_BUS_MANAGER_ID, data, + sizeof(data)); + + switch (rcode) { + case RCODE_GENERATION: + return BM_CONTENTION_OUTCOME_AT_NEW_GENERATION; + case RCODE_SEND_ERROR: + return BM_CONTENTION_OUTCOME_LOCAL_PROBLEM_AT_TRANSACTION; + case RCODE_COMPLETE: + { + int bm_id = be32_to_cpu(data[0]); + + // Used by cdev layer for "struct fw_cdev_event_bus_reset". + scoped_guard(spinlock, &card->lock) { + if (bm_id != BUS_MANAGER_ID_NOT_REGISTERED) + card->bm_node_id = 0xffc0 & bm_id; + else + card->bm_node_id = local_id; + } + + if (bm_id != BUS_MANAGER_ID_NOT_REGISTERED) + return BM_CONTENTION_OUTCOME_IRM_HOLDS_ANOTHER_NODE_AS_BM; + else + return BM_CONTENTION_OUTCOME_IRM_HOLDS_LOCAL_NODE_AS_BM; + } + default: + if (!keep_this_irm) { + fw_notice(card, "BM lock failed (%s), making local node (%02x) root\n", + fw_rcode_string(rcode), local_id); + return BM_CONTENTION_OUTCOME_IRM_COMPLIES_1394_1995_ONLY; + } else { + return BM_CONTENTION_OUTCOME_IRM_IS_NOT_CAPABLE_FOR_IRM; + } + } +} + DEFINE_FREE(node_unref, struct fw_node *, if (_T) fw_node_put(_T)) DEFINE_FREE(card_unref, struct fw_card *, if (_T) fw_card_put(_T)) @@ -305,105 +401,40 @@ static void bm_work(struct work_struct *work) local_id = card->local_node->node_id; if (card->bm_generation != generation) { - bool grace = time_is_before_jiffies64(card->reset_jiffies + msecs_to_jiffies(125)); - - if (grace || - (is_next_generation(generation, card->bm_generation) && !card->bm_abdicate)) { - // This first step is to figure out who is IRM and - // then try to become bus manager. If the IRM is not - // well defined (e.g. does not have an active link - // layer or does not responds to our lock request, we - // will have to do a little vigilante bus management. - // In that case, we do a goto into the gap count logic - // so that when we do the reset, we still optimize the - // gap count. That could well save a reset in the - // next generation. - __be32 data[2] = { - cpu_to_be32(BUS_MANAGER_ID_NOT_REGISTERED), - cpu_to_be32(local_id), - }; - struct fw_device *irm_device = fw_node_get_device(card->irm_node); - bool irm_is_1394_1995_only = false; - bool keep_this_irm = false; - int rcode; - - if (!card->irm_node->link_on) { - new_root_id = local_id; - fw_notice(card, "%s, making local node (%02x) root\n", - "IRM has link off", new_root_id); - goto pick_me; - } + enum bm_contention_outcome result = contend_for_bm(card); - if (irm_device && irm_device->config_rom) { - irm_is_1394_1995_only = (irm_device->config_rom[2] & 0x000000f0) == 0; - - // Canon MV5i works unreliably if it is not root node. - keep_this_irm = irm_device->config_rom[3] >> 8 == CANON_OUI; - } - - if (irm_is_1394_1995_only && !keep_this_irm) { - new_root_id = local_id; - fw_notice(card, "%s, making local node (%02x) root\n", - "IRM is not 1394a compliant", new_root_id); - goto pick_me; - } - - rcode = fw_run_transaction(card, TCODE_LOCK_COMPARE_SWAP, - irm_id, generation, SCODE_100, - CSR_REGISTER_BASE + CSR_BUS_MANAGER_ID, - data, sizeof(data)); - - switch (rcode) { - case RCODE_GENERATION: - // Another bus reset, BM work has been rescheduled. - return; - case RCODE_SEND_ERROR: - // We have been unable to send the lock request due to - // some local problem. Let's try again later and hope - // that the problem has gone away by then. - fw_schedule_bm_work(card, msecs_to_jiffies(125)); - return; - case RCODE_COMPLETE: - { - int bm_id = be32_to_cpu(data[0]); - - // Used by cdev layer for "struct fw_cdev_event_bus_reset". - scoped_guard(spinlock, &card->lock) { - if (bm_id != BUS_MANAGER_ID_NOT_REGISTERED) - card->bm_node_id = 0xffc0 & bm_id; - else - card->bm_node_id = local_id; - } - - if (bm_id != BUS_MANAGER_ID_NOT_REGISTERED) { - // Somebody else is BM. Only act as IRM. - if (local_id == irm_id) - allocate_broadcast_channel(card, generation); - return; - } - break; - } - default: - if (!keep_this_irm) { - // The lock request failed, maybe the IRM - // isn't really IRM capable after all. Let's - // do a bus reset and pick the local node as - // root, and thus, IRM. - new_root_id = local_id; - fw_notice(card, "BM lock failed (%s), making local node (%02x) root\n", - fw_rcode_string(rcode), new_root_id); - goto pick_me; - } - break; - } - - // A node contends for bus manager in this generation. - card->bm_generation = generation; - } else { - // We weren't BM in the last generation, and the last - // bus reset is less than 125ms ago. Reschedule this job. + switch (result) { + case BM_CONTENTION_OUTCOME_WITHIN_WINDOW: fw_schedule_bm_work(card, msecs_to_jiffies(125)); return; + case BM_CONTENTION_OUTCOME_IRM_HAS_LINK_OFF: + new_root_id = local_id; + goto pick_me; + case BM_CONTENTION_OUTCOME_IRM_COMPLIES_1394_1995_ONLY: + new_root_id = local_id; + goto pick_me; + case BM_CONTENTION_OUTCOME_AT_NEW_GENERATION: + // BM work has been rescheduled. + return; + case BM_CONTENTION_OUTCOME_LOCAL_PROBLEM_AT_TRANSACTION: + // Let's try again later and hope that the local problem has gone away by + // then. + fw_schedule_bm_work(card, msecs_to_jiffies(125)); + return; + case BM_CONTENTION_OUTCOME_IRM_IS_NOT_CAPABLE_FOR_IRM: + // Let's do a bus reset and pick the local node as root, and thus, IRM. + new_root_id = local_id; + goto pick_me; + case BM_CONTENTION_OUTCOME_IRM_HOLDS_ANOTHER_NODE_AS_BM: + if (local_id == irm_id) { + // Only acts as IRM. + allocate_broadcast_channel(card, generation); + } + fallthrough; + case BM_CONTENTION_OUTCOME_IRM_HOLDS_LOCAL_NODE_AS_BM: + default: + card->bm_generation = generation; + break; } } -- 2.48.1 |
From: Takashi S. <o-t...@sa...> - 2025-09-18 23:55:08
|
Current implementation stores the bus generation at which the bus manager contending procedure finishes. The condition for the procedure is the mismatch of the stored generation against current bus generation. This commit refactors the code for the contending procedure. Two existing branches are put into a new branch to detect the generation mismatch, thus the most of change is indentation. Signed-off-by: Takashi Sakamoto <o-t...@sa...> --- drivers/firewire/core-card.c | 188 +++++++++++++++++------------------ 1 file changed, 93 insertions(+), 95 deletions(-) diff --git a/drivers/firewire/core-card.c b/drivers/firewire/core-card.c index e9bf8d93f5b7..02058af705cc 100644 --- a/drivers/firewire/core-card.c +++ b/drivers/firewire/core-card.c @@ -290,7 +290,7 @@ static void bm_work(struct work_struct *work) struct fw_card *card __free(card_unref) = from_work(card, work, bm_work.work); struct fw_node *root_node __free(node_unref) = NULL; int root_id, new_root_id, irm_id, local_id; - int expected_gap_count, generation, grace; + int expected_gap_count, generation; bool do_reset = false; if (card->local_node == NULL) @@ -304,107 +304,107 @@ static void bm_work(struct work_struct *work) irm_id = card->irm_node->node_id; local_id = card->local_node->node_id; - grace = time_is_before_jiffies64(card->reset_jiffies + msecs_to_jiffies(125)); - - if ((is_next_generation(generation, card->bm_generation) && - !card->bm_abdicate) || - (card->bm_generation != generation && grace)) { - /* - * This first step is to figure out who is IRM and - * then try to become bus manager. If the IRM is not - * well defined (e.g. does not have an active link - * layer or does not responds to our lock request, we - * will have to do a little vigilante bus management. - * In that case, we do a goto into the gap count logic - * so that when we do the reset, we still optimize the - * gap count. That could well save a reset in the - * next generation. - */ - __be32 data[2] = { - cpu_to_be32(BUS_MANAGER_ID_NOT_REGISTERED), - cpu_to_be32(local_id), - }; - struct fw_device *irm_device = fw_node_get_device(card->irm_node); - bool irm_is_1394_1995_only = false; - bool keep_this_irm = false; - int rcode; - - if (!card->irm_node->link_on) { - new_root_id = local_id; - fw_notice(card, "%s, making local node (%02x) root\n", - "IRM has link off", new_root_id); - goto pick_me; - } - - if (irm_device && irm_device->config_rom) { - irm_is_1394_1995_only = (irm_device->config_rom[2] & 0x000000f0) == 0; - - // Canon MV5i works unreliably if it is not root node. - keep_this_irm = irm_device->config_rom[3] >> 8 == CANON_OUI; - } + if (card->bm_generation != generation) { + bool grace = time_is_before_jiffies64(card->reset_jiffies + msecs_to_jiffies(125)); + + if (grace || + (is_next_generation(generation, card->bm_generation) && !card->bm_abdicate)) { + // This first step is to figure out who is IRM and + // then try to become bus manager. If the IRM is not + // well defined (e.g. does not have an active link + // layer or does not responds to our lock request, we + // will have to do a little vigilante bus management. + // In that case, we do a goto into the gap count logic + // so that when we do the reset, we still optimize the + // gap count. That could well save a reset in the + // next generation. + __be32 data[2] = { + cpu_to_be32(BUS_MANAGER_ID_NOT_REGISTERED), + cpu_to_be32(local_id), + }; + struct fw_device *irm_device = fw_node_get_device(card->irm_node); + bool irm_is_1394_1995_only = false; + bool keep_this_irm = false; + int rcode; + + if (!card->irm_node->link_on) { + new_root_id = local_id; + fw_notice(card, "%s, making local node (%02x) root\n", + "IRM has link off", new_root_id); + goto pick_me; + } - if (irm_is_1394_1995_only && !keep_this_irm) { - new_root_id = local_id; - fw_notice(card, "%s, making local node (%02x) root\n", - "IRM is not 1394a compliant", new_root_id); - goto pick_me; - } + if (irm_device && irm_device->config_rom) { + irm_is_1394_1995_only = (irm_device->config_rom[2] & 0x000000f0) == 0; - rcode = fw_run_transaction(card, TCODE_LOCK_COMPARE_SWAP, - irm_id, generation, SCODE_100, - CSR_REGISTER_BASE + CSR_BUS_MANAGER_ID, - data, sizeof(data)); + // Canon MV5i works unreliably if it is not root node. + keep_this_irm = irm_device->config_rom[3] >> 8 == CANON_OUI; + } - switch (rcode) { - case RCODE_GENERATION: - // Another bus reset, BM work has been rescheduled. - return; - case RCODE_SEND_ERROR: - // We have been unable to send the lock request due to - // some local problem. Let's try again later and hope - // that the problem has gone away by then. - fw_schedule_bm_work(card, msecs_to_jiffies(125)); - return; - case RCODE_COMPLETE: - { - int bm_id = be32_to_cpu(data[0]); - - // Used by cdev layer for "struct fw_cdev_event_bus_reset". - scoped_guard(spinlock, &card->lock) { - if (bm_id != BUS_MANAGER_ID_NOT_REGISTERED) - card->bm_node_id = 0xffc0 & bm_id; - else - card->bm_node_id = local_id; + if (irm_is_1394_1995_only && !keep_this_irm) { + new_root_id = local_id; + fw_notice(card, "%s, making local node (%02x) root\n", + "IRM is not 1394a compliant", new_root_id); + goto pick_me; } - if (bm_id != BUS_MANAGER_ID_NOT_REGISTERED) { - // Somebody else is BM. Only act as IRM. - if (local_id == irm_id) - allocate_broadcast_channel(card, generation); + rcode = fw_run_transaction(card, TCODE_LOCK_COMPARE_SWAP, + irm_id, generation, SCODE_100, + CSR_REGISTER_BASE + CSR_BUS_MANAGER_ID, + data, sizeof(data)); + + switch (rcode) { + case RCODE_GENERATION: + // Another bus reset, BM work has been rescheduled. return; + case RCODE_SEND_ERROR: + // We have been unable to send the lock request due to + // some local problem. Let's try again later and hope + // that the problem has gone away by then. + fw_schedule_bm_work(card, msecs_to_jiffies(125)); + return; + case RCODE_COMPLETE: + { + int bm_id = be32_to_cpu(data[0]); + + // Used by cdev layer for "struct fw_cdev_event_bus_reset". + scoped_guard(spinlock, &card->lock) { + if (bm_id != BUS_MANAGER_ID_NOT_REGISTERED) + card->bm_node_id = 0xffc0 & bm_id; + else + card->bm_node_id = local_id; + } + + if (bm_id != BUS_MANAGER_ID_NOT_REGISTERED) { + // Somebody else is BM. Only act as IRM. + if (local_id == irm_id) + allocate_broadcast_channel(card, generation); + return; + } + break; } - break; - } - default: - if (!keep_this_irm) { - // The lock request failed, maybe the IRM - // isn't really IRM capable after all. Let's - // do a bus reset and pick the local node as - // root, and thus, IRM. - new_root_id = local_id; - fw_notice(card, "BM lock failed (%s), making local node (%02x) root\n", - fw_rcode_string(rcode), new_root_id); - goto pick_me; + default: + if (!keep_this_irm) { + // The lock request failed, maybe the IRM + // isn't really IRM capable after all. Let's + // do a bus reset and pick the local node as + // root, and thus, IRM. + new_root_id = local_id; + fw_notice(card, "BM lock failed (%s), making local node (%02x) root\n", + fw_rcode_string(rcode), new_root_id); + goto pick_me; + } + break; } - break; + + // A node contends for bus manager in this generation. + card->bm_generation = generation; + } else { + // We weren't BM in the last generation, and the last + // bus reset is less than 125ms ago. Reschedule this job. + fw_schedule_bm_work(card, msecs_to_jiffies(125)); + return; } - } else if (card->bm_generation != generation) { - /* - * We weren't BM in the last generation, and the last - * bus reset is less than 125ms ago. Reschedule this job. - */ - fw_schedule_bm_work(card, msecs_to_jiffies(125)); - return; } /* @@ -412,8 +412,6 @@ static void bm_work(struct work_struct *work) * make sure we have an active cycle master and do gap count * optimization. */ - card->bm_generation = generation; - if (card->gap_count == GAP_COUNT_MISMATCHED) { /* * If self IDs have inconsistent gap counts, do a -- 2.48.1 |
From: Takashi S. <o-t...@sa...> - 2025-09-18 23:55:06
|
This commit uses condition statements instead of pick_me goto label. Signed-off-by: Takashi Sakamoto <o-t...@sa...> --- drivers/firewire/core-card.c | 101 ++++++++++++++++++----------------- 1 file changed, 51 insertions(+), 50 deletions(-) diff --git a/drivers/firewire/core-card.c b/drivers/firewire/core-card.c index 6268b595d4fa..58d1f58a4a0f 100644 --- a/drivers/firewire/core-card.c +++ b/drivers/firewire/core-card.c @@ -388,6 +388,7 @@ static void bm_work(struct work_struct *work) int root_id, new_root_id, irm_id, local_id; int expected_gap_count, generation; bool do_reset = false; + bool stand_for_root = false; if (card->local_node == NULL) return; @@ -408,11 +409,11 @@ static void bm_work(struct work_struct *work) fw_schedule_bm_work(card, msecs_to_jiffies(125)); return; case BM_CONTENTION_OUTCOME_IRM_HAS_LINK_OFF: - new_root_id = local_id; - goto pick_me; + stand_for_root = true; + break; case BM_CONTENTION_OUTCOME_IRM_COMPLIES_1394_1995_ONLY: - new_root_id = local_id; - goto pick_me; + stand_for_root = true; + break; case BM_CONTENTION_OUTCOME_AT_NEW_GENERATION: // BM work has been rescheduled. return; @@ -423,8 +424,8 @@ static void bm_work(struct work_struct *work) return; case BM_CONTENTION_OUTCOME_IRM_IS_NOT_CAPABLE_FOR_IRM: // Let's do a bus reset and pick the local node as root, and thus, IRM. - new_root_id = local_id; - goto pick_me; + stand_for_root = true; + break; case BM_CONTENTION_OUTCOME_IRM_HOLDS_ANOTHER_NODE_AS_BM: if (local_id == irm_id) { // Only acts as IRM. @@ -438,56 +439,56 @@ static void bm_work(struct work_struct *work) } } - /* - * We're bus manager for this generation, so next step is to - * make sure we have an active cycle master and do gap count - * optimization. - */ - if (card->gap_count == GAP_COUNT_MISMATCHED) { - /* - * If self IDs have inconsistent gap counts, do a - * bus reset ASAP. The config rom read might never - * complete, so don't wait for it. However, still - * send a PHY configuration packet prior to the - * bus reset. The PHY configuration packet might - * fail, but 1394-2008 8.4.5.2 explicitly permits - * it in this case, so it should be safe to try. - */ - new_root_id = local_id; - /* - * We must always send a bus reset if the gap count - * is inconsistent, so bypass the 5-reset limit. - */ - card->bm_retries = 0; - } else { - // Now investigate root node. - struct fw_device *root_device = fw_node_get_device(root_node); - - if (root_device == NULL) { - // Either link_on is false, or we failed to read the - // config rom. In either case, pick another root. - new_root_id = local_id; + // We're bus manager for this generation, so next step is to make sure we have an active + // cycle master and do gap count optimization. + if (!stand_for_root) { + if (card->gap_count == GAP_COUNT_MISMATCHED) { + // If self IDs have inconsistent gap counts, do a + // bus reset ASAP. The config rom read might never + // complete, so don't wait for it. However, still + // send a PHY configuration packet prior to the + // bus reset. The PHY configuration packet might + // fail, but 1394-2008 8.4.5.2 explicitly permits + // it in this case, so it should be safe to try. + stand_for_root = true; + + // We must always send a bus reset if the gap count + // is inconsistent, so bypass the 5-reset limit. + card->bm_retries = 0; } else { - bool root_device_is_running = - atomic_read(&root_device->state) == FW_DEVICE_RUNNING; + // Now investigate root node. + struct fw_device *root_device = fw_node_get_device(root_node); - if (!root_device_is_running) { - // If we haven't probed this device yet, bail out now - // and let's try again once that's done. - return; - } else if (root_device->cmc) { - // We will send out a force root packet for this - // node as part of the gap count optimization. - new_root_id = root_id; + if (root_device == NULL) { + // Either link_on is false, or we failed to read the + // config rom. In either case, pick another root. + stand_for_root = true; } else { - // Current root has an active link layer and we - // successfully read the config rom, but it's not - // cycle master capable. - new_root_id = local_id; + bool root_device_is_running = + atomic_read(&root_device->state) == FW_DEVICE_RUNNING; + + if (!root_device_is_running) { + // If we haven't probed this device yet, bail out now + // and let's try again once that's done. + return; + } else if (!root_device->cmc) { + // Current root has an active link layer and we + // successfully read the config rom, but it's not + // cycle master capable. + stand_for_root = true; + } } } } - pick_me: + + if (stand_for_root) { + new_root_id = local_id; + } else { + // We will send out a force root packet for this node as part of the gap count + // optimization on behalf of the node. + new_root_id = root_id; + } + /* * Pick a gap count from 1394a table E-1. The table doesn't cover * the typically much larger 1394b beta repeater delays though. -- 2.48.1 |
From: Takashi S. <o-t...@sa...> - 2025-09-18 23:55:01
|
The result of the lock transaction to swap bus manager on isochronous resource manager looks like an ad-hoc style. It is hard to read. This commit uses switch statement to evaluate the result. Signed-off-by: Takashi Sakamoto <o-t...@sa...> --- drivers/firewire/core-card.c | 50 +++++++++++++++++------------------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/drivers/firewire/core-card.c b/drivers/firewire/core-card.c index ef00125fb01a..e9bf8d93f5b7 100644 --- a/drivers/firewire/core-card.c +++ b/drivers/firewire/core-card.c @@ -355,11 +355,18 @@ static void bm_work(struct work_struct *work) CSR_REGISTER_BASE + CSR_BUS_MANAGER_ID, data, sizeof(data)); - // Another bus reset, BM work has been rescheduled. - if (rcode == RCODE_GENERATION) + switch (rcode) { + case RCODE_GENERATION: + // Another bus reset, BM work has been rescheduled. return; - - if (rcode == RCODE_COMPLETE) { + case RCODE_SEND_ERROR: + // We have been unable to send the lock request due to + // some local problem. Let's try again later and hope + // that the problem has gone away by then. + fw_schedule_bm_work(card, msecs_to_jiffies(125)); + return; + case RCODE_COMPLETE: + { int bm_id = be32_to_cpu(data[0]); // Used by cdev layer for "struct fw_cdev_event_bus_reset". @@ -376,29 +383,20 @@ static void bm_work(struct work_struct *work) allocate_broadcast_channel(card, generation); return; } + break; } - - if (rcode == RCODE_SEND_ERROR) { - /* - * We have been unable to send the lock request due to - * some local problem. Let's try again later and hope - * that the problem has gone away by then. - */ - fw_schedule_bm_work(card, msecs_to_jiffies(125)); - return; - } - - if (rcode != RCODE_COMPLETE && !keep_this_irm) { - /* - * The lock request failed, maybe the IRM - * isn't really IRM capable after all. Let's - * do a bus reset and pick the local node as - * root, and thus, IRM. - */ - new_root_id = local_id; - fw_notice(card, "BM lock failed (%s), making local node (%02x) root\n", - fw_rcode_string(rcode), new_root_id); - goto pick_me; + default: + if (!keep_this_irm) { + // The lock request failed, maybe the IRM + // isn't really IRM capable after all. Let's + // do a bus reset and pick the local node as + // root, and thus, IRM. + new_root_id = local_id; + fw_notice(card, "BM lock failed (%s), making local node (%02x) root\n", + fw_rcode_string(rcode), new_root_id); + goto pick_me; + } + break; } } else if (card->bm_generation != generation) { /* -- 2.48.1 |
From: Takashi S. <o-t...@sa...> - 2025-09-18 23:54:59
|
Two functions, fw_core_handle_bus_reset() and bm_work(), are serialized by a commit 3d91fd440cc7 ("firewire: core: disable bus management work temporarily during updating topology"). Therefore the generation member of fw_card is immutable in bm_work(). This commit removes useless generation check in bm_work(). Signed-off-by: Takashi Sakamoto <o-t...@sa...> --- drivers/firewire/core-card.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/firewire/core-card.c b/drivers/firewire/core-card.c index 4fcd5ce4b2ce..ef00125fb01a 100644 --- a/drivers/firewire/core-card.c +++ b/drivers/firewire/core-card.c @@ -362,14 +362,12 @@ static void bm_work(struct work_struct *work) if (rcode == RCODE_COMPLETE) { int bm_id = be32_to_cpu(data[0]); - if (generation == card->generation) { - // Used by cdev layer for "struct fw_cdev_event_bus_reset". - scoped_guard(spinlock, &card->lock) { - if (bm_id != BUS_MANAGER_ID_NOT_REGISTERED) - card->bm_node_id = 0xffc0 & bm_id; - else - card->bm_node_id = local_id; - } + // Used by cdev layer for "struct fw_cdev_event_bus_reset". + scoped_guard(spinlock, &card->lock) { + if (bm_id != BUS_MANAGER_ID_NOT_REGISTERED) + card->bm_node_id = 0xffc0 & bm_id; + else + card->bm_node_id = local_id; } if (bm_id != BUS_MANAGER_ID_NOT_REGISTERED) { -- 2.48.1 |
From: Takashi S. <o-t...@sa...> - 2025-09-18 23:54:58
|
Hi, This patchset is the revised version of my previous one: https://lore.kernel.org/lkml/202...@sa.../ Changes from v1: * Ensure to initialize local variable Takashi Sakamoto (6): firewire: core: remove useless generation check firewire: core: use switch statement to evaluate transaction result to CSR_BUS_MANAGER_ID firewire: core: code refactoring for the case of generation mismatch firewire: core: code refactoring to split contention procedure for bus manager firewire: core; eliminate pick_me goto label firewire: core: minor code refactoring to delete useless local variable drivers/firewire/core-card.c | 335 ++++++++++++++++++----------------- 1 file changed, 177 insertions(+), 158 deletions(-) base-commit: e6d2338b6f3e522872f3a14fcc5e5de2f58bf23b -- 2.48.1 |
From: Takashi S. <o-t...@sa...> - 2025-09-18 23:46:29
|
Hi, On Fri, Sep 19, 2025 at 08:08:56AM +0900, Takashi Sakamoto wrote: > This commit uses condition statements instead of pick_me goto label. > > Signed-off-by: Takashi Sakamoto <o-t...@sa...> > --- > drivers/firewire/core-card.c | 102 ++++++++++++++++++----------------- > 1 file changed, 52 insertions(+), 50 deletions(-) > > diff --git a/drivers/firewire/core-card.c b/drivers/firewire/core-card.c > index 6268b595d4fa..b766ce5fdea4 100644 > --- a/drivers/firewire/core-card.c > +++ b/drivers/firewire/core-card.c > @@ -388,6 +388,7 @@ static void bm_work(struct work_struct *work) > int root_id, new_root_id, irm_id, local_id; > int expected_gap_count, generation; > bool do_reset = false; > + bool stand_for_root; > > if (card->local_node == NULL) > return; > @@ -408,11 +409,11 @@ static void bm_work(struct work_struct *work) > fw_schedule_bm_work(card, msecs_to_jiffies(125)); > return; > case BM_CONTENTION_OUTCOME_IRM_HAS_LINK_OFF: > - new_root_id = local_id; > - goto pick_me; > + stand_for_root = true; > + break; > case BM_CONTENTION_OUTCOME_IRM_COMPLIES_1394_1995_ONLY: > - new_root_id = local_id; > - goto pick_me; > + stand_for_root = true; > + break; > case BM_CONTENTION_OUTCOME_AT_NEW_GENERATION: > // BM work has been rescheduled. > return; > @@ -423,8 +424,8 @@ static void bm_work(struct work_struct *work) > return; > case BM_CONTENTION_OUTCOME_IRM_IS_NOT_CAPABLE_FOR_IRM: > // Let's do a bus reset and pick the local node as root, and thus, IRM. > - new_root_id = local_id; > - goto pick_me; > + stand_for_root = true; > + break; > case BM_CONTENTION_OUTCOME_IRM_HOLDS_ANOTHER_NODE_AS_BM: > if (local_id == irm_id) { > // Only acts as IRM. > @@ -434,60 +435,61 @@ static void bm_work(struct work_struct *work) > case BM_CONTENTION_OUTCOME_IRM_HOLDS_LOCAL_NODE_AS_BM: > default: > card->bm_generation = generation; > + stand_for_root = false; > break; > } > } > > - /* > - * We're bus manager for this generation, so next step is to > - * make sure we have an active cycle master and do gap count > - * optimization. > - */ > - if (card->gap_count == GAP_COUNT_MISMATCHED) { > - /* > - * If self IDs have inconsistent gap counts, do a > - * bus reset ASAP. The config rom read might never > - * complete, so don't wait for it. However, still > - * send a PHY configuration packet prior to the > - * bus reset. The PHY configuration packet might > - * fail, but 1394-2008 8.4.5.2 explicitly permits > - * it in this case, so it should be safe to try. > - */ > - new_root_id = local_id; > - /* > - * We must always send a bus reset if the gap count > - * is inconsistent, so bypass the 5-reset limit. > - */ > - card->bm_retries = 0; > - } else { > - // Now investigate root node. > - struct fw_device *root_device = fw_node_get_device(root_node); > - > - if (root_device == NULL) { > - // Either link_on is false, or we failed to read the > - // config rom. In either case, pick another root. > - new_root_id = local_id; > + // We're bus manager for this generation, so next step is to make sure we have an active > + // cycle master and do gap count optimization. > + if (!stand_for_root) { I realized that the "stand_for_root" local variable would be ununitialized here at the case of "card->bm_generation == generation". Let me post take 2. Regards Takashi Sakamoto |
From: Takashi S. <o-t...@sa...> - 2025-09-18 23:09:23
|
The do_reset local variable has less merit. Let's remove it. Signed-off-by: Takashi Sakamoto <o-t...@sa...> --- drivers/firewire/core-card.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/drivers/firewire/core-card.c b/drivers/firewire/core-card.c index b766ce5fdea4..527a99ef7c90 100644 --- a/drivers/firewire/core-card.c +++ b/drivers/firewire/core-card.c @@ -387,7 +387,6 @@ static void bm_work(struct work_struct *work) struct fw_node *root_node __free(node_unref) = NULL; int root_id, new_root_id, irm_id, local_id; int expected_gap_count, generation; - bool do_reset = false; bool stand_for_root; if (card->local_node == NULL) @@ -500,16 +499,10 @@ static void bm_work(struct work_struct *work) else expected_gap_count = 63; - /* - * Finally, figure out if we should do a reset or not. If we have - * done less than 5 resets with the same physical topology and we - * have either a new root or a new gap count setting, let's do it. - */ - - if (card->bm_retries++ < 5 && (card->gap_count != expected_gap_count || new_root_id != root_id)) - do_reset = true; - - if (do_reset) { + // Finally, figure out if we should do a reset or not. If we have done less than 5 resets + // with the same physical topology and we have either a new root or a new gap count + // setting, let's do it. + if (card->bm_retries++ < 5 && (card->gap_count != expected_gap_count || new_root_id != root_id)) { int card_gap_count = card->gap_count; fw_notice(card, "phy config: new root=%x, gap_count=%d\n", -- 2.48.1 |
From: Takashi S. <o-t...@sa...> - 2025-09-18 23:09:20
|
The precedure to contend for bus manager has much code. It is better to split it into a helper function. This commit refactors in the point. Signed-off-by: Takashi Sakamoto <o-t...@sa...> --- drivers/firewire/core-card.c | 223 ++++++++++++++++++++--------------- 1 file changed, 127 insertions(+), 96 deletions(-) diff --git a/drivers/firewire/core-card.c b/drivers/firewire/core-card.c index 02058af705cc..6268b595d4fa 100644 --- a/drivers/firewire/core-card.c +++ b/drivers/firewire/core-card.c @@ -279,6 +279,102 @@ void fw_schedule_bm_work(struct fw_card *card, unsigned long delay) fw_card_put(card); } +enum bm_contention_outcome { + // The bus management contention window is not expired. + BM_CONTENTION_OUTCOME_WITHIN_WINDOW = 0, + // The IRM node has link off. + BM_CONTENTION_OUTCOME_IRM_HAS_LINK_OFF, + // The IRM node complies IEEE 1394:1994 only. + BM_CONTENTION_OUTCOME_IRM_COMPLIES_1394_1995_ONLY, + // Another bus reset, BM work has been rescheduled. + BM_CONTENTION_OUTCOME_AT_NEW_GENERATION, + // We have been unable to send the lock request to IRM node due to some local problem. + BM_CONTENTION_OUTCOME_LOCAL_PROBLEM_AT_TRANSACTION, + // The lock request failed, maybe the IRM isn't really IRM capable after all. + BM_CONTENTION_OUTCOME_IRM_IS_NOT_CAPABLE_FOR_IRM, + // Somebody else is BM. + BM_CONTENTION_OUTCOME_IRM_HOLDS_ANOTHER_NODE_AS_BM, + // The local node succeeds after contending for bus manager. + BM_CONTENTION_OUTCOME_IRM_HOLDS_LOCAL_NODE_AS_BM, +}; + +static enum bm_contention_outcome contend_for_bm(struct fw_card *card) +{ + int generation = card->generation; + int local_id = card->local_node->node_id; + __be32 data[2] = { + cpu_to_be32(BUS_MANAGER_ID_NOT_REGISTERED), + cpu_to_be32(local_id), + }; + bool grace = time_is_before_jiffies64(card->reset_jiffies + msecs_to_jiffies(125)); + bool irm_is_1394_1995_only = false; + bool keep_this_irm = false; + struct fw_node *irm_node; + struct fw_device *irm_device; + int rcode; + + if (!grace) { + if (!is_next_generation(generation, card->bm_generation) || card->bm_abdicate) + return BM_CONTENTION_OUTCOME_WITHIN_WINDOW; + } + + irm_node = card->irm_node; + if (!irm_node->link_on) { + fw_notice(card, "IRM has link off, making local node (%02x) root\n", local_id); + return BM_CONTENTION_OUTCOME_IRM_HAS_LINK_OFF; + } + + irm_device = fw_node_get_device(irm_node); + if (irm_device && irm_device->config_rom) { + irm_is_1394_1995_only = (irm_device->config_rom[2] & 0x000000f0) == 0; + + // Canon MV5i works unreliably if it is not root node. + keep_this_irm = irm_device->config_rom[3] >> 8 == CANON_OUI; + } + + if (irm_is_1394_1995_only && !keep_this_irm) { + fw_notice(card, "IRM is not 1394a compliant, making local node (%02x) root\n", + local_id); + return BM_CONTENTION_OUTCOME_IRM_COMPLIES_1394_1995_ONLY; + } + + rcode = fw_run_transaction(card, TCODE_LOCK_COMPARE_SWAP, irm_node->node_id, generation, + SCODE_100, CSR_REGISTER_BASE + CSR_BUS_MANAGER_ID, data, + sizeof(data)); + + switch (rcode) { + case RCODE_GENERATION: + return BM_CONTENTION_OUTCOME_AT_NEW_GENERATION; + case RCODE_SEND_ERROR: + return BM_CONTENTION_OUTCOME_LOCAL_PROBLEM_AT_TRANSACTION; + case RCODE_COMPLETE: + { + int bm_id = be32_to_cpu(data[0]); + + // Used by cdev layer for "struct fw_cdev_event_bus_reset". + scoped_guard(spinlock, &card->lock) { + if (bm_id != BUS_MANAGER_ID_NOT_REGISTERED) + card->bm_node_id = 0xffc0 & bm_id; + else + card->bm_node_id = local_id; + } + + if (bm_id != BUS_MANAGER_ID_NOT_REGISTERED) + return BM_CONTENTION_OUTCOME_IRM_HOLDS_ANOTHER_NODE_AS_BM; + else + return BM_CONTENTION_OUTCOME_IRM_HOLDS_LOCAL_NODE_AS_BM; + } + default: + if (!keep_this_irm) { + fw_notice(card, "BM lock failed (%s), making local node (%02x) root\n", + fw_rcode_string(rcode), local_id); + return BM_CONTENTION_OUTCOME_IRM_COMPLIES_1394_1995_ONLY; + } else { + return BM_CONTENTION_OUTCOME_IRM_IS_NOT_CAPABLE_FOR_IRM; + } + } +} + DEFINE_FREE(node_unref, struct fw_node *, if (_T) fw_node_put(_T)) DEFINE_FREE(card_unref, struct fw_card *, if (_T) fw_card_put(_T)) @@ -305,105 +401,40 @@ static void bm_work(struct work_struct *work) local_id = card->local_node->node_id; if (card->bm_generation != generation) { - bool grace = time_is_before_jiffies64(card->reset_jiffies + msecs_to_jiffies(125)); - - if (grace || - (is_next_generation(generation, card->bm_generation) && !card->bm_abdicate)) { - // This first step is to figure out who is IRM and - // then try to become bus manager. If the IRM is not - // well defined (e.g. does not have an active link - // layer or does not responds to our lock request, we - // will have to do a little vigilante bus management. - // In that case, we do a goto into the gap count logic - // so that when we do the reset, we still optimize the - // gap count. That could well save a reset in the - // next generation. - __be32 data[2] = { - cpu_to_be32(BUS_MANAGER_ID_NOT_REGISTERED), - cpu_to_be32(local_id), - }; - struct fw_device *irm_device = fw_node_get_device(card->irm_node); - bool irm_is_1394_1995_only = false; - bool keep_this_irm = false; - int rcode; - - if (!card->irm_node->link_on) { - new_root_id = local_id; - fw_notice(card, "%s, making local node (%02x) root\n", - "IRM has link off", new_root_id); - goto pick_me; - } + enum bm_contention_outcome result = contend_for_bm(card); - if (irm_device && irm_device->config_rom) { - irm_is_1394_1995_only = (irm_device->config_rom[2] & 0x000000f0) == 0; - - // Canon MV5i works unreliably if it is not root node. - keep_this_irm = irm_device->config_rom[3] >> 8 == CANON_OUI; - } - - if (irm_is_1394_1995_only && !keep_this_irm) { - new_root_id = local_id; - fw_notice(card, "%s, making local node (%02x) root\n", - "IRM is not 1394a compliant", new_root_id); - goto pick_me; - } - - rcode = fw_run_transaction(card, TCODE_LOCK_COMPARE_SWAP, - irm_id, generation, SCODE_100, - CSR_REGISTER_BASE + CSR_BUS_MANAGER_ID, - data, sizeof(data)); - - switch (rcode) { - case RCODE_GENERATION: - // Another bus reset, BM work has been rescheduled. - return; - case RCODE_SEND_ERROR: - // We have been unable to send the lock request due to - // some local problem. Let's try again later and hope - // that the problem has gone away by then. - fw_schedule_bm_work(card, msecs_to_jiffies(125)); - return; - case RCODE_COMPLETE: - { - int bm_id = be32_to_cpu(data[0]); - - // Used by cdev layer for "struct fw_cdev_event_bus_reset". - scoped_guard(spinlock, &card->lock) { - if (bm_id != BUS_MANAGER_ID_NOT_REGISTERED) - card->bm_node_id = 0xffc0 & bm_id; - else - card->bm_node_id = local_id; - } - - if (bm_id != BUS_MANAGER_ID_NOT_REGISTERED) { - // Somebody else is BM. Only act as IRM. - if (local_id == irm_id) - allocate_broadcast_channel(card, generation); - return; - } - break; - } - default: - if (!keep_this_irm) { - // The lock request failed, maybe the IRM - // isn't really IRM capable after all. Let's - // do a bus reset and pick the local node as - // root, and thus, IRM. - new_root_id = local_id; - fw_notice(card, "BM lock failed (%s), making local node (%02x) root\n", - fw_rcode_string(rcode), new_root_id); - goto pick_me; - } - break; - } - - // A node contends for bus manager in this generation. - card->bm_generation = generation; - } else { - // We weren't BM in the last generation, and the last - // bus reset is less than 125ms ago. Reschedule this job. + switch (result) { + case BM_CONTENTION_OUTCOME_WITHIN_WINDOW: fw_schedule_bm_work(card, msecs_to_jiffies(125)); return; + case BM_CONTENTION_OUTCOME_IRM_HAS_LINK_OFF: + new_root_id = local_id; + goto pick_me; + case BM_CONTENTION_OUTCOME_IRM_COMPLIES_1394_1995_ONLY: + new_root_id = local_id; + goto pick_me; + case BM_CONTENTION_OUTCOME_AT_NEW_GENERATION: + // BM work has been rescheduled. + return; + case BM_CONTENTION_OUTCOME_LOCAL_PROBLEM_AT_TRANSACTION: + // Let's try again later and hope that the local problem has gone away by + // then. + fw_schedule_bm_work(card, msecs_to_jiffies(125)); + return; + case BM_CONTENTION_OUTCOME_IRM_IS_NOT_CAPABLE_FOR_IRM: + // Let's do a bus reset and pick the local node as root, and thus, IRM. + new_root_id = local_id; + goto pick_me; + case BM_CONTENTION_OUTCOME_IRM_HOLDS_ANOTHER_NODE_AS_BM: + if (local_id == irm_id) { + // Only acts as IRM. + allocate_broadcast_channel(card, generation); + } + fallthrough; + case BM_CONTENTION_OUTCOME_IRM_HOLDS_LOCAL_NODE_AS_BM: + default: + card->bm_generation = generation; + break; } } -- 2.48.1 |