From 102a0743326a03cd1a1202ceda21e175b7d3575c Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Tue, 20 Feb 2024 01:20:52 +0000 Subject: [PATCH] add new system file --- kernel/drivers/thunderbolt/ctl.c | 89 ++++++++++++++++++++++++++++++-------------- 1 files changed, 61 insertions(+), 28 deletions(-) diff --git a/kernel/drivers/thunderbolt/ctl.c b/kernel/drivers/thunderbolt/ctl.c index 37a7f4c..772acb1 100644 --- a/kernel/drivers/thunderbolt/ctl.c +++ b/kernel/drivers/thunderbolt/ctl.c @@ -1,8 +1,9 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Thunderbolt Cactus Ridge driver - control channel and configuration commands + * Thunderbolt driver - control channel and configuration commands * * Copyright (c) 2014 Andreas Noever <andreas.noever@gmail.com> + * Copyright (C) 2018, Intel Corporation */ #include <linux/crc32.h> @@ -218,6 +219,7 @@ static struct tb_cfg_result decode_error(const struct ctl_pkg *response) { struct cfg_error_pkg *pkg = response->buffer; + struct tb_ctl *ctl = response->ctl; struct tb_cfg_result res = { 0 }; res.response_route = tb_cfg_get_route(&pkg->header); res.response_port = 0; @@ -226,9 +228,13 @@ if (res.err) return res; - WARN(pkg->zero1, "pkg->zero1 is %#x\n", pkg->zero1); - WARN(pkg->zero2, "pkg->zero1 is %#x\n", pkg->zero1); - WARN(pkg->zero3, "pkg->zero1 is %#x\n", pkg->zero1); + if (pkg->zero1) + tb_ctl_warn(ctl, "pkg->zero1 is %#x\n", pkg->zero1); + if (pkg->zero2) + tb_ctl_warn(ctl, "pkg->zero2 is %#x\n", pkg->zero2); + if (pkg->zero3) + tb_ctl_warn(ctl, "pkg->zero3 is %#x\n", pkg->zero3); + res.err = 1; res.tb_error = pkg->error; res.response_port = pkg->port; @@ -265,9 +271,8 @@ * Invalid cfg_space/offset/length combination in * cfg_read/cfg_write. */ - tb_ctl_WARN(ctl, - "CFG_ERROR(%llx:%x): Invalid config space or offset\n", - res->response_route, res->response_port); + tb_ctl_dbg(ctl, "%llx:%x: invalid config space or offset\n", + res->response_route, res->response_port); return; case TB_CFG_ERROR_NO_SUCH_PORT: /* @@ -281,6 +286,10 @@ case TB_CFG_ERROR_LOOP: tb_ctl_WARN(ctl, "CFG_ERROR(%llx:%x): Route contains a loop\n", res->response_route, res->response_port); + return; + case TB_CFG_ERROR_LOCK: + tb_ctl_warn(ctl, "%llx:%x: downstream port is locked\n", + res->response_route, res->response_port); return; default: /* 5,6,7,9 and 11 are also valid error codes */ @@ -387,7 +396,7 @@ static int tb_async_error(const struct ctl_pkg *pkg) { - const struct cfg_error_pkg *error = (const struct cfg_error_pkg *)pkg; + const struct cfg_error_pkg *error = pkg->buffer; if (pkg->frame.eof != TB_CFG_PKG_ERROR) return false; @@ -452,7 +461,7 @@ "RX: checksum mismatch, dropping packet\n"); goto rx; } - /* Fall through */ + fallthrough; case TB_CFG_PKG_ICM_EVENT: if (tb_ctl_handle_event(pkg->ctl, frame->eof, pkg, frame->size)) goto rx; @@ -631,7 +640,7 @@ ctl->rx_packets[i]->frame.callback = tb_ctl_rx_callback; } - tb_ctl_info(ctl, "control channel created\n"); + tb_ctl_dbg(ctl, "control channel created\n"); return ctl; err: tb_ctl_free(ctl); @@ -662,8 +671,7 @@ tb_ctl_pkg_free(ctl->rx_packets[i]); - if (ctl->frame_pool) - dma_pool_destroy(ctl->frame_pool); + dma_pool_destroy(ctl->frame_pool); kfree(ctl); } @@ -673,7 +681,7 @@ void tb_ctl_start(struct tb_ctl *ctl) { int i; - tb_ctl_info(ctl, "control channel starting...\n"); + tb_ctl_dbg(ctl, "control channel starting...\n"); tb_ring_start(ctl->tx); /* is used to ack hotplug packets, start first */ tb_ring_start(ctl->rx); for (i = 0; i < TB_CTL_RX_PKG_COUNT; i++) @@ -702,25 +710,32 @@ if (!list_empty(&ctl->request_queue)) tb_ctl_WARN(ctl, "dangling request in request_queue\n"); INIT_LIST_HEAD(&ctl->request_queue); - tb_ctl_info(ctl, "control channel stopped\n"); + tb_ctl_dbg(ctl, "control channel stopped\n"); } /* public interface, commands */ /** - * tb_cfg_error() - send error packet + * tb_cfg_ack_plug() - Ack hot plug/unplug event + * @ctl: Control channel to use + * @route: Router that originated the event + * @port: Port where the hot plug/unplug happened + * @unplug: Ack hot plug or unplug * - * Return: Returns 0 on success or an error code on failure. + * Call this as response for hot plug/unplug event to ack it. + * Returns %0 on success or an error code on failure. */ -int tb_cfg_error(struct tb_ctl *ctl, u64 route, u32 port, - enum tb_cfg_error error) +int tb_cfg_ack_plug(struct tb_ctl *ctl, u64 route, u32 port, bool unplug) { struct cfg_error_pkg pkg = { .header = tb_cfg_make_header(route), .port = port, - .error = error, + .error = TB_CFG_ERROR_ACK_PLUG_EVENT, + .pg = unplug ? TB_CFG_ERROR_PG_HOT_UNPLUG + : TB_CFG_ERROR_PG_HOT_PLUG, }; - tb_ctl_info(ctl, "resetting error on %llx:%x.\n", route, port); + tb_ctl_dbg(ctl, "acking hot %splug event on %llx:%x\n", + unplug ? "un" : "", route, port); return tb_ctl_tx(ctl, &pkg, sizeof(pkg), TB_CFG_PKG_ERROR); } @@ -930,6 +945,26 @@ return res; } +static int tb_cfg_get_error(struct tb_ctl *ctl, enum tb_cfg_space space, + const struct tb_cfg_result *res) +{ + /* + * For unimplemented ports access to port config space may return + * TB_CFG_ERROR_INVALID_CONFIG_SPACE (alternatively their type is + * set to TB_TYPE_INACTIVE). In the former case return -ENODEV so + * that the caller can mark the port as disabled. + */ + if (space == TB_CFG_PORT && + res->tb_error == TB_CFG_ERROR_INVALID_CONFIG_SPACE) + return -ENODEV; + + tb_cfg_print_error(ctl, res); + + if (res->tb_error == TB_CFG_ERROR_LOCK) + return -EACCES; + return -EIO; +} + int tb_cfg_read(struct tb_ctl *ctl, void *buffer, u64 route, u32 port, enum tb_cfg_space space, u32 offset, u32 length) { @@ -942,12 +977,11 @@ case 1: /* Thunderbolt error, tb_error holds the actual number */ - tb_cfg_print_error(ctl, &res); - return -EIO; + return tb_cfg_get_error(ctl, space, &res); case -ETIMEDOUT: - tb_ctl_warn(ctl, "timeout reading config space %u from %#x\n", - space, offset); + tb_ctl_warn(ctl, "%llx: timeout reading config space %u from %#x\n", + route, space, offset); break; default: @@ -969,12 +1003,11 @@ case 1: /* Thunderbolt error, tb_error holds the actual number */ - tb_cfg_print_error(ctl, &res); - return -EIO; + return tb_cfg_get_error(ctl, space, &res); case -ETIMEDOUT: - tb_ctl_warn(ctl, "timeout writing config space %u to %#x\n", - space, offset); + tb_ctl_warn(ctl, "%llx: timeout writing config space %u to %#x\n", + route, space, offset); break; default: -- Gitblit v1.6.2