diff --git a/drivers/thunderbolt/cap.c b/drivers/thunderbolt/cap.c index 1582e4ebac56..c45b3a488412 100644 --- a/drivers/thunderbolt/cap.c +++ b/drivers/thunderbolt/cap.c @@ -59,23 +59,50 @@ static void tb_port_dummy_read(struct tb_port *port) } } +/** + * tb_port_next_cap() - Return next capability in the linked list + * @port: Port to find the capability for + * @offset: Previous capability offset (%0 for start) + * + * Returns dword offset of the next capability in port 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_port_next_cap(struct tb_port *port, unsigned int offset) +{ + struct tb_cap_any header; + int ret; + + if (!offset) + return port->config.first_cap_offset; + + ret = tb_port_read(port, &header, TB_CFG_PORT, offset, 1); + if (ret) + return ret; + + return header.basic.next; +} + static int __tb_port_find_cap(struct tb_port *port, enum tb_port_cap cap) { - u32 offset = 1; + int offset = 0; do { struct tb_cap_any header; int ret; + offset = tb_port_next_cap(port, offset); + if (offset < 0) + return offset; + ret = tb_port_read(port, &header, TB_CFG_PORT, offset, 1); if (ret) return ret; if (header.basic.cap == cap) return offset; - - offset = header.basic.next; - } while (offset); + } while (offset > 0); return -ENOENT; } diff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h index 7754c690addc..54e8fad78bee 100644 --- a/drivers/thunderbolt/tb.h +++ b/drivers/thunderbolt/tb.h @@ -823,6 +823,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_cap(struct tb_switch *sw, enum tb_switch_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); bool tb_port_is_enabled(struct tb_port *port); bool tb_usb3_port_is_enabled(struct tb_port *port);