|
@@ -144,6 +144,10 @@
|
|
/* TCO configuration bits for TCOCTL */
|
|
/* TCO configuration bits for TCOCTL */
|
|
#define TCOCTL_EN 0x0100
|
|
#define TCOCTL_EN 0x0100
|
|
|
|
|
|
|
|
+/* Auxiliary status register bits, ICH4+ only */
|
|
|
|
+#define SMBAUXSTS_CRCE 1
|
|
|
|
+#define SMBAUXSTS_STCO 2
|
|
|
|
+
|
|
/* Auxiliary control register bits, ICH4+ only */
|
|
/* Auxiliary control register bits, ICH4+ only */
|
|
#define SMBAUXCTL_CRC 1
|
|
#define SMBAUXCTL_CRC 1
|
|
#define SMBAUXCTL_E32B 2
|
|
#define SMBAUXCTL_E32B 2
|
|
@@ -305,6 +309,29 @@ static int i801_check_pre(struct i801_priv *priv)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /*
|
|
|
|
+ * Clear CRC status if needed.
|
|
|
|
+ * During normal operation, i801_check_post() takes care
|
|
|
|
+ * of it after every operation. We do it here only in case
|
|
|
|
+ * the hardware was already in this state when the driver
|
|
|
|
+ * started.
|
|
|
|
+ */
|
|
|
|
+ if (priv->features & FEATURE_SMBUS_PEC) {
|
|
|
|
+ status = inb_p(SMBAUXSTS(priv)) & SMBAUXSTS_CRCE;
|
|
|
|
+ if (status) {
|
|
|
|
+ dev_dbg(&priv->pci_dev->dev,
|
|
|
|
+ "Clearing aux status flags (%02x)\n", status);
|
|
|
|
+ outb_p(status, SMBAUXSTS(priv));
|
|
|
|
+ status = inb_p(SMBAUXSTS(priv)) & SMBAUXSTS_CRCE;
|
|
|
|
+ if (status) {
|
|
|
|
+ dev_err(&priv->pci_dev->dev,
|
|
|
|
+ "Failed clearing aux status flags (%02x)\n",
|
|
|
|
+ status);
|
|
|
|
+ return -EBUSY;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -348,8 +375,30 @@ static int i801_check_post(struct i801_priv *priv, int status)
|
|
dev_err(&priv->pci_dev->dev, "Transaction failed\n");
|
|
dev_err(&priv->pci_dev->dev, "Transaction failed\n");
|
|
}
|
|
}
|
|
if (status & SMBHSTSTS_DEV_ERR) {
|
|
if (status & SMBHSTSTS_DEV_ERR) {
|
|
- result = -ENXIO;
|
|
|
|
- dev_dbg(&priv->pci_dev->dev, "No response\n");
|
|
|
|
|
|
+ /*
|
|
|
|
+ * This may be a PEC error, check and clear it.
|
|
|
|
+ *
|
|
|
|
+ * AUXSTS is handled differently from HSTSTS.
|
|
|
|
+ * For HSTSTS, i801_isr() or i801_wait_intr()
|
|
|
|
+ * has already cleared the error bits in hardware,
|
|
|
|
+ * and we are passed a copy of the original value
|
|
|
|
+ * in "status".
|
|
|
|
+ * For AUXSTS, the hardware register is left
|
|
|
|
+ * for us to handle here.
|
|
|
|
+ * This is asymmetric, slightly iffy, but safe,
|
|
|
|
+ * since all this code is serialized and the CRCE
|
|
|
|
+ * bit is harmless as long as it's cleared before
|
|
|
|
+ * the next operation.
|
|
|
|
+ */
|
|
|
|
+ if ((priv->features & FEATURE_SMBUS_PEC) &&
|
|
|
|
+ (inb_p(SMBAUXSTS(priv)) & SMBAUXSTS_CRCE)) {
|
|
|
|
+ outb_p(SMBAUXSTS_CRCE, SMBAUXSTS(priv));
|
|
|
|
+ result = -EBADMSG;
|
|
|
|
+ dev_dbg(&priv->pci_dev->dev, "PEC error\n");
|
|
|
|
+ } else {
|
|
|
|
+ result = -ENXIO;
|
|
|
|
+ dev_dbg(&priv->pci_dev->dev, "No response\n");
|
|
|
|
+ }
|
|
}
|
|
}
|
|
if (status & SMBHSTSTS_BUS_ERR) {
|
|
if (status & SMBHSTSTS_BUS_ERR) {
|
|
result = -EAGAIN;
|
|
result = -EAGAIN;
|