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/net/phy/bcm-phy-lib.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/net/phy/bcm-phy-lib.h')
| -rw-r--r-- | drivers/net/phy/bcm-phy-lib.h | 129 |
1 files changed, 129 insertions, 0 deletions
diff --git a/drivers/net/phy/bcm-phy-lib.h b/drivers/net/phy/bcm-phy-lib.h new file mode 100644 index 000000000..bba94ce96 --- /dev/null +++ b/drivers/net/phy/bcm-phy-lib.h @@ -0,0 +1,129 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2015 Broadcom Corporation + */ + +#ifndef _LINUX_BCM_PHY_LIB_H +#define _LINUX_BCM_PHY_LIB_H + +#include <linux/brcmphy.h> +#include <linux/phy.h> +#include <linux/interrupt.h> + +struct ethtool_wolinfo; + +/* 28nm only register definitions */ +#define MISC_ADDR(base, channel) base, channel + +#define DSP_TAP10 MISC_ADDR(0x0a, 0) +#define PLL_PLLCTRL_1 MISC_ADDR(0x32, 1) +#define PLL_PLLCTRL_2 MISC_ADDR(0x32, 2) +#define PLL_PLLCTRL_4 MISC_ADDR(0x33, 0) + +#define AFE_RXCONFIG_0 MISC_ADDR(0x38, 0) +#define AFE_RXCONFIG_1 MISC_ADDR(0x38, 1) +#define AFE_RXCONFIG_2 MISC_ADDR(0x38, 2) +#define AFE_RX_LP_COUNTER MISC_ADDR(0x38, 3) +#define AFE_TX_CONFIG MISC_ADDR(0x39, 0) +#define AFE_VDCA_ICTRL_0 MISC_ADDR(0x39, 1) +#define AFE_VDAC_OTHERS_0 MISC_ADDR(0x39, 3) +#define AFE_HPF_TRIM_OTHERS MISC_ADDR(0x3a, 0) + + +int __bcm_phy_write_exp(struct phy_device *phydev, u16 reg, u16 val); +int __bcm_phy_read_exp(struct phy_device *phydev, u16 reg); +int __bcm_phy_modify_exp(struct phy_device *phydev, u16 reg, u16 mask, u16 set); +int bcm_phy_write_exp(struct phy_device *phydev, u16 reg, u16 val); +int bcm_phy_read_exp(struct phy_device *phydev, u16 reg); +int bcm_phy_modify_exp(struct phy_device *phydev, u16 reg, u16 mask, u16 set); + +static inline int bcm_phy_write_exp_sel(struct phy_device *phydev, + u16 reg, u16 val) +{ + return bcm_phy_write_exp(phydev, reg | MII_BCM54XX_EXP_SEL_ER, val); +} + +static inline int bcm_phy_read_exp_sel(struct phy_device *phydev, u16 reg) +{ + return bcm_phy_read_exp(phydev, reg | MII_BCM54XX_EXP_SEL_ER); +} + +int bcm54xx_auxctl_write(struct phy_device *phydev, u16 regnum, u16 val); +int bcm54xx_auxctl_read(struct phy_device *phydev, u16 regnum); + +int bcm_phy_write_misc(struct phy_device *phydev, + u16 reg, u16 chl, u16 value); +int bcm_phy_read_misc(struct phy_device *phydev, + u16 reg, u16 chl); + +int bcm_phy_write_shadow(struct phy_device *phydev, u16 shadow, + u16 val); +int bcm_phy_read_shadow(struct phy_device *phydev, u16 shadow); + +int __bcm_phy_write_rdb(struct phy_device *phydev, u16 rdb, u16 val); +int bcm_phy_write_rdb(struct phy_device *phydev, u16 rdb, u16 val); +int __bcm_phy_read_rdb(struct phy_device *phydev, u16 rdb); +int bcm_phy_read_rdb(struct phy_device *phydev, u16 rdb); +int __bcm_phy_modify_rdb(struct phy_device *phydev, u16 rdb, u16 mask, + u16 set); +int bcm_phy_modify_rdb(struct phy_device *phydev, u16 rdb, u16 mask, + u16 set); + +int bcm_phy_ack_intr(struct phy_device *phydev); +int bcm_phy_config_intr(struct phy_device *phydev); +irqreturn_t bcm_phy_handle_interrupt(struct phy_device *phydev); + +int bcm_phy_enable_apd(struct phy_device *phydev, bool dll_pwr_down); + +int bcm_phy_set_eee(struct phy_device *phydev, bool enable); + +int bcm_phy_downshift_get(struct phy_device *phydev, u8 *count); + +int bcm_phy_downshift_set(struct phy_device *phydev, u8 count); + +int bcm_phy_get_sset_count(struct phy_device *phydev); +void bcm_phy_get_strings(struct phy_device *phydev, u8 *data); +void bcm_phy_get_stats(struct phy_device *phydev, u64 *shadow, + struct ethtool_stats *stats, u64 *data); +void bcm_phy_update_stats_shadow(struct phy_device *phydev, u64 *shadow); +void bcm_phy_r_rc_cal_reset(struct phy_device *phydev); +int bcm_phy_28nm_a0b0_afe_config_init(struct phy_device *phydev); +int bcm_phy_enable_jumbo(struct phy_device *phydev); + +int bcm_phy_cable_test_get_status_rdb(struct phy_device *phydev, + bool *finished); +int bcm_phy_cable_test_start_rdb(struct phy_device *phydev); +int bcm_phy_cable_test_start(struct phy_device *phydev); +int bcm_phy_cable_test_get_status(struct phy_device *phydev, bool *finished); + +#if IS_ENABLED(CONFIG_BCM_NET_PHYPTP) +struct bcm_ptp_private *bcm_ptp_probe(struct phy_device *phydev); +void bcm_ptp_config_init(struct phy_device *phydev); +void bcm_ptp_stop(struct bcm_ptp_private *priv); +#else +static inline struct bcm_ptp_private *bcm_ptp_probe(struct phy_device *phydev) +{ + return NULL; +} + +static inline void bcm_ptp_config_init(struct phy_device *phydev) +{ +} + +static inline void bcm_ptp_stop(struct bcm_ptp_private *priv) +{ +} +#endif + +int bcm_phy_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol); +void bcm_phy_get_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol); +irqreturn_t bcm_phy_wol_isr(int irq, void *dev_id); + +int bcm_phy_led_brightness_set(struct phy_device *phydev, + u8 index, enum led_brightness value); + +int bcm_setup_lre_master_slave(struct phy_device *phydev); +int bcm_config_lre_aneg(struct phy_device *phydev, bool changed); +int bcm_config_lre_advert(struct phy_device *phydev); + +#endif /* _LINUX_BCM_PHY_LIB_H */ |
