1 // SPDX-License-Identifier: GPL-2.0-only 2 /* Copyright (C) 2025 Intel Corporation */ 3 4 #include "ixd.h" 5 #include "ixd_ctlq.h" 6 #include "ixd_virtchnl.h" 7 8 /** 9 * ixd_vc_recv_event_msg - Handle virtchnl event message 10 * @adapter: The adapter handling the message 11 * @ctlq_msg: Message received 12 */ 13 void ixd_vc_recv_event_msg(struct ixd_adapter *adapter, 14 struct libie_ctlq_msg *ctlq_msg) 15 { 16 int payload_size = ctlq_msg->data_len; 17 struct virtchnl2_event *v2e; 18 19 if (payload_size < sizeof(*v2e)) { 20 dev_warn_ratelimited(ixd_to_dev(adapter), 21 "Failed to receive valid payload for event msg (op 0x%X len %u)\n", 22 ctlq_msg->chnl_opcode, 23 payload_size); 24 return; 25 } 26 27 v2e = (struct virtchnl2_event *)ctlq_msg->recv_mem.iov_base; 28 29 dev_dbg(ixd_to_dev(adapter), "Got event 0x%X from the CP\n", 30 le32_to_cpu(v2e->event)); 31 } 32 33 /** 34 * ixd_vc_can_handle_msg - Decide if an event has to be handled by virtchnl code 35 * @ctlq_msg: Message received 36 * 37 * Return: %true if virtchnl code can handle the event, %false otherwise 38 */ 39 bool ixd_vc_can_handle_msg(struct libie_ctlq_msg *ctlq_msg) 40 { 41 return ctlq_msg->chnl_opcode == VIRTCHNL2_OP_EVENT; 42 } 43 44 /** 45 * ixd_handle_caps - Handle VIRTCHNL2_OP_GET_CAPS response 46 * @adapter: The adapter for which the capabilities are being updated 47 * @recv_buff: Buffer containing the response 48 * @recv_size: Response buffer size 49 * @ctx: unused 50 * 51 * Return: %0 if the response format is correct and was handled as expected, 52 * negative error otherwise. 53 */ 54 static int ixd_handle_caps(struct ixd_adapter *adapter, void *recv_buff, 55 size_t recv_size, void *ctx) 56 { 57 if (recv_size < sizeof(adapter->caps)) 58 return -EBADMSG; 59 60 adapter->caps = *(typeof(adapter->caps) *)recv_buff; 61 62 return 0; 63 } 64 65 /** 66 * ixd_req_vc_caps - Request and save device capability 67 * @adapter: The adapter to get the capabilities for 68 * 69 * Return: success or error if sending the get capability message fails 70 */ 71 static int ixd_req_vc_caps(struct ixd_adapter *adapter) 72 { 73 const struct ixd_ctlq_req req = { 74 .opcode = VIRTCHNL2_OP_GET_CAPS, 75 .send_size = sizeof(struct virtchnl2_get_capabilities), 76 .ctx = NULL, 77 .send_buff_init = NULL, 78 .recv_process = ixd_handle_caps, 79 }; 80 81 return ixd_ctlq_do_req(adapter, &req); 82 } 83 84 /** 85 * ixd_get_vc_ver - Get version info from adapter 86 * 87 * Return: filled in virtchannel2 version info, ready for sending 88 */ 89 static struct virtchnl2_version_info ixd_get_vc_ver(void) 90 { 91 return (struct virtchnl2_version_info) { 92 .major = cpu_to_le32(VIRTCHNL2_VERSION_MAJOR_2), 93 .minor = cpu_to_le32(VIRTCHNL2_VERSION_MINOR_0), 94 }; 95 } 96 97 static void ixd_fill_vc_ver(struct ixd_adapter *adapter, void *send_buff, 98 void *ctx) 99 { 100 *(struct virtchnl2_version_info *)send_buff = ixd_get_vc_ver(); 101 } 102 103 /** 104 * ixd_handle_vc_ver - Handle VIRTCHNL2_OP_VERSION response 105 * @adapter: The adapter for which the version is being updated 106 * @recv_buff: Buffer containing the response 107 * @recv_size: Response buffer size 108 * @ctx: Unused 109 * 110 * Return: %0 if the response format is correct and was handled as expected, 111 * negative error otherwise. 112 */ 113 static int ixd_handle_vc_ver(struct ixd_adapter *adapter, void *recv_buff, 114 size_t recv_size, void *ctx) 115 { 116 struct virtchnl2_version_info need_ver = ixd_get_vc_ver(); 117 struct virtchnl2_version_info *recv_ver; 118 119 if (recv_size < sizeof(need_ver)) 120 return -EBADMSG; 121 122 recv_ver = recv_buff; 123 if (le32_to_cpu(need_ver.major) != le32_to_cpu(recv_ver->major) || 124 le32_to_cpu(need_ver.minor) != le32_to_cpu(recv_ver->minor)) 125 dev_warn(ixd_to_dev(adapter), 126 "Virtchnl version does not match (expected %u.%u, received %u.%u)\n", 127 le32_to_cpu(need_ver.major), 128 le32_to_cpu(need_ver.minor), 129 le32_to_cpu(recv_ver->major), 130 le32_to_cpu(recv_ver->minor)); 131 132 if (le32_to_cpu(need_ver.major) != le32_to_cpu(recv_ver->major)) { 133 dev_err(ixd_to_dev(adapter), 134 "Device initialization failed due to virtchnl major version mismatch\n"); 135 return -EOPNOTSUPP; 136 } 137 138 adapter->vc_ver.major = le32_to_cpu(recv_ver->major); 139 adapter->vc_ver.minor = le32_to_cpu(recv_ver->minor); 140 141 return 0; 142 } 143 144 /** 145 * ixd_req_vc_version - Request and save Virtchannel2 version 146 * @adapter: The adapter to get the version for 147 * 148 * Return: success or error if sending fails or the response was not as expected 149 */ 150 static int ixd_req_vc_version(struct ixd_adapter *adapter) 151 { 152 const struct ixd_ctlq_req req = { 153 .opcode = VIRTCHNL2_OP_VERSION, 154 .send_size = sizeof(struct virtchnl2_version_info), 155 .ctx = NULL, 156 .send_buff_init = ixd_fill_vc_ver, 157 .recv_process = ixd_handle_vc_ver, 158 }; 159 160 return ixd_ctlq_do_req(adapter, &req); 161 } 162 163 /** 164 * ixd_vc_dev_init - virtchnl device core initialization 165 * @adapter: device information 166 * 167 * Return: %0 on success or error if any step of the initialization fails 168 */ 169 int ixd_vc_dev_init(struct ixd_adapter *adapter) 170 { 171 int err; 172 173 err = ixd_req_vc_version(adapter); 174 if (err) { 175 dev_warn(ixd_to_dev(adapter), 176 "Getting virtchnl version failed, error=%pe\n", 177 ERR_PTR(err)); 178 return err; 179 } 180 181 err = ixd_req_vc_caps(adapter); 182 if (err) { 183 dev_warn(ixd_to_dev(adapter), 184 "Getting virtchnl capabilities failed, error=%pe\n", 185 ERR_PTR(err)); 186 return err; 187 } 188 189 return err; 190 } 191