Commit fe68c43c authored by Alex Elder's avatar Alex Elder Committed by Jakub Kicinski

net: ipa: support enhanced channel flow control

IPA v4.2 introduced GSI channel flow control, used instead of IPA
endpoint DELAY mode to prevent a TX channel from injecting packets
into the IPA core.  It used a new FLOW_CONTROLLED channel state
which could be entered using GSI generic commands.

IPA v4.11 extended the channel flow control model.  Rather than
having a distinct FLOW_CONTROLLED channel state, each channel has a
"flow control" property that can be enabled or not--independent of
the channel state.  The AP (or modem) can modify this property using
the same GSI generic commands as before.

The AP only uses channel flow control on modem TX channels, and only
when recovering from a modem crash.  The AP has no way to discover
the state of a modem channel, so the fact that (starting with IPA
v4.11) flow control no longer uses a distinct channel state is
invisible to the AP.  So enhanced flow control generally does not
change the way AP uses flow control.

There are a few small differences, however:
  - There is a notion of "primary" or "secondary" flow control, and
    when enabling or disabling flow control that must be specified
    in a new field in the GSI generic command register.  For now, we
    always specify 0 (meaning "primary").
  - When disabling flow control, it's possible a request will need
    to be retried.  We retry up to 5 times in this case.
  - Another new generic command allows the current flow control
    state to be queried.  We do not use this.

