void IPMB_TXTask()

in common/ipmi/ipmb.c [249:490]


void IPMB_TXTask(void *pvParameters, void *arvg0, void *arvg1)
{
	struct ipmi_msg_cfg *current_msg_tx;
	IPMB_config ipmb_cfg;
	I2C_MSG *msg;
	uint8_t ipmb_buffer_tx[IPMI_MSG_MAX_LENGTH + IPMB_RESP_HEADER_LENGTH], status = 0,
									       retry = 5;
	memcpy(&ipmb_cfg, (IPMB_config *)pvParameters, sizeof(IPMB_config));

	while (1) {
		current_msg_tx = (struct ipmi_msg_cfg *)malloc(sizeof(struct ipmi_msg_cfg));
		if (current_msg_tx == NULL) { // allocate memory fail, retry later
			k_msleep(10);
			continue;
		}

		k_msgq_get(&ipmb_txqueue[ipmb_cfg.index], (ipmi_msg_cfg *)current_msg_tx,
			   K_FOREVER); // Wait for OS queue send interrupt

		if (IS_RESPONSE(current_msg_tx->buffer)) {
			/* We're sending a response */

			/**********************************/
			/*       Error checking           */
			/**********************************/

			/* See if we've already tried sending this message 3 times */
			if (current_msg_tx->retries > IPMB_MAX_RETRIES) {
				/* Free the message buffer */
				printf("IPMB IF %x write reach MAX retry\n",
				       current_msg_tx->buffer.InF_source);
				if (current_msg_tx != NULL) {
					free(current_msg_tx);
				}
				continue;
			}
			/**********************************/
			/*     Try sending the message    */
			/**********************************/
			/* Fix IPMB target address */
			current_msg_tx->buffer.dest_addr = ipmb_cfg.target_addr;
			/* Encode the message buffer to the IPMB format */
			ipmb_encode(&ipmb_buffer_tx[0], &current_msg_tx->buffer);
			uint8_t resp_tx_size =
				current_msg_tx->buffer.data_len + IPMB_RESP_HEADER_LENGTH;

			if (ipmb_cfg.Inf == I2C_IF) {
				msg = malloc(sizeof(I2C_MSG));
				if (msg == NULL) { // allocate fail, retry allocate
					k_msleep(10);
					msg = malloc(sizeof(I2C_MSG));
					if (msg == NULL) {
						printk("IPMB_TXTask: Fail to malloc for i2c resp msg\n");
						if (current_msg_tx != NULL) {
							free(current_msg_tx);
						}
						continue;
					}
				}
				msg->bus = ipmb_cfg.bus;
				msg->slave_addr = ipmb_cfg.target_addr;
				msg->tx_len = resp_tx_size;
				memcpy(&msg->data[0], &ipmb_buffer_tx[1], resp_tx_size);
				status = i2c_master_write(msg, retry);

				if (msg != NULL) {
					free(msg);
				}
			} else { // TODO: else if (ipmb_cfg.Inf == I3C_IF)
				printf("IPMB %d using not support interface: %x\n", ipmb_cfg.index,
				       ipmb_cfg.Inf);
				if (current_msg_tx != NULL) {
					free(current_msg_tx);
				}
				continue;
			}

			if (status) {
				/* Message couldn't be transmitted right now, increase retry counter and try again later */
				current_msg_tx->retries++;
				k_msgq_put(&ipmb_txqueue[ipmb_cfg.index], current_msg_tx,
					   K_NO_WAIT);
				k_msleep(IPMB_RETRY_DELAY_ms);
			} else {
				/* Success case*/
				/* Free the message buffer */
				if (DEBUG_IPMI) {
					printf("ipmb_txqueue[%x] resp netfn: %x, cmd: %x, CC: %x, target_addr: %x\n",
					       ipmb_cfg.index, current_msg_tx->buffer.netfn,
					       current_msg_tx->buffer.cmd,
					       current_msg_tx->buffer.completion_code,
					       ipmb_cfg.target_addr);
					for (int i = 0; i < resp_tx_size + 1; i++) {
						printf(" %x", ipmb_buffer_tx[i]);
					}
					printf("\n");
				}
			}

		} else {
			/***************************************/
			/* Sending new outgoing request        */
			/***************************************/
			ipmb_encode(&ipmb_buffer_tx[0], &current_msg_tx->buffer);

			uint8_t req_tx_size =
				current_msg_tx->buffer.data_len + IPMB_REQ_HEADER_LENGTH;
			if (DEBUG_IPMI) {
				uint8_t i;
				printf("Tx send req: ");
				for (i = 0; i < req_tx_size + 1; i++) {
					printf(" %x", ipmb_buffer_tx[i]);
				}
				printf("\n");
			}

			if (ipmb_cfg.Inf == I2C_IF) {
				msg = malloc(sizeof(I2C_MSG));
				if (msg == NULL) { // allocate fail, retry allocate
					k_msleep(10);
					msg = malloc(sizeof(I2C_MSG));
					if (msg == NULL) {
						printk("IPMB_TXTask: Fail to malloc for i2c req msg\n");
						if (current_msg_tx != NULL) {
							free(current_msg_tx);
						}
						continue;
					}
				}
				msg->bus = ipmb_cfg.bus;
				msg->slave_addr = ipmb_cfg.target_addr;
				msg->tx_len = req_tx_size;
				memcpy(&msg->data[0], &ipmb_buffer_tx[1], req_tx_size);

				status = i2c_master_write(msg, retry);
				if (msg != NULL) {
					free(msg);
				}
			} else { // TODO: else if (ipmb_cfg.Inf == I3C_IF)
				printf("IPMB %d using not support interface: %x\n", ipmb_cfg.index,
				       ipmb_cfg.Inf);
				if (current_msg_tx != NULL) {
					free(current_msg_tx);
				}
				continue;
			}

			if (status) {
				current_msg_tx->retries += 1;

				if (current_msg_tx->retries > IPMB_MAX_RETRIES) {
					/* Return fail status to request source */
					if (current_msg_tx->buffer.InF_source == Reserve_IFs) {
						printf("IPMB_TXTask: Bridging msg from reserve IFs\n");
					} else if (current_msg_tx->buffer.InF_source == Self_IFs) {
						printf("IPMB_TXTask: BIC sending command fail\n"); // Rain - Should record or notice command fail
#ifdef CONFIG_IPMI_KCS_ASPEED
					} else if (current_msg_tx->buffer.InF_source ==
						   HOST_KCS_IFs) {
						uint8_t *kcs_buff;
						kcs_buff = malloc(KCS_buff_size * sizeof(uint8_t));
						if (kcs_buff ==
						    NULL) { // allocate fail, retry allocate
							k_msleep(10);
							kcs_buff = malloc(KCS_buff_size *
									  sizeof(uint8_t));
							if (kcs_buff == NULL) {
								printk("IPMB_TXTask: Fail to malloc for kcs_buff\n");
								free(current_msg_tx);
								continue;
							}
						}
						current_msg_tx->buffer.completion_code =
							CC_CAN_NOT_RESPOND;
						kcs_buff[0] = current_msg_tx->buffer.netfn << 2;
						kcs_buff[1] = current_msg_tx->buffer.cmd;
						kcs_buff[2] =
							current_msg_tx->buffer.completion_code;
						if (current_msg_tx->buffer.data_len > 0) {
							memcpy(&kcs_buff[3],
							       &current_msg_tx->buffer.data[0],
							       current_msg_tx->buffer.data_len);
						}

						kcs_write(kcs_buff,
							  current_msg_tx->buffer.data_len +
								  3); // data len + netfn + cmd + cc
						if (kcs_buff != NULL) {
							free(kcs_buff);
						}
#endif
					} else {
						ipmb_error status;
						current_msg_tx->buffer.data_len = 0;
						current_msg_tx->buffer.netfn = NETFN_OEM_1S_REQ;
						current_msg_tx->buffer.cmd = CMD_OEM_1S_MSG_OUT;
						current_msg_tx->buffer.completion_code =
							CC_NODE_BUSY;
						status = ipmb_send_response(
							&current_msg_tx->buffer,
							IPMB_inf_index_map[current_msg_tx->buffer
										   .InF_source]);

						if (status != ipmb_error_success) {
							printf("IPMB_TXTask: Send IPMB req fail status: %x",
							       status);
						}
					}

					/* Free the message buffer */
					printf("IPMB send fail after retry %d times, source: %x, cmd: 0x%x 0x%x\n",
					       current_msg_tx->retries,
					       current_msg_tx->buffer.InF_source,
					       current_msg_tx->buffer.netfn,
					       current_msg_tx->buffer.cmd);
				} else {
					k_msgq_put(&ipmb_txqueue[ipmb_cfg.index], current_msg_tx,
						   K_NO_WAIT);
					k_msleep(IPMB_RETRY_DELAY_ms);
				}

			} else {
				/* Request was successfully sent, keep a copy here for future comparison and clean the last used buffer */
				// void insert_node(ipmi_msg_cfg *pnode, ipmi_msg *msg)
				current_msg_tx->buffer.seq_target = current_msg_tx->buffer.seq;
				insert_node(P_start[ipmb_cfg.index], &current_msg_tx->buffer,
					    ipmb_cfg.index);
				if (DEBUG_IPMI) {
					printf("Insert node[%x] seq_s: %x, seq_t: %x\n",
					       ipmb_cfg.Inf_source,
					       current_msg_tx->buffer.seq_source,
					       current_msg_tx->buffer.seq_target);
				}
			}
		}
		if (current_msg_tx != NULL) {
			free(current_msg_tx);
		}

		k_msleep(10);
	}
}