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
This commit is contained in:
Linus Torvalds 2018-08-31 08:38:53 -07:00
Родитель 4658aff6ee cebc07d84a
Коммит 754cf4b243
8 изменённых файлов: 66 добавлений и 44 удалений

Просмотреть файл

@ -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 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. 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 In any case, a buffer obtained from above needs to be released. Another helper
is copied back to the message and a potentially used bounce buffer is freed:: 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 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. 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 #ifdef DEBUG
if (jiffies != start && i2c_debug >= 3) if (jiffies != start && i2c_debug >= 3)
pr_debug("i2c-algo-bit: needed %ld jiffies for SCL to go " pr_debug("i2c-algo-bit: needed %ld jiffies for SCL to go high\n",
"high\n", jiffies - start); jiffies - start);
#endif #endif
done: done:
@ -171,8 +171,9 @@ static int i2c_outb(struct i2c_adapter *i2c_adap, unsigned char c)
setsda(adap, sb); setsda(adap, sb);
udelay((adap->udelay + 1) / 2); udelay((adap->udelay + 1) / 2);
if (sclhi(adap) < 0) { /* timed out */ if (sclhi(adap) < 0) { /* timed out */
bit_dbg(1, &i2c_adap->dev, "i2c_outb: 0x%02x, " bit_dbg(1, &i2c_adap->dev,
"timeout at bit #%d\n", (int)c, i); "i2c_outb: 0x%02x, timeout at bit #%d\n",
(int)c, i);
return -ETIMEDOUT; return -ETIMEDOUT;
} }
/* FIXME do arbitration here: /* FIXME do arbitration here:
@ -185,8 +186,8 @@ static int i2c_outb(struct i2c_adapter *i2c_adap, unsigned char c)
} }
sdahi(adap); sdahi(adap);
if (sclhi(adap) < 0) { /* timeout */ if (sclhi(adap) < 0) { /* timeout */
bit_dbg(1, &i2c_adap->dev, "i2c_outb: 0x%02x, " bit_dbg(1, &i2c_adap->dev,
"timeout at ack\n", (int)c); "i2c_outb: 0x%02x, timeout at ack\n", (int)c);
return -ETIMEDOUT; return -ETIMEDOUT;
} }
@ -215,8 +216,9 @@ static int i2c_inb(struct i2c_adapter *i2c_adap)
sdahi(adap); sdahi(adap);
for (i = 0; i < 8; i++) { for (i = 0; i < 8; i++) {
if (sclhi(adap) < 0) { /* timeout */ if (sclhi(adap) < 0) { /* timeout */
bit_dbg(1, &i2c_adap->dev, "i2c_inb: timeout at bit " bit_dbg(1, &i2c_adap->dev,
"#%d\n", 7 - i); "i2c_inb: timeout at bit #%d\n",
7 - i);
return -ETIMEDOUT; return -ETIMEDOUT;
} }
indata *= 2; indata *= 2;
@ -265,8 +267,9 @@ static int test_bus(struct i2c_adapter *i2c_adap)
goto bailout; goto bailout;
} }
if (!scl) { if (!scl) {
printk(KERN_WARNING "%s: SCL unexpected low " printk(KERN_WARNING
"while pulling SDA low!\n", name); "%s: SCL unexpected low while pulling SDA low!\n",
name);
goto bailout; goto bailout;
} }
@ -278,8 +281,9 @@ static int test_bus(struct i2c_adapter *i2c_adap)
goto bailout; goto bailout;
} }
if (!scl) { if (!scl) {
printk(KERN_WARNING "%s: SCL unexpected low " printk(KERN_WARNING
"while pulling SDA high!\n", name); "%s: SCL unexpected low while pulling SDA high!\n",
name);
goto bailout; goto bailout;
} }
@ -291,8 +295,9 @@ static int test_bus(struct i2c_adapter *i2c_adap)
goto bailout; goto bailout;
} }
if (!sda) { if (!sda) {
printk(KERN_WARNING "%s: SDA unexpected low " printk(KERN_WARNING
"while pulling SCL low!\n", name); "%s: SDA unexpected low while pulling SCL low!\n",
name);
goto bailout; goto bailout;
} }
@ -304,8 +309,9 @@ static int test_bus(struct i2c_adapter *i2c_adap)
goto bailout; goto bailout;
} }
if (!sda) { if (!sda) {
printk(KERN_WARNING "%s: SDA unexpected low " printk(KERN_WARNING
"while pulling SCL high!\n", name); "%s: SDA unexpected low while pulling SCL high!\n",
name);
goto bailout; goto bailout;
} }
@ -352,8 +358,8 @@ static int try_address(struct i2c_adapter *i2c_adap,
i2c_start(adap); i2c_start(adap);
} }
if (i && ret) if (i && ret)
bit_dbg(1, &i2c_adap->dev, "Used %d tries to %s client at " bit_dbg(1, &i2c_adap->dev,
"0x%02x: %s\n", i + 1, "Used %d tries to %s client at 0x%02x: %s\n", i + 1,
addr & 1 ? "read from" : "write to", addr >> 1, addr & 1 ? "read from" : "write to", addr >> 1,
ret == 1 ? "success" : "failed, timeout?"); ret == 1 ? "success" : "failed, timeout?");
return ret; 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 (inval <= 0 || inval > I2C_SMBUS_BLOCK_MAX) {
if (!(flags & I2C_M_NO_RD_ACK)) if (!(flags & I2C_M_NO_RD_ACK))
acknak(i2c_adap, 0); acknak(i2c_adap, 0);
dev_err(&i2c_adap->dev, "readbytes: invalid " dev_err(&i2c_adap->dev,
"block length (%d)\n", inval); "readbytes: invalid block length (%d)\n",
inval);
return -EPROTO; return -EPROTO;
} }
/* The original count value accounts for the extra /* 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; return -ENXIO;
} }
if (flags & I2C_M_RD) { if (flags & I2C_M_RD) {
bit_dbg(3, &i2c_adap->dev, "emitting repeated " bit_dbg(3, &i2c_adap->dev,
"start condition\n"); "emitting repeated start condition\n");
i2c_repstart(adap); i2c_repstart(adap);
/* okay, now switch into reading mode */ /* okay, now switch into reading mode */
addr |= 0x01; addr |= 0x01;
@ -564,8 +571,8 @@ static int bit_xfer(struct i2c_adapter *i2c_adap,
} }
ret = bit_doAddress(i2c_adap, pmsg); ret = bit_doAddress(i2c_adap, pmsg);
if ((ret != 0) && !nak_ok) { if ((ret != 0) && !nak_ok) {
bit_dbg(1, &i2c_adap->dev, "NAK from " bit_dbg(1, &i2c_adap->dev,
"device addr 0x%02x msg #%d\n", "NAK from device addr 0x%02x msg #%d\n",
msgs[i].addr, i); msgs[i].addr, i);
goto bailout; goto bailout;
} }

Просмотреть файл

@ -708,7 +708,6 @@ int i2c_dw_probe(struct dw_i2c_dev *dev)
i2c_set_adapdata(adap, dev); i2c_set_adapdata(adap, dev);
if (dev->pm_disabled) { if (dev->pm_disabled) {
dev_pm_syscore_device(dev->dev, true);
irq_flags = IRQF_NO_SUSPEND; irq_flags = IRQF_NO_SUSPEND;
} else { } else {
irq_flags = IRQF_SHARED | IRQF_COND_SUSPEND; 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); struct dw_i2c_dev *i_dev = dev_get_drvdata(dev);
if (i_dev->pm_disabled)
return 0;
i_dev->disable(i_dev); i_dev->disable(i_dev);
i2c_dw_prepare_clk(i_dev, false); 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); struct dw_i2c_dev *i_dev = dev_get_drvdata(dev);
if (!i_dev->pm_disabled)
i2c_dw_prepare_clk(i_dev, true); i2c_dw_prepare_clk(i_dev, true);
i_dev->init(i_dev); i_dev->init(i_dev);
return 0; return 0;

Просмотреть файл

@ -1415,6 +1415,13 @@ static void i801_add_tco(struct i801_priv *priv)
} }
#ifdef CONFIG_ACPI #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 static acpi_status
i801_acpi_io_handler(u32 function, acpi_physical_address address, u32 bits, i801_acpi_io_handler(u32 function, acpi_physical_address address, u32 bits,
u64 *value, void *handler_context, void *region_context) 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); mutex_lock(&priv->acpi_lock);
if (!priv->acpi_reserved) { if (!priv->acpi_reserved && i801_acpi_is_smbus_ioport(priv, address)) {
priv->acpi_reserved = true; priv->acpi_reserved = true;
dev_warn(&pdev->dev, "BIOS is accessing SMBus registers\n"); 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->pos = pd->msg->len;
pd->stop_after_dma = true; 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); 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); 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) bool do_init)
{ {
if (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 */ /* Enable all interrupts to begin with */
iic_wr(pd, ICIC, ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE); iic_wr(pd, ICIC, ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE);
return 0;
} }
static int poll_dte(struct sh_mobile_i2c_data *pd) 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->send_stop = i == num - 1 || msg->flags & I2C_M_STOP;
pd->stop_after_dma = false; pd->stop_after_dma = false;
err = start_ch(pd, msg, do_start); start_ch(pd, msg, do_start);
if (err)
break;
if (do_start) if (do_start)
i2c_op(pd, OP_START, 0); 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, timeout = wait_event_timeout(pd->wait,
pd->sr & (ICSR_TACK | SW_DONE), pd->sr & (ICSR_TACK | SW_DONE),
adapter->timeout); 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) { if (!timeout) {
dev_err(pd->dev, "Transfer request timed out\n"); dev_err(pd->dev, "Transfer request timed out\n");
if (pd->dma_direction != DMA_NONE) 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); EXPORT_SYMBOL_GPL(i2c_get_dma_safe_msg_buf);
/** /**
* i2c_release_dma_safe_msg_buf - release DMA safe buffer and sync with i2c_msg * i2c_put_dma_safe_msg_buf - release DMA safe buffer and sync with i2c_msg
* @msg: the message to be synced with
* @buf: the buffer obtained from i2c_get_dma_safe_msg_buf(). May be NULL. * @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) if (!buf || buf == msg->buf)
return; return;
if (msg->flags & I2C_M_RD) if (xferred && msg->flags & I2C_M_RD)
memcpy(msg->buf, buf, msg->len); memcpy(msg->buf, buf, msg->len);
kfree(buf); 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_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>");
MODULE_DESCRIPTION("I2C-Bus main module"); 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); 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); int i2c_handle_smbus_host_notify(struct i2c_adapter *adap, unsigned short addr);
/** /**