Commit 636752bcb5177a301d0266270661581de8624828

Authored by Daniel Kurtz
Committed by Jean Delvare
1 parent 6cad93c4bb

i2c-i801: Enable IRQ for SMBus transactions

Add a new 'feature' to i2c-i801 to enable using PCI 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 interrupts 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@chromium.org>
Signed-off-by: Jean Delvare <khali@linux-fr.org>

Showing 2 changed files with 105 additions and 7 deletions Side-by-side Diff

Documentation/i2c/busses/i2c-i801
... ... @@ -38,9 +38,10 @@
38 38 Disable selected features normally supported by the device. This makes it
39 39 possible to work around possible driver or hardware bugs if the feature in
40 40 question doesn't work as intended for whatever reason. Bit values:
41   - 1 disable SMBus PEC
42   - 2 disable the block buffer
43   - 8 disable the I2C block read functionality
  41 + 0x01 disable SMBus PEC
  42 + 0x02 disable the block buffer
  43 + 0x08 disable the I2C block read functionality
  44 + 0x10 don't use interrupts
44 45  
45 46  
46 47 Description
... ... @@ -84,6 +85,12 @@
84 85 -----------------
85 86  
86 87 The 82801DB (ICH4) and later chips support several SMBus 2.0 features.
  88 +
  89 +
  90 +Interrupt Support
  91 +-----------------
  92 +
  93 +PCI interrupt support is supported on the 82801EB (ICH5) and later chips.
87 94  
88 95  
89 96 Hidden ICH SMBus
drivers/i2c/busses/i2c-i801.c
... ... @@ -60,10 +60,12 @@
60 60 Block process call transaction no
61 61 I2C block read transaction yes (doesn't use the block buffer)
62 62 Slave mode no
  63 + Interrupt processing yes
63 64  
64 65 See the file Documentation/i2c/busses/i2c-i801 for details.
65 66 */
66 67  
  68 +#include <linux/interrupt.h>
67 69 #include <linux/module.h>
68 70 #include <linux/pci.h>
69 71 #include <linux/kernel.h>
... ... @@ -76,6 +78,7 @@
76 78 #include <linux/io.h>
77 79 #include <linux/dmi.h>
78 80 #include <linux/slab.h>
  81 +#include <linux/wait.h>
79 82  
80 83 /* I801 SMBus address offsets */
81 84 #define SMBHSTSTS(p) (0 + (p)->smba)
82 85  
... ... @@ -91,8 +94,12 @@
91 94  
92 95 /* PCI Address Constants */
93 96 #define SMBBAR 4
  97 +#define SMBPCISTS 0x006
94 98 #define SMBHSTCFG 0x040
95 99  
  100 +/* Host status bits for SMBPCISTS */
  101 +#define SMBPCISTS_INTS 0x08
  102 +
96 103 /* Host configuration bits for SMBHSTCFG */
97 104 #define SMBHSTCFG_HST_EN 1
98 105 #define SMBHSTCFG_SMB_SMI_EN 2
... ... @@ -155,6 +162,10 @@
155 162 unsigned char original_hstcfg;
156 163 struct pci_dev *pci_dev;
157 164 unsigned int features;
  165 +
  166 + /* isr processing */
  167 + wait_queue_head_t waitq;
  168 + u8 status;
158 169 };
159 170  
160 171 static struct pci_driver i801_driver;
... ... @@ -163,6 +174,7 @@
163 174 #define FEATURE_BLOCK_BUFFER (1 << 1)
164 175 #define FEATURE_BLOCK_PROC (1 << 2)
165 176 #define FEATURE_I2C_BLOCK_READ (1 << 3)
  177 +#define FEATURE_IRQ (1 << 4)
166 178 /* Not really a feature, but it's convenient to handle it as such */
167 179 #define FEATURE_IDF (1 << 15)
168 180  
... ... @@ -171,6 +183,7 @@
171 183 "Block buffer",
172 184 "Block process call",
173 185 "I2C block read",
  186 + "Interrupt",
