diff options
Diffstat (limited to 'drivers/net/ipa')
-rw-r--r-- | drivers/net/ipa/gsi.c | 32 | ||||
-rw-r--r-- | drivers/net/ipa/gsi.h | 1 | ||||
-rw-r--r-- | drivers/net/ipa/gsi_reg.h | 59 | ||||
-rw-r--r-- | drivers/net/ipa/gsi_trans.c | 1 | ||||
-rw-r--r-- | drivers/net/ipa/ipa.h | 17 | ||||
-rw-r--r-- | drivers/net/ipa/ipa_clock.c | 28 | ||||
-rw-r--r-- | drivers/net/ipa/ipa_endpoint.c | 53 | ||||
-rw-r--r-- | drivers/net/ipa/ipa_interrupt.c | 14 | ||||
-rw-r--r-- | drivers/net/ipa/ipa_main.c | 72 | ||||
-rw-r--r-- | drivers/net/ipa/ipa_reg.h | 2 | ||||
-rw-r--r-- | drivers/net/ipa/ipa_uc.c | 2 |
11 files changed, 114 insertions, 167 deletions
diff --git a/drivers/net/ipa/gsi.c b/drivers/net/ipa/gsi.c index 0e63d35320aa..6bfac1efe037 100644 --- a/drivers/net/ipa/gsi.c +++ b/drivers/net/ipa/gsi.c @@ -254,8 +254,8 @@ static void gsi_irq_enable(struct gsi *gsi) /* We don't use inter-EE channel or event interrupts */ val = GSI_CNTXT_TYPE_IRQ_MSK_ALL; - val &= ~MSK_INTER_EE_CH_CTRL_FMASK; - val &= ~MSK_INTER_EE_EV_CTRL_FMASK; + val &= ~INTER_EE_CH_CTRL_FMASK; + val &= ~INTER_EE_EV_CTRL_FMASK; iowrite32(val, gsi->virt + GSI_CNTXT_TYPE_IRQ_MSK_OFFSET); val = GENMASK(gsi->channel_count - 1, 0); @@ -271,7 +271,7 @@ static void gsi_irq_enable(struct gsi *gsi) iowrite32(val, gsi->virt + GSI_CNTXT_GLOB_IRQ_EN_OFFSET); /* Never enable GSI_BREAK_POINT */ - val = GSI_CNTXT_GSI_IRQ_ALL & ~EN_BREAK_POINT_FMASK; + val = GSI_CNTXT_GSI_IRQ_ALL & ~BREAK_POINT_FMASK; iowrite32(val, gsi->virt + GSI_CNTXT_GSI_IRQ_EN_OFFSET); } @@ -1074,8 +1074,8 @@ static void gsi_isr_glob_ee(struct gsi *gsi) val &= ~ERROR_INT_FMASK; - if (val & EN_GP_INT1_FMASK) { - val ^= EN_GP_INT1_FMASK; + if (val & GP_INT1_FMASK) { + val ^= GP_INT1_FMASK; gsi_isr_gp_int1(gsi); } @@ -1600,7 +1600,7 @@ err_unwind_modem: /* Compute which modem channels need to be deallocated */ mask ^= gsi->modem_channel_bitmap; while (mask) { - u32 channel_id = __fls(mask); + channel_id = __fls(mask); mask ^= BIT(channel_id); @@ -1628,7 +1628,7 @@ static void gsi_channel_teardown(struct gsi *gsi) mutex_lock(&gsi->mutex); while (mask) { - u32 channel_id = __fls(mask); + channel_id = __fls(mask); mask ^= BIT(channel_id); @@ -1972,7 +1972,6 @@ int gsi_init(struct gsi *gsi, struct platform_device *pdev, bool prefetch, */ init_dummy_netdev(&gsi->dummy_dev); - /* Get the GSI IRQ and request for it to wake the system */ ret = platform_get_irq_byname(pdev, "gsi"); if (ret <= 0) { dev_err(dev, "DT error %d getting \"gsi\" IRQ property\n", ret); @@ -1987,31 +1986,26 @@ int gsi_init(struct gsi *gsi, struct platform_device *pdev, bool prefetch, } gsi->irq = irq; - ret = enable_irq_wake(gsi->irq); - if (ret) - dev_warn(dev, "error %d enabling gsi wake irq\n", ret); - gsi->irq_wake_enabled = !ret; - /* Get GSI memory range and map it */ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "gsi"); if (!res) { dev_err(dev, "DT error getting \"gsi\" memory property\n"); ret = -ENODEV; - goto err_disable_irq_wake; + goto err_free_irq; } size = resource_size(res); if (res->start > U32_MAX || size > U32_MAX - res->start) { dev_err(dev, "DT memory resource \"gsi\" out of range\n"); ret = -EINVAL; - goto err_disable_irq_wake; + goto err_free_irq; } gsi->virt = ioremap(res->start, size); if (!gsi->virt) { dev_err(dev, "unable to remap \"gsi\" memory\n"); ret = -ENOMEM; - goto err_disable_irq_wake; + goto err_free_irq; } ret = gsi_channel_init(gsi, prefetch, count, data, modem_alloc); @@ -2025,9 +2019,7 @@ int gsi_init(struct gsi *gsi, struct platform_device *pdev, bool prefetch, err_iounmap: iounmap(gsi->virt); -err_disable_irq_wake: - if (gsi->irq_wake_enabled) - (void)disable_irq_wake(gsi->irq); +err_free_irq: free_irq(gsi->irq, gsi); return ret; @@ -2038,8 +2030,6 @@ void gsi_exit(struct gsi *gsi) { mutex_destroy(&gsi->mutex); gsi_channel_exit(gsi); - if (gsi->irq_wake_enabled) - (void)disable_irq_wake(gsi->irq); free_irq(gsi->irq, gsi); iounmap(gsi->virt); } diff --git a/drivers/net/ipa/gsi.h b/drivers/net/ipa/gsi.h index 061312773df0..3f9f29d531c4 100644 --- a/drivers/net/ipa/gsi.h +++ b/drivers/net/ipa/gsi.h @@ -150,7 +150,6 @@ struct gsi { struct net_device dummy_dev; /* needed for NAPI */ void __iomem *virt; u32 irq; - bool irq_wake_enabled; u32 channel_count; u32 evt_ring_count; struct gsi_channel channel[GSI_CHANNEL_COUNT_MAX]; diff --git a/drivers/net/ipa/gsi_reg.h b/drivers/net/ipa/gsi_reg.h index acc9e744c67d..8e0e9350c383 100644 --- a/drivers/net/ipa/gsi_reg.h +++ b/drivers/net/ipa/gsi_reg.h @@ -258,6 +258,11 @@ GSI_EE_N_CNTXT_TYPE_IRQ_OFFSET(GSI_EE_AP) #define GSI_EE_N_CNTXT_TYPE_IRQ_OFFSET(ee) \ (0x0001f080 + 0x4000 * (ee)) +#define GSI_CNTXT_TYPE_IRQ_MSK_OFFSET \ + GSI_EE_N_CNTXT_TYPE_IRQ_MSK_OFFSET(GSI_EE_AP) +#define GSI_EE_N_CNTXT_TYPE_IRQ_MSK_OFFSET(ee) \ + (0x0001f088 + 0x4000 * (ee)) +/* The masks below are used for the TYPE_IRQ and TYPE_IRQ_MASK registers */ #define CH_CTRL_FMASK GENMASK(0, 0) #define EV_CTRL_FMASK GENMASK(1, 1) #define GLOB_EE_FMASK GENMASK(2, 2) @@ -265,18 +270,6 @@ #define INTER_EE_CH_CTRL_FMASK GENMASK(4, 4) #define INTER_EE_EV_CTRL_FMASK GENMASK(5, 5) #define GENERAL_FMASK GENMASK(6, 6) - -#define GSI_CNTXT_TYPE_IRQ_MSK_OFFSET \ - GSI_EE_N_CNTXT_TYPE_IRQ_MSK_OFFSET(GSI_EE_AP) -#define GSI_EE_N_CNTXT_TYPE_IRQ_MSK_OFFSET(ee) \ - (0x0001f088 + 0x4000 * (ee)) -#define MSK_CH_CTRL_FMASK GENMASK(0, 0) -#define MSK_EV_CTRL_FMASK GENMASK(1, 1) -#define MSK_GLOB_EE_FMASK GENMASK(2, 2) -#define MSK_IEOB_FMASK GENMASK(3, 3) -#define MSK_INTER_EE_CH_CTRL_FMASK GENMASK(4, 4) -#define MSK_INTER_EE_EV_CTRL_FMASK GENMASK(5, 5) -#define MSK_GENERAL_FMASK GENMASK(6, 6) #define GSI_CNTXT_TYPE_IRQ_MSK_ALL GENMASK(6, 0) #define GSI_CNTXT_SRC_CH_IRQ_OFFSET \ @@ -328,57 +321,39 @@ GSI_EE_N_CNTXT_GLOB_IRQ_STTS_OFFSET(GSI_EE_AP) #define GSI_EE_N_CNTXT_GLOB_IRQ_STTS_OFFSET(ee) \ (0x0001f100 + 0x4000 * (ee)) -#define ERROR_INT_FMASK GENMASK(0, 0) -#define GP_INT1_FMASK GENMASK(1, 1) -#define GP_INT2_FMASK GENMASK(2, 2) -#define GP_INT3_FMASK GENMASK(3, 3) - #define GSI_CNTXT_GLOB_IRQ_EN_OFFSET \ GSI_EE_N_CNTXT_GLOB_IRQ_EN_OFFSET(GSI_EE_AP) #define GSI_EE_N_CNTXT_GLOB_IRQ_EN_OFFSET(ee) \ (0x0001f108 + 0x4000 * (ee)) -#define EN_ERROR_INT_FMASK GENMASK(0, 0) -#define EN_GP_INT1_FMASK GENMASK(1, 1) -#define EN_GP_INT2_FMASK GENMASK(2, 2) -#define EN_GP_INT3_FMASK GENMASK(3, 3) -#define GSI_CNTXT_GLOB_IRQ_ALL GENMASK(3, 0) - #define GSI_CNTXT_GLOB_IRQ_CLR_OFFSET \ GSI_EE_N_CNTXT_GLOB_IRQ_CLR_OFFSET(GSI_EE_AP) #define GSI_EE_N_CNTXT_GLOB_IRQ_CLR_OFFSET(ee) \ (0x0001f110 + 0x4000 * (ee)) -#define CLR_ERROR_INT_FMASK GENMASK(0, 0) -#define CLR_GP_INT1_FMASK GENMASK(1, 1) -#define CLR_GP_INT2_FMASK GENMASK(2, 2) -#define CLR_GP_INT3_FMASK GENMASK(3, 3) +/* The masks below are used for the general IRQ STTS, EN, and CLR registers */ +#define ERROR_INT_FMASK GENMASK(0, 0) +#define GP_INT1_FMASK GENMASK(1, 1) +#define GP_INT2_FMASK GENMASK(2, 2) +#define GP_INT3_FMASK GENMASK(3, 3) +#define GSI_CNTXT_GLOB_IRQ_ALL GENMASK(3, 0) #define GSI_CNTXT_GSI_IRQ_STTS_OFFSET \ GSI_EE_N_CNTXT_GSI_IRQ_STTS_OFFSET(GSI_EE_AP) #define GSI_EE_N_CNTXT_GSI_IRQ_STTS_OFFSET(ee) \ (0x0001f118 + 0x4000 * (ee)) -#define BREAK_POINT_FMASK GENMASK(0, 0) -#define BUS_ERROR_FMASK GENMASK(1, 1) -#define CMD_FIFO_OVRFLOW_FMASK GENMASK(2, 2) -#define MCS_STACK_OVRFLOW_FMASK GENMASK(3, 3) - #define GSI_CNTXT_GSI_IRQ_EN_OFFSET \ GSI_EE_N_CNTXT_GSI_IRQ_EN_OFFSET(GSI_EE_AP) #define GSI_EE_N_CNTXT_GSI_IRQ_EN_OFFSET(ee) \ (0x0001f120 + 0x4000 * (ee)) -#define EN_BREAK_POINT_FMASK GENMASK(0, 0) -#define EN_BUS_ERROR_FMASK GENMASK(1, 1) -#define EN_CMD_FIFO_OVRFLOW_FMASK GENMASK(2, 2) -#define EN_MCS_STACK_OVRFLOW_FMASK GENMASK(3, 3) -#define GSI_CNTXT_GSI_IRQ_ALL GENMASK(3, 0) - #define GSI_CNTXT_GSI_IRQ_CLR_OFFSET \ GSI_EE_N_CNTXT_GSI_IRQ_CLR_OFFSET(GSI_EE_AP) #define GSI_EE_N_CNTXT_GSI_IRQ_CLR_OFFSET(ee) \ (0x0001f128 + 0x4000 * (ee)) -#define CLR_BREAK_POINT_FMASK GENMASK(0, 0) -#define CLR_BUS_ERROR_FMASK GENMASK(1, 1) -#define CLR_CMD_FIFO_OVRFLOW_FMASK GENMASK(2, 2) -#define CLR_MCS_STACK_OVRFLOW_FMASK GENMASK(3, 3) +/* The masks below are used for the general IRQ STTS, EN, and CLR registers */ +#define BREAK_POINT_FMASK GENMASK(0, 0) +#define BUS_ERROR_FMASK GENMASK(1, 1) +#define CMD_FIFO_OVRFLOW_FMASK GENMASK(2, 2) +#define MCS_STACK_OVRFLOW_FMASK GENMASK(3, 3) +#define GSI_CNTXT_GSI_IRQ_ALL GENMASK(3, 0) #define GSI_CNTXT_INTSET_OFFSET \ GSI_EE_N_CNTXT_INTSET_OFFSET(GSI_EE_AP) diff --git a/drivers/net/ipa/gsi_trans.c b/drivers/net/ipa/gsi_trans.c index bdbfeed359db..43f5f5d93cb0 100644 --- a/drivers/net/ipa/gsi_trans.c +++ b/drivers/net/ipa/gsi_trans.c @@ -81,7 +81,6 @@ struct gsi_tre { /* gsi_tre->flags mask values (in CPU byte order) */ #define TRE_FLAGS_CHAIN_FMASK GENMASK(0, 0) -#define TRE_FLAGS_IEOB_FMASK GENMASK(8, 8) #define TRE_FLAGS_IEOT_FMASK GENMASK(9, 9) #define TRE_FLAGS_BEI_FMASK GENMASK(10, 10) #define TRE_FLAGS_TYPE_FMASK GENMASK(23, 16) diff --git a/drivers/net/ipa/ipa.h b/drivers/net/ipa/ipa.h index 55115cfb2972..6c2371084c55 100644 --- a/drivers/net/ipa/ipa.h +++ b/drivers/net/ipa/ipa.h @@ -10,7 +10,6 @@ #include <linux/device.h> #include <linux/notifier.h> #include <linux/pm_wakeup.h> -#include <linux/notifier.h> #include "ipa_version.h" #include "gsi.h" @@ -29,14 +28,24 @@ struct ipa_smp2p; struct ipa_interrupt; /** + * enum ipa_flag - IPA state flags + * @IPA_FLAG_RESUMED: Whether resume from suspend has been signaled + * @IPA_FLAG_COUNT: Number of defined IPA flags + */ +enum ipa_flag { + IPA_FLAG_RESUMED, + IPA_FLAG_COUNT, /* Last; not a flag */ +}; + +/** * struct ipa - IPA information * @gsi: Embedded GSI structure + * @flags: Boolean state flags * @version: IPA hardware version * @pdev: Platform device * @modem_rproc: Remoteproc handle for modem subsystem * @smp2p: SMP2P information * @clock: IPA clocking information - * @suspend_ref: Whether clock reference preventing suspend taken * @table_addr: DMA address of filter/route table content * @table_virt: Virtual address of filter/route table content * @interrupt: IPA Interrupt information @@ -71,6 +80,7 @@ struct ipa_interrupt; */ struct ipa { struct gsi gsi; + DECLARE_BITMAP(flags, IPA_FLAG_COUNT); enum ipa_version version; struct platform_device *pdev; struct rproc *modem_rproc; @@ -78,7 +88,6 @@ struct ipa { void *notifier; struct ipa_smp2p *smp2p; struct ipa_clock *clock; - atomic_t suspend_ref; dma_addr_t table_addr; __le64 *table_virt; @@ -105,8 +114,6 @@ struct ipa { void *zero_virt; size_t zero_size; - struct wakeup_source *wakeup_source; - /* Bit masks indicating endpoint state */ u32 available; /* supported by hardware */ u32 filter_map; diff --git a/drivers/net/ipa/ipa_clock.c b/drivers/net/ipa/ipa_clock.c index 398f2e47043d..a2c0fde05819 100644 --- a/drivers/net/ipa/ipa_clock.c +++ b/drivers/net/ipa/ipa_clock.c @@ -4,7 +4,7 @@ * Copyright (C) 2018-2020 Linaro Ltd. */ -#include <linux/atomic.h> +#include <linux/refcount.h> #include <linux/mutex.h> #include <linux/clk.h> #include <linux/device.h> @@ -51,7 +51,7 @@ * @config_path: Configuration space interconnect */ struct ipa_clock { - atomic_t count; + refcount_t count; struct mutex mutex; /* protects clock enable/disable */ struct clk *core; struct icc_path *memory_path; @@ -195,14 +195,13 @@ static void ipa_clock_disable(struct ipa *ipa) */ bool ipa_clock_get_additional(struct ipa *ipa) { - return !!atomic_inc_not_zero(&ipa->clock->count); + return refcount_inc_not_zero(&ipa->clock->count); } /* Get an IPA clock reference. If the reference count is non-zero, it is * incremented and return is immediate. Otherwise it is checked again - * under protection of the mutex, and if appropriate the clock (and - * interconnects) are enabled suspended endpoints (if any) are resumed - * before returning. + * under protection of the mutex, and if appropriate the IPA clock + * is enabled. * * Incrementing the reference count is intentionally deferred until * after the clock is running and endpoints are resumed. @@ -229,28 +228,23 @@ void ipa_clock_get(struct ipa *ipa) goto out_mutex_unlock; } - ipa_endpoint_resume(ipa); - - atomic_inc(&clock->count); + refcount_set(&clock->count, 1); out_mutex_unlock: mutex_unlock(&clock->mutex); } -/* Attempt to remove an IPA clock reference. If this represents the last - * reference, suspend endpoints and disable the clock (and interconnects) - * under protection of a mutex. +/* Attempt to remove an IPA clock reference. If this represents the + * last reference, disable the IPA clock under protection of the mutex. */ void ipa_clock_put(struct ipa *ipa) { struct ipa_clock *clock = ipa->clock; /* If this is not the last reference there's nothing more to do */ - if (!atomic_dec_and_mutex_lock(&clock->count, &clock->mutex)) + if (!refcount_dec_and_mutex_lock(&clock->count, &clock->mutex)) return; - ipa_endpoint_suspend(ipa); - ipa_clock_disable(ipa); mutex_unlock(&clock->mutex); @@ -294,7 +288,7 @@ struct ipa_clock *ipa_clock_init(struct device *dev) goto err_kfree; mutex_init(&clock->mutex); - atomic_set(&clock->count, 0); + refcount_set(&clock->count, 0); return clock; @@ -311,7 +305,7 @@ void ipa_clock_exit(struct ipa_clock *clock) { struct clk *clk = clock->core; - WARN_ON(atomic_read(&clock->count) != 0); + WARN_ON(refcount_read(&clock->count) != 0); mutex_destroy(&clock->mutex); ipa_interconnect_exit(clock); kfree(clock); diff --git a/drivers/net/ipa/ipa_endpoint.c b/drivers/net/ipa/ipa_endpoint.c index b7efd7c95e9c..b40b711cf4bd 100644 --- a/drivers/net/ipa/ipa_endpoint.c +++ b/drivers/net/ipa/ipa_endpoint.c @@ -42,11 +42,8 @@ /** enum ipa_status_opcode - status element opcode hardware values */ enum ipa_status_opcode { IPA_STATUS_OPCODE_PACKET = 0x01, - IPA_STATUS_OPCODE_NEW_FRAG_RULE = 0x02, IPA_STATUS_OPCODE_DROPPED_PACKET = 0x04, IPA_STATUS_OPCODE_SUSPENDED_PACKET = 0x08, - IPA_STATUS_OPCODE_LOG = 0x10, - IPA_STATUS_OPCODE_DCMP = 0x20, IPA_STATUS_OPCODE_PACKET_2ND_PASS = 0x40, }; @@ -54,13 +51,6 @@ enum ipa_status_opcode { enum ipa_status_exception { /* 0 means no exception */ IPA_STATUS_EXCEPTION_DEAGGR = 0x01, - IPA_STATUS_EXCEPTION_IPTYPE = 0x04, - IPA_STATUS_EXCEPTION_PACKET_LENGTH = 0x08, - IPA_STATUS_EXCEPTION_FRAG_RULE_MISS = 0x10, - IPA_STATUS_EXCEPTION_SW_FILT = 0x20, - /* The meaning of the next value depends on whether the IP version */ - IPA_STATUS_EXCEPTION_NAT = 0x40, /* IPv4 */ - IPA_STATUS_EXCEPTION_IPV6CT = IPA_STATUS_EXCEPTION_NAT, }; /* Status element provided by hardware */ @@ -79,36 +69,9 @@ struct ipa_status { }; /* Field masks for struct ipa_status structure fields */ - -#define IPA_STATUS_SRC_IDX_FMASK GENMASK(4, 0) - #define IPA_STATUS_DST_IDX_FMASK GENMASK(4, 0) - -#define IPA_STATUS_FLAGS1_FLT_LOCAL_FMASK GENMASK(0, 0) -#define IPA_STATUS_FLAGS1_FLT_HASH_FMASK GENMASK(1, 1) -#define IPA_STATUS_FLAGS1_FLT_GLOBAL_FMASK GENMASK(2, 2) -#define IPA_STATUS_FLAGS1_FLT_RET_HDR_FMASK GENMASK(3, 3) -#define IPA_STATUS_FLAGS1_FLT_RULE_ID_FMASK GENMASK(13, 4) -#define IPA_STATUS_FLAGS1_RT_LOCAL_FMASK GENMASK(14, 14) -#define IPA_STATUS_FLAGS1_RT_HASH_FMASK GENMASK(15, 15) -#define IPA_STATUS_FLAGS1_UCP_FMASK GENMASK(16, 16) -#define IPA_STATUS_FLAGS1_RT_TBL_IDX_FMASK GENMASK(21, 17) #define IPA_STATUS_FLAGS1_RT_RULE_ID_FMASK GENMASK(31, 22) -#define IPA_STATUS_FLAGS2_NAT_HIT_FMASK GENMASK_ULL(0, 0) -#define IPA_STATUS_FLAGS2_NAT_ENTRY_IDX_FMASK GENMASK_ULL(13, 1) -#define IPA_STATUS_FLAGS2_NAT_TYPE_FMASK GENMASK_ULL(15, 14) -#define IPA_STATUS_FLAGS2_TAG_INFO_FMASK GENMASK_ULL(63, 16) - -#define IPA_STATUS_FLAGS3_SEQ_NUM_FMASK GENMASK(7, 0) -#define IPA_STATUS_FLAGS3_TOD_CTR_FMASK GENMASK(31, 8) - -#define IPA_STATUS_FLAGS4_HDR_LOCAL_FMASK GENMASK(0, 0) -#define IPA_STATUS_FLAGS4_HDR_OFFSET_FMASK GENMASK(10, 1) -#define IPA_STATUS_FLAGS4_FRAG_HIT_FMASK GENMASK(11, 11) -#define IPA_STATUS_FLAGS4_FRAG_RULE_FMASK GENMASK(15, 12) -#define IPA_STATUS_FLAGS4_HW_SPECIFIC_FMASK GENMASK(31, 16) - #ifdef IPA_VALIDATE static void ipa_endpoint_validate_build(void) @@ -1048,8 +1011,7 @@ static bool ipa_endpoint_skb_build(struct ipa_endpoint *endpoint, } /* The format of a packet status element is the same for several status - * types (opcodes). The NEW_FRAG_RULE, LOG, DCMP (decompression) types - * aren't currently supported + * types (opcodes). Other types aren't currently supported. */ static bool ipa_status_format_packet(enum ipa_status_opcode opcode) { @@ -1086,7 +1048,7 @@ static bool ipa_status_drop_packet(const struct ipa_status *status) { u32 val; - /* Deaggregation exceptions we drop; others we consume */ + /* Deaggregation exceptions we drop; all other types we consume */ if (status->exception) return status->exception == IPA_STATUS_EXCEPTION_DEAGGR; @@ -1432,11 +1394,10 @@ void ipa_endpoint_suspend_one(struct ipa_endpoint *endpoint) if (!(endpoint->ipa->enabled & BIT(endpoint->endpoint_id))) return; - if (!endpoint->toward_ipa) + if (!endpoint->toward_ipa) { ipa_endpoint_replenish_disable(endpoint); - - if (!endpoint->toward_ipa) (void)ipa_endpoint_program_suspend(endpoint, true); + } /* IPA v3.5.1 doesn't use channel stop for suspend */ stop_channel = endpoint->ipa->version != IPA_VERSION_3_5_1; @@ -1471,6 +1432,9 @@ void ipa_endpoint_resume_one(struct ipa_endpoint *endpoint) void ipa_endpoint_suspend(struct ipa *ipa) { + if (!ipa->setup_complete) + return; + if (ipa->modem_netdev) ipa_modem_suspend(ipa->modem_netdev); @@ -1482,6 +1446,9 @@ void ipa_endpoint_suspend(struct ipa *ipa) void ipa_endpoint_resume(struct ipa *ipa) { + if (!ipa->setup_complete) + return; + ipa_endpoint_resume_one(ipa->name_map[IPA_ENDPOINT_AP_COMMAND_TX]); ipa_endpoint_resume_one(ipa->name_map[IPA_ENDPOINT_AP_LAN_RX]); diff --git a/drivers/net/ipa/ipa_interrupt.c b/drivers/net/ipa/ipa_interrupt.c index 90353987c45f..cc1ea28f7bc2 100644 --- a/drivers/net/ipa/ipa_interrupt.c +++ b/drivers/net/ipa/ipa_interrupt.c @@ -237,8 +237,16 @@ struct ipa_interrupt *ipa_interrupt_setup(struct ipa *ipa) goto err_kfree; } + ret = enable_irq_wake(irq); + if (ret) { + dev_err(dev, "error %d enabling wakeup for \"ipa\" IRQ\n", ret); + goto err_free_irq; + } + return interrupt; +err_free_irq: + free_irq(interrupt->irq, interrupt); err_kfree: kfree(interrupt); @@ -248,6 +256,12 @@ err_kfree: /* Tear down the IPA interrupt framework */ void ipa_interrupt_teardown(struct ipa_interrupt *interrupt) { + struct device *dev = &interrupt->ipa->pdev->dev; + int ret; + + ret = disable_irq_wake(interrupt->irq); + if (ret) + dev_err(dev, "error %d disabling \"ipa\" IRQ wakeup\n", ret); free_irq(interrupt->irq, interrupt); kfree(interrupt); } diff --git a/drivers/net/ipa/ipa_main.c b/drivers/net/ipa/ipa_main.c index 1fdfec41e442..cd4d993b0bbb 100644 --- a/drivers/net/ipa/ipa_main.c +++ b/drivers/net/ipa/ipa_main.c @@ -75,17 +75,19 @@ * @ipa: IPA pointer * @irq_id: IPA interrupt type (unused) * - * When in suspended state, the IPA can trigger a resume by sending a SUSPEND - * IPA interrupt. + * If an RX endpoint is in suspend state, and the IPA has a packet + * destined for that endpoint, the IPA generates a SUSPEND interrupt + * to inform the AP that it should resume the endpoint. If we get + * one of these interrupts we just resume everything. */ static void ipa_suspend_handler(struct ipa *ipa, enum ipa_irq_id irq_id) { - /* Take a a single clock reference to prevent suspend. All - * endpoints will be resumed as a result. This reference will - * be dropped when we get a power management suspend request. + /* Just report the event, and let system resume handle the rest. + * More than one endpoint could signal this; if so, ignore + * all but the first. */ - if (!atomic_xchg(&ipa->suspend_ref, 1)) - ipa_clock_get(ipa); + if (!test_and_set_bit(IPA_FLAG_RESUMED, ipa->flags)) + pm_wakeup_dev_event(&ipa->pdev->dev, 0, true); /* Acknowledge/clear the suspend interrupt on all endpoints */ ipa_interrupt_suspend_clear_all(ipa->interrupt); @@ -106,6 +108,7 @@ int ipa_setup(struct ipa *ipa) { struct ipa_endpoint *exception_endpoint; struct ipa_endpoint *command_endpoint; + struct device *dev = &ipa->pdev->dev; int ret; /* Setup for IPA v3.5.1 has some slight differences */ @@ -123,6 +126,10 @@ int ipa_setup(struct ipa *ipa) ipa_uc_setup(ipa); + ret = device_init_wakeup(dev, true); + if (ret) + goto err_uc_teardown; + ipa_endpoint_setup(ipa); /* We need to use the AP command TX endpoint to perform other @@ -158,7 +165,7 @@ int ipa_setup(struct ipa *ipa) ipa->setup_complete = true; - dev_info(&ipa->pdev->dev, "IPA driver setup completed successfully\n"); + dev_info(dev, "IPA driver setup completed successfully\n"); return 0; @@ -173,6 +180,8 @@ err_command_disable: ipa_endpoint_disable_one(command_endpoint); err_endpoint_teardown: ipa_endpoint_teardown(ipa); + (void)device_init_wakeup(dev, false); +err_uc_teardown: ipa_uc_teardown(ipa); ipa_interrupt_remove(ipa->interrupt, IPA_IRQ_TX_SUSPEND); ipa_interrupt_teardown(ipa->interrupt); @@ -200,6 +209,7 @@ static void ipa_teardown(struct ipa *ipa) command_endpoint = ipa->name_map[IPA_ENDPOINT_AP_COMMAND_TX]; ipa_endpoint_disable_one(command_endpoint); ipa_endpoint_teardown(ipa); + (void)device_init_wakeup(&ipa->pdev->dev, false); ipa_uc_teardown(ipa); ipa_interrupt_remove(ipa->interrupt, IPA_IRQ_TX_SUSPEND); ipa_interrupt_teardown(ipa->interrupt); @@ -508,7 +518,6 @@ static int ipa_config(struct ipa *ipa, const struct ipa_data *data) * is held after initialization completes, and won't get dropped * unless/until a system suspend request arrives. */ - atomic_set(&ipa->suspend_ref, 1); ipa_clock_get(ipa); ipa_hardware_config(ipa); @@ -544,7 +553,6 @@ err_endpoint_deconfig: err_hardware_deconfig: ipa_hardware_deconfig(ipa); ipa_clock_put(ipa); - atomic_set(&ipa->suspend_ref, 0); return ret; } @@ -562,7 +570,6 @@ static void ipa_deconfig(struct ipa *ipa) ipa_endpoint_deconfig(ipa); ipa_hardware_deconfig(ipa); ipa_clock_put(ipa); - atomic_set(&ipa->suspend_ref, 0); } static int ipa_firmware_load(struct device *dev) @@ -709,7 +716,6 @@ static void ipa_validate_build(void) */ static int ipa_probe(struct platform_device *pdev) { - struct wakeup_source *wakeup_source; struct device *dev = &pdev->dev; const struct ipa_data *data; struct ipa_clock *clock; @@ -717,8 +723,8 @@ static int ipa_probe(struct platform_device *pdev) bool modem_alloc; bool modem_init; struct ipa *ipa; - phandle phandle; bool prefetch; + phandle ph; int ret; ipa_validate_build(); @@ -730,13 +736,13 @@ static int ipa_probe(struct platform_device *pdev) return -EPROBE_DEFER; /* We rely on remoteproc to tell us about modem state changes */ - phandle = of_property_read_phandle(dev->of_node, "modem-remoteproc"); - if (!phandle) { + ph = of_property_read_phandle(dev->of_node, "modem-remoteproc"); + if (!ph) { dev_err(dev, "DT missing \"modem-remoteproc\" property\n"); return -EINVAL; } - rproc = rproc_get_by_phandle(phandle); + rproc = rproc_get_by_phandle(ph); if (!rproc) return -EPROBE_DEFER; @@ -758,27 +764,17 @@ static int ipa_probe(struct platform_device *pdev) goto err_clock_exit; } - /* Create a wakeup source. */ - wakeup_source = wakeup_source_register(dev, "ipa"); - if (!wakeup_source) { - /* The most likely reason for failure is memory exhaustion */ - ret = -ENOMEM; - goto err_clock_exit; - } - /* Allocate and initialize the IPA structure */ ipa = kzalloc(sizeof(*ipa), GFP_KERNEL); if (!ipa) { ret = -ENOMEM; - goto err_wakeup_source_unregister; + goto err_clock_exit; } ipa->pdev = pdev; dev_set_drvdata(dev, ipa); ipa->modem_rproc = rproc; ipa->clock = clock; - atomic_set(&ipa->suspend_ref, 0); - ipa->wakeup_source = wakeup_source; ipa->version = data->version; ret = ipa_reg_init(ipa); @@ -857,8 +853,6 @@ err_reg_exit: ipa_reg_exit(ipa); err_kfree_ipa: kfree(ipa); -err_wakeup_source_unregister: - wakeup_source_unregister(wakeup_source); err_clock_exit: ipa_clock_exit(clock); err_rproc_put: @@ -872,11 +866,8 @@ static int ipa_remove(struct platform_device *pdev) struct ipa *ipa = dev_get_drvdata(&pdev->dev); struct rproc *rproc = ipa->modem_rproc; struct ipa_clock *clock = ipa->clock; - struct wakeup_source *wakeup_source; int ret; - wakeup_source = ipa->wakeup_source; - if (ipa->setup_complete) { ret = ipa_modem_stop(ipa); if (ret) @@ -893,7 +884,6 @@ static int ipa_remove(struct platform_device *pdev) ipa_mem_exit(ipa); ipa_reg_exit(ipa); kfree(ipa); - wakeup_source_unregister(wakeup_source); ipa_clock_exit(clock); rproc_put(rproc); @@ -907,13 +897,22 @@ static int ipa_remove(struct platform_device *pdev) * Return: Always returns zero * * Called by the PM framework when a system suspend operation is invoked. + * Suspends endpoints and releases the clock reference held to keep + * the IPA clock running until this point. */ static int ipa_suspend(struct device *dev) { struct ipa *ipa = dev_get_drvdata(dev); + /* When a suspended RX endpoint has a packet ready to receive, we + * get an IPA SUSPEND interrupt. We trigger a system resume in + * that case, but only on the first such interrupt since suspend. + */ + __clear_bit(IPA_FLAG_RESUMED, ipa->flags); + + ipa_endpoint_suspend(ipa); + ipa_clock_put(ipa); - atomic_set(&ipa->suspend_ref, 0); return 0; } @@ -925,6 +924,8 @@ static int ipa_suspend(struct device *dev) * Return: Always returns 0 * * Called by the PM framework when a system resume operation is invoked. + * Takes an IPA clock reference to keep the clock running until suspend, + * and resumes endpoints. */ static int ipa_resume(struct device *dev) { @@ -933,9 +934,10 @@ static int ipa_resume(struct device *dev) /* This clock reference will keep the IPA out of suspend * until we get a power management suspend request. */ - atomic_set(&ipa->suspend_ref, 1); ipa_clock_get(ipa); + ipa_endpoint_resume(ipa); + return 0; } diff --git a/drivers/net/ipa/ipa_reg.h b/drivers/net/ipa/ipa_reg.h index eb4e39fa7d4b..e542598fd775 100644 --- a/drivers/net/ipa/ipa_reg.h +++ b/drivers/net/ipa/ipa_reg.h @@ -426,7 +426,7 @@ enum ipa_cs_offload_en { IPA_CS_RSVD }; -/** enum ipa_aggr_en - aggregation type field in ENDP_INIT_AGGR_N */ +/** enum ipa_aggr_en - aggregation enable field in ENDP_INIT_AGGR_N */ enum ipa_aggr_en { IPA_BYPASS_AGGR = 0, IPA_ENABLE_AGGR = 1, diff --git a/drivers/net/ipa/ipa_uc.c b/drivers/net/ipa/ipa_uc.c index 1a0b04e0ab74..b382d47bc70d 100644 --- a/drivers/net/ipa/ipa_uc.c +++ b/drivers/net/ipa/ipa_uc.c @@ -144,7 +144,7 @@ static void ipa_uc_response_hdlr(struct ipa *ipa, enum ipa_irq_id irq_id) * should only receive responses from the microcontroller when it has * sent it a request message. * - * We can drop the clock reference taken in ipa_uc_init() once we + * We can drop the clock reference taken in ipa_uc_setup() once we * know the microcontroller has finished its initialization. */ switch (shared->response) { |