/* A standard SMBus Transaction is limited to 32 data bytes */ #define MAX_PAYLOAD_PER_TRANSACTION 32 /* Transaction includes the address, the command, the length and the PEC byte */ #define MAX_TRANSACTION (MAX_PAYLOAD_PER_TRANSACTION + 4)
/* * IPMI 2.0 Spec, section 12.7 SSIF Timing, * Request-to-Response Time is T6max(250ms) - T1max(20ms) - 3ms = 227ms * Recover ssif_bmc from busy state if it takes up to 500ms
*/ #define RESPONSE_TIMEOUT 500 /* ms */
staticconstchar *state_to_string(enum ssif_state state)
{ switch (state) { case SSIF_READY: return"SSIF_READY"; case SSIF_START: return"SSIF_START"; case SSIF_SMBUS_CMD: return"SSIF_SMBUS_CMD"; case SSIF_REQ_RECVING: return"SSIF_REQ_RECVING"; case SSIF_RES_SENDING: return"SSIF_RES_SENDING"; case SSIF_ABORTING: return"SSIF_ABORTING"; default: return"SSIF_STATE_UNKNOWN";
}
}
/* Handle SSIF message that will be sent to user */ static ssize_t ssif_bmc_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{ struct ssif_bmc_ctx *ssif_bmc = to_ssif_bmc(file); struct ipmi_ssif_msg msg; unsignedlong flags;
ssize_t ret;
spin_lock_irqsave(&ssif_bmc->lock, flags); while (!ssif_bmc->request_available) {
spin_unlock_irqrestore(&ssif_bmc->lock, flags); if (file->f_flags & O_NONBLOCK) return -EAGAIN;
ret = wait_event_interruptible(ssif_bmc->wait_queue,
ssif_bmc->request_available); if (ret) return ret;
spin_lock_irqsave(&ssif_bmc->lock, flags);
}
spin_lock_irqsave(&ssif_bmc->lock, flags); while (ssif_bmc->response_in_progress) {
spin_unlock_irqrestore(&ssif_bmc->lock, flags); if (file->f_flags & O_NONBLOCK) return -EAGAIN;
ret = wait_event_interruptible(ssif_bmc->wait_queue,
!ssif_bmc->response_in_progress); if (ret) return ret;
spin_lock_irqsave(&ssif_bmc->lock, flags);
}
/* * The write must complete before the response timeout fired, otherwise * the response is aborted and wait for next request * Return -EINVAL if the response is aborted
*/
ret = (ssif_bmc->response_timer_inited) ? 0 : -EINVAL; if (ret) gotoexit;
spin_lock_irq(&ssif_bmc->lock); /* The request is available, userspace application can get the request */ if (ssif_bmc->request_available)
mask |= EPOLLIN;
/* Do nothing if the response is in progress */ if (!ssif_bmc->response_in_progress) { /* Recover ssif_bmc from busy */
ssif_bmc->busy = false;
ssif_bmc->response_timer_inited = false; /* Set aborting flag */
ssif_bmc->aborting = true;
}
spin_unlock_irqrestore(&ssif_bmc->lock, flags);
}
/* Called with ssif_bmc->lock held. */ staticvoid handle_request(struct ssif_bmc_ctx *ssif_bmc)
{ /* set ssif_bmc to busy waiting for response */
ssif_bmc->busy = true; /* Request message is available to process */
ssif_bmc->request_available = true; /* Clean old response buffer */
memset(&ssif_bmc->response, 0, sizeof(struct ipmi_ssif_msg)); /* This is the new READ request.*/
wake_up_all(&ssif_bmc->wait_queue);
/* Armed timer to recover slave from busy state in case of no response */ if (!ssif_bmc->response_timer_inited) {
timer_setup(&ssif_bmc->response_timer, response_timeout, 0);
ssif_bmc->response_timer_inited = true;
}
mod_timer(&ssif_bmc->response_timer, jiffies + msecs_to_jiffies(RESPONSE_TIMEOUT));
}
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 *
*/ /* Clean the buffer */
memset(&part->payload[0], 0, MAX_PAYLOAD_PER_TRANSACTION);
part->length = ssif_bmc->remain_len + 1;
part_len = ssif_bmc->remain_len;
ssif_bmc->block_num = 0xFF;
part->payload[0] = ssif_bmc->block_num;
} 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
*/
part->length = MAX_PAYLOAD_PER_TRANSACTION;
part_len = MAX_IPMI_DATA_PER_MIDDLE_TRANSACTION;
part->payload[0] = ssif_bmc->block_num;
ssif_bmc->block_num++;
}
default: /* Do not expect to go to this case */
dev_err(&ssif_bmc->client->dev, "%s: Unexpected SMBus command 0x%x\n",
__func__, part->smbus_cmd); break;
}
/* Process the IPMI response that will be read by master */ staticvoid handle_read_processed(struct ssif_bmc_ctx *ssif_bmc, u8 *val)
{ struct ssif_part_buffer *part = &ssif_bmc->part_buf;
staticvoid handle_write_received(struct ssif_bmc_ctx *ssif_bmc, u8 *val)
{ /* * The msg_idx must be 1 when first enter SSIF_REQ_RECVING state * And it would never exceeded 36 bytes included the 32 bytes max payload + * the address + the command + the len and the PEC.
*/ if (ssif_bmc->msg_idx < 1 || ssif_bmc->msg_idx > MAX_TRANSACTION) return;
if (part->index == part->length) { /* PEC is not included */
ssif_bmc->pec_support = false;
ret = true; gotoexit;
}
if (part->index != part->length + 1) {
ret = false; gotoexit;
}
/* PEC is included */
ssif_bmc->pec_support = true;
part->pec = part->payload[part->length];
addr = GET_8BIT_ADDR(ssif_bmc->client->addr);
cpec = i2c_smbus_pec(0, &addr, 1);
cpec = i2c_smbus_pec(cpec, &part->smbus_cmd, 1);
cpec = i2c_smbus_pec(cpec, &part->length, 1); /* * As SMBus specification does not allow the length * (byte count) in the Write-Block protocol to be zero. * Therefore, it is illegal to have the last Middle * transaction in the sequence carry 32-byte and have * a length of ‘0’ in the End transaction. * But some users may try to use this way and we should * prevent ssif_bmc driver broken in this case.
*/ if (part->length)
cpec = i2c_smbus_pec(cpec, part->payload, part->length);
switch (part->smbus_cmd) { case SSIF_IPMI_SINGLEPART_WRITE: /* save the whole part to request*/
ssif_bmc->request.len = part->length;
memcpy(ssif_bmc->request.payload, part->payload, part->length);
break; case SSIF_IPMI_MULTIPART_WRITE_START:
ssif_bmc->request.len = 0;
fallthrough; case SSIF_IPMI_MULTIPART_WRITE_MIDDLE: case SSIF_IPMI_MULTIPART_WRITE_END:
len = ssif_bmc->request.len + part->length; /* Do the bound check here, not allow the request len exceed 254 bytes */ if (len > IPMI_SSIF_PAYLOAD_MAX) {
dev_warn(&ssif_bmc->client->dev, "Warn: Request exceeded 254 bytes, aborting"); /* Request too long, aborting */
ssif_bmc->aborting = true;
} else {
memcpy(ssif_bmc->request.payload + ssif_bmc->request.len,
part->payload, part->length);
ssif_bmc->request.len += part->length;
} break; default: /* Do not expect to go to this case */
dev_err(&ssif_bmc->client->dev, "%s: Unexpected SMBus command 0x%x\n",
__func__, part->smbus_cmd); break;
}
}
if (*val == SSIF_IPMI_SINGLEPART_WRITE || *val == SSIF_IPMI_MULTIPART_WRITE_START) { /* * The response maybe not come in-time, causing host SSIF driver * to timeout and resend a new request. In such case check for * pending response and clear it
*/ if (ssif_bmc->response_in_progress)
complete_response(ssif_bmc);
/* This is new request, flip aborting flag if set */ if (ssif_bmc->aborting)
ssif_bmc->aborting = false;
}
}
if (ssif_bmc->aborting)
ssif_bmc->state = SSIF_ABORTING; else
ssif_bmc->state = SSIF_REQ_RECVING;
}
/* This is response sending state */ if (ssif_bmc->state == SSIF_REQ_RECVING)
handle_write_received(ssif_bmc, val); elseif (ssif_bmc->state == SSIF_SMBUS_CMD)
process_smbus_cmd(ssif_bmc, val);
}
} elseif (ssif_bmc->state == SSIF_REQ_RECVING) { if (validate_request_part(ssif_bmc)) {
process_request_part(ssif_bmc); if (ssif_bmc->part_buf.smbus_cmd == SSIF_IPMI_SINGLEPART_WRITE ||
ssif_bmc->part_buf.smbus_cmd == SSIF_IPMI_MULTIPART_WRITE_END)
handle_request(ssif_bmc);
ssif_bmc->state = SSIF_READY;
} else { /* * A BMC that receives an invalid request drop the data for the write * transaction and any further transactions (read or write) until * the next valid read or write Start transaction is received
*/
dev_err(&ssif_bmc->client->dev, "Error: invalid pec\n");
ssif_bmc->aborting = true;
}
} elseif (ssif_bmc->state == SSIF_RES_SENDING) { if (ssif_bmc->is_singlepart_read || ssif_bmc->block_num == 0xFF) {
memset(&ssif_bmc->part_buf, 0, sizeof(struct ssif_part_buffer)); /* Invalidate response buffer to denote it is sent */
complete_response(ssif_bmc);
}
ssif_bmc->state = SSIF_READY;
}
/* Reset message index */
ssif_bmc->msg_idx = 0;
}
/* * Callback function to handle I2C slave events
*/ staticint ssif_bmc_cb(struct i2c_client *client, enum i2c_slave_event event, u8 *val)
{ unsignedlong flags; struct ssif_bmc_ctx *ssif_bmc = i2c_get_clientdata(client); int ret = 0;
spin_lock_irqsave(&ssif_bmc->lock, flags);
switch (event) { case I2C_SLAVE_READ_REQUESTED:
on_read_requested_event(ssif_bmc, val); break;
case I2C_SLAVE_WRITE_REQUESTED:
on_write_requested_event(ssif_bmc, val); break;
case I2C_SLAVE_READ_PROCESSED:
on_read_processed_event(ssif_bmc, val); break;
case I2C_SLAVE_WRITE_RECEIVED:
on_write_received_event(ssif_bmc, val); break;
case I2C_SLAVE_STOP:
on_stop_event(ssif_bmc, val); break;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.