1 // SPDX-License-Identifier: GPL-2.0 2 // Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved. 3 4 #include <linux/delay.h> 5 6 #include "hinic3_cmdq.h" 7 #include "hinic3_hw_comm.h" 8 #include "hinic3_hwdev.h" 9 #include "hinic3_hwif.h" 10 #include "hinic3_mbox.h" 11 12 int hinic3_set_interrupt_cfg_direct(struct hinic3_hwdev *hwdev, 13 const struct hinic3_interrupt_info *info) 14 { 15 struct comm_cmd_cfg_msix_ctrl_reg msix_cfg = {}; 16 struct mgmt_msg_params msg_params = {}; 17 int err; 18 19 msix_cfg.func_id = hinic3_global_func_id(hwdev); 20 msix_cfg.msix_index = info->msix_index; 21 msix_cfg.opcode = MGMT_MSG_CMD_OP_SET; 22 23 msix_cfg.lli_credit_cnt = info->lli_credit_limit; 24 msix_cfg.lli_timer_cnt = info->lli_timer_cfg; 25 msix_cfg.pending_cnt = info->pending_limit; 26 msix_cfg.coalesce_timer_cnt = info->coalesc_timer_cfg; 27 msix_cfg.resend_timer_cnt = info->resend_timer_cfg; 28 29 mgmt_msg_params_init_default(&msg_params, &msix_cfg, sizeof(msix_cfg)); 30 31 err = hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_COMM, 32 COMM_CMD_CFG_MSIX_CTRL_REG, &msg_params); 33 if (err || msix_cfg.head.status) { 34 dev_err(hwdev->dev, 35 "Failed to set interrupt config, err: %d, status: 0x%x\n", 36 err, msix_cfg.head.status); 37 return -EINVAL; 38 } 39 40 return 0; 41 } 42 43 int hinic3_func_reset(struct hinic3_hwdev *hwdev, u16 func_id, u64 reset_flag) 44 { 45 struct comm_cmd_func_reset func_reset = {}; 46 struct mgmt_msg_params msg_params = {}; 47 int err; 48 49 func_reset.func_id = func_id; 50 func_reset.reset_flag = reset_flag; 51 52 mgmt_msg_params_init_default(&msg_params, &func_reset, 53 sizeof(func_reset)); 54 55 err = hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_COMM, 56 COMM_CMD_FUNC_RESET, &msg_params); 57 if (err || func_reset.head.status) { 58 dev_err(hwdev->dev, "Failed to reset func resources, reset_flag 0x%llx, err: %d, status: 0x%x\n", 59 reset_flag, err, func_reset.head.status); 60 return -EIO; 61 } 62 63 return 0; 64 } 65 66 static int hinic3_comm_features_nego(struct hinic3_hwdev *hwdev, u8 opcode, 67 u64 *s_feature, u16 size) 68 { 69 struct comm_cmd_feature_nego feature_nego = {}; 70 struct mgmt_msg_params msg_params = {}; 71 int err; 72 73 feature_nego.func_id = hinic3_global_func_id(hwdev); 74 feature_nego.opcode = opcode; 75 if (opcode == MGMT_MSG_CMD_OP_SET) 76 memcpy(feature_nego.s_feature, s_feature, 77 array_size(size, sizeof(u64))); 78 79 mgmt_msg_params_init_default(&msg_params, &feature_nego, 80 sizeof(feature_nego)); 81 82 err = hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_COMM, 83 COMM_CMD_FEATURE_NEGO, &msg_params); 84 if (err || feature_nego.head.status) { 85 dev_err(hwdev->dev, "Failed to negotiate feature, err: %d, status: 0x%x\n", 86 err, feature_nego.head.status); 87 return -EINVAL; 88 } 89 90 if (opcode == MGMT_MSG_CMD_OP_GET) 91 memcpy(s_feature, feature_nego.s_feature, 92 array_size(size, sizeof(u64))); 93 94 return 0; 95 } 96 97 int hinic3_get_comm_features(struct hinic3_hwdev *hwdev, u64 *s_feature, 98 u16 size) 99 { 100 return hinic3_comm_features_nego(hwdev, MGMT_MSG_CMD_OP_GET, s_feature, 101 size); 102 } 103 104 int hinic3_set_comm_features(struct hinic3_hwdev *hwdev, u64 *s_feature, 105 u16 size) 106 { 107 return hinic3_comm_features_nego(hwdev, MGMT_MSG_CMD_OP_SET, s_feature, 108 size); 109 } 110 111 int hinic3_get_global_attr(struct hinic3_hwdev *hwdev, 112 struct comm_global_attr *attr) 113 { 114 struct comm_cmd_get_glb_attr get_attr = {}; 115 struct mgmt_msg_params msg_params = {}; 116 int err; 117 118 mgmt_msg_params_init_default(&msg_params, &get_attr, sizeof(get_attr)); 119 120 err = hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_COMM, 121 COMM_CMD_GET_GLOBAL_ATTR, &msg_params); 122 if (err || get_attr.head.status) { 123 dev_err(hwdev->dev, 124 "Failed to get global attribute, err: %d, status: 0x%x\n", 125 err, get_attr.head.status); 126 return -EIO; 127 } 128 129 memcpy(attr, &get_attr.attr, sizeof(*attr)); 130 131 return 0; 132 } 133 134 int hinic3_set_func_svc_used_state(struct hinic3_hwdev *hwdev, u16 svc_type, 135 u8 state) 136 { 137 struct comm_cmd_set_func_svc_used_state used_state = {}; 138 struct mgmt_msg_params msg_params = {}; 139 int err; 140 141 used_state.func_id = hinic3_global_func_id(hwdev); 142 used_state.svc_type = svc_type; 143 used_state.used_state = state; 144 145 mgmt_msg_params_init_default(&msg_params, &used_state, 146 sizeof(used_state)); 147 148 err = hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_COMM, 149 COMM_CMD_SET_FUNC_SVC_USED_STATE, 150 &msg_params); 151 if (err || used_state.head.status) { 152 dev_err(hwdev->dev, 153 "Failed to set func service used state, err: %d, status: 0x%x\n", 154 err, used_state.head.status); 155 return -EIO; 156 } 157 158 return 0; 159 } 160 161 int hinic3_set_dma_attr_tbl(struct hinic3_hwdev *hwdev, u8 entry_idx, u8 st, 162 u8 at, u8 ph, u8 no_snooping, u8 tph_en) 163 { 164 struct comm_cmd_set_dma_attr dma_attr = {}; 165 struct mgmt_msg_params msg_params = {}; 166 int err; 167 168 dma_attr.func_id = hinic3_global_func_id(hwdev); 169 dma_attr.entry_idx = entry_idx; 170 dma_attr.st = st; 171 dma_attr.at = at; 172 dma_attr.ph = ph; 173 dma_attr.no_snooping = no_snooping; 174 dma_attr.tph_en = tph_en; 175 176 mgmt_msg_params_init_default(&msg_params, &dma_attr, sizeof(dma_attr)); 177 178 err = hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_COMM, 179 COMM_CMD_SET_DMA_ATTR, &msg_params); 180 if (err || dma_attr.head.status) { 181 dev_err(hwdev->dev, "Failed to set dma attr, err: %d, status: 0x%x\n", 182 err, dma_attr.head.status); 183 return -EIO; 184 } 185 186 return 0; 187 } 188 189 int hinic3_set_wq_page_size(struct hinic3_hwdev *hwdev, u16 func_idx, 190 u32 page_size) 191 { 192 struct comm_cmd_cfg_wq_page_size page_size_info = {}; 193 struct mgmt_msg_params msg_params = {}; 194 int err; 195 196 page_size_info.func_id = func_idx; 197 page_size_info.page_size = ilog2(page_size / HINIC3_MIN_PAGE_SIZE); 198 page_size_info.opcode = MGMT_MSG_CMD_OP_SET; 199 200 mgmt_msg_params_init_default(&msg_params, &page_size_info, 201 sizeof(page_size_info)); 202 203 err = hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_COMM, 204 COMM_CMD_CFG_PAGESIZE, &msg_params); 205 if (err || page_size_info.head.status) { 206 dev_err(hwdev->dev, 207 "Failed to set wq page size, err: %d, status: 0x%x\n", 208 err, page_size_info.head.status); 209 return -EFAULT; 210 } 211 212 return 0; 213 } 214 215 int hinic3_set_cmdq_depth(struct hinic3_hwdev *hwdev, u16 cmdq_depth) 216 { 217 struct comm_cmd_set_root_ctxt root_ctxt = {}; 218 struct mgmt_msg_params msg_params = {}; 219 int err; 220 221 root_ctxt.func_id = hinic3_global_func_id(hwdev); 222 223 root_ctxt.set_cmdq_depth = 1; 224 root_ctxt.cmdq_depth = ilog2(cmdq_depth); 225 226 mgmt_msg_params_init_default(&msg_params, &root_ctxt, 227 sizeof(root_ctxt)); 228 229 err = hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_COMM, 230 COMM_CMD_SET_VAT, &msg_params); 231 if (err || root_ctxt.head.status) { 232 dev_err(hwdev->dev, 233 "Failed to set cmdq depth, err: %d, status: 0x%x\n", 234 err, root_ctxt.head.status); 235 return -EFAULT; 236 } 237 238 return 0; 239 } 240 241 #define HINIC3_WAIT_CMDQ_IDLE_TIMEOUT 5000 242 243 static enum hinic3_wait_return check_cmdq_stop_handler(void *priv_data) 244 { 245 struct hinic3_hwdev *hwdev = priv_data; 246 enum hinic3_cmdq_type cmdq_type; 247 struct hinic3_cmdqs *cmdqs; 248 249 cmdqs = hwdev->cmdqs; 250 for (cmdq_type = 0; cmdq_type < cmdqs->cmdq_num; cmdq_type++) { 251 if (!hinic3_cmdq_idle(&cmdqs->cmdq[cmdq_type])) 252 return HINIC3_WAIT_PROCESS_WAITING; 253 } 254 255 return HINIC3_WAIT_PROCESS_CPL; 256 } 257 258 static int wait_cmdq_stop(struct hinic3_hwdev *hwdev) 259 { 260 struct hinic3_cmdqs *cmdqs = hwdev->cmdqs; 261 enum hinic3_cmdq_type cmdq_type; 262 int err; 263 264 if (!(cmdqs->status & HINIC3_CMDQ_ENABLE)) 265 return 0; 266 267 cmdqs->status &= ~HINIC3_CMDQ_ENABLE; 268 err = hinic3_wait_for_timeout(hwdev, check_cmdq_stop_handler, 269 HINIC3_WAIT_CMDQ_IDLE_TIMEOUT, 270 USEC_PER_MSEC); 271 272 if (err) 273 goto err_reenable_cmdq; 274 275 return 0; 276 277 err_reenable_cmdq: 278 for (cmdq_type = 0; cmdq_type < cmdqs->cmdq_num; cmdq_type++) { 279 if (!hinic3_cmdq_idle(&cmdqs->cmdq[cmdq_type])) 280 dev_err(hwdev->dev, "Cmdq %d is busy\n", cmdq_type); 281 } 282 cmdqs->status |= HINIC3_CMDQ_ENABLE; 283 284 return err; 285 } 286 287 int hinic3_func_rx_tx_flush(struct hinic3_hwdev *hwdev) 288 { 289 struct comm_cmd_clear_resource clear_db = {}; 290 struct comm_cmd_clear_resource clr_res = {}; 291 struct hinic3_hwif *hwif = hwdev->hwif; 292 struct mgmt_msg_params msg_params = {}; 293 int ret = 0; 294 int err; 295 296 err = wait_cmdq_stop(hwdev); 297 if (err) { 298 dev_warn(hwdev->dev, "CMDQ is still working, CMDQ timeout value is unreasonable\n"); 299 ret = err; 300 } 301 302 hinic3_toggle_doorbell(hwif, DISABLE_DOORBELL); 303 304 clear_db.func_id = hwif->attr.func_global_idx; 305 mgmt_msg_params_init_default(&msg_params, &clear_db, sizeof(clear_db)); 306 err = hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_COMM, 307 COMM_CMD_FLUSH_DOORBELL, &msg_params); 308 if (err || clear_db.head.status) { 309 dev_warn(hwdev->dev, "Failed to flush doorbell, err: %d, status: 0x%x\n", 310 err, clear_db.head.status); 311 if (err) 312 ret = err; 313 else 314 ret = -EFAULT; 315 } 316 317 clr_res.func_id = hwif->attr.func_global_idx; 318 msg_params.buf_in = &clr_res; 319 msg_params.in_size = sizeof(clr_res); 320 err = hinic3_send_mbox_to_mgmt_no_ack(hwdev, MGMT_MOD_COMM, 321 COMM_CMD_START_FLUSH, 322 &msg_params); 323 if (err) { 324 dev_warn(hwdev->dev, "Failed to notice flush message, err: %d\n", 325 err); 326 ret = err; 327 } 328 329 hinic3_toggle_doorbell(hwif, ENABLE_DOORBELL); 330 331 err = hinic3_reinit_cmdq_ctxts(hwdev); 332 if (err) { 333 dev_warn(hwdev->dev, "Failed to reinit cmdq\n"); 334 ret = err; 335 } 336 337 return ret; 338 } 339 340 static int get_hw_rx_buf_size_idx(int rx_buf_sz, u16 *buf_sz_idx) 341 { 342 /* Supported RX buffer sizes in bytes. Configured by array index. */ 343 static const int supported_sizes[16] = { 344 [0] = 32, [1] = 64, [2] = 96, [3] = 128, 345 [4] = 192, [5] = 256, [6] = 384, [7] = 512, 346 [8] = 768, [9] = 1024, [10] = 1536, [11] = 2048, 347 [12] = 3072, [13] = 4096, [14] = 8192, [15] = 16384, 348 }; 349 u16 idx; 350 351 /* Scan from biggest to smallest. Choose supported size that is equal or 352 * smaller. For smaller value HW will under-utilize posted buffers. For 353 * bigger value HW may overrun posted buffers. 354 */ 355 idx = ARRAY_SIZE(supported_sizes); 356 while (idx > 0) { 357 idx--; 358 if (supported_sizes[idx] <= rx_buf_sz) { 359 *buf_sz_idx = idx; 360 return 0; 361 } 362 } 363 364 return -EINVAL; 365 } 366 367 int hinic3_set_root_ctxt(struct hinic3_hwdev *hwdev, u32 rq_depth, u32 sq_depth, 368 int rx_buf_sz) 369 { 370 struct comm_cmd_set_root_ctxt root_ctxt = {}; 371 struct mgmt_msg_params msg_params = {}; 372 u16 buf_sz_idx; 373 int err; 374 375 err = get_hw_rx_buf_size_idx(rx_buf_sz, &buf_sz_idx); 376 if (err) 377 return err; 378 379 root_ctxt.func_id = hinic3_global_func_id(hwdev); 380 381 root_ctxt.set_cmdq_depth = 0; 382 root_ctxt.cmdq_depth = 0; 383 384 root_ctxt.lro_en = 1; 385 386 root_ctxt.rq_depth = ilog2(rq_depth); 387 root_ctxt.rx_buf_sz = buf_sz_idx; 388 root_ctxt.sq_depth = ilog2(sq_depth); 389 390 mgmt_msg_params_init_default(&msg_params, &root_ctxt, 391 sizeof(root_ctxt)); 392 393 err = hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_COMM, 394 COMM_CMD_SET_VAT, &msg_params); 395 if (err || root_ctxt.head.status) { 396 dev_err(hwdev->dev, 397 "Failed to set root context, err: %d, status: 0x%x\n", 398 err, root_ctxt.head.status); 399 return -EFAULT; 400 } 401 402 return 0; 403 } 404 405 int hinic3_clean_root_ctxt(struct hinic3_hwdev *hwdev) 406 { 407 struct comm_cmd_set_root_ctxt root_ctxt = {}; 408 struct mgmt_msg_params msg_params = {}; 409 int err; 410 411 root_ctxt.func_id = hinic3_global_func_id(hwdev); 412 413 mgmt_msg_params_init_default(&msg_params, &root_ctxt, 414 sizeof(root_ctxt)); 415 416 err = hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_COMM, 417 COMM_CMD_SET_VAT, &msg_params); 418 if (err || root_ctxt.head.status) { 419 dev_err(hwdev->dev, 420 "Failed to set root context, err: %d, status: 0x%x\n", 421 err, root_ctxt.head.status); 422 return -EFAULT; 423 } 424 425 return 0; 426 } 427