|
|
|
|
@ -18,6 +18,9 @@
|
|
|
|
|
#include <linux/timer.h>
|
|
|
|
|
#include <linux/jiffies.h>
|
|
|
|
|
#include <linux/ipmi_ssif_bmc.h>
|
|
|
|
|
#if IS_ENABLED(CONFIG_SSIF_IPMI_BMC_KUNIT_TEST)
|
|
|
|
|
#include <kunit/test.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#define DEVICE_NAME "ipmi-ssif-host"
|
|
|
|
|
|
|
|
|
|
@ -163,6 +166,8 @@ static ssize_t ssif_bmc_read(struct file *file, char __user *buf, size_t count,
|
|
|
|
|
spin_unlock_irqrestore(&ssif_bmc->lock, flags);
|
|
|
|
|
|
|
|
|
|
ret = copy_to_user(buf, &msg, count);
|
|
|
|
|
if (ret > 0)
|
|
|
|
|
ret = -EFAULT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (ret < 0) ? ret : count;
|
|
|
|
|
@ -456,6 +461,15 @@ static bool supported_write_cmd(u8 cmd)
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool supported_write_start_cmd(u8 cmd)
|
|
|
|
|
{
|
|
|
|
|
if (cmd == SSIF_IPMI_SINGLEPART_WRITE ||
|
|
|
|
|
cmd == SSIF_IPMI_MULTIPART_WRITE_START)
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Process the IPMI response that will be read by master */
|
|
|
|
|
static void handle_read_processed(struct ssif_bmc_ctx *ssif_bmc, u8 *val)
|
|
|
|
|
{
|
|
|
|
|
@ -558,7 +572,7 @@ static void process_request_part(struct ssif_bmc_ctx *ssif_bmc)
|
|
|
|
|
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,
|
|
|
|
|
dev_dbg(&ssif_bmc->client->dev,
|
|
|
|
|
"Warn: Request exceeded 254 bytes, aborting");
|
|
|
|
|
/* Request too long, aborting */
|
|
|
|
|
ssif_bmc->aborting = true;
|
|
|
|
|
@ -604,7 +618,7 @@ static void on_read_requested_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val)
|
|
|
|
|
ssif_bmc->state == SSIF_START ||
|
|
|
|
|
ssif_bmc->state == SSIF_REQ_RECVING ||
|
|
|
|
|
ssif_bmc->state == SSIF_RES_SENDING) {
|
|
|
|
|
dev_warn(&ssif_bmc->client->dev,
|
|
|
|
|
dev_dbg(&ssif_bmc->client->dev,
|
|
|
|
|
"Warn: %s unexpected READ REQUESTED in state=%s\n",
|
|
|
|
|
__func__, state_to_string(ssif_bmc->state));
|
|
|
|
|
ssif_bmc->state = SSIF_ABORTING;
|
|
|
|
|
@ -613,7 +627,7 @@ static void on_read_requested_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val)
|
|
|
|
|
|
|
|
|
|
} else if (ssif_bmc->state == SSIF_SMBUS_CMD) {
|
|
|
|
|
if (!supported_read_cmd(ssif_bmc->part_buf.smbus_cmd)) {
|
|
|
|
|
dev_warn(&ssif_bmc->client->dev, "Warn: Unknown SMBus read command=0x%x",
|
|
|
|
|
dev_dbg(&ssif_bmc->client->dev, "Warn: Unknown SMBus read command=0x%x",
|
|
|
|
|
ssif_bmc->part_buf.smbus_cmd);
|
|
|
|
|
ssif_bmc->aborting = true;
|
|
|
|
|
}
|
|
|
|
|
@ -648,7 +662,7 @@ static void on_read_processed_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val)
|
|
|
|
|
ssif_bmc->state == SSIF_START ||
|
|
|
|
|
ssif_bmc->state == SSIF_REQ_RECVING ||
|
|
|
|
|
ssif_bmc->state == SSIF_SMBUS_CMD) {
|
|
|
|
|
dev_warn(&ssif_bmc->client->dev,
|
|
|
|
|
dev_dbg(&ssif_bmc->client->dev,
|
|
|
|
|
"Warn: %s unexpected READ PROCESSED in state=%s\n",
|
|
|
|
|
__func__, state_to_string(ssif_bmc->state));
|
|
|
|
|
ssif_bmc->state = SSIF_ABORTING;
|
|
|
|
|
@ -673,7 +687,7 @@ static void on_write_requested_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val)
|
|
|
|
|
} else if (ssif_bmc->state == SSIF_START ||
|
|
|
|
|
ssif_bmc->state == SSIF_REQ_RECVING ||
|
|
|
|
|
ssif_bmc->state == SSIF_RES_SENDING) {
|
|
|
|
|
dev_warn(&ssif_bmc->client->dev,
|
|
|
|
|
dev_dbg(&ssif_bmc->client->dev,
|
|
|
|
|
"Warn: %s unexpected WRITE REQUEST in state=%s\n",
|
|
|
|
|
__func__, state_to_string(ssif_bmc->state));
|
|
|
|
|
ssif_bmc->state = SSIF_ABORTING;
|
|
|
|
|
@ -688,7 +702,7 @@ static void on_write_received_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val)
|
|
|
|
|
{
|
|
|
|
|
if (ssif_bmc->state == SSIF_READY ||
|
|
|
|
|
ssif_bmc->state == SSIF_RES_SENDING) {
|
|
|
|
|
dev_warn(&ssif_bmc->client->dev,
|
|
|
|
|
dev_dbg(&ssif_bmc->client->dev,
|
|
|
|
|
"Warn: %s unexpected WRITE RECEIVED in state=%s\n",
|
|
|
|
|
__func__, state_to_string(ssif_bmc->state));
|
|
|
|
|
ssif_bmc->state = SSIF_ABORTING;
|
|
|
|
|
@ -698,7 +712,7 @@ static void on_write_received_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val)
|
|
|
|
|
|
|
|
|
|
} else if (ssif_bmc->state == SSIF_SMBUS_CMD) {
|
|
|
|
|
if (!supported_write_cmd(ssif_bmc->part_buf.smbus_cmd)) {
|
|
|
|
|
dev_warn(&ssif_bmc->client->dev, "Warn: Unknown SMBus write command=0x%x",
|
|
|
|
|
dev_dbg(&ssif_bmc->client->dev, "Warn: Unknown SMBus write command=0x%x",
|
|
|
|
|
ssif_bmc->part_buf.smbus_cmd);
|
|
|
|
|
ssif_bmc->aborting = true;
|
|
|
|
|
}
|
|
|
|
|
@ -707,6 +721,11 @@ static void on_write_received_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val)
|
|
|
|
|
ssif_bmc->state = SSIF_ABORTING;
|
|
|
|
|
else
|
|
|
|
|
ssif_bmc->state = SSIF_REQ_RECVING;
|
|
|
|
|
} else if (ssif_bmc->state == SSIF_ABORTING) {
|
|
|
|
|
if (supported_write_start_cmd(*val)) {
|
|
|
|
|
ssif_bmc->state = SSIF_SMBUS_CMD;
|
|
|
|
|
ssif_bmc->aborting = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* This is response sending state */
|
|
|
|
|
@ -722,7 +741,7 @@ static void on_stop_event(struct ssif_bmc_ctx *ssif_bmc, u8 *val)
|
|
|
|
|
ssif_bmc->state == SSIF_START ||
|
|
|
|
|
ssif_bmc->state == SSIF_SMBUS_CMD ||
|
|
|
|
|
ssif_bmc->state == SSIF_ABORTING) {
|
|
|
|
|
dev_warn(&ssif_bmc->client->dev,
|
|
|
|
|
dev_dbg(&ssif_bmc->client->dev,
|
|
|
|
|
"Warn: %s unexpected SLAVE STOP in state=%s\n",
|
|
|
|
|
__func__, state_to_string(ssif_bmc->state));
|
|
|
|
|
ssif_bmc->state = SSIF_READY;
|
|
|
|
|
@ -789,7 +808,7 @@ static int ssif_bmc_cb(struct i2c_client *client, enum i2c_slave_event event, u8
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
dev_warn(&ssif_bmc->client->dev, "Warn: Unknown i2c slave event\n");
|
|
|
|
|
dev_dbg(&ssif_bmc->client->dev, "Warn: Unknown i2c slave event\n");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -843,6 +862,7 @@ static void ssif_bmc_remove(struct i2c_client *client)
|
|
|
|
|
{
|
|
|
|
|
struct ssif_bmc_ctx *ssif_bmc = i2c_get_clientdata(client);
|
|
|
|
|
|
|
|
|
|
timer_delete_sync(&ssif_bmc->response_timer);
|
|
|
|
|
i2c_slave_unregister(client);
|
|
|
|
|
misc_deregister(&ssif_bmc->miscdev);
|
|
|
|
|
}
|
|
|
|
|
@ -869,6 +889,373 @@ static struct i2c_driver ssif_bmc_driver = {
|
|
|
|
|
.id_table = ssif_bmc_id,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#if IS_ENABLED(CONFIG_SSIF_IPMI_BMC_KUNIT_TEST)
|
|
|
|
|
struct ssif_bmc_test_ctx {
|
|
|
|
|
struct ssif_bmc_ctx ssif_bmc;
|
|
|
|
|
struct i2c_client client;
|
|
|
|
|
struct i2c_adapter adapter;
|
|
|
|
|
struct i2c_algorithm algo;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static int ssif_bmc_test_init(struct kunit *test)
|
|
|
|
|
{
|
|
|
|
|
struct ssif_bmc_test_ctx *test_ctx;
|
|
|
|
|
|
|
|
|
|
test_ctx = kunit_kzalloc(test, sizeof(*test_ctx), GFP_KERNEL);
|
|
|
|
|
if (!test_ctx)
|
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
|
|
test_ctx->adapter.algo = &test_ctx->algo;
|
|
|
|
|
test_ctx->client.addr = 0x20;
|
|
|
|
|
test_ctx->client.adapter = &test_ctx->adapter;
|
|
|
|
|
|
|
|
|
|
spin_lock_init(&test_ctx->ssif_bmc.lock);
|
|
|
|
|
init_waitqueue_head(&test_ctx->ssif_bmc.wait_queue);
|
|
|
|
|
test_ctx->ssif_bmc.client = &test_ctx->client;
|
|
|
|
|
i2c_set_clientdata(&test_ctx->client, &test_ctx->ssif_bmc);
|
|
|
|
|
|
|
|
|
|
test->priv = test_ctx;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void ssif_bmc_test_exit(struct kunit *test)
|
|
|
|
|
{
|
|
|
|
|
struct ssif_bmc_test_ctx *test_ctx = test->priv;
|
|
|
|
|
|
|
|
|
|
if (test_ctx->ssif_bmc.response_timer_inited)
|
|
|
|
|
timer_delete_sync(&test_ctx->ssif_bmc.response_timer);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int ssif_bmc_test_run_event_val(struct ssif_bmc_test_ctx *test_ctx,
|
|
|
|
|
enum i2c_slave_event event,
|
|
|
|
|
u8 *value)
|
|
|
|
|
{
|
|
|
|
|
return ssif_bmc_cb(&test_ctx->client, event, value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int ssif_bmc_test_run_event(struct ssif_bmc_test_ctx *test_ctx,
|
|
|
|
|
enum i2c_slave_event event, u8 value)
|
|
|
|
|
{
|
|
|
|
|
return ssif_bmc_test_run_event_val(test_ctx, event, &value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void ssif_bmc_test_singlepart_req(struct kunit *test)
|
|
|
|
|
{
|
|
|
|
|
struct ssif_bmc_test_ctx *test_ctx = test->priv;
|
|
|
|
|
struct ssif_bmc_ctx *ssif_bmc = &test_ctx->ssif_bmc;
|
|
|
|
|
|
|
|
|
|
ssif_bmc_test_run_event(test_ctx, I2C_SLAVE_WRITE_REQUESTED,
|
|
|
|
|
GET_8BIT_ADDR(test_ctx->client.addr));
|
|
|
|
|
ssif_bmc_test_run_event(test_ctx, I2C_SLAVE_WRITE_RECEIVED,
|
|
|
|
|
SSIF_IPMI_SINGLEPART_WRITE);
|
|
|
|
|
ssif_bmc_test_run_event(test_ctx, I2C_SLAVE_WRITE_RECEIVED, 2);
|
|
|
|
|
|
|
|
|
|
ssif_bmc_test_run_event(test_ctx, I2C_SLAVE_WRITE_RECEIVED, 0xaa);
|
|
|
|
|
|
|
|
|
|
ssif_bmc_test_run_event(test_ctx, I2C_SLAVE_WRITE_RECEIVED, 0x55);
|
|
|
|
|
KUNIT_EXPECT_EQ(test,
|
|
|
|
|
ssif_bmc_test_run_event(test_ctx, I2C_SLAVE_STOP, 0), -EBUSY);
|
|
|
|
|
|
|
|
|
|
KUNIT_EXPECT_EQ(test, ssif_bmc->state, SSIF_READY);
|
|
|
|
|
KUNIT_EXPECT_TRUE(test, ssif_bmc->request_available);
|
|
|
|
|
KUNIT_EXPECT_TRUE(test, ssif_bmc->busy);
|
|
|
|
|
KUNIT_EXPECT_FALSE(test, ssif_bmc->aborting);
|
|
|
|
|
KUNIT_EXPECT_EQ(test, ssif_bmc->request.len, 2);
|
|
|
|
|
KUNIT_EXPECT_EQ(test, ssif_bmc->request.payload[0], 0xaa);
|
|
|
|
|
KUNIT_EXPECT_EQ(test, ssif_bmc->request.payload[1], 0x55);
|
|
|
|
|
KUNIT_EXPECT_TRUE(test, ssif_bmc->response_timer_inited);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void ssif_bmc_test_restart_write_without_stop(struct kunit *test)
|
|
|
|
|
{
|
|
|
|
|
struct ssif_bmc_test_ctx *test_ctx = test->priv;
|
|
|
|
|
struct ssif_bmc_ctx *ssif_bmc = &test_ctx->ssif_bmc;
|
|
|
|
|
|
|
|
|
|
KUNIT_ASSERT_EQ(test,
|
|
|
|
|
ssif_bmc_test_run_event(test_ctx, I2C_SLAVE_WRITE_REQUESTED,
|
|
|
|
|
GET_8BIT_ADDR(test_ctx->client.addr)), 0);
|
|
|
|
|
KUNIT_ASSERT_EQ(test,
|
|
|
|
|
ssif_bmc_test_run_event(test_ctx, I2C_SLAVE_WRITE_RECEIVED,
|
|
|
|
|
SSIF_IPMI_SINGLEPART_WRITE), 0);
|
|
|
|
|
KUNIT_ASSERT_EQ(test,
|
|
|
|
|
ssif_bmc_test_run_event(test_ctx, I2C_SLAVE_WRITE_RECEIVED, 2), 0);
|
|
|
|
|
KUNIT_ASSERT_EQ(test,
|
|
|
|
|
ssif_bmc_test_run_event(test_ctx, I2C_SLAVE_WRITE_RECEIVED, 0xde), 0);
|
|
|
|
|
|
|
|
|
|
KUNIT_EXPECT_EQ(test, ssif_bmc->state, SSIF_REQ_RECVING);
|
|
|
|
|
|
|
|
|
|
/* Write transaction, without stop, and new request coming */
|
|
|
|
|
ssif_bmc_test_singlepart_req(test);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void ssif_bmc_test_restart_after_invalid_command(struct kunit *test)
|
|
|
|
|
{
|
|
|
|
|
struct ssif_bmc_test_ctx *test_ctx = test->priv;
|
|
|
|
|
struct ssif_bmc_ctx *ssif_bmc = &test_ctx->ssif_bmc;
|
|
|
|
|
|
|
|
|
|
KUNIT_ASSERT_EQ(test,
|
|
|
|
|
ssif_bmc_test_run_event(test_ctx, I2C_SLAVE_WRITE_REQUESTED,
|
|
|
|
|
GET_8BIT_ADDR(test_ctx->client.addr)), 0);
|
|
|
|
|
KUNIT_ASSERT_EQ(test,
|
|
|
|
|
ssif_bmc_test_run_event(test_ctx, I2C_SLAVE_WRITE_RECEIVED, 0xff), 0);
|
|
|
|
|
KUNIT_ASSERT_EQ(test,
|
|
|
|
|
ssif_bmc_test_run_event(test_ctx, I2C_SLAVE_WRITE_RECEIVED, 1), 0);
|
|
|
|
|
|
|
|
|
|
KUNIT_EXPECT_EQ(test, ssif_bmc->state, SSIF_ABORTING);
|
|
|
|
|
KUNIT_EXPECT_TRUE(test, ssif_bmc->aborting);
|
|
|
|
|
|
|
|
|
|
/* After An Invalid Command, expect could handle new request */
|
|
|
|
|
ssif_bmc_test_singlepart_req(test);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void ssif_bmc_test_singlepart_read_response_completion(struct kunit *test)
|
|
|
|
|
{
|
|
|
|
|
struct ssif_bmc_test_ctx *test_ctx = test->priv;
|
|
|
|
|
struct ssif_bmc_ctx *ssif_bmc = &test_ctx->ssif_bmc;
|
|
|
|
|
u8 value;
|
|
|
|
|
|
|
|
|
|
ssif_bmc->state = SSIF_SMBUS_CMD;
|
|
|
|
|
ssif_bmc->part_buf.smbus_cmd = SSIF_IPMI_SINGLEPART_READ;
|
|
|
|
|
ssif_bmc->response.len = 2;
|
|
|
|
|
ssif_bmc->response.payload[0] = 0x11;
|
|
|
|
|
ssif_bmc->response.payload[1] = 0x22;
|
|
|
|
|
ssif_bmc->response_in_progress = true;
|
|
|
|
|
ssif_bmc->is_singlepart_read = true;
|
|
|
|
|
ssif_bmc->pec_support = true;
|
|
|
|
|
|
|
|
|
|
value = 0;
|
|
|
|
|
KUNIT_ASSERT_EQ(test,
|
|
|
|
|
ssif_bmc_test_run_event_val(test_ctx, I2C_SLAVE_READ_REQUESTED,
|
|
|
|
|
&value), 0);
|
|
|
|
|
KUNIT_EXPECT_EQ(test, value, 2);
|
|
|
|
|
KUNIT_EXPECT_EQ(test, ssif_bmc->state, SSIF_RES_SENDING);
|
|
|
|
|
|
|
|
|
|
value = 0;
|
|
|
|
|
KUNIT_EXPECT_EQ(test,
|
|
|
|
|
ssif_bmc_test_run_event_val(test_ctx, I2C_SLAVE_READ_PROCESSED,
|
|
|
|
|
&value), 0);
|
|
|
|
|
KUNIT_EXPECT_EQ(test, value, 0x11);
|
|
|
|
|
|
|
|
|
|
value = 0;
|
|
|
|
|
KUNIT_EXPECT_EQ(test,
|
|
|
|
|
ssif_bmc_test_run_event_val(test_ctx, I2C_SLAVE_READ_PROCESSED,
|
|
|
|
|
&value), 0);
|
|
|
|
|
KUNIT_EXPECT_EQ(test, value, 0x22);
|
|
|
|
|
|
|
|
|
|
value = 0;
|
|
|
|
|
KUNIT_EXPECT_EQ(test,
|
|
|
|
|
ssif_bmc_test_run_event_val(test_ctx, I2C_SLAVE_READ_PROCESSED,
|
|
|
|
|
&value), 0);
|
|
|
|
|
KUNIT_EXPECT_EQ(test, value, ssif_bmc->part_buf.pec);
|
|
|
|
|
|
|
|
|
|
KUNIT_EXPECT_EQ(test,
|
|
|
|
|
ssif_bmc_test_run_event(test_ctx, I2C_SLAVE_STOP, 0), 0);
|
|
|
|
|
KUNIT_EXPECT_EQ(test, ssif_bmc->state, SSIF_READY);
|
|
|
|
|
KUNIT_EXPECT_FALSE(test, ssif_bmc->response_in_progress);
|
|
|
|
|
KUNIT_EXPECT_EQ(test, ssif_bmc->response.len, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void ssif_bmc_test_stop_during_start_discards_partial_request(struct kunit *test)
|
|
|
|
|
{
|
|
|
|
|
struct ssif_bmc_test_ctx *test_ctx = test->priv;
|
|
|
|
|
struct ssif_bmc_ctx *ssif_bmc = &test_ctx->ssif_bmc;
|
|
|
|
|
|
|
|
|
|
KUNIT_ASSERT_EQ(test,
|
|
|
|
|
ssif_bmc_test_run_event(test_ctx, I2C_SLAVE_WRITE_REQUESTED,
|
|
|
|
|
GET_8BIT_ADDR(test_ctx->client.addr)), 0);
|
|
|
|
|
KUNIT_EXPECT_EQ(test, ssif_bmc->state, SSIF_START);
|
|
|
|
|
|
|
|
|
|
KUNIT_EXPECT_EQ(test,
|
|
|
|
|
ssif_bmc_test_run_event(test_ctx, I2C_SLAVE_STOP, 0), 0);
|
|
|
|
|
KUNIT_EXPECT_EQ(test, ssif_bmc->state, SSIF_READY);
|
|
|
|
|
KUNIT_EXPECT_FALSE(test, ssif_bmc->request_available);
|
|
|
|
|
KUNIT_EXPECT_EQ(test, ssif_bmc->msg_idx, 0);
|
|
|
|
|
|
|
|
|
|
KUNIT_EXPECT_EQ(test,
|
|
|
|
|
ssif_bmc_test_run_event(test_ctx, I2C_SLAVE_WRITE_REQUESTED,
|
|
|
|
|
GET_8BIT_ADDR(test_ctx->client.addr)), 0);
|
|
|
|
|
KUNIT_EXPECT_EQ(test,
|
|
|
|
|
ssif_bmc_test_run_event(test_ctx, I2C_SLAVE_WRITE_RECEIVED,
|
|
|
|
|
SSIF_IPMI_SINGLEPART_WRITE), 0);
|
|
|
|
|
KUNIT_EXPECT_EQ(test,
|
|
|
|
|
ssif_bmc_test_run_event(test_ctx, I2C_SLAVE_WRITE_RECEIVED, 1), 0);
|
|
|
|
|
KUNIT_EXPECT_EQ(test,
|
|
|
|
|
ssif_bmc_test_run_event(test_ctx, I2C_SLAVE_WRITE_RECEIVED, 0x77), 0);
|
|
|
|
|
KUNIT_EXPECT_EQ(test,
|
|
|
|
|
ssif_bmc_test_run_event(test_ctx, I2C_SLAVE_STOP, 0), -EBUSY);
|
|
|
|
|
|
|
|
|
|
KUNIT_EXPECT_TRUE(test, ssif_bmc->request_available);
|
|
|
|
|
KUNIT_EXPECT_EQ(test, ssif_bmc->request.len, 1);
|
|
|
|
|
KUNIT_EXPECT_EQ(test, ssif_bmc->request.payload[0], 0x77);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void ssif_bmc_test_read_interrupts_partial_write(struct kunit *test)
|
|
|
|
|
{
|
|
|
|
|
struct ssif_bmc_test_ctx *test_ctx = test->priv;
|
|
|
|
|
struct ssif_bmc_ctx *ssif_bmc = &test_ctx->ssif_bmc;
|
|
|
|
|
u8 value = 0xff;
|
|
|
|
|
|
|
|
|
|
KUNIT_ASSERT_EQ(test,
|
|
|
|
|
ssif_bmc_test_run_event(test_ctx, I2C_SLAVE_WRITE_REQUESTED,
|
|
|
|
|
GET_8BIT_ADDR(test_ctx->client.addr)), 0);
|
|
|
|
|
KUNIT_ASSERT_EQ(test,
|
|
|
|
|
ssif_bmc_test_run_event(test_ctx, I2C_SLAVE_WRITE_RECEIVED,
|
|
|
|
|
SSIF_IPMI_SINGLEPART_WRITE), 0);
|
|
|
|
|
KUNIT_ASSERT_EQ(test,
|
|
|
|
|
ssif_bmc_test_run_event(test_ctx, I2C_SLAVE_WRITE_RECEIVED, 2), 0);
|
|
|
|
|
KUNIT_ASSERT_EQ(test,
|
|
|
|
|
ssif_bmc_test_run_event(test_ctx, I2C_SLAVE_WRITE_RECEIVED, 0xab), 0);
|
|
|
|
|
|
|
|
|
|
KUNIT_EXPECT_EQ(test, ssif_bmc->state, SSIF_REQ_RECVING);
|
|
|
|
|
KUNIT_EXPECT_EQ(test,
|
|
|
|
|
ssif_bmc_test_run_event_val(test_ctx, I2C_SLAVE_READ_REQUESTED,
|
|
|
|
|
&value), 0);
|
|
|
|
|
KUNIT_EXPECT_EQ(test, value, 0);
|
|
|
|
|
KUNIT_EXPECT_EQ(test, ssif_bmc->state, SSIF_ABORTING);
|
|
|
|
|
|
|
|
|
|
KUNIT_EXPECT_EQ(test,
|
|
|
|
|
ssif_bmc_test_run_event(test_ctx, I2C_SLAVE_STOP, 0), 0);
|
|
|
|
|
KUNIT_EXPECT_EQ(test, ssif_bmc->state, SSIF_READY);
|
|
|
|
|
KUNIT_EXPECT_FALSE(test, ssif_bmc->request_available);
|
|
|
|
|
KUNIT_EXPECT_EQ(test, ssif_bmc->request.len, 0);
|
|
|
|
|
|
|
|
|
|
KUNIT_EXPECT_EQ(test,
|
|
|
|
|
ssif_bmc_test_run_event(test_ctx, I2C_SLAVE_WRITE_REQUESTED,
|
|
|
|
|
GET_8BIT_ADDR(test_ctx->client.addr)), 0);
|
|
|
|
|
KUNIT_EXPECT_EQ(test,
|
|
|
|
|
ssif_bmc_test_run_event(test_ctx, I2C_SLAVE_WRITE_RECEIVED,
|
|
|
|
|
SSIF_IPMI_SINGLEPART_WRITE), 0);
|
|
|
|
|
KUNIT_EXPECT_EQ(test,
|
|
|
|
|
ssif_bmc_test_run_event(test_ctx, I2C_SLAVE_WRITE_RECEIVED, 1), 0);
|
|
|
|
|
KUNIT_EXPECT_EQ(test,
|
|
|
|
|
ssif_bmc_test_run_event(test_ctx, I2C_SLAVE_WRITE_RECEIVED, 0xcd), 0);
|
|
|
|
|
KUNIT_EXPECT_EQ(test,
|
|
|
|
|
ssif_bmc_test_run_event(test_ctx, I2C_SLAVE_STOP, 0), -EBUSY);
|
|
|
|
|
|
|
|
|
|
KUNIT_EXPECT_TRUE(test, ssif_bmc->request_available);
|
|
|
|
|
KUNIT_EXPECT_EQ(test, ssif_bmc->request.len, 1);
|
|
|
|
|
KUNIT_EXPECT_EQ(test, ssif_bmc->request.payload[0], 0xcd);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void ssif_bmc_test_write_interrupts_response_send(struct kunit *test)
|
|
|
|
|
{
|
|
|
|
|
struct ssif_bmc_test_ctx *test_ctx = test->priv;
|
|
|
|
|
struct ssif_bmc_ctx *ssif_bmc = &test_ctx->ssif_bmc;
|
|
|
|
|
u8 value = 0;
|
|
|
|
|
|
|
|
|
|
ssif_bmc->state = SSIF_SMBUS_CMD;
|
|
|
|
|
ssif_bmc->part_buf.smbus_cmd = SSIF_IPMI_SINGLEPART_READ;
|
|
|
|
|
ssif_bmc->response.len = 1;
|
|
|
|
|
ssif_bmc->response.payload[0] = 0x66;
|
|
|
|
|
ssif_bmc->response_in_progress = true;
|
|
|
|
|
ssif_bmc->is_singlepart_read = true;
|
|
|
|
|
|
|
|
|
|
KUNIT_ASSERT_EQ(test,
|
|
|
|
|
ssif_bmc_test_run_event_val(test_ctx, I2C_SLAVE_READ_REQUESTED,
|
|
|
|
|
&value), 0);
|
|
|
|
|
KUNIT_EXPECT_EQ(test, ssif_bmc->state, SSIF_RES_SENDING);
|
|
|
|
|
|
|
|
|
|
/* READ_REQUESTED transaction */
|
|
|
|
|
ssif_bmc_test_singlepart_req(test);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void ssif_bmc_test_write_interrupts_response_sending(struct kunit *test)
|
|
|
|
|
{
|
|
|
|
|
struct ssif_bmc_test_ctx *test_ctx = test->priv;
|
|
|
|
|
struct ssif_bmc_ctx *ssif_bmc = &test_ctx->ssif_bmc;
|
|
|
|
|
u8 value = 0;
|
|
|
|
|
|
|
|
|
|
ssif_bmc->state = SSIF_SMBUS_CMD;
|
|
|
|
|
ssif_bmc->part_buf.smbus_cmd = SSIF_IPMI_SINGLEPART_READ;
|
|
|
|
|
ssif_bmc->response.len = 1;
|
|
|
|
|
ssif_bmc->response.payload[0] = 0x66;
|
|
|
|
|
ssif_bmc->response_in_progress = true;
|
|
|
|
|
ssif_bmc->is_singlepart_read = true;
|
|
|
|
|
|
|
|
|
|
KUNIT_ASSERT_EQ(test,
|
|
|
|
|
ssif_bmc_test_run_event_val(test_ctx, I2C_SLAVE_READ_REQUESTED,
|
|
|
|
|
&value), 0);
|
|
|
|
|
KUNIT_EXPECT_EQ(test, ssif_bmc->state, SSIF_RES_SENDING);
|
|
|
|
|
|
|
|
|
|
KUNIT_ASSERT_EQ(test,
|
|
|
|
|
ssif_bmc_test_run_event_val(test_ctx, I2C_SLAVE_READ_PROCESSED,
|
|
|
|
|
&value), 0);
|
|
|
|
|
KUNIT_EXPECT_EQ(test, value, 0x66);
|
|
|
|
|
|
|
|
|
|
/* READ_REQUESTED transaction */
|
|
|
|
|
ssif_bmc_test_singlepart_req(test);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void ssif_bmc_test_timeout_interrupt_allows_retry(struct kunit *test)
|
|
|
|
|
{
|
|
|
|
|
struct ssif_bmc_test_ctx *test_ctx = test->priv;
|
|
|
|
|
struct ssif_bmc_ctx *ssif_bmc = &test_ctx->ssif_bmc;
|
|
|
|
|
|
|
|
|
|
KUNIT_ASSERT_EQ(test,
|
|
|
|
|
ssif_bmc_test_run_event(test_ctx, I2C_SLAVE_WRITE_REQUESTED,
|
|
|
|
|
GET_8BIT_ADDR(test_ctx->client.addr)), 0);
|
|
|
|
|
KUNIT_ASSERT_EQ(test,
|
|
|
|
|
ssif_bmc_test_run_event(test_ctx, I2C_SLAVE_WRITE_RECEIVED,
|
|
|
|
|
SSIF_IPMI_SINGLEPART_WRITE), 0);
|
|
|
|
|
KUNIT_ASSERT_EQ(test,
|
|
|
|
|
ssif_bmc_test_run_event(test_ctx, I2C_SLAVE_WRITE_RECEIVED, 1), 0);
|
|
|
|
|
KUNIT_ASSERT_EQ(test,
|
|
|
|
|
ssif_bmc_test_run_event(test_ctx, I2C_SLAVE_WRITE_RECEIVED, 0x21), 0);
|
|
|
|
|
KUNIT_ASSERT_EQ(test,
|
|
|
|
|
ssif_bmc_test_run_event(test_ctx, I2C_SLAVE_STOP, 0), -EBUSY);
|
|
|
|
|
|
|
|
|
|
KUNIT_ASSERT_TRUE(test, timer_pending(&ssif_bmc->response_timer));
|
|
|
|
|
timer_delete_sync(&ssif_bmc->response_timer);
|
|
|
|
|
response_timeout(&ssif_bmc->response_timer);
|
|
|
|
|
|
|
|
|
|
KUNIT_EXPECT_FALSE(test, ssif_bmc->busy);
|
|
|
|
|
KUNIT_EXPECT_TRUE(test, ssif_bmc->aborting);
|
|
|
|
|
KUNIT_EXPECT_FALSE(test, ssif_bmc->response_timer_inited);
|
|
|
|
|
|
|
|
|
|
KUNIT_EXPECT_EQ(test,
|
|
|
|
|
ssif_bmc_test_run_event(test_ctx, I2C_SLAVE_WRITE_REQUESTED,
|
|
|
|
|
GET_8BIT_ADDR(test_ctx->client.addr)), 0);
|
|
|
|
|
KUNIT_EXPECT_EQ(test,
|
|
|
|
|
ssif_bmc_test_run_event(test_ctx, I2C_SLAVE_WRITE_RECEIVED,
|
|
|
|
|
SSIF_IPMI_SINGLEPART_WRITE), 0);
|
|
|
|
|
KUNIT_EXPECT_FALSE(test, ssif_bmc->aborting);
|
|
|
|
|
KUNIT_EXPECT_EQ(test,
|
|
|
|
|
ssif_bmc_test_run_event(test_ctx, I2C_SLAVE_WRITE_RECEIVED, 1), 0);
|
|
|
|
|
KUNIT_EXPECT_EQ(test,
|
|
|
|
|
ssif_bmc_test_run_event(test_ctx, I2C_SLAVE_WRITE_RECEIVED, 0x22), 0);
|
|
|
|
|
KUNIT_EXPECT_EQ(test,
|
|
|
|
|
ssif_bmc_test_run_event(test_ctx, I2C_SLAVE_STOP, 0), -EBUSY);
|
|
|
|
|
|
|
|
|
|
KUNIT_EXPECT_TRUE(test, ssif_bmc->request_available);
|
|
|
|
|
KUNIT_EXPECT_EQ(test, ssif_bmc->request.len, 1);
|
|
|
|
|
KUNIT_EXPECT_EQ(test, ssif_bmc->request.payload[0], 0x22);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct kunit_case ssif_bmc_test_cases[] = {
|
|
|
|
|
KUNIT_CASE(ssif_bmc_test_singlepart_req),
|
|
|
|
|
KUNIT_CASE(ssif_bmc_test_restart_write_without_stop),
|
|
|
|
|
KUNIT_CASE(ssif_bmc_test_restart_after_invalid_command),
|
|
|
|
|
KUNIT_CASE(ssif_bmc_test_singlepart_read_response_completion),
|
|
|
|
|
KUNIT_CASE(ssif_bmc_test_stop_during_start_discards_partial_request),
|
|
|
|
|
KUNIT_CASE(ssif_bmc_test_read_interrupts_partial_write),
|
|
|
|
|
KUNIT_CASE(ssif_bmc_test_write_interrupts_response_send),
|
|
|
|
|
KUNIT_CASE(ssif_bmc_test_write_interrupts_response_sending),
|
|
|
|
|
KUNIT_CASE(ssif_bmc_test_timeout_interrupt_allows_retry),
|
|
|
|
|
{}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static struct kunit_suite ssif_bmc_test_suite = {
|
|
|
|
|
.name = "ssif_bmc_test",
|
|
|
|
|
.init = ssif_bmc_test_init,
|
|
|
|
|
.exit = ssif_bmc_test_exit,
|
|
|
|
|
.test_cases = ssif_bmc_test_cases,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
kunit_test_suite(ssif_bmc_test_suite);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
module_i2c_driver(ssif_bmc_driver);
|
|
|
|
|
|
|
|
|
|
MODULE_AUTHOR("Quan Nguyen <quan@os.amperecomputing.com>");
|
|
|
|
|
|