1b2441318SGreg Kroah-Hartman /* SPDX-License-Identifier: GPL-2.0 */
2f25bf6fcSAndreas Noever /*
315c6784cSMika Westerberg * Thunderbolt driver - control channel and configuration commands
4f25bf6fcSAndreas Noever *
5f25bf6fcSAndreas Noever * Copyright (c) 2014 Andreas Noever <andreas.noever@gmail.com>
615c6784cSMika Westerberg * Copyright (C) 2018, Intel Corporation
7f25bf6fcSAndreas Noever */
8f25bf6fcSAndreas Noever
9f25bf6fcSAndreas Noever #ifndef _TB_CFG
10f25bf6fcSAndreas Noever #define _TB_CFG
11f25bf6fcSAndreas Noever
12d7f781bfSMika Westerberg #include <linux/kref.h>
13eaf8ff35SMika Westerberg #include <linux/thunderbolt.h>
14d7f781bfSMika Westerberg
15f25bf6fcSAndreas Noever #include "nhi.h"
1632af9434SMika Westerberg #include "tb_msgs.h"
17f25bf6fcSAndreas Noever
18f25bf6fcSAndreas Noever /* control channel */
19f25bf6fcSAndreas Noever struct tb_ctl;
20f25bf6fcSAndreas Noever
21d1ff7024SMika Westerberg typedef bool (*event_cb)(void *data, enum tb_cfg_pkg_type type,
2281a54b5eSMika Westerberg const void *buf, size_t size);
23f25bf6fcSAndreas Noever
247f0a34d7SMika Westerberg struct tb_ctl *tb_ctl_alloc(struct tb_nhi *nhi, int timeout_msec, event_cb cb,
257f0a34d7SMika Westerberg void *cb_data);
26f25bf6fcSAndreas Noever void tb_ctl_start(struct tb_ctl *ctl);
27f25bf6fcSAndreas Noever void tb_ctl_stop(struct tb_ctl *ctl);
28f25bf6fcSAndreas Noever void tb_ctl_free(struct tb_ctl *ctl);
29f25bf6fcSAndreas Noever
30f25bf6fcSAndreas Noever /* configuration commands */
31f25bf6fcSAndreas Noever
32f25bf6fcSAndreas Noever struct tb_cfg_result {
33f25bf6fcSAndreas Noever u64 response_route;
34f25bf6fcSAndreas Noever u32 response_port; /*
35f25bf6fcSAndreas Noever * If err = 1 then this is the port that send the
36f25bf6fcSAndreas Noever * error.
37f25bf6fcSAndreas Noever * If err = 0 and if this was a cfg_read/write then
3834b9715bSXiang Wangx * this is the upstream port of the responding
39f25bf6fcSAndreas Noever * switch.
40f25bf6fcSAndreas Noever * Otherwise the field is set to zero.
41f25bf6fcSAndreas Noever */
42f25bf6fcSAndreas Noever int err; /* negative errors, 0 for success, 1 for tb errors */
43f25bf6fcSAndreas Noever enum tb_cfg_error tb_error; /* valid if err == 1 */
44f25bf6fcSAndreas Noever };
45f25bf6fcSAndreas Noever
46d7f781bfSMika Westerberg struct ctl_pkg {
47d7f781bfSMika Westerberg struct tb_ctl *ctl;
48d7f781bfSMika Westerberg void *buffer;
49d7f781bfSMika Westerberg struct ring_frame frame;
50d7f781bfSMika Westerberg };
51d7f781bfSMika Westerberg
52d7f781bfSMika Westerberg /**
53d7f781bfSMika Westerberg * struct tb_cfg_request - Control channel request
54d7f781bfSMika Westerberg * @kref: Reference count
55d7f781bfSMika Westerberg * @ctl: Pointer to the control channel structure. Only set when the
56d7f781bfSMika Westerberg * request is queued.
57d7f781bfSMika Westerberg * @request_size: Size of the request packet (in bytes)
58d7f781bfSMika Westerberg * @request_type: Type of the request packet
59d7f781bfSMika Westerberg * @response: Response is stored here
60d7f781bfSMika Westerberg * @response_size: Maximum size of one response packet
61d7f781bfSMika Westerberg * @response_type: Expected type of the response packet
62d7f781bfSMika Westerberg * @npackets: Number of packets expected to be returned with this request
63d7f781bfSMika Westerberg * @match: Function used to match the incoming packet
64d7f781bfSMika Westerberg * @copy: Function used to copy the incoming packet to @response
65d7f781bfSMika Westerberg * @callback: Callback called when the request is finished successfully
66d7f781bfSMika Westerberg * @callback_data: Data to be passed to @callback
67d7f781bfSMika Westerberg * @flags: Flags for the request
68d7f781bfSMika Westerberg * @work: Work item used to complete the request
69d7f781bfSMika Westerberg * @result: Result after the request has been completed
70d7f781bfSMika Westerberg * @list: Requests are queued using this field
71d7f781bfSMika Westerberg *
72d7f781bfSMika Westerberg * An arbitrary request over Thunderbolt control channel. For standard
73d7f781bfSMika Westerberg * control channel message, one should use tb_cfg_read/write() and
74d7f781bfSMika Westerberg * friends if possible.
75d7f781bfSMika Westerberg */
76d7f781bfSMika Westerberg struct tb_cfg_request {
77d7f781bfSMika Westerberg struct kref kref;
78d7f781bfSMika Westerberg struct tb_ctl *ctl;
79d7f781bfSMika Westerberg const void *request;
80d7f781bfSMika Westerberg size_t request_size;
81d7f781bfSMika Westerberg enum tb_cfg_pkg_type request_type;
82d7f781bfSMika Westerberg void *response;
83d7f781bfSMika Westerberg size_t response_size;
84d7f781bfSMika Westerberg enum tb_cfg_pkg_type response_type;
85d7f781bfSMika Westerberg size_t npackets;
86d7f781bfSMika Westerberg bool (*match)(const struct tb_cfg_request *req,
87d7f781bfSMika Westerberg const struct ctl_pkg *pkg);
88d7f781bfSMika Westerberg bool (*copy)(struct tb_cfg_request *req, const struct ctl_pkg *pkg);
89d7f781bfSMika Westerberg void (*callback)(void *callback_data);
90d7f781bfSMika Westerberg void *callback_data;
91d7f781bfSMika Westerberg unsigned long flags;
92d7f781bfSMika Westerberg struct work_struct work;
93d7f781bfSMika Westerberg struct tb_cfg_result result;
94d7f781bfSMika Westerberg struct list_head list;
95d7f781bfSMika Westerberg };
96d7f781bfSMika Westerberg
97d7f781bfSMika Westerberg #define TB_CFG_REQUEST_ACTIVE 0
98d7f781bfSMika Westerberg #define TB_CFG_REQUEST_CANCELED 1
99d7f781bfSMika Westerberg
100d7f781bfSMika Westerberg struct tb_cfg_request *tb_cfg_request_alloc(void);
101d7f781bfSMika Westerberg void tb_cfg_request_get(struct tb_cfg_request *req);
102d7f781bfSMika Westerberg void tb_cfg_request_put(struct tb_cfg_request *req);
103d7f781bfSMika Westerberg int tb_cfg_request(struct tb_ctl *ctl, struct tb_cfg_request *req,
104d7f781bfSMika Westerberg void (*callback)(void *), void *callback_data);
105d7f781bfSMika Westerberg void tb_cfg_request_cancel(struct tb_cfg_request *req, int err);
106d7f781bfSMika Westerberg struct tb_cfg_result tb_cfg_request_sync(struct tb_ctl *ctl,
107d7f781bfSMika Westerberg struct tb_cfg_request *req, int timeout_msec);
108d7f781bfSMika Westerberg
tb_cfg_get_route(const struct tb_cfg_header * header)109ac6c44deSMika Westerberg static inline u64 tb_cfg_get_route(const struct tb_cfg_header *header)
110ac6c44deSMika Westerberg {
111ac6c44deSMika Westerberg return (u64) header->route_hi << 32 | header->route_lo;
112ac6c44deSMika Westerberg }
113f25bf6fcSAndreas Noever
tb_cfg_make_header(u64 route)11405c242e9SMika Westerberg static inline struct tb_cfg_header tb_cfg_make_header(u64 route)
11505c242e9SMika Westerberg {
11605c242e9SMika Westerberg struct tb_cfg_header header = {
11705c242e9SMika Westerberg .route_hi = route >> 32,
11805c242e9SMika Westerberg .route_lo = route,
11905c242e9SMika Westerberg };
12005c242e9SMika Westerberg /* check for overflow, route_hi is not 32 bits! */
12105c242e9SMika Westerberg WARN_ON(tb_cfg_get_route(&header) != route);
12205c242e9SMika Westerberg return header;
12305c242e9SMika Westerberg }
12405c242e9SMika Westerberg
125*6ce35635SMika Westerberg int tb_cfg_ack_notification(struct tb_ctl *ctl, u64 route,
126*6ce35635SMika Westerberg const struct cfg_error_pkg *error);
127210e9f56SMika Westerberg int tb_cfg_ack_plug(struct tb_ctl *ctl, u64 route, u32 port, bool unplug);
128bda83aecSMika Westerberg struct tb_cfg_result tb_cfg_reset(struct tb_ctl *ctl, u64 route);
129f25bf6fcSAndreas Noever struct tb_cfg_result tb_cfg_read_raw(struct tb_ctl *ctl, void *buffer,
130f25bf6fcSAndreas Noever u64 route, u32 port,
131f25bf6fcSAndreas Noever enum tb_cfg_space space, u32 offset,
132f25bf6fcSAndreas Noever u32 length, int timeout_msec);
13316a1258aSMika Westerberg struct tb_cfg_result tb_cfg_write_raw(struct tb_ctl *ctl, const void *buffer,
134f25bf6fcSAndreas Noever u64 route, u32 port,
135f25bf6fcSAndreas Noever enum tb_cfg_space space, u32 offset,
136f25bf6fcSAndreas Noever u32 length, int timeout_msec);
137f25bf6fcSAndreas Noever int tb_cfg_read(struct tb_ctl *ctl, void *buffer, u64 route, u32 port,
138f25bf6fcSAndreas Noever enum tb_cfg_space space, u32 offset, u32 length);
13916a1258aSMika Westerberg int tb_cfg_write(struct tb_ctl *ctl, const void *buffer, u64 route, u32 port,
140f25bf6fcSAndreas Noever enum tb_cfg_space space, u32 offset, u32 length);
141f25bf6fcSAndreas Noever int tb_cfg_get_upstream_port(struct tb_ctl *ctl, u64 route);
142f25bf6fcSAndreas Noever
143f25bf6fcSAndreas Noever
144f25bf6fcSAndreas Noever #endif
145