Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1b84f2a4 authored by Javier Martinez Canillas's avatar Javier Martinez Canillas Committed by Olof Johansson
Browse files

mfd: cros_ec: Use fixed size arrays to transfer data with the EC



The struct cros_ec_command will be used as an ioctl() argument for the
API to control the ChromeOS EC from user-space. So the data structure
has to be 64-bit safe to make it compatible between 32 and 64 avoiding
the need for a compat ioctl interface. Since pointers are self-aligned
to different byte boundaries, use fixed size arrays instead of pointers
for transferring ingoing and outgoing data with the Embedded Controller.

Also, re-arrange struct members by decreasing alignment requirements to
reduce the needing padding size.

Signed-off-by: default avatarJavier Martinez Canillas <javier.martinez@collabora.co.uk>
Acked-by: default avatarLee Jones <lee.jones@linaro.org>
Tested-by: default avatarGwendal Grignou <gwendal@chromium.org>
Reviewed-by: default avatarGwendal Grignou <gwendal@chromium.org>
Signed-off-by: default avatarOlof Johansson <olof@lixom.net>
parent c517d838
Loading
Loading
Loading
Loading
+10 −41
Original line number Original line Diff line number Diff line
@@ -182,72 +182,41 @@ static int ec_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg i2c_msgs[],
	const u16 bus_num = bus->remote_bus;
	const u16 bus_num = bus->remote_bus;
	int request_len;
	int request_len;
	int response_len;
	int response_len;
	u8 *request = NULL;
	u8 *response = NULL;
	int result;
	int result;
	struct cros_ec_command msg;
	struct cros_ec_command msg = { };


	request_len = ec_i2c_count_message(i2c_msgs, num);
	request_len = ec_i2c_count_message(i2c_msgs, num);
	if (request_len < 0) {
	if (request_len < 0) {
		dev_warn(dev, "Error constructing message %d\n", request_len);
		dev_warn(dev, "Error constructing message %d\n", request_len);
		result = request_len;
		return request_len;
		goto exit;
	}
	}

	response_len = ec_i2c_count_response(i2c_msgs, num);
	response_len = ec_i2c_count_response(i2c_msgs, num);
	if (response_len < 0) {
	if (response_len < 0) {
		/* Unexpected; no errors should come when NULL response */
		/* Unexpected; no errors should come when NULL response */
		dev_warn(dev, "Error preparing response %d\n", response_len);
		dev_warn(dev, "Error preparing response %d\n", response_len);
		result = response_len;
		return response_len;
		goto exit;
	}
	}


	if (request_len <= ARRAY_SIZE(bus->request_buf)) {
	result = ec_i2c_construct_message(msg.outdata, i2c_msgs, num, bus_num);
		request = bus->request_buf;
	} else {
		request = kzalloc(request_len, GFP_KERNEL);
		if (request == NULL) {
			result = -ENOMEM;
			goto exit;
		}
	}
	if (response_len <= ARRAY_SIZE(bus->response_buf)) {
		response = bus->response_buf;
	} else {
		response = kzalloc(response_len, GFP_KERNEL);
		if (response == NULL) {
			result = -ENOMEM;
			goto exit;
		}
	}

	result = ec_i2c_construct_message(request, i2c_msgs, num, bus_num);
	if (result)
	if (result)
		goto exit;
		return result;


	msg.version = 0;
	msg.version = 0;
	msg.command = EC_CMD_I2C_PASSTHRU;
	msg.command = EC_CMD_I2C_PASSTHRU;
	msg.outdata = request;
	msg.outsize = request_len;
	msg.outsize = request_len;
	msg.indata = response;
	msg.insize = response_len;
	msg.insize = response_len;


	result = cros_ec_cmd_xfer(bus->ec, &msg);
	result = cros_ec_cmd_xfer(bus->ec, &msg);
	if (result < 0)
	if (result < 0)
		goto exit;
		return result;


	result = ec_i2c_parse_response(response, i2c_msgs, &num);
	result = ec_i2c_parse_response(msg.indata, i2c_msgs, &num);
	if (result < 0)
	if (result < 0)
		goto exit;
		return result;


	/* Indicate success by saying how many messages were sent */
	/* Indicate success by saying how many messages were sent */
	result = num;
	return num;
exit:
	if (request != bus->request_buf)
		kfree(request);
	if (response != bus->response_buf)
		kfree(response);

	return result;
}
}


