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

i2c: mv64xxx: refactor message start to ensure proper initialization

Because the offload mechanism can fall back to a standard transfer,
having two seperate initialization states is unfortunate. Let's just
have one state which does things consistently. This fixes a bug where
some preparation was missing when the fallback happened. And it makes
the code much easier to follow. To implement this, we put the check
if offload is possible at the top of the offload setup function.

Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
Tested-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
Cc: stable@vger.kernel.org # v3.12+
Fixes: 930ab3d403ae (i2c: mv64xxx: Add I2C Transaction Generator support)

+14 -19
+14 -19
drivers/i2c/busses/i2c-mv64xxx.c
··· 97 97 enum { 98 98 MV64XXX_I2C_ACTION_INVALID, 99 99 MV64XXX_I2C_ACTION_CONTINUE, 100 - MV64XXX_I2C_ACTION_OFFLOAD_SEND_START, 101 100 MV64XXX_I2C_ACTION_SEND_START, 102 101 MV64XXX_I2C_ACTION_SEND_RESTART, 103 102 MV64XXX_I2C_ACTION_OFFLOAD_RESTART, ··· 202 203 unsigned long data_reg_lo = 0; 203 204 unsigned long ctrl_reg; 204 205 struct i2c_msg *msg = drv_data->msgs; 206 + 207 + if (!drv_data->offload_enabled) 208 + return -EOPNOTSUPP; 205 209 206 210 drv_data->msg = msg; 207 211 drv_data->byte_posn = 0; ··· 435 433 436 434 drv_data->msgs++; 437 435 drv_data->num_msgs--; 438 - if (!(drv_data->offload_enabled && 439 - mv64xxx_i2c_offload_msg(drv_data))) { 436 + if (mv64xxx_i2c_offload_msg(drv_data) < 0) { 440 437 drv_data->cntl_bits |= MV64XXX_I2C_REG_CONTROL_START; 441 438 writel(drv_data->cntl_bits, 442 439 drv_data->reg_base + drv_data->reg_offsets.control); ··· 459 458 drv_data->reg_base + drv_data->reg_offsets.control); 460 459 break; 461 460 462 - case MV64XXX_I2C_ACTION_OFFLOAD_SEND_START: 463 - if (!mv64xxx_i2c_offload_msg(drv_data)) 464 - break; 465 - else 466 - drv_data->action = MV64XXX_I2C_ACTION_SEND_START; 467 - /* FALLTHRU */ 468 461 case MV64XXX_I2C_ACTION_SEND_START: 469 - writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_START, 470 - drv_data->reg_base + drv_data->reg_offsets.control); 462 + /* Can we offload this msg ? */ 463 + if (mv64xxx_i2c_offload_msg(drv_data) < 0) { 464 + /* No, switch to standard path */ 465 + mv64xxx_i2c_prepare_for_io(drv_data, drv_data->msgs); 466 + writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_START, 467 + drv_data->reg_base + drv_data->reg_offsets.control); 468 + } 471 469 break; 472 470 473 471 case MV64XXX_I2C_ACTION_SEND_ADDR_1: ··· 625 625 unsigned long flags; 626 626 627 627 spin_lock_irqsave(&drv_data->lock, flags); 628 - if (drv_data->offload_enabled) { 629 - drv_data->action = MV64XXX_I2C_ACTION_OFFLOAD_SEND_START; 630 - drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_START_COND; 631 - } else { 632 - mv64xxx_i2c_prepare_for_io(drv_data, msg); 633 628 634 - drv_data->action = MV64XXX_I2C_ACTION_SEND_START; 635 - drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_START_COND; 636 - } 629 + drv_data->action = MV64XXX_I2C_ACTION_SEND_START; 630 + drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_START_COND; 631 + 637 632 drv_data->send_stop = is_last; 638 633 drv_data->block = 1; 639 634 mv64xxx_i2c_do_action(drv_data);