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.org Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Коммит
2c24eefb24
|
@ -21,6 +21,7 @@
|
|||
#include "gsi_trans.h"
|
||||
#include "ipa_gsi.h"
|
||||
#include "ipa_data.h"
|
||||
#include "ipa_version.h"
|
||||
|
||||
/**
|
||||
* DOC: The IPA Generic Software Interface
|
||||
|
@ -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) */
|
||||
|
||||
/* Enable the doorbell engine if requested */
|
||||
if (doorbell)
|
||||
/* We enable the doorbell engine for IPA v3.5.1 */
|
||||
if (gsi->version == IPA_VERSION_3_5_1 && doorbell)
|
||||
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;
|
||||
|
||||
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)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* Reset and reconfigure a channel (possibly leaving doorbell disabled) */
|
||||
void gsi_channel_reset(struct gsi *gsi, u32 channel_id, bool legacy)
|
||||
/* Reset and reconfigure a channel, (possibly) enabling the doorbell engine */
|
||||
void gsi_channel_reset(struct gsi *gsi, u32 channel_id, bool doorbell)
|
||||
{
|
||||
struct gsi_channel *channel = &gsi->channel[channel_id];
|
||||
|
||||
|
@ -838,10 +840,10 @@ void gsi_channel_reset(struct gsi *gsi, u32 channel_id, bool legacy)
|
|||
|
||||
gsi_channel_reset_command(channel);
|
||||
/* 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_program(channel, legacy);
|
||||
gsi_channel_program(channel, doorbell);
|
||||
gsi_channel_trans_cancel_pending(channel);
|
||||
|
||||
mutex_unlock(&gsi->mutex);
|
||||
|
@ -1452,8 +1454,7 @@ static void gsi_evt_ring_teardown(struct gsi *gsi)
|
|||
}
|
||||
|
||||
/* Setup function for a single channel */
|
||||
static int gsi_channel_setup_one(struct gsi *gsi, u32 channel_id,
|
||||
bool legacy)
|
||||
static int gsi_channel_setup_one(struct gsi *gsi, u32 channel_id)
|
||||
{
|
||||
struct gsi_channel *channel = &gsi->channel[channel_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,
|
|||
if (ret)
|
||||
goto err_evt_ring_de_alloc;
|
||||
|
||||
gsi_channel_program(channel, legacy);
|
||||
gsi_channel_program(channel, true);
|
||||
|
||||
if (channel->toward_ipa)
|
||||
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)
|
|||
}
|
||||
|
||||
/* 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 mask;
|
||||
|
@ -1561,7 +1562,7 @@ static int gsi_channel_setup(struct gsi *gsi, bool legacy)
|
|||
mutex_lock(&gsi->mutex);
|
||||
|
||||
do {
|
||||
ret = gsi_channel_setup_one(gsi, channel_id, legacy);
|
||||
ret = gsi_channel_setup_one(gsi, channel_id);
|
||||
if (ret)
|
||||
goto err_unwind;
|
||||
} while (++channel_id < gsi->channel_count);
|
||||
|
@ -1647,7 +1648,7 @@ static void gsi_channel_teardown(struct gsi *gsi)
|
|||
}
|
||||
|
||||
/* 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;
|
||||
u32 val;
|
||||
|
@ -1691,7 +1692,7 @@ int gsi_setup(struct gsi *gsi, bool legacy)
|
|||
/* Writing 1 indicates IRQ interrupts; 0 would be MSI */
|
||||
iowrite32(1, gsi->virt + GSI_CNTXT_INTSET_OFFSET);
|
||||
|
||||
return gsi_channel_setup(gsi, legacy);
|
||||
return gsi_channel_setup(gsi);
|
||||
}
|
||||
|
||||
/* Inverse of gsi_setup() */
|
||||
|
@ -1814,7 +1815,7 @@ static bool gsi_channel_data_valid(struct gsi *gsi,
|
|||
/* Init function for a single channel */
|
||||
static int gsi_channel_init_one(struct gsi *gsi,
|
||||
const struct ipa_gsi_endpoint_data *data,
|
||||
bool command, bool prefetch)
|
||||
bool command)
|
||||
{
|
||||
struct gsi_channel *channel;
|
||||
u32 tre_count;
|
||||
|
@ -1838,7 +1839,6 @@ static int gsi_channel_init_one(struct gsi *gsi,
|
|||
channel->gsi = gsi;
|
||||
channel->toward_ipa = data->toward_ipa;
|
||||
channel->command = command;
|
||||
channel->use_prefetch = command && prefetch;
|
||||
channel->tlv_count = data->channel.tlv_count;
|
||||
channel->tre_count = tre_count;
|
||||
channel->event_count = data->channel.event_count;
|
||||
|
@ -1892,13 +1892,16 @@ static void gsi_channel_exit_one(struct gsi_channel *channel)
|
|||
}
|
||||
|
||||
/* Init function for channels */
|
||||
static int gsi_channel_init(struct gsi *gsi, bool prefetch, u32 count,
|
||||
const struct ipa_gsi_endpoint_data *data,
|
||||
bool modem_alloc)
|
||||
static int gsi_channel_init(struct gsi *gsi, u32 count,
|
||||
const struct ipa_gsi_endpoint_data *data)
|
||||
{
|
||||
bool modem_alloc;
|
||||
int ret = 0;
|
||||
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);
|
||||
|
||||
/* 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,
|
|||
continue;
|
||||
}
|
||||
|
||||
ret = gsi_channel_init_one(gsi, &data[i], command, prefetch);
|
||||
ret = gsi_channel_init_one(gsi, &data[i], command);
|
||||
if (ret)
|
||||
goto err_unwind;
|
||||
}
|
||||
|
@ -1952,9 +1955,9 @@ static void gsi_channel_exit(struct gsi *gsi)
|
|||
}
|
||||
|
||||
/* Init function for GSI. GSI hardware does not need to be "ready" */
|
||||
int gsi_init(struct gsi *gsi, struct platform_device *pdev, bool prefetch,
|
||||
u32 count, const struct ipa_gsi_endpoint_data *data,
|
||||
bool modem_alloc)
|
||||
int gsi_init(struct gsi *gsi, struct platform_device *pdev,
|
||||
enum ipa_version version, u32 count,
|
||||
const struct ipa_gsi_endpoint_data *data)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct resource *res;
|
||||
|
@ -1965,6 +1968,7 @@ int gsi_init(struct gsi *gsi, struct platform_device *pdev, bool prefetch,
|
|||
gsi_validate_build();
|
||||
|
||||
gsi->dev = dev;
|
||||
gsi->version = version;
|
||||
|
||||
/* The GSI layer performs NAPI on all endpoints. NAPI requires a
|
||||
* 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,
|
|||
goto err_free_irq;
|
||||
}
|
||||
|
||||
ret = gsi_channel_init(gsi, prefetch, count, data, modem_alloc);
|
||||
ret = gsi_channel_init(gsi, count, data);
|
||||
if (ret)
|
||||
goto err_iounmap;
|
||||
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/netdevice.h>
|
||||
|
||||
#include "ipa_version.h"
|
||||
|
||||
/* Maximum number of channels and event rings supported by the driver */
|
||||
#define GSI_CHANNEL_COUNT_MAX 17
|
||||
#define GSI_EVT_RING_COUNT_MAX 13
|
||||
|
@ -107,7 +109,6 @@ struct gsi_channel {
|
|||
struct gsi *gsi;
|
||||
bool toward_ipa;
|
||||
bool command; /* AP command TX channel or not */
|
||||
bool use_prefetch; /* use prefetch (else escape buf) */
|
||||
|
||||
u8 tlv_count; /* # entries in TLV FIFO */
|
||||
u16 tre_count;
|
||||
|
@ -147,6 +148,7 @@ struct gsi_evt_ring {
|
|||
|
||||
struct gsi {
|
||||
struct device *dev; /* Same as IPA device */
|
||||
enum ipa_version version;
|
||||
struct net_device dummy_dev; /* needed for NAPI */
|
||||
void __iomem *virt;
|
||||
u32 irq;
|
||||
|
@ -164,14 +166,13 @@ struct gsi {
|
|||
/**
|
||||
* gsi_setup() - Set up the GSI subsystem
|
||||
* @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
|
||||
*
|
||||
* Performs initialization that must wait until the GSI hardware is
|
||||
* ready (including firmware loaded).
|
||||
*/
|
||||
int gsi_setup(struct gsi *gsi, bool legacy);
|
||||
int gsi_setup(struct gsi *gsi);
|
||||
|
||||
/**
|
||||
* gsi_teardown() - Tear down GSI subsystem
|
||||
|
@ -219,15 +220,15 @@ int gsi_channel_stop(struct gsi *gsi, u32 channel_id);
|
|||
* gsi_channel_reset() - Reset an allocated GSI channel
|
||||
* @gsi: GSI pointer
|
||||
* @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
|
||||
* that some steps should be done differently for legacy hardware.
|
||||
* Reset a channel and reconfigure it. The @doorbell flag indicates
|
||||
* that the doorbell engine should be enabled if needed.
|
||||
*
|
||||
* GSI hardware relinquishes ownership of all pending receive buffer
|
||||
* 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_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: Address of GSI structure embedded in an IPA structure
|
||||
* @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
|
||||
*
|
||||
* Early stage initialization of the GSI subsystem, performing tasks
|
||||
* that can be done before the GSI hardware is ready to use.
|
||||
*/
|
||||
int gsi_init(struct gsi *gsi, struct platform_device *pdev, bool prefetch,
|
||||
u32 count, const struct ipa_gsi_endpoint_data *data,
|
||||
bool modem_alloc);
|
||||
int gsi_init(struct gsi *gsi, struct platform_device *pdev,
|
||||
enum ipa_version version, u32 count,
|
||||
const struct ipa_gsi_endpoint_data *data);
|
||||
|
||||
/**
|
||||
* gsi_exit() - Exit the GSI subsystem
|
||||
|
|
|
@ -1217,7 +1217,6 @@ static int ipa_endpoint_reset_rx_aggr(struct ipa_endpoint *endpoint)
|
|||
struct gsi *gsi = &ipa->gsi;
|
||||
bool suspended = false;
|
||||
dma_addr_t addr;
|
||||
bool legacy;
|
||||
u32 retries;
|
||||
u32 len = 1;
|
||||
void *virt;
|
||||
|
@ -1279,8 +1278,7 @@ static int ipa_endpoint_reset_rx_aggr(struct ipa_endpoint *endpoint)
|
|||
* complete the channel reset sequence. Finish by suspending the
|
||||
* channel again (if necessary).
|
||||
*/
|
||||
legacy = ipa->version == IPA_VERSION_3_5_1;
|
||||
gsi_channel_reset(gsi, endpoint->channel_id, legacy);
|
||||
gsi_channel_reset(gsi, endpoint->channel_id, true);
|
||||
|
||||
msleep(1);
|
||||
|
||||
|
@ -1303,21 +1301,19 @@ static void ipa_endpoint_reset(struct ipa_endpoint *endpoint)
|
|||
u32 channel_id = endpoint->channel_id;
|
||||
struct ipa *ipa = endpoint->ipa;
|
||||
bool special;
|
||||
bool legacy;
|
||||
int ret = 0;
|
||||
|
||||
/* On IPA v3.5.1, if an RX endpoint is reset while aggregation
|
||||
* is active, we need to handle things specially to recover.
|
||||
* 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 = !endpoint->toward_ipa && endpoint->data->aggregation;
|
||||
if (legacy && special && ipa_endpoint_aggr_active(endpoint))
|
||||
special = ipa->version == IPA_VERSION_3_5_1 &&
|
||||
!endpoint->toward_ipa &&
|
||||
endpoint->data->aggregation;
|
||||
if (special && ipa_endpoint_aggr_active(endpoint))
|
||||
ret = ipa_endpoint_reset_rx_aggr(endpoint);
|
||||
else
|
||||
gsi_channel_reset(&ipa->gsi, channel_id, legacy);
|
||||
gsi_channel_reset(&ipa->gsi, channel_id, true);
|
||||
|
||||
if (ret)
|
||||
dev_err(&ipa->pdev->dev,
|
||||
|
|
|
@ -111,8 +111,7 @@ int ipa_setup(struct ipa *ipa)
|
|||
struct device *dev = &ipa->pdev->dev;
|
||||
int ret;
|
||||
|
||||
/* Setup for IPA v3.5.1 has some slight differences */
|
||||
ret = gsi_setup(&ipa->gsi, ipa->version == IPA_VERSION_3_5_1);
|
||||
ret = gsi_setup(&ipa->gsi);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -723,10 +722,8 @@ static int ipa_probe(struct platform_device *pdev)
|
|||
const struct ipa_data *data;
|
||||
struct ipa_clock *clock;
|
||||
struct rproc *rproc;
|
||||
bool modem_alloc;
|
||||
bool modem_init;
|
||||
struct ipa *ipa;
|
||||
bool prefetch;
|
||||
phandle ph;
|
||||
int ret;
|
||||
|
||||
|
@ -788,13 +785,8 @@ static int ipa_probe(struct platform_device *pdev)
|
|||
if (ret)
|
||||
goto err_reg_exit;
|
||||
|
||||
/* GSI v2.0+ (IPA v4.0+) uses prefetch for the command channel */
|
||||
prefetch = ipa->version != IPA_VERSION_3_5_1;
|
||||
/* 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);
|
||||
ret = gsi_init(&ipa->gsi, pdev, ipa->version, data->endpoint_count,
|
||||
data->endpoint_data);
|
||||
if (ret)
|
||||
goto err_mem_exit;
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче