Commit 754cf4b2 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'i2c/for-current' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux

Pull i2c fixes from Wolfram Sang:

 - regression fixes for i801 and designware

 - better API and leak fix for releasing DMA safe buffers

 - better greppable strings for the bitbang algorithm

* 'i2c/for-current' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux:
  i2c: sh_mobile: fix leak when using DMA bounce buffer
  i2c: sh_mobile: define start_ch() void as it only returns 0 anyhow
  i2c: refactor function to release a DMA safe buffer
  i2c: algos: bit: make the error messages grepable
  i2c: designware: Re-init controllers with pm_disabled set on resume
  i2c: i801: Allow ACPI AML access I/O ports not reserved for SMBus
parents 4658aff6 cebc07d8
......@@ -50,10 +50,14 @@ bounce buffer. But you don't need to care about that detail, just use the
returned buffer. If NULL is returned, the threshold was not met or a bounce
buffer could not be allocated. Fall back to PIO in that case.
In any case, a buffer obtained from above needs to be released. It ensures data
is copied back to the message and a potentially used bounce buffer is freed::
In any case, a buffer obtained from above needs to be released. Another helper
function ensures a potentially used bounce buffer is freed::
i2c_release_dma_safe_msg_buf(msg, dma_buf);
i2c_put_dma_safe_msg_buf(dma_buf, msg, xferred);
The last argument 'xferred' controls if the buffer is synced back to the
message or not. No syncing is needed in cases setting up DMA had an error and
there was no data transferred.
The bounce buffer handling from the core is generic and simple. It will always
allocate a new bounce buffer. If you want a more sophisticated handling (e.g.
......
......@@ -110,8 +110,8 @@ static int sclhi(struct i2c_algo_bit_data *adap)
}
#ifdef DEBUG
if (jiffies != start && i2c_debug >= 3)
pr_debug("i2c-algo-bit: needed %ld jiffies for SCL to go "
"high\n", jiffies - start);
pr_debug("i2c-algo-bit: needed %ld jiffies for SCL to go high\n",
jiffies - start);
#endif
done:
......@@ -171,8 +171,9 @@ static int i2c_outb(struct i2c_adapter *i2c_adap, unsigned char c)
setsda(adap, sb);
udelay((adap->udelay + 1) / 2);
if (sclhi(adap) < 0) { /* timed out */
bit_dbg(1, &i2c_adap->dev, "i2c_outb: 0x%02x, "
"timeout at bit #%d\n", (int)c, i);
bit_dbg(1, &i2c_adap->dev,
"i2c_outb: 0x%02x, timeout at bit #%d\n",
(int)c, i);
return -ETIMEDOUT;
}
/* FIXME do arbitration here:
......@@ -185,8 +186,8 @@ static int i2c_outb(struct i2c_adapter *i2c_adap, unsigned char c)
}
sdahi(adap);
if (sclhi(adap) < 0) { /* timeout */
bit_dbg(1, &i2c_adap->dev, "i2c_outb: 0x%02x, "
"timeout at ack\n", (int)c);
bit_dbg(1, &i2c_adap->dev,
"i2c_outb: 0x%02x, timeout at ack\n", (int)c);
return -ETIMEDOUT;
}
......@@ -215,8 +216,9 @@ static int i2c_inb(struct i2c_adapter *i2c_adap)
sdahi(adap);
for (i = 0; i < 8; i++) {
if (sclhi(adap) < 0) { /* timeout */
bit_dbg(1, &i2c_adap->dev, "i2c_inb: timeout at bit "
"#%d\n", 7 - i);
bit_dbg(1, &i2c_adap->dev,
"i2c_inb: timeout at bit #%d\n",
7 - i);
return -ETIMEDOUT;
}
indata *= 2;
......@@ -265,8 +267,9 @@ static int test_bus(struct i2c_adapter *i2c_adap)
goto bailout;
}
if (!scl) {
printk(KERN_WARNING "%s: SCL unexpected low "
"while pulling SDA low!\n", name);
printk(KERN_WARNING
"%s: SCL unexpected low while pulling SDA low!\n",
name);
goto bailout;
}
......@@ -278,8 +281,9 @@ static int test_bus(struct i2c_adapter *i2c_adap)
goto bailout;
}
if (!scl) {
printk(KERN_WARNING "%s: SCL unexpected low "
"while pulling SDA high!\n", name);
printk(KERN_WARNING
"%s: SCL unexpected low while pulling SDA high!\n",
name);
goto bailout;
}
......@@ -291,8 +295,9 @@ static int test_bus(struct i2c_adapter *i2c_adap)
goto bailout;
}
if (!sda) {
printk(KERN_WARNING "%s: SDA unexpected low "
"while pulling SCL low!\n", name);
printk(KERN_WARNING
"%s: SDA unexpected low while pulling SCL low!\n",
name);
goto bailout;
}
......@@ -304,8 +309,9 @@ static int test_bus(struct i2c_adapter *i2c_adap)
goto bailout;
}
if (!sda) {
printk(KERN_WARNING "%s: SDA unexpected low "
"while pulling SCL high!\n", name);
printk(KERN_WARNING
"%s: SDA unexpected low while pulling SCL high!\n",
name);
goto bailout;
}
......@@ -352,8 +358,8 @@ static int try_address(struct i2c_adapter *i2c_adap,
i2c_start(adap);
}
if (i && ret)
bit_dbg(1, &i2c_adap->dev, "Used %d tries to %s client at "
"0x%02x: %s\n", i + 1,
bit_dbg(1, &i2c_adap->dev,
"Used %d tries to %s client at 0x%02x: %s\n", i + 1,
addr & 1 ? "read from" : "write to", addr >> 1,
ret == 1 ? "success" : "failed, timeout?");
return ret;
......@@ -442,8 +448,9 @@ static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
if (inval <= 0 || inval > I2C_SMBUS_BLOCK_MAX) {
if (!(flags & I2C_M_NO_RD_ACK))
acknak(i2c_adap, 0);
dev_err(&i2c_adap->dev, "readbytes: invalid "
"block length (%d)\n", inval);
dev_err(&i2c_adap->dev,
"readbytes: invalid block length (%d)\n",
inval);
return -EPROTO;
}
/* The original count value accounts for the extra
......@@ -506,8 +513,8 @@ static int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
return -ENXIO;
}
if (flags & I2C_M_RD) {
bit_dbg(3, &i2c_adap->dev, "emitting repeated "
"start condition\n");
bit_dbg(3, &i2c_adap->dev,
"emitting repeated start condition\n");
i2c_repstart(adap);
/* okay, now switch into reading mode */
addr |= 0x01;
......@@ -564,8 +571,8 @@ static int bit_xfer(struct i2c_adapter *i2c_adap,
}
ret = bit_doAddress(i2c_adap, pmsg);
if ((ret != 0) && !nak_ok) {
bit_dbg(1, &i2c_adap->dev, "NAK from "
"device addr 0x%02x msg #%d\n",
bit_dbg(1, &i2c_adap->dev,
"NAK from device addr 0x%02x msg #%d\n",
msgs[i].addr, i);
goto bailout;
}
......
......@@ -708,7 +708,6 @@ int i2c_dw_probe(struct dw_i2c_dev *dev)
i2c_set_adapdata(adap, dev);
if (dev->pm_disabled) {
dev_pm_syscore_device(dev->dev, true);
irq_flags = IRQF_NO_SUSPEND;
} else {
irq_flags = IRQF_SHARED | IRQF_COND_SUSPEND;
......
......@@ -434,6 +434,9 @@ static int dw_i2c_plat_suspend(struct device *dev)
{
struct dw_i2c_dev *i_dev = dev_get_drvdata(dev);
if (i_dev->pm_disabled)
return 0;
i_dev->disable(i_dev);
i2c_dw_prepare_clk(i_dev, false);
......@@ -444,7 +447,9 @@ static int dw_i2c_plat_resume(struct device *dev)
{
struct dw_i2c_dev *i_dev = dev_get_drvdata(dev);
if (!i_dev->pm_disabled)
i2c_dw_prepare_clk(i_dev, true);
i_dev->init(i_dev);
return 0;
......
......@@ -1415,6 +1415,13 @@ static void i801_add_tco(struct i801_priv *priv)
}
#ifdef CONFIG_ACPI
static bool i801_acpi_is_smbus_ioport(const struct i801_priv *priv,
acpi_physical_address address)
{
return address >= priv->smba &&
address <= pci_resource_end(priv->pci_dev, SMBBAR);
}
static acpi_status
i801_acpi_io_handler(u32 function, acpi_physical_address address, u32 bits,
u64 *value, void *handler_context, void *region_context)
......@@ -1430,7 +1437,7 @@ i801_acpi_io_handler(u32 function, acpi_physical_address address, u32 bits,
*/
mutex_lock(&priv->acpi_lock);
if (!priv->acpi_reserved) {
if (!priv->acpi_reserved && i801_acpi_is_smbus_ioport(priv, address)) {
priv->acpi_reserved = true;
dev_warn(&pdev->dev, "BIOS is accessing SMBus registers\n");
......
......@@ -507,8 +507,6 @@ static void sh_mobile_i2c_dma_callback(void *data)
pd->pos = pd->msg->len;
pd->stop_after_dma = true;
i2c_release_dma_safe_msg_buf(pd->msg, pd->dma_buf);
iic_set_clr(pd, ICIC, 0, ICIC_TDMAE | ICIC_RDMAE);
}
......@@ -602,7 +600,7 @@ static void sh_mobile_i2c_xfer_dma(struct sh_mobile_i2c_data *pd)
dma_async_issue_pending(chan);
}
static int start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg,
static void start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg,
bool do_init)
{
if (do_init) {
......@@ -627,7 +625,6 @@ static int start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg,
/* Enable all interrupts to begin with */
iic_wr(pd, ICIC, ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE);
return 0;
}
static int poll_dte(struct sh_mobile_i2c_data *pd)
......@@ -698,9 +695,7 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter,
pd->send_stop = i == num - 1 || msg->flags & I2C_M_STOP;
pd->stop_after_dma = false;
err = start_ch(pd, msg, do_start);
if (err)
break;
start_ch(pd, msg, do_start);
if (do_start)
i2c_op(pd, OP_START, 0);
......@@ -709,6 +704,10 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter,
timeout = wait_event_timeout(pd->wait,
pd->sr & (ICSR_TACK | SW_DONE),
adapter->timeout);
/* 'stop_after_dma' tells if DMA transfer was complete */
i2c_put_dma_safe_msg_buf(pd->dma_buf, pd->msg, pd->stop_after_dma);
if (!timeout) {
dev_err(pd->dev, "Transfer request timed out\n");
if (pd->dma_direction != DMA_NONE)
......
......@@ -2293,21 +2293,22 @@ u8 *i2c_get_dma_safe_msg_buf(struct i2c_msg *msg, unsigned int threshold)
EXPORT_SYMBOL_GPL(i2c_get_dma_safe_msg_buf);
/**
* i2c_release_dma_safe_msg_buf - release DMA safe buffer and sync with i2c_msg
* @msg: the message to be synced with
* i2c_put_dma_safe_msg_buf - release DMA safe buffer and sync with i2c_msg
* @buf: the buffer obtained from i2c_get_dma_safe_msg_buf(). May be NULL.
* @msg: the message which the buffer corresponds to
* @xferred: bool saying if the message was transferred
*/
void i2c_release_dma_safe_msg_buf(struct i2c_msg *msg, u8 *buf)
void i2c_put_dma_safe_msg_buf(u8 *buf, struct i2c_msg *msg, bool xferred)
{
if (!buf || buf == msg->buf)
return;
if (msg->flags & I2C_M_RD)
if (xferred && msg->flags & I2C_M_RD)
memcpy(msg->buf, buf, msg->len);
kfree(buf);
}
EXPORT_SYMBOL_GPL(i2c_release_dma_safe_msg_buf);
EXPORT_SYMBOL_GPL(i2c_put_dma_safe_msg_buf);
MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>");
MODULE_DESCRIPTION("I2C-Bus main module");
......
......@@ -855,7 +855,7 @@ static inline u8 i2c_8bit_addr_from_msg(const struct i2c_msg *msg)
}
u8 *i2c_get_dma_safe_msg_buf(struct i2c_msg *msg, unsigned int threshold);
void i2c_release_dma_safe_msg_buf(struct i2c_msg *msg, u8 *buf);
void i2c_put_dma_safe_msg_buf(u8 *buf, struct i2c_msg *msg, bool xferred);
int i2c_handle_smbus_host_notify(struct i2c_adapter *adap, unsigned short addr);
/**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment