1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Huawei HiNIC PCI Express Linux driver 4 * Copyright(c) 2017 Huawei Technologies Co., Ltd 5 */ 6 7 #include <linux/kernel.h> 8 #include <linux/types.h> 9 #include <linux/errno.h> 10 #include <linux/pci.h> 11 #include <linux/device.h> 12 #include <linux/semaphore.h> 13 #include <linux/completion.h> 14 #include <linux/slab.h> 15 #include <asm/barrier.h> 16 17 #include "hinic_hw_if.h" 18 #include "hinic_hw_eqs.h" 19 #include "hinic_hw_api_cmd.h" 20 #include "hinic_hw_mgmt.h" 21 #include "hinic_hw_dev.h" 22 23 #define SYNC_MSG_ID_MASK 0x1FF 24 25 #define SYNC_MSG_ID(pf_to_mgmt) ((pf_to_mgmt)->sync_msg_id) 26 27 #define SYNC_MSG_ID_INC(pf_to_mgmt) (SYNC_MSG_ID(pf_to_mgmt) = \ 28 ((SYNC_MSG_ID(pf_to_mgmt) + 1) & \ 29 SYNC_MSG_ID_MASK)) 30 31 #define MSG_SZ_IS_VALID(in_size) ((in_size) <= MAX_MSG_LEN) 32 33 #define MGMT_MSG_LEN_MIN 20 34 #define MGMT_MSG_LEN_STEP 16 35 #define MGMT_MSG_RSVD_FOR_DEV 8 36 37 #define SEGMENT_LEN 48 38 39 #define MAX_PF_MGMT_BUF_SIZE 2048 40 41 /* Data should be SEG LEN size aligned */ 42 #define MAX_MSG_LEN 2016 43 44 #define MSG_NOT_RESP 0xFFFF 45 46 #define MGMT_MSG_TIMEOUT 5000 47 48 #define mgmt_to_pfhwdev(pf_mgmt) \ 49 container_of(pf_mgmt, struct hinic_pfhwdev, pf_to_mgmt) 50 51 enum msg_segment_type { 52 NOT_LAST_SEGMENT = 0, 53 LAST_SEGMENT = 1, 54 }; 55 56 enum mgmt_direction_type { 57 MGMT_DIRECT_SEND = 0, 58 MGMT_RESP = 1, 59 }; 60 61 enum msg_ack_type { 62 MSG_ACK = 0, 63 MSG_NO_ACK = 1, 64 }; 65 66 /** 67 * hinic_register_mgmt_msg_cb - register msg handler for a msg from a module 68 * @pf_to_mgmt: PF to MGMT channel 69 * @mod: module in the chip that this handler will handle its messages 70 * @handle: private data for the callback 71 * @callback: the handler that will handle messages 72 **/ 73 void hinic_register_mgmt_msg_cb(struct hinic_pf_to_mgmt *pf_to_mgmt, 74 enum hinic_mod_type mod, 75 void *handle, 76 void (*callback)(void *handle, 77 u8 cmd, void *buf_in, 78 u16 in_size, void *buf_out, 79 u16 *out_size)) 80 { 81 struct hinic_mgmt_cb *mgmt_cb = &pf_to_mgmt->mgmt_cb[mod]; 82 83 mgmt_cb->cb = callback; 84 mgmt_cb->handle = handle; 85 mgmt_cb->state = HINIC_MGMT_CB_ENABLED; 86 } 87 88 /** 89 * hinic_unregister_mgmt_msg_cb - unregister msg handler for a msg from a module 90 * @pf_to_mgmt: PF to MGMT channel 91 * @mod: module in the chip that this handler handles its messages 92 **/ 93 void hinic_unregister_mgmt_msg_cb(struct hinic_pf_to_mgmt *pf_to_mgmt, 94 enum hinic_mod_type mod) 95 { 96 struct hinic_mgmt_cb *mgmt_cb = &pf_to_mgmt->mgmt_cb[mod]; 97 98 mgmt_cb->state &= ~HINIC_MGMT_CB_ENABLED; 99 100 while (mgmt_cb->state & HINIC_MGMT_CB_RUNNING) 101 schedule(); 102 103 mgmt_cb->cb = NULL; 104 } 105 106 /** 107 * prepare_header - prepare the header of the message 108 * @pf_to_mgmt: PF to MGMT channel 109 * @msg_len: the length of the message 110 * @mod: module in the chip that will get the message 111 * @ack_type: ask for response 112 * @direction: the direction of the message 113 * @cmd: command of the message 114 * @msg_id: message id 115 * 116 * Return the prepared header value 117 **/ 118 static u64 prepare_header(struct hinic_pf_to_mgmt *pf_to_mgmt, 119 u16 msg_len, enum hinic_mod_type mod, 120 enum msg_ack_type ack_type, 121 enum mgmt_direction_type direction, 122 u16 cmd, u16 msg_id) 123 { 124 struct hinic_hwif *hwif = pf_to_mgmt->hwif; 125 126 return HINIC_MSG_HEADER_SET(msg_len, MSG_LEN) | 127 HINIC_MSG_HEADER_SET(mod, MODULE) | 128 HINIC_MSG_HEADER_SET(SEGMENT_LEN, SEG_LEN) | 129 HINIC_MSG_HEADER_SET(ack_type, NO_ACK) | 130 HINIC_MSG_HEADER_SET(0, ASYNC_MGMT_TO_PF) | 131 HINIC_MSG_HEADER_SET(0, SEQID) | 132 HINIC_MSG_HEADER_SET(LAST_SEGMENT, LAST) | 133 HINIC_MSG_HEADER_SET(direction, DIRECTION) | 134 HINIC_MSG_HEADER_SET(cmd, CMD) | 135 HINIC_MSG_HEADER_SET(HINIC_HWIF_PCI_INTF(hwif), PCI_INTF) | 136 HINIC_MSG_HEADER_SET(HINIC_HWIF_PF_IDX(hwif), PF_IDX) | 137 HINIC_MSG_HEADER_SET(msg_id, MSG_ID); 138 } 139 140 /** 141 * prepare_mgmt_cmd - prepare the mgmt command 142 * @mgmt_cmd: pointer to the command to prepare 143 * @header: pointer of the header for the message 144 * @msg: the data of the message 145 * @msg_len: the length of the message 146 **/ 147 static void prepare_mgmt_cmd(u8 *mgmt_cmd, u64 *header, u8 *msg, u16 msg_len) 148 { 149 memset(mgmt_cmd, 0, MGMT_MSG_RSVD_FOR_DEV); 150 151 mgmt_cmd += MGMT_MSG_RSVD_FOR_DEV; 152 memcpy(mgmt_cmd, header, sizeof(*header)); 153 154 mgmt_cmd += sizeof(*header); 155 memcpy(mgmt_cmd, msg, msg_len); 156 } 157 158 /** 159 * mgmt_msg_len - calculate the total message length 160 * @msg_data_len: the length of the message data 161 * 162 * Return the total message length 163 **/ 164 static u16 mgmt_msg_len(u16 msg_data_len) 165 { 166 /* RSVD + HEADER_SIZE + DATA_LEN */ 167 u16 msg_len = MGMT_MSG_RSVD_FOR_DEV + sizeof(u64) + msg_data_len; 168 169 if (msg_len > MGMT_MSG_LEN_MIN) 170 msg_len = MGMT_MSG_LEN_MIN + 171 ALIGN((msg_len - MGMT_MSG_LEN_MIN), 172 MGMT_MSG_LEN_STEP); 173 else 174 msg_len = MGMT_MSG_LEN_MIN; 175 176 return msg_len; 177 } 178 179 /** 180 * send_msg_to_mgmt - send message to mgmt by API CMD 181 * @pf_to_mgmt: PF to MGMT channel 182 * @mod: module in the chip that will get the message 183 * @cmd: command of the message 184 * @data: the msg data 185 * @data_len: the msg data length 186 * @ack_type: ask for response 187 * @direction: the direction of the original message 188 * @resp_msg_id: msg id to response for 189 * 190 * Return 0 - Success, negative - Failure 191 **/ 192 static int send_msg_to_mgmt(struct hinic_pf_to_mgmt *pf_to_mgmt, 193 enum hinic_mod_type mod, u8 cmd, 194 u8 *data, u16 data_len, 195 enum msg_ack_type ack_type, 196 enum mgmt_direction_type direction, 197 u16 resp_msg_id) 198 { 199 struct hinic_api_cmd_chain *chain; 200 u64 header; 201 u16 msg_id; 202 203 msg_id = SYNC_MSG_ID(pf_to_mgmt); 204 205 if (direction == MGMT_RESP) { 206 header = prepare_header(pf_to_mgmt, data_len, mod, ack_type, 207 direction, cmd, resp_msg_id); 208 } else { 209 SYNC_MSG_ID_INC(pf_to_mgmt); 210 header = prepare_header(pf_to_mgmt, data_len, mod, ack_type, 211 direction, cmd, msg_id); 212 } 213 214 prepare_mgmt_cmd(pf_to_mgmt->sync_msg_buf, &header, data, data_len); 215 216 chain = pf_to_mgmt->cmd_chain[HINIC_API_CMD_WRITE_TO_MGMT_CPU]; 217 return hinic_api_cmd_write(chain, HINIC_NODE_ID_MGMT, 218 pf_to_mgmt->sync_msg_buf, 219 mgmt_msg_len(data_len)); 220 } 221 222 /** 223 * msg_to_mgmt_sync - send sync message to mgmt 224 * @pf_to_mgmt: PF to MGMT channel 225 * @mod: module in the chip that will get the message 226 * @cmd: command of the message 227 * @buf_in: the msg data 228 * @in_size: the msg data length 229 * @buf_out: response 230 * @out_size: response length 231 * @direction: the direction of the original message 232 * @resp_msg_id: msg id to response for 233 * 234 * Return 0 - Success, negative - Failure 235 **/ 236 static int msg_to_mgmt_sync(struct hinic_pf_to_mgmt *pf_to_mgmt, 237 enum hinic_mod_type mod, u8 cmd, 238 u8 *buf_in, u16 in_size, 239 u8 *buf_out, u16 *out_size, 240 enum mgmt_direction_type direction, 241 u16 resp_msg_id) 242 { 243 struct hinic_hwif *hwif = pf_to_mgmt->hwif; 244 struct pci_dev *pdev = hwif->pdev; 245 struct hinic_recv_msg *recv_msg; 246 struct completion *recv_done; 247 u16 msg_id; 248 int err; 249 250 /* Lock the sync_msg_buf */ 251 down(&pf_to_mgmt->sync_msg_lock); 252 253 recv_msg = &pf_to_mgmt->recv_resp_msg_from_mgmt; 254 recv_done = &recv_msg->recv_done; 255 256 if (resp_msg_id == MSG_NOT_RESP) 257 msg_id = SYNC_MSG_ID(pf_to_mgmt); 258 else 259 msg_id = resp_msg_id; 260 261 init_completion(recv_done); 262 263 err = send_msg_to_mgmt(pf_to_mgmt, mod, cmd, buf_in, in_size, 264 MSG_ACK, direction, resp_msg_id); 265 if (err) { 266 dev_err(&pdev->dev, "Failed to send sync msg to mgmt\n"); 267 goto unlock_sync_msg; 268 } 269 270 if (!wait_for_completion_timeout(recv_done, 271 msecs_to_jiffies(MGMT_MSG_TIMEOUT))) { 272 dev_err(&pdev->dev, "MGMT timeout, MSG id = %d\n", msg_id); 273 err = -ETIMEDOUT; 274 goto unlock_sync_msg; 275 } 276 277 smp_rmb(); /* verify reading after completion */ 278 279 if (recv_msg->msg_id != msg_id) { 280 dev_err(&pdev->dev, "incorrect MSG for id = %d\n", msg_id); 281 err = -EFAULT; 282 goto unlock_sync_msg; 283 } 284 285 if ((buf_out) && (recv_msg->msg_len <= MAX_PF_MGMT_BUF_SIZE)) { 286 memcpy(buf_out, recv_msg->msg, recv_msg->msg_len); 287 *out_size = recv_msg->msg_len; 288 } 289 290 unlock_sync_msg: 291 up(&pf_to_mgmt->sync_msg_lock); 292 return err; 293 } 294 295 /** 296 * msg_to_mgmt_async - send message to mgmt without response 297 * @pf_to_mgmt: PF to MGMT channel 298 * @mod: module in the chip that will get the message 299 * @cmd: command of the message 300 * @buf_in: the msg data 301 * @in_size: the msg data length 302 * @direction: the direction of the original message 303 * @resp_msg_id: msg id to response for 304 * 305 * Return 0 - Success, negative - Failure 306 **/ 307 static int msg_to_mgmt_async(struct hinic_pf_to_mgmt *pf_to_mgmt, 308 enum hinic_mod_type mod, u8 cmd, 309 u8 *buf_in, u16 in_size, 310 enum mgmt_direction_type direction, 311 u16 resp_msg_id) 312 { 313 int err; 314 315 /* Lock the sync_msg_buf */ 316 down(&pf_to_mgmt->sync_msg_lock); 317 318 err = send_msg_to_mgmt(pf_to_mgmt, mod, cmd, buf_in, in_size, 319 MSG_NO_ACK, direction, resp_msg_id); 320 321 up(&pf_to_mgmt->sync_msg_lock); 322 return err; 323 } 324 325 /** 326 * hinic_msg_to_mgmt - send message to mgmt 327 * @pf_to_mgmt: PF to MGMT channel 328 * @mod: module in the chip that will get the message 329 * @cmd: command of the message 330 * @buf_in: the msg data 331 * @in_size: the msg data length 332 * @buf_out: response 333 * @out_size: returned response length 334 * @sync: sync msg or async msg 335 * 336 * Return 0 - Success, negative - Failure 337 **/ 338 int hinic_msg_to_mgmt(struct hinic_pf_to_mgmt *pf_to_mgmt, 339 enum hinic_mod_type mod, u8 cmd, 340 void *buf_in, u16 in_size, void *buf_out, u16 *out_size, 341 enum hinic_mgmt_msg_type sync) 342 { 343 struct hinic_hwif *hwif = pf_to_mgmt->hwif; 344 struct pci_dev *pdev = hwif->pdev; 345 346 if (sync != HINIC_MGMT_MSG_SYNC) { 347 dev_err(&pdev->dev, "Invalid MGMT msg type\n"); 348 return -EINVAL; 349 } 350 351 if (!MSG_SZ_IS_VALID(in_size)) { 352 dev_err(&pdev->dev, "Invalid MGMT msg buffer size\n"); 353 return -EINVAL; 354 } 355 356 return msg_to_mgmt_sync(pf_to_mgmt, mod, cmd, buf_in, in_size, 357 buf_out, out_size, MGMT_DIRECT_SEND, 358 MSG_NOT_RESP); 359 } 360 361 /** 362 * mgmt_recv_msg_handler - handler for message from mgmt cpu 363 * @pf_to_mgmt: PF to MGMT channel 364 * @recv_msg: received message details 365 **/ 366 static void mgmt_recv_msg_handler(struct hinic_pf_to_mgmt *pf_to_mgmt, 367 struct hinic_recv_msg *recv_msg) 368 { 369 struct hinic_hwif *hwif = pf_to_mgmt->hwif; 370 struct pci_dev *pdev = hwif->pdev; 371 u8 *buf_out = recv_msg->buf_out; 372 struct hinic_mgmt_cb *mgmt_cb; 373 unsigned long cb_state; 374 u16 out_size = 0; 375 376 if (recv_msg->mod >= HINIC_MOD_MAX) { 377 dev_err(&pdev->dev, "Unknown MGMT MSG module = %d\n", 378 recv_msg->mod); 379 return; 380 } 381 382 mgmt_cb = &pf_to_mgmt->mgmt_cb[recv_msg->mod]; 383 384 cb_state = cmpxchg(&mgmt_cb->state, 385 HINIC_MGMT_CB_ENABLED, 386 HINIC_MGMT_CB_ENABLED | HINIC_MGMT_CB_RUNNING); 387 388 if ((cb_state == HINIC_MGMT_CB_ENABLED) && (mgmt_cb->cb)) 389 mgmt_cb->cb(mgmt_cb->handle, recv_msg->cmd, 390 recv_msg->msg, recv_msg->msg_len, 391 buf_out, &out_size); 392 else 393 dev_err(&pdev->dev, "No MGMT msg handler, mod = %d\n", 394 recv_msg->mod); 395 396 mgmt_cb->state &= ~HINIC_MGMT_CB_RUNNING; 397 398 if (!recv_msg->async_mgmt_to_pf) 399 /* MGMT sent sync msg, send the response */ 400 msg_to_mgmt_async(pf_to_mgmt, recv_msg->mod, recv_msg->cmd, 401 buf_out, out_size, MGMT_RESP, 402 recv_msg->msg_id); 403 } 404 405 /** 406 * mgmt_resp_msg_handler - handler for a response message from mgmt cpu 407 * @pf_to_mgmt: PF to MGMT channel 408 * @recv_msg: received message details 409 **/ 410 static void mgmt_resp_msg_handler(struct hinic_pf_to_mgmt *pf_to_mgmt, 411 struct hinic_recv_msg *recv_msg) 412 { 413 wmb(); /* verify writing all, before reading */ 414 415 complete(&recv_msg->recv_done); 416 } 417 418 /** 419 * recv_mgmt_msg_handler - handler for a message from mgmt cpu 420 * @pf_to_mgmt: PF to MGMT channel 421 * @header: the header of the message 422 * @recv_msg: received message details 423 **/ 424 static void recv_mgmt_msg_handler(struct hinic_pf_to_mgmt *pf_to_mgmt, 425 u64 *header, struct hinic_recv_msg *recv_msg) 426 { 427 struct hinic_hwif *hwif = pf_to_mgmt->hwif; 428 struct pci_dev *pdev = hwif->pdev; 429 int seq_id, seg_len; 430 u8 *msg_body; 431 432 seq_id = HINIC_MSG_HEADER_GET(*header, SEQID); 433 seg_len = HINIC_MSG_HEADER_GET(*header, SEG_LEN); 434 435 if (seq_id >= (MAX_MSG_LEN / SEGMENT_LEN)) { 436 dev_err(&pdev->dev, "recv big mgmt msg\n"); 437 return; 438 } 439 440 msg_body = (u8 *)header + sizeof(*header); 441 memcpy(recv_msg->msg + seq_id * SEGMENT_LEN, msg_body, seg_len); 442 443 if (!HINIC_MSG_HEADER_GET(*header, LAST)) 444 return; 445 446 recv_msg->cmd = HINIC_MSG_HEADER_GET(*header, CMD); 447 recv_msg->mod = HINIC_MSG_HEADER_GET(*header, MODULE); 448 recv_msg->async_mgmt_to_pf = HINIC_MSG_HEADER_GET(*header, 449 ASYNC_MGMT_TO_PF); 450 recv_msg->msg_len = HINIC_MSG_HEADER_GET(*header, MSG_LEN); 451 recv_msg->msg_id = HINIC_MSG_HEADER_GET(*header, MSG_ID); 452 453 if (HINIC_MSG_HEADER_GET(*header, DIRECTION) == MGMT_RESP) 454 mgmt_resp_msg_handler(pf_to_mgmt, recv_msg); 455 else 456 mgmt_recv_msg_handler(pf_to_mgmt, recv_msg); 457 } 458 459 /** 460 * mgmt_msg_aeqe_handler - handler for a mgmt message event 461 * @handle: PF to MGMT channel 462 * @data: the header of the message 463 * @size: unused 464 **/ 465 static void mgmt_msg_aeqe_handler(void *handle, void *data, u8 size) 466 { 467 struct hinic_pf_to_mgmt *pf_to_mgmt = handle; 468 struct hinic_recv_msg *recv_msg; 469 u64 *header = (u64 *)data; 470 471 recv_msg = HINIC_MSG_HEADER_GET(*header, DIRECTION) == 472 MGMT_DIRECT_SEND ? 473 &pf_to_mgmt->recv_msg_from_mgmt : 474 &pf_to_mgmt->recv_resp_msg_from_mgmt; 475 476 recv_mgmt_msg_handler(pf_to_mgmt, header, recv_msg); 477 } 478 479 /** 480 * alloc_recv_msg - allocate receive message memory 481 * @pf_to_mgmt: PF to MGMT channel 482 * @recv_msg: pointer that will hold the allocated data 483 * 484 * Return 0 - Success, negative - Failure 485 **/ 486 static int alloc_recv_msg(struct hinic_pf_to_mgmt *pf_to_mgmt, 487 struct hinic_recv_msg *recv_msg) 488 { 489 struct hinic_hwif *hwif = pf_to_mgmt->hwif; 490 struct pci_dev *pdev = hwif->pdev; 491 492 recv_msg->msg = devm_kzalloc(&pdev->dev, MAX_PF_MGMT_BUF_SIZE, 493 GFP_KERNEL); 494 if (!recv_msg->msg) 495 return -ENOMEM; 496 497 recv_msg->buf_out = devm_kzalloc(&pdev->dev, MAX_PF_MGMT_BUF_SIZE, 498 GFP_KERNEL); 499 if (!recv_msg->buf_out) 500 return -ENOMEM; 501 502 return 0; 503 } 504 505 /** 506 * alloc_msg_buf - allocate all the message buffers of PF to MGMT channel 507 * @pf_to_mgmt: PF to MGMT channel 508 * 509 * Return 0 - Success, negative - Failure 510 **/ 511 static int alloc_msg_buf(struct hinic_pf_to_mgmt *pf_to_mgmt) 512 { 513 struct hinic_hwif *hwif = pf_to_mgmt->hwif; 514 struct pci_dev *pdev = hwif->pdev; 515 int err; 516 517 err = alloc_recv_msg(pf_to_mgmt, 518 &pf_to_mgmt->recv_msg_from_mgmt); 519 if (err) { 520 dev_err(&pdev->dev, "Failed to allocate recv msg\n"); 521 return err; 522 } 523 524 err = alloc_recv_msg(pf_to_mgmt, 525 &pf_to_mgmt->recv_resp_msg_from_mgmt); 526 if (err) { 527 dev_err(&pdev->dev, "Failed to allocate resp recv msg\n"); 528 return err; 529 } 530 531 pf_to_mgmt->sync_msg_buf = devm_kzalloc(&pdev->dev, 532 MAX_PF_MGMT_BUF_SIZE, 533 GFP_KERNEL); 534 if (!pf_to_mgmt->sync_msg_buf) 535 return -ENOMEM; 536 537 return 0; 538 } 539 540 /** 541 * hinic_pf_to_mgmt_init - initialize PF to MGMT channel 542 * @pf_to_mgmt: PF to MGMT channel 543 * @hwif: HW interface the PF to MGMT will use for accessing HW 544 * 545 * Return 0 - Success, negative - Failure 546 **/ 547 int hinic_pf_to_mgmt_init(struct hinic_pf_to_mgmt *pf_to_mgmt, 548 struct hinic_hwif *hwif) 549 { 550 struct hinic_pfhwdev *pfhwdev = mgmt_to_pfhwdev(pf_to_mgmt); 551 struct hinic_hwdev *hwdev = &pfhwdev->hwdev; 552 struct pci_dev *pdev = hwif->pdev; 553 int err; 554 555 pf_to_mgmt->hwif = hwif; 556 557 sema_init(&pf_to_mgmt->sync_msg_lock, 1); 558 pf_to_mgmt->sync_msg_id = 0; 559 560 err = alloc_msg_buf(pf_to_mgmt); 561 if (err) { 562 dev_err(&pdev->dev, "Failed to allocate msg buffers\n"); 563 return err; 564 } 565 566 err = hinic_api_cmd_init(pf_to_mgmt->cmd_chain, hwif); 567 if (err) { 568 dev_err(&pdev->dev, "Failed to initialize cmd chains\n"); 569 return err; 570 } 571 572 hinic_aeq_register_hw_cb(&hwdev->aeqs, HINIC_MSG_FROM_MGMT_CPU, 573 pf_to_mgmt, 574 mgmt_msg_aeqe_handler); 575 return 0; 576 } 577 578 /** 579 * hinic_pf_to_mgmt_free - free PF to MGMT channel 580 * @pf_to_mgmt: PF to MGMT channel 581 **/ 582 void hinic_pf_to_mgmt_free(struct hinic_pf_to_mgmt *pf_to_mgmt) 583 { 584 struct hinic_pfhwdev *pfhwdev = mgmt_to_pfhwdev(pf_to_mgmt); 585 struct hinic_hwdev *hwdev = &pfhwdev->hwdev; 586 587 hinic_aeq_unregister_hw_cb(&hwdev->aeqs, HINIC_MSG_FROM_MGMT_CPU); 588 hinic_api_cmd_free(pf_to_mgmt->cmd_chain); 589 } 590