From mboxrd@z Thu Jan 1 00:00:00 1970 From: Quan Nguyen Date: Thu, 10 Mar 2022 18:41:16 +0700 Subject: [PATCH v6 1/4] ipmi: ssif_bmc: Add SSIF BMC driver In-Reply-To: <20220310114119.13736-1-quan@os.amperecomputing.com> References: <20220310114119.13736-1-quan@os.amperecomputing.com> Message-ID: <20220310114119.13736-2-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 --- v6: + Drop the use of slave_enable() [Wolfram] + Make i2c-aspeed to issue RxCmdLast command on all I2C_SLAVE_WRITE_REQUESTED event to assert NAK when slave busy [Quan] + Make i2c slave to return -EBUSY when it's busy [Quan] + Drop the aborting feature as return Completion Code 0xFF may stop host to retry and make ipmi_ssif.so fails to load [Quan] + Add timer to recover slave from busy state when no response [Quan] + Clean request/response buffer appropriately [Quan] + Add some minor change on error and warning messages [Quan] 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() and 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 | 791 +++++++++++++++++++++++++++++++++++ drivers/char/ipmi/ssif_bmc.h | 102 +++++ 4 files changed, 905 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 b061e6b513ed..18a89093d64e 100644 --- a/drivers/char/ipmi/Kconfig +++ b/drivers/char/ipmi/Kconfig @@ -169,6 +169,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 7ce790efad92..cb6138b8ded9 100644 --- a/drivers/char/ipmi/Makefile +++ b/drivers/char/ipmi/Makefile @@ -30,3 +30,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..62db97773654 --- /dev/null +++ b/drivers/char/ipmi/ssif_bmc.c @@ -0,0 +1,791 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * The driver for BMC side of SSIF interface + * + * Copyright (c) 2022, Ampere Computing LLC + * + */ + +#include +#include +#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; + + /* ssif_bmc not busy */ + ssif_bmc->busy = false; + + if (ssif_bmc->response_timer_inited) { + del_timer(&ssif_bmc->response_timer); + ssif_bmc->response_timer_inited = false; + } + /* Clean old request buffer */ + memset(&ssif_bmc->request, 0, sizeof(struct ssif_msg)); + + spin_unlock_irqrestore(&ssif_bmc->lock, flags); + + return 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; + ssif_bmc->busy = false; + memset(&ssif_bmc->response_buf, 0, MAX_PAYLOAD_PER_TRANSACTION); + wake_up_all(&ssif_bmc->wait_queue); +} + +static void response_timeout(struct timer_list *t) +{ + struct ssif_bmc_ctx *ssif_bmc = from_timer(ssif_bmc, t, response_timer); + unsigned long flags; + + spin_lock_irqsave(&ssif_bmc->lock, flags); + + /* Recover ssif_bmc from busy */ + ssif_bmc->busy = false; + del_timer(&ssif_bmc->response_timer); + ssif_bmc->response_timer_inited = false; + + spin_unlock_irqrestore(&ssif_bmc->lock, flags); +} + +/* Called with ssif_bmc->lock held. */ +static void handle_request(struct ssif_bmc_ctx *ssif_bmc) +{ + /* set ssif_bmc to busy waiting for response */ + ssif_bmc->busy = true; + + /* Request message is available to process */ + ssif_bmc->request_available = true; + + /* Clean old response buffer */ + memset(&ssif_bmc->response, 0, sizeof(struct ssif_msg)); + + /* This is the new READ request.*/ + wake_up_all(&ssif_bmc->wait_queue); + + /* Armed timer to recover slave from busy state in case of no response */ + if (!ssif_bmc->response_timer_inited) { + timer_setup(&ssif_bmc->response_timer, response_timeout, 0); + ssif_bmc->response_timer_inited = true; + } + mod_timer(&ssif_bmc->response_timer, jiffies + msecs_to_jiffies(RESPONSE_TIMEOUT)); +} + +static void set_multipart_response_buffer(struct ssif_bmc_ctx *ssif_bmc, u8 *val) +{ + u8 response_len = 0; + int idx = 0; + u8 data_len; + + data_len = ssif_bmc->response.len; + switch (ssif_bmc->smbus_cmd) { + case SSIF_IPMI_MULTIPART_READ_START: + /* + * Read Start length is 32 bytes. + * Read Start transfer first 30 bytes of IPMI response + * and 2 special code 0x00, 0x01. + */ + *val = MAX_PAYLOAD_PER_TRANSACTION; + ssif_bmc->remain_len = data_len - MAX_IPMI_DATA_PER_START_TRANSACTION; + ssif_bmc->block_num = 0; + + ssif_bmc->response_buf[idx++] = 0x00; /* Start Flag */ + ssif_bmc->response_buf[idx++] = 0x01; /* Start Flag */ + ssif_bmc->response_buf[idx++] = ssif_bmc->response.netfn_lun; + ssif_bmc->response_buf[idx++] = ssif_bmc->response.cmd; + ssif_bmc->response_buf[idx++] = ssif_bmc->response.payload[0]; + + response_len = MAX_PAYLOAD_PER_TRANSACTION - idx; + + memcpy(&ssif_bmc->response_buf[idx], &ssif_bmc->response.payload[1], + response_len); + break; + + case SSIF_IPMI_MULTIPART_READ_MIDDLE: + /* + * IPMI READ Middle or READ End messages can carry up to 31 bytes + * IPMI data plus block number byte. + */ + if (ssif_bmc->remain_len < MAX_IPMI_DATA_PER_MIDDLE_TRANSACTION) { + /* + * This is READ End message + * Return length is the remaining response data length + * plus block number + * Block number 0xFF is to indicate this is last message + * + */ + *val = ssif_bmc->remain_len + 1; + ssif_bmc->block_num = 0xFF; + ssif_bmc->response_buf[idx++] = ssif_bmc->block_num; + response_len = ssif_bmc->remain_len; + /* Clean the buffer */ + memset(&ssif_bmc->response_buf[idx], 0, MAX_PAYLOAD_PER_TRANSACTION - idx); + } else { + /* + * This is READ Middle message + * Response length is the maximum SMBUS transfer length + * Block number byte is incremented + * Return length is maximum SMBUS transfer length + */ + *val = MAX_PAYLOAD_PER_TRANSACTION; + ssif_bmc->remain_len -= MAX_IPMI_DATA_PER_MIDDLE_TRANSACTION; + response_len = MAX_IPMI_DATA_PER_MIDDLE_TRANSACTION; + ssif_bmc->response_buf[idx++] = ssif_bmc->block_num; + ssif_bmc->block_num++; + } + + memcpy(&ssif_bmc->response_buf[idx], + ssif_bmc->response.payload + 1 + ssif_bmc->nbytes_processed, + response_len); + break; + + default: + /* Do not expect to go to this case */ + dev_err(&ssif_bmc->client->dev, + "%s: Unexpected SMBus command 0x%x\n", + __func__, ssif_bmc->smbus_cmd); + break; + } + + ssif_bmc->nbytes_processed += response_len; +} + +/* Process the IPMI response that will be read by master */ +static void handle_read_processed(struct ssif_bmc_ctx *ssif_bmc, u8 *val) +{ + u8 *buf; + u8 pec_len, addr, len; + u8 pec = 0; + + pec_len = ssif_bmc->pec_support ? 1 : 0; + /* PEC - Start Read Address */ + addr = GET_8BIT_ADDR(ssif_bmc->client->addr); + pec = i2c_smbus_pec(pec, &addr, 1); + /* PEC - SSIF Command */ + pec = i2c_smbus_pec(pec, &ssif_bmc->smbus_cmd, 1); + /* PEC - Restart Write Address */ + addr = addr | 0x01; + pec = i2c_smbus_pec(pec, &addr, 1); + + if (ssif_bmc->is_singlepart_read) { + /* Single-part Read processing */ + buf = (u8 *)&ssif_bmc->response; + + if (ssif_bmc->response.len && ssif_bmc->msg_idx < ssif_bmc->response.len) { + ssif_bmc->msg_idx++; + *val = buf[ssif_bmc->msg_idx]; + } else if (ssif_bmc->response.len && ssif_bmc->msg_idx == ssif_bmc->response.len) { + ssif_bmc->msg_idx++; + *val = i2c_smbus_pec(pec, buf, ssif_msg_len(&ssif_bmc->response)); + } else { + *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\n", + __func__, ssif_bmc->smbus_cmd); + break; + } + + len = (ssif_bmc->block_num == 0xFF) ? + ssif_bmc->remain_len + 1 : MAX_PAYLOAD_PER_TRANSACTION; + if (ssif_bmc->msg_idx == (len + 1)) { + pec = i2c_smbus_pec(pec, &len, 1); + *val = i2c_smbus_pec(pec, ssif_bmc->response_buf, len); + } + /* Invalidate response buffer to denote last response is sent */ + if (ssif_bmc->block_num == 0xFF && + ssif_bmc->msg_idx > (ssif_bmc->remain_len + pec_len)) { + complete_response(ssif_bmc); + } + } +} + +static void handle_write_received(struct ssif_bmc_ctx *ssif_bmc, u8 *val) +{ + u8 *buf = (u8 *)&ssif_bmc->request; + + if (ssif_bmc->msg_idx >= sizeof(struct ssif_msg)) + return; + + 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"); + + fallthrough; + case SSIF_IPMI_MULTIPART_WRITE_END: + /* Multi-part write, 2nd byte received is length */ + if (ssif_bmc->msg_idx == 1) { + if (*val > MAX_PAYLOAD_PER_TRANSACTION) + dev_warn(&ssif_bmc->client->dev, + "Warn: Invalid Multipart Write End len"); + + ssif_bmc->request.len += *val; + ssif_bmc->recv_len = *val; + + /* request len should never exceeded 255 bytes */ + if (ssif_bmc->request.len > 255) + dev_warn(&ssif_bmc->client->dev, + "Warn: Invalid request len"); + + } else { + 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\n", + __func__, ssif_bmc->smbus_cmd); + break; + } +} + +static bool validate_request(struct ssif_bmc_ctx *ssif_bmc) +{ + u8 rpec = 0, cpec = 0; + bool ret = true; + u8 addr, index; + u8 *buf; + + 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\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"); + + if (*val == SSIF_IPMI_SINGLEPART_WRITE || + *val == SSIF_IPMI_MULTIPART_WRITE_START) { + /* + * The response maybe not come in-time, causing host SSIF driver + * to timeout and resend a new request. In such case check for + * pending response and clear it + */ + if (ssif_bmc->response_in_progress) + complete_response(ssif_bmc); + } +} + +static void on_read_requested_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) +{ + if (ssif_bmc->state == SSIF_READY || + ssif_bmc->state == SSIF_START || + ssif_bmc->state == SSIF_REQ_RECVING || + ssif_bmc->state == SSIF_RES_SENDING) { + ssif_bmc->state = SSIF_BAD_SMBUS; + dev_warn(&ssif_bmc->client->dev, + "Warn: %s unexpected READ REQUESTED in state=%s\n", + __func__, state_to_string(ssif_bmc->state)); + + } else if (ssif_bmc->state == SSIF_SMBUS_CMD) { + ssif_bmc->state = SSIF_RES_SENDING; + } + + ssif_bmc->msg_idx = 0; + if (ssif_bmc->is_singlepart_read) + *val = ssif_bmc->response.len; + else + set_multipart_response_buffer(ssif_bmc, val); +} + +static void on_read_processed_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) +{ + if (ssif_bmc->state == SSIF_READY || + ssif_bmc->state == SSIF_START || + ssif_bmc->state == SSIF_REQ_RECVING || + ssif_bmc->state == SSIF_SMBUS_CMD) { + dev_warn(&ssif_bmc->client->dev, + "Warn: %s unexpected READ PROCESSED in state=%s\n", + __func__, state_to_string(ssif_bmc->state)); + ssif_bmc->state = SSIF_BAD_SMBUS; + } + + handle_read_processed(ssif_bmc, val); +} + +static void on_write_requested_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) +{ + ssif_bmc->msg_idx = 0; + + if (ssif_bmc->state == SSIF_READY || ssif_bmc->state == SSIF_SMBUS_CMD) { + ssif_bmc->state = SSIF_START; + + } else if (ssif_bmc->state == SSIF_START || + ssif_bmc->state == SSIF_REQ_RECVING || + ssif_bmc->state == SSIF_RES_SENDING) { + dev_warn(&ssif_bmc->client->dev, + "Warn: %s unexpected WRITE REQUEST in state=%s\n", + __func__, state_to_string(ssif_bmc->state)); + ssif_bmc->state = SSIF_BAD_SMBUS; + } +} + +static void on_write_received_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) +{ + if (ssif_bmc->state == SSIF_READY || ssif_bmc->state == SSIF_RES_SENDING) { + dev_warn(&ssif_bmc->client->dev, + "Warn: %s unexpected WRITE RECEIVED in state=%s\n", + __func__, state_to_string(ssif_bmc->state)); + ssif_bmc->state = SSIF_BAD_SMBUS; + } else if (ssif_bmc->state == SSIF_START) { + ssif_bmc->state = SSIF_SMBUS_CMD; + } else if (ssif_bmc->state == SSIF_SMBUS_CMD) { + ssif_bmc->state = SSIF_REQ_RECVING; + } + + /* This is response sending state */ + if (ssif_bmc->state == SSIF_REQ_RECVING) + handle_write_received(ssif_bmc, val); + else if (ssif_bmc->state == SSIF_SMBUS_CMD) + process_smbus_cmd(ssif_bmc, val); +} + +static void on_stop_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) +{ + if (ssif_bmc->state == SSIF_READY || + ssif_bmc->state == SSIF_START || + ssif_bmc->state == SSIF_SMBUS_CMD) { + dev_warn(&ssif_bmc->client->dev, + "Warn: %s unexpected SLAVE STOP in state=%s\n", + __func__, state_to_string(ssif_bmc->state)); + + } else if (ssif_bmc->state == SSIF_BAD_SMBUS) { + dev_warn(&ssif_bmc->client->dev, + "Warn: %s received SLAVE STOP from bad state=%s\n", + __func__, state_to_string(ssif_bmc->state)); + + } else if (ssif_bmc->state == SSIF_REQ_RECVING) { + /* A BMC that receives an invalid request drop the data for the write + * transaction and any further transactions (read or write) until + * the next valid read or write Start transaction is received + */ + if (!validate_request(ssif_bmc)) + dev_err(&ssif_bmc->client->dev, "Error: invalid pec\n"); + else if (ssif_bmc->smbus_cmd == SSIF_IPMI_SINGLEPART_WRITE || + ssif_bmc->smbus_cmd == SSIF_IPMI_MULTIPART_WRITE_END) + handle_request(ssif_bmc); + } + + ssif_bmc->state = SSIF_READY; + /* Reset message index */ + ssif_bmc->msg_idx = 0; +} + +/* + * Callback function to handle I2C slave events + */ +static int ssif_bmc_cb(struct i2c_client *client, enum i2c_slave_event event, u8 *val) +{ + unsigned long flags; + struct ssif_bmc_ctx *ssif_bmc = i2c_get_clientdata(client); + int ret = 0; + + spin_lock_irqsave(&ssif_bmc->lock, flags); + + switch (event) { + case I2C_SLAVE_READ_REQUESTED: + on_read_requested_event(ssif_bmc, val); + break; + + case I2C_SLAVE_WRITE_REQUESTED: + on_write_requested_event(ssif_bmc, val); + break; + + case I2C_SLAVE_READ_PROCESSED: + on_read_processed_event(ssif_bmc, val); + break; + + case I2C_SLAVE_WRITE_RECEIVED: + on_write_received_event(ssif_bmc, val); + break; + + case I2C_SLAVE_STOP: + on_stop_event(ssif_bmc, val); + break; + + default: + dev_warn(&ssif_bmc->client->dev, "Warn: Unknown i2c slave event\n"); + break; + } + + if (ssif_bmc->busy) + ret = -EBUSY; + + spin_unlock_irqrestore(&ssif_bmc->lock, flags); + + return ret; +} + +static int ssif_bmc_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + struct ssif_bmc_ctx *ssif_bmc; + int ret; + + ssif_bmc = devm_kzalloc(&client->dev, sizeof(*ssif_bmc), GFP_KERNEL); + if (!ssif_bmc) + return -ENOMEM; + + spin_lock_init(&ssif_bmc->lock); + + init_waitqueue_head(&ssif_bmc->wait_queue); + ssif_bmc->request_available = false; + ssif_bmc->response_in_progress = false; + ssif_bmc->busy = false; + ssif_bmc->response_timer_inited = false; + + /* Register misc device interface */ + ssif_bmc->miscdev.minor = MISC_DYNAMIC_MINOR; + ssif_bmc->miscdev.name = DEVICE_NAME; + ssif_bmc->miscdev.fops = &ssif_bmc_fops; + ssif_bmc->miscdev.parent = &client->dev; + ret = misc_register(&ssif_bmc->miscdev); + if (ret) + goto out; + + ssif_bmc->client = client; + ssif_bmc->client->flags |= I2C_CLIENT_SLAVE; + + /* Register I2C slave */ + i2c_set_clientdata(client, ssif_bmc); + ret = i2c_slave_register(client, ssif_bmc_cb); + if (ret) { + misc_deregister(&ssif_bmc->miscdev); + goto out; + } + + return 0; +out: + devm_kfree(&client->dev, ssif_bmc); + return ret; +} + +static int ssif_bmc_remove(struct i2c_client *client) +{ + struct ssif_bmc_ctx *ssif_bmc = i2c_get_clientdata(client); + + i2c_slave_unregister(client); + misc_deregister(&ssif_bmc->miscdev); + + return 0; +} + +static const struct of_device_id ssif_bmc_match[] = { + { .compatible = "ampere,ssif-bmc" }, + { }, +}; + +static const struct i2c_device_id ssif_bmc_id[] = { + { DEVICE_NAME, 0 }, + { }, +}; + +MODULE_DEVICE_TABLE(i2c, ssif_bmc_id); + +static struct i2c_driver ssif_bmc_driver = { + .driver = { + .name = DEVICE_NAME, + .of_match_table = ssif_bmc_match, + }, + .probe = ssif_bmc_probe, + .remove = ssif_bmc_remove, + .id_table = ssif_bmc_id, +}; + +module_i2c_driver(ssif_bmc_driver); + +MODULE_AUTHOR("Quan Nguyen "); +MODULE_AUTHOR("Chuong Tran "); +MODULE_DESCRIPTION("Linux device driver of the BMC IPMI SSIF interface."); +MODULE_LICENSE("GPL"); diff --git a/drivers/char/ipmi/ssif_bmc.h b/drivers/char/ipmi/ssif_bmc.h new file mode 100644 index 000000000000..9a26f3c252cc --- /dev/null +++ b/drivers/char/ipmi/ssif_bmc.h @@ -0,0 +1,102 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * The driver for BMC side of SSIF interface + * + * Copyright (c) 2022, Ampere Computing LLC + * + */ +#ifndef __SSIF_BMC_H__ +#define __SSIF_BMC_H__ + +#define DEVICE_NAME "ipmi-ssif-host" + +#define GET_8BIT_ADDR(addr_7bit) (((addr_7bit) << 1) & 0xff) + +/* A standard SMBus Transaction is limited to 32 data bytes */ +#define MAX_PAYLOAD_PER_TRANSACTION 32 + +#define MAX_IPMI_DATA_PER_START_TRANSACTION 30 +#define MAX_IPMI_DATA_PER_MIDDLE_TRANSACTION 31 + +#define SSIF_IPMI_SINGLEPART_WRITE 0x2 +#define SSIF_IPMI_SINGLEPART_READ 0x3 +#define SSIF_IPMI_MULTIPART_WRITE_START 0x6 +#define SSIF_IPMI_MULTIPART_WRITE_MIDDLE 0x7 +#define SSIF_IPMI_MULTIPART_WRITE_END 0x8 +#define SSIF_IPMI_MULTIPART_READ_START 0x3 +#define SSIF_IPMI_MULTIPART_READ_MIDDLE 0x9 + +#define MSG_PAYLOAD_LEN_MAX 252 +/* + * IPMI 2.0 Spec, section 12.7 SSIF Timing, + * Request-to-Response Time is T6max(250ms) - T1max(20ms) - 3ms = 227ms + * Recover ssif_bmc from busy state if it takes upto 500ms + */ +#define RESPONSE_TIMEOUT 500 /* ms */ + +struct ssif_msg { + u8 len; + u8 netfn_lun; + u8 cmd; + u8 payload[MSG_PAYLOAD_LEN_MAX]; +} __packed; + +static inline u32 ssif_msg_len(struct ssif_msg *ssif_msg) +{ + return ssif_msg->len + 1; +} + +/* + * SSIF internal states: + * SSIF_READY 0x00 : Ready state + * SSIF_START 0x01 : Start smbus transaction + * SSIF_SMBUS_CMD 0x02 : Received SMBus command + * SSIF_REQ_RECVING 0x03 : Receiving request + * SSIF_RES_SENDING 0x04 : Sending response + * SSIF_BAD_SMBUS 0x05 : Bad SMbus transaction + */ +enum ssif_state { + SSIF_READY, + SSIF_START, + SSIF_SMBUS_CMD, + SSIF_REQ_RECVING, + SSIF_RES_SENDING, + SSIF_BAD_SMBUS, + SSIF_STATE_MAX +}; + +struct ssif_bmc_ctx { + struct i2c_client *client; + struct miscdevice miscdev; + size_t msg_idx; + bool pec_support; + /* ssif bmc spinlock */ + spinlock_t lock; + wait_queue_head_t wait_queue; + u8 running; + enum ssif_state state; + u8 smbus_cmd; + /* Timeout waiting for response */ + struct timer_list response_timer; + bool response_timer_inited; + /* Flag to identify a Multi-part Read Transaction */ + bool is_singlepart_read; + u8 nbytes_processed; + u8 remain_len; + u8 recv_len; + /* Block Number of a Multi-part Read Transaction */ + u8 block_num; + bool request_available; + bool response_in_progress; + bool busy; + /* Response buffer for Multi-part Read Transaction */ + u8 response_buf[MAX_PAYLOAD_PER_TRANSACTION]; + struct ssif_msg response; + struct ssif_msg request; +}; + +static inline struct ssif_bmc_ctx *to_ssif_bmc(struct file *file) +{ + return container_of(file->private_data, struct ssif_bmc_ctx, miscdev); +} +#endif /* __SSIF_BMC_H__ */ -- 2.35.1 From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id DF4C8C433FE for ; Thu, 10 Mar 2022 11:42:01 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235645AbiCJLnA (ORCPT ); Thu, 10 Mar 2022 06:43:00 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40888 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S241717AbiCJLm6 (ORCPT ); Thu, 10 Mar 2022 06:42:58 -0500 Received: from NAM12-DM6-obe.outbound.protection.outlook.com (mail-dm6nam12on2095.outbound.protection.outlook.com [40.107.243.95]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7C8E9144F6C; Thu, 10 Mar 2022 03:41:56 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=WRyXzHGISb5JubypSkWIG+zUQh35HjXVewRmBNBM2UbOYhG1wWFp0MVIs6evNz3WVpwljJXSwL2G7FI6W/u5uDTxJJWcj0yrIZyOwkrYiFOAsfKg0qNCqA1BSdI7Y+kcYCFOyQvgm0H7ZqZGSp743/Zo9vDgOHp3HUe1dJlqPcn+KUEz5TZQPcvf9yUXJpJljKTKo2aAuSE1OkYvfBTDfM3vGjkmyKoaC65MaEDB3xqF6F173dYqJPzphq+k6PUbYOLHiFGMCzEL0D8KtSLBUWoPeymxc5F/Lnwft8RWNKoU6mqXQKw9Dea79BwmVnO0NXlcG986gXyzqSgg6uwMpw== 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-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=JvWm84ASHNFLEyrKTTKG6qYhEcrD9hzNbMGXYtBKHXY=; b=ci+ZGQBhuFhSRop1mNKSZdhVq3ND19nB4IOEZP4ogzoYohEQbzWA/hDB9N3nt8Yv6nL41/RbWIbvyWfM/8/iI6j9pKOWu3LgVsU92Z3KqvWsiPbs+z/MwcG4w8bOus+sg81xAqjDb2SRi1Qj9QDF/GgawWvQFRMbvlkmzY/B54S4znN/b91bi79sQBK5Fu8kx3DOBuWaIDGKkRM4KF7htf3ntXiZjjC8ESmuUjzL30hCB+7/arwZUkMiUxo84hAomRNrpMWa8BkgrAz90RTPUW6LPtpSiaF/pDn1wrzE0xj6ZRqjEgjv62C/Ax/FtHjabjVcvWJ29i5qWeD92CTACA== 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=JvWm84ASHNFLEyrKTTKG6qYhEcrD9hzNbMGXYtBKHXY=; b=Kx4Vhc6Xf3wfjdbaFghQDyiCC1PqAmNdrhMBOqUhxaij+yHGV7siHt5l1zndMX5QQbFBdXGPJa+L7OxXJosvQhyoZwbP6IWeBeTwWK5RAWfGRg2Lwc9gAyDOXBTAL0+9FzDdfJvgfN9IzhAtrMopM6IpHf2Qu8rEVqgKFguwq0U= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=os.amperecomputing.com; Received: from SJ0PR01MB7282.prod.exchangelabs.com (2603:10b6:a03:3f2::24) by BL0PR01MB4305.prod.exchangelabs.com (2603:10b6:208:4d::23) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5061.22; Thu, 10 Mar 2022 11:41:53 +0000 Received: from SJ0PR01MB7282.prod.exchangelabs.com ([fe80::cd24:39ed:7042:46d6]) by SJ0PR01MB7282.prod.exchangelabs.com ([fe80::cd24:39ed:7042:46d6%6]) with mapi id 15.20.5038.027; Thu, 10 Mar 2022 11:41:53 +0000 From: Quan Nguyen To: Corey Minyard , Rob Herring , Krzysztof Kozlowski , Joel Stanley , Andrew Jeffery , Brendan Higgins , Benjamin Herrenschmidt , Wolfram Sang , openipmi-developer@lists.sourceforge.net, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-aspeed@lists.ozlabs.org, linux-kernel@vger.kernel.org, linux-i2c@vger.kernel.org, openbmc@lists.ozlabs.org Cc: Open Source Submission , Phong Vo , "Thang Q . Nguyen" Subject: [PATCH v6 1/4] ipmi: ssif_bmc: Add SSIF BMC driver Date: Thu, 10 Mar 2022 18:41:16 +0700 Message-Id: <20220310114119.13736-2-quan@os.amperecomputing.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220310114119.13736-1-quan@os.amperecomputing.com> References: <20220310114119.13736-1-quan@os.amperecomputing.com> Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-ClientProxiedBy: SG2PR02CA0125.apcprd02.prod.outlook.com (2603:1096:4:188::13) To SJ0PR01MB7282.prod.exchangelabs.com (2603:10b6:a03:3f2::24) MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: e8a3997a-4e52-4386-d092-08da028af8ea X-MS-TrafficTypeDiagnostic: BL0PR01MB4305:EE_ X-Microsoft-Antispam-PRVS: X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: HhA7CxIx1n72js7q2HTjxU4uJOF48oZ+ur6WLYMTRAQGPtRUS5G2bXfnOBWAGvPSUeY9kA8ahdnRvd1kcf/EbCnX89LziCaavrHcb8gmnlMDWUSeQmnFmG1fa6FD5S11xeJBkS2sG8SV4VsWKiOE8RBb8AoGpeU5sDXUpZPJvyAUDTeW+/iVqjFLqtGmsubPP3pN8y7blFYlbVK+L4Ys/DT5lT2zVgV3VGiL4omlyAOCC2zEk2QgUpcQKGeMyWxtqWDnNuIT6mvZ7fOTLgLK60Vd0usHA9VgDeyecMbEMch2KK10tWcl+7UQVPGXDKJXoM5GVNHHqIQms3c2i7WggywYyV6jcen37nVRHzfppLI3q7nCDoMcXyuzUdFF5XSRsGLB5mbGlSw5/zEkbXpgRnc7ZbRIsVKKTOqal4Ith3Z30rEwMd2Ol5agOvbOeSCt2XKJxLctT+0MgyUkKeeUu52SGMvLmPMzCpbb+B+FCa4CtGSkDTXBKywCRCduKJC9PFX9JDzxhhjpl4VwPF1M1d61BfKo2Y3oTXZByANBMRBtnZr9Zaq1hTR1WXP13Ui3Osl0+XlsRE1C+JuAEqQyweLDxtTyA+11/xTLLbToza7NKB1JXzXxPFeStiioCgW7kzxtTQ5UIUd6/r1kpGqJnA7jzWVvFymsKPr8CMb9nbyRAHWJ9+L2XBP6LLH9ieZKow1/QtIsBnnTiVueZ1ynt1/JIUVElSSXhmqsVwvGViM= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:SJ0PR01MB7282.prod.exchangelabs.com;PTR:;CAT:NONE;SFS:(13230001)(4636009)(366004)(107886003)(6666004)(66556008)(66476007)(66946007)(30864003)(1076003)(5660300002)(2616005)(7416002)(316002)(38350700002)(38100700002)(86362001)(4326008)(8676002)(8936002)(83380400001)(26005)(186003)(921005)(2906002)(52116002)(6512007)(508600001)(110136005)(6506007)(6486002)(54906003);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?YVBvcDZBdXlLV3lVZi94ZFJIQjBCcXNJcDdNMTRMdmYwZ3YyTkZvTmhKU2Rv?= =?utf-8?B?SnlyRSsvaDNQaTVRRkxrWnpaZlRsVENrdFR6Um9aMzV3M0NONDAvb0VMaERq?= =?utf-8?B?U3ZIcWI0V0MydGY0aE9iZjRTa1loWW80NU94WmwySlZOOGxNNVEyTE50VFpE?= =?utf-8?B?VGxrUk9YTjdSemJ0VDhubDJnRjdwdVJuM29hTHJvZzd2T2ZuL1diL0tLQjls?= =?utf-8?B?Zit5bUw5UHBQSHlycVZDbEo4SVdCRFdzZU96STVVcUV2V1FpNm1RbWNya01T?= =?utf-8?B?ajc4dkdIQW1oUmNQelczZytFNlp1UDZJNExzSUUybFJiTnh1RCtmYWxnR1Ey?= =?utf-8?B?Zm9EbENEem85SjlPdWR6c0FSdC9GY2dXM2d4L3ZyQ1JIaUVIYWYrNWsyRGFR?= =?utf-8?B?TXlxYk1EcTR1dzZRcWNLY0FVY0pmWXQyUFRwMUhwU0pTRGpNTjB4ZUZ3Snht?= =?utf-8?B?YUpqU1ZGeHg5V2dkMHRveFR0aXcxa0c1VEFPRVY0MzFlenRLQlBMbThWalVE?= =?utf-8?B?dGR2R2ZZeUh0Z2RIcnJvZDZDVEVNQmdZdFRERHhuZ1N0cVd1NWhuN0RkVHRS?= =?utf-8?B?L2RlU1dHRVlBcnZhYURMbEwrYTI3QW52Y1YySGE1aU1rZDgrTHRzY3FLZWU5?= =?utf-8?B?enNZRjNGdHJ0QjdWNjJMV1U3anRmbk1adW9PY0MzUHJWVGdoQVFnaFYxazBQ?= =?utf-8?B?S2FGZWgrSW9jZVlpUStGVGtpRUhPeXp1SVlDUXM3YzdtRHVTa1FyNlh4aUV1?= =?utf-8?B?VXhtOWkwMkNlTUNDMG1OQWpZb1E3QS9WZHdpa1Q3Zk1RUlhZRVlDU2Flakww?= =?utf-8?B?TldJK2FlbDRuRjhXZDdYZm5sWmVMcXVNSWlGZzBWYU5IQUJ0SGxHZEtqUlla?= =?utf-8?B?a0xQd1NZMlFzcnV5QkY0aWlyTnhXZFZQeVgwNGVvbzByT3FwK0xsR25kSTRk?= =?utf-8?B?cm0zdG1mcVAxRldqTWNkMFk4Q0hWRTZhL05aYkpVOEkxYSs2NzJRQkZDN1k2?= =?utf-8?B?aDhMbHptdlhJNTJ3bWtTeUF5cVIzcUN4bG52OW9XQThWaEx0aHJCOGdGUlda?= =?utf-8?B?eHpNVDdVdGprOTJ3eE9yMHVmK0VpRjZpNnZ0dVZXMzRxOUNBWDhwRXUzenpw?= =?utf-8?B?UGZ4dnVqa21jeThHRU9EWnAyNmxHd3lRdjVMeVFHZlNTZ0FXWXc3dVp2cmFO?= =?utf-8?B?Z0tiM2JMQUp5Z0puUXhlUGtoRnVtR2ppSXdSYmw3VjhqZHlsVWVlay9xUzRW?= =?utf-8?B?cnQxOTllOHFzNjJCcmdJeFRwK1pOL3M4cVBBZDQzWWl5cXJoV1FOTlRYNmxN?= =?utf-8?B?QVBTa0FNU2hRdmhYWkczUzhseUJQYjhLbUljZ1hDOWZ0VHl2NTNJOWFCUzBl?= =?utf-8?B?QXdxZVRQZ3RwSHpMN0ZYdEFCS2VNMlJPK0I4Y0hmVmhqamV6dkcxM0dkdzNa?= =?utf-8?B?TmsrWk5UQ2pUQW5SRGQyUGlsQVQ4RVQ0UzU3VzhoVkw3RGpQWWY2RlY5SHZ3?= =?utf-8?B?OC90d282UUQ0bVoxalNDNjBTaUJqeVFEU0lnS3paTUlFeTc4TTVFQjJhZC9o?= =?utf-8?B?UHBkd3J6dE1mcGpDV2JPU0daN3pqKzNTa3dXa3hIV28xMFBkUjZKV3B1NTVF?= =?utf-8?B?ZmRFMXFHQndqTWhGUFZ1Y3d0bHFHZndmNjVHUmYyNkVTcVFsaVpqRitmUXMz?= =?utf-8?B?K0lvbmFsVmxEUEdMSUxHOUU5VkNremN2bitQYlhBOTdyMlFHdnE2RSsyTjRE?= =?utf-8?B?ZHBYOXRlUmptR0w1cWZUZmc4ajVEZ1FwMnMzbTd1OW41UXFFK2hERE1aNFR0?= =?utf-8?B?WmhrV3h1bjYzZjg0WHl6VThTOXE0aEdyZjh4dmRBa0ZIdXVOSURYRktKaWly?= =?utf-8?B?TWJHSERlVWVwcTl2MDRVT0lIL0tSRkp6QWhkQ0w2MzlzNWRYdW5TSVY2WU1u?= =?utf-8?B?SjZoNFY0eDV6bTNwMUcwZk9IcXl2S3VRd0haZmNIRlp1QUV1YUFFZ0dqbEk0?= =?utf-8?Q?nIy5RFXmTEW49Rcfz6l5HcgIx9mAaI=3D?= X-OriginatorOrg: os.amperecomputing.com X-MS-Exchange-CrossTenant-Network-Message-Id: e8a3997a-4e52-4386-d092-08da028af8ea X-MS-Exchange-CrossTenant-AuthSource: SJ0PR01MB7282.prod.exchangelabs.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 10 Mar 2022 11:41:53.7319 (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: lTbl/p67v9qAS/IHQAeKroXsQ7y9QsDsteDekZKRV+TIjRRD75zxzAr6kHaZDRT9bbCAhpRJRwDbAgF7p9008i5cwHpRyDVytHI2p4JrpEM= X-MS-Exchange-Transport-CrossTenantHeadersStamped: BL0PR01MB4305 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 --- v6: + Drop the use of slave_enable() [Wolfram] + Make i2c-aspeed to issue RxCmdLast command on all I2C_SLAVE_WRITE_REQUESTED event to assert NAK when slave busy [Quan] + Make i2c slave to return -EBUSY when it's busy [Quan] + Drop the aborting feature as return Completion Code 0xFF may stop host to retry and make ipmi_ssif.so fails to load [Quan] + Add timer to recover slave from busy state when no response [Quan] + Clean request/response buffer appropriately [Quan] + Add some minor change on error and warning messages [Quan] 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() and 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 | 791 +++++++++++++++++++++++++++++++++++ drivers/char/ipmi/ssif_bmc.h | 102 +++++ 4 files changed, 905 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 b061e6b513ed..18a89093d64e 100644 --- a/drivers/char/ipmi/Kconfig +++ b/drivers/char/ipmi/Kconfig @@ -169,6 +169,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 7ce790efad92..cb6138b8ded9 100644 --- a/drivers/char/ipmi/Makefile +++ b/drivers/char/ipmi/Makefile @@ -30,3 +30,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..62db97773654 --- /dev/null +++ b/drivers/char/ipmi/ssif_bmc.c @@ -0,0 +1,791 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * The driver for BMC side of SSIF interface + * + * Copyright (c) 2022, Ampere Computing LLC + * + */ + +#include +#include +#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; + + /* ssif_bmc not busy */ + ssif_bmc->busy = false; + + if (ssif_bmc->response_timer_inited) { + del_timer(&ssif_bmc->response_timer); + ssif_bmc->response_timer_inited = false; + } + /* Clean old request buffer */ + memset(&ssif_bmc->request, 0, sizeof(struct ssif_msg)); + + spin_unlock_irqrestore(&ssif_bmc->lock, flags); + + return 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; + ssif_bmc->busy = false; + memset(&ssif_bmc->response_buf, 0, MAX_PAYLOAD_PER_TRANSACTION); + wake_up_all(&ssif_bmc->wait_queue); +} + +static void response_timeout(struct timer_list *t) +{ + struct ssif_bmc_ctx *ssif_bmc = from_timer(ssif_bmc, t, response_timer); + unsigned long flags; + + spin_lock_irqsave(&ssif_bmc->lock, flags); + + /* Recover ssif_bmc from busy */ + ssif_bmc->busy = false; + del_timer(&ssif_bmc->response_timer); + ssif_bmc->response_timer_inited = false; + + spin_unlock_irqrestore(&ssif_bmc->lock, flags); +} + +/* Called with ssif_bmc->lock held. */ +static void handle_request(struct ssif_bmc_ctx *ssif_bmc) +{ + /* set ssif_bmc to busy waiting for response */ + ssif_bmc->busy = true; + + /* Request message is available to process */ + ssif_bmc->request_available = true; + + /* Clean old response buffer */ + memset(&ssif_bmc->response, 0, sizeof(struct ssif_msg)); + + /* This is the new READ request.*/ + wake_up_all(&ssif_bmc->wait_queue); + + /* Armed timer to recover slave from busy state in case of no response */ + if (!ssif_bmc->response_timer_inited) { + timer_setup(&ssif_bmc->response_timer, response_timeout, 0); + ssif_bmc->response_timer_inited = true; + } + mod_timer(&ssif_bmc->response_timer, jiffies + msecs_to_jiffies(RESPONSE_TIMEOUT)); +} + +static void set_multipart_response_buffer(struct ssif_bmc_ctx *ssif_bmc, u8 *val) +{ + u8 response_len = 0; + int idx = 0; + u8 data_len; + + data_len = ssif_bmc->response.len; + switch (ssif_bmc->smbus_cmd) { + case SSIF_IPMI_MULTIPART_READ_START: + /* + * Read Start length is 32 bytes. + * Read Start transfer first 30 bytes of IPMI response + * and 2 special code 0x00, 0x01. + */ + *val = MAX_PAYLOAD_PER_TRANSACTION; + ssif_bmc->remain_len = data_len - MAX_IPMI_DATA_PER_START_TRANSACTION; + ssif_bmc->block_num = 0; + + ssif_bmc->response_buf[idx++] = 0x00; /* Start Flag */ + ssif_bmc->response_buf[idx++] = 0x01; /* Start Flag */ + ssif_bmc->response_buf[idx++] = ssif_bmc->response.netfn_lun; + ssif_bmc->response_buf[idx++] = ssif_bmc->response.cmd; + ssif_bmc->response_buf[idx++] = ssif_bmc->response.payload[0]; + + response_len = MAX_PAYLOAD_PER_TRANSACTION - idx; + + memcpy(&ssif_bmc->response_buf[idx], &ssif_bmc->response.payload[1], + response_len); + break; + + case SSIF_IPMI_MULTIPART_READ_MIDDLE: + /* + * IPMI READ Middle or READ End messages can carry up to 31 bytes + * IPMI data plus block number byte. + */ + if (ssif_bmc->remain_len < MAX_IPMI_DATA_PER_MIDDLE_TRANSACTION) { + /* + * This is READ End message + * Return length is the remaining response data length + * plus block number + * Block number 0xFF is to indicate this is last message + * + */ + *val = ssif_bmc->remain_len + 1; + ssif_bmc->block_num = 0xFF; + ssif_bmc->response_buf[idx++] = ssif_bmc->block_num; + response_len = ssif_bmc->remain_len; + /* Clean the buffer */ + memset(&ssif_bmc->response_buf[idx], 0, MAX_PAYLOAD_PER_TRANSACTION - idx); + } else { + /* + * This is READ Middle message + * Response length is the maximum SMBUS transfer length + * Block number byte is incremented + * Return length is maximum SMBUS transfer length + */ + *val = MAX_PAYLOAD_PER_TRANSACTION; + ssif_bmc->remain_len -= MAX_IPMI_DATA_PER_MIDDLE_TRANSACTION; + response_len = MAX_IPMI_DATA_PER_MIDDLE_TRANSACTION; + ssif_bmc->response_buf[idx++] = ssif_bmc->block_num; + ssif_bmc->block_num++; + } + + memcpy(&ssif_bmc->response_buf[idx], + ssif_bmc->response.payload + 1 + ssif_bmc->nbytes_processed, + response_len); + break; + + default: + /* Do not expect to go to this case */ + dev_err(&ssif_bmc->client->dev, + "%s: Unexpected SMBus command 0x%x\n", + __func__, ssif_bmc->smbus_cmd); + break; + } + + ssif_bmc->nbytes_processed += response_len; +} + +/* Process the IPMI response that will be read by master */ +static void handle_read_processed(struct ssif_bmc_ctx *ssif_bmc, u8 *val) +{ + u8 *buf; + u8 pec_len, addr, len; + u8 pec = 0; + + pec_len = ssif_bmc->pec_support ? 1 : 0; + /* PEC - Start Read Address */ + addr = GET_8BIT_ADDR(ssif_bmc->client->addr); + pec = i2c_smbus_pec(pec, &addr, 1); + /* PEC - SSIF Command */ + pec = i2c_smbus_pec(pec, &ssif_bmc->smbus_cmd, 1); + /* PEC - Restart Write Address */ + addr = addr | 0x01; + pec = i2c_smbus_pec(pec, &addr, 1); + + if (ssif_bmc->is_singlepart_read) { + /* Single-part Read processing */ + buf = (u8 *)&ssif_bmc->response; + + if (ssif_bmc->response.len && ssif_bmc->msg_idx < ssif_bmc->response.len) { + ssif_bmc->msg_idx++; + *val = buf[ssif_bmc->msg_idx]; + } else if (ssif_bmc->response.len && ssif_bmc->msg_idx == ssif_bmc->response.len) { + ssif_bmc->msg_idx++; + *val = i2c_smbus_pec(pec, buf, ssif_msg_len(&ssif_bmc->response)); + } else { + *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\n", + __func__, ssif_bmc->smbus_cmd); + break; + } + + len = (ssif_bmc->block_num == 0xFF) ? + ssif_bmc->remain_len + 1 : MAX_PAYLOAD_PER_TRANSACTION; + if (ssif_bmc->msg_idx == (len + 1)) { + pec = i2c_smbus_pec(pec, &len, 1); + *val = i2c_smbus_pec(pec, ssif_bmc->response_buf, len); + } + /* Invalidate response buffer to denote last response is sent */ + if (ssif_bmc->block_num == 0xFF && + ssif_bmc->msg_idx > (ssif_bmc->remain_len + pec_len)) { + complete_response(ssif_bmc); + } + } +} + +static void handle_write_received(struct ssif_bmc_ctx *ssif_bmc, u8 *val) +{ + u8 *buf = (u8 *)&ssif_bmc->request; + + if (ssif_bmc->msg_idx >= sizeof(struct ssif_msg)) + return; + + 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"); + + fallthrough; + case SSIF_IPMI_MULTIPART_WRITE_END: + /* Multi-part write, 2nd byte received is length */ + if (ssif_bmc->msg_idx == 1) { + if (*val > MAX_PAYLOAD_PER_TRANSACTION) + dev_warn(&ssif_bmc->client->dev, + "Warn: Invalid Multipart Write End len"); + + ssif_bmc->request.len += *val; + ssif_bmc->recv_len = *val; + + /* request len should never exceeded 255 bytes */ + if (ssif_bmc->request.len > 255) + dev_warn(&ssif_bmc->client->dev, + "Warn: Invalid request len"); + + } else { + 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\n", + __func__, ssif_bmc->smbus_cmd); + break; + } +} + +static bool validate_request(struct ssif_bmc_ctx *ssif_bmc) +{ + u8 rpec = 0, cpec = 0; + bool ret = true; + u8 addr, index; + u8 *buf; + + 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\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"); + + if (*val == SSIF_IPMI_SINGLEPART_WRITE || + *val == SSIF_IPMI_MULTIPART_WRITE_START) { + /* + * The response maybe not come in-time, causing host SSIF driver + * to timeout and resend a new request. In such case check for + * pending response and clear it + */ + if (ssif_bmc->response_in_progress) + complete_response(ssif_bmc); + } +} + +static void on_read_requested_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) +{ + if (ssif_bmc->state == SSIF_READY || + ssif_bmc->state == SSIF_START || + ssif_bmc->state == SSIF_REQ_RECVING || + ssif_bmc->state == SSIF_RES_SENDING) { + ssif_bmc->state = SSIF_BAD_SMBUS; + dev_warn(&ssif_bmc->client->dev, + "Warn: %s unexpected READ REQUESTED in state=%s\n", + __func__, state_to_string(ssif_bmc->state)); + + } else if (ssif_bmc->state == SSIF_SMBUS_CMD) { + ssif_bmc->state = SSIF_RES_SENDING; + } + + ssif_bmc->msg_idx = 0; + if (ssif_bmc->is_singlepart_read) + *val = ssif_bmc->response.len; + else + set_multipart_response_buffer(ssif_bmc, val); +} + +static void on_read_processed_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) +{ + if (ssif_bmc->state == SSIF_READY || + ssif_bmc->state == SSIF_START || + ssif_bmc->state == SSIF_REQ_RECVING || + ssif_bmc->state == SSIF_SMBUS_CMD) { + dev_warn(&ssif_bmc->client->dev, + "Warn: %s unexpected READ PROCESSED in state=%s\n", + __func__, state_to_string(ssif_bmc->state)); + ssif_bmc->state = SSIF_BAD_SMBUS; + } + + handle_read_processed(ssif_bmc, val); +} + +static void on_write_requested_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) +{ + ssif_bmc->msg_idx = 0; + + if (ssif_bmc->state == SSIF_READY || ssif_bmc->state == SSIF_SMBUS_CMD) { + ssif_bmc->state = SSIF_START; + + } else if (ssif_bmc->state == SSIF_START || + ssif_bmc->state == SSIF_REQ_RECVING || + ssif_bmc->state == SSIF_RES_SENDING) { + dev_warn(&ssif_bmc->client->dev, + "Warn: %s unexpected WRITE REQUEST in state=%s\n", + __func__, state_to_string(ssif_bmc->state)); + ssif_bmc->state = SSIF_BAD_SMBUS; + } +} + +static void on_write_received_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) +{ + if (ssif_bmc->state == SSIF_READY || ssif_bmc->state == SSIF_RES_SENDING) { + dev_warn(&ssif_bmc->client->dev, + "Warn: %s unexpected WRITE RECEIVED in state=%s\n", + __func__, state_to_string(ssif_bmc->state)); + ssif_bmc->state = SSIF_BAD_SMBUS; + } else if (ssif_bmc->state == SSIF_START) { + ssif_bmc->state = SSIF_SMBUS_CMD; + } else if (ssif_bmc->state == SSIF_SMBUS_CMD) { + ssif_bmc->state = SSIF_REQ_RECVING; + } + + /* This is response sending state */ + if (ssif_bmc->state == SSIF_REQ_RECVING) + handle_write_received(ssif_bmc, val); + else if (ssif_bmc->state == SSIF_SMBUS_CMD) + process_smbus_cmd(ssif_bmc, val); +} + +static void on_stop_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) +{ + if (ssif_bmc->state == SSIF_READY || + ssif_bmc->state == SSIF_START || + ssif_bmc->state == SSIF_SMBUS_CMD) { + dev_warn(&ssif_bmc->client->dev, + "Warn: %s unexpected SLAVE STOP in state=%s\n", + __func__, state_to_string(ssif_bmc->state)); + + } else if (ssif_bmc->state == SSIF_BAD_SMBUS) { + dev_warn(&ssif_bmc->client->dev, + "Warn: %s received SLAVE STOP from bad state=%s\n", + __func__, state_to_string(ssif_bmc->state)); + + } else if (ssif_bmc->state == SSIF_REQ_RECVING) { + /* A BMC that receives an invalid request drop the data for the write + * transaction and any further transactions (read or write) until + * the next valid read or write Start transaction is received + */ + if (!validate_request(ssif_bmc)) + dev_err(&ssif_bmc->client->dev, "Error: invalid pec\n"); + else if (ssif_bmc->smbus_cmd == SSIF_IPMI_SINGLEPART_WRITE || + ssif_bmc->smbus_cmd == SSIF_IPMI_MULTIPART_WRITE_END) + handle_request(ssif_bmc); + } + + ssif_bmc->state = SSIF_READY; + /* Reset message index */ + ssif_bmc->msg_idx = 0; +} + +/* + * Callback function to handle I2C slave events + */ +static int ssif_bmc_cb(struct i2c_client *client, enum i2c_slave_event event, u8 *val) +{ + unsigned long flags; + struct ssif_bmc_ctx *ssif_bmc = i2c_get_clientdata(client); + int ret = 0; + + spin_lock_irqsave(&ssif_bmc->lock, flags); + + switch (event) { + case I2C_SLAVE_READ_REQUESTED: + on_read_requested_event(ssif_bmc, val); + break; + + case I2C_SLAVE_WRITE_REQUESTED: + on_write_requested_event(ssif_bmc, val); + break; + + case I2C_SLAVE_READ_PROCESSED: + on_read_processed_event(ssif_bmc, val); + break; + + case I2C_SLAVE_WRITE_RECEIVED: + on_write_received_event(ssif_bmc, val); + break; + + case I2C_SLAVE_STOP: + on_stop_event(ssif_bmc, val); + break; + + default: + dev_warn(&ssif_bmc->client->dev, "Warn: Unknown i2c slave event\n"); + break; + } + + if (ssif_bmc->busy) + ret = -EBUSY; + + spin_unlock_irqrestore(&ssif_bmc->lock, flags); + + return ret; +} + +static int ssif_bmc_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + struct ssif_bmc_ctx *ssif_bmc; + int ret; + + ssif_bmc = devm_kzalloc(&client->dev, sizeof(*ssif_bmc), GFP_KERNEL); + if (!ssif_bmc) + return -ENOMEM; + + spin_lock_init(&ssif_bmc->lock); + + init_waitqueue_head(&ssif_bmc->wait_queue); + ssif_bmc->request_available = false; + ssif_bmc->response_in_progress = false; + ssif_bmc->busy = false; + ssif_bmc->response_timer_inited = false; + + /* Register misc device interface */ + ssif_bmc->miscdev.minor = MISC_DYNAMIC_MINOR; + ssif_bmc->miscdev.name = DEVICE_NAME; + ssif_bmc->miscdev.fops = &ssif_bmc_fops; + ssif_bmc->miscdev.parent = &client->dev; + ret = misc_register(&ssif_bmc->miscdev); + if (ret) + goto out; + + ssif_bmc->client = client; + ssif_bmc->client->flags |= I2C_CLIENT_SLAVE; + + /* Register I2C slave */ + i2c_set_clientdata(client, ssif_bmc); + ret = i2c_slave_register(client, ssif_bmc_cb); + if (ret) { + misc_deregister(&ssif_bmc->miscdev); + goto out; + } + + return 0; +out: + devm_kfree(&client->dev, ssif_bmc); + return ret; +} + +static int ssif_bmc_remove(struct i2c_client *client) +{ + struct ssif_bmc_ctx *ssif_bmc = i2c_get_clientdata(client); + + i2c_slave_unregister(client); + misc_deregister(&ssif_bmc->miscdev); + + return 0; +} + +static const struct of_device_id ssif_bmc_match[] = { + { .compatible = "ampere,ssif-bmc" }, + { }, +}; + +static const struct i2c_device_id ssif_bmc_id[] = { + { DEVICE_NAME, 0 }, + { }, +}; + +MODULE_DEVICE_TABLE(i2c, ssif_bmc_id); + +static struct i2c_driver ssif_bmc_driver = { + .driver = { + .name = DEVICE_NAME, + .of_match_table = ssif_bmc_match, + }, + .probe = ssif_bmc_probe, + .remove = ssif_bmc_remove, + .id_table = ssif_bmc_id, +}; + +module_i2c_driver(ssif_bmc_driver); + +MODULE_AUTHOR("Quan Nguyen "); +MODULE_AUTHOR("Chuong Tran "); +MODULE_DESCRIPTION("Linux device driver of the BMC IPMI SSIF interface."); +MODULE_LICENSE("GPL"); diff --git a/drivers/char/ipmi/ssif_bmc.h b/drivers/char/ipmi/ssif_bmc.h new file mode 100644 index 000000000000..9a26f3c252cc --- /dev/null +++ b/drivers/char/ipmi/ssif_bmc.h @@ -0,0 +1,102 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * The driver for BMC side of SSIF interface + * + * Copyright (c) 2022, Ampere Computing LLC + * + */ +#ifndef __SSIF_BMC_H__ +#define __SSIF_BMC_H__ + +#define DEVICE_NAME "ipmi-ssif-host" + +#define GET_8BIT_ADDR(addr_7bit) (((addr_7bit) << 1) & 0xff) + +/* A standard SMBus Transaction is limited to 32 data bytes */ +#define MAX_PAYLOAD_PER_TRANSACTION 32 + +#define MAX_IPMI_DATA_PER_START_TRANSACTION 30 +#define MAX_IPMI_DATA_PER_MIDDLE_TRANSACTION 31 + +#define SSIF_IPMI_SINGLEPART_WRITE 0x2 +#define SSIF_IPMI_SINGLEPART_READ 0x3 +#define SSIF_IPMI_MULTIPART_WRITE_START 0x6 +#define SSIF_IPMI_MULTIPART_WRITE_MIDDLE 0x7 +#define SSIF_IPMI_MULTIPART_WRITE_END 0x8 +#define SSIF_IPMI_MULTIPART_READ_START 0x3 +#define SSIF_IPMI_MULTIPART_READ_MIDDLE 0x9 + +#define MSG_PAYLOAD_LEN_MAX 252 +/* + * IPMI 2.0 Spec, section 12.7 SSIF Timing, + * Request-to-Response Time is T6max(250ms) - T1max(20ms) - 3ms = 227ms + * Recover ssif_bmc from busy state if it takes upto 500ms + */ +#define RESPONSE_TIMEOUT 500 /* ms */ + +struct ssif_msg { + u8 len; + u8 netfn_lun; + u8 cmd; + u8 payload[MSG_PAYLOAD_LEN_MAX]; +} __packed; + +static inline u32 ssif_msg_len(struct ssif_msg *ssif_msg) +{ + return ssif_msg->len + 1; +} + +/* + * SSIF internal states: + * SSIF_READY 0x00 : Ready state + * SSIF_START 0x01 : Start smbus transaction + * SSIF_SMBUS_CMD 0x02 : Received SMBus command + * SSIF_REQ_RECVING 0x03 : Receiving request + * SSIF_RES_SENDING 0x04 : Sending response + * SSIF_BAD_SMBUS 0x05 : Bad SMbus transaction + */ +enum ssif_state { + SSIF_READY, + SSIF_START, + SSIF_SMBUS_CMD, + SSIF_REQ_RECVING, + SSIF_RES_SENDING, + SSIF_BAD_SMBUS, + SSIF_STATE_MAX +}; + +struct ssif_bmc_ctx { + struct i2c_client *client; + struct miscdevice miscdev; + size_t msg_idx; + bool pec_support; + /* ssif bmc spinlock */ + spinlock_t lock; + wait_queue_head_t wait_queue; + u8 running; + enum ssif_state state; + u8 smbus_cmd; + /* Timeout waiting for response */ + struct timer_list response_timer; + bool response_timer_inited; + /* Flag to identify a Multi-part Read Transaction */ + bool is_singlepart_read; + u8 nbytes_processed; + u8 remain_len; + u8 recv_len; + /* Block Number of a Multi-part Read Transaction */ + u8 block_num; + bool request_available; + bool response_in_progress; + bool busy; + /* Response buffer for Multi-part Read Transaction */ + u8 response_buf[MAX_PAYLOAD_PER_TRANSACTION]; + struct ssif_msg response; + struct ssif_msg request; +}; + +static inline struct ssif_bmc_ctx *to_ssif_bmc(struct file *file) +{ + return container_of(file->private_data, struct ssif_bmc_ctx, miscdev); +} +#endif /* __SSIF_BMC_H__ */ -- 2.35.1 From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.ozlabs.org (lists.ozlabs.org [112.213.38.117]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 6F38BC433F5 for ; Thu, 10 Mar 2022 11:43:43 +0000 (UTC) Received: from boromir.ozlabs.org (localhost [IPv6:::1]) by lists.ozlabs.org (Postfix) with ESMTP id 4KDnJY6QjDz30CS for ; Thu, 10 Mar 2022 22:43:41 +1100 (AEDT) Authentication-Results: lists.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=os.amperecomputing.com header.i=@os.amperecomputing.com header.a=rsa-sha256 header.s=selector2 header.b=Kx4Vhc6X; dkim-atps=neutral Authentication-Results: lists.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=os.amperecomputing.com (client-ip=2a01:111:f400:fe59::714; helo=nam12-dm6-obe.outbound.protection.outlook.com; envelope-from=quan@os.amperecomputing.com; receiver=) Authentication-Results: lists.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=os.amperecomputing.com header.i=@os.amperecomputing.com header.a=rsa-sha256 header.s=selector2 header.b=Kx4Vhc6X; dkim-atps=neutral Received: from NAM12-DM6-obe.outbound.protection.outlook.com (mail-dm6nam12on20714.outbound.protection.outlook.com [IPv6:2a01:111:f400:fe59::714]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 4KDnGq3ZYRz2xrc; Thu, 10 Mar 2022 22:42:11 +1100 (AEDT) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=WRyXzHGISb5JubypSkWIG+zUQh35HjXVewRmBNBM2UbOYhG1wWFp0MVIs6evNz3WVpwljJXSwL2G7FI6W/u5uDTxJJWcj0yrIZyOwkrYiFOAsfKg0qNCqA1BSdI7Y+kcYCFOyQvgm0H7ZqZGSp743/Zo9vDgOHp3HUe1dJlqPcn+KUEz5TZQPcvf9yUXJpJljKTKo2aAuSE1OkYvfBTDfM3vGjkmyKoaC65MaEDB3xqF6F173dYqJPzphq+k6PUbYOLHiFGMCzEL0D8KtSLBUWoPeymxc5F/Lnwft8RWNKoU6mqXQKw9Dea79BwmVnO0NXlcG986gXyzqSgg6uwMpw== 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-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=JvWm84ASHNFLEyrKTTKG6qYhEcrD9hzNbMGXYtBKHXY=; b=ci+ZGQBhuFhSRop1mNKSZdhVq3ND19nB4IOEZP4ogzoYohEQbzWA/hDB9N3nt8Yv6nL41/RbWIbvyWfM/8/iI6j9pKOWu3LgVsU92Z3KqvWsiPbs+z/MwcG4w8bOus+sg81xAqjDb2SRi1Qj9QDF/GgawWvQFRMbvlkmzY/B54S4znN/b91bi79sQBK5Fu8kx3DOBuWaIDGKkRM4KF7htf3ntXiZjjC8ESmuUjzL30hCB+7/arwZUkMiUxo84hAomRNrpMWa8BkgrAz90RTPUW6LPtpSiaF/pDn1wrzE0xj6ZRqjEgjv62C/Ax/FtHjabjVcvWJ29i5qWeD92CTACA== 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=JvWm84ASHNFLEyrKTTKG6qYhEcrD9hzNbMGXYtBKHXY=; b=Kx4Vhc6Xf3wfjdbaFghQDyiCC1PqAmNdrhMBOqUhxaij+yHGV7siHt5l1zndMX5QQbFBdXGPJa+L7OxXJosvQhyoZwbP6IWeBeTwWK5RAWfGRg2Lwc9gAyDOXBTAL0+9FzDdfJvgfN9IzhAtrMopM6IpHf2Qu8rEVqgKFguwq0U= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=os.amperecomputing.com; Received: from SJ0PR01MB7282.prod.exchangelabs.com (2603:10b6:a03:3f2::24) by BL0PR01MB4305.prod.exchangelabs.com (2603:10b6:208:4d::23) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5061.22; Thu, 10 Mar 2022 11:41:53 +0000 Received: from SJ0PR01MB7282.prod.exchangelabs.com ([fe80::cd24:39ed:7042:46d6]) by SJ0PR01MB7282.prod.exchangelabs.com ([fe80::cd24:39ed:7042:46d6%6]) with mapi id 15.20.5038.027; Thu, 10 Mar 2022 11:41:53 +0000 From: Quan Nguyen To: Corey Minyard , Rob Herring , Krzysztof Kozlowski , Joel Stanley , Andrew Jeffery , Brendan Higgins , Benjamin Herrenschmidt , Wolfram Sang , openipmi-developer@lists.sourceforge.net, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-aspeed@lists.ozlabs.org, linux-kernel@vger.kernel.org, linux-i2c@vger.kernel.org, openbmc@lists.ozlabs.org Subject: [PATCH v6 1/4] ipmi: ssif_bmc: Add SSIF BMC driver Date: Thu, 10 Mar 2022 18:41:16 +0700 Message-Id: <20220310114119.13736-2-quan@os.amperecomputing.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220310114119.13736-1-quan@os.amperecomputing.com> References: <20220310114119.13736-1-quan@os.amperecomputing.com> Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-ClientProxiedBy: SG2PR02CA0125.apcprd02.prod.outlook.com (2603:1096:4:188::13) To SJ0PR01MB7282.prod.exchangelabs.com (2603:10b6:a03:3f2::24) MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: e8a3997a-4e52-4386-d092-08da028af8ea X-MS-TrafficTypeDiagnostic: BL0PR01MB4305:EE_ X-Microsoft-Antispam-PRVS: X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: HhA7CxIx1n72js7q2HTjxU4uJOF48oZ+ur6WLYMTRAQGPtRUS5G2bXfnOBWAGvPSUeY9kA8ahdnRvd1kcf/EbCnX89LziCaavrHcb8gmnlMDWUSeQmnFmG1fa6FD5S11xeJBkS2sG8SV4VsWKiOE8RBb8AoGpeU5sDXUpZPJvyAUDTeW+/iVqjFLqtGmsubPP3pN8y7blFYlbVK+L4Ys/DT5lT2zVgV3VGiL4omlyAOCC2zEk2QgUpcQKGeMyWxtqWDnNuIT6mvZ7fOTLgLK60Vd0usHA9VgDeyecMbEMch2KK10tWcl+7UQVPGXDKJXoM5GVNHHqIQms3c2i7WggywYyV6jcen37nVRHzfppLI3q7nCDoMcXyuzUdFF5XSRsGLB5mbGlSw5/zEkbXpgRnc7ZbRIsVKKTOqal4Ith3Z30rEwMd2Ol5agOvbOeSCt2XKJxLctT+0MgyUkKeeUu52SGMvLmPMzCpbb+B+FCa4CtGSkDTXBKywCRCduKJC9PFX9JDzxhhjpl4VwPF1M1d61BfKo2Y3oTXZByANBMRBtnZr9Zaq1hTR1WXP13Ui3Osl0+XlsRE1C+JuAEqQyweLDxtTyA+11/xTLLbToza7NKB1JXzXxPFeStiioCgW7kzxtTQ5UIUd6/r1kpGqJnA7jzWVvFymsKPr8CMb9nbyRAHWJ9+L2XBP6LLH9ieZKow1/QtIsBnnTiVueZ1ynt1/JIUVElSSXhmqsVwvGViM= X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:SJ0PR01MB7282.prod.exchangelabs.com; PTR:; CAT:NONE; SFS:(13230001)(4636009)(366004)(107886003)(6666004)(66556008)(66476007)(66946007)(30864003)(1076003)(5660300002)(2616005)(7416002)(316002)(38350700002)(38100700002)(86362001)(4326008)(8676002)(8936002)(83380400001)(26005)(186003)(921005)(2906002)(52116002)(6512007)(508600001)(110136005)(6506007)(6486002)(54906003); DIR:OUT; SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?YVBvcDZBdXlLV3lVZi94ZFJIQjBCcXNJcDdNMTRMdmYwZ3YyTkZvTmhKU2Rv?= =?utf-8?B?SnlyRSsvaDNQaTVRRkxrWnpaZlRsVENrdFR6Um9aMzV3M0NONDAvb0VMaERq?= =?utf-8?B?U3ZIcWI0V0MydGY0aE9iZjRTa1loWW80NU94WmwySlZOOGxNNVEyTE50VFpE?= =?utf-8?B?VGxrUk9YTjdSemJ0VDhubDJnRjdwdVJuM29hTHJvZzd2T2ZuL1diL0tLQjls?= =?utf-8?B?Zit5bUw5UHBQSHlycVZDbEo4SVdCRFdzZU96STVVcUV2V1FpNm1RbWNya01T?= =?utf-8?B?ajc4dkdIQW1oUmNQelczZytFNlp1UDZJNExzSUUybFJiTnh1RCtmYWxnR1Ey?= =?utf-8?B?Zm9EbENEem85SjlPdWR6c0FSdC9GY2dXM2d4L3ZyQ1JIaUVIYWYrNWsyRGFR?= =?utf-8?B?TXlxYk1EcTR1dzZRcWNLY0FVY0pmWXQyUFRwMUhwU0pTRGpNTjB4ZUZ3Snht?= =?utf-8?B?YUpqU1ZGeHg5V2dkMHRveFR0aXcxa0c1VEFPRVY0MzFlenRLQlBMbThWalVE?= =?utf-8?B?dGR2R2ZZeUh0Z2RIcnJvZDZDVEVNQmdZdFRERHhuZ1N0cVd1NWhuN0RkVHRS?= =?utf-8?B?L2RlU1dHRVlBcnZhYURMbEwrYTI3QW52Y1YySGE1aU1rZDgrTHRzY3FLZWU5?= =?utf-8?B?enNZRjNGdHJ0QjdWNjJMV1U3anRmbk1adW9PY0MzUHJWVGdoQVFnaFYxazBQ?= =?utf-8?B?S2FGZWgrSW9jZVlpUStGVGtpRUhPeXp1SVlDUXM3YzdtRHVTa1FyNlh4aUV1?= =?utf-8?B?VXhtOWkwMkNlTUNDMG1OQWpZb1E3QS9WZHdpa1Q3Zk1RUlhZRVlDU2Flakww?= =?utf-8?B?TldJK2FlbDRuRjhXZDdYZm5sWmVMcXVNSWlGZzBWYU5IQUJ0SGxHZEtqUlla?= =?utf-8?B?a0xQd1NZMlFzcnV5QkY0aWlyTnhXZFZQeVgwNGVvbzByT3FwK0xsR25kSTRk?= =?utf-8?B?cm0zdG1mcVAxRldqTWNkMFk4Q0hWRTZhL05aYkpVOEkxYSs2NzJRQkZDN1k2?= =?utf-8?B?aDhMbHptdlhJNTJ3bWtTeUF5cVIzcUN4bG52OW9XQThWaEx0aHJCOGdGUlda?= =?utf-8?B?eHpNVDdVdGprOTJ3eE9yMHVmK0VpRjZpNnZ0dVZXMzRxOUNBWDhwRXUzenpw?= =?utf-8?B?UGZ4dnVqa21jeThHRU9EWnAyNmxHd3lRdjVMeVFHZlNTZ0FXWXc3dVp2cmFO?= =?utf-8?B?Z0tiM2JMQUp5Z0puUXhlUGtoRnVtR2ppSXdSYmw3VjhqZHlsVWVlay9xUzRW?= =?utf-8?B?cnQxOTllOHFzNjJCcmdJeFRwK1pOL3M4cVBBZDQzWWl5cXJoV1FOTlRYNmxN?= =?utf-8?B?QVBTa0FNU2hRdmhYWkczUzhseUJQYjhLbUljZ1hDOWZ0VHl2NTNJOWFCUzBl?= =?utf-8?B?QXdxZVRQZ3RwSHpMN0ZYdEFCS2VNMlJPK0I4Y0hmVmhqamV6dkcxM0dkdzNa?= =?utf-8?B?TmsrWk5UQ2pUQW5SRGQyUGlsQVQ4RVQ0UzU3VzhoVkw3RGpQWWY2RlY5SHZ3?= =?utf-8?B?OC90d282UUQ0bVoxalNDNjBTaUJqeVFEU0lnS3paTUlFeTc4TTVFQjJhZC9o?= =?utf-8?B?UHBkd3J6dE1mcGpDV2JPU0daN3pqKzNTa3dXa3hIV28xMFBkUjZKV3B1NTVF?= =?utf-8?B?ZmRFMXFHQndqTWhGUFZ1Y3d0bHFHZndmNjVHUmYyNkVTcVFsaVpqRitmUXMz?= =?utf-8?B?K0lvbmFsVmxEUEdMSUxHOUU5VkNremN2bitQYlhBOTdyMlFHdnE2RSsyTjRE?= =?utf-8?B?ZHBYOXRlUmptR0w1cWZUZmc4ajVEZ1FwMnMzbTd1OW41UXFFK2hERE1aNFR0?= =?utf-8?B?WmhrV3h1bjYzZjg0WHl6VThTOXE0aEdyZjh4dmRBa0ZIdXVOSURYRktKaWly?= =?utf-8?B?TWJHSERlVWVwcTl2MDRVT0lIL0tSRkp6QWhkQ0w2MzlzNWRYdW5TSVY2WU1u?= =?utf-8?B?SjZoNFY0eDV6bTNwMUcwZk9IcXl2S3VRd0haZmNIRlp1QUV1YUFFZ0dqbEk0?= =?utf-8?Q?nIy5RFXmTEW49Rcfz6l5HcgIx9mAaI=3D?= X-OriginatorOrg: os.amperecomputing.com X-MS-Exchange-CrossTenant-Network-Message-Id: e8a3997a-4e52-4386-d092-08da028af8ea X-MS-Exchange-CrossTenant-AuthSource: SJ0PR01MB7282.prod.exchangelabs.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 10 Mar 2022 11:41:53.7319 (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: lTbl/p67v9qAS/IHQAeKroXsQ7y9QsDsteDekZKRV+TIjRRD75zxzAr6kHaZDRT9bbCAhpRJRwDbAgF7p9008i5cwHpRyDVytHI2p4JrpEM= X-MS-Exchange-Transport-CrossTenantHeadersStamped: BL0PR01MB4305 X-BeenThere: openbmc@lists.ozlabs.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Development list for OpenBMC List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Open Source Submission , "Thang Q . Nguyen" , Phong Vo Errors-To: openbmc-bounces+openbmc=archiver.kernel.org@lists.ozlabs.org Sender: "openbmc" 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 --- v6: + Drop the use of slave_enable() [Wolfram] + Make i2c-aspeed to issue RxCmdLast command on all I2C_SLAVE_WRITE_REQUESTED event to assert NAK when slave busy [Quan] + Make i2c slave to return -EBUSY when it's busy [Quan] + Drop the aborting feature as return Completion Code 0xFF may stop host to retry and make ipmi_ssif.so fails to load [Quan] + Add timer to recover slave from busy state when no response [Quan] + Clean request/response buffer appropriately [Quan] + Add some minor change on error and warning messages [Quan] 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() and 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 | 791 +++++++++++++++++++++++++++++++++++ drivers/char/ipmi/ssif_bmc.h | 102 +++++ 4 files changed, 905 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 b061e6b513ed..18a89093d64e 100644 --- a/drivers/char/ipmi/Kconfig +++ b/drivers/char/ipmi/Kconfig @@ -169,6 +169,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 7ce790efad92..cb6138b8ded9 100644 --- a/drivers/char/ipmi/Makefile +++ b/drivers/char/ipmi/Makefile @@ -30,3 +30,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..62db97773654 --- /dev/null +++ b/drivers/char/ipmi/ssif_bmc.c @@ -0,0 +1,791 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * The driver for BMC side of SSIF interface + * + * Copyright (c) 2022, Ampere Computing LLC + * + */ + +#include +#include +#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; + + /* ssif_bmc not busy */ + ssif_bmc->busy = false; + + if (ssif_bmc->response_timer_inited) { + del_timer(&ssif_bmc->response_timer); + ssif_bmc->response_timer_inited = false; + } + /* Clean old request buffer */ + memset(&ssif_bmc->request, 0, sizeof(struct ssif_msg)); + + spin_unlock_irqrestore(&ssif_bmc->lock, flags); + + return 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; + ssif_bmc->busy = false; + memset(&ssif_bmc->response_buf, 0, MAX_PAYLOAD_PER_TRANSACTION); + wake_up_all(&ssif_bmc->wait_queue); +} + +static void response_timeout(struct timer_list *t) +{ + struct ssif_bmc_ctx *ssif_bmc = from_timer(ssif_bmc, t, response_timer); + unsigned long flags; + + spin_lock_irqsave(&ssif_bmc->lock, flags); + + /* Recover ssif_bmc from busy */ + ssif_bmc->busy = false; + del_timer(&ssif_bmc->response_timer); + ssif_bmc->response_timer_inited = false; + + spin_unlock_irqrestore(&ssif_bmc->lock, flags); +} + +/* Called with ssif_bmc->lock held. */ +static void handle_request(struct ssif_bmc_ctx *ssif_bmc) +{ + /* set ssif_bmc to busy waiting for response */ + ssif_bmc->busy = true; + + /* Request message is available to process */ + ssif_bmc->request_available = true; + + /* Clean old response buffer */ + memset(&ssif_bmc->response, 0, sizeof(struct ssif_msg)); + + /* This is the new READ request.*/ + wake_up_all(&ssif_bmc->wait_queue); + + /* Armed timer to recover slave from busy state in case of no response */ + if (!ssif_bmc->response_timer_inited) { + timer_setup(&ssif_bmc->response_timer, response_timeout, 0); + ssif_bmc->response_timer_inited = true; + } + mod_timer(&ssif_bmc->response_timer, jiffies + msecs_to_jiffies(RESPONSE_TIMEOUT)); +} + +static void set_multipart_response_buffer(struct ssif_bmc_ctx *ssif_bmc, u8 *val) +{ + u8 response_len = 0; + int idx = 0; + u8 data_len; + + data_len = ssif_bmc->response.len; + switch (ssif_bmc->smbus_cmd) { + case SSIF_IPMI_MULTIPART_READ_START: + /* + * Read Start length is 32 bytes. + * Read Start transfer first 30 bytes of IPMI response + * and 2 special code 0x00, 0x01. + */ + *val = MAX_PAYLOAD_PER_TRANSACTION; + ssif_bmc->remain_len = data_len - MAX_IPMI_DATA_PER_START_TRANSACTION; + ssif_bmc->block_num = 0; + + ssif_bmc->response_buf[idx++] = 0x00; /* Start Flag */ + ssif_bmc->response_buf[idx++] = 0x01; /* Start Flag */ + ssif_bmc->response_buf[idx++] = ssif_bmc->response.netfn_lun; + ssif_bmc->response_buf[idx++] = ssif_bmc->response.cmd; + ssif_bmc->response_buf[idx++] = ssif_bmc->response.payload[0]; + + response_len = MAX_PAYLOAD_PER_TRANSACTION - idx; + + memcpy(&ssif_bmc->response_buf[idx], &ssif_bmc->response.payload[1], + response_len); + break; + + case SSIF_IPMI_MULTIPART_READ_MIDDLE: + /* + * IPMI READ Middle or READ End messages can carry up to 31 bytes + * IPMI data plus block number byte. + */ + if (ssif_bmc->remain_len < MAX_IPMI_DATA_PER_MIDDLE_TRANSACTION) { + /* + * This is READ End message + * Return length is the remaining response data length + * plus block number + * Block number 0xFF is to indicate this is last message + * + */ + *val = ssif_bmc->remain_len + 1; + ssif_bmc->block_num = 0xFF; + ssif_bmc->response_buf[idx++] = ssif_bmc->block_num; + response_len = ssif_bmc->remain_len; + /* Clean the buffer */ + memset(&ssif_bmc->response_buf[idx], 0, MAX_PAYLOAD_PER_TRANSACTION - idx); + } else { + /* + * This is READ Middle message + * Response length is the maximum SMBUS transfer length + * Block number byte is incremented + * Return length is maximum SMBUS transfer length + */ + *val = MAX_PAYLOAD_PER_TRANSACTION; + ssif_bmc->remain_len -= MAX_IPMI_DATA_PER_MIDDLE_TRANSACTION; + response_len = MAX_IPMI_DATA_PER_MIDDLE_TRANSACTION; + ssif_bmc->response_buf[idx++] = ssif_bmc->block_num; + ssif_bmc->block_num++; + } + + memcpy(&ssif_bmc->response_buf[idx], + ssif_bmc->response.payload + 1 + ssif_bmc->nbytes_processed, + response_len); + break; + + default: + /* Do not expect to go to this case */ + dev_err(&ssif_bmc->client->dev, + "%s: Unexpected SMBus command 0x%x\n", + __func__, ssif_bmc->smbus_cmd); + break; + } + + ssif_bmc->nbytes_processed += response_len; +} + +/* Process the IPMI response that will be read by master */ +static void handle_read_processed(struct ssif_bmc_ctx *ssif_bmc, u8 *val) +{ + u8 *buf; + u8 pec_len, addr, len; + u8 pec = 0; + + pec_len = ssif_bmc->pec_support ? 1 : 0; + /* PEC - Start Read Address */ + addr = GET_8BIT_ADDR(ssif_bmc->client->addr); + pec = i2c_smbus_pec(pec, &addr, 1); + /* PEC - SSIF Command */ + pec = i2c_smbus_pec(pec, &ssif_bmc->smbus_cmd, 1); + /* PEC - Restart Write Address */ + addr = addr | 0x01; + pec = i2c_smbus_pec(pec, &addr, 1); + + if (ssif_bmc->is_singlepart_read) { + /* Single-part Read processing */ + buf = (u8 *)&ssif_bmc->response; + + if (ssif_bmc->response.len && ssif_bmc->msg_idx < ssif_bmc->response.len) { + ssif_bmc->msg_idx++; + *val = buf[ssif_bmc->msg_idx]; + } else if (ssif_bmc->response.len && ssif_bmc->msg_idx == ssif_bmc->response.len) { + ssif_bmc->msg_idx++; + *val = i2c_smbus_pec(pec, buf, ssif_msg_len(&ssif_bmc->response)); + } else { + *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\n", + __func__, ssif_bmc->smbus_cmd); + break; + } + + len = (ssif_bmc->block_num == 0xFF) ? + ssif_bmc->remain_len + 1 : MAX_PAYLOAD_PER_TRANSACTION; + if (ssif_bmc->msg_idx == (len + 1)) { + pec = i2c_smbus_pec(pec, &len, 1); + *val = i2c_smbus_pec(pec, ssif_bmc->response_buf, len); + } + /* Invalidate response buffer to denote last response is sent */ + if (ssif_bmc->block_num == 0xFF && + ssif_bmc->msg_idx > (ssif_bmc->remain_len + pec_len)) { + complete_response(ssif_bmc); + } + } +} + +static void handle_write_received(struct ssif_bmc_ctx *ssif_bmc, u8 *val) +{ + u8 *buf = (u8 *)&ssif_bmc->request; + + if (ssif_bmc->msg_idx >= sizeof(struct ssif_msg)) + return; + + 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"); + + fallthrough; + case SSIF_IPMI_MULTIPART_WRITE_END: + /* Multi-part write, 2nd byte received is length */ + if (ssif_bmc->msg_idx == 1) { + if (*val > MAX_PAYLOAD_PER_TRANSACTION) + dev_warn(&ssif_bmc->client->dev, + "Warn: Invalid Multipart Write End len"); + + ssif_bmc->request.len += *val; + ssif_bmc->recv_len = *val; + + /* request len should never exceeded 255 bytes */ + if (ssif_bmc->request.len > 255) + dev_warn(&ssif_bmc->client->dev, + "Warn: Invalid request len"); + + } else { + 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\n", + __func__, ssif_bmc->smbus_cmd); + break; + } +} + +static bool validate_request(struct ssif_bmc_ctx *ssif_bmc) +{ + u8 rpec = 0, cpec = 0; + bool ret = true; + u8 addr, index; + u8 *buf; + + 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\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"); + + if (*val == SSIF_IPMI_SINGLEPART_WRITE || + *val == SSIF_IPMI_MULTIPART_WRITE_START) { + /* + * The response maybe not come in-time, causing host SSIF driver + * to timeout and resend a new request. In such case check for + * pending response and clear it + */ + if (ssif_bmc->response_in_progress) + complete_response(ssif_bmc); + } +} + +static void on_read_requested_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) +{ + if (ssif_bmc->state == SSIF_READY || + ssif_bmc->state == SSIF_START || + ssif_bmc->state == SSIF_REQ_RECVING || + ssif_bmc->state == SSIF_RES_SENDING) { + ssif_bmc->state = SSIF_BAD_SMBUS; + dev_warn(&ssif_bmc->client->dev, + "Warn: %s unexpected READ REQUESTED in state=%s\n", + __func__, state_to_string(ssif_bmc->state)); + + } else if (ssif_bmc->state == SSIF_SMBUS_CMD) { + ssif_bmc->state = SSIF_RES_SENDING; + } + + ssif_bmc->msg_idx = 0; + if (ssif_bmc->is_singlepart_read) + *val = ssif_bmc->response.len; + else + set_multipart_response_buffer(ssif_bmc, val); +} + +static void on_read_processed_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) +{ + if (ssif_bmc->state == SSIF_READY || + ssif_bmc->state == SSIF_START || + ssif_bmc->state == SSIF_REQ_RECVING || + ssif_bmc->state == SSIF_SMBUS_CMD) { + dev_warn(&ssif_bmc->client->dev, + "Warn: %s unexpected READ PROCESSED in state=%s\n", + __func__, state_to_string(ssif_bmc->state)); + ssif_bmc->state = SSIF_BAD_SMBUS; + } + + handle_read_processed(ssif_bmc, val); +} + +static void on_write_requested_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) +{ + ssif_bmc->msg_idx = 0; + + if (ssif_bmc->state == SSIF_READY || ssif_bmc->state == SSIF_SMBUS_CMD) { + ssif_bmc->state = SSIF_START; + + } else if (ssif_bmc->state == SSIF_START || + ssif_bmc->state == SSIF_REQ_RECVING || + ssif_bmc->state == SSIF_RES_SENDING) { + dev_warn(&ssif_bmc->client->dev, + "Warn: %s unexpected WRITE REQUEST in state=%s\n", + __func__, state_to_string(ssif_bmc->state)); + ssif_bmc->state = SSIF_BAD_SMBUS; + } +} + +static void on_write_received_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) +{ + if (ssif_bmc->state == SSIF_READY || ssif_bmc->state == SSIF_RES_SENDING) { + dev_warn(&ssif_bmc->client->dev, + "Warn: %s unexpected WRITE RECEIVED in state=%s\n", + __func__, state_to_string(ssif_bmc->state)); + ssif_bmc->state = SSIF_BAD_SMBUS; + } else if (ssif_bmc->state == SSIF_START) { + ssif_bmc->state = SSIF_SMBUS_CMD; + } else if (ssif_bmc->state == SSIF_SMBUS_CMD) { + ssif_bmc->state = SSIF_REQ_RECVING; + } + + /* This is response sending state */ + if (ssif_bmc->state == SSIF_REQ_RECVING) + handle_write_received(ssif_bmc, val); + else if (ssif_bmc->state == SSIF_SMBUS_CMD) + process_smbus_cmd(ssif_bmc, val); +} + +static void on_stop_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) +{ + if (ssif_bmc->state == SSIF_READY || + ssif_bmc->state == SSIF_START || + ssif_bmc->state == SSIF_SMBUS_CMD) { + dev_warn(&ssif_bmc->client->dev, + "Warn: %s unexpected SLAVE STOP in state=%s\n", + __func__, state_to_string(ssif_bmc->state)); + + } else if (ssif_bmc->state == SSIF_BAD_SMBUS) { + dev_warn(&ssif_bmc->client->dev, + "Warn: %s received SLAVE STOP from bad state=%s\n", + __func__, state_to_string(ssif_bmc->state)); + + } else if (ssif_bmc->state == SSIF_REQ_RECVING) { + /* A BMC that receives an invalid request drop the data for the write + * transaction and any further transactions (read or write) until + * the next valid read or write Start transaction is received + */ + if (!validate_request(ssif_bmc)) + dev_err(&ssif_bmc->client->dev, "Error: invalid pec\n"); + else if (ssif_bmc->smbus_cmd == SSIF_IPMI_SINGLEPART_WRITE || + ssif_bmc->smbus_cmd == SSIF_IPMI_MULTIPART_WRITE_END) + handle_request(ssif_bmc); + } + + ssif_bmc->state = SSIF_READY; + /* Reset message index */ + ssif_bmc->msg_idx = 0; +} + +/* + * Callback function to handle I2C slave events + */ +static int ssif_bmc_cb(struct i2c_client *client, enum i2c_slave_event event, u8 *val) +{ + unsigned long flags; + struct ssif_bmc_ctx *ssif_bmc = i2c_get_clientdata(client); + int ret = 0; + + spin_lock_irqsave(&ssif_bmc->lock, flags); + + switch (event) { + case I2C_SLAVE_READ_REQUESTED: + on_read_requested_event(ssif_bmc, val); + break; + + case I2C_SLAVE_WRITE_REQUESTED: + on_write_requested_event(ssif_bmc, val); + break; + + case I2C_SLAVE_READ_PROCESSED: + on_read_processed_event(ssif_bmc, val); + break; + + case I2C_SLAVE_WRITE_RECEIVED: + on_write_received_event(ssif_bmc, val); + break; + + case I2C_SLAVE_STOP: + on_stop_event(ssif_bmc, val); + break; + + default: + dev_warn(&ssif_bmc->client->dev, "Warn: Unknown i2c slave event\n"); + break; + } + + if (ssif_bmc->busy) + ret = -EBUSY; + + spin_unlock_irqrestore(&ssif_bmc->lock, flags); + + return ret; +} + +static int ssif_bmc_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + struct ssif_bmc_ctx *ssif_bmc; + int ret; + + ssif_bmc = devm_kzalloc(&client->dev, sizeof(*ssif_bmc), GFP_KERNEL); + if (!ssif_bmc) + return -ENOMEM; + + spin_lock_init(&ssif_bmc->lock); + + init_waitqueue_head(&ssif_bmc->wait_queue); + ssif_bmc->request_available = false; + ssif_bmc->response_in_progress = false; + ssif_bmc->busy = false; + ssif_bmc->response_timer_inited = false; + + /* Register misc device interface */ + ssif_bmc->miscdev.minor = MISC_DYNAMIC_MINOR; + ssif_bmc->miscdev.name = DEVICE_NAME; + ssif_bmc->miscdev.fops = &ssif_bmc_fops; + ssif_bmc->miscdev.parent = &client->dev; + ret = misc_register(&ssif_bmc->miscdev); + if (ret) + goto out; + + ssif_bmc->client = client; + ssif_bmc->client->flags |= I2C_CLIENT_SLAVE; + + /* Register I2C slave */ + i2c_set_clientdata(client, ssif_bmc); + ret = i2c_slave_register(client, ssif_bmc_cb); + if (ret) { + misc_deregister(&ssif_bmc->miscdev); + goto out; + } + + return 0; +out: + devm_kfree(&client->dev, ssif_bmc); + return ret; +} + +static int ssif_bmc_remove(struct i2c_client *client) +{ + struct ssif_bmc_ctx *ssif_bmc = i2c_get_clientdata(client); + + i2c_slave_unregister(client); + misc_deregister(&ssif_bmc->miscdev); + + return 0; +} + +static const struct of_device_id ssif_bmc_match[] = { + { .compatible = "ampere,ssif-bmc" }, + { }, +}; + +static const struct i2c_device_id ssif_bmc_id[] = { + { DEVICE_NAME, 0 }, + { }, +}; + +MODULE_DEVICE_TABLE(i2c, ssif_bmc_id); + +static struct i2c_driver ssif_bmc_driver = { + .driver = { + .name = DEVICE_NAME, + .of_match_table = ssif_bmc_match, + }, + .probe = ssif_bmc_probe, + .remove = ssif_bmc_remove, + .id_table = ssif_bmc_id, +}; + +module_i2c_driver(ssif_bmc_driver); + +MODULE_AUTHOR("Quan Nguyen "); +MODULE_AUTHOR("Chuong Tran "); +MODULE_DESCRIPTION("Linux device driver of the BMC IPMI SSIF interface."); +MODULE_LICENSE("GPL"); diff --git a/drivers/char/ipmi/ssif_bmc.h b/drivers/char/ipmi/ssif_bmc.h new file mode 100644 index 000000000000..9a26f3c252cc --- /dev/null +++ b/drivers/char/ipmi/ssif_bmc.h @@ -0,0 +1,102 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * The driver for BMC side of SSIF interface + * + * Copyright (c) 2022, Ampere Computing LLC + * + */ +#ifndef __SSIF_BMC_H__ +#define __SSIF_BMC_H__ + +#define DEVICE_NAME "ipmi-ssif-host" + +#define GET_8BIT_ADDR(addr_7bit) (((addr_7bit) << 1) & 0xff) + +/* A standard SMBus Transaction is limited to 32 data bytes */ +#define MAX_PAYLOAD_PER_TRANSACTION 32 + +#define MAX_IPMI_DATA_PER_START_TRANSACTION 30 +#define MAX_IPMI_DATA_PER_MIDDLE_TRANSACTION 31 + +#define SSIF_IPMI_SINGLEPART_WRITE 0x2 +#define SSIF_IPMI_SINGLEPART_READ 0x3 +#define SSIF_IPMI_MULTIPART_WRITE_START 0x6 +#define SSIF_IPMI_MULTIPART_WRITE_MIDDLE 0x7 +#define SSIF_IPMI_MULTIPART_WRITE_END 0x8 +#define SSIF_IPMI_MULTIPART_READ_START 0x3 +#define SSIF_IPMI_MULTIPART_READ_MIDDLE 0x9 + +#define MSG_PAYLOAD_LEN_MAX 252 +/* + * IPMI 2.0 Spec, section 12.7 SSIF Timing, + * Request-to-Response Time is T6max(250ms) - T1max(20ms) - 3ms = 227ms + * Recover ssif_bmc from busy state if it takes upto 500ms + */ +#define RESPONSE_TIMEOUT 500 /* ms */ + +struct ssif_msg { + u8 len; + u8 netfn_lun; + u8 cmd; + u8 payload[MSG_PAYLOAD_LEN_MAX]; +} __packed; + +static inline u32 ssif_msg_len(struct ssif_msg *ssif_msg) +{ + return ssif_msg->len + 1; +} + +/* + * SSIF internal states: + * SSIF_READY 0x00 : Ready state + * SSIF_START 0x01 : Start smbus transaction + * SSIF_SMBUS_CMD 0x02 : Received SMBus command + * SSIF_REQ_RECVING 0x03 : Receiving request + * SSIF_RES_SENDING 0x04 : Sending response + * SSIF_BAD_SMBUS 0x05 : Bad SMbus transaction + */ +enum ssif_state { + SSIF_READY, + SSIF_START, + SSIF_SMBUS_CMD, + SSIF_REQ_RECVING, + SSIF_RES_SENDING, + SSIF_BAD_SMBUS, + SSIF_STATE_MAX +}; + +struct ssif_bmc_ctx { + struct i2c_client *client; + struct miscdevice miscdev; + size_t msg_idx; + bool pec_support; + /* ssif bmc spinlock */ + spinlock_t lock; + wait_queue_head_t wait_queue; + u8 running; + enum ssif_state state; + u8 smbus_cmd; + /* Timeout waiting for response */ + struct timer_list response_timer; + bool response_timer_inited; + /* Flag to identify a Multi-part Read Transaction */ + bool is_singlepart_read; + u8 nbytes_processed; + u8 remain_len; + u8 recv_len; + /* Block Number of a Multi-part Read Transaction */ + u8 block_num; + bool request_available; + bool response_in_progress; + bool busy; + /* Response buffer for Multi-part Read Transaction */ + u8 response_buf[MAX_PAYLOAD_PER_TRANSACTION]; + struct ssif_msg response; + struct ssif_msg request; +}; + +static inline struct ssif_bmc_ctx *to_ssif_bmc(struct file *file) +{ + return container_of(file->private_data, struct ssif_bmc_ctx, miscdev); +} +#endif /* __SSIF_BMC_H__ */ -- 2.35.1 From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id E49A6C433F5 for ; Thu, 10 Mar 2022 11:43:56 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type: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=yoIr7g6P6W26tlG49+Lo4AbHjP4WGMAAYqMxf+HBBEQ=; b=HNoHWNhyI/osml Sw/1fSPvl2WQb/YZ52d/Bl0BLFQUUvwwhbH5MTIbanW3Xtigl4I2fr36WQ/4skgfVCF0tGe1I3vQa k5eehK+orbtteuAiGkKnyQDbxvU1t4oVLjTIDeCP8Ltp6Qqk9+gVH5pibVqbMxUKP7KxRS1wfLdSG lxfk8Z2sKUzBQwADSuUk7mrQQrDWTbNjV3MND142rlL2lVmDtf2EPRHM23Z1KpOJwqN2NZx+FoXJh FynE3ZpX4YxF9kTAQaurQLDnWubXJeD4dGCXNNidfFQpT7msnUU8cpPsCVyEj2HK6UERAhCZpCC7y y+6y4IZQfwSMlME+CeEw==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1nSHBM-00CeXM-Ee; Thu, 10 Mar 2022 11:42:12 +0000 Received: from mail-dm6nam12on2070e.outbound.protection.outlook.com ([2a01:111:f400:fe59::70e] helo=NAM12-DM6-obe.outbound.protection.outlook.com) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1nSHB8-00CeTE-0J for linux-arm-kernel@lists.infradead.org; Thu, 10 Mar 2022 11:42:01 +0000 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=WRyXzHGISb5JubypSkWIG+zUQh35HjXVewRmBNBM2UbOYhG1wWFp0MVIs6evNz3WVpwljJXSwL2G7FI6W/u5uDTxJJWcj0yrIZyOwkrYiFOAsfKg0qNCqA1BSdI7Y+kcYCFOyQvgm0H7ZqZGSp743/Zo9vDgOHp3HUe1dJlqPcn+KUEz5TZQPcvf9yUXJpJljKTKo2aAuSE1OkYvfBTDfM3vGjkmyKoaC65MaEDB3xqF6F173dYqJPzphq+k6PUbYOLHiFGMCzEL0D8KtSLBUWoPeymxc5F/Lnwft8RWNKoU6mqXQKw9Dea79BwmVnO0NXlcG986gXyzqSgg6uwMpw== 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-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=JvWm84ASHNFLEyrKTTKG6qYhEcrD9hzNbMGXYtBKHXY=; b=ci+ZGQBhuFhSRop1mNKSZdhVq3ND19nB4IOEZP4ogzoYohEQbzWA/hDB9N3nt8Yv6nL41/RbWIbvyWfM/8/iI6j9pKOWu3LgVsU92Z3KqvWsiPbs+z/MwcG4w8bOus+sg81xAqjDb2SRi1Qj9QDF/GgawWvQFRMbvlkmzY/B54S4znN/b91bi79sQBK5Fu8kx3DOBuWaIDGKkRM4KF7htf3ntXiZjjC8ESmuUjzL30hCB+7/arwZUkMiUxo84hAomRNrpMWa8BkgrAz90RTPUW6LPtpSiaF/pDn1wrzE0xj6ZRqjEgjv62C/Ax/FtHjabjVcvWJ29i5qWeD92CTACA== 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=JvWm84ASHNFLEyrKTTKG6qYhEcrD9hzNbMGXYtBKHXY=; b=Kx4Vhc6Xf3wfjdbaFghQDyiCC1PqAmNdrhMBOqUhxaij+yHGV7siHt5l1zndMX5QQbFBdXGPJa+L7OxXJosvQhyoZwbP6IWeBeTwWK5RAWfGRg2Lwc9gAyDOXBTAL0+9FzDdfJvgfN9IzhAtrMopM6IpHf2Qu8rEVqgKFguwq0U= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=os.amperecomputing.com; Received: from SJ0PR01MB7282.prod.exchangelabs.com (2603:10b6:a03:3f2::24) by BL0PR01MB4305.prod.exchangelabs.com (2603:10b6:208:4d::23) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5061.22; Thu, 10 Mar 2022 11:41:53 +0000 Received: from SJ0PR01MB7282.prod.exchangelabs.com ([fe80::cd24:39ed:7042:46d6]) by SJ0PR01MB7282.prod.exchangelabs.com ([fe80::cd24:39ed:7042:46d6%6]) with mapi id 15.20.5038.027; Thu, 10 Mar 2022 11:41:53 +0000 From: Quan Nguyen To: Corey Minyard , Rob Herring , Krzysztof Kozlowski , Joel Stanley , Andrew Jeffery , Brendan Higgins , Benjamin Herrenschmidt , Wolfram Sang , openipmi-developer@lists.sourceforge.net, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-aspeed@lists.ozlabs.org, linux-kernel@vger.kernel.org, linux-i2c@vger.kernel.org, openbmc@lists.ozlabs.org Cc: Open Source Submission , Phong Vo , "Thang Q . Nguyen" Subject: [PATCH v6 1/4] ipmi: ssif_bmc: Add SSIF BMC driver Date: Thu, 10 Mar 2022 18:41:16 +0700 Message-Id: <20220310114119.13736-2-quan@os.amperecomputing.com> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220310114119.13736-1-quan@os.amperecomputing.com> References: <20220310114119.13736-1-quan@os.amperecomputing.com> X-ClientProxiedBy: SG2PR02CA0125.apcprd02.prod.outlook.com (2603:1096:4:188::13) To SJ0PR01MB7282.prod.exchangelabs.com (2603:10b6:a03:3f2::24) MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: e8a3997a-4e52-4386-d092-08da028af8ea X-MS-TrafficTypeDiagnostic: BL0PR01MB4305:EE_ X-Microsoft-Antispam-PRVS: X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: HhA7CxIx1n72js7q2HTjxU4uJOF48oZ+ur6WLYMTRAQGPtRUS5G2bXfnOBWAGvPSUeY9kA8ahdnRvd1kcf/EbCnX89LziCaavrHcb8gmnlMDWUSeQmnFmG1fa6FD5S11xeJBkS2sG8SV4VsWKiOE8RBb8AoGpeU5sDXUpZPJvyAUDTeW+/iVqjFLqtGmsubPP3pN8y7blFYlbVK+L4Ys/DT5lT2zVgV3VGiL4omlyAOCC2zEk2QgUpcQKGeMyWxtqWDnNuIT6mvZ7fOTLgLK60Vd0usHA9VgDeyecMbEMch2KK10tWcl+7UQVPGXDKJXoM5GVNHHqIQms3c2i7WggywYyV6jcen37nVRHzfppLI3q7nCDoMcXyuzUdFF5XSRsGLB5mbGlSw5/zEkbXpgRnc7ZbRIsVKKTOqal4Ith3Z30rEwMd2Ol5agOvbOeSCt2XKJxLctT+0MgyUkKeeUu52SGMvLmPMzCpbb+B+FCa4CtGSkDTXBKywCRCduKJC9PFX9JDzxhhjpl4VwPF1M1d61BfKo2Y3oTXZByANBMRBtnZr9Zaq1hTR1WXP13Ui3Osl0+XlsRE1C+JuAEqQyweLDxtTyA+11/xTLLbToza7NKB1JXzXxPFeStiioCgW7kzxtTQ5UIUd6/r1kpGqJnA7jzWVvFymsKPr8CMb9nbyRAHWJ9+L2XBP6LLH9ieZKow1/QtIsBnnTiVueZ1ynt1/JIUVElSSXhmqsVwvGViM= X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:SJ0PR01MB7282.prod.exchangelabs.com; PTR:; CAT:NONE; SFS:(13230001)(4636009)(366004)(107886003)(6666004)(66556008)(66476007)(66946007)(30864003)(1076003)(5660300002)(2616005)(7416002)(316002)(38350700002)(38100700002)(86362001)(4326008)(8676002)(8936002)(83380400001)(26005)(186003)(921005)(2906002)(52116002)(6512007)(508600001)(110136005)(6506007)(6486002)(54906003); DIR:OUT; SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?YVBvcDZBdXlLV3lVZi94ZFJIQjBCcXNJcDdNMTRMdmYwZ3YyTkZvTmhKU2Rv?= =?utf-8?B?SnlyRSsvaDNQaTVRRkxrWnpaZlRsVENrdFR6Um9aMzV3M0NONDAvb0VMaERq?= =?utf-8?B?U3ZIcWI0V0MydGY0aE9iZjRTa1loWW80NU94WmwySlZOOGxNNVEyTE50VFpE?= =?utf-8?B?VGxrUk9YTjdSemJ0VDhubDJnRjdwdVJuM29hTHJvZzd2T2ZuL1diL0tLQjls?= =?utf-8?B?Zit5bUw5UHBQSHlycVZDbEo4SVdCRFdzZU96STVVcUV2V1FpNm1RbWNya01T?= =?utf-8?B?ajc4dkdIQW1oUmNQelczZytFNlp1UDZJNExzSUUybFJiTnh1RCtmYWxnR1Ey?= =?utf-8?B?Zm9EbENEem85SjlPdWR6c0FSdC9GY2dXM2d4L3ZyQ1JIaUVIYWYrNWsyRGFR?= =?utf-8?B?TXlxYk1EcTR1dzZRcWNLY0FVY0pmWXQyUFRwMUhwU0pTRGpNTjB4ZUZ3Snht?= =?utf-8?B?YUpqU1ZGeHg5V2dkMHRveFR0aXcxa0c1VEFPRVY0MzFlenRLQlBMbThWalVE?= =?utf-8?B?dGR2R2ZZeUh0Z2RIcnJvZDZDVEVNQmdZdFRERHhuZ1N0cVd1NWhuN0RkVHRS?= =?utf-8?B?L2RlU1dHRVlBcnZhYURMbEwrYTI3QW52Y1YySGE1aU1rZDgrTHRzY3FLZWU5?= =?utf-8?B?enNZRjNGdHJ0QjdWNjJMV1U3anRmbk1adW9PY0MzUHJWVGdoQVFnaFYxazBQ?= =?utf-8?B?S2FGZWgrSW9jZVlpUStGVGtpRUhPeXp1SVlDUXM3YzdtRHVTa1FyNlh4aUV1?= =?utf-8?B?VXhtOWkwMkNlTUNDMG1OQWpZb1E3QS9WZHdpa1Q3Zk1RUlhZRVlDU2Flakww?= =?utf-8?B?TldJK2FlbDRuRjhXZDdYZm5sWmVMcXVNSWlGZzBWYU5IQUJ0SGxHZEtqUlla?= =?utf-8?B?a0xQd1NZMlFzcnV5QkY0aWlyTnhXZFZQeVgwNGVvbzByT3FwK0xsR25kSTRk?= =?utf-8?B?cm0zdG1mcVAxRldqTWNkMFk4Q0hWRTZhL05aYkpVOEkxYSs2NzJRQkZDN1k2?= =?utf-8?B?aDhMbHptdlhJNTJ3bWtTeUF5cVIzcUN4bG52OW9XQThWaEx0aHJCOGdGUlda?= =?utf-8?B?eHpNVDdVdGprOTJ3eE9yMHVmK0VpRjZpNnZ0dVZXMzRxOUNBWDhwRXUzenpw?= =?utf-8?B?UGZ4dnVqa21jeThHRU9EWnAyNmxHd3lRdjVMeVFHZlNTZ0FXWXc3dVp2cmFO?= =?utf-8?B?Z0tiM2JMQUp5Z0puUXhlUGtoRnVtR2ppSXdSYmw3VjhqZHlsVWVlay9xUzRW?= =?utf-8?B?cnQxOTllOHFzNjJCcmdJeFRwK1pOL3M4cVBBZDQzWWl5cXJoV1FOTlRYNmxN?= =?utf-8?B?QVBTa0FNU2hRdmhYWkczUzhseUJQYjhLbUljZ1hDOWZ0VHl2NTNJOWFCUzBl?= =?utf-8?B?QXdxZVRQZ3RwSHpMN0ZYdEFCS2VNMlJPK0I4Y0hmVmhqamV6dkcxM0dkdzNa?= =?utf-8?B?TmsrWk5UQ2pUQW5SRGQyUGlsQVQ4RVQ0UzU3VzhoVkw3RGpQWWY2RlY5SHZ3?= =?utf-8?B?OC90d282UUQ0bVoxalNDNjBTaUJqeVFEU0lnS3paTUlFeTc4TTVFQjJhZC9o?= =?utf-8?B?UHBkd3J6dE1mcGpDV2JPU0daN3pqKzNTa3dXa3hIV28xMFBkUjZKV3B1NTVF?= =?utf-8?B?ZmRFMXFHQndqTWhGUFZ1Y3d0bHFHZndmNjVHUmYyNkVTcVFsaVpqRitmUXMz?= =?utf-8?B?K0lvbmFsVmxEUEdMSUxHOUU5VkNremN2bitQYlhBOTdyMlFHdnE2RSsyTjRE?= =?utf-8?B?ZHBYOXRlUmptR0w1cWZUZmc4ajVEZ1FwMnMzbTd1OW41UXFFK2hERE1aNFR0?= =?utf-8?B?WmhrV3h1bjYzZjg0WHl6VThTOXE0aEdyZjh4dmRBa0ZIdXVOSURYRktKaWly?= =?utf-8?B?TWJHSERlVWVwcTl2MDRVT0lIL0tSRkp6QWhkQ0w2MzlzNWRYdW5TSVY2WU1u?= =?utf-8?B?SjZoNFY0eDV6bTNwMUcwZk9IcXl2S3VRd0haZmNIRlp1QUV1YUFFZ0dqbEk0?= =?utf-8?Q?nIy5RFXmTEW49Rcfz6l5HcgIx9mAaI=3D?= X-OriginatorOrg: os.amperecomputing.com X-MS-Exchange-CrossTenant-Network-Message-Id: e8a3997a-4e52-4386-d092-08da028af8ea X-MS-Exchange-CrossTenant-AuthSource: SJ0PR01MB7282.prod.exchangelabs.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 10 Mar 2022 11:41:53.7319 (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: lTbl/p67v9qAS/IHQAeKroXsQ7y9QsDsteDekZKRV+TIjRRD75zxzAr6kHaZDRT9bbCAhpRJRwDbAgF7p9008i5cwHpRyDVytHI2p4JrpEM= X-MS-Exchange-Transport-CrossTenantHeadersStamped: BL0PR01MB4305 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20220310_034158_144512_83B2BBB0 X-CRM114-Status: GOOD ( 20.11 ) 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 cXVhbkBvcy5hbXBlcmVjb21wdXRpbmcuY29tPgotLS0KdjY6CiAgKyBEcm9wIHRoZSB1c2Ugb2Yg c2xhdmVfZW5hYmxlKCkgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFtXb2xmcmFtXQogICsg TWFrZSBpMmMtYXNwZWVkIHRvIGlzc3VlIFJ4Q21kTGFzdCBjb21tYW5kIG9uIGFsbAogIEkyQ19T TEFWRV9XUklURV9SRVFVRVNURUQgZXZlbnQgdG8gYXNzZXJ0IE5BSyB3aGVuIHNsYXZlIGJ1c3kg ICBbUXVhbl0KICArIE1ha2UgaTJjIHNsYXZlIHRvIHJldHVybiAtRUJVU1kgd2hlbiBpdCdzIGJ1 c3kgICAgICAgICAgICAgICAgW1F1YW5dCiAgKyBEcm9wIHRoZSBhYm9ydGluZyBmZWF0dXJlIGFz IHJldHVybiBDb21wbGV0aW9uIENvZGUgMHhGRiBtYXkgc3RvcAogIGhvc3QgdG8gcmV0cnkgYW5k IG1ha2UgaXBtaV9zc2lmLnNvIGZhaWxzIHRvIGxvYWQgICAgICAgICAgICAgICBbUXVhbl0KICAr IEFkZCB0aW1lciB0byByZWNvdmVyIHNsYXZlIGZyb20gYnVzeSBzdGF0ZSB3aGVuIG5vIHJlc3Bv bnNlICAgW1F1YW5dCiAgKyBDbGVhbiByZXF1ZXN0L3Jlc3BvbnNlIGJ1ZmZlciBhcHByb3ByaWF0 ZWx5ICAgICAgICAgICAgICAgICAgIFtRdWFuXQogICsgQWRkIHNvbWUgbWlub3IgY2hhbmdlIG9u IGVycm9yIGFuZCB3YXJuaW5nIG1lc3NhZ2VzICAgICAgICAgICBbUXVhbl0KCnY1OgogICsgTm9u ZQoKdjQ6CiAgKyBTZW5kIHJlc3BvbnNlIHdpdGggQ29tcGxldGlvbiBjb2RlIDB4RkYgd2hlbiBh Ym9ydGluZyAgICAgICAgIFtRdWFuXQogICsgQWRkZWQgYm91bmRpbmcgY2hlY2sgb24gU01CdXMg d3JpdGVzIGFuZCB0aGUgd2hvbGUgcmVxdWVzdCAgICAgW0Rhbl0KICArIE1vdmVkIGJ1ZmZlciB0 byBlbmQgb2Ygc3RydWN0IHNzaWZfYm1jX2N0eCB0byBhdm9pZCBjb250ZXh0CiAgICBjb3JydXB0 aW9uIGlmIHNvbWVob3cgYnVmZmVyIGlzIHdyaXR0ZW4gcGFzdCB0aGUgZW5kICAgICAgICAgICBb RGFuXQogICsgUmV0dXJuIC1FSU5WQUwgaWYgdXNlcnNwYWNlIGJ1ZmZlciB0b28gc21hbGwsIGRv bnQKICAgIHNpbGVuY2UgdHJ1bmNhdGUgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg ICAgICBbQ29yZXksIEpvZWxdCiAgKyBOb3QgbmVjZXNzYXJ5IHRvIGNoZWNrIE5PTkJMT0NLIGlu IGxvY2sgICAgICAgICAgICAgICAgICAgICAgW0NvcmV5XQogICsgRW5mb3JjZSBvbmUgdXNlciBh dCBhIHRpbWUgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBbSm9lbF0KICArIFJl amVjdCB3cml0ZSB3aXRoIGludmFsaWQgcmVzcG9uc2UgbGVuZ3RoIGZyb20gdXNlcnNwYWNlICAg ICBbQ29yZXldCiAgKyBBZGQgc3RhdGUgbWFjaGluZXMgZm9yIGJldHRlciBzc2lmIGJtYyBzdGF0 ZSBoYW5kbGluZyAgICAgICAgIFtRdWFuXQogICsgRHJvcCBzc2lmX2JtY19hc3BlZWQuYyBhbmQg bWFrZSBzc2lmX2JtYy5jIGlzIGdlbmVyaWMKICAgIFNTSUYgQk1DIGRyaXZlciAgICAgICAgICAg ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgW1F1YW5dCiAgKyBDaGFuZ2UgY29t cGF0aWJsZSBzdHJpbmcgImFzcGVlZCxhc3QyNTAwLXNzaWYtYm1jIiB0bwogICAgImFtcGVyZSxz c2lmLWJtYyIgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBbUXVh bl0KICArIEFib3J0IGN1cnJlbnQgcmVxdWVzdCB3aXRoIGludmFsaWQgU01CdXMgd3JpdGUgb3IK ICAgIGludmFsaWQgY29tbWFuZCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg ICAgICAgICAgW1F1YW5dCiAgKyBBYm9ydCBhbGwgcmVxdWVzdCBpZiB0aGVyZSBpcyBwZW5kaW5n IHJlc3BvbnNlICAgICAgICAgICAgICAgIFtRdWFuXQogICsgQ2hhbmdlZCB2YWxpZGF0ZV9wZWMo KSB0byB2YWxpZGF0ZV9yZXF1ZXN0KCkgICAgICAgICAgICAgICAgICBbUXVhbl0KICArIEFkZCB1 bnN1cHBvcnRlZF9zbWJ1c19jbWQoKSB0byBoYW5kbGUgdW5rbm93biBTTUJ1cyBjb21tYW5kICAg W1F1YW5dCiAgKyBQcmludCBpbnRlcm5hbCBzdGF0ZSBzdHJpbmcgZm9yIGVhc2UgaW52ZXN0aWdh dGluZyBpc3N1ZSAgICAgIFtRdWFuXQogICsgTW92ZSB0byBSRUFEWSBzdGF0ZSBvbiBTTEFWRV9T VE9QIGV2ZW50ICAgICAgICAgICAgICAgICAgICAgICBbUXVhbl0KICArIENoYW5nZSBpbml0aWxp emVfdHJhbnNmZXIoKSB0byBwcm9jZXNzX3NtYnVzX2NtZCgpICAgICAgICAgICAgW1F1YW5dCiAg KyBJbnRyb2R1Y2UgZnVuY3Rpb25zIGZvciBlYWNoIHNsYXZlIGV2ZW50ICAgICAgICAgICAgICAg ICAgICAgIFtRdWFuXQoKdjM6CiAgKyBSZW1vdmVkIHJlZHVuZGFudCBsaWNlbnNlIGluZm8gICAg ICAgICAgICAgICAgICAgICAgICAgICAgICAgIFtKb2VsXQogICsgU3dpdGNoZWQgdG8gdXNlIHRy YWRpdGlvbmFsIGlmLWVsc2UgICAgICAgICAgICAgICAgICAgICAgICAgICBbSm9lbF0KICArIFJl bW92ZWQgdW51c2VkIHNzaWZfYm1jX2lvY3RsKCkgICAgICAgICAgICAgICAgICAgICAgICAgICAg ICAgW0pvZWxdCiAgKyBNYWRlIGhhbmRsZV9yZXF1ZXN0KCkvY29tcGxldGVfcmVzcG9uc2UoKSB0 byByZXR1cm4gdm9pZCAgICAgIFtKb2VsXQogICsgUmVmYWN0b3JlZCBzZW5kX3NzaWZfYm1jX3Jl c3BvbnNlKCkgYW5kCiAgcmVjZWl2ZV9zc2lmX2JtY19yZXF1ZXN0KCkgICAgICAgICAgICAgICAg ICAgICAgICAgICAgICAgICAgICAgW0NvcmV5XQogICsgUmVtb3ZlZCBtdXRleCAgICAgICAgICAg ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFtDb3JleV0KICArIFVzZSBzcGlu X2xvY2svdW5sb2NrX2lycXNhdmUvcmVzdG9yZSBpbiBjYWxsYmFjayAgICAgICAgICAgICBbQ29y ZXldCiAgKyBSZW1vdmVkIHRoZSB1bm5lY2Vzc2FyeSBtZW1zZXQgICAgICAgICAgICAgICAgICAg ICAgICAgICAgICAgW0NvcmV5XQogICsgU3dpdGNoIHRvIHVzZSBkZXZfZXJyKCkgICAgICAgICAg ICAgICAgICAgICAgICAgICAgICAgICAgICAgIFtDb3JleV0KCnYyOgogICsgRml4ZWQgY29tcGls aW5nIGVycm9yIHdpdGggQ09NUElMRV9URVNUIGZvciBhcmMKCiBkcml2ZXJzL2NoYXIvaXBtaS9L Y29uZmlnICAgIHwgIDExICsKIGRyaXZlcnMvY2hhci9pcG1pL01ha2VmaWxlICAgfCAgIDEgKwog ZHJpdmVycy9jaGFyL2lwbWkvc3NpZl9ibWMuYyB8IDc5MSArKysrKysrKysrKysrKysrKysrKysr KysrKysrKysrKysrKwogZHJpdmVycy9jaGFyL2lwbWkvc3NpZl9ibWMuaCB8IDEwMiArKysrKwog NCBmaWxlcyBjaGFuZ2VkLCA5MDUgaW5zZXJ0aW9ucygrKQogY3JlYXRlIG1vZGUgMTAwNjQ0IGRy aXZlcnMvY2hhci9pcG1pL3NzaWZfYm1jLmMKIGNyZWF0ZSBtb2RlIDEwMDY0NCBkcml2ZXJzL2No YXIvaXBtaS9zc2lmX2JtYy5oCgpkaWZmIC0tZ2l0IGEvZHJpdmVycy9jaGFyL2lwbWkvS2NvbmZp ZyBiL2RyaXZlcnMvY2hhci9pcG1pL0tjb25maWcKaW5kZXggYjA2MWU2YjUxM2VkLi4xOGE4OTA5 M2Q2NGUgMTAwNjQ0Ci0tLSBhL2RyaXZlcnMvY2hhci9pcG1pL0tjb25maWcKKysrIGIvZHJpdmVy cy9jaGFyL2lwbWkvS2NvbmZpZwpAQCAtMTY5LDYgKzE2OSwxNyBAQCBjb25maWcgQVNQRUVEX0JU X0lQTUlfQk1DCiAJICBmb3VuZCBvbiBBc3BlZWQgU09DcyAoQVNUMjQwMCBhbmQgQVNUMjUwMCku IFRoZSBkcml2ZXIKIAkgIGltcGxlbWVudHMgdGhlIEJNQyBzaWRlIG9mIHRoZSBCVCBpbnRlcmZh Y2UuCiAKK2NvbmZpZyBTU0lGX0lQTUlfQk1DCisJdHJpc3RhdGUgIlNTSUYgSVBNSSBCTUMgZHJp dmVyIgorCXNlbGVjdCBJMkMKKwlzZWxlY3QgSTJDX1NMQVZFCisJaGVscAorCSAgVGhpcyBlbmFi bGVzIHRoZSBJUE1JIFNNQnVzIHN5c3RlbSBpbnRlcmZhY2UgKFNTSUYpIGF0IHRoZQorCSAgbWFu YWdlbWVudCAoQk1DKSBzaWRlLgorCisJICBUaGUgZHJpdmVyIGltcGxlbWVudHMgdGhlIEJNQyBz aWRlIG9mIHRoZSBTTUJ1cyBzeXN0ZW0KKwkgIGludGVyZmFjZSAoU1NJRikuCisKIGNvbmZpZyBJ UE1CX0RFVklDRV9JTlRFUkZBQ0UKIAl0cmlzdGF0ZSAnSVBNQiBJbnRlcmZhY2UgaGFuZGxlcicK IAlkZXBlbmRzIG9uIEkyQwpkaWZmIC0tZ2l0IGEvZHJpdmVycy9jaGFyL2lwbWkvTWFrZWZpbGUg Yi9kcml2ZXJzL2NoYXIvaXBtaS9NYWtlZmlsZQppbmRleCA3Y2U3OTBlZmFkOTIuLmNiNjEzOGI4 ZGVkOSAxMDA2NDQKLS0tIGEvZHJpdmVycy9jaGFyL2lwbWkvTWFrZWZpbGUKKysrIGIvZHJpdmVy cy9jaGFyL2lwbWkvTWFrZWZpbGUKQEAgLTMwLDMgKzMwLDQgQEAgb2JqLSQoQ09ORklHX0FTUEVF RF9CVF9JUE1JX0JNQykgKz0gYnQtYm1jLm8KIG9iai0kKENPTkZJR19BU1BFRURfS0NTX0lQTUlf Qk1DKSArPSBrY3NfYm1jX2FzcGVlZC5vCiBvYmotJChDT05GSUdfTlBDTTdYWF9LQ1NfSVBNSV9C TUMpICs9IGtjc19ibWNfbnBjbTd4eC5vCiBvYmotJChDT05GSUdfSVBNQl9ERVZJQ0VfSU5URVJG QUNFKSArPSBpcG1iX2Rldl9pbnQubworb2JqLSQoQ09ORklHX1NTSUZfSVBNSV9CTUMpICs9IHNz aWZfYm1jLm8KZGlmZiAtLWdpdCBhL2RyaXZlcnMvY2hhci9pcG1pL3NzaWZfYm1jLmMgYi9kcml2 ZXJzL2NoYXIvaXBtaS9zc2lmX2JtYy5jCm5ldyBmaWxlIG1vZGUgMTAwNjQ0CmluZGV4IDAwMDAw MDAwMDAwMC4uNjJkYjk3NzczNjU0Ci0tLSAvZGV2L251bGwKKysrIGIvZHJpdmVycy9jaGFyL2lw bWkvc3NpZl9ibWMuYwpAQCAtMCwwICsxLDc5MSBAQAorLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZp ZXI6IEdQTC0yLjArCisvKgorICogVGhlIGRyaXZlciBmb3IgQk1DIHNpZGUgb2YgU1NJRiBpbnRl cmZhY2UKKyAqCisgKiBDb3B5cmlnaHQgKGMpIDIwMjIsIEFtcGVyZSBDb21wdXRpbmcgTExDCisg KgorICovCisKKyNpbmNsdWRlIDxsaW51eC9pMmMuaD4KKyNpbmNsdWRlIDxsaW51eC9taXNjZGV2 aWNlLmg+CisjaW5jbHVkZSA8bGludXgvbW9kdWxlLmg+CisjaW5jbHVkZSA8bGludXgvb2YuaD4K KyNpbmNsdWRlIDxsaW51eC9wbGF0Zm9ybV9kZXZpY2UuaD4KKyNpbmNsdWRlIDxsaW51eC9wb2xs Lmg+CisjaW5jbHVkZSA8bGludXgvc2NoZWQuaD4KKyNpbmNsdWRlIDxsaW51eC9tdXRleC5oPgor I2luY2x1ZGUgPGxpbnV4L3NwaW5sb2NrLmg+CisjaW5jbHVkZSA8bGludXgvdGltZXIuaD4KKyNp bmNsdWRlIDxsaW51eC9qaWZmaWVzLmg+CisKKyNpbmNsdWRlICJzc2lmX2JtYy5oIgorCitzdGF0 aWMgY29uc3QgY2hhciAqc3RhdGVfdG9fc3RyaW5nKGVudW0gc3NpZl9zdGF0ZSBzdGF0ZSkKK3sK Kwlzd2l0Y2ggKHN0YXRlKSB7CisJY2FzZSBTU0lGX1JFQURZOgorCQlyZXR1cm4gIlNTSUZfUkVB RFkiOworCWNhc2UgU1NJRl9TVEFSVDoKKwkJcmV0dXJuICJTU0lGX1NUQVJUIjsKKwljYXNlIFNT SUZfU01CVVNfQ01EOgorCQlyZXR1cm4gIlNTSUZfU01CVVNfQ01EIjsKKwljYXNlIFNTSUZfUkVR X1JFQ1ZJTkc6CisJCXJldHVybiAiU1NJRl9SRVFfUkVDVklORyI7CisJY2FzZSBTU0lGX1JFU19T RU5ESU5HOgorCQlyZXR1cm4gIlNTSUZfUkVTX1NFTkRJTkciOworCWNhc2UgU1NJRl9CQURfU01C VVM6CisJCXJldHVybiAiU1NJRl9CQURfU01CVVMiOworCWRlZmF1bHQ6CisJCXJldHVybiAiU1NJ Rl9TVEFURV9VTktOT1dOIjsKKwl9Cit9CisKKy8qIEhhbmRsZSBTU0lGIG1lc3NhZ2UgdGhhdCB3 aWxsIGJlIHNlbnQgdG8gdXNlciAqLworc3RhdGljIHNzaXplX3Qgc3NpZl9ibWNfcmVhZChzdHJ1 Y3QgZmlsZSAqZmlsZSwgY2hhciBfX3VzZXIgKmJ1Ziwgc2l6ZV90IGNvdW50LCBsb2ZmX3QgKnBw b3MpCit7CisJc3RydWN0IHNzaWZfYm1jX2N0eCAqc3NpZl9ibWMgPSB0b19zc2lmX2JtYyhmaWxl KTsKKwlzdHJ1Y3Qgc3NpZl9tc2cgbXNnOworCXVuc2lnbmVkIGxvbmcgZmxhZ3M7CisJc3NpemVf dCByZXQ7CisKKwlzcGluX2xvY2tfaXJxc2F2ZSgmc3NpZl9ibWMtPmxvY2ssIGZsYWdzKTsKKwl3 aGlsZSAoIXNzaWZfYm1jLT5yZXF1ZXN0X2F2YWlsYWJsZSkgeworCQlzcGluX3VubG9ja19pcnFy ZXN0b3JlKCZzc2lmX2JtYy0+bG9jaywgZmxhZ3MpOworCQlpZiAoZmlsZS0+Zl9mbGFncyAmIE9f Tk9OQkxPQ0spCisJCQlyZXR1cm4gLUVBR0FJTjsKKwkJcmV0ID0gd2FpdF9ldmVudF9pbnRlcnJ1 cHRpYmxlKHNzaWZfYm1jLT53YWl0X3F1ZXVlLAorCQkJCQkgICAgICAgc3NpZl9ibWMtPnJlcXVl c3RfYXZhaWxhYmxlKTsKKwkJaWYgKHJldCkKKwkJCXJldHVybiByZXQ7CisJCXNwaW5fbG9ja19p cnFzYXZlKCZzc2lmX2JtYy0+bG9jaywgZmxhZ3MpOworCX0KKworCWlmIChjb3VudCA8IG1pbl90 KHNzaXplX3QsIHNzaWZfbXNnX2xlbigmc3NpZl9ibWMtPnJlcXVlc3QpLCBzaXplb2Yoc3RydWN0 IHNzaWZfbXNnKSkpIHsKKwkJc3Bpbl91bmxvY2tfaXJxcmVzdG9yZSgmc3NpZl9ibWMtPmxvY2ss IGZsYWdzKTsKKwkJcmV0ID0gLUVJTlZBTDsKKwl9IGVsc2UgeworCQljb3VudCA9IG1pbl90KHNz aXplX3QsIHNzaWZfbXNnX2xlbigmc3NpZl9ibWMtPnJlcXVlc3QpLCBzaXplb2Yoc3RydWN0IHNz aWZfbXNnKSk7CisJCW1lbWNweSgmbXNnLCAmc3NpZl9ibWMtPnJlcXVlc3QsIGNvdW50KTsKKwkJ c3NpZl9ibWMtPnJlcXVlc3RfYXZhaWxhYmxlID0gZmFsc2U7CisJCXNwaW5fdW5sb2NrX2lycXJl c3RvcmUoJnNzaWZfYm1jLT5sb2NrLCBmbGFncyk7CisKKwkJcmV0ID0gY29weV90b191c2VyKGJ1 ZiwgJm1zZywgY291bnQpOworCX0KKworCXJldHVybiAocmV0IDwgMCkgPyByZXQgOiBjb3VudDsK K30KKworLyogSGFuZGxlIFNTSUYgbWVzc2FnZSB0aGF0IGlzIHdyaXR0ZW4gYnkgdXNlciAqLwor c3RhdGljIHNzaXplX3Qgc3NpZl9ibWNfd3JpdGUoc3RydWN0IGZpbGUgKmZpbGUsIGNvbnN0IGNo YXIgX191c2VyICpidWYsIHNpemVfdCBjb3VudCwKKwkJCSAgICAgIGxvZmZfdCAqcHBvcykKK3sK KwlzdHJ1Y3Qgc3NpZl9ibWNfY3R4ICpzc2lmX2JtYyA9IHRvX3NzaWZfYm1jKGZpbGUpOworCXN0 cnVjdCBzc2lmX21zZyBtc2c7CisJdW5zaWduZWQgbG9uZyBmbGFnczsKKwlzc2l6ZV90IHJldDsK KworCWlmIChjb3VudCA+IHNpemVvZihzdHJ1Y3Qgc3NpZl9tc2cpKQorCQlyZXR1cm4gLUVJTlZB TDsKKworCXJldCA9IGNvcHlfZnJvbV91c2VyKCZtc2csIGJ1ZiwgY291bnQpOworCWlmIChyZXQp CisJCXJldHVybiByZXQ7CisKKwlpZiAoIW1zZy5sZW4gfHwgY291bnQgPCBzc2lmX21zZ19sZW4o Jm1zZykpCisJCXJldHVybiAtRUlOVkFMOworCisJc3Bpbl9sb2NrX2lycXNhdmUoJnNzaWZfYm1j LT5sb2NrLCBmbGFncyk7CisJd2hpbGUgKHNzaWZfYm1jLT5yZXNwb25zZV9pbl9wcm9ncmVzcykg eworCQlzcGluX3VubG9ja19pcnFyZXN0b3JlKCZzc2lmX2JtYy0+bG9jaywgZmxhZ3MpOworCQlp ZiAoZmlsZS0+Zl9mbGFncyAmIE9fTk9OQkxPQ0spCisJCQlyZXR1cm4gLUVBR0FJTjsKKwkJcmV0 ID0gd2FpdF9ldmVudF9pbnRlcnJ1cHRpYmxlKHNzaWZfYm1jLT53YWl0X3F1ZXVlLAorCQkJCQkg ICAgICAgIXNzaWZfYm1jLT5yZXNwb25zZV9pbl9wcm9ncmVzcyk7CisJCWlmIChyZXQpCisJCQly ZXR1cm4gcmV0OworCQlzcGluX2xvY2tfaXJxc2F2ZSgmc3NpZl9ibWMtPmxvY2ssIGZsYWdzKTsK Kwl9CisKKwltZW1jcHkoJnNzaWZfYm1jLT5yZXNwb25zZSwgJm1zZywgY291bnQpOworCXNzaWZf Ym1jLT5pc19zaW5nbGVwYXJ0X3JlYWQgPSAoc3NpZl9tc2dfbGVuKCZtc2cpIDw9IE1BWF9QQVlM T0FEX1BFUl9UUkFOU0FDVElPTiArIDEpOworCisJc3NpZl9ibWMtPnJlc3BvbnNlX2luX3Byb2dy ZXNzID0gdHJ1ZTsKKworCS8qIHNzaWZfYm1jIG5vdCBidXN5ICovCisJc3NpZl9ibWMtPmJ1c3kg PSBmYWxzZTsKKworCWlmIChzc2lmX2JtYy0+cmVzcG9uc2VfdGltZXJfaW5pdGVkKSB7CisJCWRl bF90aW1lcigmc3NpZl9ibWMtPnJlc3BvbnNlX3RpbWVyKTsKKwkJc3NpZl9ibWMtPnJlc3BvbnNl X3RpbWVyX2luaXRlZCA9IGZhbHNlOworCX0KKwkvKiBDbGVhbiBvbGQgcmVxdWVzdCBidWZmZXIg Ki8KKwltZW1zZXQoJnNzaWZfYm1jLT5yZXF1ZXN0LCAwLCBzaXplb2Yoc3RydWN0IHNzaWZfbXNn KSk7CisKKwlzcGluX3VubG9ja19pcnFyZXN0b3JlKCZzc2lmX2JtYy0+bG9jaywgZmxhZ3MpOwor CisJcmV0dXJuIGNvdW50OworfQorCitzdGF0aWMgaW50IHNzaWZfYm1jX29wZW4oc3RydWN0IGlu b2RlICppbm9kZSwgc3RydWN0IGZpbGUgKmZpbGUpCit7CisJc3RydWN0IHNzaWZfYm1jX2N0eCAq c3NpZl9ibWMgPSB0b19zc2lmX2JtYyhmaWxlKTsKKwlpbnQgcmV0ID0gMDsKKworCXNwaW5fbG9j a19pcnEoJnNzaWZfYm1jLT5sb2NrKTsKKwlpZiAoIXNzaWZfYm1jLT5ydW5uaW5nKQorCQlzc2lm X2JtYy0+cnVubmluZyA9IDE7CisJZWxzZQorCQlyZXQgPSAtRUJVU1k7CisJc3Bpbl91bmxvY2tf aXJxKCZzc2lmX2JtYy0+bG9jayk7CisKKwlyZXR1cm4gcmV0OworfQorCitzdGF0aWMgdW5zaWdu ZWQgaW50IHNzaWZfYm1jX3BvbGwoc3RydWN0IGZpbGUgKmZpbGUsIHBvbGxfdGFibGUgKndhaXQp Cit7CisJc3RydWN0IHNzaWZfYm1jX2N0eCAqc3NpZl9ibWMgPSB0b19zc2lmX2JtYyhmaWxlKTsK Kwl1bnNpZ25lZCBpbnQgbWFzayA9IDA7CisKKwlwb2xsX3dhaXQoZmlsZSwgJnNzaWZfYm1jLT53 YWl0X3F1ZXVlLCB3YWl0KTsKKworCXNwaW5fbG9ja19pcnEoJnNzaWZfYm1jLT5sb2NrKTsKKwkv KiBUaGUgcmVxdWVzdCBpcyBhdmFpbGFibGUsIHVzZXJzcGFjZSBhcHBsaWNhdGlvbiBjYW4gZ2V0 IHRoZSByZXF1ZXN0ICovCisJaWYgKHNzaWZfYm1jLT5yZXF1ZXN0X2F2YWlsYWJsZSkKKwkJbWFz ayB8PSBQT0xMSU47CisKKwlzcGluX3VubG9ja19pcnEoJnNzaWZfYm1jLT5sb2NrKTsKKworCXJl dHVybiBtYXNrOworfQorCitzdGF0aWMgaW50IHNzaWZfYm1jX3JlbGVhc2Uoc3RydWN0IGlub2Rl ICppbm9kZSwgc3RydWN0IGZpbGUgKmZpbGUpCit7CisJc3RydWN0IHNzaWZfYm1jX2N0eCAqc3Np Zl9ibWMgPSB0b19zc2lmX2JtYyhmaWxlKTsKKworCXNwaW5fbG9ja19pcnEoJnNzaWZfYm1jLT5s b2NrKTsKKwlzc2lmX2JtYy0+cnVubmluZyA9IDA7CisJc3Bpbl91bmxvY2tfaXJxKCZzc2lmX2Jt Yy0+bG9jayk7CisKKwlyZXR1cm4gMDsKK30KKworLyoKKyAqIFN5c3RlbSBjYWxscyB0byBkZXZp Y2UgaW50ZXJmYWNlIGZvciB1c2VyIGFwcHMKKyAqLworc3RhdGljIGNvbnN0IHN0cnVjdCBmaWxl X29wZXJhdGlvbnMgc3NpZl9ibWNfZm9wcyA9IHsKKwkub3duZXIJCT0gVEhJU19NT0RVTEUsCisJ Lm9wZW4JCT0gc3NpZl9ibWNfb3BlbiwKKwkucmVhZAkJPSBzc2lmX2JtY19yZWFkLAorCS53cml0 ZQkJPSBzc2lmX2JtY193cml0ZSwKKwkucmVsZWFzZQk9IHNzaWZfYm1jX3JlbGVhc2UsCisJLnBv bGwJCT0gc3NpZl9ibWNfcG9sbCwKK307CisKKy8qIENhbGxlZCB3aXRoIHNzaWZfYm1jLT5sb2Nr IGhlbGQuICovCitzdGF0aWMgdm9pZCBjb21wbGV0ZV9yZXNwb25zZShzdHJ1Y3Qgc3NpZl9ibWNf Y3R4ICpzc2lmX2JtYykKK3sKKwkvKiBJbnZhbGlkYXRlIHJlc3BvbnNlIGluIGJ1ZmZlciB0byBk ZW5vdGUgaXQgaGF2aW5nIGJlZW4gc2VudC4gKi8KKwlzc2lmX2JtYy0+cmVzcG9uc2UubGVuID0g MDsKKwlzc2lmX2JtYy0+cmVzcG9uc2VfaW5fcHJvZ3Jlc3MgPSBmYWxzZTsKKwlzc2lmX2JtYy0+ bmJ5dGVzX3Byb2Nlc3NlZCA9IDA7CisJc3NpZl9ibWMtPnJlbWFpbl9sZW4gPSAwOworCXNzaWZf Ym1jLT5idXN5ID0gZmFsc2U7CisJbWVtc2V0KCZzc2lmX2JtYy0+cmVzcG9uc2VfYnVmLCAwLCBN QVhfUEFZTE9BRF9QRVJfVFJBTlNBQ1RJT04pOworCXdha2VfdXBfYWxsKCZzc2lmX2JtYy0+d2Fp dF9xdWV1ZSk7Cit9CisKK3N0YXRpYyB2b2lkIHJlc3BvbnNlX3RpbWVvdXQoc3RydWN0IHRpbWVy X2xpc3QgKnQpCit7CisJc3RydWN0IHNzaWZfYm1jX2N0eCAqc3NpZl9ibWMgPSBmcm9tX3RpbWVy KHNzaWZfYm1jLCB0LCByZXNwb25zZV90aW1lcik7CisJdW5zaWduZWQgbG9uZyBmbGFnczsKKwor CXNwaW5fbG9ja19pcnFzYXZlKCZzc2lmX2JtYy0+bG9jaywgZmxhZ3MpOworCisJLyogUmVjb3Zl ciBzc2lmX2JtYyBmcm9tIGJ1c3kgKi8KKwlzc2lmX2JtYy0+YnVzeSA9IGZhbHNlOworCWRlbF90 aW1lcigmc3NpZl9ibWMtPnJlc3BvbnNlX3RpbWVyKTsKKwlzc2lmX2JtYy0+cmVzcG9uc2VfdGlt ZXJfaW5pdGVkID0gZmFsc2U7CisKKwlzcGluX3VubG9ja19pcnFyZXN0b3JlKCZzc2lmX2JtYy0+ bG9jaywgZmxhZ3MpOworfQorCisvKiBDYWxsZWQgd2l0aCBzc2lmX2JtYy0+bG9jayBoZWxkLiAq Lworc3RhdGljIHZvaWQgaGFuZGxlX3JlcXVlc3Qoc3RydWN0IHNzaWZfYm1jX2N0eCAqc3NpZl9i bWMpCit7CisJLyogc2V0IHNzaWZfYm1jIHRvIGJ1c3kgd2FpdGluZyBmb3IgcmVzcG9uc2UgKi8K Kwlzc2lmX2JtYy0+YnVzeSA9IHRydWU7CisKKwkvKiBSZXF1ZXN0IG1lc3NhZ2UgaXMgYXZhaWxh YmxlIHRvIHByb2Nlc3MgKi8KKwlzc2lmX2JtYy0+cmVxdWVzdF9hdmFpbGFibGUgPSB0cnVlOwor CisJLyogQ2xlYW4gb2xkIHJlc3BvbnNlIGJ1ZmZlciAqLworCW1lbXNldCgmc3NpZl9ibWMtPnJl c3BvbnNlLCAwLCBzaXplb2Yoc3RydWN0IHNzaWZfbXNnKSk7CisKKwkvKiBUaGlzIGlzIHRoZSBu ZXcgUkVBRCByZXF1ZXN0LiovCisJd2FrZV91cF9hbGwoJnNzaWZfYm1jLT53YWl0X3F1ZXVlKTsK KworCS8qIEFybWVkIHRpbWVyIHRvIHJlY292ZXIgc2xhdmUgZnJvbSBidXN5IHN0YXRlIGluIGNh c2Ugb2Ygbm8gcmVzcG9uc2UgKi8KKwlpZiAoIXNzaWZfYm1jLT5yZXNwb25zZV90aW1lcl9pbml0 ZWQpIHsKKwkJdGltZXJfc2V0dXAoJnNzaWZfYm1jLT5yZXNwb25zZV90aW1lciwgcmVzcG9uc2Vf dGltZW91dCwgMCk7CisJCXNzaWZfYm1jLT5yZXNwb25zZV90aW1lcl9pbml0ZWQgPSB0cnVlOwor CX0KKwltb2RfdGltZXIoJnNzaWZfYm1jLT5yZXNwb25zZV90aW1lciwgamlmZmllcyArIG1zZWNz X3RvX2ppZmZpZXMoUkVTUE9OU0VfVElNRU9VVCkpOworfQorCitzdGF0aWMgdm9pZCBzZXRfbXVs dGlwYXJ0X3Jlc3BvbnNlX2J1ZmZlcihzdHJ1Y3Qgc3NpZl9ibWNfY3R4ICpzc2lmX2JtYywgdTgg KnZhbCkKK3sKKwl1OCByZXNwb25zZV9sZW4gPSAwOworCWludCBpZHggPSAwOworCXU4IGRhdGFf bGVuOworCisJZGF0YV9sZW4gPSBzc2lmX2JtYy0+cmVzcG9uc2UubGVuOworCXN3aXRjaCAoc3Np Zl9ibWMtPnNtYnVzX2NtZCkgeworCWNhc2UgU1NJRl9JUE1JX01VTFRJUEFSVF9SRUFEX1NUQVJU OgorCQkvKgorCQkgKiBSZWFkIFN0YXJ0IGxlbmd0aCBpcyAzMiBieXRlcy4KKwkJICogUmVhZCBT dGFydCB0cmFuc2ZlciBmaXJzdCAzMCBieXRlcyBvZiBJUE1JIHJlc3BvbnNlCisJCSAqIGFuZCAy IHNwZWNpYWwgY29kZSAweDAwLCAweDAxLgorCQkgKi8KKwkJKnZhbCA9IE1BWF9QQVlMT0FEX1BF Ul9UUkFOU0FDVElPTjsKKwkJc3NpZl9ibWMtPnJlbWFpbl9sZW4gPSBkYXRhX2xlbiAtIE1BWF9J UE1JX0RBVEFfUEVSX1NUQVJUX1RSQU5TQUNUSU9OOworCQlzc2lmX2JtYy0+YmxvY2tfbnVtID0g MDsKKworCQlzc2lmX2JtYy0+cmVzcG9uc2VfYnVmW2lkeCsrXSA9IDB4MDA7IC8qIFN0YXJ0IEZs YWcgKi8KKwkJc3NpZl9ibWMtPnJlc3BvbnNlX2J1ZltpZHgrK10gPSAweDAxOyAvKiBTdGFydCBG bGFnICovCisJCXNzaWZfYm1jLT5yZXNwb25zZV9idWZbaWR4KytdID0gc3NpZl9ibWMtPnJlc3Bv bnNlLm5ldGZuX2x1bjsKKwkJc3NpZl9ibWMtPnJlc3BvbnNlX2J1ZltpZHgrK10gPSBzc2lmX2Jt Yy0+cmVzcG9uc2UuY21kOworCQlzc2lmX2JtYy0+cmVzcG9uc2VfYnVmW2lkeCsrXSA9IHNzaWZf Ym1jLT5yZXNwb25zZS5wYXlsb2FkWzBdOworCisJCXJlc3BvbnNlX2xlbiA9IE1BWF9QQVlMT0FE X1BFUl9UUkFOU0FDVElPTiAtIGlkeDsKKworCQltZW1jcHkoJnNzaWZfYm1jLT5yZXNwb25zZV9i dWZbaWR4XSwgJnNzaWZfYm1jLT5yZXNwb25zZS5wYXlsb2FkWzFdLAorCQkgICAgICAgcmVzcG9u c2VfbGVuKTsKKwkJYnJlYWs7CisKKwljYXNlIFNTSUZfSVBNSV9NVUxUSVBBUlRfUkVBRF9NSURE TEU6CisJCS8qCisJCSAqIElQTUkgUkVBRCBNaWRkbGUgb3IgUkVBRCBFbmQgbWVzc2FnZXMgY2Fu IGNhcnJ5IHVwIHRvIDMxIGJ5dGVzCisJCSAqIElQTUkgZGF0YSBwbHVzIGJsb2NrIG51bWJlciBi eXRlLgorCQkgKi8KKwkJaWYgKHNzaWZfYm1jLT5yZW1haW5fbGVuIDwgTUFYX0lQTUlfREFUQV9Q RVJfTUlERExFX1RSQU5TQUNUSU9OKSB7CisJCQkvKgorCQkJICogVGhpcyBpcyBSRUFEIEVuZCBt ZXNzYWdlCisJCQkgKiAgUmV0dXJuIGxlbmd0aCBpcyB0aGUgcmVtYWluaW5nIHJlc3BvbnNlIGRh dGEgbGVuZ3RoCisJCQkgKiAgcGx1cyBibG9jayBudW1iZXIKKwkJCSAqICBCbG9jayBudW1iZXIg MHhGRiBpcyB0byBpbmRpY2F0ZSB0aGlzIGlzIGxhc3QgbWVzc2FnZQorCQkJICoKKwkJCSAqLwor CQkJKnZhbCA9IHNzaWZfYm1jLT5yZW1haW5fbGVuICsgMTsKKwkJCXNzaWZfYm1jLT5ibG9ja19u dW0gPSAweEZGOworCQkJc3NpZl9ibWMtPnJlc3BvbnNlX2J1ZltpZHgrK10gPSBzc2lmX2JtYy0+ YmxvY2tfbnVtOworCQkJcmVzcG9uc2VfbGVuID0gc3NpZl9ibWMtPnJlbWFpbl9sZW47CisJCQkv KiBDbGVhbiB0aGUgYnVmZmVyICovCisJCQltZW1zZXQoJnNzaWZfYm1jLT5yZXNwb25zZV9idWZb aWR4XSwgMCwgTUFYX1BBWUxPQURfUEVSX1RSQU5TQUNUSU9OIC0gaWR4KTsKKwkJfSBlbHNlIHsK KwkJCS8qCisJCQkgKiBUaGlzIGlzIFJFQUQgTWlkZGxlIG1lc3NhZ2UKKwkJCSAqICBSZXNwb25z ZSBsZW5ndGggaXMgdGhlIG1heGltdW0gU01CVVMgdHJhbnNmZXIgbGVuZ3RoCisJCQkgKiAgQmxv Y2sgbnVtYmVyIGJ5dGUgaXMgaW5jcmVtZW50ZWQKKwkJCSAqIFJldHVybiBsZW5ndGggaXMgbWF4 aW11bSBTTUJVUyB0cmFuc2ZlciBsZW5ndGgKKwkJCSAqLworCQkJKnZhbCA9IE1BWF9QQVlMT0FE X1BFUl9UUkFOU0FDVElPTjsKKwkJCXNzaWZfYm1jLT5yZW1haW5fbGVuIC09IE1BWF9JUE1JX0RB VEFfUEVSX01JRERMRV9UUkFOU0FDVElPTjsKKwkJCXJlc3BvbnNlX2xlbiA9IE1BWF9JUE1JX0RB VEFfUEVSX01JRERMRV9UUkFOU0FDVElPTjsKKwkJCXNzaWZfYm1jLT5yZXNwb25zZV9idWZbaWR4 KytdID0gc3NpZl9ibWMtPmJsb2NrX251bTsKKwkJCXNzaWZfYm1jLT5ibG9ja19udW0rKzsKKwkJ fQorCisJCW1lbWNweSgmc3NpZl9ibWMtPnJlc3BvbnNlX2J1ZltpZHhdLAorCQkgICAgICAgc3Np Zl9ibWMtPnJlc3BvbnNlLnBheWxvYWQgKyAxICsgc3NpZl9ibWMtPm5ieXRlc19wcm9jZXNzZWQs CisJCSAgICAgICByZXNwb25zZV9sZW4pOworCQlicmVhazsKKworCWRlZmF1bHQ6CisJCS8qIERv IG5vdCBleHBlY3QgdG8gZ28gdG8gdGhpcyBjYXNlICovCisJCWRldl9lcnIoJnNzaWZfYm1jLT5j bGllbnQtPmRldiwKKwkJCSIlczogVW5leHBlY3RlZCBTTUJ1cyBjb21tYW5kIDB4JXhcbiIsCisJ CQlfX2Z1bmNfXywgc3NpZl9ibWMtPnNtYnVzX2NtZCk7CisJCWJyZWFrOworCX0KKworCXNzaWZf Ym1jLT5uYnl0ZXNfcHJvY2Vzc2VkICs9IHJlc3BvbnNlX2xlbjsKK30KKworLyogUHJvY2VzcyB0 aGUgSVBNSSByZXNwb25zZSB0aGF0IHdpbGwgYmUgcmVhZCBieSBtYXN0ZXIgKi8KK3N0YXRpYyB2 b2lkIGhhbmRsZV9yZWFkX3Byb2Nlc3NlZChzdHJ1Y3Qgc3NpZl9ibWNfY3R4ICpzc2lmX2JtYywg dTggKnZhbCkKK3sKKwl1OCAqYnVmOworCXU4IHBlY19sZW4sIGFkZHIsIGxlbjsKKwl1OCBwZWMg PSAwOworCisJcGVjX2xlbiA9IHNzaWZfYm1jLT5wZWNfc3VwcG9ydCA/IDEgOiAwOworCS8qIFBF QyAtIFN0YXJ0IFJlYWQgQWRkcmVzcyAqLworCWFkZHIgPSBHRVRfOEJJVF9BRERSKHNzaWZfYm1j LT5jbGllbnQtPmFkZHIpOworCXBlYyA9IGkyY19zbWJ1c19wZWMocGVjLCAmYWRkciwgMSk7CisJ LyogUEVDIC0gU1NJRiBDb21tYW5kICovCisJcGVjID0gaTJjX3NtYnVzX3BlYyhwZWMsICZzc2lm X2JtYy0+c21idXNfY21kLCAxKTsKKwkvKiBQRUMgLSBSZXN0YXJ0IFdyaXRlIEFkZHJlc3MgKi8K KwlhZGRyID0gYWRkciB8IDB4MDE7CisJcGVjID0gaTJjX3NtYnVzX3BlYyhwZWMsICZhZGRyLCAx KTsKKworCWlmIChzc2lmX2JtYy0+aXNfc2luZ2xlcGFydF9yZWFkKSB7CisJCS8qIFNpbmdsZS1w YXJ0IFJlYWQgcHJvY2Vzc2luZyAqLworCQlidWYgPSAodTggKikmc3NpZl9ibWMtPnJlc3BvbnNl OworCisJCWlmIChzc2lmX2JtYy0+cmVzcG9uc2UubGVuICYmIHNzaWZfYm1jLT5tc2dfaWR4IDwg c3NpZl9ibWMtPnJlc3BvbnNlLmxlbikgeworCQkJc3NpZl9ibWMtPm1zZ19pZHgrKzsKKwkJCSp2 YWwgPSBidWZbc3NpZl9ibWMtPm1zZ19pZHhdOworCQl9IGVsc2UgaWYgKHNzaWZfYm1jLT5yZXNw b25zZS5sZW4gJiYgc3NpZl9ibWMtPm1zZ19pZHggPT0gc3NpZl9ibWMtPnJlc3BvbnNlLmxlbikg eworCQkJc3NpZl9ibWMtPm1zZ19pZHgrKzsKKwkJCSp2YWwgPSBpMmNfc21idXNfcGVjKHBlYywg YnVmLCBzc2lmX21zZ19sZW4oJnNzaWZfYm1jLT5yZXNwb25zZSkpOworCQl9IGVsc2UgeworCQkJ KnZhbCA9IDA7CisJCX0KKwkJLyogSW52YWxpZGF0ZSByZXNwb25zZSBidWZmZXIgdG8gZGVub3Rl IGl0IGlzIHNlbnQgKi8KKwkJaWYgKHNzaWZfYm1jLT5tc2dfaWR4ICsgMSA+PSAoc3NpZl9tc2df bGVuKCZzc2lmX2JtYy0+cmVzcG9uc2UpICsgcGVjX2xlbikpCisJCQljb21wbGV0ZV9yZXNwb25z ZShzc2lmX2JtYyk7CisJfSBlbHNlIHsKKwkJLyogTXVsdGktcGFydCBSZWFkIHByb2Nlc3Npbmcg Ki8KKwkJc3dpdGNoIChzc2lmX2JtYy0+c21idXNfY21kKSB7CisJCWNhc2UgU1NJRl9JUE1JX01V TFRJUEFSVF9SRUFEX1NUQVJUOgorCQljYXNlIFNTSUZfSVBNSV9NVUxUSVBBUlRfUkVBRF9NSURE TEU6CisJCQlidWYgPSAodTggKikmc3NpZl9ibWMtPnJlc3BvbnNlX2J1ZjsKKwkJCSp2YWwgPSBi dWZbc3NpZl9ibWMtPm1zZ19pZHhdOworCQkJc3NpZl9ibWMtPm1zZ19pZHgrKzsKKwkJCWJyZWFr OworCQlkZWZhdWx0OgorCQkJLyogRG8gbm90IGV4cGVjdCB0byBnbyB0byB0aGlzIGNhc2UgKi8K KwkJCWRldl9lcnIoJnNzaWZfYm1jLT5jbGllbnQtPmRldiwKKwkJCQkiJXM6IFVuZXhwZWN0ZWQg U01CdXMgY29tbWFuZCAweCV4XG4iLAorCQkJCV9fZnVuY19fLCBzc2lmX2JtYy0+c21idXNfY21k KTsKKwkJCWJyZWFrOworCQl9CisKKwkJbGVuID0gKHNzaWZfYm1jLT5ibG9ja19udW0gPT0gMHhG RikgPworCQkgICAgICAgc3NpZl9ibWMtPnJlbWFpbl9sZW4gKyAxIDogTUFYX1BBWUxPQURfUEVS X1RSQU5TQUNUSU9OOworCQlpZiAoc3NpZl9ibWMtPm1zZ19pZHggPT0gKGxlbiArIDEpKSB7CisJ CQlwZWMgPSBpMmNfc21idXNfcGVjKHBlYywgJmxlbiwgMSk7CisJCQkqdmFsID0gaTJjX3NtYnVz X3BlYyhwZWMsIHNzaWZfYm1jLT5yZXNwb25zZV9idWYsIGxlbik7CisJCX0KKwkJLyogSW52YWxp ZGF0ZSByZXNwb25zZSBidWZmZXIgdG8gZGVub3RlIGxhc3QgcmVzcG9uc2UgaXMgc2VudCAqLwor CQlpZiAoc3NpZl9ibWMtPmJsb2NrX251bSA9PSAweEZGICYmCisJCSAgICBzc2lmX2JtYy0+bXNn X2lkeCA+IChzc2lmX2JtYy0+cmVtYWluX2xlbiArIHBlY19sZW4pKSB7CisJCQljb21wbGV0ZV9y ZXNwb25zZShzc2lmX2JtYyk7CisJCX0KKwl9Cit9CisKK3N0YXRpYyB2b2lkIGhhbmRsZV93cml0 ZV9yZWNlaXZlZChzdHJ1Y3Qgc3NpZl9ibWNfY3R4ICpzc2lmX2JtYywgdTggKnZhbCkKK3sKKwl1 OCAqYnVmID0gKHU4ICopJnNzaWZfYm1jLT5yZXF1ZXN0OworCisJaWYgKHNzaWZfYm1jLT5tc2df aWR4ID49IHNpemVvZihzdHJ1Y3Qgc3NpZl9tc2cpKQorCQlyZXR1cm47CisKKwlzd2l0Y2ggKHNz aWZfYm1jLT5zbWJ1c19jbWQpIHsKKwljYXNlIFNTSUZfSVBNSV9TSU5HTEVQQVJUX1dSSVRFOgor CQlidWZbc3NpZl9ibWMtPm1zZ19pZHggLSAxXSA9ICp2YWw7CisJCXNzaWZfYm1jLT5tc2dfaWR4 Kys7CisKKwkJYnJlYWs7CisJY2FzZSBTU0lGX0lQTUlfTVVMVElQQVJUX1dSSVRFX1NUQVJUOgor CQlpZiAoc3NpZl9ibWMtPm1zZ19pZHggPT0gMSkKKwkJCXNzaWZfYm1jLT5yZXF1ZXN0LmxlbiA9 IDA7CisKKwkJZmFsbHRocm91Z2g7CisJY2FzZSBTU0lGX0lQTUlfTVVMVElQQVJUX1dSSVRFX01J RERMRToKKwkJLyogVGhlIGxlbiBzaG91bGQgYWx3YXlzIGJlIDMyICovCisJCWlmIChzc2lmX2Jt Yy0+bXNnX2lkeCA9PSAxICYmICp2YWwgIT0gTUFYX1BBWUxPQURfUEVSX1RSQU5TQUNUSU9OKQor CQkJZGV2X3dhcm4oJnNzaWZfYm1jLT5jbGllbnQtPmRldiwKKwkJCQkgIldhcm46IEludmFsaWQg TXVsdGlwYXJ0IFdyaXRlIGxlbiIpOworCisJCWZhbGx0aHJvdWdoOworCWNhc2UgU1NJRl9JUE1J X01VTFRJUEFSVF9XUklURV9FTkQ6CisJCS8qIE11bHRpLXBhcnQgd3JpdGUsIDJuZCBieXRlIHJl Y2VpdmVkIGlzIGxlbmd0aCAqLworCQlpZiAoc3NpZl9ibWMtPm1zZ19pZHggPT0gMSkgeworCQkJ aWYgKCp2YWwgPiBNQVhfUEFZTE9BRF9QRVJfVFJBTlNBQ1RJT04pCisJCQkJZGV2X3dhcm4oJnNz aWZfYm1jLT5jbGllbnQtPmRldiwKKwkJCQkJICJXYXJuOiBJbnZhbGlkIE11bHRpcGFydCBXcml0 ZSBFbmQgbGVuIik7CisKKwkJCXNzaWZfYm1jLT5yZXF1ZXN0LmxlbiArPSAqdmFsOworCQkJc3Np Zl9ibWMtPnJlY3ZfbGVuID0gKnZhbDsKKworCQkJLyogcmVxdWVzdCBsZW4gc2hvdWxkIG5ldmVy IGV4Y2VlZGVkIDI1NSBieXRlcyAqLworCQkJaWYgKHNzaWZfYm1jLT5yZXF1ZXN0LmxlbiA+IDI1 NSkKKwkJCQlkZXZfd2Fybigmc3NpZl9ibWMtPmNsaWVudC0+ZGV2LAorCQkJCQkgIldhcm46IElu dmFsaWQgcmVxdWVzdCBsZW4iKTsKKworCQl9IGVsc2UgeworCQkJYnVmW3NzaWZfYm1jLT5tc2df aWR4IC0gMSArCisJCQkgICAgc3NpZl9ibWMtPnJlcXVlc3QubGVuIC0gc3NpZl9ibWMtPnJlY3Zf bGVuXQk9ICp2YWw7CisJCX0KKworCQlzc2lmX2JtYy0+bXNnX2lkeCsrOworCisJCWJyZWFrOwor CWRlZmF1bHQ6CisJCS8qIERvIG5vdCBleHBlY3QgdG8gZ28gdG8gdGhpcyBjYXNlICovCisJCWRl dl9lcnIoJnNzaWZfYm1jLT5jbGllbnQtPmRldiwKKwkJCSIlczogVW5leHBlY3RlZCBTTUJ1cyBj b21tYW5kIDB4JXhcbiIsCisJCQlfX2Z1bmNfXywgc3NpZl9ibWMtPnNtYnVzX2NtZCk7CisJCWJy ZWFrOworCX0KK30KKworc3RhdGljIGJvb2wgdmFsaWRhdGVfcmVxdWVzdChzdHJ1Y3Qgc3NpZl9i bWNfY3R4ICpzc2lmX2JtYykKK3sKKwl1OCBycGVjID0gMCwgY3BlYyA9IDA7CisJYm9vbCByZXQg PSB0cnVlOworCXU4IGFkZHIsIGluZGV4OworCXU4ICpidWY7CisKKwlidWYgPSAodTggKikmc3Np Zl9ibWMtPnJlcXVlc3Q7CisJc3dpdGNoIChzc2lmX2JtYy0+c21idXNfY21kKSB7CisJY2FzZSBT U0lGX0lQTUlfU0lOR0xFUEFSVF9XUklURToKKwkJaWYgKChzc2lmX2JtYy0+bXNnX2lkeCAtIDEp ID09IHNzaWZfbXNnX2xlbigmc3NpZl9ibWMtPnJlcXVlc3QpKSB7CisJCQkvKiBQRUMgaXMgbm90 IGluY2x1ZGVkICovCisJCQlzc2lmX2JtYy0+cGVjX3N1cHBvcnQgPSBmYWxzZTsKKwkJCXJldCA9 IHRydWU7CisJCQlnb3RvIGV4aXQ7CisJCX0KKworCQlpZiAoKHNzaWZfYm1jLT5tc2dfaWR4IC0g MSkgIT0gKHNzaWZfbXNnX2xlbigmc3NpZl9ibWMtPnJlcXVlc3QpICsgMSkpIHsKKwkJCWRldl9l cnIoJnNzaWZfYm1jLT5jbGllbnQtPmRldiwgIkVycm9yOiBVbmV4cGVjdGVkIGxlbmd0aCByZWNl aXZlZCAlZFxuIiwKKwkJCQlzc2lmX21zZ19sZW4oJnNzaWZfYm1jLT5yZXF1ZXN0KSk7CisJCQly ZXQgPSBmYWxzZTsKKwkJCWdvdG8gZXhpdDsKKwkJfQorCisJCS8qIFBFQyBpcyBpbmNsdWRlZCAq LworCQlzc2lmX2JtYy0+cGVjX3N1cHBvcnQgPSB0cnVlOworCQlycGVjID0gYnVmW3NzaWZfYm1j LT5tc2dfaWR4IC0gMl07CisJCWFkZHIgPSBHRVRfOEJJVF9BRERSKHNzaWZfYm1jLT5jbGllbnQt PmFkZHIpOworCQljcGVjID0gaTJjX3NtYnVzX3BlYyhjcGVjLCAmYWRkciwgMSk7CisJCWNwZWMg PSBpMmNfc21idXNfcGVjKGNwZWMsICZzc2lmX2JtYy0+c21idXNfY21kLCAxKTsKKwkJY3BlYyA9 IGkyY19zbWJ1c19wZWMoY3BlYywgYnVmLCBzc2lmX21zZ19sZW4oJnNzaWZfYm1jLT5yZXF1ZXN0 KSk7CisJCWlmIChycGVjICE9IGNwZWMpIHsKKwkJCWRldl9lcnIoJnNzaWZfYm1jLT5jbGllbnQt PmRldiwgIkJhZCBQRUMgMHglMDJ4IHZzLiAweCUwMnhcbiIsIHJwZWMsIGNwZWMpOworCQkJcmV0 ID0gZmFsc2U7CisJCX0KKworCQlicmVhazsKKwljYXNlIFNTSUZfSVBNSV9NVUxUSVBBUlRfV1JJ VEVfU1RBUlQ6CisJY2FzZSBTU0lGX0lQTUlfTVVMVElQQVJUX1dSSVRFX01JRERMRToKKwljYXNl IFNTSUZfSVBNSV9NVUxUSVBBUlRfV1JJVEVfRU5EOgorCQlpbmRleCA9IHNzaWZfYm1jLT5yZXF1 ZXN0LmxlbiAtIHNzaWZfYm1jLT5yZWN2X2xlbjsKKwkJaWYgKChzc2lmX2JtYy0+bXNnX2lkeCAt IDEgKyBpbmRleCkgPT0gc3NpZl9tc2dfbGVuKCZzc2lmX2JtYy0+cmVxdWVzdCkpIHsKKwkJCS8q IFBFQyBpcyBub3QgaW5jbHVkZWQgKi8KKwkJCXNzaWZfYm1jLT5wZWNfc3VwcG9ydCA9IGZhbHNl OworCQkJcmV0ID0gdHJ1ZTsKKwkJCWdvdG8gZXhpdDsKKwkJfQorCisJCWlmICgoc3NpZl9ibWMt Pm1zZ19pZHggLSAxICsgaW5kZXgpICE9IChzc2lmX21zZ19sZW4oJnNzaWZfYm1jLT5yZXF1ZXN0 KSArIDEpKSB7CisJCQlkZXZfZXJyKCZzc2lmX2JtYy0+Y2xpZW50LT5kZXYsICJFcnJvcjogVW5l eHBlY3RlZCBsZW5ndGggcmVjZWl2ZWQgJWRcbiIsCisJCQkJc3NpZl9tc2dfbGVuKCZzc2lmX2Jt Yy0+cmVxdWVzdCkpOworCQkJcmV0ID0gZmFsc2U7CisJCQlnb3RvIGV4aXQ7CisJCX0KKworCQkv KiBQRUMgaXMgaW5jbHVkZWQgKi8KKwkJc3NpZl9ibWMtPnBlY19zdXBwb3J0ID0gdHJ1ZTsKKwkJ cnBlYyA9IGJ1Zltzc2lmX2JtYy0+bXNnX2lkeCAtIDIgKyBpbmRleF07CisJCWFkZHIgPSBHRVRf OEJJVF9BRERSKHNzaWZfYm1jLT5jbGllbnQtPmFkZHIpOworCQljcGVjID0gaTJjX3NtYnVzX3Bl YyhjcGVjLCAmYWRkciwgMSk7CisJCWNwZWMgPSBpMmNfc21idXNfcGVjKGNwZWMsICZzc2lmX2Jt Yy0+c21idXNfY21kLCAxKTsKKwkJY3BlYyA9IGkyY19zbWJ1c19wZWMoY3BlYywgJnNzaWZfYm1j LT5yZWN2X2xlbiwgMSk7CisJCS8qIEFzIFNNQnVzIHNwZWNpZmljYXRpb24gZG9lcyBub3QgYWxs b3cgdGhlIGxlbmd0aAorCQkgKiAoYnl0ZSBjb3VudCkgaW4gdGhlIFdyaXRlLUJsb2NrIHByb3Rv Y29sIHRvIGJlIHplcm8uCisJCSAqIFRoZXJlZm9yZSwgaXQgaXMgaWxsZWdhbCB0byBoYXZlIHRo ZSBsYXN0IE1pZGRsZQorCQkgKiB0cmFuc2FjdGlvbiBpbiB0aGUgc2VxdWVuY2UgY2FycnkgMzIt Ynl0ZSBhbmQgaGF2ZQorCQkgKiBhIGxlbmd0aCBvZiDigJgw4oCZIGluIHRoZSBFbmQgdHJhbnNh Y3Rpb24uCisJCSAqIEJ1dCBzb21lIHVzZXJzIG1heSB0cnkgdG8gdXNlIHRoaXMgd2F5IGFuZCB3 ZSBzaG91bGQKKwkJICogcHJldmVudCBzc2lmX2JtYyBkcml2ZXIgYnJva2VuIGluIHRoaXMgY2Fz ZS4KKwkJICovCisJCWlmIChzc2lmX2JtYy0+cmVjdl9sZW4gIT0gMCkKKwkJCWNwZWMgPSBpMmNf c21idXNfcGVjKGNwZWMsIGJ1ZiArIDEgKyBpbmRleCwgc3NpZl9ibWMtPnJlY3ZfbGVuKTsKKwor CQlpZiAocnBlYyAhPSBjcGVjKSB7CisJCQlkZXZfZXJyKCZzc2lmX2JtYy0+Y2xpZW50LT5kZXYs ICJCYWQgUEVDIDB4JTAyeCB2cy4gMHglMDJ4XG4iLCBycGVjLCBjcGVjKTsKKwkJCXJldCA9IGZh bHNlOworCQl9CisKKwkJYnJlYWs7CisJZGVmYXVsdDoKKwkJLyogRG8gbm90IGV4cGVjdCB0byBn byB0byB0aGlzIGNhc2UgKi8KKwkJZGV2X2Vycigmc3NpZl9ibWMtPmNsaWVudC0+ZGV2LCAiJXM6 IFVuZXhwZWN0ZWQgU01CdXMgY29tbWFuZCAweCV4XG4iLAorCQkJX19mdW5jX18sIHNzaWZfYm1j LT5zbWJ1c19jbWQpOworCQlyZXQgPSBmYWxzZTsKKwkJYnJlYWs7CisJfQorCitleGl0OgorCXJl dHVybiByZXQ7Cit9CisKK3N0YXRpYyBib29sIHVuc3VwcG9ydGVkX3NtYnVzX2NtZCh1OCBjbWQp Cit7CisJaWYgKGNtZCA9PSBTU0lGX0lQTUlfU0lOR0xFUEFSVF9SRUFEIHx8CisJICAgIGNtZCA9 PSBTU0lGX0lQTUlfU0lOR0xFUEFSVF9XUklURSB8fAorCSAgICBjbWQgPT0gU1NJRl9JUE1JX01V TFRJUEFSVF9XUklURV9TVEFSVCB8fAorCSAgICBjbWQgPT0gU1NJRl9JUE1JX01VTFRJUEFSVF9X UklURV9NSURETEUgfHwKKwkgICAgY21kID09IFNTSUZfSVBNSV9NVUxUSVBBUlRfV1JJVEVfRU5E IHx8CisJICAgIGNtZCA9PSBTU0lGX0lQTUlfTVVMVElQQVJUX1JFQURfU1RBUlQgfHwKKwkgICAg Y21kID09IFNTSUZfSVBNSV9NVUxUSVBBUlRfUkVBRF9NSURETEUpCisJCXJldHVybiBmYWxzZTsK KworCXJldHVybiB0cnVlOworfQorCitzdGF0aWMgdm9pZCBwcm9jZXNzX3NtYnVzX2NtZChzdHJ1 Y3Qgc3NpZl9ibWNfY3R4ICpzc2lmX2JtYywgdTggKnZhbCkKK3sKKwkvKiBTTUJVUyBjb21tYW5k IGNhbiB2YXJ5IChzaW5nbGUgb3IgbXVsdGktcGFydCkgKi8KKwlzc2lmX2JtYy0+c21idXNfY21k ID0gKnZhbDsKKwlzc2lmX2JtYy0+bXNnX2lkeCsrOworCisJaWYgKHVuc3VwcG9ydGVkX3NtYnVz X2NtZCgqdmFsKSkKKwkJZGV2X3dhcm4oJnNzaWZfYm1jLT5jbGllbnQtPmRldiwgIldhcm46IFVu a25vd24gU01CdXMgY29tbWFuZCIpOworCisJaWYgKCp2YWwgPT0gU1NJRl9JUE1JX1NJTkdMRVBB UlRfV1JJVEUgfHwKKwkgICAgKnZhbCA9PSBTU0lGX0lQTUlfTVVMVElQQVJUX1dSSVRFX1NUQVJU KSB7CisJCS8qCisJCSAqIFRoZSByZXNwb25zZSBtYXliZSBub3QgY29tZSBpbi10aW1lLCBjYXVz aW5nIGhvc3QgU1NJRiBkcml2ZXIKKwkJICogdG8gdGltZW91dCBhbmQgcmVzZW5kIGEgbmV3IHJl cXVlc3QuIEluIHN1Y2ggY2FzZSBjaGVjayBmb3IKKwkJICogcGVuZGluZyByZXNwb25zZSBhbmQg Y2xlYXIgaXQKKwkJICovCisJCWlmIChzc2lmX2JtYy0+cmVzcG9uc2VfaW5fcHJvZ3Jlc3MpCisJ CQljb21wbGV0ZV9yZXNwb25zZShzc2lmX2JtYyk7CisJfQorfQorCitzdGF0aWMgdm9pZCBvbl9y ZWFkX3JlcXVlc3RlZF9ldmVudChzdHJ1Y3Qgc3NpZl9ibWNfY3R4ICpzc2lmX2JtYywgdTggKnZh bCkKK3sKKwlpZiAoc3NpZl9ibWMtPnN0YXRlID09IFNTSUZfUkVBRFkgfHwKKwkgICAgc3NpZl9i bWMtPnN0YXRlID09IFNTSUZfU1RBUlQgfHwKKwkgICAgc3NpZl9ibWMtPnN0YXRlID09IFNTSUZf UkVRX1JFQ1ZJTkcgfHwKKwkgICAgc3NpZl9ibWMtPnN0YXRlID09IFNTSUZfUkVTX1NFTkRJTkcp IHsKKwkJc3NpZl9ibWMtPnN0YXRlID0gU1NJRl9CQURfU01CVVM7CisJCWRldl93YXJuKCZzc2lm X2JtYy0+Y2xpZW50LT5kZXYsCisJCQkgIldhcm46ICVzIHVuZXhwZWN0ZWQgUkVBRCBSRVFVRVNU RUQgaW4gc3RhdGU9JXNcbiIsCisJCQkgX19mdW5jX18sIHN0YXRlX3RvX3N0cmluZyhzc2lmX2Jt Yy0+c3RhdGUpKTsKKworCX0gZWxzZSBpZiAoc3NpZl9ibWMtPnN0YXRlID09IFNTSUZfU01CVVNf Q01EKSB7CisJCXNzaWZfYm1jLT5zdGF0ZSA9IFNTSUZfUkVTX1NFTkRJTkc7CisJfQorCisJc3Np Zl9ibWMtPm1zZ19pZHggPSAwOworCWlmIChzc2lmX2JtYy0+aXNfc2luZ2xlcGFydF9yZWFkKQor CQkqdmFsID0gc3NpZl9ibWMtPnJlc3BvbnNlLmxlbjsKKwllbHNlCisJCXNldF9tdWx0aXBhcnRf cmVzcG9uc2VfYnVmZmVyKHNzaWZfYm1jLCB2YWwpOworfQorCitzdGF0aWMgdm9pZCBvbl9yZWFk X3Byb2Nlc3NlZF9ldmVudChzdHJ1Y3Qgc3NpZl9ibWNfY3R4ICpzc2lmX2JtYywgdTggKnZhbCkK K3sKKwlpZiAoc3NpZl9ibWMtPnN0YXRlID09IFNTSUZfUkVBRFkgfHwKKwkgICAgc3NpZl9ibWMt PnN0YXRlID09IFNTSUZfU1RBUlQgfHwKKwkgICAgc3NpZl9ibWMtPnN0YXRlID09IFNTSUZfUkVR X1JFQ1ZJTkcgfHwKKwkgICAgc3NpZl9ibWMtPnN0YXRlID09IFNTSUZfU01CVVNfQ01EKSB7CisJ CWRldl93YXJuKCZzc2lmX2JtYy0+Y2xpZW50LT5kZXYsCisJCQkgIldhcm46ICVzIHVuZXhwZWN0 ZWQgUkVBRCBQUk9DRVNTRUQgaW4gc3RhdGU9JXNcbiIsCisJCQkgX19mdW5jX18sIHN0YXRlX3Rv X3N0cmluZyhzc2lmX2JtYy0+c3RhdGUpKTsKKwkJc3NpZl9ibWMtPnN0YXRlID0gU1NJRl9CQURf U01CVVM7CisJfQorCisJaGFuZGxlX3JlYWRfcHJvY2Vzc2VkKHNzaWZfYm1jLCB2YWwpOworfQor CitzdGF0aWMgdm9pZCBvbl93cml0ZV9yZXF1ZXN0ZWRfZXZlbnQoc3RydWN0IHNzaWZfYm1jX2N0 eCAqc3NpZl9ibWMsIHU4ICp2YWwpCit7CisJc3NpZl9ibWMtPm1zZ19pZHggPSAwOworCisJaWYg KHNzaWZfYm1jLT5zdGF0ZSA9PSBTU0lGX1JFQURZIHx8IHNzaWZfYm1jLT5zdGF0ZSA9PSBTU0lG X1NNQlVTX0NNRCkgeworCQlzc2lmX2JtYy0+c3RhdGUgPSBTU0lGX1NUQVJUOworCisJfSBlbHNl IGlmIChzc2lmX2JtYy0+c3RhdGUgPT0gU1NJRl9TVEFSVCB8fAorCQkgICBzc2lmX2JtYy0+c3Rh dGUgPT0gU1NJRl9SRVFfUkVDVklORyB8fAorCQkgICBzc2lmX2JtYy0+c3RhdGUgPT0gU1NJRl9S RVNfU0VORElORykgeworCQlkZXZfd2Fybigmc3NpZl9ibWMtPmNsaWVudC0+ZGV2LAorCQkJICJX YXJuOiAlcyB1bmV4cGVjdGVkIFdSSVRFIFJFUVVFU1QgaW4gc3RhdGU9JXNcbiIsCisJCQkgX19m dW5jX18sIHN0YXRlX3RvX3N0cmluZyhzc2lmX2JtYy0+c3RhdGUpKTsKKwkJc3NpZl9ibWMtPnN0 YXRlID0gU1NJRl9CQURfU01CVVM7CisJfQorfQorCitzdGF0aWMgdm9pZCBvbl93cml0ZV9yZWNl aXZlZF9ldmVudChzdHJ1Y3Qgc3NpZl9ibWNfY3R4ICpzc2lmX2JtYywgdTggKnZhbCkKK3sKKwlp ZiAoc3NpZl9ibWMtPnN0YXRlID09IFNTSUZfUkVBRFkgfHwgc3NpZl9ibWMtPnN0YXRlID09IFNT SUZfUkVTX1NFTkRJTkcpIHsKKwkJZGV2X3dhcm4oJnNzaWZfYm1jLT5jbGllbnQtPmRldiwKKwkJ CSAiV2FybjogJXMgdW5leHBlY3RlZCBXUklURSBSRUNFSVZFRCBpbiBzdGF0ZT0lc1xuIiwKKwkJ CSBfX2Z1bmNfXywgc3RhdGVfdG9fc3RyaW5nKHNzaWZfYm1jLT5zdGF0ZSkpOworCQlzc2lmX2Jt Yy0+c3RhdGUgPSBTU0lGX0JBRF9TTUJVUzsKKwl9IGVsc2UgaWYgKHNzaWZfYm1jLT5zdGF0ZSA9 PSBTU0lGX1NUQVJUKSB7CisJCXNzaWZfYm1jLT5zdGF0ZSA9IFNTSUZfU01CVVNfQ01EOworCX0g ZWxzZSBpZiAoc3NpZl9ibWMtPnN0YXRlID09IFNTSUZfU01CVVNfQ01EKSB7CisJCXNzaWZfYm1j LT5zdGF0ZSA9IFNTSUZfUkVRX1JFQ1ZJTkc7CisJfQorCisJLyogVGhpcyBpcyByZXNwb25zZSBz ZW5kaW5nIHN0YXRlICovCisJaWYgKHNzaWZfYm1jLT5zdGF0ZSA9PSBTU0lGX1JFUV9SRUNWSU5H KQorCQloYW5kbGVfd3JpdGVfcmVjZWl2ZWQoc3NpZl9ibWMsIHZhbCk7CisJZWxzZSBpZiAoc3Np Zl9ibWMtPnN0YXRlID09IFNTSUZfU01CVVNfQ01EKQorCQlwcm9jZXNzX3NtYnVzX2NtZChzc2lm X2JtYywgdmFsKTsKK30KKworc3RhdGljIHZvaWQgb25fc3RvcF9ldmVudChzdHJ1Y3Qgc3NpZl9i bWNfY3R4ICpzc2lmX2JtYywgdTggKnZhbCkKK3sKKwlpZiAoc3NpZl9ibWMtPnN0YXRlID09IFNT SUZfUkVBRFkgfHwKKwkgICAgc3NpZl9ibWMtPnN0YXRlID09IFNTSUZfU1RBUlQgfHwKKwkgICAg c3NpZl9ibWMtPnN0YXRlID09IFNTSUZfU01CVVNfQ01EKSB7CisJCWRldl93YXJuKCZzc2lmX2Jt Yy0+Y2xpZW50LT5kZXYsCisJCQkgIldhcm46ICVzIHVuZXhwZWN0ZWQgU0xBVkUgU1RPUCBpbiBz dGF0ZT0lc1xuIiwKKwkJCSBfX2Z1bmNfXywgc3RhdGVfdG9fc3RyaW5nKHNzaWZfYm1jLT5zdGF0 ZSkpOworCisJfSBlbHNlIGlmIChzc2lmX2JtYy0+c3RhdGUgPT0gU1NJRl9CQURfU01CVVMpIHsK KwkJZGV2X3dhcm4oJnNzaWZfYm1jLT5jbGllbnQtPmRldiwKKwkJCSAiV2FybjogJXMgcmVjZWl2 ZWQgU0xBVkUgU1RPUCBmcm9tIGJhZCBzdGF0ZT0lc1xuIiwKKwkJCSBfX2Z1bmNfXywgc3RhdGVf dG9fc3RyaW5nKHNzaWZfYm1jLT5zdGF0ZSkpOworCisJfSBlbHNlIGlmIChzc2lmX2JtYy0+c3Rh dGUgPT0gU1NJRl9SRVFfUkVDVklORykgeworCQkvKiBBIEJNQyB0aGF0IHJlY2VpdmVzIGFuIGlu dmFsaWQgcmVxdWVzdCBkcm9wIHRoZSBkYXRhIGZvciB0aGUgd3JpdGUKKwkJICogdHJhbnNhY3Rp b24gYW5kIGFueSBmdXJ0aGVyIHRyYW5zYWN0aW9ucyAocmVhZCBvciB3cml0ZSkgdW50aWwKKwkJ ICogdGhlIG5leHQgdmFsaWQgcmVhZCBvciB3cml0ZSBTdGFydCB0cmFuc2FjdGlvbiBpcyByZWNl aXZlZAorCQkgKi8KKwkJaWYgKCF2YWxpZGF0ZV9yZXF1ZXN0KHNzaWZfYm1jKSkKKwkJCWRldl9l cnIoJnNzaWZfYm1jLT5jbGllbnQtPmRldiwgIkVycm9yOiBpbnZhbGlkIHBlY1xuIik7CisJCWVs c2UgaWYgKHNzaWZfYm1jLT5zbWJ1c19jbWQgPT0gU1NJRl9JUE1JX1NJTkdMRVBBUlRfV1JJVEUg fHwKKwkJCSBzc2lmX2JtYy0+c21idXNfY21kID09IFNTSUZfSVBNSV9NVUxUSVBBUlRfV1JJVEVf RU5EKQorCQkJaGFuZGxlX3JlcXVlc3Qoc3NpZl9ibWMpOworCX0KKworCXNzaWZfYm1jLT5zdGF0 ZSA9IFNTSUZfUkVBRFk7CisJLyogUmVzZXQgbWVzc2FnZSBpbmRleCAqLworCXNzaWZfYm1jLT5t c2dfaWR4ID0gMDsKK30KKworLyoKKyAqIENhbGxiYWNrIGZ1bmN0aW9uIHRvIGhhbmRsZSBJMkMg c2xhdmUgZXZlbnRzCisgKi8KK3N0YXRpYyBpbnQgc3NpZl9ibWNfY2Ioc3RydWN0IGkyY19jbGll bnQgKmNsaWVudCwgZW51bSBpMmNfc2xhdmVfZXZlbnQgZXZlbnQsIHU4ICp2YWwpCit7CisJdW5z aWduZWQgbG9uZyBmbGFnczsKKwlzdHJ1Y3Qgc3NpZl9ibWNfY3R4ICpzc2lmX2JtYyA9IGkyY19n ZXRfY2xpZW50ZGF0YShjbGllbnQpOworCWludCByZXQgPSAwOworCisJc3Bpbl9sb2NrX2lycXNh dmUoJnNzaWZfYm1jLT5sb2NrLCBmbGFncyk7CisKKwlzd2l0Y2ggKGV2ZW50KSB7CisJY2FzZSBJ MkNfU0xBVkVfUkVBRF9SRVFVRVNURUQ6CisJCW9uX3JlYWRfcmVxdWVzdGVkX2V2ZW50KHNzaWZf Ym1jLCB2YWwpOworCQlicmVhazsKKworCWNhc2UgSTJDX1NMQVZFX1dSSVRFX1JFUVVFU1RFRDoK KwkJb25fd3JpdGVfcmVxdWVzdGVkX2V2ZW50KHNzaWZfYm1jLCB2YWwpOworCQlicmVhazsKKwor CWNhc2UgSTJDX1NMQVZFX1JFQURfUFJPQ0VTU0VEOgorCQlvbl9yZWFkX3Byb2Nlc3NlZF9ldmVu dChzc2lmX2JtYywgdmFsKTsKKwkJYnJlYWs7CisKKwljYXNlIEkyQ19TTEFWRV9XUklURV9SRUNF SVZFRDoKKwkJb25fd3JpdGVfcmVjZWl2ZWRfZXZlbnQoc3NpZl9ibWMsIHZhbCk7CisJCWJyZWFr OworCisJY2FzZSBJMkNfU0xBVkVfU1RPUDoKKwkJb25fc3RvcF9ldmVudChzc2lmX2JtYywgdmFs KTsKKwkJYnJlYWs7CisKKwlkZWZhdWx0OgorCQlkZXZfd2Fybigmc3NpZl9ibWMtPmNsaWVudC0+ ZGV2LCAiV2FybjogVW5rbm93biBpMmMgc2xhdmUgZXZlbnRcbiIpOworCQlicmVhazsKKwl9CisK KwlpZiAoc3NpZl9ibWMtPmJ1c3kpCisJCXJldCA9IC1FQlVTWTsKKworCXNwaW5fdW5sb2NrX2ly cXJlc3RvcmUoJnNzaWZfYm1jLT5sb2NrLCBmbGFncyk7CisKKwlyZXR1cm4gcmV0OworfQorCitz dGF0aWMgaW50IHNzaWZfYm1jX3Byb2JlKHN0cnVjdCBpMmNfY2xpZW50ICpjbGllbnQsIGNvbnN0 IHN0cnVjdCBpMmNfZGV2aWNlX2lkICppZCkKK3sKKwlzdHJ1Y3Qgc3NpZl9ibWNfY3R4ICpzc2lm X2JtYzsKKwlpbnQgcmV0OworCisJc3NpZl9ibWMgPSBkZXZtX2t6YWxsb2MoJmNsaWVudC0+ZGV2 LCBzaXplb2YoKnNzaWZfYm1jKSwgR0ZQX0tFUk5FTCk7CisJaWYgKCFzc2lmX2JtYykKKwkJcmV0 dXJuIC1FTk9NRU07CisKKwlzcGluX2xvY2tfaW5pdCgmc3NpZl9ibWMtPmxvY2spOworCisJaW5p dF93YWl0cXVldWVfaGVhZCgmc3NpZl9ibWMtPndhaXRfcXVldWUpOworCXNzaWZfYm1jLT5yZXF1 ZXN0X2F2YWlsYWJsZSA9IGZhbHNlOworCXNzaWZfYm1jLT5yZXNwb25zZV9pbl9wcm9ncmVzcyA9 IGZhbHNlOworCXNzaWZfYm1jLT5idXN5ID0gZmFsc2U7CisJc3NpZl9ibWMtPnJlc3BvbnNlX3Rp bWVyX2luaXRlZCA9IGZhbHNlOworCisJLyogUmVnaXN0ZXIgbWlzYyBkZXZpY2UgaW50ZXJmYWNl ICovCisJc3NpZl9ibWMtPm1pc2NkZXYubWlub3IgPSBNSVNDX0RZTkFNSUNfTUlOT1I7CisJc3Np Zl9ibWMtPm1pc2NkZXYubmFtZSA9IERFVklDRV9OQU1FOworCXNzaWZfYm1jLT5taXNjZGV2LmZv cHMgPSAmc3NpZl9ibWNfZm9wczsKKwlzc2lmX2JtYy0+bWlzY2Rldi5wYXJlbnQgPSAmY2xpZW50 LT5kZXY7CisJcmV0ID0gbWlzY19yZWdpc3Rlcigmc3NpZl9ibWMtPm1pc2NkZXYpOworCWlmIChy ZXQpCisJCWdvdG8gb3V0OworCisJc3NpZl9ibWMtPmNsaWVudCA9IGNsaWVudDsKKwlzc2lmX2Jt Yy0+Y2xpZW50LT5mbGFncyB8PSBJMkNfQ0xJRU5UX1NMQVZFOworCisJLyogUmVnaXN0ZXIgSTJD IHNsYXZlICovCisJaTJjX3NldF9jbGllbnRkYXRhKGNsaWVudCwgc3NpZl9ibWMpOworCXJldCA9 IGkyY19zbGF2ZV9yZWdpc3RlcihjbGllbnQsIHNzaWZfYm1jX2NiKTsKKwlpZiAocmV0KSB7CisJ CW1pc2NfZGVyZWdpc3Rlcigmc3NpZl9ibWMtPm1pc2NkZXYpOworCQlnb3RvIG91dDsKKwl9CisK KwlyZXR1cm4gMDsKK291dDoKKwlkZXZtX2tmcmVlKCZjbGllbnQtPmRldiwgc3NpZl9ibWMpOwor CXJldHVybiByZXQ7Cit9CisKK3N0YXRpYyBpbnQgc3NpZl9ibWNfcmVtb3ZlKHN0cnVjdCBpMmNf Y2xpZW50ICpjbGllbnQpCit7CisJc3RydWN0IHNzaWZfYm1jX2N0eCAqc3NpZl9ibWMgPSBpMmNf Z2V0X2NsaWVudGRhdGEoY2xpZW50KTsKKworCWkyY19zbGF2ZV91bnJlZ2lzdGVyKGNsaWVudCk7 CisJbWlzY19kZXJlZ2lzdGVyKCZzc2lmX2JtYy0+bWlzY2Rldik7CisKKwlyZXR1cm4gMDsKK30K Kworc3RhdGljIGNvbnN0IHN0cnVjdCBvZl9kZXZpY2VfaWQgc3NpZl9ibWNfbWF0Y2hbXSA9IHsK Kwl7IC5jb21wYXRpYmxlID0gImFtcGVyZSxzc2lmLWJtYyIgfSwKKwl7IH0sCit9OworCitzdGF0 aWMgY29uc3Qgc3RydWN0IGkyY19kZXZpY2VfaWQgc3NpZl9ibWNfaWRbXSA9IHsKKwl7IERFVklD RV9OQU1FLCAwIH0sCisJeyB9LAorfTsKKworTU9EVUxFX0RFVklDRV9UQUJMRShpMmMsIHNzaWZf Ym1jX2lkKTsKKworc3RhdGljIHN0cnVjdCBpMmNfZHJpdmVyIHNzaWZfYm1jX2RyaXZlciA9IHsK KwkuZHJpdmVyICAgICAgICAgPSB7CisJCS5uYW1lICAgICAgICAgICA9IERFVklDRV9OQU1FLAor CQkub2ZfbWF0Y2hfdGFibGUgPSBzc2lmX2JtY19tYXRjaCwKKwl9LAorCS5wcm9iZSAgICAgICAg ICA9IHNzaWZfYm1jX3Byb2JlLAorCS5yZW1vdmUgICAgICAgICA9IHNzaWZfYm1jX3JlbW92ZSwK KwkuaWRfdGFibGUgICAgICAgPSBzc2lmX2JtY19pZCwKK307CisKK21vZHVsZV9pMmNfZHJpdmVy KHNzaWZfYm1jX2RyaXZlcik7CisKK01PRFVMRV9BVVRIT1IoIlF1YW4gTmd1eWVuIDxxdWFuQG9z LmFtcGVyZWNvbXB1dGluZy5jb20+Iik7CitNT0RVTEVfQVVUSE9SKCJDaHVvbmcgVHJhbiA8Y2h1 b25nQG9zLmFtcGVyZWNvbXB1dGluZy5jb20+Iik7CitNT0RVTEVfREVTQ1JJUFRJT04oIkxpbnV4 IGRldmljZSBkcml2ZXIgb2YgdGhlIEJNQyBJUE1JIFNTSUYgaW50ZXJmYWNlLiIpOworTU9EVUxF X0xJQ0VOU0UoIkdQTCIpOwpkaWZmIC0tZ2l0IGEvZHJpdmVycy9jaGFyL2lwbWkvc3NpZl9ibWMu aCBiL2RyaXZlcnMvY2hhci9pcG1pL3NzaWZfYm1jLmgKbmV3IGZpbGUgbW9kZSAxMDA2NDQKaW5k ZXggMDAwMDAwMDAwMDAwLi45YTI2ZjNjMjUyY2MKLS0tIC9kZXYvbnVsbAorKysgYi9kcml2ZXJz L2NoYXIvaXBtaS9zc2lmX2JtYy5oCkBAIC0wLDAgKzEsMTAyIEBACisvKiBTUERYLUxpY2Vuc2Ut SWRlbnRpZmllcjogR1BMLTIuMCsgKi8KKy8qCisgKiBUaGUgZHJpdmVyIGZvciBCTUMgc2lkZSBv ZiBTU0lGIGludGVyZmFjZQorICoKKyAqIENvcHlyaWdodCAoYykgMjAyMiwgQW1wZXJlIENvbXB1 dGluZyBMTEMKKyAqCisgKi8KKyNpZm5kZWYgX19TU0lGX0JNQ19IX18KKyNkZWZpbmUgX19TU0lG X0JNQ19IX18KKworI2RlZmluZSBERVZJQ0VfTkFNRQkJCQkiaXBtaS1zc2lmLWhvc3QiCisKKyNk ZWZpbmUgR0VUXzhCSVRfQUREUihhZGRyXzdiaXQpCQkoKChhZGRyXzdiaXQpIDw8IDEpICYgMHhm ZikKKworLyogQSBzdGFuZGFyZCBTTUJ1cyBUcmFuc2FjdGlvbiBpcyBsaW1pdGVkIHRvIDMyIGRh dGEgYnl0ZXMgKi8KKyNkZWZpbmUgTUFYX1BBWUxPQURfUEVSX1RSQU5TQUNUSU9OCQkzMgorCisj ZGVmaW5lIE1BWF9JUE1JX0RBVEFfUEVSX1NUQVJUX1RSQU5TQUNUSU9OCTMwCisjZGVmaW5lIE1B WF9JUE1JX0RBVEFfUEVSX01JRERMRV9UUkFOU0FDVElPTgkzMQorCisjZGVmaW5lIFNTSUZfSVBN SV9TSU5HTEVQQVJUX1dSSVRFCQkweDIKKyNkZWZpbmUgU1NJRl9JUE1JX1NJTkdMRVBBUlRfUkVB RAkJMHgzCisjZGVmaW5lIFNTSUZfSVBNSV9NVUxUSVBBUlRfV1JJVEVfU1RBUlQJCTB4NgorI2Rl ZmluZSBTU0lGX0lQTUlfTVVMVElQQVJUX1dSSVRFX01JRERMRQkweDcKKyNkZWZpbmUgU1NJRl9J UE1JX01VTFRJUEFSVF9XUklURV9FTkQJCTB4OAorI2RlZmluZSBTU0lGX0lQTUlfTVVMVElQQVJU X1JFQURfU1RBUlQJCTB4MworI2RlZmluZSBTU0lGX0lQTUlfTVVMVElQQVJUX1JFQURfTUlERExF CQkweDkKKworI2RlZmluZSBNU0dfUEFZTE9BRF9MRU5fTUFYCQkJMjUyCisvKgorICogSVBNSSAy LjAgU3BlYywgc2VjdGlvbiAxMi43IFNTSUYgVGltaW5nLAorICogUmVxdWVzdC10by1SZXNwb25z ZSBUaW1lIGlzIFQ2bWF4KDI1MG1zKSAtIFQxbWF4KDIwbXMpIC0gM21zID0gMjI3bXMKKyAqIFJl Y292ZXIgc3NpZl9ibWMgZnJvbSBidXN5IHN0YXRlIGlmIGl0IHRha2VzIHVwdG8gNTAwbXMKKyAq LworI2RlZmluZSBSRVNQT05TRV9USU1FT1VUCQkJNTAwIC8qIG1zICovCisKK3N0cnVjdCBzc2lm X21zZyB7CisJdTggbGVuOworCXU4IG5ldGZuX2x1bjsKKwl1OCBjbWQ7CisJdTggcGF5bG9hZFtN U0dfUEFZTE9BRF9MRU5fTUFYXTsKK30gX19wYWNrZWQ7CisKK3N0YXRpYyBpbmxpbmUgdTMyIHNz aWZfbXNnX2xlbihzdHJ1Y3Qgc3NpZl9tc2cgKnNzaWZfbXNnKQoreworCXJldHVybiBzc2lmX21z Zy0+bGVuICsgMTsKK30KKworLyoKKyAqIFNTSUYgaW50ZXJuYWwgc3RhdGVzOgorICogICBTU0lG X1JFQURZICAgICAgICAgMHgwMCA6IFJlYWR5IHN0YXRlCisgKiAgIFNTSUZfU1RBUlQgICAgICAg ICAweDAxIDogU3RhcnQgc21idXMgdHJhbnNhY3Rpb24KKyAqICAgU1NJRl9TTUJVU19DTUQgICAg IDB4MDIgOiBSZWNlaXZlZCBTTUJ1cyBjb21tYW5kCisgKiAgIFNTSUZfUkVRX1JFQ1ZJTkcgICAw eDAzIDogUmVjZWl2aW5nIHJlcXVlc3QKKyAqICAgU1NJRl9SRVNfU0VORElORyAgIDB4MDQgOiBT ZW5kaW5nIHJlc3BvbnNlCisgKiAgIFNTSUZfQkFEX1NNQlVTICAgICAweDA1IDogQmFkIFNNYnVz IHRyYW5zYWN0aW9uCisgKi8KK2VudW0gc3NpZl9zdGF0ZSB7CisJU1NJRl9SRUFEWSwKKwlTU0lG X1NUQVJULAorCVNTSUZfU01CVVNfQ01ELAorCVNTSUZfUkVRX1JFQ1ZJTkcsCisJU1NJRl9SRVNf U0VORElORywKKwlTU0lGX0JBRF9TTUJVUywKKwlTU0lGX1NUQVRFX01BWAorfTsKKworc3RydWN0 IHNzaWZfYm1jX2N0eCB7CisJc3RydWN0IGkyY19jbGllbnQJKmNsaWVudDsKKwlzdHJ1Y3QgbWlz Y2RldmljZQltaXNjZGV2OworCXNpemVfdAkJCW1zZ19pZHg7CisJYm9vbAkJCXBlY19zdXBwb3J0 OworCS8qIHNzaWYgYm1jIHNwaW5sb2NrICovCisJc3BpbmxvY2tfdAkJbG9jazsKKwl3YWl0X3F1 ZXVlX2hlYWRfdAl3YWl0X3F1ZXVlOworCXU4CQkJcnVubmluZzsKKwllbnVtIHNzaWZfc3RhdGUJ CXN0YXRlOworCXU4CQkJc21idXNfY21kOworCS8qIFRpbWVvdXQgd2FpdGluZyBmb3IgcmVzcG9u c2UgKi8KKwlzdHJ1Y3QgdGltZXJfbGlzdAlyZXNwb25zZV90aW1lcjsKKwlib29sICAgICAgICAg ICAgICAgICAgICByZXNwb25zZV90aW1lcl9pbml0ZWQ7CisJLyogRmxhZyB0byBpZGVudGlmeSBh IE11bHRpLXBhcnQgUmVhZCBUcmFuc2FjdGlvbiAqLworCWJvb2wJCQlpc19zaW5nbGVwYXJ0X3Jl YWQ7CisJdTgJCQluYnl0ZXNfcHJvY2Vzc2VkOworCXU4CQkJcmVtYWluX2xlbjsKKwl1OAkJCXJl Y3ZfbGVuOworCS8qIEJsb2NrIE51bWJlciBvZiBhIE11bHRpLXBhcnQgUmVhZCBUcmFuc2FjdGlv biAqLworCXU4CQkJYmxvY2tfbnVtOworCWJvb2wJCQlyZXF1ZXN0X2F2YWlsYWJsZTsKKwlib29s CQkJcmVzcG9uc2VfaW5fcHJvZ3Jlc3M7CisJYm9vbAkJCWJ1c3k7CisJLyogUmVzcG9uc2UgYnVm ZmVyIGZvciBNdWx0aS1wYXJ0IFJlYWQgVHJhbnNhY3Rpb24gKi8KKwl1OAkJCXJlc3BvbnNlX2J1 ZltNQVhfUEFZTE9BRF9QRVJfVFJBTlNBQ1RJT05dOworCXN0cnVjdCBzc2lmX21zZwkJcmVzcG9u c2U7CisJc3RydWN0IHNzaWZfbXNnCQlyZXF1ZXN0OworfTsKKworc3RhdGljIGlubGluZSBzdHJ1 Y3Qgc3NpZl9ibWNfY3R4ICp0b19zc2lmX2JtYyhzdHJ1Y3QgZmlsZSAqZmlsZSkKK3sKKwlyZXR1 cm4gY29udGFpbmVyX29mKGZpbGUtPnByaXZhdGVfZGF0YSwgc3RydWN0IHNzaWZfYm1jX2N0eCwg bWlzY2Rldik7Cit9CisjZW5kaWYgLyogX19TU0lGX0JNQ19IX18gKi8KLS0gCjIuMzUuMQoKCl9f X19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fCmxpbnV4LWFybS1r ZXJuZWwgbWFpbGluZyBsaXN0CmxpbnV4LWFybS1rZXJuZWxAbGlzdHMuaW5mcmFkZWFkLm9yZwpo dHRwOi8vbGlzdHMuaW5mcmFkZWFkLm9yZy9tYWlsbWFuL2xpc3RpbmZvL2xpbnV4LWFybS1rZXJu ZWwK