On Tue, 29 Jan 2013 10:32:53 -0500, Neil Horman wrote:
> On Tue, Jan 29, 2013 at 03:05:51PM +0100, Jean Delvare wrote:
> > On Mon, 28 Jan 2013 14:43:52 -0500, Neil Horman wrote:
> > > + if (size != I2C_SMBUS_QUICK)
> > > + memcpy(data, dma_buffer,
> > > + min(sizeof(*data), (size_t)I2C_SMBUS_BLOCK_MAX));
> >
> > This computation looks wrong. We already know that sizeof(*data) ==
> > sizeof(union i2c_smbus_data) > I2C_SMBUS_BLOCK_MAX, so the min() above
> > will always return I2C_SMBUS_BLOCK_MAX. Which may be insufficient as
> > the first byte holds the length, and at the same time it will be more
> > than needed in most cases.
>
> Gah! Sorry, you're right, I wasn't paying attention and though that data was
> just an allocated buffer, I need to fix that.
>
> > My original suggestion to limit the size of the copy was meant as a
> > run-time optimization, i.e. copying exactly the number of bytes that
> > were received from the slave. That would be 1 or 2 for non-block reads,
> > and the block length for block reads. Unfortunately I'm not sure is the
> > block length is available. See my comment about this below in
> > ismt_access().
>
> We don't currently have the dma_size, no, but the only calling function
> computes
> it (either from the block header or sets it appropriately for non-block
> transfers). We can pass that into the process_desc function and fix this.
This won't fix it, unless the hardware happens to update dma_size when
receiving a block from a slave. If not then dma_size will always be
I2C_SMBUS_BLOCK_MAX, while what we need is the number of bytes actually
received.
> > > +static int ismt_access(struct i2c_adapter *adap, u16 addr,
> > > + unsigned short flags, char read_write, u8 command,
> > > + int size, union i2c_smbus_data *data)
> > > +{
> > > + int ret;
> > > + dma_addr_t dma_addr = 0; /* address of the data buffer */
> > > + u8 dma_size = 0;
> > > + enum dma_data_direction dma_direction = 0;
> > > + struct ismt_desc *desc;
> > > + struct ismt_priv *priv = i2c_get_adapdata(adap);
> > > + struct device *dev = &priv->pci_dev->dev;
> > > +
> > > + desc = &priv->hw[priv->head];
> > > +
> > > + /* Initialize the descriptor */
> > > + memset(desc, 0, sizeof(struct ismt_desc));
> > > + desc->tgtaddr_rw = ISMT_DESC_ADDR_RW(addr, read_write);
> > > +
> > > + /* Create a temporary buffer for the DMA transaction */
> > > + /* and insert the command at the beginning of the buffer */
> > > + if ((read_write == I2C_SMBUS_WRITE) &&
> > > + (size != I2C_SMBUS_QUICK)) {
> >
> > If I read the code below properly, this can be skipped for size ==
> > I2C_SMBUS_BYTE too, right?
> I don't think so. The command field contains the data, and that is right
> below
> the memcpy in that if clause. We can certainly optimize this however, given
> that I need to fix the memcpy sizes anyway.
Precisely, I'm not sure the priv->dma_buffer[0] = command is needed in
this specific case, because later on we have:
desc->control |= ISMT_DESC_CWRL;
desc->wr_len_cmd = command;
and dma_size isn't set, which suggests that priv->dma_buffer won't even
be used. Honestly this "presetting" of priv->dma_buffer causes more
confusion than it helps, and performance-wise it makes little sense, so
I wouldn't object to you exploding it to the relevant code paths in the
switch statement.
I'll take a look at the datasheet tomorrow to check if I got it right
or you did. Or neither of us ^^ I'll also look for test hardware, I
don't have that at home obviously, but at work maybe.
--
Jean Delvare
--
To unsubscribe from this list: send the line "unsubscribe linux-i2c" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html