diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2026-08-24 08:46:03 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2026-08-24 08:46:03 -0700 |
| commit | cf9610f9116d55c5a66ef9f1faecacabd93a9322 (patch) | |
| tree | 757a3d280760c654767631cab5ad8af2d86d1848 /drivers/gpu/host1x/fence.c | |
| download | linux-stable-cf9610f9116d55c5a66ef9f1faecacabd93a9322.tar.gz linux-stable-cf9610f9116d55c5a66ef9f1faecacabd93a9322.zip | |
Merge tag 'pinctrl-v7.3-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrlgrafted
Pull pin control updates from Linus Walleij:
"Core changes:
- Use the non-blocking mux_state_try_select() in the generic MUX pin
control back-end
- Free pin maps on pinctrl_generic_to_map() failure in the core
helpers
New hardware pin control:
- Qualcomm Maili TLMM SoC, PMG1110 PMIC, and Eliza LPASS LPI TLMM SoC
(this is for the low power audio, LPASS = Low Power Audio SubSystem
portions)
- Upboard support on top of the Intel pin controller
- Apple T6030 and T6031 support (just compatible strings)
- Samsung Exynos 8855 SoC
- Mediatek MT6858 SoC
- Rockchip RK3308B and RV1106 SoCs
- Airoha EN7523 and AN7563 SoCs
Improvements:
- Qualcomm TLMM GPIOs are unconditionally marked as wakeup capable
- Qualcomm improvements on top of the Qualcomm PDC (power domain
controller) irqchip improvements from tglx:s tree
- Qualcomm IPQ806x and IPQ9650 non-urgent pin grop fixups
- The NPCM8xx driver has been put into shape fixing many pin and
group definitions
- Some non-urgent Tegra 264 pin assignments are fixed up
- Some non-urgent fixups to Airoha AN7581 and AN7583 registers and
pin assignments, missing features etc"
* tag 'pinctrl-v7.3-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl: (130 commits)
dt-bindings: pinctrl: Convert TI DA850 pupd to DT schema
pinctrl: meson: sync some modify from A4
pinctrl: meson: a4: Add input enable pin configuration
pinctrl: realtek: rtd1625: remove unused group name spdif_sel
pinctrl: realtek: rtd1625: fix base_bit for VE4 GPIO 13
dt-bindings: pinctrl: microchip,pic32mzda-pinctrl: Convert to DT schema
Revert "Merge branch 'ib-rsk7204' into devel"
pinctrl: rockchip: Add RV1106 pinctrl support
dt-bindings: pinctrl: rockchip: Add RV1106 compatible
pinctrl: rockchip: Decode drive strength in the get function
pinctrl: fix PINCTRL_GENERIC_MUX not always being selectable
pinctrl: airoha: add support of an7563 SoC
dt-bindings: pinctrl: airoha: add support of an7563 pin controller
pinctrl: airoha: try to find chip scu node by phandle first
pinctrl: airoha: add support of en7523 SoC
dt-bindings: pinctrl: airoha: add support of en7523 pin controller
pinctrl: airoha: an7583: add support for olt pinmux
pinctrl: airoha: an7583: add support for pon_alt pinmux
pinctrl: airoha: an7583: add support for npu_uart pinmux
dt-bindings: pinctrl: airoha: an7583: add missed features
...
Diffstat (limited to 'drivers/gpu/host1x/fence.c')
| -rw-r--r-- | drivers/gpu/host1x/fence.c | 154 |
1 files changed, 154 insertions, 0 deletions
diff --git a/drivers/gpu/host1x/fence.c b/drivers/gpu/host1x/fence.c new file mode 100644 index 000000000..b9a7d0bf9 --- /dev/null +++ b/drivers/gpu/host1x/fence.c @@ -0,0 +1,154 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Syncpoint dma_fence implementation + * + * Copyright (c) 2020, NVIDIA Corporation. + */ + +#include <linux/dma-fence.h> +#include <linux/file.h> +#include <linux/fs.h> +#include <linux/slab.h> +#include <linux/sync_file.h> + +#include "fence.h" +#include "intr.h" +#include "syncpt.h" + +static const char *host1x_syncpt_fence_get_driver_name(struct dma_fence *f) +{ + return "host1x"; +} + +static const char *host1x_syncpt_fence_get_timeline_name(struct dma_fence *f) +{ + return "syncpoint"; +} + +static struct host1x_syncpt_fence *to_host1x_fence(struct dma_fence *f) +{ + return container_of(f, struct host1x_syncpt_fence, base); +} + +static bool host1x_syncpt_fence_enable_signaling(struct dma_fence *f) +{ + struct host1x_syncpt_fence *sf = to_host1x_fence(f); + + if (host1x_syncpt_is_expired(sf->sp, sf->threshold)) + return false; + + /* Reference for interrupt path. */ + dma_fence_get(f); + + /* + * The dma_fence framework requires the fence driver to keep a + * reference to any fences for which 'enable_signaling' has been + * called (and that have not been signalled). + * + * We cannot currently always guarantee that all fences get signalled + * or cancelled. As such, for such situations, set up a timeout, so + * that long-lasting fences will get reaped eventually. + */ + if (sf->timeout) { + /* Reference for timeout path. */ + dma_fence_get(f); + schedule_delayed_work(&sf->timeout_work, msecs_to_jiffies(30000)); + } + + host1x_intr_add_fence_locked(sf->sp->host, sf); + + /* + * The fence may get signalled at any time after the above call, + * so we need to initialize all state used by signalling + * before it. + */ + + return true; +} + +static const struct dma_fence_ops host1x_syncpt_fence_ops = { + .get_driver_name = host1x_syncpt_fence_get_driver_name, + .get_timeline_name = host1x_syncpt_fence_get_timeline_name, + .enable_signaling = host1x_syncpt_fence_enable_signaling, +}; + +void host1x_fence_signal(struct host1x_syncpt_fence *f) +{ + if (atomic_xchg(&f->signaling, 1)) { + /* + * Already on timeout path, but we removed the fence before + * timeout path could, so drop interrupt path reference. + */ + dma_fence_put(&f->base); + return; + } + + if (f->timeout && cancel_delayed_work(&f->timeout_work)) { + /* + * We know that the timeout path will not be entered. + * Safe to drop the timeout path's reference now. + */ + dma_fence_put(&f->base); + } + + dma_fence_signal_locked(&f->base); + dma_fence_put(&f->base); +} + +static void do_fence_timeout(struct work_struct *work) +{ + struct delayed_work *dwork = (struct delayed_work *)work; + struct host1x_syncpt_fence *f = + container_of(dwork, struct host1x_syncpt_fence, timeout_work); + + if (atomic_xchg(&f->signaling, 1)) { + /* Already on interrupt path, drop timeout path reference if any. */ + if (f->timeout) + dma_fence_put(&f->base); + return; + } + + if (host1x_intr_remove_fence(f->sp->host, f)) { + /* + * Managed to remove fence from queue, so it's safe to drop + * the interrupt path's reference. + */ + dma_fence_put(&f->base); + } + + dma_fence_set_error(&f->base, -ETIMEDOUT); + dma_fence_signal(&f->base); + if (f->timeout) + dma_fence_put(&f->base); +} + +struct dma_fence *host1x_fence_create(struct host1x_syncpt *sp, u32 threshold, + bool timeout) +{ + struct host1x_syncpt_fence *fence; + + fence = kzalloc_obj(*fence); + if (!fence) + return ERR_PTR(-ENOMEM); + + fence->sp = sp; + fence->threshold = threshold; + fence->timeout = timeout; + + dma_fence_init(&fence->base, &host1x_syncpt_fence_ops, &sp->fences.lock, + dma_fence_context_alloc(1), 0); + + INIT_DELAYED_WORK(&fence->timeout_work, do_fence_timeout); + + return &fence->base; +} +EXPORT_SYMBOL(host1x_fence_create); + +void host1x_fence_cancel(struct dma_fence *f) +{ + struct host1x_syncpt_fence *sf = to_host1x_fence(f); + + schedule_delayed_work(&sf->timeout_work, 0); + flush_delayed_work(&sf->timeout_work); +} +EXPORT_SYMBOL(host1x_fence_cancel); |
