Skip to content

Commit

Permalink
fsi: occ: Force sequence numbering per OCC
Browse files Browse the repository at this point in the history
Set and increment the sequence number during the submit operation.
This prevents sequence number conflicts between different users of
the interface. A sequence number conflict may result in a user
getting an OCC response meant for a different command. Since the
sequence number is now modified, the checksum must be calculated and
set before submitting the command.

Signed-off-by: Eddie James <[email protected]>
Reviewed-by: Joel Stanley <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
Signed-off-by: Joel Stanley <[email protected]>
  • Loading branch information
Eddie James authored and shenki committed Oct 15, 2021
1 parent 6880fa6 commit 62f79f3
Showing 1 changed file with 37 additions and 17 deletions.
54 changes: 37 additions & 17 deletions drivers/fsi/fsi-occ.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ struct occ {
struct device *sbefifo;
char name[32];
int idx;
u8 sequence_number;
enum versions version;
struct miscdevice mdev;
struct mutex occ_lock;
Expand Down Expand Up @@ -141,8 +142,7 @@ static ssize_t occ_write(struct file *file, const char __user *buf,
{
struct occ_client *client = file->private_data;
size_t rlen, data_length;
u16 checksum = 0;
ssize_t rc, i;
ssize_t rc;
u8 *cmd;

if (!client)
Expand All @@ -156,9 +156,6 @@ static ssize_t occ_write(struct file *file, const char __user *buf,
/* Construct the command */
cmd = client->buffer;

/* Sequence number (we could increment and compare with response) */
cmd[0] = 1;

/*
* Copy the user command (assume user data follows the occ command
* format)
Expand All @@ -178,14 +175,7 @@ static ssize_t occ_write(struct file *file, const char __user *buf,
goto done;
}

/* Calculate checksum */
for (i = 0; i < data_length + 4; ++i)
checksum += cmd[i];

cmd[data_length + 4] = checksum >> 8;
cmd[data_length + 5] = checksum & 0xFF;

/* Submit command */
/* Submit command; 4 bytes before the data and 2 bytes after */
rlen = PAGE_SIZE;
rc = fsi_occ_submit(client->occ->dev, cmd, data_length + 6, cmd,
&rlen);
Expand Down Expand Up @@ -314,11 +304,13 @@ static int occ_getsram(struct occ *occ, u32 offset, void *data, ssize_t len)
return rc;
}

static int occ_putsram(struct occ *occ, const void *data, ssize_t len)
static int occ_putsram(struct occ *occ, const void *data, ssize_t len,
u8 seq_no, u16 checksum)
{
size_t cmd_len, buf_len, resp_len, resp_data_len;
u32 data_len = ((len + 7) / 8) * 8; /* must be multiples of 8 B */
__be32 *buf;
u8 *byte_buf;
int idx = 0, rc;

cmd_len = (occ->version == occ_p10) ? 6 : 5;
Expand Down Expand Up @@ -358,6 +350,15 @@ static int occ_putsram(struct occ *occ, const void *data, ssize_t len)
buf[4 + idx] = cpu_to_be32(data_len);
memcpy(&buf[5 + idx], data, len);

byte_buf = (u8 *)&buf[5 + idx];
/*
* Overwrite the first byte with our sequence number and the last two
* bytes with the checksum.
*/
byte_buf[0] = seq_no;
byte_buf[len - 2] = checksum >> 8;
byte_buf[len - 1] = checksum & 0xff;

rc = sbefifo_submit(occ->sbefifo, buf, cmd_len, buf, &resp_len);
if (rc)
goto free;
Expand Down Expand Up @@ -467,9 +468,12 @@ int fsi_occ_submit(struct device *dev, const void *request, size_t req_len,
struct occ *occ = dev_get_drvdata(dev);
struct occ_response *resp = response;
u8 seq_no;
u16 checksum = 0;
u16 resp_data_length;
const u8 *byte_request = (const u8 *)request;
unsigned long start;
int rc;
size_t i;

if (!occ)
return -ENODEV;
Expand All @@ -479,11 +483,26 @@ int fsi_occ_submit(struct device *dev, const void *request, size_t req_len,
return -EINVAL;
}

/* Checksum the request, ignoring first byte (sequence number). */
for (i = 1; i < req_len - 2; ++i)
checksum += byte_request[i];

mutex_lock(&occ->occ_lock);

/* Extract the seq_no from the command (first byte) */
seq_no = *(const u8 *)request;
rc = occ_putsram(occ, request, req_len);
/*
* Get a sequence number and update the counter. Avoid a sequence
* number of 0 which would pass the response check below even if the
* OCC response is uninitialized. Any sequence number the user is
* trying to send is overwritten since this function is the only common
* interface to the OCC and therefore the only place we can guarantee
* unique sequence numbers.
*/
seq_no = occ->sequence_number++;
if (!occ->sequence_number)
occ->sequence_number = 1;
checksum += seq_no;

rc = occ_putsram(occ, request, req_len, seq_no, checksum);
if (rc)
goto done;

Expand Down Expand Up @@ -574,6 +593,7 @@ static int occ_probe(struct platform_device *pdev)
occ->version = (uintptr_t)of_device_get_match_data(dev);
occ->dev = dev;
occ->sbefifo = dev->parent;
occ->sequence_number = 1;
mutex_init(&occ->occ_lock);

if (dev->of_node) {
Expand Down

0 comments on commit 62f79f3

Please sign in to comment.