static u32 ec_i2c_functionality(struct i2c_adapter *adap)
static u32 ec_i2c_functionality(struct i2c_adapter *adap)
+8 −5
Original line number Original line Diff line number Diff line
@@ -148,16 +148,19 @@ static void cros_ec_keyb_process(struct cros_ec_keyb *ckdev,


static int cros_ec_keyb_get_state(struct cros_ec_keyb *ckdev, uint8_t *kb_state)
static int cros_ec_keyb_get_state(struct cros_ec_keyb *ckdev, uint8_t *kb_state)
{
{
	int ret;
	struct cros_ec_command msg = {
	struct cros_ec_command msg = {
		.version = 0,
		.command = EC_CMD_MKBP_STATE,
		.command = EC_CMD_MKBP_STATE,
		.outdata = NULL,
		.outsize = 0,
		.indata = kb_state,
		.insize = ckdev->cols,
		.insize = ckdev->cols,
	};
	};


	return cros_ec_cmd_xfer(ckdev->ec, &msg);
	ret = cros_ec_cmd_xfer(ckdev->ec, &msg);
	if (ret < 0)
		return ret;

	memcpy(kb_state, msg.indata, ckdev->cols);

	return 0;
}
}


static irqreturn_t cros_ec_keyb_irq(int irq, void *data)
static irqreturn_t cros_ec_keyb_irq(int irq, void *data)
+7 −8
Original line number Original line Diff line number Diff line
@@ -74,15 +74,11 @@ int cros_ec_cmd_xfer(struct cros_ec_device *ec_dev,
	ret = ec_dev->cmd_xfer(ec_dev, msg);
	ret = ec_dev->cmd_xfer(ec_dev, msg);
	if (msg->result == EC_RES_IN_PROGRESS) {
	if (msg->result == EC_RES_IN_PROGRESS) {
		int i;
		int i;
		struct cros_ec_command status_msg;
		struct cros_ec_command status_msg = { };
		struct ec_response_get_comms_status status;
		struct ec_response_get_comms_status *status;


		status_msg.version = 0;
		status_msg.command = EC_CMD_GET_COMMS_STATUS;
		status_msg.command = EC_CMD_GET_COMMS_STATUS;
		status_msg.outdata = NULL;
		status_msg.insize = sizeof(*status);
		status_msg.outsize = 0;
		status_msg.indata = (uint8_t *)&status;
		status_msg.insize = sizeof(status);


		/*
		/*
		 * Query the EC's status until it's no longer busy or
		 * Query the EC's status until it's no longer busy or
@@ -98,7 +94,10 @@ int cros_ec_cmd_xfer(struct cros_ec_device *ec_dev,
			msg->result = status_msg.result;
			msg->result = status_msg.result;
			if (status_msg.result != EC_RES_SUCCESS)
			if (status_msg.result != EC_RES_SUCCESS)
				break;
				break;
			if (!(status.flags & EC_COMMS_STATUS_PROCESSING))

			status = (struct ec_response_get_comms_status *)
				 status_msg.indata;
			if (!(status->flags & EC_COMMS_STATUS_PROCESSING))
				break;
				break;
		}
		}
	}
	}
+4 −4
Original line number Original line Diff line number Diff line
@@ -38,20 +38,20 @@ enum {
/*
/*
 * @version: Command version number (often 0)
 * @version: Command version number (often 0)
 * @command: Command to send (EC_CMD_...)
 * @command: Command to send (EC_CMD_...)
 * @outdata: Outgoing data to EC
 * @outsize: Outgoing length in bytes
 * @outsize: Outgoing length in bytes
 * @indata: Where to put the incoming data from EC
 * @insize: Max number of bytes to accept from EC
 * @insize: Max number of bytes to accept from EC
 * @result: EC's response to the command (separate from communication failure)
 * @result: EC's response to the command (separate from communication failure)
 * @outdata: Outgoing data to EC
 * @indata: Where to put the incoming data from EC
 */
 */
struct cros_ec_command {
struct cros_ec_command {
	uint32_t version;
	uint32_t version;
	uint32_t command;
	uint32_t command;
	uint8_t *outdata;
	uint32_t outsize;
	uint32_t outsize;
	uint8_t *indata;
	uint32_t insize;
	uint32_t insize;
	uint32_t result;
	uint32_t result;
	uint8_t outdata[EC_PROTO2_MAX_PARAM_SIZE];
	uint8_t indata[EC_PROTO2_MAX_PARAM_SIZE];
};
};


/**
/**