162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * The driver for BMC side of SSIF interface 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2022, Ampere Computing LLC 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/i2c.h> 1062306a36Sopenharmony_ci#include <linux/miscdevice.h> 1162306a36Sopenharmony_ci#include <linux/module.h> 1262306a36Sopenharmony_ci#include <linux/of.h> 1362306a36Sopenharmony_ci#include <linux/platform_device.h> 1462306a36Sopenharmony_ci#include <linux/poll.h> 1562306a36Sopenharmony_ci#include <linux/sched.h> 1662306a36Sopenharmony_ci#include <linux/mutex.h> 1762306a36Sopenharmony_ci#include <linux/spinlock.h> 1862306a36Sopenharmony_ci#include <linux/timer.h> 1962306a36Sopenharmony_ci#include <linux/jiffies.h> 2062306a36Sopenharmony_ci#include <linux/ipmi_ssif_bmc.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#define DEVICE_NAME "ipmi-ssif-host" 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#define GET_8BIT_ADDR(addr_7bit) (((addr_7bit) << 1) & 0xff) 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci/* A standard SMBus Transaction is limited to 32 data bytes */ 2762306a36Sopenharmony_ci#define MAX_PAYLOAD_PER_TRANSACTION 32 2862306a36Sopenharmony_ci/* Transaction includes the address, the command, the length and the PEC byte */ 2962306a36Sopenharmony_ci#define MAX_TRANSACTION (MAX_PAYLOAD_PER_TRANSACTION + 4) 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#define MAX_IPMI_DATA_PER_START_TRANSACTION 30 3262306a36Sopenharmony_ci#define MAX_IPMI_DATA_PER_MIDDLE_TRANSACTION 31 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#define SSIF_IPMI_SINGLEPART_WRITE 0x2 3562306a36Sopenharmony_ci#define SSIF_IPMI_SINGLEPART_READ 0x3 3662306a36Sopenharmony_ci#define SSIF_IPMI_MULTIPART_WRITE_START 0x6 3762306a36Sopenharmony_ci#define SSIF_IPMI_MULTIPART_WRITE_MIDDLE 0x7 3862306a36Sopenharmony_ci#define SSIF_IPMI_MULTIPART_WRITE_END 0x8 3962306a36Sopenharmony_ci#define SSIF_IPMI_MULTIPART_READ_START 0x3 4062306a36Sopenharmony_ci#define SSIF_IPMI_MULTIPART_READ_MIDDLE 0x9 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci/* 4362306a36Sopenharmony_ci * IPMI 2.0 Spec, section 12.7 SSIF Timing, 4462306a36Sopenharmony_ci * Request-to-Response Time is T6max(250ms) - T1max(20ms) - 3ms = 227ms 4562306a36Sopenharmony_ci * Recover ssif_bmc from busy state if it takes up to 500ms 4662306a36Sopenharmony_ci */ 4762306a36Sopenharmony_ci#define RESPONSE_TIMEOUT 500 /* ms */ 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_cistruct ssif_part_buffer { 5062306a36Sopenharmony_ci u8 address; 5162306a36Sopenharmony_ci u8 smbus_cmd; 5262306a36Sopenharmony_ci u8 length; 5362306a36Sopenharmony_ci u8 payload[MAX_PAYLOAD_PER_TRANSACTION]; 5462306a36Sopenharmony_ci u8 pec; 5562306a36Sopenharmony_ci u8 index; 5662306a36Sopenharmony_ci}; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci/* 5962306a36Sopenharmony_ci * SSIF internal states: 6062306a36Sopenharmony_ci * SSIF_READY 0x00 : Ready state 6162306a36Sopenharmony_ci * SSIF_START 0x01 : Start smbus transaction 6262306a36Sopenharmony_ci * SSIF_SMBUS_CMD 0x02 : Received SMBus command 6362306a36Sopenharmony_ci * SSIF_REQ_RECVING 0x03 : Receiving request 6462306a36Sopenharmony_ci * SSIF_RES_SENDING 0x04 : Sending response 6562306a36Sopenharmony_ci * SSIF_ABORTING 0x05 : Aborting state 6662306a36Sopenharmony_ci */ 6762306a36Sopenharmony_cienum ssif_state { 6862306a36Sopenharmony_ci SSIF_READY, 6962306a36Sopenharmony_ci SSIF_START, 7062306a36Sopenharmony_ci SSIF_SMBUS_CMD, 7162306a36Sopenharmony_ci SSIF_REQ_RECVING, 7262306a36Sopenharmony_ci SSIF_RES_SENDING, 7362306a36Sopenharmony_ci SSIF_ABORTING, 7462306a36Sopenharmony_ci SSIF_STATE_MAX 7562306a36Sopenharmony_ci}; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistruct ssif_bmc_ctx { 7862306a36Sopenharmony_ci struct i2c_client *client; 7962306a36Sopenharmony_ci struct miscdevice miscdev; 8062306a36Sopenharmony_ci int msg_idx; 8162306a36Sopenharmony_ci bool pec_support; 8262306a36Sopenharmony_ci /* ssif bmc spinlock */ 8362306a36Sopenharmony_ci spinlock_t lock; 8462306a36Sopenharmony_ci wait_queue_head_t wait_queue; 8562306a36Sopenharmony_ci u8 running; 8662306a36Sopenharmony_ci enum ssif_state state; 8762306a36Sopenharmony_ci /* Timeout waiting for response */ 8862306a36Sopenharmony_ci struct timer_list response_timer; 8962306a36Sopenharmony_ci bool response_timer_inited; 9062306a36Sopenharmony_ci /* Flag to identify a Multi-part Read Transaction */ 9162306a36Sopenharmony_ci bool is_singlepart_read; 9262306a36Sopenharmony_ci u8 nbytes_processed; 9362306a36Sopenharmony_ci u8 remain_len; 9462306a36Sopenharmony_ci u8 recv_len; 9562306a36Sopenharmony_ci /* Block Number of a Multi-part Read Transaction */ 9662306a36Sopenharmony_ci u8 block_num; 9762306a36Sopenharmony_ci bool request_available; 9862306a36Sopenharmony_ci bool response_in_progress; 9962306a36Sopenharmony_ci bool busy; 10062306a36Sopenharmony_ci bool aborting; 10162306a36Sopenharmony_ci /* Buffer for SSIF Transaction part*/ 10262306a36Sopenharmony_ci struct ssif_part_buffer part_buf; 10362306a36Sopenharmony_ci struct ipmi_ssif_msg response; 10462306a36Sopenharmony_ci struct ipmi_ssif_msg request; 10562306a36Sopenharmony_ci}; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_cistatic inline struct ssif_bmc_ctx *to_ssif_bmc(struct file *file) 10862306a36Sopenharmony_ci{ 10962306a36Sopenharmony_ci return container_of(file->private_data, struct ssif_bmc_ctx, miscdev); 11062306a36Sopenharmony_ci} 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_cistatic const char *state_to_string(enum ssif_state state) 11362306a36Sopenharmony_ci{ 11462306a36Sopenharmony_ci switch (state) { 11562306a36Sopenharmony_ci case SSIF_READY: 11662306a36Sopenharmony_ci return "SSIF_READY"; 11762306a36Sopenharmony_ci case SSIF_START: 11862306a36Sopenharmony_ci return "SSIF_START"; 11962306a36Sopenharmony_ci case SSIF_SMBUS_CMD: 12062306a36Sopenharmony_ci return "SSIF_SMBUS_CMD"; 12162306a36Sopenharmony_ci case SSIF_REQ_RECVING: 12262306a36Sopenharmony_ci return "SSIF_REQ_RECVING"; 12362306a36Sopenharmony_ci case SSIF_RES_SENDING: 12462306a36Sopenharmony_ci return "SSIF_RES_SENDING"; 12562306a36Sopenharmony_ci case SSIF_ABORTING: 12662306a36Sopenharmony_ci return "SSIF_ABORTING"; 12762306a36Sopenharmony_ci default: 12862306a36Sopenharmony_ci return "SSIF_STATE_UNKNOWN"; 12962306a36Sopenharmony_ci } 13062306a36Sopenharmony_ci} 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci/* Handle SSIF message that will be sent to user */ 13362306a36Sopenharmony_cistatic ssize_t ssif_bmc_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) 13462306a36Sopenharmony_ci{ 13562306a36Sopenharmony_ci struct ssif_bmc_ctx *ssif_bmc = to_ssif_bmc(file); 13662306a36Sopenharmony_ci struct ipmi_ssif_msg msg; 13762306a36Sopenharmony_ci unsigned long flags; 13862306a36Sopenharmony_ci ssize_t ret; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci spin_lock_irqsave(&ssif_bmc->lock, flags); 14162306a36Sopenharmony_ci while (!ssif_bmc->request_available) { 14262306a36Sopenharmony_ci spin_unlock_irqrestore(&ssif_bmc->lock, flags); 14362306a36Sopenharmony_ci if (file->f_flags & O_NONBLOCK) 14462306a36Sopenharmony_ci return -EAGAIN; 14562306a36Sopenharmony_ci ret = wait_event_interruptible(ssif_bmc->wait_queue, 14662306a36Sopenharmony_ci ssif_bmc->request_available); 14762306a36Sopenharmony_ci if (ret) 14862306a36Sopenharmony_ci return ret; 14962306a36Sopenharmony_ci spin_lock_irqsave(&ssif_bmc->lock, flags); 15062306a36Sopenharmony_ci } 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci if (count < min_t(ssize_t, 15362306a36Sopenharmony_ci sizeof_field(struct ipmi_ssif_msg, len) + ssif_bmc->request.len, 15462306a36Sopenharmony_ci sizeof(struct ipmi_ssif_msg))) { 15562306a36Sopenharmony_ci spin_unlock_irqrestore(&ssif_bmc->lock, flags); 15662306a36Sopenharmony_ci ret = -EINVAL; 15762306a36Sopenharmony_ci } else { 15862306a36Sopenharmony_ci count = min_t(ssize_t, 15962306a36Sopenharmony_ci sizeof_field(struct ipmi_ssif_msg, len) + ssif_bmc->request.len, 16062306a36Sopenharmony_ci sizeof(struct ipmi_ssif_msg)); 16162306a36Sopenharmony_ci memcpy(&msg, &ssif_bmc->request, count); 16262306a36Sopenharmony_ci ssif_bmc->request_available = false; 16362306a36Sopenharmony_ci spin_unlock_irqrestore(&ssif_bmc->lock, flags); 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci ret = copy_to_user(buf, &msg, count); 16662306a36Sopenharmony_ci } 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci return (ret < 0) ? ret : count; 16962306a36Sopenharmony_ci} 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci/* Handle SSIF message that is written by user */ 17262306a36Sopenharmony_cistatic ssize_t ssif_bmc_write(struct file *file, const char __user *buf, size_t count, 17362306a36Sopenharmony_ci loff_t *ppos) 17462306a36Sopenharmony_ci{ 17562306a36Sopenharmony_ci struct ssif_bmc_ctx *ssif_bmc = to_ssif_bmc(file); 17662306a36Sopenharmony_ci struct ipmi_ssif_msg msg; 17762306a36Sopenharmony_ci unsigned long flags; 17862306a36Sopenharmony_ci ssize_t ret; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci if (count > sizeof(struct ipmi_ssif_msg)) 18162306a36Sopenharmony_ci return -EINVAL; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci if (copy_from_user(&msg, buf, count)) 18462306a36Sopenharmony_ci return -EFAULT; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci if (!msg.len || count < sizeof_field(struct ipmi_ssif_msg, len) + msg.len) 18762306a36Sopenharmony_ci return -EINVAL; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci spin_lock_irqsave(&ssif_bmc->lock, flags); 19062306a36Sopenharmony_ci while (ssif_bmc->response_in_progress) { 19162306a36Sopenharmony_ci spin_unlock_irqrestore(&ssif_bmc->lock, flags); 19262306a36Sopenharmony_ci if (file->f_flags & O_NONBLOCK) 19362306a36Sopenharmony_ci return -EAGAIN; 19462306a36Sopenharmony_ci ret = wait_event_interruptible(ssif_bmc->wait_queue, 19562306a36Sopenharmony_ci !ssif_bmc->response_in_progress); 19662306a36Sopenharmony_ci if (ret) 19762306a36Sopenharmony_ci return ret; 19862306a36Sopenharmony_ci spin_lock_irqsave(&ssif_bmc->lock, flags); 19962306a36Sopenharmony_ci } 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci /* 20262306a36Sopenharmony_ci * The write must complete before the response timeout fired, otherwise 20362306a36Sopenharmony_ci * the response is aborted and wait for next request 20462306a36Sopenharmony_ci * Return -EINVAL if the response is aborted 20562306a36Sopenharmony_ci */ 20662306a36Sopenharmony_ci ret = (ssif_bmc->response_timer_inited) ? 0 : -EINVAL; 20762306a36Sopenharmony_ci if (ret) 20862306a36Sopenharmony_ci goto exit; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci del_timer(&ssif_bmc->response_timer); 21162306a36Sopenharmony_ci ssif_bmc->response_timer_inited = false; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci memcpy(&ssif_bmc->response, &msg, count); 21462306a36Sopenharmony_ci ssif_bmc->is_singlepart_read = (msg.len <= MAX_PAYLOAD_PER_TRANSACTION); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci ssif_bmc->response_in_progress = true; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci /* ssif_bmc not busy */ 21962306a36Sopenharmony_ci ssif_bmc->busy = false; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci /* Clean old request buffer */ 22262306a36Sopenharmony_ci memset(&ssif_bmc->request, 0, sizeof(struct ipmi_ssif_msg)); 22362306a36Sopenharmony_ciexit: 22462306a36Sopenharmony_ci spin_unlock_irqrestore(&ssif_bmc->lock, flags); 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci return (ret < 0) ? ret : count; 22762306a36Sopenharmony_ci} 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_cistatic int ssif_bmc_open(struct inode *inode, struct file *file) 23062306a36Sopenharmony_ci{ 23162306a36Sopenharmony_ci struct ssif_bmc_ctx *ssif_bmc = to_ssif_bmc(file); 23262306a36Sopenharmony_ci int ret = 0; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci spin_lock_irq(&ssif_bmc->lock); 23562306a36Sopenharmony_ci if (!ssif_bmc->running) 23662306a36Sopenharmony_ci ssif_bmc->running = 1; 23762306a36Sopenharmony_ci else 23862306a36Sopenharmony_ci ret = -EBUSY; 23962306a36Sopenharmony_ci spin_unlock_irq(&ssif_bmc->lock); 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci return ret; 24262306a36Sopenharmony_ci} 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_cistatic __poll_t ssif_bmc_poll(struct file *file, poll_table *wait) 24562306a36Sopenharmony_ci{ 24662306a36Sopenharmony_ci struct ssif_bmc_ctx *ssif_bmc = to_ssif_bmc(file); 24762306a36Sopenharmony_ci __poll_t mask = 0; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci poll_wait(file, &ssif_bmc->wait_queue, wait); 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci spin_lock_irq(&ssif_bmc->lock); 25262306a36Sopenharmony_ci /* The request is available, userspace application can get the request */ 25362306a36Sopenharmony_ci if (ssif_bmc->request_available) 25462306a36Sopenharmony_ci mask |= EPOLLIN; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci spin_unlock_irq(&ssif_bmc->lock); 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci return mask; 25962306a36Sopenharmony_ci} 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_cistatic int ssif_bmc_release(struct inode *inode, struct file *file) 26262306a36Sopenharmony_ci{ 26362306a36Sopenharmony_ci struct ssif_bmc_ctx *ssif_bmc = to_ssif_bmc(file); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci spin_lock_irq(&ssif_bmc->lock); 26662306a36Sopenharmony_ci ssif_bmc->running = 0; 26762306a36Sopenharmony_ci spin_unlock_irq(&ssif_bmc->lock); 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci return 0; 27062306a36Sopenharmony_ci} 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci/* 27362306a36Sopenharmony_ci * System calls to device interface for user apps 27462306a36Sopenharmony_ci */ 27562306a36Sopenharmony_cistatic const struct file_operations ssif_bmc_fops = { 27662306a36Sopenharmony_ci .owner = THIS_MODULE, 27762306a36Sopenharmony_ci .open = ssif_bmc_open, 27862306a36Sopenharmony_ci .read = ssif_bmc_read, 27962306a36Sopenharmony_ci .write = ssif_bmc_write, 28062306a36Sopenharmony_ci .release = ssif_bmc_release, 28162306a36Sopenharmony_ci .poll = ssif_bmc_poll, 28262306a36Sopenharmony_ci}; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci/* Called with ssif_bmc->lock held. */ 28562306a36Sopenharmony_cistatic void complete_response(struct ssif_bmc_ctx *ssif_bmc) 28662306a36Sopenharmony_ci{ 28762306a36Sopenharmony_ci /* Invalidate response in buffer to denote it having been sent. */ 28862306a36Sopenharmony_ci ssif_bmc->response.len = 0; 28962306a36Sopenharmony_ci ssif_bmc->response_in_progress = false; 29062306a36Sopenharmony_ci ssif_bmc->nbytes_processed = 0; 29162306a36Sopenharmony_ci ssif_bmc->remain_len = 0; 29262306a36Sopenharmony_ci ssif_bmc->busy = false; 29362306a36Sopenharmony_ci memset(&ssif_bmc->part_buf, 0, sizeof(struct ssif_part_buffer)); 29462306a36Sopenharmony_ci wake_up_all(&ssif_bmc->wait_queue); 29562306a36Sopenharmony_ci} 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_cistatic void response_timeout(struct timer_list *t) 29862306a36Sopenharmony_ci{ 29962306a36Sopenharmony_ci struct ssif_bmc_ctx *ssif_bmc = from_timer(ssif_bmc, t, response_timer); 30062306a36Sopenharmony_ci unsigned long flags; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci spin_lock_irqsave(&ssif_bmc->lock, flags); 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci /* Do nothing if the response is in progress */ 30562306a36Sopenharmony_ci if (!ssif_bmc->response_in_progress) { 30662306a36Sopenharmony_ci /* Recover ssif_bmc from busy */ 30762306a36Sopenharmony_ci ssif_bmc->busy = false; 30862306a36Sopenharmony_ci ssif_bmc->response_timer_inited = false; 30962306a36Sopenharmony_ci /* Set aborting flag */ 31062306a36Sopenharmony_ci ssif_bmc->aborting = true; 31162306a36Sopenharmony_ci } 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci spin_unlock_irqrestore(&ssif_bmc->lock, flags); 31462306a36Sopenharmony_ci} 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci/* Called with ssif_bmc->lock held. */ 31762306a36Sopenharmony_cistatic void handle_request(struct ssif_bmc_ctx *ssif_bmc) 31862306a36Sopenharmony_ci{ 31962306a36Sopenharmony_ci /* set ssif_bmc to busy waiting for response */ 32062306a36Sopenharmony_ci ssif_bmc->busy = true; 32162306a36Sopenharmony_ci /* Request message is available to process */ 32262306a36Sopenharmony_ci ssif_bmc->request_available = true; 32362306a36Sopenharmony_ci /* Clean old response buffer */ 32462306a36Sopenharmony_ci memset(&ssif_bmc->response, 0, sizeof(struct ipmi_ssif_msg)); 32562306a36Sopenharmony_ci /* This is the new READ request.*/ 32662306a36Sopenharmony_ci wake_up_all(&ssif_bmc->wait_queue); 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci /* Armed timer to recover slave from busy state in case of no response */ 32962306a36Sopenharmony_ci if (!ssif_bmc->response_timer_inited) { 33062306a36Sopenharmony_ci timer_setup(&ssif_bmc->response_timer, response_timeout, 0); 33162306a36Sopenharmony_ci ssif_bmc->response_timer_inited = true; 33262306a36Sopenharmony_ci } 33362306a36Sopenharmony_ci mod_timer(&ssif_bmc->response_timer, jiffies + msecs_to_jiffies(RESPONSE_TIMEOUT)); 33462306a36Sopenharmony_ci} 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_cistatic void calculate_response_part_pec(struct ssif_part_buffer *part) 33762306a36Sopenharmony_ci{ 33862306a36Sopenharmony_ci u8 addr = part->address; 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci /* PEC - Start Read Address */ 34162306a36Sopenharmony_ci part->pec = i2c_smbus_pec(0, &addr, 1); 34262306a36Sopenharmony_ci /* PEC - SSIF Command */ 34362306a36Sopenharmony_ci part->pec = i2c_smbus_pec(part->pec, &part->smbus_cmd, 1); 34462306a36Sopenharmony_ci /* PEC - Restart Write Address */ 34562306a36Sopenharmony_ci addr = addr | 0x01; 34662306a36Sopenharmony_ci part->pec = i2c_smbus_pec(part->pec, &addr, 1); 34762306a36Sopenharmony_ci part->pec = i2c_smbus_pec(part->pec, &part->length, 1); 34862306a36Sopenharmony_ci if (part->length) 34962306a36Sopenharmony_ci part->pec = i2c_smbus_pec(part->pec, part->payload, part->length); 35062306a36Sopenharmony_ci} 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_cistatic void set_singlepart_response_buffer(struct ssif_bmc_ctx *ssif_bmc) 35362306a36Sopenharmony_ci{ 35462306a36Sopenharmony_ci struct ssif_part_buffer *part = &ssif_bmc->part_buf; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci part->address = GET_8BIT_ADDR(ssif_bmc->client->addr); 35762306a36Sopenharmony_ci part->length = (u8)ssif_bmc->response.len; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci /* Clear the rest to 0 */ 36062306a36Sopenharmony_ci memset(part->payload + part->length, 0, MAX_PAYLOAD_PER_TRANSACTION - part->length); 36162306a36Sopenharmony_ci memcpy(&part->payload[0], &ssif_bmc->response.payload[0], part->length); 36262306a36Sopenharmony_ci} 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_cistatic void set_multipart_response_buffer(struct ssif_bmc_ctx *ssif_bmc) 36562306a36Sopenharmony_ci{ 36662306a36Sopenharmony_ci struct ssif_part_buffer *part = &ssif_bmc->part_buf; 36762306a36Sopenharmony_ci u8 part_len = 0; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci part->address = GET_8BIT_ADDR(ssif_bmc->client->addr); 37062306a36Sopenharmony_ci switch (part->smbus_cmd) { 37162306a36Sopenharmony_ci case SSIF_IPMI_MULTIPART_READ_START: 37262306a36Sopenharmony_ci /* 37362306a36Sopenharmony_ci * Read Start length is 32 bytes. 37462306a36Sopenharmony_ci * Read Start transfer first 30 bytes of IPMI response 37562306a36Sopenharmony_ci * and 2 special code 0x00, 0x01. 37662306a36Sopenharmony_ci */ 37762306a36Sopenharmony_ci ssif_bmc->nbytes_processed = 0; 37862306a36Sopenharmony_ci ssif_bmc->block_num = 0; 37962306a36Sopenharmony_ci part->length = MAX_PAYLOAD_PER_TRANSACTION; 38062306a36Sopenharmony_ci part_len = MAX_IPMI_DATA_PER_START_TRANSACTION; 38162306a36Sopenharmony_ci ssif_bmc->remain_len = ssif_bmc->response.len - part_len; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci part->payload[0] = 0x00; /* Start Flag */ 38462306a36Sopenharmony_ci part->payload[1] = 0x01; /* Start Flag */ 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci memcpy(&part->payload[2], &ssif_bmc->response.payload[0], part_len); 38762306a36Sopenharmony_ci break; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci case SSIF_IPMI_MULTIPART_READ_MIDDLE: 39062306a36Sopenharmony_ci /* 39162306a36Sopenharmony_ci * IPMI READ Middle or READ End messages can carry up to 31 bytes 39262306a36Sopenharmony_ci * IPMI data plus block number byte. 39362306a36Sopenharmony_ci */ 39462306a36Sopenharmony_ci if (ssif_bmc->remain_len <= MAX_IPMI_DATA_PER_MIDDLE_TRANSACTION) { 39562306a36Sopenharmony_ci /* 39662306a36Sopenharmony_ci * This is READ End message 39762306a36Sopenharmony_ci * Return length is the remaining response data length 39862306a36Sopenharmony_ci * plus block number 39962306a36Sopenharmony_ci * Block number 0xFF is to indicate this is last message 40062306a36Sopenharmony_ci * 40162306a36Sopenharmony_ci */ 40262306a36Sopenharmony_ci /* Clean the buffer */ 40362306a36Sopenharmony_ci memset(&part->payload[0], 0, MAX_PAYLOAD_PER_TRANSACTION); 40462306a36Sopenharmony_ci part->length = ssif_bmc->remain_len + 1; 40562306a36Sopenharmony_ci part_len = ssif_bmc->remain_len; 40662306a36Sopenharmony_ci ssif_bmc->block_num = 0xFF; 40762306a36Sopenharmony_ci part->payload[0] = ssif_bmc->block_num; 40862306a36Sopenharmony_ci } else { 40962306a36Sopenharmony_ci /* 41062306a36Sopenharmony_ci * This is READ Middle message 41162306a36Sopenharmony_ci * Response length is the maximum SMBUS transfer length 41262306a36Sopenharmony_ci * Block number byte is incremented 41362306a36Sopenharmony_ci * Return length is maximum SMBUS transfer length 41462306a36Sopenharmony_ci */ 41562306a36Sopenharmony_ci part->length = MAX_PAYLOAD_PER_TRANSACTION; 41662306a36Sopenharmony_ci part_len = MAX_IPMI_DATA_PER_MIDDLE_TRANSACTION; 41762306a36Sopenharmony_ci part->payload[0] = ssif_bmc->block_num; 41862306a36Sopenharmony_ci ssif_bmc->block_num++; 41962306a36Sopenharmony_ci } 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci ssif_bmc->remain_len -= part_len; 42262306a36Sopenharmony_ci memcpy(&part->payload[1], ssif_bmc->response.payload + ssif_bmc->nbytes_processed, 42362306a36Sopenharmony_ci part_len); 42462306a36Sopenharmony_ci break; 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci default: 42762306a36Sopenharmony_ci /* Do not expect to go to this case */ 42862306a36Sopenharmony_ci dev_err(&ssif_bmc->client->dev, "%s: Unexpected SMBus command 0x%x\n", 42962306a36Sopenharmony_ci __func__, part->smbus_cmd); 43062306a36Sopenharmony_ci break; 43162306a36Sopenharmony_ci } 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci ssif_bmc->nbytes_processed += part_len; 43462306a36Sopenharmony_ci} 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_cistatic bool supported_read_cmd(u8 cmd) 43762306a36Sopenharmony_ci{ 43862306a36Sopenharmony_ci if (cmd == SSIF_IPMI_SINGLEPART_READ || 43962306a36Sopenharmony_ci cmd == SSIF_IPMI_MULTIPART_READ_START || 44062306a36Sopenharmony_ci cmd == SSIF_IPMI_MULTIPART_READ_MIDDLE) 44162306a36Sopenharmony_ci return true; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci return false; 44462306a36Sopenharmony_ci} 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_cistatic bool supported_write_cmd(u8 cmd) 44762306a36Sopenharmony_ci{ 44862306a36Sopenharmony_ci if (cmd == SSIF_IPMI_SINGLEPART_WRITE || 44962306a36Sopenharmony_ci cmd == SSIF_IPMI_MULTIPART_WRITE_START || 45062306a36Sopenharmony_ci cmd == SSIF_IPMI_MULTIPART_WRITE_MIDDLE || 45162306a36Sopenharmony_ci cmd == SSIF_IPMI_MULTIPART_WRITE_END) 45262306a36Sopenharmony_ci return true; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci return false; 45562306a36Sopenharmony_ci} 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci/* Process the IPMI response that will be read by master */ 45862306a36Sopenharmony_cistatic void handle_read_processed(struct ssif_bmc_ctx *ssif_bmc, u8 *val) 45962306a36Sopenharmony_ci{ 46062306a36Sopenharmony_ci struct ssif_part_buffer *part = &ssif_bmc->part_buf; 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci /* msg_idx start from 0 */ 46362306a36Sopenharmony_ci if (part->index < part->length) 46462306a36Sopenharmony_ci *val = part->payload[part->index]; 46562306a36Sopenharmony_ci else if (part->index == part->length && ssif_bmc->pec_support) 46662306a36Sopenharmony_ci *val = part->pec; 46762306a36Sopenharmony_ci else 46862306a36Sopenharmony_ci *val = 0; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci part->index++; 47162306a36Sopenharmony_ci} 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_cistatic void handle_write_received(struct ssif_bmc_ctx *ssif_bmc, u8 *val) 47462306a36Sopenharmony_ci{ 47562306a36Sopenharmony_ci /* 47662306a36Sopenharmony_ci * The msg_idx must be 1 when first enter SSIF_REQ_RECVING state 47762306a36Sopenharmony_ci * And it would never exceeded 36 bytes included the 32 bytes max payload + 47862306a36Sopenharmony_ci * the address + the command + the len and the PEC. 47962306a36Sopenharmony_ci */ 48062306a36Sopenharmony_ci if (ssif_bmc->msg_idx < 1 || ssif_bmc->msg_idx > MAX_TRANSACTION) 48162306a36Sopenharmony_ci return; 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci if (ssif_bmc->msg_idx == 1) { 48462306a36Sopenharmony_ci ssif_bmc->part_buf.length = *val; 48562306a36Sopenharmony_ci ssif_bmc->part_buf.index = 0; 48662306a36Sopenharmony_ci } else { 48762306a36Sopenharmony_ci ssif_bmc->part_buf.payload[ssif_bmc->part_buf.index++] = *val; 48862306a36Sopenharmony_ci } 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci ssif_bmc->msg_idx++; 49162306a36Sopenharmony_ci} 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_cistatic bool validate_request_part(struct ssif_bmc_ctx *ssif_bmc) 49462306a36Sopenharmony_ci{ 49562306a36Sopenharmony_ci struct ssif_part_buffer *part = &ssif_bmc->part_buf; 49662306a36Sopenharmony_ci bool ret = true; 49762306a36Sopenharmony_ci u8 cpec; 49862306a36Sopenharmony_ci u8 addr; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci if (part->index == part->length) { 50162306a36Sopenharmony_ci /* PEC is not included */ 50262306a36Sopenharmony_ci ssif_bmc->pec_support = false; 50362306a36Sopenharmony_ci ret = true; 50462306a36Sopenharmony_ci goto exit; 50562306a36Sopenharmony_ci } 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci if (part->index != part->length + 1) { 50862306a36Sopenharmony_ci ret = false; 50962306a36Sopenharmony_ci goto exit; 51062306a36Sopenharmony_ci } 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci /* PEC is included */ 51362306a36Sopenharmony_ci ssif_bmc->pec_support = true; 51462306a36Sopenharmony_ci part->pec = part->payload[part->length]; 51562306a36Sopenharmony_ci addr = GET_8BIT_ADDR(ssif_bmc->client->addr); 51662306a36Sopenharmony_ci cpec = i2c_smbus_pec(0, &addr, 1); 51762306a36Sopenharmony_ci cpec = i2c_smbus_pec(cpec, &part->smbus_cmd, 1); 51862306a36Sopenharmony_ci cpec = i2c_smbus_pec(cpec, &part->length, 1); 51962306a36Sopenharmony_ci /* 52062306a36Sopenharmony_ci * As SMBus specification does not allow the length 52162306a36Sopenharmony_ci * (byte count) in the Write-Block protocol to be zero. 52262306a36Sopenharmony_ci * Therefore, it is illegal to have the last Middle 52362306a36Sopenharmony_ci * transaction in the sequence carry 32-byte and have 52462306a36Sopenharmony_ci * a length of ‘0’ in the End transaction. 52562306a36Sopenharmony_ci * But some users may try to use this way and we should 52662306a36Sopenharmony_ci * prevent ssif_bmc driver broken in this case. 52762306a36Sopenharmony_ci */ 52862306a36Sopenharmony_ci if (part->length) 52962306a36Sopenharmony_ci cpec = i2c_smbus_pec(cpec, part->payload, part->length); 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci if (cpec != part->pec) 53262306a36Sopenharmony_ci ret = false; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ciexit: 53562306a36Sopenharmony_ci return ret; 53662306a36Sopenharmony_ci} 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_cistatic void process_request_part(struct ssif_bmc_ctx *ssif_bmc) 53962306a36Sopenharmony_ci{ 54062306a36Sopenharmony_ci struct ssif_part_buffer *part = &ssif_bmc->part_buf; 54162306a36Sopenharmony_ci unsigned int len; 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci switch (part->smbus_cmd) { 54462306a36Sopenharmony_ci case SSIF_IPMI_SINGLEPART_WRITE: 54562306a36Sopenharmony_ci /* save the whole part to request*/ 54662306a36Sopenharmony_ci ssif_bmc->request.len = part->length; 54762306a36Sopenharmony_ci memcpy(ssif_bmc->request.payload, part->payload, part->length); 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci break; 55062306a36Sopenharmony_ci case SSIF_IPMI_MULTIPART_WRITE_START: 55162306a36Sopenharmony_ci ssif_bmc->request.len = 0; 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci fallthrough; 55462306a36Sopenharmony_ci case SSIF_IPMI_MULTIPART_WRITE_MIDDLE: 55562306a36Sopenharmony_ci case SSIF_IPMI_MULTIPART_WRITE_END: 55662306a36Sopenharmony_ci len = ssif_bmc->request.len + part->length; 55762306a36Sopenharmony_ci /* Do the bound check here, not allow the request len exceed 254 bytes */ 55862306a36Sopenharmony_ci if (len > IPMI_SSIF_PAYLOAD_MAX) { 55962306a36Sopenharmony_ci dev_warn(&ssif_bmc->client->dev, 56062306a36Sopenharmony_ci "Warn: Request exceeded 254 bytes, aborting"); 56162306a36Sopenharmony_ci /* Request too long, aborting */ 56262306a36Sopenharmony_ci ssif_bmc->aborting = true; 56362306a36Sopenharmony_ci } else { 56462306a36Sopenharmony_ci memcpy(ssif_bmc->request.payload + ssif_bmc->request.len, 56562306a36Sopenharmony_ci part->payload, part->length); 56662306a36Sopenharmony_ci ssif_bmc->request.len += part->length; 56762306a36Sopenharmony_ci } 56862306a36Sopenharmony_ci break; 56962306a36Sopenharmony_ci default: 57062306a36Sopenharmony_ci /* Do not expect to go to this case */ 57162306a36Sopenharmony_ci dev_err(&ssif_bmc->client->dev, "%s: Unexpected SMBus command 0x%x\n", 57262306a36Sopenharmony_ci __func__, part->smbus_cmd); 57362306a36Sopenharmony_ci break; 57462306a36Sopenharmony_ci } 57562306a36Sopenharmony_ci} 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_cistatic void process_smbus_cmd(struct ssif_bmc_ctx *ssif_bmc, u8 *val) 57862306a36Sopenharmony_ci{ 57962306a36Sopenharmony_ci /* SMBUS command can vary (single or multi-part) */ 58062306a36Sopenharmony_ci ssif_bmc->part_buf.smbus_cmd = *val; 58162306a36Sopenharmony_ci ssif_bmc->msg_idx = 1; 58262306a36Sopenharmony_ci memset(&ssif_bmc->part_buf.payload[0], 0, MAX_PAYLOAD_PER_TRANSACTION); 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci if (*val == SSIF_IPMI_SINGLEPART_WRITE || *val == SSIF_IPMI_MULTIPART_WRITE_START) { 58562306a36Sopenharmony_ci /* 58662306a36Sopenharmony_ci * The response maybe not come in-time, causing host SSIF driver 58762306a36Sopenharmony_ci * to timeout and resend a new request. In such case check for 58862306a36Sopenharmony_ci * pending response and clear it 58962306a36Sopenharmony_ci */ 59062306a36Sopenharmony_ci if (ssif_bmc->response_in_progress) 59162306a36Sopenharmony_ci complete_response(ssif_bmc); 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci /* This is new request, flip aborting flag if set */ 59462306a36Sopenharmony_ci if (ssif_bmc->aborting) 59562306a36Sopenharmony_ci ssif_bmc->aborting = false; 59662306a36Sopenharmony_ci } 59762306a36Sopenharmony_ci} 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_cistatic void on_read_requested_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) 60062306a36Sopenharmony_ci{ 60162306a36Sopenharmony_ci if (ssif_bmc->state == SSIF_READY || 60262306a36Sopenharmony_ci ssif_bmc->state == SSIF_START || 60362306a36Sopenharmony_ci ssif_bmc->state == SSIF_REQ_RECVING || 60462306a36Sopenharmony_ci ssif_bmc->state == SSIF_RES_SENDING) { 60562306a36Sopenharmony_ci dev_warn(&ssif_bmc->client->dev, 60662306a36Sopenharmony_ci "Warn: %s unexpected READ REQUESTED in state=%s\n", 60762306a36Sopenharmony_ci __func__, state_to_string(ssif_bmc->state)); 60862306a36Sopenharmony_ci ssif_bmc->state = SSIF_ABORTING; 60962306a36Sopenharmony_ci *val = 0; 61062306a36Sopenharmony_ci return; 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci } else if (ssif_bmc->state == SSIF_SMBUS_CMD) { 61362306a36Sopenharmony_ci if (!supported_read_cmd(ssif_bmc->part_buf.smbus_cmd)) { 61462306a36Sopenharmony_ci dev_warn(&ssif_bmc->client->dev, "Warn: Unknown SMBus read command=0x%x", 61562306a36Sopenharmony_ci ssif_bmc->part_buf.smbus_cmd); 61662306a36Sopenharmony_ci ssif_bmc->aborting = true; 61762306a36Sopenharmony_ci } 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci if (ssif_bmc->aborting) 62062306a36Sopenharmony_ci ssif_bmc->state = SSIF_ABORTING; 62162306a36Sopenharmony_ci else 62262306a36Sopenharmony_ci ssif_bmc->state = SSIF_RES_SENDING; 62362306a36Sopenharmony_ci } 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci ssif_bmc->msg_idx = 0; 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci /* Send 0 if there is nothing to send */ 62862306a36Sopenharmony_ci if (!ssif_bmc->response_in_progress || ssif_bmc->state == SSIF_ABORTING) { 62962306a36Sopenharmony_ci *val = 0; 63062306a36Sopenharmony_ci return; 63162306a36Sopenharmony_ci } 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci if (ssif_bmc->is_singlepart_read) 63462306a36Sopenharmony_ci set_singlepart_response_buffer(ssif_bmc); 63562306a36Sopenharmony_ci else 63662306a36Sopenharmony_ci set_multipart_response_buffer(ssif_bmc); 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci calculate_response_part_pec(&ssif_bmc->part_buf); 63962306a36Sopenharmony_ci ssif_bmc->part_buf.index = 0; 64062306a36Sopenharmony_ci *val = ssif_bmc->part_buf.length; 64162306a36Sopenharmony_ci} 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_cistatic void on_read_processed_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) 64462306a36Sopenharmony_ci{ 64562306a36Sopenharmony_ci if (ssif_bmc->state == SSIF_READY || 64662306a36Sopenharmony_ci ssif_bmc->state == SSIF_START || 64762306a36Sopenharmony_ci ssif_bmc->state == SSIF_REQ_RECVING || 64862306a36Sopenharmony_ci ssif_bmc->state == SSIF_SMBUS_CMD) { 64962306a36Sopenharmony_ci dev_warn(&ssif_bmc->client->dev, 65062306a36Sopenharmony_ci "Warn: %s unexpected READ PROCESSED in state=%s\n", 65162306a36Sopenharmony_ci __func__, state_to_string(ssif_bmc->state)); 65262306a36Sopenharmony_ci ssif_bmc->state = SSIF_ABORTING; 65362306a36Sopenharmony_ci *val = 0; 65462306a36Sopenharmony_ci return; 65562306a36Sopenharmony_ci } 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci /* Send 0 if there is nothing to send */ 65862306a36Sopenharmony_ci if (!ssif_bmc->response_in_progress || ssif_bmc->state == SSIF_ABORTING) { 65962306a36Sopenharmony_ci *val = 0; 66062306a36Sopenharmony_ci return; 66162306a36Sopenharmony_ci } 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci handle_read_processed(ssif_bmc, val); 66462306a36Sopenharmony_ci} 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_cistatic void on_write_requested_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) 66762306a36Sopenharmony_ci{ 66862306a36Sopenharmony_ci if (ssif_bmc->state == SSIF_READY || ssif_bmc->state == SSIF_SMBUS_CMD) { 66962306a36Sopenharmony_ci ssif_bmc->state = SSIF_START; 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci } else if (ssif_bmc->state == SSIF_START || 67262306a36Sopenharmony_ci ssif_bmc->state == SSIF_REQ_RECVING || 67362306a36Sopenharmony_ci ssif_bmc->state == SSIF_RES_SENDING) { 67462306a36Sopenharmony_ci dev_warn(&ssif_bmc->client->dev, 67562306a36Sopenharmony_ci "Warn: %s unexpected WRITE REQUEST in state=%s\n", 67662306a36Sopenharmony_ci __func__, state_to_string(ssif_bmc->state)); 67762306a36Sopenharmony_ci ssif_bmc->state = SSIF_ABORTING; 67862306a36Sopenharmony_ci return; 67962306a36Sopenharmony_ci } 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci ssif_bmc->msg_idx = 0; 68262306a36Sopenharmony_ci ssif_bmc->part_buf.address = *val; 68362306a36Sopenharmony_ci} 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_cistatic void on_write_received_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) 68662306a36Sopenharmony_ci{ 68762306a36Sopenharmony_ci if (ssif_bmc->state == SSIF_READY || 68862306a36Sopenharmony_ci ssif_bmc->state == SSIF_RES_SENDING) { 68962306a36Sopenharmony_ci dev_warn(&ssif_bmc->client->dev, 69062306a36Sopenharmony_ci "Warn: %s unexpected WRITE RECEIVED in state=%s\n", 69162306a36Sopenharmony_ci __func__, state_to_string(ssif_bmc->state)); 69262306a36Sopenharmony_ci ssif_bmc->state = SSIF_ABORTING; 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci } else if (ssif_bmc->state == SSIF_START) { 69562306a36Sopenharmony_ci ssif_bmc->state = SSIF_SMBUS_CMD; 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci } else if (ssif_bmc->state == SSIF_SMBUS_CMD) { 69862306a36Sopenharmony_ci if (!supported_write_cmd(ssif_bmc->part_buf.smbus_cmd)) { 69962306a36Sopenharmony_ci dev_warn(&ssif_bmc->client->dev, "Warn: Unknown SMBus write command=0x%x", 70062306a36Sopenharmony_ci ssif_bmc->part_buf.smbus_cmd); 70162306a36Sopenharmony_ci ssif_bmc->aborting = true; 70262306a36Sopenharmony_ci } 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci if (ssif_bmc->aborting) 70562306a36Sopenharmony_ci ssif_bmc->state = SSIF_ABORTING; 70662306a36Sopenharmony_ci else 70762306a36Sopenharmony_ci ssif_bmc->state = SSIF_REQ_RECVING; 70862306a36Sopenharmony_ci } 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci /* This is response sending state */ 71162306a36Sopenharmony_ci if (ssif_bmc->state == SSIF_REQ_RECVING) 71262306a36Sopenharmony_ci handle_write_received(ssif_bmc, val); 71362306a36Sopenharmony_ci else if (ssif_bmc->state == SSIF_SMBUS_CMD) 71462306a36Sopenharmony_ci process_smbus_cmd(ssif_bmc, val); 71562306a36Sopenharmony_ci} 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_cistatic void on_stop_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val) 71862306a36Sopenharmony_ci{ 71962306a36Sopenharmony_ci if (ssif_bmc->state == SSIF_READY || 72062306a36Sopenharmony_ci ssif_bmc->state == SSIF_START || 72162306a36Sopenharmony_ci ssif_bmc->state == SSIF_SMBUS_CMD || 72262306a36Sopenharmony_ci ssif_bmc->state == SSIF_ABORTING) { 72362306a36Sopenharmony_ci dev_warn(&ssif_bmc->client->dev, 72462306a36Sopenharmony_ci "Warn: %s unexpected SLAVE STOP in state=%s\n", 72562306a36Sopenharmony_ci __func__, state_to_string(ssif_bmc->state)); 72662306a36Sopenharmony_ci ssif_bmc->state = SSIF_READY; 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci } else if (ssif_bmc->state == SSIF_REQ_RECVING) { 72962306a36Sopenharmony_ci if (validate_request_part(ssif_bmc)) { 73062306a36Sopenharmony_ci process_request_part(ssif_bmc); 73162306a36Sopenharmony_ci if (ssif_bmc->part_buf.smbus_cmd == SSIF_IPMI_SINGLEPART_WRITE || 73262306a36Sopenharmony_ci ssif_bmc->part_buf.smbus_cmd == SSIF_IPMI_MULTIPART_WRITE_END) 73362306a36Sopenharmony_ci handle_request(ssif_bmc); 73462306a36Sopenharmony_ci ssif_bmc->state = SSIF_READY; 73562306a36Sopenharmony_ci } else { 73662306a36Sopenharmony_ci /* 73762306a36Sopenharmony_ci * A BMC that receives an invalid request drop the data for the write 73862306a36Sopenharmony_ci * transaction and any further transactions (read or write) until 73962306a36Sopenharmony_ci * the next valid read or write Start transaction is received 74062306a36Sopenharmony_ci */ 74162306a36Sopenharmony_ci dev_err(&ssif_bmc->client->dev, "Error: invalid pec\n"); 74262306a36Sopenharmony_ci ssif_bmc->aborting = true; 74362306a36Sopenharmony_ci } 74462306a36Sopenharmony_ci } else if (ssif_bmc->state == SSIF_RES_SENDING) { 74562306a36Sopenharmony_ci if (ssif_bmc->is_singlepart_read || ssif_bmc->block_num == 0xFF) 74662306a36Sopenharmony_ci /* Invalidate response buffer to denote it is sent */ 74762306a36Sopenharmony_ci complete_response(ssif_bmc); 74862306a36Sopenharmony_ci ssif_bmc->state = SSIF_READY; 74962306a36Sopenharmony_ci } 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci /* Reset message index */ 75262306a36Sopenharmony_ci ssif_bmc->msg_idx = 0; 75362306a36Sopenharmony_ci} 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci/* 75662306a36Sopenharmony_ci * Callback function to handle I2C slave events 75762306a36Sopenharmony_ci */ 75862306a36Sopenharmony_cistatic int ssif_bmc_cb(struct i2c_client *client, enum i2c_slave_event event, u8 *val) 75962306a36Sopenharmony_ci{ 76062306a36Sopenharmony_ci unsigned long flags; 76162306a36Sopenharmony_ci struct ssif_bmc_ctx *ssif_bmc = i2c_get_clientdata(client); 76262306a36Sopenharmony_ci int ret = 0; 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci spin_lock_irqsave(&ssif_bmc->lock, flags); 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci switch (event) { 76762306a36Sopenharmony_ci case I2C_SLAVE_READ_REQUESTED: 76862306a36Sopenharmony_ci on_read_requested_event(ssif_bmc, val); 76962306a36Sopenharmony_ci break; 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci case I2C_SLAVE_WRITE_REQUESTED: 77262306a36Sopenharmony_ci on_write_requested_event(ssif_bmc, val); 77362306a36Sopenharmony_ci break; 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci case I2C_SLAVE_READ_PROCESSED: 77662306a36Sopenharmony_ci on_read_processed_event(ssif_bmc, val); 77762306a36Sopenharmony_ci break; 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci case I2C_SLAVE_WRITE_RECEIVED: 78062306a36Sopenharmony_ci on_write_received_event(ssif_bmc, val); 78162306a36Sopenharmony_ci break; 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci case I2C_SLAVE_STOP: 78462306a36Sopenharmony_ci on_stop_event(ssif_bmc, val); 78562306a36Sopenharmony_ci break; 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci default: 78862306a36Sopenharmony_ci dev_warn(&ssif_bmc->client->dev, "Warn: Unknown i2c slave event\n"); 78962306a36Sopenharmony_ci break; 79062306a36Sopenharmony_ci } 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci if (!ssif_bmc->aborting && ssif_bmc->busy) 79362306a36Sopenharmony_ci ret = -EBUSY; 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci spin_unlock_irqrestore(&ssif_bmc->lock, flags); 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci return ret; 79862306a36Sopenharmony_ci} 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_cistatic int ssif_bmc_probe(struct i2c_client *client) 80162306a36Sopenharmony_ci{ 80262306a36Sopenharmony_ci struct ssif_bmc_ctx *ssif_bmc; 80362306a36Sopenharmony_ci int ret; 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci ssif_bmc = devm_kzalloc(&client->dev, sizeof(*ssif_bmc), GFP_KERNEL); 80662306a36Sopenharmony_ci if (!ssif_bmc) 80762306a36Sopenharmony_ci return -ENOMEM; 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci spin_lock_init(&ssif_bmc->lock); 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci init_waitqueue_head(&ssif_bmc->wait_queue); 81262306a36Sopenharmony_ci ssif_bmc->request_available = false; 81362306a36Sopenharmony_ci ssif_bmc->response_in_progress = false; 81462306a36Sopenharmony_ci ssif_bmc->busy = false; 81562306a36Sopenharmony_ci ssif_bmc->response_timer_inited = false; 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci /* Register misc device interface */ 81862306a36Sopenharmony_ci ssif_bmc->miscdev.minor = MISC_DYNAMIC_MINOR; 81962306a36Sopenharmony_ci ssif_bmc->miscdev.name = DEVICE_NAME; 82062306a36Sopenharmony_ci ssif_bmc->miscdev.fops = &ssif_bmc_fops; 82162306a36Sopenharmony_ci ssif_bmc->miscdev.parent = &client->dev; 82262306a36Sopenharmony_ci ret = misc_register(&ssif_bmc->miscdev); 82362306a36Sopenharmony_ci if (ret) 82462306a36Sopenharmony_ci return ret; 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci ssif_bmc->client = client; 82762306a36Sopenharmony_ci ssif_bmc->client->flags |= I2C_CLIENT_SLAVE; 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci /* Register I2C slave */ 83062306a36Sopenharmony_ci i2c_set_clientdata(client, ssif_bmc); 83162306a36Sopenharmony_ci ret = i2c_slave_register(client, ssif_bmc_cb); 83262306a36Sopenharmony_ci if (ret) 83362306a36Sopenharmony_ci misc_deregister(&ssif_bmc->miscdev); 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci return ret; 83662306a36Sopenharmony_ci} 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_cistatic void ssif_bmc_remove(struct i2c_client *client) 83962306a36Sopenharmony_ci{ 84062306a36Sopenharmony_ci struct ssif_bmc_ctx *ssif_bmc = i2c_get_clientdata(client); 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci i2c_slave_unregister(client); 84362306a36Sopenharmony_ci misc_deregister(&ssif_bmc->miscdev); 84462306a36Sopenharmony_ci} 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_cistatic const struct of_device_id ssif_bmc_match[] = { 84762306a36Sopenharmony_ci { .compatible = "ssif-bmc" }, 84862306a36Sopenharmony_ci { }, 84962306a36Sopenharmony_ci}; 85062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, ssif_bmc_match); 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_cistatic const struct i2c_device_id ssif_bmc_id[] = { 85362306a36Sopenharmony_ci { DEVICE_NAME, 0 }, 85462306a36Sopenharmony_ci { }, 85562306a36Sopenharmony_ci}; 85662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, ssif_bmc_id); 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_cistatic struct i2c_driver ssif_bmc_driver = { 85962306a36Sopenharmony_ci .driver = { 86062306a36Sopenharmony_ci .name = DEVICE_NAME, 86162306a36Sopenharmony_ci .of_match_table = ssif_bmc_match, 86262306a36Sopenharmony_ci }, 86362306a36Sopenharmony_ci .probe = ssif_bmc_probe, 86462306a36Sopenharmony_ci .remove = ssif_bmc_remove, 86562306a36Sopenharmony_ci .id_table = ssif_bmc_id, 86662306a36Sopenharmony_ci}; 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_cimodule_i2c_driver(ssif_bmc_driver); 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ciMODULE_AUTHOR("Quan Nguyen <quan@os.amperecomputing.com>"); 87162306a36Sopenharmony_ciMODULE_AUTHOR("Chuong Tran <chuong@os.amperecomputing.com>"); 87262306a36Sopenharmony_ciMODULE_DESCRIPTION("Linux device driver of the BMC IPMI SSIF interface."); 87362306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 874