Commit fb19fac1 authored by Mika Westerberg's avatar Mika Westerberg

thunderbolt: Add helper function to iterate from one port to another

We need to be able to walk from one port to another when we are creating
paths where there are multiple switches between two ports. For this
reason introduce a new function tb_next_port_on_path().
Signed-off-by: default avatarMika Westerberg <mika.westerberg@linux.intel.com>
Reviewed-by: default avatarLukas Wunner <lukas@wunner.de>
parent dfe40ca4
......@@ -676,6 +676,60 @@ void tb_port_release_out_hopid(struct tb_port *port, int hopid)
ida_simple_remove(&port->out_hopids, hopid);
}
/**
* tb_next_port_on_path() - Return next port for given port on a path
* @start: Start port of the walk
* @end: End port of the walk
* @prev: Previous port (%NULL if this is the first)
*
* This function can be used to walk from one port to another if they
* are connected through zero or more switches. If the @prev is dual
* link port, the function follows that link and returns another end on
* that same link.
*
* If the @end port has been reached, return %NULL.
*
* Domain tb->lock must be held when this function is called.
*/
struct tb_port *tb_next_port_on_path(struct tb_port *start, struct tb_port *end,
struct tb_port *prev)
{
struct tb_port *next;
if (!prev)
return start;
if (prev->sw == end->sw) {
if (prev == end)
return NULL;
return end;
}
if (start->sw->config.depth < end->sw->config.depth) {
if (prev->remote &&
prev->remote->sw->config.depth > prev->sw->config.depth)
next = prev->remote;
else
next = tb_port_at(tb_route(end->sw), prev->sw);
} else {
if (tb_is_upstream_port(prev)) {
next = prev->remote;
} else {
next = tb_upstream_port(prev->sw);
/*
* Keep the same link if prev and next are both
* dual link ports.
*/
if (next->dual_link_port &&
next->link_nr != prev->link_nr) {
next = next->dual_link_port;
}
}
}
return next;
}
/**
* tb_pci_port_enable() - Enable PCIe adapter port
* @port: PCIe port to enable
......
......@@ -495,6 +495,8 @@ int tb_port_alloc_in_hopid(struct tb_port *port, int hopid, int max_hopid);
void tb_port_release_in_hopid(struct tb_port *port, int hopid);
int tb_port_alloc_out_hopid(struct tb_port *port, int hopid, int max_hopid);
void tb_port_release_out_hopid(struct tb_port *port, int hopid);
struct tb_port *tb_next_port_on_path(struct tb_port *start, struct tb_port *end,
struct tb_port *prev);
int tb_switch_find_vse_cap(struct tb_switch *sw, enum tb_switch_vse_cap vsec);
int tb_port_find_cap(struct tb_port *port, enum tb_port_cap cap);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment