From f83a052f9a0b62318d4f6e9bdddf9fc0103ac908 Mon Sep 17 00:00:00 2001 From: Adam Goldman Date: Mon, 25 Mar 2024 07:37:25 +0900 Subject: firewire: core: option to log bus reset initiation Add a debug parameter to firewire-core, analogous to the one in firewire-ohci. When this is set to 1, log when we schedule, delay, or initiate a bus reset. Since FireWire bus resets can originate from any node on the bus, specific logging of the resets we initiate provides additional insight. Signed-off-by: Adam Goldman Signed-off-by: Takashi Sakamoto --- drivers/firewire/core-card.c | 10 ++++++++++ drivers/firewire/core-transaction.c | 7 +++++++ drivers/firewire/core.h | 4 ++++ 3 files changed, 21 insertions(+) (limited to 'drivers') diff --git a/drivers/firewire/core-card.c b/drivers/firewire/core-card.c index 401a77e3b5fa..dac1b0fc7a42 100644 --- a/drivers/firewire/core-card.c +++ b/drivers/firewire/core-card.c @@ -221,11 +221,19 @@ static int reset_bus(struct fw_card *card, bool short_reset) int reg = short_reset ? 5 : 1; int bit = short_reset ? PHY_BUS_SHORT_RESET : PHY_BUS_RESET; + if (unlikely(fw_core_param_debug & FW_CORE_PARAM_DEBUG_BUSRESETS)) + fw_notice(card, "initiating %s bus reset\n", + short_reset ? "short" : "long"); + return card->driver->update_phy_reg(card, reg, 0, bit); } void fw_schedule_bus_reset(struct fw_card *card, bool delayed, bool short_reset) { + if (unlikely(fw_core_param_debug & FW_CORE_PARAM_DEBUG_BUSRESETS)) + fw_notice(card, "scheduling %s bus reset\n", + short_reset ? "short" : "long"); + /* We don't try hard to sort out requests of long vs. short resets. */ card->br_short = short_reset; @@ -244,6 +252,8 @@ static void br_work(struct work_struct *work) /* Delay for 2s after last reset per IEEE 1394 clause 8.2.1. */ if (card->reset_jiffies != 0 && time_before64(get_jiffies_64(), card->reset_jiffies + 2 * HZ)) { + if (unlikely(fw_core_param_debug & FW_CORE_PARAM_DEBUG_BUSRESETS)) + fw_notice(card, "delaying bus reset\n"); if (!queue_delayed_work(fw_workqueue, &card->br_work, 2 * HZ)) fw_card_put(card); return; diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c index 130b95aca629..c427b7861eaf 100644 --- a/drivers/firewire/core-transaction.c +++ b/drivers/firewire/core-transaction.c @@ -1385,5 +1385,12 @@ static void __exit fw_core_cleanup(void) idr_destroy(&fw_device_idr); } +int fw_core_param_debug; +module_param_named(debug, fw_core_param_debug, int, 0644); +MODULE_PARM_DESC(debug, "Verbose logging (default = 0" + ", bus resets = " __stringify(FW_CORE_PARAM_DEBUG_BUSRESETS) + ")"); + + module_init(fw_core_init); module_exit(fw_core_cleanup); diff --git a/drivers/firewire/core.h b/drivers/firewire/core.h index 95c10f3d2282..ff96e5456b5d 100644 --- a/drivers/firewire/core.h +++ b/drivers/firewire/core.h @@ -238,6 +238,10 @@ static inline bool is_next_generation(int new_generation, int old_generation) /* OHCI-1394's default upper bound for physical DMA: 4 GB */ #define FW_MAX_PHYSICAL_RANGE (1ULL << 32) +#define FW_CORE_PARAM_DEBUG_BUSRESETS 1 + +extern int fw_core_param_debug; + void fw_core_handle_request(struct fw_card *card, struct fw_packet *request); void fw_core_handle_response(struct fw_card *card, struct fw_packet *packet); int fw_get_response_length(struct fw_request *request); -- cgit v1.2.3-58-ga151 From fb7d0e5e1f14e9f0bf743d99b54c4e6637bab098 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 31 Mar 2024 22:50:34 +0900 Subject: Revert "firewire: ohci: use devres for requested IRQ" This reverts commit 5a95f1ded28691e69f7d6718c5dcbc149613d431. As long as allocating any device interrupt vector for MSI, it is inconvenient to utilize managed device resources for IRQ requesting. Link: https://lore.kernel.org/r/20240331135037.191479-2-o-takashi@sakamocchi.jp Signed-off-by: Takashi Sakamoto --- drivers/firewire/ohci.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index b9ae0340b8a7..c1ee16c3b424 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -3758,16 +3758,17 @@ static int pci_probe(struct pci_dev *dev, if (!(ohci->quirks & QUIRK_NO_MSI)) pci_enable_msi(dev); - err = devm_request_irq(&dev->dev, dev->irq, irq_handler, - pci_dev_msi_enabled(dev) ? 0 : IRQF_SHARED, ohci_driver_name, ohci); - if (err < 0) { + if (request_irq(dev->irq, irq_handler, + pci_dev_msi_enabled(dev) ? 0 : IRQF_SHARED, + ohci_driver_name, ohci)) { ohci_err(ohci, "failed to allocate interrupt %d\n", dev->irq); + err = -EIO; goto fail_msi; } err = fw_card_add(&ohci->card, max_receive, link_speed, guid); if (err) - goto fail_msi; + goto fail_irq; version = reg_read(ohci, OHCI1394_Version) & 0x00ff00ff; ohci_notice(ohci, @@ -3780,8 +3781,9 @@ static int pci_probe(struct pci_dev *dev, return 0; + fail_irq: + free_irq(dev->irq, ohci); fail_msi: - devm_free_irq(&dev->dev, dev->irq, ohci); pci_disable_msi(dev); return err; @@ -3809,7 +3811,7 @@ static void pci_remove(struct pci_dev *dev) software_reset(ohci); - devm_free_irq(&dev->dev, dev->irq, ohci); + free_irq(dev->irq, ohci); pci_disable_msi(dev); dev_notice(&dev->dev, "removing fw-ohci device\n"); -- cgit v1.2.3-58-ga151 From d4cad4162ba3bc7a5b7aca3c11e0e8ae05a61e81 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 31 Mar 2024 22:50:35 +0900 Subject: firewire: ohci: replace request_irq() with request_threaded_irq() Nowadays request_irq() is a wrapper of request_threaded_irq(). The IRQ handler of 1394 ohci driver has never been optimized yet, while it is a good preparation for the future work to replace the latter. This commit replaces the former. Link: https://lore.kernel.org/r/20240331135037.191479-3-o-takashi@sakamocchi.jp Signed-off-by: Takashi Sakamoto --- drivers/firewire/ohci.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index c1ee16c3b424..0f55ef43292f 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -3758,11 +3758,11 @@ static int pci_probe(struct pci_dev *dev, if (!(ohci->quirks & QUIRK_NO_MSI)) pci_enable_msi(dev); - if (request_irq(dev->irq, irq_handler, - pci_dev_msi_enabled(dev) ? 0 : IRQF_SHARED, - ohci_driver_name, ohci)) { + err = request_threaded_irq(dev->irq, irq_handler, NULL, + pci_dev_msi_enabled(dev) ? 0 : IRQF_SHARED, ohci_driver_name, + ohci); + if (err < 0) { ohci_err(ohci, "failed to allocate interrupt %d\n", dev->irq); - err = -EIO; goto fail_msi; } -- cgit v1.2.3-58-ga151 From b9d9a025bf2fa93d421cc5e54bf1dfaa3a55d60a Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 31 Mar 2024 22:50:36 +0900 Subject: firewire: ohci: obsolete usage of deprecated API for MSI The usage of the pair of pci_enable_msi() and pci_disable_msi() is deprecated. This commit uses the preferred pair of API for the purpose. The call of pci_alloc_irq_vectors() can have a subeffect to change the return value of pci_dev_msi_enabled(). Link: https://lore.kernel.org/r/20240331135037.191479-4-o-takashi@sakamocchi.jp Signed-off-by: Takashi Sakamoto --- drivers/firewire/ohci.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index 0f55ef43292f..34262856f680 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -3631,7 +3631,7 @@ static int pci_probe(struct pci_dev *dev, struct fw_ohci *ohci; u32 bus_options, max_receive, link_speed, version; u64 guid; - int i, err; + int i, flags, err; size_t size; if (dev->vendor == PCI_VENDOR_ID_PINNACLE_SYSTEMS) { @@ -3756,8 +3756,13 @@ static int pci_probe(struct pci_dev *dev, guid = ((u64) reg_read(ohci, OHCI1394_GUIDHi) << 32) | reg_read(ohci, OHCI1394_GUIDLo); + flags = PCI_IRQ_INTX; if (!(ohci->quirks & QUIRK_NO_MSI)) - pci_enable_msi(dev); + flags |= PCI_IRQ_MSI; + err = pci_alloc_irq_vectors(dev, 1, 1, flags); + if (err < 0) + return err; + err = request_threaded_irq(dev->irq, irq_handler, NULL, pci_dev_msi_enabled(dev) ? 0 : IRQF_SHARED, ohci_driver_name, ohci); @@ -3784,7 +3789,7 @@ static int pci_probe(struct pci_dev *dev, fail_irq: free_irq(dev->irq, ohci); fail_msi: - pci_disable_msi(dev); + pci_free_irq_vectors(dev); return err; } @@ -3812,7 +3817,7 @@ static void pci_remove(struct pci_dev *dev) software_reset(ohci); free_irq(dev->irq, ohci); - pci_disable_msi(dev); + pci_free_irq_vectors(dev); dev_notice(&dev->dev, "removing fw-ohci device\n"); } -- cgit v1.2.3-58-ga151 From e41b2c1532d6d43945a59e7d844a258b5a82f307 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 31 Mar 2024 22:50:37 +0900 Subject: firewire: ohci: use pci_irq_vector() to retrieve allocated interrupt line The pci_irq_vector() is available to retrieve the allocated interrupt line instead of the direct access to the member of device structure. Link: https://lore.kernel.org/r/20240331135037.191479-5-o-takashi@sakamocchi.jp Signed-off-by: Takashi Sakamoto --- drivers/firewire/ohci.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index 34262856f680..0de45baf3569 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -3631,7 +3631,7 @@ static int pci_probe(struct pci_dev *dev, struct fw_ohci *ohci; u32 bus_options, max_receive, link_speed, version; u64 guid; - int i, flags, err; + int i, flags, irq, err; size_t size; if (dev->vendor == PCI_VENDOR_ID_PINNACLE_SYSTEMS) { @@ -3762,12 +3762,17 @@ static int pci_probe(struct pci_dev *dev, err = pci_alloc_irq_vectors(dev, 1, 1, flags); if (err < 0) return err; + irq = pci_irq_vector(dev, 0); + if (irq < 0) { + err = irq; + goto fail_msi; + } - err = request_threaded_irq(dev->irq, irq_handler, NULL, + err = request_threaded_irq(irq, irq_handler, NULL, pci_dev_msi_enabled(dev) ? 0 : IRQF_SHARED, ohci_driver_name, ohci); if (err < 0) { - ohci_err(ohci, "failed to allocate interrupt %d\n", dev->irq); + ohci_err(ohci, "failed to allocate interrupt %d\n", irq); goto fail_msi; } @@ -3787,7 +3792,7 @@ static int pci_probe(struct pci_dev *dev, return 0; fail_irq: - free_irq(dev->irq, ohci); + free_irq(irq, ohci); fail_msi: pci_free_irq_vectors(dev); @@ -3797,6 +3802,7 @@ static int pci_probe(struct pci_dev *dev, static void pci_remove(struct pci_dev *dev) { struct fw_ohci *ohci = pci_get_drvdata(dev); + int irq; /* * If the removal is happening from the suspend state, LPS won't be @@ -3816,7 +3822,9 @@ static void pci_remove(struct pci_dev *dev) software_reset(ohci); - free_irq(dev->irq, ohci); + irq = pci_irq_vector(dev, 0); + if (irq >= 0) + free_irq(irq, ohci); pci_free_irq_vectors(dev); dev_notice(&dev->dev, "removing fw-ohci device\n"); -- cgit v1.2.3-58-ga151 From 75527d8d9e5ec374b9b0d70c712fec78b4bb693f Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 28 Apr 2024 16:13:39 +0900 Subject: firewire: core: add common inline functions to serialize/deserialize asynchronous packet header In both core and 1394 OHCI driver, some hard-coded values and macros are used to serialize/deserialize the header of asynchronous packets. It is inconvenient to reuse them. This commit adds some helper inline functions with their tests for the purpose. Link: https://lore.kernel.org/r/20240428071347.409202-2-o-takashi@sakamocchi.jp Signed-off-by: Takashi Sakamoto --- drivers/firewire/.kunitconfig | 1 + drivers/firewire/Kconfig | 16 + drivers/firewire/Makefile | 3 + drivers/firewire/packet-header-definitions.h | 168 +++++++++ drivers/firewire/packet-serdes-test.c | 538 +++++++++++++++++++++++++++ 5 files changed, 726 insertions(+) create mode 100644 drivers/firewire/packet-header-definitions.h create mode 100644 drivers/firewire/packet-serdes-test.c (limited to 'drivers') diff --git a/drivers/firewire/.kunitconfig b/drivers/firewire/.kunitconfig index 76444a2d5e12..60d9e7c35417 100644 --- a/drivers/firewire/.kunitconfig +++ b/drivers/firewire/.kunitconfig @@ -3,3 +3,4 @@ CONFIG_PCI=y CONFIG_FIREWIRE=y CONFIG_FIREWIRE_KUNIT_UAPI_TEST=y CONFIG_FIREWIRE_KUNIT_DEVICE_ATTRIBUTE_TEST=y +CONFIG_FIREWIRE_KUNIT_PACKET_SERDES_TEST=y diff --git a/drivers/firewire/Kconfig b/drivers/firewire/Kconfig index 552a39df8cbd..869598b20e3a 100644 --- a/drivers/firewire/Kconfig +++ b/drivers/firewire/Kconfig @@ -50,6 +50,22 @@ config FIREWIRE_KUNIT_DEVICE_ATTRIBUTE_TEST For more information on KUnit and unit tests in general, refer to the KUnit documentation in Documentation/dev-tools/kunit/. +config FIREWIRE_KUNIT_PACKET_SERDES_TEST + tristate "KUnit tests for packet serialization/deserialization" if !KUNIT_ALL_TESTS + depends on FIREWIRE && KUNIT + default KUNIT_ALL_TESTS + help + This builds the KUnit tests for packet serialization and + deserialization. + + KUnit tests run during boot and output the results to the debug + log in TAP format (https://testanything.org/). Only useful for + kernel devs running KUnit test harness and are not for inclusion + into a production build. + + For more information on KUnit and unit tests in general, refer + to the KUnit documentation in Documentation/dev-tools/kunit/. + config FIREWIRE_OHCI tristate "OHCI-1394 controllers" depends on PCI && FIREWIRE && MMU diff --git a/drivers/firewire/Makefile b/drivers/firewire/Makefile index b24b2879ac34..bbde29a0fba6 100644 --- a/drivers/firewire/Makefile +++ b/drivers/firewire/Makefile @@ -17,4 +17,7 @@ obj-$(CONFIG_FIREWIRE_NOSY) += nosy.o obj-$(CONFIG_PROVIDE_OHCI1394_DMA_INIT) += init_ohci1394_dma.o firewire-uapi-test-objs += uapi-test.o +firewire-packet-serdes-test-objs += packet-serdes-test.o + obj-$(CONFIG_FIREWIRE_KUNIT_UAPI_TEST) += firewire-uapi-test.o +obj-$(CONFIG_FIREWIRE_KUNIT_PACKET_SERDES_TEST) += firewire-packet-serdes-test.o diff --git a/drivers/firewire/packet-header-definitions.h b/drivers/firewire/packet-header-definitions.h new file mode 100644 index 000000000000..83e550427706 --- /dev/null +++ b/drivers/firewire/packet-header-definitions.h @@ -0,0 +1,168 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// +// packet-header-definitions.h - The definitions of header fields for IEEE 1394 packet. +// +// Copyright (c) 2024 Takashi Sakamoto + +#ifndef _FIREWIRE_PACKET_HEADER_DEFINITIONS_H +#define _FIREWIRE_PACKET_HEADER_DEFINITIONS_H + +#define ASYNC_HEADER_QUADLET_COUNT 4 + +#define ASYNC_HEADER_Q0_DESTINATION_SHIFT 16 +#define ASYNC_HEADER_Q0_DESTINATION_MASK 0xffff0000 +#define ASYNC_HEADER_Q0_TLABEL_SHIFT 10 +#define ASYNC_HEADER_Q0_TLABEL_MASK 0x0000fc00 +#define ASYNC_HEADER_Q0_RETRY_SHIFT 8 +#define ASYNC_HEADER_Q0_RETRY_MASK 0x00000300 +#define ASYNC_HEADER_Q0_TCODE_SHIFT 4 +#define ASYNC_HEADER_Q0_TCODE_MASK 0x000000f0 +#define ASYNC_HEADER_Q0_PRIORITY_SHIFT 0 +#define ASYNC_HEADER_Q0_PRIORITY_MASK 0x0000000f +#define ASYNC_HEADER_Q1_SOURCE_SHIFT 16 +#define ASYNC_HEADER_Q1_SOURCE_MASK 0xffff0000 +#define ASYNC_HEADER_Q1_RCODE_SHIFT 12 +#define ASYNC_HEADER_Q1_RCODE_MASK 0x0000f000 +#define ASYNC_HEADER_Q1_RCODE_SHIFT 12 +#define ASYNC_HEADER_Q1_RCODE_MASK 0x0000f000 +#define ASYNC_HEADER_Q1_OFFSET_HIGH_SHIFT 0 +#define ASYNC_HEADER_Q1_OFFSET_HIGH_MASK 0x0000ffff +#define ASYNC_HEADER_Q3_DATA_LENGTH_SHIFT 16 +#define ASYNC_HEADER_Q3_DATA_LENGTH_MASK 0xffff0000 +#define ASYNC_HEADER_Q3_EXTENDED_TCODE_SHIFT 0 +#define ASYNC_HEADER_Q3_EXTENDED_TCODE_MASK 0x0000ffff + +static inline unsigned int async_header_get_destination(const u32 header[ASYNC_HEADER_QUADLET_COUNT]) +{ + return (header[0] & ASYNC_HEADER_Q0_DESTINATION_MASK) >> ASYNC_HEADER_Q0_DESTINATION_SHIFT; +} + +static inline unsigned int async_header_get_tlabel(const u32 header[ASYNC_HEADER_QUADLET_COUNT]) +{ + return (header[0] & ASYNC_HEADER_Q0_TLABEL_MASK) >> ASYNC_HEADER_Q0_TLABEL_SHIFT; +} + +static inline unsigned int async_header_get_retry(const u32 header[ASYNC_HEADER_QUADLET_COUNT]) +{ + return (header[0] & ASYNC_HEADER_Q0_RETRY_MASK) >> ASYNC_HEADER_Q0_RETRY_SHIFT; +} + +static inline unsigned int async_header_get_tcode(const u32 header[ASYNC_HEADER_QUADLET_COUNT]) +{ + return (header[0] & ASYNC_HEADER_Q0_TCODE_MASK) >> ASYNC_HEADER_Q0_TCODE_SHIFT; +} + +static inline unsigned int async_header_get_priority(const u32 header[ASYNC_HEADER_QUADLET_COUNT]) +{ + return (header[0] & ASYNC_HEADER_Q0_PRIORITY_MASK) >> ASYNC_HEADER_Q0_PRIORITY_SHIFT; +} + +static inline unsigned int async_header_get_source(const u32 header[ASYNC_HEADER_QUADLET_COUNT]) +{ + return (header[1] & ASYNC_HEADER_Q1_SOURCE_MASK) >> ASYNC_HEADER_Q1_SOURCE_SHIFT; +} + +static inline unsigned int async_header_get_rcode(const u32 header[ASYNC_HEADER_QUADLET_COUNT]) +{ + return (header[1] & ASYNC_HEADER_Q1_RCODE_MASK) >> ASYNC_HEADER_Q1_RCODE_SHIFT; +} + +static inline u64 async_header_get_offset(const u32 header[ASYNC_HEADER_QUADLET_COUNT]) +{ + u32 hi = (header[1] & ASYNC_HEADER_Q1_OFFSET_HIGH_MASK) >> ASYNC_HEADER_Q1_OFFSET_HIGH_SHIFT; + return (((u64)hi) << 32) | ((u64)header[2]); +} + +static inline u32 async_header_get_quadlet_data(const u32 header[ASYNC_HEADER_QUADLET_COUNT]) +{ + return header[3]; +} + +static inline unsigned int async_header_get_data_length(const u32 header[ASYNC_HEADER_QUADLET_COUNT]) +{ + return (header[3] & ASYNC_HEADER_Q3_DATA_LENGTH_MASK) >> ASYNC_HEADER_Q3_DATA_LENGTH_SHIFT; +} + +static inline unsigned int async_header_get_extended_tcode(const u32 header[ASYNC_HEADER_QUADLET_COUNT]) +{ + return (header[3] & ASYNC_HEADER_Q3_EXTENDED_TCODE_MASK) >> ASYNC_HEADER_Q3_EXTENDED_TCODE_SHIFT; +} + +static inline void async_header_set_destination(u32 header[ASYNC_HEADER_QUADLET_COUNT], + unsigned int destination) +{ + header[0] &= ~ASYNC_HEADER_Q0_DESTINATION_MASK; + header[0] |= (((u32)destination) << ASYNC_HEADER_Q0_DESTINATION_SHIFT) & ASYNC_HEADER_Q0_DESTINATION_MASK; +} + +static inline void async_header_set_tlabel(u32 header[ASYNC_HEADER_QUADLET_COUNT], + unsigned int tlabel) +{ + header[0] &= ~ASYNC_HEADER_Q0_TLABEL_MASK; + header[0] |= (((u32)tlabel) << ASYNC_HEADER_Q0_TLABEL_SHIFT) & ASYNC_HEADER_Q0_TLABEL_MASK; +} + +static inline void async_header_set_retry(u32 header[ASYNC_HEADER_QUADLET_COUNT], + unsigned int retry) +{ + header[0] &= ~ASYNC_HEADER_Q0_RETRY_MASK; + header[0] |= (((u32)retry) << ASYNC_HEADER_Q0_RETRY_SHIFT) & ASYNC_HEADER_Q0_RETRY_MASK; +} + +static inline void async_header_set_tcode(u32 header[ASYNC_HEADER_QUADLET_COUNT], + unsigned int tcode) +{ + header[0] &= ~ASYNC_HEADER_Q0_TCODE_MASK; + header[0] |= (((u32)tcode) << ASYNC_HEADER_Q0_TCODE_SHIFT) & ASYNC_HEADER_Q0_TCODE_MASK; +} + +static inline void async_header_set_priority(u32 header[ASYNC_HEADER_QUADLET_COUNT], + unsigned int priority) +{ + header[0] &= ~ASYNC_HEADER_Q0_PRIORITY_MASK; + header[0] |= (((u32)priority) << ASYNC_HEADER_Q0_PRIORITY_SHIFT) & ASYNC_HEADER_Q0_PRIORITY_MASK; +} + + +static inline void async_header_set_source(u32 header[ASYNC_HEADER_QUADLET_COUNT], + unsigned int source) +{ + header[1] &= ~ASYNC_HEADER_Q1_SOURCE_MASK; + header[1] |= (((u32)source) << ASYNC_HEADER_Q1_SOURCE_SHIFT) & ASYNC_HEADER_Q1_SOURCE_MASK; +} + +static inline void async_header_set_rcode(u32 header[ASYNC_HEADER_QUADLET_COUNT], + unsigned int rcode) +{ + header[1] &= ~ASYNC_HEADER_Q1_RCODE_MASK; + header[1] |= (((u32)rcode) << ASYNC_HEADER_Q1_RCODE_SHIFT) & ASYNC_HEADER_Q1_RCODE_MASK; +} + +static inline void async_header_set_offset(u32 header[ASYNC_HEADER_QUADLET_COUNT], u64 offset) +{ + u32 hi = (u32)(offset >> 32); + header[1] &= ~ASYNC_HEADER_Q1_OFFSET_HIGH_MASK; + header[1] |= (hi << ASYNC_HEADER_Q1_OFFSET_HIGH_SHIFT) & ASYNC_HEADER_Q1_OFFSET_HIGH_MASK; + header[2] = (u32)(offset & 0x00000000ffffffff); +} + +static inline void async_header_set_quadlet_data(u32 header[ASYNC_HEADER_QUADLET_COUNT], u32 quadlet_data) +{ + header[3] = quadlet_data; +} + +static inline void async_header_set_data_length(u32 header[ASYNC_HEADER_QUADLET_COUNT], + unsigned int data_length) +{ + header[3] &= ~ASYNC_HEADER_Q3_DATA_LENGTH_MASK; + header[3] |= (((u32)data_length) << ASYNC_HEADER_Q3_DATA_LENGTH_SHIFT) & ASYNC_HEADER_Q3_DATA_LENGTH_MASK; +} + +static inline void async_header_set_extended_tcode(u32 header[ASYNC_HEADER_QUADLET_COUNT], + unsigned int extended_tcode) +{ + header[3] &= ~ASYNC_HEADER_Q3_EXTENDED_TCODE_MASK; + header[3] |= (((u32)extended_tcode) << ASYNC_HEADER_Q3_EXTENDED_TCODE_SHIFT) & ASYNC_HEADER_Q3_EXTENDED_TCODE_MASK; +} + +#endif // _FIREWIRE_PACKET_HEADER_DEFINITIONS_H diff --git a/drivers/firewire/packet-serdes-test.c b/drivers/firewire/packet-serdes-test.c new file mode 100644 index 000000000000..299e9f908463 --- /dev/null +++ b/drivers/firewire/packet-serdes-test.c @@ -0,0 +1,538 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// +// packet-serdes-test.c - An application of Kunit to check serialization/deserialization of packets +// defined by IEEE 1394. +// +// Copyright (c) 2024 Takashi Sakamoto + +#include + +#include + +#include "packet-header-definitions.h" + +static void serialize_async_header_common(u32 header[ASYNC_HEADER_QUADLET_COUNT], + unsigned int dst_id, unsigned int tlabel, + unsigned int retry, unsigned int tcode, + unsigned int priority, unsigned int src_id) +{ + async_header_set_destination(header, dst_id); + async_header_set_tlabel(header, tlabel); + async_header_set_retry(header, retry); + async_header_set_tcode(header, tcode); + async_header_set_priority(header, priority); + async_header_set_source(header, src_id); +} + +static void serialize_async_header_request(u32 header[ASYNC_HEADER_QUADLET_COUNT], + unsigned int dst_id, unsigned int tlabel, + unsigned int retry, unsigned int tcode, + unsigned int priority, unsigned int src_id, u64 offset) +{ + serialize_async_header_common(header, dst_id, tlabel, retry, tcode, priority, src_id); + async_header_set_offset(header, offset); +} + +static void serialize_async_header_quadlet_request(u32 header[ASYNC_HEADER_QUADLET_COUNT], + unsigned int dst_id, unsigned int tlabel, + unsigned int retry, unsigned int tcode, + unsigned int priority, unsigned int src_id, + u64 offset) +{ + serialize_async_header_request(header, dst_id, tlabel, retry, tcode, priority, src_id, + offset); +} + +static void serialize_async_header_block_request(u32 header[ASYNC_HEADER_QUADLET_COUNT], + unsigned int dst_id, unsigned int tlabel, + unsigned int retry, unsigned int tcode, + unsigned int priority, unsigned int src_id, + u64 offset, unsigned int data_length, + unsigned int extended_tcode) +{ + serialize_async_header_request(header, dst_id, tlabel, retry, tcode, priority, src_id, + offset); + async_header_set_data_length(header, data_length); + async_header_set_extended_tcode(header, extended_tcode); +} + +static void serialize_async_header_response(u32 header[ASYNC_HEADER_QUADLET_COUNT], + unsigned int dst_id, unsigned int tlabel, + unsigned int retry, unsigned int tcode, + unsigned int priority, unsigned int src_id, + unsigned int rcode) +{ + serialize_async_header_common(header, dst_id, tlabel, retry, tcode, priority, src_id); + async_header_set_rcode(header, rcode); +} + +static void serialize_async_header_quadlet_response(u32 header[ASYNC_HEADER_QUADLET_COUNT], + unsigned int dst_id, unsigned int tlabel, + unsigned int retry, unsigned int tcode, + unsigned int priority, unsigned int src_id, + unsigned int rcode) +{ + serialize_async_header_response(header, dst_id, tlabel, retry, tcode, priority, src_id, + rcode); +} + +static void serialize_async_header_block_response(u32 header[ASYNC_HEADER_QUADLET_COUNT], + unsigned int dst_id, unsigned int tlabel, + unsigned int retry, unsigned int tcode, + unsigned int priority, unsigned int src_id, + unsigned int rcode, unsigned int data_length, + unsigned int extended_tcode) +{ + serialize_async_header_response(header, dst_id, tlabel, retry, tcode, priority, src_id, + rcode); + async_header_set_data_length(header, data_length); + async_header_set_extended_tcode(header, extended_tcode); +} + +static void deserialize_async_header_common(const u32 header[ASYNC_HEADER_QUADLET_COUNT], + unsigned int *dst_id, unsigned int *tlabel, + unsigned int *retry, unsigned int *tcode, + unsigned int *priority, unsigned int *src_id) +{ + *dst_id = async_header_get_destination(header); + *tlabel = async_header_get_tlabel(header); + *retry = async_header_get_retry(header); + *tcode = async_header_get_tcode(header); + *priority = async_header_get_priority(header); + *src_id = async_header_get_source(header); +} + +static void deserialize_async_header_request(const u32 header[ASYNC_HEADER_QUADLET_COUNT], + unsigned int *dst_id, unsigned int *tlabel, + unsigned int *retry, unsigned int *tcode, + unsigned int *priority, unsigned int *src_id, + u64 *offset) +{ + deserialize_async_header_common(header, dst_id, tlabel, retry, tcode, priority, src_id); + *offset = async_header_get_offset(header); +} + +static void deserialize_async_header_quadlet_request(const u32 header[ASYNC_HEADER_QUADLET_COUNT], + unsigned int *dst_id, unsigned int *tlabel, + unsigned int *retry, unsigned int *tcode, + unsigned int *priority, unsigned int *src_id, + u64 *offset) +{ + deserialize_async_header_request(header, dst_id, tlabel, retry, tcode, priority, src_id, + offset); +} + +static void deserialize_async_header_block_request(const u32 header[ASYNC_HEADER_QUADLET_COUNT], + unsigned int *dst_id, unsigned int *tlabel, + unsigned int *retry, unsigned int *tcode, + unsigned int *priority, unsigned int *src_id, + u64 *offset, + unsigned int *data_length, + unsigned int *extended_tcode) +{ + deserialize_async_header_request(header, dst_id, tlabel, retry, tcode, priority, src_id, + offset); + *data_length = async_header_get_data_length(header); + *extended_tcode = async_header_get_extended_tcode(header); +} + +static void deserialize_async_header_response(const u32 header[ASYNC_HEADER_QUADLET_COUNT], + unsigned int *dst_id, unsigned int *tlabel, + unsigned int *retry, unsigned int *tcode, + unsigned int *priority, unsigned int *src_id, + unsigned int *rcode) +{ + deserialize_async_header_common(header, dst_id, tlabel, retry, tcode, priority, src_id); + *rcode = async_header_get_rcode(header); +} + +static void deserialize_async_header_quadlet_response(const u32 header[ASYNC_HEADER_QUADLET_COUNT], + unsigned int *dst_id, unsigned int *tlabel, + unsigned int *retry, unsigned int *tcode, + unsigned int *priority, unsigned int *src_id, + unsigned int *rcode) +{ + deserialize_async_header_response(header, dst_id, tlabel, retry, tcode, priority, src_id, rcode); +} + +static void deserialize_async_header_block_response(const u32 header[ASYNC_HEADER_QUADLET_COUNT], + unsigned int *dst_id, unsigned int *tlabel, + unsigned int *retry, unsigned int *tcode, + unsigned int *priority, unsigned int *src_id, + unsigned int *rcode, unsigned int *data_length, + unsigned int *extended_tcode) +{ + deserialize_async_header_response(header, dst_id, tlabel, retry, tcode, priority, src_id, rcode); + *data_length = async_header_get_data_length(header); + *extended_tcode = async_header_get_extended_tcode(header); +} + +static void test_async_header_write_quadlet_request(struct kunit *test) +{ + static const u32 expected[ASYNC_HEADER_QUADLET_COUNT] = { + 0xffc05100, + 0xffc1ffff, + 0xf0000234, + 0x1f0000c0, + }; + u32 header[ASYNC_HEADER_QUADLET_COUNT] = {0, 0, 0, 0}; + + unsigned int dst_id; + unsigned int tlabel; + unsigned int retry; + unsigned int tcode; + unsigned int priority; + unsigned int src_id; + u64 offset; + u32 quadlet_data; + + deserialize_async_header_quadlet_request(expected, &dst_id, &tlabel, &retry, &tcode, + &priority, &src_id, &offset); + quadlet_data = async_header_get_quadlet_data(expected); + + KUNIT_EXPECT_EQ(test, 0xffc0, dst_id); + KUNIT_EXPECT_EQ(test, 0x14, tlabel); + KUNIT_EXPECT_EQ(test, 0x01, retry); + KUNIT_EXPECT_EQ(test, TCODE_WRITE_QUADLET_REQUEST, tcode); + KUNIT_EXPECT_EQ(test, 0x00, priority); + KUNIT_EXPECT_EQ(test, 0xffc1, src_id); + KUNIT_EXPECT_EQ(test, 0xfffff0000234, offset); + KUNIT_EXPECT_EQ(test, 0x1f0000c0, quadlet_data); + + serialize_async_header_quadlet_request(header, dst_id, tlabel, retry, tcode, priority, + src_id, offset); + async_header_set_quadlet_data(header, quadlet_data); + + KUNIT_EXPECT_MEMEQ(test, header, expected, sizeof(expected)); +} + +static void test_async_header_write_block_request(struct kunit *test) +{ + static const u32 expected[ASYNC_HEADER_QUADLET_COUNT] = { + 0xffc06510, + 0xffc1ecc0, + 0x00000000, + 0x00180000, + }; + u32 header[ASYNC_HEADER_QUADLET_COUNT] = {0, 0, 0, 0}; + + unsigned int dst_id; + unsigned int tlabel; + unsigned int retry; + unsigned int tcode; + unsigned int priority; + unsigned int src_id; + u64 offset; + unsigned int data_length; + unsigned int extended_tcode; + + deserialize_async_header_block_request(expected, &dst_id, &tlabel, &retry, &tcode, + &priority, &src_id, &offset, &data_length, + &extended_tcode); + + KUNIT_EXPECT_EQ(test, 0xffc0, dst_id); + KUNIT_EXPECT_EQ(test, 0x19, tlabel); + KUNIT_EXPECT_EQ(test, 0x01, retry); + KUNIT_EXPECT_EQ(test, TCODE_WRITE_BLOCK_REQUEST, tcode); + KUNIT_EXPECT_EQ(test, 0x00, priority); + KUNIT_EXPECT_EQ(test, 0xffc1, src_id); + KUNIT_EXPECT_EQ(test, 0xecc000000000, offset); + KUNIT_EXPECT_EQ(test, 0x0018, data_length); + KUNIT_EXPECT_EQ(test, 0x0000, extended_tcode); + + serialize_async_header_block_request(header, dst_id, tlabel, retry, tcode, priority, src_id, + offset, data_length, extended_tcode); + + KUNIT_EXPECT_MEMEQ(test, header, expected, sizeof(expected)); +} + +static void test_async_header_write_response(struct kunit *test) +{ + static const u32 expected[ASYNC_HEADER_QUADLET_COUNT] = { + 0xffc15120, + 0xffc00000, + 0x00000000, + 0x00000000, + }; + u32 header[ASYNC_HEADER_QUADLET_COUNT] = {0, 0, 0, 0}; + + unsigned int dst_id; + unsigned int tlabel; + unsigned int retry; + unsigned int tcode; + unsigned int priority; + unsigned int src_id; + unsigned int rcode; + + deserialize_async_header_quadlet_response(expected, &dst_id, &tlabel, &retry, &tcode, + &priority, &src_id, &rcode); + + KUNIT_EXPECT_EQ(test, 0xffc1, dst_id); + KUNIT_EXPECT_EQ(test, 0x14, tlabel); + KUNIT_EXPECT_EQ(test, 0x01, retry); + KUNIT_EXPECT_EQ(test, TCODE_WRITE_RESPONSE, tcode); + KUNIT_EXPECT_EQ(test, 0x00, priority); + KUNIT_EXPECT_EQ(test, 0xffc0, src_id); + KUNIT_EXPECT_EQ(test, RCODE_COMPLETE, rcode); + + serialize_async_header_quadlet_response(header, dst_id, tlabel, retry, tcode, priority, + src_id, rcode); + + KUNIT_EXPECT_MEMEQ(test, header, expected, sizeof(expected) - sizeof(expected[0])); +} + +static void test_async_header_read_quadlet_request(struct kunit *test) +{ + static const u32 expected[ASYNC_HEADER_QUADLET_COUNT] = { + 0xffc0f140, + 0xffc1ffff, + 0xf0000984, + 0x00000000, + }; + u32 header[ASYNC_HEADER_QUADLET_COUNT] = {0, 0, 0, 0}; + + unsigned int dst_id; + unsigned int tlabel; + unsigned int retry; + unsigned int tcode; + unsigned int priority; + unsigned int src_id; + u64 offset; + + deserialize_async_header_quadlet_request(expected, &dst_id, &tlabel, &retry, &tcode, + &priority, &src_id, &offset); + + KUNIT_EXPECT_EQ(test, 0xffc0, dst_id); + KUNIT_EXPECT_EQ(test, 0x3c, tlabel); + KUNIT_EXPECT_EQ(test, 0x01, retry); + KUNIT_EXPECT_EQ(test, TCODE_READ_QUADLET_REQUEST, tcode); + KUNIT_EXPECT_EQ(test, 0x00, priority); + KUNIT_EXPECT_EQ(test, 0xffc1, src_id); + KUNIT_EXPECT_EQ(test, 0xfffff0000984, offset); + + serialize_async_header_quadlet_request(header, dst_id, tlabel, retry, tcode, priority, + src_id, offset); + + KUNIT_EXPECT_MEMEQ(test, header, expected, sizeof(expected)); +} + +static void test_async_header_read_quadlet_response(struct kunit *test) +{ + static const u32 expected[ASYNC_HEADER_QUADLET_COUNT] = { + 0xffc1f160, + 0xffc00000, + 0x00000000, + 0x00000180, + }; + u32 header[ASYNC_HEADER_QUADLET_COUNT] = {0, 0, 0, 0}; + + unsigned int dst_id; + unsigned int tlabel; + unsigned int retry; + unsigned int tcode; + unsigned int priority; + unsigned int src_id; + unsigned int rcode; + u32 quadlet_data; + + deserialize_async_header_quadlet_response(expected, &dst_id, &tlabel, &retry, &tcode, + &priority, &src_id, &rcode); + quadlet_data = async_header_get_quadlet_data(expected); + + KUNIT_EXPECT_EQ(test, 0xffc1, dst_id); + KUNIT_EXPECT_EQ(test, 0x3c, tlabel); + KUNIT_EXPECT_EQ(test, 0x01, retry); + KUNIT_EXPECT_EQ(test, TCODE_READ_QUADLET_RESPONSE, tcode); + KUNIT_EXPECT_EQ(test, 0x00, priority); + KUNIT_EXPECT_EQ(test, 0xffc0, src_id); + KUNIT_EXPECT_EQ(test, RCODE_COMPLETE, rcode); + KUNIT_EXPECT_EQ(test, 0x00000180, quadlet_data); + + serialize_async_header_quadlet_response(header, dst_id, tlabel, retry, tcode, priority, + src_id, rcode); + async_header_set_quadlet_data(header, quadlet_data); + + KUNIT_EXPECT_MEMEQ(test, header, expected, sizeof(expected)); +} + +static void test_async_header_read_block_request(struct kunit *test) +{ + static const u32 expected[ASYNC_HEADER_QUADLET_COUNT] = { + 0xffc0e150, + 0xffc1ffff, + 0xf0000400, + 0x00200000, + }; + u32 header[ASYNC_HEADER_QUADLET_COUNT] = {0, 0, 0, 0}; + + unsigned int dst_id; + unsigned int tlabel; + unsigned int retry; + unsigned int tcode; + unsigned int priority; + unsigned int src_id; + u64 offset; + unsigned int data_length; + unsigned int extended_tcode; + + deserialize_async_header_block_request(expected, &dst_id, &tlabel, &retry, &tcode, + &priority, &src_id, &offset, &data_length, + &extended_tcode); + + KUNIT_EXPECT_EQ(test, 0xffc0, dst_id); + KUNIT_EXPECT_EQ(test, 0x38, tlabel); + KUNIT_EXPECT_EQ(test, 0x01, retry); + KUNIT_EXPECT_EQ(test, TCODE_READ_BLOCK_REQUEST, tcode); + KUNIT_EXPECT_EQ(test, 0x00, priority); + KUNIT_EXPECT_EQ(test, 0xffc1, src_id); + KUNIT_EXPECT_EQ(test, 0xfffff0000400, offset); + KUNIT_EXPECT_EQ(test, 0x0020, data_length); + KUNIT_EXPECT_EQ(test, 0x0000, extended_tcode); + + serialize_async_header_block_request(header, dst_id, tlabel, retry, tcode, priority, src_id, + offset, data_length, extended_tcode); + + KUNIT_EXPECT_MEMEQ(test, header, expected, sizeof(expected)); +} + +static void test_async_header_read_block_response(struct kunit *test) +{ + static const u32 expected[ASYNC_HEADER_QUADLET_COUNT] = { + 0xffc1e170, + 0xffc00000, + 0x00000000, + 0x00200000, + }; + u32 header[ASYNC_HEADER_QUADLET_COUNT] = {0, 0, 0, 0}; + + unsigned int dst_id; + unsigned int tlabel; + unsigned int retry; + unsigned int tcode; + unsigned int priority; + unsigned int src_id; + unsigned int rcode; + unsigned int data_length; + unsigned int extended_tcode; + + deserialize_async_header_block_response(expected, &dst_id, &tlabel, &retry, &tcode, + &priority, &src_id, &rcode, &data_length, + &extended_tcode); + + KUNIT_EXPECT_EQ(test, 0xffc1, dst_id); + KUNIT_EXPECT_EQ(test, 0x38, tlabel); + KUNIT_EXPECT_EQ(test, 0x01, retry); + KUNIT_EXPECT_EQ(test, TCODE_READ_BLOCK_RESPONSE, tcode); + KUNIT_EXPECT_EQ(test, 0x00, priority); + KUNIT_EXPECT_EQ(test, 0xffc0, src_id); + KUNIT_EXPECT_EQ(test, RCODE_COMPLETE, rcode); + KUNIT_EXPECT_EQ(test, 0x0020, data_length); + KUNIT_EXPECT_EQ(test, 0x0000, extended_tcode); + + serialize_async_header_block_response(header, dst_id, tlabel, retry, tcode, priority, + src_id, rcode, data_length, extended_tcode); + + KUNIT_EXPECT_MEMEQ(test, header, expected, sizeof(expected)); +} + +static void test_async_header_lock_request(struct kunit *test) +{ + static const u32 expected[ASYNC_HEADER_QUADLET_COUNT] = { + 0xffc02d90, + 0xffc1ffff, + 0xf0000984, + 0x00080002, + }; + u32 header[ASYNC_HEADER_QUADLET_COUNT] = {0, 0, 0, 0}; + + unsigned int dst_id; + unsigned int tlabel; + unsigned int retry; + unsigned int tcode; + unsigned int priority; + unsigned int src_id; + u64 offset; + unsigned int data_length; + unsigned int extended_tcode; + + deserialize_async_header_block_request(expected, &dst_id, &tlabel, &retry, &tcode, + &priority, &src_id, &offset, &data_length, + &extended_tcode); + + KUNIT_EXPECT_EQ(test, 0xffc0, dst_id); + KUNIT_EXPECT_EQ(test, 0x0b, tlabel); + KUNIT_EXPECT_EQ(test, 0x01, retry); + KUNIT_EXPECT_EQ(test, TCODE_LOCK_REQUEST, tcode); + KUNIT_EXPECT_EQ(test, 0x00, priority); + KUNIT_EXPECT_EQ(test, 0xffc1, src_id); + KUNIT_EXPECT_EQ(test, 0xfffff0000984, offset); + KUNIT_EXPECT_EQ(test, 0x0008, data_length); + KUNIT_EXPECT_EQ(test, EXTCODE_COMPARE_SWAP, extended_tcode); + + serialize_async_header_block_request(header, dst_id, tlabel, retry, tcode, priority, src_id, + offset, data_length, extended_tcode); + + KUNIT_EXPECT_MEMEQ(test, header, expected, sizeof(expected)); +} + +static void test_async_header_lock_response(struct kunit *test) +{ + static const u32 expected[ASYNC_HEADER_QUADLET_COUNT] = { + 0xffc12db0, + 0xffc00000, + 0x00000000, + 0x00040002, + }; + u32 header[ASYNC_HEADER_QUADLET_COUNT] = {0, 0, 0, 0}; + + unsigned int dst_id; + unsigned int tlabel; + unsigned int retry; + unsigned int tcode; + unsigned int priority; + unsigned int src_id; + unsigned int rcode; + unsigned int data_length; + unsigned int extended_tcode; + + deserialize_async_header_block_response(expected, &dst_id, &tlabel, &retry, &tcode, + &priority, &src_id, &rcode, &data_length, + &extended_tcode); + + KUNIT_EXPECT_EQ(test, 0xffc1, dst_id); + KUNIT_EXPECT_EQ(test, 0x0b, tlabel); + KUNIT_EXPECT_EQ(test, 0x01, retry); + KUNIT_EXPECT_EQ(test, TCODE_LOCK_RESPONSE, tcode); + KUNIT_EXPECT_EQ(test, 0x00, priority); + KUNIT_EXPECT_EQ(test, 0xffc0, src_id); + KUNIT_EXPECT_EQ(test, RCODE_COMPLETE, rcode); + KUNIT_EXPECT_EQ(test, 0x0004, data_length); + KUNIT_EXPECT_EQ(test, EXTCODE_COMPARE_SWAP, extended_tcode); + + serialize_async_header_block_response(header, dst_id, tlabel, retry, tcode, priority, + src_id, rcode, data_length, extended_tcode); + + KUNIT_EXPECT_MEMEQ(test, header, expected, sizeof(expected)); +} + + +static struct kunit_case packet_serdes_test_cases[] = { + KUNIT_CASE(test_async_header_write_quadlet_request), + KUNIT_CASE(test_async_header_write_block_request), + KUNIT_CASE(test_async_header_write_response), + KUNIT_CASE(test_async_header_read_quadlet_request), + KUNIT_CASE(test_async_header_read_quadlet_response), + KUNIT_CASE(test_async_header_read_block_request), + KUNIT_CASE(test_async_header_read_block_response), + KUNIT_CASE(test_async_header_lock_request), + KUNIT_CASE(test_async_header_lock_response), + {} +}; + +static struct kunit_suite packet_serdes_test_suite = { + .name = "firewire-packet-serdes", + .test_cases = packet_serdes_test_cases, +}; +kunit_test_suite(packet_serdes_test_suite); + +MODULE_LICENSE("GPL"); -- cgit v1.2.3-58-ga151 From e8cd3e4f2761e9d2c8b023207509aaaf675c9adf Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 28 Apr 2024 16:13:40 +0900 Subject: firewire: core: replace local macros with common inline functions for asynchronous packet header This commit uses common inline functions to serialize and deserialize header of asynchronous packet. Link: https://lore.kernel.org/r/20240428071347.409202-3-o-takashi@sakamocchi.jp Signed-off-by: Takashi Sakamoto --- drivers/firewire/core-transaction.c | 138 +++++++++++++++--------------------- 1 file changed, 56 insertions(+), 82 deletions(-) (limited to 'drivers') diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c index c427b7861eaf..a113f801cf33 100644 --- a/drivers/firewire/core-transaction.c +++ b/drivers/firewire/core-transaction.c @@ -29,29 +29,13 @@ #include #include "core.h" +#include "packet-header-definitions.h" -#define HEADER_PRI(pri) ((pri) << 0) #define HEADER_TCODE(tcode) ((tcode) << 4) -#define HEADER_RETRY(retry) ((retry) << 8) -#define HEADER_TLABEL(tlabel) ((tlabel) << 10) -#define HEADER_DESTINATION(destination) ((destination) << 16) -#define HEADER_SOURCE(source) ((source) << 16) -#define HEADER_RCODE(rcode) ((rcode) << 12) -#define HEADER_OFFSET_HIGH(offset_high) ((offset_high) << 0) #define HEADER_DATA_LENGTH(length) ((length) << 16) -#define HEADER_EXTENDED_TCODE(tcode) ((tcode) << 0) -#define HEADER_GET_TCODE(q) (((q) >> 4) & 0x0f) -#define HEADER_GET_TLABEL(q) (((q) >> 10) & 0x3f) -#define HEADER_GET_RCODE(q) (((q) >> 12) & 0x0f) -#define HEADER_GET_DESTINATION(q) (((q) >> 16) & 0xffff) -#define HEADER_GET_SOURCE(q) (((q) >> 16) & 0xffff) -#define HEADER_GET_OFFSET_HIGH(q) (((q) >> 0) & 0xffff) -#define HEADER_GET_DATA_LENGTH(q) (((q) >> 16) & 0xffff) -#define HEADER_GET_EXTENDED_TCODE(q) (((q) >> 0) & 0xffff) - -#define HEADER_DESTINATION_IS_BROADCAST(q) \ - (((q) & HEADER_DESTINATION(0x3f)) == HEADER_DESTINATION(0x3f)) +#define HEADER_DESTINATION_IS_BROADCAST(header) \ + ((async_header_get_destination(header) & 0x3f) == 0x3f) #define PHY_PACKET_CONFIG 0x0 #define PHY_PACKET_LINK_ON 0x1 @@ -248,28 +232,24 @@ static void fw_fill_request(struct fw_packet *packet, int tcode, int tlabel, } else ext_tcode = 0; - packet->header[0] = - HEADER_RETRY(RETRY_X) | - HEADER_TLABEL(tlabel) | - HEADER_TCODE(tcode) | - HEADER_DESTINATION(destination_id); - packet->header[1] = - HEADER_OFFSET_HIGH(offset >> 32) | HEADER_SOURCE(source_id); - packet->header[2] = - offset; + async_header_set_retry(packet->header, RETRY_X); + async_header_set_tlabel(packet->header, tlabel); + async_header_set_tcode(packet->header, tcode); + async_header_set_destination(packet->header, destination_id); + async_header_set_source(packet->header, source_id); + async_header_set_offset(packet->header, offset); switch (tcode) { case TCODE_WRITE_QUADLET_REQUEST: - packet->header[3] = *(u32 *)payload; + async_header_set_quadlet_data(packet->header, *(u32 *)payload); packet->header_length = 16; packet->payload_length = 0; break; case TCODE_LOCK_REQUEST: case TCODE_WRITE_BLOCK_REQUEST: - packet->header[3] = - HEADER_DATA_LENGTH(length) | - HEADER_EXTENDED_TCODE(ext_tcode); + async_header_set_data_length(packet->header, length); + async_header_set_extended_tcode(packet->header, ext_tcode); packet->header_length = 16; packet->payload = payload; packet->payload_length = length; @@ -281,9 +261,8 @@ static void fw_fill_request(struct fw_packet *packet, int tcode, int tlabel, break; case TCODE_READ_BLOCK_REQUEST: - packet->header[3] = - HEADER_DATA_LENGTH(length) | - HEADER_EXTENDED_TCODE(ext_tcode); + async_header_set_data_length(packet->header, length); + async_header_set_extended_tcode(packet->header, ext_tcode); packet->header_length = 16; packet->payload_length = 0; break; @@ -655,7 +634,7 @@ EXPORT_SYMBOL(fw_core_remove_address_handler); struct fw_request { struct kref kref; struct fw_packet response; - u32 request_header[4]; + u32 request_header[ASYNC_HEADER_QUADLET_COUNT]; int ack; u32 timestamp; u32 length; @@ -695,7 +674,7 @@ int fw_get_response_length(struct fw_request *r) { int tcode, ext_tcode, data_length; - tcode = HEADER_GET_TCODE(r->request_header[0]); + tcode = async_header_get_tcode(r->request_header); switch (tcode) { case TCODE_WRITE_QUADLET_REQUEST: @@ -706,12 +685,12 @@ int fw_get_response_length(struct fw_request *r) return 4; case TCODE_READ_BLOCK_REQUEST: - data_length = HEADER_GET_DATA_LENGTH(r->request_header[3]); + data_length = async_header_get_data_length(r->request_header); return data_length; case TCODE_LOCK_REQUEST: - ext_tcode = HEADER_GET_EXTENDED_TCODE(r->request_header[3]); - data_length = HEADER_GET_DATA_LENGTH(r->request_header[3]); + ext_tcode = async_header_get_extended_tcode(r->request_header); + data_length = async_header_get_data_length(r->request_header); switch (ext_tcode) { case EXTCODE_FETCH_ADD: case EXTCODE_LITTLE_ADD: @@ -731,46 +710,42 @@ void fw_fill_response(struct fw_packet *response, u32 *request_header, { int tcode, tlabel, extended_tcode, source, destination; - tcode = HEADER_GET_TCODE(request_header[0]); - tlabel = HEADER_GET_TLABEL(request_header[0]); - source = HEADER_GET_DESTINATION(request_header[0]); - destination = HEADER_GET_SOURCE(request_header[1]); - extended_tcode = HEADER_GET_EXTENDED_TCODE(request_header[3]); - - response->header[0] = - HEADER_RETRY(RETRY_1) | - HEADER_TLABEL(tlabel) | - HEADER_DESTINATION(destination); - response->header[1] = - HEADER_SOURCE(source) | - HEADER_RCODE(rcode); - response->header[2] = 0; + tcode = async_header_get_tcode(request_header); + tlabel = async_header_get_tlabel(request_header); + source = async_header_get_destination(request_header); // Exchange. + destination = async_header_get_source(request_header); // Exchange. + extended_tcode = async_header_get_extended_tcode(request_header); + + async_header_set_retry(response->header, RETRY_1); + async_header_set_tlabel(response->header, tlabel); + async_header_set_destination(response->header, destination); + async_header_set_source(response->header, source); + async_header_set_rcode(response->header, rcode); + response->header[2] = 0; // The field is reserved. switch (tcode) { case TCODE_WRITE_QUADLET_REQUEST: case TCODE_WRITE_BLOCK_REQUEST: - response->header[0] |= HEADER_TCODE(TCODE_WRITE_RESPONSE); + async_header_set_tcode(response->header, TCODE_WRITE_RESPONSE); response->header_length = 12; response->payload_length = 0; break; case TCODE_READ_QUADLET_REQUEST: - response->header[0] |= - HEADER_TCODE(TCODE_READ_QUADLET_RESPONSE); + async_header_set_tcode(response->header, TCODE_READ_QUADLET_RESPONSE); if (payload != NULL) - response->header[3] = *(u32 *)payload; + async_header_set_quadlet_data(response->header, *(u32 *)payload); else - response->header[3] = 0; + async_header_set_quadlet_data(response->header, 0); response->header_length = 16; response->payload_length = 0; break; case TCODE_READ_BLOCK_REQUEST: case TCODE_LOCK_REQUEST: - response->header[0] |= HEADER_TCODE(tcode + 2); - response->header[3] = - HEADER_DATA_LENGTH(length) | - HEADER_EXTENDED_TCODE(extended_tcode); + async_header_set_tcode(response->header, tcode + 2); + async_header_set_data_length(response->header, length); + async_header_set_extended_tcode(response->header, extended_tcode); response->header_length = 16; response->payload = payload; response->payload_length = length; @@ -807,7 +782,7 @@ static struct fw_request *allocate_request(struct fw_card *card, u32 *data, length; int request_tcode; - request_tcode = HEADER_GET_TCODE(p->header[0]); + request_tcode = async_header_get_tcode(p->header); switch (request_tcode) { case TCODE_WRITE_QUADLET_REQUEST: data = &p->header[3]; @@ -817,7 +792,7 @@ static struct fw_request *allocate_request(struct fw_card *card, case TCODE_WRITE_BLOCK_REQUEST: case TCODE_LOCK_REQUEST: data = p->payload; - length = HEADER_GET_DATA_LENGTH(p->header[3]); + length = async_header_get_data_length(p->header); break; case TCODE_READ_QUADLET_REQUEST: @@ -827,7 +802,7 @@ static struct fw_request *allocate_request(struct fw_card *card, case TCODE_READ_BLOCK_REQUEST: data = NULL; - length = HEADER_GET_DATA_LENGTH(p->header[3]); + length = async_header_get_data_length(p->header); break; default: @@ -872,7 +847,7 @@ void fw_send_response(struct fw_card *card, { /* unified transaction or broadcast transaction: don't respond */ if (request->ack != ACK_PENDING || - HEADER_DESTINATION_IS_BROADCAST(request->request_header[0])) { + HEADER_DESTINATION_IS_BROADCAST(request->request_header)) { fw_request_put(request); return; } @@ -926,11 +901,11 @@ static void handle_exclusive_region_request(struct fw_card *card, struct fw_address_handler *handler; int tcode, destination, source; - destination = HEADER_GET_DESTINATION(p->header[0]); - source = HEADER_GET_SOURCE(p->header[1]); - tcode = HEADER_GET_TCODE(p->header[0]); + destination = async_header_get_destination(p->header); + source = async_header_get_source(p->header); + tcode = async_header_get_tcode(p->header); if (tcode == TCODE_LOCK_REQUEST) - tcode = 0x10 + HEADER_GET_EXTENDED_TCODE(p->header[3]); + tcode = 0x10 + async_header_get_extended_tcode(p->header); rcu_read_lock(); handler = lookup_enclosing_address_handler(&address_handler_list, @@ -963,9 +938,9 @@ static void handle_fcp_region_request(struct fw_card *card, return; } - tcode = HEADER_GET_TCODE(p->header[0]); - destination = HEADER_GET_DESTINATION(p->header[0]); - source = HEADER_GET_SOURCE(p->header[1]); + tcode = async_header_get_tcode(p->header); + destination = async_header_get_destination(p->header); + source = async_header_get_source(p->header); if (tcode != TCODE_WRITE_QUADLET_REQUEST && tcode != TCODE_WRITE_BLOCK_REQUEST) { @@ -997,7 +972,7 @@ void fw_core_handle_request(struct fw_card *card, struct fw_packet *p) if (p->ack != ACK_PENDING && p->ack != ACK_COMPLETE) return; - if (TCODE_IS_LINK_INTERNAL(HEADER_GET_TCODE(p->header[0]))) { + if (TCODE_IS_LINK_INTERNAL(async_header_get_tcode(p->header))) { fw_cdev_handle_phy_packet(card, p); return; } @@ -1008,8 +983,7 @@ void fw_core_handle_request(struct fw_card *card, struct fw_packet *p) return; } - offset = ((u64)HEADER_GET_OFFSET_HIGH(p->header[1]) << 32) | - p->header[2]; + offset = async_header_get_offset(p->header); if (!is_in_fcp_region(offset, request->length)) handle_exclusive_region_request(card, p, request, offset); @@ -1027,10 +1001,10 @@ void fw_core_handle_response(struct fw_card *card, struct fw_packet *p) size_t data_length; int tcode, tlabel, source, rcode; - tcode = HEADER_GET_TCODE(p->header[0]); - tlabel = HEADER_GET_TLABEL(p->header[0]); - source = HEADER_GET_SOURCE(p->header[1]); - rcode = HEADER_GET_RCODE(p->header[1]); + tcode = async_header_get_tcode(p->header); + tlabel = async_header_get_tlabel(p->header); + source = async_header_get_source(p->header); + rcode = async_header_get_rcode(p->header); spin_lock_irqsave(&card->lock, flags); list_for_each_entry(iter, &card->transaction_list, link) { @@ -1073,7 +1047,7 @@ void fw_core_handle_response(struct fw_card *card, struct fw_packet *p) case TCODE_READ_BLOCK_RESPONSE: case TCODE_LOCK_RESPONSE: data = p->payload; - data_length = HEADER_GET_DATA_LENGTH(p->header[3]); + data_length = async_header_get_data_length(p->header); break; default: -- cgit v1.2.3-58-ga151 From 1162825c9c155c20a93249051135970f4faeea82 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 28 Apr 2024 16:13:41 +0900 Subject: firewire: ohci: replace local macros with common inline functions for asynchronous packet header This commit uses the common inline functions to serialize and deserialize header of asynchronous packet. Link: https://lore.kernel.org/r/20240428071347.409202-4-o-takashi@sakamocchi.jp Signed-off-by: Takashi Sakamoto --- drivers/firewire/ohci.c | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index 0de45baf3569..5a12223a1d91 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -40,6 +40,7 @@ #include "core.h" #include "ohci.h" +#include "packet-header-definitions.h" #define ohci_info(ohci, f, args...) dev_info(ohci->card.device, f, ##args) #define ohci_notice(ohci, f, args...) dev_notice(ohci->card.device, f, ##args) @@ -1550,12 +1551,6 @@ static int handle_at_packet(struct context *context, return 1; } -#define HEADER_GET_DESTINATION(q) (((q) >> 16) & 0xffff) -#define HEADER_GET_TCODE(q) (((q) >> 4) & 0x0f) -#define HEADER_GET_OFFSET_HIGH(q) (((q) >> 0) & 0xffff) -#define HEADER_GET_DATA_LENGTH(q) (((q) >> 16) & 0xffff) -#define HEADER_GET_EXTENDED_TCODE(q) (((q) >> 0) & 0xffff) - static u32 get_cycle_time(struct fw_ohci *ohci); static void handle_local_rom(struct fw_ohci *ohci, @@ -1564,9 +1559,9 @@ static void handle_local_rom(struct fw_ohci *ohci, struct fw_packet response; int tcode, length, i; - tcode = HEADER_GET_TCODE(packet->header[0]); + tcode = async_header_get_tcode(packet->header); if (TCODE_IS_BLOCK_PACKET(tcode)) - length = HEADER_GET_DATA_LENGTH(packet->header[3]); + length = async_header_get_data_length(packet->header); else length = 4; @@ -1595,10 +1590,10 @@ static void handle_local_lock(struct fw_ohci *ohci, __be32 *payload, lock_old; u32 lock_arg, lock_data; - tcode = HEADER_GET_TCODE(packet->header[0]); - length = HEADER_GET_DATA_LENGTH(packet->header[3]); + tcode = async_header_get_tcode(packet->header); + length = async_header_get_data_length(packet->header); payload = packet->payload; - ext_tcode = HEADER_GET_EXTENDED_TCODE(packet->header[3]); + ext_tcode = async_header_get_extended_tcode(packet->header); if (tcode == TCODE_LOCK_REQUEST && ext_tcode == EXTCODE_COMPARE_SWAP && length == 8) { @@ -1646,10 +1641,7 @@ static void handle_local_request(struct context *ctx, struct fw_packet *packet) packet->callback(packet, &ctx->ohci->card, packet->ack); } - offset = - ((unsigned long long) - HEADER_GET_OFFSET_HIGH(packet->header[1]) << 32) | - packet->header[2]; + offset = async_header_get_offset(packet->header); csr = offset - CSR_REGISTER_BASE; /* Handle config rom reads. */ @@ -1683,7 +1675,7 @@ static void at_context_transmit(struct context *ctx, struct fw_packet *packet) spin_lock_irqsave(&ctx->ohci->lock, flags); - if (HEADER_GET_DESTINATION(packet->header[0]) == ctx->ohci->node_id && + if (async_header_get_destination(packet->header) == ctx->ohci->node_id && ctx->ohci->generation == packet->generation) { spin_unlock_irqrestore(&ctx->ohci->lock, flags); -- cgit v1.2.3-58-ga151 From 4af43614186815cc026925aa4f612fb4ebfce02c Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 28 Apr 2024 16:13:42 +0900 Subject: firewire: ohci: replace hard-coded values with inline functions for asynchronous packet header This commit replaces the hard-coded values with the common inline functions to serialize and deserialize the header of asynchronous packet. Link: https://lore.kernel.org/r/20240428071347.409202-5-o-takashi@sakamocchi.jp Signed-off-by: Takashi Sakamoto --- drivers/firewire/ohci.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index 5a12223a1d91..52afed803814 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -517,14 +517,14 @@ static const char *tcodes[] = { static void log_ar_at_event(struct fw_ohci *ohci, char dir, int speed, u32 *header, int evt) { - int tcode = header[0] >> 4 & 0xf; + int tcode = async_header_get_tcode(header); char specific[12]; if (likely(!(param_debug & OHCI_PARAM_DEBUG_AT_AR))) return; if (unlikely(evt >= ARRAY_SIZE(evts))) - evt = 0x1f; + evt = 0x1f; if (evt == OHCI1394_evt_bus_reset) { ohci_notice(ohci, "A%c evt_bus_reset, generation %d\n", @@ -539,7 +539,8 @@ static void log_ar_at_event(struct fw_ohci *ohci, break; case 0x1: case 0x5: case 0x7: case 0x9: case 0xb: snprintf(specific, sizeof(specific), " %x,%x", - header[3] >> 16, header[3] & 0xffff); + async_header_get_data_length(header), + async_header_get_extended_tcode(header)); break; default: specific[0] = '\0'; @@ -556,17 +557,17 @@ static void log_ar_at_event(struct fw_ohci *ohci, break; case 0x0: case 0x1: case 0x4: case 0x5: case 0x9: ohci_notice(ohci, - "A%c spd %x tl %02x, %04x -> %04x, %s, %s, %04x%08x%s\n", - dir, speed, header[0] >> 10 & 0x3f, - header[1] >> 16, header[0] >> 16, evts[evt], - tcodes[tcode], header[1] & 0xffff, header[2], specific); + "A%c spd %x tl %02x, %04x -> %04x, %s, %s, %012llx%s\n", + dir, speed, async_header_get_tlabel(header), + async_header_get_source(header), async_header_get_destination(header), + evts[evt], tcodes[tcode], async_header_get_offset(header), specific); break; default: ohci_notice(ohci, "A%c spd %x tl %02x, %04x -> %04x, %s, %s%s\n", - dir, speed, header[0] >> 10 & 0x3f, - header[1] >> 16, header[0] >> 16, evts[evt], - tcodes[tcode], specific); + dir, speed, async_header_get_tlabel(header), + async_header_get_source(header), async_header_get_destination(header), + evts[evt], tcodes[tcode], specific); } } @@ -854,7 +855,7 @@ static __le32 *handle_ar_packet(struct ar_context *ctx, __le32 *buffer) p.header[1] = cond_le32_to_cpu(buffer[1]); p.header[2] = cond_le32_to_cpu(buffer[2]); - tcode = (p.header[0] >> 4) & 0x0f; + tcode = async_header_get_tcode(p.header); switch (tcode) { case TCODE_WRITE_QUADLET_REQUEST: case TCODE_READ_QUADLET_RESPONSE: @@ -875,7 +876,7 @@ static __le32 *handle_ar_packet(struct ar_context *ctx, __le32 *buffer) case TCODE_LOCK_RESPONSE: p.header[3] = cond_le32_to_cpu(buffer[3]); p.header_length = 16; - p.payload_length = p.header[3] >> 16; + p.payload_length = async_header_get_data_length(p.header); if (p.payload_length > MAX_ASYNC_PAYLOAD) { ar_context_abort(ctx, "invalid packet length"); return NULL; @@ -912,8 +913,7 @@ static __le32 *handle_ar_packet(struct ar_context *ctx, __le32 *buffer) * Several controllers, notably from NEC and VIA, forget to * write ack_complete status at PHY packet reception. */ - if (evt == OHCI1394_evt_no_status && - (p.header[0] & 0xff) == (OHCI1394_phy_tcode << 4)) + if (evt == OHCI1394_evt_no_status && tcode == OHCI1394_phy_tcode) p.ack = ACK_COMPLETE; /* @@ -1354,7 +1354,7 @@ static int at_context_queue_packet(struct context *ctx, * accordingly. */ - tcode = (packet->header[0] >> 4) & 0x0f; + tcode = async_header_get_tcode(packet->header); header = (__le32 *) &d[1]; switch (tcode) { case TCODE_WRITE_QUADLET_REQUEST: -- cgit v1.2.3-58-ga151 From 2a0b46a988267bcbd50af76e66fc35f83507f6a8 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 28 Apr 2024 16:13:43 +0900 Subject: firewire: ohci: replace hard-coded values with common macros In the helper function for logging in 1394 ohci driver includes the hard-coded variables for transaction code. They can be replaced with the enumerations in UAPI header. Link: https://lore.kernel.org/r/20240428071347.409202-6-o-takashi@sakamocchi.jp Signed-off-by: Takashi Sakamoto --- drivers/firewire/ohci.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index 52afed803814..c2d3dc7fbe6e 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -533,11 +533,17 @@ static void log_ar_at_event(struct fw_ohci *ohci, } switch (tcode) { - case 0x0: case 0x6: case 0x8: + case TCODE_WRITE_QUADLET_REQUEST: + case TCODE_READ_QUADLET_RESPONSE: + case TCODE_CYCLE_START: snprintf(specific, sizeof(specific), " = %08x", be32_to_cpu((__force __be32)header[3])); break; - case 0x1: case 0x5: case 0x7: case 0x9: case 0xb: + case TCODE_WRITE_BLOCK_REQUEST: + case TCODE_READ_BLOCK_REQUEST: + case TCODE_READ_BLOCK_RESPONSE: + case TCODE_LOCK_REQUEST: + case TCODE_LOCK_RESPONSE: snprintf(specific, sizeof(specific), " %x,%x", async_header_get_data_length(header), async_header_get_extended_tcode(header)); @@ -547,7 +553,7 @@ static void log_ar_at_event(struct fw_ohci *ohci, } switch (tcode) { - case 0xa: + case TCODE_STREAM_DATA: ohci_notice(ohci, "A%c %s, %s\n", dir, evts[evt], tcodes[tcode]); break; @@ -555,7 +561,11 @@ static void log_ar_at_event(struct fw_ohci *ohci, ohci_notice(ohci, "A%c %s, PHY %08x %08x\n", dir, evts[evt], header[1], header[2]); break; - case 0x0: case 0x1: case 0x4: case 0x5: case 0x9: + case TCODE_WRITE_QUADLET_REQUEST: + case TCODE_WRITE_BLOCK_REQUEST: + case TCODE_READ_QUADLET_REQUEST: + case TCODE_READ_BLOCK_REQUEST: + case TCODE_LOCK_REQUEST: ohci_notice(ohci, "A%c spd %x tl %02x, %04x -> %04x, %s, %s, %012llx%s\n", dir, speed, async_header_get_tlabel(header), -- cgit v1.2.3-58-ga151 From c5deb01849688fd5d9dd5113e81a7426b78bf02c Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 28 Apr 2024 16:13:44 +0900 Subject: firewire: core: obsolete tcode check macros with inline functions This commit declares the helper functions to check tcode to obsolete the functional macros. Link: https://lore.kernel.org/r/20240428071347.409202-7-o-takashi@sakamocchi.jp Signed-off-by: Takashi Sakamoto --- drivers/firewire/core-transaction.c | 4 ++-- drivers/firewire/core.h | 21 ++++++++++++++------- drivers/firewire/ohci.c | 6 +++--- 3 files changed, 19 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c index a113f801cf33..45ea15342ab8 100644 --- a/drivers/firewire/core-transaction.c +++ b/drivers/firewire/core-transaction.c @@ -972,7 +972,7 @@ void fw_core_handle_request(struct fw_card *card, struct fw_packet *p) if (p->ack != ACK_PENDING && p->ack != ACK_COMPLETE) return; - if (TCODE_IS_LINK_INTERNAL(async_header_get_tcode(p->header))) { + if (tcode_is_link_internal(async_header_get_tcode(p->header))) { fw_cdev_handle_phy_packet(card, p); return; } @@ -1109,7 +1109,7 @@ static void handle_topology_map(struct fw_card *card, struct fw_request *request { int start; - if (!TCODE_IS_READ_REQUEST(tcode)) { + if (!tcode_is_read_request(tcode)) { fw_send_response(card, request, RCODE_TYPE_ERROR); return; } diff --git a/drivers/firewire/core.h b/drivers/firewire/core.h index ff96e5456b5d..5097c7a270b4 100644 --- a/drivers/firewire/core.h +++ b/drivers/firewire/core.h @@ -225,13 +225,20 @@ static inline bool is_next_generation(int new_generation, int old_generation) #define TCODE_LINK_INTERNAL 0xe -#define TCODE_IS_READ_REQUEST(tcode) (((tcode) & ~1) == 4) -#define TCODE_IS_BLOCK_PACKET(tcode) (((tcode) & 1) != 0) -#define TCODE_IS_LINK_INTERNAL(tcode) ((tcode) == TCODE_LINK_INTERNAL) -#define TCODE_IS_REQUEST(tcode) (((tcode) & 2) == 0) -#define TCODE_IS_RESPONSE(tcode) (((tcode) & 2) != 0) -#define TCODE_HAS_REQUEST_DATA(tcode) (((tcode) & 12) != 4) -#define TCODE_HAS_RESPONSE_DATA(tcode) (((tcode) & 12) != 0) +static inline bool tcode_is_read_request(unsigned int tcode) +{ + return (tcode & ~1u) == 4u; +} + +static inline bool tcode_is_block_packet(unsigned int tcode) +{ + return (tcode & 1u) != 0u; +} + +static inline bool tcode_is_link_internal(unsigned int tcode) +{ + return (tcode == TCODE_LINK_INTERNAL); +} #define LOCAL_BUS 0xffc0 diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index c2d3dc7fbe6e..c8891aa70a51 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -1382,7 +1382,7 @@ static int at_context_queue_packet(struct context *ctx, (packet->header[0] & 0xffff0000)); header[2] = cpu_to_le32(packet->header[2]); - if (TCODE_IS_BLOCK_PACKET(tcode)) + if (tcode_is_block_packet(tcode)) header[3] = cpu_to_le32(packet->header[3]); else header[3] = (__force __le32) packet->header[3]; @@ -1570,7 +1570,7 @@ static void handle_local_rom(struct fw_ohci *ohci, int tcode, length, i; tcode = async_header_get_tcode(packet->header); - if (TCODE_IS_BLOCK_PACKET(tcode)) + if (tcode_is_block_packet(tcode)) length = async_header_get_data_length(packet->header); else length = 4; @@ -1579,7 +1579,7 @@ static void handle_local_rom(struct fw_ohci *ohci, if (i + length > CONFIG_ROM_SIZE) { fw_fill_response(&response, packet->header, RCODE_ADDRESS_ERROR, NULL, 0); - } else if (!TCODE_IS_READ_REQUEST(tcode)) { + } else if (!tcode_is_read_request(tcode)) { fw_fill_response(&response, packet->header, RCODE_TYPE_ERROR, NULL, 0); } else { -- cgit v1.2.3-58-ga151 From 6503df36128b56685367172ebb7b0765c466f485 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 28 Apr 2024 16:13:45 +0900 Subject: firewire: core: add common macro to serialize/deserialize isochronous packet header The packet for Asynchronous Streaming Packet includes the same header fields as the isochronous packet has. It is helpful to have some helper functions to serialize/deserialize them. This commit adds such helper functions with their test. Link: https://lore.kernel.org/r/20240428071347.409202-8-o-takashi@sakamocchi.jp Signed-off-by: Takashi Sakamoto --- drivers/firewire/packet-header-definitions.h | 66 ++++++++++++++++++++++++++++ drivers/firewire/packet-serdes-test.c | 44 +++++++++++++++++++ 2 files changed, 110 insertions(+) (limited to 'drivers') diff --git a/drivers/firewire/packet-header-definitions.h b/drivers/firewire/packet-header-definitions.h index 83e550427706..ab9d0fa790d4 100644 --- a/drivers/firewire/packet-header-definitions.h +++ b/drivers/firewire/packet-header-definitions.h @@ -165,4 +165,70 @@ static inline void async_header_set_extended_tcode(u32 header[ASYNC_HEADER_QUADL header[3] |= (((u32)extended_tcode) << ASYNC_HEADER_Q3_EXTENDED_TCODE_SHIFT) & ASYNC_HEADER_Q3_EXTENDED_TCODE_MASK; } +#define ISOC_HEADER_DATA_LENGTH_SHIFT 16 +#define ISOC_HEADER_DATA_LENGTH_MASK 0xffff0000 +#define ISOC_HEADER_TAG_SHIFT 14 +#define ISOC_HEADER_TAG_MASK 0x0000c000 +#define ISOC_HEADER_CHANNEL_SHIFT 8 +#define ISOC_HEADER_CHANNEL_MASK 0x00003f00 +#define ISOC_HEADER_TCODE_SHIFT 4 +#define ISOC_HEADER_TCODE_MASK 0x000000f0 +#define ISOC_HEADER_SY_SHIFT 0 +#define ISOC_HEADER_SY_MASK 0x0000000f + +static inline unsigned int isoc_header_get_data_length(u32 header) +{ + return (header & ISOC_HEADER_DATA_LENGTH_MASK) >> ISOC_HEADER_DATA_LENGTH_SHIFT; +} + +static inline unsigned int isoc_header_get_tag(u32 header) +{ + return (header & ISOC_HEADER_TAG_MASK) >> ISOC_HEADER_TAG_SHIFT; +} + +static inline unsigned int isoc_header_get_channel(u32 header) +{ + return (header & ISOC_HEADER_CHANNEL_MASK) >> ISOC_HEADER_CHANNEL_SHIFT; +} + +static inline unsigned int isoc_header_get_tcode(u32 header) +{ + return (header & ISOC_HEADER_TCODE_MASK) >> ISOC_HEADER_TCODE_SHIFT; +} + +static inline unsigned int isoc_header_get_sy(u32 header) +{ + return (header & ISOC_HEADER_SY_MASK) >> ISOC_HEADER_SY_SHIFT; +} + +static inline void isoc_header_set_data_length(u32 *header, unsigned int data_length) +{ + *header &= ~ISOC_HEADER_DATA_LENGTH_MASK; + *header |= (((u32)data_length) << ISOC_HEADER_DATA_LENGTH_SHIFT) & ISOC_HEADER_DATA_LENGTH_MASK; +} + +static inline void isoc_header_set_tag(u32 *header, unsigned int tag) +{ + *header &= ~ISOC_HEADER_TAG_MASK; + *header |= (((u32)tag) << ISOC_HEADER_TAG_SHIFT) & ISOC_HEADER_TAG_MASK; +} + +static inline void isoc_header_set_channel(u32 *header, unsigned int channel) +{ + *header &= ~ISOC_HEADER_CHANNEL_MASK; + *header |= (((u32)channel) << ISOC_HEADER_CHANNEL_SHIFT) & ISOC_HEADER_CHANNEL_MASK; +} + +static inline void isoc_header_set_tcode(u32 *header, unsigned int tcode) +{ + *header &= ~ISOC_HEADER_TCODE_MASK; + *header |= (((u32)tcode) << ISOC_HEADER_TCODE_SHIFT) & ISOC_HEADER_TCODE_MASK; +} + +static inline void isoc_header_set_sy(u32 *header, unsigned int sy) +{ + *header &= ~ISOC_HEADER_SY_MASK; + *header |= (((u32)sy) << ISOC_HEADER_SY_SHIFT) & ISOC_HEADER_SY_MASK; +} + #endif // _FIREWIRE_PACKET_HEADER_DEFINITIONS_H diff --git a/drivers/firewire/packet-serdes-test.c b/drivers/firewire/packet-serdes-test.c index 299e9f908463..f93c966e794d 100644 --- a/drivers/firewire/packet-serdes-test.c +++ b/drivers/firewire/packet-serdes-test.c @@ -167,6 +167,26 @@ static void deserialize_async_header_block_response(const u32 header[ASYNC_HEADE *extended_tcode = async_header_get_extended_tcode(header); } +static void serialize_isoc_header(u32 *header, unsigned int data_length, unsigned int tag, + unsigned int channel, unsigned int tcode, unsigned int sy) +{ + isoc_header_set_data_length(header, data_length); + isoc_header_set_tag(header, tag); + isoc_header_set_channel(header, channel); + isoc_header_set_tcode(header, tcode); + isoc_header_set_sy(header, sy); +} + +static void deserialize_isoc_header(u32 header, unsigned int *data_length, unsigned int *tag, + unsigned int *channel, unsigned int *tcode, unsigned int *sy) +{ + *data_length = isoc_header_get_data_length(header); + *tag = isoc_header_get_tag(header); + *channel = isoc_header_get_channel(header); + *tcode = isoc_header_get_tcode(header); + *sy = isoc_header_get_sy(header); +} + static void test_async_header_write_quadlet_request(struct kunit *test) { static const u32 expected[ASYNC_HEADER_QUADLET_COUNT] = { @@ -515,6 +535,29 @@ static void test_async_header_lock_response(struct kunit *test) KUNIT_EXPECT_MEMEQ(test, header, expected, sizeof(expected)); } +static void test_isoc_header(struct kunit *test) +{ + const u32 expected = 0x00d08dec; + u32 header = 0; + + unsigned int data_length; + unsigned int tag; + unsigned int channel; + unsigned int tcode; + unsigned int sy; + + deserialize_isoc_header(expected, &data_length, &tag, &channel, &tcode, &sy); + + KUNIT_EXPECT_EQ(test, 0xd0, data_length); + KUNIT_EXPECT_EQ(test, 0x02, tag); + KUNIT_EXPECT_EQ(test, 0x0d, channel); + KUNIT_EXPECT_EQ(test, 0x0e, tcode); + KUNIT_EXPECT_EQ(test, 0x0c, sy); + + serialize_isoc_header(&header, data_length, tag, channel, tcode, sy); + + KUNIT_EXPECT_EQ(test, header, expected); +} static struct kunit_case packet_serdes_test_cases[] = { KUNIT_CASE(test_async_header_write_quadlet_request), @@ -526,6 +569,7 @@ static struct kunit_case packet_serdes_test_cases[] = { KUNIT_CASE(test_async_header_read_block_response), KUNIT_CASE(test_async_header_lock_request), KUNIT_CASE(test_async_header_lock_response), + KUNIT_CASE(test_isoc_header), {} }; -- cgit v1.2.3-58-ga151 From aa5c5edc08c5f92753e9182c6d5f9e8caa2466d9 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 28 Apr 2024 16:13:46 +0900 Subject: firewire: core: replace local macros with common inline functions for isochronous packet header This commit replaces the local macros with the common inline functions to serialize the packer header for Asynchronous Streaming Packet. Link: https://lore.kernel.org/r/20240428071347.409202-9-o-takashi@sakamocchi.jp Signed-off-by: Takashi Sakamoto --- drivers/firewire/core-transaction.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c index 45ea15342ab8..3ecb0b945083 100644 --- a/drivers/firewire/core-transaction.c +++ b/drivers/firewire/core-transaction.c @@ -31,9 +31,6 @@ #include "core.h" #include "packet-header-definitions.h" -#define HEADER_TCODE(tcode) ((tcode) << 4) -#define HEADER_DATA_LENGTH(length) ((length) << 16) - #define HEADER_DESTINATION_IS_BROADCAST(header) \ ((async_header_get_destination(header) & 0x3f) == 0x3f) @@ -215,10 +212,11 @@ static void fw_fill_request(struct fw_packet *packet, int tcode, int tlabel, int ext_tcode; if (tcode == TCODE_STREAM_DATA) { - packet->header[0] = - HEADER_DATA_LENGTH(length) | - destination_id | - HEADER_TCODE(TCODE_STREAM_DATA); + // The value of destination_id argument should include tag, channel, and sy fields + // as isochronous packet header has. + packet->header[0] = destination_id; + isoc_header_set_data_length(packet->header, length); + isoc_header_set_tcode(packet->header, TCODE_STREAM_DATA); packet->header_length = 4; packet->payload = payload; packet->payload_length = length; -- cgit v1.2.3-58-ga151 From 57614c28843d4ec34c12ca67dd11411396aab55d Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Mon, 29 Apr 2024 13:32:14 +0900 Subject: firewire: core: add support for Linux kernel tracepoints The Linux Kernel Tracepoints framework is enough useful to trace packet data inbound to and outbound from core. This commit adds firewire subsystem to use the framework. Link: https://lore.kernel.org/r/20240429043218.609398-2-o-takashi@sakamocchi.jp Signed-off-by: Takashi Sakamoto --- drivers/firewire/Makefile | 2 +- drivers/firewire/core-trace.c | 5 +++++ include/trace/events/firewire.h | 15 +++++++++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 drivers/firewire/core-trace.c create mode 100644 include/trace/events/firewire.h (limited to 'drivers') diff --git a/drivers/firewire/Makefile b/drivers/firewire/Makefile index bbde29a0fba6..013e1f2641bd 100644 --- a/drivers/firewire/Makefile +++ b/drivers/firewire/Makefile @@ -3,7 +3,7 @@ # Makefile for the Linux IEEE 1394 implementation # -firewire-core-y += core-card.o core-cdev.o core-device.o \ +firewire-core-y += core-trace.o core-card.o core-cdev.o core-device.o \ core-iso.o core-topology.o core-transaction.o firewire-ohci-y += ohci.o firewire-sbp2-y += sbp2.o diff --git a/drivers/firewire/core-trace.c b/drivers/firewire/core-trace.c new file mode 100644 index 000000000000..96cbd9d384dc --- /dev/null +++ b/drivers/firewire/core-trace.c @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright (c) 2024 Takashi Sakamoto + +#define CREATE_TRACE_POINTS +#include diff --git a/include/trace/events/firewire.h b/include/trace/events/firewire.h new file mode 100644 index 000000000000..bc55eaabf695 --- /dev/null +++ b/include/trace/events/firewire.h @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright (c) 2024 Takashi Sakamoto + +#define TRACE_SYSTEM firewire + +#if !defined(_FIREWIRE_TRACE_EVENT_H) || defined(TRACE_HEADER_MULTI_READ) +#define _FIREWIRE_TRACE_EVENT_H + +#include + +// Placeholder for future use. + +#endif // _FIREWIRE_TRACE_EVENT_H + +#include -- cgit v1.2.3-58-ga151 From 944b06840a73a23c096b2582b960a0a1e3678d43 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Mon, 29 Apr 2024 13:32:15 +0900 Subject: firewire: core: add tracepoints events for asynchronous outbound request In a view of core transaction service, the asynchronous outbound request consists of two stages; initiation and completion. This commit adds a pair of event for them. The following example is for asynchronous lock request with compare_swap code to offset 0x'ffff'f000'0904 in node 0xffc0. async_request_outbound_initiate: \ transaction=0xffff955fc6a07a10 generation=5 scode=2 dst_id=0xffc0 \ tlabel=54 tcode=9 src_id=0xffc1 offset=0xfffff0000904 \ header={0xffc0d990,0xffc1ffff,0xf0000904,0x80002} data={0x80,0x940181} async_request_outbound_complete: \ transaction=0xffff955fc6a07a10 generation=5 scode=2 status=2 \ timestamp=0xd887 Link: https://lore.kernel.org/r/20240429043218.609398-3-o-takashi@sakamocchi.jp Signed-off-by: Takashi Sakamoto --- drivers/firewire/core-transaction.c | 7 +++ include/trace/events/firewire.h | 103 +++++++++++++++++++++++++++++++++++- 2 files changed, 109 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c index 3ecb0b945083..c9318024386f 100644 --- a/drivers/firewire/core-transaction.c +++ b/drivers/firewire/core-transaction.c @@ -29,6 +29,7 @@ #include #include "core.h" +#include #include "packet-header-definitions.h" #define HEADER_DESTINATION_IS_BROADCAST(header) \ @@ -173,6 +174,9 @@ static void transmit_complete_callback(struct fw_packet *packet, struct fw_transaction *t = container_of(packet, struct fw_transaction, packet); + trace_async_request_outbound_complete((uintptr_t)t, packet->generation, packet->speed, + status, packet->timestamp); + switch (status) { case ACK_COMPLETE: close_transaction(t, card, RCODE_COMPLETE, packet->timestamp); @@ -394,6 +398,9 @@ void __fw_send_request(struct fw_card *card, struct fw_transaction *t, int tcode spin_unlock_irqrestore(&card->lock, flags); + trace_async_request_outbound_initiate((uintptr_t)t, generation, speed, t->packet.header, payload, + tcode_is_read_request(tcode) ? 0 : length / 4); + card->driver->send_request(card, &t->packet); } EXPORT_SYMBOL_GPL(__fw_send_request); diff --git a/include/trace/events/firewire.h b/include/trace/events/firewire.h index bc55eaabf695..063695874cfb 100644 --- a/include/trace/events/firewire.h +++ b/include/trace/events/firewire.h @@ -7,8 +7,109 @@ #define _FIREWIRE_TRACE_EVENT_H #include +#include -// Placeholder for future use. +#include + +#include "../../../drivers/firewire/packet-header-definitions.h" + +// The content of TP_printk field is preprocessed, then put to the module binary. +#define ASYNC_HEADER_GET_DESTINATION(header) \ + (((header)[0] & ASYNC_HEADER_Q0_DESTINATION_MASK) >> ASYNC_HEADER_Q0_DESTINATION_SHIFT) + +#define ASYNC_HEADER_GET_TLABEL(header) \ + (((header)[0] & ASYNC_HEADER_Q0_TLABEL_MASK) >> ASYNC_HEADER_Q0_TLABEL_SHIFT) + +#define ASYNC_HEADER_GET_TCODE(header) \ + (((header)[0] & ASYNC_HEADER_Q0_TCODE_MASK) >> ASYNC_HEADER_Q0_TCODE_SHIFT) + +#define ASYNC_HEADER_GET_SOURCE(header) \ + (((header)[1] & ASYNC_HEADER_Q1_SOURCE_MASK) >> ASYNC_HEADER_Q1_SOURCE_SHIFT) + +#define ASYNC_HEADER_GET_OFFSET(header) \ + ((((unsigned long long)((header)[1] & ASYNC_HEADER_Q1_OFFSET_HIGH_MASK)) >> ASYNC_HEADER_Q1_OFFSET_HIGH_SHIFT) << 32)| \ + (header)[2] + +#define QUADLET_SIZE 4 + +DECLARE_EVENT_CLASS(async_outbound_initiate_template, + TP_PROTO(u64 transaction, unsigned int generation, unsigned int scode, const u32 *header, const u32 *data, unsigned int data_count), + TP_ARGS(transaction, generation, scode, header, data, data_count), + TP_STRUCT__entry( + __field(u64, transaction) + __field(u8, generation) + __field(u8, scode) + __array(u32, header, ASYNC_HEADER_QUADLET_COUNT) + __dynamic_array(u32, data, data_count) + ), + TP_fast_assign( + __entry->transaction = transaction; + __entry->generation = generation; + __entry->scode = scode; + memcpy(__entry->header, header, QUADLET_SIZE * ASYNC_HEADER_QUADLET_COUNT); + memcpy(__get_dynamic_array(data), data, __get_dynamic_array_len(data)); + ), + // This format is for the request subaction. + TP_printk( + "transaction=0x%llx generation=%u scode=%u dst_id=0x%04x tlabel=%u tcode=%u src_id=0x%04x offset=0x%012llx header=%s data=%s", + __entry->transaction, + __entry->generation, + __entry->scode, + ASYNC_HEADER_GET_DESTINATION(__entry->header), + ASYNC_HEADER_GET_TLABEL(__entry->header), + ASYNC_HEADER_GET_TCODE(__entry->header), + ASYNC_HEADER_GET_SOURCE(__entry->header), + ASYNC_HEADER_GET_OFFSET(__entry->header), + __print_array(__entry->header, ASYNC_HEADER_QUADLET_COUNT, QUADLET_SIZE), + __print_array(__get_dynamic_array(data), + __get_dynamic_array_len(data) / QUADLET_SIZE, QUADLET_SIZE) + ) +); + +// The value of status is one of ack codes and rcodes specific to Linux FireWire subsystem. +DECLARE_EVENT_CLASS(async_outbound_complete_template, + TP_PROTO(u64 transaction, unsigned int generation, unsigned int scode, unsigned int status, unsigned int timestamp), + TP_ARGS(transaction, generation, scode, status, timestamp), + TP_STRUCT__entry( + __field(u64, transaction) + __field(u8, generation) + __field(u8, scode) + __field(u8, status) + __field(u16, timestamp) + ), + TP_fast_assign( + __entry->transaction = transaction; + __entry->generation = generation; + __entry->scode = scode; + __entry->status = status; + __entry->timestamp = timestamp; + ), + TP_printk( + "transaction=0x%llx generation=%u scode=%u status=%u timestamp=0x%04x", + __entry->transaction, + __entry->generation, + __entry->scode, + __entry->status, + __entry->timestamp + ) +); + +DEFINE_EVENT(async_outbound_initiate_template, async_request_outbound_initiate, + TP_PROTO(u64 transaction, unsigned int generation, unsigned int scode, const u32 *header, const u32 *data, unsigned int data_count), + TP_ARGS(transaction, generation, scode, header, data, data_count) +); + +DEFINE_EVENT(async_outbound_complete_template, async_request_outbound_complete, + TP_PROTO(u64 transaction, unsigned int generation, unsigned int scode, unsigned int status, unsigned int timestamp), + TP_ARGS(transaction, generation, scode, status, timestamp) +); + +#undef ASYNC_HEADER_GET_DESTINATION +#undef ASYNC_HEADER_GET_TLABEL +#undef ASYNC_HEADER_GET_TCODE +#undef ASYNC_HEADER_GET_SOURCE +#undef ASYNC_HEADER_GET_OFFSET +#undef QUADLET_SIZE #endif // _FIREWIRE_TRACE_EVENT_H -- cgit v1.2.3-58-ga151 From 06cc078c078e58402dd42cdffe95872bf4c97c90 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Mon, 29 Apr 2024 13:32:16 +0900 Subject: firewire: core: add tracepoints event for asynchronous inbound response In the transaction of IEEE 1394, the node to receive the asynchronous request transfers any response packet to the requester except for the unified transaction. This commit adds an event for the inbound packet. Note that the code to decode the packet header is moved, against the note about the sanity check. The following example is for asynchronous lock response with compare_and_swap code. async_response_inbound: \ transaction=0xffff955fc6a07a10 generation=5 scode=2 status=1 \ timestamp=0x0089 dst_id=0xffc1 tlabel=54 tcode=11 src_id=0xffc0 \ rcode=0 header={0xffc1d9b0,0xffc00000,0x0,0x40002} data={0x50800080} Link: https://lore.kernel.org/r/20240429043218.609398-4-o-takashi@sakamocchi.jp Signed-off-by: Takashi Sakamoto --- drivers/firewire/core-transaction.c | 55 +++++++++++++++++++------------------ include/trace/events/firewire.h | 50 +++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c index c9318024386f..56510d305564 100644 --- a/drivers/firewire/core-transaction.c +++ b/drivers/firewire/core-transaction.c @@ -1011,32 +1011,10 @@ void fw_core_handle_response(struct fw_card *card, struct fw_packet *p) source = async_header_get_source(p->header); rcode = async_header_get_rcode(p->header); - spin_lock_irqsave(&card->lock, flags); - list_for_each_entry(iter, &card->transaction_list, link) { - if (iter->node_id == source && iter->tlabel == tlabel) { - if (!try_cancel_split_timeout(iter)) { - spin_unlock_irqrestore(&card->lock, flags); - goto timed_out; - } - list_del_init(&iter->link); - card->tlabel_mask &= ~(1ULL << iter->tlabel); - t = iter; - break; - } - } - spin_unlock_irqrestore(&card->lock, flags); - - if (!t) { - timed_out: - fw_notice(card, "unsolicited response (source %x, tlabel %x)\n", - source, tlabel); - return; - } - - /* - * FIXME: sanity check packet, is length correct, does tcodes - * and addresses match. - */ + // FIXME: sanity check packet, is length correct, does tcodes + // and addresses match to the transaction request queried later. + // + // For the tracepoints event, let us decode the header here against the concern. switch (tcode) { case TCODE_READ_QUADLET_RESPONSE: @@ -1062,6 +1040,31 @@ void fw_core_handle_response(struct fw_card *card, struct fw_packet *p) break; } + spin_lock_irqsave(&card->lock, flags); + list_for_each_entry(iter, &card->transaction_list, link) { + if (iter->node_id == source && iter->tlabel == tlabel) { + if (!try_cancel_split_timeout(iter)) { + spin_unlock_irqrestore(&card->lock, flags); + goto timed_out; + } + list_del_init(&iter->link); + card->tlabel_mask &= ~(1ULL << iter->tlabel); + t = iter; + break; + } + } + spin_unlock_irqrestore(&card->lock, flags); + + trace_async_response_inbound((uintptr_t)t, p->generation, p->speed, p->ack, p->timestamp, + p->header, data, data_length / 4); + + if (!t) { + timed_out: + fw_notice(card, "unsolicited response (source %x, tlabel %x)\n", + source, tlabel); + return; + } + /* * The response handler may be executed while the request handler * is still pending. Cancel the request handler. diff --git a/include/trace/events/firewire.h b/include/trace/events/firewire.h index 063695874cfb..2d5f6b196a22 100644 --- a/include/trace/events/firewire.h +++ b/include/trace/events/firewire.h @@ -30,6 +30,9 @@ ((((unsigned long long)((header)[1] & ASYNC_HEADER_Q1_OFFSET_HIGH_MASK)) >> ASYNC_HEADER_Q1_OFFSET_HIGH_SHIFT) << 32)| \ (header)[2] +#define ASYNC_HEADER_GET_RCODE(header) \ + (((header)[1] & ASYNC_HEADER_Q1_RCODE_MASK) >> ASYNC_HEADER_Q1_RCODE_SHIFT) + #define QUADLET_SIZE 4 DECLARE_EVENT_CLASS(async_outbound_initiate_template, @@ -94,6 +97,47 @@ DECLARE_EVENT_CLASS(async_outbound_complete_template, ) ); +// The value of status is one of ack codes and rcodes specific to Linux FireWire subsystem. +DECLARE_EVENT_CLASS(async_inbound_template, + TP_PROTO(u64 transaction, unsigned int generation, unsigned int scode, unsigned int status, unsigned int timestamp, const u32 *header, const u32 *data, unsigned int data_count), + TP_ARGS(transaction, generation, scode, status, timestamp, header, data, data_count), + TP_STRUCT__entry( + __field(u64, transaction) + __field(u8, generation) + __field(u8, scode) + __field(u8, status) + __field(u8, timestamp) + __array(u32, header, ASYNC_HEADER_QUADLET_COUNT) + __dynamic_array(u32, data, data_count) + ), + TP_fast_assign( + __entry->transaction = transaction; + __entry->generation = generation; + __entry->scode = scode; + __entry->status = status; + __entry->timestamp = timestamp; + memcpy(__entry->header, header, QUADLET_SIZE * ASYNC_HEADER_QUADLET_COUNT); + memcpy(__get_dynamic_array(data), data, __get_dynamic_array_len(data)); + ), + // This format is for the response subaction. + TP_printk( + "transaction=0x%llx generation=%u scode=%u status=%u timestamp=0x%04x dst_id=0x%04x tlabel=%u tcode=%u src_id=0x%04x rcode=%u header=%s data=%s", + __entry->transaction, + __entry->generation, + __entry->scode, + __entry->status, + __entry->timestamp, + ASYNC_HEADER_GET_DESTINATION(__entry->header), + ASYNC_HEADER_GET_TLABEL(__entry->header), + ASYNC_HEADER_GET_TCODE(__entry->header), + ASYNC_HEADER_GET_SOURCE(__entry->header), + ASYNC_HEADER_GET_RCODE(__entry->header), + __print_array(__entry->header, ASYNC_HEADER_QUADLET_COUNT, QUADLET_SIZE), + __print_array(__get_dynamic_array(data), + __get_dynamic_array_len(data) / QUADLET_SIZE, QUADLET_SIZE) + ) +); + DEFINE_EVENT(async_outbound_initiate_template, async_request_outbound_initiate, TP_PROTO(u64 transaction, unsigned int generation, unsigned int scode, const u32 *header, const u32 *data, unsigned int data_count), TP_ARGS(transaction, generation, scode, header, data, data_count) @@ -104,11 +148,17 @@ DEFINE_EVENT(async_outbound_complete_template, async_request_outbound_complete, TP_ARGS(transaction, generation, scode, status, timestamp) ); +DEFINE_EVENT(async_inbound_template, async_response_inbound, + TP_PROTO(u64 transaction, unsigned int generation, unsigned int scode, unsigned int status, unsigned int timestamp, const u32 *header, const u32 *data, unsigned int data_count), + TP_ARGS(transaction, generation, scode, status, timestamp, header, data, data_count) +); + #undef ASYNC_HEADER_GET_DESTINATION #undef ASYNC_HEADER_GET_TLABEL #undef ASYNC_HEADER_GET_TCODE #undef ASYNC_HEADER_GET_SOURCE #undef ASYNC_HEADER_GET_OFFSET +#undef ASYNC_HEADER_GET_RCODE #undef QUADLET_SIZE #endif // _FIREWIRE_TRACE_EVENT_H -- cgit v1.2.3-58-ga151 From 2c945b10d7a6ef923e945ef031e9cfa78671fb3f Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Mon, 29 Apr 2024 13:32:17 +0900 Subject: firewire: core: add tracepoint event for asynchronous inbound request This commit adds an event for asynchronous inbound request. The following example is for asynchronous block write request as IEC 61883-1 FCP request from node 0xffc1. async_request_inbound: \ transaction=0xffff89fa08cf16c0 generation=4 scode=2 status=2 \ timestamp=0x00b3 dst_id=0xffc0 tlabel=19 tcode=1 src_id=0xffc1 \ offset=0xfffff0000d00 header={0xffc04d10,0xffc1ffff,0xf0000d00,0x80000} \ data={0x19ff08,0xffff0090} Link: https://lore.kernel.org/r/20240429043218.609398-5-o-takashi@sakamocchi.jp Signed-off-by: Takashi Sakamoto --- drivers/firewire/core-transaction.c | 8 +++++++- include/trace/events/firewire.h | 21 +++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c index 56510d305564..8c13f996a938 100644 --- a/drivers/firewire/core-transaction.c +++ b/drivers/firewire/core-transaction.c @@ -973,11 +973,13 @@ void fw_core_handle_request(struct fw_card *card, struct fw_packet *p) { struct fw_request *request; unsigned long long offset; + unsigned int tcode; if (p->ack != ACK_PENDING && p->ack != ACK_COMPLETE) return; - if (tcode_is_link_internal(async_header_get_tcode(p->header))) { + tcode = async_header_get_tcode(p->header); + if (tcode_is_link_internal(tcode)) { fw_cdev_handle_phy_packet(card, p); return; } @@ -988,6 +990,10 @@ void fw_core_handle_request(struct fw_card *card, struct fw_packet *p) return; } + trace_async_request_inbound((uintptr_t)request, p->generation, p->speed, p->ack, + p->timestamp, p->header, request->data, + tcode_is_read_request(tcode) ? 0 : request->length / 4); + offset = async_header_get_offset(p->header); if (!is_in_fcp_region(offset, request->length)) diff --git a/include/trace/events/firewire.h b/include/trace/events/firewire.h index 2d5f6b196a22..a30cebed119a 100644 --- a/include/trace/events/firewire.h +++ b/include/trace/events/firewire.h @@ -153,6 +153,27 @@ DEFINE_EVENT(async_inbound_template, async_response_inbound, TP_ARGS(transaction, generation, scode, status, timestamp, header, data, data_count) ); +DEFINE_EVENT_PRINT(async_inbound_template, async_request_inbound, + TP_PROTO(u64 transaction, unsigned int generation, unsigned int scode, unsigned int status, unsigned int timestamp, const u32 *header, const u32 *data, unsigned int data_count), + TP_ARGS(transaction, generation, scode, status, timestamp, header, data, data_count), + TP_printk( + "transaction=0x%llx generation=%u scode=%u status=%u timestamp=0x%04x dst_id=0x%04x tlabel=%u tcode=%u src_id=0x%04x offset=0x%012llx header=%s data=%s", + __entry->transaction, + __entry->generation, + __entry->scode, + __entry->status, + __entry->timestamp, + ASYNC_HEADER_GET_DESTINATION(__entry->header), + ASYNC_HEADER_GET_TLABEL(__entry->header), + ASYNC_HEADER_GET_TCODE(__entry->header), + ASYNC_HEADER_GET_SOURCE(__entry->header), + ASYNC_HEADER_GET_OFFSET(__entry->header), + __print_array(__entry->header, ASYNC_HEADER_QUADLET_COUNT, QUADLET_SIZE), + __print_array(__get_dynamic_array(data), + __get_dynamic_array_len(data) / QUADLET_SIZE, QUADLET_SIZE) + ) +); + #undef ASYNC_HEADER_GET_DESTINATION #undef ASYNC_HEADER_GET_TLABEL #undef ASYNC_HEADER_GET_TCODE -- cgit v1.2.3-58-ga151 From 624a8535f7036d8c4de1481b72704daa7f7fd43e Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Mon, 29 Apr 2024 13:32:18 +0900 Subject: firewire: core: add tracepoints events for asynchronous outbound response In a view of core transaction service, the asynchronous outbound response consists of two stages; initiation and completion. This commit adds a pair of events for the asynchronous outbound response. The following example is for asynchronous write quadlet request as IEC 61883-1 FCP response to node 0xffc1. async_response_outbound_initiate: \ transaction=0xffff89fa08cf16c0 generation=4 scode=2 dst_id=0xffc1 \ tlabel=25 tcode=2 src_id=0xffc0 rcode=0 \ header={0xffc16420,0xffc00000,0x0,0x0} data={} async_response_outbound_complete: \ transaction=0xffff89fa08cf16c0 generation=4 scode=2 status=1 \ timestamp=0x0000 Link: https://lore.kernel.org/r/20240429043218.609398-6-o-takashi@sakamocchi.jp Signed-off-by: Takashi Sakamoto --- drivers/firewire/core-transaction.c | 23 ++++++++++++++++------- include/trace/events/firewire.h | 24 ++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c index 8c13f996a938..0e49ebf52500 100644 --- a/drivers/firewire/core-transaction.c +++ b/drivers/firewire/core-transaction.c @@ -668,6 +668,9 @@ static void free_response_callback(struct fw_packet *packet, { struct fw_request *request = container_of(packet, struct fw_request, response); + trace_async_response_outbound_complete((uintptr_t)request, packet->generation, + packet->speed, status, packet->timestamp); + // Decrease the reference count since not at in-flight. fw_request_put(request); @@ -850,6 +853,9 @@ static struct fw_request *allocate_request(struct fw_card *card, void fw_send_response(struct fw_card *card, struct fw_request *request, int rcode) { + u32 *data = NULL; + unsigned int data_length = 0; + /* unified transaction or broadcast transaction: don't respond */ if (request->ack != ACK_PENDING || HEADER_DESTINATION_IS_BROADCAST(request->request_header)) { @@ -857,17 +863,20 @@ void fw_send_response(struct fw_card *card, return; } - if (rcode == RCODE_COMPLETE) - fw_fill_response(&request->response, request->request_header, - rcode, request->data, - fw_get_response_length(request)); - else - fw_fill_response(&request->response, request->request_header, - rcode, NULL, 0); + if (rcode == RCODE_COMPLETE) { + data = request->data; + data_length = fw_get_response_length(request); + } + + fw_fill_response(&request->response, request->request_header, rcode, data, data_length); // Increase the reference count so that the object is kept during in-flight. fw_request_get(request); + trace_async_response_outbound_initiate((uintptr_t)request, request->response.generation, + request->response.speed, request->response.header, + data, data ? data_length / 4 : 0); + card->driver->send_response(card, &request->response); } EXPORT_SYMBOL(fw_send_response); diff --git a/include/trace/events/firewire.h b/include/trace/events/firewire.h index a30cebed119a..d4688e341837 100644 --- a/include/trace/events/firewire.h +++ b/include/trace/events/firewire.h @@ -174,6 +174,30 @@ DEFINE_EVENT_PRINT(async_inbound_template, async_request_inbound, ) ); +DEFINE_EVENT_PRINT(async_outbound_initiate_template, async_response_outbound_initiate, + TP_PROTO(u64 transaction, unsigned int generation, unsigned int scode, const u32 *header, const u32 *data, unsigned int data_count), + TP_ARGS(transaction, generation, scode, header, data, data_count), + TP_printk( + "transaction=0x%llx generation=%u scode=%u dst_id=0x%04x tlabel=%u tcode=%u src_id=0x%04x rcode=%u header=%s data=%s", + __entry->transaction, + __entry->generation, + __entry->scode, + ASYNC_HEADER_GET_DESTINATION(__entry->header), + ASYNC_HEADER_GET_TLABEL(__entry->header), + ASYNC_HEADER_GET_TCODE(__entry->header), + ASYNC_HEADER_GET_SOURCE(__entry->header), + ASYNC_HEADER_GET_RCODE(__entry->header), + __print_array(__entry->header, ASYNC_HEADER_QUADLET_COUNT, QUADLET_SIZE), + __print_array(__get_dynamic_array(data), + __get_dynamic_array_len(data) / QUADLET_SIZE, QUADLET_SIZE) + ) +); + +DEFINE_EVENT(async_outbound_complete_template, async_response_outbound_complete, + TP_PROTO(u64 transaction, unsigned int generation, unsigned int scode, unsigned int status, unsigned int timestamp), + TP_ARGS(transaction, generation, scode, status, timestamp) +); + #undef ASYNC_HEADER_GET_DESTINATION #undef ASYNC_HEADER_GET_TLABEL #undef ASYNC_HEADER_GET_TCODE -- cgit v1.2.3-58-ga151 From 1a4c53cf355326a28daa6cbe00939cb4b8ac2659 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Tue, 30 Apr 2024 09:14:03 +0900 Subject: firewire: core/cdev: add tracepoints events for asynchronous phy packet In IEEE 1394 bus, the type of asynchronous packet without any offset to node address space is called as phy packet. The destination of packet is IEEE 1394 phy itself. This type of packet is used for several purposes, mainly for selfID at the state of bus reset, to force selection of root node, and to adjust gap count. This commit adds tracepoints events for the type of asynchronous outbound packet. Like asynchronous outbound transaction packets, a pair of events are added to trace initiation and completion of transmission. In the case that the phy packet is sent by kernel API, the match between the initiation and completion is not so easy, since the data of 'struct fw_packet' is allocated statically. In the case that it is sent by userspace applications via cdev, the match is easy, since the data is allocated per each. This example is for Remote Access Packet by lsfirewirephy command in linux-firewire-utils: async_phy_outbound_initiate: \ packet=0xffff89fb34e42e78 generation=1 first_quadlet=0x00148200 \ second_quadlet=0xffeb7dff async_phy_outbound_complete: \ packet=0xffff89fb34e42e78 generation=1 status=1 timestamp=0x0619 Link: https://lore.kernel.org/r/20240430001404.734657-2-o-takashi@sakamocchi.jp Signed-off-by: Takashi Sakamoto --- drivers/firewire/core-cdev.c | 7 ++++++ drivers/firewire/core-transaction.c | 6 +++++ include/trace/events/firewire.h | 48 +++++++++++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+) (limited to 'drivers') diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c index 6274b86eb943..55993c9e0b90 100644 --- a/drivers/firewire/core-cdev.c +++ b/drivers/firewire/core-cdev.c @@ -35,6 +35,7 @@ #include "core.h" +#include /* * ABI version history is documented in linux/firewire-cdev.h. @@ -1558,6 +1559,9 @@ static void outbound_phy_packet_callback(struct fw_packet *packet, struct client *e_client = e->client; u32 rcode; + trace_async_phy_outbound_complete((uintptr_t)packet, status, packet->generation, + packet->timestamp); + switch (status) { // expected: case ACK_COMPLETE: @@ -1655,6 +1659,9 @@ static int ioctl_send_phy_packet(struct client *client, union ioctl_arg *arg) memcpy(pp->data, a->data, sizeof(a->data)); } + trace_async_phy_outbound_initiate((uintptr_t)&e->p, e->p.generation, e->p.header[1], + e->p.header[2]); + card->driver->send_request(card, &e->p); return 0; diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c index 0e49ebf52500..a828b7167d15 100644 --- a/drivers/firewire/core-transaction.c +++ b/drivers/firewire/core-transaction.c @@ -463,6 +463,8 @@ static DECLARE_COMPLETION(phy_config_done); static void transmit_phy_packet_callback(struct fw_packet *packet, struct fw_card *card, int status) { + trace_async_phy_outbound_complete((uintptr_t)packet, packet->generation, status, + packet->timestamp); complete(&phy_config_done); } @@ -501,6 +503,10 @@ void fw_send_phy_config(struct fw_card *card, phy_config_packet.generation = generation; reinit_completion(&phy_config_done); + trace_async_phy_outbound_initiate((uintptr_t)&phy_config_packet, + phy_config_packet.generation, phy_config_packet.header[1], + phy_config_packet.header[2]); + card->driver->send_request(card, &phy_config_packet); wait_for_completion_timeout(&phy_config_done, timeout); diff --git a/include/trace/events/firewire.h b/include/trace/events/firewire.h index d4688e341837..3ade7d4b9268 100644 --- a/include/trace/events/firewire.h +++ b/include/trace/events/firewire.h @@ -206,6 +206,54 @@ DEFINE_EVENT(async_outbound_complete_template, async_response_outbound_complete, #undef ASYNC_HEADER_GET_RCODE #undef QUADLET_SIZE +TRACE_EVENT(async_phy_outbound_initiate, + TP_PROTO(u64 packet, unsigned int generation, u32 first_quadlet, u32 second_quadlet), + TP_ARGS(packet, generation, first_quadlet, second_quadlet), + TP_STRUCT__entry( + __field(u64, packet) + __field(u8, generation) + __field(u32, first_quadlet) + __field(u32, second_quadlet) + ), + TP_fast_assign( + __entry->packet = packet; + __entry->generation = generation; + __entry->first_quadlet = first_quadlet; + __entry->second_quadlet = second_quadlet + ), + TP_printk( + "packet=0x%016llx generation=%u first_quadlet=0x%08x second_quadlet=0x%08x", + __entry->packet, + __entry->generation, + __entry->first_quadlet, + __entry->second_quadlet + ) +); + +TRACE_EVENT(async_phy_outbound_complete, + TP_PROTO(u64 packet, unsigned int generation, unsigned int status, unsigned int timestamp), + TP_ARGS(packet, generation, status, timestamp), + TP_STRUCT__entry( + __field(u64, packet) + __field(u8, generation) + __field(u8, status) + __field(u16, timestamp) + ), + TP_fast_assign( + __entry->packet = packet; + __entry->generation = generation; + __entry->status = status; + __entry->timestamp = timestamp; + ), + TP_printk( + "packet=0x%016llx generation=%u status=%u timestamp=0x%04x", + __entry->packet, + __entry->generation, + __entry->status, + __entry->timestamp + ) +); + #endif // _FIREWIRE_TRACE_EVENT_H #include -- cgit v1.2.3-58-ga151 From eec045c571cbf89cad5c6622e191af385ecf2340 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Tue, 30 Apr 2024 09:14:04 +0900 Subject: firewire: core: add tracepoints event for asynchronous inbound phy packet At the former commit, a pair of tracepoints events is added to trace asynchronous outbound phy packet. This commit adds a tracepoints event to trace inbound phy packet. It includes transaction status as well as the content of phy packet. This is an example for Remote Reply Packet as a response to Remote Access Packet sent by lsfirewirephy command in linux-firewire-utils: async_phy_inbound: \ packet=0xffff955fc02b4e10 generation=1 status=1 timestamp=0x0619 \ first_quadlet=0x001c8208 second_quadlet=0xffe37df7 Link: https://lore.kernel.org/r/20240430001404.734657-3-o-takashi@sakamocchi.jp Signed-off-by: Takashi Sakamoto --- drivers/firewire/core-transaction.c | 2 ++ include/trace/events/firewire.h | 30 ++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) (limited to 'drivers') diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c index a828b7167d15..d3eefbf23663 100644 --- a/drivers/firewire/core-transaction.c +++ b/drivers/firewire/core-transaction.c @@ -995,6 +995,8 @@ void fw_core_handle_request(struct fw_card *card, struct fw_packet *p) tcode = async_header_get_tcode(p->header); if (tcode_is_link_internal(tcode)) { + trace_async_phy_inbound((uintptr_t)p, p->generation, p->ack, p->timestamp, + p->header[1], p->header[2]); fw_cdev_handle_phy_packet(card, p); return; } diff --git a/include/trace/events/firewire.h b/include/trace/events/firewire.h index 3ade7d4b9268..db49b9828bd1 100644 --- a/include/trace/events/firewire.h +++ b/include/trace/events/firewire.h @@ -254,6 +254,36 @@ TRACE_EVENT(async_phy_outbound_complete, ) ); +TRACE_EVENT(async_phy_inbound, + TP_PROTO(u64 packet, unsigned int generation, unsigned int status, unsigned int timestamp, u32 first_quadlet, u32 second_quadlet), + TP_ARGS(packet, generation, status, timestamp, first_quadlet, second_quadlet), + TP_STRUCT__entry( + __field(u64, packet) + __field(u8, generation) + __field(u8, status) + __field(u16, timestamp) + __field(u32, first_quadlet) + __field(u32, second_quadlet) + ), + TP_fast_assign( + __entry->packet = packet; + __entry->generation = generation; + __entry->status = status; + __entry->timestamp = timestamp; + __entry->first_quadlet = first_quadlet; + __entry->second_quadlet = second_quadlet + ), + TP_printk( + "packet=0x%016llx generation=%u status=%u timestamp=0x%04x first_quadlet=0x%08x second_quadlet=0x%08x", + __entry->packet, + __entry->generation, + __entry->status, + __entry->timestamp, + __entry->first_quadlet, + __entry->second_quadlet + ) +); + #endif // _FIREWIRE_TRACE_EVENT_H #include -- cgit v1.2.3-58-ga151 From 0d12f095b439b211ba10a51fd842e6f639459283 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Wed, 1 May 2024 16:32:34 +0900 Subject: firewire: ohci: add bus-reset event for initial set of handled irq In the former commits, the spurious interrupt events are suppressed as possible, by unset bus-reset event from the set of handled irq. The change was written with the less-intrusive style, thus it firstly works at the second time to handle the event. But it is slightly inconvenient. This commit adds the event for the initial set of irq to handle. As a result, the event can be handled even if it is the first time. The change has a benefit that the OHCI_PARAM_DEBUG_BUSRESETS bit in debug module parameter is always effective. Tested-by: Adam Goldman Link: https://lore.kernel.org/r/20240501073238.72769-2-o-takashi@sakamocchi.jp Signed-off-by: Takashi Sakamoto --- drivers/firewire/ohci.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index c8891aa70a51..9794b22db640 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -394,7 +394,7 @@ MODULE_PARM_DESC(quirks, "Chip quirks (default = 0" #define OHCI_PARAM_DEBUG_AT_AR 1 #define OHCI_PARAM_DEBUG_SELFIDS 2 #define OHCI_PARAM_DEBUG_IRQS 4 -#define OHCI_PARAM_DEBUG_BUSRESETS 8 /* only effective before chip init */ +#define OHCI_PARAM_DEBUG_BUSRESETS 8 static int param_debug; module_param_named(debug, param_debug, int, 0644); @@ -2066,8 +2066,7 @@ static void bus_reset_work(struct work_struct *work) ohci->generation = generation; reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset); - if (param_debug & OHCI_PARAM_DEBUG_BUSRESETS) - reg_write(ohci, OHCI1394_IntMaskSet, OHCI1394_busReset); + reg_write(ohci, OHCI1394_IntMaskSet, OHCI1394_busReset); if (ohci->quirks & QUIRK_RESET_PACKET) ohci->request_generation = generation; @@ -2139,6 +2138,7 @@ static irqreturn_t irq_handler(int irq, void *data) reg_write(ohci, OHCI1394_IntEventClear, event & ~(OHCI1394_busReset | OHCI1394_postedWriteErr)); log_irqs(ohci, event); + // The flag is masked again at bus_reset_work() scheduled by selfID event. if (event & OHCI1394_busReset) reg_write(ohci, OHCI1394_IntMaskClear, OHCI1394_busReset); @@ -2478,9 +2478,8 @@ static int ohci_enable(struct fw_card *card, OHCI1394_cycleInconsistent | OHCI1394_unrecoverableError | OHCI1394_cycleTooLong | - OHCI1394_masterIntEnable; - if (param_debug & OHCI_PARAM_DEBUG_BUSRESETS) - irqs |= OHCI1394_busReset; + OHCI1394_masterIntEnable | + OHCI1394_busReset; reg_write(ohci, OHCI1394_IntMaskSet, irqs); reg_write(ohci, OHCI1394_HCControlSet, -- cgit v1.2.3-58-ga151 From 42374303b73cdb2f81f4618bde5b1e25b5e6430d Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Wed, 1 May 2024 16:32:35 +0900 Subject: firewire: ohci: obsolete OHCI_PARAM_DEBUG_BUSRESETS from debug module parameter The OHCI_PARAM_DEBUG_BUSRESETS bit of debug module parameter was added at a commit a007bb857e0b ("firewire: fw-ohci: conditionally log busReset interrupts"). At the former commit, the bit becomes less meaningful, just to skip logging. This commit obsoletes it. Link: https://lore.kernel.org/r/20240501073238.72769-3-o-takashi@sakamocchi.jp Signed-off-by: Takashi Sakamoto --- drivers/firewire/ohci.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index 9794b22db640..f6de0b3a9a55 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -394,7 +394,6 @@ MODULE_PARM_DESC(quirks, "Chip quirks (default = 0" #define OHCI_PARAM_DEBUG_AT_AR 1 #define OHCI_PARAM_DEBUG_SELFIDS 2 #define OHCI_PARAM_DEBUG_IRQS 4 -#define OHCI_PARAM_DEBUG_BUSRESETS 8 static int param_debug; module_param_named(debug, param_debug, int, 0644); @@ -402,7 +401,6 @@ MODULE_PARM_DESC(debug, "Verbose logging (default = 0" ", AT/AR events = " __stringify(OHCI_PARAM_DEBUG_AT_AR) ", self-IDs = " __stringify(OHCI_PARAM_DEBUG_SELFIDS) ", IRQs = " __stringify(OHCI_PARAM_DEBUG_IRQS) - ", busReset events = " __stringify(OHCI_PARAM_DEBUG_BUSRESETS) ", or a combination, or all = -1)"); static bool param_remote_dma; @@ -411,12 +409,7 @@ MODULE_PARM_DESC(remote_dma, "Enable unfiltered remote DMA (default = N)"); static void log_irqs(struct fw_ohci *ohci, u32 evt) { - if (likely(!(param_debug & - (OHCI_PARAM_DEBUG_IRQS | OHCI_PARAM_DEBUG_BUSRESETS)))) - return; - - if (!(param_debug & OHCI_PARAM_DEBUG_IRQS) && - !(evt & OHCI1394_busReset)) + if (likely(!(param_debug & OHCI_PARAM_DEBUG_IRQS))) return; ohci_notice(ohci, "IRQ %08x%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", evt, -- cgit v1.2.3-58-ga151 From 08dd8602aab9fe9dbc3e41727caf7e416d2ccec4 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Wed, 1 May 2024 16:32:36 +0900 Subject: firewire: core: add tracepoints events for initiating bus reset At a commit 673249124304 ("firewire: core: option to log bus reset initiation"), some kernel log messages were added to trace initiation of bus reset. The kernel log messages are really helpful, while nowadays it is not preferable just for debugging purpose. For the purpose, Linux kernel tracepoints is more preferable. This commit adds some alternative tracepoints events. Link: https://lore.kernel.org/r/20240501073238.72769-4-o-takashi@sakamocchi.jp Signed-off-by: Takashi Sakamoto --- drivers/firewire/core-card.c | 7 +++++++ include/trace/events/firewire.h | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) (limited to 'drivers') diff --git a/drivers/firewire/core-card.c b/drivers/firewire/core-card.c index dac1b0fc7a42..5d43acf45a7d 100644 --- a/drivers/firewire/core-card.c +++ b/drivers/firewire/core-card.c @@ -23,6 +23,7 @@ #include #include "core.h" +#include #define define_fw_printk_level(func, kern_level) \ void func(const struct fw_card *card, const char *fmt, ...) \ @@ -221,6 +222,8 @@ static int reset_bus(struct fw_card *card, bool short_reset) int reg = short_reset ? 5 : 1; int bit = short_reset ? PHY_BUS_SHORT_RESET : PHY_BUS_RESET; + trace_bus_reset_initiate(card->generation, short_reset); + if (unlikely(fw_core_param_debug & FW_CORE_PARAM_DEBUG_BUSRESETS)) fw_notice(card, "initiating %s bus reset\n", short_reset ? "short" : "long"); @@ -230,6 +233,8 @@ static int reset_bus(struct fw_card *card, bool short_reset) void fw_schedule_bus_reset(struct fw_card *card, bool delayed, bool short_reset) { + trace_bus_reset_schedule(card->generation, short_reset); + if (unlikely(fw_core_param_debug & FW_CORE_PARAM_DEBUG_BUSRESETS)) fw_notice(card, "scheduling %s bus reset\n", short_reset ? "short" : "long"); @@ -252,6 +257,8 @@ static void br_work(struct work_struct *work) /* Delay for 2s after last reset per IEEE 1394 clause 8.2.1. */ if (card->reset_jiffies != 0 && time_before64(get_jiffies_64(), card->reset_jiffies + 2 * HZ)) { + trace_bus_reset_postpone(card->generation, card->br_short); + if (unlikely(fw_core_param_debug & FW_CORE_PARAM_DEBUG_BUSRESETS)) fw_notice(card, "delaying bus reset\n"); if (!queue_delayed_work(fw_workqueue, &card->br_work, 2 * HZ)) diff --git a/include/trace/events/firewire.h b/include/trace/events/firewire.h index db49b9828bd1..92bcbe69bb42 100644 --- a/include/trace/events/firewire.h +++ b/include/trace/events/firewire.h @@ -284,6 +284,39 @@ TRACE_EVENT(async_phy_inbound, ) ); +DECLARE_EVENT_CLASS(bus_reset_arrange_template, + TP_PROTO(unsigned int generation, bool short_reset), + TP_ARGS(generation, short_reset), + TP_STRUCT__entry( + __field(u8, generation) + __field(bool, short_reset) + ), + TP_fast_assign( + __entry->generation = generation; + __entry->short_reset = short_reset; + ), + TP_printk( + "generation=%u short_reset=%s", + __entry->generation, + __entry->short_reset ? "true" : "false" + ) +); + +DEFINE_EVENT(bus_reset_arrange_template, bus_reset_initiate, + TP_PROTO(unsigned int generation, bool short_reset), + TP_ARGS(generation, short_reset) +); + +DEFINE_EVENT(bus_reset_arrange_template, bus_reset_schedule, + TP_PROTO(unsigned int generation, bool short_reset), + TP_ARGS(generation, short_reset) +); + +DEFINE_EVENT(bus_reset_arrange_template, bus_reset_postpone, + TP_PROTO(unsigned int generation, bool short_reset), + TP_ARGS(generation, short_reset) +); + #endif // _FIREWIRE_TRACE_EVENT_H #include -- cgit v1.2.3-58-ga151 From 01d860427f67fd4b797ae616a2adb57263baeee9 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Wed, 1 May 2024 16:32:37 +0900 Subject: Revert "firewire: core: option to log bus reset initiation" This reverts commit 6732491243045f5a7e1995b4be5f3c964b579ebd. The former commit adds some alternative tracepoints events to replace the reverted kernel log messages. Link: https://lore.kernel.org/r/20240501073238.72769-5-o-takashi@sakamocchi.jp Signed-off-by: Takashi Sakamoto --- drivers/firewire/core-card.c | 10 ---------- drivers/firewire/core-transaction.c | 7 ------- drivers/firewire/core.h | 4 ---- 3 files changed, 21 deletions(-) (limited to 'drivers') diff --git a/drivers/firewire/core-card.c b/drivers/firewire/core-card.c index 5d43acf45a7d..127d87e3a153 100644 --- a/drivers/firewire/core-card.c +++ b/drivers/firewire/core-card.c @@ -224,10 +224,6 @@ static int reset_bus(struct fw_card *card, bool short_reset) trace_bus_reset_initiate(card->generation, short_reset); - if (unlikely(fw_core_param_debug & FW_CORE_PARAM_DEBUG_BUSRESETS)) - fw_notice(card, "initiating %s bus reset\n", - short_reset ? "short" : "long"); - return card->driver->update_phy_reg(card, reg, 0, bit); } @@ -235,10 +231,6 @@ void fw_schedule_bus_reset(struct fw_card *card, bool delayed, bool short_reset) { trace_bus_reset_schedule(card->generation, short_reset); - if (unlikely(fw_core_param_debug & FW_CORE_PARAM_DEBUG_BUSRESETS)) - fw_notice(card, "scheduling %s bus reset\n", - short_reset ? "short" : "long"); - /* We don't try hard to sort out requests of long vs. short resets. */ card->br_short = short_reset; @@ -259,8 +251,6 @@ static void br_work(struct work_struct *work) time_before64(get_jiffies_64(), card->reset_jiffies + 2 * HZ)) { trace_bus_reset_postpone(card->generation, card->br_short); - if (unlikely(fw_core_param_debug & FW_CORE_PARAM_DEBUG_BUSRESETS)) - fw_notice(card, "delaying bus reset\n"); if (!queue_delayed_work(fw_workqueue, &card->br_work, 2 * HZ)) fw_card_put(card); return; diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c index d3eefbf23663..571fdff65c2b 100644 --- a/drivers/firewire/core-transaction.c +++ b/drivers/firewire/core-transaction.c @@ -1390,12 +1390,5 @@ static void __exit fw_core_cleanup(void) idr_destroy(&fw_device_idr); } -int fw_core_param_debug; -module_param_named(debug, fw_core_param_debug, int, 0644); -MODULE_PARM_DESC(debug, "Verbose logging (default = 0" - ", bus resets = " __stringify(FW_CORE_PARAM_DEBUG_BUSRESETS) - ")"); - - module_init(fw_core_init); module_exit(fw_core_cleanup); diff --git a/drivers/firewire/core.h b/drivers/firewire/core.h index 5097c7a270b4..7c36d2628e37 100644 --- a/drivers/firewire/core.h +++ b/drivers/firewire/core.h @@ -245,10 +245,6 @@ static inline bool tcode_is_link_internal(unsigned int tcode) /* OHCI-1394's default upper bound for physical DMA: 4 GB */ #define FW_MAX_PHYSICAL_RANGE (1ULL << 32) -#define FW_CORE_PARAM_DEBUG_BUSRESETS 1 - -extern int fw_core_param_debug; - void fw_core_handle_request(struct fw_card *card, struct fw_packet *request); void fw_core_handle_response(struct fw_card *card, struct fw_packet *packet); int fw_get_response_length(struct fw_request *request); -- cgit v1.2.3-58-ga151 From 6b0b708f12d18f9cccfb1c418bea59fcbff8798c Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Wed, 1 May 2024 16:32:38 +0900 Subject: firewire: core: add tracepoint event for handling bus reset The core function expects hardware drivers to call fw_core_handle_bus_reset() when changing bus topology. The 1394 OHCI driver calls it when handling selfID event as a result of any bus-reset. This commit adds a tracepoints event for it. Link: https://lore.kernel.org/r/20240501073238.72769-6-o-takashi@sakamocchi.jp Signed-off-by: Takashi Sakamoto --- drivers/firewire/core-topology.c | 3 +++ include/trace/events/firewire.h | 28 +++++++++++++++++++++++++++- 2 files changed, 30 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/firewire/core-topology.c b/drivers/firewire/core-topology.c index f40c81534381..837cc44d8d9f 100644 --- a/drivers/firewire/core-topology.c +++ b/drivers/firewire/core-topology.c @@ -20,6 +20,7 @@ #include #include "core.h" +#include #define SELF_ID_PHY_ID(q) (((q) >> 24) & 0x3f) #define SELF_ID_EXTENDED(q) (((q) >> 23) & 0x01) @@ -507,6 +508,8 @@ void fw_core_handle_bus_reset(struct fw_card *card, int node_id, int generation, struct fw_node *local_node; unsigned long flags; + trace_bus_reset_handle(generation, node_id, bm_abdicate, self_ids, self_id_count); + spin_lock_irqsave(&card->lock, flags); /* diff --git a/include/trace/events/firewire.h b/include/trace/events/firewire.h index 92bcbe69bb42..4163959be57a 100644 --- a/include/trace/events/firewire.h +++ b/include/trace/events/firewire.h @@ -204,7 +204,6 @@ DEFINE_EVENT(async_outbound_complete_template, async_response_outbound_complete, #undef ASYNC_HEADER_GET_SOURCE #undef ASYNC_HEADER_GET_OFFSET #undef ASYNC_HEADER_GET_RCODE -#undef QUADLET_SIZE TRACE_EVENT(async_phy_outbound_initiate, TP_PROTO(u64 packet, unsigned int generation, u32 first_quadlet, u32 second_quadlet), @@ -317,6 +316,33 @@ DEFINE_EVENT(bus_reset_arrange_template, bus_reset_postpone, TP_ARGS(generation, short_reset) ); +TRACE_EVENT(bus_reset_handle, + TP_PROTO(unsigned int generation, unsigned int node_id, bool bm_abdicate, u32 *self_ids, unsigned int self_id_count), + TP_ARGS(generation, node_id, bm_abdicate, self_ids, self_id_count), + TP_STRUCT__entry( + __field(u8, generation) + __field(u8, node_id) + __field(bool, bm_abdicate) + __dynamic_array(u32, self_ids, self_id_count) + ), + TP_fast_assign( + __entry->generation = generation; + __entry->node_id = node_id; + __entry->bm_abdicate = bm_abdicate; + memcpy(__get_dynamic_array(self_ids), self_ids, __get_dynamic_array_len(self_ids)); + ), + TP_printk( + "generation=%u node_id=0x%04x bm_abdicate=%s self_ids=%s", + __entry->generation, + __entry->node_id, + __entry->bm_abdicate ? "true" : "false", + __print_array(__get_dynamic_array(self_ids), + __get_dynamic_array_len(self_ids) / QUADLET_SIZE, QUADLET_SIZE) + ) +); + +#undef QUADLET_SIZE + #endif // _FIREWIRE_TRACE_EVENT_H #include -- cgit v1.2.3-58-ga151 From 21151fd8f0ea5dcff27e8db25b65bf892d408bdc Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Wed, 8 May 2024 19:53:51 +0900 Subject: firewire: obsolete usage of *-objs in Makefile for KUnit test Nowadays *-objs list is just for user space programs. This commit obsolete the usage, and simplify Makefile for firewire KUnit tests since the tests are not composite objects. Link: https://lore.kernel.org/r/20240508105351.532693-1-o-takashi@sakamocchi.jp Signed-off-by: Takashi Sakamoto --- drivers/firewire/Makefile | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/firewire/Makefile b/drivers/firewire/Makefile index 013e1f2641bd..75c47d046925 100644 --- a/drivers/firewire/Makefile +++ b/drivers/firewire/Makefile @@ -16,8 +16,5 @@ obj-$(CONFIG_FIREWIRE_NET) += firewire-net.o obj-$(CONFIG_FIREWIRE_NOSY) += nosy.o obj-$(CONFIG_PROVIDE_OHCI1394_DMA_INIT) += init_ohci1394_dma.o -firewire-uapi-test-objs += uapi-test.o -firewire-packet-serdes-test-objs += packet-serdes-test.o - -obj-$(CONFIG_FIREWIRE_KUNIT_UAPI_TEST) += firewire-uapi-test.o -obj-$(CONFIG_FIREWIRE_KUNIT_PACKET_SERDES_TEST) += firewire-packet-serdes-test.o +obj-$(CONFIG_FIREWIRE_KUNIT_UAPI_TEST) += uapi-test.o +obj-$(CONFIG_FIREWIRE_KUNIT_PACKET_SERDES_TEST) += packet-serdes-test.o -- cgit v1.2.3-58-ga151