1fd3b339cSMika Westerberg // SPDX-License-Identifier: GPL-2.0 2d1ff7024SMika Westerberg /* 3d1ff7024SMika Westerberg * Thunderbolt XDomain discovery protocol support 4d1ff7024SMika Westerberg * 5d1ff7024SMika Westerberg * Copyright (C) 2017, Intel Corporation 6d1ff7024SMika Westerberg * Authors: Michael Jamet <michael.jamet@intel.com> 7d1ff7024SMika Westerberg * Mika Westerberg <mika.westerberg@linux.intel.com> 8d1ff7024SMika Westerberg */ 9d1ff7024SMika Westerberg 10d1ff7024SMika Westerberg #include <linux/device.h> 115cc0df9cSIsaac Hazan #include <linux/delay.h> 12d1ff7024SMika Westerberg #include <linux/kmod.h> 13d1ff7024SMika Westerberg #include <linux/module.h> 142d8ff0b5SMika Westerberg #include <linux/pm_runtime.h> 15a6932c3fSMika Westerberg #include <linux/prandom.h> 1687fa05b6SAndy Shevchenko #include <linux/string_helpers.h> 17d1ff7024SMika Westerberg #include <linux/utsname.h> 18d1ff7024SMika Westerberg #include <linux/uuid.h> 19d1ff7024SMika Westerberg #include <linux/workqueue.h> 20d1ff7024SMika Westerberg 21d1ff7024SMika Westerberg #include "tb.h" 22d1ff7024SMika Westerberg 238e1de704SMika Westerberg #define XDOMAIN_SHORT_TIMEOUT 100 /* ms */ 243bb16333SMika Westerberg #define XDOMAIN_DEFAULT_TIMEOUT 1000 /* ms */ 258e1de704SMika Westerberg #define XDOMAIN_BONDING_TIMEOUT 10000 /* ms */ 268e1de704SMika Westerberg #define XDOMAIN_RETRIES 10 2746b494f2SMika Westerberg #define XDOMAIN_DEFAULT_MAX_HOPID 15 28d1ff7024SMika Westerberg 298e1de704SMika Westerberg enum { 308e1de704SMika Westerberg XDOMAIN_STATE_INIT, 318e1de704SMika Westerberg XDOMAIN_STATE_UUID, 328e1de704SMika Westerberg XDOMAIN_STATE_LINK_STATUS, 338e1de704SMika Westerberg XDOMAIN_STATE_LINK_STATE_CHANGE, 348e1de704SMika Westerberg XDOMAIN_STATE_LINK_STATUS2, 358e1de704SMika Westerberg XDOMAIN_STATE_BONDING_UUID_LOW, 368e1de704SMika Westerberg XDOMAIN_STATE_BONDING_UUID_HIGH, 378e1de704SMika Westerberg XDOMAIN_STATE_PROPERTIES, 388e1de704SMika Westerberg XDOMAIN_STATE_ENUMERATED, 398e1de704SMika Westerberg XDOMAIN_STATE_ERROR, 408e1de704SMika Westerberg }; 418e1de704SMika Westerberg 428e1de704SMika Westerberg static const char * const state_names[] = { 438e1de704SMika Westerberg [XDOMAIN_STATE_INIT] = "INIT", 448e1de704SMika Westerberg [XDOMAIN_STATE_UUID] = "UUID", 458e1de704SMika Westerberg [XDOMAIN_STATE_LINK_STATUS] = "LINK_STATUS", 468e1de704SMika Westerberg [XDOMAIN_STATE_LINK_STATE_CHANGE] = "LINK_STATE_CHANGE", 478e1de704SMika Westerberg [XDOMAIN_STATE_LINK_STATUS2] = "LINK_STATUS2", 488e1de704SMika Westerberg [XDOMAIN_STATE_BONDING_UUID_LOW] = "BONDING_UUID_LOW", 498e1de704SMika Westerberg [XDOMAIN_STATE_BONDING_UUID_HIGH] = "BONDING_UUID_HIGH", 508e1de704SMika Westerberg [XDOMAIN_STATE_PROPERTIES] = "PROPERTIES", 518e1de704SMika Westerberg [XDOMAIN_STATE_ENUMERATED] = "ENUMERATED", 528e1de704SMika Westerberg [XDOMAIN_STATE_ERROR] = "ERROR", 538e1de704SMika Westerberg }; 548e1de704SMika Westerberg 55d1ff7024SMika Westerberg struct xdomain_request_work { 56d1ff7024SMika Westerberg struct work_struct work; 57d1ff7024SMika Westerberg struct tb_xdp_header *pkg; 58d1ff7024SMika Westerberg struct tb *tb; 59d1ff7024SMika Westerberg }; 60d1ff7024SMika Westerberg 615ca67688SMika Westerberg static bool tb_xdomain_enabled = true; 625ca67688SMika Westerberg module_param_named(xdomain, tb_xdomain_enabled, bool, 0444); 635ca67688SMika Westerberg MODULE_PARM_DESC(xdomain, "allow XDomain protocol (default: true)"); 645ca67688SMika Westerberg 6546b494f2SMika Westerberg /* 6646b494f2SMika Westerberg * Serializes access to the properties and protocol handlers below. If 6746b494f2SMika Westerberg * you need to take both this lock and the struct tb_xdomain lock, take 6846b494f2SMika Westerberg * this one first. 6946b494f2SMika Westerberg */ 70d1ff7024SMika Westerberg static DEFINE_MUTEX(xdomain_lock); 71d1ff7024SMika Westerberg 72d1ff7024SMika Westerberg /* Properties exposed to the remote domains */ 73d1ff7024SMika Westerberg static struct tb_property_dir *xdomain_property_dir; 74d1ff7024SMika Westerberg static u32 xdomain_property_block_gen; 75d1ff7024SMika Westerberg 76d1ff7024SMika Westerberg /* Additional protocol handlers */ 77d1ff7024SMika Westerberg static LIST_HEAD(protocol_handlers); 78d1ff7024SMika Westerberg 79d1ff7024SMika Westerberg /* UUID for XDomain discovery protocol: b638d70e-42ff-40bb-97c2-90e2c0b2ff07 */ 80d1ff7024SMika Westerberg static const uuid_t tb_xdp_uuid = 81d1ff7024SMika Westerberg UUID_INIT(0xb638d70e, 0x42ff, 0x40bb, 82d1ff7024SMika Westerberg 0x97, 0xc2, 0x90, 0xe2, 0xc0, 0xb2, 0xff, 0x07); 83d1ff7024SMika Westerberg 845ca67688SMika Westerberg bool tb_is_xdomain_enabled(void) 855ca67688SMika Westerberg { 86c6da62a2SMika Westerberg return tb_xdomain_enabled && tb_acpi_is_xdomain_allowed(); 875ca67688SMika Westerberg } 885ca67688SMika Westerberg 89d1ff7024SMika Westerberg static bool tb_xdomain_match(const struct tb_cfg_request *req, 90d1ff7024SMika Westerberg const struct ctl_pkg *pkg) 91d1ff7024SMika Westerberg { 92d1ff7024SMika Westerberg switch (pkg->frame.eof) { 93d1ff7024SMika Westerberg case TB_CFG_PKG_ERROR: 94d1ff7024SMika Westerberg return true; 95d1ff7024SMika Westerberg 96d1ff7024SMika Westerberg case TB_CFG_PKG_XDOMAIN_RESP: { 97d1ff7024SMika Westerberg const struct tb_xdp_header *res_hdr = pkg->buffer; 98d1ff7024SMika Westerberg const struct tb_xdp_header *req_hdr = req->request; 99d1ff7024SMika Westerberg 100d1ff7024SMika Westerberg if (pkg->frame.size < req->response_size / 4) 101d1ff7024SMika Westerberg return false; 102d1ff7024SMika Westerberg 103d1ff7024SMika Westerberg /* Make sure route matches */ 104d1ff7024SMika Westerberg if ((res_hdr->xd_hdr.route_hi & ~BIT(31)) != 105d1ff7024SMika Westerberg req_hdr->xd_hdr.route_hi) 106d1ff7024SMika Westerberg return false; 107d1ff7024SMika Westerberg if ((res_hdr->xd_hdr.route_lo) != req_hdr->xd_hdr.route_lo) 108d1ff7024SMika Westerberg return false; 109d1ff7024SMika Westerberg 110d1ff7024SMika Westerberg /* Check that the XDomain protocol matches */ 111d1ff7024SMika Westerberg if (!uuid_equal(&res_hdr->uuid, &req_hdr->uuid)) 112d1ff7024SMika Westerberg return false; 113d1ff7024SMika Westerberg 114d1ff7024SMika Westerberg return true; 115d1ff7024SMika Westerberg } 116d1ff7024SMika Westerberg 117d1ff7024SMika Westerberg default: 118d1ff7024SMika Westerberg return false; 119d1ff7024SMika Westerberg } 120d1ff7024SMika Westerberg } 121d1ff7024SMika Westerberg 122d1ff7024SMika Westerberg static bool tb_xdomain_copy(struct tb_cfg_request *req, 123d1ff7024SMika Westerberg const struct ctl_pkg *pkg) 124d1ff7024SMika Westerberg { 125d1ff7024SMika Westerberg memcpy(req->response, pkg->buffer, req->response_size); 126d1ff7024SMika Westerberg req->result.err = 0; 127d1ff7024SMika Westerberg return true; 128d1ff7024SMika Westerberg } 129d1ff7024SMika Westerberg 130d1ff7024SMika Westerberg static void response_ready(void *data) 131d1ff7024SMika Westerberg { 132d1ff7024SMika Westerberg tb_cfg_request_put(data); 133d1ff7024SMika Westerberg } 134d1ff7024SMika Westerberg 135d1ff7024SMika Westerberg static int __tb_xdomain_response(struct tb_ctl *ctl, const void *response, 136d1ff7024SMika Westerberg size_t size, enum tb_cfg_pkg_type type) 137d1ff7024SMika Westerberg { 138d1ff7024SMika Westerberg struct tb_cfg_request *req; 139d1ff7024SMika Westerberg 140d1ff7024SMika Westerberg req = tb_cfg_request_alloc(); 141d1ff7024SMika Westerberg if (!req) 142d1ff7024SMika Westerberg return -ENOMEM; 143d1ff7024SMika Westerberg 144d1ff7024SMika Westerberg req->match = tb_xdomain_match; 145d1ff7024SMika Westerberg req->copy = tb_xdomain_copy; 146d1ff7024SMika Westerberg req->request = response; 147d1ff7024SMika Westerberg req->request_size = size; 148d1ff7024SMika Westerberg req->request_type = type; 149d1ff7024SMika Westerberg 150d1ff7024SMika Westerberg return tb_cfg_request(ctl, req, response_ready, req); 151d1ff7024SMika Westerberg } 152d1ff7024SMika Westerberg 153d1ff7024SMika Westerberg /** 154d1ff7024SMika Westerberg * tb_xdomain_response() - Send a XDomain response message 155d1ff7024SMika Westerberg * @xd: XDomain to send the message 156d1ff7024SMika Westerberg * @response: Response to send 157d1ff7024SMika Westerberg * @size: Size of the response 158d1ff7024SMika Westerberg * @type: PDF type of the response 159d1ff7024SMika Westerberg * 160d1ff7024SMika Westerberg * This can be used to send a XDomain response message to the other 161d1ff7024SMika Westerberg * domain. No response for the message is expected. 162d1ff7024SMika Westerberg * 163d1ff7024SMika Westerberg * Return: %0 in case of success and negative errno in case of failure 164d1ff7024SMika Westerberg */ 165d1ff7024SMika Westerberg int tb_xdomain_response(struct tb_xdomain *xd, const void *response, 166d1ff7024SMika Westerberg size_t size, enum tb_cfg_pkg_type type) 167d1ff7024SMika Westerberg { 168d1ff7024SMika Westerberg return __tb_xdomain_response(xd->tb->ctl, response, size, type); 169d1ff7024SMika Westerberg } 170d1ff7024SMika Westerberg EXPORT_SYMBOL_GPL(tb_xdomain_response); 171d1ff7024SMika Westerberg 172d1ff7024SMika Westerberg static int __tb_xdomain_request(struct tb_ctl *ctl, const void *request, 173d1ff7024SMika Westerberg size_t request_size, enum tb_cfg_pkg_type request_type, void *response, 174d1ff7024SMika Westerberg size_t response_size, enum tb_cfg_pkg_type response_type, 175d1ff7024SMika Westerberg unsigned int timeout_msec) 176d1ff7024SMika Westerberg { 177d1ff7024SMika Westerberg struct tb_cfg_request *req; 178d1ff7024SMika Westerberg struct tb_cfg_result res; 179d1ff7024SMika Westerberg 180d1ff7024SMika Westerberg req = tb_cfg_request_alloc(); 181d1ff7024SMika Westerberg if (!req) 182d1ff7024SMika Westerberg return -ENOMEM; 183d1ff7024SMika Westerberg 184d1ff7024SMika Westerberg req->match = tb_xdomain_match; 185d1ff7024SMika Westerberg req->copy = tb_xdomain_copy; 186d1ff7024SMika Westerberg req->request = request; 187d1ff7024SMika Westerberg req->request_size = request_size; 188d1ff7024SMika Westerberg req->request_type = request_type; 189d1ff7024SMika Westerberg req->response = response; 190d1ff7024SMika Westerberg req->response_size = response_size; 191d1ff7024SMika Westerberg req->response_type = response_type; 192d1ff7024SMika Westerberg 193d1ff7024SMika Westerberg res = tb_cfg_request_sync(ctl, req, timeout_msec); 194d1ff7024SMika Westerberg 195d1ff7024SMika Westerberg tb_cfg_request_put(req); 196d1ff7024SMika Westerberg 197d1ff7024SMika Westerberg return res.err == 1 ? -EIO : res.err; 198d1ff7024SMika Westerberg } 199d1ff7024SMika Westerberg 200d1ff7024SMika Westerberg /** 201d1ff7024SMika Westerberg * tb_xdomain_request() - Send a XDomain request 202d1ff7024SMika Westerberg * @xd: XDomain to send the request 203d1ff7024SMika Westerberg * @request: Request to send 204d1ff7024SMika Westerberg * @request_size: Size of the request in bytes 205d1ff7024SMika Westerberg * @request_type: PDF type of the request 206d1ff7024SMika Westerberg * @response: Response is copied here 207d1ff7024SMika Westerberg * @response_size: Expected size of the response in bytes 208d1ff7024SMika Westerberg * @response_type: Expected PDF type of the response 209d1ff7024SMika Westerberg * @timeout_msec: Timeout in milliseconds to wait for the response 210d1ff7024SMika Westerberg * 211d1ff7024SMika Westerberg * This function can be used to send XDomain control channel messages to 212d1ff7024SMika Westerberg * the other domain. The function waits until the response is received 213d1ff7024SMika Westerberg * or when timeout triggers. Whichever comes first. 214d1ff7024SMika Westerberg * 215d1ff7024SMika Westerberg * Return: %0 in case of success and negative errno in case of failure 216d1ff7024SMika Westerberg */ 217d1ff7024SMika Westerberg int tb_xdomain_request(struct tb_xdomain *xd, const void *request, 218d1ff7024SMika Westerberg size_t request_size, enum tb_cfg_pkg_type request_type, 219d1ff7024SMika Westerberg void *response, size_t response_size, 220d1ff7024SMika Westerberg enum tb_cfg_pkg_type response_type, unsigned int timeout_msec) 221d1ff7024SMika Westerberg { 222d1ff7024SMika Westerberg return __tb_xdomain_request(xd->tb->ctl, request, request_size, 223d1ff7024SMika Westerberg request_type, response, response_size, 224d1ff7024SMika Westerberg response_type, timeout_msec); 225d1ff7024SMika Westerberg } 226d1ff7024SMika Westerberg EXPORT_SYMBOL_GPL(tb_xdomain_request); 227d1ff7024SMika Westerberg 228d1ff7024SMika Westerberg static inline void tb_xdp_fill_header(struct tb_xdp_header *hdr, u64 route, 229d1ff7024SMika Westerberg u8 sequence, enum tb_xdp_type type, size_t size) 230d1ff7024SMika Westerberg { 231d1ff7024SMika Westerberg u32 length_sn; 232d1ff7024SMika Westerberg 233d1ff7024SMika Westerberg length_sn = (size - sizeof(hdr->xd_hdr)) / 4; 234d1ff7024SMika Westerberg length_sn |= (sequence << TB_XDOMAIN_SN_SHIFT) & TB_XDOMAIN_SN_MASK; 235d1ff7024SMika Westerberg 236d1ff7024SMika Westerberg hdr->xd_hdr.route_hi = upper_32_bits(route); 237d1ff7024SMika Westerberg hdr->xd_hdr.route_lo = lower_32_bits(route); 238d1ff7024SMika Westerberg hdr->xd_hdr.length_sn = length_sn; 239d1ff7024SMika Westerberg hdr->type = type; 240d1ff7024SMika Westerberg memcpy(&hdr->uuid, &tb_xdp_uuid, sizeof(tb_xdp_uuid)); 241d1ff7024SMika Westerberg } 242d1ff7024SMika Westerberg 24319813551SKees Cook static int tb_xdp_handle_error(const struct tb_xdp_error_response *res) 244d1ff7024SMika Westerberg { 24519813551SKees Cook if (res->hdr.type != ERROR_RESPONSE) 246d1ff7024SMika Westerberg return 0; 247d1ff7024SMika Westerberg 24819813551SKees Cook switch (res->error) { 249d1ff7024SMika Westerberg case ERROR_UNKNOWN_PACKET: 250d1ff7024SMika Westerberg case ERROR_UNKNOWN_DOMAIN: 251d1ff7024SMika Westerberg return -EIO; 252d1ff7024SMika Westerberg case ERROR_NOT_SUPPORTED: 253*668906cfSMika Westerberg return -EOPNOTSUPP; 254d1ff7024SMika Westerberg case ERROR_NOT_READY: 255d1ff7024SMika Westerberg return -EAGAIN; 256d1ff7024SMika Westerberg default: 257d1ff7024SMika Westerberg break; 258d1ff7024SMika Westerberg } 259d1ff7024SMika Westerberg 260d1ff7024SMika Westerberg return 0; 261d1ff7024SMika Westerberg } 262d1ff7024SMika Westerberg 2633b4b3235SMika Westerberg static int tb_xdp_uuid_request(struct tb_ctl *ctl, u64 route, int retry, 2648e1de704SMika Westerberg uuid_t *uuid, u64 *remote_route) 2653b4b3235SMika Westerberg { 2663b4b3235SMika Westerberg struct tb_xdp_uuid_response res; 2673b4b3235SMika Westerberg struct tb_xdp_uuid req; 2683b4b3235SMika Westerberg int ret; 2693b4b3235SMika Westerberg 2703b4b3235SMika Westerberg memset(&req, 0, sizeof(req)); 2713b4b3235SMika Westerberg tb_xdp_fill_header(&req.hdr, route, retry % 4, UUID_REQUEST, 2723b4b3235SMika Westerberg sizeof(req)); 2733b4b3235SMika Westerberg 2743b4b3235SMika Westerberg memset(&res, 0, sizeof(res)); 2753b4b3235SMika Westerberg ret = __tb_xdomain_request(ctl, &req, sizeof(req), 2763b4b3235SMika Westerberg TB_CFG_PKG_XDOMAIN_REQ, &res, sizeof(res), 2773b4b3235SMika Westerberg TB_CFG_PKG_XDOMAIN_RESP, 2783b4b3235SMika Westerberg XDOMAIN_DEFAULT_TIMEOUT); 2793b4b3235SMika Westerberg if (ret) 2803b4b3235SMika Westerberg return ret; 2813b4b3235SMika Westerberg 28219813551SKees Cook ret = tb_xdp_handle_error(&res.err); 2833b4b3235SMika Westerberg if (ret) 2843b4b3235SMika Westerberg return ret; 2853b4b3235SMika Westerberg 2863b4b3235SMika Westerberg uuid_copy(uuid, &res.src_uuid); 2878e1de704SMika Westerberg *remote_route = (u64)res.src_route_hi << 32 | res.src_route_lo; 2888e1de704SMika Westerberg 2893b4b3235SMika Westerberg return 0; 2903b4b3235SMika Westerberg } 2913b4b3235SMika Westerberg 2923b4b3235SMika Westerberg static int tb_xdp_uuid_response(struct tb_ctl *ctl, u64 route, u8 sequence, 2933b4b3235SMika Westerberg const uuid_t *uuid) 2943b4b3235SMika Westerberg { 2953b4b3235SMika Westerberg struct tb_xdp_uuid_response res; 2963b4b3235SMika Westerberg 2973b4b3235SMika Westerberg memset(&res, 0, sizeof(res)); 2983b4b3235SMika Westerberg tb_xdp_fill_header(&res.hdr, route, sequence, UUID_RESPONSE, 2993b4b3235SMika Westerberg sizeof(res)); 3003b4b3235SMika Westerberg 3013b4b3235SMika Westerberg uuid_copy(&res.src_uuid, uuid); 3023b4b3235SMika Westerberg res.src_route_hi = upper_32_bits(route); 3033b4b3235SMika Westerberg res.src_route_lo = lower_32_bits(route); 3043b4b3235SMika Westerberg 3053b4b3235SMika Westerberg return __tb_xdomain_response(ctl, &res, sizeof(res), 3063b4b3235SMika Westerberg TB_CFG_PKG_XDOMAIN_RESP); 3073b4b3235SMika Westerberg } 3083b4b3235SMika Westerberg 309d1ff7024SMika Westerberg static int tb_xdp_error_response(struct tb_ctl *ctl, u64 route, u8 sequence, 310d1ff7024SMika Westerberg enum tb_xdp_error error) 311d1ff7024SMika Westerberg { 312d1ff7024SMika Westerberg struct tb_xdp_error_response res; 313d1ff7024SMika Westerberg 314d1ff7024SMika Westerberg memset(&res, 0, sizeof(res)); 315d1ff7024SMika Westerberg tb_xdp_fill_header(&res.hdr, route, sequence, ERROR_RESPONSE, 316d1ff7024SMika Westerberg sizeof(res)); 317d1ff7024SMika Westerberg res.error = error; 318d1ff7024SMika Westerberg 319d1ff7024SMika Westerberg return __tb_xdomain_response(ctl, &res, sizeof(res), 320d1ff7024SMika Westerberg TB_CFG_PKG_XDOMAIN_RESP); 321d1ff7024SMika Westerberg } 322d1ff7024SMika Westerberg 323d1ff7024SMika Westerberg static int tb_xdp_properties_request(struct tb_ctl *ctl, u64 route, 324d1ff7024SMika Westerberg const uuid_t *src_uuid, const uuid_t *dst_uuid, int retry, 325d1ff7024SMika Westerberg u32 **block, u32 *generation) 326d1ff7024SMika Westerberg { 327d1ff7024SMika Westerberg struct tb_xdp_properties_response *res; 328d1ff7024SMika Westerberg struct tb_xdp_properties req; 329d1ff7024SMika Westerberg u16 data_len, len; 330d1ff7024SMika Westerberg size_t total_size; 331d1ff7024SMika Westerberg u32 *data = NULL; 332d1ff7024SMika Westerberg int ret; 333d1ff7024SMika Westerberg 334d1ff7024SMika Westerberg total_size = sizeof(*res) + TB_XDP_PROPERTIES_MAX_DATA_LENGTH * 4; 335d1ff7024SMika Westerberg res = kzalloc(total_size, GFP_KERNEL); 336d1ff7024SMika Westerberg if (!res) 337d1ff7024SMika Westerberg return -ENOMEM; 338d1ff7024SMika Westerberg 339d1ff7024SMika Westerberg memset(&req, 0, sizeof(req)); 340d1ff7024SMika Westerberg tb_xdp_fill_header(&req.hdr, route, retry % 4, PROPERTIES_REQUEST, 341d1ff7024SMika Westerberg sizeof(req)); 342d1ff7024SMika Westerberg memcpy(&req.src_uuid, src_uuid, sizeof(*src_uuid)); 343d1ff7024SMika Westerberg memcpy(&req.dst_uuid, dst_uuid, sizeof(*dst_uuid)); 344d1ff7024SMika Westerberg 345d1ff7024SMika Westerberg data_len = 0; 346d1ff7024SMika Westerberg 347d1ff7024SMika Westerberg do { 348d1ff7024SMika Westerberg ret = __tb_xdomain_request(ctl, &req, sizeof(req), 349d1ff7024SMika Westerberg TB_CFG_PKG_XDOMAIN_REQ, res, 350d1ff7024SMika Westerberg total_size, TB_CFG_PKG_XDOMAIN_RESP, 351d1ff7024SMika Westerberg XDOMAIN_DEFAULT_TIMEOUT); 352d1ff7024SMika Westerberg if (ret) 353d1ff7024SMika Westerberg goto err; 354d1ff7024SMika Westerberg 35519813551SKees Cook ret = tb_xdp_handle_error(&res->err); 356d1ff7024SMika Westerberg if (ret) 357d1ff7024SMika Westerberg goto err; 358d1ff7024SMika Westerberg 359d1ff7024SMika Westerberg /* 360d1ff7024SMika Westerberg * Package length includes the whole payload without the 361d1ff7024SMika Westerberg * XDomain header. Validate first that the package is at 362d1ff7024SMika Westerberg * least size of the response structure. 363d1ff7024SMika Westerberg */ 364d1ff7024SMika Westerberg len = res->hdr.xd_hdr.length_sn & TB_XDOMAIN_LENGTH_MASK; 365d1ff7024SMika Westerberg if (len < sizeof(*res) / 4) { 366d1ff7024SMika Westerberg ret = -EINVAL; 367d1ff7024SMika Westerberg goto err; 368d1ff7024SMika Westerberg } 369d1ff7024SMika Westerberg 370d1ff7024SMika Westerberg len += sizeof(res->hdr.xd_hdr) / 4; 371d1ff7024SMika Westerberg len -= sizeof(*res) / 4; 372d1ff7024SMika Westerberg 373d1ff7024SMika Westerberg if (res->offset != req.offset) { 374d1ff7024SMika Westerberg ret = -EINVAL; 375d1ff7024SMika Westerberg goto err; 376d1ff7024SMika Westerberg } 377d1ff7024SMika Westerberg 378d1ff7024SMika Westerberg /* 379d1ff7024SMika Westerberg * First time allocate block that has enough space for 380d1ff7024SMika Westerberg * the whole properties block. 381d1ff7024SMika Westerberg */ 382d1ff7024SMika Westerberg if (!data) { 383d1ff7024SMika Westerberg data_len = res->data_length; 384d1ff7024SMika Westerberg if (data_len > TB_XDP_PROPERTIES_MAX_LENGTH) { 385d1ff7024SMika Westerberg ret = -E2BIG; 386d1ff7024SMika Westerberg goto err; 387d1ff7024SMika Westerberg } 388d1ff7024SMika Westerberg 389d1ff7024SMika Westerberg data = kcalloc(data_len, sizeof(u32), GFP_KERNEL); 390d1ff7024SMika Westerberg if (!data) { 391d1ff7024SMika Westerberg ret = -ENOMEM; 392d1ff7024SMika Westerberg goto err; 393d1ff7024SMika Westerberg } 394d1ff7024SMika Westerberg } 395d1ff7024SMika Westerberg 396d1ff7024SMika Westerberg memcpy(data + req.offset, res->data, len * 4); 397d1ff7024SMika Westerberg req.offset += len; 398d1ff7024SMika Westerberg } while (!data_len || req.offset < data_len); 399d1ff7024SMika Westerberg 400d1ff7024SMika Westerberg *block = data; 401d1ff7024SMika Westerberg *generation = res->generation; 402d1ff7024SMika Westerberg 403d1ff7024SMika Westerberg kfree(res); 404d1ff7024SMika Westerberg 405d1ff7024SMika Westerberg return data_len; 406d1ff7024SMika Westerberg 407d1ff7024SMika Westerberg err: 408d1ff7024SMika Westerberg kfree(data); 409d1ff7024SMika Westerberg kfree(res); 410d1ff7024SMika Westerberg 411d1ff7024SMika Westerberg return ret; 412d1ff7024SMika Westerberg } 413d1ff7024SMika Westerberg 414d1ff7024SMika Westerberg static int tb_xdp_properties_response(struct tb *tb, struct tb_ctl *ctl, 41546b494f2SMika Westerberg struct tb_xdomain *xd, u8 sequence, const struct tb_xdp_properties *req) 416d1ff7024SMika Westerberg { 417d1ff7024SMika Westerberg struct tb_xdp_properties_response *res; 418d1ff7024SMika Westerberg size_t total_size; 419d1ff7024SMika Westerberg u16 len; 420d1ff7024SMika Westerberg int ret; 421d1ff7024SMika Westerberg 422d1ff7024SMika Westerberg /* 423d1ff7024SMika Westerberg * Currently we expect all requests to be directed to us. The 424d1ff7024SMika Westerberg * protocol supports forwarding, though which we might add 425d1ff7024SMika Westerberg * support later on. 426d1ff7024SMika Westerberg */ 42746b494f2SMika Westerberg if (!uuid_equal(xd->local_uuid, &req->dst_uuid)) { 42846b494f2SMika Westerberg tb_xdp_error_response(ctl, xd->route, sequence, 429d1ff7024SMika Westerberg ERROR_UNKNOWN_DOMAIN); 430d1ff7024SMika Westerberg return 0; 431d1ff7024SMika Westerberg } 432d1ff7024SMika Westerberg 43346b494f2SMika Westerberg mutex_lock(&xd->lock); 434d1ff7024SMika Westerberg 43546b494f2SMika Westerberg if (req->offset >= xd->local_property_block_len) { 43646b494f2SMika Westerberg mutex_unlock(&xd->lock); 437d1ff7024SMika Westerberg return -EINVAL; 438d1ff7024SMika Westerberg } 439d1ff7024SMika Westerberg 44046b494f2SMika Westerberg len = xd->local_property_block_len - req->offset; 441d1ff7024SMika Westerberg len = min_t(u16, len, TB_XDP_PROPERTIES_MAX_DATA_LENGTH); 442d1ff7024SMika Westerberg total_size = sizeof(*res) + len * 4; 443d1ff7024SMika Westerberg 444d1ff7024SMika Westerberg res = kzalloc(total_size, GFP_KERNEL); 445d1ff7024SMika Westerberg if (!res) { 44646b494f2SMika Westerberg mutex_unlock(&xd->lock); 447d1ff7024SMika Westerberg return -ENOMEM; 448d1ff7024SMika Westerberg } 449d1ff7024SMika Westerberg 45046b494f2SMika Westerberg tb_xdp_fill_header(&res->hdr, xd->route, sequence, PROPERTIES_RESPONSE, 451d1ff7024SMika Westerberg total_size); 45246b494f2SMika Westerberg res->generation = xd->local_property_block_gen; 45346b494f2SMika Westerberg res->data_length = xd->local_property_block_len; 454d1ff7024SMika Westerberg res->offset = req->offset; 45546b494f2SMika Westerberg uuid_copy(&res->src_uuid, xd->local_uuid); 456d1ff7024SMika Westerberg uuid_copy(&res->dst_uuid, &req->src_uuid); 45746b494f2SMika Westerberg memcpy(res->data, &xd->local_property_block[req->offset], len * 4); 458d1ff7024SMika Westerberg 45946b494f2SMika Westerberg mutex_unlock(&xd->lock); 460d1ff7024SMika Westerberg 461d1ff7024SMika Westerberg ret = __tb_xdomain_response(ctl, res, total_size, 462d1ff7024SMika Westerberg TB_CFG_PKG_XDOMAIN_RESP); 463d1ff7024SMika Westerberg 464d1ff7024SMika Westerberg kfree(res); 465d1ff7024SMika Westerberg return ret; 466d1ff7024SMika Westerberg } 467d1ff7024SMika Westerberg 468d1ff7024SMika Westerberg static int tb_xdp_properties_changed_request(struct tb_ctl *ctl, u64 route, 469d1ff7024SMika Westerberg int retry, const uuid_t *uuid) 470d1ff7024SMika Westerberg { 471d1ff7024SMika Westerberg struct tb_xdp_properties_changed_response res; 472d1ff7024SMika Westerberg struct tb_xdp_properties_changed req; 473d1ff7024SMika Westerberg int ret; 474d1ff7024SMika Westerberg 475d1ff7024SMika Westerberg memset(&req, 0, sizeof(req)); 476d1ff7024SMika Westerberg tb_xdp_fill_header(&req.hdr, route, retry % 4, 477d1ff7024SMika Westerberg PROPERTIES_CHANGED_REQUEST, sizeof(req)); 478d1ff7024SMika Westerberg uuid_copy(&req.src_uuid, uuid); 479d1ff7024SMika Westerberg 480d1ff7024SMika Westerberg memset(&res, 0, sizeof(res)); 481d1ff7024SMika Westerberg ret = __tb_xdomain_request(ctl, &req, sizeof(req), 482d1ff7024SMika Westerberg TB_CFG_PKG_XDOMAIN_REQ, &res, sizeof(res), 483d1ff7024SMika Westerberg TB_CFG_PKG_XDOMAIN_RESP, 484d1ff7024SMika Westerberg XDOMAIN_DEFAULT_TIMEOUT); 485d1ff7024SMika Westerberg if (ret) 486d1ff7024SMika Westerberg return ret; 487d1ff7024SMika Westerberg 48819813551SKees Cook return tb_xdp_handle_error(&res.err); 489d1ff7024SMika Westerberg } 490d1ff7024SMika Westerberg 491d1ff7024SMika Westerberg static int 492d1ff7024SMika Westerberg tb_xdp_properties_changed_response(struct tb_ctl *ctl, u64 route, u8 sequence) 493d1ff7024SMika Westerberg { 494d1ff7024SMika Westerberg struct tb_xdp_properties_changed_response res; 495d1ff7024SMika Westerberg 496d1ff7024SMika Westerberg memset(&res, 0, sizeof(res)); 497d1ff7024SMika Westerberg tb_xdp_fill_header(&res.hdr, route, sequence, 498d1ff7024SMika Westerberg PROPERTIES_CHANGED_RESPONSE, sizeof(res)); 499d1ff7024SMika Westerberg return __tb_xdomain_response(ctl, &res, sizeof(res), 500d1ff7024SMika Westerberg TB_CFG_PKG_XDOMAIN_RESP); 501d1ff7024SMika Westerberg } 502d1ff7024SMika Westerberg 5038e1de704SMika Westerberg static int tb_xdp_link_state_status_request(struct tb_ctl *ctl, u64 route, 5048e1de704SMika Westerberg u8 sequence, u8 *slw, u8 *tlw, 5058e1de704SMika Westerberg u8 *sls, u8 *tls) 5068e1de704SMika Westerberg { 5078e1de704SMika Westerberg struct tb_xdp_link_state_status_response res; 5088e1de704SMika Westerberg struct tb_xdp_link_state_status req; 5098e1de704SMika Westerberg int ret; 5108e1de704SMika Westerberg 5118e1de704SMika Westerberg memset(&req, 0, sizeof(req)); 5128e1de704SMika Westerberg tb_xdp_fill_header(&req.hdr, route, sequence, LINK_STATE_STATUS_REQUEST, 5138e1de704SMika Westerberg sizeof(req)); 5148e1de704SMika Westerberg 5158e1de704SMika Westerberg memset(&res, 0, sizeof(res)); 5168e1de704SMika Westerberg ret = __tb_xdomain_request(ctl, &req, sizeof(req), TB_CFG_PKG_XDOMAIN_REQ, 5178e1de704SMika Westerberg &res, sizeof(res), TB_CFG_PKG_XDOMAIN_RESP, 5188e1de704SMika Westerberg XDOMAIN_DEFAULT_TIMEOUT); 5198e1de704SMika Westerberg if (ret) 5208e1de704SMika Westerberg return ret; 5218e1de704SMika Westerberg 5228e1de704SMika Westerberg ret = tb_xdp_handle_error(&res.err); 5238e1de704SMika Westerberg if (ret) 5248e1de704SMika Westerberg return ret; 5258e1de704SMika Westerberg 5268e1de704SMika Westerberg if (res.status != 0) 5278e1de704SMika Westerberg return -EREMOTEIO; 5288e1de704SMika Westerberg 5298e1de704SMika Westerberg *slw = res.slw; 5308e1de704SMika Westerberg *tlw = res.tlw; 5318e1de704SMika Westerberg *sls = res.sls; 5328e1de704SMika Westerberg *tls = res.tls; 5338e1de704SMika Westerberg 5348e1de704SMika Westerberg return 0; 5358e1de704SMika Westerberg } 5368e1de704SMika Westerberg 5378e1de704SMika Westerberg static int tb_xdp_link_state_status_response(struct tb *tb, struct tb_ctl *ctl, 5388e1de704SMika Westerberg struct tb_xdomain *xd, u8 sequence) 5398e1de704SMika Westerberg { 5408e1de704SMika Westerberg struct tb_xdp_link_state_status_response res; 54117fb1a3dSMika Westerberg struct tb_port *port = tb_xdomain_downstream_port(xd); 5428e1de704SMika Westerberg u32 val[2]; 5438e1de704SMika Westerberg int ret; 5448e1de704SMika Westerberg 5458e1de704SMika Westerberg memset(&res, 0, sizeof(res)); 5468e1de704SMika Westerberg tb_xdp_fill_header(&res.hdr, xd->route, sequence, 5478e1de704SMika Westerberg LINK_STATE_STATUS_RESPONSE, sizeof(res)); 5488e1de704SMika Westerberg 5498e1de704SMika Westerberg ret = tb_port_read(port, val, TB_CFG_PORT, 5508e1de704SMika Westerberg port->cap_phy + LANE_ADP_CS_0, ARRAY_SIZE(val)); 5518e1de704SMika Westerberg if (ret) 5528e1de704SMika Westerberg return ret; 5538e1de704SMika Westerberg 5548e1de704SMika Westerberg res.slw = (val[0] & LANE_ADP_CS_0_SUPPORTED_WIDTH_MASK) >> 5558e1de704SMika Westerberg LANE_ADP_CS_0_SUPPORTED_WIDTH_SHIFT; 5568e1de704SMika Westerberg res.sls = (val[0] & LANE_ADP_CS_0_SUPPORTED_SPEED_MASK) >> 5578e1de704SMika Westerberg LANE_ADP_CS_0_SUPPORTED_SPEED_SHIFT; 5588e1de704SMika Westerberg res.tls = val[1] & LANE_ADP_CS_1_TARGET_SPEED_MASK; 5598e1de704SMika Westerberg res.tlw = (val[1] & LANE_ADP_CS_1_TARGET_WIDTH_MASK) >> 5608e1de704SMika Westerberg LANE_ADP_CS_1_TARGET_WIDTH_SHIFT; 5618e1de704SMika Westerberg 5628e1de704SMika Westerberg return __tb_xdomain_response(ctl, &res, sizeof(res), 5638e1de704SMika Westerberg TB_CFG_PKG_XDOMAIN_RESP); 5648e1de704SMika Westerberg } 5658e1de704SMika Westerberg 5668e1de704SMika Westerberg static int tb_xdp_link_state_change_request(struct tb_ctl *ctl, u64 route, 5678e1de704SMika Westerberg u8 sequence, u8 tlw, u8 tls) 5688e1de704SMika Westerberg { 5698e1de704SMika Westerberg struct tb_xdp_link_state_change_response res; 5708e1de704SMika Westerberg struct tb_xdp_link_state_change req; 5718e1de704SMika Westerberg int ret; 5728e1de704SMika Westerberg 5738e1de704SMika Westerberg memset(&req, 0, sizeof(req)); 5748e1de704SMika Westerberg tb_xdp_fill_header(&req.hdr, route, sequence, LINK_STATE_CHANGE_REQUEST, 5758e1de704SMika Westerberg sizeof(req)); 5768e1de704SMika Westerberg req.tlw = tlw; 5778e1de704SMika Westerberg req.tls = tls; 5788e1de704SMika Westerberg 5798e1de704SMika Westerberg memset(&res, 0, sizeof(res)); 5808e1de704SMika Westerberg ret = __tb_xdomain_request(ctl, &req, sizeof(req), TB_CFG_PKG_XDOMAIN_REQ, 5818e1de704SMika Westerberg &res, sizeof(res), TB_CFG_PKG_XDOMAIN_RESP, 5828e1de704SMika Westerberg XDOMAIN_DEFAULT_TIMEOUT); 5838e1de704SMika Westerberg if (ret) 5848e1de704SMika Westerberg return ret; 5858e1de704SMika Westerberg 5868e1de704SMika Westerberg ret = tb_xdp_handle_error(&res.err); 5878e1de704SMika Westerberg if (ret) 5888e1de704SMika Westerberg return ret; 5898e1de704SMika Westerberg 5908e1de704SMika Westerberg return res.status != 0 ? -EREMOTEIO : 0; 5918e1de704SMika Westerberg } 5928e1de704SMika Westerberg 5938e1de704SMika Westerberg static int tb_xdp_link_state_change_response(struct tb_ctl *ctl, u64 route, 5948e1de704SMika Westerberg u8 sequence, u32 status) 5958e1de704SMika Westerberg { 5968e1de704SMika Westerberg struct tb_xdp_link_state_change_response res; 5978e1de704SMika Westerberg 5988e1de704SMika Westerberg memset(&res, 0, sizeof(res)); 5998e1de704SMika Westerberg tb_xdp_fill_header(&res.hdr, route, sequence, LINK_STATE_CHANGE_RESPONSE, 6008e1de704SMika Westerberg sizeof(res)); 6018e1de704SMika Westerberg 6028e1de704SMika Westerberg res.status = status; 6038e1de704SMika Westerberg 6048e1de704SMika Westerberg return __tb_xdomain_response(ctl, &res, sizeof(res), 6058e1de704SMika Westerberg TB_CFG_PKG_XDOMAIN_RESP); 6068e1de704SMika Westerberg } 6078e1de704SMika Westerberg 608d1ff7024SMika Westerberg /** 609d1ff7024SMika Westerberg * tb_register_protocol_handler() - Register protocol handler 610d1ff7024SMika Westerberg * @handler: Handler to register 611d1ff7024SMika Westerberg * 612d1ff7024SMika Westerberg * This allows XDomain service drivers to hook into incoming XDomain 613d1ff7024SMika Westerberg * messages. After this function is called the service driver needs to 614d1ff7024SMika Westerberg * be able to handle calls to callback whenever a package with the 615d1ff7024SMika Westerberg * registered protocol is received. 616d1ff7024SMika Westerberg */ 617d1ff7024SMika Westerberg int tb_register_protocol_handler(struct tb_protocol_handler *handler) 618d1ff7024SMika Westerberg { 619d1ff7024SMika Westerberg if (!handler->uuid || !handler->callback) 620d1ff7024SMika Westerberg return -EINVAL; 621d1ff7024SMika Westerberg if (uuid_equal(handler->uuid, &tb_xdp_uuid)) 622d1ff7024SMika Westerberg return -EINVAL; 623d1ff7024SMika Westerberg 624d1ff7024SMika Westerberg mutex_lock(&xdomain_lock); 625d1ff7024SMika Westerberg list_add_tail(&handler->list, &protocol_handlers); 626d1ff7024SMika Westerberg mutex_unlock(&xdomain_lock); 627d1ff7024SMika Westerberg 628d1ff7024SMika Westerberg return 0; 629d1ff7024SMika Westerberg } 630d1ff7024SMika Westerberg EXPORT_SYMBOL_GPL(tb_register_protocol_handler); 631d1ff7024SMika Westerberg 632d1ff7024SMika Westerberg /** 633d1ff7024SMika Westerberg * tb_unregister_protocol_handler() - Unregister protocol handler 634d1ff7024SMika Westerberg * @handler: Handler to unregister 635d1ff7024SMika Westerberg * 636d1ff7024SMika Westerberg * Removes the previously registered protocol handler. 637d1ff7024SMika Westerberg */ 638d1ff7024SMika Westerberg void tb_unregister_protocol_handler(struct tb_protocol_handler *handler) 639d1ff7024SMika Westerberg { 640d1ff7024SMika Westerberg mutex_lock(&xdomain_lock); 641d1ff7024SMika Westerberg list_del_init(&handler->list); 642d1ff7024SMika Westerberg mutex_unlock(&xdomain_lock); 643d1ff7024SMika Westerberg } 644d1ff7024SMika Westerberg EXPORT_SYMBOL_GPL(tb_unregister_protocol_handler); 645d1ff7024SMika Westerberg 64646b494f2SMika Westerberg static void update_property_block(struct tb_xdomain *xd) 6478a00c67eSMika Westerberg { 6488a00c67eSMika Westerberg mutex_lock(&xdomain_lock); 64946b494f2SMika Westerberg mutex_lock(&xd->lock); 65046b494f2SMika Westerberg /* 65146b494f2SMika Westerberg * If the local property block is not up-to-date, rebuild it now 65246b494f2SMika Westerberg * based on the global property template. 65346b494f2SMika Westerberg */ 65446b494f2SMika Westerberg if (!xd->local_property_block || 65546b494f2SMika Westerberg xd->local_property_block_gen < xdomain_property_block_gen) { 65646b494f2SMika Westerberg struct tb_property_dir *dir; 65746b494f2SMika Westerberg int ret, block_len; 65846b494f2SMika Westerberg u32 *block; 65946b494f2SMika Westerberg 66046b494f2SMika Westerberg dir = tb_property_copy_dir(xdomain_property_dir); 66146b494f2SMika Westerberg if (!dir) { 66246b494f2SMika Westerberg dev_warn(&xd->dev, "failed to copy properties\n"); 66346b494f2SMika Westerberg goto out_unlock; 6648a00c67eSMika Westerberg } 66546b494f2SMika Westerberg 66646b494f2SMika Westerberg /* Fill in non-static properties now */ 66746b494f2SMika Westerberg tb_property_add_text(dir, "deviceid", utsname()->nodename); 66846b494f2SMika Westerberg tb_property_add_immediate(dir, "maxhopid", xd->local_max_hopid); 66946b494f2SMika Westerberg 67046b494f2SMika Westerberg ret = tb_property_format_dir(dir, NULL, 0); 67146b494f2SMika Westerberg if (ret < 0) { 67246b494f2SMika Westerberg dev_warn(&xd->dev, "local property block creation failed\n"); 67346b494f2SMika Westerberg tb_property_free_dir(dir); 67446b494f2SMika Westerberg goto out_unlock; 67546b494f2SMika Westerberg } 67646b494f2SMika Westerberg 67746b494f2SMika Westerberg block_len = ret; 67846b494f2SMika Westerberg block = kcalloc(block_len, sizeof(*block), GFP_KERNEL); 67946b494f2SMika Westerberg if (!block) { 68046b494f2SMika Westerberg tb_property_free_dir(dir); 68146b494f2SMika Westerberg goto out_unlock; 68246b494f2SMika Westerberg } 68346b494f2SMika Westerberg 68446b494f2SMika Westerberg ret = tb_property_format_dir(dir, block, block_len); 68546b494f2SMika Westerberg if (ret) { 68646b494f2SMika Westerberg dev_warn(&xd->dev, "property block generation failed\n"); 68746b494f2SMika Westerberg tb_property_free_dir(dir); 68846b494f2SMika Westerberg kfree(block); 68946b494f2SMika Westerberg goto out_unlock; 69046b494f2SMika Westerberg } 69146b494f2SMika Westerberg 69246b494f2SMika Westerberg tb_property_free_dir(dir); 69346b494f2SMika Westerberg /* Release the previous block */ 69446b494f2SMika Westerberg kfree(xd->local_property_block); 69546b494f2SMika Westerberg /* Assign new one */ 69646b494f2SMika Westerberg xd->local_property_block = block; 69746b494f2SMika Westerberg xd->local_property_block_len = block_len; 69846b494f2SMika Westerberg xd->local_property_block_gen = xdomain_property_block_gen; 69946b494f2SMika Westerberg } 70046b494f2SMika Westerberg 70146b494f2SMika Westerberg out_unlock: 70246b494f2SMika Westerberg mutex_unlock(&xd->lock); 7038a00c67eSMika Westerberg mutex_unlock(&xdomain_lock); 7048a00c67eSMika Westerberg } 7058a00c67eSMika Westerberg 706308092d0SMika Westerberg static void start_handshake(struct tb_xdomain *xd) 707308092d0SMika Westerberg { 708308092d0SMika Westerberg xd->state = XDOMAIN_STATE_INIT; 709308092d0SMika Westerberg queue_delayed_work(xd->tb->wq, &xd->state_work, 710308092d0SMika Westerberg msecs_to_jiffies(XDOMAIN_SHORT_TIMEOUT)); 711308092d0SMika Westerberg } 712308092d0SMika Westerberg 713308092d0SMika Westerberg /* Can be called from state_work */ 714308092d0SMika Westerberg static void __stop_handshake(struct tb_xdomain *xd) 715308092d0SMika Westerberg { 716308092d0SMika Westerberg cancel_delayed_work_sync(&xd->properties_changed_work); 717308092d0SMika Westerberg xd->properties_changed_retries = 0; 718308092d0SMika Westerberg xd->state_retries = 0; 719308092d0SMika Westerberg } 720308092d0SMika Westerberg 721308092d0SMika Westerberg static void stop_handshake(struct tb_xdomain *xd) 722308092d0SMika Westerberg { 723308092d0SMika Westerberg cancel_delayed_work_sync(&xd->state_work); 724308092d0SMika Westerberg __stop_handshake(xd); 725308092d0SMika Westerberg } 726308092d0SMika Westerberg 727d1ff7024SMika Westerberg static void tb_xdp_handle_request(struct work_struct *work) 728d1ff7024SMika Westerberg { 729d1ff7024SMika Westerberg struct xdomain_request_work *xw = container_of(work, typeof(*xw), work); 730d1ff7024SMika Westerberg const struct tb_xdp_header *pkg = xw->pkg; 731d1ff7024SMika Westerberg const struct tb_xdomain_header *xhdr = &pkg->xd_hdr; 732d1ff7024SMika Westerberg struct tb *tb = xw->tb; 733d1ff7024SMika Westerberg struct tb_ctl *ctl = tb->ctl; 73446b494f2SMika Westerberg struct tb_xdomain *xd; 735d1ff7024SMika Westerberg const uuid_t *uuid; 736d1ff7024SMika Westerberg int ret = 0; 7379a03c3d3SDan Carpenter u32 sequence; 738d1ff7024SMika Westerberg u64 route; 739d1ff7024SMika Westerberg 740d1ff7024SMika Westerberg route = ((u64)xhdr->route_hi << 32 | xhdr->route_lo) & ~BIT_ULL(63); 741d1ff7024SMika Westerberg sequence = xhdr->length_sn & TB_XDOMAIN_SN_MASK; 742d1ff7024SMika Westerberg sequence >>= TB_XDOMAIN_SN_SHIFT; 743d1ff7024SMika Westerberg 744d1ff7024SMika Westerberg mutex_lock(&tb->lock); 745d1ff7024SMika Westerberg if (tb->root_switch) 746d1ff7024SMika Westerberg uuid = tb->root_switch->uuid; 747d1ff7024SMika Westerberg else 748d1ff7024SMika Westerberg uuid = NULL; 749d1ff7024SMika Westerberg mutex_unlock(&tb->lock); 750d1ff7024SMika Westerberg 751d1ff7024SMika Westerberg if (!uuid) { 752d1ff7024SMika Westerberg tb_xdp_error_response(ctl, route, sequence, ERROR_NOT_READY); 753d1ff7024SMika Westerberg goto out; 754d1ff7024SMika Westerberg } 755d1ff7024SMika Westerberg 75646b494f2SMika Westerberg xd = tb_xdomain_find_by_route_locked(tb, route); 75746b494f2SMika Westerberg if (xd) 75846b494f2SMika Westerberg update_property_block(xd); 75946b494f2SMika Westerberg 760d1ff7024SMika Westerberg switch (pkg->type) { 761d1ff7024SMika Westerberg case PROPERTIES_REQUEST: 7628e1de704SMika Westerberg tb_dbg(tb, "%llx: received XDomain properties request\n", route); 76346b494f2SMika Westerberg if (xd) { 76446b494f2SMika Westerberg ret = tb_xdp_properties_response(tb, ctl, xd, sequence, 765d1ff7024SMika Westerberg (const struct tb_xdp_properties *)pkg); 76646b494f2SMika Westerberg } 767d1ff7024SMika Westerberg break; 768d1ff7024SMika Westerberg 76946b494f2SMika Westerberg case PROPERTIES_CHANGED_REQUEST: 7708e1de704SMika Westerberg tb_dbg(tb, "%llx: received XDomain properties changed request\n", 7718e1de704SMika Westerberg route); 7728e1de704SMika Westerberg 773d1ff7024SMika Westerberg ret = tb_xdp_properties_changed_response(ctl, route, sequence); 774d1ff7024SMika Westerberg 775d1ff7024SMika Westerberg /* 776d1ff7024SMika Westerberg * Since the properties have been changed, let's update 777d1ff7024SMika Westerberg * the xdomain related to this connection as well in 778d1ff7024SMika Westerberg * case there is a change in services it offers. 779d1ff7024SMika Westerberg */ 7808e1de704SMika Westerberg if (xd && device_is_registered(&xd->dev)) 7818e1de704SMika Westerberg queue_delayed_work(tb->wq, &xd->state_work, 7828e1de704SMika Westerberg msecs_to_jiffies(XDOMAIN_SHORT_TIMEOUT)); 783d1ff7024SMika Westerberg break; 784d1ff7024SMika Westerberg 7853b4b3235SMika Westerberg case UUID_REQUEST_OLD: 7863b4b3235SMika Westerberg case UUID_REQUEST: 7878e1de704SMika Westerberg tb_dbg(tb, "%llx: received XDomain UUID request\n", route); 7883b4b3235SMika Westerberg ret = tb_xdp_uuid_response(ctl, route, sequence, uuid); 789308092d0SMika Westerberg /* 790308092d0SMika Westerberg * If we've stopped the discovery with an error such as 791308092d0SMika Westerberg * timing out, we will restart the handshake now that we 792308092d0SMika Westerberg * received UUID request from the remote host. 793308092d0SMika Westerberg */ 794308092d0SMika Westerberg if (!ret && xd && xd->state == XDOMAIN_STATE_ERROR) { 795308092d0SMika Westerberg dev_dbg(&xd->dev, "restarting handshake\n"); 796308092d0SMika Westerberg start_handshake(xd); 797308092d0SMika Westerberg } 7983b4b3235SMika Westerberg break; 7993b4b3235SMika Westerberg 8008e1de704SMika Westerberg case LINK_STATE_STATUS_REQUEST: 8018e1de704SMika Westerberg tb_dbg(tb, "%llx: received XDomain link state status request\n", 8028e1de704SMika Westerberg route); 8038e1de704SMika Westerberg 8048e1de704SMika Westerberg if (xd) { 8058e1de704SMika Westerberg ret = tb_xdp_link_state_status_response(tb, ctl, xd, 8068e1de704SMika Westerberg sequence); 8078e1de704SMika Westerberg } else { 8088e1de704SMika Westerberg tb_xdp_error_response(ctl, route, sequence, 8098e1de704SMika Westerberg ERROR_NOT_READY); 8108e1de704SMika Westerberg } 8118e1de704SMika Westerberg break; 8128e1de704SMika Westerberg 8138e1de704SMika Westerberg case LINK_STATE_CHANGE_REQUEST: 8148e1de704SMika Westerberg tb_dbg(tb, "%llx: received XDomain link state change request\n", 8158e1de704SMika Westerberg route); 8168e1de704SMika Westerberg 8178e1de704SMika Westerberg if (xd && xd->state == XDOMAIN_STATE_BONDING_UUID_HIGH) { 8188e1de704SMika Westerberg const struct tb_xdp_link_state_change *lsc = 8198e1de704SMika Westerberg (const struct tb_xdp_link_state_change *)pkg; 8208e1de704SMika Westerberg 8218e1de704SMika Westerberg ret = tb_xdp_link_state_change_response(ctl, route, 8228e1de704SMika Westerberg sequence, 0); 8238e1de704SMika Westerberg xd->target_link_width = lsc->tlw; 8248e1de704SMika Westerberg queue_delayed_work(tb->wq, &xd->state_work, 8258e1de704SMika Westerberg msecs_to_jiffies(XDOMAIN_SHORT_TIMEOUT)); 8268e1de704SMika Westerberg } else { 8278e1de704SMika Westerberg tb_xdp_error_response(ctl, route, sequence, 8288e1de704SMika Westerberg ERROR_NOT_READY); 8298e1de704SMika Westerberg } 8308e1de704SMika Westerberg break; 8318e1de704SMika Westerberg 832d1ff7024SMika Westerberg default: 8338e1de704SMika Westerberg tb_dbg(tb, "%llx: unknown XDomain request %#x\n", route, pkg->type); 8343b4b3235SMika Westerberg tb_xdp_error_response(ctl, route, sequence, 8353b4b3235SMika Westerberg ERROR_NOT_SUPPORTED); 836d1ff7024SMika Westerberg break; 837d1ff7024SMika Westerberg } 838d1ff7024SMika Westerberg 83946b494f2SMika Westerberg tb_xdomain_put(xd); 84046b494f2SMika Westerberg 841d1ff7024SMika Westerberg if (ret) { 842d1ff7024SMika Westerberg tb_warn(tb, "failed to send XDomain response for %#x\n", 843d1ff7024SMika Westerberg pkg->type); 844d1ff7024SMika Westerberg } 845d1ff7024SMika Westerberg 846d1ff7024SMika Westerberg out: 847d1ff7024SMika Westerberg kfree(xw->pkg); 848d1ff7024SMika Westerberg kfree(xw); 849559c1e1eSMika Westerberg 850559c1e1eSMika Westerberg tb_domain_put(tb); 851d1ff7024SMika Westerberg } 852d1ff7024SMika Westerberg 85348f40b96SAditya Pakki static bool 854d1ff7024SMika Westerberg tb_xdp_schedule_request(struct tb *tb, const struct tb_xdp_header *hdr, 855d1ff7024SMika Westerberg size_t size) 856d1ff7024SMika Westerberg { 857d1ff7024SMika Westerberg struct xdomain_request_work *xw; 858d1ff7024SMika Westerberg 859d1ff7024SMika Westerberg xw = kmalloc(sizeof(*xw), GFP_KERNEL); 860d1ff7024SMika Westerberg if (!xw) 86148f40b96SAditya Pakki return false; 862d1ff7024SMika Westerberg 863d1ff7024SMika Westerberg INIT_WORK(&xw->work, tb_xdp_handle_request); 864d1ff7024SMika Westerberg xw->pkg = kmemdup(hdr, size, GFP_KERNEL); 86548f40b96SAditya Pakki if (!xw->pkg) { 86648f40b96SAditya Pakki kfree(xw); 86748f40b96SAditya Pakki return false; 86848f40b96SAditya Pakki } 869559c1e1eSMika Westerberg xw->tb = tb_domain_get(tb); 870d1ff7024SMika Westerberg 871559c1e1eSMika Westerberg schedule_work(&xw->work); 87248f40b96SAditya Pakki return true; 873d1ff7024SMika Westerberg } 874d1ff7024SMika Westerberg 875d1ff7024SMika Westerberg /** 876d1ff7024SMika Westerberg * tb_register_service_driver() - Register XDomain service driver 877d1ff7024SMika Westerberg * @drv: Driver to register 878d1ff7024SMika Westerberg * 879d1ff7024SMika Westerberg * Registers new service driver from @drv to the bus. 880d1ff7024SMika Westerberg */ 881d1ff7024SMika Westerberg int tb_register_service_driver(struct tb_service_driver *drv) 882d1ff7024SMika Westerberg { 883d1ff7024SMika Westerberg drv->driver.bus = &tb_bus_type; 884d1ff7024SMika Westerberg return driver_register(&drv->driver); 885d1ff7024SMika Westerberg } 886d1ff7024SMika Westerberg EXPORT_SYMBOL_GPL(tb_register_service_driver); 887d1ff7024SMika Westerberg 888d1ff7024SMika Westerberg /** 889d1ff7024SMika Westerberg * tb_unregister_service_driver() - Unregister XDomain service driver 890925a2af9SLee Jones * @drv: Driver to unregister 891d1ff7024SMika Westerberg * 892d1ff7024SMika Westerberg * Unregisters XDomain service driver from the bus. 893d1ff7024SMika Westerberg */ 894d1ff7024SMika Westerberg void tb_unregister_service_driver(struct tb_service_driver *drv) 895d1ff7024SMika Westerberg { 896d1ff7024SMika Westerberg driver_unregister(&drv->driver); 897d1ff7024SMika Westerberg } 898d1ff7024SMika Westerberg EXPORT_SYMBOL_GPL(tb_unregister_service_driver); 899d1ff7024SMika Westerberg 900d1ff7024SMika Westerberg static ssize_t key_show(struct device *dev, struct device_attribute *attr, 901d1ff7024SMika Westerberg char *buf) 902d1ff7024SMika Westerberg { 903d1ff7024SMika Westerberg struct tb_service *svc = container_of(dev, struct tb_service, dev); 904d1ff7024SMika Westerberg 905d1ff7024SMika Westerberg /* 906d1ff7024SMika Westerberg * It should be null terminated but anything else is pretty much 907d1ff7024SMika Westerberg * allowed. 908d1ff7024SMika Westerberg */ 9098283fb57SAndy Shevchenko return sysfs_emit(buf, "%*pE\n", (int)strlen(svc->key), svc->key); 910d1ff7024SMika Westerberg } 911d1ff7024SMika Westerberg static DEVICE_ATTR_RO(key); 912d1ff7024SMika Westerberg 913162736b0SGreg Kroah-Hartman static int get_modalias(const struct tb_service *svc, char *buf, size_t size) 914d1ff7024SMika Westerberg { 915d1ff7024SMika Westerberg return snprintf(buf, size, "tbsvc:k%sp%08Xv%08Xr%08X", svc->key, 916d1ff7024SMika Westerberg svc->prtcid, svc->prtcvers, svc->prtcrevs); 917d1ff7024SMika Westerberg } 918d1ff7024SMika Westerberg 919d1ff7024SMika Westerberg static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, 920d1ff7024SMika Westerberg char *buf) 921d1ff7024SMika Westerberg { 922d1ff7024SMika Westerberg struct tb_service *svc = container_of(dev, struct tb_service, dev); 923d1ff7024SMika Westerberg 924d1ff7024SMika Westerberg /* Full buffer size except new line and null termination */ 925d1ff7024SMika Westerberg get_modalias(svc, buf, PAGE_SIZE - 2); 9260a0624a2SArnd Bergmann return strlen(strcat(buf, "\n")); 927d1ff7024SMika Westerberg } 928d1ff7024SMika Westerberg static DEVICE_ATTR_RO(modalias); 929d1ff7024SMika Westerberg 930d1ff7024SMika Westerberg static ssize_t prtcid_show(struct device *dev, struct device_attribute *attr, 931d1ff7024SMika Westerberg char *buf) 932d1ff7024SMika Westerberg { 933d1ff7024SMika Westerberg struct tb_service *svc = container_of(dev, struct tb_service, dev); 934d1ff7024SMika Westerberg 9358283fb57SAndy Shevchenko return sysfs_emit(buf, "%u\n", svc->prtcid); 936d1ff7024SMika Westerberg } 937d1ff7024SMika Westerberg static DEVICE_ATTR_RO(prtcid); 938d1ff7024SMika Westerberg 939d1ff7024SMika Westerberg static ssize_t prtcvers_show(struct device *dev, struct device_attribute *attr, 940d1ff7024SMika Westerberg char *buf) 941d1ff7024SMika Westerberg { 942d1ff7024SMika Westerberg struct tb_service *svc = container_of(dev, struct tb_service, dev); 943d1ff7024SMika Westerberg 9448283fb57SAndy Shevchenko return sysfs_emit(buf, "%u\n", svc->prtcvers); 945d1ff7024SMika Westerberg } 946d1ff7024SMika Westerberg static DEVICE_ATTR_RO(prtcvers); 947d1ff7024SMika Westerberg 948d1ff7024SMika Westerberg static ssize_t prtcrevs_show(struct device *dev, struct device_attribute *attr, 949d1ff7024SMika Westerberg char *buf) 950d1ff7024SMika Westerberg { 951d1ff7024SMika Westerberg struct tb_service *svc = container_of(dev, struct tb_service, dev); 952d1ff7024SMika Westerberg 9538283fb57SAndy Shevchenko return sysfs_emit(buf, "%u\n", svc->prtcrevs); 954d1ff7024SMika Westerberg } 955d1ff7024SMika Westerberg static DEVICE_ATTR_RO(prtcrevs); 956d1ff7024SMika Westerberg 957d1ff7024SMika Westerberg static ssize_t prtcstns_show(struct device *dev, struct device_attribute *attr, 958d1ff7024SMika Westerberg char *buf) 959d1ff7024SMika Westerberg { 960d1ff7024SMika Westerberg struct tb_service *svc = container_of(dev, struct tb_service, dev); 961d1ff7024SMika Westerberg 9628283fb57SAndy Shevchenko return sysfs_emit(buf, "0x%08x\n", svc->prtcstns); 963d1ff7024SMika Westerberg } 964d1ff7024SMika Westerberg static DEVICE_ATTR_RO(prtcstns); 965d1ff7024SMika Westerberg 966d1ff7024SMika Westerberg static struct attribute *tb_service_attrs[] = { 967d1ff7024SMika Westerberg &dev_attr_key.attr, 968d1ff7024SMika Westerberg &dev_attr_modalias.attr, 969d1ff7024SMika Westerberg &dev_attr_prtcid.attr, 970d1ff7024SMika Westerberg &dev_attr_prtcvers.attr, 971d1ff7024SMika Westerberg &dev_attr_prtcrevs.attr, 972d1ff7024SMika Westerberg &dev_attr_prtcstns.attr, 973d1ff7024SMika Westerberg NULL, 974d1ff7024SMika Westerberg }; 975d1ff7024SMika Westerberg 9766889e00fSRikard Falkeborn static const struct attribute_group tb_service_attr_group = { 977d1ff7024SMika Westerberg .attrs = tb_service_attrs, 978d1ff7024SMika Westerberg }; 979d1ff7024SMika Westerberg 980d1ff7024SMika Westerberg static const struct attribute_group *tb_service_attr_groups[] = { 981d1ff7024SMika Westerberg &tb_service_attr_group, 982d1ff7024SMika Westerberg NULL, 983d1ff7024SMika Westerberg }; 984d1ff7024SMika Westerberg 985162736b0SGreg Kroah-Hartman static int tb_service_uevent(const struct device *dev, struct kobj_uevent_env *env) 986d1ff7024SMika Westerberg { 987162736b0SGreg Kroah-Hartman const struct tb_service *svc = container_of_const(dev, struct tb_service, dev); 988d1ff7024SMika Westerberg char modalias[64]; 989d1ff7024SMika Westerberg 990d1ff7024SMika Westerberg get_modalias(svc, modalias, sizeof(modalias)); 991d1ff7024SMika Westerberg return add_uevent_var(env, "MODALIAS=%s", modalias); 992d1ff7024SMika Westerberg } 993d1ff7024SMika Westerberg 994d1ff7024SMika Westerberg static void tb_service_release(struct device *dev) 995d1ff7024SMika Westerberg { 996d1ff7024SMika Westerberg struct tb_service *svc = container_of(dev, struct tb_service, dev); 997d1ff7024SMika Westerberg struct tb_xdomain *xd = tb_service_parent(svc); 998d1ff7024SMika Westerberg 999407ac931SMika Westerberg tb_service_debugfs_remove(svc); 1000dec6a613SChristophe JAILLET ida_free(&xd->service_ids, svc->id); 1001d1ff7024SMika Westerberg kfree(svc->key); 1002d1ff7024SMika Westerberg kfree(svc); 1003d1ff7024SMika Westerberg } 1004d1ff7024SMika Westerberg 1005b8a73083SRicardo B. Marliere const struct device_type tb_service_type = { 1006d1ff7024SMika Westerberg .name = "thunderbolt_service", 1007d1ff7024SMika Westerberg .groups = tb_service_attr_groups, 1008d1ff7024SMika Westerberg .uevent = tb_service_uevent, 1009d1ff7024SMika Westerberg .release = tb_service_release, 1010d1ff7024SMika Westerberg }; 1011d1ff7024SMika Westerberg EXPORT_SYMBOL_GPL(tb_service_type); 1012d1ff7024SMika Westerberg 1013d1ff7024SMika Westerberg static int remove_missing_service(struct device *dev, void *data) 1014d1ff7024SMika Westerberg { 1015d1ff7024SMika Westerberg struct tb_xdomain *xd = data; 1016d1ff7024SMika Westerberg struct tb_service *svc; 1017d1ff7024SMika Westerberg 1018d1ff7024SMika Westerberg svc = tb_to_service(dev); 1019d1ff7024SMika Westerberg if (!svc) 1020d1ff7024SMika Westerberg return 0; 1021d1ff7024SMika Westerberg 102246b494f2SMika Westerberg if (!tb_property_find(xd->remote_properties, svc->key, 1023d1ff7024SMika Westerberg TB_PROPERTY_TYPE_DIRECTORY)) 1024d1ff7024SMika Westerberg device_unregister(dev); 1025d1ff7024SMika Westerberg 1026d1ff7024SMika Westerberg return 0; 1027d1ff7024SMika Westerberg } 1028d1ff7024SMika Westerberg 1029d1ff7024SMika Westerberg static int find_service(struct device *dev, void *data) 1030d1ff7024SMika Westerberg { 1031d1ff7024SMika Westerberg const struct tb_property *p = data; 1032d1ff7024SMika Westerberg struct tb_service *svc; 1033d1ff7024SMika Westerberg 1034d1ff7024SMika Westerberg svc = tb_to_service(dev); 1035d1ff7024SMika Westerberg if (!svc) 1036d1ff7024SMika Westerberg return 0; 1037d1ff7024SMika Westerberg 1038d1ff7024SMika Westerberg return !strcmp(svc->key, p->key); 1039d1ff7024SMika Westerberg } 1040d1ff7024SMika Westerberg 1041d1ff7024SMika Westerberg static int populate_service(struct tb_service *svc, 1042d1ff7024SMika Westerberg struct tb_property *property) 1043d1ff7024SMika Westerberg { 1044d1ff7024SMika Westerberg struct tb_property_dir *dir = property->value.dir; 1045d1ff7024SMika Westerberg struct tb_property *p; 1046d1ff7024SMika Westerberg 1047d1ff7024SMika Westerberg /* Fill in standard properties */ 1048d1ff7024SMika Westerberg p = tb_property_find(dir, "prtcid", TB_PROPERTY_TYPE_VALUE); 1049d1ff7024SMika Westerberg if (p) 1050d1ff7024SMika Westerberg svc->prtcid = p->value.immediate; 1051d1ff7024SMika Westerberg p = tb_property_find(dir, "prtcvers", TB_PROPERTY_TYPE_VALUE); 1052d1ff7024SMika Westerberg if (p) 1053d1ff7024SMika Westerberg svc->prtcvers = p->value.immediate; 1054d1ff7024SMika Westerberg p = tb_property_find(dir, "prtcrevs", TB_PROPERTY_TYPE_VALUE); 1055d1ff7024SMika Westerberg if (p) 1056d1ff7024SMika Westerberg svc->prtcrevs = p->value.immediate; 1057d1ff7024SMika Westerberg p = tb_property_find(dir, "prtcstns", TB_PROPERTY_TYPE_VALUE); 1058d1ff7024SMika Westerberg if (p) 1059d1ff7024SMika Westerberg svc->prtcstns = p->value.immediate; 1060d1ff7024SMika Westerberg 1061d1ff7024SMika Westerberg svc->key = kstrdup(property->key, GFP_KERNEL); 1062d1ff7024SMika Westerberg if (!svc->key) 1063d1ff7024SMika Westerberg return -ENOMEM; 1064d1ff7024SMika Westerberg 1065d1ff7024SMika Westerberg return 0; 1066d1ff7024SMika Westerberg } 1067d1ff7024SMika Westerberg 1068d1ff7024SMika Westerberg static void enumerate_services(struct tb_xdomain *xd) 1069d1ff7024SMika Westerberg { 1070d1ff7024SMika Westerberg struct tb_service *svc; 1071d1ff7024SMika Westerberg struct tb_property *p; 1072d1ff7024SMika Westerberg struct device *dev; 10739aabb685SAditya Pakki int id; 1074d1ff7024SMika Westerberg 1075d1ff7024SMika Westerberg /* 1076d1ff7024SMika Westerberg * First remove all services that are not available anymore in 1077d1ff7024SMika Westerberg * the updated property block. 1078d1ff7024SMika Westerberg */ 1079d1ff7024SMika Westerberg device_for_each_child_reverse(&xd->dev, xd, remove_missing_service); 1080d1ff7024SMika Westerberg 1081d1ff7024SMika Westerberg /* Then re-enumerate properties creating new services as we go */ 108246b494f2SMika Westerberg tb_property_for_each(xd->remote_properties, p) { 1083d1ff7024SMika Westerberg if (p->type != TB_PROPERTY_TYPE_DIRECTORY) 1084d1ff7024SMika Westerberg continue; 1085d1ff7024SMika Westerberg 1086d1ff7024SMika Westerberg /* If the service exists already we are fine */ 1087d1ff7024SMika Westerberg dev = device_find_child(&xd->dev, p, find_service); 1088d1ff7024SMika Westerberg if (dev) { 1089d1ff7024SMika Westerberg put_device(dev); 1090d1ff7024SMika Westerberg continue; 1091d1ff7024SMika Westerberg } 1092d1ff7024SMika Westerberg 1093d1ff7024SMika Westerberg svc = kzalloc(sizeof(*svc), GFP_KERNEL); 1094d1ff7024SMika Westerberg if (!svc) 1095d1ff7024SMika Westerberg break; 1096d1ff7024SMika Westerberg 1097d1ff7024SMika Westerberg if (populate_service(svc, p)) { 1098d1ff7024SMika Westerberg kfree(svc); 1099d1ff7024SMika Westerberg break; 1100d1ff7024SMika Westerberg } 1101d1ff7024SMika Westerberg 1102dec6a613SChristophe JAILLET id = ida_alloc(&xd->service_ids, GFP_KERNEL); 11039aabb685SAditya Pakki if (id < 0) { 1104a663e0dfSMika Westerberg kfree(svc->key); 11059aabb685SAditya Pakki kfree(svc); 11069aabb685SAditya Pakki break; 11079aabb685SAditya Pakki } 11089aabb685SAditya Pakki svc->id = id; 1109d1ff7024SMika Westerberg svc->dev.bus = &tb_bus_type; 1110d1ff7024SMika Westerberg svc->dev.type = &tb_service_type; 1111d1ff7024SMika Westerberg svc->dev.parent = &xd->dev; 1112d1ff7024SMika Westerberg dev_set_name(&svc->dev, "%s.%d", dev_name(&xd->dev), svc->id); 1113d1ff7024SMika Westerberg 1114407ac931SMika Westerberg tb_service_debugfs_init(svc); 1115407ac931SMika Westerberg 1116d1ff7024SMika Westerberg if (device_register(&svc->dev)) { 1117d1ff7024SMika Westerberg put_device(&svc->dev); 1118d1ff7024SMika Westerberg break; 1119d1ff7024SMika Westerberg } 1120d1ff7024SMika Westerberg } 1121d1ff7024SMika Westerberg } 1122d1ff7024SMika Westerberg 1123d1ff7024SMika Westerberg static int populate_properties(struct tb_xdomain *xd, 1124d1ff7024SMika Westerberg struct tb_property_dir *dir) 1125d1ff7024SMika Westerberg { 1126d1ff7024SMika Westerberg const struct tb_property *p; 1127d1ff7024SMika Westerberg 1128d1ff7024SMika Westerberg /* Required properties */ 1129d1ff7024SMika Westerberg p = tb_property_find(dir, "deviceid", TB_PROPERTY_TYPE_VALUE); 1130d1ff7024SMika Westerberg if (!p) 1131d1ff7024SMika Westerberg return -EINVAL; 1132d1ff7024SMika Westerberg xd->device = p->value.immediate; 1133d1ff7024SMika Westerberg 1134d1ff7024SMika Westerberg p = tb_property_find(dir, "vendorid", TB_PROPERTY_TYPE_VALUE); 1135d1ff7024SMika Westerberg if (!p) 1136d1ff7024SMika Westerberg return -EINVAL; 1137d1ff7024SMika Westerberg xd->vendor = p->value.immediate; 1138d1ff7024SMika Westerberg 113946b494f2SMika Westerberg p = tb_property_find(dir, "maxhopid", TB_PROPERTY_TYPE_VALUE); 114046b494f2SMika Westerberg /* 114146b494f2SMika Westerberg * USB4 inter-domain spec suggests using 15 as HopID if the 114246b494f2SMika Westerberg * other end does not announce it in a property. This is for 114346b494f2SMika Westerberg * TBT3 compatibility. 114446b494f2SMika Westerberg */ 114546b494f2SMika Westerberg xd->remote_max_hopid = p ? p->value.immediate : XDOMAIN_DEFAULT_MAX_HOPID; 114646b494f2SMika Westerberg 1147d1ff7024SMika Westerberg kfree(xd->device_name); 1148d1ff7024SMika Westerberg xd->device_name = NULL; 1149d1ff7024SMika Westerberg kfree(xd->vendor_name); 1150d1ff7024SMika Westerberg xd->vendor_name = NULL; 1151d1ff7024SMika Westerberg 1152d1ff7024SMika Westerberg /* Optional properties */ 1153d1ff7024SMika Westerberg p = tb_property_find(dir, "deviceid", TB_PROPERTY_TYPE_TEXT); 1154d1ff7024SMika Westerberg if (p) 1155d1ff7024SMika Westerberg xd->device_name = kstrdup(p->value.text, GFP_KERNEL); 1156d1ff7024SMika Westerberg p = tb_property_find(dir, "vendorid", TB_PROPERTY_TYPE_TEXT); 1157d1ff7024SMika Westerberg if (p) 1158d1ff7024SMika Westerberg xd->vendor_name = kstrdup(p->value.text, GFP_KERNEL); 1159d1ff7024SMika Westerberg 1160d1ff7024SMika Westerberg return 0; 1161d1ff7024SMika Westerberg } 1162d1ff7024SMika Westerberg 11634210d50fSIsaac Hazan static int tb_xdomain_update_link_attributes(struct tb_xdomain *xd) 11644210d50fSIsaac Hazan { 11654210d50fSIsaac Hazan bool change = false; 11664210d50fSIsaac Hazan struct tb_port *port; 11674210d50fSIsaac Hazan int ret; 11684210d50fSIsaac Hazan 116917fb1a3dSMika Westerberg port = tb_xdomain_downstream_port(xd); 11704210d50fSIsaac Hazan 11714210d50fSIsaac Hazan ret = tb_port_get_link_speed(port); 11724210d50fSIsaac Hazan if (ret < 0) 11734210d50fSIsaac Hazan return ret; 11744210d50fSIsaac Hazan 11754210d50fSIsaac Hazan if (xd->link_speed != ret) 11764210d50fSIsaac Hazan change = true; 11774210d50fSIsaac Hazan 11784210d50fSIsaac Hazan xd->link_speed = ret; 11794210d50fSIsaac Hazan 11804210d50fSIsaac Hazan ret = tb_port_get_link_width(port); 11814210d50fSIsaac Hazan if (ret < 0) 11824210d50fSIsaac Hazan return ret; 11834210d50fSIsaac Hazan 11844210d50fSIsaac Hazan if (xd->link_width != ret) 11854210d50fSIsaac Hazan change = true; 11864210d50fSIsaac Hazan 11874210d50fSIsaac Hazan xd->link_width = ret; 11884210d50fSIsaac Hazan 11894210d50fSIsaac Hazan if (change) 11904210d50fSIsaac Hazan kobject_uevent(&xd->dev.kobj, KOBJ_CHANGE); 11914210d50fSIsaac Hazan 11924210d50fSIsaac Hazan return 0; 11934210d50fSIsaac Hazan } 11944210d50fSIsaac Hazan 11958e1de704SMika Westerberg static int tb_xdomain_get_uuid(struct tb_xdomain *xd) 11963b4b3235SMika Westerberg { 11973b4b3235SMika Westerberg struct tb *tb = xd->tb; 11983b4b3235SMika Westerberg uuid_t uuid; 11998e1de704SMika Westerberg u64 route; 12003b4b3235SMika Westerberg int ret; 12013b4b3235SMika Westerberg 1202d29c59b1SMika Westerberg dev_dbg(&xd->dev, "requesting remote UUID\n"); 1203d29c59b1SMika Westerberg 12048e1de704SMika Westerberg ret = tb_xdp_uuid_request(tb->ctl, xd->route, xd->state_retries, &uuid, 12058e1de704SMika Westerberg &route); 12063b4b3235SMika Westerberg if (ret < 0) { 12078e1de704SMika Westerberg if (xd->state_retries-- > 0) { 1208d29c59b1SMika Westerberg dev_dbg(&xd->dev, "failed to request UUID, retrying\n"); 12098e1de704SMika Westerberg return -EAGAIN; 12103b4b3235SMika Westerberg } 12114e99c98eSAndy Shevchenko dev_dbg(&xd->dev, "failed to read remote UUID\n"); 12128e1de704SMika Westerberg return ret; 12133b4b3235SMika Westerberg } 12143b4b3235SMika Westerberg 1215d29c59b1SMika Westerberg dev_dbg(&xd->dev, "got remote UUID %pUb\n", &uuid); 1216d29c59b1SMika Westerberg 12178e1de704SMika Westerberg if (uuid_equal(&uuid, xd->local_uuid)) { 12188e1de704SMika Westerberg if (route == xd->route) 12198e1de704SMika Westerberg dev_dbg(&xd->dev, "loop back detected\n"); 12208e1de704SMika Westerberg else 12213b4b3235SMika Westerberg dev_dbg(&xd->dev, "intra-domain loop detected\n"); 12223b4b3235SMika Westerberg 12238e1de704SMika Westerberg /* Don't bond lanes automatically for loops */ 12248e1de704SMika Westerberg xd->bonding_possible = false; 12258e1de704SMika Westerberg } 12268e1de704SMika Westerberg 12273b4b3235SMika Westerberg /* 12283b4b3235SMika Westerberg * If the UUID is different, there is another domain connected 12293b4b3235SMika Westerberg * so mark this one unplugged and wait for the connection 12303b4b3235SMika Westerberg * manager to replace it. 12313b4b3235SMika Westerberg */ 12323b4b3235SMika Westerberg if (xd->remote_uuid && !uuid_equal(&uuid, xd->remote_uuid)) { 12333b4b3235SMika Westerberg dev_dbg(&xd->dev, "remote UUID is different, unplugging\n"); 12343b4b3235SMika Westerberg xd->is_unplugged = true; 12358e1de704SMika Westerberg return -ENODEV; 12363b4b3235SMika Westerberg } 12373b4b3235SMika Westerberg 12383b4b3235SMika Westerberg /* First time fill in the missing UUID */ 12393b4b3235SMika Westerberg if (!xd->remote_uuid) { 12403b4b3235SMika Westerberg xd->remote_uuid = kmemdup(&uuid, sizeof(uuid_t), GFP_KERNEL); 12413b4b3235SMika Westerberg if (!xd->remote_uuid) 12428e1de704SMika Westerberg return -ENOMEM; 12433b4b3235SMika Westerberg } 12443b4b3235SMika Westerberg 12458e1de704SMika Westerberg return 0; 12463b4b3235SMika Westerberg } 12473b4b3235SMika Westerberg 12488e1de704SMika Westerberg static int tb_xdomain_get_link_status(struct tb_xdomain *xd) 1249d1ff7024SMika Westerberg { 12508e1de704SMika Westerberg struct tb *tb = xd->tb; 12518e1de704SMika Westerberg u8 slw, tlw, sls, tls; 12528e1de704SMika Westerberg int ret; 12538e1de704SMika Westerberg 12548e1de704SMika Westerberg dev_dbg(&xd->dev, "sending link state status request to %pUb\n", 12558e1de704SMika Westerberg xd->remote_uuid); 12568e1de704SMika Westerberg 12578e1de704SMika Westerberg ret = tb_xdp_link_state_status_request(tb->ctl, xd->route, 12588e1de704SMika Westerberg xd->state_retries, &slw, &tlw, &sls, 12598e1de704SMika Westerberg &tls); 12608e1de704SMika Westerberg if (ret) { 12618e1de704SMika Westerberg if (ret != -EOPNOTSUPP && xd->state_retries-- > 0) { 12628e1de704SMika Westerberg dev_dbg(&xd->dev, 12638e1de704SMika Westerberg "failed to request remote link status, retrying\n"); 12648e1de704SMika Westerberg return -EAGAIN; 12658e1de704SMika Westerberg } 12668e1de704SMika Westerberg dev_dbg(&xd->dev, "failed to receive remote link status\n"); 12678e1de704SMika Westerberg return ret; 12688e1de704SMika Westerberg } 12698e1de704SMika Westerberg 12708e1de704SMika Westerberg dev_dbg(&xd->dev, "remote link supports width %#x speed %#x\n", slw, sls); 12718e1de704SMika Westerberg 12728e1de704SMika Westerberg if (slw < LANE_ADP_CS_0_SUPPORTED_WIDTH_DUAL) { 12738e1de704SMika Westerberg dev_dbg(&xd->dev, "remote adapter is single lane only\n"); 12748e1de704SMika Westerberg return -EOPNOTSUPP; 12758e1de704SMika Westerberg } 12768e1de704SMika Westerberg 12778e1de704SMika Westerberg return 0; 12788e1de704SMika Westerberg } 12798e1de704SMika Westerberg 12808e1de704SMika Westerberg static int tb_xdomain_link_state_change(struct tb_xdomain *xd, 12818e1de704SMika Westerberg unsigned int width) 12828e1de704SMika Westerberg { 128317fb1a3dSMika Westerberg struct tb_port *port = tb_xdomain_downstream_port(xd); 12848e1de704SMika Westerberg struct tb *tb = xd->tb; 12858e1de704SMika Westerberg u8 tlw, tls; 12868e1de704SMika Westerberg u32 val; 12878e1de704SMika Westerberg int ret; 12888e1de704SMika Westerberg 12898e1de704SMika Westerberg if (width == 2) 12908e1de704SMika Westerberg tlw = LANE_ADP_CS_1_TARGET_WIDTH_DUAL; 12918e1de704SMika Westerberg else if (width == 1) 12928e1de704SMika Westerberg tlw = LANE_ADP_CS_1_TARGET_WIDTH_SINGLE; 12938e1de704SMika Westerberg else 12948e1de704SMika Westerberg return -EINVAL; 12958e1de704SMika Westerberg 12968e1de704SMika Westerberg /* Use the current target speed */ 12978e1de704SMika Westerberg ret = tb_port_read(port, &val, TB_CFG_PORT, port->cap_phy + LANE_ADP_CS_1, 1); 12988e1de704SMika Westerberg if (ret) 12998e1de704SMika Westerberg return ret; 13008e1de704SMika Westerberg tls = val & LANE_ADP_CS_1_TARGET_SPEED_MASK; 13018e1de704SMika Westerberg 13028e1de704SMika Westerberg dev_dbg(&xd->dev, "sending link state change request with width %#x speed %#x\n", 13038e1de704SMika Westerberg tlw, tls); 13048e1de704SMika Westerberg 13058e1de704SMika Westerberg ret = tb_xdp_link_state_change_request(tb->ctl, xd->route, 13068e1de704SMika Westerberg xd->state_retries, tlw, tls); 13078e1de704SMika Westerberg if (ret) { 13088e1de704SMika Westerberg if (ret != -EOPNOTSUPP && xd->state_retries-- > 0) { 13098e1de704SMika Westerberg dev_dbg(&xd->dev, 13108e1de704SMika Westerberg "failed to change remote link state, retrying\n"); 13118e1de704SMika Westerberg return -EAGAIN; 13128e1de704SMika Westerberg } 13138e1de704SMika Westerberg dev_err(&xd->dev, "failed request link state change, aborting\n"); 13148e1de704SMika Westerberg return ret; 13158e1de704SMika Westerberg } 13168e1de704SMika Westerberg 13178e1de704SMika Westerberg dev_dbg(&xd->dev, "received link state change response\n"); 13188e1de704SMika Westerberg return 0; 13198e1de704SMika Westerberg } 13208e1de704SMika Westerberg 13218e1de704SMika Westerberg static int tb_xdomain_bond_lanes_uuid_high(struct tb_xdomain *xd) 13228e1de704SMika Westerberg { 1323e111fb92SGil Fine unsigned int width, width_mask; 13248e1de704SMika Westerberg struct tb_port *port; 1325e111fb92SGil Fine int ret; 13268e1de704SMika Westerberg 13278e1de704SMika Westerberg if (xd->target_link_width == LANE_ADP_CS_1_TARGET_WIDTH_SINGLE) { 1328e111fb92SGil Fine width = TB_LINK_WIDTH_SINGLE; 1329e111fb92SGil Fine width_mask = width; 13308e1de704SMika Westerberg } else if (xd->target_link_width == LANE_ADP_CS_1_TARGET_WIDTH_DUAL) { 1331e111fb92SGil Fine width = TB_LINK_WIDTH_DUAL; 1332e111fb92SGil Fine width_mask = width | TB_LINK_WIDTH_ASYM_TX | TB_LINK_WIDTH_ASYM_RX; 13338e1de704SMika Westerberg } else { 13348e1de704SMika Westerberg if (xd->state_retries-- > 0) { 13358e1de704SMika Westerberg dev_dbg(&xd->dev, 13368e1de704SMika Westerberg "link state change request not received yet, retrying\n"); 13378e1de704SMika Westerberg return -EAGAIN; 13388e1de704SMika Westerberg } 13398e1de704SMika Westerberg dev_dbg(&xd->dev, "timeout waiting for link change request\n"); 13408e1de704SMika Westerberg return -ETIMEDOUT; 13418e1de704SMika Westerberg } 13428e1de704SMika Westerberg 134317fb1a3dSMika Westerberg port = tb_xdomain_downstream_port(xd); 13448e1de704SMika Westerberg 13458e1de704SMika Westerberg /* 13468e1de704SMika Westerberg * We can't use tb_xdomain_lane_bonding_enable() here because it 13478e1de704SMika Westerberg * is the other side that initiates lane bonding. So here we 13488e1de704SMika Westerberg * just set the width to both lane adapters and wait for the 13498e1de704SMika Westerberg * link to transition bonded. 13508e1de704SMika Westerberg */ 13518e1de704SMika Westerberg ret = tb_port_set_link_width(port->dual_link_port, width); 13528e1de704SMika Westerberg if (ret) { 13538e1de704SMika Westerberg tb_port_warn(port->dual_link_port, 13548e1de704SMika Westerberg "failed to set link width to %d\n", width); 13558e1de704SMika Westerberg return ret; 13568e1de704SMika Westerberg } 13578e1de704SMika Westerberg 13588e1de704SMika Westerberg ret = tb_port_set_link_width(port, width); 13598e1de704SMika Westerberg if (ret) { 13608e1de704SMika Westerberg tb_port_warn(port, "failed to set link width to %d\n", width); 13618e1de704SMika Westerberg return ret; 13628e1de704SMika Westerberg } 13638e1de704SMika Westerberg 1364e111fb92SGil Fine ret = tb_port_wait_for_link_width(port, width_mask, 1365e111fb92SGil Fine XDOMAIN_BONDING_TIMEOUT); 13668e1de704SMika Westerberg if (ret) { 13678e1de704SMika Westerberg dev_warn(&xd->dev, "error waiting for link width to become %d\n", 1368e111fb92SGil Fine width_mask); 13698e1de704SMika Westerberg return ret; 13708e1de704SMika Westerberg } 13718e1de704SMika Westerberg 1372e111fb92SGil Fine port->bonded = width > TB_LINK_WIDTH_SINGLE; 1373e111fb92SGil Fine port->dual_link_port->bonded = width > TB_LINK_WIDTH_SINGLE; 13748e1de704SMika Westerberg 13758e1de704SMika Westerberg tb_port_update_credits(port); 13768e1de704SMika Westerberg tb_xdomain_update_link_attributes(xd); 13778e1de704SMika Westerberg 137887fa05b6SAndy Shevchenko dev_dbg(&xd->dev, "lane bonding %s\n", str_enabled_disabled(width == 2)); 13798e1de704SMika Westerberg return 0; 13808e1de704SMika Westerberg } 13818e1de704SMika Westerberg 13828e1de704SMika Westerberg static int tb_xdomain_get_properties(struct tb_xdomain *xd) 13838e1de704SMika Westerberg { 1384d1ff7024SMika Westerberg struct tb_property_dir *dir; 1385d1ff7024SMika Westerberg struct tb *tb = xd->tb; 1386d1ff7024SMika Westerberg bool update = false; 1387d1ff7024SMika Westerberg u32 *block = NULL; 1388d1ff7024SMika Westerberg u32 gen = 0; 1389d1ff7024SMika Westerberg int ret; 1390d1ff7024SMika Westerberg 1391d29c59b1SMika Westerberg dev_dbg(&xd->dev, "requesting remote properties\n"); 1392d29c59b1SMika Westerberg 1393d1ff7024SMika Westerberg ret = tb_xdp_properties_request(tb->ctl, xd->route, xd->local_uuid, 13948e1de704SMika Westerberg xd->remote_uuid, xd->state_retries, 1395d1ff7024SMika Westerberg &block, &gen); 1396d1ff7024SMika Westerberg if (ret < 0) { 13978e1de704SMika Westerberg if (xd->state_retries-- > 0) { 1398d29c59b1SMika Westerberg dev_dbg(&xd->dev, 1399d29c59b1SMika Westerberg "failed to request remote properties, retrying\n"); 14008e1de704SMika Westerberg return -EAGAIN; 1401d1ff7024SMika Westerberg } 14024e99c98eSAndy Shevchenko /* Give up now */ 14034e99c98eSAndy Shevchenko dev_err(&xd->dev, "failed read XDomain properties from %pUb\n", 14044e99c98eSAndy Shevchenko xd->remote_uuid); 1405d1ff7024SMika Westerberg 14068e1de704SMika Westerberg return ret; 14078e1de704SMika Westerberg } 1408d1ff7024SMika Westerberg 1409d1ff7024SMika Westerberg mutex_lock(&xd->lock); 1410d1ff7024SMika Westerberg 1411d1ff7024SMika Westerberg /* Only accept newer generation properties */ 14128e1de704SMika Westerberg if (xd->remote_properties && gen <= xd->remote_property_block_gen) { 14138e1de704SMika Westerberg ret = 0; 1414d1ff7024SMika Westerberg goto err_free_block; 14158e1de704SMika Westerberg } 1416d1ff7024SMika Westerberg 1417d1ff7024SMika Westerberg dir = tb_property_parse_dir(block, ret); 1418d1ff7024SMika Westerberg if (!dir) { 1419d1ff7024SMika Westerberg dev_err(&xd->dev, "failed to parse XDomain properties\n"); 14208e1de704SMika Westerberg ret = -ENOMEM; 1421d1ff7024SMika Westerberg goto err_free_block; 1422d1ff7024SMika Westerberg } 1423d1ff7024SMika Westerberg 1424d1ff7024SMika Westerberg ret = populate_properties(xd, dir); 1425d1ff7024SMika Westerberg if (ret) { 1426d1ff7024SMika Westerberg dev_err(&xd->dev, "missing XDomain properties in response\n"); 1427d1ff7024SMika Westerberg goto err_free_dir; 1428d1ff7024SMika Westerberg } 1429d1ff7024SMika Westerberg 1430d1ff7024SMika Westerberg /* Release the existing one */ 143146b494f2SMika Westerberg if (xd->remote_properties) { 143246b494f2SMika Westerberg tb_property_free_dir(xd->remote_properties); 1433d1ff7024SMika Westerberg update = true; 1434d1ff7024SMika Westerberg } 1435d1ff7024SMika Westerberg 143646b494f2SMika Westerberg xd->remote_properties = dir; 143746b494f2SMika Westerberg xd->remote_property_block_gen = gen; 1438d1ff7024SMika Westerberg 14394210d50fSIsaac Hazan tb_xdomain_update_link_attributes(xd); 14404210d50fSIsaac Hazan 1441d1ff7024SMika Westerberg mutex_unlock(&xd->lock); 1442d1ff7024SMika Westerberg 1443d1ff7024SMika Westerberg kfree(block); 1444d1ff7024SMika Westerberg 1445d1ff7024SMika Westerberg /* 1446d1ff7024SMika Westerberg * Now the device should be ready enough so we can add it to the 1447d1ff7024SMika Westerberg * bus and let userspace know about it. If the device is already 1448d1ff7024SMika Westerberg * registered, we notify the userspace that it has changed. 1449d1ff7024SMika Westerberg */ 1450d1ff7024SMika Westerberg if (!update) { 145184ee211cSMika Westerberg /* 145284ee211cSMika Westerberg * Now disable lane 1 if bonding was not enabled. Do 145384ee211cSMika Westerberg * this only if bonding was possible at the beginning 145484ee211cSMika Westerberg * (that is we are the connection manager and there are 145584ee211cSMika Westerberg * two lanes). 145684ee211cSMika Westerberg */ 145784ee211cSMika Westerberg if (xd->bonding_possible) { 14588e1de704SMika Westerberg struct tb_port *port; 14598e1de704SMika Westerberg 146017fb1a3dSMika Westerberg port = tb_xdomain_downstream_port(xd); 14618e1de704SMika Westerberg if (!port->bonded) 14628e1de704SMika Westerberg tb_port_disable(port->dual_link_port); 146384ee211cSMika Westerberg } 14648e1de704SMika Westerberg 1465ea20adddSGil Fine dev_dbg(&xd->dev, "current link speed %u.0 Gb/s\n", 1466ea20adddSGil Fine xd->link_speed); 1467ea20adddSGil Fine dev_dbg(&xd->dev, "current link width %s\n", 1468ea20adddSGil Fine tb_width_name(xd->link_width)); 1469ea20adddSGil Fine 1470d1ff7024SMika Westerberg if (device_add(&xd->dev)) { 1471d1ff7024SMika Westerberg dev_err(&xd->dev, "failed to add XDomain device\n"); 14728e1de704SMika Westerberg return -ENODEV; 1473d1ff7024SMika Westerberg } 1474d29c59b1SMika Westerberg dev_info(&xd->dev, "new host found, vendor=%#x device=%#x\n", 1475d29c59b1SMika Westerberg xd->vendor, xd->device); 1476d29c59b1SMika Westerberg if (xd->vendor_name && xd->device_name) 1477d29c59b1SMika Westerberg dev_info(&xd->dev, "%s %s\n", xd->vendor_name, 1478d29c59b1SMika Westerberg xd->device_name); 1479d0f1e0c2SMika Westerberg 1480d0f1e0c2SMika Westerberg tb_xdomain_debugfs_init(xd); 1481d1ff7024SMika Westerberg } else { 1482d1ff7024SMika Westerberg kobject_uevent(&xd->dev.kobj, KOBJ_CHANGE); 1483d1ff7024SMika Westerberg } 1484d1ff7024SMika Westerberg 1485d1ff7024SMika Westerberg enumerate_services(xd); 14868e1de704SMika Westerberg return 0; 1487d1ff7024SMika Westerberg 1488d1ff7024SMika Westerberg err_free_dir: 1489d1ff7024SMika Westerberg tb_property_free_dir(dir); 1490d1ff7024SMika Westerberg err_free_block: 1491d1ff7024SMika Westerberg kfree(block); 1492d1ff7024SMika Westerberg mutex_unlock(&xd->lock); 14938e1de704SMika Westerberg 14948e1de704SMika Westerberg return ret; 14958e1de704SMika Westerberg } 14968e1de704SMika Westerberg 14978e1de704SMika Westerberg static void tb_xdomain_queue_uuid(struct tb_xdomain *xd) 14988e1de704SMika Westerberg { 14998e1de704SMika Westerberg xd->state = XDOMAIN_STATE_UUID; 15008e1de704SMika Westerberg xd->state_retries = XDOMAIN_RETRIES; 15018e1de704SMika Westerberg queue_delayed_work(xd->tb->wq, &xd->state_work, 15028e1de704SMika Westerberg msecs_to_jiffies(XDOMAIN_SHORT_TIMEOUT)); 15038e1de704SMika Westerberg } 15048e1de704SMika Westerberg 15058e1de704SMika Westerberg static void tb_xdomain_queue_link_status(struct tb_xdomain *xd) 15068e1de704SMika Westerberg { 15078e1de704SMika Westerberg xd->state = XDOMAIN_STATE_LINK_STATUS; 15088e1de704SMika Westerberg xd->state_retries = XDOMAIN_RETRIES; 15098e1de704SMika Westerberg queue_delayed_work(xd->tb->wq, &xd->state_work, 15108e1de704SMika Westerberg msecs_to_jiffies(XDOMAIN_DEFAULT_TIMEOUT)); 15118e1de704SMika Westerberg } 15128e1de704SMika Westerberg 15138e1de704SMika Westerberg static void tb_xdomain_queue_link_status2(struct tb_xdomain *xd) 15148e1de704SMika Westerberg { 15158e1de704SMika Westerberg xd->state = XDOMAIN_STATE_LINK_STATUS2; 15168e1de704SMika Westerberg xd->state_retries = XDOMAIN_RETRIES; 15178e1de704SMika Westerberg queue_delayed_work(xd->tb->wq, &xd->state_work, 15188e1de704SMika Westerberg msecs_to_jiffies(XDOMAIN_DEFAULT_TIMEOUT)); 15198e1de704SMika Westerberg } 15208e1de704SMika Westerberg 15218e1de704SMika Westerberg static void tb_xdomain_queue_bonding(struct tb_xdomain *xd) 15228e1de704SMika Westerberg { 15238e1de704SMika Westerberg if (memcmp(xd->local_uuid, xd->remote_uuid, UUID_SIZE) > 0) { 15248e1de704SMika Westerberg dev_dbg(&xd->dev, "we have higher UUID, other side bonds the lanes\n"); 15258e1de704SMika Westerberg xd->state = XDOMAIN_STATE_BONDING_UUID_HIGH; 15268e1de704SMika Westerberg } else { 15278e1de704SMika Westerberg dev_dbg(&xd->dev, "we have lower UUID, bonding lanes\n"); 15288e1de704SMika Westerberg xd->state = XDOMAIN_STATE_LINK_STATE_CHANGE; 15298e1de704SMika Westerberg } 15308e1de704SMika Westerberg 15318e1de704SMika Westerberg xd->state_retries = XDOMAIN_RETRIES; 15328e1de704SMika Westerberg queue_delayed_work(xd->tb->wq, &xd->state_work, 15338e1de704SMika Westerberg msecs_to_jiffies(XDOMAIN_DEFAULT_TIMEOUT)); 15348e1de704SMika Westerberg } 15358e1de704SMika Westerberg 15368e1de704SMika Westerberg static void tb_xdomain_queue_bonding_uuid_low(struct tb_xdomain *xd) 15378e1de704SMika Westerberg { 15388e1de704SMika Westerberg xd->state = XDOMAIN_STATE_BONDING_UUID_LOW; 15398e1de704SMika Westerberg xd->state_retries = XDOMAIN_RETRIES; 15408e1de704SMika Westerberg queue_delayed_work(xd->tb->wq, &xd->state_work, 15418e1de704SMika Westerberg msecs_to_jiffies(XDOMAIN_DEFAULT_TIMEOUT)); 15428e1de704SMika Westerberg } 15438e1de704SMika Westerberg 15448e1de704SMika Westerberg static void tb_xdomain_queue_properties(struct tb_xdomain *xd) 15458e1de704SMika Westerberg { 15468e1de704SMika Westerberg xd->state = XDOMAIN_STATE_PROPERTIES; 15478e1de704SMika Westerberg xd->state_retries = XDOMAIN_RETRIES; 15488e1de704SMika Westerberg queue_delayed_work(xd->tb->wq, &xd->state_work, 15498e1de704SMika Westerberg msecs_to_jiffies(XDOMAIN_DEFAULT_TIMEOUT)); 15508e1de704SMika Westerberg } 15518e1de704SMika Westerberg 15528e1de704SMika Westerberg static void tb_xdomain_queue_properties_changed(struct tb_xdomain *xd) 15538e1de704SMika Westerberg { 15548e1de704SMika Westerberg xd->properties_changed_retries = XDOMAIN_RETRIES; 15558e1de704SMika Westerberg queue_delayed_work(xd->tb->wq, &xd->properties_changed_work, 15568e1de704SMika Westerberg msecs_to_jiffies(XDOMAIN_SHORT_TIMEOUT)); 15578e1de704SMika Westerberg } 15588e1de704SMika Westerberg 1559308092d0SMika Westerberg static void tb_xdomain_failed(struct tb_xdomain *xd) 1560308092d0SMika Westerberg { 1561308092d0SMika Westerberg xd->state = XDOMAIN_STATE_ERROR; 1562308092d0SMika Westerberg queue_delayed_work(xd->tb->wq, &xd->state_work, 1563308092d0SMika Westerberg msecs_to_jiffies(XDOMAIN_DEFAULT_TIMEOUT)); 1564308092d0SMika Westerberg } 1565308092d0SMika Westerberg 15668e1de704SMika Westerberg static void tb_xdomain_state_work(struct work_struct *work) 15678e1de704SMika Westerberg { 15688e1de704SMika Westerberg struct tb_xdomain *xd = container_of(work, typeof(*xd), state_work.work); 15698e1de704SMika Westerberg int ret, state = xd->state; 15708e1de704SMika Westerberg 15718e1de704SMika Westerberg if (WARN_ON_ONCE(state < XDOMAIN_STATE_INIT || 15728e1de704SMika Westerberg state > XDOMAIN_STATE_ERROR)) 15738e1de704SMika Westerberg return; 15748e1de704SMika Westerberg 15758e1de704SMika Westerberg dev_dbg(&xd->dev, "running state %s\n", state_names[state]); 15768e1de704SMika Westerberg 15778e1de704SMika Westerberg switch (state) { 15788e1de704SMika Westerberg case XDOMAIN_STATE_INIT: 15798e1de704SMika Westerberg if (xd->needs_uuid) { 15808e1de704SMika Westerberg tb_xdomain_queue_uuid(xd); 15818e1de704SMika Westerberg } else { 15828e1de704SMika Westerberg tb_xdomain_queue_properties_changed(xd); 15838e1de704SMika Westerberg tb_xdomain_queue_properties(xd); 15848e1de704SMika Westerberg } 15858e1de704SMika Westerberg break; 15868e1de704SMika Westerberg 15878e1de704SMika Westerberg case XDOMAIN_STATE_UUID: 15888e1de704SMika Westerberg ret = tb_xdomain_get_uuid(xd); 15898e1de704SMika Westerberg if (ret) { 15908e1de704SMika Westerberg if (ret == -EAGAIN) 15918e1de704SMika Westerberg goto retry_state; 1592308092d0SMika Westerberg tb_xdomain_failed(xd); 15938e1de704SMika Westerberg } else { 15948e1de704SMika Westerberg tb_xdomain_queue_properties_changed(xd); 15958e1de704SMika Westerberg if (xd->bonding_possible) 15968e1de704SMika Westerberg tb_xdomain_queue_link_status(xd); 15978e1de704SMika Westerberg else 15988e1de704SMika Westerberg tb_xdomain_queue_properties(xd); 15998e1de704SMika Westerberg } 16008e1de704SMika Westerberg break; 16018e1de704SMika Westerberg 16028e1de704SMika Westerberg case XDOMAIN_STATE_LINK_STATUS: 16038e1de704SMika Westerberg ret = tb_xdomain_get_link_status(xd); 16048e1de704SMika Westerberg if (ret) { 16058e1de704SMika Westerberg if (ret == -EAGAIN) 16068e1de704SMika Westerberg goto retry_state; 16078e1de704SMika Westerberg 16088e1de704SMika Westerberg /* 16098e1de704SMika Westerberg * If any of the lane bonding states fail we skip 16108e1de704SMika Westerberg * bonding completely and try to continue from 16118e1de704SMika Westerberg * reading properties. 16128e1de704SMika Westerberg */ 16138e1de704SMika Westerberg tb_xdomain_queue_properties(xd); 16148e1de704SMika Westerberg } else { 16158e1de704SMika Westerberg tb_xdomain_queue_bonding(xd); 16168e1de704SMika Westerberg } 16178e1de704SMika Westerberg break; 16188e1de704SMika Westerberg 16198e1de704SMika Westerberg case XDOMAIN_STATE_LINK_STATE_CHANGE: 16208e1de704SMika Westerberg ret = tb_xdomain_link_state_change(xd, 2); 16218e1de704SMika Westerberg if (ret) { 16228e1de704SMika Westerberg if (ret == -EAGAIN) 16238e1de704SMika Westerberg goto retry_state; 16248e1de704SMika Westerberg tb_xdomain_queue_properties(xd); 16258e1de704SMika Westerberg } else { 16268e1de704SMika Westerberg tb_xdomain_queue_link_status2(xd); 16278e1de704SMika Westerberg } 16288e1de704SMika Westerberg break; 16298e1de704SMika Westerberg 16308e1de704SMika Westerberg case XDOMAIN_STATE_LINK_STATUS2: 16318e1de704SMika Westerberg ret = tb_xdomain_get_link_status(xd); 16328e1de704SMika Westerberg if (ret) { 16338e1de704SMika Westerberg if (ret == -EAGAIN) 16348e1de704SMika Westerberg goto retry_state; 16358e1de704SMika Westerberg tb_xdomain_queue_properties(xd); 16368e1de704SMika Westerberg } else { 16378e1de704SMika Westerberg tb_xdomain_queue_bonding_uuid_low(xd); 16388e1de704SMika Westerberg } 16398e1de704SMika Westerberg break; 16408e1de704SMika Westerberg 16418e1de704SMika Westerberg case XDOMAIN_STATE_BONDING_UUID_LOW: 16428e1de704SMika Westerberg tb_xdomain_lane_bonding_enable(xd); 16438e1de704SMika Westerberg tb_xdomain_queue_properties(xd); 16448e1de704SMika Westerberg break; 16458e1de704SMika Westerberg 16468e1de704SMika Westerberg case XDOMAIN_STATE_BONDING_UUID_HIGH: 16478e1de704SMika Westerberg if (tb_xdomain_bond_lanes_uuid_high(xd) == -EAGAIN) 16488e1de704SMika Westerberg goto retry_state; 16498e1de704SMika Westerberg tb_xdomain_queue_properties(xd); 16508e1de704SMika Westerberg break; 16518e1de704SMika Westerberg 16528e1de704SMika Westerberg case XDOMAIN_STATE_PROPERTIES: 16538e1de704SMika Westerberg ret = tb_xdomain_get_properties(xd); 16548e1de704SMika Westerberg if (ret) { 16558e1de704SMika Westerberg if (ret == -EAGAIN) 16568e1de704SMika Westerberg goto retry_state; 1657308092d0SMika Westerberg tb_xdomain_failed(xd); 16588e1de704SMika Westerberg } else { 16598e1de704SMika Westerberg xd->state = XDOMAIN_STATE_ENUMERATED; 16608e1de704SMika Westerberg } 16618e1de704SMika Westerberg break; 16628e1de704SMika Westerberg 16638e1de704SMika Westerberg case XDOMAIN_STATE_ENUMERATED: 16648e1de704SMika Westerberg tb_xdomain_queue_properties(xd); 16658e1de704SMika Westerberg break; 16668e1de704SMika Westerberg 16678e1de704SMika Westerberg case XDOMAIN_STATE_ERROR: 1668308092d0SMika Westerberg dev_dbg(&xd->dev, "discovery failed, stopping handshake\n"); 1669308092d0SMika Westerberg __stop_handshake(xd); 16708e1de704SMika Westerberg break; 16718e1de704SMika Westerberg 16728e1de704SMika Westerberg default: 16738e1de704SMika Westerberg dev_warn(&xd->dev, "unexpected state %d\n", state); 16748e1de704SMika Westerberg break; 16758e1de704SMika Westerberg } 16768e1de704SMika Westerberg 16778e1de704SMika Westerberg return; 16788e1de704SMika Westerberg 16798e1de704SMika Westerberg retry_state: 16808e1de704SMika Westerberg queue_delayed_work(xd->tb->wq, &xd->state_work, 16818e1de704SMika Westerberg msecs_to_jiffies(XDOMAIN_DEFAULT_TIMEOUT)); 1682d1ff7024SMika Westerberg } 1683d1ff7024SMika Westerberg 1684d1ff7024SMika Westerberg static void tb_xdomain_properties_changed(struct work_struct *work) 1685d1ff7024SMika Westerberg { 1686d1ff7024SMika Westerberg struct tb_xdomain *xd = container_of(work, typeof(*xd), 1687d1ff7024SMika Westerberg properties_changed_work.work); 1688d1ff7024SMika Westerberg int ret; 1689d1ff7024SMika Westerberg 1690d29c59b1SMika Westerberg dev_dbg(&xd->dev, "sending properties changed notification\n"); 1691d29c59b1SMika Westerberg 1692d1ff7024SMika Westerberg ret = tb_xdp_properties_changed_request(xd->tb->ctl, xd->route, 1693d1ff7024SMika Westerberg xd->properties_changed_retries, xd->local_uuid); 1694d1ff7024SMika Westerberg if (ret) { 1695d29c59b1SMika Westerberg if (xd->properties_changed_retries-- > 0) { 1696d29c59b1SMika Westerberg dev_dbg(&xd->dev, 1697d29c59b1SMika Westerberg "failed to send properties changed notification, retrying\n"); 1698d1ff7024SMika Westerberg queue_delayed_work(xd->tb->wq, 1699d1ff7024SMika Westerberg &xd->properties_changed_work, 17008e1de704SMika Westerberg msecs_to_jiffies(XDOMAIN_DEFAULT_TIMEOUT)); 1701d29c59b1SMika Westerberg } 1702d29c59b1SMika Westerberg dev_err(&xd->dev, "failed to send properties changed notification\n"); 1703d1ff7024SMika Westerberg return; 1704d1ff7024SMika Westerberg } 1705d1ff7024SMika Westerberg 17068e1de704SMika Westerberg xd->properties_changed_retries = XDOMAIN_RETRIES; 1707d1ff7024SMika Westerberg } 1708d1ff7024SMika Westerberg 1709d1ff7024SMika Westerberg static ssize_t device_show(struct device *dev, struct device_attribute *attr, 1710d1ff7024SMika Westerberg char *buf) 1711d1ff7024SMika Westerberg { 1712d1ff7024SMika Westerberg struct tb_xdomain *xd = container_of(dev, struct tb_xdomain, dev); 1713d1ff7024SMika Westerberg 17148283fb57SAndy Shevchenko return sysfs_emit(buf, "%#x\n", xd->device); 1715d1ff7024SMika Westerberg } 1716d1ff7024SMika Westerberg static DEVICE_ATTR_RO(device); 1717d1ff7024SMika Westerberg 1718d1ff7024SMika Westerberg static ssize_t 1719d1ff7024SMika Westerberg device_name_show(struct device *dev, struct device_attribute *attr, char *buf) 1720d1ff7024SMika Westerberg { 1721d1ff7024SMika Westerberg struct tb_xdomain *xd = container_of(dev, struct tb_xdomain, dev); 1722d1ff7024SMika Westerberg int ret; 1723d1ff7024SMika Westerberg 1724d1ff7024SMika Westerberg if (mutex_lock_interruptible(&xd->lock)) 1725d1ff7024SMika Westerberg return -ERESTARTSYS; 17268283fb57SAndy Shevchenko ret = sysfs_emit(buf, "%s\n", xd->device_name ?: ""); 1727d1ff7024SMika Westerberg mutex_unlock(&xd->lock); 1728d1ff7024SMika Westerberg 1729d1ff7024SMika Westerberg return ret; 1730d1ff7024SMika Westerberg } 1731d1ff7024SMika Westerberg static DEVICE_ATTR_RO(device_name); 1732d1ff7024SMika Westerberg 173346b494f2SMika Westerberg static ssize_t maxhopid_show(struct device *dev, struct device_attribute *attr, 173446b494f2SMika Westerberg char *buf) 173546b494f2SMika Westerberg { 173646b494f2SMika Westerberg struct tb_xdomain *xd = container_of(dev, struct tb_xdomain, dev); 173746b494f2SMika Westerberg 17388283fb57SAndy Shevchenko return sysfs_emit(buf, "%d\n", xd->remote_max_hopid); 173946b494f2SMika Westerberg } 174046b494f2SMika Westerberg static DEVICE_ATTR_RO(maxhopid); 174146b494f2SMika Westerberg 1742d1ff7024SMika Westerberg static ssize_t vendor_show(struct device *dev, struct device_attribute *attr, 1743d1ff7024SMika Westerberg char *buf) 1744d1ff7024SMika Westerberg { 1745d1ff7024SMika Westerberg struct tb_xdomain *xd = container_of(dev, struct tb_xdomain, dev); 1746d1ff7024SMika Westerberg 17478283fb57SAndy Shevchenko return sysfs_emit(buf, "%#x\n", xd->vendor); 1748d1ff7024SMika Westerberg } 1749d1ff7024SMika Westerberg static DEVICE_ATTR_RO(vendor); 1750d1ff7024SMika Westerberg 1751d1ff7024SMika Westerberg static ssize_t 1752d1ff7024SMika Westerberg vendor_name_show(struct device *dev, struct device_attribute *attr, char *buf) 1753d1ff7024SMika Westerberg { 1754d1ff7024SMika Westerberg struct tb_xdomain *xd = container_of(dev, struct tb_xdomain, dev); 1755d1ff7024SMika Westerberg int ret; 1756d1ff7024SMika Westerberg 1757d1ff7024SMika Westerberg if (mutex_lock_interruptible(&xd->lock)) 1758d1ff7024SMika Westerberg return -ERESTARTSYS; 17598283fb57SAndy Shevchenko ret = sysfs_emit(buf, "%s\n", xd->vendor_name ?: ""); 1760d1ff7024SMika Westerberg mutex_unlock(&xd->lock); 1761d1ff7024SMika Westerberg 1762d1ff7024SMika Westerberg return ret; 1763d1ff7024SMika Westerberg } 1764d1ff7024SMika Westerberg static DEVICE_ATTR_RO(vendor_name); 1765d1ff7024SMika Westerberg 1766d1ff7024SMika Westerberg static ssize_t unique_id_show(struct device *dev, struct device_attribute *attr, 1767d1ff7024SMika Westerberg char *buf) 1768d1ff7024SMika Westerberg { 1769d1ff7024SMika Westerberg struct tb_xdomain *xd = container_of(dev, struct tb_xdomain, dev); 1770d1ff7024SMika Westerberg 17718283fb57SAndy Shevchenko return sysfs_emit(buf, "%pUb\n", xd->remote_uuid); 1772d1ff7024SMika Westerberg } 1773d1ff7024SMika Westerberg static DEVICE_ATTR_RO(unique_id); 1774d1ff7024SMika Westerberg 17754210d50fSIsaac Hazan static ssize_t speed_show(struct device *dev, struct device_attribute *attr, 17764210d50fSIsaac Hazan char *buf) 17774210d50fSIsaac Hazan { 17784210d50fSIsaac Hazan struct tb_xdomain *xd = container_of(dev, struct tb_xdomain, dev); 17794210d50fSIsaac Hazan 17808283fb57SAndy Shevchenko return sysfs_emit(buf, "%u.0 Gb/s\n", xd->link_speed); 17814210d50fSIsaac Hazan } 17824210d50fSIsaac Hazan 17834210d50fSIsaac Hazan static DEVICE_ATTR(rx_speed, 0444, speed_show, NULL); 17844210d50fSIsaac Hazan static DEVICE_ATTR(tx_speed, 0444, speed_show, NULL); 17854210d50fSIsaac Hazan 1786e111fb92SGil Fine static ssize_t rx_lanes_show(struct device *dev, struct device_attribute *attr, 17874210d50fSIsaac Hazan char *buf) 17884210d50fSIsaac Hazan { 17894210d50fSIsaac Hazan struct tb_xdomain *xd = container_of(dev, struct tb_xdomain, dev); 1790e111fb92SGil Fine unsigned int width; 17914210d50fSIsaac Hazan 1792e111fb92SGil Fine switch (xd->link_width) { 1793e111fb92SGil Fine case TB_LINK_WIDTH_SINGLE: 17947ebe52f3SMohammad Rahimi case TB_LINK_WIDTH_ASYM_TX: 1795e111fb92SGil Fine width = 1; 1796e111fb92SGil Fine break; 1797e111fb92SGil Fine case TB_LINK_WIDTH_DUAL: 1798e111fb92SGil Fine width = 2; 1799e111fb92SGil Fine break; 18007ebe52f3SMohammad Rahimi case TB_LINK_WIDTH_ASYM_RX: 1801e111fb92SGil Fine width = 3; 1802e111fb92SGil Fine break; 1803e111fb92SGil Fine default: 1804e111fb92SGil Fine WARN_ON_ONCE(1); 1805e111fb92SGil Fine return -EINVAL; 18064210d50fSIsaac Hazan } 18074210d50fSIsaac Hazan 1808e111fb92SGil Fine return sysfs_emit(buf, "%u\n", width); 1809e111fb92SGil Fine } 1810e111fb92SGil Fine static DEVICE_ATTR(rx_lanes, 0444, rx_lanes_show, NULL); 1811e111fb92SGil Fine 1812e111fb92SGil Fine static ssize_t tx_lanes_show(struct device *dev, struct device_attribute *attr, 1813e111fb92SGil Fine char *buf) 1814e111fb92SGil Fine { 1815e111fb92SGil Fine struct tb_xdomain *xd = container_of(dev, struct tb_xdomain, dev); 1816e111fb92SGil Fine unsigned int width; 1817e111fb92SGil Fine 1818e111fb92SGil Fine switch (xd->link_width) { 1819e111fb92SGil Fine case TB_LINK_WIDTH_SINGLE: 18207ebe52f3SMohammad Rahimi case TB_LINK_WIDTH_ASYM_RX: 1821e111fb92SGil Fine width = 1; 1822e111fb92SGil Fine break; 1823e111fb92SGil Fine case TB_LINK_WIDTH_DUAL: 1824e111fb92SGil Fine width = 2; 1825e111fb92SGil Fine break; 18267ebe52f3SMohammad Rahimi case TB_LINK_WIDTH_ASYM_TX: 1827e111fb92SGil Fine width = 3; 1828e111fb92SGil Fine break; 1829e111fb92SGil Fine default: 1830e111fb92SGil Fine WARN_ON_ONCE(1); 1831e111fb92SGil Fine return -EINVAL; 1832e111fb92SGil Fine } 1833e111fb92SGil Fine 1834e111fb92SGil Fine return sysfs_emit(buf, "%u\n", width); 1835e111fb92SGil Fine } 1836e111fb92SGil Fine static DEVICE_ATTR(tx_lanes, 0444, tx_lanes_show, NULL); 18374210d50fSIsaac Hazan 1838d1ff7024SMika Westerberg static struct attribute *xdomain_attrs[] = { 1839d1ff7024SMika Westerberg &dev_attr_device.attr, 1840d1ff7024SMika Westerberg &dev_attr_device_name.attr, 184146b494f2SMika Westerberg &dev_attr_maxhopid.attr, 18424210d50fSIsaac Hazan &dev_attr_rx_lanes.attr, 18434210d50fSIsaac Hazan &dev_attr_rx_speed.attr, 18444210d50fSIsaac Hazan &dev_attr_tx_lanes.attr, 18454210d50fSIsaac Hazan &dev_attr_tx_speed.attr, 1846d1ff7024SMika Westerberg &dev_attr_unique_id.attr, 1847d1ff7024SMika Westerberg &dev_attr_vendor.attr, 1848d1ff7024SMika Westerberg &dev_attr_vendor_name.attr, 1849d1ff7024SMika Westerberg NULL, 1850d1ff7024SMika Westerberg }; 1851d1ff7024SMika Westerberg 18526889e00fSRikard Falkeborn static const struct attribute_group xdomain_attr_group = { 1853d1ff7024SMika Westerberg .attrs = xdomain_attrs, 1854d1ff7024SMika Westerberg }; 1855d1ff7024SMika Westerberg 1856d1ff7024SMika Westerberg static const struct attribute_group *xdomain_attr_groups[] = { 1857d1ff7024SMika Westerberg &xdomain_attr_group, 1858d1ff7024SMika Westerberg NULL, 1859d1ff7024SMika Westerberg }; 1860d1ff7024SMika Westerberg 1861d1ff7024SMika Westerberg static void tb_xdomain_release(struct device *dev) 1862d1ff7024SMika Westerberg { 1863d1ff7024SMika Westerberg struct tb_xdomain *xd = container_of(dev, struct tb_xdomain, dev); 1864d1ff7024SMika Westerberg 1865d1ff7024SMika Westerberg put_device(xd->dev.parent); 1866d1ff7024SMika Westerberg 186746b494f2SMika Westerberg kfree(xd->local_property_block); 186846b494f2SMika Westerberg tb_property_free_dir(xd->remote_properties); 1869180b0689SMika Westerberg ida_destroy(&xd->out_hopids); 1870180b0689SMika Westerberg ida_destroy(&xd->in_hopids); 1871d1ff7024SMika Westerberg ida_destroy(&xd->service_ids); 1872d1ff7024SMika Westerberg 1873d1ff7024SMika Westerberg kfree(xd->local_uuid); 1874d1ff7024SMika Westerberg kfree(xd->remote_uuid); 1875d1ff7024SMika Westerberg kfree(xd->device_name); 1876d1ff7024SMika Westerberg kfree(xd->vendor_name); 1877d1ff7024SMika Westerberg kfree(xd); 1878d1ff7024SMika Westerberg } 1879d1ff7024SMika Westerberg 1880d1ff7024SMika Westerberg static int __maybe_unused tb_xdomain_suspend(struct device *dev) 1881d1ff7024SMika Westerberg { 1882d1ff7024SMika Westerberg stop_handshake(tb_to_xdomain(dev)); 1883d1ff7024SMika Westerberg return 0; 1884d1ff7024SMika Westerberg } 1885d1ff7024SMika Westerberg 1886d1ff7024SMika Westerberg static int __maybe_unused tb_xdomain_resume(struct device *dev) 1887d1ff7024SMika Westerberg { 18888ccbed24SMika Westerberg start_handshake(tb_to_xdomain(dev)); 1889d1ff7024SMika Westerberg return 0; 1890d1ff7024SMika Westerberg } 1891d1ff7024SMika Westerberg 1892d1ff7024SMika Westerberg static const struct dev_pm_ops tb_xdomain_pm_ops = { 1893d1ff7024SMika Westerberg SET_SYSTEM_SLEEP_PM_OPS(tb_xdomain_suspend, tb_xdomain_resume) 1894d1ff7024SMika Westerberg }; 1895d1ff7024SMika Westerberg 1896b8a73083SRicardo B. Marliere const struct device_type tb_xdomain_type = { 1897d1ff7024SMika Westerberg .name = "thunderbolt_xdomain", 1898d1ff7024SMika Westerberg .release = tb_xdomain_release, 1899d1ff7024SMika Westerberg .pm = &tb_xdomain_pm_ops, 1900d1ff7024SMika Westerberg }; 1901d1ff7024SMika Westerberg EXPORT_SYMBOL_GPL(tb_xdomain_type); 1902d1ff7024SMika Westerberg 190336b6ad6aSGil Fine static void tb_xdomain_link_init(struct tb_xdomain *xd, struct tb_port *down) 190436b6ad6aSGil Fine { 190536b6ad6aSGil Fine if (!down->dual_link_port) 190636b6ad6aSGil Fine return; 190736b6ad6aSGil Fine 190836b6ad6aSGil Fine /* 190936b6ad6aSGil Fine * Gen 4 links come up already as bonded so only update the port 191036b6ad6aSGil Fine * structures here. 191136b6ad6aSGil Fine */ 191236b6ad6aSGil Fine if (tb_port_get_link_generation(down) >= 4) { 191336b6ad6aSGil Fine down->bonded = true; 191436b6ad6aSGil Fine down->dual_link_port->bonded = true; 191536b6ad6aSGil Fine } else { 191636b6ad6aSGil Fine xd->bonding_possible = true; 191736b6ad6aSGil Fine } 191836b6ad6aSGil Fine } 191936b6ad6aSGil Fine 192036b6ad6aSGil Fine static void tb_xdomain_link_exit(struct tb_xdomain *xd) 192136b6ad6aSGil Fine { 192236b6ad6aSGil Fine struct tb_port *down = tb_xdomain_downstream_port(xd); 192336b6ad6aSGil Fine 192436b6ad6aSGil Fine if (!down->dual_link_port) 192536b6ad6aSGil Fine return; 192636b6ad6aSGil Fine 192736b6ad6aSGil Fine if (tb_port_get_link_generation(down) >= 4) { 192836b6ad6aSGil Fine down->bonded = false; 192936b6ad6aSGil Fine down->dual_link_port->bonded = false; 193036b6ad6aSGil Fine } else if (xd->link_width > TB_LINK_WIDTH_SINGLE) { 193136b6ad6aSGil Fine /* 193236b6ad6aSGil Fine * Just return port structures back to way they were and 193336b6ad6aSGil Fine * update credits. No need to update userspace because 193436b6ad6aSGil Fine * the XDomain is removed soon anyway. 193536b6ad6aSGil Fine */ 193636b6ad6aSGil Fine tb_port_lane_bonding_disable(down); 193736b6ad6aSGil Fine tb_port_update_credits(down); 193836b6ad6aSGil Fine } else if (down->dual_link_port) { 193936b6ad6aSGil Fine /* 194036b6ad6aSGil Fine * Re-enable the lane 1 adapter we disabled at the end 194136b6ad6aSGil Fine * of tb_xdomain_get_properties(). 194236b6ad6aSGil Fine */ 194336b6ad6aSGil Fine tb_port_enable(down->dual_link_port); 194436b6ad6aSGil Fine } 194536b6ad6aSGil Fine } 194636b6ad6aSGil Fine 1947d1ff7024SMika Westerberg /** 1948d1ff7024SMika Westerberg * tb_xdomain_alloc() - Allocate new XDomain object 1949d1ff7024SMika Westerberg * @tb: Domain where the XDomain belongs 1950d1ff7024SMika Westerberg * @parent: Parent device (the switch through the connection to the 1951d1ff7024SMika Westerberg * other domain is reached). 1952d1ff7024SMika Westerberg * @route: Route string used to reach the other domain 1953d1ff7024SMika Westerberg * @local_uuid: Our local domain UUID 19543b4b3235SMika Westerberg * @remote_uuid: UUID of the other domain (optional) 1955d1ff7024SMika Westerberg * 1956d1ff7024SMika Westerberg * Allocates new XDomain structure and returns pointer to that. The 1957d1ff7024SMika Westerberg * object must be released by calling tb_xdomain_put(). 1958d1ff7024SMika Westerberg */ 1959d1ff7024SMika Westerberg struct tb_xdomain *tb_xdomain_alloc(struct tb *tb, struct device *parent, 1960d1ff7024SMika Westerberg u64 route, const uuid_t *local_uuid, 1961d1ff7024SMika Westerberg const uuid_t *remote_uuid) 1962d1ff7024SMika Westerberg { 1963b0407983SMika Westerberg struct tb_switch *parent_sw = tb_to_switch(parent); 1964d1ff7024SMika Westerberg struct tb_xdomain *xd; 1965b0407983SMika Westerberg struct tb_port *down; 1966b0407983SMika Westerberg 1967b0407983SMika Westerberg /* Make sure the downstream domain is accessible */ 1968b0407983SMika Westerberg down = tb_port_at(route, parent_sw); 1969b0407983SMika Westerberg tb_port_unlock(down); 1970d1ff7024SMika Westerberg 1971d1ff7024SMika Westerberg xd = kzalloc(sizeof(*xd), GFP_KERNEL); 1972d1ff7024SMika Westerberg if (!xd) 1973d1ff7024SMika Westerberg return NULL; 1974d1ff7024SMika Westerberg 1975d1ff7024SMika Westerberg xd->tb = tb; 1976d1ff7024SMika Westerberg xd->route = route; 197746b494f2SMika Westerberg xd->local_max_hopid = down->config.max_in_hop_id; 1978d1ff7024SMika Westerberg ida_init(&xd->service_ids); 1979180b0689SMika Westerberg ida_init(&xd->in_hopids); 1980180b0689SMika Westerberg ida_init(&xd->out_hopids); 1981d1ff7024SMika Westerberg mutex_init(&xd->lock); 19828e1de704SMika Westerberg INIT_DELAYED_WORK(&xd->state_work, tb_xdomain_state_work); 1983d1ff7024SMika Westerberg INIT_DELAYED_WORK(&xd->properties_changed_work, 1984d1ff7024SMika Westerberg tb_xdomain_properties_changed); 1985d1ff7024SMika Westerberg 1986d1ff7024SMika Westerberg xd->local_uuid = kmemdup(local_uuid, sizeof(uuid_t), GFP_KERNEL); 1987d1ff7024SMika Westerberg if (!xd->local_uuid) 1988d1ff7024SMika Westerberg goto err_free; 1989d1ff7024SMika Westerberg 19903b4b3235SMika Westerberg if (remote_uuid) { 19913b4b3235SMika Westerberg xd->remote_uuid = kmemdup(remote_uuid, sizeof(uuid_t), 19923b4b3235SMika Westerberg GFP_KERNEL); 1993d1ff7024SMika Westerberg if (!xd->remote_uuid) 1994d1ff7024SMika Westerberg goto err_free_local_uuid; 19953b4b3235SMika Westerberg } else { 19963b4b3235SMika Westerberg xd->needs_uuid = true; 199736b6ad6aSGil Fine 199836b6ad6aSGil Fine tb_xdomain_link_init(xd, down); 19993b4b3235SMika Westerberg } 2000d1ff7024SMika Westerberg 2001d1ff7024SMika Westerberg device_initialize(&xd->dev); 2002d1ff7024SMika Westerberg xd->dev.parent = get_device(parent); 2003d1ff7024SMika Westerberg xd->dev.bus = &tb_bus_type; 2004d1ff7024SMika Westerberg xd->dev.type = &tb_xdomain_type; 2005d1ff7024SMika Westerberg xd->dev.groups = xdomain_attr_groups; 2006d1ff7024SMika Westerberg dev_set_name(&xd->dev, "%u-%llx", tb->index, route); 2007d1ff7024SMika Westerberg 2008d29c59b1SMika Westerberg dev_dbg(&xd->dev, "local UUID %pUb\n", local_uuid); 2009d29c59b1SMika Westerberg if (remote_uuid) 2010d29c59b1SMika Westerberg dev_dbg(&xd->dev, "remote UUID %pUb\n", remote_uuid); 2011d29c59b1SMika Westerberg 20122d8ff0b5SMika Westerberg /* 20132d8ff0b5SMika Westerberg * This keeps the DMA powered on as long as we have active 20142d8ff0b5SMika Westerberg * connection to another host. 20152d8ff0b5SMika Westerberg */ 20162d8ff0b5SMika Westerberg pm_runtime_set_active(&xd->dev); 20172d8ff0b5SMika Westerberg pm_runtime_get_noresume(&xd->dev); 20182d8ff0b5SMika Westerberg pm_runtime_enable(&xd->dev); 20192d8ff0b5SMika Westerberg 2020d1ff7024SMika Westerberg return xd; 2021d1ff7024SMika Westerberg 2022d1ff7024SMika Westerberg err_free_local_uuid: 2023d1ff7024SMika Westerberg kfree(xd->local_uuid); 2024d1ff7024SMika Westerberg err_free: 2025d1ff7024SMika Westerberg kfree(xd); 2026d1ff7024SMika Westerberg 2027d1ff7024SMika Westerberg return NULL; 2028d1ff7024SMika Westerberg } 2029d1ff7024SMika Westerberg 2030d1ff7024SMika Westerberg /** 2031d1ff7024SMika Westerberg * tb_xdomain_add() - Add XDomain to the bus 2032d1ff7024SMika Westerberg * @xd: XDomain to add 2033d1ff7024SMika Westerberg * 2034d1ff7024SMika Westerberg * This function starts XDomain discovery protocol handshake and 2035d1ff7024SMika Westerberg * eventually adds the XDomain to the bus. After calling this function 2036d1ff7024SMika Westerberg * the caller needs to call tb_xdomain_remove() in order to remove and 2037d1ff7024SMika Westerberg * release the object regardless whether the handshake succeeded or not. 2038d1ff7024SMika Westerberg */ 2039d1ff7024SMika Westerberg void tb_xdomain_add(struct tb_xdomain *xd) 2040d1ff7024SMika Westerberg { 2041d1ff7024SMika Westerberg /* Start exchanging properties with the other host */ 2042d1ff7024SMika Westerberg start_handshake(xd); 2043d1ff7024SMika Westerberg } 2044d1ff7024SMika Westerberg 2045d1ff7024SMika Westerberg static int unregister_service(struct device *dev, void *data) 2046d1ff7024SMika Westerberg { 2047d1ff7024SMika Westerberg device_unregister(dev); 2048d1ff7024SMika Westerberg return 0; 2049d1ff7024SMika Westerberg } 2050d1ff7024SMika Westerberg 2051d1ff7024SMika Westerberg /** 2052d1ff7024SMika Westerberg * tb_xdomain_remove() - Remove XDomain from the bus 2053d1ff7024SMika Westerberg * @xd: XDomain to remove 2054d1ff7024SMika Westerberg * 2055d1ff7024SMika Westerberg * This will stop all ongoing configuration work and remove the XDomain 2056d1ff7024SMika Westerberg * along with any services from the bus. When the last reference to @xd 2057d1ff7024SMika Westerberg * is released the object will be released as well. 2058d1ff7024SMika Westerberg */ 2059d1ff7024SMika Westerberg void tb_xdomain_remove(struct tb_xdomain *xd) 2060d1ff7024SMika Westerberg { 2061d0f1e0c2SMika Westerberg tb_xdomain_debugfs_remove(xd); 2062d0f1e0c2SMika Westerberg 2063d1ff7024SMika Westerberg stop_handshake(xd); 2064d1ff7024SMika Westerberg 2065d1ff7024SMika Westerberg device_for_each_child_reverse(&xd->dev, xd, unregister_service); 2066d1ff7024SMika Westerberg 206736b6ad6aSGil Fine tb_xdomain_link_exit(xd); 206836b6ad6aSGil Fine 20692d8ff0b5SMika Westerberg /* 20702d8ff0b5SMika Westerberg * Undo runtime PM here explicitly because it is possible that 20712d8ff0b5SMika Westerberg * the XDomain was never added to the bus and thus device_del() 20722d8ff0b5SMika Westerberg * is not called for it (device_del() would handle this otherwise). 20732d8ff0b5SMika Westerberg */ 20742d8ff0b5SMika Westerberg pm_runtime_disable(&xd->dev); 20752d8ff0b5SMika Westerberg pm_runtime_put_noidle(&xd->dev); 20762d8ff0b5SMika Westerberg pm_runtime_set_suspended(&xd->dev); 20772d8ff0b5SMika Westerberg 2078d29c59b1SMika Westerberg if (!device_is_registered(&xd->dev)) { 2079d1ff7024SMika Westerberg put_device(&xd->dev); 2080d29c59b1SMika Westerberg } else { 2081d29c59b1SMika Westerberg dev_info(&xd->dev, "host disconnected\n"); 2082d1ff7024SMika Westerberg device_unregister(&xd->dev); 2083d1ff7024SMika Westerberg } 2084d29c59b1SMika Westerberg } 2085d1ff7024SMika Westerberg 2086d1ff7024SMika Westerberg /** 20875cc0df9cSIsaac Hazan * tb_xdomain_lane_bonding_enable() - Enable lane bonding on XDomain 20885cc0df9cSIsaac Hazan * @xd: XDomain connection 20895cc0df9cSIsaac Hazan * 20905cc0df9cSIsaac Hazan * Lane bonding is disabled by default for XDomains. This function tries 20915cc0df9cSIsaac Hazan * to enable bonding by first enabling the port and waiting for the CL0 20925cc0df9cSIsaac Hazan * state. 20935cc0df9cSIsaac Hazan * 20945cc0df9cSIsaac Hazan * Return: %0 in case of success and negative errno in case of error. 20955cc0df9cSIsaac Hazan */ 20965cc0df9cSIsaac Hazan int tb_xdomain_lane_bonding_enable(struct tb_xdomain *xd) 20975cc0df9cSIsaac Hazan { 2098e111fb92SGil Fine unsigned int width_mask; 20995cc0df9cSIsaac Hazan struct tb_port *port; 21005cc0df9cSIsaac Hazan int ret; 21015cc0df9cSIsaac Hazan 210217fb1a3dSMika Westerberg port = tb_xdomain_downstream_port(xd); 21035cc0df9cSIsaac Hazan if (!port->dual_link_port) 21045cc0df9cSIsaac Hazan return -ENODEV; 21055cc0df9cSIsaac Hazan 21065cc0df9cSIsaac Hazan ret = tb_port_enable(port->dual_link_port); 21075cc0df9cSIsaac Hazan if (ret) 21085cc0df9cSIsaac Hazan return ret; 21095cc0df9cSIsaac Hazan 21105cc0df9cSIsaac Hazan ret = tb_wait_for_port(port->dual_link_port, true); 21115cc0df9cSIsaac Hazan if (ret < 0) 21125cc0df9cSIsaac Hazan return ret; 21135cc0df9cSIsaac Hazan if (!ret) 21145cc0df9cSIsaac Hazan return -ENOTCONN; 21155cc0df9cSIsaac Hazan 21165cc0df9cSIsaac Hazan ret = tb_port_lane_bonding_enable(port); 21175cc0df9cSIsaac Hazan if (ret) { 21185cc0df9cSIsaac Hazan tb_port_warn(port, "failed to enable lane bonding\n"); 21195cc0df9cSIsaac Hazan return ret; 21205cc0df9cSIsaac Hazan } 21215cc0df9cSIsaac Hazan 2122e111fb92SGil Fine /* Any of the widths are all bonded */ 2123e111fb92SGil Fine width_mask = TB_LINK_WIDTH_DUAL | TB_LINK_WIDTH_ASYM_TX | 2124e111fb92SGil Fine TB_LINK_WIDTH_ASYM_RX; 2125e111fb92SGil Fine 2126e111fb92SGil Fine ret = tb_port_wait_for_link_width(port, width_mask, 2127e111fb92SGil Fine XDOMAIN_BONDING_TIMEOUT); 2128e7051beaSMika Westerberg if (ret) { 21298e1de704SMika Westerberg tb_port_warn(port, "failed to enable lane bonding\n"); 2130e7051beaSMika Westerberg return ret; 2131e7051beaSMika Westerberg } 2132e7051beaSMika Westerberg 213369fea377SMika Westerberg tb_port_update_credits(port); 21345cc0df9cSIsaac Hazan tb_xdomain_update_link_attributes(xd); 21355cc0df9cSIsaac Hazan 21365cc0df9cSIsaac Hazan dev_dbg(&xd->dev, "lane bonding enabled\n"); 21375cc0df9cSIsaac Hazan return 0; 21385cc0df9cSIsaac Hazan } 21395cc0df9cSIsaac Hazan EXPORT_SYMBOL_GPL(tb_xdomain_lane_bonding_enable); 21405cc0df9cSIsaac Hazan 21415cc0df9cSIsaac Hazan /** 21425cc0df9cSIsaac Hazan * tb_xdomain_lane_bonding_disable() - Disable lane bonding 21435cc0df9cSIsaac Hazan * @xd: XDomain connection 21445cc0df9cSIsaac Hazan * 21455cc0df9cSIsaac Hazan * Lane bonding is disabled by default for XDomains. If bonding has been 21465cc0df9cSIsaac Hazan * enabled, this function can be used to disable it. 21475cc0df9cSIsaac Hazan */ 21485cc0df9cSIsaac Hazan void tb_xdomain_lane_bonding_disable(struct tb_xdomain *xd) 21495cc0df9cSIsaac Hazan { 21505cc0df9cSIsaac Hazan struct tb_port *port; 21515cc0df9cSIsaac Hazan 215217fb1a3dSMika Westerberg port = tb_xdomain_downstream_port(xd); 21535cc0df9cSIsaac Hazan if (port->dual_link_port) { 2154e111fb92SGil Fine int ret; 2155e111fb92SGil Fine 21565cc0df9cSIsaac Hazan tb_port_lane_bonding_disable(port); 2157e111fb92SGil Fine ret = tb_port_wait_for_link_width(port, TB_LINK_WIDTH_SINGLE, 100); 2158e111fb92SGil Fine if (ret == -ETIMEDOUT) 2159e7051beaSMika Westerberg tb_port_warn(port, "timeout disabling lane bonding\n"); 21605cc0df9cSIsaac Hazan tb_port_disable(port->dual_link_port); 216169fea377SMika Westerberg tb_port_update_credits(port); 21625cc0df9cSIsaac Hazan tb_xdomain_update_link_attributes(xd); 21635cc0df9cSIsaac Hazan 21645cc0df9cSIsaac Hazan dev_dbg(&xd->dev, "lane bonding disabled\n"); 21655cc0df9cSIsaac Hazan } 21665cc0df9cSIsaac Hazan } 21675cc0df9cSIsaac Hazan EXPORT_SYMBOL_GPL(tb_xdomain_lane_bonding_disable); 21685cc0df9cSIsaac Hazan 21695cc0df9cSIsaac Hazan /** 2170180b0689SMika Westerberg * tb_xdomain_alloc_in_hopid() - Allocate input HopID for tunneling 2171180b0689SMika Westerberg * @xd: XDomain connection 2172180b0689SMika Westerberg * @hopid: Preferred HopID or %-1 for next available 2173180b0689SMika Westerberg * 2174180b0689SMika Westerberg * Returns allocated HopID or negative errno. Specifically returns 2175180b0689SMika Westerberg * %-ENOSPC if there are no more available HopIDs. Returned HopID is 2176180b0689SMika Westerberg * guaranteed to be within range supported by the input lane adapter. 2177180b0689SMika Westerberg * Call tb_xdomain_release_in_hopid() to release the allocated HopID. 2178180b0689SMika Westerberg */ 2179180b0689SMika Westerberg int tb_xdomain_alloc_in_hopid(struct tb_xdomain *xd, int hopid) 2180180b0689SMika Westerberg { 2181180b0689SMika Westerberg if (hopid < 0) 2182180b0689SMika Westerberg hopid = TB_PATH_MIN_HOPID; 2183180b0689SMika Westerberg if (hopid < TB_PATH_MIN_HOPID || hopid > xd->local_max_hopid) 2184180b0689SMika Westerberg return -EINVAL; 2185180b0689SMika Westerberg 2186180b0689SMika Westerberg return ida_alloc_range(&xd->in_hopids, hopid, xd->local_max_hopid, 2187180b0689SMika Westerberg GFP_KERNEL); 2188180b0689SMika Westerberg } 2189180b0689SMika Westerberg EXPORT_SYMBOL_GPL(tb_xdomain_alloc_in_hopid); 2190180b0689SMika Westerberg 2191180b0689SMika Westerberg /** 2192180b0689SMika Westerberg * tb_xdomain_alloc_out_hopid() - Allocate output HopID for tunneling 2193180b0689SMika Westerberg * @xd: XDomain connection 2194180b0689SMika Westerberg * @hopid: Preferred HopID or %-1 for next available 2195180b0689SMika Westerberg * 2196180b0689SMika Westerberg * Returns allocated HopID or negative errno. Specifically returns 2197180b0689SMika Westerberg * %-ENOSPC if there are no more available HopIDs. Returned HopID is 2198180b0689SMika Westerberg * guaranteed to be within range supported by the output lane adapter. 2199180b0689SMika Westerberg * Call tb_xdomain_release_in_hopid() to release the allocated HopID. 2200180b0689SMika Westerberg */ 2201180b0689SMika Westerberg int tb_xdomain_alloc_out_hopid(struct tb_xdomain *xd, int hopid) 2202180b0689SMika Westerberg { 2203180b0689SMika Westerberg if (hopid < 0) 2204180b0689SMika Westerberg hopid = TB_PATH_MIN_HOPID; 2205180b0689SMika Westerberg if (hopid < TB_PATH_MIN_HOPID || hopid > xd->remote_max_hopid) 2206180b0689SMika Westerberg return -EINVAL; 2207180b0689SMika Westerberg 2208180b0689SMika Westerberg return ida_alloc_range(&xd->out_hopids, hopid, xd->remote_max_hopid, 2209180b0689SMika Westerberg GFP_KERNEL); 2210180b0689SMika Westerberg } 2211180b0689SMika Westerberg EXPORT_SYMBOL_GPL(tb_xdomain_alloc_out_hopid); 2212180b0689SMika Westerberg 2213180b0689SMika Westerberg /** 2214180b0689SMika Westerberg * tb_xdomain_release_in_hopid() - Release input HopID 2215180b0689SMika Westerberg * @xd: XDomain connection 2216180b0689SMika Westerberg * @hopid: HopID to release 2217180b0689SMika Westerberg */ 2218180b0689SMika Westerberg void tb_xdomain_release_in_hopid(struct tb_xdomain *xd, int hopid) 2219180b0689SMika Westerberg { 2220180b0689SMika Westerberg ida_free(&xd->in_hopids, hopid); 2221180b0689SMika Westerberg } 2222180b0689SMika Westerberg EXPORT_SYMBOL_GPL(tb_xdomain_release_in_hopid); 2223180b0689SMika Westerberg 2224180b0689SMika Westerberg /** 2225180b0689SMika Westerberg * tb_xdomain_release_out_hopid() - Release output HopID 2226180b0689SMika Westerberg * @xd: XDomain connection 2227180b0689SMika Westerberg * @hopid: HopID to release 2228180b0689SMika Westerberg */ 2229180b0689SMika Westerberg void tb_xdomain_release_out_hopid(struct tb_xdomain *xd, int hopid) 2230180b0689SMika Westerberg { 2231180b0689SMika Westerberg ida_free(&xd->out_hopids, hopid); 2232180b0689SMika Westerberg } 2233180b0689SMika Westerberg EXPORT_SYMBOL_GPL(tb_xdomain_release_out_hopid); 2234180b0689SMika Westerberg 2235180b0689SMika Westerberg /** 2236d1ff7024SMika Westerberg * tb_xdomain_enable_paths() - Enable DMA paths for XDomain connection 2237d1ff7024SMika Westerberg * @xd: XDomain connection 2238180b0689SMika Westerberg * @transmit_path: HopID we are using to send out packets 2239180b0689SMika Westerberg * @transmit_ring: DMA ring used to send out packets 2240180b0689SMika Westerberg * @receive_path: HopID the other end is using to send packets to us 2241180b0689SMika Westerberg * @receive_ring: DMA ring used to receive packets from @receive_path 2242d1ff7024SMika Westerberg * 2243d1ff7024SMika Westerberg * The function enables DMA paths accordingly so that after successful 2244d1ff7024SMika Westerberg * return the caller can send and receive packets using high-speed DMA 2245180b0689SMika Westerberg * path. If a transmit or receive path is not needed, pass %-1 for those 2246180b0689SMika Westerberg * parameters. 2247d1ff7024SMika Westerberg * 2248d1ff7024SMika Westerberg * Return: %0 in case of success and negative errno in case of error 2249d1ff7024SMika Westerberg */ 2250180b0689SMika Westerberg int tb_xdomain_enable_paths(struct tb_xdomain *xd, int transmit_path, 2251180b0689SMika Westerberg int transmit_ring, int receive_path, 2252180b0689SMika Westerberg int receive_ring) 2253d1ff7024SMika Westerberg { 2254180b0689SMika Westerberg return tb_domain_approve_xdomain_paths(xd->tb, xd, transmit_path, 2255180b0689SMika Westerberg transmit_ring, receive_path, 2256180b0689SMika Westerberg receive_ring); 2257d1ff7024SMika Westerberg } 2258d1ff7024SMika Westerberg EXPORT_SYMBOL_GPL(tb_xdomain_enable_paths); 2259d1ff7024SMika Westerberg 2260d1ff7024SMika Westerberg /** 2261d1ff7024SMika Westerberg * tb_xdomain_disable_paths() - Disable DMA paths for XDomain connection 2262d1ff7024SMika Westerberg * @xd: XDomain connection 2263180b0689SMika Westerberg * @transmit_path: HopID we are using to send out packets 2264180b0689SMika Westerberg * @transmit_ring: DMA ring used to send out packets 2265180b0689SMika Westerberg * @receive_path: HopID the other end is using to send packets to us 2266180b0689SMika Westerberg * @receive_ring: DMA ring used to receive packets from @receive_path 2267d1ff7024SMika Westerberg * 2268d1ff7024SMika Westerberg * This does the opposite of tb_xdomain_enable_paths(). After call to 2269180b0689SMika Westerberg * this the caller is not expected to use the rings anymore. Passing %-1 2270180b0689SMika Westerberg * as path/ring parameter means don't care. Normally the callers should 2271180b0689SMika Westerberg * pass the same values here as they do when paths are enabled. 2272d1ff7024SMika Westerberg * 2273d1ff7024SMika Westerberg * Return: %0 in case of success and negative errno in case of error 2274d1ff7024SMika Westerberg */ 2275180b0689SMika Westerberg int tb_xdomain_disable_paths(struct tb_xdomain *xd, int transmit_path, 2276180b0689SMika Westerberg int transmit_ring, int receive_path, 2277180b0689SMika Westerberg int receive_ring) 2278d1ff7024SMika Westerberg { 2279180b0689SMika Westerberg return tb_domain_disconnect_xdomain_paths(xd->tb, xd, transmit_path, 2280180b0689SMika Westerberg transmit_ring, receive_path, 2281180b0689SMika Westerberg receive_ring); 2282d1ff7024SMika Westerberg } 2283d1ff7024SMika Westerberg EXPORT_SYMBOL_GPL(tb_xdomain_disable_paths); 2284d1ff7024SMika Westerberg 2285d1ff7024SMika Westerberg struct tb_xdomain_lookup { 2286d1ff7024SMika Westerberg const uuid_t *uuid; 2287d1ff7024SMika Westerberg u8 link; 2288d1ff7024SMika Westerberg u8 depth; 2289484cb153SRadion Mirchevsky u64 route; 2290d1ff7024SMika Westerberg }; 2291d1ff7024SMika Westerberg 2292d1ff7024SMika Westerberg static struct tb_xdomain *switch_find_xdomain(struct tb_switch *sw, 2293d1ff7024SMika Westerberg const struct tb_xdomain_lookup *lookup) 2294d1ff7024SMika Westerberg { 2295b433d010SMika Westerberg struct tb_port *port; 2296d1ff7024SMika Westerberg 2297b433d010SMika Westerberg tb_switch_for_each_port(sw, port) { 2298d1ff7024SMika Westerberg struct tb_xdomain *xd; 2299d1ff7024SMika Westerberg 2300d1ff7024SMika Westerberg if (port->xdomain) { 2301d1ff7024SMika Westerberg xd = port->xdomain; 2302d1ff7024SMika Westerberg 2303d1ff7024SMika Westerberg if (lookup->uuid) { 23043b4b3235SMika Westerberg if (xd->remote_uuid && 23053b4b3235SMika Westerberg uuid_equal(xd->remote_uuid, lookup->uuid)) 2306d1ff7024SMika Westerberg return xd; 23074e99c98eSAndy Shevchenko } else { 23084e99c98eSAndy Shevchenko if (lookup->link && lookup->link == xd->link && 23094e99c98eSAndy Shevchenko lookup->depth == xd->depth) 2310d1ff7024SMika Westerberg return xd; 23114e99c98eSAndy Shevchenko if (lookup->route && lookup->route == xd->route) 2312484cb153SRadion Mirchevsky return xd; 2313d1ff7024SMika Westerberg } 2314dfe40ca4SMika Westerberg } else if (tb_port_has_remote(port)) { 2315d1ff7024SMika Westerberg xd = switch_find_xdomain(port->remote->sw, lookup); 2316d1ff7024SMika Westerberg if (xd) 2317d1ff7024SMika Westerberg return xd; 2318d1ff7024SMika Westerberg } 2319d1ff7024SMika Westerberg } 2320d1ff7024SMika Westerberg 2321d1ff7024SMika Westerberg return NULL; 2322d1ff7024SMika Westerberg } 2323d1ff7024SMika Westerberg 2324d1ff7024SMika Westerberg /** 2325d1ff7024SMika Westerberg * tb_xdomain_find_by_uuid() - Find an XDomain by UUID 2326d1ff7024SMika Westerberg * @tb: Domain where the XDomain belongs to 2327d1ff7024SMika Westerberg * @uuid: UUID to look for 2328d1ff7024SMika Westerberg * 2329d1ff7024SMika Westerberg * Finds XDomain by walking through the Thunderbolt topology below @tb. 2330d1ff7024SMika Westerberg * The returned XDomain will have its reference count increased so the 2331d1ff7024SMika Westerberg * caller needs to call tb_xdomain_put() when it is done with the 2332d1ff7024SMika Westerberg * object. 2333d1ff7024SMika Westerberg * 2334d1ff7024SMika Westerberg * This will find all XDomains including the ones that are not yet added 2335d1ff7024SMika Westerberg * to the bus (handshake is still in progress). 2336d1ff7024SMika Westerberg * 2337d1ff7024SMika Westerberg * The caller needs to hold @tb->lock. 2338d1ff7024SMika Westerberg */ 2339d1ff7024SMika Westerberg struct tb_xdomain *tb_xdomain_find_by_uuid(struct tb *tb, const uuid_t *uuid) 2340d1ff7024SMika Westerberg { 2341d1ff7024SMika Westerberg struct tb_xdomain_lookup lookup; 2342d1ff7024SMika Westerberg struct tb_xdomain *xd; 2343d1ff7024SMika Westerberg 2344d1ff7024SMika Westerberg memset(&lookup, 0, sizeof(lookup)); 2345d1ff7024SMika Westerberg lookup.uuid = uuid; 2346d1ff7024SMika Westerberg 2347d1ff7024SMika Westerberg xd = switch_find_xdomain(tb->root_switch, &lookup); 2348484cb153SRadion Mirchevsky return tb_xdomain_get(xd); 2349d1ff7024SMika Westerberg } 2350d1ff7024SMika Westerberg EXPORT_SYMBOL_GPL(tb_xdomain_find_by_uuid); 2351d1ff7024SMika Westerberg 2352d1ff7024SMika Westerberg /** 2353d1ff7024SMika Westerberg * tb_xdomain_find_by_link_depth() - Find an XDomain by link and depth 2354d1ff7024SMika Westerberg * @tb: Domain where the XDomain belongs to 2355d1ff7024SMika Westerberg * @link: Root switch link number 2356d1ff7024SMika Westerberg * @depth: Depth in the link 2357d1ff7024SMika Westerberg * 2358d1ff7024SMika Westerberg * Finds XDomain by walking through the Thunderbolt topology below @tb. 2359d1ff7024SMika Westerberg * The returned XDomain will have its reference count increased so the 2360d1ff7024SMika Westerberg * caller needs to call tb_xdomain_put() when it is done with the 2361d1ff7024SMika Westerberg * object. 2362d1ff7024SMika Westerberg * 2363d1ff7024SMika Westerberg * This will find all XDomains including the ones that are not yet added 2364d1ff7024SMika Westerberg * to the bus (handshake is still in progress). 2365d1ff7024SMika Westerberg * 2366d1ff7024SMika Westerberg * The caller needs to hold @tb->lock. 2367d1ff7024SMika Westerberg */ 2368d1ff7024SMika Westerberg struct tb_xdomain *tb_xdomain_find_by_link_depth(struct tb *tb, u8 link, 2369d1ff7024SMika Westerberg u8 depth) 2370d1ff7024SMika Westerberg { 2371d1ff7024SMika Westerberg struct tb_xdomain_lookup lookup; 2372d1ff7024SMika Westerberg struct tb_xdomain *xd; 2373d1ff7024SMika Westerberg 2374d1ff7024SMika Westerberg memset(&lookup, 0, sizeof(lookup)); 2375d1ff7024SMika Westerberg lookup.link = link; 2376d1ff7024SMika Westerberg lookup.depth = depth; 2377d1ff7024SMika Westerberg 2378d1ff7024SMika Westerberg xd = switch_find_xdomain(tb->root_switch, &lookup); 2379484cb153SRadion Mirchevsky return tb_xdomain_get(xd); 2380d1ff7024SMika Westerberg } 2381d1ff7024SMika Westerberg 2382484cb153SRadion Mirchevsky /** 2383484cb153SRadion Mirchevsky * tb_xdomain_find_by_route() - Find an XDomain by route string 2384484cb153SRadion Mirchevsky * @tb: Domain where the XDomain belongs to 2385484cb153SRadion Mirchevsky * @route: XDomain route string 2386484cb153SRadion Mirchevsky * 2387484cb153SRadion Mirchevsky * Finds XDomain by walking through the Thunderbolt topology below @tb. 2388484cb153SRadion Mirchevsky * The returned XDomain will have its reference count increased so the 2389484cb153SRadion Mirchevsky * caller needs to call tb_xdomain_put() when it is done with the 2390484cb153SRadion Mirchevsky * object. 2391484cb153SRadion Mirchevsky * 2392484cb153SRadion Mirchevsky * This will find all XDomains including the ones that are not yet added 2393484cb153SRadion Mirchevsky * to the bus (handshake is still in progress). 2394484cb153SRadion Mirchevsky * 2395484cb153SRadion Mirchevsky * The caller needs to hold @tb->lock. 2396484cb153SRadion Mirchevsky */ 2397484cb153SRadion Mirchevsky struct tb_xdomain *tb_xdomain_find_by_route(struct tb *tb, u64 route) 2398484cb153SRadion Mirchevsky { 2399484cb153SRadion Mirchevsky struct tb_xdomain_lookup lookup; 2400484cb153SRadion Mirchevsky struct tb_xdomain *xd; 2401484cb153SRadion Mirchevsky 2402484cb153SRadion Mirchevsky memset(&lookup, 0, sizeof(lookup)); 2403484cb153SRadion Mirchevsky lookup.route = route; 2404484cb153SRadion Mirchevsky 2405484cb153SRadion Mirchevsky xd = switch_find_xdomain(tb->root_switch, &lookup); 2406484cb153SRadion Mirchevsky return tb_xdomain_get(xd); 2407d1ff7024SMika Westerberg } 2408484cb153SRadion Mirchevsky EXPORT_SYMBOL_GPL(tb_xdomain_find_by_route); 2409d1ff7024SMika Westerberg 2410d1ff7024SMika Westerberg bool tb_xdomain_handle_request(struct tb *tb, enum tb_cfg_pkg_type type, 2411d1ff7024SMika Westerberg const void *buf, size_t size) 2412d1ff7024SMika Westerberg { 2413d1ff7024SMika Westerberg const struct tb_protocol_handler *handler, *tmp; 2414d1ff7024SMika Westerberg const struct tb_xdp_header *hdr = buf; 2415d1ff7024SMika Westerberg unsigned int length; 2416d1ff7024SMika Westerberg int ret = 0; 2417d1ff7024SMika Westerberg 2418d1ff7024SMika Westerberg /* We expect the packet is at least size of the header */ 2419d1ff7024SMika Westerberg length = hdr->xd_hdr.length_sn & TB_XDOMAIN_LENGTH_MASK; 2420d1ff7024SMika Westerberg if (length != size / 4 - sizeof(hdr->xd_hdr) / 4) 2421d1ff7024SMika Westerberg return true; 2422d1ff7024SMika Westerberg if (length < sizeof(*hdr) / 4 - sizeof(hdr->xd_hdr) / 4) 2423d1ff7024SMika Westerberg return true; 2424d1ff7024SMika Westerberg 2425d1ff7024SMika Westerberg /* 2426d1ff7024SMika Westerberg * Handle XDomain discovery protocol packets directly here. For 2427d1ff7024SMika Westerberg * other protocols (based on their UUID) we call registered 2428d1ff7024SMika Westerberg * handlers in turn. 2429d1ff7024SMika Westerberg */ 2430d1ff7024SMika Westerberg if (uuid_equal(&hdr->uuid, &tb_xdp_uuid)) { 243148f40b96SAditya Pakki if (type == TB_CFG_PKG_XDOMAIN_REQ) 243248f40b96SAditya Pakki return tb_xdp_schedule_request(tb, hdr, size); 2433d1ff7024SMika Westerberg return false; 2434d1ff7024SMika Westerberg } 2435d1ff7024SMika Westerberg 2436d1ff7024SMika Westerberg mutex_lock(&xdomain_lock); 2437d1ff7024SMika Westerberg list_for_each_entry_safe(handler, tmp, &protocol_handlers, list) { 2438d1ff7024SMika Westerberg if (!uuid_equal(&hdr->uuid, handler->uuid)) 2439d1ff7024SMika Westerberg continue; 2440d1ff7024SMika Westerberg 2441d1ff7024SMika Westerberg mutex_unlock(&xdomain_lock); 2442d1ff7024SMika Westerberg ret = handler->callback(buf, size, handler->data); 2443d1ff7024SMika Westerberg mutex_lock(&xdomain_lock); 2444d1ff7024SMika Westerberg 2445d1ff7024SMika Westerberg if (ret) 2446d1ff7024SMika Westerberg break; 2447d1ff7024SMika Westerberg } 2448d1ff7024SMika Westerberg mutex_unlock(&xdomain_lock); 2449d1ff7024SMika Westerberg 2450d1ff7024SMika Westerberg return ret > 0; 2451d1ff7024SMika Westerberg } 2452d1ff7024SMika Westerberg 2453d1ff7024SMika Westerberg static int update_xdomain(struct device *dev, void *data) 2454d1ff7024SMika Westerberg { 2455d1ff7024SMika Westerberg struct tb_xdomain *xd; 2456d1ff7024SMika Westerberg 2457d1ff7024SMika Westerberg xd = tb_to_xdomain(dev); 2458d1ff7024SMika Westerberg if (xd) { 2459d1ff7024SMika Westerberg queue_delayed_work(xd->tb->wq, &xd->properties_changed_work, 2460d1ff7024SMika Westerberg msecs_to_jiffies(50)); 2461d1ff7024SMika Westerberg } 2462d1ff7024SMika Westerberg 2463d1ff7024SMika Westerberg return 0; 2464d1ff7024SMika Westerberg } 2465d1ff7024SMika Westerberg 2466d1ff7024SMika Westerberg static void update_all_xdomains(void) 2467d1ff7024SMika Westerberg { 2468d1ff7024SMika Westerberg bus_for_each_dev(&tb_bus_type, NULL, NULL, update_xdomain); 2469d1ff7024SMika Westerberg } 2470d1ff7024SMika Westerberg 2471d1ff7024SMika Westerberg static bool remove_directory(const char *key, const struct tb_property_dir *dir) 2472d1ff7024SMika Westerberg { 2473d1ff7024SMika Westerberg struct tb_property *p; 2474d1ff7024SMika Westerberg 2475d1ff7024SMika Westerberg p = tb_property_find(xdomain_property_dir, key, 2476d1ff7024SMika Westerberg TB_PROPERTY_TYPE_DIRECTORY); 2477d1ff7024SMika Westerberg if (p && p->value.dir == dir) { 2478d1ff7024SMika Westerberg tb_property_remove(p); 2479d1ff7024SMika Westerberg return true; 2480d1ff7024SMika Westerberg } 2481d1ff7024SMika Westerberg return false; 2482d1ff7024SMika Westerberg } 2483d1ff7024SMika Westerberg 2484d1ff7024SMika Westerberg /** 2485d1ff7024SMika Westerberg * tb_register_property_dir() - Register property directory to the host 2486d1ff7024SMika Westerberg * @key: Key (name) of the directory to add 2487d1ff7024SMika Westerberg * @dir: Directory to add 2488d1ff7024SMika Westerberg * 2489d1ff7024SMika Westerberg * Service drivers can use this function to add new property directory 2490d1ff7024SMika Westerberg * to the host available properties. The other connected hosts are 2491d1ff7024SMika Westerberg * notified so they can re-read properties of this host if they are 2492d1ff7024SMika Westerberg * interested. 2493d1ff7024SMika Westerberg * 2494d1ff7024SMika Westerberg * Return: %0 on success and negative errno on failure 2495d1ff7024SMika Westerberg */ 2496d1ff7024SMika Westerberg int tb_register_property_dir(const char *key, struct tb_property_dir *dir) 2497d1ff7024SMika Westerberg { 2498d1ff7024SMika Westerberg int ret; 2499d1ff7024SMika Westerberg 2500acb40d84SMika Westerberg if (WARN_ON(!xdomain_property_dir)) 2501acb40d84SMika Westerberg return -EAGAIN; 2502acb40d84SMika Westerberg 2503d1ff7024SMika Westerberg if (!key || strlen(key) > 8) 2504d1ff7024SMika Westerberg return -EINVAL; 2505d1ff7024SMika Westerberg 2506d1ff7024SMika Westerberg mutex_lock(&xdomain_lock); 2507d1ff7024SMika Westerberg if (tb_property_find(xdomain_property_dir, key, 2508d1ff7024SMika Westerberg TB_PROPERTY_TYPE_DIRECTORY)) { 2509d1ff7024SMika Westerberg ret = -EEXIST; 2510d1ff7024SMika Westerberg goto err_unlock; 2511d1ff7024SMika Westerberg } 2512d1ff7024SMika Westerberg 2513d1ff7024SMika Westerberg ret = tb_property_add_dir(xdomain_property_dir, key, dir); 2514d1ff7024SMika Westerberg if (ret) 2515d1ff7024SMika Westerberg goto err_unlock; 2516d1ff7024SMika Westerberg 251746b494f2SMika Westerberg xdomain_property_block_gen++; 2518d1ff7024SMika Westerberg 2519d1ff7024SMika Westerberg mutex_unlock(&xdomain_lock); 2520d1ff7024SMika Westerberg update_all_xdomains(); 2521d1ff7024SMika Westerberg return 0; 2522d1ff7024SMika Westerberg 2523d1ff7024SMika Westerberg err_unlock: 2524d1ff7024SMika Westerberg mutex_unlock(&xdomain_lock); 2525d1ff7024SMika Westerberg return ret; 2526d1ff7024SMika Westerberg } 2527d1ff7024SMika Westerberg EXPORT_SYMBOL_GPL(tb_register_property_dir); 2528d1ff7024SMika Westerberg 2529d1ff7024SMika Westerberg /** 2530d1ff7024SMika Westerberg * tb_unregister_property_dir() - Removes property directory from host 2531d1ff7024SMika Westerberg * @key: Key (name) of the directory 2532d1ff7024SMika Westerberg * @dir: Directory to remove 2533d1ff7024SMika Westerberg * 2534d1ff7024SMika Westerberg * This will remove the existing directory from this host and notify the 2535d1ff7024SMika Westerberg * connected hosts about the change. 2536d1ff7024SMika Westerberg */ 2537d1ff7024SMika Westerberg void tb_unregister_property_dir(const char *key, struct tb_property_dir *dir) 2538d1ff7024SMika Westerberg { 2539d1ff7024SMika Westerberg int ret = 0; 2540d1ff7024SMika Westerberg 2541d1ff7024SMika Westerberg mutex_lock(&xdomain_lock); 2542d1ff7024SMika Westerberg if (remove_directory(key, dir)) 254346b494f2SMika Westerberg xdomain_property_block_gen++; 2544d1ff7024SMika Westerberg mutex_unlock(&xdomain_lock); 2545d1ff7024SMika Westerberg 2546d1ff7024SMika Westerberg if (!ret) 2547d1ff7024SMika Westerberg update_all_xdomains(); 2548d1ff7024SMika Westerberg } 2549d1ff7024SMika Westerberg EXPORT_SYMBOL_GPL(tb_unregister_property_dir); 2550d1ff7024SMika Westerberg 2551d1ff7024SMika Westerberg int tb_xdomain_init(void) 2552d1ff7024SMika Westerberg { 2553d1ff7024SMika Westerberg xdomain_property_dir = tb_property_create_dir(NULL); 2554d1ff7024SMika Westerberg if (!xdomain_property_dir) 2555d1ff7024SMika Westerberg return -ENOMEM; 2556d1ff7024SMika Westerberg 2557d1ff7024SMika Westerberg /* 2558d1ff7024SMika Westerberg * Initialize standard set of properties without any service 2559d1ff7024SMika Westerberg * directories. Those will be added by service drivers 2560d1ff7024SMika Westerberg * themselves when they are loaded. 25618a00c67eSMika Westerberg * 256246b494f2SMika Westerberg * Rest of the properties are filled dynamically based on these 256346b494f2SMika Westerberg * when the P2P connection is made. 2564d1ff7024SMika Westerberg */ 2565d1ff7024SMika Westerberg tb_property_add_immediate(xdomain_property_dir, "vendorid", 2566d1ff7024SMika Westerberg PCI_VENDOR_ID_INTEL); 2567d1ff7024SMika Westerberg tb_property_add_text(xdomain_property_dir, "vendorid", "Intel Corp."); 2568d1ff7024SMika Westerberg tb_property_add_immediate(xdomain_property_dir, "deviceid", 0x1); 2569d1ff7024SMika Westerberg tb_property_add_immediate(xdomain_property_dir, "devicerv", 0x80000100); 2570d1ff7024SMika Westerberg 2571a251c17aSJason A. Donenfeld xdomain_property_block_gen = get_random_u32(); 25728a00c67eSMika Westerberg return 0; 2573d1ff7024SMika Westerberg } 2574d1ff7024SMika Westerberg 2575d1ff7024SMika Westerberg void tb_xdomain_exit(void) 2576d1ff7024SMika Westerberg { 2577d1ff7024SMika Westerberg tb_property_free_dir(xdomain_property_dir); 2578d1ff7024SMika Westerberg } 2579