Commit 2c24eefb authored by Jakub Kicinski's avatar Jakub Kicinski

Merge branch 'net-ipa-tell-gsi-the-ipa-version'

Alex Elder says:

====================
net: ipa: tell GSI the IPA version

The GSI code that supports IPA avoids having knowledge about the
IPA layer it serves.  One result of this is that Boolean flags are
used during GSI initialization to convey that certain hardware
version-dependent special behaviors should be used.

A given version of IPA hardware uses a fixed/well-defined version
of GSI, so the IPA version really implies the GSI version.

If given only the IPA version, the GSI code supporting IPA can
use it to implement certain special behaviors required for IPA
*or* GSI.  This avoids the need to pass and maintain numerous
Boolean flags.
====================

Link: https://lore.kernel.org/r/20201102175400.6282-1-elder@linaro.orgSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 3fb6928b d387c761
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include "gsi_trans.h" #include "gsi_trans.h"
#include "ipa_gsi.h" #include "ipa_gsi.h"
#include "ipa_data.h" #include "ipa_data.h"
#include "ipa_version.h"
/** /**
* DOC: The IPA Generic Software Interface * DOC: The IPA Generic Software Interface
...@@ -742,11 +743,12 @@ static void gsi_channel_program(struct gsi_channel *channel, bool doorbell) ...@@ -742,11 +743,12 @@ static void gsi_channel_program(struct gsi_channel *channel, bool doorbell)
/* Max prefetch is 1 segment (do not set MAX_PREFETCH_FMASK) */ /* Max prefetch is 1 segment (do not set MAX_PREFETCH_FMASK) */
/* Enable the doorbell engine if requested */ /* We enable the doorbell engine for IPA v3.5.1 */
if (doorbell) if (gsi->version == IPA_VERSION_3_5_1 && doorbell)
val |= USE_DB_ENG_FMASK; val |= USE_DB_ENG_FMASK;
if (!channel->use_prefetch) /* Starting with IPA v4.0 the command channel uses the escape buffer */
if (gsi->version != IPA_VERSION_3_5_1 && channel->command)
val |= USE_ESCAPE_BUF_ONLY_FMASK; val |= USE_ESCAPE_BUF_ONLY_FMASK;
iowrite32(val, gsi->virt + GSI_CH_C_QOS_OFFSET(channel_id)); iowrite32(val, gsi->virt + GSI_CH_C_QOS_OFFSET(channel_id));
...@@ -829,8 +831,8 @@ int gsi_channel_stop(struct gsi *gsi, u32 channel_id) ...@@ -829,8 +831,8 @@ int gsi_channel_stop(struct gsi *gsi, u32 channel_id)
return ret; return ret;
} }
/* Reset and reconfigure a channel (possibly leaving doorbell disabled) */ /* Reset and reconfigure a channel, (possibly) enabling the doorbell engine */
void gsi_channel_reset(struct gsi *gsi, u32 channel_id, bool legacy) void gsi_channel_reset(struct gsi *gsi, u32 channel_id, bool doorbell)
{ {
struct gsi_channel *channel = &gsi->channel[channel_id]; struct gsi_channel *channel = &gsi->channel[channel_id];
...@@ -838,10 +840,10 @@ void gsi_channel_reset(struct gsi *gsi, u32 channel_id, bool legacy) ...@@ -838,10 +840,10 @@ void gsi_channel_reset(struct gsi *gsi, u32 channel_id, bool legacy)
gsi_channel_reset_command(channel); gsi_channel_reset_command(channel);
/* Due to a hardware quirk we may need to reset RX channels twice. */ /* Due to a hardware quirk we may need to reset RX channels twice. */
if (legacy && !channel->toward_ipa) if (gsi->version == IPA_VERSION_3_5_1 && !channel->toward_ipa)
gsi_channel_reset_command(channel); gsi_channel_reset_command(channel);
gsi_channel_program(channel, legacy); gsi_channel_program(channel, doorbell);
gsi_channel_trans_cancel_pending(channel); gsi_channel_trans_cancel_pending(channel);
mutex_unlock(&gsi->mutex); mutex_unlock(&gsi->mutex);
...@@ -1452,8 +1454,7 @@ static void gsi_evt_ring_teardown(struct gsi *gsi) ...@@ -1452,8 +1454,7 @@ static void gsi_evt_ring_teardown(struct gsi *gsi)
} }
/* Setup function for a single channel */ /* Setup function for a single channel */
static int gsi_channel_setup_one(struct gsi *gsi, u32 channel_id, static int gsi_channel_setup_one(struct gsi *gsi, u32 channel_id)
bool legacy)
{ {
struct gsi_channel *channel = &gsi->channel[channel_id]; struct gsi_channel *channel = &gsi->channel[channel_id];
u32 evt_ring_id = channel->evt_ring_id; u32 evt_ring_id = channel->evt_ring_id;
...@@ -1472,7 +1473,7 @@ static int gsi_channel_setup_one(struct gsi *gsi, u32 channel_id, ...@@ -1472,7 +1473,7 @@ static int gsi_channel_setup_one(struct gsi *gsi, u32 channel_id,
if (ret) if (ret)
goto err_evt_ring_de_alloc; goto err_evt_ring_de_alloc;
gsi_channel_program(channel, legacy); gsi_channel_program(channel, true);
if (channel->toward_ipa) if (channel->toward_ipa)
netif_tx_napi_add(&gsi->dummy_dev, &channel->napi, netif_tx_napi_add(&gsi->dummy_dev, &channel->napi,
...@@ -1549,7 +1550,7 @@ static void gsi_modem_channel_halt(struct gsi *gsi, u32 channel_id) ...@@ -1549,7 +1550,7 @@ static void gsi_modem_channel_halt(struct gsi *gsi, u32 channel_id)
} }
/* Setup function for channels */ /* Setup function for channels */
static int gsi_channel_setup(struct gsi *gsi, bool legacy) static int gsi_channel_setup(struct gsi *gsi)
{ {
u32 channel_id = 0; u32 channel_id = 0;
u32 mask; u32 mask;
...@@ -1561,7 +1562,7 @@ static int gsi_channel_setup(struct gsi *gsi, bool legacy) ...@@ -1561,7 +1562,7 @@ static int gsi_channel_setup(struct gsi *gsi, bool legacy)
mutex_lock(&gsi->mutex); mutex_lock(&gsi->mutex);
do { do {
ret = gsi_channel_setup_one(gsi, channel_id, legacy); ret = gsi_channel_setup_one(gsi, channel_id);
if (ret) if (ret)
goto err_unwind; goto err_unwind;
} while (++channel_id < gsi->channel_count); } while (++channel_id < gsi->channel_count);
...@@ -1647,7 +1648,7 @@ static void gsi_channel_teardown(struct gsi *gsi) ...@@ -1647,7 +1648,7 @@ static void gsi_channel_teardown(struct gsi *gsi)
} }
/* Setup function for GSI. GSI firmware must be loaded and initialized */ /* Setup function for GSI. GSI firmware must be loaded and initialized */
int gsi_setup(struct gsi *gsi, bool legacy) int gsi_setup(struct gsi *gsi)
{ {
struct device *dev = gsi->dev; struct device *dev = gsi->dev;
u32 val; u32 val;
...@@ -1691,7 +1692,7 @@ int gsi_setup(struct gsi *gsi, bool legacy) ...@@ -1691,7 +1692,7 @@ int gsi_setup(struct gsi *gsi, bool legacy)
/* Writing 1 indicates IRQ interrupts; 0 would be MSI */ /* Writing 1 indicates IRQ interrupts; 0 would be MSI */
iowrite32(1, gsi->virt + GSI_CNTXT_INTSET_OFFSET); iowrite32(1, gsi->virt + GSI_CNTXT_INTSET_OFFSET);
return gsi_channel_setup(gsi, legacy); return gsi_channel_setup(gsi);
} }
/* Inverse of gsi_setup() */ /* Inverse of gsi_setup() */
...@@ -1814,7 +1815,7 @@ static bool gsi_channel_data_valid(struct gsi *gsi, ...@@ -1814,7 +1815,7 @@ static bool gsi_channel_data_valid(struct gsi *gsi,
/* Init function for a single channel */ /* Init function for a single channel */
static int gsi_channel_init_one(struct gsi *gsi, static int gsi_channel_init_one(struct gsi *gsi,
const struct ipa_gsi_endpoint_data *data, const struct ipa_gsi_endpoint_data *data,
bool command, bool prefetch) bool command)
{ {
struct gsi_channel *channel; struct gsi_channel *channel;
u32 tre_count; u32 tre_count;
...@@ -1838,7 +1839,6 @@ static int gsi_channel_init_one(struct gsi *gsi, ...@@ -1838,7 +1839,6 @@ static int gsi_channel_init_one(struct gsi *gsi,
channel->gsi = gsi; channel->gsi = gsi;
channel->toward_ipa = data->toward_ipa; channel->toward_ipa = data->toward_ipa;
channel->command = command; channel->command = command;
channel->use_prefetch = command && prefetch;
channel->tlv_count = data->channel.tlv_count; channel->tlv_count = data->channel.tlv_count;
channel->tre_count = tre_count; channel->tre_count = tre_count;
channel->event_count = data->channel.event_count; channel->event_count = data->channel.event_count;
...@@ -1892,13 +1892,16 @@ static void gsi_channel_exit_one(struct gsi_channel *channel) ...@@ -1892,13 +1892,16 @@ static void gsi_channel_exit_one(struct gsi_channel *channel)
} }
/* Init function for channels */ /* Init function for channels */
static int gsi_channel_init(struct gsi *gsi, bool prefetch, u32 count, static int gsi_channel_init(struct gsi *gsi, u32 count,
const struct ipa_gsi_endpoint_data *data, const struct ipa_gsi_endpoint_data *data)
bool modem_alloc)
{ {
bool modem_alloc;
int ret = 0; int ret = 0;
u32 i; u32 i;
/* IPA v4.2 requires the AP to allocate channels for the modem */
modem_alloc = gsi->version == IPA_VERSION_4_2;
gsi_evt_ring_init(gsi); gsi_evt_ring_init(gsi);
/* The endpoint data array is indexed by endpoint name */ /* The endpoint data array is indexed by endpoint name */
...@@ -1916,7 +1919,7 @@ static int gsi_channel_init(struct gsi *gsi, bool prefetch, u32 count, ...@@ -1916,7 +1919,7 @@ static int gsi_channel_init(struct gsi *gsi, bool prefetch, u32 count,
continue; continue;
} }
ret = gsi_channel_init_one(gsi, &data[i], command, prefetch); ret = gsi_channel_init_one(gsi, &data[i], command);
if (ret) if (ret)
goto err_unwind; goto err_unwind;
} }
...@@ -1952,9 +1955,9 @@ static void gsi_channel_exit(struct gsi *gsi) ...@@ -1952,9 +1955,9 @@ static void gsi_channel_exit(struct gsi *gsi)
} }
/* Init function for GSI. GSI hardware does not need to be "ready" */ /* Init function for GSI. GSI hardware does not need to be "ready" */
int gsi_init(struct gsi *gsi, struct platform_device *pdev, bool prefetch, int gsi_init(struct gsi *gsi, struct platform_device *pdev,
u32 count, const struct ipa_gsi_endpoint_data *data, enum ipa_version version, u32 count,
bool modem_alloc) const struct ipa_gsi_endpoint_data *data)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct resource *res; struct resource *res;
...@@ -1965,6 +1968,7 @@ int gsi_init(struct gsi *gsi, struct platform_device *pdev, bool prefetch, ...@@ -1965,6 +1968,7 @@ int gsi_init(struct gsi *gsi, struct platform_device *pdev, bool prefetch,
gsi_validate_build(); gsi_validate_build();
gsi->dev = dev; gsi->dev = dev;
gsi->version = version;
/* The GSI layer performs NAPI on all endpoints. NAPI requires a /* The GSI layer performs NAPI on all endpoints. NAPI requires a
* network device structure, but the GSI layer does not have one, * network device structure, but the GSI layer does not have one,
...@@ -2008,7 +2012,7 @@ int gsi_init(struct gsi *gsi, struct platform_device *pdev, bool prefetch, ...@@ -2008,7 +2012,7 @@ int gsi_init(struct gsi *gsi, struct platform_device *pdev, bool prefetch,
goto err_free_irq; goto err_free_irq;
} }
ret = gsi_channel_init(gsi, prefetch, count, data, modem_alloc); ret = gsi_channel_init(gsi, count, data);
if (ret) if (ret)
goto err_iounmap; goto err_iounmap;
......
...@@ -13,6 +13,8 @@ ...@@ -13,6 +13,8 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include "ipa_version.h"
/* Maximum number of channels and event rings supported by the driver */ /* Maximum number of channels and event rings supported by the driver */
#define GSI_CHANNEL_COUNT_MAX 17 #define GSI_CHANNEL_COUNT_MAX 17
#define GSI_EVT_RING_COUNT_MAX 13 #define GSI_EVT_RING_COUNT_MAX 13
...@@ -107,7 +109,6 @@ struct gsi_channel { ...@@ -107,7 +109,6 @@ struct gsi_channel {
struct gsi *gsi; struct gsi *gsi;
bool toward_ipa; bool toward_ipa;
bool command; /* AP command TX channel or not */ bool command; /* AP command TX channel or not */
bool use_prefetch; /* use prefetch (else escape buf) */
u8 tlv_count; /* # entries in TLV FIFO */ u8 tlv_count; /* # entries in TLV FIFO */
u16 tre_count; u16 tre_count;
...@@ -147,6 +148,7 @@ struct gsi_evt_ring { ...@@ -147,6 +148,7 @@ struct gsi_evt_ring {
struct gsi { struct gsi {
struct device *dev; /* Same as IPA device */ struct device *dev; /* Same as IPA device */
enum ipa_version version;
struct net_device dummy_dev; /* needed for NAPI */ struct net_device dummy_dev; /* needed for NAPI */
void __iomem *virt; void __iomem *virt;
u32 irq; u32 irq;
...@@ -164,14 +166,13 @@ struct gsi { ...@@ -164,14 +166,13 @@ struct gsi {
/** /**
* gsi_setup() - Set up the GSI subsystem * gsi_setup() - Set up the GSI subsystem
* @gsi: Address of GSI structure embedded in an IPA structure * @gsi: Address of GSI structure embedded in an IPA structure
* @legacy: Set up for legacy hardware
* *
* Return: 0 if successful, or a negative error code * Return: 0 if successful, or a negative error code
* *
* Performs initialization that must wait until the GSI hardware is * Performs initialization that must wait until the GSI hardware is
* ready (including firmware loaded). * ready (including firmware loaded).
*/ */
int gsi_setup(struct gsi *gsi, bool legacy); int gsi_setup(struct gsi *gsi);
/** /**
* gsi_teardown() - Tear down GSI subsystem * gsi_teardown() - Tear down GSI subsystem
...@@ -219,15 +220,15 @@ int gsi_channel_stop(struct gsi *gsi, u32 channel_id); ...@@ -219,15 +220,15 @@ int gsi_channel_stop(struct gsi *gsi, u32 channel_id);
* gsi_channel_reset() - Reset an allocated GSI channel * gsi_channel_reset() - Reset an allocated GSI channel
* @gsi: GSI pointer * @gsi: GSI pointer
* @channel_id: Channel to be reset * @channel_id: Channel to be reset
* @legacy: Legacy behavior * @doorbell: Whether to (possibly) enable the doorbell engine
* *
* Reset a channel and reconfigure it. The @legacy flag indicates * Reset a channel and reconfigure it. The @doorbell flag indicates
* that some steps should be done differently for legacy hardware. * that the doorbell engine should be enabled if needed.
* *
* GSI hardware relinquishes ownership of all pending receive buffer * GSI hardware relinquishes ownership of all pending receive buffer
* transactions and they will complete with their cancelled flag set. * transactions and they will complete with their cancelled flag set.
*/ */
void gsi_channel_reset(struct gsi *gsi, u32 channel_id, bool legacy); void gsi_channel_reset(struct gsi *gsi, u32 channel_id, bool doorbell);
int gsi_channel_suspend(struct gsi *gsi, u32 channel_id, bool stop); int gsi_channel_suspend(struct gsi *gsi, u32 channel_id, bool stop);
int gsi_channel_resume(struct gsi *gsi, u32 channel_id, bool start); int gsi_channel_resume(struct gsi *gsi, u32 channel_id, bool start);
...@@ -236,15 +237,18 @@ int gsi_channel_resume(struct gsi *gsi, u32 channel_id, bool start); ...@@ -236,15 +237,18 @@ int gsi_channel_resume(struct gsi *gsi, u32 channel_id, bool start);
* gsi_init() - Initialize the GSI subsystem * gsi_init() - Initialize the GSI subsystem
* @gsi: Address of GSI structure embedded in an IPA structure * @gsi: Address of GSI structure embedded in an IPA structure
* @pdev: IPA platform device * @pdev: IPA platform device
* @version: IPA hardware version (implies GSI version)
* @count: Number of entries in the configuration data array
* @data: Endpoint and channel configuration data
* *
* Return: 0 if successful, or a negative error code * Return: 0 if successful, or a negative error code
* *
* Early stage initialization of the GSI subsystem, performing tasks * Early stage initialization of the GSI subsystem, performing tasks
* that can be done before the GSI hardware is ready to use. * that can be done before the GSI hardware is ready to use.
*/ */
int gsi_init(struct gsi *gsi, struct platform_device *pdev, bool prefetch, int gsi_init(struct gsi *gsi, struct platform_device *pdev,
u32 count, const struct ipa_gsi_endpoint_data *data, enum ipa_version version, u32 count,
bool modem_alloc); const struct ipa_gsi_endpoint_data *data);
/** /**
* gsi_exit() - Exit the GSI subsystem * gsi_exit() - Exit the GSI subsystem
......
...@@ -1217,7 +1217,6 @@ static int ipa_endpoint_reset_rx_aggr(struct ipa_endpoint *endpoint) ...@@ -1217,7 +1217,6 @@ static int ipa_endpoint_reset_rx_aggr(struct ipa_endpoint *endpoint)
struct gsi *gsi = &ipa->gsi; struct gsi *gsi = &ipa->gsi;
bool suspended = false; bool suspended = false;
dma_addr_t addr; dma_addr_t addr;
bool legacy;
u32 retries; u32 retries;
u32 len = 1; u32 len = 1;
void *virt; void *virt;
...@@ -1279,8 +1278,7 @@ static int ipa_endpoint_reset_rx_aggr(struct ipa_endpoint *endpoint) ...@@ -1279,8 +1278,7 @@ static int ipa_endpoint_reset_rx_aggr(struct ipa_endpoint *endpoint)
* complete the channel reset sequence. Finish by suspending the * complete the channel reset sequence. Finish by suspending the
* channel again (if necessary). * channel again (if necessary).
*/ */
legacy = ipa->version == IPA_VERSION_3_5_1; gsi_channel_reset(gsi, endpoint->channel_id, true);
gsi_channel_reset(gsi, endpoint->channel_id, legacy);
msleep(1); msleep(1);
...@@ -1303,21 +1301,19 @@ static void ipa_endpoint_reset(struct ipa_endpoint *endpoint) ...@@ -1303,21 +1301,19 @@ static void ipa_endpoint_reset(struct ipa_endpoint *endpoint)
u32 channel_id = endpoint->channel_id; u32 channel_id = endpoint->channel_id;
struct ipa *ipa = endpoint->ipa; struct ipa *ipa = endpoint->ipa;
bool special; bool special;
bool legacy;
int ret = 0; int ret = 0;
/* On IPA v3.5.1, if an RX endpoint is reset while aggregation /* On IPA v3.5.1, if an RX endpoint is reset while aggregation
* is active, we need to handle things specially to recover. * is active, we need to handle things specially to recover.
* All other cases just need to reset the underlying GSI channel. * All other cases just need to reset the underlying GSI channel.
*
* IPA v3.5.1 enables the doorbell engine. Newer versions do not.
*/ */
legacy = ipa->version == IPA_VERSION_3_5_1; special = ipa->version == IPA_VERSION_3_5_1 &&
special = !endpoint->toward_ipa && endpoint->data->aggregation; !endpoint->toward_ipa &&
if (legacy && special && ipa_endpoint_aggr_active(endpoint)) endpoint->data->aggregation;
if (special && ipa_endpoint_aggr_active(endpoint))
ret = ipa_endpoint_reset_rx_aggr(endpoint); ret = ipa_endpoint_reset_rx_aggr(endpoint);
else else
gsi_channel_reset(&ipa->gsi, channel_id, legacy); gsi_channel_reset(&ipa->gsi, channel_id, true);
if (ret) if (ret)
dev_err(&ipa->pdev->dev, dev_err(&ipa->pdev->dev,
......
...@@ -111,8 +111,7 @@ int ipa_setup(struct ipa *ipa) ...@@ -111,8 +111,7 @@ int ipa_setup(struct ipa *ipa)
struct device *dev = &ipa->pdev->dev; struct device *dev = &ipa->pdev->dev;
int ret; int ret;
/* Setup for IPA v3.5.1 has some slight differences */ ret = gsi_setup(&ipa->gsi);
ret = gsi_setup(&ipa->gsi, ipa->version == IPA_VERSION_3_5_1);
if (ret) if (ret)
return ret; return ret;
...@@ -723,10 +722,8 @@ static int ipa_probe(struct platform_device *pdev) ...@@ -723,10 +722,8 @@ static int ipa_probe(struct platform_device *pdev)
const struct ipa_data *data; const struct ipa_data *data;
struct ipa_clock *clock; struct ipa_clock *clock;
struct rproc *rproc; struct rproc *rproc;
bool modem_alloc;
bool modem_init; bool modem_init;
struct ipa *ipa; struct ipa *ipa;
bool prefetch;
phandle ph; phandle ph;
int ret; int ret;
...@@ -788,13 +785,8 @@ static int ipa_probe(struct platform_device *pdev) ...@@ -788,13 +785,8 @@ static int ipa_probe(struct platform_device *pdev)
if (ret) if (ret)
goto err_reg_exit; goto err_reg_exit;
/* GSI v2.0+ (IPA v4.0+) uses prefetch for the command channel */ ret = gsi_init(&ipa->gsi, pdev, ipa->version, data->endpoint_count,
prefetch = ipa->version != IPA_VERSION_3_5_1; data->endpoint_data);
/* IPA v4.2 requires the AP to allocate channels for the modem */
modem_alloc = ipa->version == IPA_VERSION_4_2;
ret = gsi_init(&ipa->gsi, pdev, prefetch, data->endpoint_count,
data->endpoint_data, modem_alloc);
if (ret) if (ret)
goto err_mem_exit; goto err_mem_exit;
......
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