From mboxrd@z Thu Jan 1 00:00:00 1970 From: Corey Minyard Date: Thu, 17 Mar 2022 08:13:56 -0500 Subject: [PATCH v6 1/4] ipmi: ssif_bmc: Add SSIF BMC driver In-Reply-To: <569f50d5-8f13-280e-b944-6e26d95dc50b@os.amperecomputing.com> References: <20220310114119.13736-1-quan@os.amperecomputing.com> <20220310114119.13736-2-quan@os.amperecomputing.com> <20220311011942.GX3457@minyard.net> <569f50d5-8f13-280e-b944-6e26d95dc50b@os.amperecomputing.com> Message-ID: <20220317131356.GC3457@minyard.net> List-Id: To: linux-aspeed@lists.ozlabs.org MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit snip... > > > + > > > +static void response_timeout(struct timer_list *t) > > > +{ > > > + struct ssif_bmc_ctx *ssif_bmc = from_timer(ssif_bmc, t, response_timer); > > > + unsigned long flags; > > > + > > > > Is there a possible race here? The timeout can happen at the same time > > as a received message, will something bad happen if that's the case? > > > > Thanks Corey, > I think I need extra comment here. > > The purpose of this timeout is to make sure ssif_bmc will recover from busy > state in case the upper stack does not provide the response. > Hence, the response timeout is set as 500ms, twice the time of max > Request-to-Response in spec as the code below. Should it be longer? That's not what I was asking. I know what the timer is for. But what happens if the response comes in at the same time this timer goes off? What will keep the data from getting messed up? > > As per spec, the max Request-to-Respose would not exceed 250ms. > > I put the comment in ssif_bmc.h as below: > >> +/* > >> + * IPMI 2.0 Spec, section 12.7 SSIF Timing, > >> + * Request-to-Response Time is T6max(250ms) - T1max(20ms) - 3ms = 227ms > >> + * Recover ssif_bmc from busy state if it takes upto 500ms > >> + */ > >> +#define RESPONSE_TIMEOUT 500 /* ms */ > > > > > + spin_lock_irqsave(&ssif_bmc->lock, flags); > > > + > > > + /* Recover ssif_bmc from busy */ > > > + ssif_bmc->busy = false; > > > + del_timer(&ssif_bmc->response_timer); > > > > You don't need to delete the timer, it's in the timeout. > > > > Will remove this redundant code in next version > > > > + ssif_bmc->response_timer_inited = false; > > > + > > > + spin_unlock_irqrestore(&ssif_bmc->lock, flags); > > > +} > > > + > > > +/* Called with ssif_bmc->lock held. */ > > > +static void handle_request(struct ssif_bmc_ctx *ssif_bmc) > > > +{ > > > + /* set ssif_bmc to busy waiting for response */ > > > + ssif_bmc->busy = true; > > > + > > > + /* Request message is available to process */ > > > + ssif_bmc->request_available = true; > > > + > > > + /* Clean old response buffer */ > > > + memset(&ssif_bmc->response, 0, sizeof(struct ssif_msg)); > > > + > > > + /* This is the new READ request.*/ > > > + wake_up_all(&ssif_bmc->wait_queue); > > > + > > > + /* Armed timer to recover slave from busy state in case of no response */ > > > + if (!ssif_bmc->response_timer_inited) { > > > + timer_setup(&ssif_bmc->response_timer, response_timeout, 0); > > > + ssif_bmc->response_timer_inited = true; > > > + } > > > + mod_timer(&ssif_bmc->response_timer, jiffies + msecs_to_jiffies(RESPONSE_TIMEOUT)); > > > +} > > > + > > > +static void set_multipart_response_buffer(struct ssif_bmc_ctx *ssif_bmc, u8 *val) > > > +{ > > > + u8 response_len = 0; > > > + int idx = 0; > > > + u8 data_len; > > > + > > > + data_len = ssif_bmc->response.len; > > > + switch (ssif_bmc->smbus_cmd) { > > > + case SSIF_IPMI_MULTIPART_READ_START: > > > + /* > > > + * Read Start length is 32 bytes. > > > + * Read Start transfer first 30 bytes of IPMI response > > > + * and 2 special code 0x00, 0x01. > > > + */ > > > + *val = MAX_PAYLOAD_PER_TRANSACTION; > > > + ssif_bmc->remain_len = data_len - MAX_IPMI_DATA_PER_START_TRANSACTION; > > > + ssif_bmc->block_num = 0; > > > > Do you need to validate the data length before using this? > > This applies for lots of places through here. > > > > set_multipart_response_buffer() is called only when ->is_singlepart_read is > false, which is determined by the below code under the *_write() > > ssif_bmc->is_singlepart_read = (ssif_msg_len(&msg) <= > MAX_PAYLOAD_PER_TRANSACTION + 1); > > So, I think the len is validated and could be use in this functions. Ah, I had things backwards. "Read" here is when you are writing to the other side. I understand now. > > > > + > > > + ssif_bmc->response_buf[idx++] = 0x00; /* Start Flag */ > > > + ssif_bmc->response_buf[idx++] = 0x01; /* Start Flag */ > > > + ssif_bmc->response_buf[idx++] = ssif_bmc->response.netfn_lun; > > > + ssif_bmc->response_buf[idx++] = ssif_bmc->response.cmd; > > > + ssif_bmc->response_buf[idx++] = ssif_bmc->response.payload[0]; > > > + > > > + response_len = MAX_PAYLOAD_PER_TRANSACTION - idx; > > > + > > > + memcpy(&ssif_bmc->response_buf[idx], &ssif_bmc->response.payload[1], > > > + response_len); > > > + break; > > > + > > > + case SSIF_IPMI_MULTIPART_READ_MIDDLE: > > > + /* > > > + * IPMI READ Middle or READ End messages can carry up to 31 bytes > > > + * IPMI data plus block number byte. > > > + */ > > > + if (ssif_bmc->remain_len < MAX_IPMI_DATA_PER_MIDDLE_TRANSACTION) { > > > + /* > > > + * This is READ End message > > > + * Return length is the remaining response data length > > > + * plus block number > > > + * Block number 0xFF is to indicate this is last message > > > + * > > > + */ > > > + *val = ssif_bmc->remain_len + 1; > > > + ssif_bmc->block_num = 0xFF; > > > + ssif_bmc->response_buf[idx++] = ssif_bmc->block_num; > > > + response_len = ssif_bmc->remain_len; > > > + /* Clean the buffer */ > > > + memset(&ssif_bmc->response_buf[idx], 0, MAX_PAYLOAD_PER_TRANSACTION - idx); > > > + } else { > > > + /* > > > + * This is READ Middle message > > > + * Response length is the maximum SMBUS transfer length > > > + * Block number byte is incremented > > > + * Return length is maximum SMBUS transfer length > > > + */ > > > + *val = MAX_PAYLOAD_PER_TRANSACTION; > > > + ssif_bmc->remain_len -= MAX_IPMI_DATA_PER_MIDDLE_TRANSACTION; > > > + response_len = MAX_IPMI_DATA_PER_MIDDLE_TRANSACTION; > > > + ssif_bmc->response_buf[idx++] = ssif_bmc->block_num; > > > + ssif_bmc->block_num++; > > > + } > > > + > > > + memcpy(&ssif_bmc->response_buf[idx], > > > + ssif_bmc->response.payload + 1 + ssif_bmc->nbytes_processed, > > > + response_len); > > > + break; > > > + > > > + default: > > > + /* Do not expect to go to this case */ > > > + dev_err(&ssif_bmc->client->dev, > > > + "%s: Unexpected SMBus command 0x%x\n", > > > + __func__, ssif_bmc->smbus_cmd); > > > + break; > > > + } > > > + > > > + ssif_bmc->nbytes_processed += response_len; > > > +} > > > + > > > +/* Process the IPMI response that will be read by master */ > > > +static void handle_read_processed(struct ssif_bmc_ctx *ssif_bmc, u8 *val) > > > +{ > > > + u8 *buf; > > > + u8 pec_len, addr, len; > > > + u8 pec = 0; > > > + > > > + pec_len = ssif_bmc->pec_support ? 1 : 0; > > > + /* PEC - Start Read Address */ > > > + addr = GET_8BIT_ADDR(ssif_bmc->client->addr); > > > + pec = i2c_smbus_pec(pec, &addr, 1); > > > + /* PEC - SSIF Command */ > > > + pec = i2c_smbus_pec(pec, &ssif_bmc->smbus_cmd, 1); > > > + /* PEC - Restart Write Address */ > > > + addr = addr | 0x01; > > > + pec = i2c_smbus_pec(pec, &addr, 1); > > > + > > > + if (ssif_bmc->is_singlepart_read) { > > > + /* Single-part Read processing */ > > > + buf = (u8 *)&ssif_bmc->response; > > > + > > > + if (ssif_bmc->response.len && ssif_bmc->msg_idx < ssif_bmc->response.len) { > > > + ssif_bmc->msg_idx++; > > > + *val = buf[ssif_bmc->msg_idx]; > > > + } else if (ssif_bmc->response.len && ssif_bmc->msg_idx == ssif_bmc->response.len) { > > > + ssif_bmc->msg_idx++; > > > + *val = i2c_smbus_pec(pec, buf, ssif_msg_len(&ssif_bmc->response)); > > > + } else { > > > > I thought for a second that this was wrong, but I think it's correct. > > Supply zero if you don't have data. > > > > > + *val = 0; > > > + } > > > + /* Invalidate response buffer to denote it is sent */ > > > + if (ssif_bmc->msg_idx + 1 >= (ssif_msg_len(&ssif_bmc->response) + pec_len)) > > > + complete_response(ssif_bmc); > > > + } else { > > > + /* Multi-part Read processing */ > > > > You don't check the length here like you did above. I think that's > > required. > > > > As per my explanation above, the ->is_singlepart_read is determined by > testing the length, so it is validated as I assumed. > > > > + switch (ssif_bmc->smbus_cmd) { > > > + case SSIF_IPMI_MULTIPART_READ_START: > > > + case SSIF_IPMI_MULTIPART_READ_MIDDLE: > > > + buf = (u8 *)&ssif_bmc->response_buf; > > > + *val = buf[ssif_bmc->msg_idx]; > > > + ssif_bmc->msg_idx++; > > > + break; > > > + default: > > > + /* Do not expect to go to this case */ > > > + dev_err(&ssif_bmc->client->dev, > > > + "%s: Unexpected SMBus command 0x%x\n", > > > + __func__, ssif_bmc->smbus_cmd); > > > + break; > > > + } > > > + > > > + len = (ssif_bmc->block_num == 0xFF) ? > > > + ssif_bmc->remain_len + 1 : MAX_PAYLOAD_PER_TRANSACTION; > > > + if (ssif_bmc->msg_idx == (len + 1)) { > > > + pec = i2c_smbus_pec(pec, &len, 1); > > > + *val = i2c_smbus_pec(pec, ssif_bmc->response_buf, len); > > > + } > > > + /* Invalidate response buffer to denote last response is sent */ > > > + if (ssif_bmc->block_num == 0xFF && > > > + ssif_bmc->msg_idx > (ssif_bmc->remain_len + pec_len)) { > > > + complete_response(ssif_bmc); > > > + } > > > + } > > > +} > > > + > > > +static void handle_write_received(struct ssif_bmc_ctx *ssif_bmc, u8 *val) > > > +{ > > > + u8 *buf = (u8 *)&ssif_bmc->request; > > > + > > > + if (ssif_bmc->msg_idx >= sizeof(struct ssif_msg)) > > > + return; I don't think this check is valid. I believe the msg_idx only covers the current message, but ssif_msg is a full multi-part message. It covers the single-part message, I think but not the multi-part ones. Also, abort the operation and log on bad data. > > > + > > > + switch (ssif_bmc->smbus_cmd) { > > > + case SSIF_IPMI_SINGLEPART_WRITE: > > > + buf[ssif_bmc->msg_idx - 1] = *val; > > > + ssif_bmc->msg_idx++; > > > + > > > + break; > > > + case SSIF_IPMI_MULTIPART_WRITE_START: > > > + if (ssif_bmc->msg_idx == 1) > > > + ssif_bmc->request.len = 0; > > > + > > > + fallthrough; > > > + case SSIF_IPMI_MULTIPART_WRITE_MIDDLE: > > > + /* The len should always be 32 */ > > > + if (ssif_bmc->msg_idx == 1 && *val != MAX_PAYLOAD_PER_TRANSACTION) > > > + dev_warn(&ssif_bmc->client->dev, > > > + "Warn: Invalid Multipart Write len"); You should abort the operation here. Don't deliver obviously bad data. Same in the code just below. This will require that you add a message aborted type of state to just ignore everything that comes in until the full sequence ends or a new message starts. > > > + > > > + fallthrough; > > > + case SSIF_IPMI_MULTIPART_WRITE_END: > > > + /* Multi-part write, 2nd byte received is length */ > > > + if (ssif_bmc->msg_idx == 1) { > > > + if (*val > MAX_PAYLOAD_PER_TRANSACTION) > > > + dev_warn(&ssif_bmc->client->dev, > > > + "Warn: Invalid Multipart Write End len"); > > > + > > > + ssif_bmc->request.len += *val; > > > + ssif_bmc->recv_len = *val; > > > + > > > + /* request len should never exceeded 255 bytes */ > > > + if (ssif_bmc->request.len > 255) > > > + dev_warn(&ssif_bmc->client->dev, > > > + "Warn: Invalid request len"); > > > + > > > + } else { > > > > You check msg_idx above, but I'm not sure that check will cover this > > operation. > > > That check is to make sure the length (*val) must always be strictly 32 > bytes in case of MULTIPART_WRITE_START/MIDDLE. And this check allows the > length is up to 32 bytes in MULTIPART_WRITE_END. Now that I have read and write straight, this is where the previous comments apply. You are trusting the the length sent by the remote end in the second byte is correct, but there is no guarantee of this. The remote end can send as many bytes as it likes. You need to check that you don't overflow buf here and that it actually sends the number of bytes that it said it was going to send to avoid underflow. > > > > + buf[ssif_bmc->msg_idx - 1 + > > > + ssif_bmc->request.len - ssif_bmc->recv_len] = *val; This computation is fairly complicated and hard to understand. Calculations like this are asking for trouble. It would be easier to understand had request.len be the current length of what is in request.payload and increment it on every incoming byte. Then request.len could be used to add data to the buffer, like if (ssif_bmc->request.len >= sizeof(ssif_bmc->payload)) error... ssif_bmc->payload[ssif_bmc->request.len++] = *val; If you renamed msg_idx to curr_recv_idx and recv_len to curr_recv_len, it would be more clear that these are related and operate on the current incoming message. It would also be nice to get rid of the casts from ssif_msg to a buffer array and just index directly into request.payload[]. In thinking about this further, I have a few more observations... There is no need to have the netfn and cmd in ssif_msg. They are just the first and second bytes of the message. You don't care what they are in this code. Why do you deliver the length as part of the message to the user? The length is returned by the system call. You have all these +1 and -1 things around the message length, which is error-prone. Removing the length from the message would get rid of all of that. And using packed structures is generally not the best, anyway. The PEC calculations remove one byte from the maximum message length. Since they are not included in the length byte, it's kind of unnatural to do this the way you are doing it. Instead, it might be best to say if you receive a byte and curr_recv_idx == curr_recv_len, process it as PEC. That way the PEC never hits the buffer. There is no need for msg_idx, or cur_recv_idx, to be size_t. I need to look at this some more, but I'll need to see the rewrite. -corey > > > + } > > > + > > > + ssif_bmc->msg_idx++; > > > + > > > + break; > > > + default: > > > + /* Do not expect to go to this case */ > > > + dev_err(&ssif_bmc->client->dev, > > > + "%s: Unexpected SMBus command 0x%x\n", > > > + __func__, ssif_bmc->smbus_cmd); > > > + break; > > > + } > > > +} > > > + > > > +static bool validate_request(struct ssif_bmc_ctx *ssif_bmc) > > > +{ > > > + u8 rpec = 0, cpec = 0; > > > + bool ret = true; > > > + u8 addr, index; > > > + u8 *buf; > > > + > > > > Is there any length validation for using buf below? It looks like you > > are accessing without checking length, but maybe I missed something. > > > > Yes, there is length testing for each part before using buf to calculate PEC > as in the "if" below. > > > > + buf = (u8 *)&ssif_bmc->request; > > > + switch (ssif_bmc->smbus_cmd) { > > > + case SSIF_IPMI_SINGLEPART_WRITE: > > > + if ((ssif_bmc->msg_idx - 1) == ssif_msg_len(&ssif_bmc->request)) { > > > + /* PEC is not included */ > > > + ssif_bmc->pec_support = false; > > > + ret = true; > > > + goto exit; > > > + } > > > + > > > + if ((ssif_bmc->msg_idx - 1) != (ssif_msg_len(&ssif_bmc->request) + 1)) { > > > + dev_err(&ssif_bmc->client->dev, "Error: Unexpected length received %d\n", > > > + ssif_msg_len(&ssif_bmc->request)); > > > + ret = false; > > > + goto exit; > > > + } > > > + > > > + /* PEC is included */ > > > + ssif_bmc->pec_support = true; > > > + rpec = buf[ssif_bmc->msg_idx - 2]; > > > + addr = GET_8BIT_ADDR(ssif_bmc->client->addr); > > > + cpec = i2c_smbus_pec(cpec, &addr, 1); > > > + cpec = i2c_smbus_pec(cpec, &ssif_bmc->smbus_cmd, 1); > > > + cpec = i2c_smbus_pec(cpec, buf, ssif_msg_len(&ssif_bmc->request)); > > > + if (rpec != cpec) { > > > + dev_err(&ssif_bmc->client->dev, "Bad PEC 0x%02x vs. 0x%02x\n", rpec, cpec); > > > + ret = false; > > > + } > > > + > > > + break; > > > + case SSIF_IPMI_MULTIPART_WRITE_START: > > > + case SSIF_IPMI_MULTIPART_WRITE_MIDDLE: > > > + case SSIF_IPMI_MULTIPART_WRITE_END: > > > + index = ssif_bmc->request.len - ssif_bmc->recv_len; > > > + if ((ssif_bmc->msg_idx - 1 + index) == ssif_msg_len(&ssif_bmc->request)) { > > > + /* PEC is not included */ > > > + ssif_bmc->pec_support = false; > > > + ret = true; > > > + goto exit; > > > + } > > > + > > > + if ((ssif_bmc->msg_idx - 1 + index) != (ssif_msg_len(&ssif_bmc->request) + 1)) { > > > + dev_err(&ssif_bmc->client->dev, "Error: Unexpected length received %d\n", > > > + ssif_msg_len(&ssif_bmc->request)); > > > + ret = false; > > > + goto exit; > > > + } > > > + > > > + /* PEC is included */ > > > + ssif_bmc->pec_support = true; > > > + rpec = buf[ssif_bmc->msg_idx - 2 + index]; > > > + addr = GET_8BIT_ADDR(ssif_bmc->client->addr); > > > + cpec = i2c_smbus_pec(cpec, &addr, 1); > > > + cpec = i2c_smbus_pec(cpec, &ssif_bmc->smbus_cmd, 1); > > > + cpec = i2c_smbus_pec(cpec, &ssif_bmc->recv_len, 1); > > > > Just curious, I'm not sure the client side PEC in the Linux driver has > > ever been validated. Have you tested both sides? > > > > Yes, we found that request from host has an extra byte for PEC and that is > why we added PEC support. > > > > + /* As SMBus specification does not allow the length > > > + * (byte count) in the Write-Block protocol to be zero. > > > + * Therefore, it is illegal to have the last Middle > > > + * transaction in the sequence carry 32-byte and have > > > + * a length of ?0? in the End transaction. > > > + * But some users may try to use this way and we should > > > + * prevent ssif_bmc driver broken in this case. > > > + */ > > > + if (ssif_bmc->recv_len != 0) > > > + cpec = i2c_smbus_pec(cpec, buf + 1 + index, ssif_bmc->recv_len); > > > + > > > + if (rpec != cpec) { > > > + dev_err(&ssif_bmc->client->dev, "Bad PEC 0x%02x vs. 0x%02x\n", rpec, cpec); > > > + ret = false; > > > + } > > > + > > > + break; > > > + default: > > > + /* Do not expect to go to this case */ > > > + dev_err(&ssif_bmc->client->dev, "%s: Unexpected SMBus command 0x%x\n", > > > + __func__, ssif_bmc->smbus_cmd); > > > + ret = false; > > > + break; > > > + } > > > + > > > +exit: > > > + return ret; > > > +} > > > + > > > > Just a nit, more a general coding style comment. It's almost always a > > bad idea to put a negative (unsupported) into a check function. You > > often end up with something like: > > > > if (!unsupported_smbus_cmd(c)).... > > > > which looks a little strange. Double negatives can make it hard to > > follow and lead to mistakes. This one isn't too bad, but sometimes it > > can be. It's better to do: > > > > if (supported_smbus_cmd(c)).... > > or > > if (!supported_smbus_cmd(c)).... > > > > > > Thanks, Corey. I'll try to refactor this part in next version. > > > > +static bool unsupported_smbus_cmd(u8 cmd) > > > +{ > > > + if (cmd == SSIF_IPMI_SINGLEPART_READ || > > > + cmd == SSIF_IPMI_SINGLEPART_WRITE || > > > + cmd == SSIF_IPMI_MULTIPART_WRITE_START || > > > + cmd == SSIF_IPMI_MULTIPART_WRITE_MIDDLE || > > > + cmd == SSIF_IPMI_MULTIPART_WRITE_END || > > > + cmd == SSIF_IPMI_MULTIPART_READ_START || > > > + cmd == SSIF_IPMI_MULTIPART_READ_MIDDLE) > > > + return false; > > > + > > > + return true; > > > +} > > > + > > > +static void process_smbus_cmd(struct ssif_bmc_ctx *ssif_bmc, u8 *val) > > > +{ > > > + /* SMBUS command can vary (single or multi-part) */ > > > + ssif_bmc->smbus_cmd = *val; > > > + ssif_bmc->msg_idx++; > > > + > > > + if (unsupported_smbus_cmd(*val)) > > > + dev_warn(&ssif_bmc->client->dev, "Warn: Unknown SMBus command"); > > > + > > > + if (*val == SSIF_IPMI_SINGLEPART_WRITE || > > > + *val == SSIF_IPMI_MULTIPART_WRITE_START) { > > > + /* > > > + * The response maybe not come in-time, causing host SSIF driver > > > + * to timeout and resend a new request. In such case check for > > > + * pending response and clear it > > > + */ > > > + if (ssif_bmc->response_in_progress) > > > + complete_response(ssif_bmc); > > > + } > > > +} > > > + > > > +static void on_read_requested_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) > > > +{ > > > + if (ssif_bmc->state == SSIF_READY || > > > + ssif_bmc->state == SSIF_START || > > > + ssif_bmc->state == SSIF_REQ_RECVING || > > > + ssif_bmc->state == SSIF_RES_SENDING) { > > > + ssif_bmc->state = SSIF_BAD_SMBUS; > > > + dev_warn(&ssif_bmc->client->dev, > > > + "Warn: %s unexpected READ REQUESTED in state=%s\n", > > > + __func__, state_to_string(ssif_bmc->state)); > > > + > > > + } else if (ssif_bmc->state == SSIF_SMBUS_CMD) { > > > + ssif_bmc->state = SSIF_RES_SENDING; > > > + } > > > + > > > + ssif_bmc->msg_idx = 0; > > > + if (ssif_bmc->is_singlepart_read) > > > + *val = ssif_bmc->response.len; > > > + else > > > + set_multipart_response_buffer(ssif_bmc, val); > > > +} > > > + > > > +static void on_read_processed_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) > > > +{ > > > + if (ssif_bmc->state == SSIF_READY || > > > + ssif_bmc->state == SSIF_START || > > > + ssif_bmc->state == SSIF_REQ_RECVING || > > > + ssif_bmc->state == SSIF_SMBUS_CMD) { > > > + dev_warn(&ssif_bmc->client->dev, > > > + "Warn: %s unexpected READ PROCESSED in state=%s\n", > > > + __func__, state_to_string(ssif_bmc->state)); > > > + ssif_bmc->state = SSIF_BAD_SMBUS; > > > + } > > > + > > > + handle_read_processed(ssif_bmc, val); > > > +} > > > + > > > +static void on_write_requested_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) > > > +{ > > > + ssif_bmc->msg_idx = 0; > > > + > > > + if (ssif_bmc->state == SSIF_READY || ssif_bmc->state == SSIF_SMBUS_CMD) { > > > + ssif_bmc->state = SSIF_START; > > > + > > > + } else if (ssif_bmc->state == SSIF_START || > > > + ssif_bmc->state == SSIF_REQ_RECVING || > > > + ssif_bmc->state == SSIF_RES_SENDING) { > > > + dev_warn(&ssif_bmc->client->dev, > > > + "Warn: %s unexpected WRITE REQUEST in state=%s\n", > > > + __func__, state_to_string(ssif_bmc->state)); > > > + ssif_bmc->state = SSIF_BAD_SMBUS; > > > + } > > > +} > > > + > > > +static void on_write_received_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) > > > +{ > > > + if (ssif_bmc->state == SSIF_READY || ssif_bmc->state == SSIF_RES_SENDING) { > > > + dev_warn(&ssif_bmc->client->dev, > > > + "Warn: %s unexpected WRITE RECEIVED in state=%s\n", > > > + __func__, state_to_string(ssif_bmc->state)); > > > + ssif_bmc->state = SSIF_BAD_SMBUS; > > > + } else if (ssif_bmc->state == SSIF_START) { > > > + ssif_bmc->state = SSIF_SMBUS_CMD; > > > + } else if (ssif_bmc->state == SSIF_SMBUS_CMD) { > > > + ssif_bmc->state = SSIF_REQ_RECVING; > > > + } > > > + > > > + /* This is response sending state */ > > > + if (ssif_bmc->state == SSIF_REQ_RECVING) > > > + handle_write_received(ssif_bmc, val); > > > + else if (ssif_bmc->state == SSIF_SMBUS_CMD) > > > + process_smbus_cmd(ssif_bmc, val); > > > +} > > > + > > > +static void on_stop_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) > > > +{ > > > + if (ssif_bmc->state == SSIF_READY || > > > + ssif_bmc->state == SSIF_START || > > > + ssif_bmc->state == SSIF_SMBUS_CMD) { > > > + dev_warn(&ssif_bmc->client->dev, > > > + "Warn: %s unexpected SLAVE STOP in state=%s\n", > > > + __func__, state_to_string(ssif_bmc->state)); > > > + > > > + } else if (ssif_bmc->state == SSIF_BAD_SMBUS) { > > > + dev_warn(&ssif_bmc->client->dev, > > > + "Warn: %s received SLAVE STOP from bad state=%s\n", > > > + __func__, state_to_string(ssif_bmc->state)); > > > + > > > + } else if (ssif_bmc->state == SSIF_REQ_RECVING) { > > > + /* A BMC that receives an invalid request drop the data for the write > > > + * transaction and any further transactions (read or write) until > > > + * the next valid read or write Start transaction is received > > > + */ > > > + if (!validate_request(ssif_bmc)) > > > + dev_err(&ssif_bmc->client->dev, "Error: invalid pec\n"); > > > + else if (ssif_bmc->smbus_cmd == SSIF_IPMI_SINGLEPART_WRITE || > > > + ssif_bmc->smbus_cmd == SSIF_IPMI_MULTIPART_WRITE_END) > > > + handle_request(ssif_bmc); > > > + } > > > + > > > + ssif_bmc->state = SSIF_READY; > > > + /* Reset message index */ > > > + ssif_bmc->msg_idx = 0; > > > +} > > > + > > > +/* > > > + * Callback function to handle I2C slave events > > > + */ > > > +static int ssif_bmc_cb(struct i2c_client *client, enum i2c_slave_event event, u8 *val) > > > +{ > > > + unsigned long flags; > > > + struct ssif_bmc_ctx *ssif_bmc = i2c_get_clientdata(client); > > > + int ret = 0; > > > + > > > + spin_lock_irqsave(&ssif_bmc->lock, flags); > > > + > > > + switch (event) { > > > + case I2C_SLAVE_READ_REQUESTED: > > > + on_read_requested_event(ssif_bmc, val); > > > + break; > > > + > > > + case I2C_SLAVE_WRITE_REQUESTED: > > > + on_write_requested_event(ssif_bmc, val); > > > + break; > > > + > > > + case I2C_SLAVE_READ_PROCESSED: > > > + on_read_processed_event(ssif_bmc, val); > > > + break; > > > + > > > + case I2C_SLAVE_WRITE_RECEIVED: > > > + on_write_received_event(ssif_bmc, val); > > > + break; > > > + > > > + case I2C_SLAVE_STOP: > > > + on_stop_event(ssif_bmc, val); > > > + break; > > > + > > > + default: > > > + dev_warn(&ssif_bmc->client->dev, "Warn: Unknown i2c slave event\n"); > > > + break; > > > + } > > > + > > > + if (ssif_bmc->busy) > > > + ret = -EBUSY; > > > + > > > + spin_unlock_irqrestore(&ssif_bmc->lock, flags); > > > + > > > + return ret; > > > +} > > > + > > > +static int ssif_bmc_probe(struct i2c_client *client, const struct i2c_device_id *id) > > > +{ > > > + struct ssif_bmc_ctx *ssif_bmc; > > > + int ret; > > > + > > > + ssif_bmc = devm_kzalloc(&client->dev, sizeof(*ssif_bmc), GFP_KERNEL); > > > + if (!ssif_bmc) > > > + return -ENOMEM; > > > + > > > + spin_lock_init(&ssif_bmc->lock); > > > + > > > + init_waitqueue_head(&ssif_bmc->wait_queue); > > > + ssif_bmc->request_available = false; > > > + ssif_bmc->response_in_progress = false; > > > + ssif_bmc->busy = false; > > > + ssif_bmc->response_timer_inited = false; > > > + > > > + /* Register misc device interface */ > > > + ssif_bmc->miscdev.minor = MISC_DYNAMIC_MINOR; > > > + ssif_bmc->miscdev.name = DEVICE_NAME; > > > + ssif_bmc->miscdev.fops = &ssif_bmc_fops; > > > + ssif_bmc->miscdev.parent = &client->dev; > > > + ret = misc_register(&ssif_bmc->miscdev); > > > + if (ret) > > > + goto out; > > > + > > > + ssif_bmc->client = client; > > > + ssif_bmc->client->flags |= I2C_CLIENT_SLAVE; > > > + > > > + /* Register I2C slave */ > > > + i2c_set_clientdata(client, ssif_bmc); > > > + ret = i2c_slave_register(client, ssif_bmc_cb); > > > + if (ret) { > > > + misc_deregister(&ssif_bmc->miscdev); > > > + goto out; > > > + } > > > + > > > + return 0; > > > +out: > > > + devm_kfree(&client->dev, ssif_bmc); > > > + return ret; > > > +} > > > + > > > +static int ssif_bmc_remove(struct i2c_client *client) > > > +{ > > > + struct ssif_bmc_ctx *ssif_bmc = i2c_get_clientdata(client); > > > + > > > + i2c_slave_unregister(client); > > > + misc_deregister(&ssif_bmc->miscdev); > > > + > > > + return 0; > > > +} > > > + > > > +static const struct of_device_id ssif_bmc_match[] = { > > > + { .compatible = "ampere,ssif-bmc" }, > > > + { }, > > > +}; > > > + > > > +static const struct i2c_device_id ssif_bmc_id[] = { > > > + { DEVICE_NAME, 0 }, > > > + { }, > > > +}; > > > + > > > +MODULE_DEVICE_TABLE(i2c, ssif_bmc_id); > > > + > > > +static struct i2c_driver ssif_bmc_driver = { > > > + .driver = { > > > + .name = DEVICE_NAME, > > > + .of_match_table = ssif_bmc_match, > > > + }, > > > + .probe = ssif_bmc_probe, > > > + .remove = ssif_bmc_remove, > > > + .id_table = ssif_bmc_id, > > > +}; > > > + > > > +module_i2c_driver(ssif_bmc_driver); > > > + > > > +MODULE_AUTHOR("Quan Nguyen "); > > > +MODULE_AUTHOR("Chuong Tran "); > > > +MODULE_DESCRIPTION("Linux device driver of the BMC IPMI SSIF interface."); > > > +MODULE_LICENSE("GPL"); > > > diff --git a/drivers/char/ipmi/ssif_bmc.h b/drivers/char/ipmi/ssif_bmc.h > > > new file mode 100644 > > > index 000000000000..9a26f3c252cc > > > --- /dev/null > > > +++ b/drivers/char/ipmi/ssif_bmc.h > > > @@ -0,0 +1,102 @@ > > > +/* SPDX-License-Identifier: GPL-2.0+ */ > > > +/* > > > + * The driver for BMC side of SSIF interface > > > + * > > > + * Copyright (c) 2022, Ampere Computing LLC > > > + * > > > + */ > > > +#ifndef __SSIF_BMC_H__ > > > +#define __SSIF_BMC_H__ > > > + > > > +#define DEVICE_NAME "ipmi-ssif-host" > > > + > > > +#define GET_8BIT_ADDR(addr_7bit) (((addr_7bit) << 1) & 0xff) > > > + > > > +/* A standard SMBus Transaction is limited to 32 data bytes */ > > > +#define MAX_PAYLOAD_PER_TRANSACTION 32 > > > + > > > +#define MAX_IPMI_DATA_PER_START_TRANSACTION 30 > > > +#define MAX_IPMI_DATA_PER_MIDDLE_TRANSACTION 31 > > > + > > > +#define SSIF_IPMI_SINGLEPART_WRITE 0x2 > > > +#define SSIF_IPMI_SINGLEPART_READ 0x3 > > > +#define SSIF_IPMI_MULTIPART_WRITE_START 0x6 > > > +#define SSIF_IPMI_MULTIPART_WRITE_MIDDLE 0x7 > > > +#define SSIF_IPMI_MULTIPART_WRITE_END 0x8 > > > +#define SSIF_IPMI_MULTIPART_READ_START 0x3 > > > +#define SSIF_IPMI_MULTIPART_READ_MIDDLE 0x9 > > > + > > > +#define MSG_PAYLOAD_LEN_MAX 252 > > > +/* > > > + * IPMI 2.0 Spec, section 12.7 SSIF Timing, > > > + * Request-to-Response Time is T6max(250ms) - T1max(20ms) - 3ms = 227ms > > > + * Recover ssif_bmc from busy state if it takes upto 500ms > > > + */ > > > +#define RESPONSE_TIMEOUT 500 /* ms */ > > > + > > > +struct ssif_msg { > > > + u8 len; > > > + u8 netfn_lun; > > > + u8 cmd; > > > + u8 payload[MSG_PAYLOAD_LEN_MAX]; > > > +} __packed; > > > + > > > +static inline u32 ssif_msg_len(struct ssif_msg *ssif_msg) > > > +{ > > > + return ssif_msg->len + 1; > > > +} > > > + > > > +/* > > > + * SSIF internal states: > > > + * SSIF_READY 0x00 : Ready state > > > + * SSIF_START 0x01 : Start smbus transaction > > > + * SSIF_SMBUS_CMD 0x02 : Received SMBus command > > > + * SSIF_REQ_RECVING 0x03 : Receiving request > > > + * SSIF_RES_SENDING 0x04 : Sending response > > > + * SSIF_BAD_SMBUS 0x05 : Bad SMbus transaction > > > + */ > > > +enum ssif_state { > > > + SSIF_READY, > > > + SSIF_START, > > > + SSIF_SMBUS_CMD, > > > + SSIF_REQ_RECVING, > > > + SSIF_RES_SENDING, > > > + SSIF_BAD_SMBUS, > > > + SSIF_STATE_MAX > > > +}; > > > + > > > +struct ssif_bmc_ctx { > > > + struct i2c_client *client; > > > + struct miscdevice miscdev; > > > + size_t msg_idx; > > > + bool pec_support; > > > + /* ssif bmc spinlock */ > > > + spinlock_t lock; > > > + wait_queue_head_t wait_queue; > > > + u8 running; > > > + enum ssif_state state; > > > + u8 smbus_cmd; > > > + /* Timeout waiting for response */ > > > + struct timer_list response_timer; > > > + bool response_timer_inited; > > > + /* Flag to identify a Multi-part Read Transaction */ > > > + bool is_singlepart_read; > > > + u8 nbytes_processed; > > > + u8 remain_len; > > > + u8 recv_len; > > > + /* Block Number of a Multi-part Read Transaction */ > > > + u8 block_num; > > > + bool request_available; > > > + bool response_in_progress; > > > + bool busy; > > > + /* Response buffer for Multi-part Read Transaction */ > > > + u8 response_buf[MAX_PAYLOAD_PER_TRANSACTION]; > > > + struct ssif_msg response; > > > + struct ssif_msg request; > > > +}; > > > + > > > +static inline struct ssif_bmc_ctx *to_ssif_bmc(struct file *file) > > > +{ > > > + return container_of(file->private_data, struct ssif_bmc_ctx, miscdev); > > > +} > > > +#endif /* __SSIF_BMC_H__ */ > > > -- > > > 2.35.1 > > > > > > From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 962B2C433FE for ; Thu, 17 Mar 2022 13:14:11 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233738AbiCQNPY (ORCPT ); Thu, 17 Mar 2022 09:15:24 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:36932 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231713AbiCQNPY (ORCPT ); Thu, 17 Mar 2022 09:15:24 -0400 Received: from mail-qk1-x730.google.com (mail-qk1-x730.google.com [IPv6:2607:f8b0:4864:20::730]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2FE4E12F174; Thu, 17 Mar 2022 06:14:06 -0700 (PDT) Received: by mail-qk1-x730.google.com with SMTP id g8so4278058qke.2; Thu, 17 Mar 2022 06:14:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=sender:date:from:to:cc:subject:message-id:reply-to:references :mime-version:content-disposition:content-transfer-encoding :in-reply-to; bh=eWle4zbRf1n3H9JH+hlY46qvlaTRjOJL9WeucImHHOg=; b=nQ9VUi9sYyhAlmOegG+gL9U+A+k4L0h3YbQdoECtJViy3ucmZmKvZbk1M0lo+zElvW P9QSK1XhNmYuYVYGUa4pn2HOk/+sPmEIyA8nJj1ORGBwTzypv/YjSfxjqBBv6jn1eNeG 89VNacmyZlqb1Uypy/SZJdjFDbtbS6s0lYo93muJrNmZ3/2jvRBimBDe0cievdvHo+Z8 3xD6agc2lgghKoxsnMGk5BQTXecQgdNI+v1T7rxp+u0WV0oQrU5/puPU1EwhqTDoG1So Tb1r1r0sN/GtE8Oz4B01M5OFORYzkn6/F7euKMNyobLT1mwrOVYUzoP29R3AHyy5Qqa+ 2pKw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:sender:date:from:to:cc:subject:message-id :reply-to:references:mime-version:content-disposition :content-transfer-encoding:in-reply-to; bh=eWle4zbRf1n3H9JH+hlY46qvlaTRjOJL9WeucImHHOg=; b=cegaNeIe8HYH/+OwPhqAZhHBkOscUUbSduR5pfLOdgCBnwLd+9DHmEBjtMDDgQNtNF fkFTOcgqNd49cX72yr3OsPEd3DJAluNI2Om7vWsBEpNXmuu5d1GzJiR9JBdkUwVCm6jj bEQs/OmiqaxLrwOKgHJJIX3dAwirWqtWqH5F6MhstVWW1VgUKNGcEM2+AHr0EigTh5Rs iWNlllxk/c7qFJ+ugdxUGWR9/Eyk8BizVzhHlt8INqZJbvxpJE2KIaykkUbird5LcKXM RsLSTxtFMUZrYjrwG3Wh4yhOefd/Fe47lchlTtgm+J8ooPkdhNXp6+ME/jqmGfmlOGg7 O03w== X-Gm-Message-State: AOAM530myNUzFXgXhKqrIVPygAYa0PHCIC7PIl51WiSxXKNt87XGCr+N lO+1bWs6GK2ePM7SjHUesQ== X-Google-Smtp-Source: ABdhPJyjMKdRe3h0gF9p5mD85cMhaUnlFewNeqxPQzyz5DcwwNrVVLR63pDXDdHBePDcGgad/48sdA== X-Received: by 2002:a05:620a:271d:b0:67d:bb5f:8a7d with SMTP id b29-20020a05620a271d00b0067dbb5f8a7dmr2684691qkp.154.1647522844635; Thu, 17 Mar 2022 06:14:04 -0700 (PDT) Received: from serve.minyard.net (serve.minyard.net. [2001:470:b8f6:1b::1]) by smtp.gmail.com with ESMTPSA id j67-20020a37b946000000b0067b221281dbsm2445827qkf.99.2022.03.17.06.13.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 17 Mar 2022 06:13:59 -0700 (PDT) Sender: Corey Minyard Received: from minyard.net (unknown [IPv6:2001:470:b8f6:1b:797c:2e79:7998:93c9]) by serve.minyard.net (Postfix) with ESMTPSA id 43EEA180004; Thu, 17 Mar 2022 13:13:57 +0000 (UTC) Date: Thu, 17 Mar 2022 08:13:56 -0500 From: Corey Minyard To: Quan Nguyen Cc: Rob Herring , Krzysztof Kozlowski , Joel Stanley , Andrew Jeffery , Brendan Higgins , Benjamin Herrenschmidt , Wolfram Sang , openipmi-developer@lists.sourceforge.net, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-aspeed@lists.ozlabs.org, linux-kernel@vger.kernel.org, linux-i2c@vger.kernel.org, openbmc@lists.ozlabs.org, Open Source Submission , Phong Vo , "Thang Q . Nguyen" Subject: Re: [PATCH v6 1/4] ipmi: ssif_bmc: Add SSIF BMC driver Message-ID: <20220317131356.GC3457@minyard.net> Reply-To: minyard@acm.org References: <20220310114119.13736-1-quan@os.amperecomputing.com> <20220310114119.13736-2-quan@os.amperecomputing.com> <20220311011942.GX3457@minyard.net> <569f50d5-8f13-280e-b944-6e26d95dc50b@os.amperecomputing.com> MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Disposition: inline Content-Transfer-Encoding: 8bit In-Reply-To: <569f50d5-8f13-280e-b944-6e26d95dc50b@os.amperecomputing.com> Precedence: bulk List-ID: X-Mailing-List: linux-i2c@vger.kernel.org snip... > > > + > > > +static void response_timeout(struct timer_list *t) > > > +{ > > > + struct ssif_bmc_ctx *ssif_bmc = from_timer(ssif_bmc, t, response_timer); > > > + unsigned long flags; > > > + > > > > Is there a possible race here? The timeout can happen at the same time > > as a received message, will something bad happen if that's the case? > > > > Thanks Corey, > I think I need extra comment here. > > The purpose of this timeout is to make sure ssif_bmc will recover from busy > state in case the upper stack does not provide the response. > Hence, the response timeout is set as 500ms, twice the time of max > Request-to-Response in spec as the code below. Should it be longer? That's not what I was asking. I know what the timer is for. But what happens if the response comes in at the same time this timer goes off? What will keep the data from getting messed up? > > As per spec, the max Request-to-Respose would not exceed 250ms. > > I put the comment in ssif_bmc.h as below: > >> +/* > >> + * IPMI 2.0 Spec, section 12.7 SSIF Timing, > >> + * Request-to-Response Time is T6max(250ms) - T1max(20ms) - 3ms = 227ms > >> + * Recover ssif_bmc from busy state if it takes upto 500ms > >> + */ > >> +#define RESPONSE_TIMEOUT 500 /* ms */ > > > > > + spin_lock_irqsave(&ssif_bmc->lock, flags); > > > + > > > + /* Recover ssif_bmc from busy */ > > > + ssif_bmc->busy = false; > > > + del_timer(&ssif_bmc->response_timer); > > > > You don't need to delete the timer, it's in the timeout. > > > > Will remove this redundant code in next version > > > > + ssif_bmc->response_timer_inited = false; > > > + > > > + spin_unlock_irqrestore(&ssif_bmc->lock, flags); > > > +} > > > + > > > +/* Called with ssif_bmc->lock held. */ > > > +static void handle_request(struct ssif_bmc_ctx *ssif_bmc) > > > +{ > > > + /* set ssif_bmc to busy waiting for response */ > > > + ssif_bmc->busy = true; > > > + > > > + /* Request message is available to process */ > > > + ssif_bmc->request_available = true; > > > + > > > + /* Clean old response buffer */ > > > + memset(&ssif_bmc->response, 0, sizeof(struct ssif_msg)); > > > + > > > + /* This is the new READ request.*/ > > > + wake_up_all(&ssif_bmc->wait_queue); > > > + > > > + /* Armed timer to recover slave from busy state in case of no response */ > > > + if (!ssif_bmc->response_timer_inited) { > > > + timer_setup(&ssif_bmc->response_timer, response_timeout, 0); > > > + ssif_bmc->response_timer_inited = true; > > > + } > > > + mod_timer(&ssif_bmc->response_timer, jiffies + msecs_to_jiffies(RESPONSE_TIMEOUT)); > > > +} > > > + > > > +static void set_multipart_response_buffer(struct ssif_bmc_ctx *ssif_bmc, u8 *val) > > > +{ > > > + u8 response_len = 0; > > > + int idx = 0; > > > + u8 data_len; > > > + > > > + data_len = ssif_bmc->response.len; > > > + switch (ssif_bmc->smbus_cmd) { > > > + case SSIF_IPMI_MULTIPART_READ_START: > > > + /* > > > + * Read Start length is 32 bytes. > > > + * Read Start transfer first 30 bytes of IPMI response > > > + * and 2 special code 0x00, 0x01. > > > + */ > > > + *val = MAX_PAYLOAD_PER_TRANSACTION; > > > + ssif_bmc->remain_len = data_len - MAX_IPMI_DATA_PER_START_TRANSACTION; > > > + ssif_bmc->block_num = 0; > > > > Do you need to validate the data length before using this? > > This applies for lots of places through here. > > > > set_multipart_response_buffer() is called only when ->is_singlepart_read is > false, which is determined by the below code under the *_write() > > ssif_bmc->is_singlepart_read = (ssif_msg_len(&msg) <= > MAX_PAYLOAD_PER_TRANSACTION + 1); > > So, I think the len is validated and could be use in this functions. Ah, I had things backwards. "Read" here is when you are writing to the other side. I understand now. > > > > + > > > + ssif_bmc->response_buf[idx++] = 0x00; /* Start Flag */ > > > + ssif_bmc->response_buf[idx++] = 0x01; /* Start Flag */ > > > + ssif_bmc->response_buf[idx++] = ssif_bmc->response.netfn_lun; > > > + ssif_bmc->response_buf[idx++] = ssif_bmc->response.cmd; > > > + ssif_bmc->response_buf[idx++] = ssif_bmc->response.payload[0]; > > > + > > > + response_len = MAX_PAYLOAD_PER_TRANSACTION - idx; > > > + > > > + memcpy(&ssif_bmc->response_buf[idx], &ssif_bmc->response.payload[1], > > > + response_len); > > > + break; > > > + > > > + case SSIF_IPMI_MULTIPART_READ_MIDDLE: > > > + /* > > > + * IPMI READ Middle or READ End messages can carry up to 31 bytes > > > + * IPMI data plus block number byte. > > > + */ > > > + if (ssif_bmc->remain_len < MAX_IPMI_DATA_PER_MIDDLE_TRANSACTION) { > > > + /* > > > + * This is READ End message > > > + * Return length is the remaining response data length > > > + * plus block number > > > + * Block number 0xFF is to indicate this is last message > > > + * > > > + */ > > > + *val = ssif_bmc->remain_len + 1; > > > + ssif_bmc->block_num = 0xFF; > > > + ssif_bmc->response_buf[idx++] = ssif_bmc->block_num; > > > + response_len = ssif_bmc->remain_len; > > > + /* Clean the buffer */ > > > + memset(&ssif_bmc->response_buf[idx], 0, MAX_PAYLOAD_PER_TRANSACTION - idx); > > > + } else { > > > + /* > > > + * This is READ Middle message > > > + * Response length is the maximum SMBUS transfer length > > > + * Block number byte is incremented > > > + * Return length is maximum SMBUS transfer length > > > + */ > > > + *val = MAX_PAYLOAD_PER_TRANSACTION; > > > + ssif_bmc->remain_len -= MAX_IPMI_DATA_PER_MIDDLE_TRANSACTION; > > > + response_len = MAX_IPMI_DATA_PER_MIDDLE_TRANSACTION; > > > + ssif_bmc->response_buf[idx++] = ssif_bmc->block_num; > > > + ssif_bmc->block_num++; > > > + } > > > + > > > + memcpy(&ssif_bmc->response_buf[idx], > > > + ssif_bmc->response.payload + 1 + ssif_bmc->nbytes_processed, > > > + response_len); > > > + break; > > > + > > > + default: > > > + /* Do not expect to go to this case */ > > > + dev_err(&ssif_bmc->client->dev, > > > + "%s: Unexpected SMBus command 0x%x\n", > > > + __func__, ssif_bmc->smbus_cmd); > > > + break; > > > + } > > > + > > > + ssif_bmc->nbytes_processed += response_len; > > > +} > > > + > > > +/* Process the IPMI response that will be read by master */ > > > +static void handle_read_processed(struct ssif_bmc_ctx *ssif_bmc, u8 *val) > > > +{ > > > + u8 *buf; > > > + u8 pec_len, addr, len; > > > + u8 pec = 0; > > > + > > > + pec_len = ssif_bmc->pec_support ? 1 : 0; > > > + /* PEC - Start Read Address */ > > > + addr = GET_8BIT_ADDR(ssif_bmc->client->addr); > > > + pec = i2c_smbus_pec(pec, &addr, 1); > > > + /* PEC - SSIF Command */ > > > + pec = i2c_smbus_pec(pec, &ssif_bmc->smbus_cmd, 1); > > > + /* PEC - Restart Write Address */ > > > + addr = addr | 0x01; > > > + pec = i2c_smbus_pec(pec, &addr, 1); > > > + > > > + if (ssif_bmc->is_singlepart_read) { > > > + /* Single-part Read processing */ > > > + buf = (u8 *)&ssif_bmc->response; > > > + > > > + if (ssif_bmc->response.len && ssif_bmc->msg_idx < ssif_bmc->response.len) { > > > + ssif_bmc->msg_idx++; > > > + *val = buf[ssif_bmc->msg_idx]; > > > + } else if (ssif_bmc->response.len && ssif_bmc->msg_idx == ssif_bmc->response.len) { > > > + ssif_bmc->msg_idx++; > > > + *val = i2c_smbus_pec(pec, buf, ssif_msg_len(&ssif_bmc->response)); > > > + } else { > > > > I thought for a second that this was wrong, but I think it's correct. > > Supply zero if you don't have data. > > > > > + *val = 0; > > > + } > > > + /* Invalidate response buffer to denote it is sent */ > > > + if (ssif_bmc->msg_idx + 1 >= (ssif_msg_len(&ssif_bmc->response) + pec_len)) > > > + complete_response(ssif_bmc); > > > + } else { > > > + /* Multi-part Read processing */ > > > > You don't check the length here like you did above. I think that's > > required. > > > > As per my explanation above, the ->is_singlepart_read is determined by > testing the length, so it is validated as I assumed. > > > > + switch (ssif_bmc->smbus_cmd) { > > > + case SSIF_IPMI_MULTIPART_READ_START: > > > + case SSIF_IPMI_MULTIPART_READ_MIDDLE: > > > + buf = (u8 *)&ssif_bmc->response_buf; > > > + *val = buf[ssif_bmc->msg_idx]; > > > + ssif_bmc->msg_idx++; > > > + break; > > > + default: > > > + /* Do not expect to go to this case */ > > > + dev_err(&ssif_bmc->client->dev, > > > + "%s: Unexpected SMBus command 0x%x\n", > > > + __func__, ssif_bmc->smbus_cmd); > > > + break; > > > + } > > > + > > > + len = (ssif_bmc->block_num == 0xFF) ? > > > + ssif_bmc->remain_len + 1 : MAX_PAYLOAD_PER_TRANSACTION; > > > + if (ssif_bmc->msg_idx == (len + 1)) { > > > + pec = i2c_smbus_pec(pec, &len, 1); > > > + *val = i2c_smbus_pec(pec, ssif_bmc->response_buf, len); > > > + } > > > + /* Invalidate response buffer to denote last response is sent */ > > > + if (ssif_bmc->block_num == 0xFF && > > > + ssif_bmc->msg_idx > (ssif_bmc->remain_len + pec_len)) { > > > + complete_response(ssif_bmc); > > > + } > > > + } > > > +} > > > + > > > +static void handle_write_received(struct ssif_bmc_ctx *ssif_bmc, u8 *val) > > > +{ > > > + u8 *buf = (u8 *)&ssif_bmc->request; > > > + > > > + if (ssif_bmc->msg_idx >= sizeof(struct ssif_msg)) > > > + return; I don't think this check is valid. I believe the msg_idx only covers the current message, but ssif_msg is a full multi-part message. It covers the single-part message, I think but not the multi-part ones. Also, abort the operation and log on bad data. > > > + > > > + switch (ssif_bmc->smbus_cmd) { > > > + case SSIF_IPMI_SINGLEPART_WRITE: > > > + buf[ssif_bmc->msg_idx - 1] = *val; > > > + ssif_bmc->msg_idx++; > > > + > > > + break; > > > + case SSIF_IPMI_MULTIPART_WRITE_START: > > > + if (ssif_bmc->msg_idx == 1) > > > + ssif_bmc->request.len = 0; > > > + > > > + fallthrough; > > > + case SSIF_IPMI_MULTIPART_WRITE_MIDDLE: > > > + /* The len should always be 32 */ > > > + if (ssif_bmc->msg_idx == 1 && *val != MAX_PAYLOAD_PER_TRANSACTION) > > > + dev_warn(&ssif_bmc->client->dev, > > > + "Warn: Invalid Multipart Write len"); You should abort the operation here. Don't deliver obviously bad data. Same in the code just below. This will require that you add a message aborted type of state to just ignore everything that comes in until the full sequence ends or a new message starts. > > > + > > > + fallthrough; > > > + case SSIF_IPMI_MULTIPART_WRITE_END: > > > + /* Multi-part write, 2nd byte received is length */ > > > + if (ssif_bmc->msg_idx == 1) { > > > + if (*val > MAX_PAYLOAD_PER_TRANSACTION) > > > + dev_warn(&ssif_bmc->client->dev, > > > + "Warn: Invalid Multipart Write End len"); > > > + > > > + ssif_bmc->request.len += *val; > > > + ssif_bmc->recv_len = *val; > > > + > > > + /* request len should never exceeded 255 bytes */ > > > + if (ssif_bmc->request.len > 255) > > > + dev_warn(&ssif_bmc->client->dev, > > > + "Warn: Invalid request len"); > > > + > > > + } else { > > > > You check msg_idx above, but I'm not sure that check will cover this > > operation. > > > That check is to make sure the length (*val) must always be strictly 32 > bytes in case of MULTIPART_WRITE_START/MIDDLE. And this check allows the > length is up to 32 bytes in MULTIPART_WRITE_END. Now that I have read and write straight, this is where the previous comments apply. You are trusting the the length sent by the remote end in the second byte is correct, but there is no guarantee of this. The remote end can send as many bytes as it likes. You need to check that you don't overflow buf here and that it actually sends the number of bytes that it said it was going to send to avoid underflow. > > > > + buf[ssif_bmc->msg_idx - 1 + > > > + ssif_bmc->request.len - ssif_bmc->recv_len] = *val; This computation is fairly complicated and hard to understand. Calculations like this are asking for trouble. It would be easier to understand had request.len be the current length of what is in request.payload and increment it on every incoming byte. Then request.len could be used to add data to the buffer, like if (ssif_bmc->request.len >= sizeof(ssif_bmc->payload)) error... ssif_bmc->payload[ssif_bmc->request.len++] = *val; If you renamed msg_idx to curr_recv_idx and recv_len to curr_recv_len, it would be more clear that these are related and operate on the current incoming message. It would also be nice to get rid of the casts from ssif_msg to a buffer array and just index directly into request.payload[]. In thinking about this further, I have a few more observations... There is no need to have the netfn and cmd in ssif_msg. They are just the first and second bytes of the message. You don't care what they are in this code. Why do you deliver the length as part of the message to the user? The length is returned by the system call. You have all these +1 and -1 things around the message length, which is error-prone. Removing the length from the message would get rid of all of that. And using packed structures is generally not the best, anyway. The PEC calculations remove one byte from the maximum message length. Since they are not included in the length byte, it's kind of unnatural to do this the way you are doing it. Instead, it might be best to say if you receive a byte and curr_recv_idx == curr_recv_len, process it as PEC. That way the PEC never hits the buffer. There is no need for msg_idx, or cur_recv_idx, to be size_t. I need to look at this some more, but I'll need to see the rewrite. -corey > > > + } > > > + > > > + ssif_bmc->msg_idx++; > > > + > > > + break; > > > + default: > > > + /* Do not expect to go to this case */ > > > + dev_err(&ssif_bmc->client->dev, > > > + "%s: Unexpected SMBus command 0x%x\n", > > > + __func__, ssif_bmc->smbus_cmd); > > > + break; > > > + } > > > +} > > > + > > > +static bool validate_request(struct ssif_bmc_ctx *ssif_bmc) > > > +{ > > > + u8 rpec = 0, cpec = 0; > > > + bool ret = true; > > > + u8 addr, index; > > > + u8 *buf; > > > + > > > > Is there any length validation for using buf below? It looks like you > > are accessing without checking length, but maybe I missed something. > > > > Yes, there is length testing for each part before using buf to calculate PEC > as in the "if" below. > > > > + buf = (u8 *)&ssif_bmc->request; > > > + switch (ssif_bmc->smbus_cmd) { > > > + case SSIF_IPMI_SINGLEPART_WRITE: > > > + if ((ssif_bmc->msg_idx - 1) == ssif_msg_len(&ssif_bmc->request)) { > > > + /* PEC is not included */ > > > + ssif_bmc->pec_support = false; > > > + ret = true; > > > + goto exit; > > > + } > > > + > > > + if ((ssif_bmc->msg_idx - 1) != (ssif_msg_len(&ssif_bmc->request) + 1)) { > > > + dev_err(&ssif_bmc->client->dev, "Error: Unexpected length received %d\n", > > > + ssif_msg_len(&ssif_bmc->request)); > > > + ret = false; > > > + goto exit; > > > + } > > > + > > > + /* PEC is included */ > > > + ssif_bmc->pec_support = true; > > > + rpec = buf[ssif_bmc->msg_idx - 2]; > > > + addr = GET_8BIT_ADDR(ssif_bmc->client->addr); > > > + cpec = i2c_smbus_pec(cpec, &addr, 1); > > > + cpec = i2c_smbus_pec(cpec, &ssif_bmc->smbus_cmd, 1); > > > + cpec = i2c_smbus_pec(cpec, buf, ssif_msg_len(&ssif_bmc->request)); > > > + if (rpec != cpec) { > > > + dev_err(&ssif_bmc->client->dev, "Bad PEC 0x%02x vs. 0x%02x\n", rpec, cpec); > > > + ret = false; > > > + } > > > + > > > + break; > > > + case SSIF_IPMI_MULTIPART_WRITE_START: > > > + case SSIF_IPMI_MULTIPART_WRITE_MIDDLE: > > > + case SSIF_IPMI_MULTIPART_WRITE_END: > > > + index = ssif_bmc->request.len - ssif_bmc->recv_len; > > > + if ((ssif_bmc->msg_idx - 1 + index) == ssif_msg_len(&ssif_bmc->request)) { > > > + /* PEC is not included */ > > > + ssif_bmc->pec_support = false; > > > + ret = true; > > > + goto exit; > > > + } > > > + > > > + if ((ssif_bmc->msg_idx - 1 + index) != (ssif_msg_len(&ssif_bmc->request) + 1)) { > > > + dev_err(&ssif_bmc->client->dev, "Error: Unexpected length received %d\n", > > > + ssif_msg_len(&ssif_bmc->request)); > > > + ret = false; > > > + goto exit; > > > + } > > > + > > > + /* PEC is included */ > > > + ssif_bmc->pec_support = true; > > > + rpec = buf[ssif_bmc->msg_idx - 2 + index]; > > > + addr = GET_8BIT_ADDR(ssif_bmc->client->addr); > > > + cpec = i2c_smbus_pec(cpec, &addr, 1); > > > + cpec = i2c_smbus_pec(cpec, &ssif_bmc->smbus_cmd, 1); > > > + cpec = i2c_smbus_pec(cpec, &ssif_bmc->recv_len, 1); > > > > Just curious, I'm not sure the client side PEC in the Linux driver has > > ever been validated. Have you tested both sides? > > > > Yes, we found that request from host has an extra byte for PEC and that is > why we added PEC support. > > > > + /* As SMBus specification does not allow the length > > > + * (byte count) in the Write-Block protocol to be zero. > > > + * Therefore, it is illegal to have the last Middle > > > + * transaction in the sequence carry 32-byte and have > > > + * a length of ‘0’ in the End transaction. > > > + * But some users may try to use this way and we should > > > + * prevent ssif_bmc driver broken in this case. > > > + */ > > > + if (ssif_bmc->recv_len != 0) > > > + cpec = i2c_smbus_pec(cpec, buf + 1 + index, ssif_bmc->recv_len); > > > + > > > + if (rpec != cpec) { > > > + dev_err(&ssif_bmc->client->dev, "Bad PEC 0x%02x vs. 0x%02x\n", rpec, cpec); > > > + ret = false; > > > + } > > > + > > > + break; > > > + default: > > > + /* Do not expect to go to this case */ > > > + dev_err(&ssif_bmc->client->dev, "%s: Unexpected SMBus command 0x%x\n", > > > + __func__, ssif_bmc->smbus_cmd); > > > + ret = false; > > > + break; > > > + } > > > + > > > +exit: > > > + return ret; > > > +} > > > + > > > > Just a nit, more a general coding style comment. It's almost always a > > bad idea to put a negative (unsupported) into a check function. You > > often end up with something like: > > > > if (!unsupported_smbus_cmd(c)).... > > > > which looks a little strange. Double negatives can make it hard to > > follow and lead to mistakes. This one isn't too bad, but sometimes it > > can be. It's better to do: > > > > if (supported_smbus_cmd(c)).... > > or > > if (!supported_smbus_cmd(c)).... > > > > > > Thanks, Corey. I'll try to refactor this part in next version. > > > > +static bool unsupported_smbus_cmd(u8 cmd) > > > +{ > > > + if (cmd == SSIF_IPMI_SINGLEPART_READ || > > > + cmd == SSIF_IPMI_SINGLEPART_WRITE || > > > + cmd == SSIF_IPMI_MULTIPART_WRITE_START || > > > + cmd == SSIF_IPMI_MULTIPART_WRITE_MIDDLE || > > > + cmd == SSIF_IPMI_MULTIPART_WRITE_END || > > > + cmd == SSIF_IPMI_MULTIPART_READ_START || > > > + cmd == SSIF_IPMI_MULTIPART_READ_MIDDLE) > > > + return false; > > > + > > > + return true; > > > +} > > > + > > > +static void process_smbus_cmd(struct ssif_bmc_ctx *ssif_bmc, u8 *val) > > > +{ > > > + /* SMBUS command can vary (single or multi-part) */ > > > + ssif_bmc->smbus_cmd = *val; > > > + ssif_bmc->msg_idx++; > > > + > > > + if (unsupported_smbus_cmd(*val)) > > > + dev_warn(&ssif_bmc->client->dev, "Warn: Unknown SMBus command"); > > > + > > > + if (*val == SSIF_IPMI_SINGLEPART_WRITE || > > > + *val == SSIF_IPMI_MULTIPART_WRITE_START) { > > > + /* > > > + * The response maybe not come in-time, causing host SSIF driver > > > + * to timeout and resend a new request. In such case check for > > > + * pending response and clear it > > > + */ > > > + if (ssif_bmc->response_in_progress) > > > + complete_response(ssif_bmc); > > > + } > > > +} > > > + > > > +static void on_read_requested_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) > > > +{ > > > + if (ssif_bmc->state == SSIF_READY || > > > + ssif_bmc->state == SSIF_START || > > > + ssif_bmc->state == SSIF_REQ_RECVING || > > > + ssif_bmc->state == SSIF_RES_SENDING) { > > > + ssif_bmc->state = SSIF_BAD_SMBUS; > > > + dev_warn(&ssif_bmc->client->dev, > > > + "Warn: %s unexpected READ REQUESTED in state=%s\n", > > > + __func__, state_to_string(ssif_bmc->state)); > > > + > > > + } else if (ssif_bmc->state == SSIF_SMBUS_CMD) { > > > + ssif_bmc->state = SSIF_RES_SENDING; > > > + } > > > + > > > + ssif_bmc->msg_idx = 0; > > > + if (ssif_bmc->is_singlepart_read) > > > + *val = ssif_bmc->response.len; > > > + else > > > + set_multipart_response_buffer(ssif_bmc, val); > > > +} > > > + > > > +static void on_read_processed_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) > > > +{ > > > + if (ssif_bmc->state == SSIF_READY || > > > + ssif_bmc->state == SSIF_START || > > > + ssif_bmc->state == SSIF_REQ_RECVING || > > > + ssif_bmc->state == SSIF_SMBUS_CMD) { > > > + dev_warn(&ssif_bmc->client->dev, > > > + "Warn: %s unexpected READ PROCESSED in state=%s\n", > > > + __func__, state_to_string(ssif_bmc->state)); > > > + ssif_bmc->state = SSIF_BAD_SMBUS; > > > + } > > > + > > > + handle_read_processed(ssif_bmc, val); > > > +} > > > + > > > +static void on_write_requested_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) > > > +{ > > > + ssif_bmc->msg_idx = 0; > > > + > > > + if (ssif_bmc->state == SSIF_READY || ssif_bmc->state == SSIF_SMBUS_CMD) { > > > + ssif_bmc->state = SSIF_START; > > > + > > > + } else if (ssif_bmc->state == SSIF_START || > > > + ssif_bmc->state == SSIF_REQ_RECVING || > > > + ssif_bmc->state == SSIF_RES_SENDING) { > > > + dev_warn(&ssif_bmc->client->dev, > > > + "Warn: %s unexpected WRITE REQUEST in state=%s\n", > > > + __func__, state_to_string(ssif_bmc->state)); > > > + ssif_bmc->state = SSIF_BAD_SMBUS; > > > + } > > > +} > > > + > > > +static void on_write_received_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) > > > +{ > > > + if (ssif_bmc->state == SSIF_READY || ssif_bmc->state == SSIF_RES_SENDING) { > > > + dev_warn(&ssif_bmc->client->dev, > > > + "Warn: %s unexpected WRITE RECEIVED in state=%s\n", > > > + __func__, state_to_string(ssif_bmc->state)); > > > + ssif_bmc->state = SSIF_BAD_SMBUS; > > > + } else if (ssif_bmc->state == SSIF_START) { > > > + ssif_bmc->state = SSIF_SMBUS_CMD; > > > + } else if (ssif_bmc->state == SSIF_SMBUS_CMD) { > > > + ssif_bmc->state = SSIF_REQ_RECVING; > > > + } > > > + > > > + /* This is response sending state */ > > > + if (ssif_bmc->state == SSIF_REQ_RECVING) > > > + handle_write_received(ssif_bmc, val); > > > + else if (ssif_bmc->state == SSIF_SMBUS_CMD) > > > + process_smbus_cmd(ssif_bmc, val); > > > +} > > > + > > > +static void on_stop_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) > > > +{ > > > + if (ssif_bmc->state == SSIF_READY || > > > + ssif_bmc->state == SSIF_START || > > > + ssif_bmc->state == SSIF_SMBUS_CMD) { > > > + dev_warn(&ssif_bmc->client->dev, > > > + "Warn: %s unexpected SLAVE STOP in state=%s\n", > > > + __func__, state_to_string(ssif_bmc->state)); > > > + > > > + } else if (ssif_bmc->state == SSIF_BAD_SMBUS) { > > > + dev_warn(&ssif_bmc->client->dev, > > > + "Warn: %s received SLAVE STOP from bad state=%s\n", > > > + __func__, state_to_string(ssif_bmc->state)); > > > + > > > + } else if (ssif_bmc->state == SSIF_REQ_RECVING) { > > > + /* A BMC that receives an invalid request drop the data for the write > > > + * transaction and any further transactions (read or write) until > > > + * the next valid read or write Start transaction is received > > > + */ > > > + if (!validate_request(ssif_bmc)) > > > + dev_err(&ssif_bmc->client->dev, "Error: invalid pec\n"); > > > + else if (ssif_bmc->smbus_cmd == SSIF_IPMI_SINGLEPART_WRITE || > > > + ssif_bmc->smbus_cmd == SSIF_IPMI_MULTIPART_WRITE_END) > > > + handle_request(ssif_bmc); > > > + } > > > + > > > + ssif_bmc->state = SSIF_READY; > > > + /* Reset message index */ > > > + ssif_bmc->msg_idx = 0; > > > +} > > > + > > > +/* > > > + * Callback function to handle I2C slave events > > > + */ > > > +static int ssif_bmc_cb(struct i2c_client *client, enum i2c_slave_event event, u8 *val) > > > +{ > > > + unsigned long flags; > > > + struct ssif_bmc_ctx *ssif_bmc = i2c_get_clientdata(client); > > > + int ret = 0; > > > + > > > + spin_lock_irqsave(&ssif_bmc->lock, flags); > > > + > > > + switch (event) { > > > + case I2C_SLAVE_READ_REQUESTED: > > > + on_read_requested_event(ssif_bmc, val); > > > + break; > > > + > > > + case I2C_SLAVE_WRITE_REQUESTED: > > > + on_write_requested_event(ssif_bmc, val); > > > + break; > > > + > > > + case I2C_SLAVE_READ_PROCESSED: > > > + on_read_processed_event(ssif_bmc, val); > > > + break; > > > + > > > + case I2C_SLAVE_WRITE_RECEIVED: > > > + on_write_received_event(ssif_bmc, val); > > > + break; > > > + > > > + case I2C_SLAVE_STOP: > > > + on_stop_event(ssif_bmc, val); > > > + break; > > > + > > > + default: > > > + dev_warn(&ssif_bmc->client->dev, "Warn: Unknown i2c slave event\n"); > > > + break; > > > + } > > > + > > > + if (ssif_bmc->busy) > > > + ret = -EBUSY; > > > + > > > + spin_unlock_irqrestore(&ssif_bmc->lock, flags); > > > + > > > + return ret; > > > +} > > > + > > > +static int ssif_bmc_probe(struct i2c_client *client, const struct i2c_device_id *id) > > > +{ > > > + struct ssif_bmc_ctx *ssif_bmc; > > > + int ret; > > > + > > > + ssif_bmc = devm_kzalloc(&client->dev, sizeof(*ssif_bmc), GFP_KERNEL); > > > + if (!ssif_bmc) > > > + return -ENOMEM; > > > + > > > + spin_lock_init(&ssif_bmc->lock); > > > + > > > + init_waitqueue_head(&ssif_bmc->wait_queue); > > > + ssif_bmc->request_available = false; > > > + ssif_bmc->response_in_progress = false; > > > + ssif_bmc->busy = false; > > > + ssif_bmc->response_timer_inited = false; > > > + > > > + /* Register misc device interface */ > > > + ssif_bmc->miscdev.minor = MISC_DYNAMIC_MINOR; > > > + ssif_bmc->miscdev.name = DEVICE_NAME; > > > + ssif_bmc->miscdev.fops = &ssif_bmc_fops; > > > + ssif_bmc->miscdev.parent = &client->dev; > > > + ret = misc_register(&ssif_bmc->miscdev); > > > + if (ret) > > > + goto out; > > > + > > > + ssif_bmc->client = client; > > > + ssif_bmc->client->flags |= I2C_CLIENT_SLAVE; > > > + > > > + /* Register I2C slave */ > > > + i2c_set_clientdata(client, ssif_bmc); > > > + ret = i2c_slave_register(client, ssif_bmc_cb); > > > + if (ret) { > > > + misc_deregister(&ssif_bmc->miscdev); > > > + goto out; > > > + } > > > + > > > + return 0; > > > +out: > > > + devm_kfree(&client->dev, ssif_bmc); > > > + return ret; > > > +} > > > + > > > +static int ssif_bmc_remove(struct i2c_client *client) > > > +{ > > > + struct ssif_bmc_ctx *ssif_bmc = i2c_get_clientdata(client); > > > + > > > + i2c_slave_unregister(client); > > > + misc_deregister(&ssif_bmc->miscdev); > > > + > > > + return 0; > > > +} > > > + > > > +static const struct of_device_id ssif_bmc_match[] = { > > > + { .compatible = "ampere,ssif-bmc" }, > > > + { }, > > > +}; > > > + > > > +static const struct i2c_device_id ssif_bmc_id[] = { > > > + { DEVICE_NAME, 0 }, > > > + { }, > > > +}; > > > + > > > +MODULE_DEVICE_TABLE(i2c, ssif_bmc_id); > > > + > > > +static struct i2c_driver ssif_bmc_driver = { > > > + .driver = { > > > + .name = DEVICE_NAME, > > > + .of_match_table = ssif_bmc_match, > > > + }, > > > + .probe = ssif_bmc_probe, > > > + .remove = ssif_bmc_remove, > > > + .id_table = ssif_bmc_id, > > > +}; > > > + > > > +module_i2c_driver(ssif_bmc_driver); > > > + > > > +MODULE_AUTHOR("Quan Nguyen "); > > > +MODULE_AUTHOR("Chuong Tran "); > > > +MODULE_DESCRIPTION("Linux device driver of the BMC IPMI SSIF interface."); > > > +MODULE_LICENSE("GPL"); > > > diff --git a/drivers/char/ipmi/ssif_bmc.h b/drivers/char/ipmi/ssif_bmc.h > > > new file mode 100644 > > > index 000000000000..9a26f3c252cc > > > --- /dev/null > > > +++ b/drivers/char/ipmi/ssif_bmc.h > > > @@ -0,0 +1,102 @@ > > > +/* SPDX-License-Identifier: GPL-2.0+ */ > > > +/* > > > + * The driver for BMC side of SSIF interface > > > + * > > > + * Copyright (c) 2022, Ampere Computing LLC > > > + * > > > + */ > > > +#ifndef __SSIF_BMC_H__ > > > +#define __SSIF_BMC_H__ > > > + > > > +#define DEVICE_NAME "ipmi-ssif-host" > > > + > > > +#define GET_8BIT_ADDR(addr_7bit) (((addr_7bit) << 1) & 0xff) > > > + > > > +/* A standard SMBus Transaction is limited to 32 data bytes */ > > > +#define MAX_PAYLOAD_PER_TRANSACTION 32 > > > + > > > +#define MAX_IPMI_DATA_PER_START_TRANSACTION 30 > > > +#define MAX_IPMI_DATA_PER_MIDDLE_TRANSACTION 31 > > > + > > > +#define SSIF_IPMI_SINGLEPART_WRITE 0x2 > > > +#define SSIF_IPMI_SINGLEPART_READ 0x3 > > > +#define SSIF_IPMI_MULTIPART_WRITE_START 0x6 > > > +#define SSIF_IPMI_MULTIPART_WRITE_MIDDLE 0x7 > > > +#define SSIF_IPMI_MULTIPART_WRITE_END 0x8 > > > +#define SSIF_IPMI_MULTIPART_READ_START 0x3 > > > +#define SSIF_IPMI_MULTIPART_READ_MIDDLE 0x9 > > > + > > > +#define MSG_PAYLOAD_LEN_MAX 252 > > > +/* > > > + * IPMI 2.0 Spec, section 12.7 SSIF Timing, > > > + * Request-to-Response Time is T6max(250ms) - T1max(20ms) - 3ms = 227ms > > > + * Recover ssif_bmc from busy state if it takes upto 500ms > > > + */ > > > +#define RESPONSE_TIMEOUT 500 /* ms */ > > > + > > > +struct ssif_msg { > > > + u8 len; > > > + u8 netfn_lun; > > > + u8 cmd; > > > + u8 payload[MSG_PAYLOAD_LEN_MAX]; > > > +} __packed; > > > + > > > +static inline u32 ssif_msg_len(struct ssif_msg *ssif_msg) > > > +{ > > > + return ssif_msg->len + 1; > > > +} > > > + > > > +/* > > > + * SSIF internal states: > > > + * SSIF_READY 0x00 : Ready state > > > + * SSIF_START 0x01 : Start smbus transaction > > > + * SSIF_SMBUS_CMD 0x02 : Received SMBus command > > > + * SSIF_REQ_RECVING 0x03 : Receiving request > > > + * SSIF_RES_SENDING 0x04 : Sending response > > > + * SSIF_BAD_SMBUS 0x05 : Bad SMbus transaction > > > + */ > > > +enum ssif_state { > > > + SSIF_READY, > > > + SSIF_START, > > > + SSIF_SMBUS_CMD, > > > + SSIF_REQ_RECVING, > > > + SSIF_RES_SENDING, > > > + SSIF_BAD_SMBUS, > > > + SSIF_STATE_MAX > > > +}; > > > + > > > +struct ssif_bmc_ctx { > > > + struct i2c_client *client; > > > + struct miscdevice miscdev; > > > + size_t msg_idx; > > > + bool pec_support; > > > + /* ssif bmc spinlock */ > > > + spinlock_t lock; > > > + wait_queue_head_t wait_queue; > > > + u8 running; > > > + enum ssif_state state; > > > + u8 smbus_cmd; > > > + /* Timeout waiting for response */ > > > + struct timer_list response_timer; > > > + bool response_timer_inited; > > > + /* Flag to identify a Multi-part Read Transaction */ > > > + bool is_singlepart_read; > > > + u8 nbytes_processed; > > > + u8 remain_len; > > > + u8 recv_len; > > > + /* Block Number of a Multi-part Read Transaction */ > > > + u8 block_num; > > > + bool request_available; > > > + bool response_in_progress; > > > + bool busy; > > > + /* Response buffer for Multi-part Read Transaction */ > > > + u8 response_buf[MAX_PAYLOAD_PER_TRANSACTION]; > > > + struct ssif_msg response; > > > + struct ssif_msg request; > > > +}; > > > + > > > +static inline struct ssif_bmc_ctx *to_ssif_bmc(struct file *file) > > > +{ > > > + return container_of(file->private_data, struct ssif_bmc_ctx, miscdev); > > > +} > > > +#endif /* __SSIF_BMC_H__ */ > > > -- > > > 2.35.1 > > > > > > From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.ozlabs.org (lists.ozlabs.org [112.213.38.117]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 4517AC433F5 for ; Thu, 17 Mar 2022 13:15:01 +0000 (UTC) Received: from boromir.ozlabs.org (localhost [IPv6:::1]) by lists.ozlabs.org (Postfix) with ESMTP id 4KK70g4KT0z30NZ for ; Fri, 18 Mar 2022 00:14:59 +1100 (AEDT) Authentication-Results: lists.ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20210112 header.b=nQ9VUi9s; dkim-atps=neutral Authentication-Results: lists.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gmail.com (client-ip=2607:f8b0:4864:20::72b; helo=mail-qk1-x72b.google.com; envelope-from=tcminyard@gmail.com; receiver=) Authentication-Results: lists.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20210112 header.b=nQ9VUi9s; dkim-atps=neutral Received: from mail-qk1-x72b.google.com (mail-qk1-x72b.google.com [IPv6:2607:f8b0:4864:20::72b]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 4KK6zm3Xwfz2y8P; Fri, 18 Mar 2022 00:14:10 +1100 (AEDT) Received: by mail-qk1-x72b.google.com with SMTP id b189so4236225qkf.11; Thu, 17 Mar 2022 06:14:10 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=sender:date:from:to:cc:subject:message-id:reply-to:references :mime-version:content-disposition:content-transfer-encoding :in-reply-to; bh=eWle4zbRf1n3H9JH+hlY46qvlaTRjOJL9WeucImHHOg=; b=nQ9VUi9sYyhAlmOegG+gL9U+A+k4L0h3YbQdoECtJViy3ucmZmKvZbk1M0lo+zElvW P9QSK1XhNmYuYVYGUa4pn2HOk/+sPmEIyA8nJj1ORGBwTzypv/YjSfxjqBBv6jn1eNeG 89VNacmyZlqb1Uypy/SZJdjFDbtbS6s0lYo93muJrNmZ3/2jvRBimBDe0cievdvHo+Z8 3xD6agc2lgghKoxsnMGk5BQTXecQgdNI+v1T7rxp+u0WV0oQrU5/puPU1EwhqTDoG1So Tb1r1r0sN/GtE8Oz4B01M5OFORYzkn6/F7euKMNyobLT1mwrOVYUzoP29R3AHyy5Qqa+ 2pKw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:sender:date:from:to:cc:subject:message-id :reply-to:references:mime-version:content-disposition :content-transfer-encoding:in-reply-to; bh=eWle4zbRf1n3H9JH+hlY46qvlaTRjOJL9WeucImHHOg=; b=ISOIotKJ3Emm0UrJwANFd/ekBFG6yAls1iNOBXnMGZKHES98+smF5G9FNx9Jjsy7oQ +91G9NHbz9HHv2V5RQz9FUKFbMSRTadMb+f6QFom7gQmAO+QmX7F4Yd8zggvw9f/E8V4 MqXEnZddgo/XS/E65jb8YbPuLVR6jh3I1w/wJBB7tJU89BrpwDIGx2j2LU4UVj03cclO FpCO+bZHyvbOXVoRAJPFUu7EWkFEisozFKwg7MU4KbobXhk9U05PbSfoRUbsuaHMCVyx KqYCwOJ5hCtOGHZf0hujDNGHFkiXgqPuk2hmYrw+XyfYN9n/csYyEEMSO90dBTgd4/Aq /aYA== X-Gm-Message-State: AOAM532ONu1A7cBt2vjE0hAwM7dicl3wtZ61fBvliM+U32DpXAnWbJeL 0k9iboAMKmQzFEbPUrpL4A== X-Google-Smtp-Source: ABdhPJyjMKdRe3h0gF9p5mD85cMhaUnlFewNeqxPQzyz5DcwwNrVVLR63pDXDdHBePDcGgad/48sdA== X-Received: by 2002:a05:620a:271d:b0:67d:bb5f:8a7d with SMTP id b29-20020a05620a271d00b0067dbb5f8a7dmr2684691qkp.154.1647522844635; Thu, 17 Mar 2022 06:14:04 -0700 (PDT) Received: from serve.minyard.net (serve.minyard.net. [2001:470:b8f6:1b::1]) by smtp.gmail.com with ESMTPSA id j67-20020a37b946000000b0067b221281dbsm2445827qkf.99.2022.03.17.06.13.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 17 Mar 2022 06:13:59 -0700 (PDT) Received: from minyard.net (unknown [IPv6:2001:470:b8f6:1b:797c:2e79:7998:93c9]) by serve.minyard.net (Postfix) with ESMTPSA id 43EEA180004; Thu, 17 Mar 2022 13:13:57 +0000 (UTC) Date: Thu, 17 Mar 2022 08:13:56 -0500 From: Corey Minyard To: Quan Nguyen Subject: Re: [PATCH v6 1/4] ipmi: ssif_bmc: Add SSIF BMC driver Message-ID: <20220317131356.GC3457@minyard.net> References: <20220310114119.13736-1-quan@os.amperecomputing.com> <20220310114119.13736-2-quan@os.amperecomputing.com> <20220311011942.GX3457@minyard.net> <569f50d5-8f13-280e-b944-6e26d95dc50b@os.amperecomputing.com> MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Disposition: inline Content-Transfer-Encoding: 8bit In-Reply-To: <569f50d5-8f13-280e-b944-6e26d95dc50b@os.amperecomputing.com> X-BeenThere: openbmc@lists.ozlabs.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Development list for OpenBMC List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: minyard@acm.org Cc: devicetree@vger.kernel.org, linux-aspeed@lists.ozlabs.org, Krzysztof Kozlowski , Andrew Jeffery , openbmc@lists.ozlabs.org, "Thang Q . Nguyen" , Brendan Higgins , linux-kernel@vger.kernel.org, Phong Vo , Wolfram Sang , Rob Herring , Joel Stanley , openipmi-developer@lists.sourceforge.net, Open Source Submission , linux-arm-kernel@lists.infradead.org, linux-i2c@vger.kernel.org Errors-To: openbmc-bounces+openbmc=archiver.kernel.org@lists.ozlabs.org Sender: "openbmc" snip... > > > + > > > +static void response_timeout(struct timer_list *t) > > > +{ > > > + struct ssif_bmc_ctx *ssif_bmc = from_timer(ssif_bmc, t, response_timer); > > > + unsigned long flags; > > > + > > > > Is there a possible race here? The timeout can happen at the same time > > as a received message, will something bad happen if that's the case? > > > > Thanks Corey, > I think I need extra comment here. > > The purpose of this timeout is to make sure ssif_bmc will recover from busy > state in case the upper stack does not provide the response. > Hence, the response timeout is set as 500ms, twice the time of max > Request-to-Response in spec as the code below. Should it be longer? That's not what I was asking. I know what the timer is for. But what happens if the response comes in at the same time this timer goes off? What will keep the data from getting messed up? > > As per spec, the max Request-to-Respose would not exceed 250ms. > > I put the comment in ssif_bmc.h as below: > >> +/* > >> + * IPMI 2.0 Spec, section 12.7 SSIF Timing, > >> + * Request-to-Response Time is T6max(250ms) - T1max(20ms) - 3ms = 227ms > >> + * Recover ssif_bmc from busy state if it takes upto 500ms > >> + */ > >> +#define RESPONSE_TIMEOUT 500 /* ms */ > > > > > + spin_lock_irqsave(&ssif_bmc->lock, flags); > > > + > > > + /* Recover ssif_bmc from busy */ > > > + ssif_bmc->busy = false; > > > + del_timer(&ssif_bmc->response_timer); > > > > You don't need to delete the timer, it's in the timeout. > > > > Will remove this redundant code in next version > > > > + ssif_bmc->response_timer_inited = false; > > > + > > > + spin_unlock_irqrestore(&ssif_bmc->lock, flags); > > > +} > > > + > > > +/* Called with ssif_bmc->lock held. */ > > > +static void handle_request(struct ssif_bmc_ctx *ssif_bmc) > > > +{ > > > + /* set ssif_bmc to busy waiting for response */ > > > + ssif_bmc->busy = true; > > > + > > > + /* Request message is available to process */ > > > + ssif_bmc->request_available = true; > > > + > > > + /* Clean old response buffer */ > > > + memset(&ssif_bmc->response, 0, sizeof(struct ssif_msg)); > > > + > > > + /* This is the new READ request.*/ > > > + wake_up_all(&ssif_bmc->wait_queue); > > > + > > > + /* Armed timer to recover slave from busy state in case of no response */ > > > + if (!ssif_bmc->response_timer_inited) { > > > + timer_setup(&ssif_bmc->response_timer, response_timeout, 0); > > > + ssif_bmc->response_timer_inited = true; > > > + } > > > + mod_timer(&ssif_bmc->response_timer, jiffies + msecs_to_jiffies(RESPONSE_TIMEOUT)); > > > +} > > > + > > > +static void set_multipart_response_buffer(struct ssif_bmc_ctx *ssif_bmc, u8 *val) > > > +{ > > > + u8 response_len = 0; > > > + int idx = 0; > > > + u8 data_len; > > > + > > > + data_len = ssif_bmc->response.len; > > > + switch (ssif_bmc->smbus_cmd) { > > > + case SSIF_IPMI_MULTIPART_READ_START: > > > + /* > > > + * Read Start length is 32 bytes. > > > + * Read Start transfer first 30 bytes of IPMI response > > > + * and 2 special code 0x00, 0x01. > > > + */ > > > + *val = MAX_PAYLOAD_PER_TRANSACTION; > > > + ssif_bmc->remain_len = data_len - MAX_IPMI_DATA_PER_START_TRANSACTION; > > > + ssif_bmc->block_num = 0; > > > > Do you need to validate the data length before using this? > > This applies for lots of places through here. > > > > set_multipart_response_buffer() is called only when ->is_singlepart_read is > false, which is determined by the below code under the *_write() > > ssif_bmc->is_singlepart_read = (ssif_msg_len(&msg) <= > MAX_PAYLOAD_PER_TRANSACTION + 1); > > So, I think the len is validated and could be use in this functions. Ah, I had things backwards. "Read" here is when you are writing to the other side. I understand now. > > > > + > > > + ssif_bmc->response_buf[idx++] = 0x00; /* Start Flag */ > > > + ssif_bmc->response_buf[idx++] = 0x01; /* Start Flag */ > > > + ssif_bmc->response_buf[idx++] = ssif_bmc->response.netfn_lun; > > > + ssif_bmc->response_buf[idx++] = ssif_bmc->response.cmd; > > > + ssif_bmc->response_buf[idx++] = ssif_bmc->response.payload[0]; > > > + > > > + response_len = MAX_PAYLOAD_PER_TRANSACTION - idx; > > > + > > > + memcpy(&ssif_bmc->response_buf[idx], &ssif_bmc->response.payload[1], > > > + response_len); > > > + break; > > > + > > > + case SSIF_IPMI_MULTIPART_READ_MIDDLE: > > > + /* > > > + * IPMI READ Middle or READ End messages can carry up to 31 bytes > > > + * IPMI data plus block number byte. > > > + */ > > > + if (ssif_bmc->remain_len < MAX_IPMI_DATA_PER_MIDDLE_TRANSACTION) { > > > + /* > > > + * This is READ End message > > > + * Return length is the remaining response data length > > > + * plus block number > > > + * Block number 0xFF is to indicate this is last message > > > + * > > > + */ > > > + *val = ssif_bmc->remain_len + 1; > > > + ssif_bmc->block_num = 0xFF; > > > + ssif_bmc->response_buf[idx++] = ssif_bmc->block_num; > > > + response_len = ssif_bmc->remain_len; > > > + /* Clean the buffer */ > > > + memset(&ssif_bmc->response_buf[idx], 0, MAX_PAYLOAD_PER_TRANSACTION - idx); > > > + } else { > > > + /* > > > + * This is READ Middle message > > > + * Response length is the maximum SMBUS transfer length > > > + * Block number byte is incremented > > > + * Return length is maximum SMBUS transfer length > > > + */ > > > + *val = MAX_PAYLOAD_PER_TRANSACTION; > > > + ssif_bmc->remain_len -= MAX_IPMI_DATA_PER_MIDDLE_TRANSACTION; > > > + response_len = MAX_IPMI_DATA_PER_MIDDLE_TRANSACTION; > > > + ssif_bmc->response_buf[idx++] = ssif_bmc->block_num; > > > + ssif_bmc->block_num++; > > > + } > > > + > > > + memcpy(&ssif_bmc->response_buf[idx], > > > + ssif_bmc->response.payload + 1 + ssif_bmc->nbytes_processed, > > > + response_len); > > > + break; > > > + > > > + default: > > > + /* Do not expect to go to this case */ > > > + dev_err(&ssif_bmc->client->dev, > > > + "%s: Unexpected SMBus command 0x%x\n", > > > + __func__, ssif_bmc->smbus_cmd); > > > + break; > > > + } > > > + > > > + ssif_bmc->nbytes_processed += response_len; > > > +} > > > + > > > +/* Process the IPMI response that will be read by master */ > > > +static void handle_read_processed(struct ssif_bmc_ctx *ssif_bmc, u8 *val) > > > +{ > > > + u8 *buf; > > > + u8 pec_len, addr, len; > > > + u8 pec = 0; > > > + > > > + pec_len = ssif_bmc->pec_support ? 1 : 0; > > > + /* PEC - Start Read Address */ > > > + addr = GET_8BIT_ADDR(ssif_bmc->client->addr); > > > + pec = i2c_smbus_pec(pec, &addr, 1); > > > + /* PEC - SSIF Command */ > > > + pec = i2c_smbus_pec(pec, &ssif_bmc->smbus_cmd, 1); > > > + /* PEC - Restart Write Address */ > > > + addr = addr | 0x01; > > > + pec = i2c_smbus_pec(pec, &addr, 1); > > > + > > > + if (ssif_bmc->is_singlepart_read) { > > > + /* Single-part Read processing */ > > > + buf = (u8 *)&ssif_bmc->response; > > > + > > > + if (ssif_bmc->response.len && ssif_bmc->msg_idx < ssif_bmc->response.len) { > > > + ssif_bmc->msg_idx++; > > > + *val = buf[ssif_bmc->msg_idx]; > > > + } else if (ssif_bmc->response.len && ssif_bmc->msg_idx == ssif_bmc->response.len) { > > > + ssif_bmc->msg_idx++; > > > + *val = i2c_smbus_pec(pec, buf, ssif_msg_len(&ssif_bmc->response)); > > > + } else { > > > > I thought for a second that this was wrong, but I think it's correct. > > Supply zero if you don't have data. > > > > > + *val = 0; > > > + } > > > + /* Invalidate response buffer to denote it is sent */ > > > + if (ssif_bmc->msg_idx + 1 >= (ssif_msg_len(&ssif_bmc->response) + pec_len)) > > > + complete_response(ssif_bmc); > > > + } else { > > > + /* Multi-part Read processing */ > > > > You don't check the length here like you did above. I think that's > > required. > > > > As per my explanation above, the ->is_singlepart_read is determined by > testing the length, so it is validated as I assumed. > > > > + switch (ssif_bmc->smbus_cmd) { > > > + case SSIF_IPMI_MULTIPART_READ_START: > > > + case SSIF_IPMI_MULTIPART_READ_MIDDLE: > > > + buf = (u8 *)&ssif_bmc->response_buf; > > > + *val = buf[ssif_bmc->msg_idx]; > > > + ssif_bmc->msg_idx++; > > > + break; > > > + default: > > > + /* Do not expect to go to this case */ > > > + dev_err(&ssif_bmc->client->dev, > > > + "%s: Unexpected SMBus command 0x%x\n", > > > + __func__, ssif_bmc->smbus_cmd); > > > + break; > > > + } > > > + > > > + len = (ssif_bmc->block_num == 0xFF) ? > > > + ssif_bmc->remain_len + 1 : MAX_PAYLOAD_PER_TRANSACTION; > > > + if (ssif_bmc->msg_idx == (len + 1)) { > > > + pec = i2c_smbus_pec(pec, &len, 1); > > > + *val = i2c_smbus_pec(pec, ssif_bmc->response_buf, len); > > > + } > > > + /* Invalidate response buffer to denote last response is sent */ > > > + if (ssif_bmc->block_num == 0xFF && > > > + ssif_bmc->msg_idx > (ssif_bmc->remain_len + pec_len)) { > > > + complete_response(ssif_bmc); > > > + } > > > + } > > > +} > > > + > > > +static void handle_write_received(struct ssif_bmc_ctx *ssif_bmc, u8 *val) > > > +{ > > > + u8 *buf = (u8 *)&ssif_bmc->request; > > > + > > > + if (ssif_bmc->msg_idx >= sizeof(struct ssif_msg)) > > > + return; I don't think this check is valid. I believe the msg_idx only covers the current message, but ssif_msg is a full multi-part message. It covers the single-part message, I think but not the multi-part ones. Also, abort the operation and log on bad data. > > > + > > > + switch (ssif_bmc->smbus_cmd) { > > > + case SSIF_IPMI_SINGLEPART_WRITE: > > > + buf[ssif_bmc->msg_idx - 1] = *val; > > > + ssif_bmc->msg_idx++; > > > + > > > + break; > > > + case SSIF_IPMI_MULTIPART_WRITE_START: > > > + if (ssif_bmc->msg_idx == 1) > > > + ssif_bmc->request.len = 0; > > > + > > > + fallthrough; > > > + case SSIF_IPMI_MULTIPART_WRITE_MIDDLE: > > > + /* The len should always be 32 */ > > > + if (ssif_bmc->msg_idx == 1 && *val != MAX_PAYLOAD_PER_TRANSACTION) > > > + dev_warn(&ssif_bmc->client->dev, > > > + "Warn: Invalid Multipart Write len"); You should abort the operation here. Don't deliver obviously bad data. Same in the code just below. This will require that you add a message aborted type of state to just ignore everything that comes in until the full sequence ends or a new message starts. > > > + > > > + fallthrough; > > > + case SSIF_IPMI_MULTIPART_WRITE_END: > > > + /* Multi-part write, 2nd byte received is length */ > > > + if (ssif_bmc->msg_idx == 1) { > > > + if (*val > MAX_PAYLOAD_PER_TRANSACTION) > > > + dev_warn(&ssif_bmc->client->dev, > > > + "Warn: Invalid Multipart Write End len"); > > > + > > > + ssif_bmc->request.len += *val; > > > + ssif_bmc->recv_len = *val; > > > + > > > + /* request len should never exceeded 255 bytes */ > > > + if (ssif_bmc->request.len > 255) > > > + dev_warn(&ssif_bmc->client->dev, > > > + "Warn: Invalid request len"); > > > + > > > + } else { > > > > You check msg_idx above, but I'm not sure that check will cover this > > operation. > > > That check is to make sure the length (*val) must always be strictly 32 > bytes in case of MULTIPART_WRITE_START/MIDDLE. And this check allows the > length is up to 32 bytes in MULTIPART_WRITE_END. Now that I have read and write straight, this is where the previous comments apply. You are trusting the the length sent by the remote end in the second byte is correct, but there is no guarantee of this. The remote end can send as many bytes as it likes. You need to check that you don't overflow buf here and that it actually sends the number of bytes that it said it was going to send to avoid underflow. > > > > + buf[ssif_bmc->msg_idx - 1 + > > > + ssif_bmc->request.len - ssif_bmc->recv_len] = *val; This computation is fairly complicated and hard to understand. Calculations like this are asking for trouble. It would be easier to understand had request.len be the current length of what is in request.payload and increment it on every incoming byte. Then request.len could be used to add data to the buffer, like if (ssif_bmc->request.len >= sizeof(ssif_bmc->payload)) error... ssif_bmc->payload[ssif_bmc->request.len++] = *val; If you renamed msg_idx to curr_recv_idx and recv_len to curr_recv_len, it would be more clear that these are related and operate on the current incoming message. It would also be nice to get rid of the casts from ssif_msg to a buffer array and just index directly into request.payload[]. In thinking about this further, I have a few more observations... There is no need to have the netfn and cmd in ssif_msg. They are just the first and second bytes of the message. You don't care what they are in this code. Why do you deliver the length as part of the message to the user? The length is returned by the system call. You have all these +1 and -1 things around the message length, which is error-prone. Removing the length from the message would get rid of all of that. And using packed structures is generally not the best, anyway. The PEC calculations remove one byte from the maximum message length. Since they are not included in the length byte, it's kind of unnatural to do this the way you are doing it. Instead, it might be best to say if you receive a byte and curr_recv_idx == curr_recv_len, process it as PEC. That way the PEC never hits the buffer. There is no need for msg_idx, or cur_recv_idx, to be size_t. I need to look at this some more, but I'll need to see the rewrite. -corey > > > + } > > > + > > > + ssif_bmc->msg_idx++; > > > + > > > + break; > > > + default: > > > + /* Do not expect to go to this case */ > > > + dev_err(&ssif_bmc->client->dev, > > > + "%s: Unexpected SMBus command 0x%x\n", > > > + __func__, ssif_bmc->smbus_cmd); > > > + break; > > > + } > > > +} > > > + > > > +static bool validate_request(struct ssif_bmc_ctx *ssif_bmc) > > > +{ > > > + u8 rpec = 0, cpec = 0; > > > + bool ret = true; > > > + u8 addr, index; > > > + u8 *buf; > > > + > > > > Is there any length validation for using buf below? It looks like you > > are accessing without checking length, but maybe I missed something. > > > > Yes, there is length testing for each part before using buf to calculate PEC > as in the "if" below. > > > > + buf = (u8 *)&ssif_bmc->request; > > > + switch (ssif_bmc->smbus_cmd) { > > > + case SSIF_IPMI_SINGLEPART_WRITE: > > > + if ((ssif_bmc->msg_idx - 1) == ssif_msg_len(&ssif_bmc->request)) { > > > + /* PEC is not included */ > > > + ssif_bmc->pec_support = false; > > > + ret = true; > > > + goto exit; > > > + } > > > + > > > + if ((ssif_bmc->msg_idx - 1) != (ssif_msg_len(&ssif_bmc->request) + 1)) { > > > + dev_err(&ssif_bmc->client->dev, "Error: Unexpected length received %d\n", > > > + ssif_msg_len(&ssif_bmc->request)); > > > + ret = false; > > > + goto exit; > > > + } > > > + > > > + /* PEC is included */ > > > + ssif_bmc->pec_support = true; > > > + rpec = buf[ssif_bmc->msg_idx - 2]; > > > + addr = GET_8BIT_ADDR(ssif_bmc->client->addr); > > > + cpec = i2c_smbus_pec(cpec, &addr, 1); > > > + cpec = i2c_smbus_pec(cpec, &ssif_bmc->smbus_cmd, 1); > > > + cpec = i2c_smbus_pec(cpec, buf, ssif_msg_len(&ssif_bmc->request)); > > > + if (rpec != cpec) { > > > + dev_err(&ssif_bmc->client->dev, "Bad PEC 0x%02x vs. 0x%02x\n", rpec, cpec); > > > + ret = false; > > > + } > > > + > > > + break; > > > + case SSIF_IPMI_MULTIPART_WRITE_START: > > > + case SSIF_IPMI_MULTIPART_WRITE_MIDDLE: > > > + case SSIF_IPMI_MULTIPART_WRITE_END: > > > + index = ssif_bmc->request.len - ssif_bmc->recv_len; > > > + if ((ssif_bmc->msg_idx - 1 + index) == ssif_msg_len(&ssif_bmc->request)) { > > > + /* PEC is not included */ > > > + ssif_bmc->pec_support = false; > > > + ret = true; > > > + goto exit; > > > + } > > > + > > > + if ((ssif_bmc->msg_idx - 1 + index) != (ssif_msg_len(&ssif_bmc->request) + 1)) { > > > + dev_err(&ssif_bmc->client->dev, "Error: Unexpected length received %d\n", > > > + ssif_msg_len(&ssif_bmc->request)); > > > + ret = false; > > > + goto exit; > > > + } > > > + > > > + /* PEC is included */ > > > + ssif_bmc->pec_support = true; > > > + rpec = buf[ssif_bmc->msg_idx - 2 + index]; > > > + addr = GET_8BIT_ADDR(ssif_bmc->client->addr); > > > + cpec = i2c_smbus_pec(cpec, &addr, 1); > > > + cpec = i2c_smbus_pec(cpec, &ssif_bmc->smbus_cmd, 1); > > > + cpec = i2c_smbus_pec(cpec, &ssif_bmc->recv_len, 1); > > > > Just curious, I'm not sure the client side PEC in the Linux driver has > > ever been validated. Have you tested both sides? > > > > Yes, we found that request from host has an extra byte for PEC and that is > why we added PEC support. > > > > + /* As SMBus specification does not allow the length > > > + * (byte count) in the Write-Block protocol to be zero. > > > + * Therefore, it is illegal to have the last Middle > > > + * transaction in the sequence carry 32-byte and have > > > + * a length of ‘0’ in the End transaction. > > > + * But some users may try to use this way and we should > > > + * prevent ssif_bmc driver broken in this case. > > > + */ > > > + if (ssif_bmc->recv_len != 0) > > > + cpec = i2c_smbus_pec(cpec, buf + 1 + index, ssif_bmc->recv_len); > > > + > > > + if (rpec != cpec) { > > > + dev_err(&ssif_bmc->client->dev, "Bad PEC 0x%02x vs. 0x%02x\n", rpec, cpec); > > > + ret = false; > > > + } > > > + > > > + break; > > > + default: > > > + /* Do not expect to go to this case */ > > > + dev_err(&ssif_bmc->client->dev, "%s: Unexpected SMBus command 0x%x\n", > > > + __func__, ssif_bmc->smbus_cmd); > > > + ret = false; > > > + break; > > > + } > > > + > > > +exit: > > > + return ret; > > > +} > > > + > > > > Just a nit, more a general coding style comment. It's almost always a > > bad idea to put a negative (unsupported) into a check function. You > > often end up with something like: > > > > if (!unsupported_smbus_cmd(c)).... > > > > which looks a little strange. Double negatives can make it hard to > > follow and lead to mistakes. This one isn't too bad, but sometimes it > > can be. It's better to do: > > > > if (supported_smbus_cmd(c)).... > > or > > if (!supported_smbus_cmd(c)).... > > > > > > Thanks, Corey. I'll try to refactor this part in next version. > > > > +static bool unsupported_smbus_cmd(u8 cmd) > > > +{ > > > + if (cmd == SSIF_IPMI_SINGLEPART_READ || > > > + cmd == SSIF_IPMI_SINGLEPART_WRITE || > > > + cmd == SSIF_IPMI_MULTIPART_WRITE_START || > > > + cmd == SSIF_IPMI_MULTIPART_WRITE_MIDDLE || > > > + cmd == SSIF_IPMI_MULTIPART_WRITE_END || > > > + cmd == SSIF_IPMI_MULTIPART_READ_START || > > > + cmd == SSIF_IPMI_MULTIPART_READ_MIDDLE) > > > + return false; > > > + > > > + return true; > > > +} > > > + > > > +static void process_smbus_cmd(struct ssif_bmc_ctx *ssif_bmc, u8 *val) > > > +{ > > > + /* SMBUS command can vary (single or multi-part) */ > > > + ssif_bmc->smbus_cmd = *val; > > > + ssif_bmc->msg_idx++; > > > + > > > + if (unsupported_smbus_cmd(*val)) > > > + dev_warn(&ssif_bmc->client->dev, "Warn: Unknown SMBus command"); > > > + > > > + if (*val == SSIF_IPMI_SINGLEPART_WRITE || > > > + *val == SSIF_IPMI_MULTIPART_WRITE_START) { > > > + /* > > > + * The response maybe not come in-time, causing host SSIF driver > > > + * to timeout and resend a new request. In such case check for > > > + * pending response and clear it > > > + */ > > > + if (ssif_bmc->response_in_progress) > > > + complete_response(ssif_bmc); > > > + } > > > +} > > > + > > > +static void on_read_requested_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) > > > +{ > > > + if (ssif_bmc->state == SSIF_READY || > > > + ssif_bmc->state == SSIF_START || > > > + ssif_bmc->state == SSIF_REQ_RECVING || > > > + ssif_bmc->state == SSIF_RES_SENDING) { > > > + ssif_bmc->state = SSIF_BAD_SMBUS; > > > + dev_warn(&ssif_bmc->client->dev, > > > + "Warn: %s unexpected READ REQUESTED in state=%s\n", > > > + __func__, state_to_string(ssif_bmc->state)); > > > + > > > + } else if (ssif_bmc->state == SSIF_SMBUS_CMD) { > > > + ssif_bmc->state = SSIF_RES_SENDING; > > > + } > > > + > > > + ssif_bmc->msg_idx = 0; > > > + if (ssif_bmc->is_singlepart_read) > > > + *val = ssif_bmc->response.len; > > > + else > > > + set_multipart_response_buffer(ssif_bmc, val); > > > +} > > > + > > > +static void on_read_processed_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) > > > +{ > > > + if (ssif_bmc->state == SSIF_READY || > > > + ssif_bmc->state == SSIF_START || > > > + ssif_bmc->state == SSIF_REQ_RECVING || > > > + ssif_bmc->state == SSIF_SMBUS_CMD) { > > > + dev_warn(&ssif_bmc->client->dev, > > > + "Warn: %s unexpected READ PROCESSED in state=%s\n", > > > + __func__, state_to_string(ssif_bmc->state)); > > > + ssif_bmc->state = SSIF_BAD_SMBUS; > > > + } > > > + > > > + handle_read_processed(ssif_bmc, val); > > > +} > > > + > > > +static void on_write_requested_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) > > > +{ > > > + ssif_bmc->msg_idx = 0; > > > + > > > + if (ssif_bmc->state == SSIF_READY || ssif_bmc->state == SSIF_SMBUS_CMD) { > > > + ssif_bmc->state = SSIF_START; > > > + > > > + } else if (ssif_bmc->state == SSIF_START || > > > + ssif_bmc->state == SSIF_REQ_RECVING || > > > + ssif_bmc->state == SSIF_RES_SENDING) { > > > + dev_warn(&ssif_bmc->client->dev, > > > + "Warn: %s unexpected WRITE REQUEST in state=%s\n", > > > + __func__, state_to_string(ssif_bmc->state)); > > > + ssif_bmc->state = SSIF_BAD_SMBUS; > > > + } > > > +} > > > + > > > +static void on_write_received_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) > > > +{ > > > + if (ssif_bmc->state == SSIF_READY || ssif_bmc->state == SSIF_RES_SENDING) { > > > + dev_warn(&ssif_bmc->client->dev, > > > + "Warn: %s unexpected WRITE RECEIVED in state=%s\n", > > > + __func__, state_to_string(ssif_bmc->state)); > > > + ssif_bmc->state = SSIF_BAD_SMBUS; > > > + } else if (ssif_bmc->state == SSIF_START) { > > > + ssif_bmc->state = SSIF_SMBUS_CMD; > > > + } else if (ssif_bmc->state == SSIF_SMBUS_CMD) { > > > + ssif_bmc->state = SSIF_REQ_RECVING; > > > + } > > > + > > > + /* This is response sending state */ > > > + if (ssif_bmc->state == SSIF_REQ_RECVING) > > > + handle_write_received(ssif_bmc, val); > > > + else if (ssif_bmc->state == SSIF_SMBUS_CMD) > > > + process_smbus_cmd(ssif_bmc, val); > > > +} > > > + > > > +static void on_stop_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) > > > +{ > > > + if (ssif_bmc->state == SSIF_READY || > > > + ssif_bmc->state == SSIF_START || > > > + ssif_bmc->state == SSIF_SMBUS_CMD) { > > > + dev_warn(&ssif_bmc->client->dev, > > > + "Warn: %s unexpected SLAVE STOP in state=%s\n", > > > + __func__, state_to_string(ssif_bmc->state)); > > > + > > > + } else if (ssif_bmc->state == SSIF_BAD_SMBUS) { > > > + dev_warn(&ssif_bmc->client->dev, > > > + "Warn: %s received SLAVE STOP from bad state=%s\n", > > > + __func__, state_to_string(ssif_bmc->state)); > > > + > > > + } else if (ssif_bmc->state == SSIF_REQ_RECVING) { > > > + /* A BMC that receives an invalid request drop the data for the write > > > + * transaction and any further transactions (read or write) until > > > + * the next valid read or write Start transaction is received > > > + */ > > > + if (!validate_request(ssif_bmc)) > > > + dev_err(&ssif_bmc->client->dev, "Error: invalid pec\n"); > > > + else if (ssif_bmc->smbus_cmd == SSIF_IPMI_SINGLEPART_WRITE || > > > + ssif_bmc->smbus_cmd == SSIF_IPMI_MULTIPART_WRITE_END) > > > + handle_request(ssif_bmc); > > > + } > > > + > > > + ssif_bmc->state = SSIF_READY; > > > + /* Reset message index */ > > > + ssif_bmc->msg_idx = 0; > > > +} > > > + > > > +/* > > > + * Callback function to handle I2C slave events > > > + */ > > > +static int ssif_bmc_cb(struct i2c_client *client, enum i2c_slave_event event, u8 *val) > > > +{ > > > + unsigned long flags; > > > + struct ssif_bmc_ctx *ssif_bmc = i2c_get_clientdata(client); > > > + int ret = 0; > > > + > > > + spin_lock_irqsave(&ssif_bmc->lock, flags); > > > + > > > + switch (event) { > > > + case I2C_SLAVE_READ_REQUESTED: > > > + on_read_requested_event(ssif_bmc, val); > > > + break; > > > + > > > + case I2C_SLAVE_WRITE_REQUESTED: > > > + on_write_requested_event(ssif_bmc, val); > > > + break; > > > + > > > + case I2C_SLAVE_READ_PROCESSED: > > > + on_read_processed_event(ssif_bmc, val); > > > + break; > > > + > > > + case I2C_SLAVE_WRITE_RECEIVED: > > > + on_write_received_event(ssif_bmc, val); > > > + break; > > > + > > > + case I2C_SLAVE_STOP: > > > + on_stop_event(ssif_bmc, val); > > > + break; > > > + > > > + default: > > > + dev_warn(&ssif_bmc->client->dev, "Warn: Unknown i2c slave event\n"); > > > + break; > > > + } > > > + > > > + if (ssif_bmc->busy) > > > + ret = -EBUSY; > > > + > > > + spin_unlock_irqrestore(&ssif_bmc->lock, flags); > > > + > > > + return ret; > > > +} > > > + > > > +static int ssif_bmc_probe(struct i2c_client *client, const struct i2c_device_id *id) > > > +{ > > > + struct ssif_bmc_ctx *ssif_bmc; > > > + int ret; > > > + > > > + ssif_bmc = devm_kzalloc(&client->dev, sizeof(*ssif_bmc), GFP_KERNEL); > > > + if (!ssif_bmc) > > > + return -ENOMEM; > > > + > > > + spin_lock_init(&ssif_bmc->lock); > > > + > > > + init_waitqueue_head(&ssif_bmc->wait_queue); > > > + ssif_bmc->request_available = false; > > > + ssif_bmc->response_in_progress = false; > > > + ssif_bmc->busy = false; > > > + ssif_bmc->response_timer_inited = false; > > > + > > > + /* Register misc device interface */ > > > + ssif_bmc->miscdev.minor = MISC_DYNAMIC_MINOR; > > > + ssif_bmc->miscdev.name = DEVICE_NAME; > > > + ssif_bmc->miscdev.fops = &ssif_bmc_fops; > > > + ssif_bmc->miscdev.parent = &client->dev; > > > + ret = misc_register(&ssif_bmc->miscdev); > > > + if (ret) > > > + goto out; > > > + > > > + ssif_bmc->client = client; > > > + ssif_bmc->client->flags |= I2C_CLIENT_SLAVE; > > > + > > > + /* Register I2C slave */ > > > + i2c_set_clientdata(client, ssif_bmc); > > > + ret = i2c_slave_register(client, ssif_bmc_cb); > > > + if (ret) { > > > + misc_deregister(&ssif_bmc->miscdev); > > > + goto out; > > > + } > > > + > > > + return 0; > > > +out: > > > + devm_kfree(&client->dev, ssif_bmc); > > > + return ret; > > > +} > > > + > > > +static int ssif_bmc_remove(struct i2c_client *client) > > > +{ > > > + struct ssif_bmc_ctx *ssif_bmc = i2c_get_clientdata(client); > > > + > > > + i2c_slave_unregister(client); > > > + misc_deregister(&ssif_bmc->miscdev); > > > + > > > + return 0; > > > +} > > > + > > > +static const struct of_device_id ssif_bmc_match[] = { > > > + { .compatible = "ampere,ssif-bmc" }, > > > + { }, > > > +}; > > > + > > > +static const struct i2c_device_id ssif_bmc_id[] = { > > > + { DEVICE_NAME, 0 }, > > > + { }, > > > +}; > > > + > > > +MODULE_DEVICE_TABLE(i2c, ssif_bmc_id); > > > + > > > +static struct i2c_driver ssif_bmc_driver = { > > > + .driver = { > > > + .name = DEVICE_NAME, > > > + .of_match_table = ssif_bmc_match, > > > + }, > > > + .probe = ssif_bmc_probe, > > > + .remove = ssif_bmc_remove, > > > + .id_table = ssif_bmc_id, > > > +}; > > > + > > > +module_i2c_driver(ssif_bmc_driver); > > > + > > > +MODULE_AUTHOR("Quan Nguyen "); > > > +MODULE_AUTHOR("Chuong Tran "); > > > +MODULE_DESCRIPTION("Linux device driver of the BMC IPMI SSIF interface."); > > > +MODULE_LICENSE("GPL"); > > > diff --git a/drivers/char/ipmi/ssif_bmc.h b/drivers/char/ipmi/ssif_bmc.h > > > new file mode 100644 > > > index 000000000000..9a26f3c252cc > > > --- /dev/null > > > +++ b/drivers/char/ipmi/ssif_bmc.h > > > @@ -0,0 +1,102 @@ > > > +/* SPDX-License-Identifier: GPL-2.0+ */ > > > +/* > > > + * The driver for BMC side of SSIF interface > > > + * > > > + * Copyright (c) 2022, Ampere Computing LLC > > > + * > > > + */ > > > +#ifndef __SSIF_BMC_H__ > > > +#define __SSIF_BMC_H__ > > > + > > > +#define DEVICE_NAME "ipmi-ssif-host" > > > + > > > +#define GET_8BIT_ADDR(addr_7bit) (((addr_7bit) << 1) & 0xff) > > > + > > > +/* A standard SMBus Transaction is limited to 32 data bytes */ > > > +#define MAX_PAYLOAD_PER_TRANSACTION 32 > > > + > > > +#define MAX_IPMI_DATA_PER_START_TRANSACTION 30 > > > +#define MAX_IPMI_DATA_PER_MIDDLE_TRANSACTION 31 > > > + > > > +#define SSIF_IPMI_SINGLEPART_WRITE 0x2 > > > +#define SSIF_IPMI_SINGLEPART_READ 0x3 > > > +#define SSIF_IPMI_MULTIPART_WRITE_START 0x6 > > > +#define SSIF_IPMI_MULTIPART_WRITE_MIDDLE 0x7 > > > +#define SSIF_IPMI_MULTIPART_WRITE_END 0x8 > > > +#define SSIF_IPMI_MULTIPART_READ_START 0x3 > > > +#define SSIF_IPMI_MULTIPART_READ_MIDDLE 0x9 > > > + > > > +#define MSG_PAYLOAD_LEN_MAX 252 > > > +/* > > > + * IPMI 2.0 Spec, section 12.7 SSIF Timing, > > > + * Request-to-Response Time is T6max(250ms) - T1max(20ms) - 3ms = 227ms > > > + * Recover ssif_bmc from busy state if it takes upto 500ms > > > + */ > > > +#define RESPONSE_TIMEOUT 500 /* ms */ > > > + > > > +struct ssif_msg { > > > + u8 len; > > > + u8 netfn_lun; > > > + u8 cmd; > > > + u8 payload[MSG_PAYLOAD_LEN_MAX]; > > > +} __packed; > > > + > > > +static inline u32 ssif_msg_len(struct ssif_msg *ssif_msg) > > > +{ > > > + return ssif_msg->len + 1; > > > +} > > > + > > > +/* > > > + * SSIF internal states: > > > + * SSIF_READY 0x00 : Ready state > > > + * SSIF_START 0x01 : Start smbus transaction > > > + * SSIF_SMBUS_CMD 0x02 : Received SMBus command > > > + * SSIF_REQ_RECVING 0x03 : Receiving request > > > + * SSIF_RES_SENDING 0x04 : Sending response > > > + * SSIF_BAD_SMBUS 0x05 : Bad SMbus transaction > > > + */ > > > +enum ssif_state { > > > + SSIF_READY, > > > + SSIF_START, > > > + SSIF_SMBUS_CMD, > > > + SSIF_REQ_RECVING, > > > + SSIF_RES_SENDING, > > > + SSIF_BAD_SMBUS, > > > + SSIF_STATE_MAX > > > +}; > > > + > > > +struct ssif_bmc_ctx { > > > + struct i2c_client *client; > > > + struct miscdevice miscdev; > > > + size_t msg_idx; > > > + bool pec_support; > > > + /* ssif bmc spinlock */ > > > + spinlock_t lock; > > > + wait_queue_head_t wait_queue; > > > + u8 running; > > > + enum ssif_state state; > > > + u8 smbus_cmd; > > > + /* Timeout waiting for response */ > > > + struct timer_list response_timer; > > > + bool response_timer_inited; > > > + /* Flag to identify a Multi-part Read Transaction */ > > > + bool is_singlepart_read; > > > + u8 nbytes_processed; > > > + u8 remain_len; > > > + u8 recv_len; > > > + /* Block Number of a Multi-part Read Transaction */ > > > + u8 block_num; > > > + bool request_available; > > > + bool response_in_progress; > > > + bool busy; > > > + /* Response buffer for Multi-part Read Transaction */ > > > + u8 response_buf[MAX_PAYLOAD_PER_TRANSACTION]; > > > + struct ssif_msg response; > > > + struct ssif_msg request; > > > +}; > > > + > > > +static inline struct ssif_bmc_ctx *to_ssif_bmc(struct file *file) > > > +{ > > > + return container_of(file->private_data, struct ssif_bmc_ctx, miscdev); > > > +} > > > +#endif /* __SSIF_BMC_H__ */ > > > -- > > > 2.35.1 > > > > > > From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id E7F3BC433EF for ; Thu, 17 Mar 2022 13:15:47 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:Reply-To:List-Subscribe:List-Help: List-Post:List-Archive:List-Unsubscribe:List-Id:In-Reply-To:MIME-Version: References:Message-ID:Subject:Cc:To:From:Date:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=VaLq1sJW2MAK+i8jrComgLAoDEPmwI9iI3djSlf/5QU=; b=ZCK8Tg0yjOsQj2 icH65swDYHo2Y5zJG5wXBaOIjZXkGsu7Tc2A+7cXFSn8gUtuT+x+hUnohKH+oVC5bLp1LvN/jyRAa Y3y9V2IA5DaSaYz8YYwtDCNKNtM+ZbxWRUyyKeWyBzVYzq4f6wUg+VEZsae6Inr7OVS/OYnuQw5OO sE3hIiqXvHRZKZemsY5yPeX0lJHBQrJpn6qZchKDnaOZf6kFBmmyB1Qv7AD7GcL9jgxu2qkq0rrMr 3f3xUwVPetESzvX10FuSIu3svz3pVCQTaXVGpgj69VRraVHvteop0Zh/RIWbHH4fOD0bBSBpLiCXK hOfMOfLNnDVQkaFC1UJg==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1nUpxG-00GCtB-Gb; Thu, 17 Mar 2022 13:14:14 +0000 Received: from mail-qk1-x72a.google.com ([2607:f8b0:4864:20::72a]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1nUpxB-00GCrx-0U for linux-arm-kernel@lists.infradead.org; Thu, 17 Mar 2022 13:14:12 +0000 Received: by mail-qk1-x72a.google.com with SMTP id s16so4268044qks.4 for ; Thu, 17 Mar 2022 06:14:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=sender:date:from:to:cc:subject:message-id:reply-to:references :mime-version:content-disposition:content-transfer-encoding :in-reply-to; bh=eWle4zbRf1n3H9JH+hlY46qvlaTRjOJL9WeucImHHOg=; b=nQ9VUi9sYyhAlmOegG+gL9U+A+k4L0h3YbQdoECtJViy3ucmZmKvZbk1M0lo+zElvW P9QSK1XhNmYuYVYGUa4pn2HOk/+sPmEIyA8nJj1ORGBwTzypv/YjSfxjqBBv6jn1eNeG 89VNacmyZlqb1Uypy/SZJdjFDbtbS6s0lYo93muJrNmZ3/2jvRBimBDe0cievdvHo+Z8 3xD6agc2lgghKoxsnMGk5BQTXecQgdNI+v1T7rxp+u0WV0oQrU5/puPU1EwhqTDoG1So Tb1r1r0sN/GtE8Oz4B01M5OFORYzkn6/F7euKMNyobLT1mwrOVYUzoP29R3AHyy5Qqa+ 2pKw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:sender:date:from:to:cc:subject:message-id :reply-to:references:mime-version:content-disposition :content-transfer-encoding:in-reply-to; bh=eWle4zbRf1n3H9JH+hlY46qvlaTRjOJL9WeucImHHOg=; b=BBqA12nHbWDp6KudZpUETHLNoYloOe4HkG9m9Ze3XyfLc/4OcMwAgpbBY1GS5fK7TR wTqw7F+j9VkxDb0mMj7vMYNoihCKQAuLg2Y1fAr6nVGmoTDo5hnGIz9JcqEO1IeT76Ob zKnhnDzLiudpa/5BAD3zkIhY3dvvjqXGUy5hz7uaXuxNQ2IMeZvGhx9c/QoWr5/R3Y0+ oIqDTEgJJZKAmM7l1cgo081FF5bbRXCM38Schyp3kD5sXBObNA9V5BgueWvpUmkjSXKA QIfLq+0i9bQEE+Tt9iHwve9QLPHsFDDDLbeOpy32tyRHa6Tm/+LG6SelgXPubrV3ZZN6 SQDA== X-Gm-Message-State: AOAM530gMM4F6IwkMCsV9CCV4S36fLvju9KnTPY4szfPgwl520YYwbDV Zxy8O7MmtxapzI8KD7J5Qg== X-Google-Smtp-Source: ABdhPJyjMKdRe3h0gF9p5mD85cMhaUnlFewNeqxPQzyz5DcwwNrVVLR63pDXDdHBePDcGgad/48sdA== X-Received: by 2002:a05:620a:271d:b0:67d:bb5f:8a7d with SMTP id b29-20020a05620a271d00b0067dbb5f8a7dmr2684691qkp.154.1647522844635; Thu, 17 Mar 2022 06:14:04 -0700 (PDT) Received: from serve.minyard.net (serve.minyard.net. [2001:470:b8f6:1b::1]) by smtp.gmail.com with ESMTPSA id j67-20020a37b946000000b0067b221281dbsm2445827qkf.99.2022.03.17.06.13.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 17 Mar 2022 06:13:59 -0700 (PDT) Received: from minyard.net (unknown [IPv6:2001:470:b8f6:1b:797c:2e79:7998:93c9]) by serve.minyard.net (Postfix) with ESMTPSA id 43EEA180004; Thu, 17 Mar 2022 13:13:57 +0000 (UTC) Date: Thu, 17 Mar 2022 08:13:56 -0500 From: Corey Minyard To: Quan Nguyen Cc: Rob Herring , Krzysztof Kozlowski , Joel Stanley , Andrew Jeffery , Brendan Higgins , Benjamin Herrenschmidt , Wolfram Sang , openipmi-developer@lists.sourceforge.net, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-aspeed@lists.ozlabs.org, linux-kernel@vger.kernel.org, linux-i2c@vger.kernel.org, openbmc@lists.ozlabs.org, Open Source Submission , Phong Vo , "Thang Q . Nguyen" Subject: Re: [PATCH v6 1/4] ipmi: ssif_bmc: Add SSIF BMC driver Message-ID: <20220317131356.GC3457@minyard.net> References: <20220310114119.13736-1-quan@os.amperecomputing.com> <20220310114119.13736-2-quan@os.amperecomputing.com> <20220311011942.GX3457@minyard.net> <569f50d5-8f13-280e-b944-6e26d95dc50b@os.amperecomputing.com> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <569f50d5-8f13-280e-b944-6e26d95dc50b@os.amperecomputing.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20220317_061409_137762_924C2884 X-CRM114-Status: GOOD ( 54.42 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: minyard@acm.org Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: base64 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org c25pcC4uLgo+ID4gPiArCj4gPiA+ICtzdGF0aWMgdm9pZCByZXNwb25zZV90aW1lb3V0KHN0cnVj dCB0aW1lcl9saXN0ICp0KQo+ID4gPiArewo+ID4gPiArCXN0cnVjdCBzc2lmX2JtY19jdHggKnNz aWZfYm1jID0gZnJvbV90aW1lcihzc2lmX2JtYywgdCwgcmVzcG9uc2VfdGltZXIpOwo+ID4gPiAr CXVuc2lnbmVkIGxvbmcgZmxhZ3M7Cj4gPiA+ICsKPiA+IAo+ID4gSXMgdGhlcmUgYSBwb3NzaWJs ZSByYWNlIGhlcmU/ICBUaGUgdGltZW91dCBjYW4gaGFwcGVuIGF0IHRoZSBzYW1lIHRpbWUKPiA+ IGFzIGEgcmVjZWl2ZWQgbWVzc2FnZSwgd2lsbCBzb21ldGhpbmcgYmFkIGhhcHBlbiBpZiB0aGF0 J3MgdGhlIGNhc2U/Cj4gPiAKPiAKPiBUaGFua3MgQ29yZXksCj4gSSB0aGluayBJIG5lZWQgZXh0 cmEgY29tbWVudCBoZXJlLgo+IAo+IFRoZSBwdXJwb3NlIG9mIHRoaXMgdGltZW91dCBpcyB0byBt YWtlIHN1cmUgc3NpZl9ibWMgd2lsbCByZWNvdmVyIGZyb20gYnVzeQo+IHN0YXRlIGluIGNhc2Ug dGhlIHVwcGVyIHN0YWNrIGRvZXMgbm90IHByb3ZpZGUgdGhlIHJlc3BvbnNlLgo+IEhlbmNlLCB0 aGUgcmVzcG9uc2UgdGltZW91dCBpcyBzZXQgYXMgNTAwbXMsIHR3aWNlIHRoZSB0aW1lIG9mIG1h eAo+IFJlcXVlc3QtdG8tUmVzcG9uc2UgaW4gc3BlYyBhcyB0aGUgY29kZSBiZWxvdy4gU2hvdWxk IGl0IGJlIGxvbmdlcj8KClRoYXQncyBub3Qgd2hhdCBJIHdhcyBhc2tpbmcuICBJIGtub3cgd2hh dCB0aGUgdGltZXIgaXMgZm9yLiAgQnV0IHdoYXQKaGFwcGVucyBpZiB0aGUgcmVzcG9uc2UgY29t ZXMgaW4gYXQgdGhlIHNhbWUgdGltZSB0aGlzIHRpbWVyIGdvZXMgb2ZmPwpXaGF0IHdpbGwga2Vl cCB0aGUgZGF0YSBmcm9tIGdldHRpbmcgbWVzc2VkIHVwPwoKPiAKPiBBcyBwZXIgc3BlYywgdGhl IG1heCBSZXF1ZXN0LXRvLVJlc3Bvc2Ugd291bGQgbm90IGV4Y2VlZCAyNTBtcy4KPiAKPiBJIHB1 dCB0aGUgY29tbWVudCBpbiBzc2lmX2JtYy5oIGFzIGJlbG93Ogo+ID4+ICsvKgo+ID4+ICsgKiBJ UE1JIDIuMCBTcGVjLCBzZWN0aW9uIDEyLjcgU1NJRiBUaW1pbmcsCj4gPj4gKyAqIFJlcXVlc3Qt dG8tUmVzcG9uc2UgVGltZSBpcyBUNm1heCgyNTBtcykgLSBUMW1heCgyMG1zKSAtIDNtcyA9IDIy N21zCj4gPj4gKyAqIFJlY292ZXIgc3NpZl9ibWMgZnJvbSBidXN5IHN0YXRlIGlmIGl0IHRha2Vz IHVwdG8gNTAwbXMKPiA+PiArICovCj4gPj4gKyNkZWZpbmUgUkVTUE9OU0VfVElNRU9VVAkJCTUw MCAvKiBtcyAqLwo+IAo+IAo+ID4gPiArCXNwaW5fbG9ja19pcnFzYXZlKCZzc2lmX2JtYy0+bG9j aywgZmxhZ3MpOwo+ID4gPiArCj4gPiA+ICsJLyogUmVjb3ZlciBzc2lmX2JtYyBmcm9tIGJ1c3kg Ki8KPiA+ID4gKwlzc2lmX2JtYy0+YnVzeSA9IGZhbHNlOwo+ID4gPiArCWRlbF90aW1lcigmc3Np Zl9ibWMtPnJlc3BvbnNlX3RpbWVyKTsKPiA+IAo+ID4gWW91IGRvbid0IG5lZWQgdG8gZGVsZXRl IHRoZSB0aW1lciwgaXQncyBpbiB0aGUgdGltZW91dC4KPiA+IAo+IAo+IFdpbGwgcmVtb3ZlIHRo aXMgcmVkdW5kYW50IGNvZGUgaW4gbmV4dCB2ZXJzaW9uCj4gCj4gPiA+ICsJc3NpZl9ibWMtPnJl c3BvbnNlX3RpbWVyX2luaXRlZCA9IGZhbHNlOwo+ID4gPiArCj4gPiA+ICsJc3Bpbl91bmxvY2tf aXJxcmVzdG9yZSgmc3NpZl9ibWMtPmxvY2ssIGZsYWdzKTsKPiA+ID4gK30KPiA+ID4gKwo+ID4g PiArLyogQ2FsbGVkIHdpdGggc3NpZl9ibWMtPmxvY2sgaGVsZC4gKi8KPiA+ID4gK3N0YXRpYyB2 b2lkIGhhbmRsZV9yZXF1ZXN0KHN0cnVjdCBzc2lmX2JtY19jdHggKnNzaWZfYm1jKQo+ID4gPiAr ewo+ID4gPiArCS8qIHNldCBzc2lmX2JtYyB0byBidXN5IHdhaXRpbmcgZm9yIHJlc3BvbnNlICov Cj4gPiA+ICsJc3NpZl9ibWMtPmJ1c3kgPSB0cnVlOwo+ID4gPiArCj4gPiA+ICsJLyogUmVxdWVz dCBtZXNzYWdlIGlzIGF2YWlsYWJsZSB0byBwcm9jZXNzICovCj4gPiA+ICsJc3NpZl9ibWMtPnJl cXVlc3RfYXZhaWxhYmxlID0gdHJ1ZTsKPiA+ID4gKwo+ID4gPiArCS8qIENsZWFuIG9sZCByZXNw b25zZSBidWZmZXIgKi8KPiA+ID4gKwltZW1zZXQoJnNzaWZfYm1jLT5yZXNwb25zZSwgMCwgc2l6 ZW9mKHN0cnVjdCBzc2lmX21zZykpOwo+ID4gPiArCj4gPiA+ICsJLyogVGhpcyBpcyB0aGUgbmV3 IFJFQUQgcmVxdWVzdC4qLwo+ID4gPiArCXdha2VfdXBfYWxsKCZzc2lmX2JtYy0+d2FpdF9xdWV1 ZSk7Cj4gPiA+ICsKPiA+ID4gKwkvKiBBcm1lZCB0aW1lciB0byByZWNvdmVyIHNsYXZlIGZyb20g YnVzeSBzdGF0ZSBpbiBjYXNlIG9mIG5vIHJlc3BvbnNlICovCj4gPiA+ICsJaWYgKCFzc2lmX2Jt Yy0+cmVzcG9uc2VfdGltZXJfaW5pdGVkKSB7Cj4gPiA+ICsJCXRpbWVyX3NldHVwKCZzc2lmX2Jt Yy0+cmVzcG9uc2VfdGltZXIsIHJlc3BvbnNlX3RpbWVvdXQsIDApOwo+ID4gPiArCQlzc2lmX2Jt Yy0+cmVzcG9uc2VfdGltZXJfaW5pdGVkID0gdHJ1ZTsKPiA+ID4gKwl9Cj4gPiA+ICsJbW9kX3Rp bWVyKCZzc2lmX2JtYy0+cmVzcG9uc2VfdGltZXIsIGppZmZpZXMgKyBtc2Vjc190b19qaWZmaWVz KFJFU1BPTlNFX1RJTUVPVVQpKTsKPiA+ID4gK30KPiA+ID4gKwo+ID4gPiArc3RhdGljIHZvaWQg c2V0X211bHRpcGFydF9yZXNwb25zZV9idWZmZXIoc3RydWN0IHNzaWZfYm1jX2N0eCAqc3NpZl9i bWMsIHU4ICp2YWwpCj4gPiA+ICt7Cj4gPiA+ICsJdTggcmVzcG9uc2VfbGVuID0gMDsKPiA+ID4g KwlpbnQgaWR4ID0gMDsKPiA+ID4gKwl1OCBkYXRhX2xlbjsKPiA+ID4gKwo+ID4gPiArCWRhdGFf bGVuID0gc3NpZl9ibWMtPnJlc3BvbnNlLmxlbjsKPiA+ID4gKwlzd2l0Y2ggKHNzaWZfYm1jLT5z bWJ1c19jbWQpIHsKPiA+ID4gKwljYXNlIFNTSUZfSVBNSV9NVUxUSVBBUlRfUkVBRF9TVEFSVDoK PiA+ID4gKwkJLyoKPiA+ID4gKwkJICogUmVhZCBTdGFydCBsZW5ndGggaXMgMzIgYnl0ZXMuCj4g PiA+ICsJCSAqIFJlYWQgU3RhcnQgdHJhbnNmZXIgZmlyc3QgMzAgYnl0ZXMgb2YgSVBNSSByZXNw b25zZQo+ID4gPiArCQkgKiBhbmQgMiBzcGVjaWFsIGNvZGUgMHgwMCwgMHgwMS4KPiA+ID4gKwkJ ICovCj4gPiA+ICsJCSp2YWwgPSBNQVhfUEFZTE9BRF9QRVJfVFJBTlNBQ1RJT047Cj4gPiA+ICsJ CXNzaWZfYm1jLT5yZW1haW5fbGVuID0gZGF0YV9sZW4gLSBNQVhfSVBNSV9EQVRBX1BFUl9TVEFS VF9UUkFOU0FDVElPTjsKPiA+ID4gKwkJc3NpZl9ibWMtPmJsb2NrX251bSA9IDA7Cj4gPiAKPiA+ IERvIHlvdSBuZWVkIHRvIHZhbGlkYXRlIHRoZSBkYXRhIGxlbmd0aCBiZWZvcmUgdXNpbmcgdGhp cz8KPiA+IFRoaXMgYXBwbGllcyBmb3IgbG90cyBvZiBwbGFjZXMgdGhyb3VnaCBoZXJlLgo+ID4g Cj4gCj4gc2V0X211bHRpcGFydF9yZXNwb25zZV9idWZmZXIoKSBpcyBjYWxsZWQgb25seSB3aGVu IC0+aXNfc2luZ2xlcGFydF9yZWFkIGlzCj4gZmFsc2UsIHdoaWNoIGlzIGRldGVybWluZWQgYnkg dGhlIGJlbG93IGNvZGUgdW5kZXIgdGhlICpfd3JpdGUoKQo+IAo+IHNzaWZfYm1jLT5pc19zaW5n bGVwYXJ0X3JlYWQgPSAoc3NpZl9tc2dfbGVuKCZtc2cpIDw9Cj4gTUFYX1BBWUxPQURfUEVSX1RS QU5TQUNUSU9OICsgMSk7Cj4gCj4gU28sIEkgdGhpbmsgdGhlIGxlbiBpcyB2YWxpZGF0ZWQgYW5k IGNvdWxkIGJlIHVzZSBpbiB0aGlzIGZ1bmN0aW9ucy4KCkFoLCBJIGhhZCB0aGluZ3MgYmFja3dh cmRzLiAgIlJlYWQiIGhlcmUgaXMgd2hlbiB5b3UgYXJlIHdyaXRpbmcgdG8KdGhlIG90aGVyIHNp ZGUuICBJIHVuZGVyc3RhbmQgbm93LgoKPiAKPiA+ID4gKwo+ID4gPiArCQlzc2lmX2JtYy0+cmVz cG9uc2VfYnVmW2lkeCsrXSA9IDB4MDA7IC8qIFN0YXJ0IEZsYWcgKi8KPiA+ID4gKwkJc3NpZl9i bWMtPnJlc3BvbnNlX2J1ZltpZHgrK10gPSAweDAxOyAvKiBTdGFydCBGbGFnICovCj4gPiA+ICsJ CXNzaWZfYm1jLT5yZXNwb25zZV9idWZbaWR4KytdID0gc3NpZl9ibWMtPnJlc3BvbnNlLm5ldGZu X2x1bjsKPiA+ID4gKwkJc3NpZl9ibWMtPnJlc3BvbnNlX2J1ZltpZHgrK10gPSBzc2lmX2JtYy0+ cmVzcG9uc2UuY21kOwo+ID4gPiArCQlzc2lmX2JtYy0+cmVzcG9uc2VfYnVmW2lkeCsrXSA9IHNz aWZfYm1jLT5yZXNwb25zZS5wYXlsb2FkWzBdOwo+ID4gPiArCj4gPiA+ICsJCXJlc3BvbnNlX2xl biA9IE1BWF9QQVlMT0FEX1BFUl9UUkFOU0FDVElPTiAtIGlkeDsKPiA+ID4gKwo+ID4gPiArCQlt ZW1jcHkoJnNzaWZfYm1jLT5yZXNwb25zZV9idWZbaWR4XSwgJnNzaWZfYm1jLT5yZXNwb25zZS5w YXlsb2FkWzFdLAo+ID4gPiArCQkgICAgICAgcmVzcG9uc2VfbGVuKTsKPiA+ID4gKwkJYnJlYWs7 Cj4gPiA+ICsKPiA+ID4gKwljYXNlIFNTSUZfSVBNSV9NVUxUSVBBUlRfUkVBRF9NSURETEU6Cj4g PiA+ICsJCS8qCj4gPiA+ICsJCSAqIElQTUkgUkVBRCBNaWRkbGUgb3IgUkVBRCBFbmQgbWVzc2Fn ZXMgY2FuIGNhcnJ5IHVwIHRvIDMxIGJ5dGVzCj4gPiA+ICsJCSAqIElQTUkgZGF0YSBwbHVzIGJs b2NrIG51bWJlciBieXRlLgo+ID4gPiArCQkgKi8KPiA+ID4gKwkJaWYgKHNzaWZfYm1jLT5yZW1h aW5fbGVuIDwgTUFYX0lQTUlfREFUQV9QRVJfTUlERExFX1RSQU5TQUNUSU9OKSB7Cj4gPiA+ICsJ CQkvKgo+ID4gPiArCQkJICogVGhpcyBpcyBSRUFEIEVuZCBtZXNzYWdlCj4gPiA+ICsJCQkgKiAg UmV0dXJuIGxlbmd0aCBpcyB0aGUgcmVtYWluaW5nIHJlc3BvbnNlIGRhdGEgbGVuZ3RoCj4gPiA+ ICsJCQkgKiAgcGx1cyBibG9jayBudW1iZXIKPiA+ID4gKwkJCSAqICBCbG9jayBudW1iZXIgMHhG RiBpcyB0byBpbmRpY2F0ZSB0aGlzIGlzIGxhc3QgbWVzc2FnZQo+ID4gPiArCQkJICoKPiA+ID4g KwkJCSAqLwo+ID4gPiArCQkJKnZhbCA9IHNzaWZfYm1jLT5yZW1haW5fbGVuICsgMTsKPiA+ID4g KwkJCXNzaWZfYm1jLT5ibG9ja19udW0gPSAweEZGOwo+ID4gPiArCQkJc3NpZl9ibWMtPnJlc3Bv bnNlX2J1ZltpZHgrK10gPSBzc2lmX2JtYy0+YmxvY2tfbnVtOwo+ID4gPiArCQkJcmVzcG9uc2Vf bGVuID0gc3NpZl9ibWMtPnJlbWFpbl9sZW47Cj4gPiA+ICsJCQkvKiBDbGVhbiB0aGUgYnVmZmVy ICovCj4gPiA+ICsJCQltZW1zZXQoJnNzaWZfYm1jLT5yZXNwb25zZV9idWZbaWR4XSwgMCwgTUFY X1BBWUxPQURfUEVSX1RSQU5TQUNUSU9OIC0gaWR4KTsKPiA+ID4gKwkJfSBlbHNlIHsKPiA+ID4g KwkJCS8qCj4gPiA+ICsJCQkgKiBUaGlzIGlzIFJFQUQgTWlkZGxlIG1lc3NhZ2UKPiA+ID4gKwkJ CSAqICBSZXNwb25zZSBsZW5ndGggaXMgdGhlIG1heGltdW0gU01CVVMgdHJhbnNmZXIgbGVuZ3Ro Cj4gPiA+ICsJCQkgKiAgQmxvY2sgbnVtYmVyIGJ5dGUgaXMgaW5jcmVtZW50ZWQKPiA+ID4gKwkJ CSAqIFJldHVybiBsZW5ndGggaXMgbWF4aW11bSBTTUJVUyB0cmFuc2ZlciBsZW5ndGgKPiA+ID4g KwkJCSAqLwo+ID4gPiArCQkJKnZhbCA9IE1BWF9QQVlMT0FEX1BFUl9UUkFOU0FDVElPTjsKPiA+ ID4gKwkJCXNzaWZfYm1jLT5yZW1haW5fbGVuIC09IE1BWF9JUE1JX0RBVEFfUEVSX01JRERMRV9U UkFOU0FDVElPTjsKPiA+ID4gKwkJCXJlc3BvbnNlX2xlbiA9IE1BWF9JUE1JX0RBVEFfUEVSX01J RERMRV9UUkFOU0FDVElPTjsKPiA+ID4gKwkJCXNzaWZfYm1jLT5yZXNwb25zZV9idWZbaWR4Kytd ID0gc3NpZl9ibWMtPmJsb2NrX251bTsKPiA+ID4gKwkJCXNzaWZfYm1jLT5ibG9ja19udW0rKzsK PiA+ID4gKwkJfQo+ID4gPiArCj4gPiA+ICsJCW1lbWNweSgmc3NpZl9ibWMtPnJlc3BvbnNlX2J1 ZltpZHhdLAo+ID4gPiArCQkgICAgICAgc3NpZl9ibWMtPnJlc3BvbnNlLnBheWxvYWQgKyAxICsg c3NpZl9ibWMtPm5ieXRlc19wcm9jZXNzZWQsCj4gPiA+ICsJCSAgICAgICByZXNwb25zZV9sZW4p Owo+ID4gPiArCQlicmVhazsKPiA+ID4gKwo+ID4gPiArCWRlZmF1bHQ6Cj4gPiA+ICsJCS8qIERv IG5vdCBleHBlY3QgdG8gZ28gdG8gdGhpcyBjYXNlICovCj4gPiA+ICsJCWRldl9lcnIoJnNzaWZf Ym1jLT5jbGllbnQtPmRldiwKPiA+ID4gKwkJCSIlczogVW5leHBlY3RlZCBTTUJ1cyBjb21tYW5k IDB4JXhcbiIsCj4gPiA+ICsJCQlfX2Z1bmNfXywgc3NpZl9ibWMtPnNtYnVzX2NtZCk7Cj4gPiA+ ICsJCWJyZWFrOwo+ID4gPiArCX0KPiA+ID4gKwo+ID4gPiArCXNzaWZfYm1jLT5uYnl0ZXNfcHJv Y2Vzc2VkICs9IHJlc3BvbnNlX2xlbjsKPiA+ID4gK30KPiA+ID4gKwo+ID4gPiArLyogUHJvY2Vz cyB0aGUgSVBNSSByZXNwb25zZSB0aGF0IHdpbGwgYmUgcmVhZCBieSBtYXN0ZXIgKi8KPiA+ID4g K3N0YXRpYyB2b2lkIGhhbmRsZV9yZWFkX3Byb2Nlc3NlZChzdHJ1Y3Qgc3NpZl9ibWNfY3R4ICpz c2lmX2JtYywgdTggKnZhbCkKPiA+ID4gK3sKPiA+ID4gKwl1OCAqYnVmOwo+ID4gPiArCXU4IHBl Y19sZW4sIGFkZHIsIGxlbjsKPiA+ID4gKwl1OCBwZWMgPSAwOwo+ID4gPiArCj4gPiA+ICsJcGVj X2xlbiA9IHNzaWZfYm1jLT5wZWNfc3VwcG9ydCA/IDEgOiAwOwo+ID4gPiArCS8qIFBFQyAtIFN0 YXJ0IFJlYWQgQWRkcmVzcyAqLwo+ID4gPiArCWFkZHIgPSBHRVRfOEJJVF9BRERSKHNzaWZfYm1j LT5jbGllbnQtPmFkZHIpOwo+ID4gPiArCXBlYyA9IGkyY19zbWJ1c19wZWMocGVjLCAmYWRkciwg MSk7Cj4gPiA+ICsJLyogUEVDIC0gU1NJRiBDb21tYW5kICovCj4gPiA+ICsJcGVjID0gaTJjX3Nt YnVzX3BlYyhwZWMsICZzc2lmX2JtYy0+c21idXNfY21kLCAxKTsKPiA+ID4gKwkvKiBQRUMgLSBS ZXN0YXJ0IFdyaXRlIEFkZHJlc3MgKi8KPiA+ID4gKwlhZGRyID0gYWRkciB8IDB4MDE7Cj4gPiA+ ICsJcGVjID0gaTJjX3NtYnVzX3BlYyhwZWMsICZhZGRyLCAxKTsKPiA+ID4gKwo+ID4gPiArCWlm IChzc2lmX2JtYy0+aXNfc2luZ2xlcGFydF9yZWFkKSB7Cj4gPiA+ICsJCS8qIFNpbmdsZS1wYXJ0 IFJlYWQgcHJvY2Vzc2luZyAqLwo+ID4gPiArCQlidWYgPSAodTggKikmc3NpZl9ibWMtPnJlc3Bv bnNlOwo+ID4gPiArCj4gPiA+ICsJCWlmIChzc2lmX2JtYy0+cmVzcG9uc2UubGVuICYmIHNzaWZf Ym1jLT5tc2dfaWR4IDwgc3NpZl9ibWMtPnJlc3BvbnNlLmxlbikgewo+ID4gPiArCQkJc3NpZl9i bWMtPm1zZ19pZHgrKzsKPiA+ID4gKwkJCSp2YWwgPSBidWZbc3NpZl9ibWMtPm1zZ19pZHhdOwo+ ID4gPiArCQl9IGVsc2UgaWYgKHNzaWZfYm1jLT5yZXNwb25zZS5sZW4gJiYgc3NpZl9ibWMtPm1z Z19pZHggPT0gc3NpZl9ibWMtPnJlc3BvbnNlLmxlbikgewo+ID4gPiArCQkJc3NpZl9ibWMtPm1z Z19pZHgrKzsKPiA+ID4gKwkJCSp2YWwgPSBpMmNfc21idXNfcGVjKHBlYywgYnVmLCBzc2lmX21z Z19sZW4oJnNzaWZfYm1jLT5yZXNwb25zZSkpOwo+ID4gPiArCQl9IGVsc2Ugewo+ID4gCj4gPiBJ IHRob3VnaHQgZm9yIGEgc2Vjb25kIHRoYXQgdGhpcyB3YXMgd3JvbmcsIGJ1dCBJIHRoaW5rIGl0 J3MgY29ycmVjdC4KPiA+IFN1cHBseSB6ZXJvIGlmIHlvdSBkb24ndCBoYXZlIGRhdGEuCj4gPiAK PiA+ID4gKwkJCSp2YWwgPSAwOwo+ID4gPiArCQl9Cj4gPiA+ICsJCS8qIEludmFsaWRhdGUgcmVz cG9uc2UgYnVmZmVyIHRvIGRlbm90ZSBpdCBpcyBzZW50ICovCj4gPiA+ICsJCWlmIChzc2lmX2Jt Yy0+bXNnX2lkeCArIDEgPj0gKHNzaWZfbXNnX2xlbigmc3NpZl9ibWMtPnJlc3BvbnNlKSArIHBl Y19sZW4pKQo+ID4gPiArCQkJY29tcGxldGVfcmVzcG9uc2Uoc3NpZl9ibWMpOwo+ID4gPiArCX0g ZWxzZSB7Cj4gPiA+ICsJCS8qIE11bHRpLXBhcnQgUmVhZCBwcm9jZXNzaW5nICovCj4gPiAKPiA+ IFlvdSBkb24ndCBjaGVjayB0aGUgbGVuZ3RoIGhlcmUgbGlrZSB5b3UgZGlkIGFib3ZlLiAgSSB0 aGluayB0aGF0J3MKPiA+IHJlcXVpcmVkLgo+ID4gCj4gCj4gQXMgcGVyIG15IGV4cGxhbmF0aW9u IGFib3ZlLCB0aGUgLT5pc19zaW5nbGVwYXJ0X3JlYWQgaXMgZGV0ZXJtaW5lZCBieQo+IHRlc3Rp bmcgdGhlIGxlbmd0aCwgc28gaXQgaXMgdmFsaWRhdGVkIGFzIEkgYXNzdW1lZC4KPiAKPiA+ID4g KwkJc3dpdGNoIChzc2lmX2JtYy0+c21idXNfY21kKSB7Cj4gPiA+ICsJCWNhc2UgU1NJRl9JUE1J X01VTFRJUEFSVF9SRUFEX1NUQVJUOgo+ID4gPiArCQljYXNlIFNTSUZfSVBNSV9NVUxUSVBBUlRf UkVBRF9NSURETEU6Cj4gPiA+ICsJCQlidWYgPSAodTggKikmc3NpZl9ibWMtPnJlc3BvbnNlX2J1 ZjsKPiA+ID4gKwkJCSp2YWwgPSBidWZbc3NpZl9ibWMtPm1zZ19pZHhdOwo+ID4gPiArCQkJc3Np Zl9ibWMtPm1zZ19pZHgrKzsKPiA+ID4gKwkJCWJyZWFrOwo+ID4gPiArCQlkZWZhdWx0Ogo+ID4g PiArCQkJLyogRG8gbm90IGV4cGVjdCB0byBnbyB0byB0aGlzIGNhc2UgKi8KPiA+ID4gKwkJCWRl dl9lcnIoJnNzaWZfYm1jLT5jbGllbnQtPmRldiwKPiA+ID4gKwkJCQkiJXM6IFVuZXhwZWN0ZWQg U01CdXMgY29tbWFuZCAweCV4XG4iLAo+ID4gPiArCQkJCV9fZnVuY19fLCBzc2lmX2JtYy0+c21i dXNfY21kKTsKPiA+ID4gKwkJCWJyZWFrOwo+ID4gPiArCQl9Cj4gPiA+ICsKPiA+ID4gKwkJbGVu ID0gKHNzaWZfYm1jLT5ibG9ja19udW0gPT0gMHhGRikgPwo+ID4gPiArCQkgICAgICAgc3NpZl9i bWMtPnJlbWFpbl9sZW4gKyAxIDogTUFYX1BBWUxPQURfUEVSX1RSQU5TQUNUSU9OOwo+ID4gPiAr CQlpZiAoc3NpZl9ibWMtPm1zZ19pZHggPT0gKGxlbiArIDEpKSB7Cj4gPiA+ICsJCQlwZWMgPSBp MmNfc21idXNfcGVjKHBlYywgJmxlbiwgMSk7Cj4gPiA+ICsJCQkqdmFsID0gaTJjX3NtYnVzX3Bl YyhwZWMsIHNzaWZfYm1jLT5yZXNwb25zZV9idWYsIGxlbik7Cj4gPiA+ICsJCX0KPiA+ID4gKwkJ LyogSW52YWxpZGF0ZSByZXNwb25zZSBidWZmZXIgdG8gZGVub3RlIGxhc3QgcmVzcG9uc2UgaXMg c2VudCAqLwo+ID4gPiArCQlpZiAoc3NpZl9ibWMtPmJsb2NrX251bSA9PSAweEZGICYmCj4gPiA+ ICsJCSAgICBzc2lmX2JtYy0+bXNnX2lkeCA+IChzc2lmX2JtYy0+cmVtYWluX2xlbiArIHBlY19s ZW4pKSB7Cj4gPiA+ICsJCQljb21wbGV0ZV9yZXNwb25zZShzc2lmX2JtYyk7Cj4gPiA+ICsJCX0K PiA+ID4gKwl9Cj4gPiA+ICt9Cj4gPiA+ICsKPiA+ID4gK3N0YXRpYyB2b2lkIGhhbmRsZV93cml0 ZV9yZWNlaXZlZChzdHJ1Y3Qgc3NpZl9ibWNfY3R4ICpzc2lmX2JtYywgdTggKnZhbCkKPiA+ID4g K3sKPiA+ID4gKwl1OCAqYnVmID0gKHU4ICopJnNzaWZfYm1jLT5yZXF1ZXN0Owo+ID4gPiArCj4g PiA+ICsJaWYgKHNzaWZfYm1jLT5tc2dfaWR4ID49IHNpemVvZihzdHJ1Y3Qgc3NpZl9tc2cpKQo+ ID4gPiArCQlyZXR1cm47CgpJIGRvbid0IHRoaW5rIHRoaXMgY2hlY2sgaXMgdmFsaWQuICBJIGJl bGlldmUgdGhlIG1zZ19pZHggb25seSBjb3ZlcnMKdGhlIGN1cnJlbnQgbWVzc2FnZSwgYnV0IHNz aWZfbXNnIGlzIGEgZnVsbCBtdWx0aS1wYXJ0IG1lc3NhZ2UuICBJdApjb3ZlcnMgdGhlIHNpbmds ZS1wYXJ0IG1lc3NhZ2UsIEkgdGhpbmsgYnV0IG5vdCB0aGUgbXVsdGktcGFydCBvbmVzLgpBbHNv LCBhYm9ydCB0aGUgb3BlcmF0aW9uIGFuZCBsb2cgb24gYmFkIGRhdGEuCgo+ID4gPiArCj4gPiA+ ICsJc3dpdGNoIChzc2lmX2JtYy0+c21idXNfY21kKSB7Cj4gPiA+ICsJY2FzZSBTU0lGX0lQTUlf U0lOR0xFUEFSVF9XUklURToKPiA+ID4gKwkJYnVmW3NzaWZfYm1jLT5tc2dfaWR4IC0gMV0gPSAq dmFsOwo+ID4gPiArCQlzc2lmX2JtYy0+bXNnX2lkeCsrOwo+ID4gPiArCj4gPiA+ICsJCWJyZWFr Owo+ID4gPiArCWNhc2UgU1NJRl9JUE1JX01VTFRJUEFSVF9XUklURV9TVEFSVDoKPiA+ID4gKwkJ aWYgKHNzaWZfYm1jLT5tc2dfaWR4ID09IDEpCj4gPiA+ICsJCQlzc2lmX2JtYy0+cmVxdWVzdC5s ZW4gPSAwOwo+ID4gPiArCj4gPiA+ICsJCWZhbGx0aHJvdWdoOwo+ID4gPiArCWNhc2UgU1NJRl9J UE1JX01VTFRJUEFSVF9XUklURV9NSURETEU6Cj4gPiA+ICsJCS8qIFRoZSBsZW4gc2hvdWxkIGFs d2F5cyBiZSAzMiAqLwo+ID4gPiArCQlpZiAoc3NpZl9ibWMtPm1zZ19pZHggPT0gMSAmJiAqdmFs ICE9IE1BWF9QQVlMT0FEX1BFUl9UUkFOU0FDVElPTikKPiA+ID4gKwkJCWRldl93YXJuKCZzc2lm X2JtYy0+Y2xpZW50LT5kZXYsCj4gPiA+ICsJCQkJICJXYXJuOiBJbnZhbGlkIE11bHRpcGFydCBX cml0ZSBsZW4iKTsKCllvdSBzaG91bGQgYWJvcnQgdGhlIG9wZXJhdGlvbiBoZXJlLiAgRG9uJ3Qg ZGVsaXZlciBvYnZpb3VzbHkgYmFkIGRhdGEuClNhbWUgaW4gdGhlIGNvZGUganVzdCBiZWxvdy4K ClRoaXMgd2lsbCByZXF1aXJlIHRoYXQgeW91IGFkZCBhIG1lc3NhZ2UgYWJvcnRlZCB0eXBlIG9m IHN0YXRlIHRvIGp1c3QKaWdub3JlIGV2ZXJ5dGhpbmcgdGhhdCBjb21lcyBpbiB1bnRpbCB0aGUg ZnVsbCBzZXF1ZW5jZSBlbmRzIG9yIGEgbmV3Cm1lc3NhZ2Ugc3RhcnRzLgoKPiA+ID4gKwo+ID4g PiArCQlmYWxsdGhyb3VnaDsKPiA+ID4gKwljYXNlIFNTSUZfSVBNSV9NVUxUSVBBUlRfV1JJVEVf RU5EOgo+ID4gPiArCQkvKiBNdWx0aS1wYXJ0IHdyaXRlLCAybmQgYnl0ZSByZWNlaXZlZCBpcyBs ZW5ndGggKi8KPiA+ID4gKwkJaWYgKHNzaWZfYm1jLT5tc2dfaWR4ID09IDEpIHsKPiA+ID4gKwkJ CWlmICgqdmFsID4gTUFYX1BBWUxPQURfUEVSX1RSQU5TQUNUSU9OKQo+ID4gPiArCQkJCWRldl93 YXJuKCZzc2lmX2JtYy0+Y2xpZW50LT5kZXYsCj4gPiA+ICsJCQkJCSAiV2FybjogSW52YWxpZCBN dWx0aXBhcnQgV3JpdGUgRW5kIGxlbiIpOwo+ID4gPiArCj4gPiA+ICsJCQlzc2lmX2JtYy0+cmVx dWVzdC5sZW4gKz0gKnZhbDsKPiA+ID4gKwkJCXNzaWZfYm1jLT5yZWN2X2xlbiA9ICp2YWw7Cj4g PiA+ICsKPiA+ID4gKwkJCS8qIHJlcXVlc3QgbGVuIHNob3VsZCBuZXZlciBleGNlZWRlZCAyNTUg Ynl0ZXMgKi8KPiA+ID4gKwkJCWlmIChzc2lmX2JtYy0+cmVxdWVzdC5sZW4gPiAyNTUpCj4gPiA+ ICsJCQkJZGV2X3dhcm4oJnNzaWZfYm1jLT5jbGllbnQtPmRldiwKPiA+ID4gKwkJCQkJICJXYXJu OiBJbnZhbGlkIHJlcXVlc3QgbGVuIik7Cj4gPiA+ICsKPiA+ID4gKwkJfSBlbHNlIHsKPiA+IAo+ ID4gWW91IGNoZWNrIG1zZ19pZHggYWJvdmUsIGJ1dCBJJ20gbm90IHN1cmUgdGhhdCBjaGVjayB3 aWxsIGNvdmVyIHRoaXMKPiA+IG9wZXJhdGlvbi4KPiA+IAo+IFRoYXQgY2hlY2sgaXMgdG8gbWFr ZSBzdXJlIHRoZSBsZW5ndGggKCp2YWwpIG11c3QgYWx3YXlzIGJlIHN0cmljdGx5IDMyCj4gYnl0 ZXMgaW4gY2FzZSBvZiBNVUxUSVBBUlRfV1JJVEVfU1RBUlQvTUlERExFLiBBbmQgdGhpcyBjaGVj ayBhbGxvd3MgdGhlCj4gbGVuZ3RoIGlzIHVwIHRvIDMyIGJ5dGVzIGluIE1VTFRJUEFSVF9XUklU RV9FTkQuCgpOb3cgdGhhdCBJIGhhdmUgcmVhZCBhbmQgd3JpdGUgc3RyYWlnaHQsIHRoaXMgaXMg d2hlcmUgdGhlIHByZXZpb3VzCmNvbW1lbnRzIGFwcGx5LgoKWW91IGFyZSB0cnVzdGluZyB0aGUg dGhlIGxlbmd0aCBzZW50IGJ5IHRoZSByZW1vdGUgZW5kIGluIHRoZSBzZWNvbmQKYnl0ZSBpcyBj b3JyZWN0LCBidXQgdGhlcmUgaXMgbm8gZ3VhcmFudGVlIG9mIHRoaXMuICBUaGUgcmVtb3RlIGVu ZCBjYW4Kc2VuZCBhcyBtYW55IGJ5dGVzIGFzIGl0IGxpa2VzLiAgWW91IG5lZWQgdG8gY2hlY2sg dGhhdCB5b3UgZG9uJ3QKb3ZlcmZsb3cgYnVmIGhlcmUgYW5kIHRoYXQgaXQgYWN0dWFsbHkgc2Vu ZHMgdGhlIG51bWJlciBvZiBieXRlcyB0aGF0IGl0CnNhaWQgaXQgd2FzIGdvaW5nIHRvIHNlbmQg dG8gYXZvaWQgdW5kZXJmbG93LgoKPiAKPiA+ID4gKwkJCWJ1Zltzc2lmX2JtYy0+bXNnX2lkeCAt IDEgKwo+ID4gPiArCQkJICAgIHNzaWZfYm1jLT5yZXF1ZXN0LmxlbiAtIHNzaWZfYm1jLT5yZWN2 X2xlbl0JPSAqdmFsOwoKVGhpcyBjb21wdXRhdGlvbiBpcyBmYWlybHkgY29tcGxpY2F0ZWQgYW5k IGhhcmQgdG8gdW5kZXJzdGFuZC4KQ2FsY3VsYXRpb25zIGxpa2UgdGhpcyBhcmUgYXNraW5nIGZv ciB0cm91YmxlLgoKSXQgd291bGQgYmUgZWFzaWVyIHRvIHVuZGVyc3RhbmQgaGFkIHJlcXVlc3Qu bGVuIGJlIHRoZSBjdXJyZW50IGxlbmd0aApvZiB3aGF0IGlzIGluIHJlcXVlc3QucGF5bG9hZCBh bmQgaW5jcmVtZW50IGl0IG9uIGV2ZXJ5IGluY29taW5nIGJ5dGUuClRoZW4gcmVxdWVzdC5sZW4g Y291bGQgYmUgdXNlZCB0byBhZGQgZGF0YSB0byB0aGUgYnVmZmVyLCBsaWtlCgoJaWYgKHNzaWZf Ym1jLT5yZXF1ZXN0LmxlbiA+PSBzaXplb2Yoc3NpZl9ibWMtPnBheWxvYWQpKQoJCWVycm9yLi4u Cglzc2lmX2JtYy0+cGF5bG9hZFtzc2lmX2JtYy0+cmVxdWVzdC5sZW4rK10gPSAqdmFsOwoKSWYg eW91IHJlbmFtZWQgbXNnX2lkeCB0byBjdXJyX3JlY3ZfaWR4IGFuZCByZWN2X2xlbiB0byBjdXJy X3JlY3ZfbGVuLAppdCB3b3VsZCBiZSBtb3JlIGNsZWFyIHRoYXQgdGhlc2UgYXJlIHJlbGF0ZWQg YW5kIG9wZXJhdGUgb24gdGhlIGN1cnJlbnQKaW5jb21pbmcgbWVzc2FnZS4KCkl0IHdvdWxkIGFs c28gYmUgbmljZSB0byBnZXQgcmlkIG9mIHRoZSBjYXN0cyBmcm9tIHNzaWZfbXNnIHRvIGEgYnVm ZmVyCmFycmF5IGFuZCBqdXN0IGluZGV4IGRpcmVjdGx5IGludG8gcmVxdWVzdC5wYXlsb2FkW10u CgpJbiB0aGlua2luZyBhYm91dCB0aGlzIGZ1cnRoZXIsIEkgaGF2ZSBhIGZldyBtb3JlIG9ic2Vy dmF0aW9ucy4uLgoKVGhlcmUgaXMgbm8gbmVlZCB0byBoYXZlIHRoZSBuZXRmbiBhbmQgY21kIGlu IHNzaWZfbXNnLiAgVGhleSBhcmUganVzdAp0aGUgZmlyc3QgYW5kIHNlY29uZCBieXRlcyBvZiB0 aGUgbWVzc2FnZS4gIFlvdSBkb24ndCBjYXJlIHdoYXQgdGhleQphcmUgaW4gdGhpcyBjb2RlLgoK V2h5IGRvIHlvdSBkZWxpdmVyIHRoZSBsZW5ndGggYXMgcGFydCBvZiB0aGUgbWVzc2FnZSB0byB0 aGUgdXNlcj8gIFRoZQpsZW5ndGggaXMgcmV0dXJuZWQgYnkgdGhlIHN5c3RlbSBjYWxsLiAgWW91 IGhhdmUgYWxsIHRoZXNlICsxIGFuZCAtMQp0aGluZ3MgYXJvdW5kIHRoZSBtZXNzYWdlIGxlbmd0 aCwgd2hpY2ggaXMgZXJyb3ItcHJvbmUuICBSZW1vdmluZyB0aGUKbGVuZ3RoIGZyb20gdGhlIG1l c3NhZ2Ugd291bGQgZ2V0IHJpZCBvZiBhbGwgb2YgdGhhdC4gIEFuZCB1c2luZyBwYWNrZWQKc3Ry dWN0dXJlcyBpcyBnZW5lcmFsbHkgbm90IHRoZSBiZXN0LCBhbnl3YXkuCgpUaGUgUEVDIGNhbGN1 bGF0aW9ucyByZW1vdmUgb25lIGJ5dGUgZnJvbSB0aGUgbWF4aW11bSBtZXNzYWdlIGxlbmd0aC4K U2luY2UgdGhleSBhcmUgbm90IGluY2x1ZGVkIGluIHRoZSBsZW5ndGggYnl0ZSwgaXQncyBraW5k IG9mIHVubmF0dXJhbAp0byBkbyB0aGlzIHRoZSB3YXkgeW91IGFyZSBkb2luZyBpdC4gIEluc3Rl YWQsIGl0IG1pZ2h0IGJlIGJlc3QgdG8gc2F5CmlmIHlvdSByZWNlaXZlIGEgYnl0ZSBhbmQgY3Vy cl9yZWN2X2lkeCA9PSBjdXJyX3JlY3ZfbGVuLCBwcm9jZXNzIGl0CmFzIFBFQy4gIFRoYXQgd2F5 IHRoZSBQRUMgbmV2ZXIgaGl0cyB0aGUgYnVmZmVyLgoKVGhlcmUgaXMgbm8gbmVlZCBmb3IgbXNn X2lkeCwgb3IgY3VyX3JlY3ZfaWR4LCB0byBiZSBzaXplX3QuCgpJIG5lZWQgdG8gbG9vayBhdCB0 aGlzIHNvbWUgbW9yZSwgYnV0IEknbGwgbmVlZCB0byBzZWUgdGhlIHJld3JpdGUuCgotY29yZXkK Cj4gPiA+ICsJCX0KPiA+ID4gKwo+ID4gPiArCQlzc2lmX2JtYy0+bXNnX2lkeCsrOwo+ID4gPiAr Cj4gPiA+ICsJCWJyZWFrOwo+ID4gPiArCWRlZmF1bHQ6Cj4gPiA+ICsJCS8qIERvIG5vdCBleHBl Y3QgdG8gZ28gdG8gdGhpcyBjYXNlICovCj4gPiA+ICsJCWRldl9lcnIoJnNzaWZfYm1jLT5jbGll bnQtPmRldiwKPiA+ID4gKwkJCSIlczogVW5leHBlY3RlZCBTTUJ1cyBjb21tYW5kIDB4JXhcbiIs Cj4gPiA+ICsJCQlfX2Z1bmNfXywgc3NpZl9ibWMtPnNtYnVzX2NtZCk7Cj4gPiA+ICsJCWJyZWFr Owo+ID4gPiArCX0KPiA+ID4gK30KPiA+ID4gKwo+ID4gPiArc3RhdGljIGJvb2wgdmFsaWRhdGVf cmVxdWVzdChzdHJ1Y3Qgc3NpZl9ibWNfY3R4ICpzc2lmX2JtYykKPiA+ID4gK3sKPiA+ID4gKwl1 OCBycGVjID0gMCwgY3BlYyA9IDA7Cj4gPiA+ICsJYm9vbCByZXQgPSB0cnVlOwo+ID4gPiArCXU4 IGFkZHIsIGluZGV4Owo+ID4gPiArCXU4ICpidWY7Cj4gPiA+ICsKPiA+IAo+ID4gSXMgdGhlcmUg YW55IGxlbmd0aCB2YWxpZGF0aW9uIGZvciB1c2luZyBidWYgYmVsb3c/ICBJdCBsb29rcyBsaWtl IHlvdQo+ID4gYXJlIGFjY2Vzc2luZyB3aXRob3V0IGNoZWNraW5nIGxlbmd0aCwgYnV0IG1heWJl IEkgbWlzc2VkIHNvbWV0aGluZy4KPiA+IAo+IAo+IFllcywgdGhlcmUgaXMgbGVuZ3RoIHRlc3Rp bmcgZm9yIGVhY2ggcGFydCBiZWZvcmUgdXNpbmcgYnVmIHRvIGNhbGN1bGF0ZSBQRUMKPiBhcyBp biB0aGUgImlmIiBiZWxvdy4KPiAKPiA+ID4gKwlidWYgPSAodTggKikmc3NpZl9ibWMtPnJlcXVl c3Q7Cj4gPiA+ICsJc3dpdGNoIChzc2lmX2JtYy0+c21idXNfY21kKSB7Cj4gPiA+ICsJY2FzZSBT U0lGX0lQTUlfU0lOR0xFUEFSVF9XUklURToKPiA+ID4gKwkJaWYgKChzc2lmX2JtYy0+bXNnX2lk eCAtIDEpID09IHNzaWZfbXNnX2xlbigmc3NpZl9ibWMtPnJlcXVlc3QpKSB7Cj4gPiA+ICsJCQkv KiBQRUMgaXMgbm90IGluY2x1ZGVkICovCj4gPiA+ICsJCQlzc2lmX2JtYy0+cGVjX3N1cHBvcnQg PSBmYWxzZTsKPiA+ID4gKwkJCXJldCA9IHRydWU7Cj4gPiA+ICsJCQlnb3RvIGV4aXQ7Cj4gPiA+ ICsJCX0KPiA+ID4gKwo+ID4gPiArCQlpZiAoKHNzaWZfYm1jLT5tc2dfaWR4IC0gMSkgIT0gKHNz aWZfbXNnX2xlbigmc3NpZl9ibWMtPnJlcXVlc3QpICsgMSkpIHsKPiA+ID4gKwkJCWRldl9lcnIo JnNzaWZfYm1jLT5jbGllbnQtPmRldiwgIkVycm9yOiBVbmV4cGVjdGVkIGxlbmd0aCByZWNlaXZl ZCAlZFxuIiwKPiA+ID4gKwkJCQlzc2lmX21zZ19sZW4oJnNzaWZfYm1jLT5yZXF1ZXN0KSk7Cj4g PiA+ICsJCQlyZXQgPSBmYWxzZTsKPiA+ID4gKwkJCWdvdG8gZXhpdDsKPiA+ID4gKwkJfQo+ID4g PiArCj4gPiA+ICsJCS8qIFBFQyBpcyBpbmNsdWRlZCAqLwo+ID4gPiArCQlzc2lmX2JtYy0+cGVj X3N1cHBvcnQgPSB0cnVlOwo+ID4gPiArCQlycGVjID0gYnVmW3NzaWZfYm1jLT5tc2dfaWR4IC0g Ml07Cj4gPiA+ICsJCWFkZHIgPSBHRVRfOEJJVF9BRERSKHNzaWZfYm1jLT5jbGllbnQtPmFkZHIp Owo+ID4gPiArCQljcGVjID0gaTJjX3NtYnVzX3BlYyhjcGVjLCAmYWRkciwgMSk7Cj4gPiA+ICsJ CWNwZWMgPSBpMmNfc21idXNfcGVjKGNwZWMsICZzc2lmX2JtYy0+c21idXNfY21kLCAxKTsKPiA+ ID4gKwkJY3BlYyA9IGkyY19zbWJ1c19wZWMoY3BlYywgYnVmLCBzc2lmX21zZ19sZW4oJnNzaWZf Ym1jLT5yZXF1ZXN0KSk7Cj4gPiA+ICsJCWlmIChycGVjICE9IGNwZWMpIHsKPiA+ID4gKwkJCWRl dl9lcnIoJnNzaWZfYm1jLT5jbGllbnQtPmRldiwgIkJhZCBQRUMgMHglMDJ4IHZzLiAweCUwMnhc biIsIHJwZWMsIGNwZWMpOwo+ID4gPiArCQkJcmV0ID0gZmFsc2U7Cj4gPiA+ICsJCX0KPiA+ID4g Kwo+ID4gPiArCQlicmVhazsKPiA+ID4gKwljYXNlIFNTSUZfSVBNSV9NVUxUSVBBUlRfV1JJVEVf U1RBUlQ6Cj4gPiA+ICsJY2FzZSBTU0lGX0lQTUlfTVVMVElQQVJUX1dSSVRFX01JRERMRToKPiA+ ID4gKwljYXNlIFNTSUZfSVBNSV9NVUxUSVBBUlRfV1JJVEVfRU5EOgo+ID4gPiArCQlpbmRleCA9 IHNzaWZfYm1jLT5yZXF1ZXN0LmxlbiAtIHNzaWZfYm1jLT5yZWN2X2xlbjsKPiA+ID4gKwkJaWYg KChzc2lmX2JtYy0+bXNnX2lkeCAtIDEgKyBpbmRleCkgPT0gc3NpZl9tc2dfbGVuKCZzc2lmX2Jt Yy0+cmVxdWVzdCkpIHsKPiA+ID4gKwkJCS8qIFBFQyBpcyBub3QgaW5jbHVkZWQgKi8KPiA+ID4g KwkJCXNzaWZfYm1jLT5wZWNfc3VwcG9ydCA9IGZhbHNlOwo+ID4gPiArCQkJcmV0ID0gdHJ1ZTsK PiA+ID4gKwkJCWdvdG8gZXhpdDsKPiA+ID4gKwkJfQo+ID4gPiArCj4gPiA+ICsJCWlmICgoc3Np Zl9ibWMtPm1zZ19pZHggLSAxICsgaW5kZXgpICE9IChzc2lmX21zZ19sZW4oJnNzaWZfYm1jLT5y ZXF1ZXN0KSArIDEpKSB7Cj4gPiA+ICsJCQlkZXZfZXJyKCZzc2lmX2JtYy0+Y2xpZW50LT5kZXYs ICJFcnJvcjogVW5leHBlY3RlZCBsZW5ndGggcmVjZWl2ZWQgJWRcbiIsCj4gPiA+ICsJCQkJc3Np Zl9tc2dfbGVuKCZzc2lmX2JtYy0+cmVxdWVzdCkpOwo+ID4gPiArCQkJcmV0ID0gZmFsc2U7Cj4g PiA+ICsJCQlnb3RvIGV4aXQ7Cj4gPiA+ICsJCX0KPiA+ID4gKwo+ID4gPiArCQkvKiBQRUMgaXMg aW5jbHVkZWQgKi8KPiA+ID4gKwkJc3NpZl9ibWMtPnBlY19zdXBwb3J0ID0gdHJ1ZTsKPiA+ID4g KwkJcnBlYyA9IGJ1Zltzc2lmX2JtYy0+bXNnX2lkeCAtIDIgKyBpbmRleF07Cj4gPiA+ICsJCWFk ZHIgPSBHRVRfOEJJVF9BRERSKHNzaWZfYm1jLT5jbGllbnQtPmFkZHIpOwo+ID4gPiArCQljcGVj ID0gaTJjX3NtYnVzX3BlYyhjcGVjLCAmYWRkciwgMSk7Cj4gPiA+ICsJCWNwZWMgPSBpMmNfc21i dXNfcGVjKGNwZWMsICZzc2lmX2JtYy0+c21idXNfY21kLCAxKTsKPiA+ID4gKwkJY3BlYyA9IGky Y19zbWJ1c19wZWMoY3BlYywgJnNzaWZfYm1jLT5yZWN2X2xlbiwgMSk7Cj4gPiAKPiA+IEp1c3Qg Y3VyaW91cywgSSdtIG5vdCBzdXJlIHRoZSBjbGllbnQgc2lkZSBQRUMgaW4gdGhlIExpbnV4IGRy aXZlciBoYXMKPiA+IGV2ZXIgYmVlbiB2YWxpZGF0ZWQuICBIYXZlIHlvdSB0ZXN0ZWQgYm90aCBz aWRlcz8KPiA+IAo+IAo+IFllcywgd2UgZm91bmQgdGhhdCByZXF1ZXN0IGZyb20gaG9zdCBoYXMg YW4gZXh0cmEgYnl0ZSBmb3IgUEVDIGFuZCB0aGF0IGlzCj4gd2h5IHdlIGFkZGVkIFBFQyBzdXBw b3J0Lgo+IAo+ID4gPiArCQkvKiBBcyBTTUJ1cyBzcGVjaWZpY2F0aW9uIGRvZXMgbm90IGFsbG93 IHRoZSBsZW5ndGgKPiA+ID4gKwkJICogKGJ5dGUgY291bnQpIGluIHRoZSBXcml0ZS1CbG9jayBw cm90b2NvbCB0byBiZSB6ZXJvLgo+ID4gPiArCQkgKiBUaGVyZWZvcmUsIGl0IGlzIGlsbGVnYWwg dG8gaGF2ZSB0aGUgbGFzdCBNaWRkbGUKPiA+ID4gKwkJICogdHJhbnNhY3Rpb24gaW4gdGhlIHNl cXVlbmNlIGNhcnJ5IDMyLWJ5dGUgYW5kIGhhdmUKPiA+ID4gKwkJICogYSBsZW5ndGggb2Yg4oCY MOKAmSBpbiB0aGUgRW5kIHRyYW5zYWN0aW9uLgo+ID4gPiArCQkgKiBCdXQgc29tZSB1c2VycyBt YXkgdHJ5IHRvIHVzZSB0aGlzIHdheSBhbmQgd2Ugc2hvdWxkCj4gPiA+ICsJCSAqIHByZXZlbnQg c3NpZl9ibWMgZHJpdmVyIGJyb2tlbiBpbiB0aGlzIGNhc2UuCj4gPiA+ICsJCSAqLwo+ID4gPiAr CQlpZiAoc3NpZl9ibWMtPnJlY3ZfbGVuICE9IDApCj4gPiA+ICsJCQljcGVjID0gaTJjX3NtYnVz X3BlYyhjcGVjLCBidWYgKyAxICsgaW5kZXgsIHNzaWZfYm1jLT5yZWN2X2xlbik7Cj4gPiA+ICsK PiA+ID4gKwkJaWYgKHJwZWMgIT0gY3BlYykgewo+ID4gPiArCQkJZGV2X2Vycigmc3NpZl9ibWMt PmNsaWVudC0+ZGV2LCAiQmFkIFBFQyAweCUwMnggdnMuIDB4JTAyeFxuIiwgcnBlYywgY3BlYyk7 Cj4gPiA+ICsJCQlyZXQgPSBmYWxzZTsKPiA+ID4gKwkJfQo+ID4gPiArCj4gPiA+ICsJCWJyZWFr Owo+ID4gPiArCWRlZmF1bHQ6Cj4gPiA+ICsJCS8qIERvIG5vdCBleHBlY3QgdG8gZ28gdG8gdGhp cyBjYXNlICovCj4gPiA+ICsJCWRldl9lcnIoJnNzaWZfYm1jLT5jbGllbnQtPmRldiwgIiVzOiBV bmV4cGVjdGVkIFNNQnVzIGNvbW1hbmQgMHgleFxuIiwKPiA+ID4gKwkJCV9fZnVuY19fLCBzc2lm X2JtYy0+c21idXNfY21kKTsKPiA+ID4gKwkJcmV0ID0gZmFsc2U7Cj4gPiA+ICsJCWJyZWFrOwo+ ID4gPiArCX0KPiA+ID4gKwo+ID4gPiArZXhpdDoKPiA+ID4gKwlyZXR1cm4gcmV0Owo+ID4gPiAr fQo+ID4gPiArCj4gPiAKPiA+IEp1c3QgYSBuaXQsIG1vcmUgYSBnZW5lcmFsIGNvZGluZyBzdHls ZSBjb21tZW50LiAgSXQncyBhbG1vc3QgYWx3YXlzIGEKPiA+IGJhZCBpZGVhIHRvIHB1dCBhIG5l Z2F0aXZlICh1bnN1cHBvcnRlZCkgaW50byBhIGNoZWNrIGZ1bmN0aW9uLiAgWW91Cj4gPiBvZnRl biBlbmQgdXAgd2l0aCBzb21ldGhpbmcgbGlrZToKPiA+IAo+ID4gCWlmICghdW5zdXBwb3J0ZWRf c21idXNfY21kKGMpKS4uLi4KPiA+IAo+ID4gd2hpY2ggbG9va3MgYSBsaXR0bGUgc3RyYW5nZS4g IERvdWJsZSBuZWdhdGl2ZXMgY2FuIG1ha2UgaXQgaGFyZCB0bwo+ID4gZm9sbG93IGFuZCBsZWFk IHRvIG1pc3Rha2VzLiAgVGhpcyBvbmUgaXNuJ3QgdG9vIGJhZCwgYnV0IHNvbWV0aW1lcyBpdAo+ ID4gY2FuIGJlLiAgSXQncyBiZXR0ZXIgdG8gZG86Cj4gPiAKPiA+IAlpZiAoc3VwcG9ydGVkX3Nt YnVzX2NtZChjKSkuLi4uCj4gPiBvcgo+ID4gCWlmICghc3VwcG9ydGVkX3NtYnVzX2NtZChjKSku Li4uCj4gPiAKPiA+IAo+IAo+IFRoYW5rcywgQ29yZXkuIEknbGwgdHJ5IHRvIHJlZmFjdG9yIHRo aXMgcGFydCBpbiBuZXh0IHZlcnNpb24uCj4gCj4gPiA+ICtzdGF0aWMgYm9vbCB1bnN1cHBvcnRl ZF9zbWJ1c19jbWQodTggY21kKQo+ID4gPiArewo+ID4gPiArCWlmIChjbWQgPT0gU1NJRl9JUE1J X1NJTkdMRVBBUlRfUkVBRCB8fAo+ID4gPiArCSAgICBjbWQgPT0gU1NJRl9JUE1JX1NJTkdMRVBB UlRfV1JJVEUgfHwKPiA+ID4gKwkgICAgY21kID09IFNTSUZfSVBNSV9NVUxUSVBBUlRfV1JJVEVf U1RBUlQgfHwKPiA+ID4gKwkgICAgY21kID09IFNTSUZfSVBNSV9NVUxUSVBBUlRfV1JJVEVfTUlE RExFIHx8Cj4gPiA+ICsJICAgIGNtZCA9PSBTU0lGX0lQTUlfTVVMVElQQVJUX1dSSVRFX0VORCB8 fAo+ID4gPiArCSAgICBjbWQgPT0gU1NJRl9JUE1JX01VTFRJUEFSVF9SRUFEX1NUQVJUIHx8Cj4g PiA+ICsJICAgIGNtZCA9PSBTU0lGX0lQTUlfTVVMVElQQVJUX1JFQURfTUlERExFKQo+ID4gPiAr CQlyZXR1cm4gZmFsc2U7Cj4gPiA+ICsKPiA+ID4gKwlyZXR1cm4gdHJ1ZTsKPiA+ID4gK30KPiA+ ID4gKwo+ID4gPiArc3RhdGljIHZvaWQgcHJvY2Vzc19zbWJ1c19jbWQoc3RydWN0IHNzaWZfYm1j X2N0eCAqc3NpZl9ibWMsIHU4ICp2YWwpCj4gPiA+ICt7Cj4gPiA+ICsJLyogU01CVVMgY29tbWFu ZCBjYW4gdmFyeSAoc2luZ2xlIG9yIG11bHRpLXBhcnQpICovCj4gPiA+ICsJc3NpZl9ibWMtPnNt YnVzX2NtZCA9ICp2YWw7Cj4gPiA+ICsJc3NpZl9ibWMtPm1zZ19pZHgrKzsKPiA+ID4gKwo+ID4g PiArCWlmICh1bnN1cHBvcnRlZF9zbWJ1c19jbWQoKnZhbCkpCj4gPiA+ICsJCWRldl93YXJuKCZz c2lmX2JtYy0+Y2xpZW50LT5kZXYsICJXYXJuOiBVbmtub3duIFNNQnVzIGNvbW1hbmQiKTsKPiA+ ID4gKwo+ID4gPiArCWlmICgqdmFsID09IFNTSUZfSVBNSV9TSU5HTEVQQVJUX1dSSVRFIHx8Cj4g PiA+ICsJICAgICp2YWwgPT0gU1NJRl9JUE1JX01VTFRJUEFSVF9XUklURV9TVEFSVCkgewo+ID4g PiArCQkvKgo+ID4gPiArCQkgKiBUaGUgcmVzcG9uc2UgbWF5YmUgbm90IGNvbWUgaW4tdGltZSwg Y2F1c2luZyBob3N0IFNTSUYgZHJpdmVyCj4gPiA+ICsJCSAqIHRvIHRpbWVvdXQgYW5kIHJlc2Vu ZCBhIG5ldyByZXF1ZXN0LiBJbiBzdWNoIGNhc2UgY2hlY2sgZm9yCj4gPiA+ICsJCSAqIHBlbmRp bmcgcmVzcG9uc2UgYW5kIGNsZWFyIGl0Cj4gPiA+ICsJCSAqLwo+ID4gPiArCQlpZiAoc3NpZl9i bWMtPnJlc3BvbnNlX2luX3Byb2dyZXNzKQo+ID4gPiArCQkJY29tcGxldGVfcmVzcG9uc2Uoc3Np Zl9ibWMpOwo+ID4gPiArCX0KPiA+ID4gK30KPiA+ID4gKwo+ID4gPiArc3RhdGljIHZvaWQgb25f cmVhZF9yZXF1ZXN0ZWRfZXZlbnQoc3RydWN0IHNzaWZfYm1jX2N0eCAqc3NpZl9ibWMsIHU4ICp2 YWwpCj4gPiA+ICt7Cj4gPiA+ICsJaWYgKHNzaWZfYm1jLT5zdGF0ZSA9PSBTU0lGX1JFQURZIHx8 Cj4gPiA+ICsJICAgIHNzaWZfYm1jLT5zdGF0ZSA9PSBTU0lGX1NUQVJUIHx8Cj4gPiA+ICsJICAg IHNzaWZfYm1jLT5zdGF0ZSA9PSBTU0lGX1JFUV9SRUNWSU5HIHx8Cj4gPiA+ICsJICAgIHNzaWZf Ym1jLT5zdGF0ZSA9PSBTU0lGX1JFU19TRU5ESU5HKSB7Cj4gPiA+ICsJCXNzaWZfYm1jLT5zdGF0 ZSA9IFNTSUZfQkFEX1NNQlVTOwo+ID4gPiArCQlkZXZfd2Fybigmc3NpZl9ibWMtPmNsaWVudC0+ ZGV2LAo+ID4gPiArCQkJICJXYXJuOiAlcyB1bmV4cGVjdGVkIFJFQUQgUkVRVUVTVEVEIGluIHN0 YXRlPSVzXG4iLAo+ID4gPiArCQkJIF9fZnVuY19fLCBzdGF0ZV90b19zdHJpbmcoc3NpZl9ibWMt PnN0YXRlKSk7Cj4gPiA+ICsKPiA+ID4gKwl9IGVsc2UgaWYgKHNzaWZfYm1jLT5zdGF0ZSA9PSBT U0lGX1NNQlVTX0NNRCkgewo+ID4gPiArCQlzc2lmX2JtYy0+c3RhdGUgPSBTU0lGX1JFU19TRU5E SU5HOwo+ID4gPiArCX0KPiA+ID4gKwo+ID4gPiArCXNzaWZfYm1jLT5tc2dfaWR4ID0gMDsKPiA+ ID4gKwlpZiAoc3NpZl9ibWMtPmlzX3NpbmdsZXBhcnRfcmVhZCkKPiA+ID4gKwkJKnZhbCA9IHNz aWZfYm1jLT5yZXNwb25zZS5sZW47Cj4gPiA+ICsJZWxzZQo+ID4gPiArCQlzZXRfbXVsdGlwYXJ0 X3Jlc3BvbnNlX2J1ZmZlcihzc2lmX2JtYywgdmFsKTsKPiA+ID4gK30KPiA+ID4gKwo+ID4gPiAr c3RhdGljIHZvaWQgb25fcmVhZF9wcm9jZXNzZWRfZXZlbnQoc3RydWN0IHNzaWZfYm1jX2N0eCAq c3NpZl9ibWMsIHU4ICp2YWwpCj4gPiA+ICt7Cj4gPiA+ICsJaWYgKHNzaWZfYm1jLT5zdGF0ZSA9 PSBTU0lGX1JFQURZIHx8Cj4gPiA+ICsJICAgIHNzaWZfYm1jLT5zdGF0ZSA9PSBTU0lGX1NUQVJU IHx8Cj4gPiA+ICsJICAgIHNzaWZfYm1jLT5zdGF0ZSA9PSBTU0lGX1JFUV9SRUNWSU5HIHx8Cj4g PiA+ICsJICAgIHNzaWZfYm1jLT5zdGF0ZSA9PSBTU0lGX1NNQlVTX0NNRCkgewo+ID4gPiArCQlk ZXZfd2Fybigmc3NpZl9ibWMtPmNsaWVudC0+ZGV2LAo+ID4gPiArCQkJICJXYXJuOiAlcyB1bmV4 cGVjdGVkIFJFQUQgUFJPQ0VTU0VEIGluIHN0YXRlPSVzXG4iLAo+ID4gPiArCQkJIF9fZnVuY19f LCBzdGF0ZV90b19zdHJpbmcoc3NpZl9ibWMtPnN0YXRlKSk7Cj4gPiA+ICsJCXNzaWZfYm1jLT5z dGF0ZSA9IFNTSUZfQkFEX1NNQlVTOwo+ID4gPiArCX0KPiA+ID4gKwo+ID4gPiArCWhhbmRsZV9y ZWFkX3Byb2Nlc3NlZChzc2lmX2JtYywgdmFsKTsKPiA+ID4gK30KPiA+ID4gKwo+ID4gPiArc3Rh dGljIHZvaWQgb25fd3JpdGVfcmVxdWVzdGVkX2V2ZW50KHN0cnVjdCBzc2lmX2JtY19jdHggKnNz aWZfYm1jLCB1OCAqdmFsKQo+ID4gPiArewo+ID4gPiArCXNzaWZfYm1jLT5tc2dfaWR4ID0gMDsK PiA+ID4gKwo+ID4gPiArCWlmIChzc2lmX2JtYy0+c3RhdGUgPT0gU1NJRl9SRUFEWSB8fCBzc2lm X2JtYy0+c3RhdGUgPT0gU1NJRl9TTUJVU19DTUQpIHsKPiA+ID4gKwkJc3NpZl9ibWMtPnN0YXRl ID0gU1NJRl9TVEFSVDsKPiA+ID4gKwo+ID4gPiArCX0gZWxzZSBpZiAoc3NpZl9ibWMtPnN0YXRl ID09IFNTSUZfU1RBUlQgfHwKPiA+ID4gKwkJICAgc3NpZl9ibWMtPnN0YXRlID09IFNTSUZfUkVR X1JFQ1ZJTkcgfHwKPiA+ID4gKwkJICAgc3NpZl9ibWMtPnN0YXRlID09IFNTSUZfUkVTX1NFTkRJ TkcpIHsKPiA+ID4gKwkJZGV2X3dhcm4oJnNzaWZfYm1jLT5jbGllbnQtPmRldiwKPiA+ID4gKwkJ CSAiV2FybjogJXMgdW5leHBlY3RlZCBXUklURSBSRVFVRVNUIGluIHN0YXRlPSVzXG4iLAo+ID4g PiArCQkJIF9fZnVuY19fLCBzdGF0ZV90b19zdHJpbmcoc3NpZl9ibWMtPnN0YXRlKSk7Cj4gPiA+ ICsJCXNzaWZfYm1jLT5zdGF0ZSA9IFNTSUZfQkFEX1NNQlVTOwo+ID4gPiArCX0KPiA+ID4gK30K PiA+ID4gKwo+ID4gPiArc3RhdGljIHZvaWQgb25fd3JpdGVfcmVjZWl2ZWRfZXZlbnQoc3RydWN0 IHNzaWZfYm1jX2N0eCAqc3NpZl9ibWMsIHU4ICp2YWwpCj4gPiA+ICt7Cj4gPiA+ICsJaWYgKHNz aWZfYm1jLT5zdGF0ZSA9PSBTU0lGX1JFQURZIHx8IHNzaWZfYm1jLT5zdGF0ZSA9PSBTU0lGX1JF U19TRU5ESU5HKSB7Cj4gPiA+ICsJCWRldl93YXJuKCZzc2lmX2JtYy0+Y2xpZW50LT5kZXYsCj4g PiA+ICsJCQkgIldhcm46ICVzIHVuZXhwZWN0ZWQgV1JJVEUgUkVDRUlWRUQgaW4gc3RhdGU9JXNc biIsCj4gPiA+ICsJCQkgX19mdW5jX18sIHN0YXRlX3RvX3N0cmluZyhzc2lmX2JtYy0+c3RhdGUp KTsKPiA+ID4gKwkJc3NpZl9ibWMtPnN0YXRlID0gU1NJRl9CQURfU01CVVM7Cj4gPiA+ICsJfSBl bHNlIGlmIChzc2lmX2JtYy0+c3RhdGUgPT0gU1NJRl9TVEFSVCkgewo+ID4gPiArCQlzc2lmX2Jt Yy0+c3RhdGUgPSBTU0lGX1NNQlVTX0NNRDsKPiA+ID4gKwl9IGVsc2UgaWYgKHNzaWZfYm1jLT5z dGF0ZSA9PSBTU0lGX1NNQlVTX0NNRCkgewo+ID4gPiArCQlzc2lmX2JtYy0+c3RhdGUgPSBTU0lG X1JFUV9SRUNWSU5HOwo+ID4gPiArCX0KPiA+ID4gKwo+ID4gPiArCS8qIFRoaXMgaXMgcmVzcG9u c2Ugc2VuZGluZyBzdGF0ZSAqLwo+ID4gPiArCWlmIChzc2lmX2JtYy0+c3RhdGUgPT0gU1NJRl9S RVFfUkVDVklORykKPiA+ID4gKwkJaGFuZGxlX3dyaXRlX3JlY2VpdmVkKHNzaWZfYm1jLCB2YWwp Owo+ID4gPiArCWVsc2UgaWYgKHNzaWZfYm1jLT5zdGF0ZSA9PSBTU0lGX1NNQlVTX0NNRCkKPiA+ ID4gKwkJcHJvY2Vzc19zbWJ1c19jbWQoc3NpZl9ibWMsIHZhbCk7Cj4gPiA+ICt9Cj4gPiA+ICsK PiA+ID4gK3N0YXRpYyB2b2lkIG9uX3N0b3BfZXZlbnQoc3RydWN0IHNzaWZfYm1jX2N0eCAqc3Np Zl9ibWMsIHU4ICp2YWwpCj4gPiA+ICt7Cj4gPiA+ICsJaWYgKHNzaWZfYm1jLT5zdGF0ZSA9PSBT U0lGX1JFQURZIHx8Cj4gPiA+ICsJICAgIHNzaWZfYm1jLT5zdGF0ZSA9PSBTU0lGX1NUQVJUIHx8 Cj4gPiA+ICsJICAgIHNzaWZfYm1jLT5zdGF0ZSA9PSBTU0lGX1NNQlVTX0NNRCkgewo+ID4gPiAr CQlkZXZfd2Fybigmc3NpZl9ibWMtPmNsaWVudC0+ZGV2LAo+ID4gPiArCQkJICJXYXJuOiAlcyB1 bmV4cGVjdGVkIFNMQVZFIFNUT1AgaW4gc3RhdGU9JXNcbiIsCj4gPiA+ICsJCQkgX19mdW5jX18s IHN0YXRlX3RvX3N0cmluZyhzc2lmX2JtYy0+c3RhdGUpKTsKPiA+ID4gKwo+ID4gPiArCX0gZWxz ZSBpZiAoc3NpZl9ibWMtPnN0YXRlID09IFNTSUZfQkFEX1NNQlVTKSB7Cj4gPiA+ICsJCWRldl93 YXJuKCZzc2lmX2JtYy0+Y2xpZW50LT5kZXYsCj4gPiA+ICsJCQkgIldhcm46ICVzIHJlY2VpdmVk IFNMQVZFIFNUT1AgZnJvbSBiYWQgc3RhdGU9JXNcbiIsCj4gPiA+ICsJCQkgX19mdW5jX18sIHN0 YXRlX3RvX3N0cmluZyhzc2lmX2JtYy0+c3RhdGUpKTsKPiA+ID4gKwo+ID4gPiArCX0gZWxzZSBp ZiAoc3NpZl9ibWMtPnN0YXRlID09IFNTSUZfUkVRX1JFQ1ZJTkcpIHsKPiA+ID4gKwkJLyogQSBC TUMgdGhhdCByZWNlaXZlcyBhbiBpbnZhbGlkIHJlcXVlc3QgZHJvcCB0aGUgZGF0YSBmb3IgdGhl IHdyaXRlCj4gPiA+ICsJCSAqIHRyYW5zYWN0aW9uIGFuZCBhbnkgZnVydGhlciB0cmFuc2FjdGlv bnMgKHJlYWQgb3Igd3JpdGUpIHVudGlsCj4gPiA+ICsJCSAqIHRoZSBuZXh0IHZhbGlkIHJlYWQg b3Igd3JpdGUgU3RhcnQgdHJhbnNhY3Rpb24gaXMgcmVjZWl2ZWQKPiA+ID4gKwkJICovCj4gPiA+ ICsJCWlmICghdmFsaWRhdGVfcmVxdWVzdChzc2lmX2JtYykpCj4gPiA+ICsJCQlkZXZfZXJyKCZz c2lmX2JtYy0+Y2xpZW50LT5kZXYsICJFcnJvcjogaW52YWxpZCBwZWNcbiIpOwo+ID4gPiArCQll bHNlIGlmIChzc2lmX2JtYy0+c21idXNfY21kID09IFNTSUZfSVBNSV9TSU5HTEVQQVJUX1dSSVRF IHx8Cj4gPiA+ICsJCQkgc3NpZl9ibWMtPnNtYnVzX2NtZCA9PSBTU0lGX0lQTUlfTVVMVElQQVJU X1dSSVRFX0VORCkKPiA+ID4gKwkJCWhhbmRsZV9yZXF1ZXN0KHNzaWZfYm1jKTsKPiA+ID4gKwl9 Cj4gPiA+ICsKPiA+ID4gKwlzc2lmX2JtYy0+c3RhdGUgPSBTU0lGX1JFQURZOwo+ID4gPiArCS8q IFJlc2V0IG1lc3NhZ2UgaW5kZXggKi8KPiA+ID4gKwlzc2lmX2JtYy0+bXNnX2lkeCA9IDA7Cj4g PiA+ICt9Cj4gPiA+ICsKPiA+ID4gKy8qCj4gPiA+ICsgKiBDYWxsYmFjayBmdW5jdGlvbiB0byBo YW5kbGUgSTJDIHNsYXZlIGV2ZW50cwo+ID4gPiArICovCj4gPiA+ICtzdGF0aWMgaW50IHNzaWZf Ym1jX2NiKHN0cnVjdCBpMmNfY2xpZW50ICpjbGllbnQsIGVudW0gaTJjX3NsYXZlX2V2ZW50IGV2 ZW50LCB1OCAqdmFsKQo+ID4gPiArewo+ID4gPiArCXVuc2lnbmVkIGxvbmcgZmxhZ3M7Cj4gPiA+ ICsJc3RydWN0IHNzaWZfYm1jX2N0eCAqc3NpZl9ibWMgPSBpMmNfZ2V0X2NsaWVudGRhdGEoY2xp ZW50KTsKPiA+ID4gKwlpbnQgcmV0ID0gMDsKPiA+ID4gKwo+ID4gPiArCXNwaW5fbG9ja19pcnFz YXZlKCZzc2lmX2JtYy0+bG9jaywgZmxhZ3MpOwo+ID4gPiArCj4gPiA+ICsJc3dpdGNoIChldmVu dCkgewo+ID4gPiArCWNhc2UgSTJDX1NMQVZFX1JFQURfUkVRVUVTVEVEOgo+ID4gPiArCQlvbl9y ZWFkX3JlcXVlc3RlZF9ldmVudChzc2lmX2JtYywgdmFsKTsKPiA+ID4gKwkJYnJlYWs7Cj4gPiA+ ICsKPiA+ID4gKwljYXNlIEkyQ19TTEFWRV9XUklURV9SRVFVRVNURUQ6Cj4gPiA+ICsJCW9uX3dy aXRlX3JlcXVlc3RlZF9ldmVudChzc2lmX2JtYywgdmFsKTsKPiA+ID4gKwkJYnJlYWs7Cj4gPiA+ ICsKPiA+ID4gKwljYXNlIEkyQ19TTEFWRV9SRUFEX1BST0NFU1NFRDoKPiA+ID4gKwkJb25fcmVh ZF9wcm9jZXNzZWRfZXZlbnQoc3NpZl9ibWMsIHZhbCk7Cj4gPiA+ICsJCWJyZWFrOwo+ID4gPiAr Cj4gPiA+ICsJY2FzZSBJMkNfU0xBVkVfV1JJVEVfUkVDRUlWRUQ6Cj4gPiA+ICsJCW9uX3dyaXRl X3JlY2VpdmVkX2V2ZW50KHNzaWZfYm1jLCB2YWwpOwo+ID4gPiArCQlicmVhazsKPiA+ID4gKwo+ ID4gPiArCWNhc2UgSTJDX1NMQVZFX1NUT1A6Cj4gPiA+ICsJCW9uX3N0b3BfZXZlbnQoc3NpZl9i bWMsIHZhbCk7Cj4gPiA+ICsJCWJyZWFrOwo+ID4gPiArCj4gPiA+ICsJZGVmYXVsdDoKPiA+ID4g KwkJZGV2X3dhcm4oJnNzaWZfYm1jLT5jbGllbnQtPmRldiwgIldhcm46IFVua25vd24gaTJjIHNs YXZlIGV2ZW50XG4iKTsKPiA+ID4gKwkJYnJlYWs7Cj4gPiA+ICsJfQo+ID4gPiArCj4gPiA+ICsJ aWYgKHNzaWZfYm1jLT5idXN5KQo+ID4gPiArCQlyZXQgPSAtRUJVU1k7Cj4gPiA+ICsKPiA+ID4g KwlzcGluX3VubG9ja19pcnFyZXN0b3JlKCZzc2lmX2JtYy0+bG9jaywgZmxhZ3MpOwo+ID4gPiAr Cj4gPiA+ICsJcmV0dXJuIHJldDsKPiA+ID4gK30KPiA+ID4gKwo+ID4gPiArc3RhdGljIGludCBz c2lmX2JtY19wcm9iZShzdHJ1Y3QgaTJjX2NsaWVudCAqY2xpZW50LCBjb25zdCBzdHJ1Y3QgaTJj X2RldmljZV9pZCAqaWQpCj4gPiA+ICt7Cj4gPiA+ICsJc3RydWN0IHNzaWZfYm1jX2N0eCAqc3Np Zl9ibWM7Cj4gPiA+ICsJaW50IHJldDsKPiA+ID4gKwo+ID4gPiArCXNzaWZfYm1jID0gZGV2bV9r emFsbG9jKCZjbGllbnQtPmRldiwgc2l6ZW9mKCpzc2lmX2JtYyksIEdGUF9LRVJORUwpOwo+ID4g PiArCWlmICghc3NpZl9ibWMpCj4gPiA+ICsJCXJldHVybiAtRU5PTUVNOwo+ID4gPiArCj4gPiA+ ICsJc3Bpbl9sb2NrX2luaXQoJnNzaWZfYm1jLT5sb2NrKTsKPiA+ID4gKwo+ID4gPiArCWluaXRf d2FpdHF1ZXVlX2hlYWQoJnNzaWZfYm1jLT53YWl0X3F1ZXVlKTsKPiA+ID4gKwlzc2lmX2JtYy0+ cmVxdWVzdF9hdmFpbGFibGUgPSBmYWxzZTsKPiA+ID4gKwlzc2lmX2JtYy0+cmVzcG9uc2VfaW5f cHJvZ3Jlc3MgPSBmYWxzZTsKPiA+ID4gKwlzc2lmX2JtYy0+YnVzeSA9IGZhbHNlOwo+ID4gPiAr CXNzaWZfYm1jLT5yZXNwb25zZV90aW1lcl9pbml0ZWQgPSBmYWxzZTsKPiA+ID4gKwo+ID4gPiAr CS8qIFJlZ2lzdGVyIG1pc2MgZGV2aWNlIGludGVyZmFjZSAqLwo+ID4gPiArCXNzaWZfYm1jLT5t aXNjZGV2Lm1pbm9yID0gTUlTQ19EWU5BTUlDX01JTk9SOwo+ID4gPiArCXNzaWZfYm1jLT5taXNj ZGV2Lm5hbWUgPSBERVZJQ0VfTkFNRTsKPiA+ID4gKwlzc2lmX2JtYy0+bWlzY2Rldi5mb3BzID0g JnNzaWZfYm1jX2ZvcHM7Cj4gPiA+ICsJc3NpZl9ibWMtPm1pc2NkZXYucGFyZW50ID0gJmNsaWVu dC0+ZGV2Owo+ID4gPiArCXJldCA9IG1pc2NfcmVnaXN0ZXIoJnNzaWZfYm1jLT5taXNjZGV2KTsK PiA+ID4gKwlpZiAocmV0KQo+ID4gPiArCQlnb3RvIG91dDsKPiA+ID4gKwo+ID4gPiArCXNzaWZf Ym1jLT5jbGllbnQgPSBjbGllbnQ7Cj4gPiA+ICsJc3NpZl9ibWMtPmNsaWVudC0+ZmxhZ3MgfD0g STJDX0NMSUVOVF9TTEFWRTsKPiA+ID4gKwo+ID4gPiArCS8qIFJlZ2lzdGVyIEkyQyBzbGF2ZSAq Lwo+ID4gPiArCWkyY19zZXRfY2xpZW50ZGF0YShjbGllbnQsIHNzaWZfYm1jKTsKPiA+ID4gKwly ZXQgPSBpMmNfc2xhdmVfcmVnaXN0ZXIoY2xpZW50LCBzc2lmX2JtY19jYik7Cj4gPiA+ICsJaWYg KHJldCkgewo+ID4gPiArCQltaXNjX2RlcmVnaXN0ZXIoJnNzaWZfYm1jLT5taXNjZGV2KTsKPiA+ ID4gKwkJZ290byBvdXQ7Cj4gPiA+ICsJfQo+ID4gPiArCj4gPiA+ICsJcmV0dXJuIDA7Cj4gPiA+ ICtvdXQ6Cj4gPiA+ICsJZGV2bV9rZnJlZSgmY2xpZW50LT5kZXYsIHNzaWZfYm1jKTsKPiA+ID4g KwlyZXR1cm4gcmV0Owo+ID4gPiArfQo+ID4gPiArCj4gPiA+ICtzdGF0aWMgaW50IHNzaWZfYm1j X3JlbW92ZShzdHJ1Y3QgaTJjX2NsaWVudCAqY2xpZW50KQo+ID4gPiArewo+ID4gPiArCXN0cnVj dCBzc2lmX2JtY19jdHggKnNzaWZfYm1jID0gaTJjX2dldF9jbGllbnRkYXRhKGNsaWVudCk7Cj4g PiA+ICsKPiA+ID4gKwlpMmNfc2xhdmVfdW5yZWdpc3RlcihjbGllbnQpOwo+ID4gPiArCW1pc2Nf ZGVyZWdpc3Rlcigmc3NpZl9ibWMtPm1pc2NkZXYpOwo+ID4gPiArCj4gPiA+ICsJcmV0dXJuIDA7 Cj4gPiA+ICt9Cj4gPiA+ICsKPiA+ID4gK3N0YXRpYyBjb25zdCBzdHJ1Y3Qgb2ZfZGV2aWNlX2lk IHNzaWZfYm1jX21hdGNoW10gPSB7Cj4gPiA+ICsJeyAuY29tcGF0aWJsZSA9ICJhbXBlcmUsc3Np Zi1ibWMiIH0sCj4gPiA+ICsJeyB9LAo+ID4gPiArfTsKPiA+ID4gKwo+ID4gPiArc3RhdGljIGNv bnN0IHN0cnVjdCBpMmNfZGV2aWNlX2lkIHNzaWZfYm1jX2lkW10gPSB7Cj4gPiA+ICsJeyBERVZJ Q0VfTkFNRSwgMCB9LAo+ID4gPiArCXsgfSwKPiA+ID4gK307Cj4gPiA+ICsKPiA+ID4gK01PRFVM RV9ERVZJQ0VfVEFCTEUoaTJjLCBzc2lmX2JtY19pZCk7Cj4gPiA+ICsKPiA+ID4gK3N0YXRpYyBz dHJ1Y3QgaTJjX2RyaXZlciBzc2lmX2JtY19kcml2ZXIgPSB7Cj4gPiA+ICsJLmRyaXZlciAgICAg ICAgID0gewo+ID4gPiArCQkubmFtZSAgICAgICAgICAgPSBERVZJQ0VfTkFNRSwKPiA+ID4gKwkJ Lm9mX21hdGNoX3RhYmxlID0gc3NpZl9ibWNfbWF0Y2gsCj4gPiA+ICsJfSwKPiA+ID4gKwkucHJv YmUgICAgICAgICAgPSBzc2lmX2JtY19wcm9iZSwKPiA+ID4gKwkucmVtb3ZlICAgICAgICAgPSBz c2lmX2JtY19yZW1vdmUsCj4gPiA+ICsJLmlkX3RhYmxlICAgICAgID0gc3NpZl9ibWNfaWQsCj4g PiA+ICt9Owo+ID4gPiArCj4gPiA+ICttb2R1bGVfaTJjX2RyaXZlcihzc2lmX2JtY19kcml2ZXIp Owo+ID4gPiArCj4gPiA+ICtNT0RVTEVfQVVUSE9SKCJRdWFuIE5ndXllbiA8cXVhbkBvcy5hbXBl cmVjb21wdXRpbmcuY29tPiIpOwo+ID4gPiArTU9EVUxFX0FVVEhPUigiQ2h1b25nIFRyYW4gPGNo dW9uZ0Bvcy5hbXBlcmVjb21wdXRpbmcuY29tPiIpOwo+ID4gPiArTU9EVUxFX0RFU0NSSVBUSU9O KCJMaW51eCBkZXZpY2UgZHJpdmVyIG9mIHRoZSBCTUMgSVBNSSBTU0lGIGludGVyZmFjZS4iKTsK PiA+ID4gK01PRFVMRV9MSUNFTlNFKCJHUEwiKTsKPiA+ID4gZGlmZiAtLWdpdCBhL2RyaXZlcnMv Y2hhci9pcG1pL3NzaWZfYm1jLmggYi9kcml2ZXJzL2NoYXIvaXBtaS9zc2lmX2JtYy5oCj4gPiA+ IG5ldyBmaWxlIG1vZGUgMTAwNjQ0Cj4gPiA+IGluZGV4IDAwMDAwMDAwMDAwMC4uOWEyNmYzYzI1 MmNjCj4gPiA+IC0tLSAvZGV2L251bGwKPiA+ID4gKysrIGIvZHJpdmVycy9jaGFyL2lwbWkvc3Np Zl9ibWMuaAo+ID4gPiBAQCAtMCwwICsxLDEwMiBAQAo+ID4gPiArLyogU1BEWC1MaWNlbnNlLUlk ZW50aWZpZXI6IEdQTC0yLjArICovCj4gPiA+ICsvKgo+ID4gPiArICogVGhlIGRyaXZlciBmb3Ig Qk1DIHNpZGUgb2YgU1NJRiBpbnRlcmZhY2UKPiA+ID4gKyAqCj4gPiA+ICsgKiBDb3B5cmlnaHQg KGMpIDIwMjIsIEFtcGVyZSBDb21wdXRpbmcgTExDCj4gPiA+ICsgKgo+ID4gPiArICovCj4gPiA+ ICsjaWZuZGVmIF9fU1NJRl9CTUNfSF9fCj4gPiA+ICsjZGVmaW5lIF9fU1NJRl9CTUNfSF9fCj4g PiA+ICsKPiA+ID4gKyNkZWZpbmUgREVWSUNFX05BTUUJCQkJImlwbWktc3NpZi1ob3N0Igo+ID4g PiArCj4gPiA+ICsjZGVmaW5lIEdFVF84QklUX0FERFIoYWRkcl83Yml0KQkJKCgoYWRkcl83Yml0 KSA8PCAxKSAmIDB4ZmYpCj4gPiA+ICsKPiA+ID4gKy8qIEEgc3RhbmRhcmQgU01CdXMgVHJhbnNh Y3Rpb24gaXMgbGltaXRlZCB0byAzMiBkYXRhIGJ5dGVzICovCj4gPiA+ICsjZGVmaW5lIE1BWF9Q QVlMT0FEX1BFUl9UUkFOU0FDVElPTgkJMzIKPiA+ID4gKwo+ID4gPiArI2RlZmluZSBNQVhfSVBN SV9EQVRBX1BFUl9TVEFSVF9UUkFOU0FDVElPTgkzMAo+ID4gPiArI2RlZmluZSBNQVhfSVBNSV9E QVRBX1BFUl9NSURETEVfVFJBTlNBQ1RJT04JMzEKPiA+ID4gKwo+ID4gPiArI2RlZmluZSBTU0lG X0lQTUlfU0lOR0xFUEFSVF9XUklURQkJMHgyCj4gPiA+ICsjZGVmaW5lIFNTSUZfSVBNSV9TSU5H TEVQQVJUX1JFQUQJCTB4Mwo+ID4gPiArI2RlZmluZSBTU0lGX0lQTUlfTVVMVElQQVJUX1dSSVRF X1NUQVJUCQkweDYKPiA+ID4gKyNkZWZpbmUgU1NJRl9JUE1JX01VTFRJUEFSVF9XUklURV9NSURE TEUJMHg3Cj4gPiA+ICsjZGVmaW5lIFNTSUZfSVBNSV9NVUxUSVBBUlRfV1JJVEVfRU5ECQkweDgK PiA+ID4gKyNkZWZpbmUgU1NJRl9JUE1JX01VTFRJUEFSVF9SRUFEX1NUQVJUCQkweDMKPiA+ID4g KyNkZWZpbmUgU1NJRl9JUE1JX01VTFRJUEFSVF9SRUFEX01JRERMRQkJMHg5Cj4gPiA+ICsKPiA+ ID4gKyNkZWZpbmUgTVNHX1BBWUxPQURfTEVOX01BWAkJCTI1Mgo+ID4gPiArLyoKPiA+ID4gKyAq IElQTUkgMi4wIFNwZWMsIHNlY3Rpb24gMTIuNyBTU0lGIFRpbWluZywKPiA+ID4gKyAqIFJlcXVl c3QtdG8tUmVzcG9uc2UgVGltZSBpcyBUNm1heCgyNTBtcykgLSBUMW1heCgyMG1zKSAtIDNtcyA9 IDIyN21zCj4gPiA+ICsgKiBSZWNvdmVyIHNzaWZfYm1jIGZyb20gYnVzeSBzdGF0ZSBpZiBpdCB0 YWtlcyB1cHRvIDUwMG1zCj4gPiA+ICsgKi8KPiA+ID4gKyNkZWZpbmUgUkVTUE9OU0VfVElNRU9V VAkJCTUwMCAvKiBtcyAqLwo+ID4gPiArCj4gPiA+ICtzdHJ1Y3Qgc3NpZl9tc2cgewo+ID4gPiAr CXU4IGxlbjsKPiA+ID4gKwl1OCBuZXRmbl9sdW47Cj4gPiA+ICsJdTggY21kOwo+ID4gPiArCXU4 IHBheWxvYWRbTVNHX1BBWUxPQURfTEVOX01BWF07Cj4gPiA+ICt9IF9fcGFja2VkOwo+ID4gPiAr Cj4gPiA+ICtzdGF0aWMgaW5saW5lIHUzMiBzc2lmX21zZ19sZW4oc3RydWN0IHNzaWZfbXNnICpz c2lmX21zZykKPiA+ID4gK3sKPiA+ID4gKwlyZXR1cm4gc3NpZl9tc2ctPmxlbiArIDE7Cj4gPiA+ ICt9Cj4gPiA+ICsKPiA+ID4gKy8qCj4gPiA+ICsgKiBTU0lGIGludGVybmFsIHN0YXRlczoKPiA+ ID4gKyAqICAgU1NJRl9SRUFEWSAgICAgICAgIDB4MDAgOiBSZWFkeSBzdGF0ZQo+ID4gPiArICog ICBTU0lGX1NUQVJUICAgICAgICAgMHgwMSA6IFN0YXJ0IHNtYnVzIHRyYW5zYWN0aW9uCj4gPiA+ ICsgKiAgIFNTSUZfU01CVVNfQ01EICAgICAweDAyIDogUmVjZWl2ZWQgU01CdXMgY29tbWFuZAo+ ID4gPiArICogICBTU0lGX1JFUV9SRUNWSU5HICAgMHgwMyA6IFJlY2VpdmluZyByZXF1ZXN0Cj4g PiA+ICsgKiAgIFNTSUZfUkVTX1NFTkRJTkcgICAweDA0IDogU2VuZGluZyByZXNwb25zZQo+ID4g PiArICogICBTU0lGX0JBRF9TTUJVUyAgICAgMHgwNSA6IEJhZCBTTWJ1cyB0cmFuc2FjdGlvbgo+ ID4gPiArICovCj4gPiA+ICtlbnVtIHNzaWZfc3RhdGUgewo+ID4gPiArCVNTSUZfUkVBRFksCj4g PiA+ICsJU1NJRl9TVEFSVCwKPiA+ID4gKwlTU0lGX1NNQlVTX0NNRCwKPiA+ID4gKwlTU0lGX1JF UV9SRUNWSU5HLAo+ID4gPiArCVNTSUZfUkVTX1NFTkRJTkcsCj4gPiA+ICsJU1NJRl9CQURfU01C VVMsCj4gPiA+ICsJU1NJRl9TVEFURV9NQVgKPiA+ID4gK307Cj4gPiA+ICsKPiA+ID4gK3N0cnVj dCBzc2lmX2JtY19jdHggewo+ID4gPiArCXN0cnVjdCBpMmNfY2xpZW50CSpjbGllbnQ7Cj4gPiA+ ICsJc3RydWN0IG1pc2NkZXZpY2UJbWlzY2RldjsKPiA+ID4gKwlzaXplX3QJCQltc2dfaWR4Owo+ ID4gPiArCWJvb2wJCQlwZWNfc3VwcG9ydDsKPiA+ID4gKwkvKiBzc2lmIGJtYyBzcGlubG9jayAq Lwo+ID4gPiArCXNwaW5sb2NrX3QJCWxvY2s7Cj4gPiA+ICsJd2FpdF9xdWV1ZV9oZWFkX3QJd2Fp dF9xdWV1ZTsKPiA+ID4gKwl1OAkJCXJ1bm5pbmc7Cj4gPiA+ICsJZW51bSBzc2lmX3N0YXRlCQlz dGF0ZTsKPiA+ID4gKwl1OAkJCXNtYnVzX2NtZDsKPiA+ID4gKwkvKiBUaW1lb3V0IHdhaXRpbmcg Zm9yIHJlc3BvbnNlICovCj4gPiA+ICsJc3RydWN0IHRpbWVyX2xpc3QJcmVzcG9uc2VfdGltZXI7 Cj4gPiA+ICsJYm9vbCAgICAgICAgICAgICAgICAgICAgcmVzcG9uc2VfdGltZXJfaW5pdGVkOwo+ ID4gPiArCS8qIEZsYWcgdG8gaWRlbnRpZnkgYSBNdWx0aS1wYXJ0IFJlYWQgVHJhbnNhY3Rpb24g Ki8KPiA+ID4gKwlib29sCQkJaXNfc2luZ2xlcGFydF9yZWFkOwo+ID4gPiArCXU4CQkJbmJ5dGVz X3Byb2Nlc3NlZDsKPiA+ID4gKwl1OAkJCXJlbWFpbl9sZW47Cj4gPiA+ICsJdTgJCQlyZWN2X2xl bjsKPiA+ID4gKwkvKiBCbG9jayBOdW1iZXIgb2YgYSBNdWx0aS1wYXJ0IFJlYWQgVHJhbnNhY3Rp b24gKi8KPiA+ID4gKwl1OAkJCWJsb2NrX251bTsKPiA+ID4gKwlib29sCQkJcmVxdWVzdF9hdmFp bGFibGU7Cj4gPiA+ICsJYm9vbAkJCXJlc3BvbnNlX2luX3Byb2dyZXNzOwo+ID4gPiArCWJvb2wJ CQlidXN5Owo+ID4gPiArCS8qIFJlc3BvbnNlIGJ1ZmZlciBmb3IgTXVsdGktcGFydCBSZWFkIFRy YW5zYWN0aW9uICovCj4gPiA+ICsJdTgJCQlyZXNwb25zZV9idWZbTUFYX1BBWUxPQURfUEVSX1RS QU5TQUNUSU9OXTsKPiA+ID4gKwlzdHJ1Y3Qgc3NpZl9tc2cJCXJlc3BvbnNlOwo+ID4gPiArCXN0 cnVjdCBzc2lmX21zZwkJcmVxdWVzdDsKPiA+ID4gK307Cj4gPiA+ICsKPiA+ID4gK3N0YXRpYyBp bmxpbmUgc3RydWN0IHNzaWZfYm1jX2N0eCAqdG9fc3NpZl9ibWMoc3RydWN0IGZpbGUgKmZpbGUp Cj4gPiA+ICt7Cj4gPiA+ICsJcmV0dXJuIGNvbnRhaW5lcl9vZihmaWxlLT5wcml2YXRlX2RhdGEs IHN0cnVjdCBzc2lmX2JtY19jdHgsIG1pc2NkZXYpOwo+ID4gPiArfQo+ID4gPiArI2VuZGlmIC8q IF9fU1NJRl9CTUNfSF9fICovCj4gPiA+IC0tIAo+ID4gPiAyLjM1LjEKPiA+ID4gCj4gPiA+IAoK X19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18KbGludXgtYXJt LWtlcm5lbCBtYWlsaW5nIGxpc3QKbGludXgtYXJtLWtlcm5lbEBsaXN0cy5pbmZyYWRlYWQub3Jn Cmh0dHA6Ly9saXN0cy5pbmZyYWRlYWQub3JnL21haWxtYW4vbGlzdGluZm8vbGludXgtYXJtLWtl cm5lbAo=