| From 7f6c7de2533bab63212a164b29e1fa352880a05b Mon Sep 17 00:00:00 2001 |
| From: Jinliang Wang <jinliangw@google.com> |
| Date: Tue, 28 Mar 2023 11:16:27 -0700 |
| Subject: [PATCH] i2c: npcm: quirk to fix multiple master xfer failure |
| |
| This patch is backported from Avi.Fishman@nuvoton.com and |
| tali.perry@nuvoton.com 's debug version driver v15. |
| Link (https://drive.google.com/corp/drive/folders/19RaTMJcarpN-dpuAlbTFPm_0xKx7TKjU?resourcekey=0-UI41jAZA4xd_5VINmDcN0Q) |
| It contains some quirk to detect MCTP packet and then apply some |
| special handling. Nuvoton is still trying to find a more proper way to |
| support multiple master mode in upstream i2c-npcm7xx.c. |
| |
| Signed-off-by: Jinliang Wang <jinliangw@google.com> |
| |
| Patch Tracking Bug: b/275108914 |
| Upstream info / review: N/A |
| Upstream-Status: Pending |
| Justification: The patch is upstreamable however Nuvoton is still |
| working on more appropriate and general implementation |
| |
| Signed-off-by: William A. Kennington III <wak@google.com> |
| --- |
| drivers/i2c/busses/i2c-npcm7xx.c | 62 ++++++++++++++++++++++++-------- |
| 1 file changed, 48 insertions(+), 14 deletions(-) |
| |
| diff --git a/drivers/i2c/busses/i2c-npcm7xx.c b/drivers/i2c/busses/i2c-npcm7xx.c |
| index bfef6ae45988..f2a4a7ee14f2 100644 |
| --- a/drivers/i2c/busses/i2c-npcm7xx.c |
| +++ b/drivers/i2c/busses/i2c-npcm7xx.c |
| @@ -433,6 +433,7 @@ struct npcm_i2c { |
| bool read_block_use; |
| unsigned long int_time_stamp; |
| unsigned long bus_freq; /* in Hz */ |
| + bool multi_master; |
| #if IS_ENABLED(CONFIG_I2C_SLAVE) |
| u8 own_slave_addr; |
| struct i2c_client *slave; |
| @@ -1218,7 +1219,7 @@ static irqreturn_t npcm_i2c_int_slave_handler(struct npcm_i2c *bus) |
| * master ( for a channel which is master\slave switching) |
| */ |
| if (completion_done(&bus->cmd_complete) == false) { |
| - bus->cmd_err = -EIO; |
| + bus->cmd_err = -EAGAIN; |
| complete(&bus->cmd_complete); |
| } |
| bus->own_slave_addr = 0xFF; |
| @@ -1643,6 +1644,7 @@ static void npcm_i2c_irq_handle_ber(struct npcm_i2c *bus) |
| bus->stop_ind = I2C_BUS_ERR_IND; |
| if (npcm_i2c_is_master(bus)) { |
| npcm_i2c_master_abort(bus); |
| + bus->cmd_err = -EAGAIN; |
| } else { |
| bus->ber_state = true; |
| npcm_i2c_clear_master_status(bus); |
| @@ -1788,6 +1790,14 @@ static int npcm_i2c_int_master_handler(struct npcm_i2c *bus) |
| (FIELD_GET(NPCM_I2CCST3_EO_BUSY, |
| ioread8(bus->reg + NPCM_I2CCST3)))) { |
| npcm_i2c_irq_handle_eob(bus); |
| + |
| +/* VIVEK */ |
| +#if IS_ENABLED(CONFIG_I2C_SLAVE) |
| + /* reenable slave if it was enabled */ |
| + if (bus->slave) |
| + iowrite8((bus->slave->addr & 0x7F) | NPCM_I2CADDR_SAEN, |
| + bus->reg + NPCM_I2CADDR1); |
| +#endif |
| return 0; |
| } |
| |
| @@ -1819,11 +1829,16 @@ static int npcm_i2c_recovery_tgclk(struct i2c_adapter *_adap) |
| /* Allow 3 bytes (27 toggles) to be read from the slave: */ |
| int iter = 27; |
| |
| + bus->ber_state = false; |
| + |
| + if (bus->multi_master) { |
| + return 0; |
| + } |
| + |
| if ((npcm_i2c_get_SDA(_adap) == 1) && (npcm_i2c_get_SCL(_adap) == 1)) { |
| dev_dbg(bus->dev, "bus%d-0x%x recovery skipped, bus not stuck", |
| bus->num, bus->dest_addr); |
| npcm_i2c_reset(bus); |
| - bus->ber_state = false; |
| return 0; |
| } |
| |
| @@ -1888,7 +1903,6 @@ static int npcm_i2c_recovery_tgclk(struct i2c_adapter *_adap) |
| if (bus->rec_succ_cnt < ULLONG_MAX) |
| bus->rec_succ_cnt++; |
| } |
| - bus->ber_state = false; |
| return status; |
| } |
| |
| @@ -2107,7 +2121,7 @@ static bool npcm_i2c_master_start_xmit(struct npcm_i2c *bus, |
| bool use_PEC, bool use_read_block) |
| { |
| if (bus->state != I2C_IDLE) { |
| - bus->cmd_err = -EBUSY; |
| + bus->cmd_err = -EAGAIN; |
| return false; |
| } |
| bus->dest_addr = slave_addr << 1; |
| @@ -2184,6 +2198,11 @@ static int npcm_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, |
| write_data = msg0->buf; |
| nread = 0; |
| read_data = NULL; |
| + if ((num == 1) && (nwrite > 7) && (write_data[0] == 0xF) && ((write_data[1] + 3) == nwrite)) |
| + { |
| + printk_once("i2c%d: Met MCTP packet\n", bus->num); |
| + bus->multi_master = true; |
| + } |
| if (num == 2) { |
| msg1 = &msgs[1]; |
| read_data = msg1->buf; |
| @@ -2201,6 +2220,7 @@ static int npcm_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, |
| |
| if (nwrite >= 32 * 1024 || nread >= 32 * 1024) { |
| dev_err(bus->dev, "i2c%d buffer too big\n", bus->num); |
| + bus->multi_master = false; |
| return -EINVAL; |
| } |
| |
| @@ -2212,7 +2232,7 @@ static int npcm_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, |
| * entire while since it is too long. |
| */ |
| spin_lock_irqsave(&bus->lock, flags); |
| - bus_busy = ioread8(bus->reg + NPCM_I2CCST) & NPCM_I2CCST_BB; |
| + bus_busy = (ioread8(bus->reg + NPCM_I2CCST) & NPCM_I2CCST_BB) || (bus->state != I2C_IDLE); |
| #if IS_ENABLED(CONFIG_I2C_SLAVE) |
| if (!bus_busy && bus->slave) |
| iowrite8((bus->slave->addr & 0x7F), |
| @@ -2225,15 +2245,19 @@ static int npcm_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, |
| bus->dest_addr = slave_addr << 1; |
| if (bus_busy || bus->ber_state) { |
| iowrite8(NPCM_I2CCST_BB, bus->reg + NPCM_I2CCST); |
| - npcm_i2c_reset(bus); |
| - i2c_recover_bus(adap); |
| - return -EAGAIN; |
| + if(bus->multi_master == false) |
| + { |
| + npcm_i2c_reset(bus); |
| + i2c_recover_bus(adap); |
| + } |
| + bus->cmd_err = -EAGAIN; |
| + goto npcm_i2c_xfer_complete; |
| } |
| |
| npcm_i2c_init_params(bus); |
| bus->msgs = msgs; |
| bus->msgs_num = num; |
| - bus->cmd_err = 0; |
| + bus->cmd_err = -EAGAIN; |
| bus->read_block_use = read_block; |
| |
| reinit_completion(&bus->cmd_complete); |
| @@ -2258,8 +2282,7 @@ static int npcm_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, |
| if (bus->timeout_cnt < ULLONG_MAX) |
| bus->timeout_cnt++; |
| if (bus->master_or_slave == I2C_MASTER) { |
| - i2c_recover_bus(adap); |
| - bus->cmd_err = -EIO; |
| + bus->cmd_err = -EAGAIN; |
| bus->state = I2C_IDLE; |
| } |
| } |
| @@ -2267,7 +2290,7 @@ static int npcm_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, |
| |
| /* if there was BER, check if need to recover the bus: */ |
| if (bus->cmd_err == -EAGAIN) |
| - bus->cmd_err = i2c_recover_bus(adap); |
| + i2c_recover_bus(adap); |
| |
| /* |
| * After any type of error, check if LAST bit is still set, |
| @@ -2282,6 +2305,15 @@ static int npcm_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, |
| npcm_i2c_stall_after_start(bus, false); |
| npcm_i2c_eob_int(bus, false); |
| |
| +npcm_i2c_xfer_complete: |
| + if (bus->multi_master) { |
| + if ((bus->cmd_err < 0 && bus->cmd_err != -EAGAIN)|| |
| + (bus->cmd_err >= 0 && bus->cmd_err != num)){ |
| + dev_err(bus->dev, "i2c%d xfer returned %d\n", bus->num, bus->cmd_err); |
| + } |
| + /* reset it to false upon exit */ |
| + bus->multi_master = false; |
| + } |
| #if IS_ENABLED(CONFIG_I2C_SLAVE) |
| /* reenable slave if it was enabled */ |
| if (bus->slave) |
| @@ -2423,8 +2455,10 @@ static int npcm_i2c_probe_bus(struct platform_device *pdev) |
| |
| adap = &bus->adap; |
| adap->owner = THIS_MODULE; |
| - adap->retries = 3; |
| - adap->timeout = 2 * HZ; |
| + /* 10 retries x 400 ms = 4 seconds(HZ) */ |
| + adap->retries = 10; |
| + adap->timeout = msecs_to_jiffies(400) * adap->retries; |
| + bus->multi_master = false; |
| adap->algo = &npcm_i2c_algo; |
| adap->quirks = &npcm_i2c_quirks; |
| adap->algo_data = bus; |
| -- |
| 2.40.1.495.gc816e09b53d-goog |
| |