diff options
| author | Tejun Heo <tj@kernel.org> | 2026-09-14 22:12:34 -1000 |
|---|---|---|
| committer | Tejun Heo <tj@kernel.org> | 2026-09-15 06:57:20 -1000 |
| commit | a9e3760b0838299649c0d57cca44daaf40ba3c33 (patch) | |
| tree | 95807ff0e511c05602ef34808cfc660303309057 /drivers/clocksource/timer-ralink.c | |
| download | linux-stable-a9e3760b0838299649c0d57cca44daaf40ba3c33.tar.gz linux-stable-a9e3760b0838299649c0d57cca44daaf40ba3c33.zip | |
sched_ext: Maintain an online cid mask in the scheduler arenagrafted
Schedulers on the default cid mapping treat [0, nr_online_cids) as the
online set and restart on hotplug. Schedulers that install their own mapping
with scx_bpf_cid_override() have no way to learn which cids are online: the
count no longer identifies members and the CPU-form cpumask is unusable from
cid programs. This is an obvious hole in the cid API.
Add scx_bpf_online_cmask(), a kernel-maintained cmask in the scheduler's
arena, allocated alongside the per-CPU scratch masks and populated after the
cid mapping is finalized and before ops.init(), for child schedulers too.
The pointer stays valid through ops.exit() with no reference to take. It is
the arena offset as a void pointer, the same form struct_ops arena arguments
arrive in. The verifier types the void return as a scalar for the program's
arena cast.
The mask follows the SCX hotplug notifications: seeded from cpu_active_mask
and updated before ops.cid_online/offline() runs, so it lags cpu_online_mask
only inside a hotplug transition. Updates walk the scheduler list under the
lock that also serializes unlinking. Reads are live, not atomic snapshots.
Root initialization excludes hotplug.
v2: Reworded the getter kerneldoc (Andrea Righi).
Signed-off-by: Tejun Heo <tj@kernel.org>
Reviewed-by: Andrea Righi <arighi@nvidia.com>
Diffstat (limited to 'drivers/clocksource/timer-ralink.c')
| -rw-r--r-- | drivers/clocksource/timer-ralink.c | 157 |
1 files changed, 157 insertions, 0 deletions
diff --git a/drivers/clocksource/timer-ralink.c b/drivers/clocksource/timer-ralink.c new file mode 100644 index 000000000..68434d9ed --- /dev/null +++ b/drivers/clocksource/timer-ralink.c @@ -0,0 +1,157 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Ralink System Tick Counter driver present on RT3352 and MT7620 SoCs. + * + * Copyright (C) 2013 by John Crispin <john@phrozen.org> + */ + +#include <linux/clockchips.h> +#include <linux/clocksource.h> +#include <linux/interrupt.h> +#include <linux/reset.h> +#include <linux/init.h> +#include <linux/time.h> +#include <linux/of.h> +#include <linux/of_irq.h> +#include <linux/of_address.h> + +#define SYSTICK_FREQ (50 * 1000) + +#define SYSTICK_CONFIG 0x00 +#define SYSTICK_COMPARE 0x04 +#define SYSTICK_COUNT 0x08 + +/* route systick irq to mips irq 7 instead of the r4k-timer */ +#define CFG_EXT_STK_EN 0x2 +/* enable the counter */ +#define CFG_CNT_EN 0x1 + +struct systick_device { + void __iomem *membase; + struct clock_event_device dev; + int irq_requested; + int freq_scale; +}; + +static int systick_set_oneshot(struct clock_event_device *evt); +static int systick_shutdown(struct clock_event_device *evt); + +static int systick_next_event(unsigned long delta, + struct clock_event_device *evt) +{ + struct systick_device *sdev; + u32 count; + + sdev = container_of(evt, struct systick_device, dev); + count = ioread32(sdev->membase + SYSTICK_COUNT); + count = (count + delta) % SYSTICK_FREQ; + iowrite32(count, sdev->membase + SYSTICK_COMPARE); + + return 0; +} + +static void systick_event_handler(struct clock_event_device *dev) +{ + /* noting to do here */ +} + +static irqreturn_t systick_interrupt(int irq, void *dev_id) +{ + struct clock_event_device *dev = (struct clock_event_device *)dev_id; + + dev->event_handler(dev); + + return IRQ_HANDLED; +} + +static struct systick_device systick = { + .dev = { + /* + * cevt-r4k uses 300, make sure systick + * gets used if available + */ + .rating = 310, + .features = CLOCK_EVT_FEAT_ONESHOT, + .set_next_event = systick_next_event, + .set_state_shutdown = systick_shutdown, + .set_state_oneshot = systick_set_oneshot, + .event_handler = systick_event_handler, + }, +}; + +static int systick_shutdown(struct clock_event_device *evt) +{ + struct systick_device *sdev; + + sdev = container_of(evt, struct systick_device, dev); + + if (sdev->irq_requested) + free_irq(systick.dev.irq, &systick.dev); + sdev->irq_requested = 0; + iowrite32(0, systick.membase + SYSTICK_CONFIG); + + return 0; +} + +static int systick_set_oneshot(struct clock_event_device *evt) +{ + const char *name = systick.dev.name; + struct systick_device *sdev; + int irq = systick.dev.irq; + + sdev = container_of(evt, struct systick_device, dev); + + if (!sdev->irq_requested) { + if (request_irq(irq, systick_interrupt, + IRQF_PERCPU | IRQF_TIMER, name, &systick.dev)) + pr_err("Failed to request irq %d (%s)\n", irq, name); + } + sdev->irq_requested = 1; + iowrite32(CFG_EXT_STK_EN | CFG_CNT_EN, + systick.membase + SYSTICK_CONFIG); + + return 0; +} + +static int __init ralink_systick_init(struct device_node *np) +{ + int ret; + + systick.membase = of_iomap(np, 0); + if (!systick.membase) + return -ENXIO; + + systick.dev.name = np->name; + clockevents_calc_mult_shift(&systick.dev, SYSTICK_FREQ, 60); + systick.dev.max_delta_ns = clockevent_delta2ns(0x7fff, &systick.dev); + systick.dev.max_delta_ticks = 0x7fff; + systick.dev.min_delta_ns = clockevent_delta2ns(0x3, &systick.dev); + systick.dev.min_delta_ticks = 0x3; + systick.dev.irq = irq_of_parse_and_map(np, 0); + if (!systick.dev.irq) { + pr_err("%pOFn: request_irq failed", np); + ret = -EINVAL; + goto err_iounmap; + } + + ret = clocksource_mmio_init(systick.membase + SYSTICK_COUNT, np->name, + SYSTICK_FREQ, 301, 16, + clocksource_mmio_readl_up); + if (ret) + goto err_free_irq; + + clockevents_register_device(&systick.dev); + + pr_info("%pOFn: running - mult: %d, shift: %d\n", + np, systick.dev.mult, systick.dev.shift); + + return 0; + +err_free_irq: + irq_dispose_mapping(systick.dev.irq); +err_iounmap: + iounmap(systick.membase); + return ret; +} + +TIMER_OF_DECLARE(systick, "ralink,cevt-systick", ralink_systick_init); |
