diff --git a/drivers/thunderbolt/Makefile b/drivers/thunderbolt/Makefile index f2f0de27252b16402b9d0a3f32f14d1e488ea7f2..8531f15d3b3c17eaa9046a2123ceb302bd14a017 100644 --- a/drivers/thunderbolt/Makefile +++ b/drivers/thunderbolt/Makefile @@ -1,3 +1,3 @@ obj-${CONFIG_THUNDERBOLT} := thunderbolt.o thunderbolt-objs := nhi.o ctl.o tb.o switch.o cap.o path.o tunnel_pci.o eeprom.o -thunderbolt-objs += domain.o dma_port.o icm.o property.o xdomain.o +thunderbolt-objs += domain.o dma_port.o icm.o property.o xdomain.o lc.o diff --git a/drivers/thunderbolt/lc.c b/drivers/thunderbolt/lc.c new file mode 100644 index 0000000000000000000000000000000000000000..2134a55ed8372df49c76f10029163ea379dccad1 --- /dev/null +++ b/drivers/thunderbolt/lc.c @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Thunderbolt link controller support + * + * Copyright (C) 2019, Intel Corporation + * Author: Mika Westerberg + */ + +#include "tb.h" + +/** + * tb_lc_read_uuid() - Read switch UUID from link controller common register + * @sw: Switch whose UUID is read + * @uuid: UUID is placed here + */ +int tb_lc_read_uuid(struct tb_switch *sw, u32 *uuid) +{ + if (!sw->cap_lc) + return -EINVAL; + return tb_sw_read(sw, uuid, TB_CFG_SWITCH, sw->cap_lc + TB_LC_FUSE, 4); +} diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c index 1e29c06947af7c5f8ef83ac3dcbc803476ae6b60..63ff4c753d8987a171c2b006fe9dbe24efe84ebb 100644 --- a/drivers/thunderbolt/switch.c +++ b/drivers/thunderbolt/switch.c @@ -1182,6 +1182,10 @@ struct tb_switch *tb_switch_alloc(struct tb *tb, struct device *parent, } sw->cap_plug_events = cap; + cap = tb_switch_find_vse_cap(sw, TB_VSE_CAP_LINK_CONTROLLER); + if (cap > 0) + sw->cap_lc = cap; + /* Root switch is always authorized */ if (!route) sw->authorized = true; @@ -1278,22 +1282,17 @@ int tb_switch_configure(struct tb_switch *sw) static int tb_switch_set_uuid(struct tb_switch *sw) { u32 uuid[4]; - int cap, ret; + int ret; - ret = 0; if (sw->uuid) - return ret; + return 0; /* * The newer controllers include fused UUID as part of link * controller specific registers */ - cap = tb_switch_find_vse_cap(sw, TB_VSE_CAP_LINK_CONTROLLER); - if (cap > 0) { - ret = tb_sw_read(sw, uuid, TB_CFG_SWITCH, cap + 3, 4); - if (ret) - return ret; - } else { + ret = tb_lc_read_uuid(sw, uuid); + if (ret) { /* * ICM generates UUID based on UID and fills the upper * two words with ones. This is not strictly following @@ -1308,8 +1307,8 @@ static int tb_switch_set_uuid(struct tb_switch *sw) sw->uuid = kmemdup(uuid, sizeof(uuid), GFP_KERNEL); if (!sw->uuid) - ret = -ENOMEM; - return ret; + return -ENOMEM; + return 0; } static int tb_switch_add_dma_port(struct tb_switch *sw) diff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h index a166265dfcf91b0856ee7a554eb95c418c960208..e52d39b25266a53bfcdef715b3c5061664408cfa 100644 --- a/drivers/thunderbolt/tb.h +++ b/drivers/thunderbolt/tb.h @@ -63,6 +63,7 @@ struct tb_switch_nvm { * @device_name: Name of the device (or %NULL if not known) * @generation: Switch Thunderbolt generation * @cap_plug_events: Offset to the plug events capability (%0 if not found) + * @cap_lc: Offset to the link controller capability (%0 if not found) * @is_unplugged: The switch is going away * @drom: DROM of the switch (%NULL if not found) * @nvm: Pointer to the NVM if the switch has one (%NULL otherwise) @@ -96,6 +97,7 @@ struct tb_switch { const char *device_name; unsigned int generation; int cap_plug_events; + int cap_lc; bool is_unplugged; u8 *drom; struct tb_switch_nvm *nvm; @@ -462,6 +464,7 @@ bool tb_path_is_invalid(struct tb_path *path); int tb_drom_read(struct tb_switch *sw); int tb_drom_read_uid_only(struct tb_switch *sw, u64 *uid); +int tb_lc_read_uuid(struct tb_switch *sw, u32 *uuid); static inline int tb_route_length(u64 route) { diff --git a/drivers/thunderbolt/tb_regs.h b/drivers/thunderbolt/tb_regs.h index 6f1ff04ee1959cf1d24cf130bbffbc3537679d10..4895ae9f0b4016cccb9aab9c909869570794357f 100644 --- a/drivers/thunderbolt/tb_regs.h +++ b/drivers/thunderbolt/tb_regs.h @@ -237,5 +237,7 @@ struct tb_regs_hop { u32 unknown3:4; /* set to zero */ } __packed; +/* Common link controller registers */ +#define TB_LC_FUSE 0x03 #endif