diff --git a/drivers/net/ipa/Makefile b/drivers/net/ipa/Makefile index 166ef86f7ad3f..d87f2cfe08c61 100644 --- a/drivers/net/ipa/Makefile +++ b/drivers/net/ipa/Makefile @@ -4,6 +4,9 @@ IPA_VERSIONS := 3.1 3.5.1 4.2 4.5 4.7 4.9 4.11 +# Some IPA versions can reuse another set of GSI register definitions. +GSI_IPA_VERSIONS := 3.1 + obj-$(CONFIG_QCOM_IPA) += ipa.o ipa-y := ipa_main.o ipa_power.o ipa_reg.o ipa_mem.o \ @@ -13,6 +16,8 @@ ipa-y := ipa_main.o ipa_power.o ipa_reg.o ipa_mem.o \ ipa_resource.o ipa_qmi.o ipa_qmi_msg.o \ ipa_sysfs.o +ipa-y += $(GSI_IPA_VERSIONS:%=reg/gsi_reg-v%.o) + ipa-y += $(IPA_VERSIONS:%=reg/ipa_reg-v%.o) ipa-y += $(IPA_VERSIONS:%=data/ipa_data-v%.o) diff --git a/drivers/net/ipa/gsi.c b/drivers/net/ipa/gsi.c index a000bef49f8e5..f07b7554d21fd 100644 --- a/drivers/net/ipa/gsi.c +++ b/drivers/net/ipa/gsi.c @@ -16,6 +16,7 @@ #include #include "gsi.h" +#include "reg.h" #include "gsi_reg.h" #include "gsi_private.h" #include "gsi_trans.h" @@ -796,6 +797,7 @@ static void gsi_channel_program(struct gsi_channel *channel, bool doorbell) union gsi_channel_scratch scr = { }; struct gsi_channel_scratch_gpi *gpi; struct gsi *gsi = channel->gsi; + const struct reg *reg; u32 wrr_weight = 0; u32 val; @@ -819,6 +821,8 @@ static void gsi_channel_program(struct gsi_channel *channel, bool doorbell) val = upper_32_bits(channel->tre_ring.addr); iowrite32(val, gsi->virt + GSI_CH_C_CNTXT_3_OFFSET(channel_id)); + reg = gsi_reg(gsi, CH_C_QOS); + /* Command channel gets low weighted round-robin priority */ if (channel->command) wrr_weight = field_max(WRR_WEIGHT_FMASK); @@ -845,7 +849,7 @@ static void gsi_channel_program(struct gsi_channel *channel, bool doorbell) if (gsi->version >= IPA_VERSION_4_9) val |= DB_IN_BYTES; - iowrite32(val, gsi->virt + GSI_CH_C_QOS_OFFSET(channel_id)); + iowrite32(val, gsi->virt + reg_n_offset(reg, channel_id)); /* Now update the scratch registers for GPI protocol */ gpi = &scr.gpi; diff --git a/drivers/net/ipa/gsi.h b/drivers/net/ipa/gsi.h index 49dcadba4e0b9..bc5ff617341a7 100644 --- a/drivers/net/ipa/gsi.h +++ b/drivers/net/ipa/gsi.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. - * Copyright (C) 2018-2022 Linaro Ltd. + * Copyright (C) 2018-2023 Linaro Ltd. */ #ifndef _GSI_H_ #define _GSI_H_ @@ -142,6 +142,8 @@ struct gsi { enum ipa_version version; void __iomem *virt_raw; /* I/O mapped address range */ void __iomem *virt; /* Adjusted for most registers */ + const struct regs *regs; + u32 irq; u32 channel_count; u32 evt_ring_count; diff --git a/drivers/net/ipa/gsi_reg.c b/drivers/net/ipa/gsi_reg.c index c20b3bcdd4151..2334244d40da0 100644 --- a/drivers/net/ipa/gsi_reg.c +++ b/drivers/net/ipa/gsi_reg.c @@ -6,6 +6,7 @@ #include #include "gsi.h" +#include "reg.h" #include "gsi_reg.h" /* GSI EE registers as a group are shifted downward by a fixed constant amount @@ -85,6 +86,31 @@ static bool gsi_reg_id_valid(struct gsi *gsi, enum gsi_reg_id reg_id) } } +const struct reg *gsi_reg(struct gsi *gsi, enum gsi_reg_id reg_id) +{ + if (WARN(!gsi_reg_id_valid(gsi, reg_id), "invalid reg %u\n", reg_id)) + return NULL; + + return reg(gsi->regs, reg_id); +} + +static const struct regs *gsi_regs(struct gsi *gsi) +{ + switch (gsi->version) { + case IPA_VERSION_3_1: + case IPA_VERSION_3_5_1: + case IPA_VERSION_4_2: + case IPA_VERSION_4_5: + case IPA_VERSION_4_7: + case IPA_VERSION_4_9: + case IPA_VERSION_4_11: + return &gsi_regs_v3_1; + + default: + return NULL; + } +} + /* Sets gsi->virt_raw and gsi->virt, and I/O maps the "gsi" memory range */ int gsi_reg_init(struct gsi *gsi, struct platform_device *pdev) { @@ -93,8 +119,6 @@ int gsi_reg_init(struct gsi *gsi, struct platform_device *pdev) resource_size_t size; u32 adjust; - (void)gsi_reg_id_valid; /* Avoid a warning */ - /* Get GSI memory range and map it */ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "gsi"); if (!res) { @@ -116,6 +140,12 @@ int gsi_reg_init(struct gsi *gsi, struct platform_device *pdev) return -EINVAL; } + gsi->regs = gsi_regs(gsi); + if (!gsi->regs) { + dev_err(dev, "unsupported IPA version %u (?)\n", gsi->version); + return -EINVAL; + } + gsi->virt_raw = ioremap(res->start, size); if (!gsi->virt_raw) { dev_err(dev, "unable to remap \"gsi\" memory\n"); diff --git a/drivers/net/ipa/gsi_reg.h b/drivers/net/ipa/gsi_reg.h index 1f613cd677b01..398546fbfd697 100644 --- a/drivers/net/ipa/gsi_reg.h +++ b/drivers/net/ipa/gsi_reg.h @@ -140,8 +140,7 @@ enum gsi_channel_type { #define GSI_CH_C_CNTXT_3_OFFSET(ch) \ (0x0001c00c + 0x4000 * GSI_EE_AP + 0x80 * (ch)) -#define GSI_CH_C_QOS_OFFSET(ch) \ - (0x0001c05c + 0x4000 * GSI_EE_AP + 0x80 * (ch)) +/* CH_C_QOS register */ #define WRR_WEIGHT_FMASK GENMASK(3, 0) #define MAX_PREFETCH_FMASK GENMASK(8, 8) #define USE_DB_ENG_FMASK GENMASK(9, 9) @@ -443,6 +442,15 @@ enum gsi_generic_ee_result { GENERIC_EE_NO_RESOURCES = 0x7, }; +extern const struct regs gsi_regs_v3_1; + +/** + * gsi_reg() - Return the structure describing a GSI register + * @gsi: GSI pointer + * @reg_id: GSI register ID + */ +const struct reg *gsi_reg(struct gsi *gsi, enum gsi_reg_id reg_id); + /** * gsi_reg_init() - Perform GSI register initialization * @gsi: GSI pointer diff --git a/drivers/net/ipa/reg/gsi_reg-v3.1.c b/drivers/net/ipa/reg/gsi_reg-v3.1.c new file mode 100644 index 0000000000000..c4d4beb7738f3 --- /dev/null +++ b/drivers/net/ipa/reg/gsi_reg-v3.1.c @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* Copyright (C) 2023 Linaro Ltd. */ + +#include + +#include "../gsi.h" +#include "../reg.h" +#include "../gsi_reg.h" + +REG_STRIDE(CH_C_QOS, ch_c_qos, 0x0001c05c + 0x4000 * GSI_EE_AP, 0x80); + +static const struct reg *reg_array[] = { + [CH_C_QOS] = ®_ch_c_qos, +}; + +const struct regs gsi_regs_v3_1 = { + .reg_count = ARRAY_SIZE(reg_array), + .reg = reg_array, +};