Commit 95b75cbd authored by Vadim Pasternak's avatar Vadim Pasternak Committed by David S. Miller
Browse files

mlxsw: i2c: Extend input parameters list of command API



Extend input parameters list of command API in mlxsw_i2c_cmd() in order
to support initialization commands. Up until now, only access commands
were supported by I2C driver.

Signed-off-by: default avatarVadim Pasternak <vadimp@mellanox.com>
Acked-by: default avatarJiri Pirko <jiri@mellanox.com>
Signed-off-by: default avatarIdo Schimmel <idosch@mellanox.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent f43d9d9b
Loading
Loading
Loading
Loading
+101 −19
Original line number Diff line number Diff line
@@ -20,8 +20,10 @@
#define MLXSW_I2C_CIR2_OFF_STATUS	(MLXSW_I2C_CIR2_BASE + \
					 MLXSW_I2C_CIR_STATUS_OFF)
#define MLXSW_I2C_OPMOD_SHIFT		12
#define MLXSW_I2C_EVENT_BIT_SHIFT	22
#define MLXSW_I2C_GO_BIT_SHIFT		23
#define MLXSW_I2C_CIR_CTRL_STATUS_SHIFT	24
#define MLXSW_I2C_EVENT_BIT		BIT(MLXSW_I2C_EVENT_BIT_SHIFT)
#define MLXSW_I2C_GO_BIT		BIT(MLXSW_I2C_GO_BIT_SHIFT)
#define MLXSW_I2C_GO_OPMODE		BIT(MLXSW_I2C_OPMOD_SHIFT)
#define MLXSW_I2C_SET_IMM_CMD		(MLXSW_I2C_GO_OPMODE | \
@@ -33,6 +35,9 @@
#define MLXSW_I2C_TLV_HDR_SIZE		0x10
#define MLXSW_I2C_ADDR_WIDTH		4
#define MLXSW_I2C_PUSH_CMD_SIZE		(MLXSW_I2C_ADDR_WIDTH + 4)
#define MLXSW_I2C_SET_EVENT_CMD		(MLXSW_I2C_EVENT_BIT)
#define MLXSW_I2C_PUSH_EVENT_CMD	(MLXSW_I2C_GO_BIT | \
					 MLXSW_I2C_SET_EVENT_CMD)
#define MLXSW_I2C_READ_SEMA_SIZE	4
#define MLXSW_I2C_PREP_SIZE		(MLXSW_I2C_ADDR_WIDTH + 28)
#define MLXSW_I2C_MBOX_SIZE		20
@@ -44,6 +49,7 @@
#define MLXSW_I2C_BLK_MAX		32
#define MLXSW_I2C_RETRY			5
#define MLXSW_I2C_TIMEOUT_MSECS		5000
#define MLXSW_I2C_MAX_DATA_SIZE		256

/**
 * struct mlxsw_i2c - device private data:
@@ -213,6 +219,66 @@ static int mlxsw_i2c_write_cmd(struct i2c_client *client,
	return 0;
}

/* Routine posts initialization command to ASIC through mail box. */
static int
mlxsw_i2c_write_init_cmd(struct i2c_client *client,
			 struct mlxsw_i2c *mlxsw_i2c, u16 opcode, u32 in_mod)
{
	__be32 push_cmd_buf[MLXSW_I2C_PUSH_CMD_SIZE / 4] = {
		0, cpu_to_be32(MLXSW_I2C_PUSH_EVENT_CMD)
	};
	__be32 prep_cmd_buf[MLXSW_I2C_PREP_SIZE / 4] = {
		0, 0, 0, 0, 0, 0,
		cpu_to_be32(client->adapter->nr & 0xffff),
		cpu_to_be32(MLXSW_I2C_SET_EVENT_CMD)
	};
	struct i2c_msg push_cmd =
		MLXSW_I2C_WRITE_MSG(client, push_cmd_buf,
				    MLXSW_I2C_PUSH_CMD_SIZE);
	struct i2c_msg prep_cmd =
		MLXSW_I2C_WRITE_MSG(client, prep_cmd_buf, MLXSW_I2C_PREP_SIZE);
	u8 status;
	int err;