174 187 };
175 188  
176 189 static unsigned int disable_features;
... ... @@ -215,7 +228,12 @@
215 228 {
216 229 int result = 0;
217 230  
218   - /* If the SMBus is still busy, we give up */
  231 + /*
  232 + * If the SMBus is still busy, we give up
  233 + * Note: This timeout condition only happens when using polling
  234 + * transactions. For interrupt operation, NAK/timeout is indicated by
  235 + * DEV_ERR.
  236 + */
219 237 if (unlikely(status < 0)) {
220 238 dev_err(&priv->pci_dev->dev, "Transaction timeout\n");
221 239 /* try to stop the current command */
... ... @@ -305,6 +323,14 @@
305 323 if (result < 0)
306 324 return result;
307 325  
  326 + if (priv->features & FEATURE_IRQ) {
  327 + outb_p(xact | SMBHSTCNT_INTREN | SMBHSTCNT_START,
  328 + SMBHSTCNT(priv));
  329 + wait_event(priv->waitq, (status = priv->status));
  330 + priv->status = 0;
  331 + return i801_check_post(priv, status);
  332 + }
  333 +
308 334 /* the current contents of SMBHSTCNT can be overwritten, since PEC,
309 335 * SMBSCMD are passed in xact */
310 336 outb_p(xact | SMBHSTCNT_START, SMBHSTCNT(priv));
... ... @@ -348,6 +374,44 @@
348 374 }
349 375  
350 376 /*
  377 + * i801 signals transaction completion with one of these interrupts:
  378 + * INTR - Success
  379 + * DEV_ERR - Invalid command, NAK or communication timeout
  380 + * BUS_ERR - SMI# transaction collision
  381 + * FAILED - transaction was canceled due to a KILL request
  382 + * When any of these occur, update ->status and wake up the waitq.
  383 + * ->status must be cleared before kicking off the next transaction.
  384 + */
  385 +static irqreturn_t i801_isr(int irq, void *dev_id)
  386 +{
  387 + struct i801_priv *priv = dev_id;
  388 + u16 pcists;
  389 + u8 status;
  390 +
  391 + /* Confirm this is our interrupt */
  392 + pci_read_config_word(priv->pci_dev, SMBPCISTS, &pcists);
  393 + if (!(pcists & SMBPCISTS_INTS))
  394 + return IRQ_NONE;
  395 +
  396 + status = inb_p(SMBHSTSTS(priv));
  397 + if (status != 0x42)
  398 + dev_dbg(&priv->pci_dev->dev, "irq: status = %02x\n", status);
  399 +
  400 + /*
  401 + * Clear irq sources and report transaction result.
  402 + * ->status must be cleared before the next transaction is started.
  403 + */
  404 + status &= SMBHSTSTS_INTR | STATUS_ERROR_FLAGS;
  405 + if (status) {
  406 + outb_p(status, SMBHSTSTS(priv));
  407 + priv->status |= status;
  408 + wake_up(&priv->waitq);
  409 + }
  410 +
  411 + return IRQ_HANDLED;
  412 +}
  413 +
  414 +/*
351 415 * For "byte-by-byte" block transactions:
352 416 * I2C write uses cmd=I801_BLOCK_DATA, I2C_EN=1
353 417 * I2C read uses cmd=I801_I2C_BLOCK_DATA
... ... @@ -799,6 +863,10 @@
799 863 break;
800 864 }
801 865  
  866 + /* IRQ processing only tested on CougarPoint PCH */
  867 + if (dev->device == PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS)
  868 + priv->features |= FEATURE_IRQ;
  869 +
802 870 /* Disable features on user request */
803 871 for (i = 0; i < ARRAY_SIZE(i801_feature_names); i++) {
804 872 if (priv->features & disable_features & (1 << i))
805 873  
806 874  
807 875  
... ... @@ -846,16 +914,31 @@
846 914 }
847 915 pci_write_config_byte(priv->pci_dev, SMBHSTCFG, temp);
848 916  
849   - if (temp & SMBHSTCFG_SMB_SMI_EN)
  917 + if (temp & SMBHSTCFG_SMB_SMI_EN) {
850 918 dev_dbg(&dev->dev, "SMBus using interrupt SMI#\n");
851   - else
  919 + /* Disable SMBus interrupt feature if SMBus using SMI# */
  920 + priv->features &= ~FEATURE_IRQ;
  921 + } else {
852 922 dev_dbg(&dev->dev, "SMBus using PCI Interrupt\n");
  923 + }
853 924  
854 925 /* Clear special mode bits */
855 926 if (priv->features & (FEATURE_SMBUS_PEC | FEATURE_BLOCK_BUFFER))
856 927 outb_p(inb_p(SMBAUXCTL(priv)) &
857 928 ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), SMBAUXCTL(priv));
858 929  
  930 + if (priv->features & FEATURE_IRQ) {
  931 + init_waitqueue_head(&priv->waitq);
  932 +
  933 + err = request_irq(dev->irq, i801_isr, IRQF_SHARED,
  934 + i801_driver.name, priv);
  935 + if (err) {
  936 + dev_err(&dev->dev, "Failed to allocate irq %d: %d\n",
  937 + dev->irq, err);
  938 + goto exit_release;
  939 + }
  940 + }
  941 +
859 942 /* set up the sysfs linkage to our parent device */
860 943 priv->adapter.dev.parent = &dev->dev;
861 944  
862 945  
863 946  
... ... @@ -867,14 +950,18 @@
867 950 err = i2c_add_adapter(&priv->adapter);
868 951 if (err) {
869 952 dev_err(&dev->dev, "Failed to add SMBus adapter\n");
870   - goto exit_release;
  953 + goto exit_free_irq;
871 954 }
872 955  
873 956 i801_probe_optional_slaves(priv);
874 957  
875 958 pci_set_drvdata(dev, priv);
  959 +
876 960 return 0;
877 961  
  962 +exit_free_irq:
  963 + if (priv->features & FEATURE_IRQ)
  964 + free_irq(dev->irq, priv);
878 965 exit_release:
879 966 pci_release_region(dev, SMBBAR);
880 967 exit:
881 968  
... ... @@ -888,7 +975,11 @@
888 975  
889 976 i2c_del_adapter(&priv->adapter);
890 977 pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg);
  978 +
  979 + if (priv->features & FEATURE_IRQ)
  980 + free_irq(dev->irq, priv);
891 981 pci_release_region(dev, SMBBAR);
  982 +
892 983 pci_set_drvdata(dev, NULL);
893 984 kfree(priv);
894 985 /*