mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	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: Javier Martinez Canillas <javier.martinez@collabora.co.uk> Acked-by: Lee Jones <lee.jones@linaro.org> Tested-by: Gwendal Grignou <gwendal@chromium.org> Reviewed-by: Gwendal Grignou <gwendal@chromium.org> Signed-off-by: Olof Johansson <olof@lixom.net>
This commit is contained in:
		
							parent
							
								
									c517d838eb
								
							
						
					
					
						commit
						1b84f2a4cd
					
				
					 4 changed files with 29 additions and 58 deletions
				
			
		| 
						 | 
				
			
			@ -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;
 | 
			
		||||
	int request_len;
 | 
			
		||||
	int response_len;
 | 
			
		||||
	u8 *request = NULL;
 | 
			
		||||
	u8 *response = NULL;
 | 
			
		||||
	int result;
 | 
			
		||||
	struct cros_ec_command msg;
 | 
			
		||||
	struct cros_ec_command msg = { };
 | 
			
		||||
 | 
			
		||||
	request_len = ec_i2c_count_message(i2c_msgs, num);
 | 
			
		||||
	if (request_len < 0) {
 | 
			
		||||
		dev_warn(dev, "Error constructing message %d\n", request_len);
 | 
			
		||||
		result = request_len;
 | 
			
		||||
		goto exit;
 | 
			
		||||
		return request_len;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	response_len = ec_i2c_count_response(i2c_msgs, num);
 | 
			
		||||
	if (response_len < 0) {
 | 
			
		||||
		/* Unexpected; no errors should come when NULL response */
 | 
			
		||||
		dev_warn(dev, "Error preparing response %d\n", response_len);
 | 
			
		||||
		result = response_len;
 | 
			
		||||
		goto exit;
 | 
			
		||||
		return response_len;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (request_len <= ARRAY_SIZE(bus->request_buf)) {
 | 
			
		||||
		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);
 | 
			
		||||
	result = ec_i2c_construct_message(msg.outdata, i2c_msgs, num, bus_num);
 | 
			
		||||
	if (result)
 | 
			
		||||
		goto exit;
 | 
			
		||||
		return result;
 | 
			
		||||
 | 
			
		||||
	msg.version = 0;
 | 
			
		||||
	msg.command = EC_CMD_I2C_PASSTHRU;
 | 
			
		||||
	msg.outdata = request;
 | 
			
		||||
	msg.outsize = request_len;
 | 
			
		||||
	msg.indata = response;
 | 
			
		||||
	msg.insize = response_len;
 | 
			
		||||
 | 
			
		||||
	result = cros_ec_cmd_xfer(bus->ec, &msg);
 | 
			
		||||
	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)
 | 
			
		||||
		goto exit;
 | 
			
		||||
		return result;
 | 
			
		||||
 | 
			
		||||
	/* Indicate success by saying how many messages were sent */
 | 
			
		||||
	result = num;
 | 
			
		||||
exit:
 | 
			
		||||
	if (request != bus->request_buf)
 | 
			
		||||
		kfree(request);
 | 
			
		||||
	if (response != bus->response_buf)
 | 
			
		||||
		kfree(response);
 | 
			
		||||
 | 
			
		||||
	return result;
 | 
			
		||||
	return num;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static u32 ec_i2c_functionality(struct i2c_adapter *adap)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
	struct cros_ec_command msg = {
 | 
			
		||||
		.version = 0,
 | 
			
		||||
		.command = EC_CMD_MKBP_STATE,
 | 
			
		||||
		.outdata = NULL,
 | 
			
		||||
		.outsize = 0,
 | 
			
		||||
		.indata = kb_state,
 | 
			
		||||
		.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)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -74,15 +74,11 @@ int cros_ec_cmd_xfer(struct cros_ec_device *ec_dev,
 | 
			
		|||
	ret = ec_dev->cmd_xfer(ec_dev, msg);
 | 
			
		||||
	if (msg->result == EC_RES_IN_PROGRESS) {
 | 
			
		||||
		int i;
 | 
			
		||||
		struct cros_ec_command status_msg;
 | 
			
		||||
		struct ec_response_get_comms_status status;
 | 
			
		||||
		struct cros_ec_command status_msg = { };
 | 
			
		||||
		struct ec_response_get_comms_status *status;
 | 
			
		||||
 | 
			
		||||
		status_msg.version = 0;
 | 
			
		||||
		status_msg.command = EC_CMD_GET_COMMS_STATUS;
 | 
			
		||||
		status_msg.outdata = NULL;
 | 
			
		||||
		status_msg.outsize = 0;
 | 
			
		||||
		status_msg.indata = (uint8_t *)&status;
 | 
			
		||||
		status_msg.insize = sizeof(status);
 | 
			
		||||
		status_msg.insize = sizeof(*status);
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
		 * 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;
 | 
			
		||||
			if (status_msg.result != EC_RES_SUCCESS)
 | 
			
		||||
				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;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -38,20 +38,20 @@ enum {
 | 
			
		|||
/*
 | 
			
		||||
 * @version: Command version number (often 0)
 | 
			
		||||
 * @command: Command to send (EC_CMD_...)
 | 
			
		||||
 * @outdata: Outgoing data to EC
 | 
			
		||||
 * @outsize: Outgoing length in bytes
 | 
			
		||||
 * @indata: Where to put the incoming data from EC
 | 
			
		||||
 * @insize: Max number of bytes to accept from EC
 | 
			
		||||
 * @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 {
 | 
			
		||||
	uint32_t version;
 | 
			
		||||
	uint32_t command;
 | 
			
		||||
	uint8_t *outdata;
 | 
			
		||||
	uint32_t outsize;
 | 
			
		||||
	uint8_t *indata;
 | 
			
		||||
	uint32_t insize;
 | 
			
		||||
	uint32_t result;
 | 
			
		||||
	uint8_t outdata[EC_PROTO2_MAX_PARAM_SIZE];
 | 
			
		||||
	uint8_t indata[EC_PROTO2_MAX_PARAM_SIZE];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue