thunderbolt: Introduce tb_switch_next_cap()
This is similar to tb_port_next_cap() but instead allows walking capability list of a switch (router). Convert tb_switch_find_cap() and tb_switch_find_vse_cap() to use this as well. Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com> Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
3c8b228d43
commit
6de057ef91
|
@ -132,6 +132,50 @@ int tb_port_find_cap(struct tb_port *port, enum tb_port_cap cap)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tb_switch_next_cap() - Return next capability in the linked list
|
||||||
|
* @sw: Switch to find the capability for
|
||||||
|
* @offset: Previous capability offset (%0 for start)
|
||||||
|
*
|
||||||
|
* Finds dword offset of the next capability in router config space
|
||||||
|
* capability list and returns it. Passing %0 returns the first entry in
|
||||||
|
* the capability list. If no next capability is found returns %0. In case
|
||||||
|
* of failure returns negative errno.
|
||||||
|
*/
|
||||||
|
int tb_switch_next_cap(struct tb_switch *sw, unsigned int offset)
|
||||||
|
{
|
||||||
|
struct tb_cap_any header;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!offset)
|
||||||
|
return sw->config.first_cap_offset;
|
||||||
|
|
||||||
|
ret = tb_sw_read(sw, &header, TB_CFG_SWITCH, offset, 2);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
switch (header.basic.cap) {
|
||||||
|
case TB_SWITCH_CAP_TMU:
|
||||||
|
ret = header.basic.next;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TB_SWITCH_CAP_VSE:
|
||||||
|
if (!header.extended_short.length)
|
||||||
|
ret = header.extended_long.next;
|
||||||
|
else
|
||||||
|
ret = header.extended_short.next;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
tb_sw_dbg(sw, "unknown capability %#x at %#x\n",
|
||||||
|
header.basic.cap, offset);
|
||||||
|
ret = -EINVAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret >= VSE_CAP_OFFSET_MAX ? 0 : ret;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* tb_switch_find_cap() - Find switch capability
|
* tb_switch_find_cap() - Find switch capability
|
||||||
* @sw Switch to find the capability for
|
* @sw Switch to find the capability for
|
||||||
|
@ -143,21 +187,23 @@ int tb_port_find_cap(struct tb_port *port, enum tb_port_cap cap)
|
||||||
*/
|
*/
|
||||||
int tb_switch_find_cap(struct tb_switch *sw, enum tb_switch_cap cap)
|
int tb_switch_find_cap(struct tb_switch *sw, enum tb_switch_cap cap)
|
||||||
{
|
{
|
||||||
int offset = sw->config.first_cap_offset;
|
int offset = 0;
|
||||||
|
|
||||||
while (offset > 0 && offset < CAP_OFFSET_MAX) {
|
do {
|
||||||
struct tb_cap_any header;
|
struct tb_cap_any header;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
offset = tb_switch_next_cap(sw, offset);
|
||||||
|
if (offset < 0)
|
||||||
|
return offset;
|
||||||
|
|
||||||
ret = tb_sw_read(sw, &header, TB_CFG_SWITCH, offset, 1);
|
ret = tb_sw_read(sw, &header, TB_CFG_SWITCH, offset, 1);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if (header.basic.cap == cap)
|
if (header.basic.cap == cap)
|
||||||
return offset;
|
return offset;
|
||||||
|
} while (offset);
|
||||||
offset = header.basic.next;
|
|
||||||
}
|
|
||||||
|
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
|
@ -174,37 +220,24 @@ int tb_switch_find_cap(struct tb_switch *sw, enum tb_switch_cap cap)
|
||||||
*/
|
*/
|
||||||
int tb_switch_find_vse_cap(struct tb_switch *sw, enum tb_switch_vse_cap vsec)
|
int tb_switch_find_vse_cap(struct tb_switch *sw, enum tb_switch_vse_cap vsec)
|
||||||
{
|
{
|
||||||
struct tb_cap_any header;
|
int offset = 0;
|
||||||
int offset;
|
|
||||||
|
|
||||||
offset = tb_switch_find_cap(sw, TB_SWITCH_CAP_VSE);
|
do {
|
||||||
if (offset < 0)
|
struct tb_cap_any header;
|
||||||
return offset;
|
|
||||||
|
|
||||||
while (offset > 0 && offset < VSE_CAP_OFFSET_MAX) {
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = tb_sw_read(sw, &header, TB_CFG_SWITCH, offset, 2);
|
offset = tb_switch_next_cap(sw, offset);
|
||||||
|
if (offset < 0)
|
||||||
|
return offset;
|
||||||
|
|
||||||
|
ret = tb_sw_read(sw, &header, TB_CFG_SWITCH, offset, 1);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
/*
|
if (header.extended_short.cap == TB_SWITCH_CAP_VSE &&
|
||||||
* Extended vendor specific capabilities come in two
|
header.extended_short.vsec_id == vsec)
|
||||||
* flavors: short and long. The latter is used when
|
return offset;
|
||||||
* offset is over 0xff.
|
} while (offset);
|
||||||
*/
|
|
||||||
if (offset >= CAP_OFFSET_MAX) {
|
|
||||||
if (header.extended_long.vsec_id == vsec)
|
|
||||||
return offset;
|
|
||||||
offset = header.extended_long.next;
|
|
||||||
} else {
|
|
||||||
if (header.extended_short.vsec_id == vsec)
|
|
||||||
return offset;
|
|
||||||
if (!header.extended_short.length)
|
|
||||||
return -ENOENT;
|
|
||||||
offset = header.extended_short.next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
|
|
|
@ -822,6 +822,7 @@ int tb_port_get_link_speed(struct tb_port *port);
|
||||||
|
|
||||||
int tb_switch_find_vse_cap(struct tb_switch *sw, enum tb_switch_vse_cap vsec);
|
int tb_switch_find_vse_cap(struct tb_switch *sw, enum tb_switch_vse_cap vsec);
|
||||||
int tb_switch_find_cap(struct tb_switch *sw, enum tb_switch_cap cap);
|
int tb_switch_find_cap(struct tb_switch *sw, enum tb_switch_cap cap);
|
||||||
|
int tb_switch_next_cap(struct tb_switch *sw, unsigned int offset);
|
||||||
int tb_port_find_cap(struct tb_port *port, enum tb_port_cap cap);
|
int tb_port_find_cap(struct tb_port *port, enum tb_port_cap cap);
|
||||||
int tb_port_next_cap(struct tb_port *port, unsigned int offset);
|
int tb_port_next_cap(struct tb_port *port, unsigned int offset);
|
||||||
bool tb_port_is_enabled(struct tb_port *port);
|
bool tb_port_is_enabled(struct tb_port *port);
|
||||||
|
|
Loading…
Reference in New Issue