From mboxrd@z Thu Jan 1 00:00:00 1970 From: Quan Nguyen Date: Wed, 14 Jul 2021 10:38:32 +0700 Subject: [PATCH v5 2/3] ipmi: ssif_bmc: Add SSIF BMC driver In-Reply-To: <20210714033833.11640-1-quan@os.amperecomputing.com> References: <20210714033833.11640-1-quan@os.amperecomputing.com> Message-ID: <20210714033833.11640-3-quan@os.amperecomputing.com> List-Id: To: linux-aspeed@lists.ozlabs.org MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit The SMBus system interface (SSIF) IPMI BMC driver can be used to perform in-band IPMI communication with their host in management (BMC) side. Signed-off-by: Quan Nguyen --- v5: + None v4: + Send response with Completion code 0xFF when aborting [Quan] + Added bounding check on SMBus writes and the whole request [Dan] + Moved buffer to end of struct ssif_bmc_ctx to avoid context corruption if somehow buffer is written past the end [Dan] + Return -EINVAL if userspace buffer too small, dont silence truncate [Corey, Joel] + Not necessary to check NONBLOCK in lock [Corey] + Enforce one user at a time [Joel] + Reject write with invalid response length from userspace [Corey] + Add state machines for better ssif bmc state handling [Quan] + Drop ssif_bmc_aspeed.c and make ssif_bmc.c is generic SSIF BMC driver [Quan] + Change compatible string "aspeed,ast2500-ssif-bmc" to "ampere,ssif-bmc" [Quan] + Abort current request with invalid SMBus write or invalid command [Quan] + Abort all request if there is pending response [Quan] + Changed validate_pec() to validate_request() [Quan] + Add unsupported_smbus_cmd() to handle unknown SMBus command [Quan] + Print internal state string for ease investigating issue [Quan] + Move to READY state on SLAVE_STOP event [Quan] + Change initilize_transfer() to process_smbus_cmd() [Quan] + Introduce functions for each slave event [Quan] v3: + Removed redundant license info [Joel] + Switched to use traditional if-else [Joel] + Removed unused ssif_bmc_ioctl() [Joel] + Made handle_request()/complete_response() to return void [Joel] + Refactored send_ssif_bmc_response()/receive_ssif_bmc_request() [Corey] + Removed mutex [Corey] + Use spin_lock/unlock_irqsave/restore in callback [Corey] + Removed the unnecessary memset [Corey] + Switch to use dev_err() [Corey] v2: + Fixed compiling error with COMPILE_TEST for arc drivers/char/ipmi/Kconfig | 11 + drivers/char/ipmi/Makefile | 1 + drivers/char/ipmi/ssif_bmc.c | 781 +++++++++++++++++++++++++++++++++++ drivers/char/ipmi/ssif_bmc.h | 106 +++++ 4 files changed, 899 insertions(+) create mode 100644 drivers/char/ipmi/ssif_bmc.c create mode 100644 drivers/char/ipmi/ssif_bmc.h diff --git a/drivers/char/ipmi/Kconfig b/drivers/char/ipmi/Kconfig index 249b31197eea..e09a470ab2da 100644 --- a/drivers/char/ipmi/Kconfig +++ b/drivers/char/ipmi/Kconfig @@ -160,6 +160,17 @@ config ASPEED_BT_IPMI_BMC found on Aspeed SOCs (AST2400 and AST2500). The driver implements the BMC side of the BT interface. +config SSIF_IPMI_BMC + tristate "SSIF IPMI BMC driver" + select I2C + select I2C_SLAVE + help + This enables the IPMI SMBus system interface (SSIF) at the + management (BMC) side. + + The driver implements the BMC side of the SMBus system + interface (SSIF). + config IPMB_DEVICE_INTERFACE tristate 'IPMB Interface handler' depends on I2C diff --git a/drivers/char/ipmi/Makefile b/drivers/char/ipmi/Makefile index 84f47d18007f..a93c09dad22a 100644 --- a/drivers/char/ipmi/Makefile +++ b/drivers/char/ipmi/Makefile @@ -29,3 +29,4 @@ obj-$(CONFIG_ASPEED_BT_IPMI_BMC) += bt-bmc.o obj-$(CONFIG_ASPEED_KCS_IPMI_BMC) += kcs_bmc_aspeed.o obj-$(CONFIG_NPCM7XX_KCS_IPMI_BMC) += kcs_bmc_npcm7xx.o obj-$(CONFIG_IPMB_DEVICE_INTERFACE) += ipmb_dev_int.o +obj-$(CONFIG_SSIF_IPMI_BMC) += ssif_bmc.o diff --git a/drivers/char/ipmi/ssif_bmc.c b/drivers/char/ipmi/ssif_bmc.c new file mode 100644 index 000000000000..b15c05622e72 --- /dev/null +++ b/drivers/char/ipmi/ssif_bmc.c @@ -0,0 +1,781 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * The driver for BMC side of SSIF interface + * + * Copyright (c) 2021, Ampere Computing LLC + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ssif_bmc.h" + +static const char *state_to_string(enum ssif_state state) +{ + switch (state) { + case SSIF_READY: + return "SSIF_READY"; + case SSIF_START: + return "SSIF_START"; + case SSIF_SMBUS_CMD: + return "SSIF_SMBUS_CMD"; + case SSIF_REQ_RECVING: + return "SSIF_REQ_RECVING"; + case SSIF_RES_SENDING: + return "SSIF_RES_SENDING"; + case SSIF_BAD_SMBUS: + return "SSIF_BAD_SMBUS"; + default: + return "SSIF_STATE_UNKNOWN"; + } +} + +/* Handle SSIF message that will be sent to user */ +static ssize_t ssif_bmc_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) +{ + struct ssif_bmc_ctx *ssif_bmc = to_ssif_bmc(file); + struct ssif_msg msg; + unsigned long flags; + ssize_t ret; + + spin_lock_irqsave(&ssif_bmc->lock, flags); + while (!ssif_bmc->request_available) { + spin_unlock_irqrestore(&ssif_bmc->lock, flags); + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; + ret = wait_event_interruptible(ssif_bmc->wait_queue, + ssif_bmc->request_available); + if (ret) + return ret; + spin_lock_irqsave(&ssif_bmc->lock, flags); + } + + if (count < min_t(ssize_t, ssif_msg_len(&ssif_bmc->request), sizeof(struct ssif_msg))) { + spin_unlock_irqrestore(&ssif_bmc->lock, flags); + ret = -EINVAL; + } else { + count = min_t(ssize_t, ssif_msg_len(&ssif_bmc->request), sizeof(struct ssif_msg)); + memcpy(&msg, &ssif_bmc->request, count); + ssif_bmc->request_available = false; + spin_unlock_irqrestore(&ssif_bmc->lock, flags); + + ret = copy_to_user(buf, &msg, count); + } + + return (ret < 0) ? ret : count; +} + +/* Handle SSIF message that is written by user */ +static ssize_t ssif_bmc_write(struct file *file, const char __user *buf, size_t count, + loff_t *ppos) +{ + struct ssif_bmc_ctx *ssif_bmc = to_ssif_bmc(file); + struct ssif_msg msg; + unsigned long flags; + ssize_t ret; + + if (count > sizeof(struct ssif_msg)) + return -EINVAL; + + ret = copy_from_user(&msg, buf, count); + if (ret) + return ret; + + if (!msg.len || count < ssif_msg_len(&msg)) + return -EINVAL; + + spin_lock_irqsave(&ssif_bmc->lock, flags); + while (ssif_bmc->response_in_progress) { + spin_unlock_irqrestore(&ssif_bmc->lock, flags); + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; + ret = wait_event_interruptible(ssif_bmc->wait_queue, + !ssif_bmc->response_in_progress); + if (ret) + return ret; + spin_lock_irqsave(&ssif_bmc->lock, flags); + } + + memcpy(&ssif_bmc->response, &msg, count); + ssif_bmc->is_singlepart_read = (ssif_msg_len(&msg) <= MAX_PAYLOAD_PER_TRANSACTION + 1); + ssif_bmc->response_in_progress = true; + + if (ssif_bmc->client->adapter->algo->slave_enable) + ret = ssif_bmc->client->adapter->algo->slave_enable(ssif_bmc->client, true); + + spin_unlock_irqrestore(&ssif_bmc->lock, flags); + + return (ret < 0) ? ret : count; +} + +static int ssif_bmc_open(struct inode *inode, struct file *file) +{ + struct ssif_bmc_ctx *ssif_bmc = to_ssif_bmc(file); + int ret = 0; + + spin_lock_irq(&ssif_bmc->lock); + if (!ssif_bmc->running) + ssif_bmc->running = 1; + else + ret = -EBUSY; + spin_unlock_irq(&ssif_bmc->lock); + + return ret; +} + +static unsigned int ssif_bmc_poll(struct file *file, poll_table *wait) +{ + struct ssif_bmc_ctx *ssif_bmc = to_ssif_bmc(file); + unsigned int mask = 0; + + poll_wait(file, &ssif_bmc->wait_queue, wait); + + spin_lock_irq(&ssif_bmc->lock); + /* The request is available, userspace application can get the request */ + if (ssif_bmc->request_available) + mask |= POLLIN; + + spin_unlock_irq(&ssif_bmc->lock); + + return mask; +} + +static int ssif_bmc_release(struct inode *inode, struct file *file) +{ + struct ssif_bmc_ctx *ssif_bmc = to_ssif_bmc(file); + + spin_lock_irq(&ssif_bmc->lock); + ssif_bmc->running = 0; + spin_unlock_irq(&ssif_bmc->lock); + + return 0; +} + +/* + * System calls to device interface for user apps + */ +static const struct file_operations ssif_bmc_fops = { + .owner = THIS_MODULE, + .open = ssif_bmc_open, + .read = ssif_bmc_read, + .write = ssif_bmc_write, + .release = ssif_bmc_release, + .poll = ssif_bmc_poll, +}; + +/* Called with ssif_bmc->lock held. */ +static void complete_response(struct ssif_bmc_ctx *ssif_bmc) +{ + /* Invalidate response in buffer to denote it having been sent. */ + ssif_bmc->response.len = 0; + ssif_bmc->response_in_progress = false; + ssif_bmc->nbytes_processed = 0; + ssif_bmc->remain_len = 0; + wake_up_all(&ssif_bmc->wait_queue); +} + +/* Called with ssif_bmc->lock held. */ +static void handle_request(struct ssif_bmc_ctx *ssif_bmc) +{ + if (ssif_bmc->client->adapter->algo->slave_enable) + ssif_bmc->client->adapter->algo->slave_enable(ssif_bmc->client, false); + + /* Request message is available to process */ + ssif_bmc->request_available = true; + /* + * This is the new READ request. + */ + wake_up_all(&ssif_bmc->wait_queue); +} + +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; + + 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, aborting ...\n", + __func__, ssif_bmc->smbus_cmd); + ssif_bmc->aborting = true; + 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 { + *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 */ + 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, aborting ...\n", + __func__, ssif_bmc->smbus_cmd); + ssif_bmc->aborting = true; + 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; + + 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, aborting ..."); + ssif_bmc->aborting = true; + } + + 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, aborting ..."); + ssif_bmc->aborting = true; + } + + 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, aborting ..."); + ssif_bmc->aborting = true; + } + + } else { + buf[ssif_bmc->msg_idx - 1 + + ssif_bmc->request.len - ssif_bmc->recv_len] = *val; + } + + 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, aborting ...\n", + __func__, ssif_bmc->smbus_cmd); + ssif_bmc->aborting = true; + break; + } +} + +static bool validate_request(struct ssif_bmc_ctx *ssif_bmc) +{ + u8 rpec = 0, cpec = 0; + bool ret = true; + u8 addr, index; + u8 *buf; + + 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); + /* 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, aborting ...\n", + __func__, ssif_bmc->smbus_cmd); + ret = false; + break; + } + +exit: + return ret; +} + +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, aborting ..."); + ssif_bmc->aborting = true; + } else if (ssif_bmc->aborting && + (*val == SSIF_IPMI_SINGLEPART_WRITE || + *val == SSIF_IPMI_MULTIPART_WRITE_START)) { + /* New request */ + dev_warn(&ssif_bmc->client->dev, "Warn: New request found, stop aborting ..."); + ssif_bmc->aborting = false; + } +} + +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, aborting ...\n", + __func__, state_to_string(ssif_bmc->state)); + ssif_bmc->aborting = true; + + } else if (ssif_bmc->state == SSIF_SMBUS_CMD) { + ssif_bmc->state = SSIF_RES_SENDING; + } + + if (ssif_bmc->aborting || ssif_bmc->state != SSIF_RES_SENDING) { + /* Abort by returning the last request with 0xFF as completion code */ + ssif_bmc->is_singlepart_read = true; + ssif_bmc->response.len = 0x03; + ssif_bmc->response.netfn_lun = ssif_bmc->request.netfn_lun | 4; + ssif_bmc->response.cmd = ssif_bmc->request.cmd; + memset(&ssif_bmc->response.payload[0], 0xFF, MAX_PAYLOAD_PER_TRANSACTION); + } + + 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) { + if (ssif_bmc->response_in_progress) { + /* + * As per spec, it is generic management software or SSIF drivers to take + * care of issuing new request before the prior requests completed. + * So just abort everything here and wait for next new request + */ + dev_warn(&ssif_bmc->client->dev, + "Warn: SSIF new request with pending response, aborting ..."); + ssif_bmc->aborting = true; + complete_response(ssif_bmc); + } + + 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)) + ssif_bmc->aborting = true; + + if (!ssif_bmc->aborting && + (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); + + 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, aborting ...\n"); + ssif_bmc->aborting = true; + break; + } + + spin_unlock_irqrestore(&ssif_bmc->lock, flags); + + return 0; +} + +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; + + /* 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 v2"); diff --git a/drivers/char/ipmi/ssif_bmc.h b/drivers/char/ipmi/ssif_bmc.h new file mode 100644 index 000000000000..b63e40a4b900 --- /dev/null +++ b/drivers/char/ipmi/ssif_bmc.h @@ -0,0 +1,106 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * The driver for BMC side of SSIF interface + * + * Copyright (c) 2021, Ampere Computing LLC + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#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 + +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; + /* Flag to abort current process */ + bool aborting; + /* 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; + /* 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.28.0 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 X-Spam-Level: X-Spam-Status: No, score=-18.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,MSGID_FROM_MTA_HEADER,SPF_HELO_NONE, SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id C8F85C11F67 for ; Wed, 14 Jul 2021 03:39:20 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id A7B4B613BE for ; Wed, 14 Jul 2021 03:39:20 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237795AbhGNDmK (ORCPT ); Tue, 13 Jul 2021 23:42:10 -0400 Received: from mail-bn8nam12on2124.outbound.protection.outlook.com ([40.107.237.124]:57697 "EHLO NAM12-BN8-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S237777AbhGNDmE (ORCPT ); Tue, 13 Jul 2021 23:42:04 -0400 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=Fm6iozN+8dJttORZOtFCd9ZSBwrVFUBPR3WKvvzGcaF0CVwkvdDd9tHCZu5jsgosJarnf+V189ffAzM2NX0ZJH1WTkvC0cv5xS4N6N8W4DA/94mZdmWfUOkh8s7BuMpJZDvddaJ6k8m83k0C95HOfF1xnNiogGNfIZxEO4yR4z0Ibu5qBuVxE6D172F7koGc912uo0vnyGJU964GkfWJ5W4SCzsrTFZG4VO7Zri7sBh2qlFdSeL757Ca0Qa4hWbd9lInvmN3rH5TsxmPtytPy8rMKF2FvrZhHGghKXgB9yhi+xuJdipCETe4jvKLTt+ztN0NaOD7as4F7IMSp/kXmQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=43sUey2steEyS7GkmjkqCXWUMwi0B7maERi2FrYOQHg=; b=T5QLE38SvX1lkrNbuZlOcJ1Uke6akWStFVAJxe6ugWeYguCRw3qrpjMosy/aCCMnLSfKcP3Gl/PnDgMvgzraxf5wUFleTxI/5H3PdfZVK/AQoNnw2n2v1kujUYuxW0+ehDcSCMuKC8qwowN4uNn06Bz3F9at1bjKxinfTCKGxsjhe1LHpteyvWk36AMw7jaNdlf02RejsKGIqbinr3D8v6Hv1dj+OJ7s19qNinEtrQPpr6Q/AiLLBeLd/9oTDqIFbTUWwDv/aLRxMiFYttSsHPraGjXVLSFpDoffpv3vkmPAbrD483dq1uVLkZr3GoSQpR+ts99c3ZNfqc/uUYIuTA== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=os.amperecomputing.com; dmarc=pass action=none header.from=os.amperecomputing.com; dkim=pass header.d=os.amperecomputing.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=os.amperecomputing.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=43sUey2steEyS7GkmjkqCXWUMwi0B7maERi2FrYOQHg=; b=QU8rbeWmcYP6ZB9YOJhlXysOwadwf0gWSANEIiAM9OtsIfUhjIUZoF9iBwB7THNb1wUlObNWZ1pf8eW4jCfhbDy/rxfPgBKHyRF8DIPIcYpI0VS6Xk80z0nSlHmEMcvjzZKDxZB+a4gdmkwrPCJRQdmoRaJ/odfnIgvGQhZZRRY= Authentication-Results: acm.org; dkim=none (message not signed) header.d=none;acm.org; dmarc=none action=none header.from=os.amperecomputing.com; Received: from MW2PR0102MB3482.prod.exchangelabs.com (2603:10b6:302:c::32) by MW2PR0102MB3370.prod.exchangelabs.com (2603:10b6:302:2::23) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4308.22; Wed, 14 Jul 2021 03:39:01 +0000 Received: from MW2PR0102MB3482.prod.exchangelabs.com ([fe80::452a:24fb:12cb:9d7e]) by MW2PR0102MB3482.prod.exchangelabs.com ([fe80::452a:24fb:12cb:9d7e%5]) with mapi id 15.20.4308.027; Wed, 14 Jul 2021 03:39:01 +0000 From: Quan Nguyen To: Corey Minyard , Rob Herring , 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 Cc: Open Source Submission , Phong Vo , "Thang Q . Nguyen" Subject: [PATCH v5 2/3] ipmi: ssif_bmc: Add SSIF BMC driver Date: Wed, 14 Jul 2021 10:38:32 +0700 Message-Id: <20210714033833.11640-3-quan@os.amperecomputing.com> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20210714033833.11640-1-quan@os.amperecomputing.com> References: <20210714033833.11640-1-quan@os.amperecomputing.com> Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-ClientProxiedBy: HK0PR03CA0099.apcprd03.prod.outlook.com (2603:1096:203:b0::15) To MW2PR0102MB3482.prod.exchangelabs.com (2603:10b6:302:c::32) MIME-Version: 1.0 X-MS-Exchange-MessageSentRepresentingType: 1 Received: from hcm-sw-17.amperecomputing.com (118.69.219.201) by HK0PR03CA0099.apcprd03.prod.outlook.com (2603:1096:203:b0::15) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4331.21 via Frontend Transport; Wed, 14 Jul 2021 03:38:57 +0000 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: 076d9254-0e13-4fe6-5dd9-08d94678eb56 X-MS-TrafficTypeDiagnostic: MW2PR0102MB3370: X-MS-Exchange-Transport-Forked: True X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:3044; X-MS-Exchange-SenderADCheck: 1 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: iPyEj+dDftSGg5YPE7wpseaOamvUiKAXVM4caEckd2Z+b3enjxsjp/obo7ti3YeV7mZDkmAML0vu1JZ7eTOsj6BjOAugpolfu5EnClMybn3rfVfNjOsjX62NXF5W/zbUxJ3qcY9bfXPLQ2TyGbBXe3rtYFpP2RnM/ujpPPMItVWj87xRcn55uHM0Juo8eRGoIJdhtRXZYoL2Z2r/AevfM1qFtBZWvENmrDBv6pmZ9iF64nSWgt5APPLDTWu5akHgKn6SfJBYiK9GKc4nYdu+bIMR46RDk5rzmO83LHOQK4Jj2EOYoAprjU/GrR+/JHLiYauaXJE6z9bFe4fBwp7STKGwF6j0BEtL0IJJlVTrpmWFTWOE3d24mW4ULSVBN1EsKe0zgUXhwIbnBJ0eP89mHMVnwYKRExIfAezU4BEa1LbpeU6PI3+hKZKL+qoazw/R5wffJwzoTb6qSne9NRrt4HsGiyYsGuFlbB8Ub5p+hSnM4xxMApP2Gegzduqkan6q8ehoqzV0MmtR6H6dNdkfJKFhL6wV0x+SG5S+A6FI+XpV/rcKcflkvDxxnm4hV5XV7vrQ1DNBw0o3R70MC2DA6cyw18Im5w0TSiqdVwMw4JhRKHrDXRvNwQ4aOkEwsK59TbHBZQnMMOPA+p69NnurFT+hg0wkg+ZDRFXpuYIbJlopKPWcGnTsToMCDPqLZyj/SujkepzHSrrYH6g8A8N1FrnxP//rZ14LGl6WliTSexgXi1paNEn3pVyLbwLu6UUGV/1KrkWtuL/+eEDeHbXtIywG9oB/HZmMQAxBrKC0PG+oT6C3oVl1PX+b8TsUMbDeKxZO9EFs7ydlUxPVAl+wvQ== X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:MW2PR0102MB3482.prod.exchangelabs.com;PTR:;CAT:NONE;SFS:(4636009)(376002)(136003)(346002)(366004)(39850400004)(396003)(4326008)(38100700002)(1076003)(38350700002)(2616005)(107886003)(956004)(8936002)(8676002)(6506007)(30864003)(86362001)(110136005)(52116002)(5660300002)(54906003)(2906002)(6666004)(478600001)(26005)(186003)(66946007)(83380400001)(7416002)(66556008)(66476007)(6512007)(921005)(6486002)(316002)(2004002);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?d3ovTkNMNGRDRFZvUjY5VVMxeVF1UWJGUXV2bDhpY0NZNytPeVZXcnZFT1Zu?= =?utf-8?B?VUx4MzJZcnViWUYzS3RwZy9qYjVoT1ZrUXA4Y1VFTHpRMDVsa0MzNHlBVjVz?= =?utf-8?B?b203dVlnNjhYWTR3YXU5SmVXR1NGaVY1U05XZDdOSno5SnNGbE81ZlFydk5L?= =?utf-8?B?a3Ivb1UwdFNQUm5FaUFDendGMWxVaitGUXdMcmxZZ3krNndLSUtMQnV3eUdm?= =?utf-8?B?QjB0M0ZQZml6SDRsZTI5Q21XWkw0T0dLS1NYbUFYWHJFV25HLzdVZE5DUkp0?= =?utf-8?B?MStET3BkYVl5RjNlRmRTSlZ1MS9Vcnk4NlJ1T04yTlRZYjhKSkthODcxb1RJ?= =?utf-8?B?SW1jVGpuM2FlRmI5T0E3dCtMbG5KWFRhY1hubENoMXU0U081RkY5SXZwb2k1?= =?utf-8?B?RGZuR0MrVkZwb012RHcycG82UWZFYlM0TWlTQlJDMSszV1I0c1JUYkFWTUlk?= =?utf-8?B?T3NyU0dGOGZmU3hyM3VuRkdXOTFXR0NwSWhWNHhwODhPOUEvK0dUbnNuTlR3?= =?utf-8?B?STk2YktkRThXT0c1ZlZUcUJjQUlVeFduMUQwa1VkWG9uWHBoUzZaWG1xVGNy?= =?utf-8?B?Q1RZbE5SUmZqSFNYYTdZMXdLT1psY0VnRk1CemdjTzVBQnFlcXNIUlNVTU1n?= =?utf-8?B?ZWwxTUtBNXZyUGJuU0U5YWcxNXJ6TkpHQzJmdmN6ek1FNVFtZjRjSzM3NTZj?= =?utf-8?B?ank1UjdMdjk2TTRha1NPS2pmRmtJSnQwRGt2ZDR5cWxBVXFDM2NsR244QThM?= =?utf-8?B?VHpFYXJoUkVyOGpWcTlaVU53OFZ2S29Jd2s1T3MvMHhBUHJWV250cGlWenB4?= =?utf-8?B?TzBXVDAyVmI4cEVUYWJwSXJyalVuNHFndmh6ZUlWelIvSnl1VUh6T2JodGJ3?= =?utf-8?B?NnBFWUxsKzJOSnZtdlE1dkcyNHpXKzNJaTlKVHAvRll0amEvZllTRUo5Sm15?= =?utf-8?B?VmQrZjFxR2l5R2kvSStnSTJwNHFvYXQwcGRSTWpHM2dac1ZJNnErTEMzMFlX?= =?utf-8?B?RVlpRXcvbk9GMm0ySHJ4aFlkTFUyTFc1N2hKMmFOYUlDTlV5YjJlY0lGSFQv?= =?utf-8?B?VXZGSmhKM3lPcHgxaDJ0RXI3MWVFNlpCemdJZCtWd2lqLyt5VzgrWlZ4TVZ5?= =?utf-8?B?UFpqZ2NQRnVyS2NCZDRheWNMNlZwdzFuYnJYN3d5NDNqM21melVPVFJqNG0z?= =?utf-8?B?Z0RRenBSWENsNXZNa29TWEJMTkMxVENOL2NGeFdiNWRjZ2ZCMG5pSWJkOVpI?= =?utf-8?B?M1hLRFMydmE3OVppVWxLbmJOTWhrTzhuL3pGbCtUdHlydzlPQ2k1VlZ0VGda?= =?utf-8?B?MWpmeDJSdzlKOTZsNnlqMzFLcVR4YmhKSnFlb3RCWUNjZktHcHg4R0tZek05?= =?utf-8?B?VlJ5cStBYy9CelZGTDl3dzVPUmt0NHVrR0ZXUFpEWkVvOTg5dWVJUUVNQzQv?= =?utf-8?B?WGgyWDdSRlBQYUxmZ3RrVkM5SGRPUlA3ZW52b0Jaa2xwZ3lYM1JDWlRpSkZL?= =?utf-8?B?eGs4ZXRPYzE3VkVEaWtiM3F2eUJyUk5TL3FMd2IraWN4amNQUlZWazlwa2FF?= =?utf-8?B?TmMvUmxBbmFnUXIvZUp5TEhsa0RML2l4REo0aFYzYk82TzB1NnZ2NzVMdE5p?= =?utf-8?B?ZlBJMzNTcEFibTVVRDRmTmgrTWZpRHUrZTV1a2VlYnNKWmNPSUtQSi9kM0JG?= =?utf-8?B?WTVpaWtSdVJSU2V5dE1maFJYZi9rK1hrNWQxQ3NUTXdGOGNnNUpLS2dxV3BM?= =?utf-8?Q?D9Ff1C5Y3hR4+BWq6V6gKVjHpXDppZ4mjZdeWcg?= X-OriginatorOrg: os.amperecomputing.com X-MS-Exchange-CrossTenant-Network-Message-Id: 076d9254-0e13-4fe6-5dd9-08d94678eb56 X-MS-Exchange-CrossTenant-AuthSource: MW2PR0102MB3482.prod.exchangelabs.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 14 Jul 2021 03:39:01.2898 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 3bc2b170-fd94-476d-b0ce-4229bdc904a7 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: Li/s/gGCJxTYjiC7HzTl8EmUZpzDLn/la2VBPcMQYZlgNNmRhfi533B4BqFZ/xs0RRt1FgelW/56vQaHimCaVMvak6Vs4K8ZiWnx9EllQBU= X-MS-Exchange-Transport-CrossTenantHeadersStamped: MW2PR0102MB3370 Precedence: bulk List-ID: X-Mailing-List: linux-i2c@vger.kernel.org The SMBus system interface (SSIF) IPMI BMC driver can be used to perform in-band IPMI communication with their host in management (BMC) side. Signed-off-by: Quan Nguyen --- v5: + None v4: + Send response with Completion code 0xFF when aborting [Quan] + Added bounding check on SMBus writes and the whole request [Dan] + Moved buffer to end of struct ssif_bmc_ctx to avoid context corruption if somehow buffer is written past the end [Dan] + Return -EINVAL if userspace buffer too small, dont silence truncate [Corey, Joel] + Not necessary to check NONBLOCK in lock [Corey] + Enforce one user at a time [Joel] + Reject write with invalid response length from userspace [Corey] + Add state machines for better ssif bmc state handling [Quan] + Drop ssif_bmc_aspeed.c and make ssif_bmc.c is generic SSIF BMC driver [Quan] + Change compatible string "aspeed,ast2500-ssif-bmc" to "ampere,ssif-bmc" [Quan] + Abort current request with invalid SMBus write or invalid command [Quan] + Abort all request if there is pending response [Quan] + Changed validate_pec() to validate_request() [Quan] + Add unsupported_smbus_cmd() to handle unknown SMBus command [Quan] + Print internal state string for ease investigating issue [Quan] + Move to READY state on SLAVE_STOP event [Quan] + Change initilize_transfer() to process_smbus_cmd() [Quan] + Introduce functions for each slave event [Quan] v3: + Removed redundant license info [Joel] + Switched to use traditional if-else [Joel] + Removed unused ssif_bmc_ioctl() [Joel] + Made handle_request()/complete_response() to return void [Joel] + Refactored send_ssif_bmc_response()/receive_ssif_bmc_request() [Corey] + Removed mutex [Corey] + Use spin_lock/unlock_irqsave/restore in callback [Corey] + Removed the unnecessary memset [Corey] + Switch to use dev_err() [Corey] v2: + Fixed compiling error with COMPILE_TEST for arc drivers/char/ipmi/Kconfig | 11 + drivers/char/ipmi/Makefile | 1 + drivers/char/ipmi/ssif_bmc.c | 781 +++++++++++++++++++++++++++++++++++ drivers/char/ipmi/ssif_bmc.h | 106 +++++ 4 files changed, 899 insertions(+) create mode 100644 drivers/char/ipmi/ssif_bmc.c create mode 100644 drivers/char/ipmi/ssif_bmc.h diff --git a/drivers/char/ipmi/Kconfig b/drivers/char/ipmi/Kconfig index 249b31197eea..e09a470ab2da 100644 --- a/drivers/char/ipmi/Kconfig +++ b/drivers/char/ipmi/Kconfig @@ -160,6 +160,17 @@ config ASPEED_BT_IPMI_BMC found on Aspeed SOCs (AST2400 and AST2500). The driver implements the BMC side of the BT interface. +config SSIF_IPMI_BMC + tristate "SSIF IPMI BMC driver" + select I2C + select I2C_SLAVE + help + This enables the IPMI SMBus system interface (SSIF) at the + management (BMC) side. + + The driver implements the BMC side of the SMBus system + interface (SSIF). + config IPMB_DEVICE_INTERFACE tristate 'IPMB Interface handler' depends on I2C diff --git a/drivers/char/ipmi/Makefile b/drivers/char/ipmi/Makefile index 84f47d18007f..a93c09dad22a 100644 --- a/drivers/char/ipmi/Makefile +++ b/drivers/char/ipmi/Makefile @@ -29,3 +29,4 @@ obj-$(CONFIG_ASPEED_BT_IPMI_BMC) += bt-bmc.o obj-$(CONFIG_ASPEED_KCS_IPMI_BMC) += kcs_bmc_aspeed.o obj-$(CONFIG_NPCM7XX_KCS_IPMI_BMC) += kcs_bmc_npcm7xx.o obj-$(CONFIG_IPMB_DEVICE_INTERFACE) += ipmb_dev_int.o +obj-$(CONFIG_SSIF_IPMI_BMC) += ssif_bmc.o diff --git a/drivers/char/ipmi/ssif_bmc.c b/drivers/char/ipmi/ssif_bmc.c new file mode 100644 index 000000000000..b15c05622e72 --- /dev/null +++ b/drivers/char/ipmi/ssif_bmc.c @@ -0,0 +1,781 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * The driver for BMC side of SSIF interface + * + * Copyright (c) 2021, Ampere Computing LLC + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ssif_bmc.h" + +static const char *state_to_string(enum ssif_state state) +{ + switch (state) { + case SSIF_READY: + return "SSIF_READY"; + case SSIF_START: + return "SSIF_START"; + case SSIF_SMBUS_CMD: + return "SSIF_SMBUS_CMD"; + case SSIF_REQ_RECVING: + return "SSIF_REQ_RECVING"; + case SSIF_RES_SENDING: + return "SSIF_RES_SENDING"; + case SSIF_BAD_SMBUS: + return "SSIF_BAD_SMBUS"; + default: + return "SSIF_STATE_UNKNOWN"; + } +} + +/* Handle SSIF message that will be sent to user */ +static ssize_t ssif_bmc_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) +{ + struct ssif_bmc_ctx *ssif_bmc = to_ssif_bmc(file); + struct ssif_msg msg; + unsigned long flags; + ssize_t ret; + + spin_lock_irqsave(&ssif_bmc->lock, flags); + while (!ssif_bmc->request_available) { + spin_unlock_irqrestore(&ssif_bmc->lock, flags); + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; + ret = wait_event_interruptible(ssif_bmc->wait_queue, + ssif_bmc->request_available); + if (ret) + return ret; + spin_lock_irqsave(&ssif_bmc->lock, flags); + } + + if (count < min_t(ssize_t, ssif_msg_len(&ssif_bmc->request), sizeof(struct ssif_msg))) { + spin_unlock_irqrestore(&ssif_bmc->lock, flags); + ret = -EINVAL; + } else { + count = min_t(ssize_t, ssif_msg_len(&ssif_bmc->request), sizeof(struct ssif_msg)); + memcpy(&msg, &ssif_bmc->request, count); + ssif_bmc->request_available = false; + spin_unlock_irqrestore(&ssif_bmc->lock, flags); + + ret = copy_to_user(buf, &msg, count); + } + + return (ret < 0) ? ret : count; +} + +/* Handle SSIF message that is written by user */ +static ssize_t ssif_bmc_write(struct file *file, const char __user *buf, size_t count, + loff_t *ppos) +{ + struct ssif_bmc_ctx *ssif_bmc = to_ssif_bmc(file); + struct ssif_msg msg; + unsigned long flags; + ssize_t ret; + + if (count > sizeof(struct ssif_msg)) + return -EINVAL; + + ret = copy_from_user(&msg, buf, count); + if (ret) + return ret; + + if (!msg.len || count < ssif_msg_len(&msg)) + return -EINVAL; + + spin_lock_irqsave(&ssif_bmc->lock, flags); + while (ssif_bmc->response_in_progress) { + spin_unlock_irqrestore(&ssif_bmc->lock, flags); + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; + ret = wait_event_interruptible(ssif_bmc->wait_queue, + !ssif_bmc->response_in_progress); + if (ret) + return ret; + spin_lock_irqsave(&ssif_bmc->lock, flags); + } + + memcpy(&ssif_bmc->response, &msg, count); + ssif_bmc->is_singlepart_read = (ssif_msg_len(&msg) <= MAX_PAYLOAD_PER_TRANSACTION + 1); + ssif_bmc->response_in_progress = true; + + if (ssif_bmc->client->adapter->algo->slave_enable) + ret = ssif_bmc->client->adapter->algo->slave_enable(ssif_bmc->client, true); + + spin_unlock_irqrestore(&ssif_bmc->lock, flags); + + return (ret < 0) ? ret : count; +} + +static int ssif_bmc_open(struct inode *inode, struct file *file) +{ + struct ssif_bmc_ctx *ssif_bmc = to_ssif_bmc(file); + int ret = 0; + + spin_lock_irq(&ssif_bmc->lock); + if (!ssif_bmc->running) + ssif_bmc->running = 1; + else + ret = -EBUSY; + spin_unlock_irq(&ssif_bmc->lock); + + return ret; +} + +static unsigned int ssif_bmc_poll(struct file *file, poll_table *wait) +{ + struct ssif_bmc_ctx *ssif_bmc = to_ssif_bmc(file); + unsigned int mask = 0; + + poll_wait(file, &ssif_bmc->wait_queue, wait); + + spin_lock_irq(&ssif_bmc->lock); + /* The request is available, userspace application can get the request */ + if (ssif_bmc->request_available) + mask |= POLLIN; + + spin_unlock_irq(&ssif_bmc->lock); + + return mask; +} + +static int ssif_bmc_release(struct inode *inode, struct file *file) +{ + struct ssif_bmc_ctx *ssif_bmc = to_ssif_bmc(file); + + spin_lock_irq(&ssif_bmc->lock); + ssif_bmc->running = 0; + spin_unlock_irq(&ssif_bmc->lock); + + return 0; +} + +/* + * System calls to device interface for user apps + */ +static const struct file_operations ssif_bmc_fops = { + .owner = THIS_MODULE, + .open = ssif_bmc_open, + .read = ssif_bmc_read, + .write = ssif_bmc_write, + .release = ssif_bmc_release, + .poll = ssif_bmc_poll, +}; + +/* Called with ssif_bmc->lock held. */ +static void complete_response(struct ssif_bmc_ctx *ssif_bmc) +{ + /* Invalidate response in buffer to denote it having been sent. */ + ssif_bmc->response.len = 0; + ssif_bmc->response_in_progress = false; + ssif_bmc->nbytes_processed = 0; + ssif_bmc->remain_len = 0; + wake_up_all(&ssif_bmc->wait_queue); +} + +/* Called with ssif_bmc->lock held. */ +static void handle_request(struct ssif_bmc_ctx *ssif_bmc) +{ + if (ssif_bmc->client->adapter->algo->slave_enable) + ssif_bmc->client->adapter->algo->slave_enable(ssif_bmc->client, false); + + /* Request message is available to process */ + ssif_bmc->request_available = true; + /* + * This is the new READ request. + */ + wake_up_all(&ssif_bmc->wait_queue); +} + +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; + + 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, aborting ...\n", + __func__, ssif_bmc->smbus_cmd); + ssif_bmc->aborting = true; + 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 { + *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 */ + 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, aborting ...\n", + __func__, ssif_bmc->smbus_cmd); + ssif_bmc->aborting = true; + 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; + + 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, aborting ..."); + ssif_bmc->aborting = true; + } + + 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, aborting ..."); + ssif_bmc->aborting = true; + } + + 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, aborting ..."); + ssif_bmc->aborting = true; + } + + } else { + buf[ssif_bmc->msg_idx - 1 + + ssif_bmc->request.len - ssif_bmc->recv_len] = *val; + } + + 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, aborting ...\n", + __func__, ssif_bmc->smbus_cmd); + ssif_bmc->aborting = true; + break; + } +} + +static bool validate_request(struct ssif_bmc_ctx *ssif_bmc) +{ + u8 rpec = 0, cpec = 0; + bool ret = true; + u8 addr, index; + u8 *buf; + + 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); + /* 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, aborting ...\n", + __func__, ssif_bmc->smbus_cmd); + ret = false; + break; + } + +exit: + return ret; +} + +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, aborting ..."); + ssif_bmc->aborting = true; + } else if (ssif_bmc->aborting && + (*val == SSIF_IPMI_SINGLEPART_WRITE || + *val == SSIF_IPMI_MULTIPART_WRITE_START)) { + /* New request */ + dev_warn(&ssif_bmc->client->dev, "Warn: New request found, stop aborting ..."); + ssif_bmc->aborting = false; + } +} + +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, aborting ...\n", + __func__, state_to_string(ssif_bmc->state)); + ssif_bmc->aborting = true; + + } else if (ssif_bmc->state == SSIF_SMBUS_CMD) { + ssif_bmc->state = SSIF_RES_SENDING; + } + + if (ssif_bmc->aborting || ssif_bmc->state != SSIF_RES_SENDING) { + /* Abort by returning the last request with 0xFF as completion code */ + ssif_bmc->is_singlepart_read = true; + ssif_bmc->response.len = 0x03; + ssif_bmc->response.netfn_lun = ssif_bmc->request.netfn_lun | 4; + ssif_bmc->response.cmd = ssif_bmc->request.cmd; + memset(&ssif_bmc->response.payload[0], 0xFF, MAX_PAYLOAD_PER_TRANSACTION); + } + + 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) { + if (ssif_bmc->response_in_progress) { + /* + * As per spec, it is generic management software or SSIF drivers to take + * care of issuing new request before the prior requests completed. + * So just abort everything here and wait for next new request + */ + dev_warn(&ssif_bmc->client->dev, + "Warn: SSIF new request with pending response, aborting ..."); + ssif_bmc->aborting = true; + complete_response(ssif_bmc); + } + + 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)) + ssif_bmc->aborting = true; + + if (!ssif_bmc->aborting && + (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); + + 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, aborting ...\n"); + ssif_bmc->aborting = true; + break; + } + + spin_unlock_irqrestore(&ssif_bmc->lock, flags); + + return 0; +} + +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; + + /* 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 v2"); diff --git a/drivers/char/ipmi/ssif_bmc.h b/drivers/char/ipmi/ssif_bmc.h new file mode 100644 index 000000000000..b63e40a4b900 --- /dev/null +++ b/drivers/char/ipmi/ssif_bmc.h @@ -0,0 +1,106 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * The driver for BMC side of SSIF interface + * + * Copyright (c) 2021, Ampere Computing LLC + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#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 + +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; + /* Flag to abort current process */ + bool aborting; + /* 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; + /* 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.28.0 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 X-Spam-Level: X-Spam-Status: No, score=-17.4 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,MSGID_FROM_MTA_HEADER,SPF_HELO_NONE, SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 92E12C07E9A for ; Wed, 14 Jul 2021 03:41:43 +0000 (UTC) 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 mail.kernel.org (Postfix) with ESMTPS id 4D9036127C for ; Wed, 14 Jul 2021 03:41:43 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 4D9036127C Authentication-Results: mail.kernel.org; dmarc=fail (p=quarantine dis=none) header.from=os.amperecomputing.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org 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:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=UdZFW8bQoEYERdK7/RdO9a/Q4C2szuIVeYTBnWAb/zU=; b=48p2IY/aKPP4YQ QLBH9e2IqlI3PTBw+CKdEs55WtRG0o4lMCJpgUcWFWm4VEOF1kmoFm4+bjRPFmQStgXkCvnsYkIfL M55b20EhvR6rdl5Zo9+PCSTHSxR8KLko1hN0TlDAH+s6quHt55pCOLmTAEyaXxzhuPzUtgRgIzvK2 xeycDLJyQYs9zLCPCU9qkKP5ZqhBDVvTUE50vVJ3fJ2x9ieGmzFO3DwdCYktwuBZiN+Oo2f1DGQ8S qEoPJ1aEXMMv1Ks2CqJrophYXvIZcdw1tsfSPETykCHRSoDhg5pEEd1noTN7weW3p91A7AhS+thVW e4Bq2JRy8eDDQdS7bUNw==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1m3Vk5-00CDuP-Nu; Wed, 14 Jul 2021 03:39:26 +0000 Received: from mail-mw2nam12on2108.outbound.protection.outlook.com ([40.107.244.108] helo=NAM12-MW2-obe.outbound.protection.outlook.com) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1m3Vjj-00CDrh-Pd for linux-arm-kernel@lists.infradead.org; Wed, 14 Jul 2021 03:39:07 +0000 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=Fm6iozN+8dJttORZOtFCd9ZSBwrVFUBPR3WKvvzGcaF0CVwkvdDd9tHCZu5jsgosJarnf+V189ffAzM2NX0ZJH1WTkvC0cv5xS4N6N8W4DA/94mZdmWfUOkh8s7BuMpJZDvddaJ6k8m83k0C95HOfF1xnNiogGNfIZxEO4yR4z0Ibu5qBuVxE6D172F7koGc912uo0vnyGJU964GkfWJ5W4SCzsrTFZG4VO7Zri7sBh2qlFdSeL757Ca0Qa4hWbd9lInvmN3rH5TsxmPtytPy8rMKF2FvrZhHGghKXgB9yhi+xuJdipCETe4jvKLTt+ztN0NaOD7as4F7IMSp/kXmQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=43sUey2steEyS7GkmjkqCXWUMwi0B7maERi2FrYOQHg=; b=T5QLE38SvX1lkrNbuZlOcJ1Uke6akWStFVAJxe6ugWeYguCRw3qrpjMosy/aCCMnLSfKcP3Gl/PnDgMvgzraxf5wUFleTxI/5H3PdfZVK/AQoNnw2n2v1kujUYuxW0+ehDcSCMuKC8qwowN4uNn06Bz3F9at1bjKxinfTCKGxsjhe1LHpteyvWk36AMw7jaNdlf02RejsKGIqbinr3D8v6Hv1dj+OJ7s19qNinEtrQPpr6Q/AiLLBeLd/9oTDqIFbTUWwDv/aLRxMiFYttSsHPraGjXVLSFpDoffpv3vkmPAbrD483dq1uVLkZr3GoSQpR+ts99c3ZNfqc/uUYIuTA== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=os.amperecomputing.com; dmarc=pass action=none header.from=os.amperecomputing.com; dkim=pass header.d=os.amperecomputing.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=os.amperecomputing.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=43sUey2steEyS7GkmjkqCXWUMwi0B7maERi2FrYOQHg=; b=QU8rbeWmcYP6ZB9YOJhlXysOwadwf0gWSANEIiAM9OtsIfUhjIUZoF9iBwB7THNb1wUlObNWZ1pf8eW4jCfhbDy/rxfPgBKHyRF8DIPIcYpI0VS6Xk80z0nSlHmEMcvjzZKDxZB+a4gdmkwrPCJRQdmoRaJ/odfnIgvGQhZZRRY= Authentication-Results: acm.org; dkim=none (message not signed) header.d=none;acm.org; dmarc=none action=none header.from=os.amperecomputing.com; Received: from MW2PR0102MB3482.prod.exchangelabs.com (2603:10b6:302:c::32) by MW2PR0102MB3370.prod.exchangelabs.com (2603:10b6:302:2::23) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4308.22; Wed, 14 Jul 2021 03:39:01 +0000 Received: from MW2PR0102MB3482.prod.exchangelabs.com ([fe80::452a:24fb:12cb:9d7e]) by MW2PR0102MB3482.prod.exchangelabs.com ([fe80::452a:24fb:12cb:9d7e%5]) with mapi id 15.20.4308.027; Wed, 14 Jul 2021 03:39:01 +0000 From: Quan Nguyen To: Corey Minyard , Rob Herring , 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 Cc: Open Source Submission , Phong Vo , "Thang Q . Nguyen" Subject: [PATCH v5 2/3] ipmi: ssif_bmc: Add SSIF BMC driver Date: Wed, 14 Jul 2021 10:38:32 +0700 Message-Id: <20210714033833.11640-3-quan@os.amperecomputing.com> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20210714033833.11640-1-quan@os.amperecomputing.com> References: <20210714033833.11640-1-quan@os.amperecomputing.com> X-ClientProxiedBy: HK0PR03CA0099.apcprd03.prod.outlook.com (2603:1096:203:b0::15) To MW2PR0102MB3482.prod.exchangelabs.com (2603:10b6:302:c::32) MIME-Version: 1.0 X-MS-Exchange-MessageSentRepresentingType: 1 Received: from hcm-sw-17.amperecomputing.com (118.69.219.201) by HK0PR03CA0099.apcprd03.prod.outlook.com (2603:1096:203:b0::15) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4331.21 via Frontend Transport; Wed, 14 Jul 2021 03:38:57 +0000 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: 076d9254-0e13-4fe6-5dd9-08d94678eb56 X-MS-TrafficTypeDiagnostic: MW2PR0102MB3370: X-MS-Exchange-Transport-Forked: True X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:3044; X-MS-Exchange-SenderADCheck: 1 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: iPyEj+dDftSGg5YPE7wpseaOamvUiKAXVM4caEckd2Z+b3enjxsjp/obo7ti3YeV7mZDkmAML0vu1JZ7eTOsj6BjOAugpolfu5EnClMybn3rfVfNjOsjX62NXF5W/zbUxJ3qcY9bfXPLQ2TyGbBXe3rtYFpP2RnM/ujpPPMItVWj87xRcn55uHM0Juo8eRGoIJdhtRXZYoL2Z2r/AevfM1qFtBZWvENmrDBv6pmZ9iF64nSWgt5APPLDTWu5akHgKn6SfJBYiK9GKc4nYdu+bIMR46RDk5rzmO83LHOQK4Jj2EOYoAprjU/GrR+/JHLiYauaXJE6z9bFe4fBwp7STKGwF6j0BEtL0IJJlVTrpmWFTWOE3d24mW4ULSVBN1EsKe0zgUXhwIbnBJ0eP89mHMVnwYKRExIfAezU4BEa1LbpeU6PI3+hKZKL+qoazw/R5wffJwzoTb6qSne9NRrt4HsGiyYsGuFlbB8Ub5p+hSnM4xxMApP2Gegzduqkan6q8ehoqzV0MmtR6H6dNdkfJKFhL6wV0x+SG5S+A6FI+XpV/rcKcflkvDxxnm4hV5XV7vrQ1DNBw0o3R70MC2DA6cyw18Im5w0TSiqdVwMw4JhRKHrDXRvNwQ4aOkEwsK59TbHBZQnMMOPA+p69NnurFT+hg0wkg+ZDRFXpuYIbJlopKPWcGnTsToMCDPqLZyj/SujkepzHSrrYH6g8A8N1FrnxP//rZ14LGl6WliTSexgXi1paNEn3pVyLbwLu6UUGV/1KrkWtuL/+eEDeHbXtIywG9oB/HZmMQAxBrKC0PG+oT6C3oVl1PX+b8TsUMbDeKxZO9EFs7ydlUxPVAl+wvQ== X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:MW2PR0102MB3482.prod.exchangelabs.com; PTR:; CAT:NONE; SFS:(4636009)(376002)(136003)(346002)(366004)(39850400004)(396003)(4326008)(38100700002)(1076003)(38350700002)(2616005)(107886003)(956004)(8936002)(8676002)(6506007)(30864003)(86362001)(110136005)(52116002)(5660300002)(54906003)(2906002)(6666004)(478600001)(26005)(186003)(66946007)(83380400001)(7416002)(66556008)(66476007)(6512007)(921005)(6486002)(316002)(2004002); DIR:OUT; SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?d3ovTkNMNGRDRFZvUjY5VVMxeVF1UWJGUXV2bDhpY0NZNytPeVZXcnZFT1Zu?= =?utf-8?B?VUx4MzJZcnViWUYzS3RwZy9qYjVoT1ZrUXA4Y1VFTHpRMDVsa0MzNHlBVjVz?= =?utf-8?B?b203dVlnNjhYWTR3YXU5SmVXR1NGaVY1U05XZDdOSno5SnNGbE81ZlFydk5L?= =?utf-8?B?a3Ivb1UwdFNQUm5FaUFDendGMWxVaitGUXdMcmxZZ3krNndLSUtMQnV3eUdm?= =?utf-8?B?QjB0M0ZQZml6SDRsZTI5Q21XWkw0T0dLS1NYbUFYWHJFV25HLzdVZE5DUkp0?= =?utf-8?B?MStET3BkYVl5RjNlRmRTSlZ1MS9Vcnk4NlJ1T04yTlRZYjhKSkthODcxb1RJ?= =?utf-8?B?SW1jVGpuM2FlRmI5T0E3dCtMbG5KWFRhY1hubENoMXU0U081RkY5SXZwb2k1?= =?utf-8?B?RGZuR0MrVkZwb012RHcycG82UWZFYlM0TWlTQlJDMSszV1I0c1JUYkFWTUlk?= =?utf-8?B?T3NyU0dGOGZmU3hyM3VuRkdXOTFXR0NwSWhWNHhwODhPOUEvK0dUbnNuTlR3?= =?utf-8?B?STk2YktkRThXT0c1ZlZUcUJjQUlVeFduMUQwa1VkWG9uWHBoUzZaWG1xVGNy?= =?utf-8?B?Q1RZbE5SUmZqSFNYYTdZMXdLT1psY0VnRk1CemdjTzVBQnFlcXNIUlNVTU1n?= =?utf-8?B?ZWwxTUtBNXZyUGJuU0U5YWcxNXJ6TkpHQzJmdmN6ek1FNVFtZjRjSzM3NTZj?= =?utf-8?B?ank1UjdMdjk2TTRha1NPS2pmRmtJSnQwRGt2ZDR5cWxBVXFDM2NsR244QThM?= =?utf-8?B?VHpFYXJoUkVyOGpWcTlaVU53OFZ2S29Jd2s1T3MvMHhBUHJWV250cGlWenB4?= =?utf-8?B?TzBXVDAyVmI4cEVUYWJwSXJyalVuNHFndmh6ZUlWelIvSnl1VUh6T2JodGJ3?= =?utf-8?B?NnBFWUxsKzJOSnZtdlE1dkcyNHpXKzNJaTlKVHAvRll0amEvZllTRUo5Sm15?= =?utf-8?B?VmQrZjFxR2l5R2kvSStnSTJwNHFvYXQwcGRSTWpHM2dac1ZJNnErTEMzMFlX?= =?utf-8?B?RVlpRXcvbk9GMm0ySHJ4aFlkTFUyTFc1N2hKMmFOYUlDTlV5YjJlY0lGSFQv?= =?utf-8?B?VXZGSmhKM3lPcHgxaDJ0RXI3MWVFNlpCemdJZCtWd2lqLyt5VzgrWlZ4TVZ5?= =?utf-8?B?UFpqZ2NQRnVyS2NCZDRheWNMNlZwdzFuYnJYN3d5NDNqM21melVPVFJqNG0z?= =?utf-8?B?Z0RRenBSWENsNXZNa29TWEJMTkMxVENOL2NGeFdiNWRjZ2ZCMG5pSWJkOVpI?= =?utf-8?B?M1hLRFMydmE3OVppVWxLbmJOTWhrTzhuL3pGbCtUdHlydzlPQ2k1VlZ0VGda?= =?utf-8?B?MWpmeDJSdzlKOTZsNnlqMzFLcVR4YmhKSnFlb3RCWUNjZktHcHg4R0tZek05?= =?utf-8?B?VlJ5cStBYy9CelZGTDl3dzVPUmt0NHVrR0ZXUFpEWkVvOTg5dWVJUUVNQzQv?= =?utf-8?B?WGgyWDdSRlBQYUxmZ3RrVkM5SGRPUlA3ZW52b0Jaa2xwZ3lYM1JDWlRpSkZL?= =?utf-8?B?eGs4ZXRPYzE3VkVEaWtiM3F2eUJyUk5TL3FMd2IraWN4amNQUlZWazlwa2FF?= =?utf-8?B?TmMvUmxBbmFnUXIvZUp5TEhsa0RML2l4REo0aFYzYk82TzB1NnZ2NzVMdE5p?= =?utf-8?B?ZlBJMzNTcEFibTVVRDRmTmgrTWZpRHUrZTV1a2VlYnNKWmNPSUtQSi9kM0JG?= =?utf-8?B?WTVpaWtSdVJSU2V5dE1maFJYZi9rK1hrNWQxQ3NUTXdGOGNnNUpLS2dxV3BM?= =?utf-8?Q?D9Ff1C5Y3hR4+BWq6V6gKVjHpXDppZ4mjZdeWcg?= X-OriginatorOrg: os.amperecomputing.com X-MS-Exchange-CrossTenant-Network-Message-Id: 076d9254-0e13-4fe6-5dd9-08d94678eb56 X-MS-Exchange-CrossTenant-AuthSource: MW2PR0102MB3482.prod.exchangelabs.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 14 Jul 2021 03:39:01.2898 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 3bc2b170-fd94-476d-b0ce-4229bdc904a7 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: Li/s/gGCJxTYjiC7HzTl8EmUZpzDLn/la2VBPcMQYZlgNNmRhfi533B4BqFZ/xs0RRt1FgelW/56vQaHimCaVMvak6Vs4K8ZiWnx9EllQBU= X-MS-Exchange-Transport-CrossTenantHeadersStamped: MW2PR0102MB3370 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20210713_203903_933885_35A11438 X-CRM114-Status: GOOD ( 18.78 ) 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: , 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 VGhlIFNNQnVzIHN5c3RlbSBpbnRlcmZhY2UgKFNTSUYpIElQTUkgQk1DIGRyaXZlciBjYW4gYmUg dXNlZCB0byBwZXJmb3JtCmluLWJhbmQgSVBNSSBjb21tdW5pY2F0aW9uIHdpdGggdGhlaXIgaG9z dCBpbiBtYW5hZ2VtZW50IChCTUMpIHNpZGUuCgpTaWduZWQtb2ZmLWJ5OiBRdWFuIE5ndXllbiA8 cXVhbkBvcy5hbXBlcmVjb21wdXRpbmcuY29tPgotLS0KdjU6CiAgKyBOb25lCgp2NDoKICArIFNl bmQgcmVzcG9uc2Ugd2l0aCBDb21wbGV0aW9uIGNvZGUgMHhGRiB3aGVuIGFib3J0aW5nICAgICAg ICAgW1F1YW5dCiAgKyBBZGRlZCBib3VuZGluZyBjaGVjayBvbiBTTUJ1cyB3cml0ZXMgYW5kIHRo ZSB3aG9sZSByZXF1ZXN0ICAgICBbRGFuXQogICsgTW92ZWQgYnVmZmVyIHRvIGVuZCBvZiBzdHJ1 Y3Qgc3NpZl9ibWNfY3R4IHRvIGF2b2lkIGNvbnRleHQKICAgIGNvcnJ1cHRpb24gaWYgc29tZWhv dyBidWZmZXIgaXMgd3JpdHRlbiBwYXN0IHRoZSBlbmQgICAgICAgICAgIFtEYW5dCiAgKyBSZXR1 cm4gLUVJTlZBTCBpZiB1c2Vyc3BhY2UgYnVmZmVyIHRvbyBzbWFsbCwgZG9udAogICAgc2lsZW5j ZSB0cnVuY2F0ZSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFtDb3JleSwg Sm9lbF0KICArIE5vdCBuZWNlc3NhcnkgdG8gY2hlY2sgTk9OQkxPQ0sgaW4gbG9jayAgICAgICAg ICAgICAgICAgICAgICBbQ29yZXldCiAgKyBFbmZvcmNlIG9uZSB1c2VyIGF0IGEgdGltZSAgICAg ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFtKb2VsXQogICsgUmVqZWN0IHdyaXRlIHdp dGggaW52YWxpZCByZXNwb25zZSBsZW5ndGggZnJvbSB1c2Vyc3BhY2UgICAgIFtDb3JleV0KICAr IEFkZCBzdGF0ZSBtYWNoaW5lcyBmb3IgYmV0dGVyIHNzaWYgYm1jIHN0YXRlIGhhbmRsaW5nICAg ICAgICAgW1F1YW5dCiAgKyBEcm9wIHNzaWZfYm1jX2FzcGVlZC5jIGFuZCBtYWtlIHNzaWZfYm1j LmMgaXMgZ2VuZXJpYwogICAgU1NJRiBCTUMgZHJpdmVyICAgICAgICAgICAgICAgICAgICAgICAg ICAgICAgICAgICAgICAgICAgICAgICBbUXVhbl0KICArIENoYW5nZSBjb21wYXRpYmxlIHN0cmlu ZyAiYXNwZWVkLGFzdDI1MDAtc3NpZi1ibWMiIHRvCiAgICAiYW1wZXJlLHNzaWYtYm1jIiAgICAg ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFtRdWFuXQogICsgQWJvcnQg Y3VycmVudCByZXF1ZXN0IHdpdGggaW52YWxpZCBTTUJ1cyB3cml0ZSBvcgogICAgaW52YWxpZCBj b21tYW5kICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBbUXVh bl0KICArIEFib3J0IGFsbCByZXF1ZXN0IGlmIHRoZXJlIGlzIHBlbmRpbmcgcmVzcG9uc2UgICAg ICAgICAgICAgICAgW1F1YW5dCiAgKyBDaGFuZ2VkIHZhbGlkYXRlX3BlYygpIHRvIHZhbGlkYXRl X3JlcXVlc3QoKSAgICAgICAgICAgICAgICAgIFtRdWFuXQogICsgQWRkIHVuc3VwcG9ydGVkX3Nt YnVzX2NtZCgpIHRvIGhhbmRsZSB1bmtub3duIFNNQnVzIGNvbW1hbmQgICBbUXVhbl0KICArIFBy aW50IGludGVybmFsIHN0YXRlIHN0cmluZyBmb3IgZWFzZSBpbnZlc3RpZ2F0aW5nIGlzc3VlICAg ICAgW1F1YW5dCiAgKyBNb3ZlIHRvIFJFQURZIHN0YXRlIG9uIFNMQVZFX1NUT1AgZXZlbnQgICAg ICAgICAgICAgICAgICAgICAgIFtRdWFuXQogICsgQ2hhbmdlIGluaXRpbGl6ZV90cmFuc2Zlcigp IHRvIHByb2Nlc3Nfc21idXNfY21kKCkgICAgICAgICAgICBbUXVhbl0KICArIEludHJvZHVjZSBm dW5jdGlvbnMgZm9yIGVhY2ggc2xhdmUgZXZlbnQgICAgICAgICAgICAgICAgICAgICAgW1F1YW5d Cgp2MzoKICArIFJlbW92ZWQgcmVkdW5kYW50IGxpY2Vuc2UgaW5mbyBbSm9lbF0KICArIFN3aXRj aGVkIHRvIHVzZSB0cmFkaXRpb25hbCBpZi1lbHNlIFtKb2VsXQogICsgUmVtb3ZlZCB1bnVzZWQg c3NpZl9ibWNfaW9jdGwoKSBbSm9lbF0KICArIE1hZGUgaGFuZGxlX3JlcXVlc3QoKS9jb21wbGV0 ZV9yZXNwb25zZSgpIHRvIHJldHVybiB2b2lkIFtKb2VsXQogICsgUmVmYWN0b3JlZCBzZW5kX3Nz aWZfYm1jX3Jlc3BvbnNlKCkvcmVjZWl2ZV9zc2lmX2JtY19yZXF1ZXN0KCkKW0NvcmV5XQogICsg UmVtb3ZlZCBtdXRleCBbQ29yZXldCiAgKyBVc2Ugc3Bpbl9sb2NrL3VubG9ja19pcnFzYXZlL3Jl c3RvcmUgaW4gY2FsbGJhY2sgW0NvcmV5XQogICsgUmVtb3ZlZCB0aGUgdW5uZWNlc3NhcnkgbWVt c2V0IFtDb3JleV0KICArIFN3aXRjaCB0byB1c2UgZGV2X2VycigpIFtDb3JleV0KCnYyOgogICsg Rml4ZWQgY29tcGlsaW5nIGVycm9yIHdpdGggQ09NUElMRV9URVNUIGZvciBhcmMKCiBkcml2ZXJz L2NoYXIvaXBtaS9LY29uZmlnICAgIHwgIDExICsKIGRyaXZlcnMvY2hhci9pcG1pL01ha2VmaWxl ICAgfCAgIDEgKwogZHJpdmVycy9jaGFyL2lwbWkvc3NpZl9ibWMuYyB8IDc4MSArKysrKysrKysr KysrKysrKysrKysrKysrKysrKysrKysrKwogZHJpdmVycy9jaGFyL2lwbWkvc3NpZl9ibWMuaCB8 IDEwNiArKysrKwogNCBmaWxlcyBjaGFuZ2VkLCA4OTkgaW5zZXJ0aW9ucygrKQogY3JlYXRlIG1v ZGUgMTAwNjQ0IGRyaXZlcnMvY2hhci9pcG1pL3NzaWZfYm1jLmMKIGNyZWF0ZSBtb2RlIDEwMDY0 NCBkcml2ZXJzL2NoYXIvaXBtaS9zc2lmX2JtYy5oCgpkaWZmIC0tZ2l0IGEvZHJpdmVycy9jaGFy L2lwbWkvS2NvbmZpZyBiL2RyaXZlcnMvY2hhci9pcG1pL0tjb25maWcKaW5kZXggMjQ5YjMxMTk3 ZWVhLi5lMDlhNDcwYWIyZGEgMTAwNjQ0Ci0tLSBhL2RyaXZlcnMvY2hhci9pcG1pL0tjb25maWcK KysrIGIvZHJpdmVycy9jaGFyL2lwbWkvS2NvbmZpZwpAQCAtMTYwLDYgKzE2MCwxNyBAQCBjb25m aWcgQVNQRUVEX0JUX0lQTUlfQk1DCiAJICBmb3VuZCBvbiBBc3BlZWQgU09DcyAoQVNUMjQwMCBh bmQgQVNUMjUwMCkuIFRoZSBkcml2ZXIKIAkgIGltcGxlbWVudHMgdGhlIEJNQyBzaWRlIG9mIHRo ZSBCVCBpbnRlcmZhY2UuCiAKK2NvbmZpZyBTU0lGX0lQTUlfQk1DCisJdHJpc3RhdGUgIlNTSUYg SVBNSSBCTUMgZHJpdmVyIgorCXNlbGVjdCBJMkMKKwlzZWxlY3QgSTJDX1NMQVZFCisJaGVscAor CSAgVGhpcyBlbmFibGVzIHRoZSBJUE1JIFNNQnVzIHN5c3RlbSBpbnRlcmZhY2UgKFNTSUYpIGF0 IHRoZQorCSAgbWFuYWdlbWVudCAoQk1DKSBzaWRlLgorCisJICBUaGUgZHJpdmVyIGltcGxlbWVu dHMgdGhlIEJNQyBzaWRlIG9mIHRoZSBTTUJ1cyBzeXN0ZW0KKwkgIGludGVyZmFjZSAoU1NJRiku CisKIGNvbmZpZyBJUE1CX0RFVklDRV9JTlRFUkZBQ0UKIAl0cmlzdGF0ZSAnSVBNQiBJbnRlcmZh Y2UgaGFuZGxlcicKIAlkZXBlbmRzIG9uIEkyQwpkaWZmIC0tZ2l0IGEvZHJpdmVycy9jaGFyL2lw bWkvTWFrZWZpbGUgYi9kcml2ZXJzL2NoYXIvaXBtaS9NYWtlZmlsZQppbmRleCA4NGY0N2QxODAw N2YuLmE5M2MwOWRhZDIyYSAxMDA2NDQKLS0tIGEvZHJpdmVycy9jaGFyL2lwbWkvTWFrZWZpbGUK KysrIGIvZHJpdmVycy9jaGFyL2lwbWkvTWFrZWZpbGUKQEAgLTI5LDMgKzI5LDQgQEAgb2JqLSQo Q09ORklHX0FTUEVFRF9CVF9JUE1JX0JNQykgKz0gYnQtYm1jLm8KIG9iai0kKENPTkZJR19BU1BF RURfS0NTX0lQTUlfQk1DKSArPSBrY3NfYm1jX2FzcGVlZC5vCiBvYmotJChDT05GSUdfTlBDTTdY WF9LQ1NfSVBNSV9CTUMpICs9IGtjc19ibWNfbnBjbTd4eC5vCiBvYmotJChDT05GSUdfSVBNQl9E RVZJQ0VfSU5URVJGQUNFKSArPSBpcG1iX2Rldl9pbnQubworb2JqLSQoQ09ORklHX1NTSUZfSVBN SV9CTUMpICs9IHNzaWZfYm1jLm8KZGlmZiAtLWdpdCBhL2RyaXZlcnMvY2hhci9pcG1pL3NzaWZf Ym1jLmMgYi9kcml2ZXJzL2NoYXIvaXBtaS9zc2lmX2JtYy5jCm5ldyBmaWxlIG1vZGUgMTAwNjQ0 CmluZGV4IDAwMDAwMDAwMDAwMC4uYjE1YzA1NjIyZTcyCi0tLSAvZGV2L251bGwKKysrIGIvZHJp dmVycy9jaGFyL2lwbWkvc3NpZl9ibWMuYwpAQCAtMCwwICsxLDc4MSBAQAorLy8gU1BEWC1MaWNl bnNlLUlkZW50aWZpZXI6IEdQTC0yLjArCisvKgorICogVGhlIGRyaXZlciBmb3IgQk1DIHNpZGUg b2YgU1NJRiBpbnRlcmZhY2UKKyAqCisgKiBDb3B5cmlnaHQgKGMpIDIwMjEsIEFtcGVyZSBDb21w dXRpbmcgTExDCisgKgorICovCisKKyNpbmNsdWRlIDxsaW51eC9pMmMuaD4KKyNpbmNsdWRlIDxs aW51eC9taXNjZGV2aWNlLmg+CisjaW5jbHVkZSA8bGludXgvbW9kdWxlLmg+CisjaW5jbHVkZSA8 bGludXgvb2YuaD4KKyNpbmNsdWRlIDxsaW51eC9wbGF0Zm9ybV9kZXZpY2UuaD4KKyNpbmNsdWRl IDxsaW51eC9wb2xsLmg+CisjaW5jbHVkZSA8bGludXgvc2NoZWQuaD4KKyNpbmNsdWRlIDxsaW51 eC9tdXRleC5oPgorI2luY2x1ZGUgPGxpbnV4L3NwaW5sb2NrLmg+CisKKyNpbmNsdWRlICJzc2lm X2JtYy5oIgorCitzdGF0aWMgY29uc3QgY2hhciAqc3RhdGVfdG9fc3RyaW5nKGVudW0gc3NpZl9z dGF0ZSBzdGF0ZSkKK3sKKwlzd2l0Y2ggKHN0YXRlKSB7CisJY2FzZSBTU0lGX1JFQURZOgorCQly ZXR1cm4gIlNTSUZfUkVBRFkiOworCWNhc2UgU1NJRl9TVEFSVDoKKwkJcmV0dXJuICJTU0lGX1NU QVJUIjsKKwljYXNlIFNTSUZfU01CVVNfQ01EOgorCQlyZXR1cm4gIlNTSUZfU01CVVNfQ01EIjsK KwljYXNlIFNTSUZfUkVRX1JFQ1ZJTkc6CisJCXJldHVybiAiU1NJRl9SRVFfUkVDVklORyI7CisJ Y2FzZSBTU0lGX1JFU19TRU5ESU5HOgorCQlyZXR1cm4gIlNTSUZfUkVTX1NFTkRJTkciOworCWNh c2UgU1NJRl9CQURfU01CVVM6CisJCXJldHVybiAiU1NJRl9CQURfU01CVVMiOworCWRlZmF1bHQ6 CisJCXJldHVybiAiU1NJRl9TVEFURV9VTktOT1dOIjsKKwl9Cit9CisKKy8qIEhhbmRsZSBTU0lG IG1lc3NhZ2UgdGhhdCB3aWxsIGJlIHNlbnQgdG8gdXNlciAqLworc3RhdGljIHNzaXplX3Qgc3Np Zl9ibWNfcmVhZChzdHJ1Y3QgZmlsZSAqZmlsZSwgY2hhciBfX3VzZXIgKmJ1Ziwgc2l6ZV90IGNv dW50LCBsb2ZmX3QgKnBwb3MpCit7CisJc3RydWN0IHNzaWZfYm1jX2N0eCAqc3NpZl9ibWMgPSB0 b19zc2lmX2JtYyhmaWxlKTsKKwlzdHJ1Y3Qgc3NpZl9tc2cgbXNnOworCXVuc2lnbmVkIGxvbmcg ZmxhZ3M7CisJc3NpemVfdCByZXQ7CisKKwlzcGluX2xvY2tfaXJxc2F2ZSgmc3NpZl9ibWMtPmxv Y2ssIGZsYWdzKTsKKwl3aGlsZSAoIXNzaWZfYm1jLT5yZXF1ZXN0X2F2YWlsYWJsZSkgeworCQlz cGluX3VubG9ja19pcnFyZXN0b3JlKCZzc2lmX2JtYy0+bG9jaywgZmxhZ3MpOworCQlpZiAoZmls ZS0+Zl9mbGFncyAmIE9fTk9OQkxPQ0spCisJCQlyZXR1cm4gLUVBR0FJTjsKKwkJcmV0ID0gd2Fp dF9ldmVudF9pbnRlcnJ1cHRpYmxlKHNzaWZfYm1jLT53YWl0X3F1ZXVlLAorCQkJCQkgICAgICAg c3NpZl9ibWMtPnJlcXVlc3RfYXZhaWxhYmxlKTsKKwkJaWYgKHJldCkKKwkJCXJldHVybiByZXQ7 CisJCXNwaW5fbG9ja19pcnFzYXZlKCZzc2lmX2JtYy0+bG9jaywgZmxhZ3MpOworCX0KKworCWlm IChjb3VudCA8IG1pbl90KHNzaXplX3QsIHNzaWZfbXNnX2xlbigmc3NpZl9ibWMtPnJlcXVlc3Qp LCBzaXplb2Yoc3RydWN0IHNzaWZfbXNnKSkpIHsKKwkJc3Bpbl91bmxvY2tfaXJxcmVzdG9yZSgm c3NpZl9ibWMtPmxvY2ssIGZsYWdzKTsKKwkJcmV0ID0gLUVJTlZBTDsKKwl9IGVsc2UgeworCQlj b3VudCA9IG1pbl90KHNzaXplX3QsIHNzaWZfbXNnX2xlbigmc3NpZl9ibWMtPnJlcXVlc3QpLCBz aXplb2Yoc3RydWN0IHNzaWZfbXNnKSk7CisJCW1lbWNweSgmbXNnLCAmc3NpZl9ibWMtPnJlcXVl c3QsIGNvdW50KTsKKwkJc3NpZl9ibWMtPnJlcXVlc3RfYXZhaWxhYmxlID0gZmFsc2U7CisJCXNw aW5fdW5sb2NrX2lycXJlc3RvcmUoJnNzaWZfYm1jLT5sb2NrLCBmbGFncyk7CisKKwkJcmV0ID0g Y29weV90b191c2VyKGJ1ZiwgJm1zZywgY291bnQpOworCX0KKworCXJldHVybiAocmV0IDwgMCkg PyByZXQgOiBjb3VudDsKK30KKworLyogSGFuZGxlIFNTSUYgbWVzc2FnZSB0aGF0IGlzIHdyaXR0 ZW4gYnkgdXNlciAqLworc3RhdGljIHNzaXplX3Qgc3NpZl9ibWNfd3JpdGUoc3RydWN0IGZpbGUg KmZpbGUsIGNvbnN0IGNoYXIgX191c2VyICpidWYsIHNpemVfdCBjb3VudCwKKwkJCSAgICAgIGxv ZmZfdCAqcHBvcykKK3sKKwlzdHJ1Y3Qgc3NpZl9ibWNfY3R4ICpzc2lmX2JtYyA9IHRvX3NzaWZf Ym1jKGZpbGUpOworCXN0cnVjdCBzc2lmX21zZyBtc2c7CisJdW5zaWduZWQgbG9uZyBmbGFnczsK Kwlzc2l6ZV90IHJldDsKKworCWlmIChjb3VudCA+IHNpemVvZihzdHJ1Y3Qgc3NpZl9tc2cpKQor CQlyZXR1cm4gLUVJTlZBTDsKKworCXJldCA9IGNvcHlfZnJvbV91c2VyKCZtc2csIGJ1ZiwgY291 bnQpOworCWlmIChyZXQpCisJCXJldHVybiByZXQ7CisKKwlpZiAoIW1zZy5sZW4gfHwgY291bnQg PCBzc2lmX21zZ19sZW4oJm1zZykpCisJCXJldHVybiAtRUlOVkFMOworCisJc3Bpbl9sb2NrX2ly cXNhdmUoJnNzaWZfYm1jLT5sb2NrLCBmbGFncyk7CisJd2hpbGUgKHNzaWZfYm1jLT5yZXNwb25z ZV9pbl9wcm9ncmVzcykgeworCQlzcGluX3VubG9ja19pcnFyZXN0b3JlKCZzc2lmX2JtYy0+bG9j aywgZmxhZ3MpOworCQlpZiAoZmlsZS0+Zl9mbGFncyAmIE9fTk9OQkxPQ0spCisJCQlyZXR1cm4g LUVBR0FJTjsKKwkJcmV0ID0gd2FpdF9ldmVudF9pbnRlcnJ1cHRpYmxlKHNzaWZfYm1jLT53YWl0 X3F1ZXVlLAorCQkJCQkgICAgICAgIXNzaWZfYm1jLT5yZXNwb25zZV9pbl9wcm9ncmVzcyk7CisJ CWlmIChyZXQpCisJCQlyZXR1cm4gcmV0OworCQlzcGluX2xvY2tfaXJxc2F2ZSgmc3NpZl9ibWMt PmxvY2ssIGZsYWdzKTsKKwl9CisKKwltZW1jcHkoJnNzaWZfYm1jLT5yZXNwb25zZSwgJm1zZywg Y291bnQpOworCXNzaWZfYm1jLT5pc19zaW5nbGVwYXJ0X3JlYWQgPSAoc3NpZl9tc2dfbGVuKCZt c2cpIDw9IE1BWF9QQVlMT0FEX1BFUl9UUkFOU0FDVElPTiArIDEpOworCXNzaWZfYm1jLT5yZXNw b25zZV9pbl9wcm9ncmVzcyA9IHRydWU7CisKKwlpZiAoc3NpZl9ibWMtPmNsaWVudC0+YWRhcHRl ci0+YWxnby0+c2xhdmVfZW5hYmxlKQorCQlyZXQgPSBzc2lmX2JtYy0+Y2xpZW50LT5hZGFwdGVy LT5hbGdvLT5zbGF2ZV9lbmFibGUoc3NpZl9ibWMtPmNsaWVudCwgdHJ1ZSk7CisKKwlzcGluX3Vu bG9ja19pcnFyZXN0b3JlKCZzc2lmX2JtYy0+bG9jaywgZmxhZ3MpOworCisJcmV0dXJuIChyZXQg PCAwKSA/IHJldCA6IGNvdW50OworfQorCitzdGF0aWMgaW50IHNzaWZfYm1jX29wZW4oc3RydWN0 IGlub2RlICppbm9kZSwgc3RydWN0IGZpbGUgKmZpbGUpCit7CisJc3RydWN0IHNzaWZfYm1jX2N0 eCAqc3NpZl9ibWMgPSB0b19zc2lmX2JtYyhmaWxlKTsKKwlpbnQgcmV0ID0gMDsKKworCXNwaW5f bG9ja19pcnEoJnNzaWZfYm1jLT5sb2NrKTsKKwlpZiAoIXNzaWZfYm1jLT5ydW5uaW5nKQorCQlz c2lmX2JtYy0+cnVubmluZyA9IDE7CisJZWxzZQorCQlyZXQgPSAtRUJVU1k7CisJc3Bpbl91bmxv Y2tfaXJxKCZzc2lmX2JtYy0+bG9jayk7CisKKwlyZXR1cm4gcmV0OworfQorCitzdGF0aWMgdW5z aWduZWQgaW50IHNzaWZfYm1jX3BvbGwoc3RydWN0IGZpbGUgKmZpbGUsIHBvbGxfdGFibGUgKndh aXQpCit7CisJc3RydWN0IHNzaWZfYm1jX2N0eCAqc3NpZl9ibWMgPSB0b19zc2lmX2JtYyhmaWxl KTsKKwl1bnNpZ25lZCBpbnQgbWFzayA9IDA7CisKKwlwb2xsX3dhaXQoZmlsZSwgJnNzaWZfYm1j LT53YWl0X3F1ZXVlLCB3YWl0KTsKKworCXNwaW5fbG9ja19pcnEoJnNzaWZfYm1jLT5sb2NrKTsK KwkvKiBUaGUgcmVxdWVzdCBpcyBhdmFpbGFibGUsIHVzZXJzcGFjZSBhcHBsaWNhdGlvbiBjYW4g Z2V0IHRoZSByZXF1ZXN0ICovCisJaWYgKHNzaWZfYm1jLT5yZXF1ZXN0X2F2YWlsYWJsZSkKKwkJ bWFzayB8PSBQT0xMSU47CisKKwlzcGluX3VubG9ja19pcnEoJnNzaWZfYm1jLT5sb2NrKTsKKwor CXJldHVybiBtYXNrOworfQorCitzdGF0aWMgaW50IHNzaWZfYm1jX3JlbGVhc2Uoc3RydWN0IGlu b2RlICppbm9kZSwgc3RydWN0IGZpbGUgKmZpbGUpCit7CisJc3RydWN0IHNzaWZfYm1jX2N0eCAq c3NpZl9ibWMgPSB0b19zc2lmX2JtYyhmaWxlKTsKKworCXNwaW5fbG9ja19pcnEoJnNzaWZfYm1j LT5sb2NrKTsKKwlzc2lmX2JtYy0+cnVubmluZyA9IDA7CisJc3Bpbl91bmxvY2tfaXJxKCZzc2lm X2JtYy0+bG9jayk7CisKKwlyZXR1cm4gMDsKK30KKworLyoKKyAqIFN5c3RlbSBjYWxscyB0byBk ZXZpY2UgaW50ZXJmYWNlIGZvciB1c2VyIGFwcHMKKyAqLworc3RhdGljIGNvbnN0IHN0cnVjdCBm aWxlX29wZXJhdGlvbnMgc3NpZl9ibWNfZm9wcyA9IHsKKwkub3duZXIJCT0gVEhJU19NT0RVTEUs CisJLm9wZW4JCT0gc3NpZl9ibWNfb3BlbiwKKwkucmVhZAkJPSBzc2lmX2JtY19yZWFkLAorCS53 cml0ZQkJPSBzc2lmX2JtY193cml0ZSwKKwkucmVsZWFzZQk9IHNzaWZfYm1jX3JlbGVhc2UsCisJ LnBvbGwJCT0gc3NpZl9ibWNfcG9sbCwKK307CisKKy8qIENhbGxlZCB3aXRoIHNzaWZfYm1jLT5s b2NrIGhlbGQuICovCitzdGF0aWMgdm9pZCBjb21wbGV0ZV9yZXNwb25zZShzdHJ1Y3Qgc3NpZl9i bWNfY3R4ICpzc2lmX2JtYykKK3sKKwkvKiBJbnZhbGlkYXRlIHJlc3BvbnNlIGluIGJ1ZmZlciB0 byBkZW5vdGUgaXQgaGF2aW5nIGJlZW4gc2VudC4gKi8KKwlzc2lmX2JtYy0+cmVzcG9uc2UubGVu ID0gMDsKKwlzc2lmX2JtYy0+cmVzcG9uc2VfaW5fcHJvZ3Jlc3MgPSBmYWxzZTsKKwlzc2lmX2Jt Yy0+bmJ5dGVzX3Byb2Nlc3NlZCA9IDA7CisJc3NpZl9ibWMtPnJlbWFpbl9sZW4gPSAwOworCXdh a2VfdXBfYWxsKCZzc2lmX2JtYy0+d2FpdF9xdWV1ZSk7Cit9CisKKy8qIENhbGxlZCB3aXRoIHNz aWZfYm1jLT5sb2NrIGhlbGQuICovCitzdGF0aWMgdm9pZCBoYW5kbGVfcmVxdWVzdChzdHJ1Y3Qg c3NpZl9ibWNfY3R4ICpzc2lmX2JtYykKK3sKKwlpZiAoc3NpZl9ibWMtPmNsaWVudC0+YWRhcHRl ci0+YWxnby0+c2xhdmVfZW5hYmxlKQorCQlzc2lmX2JtYy0+Y2xpZW50LT5hZGFwdGVyLT5hbGdv LT5zbGF2ZV9lbmFibGUoc3NpZl9ibWMtPmNsaWVudCwgZmFsc2UpOworCisJLyogUmVxdWVzdCBt ZXNzYWdlIGlzIGF2YWlsYWJsZSB0byBwcm9jZXNzICovCisJc3NpZl9ibWMtPnJlcXVlc3RfYXZh aWxhYmxlID0gdHJ1ZTsKKwkvKgorCSAqIFRoaXMgaXMgdGhlIG5ldyBSRUFEIHJlcXVlc3QuCisJ ICovCisJd2FrZV91cF9hbGwoJnNzaWZfYm1jLT53YWl0X3F1ZXVlKTsKK30KKworc3RhdGljIHZv aWQgc2V0X211bHRpcGFydF9yZXNwb25zZV9idWZmZXIoc3RydWN0IHNzaWZfYm1jX2N0eCAqc3Np Zl9ibWMsIHU4ICp2YWwpCit7CisJdTggcmVzcG9uc2VfbGVuID0gMDsKKwlpbnQgaWR4ID0gMDsK Kwl1OCBkYXRhX2xlbjsKKworCWRhdGFfbGVuID0gc3NpZl9ibWMtPnJlc3BvbnNlLmxlbjsKKwlz d2l0Y2ggKHNzaWZfYm1jLT5zbWJ1c19jbWQpIHsKKwljYXNlIFNTSUZfSVBNSV9NVUxUSVBBUlRf UkVBRF9TVEFSVDoKKwkJLyoKKwkJICogUmVhZCBTdGFydCBsZW5ndGggaXMgMzIgYnl0ZXMuCisJ CSAqIFJlYWQgU3RhcnQgdHJhbnNmZXIgZmlyc3QgMzAgYnl0ZXMgb2YgSVBNSSByZXNwb25zZQor CQkgKiBhbmQgMiBzcGVjaWFsIGNvZGUgMHgwMCwgMHgwMS4KKwkJICovCisJCSp2YWwgPSBNQVhf UEFZTE9BRF9QRVJfVFJBTlNBQ1RJT047CisJCXNzaWZfYm1jLT5yZW1haW5fbGVuID0gZGF0YV9s ZW4gLSBNQVhfSVBNSV9EQVRBX1BFUl9TVEFSVF9UUkFOU0FDVElPTjsKKwkJc3NpZl9ibWMtPmJs b2NrX251bSA9IDA7CisKKwkJc3NpZl9ibWMtPnJlc3BvbnNlX2J1ZltpZHgrK10gPSAweDAwOyAv KiBTdGFydCBGbGFnICovCisJCXNzaWZfYm1jLT5yZXNwb25zZV9idWZbaWR4KytdID0gMHgwMTsg LyogU3RhcnQgRmxhZyAqLworCQlzc2lmX2JtYy0+cmVzcG9uc2VfYnVmW2lkeCsrXSA9IHNzaWZf Ym1jLT5yZXNwb25zZS5uZXRmbl9sdW47CisJCXNzaWZfYm1jLT5yZXNwb25zZV9idWZbaWR4Kytd ID0gc3NpZl9ibWMtPnJlc3BvbnNlLmNtZDsKKwkJc3NpZl9ibWMtPnJlc3BvbnNlX2J1ZltpZHgr K10gPSBzc2lmX2JtYy0+cmVzcG9uc2UucGF5bG9hZFswXTsKKworCQlyZXNwb25zZV9sZW4gPSBN QVhfUEFZTE9BRF9QRVJfVFJBTlNBQ1RJT04gLSBpZHg7CisKKwkJbWVtY3B5KCZzc2lmX2JtYy0+ cmVzcG9uc2VfYnVmW2lkeF0sICZzc2lmX2JtYy0+cmVzcG9uc2UucGF5bG9hZFsxXSwKKwkJICAg ICAgIHJlc3BvbnNlX2xlbik7CisJCWJyZWFrOworCisJY2FzZSBTU0lGX0lQTUlfTVVMVElQQVJU X1JFQURfTUlERExFOgorCQkvKgorCQkgKiBJUE1JIFJFQUQgTWlkZGxlIG9yIFJFQUQgRW5kIG1l c3NhZ2VzIGNhbiBjYXJyeSB1cCB0byAzMSBieXRlcworCQkgKiBJUE1JIGRhdGEgcGx1cyBibG9j ayBudW1iZXIgYnl0ZS4KKwkJICovCisJCWlmIChzc2lmX2JtYy0+cmVtYWluX2xlbiA8IE1BWF9J UE1JX0RBVEFfUEVSX01JRERMRV9UUkFOU0FDVElPTikgeworCQkJLyoKKwkJCSAqIFRoaXMgaXMg UkVBRCBFbmQgbWVzc2FnZQorCQkJICogIFJldHVybiBsZW5ndGggaXMgdGhlIHJlbWFpbmluZyBy ZXNwb25zZSBkYXRhIGxlbmd0aAorCQkJICogIHBsdXMgYmxvY2sgbnVtYmVyCisJCQkgKiAgQmxv Y2sgbnVtYmVyIDB4RkYgaXMgdG8gaW5kaWNhdGUgdGhpcyBpcyBsYXN0IG1lc3NhZ2UKKwkJCSAq CisJCQkgKi8KKwkJCSp2YWwgPSBzc2lmX2JtYy0+cmVtYWluX2xlbiArIDE7CisJCQlzc2lmX2Jt Yy0+YmxvY2tfbnVtID0gMHhGRjsKKwkJCXNzaWZfYm1jLT5yZXNwb25zZV9idWZbaWR4KytdID0g c3NpZl9ibWMtPmJsb2NrX251bTsKKwkJCXJlc3BvbnNlX2xlbiA9IHNzaWZfYm1jLT5yZW1haW5f bGVuOworCQkJLyogQ2xlYW4gdGhlIGJ1ZmZlciAqLworCQkJbWVtc2V0KCZzc2lmX2JtYy0+cmVz cG9uc2VfYnVmW2lkeF0sIDAsIE1BWF9QQVlMT0FEX1BFUl9UUkFOU0FDVElPTiAtIGlkeCk7CisJ CX0gZWxzZSB7CisJCQkvKgorCQkJICogVGhpcyBpcyBSRUFEIE1pZGRsZSBtZXNzYWdlCisJCQkg KiAgUmVzcG9uc2UgbGVuZ3RoIGlzIHRoZSBtYXhpbXVtIFNNQlVTIHRyYW5zZmVyIGxlbmd0aAor CQkJICogIEJsb2NrIG51bWJlciBieXRlIGlzIGluY3JlbWVudGVkCisJCQkgKiBSZXR1cm4gbGVu Z3RoIGlzIG1heGltdW0gU01CVVMgdHJhbnNmZXIgbGVuZ3RoCisJCQkgKi8KKwkJCSp2YWwgPSBN QVhfUEFZTE9BRF9QRVJfVFJBTlNBQ1RJT047CisJCQlzc2lmX2JtYy0+cmVtYWluX2xlbiAtPSBN QVhfSVBNSV9EQVRBX1BFUl9NSURETEVfVFJBTlNBQ1RJT047CisJCQlyZXNwb25zZV9sZW4gPSBN QVhfSVBNSV9EQVRBX1BFUl9NSURETEVfVFJBTlNBQ1RJT047CisJCQlzc2lmX2JtYy0+cmVzcG9u c2VfYnVmW2lkeCsrXSA9IHNzaWZfYm1jLT5ibG9ja19udW07CisJCQlzc2lmX2JtYy0+YmxvY2tf bnVtKys7CisJCX0KKworCQltZW1jcHkoJnNzaWZfYm1jLT5yZXNwb25zZV9idWZbaWR4XSwKKwkJ ICAgICAgIHNzaWZfYm1jLT5yZXNwb25zZS5wYXlsb2FkICsgMSArIHNzaWZfYm1jLT5uYnl0ZXNf cHJvY2Vzc2VkLAorCQkgICAgICAgcmVzcG9uc2VfbGVuKTsKKwkJYnJlYWs7CisKKwlkZWZhdWx0 OgorCQkvKiBEbyBub3QgZXhwZWN0IHRvIGdvIHRvIHRoaXMgY2FzZSAqLworCQlkZXZfZXJyKCZz c2lmX2JtYy0+Y2xpZW50LT5kZXYsCisJCQkiJXM6IFVuZXhwZWN0ZWQgU01CdXMgY29tbWFuZCAw eCV4LCBhYm9ydGluZyAuLi5cbiIsCisJCQlfX2Z1bmNfXywgc3NpZl9ibWMtPnNtYnVzX2NtZCk7 CisJCXNzaWZfYm1jLT5hYm9ydGluZyA9IHRydWU7CisJCWJyZWFrOworCX0KKworCXNzaWZfYm1j LT5uYnl0ZXNfcHJvY2Vzc2VkICs9IHJlc3BvbnNlX2xlbjsKK30KKworLyogUHJvY2VzcyB0aGUg SVBNSSByZXNwb25zZSB0aGF0IHdpbGwgYmUgcmVhZCBieSBtYXN0ZXIgKi8KK3N0YXRpYyB2b2lk IGhhbmRsZV9yZWFkX3Byb2Nlc3NlZChzdHJ1Y3Qgc3NpZl9ibWNfY3R4ICpzc2lmX2JtYywgdTgg KnZhbCkKK3sKKwl1OCAqYnVmOworCXU4IHBlY19sZW4sIGFkZHIsIGxlbjsKKwl1OCBwZWMgPSAw OworCisJcGVjX2xlbiA9IHNzaWZfYm1jLT5wZWNfc3VwcG9ydCA/IDEgOiAwOworCS8qIFBFQyAt IFN0YXJ0IFJlYWQgQWRkcmVzcyAqLworCWFkZHIgPSBHRVRfOEJJVF9BRERSKHNzaWZfYm1jLT5j bGllbnQtPmFkZHIpOworCXBlYyA9IGkyY19zbWJ1c19wZWMocGVjLCAmYWRkciwgMSk7CisJLyog UEVDIC0gU1NJRiBDb21tYW5kICovCisJcGVjID0gaTJjX3NtYnVzX3BlYyhwZWMsICZzc2lmX2Jt Yy0+c21idXNfY21kLCAxKTsKKwkvKiBQRUMgLSBSZXN0YXJ0IFdyaXRlIEFkZHJlc3MgKi8KKwlh ZGRyID0gYWRkciB8IDB4MDE7CisJcGVjID0gaTJjX3NtYnVzX3BlYyhwZWMsICZhZGRyLCAxKTsK KworCWlmIChzc2lmX2JtYy0+aXNfc2luZ2xlcGFydF9yZWFkKSB7CisJCS8qIFNpbmdsZS1wYXJ0 IFJlYWQgcHJvY2Vzc2luZyAqLworCQlidWYgPSAodTggKikmc3NpZl9ibWMtPnJlc3BvbnNlOwor CisJCWlmIChzc2lmX2JtYy0+cmVzcG9uc2UubGVuICYmIHNzaWZfYm1jLT5tc2dfaWR4IDwgc3Np Zl9ibWMtPnJlc3BvbnNlLmxlbikgeworCQkJc3NpZl9ibWMtPm1zZ19pZHgrKzsKKwkJCSp2YWwg PSBidWZbc3NpZl9ibWMtPm1zZ19pZHhdOworCQl9IGVsc2UgaWYgKHNzaWZfYm1jLT5yZXNwb25z ZS5sZW4gJiYgc3NpZl9ibWMtPm1zZ19pZHggPT0gc3NpZl9ibWMtPnJlc3BvbnNlLmxlbikgewor CQkJc3NpZl9ibWMtPm1zZ19pZHgrKzsKKwkJCSp2YWwgPSBpMmNfc21idXNfcGVjKHBlYywgYnVm LCBzc2lmX21zZ19sZW4oJnNzaWZfYm1jLT5yZXNwb25zZSkpOworCQl9IGVsc2UgeworCQkJKnZh bCA9IDA7CisJCX0KKwkJLyogSW52YWxpZGF0ZSByZXNwb25zZSBidWZmZXIgdG8gZGVub3RlIGl0 IGlzIHNlbnQgKi8KKwkJaWYgKHNzaWZfYm1jLT5tc2dfaWR4ICsgMSA+PSAoc3NpZl9tc2dfbGVu KCZzc2lmX2JtYy0+cmVzcG9uc2UpICsgcGVjX2xlbikpCisJCQljb21wbGV0ZV9yZXNwb25zZShz c2lmX2JtYyk7CisJfSBlbHNlIHsKKwkJLyogTXVsdGktcGFydCBSZWFkIHByb2Nlc3NpbmcgKi8K KwkJc3dpdGNoIChzc2lmX2JtYy0+c21idXNfY21kKSB7CisJCWNhc2UgU1NJRl9JUE1JX01VTFRJ UEFSVF9SRUFEX1NUQVJUOgorCQljYXNlIFNTSUZfSVBNSV9NVUxUSVBBUlRfUkVBRF9NSURETEU6 CisJCQlidWYgPSAodTggKikmc3NpZl9ibWMtPnJlc3BvbnNlX2J1ZjsKKwkJCSp2YWwgPSBidWZb c3NpZl9ibWMtPm1zZ19pZHhdOworCQkJc3NpZl9ibWMtPm1zZ19pZHgrKzsKKwkJCWJyZWFrOwor CQlkZWZhdWx0OgorCQkJLyogRG8gbm90IGV4cGVjdCB0byBnbyB0byB0aGlzIGNhc2UgKi8KKwkJ CWRldl9lcnIoJnNzaWZfYm1jLT5jbGllbnQtPmRldiwKKwkJCQkiJXM6IFVuZXhwZWN0ZWQgU01C dXMgY29tbWFuZCAweCV4LCBhYm9ydGluZyAuLi5cbiIsCisJCQkJX19mdW5jX18sIHNzaWZfYm1j LT5zbWJ1c19jbWQpOworCQkJc3NpZl9ibWMtPmFib3J0aW5nID0gdHJ1ZTsKKwkJCWJyZWFrOwor CQl9CisKKwkJbGVuID0gKHNzaWZfYm1jLT5ibG9ja19udW0gPT0gMHhGRikgPworCQkgICAgICAg c3NpZl9ibWMtPnJlbWFpbl9sZW4gKyAxIDogTUFYX1BBWUxPQURfUEVSX1RSQU5TQUNUSU9OOwor CQlpZiAoc3NpZl9ibWMtPm1zZ19pZHggPT0gKGxlbiArIDEpKSB7CisJCQlwZWMgPSBpMmNfc21i dXNfcGVjKHBlYywgJmxlbiwgMSk7CisJCQkqdmFsID0gaTJjX3NtYnVzX3BlYyhwZWMsIHNzaWZf Ym1jLT5yZXNwb25zZV9idWYsIGxlbik7CisJCX0KKwkJLyogSW52YWxpZGF0ZSByZXNwb25zZSBi dWZmZXIgdG8gZGVub3RlIGxhc3QgcmVzcG9uc2UgaXMgc2VudCAqLworCQlpZiAoc3NpZl9ibWMt PmJsb2NrX251bSA9PSAweEZGICYmCisJCSAgICBzc2lmX2JtYy0+bXNnX2lkeCA+IChzc2lmX2Jt Yy0+cmVtYWluX2xlbiArIHBlY19sZW4pKSB7CisJCQljb21wbGV0ZV9yZXNwb25zZShzc2lmX2Jt Yyk7CisJCX0KKwl9Cit9CisKK3N0YXRpYyB2b2lkIGhhbmRsZV93cml0ZV9yZWNlaXZlZChzdHJ1 Y3Qgc3NpZl9ibWNfY3R4ICpzc2lmX2JtYywgdTggKnZhbCkKK3sKKwl1OCAqYnVmID0gKHU4ICop JnNzaWZfYm1jLT5yZXF1ZXN0OworCisJaWYgKHNzaWZfYm1jLT5tc2dfaWR4ID49IHNpemVvZihz dHJ1Y3Qgc3NpZl9tc2cpKQorCQlyZXR1cm47CisKKwlzd2l0Y2ggKHNzaWZfYm1jLT5zbWJ1c19j bWQpIHsKKwljYXNlIFNTSUZfSVBNSV9TSU5HTEVQQVJUX1dSSVRFOgorCQlidWZbc3NpZl9ibWMt Pm1zZ19pZHggLSAxXSA9ICp2YWw7CisJCXNzaWZfYm1jLT5tc2dfaWR4Kys7CisKKwkJYnJlYWs7 CisJY2FzZSBTU0lGX0lQTUlfTVVMVElQQVJUX1dSSVRFX1NUQVJUOgorCQlpZiAoc3NpZl9ibWMt Pm1zZ19pZHggPT0gMSkKKwkJCXNzaWZfYm1jLT5yZXF1ZXN0LmxlbiA9IDA7CisKKwkJZmFsbHRo cm91Z2g7CisJY2FzZSBTU0lGX0lQTUlfTVVMVElQQVJUX1dSSVRFX01JRERMRToKKwkJLyogVGhl IGxlbiBzaG91bGQgYWx3YXlzIGJlIDMyICovCisJCWlmIChzc2lmX2JtYy0+bXNnX2lkeCA9PSAx ICYmICp2YWwgIT0gTUFYX1BBWUxPQURfUEVSX1RSQU5TQUNUSU9OKSB7CisJCQlkZXZfd2Fybigm c3NpZl9ibWMtPmNsaWVudC0+ZGV2LAorCQkJCSAiV2FybjogSW52YWxpZCBNdWx0aXBhcnQgV3Jp dGUgbGVuLCBhYm9ydGluZyAuLi4iKTsKKwkJCXNzaWZfYm1jLT5hYm9ydGluZyA9IHRydWU7CisJ CX0KKworCQlmYWxsdGhyb3VnaDsKKwljYXNlIFNTSUZfSVBNSV9NVUxUSVBBUlRfV1JJVEVfRU5E OgorCQkvKiBNdWx0aS1wYXJ0IHdyaXRlLCAybmQgYnl0ZSByZWNlaXZlZCBpcyBsZW5ndGggKi8K KwkJaWYgKHNzaWZfYm1jLT5tc2dfaWR4ID09IDEpIHsKKwkJCWlmICgqdmFsID4gTUFYX1BBWUxP QURfUEVSX1RSQU5TQUNUSU9OKSB7CisJCQkJZGV2X3dhcm4oJnNzaWZfYm1jLT5jbGllbnQtPmRl diwKKwkJCQkJICJXYXJuOiBJbnZhbGlkIE11bHRpcGFydCBXcml0ZSBFbmQgbGVuLCBhYm9ydGlu ZyAuLi4iKTsKKwkJCQlzc2lmX2JtYy0+YWJvcnRpbmcgPSB0cnVlOworCQkJfQorCisJCQlzc2lm X2JtYy0+cmVxdWVzdC5sZW4gKz0gKnZhbDsKKwkJCXNzaWZfYm1jLT5yZWN2X2xlbiA9ICp2YWw7 CisKKwkJCS8qIHJlcXVlc3QgbGVuIHNob3VsZCBuZXZlciBleGNlZWRlZCAyNTUgYnl0ZXMgKi8K KwkJCWlmIChzc2lmX2JtYy0+cmVxdWVzdC5sZW4gPiAyNTUpIHsKKwkJCQlkZXZfd2Fybigmc3Np Zl9ibWMtPmNsaWVudC0+ZGV2LAorCQkJCQkgIldhcm46IEludmFsaWQgcmVxdWVzdCBsZW4sIGFi b3J0aW5nIC4uLiIpOworCQkJCXNzaWZfYm1jLT5hYm9ydGluZyA9IHRydWU7CisJCQl9CisKKwkJ fSBlbHNlIHsKKwkJCWJ1Zltzc2lmX2JtYy0+bXNnX2lkeCAtIDEgKworCQkJICAgIHNzaWZfYm1j LT5yZXF1ZXN0LmxlbiAtIHNzaWZfYm1jLT5yZWN2X2xlbl0JPSAqdmFsOworCQl9CisKKwkJc3Np Zl9ibWMtPm1zZ19pZHgrKzsKKworCQlicmVhazsKKwlkZWZhdWx0OgorCQkvKiBEbyBub3QgZXhw ZWN0IHRvIGdvIHRvIHRoaXMgY2FzZSAqLworCQlkZXZfZXJyKCZzc2lmX2JtYy0+Y2xpZW50LT5k ZXYsCisJCQkiJXM6IFVuZXhwZWN0ZWQgU01CdXMgY29tbWFuZCAweCV4LCBhYm9ydGluZyAuLi5c biIsCisJCQlfX2Z1bmNfXywgc3NpZl9ibWMtPnNtYnVzX2NtZCk7CisJCXNzaWZfYm1jLT5hYm9y dGluZyA9IHRydWU7CisJCWJyZWFrOworCX0KK30KKworc3RhdGljIGJvb2wgdmFsaWRhdGVfcmVx dWVzdChzdHJ1Y3Qgc3NpZl9ibWNfY3R4ICpzc2lmX2JtYykKK3sKKwl1OCBycGVjID0gMCwgY3Bl YyA9IDA7CisJYm9vbCByZXQgPSB0cnVlOworCXU4IGFkZHIsIGluZGV4OworCXU4ICpidWY7CisK KwlidWYgPSAodTggKikmc3NpZl9ibWMtPnJlcXVlc3Q7CisJc3dpdGNoIChzc2lmX2JtYy0+c21i dXNfY21kKSB7CisJY2FzZSBTU0lGX0lQTUlfU0lOR0xFUEFSVF9XUklURToKKwkJaWYgKChzc2lm X2JtYy0+bXNnX2lkeCAtIDEpID09IHNzaWZfbXNnX2xlbigmc3NpZl9ibWMtPnJlcXVlc3QpKSB7 CisJCQkvKiBQRUMgaXMgbm90IGluY2x1ZGVkICovCisJCQlzc2lmX2JtYy0+cGVjX3N1cHBvcnQg PSBmYWxzZTsKKwkJCXJldCA9IHRydWU7CisJCQlnb3RvIGV4aXQ7CisJCX0KKworCQlpZiAoKHNz aWZfYm1jLT5tc2dfaWR4IC0gMSkgIT0gKHNzaWZfbXNnX2xlbigmc3NpZl9ibWMtPnJlcXVlc3Qp ICsgMSkpIHsKKwkJCWRldl9lcnIoJnNzaWZfYm1jLT5jbGllbnQtPmRldiwgIkVycm9yOiBVbmV4 cGVjdGVkIGxlbmd0aCByZWNlaXZlZCAlZFxuIiwKKwkJCQlzc2lmX21zZ19sZW4oJnNzaWZfYm1j LT5yZXF1ZXN0KSk7CisJCQlyZXQgPSBmYWxzZTsKKwkJCWdvdG8gZXhpdDsKKwkJfQorCisJCS8q IFBFQyBpcyBpbmNsdWRlZCAqLworCQlzc2lmX2JtYy0+cGVjX3N1cHBvcnQgPSB0cnVlOworCQly cGVjID0gYnVmW3NzaWZfYm1jLT5tc2dfaWR4IC0gMl07CisJCWFkZHIgPSBHRVRfOEJJVF9BRERS KHNzaWZfYm1jLT5jbGllbnQtPmFkZHIpOworCQljcGVjID0gaTJjX3NtYnVzX3BlYyhjcGVjLCAm YWRkciwgMSk7CisJCWNwZWMgPSBpMmNfc21idXNfcGVjKGNwZWMsICZzc2lmX2JtYy0+c21idXNf Y21kLCAxKTsKKwkJY3BlYyA9IGkyY19zbWJ1c19wZWMoY3BlYywgYnVmLCBzc2lmX21zZ19sZW4o JnNzaWZfYm1jLT5yZXF1ZXN0KSk7CisJCWlmIChycGVjICE9IGNwZWMpIHsKKwkJCWRldl9lcnIo JnNzaWZfYm1jLT5jbGllbnQtPmRldiwgIkJhZCBQRUMgMHglMDJ4IHZzLiAweCUwMnhcbiIsIHJw ZWMsIGNwZWMpOworCQkJcmV0ID0gZmFsc2U7CisJCX0KKworCQlicmVhazsKKwljYXNlIFNTSUZf SVBNSV9NVUxUSVBBUlRfV1JJVEVfU1RBUlQ6CisJY2FzZSBTU0lGX0lQTUlfTVVMVElQQVJUX1dS SVRFX01JRERMRToKKwljYXNlIFNTSUZfSVBNSV9NVUxUSVBBUlRfV1JJVEVfRU5EOgorCQlpbmRl eCA9IHNzaWZfYm1jLT5yZXF1ZXN0LmxlbiAtIHNzaWZfYm1jLT5yZWN2X2xlbjsKKwkJaWYgKChz c2lmX2JtYy0+bXNnX2lkeCAtIDEgKyBpbmRleCkgPT0gc3NpZl9tc2dfbGVuKCZzc2lmX2JtYy0+ cmVxdWVzdCkpIHsKKwkJCS8qIFBFQyBpcyBub3QgaW5jbHVkZWQgKi8KKwkJCXNzaWZfYm1jLT5w ZWNfc3VwcG9ydCA9IGZhbHNlOworCQkJcmV0ID0gdHJ1ZTsKKwkJCWdvdG8gZXhpdDsKKwkJfQor CisJCWlmICgoc3NpZl9ibWMtPm1zZ19pZHggLSAxICsgaW5kZXgpICE9IChzc2lmX21zZ19sZW4o JnNzaWZfYm1jLT5yZXF1ZXN0KSArIDEpKSB7CisJCQlkZXZfZXJyKCZzc2lmX2JtYy0+Y2xpZW50 LT5kZXYsICJFcnJvcjogVW5leHBlY3RlZCBsZW5ndGggcmVjZWl2ZWQgJWRcbiIsCisJCQkJc3Np Zl9tc2dfbGVuKCZzc2lmX2JtYy0+cmVxdWVzdCkpOworCQkJcmV0ID0gZmFsc2U7CisJCQlnb3Rv IGV4aXQ7CisJCX0KKworCQkvKiBQRUMgaXMgaW5jbHVkZWQgKi8KKwkJc3NpZl9ibWMtPnBlY19z dXBwb3J0ID0gdHJ1ZTsKKwkJcnBlYyA9IGJ1Zltzc2lmX2JtYy0+bXNnX2lkeCAtIDIgKyBpbmRl eF07CisJCWFkZHIgPSBHRVRfOEJJVF9BRERSKHNzaWZfYm1jLT5jbGllbnQtPmFkZHIpOworCQlj cGVjID0gaTJjX3NtYnVzX3BlYyhjcGVjLCAmYWRkciwgMSk7CisJCWNwZWMgPSBpMmNfc21idXNf cGVjKGNwZWMsICZzc2lmX2JtYy0+c21idXNfY21kLCAxKTsKKwkJY3BlYyA9IGkyY19zbWJ1c19w ZWMoY3BlYywgJnNzaWZfYm1jLT5yZWN2X2xlbiwgMSk7CisJCS8qIEFzIFNNQnVzIHNwZWNpZmlj YXRpb24gZG9lcyBub3QgYWxsb3cgdGhlIGxlbmd0aAorCQkgKiAoYnl0ZSBjb3VudCkgaW4gdGhl IFdyaXRlLUJsb2NrIHByb3RvY29sIHRvIGJlIHplcm8uCisJCSAqIFRoZXJlZm9yZSwgaXQgaXMg aWxsZWdhbCB0byBoYXZlIHRoZSBsYXN0IE1pZGRsZQorCQkgKiB0cmFuc2FjdGlvbiBpbiB0aGUg c2VxdWVuY2UgY2FycnkgMzItYnl0ZSBhbmQgaGF2ZQorCQkgKiBhIGxlbmd0aCBvZiDigJgw4oCZ IGluIHRoZSBFbmQgdHJhbnNhY3Rpb24uCisJCSAqIEJ1dCBzb21lIHVzZXJzIG1heSB0cnkgdG8g dXNlIHRoaXMgd2F5IGFuZCB3ZSBzaG91bGQKKwkJICogcHJldmVudCBzc2lmX2JtYyBkcml2ZXIg YnJva2VuIGluIHRoaXMgY2FzZS4KKwkJICovCisJCWlmIChzc2lmX2JtYy0+cmVjdl9sZW4gIT0g MCkKKwkJCWNwZWMgPSBpMmNfc21idXNfcGVjKGNwZWMsIGJ1ZiArIDEgKyBpbmRleCwgc3NpZl9i bWMtPnJlY3ZfbGVuKTsKKworCQlpZiAocnBlYyAhPSBjcGVjKSB7CisJCQlkZXZfZXJyKCZzc2lm X2JtYy0+Y2xpZW50LT5kZXYsICJCYWQgUEVDIDB4JTAyeCB2cy4gMHglMDJ4XG4iLCBycGVjLCBj cGVjKTsKKwkJCXJldCA9IGZhbHNlOworCQl9CisKKwkJYnJlYWs7CisJZGVmYXVsdDoKKwkJLyog RG8gbm90IGV4cGVjdCB0byBnbyB0byB0aGlzIGNhc2UgKi8KKwkJZGV2X2Vycigmc3NpZl9ibWMt PmNsaWVudC0+ZGV2LCAiJXM6IFVuZXhwZWN0ZWQgU01CdXMgY29tbWFuZCAweCV4LCBhYm9ydGlu ZyAuLi5cbiIsCisJCQlfX2Z1bmNfXywgc3NpZl9ibWMtPnNtYnVzX2NtZCk7CisJCXJldCA9IGZh bHNlOworCQlicmVhazsKKwl9CisKK2V4aXQ6CisJcmV0dXJuIHJldDsKK30KKworc3RhdGljIGJv b2wgdW5zdXBwb3J0ZWRfc21idXNfY21kKHU4IGNtZCkKK3sKKwlpZiAoY21kID09IFNTSUZfSVBN SV9TSU5HTEVQQVJUX1JFQUQgfHwKKwkgICAgY21kID09IFNTSUZfSVBNSV9TSU5HTEVQQVJUX1dS SVRFIHx8CisJICAgIGNtZCA9PSBTU0lGX0lQTUlfTVVMVElQQVJUX1dSSVRFX1NUQVJUIHx8CisJ ICAgIGNtZCA9PSBTU0lGX0lQTUlfTVVMVElQQVJUX1dSSVRFX01JRERMRSB8fAorCSAgICBjbWQg PT0gU1NJRl9JUE1JX01VTFRJUEFSVF9XUklURV9FTkQgfHwKKwkgICAgY21kID09IFNTSUZfSVBN SV9NVUxUSVBBUlRfUkVBRF9TVEFSVCB8fAorCSAgICBjbWQgPT0gU1NJRl9JUE1JX01VTFRJUEFS VF9SRUFEX01JRERMRSkKKwkJcmV0dXJuIGZhbHNlOworCisJcmV0dXJuIHRydWU7Cit9CisKK3N0 YXRpYyB2b2lkIHByb2Nlc3Nfc21idXNfY21kKHN0cnVjdCBzc2lmX2JtY19jdHggKnNzaWZfYm1j LCB1OCAqdmFsKQoreworCS8qIFNNQlVTIGNvbW1hbmQgY2FuIHZhcnkgKHNpbmdsZSBvciBtdWx0 aS1wYXJ0KSAqLworCXNzaWZfYm1jLT5zbWJ1c19jbWQgPSAqdmFsOworCXNzaWZfYm1jLT5tc2df aWR4Kys7CisKKwlpZiAodW5zdXBwb3J0ZWRfc21idXNfY21kKCp2YWwpKSB7CisJCWRldl93YXJu KCZzc2lmX2JtYy0+Y2xpZW50LT5kZXYsICJXYXJuOiBVbmtub3duIFNNQnVzIGNvbW1hbmQsIGFi b3J0aW5nIC4uLiIpOworCQlzc2lmX2JtYy0+YWJvcnRpbmcgPSB0cnVlOworCX0gZWxzZSBpZiAo c3NpZl9ibWMtPmFib3J0aW5nICYmCisJCSAgICgqdmFsID09IFNTSUZfSVBNSV9TSU5HTEVQQVJU X1dSSVRFIHx8CisJCSAgICAqdmFsID09IFNTSUZfSVBNSV9NVUxUSVBBUlRfV1JJVEVfU1RBUlQp KSB7CisJCS8qIE5ldyByZXF1ZXN0ICovCisJCWRldl93YXJuKCZzc2lmX2JtYy0+Y2xpZW50LT5k ZXYsICJXYXJuOiBOZXcgcmVxdWVzdCBmb3VuZCwgc3RvcCBhYm9ydGluZyAuLi4iKTsKKwkJc3Np Zl9ibWMtPmFib3J0aW5nID0gZmFsc2U7CisJfQorfQorCitzdGF0aWMgdm9pZCBvbl9yZWFkX3Jl cXVlc3RlZF9ldmVudChzdHJ1Y3Qgc3NpZl9ibWNfY3R4ICpzc2lmX2JtYywgdTggKnZhbCkKK3sK KwlpZiAoc3NpZl9ibWMtPnN0YXRlID09IFNTSUZfUkVBRFkgfHwKKwkgICAgc3NpZl9ibWMtPnN0 YXRlID09IFNTSUZfU1RBUlQgfHwKKwkgICAgc3NpZl9ibWMtPnN0YXRlID09IFNTSUZfUkVRX1JF Q1ZJTkcgfHwKKwkgICAgc3NpZl9ibWMtPnN0YXRlID09IFNTSUZfUkVTX1NFTkRJTkcpIHsKKwkJ c3NpZl9ibWMtPnN0YXRlID0gU1NJRl9CQURfU01CVVM7CisJCWRldl93YXJuKCZzc2lmX2JtYy0+ Y2xpZW50LT5kZXYsCisJCQkgIldhcm46ICVzIHVuZXhwZWN0ZWQgUkVBRCBSRVFVRVNURUQgaW4g c3RhdGU9JXMsIGFib3J0aW5nIC4uLlxuIiwKKwkJCSBfX2Z1bmNfXywgc3RhdGVfdG9fc3RyaW5n KHNzaWZfYm1jLT5zdGF0ZSkpOworCQlzc2lmX2JtYy0+YWJvcnRpbmcgPSB0cnVlOworCisJfSBl bHNlIGlmIChzc2lmX2JtYy0+c3RhdGUgPT0gU1NJRl9TTUJVU19DTUQpIHsKKwkJc3NpZl9ibWMt PnN0YXRlID0gU1NJRl9SRVNfU0VORElORzsKKwl9CisKKwlpZiAoc3NpZl9ibWMtPmFib3J0aW5n IHx8IHNzaWZfYm1jLT5zdGF0ZSAhPSBTU0lGX1JFU19TRU5ESU5HKSB7CisJCS8qIEFib3J0IGJ5 IHJldHVybmluZyB0aGUgbGFzdCByZXF1ZXN0IHdpdGggMHhGRiBhcyBjb21wbGV0aW9uIGNvZGUg Ki8KKwkJc3NpZl9ibWMtPmlzX3NpbmdsZXBhcnRfcmVhZCA9IHRydWU7CisJCXNzaWZfYm1jLT5y ZXNwb25zZS5sZW4gPSAweDAzOworCQlzc2lmX2JtYy0+cmVzcG9uc2UubmV0Zm5fbHVuID0gc3Np Zl9ibWMtPnJlcXVlc3QubmV0Zm5fbHVuIHwgNDsKKwkJc3NpZl9ibWMtPnJlc3BvbnNlLmNtZCA9 IHNzaWZfYm1jLT5yZXF1ZXN0LmNtZDsKKwkJbWVtc2V0KCZzc2lmX2JtYy0+cmVzcG9uc2UucGF5 bG9hZFswXSwgMHhGRiwgTUFYX1BBWUxPQURfUEVSX1RSQU5TQUNUSU9OKTsKKwl9CisKKwlzc2lm X2JtYy0+bXNnX2lkeCA9IDA7CisJaWYgKHNzaWZfYm1jLT5pc19zaW5nbGVwYXJ0X3JlYWQpCisJ CSp2YWwgPSBzc2lmX2JtYy0+cmVzcG9uc2UubGVuOworCWVsc2UKKwkJc2V0X211bHRpcGFydF9y ZXNwb25zZV9idWZmZXIoc3NpZl9ibWMsIHZhbCk7Cit9CisKK3N0YXRpYyB2b2lkIG9uX3JlYWRf cHJvY2Vzc2VkX2V2ZW50KHN0cnVjdCBzc2lmX2JtY19jdHggKnNzaWZfYm1jLCB1OCAqdmFsKQor eworCWlmIChzc2lmX2JtYy0+c3RhdGUgPT0gU1NJRl9SRUFEWSB8fAorCSAgICBzc2lmX2JtYy0+ c3RhdGUgPT0gU1NJRl9TVEFSVCB8fAorCSAgICBzc2lmX2JtYy0+c3RhdGUgPT0gU1NJRl9SRVFf UkVDVklORyB8fAorCSAgICBzc2lmX2JtYy0+c3RhdGUgPT0gU1NJRl9TTUJVU19DTUQpIHsKKwkJ ZGV2X3dhcm4oJnNzaWZfYm1jLT5jbGllbnQtPmRldiwKKwkJCSAiV2FybjogJXMgdW5leHBlY3Rl ZCBSRUFEIFBST0NFU1NFRCBpbiBzdGF0ZT0lc1xuIiwKKwkJCSBfX2Z1bmNfXywgc3RhdGVfdG9f c3RyaW5nKHNzaWZfYm1jLT5zdGF0ZSkpOworCQlzc2lmX2JtYy0+c3RhdGUgPSBTU0lGX0JBRF9T TUJVUzsKKwl9CisKKwloYW5kbGVfcmVhZF9wcm9jZXNzZWQoc3NpZl9ibWMsIHZhbCk7Cit9CisK K3N0YXRpYyB2b2lkIG9uX3dyaXRlX3JlcXVlc3RlZF9ldmVudChzdHJ1Y3Qgc3NpZl9ibWNfY3R4 ICpzc2lmX2JtYywgdTggKnZhbCkKK3sKKwlzc2lmX2JtYy0+bXNnX2lkeCA9IDA7CisKKwlpZiAo c3NpZl9ibWMtPnN0YXRlID09IFNTSUZfUkVBRFkgfHwgc3NpZl9ibWMtPnN0YXRlID09IFNTSUZf U01CVVNfQ01EKSB7CisJCXNzaWZfYm1jLT5zdGF0ZSA9IFNTSUZfU1RBUlQ7CisKKwl9IGVsc2Ug aWYgKHNzaWZfYm1jLT5zdGF0ZSA9PSBTU0lGX1NUQVJUIHx8CisJCSAgIHNzaWZfYm1jLT5zdGF0 ZSA9PSBTU0lGX1JFUV9SRUNWSU5HIHx8CisJCSAgIHNzaWZfYm1jLT5zdGF0ZSA9PSBTU0lGX1JF U19TRU5ESU5HKSB7CisJCWRldl93YXJuKCZzc2lmX2JtYy0+Y2xpZW50LT5kZXYsCisJCQkgIldh cm46ICVzIHVuZXhwZWN0ZWQgV1JJVEUgUkVRVUVTVCBpbiBzdGF0ZT0lc1xuIiwKKwkJCSBfX2Z1 bmNfXywgc3RhdGVfdG9fc3RyaW5nKHNzaWZfYm1jLT5zdGF0ZSkpOworCQlzc2lmX2JtYy0+c3Rh dGUgPSBTU0lGX0JBRF9TTUJVUzsKKwl9Cit9CisKK3N0YXRpYyB2b2lkIG9uX3dyaXRlX3JlY2Vp dmVkX2V2ZW50KHN0cnVjdCBzc2lmX2JtY19jdHggKnNzaWZfYm1jLCB1OCAqdmFsKQoreworCWlm IChzc2lmX2JtYy0+c3RhdGUgPT0gU1NJRl9SRUFEWSB8fCBzc2lmX2JtYy0+c3RhdGUgPT0gU1NJ Rl9SRVNfU0VORElORykgeworCQlkZXZfd2Fybigmc3NpZl9ibWMtPmNsaWVudC0+ZGV2LAorCQkJ ICJXYXJuOiAlcyB1bmV4cGVjdGVkIFdSSVRFIFJFQ0VJVkVEIGluIHN0YXRlPSVzXG4iLAorCQkJ IF9fZnVuY19fLCBzdGF0ZV90b19zdHJpbmcoc3NpZl9ibWMtPnN0YXRlKSk7CisJCXNzaWZfYm1j LT5zdGF0ZSA9IFNTSUZfQkFEX1NNQlVTOworCX0gZWxzZSBpZiAoc3NpZl9ibWMtPnN0YXRlID09 IFNTSUZfU1RBUlQpIHsKKwkJc3NpZl9ibWMtPnN0YXRlID0gU1NJRl9TTUJVU19DTUQ7CisJfSBl bHNlIGlmIChzc2lmX2JtYy0+c3RhdGUgPT0gU1NJRl9TTUJVU19DTUQpIHsKKwkJc3NpZl9ibWMt PnN0YXRlID0gU1NJRl9SRVFfUkVDVklORzsKKwl9CisKKwkvKiBUaGlzIGlzIHJlc3BvbnNlIHNl bmRpbmcgc3RhdGUgKi8KKwlpZiAoc3NpZl9ibWMtPnN0YXRlID09IFNTSUZfUkVRX1JFQ1ZJTkcp IHsKKwkJaWYgKHNzaWZfYm1jLT5yZXNwb25zZV9pbl9wcm9ncmVzcykgeworCQkJLyoKKwkJCSAq IEFzIHBlciBzcGVjLCBpdCBpcyBnZW5lcmljIG1hbmFnZW1lbnQgc29mdHdhcmUgb3IgU1NJRiBk cml2ZXJzIHRvIHRha2UKKwkJCSAqIGNhcmUgb2YgaXNzdWluZyBuZXcgcmVxdWVzdCBiZWZvcmUg dGhlIHByaW9yIHJlcXVlc3RzIGNvbXBsZXRlZC4KKwkJCSAqIFNvIGp1c3QgYWJvcnQgZXZlcnl0 aGluZyBoZXJlIGFuZCB3YWl0IGZvciBuZXh0IG5ldyByZXF1ZXN0CisJCQkgKi8KKwkJCWRldl93 YXJuKCZzc2lmX2JtYy0+Y2xpZW50LT5kZXYsCisJCQkJICJXYXJuOiBTU0lGIG5ldyByZXF1ZXN0 IHdpdGggcGVuZGluZyByZXNwb25zZSwgYWJvcnRpbmcgLi4uIik7CisJCQlzc2lmX2JtYy0+YWJv cnRpbmcgPSB0cnVlOworCQkJY29tcGxldGVfcmVzcG9uc2Uoc3NpZl9ibWMpOworCQl9CisKKwkJ aGFuZGxlX3dyaXRlX3JlY2VpdmVkKHNzaWZfYm1jLCB2YWwpOworCX0gZWxzZSBpZiAoc3NpZl9i bWMtPnN0YXRlID09IFNTSUZfU01CVVNfQ01EKSB7CisJCXByb2Nlc3Nfc21idXNfY21kKHNzaWZf Ym1jLCB2YWwpOworCX0KK30KKworc3RhdGljIHZvaWQgb25fc3RvcF9ldmVudChzdHJ1Y3Qgc3Np Zl9ibWNfY3R4ICpzc2lmX2JtYywgdTggKnZhbCkKK3sKKwlpZiAoc3NpZl9ibWMtPnN0YXRlID09 IFNTSUZfUkVBRFkgfHwKKwkgICAgc3NpZl9ibWMtPnN0YXRlID09IFNTSUZfU1RBUlQgfHwKKwkg ICAgc3NpZl9ibWMtPnN0YXRlID09IFNTSUZfU01CVVNfQ01EKSB7CisJCWRldl93YXJuKCZzc2lm X2JtYy0+Y2xpZW50LT5kZXYsCisJCQkgIldhcm46ICVzIHVuZXhwZWN0ZWQgU0xBVkUgU1RPUCBp biBzdGF0ZT0lc1xuIiwKKwkJCSBfX2Z1bmNfXywgc3RhdGVfdG9fc3RyaW5nKHNzaWZfYm1jLT5z dGF0ZSkpOworCisJfSBlbHNlIGlmIChzc2lmX2JtYy0+c3RhdGUgPT0gU1NJRl9CQURfU01CVVMp IHsKKwkJZGV2X3dhcm4oJnNzaWZfYm1jLT5jbGllbnQtPmRldiwKKwkJCSAiV2FybjogJXMgcmVj ZWl2ZWQgU0xBVkUgU1RPUCBmcm9tIGJhZCBzdGF0ZT0lc1xuIiwKKwkJCSBfX2Z1bmNfXywgc3Rh dGVfdG9fc3RyaW5nKHNzaWZfYm1jLT5zdGF0ZSkpOworCisJfSBlbHNlIGlmIChzc2lmX2JtYy0+ c3RhdGUgPT0gU1NJRl9SRVFfUkVDVklORykgeworCQkvKiBBIEJNQyB0aGF0IHJlY2VpdmVzIGFu IGludmFsaWQgcmVxdWVzdCBkcm9wIHRoZSBkYXRhIGZvciB0aGUgd3JpdGUKKwkJICogdHJhbnNh Y3Rpb24gYW5kIGFueSBmdXJ0aGVyIHRyYW5zYWN0aW9ucyAocmVhZCBvciB3cml0ZSkgdW50aWwK KwkJICogdGhlIG5leHQgdmFsaWQgcmVhZCBvciB3cml0ZSBTdGFydCB0cmFuc2FjdGlvbiBpcyBy ZWNlaXZlZAorCQkgKi8KKwkJaWYgKCF2YWxpZGF0ZV9yZXF1ZXN0KHNzaWZfYm1jKSkKKwkJCXNz aWZfYm1jLT5hYm9ydGluZyA9IHRydWU7CisKKwkJaWYgKCFzc2lmX2JtYy0+YWJvcnRpbmcgJiYK KwkJICAgIChzc2lmX2JtYy0+c21idXNfY21kID09IFNTSUZfSVBNSV9TSU5HTEVQQVJUX1dSSVRF IHx8CisJCSAgICAgc3NpZl9ibWMtPnNtYnVzX2NtZCA9PSBTU0lGX0lQTUlfTVVMVElQQVJUX1dS SVRFX0VORCkpCisJCQloYW5kbGVfcmVxdWVzdChzc2lmX2JtYyk7CisJfQorCisJc3NpZl9ibWMt PnN0YXRlID0gU1NJRl9SRUFEWTsKKwkvKiBSZXNldCBtZXNzYWdlIGluZGV4ICovCisJc3NpZl9i bWMtPm1zZ19pZHggPSAwOworfQorCisvKgorICogQ2FsbGJhY2sgZnVuY3Rpb24gdG8gaGFuZGxl IEkyQyBzbGF2ZSBldmVudHMKKyAqLworc3RhdGljIGludCBzc2lmX2JtY19jYihzdHJ1Y3QgaTJj X2NsaWVudCAqY2xpZW50LCBlbnVtIGkyY19zbGF2ZV9ldmVudCBldmVudCwgdTggKnZhbCkKK3sK Kwl1bnNpZ25lZCBsb25nIGZsYWdzOworCXN0cnVjdCBzc2lmX2JtY19jdHggKnNzaWZfYm1jID0g aTJjX2dldF9jbGllbnRkYXRhKGNsaWVudCk7CisKKwlzcGluX2xvY2tfaXJxc2F2ZSgmc3NpZl9i bWMtPmxvY2ssIGZsYWdzKTsKKworCXN3aXRjaCAoZXZlbnQpIHsKKwljYXNlIEkyQ19TTEFWRV9S RUFEX1JFUVVFU1RFRDoKKwkJb25fcmVhZF9yZXF1ZXN0ZWRfZXZlbnQoc3NpZl9ibWMsIHZhbCk7 CisJCWJyZWFrOworCisJY2FzZSBJMkNfU0xBVkVfV1JJVEVfUkVRVUVTVEVEOgorCQlvbl93cml0 ZV9yZXF1ZXN0ZWRfZXZlbnQoc3NpZl9ibWMsIHZhbCk7CisJCWJyZWFrOworCisJY2FzZSBJMkNf U0xBVkVfUkVBRF9QUk9DRVNTRUQ6CisJCW9uX3JlYWRfcHJvY2Vzc2VkX2V2ZW50KHNzaWZfYm1j LCB2YWwpOworCQlicmVhazsKKworCWNhc2UgSTJDX1NMQVZFX1dSSVRFX1JFQ0VJVkVEOgorCQlv bl93cml0ZV9yZWNlaXZlZF9ldmVudChzc2lmX2JtYywgdmFsKTsKKwkJYnJlYWs7CisKKwljYXNl IEkyQ19TTEFWRV9TVE9QOgorCQlvbl9zdG9wX2V2ZW50KHNzaWZfYm1jLCB2YWwpOworCQlicmVh azsKKworCWRlZmF1bHQ6CisJCWRldl93YXJuKCZzc2lmX2JtYy0+Y2xpZW50LT5kZXYsICJXYXJu OiBVbmtub3duIGkyYyBzbGF2ZSBldmVudCwgYWJvcnRpbmcgLi4uXG4iKTsKKwkJc3NpZl9ibWMt PmFib3J0aW5nID0gdHJ1ZTsKKwkJYnJlYWs7CisJfQorCisJc3Bpbl91bmxvY2tfaXJxcmVzdG9y ZSgmc3NpZl9ibWMtPmxvY2ssIGZsYWdzKTsKKworCXJldHVybiAwOworfQorCitzdGF0aWMgaW50 IHNzaWZfYm1jX3Byb2JlKHN0cnVjdCBpMmNfY2xpZW50ICpjbGllbnQsIGNvbnN0IHN0cnVjdCBp MmNfZGV2aWNlX2lkICppZCkKK3sKKwlzdHJ1Y3Qgc3NpZl9ibWNfY3R4ICpzc2lmX2JtYzsKKwlp bnQgcmV0OworCisJc3NpZl9ibWMgPSBkZXZtX2t6YWxsb2MoJmNsaWVudC0+ZGV2LCBzaXplb2Yo KnNzaWZfYm1jKSwgR0ZQX0tFUk5FTCk7CisJaWYgKCFzc2lmX2JtYykKKwkJcmV0dXJuIC1FTk9N RU07CisKKwlzcGluX2xvY2tfaW5pdCgmc3NpZl9ibWMtPmxvY2spOworCisJaW5pdF93YWl0cXVl dWVfaGVhZCgmc3NpZl9ibWMtPndhaXRfcXVldWUpOworCXNzaWZfYm1jLT5yZXF1ZXN0X2F2YWls YWJsZSA9IGZhbHNlOworCXNzaWZfYm1jLT5yZXNwb25zZV9pbl9wcm9ncmVzcyA9IGZhbHNlOwor CisJLyogUmVnaXN0ZXIgbWlzYyBkZXZpY2UgaW50ZXJmYWNlICovCisJc3NpZl9ibWMtPm1pc2Nk ZXYubWlub3IgPSBNSVNDX0RZTkFNSUNfTUlOT1I7CisJc3NpZl9ibWMtPm1pc2NkZXYubmFtZSA9 IERFVklDRV9OQU1FOworCXNzaWZfYm1jLT5taXNjZGV2LmZvcHMgPSAmc3NpZl9ibWNfZm9wczsK Kwlzc2lmX2JtYy0+bWlzY2Rldi5wYXJlbnQgPSAmY2xpZW50LT5kZXY7CisJcmV0ID0gbWlzY19y ZWdpc3Rlcigmc3NpZl9ibWMtPm1pc2NkZXYpOworCWlmIChyZXQpCisJCWdvdG8gb3V0OworCisJ c3NpZl9ibWMtPmNsaWVudCA9IGNsaWVudDsKKwlzc2lmX2JtYy0+Y2xpZW50LT5mbGFncyB8PSBJ MkNfQ0xJRU5UX1NMQVZFOworCisJLyogUmVnaXN0ZXIgSTJDIHNsYXZlICovCisJaTJjX3NldF9j bGllbnRkYXRhKGNsaWVudCwgc3NpZl9ibWMpOworCXJldCA9IGkyY19zbGF2ZV9yZWdpc3Rlcihj bGllbnQsIHNzaWZfYm1jX2NiKTsKKwlpZiAocmV0KSB7CisJCW1pc2NfZGVyZWdpc3Rlcigmc3Np Zl9ibWMtPm1pc2NkZXYpOworCQlnb3RvIG91dDsKKwl9CisKKwlyZXR1cm4gMDsKK291dDoKKwlk ZXZtX2tmcmVlKCZjbGllbnQtPmRldiwgc3NpZl9ibWMpOworCXJldHVybiByZXQ7Cit9CisKK3N0 YXRpYyBpbnQgc3NpZl9ibWNfcmVtb3ZlKHN0cnVjdCBpMmNfY2xpZW50ICpjbGllbnQpCit7CisJ c3RydWN0IHNzaWZfYm1jX2N0eCAqc3NpZl9ibWMgPSBpMmNfZ2V0X2NsaWVudGRhdGEoY2xpZW50 KTsKKworCWkyY19zbGF2ZV91bnJlZ2lzdGVyKGNsaWVudCk7CisJbWlzY19kZXJlZ2lzdGVyKCZz c2lmX2JtYy0+bWlzY2Rldik7CisKKwlyZXR1cm4gMDsKK30KKworc3RhdGljIGNvbnN0IHN0cnVj dCBvZl9kZXZpY2VfaWQgc3NpZl9ibWNfbWF0Y2hbXSA9IHsKKwl7IC5jb21wYXRpYmxlID0gImFt cGVyZSxzc2lmLWJtYyIgfSwKKwl7IH0sCit9OworCitzdGF0aWMgY29uc3Qgc3RydWN0IGkyY19k ZXZpY2VfaWQgc3NpZl9ibWNfaWRbXSA9IHsKKwl7IERFVklDRV9OQU1FLCAwIH0sCisJeyB9LAor fTsKKworTU9EVUxFX0RFVklDRV9UQUJMRShpMmMsIHNzaWZfYm1jX2lkKTsKKworc3RhdGljIHN0 cnVjdCBpMmNfZHJpdmVyIHNzaWZfYm1jX2RyaXZlciA9IHsKKwkuZHJpdmVyICAgICAgICAgPSB7 CisJCS5uYW1lICAgICAgICAgICA9IERFVklDRV9OQU1FLAorCQkub2ZfbWF0Y2hfdGFibGUgPSBz c2lmX2JtY19tYXRjaCwKKwl9LAorCS5wcm9iZSAgICAgICAgICA9IHNzaWZfYm1jX3Byb2JlLAor CS5yZW1vdmUgICAgICAgICA9IHNzaWZfYm1jX3JlbW92ZSwKKwkuaWRfdGFibGUgICAgICAgPSBz c2lmX2JtY19pZCwKK307CisKK21vZHVsZV9pMmNfZHJpdmVyKHNzaWZfYm1jX2RyaXZlcik7CisK K01PRFVMRV9BVVRIT1IoIlF1YW4gTmd1eWVuIDxxdWFuQG9zLmFtcGVyZWNvbXB1dGluZy5jb20+ Iik7CitNT0RVTEVfQVVUSE9SKCJDaHVvbmcgVHJhbiA8Y2h1b25nQG9zLmFtcGVyZWNvbXB1dGlu Zy5jb20+Iik7CitNT0RVTEVfREVTQ1JJUFRJT04oIkxpbnV4IGRldmljZSBkcml2ZXIgb2YgdGhl IEJNQyBJUE1JIFNTSUYgaW50ZXJmYWNlLiIpOworTU9EVUxFX0xJQ0VOU0UoIkdQTCB2MiIpOwpk aWZmIC0tZ2l0IGEvZHJpdmVycy9jaGFyL2lwbWkvc3NpZl9ibWMuaCBiL2RyaXZlcnMvY2hhci9p cG1pL3NzaWZfYm1jLmgKbmV3IGZpbGUgbW9kZSAxMDA2NDQKaW5kZXggMDAwMDAwMDAwMDAwLi5i NjNlNDBhNGI5MDAKLS0tIC9kZXYvbnVsbAorKysgYi9kcml2ZXJzL2NoYXIvaXBtaS9zc2lmX2Jt Yy5oCkBAIC0wLDAgKzEsMTA2IEBACisvKiBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogR1BMLTIu MCsgKi8KKy8qCisgKiBUaGUgZHJpdmVyIGZvciBCTUMgc2lkZSBvZiBTU0lGIGludGVyZmFjZQor ICoKKyAqIENvcHlyaWdodCAoYykgMjAyMSwgQW1wZXJlIENvbXB1dGluZyBMTEMKKyAqCisgKiBU aGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTsgeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5k L29yCisgKiBtb2RpZnkgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJs aWMgTGljZW5zZSBhcworICogcHVibGlzaGVkIGJ5IHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRp b247IGVpdGhlciB2ZXJzaW9uIDIgb2YKKyAqIHRoZSBMaWNlbnNlLCBvciAoYXQgeW91ciBvcHRp b24pIGFueSBsYXRlciB2ZXJzaW9uLgorICoKKyAqIFRoaXMgcHJvZ3JhbSBpcyBkaXN0cmlidXRl ZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLAorICogYnV0IFdJVEhPVVQgQU5Z IFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2YKKyAqIE1FUkNI QU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGUK KyAqIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuCisgKgorICog WW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGlj IExpY2Vuc2UKKyAqIGFsb25nIHdpdGggdGhpcyBwcm9ncmFtLiAgSWYgbm90LCBzZWUgPGh0dHBz Oi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi4KKyAqLworI2lmbmRlZiBfX1NTSUZfQk1DX0hfXwor I2RlZmluZSBfX1NTSUZfQk1DX0hfXworCisjZGVmaW5lIERFVklDRV9OQU1FCQkJCSJpcG1pLXNz aWYtaG9zdCIKKworI2RlZmluZSBHRVRfOEJJVF9BRERSKGFkZHJfN2JpdCkJCSgoKGFkZHJfN2Jp dCkgPDwgMSkgJiAweGZmKQorCisvKiBBIHN0YW5kYXJkIFNNQnVzIFRyYW5zYWN0aW9uIGlzIGxp bWl0ZWQgdG8gMzIgZGF0YSBieXRlcyAqLworI2RlZmluZSBNQVhfUEFZTE9BRF9QRVJfVFJBTlNB Q1RJT04JCTMyCisKKyNkZWZpbmUgTUFYX0lQTUlfREFUQV9QRVJfU1RBUlRfVFJBTlNBQ1RJT04J MzAKKyNkZWZpbmUgTUFYX0lQTUlfREFUQV9QRVJfTUlERExFX1RSQU5TQUNUSU9OCTMxCisKKyNk ZWZpbmUgU1NJRl9JUE1JX1NJTkdMRVBBUlRfV1JJVEUJCTB4MgorI2RlZmluZSBTU0lGX0lQTUlf U0lOR0xFUEFSVF9SRUFECQkweDMKKyNkZWZpbmUgU1NJRl9JUE1JX01VTFRJUEFSVF9XUklURV9T VEFSVAkJMHg2CisjZGVmaW5lIFNTSUZfSVBNSV9NVUxUSVBBUlRfV1JJVEVfTUlERExFCTB4Nwor I2RlZmluZSBTU0lGX0lQTUlfTVVMVElQQVJUX1dSSVRFX0VORAkJMHg4CisjZGVmaW5lIFNTSUZf SVBNSV9NVUxUSVBBUlRfUkVBRF9TVEFSVAkJMHgzCisjZGVmaW5lIFNTSUZfSVBNSV9NVUxUSVBB UlRfUkVBRF9NSURETEUJCTB4OQorCisjZGVmaW5lIE1TR19QQVlMT0FEX0xFTl9NQVgJCQkyNTIK Kworc3RydWN0IHNzaWZfbXNnIHsKKwl1OCBsZW47CisJdTggbmV0Zm5fbHVuOworCXU4IGNtZDsK Kwl1OCBwYXlsb2FkW01TR19QQVlMT0FEX0xFTl9NQVhdOworfSBfX3BhY2tlZDsKKworc3RhdGlj IGlubGluZSB1MzIgc3NpZl9tc2dfbGVuKHN0cnVjdCBzc2lmX21zZyAqc3NpZl9tc2cpCit7CisJ cmV0dXJuIHNzaWZfbXNnLT5sZW4gKyAxOworfQorCisvKgorICogU1NJRiBpbnRlcm5hbCBzdGF0 ZXM6CisgKiAgIFNTSUZfUkVBRFkgICAgICAgICAweDAwIDogUmVhZHkgc3RhdGUKKyAqICAgU1NJ Rl9TVEFSVCAgICAgICAgIDB4MDEgOiBTdGFydCBzbWJ1cyB0cmFuc2FjdGlvbgorICogICBTU0lG X1NNQlVTX0NNRCAgICAgMHgwMiA6IFJlY2VpdmVkIFNNQnVzIGNvbW1hbmQKKyAqICAgU1NJRl9S RVFfUkVDVklORyAgIDB4MDMgOiBSZWNlaXZpbmcgcmVxdWVzdAorICogICBTU0lGX1JFU19TRU5E SU5HICAgMHgwNCA6IFNlbmRpbmcgcmVzcG9uc2UKKyAqICAgU1NJRl9CQURfU01CVVMgICAgIDB4 MDUgOiBCYWQgU01idXMgdHJhbnNhY3Rpb24KKyAqLworZW51bSBzc2lmX3N0YXRlIHsKKwlTU0lG X1JFQURZLAorCVNTSUZfU1RBUlQsCisJU1NJRl9TTUJVU19DTUQsCisJU1NJRl9SRVFfUkVDVklO RywKKwlTU0lGX1JFU19TRU5ESU5HLAorCVNTSUZfQkFEX1NNQlVTLAorCVNTSUZfU1RBVEVfTUFY Cit9OworCitzdHJ1Y3Qgc3NpZl9ibWNfY3R4IHsKKwlzdHJ1Y3QgaTJjX2NsaWVudAkqY2xpZW50 OworCXN0cnVjdCBtaXNjZGV2aWNlCW1pc2NkZXY7CisJc2l6ZV90CQkJbXNnX2lkeDsKKwlib29s CQkJcGVjX3N1cHBvcnQ7CisJLyogc3NpZiBibWMgc3BpbmxvY2sgKi8KKwlzcGlubG9ja190CQls b2NrOworCXdhaXRfcXVldWVfaGVhZF90CXdhaXRfcXVldWU7CisJdTgJCQlydW5uaW5nOworCWVu dW0gc3NpZl9zdGF0ZQkJc3RhdGU7CisJdTgJCQlzbWJ1c19jbWQ7CisJLyogRmxhZyB0byBhYm9y dCBjdXJyZW50IHByb2Nlc3MgKi8KKwlib29sCQkJYWJvcnRpbmc7CisJLyogRmxhZyB0byBpZGVu dGlmeSBhIE11bHRpLXBhcnQgUmVhZCBUcmFuc2FjdGlvbiAqLworCWJvb2wJCQlpc19zaW5nbGVw YXJ0X3JlYWQ7CisJdTgJCQluYnl0ZXNfcHJvY2Vzc2VkOworCXU4CQkJcmVtYWluX2xlbjsKKwl1 OAkJCXJlY3ZfbGVuOworCS8qIEJsb2NrIE51bWJlciBvZiBhIE11bHRpLXBhcnQgUmVhZCBUcmFu c2FjdGlvbiAqLworCXU4CQkJYmxvY2tfbnVtOworCWJvb2wJCQlyZXF1ZXN0X2F2YWlsYWJsZTsK Kwlib29sCQkJcmVzcG9uc2VfaW5fcHJvZ3Jlc3M7CisJLyogUmVzcG9uc2UgYnVmZmVyIGZvciBN dWx0aS1wYXJ0IFJlYWQgVHJhbnNhY3Rpb24gKi8KKwl1OAkJCXJlc3BvbnNlX2J1ZltNQVhfUEFZ TE9BRF9QRVJfVFJBTlNBQ1RJT05dOworCXN0cnVjdCBzc2lmX21zZwkJcmVzcG9uc2U7CisJc3Ry dWN0IHNzaWZfbXNnCQlyZXF1ZXN0OworfTsKKworc3RhdGljIGlubGluZSBzdHJ1Y3Qgc3NpZl9i bWNfY3R4ICp0b19zc2lmX2JtYyhzdHJ1Y3QgZmlsZSAqZmlsZSkKK3sKKwlyZXR1cm4gY29udGFp bmVyX29mKGZpbGUtPnByaXZhdGVfZGF0YSwgc3RydWN0IHNzaWZfYm1jX2N0eCwgbWlzY2Rldik7 Cit9CisjZW5kaWYgLyogX19TU0lGX0JNQ19IX18gKi8KLS0gCjIuMjguMAoKCl9fX19fX19fX19f X19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fCmxpbnV4LWFybS1rZXJuZWwgbWFp bGluZyBsaXN0CmxpbnV4LWFybS1rZXJuZWxAbGlzdHMuaW5mcmFkZWFkLm9yZwpodHRwOi8vbGlz dHMuaW5mcmFkZWFkLm9yZy9tYWlsbWFuL2xpc3RpbmZvL2xpbnV4LWFybS1rZXJuZWwK