Commit 571b1e7e authored by Alex Elder's avatar Alex Elder Committed by David S. Miller

net: ipa: use a separate pointer for adjusted GSI memory

This patch actually fixes a bug, though it doesn't affect the two
platforms supported currently.  The fix implements GSI memory
pointers a bit differently.

For IPA version 4.5 and above, the address space for almost all GSI
registers is adjusted downward by a fixed amount.  This is currently
handled by adjusting the I/O virtual address pointer after it has
been mapped.  The bug is that the pointer is not "de-adjusted" as it
should be when it's unmapped.

This patch fixes that error, but it does so by maintaining one "raw"
pointer for the mapped memory range.  This is assigned when the
memory is mapped and used to unmap the memory.  This pointer is also
used to access the two registers that do *not* sit in the "adjusted"
memory space.

Rather than adjusting *that* pointer, we maintain a separate pointer
that's an adjusted copy of the "raw" pointer, and that is used for
most GSI register accesses.
Signed-off-by: default avatarAlex Elder <elder@linaro.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 21cc70c7
// SPDX-License-Identifier: GPL-2.0 // SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. /* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
* Copyright (C) 2018-2020 Linaro Ltd. * Copyright (C) 2018-2021 Linaro Ltd.
*/ */
#include <linux/types.h> #include <linux/types.h>
...@@ -195,8 +195,6 @@ static void gsi_irq_type_disable(struct gsi *gsi, enum gsi_irq_type_id type_id) ...@@ -195,8 +195,6 @@ static void gsi_irq_type_disable(struct gsi *gsi, enum gsi_irq_type_id type_id)
/* Turn off all GSI interrupts initially */ /* Turn off all GSI interrupts initially */
static void gsi_irq_setup(struct gsi *gsi) static void gsi_irq_setup(struct gsi *gsi)
{ {
u32 adjust;
/* Disable all interrupt types */ /* Disable all interrupt types */
gsi_irq_type_update(gsi, 0); gsi_irq_type_update(gsi, 0);
...@@ -206,10 +204,9 @@ static void gsi_irq_setup(struct gsi *gsi) ...@@ -206,10 +204,9 @@ static void gsi_irq_setup(struct gsi *gsi)
iowrite32(0, gsi->virt + GSI_CNTXT_GLOB_IRQ_EN_OFFSET); iowrite32(0, gsi->virt + GSI_CNTXT_GLOB_IRQ_EN_OFFSET);
iowrite32(0, gsi->virt + GSI_CNTXT_SRC_IEOB_IRQ_MSK_OFFSET); iowrite32(0, gsi->virt + GSI_CNTXT_SRC_IEOB_IRQ_MSK_OFFSET);
/* Reverse the offset adjustment for inter-EE register offsets */ /* The inter-EE registers are in the non-adjusted address range */
adjust = gsi->version < IPA_VERSION_4_5 ? 0 : GSI_EE_REG_ADJUST; iowrite32(0, gsi->virt_raw + GSI_INTER_EE_SRC_CH_IRQ_OFFSET);
iowrite32(0, gsi->virt + adjust + GSI_INTER_EE_SRC_CH_IRQ_OFFSET); iowrite32(0, gsi->virt_raw + GSI_INTER_EE_SRC_EV_CH_IRQ_OFFSET);
iowrite32(0, gsi->virt + adjust + GSI_INTER_EE_SRC_EV_CH_IRQ_OFFSET);
iowrite32(0, gsi->virt + GSI_CNTXT_GSI_IRQ_EN_OFFSET); iowrite32(0, gsi->virt + GSI_CNTXT_GSI_IRQ_EN_OFFSET);
} }
...@@ -2181,9 +2178,8 @@ int gsi_init(struct gsi *gsi, struct platform_device *pdev, ...@@ -2181,9 +2178,8 @@ int gsi_init(struct gsi *gsi, struct platform_device *pdev,
gsi->dev = dev; gsi->dev = dev;
gsi->version = version; gsi->version = version;
/* The GSI layer performs NAPI on all endpoints. NAPI requires a /* GSI uses NAPI on all channels. Create a dummy network device
* network device structure, but the GSI layer does not have one, * for the channel NAPI contexts to be associated with.
* so we must create a dummy network device for this purpose.
*/ */
init_dummy_netdev(&gsi->dummy_dev); init_dummy_netdev(&gsi->dummy_dev);
...@@ -2208,13 +2204,13 @@ int gsi_init(struct gsi *gsi, struct platform_device *pdev, ...@@ -2208,13 +2204,13 @@ int gsi_init(struct gsi *gsi, struct platform_device *pdev,
return -EINVAL; return -EINVAL;
} }
gsi->virt = ioremap(res->start, size); gsi->virt_raw = ioremap(res->start, size);
if (!gsi->virt) { if (!gsi->virt_raw) {
dev_err(dev, "unable to remap \"gsi\" memory\n"); dev_err(dev, "unable to remap \"gsi\" memory\n");
return -ENOMEM; return -ENOMEM;
} }
/* Adjust register range pointer downward for newer IPA versions */ /* Most registers are accessed using an adjusted register range */
gsi->virt -= adjust; gsi->virt = gsi->virt_raw - adjust;
init_completion(&gsi->completion); init_completion(&gsi->completion);
...@@ -2233,7 +2229,7 @@ int gsi_init(struct gsi *gsi, struct platform_device *pdev, ...@@ -2233,7 +2229,7 @@ int gsi_init(struct gsi *gsi, struct platform_device *pdev,
err_irq_exit: err_irq_exit:
gsi_irq_exit(gsi); gsi_irq_exit(gsi);
err_iounmap: err_iounmap:
iounmap(gsi->virt); iounmap(gsi->virt_raw);
return ret; return ret;
} }
...@@ -2244,7 +2240,7 @@ void gsi_exit(struct gsi *gsi) ...@@ -2244,7 +2240,7 @@ void gsi_exit(struct gsi *gsi)
mutex_destroy(&gsi->mutex); mutex_destroy(&gsi->mutex);
gsi_channel_exit(gsi); gsi_channel_exit(gsi);
gsi_irq_exit(gsi); gsi_irq_exit(gsi);
iounmap(gsi->virt); iounmap(gsi->virt_raw);
} }
/* The maximum number of outstanding TREs on a channel. This limits /* The maximum number of outstanding TREs on a channel. This limits
......
/* SPDX-License-Identifier: GPL-2.0 */ /* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. /* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
* Copyright (C) 2018-2020 Linaro Ltd. * Copyright (C) 2018-2021 Linaro Ltd.
*/ */
#ifndef _GSI_H_ #ifndef _GSI_H_
#define _GSI_H_ #define _GSI_H_
...@@ -149,7 +149,8 @@ struct gsi { ...@@ -149,7 +149,8 @@ struct gsi {
struct device *dev; /* Same as IPA device */ struct device *dev; /* Same as IPA device */
enum ipa_version version; 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_raw; /* I/O mapped address range */
void __iomem *virt; /* Adjusted for most registers */
u32 irq; u32 irq;
u32 channel_count; u32 channel_count;
u32 evt_ring_count; u32 evt_ring_count;
......
/* SPDX-License-Identifier: GPL-2.0 */ /* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. /* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
* Copyright (C) 2018-2020 Linaro Ltd. * Copyright (C) 2018-2021 Linaro Ltd.
*/ */
#ifndef _GSI_REG_H_ #ifndef _GSI_REG_H_
#define _GSI_REG_H_ #define _GSI_REG_H_
...@@ -38,17 +38,21 @@ ...@@ -38,17 +38,21 @@
* (though the actual limit is hardware-dependent). * (though the actual limit is hardware-dependent).
*/ */
/* GSI EE registers as a group are shifted downward by a fixed /* GSI EE registers as a group are shifted downward by a fixed constant amount
* constant amount for IPA versions 4.5 and beyond. This applies * for IPA versions 4.5 and beyond. This applies to all GSI registers we use
* to all GSI registers we use *except* the ones that disable * *except* the ones that disable inter-EE interrupts for channels and event
* inter-EE interrupts for channels and event channels. * channels.
* *
* We handle this by adjusting the pointer to the mapped GSI memory * The "raw" (not adjusted) GSI register range is mapped, and a pointer to
* region downward. Then in the one place we use them (gsi_irq_setup()) * the mapped range is held in gsi->virt_raw. The inter-EE interrupt
* we undo that adjustment for the inter-EE interrupt registers. * registers are accessed using that pointer.
*
* Most registers are accessed using gsi->virt, which is a copy of the "raw"
* pointer, adjusted downward by the fixed amount.
*/ */
#define GSI_EE_REG_ADJUST 0x0000d000 /* IPA v4.5+ */ #define GSI_EE_REG_ADJUST 0x0000d000 /* IPA v4.5+ */
/* The two inter-EE IRQ register offsets are relative to gsi->virt_raw */
#define GSI_INTER_EE_SRC_CH_IRQ_OFFSET \ #define GSI_INTER_EE_SRC_CH_IRQ_OFFSET \
GSI_INTER_EE_N_SRC_CH_IRQ_OFFSET(GSI_EE_AP) GSI_INTER_EE_N_SRC_CH_IRQ_OFFSET(GSI_EE_AP)
#define GSI_INTER_EE_N_SRC_CH_IRQ_OFFSET(ee) \ #define GSI_INTER_EE_N_SRC_CH_IRQ_OFFSET(ee) \
...@@ -59,6 +63,7 @@ ...@@ -59,6 +63,7 @@
#define GSI_INTER_EE_N_SRC_EV_CH_IRQ_OFFSET(ee) \ #define GSI_INTER_EE_N_SRC_EV_CH_IRQ_OFFSET(ee) \
(0x0000c01c + 0x1000 * (ee)) (0x0000c01c + 0x1000 * (ee))
/* All other register offsets are relative to gsi->virt */
#define GSI_CH_C_CNTXT_0_OFFSET(ch) \ #define GSI_CH_C_CNTXT_0_OFFSET(ch) \
GSI_EE_N_CH_C_CNTXT_0_OFFSET((ch), GSI_EE_AP) GSI_EE_N_CH_C_CNTXT_0_OFFSET((ch), GSI_EE_AP)
#define GSI_EE_N_CH_C_CNTXT_0_OFFSET(ch, ee) \ #define GSI_EE_N_CH_C_CNTXT_0_OFFSET(ch, ee) \
......
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