diff options
| author | Tim Chen <tim.c.chen@linux.intel.com> | 2026-09-21 17:37:22 -0700 |
|---|---|---|
| committer | Ingo Molnar <mingo@kernel.org> | 2026-09-22 10:49:53 +0200 |
| commit | 0d6526f82c3cdefcca47f73f5fc08dc6f335eac6 (patch) | |
| tree | 176dc2d685debcfb082c151ee94f2425ac96b364 /drivers/pinctrl/pinctrl-equilibrium.h | |
| download | linux-stable-0d6526f82c3cdefcca47f73f5fc08dc6f335eac6.tar.gz linux-stable-0d6526f82c3cdefcca47f73f5fc08dc6f335eac6.zip | |
sched/cache: Keep nr_pref_llc_running in the runnable domain, to fix LLC mis-scheduling buggrafted
alb_break_llc() decides whether to break LLC preference during active
load balance. It does so by testing that every runnable fair task on the
source rq prefers its LLC:
env->src_rq->nr_pref_llc_running == env->src_rq->cfs.h_nr_runnable
But the two counters cover different sets. nr_pref_llc_running is updated
in account_llc_enqueue()/account_llc_dequeue(), next to cfs_rq->nr_queued,
so it follows queued tasks. h_nr_runnable is updated in set_delayed()/
clear_delayed() and drops delay-dequeued tasks.
So under DELAY_DEQUEUE, a preferring task that goes to sleep stays counted
in nr_pref_llc_running while h_nr_runnable falls. The equality then breaks,
alb_break_llc() returns false, and active balance is free to pull a task
off its preferred LLC. Active balance only moves runnable tasks, and this
is the only LLC check it consults: once the stopper runs, LBF_ACTIVE_LB
skips the per-task test in can_migrate_task(). The runnable set is the one
we want.
Fix it on the counter side. A task should be counted in
nr_pref_llc_running exactly while it is both queued on its preferred LLC
(pref_llc_queued) and runnable (!sched_delayed). Define that membership
once in task_pref_llc_runnable(), and adjust the counter only through
pref_llc_running_inc()/pref_llc_running_dec() from the four sites that
change either input: account_llc_enqueue(), account_llc_dequeue(),
set_delayed() and clear_delayed(). Gating every update on the same
predicate keeps the delay, wake and dequeue paths from double-counting
or underflowing; see the comments at those sites for the ordering.
nr_llc_running and sd->llc_counts are not touched and stay on queued
semantics.
Fixes: 714059f79ff0 ("sched/cache: Handle moving single tasks to/from their preferred LLC")
Closes: https://lore.kernel.org/lkml/20260827135000.735138-1-zhanxusheng@xiaomi.com/
Reported-by: Zhan Xusheng <zhanxusheng@xiaomi.com>
Suggested-by: Chen Yu <yu.c.chen@intel.com>
Signed-off-by: Tim Chen <tim.c.chen@linux.intel.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Reviewed-by: Kayra Cizmeci <kayracizmeci@gmail.com>
Cc: <stable@kernel.org> # v7.2.x
Link: https://patch.msgid.link/06af61afedac32e6477f57feb4d658f6c411c3af.1790035273.git.tim.c.chen@linux.intel.com
Diffstat (limited to 'drivers/pinctrl/pinctrl-equilibrium.h')
| -rw-r--r-- | drivers/pinctrl/pinctrl-equilibrium.h | 132 |
1 files changed, 132 insertions, 0 deletions
diff --git a/drivers/pinctrl/pinctrl-equilibrium.h b/drivers/pinctrl/pinctrl-equilibrium.h new file mode 100644 index 000000000..b56124d7f --- /dev/null +++ b/drivers/pinctrl/pinctrl-equilibrium.h @@ -0,0 +1,132 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(c) 2019 Intel Corporation. + */ + +#ifndef __PINCTRL_EQUILIBRIUM_H +#define __PINCTRL_EQUILIBRIUM_H + +/* PINPAD register offset */ +#define REG_PMX_BASE 0x0 /* Port Multiplexer Control Register */ +#define REG_PUEN 0x80 /* PULL UP Enable Register */ +#define REG_PDEN 0x84 /* PULL DOWN Enable Register */ +#define REG_SRC 0x88 /* Slew Rate Control Register */ +#define REG_DCC0 0x8C /* Drive Current Control Register 0 */ +#define REG_DCC1 0x90 /* Drive Current Control Register 1 */ +#define REG_OD 0x94 /* Open Drain Enable Register */ +#define REG_AVAIL 0x98 /* Pad Control Availability Register */ +#define DRV_CUR_PINS 16 /* Drive Current pin number per register */ +#define REG_DRCC(x) (REG_DCC0 + (x) * 4) /* Driver current macro */ + +/* GPIO register offset */ +#define GPIO_OUT 0x0 /* Data Output Register */ +#define GPIO_IN 0x4 /* Data Input Register */ +#define GPIO_DIR 0x8 /* Direction Register */ +#define GPIO_EXINTCR0 0x18 /* External Interrupt Control Register 0 */ +#define GPIO_EXINTCR1 0x1C /* External Interrupt Control Register 1 */ +#define GPIO_IRNCR 0x20 /* IRN Capture Register */ +#define GPIO_IRNICR 0x24 /* IRN Interrupt Control Register */ +#define GPIO_IRNEN 0x28 /* IRN Interrupt Enable Register */ +#define GPIO_IRNCFG 0x2C /* IRN Interrupt Configuration Register */ +#define GPIO_IRNRNSET 0x30 /* IRN Interrupt Enable Set Register */ +#define GPIO_IRNENCLR 0x34 /* IRN Interrupt Enable Clear Register */ +#define GPIO_OUTSET 0x40 /* Output Set Register */ +#define GPIO_OUTCLR 0x44 /* Output Clear Register */ +#define GPIO_DIRSET 0x48 /* Direction Set Register */ +#define GPIO_DIRCLR 0x4C /* Direction Clear Register */ + +/* parse given pin's driver current value */ +#define PARSE_DRV_CURRENT(val, pin) (((val) >> ((pin) * 2)) & 0x3) + +#define GPIO_EDGE_TRIG 0 +#define GPIO_LEVEL_TRIG 1 +#define GPIO_SINGLE_EDGE 0 +#define GPIO_BOTH_EDGE 1 +#define GPIO_POSITIVE_TRIG 0 +#define GPIO_NEGATIVE_TRIG 1 + +#define EQBR_GPIO_MODE 0 + +typedef enum { + OP_COUNT_NR_FUNCS, + OP_ADD_FUNCS, + OP_COUNT_NR_FUNC_GRPS, + OP_ADD_FUNC_GRPS, + OP_NONE, +} funcs_util_ops; + +/** + * struct gpio_irq_type: gpio irq configuration + * @trig_type: level trigger or edge trigger + * @edge_type: sigle edge or both edge + * @logic_type: positive trigger or negative trigger + */ +struct gpio_irq_type { + unsigned int trig_type; + unsigned int edge_type; + unsigned int logic_type; +}; + +/** + * struct eqbr_pin_bank: represent a pin bank. + * @membase: base address of the pin bank register. + * @id: bank id, to idenify the unique bank. + * @pin_base: starting pin number of the pin bank. + * @nr_pins: number of the pins of the pin bank. + * @aval_pinmap: available pin bitmap of the pin bank. + */ +struct eqbr_pin_bank { + void __iomem *membase; + unsigned int id; + unsigned int pin_base; + unsigned int nr_pins; + u32 aval_pinmap; +}; + +struct fwnode_handle; + +/** + * struct eqbr_gpio_ctrl: represent a gpio controller. + * @chip: gpio chip. + * @fwnode: firmware node of gpio controller. + * @bank: pointer to corresponding pin bank. + * @membase: base address of the gpio controller. + * @name: gpio chip name. + * @virq: irq number of the gpio chip to parent's irq domain. + * @lock: spin lock to protect gpio register write. + */ +struct eqbr_gpio_ctrl { + struct gpio_generic_chip chip; + struct fwnode_handle *fwnode; + struct eqbr_pin_bank *bank; + void __iomem *membase; + const char *name; + unsigned int virq; + raw_spinlock_t lock; /* protect gpio register */ +}; + +/** + * struct eqbr_pinctrl_drv_data: + * @dev: device instance representing the controller. + * @pctl_desc: pin controller descriptor. + * @pctl_dev: pin control class device + * @membase: base address of pin controller + * @pin_banks: list of pin banks of the driver. + * @nr_banks: number of pin banks. + * @gpio_ctrls: list of gpio controllers. + * @nr_gpio_ctrls: number of gpio controllers. + * @lock: protect pinctrl register write + */ +struct eqbr_pinctrl_drv_data { + struct device *dev; + struct pinctrl_desc pctl_desc; + struct pinctrl_dev *pctl_dev; + void __iomem *membase; + struct eqbr_pin_bank *pin_banks; + unsigned int nr_banks; + struct eqbr_gpio_ctrl *gpio_ctrls; + unsigned int nr_gpio_ctrls; + raw_spinlock_t lock; /* protect pinpad register */ +}; + +#endif /* __PINCTRL_EQUILIBRIUM_H */ |
