forked from sonic-net/sonic-buildimage
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix i2c ISMT DMA buffer alignment issue (sonic-net#123)
Add linux patch to fix i2c ISMT 16-byte alignment issue of the DMA buffer address. Co-authored-by: lguohan <lguohan@gmail.com>
- Loading branch information
1 parent
0d15257
commit d446f16
Showing
2 changed files
with
142 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
From Commit ID: 5cd5f0bb0d9c32876b3d86b70fb45da10d028be7 | ||
Subject: 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: Radu Rendec <radu.rendec@gmail.com> | ||
Acked-by: Neil Horman <nhorman@tuxdriver.com> | ||
Signed-off-by: Wolfram Sang <wsa@the-dreams.de> | ||
--- | ||
|
||
diff --git a/drivers/i2c/busses/i2c-ismt.c b/drivers/i2c/busses/i2c-ismt.c | ||
index c97b48c..91c6524 100644 | ||
--- a/drivers/i2c/busses/i2c-ismt.c | ||
+++ b/drivers/i2c/busses/i2c-ismt.c | ||
@@ -173,7 +173,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 */ | ||
}; | ||
|
||
/** | ||
@@ -324,7 +324,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); | ||
@@ -397,6 +397,7 @@ 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); | ||
|
||
if (delay > 0) | ||
udelay(delay); | ||
@@ -404,7 +405,7 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr, | ||
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)); | ||
@@ -453,8 +454,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"); | ||
@@ -473,9 +474,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"); | ||
@@ -493,9 +494,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: | ||
@@ -506,8 +507,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"); | ||
@@ -534,8 +535,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"); | ||
@@ -564,18 +565,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; | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters