From: Jean Delvare <khali-PUYAD+kWke1g9hUCZPvPmw@public.gmane.org>
To: Daniel Kurtz <djkurtz-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
Cc: Ben Dooks <ben-linux-elnMNo+KYs3YtjvyW6yDsg@public.gmane.org>,
Wolfram Sang <w.sang-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>,
Seth Heasley
<seth.heasley-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>,
Olof Johansson <olof-nZhT3qVonbNeoWH0uzbU5w@public.gmane.org>,
Benson Leung <bleung-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>,
linux-i2c-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Subject: Re: [PATCH 7/8 v3] i2c: i801: enable irq for i801 smbus transactions
Date: Wed, 4 Jul 2012 17:48:41 +0200 [thread overview]
Message-ID: <20120704174841.68dc6587@endymion.delvare> (raw)
In-Reply-To: <1340805255-8041-8-git-send-email-djkurtz-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
Hi Daniel,
On Wed, 27 Jun 2012 21:54:14 +0800, Daniel Kurtz wrote:
> Add a new 'feature' to i2c-i801 to enable using i801 interrupts.
> When the feature is enabled, then an isr is installed for the device's
> pci irq.
>
> An I2C/SMBus transaction is always terminated by one of the following
> interrupt sources: FAILED, BUS_ERR, DEV_ERR, or on success: INTR.
>
> When the isr fires for one of these cases, it sets the ->status variable
> and wakes up the waitq. The waitq then saves off the status code, and
> clears ->status (in preparation for some future transaction).
> The SMBus controller generates an INTR irq at the end of each
> transaction where INTREN was set in the HST_CNT register.
>
> No locking is needed around accesses to priv->status since all writes to
> it are serialized: it is only ever set once in the isr at the end of a
> transaction, and cleared while no irqs can occur. In addition, the I2C
> adapter lock guarantees that entire I2C transactions for a single
> adapter are always serialized.
>
> For this patch, the INTREN bit is set only for SMBus block, byte and word
> transactions, but not for I2C reads or writes. The use of the DS
> (BYTE_DONE) interrupt with byte-by-byte I2C transactions is implemented in
> a subsequent patch.
>
> The interrupt feature has only been enabled for COUGARPOINT hardware.
> In addition, it is disabled if SMBus is using the SMI# interrupt.
>
> Signed-off-by: Daniel Kurtz <djkurtz-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
> ---
> drivers/i2c/busses/i2c-i801.c | 93 ++++++++++++++++++++++++++++++++++++++---
> 1 files changed, 87 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
> index 6fa2a0b..6bfedc0 100644
> --- a/drivers/i2c/busses/i2c-i801.c
> +++ b/drivers/i2c/busses/i2c-i801.c
> @@ -60,10 +60,12 @@
> Block process call transaction no
> I2C block read transaction yes (doesn't use the block buffer)
> Slave mode no
> + Interrupt processing yes
>
> See the file Documentation/i2c/busses/i2c-i801 for details.
> */
>
> +#include <linux/interrupt.h>
> #include <linux/module.h>
> #include <linux/pci.h>
> #include <linux/kernel.h>
> @@ -76,6 +78,7 @@
> #include <linux/io.h>
> #include <linux/dmi.h>
> #include <linux/slab.h>
> +#include <linux/wait.h>
>
> /* I801 SMBus address offsets */
> #define SMBHSTSTS(p) (0 + (p)->smba)
> @@ -134,8 +137,9 @@
> #define STATUS_ERROR_FLAGS (SMBHSTSTS_FAILED | SMBHSTSTS_BUS_ERR | \
> SMBHSTSTS_DEV_ERR)
>
> -#define STATUS_FLAGS (SMBHSTSTS_BYTE_DONE | SMBHSTSTS_INTR | \
> - STATUS_ERROR_FLAGS)
> +#define STATUS_RESULT_FLAGS (SMBHSTSTS_INTR | STATUS_ERROR_FLAGS)
I see no good reason to introduce this, you use it only once and
STATUS_FLAGS would work as well there.
> +
> +#define STATUS_FLAGS (SMBHSTSTS_BYTE_DONE | STATUS_RESULT_FLAGS)
>
> /* Older devices have their ID defined in <linux/pci_ids.h> */
> #define PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS 0x1c22
> @@ -155,6 +159,10 @@ struct i801_priv {
> unsigned char original_hstcfg;
> struct pci_dev *pci_dev;
> unsigned int features;
> +
> + /* isr processing */
> + wait_queue_head_t waitq;
> + u8 status;
> };
>
> static struct pci_driver i801_driver;
> @@ -163,6 +171,7 @@ static struct pci_driver i801_driver;
> #define FEATURE_BLOCK_BUFFER (1 << 1)
> #define FEATURE_BLOCK_PROC (1 << 2)
> #define FEATURE_I2C_BLOCK_READ (1 << 3)
> +#define FEATURE_IRQ (1 << 4)
> /* Not really a feature, but it's convenient to handle it as such */
> #define FEATURE_IDF (1 << 15)
>
> @@ -171,6 +180,7 @@ static const char *i801_feature_names[] = {
> "Block buffer",
> "Block process call",
> "I2C block read",
> + "Interrupt",
> };
>
> static unsigned int disable_features;
> @@ -211,7 +221,12 @@ static int i801_check_post(struct i801_priv *priv, int status, int timeout)
> {
> int result = 0;
>
> - /* If the SMBus is still busy, we give up */
> + /*
> + * If the SMBus is still busy, we give up
> + * Note: This timeout condition only happens when using polling
> + * transactions. For interrupt operation, NAK/timeout is indicated by
> + * DEV_ERR.
> + */
> if (timeout) {
> dev_err(&priv->pci_dev->dev, "Transaction timeout\n");
> /* try to stop the current command */
> @@ -287,6 +302,14 @@ static int i801_transaction(struct i801_priv *priv, int xact)
> if (result < 0)
> return result;
>
> + if (priv->features & FEATURE_IRQ) {
> + outb_p(xact | SMBHSTCNT_INTREN | SMBHSTCNT_START,
> + SMBHSTCNT(priv));
> + wait_event(priv->waitq, (status = priv->status));
> + priv->status = 0;
> + return i801_check_post(priv, status, 0);
> + }
> +
> /* the current contents of SMBHSTCNT can be overwritten, since PEC,
> * SMBSCMD are passed in xact */
> outb_p(xact | SMBHSTCNT_START, SMBHSTCNT(priv));
> @@ -341,6 +364,37 @@ static int i801_block_transaction_by_block(struct i801_priv *priv,
> }
>
> /*
> + * i801 signals transaction completion with one of these interrupts:
> + * INTR - Success
> + * DEV_ERR - Invalid command, NAK or communication timeout
> + * BUS_ERR - SMI# transaction collision
> + * FAILED - transaction was canceled due to a KILL request
> + * When any of these occur, update ->status and wake up the waitq.
> + * ->status must be cleared before kicking off the next transaction.
> + */
> +static irqreturn_t i801_isr(int irq, void *dev_id)
> +{
> + struct i801_priv *priv = dev_id;
> + u8 hststs;
It's named "status" everywhere else, now that the confusion with the
PCI status register is no longer possible, I would advise that we stick
with "status".
> +
> + hststs = inb_p(SMBHSTSTS(priv));
> + dev_dbg(&priv->pci_dev->dev, "irq: hststs = %02x\n", hststs);
> +
> + /*
> + * Clear irq sources and report transaction result.
> + * ->status must be cleared before the next transaction is started.
> + */
> + hststs &= STATUS_RESULT_FLAGS;
> + if (hststs) {
> + outb_p(hststs, SMBHSTSTS(priv));
> + priv->status |= hststs;
> + wake_up(&priv->waitq);
> + }
Your original patch did handle shared interrupts, I don't think this
version does. We are supposed to return IRQ_NONE if the interrupt
wasn't ours, aren't we? Plus, logging the register value when the
interrupt isn't ours fills the kernel log very fast for heavily shared
interrupts (as is the case on my old ICH3-M laptop.)
> +
> + return IRQ_HANDLED;
> +}
> +
> +/*
> * For "byte-by-byte" block transactions:
> * I2C write uses cmd=I801_BLOCK_DATA, I2C_EN=1
> * I2C read uses cmd=I801_I2C_BLOCK_DATA
> @@ -801,6 +855,10 @@ static int __devinit i801_probe(struct pci_dev *dev,
> break;
> }
>
> + /* IRQ processing only tested on CougarPoint PCH */
> + if (dev->device == PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS)
> + priv->features |= FEATURE_IRQ;
> +
> /* Disable features on user request */
> for (i = 0; i < ARRAY_SIZE(i801_feature_names); i++) {
> if (priv->features & disable_features & (1 << i))
> @@ -848,16 +906,31 @@ static int __devinit i801_probe(struct pci_dev *dev,
> }
> pci_write_config_byte(priv->pci_dev, SMBHSTCFG, temp);
>
> - if (temp & SMBHSTCFG_SMB_SMI_EN)
> + if (temp & SMBHSTCFG_SMB_SMI_EN) {
> dev_dbg(&dev->dev, "SMBus using interrupt SMI#\n");
> - else
> + /* Disable SMBus interrupt feature if SMBus using SMI# */
> + priv->features &= ~FEATURE_IRQ;
> + } else {
> dev_dbg(&dev->dev, "SMBus using PCI Interrupt\n");
> + }
>
> /* Clear special mode bits */
> if (priv->features & (FEATURE_SMBUS_PEC | FEATURE_BLOCK_BUFFER))
> outb_p(inb_p(SMBAUXCTL(priv)) &
> ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), SMBAUXCTL(priv));
>
> + if (priv->features & FEATURE_IRQ) {
> + init_waitqueue_head(&priv->waitq);
> +
> + err = request_irq(dev->irq, i801_isr, IRQF_SHARED,
> + i801_driver.name, priv);
> + if (err) {
> + dev_err(&dev->dev, "Failed to allocate irq %d: %d\n",
> + dev->irq, err);
> + goto exit_release;
> + }
> + }
> +
> /* set up the sysfs linkage to our parent device */
> priv->adapter.dev.parent = &dev->dev;
>
> @@ -869,14 +942,18 @@ static int __devinit i801_probe(struct pci_dev *dev,
> err = i2c_add_adapter(&priv->adapter);
> if (err) {
> dev_err(&dev->dev, "Failed to add SMBus adapter\n");
> - goto exit_release;
> + goto exit_free_irq;
> }
>
> i801_probe_optional_slaves(priv);
>
> pci_set_drvdata(dev, priv);
> +
> return 0;
>
> +exit_free_irq:
> + if (priv->features & FEATURE_IRQ)
> + free_irq(dev->irq, priv);
> exit_release:
> pci_release_region(dev, SMBBAR);
> exit:
> @@ -891,6 +968,10 @@ static void __devexit i801_remove(struct pci_dev *dev)
> i2c_del_adapter(&priv->adapter);
> pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg);
> pci_release_region(dev, SMBBAR);
> +
> + if (priv->features & FEATURE_IRQ)
> + free_irq(dev->irq, priv);
> +
It should make no difference in practice, but I would prefer that we
swamp these, to have the exact same order as in the error path of the
probe function.
> pci_set_drvdata(dev, NULL);
> kfree(priv);
> /*
--
Jean Delvare
next prev parent reply other threads:[~2012-07-04 15:48 UTC|newest]
Thread overview: 32+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-06-27 13:54 [PATCH 0/8 v3] i2c: i801: enable irq Daniel Kurtz
2012-06-27 13:54 ` [PATCH 1/8 v3] i2c: i801: refactor use of LAST_BYTE i801_block_transaction_byte_by_byte Daniel Kurtz
2012-06-27 14:39 ` Jean Delvare
2012-06-27 13:54 ` [PATCH 2/8 v3] i2c: i801: optimize waiting for HWPEC to finish Daniel Kurtz
2012-06-27 14:58 ` Jean Delvare
2012-06-27 13:54 ` [PATCH 3/8 v3] i2c: i801: check INTR after every transaction Daniel Kurtz
[not found] ` <1340805255-8041-4-git-send-email-djkurtz-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
2012-06-27 16:07 ` Jean Delvare
2012-06-28 7:51 ` Daniel Kurtz
[not found] ` <CAGS+omCoto4djKuZUooeD2A-szjrH4e9=YJCptR_raOdQ8g3-A-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2012-06-28 11:36 ` Jean Delvare
[not found] ` <20120627180724.762f854a-R0o5gVi9kd7kN2dkZ6Wm7A@public.gmane.org>
2012-07-01 21:20 ` Jean Delvare
[not found] ` <20120701232051.308c03d1-R0o5gVi9kd7kN2dkZ6Wm7A@public.gmane.org>
2012-07-02 1:19 ` Daniel Kurtz
[not found] ` <CAGS+omDV_ynBL-PN0qmLmDRiHGbQFf+TwqC2-+KJY8zy9FDhrA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2012-07-02 10:08 ` Jean Delvare
[not found] ` <20120702120814.47d71bc5-R0o5gVi9kd7kN2dkZ6Wm7A@public.gmane.org>
2012-07-02 15:16 ` Jean Delvare
2012-06-27 13:54 ` [PATCH 4/8 v3] i2c: i801: check and return errors during byte-by-byte transfers Daniel Kurtz
[not found] ` <1340805255-8041-5-git-send-email-djkurtz-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
2012-06-27 16:51 ` Jean Delvare
2012-06-28 3:46 ` Daniel Kurtz
[not found] ` <CAGS+omDkhA=dP0JP=4huQEwJ4j6YqZWJ+mFsJv+eeGMBRpu5fQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2012-06-28 7:08 ` Jean Delvare
[not found] ` <1340805255-8041-1-git-send-email-djkurtz-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
2012-06-27 13:54 ` [PATCH 5/8 v3] i2c: i801: rename some SMBHSTCNT bit constants Daniel Kurtz
[not found] ` <1340805255-8041-6-git-send-email-djkurtz-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
2012-06-27 17:01 ` Jean Delvare
2012-06-27 13:54 ` [PATCH 6/8 v3] i2c: i801: drop ENABLE_INT9 Daniel Kurtz
[not found] ` <1340805255-8041-7-git-send-email-djkurtz-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
2012-06-28 7:04 ` Jean Delvare
2012-06-27 13:54 ` [PATCH 7/8 v3] i2c: i801: enable irq for i801 smbus transactions Daniel Kurtz
[not found] ` <1340805255-8041-8-git-send-email-djkurtz-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
2012-07-04 15:48 ` Jean Delvare [this message]
2012-07-04 20:16 ` Jean Delvare
[not found] ` <20120704221600.416d4475-R0o5gVi9kd7kN2dkZ6Wm7A@public.gmane.org>
2012-07-05 4:31 ` Daniel Kurtz
2012-07-05 8:10 ` Jean Delvare
2012-07-05 10:29 ` Jean Delvare
2012-07-06 10:28 ` Daniel Kurtz
[not found] ` <CAGS+omAgVLumYvOssHfdjELXixMdfRSxSj003xPzQ5v4h_D-mA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2012-07-06 11:55 ` Jean Delvare
2012-06-27 13:54 ` [PATCH 8/8 v3] i2c: i801: enable irq for byte_by_byte transactions Daniel Kurtz
2012-07-05 14:46 ` Jean Delvare
[not found] ` <1340805255-8041-9-git-send-email-djkurtz-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
2012-07-08 11:53 ` Jean Delvare
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20120704174841.68dc6587@endymion.delvare \
--to=khali-puyad+kwke1g9huczpvpmw@public.gmane.org \
--cc=ben-linux-elnMNo+KYs3YtjvyW6yDsg@public.gmane.org \
--cc=bleung-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org \
--cc=djkurtz-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org \
--cc=linux-i2c-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
--cc=linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
--cc=olof-nZhT3qVonbNeoWH0uzbU5w@public.gmane.org \
--cc=seth.heasley-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org \
--cc=w.sang-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).