Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

i2c: pasemi: Improve error recovery

Add handling for all the missing error condition, and better recovery in
pasemi_smb_clear().

Reviewed-by: Alyssa Rosenzweig <alyssa@rosenzweig.io>
Reviewed-by: Neal Gompa <neal@gompa.dev>
Signed-off-by: Hector Martin <marcan@marcan.st>
Co-developed-by: Sven Peter <sven@svenpeter.dev>
Signed-off-by: Sven Peter <sven@svenpeter.dev>
Link: https://lore.kernel.org/r/20250427-pasemi-fixes-v3-3-af28568296c0@svenpeter.dev
Signed-off-by: Andi Shyti <andi.shyti@kernel.org>

authored by

Hector Martin and committed by
Andi Shyti
f4f64fa8 390b8f58

+54 -7
+54 -7
drivers/i2c/busses/i2c-pasemi-core.c
··· 87 87 reinit_completion(&smbus->irq_completion); 88 88 } 89 89 90 - static void pasemi_smb_clear(struct pasemi_smbus *smbus) 90 + static int pasemi_smb_clear(struct pasemi_smbus *smbus) 91 91 { 92 92 unsigned int status; 93 + int ret; 93 94 94 - status = reg_read(smbus, REG_SMSTA); 95 + /* First wait for the bus to go idle */ 96 + ret = readx_poll_timeout(ioread32, smbus->ioaddr + REG_SMSTA, 97 + status, !(status & (SMSTA_XIP | SMSTA_JAM)), 98 + USEC_PER_MSEC, 99 + USEC_PER_MSEC * PASEMI_TRANSFER_TIMEOUT_MS); 100 + 101 + if (ret < 0) { 102 + dev_err(smbus->dev, "Bus is still stuck (status 0x%08x)\n", status); 103 + return -EIO; 104 + } 105 + 106 + /* If any badness happened or there is data in the FIFOs, reset the FIFOs */ 107 + if ((status & (SMSTA_MRNE | SMSTA_JMD | SMSTA_MTO | SMSTA_TOM | SMSTA_MTN | SMSTA_MTA)) || 108 + !(status & SMSTA_MTE)) 109 + pasemi_reset(smbus); 110 + 111 + /* Clear the flags */ 95 112 reg_write(smbus, REG_SMSTA, status); 113 + 114 + return 0; 96 115 } 97 116 98 117 static int pasemi_smb_waitready(struct pasemi_smbus *smbus) ··· 149 130 } 150 131 } 151 132 133 + /* Controller timeout? */ 134 + if (status & SMSTA_TOM) { 135 + dev_err(smbus->dev, "Controller timeout, status 0x%08x\n", status); 136 + return -EIO; 137 + } 138 + 139 + /* Peripheral timeout? */ 140 + if (status & SMSTA_MTO) { 141 + dev_err(smbus->dev, "Peripheral timeout, status 0x%08x\n", status); 142 + return -ETIME; 143 + } 144 + 145 + /* Still stuck in a transaction? */ 146 + if (status & SMSTA_XIP) { 147 + dev_err(smbus->dev, "Bus stuck, status 0x%08x\n", status); 148 + return -EIO; 149 + } 150 + 151 + /* Arbitration loss? */ 152 + if (status & SMSTA_MTA) { 153 + dev_err(smbus->dev, "Arbitration loss, status 0x%08x\n", status); 154 + return -EBUSY; 155 + } 156 + 152 157 /* Got NACK? */ 153 - if (status & SMSTA_MTN) 158 + if (status & SMSTA_MTN) { 159 + dev_err(smbus->dev, "NACK, status 0x%08x\n", status); 154 160 return -ENXIO; 161 + } 155 162 156 163 /* Clear XEN */ 157 164 reg_write(smbus, REG_SMSTA, SMSTA_XEN); ··· 239 194 struct pasemi_smbus *smbus = adapter->algo_data; 240 195 int ret, i; 241 196 242 - pasemi_smb_clear(smbus); 243 - 244 - ret = 0; 197 + ret = pasemi_smb_clear(smbus); 198 + if (ret) 199 + return ret; 245 200 246 201 for (i = 0; i < num && !ret; i++) 247 202 ret = pasemi_i2c_xfer_msg(adapter, &msgs[i], (i == (num - 1))); ··· 262 217 addr <<= 1; 263 218 read_flag = read_write == I2C_SMBUS_READ; 264 219 265 - pasemi_smb_clear(smbus); 220 + err = pasemi_smb_clear(smbus); 221 + if (err) 222 + return err; 266 223 267 224 switch (size) { 268 225 case I2C_SMBUS_QUICK: