From mboxrd@z Thu Jan 1 00:00:00 1970 From: Corey Minyard Date: Wed, 19 May 2021 07:30:42 -0500 Subject: [PATCH v3 2/7] ipmi: ssif_bmc: Add SSIF BMC driver In-Reply-To: <20210519074934.20712-3-quan@os.amperecomputing.com> References: <20210519074934.20712-1-quan@os.amperecomputing.com> <20210519074934.20712-3-quan@os.amperecomputing.com> Message-ID: <20210519123042.GF2921206@minyard.net> List-Id: To: linux-aspeed@lists.ozlabs.org MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit On Wed, May 19, 2021 at 02:49:29PM +0700, Quan Nguyen wrote: > 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 > --- > v3: > + Removed redundant license info [Joel] > + Switched to use traditional if-else [Joel] > + Removed unused ssif_bmc_ioctl() [Joel] > + Made handle_request()/complete_response() to return void [Joel] > + Refactored send_ssif_bmc_response()/receive_ssif_bmc_request() [Corey] > + Removed mutex [Corey] > + Use spin_lock/unlock_irqsave/restore in callback [Corey] > + Removed the unnecessary memset [Corey] > + Switch to use dev_err() [Corey] > > v2: > + Fixed compiling error with COMPILE_TEST for arc > > drivers/char/ipmi/Kconfig | 11 + > drivers/char/ipmi/Makefile | 1 + > drivers/char/ipmi/ssif_bmc.c | 605 +++++++++++++++++++++++++++++++++++ > drivers/char/ipmi/ssif_bmc.h | 93 ++++++ > 4 files changed, 710 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 07847d9a459a..ad5c5161bcd6 100644 > --- a/drivers/char/ipmi/Kconfig > +++ b/drivers/char/ipmi/Kconfig > @@ -133,6 +133,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 0822adc2ec41..d04a214d74c4 100644 > --- a/drivers/char/ipmi/Makefile > +++ b/drivers/char/ipmi/Makefile > @@ -27,3 +27,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..d0ea7059b1db > --- /dev/null > +++ b/drivers/char/ipmi/ssif_bmc.c > @@ -0,0 +1,605 @@ > +// SPDX-License-Identifier: GPL-2.0+ > +/* > + * The driver for BMC side of SSIF interface > + * > + * Copyright (c) 2021, Ampere Computing LLC > + * > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include "ssif_bmc.h" > + > +/* 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) { > + if (file->f_flags & O_NONBLOCK) { There is no real need to check this under the lock. It would simplify the end of this function if you checked this outside the lock. > + ret = -EAGAIN; > + goto out_unlock; > + } > + spin_unlock_irqrestore(&ssif_bmc->lock, flags); > + ret = wait_event_interruptible(ssif_bmc->wait_queue, > + ssif_bmc->request_available); > + if (ret) > + return ret; > + spin_lock_irqsave(&ssif_bmc->lock, flags); > + } > + > + count = min_t(ssize_t, ssif_msg_len(&ssif_bmc->request), > + min_t(ssize_t, sizeof(struct ssif_msg), count)); Just curious, what happens if userland supplies a buffer that is too small? Is data lost? In that case, I would think returning an error here would be the better thing, as opposed to silently truncating the message. > + 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); > + goto out; > + > +out_unlock: > + spin_unlock_irqrestore(&ssif_bmc->lock, flags); > +out: > + 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) { > + if (file->f_flags & O_NONBLOCK) { Same comment as O_NONBLOCK before. > + ret = -EAGAIN; > + goto out_unlock; > + } > + spin_unlock_irqrestore(&ssif_bmc->lock, flags); > + ret = wait_event_interruptible(ssif_bmc->wait_queue, > + !ssif_bmc->response_in_progress); > + if (ret) > + goto out; > + spin_lock_irqsave(&ssif_bmc->lock, flags); > + } > + > + memcpy(&ssif_bmc->response, &msg, count); > + ssif_bmc->is_singlepart_read = (ssif_msg_len(&msg) <= MAX_PAYLOAD_PER_TRANSACTION + 1); > + ssif_bmc->response_in_progress = true; > + if (ssif_bmc->set_ssif_bmc_status) > + ssif_bmc->set_ssif_bmc_status(ssif_bmc, SSIF_BMC_READY); > + > +out_unlock: > + spin_unlock_irqrestore(&ssif_bmc->lock, flags); > + > +out: > + return (ret < 0) ? ret : count; > +} > + > +static int ssif_bmc_open(struct inode *inode, struct file *file) > +{ > + struct ssif_bmc_ctx *ssif_bmc = to_ssif_bmc(file); > + int ret = 0; > + > + spin_lock_irq(&ssif_bmc->lock); > + if (!ssif_bmc->running) > + ssif_bmc->running = 1; > + else > + ret = -EBUSY; > + spin_unlock_irq(&ssif_bmc->lock); > + > + return ret; > +} > + > +static unsigned int ssif_bmc_poll(struct file *file, poll_table *wait) > +{ > + struct ssif_bmc_ctx *ssif_bmc = to_ssif_bmc(file); > + unsigned int mask = 0; > + > + poll_wait(file, &ssif_bmc->wait_queue, wait); > + > + spin_lock_irq(&ssif_bmc->lock); > + /* > + * The request message is now available so 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 handle_request(struct ssif_bmc_ctx *ssif_bmc) > +{ > + if (ssif_bmc->set_ssif_bmc_status) > + ssif_bmc->set_ssif_bmc_status(ssif_bmc, SSIF_BMC_BUSY); > + > + /* Request message is available to process */ > + ssif_bmc->request_available = true; > + /* > + * This is the new READ request. > + */ > + wake_up_all(&ssif_bmc->wait_queue); > +} > + > +/* Called with ssif_bmc->lock held. */ > +static void complete_response(struct ssif_bmc_ctx *ssif_bmc) > +{ > + /* Invalidate response in buffer to denote it having been sent. */ > + ssif_bmc->response.len = 0; > + ssif_bmc->response_in_progress = false; > + ssif_bmc->nbytes_processed = 0; > + ssif_bmc->remain_len = 0; > + wake_up_all(&ssif_bmc->wait_queue); > +} > + > +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, > + "Error: Unexpected SMBus command received 0x%x\n", 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, > + "Error: Unexpected SMBus command received 0x%x\n", > + 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 smbus_cmd; > + > + buf = (u8 *)&ssif_bmc->request; > + if (ssif_bmc->msg_idx >= sizeof(struct ssif_msg)) Shouldn't you abort the message if you get too much data? Otherwise you get silent truncation. > + return; > + > + smbus_cmd = ssif_bmc->smbus_cmd; > + switch (smbus_cmd) { > + case SSIF_IPMI_SINGLEPART_WRITE: > + /* Single-part write */ > + buf[ssif_bmc->msg_idx - 1] = *val; > + ssif_bmc->msg_idx++; > + > + break; Generally you put the space after the break, not before. You did this right before, but didn't from here down in the file. > + case SSIF_IPMI_MULTIPART_WRITE_START: > + /* Reset length to zero */ > + if (ssif_bmc->msg_idx == 1) > + ssif_bmc->request.len = 0; What happens if you get this and you are in the middle of a message? > + > + fallthrough; > + case SSIF_IPMI_MULTIPART_WRITE_MIDDLE: > + case SSIF_IPMI_MULTIPART_WRITE_END: What happens if you get these and you are not in a message? > + /* Multi-part write, 2nd byte received is length */ > + if (ssif_bmc->msg_idx == 1) { > + ssif_bmc->request.len += *val; > + ssif_bmc->recv_len = *val; > + } 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, > + "Error: Unexpected SMBus command received 0x%x\n", ssif_bmc->smbus_cmd); > + break; > + } > +} > + > +static bool validate_pec(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; > + return true; > + } > + > + if ((ssif_bmc->msg_idx - 1) != (ssif_msg_len(&ssif_bmc->request) + 1)) > + goto error; > + > + /* 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; > + return true; > + } > + > + if ((ssif_bmc->msg_idx - 1 + index) != (ssif_msg_len(&ssif_bmc->request) + 1)) > + goto error; > + > + /* 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-bytes 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: > + break; > + } > + > + return ret; > +error: > + /* Do not expect to go to this case */ > + dev_err(&ssif_bmc->client->dev, > + "Error: Unexpected length received %d\n", ssif_msg_len(&ssif_bmc->request)); > + > + return false; > +} > + > +static void complete_write_received(struct ssif_bmc_ctx *ssif_bmc) > +{ > + u8 cmd = ssif_bmc->smbus_cmd; > + > + /* A BMC that receives an invalid PEC shall 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_pec(ssif_bmc)) { > + dev_err(&ssif_bmc->client->dev, "Received invalid PEC\n"); > + return; > + } > + > + if (cmd == SSIF_IPMI_SINGLEPART_WRITE || cmd == SSIF_IPMI_MULTIPART_WRITE_END) > + handle_request(ssif_bmc); > +} > + > +static void initialize_transfer(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 (ssif_bmc->smbus_cmd == SSIF_IPMI_SINGLEPART_WRITE || > + ssif_bmc->smbus_cmd == SSIF_IPMI_MULTIPART_WRITE_START) { > + /* > + * The response can be delayed in BMC causing host SSIF driver > + * to timeout and send a new request once BMC slave is ready. > + * In that case check for pending response and clear it > + */ > + if (ssif_bmc->response_in_progress) { > + dev_err(&ssif_bmc->client->dev, > + "Warn: SSIF new request with pending response"); > + complete_response(ssif_bmc); > + } > + } else if (unlikely(ssif_bmc->smbus_cmd != SSIF_IPMI_SINGLEPART_READ && > + ssif_bmc->smbus_cmd != SSIF_IPMI_MULTIPART_WRITE_MIDDLE && > + ssif_bmc->smbus_cmd != SSIF_IPMI_MULTIPART_WRITE_END && > + ssif_bmc->smbus_cmd != SSIF_IPMI_MULTIPART_READ_START && > + ssif_bmc->smbus_cmd != SSIF_IPMI_MULTIPART_READ_MIDDLE)) { > + /* Unknown command, clear it */ > + dev_err(&ssif_bmc->client->dev, "Warn: Unknown SMBus command"); > + complete_response(ssif_bmc); > + } > +} > + > +/* > + * Callback function to handle I2C slave events > + */ > +static int ssif_bmc_cb(struct i2c_client *client, enum i2c_slave_event event, u8 *val) > +{ > + unsigned long flags; > + struct ssif_bmc_ctx *ssif_bmc = i2c_get_clientdata(client); > + > + spin_lock_irqsave(&ssif_bmc->lock, flags); > + > + /* I2C Event Handler: > + * I2C_SLAVE_READ_REQUESTED 0x0 > + * I2C_SLAVE_WRITE_REQUESTED 0x1 > + * I2C_SLAVE_READ_PROCESSED 0x2 > + * I2C_SLAVE_WRITE_RECEIVED 0x3 > + * I2C_SLAVE_STOP 0x4 > + */ > + switch (event) { > + case I2C_SLAVE_READ_REQUESTED: > + ssif_bmc->msg_idx = 0; > + if (ssif_bmc->is_singlepart_read) > + *val = ssif_bmc->response.len; > + else > + set_multipart_response_buffer(ssif_bmc, val); > + break; > + > + case I2C_SLAVE_WRITE_REQUESTED: > + ssif_bmc->msg_idx = 0; > + break; > + > + case I2C_SLAVE_READ_PROCESSED: > + handle_read_processed(ssif_bmc, val); > + break; > + > + case I2C_SLAVE_WRITE_RECEIVED: > + if (ssif_bmc->msg_idx) > + handle_write_received(ssif_bmc, val); > + else > + initialize_transfer(ssif_bmc, val); > + > + break; > + > + case I2C_SLAVE_STOP: > + if (ssif_bmc->last_event == I2C_SLAVE_WRITE_RECEIVED) > + complete_write_received(ssif_bmc); > + /* Reset message index */ > + ssif_bmc->msg_idx = 0; > + break; > + > + default: > + break; > + } > + ssif_bmc->last_event = event; > + spin_unlock_irqrestore(&ssif_bmc->lock, flags); > + > + return 0; > +} > + > +struct ssif_bmc_ctx *ssif_bmc_alloc(struct i2c_client *client, int sizeof_priv) > +{ > + struct ssif_bmc_ctx *ssif_bmc; > + int ret; > + > + ssif_bmc = devm_kzalloc(&client->dev, sizeof(*ssif_bmc) + sizeof_priv, GFP_KERNEL); > + if (!ssif_bmc) > + return ERR_PTR(-ENOMEM); > + > + spin_lock_init(&ssif_bmc->lock); > + > + init_waitqueue_head(&ssif_bmc->wait_queue); > + ssif_bmc->request_available = false; > + ssif_bmc->response_in_progress = false; > + > + /* Register misc device interface */ > + ssif_bmc->miscdev.minor = MISC_DYNAMIC_MINOR; > + ssif_bmc->miscdev.name = DEVICE_NAME; > + ssif_bmc->miscdev.fops = &ssif_bmc_fops; > + ssif_bmc->miscdev.parent = &client->dev; > + ret = misc_register(&ssif_bmc->miscdev); > + if (ret) > + goto out; > + > + ssif_bmc->client = client; > + ssif_bmc->client->flags |= I2C_CLIENT_SLAVE; > + > + /* Register I2C slave */ > + i2c_set_clientdata(client, ssif_bmc); > + ret = i2c_slave_register(client, ssif_bmc_cb); > + if (ret) { > + misc_deregister(&ssif_bmc->miscdev); > + goto out; > + } > + > + return ssif_bmc; > + > +out: > + devm_kfree(&client->dev, ssif_bmc); > + return ERR_PTR(ret); > +} > +EXPORT_SYMBOL(ssif_bmc_alloc); > + > +MODULE_AUTHOR("Chuong Tran "); > +MODULE_AUTHOR("Quan Nguyen "); > +MODULE_DESCRIPTION("Linux device driver of the BMC IPMI SSIF interface."); > +MODULE_LICENSE("GPL v2"); > diff --git a/drivers/char/ipmi/ssif_bmc.h b/drivers/char/ipmi/ssif_bmc.h > new file mode 100644 > index 000000000000..eab540061f14 > --- /dev/null > +++ b/drivers/char/ipmi/ssif_bmc.h > @@ -0,0 +1,93 @@ > +/* SPDX-License-Identifier: GPL-2.0+ */ > +/* > + * The driver for BMC side of SSIF interface > + * > + * Copyright (c) 2021, Ampere Computing LLC > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public License as > + * published by the Free Software Foundation; either version 2 of > + * the License, or (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program. If not, see . > + */ > +#ifndef __SSIF_BMC_H__ > +#define __SSIF_BMC_H__ > + > +#define DEVICE_NAME "ipmi-ssif-host" > + > +#define GET_8BIT_ADDR(addr_7bit) (((addr_7bit) << 1) & 0xff) > + > +#define MSG_PAYLOAD_LEN_MAX 252 > + > +/* 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 > + > +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; > +} > + > +#define SSIF_BMC_BUSY 0x01 > +#define SSIF_BMC_READY 0x02 > + > +struct ssif_bmc_ctx { > + struct i2c_client *client; > + struct miscdevice miscdev; > + u8 running; > + u8 smbus_cmd; > + struct ssif_msg request; > + bool request_available; > + struct ssif_msg response; > + bool response_in_progress; > + /* Response buffer for Multi-part Read Transaction */ > + u8 response_buf[MAX_PAYLOAD_PER_TRANSACTION]; > + /* 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; > + size_t msg_idx; > + enum i2c_slave_event last_event; > + bool pec_support; > + /* spinlock */ > + spinlock_t lock; > + wait_queue_head_t wait_queue; > + void (*set_ssif_bmc_status)(struct ssif_bmc_ctx *ssif_bmc, unsigned int flags); > + void *priv; > +}; > + > +static inline struct ssif_bmc_ctx *to_ssif_bmc(struct file *file) > +{ > + return container_of(file->private_data, struct ssif_bmc_ctx, miscdev); > +} > + > +struct ssif_bmc_ctx *ssif_bmc_alloc(struct i2c_client *client, int sizeof_priv); > + > +#endif /* __SSIF_BMC_H__ */ > -- > 2.28.0 > From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 45599C433B4 for ; Wed, 19 May 2021 12:30:49 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 1C8B76135B for ; Wed, 19 May 2021 12:30:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S241398AbhESMcH (ORCPT ); Wed, 19 May 2021 08:32:07 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42316 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232850AbhESMcG (ORCPT ); Wed, 19 May 2021 08:32:06 -0400 Received: from mail-ot1-x332.google.com (mail-ot1-x332.google.com [IPv6:2607:f8b0:4864:20::332]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 768FDC06175F; Wed, 19 May 2021 05:30:46 -0700 (PDT) Received: by mail-ot1-x332.google.com with SMTP id i12-20020a05683033ecb02903346fa0f74dso937813otu.10; Wed, 19 May 2021 05:30:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:date:from:to:cc:subject:message-id:reply-to:references :mime-version:content-disposition:content-transfer-encoding :in-reply-to; bh=aKHr+1V+CDnfzSzbLj1hWsDUAY0cmFm/k2Vt/tEA6F8=; b=mS6dszP8bCc2Bg+C3HNJ90znzhnOLWLPWwIiOluenf/xCXlIEpAtt+46phu38p/Fwd 6eEb0hNH6g4T4MKxxgIqyzCgBs5WHfUPY9TSeC4WbfBgHoGSFDc/UDmAK9E9CA0wX7O6 z1J375Xmxq3LEb8QdLdZq8p5gFtUJS37C6E5P/+LYy2eqqNXQ0wlx8i0x1QmkWMizQ9x lqIxiiVb+5xD0JXUb9HkN4lQ81/NM71gwLE8cldY/aXtY4jpVAVhiLNUSgZvpuEV5QCc YUsCH/Dm9kwzqk48pzrWSDZzVvK5crEW+Np/tcOrpSIMQqgc/KxFD/NlKXezFylBmXYh poow== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:date:from:to:cc:subject:message-id :reply-to:references:mime-version:content-disposition :content-transfer-encoding:in-reply-to; bh=aKHr+1V+CDnfzSzbLj1hWsDUAY0cmFm/k2Vt/tEA6F8=; b=bgeuMXBagTXM3jzCsmQIfutOdn5DpgR7bzNkJiTTgsVt6EbK9JzSW4DWtMYgiKafTZ 0e41j/xPn52cWDap7eLEAGgoRIkDPTBXq8Ep1Eq7qsZChMp1lqdwFLjOHBmn05y896VX eIHHX8akvdfLrODjjuUaLY4gB+8UuSgZcN27kos7HJspZh24mdXaw2X6E0fz2kLcQakg hfh0EGgKrZowgXPetH9ofBDRAi/PUz8AWl6CMhAjkdemguoqNv1xENBSHzbPQkKDQcaz IbZTUsNssVPEe/8T7+FiksPmdQPM7+gUlavFuyMrUDmF7uEzGsh51q9iLPlGWz8pVKsH dOFw== X-Gm-Message-State: AOAM5307xHGygtnOjJpAOaoM8qkn03aOIXEgrFAVBeYTvZQj5IbEoO+H kMaJywjLLnJDRS8/2mZF8B6xyh9/pZgt X-Google-Smtp-Source: ABdhPJxOhBgHwUIx0RCQQWzAVbOph3yRvDgdajDuJH9n960Otk/URTgPiiYCbnqV6/LOlbQctg972Q== X-Received: by 2002:a05:6830:18fb:: with SMTP id d27mr8529362otf.235.1621427445589; Wed, 19 May 2021 05:30:45 -0700 (PDT) Received: from serve.minyard.net ([47.184.156.158]) by smtp.gmail.com with ESMTPSA id r2sm4471424otq.28.2021.05.19.05.30.44 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 19 May 2021 05:30:44 -0700 (PDT) Sender: Corey Minyard Received: from minyard.net (unknown [IPv6:2001:470:b8f6:1b:9144:ba66:ea13:f260]) by serve.minyard.net (Postfix) with ESMTPSA id 6AFE818000C; Wed, 19 May 2021 12:30:43 +0000 (UTC) Date: Wed, 19 May 2021 07:30:42 -0500 From: Corey Minyard To: Quan Nguyen Cc: Rob Herring , Joel Stanley , Andrew Jeffery , Brendan Higgins , Benjamin Herrenschmidt , Wolfram Sang , Philipp Zabel , 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, Open Source Submission , Phong Vo , "Thang Q . Nguyen" , openbmc@lists.ozlabs.org Subject: Re: [PATCH v3 2/7] ipmi: ssif_bmc: Add SSIF BMC driver Message-ID: <20210519123042.GF2921206@minyard.net> Reply-To: minyard@acm.org References: <20210519074934.20712-1-quan@os.amperecomputing.com> <20210519074934.20712-3-quan@os.amperecomputing.com> MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Disposition: inline Content-Transfer-Encoding: 8bit In-Reply-To: <20210519074934.20712-3-quan@os.amperecomputing.com> Precedence: bulk List-ID: X-Mailing-List: linux-i2c@vger.kernel.org On Wed, May 19, 2021 at 02:49:29PM +0700, Quan Nguyen wrote: > 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 > --- > v3: > + Removed redundant license info [Joel] > + Switched to use traditional if-else [Joel] > + Removed unused ssif_bmc_ioctl() [Joel] > + Made handle_request()/complete_response() to return void [Joel] > + Refactored send_ssif_bmc_response()/receive_ssif_bmc_request() [Corey] > + Removed mutex [Corey] > + Use spin_lock/unlock_irqsave/restore in callback [Corey] > + Removed the unnecessary memset [Corey] > + Switch to use dev_err() [Corey] > > v2: > + Fixed compiling error with COMPILE_TEST for arc > > drivers/char/ipmi/Kconfig | 11 + > drivers/char/ipmi/Makefile | 1 + > drivers/char/ipmi/ssif_bmc.c | 605 +++++++++++++++++++++++++++++++++++ > drivers/char/ipmi/ssif_bmc.h | 93 ++++++ > 4 files changed, 710 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 07847d9a459a..ad5c5161bcd6 100644 > --- a/drivers/char/ipmi/Kconfig > +++ b/drivers/char/ipmi/Kconfig > @@ -133,6 +133,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 0822adc2ec41..d04a214d74c4 100644 > --- a/drivers/char/ipmi/Makefile > +++ b/drivers/char/ipmi/Makefile > @@ -27,3 +27,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..d0ea7059b1db > --- /dev/null > +++ b/drivers/char/ipmi/ssif_bmc.c > @@ -0,0 +1,605 @@ > +// SPDX-License-Identifier: GPL-2.0+ > +/* > + * The driver for BMC side of SSIF interface > + * > + * Copyright (c) 2021, Ampere Computing LLC > + * > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include "ssif_bmc.h" > + > +/* 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) { > + if (file->f_flags & O_NONBLOCK) { There is no real need to check this under the lock. It would simplify the end of this function if you checked this outside the lock. > + ret = -EAGAIN; > + goto out_unlock; > + } > + spin_unlock_irqrestore(&ssif_bmc->lock, flags); > + ret = wait_event_interruptible(ssif_bmc->wait_queue, > + ssif_bmc->request_available); > + if (ret) > + return ret; > + spin_lock_irqsave(&ssif_bmc->lock, flags); > + } > + > + count = min_t(ssize_t, ssif_msg_len(&ssif_bmc->request), > + min_t(ssize_t, sizeof(struct ssif_msg), count)); Just curious, what happens if userland supplies a buffer that is too small? Is data lost? In that case, I would think returning an error here would be the better thing, as opposed to silently truncating the message. > + 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); > + goto out; > + > +out_unlock: > + spin_unlock_irqrestore(&ssif_bmc->lock, flags); > +out: > + 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) { > + if (file->f_flags & O_NONBLOCK) { Same comment as O_NONBLOCK before. > + ret = -EAGAIN; > + goto out_unlock; > + } > + spin_unlock_irqrestore(&ssif_bmc->lock, flags); > + ret = wait_event_interruptible(ssif_bmc->wait_queue, > + !ssif_bmc->response_in_progress); > + if (ret) > + goto out; > + spin_lock_irqsave(&ssif_bmc->lock, flags); > + } > + > + memcpy(&ssif_bmc->response, &msg, count); > + ssif_bmc->is_singlepart_read = (ssif_msg_len(&msg) <= MAX_PAYLOAD_PER_TRANSACTION + 1); > + ssif_bmc->response_in_progress = true; > + if (ssif_bmc->set_ssif_bmc_status) > + ssif_bmc->set_ssif_bmc_status(ssif_bmc, SSIF_BMC_READY); > + > +out_unlock: > + spin_unlock_irqrestore(&ssif_bmc->lock, flags); > + > +out: > + return (ret < 0) ? ret : count; > +} > + > +static int ssif_bmc_open(struct inode *inode, struct file *file) > +{ > + struct ssif_bmc_ctx *ssif_bmc = to_ssif_bmc(file); > + int ret = 0; > + > + spin_lock_irq(&ssif_bmc->lock); > + if (!ssif_bmc->running) > + ssif_bmc->running = 1; > + else > + ret = -EBUSY; > + spin_unlock_irq(&ssif_bmc->lock); > + > + return ret; > +} > + > +static unsigned int ssif_bmc_poll(struct file *file, poll_table *wait) > +{ > + struct ssif_bmc_ctx *ssif_bmc = to_ssif_bmc(file); > + unsigned int mask = 0; > + > + poll_wait(file, &ssif_bmc->wait_queue, wait); > + > + spin_lock_irq(&ssif_bmc->lock); > + /* > + * The request message is now available so 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 handle_request(struct ssif_bmc_ctx *ssif_bmc) > +{ > + if (ssif_bmc->set_ssif_bmc_status) > + ssif_bmc->set_ssif_bmc_status(ssif_bmc, SSIF_BMC_BUSY); > + > + /* Request message is available to process */ > + ssif_bmc->request_available = true; > + /* > + * This is the new READ request. > + */ > + wake_up_all(&ssif_bmc->wait_queue); > +} > + > +/* Called with ssif_bmc->lock held. */ > +static void complete_response(struct ssif_bmc_ctx *ssif_bmc) > +{ > + /* Invalidate response in buffer to denote it having been sent. */ > + ssif_bmc->response.len = 0; > + ssif_bmc->response_in_progress = false; > + ssif_bmc->nbytes_processed = 0; > + ssif_bmc->remain_len = 0; > + wake_up_all(&ssif_bmc->wait_queue); > +} > + > +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, > + "Error: Unexpected SMBus command received 0x%x\n", 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, > + "Error: Unexpected SMBus command received 0x%x\n", > + 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 smbus_cmd; > + > + buf = (u8 *)&ssif_bmc->request; > + if (ssif_bmc->msg_idx >= sizeof(struct ssif_msg)) Shouldn't you abort the message if you get too much data? Otherwise you get silent truncation. > + return; > + > + smbus_cmd = ssif_bmc->smbus_cmd; > + switch (smbus_cmd) { > + case SSIF_IPMI_SINGLEPART_WRITE: > + /* Single-part write */ > + buf[ssif_bmc->msg_idx - 1] = *val; > + ssif_bmc->msg_idx++; > + > + break; Generally you put the space after the break, not before. You did this right before, but didn't from here down in the file. > + case SSIF_IPMI_MULTIPART_WRITE_START: > + /* Reset length to zero */ > + if (ssif_bmc->msg_idx == 1) > + ssif_bmc->request.len = 0; What happens if you get this and you are in the middle of a message? > + > + fallthrough; > + case SSIF_IPMI_MULTIPART_WRITE_MIDDLE: > + case SSIF_IPMI_MULTIPART_WRITE_END: What happens if you get these and you are not in a message? > + /* Multi-part write, 2nd byte received is length */ > + if (ssif_bmc->msg_idx == 1) { > + ssif_bmc->request.len += *val; > + ssif_bmc->recv_len = *val; > + } 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, > + "Error: Unexpected SMBus command received 0x%x\n", ssif_bmc->smbus_cmd); > + break; > + } > +} > + > +static bool validate_pec(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; > + return true; > + } > + > + if ((ssif_bmc->msg_idx - 1) != (ssif_msg_len(&ssif_bmc->request) + 1)) > + goto error; > + > + /* 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; > + return true; > + } > + > + if ((ssif_bmc->msg_idx - 1 + index) != (ssif_msg_len(&ssif_bmc->request) + 1)) > + goto error; > + > + /* 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-bytes 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: > + break; > + } > + > + return ret; > +error: > + /* Do not expect to go to this case */ > + dev_err(&ssif_bmc->client->dev, > + "Error: Unexpected length received %d\n", ssif_msg_len(&ssif_bmc->request)); > + > + return false; > +} > + > +static void complete_write_received(struct ssif_bmc_ctx *ssif_bmc) > +{ > + u8 cmd = ssif_bmc->smbus_cmd; > + > + /* A BMC that receives an invalid PEC shall 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_pec(ssif_bmc)) { > + dev_err(&ssif_bmc->client->dev, "Received invalid PEC\n"); > + return; > + } > + > + if (cmd == SSIF_IPMI_SINGLEPART_WRITE || cmd == SSIF_IPMI_MULTIPART_WRITE_END) > + handle_request(ssif_bmc); > +} > + > +static void initialize_transfer(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 (ssif_bmc->smbus_cmd == SSIF_IPMI_SINGLEPART_WRITE || > + ssif_bmc->smbus_cmd == SSIF_IPMI_MULTIPART_WRITE_START) { > + /* > + * The response can be delayed in BMC causing host SSIF driver > + * to timeout and send a new request once BMC slave is ready. > + * In that case check for pending response and clear it > + */ > + if (ssif_bmc->response_in_progress) { > + dev_err(&ssif_bmc->client->dev, > + "Warn: SSIF new request with pending response"); > + complete_response(ssif_bmc); > + } > + } else if (unlikely(ssif_bmc->smbus_cmd != SSIF_IPMI_SINGLEPART_READ && > + ssif_bmc->smbus_cmd != SSIF_IPMI_MULTIPART_WRITE_MIDDLE && > + ssif_bmc->smbus_cmd != SSIF_IPMI_MULTIPART_WRITE_END && > + ssif_bmc->smbus_cmd != SSIF_IPMI_MULTIPART_READ_START && > + ssif_bmc->smbus_cmd != SSIF_IPMI_MULTIPART_READ_MIDDLE)) { > + /* Unknown command, clear it */ > + dev_err(&ssif_bmc->client->dev, "Warn: Unknown SMBus command"); > + complete_response(ssif_bmc); > + } > +} > + > +/* > + * Callback function to handle I2C slave events > + */ > +static int ssif_bmc_cb(struct i2c_client *client, enum i2c_slave_event event, u8 *val) > +{ > + unsigned long flags; > + struct ssif_bmc_ctx *ssif_bmc = i2c_get_clientdata(client); > + > + spin_lock_irqsave(&ssif_bmc->lock, flags); > + > + /* I2C Event Handler: > + * I2C_SLAVE_READ_REQUESTED 0x0 > + * I2C_SLAVE_WRITE_REQUESTED 0x1 > + * I2C_SLAVE_READ_PROCESSED 0x2 > + * I2C_SLAVE_WRITE_RECEIVED 0x3 > + * I2C_SLAVE_STOP 0x4 > + */ > + switch (event) { > + case I2C_SLAVE_READ_REQUESTED: > + ssif_bmc->msg_idx = 0; > + if (ssif_bmc->is_singlepart_read) > + *val = ssif_bmc->response.len; > + else > + set_multipart_response_buffer(ssif_bmc, val); > + break; > + > + case I2C_SLAVE_WRITE_REQUESTED: > + ssif_bmc->msg_idx = 0; > + break; > + > + case I2C_SLAVE_READ_PROCESSED: > + handle_read_processed(ssif_bmc, val); > + break; > + > + case I2C_SLAVE_WRITE_RECEIVED: > + if (ssif_bmc->msg_idx) > + handle_write_received(ssif_bmc, val); > + else > + initialize_transfer(ssif_bmc, val); > + > + break; > + > + case I2C_SLAVE_STOP: > + if (ssif_bmc->last_event == I2C_SLAVE_WRITE_RECEIVED) > + complete_write_received(ssif_bmc); > + /* Reset message index */ > + ssif_bmc->msg_idx = 0; > + break; > + > + default: > + break; > + } > + ssif_bmc->last_event = event; > + spin_unlock_irqrestore(&ssif_bmc->lock, flags); > + > + return 0; > +} > + > +struct ssif_bmc_ctx *ssif_bmc_alloc(struct i2c_client *client, int sizeof_priv) > +{ > + struct ssif_bmc_ctx *ssif_bmc; > + int ret; > + > + ssif_bmc = devm_kzalloc(&client->dev, sizeof(*ssif_bmc) + sizeof_priv, GFP_KERNEL); > + if (!ssif_bmc) > + return ERR_PTR(-ENOMEM); > + > + spin_lock_init(&ssif_bmc->lock); > + > + init_waitqueue_head(&ssif_bmc->wait_queue); > + ssif_bmc->request_available = false; > + ssif_bmc->response_in_progress = false; > + > + /* Register misc device interface */ > + ssif_bmc->miscdev.minor = MISC_DYNAMIC_MINOR; > + ssif_bmc->miscdev.name = DEVICE_NAME; > + ssif_bmc->miscdev.fops = &ssif_bmc_fops; > + ssif_bmc->miscdev.parent = &client->dev; > + ret = misc_register(&ssif_bmc->miscdev); > + if (ret) > + goto out; > + > + ssif_bmc->client = client; > + ssif_bmc->client->flags |= I2C_CLIENT_SLAVE; > + > + /* Register I2C slave */ > + i2c_set_clientdata(client, ssif_bmc); > + ret = i2c_slave_register(client, ssif_bmc_cb); > + if (ret) { > + misc_deregister(&ssif_bmc->miscdev); > + goto out; > + } > + > + return ssif_bmc; > + > +out: > + devm_kfree(&client->dev, ssif_bmc); > + return ERR_PTR(ret); > +} > +EXPORT_SYMBOL(ssif_bmc_alloc); > + > +MODULE_AUTHOR("Chuong Tran "); > +MODULE_AUTHOR("Quan Nguyen "); > +MODULE_DESCRIPTION("Linux device driver of the BMC IPMI SSIF interface."); > +MODULE_LICENSE("GPL v2"); > diff --git a/drivers/char/ipmi/ssif_bmc.h b/drivers/char/ipmi/ssif_bmc.h > new file mode 100644 > index 000000000000..eab540061f14 > --- /dev/null > +++ b/drivers/char/ipmi/ssif_bmc.h > @@ -0,0 +1,93 @@ > +/* SPDX-License-Identifier: GPL-2.0+ */ > +/* > + * The driver for BMC side of SSIF interface > + * > + * Copyright (c) 2021, Ampere Computing LLC > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public License as > + * published by the Free Software Foundation; either version 2 of > + * the License, or (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program. If not, see . > + */ > +#ifndef __SSIF_BMC_H__ > +#define __SSIF_BMC_H__ > + > +#define DEVICE_NAME "ipmi-ssif-host" > + > +#define GET_8BIT_ADDR(addr_7bit) (((addr_7bit) << 1) & 0xff) > + > +#define MSG_PAYLOAD_LEN_MAX 252 > + > +/* 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 > + > +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; > +} > + > +#define SSIF_BMC_BUSY 0x01 > +#define SSIF_BMC_READY 0x02 > + > +struct ssif_bmc_ctx { > + struct i2c_client *client; > + struct miscdevice miscdev; > + u8 running; > + u8 smbus_cmd; > + struct ssif_msg request; > + bool request_available; > + struct ssif_msg response; > + bool response_in_progress; > + /* Response buffer for Multi-part Read Transaction */ > + u8 response_buf[MAX_PAYLOAD_PER_TRANSACTION]; > + /* 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; > + size_t msg_idx; > + enum i2c_slave_event last_event; > + bool pec_support; > + /* spinlock */ > + spinlock_t lock; > + wait_queue_head_t wait_queue; > + void (*set_ssif_bmc_status)(struct ssif_bmc_ctx *ssif_bmc, unsigned int flags); > + void *priv; > +}; > + > +static inline struct ssif_bmc_ctx *to_ssif_bmc(struct file *file) > +{ > + return container_of(file->private_data, struct ssif_bmc_ctx, miscdev); > +} > + > +struct ssif_bmc_ctx *ssif_bmc_alloc(struct i2c_client *client, int sizeof_priv); > + > +#endif /* __SSIF_BMC_H__ */ > -- > 2.28.0 > From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.5 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id EF301C433ED for ; Wed, 19 May 2021 12:31:26 +0000 (UTC) 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 mail.kernel.org (Postfix) with ESMTPS id 5134A6124C for ; Wed, 19 May 2021 12:31:26 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 5134A6124C Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=acm.org Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=openbmc-bounces+openbmc=archiver.kernel.org@lists.ozlabs.org Received: from boromir.ozlabs.org (localhost [IPv6:::1]) by lists.ozlabs.org (Postfix) with ESMTP id 4FlXKn0JbHz2yxS for ; Wed, 19 May 2021 22:31:25 +1000 (AEST) Authentication-Results: lists.ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20161025 header.b=mS6dszP8; dkim-atps=neutral Authentication-Results: lists.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gmail.com (client-ip=2607:f8b0:4864:20::333; helo=mail-ot1-x333.google.com; envelope-from=tcminyard@gmail.com; receiver=) Authentication-Results: lists.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20161025 header.b=mS6dszP8; dkim-atps=neutral Received: from mail-ot1-x333.google.com (mail-ot1-x333.google.com [IPv6:2607:f8b0:4864:20::333]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 4FlXK81gXlz2yQy; Wed, 19 May 2021 22:30:49 +1000 (AEST) Received: by mail-ot1-x333.google.com with SMTP id i14-20020a9d624e0000b029033683c71999so407746otk.5; Wed, 19 May 2021 05:30:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:date:from:to:cc:subject:message-id:reply-to:references :mime-version:content-disposition:content-transfer-encoding :in-reply-to; bh=aKHr+1V+CDnfzSzbLj1hWsDUAY0cmFm/k2Vt/tEA6F8=; b=mS6dszP8bCc2Bg+C3HNJ90znzhnOLWLPWwIiOluenf/xCXlIEpAtt+46phu38p/Fwd 6eEb0hNH6g4T4MKxxgIqyzCgBs5WHfUPY9TSeC4WbfBgHoGSFDc/UDmAK9E9CA0wX7O6 z1J375Xmxq3LEb8QdLdZq8p5gFtUJS37C6E5P/+LYy2eqqNXQ0wlx8i0x1QmkWMizQ9x lqIxiiVb+5xD0JXUb9HkN4lQ81/NM71gwLE8cldY/aXtY4jpVAVhiLNUSgZvpuEV5QCc YUsCH/Dm9kwzqk48pzrWSDZzVvK5crEW+Np/tcOrpSIMQqgc/KxFD/NlKXezFylBmXYh poow== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:date:from:to:cc:subject:message-id :reply-to:references:mime-version:content-disposition :content-transfer-encoding:in-reply-to; bh=aKHr+1V+CDnfzSzbLj1hWsDUAY0cmFm/k2Vt/tEA6F8=; b=ZetJ2cSMISdKjS0ThJT6owAk+fGdSHmb2YYEY6I9Mon26k9N4iNt6gO/b744yoCyPL bI1N4P/2BkDvlp5rwrL0SD1+6BH/H6ln+4YxsG8EMNX2G0e9iRSeFIz2twuNWMjtTORN LA+Za0ZpGoOsT7fEil0qMbwJ4bUU2HTeR6UrkfB/aSZFRfFJpvqdsTL3cZvVmoO7dqQG B9cOMH6fDve50LDqIKh0o1t4TvVJoWAzXoTKDKue//FAhhIDV+kR0FIOVCZxMTh7RDe2 6yXaLk5HVlinKl9F9UPX6C+iMVP79eydeYZqLDI+4zDPZA1Y9GyFLC86JvvozzB8Lr5/ TUrA== X-Gm-Message-State: AOAM5308T4bq4WCpDwiliKNn3xGsS+PD1Q1dmZ10RfN3allMwE/JPwVW sROL5tHGlxrqj+pO2bdYRA== X-Google-Smtp-Source: ABdhPJxOhBgHwUIx0RCQQWzAVbOph3yRvDgdajDuJH9n960Otk/URTgPiiYCbnqV6/LOlbQctg972Q== X-Received: by 2002:a05:6830:18fb:: with SMTP id d27mr8529362otf.235.1621427445589; Wed, 19 May 2021 05:30:45 -0700 (PDT) Received: from serve.minyard.net ([47.184.156.158]) by smtp.gmail.com with ESMTPSA id r2sm4471424otq.28.2021.05.19.05.30.44 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 19 May 2021 05:30:44 -0700 (PDT) Received: from minyard.net (unknown [IPv6:2001:470:b8f6:1b:9144:ba66:ea13:f260]) by serve.minyard.net (Postfix) with ESMTPSA id 6AFE818000C; Wed, 19 May 2021 12:30:43 +0000 (UTC) Date: Wed, 19 May 2021 07:30:42 -0500 From: Corey Minyard To: Quan Nguyen Subject: Re: [PATCH v3 2/7] ipmi: ssif_bmc: Add SSIF BMC driver Message-ID: <20210519123042.GF2921206@minyard.net> References: <20210519074934.20712-1-quan@os.amperecomputing.com> <20210519074934.20712-3-quan@os.amperecomputing.com> MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Disposition: inline Content-Transfer-Encoding: 8bit In-Reply-To: <20210519074934.20712-3-quan@os.amperecomputing.com> X-BeenThere: openbmc@lists.ozlabs.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Development list for OpenBMC List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: minyard@acm.org Cc: devicetree@vger.kernel.org, linux-aspeed@lists.ozlabs.org, Andrew Jeffery , openbmc@lists.ozlabs.org, "Thang Q . Nguyen" , Brendan Higgins , linux-kernel@vger.kernel.org, Phong Vo , Wolfram Sang , Rob Herring , Philipp Zabel , openipmi-developer@lists.sourceforge.net, Open Source Submission , linux-arm-kernel@lists.infradead.org, linux-i2c@vger.kernel.org Errors-To: openbmc-bounces+openbmc=archiver.kernel.org@lists.ozlabs.org Sender: "openbmc" On Wed, May 19, 2021 at 02:49:29PM +0700, Quan Nguyen wrote: > 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 > --- > v3: > + Removed redundant license info [Joel] > + Switched to use traditional if-else [Joel] > + Removed unused ssif_bmc_ioctl() [Joel] > + Made handle_request()/complete_response() to return void [Joel] > + Refactored send_ssif_bmc_response()/receive_ssif_bmc_request() [Corey] > + Removed mutex [Corey] > + Use spin_lock/unlock_irqsave/restore in callback [Corey] > + Removed the unnecessary memset [Corey] > + Switch to use dev_err() [Corey] > > v2: > + Fixed compiling error with COMPILE_TEST for arc > > drivers/char/ipmi/Kconfig | 11 + > drivers/char/ipmi/Makefile | 1 + > drivers/char/ipmi/ssif_bmc.c | 605 +++++++++++++++++++++++++++++++++++ > drivers/char/ipmi/ssif_bmc.h | 93 ++++++ > 4 files changed, 710 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 07847d9a459a..ad5c5161bcd6 100644 > --- a/drivers/char/ipmi/Kconfig > +++ b/drivers/char/ipmi/Kconfig > @@ -133,6 +133,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 0822adc2ec41..d04a214d74c4 100644 > --- a/drivers/char/ipmi/Makefile > +++ b/drivers/char/ipmi/Makefile > @@ -27,3 +27,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..d0ea7059b1db > --- /dev/null > +++ b/drivers/char/ipmi/ssif_bmc.c > @@ -0,0 +1,605 @@ > +// SPDX-License-Identifier: GPL-2.0+ > +/* > + * The driver for BMC side of SSIF interface > + * > + * Copyright (c) 2021, Ampere Computing LLC > + * > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include "ssif_bmc.h" > + > +/* 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) { > + if (file->f_flags & O_NONBLOCK) { There is no real need to check this under the lock. It would simplify the end of this function if you checked this outside the lock. > + ret = -EAGAIN; > + goto out_unlock; > + } > + spin_unlock_irqrestore(&ssif_bmc->lock, flags); > + ret = wait_event_interruptible(ssif_bmc->wait_queue, > + ssif_bmc->request_available); > + if (ret) > + return ret; > + spin_lock_irqsave(&ssif_bmc->lock, flags); > + } > + > + count = min_t(ssize_t, ssif_msg_len(&ssif_bmc->request), > + min_t(ssize_t, sizeof(struct ssif_msg), count)); Just curious, what happens if userland supplies a buffer that is too small? Is data lost? In that case, I would think returning an error here would be the better thing, as opposed to silently truncating the message. > + 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); > + goto out; > + > +out_unlock: > + spin_unlock_irqrestore(&ssif_bmc->lock, flags); > +out: > + 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) { > + if (file->f_flags & O_NONBLOCK) { Same comment as O_NONBLOCK before. > + ret = -EAGAIN; > + goto out_unlock; > + } > + spin_unlock_irqrestore(&ssif_bmc->lock, flags); > + ret = wait_event_interruptible(ssif_bmc->wait_queue, > + !ssif_bmc->response_in_progress); > + if (ret) > + goto out; > + spin_lock_irqsave(&ssif_bmc->lock, flags); > + } > + > + memcpy(&ssif_bmc->response, &msg, count); > + ssif_bmc->is_singlepart_read = (ssif_msg_len(&msg) <= MAX_PAYLOAD_PER_TRANSACTION + 1); > + ssif_bmc->response_in_progress = true; > + if (ssif_bmc->set_ssif_bmc_status) > + ssif_bmc->set_ssif_bmc_status(ssif_bmc, SSIF_BMC_READY); > + > +out_unlock: > + spin_unlock_irqrestore(&ssif_bmc->lock, flags); > + > +out: > + return (ret < 0) ? ret : count; > +} > + > +static int ssif_bmc_open(struct inode *inode, struct file *file) > +{ > + struct ssif_bmc_ctx *ssif_bmc = to_ssif_bmc(file); > + int ret = 0; > + > + spin_lock_irq(&ssif_bmc->lock); > + if (!ssif_bmc->running) > + ssif_bmc->running = 1; > + else > + ret = -EBUSY; > + spin_unlock_irq(&ssif_bmc->lock); > + > + return ret; > +} > + > +static unsigned int ssif_bmc_poll(struct file *file, poll_table *wait) > +{ > + struct ssif_bmc_ctx *ssif_bmc = to_ssif_bmc(file); > + unsigned int mask = 0; > + > + poll_wait(file, &ssif_bmc->wait_queue, wait); > + > + spin_lock_irq(&ssif_bmc->lock); > + /* > + * The request message is now available so 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 handle_request(struct ssif_bmc_ctx *ssif_bmc) > +{ > + if (ssif_bmc->set_ssif_bmc_status) > + ssif_bmc->set_ssif_bmc_status(ssif_bmc, SSIF_BMC_BUSY); > + > + /* Request message is available to process */ > + ssif_bmc->request_available = true; > + /* > + * This is the new READ request. > + */ > + wake_up_all(&ssif_bmc->wait_queue); > +} > + > +/* Called with ssif_bmc->lock held. */ > +static void complete_response(struct ssif_bmc_ctx *ssif_bmc) > +{ > + /* Invalidate response in buffer to denote it having been sent. */ > + ssif_bmc->response.len = 0; > + ssif_bmc->response_in_progress = false; > + ssif_bmc->nbytes_processed = 0; > + ssif_bmc->remain_len = 0; > + wake_up_all(&ssif_bmc->wait_queue); > +} > + > +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, > + "Error: Unexpected SMBus command received 0x%x\n", 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, > + "Error: Unexpected SMBus command received 0x%x\n", > + 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 smbus_cmd; > + > + buf = (u8 *)&ssif_bmc->request; > + if (ssif_bmc->msg_idx >= sizeof(struct ssif_msg)) Shouldn't you abort the message if you get too much data? Otherwise you get silent truncation. > + return; > + > + smbus_cmd = ssif_bmc->smbus_cmd; > + switch (smbus_cmd) { > + case SSIF_IPMI_SINGLEPART_WRITE: > + /* Single-part write */ > + buf[ssif_bmc->msg_idx - 1] = *val; > + ssif_bmc->msg_idx++; > + > + break; Generally you put the space after the break, not before. You did this right before, but didn't from here down in the file. > + case SSIF_IPMI_MULTIPART_WRITE_START: > + /* Reset length to zero */ > + if (ssif_bmc->msg_idx == 1) > + ssif_bmc->request.len = 0; What happens if you get this and you are in the middle of a message? > + > + fallthrough; > + case SSIF_IPMI_MULTIPART_WRITE_MIDDLE: > + case SSIF_IPMI_MULTIPART_WRITE_END: What happens if you get these and you are not in a message? > + /* Multi-part write, 2nd byte received is length */ > + if (ssif_bmc->msg_idx == 1) { > + ssif_bmc->request.len += *val; > + ssif_bmc->recv_len = *val; > + } 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, > + "Error: Unexpected SMBus command received 0x%x\n", ssif_bmc->smbus_cmd); > + break; > + } > +} > + > +static bool validate_pec(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; > + return true; > + } > + > + if ((ssif_bmc->msg_idx - 1) != (ssif_msg_len(&ssif_bmc->request) + 1)) > + goto error; > + > + /* 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; > + return true; > + } > + > + if ((ssif_bmc->msg_idx - 1 + index) != (ssif_msg_len(&ssif_bmc->request) + 1)) > + goto error; > + > + /* 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-bytes 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: > + break; > + } > + > + return ret; > +error: > + /* Do not expect to go to this case */ > + dev_err(&ssif_bmc->client->dev, > + "Error: Unexpected length received %d\n", ssif_msg_len(&ssif_bmc->request)); > + > + return false; > +} > + > +static void complete_write_received(struct ssif_bmc_ctx *ssif_bmc) > +{ > + u8 cmd = ssif_bmc->smbus_cmd; > + > + /* A BMC that receives an invalid PEC shall 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_pec(ssif_bmc)) { > + dev_err(&ssif_bmc->client->dev, "Received invalid PEC\n"); > + return; > + } > + > + if (cmd == SSIF_IPMI_SINGLEPART_WRITE || cmd == SSIF_IPMI_MULTIPART_WRITE_END) > + handle_request(ssif_bmc); > +} > + > +static void initialize_transfer(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 (ssif_bmc->smbus_cmd == SSIF_IPMI_SINGLEPART_WRITE || > + ssif_bmc->smbus_cmd == SSIF_IPMI_MULTIPART_WRITE_START) { > + /* > + * The response can be delayed in BMC causing host SSIF driver > + * to timeout and send a new request once BMC slave is ready. > + * In that case check for pending response and clear it > + */ > + if (ssif_bmc->response_in_progress) { > + dev_err(&ssif_bmc->client->dev, > + "Warn: SSIF new request with pending response"); > + complete_response(ssif_bmc); > + } > + } else if (unlikely(ssif_bmc->smbus_cmd != SSIF_IPMI_SINGLEPART_READ && > + ssif_bmc->smbus_cmd != SSIF_IPMI_MULTIPART_WRITE_MIDDLE && > + ssif_bmc->smbus_cmd != SSIF_IPMI_MULTIPART_WRITE_END && > + ssif_bmc->smbus_cmd != SSIF_IPMI_MULTIPART_READ_START && > + ssif_bmc->smbus_cmd != SSIF_IPMI_MULTIPART_READ_MIDDLE)) { > + /* Unknown command, clear it */ > + dev_err(&ssif_bmc->client->dev, "Warn: Unknown SMBus command"); > + complete_response(ssif_bmc); > + } > +} > + > +/* > + * Callback function to handle I2C slave events > + */ > +static int ssif_bmc_cb(struct i2c_client *client, enum i2c_slave_event event, u8 *val) > +{ > + unsigned long flags; > + struct ssif_bmc_ctx *ssif_bmc = i2c_get_clientdata(client); > + > + spin_lock_irqsave(&ssif_bmc->lock, flags); > + > + /* I2C Event Handler: > + * I2C_SLAVE_READ_REQUESTED 0x0 > + * I2C_SLAVE_WRITE_REQUESTED 0x1 > + * I2C_SLAVE_READ_PROCESSED 0x2 > + * I2C_SLAVE_WRITE_RECEIVED 0x3 > + * I2C_SLAVE_STOP 0x4 > + */ > + switch (event) { > + case I2C_SLAVE_READ_REQUESTED: > + ssif_bmc->msg_idx = 0; > + if (ssif_bmc->is_singlepart_read) > + *val = ssif_bmc->response.len; > + else > + set_multipart_response_buffer(ssif_bmc, val); > + break; > + > + case I2C_SLAVE_WRITE_REQUESTED: > + ssif_bmc->msg_idx = 0; > + break; > + > + case I2C_SLAVE_READ_PROCESSED: > + handle_read_processed(ssif_bmc, val); > + break; > + > + case I2C_SLAVE_WRITE_RECEIVED: > + if (ssif_bmc->msg_idx) > + handle_write_received(ssif_bmc, val); > + else > + initialize_transfer(ssif_bmc, val); > + > + break; > + > + case I2C_SLAVE_STOP: > + if (ssif_bmc->last_event == I2C_SLAVE_WRITE_RECEIVED) > + complete_write_received(ssif_bmc); > + /* Reset message index */ > + ssif_bmc->msg_idx = 0; > + break; > + > + default: > + break; > + } > + ssif_bmc->last_event = event; > + spin_unlock_irqrestore(&ssif_bmc->lock, flags); > + > + return 0; > +} > + > +struct ssif_bmc_ctx *ssif_bmc_alloc(struct i2c_client *client, int sizeof_priv) > +{ > + struct ssif_bmc_ctx *ssif_bmc; > + int ret; > + > + ssif_bmc = devm_kzalloc(&client->dev, sizeof(*ssif_bmc) + sizeof_priv, GFP_KERNEL); > + if (!ssif_bmc) > + return ERR_PTR(-ENOMEM); > + > + spin_lock_init(&ssif_bmc->lock); > + > + init_waitqueue_head(&ssif_bmc->wait_queue); > + ssif_bmc->request_available = false; > + ssif_bmc->response_in_progress = false; > + > + /* Register misc device interface */ > + ssif_bmc->miscdev.minor = MISC_DYNAMIC_MINOR; > + ssif_bmc->miscdev.name = DEVICE_NAME; > + ssif_bmc->miscdev.fops = &ssif_bmc_fops; > + ssif_bmc->miscdev.parent = &client->dev; > + ret = misc_register(&ssif_bmc->miscdev); > + if (ret) > + goto out; > + > + ssif_bmc->client = client; > + ssif_bmc->client->flags |= I2C_CLIENT_SLAVE; > + > + /* Register I2C slave */ > + i2c_set_clientdata(client, ssif_bmc); > + ret = i2c_slave_register(client, ssif_bmc_cb); > + if (ret) { > + misc_deregister(&ssif_bmc->miscdev); > + goto out; > + } > + > + return ssif_bmc; > + > +out: > + devm_kfree(&client->dev, ssif_bmc); > + return ERR_PTR(ret); > +} > +EXPORT_SYMBOL(ssif_bmc_alloc); > + > +MODULE_AUTHOR("Chuong Tran "); > +MODULE_AUTHOR("Quan Nguyen "); > +MODULE_DESCRIPTION("Linux device driver of the BMC IPMI SSIF interface."); > +MODULE_LICENSE("GPL v2"); > diff --git a/drivers/char/ipmi/ssif_bmc.h b/drivers/char/ipmi/ssif_bmc.h > new file mode 100644 > index 000000000000..eab540061f14 > --- /dev/null > +++ b/drivers/char/ipmi/ssif_bmc.h > @@ -0,0 +1,93 @@ > +/* SPDX-License-Identifier: GPL-2.0+ */ > +/* > + * The driver for BMC side of SSIF interface > + * > + * Copyright (c) 2021, Ampere Computing LLC > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public License as > + * published by the Free Software Foundation; either version 2 of > + * the License, or (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program. If not, see . > + */ > +#ifndef __SSIF_BMC_H__ > +#define __SSIF_BMC_H__ > + > +#define DEVICE_NAME "ipmi-ssif-host" > + > +#define GET_8BIT_ADDR(addr_7bit) (((addr_7bit) << 1) & 0xff) > + > +#define MSG_PAYLOAD_LEN_MAX 252 > + > +/* 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 > + > +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; > +} > + > +#define SSIF_BMC_BUSY 0x01 > +#define SSIF_BMC_READY 0x02 > + > +struct ssif_bmc_ctx { > + struct i2c_client *client; > + struct miscdevice miscdev; > + u8 running; > + u8 smbus_cmd; > + struct ssif_msg request; > + bool request_available; > + struct ssif_msg response; > + bool response_in_progress; > + /* Response buffer for Multi-part Read Transaction */ > + u8 response_buf[MAX_PAYLOAD_PER_TRANSACTION]; > + /* 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; > + size_t msg_idx; > + enum i2c_slave_event last_event; > + bool pec_support; > + /* spinlock */ > + spinlock_t lock; > + wait_queue_head_t wait_queue; > + void (*set_ssif_bmc_status)(struct ssif_bmc_ctx *ssif_bmc, unsigned int flags); > + void *priv; > +}; > + > +static inline struct ssif_bmc_ctx *to_ssif_bmc(struct file *file) > +{ > + return container_of(file->private_data, struct ssif_bmc_ctx, miscdev); > +} > + > +struct ssif_bmc_ctx *ssif_bmc_alloc(struct i2c_client *client, int sizeof_priv); > + > +#endif /* __SSIF_BMC_H__ */ > -- > 2.28.0 > From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-14.1 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 83755C433B4 for ; Wed, 19 May 2021 12:33:25 +0000 (UTC) Received: from desiato.infradead.org (desiato.infradead.org [90.155.92.199]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id B43EE6108B for ; Wed, 19 May 2021 12:33:24 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org B43EE6108B Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=acm.org Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=desiato.20200630; h=Sender:Content-Transfer-Encoding :Content-Type:Reply-To:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:In-Reply-To:MIME-Version:References:Message-ID: Subject:Cc:To:From:Date:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=PGvXhtpP7IUJbOZ0b/tWCYnmpLEizgcChmwNN313OBU=; b=Q8civLuPOdJAUev0DrzgTXA5I bpdO5uVnr9gk4vPa1En6Xc/zTPrNuDZCxWEKj7XPu+VAf2xnvVUipZa1DJa3iTEs+Q7TWZqI4lUYU bUB27CpcaaZRofyBsW0tYjpqvaygjmaE0eeszN45SK6m4Cx0Fz8gTc0ut39zpYFRUK2xhnRdZXtmo uWIr7M2S5NekeT1RvHa9Jxs0vvl5EmmBhw9kAaqxDTmjlRsuFpe82j1QUq9KxnKx8iSyiher2hITt CdkZdtCsDZO/2RNS1ABx387GwacjlHoarrayncSReH8PSFUK6ShYOrmmIYTOqEC81iA6VvMfXoAHl vtOkTzxVA==; Received: from localhost ([::1] helo=desiato.infradead.org) by desiato.infradead.org with esmtp (Exim 4.94 #2 (Red Hat Linux)) id 1ljLLk-003uJt-Rt; Wed, 19 May 2021 12:30:56 +0000 Received: from bombadil.infradead.org ([2607:7c80:54:e::133]) by desiato.infradead.org with esmtps (Exim 4.94 #2 (Red Hat Linux)) id 1ljLLg-003uJW-Sc for linux-arm-kernel@desiato.infradead.org; Wed, 19 May 2021 12:30:53 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=bombadil.20210309; h=In-Reply-To:Content-Transfer-Encoding :Content-Type:MIME-Version:References:Reply-To:Message-ID:Subject:Cc:To:From: Date:Sender:Content-ID:Content-Description; bh=aKHr+1V+CDnfzSzbLj1hWsDUAY0cmFm/k2Vt/tEA6F8=; b=E9gNRA6qtFGAA1LUzDpr0a1kH6 7yv+La6ot2LvVZvJd/isWotuTVylyDg0iXuKDpBywH8Xn/IcK8J/15iIuByNj3cocvocbNEaWoIDg +IOdd1Lw+0/wPrOhphc5Dz6UTCV+MZKrigSK2x55/nlg7OVMxVHGrqXTVEXg/gjMB4S9F9vTi7S0Y wuCYsqMM5Zc/MZJcsuwAykp4d130w5rwVDL5bffHtof1caHz2VDD2CsfrP8St8X/D2ZVsrsUb5+z4 VZOW55QWZIxqFZOWZv7FRO54R6Bk6ErPiSF3wHWomZXnmrJtbZcDJubseOG7eVCMt20WwkU+cWblU +/MfkLsA==; Received: from mail-ot1-x32f.google.com ([2607:f8b0:4864:20::32f]) by bombadil.infradead.org with esmtps (Exim 4.94 #2 (Red Hat Linux)) id 1ljLLb-00FS84-QQ for linux-arm-kernel@lists.infradead.org; Wed, 19 May 2021 12:30:51 +0000 Received: by mail-ot1-x32f.google.com with SMTP id r26-20020a056830121ab02902a5ff1c9b81so11576850otp.11 for ; Wed, 19 May 2021 05:30:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:date:from:to:cc:subject:message-id:reply-to:references :mime-version:content-disposition:content-transfer-encoding :in-reply-to; bh=aKHr+1V+CDnfzSzbLj1hWsDUAY0cmFm/k2Vt/tEA6F8=; b=mS6dszP8bCc2Bg+C3HNJ90znzhnOLWLPWwIiOluenf/xCXlIEpAtt+46phu38p/Fwd 6eEb0hNH6g4T4MKxxgIqyzCgBs5WHfUPY9TSeC4WbfBgHoGSFDc/UDmAK9E9CA0wX7O6 z1J375Xmxq3LEb8QdLdZq8p5gFtUJS37C6E5P/+LYy2eqqNXQ0wlx8i0x1QmkWMizQ9x lqIxiiVb+5xD0JXUb9HkN4lQ81/NM71gwLE8cldY/aXtY4jpVAVhiLNUSgZvpuEV5QCc YUsCH/Dm9kwzqk48pzrWSDZzVvK5crEW+Np/tcOrpSIMQqgc/KxFD/NlKXezFylBmXYh poow== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:date:from:to:cc:subject:message-id :reply-to:references:mime-version:content-disposition :content-transfer-encoding:in-reply-to; bh=aKHr+1V+CDnfzSzbLj1hWsDUAY0cmFm/k2Vt/tEA6F8=; b=WT6ay2t/mMqnbaPFAlFW1pVJk8ZYvdaiyUxa2BGRUEmTvZrAaOhg7LPWOhFdBV5vnq 162nwkoXatKeAYFEqz0KAezfoUYy3liGNowVbxk87VLnIKt6cUFX/9fdiQ4QgWrifoqV T2BkipmjtATt8gUEXqys3m97KUUsMku30NVkdAHgwtUBMS4lt/6LxElj94pgFeDarhm2 LyRfcnRktPkPYzTwADxL39pdTRYjEcwK2sfJlp5E1wxVd6zoMya9LzCQ1qQ3mW7F59ea SLB+LO2PKo92LCg7dmDDdg4j00woqHEcTP1t8ehQDsEUAgVnmMEVk5b6QcTu6bJofHwA LKtQ== X-Gm-Message-State: AOAM531PHxmapMLaWg3PvRUi4u5V2p/Ax47Eugq704GPu25NmZY3PXvT NsKYhuuquKgf2Y2gigMUkQ== X-Google-Smtp-Source: ABdhPJxOhBgHwUIx0RCQQWzAVbOph3yRvDgdajDuJH9n960Otk/URTgPiiYCbnqV6/LOlbQctg972Q== X-Received: by 2002:a05:6830:18fb:: with SMTP id d27mr8529362otf.235.1621427445589; Wed, 19 May 2021 05:30:45 -0700 (PDT) Received: from serve.minyard.net ([47.184.156.158]) by smtp.gmail.com with ESMTPSA id r2sm4471424otq.28.2021.05.19.05.30.44 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 19 May 2021 05:30:44 -0700 (PDT) Received: from minyard.net (unknown [IPv6:2001:470:b8f6:1b:9144:ba66:ea13:f260]) by serve.minyard.net (Postfix) with ESMTPSA id 6AFE818000C; Wed, 19 May 2021 12:30:43 +0000 (UTC) Date: Wed, 19 May 2021 07:30:42 -0500 From: Corey Minyard To: Quan Nguyen Cc: Rob Herring , Joel Stanley , Andrew Jeffery , Brendan Higgins , Benjamin Herrenschmidt , Wolfram Sang , Philipp Zabel , 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, Open Source Submission , Phong Vo , "Thang Q . Nguyen" , openbmc@lists.ozlabs.org Subject: Re: [PATCH v3 2/7] ipmi: ssif_bmc: Add SSIF BMC driver Message-ID: <20210519123042.GF2921206@minyard.net> References: <20210519074934.20712-1-quan@os.amperecomputing.com> <20210519074934.20712-3-quan@os.amperecomputing.com> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <20210519074934.20712-3-quan@os.amperecomputing.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20210519_053047_947608_759FC0BF X-CRM114-Status: GOOD ( 41.76 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: minyard@acm.org Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: base64 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org T24gV2VkLCBNYXkgMTksIDIwMjEgYXQgMDI6NDk6MjlQTSArMDcwMCwgUXVhbiBOZ3V5ZW4gd3Jv dGU6Cj4gVGhlIFNNQnVzIHN5c3RlbSBpbnRlcmZhY2UgKFNTSUYpIElQTUkgQk1DIGRyaXZlciBj YW4gYmUgdXNlZCB0byBwZXJmb3JtCj4gaW4tYmFuZCBJUE1JIGNvbW11bmljYXRpb24gd2l0aCB0 aGVpciBob3N0IGluIG1hbmFnZW1lbnQgKEJNQykgc2lkZS4KPiAKPiBTaWduZWQtb2ZmLWJ5OiBR dWFuIE5ndXllbiA8cXVhbkBvcy5hbXBlcmVjb21wdXRpbmcuY29tPgo+IC0tLQo+IHYzOgo+ICAg KyBSZW1vdmVkIHJlZHVuZGFudCBsaWNlbnNlIGluZm8gW0pvZWxdCj4gICArIFN3aXRjaGVkIHRv IHVzZSB0cmFkaXRpb25hbCBpZi1lbHNlIFtKb2VsXQo+ICAgKyBSZW1vdmVkIHVudXNlZCBzc2lm X2JtY19pb2N0bCgpIFtKb2VsXQo+ICAgKyBNYWRlIGhhbmRsZV9yZXF1ZXN0KCkvY29tcGxldGVf cmVzcG9uc2UoKSB0byByZXR1cm4gdm9pZCBbSm9lbF0KPiAgICsgUmVmYWN0b3JlZCBzZW5kX3Nz aWZfYm1jX3Jlc3BvbnNlKCkvcmVjZWl2ZV9zc2lmX2JtY19yZXF1ZXN0KCkgW0NvcmV5XQo+ICAg KyBSZW1vdmVkIG11dGV4IFtDb3JleV0KPiAgICsgVXNlIHNwaW5fbG9jay91bmxvY2tfaXJxc2F2 ZS9yZXN0b3JlIGluIGNhbGxiYWNrIFtDb3JleV0KPiAgICsgUmVtb3ZlZCB0aGUgdW5uZWNlc3Nh cnkgbWVtc2V0IFtDb3JleV0KPiAgICsgU3dpdGNoIHRvIHVzZSBkZXZfZXJyKCkgW0NvcmV5XQo+ IAo+IHYyOgo+ICAgKyBGaXhlZCBjb21waWxpbmcgZXJyb3Igd2l0aCBDT01QSUxFX1RFU1QgZm9y IGFyYwo+IAo+ICBkcml2ZXJzL2NoYXIvaXBtaS9LY29uZmlnICAgIHwgIDExICsKPiAgZHJpdmVy cy9jaGFyL2lwbWkvTWFrZWZpbGUgICB8ICAgMSArCj4gIGRyaXZlcnMvY2hhci9pcG1pL3NzaWZf Ym1jLmMgfCA2MDUgKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysKPiAgZHJpdmVy cy9jaGFyL2lwbWkvc3NpZl9ibWMuaCB8ICA5MyArKysrKysKPiAgNCBmaWxlcyBjaGFuZ2VkLCA3 MTAgaW5zZXJ0aW9ucygrKQo+ICBjcmVhdGUgbW9kZSAxMDA2NDQgZHJpdmVycy9jaGFyL2lwbWkv c3NpZl9ibWMuYwo+ICBjcmVhdGUgbW9kZSAxMDA2NDQgZHJpdmVycy9jaGFyL2lwbWkvc3NpZl9i bWMuaAo+IAo+IGRpZmYgLS1naXQgYS9kcml2ZXJzL2NoYXIvaXBtaS9LY29uZmlnIGIvZHJpdmVy cy9jaGFyL2lwbWkvS2NvbmZpZwo+IGluZGV4IDA3ODQ3ZDlhNDU5YS4uYWQ1YzUxNjFiY2Q2IDEw MDY0NAo+IC0tLSBhL2RyaXZlcnMvY2hhci9pcG1pL0tjb25maWcKPiArKysgYi9kcml2ZXJzL2No YXIvaXBtaS9LY29uZmlnCj4gQEAgLTEzMyw2ICsxMzMsMTcgQEAgY29uZmlnIEFTUEVFRF9CVF9J UE1JX0JNQwo+ICAJICBmb3VuZCBvbiBBc3BlZWQgU09DcyAoQVNUMjQwMCBhbmQgQVNUMjUwMCku IFRoZSBkcml2ZXIKPiAgCSAgaW1wbGVtZW50cyB0aGUgQk1DIHNpZGUgb2YgdGhlIEJUIGludGVy ZmFjZS4KPiAgCj4gK2NvbmZpZyBTU0lGX0lQTUlfQk1DCj4gKwl0cmlzdGF0ZSAiU1NJRiBJUE1J IEJNQyBkcml2ZXIiCj4gKwlzZWxlY3QgSTJDCj4gKwlzZWxlY3QgSTJDX1NMQVZFCj4gKwloZWxw Cj4gKwkgIFRoaXMgZW5hYmxlcyB0aGUgSVBNSSBTTUJ1cyBzeXN0ZW0gaW50ZXJmYWNlIChTU0lG KSBhdCB0aGUKPiArCSAgbWFuYWdlbWVudCAoQk1DKSBzaWRlLgo+ICsKPiArCSAgVGhlIGRyaXZl ciBpbXBsZW1lbnRzIHRoZSBCTUMgc2lkZSBvZiB0aGUgU01CdXMgc3lzdGVtCj4gKwkgIGludGVy ZmFjZSAoU1NJRikuCj4gKwo+ICBjb25maWcgSVBNQl9ERVZJQ0VfSU5URVJGQUNFCj4gIAl0cmlz dGF0ZSAnSVBNQiBJbnRlcmZhY2UgaGFuZGxlcicKPiAgCWRlcGVuZHMgb24gSTJDCj4gZGlmZiAt LWdpdCBhL2RyaXZlcnMvY2hhci9pcG1pL01ha2VmaWxlIGIvZHJpdmVycy9jaGFyL2lwbWkvTWFr ZWZpbGUKPiBpbmRleCAwODIyYWRjMmVjNDEuLmQwNGEyMTRkNzRjNCAxMDA2NDQKPiAtLS0gYS9k cml2ZXJzL2NoYXIvaXBtaS9NYWtlZmlsZQo+ICsrKyBiL2RyaXZlcnMvY2hhci9pcG1pL01ha2Vm aWxlCj4gQEAgLTI3LDMgKzI3LDQgQEAgb2JqLSQoQ09ORklHX0FTUEVFRF9CVF9JUE1JX0JNQykg Kz0gYnQtYm1jLm8KPiAgb2JqLSQoQ09ORklHX0FTUEVFRF9LQ1NfSVBNSV9CTUMpICs9IGtjc19i bWNfYXNwZWVkLm8KPiAgb2JqLSQoQ09ORklHX05QQ003WFhfS0NTX0lQTUlfQk1DKSArPSBrY3Nf Ym1jX25wY203eHgubwo+ICBvYmotJChDT05GSUdfSVBNQl9ERVZJQ0VfSU5URVJGQUNFKSArPSBp cG1iX2Rldl9pbnQubwo+ICtvYmotJChDT05GSUdfU1NJRl9JUE1JX0JNQykgKz0gc3NpZl9ibWMu bwo+IGRpZmYgLS1naXQgYS9kcml2ZXJzL2NoYXIvaXBtaS9zc2lmX2JtYy5jIGIvZHJpdmVycy9j aGFyL2lwbWkvc3NpZl9ibWMuYwo+IG5ldyBmaWxlIG1vZGUgMTAwNjQ0Cj4gaW5kZXggMDAwMDAw MDAwMDAwLi5kMGVhNzA1OWIxZGIKPiAtLS0gL2Rldi9udWxsCj4gKysrIGIvZHJpdmVycy9jaGFy L2lwbWkvc3NpZl9ibWMuYwo+IEBAIC0wLDAgKzEsNjA1IEBACj4gKy8vIFNQRFgtTGljZW5zZS1J ZGVudGlmaWVyOiBHUEwtMi4wKwo+ICsvKgo+ICsgKiBUaGUgZHJpdmVyIGZvciBCTUMgc2lkZSBv ZiBTU0lGIGludGVyZmFjZQo+ICsgKgo+ICsgKiBDb3B5cmlnaHQgKGMpIDIwMjEsIEFtcGVyZSBD b21wdXRpbmcgTExDCj4gKyAqCj4gKyAqLwo+ICsKPiArI2luY2x1ZGUgPGxpbnV4L2kyYy5oPgo+ ICsjaW5jbHVkZSA8bGludXgvbWlzY2RldmljZS5oPgo+ICsjaW5jbHVkZSA8bGludXgvbW9kdWxl Lmg+Cj4gKyNpbmNsdWRlIDxsaW51eC9vZi5oPgo+ICsjaW5jbHVkZSA8bGludXgvcGxhdGZvcm1f ZGV2aWNlLmg+Cj4gKyNpbmNsdWRlIDxsaW51eC9wb2xsLmg+Cj4gKyNpbmNsdWRlIDxsaW51eC9z Y2hlZC5oPgo+ICsjaW5jbHVkZSA8bGludXgvbXV0ZXguaD4KPiArI2luY2x1ZGUgPGxpbnV4L3Nw aW5sb2NrLmg+Cj4gKwo+ICsjaW5jbHVkZSAic3NpZl9ibWMuaCIKPiArCj4gKy8qIEhhbmRsZSBT U0lGIG1lc3NhZ2UgdGhhdCB3aWxsIGJlIHNlbnQgdG8gdXNlciAqLwo+ICtzdGF0aWMgc3NpemVf dCBzc2lmX2JtY19yZWFkKHN0cnVjdCBmaWxlICpmaWxlLCBjaGFyIF9fdXNlciAqYnVmLCBzaXpl X3QgY291bnQsIGxvZmZfdCAqcHBvcykKPiArewo+ICsJc3RydWN0IHNzaWZfYm1jX2N0eCAqc3Np Zl9ibWMgPSB0b19zc2lmX2JtYyhmaWxlKTsKPiArCXN0cnVjdCBzc2lmX21zZyBtc2c7Cj4gKwl1 bnNpZ25lZCBsb25nIGZsYWdzOwo+ICsJc3NpemVfdCByZXQ7Cj4gKwo+ICsJc3Bpbl9sb2NrX2ly cXNhdmUoJnNzaWZfYm1jLT5sb2NrLCBmbGFncyk7Cj4gKwl3aGlsZSAoIXNzaWZfYm1jLT5yZXF1 ZXN0X2F2YWlsYWJsZSkgewo+ICsJCWlmIChmaWxlLT5mX2ZsYWdzICYgT19OT05CTE9DSykgewoK VGhlcmUgaXMgbm8gcmVhbCBuZWVkIHRvIGNoZWNrIHRoaXMgdW5kZXIgdGhlIGxvY2suICBJdCB3 b3VsZCBzaW1wbGlmeQp0aGUgZW5kIG9mIHRoaXMgZnVuY3Rpb24gaWYgeW91IGNoZWNrZWQgdGhp cyBvdXRzaWRlIHRoZSBsb2NrLgoKPiArCQkJcmV0ID0gLUVBR0FJTjsKPiArCQkJZ290byBvdXRf dW5sb2NrOwo+ICsJCX0KPiArCQlzcGluX3VubG9ja19pcnFyZXN0b3JlKCZzc2lmX2JtYy0+bG9j aywgZmxhZ3MpOwo+ICsJCXJldCA9IHdhaXRfZXZlbnRfaW50ZXJydXB0aWJsZShzc2lmX2JtYy0+ d2FpdF9xdWV1ZSwKPiArCQkJCQkgICAgICAgc3NpZl9ibWMtPnJlcXVlc3RfYXZhaWxhYmxlKTsK PiArCQlpZiAocmV0KQo+ICsJCQlyZXR1cm4gcmV0Owo+ICsJCXNwaW5fbG9ja19pcnFzYXZlKCZz c2lmX2JtYy0+bG9jaywgZmxhZ3MpOwo+ICsJfQo+ICsKPiArCWNvdW50ID0gbWluX3Qoc3NpemVf dCwgc3NpZl9tc2dfbGVuKCZzc2lmX2JtYy0+cmVxdWVzdCksCj4gKwkJICAgICAgbWluX3Qoc3Np emVfdCwgc2l6ZW9mKHN0cnVjdCBzc2lmX21zZyksIGNvdW50KSk7CgpKdXN0IGN1cmlvdXMsIHdo YXQgaGFwcGVucyBpZiB1c2VybGFuZCBzdXBwbGllcyBhIGJ1ZmZlciB0aGF0IGlzIHRvbwpzbWFs bD8gIElzIGRhdGEgbG9zdD8gIEluIHRoYXQgY2FzZSwgSSB3b3VsZCB0aGluayByZXR1cm5pbmcg YW4gZXJyb3IKaGVyZSB3b3VsZCBiZSB0aGUgYmV0dGVyIHRoaW5nLCBhcyBvcHBvc2VkIHRvIHNp bGVudGx5IHRydW5jYXRpbmcgdGhlCm1lc3NhZ2UuCgo+ICsJbWVtY3B5KCZtc2csICZzc2lmX2Jt Yy0+cmVxdWVzdCwgY291bnQpOwo+ICsJc3NpZl9ibWMtPnJlcXVlc3RfYXZhaWxhYmxlID0gZmFs c2U7Cj4gKwlzcGluX3VubG9ja19pcnFyZXN0b3JlKCZzc2lmX2JtYy0+bG9jaywgZmxhZ3MpOwo+ ICsKPiArCXJldCA9IGNvcHlfdG9fdXNlcihidWYsICZtc2csIGNvdW50KTsKPiArCWdvdG8gb3V0 Owo+ICsKPiArb3V0X3VubG9jazoKPiArCXNwaW5fdW5sb2NrX2lycXJlc3RvcmUoJnNzaWZfYm1j LT5sb2NrLCBmbGFncyk7Cj4gK291dDoKPiArCXJldHVybiAocmV0IDwgMCkgPyByZXQgOiBjb3Vu dDsKPiArfQo+ICsKPiArLyogSGFuZGxlIFNTSUYgbWVzc2FnZSB0aGF0IGlzIHdyaXR0ZW4gYnkg dXNlciAqLwo+ICtzdGF0aWMgc3NpemVfdCBzc2lmX2JtY193cml0ZShzdHJ1Y3QgZmlsZSAqZmls ZSwgY29uc3QgY2hhciBfX3VzZXIgKmJ1Ziwgc2l6ZV90IGNvdW50LAo+ICsJCQkgICAgICBsb2Zm X3QgKnBwb3MpCj4gK3sKPiArCXN0cnVjdCBzc2lmX2JtY19jdHggKnNzaWZfYm1jID0gdG9fc3Np Zl9ibWMoZmlsZSk7Cj4gKwlzdHJ1Y3Qgc3NpZl9tc2cgbXNnOwo+ICsJdW5zaWduZWQgbG9uZyBm bGFnczsKPiArCXNzaXplX3QgcmV0Owo+ICsKPiArCWlmIChjb3VudCA+IHNpemVvZihzdHJ1Y3Qg c3NpZl9tc2cpKQo+ICsJCXJldHVybiAtRUlOVkFMOwo+ICsKPiArCXJldCA9IGNvcHlfZnJvbV91 c2VyKCZtc2csIGJ1ZiwgY291bnQpOwo+ICsJaWYgKHJldCkKPiArCQlyZXR1cm4gcmV0Owo+ICsK PiArCWlmICghbXNnLmxlbiB8fCBjb3VudCA8IHNzaWZfbXNnX2xlbigmbXNnKSkKPiArCQlyZXR1 cm4gLUVJTlZBTDsKPiArCj4gKwlzcGluX2xvY2tfaXJxc2F2ZSgmc3NpZl9ibWMtPmxvY2ssIGZs YWdzKTsKPiArCXdoaWxlIChzc2lmX2JtYy0+cmVzcG9uc2VfaW5fcHJvZ3Jlc3MpIHsKPiArCQlp ZiAoZmlsZS0+Zl9mbGFncyAmIE9fTk9OQkxPQ0spIHsKClNhbWUgY29tbWVudCBhcyBPX05PTkJM T0NLIGJlZm9yZS4KCj4gKwkJCXJldCA9IC1FQUdBSU47Cj4gKwkJCWdvdG8gb3V0X3VubG9jazsK PiArCQl9Cj4gKwkJc3Bpbl91bmxvY2tfaXJxcmVzdG9yZSgmc3NpZl9ibWMtPmxvY2ssIGZsYWdz KTsKPiArCQlyZXQgPSB3YWl0X2V2ZW50X2ludGVycnVwdGlibGUoc3NpZl9ibWMtPndhaXRfcXVl dWUsCj4gKwkJCQkJICAgICAgICFzc2lmX2JtYy0+cmVzcG9uc2VfaW5fcHJvZ3Jlc3MpOwo+ICsJ CWlmIChyZXQpCj4gKwkJCWdvdG8gb3V0Owo+ICsJCXNwaW5fbG9ja19pcnFzYXZlKCZzc2lmX2Jt Yy0+bG9jaywgZmxhZ3MpOwo+ICsJfQo+ICsKPiArCW1lbWNweSgmc3NpZl9ibWMtPnJlc3BvbnNl LCAmbXNnLCBjb3VudCk7Cj4gKwlzc2lmX2JtYy0+aXNfc2luZ2xlcGFydF9yZWFkID0gKHNzaWZf bXNnX2xlbigmbXNnKSA8PSBNQVhfUEFZTE9BRF9QRVJfVFJBTlNBQ1RJT04gKyAxKTsKPiArCXNz aWZfYm1jLT5yZXNwb25zZV9pbl9wcm9ncmVzcyA9IHRydWU7Cj4gKwlpZiAoc3NpZl9ibWMtPnNl dF9zc2lmX2JtY19zdGF0dXMpCj4gKwkJc3NpZl9ibWMtPnNldF9zc2lmX2JtY19zdGF0dXMoc3Np Zl9ibWMsIFNTSUZfQk1DX1JFQURZKTsKPiArCj4gK291dF91bmxvY2s6Cj4gKwlzcGluX3VubG9j a19pcnFyZXN0b3JlKCZzc2lmX2JtYy0+bG9jaywgZmxhZ3MpOwo+ICsKPiArb3V0Ogo+ICsJcmV0 dXJuIChyZXQgPCAwKSA/IHJldCA6IGNvdW50Owo+ICt9Cj4gKwo+ICtzdGF0aWMgaW50IHNzaWZf Ym1jX29wZW4oc3RydWN0IGlub2RlICppbm9kZSwgc3RydWN0IGZpbGUgKmZpbGUpCj4gK3sKPiAr CXN0cnVjdCBzc2lmX2JtY19jdHggKnNzaWZfYm1jID0gdG9fc3NpZl9ibWMoZmlsZSk7Cj4gKwlp bnQgcmV0ID0gMDsKPiArCj4gKwlzcGluX2xvY2tfaXJxKCZzc2lmX2JtYy0+bG9jayk7Cj4gKwlp ZiAoIXNzaWZfYm1jLT5ydW5uaW5nKQo+ICsJCXNzaWZfYm1jLT5ydW5uaW5nID0gMTsKPiArCWVs c2UKPiArCQlyZXQgPSAtRUJVU1k7Cj4gKwlzcGluX3VubG9ja19pcnEoJnNzaWZfYm1jLT5sb2Nr KTsKPiArCj4gKwlyZXR1cm4gcmV0Owo+ICt9Cj4gKwo+ICtzdGF0aWMgdW5zaWduZWQgaW50IHNz aWZfYm1jX3BvbGwoc3RydWN0IGZpbGUgKmZpbGUsIHBvbGxfdGFibGUgKndhaXQpCj4gK3sKPiAr CXN0cnVjdCBzc2lmX2JtY19jdHggKnNzaWZfYm1jID0gdG9fc3NpZl9ibWMoZmlsZSk7Cj4gKwl1 bnNpZ25lZCBpbnQgbWFzayA9IDA7Cj4gKwo+ICsJcG9sbF93YWl0KGZpbGUsICZzc2lmX2JtYy0+ d2FpdF9xdWV1ZSwgd2FpdCk7Cj4gKwo+ICsJc3Bpbl9sb2NrX2lycSgmc3NpZl9ibWMtPmxvY2sp Owo+ICsJLyoKPiArCSAqIFRoZSByZXF1ZXN0IG1lc3NhZ2UgaXMgbm93IGF2YWlsYWJsZSBzbyB1 c2Vyc3BhY2UgYXBwbGljYXRpb24gY2FuCj4gKwkgKiBnZXQgdGhlIHJlcXVlc3QKPiArCSAqLwo+ ICsJaWYgKHNzaWZfYm1jLT5yZXF1ZXN0X2F2YWlsYWJsZSkKPiArCQltYXNrIHw9IFBPTExJTjsK PiArCj4gKwlzcGluX3VubG9ja19pcnEoJnNzaWZfYm1jLT5sb2NrKTsKPiArCj4gKwlyZXR1cm4g bWFzazsKPiArfQo+ICsKPiArc3RhdGljIGludCBzc2lmX2JtY19yZWxlYXNlKHN0cnVjdCBpbm9k ZSAqaW5vZGUsIHN0cnVjdCBmaWxlICpmaWxlKQo+ICt7Cj4gKwlzdHJ1Y3Qgc3NpZl9ibWNfY3R4 ICpzc2lmX2JtYyA9IHRvX3NzaWZfYm1jKGZpbGUpOwo+ICsKPiArCXNwaW5fbG9ja19pcnEoJnNz aWZfYm1jLT5sb2NrKTsKPiArCXNzaWZfYm1jLT5ydW5uaW5nID0gMDsKPiArCXNwaW5fdW5sb2Nr X2lycSgmc3NpZl9ibWMtPmxvY2spOwo+ICsKPiArCXJldHVybiAwOwo+ICt9Cj4gKwo+ICsvKgo+ ICsgKiBTeXN0ZW0gY2FsbHMgdG8gZGV2aWNlIGludGVyZmFjZSBmb3IgdXNlciBhcHBzCj4gKyAq Lwo+ICtzdGF0aWMgY29uc3Qgc3RydWN0IGZpbGVfb3BlcmF0aW9ucyBzc2lmX2JtY19mb3BzID0g ewo+ICsJLm93bmVyCQk9IFRISVNfTU9EVUxFLAo+ICsJLm9wZW4JCT0gc3NpZl9ibWNfb3BlbiwK PiArCS5yZWFkCQk9IHNzaWZfYm1jX3JlYWQsCj4gKwkud3JpdGUJCT0gc3NpZl9ibWNfd3JpdGUs Cj4gKwkucmVsZWFzZQk9IHNzaWZfYm1jX3JlbGVhc2UsCj4gKwkucG9sbAkJPSBzc2lmX2JtY19w b2xsLAo+ICt9Owo+ICsKPiArLyogQ2FsbGVkIHdpdGggc3NpZl9ibWMtPmxvY2sgaGVsZC4gKi8K PiArc3RhdGljIHZvaWQgaGFuZGxlX3JlcXVlc3Qoc3RydWN0IHNzaWZfYm1jX2N0eCAqc3NpZl9i bWMpCj4gK3sKPiArCWlmIChzc2lmX2JtYy0+c2V0X3NzaWZfYm1jX3N0YXR1cykKPiArCQlzc2lm X2JtYy0+c2V0X3NzaWZfYm1jX3N0YXR1cyhzc2lmX2JtYywgU1NJRl9CTUNfQlVTWSk7Cj4gKwo+ ICsJLyogUmVxdWVzdCBtZXNzYWdlIGlzIGF2YWlsYWJsZSB0byBwcm9jZXNzICovCj4gKwlzc2lm X2JtYy0+cmVxdWVzdF9hdmFpbGFibGUgPSB0cnVlOwo+ICsJLyoKPiArCSAqIFRoaXMgaXMgdGhl IG5ldyBSRUFEIHJlcXVlc3QuCj4gKwkgKi8KPiArCXdha2VfdXBfYWxsKCZzc2lmX2JtYy0+d2Fp dF9xdWV1ZSk7Cj4gK30KPiArCj4gKy8qIENhbGxlZCB3aXRoIHNzaWZfYm1jLT5sb2NrIGhlbGQu ICovCj4gK3N0YXRpYyB2b2lkIGNvbXBsZXRlX3Jlc3BvbnNlKHN0cnVjdCBzc2lmX2JtY19jdHgg KnNzaWZfYm1jKQo+ICt7Cj4gKwkvKiBJbnZhbGlkYXRlIHJlc3BvbnNlIGluIGJ1ZmZlciB0byBk ZW5vdGUgaXQgaGF2aW5nIGJlZW4gc2VudC4gKi8KPiArCXNzaWZfYm1jLT5yZXNwb25zZS5sZW4g PSAwOwo+ICsJc3NpZl9ibWMtPnJlc3BvbnNlX2luX3Byb2dyZXNzID0gZmFsc2U7Cj4gKwlzc2lm X2JtYy0+bmJ5dGVzX3Byb2Nlc3NlZCA9IDA7Cj4gKwlzc2lmX2JtYy0+cmVtYWluX2xlbiA9IDA7 Cj4gKwl3YWtlX3VwX2FsbCgmc3NpZl9ibWMtPndhaXRfcXVldWUpOwo+ICt9Cj4gKwo+ICtzdGF0 aWMgdm9pZCBzZXRfbXVsdGlwYXJ0X3Jlc3BvbnNlX2J1ZmZlcihzdHJ1Y3Qgc3NpZl9ibWNfY3R4 ICpzc2lmX2JtYywgdTggKnZhbCkKPiArewo+ICsJdTggcmVzcG9uc2VfbGVuID0gMDsKPiArCWlu dCBpZHggPSAwOwo+ICsJdTggZGF0YV9sZW47Cj4gKwo+ICsJZGF0YV9sZW4gPSBzc2lmX2JtYy0+ cmVzcG9uc2UubGVuOwo+ICsJc3dpdGNoIChzc2lmX2JtYy0+c21idXNfY21kKSB7Cj4gKwljYXNl IFNTSUZfSVBNSV9NVUxUSVBBUlRfUkVBRF9TVEFSVDoKPiArCQkvKgo+ICsJCSAqIFJlYWQgU3Rh cnQgbGVuZ3RoIGlzIDMyIGJ5dGVzLgo+ICsJCSAqIFJlYWQgU3RhcnQgdHJhbnNmZXIgZmlyc3Qg MzAgYnl0ZXMgb2YgSVBNSSByZXNwb25zZQo+ICsJCSAqIGFuZCAyIHNwZWNpYWwgY29kZSAweDAw LCAweDAxLgo+ICsJCSAqLwo+ICsJCSp2YWwgPSBNQVhfUEFZTE9BRF9QRVJfVFJBTlNBQ1RJT047 Cj4gKwkJc3NpZl9ibWMtPnJlbWFpbl9sZW4gPSBkYXRhX2xlbiAtIE1BWF9JUE1JX0RBVEFfUEVS X1NUQVJUX1RSQU5TQUNUSU9OOwo+ICsJCXNzaWZfYm1jLT5ibG9ja19udW0gPSAwOwo+ICsKPiAr CQlzc2lmX2JtYy0+cmVzcG9uc2VfYnVmW2lkeCsrXSA9IDB4MDA7IC8qIFN0YXJ0IEZsYWcgKi8K PiArCQlzc2lmX2JtYy0+cmVzcG9uc2VfYnVmW2lkeCsrXSA9IDB4MDE7IC8qIFN0YXJ0IEZsYWcg Ki8KPiArCQlzc2lmX2JtYy0+cmVzcG9uc2VfYnVmW2lkeCsrXSA9IHNzaWZfYm1jLT5yZXNwb25z ZS5uZXRmbl9sdW47Cj4gKwkJc3NpZl9ibWMtPnJlc3BvbnNlX2J1ZltpZHgrK10gPSBzc2lmX2Jt Yy0+cmVzcG9uc2UuY21kOwo+ICsJCXNzaWZfYm1jLT5yZXNwb25zZV9idWZbaWR4KytdID0gc3Np Zl9ibWMtPnJlc3BvbnNlLnBheWxvYWRbMF07Cj4gKwo+ICsJCXJlc3BvbnNlX2xlbiA9IE1BWF9Q QVlMT0FEX1BFUl9UUkFOU0FDVElPTiAtIGlkeDsKPiArCj4gKwkJbWVtY3B5KCZzc2lmX2JtYy0+ cmVzcG9uc2VfYnVmW2lkeF0sICZzc2lmX2JtYy0+cmVzcG9uc2UucGF5bG9hZFsxXSwKPiArCQkg ICAgICAgcmVzcG9uc2VfbGVuKTsKPiArCQlicmVhazsKPiArCj4gKwljYXNlIFNTSUZfSVBNSV9N VUxUSVBBUlRfUkVBRF9NSURETEU6Cj4gKwkJLyoKPiArCQkgKiBJUE1JIFJFQUQgTWlkZGxlIG9y IFJFQUQgRW5kIG1lc3NhZ2VzIGNhbiBjYXJyeSB1cCB0byAzMSBieXRlcwo+ICsJCSAqIElQTUkg ZGF0YSBwbHVzIGJsb2NrIG51bWJlciBieXRlLgo+ICsJCSAqLwo+ICsJCWlmIChzc2lmX2JtYy0+ cmVtYWluX2xlbiA8IE1BWF9JUE1JX0RBVEFfUEVSX01JRERMRV9UUkFOU0FDVElPTikgewo+ICsJ CQkvKgo+ICsJCQkgKiBUaGlzIGlzIFJFQUQgRW5kIG1lc3NhZ2UKPiArCQkJICogIFJldHVybiBs ZW5ndGggaXMgdGhlIHJlbWFpbmluZyByZXNwb25zZSBkYXRhIGxlbmd0aAo+ICsJCQkgKiAgcGx1 cyBibG9jayBudW1iZXIKPiArCQkJICogIEJsb2NrIG51bWJlciAweEZGIGlzIHRvIGluZGljYXRl IHRoaXMgaXMgbGFzdCBtZXNzYWdlCj4gKwkJCSAqCj4gKwkJCSAqLwo+ICsJCQkqdmFsID0gc3Np Zl9ibWMtPnJlbWFpbl9sZW4gKyAxOwo+ICsJCQlzc2lmX2JtYy0+YmxvY2tfbnVtID0gMHhGRjsK PiArCQkJc3NpZl9ibWMtPnJlc3BvbnNlX2J1ZltpZHgrK10gPSBzc2lmX2JtYy0+YmxvY2tfbnVt Owo+ICsJCQlyZXNwb25zZV9sZW4gPSBzc2lmX2JtYy0+cmVtYWluX2xlbjsKPiArCQkJLyogQ2xl YW4gdGhlIGJ1ZmZlciAqLwo+ICsJCQltZW1zZXQoJnNzaWZfYm1jLT5yZXNwb25zZV9idWZbaWR4 XSwgMCwgTUFYX1BBWUxPQURfUEVSX1RSQU5TQUNUSU9OIC0gaWR4KTsKPiArCQl9IGVsc2Ugewo+ ICsJCQkvKgo+ICsJCQkgKiBUaGlzIGlzIFJFQUQgTWlkZGxlIG1lc3NhZ2UKPiArCQkJICogIFJl c3BvbnNlIGxlbmd0aCBpcyB0aGUgbWF4aW11bSBTTUJVUyB0cmFuc2ZlciBsZW5ndGgKPiArCQkJ ICogIEJsb2NrIG51bWJlciBieXRlIGlzIGluY3JlbWVudGVkCj4gKwkJCSAqIFJldHVybiBsZW5n dGggaXMgbWF4aW11bSBTTUJVUyB0cmFuc2ZlciBsZW5ndGgKPiArCQkJICovCj4gKwkJCSp2YWwg PSBNQVhfUEFZTE9BRF9QRVJfVFJBTlNBQ1RJT047Cj4gKwkJCXNzaWZfYm1jLT5yZW1haW5fbGVu IC09IE1BWF9JUE1JX0RBVEFfUEVSX01JRERMRV9UUkFOU0FDVElPTjsKPiArCQkJcmVzcG9uc2Vf bGVuID0gTUFYX0lQTUlfREFUQV9QRVJfTUlERExFX1RSQU5TQUNUSU9OOwo+ICsJCQlzc2lmX2Jt Yy0+cmVzcG9uc2VfYnVmW2lkeCsrXSA9IHNzaWZfYm1jLT5ibG9ja19udW07Cj4gKwkJCXNzaWZf Ym1jLT5ibG9ja19udW0rKzsKPiArCQl9Cj4gKwo+ICsJCW1lbWNweSgmc3NpZl9ibWMtPnJlc3Bv bnNlX2J1ZltpZHhdLAo+ICsJCSAgICAgICBzc2lmX2JtYy0+cmVzcG9uc2UucGF5bG9hZCArIDEg KyBzc2lmX2JtYy0+bmJ5dGVzX3Byb2Nlc3NlZCwKPiArCQkgICAgICAgcmVzcG9uc2VfbGVuKTsK PiArCQlicmVhazsKPiArCj4gKwlkZWZhdWx0Ogo+ICsJCS8qIERvIG5vdCBleHBlY3QgdG8gZ28g dG8gdGhpcyBjYXNlICovCj4gKwkJZGV2X2Vycigmc3NpZl9ibWMtPmNsaWVudC0+ZGV2LAo+ICsJ CQkiRXJyb3I6IFVuZXhwZWN0ZWQgU01CdXMgY29tbWFuZCByZWNlaXZlZCAweCV4XG4iLCBzc2lm X2JtYy0+c21idXNfY21kKTsKPiArCQlicmVhazsKPiArCX0KPiArCj4gKwlzc2lmX2JtYy0+bmJ5 dGVzX3Byb2Nlc3NlZCArPSByZXNwb25zZV9sZW47Cj4gK30KPiArCj4gKy8qIFByb2Nlc3MgdGhl IElQTUkgcmVzcG9uc2UgdGhhdCB3aWxsIGJlIHJlYWQgYnkgbWFzdGVyICovCj4gK3N0YXRpYyB2 b2lkIGhhbmRsZV9yZWFkX3Byb2Nlc3NlZChzdHJ1Y3Qgc3NpZl9ibWNfY3R4ICpzc2lmX2JtYywg dTggKnZhbCkKPiArewo+ICsJdTggKmJ1ZjsKPiArCXU4IHBlY19sZW4sIGFkZHIsIGxlbjsKPiAr CXU4IHBlYyA9IDA7Cj4gKwo+ICsJcGVjX2xlbiA9IHNzaWZfYm1jLT5wZWNfc3VwcG9ydCA/IDEg OiAwOwo+ICsJLyogUEVDIC0gU3RhcnQgUmVhZCBBZGRyZXNzICovCj4gKwlhZGRyID0gR0VUXzhC SVRfQUREUihzc2lmX2JtYy0+Y2xpZW50LT5hZGRyKTsKPiArCXBlYyA9IGkyY19zbWJ1c19wZWMo cGVjLCAmYWRkciwgMSk7Cj4gKwkvKiBQRUMgLSBTU0lGIENvbW1hbmQgKi8KPiArCXBlYyA9IGky Y19zbWJ1c19wZWMocGVjLCAmc3NpZl9ibWMtPnNtYnVzX2NtZCwgMSk7Cj4gKwkvKiBQRUMgLSBS ZXN0YXJ0IFdyaXRlIEFkZHJlc3MgKi8KPiArCWFkZHIgPSBhZGRyIHwgMHgwMTsKPiArCXBlYyA9 IGkyY19zbWJ1c19wZWMocGVjLCAmYWRkciwgMSk7Cj4gKwo+ICsJaWYgKHNzaWZfYm1jLT5pc19z aW5nbGVwYXJ0X3JlYWQpIHsKPiArCQkvKiBTaW5nbGUtcGFydCBSZWFkIHByb2Nlc3NpbmcgKi8K PiArCQlidWYgPSAodTggKikmc3NpZl9ibWMtPnJlc3BvbnNlOwo+ICsKPiArCQlpZiAoc3NpZl9i bWMtPnJlc3BvbnNlLmxlbiAmJiBzc2lmX2JtYy0+bXNnX2lkeCA8IHNzaWZfYm1jLT5yZXNwb25z ZS5sZW4pIHsKPiArCQkJc3NpZl9ibWMtPm1zZ19pZHgrKzsKPiArCQkJKnZhbCA9IGJ1Zltzc2lm X2JtYy0+bXNnX2lkeF07Cj4gKwkJfSBlbHNlIGlmIChzc2lmX2JtYy0+cmVzcG9uc2UubGVuICYm IHNzaWZfYm1jLT5tc2dfaWR4ID09IHNzaWZfYm1jLT5yZXNwb25zZS5sZW4pIHsKPiArCQkJc3Np Zl9ibWMtPm1zZ19pZHgrKzsKPiArCQkJKnZhbCA9IGkyY19zbWJ1c19wZWMocGVjLCBidWYsIHNz aWZfbXNnX2xlbigmc3NpZl9ibWMtPnJlc3BvbnNlKSk7Cj4gKwkJfSBlbHNlIHsKPiArCQkJKnZh bCA9IDA7Cj4gKwkJfQo+ICsJCS8qIEludmFsaWRhdGUgcmVzcG9uc2UgYnVmZmVyIHRvIGRlbm90 ZSBpdCBpcyBzZW50ICovCj4gKwkJaWYgKHNzaWZfYm1jLT5tc2dfaWR4ICsgMSA+PSAoc3NpZl9t c2dfbGVuKCZzc2lmX2JtYy0+cmVzcG9uc2UpICsgcGVjX2xlbikpCj4gKwkJCWNvbXBsZXRlX3Jl c3BvbnNlKHNzaWZfYm1jKTsKPiArCX0gZWxzZSB7Cj4gKwkJLyogTXVsdGktcGFydCBSZWFkIHBy b2Nlc3NpbmcgKi8KPiArCQlzd2l0Y2ggKHNzaWZfYm1jLT5zbWJ1c19jbWQpIHsKPiArCQljYXNl IFNTSUZfSVBNSV9NVUxUSVBBUlRfUkVBRF9TVEFSVDoKPiArCQljYXNlIFNTSUZfSVBNSV9NVUxU SVBBUlRfUkVBRF9NSURETEU6Cj4gKwkJCWJ1ZiA9ICh1OCAqKSZzc2lmX2JtYy0+cmVzcG9uc2Vf YnVmOwo+ICsJCQkqdmFsID0gYnVmW3NzaWZfYm1jLT5tc2dfaWR4XTsKPiArCQkJc3NpZl9ibWMt Pm1zZ19pZHgrKzsKPiArCQkJYnJlYWs7Cj4gKwkJZGVmYXVsdDoKPiArCQkJLyogRG8gbm90IGV4 cGVjdCB0byBnbyB0byB0aGlzIGNhc2UgKi8KPiArCQkJZGV2X2Vycigmc3NpZl9ibWMtPmNsaWVu dC0+ZGV2LAo+ICsJCQkJIkVycm9yOiBVbmV4cGVjdGVkIFNNQnVzIGNvbW1hbmQgcmVjZWl2ZWQg MHgleFxuIiwKPiArCQkJCXNzaWZfYm1jLT5zbWJ1c19jbWQpOwo+ICsJCQlicmVhazsKPiArCQl9 Cj4gKwkJbGVuID0gKHNzaWZfYm1jLT5ibG9ja19udW0gPT0gMHhGRikgPwo+ICsJCSAgICAgICBz c2lmX2JtYy0+cmVtYWluX2xlbiArIDEgOiBNQVhfUEFZTE9BRF9QRVJfVFJBTlNBQ1RJT047Cj4g KwkJaWYgKHNzaWZfYm1jLT5tc2dfaWR4ID09IChsZW4gKyAxKSkgewo+ICsJCQlwZWMgPSBpMmNf c21idXNfcGVjKHBlYywgJmxlbiwgMSk7Cj4gKwkJCSp2YWwgPSBpMmNfc21idXNfcGVjKHBlYywg c3NpZl9ibWMtPnJlc3BvbnNlX2J1ZiwgbGVuKTsKPiArCQl9Cj4gKwkJLyogSW52YWxpZGF0ZSBy ZXNwb25zZSBidWZmZXIgdG8gZGVub3RlIGxhc3QgcmVzcG9uc2UgaXMgc2VudCAqLwo+ICsJCWlm IChzc2lmX2JtYy0+YmxvY2tfbnVtID09IDB4RkYgJiYKPiArCQkgICAgc3NpZl9ibWMtPm1zZ19p ZHggPiAoc3NpZl9ibWMtPnJlbWFpbl9sZW4gKyBwZWNfbGVuKSkgewo+ICsJCQljb21wbGV0ZV9y ZXNwb25zZShzc2lmX2JtYyk7Cj4gKwkJfQo+ICsJfQo+ICt9Cj4gKwo+ICtzdGF0aWMgdm9pZCBo YW5kbGVfd3JpdGVfcmVjZWl2ZWQoc3RydWN0IHNzaWZfYm1jX2N0eCAqc3NpZl9ibWMsIHU4ICp2 YWwpCj4gK3sKPiArCXU4ICpidWY7Cj4gKwl1OCBzbWJ1c19jbWQ7Cj4gKwo+ICsJYnVmID0gKHU4 ICopJnNzaWZfYm1jLT5yZXF1ZXN0Owo+ICsJaWYgKHNzaWZfYm1jLT5tc2dfaWR4ID49IHNpemVv ZihzdHJ1Y3Qgc3NpZl9tc2cpKQoKU2hvdWxkbid0IHlvdSBhYm9ydCB0aGUgbWVzc2FnZSBpZiB5 b3UgZ2V0IHRvbyBtdWNoIGRhdGE/ICBPdGhlcndpc2UgeW91CmdldCBzaWxlbnQgdHJ1bmNhdGlv bi4KCj4gKwkJcmV0dXJuOwo+ICsKPiArCXNtYnVzX2NtZCA9IHNzaWZfYm1jLT5zbWJ1c19jbWQ7 Cj4gKwlzd2l0Y2ggKHNtYnVzX2NtZCkgewo+ICsJY2FzZSBTU0lGX0lQTUlfU0lOR0xFUEFSVF9X UklURToKPiArCQkvKiBTaW5nbGUtcGFydCB3cml0ZSAqLwo+ICsJCWJ1Zltzc2lmX2JtYy0+bXNn X2lkeCAtIDFdID0gKnZhbDsKPiArCQlzc2lmX2JtYy0+bXNnX2lkeCsrOwo+ICsKPiArCQlicmVh azsKCkdlbmVyYWxseSB5b3UgcHV0IHRoZSBzcGFjZSBhZnRlciB0aGUgYnJlYWssIG5vdCBiZWZv cmUuICBZb3UgZGlkIHRoaXMKcmlnaHQgYmVmb3JlLCBidXQgZGlkbid0IGZyb20gaGVyZSBkb3du IGluIHRoZSBmaWxlLgoKPiArCWNhc2UgU1NJRl9JUE1JX01VTFRJUEFSVF9XUklURV9TVEFSVDoK PiArCQkvKiBSZXNldCBsZW5ndGggdG8gemVybyAqLwo+ICsJCWlmIChzc2lmX2JtYy0+bXNnX2lk eCA9PSAxKQo+ICsJCQlzc2lmX2JtYy0+cmVxdWVzdC5sZW4gPSAwOwoKV2hhdCBoYXBwZW5zIGlm IHlvdSBnZXQgdGhpcyBhbmQgeW91IGFyZSBpbiB0aGUgbWlkZGxlIG9mIGEgbWVzc2FnZT8KCj4g Kwo+ICsJCWZhbGx0aHJvdWdoOwo+ICsJY2FzZSBTU0lGX0lQTUlfTVVMVElQQVJUX1dSSVRFX01J RERMRToKPiArCWNhc2UgU1NJRl9JUE1JX01VTFRJUEFSVF9XUklURV9FTkQ6CgpXaGF0IGhhcHBl bnMgaWYgeW91IGdldCB0aGVzZSBhbmQgeW91IGFyZSBub3QgaW4gYSBtZXNzYWdlPwoKPiArCQkv KiBNdWx0aS1wYXJ0IHdyaXRlLCAybmQgYnl0ZSByZWNlaXZlZCBpcyBsZW5ndGggKi8KPiArCQlp ZiAoc3NpZl9ibWMtPm1zZ19pZHggPT0gMSkgewo+ICsJCQlzc2lmX2JtYy0+cmVxdWVzdC5sZW4g Kz0gKnZhbDsKPiArCQkJc3NpZl9ibWMtPnJlY3ZfbGVuID0gKnZhbDsKPiArCQl9IGVsc2Ugewo+ ICsJCQlidWZbc3NpZl9ibWMtPm1zZ19pZHggLSAxICsKPiArCQkJICAgIHNzaWZfYm1jLT5yZXF1 ZXN0LmxlbiAtIHNzaWZfYm1jLT5yZWN2X2xlbl0JPSAqdmFsOwo+ICsJCX0KPiArCj4gKwkJc3Np Zl9ibWMtPm1zZ19pZHgrKzsKPiArCj4gKwkJYnJlYWs7Cj4gKwlkZWZhdWx0Ogo+ICsJCS8qIERv IG5vdCBleHBlY3QgdG8gZ28gdG8gdGhpcyBjYXNlICovCj4gKwkJZGV2X2Vycigmc3NpZl9ibWMt PmNsaWVudC0+ZGV2LAo+ICsJCQkiRXJyb3I6IFVuZXhwZWN0ZWQgU01CdXMgY29tbWFuZCByZWNl aXZlZCAweCV4XG4iLCBzc2lmX2JtYy0+c21idXNfY21kKTsKPiArCQlicmVhazsKPiArCX0KPiAr fQo+ICsKPiArc3RhdGljIGJvb2wgdmFsaWRhdGVfcGVjKHN0cnVjdCBzc2lmX2JtY19jdHggKnNz aWZfYm1jKQo+ICt7Cj4gKwl1OCBycGVjID0gMCwgY3BlYyA9IDA7Cj4gKwlib29sIHJldCA9IHRy dWU7Cj4gKwl1OCBhZGRyLCBpbmRleDsKPiArCXU4ICpidWY7Cj4gKwo+ICsJYnVmID0gKHU4ICop JnNzaWZfYm1jLT5yZXF1ZXN0Owo+ICsJc3dpdGNoIChzc2lmX2JtYy0+c21idXNfY21kKSB7Cj4g KwljYXNlIFNTSUZfSVBNSV9TSU5HTEVQQVJUX1dSSVRFOgo+ICsJCWlmICgoc3NpZl9ibWMtPm1z Z19pZHggLSAxKSA9PSBzc2lmX21zZ19sZW4oJnNzaWZfYm1jLT5yZXF1ZXN0KSkgewo+ICsJCQkv KiBQRUMgaXMgbm90IGluY2x1ZGVkICovCj4gKwkJCXNzaWZfYm1jLT5wZWNfc3VwcG9ydCA9IGZh bHNlOwo+ICsJCQlyZXR1cm4gdHJ1ZTsKPiArCQl9Cj4gKwo+ICsJCWlmICgoc3NpZl9ibWMtPm1z Z19pZHggLSAxKSAhPSAoc3NpZl9tc2dfbGVuKCZzc2lmX2JtYy0+cmVxdWVzdCkgKyAxKSkKPiAr CQkJZ290byBlcnJvcjsKPiArCj4gKwkJLyogUEVDIGlzIGluY2x1ZGVkICovCj4gKwkJc3NpZl9i bWMtPnBlY19zdXBwb3J0ID0gdHJ1ZTsKPiArCQlycGVjID0gYnVmW3NzaWZfYm1jLT5tc2dfaWR4 IC0gMl07Cj4gKwkJYWRkciA9IEdFVF84QklUX0FERFIoc3NpZl9ibWMtPmNsaWVudC0+YWRkcik7 Cj4gKwkJY3BlYyA9IGkyY19zbWJ1c19wZWMoY3BlYywgJmFkZHIsIDEpOwo+ICsJCWNwZWMgPSBp MmNfc21idXNfcGVjKGNwZWMsICZzc2lmX2JtYy0+c21idXNfY21kLCAxKTsKPiArCQljcGVjID0g aTJjX3NtYnVzX3BlYyhjcGVjLCBidWYsIHNzaWZfbXNnX2xlbigmc3NpZl9ibWMtPnJlcXVlc3Qp KTsKPiArCQlpZiAocnBlYyAhPSBjcGVjKSB7Cj4gKwkJCWRldl9lcnIoJnNzaWZfYm1jLT5jbGll bnQtPmRldiwgIkJhZCBQRUMgMHglMDJ4IHZzLiAweCUwMnhcbiIsIHJwZWMsIGNwZWMpOwo+ICsJ CQlyZXQgPSBmYWxzZTsKPiArCQl9Cj4gKwo+ICsJCWJyZWFrOwo+ICsJY2FzZSBTU0lGX0lQTUlf TVVMVElQQVJUX1dSSVRFX1NUQVJUOgo+ICsJY2FzZSBTU0lGX0lQTUlfTVVMVElQQVJUX1dSSVRF X01JRERMRToKPiArCWNhc2UgU1NJRl9JUE1JX01VTFRJUEFSVF9XUklURV9FTkQ6Cj4gKwkJaW5k ZXggPSBzc2lmX2JtYy0+cmVxdWVzdC5sZW4gLSBzc2lmX2JtYy0+cmVjdl9sZW47Cj4gKwkJaWYg KChzc2lmX2JtYy0+bXNnX2lkeCAtIDEgKyBpbmRleCkgPT0gc3NpZl9tc2dfbGVuKCZzc2lmX2Jt Yy0+cmVxdWVzdCkpIHsKPiArCQkJLyogUEVDIGlzIG5vdCBpbmNsdWRlZCAqLwo+ICsJCQlzc2lm X2JtYy0+cGVjX3N1cHBvcnQgPSBmYWxzZTsKPiArCQkJcmV0dXJuIHRydWU7Cj4gKwkJfQo+ICsK PiArCQlpZiAoKHNzaWZfYm1jLT5tc2dfaWR4IC0gMSArIGluZGV4KSAhPSAoc3NpZl9tc2dfbGVu KCZzc2lmX2JtYy0+cmVxdWVzdCkgKyAxKSkKPiArCQkJZ290byBlcnJvcjsKPiArCj4gKwkJLyog UEVDIGlzIGluY2x1ZGVkICovCj4gKwkJc3NpZl9ibWMtPnBlY19zdXBwb3J0ID0gdHJ1ZTsKPiAr CQlycGVjID0gYnVmW3NzaWZfYm1jLT5tc2dfaWR4IC0gMiArIGluZGV4XTsKPiArCQlhZGRyID0g R0VUXzhCSVRfQUREUihzc2lmX2JtYy0+Y2xpZW50LT5hZGRyKTsKPiArCQljcGVjID0gaTJjX3Nt YnVzX3BlYyhjcGVjLCAmYWRkciwgMSk7Cj4gKwkJY3BlYyA9IGkyY19zbWJ1c19wZWMoY3BlYywg JnNzaWZfYm1jLT5zbWJ1c19jbWQsIDEpOwo+ICsJCWNwZWMgPSBpMmNfc21idXNfcGVjKGNwZWMs ICZzc2lmX2JtYy0+cmVjdl9sZW4sIDEpOwo+ICsJCS8qIEFzIFNNQnVzIHNwZWNpZmljYXRpb24g ZG9lcyBub3QgYWxsb3cgdGhlIGxlbmd0aAo+ICsJCSAqIChieXRlIGNvdW50KSBpbiB0aGUgV3Jp dGUtQmxvY2sgcHJvdG9jb2wgdG8gYmUgemVyby4KPiArCQkgKiBUaGVyZWZvcmUsIGl0IGlzIGls bGVnYWwgdG8gaGF2ZSB0aGUgbGFzdCBNaWRkbGUKPiArCQkgKiB0cmFuc2FjdGlvbiBpbiB0aGUg c2VxdWVuY2UgY2FycnkgMzItYnl0ZXMgYW5kIGhhdmUKPiArCQkgKiBhIGxlbmd0aCBvZiDigJgw 4oCZIGluIHRoZSBFbmQgdHJhbnNhY3Rpb24uCj4gKwkJICogQnV0IHNvbWUgdXNlcnMgbWF5IHRy eSB0byB1c2UgdGhpcyB3YXkgYW5kIHdlIHNob3VsZAo+ICsJCSAqIHByZXZlbnQgc3NpZl9ibWMg ZHJpdmVyIGJyb2tlbiBpbiB0aGlzIGNhc2UuCj4gKwkJICovCj4gKwkJaWYgKHNzaWZfYm1jLT5y ZWN2X2xlbiAhPSAwKQo+ICsJCQljcGVjID0gaTJjX3NtYnVzX3BlYyhjcGVjLCBidWYgKyAxICsg aW5kZXgsIHNzaWZfYm1jLT5yZWN2X2xlbik7Cj4gKwo+ICsJCWlmIChycGVjICE9IGNwZWMpIHsK PiArCQkJZGV2X2Vycigmc3NpZl9ibWMtPmNsaWVudC0+ZGV2LCAiQmFkIFBFQyAweCUwMnggdnMu IDB4JTAyeFxuIiwgcnBlYywgY3BlYyk7Cj4gKwkJCXJldCA9IGZhbHNlOwo+ICsJCX0KPiArCj4g KwkJYnJlYWs7Cj4gKwlkZWZhdWx0Ogo+ICsJCWJyZWFrOwo+ICsJfQo+ICsKPiArCXJldHVybiBy ZXQ7Cj4gK2Vycm9yOgo+ICsJLyogRG8gbm90IGV4cGVjdCB0byBnbyB0byB0aGlzIGNhc2UgKi8K PiArCWRldl9lcnIoJnNzaWZfYm1jLT5jbGllbnQtPmRldiwKPiArCQkiRXJyb3I6IFVuZXhwZWN0 ZWQgbGVuZ3RoIHJlY2VpdmVkICVkXG4iLCBzc2lmX21zZ19sZW4oJnNzaWZfYm1jLT5yZXF1ZXN0 KSk7Cj4gKwo+ICsJcmV0dXJuIGZhbHNlOwo+ICt9Cj4gKwo+ICtzdGF0aWMgdm9pZCBjb21wbGV0 ZV93cml0ZV9yZWNlaXZlZChzdHJ1Y3Qgc3NpZl9ibWNfY3R4ICpzc2lmX2JtYykKPiArewo+ICsJ dTggY21kID0gc3NpZl9ibWMtPnNtYnVzX2NtZDsKPiArCj4gKwkvKiBBIEJNQyB0aGF0IHJlY2Vp dmVzIGFuIGludmFsaWQgUEVDIHNoYWxsIGRyb3AgdGhlIGRhdGEgZm9yIHRoZSB3cml0ZQo+ICsJ ICogdHJhbnNhY3Rpb24gYW5kIGFueSBmdXJ0aGVyIHRyYW5zYWN0aW9ucyAocmVhZCBvciB3cml0 ZSkgdW50aWwKPiArCSAqIHRoZSBuZXh0IHZhbGlkIHJlYWQgb3Igd3JpdGUgU3RhcnQgdHJhbnNh Y3Rpb24gaXMgcmVjZWl2ZWQKPiArCSAqLwo+ICsJaWYgKCF2YWxpZGF0ZV9wZWMoc3NpZl9ibWMp KSB7Cj4gKwkJZGV2X2Vycigmc3NpZl9ibWMtPmNsaWVudC0+ZGV2LCAiUmVjZWl2ZWQgaW52YWxp ZCBQRUNcbiIpOwo+ICsJCXJldHVybjsKPiArCX0KPiArCj4gKwlpZiAoY21kID09IFNTSUZfSVBN SV9TSU5HTEVQQVJUX1dSSVRFIHx8IGNtZCA9PSBTU0lGX0lQTUlfTVVMVElQQVJUX1dSSVRFX0VO RCkKPiArCQloYW5kbGVfcmVxdWVzdChzc2lmX2JtYyk7Cj4gK30KPiArCj4gK3N0YXRpYyB2b2lk IGluaXRpYWxpemVfdHJhbnNmZXIoc3RydWN0IHNzaWZfYm1jX2N0eCAqc3NpZl9ibWMsIHU4ICp2 YWwpCj4gK3sKPiArCS8qIFNNQlVTIGNvbW1hbmQgY2FuIHZhcnkgKHNpbmdsZSBvciBtdWx0aS1w YXJ0KSAqLwo+ICsJc3NpZl9ibWMtPnNtYnVzX2NtZCA9ICp2YWw7Cj4gKwlzc2lmX2JtYy0+bXNn X2lkeCsrOwo+ICsKPiArCWlmIChzc2lmX2JtYy0+c21idXNfY21kID09IFNTSUZfSVBNSV9TSU5H TEVQQVJUX1dSSVRFIHx8Cj4gKwkgICAgc3NpZl9ibWMtPnNtYnVzX2NtZCA9PSBTU0lGX0lQTUlf TVVMVElQQVJUX1dSSVRFX1NUQVJUKSB7Cj4gKwkJLyoKPiArCQkgKiBUaGUgcmVzcG9uc2UgY2Fu IGJlIGRlbGF5ZWQgaW4gQk1DIGNhdXNpbmcgaG9zdCBTU0lGIGRyaXZlcgo+ICsJCSAqIHRvIHRp bWVvdXQgYW5kIHNlbmQgYSBuZXcgcmVxdWVzdCBvbmNlIEJNQyBzbGF2ZSBpcyByZWFkeS4KPiAr CQkgKiBJbiB0aGF0IGNhc2UgY2hlY2sgZm9yIHBlbmRpbmcgcmVzcG9uc2UgYW5kIGNsZWFyIGl0 Cj4gKwkJICovCj4gKwkJaWYgKHNzaWZfYm1jLT5yZXNwb25zZV9pbl9wcm9ncmVzcykgewo+ICsJ CQlkZXZfZXJyKCZzc2lmX2JtYy0+Y2xpZW50LT5kZXYsCj4gKwkJCQkiV2FybjogU1NJRiBuZXcg cmVxdWVzdCB3aXRoIHBlbmRpbmcgcmVzcG9uc2UiKTsKPiArCQkJY29tcGxldGVfcmVzcG9uc2Uo c3NpZl9ibWMpOwo+ICsJCX0KPiArCX0gZWxzZSBpZiAodW5saWtlbHkoc3NpZl9ibWMtPnNtYnVz X2NtZCAhPSBTU0lGX0lQTUlfU0lOR0xFUEFSVF9SRUFEICYmCj4gKwkJCSAgICBzc2lmX2JtYy0+ c21idXNfY21kICE9IFNTSUZfSVBNSV9NVUxUSVBBUlRfV1JJVEVfTUlERExFICYmCj4gKwkJCSAg ICBzc2lmX2JtYy0+c21idXNfY21kICE9IFNTSUZfSVBNSV9NVUxUSVBBUlRfV1JJVEVfRU5EICYm Cj4gKwkJCSAgICBzc2lmX2JtYy0+c21idXNfY21kICE9IFNTSUZfSVBNSV9NVUxUSVBBUlRfUkVB RF9TVEFSVCAmJgo+ICsJCQkgICAgc3NpZl9ibWMtPnNtYnVzX2NtZCAhPSBTU0lGX0lQTUlfTVVM VElQQVJUX1JFQURfTUlERExFKSkgewo+ICsJCS8qIFVua25vd24gY29tbWFuZCwgY2xlYXIgaXQg Ki8KPiArCQlkZXZfZXJyKCZzc2lmX2JtYy0+Y2xpZW50LT5kZXYsICJXYXJuOiBVbmtub3duIFNN QnVzIGNvbW1hbmQiKTsKPiArCQljb21wbGV0ZV9yZXNwb25zZShzc2lmX2JtYyk7Cj4gKwl9Cj4g K30KPiArCj4gKy8qCj4gKyAqIENhbGxiYWNrIGZ1bmN0aW9uIHRvIGhhbmRsZSBJMkMgc2xhdmUg ZXZlbnRzCj4gKyAqLwo+ICtzdGF0aWMgaW50IHNzaWZfYm1jX2NiKHN0cnVjdCBpMmNfY2xpZW50 ICpjbGllbnQsIGVudW0gaTJjX3NsYXZlX2V2ZW50IGV2ZW50LCB1OCAqdmFsKQo+ICt7Cj4gKwl1 bnNpZ25lZCBsb25nIGZsYWdzOwo+ICsJc3RydWN0IHNzaWZfYm1jX2N0eCAqc3NpZl9ibWMgPSBp MmNfZ2V0X2NsaWVudGRhdGEoY2xpZW50KTsKPiArCj4gKwlzcGluX2xvY2tfaXJxc2F2ZSgmc3Np Zl9ibWMtPmxvY2ssIGZsYWdzKTsKPiArCj4gKwkvKiBJMkMgRXZlbnQgSGFuZGxlcjoKPiArCSAq ICAgSTJDX1NMQVZFX1JFQURfUkVRVUVTVEVECTB4MAo+ICsJICogICBJMkNfU0xBVkVfV1JJVEVf UkVRVUVTVEVECTB4MQo+ICsJICogICBJMkNfU0xBVkVfUkVBRF9QUk9DRVNTRUQJMHgyCj4gKwkg KiAgIEkyQ19TTEFWRV9XUklURV9SRUNFSVZFRAkweDMKPiArCSAqICAgSTJDX1NMQVZFX1NUT1AJ CTB4NAo+ICsJICovCj4gKwlzd2l0Y2ggKGV2ZW50KSB7Cj4gKwljYXNlIEkyQ19TTEFWRV9SRUFE X1JFUVVFU1RFRDoKPiArCQlzc2lmX2JtYy0+bXNnX2lkeCA9IDA7Cj4gKwkJaWYgKHNzaWZfYm1j LT5pc19zaW5nbGVwYXJ0X3JlYWQpCj4gKwkJCSp2YWwgPSBzc2lmX2JtYy0+cmVzcG9uc2UubGVu Owo+ICsJCWVsc2UKPiArCQkJc2V0X211bHRpcGFydF9yZXNwb25zZV9idWZmZXIoc3NpZl9ibWMs IHZhbCk7Cj4gKwkJYnJlYWs7Cj4gKwo+ICsJY2FzZSBJMkNfU0xBVkVfV1JJVEVfUkVRVUVTVEVE Ogo+ICsJCXNzaWZfYm1jLT5tc2dfaWR4ID0gMDsKPiArCQlicmVhazsKPiArCj4gKwljYXNlIEky Q19TTEFWRV9SRUFEX1BST0NFU1NFRDoKPiArCQloYW5kbGVfcmVhZF9wcm9jZXNzZWQoc3NpZl9i bWMsIHZhbCk7Cj4gKwkJYnJlYWs7Cj4gKwo+ICsJY2FzZSBJMkNfU0xBVkVfV1JJVEVfUkVDRUlW RUQ6Cj4gKwkJaWYgKHNzaWZfYm1jLT5tc2dfaWR4KQo+ICsJCQloYW5kbGVfd3JpdGVfcmVjZWl2 ZWQoc3NpZl9ibWMsIHZhbCk7Cj4gKwkJZWxzZQo+ICsJCQlpbml0aWFsaXplX3RyYW5zZmVyKHNz aWZfYm1jLCB2YWwpOwo+ICsKPiArCQlicmVhazsKPiArCj4gKwljYXNlIEkyQ19TTEFWRV9TVE9Q Ogo+ICsJCWlmIChzc2lmX2JtYy0+bGFzdF9ldmVudCA9PSBJMkNfU0xBVkVfV1JJVEVfUkVDRUlW RUQpCj4gKwkJCWNvbXBsZXRlX3dyaXRlX3JlY2VpdmVkKHNzaWZfYm1jKTsKPiArCQkvKiBSZXNl dCBtZXNzYWdlIGluZGV4ICovCj4gKwkJc3NpZl9ibWMtPm1zZ19pZHggPSAwOwo+ICsJCWJyZWFr Owo+ICsKPiArCWRlZmF1bHQ6Cj4gKwkJYnJlYWs7Cj4gKwl9Cj4gKwlzc2lmX2JtYy0+bGFzdF9l dmVudCA9IGV2ZW50Owo+ICsJc3Bpbl91bmxvY2tfaXJxcmVzdG9yZSgmc3NpZl9ibWMtPmxvY2ss IGZsYWdzKTsKPiArCj4gKwlyZXR1cm4gMDsKPiArfQo+ICsKPiArc3RydWN0IHNzaWZfYm1jX2N0 eCAqc3NpZl9ibWNfYWxsb2Moc3RydWN0IGkyY19jbGllbnQgKmNsaWVudCwgaW50IHNpemVvZl9w cml2KQo+ICt7Cj4gKwlzdHJ1Y3Qgc3NpZl9ibWNfY3R4ICpzc2lmX2JtYzsKPiArCWludCByZXQ7 Cj4gKwo+ICsJc3NpZl9ibWMgPSBkZXZtX2t6YWxsb2MoJmNsaWVudC0+ZGV2LCBzaXplb2YoKnNz aWZfYm1jKSArIHNpemVvZl9wcml2LCBHRlBfS0VSTkVMKTsKPiArCWlmICghc3NpZl9ibWMpCj4g KwkJcmV0dXJuIEVSUl9QVFIoLUVOT01FTSk7Cj4gKwo+ICsJc3Bpbl9sb2NrX2luaXQoJnNzaWZf Ym1jLT5sb2NrKTsKPiArCj4gKwlpbml0X3dhaXRxdWV1ZV9oZWFkKCZzc2lmX2JtYy0+d2FpdF9x dWV1ZSk7Cj4gKwlzc2lmX2JtYy0+cmVxdWVzdF9hdmFpbGFibGUgPSBmYWxzZTsKPiArCXNzaWZf Ym1jLT5yZXNwb25zZV9pbl9wcm9ncmVzcyA9IGZhbHNlOwo+ICsKPiArCS8qIFJlZ2lzdGVyIG1p c2MgZGV2aWNlIGludGVyZmFjZSAqLwo+ICsJc3NpZl9ibWMtPm1pc2NkZXYubWlub3IgPSBNSVND X0RZTkFNSUNfTUlOT1I7Cj4gKwlzc2lmX2JtYy0+bWlzY2Rldi5uYW1lID0gREVWSUNFX05BTUU7 Cj4gKwlzc2lmX2JtYy0+bWlzY2Rldi5mb3BzID0gJnNzaWZfYm1jX2ZvcHM7Cj4gKwlzc2lmX2Jt Yy0+bWlzY2Rldi5wYXJlbnQgPSAmY2xpZW50LT5kZXY7Cj4gKwlyZXQgPSBtaXNjX3JlZ2lzdGVy KCZzc2lmX2JtYy0+bWlzY2Rldik7Cj4gKwlpZiAocmV0KQo+ICsJCWdvdG8gb3V0Owo+ICsKPiAr CXNzaWZfYm1jLT5jbGllbnQgPSBjbGllbnQ7Cj4gKwlzc2lmX2JtYy0+Y2xpZW50LT5mbGFncyB8 PSBJMkNfQ0xJRU5UX1NMQVZFOwo+ICsKPiArCS8qIFJlZ2lzdGVyIEkyQyBzbGF2ZSAqLwo+ICsJ aTJjX3NldF9jbGllbnRkYXRhKGNsaWVudCwgc3NpZl9ibWMpOwo+ICsJcmV0ID0gaTJjX3NsYXZl X3JlZ2lzdGVyKGNsaWVudCwgc3NpZl9ibWNfY2IpOwo+ICsJaWYgKHJldCkgewo+ICsJCW1pc2Nf ZGVyZWdpc3Rlcigmc3NpZl9ibWMtPm1pc2NkZXYpOwo+ICsJCWdvdG8gb3V0Owo+ICsJfQo+ICsK PiArCXJldHVybiBzc2lmX2JtYzsKPiArCj4gK291dDoKPiArCWRldm1fa2ZyZWUoJmNsaWVudC0+ ZGV2LCBzc2lmX2JtYyk7Cj4gKwlyZXR1cm4gRVJSX1BUUihyZXQpOwo+ICt9Cj4gK0VYUE9SVF9T WU1CT0woc3NpZl9ibWNfYWxsb2MpOwo+ICsKPiArTU9EVUxFX0FVVEhPUigiQ2h1b25nIFRyYW4g PGNodW9uZ0Bvcy5hbXBlcmVjb21wdXRpbmcuY29tPiIpOwo+ICtNT0RVTEVfQVVUSE9SKCJRdWFu IE5ndXllbiA8cXVhbkBvcy5hbXBlcmVjb21wdXRpbmcuY29tPiIpOwo+ICtNT0RVTEVfREVTQ1JJ UFRJT04oIkxpbnV4IGRldmljZSBkcml2ZXIgb2YgdGhlIEJNQyBJUE1JIFNTSUYgaW50ZXJmYWNl LiIpOwo+ICtNT0RVTEVfTElDRU5TRSgiR1BMIHYyIik7Cj4gZGlmZiAtLWdpdCBhL2RyaXZlcnMv Y2hhci9pcG1pL3NzaWZfYm1jLmggYi9kcml2ZXJzL2NoYXIvaXBtaS9zc2lmX2JtYy5oCj4gbmV3 IGZpbGUgbW9kZSAxMDA2NDQKPiBpbmRleCAwMDAwMDAwMDAwMDAuLmVhYjU0MDA2MWYxNAo+IC0t LSAvZGV2L251bGwKPiArKysgYi9kcml2ZXJzL2NoYXIvaXBtaS9zc2lmX2JtYy5oCj4gQEAgLTAs MCArMSw5MyBAQAo+ICsvKiBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogR1BMLTIuMCsgKi8KPiAr LyoKPiArICogVGhlIGRyaXZlciBmb3IgQk1DIHNpZGUgb2YgU1NJRiBpbnRlcmZhY2UKPiArICoK PiArICogQ29weXJpZ2h0IChjKSAyMDIxLCBBbXBlcmUgQ29tcHV0aW5nIExMQwo+ICsgKgo+ICsg KiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTsgeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQg YW5kL29yCj4gKyAqIG1vZGlmeSBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFs IFB1YmxpYyBMaWNlbnNlIGFzCj4gKyAqIHB1Ymxpc2hlZCBieSB0aGUgRnJlZSBTb2Z0d2FyZSBG b3VuZGF0aW9uOyBlaXRoZXIgdmVyc2lvbiAyIG9mCj4gKyAqIHRoZSBMaWNlbnNlLCBvciAoYXQg eW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLgo+ICsgKgo+ICsgKiBUaGlzIHByb2dyYW0g aXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCwKPiArICog YnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFu dHkgb2YKPiArICogTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQ VVJQT1NFLiAgU2VlIHRoZQo+ICsgKiBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9y ZSBkZXRhaWxzLgo+ICsgKgo+ICsgKiBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9m IHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZQo+ICsgKiBhbG9uZyB3aXRoIHRoaXMgcHJv Z3JhbS4gIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uCj4gKyAq Lwo+ICsjaWZuZGVmIF9fU1NJRl9CTUNfSF9fCj4gKyNkZWZpbmUgX19TU0lGX0JNQ19IX18KPiAr Cj4gKyNkZWZpbmUgREVWSUNFX05BTUUJCQkJImlwbWktc3NpZi1ob3N0Igo+ICsKPiArI2RlZmlu ZSBHRVRfOEJJVF9BRERSKGFkZHJfN2JpdCkJCSgoKGFkZHJfN2JpdCkgPDwgMSkgJiAweGZmKQo+ ICsKPiArI2RlZmluZSBNU0dfUEFZTE9BRF9MRU5fTUFYCQkJMjUyCj4gKwo+ICsvKiBBIHN0YW5k YXJkIFNNQnVzIFRyYW5zYWN0aW9uIGlzIGxpbWl0ZWQgdG8gMzIgZGF0YSBieXRlcyAqLwo+ICsj ZGVmaW5lIE1BWF9QQVlMT0FEX1BFUl9UUkFOU0FDVElPTgkJMzIKPiArCj4gKyNkZWZpbmUgTUFY X0lQTUlfREFUQV9QRVJfU1RBUlRfVFJBTlNBQ1RJT04JMzAKPiArI2RlZmluZSBNQVhfSVBNSV9E QVRBX1BFUl9NSURETEVfVFJBTlNBQ1RJT04JMzEKPiArCj4gKyNkZWZpbmUgU1NJRl9JUE1JX1NJ TkdMRVBBUlRfV1JJVEUJCTB4Mgo+ICsjZGVmaW5lIFNTSUZfSVBNSV9TSU5HTEVQQVJUX1JFQUQJ CTB4Mwo+ICsjZGVmaW5lIFNTSUZfSVBNSV9NVUxUSVBBUlRfV1JJVEVfU1RBUlQJCTB4Ngo+ICsj ZGVmaW5lIFNTSUZfSVBNSV9NVUxUSVBBUlRfV1JJVEVfTUlERExFCTB4Nwo+ICsjZGVmaW5lIFNT SUZfSVBNSV9NVUxUSVBBUlRfV1JJVEVfRU5ECQkweDgKPiArI2RlZmluZSBTU0lGX0lQTUlfTVVM VElQQVJUX1JFQURfU1RBUlQJCTB4Mwo+ICsjZGVmaW5lIFNTSUZfSVBNSV9NVUxUSVBBUlRfUkVB RF9NSURETEUJCTB4OQo+ICsKPiArc3RydWN0IHNzaWZfbXNnIHsKPiArCXU4IGxlbjsKPiArCXU4 IG5ldGZuX2x1bjsKPiArCXU4IGNtZDsKPiArCXU4IHBheWxvYWRbTVNHX1BBWUxPQURfTEVOX01B WF07Cj4gK30gX19wYWNrZWQ7Cj4gKwo+ICtzdGF0aWMgaW5saW5lIHUzMiBzc2lmX21zZ19sZW4o c3RydWN0IHNzaWZfbXNnICpzc2lmX21zZykKPiArewo+ICsJcmV0dXJuIHNzaWZfbXNnLT5sZW4g KyAxOwo+ICt9Cj4gKwo+ICsjZGVmaW5lIFNTSUZfQk1DX0JVU1kgICAweDAxCj4gKyNkZWZpbmUg U1NJRl9CTUNfUkVBRFkgIDB4MDIKPiArCj4gK3N0cnVjdCBzc2lmX2JtY19jdHggewo+ICsJc3Ry dWN0IGkyY19jbGllbnQJKmNsaWVudDsKPiArCXN0cnVjdCBtaXNjZGV2aWNlCW1pc2NkZXY7Cj4g Kwl1OAkJCXJ1bm5pbmc7Cj4gKwl1OAkJCXNtYnVzX2NtZDsKPiArCXN0cnVjdCBzc2lmX21zZwkJ cmVxdWVzdDsKPiArCWJvb2wJCQlyZXF1ZXN0X2F2YWlsYWJsZTsKPiArCXN0cnVjdCBzc2lmX21z ZwkJcmVzcG9uc2U7Cj4gKwlib29sCQkJcmVzcG9uc2VfaW5fcHJvZ3Jlc3M7Cj4gKwkvKiBSZXNw b25zZSBidWZmZXIgZm9yIE11bHRpLXBhcnQgUmVhZCBUcmFuc2FjdGlvbiAqLwo+ICsJdTgJCQly ZXNwb25zZV9idWZbTUFYX1BBWUxPQURfUEVSX1RSQU5TQUNUSU9OXTsKPiArCS8qIEZsYWcgdG8g aWRlbnRpZnkgYSBNdWx0aS1wYXJ0IFJlYWQgVHJhbnNhY3Rpb24gKi8KPiArCWJvb2wJCQlpc19z aW5nbGVwYXJ0X3JlYWQ7Cj4gKwl1OAkJCW5ieXRlc19wcm9jZXNzZWQ7Cj4gKwl1OAkJCXJlbWFp bl9sZW47Cj4gKwl1OAkJCXJlY3ZfbGVuOwo+ICsJLyogQmxvY2sgTnVtYmVyIG9mIGEgTXVsdGkt cGFydCBSZWFkIFRyYW5zYWN0aW9uICovCj4gKwl1OAkJCWJsb2NrX251bTsKPiArCXNpemVfdAkJ CW1zZ19pZHg7Cj4gKwllbnVtIGkyY19zbGF2ZV9ldmVudAlsYXN0X2V2ZW50Owo+ICsJYm9vbAkJ CXBlY19zdXBwb3J0Owo+ICsJLyogc3BpbmxvY2sgKi8KPiArCXNwaW5sb2NrX3QJCWxvY2s7Cj4g Kwl3YWl0X3F1ZXVlX2hlYWRfdAl3YWl0X3F1ZXVlOwo+ICsJdm9pZCAoKnNldF9zc2lmX2JtY19z dGF0dXMpKHN0cnVjdCBzc2lmX2JtY19jdHggKnNzaWZfYm1jLCB1bnNpZ25lZCBpbnQgZmxhZ3Mp Owo+ICsJdm9pZAkJCSpwcml2Owo+ICt9Owo+ICsKPiArc3RhdGljIGlubGluZSBzdHJ1Y3Qgc3Np Zl9ibWNfY3R4ICp0b19zc2lmX2JtYyhzdHJ1Y3QgZmlsZSAqZmlsZSkKPiArewo+ICsJcmV0dXJu IGNvbnRhaW5lcl9vZihmaWxlLT5wcml2YXRlX2RhdGEsIHN0cnVjdCBzc2lmX2JtY19jdHgsIG1p c2NkZXYpOwo+ICt9Cj4gKwo+ICtzdHJ1Y3Qgc3NpZl9ibWNfY3R4ICpzc2lmX2JtY19hbGxvYyhz dHJ1Y3QgaTJjX2NsaWVudCAqY2xpZW50LCBpbnQgc2l6ZW9mX3ByaXYpOwo+ICsKPiArI2VuZGlm IC8qIF9fU1NJRl9CTUNfSF9fICovCj4gLS0gCj4gMi4yOC4wCj4gCgpfX19fX19fX19fX19fX19f X19fX19fX19fX19fX19fX19fX19fX19fX19fX19fXwpsaW51eC1hcm0ta2VybmVsIG1haWxpbmcg bGlzdApsaW51eC1hcm0ta2VybmVsQGxpc3RzLmluZnJhZGVhZC5vcmcKaHR0cDovL2xpc3RzLmlu ZnJhZGVhZC5vcmcvbWFpbG1hbi9saXN0aW5mby9saW51eC1hcm0ta2VybmVsCg==