Other than the need for retries, the code essentially works the same
way as before.
Signed-off-by: default avatarAlex Elder <elder@linaro.org>
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 4c9d631a
...@@ -93,6 +93,7 @@ ...@@ -93,6 +93,7 @@
#define GSI_CHANNEL_STOP_RETRIES 10 #define GSI_CHANNEL_STOP_RETRIES 10
#define GSI_CHANNEL_MODEM_HALT_RETRIES 10 #define GSI_CHANNEL_MODEM_HALT_RETRIES 10
#define GSI_CHANNEL_MODEM_FLOW_RETRIES 5 /* disable flow control only */
#define GSI_MHI_EVENT_ID_START 10 /* 1st reserved event id */ #define GSI_MHI_EVENT_ID_START 10 /* 1st reserved event id */
#define GSI_MHI_EVENT_ID_END 16 /* Last reserved event id */ #define GSI_MHI_EVENT_ID_END 16 /* Last reserved event id */
...@@ -1649,7 +1650,8 @@ static void gsi_channel_teardown_one(struct gsi *gsi, u32 channel_id) ...@@ -1649,7 +1650,8 @@ static void gsi_channel_teardown_one(struct gsi *gsi, u32 channel_id)
* issue the command and wait for it to complete. * issue the command and wait for it to complete.
*/ */
static int gsi_generic_command(struct gsi *gsi, u32 channel_id, static int gsi_generic_command(struct gsi *gsi, u32 channel_id,
enum gsi_generic_cmd_opcode opcode) enum gsi_generic_cmd_opcode opcode,
u8 params)
{ {
bool timeout; bool timeout;
u32 val; u32 val;
...@@ -1675,6 +1677,7 @@ static int gsi_generic_command(struct gsi *gsi, u32 channel_id, ...@@ -1675,6 +1677,7 @@ static int gsi_generic_command(struct gsi *gsi, u32 channel_id,
val = u32_encode_bits(opcode, GENERIC_OPCODE_FMASK); val = u32_encode_bits(opcode, GENERIC_OPCODE_FMASK);
val |= u32_encode_bits(channel_id, GENERIC_CHID_FMASK); val |= u32_encode_bits(channel_id, GENERIC_CHID_FMASK);
val |= u32_encode_bits(GSI_EE_MODEM, GENERIC_EE_FMASK); val |= u32_encode_bits(GSI_EE_MODEM, GENERIC_EE_FMASK);
val |= u32_encode_bits(params, GENERIC_PARAMS_FMASK);
timeout = !gsi_command(gsi, GSI_GENERIC_CMD_OFFSET, val); timeout = !gsi_command(gsi, GSI_GENERIC_CMD_OFFSET, val);
...@@ -1693,7 +1696,7 @@ static int gsi_generic_command(struct gsi *gsi, u32 channel_id, ...@@ -1693,7 +1696,7 @@ static int gsi_generic_command(struct gsi *gsi, u32 channel_id,
static int gsi_modem_channel_alloc(struct gsi *gsi, u32 channel_id) static int gsi_modem_channel_alloc(struct gsi *gsi, u32 channel_id)
{ {
return gsi_generic_command(gsi, channel_id, return gsi_generic_command(gsi, channel_id,
GSI_GENERIC_ALLOCATE_CHANNEL); GSI_GENERIC_ALLOCATE_CHANNEL, 0);
} }
static void gsi_modem_channel_halt(struct gsi *gsi, u32 channel_id) static void gsi_modem_channel_halt(struct gsi *gsi, u32 channel_id)
...@@ -1703,7 +1706,7 @@ static void gsi_modem_channel_halt(struct gsi *gsi, u32 channel_id) ...@@ -1703,7 +1706,7 @@ static void gsi_modem_channel_halt(struct gsi *gsi, u32 channel_id)
do do
ret = gsi_generic_command(gsi, channel_id, ret = gsi_generic_command(gsi, channel_id,
GSI_GENERIC_HALT_CHANNEL); GSI_GENERIC_HALT_CHANNEL, 0);
while (ret == -EAGAIN && retries--); while (ret == -EAGAIN && retries--);
if (ret) if (ret)
...@@ -1715,13 +1718,22 @@ static void gsi_modem_channel_halt(struct gsi *gsi, u32 channel_id) ...@@ -1715,13 +1718,22 @@ static void gsi_modem_channel_halt(struct gsi *gsi, u32 channel_id)
void void
gsi_modem_channel_flow_control(struct gsi *gsi, u32 channel_id, bool enable) gsi_modem_channel_flow_control(struct gsi *gsi, u32 channel_id, bool enable)
{ {
u32 retries = 0;
u32 command; u32 command;
int ret; int ret;
command = enable ? GSI_GENERIC_ENABLE_FLOW_CONTROL command = enable ? GSI_GENERIC_ENABLE_FLOW_CONTROL
: GSI_GENERIC_DISABLE_FLOW_CONTROL; : GSI_GENERIC_DISABLE_FLOW_CONTROL;
/* Disabling flow control on IPA v4.11+ can return -EAGAIN if enable
* is underway. In this case we need to retry the command.
*/
if (!enable && gsi->version >= IPA_VERSION_4_11)
retries = GSI_CHANNEL_MODEM_FLOW_RETRIES;
do
ret = gsi_generic_command(gsi, channel_id, command, 0);
while (ret == -EAGAIN && retries--);
ret = gsi_generic_command(gsi, channel_id, command);
if (ret) if (ret)
dev_err(gsi->dev, dev_err(gsi->dev,
"error %d %sabling mode channel %u flow control\n", "error %d %sabling mode channel %u flow control\n",
......
...@@ -101,7 +101,7 @@ enum gsi_channel_state { ...@@ -101,7 +101,7 @@ enum gsi_channel_state {
GSI_CHANNEL_STATE_STARTED = 0x2, GSI_CHANNEL_STATE_STARTED = 0x2,
GSI_CHANNEL_STATE_STOPPED = 0x3, GSI_CHANNEL_STATE_STOPPED = 0x3,
GSI_CHANNEL_STATE_STOP_IN_PROC = 0x4, GSI_CHANNEL_STATE_STOP_IN_PROC = 0x4,
GSI_CHANNEL_STATE_FLOW_CONTROLLED = 0x5, /* IPA v4.2+ */ GSI_CHANNEL_STATE_FLOW_CONTROLLED = 0x5, /* IPA v4.2-v4.9 */
GSI_CHANNEL_STATE_ERROR = 0xf, GSI_CHANNEL_STATE_ERROR = 0xf,
}; };
......
...@@ -313,6 +313,7 @@ enum gsi_evt_cmd_opcode { ...@@ -313,6 +313,7 @@ enum gsi_evt_cmd_opcode {
#define GENERIC_OPCODE_FMASK GENMASK(4, 0) #define GENERIC_OPCODE_FMASK GENMASK(4, 0)
#define GENERIC_CHID_FMASK GENMASK(9, 5) #define GENERIC_CHID_FMASK GENMASK(9, 5)
#define GENERIC_EE_FMASK GENMASK(13, 10) #define GENERIC_EE_FMASK GENMASK(13, 10)
#define GENERIC_PARAMS_FMASK GENMASK(31, 24) /* IPA v4.11+ */
/** enum gsi_generic_cmd_opcode - GENERIC_OPCODE field values in GENERIC_CMD */ /** enum gsi_generic_cmd_opcode - GENERIC_OPCODE field values in GENERIC_CMD */
enum gsi_generic_cmd_opcode { enum gsi_generic_cmd_opcode {
...@@ -320,6 +321,7 @@ enum gsi_generic_cmd_opcode { ...@@ -320,6 +321,7 @@ enum gsi_generic_cmd_opcode {
GSI_GENERIC_ALLOCATE_CHANNEL = 0x2, GSI_GENERIC_ALLOCATE_CHANNEL = 0x2,
GSI_GENERIC_ENABLE_FLOW_CONTROL = 0x3, /* IPA v4.2+ */ GSI_GENERIC_ENABLE_FLOW_CONTROL = 0x3, /* IPA v4.2+ */
GSI_GENERIC_DISABLE_FLOW_CONTROL = 0x4, /* IPA v4.2+ */ GSI_GENERIC_DISABLE_FLOW_CONTROL = 0x4, /* IPA v4.2+ */
GSI_GENERIC_QUERY_FLOW_CONTROL = 0x5, /* IPA v4.11+ */
}; };
/* The next register is present for IPA v3.5.1 and above */ /* The next register is present for IPA v3.5.1 and above */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment