mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 04:34:03 +02:00
firewire updates for v7.3
This update includes error checks, a potential bug fix, and KUnit tests.
Sreeraj S Kurup addressed an error case when generating the contents of
the configuration ROM with parameters supplied by in-kernel
implementations such as unit drivers. Some error checks were added to
handle failures in this path.
Abdun Nihaal identified a potential memory leak when an invalid self-ID
sequence causes an error while building the internal node tree. KUnit
tests have been added to trigger this case. This memory leak has existed
since the first commit and has now been fixed.
-----BEGIN PGP SIGNATURE-----
iHUEABYKAB0WIQQE66IEYNDXNBPeGKSsLtaWM8LwEwUCaoku5AAKCRCsLtaWM8Lw
Ew7jAP9Flfyfrf0bfhi4Wmf/L25yNXBS3K5sdbQI5ZlK3Jk9XgEAq0OIsvX1i1Gz
evFvEjLgu41TTiWOIpPIWoY7OKh0SQA=
=jJGQ
-----END PGP SIGNATURE-----
Merge tag 'firewire-updates-7.3' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394
Pull firewire updates from Takashi Sakamoto:
"Error handling, a potential bug fix, and KUnit tests:
- Handle failures when generating the contents of the configuration
ROM with parameters supplied by in-kernel implementations such as
unit drivers (Sreeraj S Kurup)
- Fix potential memory leak when an invalid self-ID sequence causes
an error while building the internal node tree (Abdun Nihaal)
KUnit tests have been added to trigger this case"
* tag 'firewire-updates-7.3' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394:
firewire: core: fix memory leak in error path of build_tree()
firewire: core: validate parent port count before allocating nodes in build_tree()
firewire: core: consolidate port counting in build_tree()
firewire: core: add KUnit tests for failure of tree building
firewire: core: add KUnit tests for successful tree building
firewire: core: add KUnit test skeleton for node tree
firewire: core: validate sub-block lengths in fw_core_add_descriptor()
firewire: core: validate overall descriptor length in fw_core_add_descriptor()
This commit is contained in:
commit
47f05f71ad
|
|
@ -6,3 +6,4 @@ CONFIG_FIREWIRE_KUNIT_DEVICE_ATTRIBUTE_TEST=y
|
|||
CONFIG_FIREWIRE_KUNIT_PACKET_SERDES_TEST=y
|
||||
CONFIG_FIREWIRE_KUNIT_SELF_ID_SEQUENCE_HELPER_TEST=y
|
||||
CONFIG_FIREWIRE_KUNIT_OHCI_SERDES_TEST=y
|
||||
CONFIG_FIREWIRE_KUNIT_NODE_TREE_TEST=y
|
||||
|
|
|
|||
|
|
@ -81,6 +81,21 @@ config FIREWIRE_KUNIT_SELF_ID_SEQUENCE_HELPER_TEST
|
|||
For more information on KUnit and unit tests in general, refer
|
||||
to the KUnit documentation in Documentation/dev-tools/kunit/.
|
||||
|
||||
config FIREWIRE_KUNIT_NODE_TREE_TEST
|
||||
tristate "KUnit tests for node tree" if !KUNIT_ALL_TESTS
|
||||
depends on FIREWIRE && KUNIT
|
||||
default KUNIT_ALL_TESTS
|
||||
help
|
||||
This builds the KUnit tests for node tree.
|
||||
|
||||
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
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
#include <linux/list.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/minmax.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
|
|
@ -167,15 +168,30 @@ int fw_core_add_descriptor(struct fw_descriptor *desc)
|
|||
{
|
||||
size_t i;
|
||||
|
||||
/*
|
||||
* Check descriptor is valid; the length of all blocks in the
|
||||
* descriptor has to add up to exactly the length of the
|
||||
* block.
|
||||
*/
|
||||
i = 0;
|
||||
while (i < desc->length)
|
||||
i += (desc->data[i] >> 16) + 1;
|
||||
/* Reject empty descriptors or those exceeding max Config ROM size (256 quadlets) */
|
||||
if (!in_range(desc->length, 1, 256))
|
||||
return -EINVAL;
|
||||
|
||||
i = 0;
|
||||
/*
|
||||
* Validate internal block structures within the descriptor. Each sub-block
|
||||
* encodes its length in the top 16 bits of its header quadlet.
|
||||
*/
|
||||
while (i < desc->length) {
|
||||
u16 block_len = desc->data[i] >> 16;
|
||||
|
||||
/*
|
||||
* Guard against corrupted descriptors where an individual block length
|
||||
* claims to extend past the allocated end of desc->data, avoiding
|
||||
* out-of-bounds reads.
|
||||
*/
|
||||
if (block_len >= desc->length - i)
|
||||
return -EINVAL;
|
||||
|
||||
i += block_len + 1;
|
||||
}
|
||||
|
||||
/* The sum of sub-block lengths must match total descriptor length */
|
||||
if (i != desc->length)
|
||||
return -EINVAL;
|
||||
|
||||
|
|
|
|||
|
|
@ -88,6 +88,17 @@ static inline struct fw_node *fw_node(struct list_head *l)
|
|||
return list_entry(l, struct fw_node, link);
|
||||
}
|
||||
|
||||
typedef void (*fw_node_callback_t)(struct fw_card *card, struct fw_node *node,
|
||||
struct fw_node *parent);
|
||||
|
||||
static void for_each_fw_node(struct fw_card *card, struct fw_node *root,
|
||||
fw_node_callback_t callback);
|
||||
|
||||
static void free_fw_node(struct fw_card *card, struct fw_node *node, struct fw_node *parent)
|
||||
{
|
||||
kfree(node);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function builds the tree representation of the topology given
|
||||
* by the self IDs from the latest bus reset. During the construction
|
||||
|
|
@ -119,8 +130,8 @@ static struct fw_node *build_tree(struct fw_card *card, const u32 *sid, int self
|
|||
|
||||
while (enumerator.quadlet_count > 0) {
|
||||
unsigned int child_port_count = 0;
|
||||
unsigned int parent_port_count = 0;
|
||||
unsigned int total_port_count = 0;
|
||||
unsigned int parent_count = 0;
|
||||
unsigned int quadlet_count;
|
||||
const u32 *self_id_sequence;
|
||||
unsigned int port_capacity;
|
||||
|
|
@ -134,7 +145,7 @@ static struct fw_node *build_tree(struct fw_card *card, const u32 *sid, int self
|
|||
if (PTR_ERR(self_id_sequence) != -ENODATA) {
|
||||
fw_err(card, "inconsistent extended self IDs: %ld\n",
|
||||
PTR_ERR(self_id_sequence));
|
||||
return NULL;
|
||||
goto error;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -148,26 +159,38 @@ static struct fw_node *build_tree(struct fw_card *card, const u32 *sid, int self
|
|||
switch (port_status) {
|
||||
case PHY_PACKET_SELF_ID_PORT_STATUS_CHILD:
|
||||
++child_port_count;
|
||||
fallthrough;
|
||||
break;
|
||||
case PHY_PACKET_SELF_ID_PORT_STATUS_PARENT:
|
||||
++parent_port_count;
|
||||
break;
|
||||
case PHY_PACKET_SELF_ID_PORT_STATUS_NCONN:
|
||||
++total_port_count;
|
||||
fallthrough;
|
||||
break;
|
||||
case PHY_PACKET_SELF_ID_PORT_STATUS_NONE:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
total_port_count += child_port_count + parent_port_count;
|
||||
|
||||
// Check that the node reports exactly one parent port, except for the root, which
|
||||
// of course should have no parents.
|
||||
if ((enumerator.quadlet_count == 0 && parent_port_count != 0) ||
|
||||
(enumerator.quadlet_count > 0 && parent_port_count != 1)) {
|
||||
fw_err(card, "parent port inconsistency for node %d: parent_count=%d\n",
|
||||
phy_id, parent_port_count);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (phy_id != phy_packet_self_id_get_phy_id(self_id_sequence[0])) {
|
||||
fw_err(card, "PHY ID mismatch in self ID: %d != %d\n",
|
||||
phy_id, phy_packet_self_id_get_phy_id(self_id_sequence[0]));
|
||||
return NULL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (child_port_count > stack_depth) {
|
||||
fw_err(card, "topology stack underflow\n");
|
||||
return NULL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -185,7 +208,7 @@ static struct fw_node *build_tree(struct fw_card *card, const u32 *sid, int self
|
|||
node = fw_node_create(self_id_sequence[0], total_port_count, card->color);
|
||||
if (node == NULL) {
|
||||
fw_err(card, "out of memory while building topology\n");
|
||||
return NULL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (phy_id == (card->node_id & 0x3f))
|
||||
|
|
@ -203,7 +226,6 @@ static struct fw_node *build_tree(struct fw_card *card, const u32 *sid, int self
|
|||
// we temporarily abuse node->color for remembering the entry in
|
||||
// the node->ports array where the parent node should be. Later,
|
||||
// when we handle the parent node, we fix up the reference.
|
||||
++parent_count;
|
||||
node->color = port_index;
|
||||
break;
|
||||
|
||||
|
|
@ -221,21 +243,12 @@ static struct fw_node *build_tree(struct fw_card *card, const u32 *sid, int self
|
|||
}
|
||||
}
|
||||
|
||||
// Check that the node reports exactly one parent port, except for the root, which
|
||||
// of course should have no parents.
|
||||
if ((enumerator.quadlet_count == 0 && parent_count != 0) ||
|
||||
(enumerator.quadlet_count > 0 && parent_count != 1)) {
|
||||
fw_err(card, "parent port inconsistency for node %d: "
|
||||
"parent_count=%d\n", phy_id, parent_count);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Pop the child nodes off the stack and push the new node. */
|
||||
__list_del(h->prev, &stack);
|
||||
list_add_tail(&node->link, &stack);
|
||||
stack_depth += 1 - child_port_count;
|
||||
|
||||
if (node->phy_speed == SCODE_BETA && parent_count + child_port_count > 1)
|
||||
if (node->phy_speed == SCODE_BETA && parent_port_count + child_port_count > 1)
|
||||
beta_repeaters_present = true;
|
||||
|
||||
// If PHYs report different gap counts, set an invalid count which will force a gap
|
||||
|
|
@ -254,12 +267,13 @@ static struct fw_node *build_tree(struct fw_card *card, const u32 *sid, int self
|
|||
card->beta_repeaters_present = beta_repeaters_present;
|
||||
|
||||
return local_node;
|
||||
error:
|
||||
++card->color;
|
||||
list_for_each_entry_safe(node, child, &stack, link)
|
||||
for_each_fw_node(card, node, free_fw_node);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
typedef void (*fw_node_callback_t)(struct fw_card * card,
|
||||
struct fw_node * node,
|
||||
struct fw_node * parent);
|
||||
|
||||
static void for_each_fw_node(struct fw_card *card, struct fw_node *root,
|
||||
fw_node_callback_t callback)
|
||||
{
|
||||
|
|
@ -507,3 +521,7 @@ void fw_core_handle_bus_reset(struct fw_card *card, int node_id, int generation,
|
|||
}
|
||||
}
|
||||
EXPORT_SYMBOL(fw_core_handle_bus_reset);
|
||||
|
||||
#ifdef CONFIG_FIREWIRE_KUNIT_NODE_TREE_TEST
|
||||
#include "node-tree-test.c"
|
||||
#endif
|
||||
|
|
|
|||
607
drivers/firewire/node-tree-test.c
Normal file
607
drivers/firewire/node-tree-test.c
Normal file
|
|
@ -0,0 +1,607 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
//
|
||||
// node-tree-test.c - An application of Kunit to test node tree.
|
||||
//
|
||||
// Copyright (c) 2026 Takashi Sakamoto
|
||||
//
|
||||
// This file can not be built independently since it is intentionally included in core-topology.c.
|
||||
|
||||
#include <kunit/test.h>
|
||||
#include <kunit/test-bug.h>
|
||||
#include <kunit/device.h>
|
||||
|
||||
struct private_data {
|
||||
struct fw_card *card;
|
||||
unsigned int release_count;
|
||||
};
|
||||
|
||||
static int node_tree_test_init(struct kunit *test)
|
||||
{
|
||||
struct private_data *data;
|
||||
|
||||
data = kunit_kzalloc(test, sizeof(*data), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, data);
|
||||
|
||||
data->card = kunit_kzalloc(test, sizeof(struct fw_card), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, data->card);
|
||||
|
||||
data->card->device = kunit_device_register(test, "dummy-device");
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, data->card->device);
|
||||
|
||||
test->priv = data;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void node_tree_test_exit(struct kunit *test)
|
||||
{
|
||||
struct private_data *data = test->priv;
|
||||
|
||||
kunit_device_unregister(test, data->card->device);
|
||||
kunit_kfree(test, data->card);
|
||||
kunit_kfree(test, data);
|
||||
}
|
||||
|
||||
static void release_fw_node(struct fw_card *card, struct fw_node *node, struct fw_node *parent)
|
||||
{
|
||||
struct private_data *data = kunit_get_current_test()->priv;
|
||||
|
||||
fw_node_put(node);
|
||||
++data->release_count;
|
||||
}
|
||||
|
||||
static void node_tree_test_two_nodes(struct kunit *test)
|
||||
{
|
||||
// root
|
||||
// ++============++
|
||||
// || phy 1 ||
|
||||
// || P0 P1 P2 ||
|
||||
// ++===|==|==|==++
|
||||
// |
|
||||
// +-----+
|
||||
// |
|
||||
// ++===|==x==x==++
|
||||
// || P0 P1 P2 ||
|
||||
// || phy 0 ||
|
||||
// ++============++
|
||||
//
|
||||
static const u32 self_id_sequence[] = {
|
||||
0x80000080,
|
||||
0x8100005e,
|
||||
};
|
||||
struct private_data *data = test->priv;
|
||||
struct fw_card *card = data->card;
|
||||
|
||||
card->node_id = LOCAL_BUS | 0x01;
|
||||
|
||||
card->local_node = build_tree(card, self_id_sequence, ARRAY_SIZE(self_id_sequence), 123);
|
||||
KUNIT_EXPECT_NOT_NULL(test, card->local_node);
|
||||
KUNIT_EXPECT_PTR_EQ(test, card->local_node, card->root_node);
|
||||
|
||||
struct fw_node *node = card->root_node;
|
||||
KUNIT_EXPECT_EQ(test, node->node_id, LOCAL_BUS | 0x01);
|
||||
KUNIT_EXPECT_EQ(test, node->port_count, 3);
|
||||
KUNIT_EXPECT_NULL(test, node->ports[0]);
|
||||
KUNIT_EXPECT_NULL(test, node->ports[1]);
|
||||
KUNIT_EXPECT_NOT_NULL(test, node->ports[2]);
|
||||
|
||||
struct fw_node *parent = node;
|
||||
node = parent->ports[2];
|
||||
KUNIT_EXPECT_EQ(test, node->node_id, LOCAL_BUS | 0x00);
|
||||
KUNIT_EXPECT_EQ(test, node->port_count, 1);
|
||||
KUNIT_EXPECT_PTR_EQ(test, node->ports[0], parent);
|
||||
|
||||
++card->color;
|
||||
for_each_fw_node(card, card->root_node, release_fw_node);
|
||||
KUNIT_EXPECT_EQ(test, data->release_count, 2);
|
||||
}
|
||||
|
||||
static void node_tree_test_two_nodes_1394a(struct kunit *test)
|
||||
{
|
||||
// root
|
||||
// ++===============++
|
||||
// || phy 0 ||
|
||||
// || P0 P1 P2 P3 ||
|
||||
// ++===|==|==|==|==++
|
||||
// |
|
||||
// +--+
|
||||
// |
|
||||
// ++===|==|==|==|==|==++
|
||||
// || P0 P1 P2 P3 P4 ||
|
||||
// || phy 1 ||
|
||||
// ++==================++
|
||||
//
|
||||
// NOTE: Just for Self-ID Packets Zero and One.
|
||||
static const u32 self_id_sequence[] = {
|
||||
0x80000065, 0x80814000,
|
||||
0x8100005d, 0x81810000,
|
||||
};
|
||||
struct private_data *data = test->priv;
|
||||
struct fw_card *card = data->card;
|
||||
|
||||
card->node_id = LOCAL_BUS | 0x01;
|
||||
|
||||
card->local_node = build_tree(card, self_id_sequence, ARRAY_SIZE(self_id_sequence), 123);
|
||||
KUNIT_EXPECT_NOT_NULL(test, card->local_node);
|
||||
KUNIT_EXPECT_PTR_EQ(test, card->local_node, card->root_node);
|
||||
|
||||
struct fw_node *node = card->root_node;
|
||||
KUNIT_EXPECT_EQ(test, node->node_id, LOCAL_BUS | 0x01);
|
||||
KUNIT_EXPECT_EQ(test, node->port_count, 4);
|
||||
KUNIT_EXPECT_NULL(test, node->ports[0]);
|
||||
KUNIT_EXPECT_NULL(test, node->ports[1]);
|
||||
KUNIT_EXPECT_NOT_NULL(test, node->ports[2]);
|
||||
KUNIT_EXPECT_NULL(test, node->ports[3]);
|
||||
|
||||
struct fw_node *parent = node;
|
||||
node = parent->ports[2];
|
||||
KUNIT_EXPECT_EQ(test, node->node_id, LOCAL_BUS | 0x00);
|
||||
KUNIT_EXPECT_EQ(test, node->port_count, 5);
|
||||
KUNIT_EXPECT_NULL(test, node->ports[0]);
|
||||
KUNIT_EXPECT_PTR_EQ(test, node->ports[1], parent);
|
||||
KUNIT_EXPECT_NULL(test, node->ports[2]);
|
||||
KUNIT_EXPECT_NULL(test, node->ports[3]);
|
||||
KUNIT_EXPECT_NULL(test, node->ports[4]);
|
||||
|
||||
++card->color;
|
||||
for_each_fw_node(card, card->root_node, release_fw_node);
|
||||
KUNIT_EXPECT_EQ(test, data->release_count, 2);
|
||||
}
|
||||
|
||||
static void node_tree_test_three_nodes_case0(struct kunit *test)
|
||||
{
|
||||
// root
|
||||
// ++============++
|
||||
// || phy 2 ||
|
||||
// || P0 P1 P2 ||
|
||||
// ++===|==|==|==++
|
||||
// | |
|
||||
// +--+ +-----------------+
|
||||
// | |
|
||||
// ++===|==|==x==++ ++===|==|==|==++
|
||||
// || P0 P1 P2 || || P0 P1 P2 ||
|
||||
// || phy 0 || || phy 1 ||
|
||||
// ++============++ ++============++
|
||||
//
|
||||
static const u32 self_id_sequence[] = {
|
||||
0x80000060,
|
||||
0x81000058,
|
||||
0x820000dc,
|
||||
};
|
||||
struct private_data *data = test->priv;
|
||||
struct fw_card *card = data->card;
|
||||
|
||||
card->node_id = LOCAL_BUS | 0x02;
|
||||
|
||||
card->local_node = build_tree(card, self_id_sequence, ARRAY_SIZE(self_id_sequence), 123);
|
||||
KUNIT_EXPECT_NOT_NULL(test, card->local_node);
|
||||
KUNIT_EXPECT_PTR_EQ(test, card->local_node, card->root_node);
|
||||
|
||||
struct fw_node *node = card->root_node;
|
||||
KUNIT_EXPECT_EQ(test, node->node_id, LOCAL_BUS | 0x02);
|
||||
KUNIT_EXPECT_EQ(test, node->port_count, 3);
|
||||
KUNIT_EXPECT_NOT_NULL(test, node->ports[0]);
|
||||
KUNIT_EXPECT_NULL(test, node->ports[1]);
|
||||
KUNIT_EXPECT_NOT_NULL(test, node->ports[2]);
|
||||
|
||||
struct fw_node *parent = node;
|
||||
node = parent->ports[0];
|
||||
KUNIT_EXPECT_EQ(test, node->node_id, LOCAL_BUS | 0x00);
|
||||
KUNIT_EXPECT_EQ(test, node->port_count, 2);
|
||||
KUNIT_EXPECT_NULL(test, node->ports[0]);
|
||||
KUNIT_EXPECT_PTR_EQ(test, node->ports[1], parent);
|
||||
|
||||
node = parent->ports[2];
|
||||
KUNIT_EXPECT_EQ(test, node->node_id, LOCAL_BUS | 0x01);
|
||||
KUNIT_EXPECT_EQ(test, node->port_count, 3);
|
||||
KUNIT_EXPECT_NULL(test, node->ports[0]);
|
||||
KUNIT_EXPECT_NULL(test, node->ports[1]);
|
||||
KUNIT_EXPECT_PTR_EQ(test, node->ports[2], parent);
|
||||
|
||||
++card->color;
|
||||
for_each_fw_node(card, card->root_node, release_fw_node);
|
||||
KUNIT_EXPECT_EQ(test, data->release_count, 3);
|
||||
}
|
||||
|
||||
static void node_tree_test_three_nodes_case1(struct kunit *test)
|
||||
{
|
||||
// root
|
||||
// ++============++
|
||||
// || phy 2 ||
|
||||
// || P0 P1 P2 ||
|
||||
// ++===|==|==x==++
|
||||
// |
|
||||
// | +-----------+
|
||||
// | | |
|
||||
// ++===|==|==|==++ ++===|==x==x==++
|
||||
// || P0 P1 P2 || || P0 P1 P2 ||
|
||||
// || phy 1 || || phy 0 ||
|
||||
// ++============++ ++============++
|
||||
//
|
||||
static const u32 self_id_sequence[] = {
|
||||
0x80000080,
|
||||
0x8100006c,
|
||||
0x82000070,
|
||||
};
|
||||
struct private_data *data = test->priv;
|
||||
struct fw_card *card = data->card;
|
||||
|
||||
card->node_id = LOCAL_BUS | 0x02;
|
||||
|
||||
card->local_node = build_tree(card, self_id_sequence, ARRAY_SIZE(self_id_sequence), 123);
|
||||
KUNIT_EXPECT_NOT_NULL(test, card->local_node);
|
||||
KUNIT_EXPECT_PTR_EQ(test, card->local_node, card->root_node);
|
||||
|
||||
struct fw_node *node = card->root_node;
|
||||
KUNIT_EXPECT_EQ(test, node->node_id, LOCAL_BUS | 0x02);
|
||||
KUNIT_EXPECT_EQ(test, node->port_count, 2);
|
||||
KUNIT_EXPECT_NULL(test, node->ports[0]);
|
||||
KUNIT_EXPECT_NOT_NULL(test, node->ports[1]);
|
||||
|
||||
struct fw_node *parent = node;
|
||||
node = parent->ports[1];
|
||||
KUNIT_EXPECT_EQ(test, node->node_id, LOCAL_BUS | 0x01);
|
||||
KUNIT_EXPECT_EQ(test, node->port_count, 3);
|
||||
KUNIT_EXPECT_NULL(test, node->ports[0]);
|
||||
KUNIT_EXPECT_PTR_EQ(test, node->ports[1], parent);
|
||||
KUNIT_EXPECT_NOT_NULL(test, node->ports[2]);
|
||||
|
||||
parent = node;
|
||||
node = parent->ports[2];
|
||||
KUNIT_EXPECT_EQ(test, node->node_id, LOCAL_BUS | 0x00);
|
||||
KUNIT_EXPECT_EQ(test, node->port_count, 1);
|
||||
KUNIT_EXPECT_PTR_EQ(test, node->ports[0], parent);
|
||||
|
||||
++card->color;
|
||||
for_each_fw_node(card, card->root_node, release_fw_node);
|
||||
KUNIT_EXPECT_EQ(test, data->release_count, 3);
|
||||
}
|
||||
|
||||
static void node_tree_test_four_nodes_case0(struct kunit *test)
|
||||
{
|
||||
// root
|
||||
// ++============++
|
||||
// || phy 3 ||
|
||||
// || P0 P1 P2 ||
|
||||
// ++===|==|==|==++
|
||||
// |
|
||||
// | +-----------+ +--------------+
|
||||
// | | | | |
|
||||
// ++===|==|==|==++ ++===|==|==x==++ ++===|==x==x==++
|
||||
// || P0 P1 P2 || || P0 P1 P2 || || P0 P1 P2 ||
|
||||
// || phy 2 || || phy 1 || || phy 0 ||
|
||||
// ++============++ ++============++ ++============++
|
||||
//
|
||||
static const u32 self_id_sequence[] = {
|
||||
0x80000080,
|
||||
0x810000b0,
|
||||
0x8200006c,
|
||||
0x83000074,
|
||||
};
|
||||
struct private_data *data = test->priv;
|
||||
struct fw_card *card = data->card;
|
||||
|
||||
card->node_id = LOCAL_BUS | 0x03;
|
||||
|
||||
card->local_node = build_tree(card, self_id_sequence, ARRAY_SIZE(self_id_sequence), 123);
|
||||
KUNIT_EXPECT_NOT_NULL(test, card->local_node);
|
||||
KUNIT_EXPECT_PTR_EQ(test, card->local_node, card->root_node);
|
||||
|
||||
struct fw_node *node = card->root_node;
|
||||
KUNIT_EXPECT_EQ(test, node->node_id, LOCAL_BUS | 0x03);
|
||||
KUNIT_EXPECT_EQ(test, node->port_count, 3);
|
||||
KUNIT_EXPECT_NULL(test, node->ports[0]);
|
||||
KUNIT_EXPECT_NOT_NULL(test, node->ports[1]);
|
||||
KUNIT_EXPECT_NULL(test, node->ports[2]);
|
||||
|
||||
struct fw_node *parent = node;
|
||||
node = parent->ports[1];
|
||||
KUNIT_EXPECT_EQ(test, node->node_id, LOCAL_BUS | 0x02);
|
||||
KUNIT_EXPECT_EQ(test, node->port_count, 3);
|
||||
KUNIT_EXPECT_NULL(test, node->ports[0]);
|
||||
KUNIT_EXPECT_PTR_EQ(test, node->ports[1], parent);
|
||||
KUNIT_EXPECT_NOT_NULL(test, node->ports[2]);
|
||||
|
||||
parent = node;
|
||||
node = parent->ports[2];
|
||||
KUNIT_EXPECT_EQ(test, node->node_id, LOCAL_BUS | 0x01);
|
||||
KUNIT_EXPECT_EQ(test, node->port_count, 2);
|
||||
KUNIT_EXPECT_PTR_EQ(test, node->ports[0], parent);
|
||||
KUNIT_EXPECT_NOT_NULL(test, node->ports[1]);
|
||||
|
||||
parent = node;
|
||||
node = parent->ports[1];
|
||||
KUNIT_EXPECT_EQ(test, node->node_id, LOCAL_BUS | 0x00);
|
||||
KUNIT_EXPECT_EQ(test, node->port_count, 1);
|
||||
KUNIT_EXPECT_PTR_EQ(test, node->ports[0], parent);
|
||||
|
||||
++card->color;
|
||||
for_each_fw_node(card, card->root_node, release_fw_node);
|
||||
KUNIT_EXPECT_EQ(test, data->release_count, 4);
|
||||
}
|
||||
|
||||
static void node_tree_test_four_nodes_case1(struct kunit *test)
|
||||
{
|
||||
// root
|
||||
// ++============++
|
||||
// || phy 3 ||
|
||||
// || P0 P1 P2 ||
|
||||
// ++===|==|==x==++
|
||||
// |
|
||||
// | +--------------------------------+
|
||||
// | | +-----------+ |
|
||||
// ++===|==|==|==++ ++===|==x==x==++ ++===|==|==|==++
|
||||
// || P0 P1 P2 || || P0 P1 P2 || || P0 P1 P2 ||
|
||||
// || phy 2 || || phy 1 || || phy 0 ||
|
||||
// ++============++ ++============++ ++============++
|
||||
//
|
||||
static const u32 self_id_sequence[] = {
|
||||
0x80000094,
|
||||
0x81000080,
|
||||
0x820000bc,
|
||||
0x830000d0,
|
||||
};
|
||||
struct private_data *data = test->priv;
|
||||
struct fw_card *card = data->card;
|
||||
|
||||
card->node_id = LOCAL_BUS | 0x03;
|
||||
|
||||
card->local_node = build_tree(card, self_id_sequence, ARRAY_SIZE(self_id_sequence), 123);
|
||||
KUNIT_EXPECT_NOT_NULL(test, card->local_node);
|
||||
KUNIT_EXPECT_PTR_EQ(test, card->local_node, card->root_node);
|
||||
|
||||
struct fw_node *node = card->root_node;
|
||||
KUNIT_EXPECT_EQ(test, node->node_id, LOCAL_BUS | 0x03);
|
||||
KUNIT_EXPECT_EQ(test, node->port_count, 2);
|
||||
KUNIT_EXPECT_NOT_NULL(test, node->ports[0]);
|
||||
KUNIT_EXPECT_NULL(test, node->ports[1]);
|
||||
|
||||
struct fw_node *parent = node;
|
||||
node = parent->ports[0];
|
||||
KUNIT_EXPECT_EQ(test, node->node_id, LOCAL_BUS | 0x02);
|
||||
KUNIT_EXPECT_EQ(test, node->port_count, 3);
|
||||
KUNIT_EXPECT_PTR_EQ(test, node->ports[0], parent);
|
||||
KUNIT_EXPECT_NOT_NULL(test, node->ports[1]);
|
||||
KUNIT_EXPECT_NOT_NULL(test, node->ports[2]);
|
||||
|
||||
parent = node;
|
||||
node = parent->ports[2];
|
||||
KUNIT_EXPECT_EQ(test, node->node_id, LOCAL_BUS | 0x01);
|
||||
KUNIT_EXPECT_EQ(test, node->port_count, 1);
|
||||
KUNIT_EXPECT_PTR_EQ(test, node->ports[0], parent);
|
||||
|
||||
node = parent->ports[1];
|
||||
KUNIT_EXPECT_EQ(test, node->node_id, LOCAL_BUS | 0x00);
|
||||
KUNIT_EXPECT_EQ(test, node->port_count, 3);
|
||||
KUNIT_EXPECT_PTR_EQ(test, node->ports[0], parent);
|
||||
KUNIT_EXPECT_NULL(test, node->ports[1]);
|
||||
KUNIT_EXPECT_NULL(test, node->ports[2]);
|
||||
|
||||
++card->color;
|
||||
for_each_fw_node(card, card->root_node, release_fw_node);
|
||||
KUNIT_EXPECT_EQ(test, data->release_count, 4);
|
||||
}
|
||||
|
||||
static void node_tree_test_four_nodes_case2(struct kunit *test)
|
||||
{
|
||||
// root
|
||||
// ++============++
|
||||
// || phy 3 ||
|
||||
// || P0 P1 P2 ||
|
||||
// ++===|==|==|==++
|
||||
// | |
|
||||
// | +-----------------------------+
|
||||
// | +--------------+ |
|
||||
// ++===|==|==x==++ ++===|==|==|==++ ++===|==x==x==++
|
||||
// || P0 P1 P2 || || P0 P1 P2 || || P0 P1 P2 ||
|
||||
// || phy 1 || || phy 0 || || phy 2 ||
|
||||
// ++============++ ++============++ ++============++
|
||||
//
|
||||
static const u32 self_id_sequence[] = {
|
||||
0x80000094,
|
||||
0x810000b0,
|
||||
0x82000080,
|
||||
0x830000dc,
|
||||
};
|
||||
struct private_data *data = test->priv;
|
||||
struct fw_card *card = data->card;
|
||||
|
||||
card->node_id = LOCAL_BUS | 0x03;
|
||||
|
||||
card->local_node = build_tree(card, self_id_sequence, ARRAY_SIZE(self_id_sequence), 123);
|
||||
KUNIT_EXPECT_NOT_NULL(test, card->local_node);
|
||||
KUNIT_EXPECT_PTR_EQ(test, card->local_node, card->root_node);
|
||||
|
||||
struct fw_node *node = card->root_node;
|
||||
KUNIT_EXPECT_EQ(test, node->node_id, LOCAL_BUS | 0x03);
|
||||
KUNIT_EXPECT_EQ(test, node->port_count, 3);
|
||||
KUNIT_EXPECT_NOT_NULL(test, node->ports[0]);
|
||||
KUNIT_EXPECT_NULL(test, node->ports[1]);
|
||||
KUNIT_EXPECT_NOT_NULL(test, node->ports[2]);
|
||||
|
||||
struct fw_node *parent = node;
|
||||
node = parent->ports[2];
|
||||
KUNIT_EXPECT_EQ(test, node->node_id, LOCAL_BUS | 0x02);
|
||||
KUNIT_EXPECT_EQ(test, node->port_count, 1);
|
||||
KUNIT_EXPECT_PTR_EQ(test, node->ports[0], parent);
|
||||
|
||||
node = parent->ports[0];
|
||||
KUNIT_EXPECT_EQ(test, node->node_id, LOCAL_BUS | 0x01);
|
||||
KUNIT_EXPECT_EQ(test, node->port_count, 2);
|
||||
KUNIT_EXPECT_PTR_EQ(test, node->ports[0], parent);
|
||||
KUNIT_EXPECT_NOT_NULL(test, node->ports[1]);
|
||||
|
||||
parent = node;
|
||||
node = parent->ports[1];
|
||||
KUNIT_EXPECT_EQ(test, node->node_id, LOCAL_BUS | 0x00);
|
||||
KUNIT_EXPECT_EQ(test, node->port_count, 3);
|
||||
KUNIT_EXPECT_PTR_EQ(test, node->ports[0], parent);
|
||||
KUNIT_EXPECT_NULL(test, node->ports[1]);
|
||||
KUNIT_EXPECT_NULL(test, node->ports[2]);
|
||||
|
||||
++card->color;
|
||||
for_each_fw_node(card, card->root_node, release_fw_node);
|
||||
KUNIT_EXPECT_EQ(test, data->release_count, 4);
|
||||
}
|
||||
|
||||
static void node_tree_test_four_nodes_case3(struct kunit *test)
|
||||
{
|
||||
// root
|
||||
// ++============++
|
||||
// || phy 3 ||
|
||||
// || P0 P1 P2 ||
|
||||
// ++===|==|==|==++
|
||||
// | | +--------------------------------+
|
||||
// | +--------------------+ |
|
||||
// | | |
|
||||
// ++===|==|==x==++ ++===|==|==|==++ ++===|==|==x==++
|
||||
// || P0 P1 P2 || || P0 P1 P2 || || P0 P1 P2 ||
|
||||
// || phy 0 || || phy 1 || || phy 2 ||
|
||||
// ++============++ ++============++ ++============++
|
||||
//
|
||||
static const u32 self_id_sequence[] = {
|
||||
0x80000090,
|
||||
0x81000058,
|
||||
0x82000060,
|
||||
0x830000fc,
|
||||
};
|
||||
struct private_data *data = test->priv;
|
||||
struct fw_card *card = data->card;
|
||||
|
||||
card->node_id = LOCAL_BUS | 0x03;
|
||||
|
||||
card->local_node = build_tree(card, self_id_sequence, ARRAY_SIZE(self_id_sequence), 123);
|
||||
KUNIT_EXPECT_NOT_NULL(test, card->local_node);
|
||||
KUNIT_EXPECT_PTR_EQ(test, card->local_node, card->root_node);
|
||||
|
||||
struct fw_node *node = card->root_node;
|
||||
KUNIT_EXPECT_EQ(test, node->node_id, LOCAL_BUS | 0x03);
|
||||
KUNIT_EXPECT_EQ(test, node->port_count, 3);
|
||||
KUNIT_EXPECT_NOT_NULL(test, node->ports[0]);
|
||||
KUNIT_EXPECT_NOT_NULL(test, node->ports[1]);
|
||||
KUNIT_EXPECT_NOT_NULL(test, node->ports[2]);
|
||||
|
||||
struct fw_node *parent = node;
|
||||
node = parent->ports[2];
|
||||
KUNIT_EXPECT_EQ(test, node->node_id, LOCAL_BUS | 0x02);
|
||||
KUNIT_EXPECT_EQ(test, node->port_count, 2);
|
||||
KUNIT_EXPECT_NULL(test, node->ports[0]);
|
||||
KUNIT_EXPECT_PTR_EQ(test, node->ports[1], parent);
|
||||
|
||||
node = parent->ports[1];
|
||||
KUNIT_EXPECT_EQ(test, node->node_id, LOCAL_BUS | 0x01);
|
||||
KUNIT_EXPECT_EQ(test, node->port_count, 3);
|
||||
KUNIT_EXPECT_NULL(test, node->ports[0]);
|
||||
KUNIT_EXPECT_NULL(test, node->ports[1]);
|
||||
KUNIT_EXPECT_PTR_EQ(test, node->ports[2], parent);
|
||||
|
||||
node = parent->ports[0];
|
||||
KUNIT_EXPECT_EQ(test, node->node_id, LOCAL_BUS | 0x00);
|
||||
KUNIT_EXPECT_EQ(test, node->port_count, 2);
|
||||
KUNIT_EXPECT_PTR_EQ(test, node->ports[0], parent);
|
||||
KUNIT_EXPECT_NULL(test, node->ports[1]);
|
||||
|
||||
++card->color;
|
||||
for_each_fw_node(card, card->root_node, release_fw_node);
|
||||
KUNIT_EXPECT_EQ(test, data->release_count, 4);
|
||||
}
|
||||
|
||||
static void node_tree_test_invalid_extended_self_id_sequence(struct kunit *test)
|
||||
{
|
||||
// Use the same node tree as node_tree_test_four_nodes_case1, except for the invalid
|
||||
// content of self ID packet for the phy 3.
|
||||
static const u32 self_id_sequence[] = {
|
||||
0x80000094,
|
||||
0x81000080,
|
||||
0x820000bc,
|
||||
0x830000d1, // Invalid.
|
||||
};
|
||||
struct private_data *data = test->priv;
|
||||
struct fw_card *card = data->card;
|
||||
|
||||
card->node_id = LOCAL_BUS | 0x03;
|
||||
|
||||
card->local_node = build_tree(card, self_id_sequence, ARRAY_SIZE(self_id_sequence), 123);
|
||||
KUNIT_EXPECT_NULL(test, card->local_node);
|
||||
}
|
||||
|
||||
static void node_tree_test_invalid_phy_id(struct kunit *test)
|
||||
{
|
||||
// Use the same node tree as node_tree_test_four_nodes_case1, except for the invalid
|
||||
// phy ID for phy 3.
|
||||
static const u32 self_id_sequence[] = {
|
||||
0x80000094,
|
||||
0x81000080,
|
||||
0x820000bc,
|
||||
0x8f0000d0, // Invalid.
|
||||
};
|
||||
struct private_data *data = test->priv;
|
||||
struct fw_card *card = data->card;
|
||||
|
||||
card->node_id = LOCAL_BUS | 0x03;
|
||||
|
||||
card->local_node = build_tree(card, self_id_sequence, ARRAY_SIZE(self_id_sequence), 123);
|
||||
KUNIT_EXPECT_NULL(test, card->local_node);
|
||||
}
|
||||
|
||||
static void node_tree_test_invalid_child_port_count(struct kunit *test)
|
||||
{
|
||||
// Use the same node tree as node_tree_test_four_nodes_case1, except for the invalid
|
||||
// count of child ports for phy 3.
|
||||
static const u32 self_id_sequence[] = {
|
||||
0x80000094,
|
||||
0x81000080,
|
||||
0x820000bc,
|
||||
0x830000fc, // Invalid.
|
||||
};
|
||||
struct private_data *data = test->priv;
|
||||
struct fw_card *card = data->card;
|
||||
|
||||
card->node_id = LOCAL_BUS | 0x03;
|
||||
|
||||
card->local_node = build_tree(card, self_id_sequence, ARRAY_SIZE(self_id_sequence), 123);
|
||||
KUNIT_EXPECT_NULL(test, card->local_node);
|
||||
}
|
||||
|
||||
static void node_tree_test_invalid_parent_port_count(struct kunit *test)
|
||||
{
|
||||
// Use the same node tree as node_tree_test_four_nodes_case1, except for the invalid
|
||||
// count of parent ports for phy 3.
|
||||
static const u32 self_id_sequence[] = {
|
||||
0x80000094,
|
||||
0x81000080,
|
||||
0x820000bc,
|
||||
0x830000e8, // Invalid.
|
||||
};
|
||||
struct private_data *data = test->priv;
|
||||
struct fw_card *card = data->card;
|
||||
|
||||
card->node_id = LOCAL_BUS | 0x03;
|
||||
|
||||
card->local_node = build_tree(card, self_id_sequence, ARRAY_SIZE(self_id_sequence), 123);
|
||||
KUNIT_EXPECT_NULL(test, card->local_node);
|
||||
}
|
||||
|
||||
static struct kunit_case node_tree_test_cases[] = {
|
||||
KUNIT_CASE(node_tree_test_two_nodes),
|
||||
KUNIT_CASE(node_tree_test_two_nodes_1394a),
|
||||
KUNIT_CASE(node_tree_test_three_nodes_case0),
|
||||
KUNIT_CASE(node_tree_test_three_nodes_case1),
|
||||
KUNIT_CASE(node_tree_test_four_nodes_case0),
|
||||
KUNIT_CASE(node_tree_test_four_nodes_case1),
|
||||
KUNIT_CASE(node_tree_test_four_nodes_case2),
|
||||
KUNIT_CASE(node_tree_test_four_nodes_case3),
|
||||
KUNIT_CASE(node_tree_test_invalid_extended_self_id_sequence),
|
||||
KUNIT_CASE(node_tree_test_invalid_phy_id),
|
||||
KUNIT_CASE(node_tree_test_invalid_child_port_count),
|
||||
KUNIT_CASE(node_tree_test_invalid_parent_port_count),
|
||||
{}
|
||||
};
|
||||
|
||||
static struct kunit_suite node_tree_test_suite = {
|
||||
.name = "firewire-node-tree",
|
||||
.init = node_tree_test_init,
|
||||
.exit = node_tree_test_exit,
|
||||
.test_cases = node_tree_test_cases,
|
||||
};
|
||||
kunit_test_suite(node_tree_test_suite);
|
||||
Loading…
Reference in New Issue
Block a user