Index: sys/dev/pci/amdpm_smbus.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/amdpm_smbus.c,v
retrieving revision 1.16
diff -u -r1.16 amdpm_smbus.c
--- sys/dev/pci/amdpm_smbus.c	3 Feb 2009 16:27:13 -0000	1.16
+++ sys/dev/pci/amdpm_smbus.c	23 Feb 2010 00:52:52 -0000
@@ -187,7 +187,26 @@
 	sc->sc_smbus_slaveaddr  = addr;
 	uint8_t *p = vbuf;
 	int rv;
-	
+	/* sleep for half a second? */
+	int count = 500;
+	uint16_t data;
+	int off = (sc->sc_nforce ? 0xe0 : 0);
+
+	/* Check if the controller is busy */
+	while (count--) {
+		DELAY(10);
+
+		data = bus_space_read_2(sc->sc_iot, sc->sc_ioh,
+		    AMDPM_8111_SMBUS_STAT - off);
+		if (!(data & AMDPM_GSR_HST_STS) && !(data & AMDPM_GSR_SMB_BUSY_STS))
+			break;
+	}
+	if  ((data & AMDPM_GSR_HST_STS) || (data & AMDPM_GSR_SMB_BUSY_STS)) {
+		aprint_error_dev(&sc->sc_dev,
+			"Timeout waiting for controller, aborting transaction\n");
+		goto abort;
+	}
+
 	if ((cmdlen == 0) && (buflen == 0))
 		return amdpm_smbus_quick(sc, op);
 
@@ -217,23 +236,74 @@
 					   op);
 	
 	return -1;  
+
+abort:
+	/* Abort the transaction */
+	bus_space_write_2(sc->sc_iot, sc->sc_ioh,
+	    AMDPM_8111_SMBUS_CTRL - off, AMDPM_GCR_ABORT);
+
+	/* Wait 10 miliseconds */
+	DELAY(10 * 1000);
+
+	/* Clear the status reg */
+	amdpm_smbus_clear_gsr(sc);
+
+	/* Hope to do it right next time */
+	return -1;
+
 }
 
 static int 
 amdpm_smbus_check_done(struct amdpm_softc *sc, i2c_op_t op)
 {  
         int i;
+	int off = (sc->sc_nforce ? 0xe0 : 0);
+	uint16_t data;
+
+	/* Wait for one ms to give the chip a chance to actually do something */
+	DELAY(1000);
 
-	for (i = 0; i < 1000; i++) {
 	/* check gsr and wait till cycle is done */
-		uint16_t data = amdpm_smbus_get_gsr(sc);
-		if (data & AMDPM_8111_GSR_CYCLE_DONE)
-			return 0;	
+	for (i = 0; i < 1000; i++) {
+		data = amdpm_smbus_get_gsr(sc);
+		if (data & AMDPM_GSR_HCYC_STS)
+			return 0;
+		DELAY(100);
 	}
 
 	if (!(op & I2C_F_POLL))
 	    delay(1);
 
+	/* The transaction was not done, see if an error bit is set */
+	if ((data & AMDPM_GSR_PRERR_STS))
+		aprint_error_dev(&sc->sc_dev,
+			"WARNING: SMBus Protocol error (no response from device)\n");
+
+	if ((data & AMDPM_GSR_COL_STS))
+		aprint_error_dev(&sc->sc_dev, "WARNING: SMBus collision\n");
+
+	if ((data & AMDPM_GSR_TO_STS))
+		aprint_error_dev(&sc->sc_dev,
+			"WARNING: SMBus timeout (slave forced timeout)\n");
+
+	if ((data & AMDPM_GSR_SMB_BUSY_STS) || (data & AMDPM_GSR_HST_STS)) {
+		aprint_error_dev(&sc->sc_dev,
+			"WARNING: Aborting transaction because controller still busy\n");
+		/* abort the transaction if things go wrong */
+		bus_space_write_2(sc->sc_iot, sc->sc_ioh,
+		    AMDPM_8111_SMBUS_CTRL - off, AMDPM_GCR_ABORT);
+
+		int count = 0;
+		while (count++ < 500) {
+			DELAY(1000);
+			if (amdpm_smbus_get_gsr(sc) & AMDPM_GSR_ABRT_STS)
+				break;
+		}
+
+		/* Clear the status reg */
+		amdpm_smbus_clear_gsr(sc);
+	}
+
 	return -1;    
 }
 
@@ -246,6 +316,20 @@
 	int off = (sc->sc_nforce ? 0xe0 : 0);
 	bus_space_write_2(sc->sc_iot, sc->sc_ioh,
 	    AMDPM_8111_SMBUS_STAT - off, data);
+
+	/* sleep one msec */
+	DELAY(1000);
+	int count = 500;
+	while (count-- > 0) {
+		data = bus_space_read_2(sc->sc_iot, sc->sc_ioh,
+				AMDPM_8111_SMBUS_STAT - off);
+		if (data == 0)
+			return;
+		DELAY(10);
+	}
+
+	aprint_error_dev(&sc->sc_dev,
+		"WARNING: Clearing GSR failed (gsr = %d instead of 0)\n", data);
 }
 
 static uint16_t
Index: sys/dev/pci/amdpm_smbusreg.h
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/amdpm_smbusreg.h,v
retrieving revision 1.2
diff -u -r1.2 amdpm_smbusreg.h
--- sys/dev/pci/amdpm_smbusreg.h	3 Feb 2009 16:27:13 -0000	1.2
+++ sys/dev/pci/amdpm_smbusreg.h	23 Feb 2010 00:52:52 -0000
@@ -54,6 +54,17 @@
 #define AMDPM_8111_SMBUS_WRITE       0x0000 /* smbus write cycle indicator */
 #define AMDPM_8111_SMBUS_SEND        0x0000 /* smbus send cycle indicator */
 
+/* Bits in the SMBus Global Status Register */
+#define AMDPM_GSR_SMB_BUSY_STS       (1 << 11) /* SMBus busy */
+#define AMDPM_GSR_TO_STS             (1 <<  5) /* time out error status */
+#define AMDPM_GSR_HCYC_STS           (1 <<  4) /* host cycle complete status */
+#define AMDPM_GSR_HST_STS            (1 <<  3) /* host controller busy */
+#define AMDPM_GSR_PRERR_STS          (1 <<  2) /* protocol error status */
+#define AMDPM_GSR_COL_STS            (1 <<  1) /* host collision status */
+#define AMDPM_GSR_ABRT_STS           (1 <<  0) /* host transfer abort status */
+
+#define AMDPM_GCR_ABORT              (1 <<  5) /* abort current host transfer command */
+
 void      amdpm_smbus_attach(struct amdpm_softc *sc);
 
 #endif
