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

Commit 5cd5f0bb authored by Radu Rendec's avatar Radu Rendec Committed by Wolfram Sang
Browse files

i2c: ismt: 16-byte align the DMA buffer address



Use only a portion of the data buffer for DMA transfers, which is always
16-byte aligned. This makes the DMA buffer address 16-byte aligned and
compensates for spurious hardware parity errors that may appear when the
DMA buffer address is not 16-byte aligned.

The data buffer is enlarged in order to accommodate any possible 16-byte
alignment offset and changes the DMA code to only use a portion of the
data buffer, which is 16-byte aligned.

The symptom of the hardware issue is the same as the one addressed in
v3.12-rc2-5-gbf41691 and manifests by transfers failing with EIO, with
bit 9 being set in the ERRSTS register.

Signed-off-by: default avatarRadu Rendec <radu.rendec@gmail.com>
Acked-by: default avatarNeil Horman <nhorman@tuxdriver.com>
Signed-off-by: default avatarWolfram Sang <wsa@the-dreams.de>
parent 38a99bd7
Loading
Loading
Loading
Loading
+19 −18
Original line number Diff line number Diff line
@@ -172,7 +172,7 @@ struct ismt_priv {
	dma_addr_t io_rng_dma;			/* descriptor HW base addr */
	u8 head;				/* ring buffer head pointer */
	struct completion cmp;			/* interrupt completion */
	u8 dma_buffer[I2C_SMBUS_BLOCK_MAX + 1];	/* temp R/W data buffer */
	u8 buffer[I2C_SMBUS_BLOCK_MAX + 16];	/* temp R/W data buffer */
};

/**
@@ -320,7 +320,7 @@ static int ismt_process_desc(const struct ismt_desc *desc,
			     struct ismt_priv *priv, int size,
			     char read_write)
{
	u8 *dma_buffer = priv->dma_buffer;
	u8 *dma_buffer = PTR_ALIGN(&priv->buffer[0], 16);

	dev_dbg(&priv->pci_dev->dev, "Processing completed descriptor\n");
	__ismt_desc_dump(&priv->pci_dev->dev, desc);
@@ -395,11 +395,12 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr,
	struct ismt_desc *desc;
	struct ismt_priv *priv = i2c_get_adapdata(adap);
	struct device *dev = &priv->pci_dev->dev;
	u8 *dma_buffer = PTR_ALIGN(&priv->buffer[0], 16);

	desc = &priv->hw[priv->head];

	/* Initialize the DMA buffer */
	memset(priv->dma_buffer, 0, sizeof(priv->dma_buffer));
	memset(priv->buffer, 0, sizeof(priv->buffer));

	/* Initialize the descriptor */
	memset(desc, 0, sizeof(struct ismt_desc));
@@ -448,8 +449,8 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr,
			desc->wr_len_cmd = 2;
			dma_size = 2;
			dma_direction = DMA_TO_DEVICE;
			priv->dma_buffer[0] = command;
			priv->dma_buffer[1] = data->byte;
			dma_buffer[0] = command;
			dma_buffer[1] = data->byte;
		} else {
			/* Read Byte */
			dev_dbg(dev, "I2C_SMBUS_BYTE_DATA:  READ\n");
@@ -468,9 +469,9 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr,
			desc->wr_len_cmd = 3;
			dma_size = 3;
			dma_direction = DMA_TO_DEVICE;
			priv->dma_buffer[0] = command;
			priv->dma_buffer[1] = data->word & 0xff;
			priv->dma_buffer[2] = data->word >> 8;
			dma_buffer[0] = command;
			dma_buffer[1] = data->word & 0xff;
			dma_buffer[2] = data->word >> 8;
		} else {
			/* Read Word */
			dev_dbg(dev, "I2C_SMBUS_WORD_DATA:  READ\n");
@@ -488,9 +489,9 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr,
		desc->rd_len = 2;
		dma_size = 3;
		dma_direction = DMA_BIDIRECTIONAL;
		priv->dma_buffer[0] = command;
		priv->dma_buffer[1] = data->word & 0xff;
		priv->dma_buffer[2] = data->word >> 8;
		dma_buffer[0] = command;
		dma_buffer[1] = data->word & 0xff;
		dma_buffer[2] = data->word >> 8;
		break;

	case I2C_SMBUS_BLOCK_DATA:
@@ -501,8 +502,8 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr,
			dma_direction = DMA_TO_DEVICE;
			desc->wr_len_cmd = dma_size;
			desc->control |= ISMT_DESC_BLK;
			priv->dma_buffer[0] = command;
			memcpy(&priv->dma_buffer[1], &data->block[1], dma_size - 1);
			dma_buffer[0] = command;
			memcpy(&dma_buffer[1], &data->block[1], dma_size - 1);
		} else {
			/* Block Read */
			dev_dbg(dev, "I2C_SMBUS_BLOCK_DATA:  READ\n");
@@ -529,8 +530,8 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr,
			dma_direction = DMA_TO_DEVICE;
			desc->wr_len_cmd = dma_size;
			desc->control |= ISMT_DESC_I2C;
			priv->dma_buffer[0] = command;
			memcpy(&priv->dma_buffer[1], &data->block[1], dma_size - 1);
			dma_buffer[0] = command;
			memcpy(&dma_buffer[1], &data->block[1], dma_size - 1);
		} else {
			/* i2c Block Read */
			dev_dbg(dev, "I2C_SMBUS_I2C_BLOCK_DATA:  READ\n");
@@ -559,18 +560,18 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr,
	if (dma_size != 0) {
		dev_dbg(dev, " dev=%p\n", dev);
		dev_dbg(dev, " data=%p\n", data);
		dev_dbg(dev, " dma_buffer=%p\n", priv->dma_buffer);
		dev_dbg(dev, " dma_buffer=%p\n", dma_buffer);
		dev_dbg(dev, " dma_size=%d\n", dma_size);
		dev_dbg(dev, " dma_direction=%d\n", dma_direction);

		dma_addr = dma_map_single(dev,
				      priv->dma_buffer,
				      dma_buffer,
				      dma_size,
				      dma_direction);

		if (dma_mapping_error(dev, dma_addr)) {
			dev_err(dev, "Error in mapping dma buffer %p\n",
				priv->dma_buffer);
				dma_buffer);
			return -EIO;
		}