| 1 |
|
| 2 | |
| 3 | * Thunderbolt driver - control channel and configuration commands
|
| 4 | *
|
| 5 | * Copyright (c) 2014 Andreas Noever <[email protected]>
|
| 6 | * Copyright (C) 2018, Intel Corporation
|
| 7 |
|
| 8 |
|
| 9 | #ifndef _TB_CFG
|
| 10 | #define _TB_CFG
|
| 11 |
|
| 12 | #include <linux/kref.h>
|
| 13 | #include <linux/thunderbolt.h>
|
| 14 |
|
| 15 | #include "nhi.h"
|
| 16 | #include "tb_msgs.h"
|
| 17 |
|
| 18 |
|
| 19 | struct tb_ctl;
|
| 20 |
|
| 21 | typedef bool (*event_cb)(void *data, enum tb_cfg_pkg_type type,
|
| 22 | const void *buf, size_t size);
|
| 23 |
|
| 24 | struct tb_ctl *tb_ctl_alloc(struct tb_nhi *nhi, int index, int timeout_msec,
|
| 25 | event_cb cb, void *cb_data);
|
| 26 | void tb_ctl_start(struct tb_ctl *ctl);
|
| 27 | void tb_ctl_stop(struct tb_ctl *ctl);
|
| 28 | void tb_ctl_free(struct tb_ctl *ctl);
|
| 29 |
|
| 30 |
|
| 31 |
|
| 32 | struct tb_cfg_result {
|
| 33 | u64 response_route;
|
| 34 | u32 response_port; |
| 35 | * If err = 1 then this is the port that send the
|
| 36 | * error.
|
| 37 | * If err = 0 and if this was a cfg_read/write then
|
| 38 | * this is the upstream port of the responding
|
| 39 | * switch.
|
| 40 | * Otherwise the field is set to zero.
|
| 41 |
|
| 42 | int err;
|
| 43 | enum tb_cfg_error tb_error;
|
| 44 | };
|
| 45 |
|
| 46 | struct ctl_pkg {
|
| 47 | struct tb_ctl *ctl;
|
| 48 | void *buffer;
|
| 49 | struct ring_frame frame;
|
| 50 | };
|
| 51 |
|
| 52 | |
| 53 | * struct tb_cfg_request - Control channel request
|
| 54 | * @kref: Reference count
|
| 55 | * @ctl: Pointer to the control channel structure. Only set when the
|
| 56 | * request is queued.
|
| 57 | * @request: Request is stored here
|
| 58 | * @request_size: Size of the request packet (in bytes)
|
| 59 | * @request_type: Type of the request packet
|
| 60 | * @response: Response is stored here
|
| 61 | * @response_size: Maximum size of one response packet
|
| 62 | * @response_type: Expected type of the response packet
|
| 63 | * @npackets: Number of packets expected to be returned with this request
|
| 64 | * @match: Function used to match the incoming packet
|
| 65 | * @copy: Function used to copy the incoming packet to @response
|
| 66 | * @callback: Callback called when the request is finished successfully
|
| 67 | * @callback_data: Data to be passed to @callback
|
| 68 | * @flags: Flags for the request
|
| 69 | * @work: Work item used to complete the request
|
| 70 | * @result: Result after the request has been completed
|
| 71 | * @list: Requests are queued using this field
|
| 72 | *
|
| 73 | * An arbitrary request over Thunderbolt control channel. For standard
|
| 74 | * control channel message, one should use tb_cfg_read/write() and
|
| 75 | * friends if possible.
|
| 76 |
|
| 77 | struct tb_cfg_request {
|
| 78 | struct kref kref;
|
| 79 | struct tb_ctl *ctl;
|
| 80 | const void *request;
|
| 81 | size_t request_size;
|
| 82 | enum tb_cfg_pkg_type request_type;
|
| 83 | void *response;
|
| 84 | size_t response_size;
|
| 85 | enum tb_cfg_pkg_type response_type;
|
| 86 | size_t npackets;
|
| 87 | bool (*match)(const struct tb_cfg_request *req,
|
| 88 | const struct ctl_pkg *pkg);
|
| 89 | bool (*copy)(struct tb_cfg_request *req, const struct ctl_pkg *pkg);
|
| 90 | void (*callback)(void *callback_data);
|
| 91 | void *callback_data;
|
| 92 | unsigned long flags;
|
| 93 | struct work_struct work;
|
| 94 | struct tb_cfg_result result;
|
| 95 | struct list_head list;
|
| 96 | };
|
| 97 |
|
| 98 | #define TB_CFG_REQUEST_ACTIVE 0
|
| 99 | #define TB_CFG_REQUEST_CANCELED 1
|
| 100 |
|
| 101 | struct tb_cfg_request *tb_cfg_request_alloc(void);
|
| 102 | void tb_cfg_request_get(struct tb_cfg_request *req);
|
| 103 | void tb_cfg_request_put(struct tb_cfg_request *req);
|
| 104 | int tb_cfg_request(struct tb_ctl *ctl, struct tb_cfg_request *req,
|
| 105 | void (*callback)(void *), void *callback_data);
|
| 106 | void tb_cfg_request_cancel(struct tb_cfg_request *req, int err);
|
| 107 | struct tb_cfg_result tb_cfg_request_sync(struct tb_ctl *ctl,
|
| 108 | struct tb_cfg_request *req, int timeout_msec);
|
| 109 |
|
| 110 | static inline u64 tb_cfg_get_route(const struct tb_cfg_header *header)
|
| 111 | {
|
| 112 | return (u64) header->route_hi << 32 | header->route_lo;
|
| 113 | }
|
| 114 |
|
| 115 | static inline struct tb_cfg_header tb_cfg_make_header(u64 route)
|
| 116 | {
|
| 117 | struct tb_cfg_header header = {
|
| 118 | .route_hi = route >> 32,
|
| 119 | .route_lo = route,
|
| 120 | };
|
| 121 |
|
| 122 | WARN_ON(tb_cfg_get_route(&header) != route);
|
| 123 | return header;
|
| 124 | }
|
| 125 |
|
| 126 | int tb_cfg_ack_notification(struct tb_ctl *ctl, u64 route,
|
| 127 | const struct cfg_error_pkg *error);
|
| 128 | int tb_cfg_ack_plug(struct tb_ctl *ctl, u64 route, u32 port, bool unplug);
|
| 129 | struct tb_cfg_result tb_cfg_reset(struct tb_ctl *ctl, u64 route);
|
| 130 | struct tb_cfg_result tb_cfg_read_raw(struct tb_ctl *ctl, void *buffer,
|
| 131 | u64 route, u32 port,
|
| 132 | enum tb_cfg_space space, u32 offset,
|
| 133 | u32 length, int timeout_msec);
|
| 134 | struct tb_cfg_result tb_cfg_write_raw(struct tb_ctl *ctl, const void *buffer,
|
| 135 | u64 route, u32 port,
|
| 136 | enum tb_cfg_space space, u32 offset,
|
| 137 | u32 length, int timeout_msec);
|
| 138 | int tb_cfg_read(struct tb_ctl *ctl, void *buffer, u64 route, u32 port,
|
| 139 | enum tb_cfg_space space, u32 offset, u32 length);
|
| 140 | int tb_cfg_write(struct tb_ctl *ctl, const void *buffer, u64 route, u32 port,
|
| 141 | enum tb_cfg_space space, u32 offset, u32 length);
|
| 142 | int tb_cfg_get_upstream_port(struct tb_ctl *ctl, u64 route);
|
| 143 |
|
| 144 | #endif
|