Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 701dc207 authored by Ricardo Ribalda Delgado's avatar Ricardo Ribalda Delgado Committed by Wolfram Sang
Browse files

i2c: piix4: Avoid race conditions with IMC

On AMD's SB800 and upwards, the SMBus is shared with the Integrated
Micro Controller (IMC).

The platform provides a hardware semaphore to avoid race conditions
among them. (Check page 288 of the SB800-Series Southbridges Register
Reference Guide http://support.amd.com/TechDocs/45482.pdf

)

Without this patch, many access to the SMBus end with an invalid
transaction or even with the bus stalled.

Reported-by: default avatarAlexandre Desnoyers <alex@qtec.com>
Signed-off-by: default avatarRicardo Ribalda Delgado <ricardo.ribalda@gmail.com>
Reviewed-by: default avatarAndy Shevchenko <andy.shevchenko@gmail.com&gt;:>
Signed-off-by: default avatarWolfram Sang <wsa@the-dreams.de>
parent 2659161d
Loading
Loading
Loading
Loading
+22 −0
Original line number Diff line number Diff line
@@ -585,10 +585,29 @@ static s32 piix4_access_sb800(struct i2c_adapter *adap, u16 addr,
		 u8 command, int size, union i2c_smbus_data *data)
{
	struct i2c_piix4_adapdata *adapdata = i2c_get_adapdata(adap);
	unsigned short piix4_smba = adapdata->smba;
	int retries = MAX_TIMEOUT;
	int smbslvcnt;
	u8 smba_en_lo;
	u8 port;
	int retval;

	/* Request the SMBUS semaphore, avoid conflicts with the IMC */
	smbslvcnt  = inb_p(SMBSLVCNT);
	do {
		outb_p(smbslvcnt | 0x10, SMBSLVCNT);

		/* Check the semaphore status */
		smbslvcnt  = inb_p(SMBSLVCNT);
		if (smbslvcnt & 0x10)
			break;

		usleep_range(1000, 2000);
	} while (--retries);
	/* SMBus is still owned by the IMC, we give up */
	if (!retries)
		return -EBUSY;

	mutex_lock(&piix4_mutex_sb800);

	outb_p(piix4_port_sel_sb800, SB800_PIIX4_SMB_IDX);
@@ -606,6 +625,9 @@ static s32 piix4_access_sb800(struct i2c_adapter *adap, u16 addr,

	mutex_unlock(&piix4_mutex_sb800);

	/* Release the semaphore */
	outb_p(smbslvcnt | 0x20, SMBSLVCNT);

	return retval;
}