.. | .. |
---|
1 | 1 | // SPDX-License-Identifier: GPL-2.0 |
---|
2 | 2 | /* |
---|
3 | | - * Thunderbolt Cactus Ridge driver - control channel and configuration commands |
---|
| 3 | + * Thunderbolt driver - control channel and configuration commands |
---|
4 | 4 | * |
---|
5 | 5 | * Copyright (c) 2014 Andreas Noever <andreas.noever@gmail.com> |
---|
| 6 | + * Copyright (C) 2018, Intel Corporation |
---|
6 | 7 | */ |
---|
7 | 8 | |
---|
8 | 9 | #include <linux/crc32.h> |
---|
.. | .. |
---|
218 | 219 | static struct tb_cfg_result decode_error(const struct ctl_pkg *response) |
---|
219 | 220 | { |
---|
220 | 221 | struct cfg_error_pkg *pkg = response->buffer; |
---|
| 222 | + struct tb_ctl *ctl = response->ctl; |
---|
221 | 223 | struct tb_cfg_result res = { 0 }; |
---|
222 | 224 | res.response_route = tb_cfg_get_route(&pkg->header); |
---|
223 | 225 | res.response_port = 0; |
---|
.. | .. |
---|
226 | 228 | if (res.err) |
---|
227 | 229 | return res; |
---|
228 | 230 | |
---|
229 | | - WARN(pkg->zero1, "pkg->zero1 is %#x\n", pkg->zero1); |
---|
230 | | - WARN(pkg->zero2, "pkg->zero1 is %#x\n", pkg->zero1); |
---|
231 | | - WARN(pkg->zero3, "pkg->zero1 is %#x\n", pkg->zero1); |
---|
| 231 | + if (pkg->zero1) |
---|
| 232 | + tb_ctl_warn(ctl, "pkg->zero1 is %#x\n", pkg->zero1); |
---|
| 233 | + if (pkg->zero2) |
---|
| 234 | + tb_ctl_warn(ctl, "pkg->zero2 is %#x\n", pkg->zero2); |
---|
| 235 | + if (pkg->zero3) |
---|
| 236 | + tb_ctl_warn(ctl, "pkg->zero3 is %#x\n", pkg->zero3); |
---|
| 237 | + |
---|
232 | 238 | res.err = 1; |
---|
233 | 239 | res.tb_error = pkg->error; |
---|
234 | 240 | res.response_port = pkg->port; |
---|
.. | .. |
---|
265 | 271 | * Invalid cfg_space/offset/length combination in |
---|
266 | 272 | * cfg_read/cfg_write. |
---|
267 | 273 | */ |
---|
268 | | - tb_ctl_WARN(ctl, |
---|
269 | | - "CFG_ERROR(%llx:%x): Invalid config space or offset\n", |
---|
270 | | - res->response_route, res->response_port); |
---|
| 274 | + tb_ctl_dbg(ctl, "%llx:%x: invalid config space or offset\n", |
---|
| 275 | + res->response_route, res->response_port); |
---|
271 | 276 | return; |
---|
272 | 277 | case TB_CFG_ERROR_NO_SUCH_PORT: |
---|
273 | 278 | /* |
---|
.. | .. |
---|
281 | 286 | case TB_CFG_ERROR_LOOP: |
---|
282 | 287 | tb_ctl_WARN(ctl, "CFG_ERROR(%llx:%x): Route contains a loop\n", |
---|
283 | 288 | res->response_route, res->response_port); |
---|
| 289 | + return; |
---|
| 290 | + case TB_CFG_ERROR_LOCK: |
---|
| 291 | + tb_ctl_warn(ctl, "%llx:%x: downstream port is locked\n", |
---|
| 292 | + res->response_route, res->response_port); |
---|
284 | 293 | return; |
---|
285 | 294 | default: |
---|
286 | 295 | /* 5,6,7,9 and 11 are also valid error codes */ |
---|
.. | .. |
---|
387 | 396 | |
---|
388 | 397 | static int tb_async_error(const struct ctl_pkg *pkg) |
---|
389 | 398 | { |
---|
390 | | - const struct cfg_error_pkg *error = (const struct cfg_error_pkg *)pkg; |
---|
| 399 | + const struct cfg_error_pkg *error = pkg->buffer; |
---|
391 | 400 | |
---|
392 | 401 | if (pkg->frame.eof != TB_CFG_PKG_ERROR) |
---|
393 | 402 | return false; |
---|
.. | .. |
---|
452 | 461 | "RX: checksum mismatch, dropping packet\n"); |
---|
453 | 462 | goto rx; |
---|
454 | 463 | } |
---|
455 | | - /* Fall through */ |
---|
| 464 | + fallthrough; |
---|
456 | 465 | case TB_CFG_PKG_ICM_EVENT: |
---|
457 | 466 | if (tb_ctl_handle_event(pkg->ctl, frame->eof, pkg, frame->size)) |
---|
458 | 467 | goto rx; |
---|
.. | .. |
---|
631 | 640 | ctl->rx_packets[i]->frame.callback = tb_ctl_rx_callback; |
---|
632 | 641 | } |
---|
633 | 642 | |
---|
634 | | - tb_ctl_info(ctl, "control channel created\n"); |
---|
| 643 | + tb_ctl_dbg(ctl, "control channel created\n"); |
---|
635 | 644 | return ctl; |
---|
636 | 645 | err: |
---|
637 | 646 | tb_ctl_free(ctl); |
---|
.. | .. |
---|
662 | 671 | tb_ctl_pkg_free(ctl->rx_packets[i]); |
---|
663 | 672 | |
---|
664 | 673 | |
---|
665 | | - if (ctl->frame_pool) |
---|
666 | | - dma_pool_destroy(ctl->frame_pool); |
---|
| 674 | + dma_pool_destroy(ctl->frame_pool); |
---|
667 | 675 | kfree(ctl); |
---|
668 | 676 | } |
---|
669 | 677 | |
---|
.. | .. |
---|
673 | 681 | void tb_ctl_start(struct tb_ctl *ctl) |
---|
674 | 682 | { |
---|
675 | 683 | int i; |
---|
676 | | - tb_ctl_info(ctl, "control channel starting...\n"); |
---|
| 684 | + tb_ctl_dbg(ctl, "control channel starting...\n"); |
---|
677 | 685 | tb_ring_start(ctl->tx); /* is used to ack hotplug packets, start first */ |
---|
678 | 686 | tb_ring_start(ctl->rx); |
---|
679 | 687 | for (i = 0; i < TB_CTL_RX_PKG_COUNT; i++) |
---|
.. | .. |
---|
702 | 710 | if (!list_empty(&ctl->request_queue)) |
---|
703 | 711 | tb_ctl_WARN(ctl, "dangling request in request_queue\n"); |
---|
704 | 712 | INIT_LIST_HEAD(&ctl->request_queue); |
---|
705 | | - tb_ctl_info(ctl, "control channel stopped\n"); |
---|
| 713 | + tb_ctl_dbg(ctl, "control channel stopped\n"); |
---|
706 | 714 | } |
---|
707 | 715 | |
---|
708 | 716 | /* public interface, commands */ |
---|
709 | 717 | |
---|
710 | 718 | /** |
---|
711 | | - * tb_cfg_error() - send error packet |
---|
| 719 | + * tb_cfg_ack_plug() - Ack hot plug/unplug event |
---|
| 720 | + * @ctl: Control channel to use |
---|
| 721 | + * @route: Router that originated the event |
---|
| 722 | + * @port: Port where the hot plug/unplug happened |
---|
| 723 | + * @unplug: Ack hot plug or unplug |
---|
712 | 724 | * |
---|
713 | | - * Return: Returns 0 on success or an error code on failure. |
---|
| 725 | + * Call this as response for hot plug/unplug event to ack it. |
---|
| 726 | + * Returns %0 on success or an error code on failure. |
---|
714 | 727 | */ |
---|
715 | | -int tb_cfg_error(struct tb_ctl *ctl, u64 route, u32 port, |
---|
716 | | - enum tb_cfg_error error) |
---|
| 728 | +int tb_cfg_ack_plug(struct tb_ctl *ctl, u64 route, u32 port, bool unplug) |
---|
717 | 729 | { |
---|
718 | 730 | struct cfg_error_pkg pkg = { |
---|
719 | 731 | .header = tb_cfg_make_header(route), |
---|
720 | 732 | .port = port, |
---|
721 | | - .error = error, |
---|
| 733 | + .error = TB_CFG_ERROR_ACK_PLUG_EVENT, |
---|
| 734 | + .pg = unplug ? TB_CFG_ERROR_PG_HOT_UNPLUG |
---|
| 735 | + : TB_CFG_ERROR_PG_HOT_PLUG, |
---|
722 | 736 | }; |
---|
723 | | - tb_ctl_info(ctl, "resetting error on %llx:%x.\n", route, port); |
---|
| 737 | + tb_ctl_dbg(ctl, "acking hot %splug event on %llx:%x\n", |
---|
| 738 | + unplug ? "un" : "", route, port); |
---|
724 | 739 | return tb_ctl_tx(ctl, &pkg, sizeof(pkg), TB_CFG_PKG_ERROR); |
---|
725 | 740 | } |
---|
726 | 741 | |
---|
.. | .. |
---|
930 | 945 | return res; |
---|
931 | 946 | } |
---|
932 | 947 | |
---|
| 948 | +static int tb_cfg_get_error(struct tb_ctl *ctl, enum tb_cfg_space space, |
---|
| 949 | + const struct tb_cfg_result *res) |
---|
| 950 | +{ |
---|
| 951 | + /* |
---|
| 952 | + * For unimplemented ports access to port config space may return |
---|
| 953 | + * TB_CFG_ERROR_INVALID_CONFIG_SPACE (alternatively their type is |
---|
| 954 | + * set to TB_TYPE_INACTIVE). In the former case return -ENODEV so |
---|
| 955 | + * that the caller can mark the port as disabled. |
---|
| 956 | + */ |
---|
| 957 | + if (space == TB_CFG_PORT && |
---|
| 958 | + res->tb_error == TB_CFG_ERROR_INVALID_CONFIG_SPACE) |
---|
| 959 | + return -ENODEV; |
---|
| 960 | + |
---|
| 961 | + tb_cfg_print_error(ctl, res); |
---|
| 962 | + |
---|
| 963 | + if (res->tb_error == TB_CFG_ERROR_LOCK) |
---|
| 964 | + return -EACCES; |
---|
| 965 | + return -EIO; |
---|
| 966 | +} |
---|
| 967 | + |
---|
933 | 968 | int tb_cfg_read(struct tb_ctl *ctl, void *buffer, u64 route, u32 port, |
---|
934 | 969 | enum tb_cfg_space space, u32 offset, u32 length) |
---|
935 | 970 | { |
---|
.. | .. |
---|
942 | 977 | |
---|
943 | 978 | case 1: |
---|
944 | 979 | /* Thunderbolt error, tb_error holds the actual number */ |
---|
945 | | - tb_cfg_print_error(ctl, &res); |
---|
946 | | - return -EIO; |
---|
| 980 | + return tb_cfg_get_error(ctl, space, &res); |
---|
947 | 981 | |
---|
948 | 982 | case -ETIMEDOUT: |
---|
949 | | - tb_ctl_warn(ctl, "timeout reading config space %u from %#x\n", |
---|
950 | | - space, offset); |
---|
| 983 | + tb_ctl_warn(ctl, "%llx: timeout reading config space %u from %#x\n", |
---|
| 984 | + route, space, offset); |
---|
951 | 985 | break; |
---|
952 | 986 | |
---|
953 | 987 | default: |
---|
.. | .. |
---|
969 | 1003 | |
---|
970 | 1004 | case 1: |
---|
971 | 1005 | /* Thunderbolt error, tb_error holds the actual number */ |
---|
972 | | - tb_cfg_print_error(ctl, &res); |
---|
973 | | - return -EIO; |
---|
| 1006 | + return tb_cfg_get_error(ctl, space, &res); |
---|
974 | 1007 | |
---|
975 | 1008 | case -ETIMEDOUT: |
---|
976 | | - tb_ctl_warn(ctl, "timeout writing config space %u to %#x\n", |
---|
977 | | - space, offset); |
---|
| 1009 | + tb_ctl_warn(ctl, "%llx: timeout writing config space %u to %#x\n", |
---|
| 1010 | + route, space, offset); |
---|
978 | 1011 | break; |
---|
979 | 1012 | |
---|
980 | 1013 | default: |
---|