	push_cmd_buf[1] = cpu_to_be32(MLXSW_I2C_PUSH_EVENT_CMD | opcode);
	prep_cmd_buf[3] = cpu_to_be32(in_mod);
	prep_cmd_buf[7] = cpu_to_be32(MLXSW_I2C_GO_BIT | opcode);
	mlxsw_i2c_set_slave_addr((u8 *)prep_cmd_buf,
				 MLXSW_I2C_CIR2_BASE);
	mlxsw_i2c_set_slave_addr((u8 *)push_cmd_buf,
				 MLXSW_I2C_CIR2_OFF_STATUS);

	/* Prepare Command Interface Register for transaction */
	err = i2c_transfer(client->adapter, &prep_cmd, 1);
	if (err < 0)
		return err;
	else if (err != 1)
		return -EIO;

	/* Write out Command Interface Register GO bit to push transaction */
	err = i2c_transfer(client->adapter, &push_cmd, 1);
	if (err < 0)
		return err;
	else if (err != 1)
		return -EIO;

	/* Wait until go bit is cleared. */
	err = mlxsw_i2c_wait_go_bit(client, mlxsw_i2c, &status);
	if (err) {
		dev_err(&client->dev, "HW semaphore is not released");
		return err;
	}

	/* Validate transaction completion status. */
	if (status) {
		dev_err(&client->dev, "Bad transaction completion status %x\n",
			status);
		return -EIO;
	}

	return 0;
}

/* Routine obtains mail box offsets from ASIC register space. */
static int mlxsw_i2c_get_mbox(struct i2c_client *client,
			      struct mlxsw_i2c *mlxsw_i2c)
@@ -310,8 +376,8 @@ mlxsw_i2c_write(struct device *dev, size_t in_mbox_size, u8 *in_mbox, int num,

/* Routine executes I2C command. */
static int
mlxsw_i2c_cmd(struct device *dev, size_t in_mbox_size, u8 *in_mbox,
	      size_t out_mbox_size, u8 *out_mbox, u8 *status)
mlxsw_i2c_cmd(struct device *dev, u16 opcode, u32 in_mod, size_t in_mbox_size,
	      u8 *in_mbox, size_t out_mbox_size, u8 *out_mbox, u8 *status)
{
	struct i2c_client *client = to_i2c_client(dev);
	struct mlxsw_i2c *mlxsw_i2c = i2c_get_clientdata(client);
@@ -326,6 +392,7 @@ mlxsw_i2c_cmd(struct device *dev, size_t in_mbox_size, u8 *in_mbox,

	WARN_ON(in_mbox_size % sizeof(u32) || out_mbox_size % sizeof(u32));

	if (in_mbox) {
		reg_size = mlxsw_i2c_get_reg_size(in_mbox);
		num = reg_size / MLXSW_I2C_BLK_MAX;
		if (reg_size % MLXSW_I2C_BLK_MAX)
@@ -345,6 +412,21 @@ mlxsw_i2c_cmd(struct device *dev, size_t in_mbox_size, u8 *in_mbox,
			mutex_unlock(&mlxsw_i2c->cmd.lock);
			return 0;
		}
	} else {
		/* No input mailbox is case of initialization query command. */
		reg_size = MLXSW_I2C_MAX_DATA_SIZE;
		num = reg_size / MLXSW_I2C_BLK_MAX;

		if (mutex_lock_interruptible(&mlxsw_i2c->cmd.lock) < 0) {
			dev_err(&client->dev, "Could not acquire lock");
			return -EINVAL;
		}

		err = mlxsw_i2c_write_init_cmd(client, mlxsw_i2c, opcode,
					       in_mod);
		if (err)
			goto cmd_fail;
	}

	/* Send read transaction to get output mailbox content. */
	read_tran[1].buf = out_mbox;
@@ -395,8 +477,8 @@ static int mlxsw_i2c_cmd_exec(void *bus_priv, u16 opcode, u8 opcode_mod,
{
	struct mlxsw_i2c *mlxsw_i2c = bus_priv;

	return mlxsw_i2c_cmd(mlxsw_i2c->dev, in_mbox_size, in_mbox,
			     out_mbox_size, out_mbox, status);
	return mlxsw_i2c_cmd(mlxsw_i2c->dev, opcode, in_mod, in_mbox_size,
			     in_mbox, out_mbox_size, out_mbox, status);
}

static bool mlxsw_i2c_skb_transmit_busy(void *bus_priv,