From ecb37f4f54397f2d41013318df9a5fde759da478 Mon Sep 17 00:00:00 2001 From: zuoqian Date: Thu, 26 Jun 2025 14:43:04 +0800 Subject: [PATCH 001/155] net: phytmac: fix page refcounting for XDP_REDIRECT The current page counting scheme assumes that the reference count cannot decrease until the received frame is sent to the upper layers of the networking stack. This assumption does not hold for the XDP_REDIRECT action, particularly with BPF_MAP_TYPE_XSKMAP handling, since a page (pointed out by xdp_buff) can have its reference count decreased via the xdp_do_redirect call. To work around that, now start off by a large page count and then don't allow a refcount less than two. Signed-off-by: zuoqian --- drivers/net/ethernet/phytium/phytmac_main.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/phytium/phytmac_main.c b/drivers/net/ethernet/phytium/phytmac_main.c index 9ed5ec0952..ece14f0a7b 100644 --- a/drivers/net/ethernet/phytium/phytmac_main.c +++ b/drivers/net/ethernet/phytium/phytmac_main.c @@ -739,7 +739,8 @@ static bool phytmac_alloc_mapped_page(struct phytmac *pdata, bi->addr = dma; bi->page = page; bi->page_offset = PHYTMAC_SKB_PAD; - bi->pagecnt_bias = 1; + page_ref_add(page, USHRT_MAX - 1); + bi->pagecnt_bias = USHRT_MAX; return true; } @@ -769,8 +770,8 @@ static bool phytmac_can_reuse_rx_page(struct phytmac_rx_buffer *rx_buffer) * the pagecnt_bias and page count so that we fully restock the * number of references the driver holds. */ - if (unlikely(!pagecnt_bias)) { - page_ref_add(page, USHRT_MAX); + if (unlikely(pagecnt_bias == 1)) { + page_ref_add(page, USHRT_MAX - 1); rx_buffer->pagecnt_bias = USHRT_MAX; } -- Gitee From e0afd4a644ef7a05096822bcfefe1b5671590434 Mon Sep 17 00:00:00 2001 From: Wanqing Zhu Date: Fri, 4 Jul 2025 14:39:00 +0800 Subject: [PATCH 002/155] arm64: phytium_defconfig: enable CONFIG_SND_HDA_INTEL Signed-off-by: Wanqing Zhu --- arch/arm64/configs/phytium_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/configs/phytium_defconfig b/arch/arm64/configs/phytium_defconfig index 21c153d162..e8c0e57bda 100644 --- a/arch/arm64/configs/phytium_defconfig +++ b/arch/arm64/configs/phytium_defconfig @@ -606,6 +606,7 @@ CONFIG_LOGO=y CONFIG_SOUND=y CONFIG_SND=y CONFIG_SND_ALOOP=m +CONFIG_SND_HDA_INTEL=y CONFIG_SND_HDA_PHYTIUM=y CONFIG_SND_HDA_CODEC_REALTEK=y CONFIG_SND_HDA_CODEC_HDMI=y -- Gitee From 245f0f86d4362aa2d5f1c6f23a8e1d7311a84fe3 Mon Sep 17 00:00:00 2001 From: Huangjie Date: Thu, 3 Jul 2025 17:26:49 +0800 Subject: [PATCH 003/155] drivers: i2s/phytium-i2s: optimize the playback format supported by DP audio DP protocol not support S32_LE format, remove S32_LE format on DP I2S Signed-off-by: Huangjie --- sound/soc/phytium/phytium_i2s.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/sound/soc/phytium/phytium_i2s.c b/sound/soc/phytium/phytium_i2s.c index 07254f15c8..5218fb16c2 100644 --- a/sound/soc/phytium/phytium_i2s.c +++ b/sound/soc/phytium/phytium_i2s.c @@ -520,8 +520,7 @@ static struct snd_soc_dai_driver phytium_i2s_dai = { .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_LE | - SNDRV_PCM_FMTBIT_S24_LE | - SNDRV_PCM_FMTBIT_S32_LE, + SNDRV_PCM_FMTBIT_S24_LE, }, .capture = { .stream_name = "i2s-Capture", @@ -538,7 +537,7 @@ static struct snd_soc_dai_driver phytium_i2s_dai = { .symmetric_rate = 1, }; -static const struct snd_pcm_hardware phytium_pcm_hardware = { +static struct snd_pcm_hardware phytium_pcm_hardware = { .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | @@ -552,8 +551,7 @@ static const struct snd_pcm_hardware phytium_pcm_hardware = { .formats = (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_LE | - SNDRV_PCM_FMTBIT_S24_LE | - SNDRV_PCM_FMTBIT_S32_LE), + SNDRV_PCM_FMTBIT_S24_LE ), .channels_min = 2, .channels_max = 2, .buffer_bytes_max = 4096*16, @@ -627,6 +625,9 @@ static int phytium_pcm_open(struct snd_soc_component *component, if (azx_dev == NULL) return -EBUSY; + if (!dev->i2s_dp) + phytium_pcm_hardware.formats |= SNDRV_PCM_FMTBIT_S32_LE; + snd_soc_set_runtime_hwparams(substream, &phytium_pcm_hardware); snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 128); @@ -1525,6 +1526,14 @@ static int phytium_i2s_probe(struct platform_device *pdev) } } + if (strstr(dai_drv->name, "dp")) + i2s->i2s_dp = 1; + else + i2s->i2s_dp = 0; + + if (!i2s->i2s_dp) + dai_drv->playback.formats |= SNDRV_PCM_FMTBIT_S32_LE; + ret = devm_snd_soc_register_component(&pdev->dev, &phytium_i2s_component, dai_drv, 1); if (ret != 0) -- Gitee From e1606c7367be79b225ad03ebe92c6fd16c559ed6 Mon Sep 17 00:00:00 2001 From: Huangjie Date: Fri, 4 Jul 2025 14:32:00 +0800 Subject: [PATCH 004/155] drivers: i2s/phytium_i2s: add dai-name property check Signed-off-by: Huangjie --- sound/soc/phytium/phytium_i2s.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/phytium/phytium_i2s.c b/sound/soc/phytium/phytium_i2s.c index 5218fb16c2..02862a489f 100644 --- a/sound/soc/phytium/phytium_i2s.c +++ b/sound/soc/phytium/phytium_i2s.c @@ -1507,6 +1507,10 @@ static int phytium_i2s_probe(struct platform_device *pdev) i2s->pcie = 1; } else if (pdev->dev.of_node) { device_property_read_string(&pdev->dev, "dai-name", &dai_drv->name); + if (ret < 0) { + dev_err(&pdev->dev, "missing dai-name property from dts\n"); + goto failed_get_dai_name; + } i2s->pdev = &pdev->dev; clk = devm_clk_get(&pdev->dev, NULL); i2s->clk_base = clk_get_rate(clk); -- Gitee From 324c39eeef495bab4807d2569b20efb037e8ff66 Mon Sep 17 00:00:00 2001 From: Huangjie Date: Fri, 4 Jul 2025 14:47:45 +0800 Subject: [PATCH 005/155] dts: arm64/phytium: add dai-name property in i2s0 node Signed-off-by: Huangjie --- arch/arm64/boot/dts/phytium/pe2202.dtsi | 1 + arch/arm64/boot/dts/phytium/pe2204.dtsi | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm64/boot/dts/phytium/pe2202.dtsi b/arch/arm64/boot/dts/phytium/pe2202.dtsi index 5d42cccc6c..c5d94059e5 100644 --- a/arch/arm64/boot/dts/phytium/pe2202.dtsi +++ b/arch/arm64/boot/dts/phytium/pe2202.dtsi @@ -114,6 +114,7 @@ i2s0: i2s@28009000 { interrupts = ; clocks = <&sysclk_600mhz>; clock-names = "i2s_clk"; + dai-name = "phytium-i2s-lsd"; status = "disabled"; }; diff --git a/arch/arm64/boot/dts/phytium/pe2204.dtsi b/arch/arm64/boot/dts/phytium/pe2204.dtsi index 228264b282..16bc488978 100644 --- a/arch/arm64/boot/dts/phytium/pe2204.dtsi +++ b/arch/arm64/boot/dts/phytium/pe2204.dtsi @@ -149,6 +149,7 @@ i2s0: i2s@28009000 { interrupts = ; clocks = <&sysclk_600mhz>; clock-names = "i2s_clk"; + dai-name = "phytium-i2s-lsd"; status = "disabled"; }; -- Gitee From 7670b9601ad26a8beadacd37291e6007dd09670c Mon Sep 17 00:00:00 2001 From: zuoqian Date: Mon, 7 Jul 2025 16:51:16 +0800 Subject: [PATCH 006/155] arm64: phytium_defconfig: open gpio sysfs support Signed-off-by: zuoqian --- arch/arm64/configs/phytium_defconfig | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/arch/arm64/configs/phytium_defconfig b/arch/arm64/configs/phytium_defconfig index e8c0e57bda..cdf6033ec6 100644 --- a/arch/arm64/configs/phytium_defconfig +++ b/arch/arm64/configs/phytium_defconfig @@ -27,9 +27,11 @@ CONFIG_CGROUP_DEVICE=y CONFIG_CGROUP_CPUACCT=y CONFIG_CGROUP_PERF=y CONFIG_CGROUP_BPF=y +CONFIG_NAMESPACES=y CONFIG_USER_NS=y CONFIG_SCHED_AUTOGROUP=y CONFIG_BLK_DEV_INITRD=y +CONFIG_EXPERT=y CONFIG_KALLSYMS_ALL=y CONFIG_PROFILING=y CONFIG_KEXEC=y @@ -433,6 +435,7 @@ CONFIG_PINCTRL=y CONFIG_PINCTRL_MAX77620=y CONFIG_PINCTRL_RK805=m CONFIG_PINCTRL_SINGLE=y +CONFIG_GPIO_SYSFS=y CONFIG_GPIO_ALTERA=m CONFIG_GPIO_DWAPB=y CONFIG_GPIO_MB86S7X=y @@ -531,6 +534,7 @@ CONFIG_RC_DECODERS=y CONFIG_RC_DEVICES=y CONFIG_IR_GPIO_CIR=m CONFIG_MEDIA_SUPPORT=m +CONFIG_MEDIA_SUPPORT_FILTER=y CONFIG_MEDIA_CAMERA_SUPPORT=y CONFIG_MEDIA_ANALOG_TV_SUPPORT=y CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y @@ -675,6 +679,19 @@ CONFIG_SND_SOC_LPASS_TX_MACRO=m CONFIG_SND_SIMPLE_CARD=y CONFIG_SND_AUDIO_GRAPH_CARD=m CONFIG_SND_AUDIO_GRAPH_CARD2=m +CONFIG_HID_A4TECH=y +CONFIG_HID_APPLE=y +CONFIG_HID_BELKIN=y +CONFIG_HID_CHERRY=y +CONFIG_HID_CHICONY=y +CONFIG_HID_CYPRESS=y +CONFIG_HID_EZKEY=y +CONFIG_HID_ITE=y +CONFIG_HID_KENSINGTON=y +CONFIG_HID_LOGITECH=y +CONFIG_HID_REDRAGON=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MONTEREY=y CONFIG_HID_MULTITOUCH=m CONFIG_I2C_HID_ACPI=m CONFIG_I2C_HID_OF=m @@ -989,7 +1006,6 @@ CONFIG_INDIRECT_PIO=y CONFIG_DMA_RESTRICTED_POOL=y CONFIG_CMA_SIZE_MBYTES=32 CONFIG_PRINTK_TIME=y -CONFIG_DEBUG_KERNEL=y CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y CONFIG_DEBUG_INFO_REDUCED=y CONFIG_MAGIC_SYSRQ=y -- Gitee From bfc66def8d8b098bcbf70737592b858aab4c7436 Mon Sep 17 00:00:00 2001 From: Huangjie Date: Thu, 19 Jun 2025 15:29:16 +0800 Subject: [PATCH 007/155] drivers: drm/phytium: optimize the logic of DRM force 1. not check display mode when enable DRM force 2. turn off DRM force after connect a screen Signed-off-by: Huangjie --- drivers/gpu/drm/phytium/phytium_dp.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/phytium/phytium_dp.c b/drivers/gpu/drm/phytium/phytium_dp.c index da3757541d..b9277c2fb2 100644 --- a/drivers/gpu/drm/phytium/phytium_dp.c +++ b/drivers/gpu/drm/phytium/phytium_dp.c @@ -1896,8 +1896,11 @@ void phytium_dp_hpd_work_func(struct work_struct *work) drm_dbg_kms(dev, "running encoder hotplug work functions\n"); drm_connector_list_iter_begin(dev, &conn_iter); drm_for_each_connector_iter(connector, &conn_iter) { - if (connector->force) + if (connector->force) { + connector->force = 0; + changed = true; continue; + } old_status = connector->status; connector->status = drm_helper_probe_detect(connector, NULL, false); if (old_status != connector->status) { @@ -2227,6 +2230,9 @@ phytium_encoder_mode_valid(struct drm_encoder *encoder, const struct drm_display break; } + if (phytium_dp->connector.force == DRM_FORCE_ON) + return MODE_OK; + if ((display_info->color_formats & DRM_COLOR_FORMAT_RGB444) == 0) { DRM_DEBUG_KMS("not support color_format(%d)\n", display_info->color_formats); display_info->color_formats = DRM_COLOR_FORMAT_RGB444; -- Gitee From 5e04499515c89ed17d2237e53b91ca32cb738210 Mon Sep 17 00:00:00 2001 From: root Date: Thu, 21 Aug 2025 19:04:14 +0800 Subject: [PATCH 008/155] arm64: phytium_defconfig: open CONFIG_SQUASHFS_XATTR for firefox snap --- arch/arm64/configs/phytium_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/configs/phytium_defconfig b/arch/arm64/configs/phytium_defconfig index cdf6033ec6..286f38c301 100644 --- a/arch/arm64/configs/phytium_defconfig +++ b/arch/arm64/configs/phytium_defconfig @@ -959,6 +959,7 @@ CONFIG_HUGETLBFS=y CONFIG_EFIVAR_FS=y CONFIG_UBIFS_FS=m CONFIG_SQUASHFS=y +CONFIG_SQUASHFS_XATTR=y CONFIG_SQUASHFS_LZO=y CONFIG_SQUASHFS_XZ=y CONFIG_NFS_FS=y -- Gitee From 3bc58a6884d210bee870635b315a7a1cb9f3cc01 Mon Sep 17 00:00:00 2001 From: Huang Shaobo Date: Tue, 11 Feb 2025 16:13:37 +0800 Subject: [PATCH 009/155] misc: Add power monitor driver for Phytium platform This patch adds a power monitor driver, which provides a simple procfs interface to read power data in Phytium SoC. Mainline: NA Signed-off-by: Huang Shaobo Signed-off-by: Wang Yinfeng Change-Id: I4cd4fb626f13063a8a56d74ea7197154d81508dd --- MAINTAINERS | 1 + drivers/misc/Kconfig | 11 + drivers/misc/Makefile | 1 + drivers/misc/phytium_pwrmon.c | 566 ++++++++++++++++++++++++++++++++++ 4 files changed, 579 insertions(+) create mode 100644 drivers/misc/phytium_pwrmon.c diff --git a/MAINTAINERS b/MAINTAINERS index 3df7cd7278..b01b0bec4a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -17504,6 +17504,7 @@ F: drivers/media/platform/phytium-jpeg/phytium_jpeg* F: drivers/mfd/phytium_px210_i2s_lsd.c F: drivers/mfd/phytium_px210_i2s_mmd.c F: drivers/misc/phytium-snoop-ctrl.c +F: drivers/misc/phytium_pwrmon.c F: drivers/mmc/host/phytium-mci* F: drivers/mmc/host/phytium-mci-plat-v2.c F: drivers/mmc/host/phytium-mci-v2* diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index a36a8868bb..08e90e564b 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -573,6 +573,17 @@ config TPS6594_PFSM This driver can also be built as a module. If so, the module will be called tps6594-pfsm. +config PHYTIUM_POWER_MONITOR + tristate "Phytium power monitor support" + depends on ARCH_PHYTIUM + default m + help + Select this option will enable the power monitor driver in + Phytium platform, allowing user to obtain power information + in SoC through procfs, such as power consumption, voltage. + + If unsure, say N. + source "drivers/misc/c2port/Kconfig" source "drivers/misc/eeprom/Kconfig" source "drivers/misc/cb710/Kconfig" diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 16480d807b..25fb543d12 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -68,3 +68,4 @@ obj-$(CONFIG_TMR_MANAGER) += xilinx_tmr_manager.o obj-$(CONFIG_TMR_INJECT) += xilinx_tmr_inject.o obj-$(CONFIG_TPS6594_ESM) += tps6594-esm.o obj-$(CONFIG_TPS6594_PFSM) += tps6594-pfsm.o +obj-$(CONFIG_PHYTIUM_POWER_MONITOR) += phytium_pwrmon.o diff --git a/drivers/misc/phytium_pwrmon.c b/drivers/misc/phytium_pwrmon.c new file mode 100644 index 0000000000..5ccac223a6 --- /dev/null +++ b/drivers/misc/phytium_pwrmon.c @@ -0,0 +1,566 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Phytium SoC Power Monitor Driver + * + * This driver provides a simple interface to read power monitor + * data from Phytium SoC. + * + * Copyright (c) 2021-2025 Phytium Technology Co., Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include + +#undef pr_fmt +#define pr_fmt(fmt) "phytium_pwrmon: " fmt + +#define ACPI_METHOD_PKG "PGET" +#define DEFAULT_BUFFER_SIZE (256) + +static struct proc_dir_entry *pwrmon_dir; +static struct proc_dir_entry *proc_entry; + +struct buffer_handler { + char *buf; + size_t sz; + ssize_t len; +}; + +struct pwrmon_drv_data { + struct platform_device *pdev; + struct kmem_cache *bh_cache; +}; + +/** + * get_buffer_handler - Get a buffer handler from kmem_cache + * @drv_data: Pointer to pwrmon_drv_data structure + * + * This function allocates a buffer handler from kmem_cache and initializes it. + * The buffer handler contains a buffer, and the size of the buffer is set to + * DEFAULT_BUFFER_SIZE. The buffer is allocated using kmalloc. + * + * Return: Pointer to buffer handler or NULL on failure + */ +static inline struct buffer_handler *get_buffer_handler(struct pwrmon_drv_data *drv_data) +{ + struct buffer_handler *bh; + + if (!drv_data || !drv_data->bh_cache) + return NULL; + + bh = kmem_cache_zalloc(drv_data->bh_cache, GFP_KERNEL); + if (bh) { + bh->buf = kmalloc(DEFAULT_BUFFER_SIZE, GFP_KERNEL); + if (bh->buf) { + bh->sz = DEFAULT_BUFFER_SIZE; + bh->len = 0; + } else { + kmem_cache_free(drv_data->bh_cache, bh); + bh = NULL; + } + } + return bh; +} + +/** + * put_buffer_handler - Put a buffer handler back to kmem_cache + * @drv_data: Pointer to pwrmon_drv_data structure + * @bh: Pointer to buffer handler + * + * This function puts a buffer handler back to kmem_cache. It first checks if + * the parameters are valid, and then frees the buffer in the buffer handler + * using kfree, and finally frees the buffer handler itself using + * kmem_cache_free. + * + * Return: None + */ +static inline void put_buffer_handler(struct pwrmon_drv_data *drv_data, struct buffer_handler *bh) +{ + if (!bh || !drv_data || !drv_data->bh_cache) + return; + + kfree(bh->buf); + kmem_cache_free(drv_data->bh_cache, bh); +} + +/** + * free_buffer_handler - Free a kmem_cache used to allocate buffer handler + * @drv_data: Pointer to pwrmon_drv_data structure + * + * This function frees a kmem_cache used to allocate buffer handler, and then + * sets the pointer of the cache to NULL. It first checks if the parameters are + * valid, i.e., if the pointer to pwrmon_drv_data structure is not NULL and if + * the pointer to the cache is not NULL. + * + * Return: None + */ +static inline void free_buffer_handler(struct pwrmon_drv_data *drv_data) +{ + if (!drv_data || !drv_data->bh_cache) + return; + + kmem_cache_destroy(drv_data->bh_cache); + drv_data->bh_cache = NULL; +} + +/** + * shrink_buffer_handler - Shrink the buffer handler cache + * @drv_data: Pointer to pwrmon_drv_data structure + * + * This function shrinks the buffer handler cache to release unused memory. + * It checks if the input parameters are valid before proceeding with the + * shrink operation. If either the driver data or the buffer handler cache + * pointer is NULL, the function returns immediately without performing any + * operation. + * + * Return: None + */ +static inline void shrink_buffer_handler(struct pwrmon_drv_data *drv_data) +{ + if (!drv_data || !drv_data->bh_cache) + return; + + kmem_cache_shrink(drv_data->bh_cache); +} + +/** + * init_buffer_handler - Initialize a buffer handler cache + * @drv_data: Pointer to pwrmon_drv_data structure + * + * This function creates a buffer handler cache to store buffer handlers. + * The cache is created with the name "buffer_handler" and the size of a + * buffer handler structure. The cache is created with the SLAB_HWCACHE_ALIGN + * flag to ensure that the cache is aligned to the hardware cache size. + * The cache is created with the NULL constructor and the NULL destructor. + * + * Return: 0 if the cache is created successfully, -ENOMEM if the cache + * cannot be created. + */ +static inline int init_buffer_handler(struct pwrmon_drv_data *drv_data) +{ + if (!drv_data) + return -EINVAL; + + drv_data->bh_cache = kmem_cache_create("buffer_handler", + sizeof(struct buffer_handler), 0, + SLAB_HWCACHE_ALIGN, NULL); + + return drv_data->bh_cache ? 0 : -ENOMEM; +} + +/** + * enlarge_buffer - Enlarge the buffer size of a buffer handler + * @bh: Pointer to buffer_handler structure + * + * This function doubles the size of the buffer in the given buffer handler + * structure. If the buffer handler structure does not have a buffer allocated, + * it allocates a new buffer with the default size. + * + * Return: 0 if the buffer is enlarged successfully, -ENOMEM if memory cannot + * be allocated. + */ +static int enlarge_buffer(struct buffer_handler *bh) +{ + size_t next_sz; + char *new_buf; + + if (!bh || !bh->buf) + return -EFAULT; + + next_sz = bh->sz ? bh->sz * 2 : DEFAULT_BUFFER_SIZE; + new_buf = krealloc(bh->buf, next_sz, GFP_KERNEL); + if (!new_buf) + return -ENOMEM; + + bh->buf = new_buf; + bh->sz = next_sz; + return 0; +} + +static inline struct platform_device *get_pdev(struct inode *inode) +{ + return pde_data(inode); +} + +static inline struct pwrmon_drv_data *get_drv_data(struct inode *node) +{ + struct platform_device *pdev = get_pdev(node); + + return pdev ? platform_get_drvdata(pdev) : NULL; +} + +/** + * prepare_pwrmon_data_acpi - Prepare power monitor data in ACPI mode. + * @pdev: The platform device associated with the power monitor. + * @bh: The buffer handler structure to store the prepared data. + * + * This function evaluates the ACPI method _PGET to get the power monitor data, + * and stores the data in the buffer handler structure. + * + * Return: 0 if the data is prepared successfully, -ENOMEM if memory cannot be + * allocated, -EINVAL if the ACPI handle is invalid or the method evaluation + * fails. + */ +static int prepare_pwrmon_data_acpi(struct platform_device *pdev, struct buffer_handler *bh) +{ + acpi_status status; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object *package; + int ret = 0, i, j; + size_t remaining; + + if (!ACPI_HANDLE(&pdev->dev)) { + pr_err("Invalid ACPI handle\n"); + return -EINVAL; + } + + status = acpi_evaluate_object(ACPI_HANDLE(&pdev->dev), ACPI_METHOD_PKG, NULL, &buffer); + if (ACPI_FAILURE(status)) { + pr_err("ACPI method %s evaluation failed: %d\n", ACPI_METHOD_PKG, status); + return -EINVAL; + } + + package = buffer.pointer; + if (!package || package->type != ACPI_TYPE_PACKAGE) { + pr_err("ACPI method %s did not return a valid package\n", ACPI_METHOD_PKG); + bh->len = 0; + ret = -EINVAL; + goto free_buffer; + } + + for (i = 0; i < package->package.count; i++) { + union acpi_object *element = &package->package.elements[i]; + + if (element->type != ACPI_TYPE_PACKAGE || element->package.count < 2) { + pr_warn_ratelimited("Element %d has %d elements, expected at least 2\n", + i, element->package.count); + continue; + } + for (j = 0; j < element->package.count; j++) { + if (unlikely(element->package.elements[j].type != ACPI_TYPE_INTEGER)) { + pr_warn_ratelimited("Element [%d, %d] is not an integer\n", i, j); + continue; + } else { + /* + * We first check if the buffer is going to overflow. + * If so, we enlarge it. + */ + remaining = bh->sz - bh->len; + if (remaining < 23) { + ret = enlarge_buffer(bh); + if (ret < 0) { + pr_err("Failed to enlarge buffer\n"); + ret = -ENOMEM; + goto free_buffer; + } + } + + /* + * We do not check for overflow here, because we have already + * reserved enough space above. + */ + remaining = bh->sz - bh->len; + ret = scnprintf(bh->buf + bh->len, remaining, "%lld%s%s", + element->package.elements[j].integer.value, + j == 0 ? ": " : " ", + j == element->package.count - 1 ? "\n" : ""); + if (ret < 0) { + pr_err("Write error\n"); + goto free_buffer; + } + + bh->len += ret; + } + } + } + + ret = 0; +free_buffer: + kfree(buffer.pointer); + return ret; +} + + +/** + * prepare_pwrmon_data_of - Prepare power monitor data from Device Tree + * @pdev: Pointer to platform device structure + * @bh: Pointer to buffer handler structure + * + * This function is not implemented yet. + * + * Return: -EOPNOTSUPP if the method is not supported. + */ +static int prepare_pwrmon_data_of(struct platform_device *pdev, struct buffer_handler *bh) +{ + /* TODO: Implement Device Tree support by reading from regmap */ + return -EOPNOTSUPP; +} + +/** + * prepare_pwrmon_data - Prepare power monitor data in the corresponding format. + * @inode: Pointer to inode structure associated with the power monitor device. + * @file: Pointer to file structure associated with the power monitor device. + * + * This function prepares the power monitor data in the corresponding format + * (ACPI or Device Tree) and stores it in the buffer handler structure. + * + * Return: 0 if the data is prepared successfully, -EINVAL if the platform device + * or the buffer handler is invalid, -EOPNOTSUPP if the method is not supported. + */ +static int prepare_pwrmon_data(struct inode *inode, struct file *file) +{ + struct platform_device *pdev = get_pdev(inode); + struct buffer_handler *bh = file->private_data; + + if (!pdev || !bh) + return -EINVAL; + + if (ACPI_HANDLE(&pdev->dev)) + return prepare_pwrmon_data_acpi(pdev, bh); + else if (pdev->dev.of_node) + return prepare_pwrmon_data_of(pdev, bh); + + return -EOPNOTSUPP; +} + +/** + * pwrmon_pm_suspend - Suspend power monitor device + * @dev: Pointer to the device structure + * + * This function is called during the suspend phase of the power management + * process. It attempts to shrink the buffer handler associated with the + * power monitor device to release unused memory. If the driver data is + * not available, it returns an error. The function is intended to be + * expanded with additional suspend operations, such as suspending I/O + * mappings, if needed. + * + * Return: 0 on success, -EINVAL if driver data is not available. + */ + +static int pwrmon_pm_suspend(struct device *dev) +{ + struct pwrmon_drv_data *drv_data = dev_get_drvdata(dev); + + if (!drv_data) + return -EINVAL; + + /* Try to shrink the buffer handler */ + shrink_buffer_handler(drv_data); + + /* TODO: suspend some iomap */ + return 0; +} + +/** + * pwrmon_pm_resume - Resume power monitor device + * @dev: Pointer to the device structure + * + * This function is called during the resume phase of the power management + * process. It attempts to resume I/O mappings associated with the + * power monitor device. If the driver data is not available, it returns + * an error. + * + * Return: 0 on success, -EINVAL if driver data is not available. + */ +static int pwrmon_pm_resume(struct device *dev) +{ + struct pwrmon_drv_data *drv_data = dev_get_drvdata(dev); + + if (!drv_data) + return -EINVAL; + + /* TODO: resume some iomap */ + return 0; +} + +static const struct dev_pm_ops pwrmon_pm_ops = { + .suspend = pwrmon_pm_suspend, + .resume = pwrmon_pm_resume, +}; + +/** + * pwrmon_proc_open - Open a power monitor device for reading + * @inode: Pointer to the inode structure + * @file: Pointer to the file structure + * + * This function is called when the /proc interface is opened for reading. + * It tries to allocate a buffer handler and prepare the power monitor + * data for the user space to read. If the driver data is not available, + * it returns -EINVAL. If the buffer handler cannot be allocated, it + * returns -ENOMEM. If the power monitor data preparation fails, it + * returns -EFAULT. + * + * Return: 0 on success, -EINVAL if driver data is not available, + * -ENOMEM if buffer handler allocation fails, -EFAULT if power monitor + * data preparation fails. + */ +static int pwrmon_proc_open(struct inode *inode, struct file *file) +{ + struct pwrmon_drv_data *drv_data = get_drv_data(inode); + struct buffer_handler *bh; + + if (!drv_data) + return -EINVAL; + + bh = get_buffer_handler(drv_data); + if (!bh) + return -ENOMEM; + + file->private_data = bh; + + if (prepare_pwrmon_data(inode, file)) { + file->private_data = NULL; + put_buffer_handler(drv_data, bh); + return -EFAULT; + } + + return 0; +} + +/** + * pwrmon_proc_release - Release a power monitor device after reading + * @inode: Pointer to the inode structure + * @file: Pointer to the file structure + * + * This function is called when the /proc interface is closed after reading. + * It releases the buffer handler associated with the power monitor device. + * + * Return: 0 on success, -EINVAL if driver data is not available. + */ +static int pwrmon_proc_release(struct inode *inode, struct file *file) +{ + put_buffer_handler(get_drv_data(inode), file->private_data); + return 0; +} + +/** + * pwrmon_proc_read - Read a power monitor device through the /proc interface + * @file: Pointer to the file structure + * @ubuf: Pointer to the user-space buffer + * @count: Size of the user-space buffer + * @ppos: Pointer to the file offset + * + * This function is called when the /proc interface is read. It returns the + * power monitor data stored in the buffer handler associated with the power + * monitor device. + * + * Return: The number of bytes read, -EINVAL if no buffer handler is available. + */ +static ssize_t pwrmon_proc_read(struct file *file, char __user *ubuf, size_t count, loff_t *ppos) +{ + struct buffer_handler *bh = file->private_data; + + return bh ? simple_read_from_buffer(ubuf, count, ppos, bh->buf, bh->len) : -EINVAL; +} + +static const struct proc_ops pwrmon_ops = { + .proc_open = pwrmon_proc_open, + .proc_read = pwrmon_proc_read, + .proc_release = pwrmon_proc_release, +}; + +/** + * pwrmon_probe - Probe the power monitor device + * @pdev: Pointer to the platform device structure + * + * This function is called when the power monitor device is probed. It allocates + * the driver data structure, initializes the buffer handler, and sets up the + * /proc interface. + * + * Return: 0 on success, error code on failure. + */ +static int pwrmon_probe(struct platform_device *pdev) +{ + struct pwrmon_drv_data *drv_data; + + if (!pdev) + return -EINVAL; + + drv_data = devm_kzalloc(&pdev->dev, sizeof(struct pwrmon_drv_data), GFP_KERNEL); + if (!drv_data) + return -ENOMEM; + + drv_data->pdev = pdev; + + + if (init_buffer_handler(drv_data)) { + pr_err("Failed to init buffer handler\n"); + devm_kfree(&pdev->dev, drv_data); + return -ENOMEM; + } + + platform_set_drvdata(pdev, drv_data); + + pwrmon_dir = proc_mkdir("phytium_pwrmon", NULL); + if (!pwrmon_dir) { + pr_err("Failed to create /proc/phytium_pwrmon dir\n"); + goto dir_create_error; + } + + proc_entry = proc_create_data("data", 0444, pwrmon_dir, &pwrmon_ops, pdev); + if (!proc_entry) { + pr_err("Failed to create /proc/phytium_pwrmon/data entry\n"); + goto entry_create_error; + } + + pr_notice("Phytium power monitor driver loaded\n"); + return 0; + +entry_create_error: + if (pwrmon_dir) + proc_remove(pwrmon_dir); +dir_create_error: + free_buffer_handler(drv_data); + return -ENOMEM; +} + +/** + * pwrmon_remove - Remove a power monitor device + * @pdev: Pointer to the platform device structure + * + * This function is called when the power monitor device is removed. It removes + * the /proc interface entries associated with the power monitor device and + * releases the buffer handler. + * + * Return: 0 on success. + */ +static int pwrmon_remove(struct platform_device *pdev) +{ + if (proc_entry) + proc_remove(proc_entry); + + if (pwrmon_dir) + proc_remove(pwrmon_dir); + + free_buffer_handler(platform_get_drvdata(pdev)); + platform_set_drvdata(pdev, NULL); + pr_notice("Phytium power monitor driver unloaded\n"); + return 0; +} + +static const struct acpi_device_id acpi_ids[] = { + { "PHYT800B", 0 }, + { "", 0 } +}; +MODULE_DEVICE_TABLE(acpi, acpi_ids); + +static struct platform_driver pwrmon_driver = { + .probe = pwrmon_probe, + .remove = pwrmon_remove, + .driver = { + .name = "pwrmon_driver", + .acpi_match_table = ACPI_PTR(acpi_ids), + .pm = &pwrmon_pm_ops, + }, +}; + +module_platform_driver(pwrmon_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Huang Shaobo "); +MODULE_DESCRIPTION("Phytium power monitor driver"); -- Gitee From af8ee0093b456e4f587627dafbc7028e08db8b56 Mon Sep 17 00:00:00 2001 From: Zhou Zheng Date: Wed, 26 Feb 2025 17:01:43 +0800 Subject: [PATCH 010/155] codec-v2: phytium: Bugfix the NULL pointer issue in S3 When entering suspend mode, the controller mistakenly releases the memory space for codec registers due to an incorrect if statement. Upon resuming, it releases the same memory space again. which will cause the NULL pointer issue. So modify if statement in suspend, and add a new function to print codec registers. Mainline: NA Signed-off-by: Zhou Zheng Signed-off-by: Wang Yinfeng Change-Id: Ib002be01922c2e6e2dbde67eedd42fa76a2aa623 --- sound/soc/codecs/phytium-codec-v2.c | 86 +++++++++++++++++++++++------ 1 file changed, 70 insertions(+), 16 deletions(-) diff --git a/sound/soc/codecs/phytium-codec-v2.c b/sound/soc/codecs/phytium-codec-v2.c index f117e76ed3..c0e8ff372d 100644 --- a/sound/soc/codecs/phytium-codec-v2.c +++ b/sound/soc/codecs/phytium-codec-v2.c @@ -184,7 +184,7 @@ static int phyt_pm_cmd(struct phytium_codec *priv, struct phytcodec_cmd *msg = priv->sharemem_base; uint16_t total_regs_len; uint8_t *regs; - int ret = 0, i; + int ret = 0, i = 0, cnt = 1; memset(msg, 0, sizeof(struct phytcodec_cmd)); @@ -194,6 +194,7 @@ static int phyt_pm_cmd(struct phytium_codec *priv, msg->cmd_subid = cmd; msg->complete = 0; msg->cmd_para.phytcodec_reg.cnt = 0; + if (cmd == PHYTCODEC_MSG_CMD_SET_RESUME) { memcpy(msg->cmd_para.phytcodec_reg.regs, priv->regs, REG_SH_LEN); phyt_writel_reg(priv->regfile_base, PHYTIUM_CODEC_INT_MASK, 0x0); @@ -202,15 +203,24 @@ static int phyt_pm_cmd(struct phytium_codec *priv, ret = phyt_codec_msg_set_cmd(priv); if (ret < 0) { dev_err(priv->dev, "set cmd_subid 0x%x failed\n", cmd); - ret = -EINVAL; - goto error; + return -EINVAL; } total_regs_len = msg->cmd_para.phytcodec_reg.total_regs_len; + if (total_regs_len % REG_SH_LEN == 0) + cnt = total_regs_len / REG_SH_LEN; + else + cnt = total_regs_len / REG_SH_LEN + 1; - if (cmd == PHYTCODEC_MSG_CMD_SET_SUSPEND || cmd == PHYTCODEC_MSG_CMD_GET_ALL_REGS) { + if (cmd == PHYTCODEC_MSG_CMD_SET_SUSPEND) { regs = kmalloc(total_regs_len, GFP_KERNEL); priv->regs = regs; - while (total_regs_len > REG_SH_LEN * msg->cmd_para.phytcodec_reg.cnt) { + + for (i = 1; i < cnt; i++) { + if (msg->cmd_para.phytcodec_reg.cnt != i) { + dev_err(priv->dev, "error phytcodec_reg.cnt\n"); + ret = -EINVAL; + goto error; + } memcpy(regs, msg->cmd_para.phytcodec_reg.regs, REG_SH_LEN); regs += REG_SH_LEN; msg->complete = 0; @@ -223,15 +233,14 @@ static int phyt_pm_cmd(struct phytium_codec *priv, } memcpy(regs, msg->cmd_para.phytcodec_reg.regs, total_regs_len - REG_SH_LEN * (msg->cmd_para.phytcodec_reg.cnt - 1)); - if (cmd == PHYTCODEC_MSG_CMD_GET_ALL_REGS) { - dev_dbg(priv->dev, "all codec registers:\n"); - for (i = 0; i < total_regs_len; i++) - dev_dbg(priv->dev, "0x%02x-0x%02x\n", i, priv->regs[i]); - kfree(priv->regs); - } } else if (cmd == PHYTCODEC_MSG_CMD_SET_RESUME) { regs = priv->regs; - while (total_regs_len > REG_SH_LEN * msg->cmd_para.phytcodec_reg.cnt) { + for (i = 1; i < cnt; i++) { + if (msg->cmd_para.phytcodec_reg.cnt != i) { + dev_err(priv->dev, "error phytcodec_reg.cnt\n"); + ret = -EINVAL; + goto error; + } regs += REG_SH_LEN; memcpy(msg->cmd_para.phytcodec_reg.regs, regs, REG_SH_LEN); msg->complete = 0; @@ -243,28 +252,73 @@ static int phyt_pm_cmd(struct phytium_codec *priv, } } kfree(priv->regs); + priv->regs = NULL; } + return ret; + error: + kfree(priv->regs); + priv->regs = NULL; return ret; } static int phyt_get_cmd(struct phytium_codec *priv, unsigned int cmd) { struct phytcodec_cmd *msg = priv->sharemem_base; - int ret = 0; + int ret = 0, i = 0, cnt = 1; + uint16_t total_regs_len; + uint8_t *regs; msg->reserved = 0; msg->seq = 0; msg->cmd_id = PHYTCODEC_MSG_CMD_GET; msg->cmd_subid = cmd; msg->complete = 0; + if (cmd == PHYTCODEC_MSG_CMD_GET_ALL_REGS) + msg->cmd_para.phytcodec_reg.cnt = 0; ret = phyt_codec_msg_set_cmd(priv); if (ret < 0) { dev_err(priv->dev, "get cmd_subid 0x%x failed\n", cmd); - ret = -EINVAL; + return -EINVAL; } + total_regs_len = msg->cmd_para.phytcodec_reg.total_regs_len; + if (cmd == PHYTCODEC_MSG_CMD_GET_ALL_REGS) { + if (total_regs_len % REG_SH_LEN == 0) + cnt = total_regs_len / REG_SH_LEN; + else + cnt = total_regs_len / REG_SH_LEN + 1; + regs = kmalloc(total_regs_len, GFP_KERNEL); + priv->regs = regs; + for (i = 1; i < cnt; i++) { + if (msg->cmd_para.phytcodec_reg.cnt != i) { + dev_err(priv->dev, "error phytcodec_reg.cnt\n"); + ret = -EINVAL; + goto error; + } + memcpy(regs, msg->cmd_para.phytcodec_reg.regs, REG_SH_LEN); + regs += REG_SH_LEN; + msg->complete = 0; + ret = phyt_codec_msg_set_cmd(priv); + if (ret < 0) { + dev_err(priv->dev, "set cmd_subid 0x%x failed\n", cmd); + ret = -EINVAL; + goto error; + } + } + memcpy(regs, msg->cmd_para.phytcodec_reg.regs, + total_regs_len - REG_SH_LEN * (msg->cmd_para.phytcodec_reg.cnt - 1)); + for (i = 0; i < total_regs_len; i++) + dev_info(priv->dev, "0x%02x-0x%02x\n", i, priv->regs[i]); + + kfree(priv->regs); + priv->regs = NULL; + } return ret; +error: + kfree(priv->regs); + priv->regs = NULL; + return -EINVAL; } static int phyt_probe(struct snd_soc_component *component) @@ -552,7 +606,7 @@ static int phyt_get_one_reg(struct phytium_codec *priv, uint8_t arg1, uint8_t ar msg->cmd_para.rw_data.addr = arg1; msg->cmd_para.rw_data.reg = arg2; ret = phyt_get_cmd(priv, PHYTCODEC_MSG_CMD_GET_ONE_REG); - dev_dbg(priv->dev, "val: 0x%x\n", msg->cmd_para.rw_data.val); + dev_info(priv->dev, "val: 0x%x\n", msg->cmd_para.rw_data.val); return ret; } @@ -687,7 +741,7 @@ static ssize_t debug_store(struct device *dev, struct device_attribute *da, dev_err(dev, "dump command requires one argument\n"); goto error; } - phyt_pm_cmd(priv, PHYTCODEC_MSG_CMD_GET_ALL_REGS); + phyt_get_cmd(priv, PHYTCODEC_MSG_CMD_GET_ALL_REGS); } else if (strcmp(cmd, "help") == 0) { dev_info(dev, "Available commands:\n" "dump all regs: echo \"dump\" > debug\n" -- Gitee From 9308f464585d26e7f26c7c353c9cf897c001b9f5 Mon Sep 17 00:00:00 2001 From: zhouyulin1283 Date: Wed, 13 Aug 2025 11:07:41 +0800 Subject: [PATCH 011/155] Revert "ec: phytium: Add support for phytium EC driver" This reverts commit 3cdf38d8671e46ffdcb129d1650952f2fbd733a1. --- drivers/acpi/ec.c | 66 ++++++----------------------------------------- 1 file changed, 8 insertions(+), 58 deletions(-) diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index e5d77ee100..115994dfef 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -31,9 +31,6 @@ #include #include "internal.h" -#ifdef CONFIG_ARCH_PHYTIUM -#include "phytium_base_ctrl.h" -#endif #define ACPI_EC_CLASS "embedded_controller" #define ACPI_EC_DEVICE_NAME "Embedded Controller" @@ -276,12 +273,7 @@ static bool acpi_ec_flushed(struct acpi_ec *ec) static inline u8 acpi_ec_read_status(struct acpi_ec *ec) { - u8 x; - - if (phytium_check_cpu() == true) - x = base_ctrl_readb(ec->command_addr); - else - x = inb(ec->command_addr); + u8 x = inb(ec->command_addr); ec_dbg_raw("EC_SC(R) = 0x%2.2x " "SCI_EVT=%d BURST=%d CMD=%d IBF=%d OBF=%d", @@ -296,12 +288,7 @@ static inline u8 acpi_ec_read_status(struct acpi_ec *ec) static inline u8 acpi_ec_read_data(struct acpi_ec *ec) { - u8 x; - - if (phytium_check_cpu() == true) - x = base_ctrl_readb(ec->data_addr); - else - x = inb(ec->data_addr); + u8 x = inb(ec->data_addr); ec->timestamp = jiffies; ec_dbg_raw("EC_DATA(R) = 0x%2.2x", x); @@ -311,24 +298,14 @@ static inline u8 acpi_ec_read_data(struct acpi_ec *ec) static inline void acpi_ec_write_cmd(struct acpi_ec *ec, u8 command) { ec_dbg_raw("EC_SC(W) = 0x%2.2x", command); - - if (phytium_check_cpu() == true) - base_ctrl_writeb(ec->command_addr, command); - else - outb(command, ec->command_addr); - + outb(command, ec->command_addr); ec->timestamp = jiffies; } static inline void acpi_ec_write_data(struct acpi_ec *ec, u8 data) { ec_dbg_raw("EC_DATA(W) = 0x%2.2x", data); - - if (phytium_check_cpu() == true) - base_ctrl_writeb(ec->data_addr, data); - else - outb(data, ec->data_addr); - + outb(data, ec->data_addr); ec->timestamp = jiffies; } @@ -394,17 +371,6 @@ static inline void acpi_ec_disable_gpe(struct acpi_ec *ec, bool close) } } -#ifdef CONFIG_ARCH_PHYTIUM -static void hwreduce_acpi_enable(struct acpi_ec *ec) -{ - base_ctrl_writeb(ec->command_addr, 0x86); -} -static void hwreduce_acpi_disable(struct acpi_ec *ec) -{ - base_ctrl_writeb(ec->command_addr, 0x87); -} -#endif - /* -------------------------------------------------------------------------- * Transaction Management * -------------------------------------------------------------------------- */ @@ -449,12 +415,9 @@ static void acpi_ec_unmask_events(struct acpi_ec *ec) clear_bit(EC_FLAGS_EVENTS_MASKED, &ec->flags); if (ec->gpe >= 0) acpi_ec_enable_gpe(ec, false); - else { - if (!phytium_check_cpu()) - enable_irq(ec->irq); - else if ((irq_to_desc(ec->irq))->depth > 0) - enable_irq(ec->irq); - } + else + enable_irq(ec->irq); + ec_dbg_drv("Polling disabled"); } } @@ -533,10 +496,6 @@ static inline void __acpi_ec_enable_event(struct acpi_ec *ec) * Unconditionally invoke this once after enabling the event * handling mechanism to detect the pending events. */ -#ifdef CONFIG_ARCH_PHYTIUM - if (phytium_check_cpu()) - hwreduce_acpi_enable(ec); -#endif advance_transaction(ec, false); } @@ -544,11 +503,6 @@ static inline void __acpi_ec_disable_event(struct acpi_ec *ec) { if (test_and_clear_bit(EC_FLAGS_QUERY_ENABLED, &ec->flags)) ec_log_drv("event blocked"); - -#ifdef CONFIG_ARCH_PHYTIUM - if (phytium_check_cpu()) - hwreduce_acpi_disable(ec); -#endif } /* @@ -2163,10 +2117,6 @@ static int acpi_ec_resume(struct device *dev) struct acpi_ec *ec = acpi_driver_data(to_acpi_device(dev)); -#ifdef CONFIG_ARCH_PHYTIUM - if (phytium_check_cpu()) - hwreduce_acpi_enable(ec); -#endif acpi_ec_enable_event(ec); return 0; } @@ -2180,7 +2130,7 @@ EXPORT_SYMBOL_GPL(acpi_ec_mark_gpe_for_wake); void acpi_ec_set_gpe_wake_mask(u8 action) { - if (!phytium_check_cpu() && pm_suspend_no_platform() && first_ec && !ec_no_wakeup) + if (pm_suspend_no_platform() && first_ec && !ec_no_wakeup) acpi_set_gpe_wake_mask(NULL, first_ec->gpe, action); } -- Gitee From f12c1673b01bbd5ca622435b6d0d480df2d23849 Mon Sep 17 00:00:00 2001 From: Li Yuze Date: Wed, 9 Apr 2025 17:25:06 +0800 Subject: [PATCH 012/155] Revert "i8042: Add support for phytium platforms" This reverts commit ea9e737e02ca1e45bad5eb2dc8fdc428c761ba10. Change-Id: If7a72119efbef18c6c637d75840e4d2b611189f2 --- drivers/input/serio/i8042-io.h | 24 ++++--------------- drivers/input/serio/i8042.c | 43 +++++++++++----------------------- 2 files changed, 19 insertions(+), 48 deletions(-) diff --git a/drivers/input/serio/i8042-io.h b/drivers/input/serio/i8042-io.h index 8dfb23df58..64590b86eb 100644 --- a/drivers/input/serio/i8042-io.h +++ b/drivers/input/serio/i8042-io.h @@ -2,9 +2,7 @@ #ifndef _I8042_IO_H #define _I8042_IO_H -#ifdef CONFIG_ARCH_PHYTIUM -#include "../../acpi/phytium_base_ctrl.h" -#endif + /* * Names. */ @@ -44,34 +42,22 @@ extern int of_i8042_aux_irq; static inline int i8042_read_data(void) { - if (phytium_check_cpu() == true) - return base_ctrl_readb(I8042_DATA_REG); - else - return inb(I8042_DATA_REG); + return inb(I8042_DATA_REG); } static inline int i8042_read_status(void) { - if (phytium_check_cpu() == true) - return base_ctrl_readb(I8042_STATUS_REG); - else - return inb(I8042_STATUS_REG); + return inb(I8042_STATUS_REG); } static inline void i8042_write_data(int val) { - if (phytium_check_cpu() == true) - base_ctrl_writeb(I8042_DATA_REG, val); - else - outb(val, I8042_DATA_REG); + outb(val, I8042_DATA_REG); } static inline void i8042_write_command(int val) { - if (phytium_check_cpu() == true) - base_ctrl_writeb(I8042_COMMAND_REG, val); - else - outb(val, I8042_COMMAND_REG); + outb(val, I8042_COMMAND_REG); } static inline int i8042_platform_init(void) diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index feff507a38..131988b6ad 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -536,9 +536,6 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id) spin_lock_irqsave(&i8042_lock, flags); - if (phytium_check_cpu() == true) - base_ctrl_write_int_clear(0x0); - str = i8042_read_status(); if (unlikely(~str & I8042_STR_OBF)) { spin_unlock_irqrestore(&i8042_lock, flags); @@ -1460,7 +1457,7 @@ static int i8042_setup_aux(void) int error; int i; - if (!phytium_check_cpu() && i8042_check_aux()) + if (i8042_check_aux()) return -ENODEV; if (i8042_nomux || i8042_check_mux()) { @@ -1477,12 +1474,10 @@ static int i8042_setup_aux(void) aux_enable = i8042_enable_mux_ports; } - if (!phytium_check_cpu()) { - error = request_irq(I8042_AUX_IRQ, i8042_interrupt, IRQF_SHARED, - "i8042", i8042_platform_device); - if (error) - goto err_free_ports; - } + error = request_irq(I8042_AUX_IRQ, i8042_interrupt, IRQF_SHARED, + "i8042", i8042_platform_device); + if (error) + goto err_free_ports; error = aux_enable(); if (error) @@ -1507,17 +1502,8 @@ static int i8042_setup_kbd(void) if (error) return error; - if (phytium_check_cpu() == true) { - error = phytium_base_ctrl_irq(); - if (error < 0) - goto err_free_port; - - error = devm_request_irq(&i8042_platform_device->dev, error, - i8042_interrupt, IRQF_SHARED, "i8042", i8042_platform_device); - } else { - error = request_irq(I8042_KBD_IRQ, i8042_interrupt, IRQF_SHARED, - "i8042", i8042_platform_device); - } + error = request_irq(I8042_KBD_IRQ, i8042_interrupt, IRQF_SHARED, + "i8042", i8042_platform_device); if (error) goto err_free_port; @@ -1634,15 +1620,14 @@ static int __init i8042_init(void) dbg_init(); - if (!phytium_check_cpu()) { - err = i8042_platform_init(); - if (err) - return (err == -ENODEV) ? 0 : err; + err = i8042_platform_init(); + if (err) + return (err == -ENODEV) ? 0 : err; + + err = i8042_controller_check(); + if (err) + goto err_platform_exit; - err = i8042_controller_check(); - if (err) - goto err_platform_exit; - } /* Set this before creating the dev to allow i8042_command to work right away */ i8042_present = true; -- Gitee From 075e29d94d7978b6eaa81191bc1cf91c8835de0c Mon Sep 17 00:00:00 2001 From: zhouyulin1283 Date: Wed, 13 Aug 2025 11:25:55 +0800 Subject: [PATCH 013/155] Revert "Base_ctrl: phytium: Add driver for base controller" This reverts commit 9ffc16e3d6e60792fe9848e8eee751f78f92647f. --- MAINTAINERS | 1 - drivers/acpi/Kconfig | 7 ------- drivers/acpi/Makefile | 1 - drivers/acpi/phytium_base_ctrl.h | 27 --------------------------- 4 files changed, 36 deletions(-) delete mode 100644 drivers/acpi/phytium_base_ctrl.h diff --git a/MAINTAINERS b/MAINTAINERS index b01b0bec4a..3563cf2775 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -17477,7 +17477,6 @@ F: Documentation/devicetree/bindings/staging/phytium-npu.yaml F: arch/arm64/boot/dts/phytium/* F: arch/arm64/include/asm/ras.h F: arch/arm64/kernel/ras.c -F: drivers/acpi/phytium_base_ctrl.c F: drivers/char/hw_random/phytium-rng.c F: drivers/char/ipmi/bt_bmc_phytium.c F: drivers/char/ipmi/kcs_bmc_phytium.c diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 48e7d00bac..cee82b473d 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -45,13 +45,6 @@ if ACPI config ACPI_LEGACY_TABLES_LOOKUP bool -config PHYTIUM_BASE_CTRL - bool "Phytium base ctrl driver" - default y - help - This driver provides interface functions for reading and - writing phytium base controller device address. - config ARCH_MIGHT_HAVE_ACPI_PDC bool diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index e483aa370c..eaa09bf52f 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -42,7 +42,6 @@ acpi-y += resource.o acpi-y += acpi_processor.o acpi-y += processor_core.o acpi-$(CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC) += processor_pdc.o -acpi-$(CONFIG_PHYTIUM_BASE_CTRL) += phytium_base_ctrl.o acpi-y += ec.o acpi-$(CONFIG_ACPI_DOCK) += dock.o acpi-$(CONFIG_PCI) += pci_root.o pci_link.o pci_irq.o diff --git a/drivers/acpi/phytium_base_ctrl.h b/drivers/acpi/phytium_base_ctrl.h deleted file mode 100644 index 017f21e5ac..0000000000 --- a/drivers/acpi/phytium_base_ctrl.h +++ /dev/null @@ -1,27 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * acpi/phytium_base_ctrl.h - * - * Copyright (C) 2021-2024, Phytium Technology Co., Ltd. - */ - -#define base_ctrl_INT_STATE 0x7FFFFC4 -#define base_ctrl_CLR_INT 0x7FFFFC0 - -struct phytium_base_ctrl { - struct device *dev; - void __iomem *base; - int irq; - spinlock_t lock; - u32 int_status_reg; - u32 int_clear_reg; -}; - -int phytium_base_ctrl_irq(void); -u8 base_ctrl_readb(unsigned long offset); -u32 base_ctrl_readl(unsigned long offset); -bool phytium_check_cpu(void); -int base_ctrl_writeb(unsigned long offset, u8 value); -int base_ctrl_writel(unsigned long offset, u32 value); -int base_ctrl_read_int_status(void); -void base_ctrl_write_int_clear(int val); -- Gitee From 671052bc5a8aad082dbc2ea1adcf84a6c7b0d01c Mon Sep 17 00:00:00 2001 From: Feng Jun Date: Wed, 9 Apr 2025 17:51:05 +0800 Subject: [PATCH 014/155] bus: phytium-pio: Add support for legacy I/O operation This Phytium PIO controller driver makes it possible for Socs to access legacy I/O ports. Mainline: NA Signed-off-by: Feng Jun Signed-off-by: Wang Yinfeng Change-Id: I36b772864ebe56dfb744c5327d96e4fe7c73283e --- MAINTAINERS | 1 + drivers/bus/Kconfig | 9 ++ drivers/bus/Makefile | 1 + drivers/bus/phytium_pio.c | 264 ++++++++++++++++++++++++++++++++++++++ drivers/bus/phytium_pio.h | 33 +++++ lib/logic_pio.c | 20 ++- 6 files changed, 326 insertions(+), 2 deletions(-) create mode 100644 drivers/bus/phytium_pio.c create mode 100644 drivers/bus/phytium_pio.h diff --git a/MAINTAINERS b/MAINTAINERS index 3563cf2775..bce049f85f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -17477,6 +17477,7 @@ F: Documentation/devicetree/bindings/staging/phytium-npu.yaml F: arch/arm64/boot/dts/phytium/* F: arch/arm64/include/asm/ras.h F: arch/arm64/kernel/ras.c +F: drivers/bus/phytium_pio.c F: drivers/char/hw_random/phytium-rng.c F: drivers/char/ipmi/bt_bmc_phytium.c F: drivers/char/ipmi/kcs_bmc_phytium.c diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig index fab27506d9..e34e7ab4c2 100644 --- a/drivers/bus/Kconfig +++ b/drivers/bus/Kconfig @@ -142,6 +142,15 @@ config OMAP_OCP2SCP OCP2SCP and in OMAP5, both USB PHY and SATA PHY is connected via OCP2SCP. +config PHYTIUM_PIO + bool "Support for ISA I/O space on Phytium SoCs" + depends on (ARM64 && ARCH_PHYTIUM) + depends on HAS_IOMEM + select INDIRECT_PIO if ARM64 + help + Driver to enable I/O access to devices attached to the Legacy IO ports + on the Phytium SoCs. + config QCOM_EBI2 bool "Qualcomm External Bus Interface 2 (EBI2)" depends on HAS_IOMEM diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile index d90eed189a..89aec3e3ae 100644 --- a/drivers/bus/Makefile +++ b/drivers/bus/Makefile @@ -6,6 +6,7 @@ # Interconnect bus drivers for ARM platforms obj-$(CONFIG_ARM_CCI) += arm-cci.o obj-$(CONFIG_ARM_INTEGRATOR_LM) += arm-integrator-lm.o +obj-$(CONFIG_PHYTIUM_PIO) += phytium_pio.o obj-$(CONFIG_HISILICON_LPC) += hisi_lpc.o obj-$(CONFIG_BRCMSTB_GISB_ARB) += brcmstb_gisb.o obj-$(CONFIG_MOXTET) += moxtet.o diff --git a/drivers/bus/phytium_pio.c b/drivers/bus/phytium_pio.c new file mode 100644 index 0000000000..6dd42798f3 --- /dev/null +++ b/drivers/bus/phytium_pio.c @@ -0,0 +1,264 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Phytium PIO driver + * + * Copyright (C) 2024 Phytium Technology Co., Ltd. All Rights Reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "phytium_pio.h" + +#define PHYT_PIO_DRIVER_NAME "phytium-pio" +#define PHYT_PIO_DRV_VER "1.1.0" + +static struct phytium_pio *ppio; + +bool check_cpu_type(void) +{ + if (read_cpuid_implementor() == ARM_CPU_IMP_PHYTIUM) + return true; + return false; +} +EXPORT_SYMBOL(check_cpu_type); + +void phytium_pio_clear_interrupt(u32 val) +{ + unsigned long flags; + + if (!ppio) + return; + spin_lock_irqsave(&ppio->lock, flags); + writew(val, ppio->membase + PHYTIUM_PIO_CLR_INT); + spin_unlock_irqrestore(&ppio->lock, flags); +} +EXPORT_SYMBOL(phytium_pio_clear_interrupt); + +int phytium_pio_get_irq(void) +{ + if (!ppio) + return -EINVAL; + return ppio->irq; +} +EXPORT_SYMBOL(phytium_pio_get_irq); + +/* + * phytium_pio_in - input the data from the target I/O port + * @hostdata: pointer to the device information relevant to PIO controller + * @addr: the target I/O port address + * @dwidth: the data width required reading from the target I/O port + * + * Return the data read back on success, -ERRNO otherwise. + */ +static u32 phytium_pio_in(void *hostdata, unsigned long addr, size_t dwidth) +{ + struct phytium_pio *pio = hostdata; + struct logic_pio_hwaddr *range = pio->range; + __le32 rd_data = 0; + unsigned long flags; + + spin_lock_irqsave(&pio->lock, flags); + switch (dwidth) { + case 1: + rd_data = readb(pio->membase + addr - range->io_start); + break; + case 2: + rd_data = readw(pio->membase + addr - range->io_start); + break; + case 4: + rd_data = readl(pio->membase + addr - range->io_start); + break; + default: + break; + } + spin_unlock_irqrestore(&pio->lock, flags); + return le32_to_cpu(rd_data); +} + +/* + * phytium_pio_out - output the data to the target I/O port + * @hostdata: pointer to the device information relevant to PIO controller + * @addr: the target I/O port address + * @val: the data to be output + * @dwidth: the data width required writing to the target I/O port + */ +static void phytium_pio_out(void *hostdata, unsigned long addr, u32 val, + size_t dwidth) +{ + struct phytium_pio *pio = hostdata; + struct logic_pio_hwaddr *range = pio->range; + unsigned long flags; + + spin_lock_irqsave(&pio->lock, flags); + switch (dwidth) { + case 1: + writeb(val, pio->membase + addr - range->io_start); + break; + case 2: + writew(val, pio->membase + addr - range->io_start); + break; + case 4: + writel(val, pio->membase + addr - range->io_start); + break; + default: + break; + } + spin_unlock_irqrestore(&pio->lock, flags); +} + +/* + * phytium_pio_ins - input the data in the buffer in multiple operations + * @hostdata: pointer to the device information relevant to PIO controller + * @pio: the target I/O port address + * @buffer: the buffer to store the data + * @dwidth: the data width required reading from the target I/O port + * @count: the number of data to be read + * + * When success, the data read back is stored in buffer pointed by buffer. + * Return 0 on success, -ERRNO otherwise. + */ +static u32 phytium_pio_ins(void *hostdata, unsigned long addr, void *buffer, + size_t dwidth, unsigned int count) +{ + struct phytium_pio *pio = hostdata; + unsigned char *buf = buffer; + + if (!pio || !buf || !count || !dwidth || dwidth > 4) + return -EINVAL; + + do { + *(u32 *)buf = phytium_pio_in(pio, addr, dwidth); + buf += dwidth; + addr += dwidth; + } while (--count); + + return 0; +} + +/* + * phytium_pio_outs - output the data in the buffer in multiple operations + * @hostdata: pointer to the device information relevant to PIO controller + * @addr: the target I/O port address + * @buffer: the buffer to store the data + * @dwidth: the data width required writing to the target I/O port + * @count: the number of data to be written + */ +static void phytium_pio_outs(void *hostdata, unsigned long addr, + const void *buffer, size_t dwidth, unsigned int count) +{ + struct phytium_pio *pio = hostdata; + const unsigned char *buf = buffer; + + if (!pio || !buf || !count || !dwidth || dwidth > 4) + return; + + do { + phytium_pio_out(pio, addr, *(u32 *)buf, dwidth); + buf += dwidth; + addr += dwidth; + } while (--count); +} + +static const struct logic_pio_host_ops phytium_pio_ops = { + .in = phytium_pio_in, + .ins = phytium_pio_ins, + .out = phytium_pio_out, + .outs = phytium_pio_outs, +}; + +static int phytium_pio_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct logic_pio_hwaddr *range; + struct phytium_pio *pio; + int ret; + + pio = devm_kzalloc(dev, sizeof(*pio), GFP_KERNEL); + if (!pio) + return -ENOMEM; + pio->membase = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR_OR_NULL(pio->membase)) + return PTR_ERR(pio->membase); + + pio->irq = platform_get_irq(pdev, 0); + if (pio->irq < 0) { + dev_err(dev, "no irq resource?\n"); + return pio->irq; + } + + ret = device_property_read_u32(&pdev->dev, "int_state", + &pio->int_status_reg); + if (ret) + pio->int_status_reg = PHYTIUM_PIO_INT_STATE; + + ret = device_property_read_u32(&pdev->dev, "clr_int", + &pio->int_clear_reg); + if (ret) + pio->int_clear_reg = PHYTIUM_PIO_CLR_INT; + + range = devm_kzalloc(dev, sizeof(*range), GFP_KERNEL); + if (!range) + return -ENOMEM; + range->fwnode = dev_fwnode(dev); + range->flags = LOGIC_PIO_INDIRECT; + range->size = PIO_INDIRECT_SIZE; + range->hostdata = pio; + range->ops = &phytium_pio_ops; + pio->range = range; + ppio = pio; + ret = logic_pio_register_range(range); + if (ret) { + dev_err(dev, "Failed to register logic pio range (%d)!\n", ret); + goto out; + } + spin_lock_init(&pio->lock); + dev_set_drvdata(dev, pio); +out: + return ret; +} + +static int phytium_pio_remove(struct platform_device *pdev) +{ + struct logic_pio_hwaddr *range; + + range = find_io_range_by_fwnode(pdev->dev.fwnode); + if (!range) + return -EINVAL; + + logic_pio_unregister_range(range); + + return 0; +} + +static const struct acpi_device_id phytium_pio_acpi_match[] = { + { "PHYT0007", }, + {}, +}; +MODULE_DEVICE_TABLE(acpi, phytium_pio_acpi_match); + +static struct platform_driver phytium_pio_driver = { + .driver = { + .name = PHYT_PIO_DRIVER_NAME, + .acpi_match_table = ACPI_PTR(phytium_pio_acpi_match), + }, + .probe = phytium_pio_probe, + .remove = phytium_pio_remove, +}; + + +static int __init phytium_pio_init(void) +{ + return platform_driver_register(&phytium_pio_driver); +} +arch_initcall(phytium_pio_init); + +MODULE_DESCRIPTION("Phytium pio driver"); +MODULE_VERSION(PHYT_PIO_DRV_VER); +MODULE_LICENSE("GPL"); + diff --git a/drivers/bus/phytium_pio.h b/drivers/bus/phytium_pio.h new file mode 100644 index 0000000000..5e22687627 --- /dev/null +++ b/drivers/bus/phytium_pio.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * bus/phytium_pio.h + * + * Copyright (C) 2021-2025, Phytium Technology Co., Ltd. + */ + +#ifndef _PHYTIUM_PIO_H_ +#define _PHYTIUM_PIO_H_ + +#include +#include + +#define PHYTIUM_PIO_INT_STATE 0x7FFFFC4 +#define PHYTIUM_PIO_CLR_INT 0x7FFFFC0 +#define LEGACY_ISA_SIZE 0x400 + +struct phytium_pio { + void __iomem *membase; + int irq; + spinlock_t lock; + u32 int_status_reg; + u32 int_clear_reg; + struct logic_pio_hwaddr *range; +}; + +bool check_cpu_type(void); +int phytium_pio_get_irq(void); +void phytium_pio_clear_interrupt(u32 val); + +#endif + + diff --git a/lib/logic_pio.c b/lib/logic_pio.c index 2ea564a400..b8b7b1ba61 100644 --- a/lib/logic_pio.c +++ b/lib/logic_pio.c @@ -16,6 +16,14 @@ #include #include +#ifdef CONFIG_PHYTIUM_PIO +#include "../drivers/bus/phytium_pio.h" +#endif + +__weak bool check_cpu_type(void) +{ + return false; +} /* The unique hardware address list */ static LIST_HEAD(io_range_list); static DEFINE_MUTEX(io_range_mutex); @@ -234,6 +242,8 @@ type logic_in##bwl(unsigned long addr) \ { \ type ret = (type)~0; \ \ + if (check_cpu_type() == true) \ + addr += MMIO_UPPER_LIMIT; \ if (addr < MMIO_UPPER_LIMIT) { \ ret = _in##bwl(addr); \ } else if (addr >= MMIO_UPPER_LIMIT && addr < IO_SPACE_LIMIT) { \ @@ -242,14 +252,20 @@ type logic_in##bwl(unsigned long addr) \ if (entry) \ ret = entry->ops->in(entry->hostdata, \ addr, sizeof(type)); \ - else \ - WARN_ON_ONCE(1); \ + else { \ + if (check_cpu_type() == true) \ + ret = 1; \ + else \ + WARN_ON_ONCE(1); \ + } \ } \ return ret; \ } \ \ void logic_out##bwl(type value, unsigned long addr) \ { \ + if (check_cpu_type() == true) \ + addr += MMIO_UPPER_LIMIT; \ if (addr < MMIO_UPPER_LIMIT) { \ _out##bwl(value, addr); \ } else if (addr >= MMIO_UPPER_LIMIT && addr < IO_SPACE_LIMIT) { \ -- Gitee From c9026b02736e348668f119d1ec0f4eddf1f41be9 Mon Sep 17 00:00:00 2001 From: Feng Jun Date: Wed, 9 Apr 2025 18:03:00 +0800 Subject: [PATCH 015/155] Input: i8042: Add i8042 driver support for phytium SoCs This patch restores i8042 legacy access of I/O ports for phytium SoCs. Mainline: NA Signed-off-by: Feng Jun Signed-off-by: Wang Yinfeng Change-Id: I780be71e87d70febc3f96f8d1045f5e82d5a939f --- drivers/input/serio/i8042.c | 64 ++++++++++++++++++++++++++++++++++--- 1 file changed, 60 insertions(+), 4 deletions(-) diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index 131988b6ad..a6aacb6ac5 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -22,7 +22,9 @@ #include #include #include - +#if defined(CONFIG_PHYTIUM_PIO) +#include "../../bus/phytium_pio.h" +#endif #include MODULE_AUTHOR("Vojtech Pavlik "); @@ -535,7 +537,10 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id) int ret = 1; spin_lock_irqsave(&i8042_lock, flags); - +#if defined(CONFIG_PHYTIUM_PIO) + if (check_cpu_type() == true) + phytium_pio_clear_interrupt(0x0); +#endif str = i8042_read_status(); if (unlikely(~str & I8042_STR_OBF)) { spin_unlock_irqrestore(&i8042_lock, flags); @@ -1494,6 +1499,43 @@ static int i8042_setup_aux(void) return error; } +#if defined(CONFIG_PHYTIUM_PIO) +static int phytium_i8042_setup_kbd(void) +{ + int error; + int kbd_irq_num; + + if (i8042_nokbd) { + i8042_register_ports(); + return 0; + } + error = i8042_create_kbd_port(); + if (error) + return error; + + kbd_irq_num = phytium_pio_get_irq(); + if (kbd_irq_num < 0) { + error = -EINVAL; + goto err_free_port; + } + error = devm_request_irq(&i8042_platform_device->dev, kbd_irq_num, + i8042_interrupt, IRQF_SHARED, "i8042", i8042_platform_device); + if (error) + goto err_free_port; + error = i8042_enable_kbd_port(); + if (error) + goto err_free_port; + + i8042_register_ports(); + return 0; + + err_free_port: + i8042_free_kbd_port(); + i8042_controller_reset(false); + + return error; +} +#endif static int i8042_setup_kbd(void) { int error; @@ -1562,7 +1604,10 @@ static int i8042_probe(struct platform_device *dev) if (i8042_dritek) i8042_dritek_enable(); #endif - +#if defined(CONFIG_PHYTIUM_PIO) + if (check_cpu_type() == true) + return phytium_i8042_setup_kbd(); +#endif if (!i8042_noaux) { error = i8042_setup_aux(); if (error && error != -ENODEV && error != -EBUSY) @@ -1619,7 +1664,17 @@ static int __init i8042_init(void) int err; dbg_init(); - +#if defined(CONFIG_PHYTIUM_PIO) + if (!check_cpu_type()) { + err = i8042_platform_init(); + if (err) + return (err == -ENODEV) ? 0 : err; + + err = i8042_controller_check(); + if (err) + goto err_platform_exit; + } +#else err = i8042_platform_init(); if (err) return (err == -ENODEV) ? 0 : err; @@ -1628,6 +1683,7 @@ static int __init i8042_init(void) if (err) goto err_platform_exit; +#endif /* Set this before creating the dev to allow i8042_command to work right away */ i8042_present = true; -- Gitee From 1b02bf7b08ef38b5a1f516b571589939382fbfd5 Mon Sep 17 00:00:00 2001 From: Tang Jiemin Date: Thu, 24 Apr 2025 13:54:44 +0800 Subject: [PATCH 016/155] mmu_notifiers: Add a new callback in __flush_tlb_range It is necessary to obtain the accurate address for Duptext tools in the __flush_tlb_range function. However, the address of flush_tlb_mm is from 0 to -1, so we have added the callback with the accurate address here. Mainline: Open-Source Signed-off-by: Tang Jiemin Signed-off-by: Wang Yinfeng Change-Id: I62a88f81d0f39721a43f6ec0dfb72840b804d9f8 --- arch/arm64/include/asm/tlbflush.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm64/include/asm/tlbflush.h b/arch/arm64/include/asm/tlbflush.h index b73baaf8ae..1b7fb0ea9e 100644 --- a/arch/arm64/include/asm/tlbflush.h +++ b/arch/arm64/include/asm/tlbflush.h @@ -423,6 +423,9 @@ static inline void __flush_tlb_range(struct vm_area_struct *vma, (end - start) >= (MAX_TLBI_OPS * stride)) || pages >= MAX_TLBI_RANGE_PAGES) { flush_tlb_mm(vma->vm_mm); +#ifdef CONFIG_ARCH_PHYTIUM + mmu_notifier_arch_invalidate_secondary_tlbs(vma->vm_mm, start, end); +#endif return; } -- Gitee From 2f89ba486dbe593d0d739859175f570884c0164d Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 16 Dec 2024 14:20:56 +0100 Subject: [PATCH 017/155] sched/core: Prevent rescheduling when interrupts are disabled David reported a warning observed while loop testing kexec jump: Interrupts enabled after irqrouter_resume+0x0/0x50 WARNING: CPU: 0 PID: 560 at drivers/base/syscore.c:103 syscore_resume+0x18a/0x220 kernel_kexec+0xf6/0x180 __do_sys_reboot+0x206/0x250 do_syscall_64+0x95/0x180 The corresponding interrupt flag trace: hardirqs last enabled at (15573): [] __up_console_sem+0x7e/0x90 hardirqs last disabled at (15580): [] __up_console_sem+0x63/0x90 That means __up_console_sem() was invoked with interrupts enabled. Further instrumentation revealed that in the interrupt disabled section of kexec jump one of the syscore_suspend() callbacks woke up a task, which set the NEED_RESCHED flag. A later callback in the resume path invoked cond_resched() which in turn led to the invocation of the scheduler: __cond_resched+0x21/0x60 down_timeout+0x18/0x60 acpi_os_wait_semaphore+0x4c/0x80 acpi_ut_acquire_mutex+0x3d/0x100 acpi_ns_get_node+0x27/0x60 acpi_ns_evaluate+0x1cb/0x2d0 acpi_rs_set_srs_method_data+0x156/0x190 acpi_pci_link_set+0x11c/0x290 irqrouter_resume+0x54/0x60 syscore_resume+0x6a/0x200 kernel_kexec+0x145/0x1c0 __do_sys_reboot+0xeb/0x240 do_syscall_64+0x95/0x180 This is a long standing problem, which probably got more visible with the recent printk changes. Something does a task wakeup and the scheduler sets the NEED_RESCHED flag. cond_resched() sees it set and invokes schedule() from a completely bogus context. The scheduler enables interrupts after context switching, which causes the above warning at the end. Quite some of the code paths in syscore_suspend()/resume() can result in triggering a wakeup with the exactly same consequences. They might not have done so yet, but as they share a lot of code with normal operations it's just a question of time. The problem only affects the PREEMPT_NONE and PREEMPT_VOLUNTARY scheduling models. Full preemption is not affected as cond_resched() is disabled and the preemption check preemptible() takes the interrupt disabled flag into account. Cure the problem by adding a corresponding check into cond_resched(). Reported-by: David Woodhouse Suggested-by: Peter Zijlstra Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar Tested-by: David Woodhouse Cc: Linus Torvalds Cc: stable@vger.kernel.org Closes: https://lore.kernel.org/all/7717fe2ac0ce5f0a2c43fdab8b11f4483d54a2a4.camel@infradead.org Signed-off-by: Huang Shaobo Signed-off-by: Wang Yinfeng Change-Id: I71123973947371bae8c8b69035ec52d910bca85f --- kernel/sched/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/sched/core.c b/kernel/sched/core.c index b6f922a20f..39afffe9ae 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -8561,7 +8561,7 @@ SYSCALL_DEFINE0(sched_yield) #if !defined(CONFIG_PREEMPTION) || defined(CONFIG_PREEMPT_DYNAMIC) int __sched __cond_resched(void) { - if (should_resched(0)) { + if (should_resched(0) && !irqs_disabled()) { preempt_schedule_common(); return 1; } -- Gitee From c6313ef3083912c3f36cada080d4643c6ee17284 Mon Sep 17 00:00:00 2001 From: Peng Min Date: Mon, 10 Mar 2025 17:11:48 +0800 Subject: [PATCH 018/155] ras: phytium: Identify and report Phytium custom errors Identify the section type of the Phytium Error Record and print information about the associated error register. Mainline: Open-Source Signed-off-by: Peng Min Signed-off-by: Wang Yinfeng Change-Id: I55b2e294f3e067bf728107379052b1d2c7c1bad7 --- drivers/acpi/apei/ghes.c | 6 ++++++ drivers/firmware/efi/cper.c | 42 +++++++++++++++++++++++++++++++++++++ drivers/ras/ras.c | 11 ++++++++++ include/linux/cper.h | 18 ++++++++++++++++ include/linux/ras.h | 3 +++ include/ras/ras_event.h | 33 +++++++++++++++++++++++++++++ 6 files changed, 113 insertions(+) diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index 2a7aa5e878..73580a6b71 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c @@ -714,6 +714,12 @@ static bool ghes_do_proc(struct ghes *ghes, } else if (guid_equal(sec_type, &CPER_SEC_PROC_ARM)) { queued = ghes_handle_arm_hw_error(gdata, sev, sync); + } else if (guid_equal(sec_type, &CPER_SEC_PHYT_ERR)) { + struct cper_sec_phyt_err *phyt = acpi_hest_get_payload(gdata); + int sec_sev; + + sec_sev = ghes_severity(gdata->error_severity); + log_phyt_err_event(phyt, sec_sev); } else { void *err = acpi_hest_get_payload(gdata); diff --git a/drivers/firmware/efi/cper.c b/drivers/firmware/efi/cper.c index 35c37f6677..9f203034e1 100644 --- a/drivers/firmware/efi/cper.c +++ b/drivers/firmware/efi/cper.c @@ -26,6 +26,10 @@ #include #include "cper_cxl.h" +#ifndef PHYT_ERR_OTHER +#define PHYT_ERR_OTHER 0xff +#endif + /* * CPER record ID need to be unique even after reboot, because record * ID is used as index for ERST storage, while CPER records from @@ -502,6 +506,36 @@ static void cper_print_fw_err(const char *pfx, print_hex_dump(pfx, "", DUMP_PREFIX_OFFSET, 16, 4, buf, length, true); } +static const char * const phyt_err_type_strs[] = { + "Core", + "L3C", + "LSD", + "SMMU", + "GIC", + "DDR", + "PCIE", + "C2C", +}; + +static void cper_print_phyt_err(const char *pfx, + const struct cper_sec_phyt_err *phyt) +{ + if (phyt->type == PHYT_ERR_OTHER) + pr_err("%sPhytium Error Record Type: %s\n", pfx, "Other"); + else + pr_err("%sPhytium Error Record Type: %s\n", pfx, + phyt->type < ARRAY_SIZE(phyt_err_type_strs) ? + phyt_err_type_strs[phyt->type] : "unknown"); + pr_err("%sSubtype: %d\n", pfx, phyt->subtype); + pr_err("%sID: 0x%x\n", pfx, phyt->id); + pr_err("%sError Status: 0x%x\n", pfx, phyt->error_status); + pr_err("%sPhysical Address: 0x%llx\n", pfx, phyt->phys_address); + pr_err("%sMISC0: 0x%llx\n", pfx, phyt->misc0); + pr_err("%sMISC1: 0x%llx\n", pfx, phyt->misc1); + pr_err("%sMISC2: 0x%llx\n", pfx, phyt->misc2); + pr_err("%sMISC3: 0x%llx\n", pfx, phyt->misc3); +} + static void cper_print_tstamp(const char *pfx, struct acpi_hest_generic_data_v300 *gdata) { @@ -607,6 +641,14 @@ cper_estatus_print_section(const char *pfx, struct acpi_hest_generic_data *gdata cper_print_prot_err(newpfx, prot_err); else goto err_section_too_small; + } else if (guid_equal(sec_type, &CPER_SEC_PHYT_ERR)) { + struct cper_sec_phyt_err *phyt_err = acpi_hest_get_payload(gdata); + + pr_err("%ssection_type: Phytium Error Record\n", newpfx); + if (gdata->error_data_length >= sizeof(*phyt_err)) + cper_print_phyt_err(newpfx, phyt_err); + else + goto err_section_too_small; } else { const void *err = acpi_hest_get_payload(gdata); diff --git a/drivers/ras/ras.c b/drivers/ras/ras.c index e8094b9317..c590e0b22f 100644 --- a/drivers/ras/ras.c +++ b/drivers/ras/ras.c @@ -70,6 +70,16 @@ void log_arm_hw_error(struct cper_sec_proc_arm *err, const u8 sev) ven_err_data, vsei_len, sev, cpu); } +void log_phyt_err_event(struct cper_sec_phyt_err *err, const u8 sev) +{ + u32 phyt_len; + u8 *phyt; + + phyt_len = sizeof(struct cper_sec_phyt_err); + phyt = (u8 *)err; + trace_phyt_err_event(phyt_len, phyt, sev); +} + static int __init ras_init(void) { int rc = 0; @@ -87,6 +97,7 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(extlog_mem_event); EXPORT_TRACEPOINT_SYMBOL_GPL(mc_event); EXPORT_TRACEPOINT_SYMBOL_GPL(non_standard_event); EXPORT_TRACEPOINT_SYMBOL_GPL(arm_event); +EXPORT_TRACEPOINT_SYMBOL_GPL(phyt_err_event); static int __init parse_ras_param(char *str) { diff --git a/include/linux/cper.h b/include/linux/cper.h index c1a7dc3251..a053d52c70 100644 --- a/include/linux/cper.h +++ b/include/linux/cper.h @@ -198,6 +198,11 @@ enum { GUID_INIT(0x036F84E1, 0x7F37, 0x428c, 0xA7, 0x9E, 0x57, 0x5F, \ 0xDF, 0xAA, 0x84, 0xEC) +/* Phytium Error Record */ +#define CPER_SEC_PHYT_ERR \ + GUID_INIT(0x253C8E21, 0xB0B5, 0x4B1A, 0x8C, 0x45, 0x5A, 0x0F, \ + 0x5C, 0x06, 0x69, 0x8D) + #define CPER_PROC_VALID_TYPE 0x0001 #define CPER_PROC_VALID_ISA 0x0002 #define CPER_PROC_VALID_ERROR_TYPE 0x0004 @@ -550,6 +555,19 @@ struct cper_sec_fw_err_rec_ref { guid_t record_identifier_guid; }; +/* Phytium Error Record, Phytium RAS V1.1 */ +struct cper_sec_phyt_err { + u8 type; + u8 subtype; + u16 id; + u32 error_status; + u64 phys_address; + u64 misc0; + u64 misc1; + u64 misc2; + u64 misc3; +}; + /* Reset to default packing */ #pragma pack() diff --git a/include/linux/ras.h b/include/linux/ras.h index f695e7e760..d138d537a5 100644 --- a/include/linux/ras.h +++ b/include/linux/ras.h @@ -25,6 +25,7 @@ void log_non_standard_event(const guid_t *sec_type, const guid_t *fru_id, const char *fru_text, const u8 sev, const u8 *err, const u32 len); void log_arm_hw_error(struct cper_sec_proc_arm *err, const u8 sev); +void log_phyt_err_event(struct cper_sec_phyt_err *err, const u8 sev); #else static inline void log_non_standard_event(const guid_t *sec_type, @@ -33,6 +34,8 @@ log_non_standard_event(const guid_t *sec_type, { return; } static inline void log_arm_hw_error(struct cper_sec_proc_arm *err, const u8 sev) { return; } +static inline void +log_phyt_err_event(struct cper_sec_phyt_err *err, const u8 sev) { return; } #endif #if defined(CONFIG_ARM) || defined(CONFIG_ARM64) diff --git a/include/ras/ras_event.h b/include/ras/ras_event.h index 417c7fb994..ca05802a86 100644 --- a/include/ras/ras_event.h +++ b/include/ras/ras_event.h @@ -460,6 +460,39 @@ TRACE_EVENT(memory_failure_event, ) ); #endif /* CONFIG_MEMORY_FAILURE */ + +/* + * Phytium Error Section Report + * + * This event is Phytium Error Record event. + * + */ +#define PHYTERR "Phytium Error Record" +TRACE_EVENT(phyt_err_event, + + TP_PROTO(u32 phyt_len, + u8 *phyt, + u8 sev), + + TP_ARGS(phyt_len, phyt, sev), + + TP_STRUCT__entry( + __field(u32, phyt_len) + __dynamic_array(u8, buf, phyt_len) + __field(u8, sev) + ), + + TP_fast_assign( + __entry->phyt_len = phyt_len; + memcpy(__get_dynamic_array(buf), phyt, phyt_len); + __entry->sev = sev; + ), + + TP_printk("%s: %s", + PHYTERR, + __print_hex(__get_dynamic_array(buf), __entry->phyt_len)) +); + #endif /* _TRACE_HW_EVENT_MC_H */ /* This part must be outside protection */ -- Gitee From 4106cc7f13e4ebd57a9f1eb505026c631c0fc246 Mon Sep 17 00:00:00 2001 From: Xiao Cong Date: Fri, 9 May 2025 17:14:52 +0800 Subject: [PATCH 019/155] arm64: Add phytium PS24080 SoC platform judgement This patch adds PS24080 SoC platform judgement according to MIDR encoding for FTC862 cores and its SoC ID. Mainline: NA Signed-off-by: Xiao Cong Signed-off-by: Wang Yinfeng Change-Id: I495bcd504f0e385e5b7a60f22fd5f77a6941e0f9 --- arch/arm64/include/asm/cputype.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h index 9cf44f567f..a3097136f9 100644 --- a/arch/arm64/include/asm/cputype.h +++ b/arch/arm64/include/asm/cputype.h @@ -155,6 +155,9 @@ #define PHYTIUM_CPU_PART_FTC662 0x662 #define PHYTIUM_CPU_PART_FTC663 0x663 #define PHYTIUM_CPU_PART_FTC664 0x664 +#define PHYTIUM_CPU_PART_FTC862 0x862 + +#define PHYTIUM_CPU_SOCID_PS24080 0x6 #define MIDR_CORTEX_A53 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A53) #define MIDR_CORTEX_A57 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A57) @@ -229,6 +232,8 @@ #define MIDR_PHYTIUM_PS17064 MIDR_CPU_MODEL(ARM_CPU_IMP_PHYTIUM, PHYTIUM_CPU_PART_FTC662) #define MIDR_PHYTIUM_FTC663 MIDR_CPU_MODEL(ARM_CPU_IMP_PHYTIUM, PHYTIUM_CPU_PART_FTC663) #define MIDR_PHYTIUM_FTC664 MIDR_CPU_MODEL(ARM_CPU_IMP_PHYTIUM, PHYTIUM_CPU_PART_FTC664) +#define MIDR_PHYTIUM_FTC862 MIDR_CPU_MODEL(ARM_CPU_IMP_PHYTIUM, PHYTIUM_CPU_PART_FTC862) + #define MIDR_AMPERE1A MIDR_CPU_MODEL(ARM_CPU_IMP_AMPERE, AMPERE_CPU_PART_AMPERE1A) #define MIDR_MICROSOFT_AZURE_COBALT_100 MIDR_CPU_MODEL(ARM_CPU_IMP_MICROSOFT, MICROSOFT_CPU_PART_AZURE_COBALT_100) -- Gitee From acffbb3be00b49eecf1bfe91984c85f65f4ca326 Mon Sep 17 00:00:00 2001 From: Xiao Cong Date: Fri, 9 May 2025 17:27:39 +0800 Subject: [PATCH 020/155] iommu: smmuv3: Not print information of SMMU 0x10 event In the Phytium PS24080 SoC platforms, when SMMU event type is 0x10 and the fault translate address is 0x0, we skip this error informfation. Due to our RC controller's inability to fully handle the MCTP protocol. Mainline: NA Signed-off-by: Xiao Cong Signed-off-by: Wang Yinfeng Change-Id: I508a5e2cfc2b5ecbe94b21e1d95ebdaaf70b1d2b --- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 11 +++++++++++ drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 2 ++ 2 files changed, 13 insertions(+) diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c index aeb8880964..d4888c7ef3 100644 --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c @@ -1613,6 +1613,17 @@ static irqreturn_t arm_smmu_evtq_thread(int irq, void *dev) ret = arm_smmu_handle_evt(smmu, evt); if (!ret || !__ratelimit(&rs)) continue; +#ifdef CONFIG_ARCH_PHYTIUM + if (read_cpuid_id() == MIDR_PHYTIUM_FTC862 && + read_sysreg_s(SYS_AIDR_EL1) == PHYTIUM_CPU_SOCID_PS24080) { + u8 type = FIELD_GET(EVTQ_0_ID, evt[0]); + u64 addr = FIELD_GET(EVTQ_2_ADDR, evt[2]); + + if (type == EVT_ID_TRANSLATION_FAULT && + addr == TRANSLATE_INVALID_ADDR) + continue; + } +#endif dev_info(smmu->dev, "event 0x%02x received:\n", id); for (i = 0; i < ARRAY_SIZE(evt); ++i) diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h index 07f2b0941d..88c9cbee4d 100644 --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h @@ -426,6 +426,8 @@ #define MSI_IOVA_BASE 0x8000000 #define MSI_IOVA_LENGTH 0x100000 +#define TRANSLATE_INVALID_ADDR 0x0 + enum pri_resp { PRI_RESP_DENY = 0, PRI_RESP_FAIL = 1, -- Gitee From 0260b9432c5ba477e82a1d698c9d7918b1b3c942 Mon Sep 17 00:00:00 2001 From: Long Shixiang Date: Thu, 29 May 2025 08:47:10 +0800 Subject: [PATCH 021/155] PCI: phytium: Add hotplug and hotreset workaround patch for phytium SoCs When the PCIe device is unplugged or under hotreset, the PCIe controller's protrction mechanism is triggered, which will make the link inaccessible. This patch disables the protection after the link is up and makes the PCIe hotplug or hotreset process work well. Mainline: NA Signed-off-by: Long Shixiang Signed-off-by: Wang Yinfeng Change-Id: I08941b4062233f3dc7243f25e90e8563653f27a3 --- drivers/pci/hotplug/pciehp_ctrl.c | 7 ++++++ drivers/pci/pci.c | 4 +++ drivers/pci/pci.h | 42 +++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+) diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c index dcdbfcf404..4b105878aa 100644 --- a/drivers/pci/hotplug/pciehp_ctrl.c +++ b/drivers/pci/hotplug/pciehp_ctrl.c @@ -20,6 +20,9 @@ #include #include #include "pciehp.h" +#ifdef CONFIG_ARCH_PHYTIUM +#include "../pci.h" +#endif /* The following routines constitute the bulk of the hotplug controller logic @@ -282,6 +285,10 @@ void pciehp_handle_presence_or_link_change(struct controller *ctrl, u32 events) if (link_active) ctrl_info(ctrl, "Slot(%s): Link Up\n", slot_name(ctrl)); +#ifdef CONFIG_ARCH_PHYTIUM + if (present && link_active) + phytium_clear_ctrl_prot(ctrl->pcie->port, PHYTIUM_PCIE_HOTPLUG); +#endif ctrl->request_result = pciehp_enable_slot(ctrl); break; default: diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 00d8fbbc52..7205fe98ec 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -5257,6 +5257,10 @@ void pci_reset_secondary_bus(struct pci_dev *dev) ctrl &= ~PCI_BRIDGE_CTL_BUS_RESET; pci_write_config_word(dev, PCI_BRIDGE_CONTROL, ctrl); + +#ifdef CONFIG_ARCH_PHYTIUM + phytium_clear_ctrl_prot(dev, PHYTIUM_PCIE_HOTRESET); +#endif } void __weak pcibios_reset_secondary_bus(struct pci_dev *dev) diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index d5e9010a13..2fe6edc95d 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -832,4 +832,46 @@ static inline pci_power_t mid_pci_get_power_state(struct pci_dev *pdev) (PCI_CONF1_ADDRESS(bus, dev, func, reg) | \ PCI_CONF1_EXT_REG(reg)) +#ifdef CONFIG_ARCH_PHYTIUM +#include + +#define PHYTIUM_PCIE_HOTRESET 0 +#define PHYTIUM_PCIE_HOTPLUG 1 +#define PHYTIUM_PCI_VENDOR_ID 0x1DB7 +#define PHYTIUM_PCI_CTRL_ID 0x0100 +#define PHYTIUM_PCIE_CLEAR_CTRL_PROT_SMC_FUNC_ID 0xC2000020 + +static inline void phytium_clear_ctrl_prot(struct pci_dev *pdev, int op) +{ + int socket; + u8 bus = pdev->bus->number; + u8 device = PCI_SLOT(pdev->devfn); + u8 function = PCI_FUNC(pdev->devfn); + u16 vendor_id = pdev->vendor; + u16 device_id = pdev->device; + struct arm_smccc_res res; + u32 arg; + + if (vendor_id != PHYTIUM_PCI_VENDOR_ID || + device_id != PHYTIUM_PCI_CTRL_ID || + pci_pcie_type(pdev) != PCI_EXP_TYPE_ROOT_PORT) + return; + + socket = dev_to_node(&pdev->dev); + if (socket < 0) { + pci_err(pdev, "Cannot find socket, stop clean pcie protection\n"); + return; + } + + arg = (socket << 16) | (bus << 8) | (device << 3) | function; + arm_smccc_smc(PHYTIUM_PCIE_CLEAR_CTRL_PROT_SMC_FUNC_ID, arg, op, 0, 0, 0, 0, 0, &res); + if (res.a0 != 0) + pci_err(pdev, "Error: Firmware call PCIE protection clear Failed: %d, sbdf: 0x%x\n", + (int)res.a0, arg); + else + pci_info(pdev, "%s : Clear pcie protection successfully\n", + op ? "HotPlug" : "HotReset"); +} +#endif + #endif /* DRIVERS_PCI_H */ -- Gitee From 6baafcdcca483449097e9a73208aebb3c98b4ed9 Mon Sep 17 00:00:00 2001 From: Li Wencheng Date: Mon, 12 May 2025 13:51:22 +0800 Subject: [PATCH 022/155] net/macb: Slove the compile error in X86 architecture In the x86 architecture, if the CONFIG_OF configuration is not enabled,it will cause the compilation to fail. So we adjust the position of "#if defined (CONFIG_OF)". Mainline: Open-Source Signed-off-by: Li Wencheng Signed-off-by: Wang Yinfeng Change-Id: I658f0ad7da242e22249471529205f659d4738766 --- drivers/net/ethernet/cadence/macb_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index 0391a41ea5..65c375e8a4 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -4809,7 +4809,6 @@ static const struct macb_usrio_config macb_default_usrio = { .refclk = MACB_BIT(CLKEN), }; -#if defined(CONFIG_OF) /* 1518 rounded up */ #define AT91ETHER_MAX_RBUFF_SZ 0x600 /* max number of receive buffers */ @@ -5526,6 +5525,7 @@ static const struct macb_config phytium_gem2p0_config = { .usrio = &macb_default_usrio, }; +#if defined(CONFIG_OF) static const struct of_device_id macb_dt_ids[] = { { .compatible = "cdns,at91sam9260-macb", .data = &at91sam9260_config }, { .compatible = "cdns,macb" }, -- Gitee From 9705bfba35de86e392c15a092fb23622ff48c1fa Mon Sep 17 00:00:00 2001 From: Peng Min Date: Thu, 19 Jun 2025 09:06:52 +0800 Subject: [PATCH 023/155] spi-v2: phytium: Adapt the tpm device The spi-v2 driver is adapted to the tpm device. Furthermore, spi-v2 currently only supports half-duplex. Mainline: Open-Source Signed-off-by: Peng Min Signed-off-by: Wang Yinfeng Change-Id: I9fbb9844de5c78a5edb1eaf2d6c7cf1e4746d88b --- drivers/spi/spi-phytium-plat-v2.c | 4 ++-- drivers/spi/spi-phytium-v2.c | 26 +++++++++----------------- 2 files changed, 11 insertions(+), 19 deletions(-) diff --git a/drivers/spi/spi-phytium-plat-v2.c b/drivers/spi/spi-phytium-plat-v2.c index 9801406d61..b346df744d 100644 --- a/drivers/spi/spi-phytium-plat-v2.c +++ b/drivers/spi/spi-phytium-plat-v2.c @@ -26,7 +26,7 @@ #include "spi-phytium.h" #define DRIVER_NAME_PHYT "phytium_spi_2.0" -#define DRIVER_VERSION "1.0.7" +#define DRIVER_VERSION "1.0.8" #define PHYTIUM_CPU_PART_FTC872 0x872 @@ -130,7 +130,7 @@ static int spi_phyt_probe(struct platform_device *pdev) int ret; int num_cs; int cs_gpio; - int global_cs = 0; + int global_cs = 1; int i; u32 clk_rate = SPI_DEFAULT_CLK; diff --git a/drivers/spi/spi-phytium-v2.c b/drivers/spi/spi-phytium-v2.c index dbf834f0e1..c05b245775 100644 --- a/drivers/spi/spi-phytium-v2.c +++ b/drivers/spi/spi-phytium-v2.c @@ -15,6 +15,8 @@ #include #include #include +#include +#include #include #include #include @@ -25,10 +27,6 @@ #include #include "spi-phytium.h" -#define MCP251x_READ 0x03 -#define MCP251x_READ_RXB0 0x90 -#define MCP251x_READ_RXB1 0x94 - static inline void spi_phyt_enable_chip(struct phytium_spi *fts, u8 enable) { u8 val = enable ? 1 : 2; @@ -99,13 +97,6 @@ static void spi_phyt_set_cs(struct spi_device *spi, bool enable) u32 origin; u16 cs; - if (fts->tx || fts->rx) - return; - - if (fts->msg->cmd_id == PHYTSPI_MSG_CMD_DATA && - fts->msg->cmd_subid == PHYTSPI_MSG_CMD_DATA_TX) - return; - if (chip && chip->cs_control) chip->cs_control(!enable); @@ -145,8 +136,13 @@ static int spi_phyt_transfer_one(struct spi_master *master, { struct phytium_spi *fts = spi_master_get_devdata(master); struct chip_data *chip = spi_get_ctldata(spi); + struct spi_mem *mem = spi_get_drvdata(spi); + struct spi_nor *nor; int ret; + if (mem) + nor = spi_mem_get_drvdata(mem); + fts->tx = (void *)transfer->tx_buf; fts->tx_end = fts->tx + transfer->len; fts->rx = transfer->rx_buf; @@ -162,7 +158,7 @@ static int spi_phyt_transfer_one(struct spi_master *master, chip->tmode = TMOD_TO; } - if (fts->tx && fts->len == 1) { + if (mem == nor->spimem && fts->tx && fts->len == 1) { if ((*(u8 *)fts->tx == SPINOR_OP_WREN) && fts->spi_write_flag == 0) { spi_phytium_write_pre(fts, spi->chip_select, transfer->bits_per_word, spi->mode, @@ -262,11 +258,7 @@ static int spi_phyt_transfer_one(struct spi_master *master, } fts->flash_erase = 0; } else { - fts->flags = 1; - if (fts->spi_write_flag == 0 && *(u8 *)(fts->tx) != MCP251x_READ - && *(u8 *)(fts->tx) != MCP251x_READ_RXB0 - && *(u8 *)(fts->tx) != MCP251x_READ_RXB1) - fts->flags = 3; + fts->flags = 0; ret = spi_phytium_write(fts, spi->chip_select, transfer->bits_per_word, spi->mode, chip->tmode, fts->flags, fts->spi_write_flag); -- Gitee From 14b0572e8eb0ebf505599444911c4474b5ee32c0 Mon Sep 17 00:00:00 2001 From: Tan Rui Date: Tue, 18 Feb 2025 11:03:11 +0800 Subject: [PATCH 024/155] Revert "drivers/perf:phytium: Added some functional improvements for PCIe PMU." This reverts commit c019dd510742274e7faadf2ccf934902638c7199. Reason for revert: Change-Id: I4b2f2aaf8f570da78a77d5755debb7c8f631ed1e --- drivers/perf/phytium/phytium_pcie_pmu.c | 409 ++++++++++-------------- 1 file changed, 169 insertions(+), 240 deletions(-) diff --git a/drivers/perf/phytium/phytium_pcie_pmu.c b/drivers/perf/phytium/phytium_pcie_pmu.c index 80a931e4e4..9b73aded43 100644 --- a/drivers/perf/phytium/phytium_pcie_pmu.c +++ b/drivers/perf/phytium/phytium_pcie_pmu.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include @@ -31,72 +30,51 @@ #undef pr_fmt #define pr_fmt(fmt) "phytium_pcie_pmu: " fmt -#define PHYTIUM_PCIE_MAX_COUNTERS 18 -#define PCIE_PERF_DRIVER_VERSION "1.3.0" - -#define PCIE_START_TIMER 0x000 -#define PCIE_STOP_TIMER 0x004 -#define PCIE_CLEAR_EVENT 0x008 - -#define PCIE_EVENT_CYCLES 0x0e4 -#define PCIE_TPOINT_END_L 0x0e4 -#define PCIE_TPOINT_END_H 0x0e8 -#define PCIE_STATE_STOP 0x0ec - -#define PCIE_EVENT_AW 0x100 -#define PCIE_EVENT_W_LAST 0x104 -#define PCIE_EVENT_B 0x108 -#define PCIE_EVENT_AR 0x10c -#define PCIE_EVENT_R_LAST 0x110 -#define PCIE_EVENT_R_FULL 0x114 -#define PCIE_EVENT_R_ERR 0x118 -#define PCIE_EVENT_W_ERR 0x11c -#define PCIE_EVENT_DELAY_RD 0x120 -#define PCIE_EVENT_DELAY_WR 0x124 -#define PCIE_EVENT_RD_MAX 0x128 -#define PCIE_EVENT_RD_MIN 0x12c -#define PCIE_EVENT_WR_MAX 0x130 -#define PCIE_EVENT_WR_MIN 0x134 - -#define PCIE_EVENT_W_DATA 0x200 -#define PCIE_W_DATA_BASE 0x200 - -#define PCIE_EVENT_RDELAY_TIME 0x300 -#define PCIE_RDELAY_TIME_BASE 0x300 - -#define PCIE_EVENT_WDELAY_TIME 0x700 -#define PCIE_WDELAY_TIME_BASE 0x700 - -#define PCIE_DATA_WIDTH 0xe04 - -#define PCIE_PMU_OFL_STOP_TYPE_VAL 0x10 - -#define SYS_AIDR_EL1 sys_reg(3, 1, 0, 0, 7) -#define SOC_ID_PS230XX 0x8 -#define SOC_ID_PS240XX 0x6 -#define MIDR_PSXX 0x700f8620 - -#define to_phytium_pcie_pmu(p) (container_of(p, struct phytium_pcie_pmu, pmu)) - -enum { - PS230XX = 0x1, - PS240XX = 0x2, -}; +#define PCIE_PERF_DRIVER_VERSION "1.2.1" -static inline int phytium_socs_type(void) -{ - unsigned int soc_id, cpu_id; +#define PHYTIUM_PCIE_MAX_COUNTERS 18 - soc_id = read_sysreg_s(SYS_AIDR_EL1); - cpu_id = read_cpuid_id(); +#define PCIE_START_TIMER 0x000 +#define PCIE_STOP_TIMER 0x004 +#define PCIE_CLEAR_EVENT 0x008 +#define PCIE_SET_TIMER_L 0x00c +#define PCIE_SET_TIMER_H 0x010 +#define PCIE_TRIG_MODE 0x014 + +#define PCIE_NOW_STATE 0x0e0 +#define PCIE_EVENT_CYCLES 0x0e4 +#define PCIE_TPOINT_END_L 0x0e4 +#define PCIE_TPOINT_END_H 0x0e8 +#define PCIE_STATE_STOP 0x0ec + +#define PCIE_EVENT_AW 0x100 +#define PCIE_EVENT_W_LAST 0x104 +#define PCIE_EVENT_B 0x108 +#define PCIE_EVENT_AR 0x10c +#define PCIE_EVENT_R_LAST 0x110 +#define PCIE_EVENT_R_FULL 0x114 +#define PCIE_EVENT_R_ERR 0x118 +#define PCIE_EVENT_W_ERR 0x11c +#define PCIE_EVENT_DELAY_RD 0x120 +#define PCIE_EVENT_DELAY_WR 0x124 +#define PCIE_EVENT_RD_MAX 0x128 +#define PCIE_EVENT_RD_MIN 0x12c +#define PCIE_EVENT_WR_MAX 0x130 +#define PCIE_EVENT_WR_MIN 0x134 + +#define PCIE_EVENT_W_DATA 0x200 +#define PCIE_W_DATA_BASE 0x200 + +#define PCIE_EVENT_RDELAY_TIME 0x300 +#define PCIE_RDELAY_TIME_BASE 0x300 + +#define PCIE_EVENT_WDELAY_TIME 0x700 +#define PCIE_WDELAY_TIME_BASE 0x700 + +#define PCIE_CLK_FRE 0xe00 +#define PCIE_DATA_WIDTH 0xe04 - if ((soc_id == SOC_ID_PS230XX) && (cpu_id == MIDR_PSXX)) - return PS230XX; - else if ((soc_id == SOC_ID_PS240XX) && (cpu_id == MIDR_PSXX)) - return PS240XX; - else - return 0; -} +#define to_phytium_pcie_pmu(p) (container_of(p, struct phytium_pcie_pmu, pmu)) static int phytium_pcie_pmu_hp_state; @@ -108,21 +86,18 @@ struct phytium_pcie_pmu_hwevents { struct phytium_pcie_pmu { struct device *dev; void __iomem *base; - void __iomem *cfg_base; + void __iomem *csr_base; void __iomem *irq_reg; struct pmu pmu; struct phytium_pcie_pmu_hwevents pmu_events; u32 die_id; - u32 pcie_id; u32 pmu_id; int on_cpu; int irq; - int irq_bit; struct hlist_node node; int ctrler_id; int real_ctrler; u32 clk_bits; - u32 soc_version; }; #define GET_PCIE_EVENTID(hwc) (hwc->config_base & 0x1F) @@ -185,6 +160,7 @@ static ssize_t cpumask_show(struct device *dev, struct device_attribute *attr, static struct attribute *phytium_pcie_pmu_format_attr[] = { PHYTIUM_PCIE_PMU_FORMAT_ATTR(event, "config:0-4"), PHYTIUM_PCIE_PMU_FORMAT_ATTR(ctrler, "config:8-10"), + PHYTIUM_PCIE_PMU_FORMAT_ATTR(timer, "config1:0-31"), NULL, }; @@ -243,6 +219,11 @@ static u32 phytium_pcie_pmu_get_event_ctrler(struct perf_event *event) return FIELD_GET(GENMASK(10, 8), event->attr.config); } +static u32 phytium_pcie_pmu_get_event_timer(struct perf_event *event) +{ + return FIELD_GET(GENMASK(31, 0), event->attr.config1); +} + static u64 phytium_pcie_pmu_read_counter(struct phytium_pcie_pmu *pcie_pmu, struct hw_perf_event *hwc) { @@ -252,16 +233,12 @@ static u64 phytium_pcie_pmu_read_counter(struct phytium_pcie_pmu *pcie_pmu, u64 val64 = 0; int i; u32 counter_offset = pcie_counter_reg_offset[idx]; - u32 rdelay_num = 127; if (!EVENT_VALID(idx)) { dev_err(pcie_pmu->dev, "Unsupported event index:%d!\n", idx); return 0; } - if (pcie_pmu->soc_version == PS240XX && pcie_pmu->pmu_id == 3) - rdelay_num = 63; - switch (idx) { case 0: cycle_l = readl(pcie_pmu->base + counter_offset); @@ -276,7 +253,7 @@ static u64 phytium_pcie_pmu_read_counter(struct phytium_pcie_pmu *pcie_pmu, } break; case 16: - for (i = 0; i <= rdelay_num; i = i + 2) { + for (i = 0; i <= 127; i = i + 2) { rdelay_l = readl(pcie_pmu->base + counter_offset + 4 * i); rdelay_h = readl(pcie_pmu->base + counter_offset + @@ -304,40 +281,38 @@ static void phytium_pcie_pmu_enable_clk(struct phytium_pcie_pmu *pcie_pmu) { u32 val; - val = readl(pcie_pmu->cfg_base); + val = readl(pcie_pmu->csr_base); val |= (pcie_pmu->clk_bits); - writel(val, pcie_pmu->cfg_base); + writel(val, pcie_pmu->csr_base); } static void phytium_pcie_pmu_disable_clk(struct phytium_pcie_pmu *pcie_pmu) { u32 val; - val = readl(pcie_pmu->cfg_base); + val = readl(pcie_pmu->csr_base); val &= ~(pcie_pmu->clk_bits); - writel(val, pcie_pmu->cfg_base); + writel(val, pcie_pmu->csr_base); } static void phytium_pcie_pmu_select_ctrler(struct phytium_pcie_pmu *pcie_pmu) { - u32 val, offset; - u32 mask = 0xfffffffc; + u32 val, offset = 0; - if (pcie_pmu->soc_version == PS230XX) { - if (pcie_pmu->pmu_id == 2) { - mask = 0xffffffcf; - offset = 0x0; - } else - offset = 0xc; + if (pcie_pmu->pmu_id != 2) + offset = 0xc; + + val = readl(pcie_pmu->csr_base + offset); + + if (pcie_pmu->pmu_id == 2) { + val &= 0xffffffcf; + val |= pcie_pmu->real_ctrler; } else { - offset = 0x170; + val &= 0xfffffffc; + val |= pcie_pmu->real_ctrler; } - val = readl(pcie_pmu->cfg_base + offset); - val &= mask; - val |= pcie_pmu->real_ctrler; - writel(val, pcie_pmu->cfg_base + offset); - + writel(val, pcie_pmu->csr_base + offset); } static void @@ -358,6 +333,29 @@ phytium_pcie_pmu_stop_all_counters(struct phytium_pcie_pmu *pcie_pmu) writel(0x1, pcie_pmu->base + PCIE_STOP_TIMER); } +static void phytium_pcie_pmu_set_timer(struct phytium_pcie_pmu *pcie_pmu, + u32 th_val) +{ + u32 val; + + val = readl(pcie_pmu->base + PCIE_SET_TIMER_L); + val = readl(pcie_pmu->base + PCIE_SET_TIMER_H); + + writel(th_val, pcie_pmu->base + PCIE_SET_TIMER_L); + writel(0, pcie_pmu->base + PCIE_SET_TIMER_H); +} + +static void phytium_pcie_pmu_reset_timer(struct phytium_pcie_pmu *pcie_pmu) +{ + u32 val; + + val = readl(pcie_pmu->base + PCIE_SET_TIMER_L); + val = readl(pcie_pmu->base + PCIE_SET_TIMER_H); + + writel(0xFFFFFFFF, pcie_pmu->base + PCIE_SET_TIMER_L); + writel(0xFFFFFFFF, pcie_pmu->base + PCIE_SET_TIMER_H); +} + static unsigned long phytium_pcie_pmu_get_stop_state(struct phytium_pcie_pmu *pcie_pmu) { @@ -407,7 +405,7 @@ int phytium_pcie_pmu_event_init(struct perf_event *event) { struct hw_perf_event *hwc = &event->hw; struct phytium_pcie_pmu *pcie_pmu; - u32 event_ctrler; + u32 event_ctrler, event_timer; if (event->attr.type != event->pmu->type) return -ENOENT; @@ -428,83 +426,57 @@ int phytium_pcie_pmu_event_init(struct perf_event *event) if (pcie_pmu->on_cpu == -1) return -EINVAL; - if (pcie_pmu->soc_version == PS240XX) { - event_ctrler = phytium_pcie_pmu_get_event_ctrler(event); - if (pcie_pmu->pmu_id == 2) { - if (event_ctrler == 0) - event_ctrler = 2; - else if ((event_ctrler < 2) || (event_ctrler > 3)) { - dev_warn(pcie_pmu->dev, "Wrong ctrler id(%d) for pcie-pmu2!\n", - event_ctrler); - return -EINVAL; - } - if (pcie_pmu->ctrler_id != event_ctrler) { - pcie_pmu->ctrler_id = event_ctrler; - pcie_pmu->real_ctrler = pcie_pmu->ctrler_id; - phytium_pcie_pmu_select_ctrler(pcie_pmu); - } - } else { - if (event_ctrler != 0) { - dev_warn(pcie_pmu->dev, "Don't need to set ctrler id(%d) for pcie-pmu%d!\n", - event_ctrler, pcie_pmu->pmu_id); - return -EINVAL; - } - pcie_pmu->ctrler_id = pcie_pmu->pmu_id; - pcie_pmu->real_ctrler = pcie_pmu->ctrler_id; + event_timer = phytium_pcie_pmu_get_event_timer(event); + if (event_timer != 0) + phytium_pcie_pmu_set_timer(pcie_pmu, event_timer); + + event_ctrler = phytium_pcie_pmu_get_event_ctrler(event); + switch (pcie_pmu->pmu_id) { + case 0: + if (event_ctrler != 0) { + dev_warn(pcie_pmu->dev, + "Wrong ctrler id(%d) for pcie-pmu0!\n", + event_ctrler); + return -EINVAL; } - } else { - event_ctrler = phytium_pcie_pmu_get_event_ctrler(event); - switch (pcie_pmu->pmu_id) { - case 0: - if (event_ctrler != 0) { - dev_warn(pcie_pmu->dev, - "Wrong ctrler id(%d) for pcie-pmu0!\n", - event_ctrler); - return -EINVAL; - } - break; - case 1: - if (event_ctrler == 0) - event_ctrler = 1; - else if ((event_ctrler < 1) || (event_ctrler > 3)) { - dev_warn(pcie_pmu->dev, - "Wrong ctrler id(%d) for pcie-pmu1!\n", - event_ctrler); - return -EINVAL; - } - break; - case 2: - if (event_ctrler == 0) - event_ctrler = 4; - else if ((event_ctrler < 4) || (event_ctrler > 7)) { - dev_warn(pcie_pmu->dev, - "Wrong ctrler id(%d) for pcie-pmu2!\n", - event_ctrler); - return -EINVAL; - } - break; - default: - dev_err(pcie_pmu->dev, "Unsupported pmu id:%d!\n", - pcie_pmu->pmu_id); + break; + case 1: + if ((event_ctrler < 1) || (event_ctrler > 3)) { + dev_warn(pcie_pmu->dev, + "Wrong ctrler id(%d) for pcie-pmu1!\n", + event_ctrler); return -EINVAL; } - - pcie_pmu->ctrler_id = event_ctrler; - switch (pcie_pmu->pmu_id) { - case 0: - case 1: - pcie_pmu->real_ctrler = pcie_pmu->ctrler_id; - break; - case 2: - pcie_pmu->real_ctrler = (pcie_pmu->ctrler_id - 4) * 16; - break; - default: - dev_err(pcie_pmu->dev, "Unsupported pmu id:%d!\n", - pcie_pmu->pmu_id); + break; + case 2: + if ((event_ctrler < 4) || (event_ctrler > 7)) { + dev_warn(pcie_pmu->dev, + "Wrong ctrler id(%d) for pcie-pmu2!\n", + event_ctrler); return -EINVAL; } - phytium_pcie_pmu_select_ctrler(pcie_pmu); + break; + default: + dev_err(pcie_pmu->dev, "Unsupported pmu id:%d!\n", + pcie_pmu->pmu_id); + return -EINVAL; + } + + pcie_pmu->ctrler_id = event_ctrler; + switch (pcie_pmu->pmu_id) { + case 0: + case 1: + pcie_pmu->real_ctrler = pcie_pmu->ctrler_id; + break; + case 2: + pcie_pmu->real_ctrler = (pcie_pmu->ctrler_id - 4) * 16; + break; + default: + dev_err(pcie_pmu->dev, "Unsupported pmu id:%d!\n", + pcie_pmu->pmu_id); + return -EINVAL; } + phytium_pcie_pmu_select_ctrler(pcie_pmu); hwc->idx = -1; hwc->config_base = event->attr.config; @@ -564,12 +536,17 @@ void phytium_pcie_pmu_event_del(struct perf_event *event, int flags) struct phytium_pcie_pmu *pcie_pmu = to_phytium_pcie_pmu(event->pmu); struct hw_perf_event *hwc = &event->hw; unsigned long val; + u32 event_timer; phytium_pcie_pmu_event_stop(event, PERF_EF_UPDATE); val = phytium_pcie_pmu_get_irq_flag(pcie_pmu); val = phytium_pcie_pmu_get_stop_state(pcie_pmu); phytium_pcie_pmu_unmark_event(pcie_pmu, hwc->idx); + event_timer = phytium_pcie_pmu_get_event_timer(event); + if (event_timer != 0) + phytium_pcie_pmu_reset_timer(pcie_pmu); + perf_event_update_userpage(event); pcie_pmu->pmu_events.hw_events[hwc->idx] = NULL; } @@ -596,12 +573,6 @@ void phytium_pcie_pmu_disable(struct pmu *pmu) phytium_pcie_pmu_stop_all_counters(pcie_pmu); } -void phytium_pcie_pmu_reset(struct phytium_pcie_pmu *pcie_pmu) -{ - phytium_pcie_pmu_disable_clk(pcie_pmu); - phytium_pcie_pmu_clear_all_counters(pcie_pmu); -} - static const struct acpi_device_id phytium_pcie_pmu_acpi_match[] = { { "PHYT0044", @@ -621,7 +592,7 @@ static irqreturn_t phytium_pcie_pmu_overflow_handler(int irq, void *dev_id) overflown = phytium_pcie_pmu_get_irq_flag(pcie_pmu); - if (!test_bit(pcie_pmu->irq_bit, &overflown)) + if (!test_bit(pcie_pmu->pmu_id + 4, &overflown)) return IRQ_NONE; stop_state = phytium_pcie_pmu_get_stop_state(pcie_pmu); @@ -634,8 +605,7 @@ static irqreturn_t phytium_pcie_pmu_overflow_handler(int irq, void *dev_id) phytium_pcie_pmu_event_update(event); } phytium_pcie_pmu_clear_all_counters(pcie_pmu); - if ((stop_state & PCIE_PMU_OFL_STOP_TYPE_VAL) == 0) - phytium_pcie_pmu_start_all_counters(pcie_pmu); + phytium_pcie_pmu_start_all_counters(pcie_pmu); return IRQ_HANDLED; } @@ -671,14 +641,9 @@ static int phytium_pcie_pmu_init_irq(struct phytium_pcie_pmu *pcie_pmu, } static int phytium_pcie_pmu_init_data(struct platform_device *pdev, - struct phytium_pcie_pmu *pcie_pmu) + struct phytium_pcie_pmu *pcie_pmu) { struct resource *res, *clkres, *irqres; - pcie_pmu->soc_version = phytium_socs_type(); - if (pcie_pmu->soc_version == 0) { - dev_err(&pdev->dev, "The PCIe PMU driver can't be installed in this SoC.\n"); - return -EINVAL; - } if (device_property_read_u32(&pdev->dev, "phytium,die-id", &pcie_pmu->die_id)) { @@ -692,46 +657,20 @@ static int phytium_pcie_pmu_init_data(struct platform_device *pdev, return -EINVAL; } - if (pcie_pmu->soc_version == PS230XX) { - switch (pcie_pmu->pmu_id) { - case 0: - pcie_pmu->clk_bits = 0x1; - break; - case 1: - pcie_pmu->clk_bits = 0xe; - break; - case 2: - pcie_pmu->clk_bits = 0xf; - break; - default: - dev_err(&pdev->dev, "Unsupported pmu id:%d!\n", pcie_pmu->pmu_id); - break; - } - - pcie_pmu->irq_bit = pcie_pmu->pmu_id + 4; - } else { - if (device_property_read_u32(&pdev->dev, "phytium,pcie-id", &pcie_pmu->pcie_id)) { - dev_err(&pdev->dev, "Can not read phytium,pcie-id!\n"); - return -EINVAL; - } - - switch (pcie_pmu->pmu_id) { - case 0: - case 3: - pcie_pmu->clk_bits = 0x1; - break; - case 1: - pcie_pmu->clk_bits = 0x2; - break; - case 2: - pcie_pmu->clk_bits = 0xc; - break; - default: - dev_err(&pdev->dev, "Unsupported pmu id:%d!\n", pcie_pmu->pmu_id); - break; - } - - pcie_pmu->irq_bit = pcie_pmu->pcie_id * 4 + pcie_pmu->pmu_id + 16; + switch (pcie_pmu->pmu_id) { + case 0: + pcie_pmu->clk_bits = 0x1; + break; + case 1: + pcie_pmu->clk_bits = 0xe; + break; + case 2: + pcie_pmu->clk_bits = 0xf; + break; + default: + dev_err(&pdev->dev, "Unsupported pmu id:%d!\n", + pcie_pmu->pmu_id); + break; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -747,12 +686,12 @@ static int phytium_pcie_pmu_init_data(struct platform_device *pdev, return -EINVAL; } - pcie_pmu->cfg_base = + pcie_pmu->csr_base = devm_ioremap(&pdev->dev, clkres->start, resource_size(clkres)); - if (IS_ERR(pcie_pmu->cfg_base)) { + if (IS_ERR(pcie_pmu->csr_base)) { dev_err(&pdev->dev, "ioremap failed for pcie_pmu csr resource\n"); - return PTR_ERR(pcie_pmu->cfg_base); + return PTR_ERR(pcie_pmu->csr_base); } irqres = platform_get_resource(pdev, IORESOURCE_MEM, 2); @@ -770,13 +709,11 @@ static int phytium_pcie_pmu_init_data(struct platform_device *pdev, return PTR_ERR(pcie_pmu->irq_reg); } - phytium_pcie_pmu_reset(pcie_pmu); - return 0; } static int phytium_pcie_pmu_dev_probe(struct platform_device *pdev, - struct phytium_pcie_pmu *pcie_pmu) + struct phytium_pcie_pmu *pcie_pmu) { int ret; @@ -817,12 +754,8 @@ static int phytium_pcie_pmu_probe(struct platform_device *pdev) return ret; } - if (pcie_pmu->soc_version == PS230XX) - name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "phyt%u_pcie_pmu%u", - pcie_pmu->die_id, pcie_pmu->pmu_id); - else - name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "phyt%u_pcie%u_pmu%u", - pcie_pmu->die_id, pcie_pmu->pcie_id, pcie_pmu->pmu_id); + name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "phyt%u_pcie_pmu%u", + pcie_pmu->die_id, pcie_pmu->pmu_id); pcie_pmu->pmu = (struct pmu){ .name = name, .module = THIS_MODULE, @@ -836,6 +769,7 @@ static int phytium_pcie_pmu_probe(struct platform_device *pdev) .stop = phytium_pcie_pmu_event_stop, .read = phytium_pcie_pmu_event_update, .attr_groups = phytium_pcie_pmu_attr_groups, + .capabilities = PERF_PMU_CAP_NO_EXCLUDE, }; ret = perf_pmu_register(&pcie_pmu->pmu, name, -1); @@ -848,12 +782,9 @@ static int phytium_pcie_pmu_probe(struct platform_device *pdev) phytium_pcie_pmu_enable_clk(pcie_pmu); - if (pcie_pmu->soc_version == PS230XX) - pr_info("die%d_pcie_pmu%d on cpu%d.\n", - pcie_pmu->die_id, pcie_pmu->pmu_id, pcie_pmu->on_cpu); - else - pr_info("die%d_pcie%d_pmu%d on cpu%d.\n", - pcie_pmu->die_id, pcie_pmu->pcie_id, pcie_pmu->pmu_id, pcie_pmu->on_cpu); + pr_info("Phytium PCIe PMU: "); + pr_info("die_id = %d pmu_id = %d.\n", pcie_pmu->die_id, + pcie_pmu->pmu_id); return ret; } @@ -895,7 +826,6 @@ int phytium_pcie_pmu_online_cpu(unsigned int cpu, struct hlist_node *node) pcie_pmu->on_cpu = cpu; WARN_ON(irq_set_affinity_hint(pcie_pmu->irq, cpumask_of(cpu))); } - return 0; } @@ -942,8 +872,8 @@ static int __init phytium_pcie_pmu_module_init(void) phytium_pcie_pmu_hp_state = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN, - "perf/phytium/pciepmu:online", phytium_pcie_pmu_online_cpu, - phytium_pcie_pmu_offline_cpu); + "perf/phytium/pciepmu:online", + phytium_pcie_pmu_online_cpu, phytium_pcie_pmu_offline_cpu); if (phytium_pcie_pmu_hp_state < 0) { pr_err("PCIE PMU: setup hotplug, ret = %d\n", phytium_pcie_pmu_hp_state); @@ -970,4 +900,3 @@ MODULE_DESCRIPTION("Phytium PCIe PMU driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(PCIE_PERF_DRIVER_VERSION); MODULE_AUTHOR("Hu Xianghua "); -MODULE_AUTHOR("Tan Rui "); -- Gitee From 82be9ecb37f46c5a4eafcc393d3213732ce7852e Mon Sep 17 00:00:00 2001 From: Tan Rui Date: Tue, 18 Feb 2025 11:38:07 +0800 Subject: [PATCH 025/155] Revert "drivers/perf:phytium: Added some functional improvements for DDR PMU." This reverts commit 6b95559ae805afcc01cd1960da56c96214ef3522. Reason for revert: Change-Id: I0dc257f60da0edf605e91919e5f0bf9bc41c1a08 --- drivers/perf/phytium/phytium_ddr_pmu.c | 223 +++++++++++-------------- 1 file changed, 101 insertions(+), 122 deletions(-) diff --git a/drivers/perf/phytium/phytium_ddr_pmu.c b/drivers/perf/phytium/phytium_ddr_pmu.c index 8fd6f997c4..eda53c1024 100644 --- a/drivers/perf/phytium/phytium_ddr_pmu.c +++ b/drivers/perf/phytium/phytium_ddr_pmu.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include @@ -31,59 +30,33 @@ #undef pr_fmt #define pr_fmt(fmt) "phytium_ddr_pmu: " fmt +#define DDR_PERF_DRIVER_VERSION "1.2.1" #define PHYTIUM_DDR_MAX_COUNTERS 8 -#define DDR_PERF_DRIVER_VERSION "1.3.0" - -#define DDR_START_TIMER 0x000 -#define DDR_STOP_TIMER 0x004 -#define DDR_CLEAR_EVENT 0x008 -#define DDR_SET_TIMER_L 0x00c -#define DDR_SET_TIMER_H 0x010 -#define DDR_TRIG_MODE 0x014 -#define DDR_NOW_STATE 0x0e0 -#define DDR_EVENT_CYCLES 0x0e4 -#define DDR_TPOINT_END_L 0x0e4 -#define DDR_TPOINT_END_H 0x0e8 -#define DDR_STATE_STOP 0x0ec -#define DDR_EVENT_RXREQ 0x100 -#define DDR_EVENT_RXDAT 0x104 -#define DDR_EVENT_TXDAT 0x108 -#define DDR_EVENT_RXREQ_RNS 0x10c -#define DDR_EVENT_RXREQ_WNSP 0x110 -#define DDR_EVENT_RXREQ_WNSF 0x114 -#define DDR_EVENT_BANDWIDTH 0x200 -#define DDR_W_DATA_BASE 0x200 -#define DDR_CLK_FRE 0xe00 -#define DDR_DATA_WIDTH 0xe04 - -#define DDR_PMU_OFL_STOP_TYPE_VAL 0x10 - -#define SOC_ID_PS230XX 0x8 -#define SOC_ID_PS240XX 0x6 -#define MIDR_PSXX 0x700F8620 -#define to_phytium_ddr_pmu(p) (container_of(p, struct phytium_ddr_pmu, pmu)) - -enum { - PS230XX = 0x01, - PS240XX = 0x02, -}; - -static inline int phytium_socs_type(void) -{ - unsigned int soc_id, cpu_id; - - soc_id = read_sysreg_s(SYS_AIDR_EL1); - cpu_id = read_cpuid_id(); +#define DDR_START_TIMER 0x000 +#define DDR_STOP_TIMER 0x004 +#define DDR_CLEAR_EVENT 0x008 +#define DDR_SET_TIMER_L 0x00c +#define DDR_SET_TIMER_H 0x010 +#define DDR_TRIG_MODE 0x014 +#define DDR_NOW_STATE 0x0e0 +#define DDR_EVENT_CYCLES 0x0e4 +#define DDR_TPOINT_END_L 0x0e4 +#define DDR_TPOINT_END_H 0x0e8 +#define DDR_STATE_STOP 0x0ec +#define DDR_EVENT_RXREQ 0x100 +#define DDR_EVENT_RXDAT 0x104 +#define DDR_EVENT_TXDAT 0x108 +#define DDR_EVENT_RXREQ_RNS 0x10c +#define DDR_EVENT_RXREQ_WNSP 0x110 +#define DDR_EVENT_RXREQ_WNSF 0x114 +#define DDR_EVENT_BANDWIDTH 0x200 +#define DDR_W_DATA_BASE 0x200 +#define DDR_CLK_FRE 0xe00 +#define DDR_DATA_WIDTH 0xe04 - if ((soc_id == SOC_ID_PS230XX) && (cpu_id == MIDR_PSXX)) - return PS230XX; - else if ((soc_id == SOC_ID_PS240XX) && (cpu_id == MIDR_PSXX)) - return PS240XX; - else - return 0; -} +#define to_phytium_ddr_pmu(p) (container_of(p, struct phytium_ddr_pmu, pmu)) static int phytium_ddr_pmu_hp_state; @@ -95,17 +68,15 @@ struct phytium_ddr_pmu_hwevents { struct phytium_ddr_pmu { struct device *dev; void __iomem *base; - void __iomem *cfg_base; - void __iomem *irq_reg; + void __iomem *csr_base; struct pmu pmu; struct phytium_ddr_pmu_hwevents pmu_events; u32 die_id; u32 ddr_id; u32 pmu_id; - int irq_bit; + int bit_idx; int on_cpu; int irq; - int soc_version; struct hlist_node node; }; @@ -149,21 +120,22 @@ static ssize_t cpumask_show(struct device *dev, struct device_attribute *attr, return cpumap_print_to_pagebuf(true, buf, cpumask_of(ddr_pmu->on_cpu)); } -#define PHYTIUM_PMU_ATTR(_name, _func, _config) \ - (&((struct dev_ext_attribute[]){ \ - { __ATTR(_name, 0444, _func, NULL), (void *)_config } })[0] \ - .attr.attr) +#define PHYTIUM_PMU_ATTR(_name, _func, _config) \ + (&((struct dev_ext_attribute[]){ \ + { __ATTR(_name, 0444, _func, NULL), (void *)_config } })[0] \ + .attr.attr) -#define PHYTIUM_DDR_PMU_FORMAT_ATTR(_name, _config) \ - PHYTIUM_PMU_ATTR(_name, phytium_ddr_pmu_format_sysfs_show, \ - (void *)_config) +#define PHYTIUM_DDR_PMU_FORMAT_ATTR(_name, _config) \ + PHYTIUM_PMU_ATTR(_name, phytium_ddr_pmu_format_sysfs_show, \ + (void *)_config) -#define PHYTIUM_DDR_PMU_EVENT_ATTR(_name, _config) \ - PHYTIUM_PMU_ATTR(_name, phytium_ddr_pmu_event_sysfs_show, \ - (unsigned long)_config) +#define PHYTIUM_DDR_PMU_EVENT_ATTR(_name, _config) \ + PHYTIUM_PMU_ATTR(_name, phytium_ddr_pmu_event_sysfs_show, \ + (unsigned long)_config) static struct attribute *phytium_ddr_pmu_format_attr[] = { PHYTIUM_DDR_PMU_FORMAT_ATTR(event, "config:0-2"), + PHYTIUM_DDR_PMU_FORMAT_ATTR(timer, "config1:0-31"), NULL, }; @@ -207,6 +179,11 @@ static const struct attribute_group *phytium_ddr_pmu_attr_groups[] = { NULL, }; +static u32 phytium_ddr_pmu_get_event_timer(struct perf_event *event) +{ + return FIELD_GET(GENMASK(31, 0), event->attr.config1); +} + static u64 phytium_ddr_pmu_read_counter(struct phytium_ddr_pmu *ddr_pmu, struct hw_perf_event *hwc) { @@ -246,24 +223,18 @@ static void phytium_ddr_pmu_enable_clk(struct phytium_ddr_pmu *ddr_pmu) { u32 val; - if (ddr_pmu->soc_version == PS240XX) - return; - - val = readl(ddr_pmu->cfg_base); + val = readl(ddr_pmu->csr_base); val |= 0xF; - writel(val, ddr_pmu->cfg_base); + writel(val, ddr_pmu->csr_base); } static void phytium_ddr_pmu_disable_clk(struct phytium_ddr_pmu *ddr_pmu) { u32 val; - if (ddr_pmu->soc_version == PS240XX) - return; - - val = readl(ddr_pmu->cfg_base); + val = readl(ddr_pmu->csr_base); val &= ~(0xF); - writel(val, ddr_pmu->cfg_base); + writel(val, ddr_pmu->csr_base); } static void phytium_ddr_pmu_clear_all_counters(struct phytium_ddr_pmu *ddr_pmu) @@ -281,6 +252,29 @@ static void phytium_ddr_pmu_stop_all_counters(struct phytium_ddr_pmu *ddr_pmu) writel(0x1, ddr_pmu->base + DDR_STOP_TIMER); } +static void phytium_ddr_pmu_set_timer(struct phytium_ddr_pmu *ddr_pmu, + u32 th_val) +{ + u32 val; + + val = readl(ddr_pmu->base + DDR_SET_TIMER_L); + val = readl(ddr_pmu->base + DDR_SET_TIMER_H); + + writel(th_val, ddr_pmu->base + DDR_SET_TIMER_L); + writel(0, ddr_pmu->base + DDR_SET_TIMER_H); +} + +static void phytium_ddr_pmu_reset_timer(struct phytium_ddr_pmu *ddr_pmu) +{ + u32 val; + + val = readl(ddr_pmu->base + DDR_SET_TIMER_L); + val = readl(ddr_pmu->base + DDR_SET_TIMER_H); + + writel(0xFFFFFFFF, ddr_pmu->base + DDR_SET_TIMER_L); + writel(0xFFFFFFFF, ddr_pmu->base + DDR_SET_TIMER_H); +} + static unsigned long phytium_ddr_pmu_get_stop_state(struct phytium_ddr_pmu *ddr_pmu) { @@ -295,7 +289,7 @@ phytium_ddr_pmu_get_irq_flag(struct phytium_ddr_pmu *ddr_pmu) { unsigned long val; - val = (unsigned long)readl(ddr_pmu->irq_reg); + val = (unsigned long)readl(ddr_pmu->csr_base + 4); return val; } @@ -330,6 +324,7 @@ int phytium_ddr_pmu_event_init(struct perf_event *event) { struct hw_perf_event *hwc = &event->hw; struct phytium_ddr_pmu *ddr_pmu; + u32 event_timer; if (event->attr.type != event->pmu->type) return -ENOENT; @@ -350,6 +345,10 @@ int phytium_ddr_pmu_event_init(struct perf_event *event) if (ddr_pmu->on_cpu == -1) return -EINVAL; + event_timer = phytium_ddr_pmu_get_event_timer(event); + if (event_timer != 0) + phytium_ddr_pmu_set_timer(ddr_pmu, event_timer); + hwc->idx = -1; hwc->config_base = event->attr.config; @@ -409,12 +408,17 @@ void phytium_ddr_pmu_event_del(struct perf_event *event, int flags) struct phytium_ddr_pmu *ddr_pmu = to_phytium_ddr_pmu(event->pmu); struct hw_perf_event *hwc = &event->hw; unsigned long val; + u32 event_timer; phytium_ddr_pmu_event_stop(event, PERF_EF_UPDATE); val = phytium_ddr_pmu_get_irq_flag(ddr_pmu); val = phytium_ddr_pmu_get_stop_state(ddr_pmu); phytium_ddr_pmu_unmark_event(ddr_pmu, hwc->idx); + event_timer = phytium_ddr_pmu_get_event_timer(event); + if (event_timer != 0) + phytium_ddr_pmu_reset_timer(ddr_pmu); + perf_event_update_userpage(event); ddr_pmu->pmu_events.hw_events[hwc->idx] = NULL; } @@ -441,12 +445,6 @@ void phytium_ddr_pmu_disable(struct pmu *pmu) phytium_ddr_pmu_stop_all_counters(ddr_pmu); } -void phytium_ddr_pmu_reset(struct phytium_ddr_pmu *ddr_pmu) -{ - phytium_ddr_pmu_disable_clk(ddr_pmu); - phytium_ddr_pmu_clear_all_counters(ddr_pmu); -} - static const struct acpi_device_id phytium_ddr_pmu_acpi_match[] = { { "PHYT0043", @@ -460,13 +458,14 @@ static irqreturn_t phytium_ddr_pmu_overflow_handler(int irq, void *dev_id) struct phytium_ddr_pmu *ddr_pmu = dev_id; struct perf_event *event; unsigned long overflown, stop_state; - unsigned long *used_mask = ddr_pmu->pmu_events.used_mask; int idx; + unsigned long *used_mask = ddr_pmu->pmu_events.used_mask; + int event_added = bitmap_weight(used_mask, PHYTIUM_DDR_MAX_COUNTERS); overflown = phytium_ddr_pmu_get_irq_flag(ddr_pmu); - if (!test_bit(ddr_pmu->irq_bit, &overflown)) + if (!test_bit(ddr_pmu->bit_idx, &overflown)) return IRQ_NONE; stop_state = phytium_ddr_pmu_get_stop_state(ddr_pmu); @@ -478,10 +477,8 @@ static irqreturn_t phytium_ddr_pmu_overflow_handler(int irq, void *dev_id) continue; phytium_ddr_pmu_event_update(event); } - phytium_ddr_pmu_clear_all_counters(ddr_pmu); - if ((stop_state & DDR_PMU_OFL_STOP_TYPE_VAL) == 0) - phytium_ddr_pmu_start_all_counters(ddr_pmu); + phytium_ddr_pmu_start_all_counters(ddr_pmu); return IRQ_HANDLED; } @@ -521,13 +518,7 @@ static int phytium_ddr_pmu_init_irq(struct phytium_ddr_pmu *ddr_pmu, static int phytium_ddr_pmu_init_data(struct platform_device *pdev, struct phytium_ddr_pmu *ddr_pmu) { - struct resource *res, *clkres, *irqres; - - ddr_pmu->soc_version = phytium_socs_type(); - if (ddr_pmu->soc_version == 0) { - dev_err(&pdev->dev, "The DDR PMU driver can't be installed in this SoC!\n"); - return -EINVAL; - } + struct resource *res, *clkres; if (device_property_read_u32(&pdev->dev, "phytium,die-id", &ddr_pmu->die_id)) { @@ -547,7 +538,7 @@ static int phytium_ddr_pmu_init_data(struct platform_device *pdev, return -EINVAL; } - ddr_pmu->irq_bit = ddr_pmu->ddr_id * 2 + ddr_pmu->pmu_id; + ddr_pmu->bit_idx = ddr_pmu->ddr_id * 2 + ddr_pmu->pmu_id; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ddr_pmu->base = devm_ioremap_resource(&pdev->dev, res); @@ -563,29 +554,15 @@ static int phytium_ddr_pmu_init_data(struct platform_device *pdev, dev_err(&pdev->dev, "failed for get ddr_pmu clk resource.\n"); return -EINVAL; } - ddr_pmu->cfg_base = devm_ioremap(&pdev->dev, clkres->start, resource_size(clkres)); - if (IS_ERR(ddr_pmu->cfg_base)) { - dev_err(&pdev->dev, "ioremap failed for ddr_pmu clk resource\n"); - return PTR_ERR(ddr_pmu->cfg_base); - } - if (ddr_pmu->soc_version == PS240XX) { - irqres = platform_get_resource(pdev, IORESOURCE_MEM, 2); - if (!irqres) { - dev_err(&pdev->dev, "failed for get ddr_pmu irq resource.\n"); - return -EINVAL; - } - ddr_pmu->irq_reg = devm_ioremap(&pdev->dev, irqres->start, resource_size(irqres)); - if (IS_ERR(ddr_pmu->irq_reg)) { - dev_err(&pdev->dev, "ioremap failed for ddr_pmu irq resource\n"); - return PTR_ERR(ddr_pmu->irq_reg); - } - } else { - ddr_pmu->irq_reg = ddr_pmu->cfg_base + 0x4; + ddr_pmu->csr_base = + devm_ioremap(&pdev->dev, clkres->start, resource_size(clkres)); + if (IS_ERR(ddr_pmu->csr_base)) { + dev_err(&pdev->dev, + "ioremap failed for ddr_pmu csr resource\n"); + return PTR_ERR(ddr_pmu->csr_base); } - phytium_ddr_pmu_reset(ddr_pmu); - return 0; } @@ -624,8 +601,8 @@ static int phytium_ddr_pmu_probe(struct platform_device *pdev) if (ret) return ret; - ret = cpuhp_state_add_instance(phytium_ddr_pmu_hp_state, - &ddr_pmu->node); + ret = cpuhp_state_add_instance( + phytium_ddr_pmu_hp_state, &ddr_pmu->node); if (ret) { dev_err(&pdev->dev, "Error %d registering hotplug;\n", ret); return ret; @@ -647,19 +624,22 @@ static int phytium_ddr_pmu_probe(struct platform_device *pdev) .stop = phytium_ddr_pmu_event_stop, .read = phytium_ddr_pmu_event_update, .attr_groups = phytium_ddr_pmu_attr_groups, + .capabilities = PERF_PMU_CAP_NO_EXCLUDE, }; ret = perf_pmu_register(&ddr_pmu->pmu, name, -1); if (ret) { dev_err(ddr_pmu->dev, "DDR PMU register failed!\n"); - cpuhp_state_remove_instance_nocalls(phytium_ddr_pmu_hp_state, + cpuhp_state_remove_instance_nocalls( + phytium_ddr_pmu_hp_state, &ddr_pmu->node); } phytium_ddr_pmu_enable_clk(ddr_pmu); - pr_info("die%d_ddr%d_pmu%d on cpu%d.\n", ddr_pmu->die_id, - ddr_pmu->ddr_id, ddr_pmu->pmu_id, ddr_pmu->on_cpu); + pr_info("Phytium DDR PMU: "); + pr_info(" die_id = %d ddr_id = %d pmu_id = %d.\n", ddr_pmu->die_id, + ddr_pmu->ddr_id, ddr_pmu->pmu_id); return ret; } @@ -671,8 +651,8 @@ static int phytium_ddr_pmu_remove(struct platform_device *pdev) phytium_ddr_pmu_disable_clk(ddr_pmu); perf_pmu_unregister(&ddr_pmu->pmu); - cpuhp_state_remove_instance_nocalls(phytium_ddr_pmu_hp_state, - &ddr_pmu->node); + cpuhp_state_remove_instance_nocalls( + phytium_ddr_pmu_hp_state, &ddr_pmu->node); return 0; } @@ -774,4 +754,3 @@ MODULE_DESCRIPTION("Phytium DDR PMU driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(DDR_PERF_DRIVER_VERSION); MODULE_AUTHOR("Hu Xianghua "); -MODULE_AUTHOR("Tan Rui "); -- Gitee From 5033a2d6662bb42ed7ad7ccc2648943d361f1ab8 Mon Sep 17 00:00:00 2001 From: Tan Rui Date: Tue, 18 Feb 2025 14:53:24 +0800 Subject: [PATCH 026/155] drivers/perf:phytium: Add DDR PMU Support for PS240XX. Add a new HID to differentiate between PS230XX and PS240XX DDR PMU and add support for PS240XX platforms. Signed-off-by: Tan Rui Change-Id: I05e8adf4862c8559fcdc9d87acc58b88888bb03a --- drivers/perf/phytium/phytium_ddr_pmu.c | 228 +++++++++++++------------ 1 file changed, 121 insertions(+), 107 deletions(-) diff --git a/drivers/perf/phytium/phytium_ddr_pmu.c b/drivers/perf/phytium/phytium_ddr_pmu.c index eda53c1024..4c3475ddf9 100644 --- a/drivers/perf/phytium/phytium_ddr_pmu.c +++ b/drivers/perf/phytium/phytium_ddr_pmu.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -30,34 +31,40 @@ #undef pr_fmt #define pr_fmt(fmt) "phytium_ddr_pmu: " fmt -#define DDR_PERF_DRIVER_VERSION "1.2.1" - #define PHYTIUM_DDR_MAX_COUNTERS 8 - -#define DDR_START_TIMER 0x000 -#define DDR_STOP_TIMER 0x004 -#define DDR_CLEAR_EVENT 0x008 -#define DDR_SET_TIMER_L 0x00c -#define DDR_SET_TIMER_H 0x010 -#define DDR_TRIG_MODE 0x014 -#define DDR_NOW_STATE 0x0e0 -#define DDR_EVENT_CYCLES 0x0e4 -#define DDR_TPOINT_END_L 0x0e4 -#define DDR_TPOINT_END_H 0x0e8 -#define DDR_STATE_STOP 0x0ec -#define DDR_EVENT_RXREQ 0x100 -#define DDR_EVENT_RXDAT 0x104 -#define DDR_EVENT_TXDAT 0x108 -#define DDR_EVENT_RXREQ_RNS 0x10c -#define DDR_EVENT_RXREQ_WNSP 0x110 -#define DDR_EVENT_RXREQ_WNSF 0x114 -#define DDR_EVENT_BANDWIDTH 0x200 -#define DDR_W_DATA_BASE 0x200 -#define DDR_CLK_FRE 0xe00 -#define DDR_DATA_WIDTH 0xe04 +#define DDR_PERF_DRIVER_VERSION "1.3.0" + +#define DDR_START_TIMER 0x000 +#define DDR_STOP_TIMER 0x004 +#define DDR_CLEAR_EVENT 0x008 +#define DDR_SET_TIMER_L 0x00c +#define DDR_SET_TIMER_H 0x010 +#define DDR_TRIG_MODE 0x014 +#define DDR_NOW_STATE 0x0e0 +#define DDR_EVENT_CYCLES 0x0e4 +#define DDR_TPOINT_END_L 0x0e4 +#define DDR_TPOINT_END_H 0x0e8 +#define DDR_STATE_STOP 0x0ec +#define DDR_EVENT_RXREQ 0x100 +#define DDR_EVENT_RXDAT 0x104 +#define DDR_EVENT_TXDAT 0x108 +#define DDR_EVENT_RXREQ_RNS 0x10c +#define DDR_EVENT_RXREQ_WNSP 0x110 +#define DDR_EVENT_RXREQ_WNSF 0x114 +#define DDR_EVENT_BANDWIDTH 0x200 +#define DDR_W_DATA_BASE 0x200 +#define DDR_CLK_FRE 0xe00 +#define DDR_DATA_WIDTH 0xe04 + +#define DDR_PMU_OFL_STOP_TYPE_VAL 0x10 #define to_phytium_ddr_pmu(p) (container_of(p, struct phytium_ddr_pmu, pmu)) +enum { + DDRV1P0 = 0x01, + DDRV1P5 = 0x02, +}; + static int phytium_ddr_pmu_hp_state; struct phytium_ddr_pmu_hwevents { @@ -68,15 +75,17 @@ struct phytium_ddr_pmu_hwevents { struct phytium_ddr_pmu { struct device *dev; void __iomem *base; - void __iomem *csr_base; + void __iomem *cfg_base; + void __iomem *irq_reg; struct pmu pmu; struct phytium_ddr_pmu_hwevents pmu_events; u32 die_id; u32 ddr_id; u32 pmu_id; - int bit_idx; + int irq_bit; int on_cpu; int irq; + int ver; struct hlist_node node; }; @@ -89,7 +98,6 @@ static const u32 ddr_counter_reg_offset[] = { DDR_EVENT_RXREQ_WNSF, DDR_EVENT_BANDWIDTH }; - ssize_t phytium_ddr_pmu_format_sysfs_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -97,6 +105,7 @@ ssize_t phytium_ddr_pmu_format_sysfs_show(struct device *dev, struct dev_ext_attribute *eattr; eattr = container_of(attr, struct dev_ext_attribute, attr); + return sprintf(buf, "%s\n", (char *)eattr->var); } @@ -112,7 +121,7 @@ ssize_t phytium_ddr_pmu_event_sysfs_show(struct device *dev, } static ssize_t cpumask_show(struct device *dev, struct device_attribute *attr, - char *buf) + char *buf) { struct phytium_ddr_pmu *ddr_pmu = to_phytium_ddr_pmu(dev_get_drvdata(dev)); @@ -120,22 +129,21 @@ static ssize_t cpumask_show(struct device *dev, struct device_attribute *attr, return cpumap_print_to_pagebuf(true, buf, cpumask_of(ddr_pmu->on_cpu)); } -#define PHYTIUM_PMU_ATTR(_name, _func, _config) \ - (&((struct dev_ext_attribute[]){ \ +#define PHYTIUM_PMU_ATTR(_name, _func, _config) \ + (&((struct dev_ext_attribute[]){ \ { __ATTR(_name, 0444, _func, NULL), (void *)_config } })[0] \ .attr.attr) -#define PHYTIUM_DDR_PMU_FORMAT_ATTR(_name, _config) \ - PHYTIUM_PMU_ATTR(_name, phytium_ddr_pmu_format_sysfs_show, \ +#define PHYTIUM_DDR_PMU_FORMAT_ATTR(_name, _config) \ + PHYTIUM_PMU_ATTR(_name, phytium_ddr_pmu_format_sysfs_show, \ (void *)_config) -#define PHYTIUM_DDR_PMU_EVENT_ATTR(_name, _config) \ - PHYTIUM_PMU_ATTR(_name, phytium_ddr_pmu_event_sysfs_show, \ - (unsigned long)_config) +#define PHYTIUM_DDR_PMU_EVENT_ATTR(_name, _config) \ + PHYTIUM_PMU_ATTR(_name, phytium_ddr_pmu_event_sysfs_show, \ + (unsigned long)_config) static struct attribute *phytium_ddr_pmu_format_attr[] = { PHYTIUM_DDR_PMU_FORMAT_ATTR(event, "config:0-2"), - PHYTIUM_DDR_PMU_FORMAT_ATTR(timer, "config1:0-31"), NULL, }; @@ -179,11 +187,6 @@ static const struct attribute_group *phytium_ddr_pmu_attr_groups[] = { NULL, }; -static u32 phytium_ddr_pmu_get_event_timer(struct perf_event *event) -{ - return FIELD_GET(GENMASK(31, 0), event->attr.config1); -} - static u64 phytium_ddr_pmu_read_counter(struct phytium_ddr_pmu *ddr_pmu, struct hw_perf_event *hwc) { @@ -223,18 +226,24 @@ static void phytium_ddr_pmu_enable_clk(struct phytium_ddr_pmu *ddr_pmu) { u32 val; - val = readl(ddr_pmu->csr_base); + if (ddr_pmu->ver == DDRV1P5) + return; + + val = readl(ddr_pmu->cfg_base); val |= 0xF; - writel(val, ddr_pmu->csr_base); + writel(val, ddr_pmu->cfg_base); } static void phytium_ddr_pmu_disable_clk(struct phytium_ddr_pmu *ddr_pmu) { u32 val; - val = readl(ddr_pmu->csr_base); + if (ddr_pmu->ver == DDRV1P5) + return; + + val = readl(ddr_pmu->cfg_base); val &= ~(0xF); - writel(val, ddr_pmu->csr_base); + writel(val, ddr_pmu->cfg_base); } static void phytium_ddr_pmu_clear_all_counters(struct phytium_ddr_pmu *ddr_pmu) @@ -252,29 +261,6 @@ static void phytium_ddr_pmu_stop_all_counters(struct phytium_ddr_pmu *ddr_pmu) writel(0x1, ddr_pmu->base + DDR_STOP_TIMER); } -static void phytium_ddr_pmu_set_timer(struct phytium_ddr_pmu *ddr_pmu, - u32 th_val) -{ - u32 val; - - val = readl(ddr_pmu->base + DDR_SET_TIMER_L); - val = readl(ddr_pmu->base + DDR_SET_TIMER_H); - - writel(th_val, ddr_pmu->base + DDR_SET_TIMER_L); - writel(0, ddr_pmu->base + DDR_SET_TIMER_H); -} - -static void phytium_ddr_pmu_reset_timer(struct phytium_ddr_pmu *ddr_pmu) -{ - u32 val; - - val = readl(ddr_pmu->base + DDR_SET_TIMER_L); - val = readl(ddr_pmu->base + DDR_SET_TIMER_H); - - writel(0xFFFFFFFF, ddr_pmu->base + DDR_SET_TIMER_L); - writel(0xFFFFFFFF, ddr_pmu->base + DDR_SET_TIMER_H); -} - static unsigned long phytium_ddr_pmu_get_stop_state(struct phytium_ddr_pmu *ddr_pmu) { @@ -289,7 +275,7 @@ phytium_ddr_pmu_get_irq_flag(struct phytium_ddr_pmu *ddr_pmu) { unsigned long val; - val = (unsigned long)readl(ddr_pmu->csr_base + 4); + val = (unsigned long)readl(ddr_pmu->irq_reg); return val; } @@ -324,7 +310,6 @@ int phytium_ddr_pmu_event_init(struct perf_event *event) { struct hw_perf_event *hwc = &event->hw; struct phytium_ddr_pmu *ddr_pmu; - u32 event_timer; if (event->attr.type != event->pmu->type) return -ENOENT; @@ -345,10 +330,6 @@ int phytium_ddr_pmu_event_init(struct perf_event *event) if (ddr_pmu->on_cpu == -1) return -EINVAL; - event_timer = phytium_ddr_pmu_get_event_timer(event); - if (event_timer != 0) - phytium_ddr_pmu_set_timer(ddr_pmu, event_timer); - hwc->idx = -1; hwc->config_base = event->attr.config; @@ -407,17 +388,10 @@ void phytium_ddr_pmu_event_del(struct perf_event *event, int flags) { struct phytium_ddr_pmu *ddr_pmu = to_phytium_ddr_pmu(event->pmu); struct hw_perf_event *hwc = &event->hw; - unsigned long val; - u32 event_timer; phytium_ddr_pmu_event_stop(event, PERF_EF_UPDATE); - val = phytium_ddr_pmu_get_irq_flag(ddr_pmu); - val = phytium_ddr_pmu_get_stop_state(ddr_pmu); - phytium_ddr_pmu_unmark_event(ddr_pmu, hwc->idx); - event_timer = phytium_ddr_pmu_get_event_timer(event); - if (event_timer != 0) - phytium_ddr_pmu_reset_timer(ddr_pmu); + phytium_ddr_pmu_unmark_event(ddr_pmu, hwc->idx); perf_event_update_userpage(event); ddr_pmu->pmu_events.hw_events[hwc->idx] = NULL; @@ -445,10 +419,15 @@ void phytium_ddr_pmu_disable(struct pmu *pmu) phytium_ddr_pmu_stop_all_counters(ddr_pmu); } +void phytium_ddr_pmu_reset(struct phytium_ddr_pmu *ddr_pmu) +{ + phytium_ddr_pmu_disable_clk(ddr_pmu); + phytium_ddr_pmu_clear_all_counters(ddr_pmu); +} + static const struct acpi_device_id phytium_ddr_pmu_acpi_match[] = { - { - "PHYT0043", - }, + { "PHYT0043", }, + { "PHYT0067", }, {}, }; MODULE_DEVICE_TABLE(acpi, phytium_ddr_pmu_acpi_match); @@ -458,14 +437,13 @@ static irqreturn_t phytium_ddr_pmu_overflow_handler(int irq, void *dev_id) struct phytium_ddr_pmu *ddr_pmu = dev_id; struct perf_event *event; unsigned long overflown, stop_state; - int idx; unsigned long *used_mask = ddr_pmu->pmu_events.used_mask; - + int idx; int event_added = bitmap_weight(used_mask, PHYTIUM_DDR_MAX_COUNTERS); overflown = phytium_ddr_pmu_get_irq_flag(ddr_pmu); - if (!test_bit(ddr_pmu->bit_idx, &overflown)) + if (!test_bit(ddr_pmu->irq_bit, &overflown)) return IRQ_NONE; stop_state = phytium_ddr_pmu_get_stop_state(ddr_pmu); @@ -477,8 +455,10 @@ static irqreturn_t phytium_ddr_pmu_overflow_handler(int irq, void *dev_id) continue; phytium_ddr_pmu_event_update(event); } + phytium_ddr_pmu_clear_all_counters(ddr_pmu); - phytium_ddr_pmu_start_all_counters(ddr_pmu); + if ((stop_state & DDR_PMU_OFL_STOP_TYPE_VAL) == 0) + phytium_ddr_pmu_start_all_counters(ddr_pmu); return IRQ_HANDLED; } @@ -491,6 +471,24 @@ static irqreturn_t phytium_ddr_pmu_overflow_handler(int irq, void *dev_id) return IRQ_NONE; } +static int phytium_ddr_pmu_version(struct platform_device *pdev, + struct phytium_ddr_pmu *ddr_pmu) +{ + struct acpi_device *acpi_dev; + + acpi_dev = ACPI_COMPANION(&pdev->dev); + if (!strcmp(acpi_device_hid(acpi_dev), "PHYT0043")) { + ddr_pmu->ver = DDRV1P0; + } else if (!strcmp(acpi_device_hid(acpi_dev), "PHYT0067")) { + ddr_pmu->ver = DDRV1P5; + } else { + dev_err(&pdev->dev, "The current driver does not support this device.\n"); + return -ENODEV; + } + + return 0; +} + static int phytium_ddr_pmu_init_irq(struct phytium_ddr_pmu *ddr_pmu, struct platform_device *pdev) { @@ -518,7 +516,7 @@ static int phytium_ddr_pmu_init_irq(struct phytium_ddr_pmu *ddr_pmu, static int phytium_ddr_pmu_init_data(struct platform_device *pdev, struct phytium_ddr_pmu *ddr_pmu) { - struct resource *res, *clkres; + struct resource *res, *clkres, *irqres; if (device_property_read_u32(&pdev->dev, "phytium,die-id", &ddr_pmu->die_id)) { @@ -538,7 +536,7 @@ static int phytium_ddr_pmu_init_data(struct platform_device *pdev, return -EINVAL; } - ddr_pmu->bit_idx = ddr_pmu->ddr_id * 2 + ddr_pmu->pmu_id; + ddr_pmu->irq_bit = ddr_pmu->ddr_id * 2 + ddr_pmu->pmu_id; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ddr_pmu->base = devm_ioremap_resource(&pdev->dev, res); @@ -554,15 +552,29 @@ static int phytium_ddr_pmu_init_data(struct platform_device *pdev, dev_err(&pdev->dev, "failed for get ddr_pmu clk resource.\n"); return -EINVAL; } + ddr_pmu->cfg_base = devm_ioremap(&pdev->dev, clkres->start, resource_size(clkres)); + if (IS_ERR(ddr_pmu->cfg_base)) { + dev_err(&pdev->dev, "ioremap failed for ddr_pmu clk resource\n"); + return PTR_ERR(ddr_pmu->cfg_base); + } - ddr_pmu->csr_base = - devm_ioremap(&pdev->dev, clkres->start, resource_size(clkres)); - if (IS_ERR(ddr_pmu->csr_base)) { - dev_err(&pdev->dev, - "ioremap failed for ddr_pmu csr resource\n"); - return PTR_ERR(ddr_pmu->csr_base); + if (ddr_pmu->ver == DDRV1P5) { + irqres = platform_get_resource(pdev, IORESOURCE_MEM, 2); + if (!irqres) { + dev_err(&pdev->dev, "failed for get ddr_pmu irq resource.\n"); + return -EINVAL; + } + ddr_pmu->irq_reg = devm_ioremap(&pdev->dev, irqres->start, resource_size(irqres)); + if (IS_ERR(ddr_pmu->irq_reg)) { + dev_err(&pdev->dev, "ioremap failed for ddr_pmu irq resource\n"); + return PTR_ERR(ddr_pmu->irq_reg); + } + } else { + ddr_pmu->irq_reg = ddr_pmu->cfg_base + 0x4; } + phytium_ddr_pmu_reset(ddr_pmu); + return 0; } @@ -571,6 +583,10 @@ static int phytium_ddr_pmu_dev_probe(struct platform_device *pdev, { int ret; + ret = phytium_ddr_pmu_version(pdev, ddr_pmu); + if (ret) + return ret; + ret = phytium_ddr_pmu_init_data(pdev, ddr_pmu); if (ret) return ret; @@ -601,8 +617,8 @@ static int phytium_ddr_pmu_probe(struct platform_device *pdev) if (ret) return ret; - ret = cpuhp_state_add_instance( - phytium_ddr_pmu_hp_state, &ddr_pmu->node); + ret = cpuhp_state_add_instance(phytium_ddr_pmu_hp_state, + &ddr_pmu->node); if (ret) { dev_err(&pdev->dev, "Error %d registering hotplug;\n", ret); return ret; @@ -624,22 +640,19 @@ static int phytium_ddr_pmu_probe(struct platform_device *pdev) .stop = phytium_ddr_pmu_event_stop, .read = phytium_ddr_pmu_event_update, .attr_groups = phytium_ddr_pmu_attr_groups, - .capabilities = PERF_PMU_CAP_NO_EXCLUDE, }; ret = perf_pmu_register(&ddr_pmu->pmu, name, -1); if (ret) { dev_err(ddr_pmu->dev, "DDR PMU register failed!\n"); - cpuhp_state_remove_instance_nocalls( - phytium_ddr_pmu_hp_state, + cpuhp_state_remove_instance_nocalls(phytium_ddr_pmu_hp_state, &ddr_pmu->node); } phytium_ddr_pmu_enable_clk(ddr_pmu); - pr_info("Phytium DDR PMU: "); - pr_info(" die_id = %d ddr_id = %d pmu_id = %d.\n", ddr_pmu->die_id, - ddr_pmu->ddr_id, ddr_pmu->pmu_id); + pr_info("die%d_ddr%d_pmu%d on cpu%d.\n", ddr_pmu->die_id, + ddr_pmu->ddr_id, ddr_pmu->pmu_id, ddr_pmu->on_cpu); return ret; } @@ -651,8 +664,8 @@ static int phytium_ddr_pmu_remove(struct platform_device *pdev) phytium_ddr_pmu_disable_clk(ddr_pmu); perf_pmu_unregister(&ddr_pmu->pmu); - cpuhp_state_remove_instance_nocalls( - phytium_ddr_pmu_hp_state, &ddr_pmu->node); + cpuhp_state_remove_instance_nocalls(phytium_ddr_pmu_hp_state, + &ddr_pmu->node); return 0; } @@ -754,3 +767,4 @@ MODULE_DESCRIPTION("Phytium DDR PMU driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(DDR_PERF_DRIVER_VERSION); MODULE_AUTHOR("Hu Xianghua "); +MODULE_AUTHOR("Tan Rui "); -- Gitee From fb404501df6939c898d21e8d2b818ae39c0d6183 Mon Sep 17 00:00:00 2001 From: Tan Rui Date: Tue, 18 Feb 2025 14:54:30 +0800 Subject: [PATCH 027/155] drivers/perf:phytium: Add PCIe PMU Support for PS240XX. Add a new HID to differentiate between PS230XX and PS240XX PCIe PMU and add support for PS240XX platforms. Mainline: NA Signed-off-by: Tan Rui Signed-off-by: Wang Yinfeng Change-Id: Ib2fc590a2e8ce7b394afc3daa487a3ad5b23ec05 --- drivers/perf/phytium/phytium_pcie_pmu.c | 413 ++++++++++++++---------- 1 file changed, 240 insertions(+), 173 deletions(-) diff --git a/drivers/perf/phytium/phytium_pcie_pmu.c b/drivers/perf/phytium/phytium_pcie_pmu.c index 9b73aded43..7f3294d168 100644 --- a/drivers/perf/phytium/phytium_pcie_pmu.c +++ b/drivers/perf/phytium/phytium_pcie_pmu.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -30,52 +31,54 @@ #undef pr_fmt #define pr_fmt(fmt) "phytium_pcie_pmu: " fmt -#define PCIE_PERF_DRIVER_VERSION "1.2.1" +#define PCIE_PERF_DRIVER_VERSION "1.3.0" #define PHYTIUM_PCIE_MAX_COUNTERS 18 -#define PCIE_START_TIMER 0x000 -#define PCIE_STOP_TIMER 0x004 -#define PCIE_CLEAR_EVENT 0x008 -#define PCIE_SET_TIMER_L 0x00c -#define PCIE_SET_TIMER_H 0x010 -#define PCIE_TRIG_MODE 0x014 - -#define PCIE_NOW_STATE 0x0e0 -#define PCIE_EVENT_CYCLES 0x0e4 -#define PCIE_TPOINT_END_L 0x0e4 -#define PCIE_TPOINT_END_H 0x0e8 -#define PCIE_STATE_STOP 0x0ec - -#define PCIE_EVENT_AW 0x100 -#define PCIE_EVENT_W_LAST 0x104 -#define PCIE_EVENT_B 0x108 -#define PCIE_EVENT_AR 0x10c -#define PCIE_EVENT_R_LAST 0x110 -#define PCIE_EVENT_R_FULL 0x114 -#define PCIE_EVENT_R_ERR 0x118 -#define PCIE_EVENT_W_ERR 0x11c -#define PCIE_EVENT_DELAY_RD 0x120 -#define PCIE_EVENT_DELAY_WR 0x124 -#define PCIE_EVENT_RD_MAX 0x128 -#define PCIE_EVENT_RD_MIN 0x12c -#define PCIE_EVENT_WR_MAX 0x130 -#define PCIE_EVENT_WR_MIN 0x134 - -#define PCIE_EVENT_W_DATA 0x200 -#define PCIE_W_DATA_BASE 0x200 - -#define PCIE_EVENT_RDELAY_TIME 0x300 -#define PCIE_RDELAY_TIME_BASE 0x300 - -#define PCIE_EVENT_WDELAY_TIME 0x700 -#define PCIE_WDELAY_TIME_BASE 0x700 - -#define PCIE_CLK_FRE 0xe00 -#define PCIE_DATA_WIDTH 0xe04 +#define PCIE_START_TIMER 0x000 +#define PCIE_STOP_TIMER 0x004 +#define PCIE_CLEAR_EVENT 0x008 + +#define PCIE_EVENT_CYCLES 0x0e4 +#define PCIE_TPOINT_END_L 0x0e4 +#define PCIE_TPOINT_END_H 0x0e8 +#define PCIE_STATE_STOP 0x0ec + +#define PCIE_EVENT_AW 0x100 +#define PCIE_EVENT_W_LAST 0x104 +#define PCIE_EVENT_B 0x108 +#define PCIE_EVENT_AR 0x10c +#define PCIE_EVENT_R_LAST 0x110 +#define PCIE_EVENT_R_FULL 0x114 +#define PCIE_EVENT_R_ERR 0x118 +#define PCIE_EVENT_W_ERR 0x11c +#define PCIE_EVENT_DELAY_RD 0x120 +#define PCIE_EVENT_DELAY_WR 0x124 +#define PCIE_EVENT_RD_MAX 0x128 +#define PCIE_EVENT_RD_MIN 0x12c +#define PCIE_EVENT_WR_MAX 0x130 +#define PCIE_EVENT_WR_MIN 0x134 + +#define PCIE_EVENT_W_DATA 0x200 +#define PCIE_W_DATA_BASE 0x200 + +#define PCIE_EVENT_RDELAY_TIME 0x300 +#define PCIE_RDELAY_TIME_BASE 0x300 + +#define PCIE_EVENT_WDELAY_TIME 0x700 +#define PCIE_WDELAY_TIME_BASE 0x700 + +#define PCIE_DATA_WIDTH 0xe04 +#define PCIE_PMU_OFL_STOP_TYPE_VAL 0x10 #define to_phytium_pcie_pmu(p) (container_of(p, struct phytium_pcie_pmu, pmu)) +enum { + PCIEV1P0 = 0x1, + PCIEV1P5 = 0x2, +}; + + static int phytium_pcie_pmu_hp_state; struct phytium_pcie_pmu_hwevents { @@ -86,17 +89,20 @@ struct phytium_pcie_pmu_hwevents { struct phytium_pcie_pmu { struct device *dev; void __iomem *base; - void __iomem *csr_base; + void __iomem *cfg_base; void __iomem *irq_reg; struct pmu pmu; struct phytium_pcie_pmu_hwevents pmu_events; u32 die_id; + u32 pcie_id; u32 pmu_id; int on_cpu; int irq; + int irq_bit; struct hlist_node node; int ctrler_id; int real_ctrler; + int ver; u32 clk_bits; }; @@ -160,7 +166,6 @@ static ssize_t cpumask_show(struct device *dev, struct device_attribute *attr, static struct attribute *phytium_pcie_pmu_format_attr[] = { PHYTIUM_PCIE_PMU_FORMAT_ATTR(event, "config:0-4"), PHYTIUM_PCIE_PMU_FORMAT_ATTR(ctrler, "config:8-10"), - PHYTIUM_PCIE_PMU_FORMAT_ATTR(timer, "config1:0-31"), NULL, }; @@ -219,11 +224,6 @@ static u32 phytium_pcie_pmu_get_event_ctrler(struct perf_event *event) return FIELD_GET(GENMASK(10, 8), event->attr.config); } -static u32 phytium_pcie_pmu_get_event_timer(struct perf_event *event) -{ - return FIELD_GET(GENMASK(31, 0), event->attr.config1); -} - static u64 phytium_pcie_pmu_read_counter(struct phytium_pcie_pmu *pcie_pmu, struct hw_perf_event *hwc) { @@ -233,12 +233,16 @@ static u64 phytium_pcie_pmu_read_counter(struct phytium_pcie_pmu *pcie_pmu, u64 val64 = 0; int i; u32 counter_offset = pcie_counter_reg_offset[idx]; + u32 rdelay_num = 127; if (!EVENT_VALID(idx)) { dev_err(pcie_pmu->dev, "Unsupported event index:%d!\n", idx); return 0; } + if (pcie_pmu->ver == PCIEV1P5 && pcie_pmu->pmu_id == 3) + rdelay_num = 63; + switch (idx) { case 0: cycle_l = readl(pcie_pmu->base + counter_offset); @@ -253,7 +257,7 @@ static u64 phytium_pcie_pmu_read_counter(struct phytium_pcie_pmu *pcie_pmu, } break; case 16: - for (i = 0; i <= 127; i = i + 2) { + for (i = 0; i <= rdelay_num; i = i + 2) { rdelay_l = readl(pcie_pmu->base + counter_offset + 4 * i); rdelay_h = readl(pcie_pmu->base + counter_offset + @@ -281,38 +285,40 @@ static void phytium_pcie_pmu_enable_clk(struct phytium_pcie_pmu *pcie_pmu) { u32 val; - val = readl(pcie_pmu->csr_base); + val = readl(pcie_pmu->cfg_base); val |= (pcie_pmu->clk_bits); - writel(val, pcie_pmu->csr_base); + writel(val, pcie_pmu->cfg_base); } static void phytium_pcie_pmu_disable_clk(struct phytium_pcie_pmu *pcie_pmu) { u32 val; - val = readl(pcie_pmu->csr_base); + val = readl(pcie_pmu->cfg_base); val &= ~(pcie_pmu->clk_bits); - writel(val, pcie_pmu->csr_base); + writel(val, pcie_pmu->cfg_base); } static void phytium_pcie_pmu_select_ctrler(struct phytium_pcie_pmu *pcie_pmu) { - u32 val, offset = 0; - - if (pcie_pmu->pmu_id != 2) - offset = 0xc; + u32 val, offset; + u32 mask = 0xfffffffc; - val = readl(pcie_pmu->csr_base + offset); - - if (pcie_pmu->pmu_id == 2) { - val &= 0xffffffcf; - val |= pcie_pmu->real_ctrler; + if (pcie_pmu->ver == PCIEV1P0) { + if (pcie_pmu->pmu_id == 2) { + mask = 0xffffffcf; + offset = 0x0; + } else + offset = 0xc; } else { - val &= 0xfffffffc; - val |= pcie_pmu->real_ctrler; + offset = 0x170; } - writel(val, pcie_pmu->csr_base + offset); + val = readl(pcie_pmu->cfg_base + offset); + val &= mask; + val |= pcie_pmu->real_ctrler; + writel(val, pcie_pmu->cfg_base + offset); + } static void @@ -333,29 +339,6 @@ phytium_pcie_pmu_stop_all_counters(struct phytium_pcie_pmu *pcie_pmu) writel(0x1, pcie_pmu->base + PCIE_STOP_TIMER); } -static void phytium_pcie_pmu_set_timer(struct phytium_pcie_pmu *pcie_pmu, - u32 th_val) -{ - u32 val; - - val = readl(pcie_pmu->base + PCIE_SET_TIMER_L); - val = readl(pcie_pmu->base + PCIE_SET_TIMER_H); - - writel(th_val, pcie_pmu->base + PCIE_SET_TIMER_L); - writel(0, pcie_pmu->base + PCIE_SET_TIMER_H); -} - -static void phytium_pcie_pmu_reset_timer(struct phytium_pcie_pmu *pcie_pmu) -{ - u32 val; - - val = readl(pcie_pmu->base + PCIE_SET_TIMER_L); - val = readl(pcie_pmu->base + PCIE_SET_TIMER_H); - - writel(0xFFFFFFFF, pcie_pmu->base + PCIE_SET_TIMER_L); - writel(0xFFFFFFFF, pcie_pmu->base + PCIE_SET_TIMER_H); -} - static unsigned long phytium_pcie_pmu_get_stop_state(struct phytium_pcie_pmu *pcie_pmu) { @@ -405,7 +388,7 @@ int phytium_pcie_pmu_event_init(struct perf_event *event) { struct hw_perf_event *hwc = &event->hw; struct phytium_pcie_pmu *pcie_pmu; - u32 event_ctrler, event_timer; + u32 event_ctrler; if (event->attr.type != event->pmu->type) return -ENOENT; @@ -426,57 +409,83 @@ int phytium_pcie_pmu_event_init(struct perf_event *event) if (pcie_pmu->on_cpu == -1) return -EINVAL; - event_timer = phytium_pcie_pmu_get_event_timer(event); - if (event_timer != 0) - phytium_pcie_pmu_set_timer(pcie_pmu, event_timer); - - event_ctrler = phytium_pcie_pmu_get_event_ctrler(event); - switch (pcie_pmu->pmu_id) { - case 0: - if (event_ctrler != 0) { - dev_warn(pcie_pmu->dev, - "Wrong ctrler id(%d) for pcie-pmu0!\n", - event_ctrler); - return -EINVAL; + if (pcie_pmu->ver == PCIEV1P5) { + event_ctrler = phytium_pcie_pmu_get_event_ctrler(event); + if (pcie_pmu->pmu_id == 2) { + if (event_ctrler == 0) + event_ctrler = 2; + else if ((event_ctrler < 2) || (event_ctrler > 3)) { + dev_warn(pcie_pmu->dev, "Wrong ctrler id(%d) for pcie-pmu2!\n", + event_ctrler); + return -EINVAL; + } + if (pcie_pmu->ctrler_id != event_ctrler) { + pcie_pmu->ctrler_id = event_ctrler; + pcie_pmu->real_ctrler = pcie_pmu->ctrler_id; + phytium_pcie_pmu_select_ctrler(pcie_pmu); + } + } else { + if (event_ctrler != 0) { + dev_warn(pcie_pmu->dev, "Don't need to set ctrler id(%d) for pcie-pmu%d!\n", + event_ctrler, pcie_pmu->pmu_id); + return -EINVAL; + } + pcie_pmu->ctrler_id = pcie_pmu->pmu_id; + pcie_pmu->real_ctrler = pcie_pmu->ctrler_id; } - break; - case 1: - if ((event_ctrler < 1) || (event_ctrler > 3)) { - dev_warn(pcie_pmu->dev, - "Wrong ctrler id(%d) for pcie-pmu1!\n", - event_ctrler); + } else { + event_ctrler = phytium_pcie_pmu_get_event_ctrler(event); + switch (pcie_pmu->pmu_id) { + case 0: + if (event_ctrler != 0) { + dev_warn(pcie_pmu->dev, + "Wrong ctrler id(%d) for pcie-pmu0!\n", + event_ctrler); + return -EINVAL; + } + break; + case 1: + if (event_ctrler == 0) + event_ctrler = 1; + else if ((event_ctrler < 1) || (event_ctrler > 3)) { + dev_warn(pcie_pmu->dev, + "Wrong ctrler id(%d) for pcie-pmu1!\n", + event_ctrler); + return -EINVAL; + } + break; + case 2: + if (event_ctrler == 0) + event_ctrler = 4; + else if ((event_ctrler < 4) || (event_ctrler > 7)) { + dev_warn(pcie_pmu->dev, + "Wrong ctrler id(%d) for pcie-pmu2!\n", + event_ctrler); + return -EINVAL; + } + break; + default: + dev_err(pcie_pmu->dev, "Unsupported pmu id:%d!\n", + pcie_pmu->pmu_id); return -EINVAL; } - break; - case 2: - if ((event_ctrler < 4) || (event_ctrler > 7)) { - dev_warn(pcie_pmu->dev, - "Wrong ctrler id(%d) for pcie-pmu2!\n", - event_ctrler); + + pcie_pmu->ctrler_id = event_ctrler; + switch (pcie_pmu->pmu_id) { + case 0: + case 1: + pcie_pmu->real_ctrler = pcie_pmu->ctrler_id; + break; + case 2: + pcie_pmu->real_ctrler = (pcie_pmu->ctrler_id - 4) * 16; + break; + default: + dev_err(pcie_pmu->dev, "Unsupported pmu id:%d!\n", + pcie_pmu->pmu_id); return -EINVAL; } - break; - default: - dev_err(pcie_pmu->dev, "Unsupported pmu id:%d!\n", - pcie_pmu->pmu_id); - return -EINVAL; - } - - pcie_pmu->ctrler_id = event_ctrler; - switch (pcie_pmu->pmu_id) { - case 0: - case 1: - pcie_pmu->real_ctrler = pcie_pmu->ctrler_id; - break; - case 2: - pcie_pmu->real_ctrler = (pcie_pmu->ctrler_id - 4) * 16; - break; - default: - dev_err(pcie_pmu->dev, "Unsupported pmu id:%d!\n", - pcie_pmu->pmu_id); - return -EINVAL; + phytium_pcie_pmu_select_ctrler(pcie_pmu); } - phytium_pcie_pmu_select_ctrler(pcie_pmu); hwc->idx = -1; hwc->config_base = event->attr.config; @@ -535,17 +544,10 @@ void phytium_pcie_pmu_event_del(struct perf_event *event, int flags) { struct phytium_pcie_pmu *pcie_pmu = to_phytium_pcie_pmu(event->pmu); struct hw_perf_event *hwc = &event->hw; - unsigned long val; - u32 event_timer; phytium_pcie_pmu_event_stop(event, PERF_EF_UPDATE); - val = phytium_pcie_pmu_get_irq_flag(pcie_pmu); - val = phytium_pcie_pmu_get_stop_state(pcie_pmu); - phytium_pcie_pmu_unmark_event(pcie_pmu, hwc->idx); - event_timer = phytium_pcie_pmu_get_event_timer(event); - if (event_timer != 0) - phytium_pcie_pmu_reset_timer(pcie_pmu); + phytium_pcie_pmu_unmark_event(pcie_pmu, hwc->idx); perf_event_update_userpage(event); pcie_pmu->pmu_events.hw_events[hwc->idx] = NULL; @@ -573,10 +575,15 @@ void phytium_pcie_pmu_disable(struct pmu *pmu) phytium_pcie_pmu_stop_all_counters(pcie_pmu); } +void phytium_pcie_pmu_reset(struct phytium_pcie_pmu *pcie_pmu) +{ + phytium_pcie_pmu_disable_clk(pcie_pmu); + phytium_pcie_pmu_clear_all_counters(pcie_pmu); +} + static const struct acpi_device_id phytium_pcie_pmu_acpi_match[] = { - { - "PHYT0044", - }, + { "PHYT0044", }, + { "PHYT0068", }, {}, }; MODULE_DEVICE_TABLE(acpi, phytium_pcie_pmu_acpi_match); @@ -592,7 +599,7 @@ static irqreturn_t phytium_pcie_pmu_overflow_handler(int irq, void *dev_id) overflown = phytium_pcie_pmu_get_irq_flag(pcie_pmu); - if (!test_bit(pcie_pmu->pmu_id + 4, &overflown)) + if (!test_bit(pcie_pmu->irq_bit, &overflown)) return IRQ_NONE; stop_state = phytium_pcie_pmu_get_stop_state(pcie_pmu); @@ -605,7 +612,8 @@ static irqreturn_t phytium_pcie_pmu_overflow_handler(int irq, void *dev_id) phytium_pcie_pmu_event_update(event); } phytium_pcie_pmu_clear_all_counters(pcie_pmu); - phytium_pcie_pmu_start_all_counters(pcie_pmu); + if ((stop_state & PCIE_PMU_OFL_STOP_TYPE_VAL) == 0) + phytium_pcie_pmu_start_all_counters(pcie_pmu); return IRQ_HANDLED; } @@ -616,6 +624,25 @@ static irqreturn_t phytium_pcie_pmu_overflow_handler(int irq, void *dev_id) return IRQ_NONE; } +static int phytium_pcie_pmu_version(struct platform_device *pdev, + struct phytium_pcie_pmu *pcie_pmu) +{ + struct acpi_device *acpi_dev; + + acpi_dev = ACPI_COMPANION(&pdev->dev); + if (!strcmp(acpi_device_hid(acpi_dev), "PHYT0044")) { + pcie_pmu->ver = PCIEV1P0; + } else if (!strcmp(acpi_device_hid(acpi_dev), "PHYT0068")) { + pcie_pmu->ver = PCIEV1P5; + } else { + dev_err(&pdev->dev, "The current driver does not support this device.\n"); + return -ENODEV; + + } + + return 0; +} + static int phytium_pcie_pmu_init_irq(struct phytium_pcie_pmu *pcie_pmu, struct platform_device *pdev) { @@ -641,7 +668,7 @@ static int phytium_pcie_pmu_init_irq(struct phytium_pcie_pmu *pcie_pmu, } static int phytium_pcie_pmu_init_data(struct platform_device *pdev, - struct phytium_pcie_pmu *pcie_pmu) + struct phytium_pcie_pmu *pcie_pmu) { struct resource *res, *clkres, *irqres; @@ -657,20 +684,46 @@ static int phytium_pcie_pmu_init_data(struct platform_device *pdev, return -EINVAL; } - switch (pcie_pmu->pmu_id) { - case 0: - pcie_pmu->clk_bits = 0x1; - break; - case 1: - pcie_pmu->clk_bits = 0xe; - break; - case 2: - pcie_pmu->clk_bits = 0xf; - break; - default: - dev_err(&pdev->dev, "Unsupported pmu id:%d!\n", - pcie_pmu->pmu_id); - break; + if (pcie_pmu->ver == PCIEV1P0) { + switch (pcie_pmu->pmu_id) { + case 0: + pcie_pmu->clk_bits = 0x1; + break; + case 1: + pcie_pmu->clk_bits = 0xe; + break; + case 2: + pcie_pmu->clk_bits = 0xf; + break; + default: + dev_err(&pdev->dev, "Unsupported pmu id:%d!\n", pcie_pmu->pmu_id); + break; + } + + pcie_pmu->irq_bit = pcie_pmu->pmu_id + 4; + } else { + if (device_property_read_u32(&pdev->dev, "phytium,pcie-id", &pcie_pmu->pcie_id)) { + dev_err(&pdev->dev, "Can not read phytium,pcie-id!\n"); + return -EINVAL; + } + + switch (pcie_pmu->pmu_id) { + case 0: + case 3: + pcie_pmu->clk_bits = 0x1; + break; + case 1: + pcie_pmu->clk_bits = 0x2; + break; + case 2: + pcie_pmu->clk_bits = 0xc; + break; + default: + dev_err(&pdev->dev, "Unsupported pmu id:%d!\n", pcie_pmu->pmu_id); + break; + } + + pcie_pmu->irq_bit = pcie_pmu->pcie_id * 4 + pcie_pmu->pmu_id + 16; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -686,12 +739,12 @@ static int phytium_pcie_pmu_init_data(struct platform_device *pdev, return -EINVAL; } - pcie_pmu->csr_base = + pcie_pmu->cfg_base = devm_ioremap(&pdev->dev, clkres->start, resource_size(clkres)); - if (IS_ERR(pcie_pmu->csr_base)) { + if (IS_ERR(pcie_pmu->cfg_base)) { dev_err(&pdev->dev, "ioremap failed for pcie_pmu csr resource\n"); - return PTR_ERR(pcie_pmu->csr_base); + return PTR_ERR(pcie_pmu->cfg_base); } irqres = platform_get_resource(pdev, IORESOURCE_MEM, 2); @@ -709,14 +762,20 @@ static int phytium_pcie_pmu_init_data(struct platform_device *pdev, return PTR_ERR(pcie_pmu->irq_reg); } + phytium_pcie_pmu_reset(pcie_pmu); + return 0; } static int phytium_pcie_pmu_dev_probe(struct platform_device *pdev, - struct phytium_pcie_pmu *pcie_pmu) + struct phytium_pcie_pmu *pcie_pmu) { int ret; + ret = phytium_pcie_pmu_version(pdev, pcie_pmu); + if (ret) + return ret; + ret = phytium_pcie_pmu_init_data(pdev, pcie_pmu); if (ret) return ret; @@ -754,8 +813,12 @@ static int phytium_pcie_pmu_probe(struct platform_device *pdev) return ret; } - name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "phyt%u_pcie_pmu%u", - pcie_pmu->die_id, pcie_pmu->pmu_id); + if (pcie_pmu->ver == PCIEV1P0) + name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "phyt%u_pcie_pmu%u", + pcie_pmu->die_id, pcie_pmu->pmu_id); + else + name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "phyt%u_pcie%u_pmu%u", + pcie_pmu->die_id, pcie_pmu->pcie_id, pcie_pmu->pmu_id); pcie_pmu->pmu = (struct pmu){ .name = name, .module = THIS_MODULE, @@ -769,7 +832,6 @@ static int phytium_pcie_pmu_probe(struct platform_device *pdev) .stop = phytium_pcie_pmu_event_stop, .read = phytium_pcie_pmu_event_update, .attr_groups = phytium_pcie_pmu_attr_groups, - .capabilities = PERF_PMU_CAP_NO_EXCLUDE, }; ret = perf_pmu_register(&pcie_pmu->pmu, name, -1); @@ -782,9 +844,12 @@ static int phytium_pcie_pmu_probe(struct platform_device *pdev) phytium_pcie_pmu_enable_clk(pcie_pmu); - pr_info("Phytium PCIe PMU: "); - pr_info("die_id = %d pmu_id = %d.\n", pcie_pmu->die_id, - pcie_pmu->pmu_id); + if (pcie_pmu->ver == PCIEV1P0) + pr_info("die%d_pcie_pmu%d on cpu%d.\n", + pcie_pmu->die_id, pcie_pmu->pmu_id, pcie_pmu->on_cpu); + else + pr_info("die%d_pcie%d_pmu%d on cpu%d.\n", + pcie_pmu->die_id, pcie_pmu->pcie_id, pcie_pmu->pmu_id, pcie_pmu->on_cpu); return ret; } @@ -826,6 +891,7 @@ int phytium_pcie_pmu_online_cpu(unsigned int cpu, struct hlist_node *node) pcie_pmu->on_cpu = cpu; WARN_ON(irq_set_affinity_hint(pcie_pmu->irq, cpumask_of(cpu))); } + return 0; } @@ -872,8 +938,8 @@ static int __init phytium_pcie_pmu_module_init(void) phytium_pcie_pmu_hp_state = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN, - "perf/phytium/pciepmu:online", - phytium_pcie_pmu_online_cpu, phytium_pcie_pmu_offline_cpu); + "perf/phytium/pciepmu:online", phytium_pcie_pmu_online_cpu, + phytium_pcie_pmu_offline_cpu); if (phytium_pcie_pmu_hp_state < 0) { pr_err("PCIE PMU: setup hotplug, ret = %d\n", phytium_pcie_pmu_hp_state); @@ -900,3 +966,4 @@ MODULE_DESCRIPTION("Phytium PCIe PMU driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(PCIE_PERF_DRIVER_VERSION); MODULE_AUTHOR("Hu Xianghua "); +MODULE_AUTHOR("Tan Rui "); -- Gitee From 7c3099d9fb849e065e3a200db3b14eb58dda09f7 Mon Sep 17 00:00:00 2001 From: Tan Rui Date: Fri, 20 Jun 2025 10:21:50 +0800 Subject: [PATCH 028/155] drivers/perf: phytium: Modify the name of DMU PMU cycles event. Add a prefix before the name of the pd2408 dmu pmu cycles event. Mainline: Open-Source Signed-off-by: Tan Rui Signed-off-by: Wang Yinfeng Change-Id: I98b5a8c474760231c482aaa416a20545c7426984 --- drivers/perf/phytium/phytium_dmu_pmu_pd2408.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/perf/phytium/phytium_dmu_pmu_pd2408.c b/drivers/perf/phytium/phytium_dmu_pmu_pd2408.c index df873b018c..4f0049c74c 100644 --- a/drivers/perf/phytium/phytium_dmu_pmu_pd2408.c +++ b/drivers/perf/phytium/phytium_dmu_pmu_pd2408.c @@ -31,7 +31,7 @@ #undef pr_fmt #define pr_fmt(fmt) "pd2408_dmu_pmu: " fmt -#define DMU_PERF_DRIVER_VERSION "1.0.0" +#define DMU_PERF_DRIVER_VERSION "1.0.1" #define DMU_PMU_TIMER_START 0x0 #define DMU_PMU_TIMER_STOP 0x4 @@ -151,7 +151,7 @@ static const struct attribute_group pd2408_dmu_pmu_format_group = { }; static struct attribute *pd2408_dmu_pmu_events_attr[] = { - PHYTIUM_DMU_PMU_EVENT_ATTR(cycles, 0x00), + PHYTIUM_DMU_PMU_EVENT_ATTR(dmu_axi_cycles, 0x00), PHYTIUM_DMU_PMU_EVENT_ATTR(axi_write_flux, 0x01), PHYTIUM_DMU_PMU_EVENT_ATTR(axi_read_flux, 0x02), PHYTIUM_DMU_PMU_EVENT_ATTR(axi_write_cmd, 0x03), -- Gitee From e16825961153b9fd50778b59bd8f483c3ab08869 Mon Sep 17 00:00:00 2001 From: Tan Rui Date: Fri, 20 Jun 2025 10:23:30 +0800 Subject: [PATCH 029/155] drivers/perf: phytium: Modify the name of DDR PMU cycles event. Add a prefix before the name of the ddr pmu cycles event. Mainline: Open-Source Signed-off-by: Tan Rui Signed-off-by: Wang Yinfeng Change-Id: I6dfd9325956ff9c4be6e51cdb102fa7644988b4c --- drivers/perf/phytium/phytium_ddr_pmu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/perf/phytium/phytium_ddr_pmu.c b/drivers/perf/phytium/phytium_ddr_pmu.c index 4c3475ddf9..2a28aa0ae2 100644 --- a/drivers/perf/phytium/phytium_ddr_pmu.c +++ b/drivers/perf/phytium/phytium_ddr_pmu.c @@ -32,7 +32,7 @@ #define pr_fmt(fmt) "phytium_ddr_pmu: " fmt #define PHYTIUM_DDR_MAX_COUNTERS 8 -#define DDR_PERF_DRIVER_VERSION "1.3.0" +#define DDR_PERF_DRIVER_VERSION "1.3.1" #define DDR_START_TIMER 0x000 #define DDR_STOP_TIMER 0x004 @@ -153,7 +153,7 @@ static const struct attribute_group phytium_ddr_pmu_format_group = { }; static struct attribute *phytium_ddr_pmu_events_attr[] = { - PHYTIUM_DDR_PMU_EVENT_ATTR(cycles, 0x00), + PHYTIUM_DDR_PMU_EVENT_ATTR(ddr_cycles, 0x00), PHYTIUM_DDR_PMU_EVENT_ATTR(rxreq, 0x01), PHYTIUM_DDR_PMU_EVENT_ATTR(rxdat, 0x02), PHYTIUM_DDR_PMU_EVENT_ATTR(txdat, 0x03), -- Gitee From d95e299ca9b8727553e1338f6947c075ac5202af Mon Sep 17 00:00:00 2001 From: Tan Rui Date: Fri, 20 Jun 2025 10:24:14 +0800 Subject: [PATCH 030/155] drivers/perf: phytium: Modify the name of PCIe PMU cycles event. Add a prefix before the name of the pcie pmu cycles event. Mainline: Open-Source Signed-off-by: Tan Rui Signed-off-by: Wang Yinfeng Change-Id: I293f842b3d002363dec857ab6470d8555a61bd97 --- drivers/perf/phytium/phytium_pcie_pmu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/perf/phytium/phytium_pcie_pmu.c b/drivers/perf/phytium/phytium_pcie_pmu.c index 7f3294d168..8f67636b0b 100644 --- a/drivers/perf/phytium/phytium_pcie_pmu.c +++ b/drivers/perf/phytium/phytium_pcie_pmu.c @@ -31,7 +31,7 @@ #undef pr_fmt #define pr_fmt(fmt) "phytium_pcie_pmu: " fmt -#define PCIE_PERF_DRIVER_VERSION "1.3.0" +#define PCIE_PERF_DRIVER_VERSION "1.3.1" #define PHYTIUM_PCIE_MAX_COUNTERS 18 @@ -175,7 +175,7 @@ static const struct attribute_group phytium_pcie_pmu_format_group = { }; static struct attribute *phytium_pcie_pmu_events_attr[] = { - PHYTIUM_PCIE_PMU_EVENT_ATTR(cycles, 0x00), + PHYTIUM_PCIE_PMU_EVENT_ATTR(pcie_cycles, 0x00), PHYTIUM_PCIE_PMU_EVENT_ATTR(aw, 0x01), PHYTIUM_PCIE_PMU_EVENT_ATTR(w_last, 0x02), PHYTIUM_PCIE_PMU_EVENT_ATTR(b, 0x03), -- Gitee From ba68e7e75fb46113981cc3dd2502e3d57e8bcc62 Mon Sep 17 00:00:00 2001 From: Tan Rui Date: Sun, 8 Jun 2025 12:09:50 +0800 Subject: [PATCH 031/155] drivers/perf: phytium: Fix issue with PS23X00 DDR PMU on PBF < 1.20. Fix a system panic issue caused by the PS23X00 DDR PMU on Phytium PBF firmware version below 1.20. Use the SMC instruction to retrieve the PBF version and enforce a requirement that the driver only loads if the PBF version is greater than or equal to 1.20. Mainline: Open-Source Signed-off-by: Tan Rui Signed-off-by: Wang Yinfeng Change-Id: Ia2d495ff8981b723d26ffc66838d18243b04e0bd --- drivers/perf/phytium/phytium_ddr_pmu.c | 35 +++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/drivers/perf/phytium/phytium_ddr_pmu.c b/drivers/perf/phytium/phytium_ddr_pmu.c index 2a28aa0ae2..ae9ff4a524 100644 --- a/drivers/perf/phytium/phytium_ddr_pmu.c +++ b/drivers/perf/phytium/phytium_ddr_pmu.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -32,7 +33,7 @@ #define pr_fmt(fmt) "phytium_ddr_pmu: " fmt #define PHYTIUM_DDR_MAX_COUNTERS 8 -#define DDR_PERF_DRIVER_VERSION "1.3.1" +#define DDR_PERF_DRIVER_VERSION "1.3.2" #define DDR_START_TIMER 0x000 #define DDR_STOP_TIMER 0x004 @@ -58,6 +59,8 @@ #define DDR_PMU_OFL_STOP_TYPE_VAL 0x10 +#define PBFVER_FUNC_ID 0x82000001 + #define to_phytium_ddr_pmu(p) (container_of(p, struct phytium_ddr_pmu, pmu)) enum { @@ -471,6 +474,30 @@ static irqreturn_t phytium_ddr_pmu_overflow_handler(int irq, void *dev_id) return IRQ_NONE; } +static int phytium_verify_pbf_version(struct platform_device *pdev) +{ + struct arm_smccc_res res; + unsigned long major_ver, minor_ver; + + arm_smccc_smc(PBFVER_FUNC_ID, 0, 0, 0, 0, 0, 0, 0, &res); + if (res.a0 <= 0) { + dev_warn(&pdev->dev, "Can not recognize PBF Firmware version!\n"); + return -EINVAL; + } + + minor_ver = res.a0 & 0xFFFF; + major_ver = (res.a0 >> 16) & 0xFFFF; + + if (major_ver < 1 || (major_ver == 1 && minor_ver < 20)) { + dev_err(&pdev->dev, + "Driver load failed, Please upgrade PBF Firmware version to 1.20 or later!\n"); + return -EINVAL; + } + + return 0; + +} + static int phytium_ddr_pmu_version(struct platform_device *pdev, struct phytium_ddr_pmu *ddr_pmu) { @@ -587,6 +614,12 @@ static int phytium_ddr_pmu_dev_probe(struct platform_device *pdev, if (ret) return ret; + if (ddr_pmu->ver == DDRV1P0) { + ret = phytium_verify_pbf_version(pdev); + if (ret) + return ret; + } + ret = phytium_ddr_pmu_init_data(pdev, ddr_pmu); if (ret) return ret; -- Gitee From 84bcfa7a0de2efbd8b13436adf490cdcfe77e7ab Mon Sep 17 00:00:00 2001 From: Tan Rui Date: Mon, 9 Jun 2025 17:54:10 +0800 Subject: [PATCH 032/155] drivers/perf: phytium: Fix issue in dmu pmu driver when cpu is offlined When the dmu pmu driver is migrated to the target cpu, offlining the target cpu will cause the system panic. We fix this issue. Mainline: Open-Source Signed-off-by: Tan Rui Signed-off-by: Wang Yinfeng Change-Id: I25895b104bc6093ba40bf85200ec2347bbf182f8 --- drivers/perf/phytium/phytium_dmu_pmu_pd2408.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/perf/phytium/phytium_dmu_pmu_pd2408.c b/drivers/perf/phytium/phytium_dmu_pmu_pd2408.c index 4f0049c74c..b4a9ff59b2 100644 --- a/drivers/perf/phytium/phytium_dmu_pmu_pd2408.c +++ b/drivers/perf/phytium/phytium_dmu_pmu_pd2408.c @@ -31,7 +31,7 @@ #undef pr_fmt #define pr_fmt(fmt) "pd2408_dmu_pmu: " fmt -#define DMU_PERF_DRIVER_VERSION "1.0.1" +#define DMU_PERF_DRIVER_VERSION "1.0.2" #define DMU_PMU_TIMER_START 0x0 #define DMU_PMU_TIMER_STOP 0x4 @@ -652,11 +652,13 @@ int pd2408_dmu_pmu_offline_cpu(unsigned int cpu, struct hlist_node *node) struct pd2408_dmu_pmu *dmu_pmu = hlist_entry_safe(node, struct pd2408_dmu_pmu, node); unsigned int target; + cpumask_t available_cpus; if (dmu_pmu->on_cpu != cpu) return 0; - target = cpumask_last(cpu_online_mask); + cpumask_andnot(&available_cpus, cpu_online_mask, cpumask_of(cpu)); + target = cpumask_last(&available_cpus); if (target >= nr_cpu_ids) { dev_err(dmu_pmu->dev, "offline cpu%d with no target to migrate.\n", -- Gitee From 4277fee7eb34284ec73d32017c874c639e8a4f59 Mon Sep 17 00:00:00 2001 From: Tan Rui Date: Wed, 11 Jun 2025 17:53:23 +0800 Subject: [PATCH 033/155] drivers/perf: phytium: Rename DDR PMU event names Standarize event naming to use all lowercase and avoid mixing uppercase mixing uppercase and lowercase letters. Mainline: Open-Source Signed-off-by: Tan Rui Signed-off-by: Wang Yinfeng Change-Id: I9fdec41ae2d454f1ef17357dfe01eb8b88e6ee2e --- drivers/perf/phytium/phytium_ddr_pmu.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/perf/phytium/phytium_ddr_pmu.c b/drivers/perf/phytium/phytium_ddr_pmu.c index ae9ff4a524..2443262f23 100644 --- a/drivers/perf/phytium/phytium_ddr_pmu.c +++ b/drivers/perf/phytium/phytium_ddr_pmu.c @@ -33,7 +33,7 @@ #define pr_fmt(fmt) "phytium_ddr_pmu: " fmt #define PHYTIUM_DDR_MAX_COUNTERS 8 -#define DDR_PERF_DRIVER_VERSION "1.3.2" +#define DDR_PERF_DRIVER_VERSION "1.3.3" #define DDR_START_TIMER 0x000 #define DDR_STOP_TIMER 0x004 @@ -160,9 +160,9 @@ static struct attribute *phytium_ddr_pmu_events_attr[] = { PHYTIUM_DDR_PMU_EVENT_ATTR(rxreq, 0x01), PHYTIUM_DDR_PMU_EVENT_ATTR(rxdat, 0x02), PHYTIUM_DDR_PMU_EVENT_ATTR(txdat, 0x03), - PHYTIUM_DDR_PMU_EVENT_ATTR(rxreq_RNS, 0x04), - PHYTIUM_DDR_PMU_EVENT_ATTR(rxreq_WNSP, 0x05), - PHYTIUM_DDR_PMU_EVENT_ATTR(rxreq_WNSF, 0x06), + PHYTIUM_DDR_PMU_EVENT_ATTR(rxreq_rns, 0x04), + PHYTIUM_DDR_PMU_EVENT_ATTR(rxreq_wnsp, 0x05), + PHYTIUM_DDR_PMU_EVENT_ATTR(rxreq_wnsf, 0x06), PHYTIUM_DDR_PMU_EVENT_ATTR(bandwidth, 0x07), NULL, }; -- Gitee From 7f0f360f521afd23fff9f3f17faef011aa9378ee Mon Sep 17 00:00:00 2001 From: liutianyu1250 Date: Thu, 4 Sep 2025 10:59:16 +0800 Subject: [PATCH 034/155] Revert "i2s: phytium: not report jack status if snd_card bind failed" This reverts commit 2ef6d46488eb3c072c93febf4cb64f7a1f100304. --- sound/soc/phytium/phytium-i2s-v2.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/sound/soc/phytium/phytium-i2s-v2.c b/sound/soc/phytium/phytium-i2s-v2.c index 1817bf3ce2..f2ad6fd13f 100644 --- a/sound/soc/phytium/phytium-i2s-v2.c +++ b/sound/soc/phytium/phytium-i2s-v2.c @@ -690,12 +690,6 @@ static void phyt_i2s_gpio_jack_work(struct work_struct *work) int ret = 0; u32 unplug = phyt_readl_reg(priv->regfile_base, PHYTIUM_REGFILE_HPDET); - if (IS_ERR_OR_NULL(hs_jack.card->snd_card)) { - dev_warn(priv->dev, "sound card %s not binded", - hs_jack.card->name); - return; - } - if (unplug & 0x1) { if (hs_jack.jack) { snd_soc_jack_report(&hs_jack, HEADPHONE_DISABLE, SND_JACK_HEADSET); -- Gitee From 270899f3a142b5d5f8105c98bfd5ea4638b50451 Mon Sep 17 00:00:00 2001 From: Zhou Zheng Date: Thu, 5 Jun 2025 16:44:47 +0800 Subject: [PATCH 035/155] i2s-v2: phytium: Improve code style and robustness The patch enhances code in three ways. Firstly, it adjusts the boundary condition for printing logs, which prevents unexpected behaviors. Secondly, Fix the issue of detecting headphones status even without sound card. Finally, it optimizer the code style to make code more readable. Mainline: Open-Source Signed-off-by: Zhou Zheng Signed-off-by: Wang Yinfeng Change-Id: I2cb3b97c48b44eb6c2c8352c847e65df3b7e226b --- sound/soc/phytium/phytium-i2s-v2.c | 47 +++++++++++++------------- sound/soc/phytium/phytium-i2s-v2.h | 4 +-- sound/soc/phytium/phytium-machine-v2.c | 2 +- 3 files changed, 27 insertions(+), 26 deletions(-) diff --git a/sound/soc/phytium/phytium-i2s-v2.c b/sound/soc/phytium/phytium-i2s-v2.c index f2ad6fd13f..5149941ca0 100644 --- a/sound/soc/phytium/phytium-i2s-v2.c +++ b/sound/soc/phytium/phytium-i2s-v2.c @@ -2,7 +2,7 @@ /* * Phytium I2S ASoC driver * - * Copyright (C) 2024, Phytium Technology Co., Ltd. + * Copyright (C) 2023-2024, Phytium Technology Co., Ltd. * */ @@ -30,7 +30,7 @@ #include #include "phytium-i2s-v2.h" -#define PHYT_I2S_V2_VERSION "1.0.5" +#define PHYT_I2S_V2_VERSION "1.0.6" static struct snd_soc_jack hs_jack; static irqreturn_t phyt_i2s_gpio_interrupt(int irq, void *dev_id); @@ -157,7 +157,7 @@ static int phyt_pcm_hw_params(struct snd_soc_component *component, { struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct phytium_i2s *priv = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0)); - int ret; + int ret = 0; uint32_t format_val; switch (params_format(hw_params)) { @@ -185,10 +185,8 @@ static int phyt_pcm_hw_params(struct snd_soc_component *component, priv->pcm_config[DIRECTION_CAPTURE].format_val = format_val; ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); - if (ret < 0) - return ret; - return 0; + return ret; } static void phyt_bdl_entry_setup(dma_addr_t addr, uint32_t **pbdl, @@ -273,7 +271,7 @@ static int phyt_pcm_prepare(struct snd_soc_component *component, else config = CAPTRUE_ADDRESS_OFFSET; phyt_writel_reg(priv->dma_reg_base, PHYTIUM_DMA_CHALX_DEV_ADDR(direction), - E2000_LSD_I2S_BASE + config); + LSD_I2S_BASE + config); phyt_writel_reg(priv->dma_reg_base, PHYTIUM_DMA_CHALX_LVI(direction), frags - 1); phyt_writel_reg(priv->dma_reg_base, PHYTIUM_DMA_CHALX_CBL(direction), pcm_config->buffer_size); @@ -361,7 +359,6 @@ static snd_pcm_uframes_t phyt_pcm_pointer(struct snd_soc_component *component, { struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct phytium_i2s *priv = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0)); - uint32_t pos = 0; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) @@ -372,10 +369,10 @@ static snd_pcm_uframes_t phyt_pcm_pointer(struct snd_soc_component *component, return bytes_to_frames(substream->runtime, pos); } -int phyt_i2s_msg_set_cmd(struct phytium_i2s *priv, bool is_gpio) +static int phyt_i2s_msg_set_cmd(struct phytium_i2s *priv, bool is_gpio) { struct phyti2s_cmd *ans_msg; - int timeout = 40, ret = 0; + int timeout = 100, ret = 0; if (is_gpio) { phyt_writel_reg(priv->regfile_base, PHYTIUM_REGFILE_AP2RV_INT_STATE, @@ -690,6 +687,9 @@ static void phyt_i2s_gpio_jack_work(struct work_struct *work) int ret = 0; u32 unplug = phyt_readl_reg(priv->regfile_base, PHYTIUM_REGFILE_HPDET); + if (!hs_jack.card->snd_card) + return; + if (unplug & 0x1) { if (hs_jack.jack) { snd_soc_jack_report(&hs_jack, HEADPHONE_DISABLE, SND_JACK_HEADSET); @@ -836,7 +836,7 @@ void phyt_i2s_show_log(struct phytium_i2s *priv) { u32 reg, len; u8 *plog; - int i; + int i, cur_len; if (!priv->log_addr) return; @@ -847,12 +847,12 @@ void phyt_i2s_show_log(struct phytium_i2s *priv) len = strnlen((char *)priv->log_addr, LOG_SIZE_MAX); dev_info(priv->dev, "log len :%d, addr:0x%llx, size:%d\n", len, (u64)priv->log_addr, priv->log_size); - if (len > LOG_LINE_MAX_LEN) { - for (i = 0; i < len; i += LOG_LINE_MAX_LEN) - dev_info(priv->dev, "(DEV)%.*s\n", LOG_LINE_MAX_LEN, &plog[i]); - } else { - dev_info(priv->dev, "(DDR)%.*s\n", LOG_LINE_MAX_LEN, &plog[i]); + + for (i = 0; i < len; i += LOG_LINE_MAX_LEN) { + cur_len = (((len - i) < LOG_LINE_MAX_LEN) ? (len - i) : LOG_LINE_MAX_LEN); + dev_info(priv->dev, "(DEV)%.*s\n", cur_len, &plog[i]); } + for (i = 0; i < priv->log_size; i++) plog[i] = 0; } @@ -860,12 +860,13 @@ void phyt_i2s_show_log(struct phytium_i2s *priv) phyt_writel_reg(priv->regfile_base, PHYTIUM_REGFILE_DEBUG, reg); } -int phyt_i2s_alloc_log_mem(struct phytium_i2s *priv) +int phyt_i2s_init_log(struct phytium_i2s *priv) { u32 reg; u64 phy_addr; reg = phyt_readl_reg(priv->regfile_base, PHYTIUM_REGFILE_DEBUG); + reg = reg | DEBUG_ENABLE; phy_addr = ((reg & ADDR_MASK) >> ADDR_LOW_SHIFT) << ADDR_SHIFT; priv->log_size = ((reg & LOG_SIZE_MASK) >> LOG_SIZE_LOW_SHIFT) * 1024; @@ -883,6 +884,8 @@ static ssize_t phyt_i2s_debug_show(struct device *dev, struct phytium_i2s *priv = dev_get_drvdata(dev); u32 debug_reg = phyt_readl_reg(priv->regfile_base, PHYTIUM_REGFILE_DEBUG); + dev_info(dev, "echo debug(1)/alive(0) enable(1)/disable(0) > debug\n"); + return sprintf(buf, "%x\n", debug_reg); } @@ -897,8 +900,6 @@ static ssize_t phyt_i2s_debug_store(struct device *dev, int ret; long value; - dev_info(dev, "echo debug(1)/alive(0) enable(1)/disable(0) > debug\n"); - p = kmalloc(size, GFP_KERNEL); if (p == NULL) return -EINVAL; @@ -1007,10 +1008,10 @@ static int phyt_i2s_probe(struct platform_device *pdev) goto failed_ioremap_res2; } - ret = phyt_i2s_alloc_log_mem(priv); + ret = phyt_i2s_init_log(priv); if (ret != 0) { - dev_err(&pdev->dev, "failed to alloc log mem\n"); - goto failed_alloc_log_mem; + dev_err(&pdev->dev, "failed to init log\n"); + goto failed_init_log; } status = readl(priv->dma_reg_base + PHYTIUM_DMA_STS); @@ -1097,7 +1098,7 @@ static int phyt_i2s_probe(struct platform_device *pdev) failed_get_dai_name: failed_request_irq: failed_disable_gpioint: -failed_alloc_log_mem: +failed_init_log: failed_ioremap_res2: failed_ioremap_res1: failed_ioremap_res0: diff --git a/sound/soc/phytium/phytium-i2s-v2.h b/sound/soc/phytium/phytium-i2s-v2.h index 5db90b103c..e37644d199 100644 --- a/sound/soc/phytium/phytium-i2s-v2.h +++ b/sound/soc/phytium/phytium-i2s-v2.h @@ -2,7 +2,7 @@ * * Phytium I2S ASoC driver * - * Copyright (C) 2024, Phytium Technology Co., Ltd. + * Copyright (C) 2023-2024, Phytium Technology Co., Ltd. * */ @@ -174,7 +174,7 @@ struct phyti2s_cmd { #define PHYTIUM_DMA_BDLPU(x) (0x40 * x + 0x0040) #define PHYTIUM_DMA_BDLPL(x) (0x40 * x + 0x0044) #define PHYTIUM_DMA_CHALX_DEV_ADDR(x) (0x40 * x + 0x0048) - #define E2000_LSD_I2S_BASE 0x28009000 + #define LSD_I2S_BASE 0x18009000 #define PLAYBACK_ADDRESS_OFFSET 0x1c8 #define CAPTRUE_ADDRESS_OFFSET 0x1c0 #define PHYTIUM_DMA_CHALX_LVI(x) (0x40 * x + 0x004c) diff --git a/sound/soc/phytium/phytium-machine-v2.c b/sound/soc/phytium/phytium-machine-v2.c index cf29c368b2..d02ae022e5 100644 --- a/sound/soc/phytium/phytium-machine-v2.c +++ b/sound/soc/phytium/phytium-machine-v2.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Copyright (c) 2024, Phytium Techonology Co., Ltd. + * Copyright (c) 2023-2024, Phytium Techonology Co., Ltd. */ #include -- Gitee From 897d217c1d7202faf8034dc2daacfd88392c20c0 Mon Sep 17 00:00:00 2001 From: Zhou Zheng Date: Thu, 5 Jun 2025 17:15:39 +0800 Subject: [PATCH 036/155] codec-v2: phytium: Impove the readability of driver code This patch prints controller status when complete code are abnormal and moves complex initalization operations from the probe function to a new function to make the code readable. Mainline: Open-Source Signed-off-by: Zhou Zheng Signed-off-by: Wang Yinfeng Change-Id: I3a9ea31bbc9d1a09afafd9c5329737e9e3467948 --- sound/soc/codecs/phytium-codec-v2.c | 54 ++++++++++++++++------------- sound/soc/codecs/phytium-codec-v2.h | 8 ++++- 2 files changed, 37 insertions(+), 25 deletions(-) diff --git a/sound/soc/codecs/phytium-codec-v2.c b/sound/soc/codecs/phytium-codec-v2.c index c0e8ff372d..c558e35b7e 100644 --- a/sound/soc/codecs/phytium-codec-v2.c +++ b/sound/soc/codecs/phytium-codec-v2.c @@ -2,7 +2,7 @@ /* * Phytium CODEC ALSA SoC Audio driver * - * Copyright (C) 2024, Phytium Technology Co., Ltd. + * Copyright (C) 2023-2024, Phytium Technology Co., Ltd. * */ @@ -32,7 +32,7 @@ #include "phytium-codec-v2.h" -#define PHYT_CODEC_V2_VERSION "1.1.0" +#define PHYT_CODEC_V2_VERSION "1.1.1" #define PHYTIUM_RATES (SNDRV_PCM_RATE_192000 | \ SNDRV_PCM_RATE_96000 | \ SNDRV_PCM_RATE_88200 | \ @@ -146,6 +146,7 @@ int phyt_codec_msg_set_cmd(struct phytium_codec *priv) return -EINVAL; } } else if (ans_msg->complete != PHYTCODEC_COMPLETE_SUCCESS) { + phyt_codec_show_status(ans_msg->status); dev_err(priv->dev, "receive msg; error code:%d\n", ans_msg->complete); ret = -EINVAL; @@ -456,19 +457,19 @@ static int phyt_hw_params(struct snd_pcm_substream *substream, priv->channels = params_channels(params); switch (params_width(params)) { - case 16: + case PHYTCODEC_FORMAT_S16: wl = 3; break; - case 18: + case PHYTCODEC_FORMAT_S18: wl = 2; break; - case 20: + case PHYTCODEC_FORMAT_S20: wl = 1; break; - case 24: + case PHYTCODEC_FORMAT_S24: wl = 0; break; - case 32: + case PHYTCODEC_FORMAT_S32: wl = 4; break; default: @@ -786,6 +787,27 @@ static int phyt_get_channels(struct phytium_codec *priv) return channels; } +static void phyt_codec_init(struct phytium_codec *priv) +{ + phyt_disable_debug(priv); + phyt_disable_alive(priv); + priv->debug_enabled = false; + priv->alive_enabled = false; + priv->heartbeat = phyt_heartbeat; + priv->timer.expires = jiffies + msecs_to_jiffies(10000); + timer_setup(&priv->timer, phyt_timer_handle, 0); + add_timer(&priv->timer); + + if (sysfs_create_group(&priv->dev->kobj, &phyt_codec_device_group)) + dev_warn(priv->dev, "failed to create sysfs\n"); + + phyt_dai.playback.channels_max = phyt_get_channels(priv); + phyt_dai.capture.channels_max = phyt_dai.playback.channels_max; + + phyt_writel_reg(priv->regfile_base, PHYTIUM_CODEC_INT_MASK, 0x0); + phyt_writel_reg(priv->regfile_base, PHYTIUM_CODEC_INT_ENABLE, 0x1); +} + static int phyt_codec_probe(struct platform_device *pdev) { struct phytium_codec *priv; @@ -828,23 +850,7 @@ static int phyt_codec_probe(struct platform_device *pdev) goto failed_regmap_init; } - phyt_disable_debug(priv); - phyt_disable_alive(priv); - priv->debug_enabled = false; - priv->alive_enabled = false; - priv->heartbeat = phyt_heartbeat; - priv->timer.expires = jiffies + msecs_to_jiffies(10000); - timer_setup(&priv->timer, phyt_timer_handle, 0); - add_timer(&priv->timer); - - if (sysfs_create_group(&pdev->dev.kobj, &phyt_codec_device_group)) - dev_warn(dev, "failed to create sysfs\n"); - - phyt_dai.playback.channels_max = phyt_get_channels(priv); - phyt_dai.capture.channels_max = phyt_dai.playback.channels_max; - - phyt_writel_reg(priv->regfile_base, PHYTIUM_CODEC_INT_MASK, 0x0); - phyt_writel_reg(priv->regfile_base, PHYTIUM_CODEC_INT_ENABLE, 0x1); + phyt_codec_init(priv); ret = devm_snd_soc_register_component(dev, &phyt_component_driver, &phyt_dai, 1); diff --git a/sound/soc/codecs/phytium-codec-v2.h b/sound/soc/codecs/phytium-codec-v2.h index b699c7276e..f0515d0cfa 100644 --- a/sound/soc/codecs/phytium-codec-v2.h +++ b/sound/soc/codecs/phytium-codec-v2.h @@ -2,7 +2,7 @@ * * Phytium CODEC ASoC driver * - * Copyright (C) 2024, Phytium Technology Co., Ltd. + * Copyright (C) 2023-2024, Phytium Technology Co., Ltd. * */ @@ -43,6 +43,12 @@ /****************register end *****************/ +#define PHYTCODEC_FORMAT_S16 16 +#define PHYTCODEC_FORMAT_S18 18 +#define PHYTCODEC_FORMAT_S20 20 +#define PHYTCODEC_FORMAT_S24 24 +#define PHYTCODEC_FORMAT_S32 32 + #define PHYTIUM_CODEC_LSD_ID 0x701 enum phytcodec_msg_cmd_id { -- Gitee From 5f706b5fb74a4ceda9cf8b57c5930c71cacb0785 Mon Sep 17 00:00:00 2001 From: liutianyu1250 Date: Thu, 4 Sep 2025 11:02:31 +0800 Subject: [PATCH 037/155] Revert "drivers: phytium-i2s-v2: add dai-name property check in devicetree" This reverts commit 8da78bf7f32256f99dda2950afd6f6bc10a7bdc1. --- sound/soc/phytium/phytium-i2s-v2.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/sound/soc/phytium/phytium-i2s-v2.c b/sound/soc/phytium/phytium-i2s-v2.c index 5149941ca0..21f4093984 100644 --- a/sound/soc/phytium/phytium-i2s-v2.c +++ b/sound/soc/phytium/phytium-i2s-v2.c @@ -1050,11 +1050,7 @@ static int phyt_i2s_probe(struct platform_device *pdev) } if (pdev->dev.of_node) { - ret = device_property_read_string(&pdev->dev, "dai-name", &dai_driver->name); - if (ret < 0) { - dev_err(&pdev->dev, "missing dai-name property %d\n", ret); - goto failed_get_dai_name; - } + device_property_read_string(&pdev->dev, "dai-name", &dai_driver->name); clk = devm_clk_get(&pdev->dev, NULL); priv->clk_base = clk_get_rate(clk); } else if (has_acpi_companion(&pdev->dev)) { -- Gitee From 0a85a46e1bdd08017b3a47791809812c41b752aa Mon Sep 17 00:00:00 2001 From: liutianyu1250 Date: Thu, 4 Sep 2025 11:03:47 +0800 Subject: [PATCH 038/155] Revert "drivers: i2s/phytium_i2s: add dai-name property check" This reverts commit c6de810e06a767c06743db15a1443cea8cfce2ca. --- sound/soc/phytium/phytium_i2s.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sound/soc/phytium/phytium_i2s.c b/sound/soc/phytium/phytium_i2s.c index 02862a489f..5218fb16c2 100644 --- a/sound/soc/phytium/phytium_i2s.c +++ b/sound/soc/phytium/phytium_i2s.c @@ -1507,10 +1507,6 @@ static int phytium_i2s_probe(struct platform_device *pdev) i2s->pcie = 1; } else if (pdev->dev.of_node) { device_property_read_string(&pdev->dev, "dai-name", &dai_drv->name); - if (ret < 0) { - dev_err(&pdev->dev, "missing dai-name property from dts\n"); - goto failed_get_dai_name; - } i2s->pdev = &pdev->dev; clk = devm_clk_get(&pdev->dev, NULL); i2s->clk_base = clk_get_rate(clk); -- Gitee From 934aa61a56b8791d9eaddb7074edaa6c4db6dbc9 Mon Sep 17 00:00:00 2001 From: Zhou Zheng Date: Wed, 25 Jun 2025 14:08:25 +0800 Subject: [PATCH 039/155] i2s: phytium: Add checking for dai-name attribute When driver is loaded, if it does not check whether the dai-name is successfully abtained from the device tree, a call trace error will occur. Mainline: Open-Source Signed-off-by: Zhou Zheng Signed-off-by: Wang Yinfeng Change-Id: I1b9fc1705ffc1a2a78d0129b6eacf5dcbd723eb3 --- sound/soc/phytium/phytium-i2s-v2.c | 6 +++++- sound/soc/phytium/phytium_i2s.c | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/sound/soc/phytium/phytium-i2s-v2.c b/sound/soc/phytium/phytium-i2s-v2.c index 21f4093984..8df71b5d76 100644 --- a/sound/soc/phytium/phytium-i2s-v2.c +++ b/sound/soc/phytium/phytium-i2s-v2.c @@ -1050,7 +1050,11 @@ static int phyt_i2s_probe(struct platform_device *pdev) } if (pdev->dev.of_node) { - device_property_read_string(&pdev->dev, "dai-name", &dai_driver->name); + ret = device_property_read_string(&pdev->dev, "dai-name", &dai_driver->name); + if (ret < 0) { + dev_err(&pdev->dev, "missing dai-name property from device tree\n"); + goto failed_get_dai_name; + } clk = devm_clk_get(&pdev->dev, NULL); priv->clk_base = clk_get_rate(clk); } else if (has_acpi_companion(&pdev->dev)) { diff --git a/sound/soc/phytium/phytium_i2s.c b/sound/soc/phytium/phytium_i2s.c index 5218fb16c2..5edd754021 100644 --- a/sound/soc/phytium/phytium_i2s.c +++ b/sound/soc/phytium/phytium_i2s.c @@ -1506,7 +1506,11 @@ static int phytium_i2s_probe(struct platform_device *pdev) i2s->clk_base = pdata->clk_base; i2s->pcie = 1; } else if (pdev->dev.of_node) { - device_property_read_string(&pdev->dev, "dai-name", &dai_drv->name); + ret = device_property_read_string(&pdev->dev, "dai-name", &dai_drv->name); + if (ret < 0) { + dev_err(&pdev->dev, "missing dai-name property from device tree\n"); + goto failed_get_dai_name; + } i2s->pdev = &pdev->dev; clk = devm_clk_get(&pdev->dev, NULL); i2s->clk_base = clk_get_rate(clk); -- Gitee From 52e4d5b4664ae8adafc9883c5660a43a9c16f7bb Mon Sep 17 00:00:00 2001 From: YuDa Date: Tue, 17 Jun 2025 02:59:35 +0000 Subject: [PATCH 040/155] drm/phytium: Fix NULL pointer issue in drm_gem_object_free The root cause is that phytium_drm_gem_object_funcs is not assingned before phytium_gem_create_object enters the failed_dma_alloc label. Mainline: Open-Source Signed-off-by: YuDa Signed-off-by: Wang Yinfeng Change-Id: I5bb5914c3155881e610a8f53f8385dbc2d48404f --- drivers/gpu/drm/phytium/phytium_gem.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/phytium/phytium_gem.c b/drivers/gpu/drm/phytium/phytium_gem.c index 8234b6b6e8..30e60e64bb 100644 --- a/drivers/gpu/drm/phytium/phytium_gem.c +++ b/drivers/gpu/drm/phytium/phytium_gem.c @@ -432,6 +432,8 @@ struct phytium_gem_object *phytium_gem_create_object(struct drm_device *dev, uns goto failed_object_init; } + phytium_gem_obj->base.funcs = &phytium_drm_gem_object_funcs; + if (priv->support_memory_type & (MEMORY_TYPE_VRAM_WC | MEMORY_TYPE_VRAM_DEVICE)) { ret = phytium_memory_pool_alloc(priv, &phytium_gem_obj->vaddr, &phytium_gem_obj->phys_addr, size); @@ -475,8 +477,6 @@ struct phytium_gem_object *phytium_gem_create_object(struct drm_device *dev, uns goto failed_dma_alloc; } - phytium_gem_obj->base.funcs = &phytium_drm_gem_object_funcs; - phytium_gem_obj->size = size; list_add_tail(&phytium_gem_obj->list, &priv->gem_list_head); DRM_DEBUG_KMS("phytium_gem_obj iova:0x%pa size:0x%lx\n", -- Gitee From 2b62c9302c4fb31295c06434e28e098dedbf0d72 Mon Sep 17 00:00:00 2001 From: Cui Chao Date: Fri, 4 Jul 2025 14:21:24 +0800 Subject: [PATCH 041/155] pswiotlb: Move pswiotlb dma functions behind dma_map_ops To reduce the difficulty of maintenance, pswiotlb_dma* functions are moved behind the struct dma_map_ops. Mainline: Open-Source Signed-off-by: Cui Chao Signed-off-by: Wang Yinfeng Change-Id: I7d7c03c82f87f723d9cfb2e04c9f491bc64e7ba2 --- arch/arm64/mm/dma-mapping.c | 8 + drivers/pci/pci.c | 9 - include/linux/device.h | 18 +- include/linux/pswiotlb.h | 1 + kernel/dma/mapping.c | 60 +---- kernel/dma/phytium/pswiotlb-dma.h | 74 +++++- kernel/dma/phytium/pswiotlb-iommu.c | 12 +- kernel/dma/phytium/pswiotlb-mapping.c | 337 ++++++++++++++++++++++++-- 8 files changed, 431 insertions(+), 88 deletions(-) diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c index 3cb101e8cb..17ebc794a7 100644 --- a/arch/arm64/mm/dma-mapping.c +++ b/arch/arm64/mm/dma-mapping.c @@ -13,6 +13,10 @@ #include #include +#ifdef CONFIG_PSWIOTLB +#include +#endif + void arch_sync_dma_for_device(phys_addr_t paddr, size_t size, enum dma_data_direction dir) { @@ -61,5 +65,9 @@ void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size, if (iommu) iommu_setup_dma_ops(dev, dma_base, dma_base + size - 1); +#ifdef CONFIG_PSWIOTLB + pswiotlb_setup_dma_ops(dev); +#endif + xen_setup_dma_ops(dev); } diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 7205fe98ec..e9a1071c56 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -4534,15 +4534,6 @@ void __weak pcibios_set_master(struct pci_dev *dev) */ void pci_set_master(struct pci_dev *dev) { -#ifdef CONFIG_PSWIOTLB - if ((pswiotlb_force_disable != true) && - is_phytium_ps_socs()) { - dev->dev.can_use_pswiotlb = pswiotlb_is_dev_in_passthroughlist(dev); - dev_info(&dev->dev, "The device %s use pswiotlb because vendor 0x%04x %s in pswiotlb passthroughlist\n", - dev->dev.can_use_pswiotlb ? "would" : "would NOT", - dev->vendor, dev->dev.can_use_pswiotlb ? "is NOT" : "is"); - } -#endif __pci_set_master(dev, true); pcibios_set_master(dev); } diff --git a/include/linux/device.h b/include/linux/device.h index 2c5e240eb7..b2ddba6725 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -656,7 +656,10 @@ struct device_physical_location { * @dma_io_tlb_lock: Protects changes to the list of active pools. * @dma_uses_io_tlb: %true if device has used the software IO TLB. * @dma_p_io_tlb_mem: Phytium Software IO TLB allocator. Not for driver use. + * @orig_dma_ops: Original DMA mapping operations for this device. + * @local_node: NUMA node this device is really belong to. * @dma_uses_p_io_tlb: %true if device has used the Phytium software IO TLB. + * @can_use_pswiotlb: %true if device can use the Phytium software IO TLB. * @archdata: For arch-specific additions. * @of_node: Associated device tree node. * @fwnode: Associated device node supplied by platform firmware. @@ -765,8 +768,16 @@ struct device { #endif #ifdef CONFIG_PSWIOTLB struct p_io_tlb_mem *dma_p_io_tlb_mem; - bool dma_uses_p_io_tlb; - bool can_use_pswiotlb; +#ifdef CONFIG_DMA_OPS + const struct dma_map_ops *orig_dma_ops; +#endif + struct { +#ifdef CONFIG_NUMA + int local_node; +#endif + bool dma_uses_p_io_tlb; + bool can_use_pswiotlb; + }; #endif #ifdef CONFIG_SWIOTLB_DYNAMIC struct list_head dma_io_tlb_pools; @@ -781,9 +792,6 @@ struct device { #ifdef CONFIG_NUMA int numa_node; /* NUMA node this device is close to */ -#ifdef CONFIG_PSWIOTLB - int local_node; /* NUMA node this device is really belong to */ -#endif #endif dev_t devt; /* dev_t, creates the sysfs "dev" */ u32 id; /* device instance */ diff --git a/include/linux/pswiotlb.h b/include/linux/pswiotlb.h index 26b2a9d7f5..510cff3ad3 100644 --- a/include/linux/pswiotlb.h +++ b/include/linux/pswiotlb.h @@ -79,6 +79,7 @@ dma_addr_t pswiotlb_map(struct device *dev, int nid, phys_addr_t phys, void pswiotlb_store_local_node(struct pci_dev *dev, struct pci_bus *bus); void iommu_dma_unmap_sg_pswiotlb(struct device *dev, struct scatterlist *sg, unsigned long iova, size_t mapped, int nents, enum dma_data_direction dir, unsigned long attrs); +void pswiotlb_setup_dma_ops(struct device *dev); #ifdef CONFIG_PSWIOTLB struct pswiotlb_passthroughlist { struct list_head node; diff --git a/kernel/dma/mapping.c b/kernel/dma/mapping.c index 2e392fc6c2..b0953cf247 100644 --- a/kernel/dma/mapping.c +++ b/kernel/dma/mapping.c @@ -158,13 +158,6 @@ dma_addr_t dma_map_page_attrs(struct device *dev, struct page *page, if (WARN_ON_ONCE(!dev->dma_mask)) return DMA_MAPPING_ERROR; -#ifdef CONFIG_PSWIOTLB - if (check_if_pswiotlb_is_applicable(dev) && - !pswiotlb_bypass_is_needed(dev, 0, dir)) { - addr = pswiotlb_dma_map_page_distribute(dev, page, offset, size, dir, attrs); - return addr; - } -#endif if (dma_map_direct(dev, ops) || arch_dma_map_page_direct(dev, page_to_phys(page) + offset + size)) addr = dma_direct_map_page(dev, page, offset, size, dir, attrs); @@ -182,12 +175,7 @@ void dma_unmap_page_attrs(struct device *dev, dma_addr_t addr, size_t size, const struct dma_map_ops *ops = get_dma_ops(dev); BUG_ON(!valid_dma_direction(dir)); -#ifdef CONFIG_PSWIOTLB - if (check_if_pswiotlb_is_applicable(dev)) { - pswiotlb_dma_unmap_page_attrs_distribute(dev, addr, size, dir, attrs); - return; - } -#endif + if (dma_map_direct(dev, ops) || arch_dma_unmap_page_direct(dev, addr + size)) dma_direct_unmap_page(dev, addr, size, dir, attrs); @@ -206,13 +194,7 @@ static int __dma_map_sg_attrs(struct device *dev, struct scatterlist *sg, if (WARN_ON_ONCE(!dev->dma_mask)) return 0; -#ifdef CONFIG_PSWIOTLB - if (check_if_pswiotlb_is_applicable(dev) && - !pswiotlb_bypass_is_needed(dev, nents, dir)) { - ents = pswiotlb_dma_map_sg_attrs_distribute(dev, sg, nents, dir, attrs); - return ents; - } -#endif + if (dma_map_direct(dev, ops) || arch_dma_map_sg_direct(dev, sg, nents)) ents = dma_direct_map_sg(dev, sg, nents, dir, attrs); @@ -306,12 +288,7 @@ void dma_unmap_sg_attrs(struct device *dev, struct scatterlist *sg, BUG_ON(!valid_dma_direction(dir)); debug_dma_unmap_sg(dev, sg, nents, dir); -#ifdef CONFIG_PSWIOTLB - if (check_if_pswiotlb_is_applicable(dev)) { - pswiotlb_dma_unmap_sg_attrs_distribute(dev, sg, nents, dir, attrs); - return; - } -#endif + if (dma_map_direct(dev, ops) || arch_dma_unmap_sg_direct(dev, sg, nents)) dma_direct_unmap_sg(dev, sg, nents, dir, attrs); @@ -358,12 +335,7 @@ void dma_sync_single_for_cpu(struct device *dev, dma_addr_t addr, size_t size, const struct dma_map_ops *ops = get_dma_ops(dev); BUG_ON(!valid_dma_direction(dir)); -#ifdef CONFIG_PSWIOTLB - if (check_if_pswiotlb_is_applicable(dev)) { - pswiotlb_dma_sync_single_for_cpu_distribute(dev, addr, size, dir); - return; - } -#endif + if (dma_map_direct(dev, ops)) dma_direct_sync_single_for_cpu(dev, addr, size, dir); else if (ops->sync_single_for_cpu) @@ -377,12 +349,7 @@ void dma_sync_single_for_device(struct device *dev, dma_addr_t addr, const struct dma_map_ops *ops = get_dma_ops(dev); BUG_ON(!valid_dma_direction(dir)); -#ifdef CONFIG_PSWIOTLB - if (check_if_pswiotlb_is_applicable(dev)) { - pswiotlb_dma_sync_single_for_device_distribute(dev, addr, size, dir); - return; - } -#endif + if (dma_map_direct(dev, ops)) dma_direct_sync_single_for_device(dev, addr, size, dir); else if (ops->sync_single_for_device) @@ -396,12 +363,7 @@ void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, const struct dma_map_ops *ops = get_dma_ops(dev); BUG_ON(!valid_dma_direction(dir)); -#ifdef CONFIG_PSWIOTLB - if (check_if_pswiotlb_is_applicable(dev)) { - pswiotlb_dma_sync_sg_for_cpu_distribute(dev, sg, nelems, dir); - return; - } -#endif + if (dma_map_direct(dev, ops)) dma_direct_sync_sg_for_cpu(dev, sg, nelems, dir); else if (ops->sync_sg_for_cpu) @@ -415,12 +377,7 @@ void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, const struct dma_map_ops *ops = get_dma_ops(dev); BUG_ON(!valid_dma_direction(dir)); -#ifdef CONFIG_PSWIOTLB - if (check_if_pswiotlb_is_applicable(dev)) { - pswiotlb_dma_sync_sg_for_device_distribute(dev, sg, nelems, dir); - return; - } -#endif + if (dma_map_direct(dev, ops)) dma_direct_sync_sg_for_device(dev, sg, nelems, dir); else if (ops->sync_sg_for_device) @@ -554,9 +511,6 @@ void *dma_alloc_attrs(struct device *dev, size_t size, dma_addr_t *dma_handle, if (WARN_ON_ONCE(flag & __GFP_COMP)) return NULL; -#ifdef CONFIG_PSWIOTLB - check_if_pswiotlb_is_applicable(dev); -#endif if (dma_alloc_from_dev_coherent(dev, size, dma_handle, &cpu_addr)) return cpu_addr; diff --git a/kernel/dma/phytium/pswiotlb-dma.h b/kernel/dma/phytium/pswiotlb-dma.h index 0f159a3891..8d355e8baa 100644 --- a/kernel/dma/phytium/pswiotlb-dma.h +++ b/kernel/dma/phytium/pswiotlb-dma.h @@ -13,6 +13,69 @@ #include extern bool pswiotlb_force_disable; +struct pswiotlb_dma_map_ops { + unsigned int flags; + + void *(*alloc)(struct device *dev, size_t size, + dma_addr_t *dma_handle, gfp_t gfp, + unsigned long attrs); + void (*free)(struct device *dev, size_t size, void *vaddr, + dma_addr_t dma_handle, unsigned long attrs); + struct page *(*alloc_pages)(struct device *dev, size_t size, + dma_addr_t *dma_handle, enum dma_data_direction dir, + gfp_t gfp); + void (*free_pages)(struct device *dev, size_t size, struct page *vaddr, + dma_addr_t dma_handle, enum dma_data_direction dir); + struct sg_table *(*alloc_noncontiguous)(struct device *dev, size_t size, + enum dma_data_direction dir, gfp_t gfp, + unsigned long attrs); + void (*free_noncontiguous)(struct device *dev, size_t size, + struct sg_table *sgt, enum dma_data_direction dir); + int (*mmap)(struct device *dev, struct vm_area_struct *vma, + void *cpu_addr, dma_addr_t dma_addr, size_t size, unsigned long attrs); + + int (*get_sgtable)(struct device *dev, struct sg_table *sgt, + void *cpu_addr, dma_addr_t dma_addr, size_t size, + unsigned long attrs); + + dma_addr_t (*map_page)(struct device *dev, struct page *page, + unsigned long offset, size_t size, + enum dma_data_direction dir, unsigned long attrs); + void (*unmap_page)(struct device *dev, dma_addr_t dma_handle, + size_t size, enum dma_data_direction dir, + unsigned long attrs); + /* + * map_sg should return a negative error code on error. See + * dma_map_sgtable() for a list of appropriate error codes + * and their meanings. + */ + int (*map_sg)(struct device *dev, struct scatterlist *sg, int nents, + enum dma_data_direction dir, unsigned long attrs); + void (*unmap_sg)(struct device *dev, struct scatterlist *sg, int nents, + enum dma_data_direction dir, unsigned long attrs); + dma_addr_t (*map_resource)(struct device *dev, phys_addr_t phys_addr, + size_t size, enum dma_data_direction dir, + unsigned long attrs); + void (*unmap_resource)(struct device *dev, dma_addr_t dma_handle, + size_t size, enum dma_data_direction dir, + unsigned long attrs); + void (*sync_single_for_cpu)(struct device *dev, dma_addr_t dma_handle, + size_t size, enum dma_data_direction dir); + void (*sync_single_for_device)(struct device *dev, + dma_addr_t dma_handle, size_t size, + enum dma_data_direction dir); + void (*sync_sg_for_cpu)(struct device *dev, struct scatterlist *sg, + int nents, enum dma_data_direction dir); + void (*sync_sg_for_device)(struct device *dev, struct scatterlist *sg, + int nents, enum dma_data_direction dir); + void (*cache_sync)(struct device *dev, void *vaddr, size_t size, + enum dma_data_direction direction); + int (*dma_supported)(struct device *dev, u64 mask); + u64 (*get_required_mask)(struct device *dev); + size_t (*max_mapping_size)(struct device *dev); + size_t (*opt_mapping_size)(void); + unsigned long (*get_merge_boundary)(struct device *dev); +}; #if defined(CONFIG_ARCH_HAS_SYNC_DMA_FOR_DEVICE) || \ defined(CONFIG_PSWIOTLB) void pswiotlb_dma_direct_sync_sg_for_device(struct device *dev, @@ -46,7 +109,7 @@ static inline void pswiotlb_dma_direct_sync_sg_for_cpu(struct device *dev, #ifdef CONFIG_PSWIOTLB int pswiotlb_dma_direct_map_sg(struct device *dev, struct scatterlist *sgl, int nents, enum dma_data_direction dir, unsigned long attrs); -dma_addr_t pswiotlb_dma_map_page_distribute(struct device *dev, struct page *page, +dma_addr_t pswiotlb_dma_map_page_attrs_distribute(struct device *dev, struct page *page, size_t offset, size_t size, enum dma_data_direction dir, unsigned long attrs); void pswiotlb_dma_unmap_page_attrs_distribute(struct device *dev, dma_addr_t addr, @@ -80,6 +143,8 @@ void pswiotlb_iommu_dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sgl, int nelems, enum dma_data_direction dir); void pswiotlb_iommu_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sgl, int nelems, enum dma_data_direction dir); +void pswiotlb_iommu_dma_free(struct device *dev, size_t size, void *cpu_addr, + dma_addr_t handle, unsigned long attrs); static inline bool check_if_pswiotlb_is_applicable(struct device *dev) { @@ -212,7 +277,7 @@ static inline int pswiotlb_dma_direct_map_sg(struct device *dev, struct scatterl return 0; } -static inline dma_addr_t pswiotlb_dma_map_page_distribute(struct device *dev, +static inline dma_addr_t pswiotlb_dma_map_page_attrs_distribute(struct device *dev, struct page *page, size_t offset, size_t size, enum dma_data_direction dir, unsigned long attrs) { @@ -304,6 +369,11 @@ static inline void pswiotlb_iommu_dma_sync_sg_for_device(struct device *dev, { } +static inline void pswiotlb_iommu_dma_free(struct device *dev, size_t size, + void *cpu_addr, dma_addr_t handle, unsigned long attrs) +{ +} + static inline bool check_if_pswiotlb_is_applicable(struct device *dev) { return false; diff --git a/kernel/dma/phytium/pswiotlb-iommu.c b/kernel/dma/phytium/pswiotlb-iommu.c index bc8954afff..e19ae0c2df 100644 --- a/kernel/dma/phytium/pswiotlb-iommu.c +++ b/kernel/dma/phytium/pswiotlb-iommu.c @@ -116,16 +116,24 @@ struct iova_fq { * The following functions are ported from * ./drivers/iommu/dma-iommu.c * ./drivers/iommu/iommu.c + * static inline bool fq_full(struct iova_fq *fq); + * static void fq_flush_iotlb(struct iommu_dma_cookie *cookie); + * static inline unsigned int fq_ring_add(struct iova_fq *fq); + * static void fq_ring_free(struct iommu_dma_cookie *cookie, struct iova_fq *fq); * static size_t iommu_pgsize(struct iommu_domain *domain, unsigned long iova, * phys_addr_t paddr, size_t size, size_t *count); * static int __iommu_map_pages(struct iommu_domain *domain, unsigned long iova, - * phys_addr_t paddr, size_t size, int prot, - * gfp_t gfp, size_t *mapped); + * phys_addr_t paddr, size_t size, int prot, gfp_t gfp, size_t *mapped); * static int __iommu_map(struct iommu_domain *domain, unsigned long iova, * phys_addr_t paddr, size_t size, int prot, gfp_t gfp); + * static bool dev_use_swiotlb(struct device *dev, size_t size, + * enum dma_data_direction dir); * static bool dev_is_untrusted(struct device *dev); * static int dma_info_to_prot(enum dma_data_direction dir, bool coherent, * unsigned long attrs); + * static void queue_iova(struct iommu_dma_cookie *cookie, + * unsigned long pfn, unsigned long pages, + * struct list_head *freelist); * static dma_addr_t iommu_dma_alloc_iova(struct iommu_domain *domain, * size_t size, u64 dma_limit, struct device *dev); * static void iommu_dma_free_iova(struct iommu_dma_cookie *cookie, diff --git a/kernel/dma/phytium/pswiotlb-mapping.c b/kernel/dma/phytium/pswiotlb-mapping.c index 65674b7bde..7d518b5646 100644 --- a/kernel/dma/phytium/pswiotlb-mapping.c +++ b/kernel/dma/phytium/pswiotlb-mapping.c @@ -13,6 +13,8 @@ #include #include #include +#include +#include #include "../debug.h" #include "../direct.h" #include "pswiotlb-dma.h" @@ -22,8 +24,18 @@ * ./drivers/dma/mapping.c * static bool dma_go_direct(struct device *dev, dma_addr_t mask, * const struct dma_map_ops *ops); + * static inline bool dma_alloc_direct(struct device *dev, + * const struct dma_map_ops *ops); * static inline bool dma_map_direct(struct device *dev, * const struct dma_map_ops *ops); + * static struct page *__dma_alloc_pages(struct device *dev, size_t size, + * dma_addr_t *dma_handle, enum dma_data_direction dir, gfp_t gfp); + * static struct sg_table *alloc_single_sgt(struct device *dev, size_t size, + * enum dma_data_direction dir, gfp_t gfp); + * static void __dma_free_pages(struct device *dev, size_t size, struct page *page, + * dma_addr_t dma_handle, enum dma_data_direction dir); + * static void free_single_sgt(struct device *dev, size_t size, + * struct sg_table *sgt, enum dma_data_direction dir); */ static bool dma_go_direct(struct device *dev, dma_addr_t mask, @@ -39,23 +51,38 @@ static bool dma_go_direct(struct device *dev, dma_addr_t mask, return false; } +static inline bool dma_alloc_direct(struct device *dev, + const struct dma_map_ops *ops) +{ + return dma_go_direct(dev, dev->coherent_dma_mask, ops); +} + static inline bool dma_map_direct(struct device *dev, const struct dma_map_ops *ops) { return dma_go_direct(dev, *dev->dma_mask, ops); } -dma_addr_t pswiotlb_dma_map_page_distribute(struct device *dev, struct page *page, + +dma_addr_t pswiotlb_dma_map_page_attrs_distribute(struct device *dev, struct page *page, size_t offset, size_t size, enum dma_data_direction dir, unsigned long attrs) { - const struct dma_map_ops *ops = get_dma_ops(dev); + const struct dma_map_ops *ops = dev->orig_dma_ops; dma_addr_t addr; if (dma_map_direct(dev, ops) || - arch_dma_map_page_direct(dev, page_to_phys(page) + offset + size)) - addr = pswiotlb_dma_direct_map_page(dev, page, offset, size, dir, attrs); - else - addr = pswiotlb_iommu_dma_map_page(dev, page, offset, size, dir, attrs); + arch_dma_map_page_direct(dev, page_to_phys(page) + offset + size)) { + if (!pswiotlb_bypass_is_needed(dev, 0, dir)) + addr = pswiotlb_dma_direct_map_page(dev, page, offset, size, dir, attrs); + else + addr = dma_direct_map_page(dev, page, offset, size, dir, attrs); + } else { + if (!pswiotlb_bypass_is_needed(dev, 0, dir)) + addr = pswiotlb_iommu_dma_map_page(dev, page, offset, size, dir, attrs); + else + addr = ops->map_page(dev, page, offset, size, dir, attrs); + } + kmsan_handle_dma(page, offset, size, dir); debug_dma_map_page(dev, page, offset, size, dir, addr, attrs); return addr; @@ -64,7 +91,7 @@ dma_addr_t pswiotlb_dma_map_page_distribute(struct device *dev, struct page *pag void pswiotlb_dma_unmap_page_attrs_distribute(struct device *dev, dma_addr_t addr, size_t size, enum dma_data_direction dir, unsigned long attrs) { - const struct dma_map_ops *ops = get_dma_ops(dev); + const struct dma_map_ops *ops = dev->orig_dma_ops; if (dma_map_direct(dev, ops) || arch_dma_unmap_page_direct(dev, addr + size)) @@ -77,14 +104,21 @@ void pswiotlb_dma_unmap_page_attrs_distribute(struct device *dev, dma_addr_t add int pswiotlb_dma_map_sg_attrs_distribute(struct device *dev, struct scatterlist *sg, int nents, enum dma_data_direction dir, unsigned long attrs) { - const struct dma_map_ops *ops = get_dma_ops(dev); + const struct dma_map_ops *ops = dev->orig_dma_ops; int ents; if (dma_map_direct(dev, ops) || - arch_dma_map_sg_direct(dev, sg, nents)) - ents = pswiotlb_dma_direct_map_sg(dev, sg, nents, dir, attrs); - else - ents = pswiotlb_iommu_dma_map_sg(dev, sg, nents, dir, attrs); + arch_dma_map_sg_direct(dev, sg, nents)) { + if (!pswiotlb_bypass_is_needed(dev, nents, dir)) + ents = pswiotlb_dma_direct_map_sg(dev, sg, nents, dir, attrs); + else + ents = dma_direct_map_sg(dev, sg, nents, dir, attrs); + } else { + if (!pswiotlb_bypass_is_needed(dev, nents, dir)) + ents = pswiotlb_iommu_dma_map_sg(dev, sg, nents, dir, attrs); + else + ents = ops->map_sg(dev, sg, nents, dir, attrs); + } if (ents > 0) debug_dma_map_sg(dev, sg, nents, ents, dir, attrs); @@ -99,7 +133,7 @@ void pswiotlb_dma_unmap_sg_attrs_distribute(struct device *dev, struct scatterli int nents, enum dma_data_direction dir, unsigned long attrs) { - const struct dma_map_ops *ops = get_dma_ops(dev); + const struct dma_map_ops *ops = dev->orig_dma_ops; if (dma_map_direct(dev, ops) || arch_dma_unmap_sg_direct(dev, sg, nents)) @@ -111,7 +145,7 @@ void pswiotlb_dma_unmap_sg_attrs_distribute(struct device *dev, struct scatterli void pswiotlb_dma_sync_single_for_cpu_distribute(struct device *dev, dma_addr_t addr, size_t size, enum dma_data_direction dir) { - const struct dma_map_ops *ops = get_dma_ops(dev); + const struct dma_map_ops *ops = dev->orig_dma_ops; if (dma_map_direct(dev, ops)) pswiotlb_dma_direct_sync_single_for_cpu(dev, addr, size, dir); @@ -123,7 +157,7 @@ void pswiotlb_dma_sync_single_for_cpu_distribute(struct device *dev, dma_addr_t void pswiotlb_dma_sync_single_for_device_distribute(struct device *dev, dma_addr_t addr, size_t size, enum dma_data_direction dir) { - const struct dma_map_ops *ops = get_dma_ops(dev); + const struct dma_map_ops *ops = dev->orig_dma_ops; if (dma_map_direct(dev, ops)) pswiotlb_dma_direct_sync_single_for_device(dev, addr, size, dir); @@ -135,7 +169,7 @@ void pswiotlb_dma_sync_single_for_device_distribute(struct device *dev, dma_addr void pswiotlb_dma_sync_sg_for_cpu_distribute(struct device *dev, struct scatterlist *sg, int nelems, enum dma_data_direction dir) { - const struct dma_map_ops *ops = get_dma_ops(dev); + const struct dma_map_ops *ops = dev->orig_dma_ops; if (dma_map_direct(dev, ops)) pswiotlb_dma_direct_sync_sg_for_cpu(dev, sg, nelems, dir); @@ -147,7 +181,7 @@ void pswiotlb_dma_sync_sg_for_cpu_distribute(struct device *dev, struct scatterl void pswiotlb_dma_sync_sg_for_device_distribute(struct device *dev, struct scatterlist *sg, int nelems, enum dma_data_direction dir) { - const struct dma_map_ops *ops = get_dma_ops(dev); + const struct dma_map_ops *ops = dev->orig_dma_ops; if (dma_map_direct(dev, ops)) pswiotlb_dma_direct_sync_sg_for_device(dev, sg, nelems, dir); @@ -155,3 +189,272 @@ void pswiotlb_dma_sync_sg_for_device_distribute(struct device *dev, struct scatt pswiotlb_iommu_dma_sync_sg_for_device(dev, sg, nelems, dir); debug_dma_sync_sg_for_device(dev, sg, nelems, dir); } + +static dma_addr_t pswiotlb_dma_map_resource_distribute(struct device *dev, phys_addr_t phys, + size_t size, enum dma_data_direction dir, unsigned long attrs) +{ + return dma_direct_map_resource(dev, phys, size, dir, attrs); +} + +static struct page *__dma_alloc_pages(struct device *dev, size_t size, + dma_addr_t *dma_handle, enum dma_data_direction dir, gfp_t gfp) +{ + const struct dma_map_ops *ops = get_dma_ops(dev); + + if (WARN_ON_ONCE(!dev->coherent_dma_mask)) + return NULL; + if (WARN_ON_ONCE(gfp & (__GFP_DMA | __GFP_DMA32 | __GFP_HIGHMEM))) + return NULL; + if (WARN_ON_ONCE(gfp & __GFP_COMP)) + return NULL; + + size = PAGE_ALIGN(size); + if (dma_alloc_direct(dev, ops)) + return dma_direct_alloc_pages(dev, size, dma_handle, dir, gfp); + if (!ops->alloc_pages) + return NULL; + return ops->alloc_pages(dev, size, dma_handle, dir, gfp); +} + +static struct sg_table *alloc_single_sgt(struct device *dev, size_t size, + enum dma_data_direction dir, gfp_t gfp) +{ + struct sg_table *sgt; + struct page *page; + + sgt = kmalloc(sizeof(*sgt), gfp); + if (!sgt) + return NULL; + if (sg_alloc_table(sgt, 1, gfp)) + goto out_free_sgt; + page = __dma_alloc_pages(dev, size, &sgt->sgl->dma_address, dir, gfp); + if (!page) + goto out_free_table; + sg_set_page(sgt->sgl, page, PAGE_ALIGN(size), 0); + sg_dma_len(sgt->sgl) = sgt->sgl->length; + return sgt; +out_free_table: + sg_free_table(sgt); +out_free_sgt: + kfree(sgt); + return NULL; +} + +static struct sg_table *pswiotlb_dma_alloc_noncontiguous_distribute(struct device *dev, + size_t size, enum dma_data_direction dir, gfp_t gfp, + unsigned long attrs) +{ + return alloc_single_sgt(dev, size, dir, gfp); +} + +static void __dma_free_pages(struct device *dev, size_t size, struct page *page, + dma_addr_t dma_handle, enum dma_data_direction dir) +{ + const struct dma_map_ops *ops = get_dma_ops(dev); + + size = PAGE_ALIGN(size); + if (dma_alloc_direct(dev, ops)) + dma_direct_free_pages(dev, size, page, dma_handle, dir); + else if (ops->free_pages) + ops->free_pages(dev, size, page, dma_handle, dir); +} + +static void free_single_sgt(struct device *dev, size_t size, + struct sg_table *sgt, enum dma_data_direction dir) +{ + __dma_free_pages(dev, size, sg_page(sgt->sgl), sgt->sgl->dma_address, + dir); + sg_free_table(sgt); + kfree(sgt); +} + +static void pswiotlb_dma_free_noncontiguous_distribute(struct device *dev, size_t size, + struct sg_table *sgt, enum dma_data_direction dir) +{ + free_single_sgt(dev, size, sgt, dir); +} + +static int pswiotlb_dma_get_sgtable_distribute(struct device *dev, struct sg_table *sgt, + void *cpu_addr, dma_addr_t dma_addr, size_t size, + unsigned long attrs) +{ + return dma_direct_get_sgtable(dev, sgt, cpu_addr, dma_addr, + size, attrs); +} + +static int pswiotlb_dma_mmap_distribute(struct device *dev, struct vm_area_struct *vma, + void *cpu_addr, dma_addr_t dma_addr, size_t size, + unsigned long attrs) +{ + return dma_direct_mmap(dev, vma, cpu_addr, dma_addr, size, + attrs); +} + +static u64 pswiotlb_dma_get_required_mask_distribute(struct device *dev) +{ + return dma_direct_get_required_mask(dev); +} + +static void *pswiotlb_dma_alloc_distribute(struct device *dev, size_t size, + dma_addr_t *handle, gfp_t gfp, unsigned long attrs) +{ + const struct dma_map_ops *ops = dev->orig_dma_ops; + void *cpu_addr; + + check_if_pswiotlb_is_applicable(dev); + + if (dma_alloc_direct(dev, ops)) + cpu_addr = dma_direct_alloc(dev, size, handle, gfp, attrs); + else + cpu_addr = ops->alloc(dev, size, handle, gfp, attrs); + + return cpu_addr; +} + +static void pswiotlb_dma_free_distribute(struct device *dev, size_t size, + void *cpu_addr, dma_addr_t handle, unsigned long attrs) +{ + const struct dma_map_ops *ops = dev->orig_dma_ops; + + if (dma_alloc_direct(dev, ops)) + dma_direct_free(dev, size, cpu_addr, handle, attrs); + else + ops->free(dev, size, cpu_addr, handle, attrs); +} + +static struct page *pswiotlb_dma_common_alloc_pages_distribute(struct device *dev, size_t size, + dma_addr_t *dma_handle, enum dma_data_direction dir, gfp_t gfp) +{ + return dma_direct_alloc_pages(dev, size, dma_handle, dir, gfp); +} + +static void pswiotlb_dma_common_free_pages_distribute(struct device *dev, size_t size, + struct page *page, dma_addr_t dma_handle, enum dma_data_direction dir) +{ + dma_direct_free_pages(dev, size, page, dma_handle, dir); +} + +static int pswiotlb_dma_supported_distribute(struct device *dev, u64 mask) +{ + return dma_direct_supported(dev, mask); +} + +static size_t pswiotlb_dma_max_mapping_size_distribute(struct device *dev) +{ + const struct dma_map_ops *ops = dev->orig_dma_ops; + + if (dma_map_direct(dev, ops)) + return dma_direct_max_mapping_size(dev); + else + return SIZE_MAX; +} + +static size_t pswiotlb_iommu_dma_opt_mapping_size(void) +{ + if (iommu_default_passthrough()) + return SIZE_MAX; + else + return iova_rcache_range(); +} + +static size_t pswiotlb_dma_opt_mapping_size_distribute(void) +{ + size_t size; + + size = pswiotlb_iommu_dma_opt_mapping_size(); + + return min(SIZE_MAX, size); +} + +static unsigned long pswiotlb_dma_get_merge_boundary_distribute(struct device *dev) +{ + return 0; /* can't merge */ +} + +static const struct dma_map_ops pswiotlb_noiommu_dma_ops = { + .flags = DMA_F_PCI_P2PDMA_SUPPORTED, + .alloc = pswiotlb_dma_alloc_distribute, + .free = pswiotlb_dma_free_distribute, + .alloc_pages = pswiotlb_dma_common_alloc_pages_distribute, + .free_pages = pswiotlb_dma_common_free_pages_distribute, + .alloc_noncontiguous = pswiotlb_dma_alloc_noncontiguous_distribute, + .free_noncontiguous = pswiotlb_dma_free_noncontiguous_distribute, + .mmap = pswiotlb_dma_mmap_distribute, + .get_sgtable = pswiotlb_dma_get_sgtable_distribute, + .map_page = pswiotlb_dma_map_page_attrs_distribute, + .unmap_page = pswiotlb_dma_unmap_page_attrs_distribute, + .map_sg = pswiotlb_dma_map_sg_attrs_distribute, + .unmap_sg = pswiotlb_dma_unmap_sg_attrs_distribute, + .sync_single_for_cpu = pswiotlb_dma_sync_single_for_cpu_distribute, + .sync_single_for_device = pswiotlb_dma_sync_single_for_device_distribute, + .sync_sg_for_cpu = pswiotlb_dma_sync_sg_for_cpu_distribute, + .sync_sg_for_device = pswiotlb_dma_sync_sg_for_device_distribute, + .map_resource = pswiotlb_dma_map_resource_distribute, + .unmap_resource = NULL, + .get_merge_boundary = pswiotlb_dma_get_merge_boundary_distribute, + .get_required_mask = pswiotlb_dma_get_required_mask_distribute, + .dma_supported = pswiotlb_dma_supported_distribute, + .max_mapping_size = pswiotlb_dma_max_mapping_size_distribute, + .opt_mapping_size = pswiotlb_dma_opt_mapping_size_distribute, +}; +struct pswiotlb_dma_map_ops *pswiotlb_clone_orig_dma_ops(struct device *dev, + const struct dma_map_ops *ops) +{ + struct pswiotlb_dma_map_ops *new_dma_ops = kmalloc(sizeof(struct pswiotlb_dma_map_ops), + GFP_KERNEL); + if (!new_dma_ops) + return NULL; + + memcpy(new_dma_ops, ops, sizeof(struct pswiotlb_dma_map_ops)); + + return new_dma_ops; +} + +void pswiotlb_setup_dma_ops(struct device *dev) +{ + const struct dma_map_ops *orig_ops = get_dma_ops(dev); + struct pswiotlb_dma_map_ops *new_ops; + struct pci_dev *pdev; + + if (dev && dev_is_pci(dev) && (pswiotlb_force_disable != true) && + is_phytium_ps_socs()) { + pdev = to_pci_dev(dev); + pdev->dev.can_use_pswiotlb = pswiotlb_is_dev_in_passthroughlist(pdev); + dev_info(&pdev->dev, "The device %s use pswiotlb because vendor 0x%04x %s in pswiotlb passthroughlist\n", + pdev->dev.can_use_pswiotlb ? "would" : "would NOT", + pdev->vendor, pdev->dev.can_use_pswiotlb ? "is NOT" : "is"); + } + + if (check_if_pswiotlb_is_applicable(dev)) { + if (!orig_ops) + set_dma_ops(dev, &pswiotlb_noiommu_dma_ops); + else { + new_ops = pswiotlb_clone_orig_dma_ops(dev, orig_ops); + if (!new_ops) { + dev_warn(dev, "Failed to clone dma ops, pswiotlb is NOT applicable\n"); + return; + } + + dev->orig_dma_ops = get_dma_ops(dev); + new_ops->alloc = pswiotlb_dma_alloc_distribute; + new_ops->map_page = pswiotlb_dma_map_page_attrs_distribute; + new_ops->unmap_page = pswiotlb_dma_unmap_page_attrs_distribute; + new_ops->map_sg = pswiotlb_dma_map_sg_attrs_distribute; + new_ops->unmap_sg = pswiotlb_dma_unmap_sg_attrs_distribute; + new_ops->sync_single_for_cpu = + pswiotlb_dma_sync_single_for_cpu_distribute; + new_ops->sync_single_for_device = + pswiotlb_dma_sync_single_for_device_distribute; + new_ops->sync_sg_for_cpu = + pswiotlb_dma_sync_sg_for_cpu_distribute; + new_ops->sync_sg_for_device = + pswiotlb_dma_sync_sg_for_device_distribute; + new_ops->max_mapping_size = + pswiotlb_dma_max_mapping_size_distribute; + new_ops->opt_mapping_size = + pswiotlb_dma_opt_mapping_size_distribute; + + set_dma_ops(dev, (const struct dma_map_ops *)new_ops); + } + } +} -- Gitee From 922fdd176a66e05fb2e2c016ce162d8a37d745ce Mon Sep 17 00:00:00 2001 From: Li Yuze Date: Thu, 22 May 2025 13:53:38 +0800 Subject: [PATCH 042/155] gpio:phytium: Add lock for irq_set_wake function Add lock for irq_set_wake function to prevent concurrency access register issue. Mainline: Open-Source Signed-off-by: Li Yuze Signed-off-by: Wang Yinfeng Change-Id: Ie07caa27c833fcddbabde8300df8242ba06b00dc --- drivers/gpio/gpio-phytium-core.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpio/gpio-phytium-core.c b/drivers/gpio/gpio-phytium-core.c index 33928c4af8..d6fed89964 100644 --- a/drivers/gpio/gpio-phytium-core.c +++ b/drivers/gpio/gpio-phytium-core.c @@ -385,6 +385,7 @@ int phytium_gpio_irq_set_wake(struct irq_data *d, unsigned int enable) struct phytium_gpio *gpio = gpiochip_get_data(gc); struct phytium_gpio_ctx *ctx = &gpio->ctx; irq_hw_number_t bit = irqd_to_hwirq(d); + unsigned long flags; int ret; if (gpio->irq[bit]) @@ -395,6 +396,8 @@ int phytium_gpio_irq_set_wake(struct irq_data *d, unsigned int enable) if (ret < 0) dev_err(gc->parent, "set gpio irq wake failed!\n"); + raw_spin_lock_irqsave(&gpio->lock, flags); + if (enable) { ctx->wake_en |= BIT(bit); if (gpio->is_resuming == 1) { @@ -404,6 +407,8 @@ int phytium_gpio_irq_set_wake(struct irq_data *d, unsigned int enable) } else ctx->wake_en &= ~BIT(bit); + raw_spin_unlock_irqrestore(&gpio->lock, flags); + return 0; } EXPORT_SYMBOL_GPL(phytium_gpio_irq_set_wake); -- Gitee From 825d21ce31ff37243462dedec00ddb16e38cbe01 Mon Sep 17 00:00:00 2001 From: Li Yuze Date: Mon, 9 Jun 2025 16:08:04 +0800 Subject: [PATCH 043/155] kcs: phytium: Disable channel and mask IRQ before request interrupt Disable kcs channel and mask IRQ before request interrupt. If wdt does not reset kcs controller, the channel and IRQ enable will remain on. This patch makes sure the kcs channels and irq disabled before request interrupt to avoid kcs IRQ can't be handled. Mainline: Open-Source Signed-off-by: Li Yuze Signed-off-by: Wang Yinfeng Change-Id: I9ba45fb9f651d02066573d83ad214a063457cc3f --- drivers/char/ipmi/kcs_bmc_phytium.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/char/ipmi/kcs_bmc_phytium.c b/drivers/char/ipmi/kcs_bmc_phytium.c index 32a8b3f8a0..f5911952b2 100644 --- a/drivers/char/ipmi/kcs_bmc_phytium.c +++ b/drivers/char/ipmi/kcs_bmc_phytium.c @@ -380,14 +380,15 @@ static int phytium_kcs_probe(struct platform_device *pdev) if (rc) return rc; + phytium_kcs_enable_channel(kcs_bmc, false); + phytium_kcs_irq_mask_update(kcs_bmc, (KCS_BMC_EVENT_TYPE_IBF | KCS_BMC_EVENT_TYPE_OBE), 0); + rc = phytium_kcs_config_irq(kcs_bmc, pdev); if (rc) return rc; platform_set_drvdata(pdev, priv); - phytium_kcs_irq_mask_update(kcs_bmc, (KCS_BMC_EVENT_TYPE_IBF | KCS_BMC_EVENT_TYPE_OBE), 0); - phytium_kcs_enable_channel(kcs_bmc, true); rc = kcs_bmc_add_device(&priv->kcs_bmc); -- Gitee From d471f4873496c788f6188729d36ff2ca037ac0cc Mon Sep 17 00:00:00 2001 From: Li Yuze Date: Wed, 11 Jun 2025 10:52:14 +0800 Subject: [PATCH 044/155] snoop: phytium: Disable snoop and mask IRQ before request interrupt Disable snoop and mask IRQ before request interrupt. If wdt does not reset snoop controller, the snoop and IRQ enable will remain on. This patch ensures that the snoop and IRQ is disabled before request interrupt to avoid snoop controller'irq can't be handled. Mainline: Open-Source Signed-off-by: Li Yuze Signed-off-by: Wang Yinfeng Change-Id: I5e22f7489fad2ec7f60df4fca095bca3d909caff --- drivers/misc/phytium-snoop-ctrl.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/misc/phytium-snoop-ctrl.c b/drivers/misc/phytium-snoop-ctrl.c index aedb15bbfa..8812299ebf 100644 --- a/drivers/misc/phytium-snoop-ctrl.c +++ b/drivers/misc/phytium-snoop-ctrl.c @@ -275,6 +275,12 @@ static int phytium_snoop_ctrl_probe(struct platform_device *pdev) return -ENODEV; } + regmap_update_bits(snoop_ctrl->regmap, snp_enable_reg, + snp_enable_reg_snp1_en | snp_enable_reg_snp1_int_en, 0); + + regmap_update_bits(snoop_ctrl->regmap, snp_enable_reg, + snp_enable_reg_snp2_en | snp_enable_reg_snp2_int_en, 0); + rc = phytium_snoop_ctrl_config_irq(snoop_ctrl, pdev); if (rc) return rc; -- Gitee From af88d01c2f444ca8e2fc9248289e2dd28bfac72c Mon Sep 17 00:00:00 2001 From: Li Yuze Date: Wed, 11 Jun 2025 11:21:35 +0800 Subject: [PATCH 045/155] bt: phytium: Disable bt channel and mask IRQ before request interrupt Disable BT and mask IRQ before request interrupt. If wdt does not reset BT controller, the BT and IRQ enable will remain on. This patch ensures that the BT and IRQ is disabled before request interrupt to avoid BT controller'irq can't be handled. Mainline: Open-Source Signed-off-by: Li Yuze Signed-off-by: Wang Yinfeng Change-Id: I88ffeab92d7cd91d8d6a0980f118a42b44fd5c54 --- drivers/char/ipmi/bt_bmc_phytium.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/char/ipmi/bt_bmc_phytium.c b/drivers/char/ipmi/bt_bmc_phytium.c index 69567e7fe7..795847c472 100644 --- a/drivers/char/ipmi/bt_bmc_phytium.c +++ b/drivers/char/ipmi/bt_bmc_phytium.c @@ -427,6 +427,10 @@ static int bt_bmc_config_irq(struct bt_bmc *bt_bmc, if (!bt_bmc->irq) return -ENODEV; + rc = regmap_update_bits(bt_bmc->map, BT_CSR1, + BT_CSR1_IRQ_H2B | BT_CSR1_IRQ_HWRST, + 0); + rc = devm_request_irq(dev, bt_bmc->irq, bt_bmc_irq, IRQF_SHARED, DEVICE_NAME, bt_bmc); if (rc < 0) { @@ -481,6 +485,10 @@ static int bt_bmc_probe(struct platform_device *pdev) return rc; } + regmap_update_bits(bt_bmc->map, LPC_HICR0, LPC_HICR0_LPC3E, 0); + regmap_update_bits(bt_bmc->map, LPC_HICR4, LPC_BTENABLE, 0); + regmap_update_bits(bt_bmc->map, LPC_HICR2, LPC_HICR2_IBFIF3, 0); + bt_bmc_config_irq(bt_bmc, pdev); if (bt_bmc->irq) { -- Gitee From 2e102bdffa42ec61ee9e5e8e2da28ecb7f2dffe1 Mon Sep 17 00:00:00 2001 From: Li Yuze Date: Thu, 22 May 2025 11:48:28 +0800 Subject: [PATCH 046/155] gpio: phytium: Add irq clear macro and delete redundant code Add irq clear macro definitions as 0xffffffff to make the code more standardized. And delete the redundant code about "is_resuming" variable initialization. Mainline: Open-Source Signed-off-by: Li Yuze Signed-off-by: Wang Yinfeng Change-Id: Ied14628e13a05e51480b802a422d8d7428ce37ab --- drivers/gpio/gpio-phytium-core.h | 3 ++- drivers/gpio/gpio-phytium-pci.c | 5 ++--- drivers/gpio/gpio-phytium-platform.c | 5 ++--- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/gpio/gpio-phytium-core.h b/drivers/gpio/gpio-phytium-core.h index 739ddc18a0..8af0e4808f 100644 --- a/drivers/gpio/gpio-phytium-core.h +++ b/drivers/gpio/gpio-phytium-core.h @@ -32,8 +32,9 @@ #define NGPIO_DEFAULT 8 #define NGPIO_MAX 32 #define GPIO_PORT_STRIDE (GPIO_EXT_PORTB - GPIO_EXT_PORTA) +#define GPIO_CLEAR_IRQ 0xffffffff -#define PHYTIUM_GPIO_DRIVER_VERSION "1.1.1" +#define PHYTIUM_GPIO_DRIVER_VERSION "1.1.2" struct pin_loc { unsigned int port; diff --git a/drivers/gpio/gpio-phytium-pci.c b/drivers/gpio/gpio-phytium-pci.c index be4670936b..e3074342d1 100644 --- a/drivers/gpio/gpio-phytium-pci.c +++ b/drivers/gpio/gpio-phytium-pci.c @@ -74,7 +74,7 @@ static int phytium_gpio_pci_probe(struct pci_dev *pdev, const struct pci_device_ raw_spin_lock_init(&gpio->lock); writel(0, gpio->regs + GPIO_INTEN); - writel(0xffffffff, gpio->regs + GPIO_PORTA_EOI); + writel(GPIO_CLEAR_IRQ, gpio->regs + GPIO_PORTA_EOI); gpio->gc.base = -1; gpio->gc.get_direction = phytium_gpio_get_direction; @@ -90,7 +90,6 @@ static int phytium_gpio_pci_probe(struct pci_dev *pdev, const struct pci_device_ girq = &gpio->gc.irq; girq->handler = handle_bad_irq; girq->default_type = IRQ_TYPE_NONE; - gpio->is_resuming = 0; girq->num_parents = 1; girq->parents = devm_kcalloc(&pdev->dev, girq->num_parents, @@ -171,7 +170,7 @@ static int phytium_gpio_pci_resume(struct device *dev) writel(gpio->ctx.int_polarity, gpio->regs + GPIO_INT_POLARITY); writel(gpio->ctx.debounce, gpio->regs + GPIO_DEBOUNCE); - writel(0xffffffff, gpio->regs + GPIO_PORTA_EOI); + writel(GPIO_CLEAR_IRQ, gpio->regs + GPIO_PORTA_EOI); writel(gpio->ctx.inten, gpio->regs + GPIO_INTEN); gpio->is_resuming = 0; diff --git a/drivers/gpio/gpio-phytium-platform.c b/drivers/gpio/gpio-phytium-platform.c index 5fd6201b96..2d087b0327 100644 --- a/drivers/gpio/gpio-phytium-platform.c +++ b/drivers/gpio/gpio-phytium-platform.c @@ -93,7 +93,7 @@ static int phytium_gpio_probe(struct platform_device *pdev) raw_spin_lock_init(&gpio->lock); writel(0, gpio->regs + GPIO_INTEN); - writel(0xffffffff, gpio->regs + GPIO_PORTA_EOI); + writel(GPIO_CLEAR_IRQ, gpio->regs + GPIO_PORTA_EOI); gpio->gc.base = -1; gpio->gc.get_direction = phytium_gpio_get_direction; @@ -109,7 +109,6 @@ static int phytium_gpio_probe(struct platform_device *pdev) girq = &gpio->gc.irq; girq->handler = handle_bad_irq; girq->default_type = IRQ_TYPE_NONE; - gpio->is_resuming = 0; for (irq_count = 0; irq_count < platform_irq_count(pdev); irq_count++) { gpio->irq[irq_count] = -ENXIO; @@ -187,7 +186,7 @@ static int phytium_gpio_resume(struct device *dev) writel(gpio->ctx.int_polarity, gpio->regs + GPIO_INT_POLARITY); writel(gpio->ctx.debounce, gpio->regs + GPIO_DEBOUNCE); - writel(0xffffffff, gpio->regs + GPIO_PORTA_EOI); + writel(GPIO_CLEAR_IRQ, gpio->regs + GPIO_PORTA_EOI); writel(gpio->ctx.inten, gpio->regs + GPIO_INTEN); gpio->is_resuming = 0; -- Gitee From 24ddee594aa10d6885d16c72843d1efd628762c2 Mon Sep 17 00:00:00 2001 From: Chen Zhenhua Date: Tue, 1 Jul 2025 14:18:02 +0800 Subject: [PATCH 047/155] usb: phytium_v2: Fixed USB host controller stop logic The correct stop logic is to release the controller resources first, and then stop the HOST working mode, otherwise the resources release may fail. Mainline: Open-Source Signed-off-by: Chen Zhenhua Signed-off-by: Wang Yinfeng Change-Id: I8e4f6b68b9fe3de3cac30d249a8442d254d9c944 --- drivers/usb/phytium_usb_v2/host.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/phytium_usb_v2/host.c b/drivers/usb/phytium_usb_v2/host.c index 28151f1faf..40e066bad5 100644 --- a/drivers/usb/phytium_usb_v2/host.c +++ b/drivers/usb/phytium_usb_v2/host.c @@ -115,10 +115,10 @@ static void host_stop(void *data) struct phytium_usb *phytium_usb = (struct phytium_usb *)data; if (phytium_usb) { - phytium_usb_otg_host_off((void *)phytium_usb); kfree(phytium_usb->host_plat_data); platform_device_unregister(phytium_usb->host_dev); phytium_usb->host_dev = NULL; + phytium_usb_otg_host_off((void *)phytium_usb); } } -- Gitee From 612c7b0acfa592fb563199f31145f856445285b7 Mon Sep 17 00:00:00 2001 From: Chen Zhenhua Date: Fri, 4 Jul 2025 14:58:34 +0800 Subject: [PATCH 048/155] usb: xhci: Disable stream for PHYTIUM platform xHC controller This patch disable stream for PHYTIUM platform xHC controller with XHCI_BROKEN_STREAMS Mainline: Open-Source Signed-off-by: Chen Zhenhua Signed-off-by: Wang Yinfeng Change-Id: I777898447a4b5afb495d79c9cfdca3ab422aed36 --- drivers/usb/host/xhci-plat.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index 2025465152..e4bdfdeb0d 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -101,7 +101,8 @@ static int xhci_plat_start(struct usb_hcd *hcd) } static const struct xhci_plat_priv xhci_plat_phytium_pe220x = { - .quirks = XHCI_RESET_ON_RESUME | XHCI_S1_SUSPEND_WAKEUP, + .quirks = XHCI_RESET_ON_RESUME | XHCI_S1_SUSPEND_WAKEUP | + XHCI_BROKEN_STREAMS, }; #ifdef CONFIG_OF @@ -320,7 +321,8 @@ int xhci_plat_probe(struct platform_device *pdev, struct device *sysdev, const s } usb3_hcd = xhci_get_usb3_hcd(xhci); - if (usb3_hcd && HCC_MAX_PSA(xhci->hcc_params) >= 4) + if (usb3_hcd && HCC_MAX_PSA(xhci->hcc_params) >= 4 && + !(xhci->quirks & XHCI_BROKEN_STREAMS)) usb3_hcd->can_do_streams = 1; if (xhci->shared_hcd) { -- Gitee From 7d1ac5c845a0c7de1719a5f303bddf9ebef497ea Mon Sep 17 00:00:00 2001 From: Chen Zhenhua Date: Mon, 14 Jul 2025 09:43:54 +0800 Subject: [PATCH 049/155] usb: phytium: Add a forced operation to send the port reset command In the HubPortReset function, add a forced operation to send port reset command to fix the issue where the port reset command is not sent, casusing abnormal device operation. Mainline: Open-Source Signed-off-by: Chen Zhenhua Signed-off-by: Wang Yinfeng Change-Id: I65d2f074bd6394aa067bc2eed299ef434b3420aa --- drivers/usb/phytium/host.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/phytium/host.c b/drivers/usb/phytium/host.c index 8572c58f41..25cad697b9 100644 --- a/drivers/usb/phytium/host.c +++ b/drivers/usb/phytium/host.c @@ -26,6 +26,7 @@ #define HOST_ESHUTDOWN 4 #define HOST_EP_NUM 16 +#define FORCE_PORT_RESET 0x60 static void dump_ep_remap_pool(struct HOST_CTRL *priv, bool dirIn) { @@ -2334,6 +2335,7 @@ static void HubPortReset(struct HOST_CTRL *priv, uint8_t on) phytium_write8(&priv->regs->ep0fifoctrl, FIFOCTRL_FIFOAUTO | FIFOCTRL_IO_TX | 0 | 0x04); + phytium_write8(&priv->regs->portctrl, FORCE_PORT_RESET); priv->portStatus |= USB_PORT_STAT_RESET; priv->portStatus &= ~USB_PORT_STAT_ENABLE; priv->port_resetting = 0; -- Gitee From b4a993a45c1af76ceb636dc2fd95e1658c73389e Mon Sep 17 00:00:00 2001 From: Xiao Cong Date: Wed, 11 Jun 2025 16:17:40 +0800 Subject: [PATCH 050/155] PCI: Add ACS quirk for phytium root and switch ports The phytium PCIe root ports and X100 switch do not support ACS at this point. However, the hardware provides isolation and source validation through the SMMU. The stream ID generated by the PCIe ports contain both the bus/device/function number as well as the port ID in its 3 most significant bits. Turn on ACS but disable all the peer-to-peer features. Mainline: Open-Source Signed-off-by: Wang Yinfeng Signed-off-by: Xiao Cong Change-Id: I468f41916ea98f7bc27744e5f9913aec47042638 --- drivers/pci/quirks.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 399b1def4c..86f4aec816 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -5159,6 +5159,10 @@ static const struct pci_dev_acs_enabled { { PCI_VENDOR_ID_ZHAOXIN, PCI_ANY_ID, pci_quirk_zhaoxin_pcie_ports_acs }, /* Wangxun nics */ { PCI_VENDOR_ID_WANGXUN, PCI_ANY_ID, pci_quirk_wangxun_nic_acs }, + /* Phytium Technology */ + { 0x10b5, PCI_ANY_ID, pci_quirk_xgene_acs }, + { 0x17cd, PCI_ANY_ID, pci_quirk_xgene_acs }, + { 0x1db7, PCI_ANY_ID, pci_quirk_xgene_acs }, { 0 } }; -- Gitee From 7b8d921e5a3d3ddd167b6fb7700ba2060911d23a Mon Sep 17 00:00:00 2001 From: Li Yuze Date: Mon, 8 Jul 2024 10:39:18 +0800 Subject: [PATCH 051/155] kcs: phytium: Avoid OBF and IBF not being set right on pe220x BMC cards This patch reads ODR and writes IDR twice to avoid unessasery trouble on phytium pe220x BMC cards. Mainline: NA Signed-off-by: Li Yuze Signed-off-by: Wang Yinfeng Change-Id: I4f9e3e19ec311167e861adacf9124fb3ac75c9ed --- drivers/char/ipmi/kcs_bmc_phytium.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/char/ipmi/kcs_bmc_phytium.c b/drivers/char/ipmi/kcs_bmc_phytium.c index f5911952b2..e07b3ebe2a 100644 --- a/drivers/char/ipmi/kcs_bmc_phytium.c +++ b/drivers/char/ipmi/kcs_bmc_phytium.c @@ -121,6 +121,10 @@ static u8 phytium_kcs_inb(struct kcs_bmc_device *kcs_bmc, u32 reg) rc = regmap_read(priv->map, reg, &val); WARN(rc != 0, "regmap_read() failed: %d\n", rc); + if (reg == LPC_IDR1 || reg == LPC_IDR2 || + reg == LPC_IDR3 || reg == LPC_IDR4) + rc = regmap_read(priv->map, reg, &val); + return rc == 0 ? (u8) val : 0; } @@ -129,6 +133,10 @@ static void phytium_kcs_outb(struct kcs_bmc_device *kcs_bmc, u32 reg, u8 data) struct phytium_kcs_bmc *priv = to_phytium_kcs_bmc(kcs_bmc); int rc; + if (reg == LPC_ODR1 || reg == LPC_ODR2 || + reg == LPC_ODR3 || reg == LPC_ODR4) + regmap_write(priv->map, reg, data); + rc = regmap_write(priv->map, reg, data); WARN(rc != 0, "regmap_write() failed: %d\n", rc); } -- Gitee From 66d6a9c74c8bc758be910769065ec97477511580 Mon Sep 17 00:00:00 2001 From: Li Yuze Date: Tue, 13 May 2025 15:35:54 +0800 Subject: [PATCH 052/155] watchdog: dw: Modify rate date type from u64 to u32 Because the clock frequency represented by u32 type meets the usage requirements, so modify rate date type from u64 to u32 to solve the compilation issue in arm32: [build warning: ERROR: modpost: "__aeabi_uldivmod" undefined!] Mainline: Open-Source Signed-off-by: Li Yuze Signed-off-by: Wang Yinfeng Change-Id: I99bb02935a5bbec88f9b2c36ca184322cbe1a0f4 --- drivers/watchdog/dw_wdt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/watchdog/dw_wdt.c b/drivers/watchdog/dw_wdt.c index c444082e04..5ac9c3b2bd 100644 --- a/drivers/watchdog/dw_wdt.c +++ b/drivers/watchdog/dw_wdt.c @@ -84,7 +84,7 @@ struct dw_wdt { void __iomem *regs; struct clk *clk; struct clk *pclk; - u64 rate; + u32 rate; enum dw_wdt_rmod rmod; struct dw_wdt_timeout timeouts[DW_WDT_NUM_TOPS]; struct watchdog_device wdd; @@ -595,7 +595,7 @@ static int dw_wdt_drv_probe(struct platform_device *pdev) * are not available, so watchdog rate get from * clock-frequency property given in _DSD object. */ - device_property_read_u64(dev, "clock-frequency", + device_property_read_u32(dev, "clock-frequency", &dw_wdt->rate); if (dw_wdt->rate == 0) return -EINVAL; -- Gitee From 37c809f0f6c97e3084fc1ae19499057e6de309ed Mon Sep 17 00:00:00 2001 From: Li Mingzhe Date: Thu, 17 Jul 2025 08:54:32 +0800 Subject: [PATCH 053/155] devfreq: Phytium: Modify some issues related to the dmu driver Firstly, replace ioremap with devm_ioremap. The advantage of this approach is that it can be automatically managed during the unloading stage, eliminating the need for manual resource cleanup, thus preventing resource leakage. Secondly, resolve the repeated printing issues. Mainline: Open-Source Signed-off-by: Li Mingzhe Signed-off-by: Wang Yinfeng Change-Id: Iad95dd70a7fca7b8cb6d1b22d426b0a7e6b0e5ce --- drivers/devfreq/phytium_dmu.c | 35 ++++++++++++++--------------------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/drivers/devfreq/phytium_dmu.c b/drivers/devfreq/phytium_dmu.c index 46062b2a53..7c9f8ffbcc 100644 --- a/drivers/devfreq/phytium_dmu.c +++ b/drivers/devfreq/phytium_dmu.c @@ -41,7 +41,7 @@ #define DDR_PMU_NOTICE_START 0x0 #define DDR_PMU_NOTICE_STOP 0x1 -#define DMUFREQ_DRIVER_VERSION "1.0.0" +#define DMUFREQ_DRIVER_VERSION "1.0.1" struct phytium_dmufreq { struct device *dev; @@ -91,7 +91,6 @@ static inline unsigned long dmu_read32(struct phytium_dmufreq *priv, int dmu, return readl_relaxed(priv->base[dmu] + offest); } -#if IS_ENABLED(CONFIG_PHYT_DMU_PMU_PD2408) BLOCKING_NOTIFIER_HEAD(dmu_pmu_notifier_chain); EXPORT_SYMBOL(dmu_pmu_notifier_chain); @@ -116,7 +115,6 @@ static int dmu_pmu_notifier_call(struct notifier_block *nb, unsigned long event, return NOTIFY_OK; } -#endif static ktime_t stop; @@ -262,7 +260,7 @@ struct acpi_result phytium_read_threshold_value(struct device *dev) status = acpi_evaluate_integer(handle, "BAND", NULL, &single_threshold_value); if (ACPI_FAILURE(status)) { - dev_err(dev, "Failed to evaluate BAND method: ACPI status 0x%x\n", status); + WARN_ONCE(1, "Failed to evaluate BAND method: ACPI status 0x%x\n", status); result.status = -EIO; result.value = 0; return result; @@ -342,7 +340,7 @@ static int phytium_dmu_get_dev_status(struct device *dev, result = phytium_read_threshold_value(dev); if (result.status) { - dev_err(dev, "Failed to get threshold value\n"); + WARN_ONCE(1, "Failed to get threshold value\n"); return -EINVAL; } single_threshold_value = result.value; @@ -519,7 +517,6 @@ static int phytium_dmufreq_probe(struct platform_device *pdev) } platform_set_drvdata(pdev, priv); -#if IS_ENABLED(CONFIG_PHYT_DMU_PMU_PD2408) /* Register the notifier */ priv->nb.notifier_call = dmu_pmu_notifier_call; ret = blocking_notifier_chain_register(&dmu_pmu_notifier_chain, &priv->nb); @@ -527,14 +524,17 @@ static int phytium_dmufreq_probe(struct platform_device *pdev) dev_err(dev, "Failed to register notifier\n"); return ret; } -#endif /* Get the base address of the DMU PMU */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - for (int i = 0; i < priv->max_count; i++) { - priv->base[i] = ioremap(res->start + i * DMU_PMU_STRIDE, resource_size(res)); - if (!priv->base[i]) - return -ENOMEM; + for (i = 0; i < priv->max_count; i++) { + resource_size_t offset = res->start + i * DMU_PMU_STRIDE; + + priv->base[i] = devm_ioremap(&pdev->dev, offset, resource_size(res)); + if (IS_ERR(priv->base[i])) { + dev_err(dev, "Ioremap failed for dmu base resource\n"); + return PTR_ERR(priv->base); + } } ret = phytium_dmu_get_freq_info(dev); @@ -593,7 +593,6 @@ static int phytium_dmufreq_probe(struct platform_device *pdev) err: dev_pm_opp_of_remove_table(dev); - kfree(priv); return ret; } @@ -603,24 +602,19 @@ static int phytium_dmufreq_remove(struct platform_device *pdev) struct device *dev = &pdev->dev; for (int i = 0; i < priv->max_count; i++) { - dmu_write32(priv, i, AXI_MONITOR_EN, 0x0); dmu_write32(priv, i, TIMER_STOP, 0x1); + dmu_write32(priv, i, AXI_MONITOR_EN, 0x0); } -#if IS_ENABLED(CONFIG_PHYT_DMU_PMU_PD2408) /*Unregister the notifier*/ blocking_notifier_chain_unregister(&dmu_pmu_notifier_chain, &priv->nb); -#endif if (!priv->devfreq) return 0; - flush_work(&priv->work); del_timer_sync(&priv->sampling); - + cancel_work_sync(&priv->work); dev_pm_opp_remove_all_dynamic(dev); - kfree(priv); - return 0; } @@ -635,11 +629,9 @@ MODULE_DEVICE_TABLE(acpi, phytium_dmufreq_acpi_ids); #define phytium_dmu_acpi_ids NULL #endif -#if IS_ENABLED(CONFIG_PHYT_DMU_PMU_PD2408) struct notifier_block nb = { .notifier_call = dmu_pmu_notifier_call, }; -#endif static struct platform_driver phytium_dmufreq_driver = { .probe = phytium_dmufreq_probe, @@ -655,5 +647,6 @@ module_platform_driver(phytium_dmufreq_driver); MODULE_DESCRIPTION("Phytium DDR Memory Unit frequency driver"); MODULE_AUTHOR("Li Jiayi "); +MODULE_AUTHOR("Li Mingzhe "); MODULE_LICENSE("GPL"); MODULE_VERSION(DMUFREQ_DRIVER_VERSION); -- Gitee From 6be412b74cda4eb9f3193332a3c47e6c2ec6101f Mon Sep 17 00:00:00 2001 From: Li Mingzhe Date: Fri, 11 Jul 2025 14:51:51 +0800 Subject: [PATCH 054/155] devfreq: Phytium: Modify the sampling logic of DMU driver Optimize the timer logic for sampling, with the aim of reducing the frequent calls made by processes within the system. It is very helpfull to reduce power consumption. Mainline: Open-Source Signed-off-by: Li Mingzhe Signed-off-by: Wang Yinfeng Change-Id: I4a0d4ba12d470ef88be50e09ebb75e1b05baea06 --- drivers/devfreq/phytium_dmu.c | 90 ++++++++++------------------------- 1 file changed, 25 insertions(+), 65 deletions(-) diff --git a/drivers/devfreq/phytium_dmu.c b/drivers/devfreq/phytium_dmu.c index 7c9f8ffbcc..44ddf5dd07 100644 --- a/drivers/devfreq/phytium_dmu.c +++ b/drivers/devfreq/phytium_dmu.c @@ -25,8 +25,6 @@ #define DEVICE_TYPE 9 //DMU ID -#define UPDATE_INTERVAL_MS 10 - #define DMU_PMU_STRIDE 0x80000 #define AXI_MONITOR2_L 0x084 @@ -41,7 +39,7 @@ #define DDR_PMU_NOTICE_START 0x0 #define DDR_PMU_NOTICE_STOP 0x1 -#define DMUFREQ_DRIVER_VERSION "1.0.1" +#define DMUFREQ_DRIVER_VERSION "1.0.2" struct phytium_dmufreq { struct device *dev; @@ -52,6 +50,7 @@ struct phytium_dmufreq { unsigned long rate, target_rate; unsigned long bandwidth; + unsigned long single_threshold_value; int max_count; int cnt; @@ -60,9 +59,6 @@ struct phytium_dmufreq { unsigned long *read_bw; unsigned long *write_bw; - struct timer_list sampling; - struct work_struct work; - struct notifier_block nb; /*dmu to pmu operation status identification 0: not operable, 1: operable*/ @@ -116,7 +112,6 @@ static int dmu_pmu_notifier_call(struct notifier_block *nb, unsigned long event, return NOTIFY_OK; } -static ktime_t stop; static int phytium_dmu_set_freq(struct device *dev, unsigned long freq) { @@ -275,8 +270,9 @@ static u64 phytium_dmufreq_get_real_bw(struct phytium_dmufreq *priv) { unsigned long peak_bw = 0; unsigned long sum_peak_bw = 0; + int i; - for (int i = 0; i < priv->max_count; i++) { + for (i = 0; i < priv->max_count; i++) { priv->read_bw[i] = dmu_read32(priv, i, AXI_MONITOR2_L); priv->write_bw[i] = dmu_read32(priv, i, AXI_MONITOR3_L); @@ -291,66 +287,36 @@ static u64 phytium_dmufreq_get_real_bw(struct phytium_dmufreq *priv) return peak_bw; } -static void sampling_timer_callback(struct timer_list *t) -{ - struct phytium_dmufreq *priv = from_timer(priv, t, sampling); - - schedule_work(&priv->work); -} - -static void sampling_work_handle(struct work_struct *work) +static void polling_handle(struct phytium_dmufreq *priv) { - struct phytium_dmufreq *priv = container_of(work, struct phytium_dmufreq, work); - static unsigned long load_counter; - static int count; - unsigned long current_load; + int i; /*if the pmu_reg is not active, return the last busy time(pmu_reg not work)*/ if (!priv->pmu_active) { priv->bandwidth = priv->last_bust_time; - mod_timer(&priv->sampling, jiffies + msecs_to_jiffies(UPDATE_INTERVAL_MS)); return; } if (priv->cnt > 0) { - for (int i = 0; i < priv->max_count ; i++) { + for (i = 0; i < priv->max_count ; i++) { dmu_write32(priv, i, AXI_MONITOR_EN, 0x101); dmu_write32(priv, i, TIMER_STOP, 0x1); } - current_load = phytium_dmufreq_get_real_bw(priv); - load_counter += current_load; - count += 1; + priv->bandwidth = phytium_dmufreq_get_real_bw(priv); } priv->cnt = 1; - if (ktime_after(ktime_get(), stop)) { - priv->bandwidth = div64_u64(load_counter, count); - load_counter = 0; - count = 0; - stop = ktime_add_ms(ktime_get(), priv->profile.polling_ms); - mod_timer(&priv->sampling, jiffies + msecs_to_jiffies(UPDATE_INTERVAL_MS)); - } else - mod_timer(&priv->sampling, jiffies + msecs_to_jiffies(UPDATE_INTERVAL_MS)); } static int phytium_dmu_get_dev_status(struct device *dev, struct devfreq_dev_status *stat) { struct phytium_dmufreq *priv = dev_get_drvdata(dev); - struct acpi_result result; - unsigned long long single_threshold_value; - result = phytium_read_threshold_value(dev); - if (result.status) { - WARN_ONCE(1, "Failed to get threshold value\n"); - return -EINVAL; - } - single_threshold_value = result.value; - single_threshold_value = (single_threshold_value * 1024 * 1024) / 100; + polling_handle(priv); + priv->last_bust_time = stat->busy_time = priv->bandwidth; + stat->total_time = (priv->single_threshold_value * priv->rate) / priv->freq_table[0]; - stat->busy_time = priv->bandwidth; - stat->total_time = (single_threshold_value * priv->rate) / priv->freq_table[0]; - priv->last_bust_time = priv->bandwidth; dev_dbg(dev, "busy_time = %lu, total_time = %lu,single_threshold_value = %llu\n", - stat->busy_time, stat->total_time, single_threshold_value); + stat->busy_time, stat->total_time, priv->single_threshold_value); stat->current_frequency = priv->rate; return 0; @@ -439,9 +405,6 @@ static __maybe_unused int phytium_dmufreq_suspend(struct device *dev) dev_dbg(dev, "DMU is being suspended\n"); - del_timer_sync(&priv->sampling); - flush_work(&priv->work); - ret = devfreq_suspend_device(priv->devfreq); if (ret < 0) { dev_err(dev, "failed to suspend the devfreq devices\n"); @@ -464,11 +427,6 @@ static __maybe_unused int phytium_dmufreq_resume(struct device *dev) return ret; } - if (!timer_pending(&priv->sampling)) - mod_timer(&priv->sampling, jiffies + msecs_to_jiffies(UPDATE_INTERVAL_MS)); - else - dev_warn(dev, "Sampling timer already active ,skipping reinitialization\n"); - return 0; } @@ -485,6 +443,9 @@ static int phytium_dmufreq_probe(struct platform_device *pdev) struct acpi_result result; struct resource *res; + if (max_state <= 0) + return -EINVAL; + result = phytium_dmufreq_state(dev); if (result.value == 0) { dev_err(dev, "DMUFREQ is not enabled\n"); @@ -503,8 +464,13 @@ static int phytium_dmufreq_probe(struct platform_device *pdev) priv->max_count = result.value; - if (max_state <= 0) - return max_state; + result = phytium_read_threshold_value(dev); + if (result.status) { + dev_err(dev, "Failed to get threshold value\n"); + return -EINVAL; + } + priv->single_threshold_value = result.value; + priv->single_threshold_value = (priv->single_threshold_value * 1024 * 1024) / 10; dev->init_name = "dmufreq"; @@ -575,18 +541,13 @@ static int phytium_dmufreq_probe(struct platform_device *pdev) /*Enable PMU*/ if (priv->pmu_active) { - for (int i = 0; i < priv->max_count; i++) { + for (i = 0; i < priv->max_count; i++) { dmu_write32(priv, i, AXI_MONITOR_EN, 0x101); dmu_write32(priv, i, CLEAR_EVENT, 0x1); dmu_write32(priv, i, TIMER_START, 0x1); } } - INIT_WORK(&priv->work, sampling_work_handle); - timer_setup(&priv->sampling, sampling_timer_callback, 0); - stop = ktime_add_ms(ktime_get(), priv->profile.polling_ms); - mod_timer(&priv->sampling, jiffies + msecs_to_jiffies(UPDATE_INTERVAL_MS)); - priv->dev = dev; return 0; @@ -600,8 +561,9 @@ static int phytium_dmufreq_remove(struct platform_device *pdev) { struct phytium_dmufreq *priv = platform_get_drvdata(pdev); struct device *dev = &pdev->dev; + int i; - for (int i = 0; i < priv->max_count; i++) { + for (i = 0; i < priv->max_count; i++) { dmu_write32(priv, i, TIMER_STOP, 0x1); dmu_write32(priv, i, AXI_MONITOR_EN, 0x0); } @@ -611,8 +573,6 @@ static int phytium_dmufreq_remove(struct platform_device *pdev) if (!priv->devfreq) return 0; - del_timer_sync(&priv->sampling); - cancel_work_sync(&priv->work); dev_pm_opp_remove_all_dynamic(dev); return 0; -- Gitee From 98b9c9e878c6128944c9ee1958c36b843068cb76 Mon Sep 17 00:00:00 2001 From: Li Mingzhe Date: Thu, 17 Jul 2025 09:00:48 +0800 Subject: [PATCH 055/155] devfreq: Phytium: Delete the unnecessary release of resources Delete the unnecessary release of resources when using devm_kzalloc function to allocate memory. Mainline: Open-Source Signed-off-by: Li Mingzhe Signed-off-by: Wang Yinfeng Change-Id: I37db095a57ca3ac8f8847a9519e0b9e627ed20ac --- drivers/devfreq/phytium_noc.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/devfreq/phytium_noc.c b/drivers/devfreq/phytium_noc.c index 9658d95061..49b576c1bb 100644 --- a/drivers/devfreq/phytium_noc.c +++ b/drivers/devfreq/phytium_noc.c @@ -26,7 +26,7 @@ #define DEBUG #define DEVICE_TYPE 7 -#define NOCFREQ_DRIVER_VERSION "1.0.0" +#define NOCFREQ_DRIVER_VERSION "1.0.1" struct phytium_nocfreq { struct device *dev; @@ -379,7 +379,6 @@ static int phytium_nocfreq_probe(struct platform_device *pdev) err: dev_pm_opp_of_remove_table(dev); - kfree(priv); return ret; } @@ -404,13 +403,10 @@ static int phytium_nocfreq_remove(struct platform_device *pdev) if (ret) dev_warn(dev, "failed to restore NOC frequency: %d\n", ret); - iounmap(priv->reg_noc); - if (!priv->devfreq) return 0; dev_pm_opp_remove_all_dynamic(dev); - kfree(priv); return 0; } -- Gitee From e754e8922a13fa1d043b56af07fbe8b2d37430f2 Mon Sep 17 00:00:00 2001 From: Li Mingzhe Date: Fri, 11 Jul 2025 13:52:55 +0800 Subject: [PATCH 056/155] devfreq: Phytium: Add power mangement interface for noc devfreq This patch adds power mangement interface, Specifically adds the phytium_nocfreq_suspend/phytium_nocfreq_resume functions so that the frequency can be restored upon waking up. Mainline: Open-Source Signed-off-by: Li Mingzhe Signed-off-by: Wang Yinfeng Change-Id: I99e1fda9a339d4f4eb444ee61d4ccc1f2744b9b7 --- drivers/devfreq/phytium_noc.c | 74 ++++++++++++++++++++++++++++++++++- 1 file changed, 72 insertions(+), 2 deletions(-) diff --git a/drivers/devfreq/phytium_noc.c b/drivers/devfreq/phytium_noc.c index 49b576c1bb..9225313eb0 100644 --- a/drivers/devfreq/phytium_noc.c +++ b/drivers/devfreq/phytium_noc.c @@ -14,6 +14,7 @@ #include #include #include +#include #define MINI_SIZE 0x400 #define CNT_ENABLE 0x000 @@ -26,7 +27,7 @@ #define DEBUG #define DEVICE_TYPE 7 -#define NOCFREQ_DRIVER_VERSION "1.0.1" +#define NOCFREQ_DRIVER_VERSION "1.0.2" struct phytium_nocfreq { struct device *dev; @@ -38,7 +39,7 @@ struct phytium_nocfreq { void __iomem *reg_noc; struct mutex lock; - unsigned long rate, target_rate; + unsigned long rate, target_rate, suspend_freq; unsigned int freq_count; unsigned long freq_table[]; }; @@ -297,6 +298,74 @@ static int phytium_noc_get_dev_status(struct device *dev, return 0; } +static __maybe_unused int phytium_nocfreq_suspend(struct device *dev) +{ + struct phytium_nocfreq *priv = dev_get_drvdata(dev); + int ret = 0; + + dev_dbg(dev, "NOCfreq is being suspended\n"); + + ret = phytium_noc_get_cur_freq(dev, &priv->suspend_freq); + if (ret) + dev_warn(dev, "failed to get suspend freq\n"); + else + dev_info(dev, "saved suspend freq = %lu\n", priv->suspend_freq); + + ret = devfreq_suspend_device(priv->devfreq); + if (ret < 0) { + dev_err(dev, "failed to suspend the devfreq devices\n"); + return ret; + } + priv->devfreq->stop_polling = true; + + writel_relaxed(0x0, priv->reg_noc + CNT_ENABLE); + writel_relaxed(0x0, priv->reg_noc + MINI_SIZE*1+CNT_ENABLE); + writel_relaxed(0x0, priv->reg_noc + MINI_SIZE*2+CNT_ENABLE); + writel_relaxed(0x0, priv->reg_noc + MINI_SIZE*3+CNT_ENABLE); + + return ret; +} + +static __maybe_unused int phytium_nocfreq_resume(struct device *dev) +{ + struct phytium_nocfreq *priv = dev_get_drvdata(dev); + int ret = 0; + + dev_dbg(dev, "NOCfreq is being resumed\n"); + + ret = devfreq_resume_device(priv->devfreq); + if (ret < 0) { + dev_err(dev, "failed to resume the devfreq devices\n"); + return ret; + } + if (!delayed_work_pending(&priv->devfreq->work) && priv->devfreq->profile->polling_ms) { + dev_info(dev, "Polling work not pending, manually restarting polling\n"); + priv->devfreq->stop_polling = true; + } + writel_relaxed(0x02, priv->reg_noc + WORK_STATE); + writel_relaxed(0x02, priv->reg_noc + MINI_SIZE*1 + WORK_STATE); + writel_relaxed(0x02, priv->reg_noc + MINI_SIZE*2 + WORK_STATE); + writel_relaxed(0x02, priv->reg_noc + MINI_SIZE*3 + WORK_STATE); + + writel_relaxed(0x3f, priv->reg_noc + CNT_ENABLE); + writel_relaxed(0x3f, priv->reg_noc + MINI_SIZE*1+CNT_ENABLE); + writel_relaxed(0x3f, priv->reg_noc + MINI_SIZE*2+CNT_ENABLE); + writel_relaxed(0x3f, priv->reg_noc + MINI_SIZE*3+CNT_ENABLE); + + if (priv->suspend_freq) { + ret = phytium_noc_set_freq(dev, priv->suspend_freq); + if (ret < 0) + dev_warn(dev, "failed to restore suspend freq %lu\n", priv->suspend_freq); + else { + dev_info(dev, "restored suspend freq = %lu\n", priv->suspend_freq); + priv->rate = priv->suspend_freq; + } + } + return ret; +} + +static SIMPLE_DEV_PM_OPS(phytium_nocfreq_pm, phytium_nocfreq_suspend, + phytium_nocfreq_resume); static int phytium_nocfreq_probe(struct platform_device *pdev) { @@ -423,6 +492,7 @@ static struct platform_driver phytium_nocfreq_driver = { .remove = phytium_nocfreq_remove, .driver = { .name = "phytium_nocfreq", + .pm = &phytium_nocfreq_pm, .acpi_match_table = ACPI_PTR(phytium_noc_acpi_ids), .suppress_bind_attrs = true, }, -- Gitee From 435c226872154129903b6e758a28f424b8d932e8 Mon Sep 17 00:00:00 2001 From: Yang Jianren Date: Tue, 13 May 2025 18:06:39 +0800 Subject: [PATCH 057/155] staging: npu: Slove some clang compile errors and Kconfig format The patch Fixed some clang compile errors and optimized the structure of Kconfig format. Mainline: Open-Source Signed-off-by: Yang Jianren Signed-off-by: Wang Yinfeng Change-Id: I8152f1e1b5f74a541c31221c39006d58364dbdf8 --- drivers/staging/phytium-npu/Kconfig | 3 ++- drivers/staging/phytium-npu/phytium_npu_common.c | 7 +++---- drivers/staging/phytium-npu/phytium_npu_pci.c | 6 ++++-- drivers/staging/phytium-npu/phytium_npu_uapi.c | 2 +- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/staging/phytium-npu/Kconfig b/drivers/staging/phytium-npu/Kconfig index 6f15304154..36dc65dadd 100644 --- a/drivers/staging/phytium-npu/Kconfig +++ b/drivers/staging/phytium-npu/Kconfig @@ -17,7 +17,7 @@ choice You need to select a suitable NPU controller in the current board. This option allows you to decide which Phytium NPU will be built in system. - If in doubt, select 'N' + config NPU_PLATFORM tristate "driver runs on platform" help @@ -25,6 +25,7 @@ choice This support is for devices that have the Phytium NPU controller IP. To compile this driver as a module, choose M here: the module will be called phytium_npu_platform. + config NPU_PCI tristate "driver runs on PCI hardware" help diff --git a/drivers/staging/phytium-npu/phytium_npu_common.c b/drivers/staging/phytium-npu/phytium_npu_common.c index ec8e07dabc..d844b2dbf6 100644 --- a/drivers/staging/phytium-npu/phytium_npu_common.c +++ b/drivers/staging/phytium-npu/phytium_npu_common.c @@ -397,13 +397,12 @@ static int phytium_npu_response_stream(struct phytium_npu_session *sess, } else { size = MAX_NPU_USER_RSP_SIZE; } + nustream_rsp = kzalloc(alloc_size, GFP_KERNEL); + if (!nustream_rsp) + return -ENOMEM; if (nustream->estream.stype & NPU_COMPUTEFLAG_NOTIFY) { if (!nstream->rsp) { - nustream_rsp = kzalloc(alloc_size, GFP_KERNEL); - if (!nustream_rsp) - return -ENOMEM; - nstream->rsp = nustream_rsp; INIT_LIST_HEAD(&nustream_rsp->stream_rsp_list_entry); } diff --git a/drivers/staging/phytium-npu/phytium_npu_pci.c b/drivers/staging/phytium-npu/phytium_npu_pci.c index c1ffeb78fb..b454a9d65b 100644 --- a/drivers/staging/phytium-npu/phytium_npu_pci.c +++ b/drivers/staging/phytium-npu/phytium_npu_pci.c @@ -48,8 +48,10 @@ static int phytium_npu_pci_probe(struct pci_dev *pci_dev, { struct phytium_npu_dev *npu_dev; struct device *dev = &pci_dev->dev; - void __iomem *reg_addr; - int ret, irq, bar; + void __iomem *reg_addr = NULL; + int ret = 0; + int irq = 0; + int bar = 0; dev_info(dev, "probed a NPU device, pci_dev: %x:%x\n", pci_dev->vendor, pci_dev->device); diff --git a/drivers/staging/phytium-npu/phytium_npu_uapi.c b/drivers/staging/phytium-npu/phytium_npu_uapi.c index 0fc968a38d..3cc3bac1ed 100644 --- a/drivers/staging/phytium-npu/phytium_npu_uapi.c +++ b/drivers/staging/phytium-npu/phytium_npu_uapi.c @@ -326,7 +326,7 @@ static long phytium_npu_ioctl(struct file *file, unsigned int cmd, unsigned long { struct phytium_npu_session *sess = file->private_data; struct phytium_npu_dev *npu = sess->npu_dev; - int retval; + int retval = 0; if (!sess) return -EINVAL; -- Gitee From c69ae564ec0d4b477f10f89a447c0e2fb432ea43 Mon Sep 17 00:00:00 2001 From: Yang Jianren Date: Wed, 11 Jun 2025 18:01:43 +0800 Subject: [PATCH 058/155] staging: phytium-npu: refactor Kbuild of Phytium NPU and remove words Turn this staging driver to standard Linux kernel styles and remove unnecessary words. Mainline: Open-Source Signed-off-by: Yang Jianren Signed-off-by: Wang Yinfeng Change-Id: I98bfd7c50aef2d3fa3d6af1ee23237d86eba3f22 --- drivers/staging/phytium-npu/Kconfig | 58 +++++++++---------- drivers/staging/phytium-npu/Makefile | 29 ++++------ drivers/staging/phytium-npu/Makefile.testing | 37 ------------ .../phytium-npu/{include => }/phytium_npu.h | 0 .../staging/phytium-npu/phytium_npu_common.c | 6 +- .../staging/phytium-npu/phytium_npu_debug.c | 6 +- drivers/staging/phytium-npu/phytium_npu_dev.c | 7 +-- .../staging/phytium-npu/phytium_npu_dev_mmu.c | 6 +- .../{include => }/phytium_npu_mmu.h | 0 drivers/staging/phytium-npu/phytium_npu_pci.c | 2 +- ...leopard_reg.h => phytium_npu_pd2408_reg.h} | 6 +- .../phytium-npu/phytium_npu_platform.c | 2 +- ...tium_npu_reg.h => phytium_npu_px210_reg.h} | 6 +- .../staging/phytium-npu/phytium_npu_uapi.c | 4 +- .../{include => }/phytium_npu_uapi.h | 0 .../phytium-npu/phytium_npu_workqueue.c | 6 +- 16 files changed, 54 insertions(+), 121 deletions(-) delete mode 100644 drivers/staging/phytium-npu/Makefile.testing rename drivers/staging/phytium-npu/{include => }/phytium_npu.h (100%) rename drivers/staging/phytium-npu/{include => }/phytium_npu_mmu.h (100%) rename drivers/staging/phytium-npu/{include/phytium_npu_leopard_reg.h => phytium_npu_pd2408_reg.h} (98%) rename drivers/staging/phytium-npu/{include/phytium_npu_reg.h => phytium_npu_px210_reg.h} (98%) rename drivers/staging/phytium-npu/{include => }/phytium_npu_uapi.h (100%) diff --git a/drivers/staging/phytium-npu/Kconfig b/drivers/staging/phytium-npu/Kconfig index 36dc65dadd..8e03300195 100644 --- a/drivers/staging/phytium-npu/Kconfig +++ b/drivers/staging/phytium-npu/Kconfig @@ -1,38 +1,34 @@ # SPDX-License-Identifier: GPL-2.0 -menuconfig PHYTIUM_NPU - tristate "Phytium neural network processing unit" - depends on ARCH_PHYTIUM - help - Say Y here if your want support for Phytium NPU controller framework. - This is common support for devices that embed the Phytium NPU IP. +config PHYTIUM_NPU + tristate "Phytium neural network processing unit" + help + Say Y here if your want support for Phytium NPU controller framework. + This is common support for devices that embed the Phytium NPU IP. - To compile this driver as a module, choose M here: the module will be - called phytium_npu. + To compile this driver as a module, choose M here: the module will be + called phytium_npu. if PHYTIUM_NPU -choice - prompt "Select the Phytium NPU Hardware" - default NPU_PLATFORM - help - You need to select a suitable NPU controller in the current board. - This option allows you to decide which Phytium NPU will be built - in system. +config PHYTIUM_NPU_PLATFORM + tristate "Phytium NPU platform support" + depends on ARCH_PHYTIUM && (ACPI || OF) + depends on PHYTIUM_NPU + help + Say Y here if you want to support for IO Mapped Phytium NPU controller. + This support is for devices that have the Phytium NPU controller IP. - config NPU_PLATFORM - tristate "driver runs on platform" - help - Say Y here if you want to support for IO Mapped Phytium NPU controller. - This support is for devices that have the Phytium NPU controller IP. - To compile this driver as a module, choose M here: the module will be - called phytium_npu_platform. + To compile this driver as a module, choose M here: the module will be + called phytium_npu_platform. - config NPU_PCI - tristate "driver runs on PCI hardware" - help - Say Y here if you want to support for Phytium NPU controller connected - to the PCI bus. This support is for devices that have the Phytium NPU - controller IP embedded into a PCI device. - To compile this driver as a module, choose M here: the module will be - called phytium_npu_pci. -endchoice +config PHYTIUM_NPU_PCI + tristate "Phytium NPU PCI support" + depends on PCI + depends on PHYTIUM_NPU + help + Say Y here if you want to support for Phytium NPU controller connected + to the PCI bus. This support is for devices that have the Phytium NPU + controller IP embedded into a PCI device. + + To compile this driver as a module, choose M here: the module will be + called phytium_npu_pci. endif diff --git a/drivers/staging/phytium-npu/Makefile b/drivers/staging/phytium-npu/Makefile index ecbcb63975..ce7a5f0f03 100644 --- a/drivers/staging/phytium-npu/Makefile +++ b/drivers/staging/phytium-npu/Makefile @@ -1,21 +1,14 @@ # SPDX-License-Identifier: GPL-2.0 -ccflags-y += -I$(src)/include/ -ccflags-y += -I$(srctree)/drivers/staging/phytium-npu/include/ - -ifdef CONFIG_NPU_PLATFORM - ifeq ($(CONFIG_NPU_PLATFORM),m) - EXTRA_CFLAGS += -DPHYTIUM_NPU_PLATFORM - endif - - ifeq ($(CONFIG_NPU_PLATFORM),y) - EXTRA_CFLAGS += -DPHYTIUM_NPU_PLATFORM - endif -endif obj-$(CONFIG_PHYTIUM_NPU) += phytium_npu.o -phytium_npu-y := phytium_npu_common.o phytium_npu_dev.o \ -phytium_npu_dev_mmu.o phytium_npu_mm_mmu.o phytium_npu_workqueue.o \ -phytium_npu_session.o phytium_npu_uapi.o phytium_npu_debug.o - -obj-$(CONFIG_NPU_PLATFORM) += phytium_npu_platform.o -obj-$(CONFIG_NPU_PCI) += phytium_npu_pci.o +phytium_npu-y := phytium_npu_common.o \ + phytium_npu_dev.o \ + phytium_npu_dev_mmu.o \ + phytium_npu_mm_mmu.o \ + phytium_npu_workqueue.o \ + phytium_npu_session.o \ + phytium_npu_uapi.o \ + phytium_npu_debug.o + +obj-$(CONFIG_PHYTIUM_NPU_PLATFORM) += phytium_npu_platform.o +obj-$(CONFIG_PHYTIUM_NPU_PCI) += phytium_npu_pci.o diff --git a/drivers/staging/phytium-npu/Makefile.testing b/drivers/staging/phytium-npu/Makefile.testing deleted file mode 100644 index da579693a6..0000000000 --- a/drivers/staging/phytium-npu/Makefile.testing +++ /dev/null @@ -1,37 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -export CONFIG_PHYTIUM_NPU := y -export CONFIG_NPU_PLATFORM := y -export CONFIG_PHYTIUM_NPU_DMA_HEAP := y -include Makefile -ARCH := arm64 -CROSS_COMPILE := aarch64-linux-gnu- - -#------------------------------------ -# for internal use -#------------------------------------ - -ifeq ($(KERNELRELEASE),) - -#KDIR ?= /lib/modules/$(shell uname -r)/build -KSRC := /home/chengquan/code/phytium-linux-kernel-master/ -PWD := $(shell pwd) - -# kernel warning levels: as high as possible: -# W=12 and W=123 seem to warn about linux kernel headers, so use W=1. -KWARN := W=1 - -ifneq (,$(shell which sparse)) -# C=1: use 'sparse' for extra warnings, if it is avail. -SPARSE := C=1 -endif - -all: modules -modules: - $(MAKE) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE)-C $(KSRC) M=$(shell pwd) modules - -clean: - $(MAKE) -C $(KDIR) M=$(PWD) clean -check: - cd $(KDIR); scripts/checkpatch.pl -f `find $(PWD)/include -name "*\.[ch]"` - -endif # KERNELRELEASE diff --git a/drivers/staging/phytium-npu/include/phytium_npu.h b/drivers/staging/phytium-npu/phytium_npu.h similarity index 100% rename from drivers/staging/phytium-npu/include/phytium_npu.h rename to drivers/staging/phytium-npu/phytium_npu.h diff --git a/drivers/staging/phytium-npu/phytium_npu_common.c b/drivers/staging/phytium-npu/phytium_npu_common.c index d844b2dbf6..193c420ab2 100644 --- a/drivers/staging/phytium-npu/phytium_npu_common.c +++ b/drivers/staging/phytium-npu/phytium_npu_common.c @@ -18,11 +18,7 @@ #include #include #include -#ifdef PHYTIUM_NPU_PLATFORM -#include "phytium_npu_leopard_reg.h" -#else -#include "phytium_npu_reg.h" -#endif +#include "phytium_npu_pd2408_reg.h" struct phytium_npu_dev *gnpu_dev; #define AP_CPPC2_STAT 0x0 diff --git a/drivers/staging/phytium-npu/phytium_npu_debug.c b/drivers/staging/phytium-npu/phytium_npu_debug.c index 3c21aec679..0f2d424864 100644 --- a/drivers/staging/phytium-npu/phytium_npu_debug.c +++ b/drivers/staging/phytium-npu/phytium_npu_debug.c @@ -9,11 +9,7 @@ #include "phytium_npu.h" #include "phytium_npu_mmu.h" #include "linux/phytium_npu_dma_buf_heap.h" -#ifdef PHYTIUM_NPU_PLATFORM -#include "phytium_npu_leopard_reg.h" -#else -#include "phytium_npu_reg.h" -#endif +#include "phytium_npu_pd2408_reg.h" #define DEBUG_BAND_COUNT_RESET 0x3fffffff #define DEBUG_BAND_EN 0x1 diff --git a/drivers/staging/phytium-npu/phytium_npu_dev.c b/drivers/staging/phytium-npu/phytium_npu_dev.c index 3c13262db1..04ae5fa37b 100644 --- a/drivers/staging/phytium-npu/phytium_npu_dev.c +++ b/drivers/staging/phytium-npu/phytium_npu_dev.c @@ -7,11 +7,8 @@ #include #include "phytium_npu_mmu.h" #include "phytium_npu.h" -#ifdef PHYTIUM_NPU_PLATFORM -#include "phytium_npu_leopard_reg.h" -#else -#include "phytium_npu_reg.h" -#endif +#include "phytium_npu_pd2408_reg.h" + #define POLL_PERIOD 100 #define POLL_TIMEOUT 100000 diff --git a/drivers/staging/phytium-npu/phytium_npu_dev_mmu.c b/drivers/staging/phytium-npu/phytium_npu_dev_mmu.c index 39f544750f..542b9753de 100644 --- a/drivers/staging/phytium-npu/phytium_npu_dev_mmu.c +++ b/drivers/staging/phytium-npu/phytium_npu_dev_mmu.c @@ -6,11 +6,7 @@ #include "phytium_npu_mmu.h" #include "phytium_npu.h" #include -#ifdef PHYTIUM_NPU_PLATFORM -#include "phytium_npu_leopard_reg.h" -#else -#include "phytium_npu_reg.h" -#endif +#include "phytium_npu_pd2408_reg.h" int pg_size[6] = {4096, 16384, 65536, 262144, 1048576, 2097152}; diff --git a/drivers/staging/phytium-npu/include/phytium_npu_mmu.h b/drivers/staging/phytium-npu/phytium_npu_mmu.h similarity index 100% rename from drivers/staging/phytium-npu/include/phytium_npu_mmu.h rename to drivers/staging/phytium-npu/phytium_npu_mmu.h diff --git a/drivers/staging/phytium-npu/phytium_npu_pci.c b/drivers/staging/phytium-npu/phytium_npu_pci.c index b454a9d65b..6e4796786c 100644 --- a/drivers/staging/phytium-npu/phytium_npu_pci.c +++ b/drivers/staging/phytium-npu/phytium_npu_pci.c @@ -11,7 +11,7 @@ #include #include #include "phytium_npu.h" -#include "phytium_npu_reg.h" +#include "phytium_npu_px210_reg.h" #define PHYTIUM_PCI_VENDOR_ID 0x1DB7 #define PHYTIUM_PCI_DEVICE_ID 0xDC24 diff --git a/drivers/staging/phytium-npu/include/phytium_npu_leopard_reg.h b/drivers/staging/phytium-npu/phytium_npu_pd2408_reg.h similarity index 98% rename from drivers/staging/phytium-npu/include/phytium_npu_leopard_reg.h rename to drivers/staging/phytium-npu/phytium_npu_pd2408_reg.h index fd3f041580..0f3b24889a 100644 --- a/drivers/staging/phytium-npu/include/phytium_npu_leopard_reg.h +++ b/drivers/staging/phytium-npu/phytium_npu_pd2408_reg.h @@ -2,8 +2,8 @@ /* * Copyright (C) 2023 Phytium Technology Co., Ltd. */ -#ifndef __PHYTIUM_NPU_LEOPARD_NEW_REG_H__ -#define __PHYTIUM_NPU_LEOPARD_NEW_REG_H__ +#ifndef __PHYTIUM_NPU_PD2408_REG_H__ +#define __PHYTIUM_NPU_PD2408_REG_H__ #define NPU_SYS_CLK_STATUS (0x0888U) #define NPU_SYS_MWDT (0x08C8U) @@ -237,4 +237,4 @@ #define NPU_PRE_WR_256 0x00200000 #define NPU_PRELOAD_CFG (NPU_PRE_CBUF | NPU_PRE_RD_256 | NPU_PRE_WR_256) -#endif /* __PHYTIUM_NPU_LEOPARD_REG_H__ */ +#endif /* __PHYTIUM_NPU_PD2408_REG_H__ */ diff --git a/drivers/staging/phytium-npu/phytium_npu_platform.c b/drivers/staging/phytium-npu/phytium_npu_platform.c index fbb4a8b858..408bb040e8 100644 --- a/drivers/staging/phytium-npu/phytium_npu_platform.c +++ b/drivers/staging/phytium-npu/phytium_npu_platform.c @@ -15,7 +15,7 @@ #include #include #include "phytium_npu.h" -#include "phytium_npu_leopard_reg.h" +#include "phytium_npu_pd2408_reg.h" static irqreturn_t phytium_npu_thread_irq(int irq, void *dev_id) { diff --git a/drivers/staging/phytium-npu/include/phytium_npu_reg.h b/drivers/staging/phytium-npu/phytium_npu_px210_reg.h similarity index 98% rename from drivers/staging/phytium-npu/include/phytium_npu_reg.h rename to drivers/staging/phytium-npu/phytium_npu_px210_reg.h index 3663c68ae5..f527379fe2 100644 --- a/drivers/staging/phytium-npu/include/phytium_npu_reg.h +++ b/drivers/staging/phytium-npu/phytium_npu_px210_reg.h @@ -2,8 +2,8 @@ /* * Copyright (C) 2023 Phytium Technology Co., Ltd. */ -#ifndef __PHYTIUM_NPU_X100_REG_H__ -#define __PHYTIUM_NPU_X100_REG_H__ +#ifndef __PHYTIUM_NPU_PX210_REG_H__ +#define __PHYTIUM_NPU_PX210_REG_H__ #define NPU_SYS_CLK_STATUS (0x0008U) #define NPU_SYS_MWDT (0x0048U) @@ -238,4 +238,4 @@ #define NPU_PRE_WR_256 0x00200000 #define NPU_PRELOAD_CFG (NPU_PRE_CBUF | NPU_PRE_RD_256 | NPU_PRE_WR_256) -#endif /* __PHYTIUM_NPU_LEOPARD_REG_H__ */ +#endif /* __PHYTIUM_NPU_PX210_REG_H__ */ diff --git a/drivers/staging/phytium-npu/phytium_npu_uapi.c b/drivers/staging/phytium-npu/phytium_npu_uapi.c index 3cc3bac1ed..4edd295439 100644 --- a/drivers/staging/phytium-npu/phytium_npu_uapi.c +++ b/drivers/staging/phytium-npu/phytium_npu_uapi.c @@ -12,8 +12,8 @@ #include #include #include -#include "include/phytium_npu.h" -#include "include/phytium_npu_uapi.h" +#include "phytium_npu.h" +#include "phytium_npu_uapi.h" static int phytium_npu_open(struct inode *inode, struct file *file) { diff --git a/drivers/staging/phytium-npu/include/phytium_npu_uapi.h b/drivers/staging/phytium-npu/phytium_npu_uapi.h similarity index 100% rename from drivers/staging/phytium-npu/include/phytium_npu_uapi.h rename to drivers/staging/phytium-npu/phytium_npu_uapi.h diff --git a/drivers/staging/phytium-npu/phytium_npu_workqueue.c b/drivers/staging/phytium-npu/phytium_npu_workqueue.c index 1d7301949b..ba9e069e97 100644 --- a/drivers/staging/phytium-npu/phytium_npu_workqueue.c +++ b/drivers/staging/phytium-npu/phytium_npu_workqueue.c @@ -9,11 +9,7 @@ #include #include "phytium_npu.h" #include "phytium_npu_uapi.h" -#ifdef PHYTIUM_NPU_PLATFORM -#include "phytium_npu_leopard_reg.h" -#else -#include "phytium_npu_reg.h" -#endif +#include "phytium_npu_pd2408_reg.h" static void wake(struct phytium_npu_dev *npu) { -- Gitee From 914f58fb2c93c12317f90364b6992e27ca784940 Mon Sep 17 00:00:00 2001 From: Wu Jinyong Date: Thu, 17 Jul 2025 18:25:35 +0800 Subject: [PATCH 059/155] i2c-2.0: phytium: Fixed the bug of delayed response to interrupts Before the modification,when the AP core was responding to other interrupt handlers,it could not respond in time to the I2C interrupt cast by the RV core,and at this time,if the RV core finished processing all the packets and judged that it was not the last packet of data,it would cast an error and end the transmission. After the modification,the RV core no longer considers this condition as an error,but switches to other transactions for processing,and when the AP core's interrupt program gets a response,it triggers the RV core to start the I2C transaction transmission again. Mainline: Open-Source Signed-off-by: Wu Jinyong Signed-off-by: Wang Yinfeng Change-Id: I4eb257387317325f4176c7c1c6e8e84b320cd70b --- .../busses/phytium_i2c_v2/i2c-phyt-common.c | 15 ++++++++--- .../i2c/busses/phytium_i2c_v2/i2c-phyt-core.h | 12 ++++++--- .../busses/phytium_i2c_v2/i2c-phyt-master.c | 26 ++++++++++++++----- .../busses/phytium_i2c_v2/i2c-phyt-platform.c | 1 + 4 files changed, 41 insertions(+), 13 deletions(-) diff --git a/drivers/i2c/busses/phytium_i2c_v2/i2c-phyt-common.c b/drivers/i2c/busses/phytium_i2c_v2/i2c-phyt-common.c index 1d00ba706f..1eb8bedd15 100644 --- a/drivers/i2c/busses/phytium_i2c_v2/i2c-phyt-common.c +++ b/drivers/i2c/busses/phytium_i2c_v2/i2c-phyt-common.c @@ -20,7 +20,7 @@ #include "i2c-phyt-core.h" #define FT_LOG_LINE_MAX_LEN 400 -#define FT_LOG_MAX_SIZE 8192 +#define FT_LOG_MAX_SIZE 32768 static void i2c_phyt_send_msg(struct i2c_phyt_dev *dev, struct phyt_msg_info *set_msg, bool complete_flag); @@ -32,6 +32,11 @@ static char *i2c_ft_abort_sources[] = { [FT_I2C_INT_ERR] = "Interrupt error", [FT_I2C_BLOCK_SIZE] = "smbus block error", [FT_I2C_INVALID_ADDR] = "slave address invalid", + [FT_I2C_TRANS_PACKET_FAIL] = "Packet transfer fail", + [FT_I2C_PACKET_NOT_START] = "Packet not start", + [FT_I2C_PARA_ERR] = "Para error", + [FT_I2C_INTR_XFER_INIT] = "Intr mode xfer init", + [FT_I2C_TRANS_WAIT] = "Trans wait", [FT_I2C_CHECK_STATUS_ERR] = "Uncomplete status", }; @@ -183,7 +188,7 @@ int i2c_phyt_malloc_log_mem(struct i2c_phyt_dev *dev) reg = i2c_phyt_read_reg(dev, FT_I2C_REGFILE_DEBUG); phy_addr = ((reg & FT_I2C_LOG_ADDR_MASK) >> FT_I2C_LOG_ADDR_LOW_SHIFT) << FT_I2C_LOG_ADDR_SHIFT; - dev->log_size = ((reg & FT_I2C_LOG_SIZE_MASK) >> FT_I2C_LOG_SIZE_LOW_SHIFT) * 1024; + dev->log_size = ((reg & FT_I2C_LOG_SIZE_MASK) >> FT_I2C_LOG_SIZE_LOW_SHIFT) * 4096; dev->log_addr = devm_ioremap(dev->dev, phy_addr, dev->log_size); @@ -293,6 +298,7 @@ void i2c_phyt_default_cfg(struct i2c_phyt_dev *dev, struct phyt_msg_info i2c_mng_msg; memset(&i2c_mng_msg, 0, sizeof(i2c_mng_msg)); + memset(dev->rx_shmem_addr, 0xFF, sizeof(struct phyt_msg_info)); i2c_phyt_common_set_cmd(dev, &i2c_mng_msg, PHYTI2C_MSG_CMD_DEFAULT, PHYTI2C_MSG_CMD_DEFAULT_RESUME); @@ -370,9 +376,12 @@ int i2c_phyt_check_status(struct i2c_phyt_dev *dev, if (msg->head.status0 != FT_I2C_MSG_COMPLETE_UNKNOW) { if (!dev->mng.is_need_check || ((msg->head.status0 == FT_I2C_MSG_COMPLETE_OK) && - (msg->head.status1 == FT_I2C_SUCCESS))) { + ((msg->head.status1 == FT_I2C_SUCCESS) || + (msg->head.status1 == FT_I2C_TRANS_WAIT)))) { dev->abort_source = 0; result = FT_I2C_SUCCESS; + if (msg->head.status1 == FT_I2C_TRANS_WAIT) + dev->flags = FT_I2C_TRANS_WAIT; } else { i2c_phyt_show_log(dev); dev->abort_source = 1 << msg->head.status1; diff --git a/drivers/i2c/busses/phytium_i2c_v2/i2c-phyt-core.h b/drivers/i2c/busses/phytium_i2c_v2/i2c-phyt-core.h index 8c44e50586..7197992b58 100644 --- a/drivers/i2c/busses/phytium_i2c_v2/i2c-phyt-core.h +++ b/drivers/i2c/busses/phytium_i2c_v2/i2c-phyt-core.h @@ -14,7 +14,7 @@ #include #include -#define I2C_PHYTIUM_V2_DRV_VERSION "1.0.2" +#define I2C_PHYTIUM_V2_DRV_VERSION "1.0.3" #define FT_I2C_MSG_UNIT_SIZE 10 #define FT_I2C_DATA_RESV_LEN 2 @@ -38,9 +38,9 @@ #define FT_I2C_REGFILE_HEARTBIT_VAL BIT(2) #define FT_I2C_LOG_SIZE_LOW_SHIFT 4 #define FT_I2C_LOG_SIZE_MASK GENMASK(7, FT_I2C_LOG_SIZE_LOW_SHIFT) -#define FT_I2C_LOG_ADDR_SHIFT 10 +#define FT_I2C_LOG_ADDR_SHIFT 12 #define FT_I2C_LOG_ADDR_LOW_SHIFT 8 -#define FT_I2C_LOG_ADDR_MASK GENMASK(29, FT_I2C_LOG_ADDR_LOW_SHIFT) +#define FT_I2C_LOG_ADDR_MASK GENMASK(27, FT_I2C_LOG_ADDR_LOW_SHIFT) #define FT_I2C_LOG_ADDR_LOCK_VAL BIT(31) #define FT_I2C_LOG_ADDR_LOG_FLAG BIT(3) #define FT_I2C_LOG_ADDR_LOG_ALIVE BIT(1) @@ -267,6 +267,10 @@ enum phyti2c_status_code { FT_I2C_BLOCK_SIZE, FT_I2C_INVALID_ADDR, FT_I2C_TRANS_PACKET_FAIL, + FT_I2C_PACKET_NOT_START, + FT_I2C_PARA_ERR, + FT_I2C_INTR_XFER_INIT, + FT_I2C_TRANS_WAIT, /*The RV result must put above*/ FT_I2C_RUNNING, FT_I2C_CHECK_STATUS_ERR @@ -389,6 +393,7 @@ struct i2c_phyt_dev { u32 master_cfg; u32 slave_cfg; u32 functionality; + spinlock_t i2c_lock; u8 real_index[FT_I2C_SINGLE_FRAME_CNT]; struct i2c_timings timings; @@ -509,4 +514,5 @@ void i2c_phyt_notify_rv(struct i2c_phyt_dev *dev, bool need_check); int i2c_phyt_check_status(struct i2c_phyt_dev *dev, struct phyt_msg_info *msg); void i2c_phyt_set_int_interrupt(struct i2c_phyt_dev *dev, u32 is_enable, u32 intr_mask); +void i2c_phyt_trig_rv_intr(struct i2c_phyt_dev *dev); #endif diff --git a/drivers/i2c/busses/phytium_i2c_v2/i2c-phyt-master.c b/drivers/i2c/busses/phytium_i2c_v2/i2c-phyt-master.c index 8b205ae745..a4bf85dfcf 100644 --- a/drivers/i2c/busses/phytium_i2c_v2/i2c-phyt-master.c +++ b/drivers/i2c/busses/phytium_i2c_v2/i2c-phyt-master.c @@ -345,9 +345,11 @@ static int i2c_phyt_master_xfer(struct i2c_adapter *adapter, { struct i2c_phyt_dev *dev = i2c_get_adapdata(adapter); int ret; + unsigned long flags; pm_runtime_get_sync(dev->dev); + spin_lock_irqsave(&dev->i2c_lock, flags); dev->msgs = msgs; dev->msgs_num = num; dev->msg_err = 0; @@ -356,12 +358,13 @@ static int i2c_phyt_master_xfer(struct i2c_adapter *adapter, dev->mng.tx_cmd_cnt = 0; dev->mng.cur_cmd_cnt = 0; dev->mng.is_last_frame = false; + dev->flags = ~FT_I2C_TRANS_WAIT; i2c_phyt_write_reg(dev, FT_I2C_REGFILE_TX_HEAD, 0); i2c_phyt_write_reg(dev, FT_I2C_REGFILE_TX_TAIL, 0); i2c_phyt_master_xfer_single_frame(dev); - + spin_unlock_irqrestore(&dev->i2c_lock, flags); ret = i2c_phyt_check_result(dev); if (!ret) { ret = num; @@ -369,7 +372,8 @@ static int i2c_phyt_master_xfer(struct i2c_adapter *adapter, if (dev->abort_source != FT_I2C_SUCCESS) { i2c_phyt_handle_tx_abort(dev); if ((dev->abort_source & BIT(FT_I2C_TIMEOUT)) || - (dev->abort_source & BIT(FT_I2C_TRANS_PACKET_FAIL))) { + (dev->abort_source & BIT(FT_I2C_TRANS_PACKET_FAIL)) || + (dev->abort_source & BIT(FT_I2C_INTR_XFER_INIT))) { i2c_phyt_set_module_en( dev, FT_I2C_ADAPTER_MODULE_RESET); i2c_phyt_check_result(dev); @@ -447,10 +451,12 @@ static irqreturn_t i2c_phyt_master_regfile_isr(int this_irq, void *dev_id) u32 stat, head, tail; int ret; + spin_lock(&dev->i2c_lock); stat = i2c_phyt_read_reg(dev, FT_I2C_REGFILE_RV2AP_INTR_STAT); if (!(stat & FT_I2C_RV2AP_INTR_BIT4)) { dev_warn(dev->dev, "unexpect i2c_phyt regfile intr, stat:%#x\n", stat); + spin_unlock(&dev->i2c_lock); return IRQ_NONE; } @@ -458,6 +464,7 @@ static irqreturn_t i2c_phyt_master_regfile_isr(int this_irq, void *dev_id) if (!dev->mng.tx_ring_cnt) { dev_err(dev->dev, "tx_ring_cnt is zero\n"); + spin_unlock(&dev->i2c_lock); return IRQ_NONE; } head = i2c_phyt_read_reg(dev, FT_I2C_REGFILE_TX_HEAD) % dev->mng.tx_ring_cnt; @@ -465,10 +472,10 @@ static irqreturn_t i2c_phyt_master_regfile_isr(int this_irq, void *dev_id) do { tail++; tail %= dev->mng.tx_ring_cnt; - if (dev->complete_flag) { - if (rx_msg->head.cmd_type == PHYTI2C_MSG_CMD_REPORT) - goto done; + if (rx_msg->head.cmd_type == PHYTI2C_MSG_CMD_REPORT) + i2c_phyt_master_isr_handle(dev); + if (dev->complete_flag) { ret = i2c_phyt_master_handle(dev); if (ret == FT_I2C_RUNNING) continue; @@ -478,12 +485,17 @@ static irqreturn_t i2c_phyt_master_regfile_isr(int this_irq, void *dev_id) i2c_phyt_write_reg(dev, FT_I2C_REGFILE_TX_HEAD, 0); i2c_phyt_write_reg(dev, FT_I2C_REGFILE_TX_TAIL, 0); complete(&dev->cmd_complete); + spin_unlock(&dev->i2c_lock); return IRQ_HANDLED; } } while (tail != head); -done: - i2c_phyt_master_isr_handle(dev); + if (dev->flags == FT_I2C_TRANS_WAIT) { + dev->flags = ~FT_I2C_TRANS_WAIT; + i2c_phyt_trig_rv_intr(dev); + } + + spin_unlock(&dev->i2c_lock); return IRQ_HANDLED; } diff --git a/drivers/i2c/busses/phytium_i2c_v2/i2c-phyt-platform.c b/drivers/i2c/busses/phytium_i2c_v2/i2c-phyt-platform.c index 45ad303f28..4ff35cbf69 100644 --- a/drivers/i2c/busses/phytium_i2c_v2/i2c-phyt-platform.c +++ b/drivers/i2c/busses/phytium_i2c_v2/i2c-phyt-platform.c @@ -305,6 +305,7 @@ static int i2c_phyt_plat_probe(struct platform_device *pdev) dev->mng.tx_ring_cnt * sizeof(struct phyt_msg_info); dev->dev = &pdev->dev; + spin_lock_init(&dev->i2c_lock); platform_set_drvdata(pdev, dev); ret = i2c_phyt_malloc_log_mem(dev); -- Gitee From 2db189969bf06d6445f8b906e90cffd5e30fb11c Mon Sep 17 00:00:00 2001 From: liutianyu1250 Date: Fri, 1 Aug 2025 11:36:09 +0800 Subject: [PATCH 060/155] rt: arm64: phytium_defconfig: update for better realtime Change list: 1.enable NO_HZ_FULL mode. 2.disable SCHED_SMT 3.disable IRQ_TIME_ACCOUNTING Signed-off-by: liutianyu1250 --- arch/arm64/configs/phytium_defconfig | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/arch/arm64/configs/phytium_defconfig b/arch/arm64/configs/phytium_defconfig index 234dfbbf32..58bd118b25 100644 --- a/arch/arm64/configs/phytium_defconfig +++ b/arch/arm64/configs/phytium_defconfig @@ -3,12 +3,11 @@ CONFIG_LOCALVERSION="-phytium-embedded-v3.2" CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y CONFIG_AUDIT=y -CONFIG_NO_HZ_IDLE=y +CONFIG_NO_HZ_FULL=y CONFIG_HIGH_RES_TIMERS=y CONFIG_BPF_SYSCALL=y CONFIG_BPF_JIT=y CONFIG_PREEMPT_RT=y -CONFIG_IRQ_TIME_ACCOUNTING=y CONFIG_BSD_PROCESS_ACCT=y CONFIG_BSD_PROCESS_ACCT_V3=y CONFIG_TASKSTATS=y @@ -39,7 +38,6 @@ CONFIG_CRASH_DUMP=y CONFIG_ARCH_PHYTIUM=y CONFIG_ARM64_VA_BITS_48=y CONFIG_SCHED_MC=y -CONFIG_SCHED_SMT=y CONFIG_NUMA=y CONFIG_XEN=y CONFIG_COMPAT=y @@ -54,6 +52,7 @@ CONFIG_RANDOMIZE_BASE=y CONFIG_HIBERNATION=y CONFIG_WQ_POWER_EFFICIENT_DEFAULT=y CONFIG_ENERGY_MODEL=y +CONFIG_CPU_IDLE_GOV_MENU=y CONFIG_ARM_PSCI_CPUIDLE=y CONFIG_CPU_FREQ=y CONFIG_CPU_FREQ_STAT=y -- Gitee From 5bb74397e708b6ea8898e8e3e8a8114ff399809d Mon Sep 17 00:00:00 2001 From: Feng Jun Date: Thu, 17 Jul 2025 14:25:37 +0800 Subject: [PATCH 061/155] arm64: phytium: Add support of reading cpu type for Phytium Socs This patch provides three methods for reading cpu type for Phytium Socs, with priority from high to low as follows: - read socid by arm-smccc - read system register of SYS_AIDR_EL1 - read system register of MPIDR_EL1 Mainline: NA Signed-off-by: Feng Jun Signed-off-by: Wang Yinfeng Change-Id: If6509ce0c20e7682f1107c04b0e20a2ebf6fb065 --- MAINTAINERS | 2 + arch/arm64/include/asm/phytium_cputype.h | 198 +++++++++++++++++++++++ 2 files changed, 200 insertions(+) create mode 100644 arch/arm64/include/asm/phytium_cputype.h diff --git a/MAINTAINERS b/MAINTAINERS index bce049f85f..265e08b32d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -17475,6 +17475,8 @@ F: Documentation/devicetree/bindings/usb/phytium.role-sw.yaml F: Documentation/devicetree/bindings/w1/phytium,w1.yaml F: Documentation/devicetree/bindings/staging/phytium-npu.yaml F: arch/arm64/boot/dts/phytium/* +F: arch/arm64/include/asm/phytium_cputype.h +F: arch/arm64/include/asm/phyt.h F: arch/arm64/include/asm/ras.h F: arch/arm64/kernel/ras.c F: drivers/bus/phytium_pio.c diff --git a/arch/arm64/include/asm/phytium_cputype.h b/arch/arm64/include/asm/phytium_cputype.h new file mode 100644 index 0000000000..eb5c1735b9 --- /dev/null +++ b/arch/arm64/include/asm/phytium_cputype.h @@ -0,0 +1,198 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2025 Phytium Technology Co., Ltd. + */ +#ifndef __ASM_PHYTIUM_CPUTYPE_H +#define __ASM_PHYTIUM_CPUTYPE_H + +#include +#include + +#define SOC_ID_PE1702 0x1 +#define SOC_ID_PS17064 0x2 +#define SOC_ID_PD1904 0x3 +#define SOC_ID_PS20064 0x4 + +#define SOC_ID_PD2008 0x5 +#define SOC_ID_PS21064 0x6 +#define SOC_ID_PE220X 0x7 +#define SOC_ID_PS23064 0x8 +#define SOC_ID_PD2308 0x9 +#define SOC_ID_PS2480 0xa +#define SOC_ID_PD2408 0xb + +#define SYS_REG_VAL_PS24080 0x6 +#define SYS_REG_VAL_PS23064 0x8 + +#define SMCCC_SUCCESS 0 +#define SMCCC_FAILURE (-1) +#define FUNC_ID_GET_CPU_VERSION 0xc2000002 + +enum phyt_cpu_type { + PE1702 = 1, + PS17064, + PD1904, + PS20064, + PD2008, + PS21064, + PE220X, + PS23064, + PD2308, + PS24080, + PD2408, + PS15016, + UNKNOWN_SOC +}; + +static enum phyt_cpu_type do_smccc_res(struct arm_smccc_res res) +{ + unsigned long smc_cpu_ver = res.a1; + + smc_cpu_ver = (smc_cpu_ver >> 8); + switch (smc_cpu_ver) { + case SOC_ID_PE1702: + return PE1702; + case SOC_ID_PS17064: + return PS17064; + case SOC_ID_PD1904: + return PD1904; + case SOC_ID_PS20064: + return PS20064; + case SOC_ID_PD2008: + return PD2008; + case SOC_ID_PS21064: + return PS21064; + case SOC_ID_PE220X: + return PE220X; + case SOC_ID_PS23064: + return PS23064; + case SOC_ID_PD2308: + return PD2308; + case SOC_ID_PS2480: + return PS24080; + case SOC_ID_PD2408: + return PD2408; + default: + return UNKNOWN_SOC; + } +} + +static enum phyt_cpu_type do_read_sysreg(void) +{ + u32 aidr_reg_val = read_sysreg(aidr_el1); + + switch (aidr_reg_val) { + case SYS_REG_VAL_PS24080: + return PS24080; + case SYS_REG_VAL_PS23064: + return PS23064; + default: + return UNKNOWN_SOC; + } +} + +static enum phyt_cpu_type do_read_mpidr(void) +{ + u32 part_id = read_cpuid_part_number(); + + switch (part_id) { + case PHYTIUM_CPU_PART_FTC303: + return PE220X; + case PHYTIUM_CPU_PART_FTC660: + return PS15016; + case PHYTIUM_CPU_PART_FTC661: + return PE1702; + case PHYTIUM_CPU_PART_FTC662: + return PS17064; + case PHYTIUM_CPU_PART_FTC663: + return PD1904; + case PHYTIUM_CPU_PART_FTC862: + return PD2408; + default: + return UNKNOWN_SOC; + } +} + +static inline bool is_phytium_soc(void) +{ + if (read_cpuid_implementor() == ARM_CPU_IMP_PHYTIUM) + return true; + return false; +} + +static inline enum phyt_cpu_type phyt_read_cpu_type(void) +{ + enum phyt_cpu_type ctype; + struct arm_smccc_res res; + + if (!is_phytium_soc()) + return UNKNOWN_SOC; + + arm_smccc_smc(FUNC_ID_GET_CPU_VERSION, 0, 0, 0, 0, 0, 0, 0, &res); + switch (res.a0) { + case SMCCC_SUCCESS: + ctype = do_smccc_res(res); + if (ctype != UNKNOWN_SOC) + break; + fallthrough; + case SMCCC_FAILURE: + ctype = do_read_sysreg(); + if (ctype != UNKNOWN_SOC) + break; + fallthrough; + default: + ctype = do_read_mpidr(); + break; + } + return ctype; +} + +static inline bool is_pd2408(void) +{ + enum phyt_cpu_type ctype = phyt_read_cpu_type(); + + if (ctype == PD2408) + return true; + return false; +} + +static inline bool is_ps23064(void) +{ + enum phyt_cpu_type ctype = phyt_read_cpu_type(); + + if (ctype == PS23064) + return true; + return false; +} + +static inline bool is_ps24080(void) +{ + enum phyt_cpu_type ctype = phyt_read_cpu_type(); + + if (ctype == PS24080) + return true; + return false; +} + +static inline bool is_pd2308(void) +{ + enum phyt_cpu_type ctype = phyt_read_cpu_type(); + + if (ctype == PD2308) + return true; + return false; +} + +static inline bool is_pe220x(void) +{ + enum phyt_cpu_type ctype = phyt_read_cpu_type(); + + if (ctype == PE220X) + return true; + + return false; +} + +#endif + + -- Gitee From 8ec72265fbb3cc4002decf63bfd0da099c936959 Mon Sep 17 00:00:00 2001 From: Feng Jun Date: Fri, 18 Jul 2025 21:20:27 +0800 Subject: [PATCH 062/155] arm64: phytium: Update the method to obtain CPU type for Phytium SoCs This patch adjusts the machanism of obtaining the CPU type for Phytium Socs. It can directly return current CPU type when external interface calls the function. Mainline: Open-Source Signed-off-by: Feng Jun Signed-off-by: Wang Yinfeng Change-Id: I0ca3a046b20cfae39da82abdc87823254df95227 --- arch/arm64/include/asm/phytium_cputype.h | 77 ++++++++++++++++++------ arch/arm64/kernel/setup.c | 9 +++ 2 files changed, 69 insertions(+), 17 deletions(-) diff --git a/arch/arm64/include/asm/phytium_cputype.h b/arch/arm64/include/asm/phytium_cputype.h index eb5c1735b9..5873ecff16 100644 --- a/arch/arm64/include/asm/phytium_cputype.h +++ b/arch/arm64/include/asm/phytium_cputype.h @@ -28,7 +28,7 @@ #define SMCCC_FAILURE (-1) #define FUNC_ID_GET_CPU_VERSION 0xc2000002 -enum phyt_cpu_type { +enum phyt_soc_type { PE1702 = 1, PS17064, PD1904, @@ -44,7 +44,9 @@ enum phyt_cpu_type { UNKNOWN_SOC }; -static enum phyt_cpu_type do_smccc_res(struct arm_smccc_res res) +extern enum phyt_soc_type phyt_soc_type_t; + +static enum phyt_soc_type do_smccc_res(struct arm_smccc_res res) { unsigned long smc_cpu_ver = res.a1; @@ -77,7 +79,7 @@ static enum phyt_cpu_type do_smccc_res(struct arm_smccc_res res) } } -static enum phyt_cpu_type do_read_sysreg(void) +static enum phyt_soc_type do_read_sysreg(void) { u32 aidr_reg_val = read_sysreg(aidr_el1); @@ -91,7 +93,7 @@ static enum phyt_cpu_type do_read_sysreg(void) } } -static enum phyt_cpu_type do_read_mpidr(void) +static enum phyt_soc_type do_read_mpidr(void) { u32 part_id = read_cpuid_part_number(); @@ -120,9 +122,9 @@ static inline bool is_phytium_soc(void) return false; } -static inline enum phyt_cpu_type phyt_read_cpu_type(void) +static inline enum phyt_soc_type phyt_read_soc_type(void) { - enum phyt_cpu_type ctype; + enum phyt_soc_type ctype; struct arm_smccc_res res; if (!is_phytium_soc()) @@ -147,49 +149,90 @@ static inline enum phyt_cpu_type phyt_read_cpu_type(void) return ctype; } +static inline void phyt_soc_type_init(void) +{ + enum phyt_soc_type ctype = phyt_read_soc_type(); + + switch (ctype) { + case PE1702: + phyt_soc_type_t = PE1702; + break; + case PS17064: + phyt_soc_type_t = PS17064; + break; + case PD1904: + phyt_soc_type_t = PD1904; + break; + case PS20064: + phyt_soc_type_t = PS20064; + break; + case PD2008: + phyt_soc_type_t = PD2008; + break; + case PS21064: + phyt_soc_type_t = PS21064; + break; + case PE220X: + phyt_soc_type_t = PE220X; + break; + case PS23064: + phyt_soc_type_t = PS23064; + break; + case PD2308: + phyt_soc_type_t = PD2308; + break; + case PS24080: + phyt_soc_type_t = PS24080; + break; + case PD2408: + phyt_soc_type_t = PD2408; + break; + case PS15016: + phyt_soc_type_t = PS15016; + break; + default: + phyt_soc_type_t = UNKNOWN_SOC; + break; + } +} + static inline bool is_pd2408(void) { - enum phyt_cpu_type ctype = phyt_read_cpu_type(); - if (ctype == PD2408) + if (phyt_soc_type_t == PD2408) return true; return false; } static inline bool is_ps23064(void) { - enum phyt_cpu_type ctype = phyt_read_cpu_type(); - if (ctype == PS23064) + if (phyt_soc_type_t == PS23064) return true; return false; } static inline bool is_ps24080(void) { - enum phyt_cpu_type ctype = phyt_read_cpu_type(); - if (ctype == PS24080) + if (phyt_soc_type_t == PS24080) return true; return false; } static inline bool is_pd2308(void) { - enum phyt_cpu_type ctype = phyt_read_cpu_type(); - if (ctype == PD2308) + if (phyt_soc_type_t == PD2308) return true; return false; } static inline bool is_pe220x(void) { - enum phyt_cpu_type ctype = phyt_read_cpu_type(); - if (ctype == PE220X) + if (phyt_soc_type_t == PE220X) return true; - return false; } diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index 80ba335158..eca4c04010 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -54,6 +54,12 @@ #include #include +#ifdef CONFIG_ARCH_PHYTIUM +#include +enum phyt_soc_type phyt_soc_type_t; +EXPORT_SYMBOL(phyt_soc_type_t); +#endif + static int num_standard_resources; static struct resource *standard_resources; @@ -342,6 +348,9 @@ void __init __no_sanitize_address setup_arch(char **cmdline_p) FW_BUG "Booted with MMU enabled!"); } +#ifdef CONFIG_ARCH_PHYTIUM + phyt_soc_type_init(); +#endif arm64_memblock_init(); paging_init(); -- Gitee From a39e4ad6cc1eb2933f9abe87aaf39d39f1f6991b Mon Sep 17 00:00:00 2001 From: Chen Zhenhua Date: Tue, 17 Jun 2025 14:50:55 +0800 Subject: [PATCH 063/155] usb: xhci: Add the method to reactivate the USB controller Sometimes, when the USB controller experiences a timeout for the stop EP endpoint command for a timeout for processing commands, xhci driver will shutdown the USB controller. If you want to reactivate the USB controller, you need to follow the reactivation operation process. note: This patch is only applicable to the Phytium platform. Mainline: Open-Source Signed-off-by: Chen Zhenhua Signed-off-by: Wang Yinfeng Change-Id: I686017f657de7e75b3c9c8c8cb83cb45d62a12c9 --- drivers/usb/host/xhci-plat.c | 57 +++++++++++++++++++++++++++++++++++- drivers/usb/host/xhci-ring.c | 7 +++++ drivers/usb/host/xhci.h | 7 +++++ 3 files changed, 70 insertions(+), 1 deletion(-) diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index e4bdfdeb0d..47af8dceaa 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -21,10 +21,38 @@ #include #include +#ifdef CONFIG_ARCH_PHYTIUM +#include +#endif + #include "xhci.h" #include "xhci-plat.h" #include "xhci-mvebu.h" +#ifdef CONFIG_ARCH_PHYTIUM +static struct workqueue_struct *xhci_wq; +static struct workqueue_struct *get_xhci_wq(void) +{ + return xhci_wq; +} + +static int xhci_generic_plat_probe(struct platform_device *pdev); + +static void xhci_delay_work_func(struct work_struct *work) +{ + struct xhci_hcd *xhci; + struct usb_hcd *hcd; + struct platform_device *pdev; + + xhci = container_of(to_delayed_work(work), struct xhci_hcd, xhci_delay_wq); + hcd = xhci_to_hcd(xhci); + pdev = to_platform_device(hcd->self.controller); + + xhci_plat_remove(pdev); + xhci_generic_plat_probe(pdev); +} +#endif + static struct hc_driver __read_mostly xhci_plat_hc_driver; static int xhci_plat_setup(struct usb_hcd *hcd); @@ -185,8 +213,17 @@ int xhci_plat_probe(struct platform_device *pdev, struct device *sysdev, const s ret = -ENOMEM; goto disable_runtime; } - +#ifdef CONFIG_ARCH_PHYTIUM + if (is_pe220x() || is_pd2408()) { + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + hcd->regs = devm_ioremap(&pdev->dev, res->start, resource_size(res)); + } else { + hcd->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res); + } +#else hcd->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res); +#endif + if (IS_ERR(hcd->regs)) { ret = PTR_ERR(hcd->regs); goto put_hcd; @@ -334,6 +371,13 @@ int xhci_plat_probe(struct platform_device *pdev, struct device *sysdev, const s device_enable_async_suspend(&pdev->dev); pm_runtime_put_noidle(&pdev->dev); +#ifdef CONFIG_ARCH_PHYTIUM + if (is_pe220x() || is_pd2408()) { + INIT_DELAYED_WORK(&xhci->xhci_delay_wq, xhci_delay_work_func); + xhci->get_xhci_wq = get_xhci_wq; + } +#endif + /* * Prevent runtime pm from being on as default, users should enable * runtime pm using power/control in sysfs. @@ -586,6 +630,13 @@ MODULE_ALIAS("platform:xhci-hcd"); static int __init xhci_plat_init(void) { +#ifdef CONFIG_ARCH_PHYTIUM + if (is_pe220x() || is_pd2408()) { + xhci_wq = create_workqueue("xhci_wq"); + if (!xhci_wq) + return -ENOMEM; + } +#endif xhci_init_driver(&xhci_plat_hc_driver, &xhci_plat_overrides); return platform_driver_register(&usb_generic_xhci_driver); } @@ -593,6 +644,10 @@ module_init(xhci_plat_init); static void __exit xhci_plat_exit(void) { +#ifdef CONFIG_ARCH_PHYTIUM + if (is_pe220x() || is_pd2408()) + destroy_workqueue(xhci_wq); +#endif platform_driver_unregister(&usb_generic_xhci_driver); } module_exit(xhci_plat_exit); diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 4587b652ce..7c0e617205 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1298,6 +1298,13 @@ void xhci_hc_died(struct xhci_hcd *xhci) /* inform usb core hc died if PCI remove isn't already handling it */ if (!(xhci->xhc_state & XHCI_STATE_REMOVING)) usb_hc_died(xhci_to_hcd(xhci)); + +#ifdef CONFIG_ARCH_PHYTIUM + if (is_pe220x() || is_pd2408()) { + if (xhci->get_xhci_wq && (xhci->quirks & XHCI_S1_SUSPEND_WAKEUP)) + mod_delayed_work(xhci->get_xhci_wq(), &xhci->xhci_delay_wq, 1000); + } +#endif } static void update_ring_for_set_deq_completion(struct xhci_hcd *xhci, diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 3376f1f38d..c0e4dc7c17 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -18,6 +18,9 @@ #include #include #include +#ifdef CONFIG_ARCH_PHYTIUM +#include +#endif /* Code sharing between pci-quirks and xhci hcd */ #include "xhci-ext-caps.h" @@ -1562,6 +1565,10 @@ struct xhci_hcd { struct list_head cmd_list; unsigned int cmd_ring_reserved_trbs; struct delayed_work cmd_timer; +#ifdef CONFIG_ARCH_PHYTIUM + struct delayed_work xhci_delay_wq; + struct workqueue_struct* (*get_xhci_wq)(void); +#endif struct completion cmd_ring_stop_completion; struct xhci_command *current_cmd; -- Gitee From fc38c345dd09bec8628c897823a62428200bfea5 Mon Sep 17 00:00:00 2001 From: Li Wencheng Date: Fri, 18 Jul 2025 15:57:40 +0800 Subject: [PATCH 064/155] net/phytmac: Fix compile error on X86 architecture Add dependency on ARCH_PHYTIUM to slove the compilation problem of hybrid architecture, such as X86 and RISCV. Mainline: Open-Source Signed-off-by: Li Wencheng Signed-off-by: Wang Yinfeng Change-Id: Ie2d1bafaa559ece975d0a892cc758ff210776efd --- drivers/net/ethernet/phytium/Kconfig | 1 + drivers/net/ethernet/phytium/phytmac.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/phytium/Kconfig b/drivers/net/ethernet/phytium/Kconfig index 14a77adbfd..e68ca5d821 100644 --- a/drivers/net/ethernet/phytium/Kconfig +++ b/drivers/net/ethernet/phytium/Kconfig @@ -5,6 +5,7 @@ config NET_VENDOR_PHYTIUM bool "Phytium devices" + depends on ARCH_PHYTIUM depends on HAS_IOMEM default y help diff --git a/drivers/net/ethernet/phytium/phytmac.h b/drivers/net/ethernet/phytium/phytmac.h index ee22cda030..7d1ecbacf9 100644 --- a/drivers/net/ethernet/phytium/phytmac.h +++ b/drivers/net/ethernet/phytium/phytmac.h @@ -17,7 +17,7 @@ #define PHYTMAC_PCI_DRV_NAME "phytmac_pci" #define PHYTMAC_PLAT_DRV_NAME "phytmac_platform" #define PHYTMAC_DRV_DESC "PHYTIUM Ethernet Driver" -#define PHYTMAC_DRIVER_VERSION "1.0.47" +#define PHYTMAC_DRIVER_VERSION "1.0.48" #define PHYTMAC_DEFAULT_MSG_ENABLE \ (NETIF_MSG_DRV | \ NETIF_MSG_PROBE | \ -- Gitee From 71bc411dd6878806fe5590276b04ea8f9c9741ae Mon Sep 17 00:00:00 2001 From: Li Wencheng Date: Fri, 18 Jul 2025 16:07:06 +0800 Subject: [PATCH 065/155] net/phytmac: Fix page refcounting issue for XDP_REDIRECT The current page counting scheme assumes that the reference count cannot decrease until the received frame is sent to the upper layers of the networking stack. This assumption does not hold for the XDP_REDIRECT action, particularly with BPF_MAP_TYPE_XSKMAP handling, since a page that pointed out by xdp_buff can have its reference count decreased via the xdp_do_redirect call. To work around that, now start off by a large page count and then don't allow a refcount less than two. Mainline: Open-Source Signed-off-by: Li Wencheng Signed-off-by: Wang Yinfeng Change-Id: Ieea455dabd7c5f4827b560bf82bd81ba6bd18784 --- drivers/net/ethernet/phytium/phytmac.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/phytium/phytmac.h b/drivers/net/ethernet/phytium/phytmac.h index 7d1ecbacf9..f483524b39 100644 --- a/drivers/net/ethernet/phytium/phytmac.h +++ b/drivers/net/ethernet/phytium/phytmac.h @@ -17,7 +17,7 @@ #define PHYTMAC_PCI_DRV_NAME "phytmac_pci" #define PHYTMAC_PLAT_DRV_NAME "phytmac_platform" #define PHYTMAC_DRV_DESC "PHYTIUM Ethernet Driver" -#define PHYTMAC_DRIVER_VERSION "1.0.48" +#define PHYTMAC_DRIVER_VERSION "1.0.49" #define PHYTMAC_DEFAULT_MSG_ENABLE \ (NETIF_MSG_DRV | \ NETIF_MSG_PROBE | \ -- Gitee From 39f4e319cea6eb80aab0e997335db58d2f21d381 Mon Sep 17 00:00:00 2001 From: Li Wencheng Date: Fri, 18 Jul 2025 16:14:52 +0800 Subject: [PATCH 066/155] net/phytmac: Bugfix the potential deadlock issue If the SOFTIRQ-unsafe lock is called inside the SOFTIRQ-safe lock, it will cause high potential deadlock risk. In dependency chain &(&mc->mca_lock)->rlock --> &dev->addr_list_lock_key --> &(&pdata->msg_ring.msg_lock)->rlock, msg_ring.msg_lock use spin_lock, which is SOFTIRQ-unsafe. it should be modified to use spin_lock_irqsave. Mainline: Open-Source Signed-off-by: Li Wencheng Signed-off-by: Wang Yinfeng Change-Id: I08e5787cd8537414ef132004d21d6a4504738304 --- drivers/net/ethernet/phytium/phytmac.h | 2 +- drivers/net/ethernet/phytium/phytmac_v2.c | 22 ++++++++++++---------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/phytium/phytmac.h b/drivers/net/ethernet/phytium/phytmac.h index f483524b39..c3feca3d96 100644 --- a/drivers/net/ethernet/phytium/phytmac.h +++ b/drivers/net/ethernet/phytium/phytmac.h @@ -17,7 +17,7 @@ #define PHYTMAC_PCI_DRV_NAME "phytmac_pci" #define PHYTMAC_PLAT_DRV_NAME "phytmac_platform" #define PHYTMAC_DRV_DESC "PHYTIUM Ethernet Driver" -#define PHYTMAC_DRIVER_VERSION "1.0.49" +#define PHYTMAC_DRIVER_VERSION "1.0.50" #define PHYTMAC_DEFAULT_MSG_ENABLE \ (NETIF_MSG_DRV | \ NETIF_MSG_PROBE | \ diff --git a/drivers/net/ethernet/phytium/phytmac_v2.c b/drivers/net/ethernet/phytium/phytmac_v2.c index 1afff67d62..4dd3ddd18e 100644 --- a/drivers/net/ethernet/phytium/phytmac_v2.c +++ b/drivers/net/ethernet/phytium/phytmac_v2.c @@ -25,10 +25,11 @@ static int phytmac_v2_msg_send(struct phytmac *pdata, u16 cmd_id, u32 tx_head, tx_tail, ring_size; struct phytmac_msg_info msg; struct phytmac_msg_info msg_rx; + unsigned long flags; u32 retry = 0; int ret = 0; - spin_lock(&pdata->msg_ring.msg_lock); + spin_lock_irqsave(&pdata->msg_ring.msg_lock, flags); tx_head = PHYTMAC_READ(pdata, PHYTMAC_TX_MSG_HEAD) & 0xff; tx_tail = phytmac_v2_tx_ring_wrap(pdata, pdata->msg_ring.tx_msg_wr_tail); pdata->msg_ring.tx_msg_rd_tail = tx_tail; @@ -42,8 +43,8 @@ static int phytmac_v2_msg_send(struct phytmac *pdata, u16 cmd_id, netdev_err(pdata->ndev, "Time out waiting for Tx msg ring free, tx_tail:0x%x, tx_head:0x%x", tx_tail, tx_head); - spin_unlock(&pdata->msg_ring.msg_lock); - return -EINVAL; + ret = -EINVAL; + goto err_out; } } @@ -58,8 +59,8 @@ static int phytmac_v2_msg_send(struct phytmac *pdata, u16 cmd_id, } else if (len > PHYTMAC_MSG_PARA_LEN) { netdev_err(pdata->ndev, "Tx msg para len %d is greater than the max len %d", len, PHYTMAC_MSG_PARA_LEN); - spin_unlock(&pdata->msg_ring.msg_lock); - return -EINVAL; + ret = -EINVAL; + goto err_out; } if (netif_msg_hw(pdata)) { @@ -80,8 +81,8 @@ static int phytmac_v2_msg_send(struct phytmac *pdata, u16 cmd_id, retry++; if (retry >= PHYTMAC_RETRY_TIMES) { netdev_err(pdata->ndev, "Msg process time out!"); - spin_unlock(&pdata->msg_ring.msg_lock); - return -EINVAL; + ret = -EINVAL; + goto err_out; } } @@ -90,12 +91,13 @@ static int phytmac_v2_msg_send(struct phytmac *pdata, u16 cmd_id, if (!(msg_rx.status0 & PHYTMAC_CMD_PRC_SUCCESS)) { netdev_err(pdata->ndev, "Msg process error, cmdid:%d, subid:%d, status0:%d, tail:%d", msg.cmd_type, msg.cmd_subid, msg.status0, tx_tail); - spin_unlock(&pdata->msg_ring.msg_lock); - return -EINVAL; + ret = -EINVAL; + goto err_out; } } - spin_unlock(&pdata->msg_ring.msg_lock); +err_out: + spin_unlock_irqrestore(&pdata->msg_ring.msg_lock, flags); return ret; } -- Gitee From edceee7231280a09fb9b1ec8d4b1d5130bc19fc5 Mon Sep 17 00:00:00 2001 From: Wang Xu Date: Thu, 24 Jul 2025 20:17:05 +0800 Subject: [PATCH 067/155] PM: power: Add a standby system state on Phytium platforms This patch adds a "standby" system state on phytium SoCs, This state has a power consumption level between S2idle and S3, but it provides better system responsiveness. Mainline: NA Signed-off-by: Wang Xu Signed-off-by: Wang Yinfeng Change-Id: Ifddd4c1428509c9dfbd89a5e474572e3d8eab2a3 --- drivers/firmware/psci/psci.c | 36 +++++++++++++++++++++++++++++++++++- include/linux/suspend.h | 3 +++ kernel/power/suspend.c | 16 ++++++++++++++++ 3 files changed, 54 insertions(+), 1 deletion(-) diff --git a/drivers/firmware/psci/psci.c b/drivers/firmware/psci/psci.c index 2328ca58bb..eb5fde61d0 100644 --- a/drivers/firmware/psci/psci.c +++ b/drivers/firmware/psci/psci.c @@ -28,7 +28,9 @@ #include #include #include - +#ifdef CONFIG_ARCH_PHYTIUM +#include +#endif /* * While a 64-bit OS can make calls with SMC32 calling conventions, for some * calls it is necessary to use SMC64 to pass or return 64-bit values. @@ -495,6 +497,31 @@ int psci_cpu_suspend_enter(u32 state) } #endif +#ifdef CONFIG_ARCH_PHYTIUM +static int phytium_psci_system_suspend(unsigned long state) +{ + phys_addr_t pa_cpu_resume = __pa_symbol(cpu_resume); + + if (state == PM_SUSPEND_STANDBY) + return invoke_psci_fn(PSCI_FN_NATIVE(1_0, SYSTEM_SUSPEND), + pa_cpu_resume, 0x544600c2, 0); + else + return invoke_psci_fn(PSCI_FN_NATIVE(1_0, SYSTEM_SUSPEND), + pa_cpu_resume, 0, 0); +} + +static int phytium_psci_system_suspend_enter(suspend_state_t state) +{ + return cpu_suspend(state, phytium_psci_system_suspend); +} + + +static const struct platform_suspend_ops phytium_psci_suspend_ops = { + .valid = phytium_suspend_valid_mem, + .enter = phytium_psci_system_suspend_enter, +}; +#endif + static int psci_system_suspend(unsigned long unused) { int err; @@ -535,7 +562,14 @@ static void __init psci_init_system_suspend(void) ret = psci_features(PSCI_FN_NATIVE(1_0, SYSTEM_SUSPEND)); if (ret != PSCI_RET_NOT_SUPPORTED) +#ifdef CONFIG_ARCH_PHYTIUM + if (is_pd2408()) + suspend_set_ops(&phytium_psci_suspend_ops); + else + suspend_set_ops(&psci_suspend_ops); +#else suspend_set_ops(&psci_suspend_ops); +#endif } static void __init psci_init_cpu_suspend(void) diff --git a/include/linux/suspend.h b/include/linux/suspend.h index ef50308894..6b51f5665d 100644 --- a/include/linux/suspend.h +++ b/include/linux/suspend.h @@ -212,6 +212,9 @@ extern suspend_state_t mem_sleep_default; */ extern void suspend_set_ops(const struct platform_suspend_ops *ops); extern int suspend_valid_only_mem(suspend_state_t state); +#ifdef CONFIG_ARCH_PHYTIUM +extern int phytium_suspend_valid_mem(suspend_state_t state); +#endif extern unsigned int pm_suspend_global_flags; diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index 3aae526cc4..7e855ad243 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c @@ -248,6 +248,22 @@ int suspend_valid_only_mem(suspend_state_t state) } EXPORT_SYMBOL_GPL(suspend_valid_only_mem); +#ifdef CONFIG_ARCH_PHYTIUM +int phytium_suspend_valid_mem(suspend_state_t state) +{ + switch (state) { + case PM_SUSPEND_MEM: + return state == PM_SUSPEND_MEM; + case PM_SUSPEND_STANDBY: + return state == PM_SUSPEND_STANDBY; + default: + pr_err("no valid state support\n"); + return 0; + } +} +EXPORT_SYMBOL_GPL(phytium_suspend_valid_mem); +#endif + static bool sleep_state_supported(suspend_state_t state) { return state == PM_SUSPEND_TO_IDLE || -- Gitee From 0a14ba45f2a25cad681ab10156b7c3b0293aff0a Mon Sep 17 00:00:00 2001 From: Huang Shaobo Date: Thu, 24 Jul 2025 16:32:53 +0800 Subject: [PATCH 068/155] mm/sysinfo: show present pages instead of managed pages on PD2408 SoC On Phytium PD2408 platform, a large portion of memory (2G) is reserved via firmware, causing /proc/meminfo and tools like 'free -h' to show significantly less available memory than actually physically present. This patch modifies si_meminfo() and si_meminfo_node() to use node_present_pages() instead of zone_managed_pages() when config CONFIG_ARCH_PHYTIUM is enabled and the SoC is PD2408. This ensures that reserved memory is still counted in the totalram statistics, providing a more accurate representation of the system's physical memory layout as seen by the firmware and early boot code. Mainline: NA Signed-off-by: Huang Shaobo Signed-off-by: Wang Yinfeng Change-Id: I4f368c30820a5448f3c3ac3788450a998faee7e4 --- mm/show_mem.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/mm/show_mem.c b/mm/show_mem.c index b896e54e3a..ab4f147bc0 100644 --- a/mm/show_mem.c +++ b/mm/show_mem.c @@ -14,6 +14,9 @@ #include #include #include +#ifdef CONFIG_ARCH_PHYTIUM +#include +#endif #include "internal.h" #include "swap.h" @@ -78,6 +81,17 @@ EXPORT_SYMBOL_GPL(si_mem_available); void si_meminfo(struct sysinfo *val) { val->totalram = totalram_pages(); +#ifdef CONFIG_ARCH_PHYTIUM + if (is_pd2408()) { + int nid; + unsigned long total_pages = 0; + + for_each_node_state(nid, N_MEMORY) { + total_pages += node_present_pages(nid); + } + val->totalram = total_pages; + } +#endif val->sharedram = global_node_page_state(NR_SHMEM); val->freeram = global_zone_page_state(NR_FREE_PAGES); val->bufferram = nr_blockdev_pages(); @@ -100,6 +114,10 @@ void si_meminfo_node(struct sysinfo *val, int nid) for (zone_type = 0; zone_type < MAX_NR_ZONES; zone_type++) managed_pages += zone_managed_pages(&pgdat->node_zones[zone_type]); val->totalram = managed_pages; +#ifdef CONFIG_ARCH_PHYTIUM + if (is_pd2408()) + val->totalram = node_present_pages(nid); +#endif val->sharedram = node_page_state(pgdat, NR_SHMEM); val->freeram = sum_zone_node_page_state(nid, NR_FREE_PAGES); #ifdef CONFIG_HIGHMEM -- Gitee From 2a83f8002a4c06fd016eedbbfee8cd708156c98c Mon Sep 17 00:00:00 2001 From: Li Hao Date: Fri, 18 Jul 2025 16:32:00 +0800 Subject: [PATCH 069/155] Revert "virt: phytium: add ARM64 support for CPU hotplug" This reverts commit f654646ead8be8b566e6efeae62ba735dc19e546. Reason for revert: This patch only supports vCPU hot-plug, not hot-unplug. Revert this patch first, and then add the subsequent vCPU hot-plug and hot-unplug patches. Mainline: NA Signed-off-by: Li Hao Signed-off-by: Wang Yinfeng Change-Id: I779e58d496f6351a68c3393e34f0a831d3ed99ac --- arch/arm64/kernel/acpi.c | 33 --------------------------------- arch/arm64/kernel/setup.c | 23 +---------------------- arch/arm64/kernel/smp.c | 16 ++++++---------- 3 files changed, 7 insertions(+), 65 deletions(-) diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c index 31deddea5c..dba8fcec7f 100644 --- a/arch/arm64/kernel/acpi.c +++ b/arch/arm64/kernel/acpi.c @@ -29,7 +29,6 @@ #include #include -#include #include #include #include @@ -518,35 +517,3 @@ int acpi_ffh_address_space_arch_handler(acpi_integer *value, void *region_contex return ret; } #endif /* CONFIG_ACPI_FFH */ - -int acpi_map_cpu(acpi_handle handle, phys_cpuid_t physid, u32 acpi_id, - int *pcpu) -{ - int cpu, nid; - - cpu = acpi_map_cpuid(physid, acpi_id); - if (cpu < 0) { - pr_info("Unable to map GICC to logical cpu number\n"); - return cpu; - } - nid = acpi_get_node(handle); - if (nid != NUMA_NO_NODE) { - set_cpu_numa_node(cpu, nid); - numa_add_cpu(cpu); - } - - *pcpu = cpu; - set_cpu_present(cpu, true); - - return 0; -} -EXPORT_SYMBOL(acpi_map_cpu); - -int acpi_unmap_cpu(int cpu) -{ - set_cpu_present(cpu, false); - numa_clear_node(cpu); - - return 0; -} -EXPORT_SYMBOL(acpi_unmap_cpu); diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index eca4c04010..8fa046ac17 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -412,7 +412,7 @@ static int __init topology_init(void) { int i; - for_each_present_cpu(i) { + for_each_possible_cpu(i) { struct cpu *cpu = &per_cpu(cpu_data.cpu, i); cpu->hotpluggable = cpu_can_disable(i); register_cpu(cpu, i); @@ -463,24 +463,3 @@ static int __init check_mmu_enabled_at_boot(void) return 0; } device_initcall_sync(check_mmu_enabled_at_boot); - -#ifdef CONFIG_HOTPLUG_CPU - -int arch_register_cpu(int num) -{ - struct cpu *cpu = &per_cpu(cpu_data.cpu, num); - - cpu->hotpluggable = 1; - return register_cpu(cpu, num); -} -EXPORT_SYMBOL(arch_register_cpu); - -void arch_unregister_cpu(int num) -{ - struct cpu *cpu = &per_cpu(cpu_data.cpu, num); - - unregister_cpu(cpu); -} -EXPORT_SYMBOL(arch_unregister_cpu); - -#endif diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c index 82c9c82ee0..14365ef842 100644 --- a/arch/arm64/kernel/smp.c +++ b/arch/arm64/kernel/smp.c @@ -522,14 +522,16 @@ acpi_map_gic_cpu_interface(struct acpi_madt_generic_interrupt *processor) { u64 hwid = processor->arm_mpidr; + if (!(processor->flags & ACPI_MADT_ENABLED)) { + pr_debug("skipping disabled CPU entry with 0x%llx MPIDR\n", hwid); + return; + } + if (hwid & ~MPIDR_HWID_BITMASK || hwid == INVALID_HWID) { pr_err("skipping CPU entry with invalid MPIDR 0x%llx\n", hwid); return; } - if (!(processor->flags & ACPI_MADT_ENABLED)) - pr_debug("disabled CPU entry with 0x%llx MPIDR\n", hwid); - if (is_mpidr_duplicate(cpu_count, hwid)) { pr_err("duplicate CPU MPIDR 0x%llx in MADT\n", hwid); return; @@ -752,13 +754,7 @@ void __init smp_prepare_cpus(unsigned int max_cpus) if (err) continue; - if (acpi_disabled) { - set_cpu_present(cpu, true); - } else { - if ((cpu_madt_gicc[cpu].flags & ACPI_MADT_ENABLED)) - set_cpu_present(cpu, true); - } - + set_cpu_present(cpu, true); numa_store_cpu_info(cpu); } } -- Gitee From a399c1e6565e44cc1f59a828deb12154a0182423 Mon Sep 17 00:00:00 2001 From: Peng Mengguang Date: Tue, 22 Jul 2025 16:44:35 +0800 Subject: [PATCH 070/155] arm64/KVM: Cancel writeable_mask judgment in arm64_check_features When userspace try to modify sys_reg value, this will fail due to writeable_mask limitations. It's time to make ID registers configurable. When userspace want to set the values of ID registers, save the value in kvm_arch_vcpu so that guest can read the modified value. Mainline: NA Signed-off-by: Peng Mengguang Backported-by: Wu Chen Change-Id: Ied0c36976153ce547278c8b462434f04ec62be6e --- arch/arm64/kvm/sys_regs.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 370a1a7bd3..543fa3c630 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -1253,7 +1253,6 @@ static int arm64_check_features(struct kvm_vcpu *vcpu, const struct arm64_ftr_reg *ftr_reg; const struct arm64_ftr_bits *ftrp = NULL; u32 id = reg_to_encoding(rd); - u64 writable_mask = rd->val; u64 limit = rd->reset(vcpu, rd); u64 mask = 0; @@ -1273,15 +1272,11 @@ static int arm64_check_features(struct kvm_vcpu *vcpu, for (; ftrp && ftrp->width; ftrp++) { s64 f_val, f_lim, safe_val; - u64 ftr_mask; - ftr_mask = arm64_ftr_mask(ftrp); - if ((ftr_mask & writable_mask) != ftr_mask) - continue; + mask |= arm64_ftr_mask(ftrp); f_val = arm64_ftr_value(ftrp, val); f_lim = arm64_ftr_value(ftrp, limit); - mask |= ftr_mask; if (f_val == f_lim) safe_val = f_val; -- Gitee From 2d8a0022cc2dcfd6f061eea7d89db741f6ac728c Mon Sep 17 00:00:00 2001 From: Zheng Zengkai Date: Tue, 22 Jul 2025 17:56:22 +0800 Subject: [PATCH 071/155] arm64: Add config switch and kernel parameter for CPU0 hotplug New config switch CONFIG_ARM64_BOOTPARAM_HOTPLUG_CPU0 sets whether default state of arm64_cpu0_hotpluggable is on or off. If the config switch if off, arm64_cpu0_hotpluggable is off by default. But arm64_cpu0_hotpluggable can still be turned on by kernel parameter arm64_cpu0_hotplug at boot. If the config switch is on, arm64_cpu0_hotpluggable is always on. whether CPU0 is hotpluggable depends on cpu_can_disable(0) and arm64_cpu0_hotpluggable. The default value of the config switch is off. Mainline: NA (cherry picked form openEuler/OLK-6.6 commit 2f465989e7cca014100f7a58b7af588245dddd20) Signed-off-by: Zheng Zengkai Backported-by: Wu Chen Change-Id: Ie762e6e9e95257fd058f1a53f5a1e95790f86319 --- .../admin-guide/kernel-parameters.txt | 8 ++++++ arch/arm64/Kconfig | 28 +++++++++++++++++++ arch/arm64/kernel/setup.c | 21 ++++++++++++-- 3 files changed, 55 insertions(+), 2 deletions(-) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index d83a3f47e2..4d31800dce 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -3989,6 +3989,14 @@ parameter, xsave area per process might occupy more memory on xsaves enabled systems. + arm64_cpu0_hotplug [ARM64] Turn on arm64_cpu0_hotpluggable when + CONFIG_ARM64_BOOTPARAM_HOTPLUG_CPU0 is off. + Some features depend on CPU0. Known dependency is: + MegaRAID Tri-Mode SAS3508 may block the reboot process + after offline CPU0. + If the dependencies are under your control, you can + turn on arm64_cpu0_hotplug. + nps_mtm_hs_ctr= [KNL,ARC] This parameter sets the maximum duration, in cycles, each HW thread of the CTOP can run diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index da9b13c30f..c944fe2c91 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -1475,6 +1475,34 @@ config HOTPLUG_CPU Say Y here to experiment with turning CPUs off and on. CPUs can be controlled through /sys/devices/system/cpu. +config ARM64_BOOTPARAM_HOTPLUG_CPU0 + bool "Set default setting of arm64_cpu0_hotpluggable" + default n + depends on HOTPLUG_CPU + help + Set whether default state of arm64_cpu0_hotpluggable is on or off. + + Say Y here to set arm64_cpu0_hotpluggable on by default. If this + switch is turned on, there is no need to give arm64_cpu0_hotplug + kernel parameter and arm64_cpu0_hotpluggable is on by default. + + Please note: there may be some CPU0 dependencies if you want + to enable the CPU0 hotplug feature either by this switch or by + arm64_cpu0_hotplug kernel parameter. + + For example: + We found the following issue related to CPU0 dependency: + 1. echo 0 > /sys/devices/system/cpu/cpu0/online + 2. reboot + MegaRAID Tri-Mode SAS3508 may block the reboot process. + + Please make sure the dependencies are under your control before + you enable this feature. + + Say N if you don't want to enable CPU0 hotplug feature by default. + You still can set arm64_cpu0_hotpluggable on at boot by kernel + parameter arm64_cpu0_hotplug. + config ARM64_ERR_RECOV bool "Support arm64 RAS error recovery" depends on ACPI_APEI_SEA && MEMORY_FAILURE diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index 8fa046ac17..04a07e7348 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -63,6 +63,19 @@ EXPORT_SYMBOL(phyt_soc_type_t); static int num_standard_resources; static struct resource *standard_resources; +#ifdef CONFIG_ARM64_BOOTPARAM_HOTPLUG_CPU0 +static int arm64_cpu0_hotpluggable = 1; +#else +static int arm64_cpu0_hotpluggable; +static int __init arm64_enable_cpu0_hotplug(char *str) +{ + arm64_cpu0_hotpluggable = 1; + return 1; +} + +__setup("arm64_cpu0_hotplug", arm64_enable_cpu0_hotplug); +#endif + phys_addr_t __fdt_pointer __initdata; u64 mmu_enabled_at_boot __initdata; @@ -402,8 +415,12 @@ static inline bool cpu_can_disable(unsigned int cpu) #ifdef CONFIG_HOTPLUG_CPU const struct cpu_operations *ops = get_cpu_ops(cpu); - if (ops && ops->cpu_can_disable) - return ops->cpu_can_disable(cpu); + if (ops && ops->cpu_can_disable) { + if (cpu == 0) + return ops->cpu_can_disable(0) && arm64_cpu0_hotpluggable; + else + return ops->cpu_can_disable(cpu); + } #endif return false; } -- Gitee From 30e9f8dd9b4e1557b1502807368d035f65a20123 Mon Sep 17 00:00:00 2001 From: James Morse Date: Tue, 22 Jul 2025 18:01:45 +0800 Subject: [PATCH 072/155] ACPI/scan: Use the acpi_device_is_present() helper in more places acpi_device_is_present() checks the present or functional bits from the cached copy of _STA. A few places open-code this check. Use the helper instead to improve readability. Mainline: NA (cherry picked form openEuler/OLK-6.6 commit af5d22753af958748f9074f43580c37d487517a0) Signed-off-by: James Morse Reviewed-by: Jonathan Cameron Reviewed-by: Gavin Shan Signed-off-by: Russell King (Oracle) Reviewed-by: Miguel Luis Signed-off-by: Rafael J. Wysocki Signed-off-by: Li Wei Backported-by: Wu Chen Signed-off-by: Wang Yinfeng Change-Id: I9753746262a0d09946ef013cecda529f47d74c2d --- drivers/acpi/scan.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index c0c5c5c58a..e492563ca0 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -304,7 +304,7 @@ static int acpi_scan_device_check(struct acpi_device *adev) int error; acpi_bus_get_status(adev); - if (adev->status.present || adev->status.functional) { + if (acpi_device_is_present(adev)) { /* * This function is only called for device objects for which * matching scan handlers exist. The only situation in which @@ -334,7 +334,7 @@ static int acpi_scan_bus_check(struct acpi_device *adev, void *not_used) int error; acpi_bus_get_status(adev); - if (!(adev->status.present || adev->status.functional)) { + if (!acpi_device_is_present(adev)) { acpi_scan_device_not_present(adev); return 0; } -- Gitee From 67f97396c67bed8df370092bad65086f2e71af36 Mon Sep 17 00:00:00 2001 From: James Morse Date: Tue, 22 Jul 2025 18:04:31 +0800 Subject: [PATCH 073/155] ACPI/scan: Rename acpi_scan_device_not_present() to be about enumeration acpi_scan_device_not_present() is called when a device in the hierarchy is not available for enumeration. Historically enumeration was only based on whether the device was present. To add support for only enumerating devices that are both present and enabled, this helper should be renamed. It was only ever about enumeration, rename it acpi_scan_device_not_enumerated(). No change in behaviour is intended. Mainline: NA (cherry picked form openEuler/OLK-6.6 commit 7841fd7ddf7dfe571a33eba631143f894c50045d) Signed-off-by: Reviewed-by: Gavin Shan Signed-off-by: Russell King (Oracle) Reviewed-by: Miguel Luis Signed-off-by: Rafael J. Wysocki Signed-off-by: Li Wei Backported-by: Wu Chen Signed-off-by: Wang Yinfeng Change-Id: I1615da23a6aafa905485f2986a488c67bd7c2df0 --- drivers/acpi/scan.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index e492563ca0..08a1df2a3e 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -289,10 +289,10 @@ static int acpi_scan_hot_remove(struct acpi_device *device) return 0; } -static int acpi_scan_device_not_present(struct acpi_device *adev) +static int acpi_scan_device_not_enumerated(struct acpi_device *adev) { if (!acpi_device_enumerated(adev)) { - dev_warn(&adev->dev, "Still not present\n"); + dev_warn(&adev->dev, "Still not enumerated\n"); return -EALREADY; } acpi_bus_trim(adev); @@ -323,7 +323,7 @@ static int acpi_scan_device_check(struct acpi_device *adev) return error; } } else { - error = acpi_scan_device_not_present(adev); + error = acpi_scan_device_not_enumerated(adev); } return error; } @@ -335,7 +335,7 @@ static int acpi_scan_bus_check(struct acpi_device *adev, void *not_used) acpi_bus_get_status(adev); if (!acpi_device_is_present(adev)) { - acpi_scan_device_not_present(adev); + acpi_scan_device_not_enumerated(adev); return 0; } if (handler && handler->hotplug.scan_dependent) -- Gitee From 98d599cc1ef1a7063a88381af7497b14f78dc10f Mon Sep 17 00:00:00 2001 From: James Morse Date: Tue, 22 Jul 2025 18:10:02 +0800 Subject: [PATCH 074/155] ACPI/arm64: Move MADT GICC enabled check ACPI, irqchip and the architecture code all inspect the MADT enabled bit for a GICC entry in the MADT. The addition of an 'online capable' bit means all these sites need updating. Move the current checks behind a helper to make future updates easier. Mainline: NA (cherry picked form openEuler/OLK-6.6 commit 853f84d34f8ff9bbe9b4be38492f1bd8a8a4e4b3) Signed-off-by: James Morse Reviewed-by: Jonathan Cameron Reviewed-by: Gavin Shan Signed-off-by: "Russell King (Oracle)" Acked-by: "Rafael J. Wysocki" Reviewed-by: Sudeep Holla Link: https://lore.kernel.org/r/E1quv5D-00AeNJ-U8@rmk-PC.armlinux.org.uk Signed-off-by: Catalin Marinas Signed-off-by: Li Wei Backported-by: Wu Chen Signed-off-by: Wang Yinfeng Change-Id: I11005eb09525046798a473c15a66114bdd75edf9 --- arch/arm64/kernel/smp.c | 2 +- drivers/acpi/processor_core.c | 2 +- drivers/irqchip/irq-gic-v3.c | 10 ++++------ include/linux/acpi.h | 5 +++++ 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c index 14365ef842..4a13c5376d 100644 --- a/arch/arm64/kernel/smp.c +++ b/arch/arm64/kernel/smp.c @@ -522,7 +522,7 @@ acpi_map_gic_cpu_interface(struct acpi_madt_generic_interrupt *processor) { u64 hwid = processor->arm_mpidr; - if (!(processor->flags & ACPI_MADT_ENABLED)) { + if (!acpi_gicc_is_usable(processor)) { pr_debug("skipping disabled CPU entry with 0x%llx MPIDR\n", hwid); return; } diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index 7dd6dbaa98..b203cfe285 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -90,7 +90,7 @@ static int map_gicc_mpidr(struct acpi_subtable_header *entry, struct acpi_madt_generic_interrupt *gicc = container_of(entry, struct acpi_madt_generic_interrupt, header); - if (!(gicc->flags & ACPI_MADT_ENABLED)) + if (!acpi_gicc_is_usable(gicc)) return -ENODEV; /* device_declaration means Device object in DSDT, in the diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index e7f000f90b..db6eae5676 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -2387,8 +2387,7 @@ gic_acpi_parse_madt_gicc(union acpi_subtable_headers *header, u32 size = reg == GIC_PIDR2_ARCH_GICv4 ? SZ_64K * 4 : SZ_64K * 2; void __iomem *redist_base; - /* GICC entry which has !ACPI_MADT_ENABLED is not unusable so skip */ - if (!(gicc->flags & ACPI_MADT_ENABLED)) + if (!acpi_gicc_is_usable(gicc)) return 0; redist_base = ioremap(gicc->gicr_base_address, size); @@ -2438,7 +2437,7 @@ static int __init gic_acpi_match_gicc(union acpi_subtable_headers *header, * If GICC is enabled and has valid gicr base address, then it means * GICR base is presented via GICC */ - if ((gicc->flags & ACPI_MADT_ENABLED) && gicc->gicr_base_address) { + if (acpi_gicc_is_usable(gicc) && gicc->gicr_base_address) { acpi_data.enabled_rdists++; return 0; } @@ -2447,7 +2446,7 @@ static int __init gic_acpi_match_gicc(union acpi_subtable_headers *header, * It's perfectly valid firmware can pass disabled GICC entry, driver * should not treat as errors, skip the entry instead of probe fail. */ - if (!(gicc->flags & ACPI_MADT_ENABLED)) + if (!acpi_gicc_is_usable(gicc)) return 0; return -ENODEV; @@ -2506,8 +2505,7 @@ static int __init gic_acpi_parse_virt_madt_gicc(union acpi_subtable_headers *hea int maint_irq_mode; static int first_madt = true; - /* Skip unusable CPUs */ - if (!(gicc->flags & ACPI_MADT_ENABLED)) + if (!acpi_gicc_is_usable(gicc)) return 0; maint_irq_mode = (gicc->flags & ACPI_MADT_VGIC_IRQ_MODE) ? diff --git a/include/linux/acpi.h b/include/linux/acpi.h index cb1a465f1c..3c16781249 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -256,6 +256,11 @@ acpi_table_parse_cedt(enum acpi_cedt_type id, int acpi_parse_mcfg (struct acpi_table_header *header); void acpi_table_print_madt_entry (struct acpi_subtable_header *madt); +static inline bool acpi_gicc_is_usable(struct acpi_madt_generic_interrupt *gicc) +{ + return gicc->flags & ACPI_MADT_ENABLED; +} + /* the following numa functions are architecture-dependent */ void acpi_numa_slit_init (struct acpi_table_slit *slit); -- Gitee From 3c9289cbf17f8cdbd38cbdfa3343871ddf71a29b Mon Sep 17 00:00:00 2001 From: James Morse Date: Tue, 22 Jul 2025 18:13:29 +0800 Subject: [PATCH 075/155] arch_topology: Make register_cpu_capacity_sysctl() tolerant to late CPUs register_cpu_capacity_sysctl() adds a property to sysfs that describes the CPUs capacity. This is done from a subsys_initcall() that assumes all possible CPUs are registered. With CPU hotplug, possible CPUs aren't registered until they become present, (or for arm64 enabled). This leads to messages during boot: | register_cpu_capacity_sysctl: too early to get CPU1 device! and once these CPUs are added to the system, the file is missing. Move this to a cpuhp callback, so that the file is created once CPUs are brought online. This covers CPUs that are added late by mechanisms like hotplug. One observable difference is the file is now missing for offline CPUs. Mainline: NA (cherry picked form openEuler/OLK-6.6 commit 59d8f494c95bb449060e4b64245fc35eac52d470) Signed-off-by: James Morse Reviewed-by: Gavin Shan Signed-off-by: "Russell King (Oracle)" Reviewed-by: Jonathan Cameron Reviewed-by: Thomas Gleixner Link: https://lore.kernel.org/r/E1r5R2g-00CsyV-Ss@rmk-PC.armlinux.org.uk Signed-off-by: Greg Kroah-Hartman Signed-off-by: Li Wei Backported-by: Wu Chen Signed-off-by: Wang Yinfeng Change-Id: Ibefa0d317a2b78f49c7257147861f3159226be38 --- drivers/base/arch_topology.c | 38 ++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c index b741b5ba82..9ccb7daee7 100644 --- a/drivers/base/arch_topology.c +++ b/drivers/base/arch_topology.c @@ -220,20 +220,34 @@ static DECLARE_WORK(update_topology_flags_work, update_topology_flags_workfn); static DEVICE_ATTR_RO(cpu_capacity); -static int register_cpu_capacity_sysctl(void) +static int cpu_capacity_sysctl_add(unsigned int cpu) { - int i; - struct device *cpu; + struct device *cpu_dev = get_cpu_device(cpu); - for_each_possible_cpu(i) { - cpu = get_cpu_device(i); - if (!cpu) { - pr_err("%s: too early to get CPU%d device!\n", - __func__, i); - continue; - } - device_create_file(cpu, &dev_attr_cpu_capacity); - } + if (!cpu_dev) + return -ENOENT; + + device_create_file(cpu_dev, &dev_attr_cpu_capacity); + + return 0; +} + +static int cpu_capacity_sysctl_remove(unsigned int cpu) +{ + struct device *cpu_dev = get_cpu_device(cpu); + + if (!cpu_dev) + return -ENOENT; + + device_remove_file(cpu_dev, &dev_attr_cpu_capacity); + + return 0; +} + +static int register_cpu_capacity_sysctl(void) +{ + cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "topology/cpu-capacity", + cpu_capacity_sysctl_add, cpu_capacity_sysctl_remove); return 0; } -- Gitee From d85007c4aab8521463886404b0ab88a65fad9f00 Mon Sep 17 00:00:00 2001 From: James Morse Date: Tue, 22 Jul 2025 18:14:52 +0800 Subject: [PATCH 076/155] ACPI: Move ACPI_HOTPLUG_CPU to be disabled on arm64 and riscv Neither arm64 nor riscv support physical hotadd of CPUs that were not present at boot. For arm64 much of the platform description is in static tables which do not have update methods. arm64 does support HOTPLUG_CPU, which is backed by a firmware interface to turn CPUs on and off. acpi_processor_hotadd_init() and acpi_processor_remove() are for adding and removing CPUs that were not present at boot. arm64 systems that do this are not supported as there is currently insufficient information in the platform description. (e.g. did the GICR get removed too?) arm64 currently relies on the MADT enabled flag check in map_gicc_mpidr() to prevent CPUs that were not described as present at boot from being added to the system. Similarly, riscv relies on the same check in map_rintc_hartid(). Both architectures also rely on the weak 'always fails' definitions of acpi_map_cpu() and arch_register_cpu(). Subsequent changes will redefine ACPI_HOTPLUG_CPU as making possible CPUs present. Neither arm64 nor riscv support this. Disable ACPI_HOTPLUG_CPU for arm64 and riscv by removing 'default y' and selecting it on the other three ACPI architectures. This allows the weak definitions of some symbols to be removed. Mainline: NA (cherry picked and rework form openEuler/OLK-6.6 commit 8441c7c97519cc743e945db3352464f555225226) Signed-off-by: James Morse Reviewed-by: Shaoqin Huang Reviewed-by: Gavin Shan Signed-off-by: "Russell King (Oracle)" Reviewed-by: Jonathan Cameron Reviewed-by: Thomas Gleixner Link: https://lore.kernel.org/r/E1r5R31-00Csyt-Jq@rmk-PC.armlinux.org.uk Signed-off-by: Greg Kroah-Hartman Signed-off-by: Li Wei Backported-by: Wu Chen Signed-off-by: Wang Yinfeng Change-Id: I40321d6fcd0e50b9a71f15e869507a447d2a03f9 --- drivers/acpi/Kconfig | 1 - drivers/acpi/acpi_processor.c | 18 ------------------ 2 files changed, 19 deletions(-) diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index cee82b473d..8456d48ba7 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -309,7 +309,6 @@ config ACPI_HOTPLUG_CPU bool depends on ACPI_PROCESSOR && HOTPLUG_CPU select ACPI_CONTAINER - default y config ACPI_PROCESSOR_AGGREGATOR tristate "Processor Aggregator" diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c index 7053f1b9fc..a68c6d6b11 100644 --- a/drivers/acpi/acpi_processor.c +++ b/drivers/acpi/acpi_processor.c @@ -184,24 +184,6 @@ static void __init acpi_pcc_cpufreq_init(void) {} /* Initialization */ #ifdef CONFIG_ACPI_HOTPLUG_CPU -int __weak acpi_map_cpu(acpi_handle handle, - phys_cpuid_t physid, u32 acpi_id, int *pcpu) -{ - return -ENODEV; -} - -int __weak acpi_unmap_cpu(int cpu) -{ - return -ENODEV; -} - -int __weak arch_register_cpu(int cpu) -{ - return -ENODEV; -} - -void __weak arch_unregister_cpu(int cpu) {} - static int acpi_processor_hotadd_init(struct acpi_processor *pr) { unsigned long long sta; -- Gitee From 8708bb2cea39b0b767c4ded2b19605a36644f0bc Mon Sep 17 00:00:00 2001 From: James Morse Date: Tue, 22 Jul 2025 18:17:05 +0800 Subject: [PATCH 077/155] drivers/base: Use present CPUs in GENERIC_CPU_DEVICES Three of the five ACPI architectures create sysfs entries using register_cpu() for present CPUs, whereas arm64, riscv and all GENERIC_CPU_DEVICES do this for possible CPUs. Registering a CPU is what causes them to show up in sysfs. It makes very little sense to register all possible CPUs. Registering a CPU is what triggers the udev notifications allowing user-space to react to newly added CPUs. To allow all five ACPI architectures to use GENERIC_CPU_DEVICES, change it to use for_each_present_cpu(). Making the ACPI architectures use GENERIC_CPU_DEVICES is a pre-requisite step to centralise their register_cpu() logic, before moving it into the ACPI processor driver. When we add support for register CPUs from ACPI in a later patch, we will avoid registering CPUs in this path. Of the ACPI architectures that register possible CPUs, arm64 and riscv do not support making possible CPUs present as they use the weak 'always fails' version of arch_register_cpu(). Only two of the eight architectures that use GENERIC_CPU_DEVICES have a distinction between present and possible CPUs. The following architectures use GENERIC_CPU_DEVICES but are not SMP, so possible == present: * m68k * microblaze * nios2 The following architectures use GENERIC_CPU_DEVICES and consider possible == present: * csky: setup_smp() * processor_probe() sets possible for all CPUs and present for all CPUs except the boot cpu, which will have been done by init/main.c::start_kernel(). Um appears to be a subarchitecture of x86. The remaining architecture using GENERIC_CPU_DEVICES are: * openrisc and hexagon: where smp_init_cpus() makes all CPUs < NR_CPUS possible, whereas smp_prepare_cpus() only makes CPUs < setup_max_cpus present. After this change, openrisc and hexagon systems that use the max_cpus command line argument would not see the other CPUs present in sysfs. This should not be a problem as these CPUs can't be brought online as _cpu_up() checks cpu_present(). After this change, only CPUs which are present appear in sysfs. Mainline: NA (cherry picked form openEuler/OLK-6.6 commit 0e3c47820dd9e65463ba5b07deed19b1b5f89b91) Signed-off-by: James Morse Reviewed-by: Jonathan Cameron Reviewed-by: Gavin Shan Signed-off-by: "Russell King (Oracle)" Reviewed-by: Thomas Gleixner Link: https://lore.kernel.org/r/E1r5R36-00Csz0-Px@rmk-PC.armlinux.org.uk Signed-off-by: Greg Kroah-Hartman Signed-off-by: Li Wei Backported-by: Wu Chen Signed-off-by: Wang Yinfeng Change-Id: Ib908ee5db02f074f15ac13eb4856a43820a4ec1a --- drivers/base/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index ef427ee787..f3340aa7e0 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c @@ -533,7 +533,7 @@ static void __init cpu_dev_register_generic(void) #ifdef CONFIG_GENERIC_CPU_DEVICES int i; - for_each_possible_cpu(i) { + for_each_present_cpu(i) { if (register_cpu(&per_cpu(cpu_devices, i), i)) panic("Failed to register CPU device"); } -- Gitee From e6c7d694dc2739099c0cebdf720d25a63ba02a29 Mon Sep 17 00:00:00 2001 From: James Morse Date: Tue, 22 Jul 2025 18:18:33 +0800 Subject: [PATCH 078/155] drivers/base: Allow parts of GENERIC_CPU_DEVICES to be overridden Architectures often have extra per-cpu work that needs doing before a CPU is registered, often to determine if a CPU is hotpluggable. To allow the ACPI architectures to use GENERIC_CPU_DEVICES, move the cpu_register() call into arch_register_cpu(), which is made __weak so architectures with extra work can override it. This aligns with the way x86, ia64 and loongarch register hotplug CPUs when they become present. Mainline: NA (cherry picked form openEuler/OLK-6.6 commit 3afe4eefb90e6cfe4c0c2eaf8d6b958bd7636e45) Signed-off-by: James Morse Reviewed-by: Shaoqin Huang Reviewed-by: Gavin Shan Signed-off-by: "Russell King (Oracle)" Reviewed-by: Jonathan Cameron Reviewed-by: Thomas Gleixner Link: https://lore.kernel.org/r/E1r5R3B-00Csz6-Uh@rmk-PC.armlinux.org.uk Signed-off-by: Greg Kroah-Hartman Signed-off-by: Li Wei Backported-by: Wu Chen Signed-off-by: Wang Yinfeng Change-Id: I161749a85b0e7b355e1a6f8caefd7b44bf53d0ed --- drivers/base/cpu.c | 14 ++++++++++---- include/linux/cpu.h | 4 ++++ 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index f3340aa7e0..631f8c85e8 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c @@ -525,19 +525,25 @@ bool cpu_is_hotpluggable(unsigned int cpu) EXPORT_SYMBOL_GPL(cpu_is_hotpluggable); #ifdef CONFIG_GENERIC_CPU_DEVICES -static DEFINE_PER_CPU(struct cpu, cpu_devices); +DEFINE_PER_CPU(struct cpu, cpu_devices); + +int __weak arch_register_cpu(int cpu) +{ + return register_cpu(&per_cpu(cpu_devices, cpu), cpu); +} #endif static void __init cpu_dev_register_generic(void) { -#ifdef CONFIG_GENERIC_CPU_DEVICES int i; + if (!IS_ENABLED(CONFIG_GENERIC_CPU_DEVICES)) + return; + for_each_present_cpu(i) { - if (register_cpu(&per_cpu(cpu_devices, i), i)) + if (arch_register_cpu(i)) panic("Failed to register CPU device"); } -#endif } #ifdef CONFIG_GENERIC_CPU_VULNERABILITIES diff --git a/include/linux/cpu.h b/include/linux/cpu.h index a7d91a167a..56060c4055 100644 --- a/include/linux/cpu.h +++ b/include/linux/cpu.h @@ -90,6 +90,10 @@ extern ssize_t arch_cpu_probe(const char *, size_t); extern ssize_t arch_cpu_release(const char *, size_t); #endif +#ifdef CONFIG_GENERIC_CPU_DEVICES +DECLARE_PER_CPU(struct cpu, cpu_devices); +#endif + /* * These states are not related to the core CPU hotplug mechanism. They are * used by various (sub)architectures to track internal state -- Gitee From c6637239423358159ea52365d333a5472a052073 Mon Sep 17 00:00:00 2001 From: James Morse Date: Tue, 22 Jul 2025 18:19:57 +0800 Subject: [PATCH 079/155] drivers/Base: Implement weak arch_unregister_cpu() Add arch_unregister_cpu() to allow the ACPI machinery to call unregister_cpu(). This is enough for arm64, riscv and loongarch, but needs to be overridden by x86 and ia64 who need to do more work. Mainline: NA (cherry picked form openEuler/OLK-6.6 commit 9113446db628e6495e09d49bc8180c6d87864bd4) CC: Jean-Philippe Brucker Signed-off-by: James Morse Reviewed-by: Shaoqin Huang Signed-off-by: "Russell King (Oracle)" Reviewed-by: Gavin Shan Reviewed-by: Jonathan Cameron Reviewed-by: Thomas Gleixner Link: https://lore.kernel.org/r/E1r5R3H-00CszC-2n@rmk-PC.armlinux.org.uk Signed-off-by: Greg Kroah-Hartman Signed-off-by: Li Wei Backported-by: Wu Chen Signed-off-by: Wang Yinfeng Change-Id: I0ab5d9c92b4434bc305dccf58af98182e7c35264 --- drivers/base/cpu.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index 631f8c85e8..da66455ca9 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c @@ -531,7 +531,14 @@ int __weak arch_register_cpu(int cpu) { return register_cpu(&per_cpu(cpu_devices, cpu), cpu); } -#endif + +#ifdef CONFIG_HOTPLUG_CPU +void __weak arch_unregister_cpu(int num) +{ + unregister_cpu(&per_cpu(cpu_devices, num)); +} +#endif /* CONFIG_HOTPLUG_CPU */ +#endif /* CONFIG_GENERIC_CPU_DEVICES */ static void __init cpu_dev_register_generic(void) { -- Gitee From 24387f6ca1f95a632a55ced9f3ac19179ae8452c Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Tue, 22 Jul 2025 18:25:39 +0800 Subject: [PATCH 080/155] drivers/base: Add arch_cpu_is_hotpluggable() The differences between architecture specific implementations of arch_register_cpu() are down to whether the CPU is hotpluggable or not. Rather than overriding the weak version of arch_register_cpu(), provide a function that can be used to provide this detail instead. Mainline: NA (cherry picked form openEuler/OLK-6.6 commit ac60940c5c7046f2d931ce78802e5be8496e2deb) Reviewed-by: Shaoqin Huang Signed-off-by: "Russell King (Oracle)" Reviewed-by: Jonathan Cameron Reviewed-by: Gavin Shan Reviewed-by: Thomas Gleixner Link: https://lore.kernel.org/r/E1r5R3M-00CszH-6r@rmk-PC.armlinux.org.uk Signed-off-by: Greg Kroah-Hartman Signed-off-by: Li Wei Backported-by: Wu Chen Signed-off-by: Wang Yinfeng Change-Id: I94dfef66142626c4a46c917aa6c8e796eda81c9a --- drivers/base/cpu.c | 11 ++++++++++- include/linux/cpu.h | 1 + 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index da66455ca9..12f0e9758e 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c @@ -527,9 +527,18 @@ EXPORT_SYMBOL_GPL(cpu_is_hotpluggable); #ifdef CONFIG_GENERIC_CPU_DEVICES DEFINE_PER_CPU(struct cpu, cpu_devices); +bool __weak arch_cpu_is_hotpluggable(int cpu) +{ + return false; +} + int __weak arch_register_cpu(int cpu) { - return register_cpu(&per_cpu(cpu_devices, cpu), cpu); + struct cpu *c = &per_cpu(cpu_devices, cpu); + + c->hotpluggable = arch_cpu_is_hotpluggable(cpu); + + return register_cpu(c, cpu); } #ifdef CONFIG_HOTPLUG_CPU diff --git a/include/linux/cpu.h b/include/linux/cpu.h index 56060c4055..75f0344bd3 100644 --- a/include/linux/cpu.h +++ b/include/linux/cpu.h @@ -82,6 +82,7 @@ extern __printf(4, 5) struct device *cpu_device_create(struct device *parent, void *drvdata, const struct attribute_group **groups, const char *fmt, ...); +extern bool arch_cpu_is_hotpluggable(int cpu); extern int arch_register_cpu(int cpu); extern void arch_unregister_cpu(int cpu); #ifdef CONFIG_HOTPLUG_CPU -- Gitee From 88c61ce2952423d6df1cf83b7616e8c4c6150636 Mon Sep 17 00:00:00 2001 From: James Morse Date: Tue, 22 Jul 2025 18:27:16 +0800 Subject: [PATCH 081/155] drivers/base: Move cpu_dev_init() after node_dev_init() NUMA systems require the node descriptions to be ready before CPUs are registered. This is so that the node symlinks can be created in sysfs. Currently no NUMA platform uses GENERIC_CPU_DEVICES, meaning that CPUs are registered by arch code, instead of cpu_dev_init(). Move cpu_dev_init() after node_dev_init() so that NUMA architectures can use GENERIC_CPU_DEVICES. Mainline: NA (cherry picked form openEuler/OLK-6.6 commit a751935d9ccb40e4b16654e43aa71b2a452fea17) Signed-off-by: James Morse Signed-off-by: "Russell King (Oracle)" Reviewed-by: Gavin Shan Reviewed-by: Jonathan Cameron Reviewed-by: Thomas Gleixner Link: https://lore.kernel.org/r/E1r5R3R-00CszO-C0@rmk-PC.armlinux.org.uk Signed-off-by: Greg Kroah-Hartman Signed-off-by: Li Wei Backported-by: Wu Chen Signed-off-by: Wang Yinfeng Change-Id: Ibbb7b075435f0f53156e3ffcea0f2efa0caeb234 --- drivers/base/init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/base/init.c b/drivers/base/init.c index 397eb9880c..c495483512 100644 --- a/drivers/base/init.c +++ b/drivers/base/init.c @@ -35,8 +35,8 @@ void __init driver_init(void) of_core_init(); platform_bus_init(); auxiliary_bus_init(); - cpu_dev_init(); memory_dev_init(); node_dev_init(); + cpu_dev_init(); container_dev_init(); } -- Gitee From aeb91f6b8d110a0902b126e84c6075960bb1a61d Mon Sep 17 00:00:00 2001 From: James Morse Date: Wed, 23 Jul 2025 09:20:18 +0800 Subject: [PATCH 082/155] drivers/base: Print warning instead of panic() when register_cpu() fails Errors in this path indicate something is wrong with the firmware description of the platform, but the kernel is able to keep running. Downgrade this to a warning to make it easier to debug this issue. This will allow architectures that switching over to GENERIC_CPU_DEVICES to drop their warning, but keep the existing behaviour. Mainline: NA (cherry picked form openEuler/OLK-6.6 commit 6ccea992445f82f4d6cfbed125616ebe7dfb8254) Signed-off-by: James Morse Reviewed-by: "Russell King (Oracle)" Reviewed-by: Shaoqin Huang Signed-off-by: "Russell King (Oracle)" Reviewed-by: Gavin Shan Reviewed-by: Jonathan Cameron Reviewed-by: Thomas Gleixner Link: https://lore.kernel.org/r/E1r5R3W-00CszU-GM@rmk-PC.armlinux.org.uk Signed-off-by: Greg Kroah-Hartman Signed-off-by: Li Wei Backported-by: Wu Chen Signed-off-by: Wang Yinfeng Change-Id: Ibdf9c525a3169bdaa895287d9df52d8b0016abd5 --- drivers/base/cpu.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index 12f0e9758e..0b33e81f9c 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c @@ -551,14 +551,15 @@ void __weak arch_unregister_cpu(int num) static void __init cpu_dev_register_generic(void) { - int i; + int i, ret; if (!IS_ENABLED(CONFIG_GENERIC_CPU_DEVICES)) return; for_each_present_cpu(i) { - if (arch_register_cpu(i)) - panic("Failed to register CPU device"); + ret = arch_register_cpu(i); + if (ret) + pr_warn("register_cpu %d failed (%d)\n", i, ret); } } -- Gitee From 1b137233436f8f4e1ada4241a03044362262a170 Mon Sep 17 00:00:00 2001 From: James Morse Date: Wed, 23 Jul 2025 14:05:13 +0800 Subject: [PATCH 083/155] arm64/setup: Switch over to GENERIC_CPU_DEVICES using arch_register_cpu() To allow ACPI's _STA value to hide CPUs that are present, but not available to online right now due to VMM or firmware policy, the register_cpu() call needs to be made by the ACPI machinery when ACPI is in use. This allows it to hide CPUs that are unavailable from sysfs. Switching to GENERIC_CPU_DEVICES is an intermediate step to allow all five ACPI architectures to be modified at once. Switch over to GENERIC_CPU_DEVICES, and provide an arch_register_cpu() that populates the hotpluggable flag. arch_register_cpu() is also the interface the ACPI machinery expects. The struct cpu in struct cpuinfo_arm64 is never used directly, remove it to use the one GENERIC_CPU_DEVICES provides. This changes the CPUs visible in sysfs from possible to present, but on arm64 smp_prepare_cpus() ensures these are the same. This patch also has the effect of moving the registration of CPUs from subsys to driver core initialisation, prior to any initcalls running. Mainline: NA (cherry picked form openEuler/OLK-6.6 commit 85000d4749901c304f0ef5446203718862ea8e9d) Signed-off-by: James Morse Reviewed-by: "Russell King (Oracle)" Reviewed-by: Shaoqin Huang Reviewed-by: Gavin Shan Signed-off-by: "Russell King (Oracle)" Reviewed-by: Jonathan Cameron Reviewed-by: Thomas Gleixner Link: https://lore.kernel.org/r/E1r5R3b-00Csza-Ku@rmk-PC.armlinux.org.uk Signed-off-by: Greg Kroah-Hartman Signed-off-by: Li Wei Backported-by: Wu Chen Signed-off-by: Wang Yinfeng Change-Id: I415d5ebc2b4dca371a579b632fcfccabe32e90fa --- arch/arm64/Kconfig | 1 + arch/arm64/include/asm/cpu.h | 1 - arch/arm64/kernel/setup.c | 13 ++++--------- 3 files changed, 5 insertions(+), 10 deletions(-) diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index c944fe2c91..8ca0fecba5 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -134,6 +134,7 @@ config ARM64 select GENERIC_ARCH_TOPOLOGY select GENERIC_CLOCKEVENTS_BROADCAST select GENERIC_CPU_AUTOPROBE + select GENERIC_CPU_DEVICES select GENERIC_CPU_VULNERABILITIES select GENERIC_EARLY_IOREMAP select GENERIC_IDLE_POLL_SETUP diff --git a/arch/arm64/include/asm/cpu.h b/arch/arm64/include/asm/cpu.h index e749838b9c..887bd0d992 100644 --- a/arch/arm64/include/asm/cpu.h +++ b/arch/arm64/include/asm/cpu.h @@ -38,7 +38,6 @@ struct cpuinfo_32bit { }; struct cpuinfo_arm64 { - struct cpu cpu; struct kobject kobj; u64 reg_ctr; u64 reg_cntfrq; diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index 04a07e7348..8df7628a73 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -425,19 +425,14 @@ static inline bool cpu_can_disable(unsigned int cpu) return false; } -static int __init topology_init(void) +int arch_register_cpu(int num) { - int i; + struct cpu *cpu = &per_cpu(cpu_devices, num); - for_each_possible_cpu(i) { - struct cpu *cpu = &per_cpu(cpu_data.cpu, i); - cpu->hotpluggable = cpu_can_disable(i); - register_cpu(cpu, i); - } + cpu->hotpluggable = cpu_can_disable(num); - return 0; + return register_cpu(cpu, num); } -subsys_initcall(topology_init); static void dump_kernel_offset(void) { -- Gitee From dbc66341f7e7d0e4ba6769f2611204d84fcaddc5 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Wed, 23 Jul 2025 14:08:07 +0800 Subject: [PATCH 084/155] arm64: Convert to arch_cpu_is_hotpluggable() Convert arm64 to use the arch_cpu_is_hotpluggable() helper rather than arch_register_cpu(). Mainline: NA (cherry picked form openEuler/OLK-6.6 commit d78aba4f20f67f24df678e1b19905608c3aa6cca) Reviewed-by: Shaoqin Huang Reviewed-by: Gavin Shan Signed-off-by: "Russell King (Oracle)" Reviewed-by: Jonathan Cameron Reviewed-by: Thomas Gleixner Link: https://lore.kernel.org/r/E1r5R3g-00Cszg-PP@rmk-PC.armlinux.org.uk Signed-off-by: Greg Kroah-Hartman Signed-off-by: Li Wei Backported-by: Wu Chen Signed-off-by: Wang Yinfeng Change-Id: Ia0259632c69bc9e57af0e0e5e2a1d21f5f36aed5 --- arch/arm64/kernel/setup.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index 8df7628a73..fca316e33d 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -425,13 +425,9 @@ static inline bool cpu_can_disable(unsigned int cpu) return false; } -int arch_register_cpu(int num) +bool arch_cpu_is_hotpluggable(int num) { - struct cpu *cpu = &per_cpu(cpu_devices, num); - - cpu->hotpluggable = cpu_can_disable(num); - - return register_cpu(cpu, num); + return cpu_can_disable(num); } static void dump_kernel_offset(void) -- Gitee From e2cdf862fc8b0068a560698dae74a114d22a4f00 Mon Sep 17 00:00:00 2001 From: James Morse Date: Wed, 23 Jul 2025 14:31:01 +0800 Subject: [PATCH 085/155] ACPI: Only enumerate enabled (or functional) devices Today the ACPI enumeration code 'visits' all devices that are present. This is a problem for arm64, where CPUs are always present, but not always enabled. When a device-check occurs because the firmware-policy has changed and a CPU is now enabled, the following error occurs: | acpi ACPI0007:48: Enumeration failure This is ultimately because acpi_dev_ready_for_enumeration() returns true for a device that is not enabled. The ACPI Processor driver will not register such CPUs as they are not 'decoding their resources'. Change acpi_dev_ready_for_enumeration() to also check the enabled bit. ACPI allows a device to be functional instead of maintaining the present and enabled bit. Make this behaviour an explicit check with a reference to the spec, and then check the present and enabled bits. This is needed to avoid enumerating present && functional devices that are not enabled. Mainline: NA (cherry picked form openEuler/OLK-6.6 commit 29b33523c2db90015694fe8035c1f143c07e361e) Signed-off-by: James Morse Tested-by: Miguel Luis Tested-by: Vishnu Pajjuri Tested-by: Jianyong Wu Signed-off-by: Russell King (Oracle) Reviewed-by: Jonathan Cameron Signed-off-by: James Morse Signed-off-by: Russell King (Oracle) Tested-by: Jonathan Cameron Reviewed-by: Jonathan Cameron Signed-off-by: Li Wei Backported-by: Wu Chen Signed-off-by: Wang Yinfeng Change-Id: I91bdaaaf0c7a2c2a8c445e0d96bbc42313d77273 --- drivers/acpi/device_pm.c | 2 +- drivers/acpi/device_sysfs.c | 2 +- drivers/acpi/internal.h | 1 - drivers/acpi/property.c | 2 +- drivers/acpi/scan.c | 24 ++++++++++++++---------- 5 files changed, 17 insertions(+), 14 deletions(-) diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index 3b4d048c49..e3c80f3b3b 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -313,7 +313,7 @@ int acpi_bus_init_power(struct acpi_device *device) return -EINVAL; device->power.state = ACPI_STATE_UNKNOWN; - if (!acpi_device_is_present(device)) { + if (!acpi_dev_ready_for_enumeration(device)) { device->flags.initialized = false; return -ENXIO; } diff --git a/drivers/acpi/device_sysfs.c b/drivers/acpi/device_sysfs.c index 6ed5e9e56b..eae6016ad2 100644 --- a/drivers/acpi/device_sysfs.c +++ b/drivers/acpi/device_sysfs.c @@ -141,7 +141,7 @@ static int create_pnp_modalias(const struct acpi_device *acpi_dev, char *modalia struct acpi_hardware_id *id; /* Avoid unnecessarily loading modules for non present devices. */ - if (!acpi_device_is_present(acpi_dev)) + if (!acpi_dev_ready_for_enumeration(acpi_dev)) return 0; /* diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 3642bd3860..dec9532b35 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -119,7 +119,6 @@ int acpi_device_setup_files(struct acpi_device *dev); void acpi_device_remove_files(struct acpi_device *dev); void acpi_device_add_finalize(struct acpi_device *device); void acpi_free_pnp_ids(struct acpi_device_pnp *pnp); -bool acpi_device_is_present(const struct acpi_device *adev); bool acpi_device_is_battery(struct acpi_device *adev); bool acpi_device_is_first_physical_node(struct acpi_device *adev, const struct device *dev); diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c index 4d958a165d..a0b03160fd 100644 --- a/drivers/acpi/property.c +++ b/drivers/acpi/property.c @@ -1423,7 +1423,7 @@ static bool acpi_fwnode_device_is_available(const struct fwnode_handle *fwnode) if (!is_acpi_device_node(fwnode)) return false; - return acpi_device_is_present(to_acpi_device_node(fwnode)); + return acpi_dev_ready_for_enumeration(to_acpi_device_node(fwnode)); } static const void * diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 08a1df2a3e..54819bc510 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -304,7 +304,7 @@ static int acpi_scan_device_check(struct acpi_device *adev) int error; acpi_bus_get_status(adev); - if (acpi_device_is_present(adev)) { + if (acpi_dev_ready_for_enumeration(adev)) { /* * This function is only called for device objects for which * matching scan handlers exist. The only situation in which @@ -334,7 +334,7 @@ static int acpi_scan_bus_check(struct acpi_device *adev, void *not_used) int error; acpi_bus_get_status(adev); - if (!acpi_device_is_present(adev)) { + if (!acpi_dev_ready_for_enumeration(adev)) { acpi_scan_device_not_enumerated(adev); return 0; } @@ -1910,11 +1910,6 @@ static bool acpi_device_should_be_hidden(acpi_handle handle) return true; } -bool acpi_device_is_present(const struct acpi_device *adev) -{ - return adev->status.present || adev->status.functional; -} - static bool acpi_scan_handler_matching(struct acpi_scan_handler *handler, const char *idstr, const struct acpi_device_id **matchid) @@ -2379,16 +2374,25 @@ EXPORT_SYMBOL_GPL(acpi_dev_clear_dependencies); * acpi_dev_ready_for_enumeration - Check if the ACPI device is ready for enumeration * @device: Pointer to the &struct acpi_device to check * - * Check if the device is present and has no unmet dependencies. + * Check if the device is functional or enabled and has no unmet dependencies. * - * Return true if the device is ready for enumeratino. Otherwise, return false. + * Return true if the device is ready for enumeration. Otherwise, return false. */ bool acpi_dev_ready_for_enumeration(const struct acpi_device *device) { if (device->flags.honor_deps && device->dep_unmet) return false; - return acpi_device_is_present(device); + /* + * ACPI 6.5's 6.3.7 "_STA (Device Status)" allows firmware to return + * (!present && functional) for certain types of devices that should be + * enumerated. Note that the enabled bit can't be sert until the present + * bit is set. + */ + if (device->status.present) + return device->status.enabled; + else + return device->status.functional; } EXPORT_SYMBOL_GPL(acpi_dev_ready_for_enumeration); -- Gitee From 295c1add1e7ab89f0b011d61d0eb1f0724993dcf Mon Sep 17 00:00:00 2001 From: James Morse Date: Wed, 23 Jul 2025 14:32:17 +0800 Subject: [PATCH 086/155] ACPI/processor: Register CPUs that online,but not described in the DSDT ACPI has two descriptions of CPUs, one in the MADT/APIC table, the other in the DSDT. Both are required. (ACPI 6.5's 8.4 "Declaring Processors" says "Each processor in the system must be declared in the ACPI namespace"). Having two descriptions allows firmware authors to get this wrong. If CPUs are described in the MADT/APIC, they will be brought online early during boot. Once the register_cpu() calls are moved to ACPI, they will be based on the DSDT description of the CPUs. When CPUs are missing from the DSDT description, they will end up online, but not registered. Add a helper that runs after acpi_init() has completed to register CPUs that are online, but weren't found in the DSDT. Any CPU that is registered by this code triggers a firmware-bug warning and kernel taint. Qemu TCG only describes the first CPU in the DSDT, unless cpu-hotplug is configured. Mainline: NA (cherry picked form openEuler/OLK-6.6 commit b6e0a37a92d9a4b2f374fa4f298ff8fc8cdae448) Signed-off-by: James Morse Reviewed-by: Jonathan Cameron Reviewed-by: Gavin Shan Tested-by: Miguel Luis Tested-by: Vishnu Pajjuri Tested-by: Jianyong Wu Signed-off-by: Russell King (Oracle) Signed-off-by: Li Wei Backported-by: Wu Chen Signed-off-by: Wang Yinfeng Change-Id: Iec9f9c0af66be034085f17d1638596668c2e4f3d --- drivers/acpi/acpi_processor.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c index a68c6d6b11..69861684aa 100644 --- a/drivers/acpi/acpi_processor.c +++ b/drivers/acpi/acpi_processor.c @@ -770,6 +770,25 @@ void __init acpi_processor_init(void) acpi_pcc_cpufreq_init(); } +static int __init acpi_processor_register_missing_cpus(void) +{ + int cpu; + + if (acpi_disabled) + return 0; + + for_each_online_cpu(cpu) { + if (!get_cpu_device(cpu)) { + pr_err_once(FW_BUG "CPU %u has no ACPI namespace description!\n", cpu); + add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK); + arch_register_cpu(cpu); + } + } + + return 0; +} +subsys_initcall_sync(acpi_processor_register_missing_cpus); + #ifdef CONFIG_ACPI_PROCESSOR_CSTATE /** * acpi_processor_claim_cst_control - Request _CST control from the platform. -- Gitee From e9733b328bd97aad145fd681d6c92a4e9a38a2d4 Mon Sep 17 00:00:00 2001 From: James Morse Date: Wed, 23 Jul 2025 14:34:53 +0800 Subject: [PATCH 087/155] ACPI/processor: Register all CPUs from acpi_processor_get_info() To allow ACPI to skip the call to arch_register_cpu() when the _STA value indicates the CPU can't be brought online right now, move the arch_register_cpu() call into acpi_processor_get_info(). Systems can still be booted with 'acpi=off', or not include an ACPI description at all. For these, the CPUs continue to be registered by cpu_dev_register_generic(). This moves the CPU register logic back to a subsys_initcall(), while the memory nodes will have been registered earlier. Mainline: NA (cherry picked form openEuler/OLK-6.6 commit 734ada1b9f8b9b802037d8303547f81ccbc6ac2b) Signed-off-by: James Morse Reviewed-by: Gavin Shan Tested-by: Miguel Luis Tested-by: Vishnu Pajjuri Tested-by: Jianyong Wu Signed-off-by: Russell King (Oracle) Reviewed-by: Jonathan Cameron Signed-off-by: Li Wei Backported-by: Wu Chen Signed-off-by: Wang Yinfeng Change-Id: I00dd19a011e9bc279d96da6cc3fb4d4e50b35a7c --- drivers/acpi/acpi_processor.c | 12 ++++++++++++ drivers/base/cpu.c | 6 +++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c index 69861684aa..1f32b7cced 100644 --- a/drivers/acpi/acpi_processor.c +++ b/drivers/acpi/acpi_processor.c @@ -314,6 +314,18 @@ static int acpi_processor_get_info(struct acpi_device *device) cpufreq_add_device("acpi-cpufreq"); } + /* + * Register CPUs that are present. get_cpu_device() is used to skip + * duplicate CPU descriptions from firmware. + */ + if (!invalid_logical_cpuid(pr->id) && cpu_present(pr->id) && + !get_cpu_device(pr->id)) { + int ret = arch_register_cpu(pr->id); + + if (ret) + return ret; + } + /* * Extra Processor objects may be enumerated on MP systems with * less than the max # of CPUs. They should be ignored _iff diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index 0b33e81f9c..c39cc487d0 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c @@ -553,7 +553,11 @@ static void __init cpu_dev_register_generic(void) { int i, ret; - if (!IS_ENABLED(CONFIG_GENERIC_CPU_DEVICES)) + /* + * When ACPI is enabled, CPUs are registered via + * acpi_processor_get_info(). + */ + if (!IS_ENABLED(CONFIG_GENERIC_CPU_DEVICES) || !acpi_disabled) return; for_each_present_cpu(i) { -- Gitee From 0a3e3dbee712787d539dcaebea780c53374701ff Mon Sep 17 00:00:00 2001 From: James Morse Date: Wed, 23 Jul 2025 14:36:33 +0800 Subject: [PATCH 088/155] ACPI: Rename ACPI_HOTPLUG_CPU to include 'present' The code behind ACPI_HOTPLUG_CPU allows a not-present CPU to become present. This isn't the only use of HOTPLUG_CPU. On arm64 and riscv CPUs can be taken offline as a power saving measure. On arm64 an offline CPU may be disabled by firmware, preventing it from being brought back online, but it remains present throughout. Adding code to prevent user-space trying to online these disabled CPUs needs some additional terminology. Rename the Kconfig symbol CONFIG_ACPI_HOTPLUG_PRESENT_CPU to reflect that it makes possible CPUs present. HOTPLUG_CPU is untouched as this is only about the ACPI mechanism. Mainline: NA (cherry picked and rework form openEuler/OLK-6.6 commit 2eb3daf61b18d620b0624e31ad44ac1c76d94075) Signed-off-by: James Morse Tested-by: Miguel Luis Tested-by: Vishnu Pajjuri Tested-by: Jianyong Wu Signed-off-by: Russell King (Oracle) Reviewed-by: Jonathan Cameron Backported-by: Wu Chen Signed-off-by: Wang Yinfeng Change-Id: I83bba65a582aa90dc0a19c2cc24d072312cef256 --- drivers/acpi/Kconfig | 4 ++-- drivers/acpi/acpi_processor.c | 10 +++++----- include/linux/acpi.h | 6 +++--- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 8456d48ba7..417f9f3077 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -305,7 +305,7 @@ config ACPI_IPMI To compile this driver as a module, choose M here: the module will be called as acpi_ipmi. -config ACPI_HOTPLUG_CPU +config ACPI_HOTPLUG_PRESENT_CPU bool depends on ACPI_PROCESSOR && HOTPLUG_CPU select ACPI_CONTAINER @@ -399,7 +399,7 @@ config ACPI_PCI_SLOT config ACPI_CONTAINER bool "Container and Module Devices" - default (ACPI_HOTPLUG_MEMORY || ACPI_HOTPLUG_CPU) + default (ACPI_HOTPLUG_MEMORY || ACPI_HOTPLUG_PRESENT_CPU) help This driver supports ACPI Container and Module devices (IDs ACPI0004, PNP0A05, and PNP0A06). diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c index 1f32b7cced..d8042331a8 100644 --- a/drivers/acpi/acpi_processor.c +++ b/drivers/acpi/acpi_processor.c @@ -183,7 +183,7 @@ static void __init acpi_pcc_cpufreq_init(void) {} #endif /* CONFIG_X86 */ /* Initialization */ -#ifdef CONFIG_ACPI_HOTPLUG_CPU +#ifdef CONFIG_ACPI_HOTPLUG_PRESENT_CPU static int acpi_processor_hotadd_init(struct acpi_processor *pr) { unsigned long long sta; @@ -228,7 +228,7 @@ static inline int acpi_processor_hotadd_init(struct acpi_processor *pr) { return -ENODEV; } -#endif /* CONFIG_ACPI_HOTPLUG_CPU */ +#endif /* CONFIG_ACPI_HOTPLUG_PRESENT_CPU */ static int acpi_processor_get_info(struct acpi_device *device) { @@ -462,7 +462,7 @@ static int acpi_processor_add(struct acpi_device *device, return result; } -#ifdef CONFIG_ACPI_HOTPLUG_CPU +#ifdef CONFIG_ACPI_HOTPLUG_PRESENT_CPU /* Removal */ static void acpi_processor_remove(struct acpi_device *device) { @@ -506,7 +506,7 @@ static void acpi_processor_remove(struct acpi_device *device) free_cpumask_var(pr->throttling.shared_cpu_map); kfree(pr); } -#endif /* CONFIG_ACPI_HOTPLUG_CPU */ +#endif /* CONFIG_ACPI_HOTPLUG_PRESENT_CPU */ #ifdef CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC bool __init processor_physically_present(acpi_handle handle) @@ -631,7 +631,7 @@ static const struct acpi_device_id processor_device_ids[] = { static struct acpi_scan_handler processor_handler = { .ids = processor_device_ids, .attach = acpi_processor_add, -#ifdef CONFIG_ACPI_HOTPLUG_CPU +#ifdef CONFIG_ACPI_HOTPLUG_PRESENT_CPU .detach = acpi_processor_remove, #endif .hotplug = { diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 3c16781249..e7936630a1 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -321,12 +321,12 @@ static inline int acpi_processor_evaluate_cst(acpi_handle handle, u32 cpu, } #endif -#ifdef CONFIG_ACPI_HOTPLUG_CPU +#ifdef CONFIG_ACPI_HOTPLUG_PRESENT_CPU /* Arch dependent functions for cpu hotplug support */ int acpi_map_cpu(acpi_handle handle, phys_cpuid_t physid, u32 acpi_id, int *pcpu); int acpi_unmap_cpu(int cpu); -#endif /* CONFIG_ACPI_HOTPLUG_CPU */ +#endif /* CONFIG_ACPI_HOTPLUG_PRESENT_CPU */ #ifdef CONFIG_ACPI_HOTPLUG_IOAPIC int acpi_get_ioapic_id(acpi_handle handle, u32 gsi_base, u64 *phys_addr); @@ -661,7 +661,7 @@ static inline u32 acpi_osc_ctx_get_cxl_control(struct acpi_osc_context *context) #define ACPI_GSB_ACCESS_ATTRIB_RAW_PROCESS 0x0000000F /* Enable _OST when all relevant hotplug operations are enabled */ -#if defined(CONFIG_ACPI_HOTPLUG_CPU) && \ +#if defined(CONFIG_ACPI_HOTPLUG_PRESENT_CPU) && \ defined(CONFIG_ACPI_HOTPLUG_MEMORY) && \ defined(CONFIG_ACPI_CONTAINER) #define ACPI_HOTPLUG_OST -- Gitee From 0d1b0c204b22f8186f9dc6c235b24b6a984a2a4a Mon Sep 17 00:00:00 2001 From: James Morse Date: Wed, 23 Jul 2025 14:44:24 +0800 Subject: [PATCH 089/155] ACPI: Move acpi_bus_trim_one() before acpi_scan_hot_remove() A subsequent patch will change acpi_scan_hot_remove() to call acpi_bus_trim_one() instead of acpi_bus_trim(), meaning it can no longer rely on the prototype in the header file. Move these functions further up the file. No change in behaviour. Mainline: NA (cherry picked form openEuler/OLK-6.6 commit 39200a03949fd68a94a1aac6d2f6450354afb47c) Signed-off-by: James Morse Reviewed-by: Jonathan Cameron Reviewed-by: Gavin Shan Tested-by: Miguel Luis Tested-by: Vishnu Pajjuri Tested-by: Jianyong Wu Signed-off-by: Russell King (Oracle) Signed-off-by: Li Wei Backported-by: Wu Chen Signed-off-by: Wang Yinfeng Change-Id: Ifb8dfd450e1064926644d1badfa65eaa3978aaf7 --- drivers/acpi/scan.c | 76 ++++++++++++++++++++++----------------------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 54819bc510..84573f5b6b 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -244,6 +244,44 @@ static int acpi_scan_try_to_offline(struct acpi_device *device) return 0; } +static int acpi_bus_trim_one(struct acpi_device *adev, void *not_used) +{ + struct acpi_scan_handler *handler = adev->handler; + + acpi_dev_for_each_child_reverse(adev, acpi_bus_trim_one, NULL); + + adev->flags.match_driver = false; + if (handler) { + if (handler->detach) + handler->detach(adev); + + adev->handler = NULL; + } else { + device_release_driver(&adev->dev); + } + /* + * Most likely, the device is going away, so put it into D3cold before + * that. + */ + acpi_device_set_power(adev, ACPI_STATE_D3_COLD); + adev->flags.initialized = false; + acpi_device_clear_enumerated(adev); + + return 0; +} + +/** + * acpi_bus_trim - Detach scan handlers and drivers from ACPI device objects. + * @adev: Root of the ACPI namespace scope to walk. + * + * Must be called under acpi_scan_lock. + */ +void acpi_bus_trim(struct acpi_device *adev) +{ + acpi_bus_trim_one(adev, NULL); +} +EXPORT_SYMBOL_GPL(acpi_bus_trim); + static int acpi_scan_hot_remove(struct acpi_device *device) { acpi_handle handle = device->handle; @@ -2511,44 +2549,6 @@ int acpi_bus_scan(acpi_handle handle) } EXPORT_SYMBOL(acpi_bus_scan); -static int acpi_bus_trim_one(struct acpi_device *adev, void *not_used) -{ - struct acpi_scan_handler *handler = adev->handler; - - acpi_dev_for_each_child_reverse(adev, acpi_bus_trim_one, NULL); - - adev->flags.match_driver = false; - if (handler) { - if (handler->detach) - handler->detach(adev); - - adev->handler = NULL; - } else { - device_release_driver(&adev->dev); - } - /* - * Most likely, the device is going away, so put it into D3cold before - * that. - */ - acpi_device_set_power(adev, ACPI_STATE_D3_COLD); - adev->flags.initialized = false; - acpi_device_clear_enumerated(adev); - - return 0; -} - -/** - * acpi_bus_trim - Detach scan handlers and drivers from ACPI device objects. - * @adev: Root of the ACPI namespace scope to walk. - * - * Must be called under acpi_scan_lock. - */ -void acpi_bus_trim(struct acpi_device *adev) -{ - acpi_bus_trim_one(adev, NULL); -} -EXPORT_SYMBOL_GPL(acpi_bus_trim); - int acpi_bus_register_early_device(int type) { struct acpi_device *device = NULL; -- Gitee From cff378a5e4f2140a8b04b4192b081b6a6ec4d3a3 Mon Sep 17 00:00:00 2001 From: James Morse Date: Wed, 23 Jul 2025 14:46:35 +0800 Subject: [PATCH 090/155] ACPI: Rename acpi_processor_hotadd_init and remove pre-processor guards acpi_processor_hotadd_init() will make a CPU present by mapping it based on its hardware id. 'hotadd_init' is ambiguous once there are two different behaviours for cpu hotplug. This is for toggling the _STA present bit. Subsequent patches will add support for toggling the _STA enabled bit, named acpi_processor_make_enabled(). Rename it acpi_processor_make_present() to make it clear this is for CPUs that were not previously present. Expose the function prototypes it uses to allow the preprocessor guards to be removed. The IS_ENABLED() check will let the compiler dead-code elimination pass remove this if it isn't going to be used. Mainline: NA (cherry picked form openEuler/OLK-6.6 commit 2edf4314b124fe7b01108e40b572f6e3add8c518) Signed-off-by: James Morse Tested-by: Miguel Luis Tested-by: Vishnu Pajjuri Tested-by: Jianyong Wu Reviewed-by: Jonathan Cameron Signed-off-by: Li Wei Backporded-by: Wu Chen Signed-off-by: Wang Yinfeng Change-Id: I66a9e1e48eb2dc1e01c713f454c45403f3544878 --- drivers/acpi/acpi_processor.c | 14 +++++--------- include/linux/acpi.h | 2 -- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c index d8042331a8..4af3f581ff 100644 --- a/drivers/acpi/acpi_processor.c +++ b/drivers/acpi/acpi_processor.c @@ -183,13 +183,15 @@ static void __init acpi_pcc_cpufreq_init(void) {} #endif /* CONFIG_X86 */ /* Initialization */ -#ifdef CONFIG_ACPI_HOTPLUG_PRESENT_CPU -static int acpi_processor_hotadd_init(struct acpi_processor *pr) +static int acpi_processor_make_present(struct acpi_processor *pr) { unsigned long long sta; acpi_status status; int ret; + if (!IS_ENABLED(CONFIG_ACPI_HOTPLUG_PRESENT_CPU)) + return -ENODEV; + if (invalid_phys_cpuid(pr->phys_id)) return -ENODEV; @@ -223,12 +225,6 @@ static int acpi_processor_hotadd_init(struct acpi_processor *pr) cpu_maps_update_done(); return ret; } -#else -static inline int acpi_processor_hotadd_init(struct acpi_processor *pr) -{ - return -ENODEV; -} -#endif /* CONFIG_ACPI_HOTPLUG_PRESENT_CPU */ static int acpi_processor_get_info(struct acpi_device *device) { @@ -335,7 +331,7 @@ static int acpi_processor_get_info(struct acpi_device *device) * because cpuid <-> apicid mapping is persistent now. */ if (invalid_logical_cpuid(pr->id) || !cpu_present(pr->id)) { - int ret = acpi_processor_hotadd_init(pr); + int ret = acpi_processor_make_present(pr); if (ret) return ret; diff --git a/include/linux/acpi.h b/include/linux/acpi.h index e7936630a1..42b993e771 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -321,12 +321,10 @@ static inline int acpi_processor_evaluate_cst(acpi_handle handle, u32 cpu, } #endif -#ifdef CONFIG_ACPI_HOTPLUG_PRESENT_CPU /* Arch dependent functions for cpu hotplug support */ int acpi_map_cpu(acpi_handle handle, phys_cpuid_t physid, u32 acpi_id, int *pcpu); int acpi_unmap_cpu(int cpu); -#endif /* CONFIG_ACPI_HOTPLUG_PRESENT_CPU */ #ifdef CONFIG_ACPI_HOTPLUG_IOAPIC int acpi_get_ioapic_id(acpi_handle handle, u32 gsi_base, u64 *phys_addr); -- Gitee From 5653f00d46be73c5a42be9df98b4ccd310674b1d Mon Sep 17 00:00:00 2001 From: James Morse Date: Wed, 23 Jul 2025 15:00:43 +0800 Subject: [PATCH 091/155] ACPI: Add post_eject to struct acpi_scan_handler for cpu hotplug Struct acpi_scan_handler has a detach callback that is used to remove a driver when a bus is changed. When interacting with an eject-request, the detach callback is called before _EJ0. This means the ACPI processor driver can't use _STA to determine if a CPU has been made not-present, or some of the other _STA bits have been changed. acpi_processor_remove() needs to know the value of _STA after _EJ0 has been called. Add a post_eject callback to struct acpi_scan_handler. This is called after acpi_scan_hot_remove() has successfully called _EJ0. Because acpi_bus_trim_one() also clears the handler pointer, it needs to be told if the caller will go on to call acpi_bus_post_eject(), so that acpi_device_clear_enumerated() and clearing the handler pointer can be deferred. The existing not-used pointer is used for this. Mainline: NA (cherry picked form openEuler/OLK6.6 commit f60dfc949efefbfbeb4fad3ec0ea39402d058076) Signed-off-by: James Morse Reviewed-by: Joanthan Cameron Reviewed-by: Gavin Shan Tested-by: Miguel Luis Tested-by: Vishnu Pajjuri Tested-by: Jianyong Wu Signed-off-by: Li Wei Backported-by: Wu Chen Signed-off-by: Wang Yinfeng Change-Id: I94f3c2fbcf16536116be1d5467b57be4b1f3cc33 --- drivers/acpi/acpi_processor.c | 4 +-- drivers/acpi/scan.c | 52 ++++++++++++++++++++++++++++++----- include/acpi/acpi_bus.h | 1 + 3 files changed, 48 insertions(+), 9 deletions(-) diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c index 4af3f581ff..9d9a234582 100644 --- a/drivers/acpi/acpi_processor.c +++ b/drivers/acpi/acpi_processor.c @@ -460,7 +460,7 @@ static int acpi_processor_add(struct acpi_device *device, #ifdef CONFIG_ACPI_HOTPLUG_PRESENT_CPU /* Removal */ -static void acpi_processor_remove(struct acpi_device *device) +static void acpi_processor_post_eject(struct acpi_device *device) { struct acpi_processor *pr; @@ -628,7 +628,7 @@ static struct acpi_scan_handler processor_handler = { .ids = processor_device_ids, .attach = acpi_processor_add, #ifdef CONFIG_ACPI_HOTPLUG_PRESENT_CPU - .detach = acpi_processor_remove, + .post_eject = acpi_processor_post_eject, #endif .hotplug = { .enabled = true, diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 84573f5b6b..6dbe457944 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -244,18 +244,28 @@ static int acpi_scan_try_to_offline(struct acpi_device *device) return 0; } -static int acpi_bus_trim_one(struct acpi_device *adev, void *not_used) +/** + * acpi_bus_trim_one() - Detach scan handlers and drivers from ACPI device + * objects. + * @adev: Root of the ACPI namespace scope to walk. + * @eject: Pointer to a bool that indicates if this was due to an + * eject-request. + * + * Must be called under acpi_scan_lock. + * If @eject points to true, clearing the device enumeration is deferred until + * acpi_bus_post_eject() is called. + */ +static int acpi_bus_trim_one(struct acpi_device *adev, void *eject) { struct acpi_scan_handler *handler = adev->handler; + bool is_eject = *(bool *)eject; - acpi_dev_for_each_child_reverse(adev, acpi_bus_trim_one, NULL); + acpi_dev_for_each_child_reverse(adev, acpi_bus_trim_one, eject); adev->flags.match_driver = false; if (handler) { if (handler->detach) handler->detach(adev); - - adev->handler = NULL; } else { device_release_driver(&adev->dev); } @@ -265,7 +275,12 @@ static int acpi_bus_trim_one(struct acpi_device *adev, void *not_used) */ acpi_device_set_power(adev, ACPI_STATE_D3_COLD); adev->flags.initialized = false; - acpi_device_clear_enumerated(adev); + + /* For eject this is deferred to acpi_bus_post_eject() */ + if (!is_eject) { + adev->handler = NULL; + acpi_device_clear_enumerated(adev); + } return 0; } @@ -278,15 +293,36 @@ static int acpi_bus_trim_one(struct acpi_device *adev, void *not_used) */ void acpi_bus_trim(struct acpi_device *adev) { - acpi_bus_trim_one(adev, NULL); + bool eject = false; + + acpi_bus_trim_one(adev, &eject); } EXPORT_SYMBOL_GPL(acpi_bus_trim); +static int acpi_bus_post_eject(struct acpi_device *adev, void *not_used) +{ + struct acpi_scan_handler *handler = adev->handler; + + acpi_dev_for_each_child_reverse(adev, acpi_bus_post_eject, NULL); + + if (handler) { + if (handler->post_eject) + handler->post_eject(adev); + + adev->handler = NULL; + } + + acpi_device_clear_enumerated(adev); + + return 0; +} + static int acpi_scan_hot_remove(struct acpi_device *device) { acpi_handle handle = device->handle; unsigned long long sta; acpi_status status; + bool eject = true; if (device->handler && device->handler->hotplug.demand_offline) { if (!acpi_scan_is_offline(device, true)) @@ -299,7 +335,7 @@ static int acpi_scan_hot_remove(struct acpi_device *device) acpi_handle_debug(handle, "Ejecting\n"); - acpi_bus_trim(device); + acpi_bus_trim_one(device, &eject); acpi_evaluate_lck(handle, 0); /* @@ -322,6 +358,8 @@ static int acpi_scan_hot_remove(struct acpi_device *device) } else if (sta & ACPI_STA_DEVICE_ENABLED) { acpi_handle_warn(handle, "Eject incomplete - status 0x%llx\n", sta); + } else { + acpi_bus_post_eject(device, NULL); } return 0; diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index d9c20ae23b..a23b352e13 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -127,6 +127,7 @@ struct acpi_scan_handler { bool (*match)(const char *idstr, const struct acpi_device_id **matchid); int (*attach)(struct acpi_device *dev, const struct acpi_device_id *id); void (*detach)(struct acpi_device *dev); + void (*post_eject)(struct acpi_device *dev); void (*bind)(struct device *phys_dev); void (*unbind)(struct device *phys_dev); struct acpi_hotplug_profile hotplug; -- Gitee From d9176b8e4eacdd05bc1c2e4390ea79dcdca01c39 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Wed, 23 Jul 2025 15:02:39 +0800 Subject: [PATCH 092/155] ACPI: convert acpi_processor_post_eject() to use IS_ENABLED() Rather than ifdef'ing acpi_processor_post_eject() and its use site, use IS_ENABLED() to increase compile coverage. Mainline: NA (cherry picked form openEuler/OLK6.6 commit 3673ebef197d554fb582d5ac9db301814cd617c5) Signed-off-by: Russell King (Oracle) Reviewed-by: Jonathan Cameron Signed-off-by: Li Wei Backported-by: Wu Chen Signed-off-by: Wang Yinfeng Change-Id: Ifb0fbe428f31d9b0076083fd6f3d0ff88421c335 --- drivers/acpi/acpi_processor.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c index 9d9a234582..fc13e83c08 100644 --- a/drivers/acpi/acpi_processor.c +++ b/drivers/acpi/acpi_processor.c @@ -458,12 +458,14 @@ static int acpi_processor_add(struct acpi_device *device, return result; } -#ifdef CONFIG_ACPI_HOTPLUG_PRESENT_CPU /* Removal */ static void acpi_processor_post_eject(struct acpi_device *device) { struct acpi_processor *pr; + if (!IS_ENABLED(CONFIG_ACPI_HOTPLUG_PRESENT_CPU)) + return; + if (!device || !acpi_driver_data(device)) return; @@ -502,7 +504,6 @@ static void acpi_processor_post_eject(struct acpi_device *device) free_cpumask_var(pr->throttling.shared_cpu_map); kfree(pr); } -#endif /* CONFIG_ACPI_HOTPLUG_PRESENT_CPU */ #ifdef CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC bool __init processor_physically_present(acpi_handle handle) @@ -627,9 +628,7 @@ static const struct acpi_device_id processor_device_ids[] = { static struct acpi_scan_handler processor_handler = { .ids = processor_device_ids, .attach = acpi_processor_add, -#ifdef CONFIG_ACPI_HOTPLUG_PRESENT_CPU .post_eject = acpi_processor_post_eject, -#endif .hotplug = { .enabled = true, }, -- Gitee From 1035ddc263837c8e4110d7975aed87307b0eaf38 Mon Sep 17 00:00:00 2001 From: James Morse Date: Wed, 23 Jul 2025 15:04:31 +0800 Subject: [PATCH 093/155] ACPI: Check _STA present bit before making CPUs not present When called acpi_processor_post_eject() unconditionally make a CPU not-present and unregisters it. To add support for AML events where the CPU has become disabled, but remains present, the _STA method should be checked before calling acpi_processor_remove(). Rename acpi_processor_post_eject() acpi_processor_remove_possible(), and check the _STA before calling. Adding the function prototype for arch_unregister_cpu() allows the preprocessor guards to be removed. After this change CPUs will remain registered and visible to user-space as offline if buggy firmware triggers an eject-request, but doesn't clear the corresponding _STA bits after _EJ0 has been called. Mainline: NA (cherry picked form OLK-6.6commit 1139eab2a0091f9704cb35548a4b13b35cc8efe4) Signed-off-by: James Morse Tested-by: Miguel Luis Tested-by: Vishnu Pajjuri Tested-by: Jianyong Wu Reviewed-by: Jonathan Cameron Signed-off-by: Li Wei Backpord-by: Wu Chen Signed-off-by: Wang Yinfeng Change-Id: I54a489fc1c66cb9eb66ec4c3a51f53f56e451a8c --- drivers/acpi/acpi_processor.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c index fc13e83c08..537c60f5f8 100644 --- a/drivers/acpi/acpi_processor.c +++ b/drivers/acpi/acpi_processor.c @@ -459,16 +459,13 @@ static int acpi_processor_add(struct acpi_device *device, } /* Removal */ -static void acpi_processor_post_eject(struct acpi_device *device) +static void acpi_processor_make_not_present(struct acpi_device *device) { struct acpi_processor *pr; if (!IS_ENABLED(CONFIG_ACPI_HOTPLUG_PRESENT_CPU)) return; - if (!device || !acpi_driver_data(device)) - return; - pr = acpi_driver_data(device); if (pr->id >= nr_cpu_ids) goto out; @@ -505,6 +502,29 @@ static void acpi_processor_post_eject(struct acpi_device *device) kfree(pr); } +static void acpi_processor_post_eject(struct acpi_device *device) +{ + struct acpi_processor *pr; + unsigned long long sta; + acpi_status status; + + if (!device) + return; + + pr = acpi_driver_data(device); + if (!pr || pr->id >= nr_cpu_ids || invalid_phys_cpuid(pr->phys_id)) + return; + + status = acpi_evaluate_integer(pr->handle, "_STA", NULL, &sta); + if (ACPI_FAILURE(status)) + return; + + if (cpu_present(pr->id) && !(sta & ACPI_STA_DEVICE_PRESENT)) { + acpi_processor_make_not_present(device); + return; + } +} + #ifdef CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC bool __init processor_physically_present(acpi_handle handle) { -- Gitee From 30b2ec13adf704a91133b261c659c503710fcdc8 Mon Sep 17 00:00:00 2001 From: James Morse Date: Wed, 23 Jul 2025 15:06:53 +0800 Subject: [PATCH 094/155] ACPI: Warn when the present bit changes but the feature is not enabled ACPI firmware can trigger the events to add and remove CPUs, but the OS may not support this. Print an error message when this happens. This gives early warning on arm64 systems that don't support CONFIG_ACPI_HOTPLUG_PRESENT_CPU, as making CPUs not present has side effects for other parts of the system. Mainline: NA (cherry picked form openEuler/OLK-6.6 commit ce7c338ade724554a4a3e1ca2394672214387866) Signed-off-by: James Morse Reviewed-by: Jonathan Cameron Reviewed-by: Gavin Shan Tested-by: Miguel Luis Tested-by: Vishnu Pajjuri Tested-by: Jianyong Wu Signed-off-by: Russell King (Oracle) Signed-off-by: Li Wei Backported-by: Wu Chen Signed-off-by: Wang Yinfeng Change-Id: Iacfb854e3b6ff5a6effc361700d7b4e6218036a2 --- drivers/acpi/acpi_processor.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c index 537c60f5f8..ba2cea7c12 100644 --- a/drivers/acpi/acpi_processor.c +++ b/drivers/acpi/acpi_processor.c @@ -189,8 +189,10 @@ static int acpi_processor_make_present(struct acpi_processor *pr) acpi_status status; int ret; - if (!IS_ENABLED(CONFIG_ACPI_HOTPLUG_PRESENT_CPU)) + if (!IS_ENABLED(CONFIG_ACPI_HOTPLUG_PRESENT_CPU)) { + pr_err_once("Changing CPU present bit is not supported\n"); return -ENODEV; + } if (invalid_phys_cpuid(pr->phys_id)) return -ENODEV; @@ -463,8 +465,10 @@ static void acpi_processor_make_not_present(struct acpi_device *device) { struct acpi_processor *pr; - if (!IS_ENABLED(CONFIG_ACPI_HOTPLUG_PRESENT_CPU)) + if (!IS_ENABLED(CONFIG_ACPI_HOTPLUG_PRESENT_CPU)) { + pr_err_once("Changing CPU present bit is not supported"); return; + } pr = acpi_driver_data(device); if (pr->id >= nr_cpu_ids) -- Gitee From 79da15679395a69372b5d624a1eb0a9682b3924f Mon Sep 17 00:00:00 2001 From: James Morse Date: Wed, 23 Jul 2025 15:10:15 +0800 Subject: [PATCH 095/155] ACPICA: Add new MADT GICC flags fields Add the new flag field to the MADT's GICC structure. 'Online Capable' indicates a disabled CPU can be enabled later. See ACPI specification 6.5 Tabel 5.37: GICC CPU Interface Flags. Mainline: NA (cherry picked form openEuler/OLK-6.6 commit a0252e9aec9c5b72de43948617c06b586238826b) Signed-off-by: James Morse Tested-by: Miguel Luis Tested-by: Vishnu Pajjuri Tested-by: Jianyong Wu Signed-off-by: Russell King (Oracle) Signed-off-by: Li Wei Backported-by: Wu Chen Signed-off-by: Wang Yinfeng Change-Id: I92fcca98cbbcda4415263469e48800d05cee73a1 --- include/acpi/actbl2.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/acpi/actbl2.h b/include/acpi/actbl2.h index 3751ae6943..c433a079d8 100644 --- a/include/acpi/actbl2.h +++ b/include/acpi/actbl2.h @@ -1046,6 +1046,7 @@ struct acpi_madt_generic_interrupt { /* ACPI_MADT_ENABLED (1) Processor is usable if set */ #define ACPI_MADT_PERFORMANCE_IRQ_MODE (1<<1) /* 01: Performance Interrupt Mode */ #define ACPI_MADT_VGIC_IRQ_MODE (1<<2) /* 02: VGIC Maintenance Interrupt mode */ +#define ACPI_MADT_GICC_CPU_CAPABLE (1<<3) /* 03: CPU is online capable */ /* 12: Generic Distributor (ACPI 5.0 + ACPI 6.0 changes) */ -- Gitee From e179e30ef7474a123b2ec22d34d2864cfab10d16 Mon Sep 17 00:00:00 2001 From: James Morse Date: Wed, 23 Jul 2025 15:11:27 +0800 Subject: [PATCH 096/155] irqchip/gic-v3: Don't return errors from gic_acpi_match_gicc() gic_acpi_match_gicc() is only called via gic_acpi_count_gicr_regions(). It should only count the number of enabled redistributors, but it also tries to sanity check the GICC entry, currently returning an error if the Enabled bit is set, but the gicr_base_address is zero. Adding support for the online-capable bit to the sanity check complicates it, for no benefit. The existing check implicitly depends on gic_acpi_count_gicr_regions() previous failing to find any GICR regions (as it is valid to have gicr_base_address of zero if the redistributors are described via a GICR entry). Instead of complicating the check, remove it. Failures that happen at this point cause the irqchip not to register, meaning no irqs can be requested. The kernel grinds to a panic() pretty quickly. Without the check, MADT tables that exhibit this problem are still caught by gic_populate_rdist(), which helpfully also prints what went wrong: | CPU4: mpidr 100 has no re-distributor! Mainline: NA (cherry picked form openEuler/OLK-6.6 commit 5020c22c488eb952b5d24151457385da4f0f283d) Signed-off-by: James Morse Reviewed-by: Gavin Shan Tested-by: Miguel Luis Tested-by: Vishnu Pajjuri Tested-by: Jianyong Wu Signed-off-by: Russell King (Oracle) Signed-off-by: Li Wei Backported-by: Wu Chen Signed-off-by: Wang Yinfeng Change-Id: I2eb7a0a287f98b3483359ebf2224540116d0e3f6 --- drivers/irqchip/irq-gic-v3.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index db6eae5676..7bd3c2cf8f 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -2435,21 +2435,15 @@ static int __init gic_acpi_match_gicc(union acpi_subtable_headers *header, /* * If GICC is enabled and has valid gicr base address, then it means - * GICR base is presented via GICC + * GICR base is presented via GICC. The redistributor is only known to + * be accessible if the GICC is marked as enabled. If this bit is not + * set, we'd need to add the redistributor at runtime, which isn't + * supported. */ - if (acpi_gicc_is_usable(gicc) && gicc->gicr_base_address) { + if (gicc->flags & ACPI_MADT_ENABLED && gicc->gicr_base_address) acpi_data.enabled_rdists++; - return 0; - } - /* - * It's perfectly valid firmware can pass disabled GICC entry, driver - * should not treat as errors, skip the entry instead of probe fail. - */ - if (!acpi_gicc_is_usable(gicc)) - return 0; - - return -ENODEV; + return 0; } static int __init gic_acpi_count_gicr_regions(void) -- Gitee From 9a5051b1c2890d7e1a397294c94162b38b8a14b4 Mon Sep 17 00:00:00 2001 From: James Morse Date: Wed, 23 Jul 2025 15:13:56 +0800 Subject: [PATCH 097/155] irqchip/gic-v3: Add support for ACPI's disabled but 'online capable' CPUs To support virtual CPU hotplug, ACPI has added an 'online capable' bit to the MADT GICC entries. This indicates a disabled CPU entry may not be possible to online via PSCI until firmware has set enabled bit in _STA. What about the redistributor in the GICC entry? ACPI doesn't want to say. Assume the worst: When a redistributor is described in the GICC entry, but the entry is marked as disabled at boot, assume the redistributor is inaccessible. The GICv3 driver doesn't support late online of redistributors, so this means the corresponding CPU can't be brought online either. Clear the possible and present bits. Systems that want CPU hotplug in a VM can ensure their redistributors are always-on, and describe them that way with a GICR entry in the MADT. When mapping redistributors found via GICC entries, handle the case where the arch code believes the CPU is present and possible, but it does not have an accessible redistributor. Print a warning and clear the present and possible bits. Mainline: NA (cherry picked form openEuler/OLK-6.6 commit af957c26262bf1f75d075d3b292c9a08be8bd6a5) Signed-off-by: James Morse Tested-by: Miguel Luis Tested-by: Vishnu Pajjuri Tested-by: Jianyong Wu Signed-off-by: Russell King (Oracle) Backported-by: Wu Chen Signed-off-by: Wang Yinfeng Change-Id: I12d2e02666840a4d83921f8bd70dc906abd6e402 --- drivers/irqchip/irq-gic-v3.c | 14 ++++++++++++++ include/linux/acpi.h | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index 7bd3c2cf8f..c4b021919c 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -2385,11 +2385,25 @@ gic_acpi_parse_madt_gicc(union acpi_subtable_headers *header, (struct acpi_madt_generic_interrupt *)header; u32 reg = readl_relaxed(acpi_data.dist_base + GICD_PIDR2) & GIC_PIDR2_ARCH_MASK; u32 size = reg == GIC_PIDR2_ARCH_GICv4 ? SZ_64K * 4 : SZ_64K * 2; + int cpu = get_cpu_for_acpi_id(gicc->uid); void __iomem *redist_base; if (!acpi_gicc_is_usable(gicc)) return 0; + /* + * Capable but disabled CPUs can be brought online later. What about + * the redistributor? ACPI doesn't want to say! + * Virtual hotplug systems can use the MADT's "always-on" GICR entries. + * Otherwise, prevent such CPUs from being brought online. + */ + if (!(gicc->flags & ACPI_MADT_ENABLED)) { + pr_warn_once("CPU %u inaccessible: can't brought\n", cpu); + set_cpu_present(cpu, false); + set_cpu_possible(cpu, false); + return 0; + } + redist_base = ioremap(gicc->gicr_base_address, size); if (!redist_base) return -ENOMEM; diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 42b993e771..290b490e21 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -258,7 +258,7 @@ void acpi_table_print_madt_entry (struct acpi_subtable_header *madt); static inline bool acpi_gicc_is_usable(struct acpi_madt_generic_interrupt *gicc) { - return gicc->flags & ACPI_MADT_ENABLED; + return gicc->flags & (ACPI_MADT_ENABLED | ACPI_MADT_GICC_CPU_CAPABLE); } /* the following numa functions are architecture-dependent */ -- Gitee From da3b6a46b572f107d236bf2e8d0c4d03297bc409 Mon Sep 17 00:00:00 2001 From: James Morse Date: Wed, 23 Jul 2025 15:22:13 +0800 Subject: [PATCH 098/155] arm64/psci: Ignore DENIED CPUs When a CPU is marked as disabled, but online capable in the MADT, PSCI applies some firmware policy to control when it can be brought online. PSCI returns DENIED to a CPU_ON request if this is not currently permitted. The OS can learn the current policy from the _STA enabled bit. Handle the PSCI DENIED return code gracefully instead of printing an error. See https://developer.arm.com/documentation/den0022/f/?lang=en page 58. Mainline: NA (cherry picked form openEuler/OLK-6.6 commit e7779096cd4f101a4339b166de004c4469f98377) Signed-off-by: Jean-Philippe Brucker [ morse: Rewrote commit message ] Signed-off-by: James Morse Tested-by: Miguel Luis Tested-by: Vishnu Pajjuri Tested-by: Jianyong Wu Signed-off-by: Russell King (Oracle) Reviewed-by: Jonathan Cameron Signed-off-by: Li Wei Backported-by: Wu Chen Signed-off-by: Wang Yinfeng Change-Id: Ia15bf08b9ac4e7dc214f3b22f00f6be3e7dc0049 --- arch/arm64/kernel/psci.c | 2 +- arch/arm64/kernel/smp.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/arm64/kernel/psci.c b/arch/arm64/kernel/psci.c index 29a8e444db..fabd732d0a 100644 --- a/arch/arm64/kernel/psci.c +++ b/arch/arm64/kernel/psci.c @@ -40,7 +40,7 @@ static int cpu_psci_cpu_boot(unsigned int cpu) { phys_addr_t pa_secondary_entry = __pa_symbol(secondary_entry); int err = psci_ops.cpu_on(cpu_logical_map(cpu), pa_secondary_entry); - if (err) + if (err && err != -EPERM) pr_err("failed to boot CPU%d (%d)\n", cpu, err); return err; diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c index 4a13c5376d..0f7f374a0f 100644 --- a/arch/arm64/kernel/smp.c +++ b/arch/arm64/kernel/smp.c @@ -124,7 +124,8 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle) /* Now bring the CPU into our world */ ret = boot_secondary(cpu, idle); if (ret) { - pr_err("CPU%u: failed to boot: %d\n", cpu, ret); + if (ret != -EPERM) + pr_err("CPU%u: failed to boot: %d\n", cpu, ret); return ret; } -- Gitee From 0a80c5ed4bf5c3346180fd090074c5d43527d601 Mon Sep 17 00:00:00 2001 From: James Morse Date: Wed, 23 Jul 2025 15:24:57 +0800 Subject: [PATCH 099/155] ACPI: add support to register CPUs based on the _STA enabled bit acpi_processor_get_info() registers all present CPUs. Registering a CPU is what creates the sysfs entries and triggers the udev notifications. arm64 virtual machines that support 'virtual cpu hotplug' use the enabled bit to indicate whether the CPU can be brought online, as the existing ACPI tables require all hardware to be described and present. If firmware describes a CPU as present, but disabled, skip the registration. Such CPUs are present, but can't be brought online for whatever reason. (e.g. firmware/hypervisor policy). Once firmware sets the enabled bit, the CPU can be registered and brought online by user-space. Online CPUs, or CPUs that are missing an _STA method must always be registered. Mainline: NA (cherry picked form openEuler/OLK-6.6 commit 901942263f476b53dfc92fa5ce9f6627f671f728) Signed-off-by: James Morse Reviewed-by: Gavin Shan Reviewed-by: Jonathan Cameron Tested-by: Miguel Luis Tested-by: Vishnu Pajjuri Tested-by: Jianyong Wu Signed-off-by: Russell King (Oracle) Signed-off-by: Li Wei Backported-by: Wu Chen Signed-off-by: Wang Yinfeng Change-Id: I517ee1607e9bea983df995b18b2b35b47142d15e --- drivers/acpi/acpi_processor.c | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c index ba2cea7c12..6447ad1aaf 100644 --- a/drivers/acpi/acpi_processor.c +++ b/drivers/acpi/acpi_processor.c @@ -228,6 +228,32 @@ static int acpi_processor_make_present(struct acpi_processor *pr) return ret; } +static int acpi_processor_make_enabled(struct acpi_processor *pr) +{ + unsigned long long sta; + acpi_status status; + bool present, enabled; + + if (!acpi_has_method(pr->handle, "_STA")) + return arch_register_cpu(pr->id); + + status = acpi_evaluate_integer(pr->handle, "_STA", NULL, &sta); + if (ACPI_FAILURE(status)) + return -ENODEV; + + present = sta & ACPI_STA_DEVICE_PRESENT; + enabled = sta & ACPI_STA_DEVICE_ENABLED; + + if (cpu_online(pr->id) && (!present || !enabled)) { + pr_err_once(FW_BUG "CPU %u online, disabled!\n", pr->id); + add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK); + } else if (!present || !enabled) { + return -ENODEV; + } + + return arch_register_cpu(pr->id); +} + static int acpi_processor_get_info(struct acpi_device *device) { union acpi_object object = { 0 }; @@ -318,7 +344,7 @@ static int acpi_processor_get_info(struct acpi_device *device) */ if (!invalid_logical_cpuid(pr->id) && cpu_present(pr->id) && !get_cpu_device(pr->id)) { - int ret = arch_register_cpu(pr->id); + int ret = acpi_processor_make_enabled(pr); if (ret) return ret; @@ -527,6 +553,9 @@ static void acpi_processor_post_eject(struct acpi_device *device) acpi_processor_make_not_present(device); return; } + + if (cpu_present(pr->id) && !(sta & ACPI_STA_DEVICE_ENABLED)) + arch_unregister_cpu(pr->id); } #ifdef CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC -- Gitee From 8b6dbad76d0e57bd210a7c4a3047de3ac64bbdc3 Mon Sep 17 00:00:00 2001 From: James Morse Date: Wed, 23 Jul 2025 15:27:01 +0800 Subject: [PATCH 100/155] ACPI/processor: Only call arch_unregister_cpu() if HOTPLUG_CPU is selected The kbuild robot points out that configurations without HOTPLUG_CPU selected can try to build acpi_processor_post_eject() without success as arch_unregister_cpu() is not defined. Check this explicitly. This will be merged into:ACPI: Add post_eject to struct acpi_scan_handler for cpu hotplug for any subsequent posting. Mainline: NA (cherry picked form openEuler/OLK-6.6 commit 8d20f189c3e31b501050957edb9c649322072d8a) Reported-by: kbuild test robot Signed-off-by: James Morse Tested-by: Miguel Luis Tested-by: Vishnu Pajjuri Tested-by: Jianyong Wu Reviewed-by: Jonathan Cameron Signed-off-by: Li Wei Backported-by: Wu Chen Signed-off-by: Wang Yinfeng Change-Id: I1a292b68ef123121779e075f104778e74b585cda --- drivers/acpi/acpi_processor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c index 6447ad1aaf..c1847954b4 100644 --- a/drivers/acpi/acpi_processor.c +++ b/drivers/acpi/acpi_processor.c @@ -538,7 +538,7 @@ static void acpi_processor_post_eject(struct acpi_device *device) unsigned long long sta; acpi_status status; - if (!device) + if (!IS_ENABLED(CONFIG_HOTPLUG_CPU) || !device) return; pr = acpi_driver_data(device); -- Gitee From 261e991757e39fef89124837905f8f72343551b7 Mon Sep 17 00:00:00 2001 From: James Morse Date: Wed, 23 Jul 2025 15:28:05 +0800 Subject: [PATCH 101/155] arm64: Document virtual CPU hotplug's expectations Add a description of physical and virtual CPU hotplug, explain the differences and elaborate on what is required in ACPI for a working virtual hotplug system. Mainline: NA (cherry picked form openEuler/OLK-6.6 commit 308c37e9d96cb85fe9ac0445ca58e73af7f0acc8) Signed-off-by: James Morse Reviewed-by: Jonathan Cameron Signed-off-by: Li Wei Backported-by: Wu Chen Signed-off-by: Wang Yinfeng Change-Id: I649eb7a06ec2faddfb3eaa10b7d8fa3e447e68d4 --- Documentation/arch/arm64/cpu-hotplug.rst | 79 ++++++++++++++++++++++++ Documentation/arch/arm64/index.rst | 1 + MAINTAINERS | 1 + 3 files changed, 81 insertions(+) create mode 100644 Documentation/arch/arm64/cpu-hotplug.rst diff --git a/Documentation/arch/arm64/cpu-hotplug.rst b/Documentation/arch/arm64/cpu-hotplug.rst new file mode 100644 index 0000000000..76ba8d932c --- /dev/null +++ b/Documentation/arch/arm64/cpu-hotplug.rst @@ -0,0 +1,79 @@ +.. SPDX-License-Identifier: GPL-2.0 +.. _cpuhp_index: + +==================== +CPU Hotplug and ACPI +==================== + +CPU hotplug in the arm64 world is commonly used to describe the kernel taking +CPUs online/offline using PSCI. This document is about ACPI firmware allowing +CPUs that were not available during boot to be added to the system later. + +``possible`` and ``present`` refer to the state of the CPU as seen by linux. + + +CPU Hotplug on physical systems - CPUs not present at boot +---------------------------------------------------------- + +Physical systems need to mark a CPU that is ``possible`` but not ``present`` as +being ``present``. An example would be a dual socket machine, where the package +in one of the sockets can be replaced while the system is running. + +This is not supported. + +In the arm64 world CPUs are not a single device but a slice of the system. +There are no systems that support the physical addition (or removal) of CPUs +while the system is running, and ACPI is not able to sufficiently describe +them. + +e.g. New CPUs come with new caches, but the platform's cache toplogy is +described in a static table, the PPTT. How caches are shared between CPUs is +not discoverable, and must be described by firmware. + +e.g. The GIC redistributor for each CPU must be accessed by the driver during +boot to discover the system wide supported features. ACPI's MADT GICC +structures can describe a redistributor associated with a disabled CPU, but +can't describe whether the redistributor is accessible, only that it is not +'always on'. + +arm64's ACPI tables assume that everything described is ``present``. + + +CPU Hotplug on virtual systems - CPUs not enabled at boot +--------------------------------------------------------- + +Virtual systems have the advantage that all the properties the system will +ever have can be described at boot. There are no power-domain considerations +as such devices are emulated. + +CPU Hotplug on virtual systems is supported. It is distinct from physical +CPU Hotplug as all resources are described as ``present``, but CPUs may be +marked as disabled by firmware. Only the CPU's online/offline behaviour is +influenced by firmware. An example is where a virtual machine boots with a +single CPU, and additional CPUs are added once a cloud orchestrator deploys +the workload. + +For a virtual machine, the VMM (e.g. Qemu) plays the part of firmware. + +Virtual hotplug is implemented as a firmware policy affecting which CPUs can be +brought online. Firmware can enforce its policy via PSCI's return codes. e.g. +``DENIED``. + +The ACPI tables must describe all the resources of the virtual machine. CPUs +that firmware wishes to disable either from boot (or later) should not be +``enabled`` in the MADT GICC structures, but should have the ``online capable`` +bit set, to indicate they can be enabled later. The boot CPU must be marked as +``enabled``. The 'always on' GICR structure must be used to describe the +redistributors. + +CPUs described as ``online capable`` but not ``enabled`` can be set to enabled +by the DSDT's Processor object's _STA method. On virtual systems the _STA method +must always report the CPU as ``present``. Changes to the firmware policy can +be notified to the OS via device-check or eject-request. + +CPUs described as ``enabled`` in the static table, should not have their _STA +modified dynamically by firmware. Soft-restart features such as kexec will +re-read the static properties of the system from these static tables, and +may malfunction if these no longer describe the running system. Linux will +re-discover the dynamic properties of the system from the _STA method later +during boot. diff --git a/Documentation/arch/arm64/index.rst b/Documentation/arch/arm64/index.rst index d08e924204..78544de0a8 100644 --- a/Documentation/arch/arm64/index.rst +++ b/Documentation/arch/arm64/index.rst @@ -13,6 +13,7 @@ ARM64 Architecture asymmetric-32bit booting cpu-feature-registers + cpu-hotplug elf_hwcaps hugetlbpage kdump diff --git a/MAINTAINERS b/MAINTAINERS index 265e08b32d..ccc65f30a9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -17429,6 +17429,7 @@ ARM/PHYTIUM SOC SUPPORT M: Wang Yinfeng S: Maintained W: https://www.phytium.com.cn +F: Documentation/arch/arm64/cpu-hotplug.rst F: Documentation/devicetree/bindings/dma/phytium,ddma.yaml F: Documentation/devicetree/bindings/dma/phytium,gdma.yaml F: Documentation/devicetree/bindings/edac/phytium-pe220x-edac.txt -- Gitee From 0b96cf215d7b60887b8493c05a6ffdf410a463ef Mon Sep 17 00:00:00 2001 From: James Morse Date: Wed, 23 Jul 2025 15:30:22 +0800 Subject: [PATCH 102/155] ACPI: Add _OSC bits to advertise OS support toggling CPU present/enabled Platform firmware can disabled a CPU, or make it not-present by making an eject-request notification, then waiting for the os to make it offline and call _EJx. After the firmware updates _STA with the new status. Not all operating systems support this. For arm64 making CPUs not-present has never been supported. For all ACPI architectures, making CPUs disabled has recently been added. Firmware can't know what the OS has support for. Add two new _OSC bits to advertise whether the OS supports the _STA enabled or present bits being toggled for CPUs. This will be important for arm64 if systems that support physical CPU hotplug ever appear as arm64 linux doesn't currently support this, so firmware shouldn't try. Advertising this support to firmware is useful for cloud orchestrators to know whether they can scale a particular VM by adding CPUs. Mainline: NA (cherry picked and rework form openEuler/OLK-6.6 commit 362f33cba6a04a09bcfc47ade55ace95e8a51c5b) Signed-off-by: James Morse Tested-by: Miguel Luis Tested-by: Vishnu Pajjuri Tested-by: Jianyong Wu Signed-off-by: Li Wei Backported-by: Wu Chen Signed-off-by: Wang Yinfeng Change-Id: Ib6e8a702b12d29f80e6eb2746988aae17b1bcffc --- drivers/acpi/Kconfig | 9 +++++++++ drivers/acpi/acpi_processor.c | 14 +++++++++++++- drivers/acpi/bus.c | 16 ++++++++++++++++ include/linux/acpi.h | 4 ++++ 4 files changed, 42 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 417f9f3077..c49978b4b1 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -310,6 +310,15 @@ config ACPI_HOTPLUG_PRESENT_CPU depends on ACPI_PROCESSOR && HOTPLUG_CPU select ACPI_CONTAINER +config ACPI_HOTPLUG_IGNORE_OSC + bool + depends on ACPI_HOTPLUG_PRESENT_CPU + help + Ignore whether firmware acknowledged support for toggling the CPU + present bit in _STA. Some architectures predate the _OSC bits, so + firmware doesn't know to do this. + + config ACPI_PROCESSOR_AGGREGATOR tristate "Processor Aggregator" depends on ACPI_PROCESSOR diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c index c1847954b4..a2675745ed 100644 --- a/drivers/acpi/acpi_processor.c +++ b/drivers/acpi/acpi_processor.c @@ -182,6 +182,18 @@ static void __init acpi_pcc_cpufreq_init(void) static void __init acpi_pcc_cpufreq_init(void) {} #endif /* CONFIG_X86 */ +static bool acpi_processor_hotplug_present_supported(void) +{ + if (!IS_ENABLED(CONFIG_ACPI_HOTPLUG_PRESENT_CPU)) + return false; + + /* x86 systems pre-date the _OSC bit */ + if (IS_ENABLED(CONFIG_ACPI_HOTPLUG_IGNORE_OSC)) + return true; + + return osc_sb_hotplug_present_support_acked; +} + /* Initialization */ static int acpi_processor_make_present(struct acpi_processor *pr) { @@ -189,7 +201,7 @@ static int acpi_processor_make_present(struct acpi_processor *pr) acpi_status status; int ret; - if (!IS_ENABLED(CONFIG_ACPI_HOTPLUG_PRESENT_CPU)) { + if (!acpi_processor_hotplug_present_supported()) { pr_err_once("Changing CPU present bit is not supported\n"); return -ENODEV; } diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index a4aa53b7e2..b42f17bfbb 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -298,6 +298,13 @@ EXPORT_SYMBOL_GPL(osc_sb_native_usb4_support_confirmed); bool osc_sb_cppc2_support_acked; +/* + * ACPI 6.? Proposed Operating System Capabilities for modifying CPU + * present/enable. + */ +bool osc_sb_hotplug_enabled_support_acked; +bool osc_sb_hotplug_present_support_acked; + static u8 sb_uuid_str[] = "0811B06E-4A27-44F9-8D60-3CBBC22E7B48"; static void acpi_bus_osc_negotiate_platform_control(void) { @@ -346,6 +353,11 @@ static void acpi_bus_osc_negotiate_platform_control(void) if (!ghes_disable) capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_APEI_SUPPORT; + + capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_HOTPLUG_ENABLED_SUPPORT; + if (IS_ENABLED(CONFIG_ACPI_HOTPLUG_PRESENT_CPU)) + capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_HOTPLUG_PRESENT_SUPPORT; + if (ACPI_FAILURE(acpi_get_handle(NULL, "\\_SB", &handle))) return; @@ -383,6 +395,10 @@ static void acpi_bus_osc_negotiate_platform_control(void) capbuf_ret[OSC_SUPPORT_DWORD] & OSC_SB_NATIVE_USB4_SUPPORT; osc_cpc_flexible_adr_space_confirmed = capbuf_ret[OSC_SUPPORT_DWORD] & OSC_SB_CPC_FLEXIBLE_ADR_SPACE; + osc_sb_hotplug_enabled_support_acked = + capbuf_ret[OSC_SUPPORT_DWORD] & OSC_SB_HOTPLUG_ENABLED_SUPPORT; + osc_sb_hotplug_present_support_acked = + capbuf_ret[OSC_SUPPORT_DWORD] & OSC_SB_HOTPLUG_PRESENT_SUPPORT; } kfree(context.ret.pointer); diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 290b490e21..d5b38e4f12 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -591,12 +591,16 @@ acpi_status acpi_run_osc(acpi_handle handle, struct acpi_osc_context *context); #define OSC_SB_NATIVE_USB4_SUPPORT 0x00040000 #define OSC_SB_PRM_SUPPORT 0x00200000 #define OSC_SB_FFH_OPR_SUPPORT 0x00400000 +#define OSC_SB_HOTPLUG_ENABLED_SUPPORT 0x00800000 +#define OSC_SB_HOTPLUG_PRESENT_SUPPORT 0x01000000 extern bool osc_sb_apei_support_acked; extern bool osc_pc_lpi_support_confirmed; extern bool osc_sb_native_usb4_support_confirmed; extern bool osc_sb_cppc2_support_acked; extern bool osc_cpc_flexible_adr_space_confirmed; +extern bool osc_sb_hotplug_enabled_support_acked; +extern bool osc_sb_hotplug_present_support_acked; /* USB4 Capabilities */ #define OSC_USB_USB3_TUNNELING 0x00000001 -- Gitee From 420614e40338ad6d86c51bd94a4e570c2d7ccb20 Mon Sep 17 00:00:00 2001 From: James Morse Date: Wed, 23 Jul 2025 15:31:13 +0800 Subject: [PATCH 103/155] cpumask: Add enabled cpumask for present CPUs that can brought online The 'offline' file in sysfs shows all offline CPUs, including those that aren't present. User-space is expected to remove not-present CPUs from this list to learn which CPUs could be brought online. CPUs can be present but not-enabled. These CPUs can't be brought online until the firmware policy changes, which comes with an ACPI notification that will register the CPUs. With only the offline and present files, user-space is unable to determine which CPUs it can try to bring online. Add a new CPU mask that shows this based on all the registered CPUs. Mainline: NA (cherry picked form openEuler/OLK-6.6 commit ba9a8ddad0e274edb55e041c82b953696bf568be) Signed-off-by: James Morse Tested-by: Miguel Luis Tested-by: Vishnu Pajjuri Tested-by: Jianyong Wu Acked-by: Thomas Gleixner Signed-off-by: Li Wei Backported-by: Wu Chen Signed-off-by: Wang Yinfeng Change-Id: Ia2d8e068e4b120b9c79af9a9423ed8b90f8b1b1d --- drivers/base/cpu.c | 10 ++++++++++ include/linux/cpumask.h | 25 +++++++++++++++++++++++++ kernel/cpu.c | 3 +++ 3 files changed, 38 insertions(+) diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index c39cc487d0..738d666122 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c @@ -95,6 +95,7 @@ void unregister_cpu(struct cpu *cpu) { int logical_cpu = cpu->dev.id; + set_cpu_enabled(logical_cpu, false); unregister_cpu_under_node(logical_cpu, cpu_to_node(logical_cpu)); device_unregister(&cpu->dev); @@ -273,6 +274,13 @@ static ssize_t print_cpus_offline(struct device *dev, } static DEVICE_ATTR(offline, 0444, print_cpus_offline, NULL); +static ssize_t print_cpus_enabled(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sysfs_emit(buf, "%*pbl\n", cpumask_pr_args(cpu_enabled_mask)); +} +static DEVICE_ATTR(enabled, 0444, print_cpus_enabled, NULL); + static ssize_t print_cpus_isolated(struct device *dev, struct device_attribute *attr, char *buf) { @@ -413,6 +421,7 @@ int register_cpu(struct cpu *cpu, int num) register_cpu_under_node(num, cpu_to_node(num)); dev_pm_qos_expose_latency_limit(&cpu->dev, PM_QOS_RESUME_LATENCY_NO_CONSTRAINT); + set_cpu_enabled(num, true); return 0; } @@ -494,6 +503,7 @@ static struct attribute *cpu_root_attrs[] = { &cpu_attrs[2].attr.attr, &dev_attr_kernel_max.attr, &dev_attr_offline.attr, + &dev_attr_enabled.attr, &dev_attr_isolated.attr, #ifdef CONFIG_NO_HZ_FULL &dev_attr_nohz_full.attr, diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h index dbdbf1451c..4c26ede3b8 100644 --- a/include/linux/cpumask.h +++ b/include/linux/cpumask.h @@ -92,6 +92,7 @@ static inline void set_nr_cpu_ids(unsigned int nr) * * cpu_possible_mask- has bit 'cpu' set iff cpu is populatable * cpu_present_mask - has bit 'cpu' set iff cpu is populated + * cpu_enabled_mask - has bit 'cpu' set iff cpu can be brought online * cpu_online_mask - has bit 'cpu' set iff cpu available to scheduler * cpu_active_mask - has bit 'cpu' set iff cpu available to migration * @@ -124,11 +125,13 @@ static inline void set_nr_cpu_ids(unsigned int nr) extern struct cpumask __cpu_possible_mask; extern struct cpumask __cpu_online_mask; +extern struct cpumask __cpu_enabled_mask; extern struct cpumask __cpu_present_mask; extern struct cpumask __cpu_active_mask; extern struct cpumask __cpu_dying_mask; #define cpu_possible_mask ((const struct cpumask *)&__cpu_possible_mask) #define cpu_online_mask ((const struct cpumask *)&__cpu_online_mask) +#define cpu_enabled_mask ((const struct cpumask *)&__cpu_enabled_mask) #define cpu_present_mask ((const struct cpumask *)&__cpu_present_mask) #define cpu_active_mask ((const struct cpumask *)&__cpu_active_mask) #define cpu_dying_mask ((const struct cpumask *)&__cpu_dying_mask) @@ -973,6 +976,7 @@ extern const DECLARE_BITMAP(cpu_all_bits, NR_CPUS); #else #define for_each_possible_cpu(cpu) for_each_cpu((cpu), cpu_possible_mask) #define for_each_online_cpu(cpu) for_each_cpu((cpu), cpu_online_mask) +#define for_each_enabled_cpu(cpu) for_each_cpu((cpu), cpu_enabled_mask) #define for_each_present_cpu(cpu) for_each_cpu((cpu), cpu_present_mask) #endif @@ -995,6 +999,15 @@ set_cpu_possible(unsigned int cpu, bool possible) cpumask_clear_cpu(cpu, &__cpu_possible_mask); } +static inline void +set_cpu_enabled(unsigned int cpu, bool can_be_onlined) +{ + if (can_be_onlined) + cpumask_set_cpu(cpu, &__cpu_enabled_mask); + else + cpumask_clear_cpu(cpu, &__cpu_enabled_mask); +} + static inline void set_cpu_present(unsigned int cpu, bool present) { @@ -1074,6 +1087,7 @@ static __always_inline unsigned int num_online_cpus(void) return raw_atomic_read(&__num_online_cpus); } #define num_possible_cpus() cpumask_weight(cpu_possible_mask) +#define num_enabled_cpus() cpumask_weight(cpu_enabled_mask) #define num_present_cpus() cpumask_weight(cpu_present_mask) #define num_active_cpus() cpumask_weight(cpu_active_mask) @@ -1082,6 +1096,11 @@ static inline bool cpu_online(unsigned int cpu) return cpumask_test_cpu(cpu, cpu_online_mask); } +static inline bool cpu_enabled(unsigned int cpu) +{ + return cpumask_test_cpu(cpu, cpu_enabled_mask); +} + static inline bool cpu_possible(unsigned int cpu) { return cpumask_test_cpu(cpu, cpu_possible_mask); @@ -1106,6 +1125,7 @@ static inline bool cpu_dying(unsigned int cpu) #define num_online_cpus() 1U #define num_possible_cpus() 1U +#define num_enabled_cpus() 1U #define num_present_cpus() 1U #define num_active_cpus() 1U @@ -1119,6 +1139,11 @@ static inline bool cpu_possible(unsigned int cpu) return cpu == 0; } +static inline bool cpu_enabled(unsigned int cpu) +{ + return cpu == 0; +} + static inline bool cpu_present(unsigned int cpu) { return cpu == 0; diff --git a/kernel/cpu.c b/kernel/cpu.c index 0c72b94ed0..d007c6a74c 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c @@ -3131,6 +3131,9 @@ EXPORT_SYMBOL(__cpu_possible_mask); struct cpumask __cpu_online_mask __read_mostly; EXPORT_SYMBOL(__cpu_online_mask); +struct cpumask __cpu_enabled_mask __read_mostly; +EXPORT_SYMBOL(__cpu_enabled_mask); + struct cpumask __cpu_present_mask __read_mostly; EXPORT_SYMBOL(__cpu_present_mask); -- Gitee From 4fef4ca255e724d0c0a392e1f129046ec3edfb9a Mon Sep 17 00:00:00 2001 From: Li Wei Date: Wed, 23 Jul 2025 15:34:00 +0800 Subject: [PATCH 104/155] arm64/psci: Add undefined error message printing for psci_x_cpu_on If the error code returned by the cpu_on interface is not -EPERM, no error information is printed. For instance, => res.a0 = PSCI_RET_DENIED (-3) => arm_smccc_hvc(function_id, arg0, arg1, arg2, 0, 0, 0, 0, &res) => invoke_psci_fn = __invoke_psci_fn_hvc => __psci_cpu_on(PSCI_FN_NATIVE(0_2, CPU_ON), cpuid, entry_point) => psci_0_2_cpu_on => cpu_psci_cpu_boot => bringup_cpu => cpuhp_invoke_callback => __cpuhp_invoke_callback_range => cpuhp_up_callbacks => cpu_up When the value of res.a0 is PSCI_RET_DENIED(-3), no information is displayed, indicating that the CPU fails to go online. Mainline: NA (cherry picked form openEuler/OLK-6.6 commit c5a9c0d2c8d8535dbee657bb5eff16a226405ebe) Signed-off-by: Li Wei Backported-by: Wu Chen Signed-off-by: Wang Yinfeng Change-Id: I828a89609f2d20cba26679a8d4c50b890deaec16 --- arch/arm64/kernel/psci.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/arch/arm64/kernel/psci.c b/arch/arm64/kernel/psci.c index fabd732d0a..48ff9dc812 100644 --- a/arch/arm64/kernel/psci.c +++ b/arch/arm64/kernel/psci.c @@ -40,8 +40,12 @@ static int cpu_psci_cpu_boot(unsigned int cpu) { phys_addr_t pa_secondary_entry = __pa_symbol(secondary_entry); int err = psci_ops.cpu_on(cpu_logical_map(cpu), pa_secondary_entry); - if (err && err != -EPERM) - pr_err("failed to boot CPU%d (%d)\n", cpu, err); + if (err) { + if (err != -EPERM) + pr_err("failed to boot CPU%d (%d)\n", cpu, err); + else + pr_err("psci feedback boot CPU%d result(%d) undefined\n", cpu, err); + } return err; } -- Gitee From 54904f57cd5e515cf6967c76effccd708d96f091 Mon Sep 17 00:00:00 2001 From: Li Wei Date: Wed, 23 Jul 2025 15:35:37 +0800 Subject: [PATCH 105/155] ACPI: Rename ACPI_HOTPLUG_CPU to include 'present' This reverts commit 2eb3daf61b18d620b0624e31ad44ac1c76d94075. To keep CONFIG unchanged, modify ACPI_HOTPLUG_PRESENT_CPU to ACPI_HOTPLUG_CPU. Conflicts: arch/x86/Kconfig drivers/acpi/acpi_processor.c include/linux/acpi.h Mainline: NA (cherry picked and rework form openEuler/OLK-6.6 commit 38098f83388c90c0f2bf4c98ec610642a057d46e) Signed-off-by: Li Wei Backported-by: Wu Chen Signed-off-by: Wang Yinfeng Change-Id: Iac2f9d483c58915eb7867ca9e18354db11c1c674 --- drivers/acpi/Kconfig | 6 +++--- drivers/acpi/acpi_processor.c | 4 ++-- drivers/acpi/bus.c | 2 +- include/linux/acpi.h | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index c49978b4b1..c4746869d6 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -305,14 +305,14 @@ config ACPI_IPMI To compile this driver as a module, choose M here: the module will be called as acpi_ipmi. -config ACPI_HOTPLUG_PRESENT_CPU +config ACPI_HOTPLUG_CPU bool depends on ACPI_PROCESSOR && HOTPLUG_CPU select ACPI_CONTAINER config ACPI_HOTPLUG_IGNORE_OSC bool - depends on ACPI_HOTPLUG_PRESENT_CPU + depends on ACPI_HOTPLUG_CPU help Ignore whether firmware acknowledged support for toggling the CPU present bit in _STA. Some architectures predate the _OSC bits, so @@ -408,7 +408,7 @@ config ACPI_PCI_SLOT config ACPI_CONTAINER bool "Container and Module Devices" - default (ACPI_HOTPLUG_MEMORY || ACPI_HOTPLUG_PRESENT_CPU) + default (ACPI_HOTPLUG_MEMORY || ACPI_HOTPLUG_CPU) help This driver supports ACPI Container and Module devices (IDs ACPI0004, PNP0A05, and PNP0A06). diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c index a2675745ed..1f886245aa 100644 --- a/drivers/acpi/acpi_processor.c +++ b/drivers/acpi/acpi_processor.c @@ -184,7 +184,7 @@ static void __init acpi_pcc_cpufreq_init(void) {} static bool acpi_processor_hotplug_present_supported(void) { - if (!IS_ENABLED(CONFIG_ACPI_HOTPLUG_PRESENT_CPU)) + if (!IS_ENABLED(CONFIG_ACPI_HOTPLUG_CPU)) return false; /* x86 systems pre-date the _OSC bit */ @@ -503,7 +503,7 @@ static void acpi_processor_make_not_present(struct acpi_device *device) { struct acpi_processor *pr; - if (!IS_ENABLED(CONFIG_ACPI_HOTPLUG_PRESENT_CPU)) { + if (!IS_ENABLED(CONFIG_ACPI_HOTPLUG_CPU)) { pr_err_once("Changing CPU present bit is not supported"); return; } diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index b42f17bfbb..0d2e1de143 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -355,7 +355,7 @@ static void acpi_bus_osc_negotiate_platform_control(void) capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_APEI_SUPPORT; capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_HOTPLUG_ENABLED_SUPPORT; - if (IS_ENABLED(CONFIG_ACPI_HOTPLUG_PRESENT_CPU)) + if (IS_ENABLED(CONFIG_ACPI_HOTPLUG_CPU)) capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_HOTPLUG_PRESENT_SUPPORT; if (ACPI_FAILURE(acpi_get_handle(NULL, "\\_SB", &handle))) diff --git a/include/linux/acpi.h b/include/linux/acpi.h index d5b38e4f12..1504c720c3 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -663,7 +663,7 @@ static inline u32 acpi_osc_ctx_get_cxl_control(struct acpi_osc_context *context) #define ACPI_GSB_ACCESS_ATTRIB_RAW_PROCESS 0x0000000F /* Enable _OST when all relevant hotplug operations are enabled */ -#if defined(CONFIG_ACPI_HOTPLUG_PRESENT_CPU) && \ +#if defined(CONFIG_ACPI_HOTPLUG_CPU) && \ defined(CONFIG_ACPI_HOTPLUG_MEMORY) && \ defined(CONFIG_ACPI_CONTAINER) #define ACPI_HOTPLUG_OST -- Gitee From 5061cd6cba871f8447ffefa39dcda46c0d419adc Mon Sep 17 00:00:00 2001 From: Zengruan Ye Date: Wed, 23 Jul 2025 15:43:18 +0800 Subject: [PATCH 106/155] KVM/arm64: Document PV-sched interface Introduce a paravirtualization interface for KVM/arm64 to PV-sched. A hypercall interface is provided for the guest to interrogate the hypervisor's support for this interface and the location of the shared memory structures. Mainline: NA (cherry picked form openEuler/OLK-6.6 commit 3566c5bf78e802ea93b11fb5e0abd142cd174fad) Signed-off-by: Zengruan Ye Signed-off-by: Li ShuSen Backported-by: Wu Chen Signed-off-by: Wang Yinfeng Change-Id: I623fbc7f12e8baf110bde9e0c47daf29b17ea3af --- Documentation/virt/kvm/arm/pvsched.rst | 58 ++++++++++++++++++++++++++ MAINTAINERS | 1 + 2 files changed, 59 insertions(+) create mode 100644 Documentation/virt/kvm/arm/pvsched.rst diff --git a/Documentation/virt/kvm/arm/pvsched.rst b/Documentation/virt/kvm/arm/pvsched.rst new file mode 100644 index 0000000000..8f7112a8a9 --- /dev/null +++ b/Documentation/virt/kvm/arm/pvsched.rst @@ -0,0 +1,58 @@ +.. SPDX-License-Identifier: GPL-2.0 + +Paravirtualized sched support for arm64 +======================================= + +KVM/arm64 provides some hypervisor service calls to support a paravirtualized +sched. + +Some SMCCC compatible hypercalls are defined: + +* PV_SCHED_FEATURES: 0xC5000090 +* PV_SCHED_IPA_INIT: 0xC5000091 +* PV_SCHED_IPA_RELEASE: 0xC5000092 + +The existence of the PV_SCHED hypercall should be probed using the SMCCC 1.1 +ARCH_FEATURES mechanism before calling it. + +PV_SCHED_FEATURES + ============= ======== ========== + Function ID: (uint32) 0xC5000090 + PV_call_id: (uint32) The function to query for support. + Return value: (int64) NOT_SUPPORTED (-1) or SUCCESS (0) if the relevant + PV-sched feature is supported by the hypervisor. + ============= ======== ========== + +PV_SCHED_IPA_INIT + ============= ======== ========== + Function ID: (uint32) 0xC5000091 + Return value: (int64) NOT_SUPPORTED (-1) or SUCCESS (0) if the IPA of + this vCPU's PV data structure is shared to the + hypervisor. + ============= ======== ========== + +PV_SCHED_IPA_RELEASE + ============= ======== ========== + Function ID: (uint32) 0xC5000092 + Return value: (int64) NOT_SUPPORTED (-1) or SUCCESS (0) if the IPA of + this vCPU's PV data structure is released. + ============= ======== ========== + +PV sched state +-------------- + +The structure pointed to by the PV_SCHED_IPA hypercall is as follows: + ++-----------+-------------+-------------+-----------------------------------+ +| Field | Byte Length | Byte Offset | Description | ++===========+=============+=============+===================================+ +| preempted | 4 | 0 | Indicates that the vCPU that owns | +| | | | this struct is running or not. | +| | | | Non-zero values mean the vCPU has | +| | | | been preempted. Zero means the | +| | | | vCPU is not preempted. | ++-----------+-------------+-------------+-----------------------------------+ + +The preempted field will be updated to 0 by the hypervisor prior to scheduling +a vCPU. When the vCPU is scheduled out, the preempted field will be updated +to 1 by the hypervisor. diff --git a/MAINTAINERS b/MAINTAINERS index ccc65f30a9..7a4eca409a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -17475,6 +17475,7 @@ F: Documentation/devicetree/bindings/usb/phytium,usb2.yaml F: Documentation/devicetree/bindings/usb/phytium.role-sw.yaml F: Documentation/devicetree/bindings/w1/phytium,w1.yaml F: Documentation/devicetree/bindings/staging/phytium-npu.yaml +F: Documentation/virt/kvm/arm/pvsched.rst F: arch/arm64/boot/dts/phytium/* F: arch/arm64/include/asm/phytium_cputype.h F: arch/arm64/include/asm/phyt.h -- Gitee From 19cb207d5c50f91ee9e754a3340bb70cf2838ed5 Mon Sep 17 00:00:00 2001 From: Zengruan Ye Date: Wed, 23 Jul 2025 15:44:23 +0800 Subject: [PATCH 107/155] KVM/arm64: Implement PV_SCHED_FEATURES call This provides a mechanism for querying which paravirtualized sched features are available in this hypervisor. Add some SMCCC compatible hypercalls for PV sched features: PV_SCHED_FEATURES: 0xC5000090 PV_SCHED_IPA_INIT: 0xC5000091 PV_SCHED_IPA_RELEASE: 0xC5000092 Also add the header file which defines the ABI for the paravirtualized sched features we're about to add. Mainline: NA (cherry picked and rework form OLK-6.6 commit b4787311f2024bf5243352b3485605c61b15f516) Signed-off-by: Zengruan Ye Signed-off-by: Li ShuSen Backported-by: Wu Chen Signed-off-by: Wang Yinfeng Change-Id: Iad45300a85ca54ae254220e646ac65a1d6f52cab --- MAINTAINERS | 1 + arch/arm64/Kconfig | 11 +++++++++++ arch/arm64/include/asm/kvm_host.h | 9 +++++++++ arch/arm64/include/asm/pvsched-abi.h | 16 ++++++++++++++++ arch/arm64/kvm/Makefile | 2 +- arch/arm64/kvm/hypercalls.c | 6 ++++++ arch/arm64/kvm/pvsched.c | 25 +++++++++++++++++++++++++ include/linux/arm-smccc.h | 19 +++++++++++++++++++ 8 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 arch/arm64/include/asm/pvsched-abi.h create mode 100644 arch/arm64/kvm/pvsched.c diff --git a/MAINTAINERS b/MAINTAINERS index 7a4eca409a..44fe8a5940 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -17429,6 +17429,7 @@ ARM/PHYTIUM SOC SUPPORT M: Wang Yinfeng S: Maintained W: https://www.phytium.com.cn +F: arch/arm64/include/asm/pvsched-abi.h F: Documentation/arch/arm64/cpu-hotplug.rst F: Documentation/devicetree/bindings/dma/phytium,ddma.yaml F: Documentation/devicetree/bindings/dma/phytium,gdma.yaml diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 8ca0fecba5..da241808b0 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -1563,6 +1563,17 @@ config PARAVIRT under a hypervisor, potentially improving performance significantly over full virtualization. +config PARAVIRT_SCHED + bool "Paravirtualization layer for sched" + depends on PARAVIRT + help + This supports the vCPU preemption check to enhance lock performance on + overcommitted hosts (more runnable vCPUs than physical CPUs in the + system) as doing busy waits for preempted vCPUs will hurt system + performance far worse than early yielding. + + If you are unsure how to answer this question, answer Y. + config PARAVIRT_TIME_ACCOUNTING bool "Paravirtual steal time accounting" select PARAVIRT diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index af06ccb7ee..9006b8f8f6 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -1038,6 +1038,15 @@ static inline bool kvm_arm_is_pvtime_enabled(struct kvm_vcpu_arch *vcpu_arch) return (vcpu_arch->steal.base != INVALID_GPA); } +#ifdef CONFIG_PARAVIRT_SCHED +long kvm_hypercall_pvsched_features(struct kvm_vcpu *vcpu); +#else +static inline long kvm_hypercall_pvsched_features(struct kvm_vcpu *vcpu) +{ + return 0; +} +#endif + void kvm_set_sei_esr(struct kvm_vcpu *vcpu, u64 syndrome); struct kvm_vcpu *kvm_mpidr_to_vcpu(struct kvm *kvm, unsigned long mpidr); diff --git a/arch/arm64/include/asm/pvsched-abi.h b/arch/arm64/include/asm/pvsched-abi.h new file mode 100644 index 0000000000..80e50e7a1a --- /dev/null +++ b/arch/arm64/include/asm/pvsched-abi.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(c) 2019 Huawei Technologies Co., Ltd + * Author: Zengruan Ye + */ + +#ifndef __ASM_PVSCHED_ABI_H +#define __ASM_PVSCHED_ABI_H + +struct pvsched_vcpu_state { + __le32 preempted; + /* Structure must be 64 byte aligned, pad to that size */ + u8 padding[60]; +} __packed; + +#endif diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile index c0c050e531..3e16e6c364 100644 --- a/arch/arm64/kvm/Makefile +++ b/arch/arm64/kvm/Makefile @@ -10,7 +10,7 @@ include $(srctree)/virt/kvm/Makefile.kvm obj-$(CONFIG_KVM) += kvm.o obj-$(CONFIG_KVM) += hyp/ -kvm-y += arm.o mmu.o mmio.o psci.o hypercalls.o pvtime.o \ +kvm-y += arm.o mmu.o mmio.o psci.o hypercalls.o pvtime.o pvsched.o \ inject_fault.o va_layout.o handle_exit.o \ guest.o debug.o reset.o sys_regs.o stacktrace.o \ vgic-sys-reg-v3.o fpsimd.o pkvm.o \ diff --git a/arch/arm64/kvm/hypercalls.c b/arch/arm64/kvm/hypercalls.c index 7fb4df0456..a7c4090a5d 100644 --- a/arch/arm64/kvm/hypercalls.c +++ b/arch/arm64/kvm/hypercalls.c @@ -332,6 +332,9 @@ int kvm_smccc_call_handler(struct kvm_vcpu *vcpu) &smccc_feat->std_hyp_bmap)) val[0] = SMCCC_RET_SUCCESS; break; + case ARM_SMCCC_HV_PV_SCHED_FEATURES: + val[0] = SMCCC_RET_SUCCESS; + break; } break; case ARM_SMCCC_HV_PV_TIME_FEATURES: @@ -342,6 +345,9 @@ int kvm_smccc_call_handler(struct kvm_vcpu *vcpu) if (gpa != INVALID_GPA) val[0] = gpa; break; + case ARM_SMCCC_HV_PV_SCHED_FEATURES: + val[0] = kvm_hypercall_pvsched_features(vcpu); + break; case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID: val[0] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_0; val[1] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_1; diff --git a/arch/arm64/kvm/pvsched.c b/arch/arm64/kvm/pvsched.c new file mode 100644 index 0000000000..f280296f6a --- /dev/null +++ b/arch/arm64/kvm/pvsched.c @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright(c) 2019 Huawei Technologies Co., Ltd + * Author: Zengruan Ye + */ + +#ifdef CONFIG_PARAVIRT_SCHED +#include + +#include + +long kvm_hypercall_pvsched_features(struct kvm_vcpu *vcpu) +{ + u32 feature = smccc_get_arg1(vcpu); + long val = SMCCC_RET_NOT_SUPPORTED; + + switch (feature) { + case ARM_SMCCC_HV_PV_SCHED_FEATURES: + val = SMCCC_RET_SUCCESS; + break; + } + + return val; +} +#endif /* CONFIG_PARAVIRT_SCHED */ diff --git a/include/linux/arm-smccc.h b/include/linux/arm-smccc.h index 374ff33875..42d1f73c1b 100644 --- a/include/linux/arm-smccc.h +++ b/include/linux/arm-smccc.h @@ -551,5 +551,24 @@ asmlinkage void __arm_smccc_hvc(unsigned long a0, unsigned long a1, method; \ }) +/* Paravirtualised sched calls */ +#define ARM_SMCCC_HV_PV_SCHED_FEATURES \ + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ + ARM_SMCCC_SMC_64, \ + ARM_SMCCC_OWNER_STANDARD_HYP, \ + 0x90) + +#define ARM_SMCCC_HV_PV_SCHED_IPA_INIT \ + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ + ARM_SMCCC_SMC_64, \ + ARM_SMCCC_OWNER_STANDARD_HYP, \ + 0x91) + +#define ARM_SMCCC_HV_PV_SCHED_IPA_RELEASE \ + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ + ARM_SMCCC_SMC_64, \ + ARM_SMCCC_OWNER_STANDARD_HYP, \ + 0x92) + #endif /*__ASSEMBLY__*/ #endif /*__LINUX_ARM_SMCCC_H*/ -- Gitee From c08bc94bba7364926d7078469816f5894b90f040 Mon Sep 17 00:00:00 2001 From: Zengruan Ye Date: Wed, 23 Jul 2025 15:45:39 +0800 Subject: [PATCH 108/155] KVM/arm64: Support pvsched preempted via shared structure Implement the service call for configuring a shared structure between a vCPU and the hypervisor in which the hypervisor can tell the vCPU that is running or not. Mainline: NA (cherry picked form openEuler/OLK-6.6 commit c0d910ffc72eed3bcda04d26669f04915d956ae7) Signed-off-by: Zengruan Ye Signed-off-by: Li ShuSen Backported-by: Wu Chen Signed-off-by: Wang Yinfeng Change-Id: If1808d7095b776c88062d7010d6c8bbb69803aec --- MAINTAINERS | 1 + arch/arm64/include/asm/kvm_host.h | 23 ++++++++++++++++++++++ arch/arm64/include/asm/paravirt.h | 8 ++++++++ arch/arm64/include/asm/spinlock.h | 8 ++++++++ arch/arm64/kernel/Makefile | 2 +- arch/arm64/kernel/paravirt-spinlocks.c | 16 +++++++++++++++ arch/arm64/kvm/arm.c | 8 ++++++++ arch/arm64/kvm/hypercalls.c | 11 +++++++++++ arch/arm64/kvm/pvsched.c | 27 ++++++++++++++++++++++++++ 9 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 arch/arm64/kernel/paravirt-spinlocks.c diff --git a/MAINTAINERS b/MAINTAINERS index 44fe8a5940..e70c8cd744 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -17430,6 +17430,7 @@ M: Wang Yinfeng S: Maintained W: https://www.phytium.com.cn F: arch/arm64/include/asm/pvsched-abi.h +F: arch/arm64/kernel/paravirt-spinlocks.c F: Documentation/arch/arm64/cpu-hotplug.rst F: Documentation/devicetree/bindings/dma/phytium,ddma.yaml F: Documentation/devicetree/bindings/dma/phytium,gdma.yaml diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 9006b8f8f6..dd62836ed8 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -589,6 +589,11 @@ struct kvm_vcpu_arch { gpa_t base; } steal; + /* Guest PV sched state */ + struct { + gpa_t base; + } pvsched; + /* Per-vcpu CCSIDR override or NULL */ u32 *ccsidr; }; @@ -1040,11 +1045,29 @@ static inline bool kvm_arm_is_pvtime_enabled(struct kvm_vcpu_arch *vcpu_arch) #ifdef CONFIG_PARAVIRT_SCHED long kvm_hypercall_pvsched_features(struct kvm_vcpu *vcpu); +void kvm_update_pvsched_preempted(struct kvm_vcpu *vcpu, u32 preempted); + +static inline void kvm_arm_pvsched_vcpu_init(struct kvm_vcpu_arch *vcpu_arch) +{ + vcpu_arch->pvsched.base = INVALID_GPA; +} + +static inline bool kvm_arm_is_pvsched_enabled(struct kvm_vcpu_arch *vcpu_arch) +{ + return (vcpu_arch->pvsched.base != INVALID_GPA); +} #else static inline long kvm_hypercall_pvsched_features(struct kvm_vcpu *vcpu) { return 0; } +static inline void kvm_update_pvsched_preempted(struct kvm_vcpu *vcpu, + u32 preempted) {} +static inline void kvm_arm_pvsched_vcpu_init(struct kvm_vcpu_arch *vcpu_arch) {} +static inline bool kvm_arm_is_pvsched_enabled(struct kvm_vcpu_arch *vcpu_arch) +{ + return false; +} #endif void kvm_set_sei_esr(struct kvm_vcpu *vcpu, u64 syndrome); diff --git a/arch/arm64/include/asm/paravirt.h b/arch/arm64/include/asm/paravirt.h index 9aa193e0e8..53282dc429 100644 --- a/arch/arm64/include/asm/paravirt.h +++ b/arch/arm64/include/asm/paravirt.h @@ -20,6 +20,14 @@ static inline u64 paravirt_steal_clock(int cpu) int __init pv_time_init(void); +__visible bool __native_vcpu_is_preempted(int cpu); +DECLARE_STATIC_CALL(pv_vcpu_preempted, __native_vcpu_is_preempted); + +static inline bool pv_vcpu_is_preempted(int cpu) +{ + return static_call(pv_vcpu_preempted)(cpu); +} + #else #define pv_time_init() do {} while (0) diff --git a/arch/arm64/include/asm/spinlock.h b/arch/arm64/include/asm/spinlock.h index 0525c0b089..378aea19e8 100644 --- a/arch/arm64/include/asm/spinlock.h +++ b/arch/arm64/include/asm/spinlock.h @@ -7,6 +7,7 @@ #include #include +#include /* See include/linux/spinlock.h */ #define smp_mb__after_spinlock() smp_mb() @@ -19,9 +20,16 @@ * https://lore.kernel.org/lkml/20200110100612.GC2827@hirez.programming.kicks-ass.net */ #define vcpu_is_preempted vcpu_is_preempted +#if defined(CONFIG_PARAVIRT) && defined(CONFIG_PARAVIRT_SCHED) +static inline bool vcpu_is_preempted(int cpu) +{ + return pv_vcpu_is_preempted(cpu); +} +#else static inline bool vcpu_is_preempted(int cpu) { return false; } +#endif /* CONFIG_PARAVIRT && CONFIG_PARAVIRT_SCHED */ #endif /* __ASM_SPINLOCK_H */ diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index eca1f9012a..e0ac2ddb09 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile @@ -57,7 +57,7 @@ obj-$(CONFIG_ACPI) += acpi.o obj-$(CONFIG_ARM64_ERR_RECOV) += ras.o obj-$(CONFIG_ACPI_NUMA) += acpi_numa.o obj-$(CONFIG_ARM64_ACPI_PARKING_PROTOCOL) += acpi_parking_protocol.o -obj-$(CONFIG_PARAVIRT) += paravirt.o +obj-$(CONFIG_PARAVIRT) += paravirt.o paravirt-spinlocks.o obj-$(CONFIG_RANDOMIZE_BASE) += kaslr.o pi/ obj-$(CONFIG_HIBERNATION) += hibernate.o hibernate-asm.o obj-$(CONFIG_ELF_CORE) += elfcore.o diff --git a/arch/arm64/kernel/paravirt-spinlocks.c b/arch/arm64/kernel/paravirt-spinlocks.c new file mode 100644 index 0000000000..3566897070 --- /dev/null +++ b/arch/arm64/kernel/paravirt-spinlocks.c @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright(c) 2019 Huawei Technologies Co., Ltd + * Author: Zengruan Ye + */ + +#include +#include +#include + +__visible bool __native_vcpu_is_preempted(int cpu) +{ + return false; +} + +DEFINE_STATIC_CALL(pv_vcpu_preempted, __native_vcpu_is_preempted); diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 18413d869c..716d840ade 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -386,6 +386,8 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu) kvm_arm_pvtime_vcpu_init(&vcpu->arch); + kvm_arm_pvsched_vcpu_init(&vcpu->arch); + vcpu->arch.hw_mmu = &vcpu->kvm->arch.mmu; err = kvm_vgic_vcpu_init(vcpu); @@ -465,6 +467,9 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) if (!cpumask_test_cpu(cpu, vcpu->kvm->arch.supported_cpus)) vcpu_set_on_unsupported_cpu(vcpu); + + if (kvm_arm_is_pvsched_enabled(&vcpu->arch)) + kvm_update_pvsched_preempted(vcpu, 0); } void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) @@ -480,6 +485,9 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) vcpu_clear_on_unsupported_cpu(vcpu); vcpu->cpu = -1; + + if (kvm_arm_is_pvsched_enabled(&vcpu->arch)) + kvm_update_pvsched_preempted(vcpu, 1); } static void __kvm_arm_vcpu_power_off(struct kvm_vcpu *vcpu) diff --git a/arch/arm64/kvm/hypercalls.c b/arch/arm64/kvm/hypercalls.c index a7c4090a5d..48bf2e0b7a 100644 --- a/arch/arm64/kvm/hypercalls.c +++ b/arch/arm64/kvm/hypercalls.c @@ -348,6 +348,17 @@ int kvm_smccc_call_handler(struct kvm_vcpu *vcpu) case ARM_SMCCC_HV_PV_SCHED_FEATURES: val[0] = kvm_hypercall_pvsched_features(vcpu); break; + case ARM_SMCCC_HV_PV_SCHED_IPA_INIT: + gpa = smccc_get_arg1(vcpu); + if (gpa != INVALID_GPA) { + vcpu->arch.pvsched.base = gpa; + val[0] = SMCCC_RET_SUCCESS; + } + break; + case ARM_SMCCC_HV_PV_SCHED_IPA_RELEASE: + vcpu->arch.pvsched.base = INVALID_GPA; + val[0] = SMCCC_RET_SUCCESS; + break; case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID: val[0] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_0; val[1] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_1; diff --git a/arch/arm64/kvm/pvsched.c b/arch/arm64/kvm/pvsched.c index f280296f6a..6371dc1374 100644 --- a/arch/arm64/kvm/pvsched.c +++ b/arch/arm64/kvm/pvsched.c @@ -6,9 +6,34 @@ #ifdef CONFIG_PARAVIRT_SCHED #include +#include +#include #include +void kvm_update_pvsched_preempted(struct kvm_vcpu *vcpu, u32 preempted) +{ + struct kvm *kvm = vcpu->kvm; + u64 base = vcpu->arch.pvsched.base; + u64 offset = offsetof(struct pvsched_vcpu_state, preempted); + int idx; + + if (base == INVALID_GPA) + return; + + /* + * This function is called from atomic context, so we need to + * disable page faults. + */ + pagefault_disable(); + + idx = srcu_read_lock(&kvm->srcu); + kvm_put_guest(kvm, base + offset, cpu_to_le32(preempted)); + srcu_read_unlock(&kvm->srcu, idx); + + pagefault_enable(); +} + long kvm_hypercall_pvsched_features(struct kvm_vcpu *vcpu) { u32 feature = smccc_get_arg1(vcpu); @@ -16,6 +41,8 @@ long kvm_hypercall_pvsched_features(struct kvm_vcpu *vcpu) switch (feature) { case ARM_SMCCC_HV_PV_SCHED_FEATURES: + case ARM_SMCCC_HV_PV_SCHED_IPA_INIT: + case ARM_SMCCC_HV_PV_SCHED_IPA_RELEASE: val = SMCCC_RET_SUCCESS; break; } -- Gitee From 90e630dba29b2b7c9fb63a5deeb0ce38d2d58bbc Mon Sep 17 00:00:00 2001 From: Zengruan Ye Date: Wed, 23 Jul 2025 15:48:43 +0800 Subject: [PATCH 109/155] KVM/arm64: Support the vCPU preemption check This is to fix some lock holder preemption issues. Some other locks implementation do a spin loop before acquiring the lock itself. Currently kernel has an interface of bool vcpu_is_preempted(int cpu). It takes the CPU as parameter and return true if the CPU is preempted. Then kernel can break the spin loops upon the retval of vcpu_is_preempted. As kernel has used this interface, So lets support it. Mainline: NA (cherry picked form openEuler/OLK-6.6 commit 858bccb74369c985bff0cafbf0888cb951cc3754) Signed-off-by: Zengruan Ye Signed-off-by: Li ShuSen Backported-by: Wu Chen Signed-off-by: Wang Yinfeng Change-Id: If39db53cff0f6046a10c95915b4a630131b86e1e --- arch/arm64/include/asm/kvm_host.h | 2 + arch/arm64/include/asm/paravirt.h | 5 ++ arch/arm64/include/asm/pvsched-abi.h | 2 + arch/arm64/kernel/paravirt-spinlocks.c | 2 + arch/arm64/kernel/paravirt.c | 109 +++++++++++++++++++++++++ arch/arm64/kvm/arm.c | 2 + arch/arm64/kvm/hypercalls.c | 4 + include/linux/arm-smccc.h | 2 + include/linux/cpuhotplug.h | 1 + 9 files changed, 129 insertions(+) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index dd62836ed8..038b4de4c8 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -589,10 +589,12 @@ struct kvm_vcpu_arch { gpa_t base; } steal; +#ifdef CONFIG_PARAVIRT_SCHED /* Guest PV sched state */ struct { gpa_t base; } pvsched; +#endif /* Per-vcpu CCSIDR override or NULL */ u32 *ccsidr; diff --git a/arch/arm64/include/asm/paravirt.h b/arch/arm64/include/asm/paravirt.h index 53282dc429..5ccead71bf 100644 --- a/arch/arm64/include/asm/paravirt.h +++ b/arch/arm64/include/asm/paravirt.h @@ -20,6 +20,9 @@ static inline u64 paravirt_steal_clock(int cpu) int __init pv_time_init(void); +#ifdef CONFIG_PARAVIRT_SCHED +int __init pv_sched_init(void); + __visible bool __native_vcpu_is_preempted(int cpu); DECLARE_STATIC_CALL(pv_vcpu_preempted, __native_vcpu_is_preempted); @@ -27,10 +30,12 @@ static inline bool pv_vcpu_is_preempted(int cpu) { return static_call(pv_vcpu_preempted)(cpu); } +#endif /* CONFIG_PARAVIRT_SCHED */ #else #define pv_time_init() do {} while (0) +#define pv_sched_init() do {} while (0) #endif // CONFIG_PARAVIRT diff --git a/arch/arm64/include/asm/pvsched-abi.h b/arch/arm64/include/asm/pvsched-abi.h index 80e50e7a1a..cc8e27dd26 100644 --- a/arch/arm64/include/asm/pvsched-abi.h +++ b/arch/arm64/include/asm/pvsched-abi.h @@ -7,10 +7,12 @@ #ifndef __ASM_PVSCHED_ABI_H #define __ASM_PVSCHED_ABI_H +#ifdef CONFIG_PARAVIRT_SCHED struct pvsched_vcpu_state { __le32 preempted; /* Structure must be 64 byte aligned, pad to that size */ u8 padding[60]; } __packed; +#endif /* CONFIG_PARAVIRT_SCHED */ #endif diff --git a/arch/arm64/kernel/paravirt-spinlocks.c b/arch/arm64/kernel/paravirt-spinlocks.c index 3566897070..f402e7e6c3 100644 --- a/arch/arm64/kernel/paravirt-spinlocks.c +++ b/arch/arm64/kernel/paravirt-spinlocks.c @@ -4,6 +4,7 @@ * Author: Zengruan Ye */ +#ifdef CONFIG_PARAVIRT_SCHED #include #include #include @@ -14,3 +15,4 @@ __visible bool __native_vcpu_is_preempted(int cpu) } DEFINE_STATIC_CALL(pv_vcpu_preempted, __native_vcpu_is_preempted); +#endif /* CONFIG_PARAVIRT_SCHED */ diff --git a/arch/arm64/kernel/paravirt.c b/arch/arm64/kernel/paravirt.c index aa718d6a92..8a5fcb0d99 100644 --- a/arch/arm64/kernel/paravirt.c +++ b/arch/arm64/kernel/paravirt.c @@ -22,6 +22,7 @@ #include #include +#include #include struct static_key paravirt_steal_enabled; @@ -174,3 +175,111 @@ int __init pv_time_init(void) return 0; } + +#ifdef CONFIG_PARAVIRT_SCHED +DEFINE_PER_CPU(struct pvsched_vcpu_state, pvsched_vcpu_region) __aligned(64); +EXPORT_PER_CPU_SYMBOL(pvsched_vcpu_region); + +static bool kvm_vcpu_is_preempted(int cpu) +{ + struct pvsched_vcpu_state *reg; + u32 preempted; + + reg = &per_cpu(pvsched_vcpu_region, cpu); + if (!reg) { + pr_warn_once("PV sched enabled but not configured for cpu %d\n", + cpu); + return false; + } + + preempted = le32_to_cpu(READ_ONCE(reg->preempted)); + + return !!preempted; +} + +static int pvsched_vcpu_state_dying_cpu(unsigned int cpu) +{ + struct pvsched_vcpu_state *reg; + struct arm_smccc_res res; + + reg = this_cpu_ptr(&pvsched_vcpu_region); + if (!reg) + return -EFAULT; + + arm_smccc_1_1_invoke(ARM_SMCCC_HV_PV_SCHED_IPA_RELEASE, &res); + memset(reg, 0, sizeof(*reg)); + + return 0; +} + +static int init_pvsched_vcpu_state(unsigned int cpu) +{ + struct pvsched_vcpu_state *reg; + struct arm_smccc_res res; + + reg = this_cpu_ptr(&pvsched_vcpu_region); + if (!reg) + return -EFAULT; + + /* Pass the memory address to host via hypercall */ + arm_smccc_1_1_invoke(ARM_SMCCC_HV_PV_SCHED_IPA_INIT, + virt_to_phys(reg), &res); + + return 0; +} + +static int kvm_arm_init_pvsched(void) +{ + int ret; + + ret = cpuhp_setup_state(CPUHP_AP_ARM_KVM_PVSCHED_STARTING, + "hypervisor/arm/pvsched:starting", + init_pvsched_vcpu_state, + pvsched_vcpu_state_dying_cpu); + + if (ret < 0) { + pr_warn("PV sched init failed\n"); + return ret; + } + + return 0; +} + +static bool has_kvm_pvsched(void) +{ + struct arm_smccc_res res; + + /* To detect the presence of PV sched support we require SMCCC 1.1+ */ + if (arm_smccc_1_1_get_conduit() == SMCCC_CONDUIT_NONE) + return false; + + arm_smccc_1_1_invoke(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, + ARM_SMCCC_HV_PV_SCHED_FEATURES, &res); + + return (res.a0 == SMCCC_RET_SUCCESS); +} + +int __init pv_sched_init(void) +{ + int ret; + + if (is_hyp_mode_available()) + return 0; + + if (!has_kvm_pvsched()) { + pr_warn("PV sched is not available\n"); + return 0; + } + + ret = kvm_arm_init_pvsched(); + if (ret) + return ret; + + static_call_update(pv_vcpu_preempted, kvm_vcpu_is_preempted); + pr_info("using PV sched preempted\n"); + + return 0; +} +early_initcall(pv_sched_init); +#endif /* CONFIG_PARAVIRT_SCHED */ + diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 716d840ade..865320250e 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -1343,6 +1343,8 @@ static int kvm_arch_vcpu_ioctl_vcpu_init(struct kvm_vcpu *vcpu, spin_unlock(&vcpu->arch.mp_state_lock); + kvm_arm_pvsched_vcpu_init(&vcpu->arch); + return 0; } diff --git a/arch/arm64/kvm/hypercalls.c b/arch/arm64/kvm/hypercalls.c index 48bf2e0b7a..4c9fc5df51 100644 --- a/arch/arm64/kvm/hypercalls.c +++ b/arch/arm64/kvm/hypercalls.c @@ -332,9 +332,11 @@ int kvm_smccc_call_handler(struct kvm_vcpu *vcpu) &smccc_feat->std_hyp_bmap)) val[0] = SMCCC_RET_SUCCESS; break; +#ifdef CONFIG_PARAVIRT_SCHED case ARM_SMCCC_HV_PV_SCHED_FEATURES: val[0] = SMCCC_RET_SUCCESS; break; +#endif /* CONFIG_PARAVIRT_SCHED */ } break; case ARM_SMCCC_HV_PV_TIME_FEATURES: @@ -345,6 +347,7 @@ int kvm_smccc_call_handler(struct kvm_vcpu *vcpu) if (gpa != INVALID_GPA) val[0] = gpa; break; +#ifdef CONFIG_PARAVIRT_SCHED case ARM_SMCCC_HV_PV_SCHED_FEATURES: val[0] = kvm_hypercall_pvsched_features(vcpu); break; @@ -359,6 +362,7 @@ int kvm_smccc_call_handler(struct kvm_vcpu *vcpu) vcpu->arch.pvsched.base = INVALID_GPA; val[0] = SMCCC_RET_SUCCESS; break; +#endif /* CONFIG_PARAVIRT_SCHED */ case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID: val[0] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_0; val[1] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_1; diff --git a/include/linux/arm-smccc.h b/include/linux/arm-smccc.h index 42d1f73c1b..9aba481603 100644 --- a/include/linux/arm-smccc.h +++ b/include/linux/arm-smccc.h @@ -551,6 +551,7 @@ asmlinkage void __arm_smccc_hvc(unsigned long a0, unsigned long a1, method; \ }) +#ifdef CONFIG_PARAVIRT_SCHED /* Paravirtualised sched calls */ #define ARM_SMCCC_HV_PV_SCHED_FEATURES \ ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ @@ -569,6 +570,7 @@ asmlinkage void __arm_smccc_hvc(unsigned long a0, unsigned long a1, ARM_SMCCC_SMC_64, \ ARM_SMCCC_OWNER_STANDARD_HYP, \ 0x92) +#endif /* CONFIG_PARAVIRT_SCHED */ #endif /*__ASSEMBLY__*/ #endif /*__LINUX_ARM_SMCCC_H*/ diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h index 2f979c03d7..18fb6ceea6 100644 --- a/include/linux/cpuhotplug.h +++ b/include/linux/cpuhotplug.h @@ -190,6 +190,7 @@ enum cpuhp_state { CPUHP_AP_DUMMY_TIMER_STARTING, CPUHP_AP_ARM_XEN_STARTING, CPUHP_AP_ARM_XEN_RUNSTATE_STARTING, + CPUHP_AP_ARM_KVM_PVSCHED_STARTING, CPUHP_AP_ARM_CORESIGHT_STARTING, CPUHP_AP_ARM_CORESIGHT_CTI_STARTING, CPUHP_AP_ARM64_ISNDEP_STARTING, -- Gitee From aed2b39a57916f79e3c092a6e7744f8ccdfe580a Mon Sep 17 00:00:00 2001 From: Zengruan Ye Date: Wed, 23 Jul 2025 15:51:55 +0800 Subject: [PATCH 110/155] KVM/arm64: Enable PV_SCHED features in the hypervisor The paravirtualized sched features we're about to add. We split the patch (commit: b4787311) into two parts based on its content and configuration option. Mainline: NA (cherry picked and rework form openEuler/OLK-6.6 commit b4787311f2024bf5243352b3485605c61b15f516) Signed-off-by: Zengruan Ye Signed-off-by: Li ShuSen Signed-off-by: Wu Chen Signed-off-by: Wang Yinfeng Change-Id: I2a5adb5f245bc581cdf56db60917429c28b27eb6 --- arch/arm64/configs/defconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index 6f24e05668..e9279fa100 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -78,6 +78,8 @@ CONFIG_ARM64_VA_BITS_48=y CONFIG_SCHED_MC=y CONFIG_SCHED_SMT=y CONFIG_NUMA=y +CONFIG_PARAVIRT=y +CONFIG_PARAVIRT_SCHED=y CONFIG_KEXEC=y CONFIG_KEXEC_FILE=y CONFIG_CRASH_DUMP=y -- Gitee From d1774b9acf4205e0877f2eff4838495373da899e Mon Sep 17 00:00:00 2001 From: Ankit Agrawal Date: Wed, 23 Jul 2025 16:42:13 +0800 Subject: [PATCH 111/155] KVM/arm64: Introduce new flag for non-cacheable IO memory Currently, KVM for ARM64 maps at stage 2 memory that is considered device (i.e. it is not RAM) with DEVICE_nGnRE memory attributes; this setting overrides (as per the ARM architecture [1]) any device MMIO mapping present at stage 1, resulting in a set-up whereby a guest operating system cannot determine device MMIO mapping memory attributes on its own but it is always overridden by the KVM stage 2 default. This set-up does not allow guest operating systems to select device memory attributes independently from KVM stage-2 mappings (refer to [1], "Combining stage 1 and stage 2 memory type attributes"), which turns out to be an issue in that guest operating systems (e.g. Linux) may request to map devices MMIO regions with memory attributes that guarantee better performance (e.g. gathering attribute - that for some devices can generate larger PCIe memory writes TLPs) and specific operations (e.g. unaligned transactions) such as the NormalNC memory type. The default device stage 2 mapping was chosen in KVM for ARM64 since it was considered safer (i.e. it would not allow guests to trigger uncontained failures ultimately crashing the machine) but this turned out to be asynchronous (SError) defeating the purpose. Failures containability is a property of the platform and is independent from the memory type used for MMIO device memory mappings. Actually, DEVICE_nGnRE memory type is even more problematic than Normal-NC memory type in terms of faults containability in that e.g. aborts triggered on DEVICE_nGnRE loads cannot be made, architecturally, synchronous (i.e. that would imply that the processor should issue at most 1 load transaction at a time - it cannot pipeline them - otherwise the synchronous abort semantics would break the no-speculation attribute attached to DEVICE_XXX memory). This means that regardless of the combined stage1+stage2 mappings a platform is safe if and only if device transactions cannot trigger uncontained failures and that in turn relies on platform capabilities and the device type being assigned (i.e. PCIe AER/DPC error containment and RAS architecture[3]); therefore the default KVM device stage 2 memory attributes play no role in making device assignment safer for a given platform (if the platform design adheres to design guidelines outlined in [3]) and therefore can be relaxed. For all these reasons, relax the KVM stage 2 device memory attributes from DEVICE_nGnRE to Normal-NC. The NormalNC was chosen over a different Normal memory type default at stage-2 (e.g. Normal Write-through) to avoid cache allocation/snooping. Relaxing S2 KVM device MMIO mappings to Normal-NC is not expected to trigger any issue on guest device reclaim use cases either (i.e. device MMIO unmap followed by a device reset) at least for PCIe devices, in that in PCIe a device reset is architected and carried out through PCI config space transactions that are naturally ordered with respect to MMIO transactions according to the PCI ordering rules. Having Normal-NC S2 default puts guests in control (thanks to stage1+stage2 combined memory attributes rules [1]) of device MMIO regions memory mappings, according to the rules described in [1] and summarized here ([(S1) - stage1], [(S2) - stage 2]): S1 | S2 | Result NORMAL-WB | NORMAL-NC | NORMAL-NC NORMAL-WT | NORMAL-NC | NORMAL-NC NORMAL-NC | NORMAL-NC | NORMAL-NC DEVICE | NORMAL-NC | DEVICE It is worth noting that currently, to map devices MMIO space to user space in a device pass-through use case the VFIO framework applies memory attributes derived from pgprot_noncached() settings applied to VMAs, which result in device-nGnRnE memory attributes for the stage-1 VMM mappings. This means that a userspace mapping for device MMIO space carried out with the current VFIO framework and a guest OS mapping for the same MMIO space may result in a mismatched alias as described in [2]. Defaulting KVM device stage-2 mappings to Normal-NC attributes does not change anything in this respect, in that the mismatched aliases would only affect (refer to [2] for a detailed explanation) ordering between the userspace and GuestOS mappings resulting stream of transactions (i.e. it does not cause loss of property for either stream of transactions on its own), which is harmless given that the userspace and GuestOS access to the device is carried out through independent transactions streams. A Normal-NC flag is not present today. So add a new kvm_pgtable_prot (KVM_PGTABLE_PROT_NORMAL_NC) flag for it, along with its corresponding PTE value 0x5 (0b101) determined from [1]. Lastly, adapt the stage2 PTE property setter function (stage2_set_prot_attr) to handle the NormalNC attribute. The entire discussion leading to this patch series may be followed through the following links. Link: https://lore.kernel.org/all/20230907181459.18145-3-ankita@nvidia.com Link: https://lore.kernel.org/r/20231205033015.10044-1-ankita@nvidia.com [1] section D8.5.5 - DDI0487J_a_a-profile_architecture_reference_manual.pdf [2] section B2.8 - DDI0487J_a_a-profile_architecture_reference_manual.pdf [3] sections 1.7.7.3/1.8.5.2/appendix C - DEN0029H_SBSA_7.1.pdf Mainline: NA (cherry picked from commit c034ec84e8795cf379bd47cc8871445f070a0110) Suggested-by: Jason Gunthorpe Acked-by: Catalin Marinas Acked-by: Will Deacon Reviewed-by: Marc Zyngier Signed-off-by: Ankit Agrawal Backported-by: Li Hao Signed-off-by: Wang Yinfeng Change-Id: I06356b2e8745543b5bb2055cc195a5522af56d80 --- arch/arm64/include/asm/kvm_pgtable.h | 2 ++ arch/arm64/include/asm/memory.h | 2 ++ arch/arm64/kvm/hyp/pgtable.c | 24 +++++++++++++++++++----- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/arch/arm64/include/asm/kvm_pgtable.h b/arch/arm64/include/asm/kvm_pgtable.h index d3e354bb83..de0b8845df 100644 --- a/arch/arm64/include/asm/kvm_pgtable.h +++ b/arch/arm64/include/asm/kvm_pgtable.h @@ -169,6 +169,7 @@ enum kvm_pgtable_stage2_flags { * @KVM_PGTABLE_PROT_W: Write permission. * @KVM_PGTABLE_PROT_R: Read permission. * @KVM_PGTABLE_PROT_DEVICE: Device attributes. + * @KVM_PGTABLE_PROT_NORMAL_NC: Normal noncacheable attributes. * @KVM_PGTABLE_PROT_SW0: Software bit 0. * @KVM_PGTABLE_PROT_SW1: Software bit 1. * @KVM_PGTABLE_PROT_SW2: Software bit 2. @@ -180,6 +181,7 @@ enum kvm_pgtable_prot { KVM_PGTABLE_PROT_R = BIT(2), KVM_PGTABLE_PROT_DEVICE = BIT(3), + KVM_PGTABLE_PROT_NORMAL_NC = BIT(4), KVM_PGTABLE_PROT_SW0 = BIT(55), KVM_PGTABLE_PROT_SW1 = BIT(56), diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h index fde4186cc3..c247e5f29d 100644 --- a/arch/arm64/include/asm/memory.h +++ b/arch/arm64/include/asm/memory.h @@ -147,6 +147,7 @@ * Memory types for Stage-2 translation */ #define MT_S2_NORMAL 0xf +#define MT_S2_NORMAL_NC 0x5 #define MT_S2_DEVICE_nGnRE 0x1 /* @@ -154,6 +155,7 @@ * Stage-2 enforces Normal-WB and Device-nGnRE */ #define MT_S2_FWB_NORMAL 6 +#define MT_S2_FWB_NORMAL_NC 5 #define MT_S2_FWB_DEVICE_nGnRE 1 #ifdef CONFIG_ARM64_4K_PAGES diff --git a/arch/arm64/kvm/hyp/pgtable.c b/arch/arm64/kvm/hyp/pgtable.c index ca0bf0b92c..b0586d79d2 100644 --- a/arch/arm64/kvm/hyp/pgtable.c +++ b/arch/arm64/kvm/hyp/pgtable.c @@ -695,15 +695,29 @@ void kvm_tlb_flush_vmid_range(struct kvm_s2_mmu *mmu, static int stage2_set_prot_attr(struct kvm_pgtable *pgt, enum kvm_pgtable_prot prot, kvm_pte_t *ptep) { - bool device = prot & KVM_PGTABLE_PROT_DEVICE; - kvm_pte_t attr = device ? KVM_S2_MEMATTR(pgt, DEVICE_nGnRE) : - KVM_S2_MEMATTR(pgt, NORMAL); + kvm_pte_t attr; u32 sh = KVM_PTE_LEAF_ATTR_LO_S2_SH_IS; + switch (prot & (KVM_PGTABLE_PROT_DEVICE | + KVM_PGTABLE_PROT_NORMAL_NC)) { + case KVM_PGTABLE_PROT_DEVICE | KVM_PGTABLE_PROT_NORMAL_NC: + return -EINVAL; + case KVM_PGTABLE_PROT_DEVICE: + if (prot & KVM_PGTABLE_PROT_X) + return -EINVAL; + attr = KVM_S2_MEMATTR(pgt, DEVICE_nGnRE); + break; + case KVM_PGTABLE_PROT_NORMAL_NC: + if (prot & KVM_PGTABLE_PROT_X) + return -EINVAL; + attr = KVM_S2_MEMATTR(pgt, NORMAL_NC); + break; + default: + attr = KVM_S2_MEMATTR(pgt, NORMAL); + } + if (!(prot & KVM_PGTABLE_PROT_X)) attr |= KVM_PTE_LEAF_ATTR_HI_S2_XN; - else if (device) - return -EINVAL; if (prot & KVM_PGTABLE_PROT_R) attr |= KVM_PTE_LEAF_ATTR_LO_S2_S2AP_R; -- Gitee From 0cf6f16087375e65cd52aeda7847f288abcc0b31 Mon Sep 17 00:00:00 2001 From: Ankit Agrawal Date: Wed, 23 Jul 2025 16:44:58 +0800 Subject: [PATCH 112/155] linux/mm: Introduce new flag to indicate wc safe The VM_ALLOW_ANY_UNCACHED flag is implemented for ARM64, allowing KVM stage 2 device mapping attributes to use NormalNC rather than DEVICE_nGnRE, which allows guest mappings supporting write-combining attributes (WC). ARM does not architecturally guarantee this is safe, and indeed some MMIO regions like the GICv2 VCPU interface can trigger uncontained faults if NormalNC is used. Even worse, the expectation is that there are platforms where even DEVICE_nGnRE can allow uncontained faults in corner cases. Unfortunately existing ARM IP requires platform integration to take responsibility to prevent this. To safely use VFIO in KVM the platform must guarantee full safety in the guest where no action taken against a MMIO mapping can trigger an uncontained failure. The assumption is that most VFIO PCI platforms support this for both mapping types, at least in common flows, based on some expectations of how PCI IP is integrated. This can be enabled more broadly, for instance into vfio-platform drivers, but only after the platform vendor completes auditing for safety. The VMA flag VM_ALLOW_ANY_UNCACHED was found to be the simplest and cleanest way to communicate the information from VFIO to KVM that mapping the region in S2 as NormalNC is safe. KVM consumes it to activate the code that does the S2 mapping as NormalNC. Mainline: NA (cherry picked from commit 5c656fcdd6c60f71fccb07fe7b9d8d7e6c9811ff) Suggested-by: Catalin Marinas Reviewed-by: Jason Gunthorpe Reviewed-by: Marc Zyngier Acked-by: David Hildenbrand Signed-off-by: Ankit Agrawal Backported-by: Li Hao Signed-off-by: Wang Yinfeng Change-Id: I37bc3cc3614aacd984fa21964da3d875940d8923 --- include/linux/mm.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/include/linux/mm.h b/include/linux/mm.h index b6a4d6471b..5824f90c18 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -397,6 +397,20 @@ extern unsigned int kobjsize(const void *objp); # define VM_UFFD_MINOR VM_NONE #endif /* CONFIG_HAVE_ARCH_USERFAULTFD_MINOR */ +/* + * This flag is used to connect VFIO to arch specific KVM code. It + * indicates that the memory under this VMA is safe for use with any + * non-cachable memory type inside KVM. Some VFIO devices, on some + * platforms, are thought to be unsafe and can cause machine crashes + * if KVM does not lock down the memory type. + */ +#ifdef CONFIG_64BIT +#define VM_ALLOW_ANY_UNCACHED_BIT 39 +#define VM_ALLOW_ANY_UNCACHED BIT(VM_ALLOW_ANY_UNCACHED_BIT) +#else +#define VM_ALLOW_ANY_UNCACHED VM_NONE +#endif + /* Bits set in the VMA until the stack is in its final location */ #define VM_STACK_INCOMPLETE_SETUP (VM_RAND_READ | VM_SEQ_READ | VM_STACK_EARLY) -- Gitee From 35159363ac469f8702b31d2999f52a5611789aea Mon Sep 17 00:00:00 2001 From: Ankit Agrawal Date: Wed, 23 Jul 2025 16:53:50 +0800 Subject: [PATCH 113/155] KVM: arm64: Set io memory s2 pte as normalnc for vfio pci device To provide VM with the ability to get device IO memory with NormalNC property, map device MMIO in KVM for ARM64 at stage2 as NormalNC. Having NormalNC S2 default puts guests in control (based on [1], "Combining stage 1 and stage 2 memory type attributes") of device MMIO regions memory mappings. The rules are summarized below: ([(S1) - stage1], [(S2) - stage 2]) S1 | S2 | Result NORMAL-WB | NORMAL-NC | NORMAL-NC NORMAL-WT | NORMAL-NC | NORMAL-NC NORMAL-NC | NORMAL-NC | NORMAL-NC DEVICE | NORMAL-NC | DEVICE Still this cannot be generalized to non PCI devices such as GICv2. There is insufficient information and uncertainity in the behavior of non PCI driver. A driver must indicate support using the new flag VM_ALLOW_ANY_UNCACHED. Adapt KVM to make use of the flag VM_ALLOW_ANY_UNCACHED as indicator to activate the S2 setting to NormalNc. [1] section D8.5.5 of DDI0487J_a_a-profile_architecture_reference_manual.pdf Mainline: NA (cherry picked from commit 8c47ce3e1d2c285349edf426b98e8460ce3e2f33) Suggested-by: Catalin Marinas Acked-by: Jason Gunthorpe Reviewed-by: Catalin Marinas Reviewed-by: Marc Zyngier Signed-off-by: Ankit Agrawal Backported-by: Li Hao Signed-off-by: Wang Yinfeng Change-Id: Ie83a14cc40c9a1efce364fe47b6a456e0bbe2ffa --- arch/arm64/kvm/mmu.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c index 482280fe22..1226d95af1 100644 --- a/arch/arm64/kvm/mmu.c +++ b/arch/arm64/kvm/mmu.c @@ -1398,7 +1398,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, int ret = 0; bool write_fault, writable, force_pte = false; bool exec_fault, mte_allowed; - bool device = false; + bool device = false, vfio_allow_any_uc = false; unsigned long mmu_seq; struct kvm *kvm = vcpu->kvm; struct kvm_mmu_memory_cache *memcache = &vcpu->arch.mmu_page_cache; @@ -1490,6 +1490,8 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, gfn = fault_ipa >> PAGE_SHIFT; mte_allowed = kvm_vma_mte_allowed(vma); + vfio_allow_any_uc = vma->vm_flags & VM_ALLOW_ANY_UNCACHED; + /* Don't use the VMA after the unlock -- it may have vanished */ vma = NULL; @@ -1576,10 +1578,15 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, if (exec_fault) prot |= KVM_PGTABLE_PROT_X; - if (device) - prot |= KVM_PGTABLE_PROT_DEVICE; - else if (cpus_have_const_cap(ARM64_HAS_CACHE_DIC)) + if (device) { + if (vfio_allow_any_uc) + prot |= KVM_PGTABLE_PROT_NORMAL_NC; + else + prot |= KVM_PGTABLE_PROT_DEVICE; + } else if (cpus_have_final_cap(ARM64_HAS_CACHE_DIC)) { prot |= KVM_PGTABLE_PROT_X; + } + /* * Under the premise of getting a FSC_PERM fault, we just need to relax -- Gitee From df6c0e4d8586f2cd981cec57c49fdb132b4f0ac8 Mon Sep 17 00:00:00 2001 From: Ankit Agrawal Date: Wed, 23 Jul 2025 16:55:50 +0800 Subject: [PATCH 114/155] vfio: Convey kvm that the vfio-pci device is wc safe The VM_ALLOW_ANY_UNCACHED flag is implemented for ARM64, allowing KVM stage 2 device mapping attributes to use Normal-NC rather than DEVICE_nGnRE, which allows guest mappings supporting write-combining attributes (WC). ARM does not architecturally guarantee this is safe, and indeed some MMIO regions like the GICv2 VCPU interface can trigger uncontained faults if Normal-NC is used. To safely use VFIO in KVM the platform must guarantee full safety in the guest where no action taken against a MMIO mapping can trigger an uncontained failure. The expectation is that most VFIO PCI platforms support this for both mapping types, at least in common flows, based on some expectations of how PCI IP is integrated. So make vfio-pci set the VM_ALLOW_ANY_UNCACHED flag. Mainline: NA (cherry picked from commit a39d3a966a090989b89c0287a67cd98c85ae2f52) Suggested-by: Catalin Marinas Acked-by: Jason Gunthorpe Acked-by: Catalin Marinas Acked-by: Alex Williamson Reviewed-by: David Hildenbrand Reviewed-by: Marc Zyngier Signed-off-by: Ankit Agrawal Backported-by: Li Hao Signed-off-by: Wang Yinfeng Change-Id: Ie91f778fb7770f0130c84cb95b3bc40f896f3b89 --- drivers/vfio/pci/vfio_pci_core.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/drivers/vfio/pci/vfio_pci_core.c b/drivers/vfio/pci/vfio_pci_core.c index a8f259bc2f..2df176edc6 100644 --- a/drivers/vfio/pci/vfio_pci_core.c +++ b/drivers/vfio/pci/vfio_pci_core.c @@ -1882,8 +1882,25 @@ int vfio_pci_core_mmap(struct vfio_device *core_vdev, struct vm_area_struct *vma /* * See remap_pfn_range(), called from vfio_pci_fault() but we can't * change vm_flags within the fault handler. Set them now. + * + * VM_ALLOW_ANY_UNCACHED: The VMA flag is implemented for ARM64, + * allowing KVM stage 2 device mapping attributes to use Normal-NC + * rather than DEVICE_nGnRE, which allows guest mappings + * supporting write-combining attributes (WC). ARM does not + * architecturally guarantee this is safe, and indeed some MMIO + * regions like the GICv2 VCPU interface can trigger uncontained + * faults if Normal-NC is used. + * + * To safely use VFIO in KVM the platform must guarantee full + * safety in the guest where no action taken against a MMIO + * mapping can trigger an uncontained failure. The assumption is + * that most VFIO PCI platforms support this for both mapping types, + * at least in common flows, based on some expectations of how + * PCI IP is integrated. Hence VM_ALLOW_ANY_UNCACHED is set in + * the VMA flags. */ - vm_flags_set(vma, VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP); + vm_flags_set(vma, VM_ALLOW_ANY_UNCACHED | VM_IO | VM_PFNMAP | + VM_DONTEXPAND | VM_DONTDUMP); vma->vm_ops = &vfio_pci_mmap_ops; return 0; -- Gitee From 8e3df9f238964a1872460bf3234e8067315091f3 Mon Sep 17 00:00:00 2001 From: Li Hao Date: Wed, 23 Jul 2025 17:12:17 +0800 Subject: [PATCH 115/155] virt/kvm: Optimized a slow startup of a large VM with huge pages Due to Phytium CPU's cache consistency support, just flush d-cache on one vCPU not all vcpus in the VM. This can reduce the number of flush d-caches and improve the efficiency of SMP multi-core startup, especiallyfor a large VM with hugepages. Mainline: NA Signed-off-by: Li Hao Signed-off-by: Wang Yinfeng Change-Id: Ied8c1c656a4b447a8d56cae23e9f58e39fb53d6d --- arch/arm64/kvm/mmu.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c index 1226d95af1..6876400b34 100644 --- a/arch/arm64/kvm/mmu.c +++ b/arch/arm64/kvm/mmu.c @@ -2154,8 +2154,20 @@ void kvm_toggle_cache(struct kvm_vcpu *vcpu, bool was_enabled) * If switching it off, need to clean the caches. * Clean + invalidate does the trick always. */ - if (now_enabled != was_enabled) - stage2_flush_vm(vcpu->kvm); + if (now_enabled != was_enabled) { + /* + * Due to Phytium CPU's cache consistency support, + * just flush dcache on one vcpu not all vcpus in the VM. + * This can reduce the number of flush dcaches and + * improve the efficiency of SMP multi-core startup, + * especially for the large VM with hugepages. + */ + if (read_cpuid_implementor() == ARM_CPU_IMP_PHYTIUM) { + if (vcpu->vcpu_id == 0) + stage2_flush_vm(vcpu->kvm); + } else + stage2_flush_vm(vcpu->kvm); + } /* Caches are now on, stop trapping VM ops (until a S/W op) */ if (now_enabled) -- Gitee From 7d767eb17d14ef967bf9d82404253d1a2fd012b2 Mon Sep 17 00:00:00 2001 From: Zou Wei Date: Wed, 23 Jul 2025 17:18:56 +0800 Subject: [PATCH 116/155] virt/kvm: Solve the softlock problem after live migration of a VM with huge pages If it's a VM with huge pages after live migration, other vCPUs do not need to refresh i-cache because of the CMO mechanism. Mainline: NA Signed-off-by: Zou Wei Signed-off-by: Li Hao Signed-off-by: Wang Yinfeng Change-Id: I61da97ff85aebddc2b8544f194c61bc5da04c2c2 --- arch/arm64/kvm/hyp/pgtable.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/arch/arm64/kvm/hyp/pgtable.c b/arch/arm64/kvm/hyp/pgtable.c index b0586d79d2..1af8912ce9 100644 --- a/arch/arm64/kvm/hyp/pgtable.c +++ b/arch/arm64/kvm/hyp/pgtable.c @@ -1175,6 +1175,20 @@ struct stage2_attr_data { u32 level; }; +static inline bool post_migration_huge(kvm_pte_t pte, kvm_pte_t old_pte, + u32 level) +{ + /* + * Based on pagesize and PTE permissions(read, write and execute), + * determine whether it is a huge pagesize VM live migration. + */ + return (kvm_granule_size(level) > PAGE_SIZE + && (pte & KVM_PTE_LEAF_ATTR_LO_S2_S2AP_R) + && (pte & KVM_PTE_LEAF_ATTR_LO_S2_S2AP_W) + && stage2_pte_executable(pte) + && !stage2_pte_executable(old_pte)); +} + static int stage2_attr_walker(const struct kvm_pgtable_visit_ctx *ctx, enum kvm_pgtable_walk_flags visit) { @@ -1196,6 +1210,16 @@ static int stage2_attr_walker(const struct kvm_pgtable_visit_ctx *ctx, * set on the next access instead. */ if (data->pte != pte) { + /* + * if it's a huge page VM after live migration, other + * vCPUs do not need to refresh icache because of the + * CMO mechanism. + */ + if (read_cpuid_implementor() == ARM_CPU_IMP_PHYTIUM) { + if (post_migration_huge(pte, ctx->old, ctx->level)) + goto set_pte; + } + /* * Invalidate instruction cache before updating the guest * stage-2 PTE if we are going to add executable permission. @@ -1205,6 +1229,7 @@ static int stage2_attr_walker(const struct kvm_pgtable_visit_ctx *ctx, mm_ops->icache_inval_pou(kvm_pte_follow(pte, mm_ops), kvm_granule_size(ctx->level)); +set_pte: if (!stage2_try_set_pte(ctx, pte)) return -EAGAIN; } -- Gitee From cb1a9a9a4ed72403d6f4d91ad5e0ac303fde2e22 Mon Sep 17 00:00:00 2001 From: James Morse Date: Thu, 7 Aug 2025 17:48:06 +0800 Subject: [PATCH 117/155] x86: intel_epb Don't rely on link order intel_epb_init() is called as a subsys_initcall() to register cpuhp callbacks. The callbacks make use of get_cpu_device() which will return NULL unless register_cpu() has been called. register_cpu() is called from topology_init(), which is also a subsys_initcall(). This is fragile. Moving the register_cpu() to a different subsys_initcall() leads to a NULL dereference during boot. Make intel_epb_init() a late_initcall(), user-space can't provide a policy before this point anyway. Mainline: NA (cherry picked from commit c268384c04ed14c9c4ea266526f5578dcb7ddde3) Signed-off-by: James Morse Reviewed-by: Gavin Shan Signed-off-by: Russell King (Oracle) Acked-by: Rafael J. Wysocki Reviewed-by: Thomas Gleixner Link: https://lore.kernel.org/r/E1r5R2m-00Csyb-2S@rmk-PC.armlinux.org.uk Signed-off-by: Greg Kroah-Hartman Signed-off-by: Li Wei Backported-by: Wu Chen Signed-off-by: Wang Yinfeng Change-Id: Ib91f3ed9e43f2e8e3d1b2d154e572e6794a32502 --- arch/x86/kernel/cpu/intel_epb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kernel/cpu/intel_epb.c b/arch/x86/kernel/cpu/intel_epb.c index e4c3ba9132..f18d35fe27 100644 --- a/arch/x86/kernel/cpu/intel_epb.c +++ b/arch/x86/kernel/cpu/intel_epb.c @@ -237,4 +237,4 @@ static __init int intel_epb_init(void) cpuhp_remove_state(CPUHP_AP_X86_INTEL_EPB_ONLINE); return ret; } -subsys_initcall(intel_epb_init); +late_initcall(intel_epb_init); -- Gitee From 5e7cfda345c908cfa64b5fb5029edb066a61dd67 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Thu, 7 Aug 2025 17:55:59 +0800 Subject: [PATCH 118/155] x86: Topology Remove arch_*register_cpu() exports arch_register_cpu() and arch_unregister_cpu() are not used by anything that can be a module - they are used by drivers/base/cpu.c and drivers/acpi/acpi_processor.c, neither of which can be a module. Remove the exports. Mainline: NA (cherry picked from commit eec386129866404497a0636f884ea790cd898153) Reviewed-by: Gavin Shan Signed-off-by: Russell King (Oracle) Reviewed-by: Jonathan Cameron Reviewed-by: Thomas Gleixner Link: https://lore.kernel.org/r/E1r5R2r-00Csyh-7B@rmk-PC.armlinux.org.uk Signed-off-by: Greg Kroah-Hartman Signed-off-by: Li Wei Backported-by: Wu Chen Signed-off-by: Wang Yinfeng Change-Id: I77fb7bab5b3b1243237af4209e176e2e603836eb --- arch/x86/kernel/topology.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/x86/kernel/topology.c b/arch/x86/kernel/topology.c index 0bab031300..fcb62cfdf9 100644 --- a/arch/x86/kernel/topology.c +++ b/arch/x86/kernel/topology.c @@ -45,13 +45,11 @@ int arch_register_cpu(int cpu) xc->cpu.hotpluggable = cpu > 0; return register_cpu(&xc->cpu, cpu); } -EXPORT_SYMBOL(arch_register_cpu); void arch_unregister_cpu(int num) { unregister_cpu(&per_cpu(cpu_devices, num).cpu); } -EXPORT_SYMBOL(arch_unregister_cpu); #else /* CONFIG_HOTPLUG_CPU */ int __init arch_register_cpu(int num) -- Gitee From 9d37b8a75e6b8f3c7e307b5b98b5da63f9cbbc1a Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Thu, 7 Aug 2025 17:58:57 +0800 Subject: [PATCH 119/155] Loongarch: remove arch_*register_cpu() exports arch_register_cpu() and arch_unregister_cpu() are not used by anything that can be a module - they are used by drivers/base/cpu.c and drivers/acpi/acpi_processor.c, neither of which can be a module. Remove the exports. Mainline: NA (cherry picked from commit b4747245d876c8a6f66b5ae706c734cec364823c) Reviewed-by: Gavin Shan Signed-off-by: Russell King (Oracle) Reviewed-by: Jonathan Cameron Reviewed-by: Thomas Gleixner Link: https://lore.kernel.org/r/E1r5R2w-00Csyn-E2@rmk-PC.armlinux.org.uk Signed-off-by: Greg Kroah-Hartman Signed-off-by: Li Wei Backported-by: Wu Chen Signed-off-by: Wang Yinfeng Change-Id: I1dcef6416563b5d165236afacb1923ffd3b170e8 --- arch/loongarch/kernel/topology.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/loongarch/kernel/topology.c b/arch/loongarch/kernel/topology.c index 3fd1660066..ae860fe815 100644 --- a/arch/loongarch/kernel/topology.c +++ b/arch/loongarch/kernel/topology.c @@ -25,7 +25,6 @@ int arch_register_cpu(int cpu) return ret; } -EXPORT_SYMBOL(arch_register_cpu); void arch_unregister_cpu(int cpu) { @@ -34,7 +33,6 @@ void arch_unregister_cpu(int cpu) c->hotpluggable = 0; unregister_cpu(c); } -EXPORT_SYMBOL(arch_unregister_cpu); #endif static int __init topology_init(void) -- Gitee From aaa253f5d78140a004259e85e1009d9760c185ea Mon Sep 17 00:00:00 2001 From: James Morse Date: Thu, 7 Aug 2025 18:04:35 +0800 Subject: [PATCH 120/155] ACPI: Move ACPI_HOTPLUG_CPU to be disabled on x86/loongarch Neither arm64 nor riscv support physical hotadd of CPUs that were not present at boot. For arm64 much of the platform description is in static tables which do not have update methods. arm64 does support HOTPLUG_CPU, which is backed by a firmware interface to turn CPUs on and off. acpi_processor_hotadd_init() and acpi_processor_remove() are for adding and removing CPUs that were not present at boot. arm64 systems that do this are not supported as there is currently insufficient information in the platform description. (e.g. did the GICR get removed too?) arm64 currently relies on the MADT enabled flag check in map_gicc_mpidr() to prevent CPUs that were not described as present at boot from being added to the system. Similarly, riscv relies on the same check in map_rintc_hartid(). Both architectures also rely on the weak 'always fails' definitions of acpi_map_cpu() and arch_register_cpu(). Subsequent changes will redefine ACPI_HOTPLUG_CPU as making possible CPUs present. Neither arm64 nor riscv support this. Disable ACPI_HOTPLUG_CPU for arm64 and riscv by removing 'default y' and selecting it on the other three ACPI architectures. This allows the weak definitions of some symbols to be removed. Mainline: NA (cherry picked and rework from commit 8441c7c97519cc743e945db3352464f555225226) Signed-off-by: James Morse Reviewed-by: Shaoqin Huang Reviewed-by: Gavin Shan Signed-off-by: Russell King (Oracle) Reviewed-by: Jonathan Cameron Reviewed-by: Thomas Gleixner Link: https://lore.kernel.org/r/E1r5R31-00Csyt-Jq@rmk-PC.armlinux.org.uk Signed-off-by: Greg Kroah-Hartman Signed-off-by: Li Wei Backported-by: Wu Chen Signed-off-by: Wang Yinfeng Change-Id: Ib1bb1784cf4b3c48501b0ba64d4b65a448fb0679 --- arch/loongarch/Kconfig | 1 + arch/x86/Kconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig index 9fd8644a9a..ea5f37e87c 100644 --- a/arch/loongarch/Kconfig +++ b/arch/loongarch/Kconfig @@ -5,6 +5,7 @@ config LOONGARCH select ACPI select ACPI_GENERIC_GSI if ACPI select ACPI_MCFG if ACPI + select ACPI_HOTPLUG_CPU if ACPI_PROCESSOR && HOTPLUG_CPU select ACPI_PPTT if ACPI select ACPI_SYSTEM_POWER_STATES_SUPPORT if ACPI select ARCH_BINFMT_ELF_STATE diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 05c82fd5d0..924e3e1e8d 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -60,6 +60,7 @@ config X86 # select ACPI_LEGACY_TABLES_LOOKUP if ACPI select ACPI_SYSTEM_POWER_STATES_SUPPORT if ACPI + select ACPI_HOTPLUG_CPU if ACPI_PROCESSOR && HOTPLUG_CPU select ARCH_32BIT_OFF_T if X86_32 select ARCH_CLOCKSOURCE_INIT select ARCH_CONFIGURES_CPU_MITIGATIONS -- Gitee From 266dd5e55643a7cfbcea220ae6b73162a86e6e42 Mon Sep 17 00:00:00 2001 From: James Morse Date: Thu, 7 Aug 2025 18:08:24 +0800 Subject: [PATCH 121/155] x86: Topology Switch over to GENERIC_CPU_DEVICES Now that GENERIC_CPU_DEVICES calls arch_register_cpu(), which can be overridden by the arch code, switch over to this to allow common code to choose when the register_cpu() call is made. x86's struct cpus come from struct x86_cpu, which has no other members or users. Remove this and use the version defined by common code. This is an intermediate step to the logic being moved to drivers/acpi, where GENERIC_CPU_DEVICES will do the work when booting with acpi=off. This patch also has the effect of moving the registration of CPUs from subsys to driver core initialisation, prior to any initcalls running. Mainline: NA (cherry picked from commit 8e648c011f34e201f480da775eb00469fa735e07) Signed-off-by: James Morse Reviewed-by: Shaoqin Huang Reviewed-by: Gavin Shan Signed-off-by: Russell King (Oracle) Reviewed-by: Jonathan Cameron Reviewed-by: Thomas Gleixner Link: https://lore.kernel.org/r/E1r5R31-00Csyt-Jq@rmk-PC.armlinux.org.uk Signed-off-by: Greg Kroah-Hartman Signed-off-by: Li Wei Backported-by: Wu Chen Signed-off-by: Wang Yinfeng Change-Id: I700fd069a2c35d43f66fe9fbf59eedc5cb081f0b --- arch/x86/Kconfig | 1 + arch/x86/include/asm/cpu.h | 4 ---- arch/x86/kernel/topology.c | 27 ++++----------------------- 3 files changed, 5 insertions(+), 27 deletions(-) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 924e3e1e8d..0f9bab72ce 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -149,6 +149,7 @@ config X86 select GENERIC_CLOCKEVENTS_MIN_ADJUST select GENERIC_CMOS_UPDATE select GENERIC_CPU_AUTOPROBE + select GENERIC_CPU_DEVICES select GENERIC_CPU_VULNERABILITIES select GENERIC_EARLY_IOREMAP select GENERIC_ENTRY diff --git a/arch/x86/include/asm/cpu.h b/arch/x86/include/asm/cpu.h index 25050d953e..91867a6a9f 100644 --- a/arch/x86/include/asm/cpu.h +++ b/arch/x86/include/asm/cpu.h @@ -23,10 +23,6 @@ static inline void prefill_possible_map(void) {} #endif /* CONFIG_SMP */ -struct x86_cpu { - struct cpu cpu; -}; - #ifdef CONFIG_HOTPLUG_CPU extern void soft_restart_cpu(void); #endif diff --git a/arch/x86/kernel/topology.c b/arch/x86/kernel/topology.c index fcb62cfdf9..c2ed3145a9 100644 --- a/arch/x86/kernel/topology.c +++ b/arch/x86/kernel/topology.c @@ -35,36 +35,17 @@ #include #include -static DEFINE_PER_CPU(struct x86_cpu, cpu_devices); - #ifdef CONFIG_HOTPLUG_CPU int arch_register_cpu(int cpu) { - struct x86_cpu *xc = per_cpu_ptr(&cpu_devices, cpu); + struct cpu *c = per_cpu_ptr(&cpu_devices, cpu); - xc->cpu.hotpluggable = cpu > 0; - return register_cpu(&xc->cpu, cpu); + c->hotpluggable = cpu > 0; + return register_cpu(c, cpu); } void arch_unregister_cpu(int num) { - unregister_cpu(&per_cpu(cpu_devices, num).cpu); -} -#else /* CONFIG_HOTPLUG_CPU */ - -int __init arch_register_cpu(int num) -{ - return register_cpu(&per_cpu(cpu_devices, num).cpu, num); + unregister_cpu(&per_cpu(cpu_devices, num)); } #endif /* CONFIG_HOTPLUG_CPU */ - -static int __init topology_init(void) -{ - int i; - - for_each_present_cpu(i) - arch_register_cpu(i); - - return 0; -} -subsys_initcall(topology_init); -- Gitee From df1c349015f5413841f90172dd4d52f35196632e Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Thu, 7 Aug 2025 18:13:52 +0800 Subject: [PATCH 122/155] x86: Topology use weak version of arch_unregister_cpu() Since the x86 version of arch_unregister_cpu() is the same as the weak version, drop the x86 specific version. Mainline: NA (cherry picked from commit c99226aa87fe47c4707224b66e3d763125c678d5) Reviewed-by: Gavin Shan Signed-off-by: Russell King (Oracle) Reviewed-by: Jonathan Cameron Reviewed-by: Thomas Gleixner Link: https://lore.kernel.org/r/E1r5R3r-00Cszs-2R@rmk-PC.armlinux.org.uk Signed-off-by: Greg Kroah-Hartman Signed-off-by: Li Wei Backported-by: Wu Chen Signed-off-by: Wang Yinfeng Change-Id: I6b4bf8ed2c9092c5787f4ce4ef716f0cfe508d0a --- arch/x86/kernel/topology.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/arch/x86/kernel/topology.c b/arch/x86/kernel/topology.c index c2ed3145a9..211863cb5b 100644 --- a/arch/x86/kernel/topology.c +++ b/arch/x86/kernel/topology.c @@ -43,9 +43,4 @@ int arch_register_cpu(int cpu) c->hotpluggable = cpu > 0; return register_cpu(c, cpu); } - -void arch_unregister_cpu(int num) -{ - unregister_cpu(&per_cpu(cpu_devices, num)); -} #endif /* CONFIG_HOTPLUG_CPU */ -- Gitee From 5e2d481634cc1d405445e0b2fa022f4740589bd4 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Thu, 7 Aug 2025 18:15:42 +0800 Subject: [PATCH 123/155] x86/topology: convert to use arch_cpu_is_hotpluggable() Convert x86 to use the arch_cpu_is_hotpluggable() helper rather than arch_register_cpu(). Mainline: NA (cherry picked from commit 584ef75057c33ca394db70431f228aa0d614c981) Reviewed-by: Gavin Shan Signed-off-by: Russell King (Oracle) Reviewed-by: Jonathan Cameron Reviewed-by: Thomas Gleixner Link: https://lore.kernel.org/r/E1r5R3w-00Cszy-6k@rmk-PC.armlinux.org.uk Signed-off-by: Greg Kroah-Hartman Signed-off-by: Li Wei Backported-by: Wu Chen Signed-off-by: Wang Yinfeng Change-Id: Ief99b73040d78e87ba8690674f465826f68ab371 --- arch/x86/kernel/topology.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/arch/x86/kernel/topology.c b/arch/x86/kernel/topology.c index 211863cb5b..d42c28b8bf 100644 --- a/arch/x86/kernel/topology.c +++ b/arch/x86/kernel/topology.c @@ -36,11 +36,8 @@ #include #ifdef CONFIG_HOTPLUG_CPU -int arch_register_cpu(int cpu) +bool arch_cpu_is_hotpluggable(int cpu) { - struct cpu *c = per_cpu_ptr(&cpu_devices, cpu); - - c->hotpluggable = cpu > 0; - return register_cpu(c, cpu); + return cpu > 0; } #endif /* CONFIG_HOTPLUG_CPU */ -- Gitee From 48db12194087de4989e2fa113e13df4e14ceca3d Mon Sep 17 00:00:00 2001 From: James Morse Date: Wed, 6 Aug 2025 16:53:00 +0800 Subject: [PATCH 124/155] LoongArch: Switch over to GENERIC_CPU_DEVICES Now that GENERIC_CPU_DEVICES calls arch_register_cpu(), which can be overridden by the arch code, switch over to this to allow common code to choose when the register_cpu() call is made. This allows topology_init() to be removed. This is an intermediate step to the logic being moved to drivers/acpi, where GENERIC_CPU_DEVICES will do the work when booting with acpi=off. This is a subtle change. Originally: - on boot, topology_init() would have marked present CPUs that io_master() is true for as hotplug-incapable. - if a CPU is hotplugged that is an io_master(), it can later be hot-unplugged. The new behaviour is that any CPU that io_master() is true for will now always be marked as hotplug-incapable, thus even if it was hotplugged, it can no longer be hot-unplugged. This patch also has the effect of moving the registration of CPUs from subsys to driver core initialisation, prior to any initcalls running. Mainline: NA (cherry picked from commit 7a8dab0d1f42917f348910d6b5b551adc3958a42) Signed-off-by: James Morse Reviewed-by: Gavin Shan Signed-off-by: Russell King (Oracle) Reviewed-by: Jonathan Cameron Reviewed-by: Thomas Gleixner Link: https://lore.kernel.org/r/E1r5R41-00Ct04-Bg@rmk-PC.armlinux.org.uk Signed-off-by: Greg Kroah-Hartman Signed-off-by: Li Wei Backported-by: Wu Chen Signed-off-by: Wang Yinfeng Change-Id: I40385f08d71e4b7579e5351f565f2af4d30b4fa5 --- arch/loongarch/Kconfig | 1 + arch/loongarch/kernel/topology.c | 29 ++--------------------------- 2 files changed, 3 insertions(+), 27 deletions(-) diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig index ea5f37e87c..5533e33074 100644 --- a/arch/loongarch/Kconfig +++ b/arch/loongarch/Kconfig @@ -73,6 +73,7 @@ config LOONGARCH select GENERIC_CLOCKEVENTS select GENERIC_CMOS_UPDATE select GENERIC_CPU_AUTOPROBE + select GENERIC_CPU_DEVICES select GENERIC_ENTRY select GENERIC_GETTIMEOFDAY select GENERIC_IOREMAP if !ARCH_IOREMAP diff --git a/arch/loongarch/kernel/topology.c b/arch/loongarch/kernel/topology.c index ae860fe815..7dfb46c68f 100644 --- a/arch/loongarch/kernel/topology.c +++ b/arch/loongarch/kernel/topology.c @@ -10,20 +10,13 @@ #include -static DEFINE_PER_CPU(struct cpu, cpu_devices); - #ifdef CONFIG_HOTPLUG_CPU int arch_register_cpu(int cpu) { - int ret; struct cpu *c = &per_cpu(cpu_devices, cpu); - c->hotpluggable = 1; - ret = register_cpu(c, cpu); - if (ret < 0) - pr_warn("register_cpu %d failed (%d)\n", cpu, ret); - - return ret; + c->hotpluggable = !io_master(cpu); + return register_cpu(c, cpu); } void arch_unregister_cpu(int cpu) @@ -34,21 +27,3 @@ void arch_unregister_cpu(int cpu) unregister_cpu(c); } #endif - -static int __init topology_init(void) -{ - int i, ret; - - for_each_present_cpu(i) { - struct cpu *c = &per_cpu(cpu_devices, i); - - c->hotpluggable = !io_master(i); - ret = register_cpu(c, i); - if (ret < 0) - pr_warn("topology_init: register_cpu %d failed (%d)\n", i, ret); - } - - return 0; -} - -subsys_initcall(topology_init); -- Gitee From b7eda7da09899e686df7f80eb6b4d5ac0f9b07ec Mon Sep 17 00:00:00 2001 From: James Morse Date: Wed, 6 Aug 2025 17:02:43 +0800 Subject: [PATCH 125/155] LoongArch: Use the weak version of arch_unregister_cpu() LoongArch provides its own arch_unregister_cpu(). This clears the hotpluggable flag, then unregisters the CPU. It isn't necessary to clear the hotpluggable flag when unregistering a cpu. unregister_cpu() writes NULL to the percpu cpu_sys_devices pointer, meaning cpu_is_hotpluggable() will return false, as get_cpu_device() has returned NULL. Remove arch_unregister_cpu() and use the __weak version. Mainline: NA (cherry picked from commit 90f5e8c5781f497595b098ba5c62b7affbaa26e9) Signed-off-by: James Morse Reviewed-by: Jonathan Cameron Reviewed-by: Gavin Shan Signed-off-by: Russell King (Oracle) Reviewed-by: Thomas Gleixner Link: https://lore.kernel.org/r/E1r5R46-00Ct0A-GJ@rmk-PC.armlinux.org.uk Signed-off-by: Greg Kroah-Hartman Signed-off-by: Li Wei Backported-by: Wu Chen Signed-off-by: Wang Yinfeng Change-Id: Ie8249ad562e963c48e2a940d2326bc26b74462ac --- arch/loongarch/kernel/topology.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/arch/loongarch/kernel/topology.c b/arch/loongarch/kernel/topology.c index 7dfb46c68f..866c2c9ef6 100644 --- a/arch/loongarch/kernel/topology.c +++ b/arch/loongarch/kernel/topology.c @@ -18,12 +18,4 @@ int arch_register_cpu(int cpu) c->hotpluggable = !io_master(cpu); return register_cpu(c, cpu); } - -void arch_unregister_cpu(int cpu) -{ - struct cpu *c = &per_cpu(cpu_devices, cpu); - - c->hotpluggable = 0; - unregister_cpu(c); -} #endif -- Gitee From 5233d853acc5f544529545b713d5edc0340bd3f6 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Wed, 6 Aug 2025 17:05:06 +0800 Subject: [PATCH 126/155] LoongArch: convert to use arch_cpu_is_hotpluggable() Convert loongarch to use the arch_cpu_is_hotpluggable() helper rather than arch_register_cpu(). Also remove the export as nothing should be using arch_register_cpu() outside of the core kernel/acpi code. Mainline: NA (cherry picked from commit 5b77fe2e54da793ba85704bcfb33a40134464d26) Reviewed-by: Gavin Shan Signed-off-by: Russell King (Oracle) Reviewed-by: Jonathan Cameron Reviewed-by: Thomas Gleixner Link: https://lore.kernel.org/r/E1r5R4B-00Ct0G-Kk@rmk-PC.armlinux.org.uk Signed-off-by: Greg Kroah-Hartman Signed-off-by: Li Wei Backported-by: Wu Chen Signed-off-by: Wang Yinfeng Change-Id: Ibd3ffd90e90cd11b634739afae32b2d816ce9111 --- arch/loongarch/kernel/topology.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/arch/loongarch/kernel/topology.c b/arch/loongarch/kernel/topology.c index 866c2c9ef6..75d5c51a7c 100644 --- a/arch/loongarch/kernel/topology.c +++ b/arch/loongarch/kernel/topology.c @@ -11,11 +11,8 @@ #include #ifdef CONFIG_HOTPLUG_CPU -int arch_register_cpu(int cpu) +bool arch_cpu_is_hotpluggable(int cpu) { - struct cpu *c = &per_cpu(cpu_devices, cpu); - - c->hotpluggable = !io_master(cpu); - return register_cpu(c, cpu); + return !io_master(cpu); } #endif -- Gitee From a2512a27bec371d26a7fee19feb3613fedc5c0d7 Mon Sep 17 00:00:00 2001 From: James Morse Date: Wed, 6 Aug 2025 17:09:50 +0800 Subject: [PATCH 127/155] riscv: Switch over to GENERIC_CPU_DEVICES Now that GENERIC_CPU_DEVICES calls arch_register_cpu(), which can be overridden by the arch code, switch over to this to allow common code to choose when the register_cpu() call is made. This allows topology_init() to be removed. This is an intermediate step to the logic being moved to drivers/acpi, where GENERIC_CPU_DEVICES will do the work when booting with acpi=off. This patch also has the effect of moving the registration of CPUs from subsys to driver core initialisation, prior to any initcalls running. (cherry picked from commit e785b5a370b27f205a756ec2a87223540b8e1757) Signed-off-by: James Morse Reviewed-by: Jonathan Cameron Acked-by: Palmer Dabbelt Reviewed-by: Gavin Shan Signed-off-by: Russell King (Oracle) Reviewed-by: Samuel Holland Tested-by: Samuel Holland Reviewed-by: Thomas Gleixner Link: https://lore.kernel.org/r/E1r5R4G-00Ct0M-PS@rmk-PC.armlinux.org.uk Signed-off-by: Greg Kroah-Hartman Signed-off-by: Li Wei Backported-by: Wu Chen Change-Id: I2c6f54c68e11bb3413c506dc23dc4d2000c7f577 --- arch/riscv/Kconfig | 1 + arch/riscv/kernel/setup.c | 19 ++++--------------- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 1304992232..bcc8146115 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -70,6 +70,7 @@ config RISCV select GENERIC_ARCH_TOPOLOGY select GENERIC_ATOMIC64 if !64BIT select GENERIC_CLOCKEVENTS_BROADCAST if SMP + select GENERIC_CPU_DEVICES select GENERIC_EARLY_IOREMAP select GENERIC_ENTRY select GENERIC_GETTIMEOFDAY if HAVE_GENERIC_VDSO diff --git a/arch/riscv/kernel/setup.c b/arch/riscv/kernel/setup.c index ddadee6621..e3391a339d 100644 --- a/arch/riscv/kernel/setup.c +++ b/arch/riscv/kernel/setup.c @@ -55,7 +55,6 @@ atomic_t hart_lottery __section(".sdata") #endif ; unsigned long boot_cpu_hartid; -static DEFINE_PER_CPU(struct cpu, cpu_devices); /* * Place kernel memory regions on the resource tree so that @@ -313,23 +312,13 @@ void __init setup_arch(char **cmdline_p) riscv_set_dma_cache_alignment(); } -static int __init topology_init(void) +int arch_register_cpu(int cpu) { - int i, ret; + struct cpu *c = &per_cpu(cpu_devices, cpu); - for_each_possible_cpu(i) { - struct cpu *cpu = &per_cpu(cpu_devices, i); - - cpu->hotpluggable = cpu_has_hotplug(i); - ret = register_cpu(cpu, i); - if (unlikely(ret)) - pr_warn("Warning: %s: register_cpu %d failed (%d)\n", - __func__, i, ret); - } - - return 0; + c->hotpluggable = cpu_has_hotplug(cpu); + return register_cpu(c, cpu); } -subsys_initcall(topology_init); void free_initmem(void) { -- Gitee From bc9d0f8212f7a7f558f4f9f7c18ea6fffce33144 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Wed, 6 Aug 2025 17:16:55 +0800 Subject: [PATCH 128/155] riscv: convert to use arch_cpu_is_hotpluggable() Convert riscv to use the arch_cpu_is_hotpluggable() helper rather than arch_register_cpu(). Mainline: NA (cherry picked from commit 404a20185859d87697a137176b5b91d4e27e1292) Acked-by: Palmer Dabbelt Reviewed-by: Gavin Shan Signed-off-by: Russell King (Oracle) Reviewed-by: Jonathan Cameron Reviewed-by: Samuel Holland Tested-by: Samuel Holland # On HiFive Unmatched Reviewed-by: Thomas Gleixner Link: https://lore.kernel.org/r/E1r5R4L-00Ct0d-To@rmk-PC.armlinux.org.uk Signed-off-by: Greg Kroah-Hartman Signed-off-by: Li Wei Backported-by: Wu Chen Signed-off-by: Wang Yinfeng Change-Id: I5d2df78a9f5cee787776de6bdbf5ba8e09a90605 --- arch/riscv/kernel/setup.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/arch/riscv/kernel/setup.c b/arch/riscv/kernel/setup.c index e3391a339d..1480791e50 100644 --- a/arch/riscv/kernel/setup.c +++ b/arch/riscv/kernel/setup.c @@ -312,12 +312,9 @@ void __init setup_arch(char **cmdline_p) riscv_set_dma_cache_alignment(); } -int arch_register_cpu(int cpu) +bool arch_cpu_is_hotpluggable(int cpu) { - struct cpu *c = &per_cpu(cpu_devices, cpu); - - c->hotpluggable = cpu_has_hotplug(cpu); - return register_cpu(c, cpu); + return cpu_has_hotplug(cpu); } void free_initmem(void) -- Gitee From afae6088905d372673417079c3cbebb1033c4c88 Mon Sep 17 00:00:00 2001 From: James Morse Date: Wed, 6 Aug 2025 17:19:17 +0800 Subject: [PATCH 129/155] ACPI: Rename ACPI_HOTPLUG_CPU to include present on x86/loongarch The code behind ACPI_HOTPLUG_CPU allows a not-present CPU to become present. This isn't the only use of HOTPLUG_CPU. On arm64 and riscv CPUs can be taken offline as a power saving measure. On arm64 an offline CPU may be disabled by firmware, preventing it from being brought back online, but it remains present throughout. Adding code to prevent user-space trying to online these disabled CPUs needs some additional terminology. Rename the Kconfig symbol CONFIG_ACPI_HOTPLUG_PRESENT_CPU to reflect that it makes possible CPUs present. HOTPLUG_CPU is untouched as this is only about the ACPI mechanism. Mainline: NA (cherry picked and rework from commit 2eb3daf61b18d620b0624e31ad44ac1c76d94075) Signed-off-by: James Morse Tested-by: Miguel Luis Tested-by: Vishnu Pajjuri Tested-by: Jianyong Wu Signed-off-by: Russell King (Oracle) Reviewed-by: Jonathan Cameron Backported-by: Wu Chen Signed-off-by: Wang Yinfeng Change-Id: Idc594e2ad2e4f90fa441486759b770b5223e45bb --- arch/loongarch/Kconfig | 2 +- arch/loongarch/kernel/acpi.c | 4 ++-- arch/x86/Kconfig | 2 +- arch/x86/kernel/acpi/boot.c | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig index 5533e33074..ddc51989ce 100644 --- a/arch/loongarch/Kconfig +++ b/arch/loongarch/Kconfig @@ -5,7 +5,7 @@ config LOONGARCH select ACPI select ACPI_GENERIC_GSI if ACPI select ACPI_MCFG if ACPI - select ACPI_HOTPLUG_CPU if ACPI_PROCESSOR && HOTPLUG_CPU + select ACPI_HOTPLUG_PRESENT_CPU if ACPI_PROCESSOR && HOTPLUG_CPU select ACPI_PPTT if ACPI select ACPI_SYSTEM_POWER_STATES_SUPPORT if ACPI select ARCH_BINFMT_ELF_STATE diff --git a/arch/loongarch/kernel/acpi.c b/arch/loongarch/kernel/acpi.c index 55d6a48c76..d9f7838d2a 100644 --- a/arch/loongarch/kernel/acpi.c +++ b/arch/loongarch/kernel/acpi.c @@ -286,7 +286,7 @@ void __init arch_reserve_mem_area(acpi_physical_address addr, size_t size) memblock_reserve(addr, size); } -#ifdef CONFIG_ACPI_HOTPLUG_CPU +#ifdef CONFIG_ACPI_HOTPLUG_PRESENT_CPU #include @@ -338,4 +338,4 @@ int acpi_unmap_cpu(int cpu) } EXPORT_SYMBOL(acpi_unmap_cpu); -#endif /* CONFIG_ACPI_HOTPLUG_CPU */ +#endif /* CONFIG_ACPI_HOTPLUG_PRESENT_CPU */ diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 0f9bab72ce..9ccdd87ee5 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -60,7 +60,7 @@ config X86 # select ACPI_LEGACY_TABLES_LOOKUP if ACPI select ACPI_SYSTEM_POWER_STATES_SUPPORT if ACPI - select ACPI_HOTPLUG_CPU if ACPI_PROCESSOR && HOTPLUG_CPU + select ACPI_HOTPLUG_PRESENT_CPU if ACPI_PROCESSOR && HOTPLUG_CPU select ARCH_32BIT_OFF_T if X86_32 select ARCH_CLOCKSOURCE_INIT select ARCH_CONFIGURES_CPU_MITIGATIONS diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index 49c39f5dc1..ae28c2b591 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -817,7 +817,7 @@ static void __init acpi_set_irq_model_ioapic(void) /* * ACPI based hotplug support for CPU */ -#ifdef CONFIG_ACPI_HOTPLUG_CPU +#ifdef CONFIG_ACPI_HOTPLUG_PRESENT_CPU #include static int acpi_map_cpu2node(acpi_handle handle, int cpu, int physid) @@ -866,7 +866,7 @@ int acpi_unmap_cpu(int cpu) return (0); } EXPORT_SYMBOL(acpi_unmap_cpu); -#endif /* CONFIG_ACPI_HOTPLUG_CPU */ +#endif /* CONFIG_ACPI_HOTPLUG_PRESENT_CPU */ int acpi_register_ioapic(acpi_handle handle, u64 phys_addr, u32 gsi_base) { -- Gitee From c5946be5ded70e4cf57ad75aeee7a5432021684b Mon Sep 17 00:00:00 2001 From: James Morse Date: Wed, 6 Aug 2025 17:25:27 +0800 Subject: [PATCH 130/155] ACPI: Add _OSC bits to advertise OS support for toggling CPU present/enabled on x86 Platform firmware can disabled a CPU, or make it not-present by making an eject-request notification, then waiting for the os to make it offline and call _EJx. After the firmware updates _STA with the new status. Not all operating systems support this. For arm64 making CPUs not-present has never been supported. For all ACPI architectures, making CPUs disabled has recently been added. Firmware can't know what the OS has support for. Add two new _OSC bits to advertise whether the OS supports the _STA enabled or present bits being toggled for CPUs. This will be important for arm64 if systems that support physical CPU hotplug ever appear as arm64 linux doesn't currently support this, so firmware shouldn't try. Advertising this support to firmware is useful for cloud orchestrators to know whether they can scale a particular VM by adding CPUs. Mainline: NA (cherry picked and rework from commit 362f33cba6a04a09bcfc47ade55ace95e8a51c5b) Signed-off-by: James Morse Tested-by: Miguel Luis Tested-by: Vishnu Pajjuri Tested-by: Jianyong Wu Signed-off-by: Li Wei Backported-by: Wu Chen Signed-off-by: Wang Yinfeng Change-Id: I6d552adf1e77df5dd7813822b949aa57b789fb5b --- arch/x86/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 9ccdd87ee5..f5f43312e5 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -61,6 +61,7 @@ config X86 select ACPI_LEGACY_TABLES_LOOKUP if ACPI select ACPI_SYSTEM_POWER_STATES_SUPPORT if ACPI select ACPI_HOTPLUG_PRESENT_CPU if ACPI_PROCESSOR && HOTPLUG_CPU + select ACPI_HOTPLUG_IGNORE_OSC if ACPI && HOTPLUG_CPU select ARCH_32BIT_OFF_T if X86_32 select ARCH_CLOCKSOURCE_INIT select ARCH_CONFIGURES_CPU_MITIGATIONS -- Gitee From 1825d46c5bd308d576ffb138ba796612ab82c0e8 Mon Sep 17 00:00:00 2001 From: Li Wei Date: Thu, 7 Aug 2025 11:44:51 +0800 Subject: [PATCH 131/155] Revert ACPI: Rename ACPI_HOTPLUG_CPU to include present This reverts commit 2eb3daf61b18d620b0624e31ad44ac1c76d94075. To keep CONFIG unchanged, modify ACPI_HOTPLUG_PRESENT_CPU to ACPI_HOTPLUG_CPU. Mainline: NA (cherry picked and rework from commit 38098f83388c90c0f2bf4c98ec610642a057d46e) Signed-off-by: Li Wei Backported-by: Wu Chen Signed-off-by: Wang Yinfeng Change-Id: I044e67268cffe132846c82f89cea381ca2710771 --- arch/loongarch/Kconfig | 2 +- arch/loongarch/kernel/acpi.c | 4 ++-- arch/x86/Kconfig | 2 +- arch/x86/kernel/acpi/boot.c | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig index ddc51989ce..5533e33074 100644 --- a/arch/loongarch/Kconfig +++ b/arch/loongarch/Kconfig @@ -5,7 +5,7 @@ config LOONGARCH select ACPI select ACPI_GENERIC_GSI if ACPI select ACPI_MCFG if ACPI - select ACPI_HOTPLUG_PRESENT_CPU if ACPI_PROCESSOR && HOTPLUG_CPU + select ACPI_HOTPLUG_CPU if ACPI_PROCESSOR && HOTPLUG_CPU select ACPI_PPTT if ACPI select ACPI_SYSTEM_POWER_STATES_SUPPORT if ACPI select ARCH_BINFMT_ELF_STATE diff --git a/arch/loongarch/kernel/acpi.c b/arch/loongarch/kernel/acpi.c index d9f7838d2a..55d6a48c76 100644 --- a/arch/loongarch/kernel/acpi.c +++ b/arch/loongarch/kernel/acpi.c @@ -286,7 +286,7 @@ void __init arch_reserve_mem_area(acpi_physical_address addr, size_t size) memblock_reserve(addr, size); } -#ifdef CONFIG_ACPI_HOTPLUG_PRESENT_CPU +#ifdef CONFIG_ACPI_HOTPLUG_CPU #include @@ -338,4 +338,4 @@ int acpi_unmap_cpu(int cpu) } EXPORT_SYMBOL(acpi_unmap_cpu); -#endif /* CONFIG_ACPI_HOTPLUG_PRESENT_CPU */ +#endif /* CONFIG_ACPI_HOTPLUG_CPU */ diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index f5f43312e5..026213db7f 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -60,7 +60,7 @@ config X86 # select ACPI_LEGACY_TABLES_LOOKUP if ACPI select ACPI_SYSTEM_POWER_STATES_SUPPORT if ACPI - select ACPI_HOTPLUG_PRESENT_CPU if ACPI_PROCESSOR && HOTPLUG_CPU + select ACPI_HOTPLUG_CPU if ACPI_PROCESSOR && HOTPLUG_CPU select ACPI_HOTPLUG_IGNORE_OSC if ACPI && HOTPLUG_CPU select ARCH_32BIT_OFF_T if X86_32 select ARCH_CLOCKSOURCE_INIT diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index ae28c2b591..49c39f5dc1 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -817,7 +817,7 @@ static void __init acpi_set_irq_model_ioapic(void) /* * ACPI based hotplug support for CPU */ -#ifdef CONFIG_ACPI_HOTPLUG_PRESENT_CPU +#ifdef CONFIG_ACPI_HOTPLUG_CPU #include static int acpi_map_cpu2node(acpi_handle handle, int cpu, int physid) @@ -866,7 +866,7 @@ int acpi_unmap_cpu(int cpu) return (0); } EXPORT_SYMBOL(acpi_unmap_cpu); -#endif /* CONFIG_ACPI_HOTPLUG_PRESENT_CPU */ +#endif /* CONFIG_ACPI_HOTPLUG_CPU */ int acpi_register_ioapic(acpi_handle handle, u64 phys_addr, u32 gsi_base) { -- Gitee From a0bcbf357f93dbc4f29eaab0f0e1cc742e61300b Mon Sep 17 00:00:00 2001 From: Xiao Cong Date: Wed, 6 Aug 2025 15:33:16 +0800 Subject: [PATCH 132/155] pci: phytium: Restore PCIe config space after hotrest In the phytium ps2308 platforms, when host PCIe bridge operate hotreset, then host pcie bridge config register will restore default value. So before hotreset, it need save host PCIe bridge config register. Then after hotreset, it need restore save host PCIe bridge config register. Mainline: NA Signed-off-by: Xiao Cong Signed-off-by: Wang Yinfeng Change-Id: I3ca22630d22e9f9399d8ad263df386efb538f891 --- drivers/pci/pci.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index e9a1071c56..c5506bd0a2 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -36,6 +36,9 @@ #ifdef CONFIG_PSWIOTLB #include #endif +#ifdef CONFIG_ARCH_PHYTIUM +#include +#endif DEFINE_MUTEX(pci_slot_mutex); @@ -5268,6 +5271,17 @@ void __weak pcibios_reset_secondary_bus(struct pci_dev *dev) */ int pci_bridge_secondary_bus_reset(struct pci_dev *dev) { +#ifdef CONFIG_ARCH_PHYTIUM + if (is_pd2308()) { + int ret = 0; + + pci_save_state(dev); + pcibios_reset_secondary_bus(dev); + ret = pci_bridge_wait_for_secondary_bus(dev, "bus reset"); + pci_restore_state(dev); + return ret; + } +#endif pcibios_reset_secondary_bus(dev); return pci_bridge_wait_for_secondary_bus(dev, "bus reset"); -- Gitee From d5996c87035accd727910e3f56b960f8224f2a5b Mon Sep 17 00:00:00 2001 From: Dai Jingtao Date: Fri, 1 Aug 2025 09:43:00 +0800 Subject: [PATCH 133/155] hda: phytium: Enable async suspend Enable async suspend so that different driver can resume parallely. Mainline: NA Signed-off-by: Dai Jingtao Signed-off-by: Wang Yinfeng Change-Id: I581ebf5972236c4357a7d34ab215d7e58053e79b --- sound/pci/hda/hda_phytium.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/hda_phytium.c b/sound/pci/hda/hda_phytium.c index 443c78af3f..1e9789a18c 100644 --- a/sound/pci/hda/hda_phytium.c +++ b/sound/pci/hda/hda_phytium.c @@ -848,6 +848,7 @@ static int azx_first_init(struct azx *chip) struct resource *res; const struct acpi_device_id *match; + device_enable_async_suspend(hddev); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); hda->regs = devm_ioremap_resource(hddev, res); if (IS_ERR(hda->regs)) -- Gitee From 7ad99ee641a36f7c7da251da30d56dc9c57e07b3 Mon Sep 17 00:00:00 2001 From: Chen Zhenhua Date: Tue, 29 Jul 2025 19:38:17 +0800 Subject: [PATCH 134/155] usb: xhci: Add a reset endpoint command to the specified PHYTIUM SOC When a transmission error occurs, EP_CTX_STATE is not equal to EP_STATE_HALTED, and the reset endpoint command is forcibly sent for the specified PHYTIUM platform. Mainline: Open-Source Signed-off-by: Chen Zhenhua Signed-off-by: Wang Yinfeng Change-Id: I1348eea88341d8b51c3e988e47806b2a647b0571 --- drivers/usb/host/xhci-ring.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 7c0e617205..903094cb03 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -2262,6 +2262,13 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_virt_ep *ep, td->start_seg, td->first_trb)); return 0; } +#ifdef CONFIG_ARCH_PHYTIUM + if (is_pd2408() || is_pe220x()) { + xhci_clear_hub_tt_buffer(xhci, td, ep); + xhci_handle_halted_endpoint(xhci, ep, td, EP_SOFT_RESET); + return 0; + } +#endif /* endpoint not halted, don't reset it */ break; } -- Gitee From f8a4d5fcd8c8c54883201a0f1392e4f82f73c279 Mon Sep 17 00:00:00 2001 From: liutianyu1250 Date: Thu, 4 Sep 2025 17:03:16 +0800 Subject: [PATCH 135/155] Revert "serio: i8042: fix probe fail WARN" This reverts commit 849eb1695ab678b9a9125e31c7808e301b4b118c. --- drivers/input/serio/i8042.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index a6aacb6ac5..f7b09c0bef 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -1488,8 +1488,7 @@ static int i8042_setup_aux(void) if (error) goto err_free_irq; - if (!phytium_check_cpu()) - i8042_aux_irq_registered = true; + i8042_aux_irq_registered = true; return 0; err_free_irq: -- Gitee From 2ca76c255c3a6ab187f23015012e18c1b99ceb64 Mon Sep 17 00:00:00 2001 From: liutianyu1250 Date: Thu, 4 Sep 2025 16:54:29 +0800 Subject: [PATCH 136/155] arm64: phytium_defconfig: update config after merge code Signed-off-by: liutianyu1250 --- arch/arm64/configs/phytium_defconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/configs/phytium_defconfig b/arch/arm64/configs/phytium_defconfig index 286f38c301..111b8e2db6 100644 --- a/arch/arm64/configs/phytium_defconfig +++ b/arch/arm64/configs/phytium_defconfig @@ -192,6 +192,7 @@ CONFIG_FW_LOADER_USER_HELPER=y CONFIG_FW_LOADER_COMPRESS=y CONFIG_FW_LOADER_COMPRESS_ZSTD=y CONFIG_BRCMSTB_GISB_ARB=y +CONFIG_PHYTIUM_PIO=y CONFIG_VEXPRESS_CONFIG=y CONFIG_MHI_BUS_PCI_GENERIC=m CONFIG_ARM_SCMI_PROTOCOL=y @@ -838,7 +839,7 @@ CONFIG_STAGING=y CONFIG_STAGING_MEDIA=y CONFIG_VIDEO_MAX96712=m CONFIG_PHYTIUM_NPU=y -CONFIG_NPU_PLATFORM=y +CONFIG_PHYTIUM_NPU_PLATFORM=y CONFIG_CHROME_PLATFORMS=y CONFIG_CROS_EC=y CONFIG_CROS_EC_I2C=y @@ -1003,7 +1004,6 @@ CONFIG_CRYPTO_DEV_HISI_ZIP=m CONFIG_CRYPTO_DEV_HISI_HPRE=m CONFIG_CRYPTO_DEV_HISI_TRNG=m CONFIG_CRYPTO_DEV_AMLOGIC_GXL=m -CONFIG_INDIRECT_PIO=y CONFIG_DMA_RESTRICTED_POOL=y CONFIG_CMA_SIZE_MBYTES=32 CONFIG_PRINTK_TIME=y -- Gitee From 7d50aec4292905d22132e42317b554452927549c Mon Sep 17 00:00:00 2001 From: liutianyu1250 Date: Tue, 16 Sep 2025 10:49:58 +0800 Subject: [PATCH 137/155] arm64: dts: restore dts memory info Signed-off-by: liutianyu1250 --- arch/arm64/boot/dts/phytium/pe2201-demo-ddr4.dts | 2 +- arch/arm64/boot/dts/phytium/pe2202-chillipi-edu-board.dts | 2 +- arch/arm64/boot/dts/phytium/pe2202-demo-ddr4-local.dts | 2 +- arch/arm64/boot/dts/phytium/pe2202-demo-ddr4.dts | 2 +- arch/arm64/boot/dts/phytium/pe2202-miniitx-board.dts | 2 +- arch/arm64/boot/dts/phytium/pe2202-power-board.dts | 2 +- arch/arm64/boot/dts/phytium/pe2204-come-board.dts | 2 +- arch/arm64/boot/dts/phytium/pe2204-demo-ddr4-local.dts | 2 +- arch/arm64/boot/dts/phytium/pe2204-demo-ddr4.dts | 2 +- arch/arm64/boot/dts/phytium/pe2204-edu-board.dts | 2 +- arch/arm64/boot/dts/phytium/pe2204-hanwei-board.dts | 2 +- arch/arm64/boot/dts/phytium/pe2204-miniitx-board.dts | 2 +- arch/arm64/boot/dts/phytium/pe2204-vpx-board.dts | 2 +- arch/arm64/boot/dts/phytium/phytiumpi_firefly.dts | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) diff --git a/arch/arm64/boot/dts/phytium/pe2201-demo-ddr4.dts b/arch/arm64/boot/dts/phytium/pe2201-demo-ddr4.dts index 7e8e51fc41..38f61d2aa8 100644 --- a/arch/arm64/boot/dts/phytium/pe2201-demo-ddr4.dts +++ b/arch/arm64/boot/dts/phytium/pe2201-demo-ddr4.dts @@ -18,7 +18,7 @@ chosen { stdout-path = "serial1:115200n8"; }; - memory@0 { + memory@00 { device_type = "memory"; reg = <0x0 0x80000000 0x0 0x80000000>; }; diff --git a/arch/arm64/boot/dts/phytium/pe2202-chillipi-edu-board.dts b/arch/arm64/boot/dts/phytium/pe2202-chillipi-edu-board.dts index e358e7c239..0ab55a50ff 100644 --- a/arch/arm64/boot/dts/phytium/pe2202-chillipi-edu-board.dts +++ b/arch/arm64/boot/dts/phytium/pe2202-chillipi-edu-board.dts @@ -25,7 +25,7 @@ chosen { stdout-path = "serial1:115200n8"; }; - memory@0{ + memory@00{ device_type = "memory"; reg = <0x0 0x80000000 0x0 0x80000000>; }; diff --git a/arch/arm64/boot/dts/phytium/pe2202-demo-ddr4-local.dts b/arch/arm64/boot/dts/phytium/pe2202-demo-ddr4-local.dts index 0684e91f7b..79c0262ed3 100644 --- a/arch/arm64/boot/dts/phytium/pe2202-demo-ddr4-local.dts +++ b/arch/arm64/boot/dts/phytium/pe2202-demo-ddr4-local.dts @@ -18,7 +18,7 @@ chosen { stdout-path = "serial1:115200n8"; }; - memory@0 { + memory@00 { device_type = "memory"; reg = <0x0 0x80000000 0x0 0x80000000>; }; diff --git a/arch/arm64/boot/dts/phytium/pe2202-demo-ddr4.dts b/arch/arm64/boot/dts/phytium/pe2202-demo-ddr4.dts index f9dacea116..d139f6850e 100644 --- a/arch/arm64/boot/dts/phytium/pe2202-demo-ddr4.dts +++ b/arch/arm64/boot/dts/phytium/pe2202-demo-ddr4.dts @@ -19,7 +19,7 @@ chosen { stdout-path = "serial1:115200n8"; }; - memory@0 { + memory@00 { device_type = "memory"; reg = <0x0 0x80000000 0x0 0x80000000>; }; diff --git a/arch/arm64/boot/dts/phytium/pe2202-miniitx-board.dts b/arch/arm64/boot/dts/phytium/pe2202-miniitx-board.dts index 7d06f07cc0..6f38e532a2 100644 --- a/arch/arm64/boot/dts/phytium/pe2202-miniitx-board.dts +++ b/arch/arm64/boot/dts/phytium/pe2202-miniitx-board.dts @@ -25,7 +25,7 @@ chosen { stdout-path = "serial1:115200n8"; }; - memory@0{ + memory@00{ device_type = "memory"; reg = <0x0 0x80000000 0x1 0x00000000>; }; diff --git a/arch/arm64/boot/dts/phytium/pe2202-power-board.dts b/arch/arm64/boot/dts/phytium/pe2202-power-board.dts index b0294d02d9..1726a84fa7 100644 --- a/arch/arm64/boot/dts/phytium/pe2202-power-board.dts +++ b/arch/arm64/boot/dts/phytium/pe2202-power-board.dts @@ -25,7 +25,7 @@ chosen { stdout-path = "serial1:115200n8"; }; - memory@0{ + memory@00{ device_type = "memory"; reg = <0x0 0x80000000 0x1 0x00000000>; }; diff --git a/arch/arm64/boot/dts/phytium/pe2204-come-board.dts b/arch/arm64/boot/dts/phytium/pe2204-come-board.dts index e87b260782..1ce5c0034d 100644 --- a/arch/arm64/boot/dts/phytium/pe2204-come-board.dts +++ b/arch/arm64/boot/dts/phytium/pe2204-come-board.dts @@ -25,7 +25,7 @@ chosen { stdout-path = "serial1:115200n8"; }; - memory@0{ + memory@00{ device_type = "memory"; reg = <0x0 0x80000000 0x2 0x00000000>; }; diff --git a/arch/arm64/boot/dts/phytium/pe2204-demo-ddr4-local.dts b/arch/arm64/boot/dts/phytium/pe2204-demo-ddr4-local.dts index 402d07735b..65fb64e87d 100644 --- a/arch/arm64/boot/dts/phytium/pe2204-demo-ddr4-local.dts +++ b/arch/arm64/boot/dts/phytium/pe2204-demo-ddr4-local.dts @@ -18,7 +18,7 @@ chosen { stdout-path = "serial1:115200n8"; }; - memory@0 { + memory@00 { device_type = "memory"; reg = <0x0 0x80000000 0x0 0x80000000>; }; diff --git a/arch/arm64/boot/dts/phytium/pe2204-demo-ddr4.dts b/arch/arm64/boot/dts/phytium/pe2204-demo-ddr4.dts index c12eb58105..dd62c6889d 100644 --- a/arch/arm64/boot/dts/phytium/pe2204-demo-ddr4.dts +++ b/arch/arm64/boot/dts/phytium/pe2204-demo-ddr4.dts @@ -19,7 +19,7 @@ chosen { stdout-path = "serial1:115200n8"; }; - memory@0 { + memory@00 { device_type = "memory"; reg = <0x0 0x80000000 0x0 0x80000000>; }; diff --git a/arch/arm64/boot/dts/phytium/pe2204-edu-board.dts b/arch/arm64/boot/dts/phytium/pe2204-edu-board.dts index 7a47cbc375..96c84e5eab 100644 --- a/arch/arm64/boot/dts/phytium/pe2204-edu-board.dts +++ b/arch/arm64/boot/dts/phytium/pe2204-edu-board.dts @@ -25,7 +25,7 @@ chosen { stdout-path = "serial1:115200n8"; }; - memory@0{ + memory@00{ device_type = "memory"; reg = <0x0 0x80000000 0x2 0x00000000>; }; diff --git a/arch/arm64/boot/dts/phytium/pe2204-hanwei-board.dts b/arch/arm64/boot/dts/phytium/pe2204-hanwei-board.dts index d9e1eae59d..02b635dd48 100644 --- a/arch/arm64/boot/dts/phytium/pe2204-hanwei-board.dts +++ b/arch/arm64/boot/dts/phytium/pe2204-hanwei-board.dts @@ -25,7 +25,7 @@ chosen { stdout-path = "serial1:115200n8"; }; - memory@0{ + memory@00{ device_type = "memory"; reg = <0x0 0x80000000 0x2 0x00000000>; }; diff --git a/arch/arm64/boot/dts/phytium/pe2204-miniitx-board.dts b/arch/arm64/boot/dts/phytium/pe2204-miniitx-board.dts index 2513b7b5e2..a806f11610 100644 --- a/arch/arm64/boot/dts/phytium/pe2204-miniitx-board.dts +++ b/arch/arm64/boot/dts/phytium/pe2204-miniitx-board.dts @@ -32,7 +32,7 @@ aliases { serial8 = &mio15; }; - memory@0{ + memory@00{ device_type = "memory"; reg = <0x0 0x80000000 0x2 0x00000000>; }; diff --git a/arch/arm64/boot/dts/phytium/pe2204-vpx-board.dts b/arch/arm64/boot/dts/phytium/pe2204-vpx-board.dts index 22c3c4395b..c3a6950a46 100644 --- a/arch/arm64/boot/dts/phytium/pe2204-vpx-board.dts +++ b/arch/arm64/boot/dts/phytium/pe2204-vpx-board.dts @@ -25,7 +25,7 @@ chosen { stdout-path = "serial1:115200n8"; }; - memory@0{ + memory@00{ device_type = "memory"; reg = <0x0 0x80000000 0x2 0x00000000>; }; diff --git a/arch/arm64/boot/dts/phytium/phytiumpi_firefly.dts b/arch/arm64/boot/dts/phytium/phytiumpi_firefly.dts index e16a4759c4..13f2e61bf6 100644 --- a/arch/arm64/boot/dts/phytium/phytiumpi_firefly.dts +++ b/arch/arm64/boot/dts/phytium/phytiumpi_firefly.dts @@ -26,7 +26,7 @@ aliases { serial6 = &mio15; }; - memory@0{ + memory@00{ device_type = "memory"; reg = <0x0 0x80000000 0x2 0x00000000>; }; -- Gitee From 03838966c9af555a2d203ab857e16ec388b5222e Mon Sep 17 00:00:00 2001 From: liutianyu1250 Date: Tue, 23 Sep 2025 11:09:29 +0800 Subject: [PATCH 138/155] net: phy: motorcomm: imporve yt8521 read_status Add reset phydev->speed & duplex when not link. When link is down, ethtool will show: ... Speed: Unknown! Duplex: Unknown! (255) ... rather than the old speed & duplex info at link up. Signed-off-by: liutianyu1250 --- drivers/net/phy/motorcomm.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/phy/motorcomm.c b/drivers/net/phy/motorcomm.c index d0763fc364..e800d35e43 100644 --- a/drivers/net/phy/motorcomm.c +++ b/drivers/net/phy/motorcomm.c @@ -1558,6 +1558,8 @@ static int yt8521_read_status(struct phy_device *phydev) ytxxxx_adjust_status(phydev, val_utp, 1); } else { link_utp = 0; + phydev->speed = SPEED_UNKNOWN; + phydev->duplex = DUPLEX_UNKNOWN; } if (link_utp) { -- Gitee From 12c274eac4a126a029ad3102407b7704969730ca Mon Sep 17 00:00:00 2001 From: Huangjie Date: Wed, 24 Sep 2025 16:37:57 +0800 Subject: [PATCH 139/155] lib: logic_pio: workaround for pio error logs when not load phytium_pio Signed-off-by: Huangjie --- lib/logic_pio.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/logic_pio.c b/lib/logic_pio.c index b8b7b1ba61..8884b22f3a 100644 --- a/lib/logic_pio.c +++ b/lib/logic_pio.c @@ -160,7 +160,7 @@ static struct logic_pio_hwaddr *find_io_range(unsigned long pio) } rcu_read_unlock(); - if (!found_range) + if (!found_range && !check_cpu_type()) pr_err("PIO entry token 0x%lx invalid\n", pio); return found_range; @@ -275,7 +275,8 @@ void logic_out##bwl(type value, unsigned long addr) \ entry->ops->out(entry->hostdata, \ addr, value, sizeof(type)); \ else \ - WARN_ON_ONCE(1); \ + if (!check_cpu_type()) \ + WARN_ON_ONCE(1); \ } \ } \ \ -- Gitee From a2a23d6490cc73d00340c80a8b2f6e95b5c73260 Mon Sep 17 00:00:00 2001 From: Huangjie Date: Wed, 17 Sep 2025 17:20:24 +0800 Subject: [PATCH 140/155] drivers: edac/phytium: add support for pd2208 Signed-off-by: Huangjie --- drivers/edac/phytium_edac.c | 227 ++++++++++++++++++++++++++++++++---- 1 file changed, 207 insertions(+), 20 deletions(-) diff --git a/drivers/edac/phytium_edac.c b/drivers/edac/phytium_edac.c index 00a5134f02..aaca6ac8b9 100644 --- a/drivers/edac/phytium_edac.c +++ b/drivers/edac/phytium_edac.c @@ -14,6 +14,7 @@ #include #include #include "edac_module.h" +#include #define EDAC_MOD_STR "phytium_edac" @@ -36,21 +37,21 @@ #define CORRECTED_ERROR 0 #define UNCORRECTED_ERROR 1 -#define MAX_ERR_GROUP 3 +#define EDAC_DRIVER_VERSION "1.1.2" -#define EDAC_DRIVER_VERSION "1.1.1" +struct ras_error_info { + u32 index; + u32 error_type; + const char *error_str; +}; struct phytium_edac { struct device *dev; void __iomem **ras_base; struct dentry *dfs; struct edac_device_ctl_info *edac_dev; -}; - -struct ras_error_info { - u32 index; - u32 error_type; - const char *error_str; + int num_err_group; + const struct ras_error_info **error_info; }; /* error severity definition */ @@ -128,8 +129,182 @@ static const struct ras_error_info pe220x_ras_peu_error[] = { { 5, CORRECTED_ERROR, "axi_r_rsp_error" }, }; +/* pd2208 error */ +static const struct ras_error_info pd2208_ras_err[] = { + {0, CORRECTED_ERROR, "lmu0_ras_ecc_corrected_err"}, + {1, UNCORRECTED_ERROR, "lmu0_ras_ecc_uncorrected_err"}, + {2, CORRECTED_ERROR, "lmu1_ras_ecc_corrected_err"}, + {3, UNCORRECTED_ERROR, "lmu1_ras_ecc_uncorrected_err"}, + {4, CORRECTED_ERROR, "sram_corrected_err"}, + {5, UNCORRECTED_ERROR, "sram_uncorrected_err"}, + {6, UNCORRECTED_ERROR, "qspi_ras_addr_err"}, + {7, UNCORRECTED_ERROR, "qspi_ras_pstrb_err"}, + {8, UNCORRECTED_ERROR, "intreq_err"}, + {9, UNCORRECTED_ERROR, "gic_axim_err"}, + {10, UNCORRECTED_ERROR, "gic_ecc_fatal"}, + {11, UNCORRECTED_ERROR, "lsd_lbc_ras_err"}, + {12, UNCORRECTED_ERROR, "nEXTERRIRQ_cluster0"}, + {13, UNCORRECTED_ERROR, "nINTERRIRQ_cluster0"}, + {14, UNCORRECTED_ERROR, "nEXTERRIRQ_cluster1"}, + {15, UNCORRECTED_ERROR, "nINTERRIRQ_cluster1"}, + {16, UNCORRECTED_ERROR, "nEXTERRIRQ_cluster2"}, + {17, UNCORRECTED_ERROR, "nINTERRIRQ_cluster2"}, + {18, UNCORRECTED_ERROR, "nEXTERRIRQ_cluster3"}, + {19, UNCORRECTED_ERROR, "nINTERRIRQ_cluster3"}, + {20, CORRECTED_ERROR, "lbc_ecc_corrected_err"}, + {21, UNCORRECTED_ERROR, "lbc_ecc_uncorrected_err"}, +}; + +static const struct ras_error_info pd2208_ras_sram_err[] = { + {0, CORRECTED_ERROR, "scp_sram_corrected_err"}, + {1, UNCORRECTED_ERROR, "scp_sram_uncorrected_err"}, + {2, CORRECTED_ERROR, "scp_sharemem_corrected_err"}, + {3, UNCORRECTED_ERROR, "scp_sharemem_uncorrected_err"}, + {4, CORRECTED_ERROR, "wr_cmd_buf_corrected_err"}, + {5, UNCORRECTED_ERROR, "wr_cmd_buf_uncorrected_err"}, + {6, CORRECTED_ERROR, "rd_dat_buf_corrected_err"}, + {7, UNCORRECTED_ERROR, "rd_dat_buf_uncorrected_err"}, + {8, CORRECTED_ERROR, "wr_cmd_buf_corrected_err"}, + {9, UNCORRECTED_ERROR, "wr_cmd_buf_uncorrected_err"}, + {10, CORRECTED_ERROR, "wr_dat_buf_corrected_err"}, + {11, UNCORRECTED_ERROR, "wr_dat_buf_uncorrected_err"}, + {12, CORRECTED_ERROR, "drtrch0_corrected_err"}, + {13, UNCORRECTED_ERROR, "drtrch0_uncorrected_err"}, + {14, CORRECTED_ERROR, "drtrch0_corrected_err"}, + {15, UNCORRECTED_ERROR, "drtrch0_uncorrected_err"}, + {16, CORRECTED_ERROR, "dmac_corrected_err"}, + {17, UNCORRECTED_ERROR, "dmac_uncorrected_err"}, + {18, CORRECTED_ERROR, "rmram0_corrected_err"}, + {19, UNCORRECTED_ERROR, "rmram0_uncorrected_err"}, + {20, CORRECTED_ERROR, "rmram1_corrected_err"}, + {21, UNCORRECTED_ERROR, "rmram1_uncorrected_err"}, + {22, CORRECTED_ERROR, "rmram2_corrected_err"}, + {23, UNCORRECTED_ERROR, "rmram2_uncorrected_err"}, + {24, CORRECTED_ERROR, "rmram3_corrected_err"}, + {25, UNCORRECTED_ERROR, "rmram3_uncorrected_err"}, + {26, CORRECTED_ERROR, "gmactx0_corrected_err"}, + {27, UNCORRECTED_ERROR, "gmactx0_uncorrected_err"}, + {28, CORRECTED_ERROR, "gmactx1_corrected_err"}, + {29, UNCORRECTED_ERROR, "gmactx1_uncorrected_err"}, + {30, CORRECTED_ERROR, "gmactx2_corrected_err"}, + {31, UNCORRECTED_ERROR, "gmactx2_uncorrected_err"}, + {32, CORRECTED_ERROR, "gmactx3_corrected_err"}, + {33, UNCORRECTED_ERROR, "gmactx3_uncorrected_err"}, +}; + +static const struct ras_error_info pd2208_ras_peu_sram0_err[] = { + {0, CORRECTED_ERROR, "c0p2a_corrected_err"}, + {1, UNCORRECTED_ERROR, "c0p2a_uncorrected_err"}, + {2, CORRECTED_ERROR, "c0a2p_corrected_err"}, + {3, UNCORRECTED_ERROR, "c0a2p_uncorrected_err"}, + {4, CORRECTED_ERROR, "c0rxbuf0_corrected_err"}, + {5, UNCORRECTED_ERROR, "c0rxbuf0_uncorrected_err"}, + {6, CORRECTED_ERROR, "c0rxbuf1_corrected_err"}, + {7, UNCORRECTED_ERROR, "c0rxbuf1 _uncorrected_err"}, + {8, CORRECTED_ERROR, "c0rxbuf2_corrected_err"}, + {9, UNCORRECTED_ERROR, "c0rxbuf2 _uncorrected_err"}, + {10, CORRECTED_ERROR, "c0rxbuf3_corrected_err"}, + {11, UNCORRECTED_ERROR, "c0rxbuf3 _uncorrected_err"}, + {12, CORRECTED_ERROR, "c0txbuf0_corrected_err"}, + {13, UNCORRECTED_ERROR, "c0txbuf0_uncorrected_err"}, + {14, CORRECTED_ERROR, "c0txbuf1_corrected_err"}, + {15, UNCORRECTED_ERROR, "c0txbuf1 _uncorrected_err"}, + {16, CORRECTED_ERROR, "c0txbuf2_corrected_err"}, + {17, UNCORRECTED_ERROR, "c0txbuf2 _uncorrected_err"}, + {18, CORRECTED_ERROR, "c0txbuf3_corrected_err"}, + {19, UNCORRECTED_ERROR, "c0txbuf3 _uncorrected_err"}, + {20, CORRECTED_ERROR, "c1p2a_corrected_err"}, + {21, UNCORRECTED_ERROR, "c1p2a_uncorrected_err"}, + {22, CORRECTED_ERROR, "c1a2p_corrected_err"}, + {23, UNCORRECTED_ERROR, "c1a2p_uncorrected_err"}, + {24, CORRECTED_ERROR, "c1rxbuf0_corrected_err"}, + {25, UNCORRECTED_ERROR, "c1rxbuf0_uncorrected_err"}, + {26, CORRECTED_ERROR, "c1rxbuf1_corrected_err"}, + {27, UNCORRECTED_ERROR, "c1rxbuf1 _uncorrected_err"}, + {28, CORRECTED_ERROR, "c1rxbuf2_corrected_err"}, + {29, UNCORRECTED_ERROR, "c1rxbuf2 _uncorrected_err"}, + {30, CORRECTED_ERROR, "c1rxbuf3_corrected_err"}, + {31, UNCORRECTED_ERROR, "c1rxbuf3 _uncorrected_err"}, + {32, CORRECTED_ERROR, "c1txbuf0_corrected_err"}, + {33, UNCORRECTED_ERROR, "c1txbuf0_uncorrected_err"}, + {34, CORRECTED_ERROR, "c1txbuf1_corrected_err"}, + {35, UNCORRECTED_ERROR, "c1txbuf1 _uncorrected_err"}, + {36, CORRECTED_ERROR, "c1txbuf2_corrected_err"}, + {37, UNCORRECTED_ERROR, "c1txbuf2 _uncorrected_err"}, + {38, CORRECTED_ERROR, "c1txbuf3_corrected_err"}, + {39, UNCORRECTED_ERROR, "c1txbuf3 _uncorrected_err"}, + {40, CORRECTED_ERROR, "c2p2a_corrected_err"}, + {41, UNCORRECTED_ERROR, "c2p2a_uncorrected_err"}, + {42, CORRECTED_ERROR, "c2a2p_corrected_err"}, + {43, UNCORRECTED_ERROR, "c2a2p_uncorrected_err"}, + {44, CORRECTED_ERROR, "c2rxbuf0_corrected_err"}, + {45, UNCORRECTED_ERROR, "c2rxbuf0_uncorrected_err"}, + {46, CORRECTED_ERROR, "c2rxbuf1_corrected_err"}, + {47, UNCORRECTED_ERROR, "c2rxbuf1 _uncorrected_err"}, + {48, CORRECTED_ERROR, "c2rxbuf2_corrected_err"}, + {49, UNCORRECTED_ERROR, "c2rxbuf2 _uncorrected_err"}, + {50, CORRECTED_ERROR, "c2rxbuf3_corrected_err"}, + {51, UNCORRECTED_ERROR, "c2rxbuf3 _uncorrected_err"}, + {52, CORRECTED_ERROR, "c2txbuf0_corrected_err"}, + {53, UNCORRECTED_ERROR, "c2txbuf0_uncorrected_err"}, + {54, CORRECTED_ERROR, "c2txbuf1_corrected_err"}, + {55, UNCORRECTED_ERROR, "c2txbuf1 _uncorrected_err"}, +}; + +static const struct ras_error_info pd2208_ras_peu_sram1_err[] = { + {0, CORRECTED_ERROR, "c2txbuf2_corrected_err"}, + {1, UNCORRECTED_ERROR, "c2txbuf2_uncorrected_err"}, + {2, CORRECTED_ERROR, "c2txbuf3_corrected_err"}, + {3, UNCORRECTED_ERROR, "c2txbuf3_uncorrected_err"}, + {4, CORRECTED_ERROR, "phy0_sram0_corrected_err"}, + {5, UNCORRECTED_ERROR, "phy0_sram0_uncorrected_err"}, + {6, CORRECTED_ERROR, "phy0_sram1_corrected_err"}, + {7, UNCORRECTED_ERROR, "phy0_sram1 _uncorrected_err"}, + {8, CORRECTED_ERROR, "phy0_sram2_corrected_err"}, + {9, UNCORRECTED_ERROR, "phy0_sram2 _uncorrected_err"}, + {10, CORRECTED_ERROR, "phy0_sram3_corrected_err"}, + {11, UNCORRECTED_ERROR, "phy0_sram3 _uncorrected_err"}, + {12, CORRECTED_ERROR, "phy1_sram0_corrected_err"}, + {13, UNCORRECTED_ERROR, "phy1_sram0_uncorrected_err"}, + {14, CORRECTED_ERROR, "mac0_rxdpram_corrected_err"}, + {15, UNCORRECTED_ERROR, "mac0_rxdpram _uncorrected_err"}, + {16, CORRECTED_ERROR, "mac0_txdpram_corrected_err"}, + {17, UNCORRECTED_ERROR, "mac0_txdpram _uncorrected_err"}, + {18, CORRECTED_ERROR, "mac1_rxdpram_corrected_err"}, + {19, UNCORRECTED_ERROR, "mac1_rxdpram _uncorrected_err"}, + {20, CORRECTED_ERROR, "mac1_txdpram_corrected_err"}, + {21, UNCORRECTED_ERROR, "mac1_txdpram _uncorrected_err"}, +}; + +static const struct ras_error_info pd2208_ras_peu_base_err[] = { + {0, UNCORRECTED_ERROR, "pio_rd_addr_error"}, + {1, UNCORRECTED_ERROR, "pio_rd_timeout"}, + {2, UNCORRECTED_ERROR, "pio_wr_addr_error"}, + {3, UNCORRECTED_ERROR, "pio_wr_timeout"}, + {4, CORRECTED_ERROR, "axi_b_rsp_error"}, + {5, UNCORRECTED_ERROR, "axi_r_rsp_error"}, + {6, UNCORRECTED_ERROR, "mac0_asf_trans_to_err"}, + {7, UNCORRECTED_ERROR, "mac0_asf_protocol_err"}, + {8, UNCORRECTED_ERROR, "mac0_asf_nonfatal_int"}, + {9, UNCORRECTED_ERROR, "mac0_asf_fatal_int"}, + {10, UNCORRECTED_ERROR, "mac1_asf_trans_to_err"}, + {11, UNCORRECTED_ERROR, "mac1_asf_protocol_err"}, + {12, UNCORRECTED_ERROR, "mac1_asf_nonfatal_int"}, + {13, UNCORRECTED_ERROR, "mac1_asf_fatal_int"}, +}; + static const struct ras_error_info *pe220x_ras_error[] = { - pe220x_ras_soc_error, pe220x_ras_peu_psu_error, pe220x_ras_peu_error + pe220x_ras_soc_error, + pe220x_ras_peu_psu_error, + pe220x_ras_peu_error, +}; + +static const struct ras_error_info *pd2208_ras_error[] = { + pd2208_ras_err, + pd2208_ras_sram_err, + pd2208_ras_peu_sram0_err, + pd2208_ras_peu_sram1_err, + pd2208_ras_peu_base_err, }; static inline unsigned int get_error_num(const struct phytium_edac *edac, @@ -146,11 +321,11 @@ static inline void phytium_ras_setup(const struct phytium_edac *edac) { u64 val = 0; unsigned int i = 0; + /* * enable error report and generate interrupt for corrected error event - * first error record owned by node present the node configuration */ - for (i = 0; i < MAX_ERR_GROUP; i++) { + for (i = 0; i < edac->num_err_group; i++) { val = readq(edac->ras_base[i] + ERR_CTLR(0)); val |= CTLR_ED | CTLR_UI | CTLR_CFI; writeq(val, edac->ras_base[i] + ERR_CTLR(0)); @@ -190,7 +365,7 @@ static ssize_t phytium_edac_inject_ctrl_write(struct file *filp, goto out; res = kstrtouint(tmp, 0, &error_group); - if (res || error_group >= MAX_ERR_GROUP) { + if (res || error_group >= edac->num_err_group) { dev_err(edac->dev, "invalid error group parameters"); goto out; } @@ -207,10 +382,10 @@ static ssize_t phytium_edac_inject_ctrl_write(struct file *filp, goto out; } - dev_dbg(edac->dev, "inject group%d, error_id: %d\n", + dev_dbg(edac->dev, "inject group: %d, error_id: %d\n", error_group, error_id); - if (pe220x_ras_error[error_group][error_id].error_type + if (edac->error_info[error_group][error_id].error_type == CORRECTED_ERROR) { writeq(MISC0_CEC(0xFF), edac->ras_base[error_group] + ERR_MISC0(error_id)); @@ -295,7 +470,7 @@ static int get_error_id(struct phytium_edac *edac, int *error_id, int err_id = 0; /* Iterate over the ras node to check error status */ - for (i = 0; i < MAX_ERR_GROUP; i++) { + for (i = 0; i < edac->num_err_group; i++) { error_num = get_error_num(edac, i); error_bit = readq(edac->ras_base[i] + ERR_GSR); for (err_id = 0; err_id < error_num; err_id++) { @@ -311,7 +486,7 @@ static int get_error_id(struct phytium_edac *edac, int *error_id, } } - if (i >= MAX_ERR_GROUP) { + if (i >= edac->num_err_group) { ret = -1; dev_warn(edac->dev, "no error detect.\n"); } @@ -323,7 +498,7 @@ static void phytium_edac_error_report(struct phytium_edac *edac, const int error_id, const int error_group) { const struct ras_error_info *err_info = - pe220x_ras_error[error_group]; + edac->error_info[error_group]; if (err_info[error_id].error_type == UNCORRECTED_ERROR) { edac_printk(KERN_CRIT, EDAC_MOD_STR, "uncorrected error: %s\n", @@ -398,14 +573,23 @@ static int phytium_edac_probe(struct platform_device *pdev) edac->dev = &pdev->dev; platform_set_drvdata(pdev, edac); - edac->ras_base = devm_kcalloc(&pdev->dev, 3, + edac->error_info = + (const struct ras_error_info **)of_device_get_match_data(&pdev->dev); + + edac->num_err_group = of_address_count(pdev->dev.of_node); + if (edac->num_err_group <= 0) { + dev_err(&pdev->dev, "can't get error group count"); + goto out; + } + + edac->ras_base = devm_kcalloc(&pdev->dev, edac->num_err_group, sizeof(*edac->ras_base), GFP_KERNEL); if (!edac->ras_base) { return -ENOMEM; goto out; } - for (i = 0; i < MAX_ERR_GROUP; i++) { + for (i = 0; i < edac->num_err_group; i++) { res = platform_get_resource(pdev, IORESOURCE_MEM, i); edac->ras_base[i] = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(edac->ras_base[i])) { @@ -463,7 +647,10 @@ static int phytium_edac_remove(struct platform_device *pdev) } static const struct of_device_id phytium_edac_of_match[] = { - { .compatible = "phytium,pe220x-edac" }, + { .compatible = "phytium,pe220x-edac", + .data = pe220x_ras_error }, + { .compatible = "phytium,pd2208-edac", + .data = pd2208_ras_error }, {}, }; MODULE_DEVICE_TABLE(of, phytium_edac_of_match); -- Gitee From 7872b0d261da40110ca63ba7bc8b23081078df2d Mon Sep 17 00:00:00 2001 From: aa68454650 <10051149+aa68454650@user.noreply.gitee.com> Date: Wed, 15 Jan 2025 03:23:58 +0000 Subject: [PATCH 141/155] ASoC: codecs: add CUBIC LATTICE MA1026 driver --- sound/soc/codecs/Kconfig | 4 + sound/soc/codecs/Makefile | 3 + sound/soc/codecs/ma1026.c | 1048 +++++++++++++++++++++++++++++++ sound/soc/codecs/ma1026.h | 127 ++++ sound/soc/phytium/Kconfig | 7 + sound/soc/phytium/Makefile | 3 + sound/soc/phytium/pmdk_ma1026.c | 103 +++ 7 files changed, 1295 insertions(+) create mode 100755 sound/soc/codecs/ma1026.c create mode 100644 sound/soc/codecs/ma1026.h create mode 100644 sound/soc/phytium/pmdk_ma1026.c diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 6e16cc2cce..5c81b1a5e3 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -224,6 +224,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_SIMPLE_AMPLIFIER imply SND_SOC_SIMPLE_MUX imply SND_SOC_SMA1303 + imply SND_SOC_MA1026 if I2C imply SND_SOC_SPDIF imply SND_SOC_SRC4XXX_I2C imply SND_SOC_SSM2305 @@ -1700,6 +1701,9 @@ config SND_SOC_SMA1303 help Enable support for Iron Device SMA1303 Boosted Class-D amplifier +config SND_SOC_MA1026 + tristate "Cubiclattice MA1026 CODEC" + config SND_SOC_SPDIF tristate "S/PDIF CODEC" diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index a2f54c2ca7..da8664ebed 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -256,6 +256,7 @@ snd-soc-sigmadsp-i2c-objs := sigmadsp-i2c.o snd-soc-sigmadsp-regmap-objs := sigmadsp-regmap.o snd-soc-si476x-objs := si476x.o snd-soc-sma1303-objs := sma1303.o +snd-soc-ma1026-objs := ma1026.o snd-soc-spdif-tx-objs := spdif_transmitter.o snd-soc-spdif-rx-objs := spdif_receiver.o snd-soc-src4xxx-objs := src4xxx.o @@ -641,6 +642,8 @@ obj-$(CONFIG_SND_SOC_SIGMADSP_REGMAP) += snd-soc-sigmadsp-regmap.o obj-$(CONFIG_SND_SOC_SI476X) += snd-soc-si476x.o obj-$(CONFIG_SND_SOC_SMA1303) += snd-soc-sma1303.o obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif-rx.o snd-soc-spdif-tx.o +obj-$(CONFIG_SND_SOC_SIRF_AUDIO_CODEC) += sirf-audio-codec.o +obj-$(CONFIG_SND_SOC_MA1026) += snd-soc-ma1026.o obj-$(CONFIG_SND_SOC_SRC4XXX) += snd-soc-src4xxx.o obj-$(CONFIG_SND_SOC_SRC4XXX_I2C) += snd-soc-src4xxx-i2c.o obj-$(CONFIG_SND_SOC_SSM2305) += snd-soc-ssm2305.o diff --git a/sound/soc/codecs/ma1026.c b/sound/soc/codecs/ma1026.c new file mode 100755 index 0000000000..c3d6ad74f3 --- /dev/null +++ b/sound/soc/codecs/ma1026.c @@ -0,0 +1,1048 @@ +//SPDX-License-Identifier:GPL-2.0 +/* + * ma1026 ALSA SoC audio driver + * + * Copyright (c) Cubiclattice semiconductor.co.,Ltd + * Copyright (c) 2022-2024 PhytiumTechnology co.,"Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ma1026.h" + +#define TEMP_DEBUG 0 +#define MA_DBG(fmt...) printk(fmt) + +#define MA1026_LRCK (SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_KNOT) +#define MA1026_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE) + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 00, 0)) + #define snd_soc_write_ma1026(codec, addr, value) \ + snd_soc_write(codec, addr, value); + #define snd_soc_update_ma1026(component, reg, mask, val) \ + snd_soc_update_bits(component, reg, mask, val) +#elif (LINUX_VERSION_CODE < KERNEL_VERSION(5, 00, 0)) + #define snd_soc_write_ma1026(codec, addr, value) \ + snd_soc_component_write(codec, addr, value); + #define snd_soc_update_ma1026(component, reg, mask, val) \ + snd_soc_component_update_bits(component, reg, mask, val) +#elif (LINUX_VERSION_CODE < KERNEL_VERSION(6, 00, 0)) + #define snd_soc_write_ma1026(codec, addr, value) \ + snd_soc_component_write(codec, addr, value); + #define snd_soc_update_ma1026(component, reg, mask, val) \ + snd_soc_component_update_bits(component, reg, mask, val) +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 00, 0)) + #define snd_soc_read_ma1026(codec, addr) \ + snd_soc_read(codec, addr); +#elif (LINUX_VERSION_CODE < KERNEL_VERSION(5, 00, 0)) + #define snd_soc_read_ma1026(codec, addr) \ + snd_soc_component_read32(codec, addr); +#elif (LINUX_VERSION_CODE < KERNEL_VERSION(6, 00, 0)) + #define snd_soc_read_ma1026(codec, addr) \ + snd_soc_component_read(codec, addr); +#endif + +struct sp_config { + u8 spc, mmcc, spfs; + u32 lrckfreq; +}; + +struct ma1026_priv{ + struct gpio_desc *gpiod_spk_ctl; + struct sp_config config; + struct regmap *regmap; + struct clk *mclk; + unsigned int sysclk; + struct snd_pcm_hw_constraint_list *sysclk_constraints; + int shutdwn_delay; + bool hp_mute; + bool hp_inserted; + long force_muted; + long playback_path; + long capture_path; +}; + +struct snd_pcm_constr_list { + int count; + u32 *list; +}; + +struct ma1026_mclk_div { + u32 mclk, lrckfreq; + u8 mmcc; +}; + +static struct ma1026_mclk_div ma1026_mclk_coeffs[] = { + /* MCLK, LRCK, MMCC[5:0] */ + {5644800, 11025, 0x30}, + {5644800, 22050, 0x20}, + {5644800, 44100, 0x10}, + + {6144000, 8000, 0x38}, + {6144000, 12000, 0x30}, + {6144000, 16000, 0x28}, + {6144000, 24000, 0x20}, + {6144000, 32000, 0x18}, + {6144000, 48000, 0x10}, +}; + +struct ma1026_priv *globe_ma1026; +static struct snd_soc_component *ma1026_codec; + +struct workqueue_struct *spk_monitor_wq; +struct delayed_work spk_delay_work; + + +static unsigned int rates_12288[] = { + 8000, 12000, 16000, 24000, 24000, 32000, 48000, 96000, +}; + +static struct snd_pcm_hw_constraint_list constraints_12288 = { + .count = ARRAY_SIZE(rates_12288), + .list = rates_12288, +}; + +static unsigned int rates_112896[] = { + 8000, 11025, 22050, 44100, +}; + +static struct snd_pcm_hw_constraint_list constraints_112896 = { + .count = ARRAY_SIZE(rates_112896), + .list = rates_112896, +}; + +static unsigned int rates_12[] = { + 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, + 48000, 88235, 96000, +}; + +static struct snd_pcm_hw_constraint_list constraints_12 = { + .count = ARRAY_SIZE(rates_12), + .list = rates_12, +}; + +static bool ma1026_volatile_reg(struct device *dev, unsigned int reg) +{ + if (reg <= 255) + return true; + else + return false; +} + +static bool ma1026_readable_reg(struct device *dev, unsigned int reg) +{ + if (reg <= 255) + return true; + else + return false; +} + +static const struct reg_default ma1026_reg_defaults[] = { + {1, 0xF1}, {2, 0xDF}, {3, 0x3F}, {4, 0x60}, + {5, 0x77}, {6, 0x04}, {7, 0x00}, {8, 0x15}, + {9, 0x06}, {10, 0x00}, {11, 0x00}, {12, 0x00}, + {13, 0x00}, {14, 0x00}, {15, 0x00}, {16, 0x00}, + {17, 0x00}, {18, 0x02}, {19, 0x02}, {20, 0x00}, + {21, 0x00}, {22, 0x00}, {23, 0x7F}, {24, 0x03}, + {25, 0x00}, {26, 0x3F}, {27, 0xE1}, {28, 0x00}, + {29, 0x00}, {30, 0x08}, {31, 0x3F}, {32, 0x3F}, + {33, 0x00}, {34, 0x00}, {35, 0x00}, {36, 0x00}, + {37, 0x3F}, {38, 0x3F}, {94, 0x00}, +}; + +static struct regmap_config ma1026_regmap = { + .reg_bits = 8, + .val_bits = 8, + .max_register = MA1026_MAX_REGISTER, + .reg_defaults = ma1026_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(ma1026_reg_defaults), + .volatile_reg = ma1026_volatile_reg, + .readable_reg = ma1026_readable_reg, + .cache_type = REGCACHE_RBTREE, +}; + +static int ma1026_set_bias_level( +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 00, 0)) + struct snd_soc_codec *codec, +#elif (LINUX_VERSION_CODE < KERNEL_VERSION(5, 00, 0)) + struct snd_soc_component *codec, +#elif (LINUX_VERSION_CODE < KERNEL_VERSION(6, 00, 0)) + struct snd_soc_component *codec, +#endif + enum snd_soc_bias_level level) +{ + MA_DBG("ma1026" "set ma1026 bias level level = %d \n", level); + if (level == SND_SOC_BIAS_ON) { + snd_soc_component_update_bits(codec, MA1026_DMMCC, + MA1026_MCLKDIS, 0); + snd_soc_component_update_bits(codec, MA1026_PWRCTRL1, + MA1026_PDN, 0); + } + return 0; +} + +static DECLARE_TLV_DB_SCALE(micpga_tlv, 0, 100, 0); +static DECLARE_TLV_DB_SCALE(ipdig_tlv, -9600, 100, 0); +static DECLARE_TLV_DB_SCALE(adc_20db_tlv, 0, 2000, 0); + +static const char * const ma1026_pgaa[] = {"Line 1", "Mic 1"}; +static const char * const ma1026_pgab[] = {"Line 2", "Mic 2"}; + +static const struct soc_enum pgaa_enum = + SOC_ENUM_SINGLE(MA1026_ADCIPC, 3, ARRAY_SIZE(ma1026_pgaa), ma1026_pgaa); + +static const struct soc_enum pgab_enum = + SOC_ENUM_SINGLE(MA1026_ADCIPC, 7, ARRAY_SIZE(ma1026_pgab), ma1026_pgab); + +static const char * const ma1026_ip_swap[] = { + "Stereo", + "Mono 1", + "Mono 2", + "Swap 1/2" +}; + +static const struct soc_enum ip_swap_enum = + SOC_ENUM_SINGLE(MA1026_MIOPC, 6, + ARRAY_SIZE(ma1026_ip_swap), ma1026_ip_swap); + +static const char * const ma1026_ng_delay[] = { + "50ms", + "100ms", + "150ms", + "200ms" +}; + +static const struct soc_enum ng_delay_enum = + SOC_ENUM_SINGLE(MA1026_NGCAB, 0, + ARRAY_SIZE(ma1026_ng_delay), ma1026_ng_delay); + +static const struct snd_kcontrol_new pgaa_mux = + SOC_DAPM_ENUM("Left Analog Input Capture Mux", pgaa_enum); + +static const struct snd_kcontrol_new pgab_mux = + SOC_DAPM_ENUM("Right Analog Input Capture Mux", pgab_enum); + +static const struct snd_kcontrol_new input_left_mixer[] = { + SOC_DAPM_SINGLE("ADC Left Input", MA1026_PWRCTRL1, 5, 1, 1), + SOC_DAPM_SINGLE("DMIC Left Input", MA1026_PWRCTRL1, 4, 1, 1), +}; + +static const struct snd_kcontrol_new input_right_mixer[] = { + SOC_DAPM_SINGLE("ADC Right Input", MA1026_PWRCTRL1, 7, 1, 1), + SOC_DAPM_SINGLE("DMIC Right Input", MA1026_PWRCTRL1, 6, 1, 1), +}; + +static DECLARE_TLV_DB_SCALE(hpd_tlv, -10200, 50, 0); +static DECLARE_TLV_DB_SCALE(hpa_tlv, -5400, 200, 0); + +static const unsigned int limiter_tlv[] = { + TLV_DB_RANGE_HEAD(2), + 0, 2, TLV_DB_SCALE_ITEM(-3000, 600, 0), + 3, 7, TLV_DB_SCALE_ITEM(-1200, 300, 0), +}; + +static const char * const ma1026_playback_path_mode[] = { + "OPEN SPK", + "CLOSE SPK", + "OPEN HP A", + "CLOSE HP A", + "OPEN HP B", + "CLOSE HP B", + "OPEN HP", + "CLOSE HP" +}; + +static const char * const ma1026_capture_path_mode[] = { + "OPEN DIGITAL MIC", + "CLOSE DIGITAL MIC", + "OPEN MIC A", + "CLOSE MIC A", + "OPEN MIC B", + "CLOSE MIC B" +}; + +static const char * const ma1026_mute_mode[] = { + "MUTE OFF", + "MUTE ON", +}; + +static SOC_ENUM_SINGLE_DECL(ma1026_playback_path_type, + 0, 0, ma1026_playback_path_mode); + +static SOC_ENUM_SINGLE_DECL(ma1026_capture_path_type, + 0, 0, ma1026_capture_path_mode); + +static SOC_ENUM_SINGLE_DECL(ma1026_mute_type, + 0, 0, ma1026_mute_mode); + +static int ma1026_playback_path_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct ma1026_priv *ma1026 = snd_soc_component_get_drvdata(component); + + MA_DBG("ma1026 %s : playback_path %ld\n", + __func__, ma1026->playback_path); + + ucontrol->value.integer.value[0] = ma1026->playback_path; + + return 0; +} + +static int ma1026_playback_path_config(struct snd_soc_component *component, + long int pre_path, long int target_path) +{ + int reg = 0; + struct ma1026_priv *ma1026 = snd_soc_component_get_drvdata(component); + + ma1026->playback_path = target_path; + + switch (ma1026->playback_path) { + case OPEN_SPK_E: + break; + + case CLOSE_SPK: + break; + + case OPEN_HP_A: + snd_soc_update_ma1026(component, MA1026_MICBSVDDA, + MA1026_MICBSVDDA_HPA, 1<<5); + snd_soc_update_ma1026(component, MA1026_PWRCTRL3, + MA1026_PDN_HP, 0); + break; + + case CLOSE_HP_A: + snd_soc_update_ma1026(component, MA1026_MICBSVDDA, + MA1026_MICBSVDDA_HPA, 0<<5); + reg = snd_soc_read_ma1026(component, MA1026_MICBSVDDA); + MA_DBG("ma1026" "%s : ma1026_MICBSVDDA = %x\n", __func__, reg); + if ((reg&MA1026_MICBSVDDA_HPB) == 0) + snd_soc_update_ma1026(component, MA1026_PWRCTRL3, + MA1026_PDN_HP, 1); + break; + + case OPEN_HP_B: + snd_soc_update_ma1026(component, MA1026_MICBSVDDA, + MA1026_MICBSVDDA_HPB, 1<<6); + snd_soc_update_ma1026(component, MA1026_PWRCTRL3, + MA1026_PDN_HP, 0); + break; + + case CLOSE_HP_B: + snd_soc_update_ma1026(component, MA1026_MICBSVDDA, + MA1026_MICBSVDDA_HPB, 0<<6); + reg = snd_soc_read_ma1026(component, MA1026_MICBSVDDA); + MA_DBG("ma1026" "%s : ma1026_MICBSVDDA = %x\n", __func__, reg); + if ((reg&MA1026_MICBSVDDA_HPA) == 0) + snd_soc_update_ma1026(component, MA1026_PWRCTRL3, + MA1026_PDN_HP, 1); + break; + + case OPEN_HP: + snd_soc_update_ma1026(component, MA1026_MICBSVDDA, + MA1026_MICBSVDDA_HPA, 1<<5); + snd_soc_update_ma1026(component, MA1026_MICBSVDDA, + MA1026_MICBSVDDA_HPB, 1<<6); + break; + + case CLOSE_HP: + snd_soc_update_ma1026(component, MA1026_MICBSVDDA, + MA1026_MICBSVDDA_HPB, 0<<6); + snd_soc_update_ma1026(component, MA1026_MICBSVDDA, + MA1026_MICBSVDDA_HPB, 0<<5); + snd_soc_update_ma1026(component, MA1026_PWRCTRL3, + MA1026_PDN_HP, 1); + break; + } + + return 0; +} + +static int ma1026_playback_path_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct ma1026_priv *ma1026 = snd_soc_component_get_drvdata(component); + static int isSet; + + if ((ma1026->playback_path == ucontrol->value.integer.value[0]) && + (isSet == 1)) { + MA_DBG("ma1026" "%s : playback_path is not changed!\n", + __func__); + return 0; + } + isSet = 1; + return ma1026_playback_path_config(component, ma1026->playback_path, + ucontrol->value.integer.value[0]); +} + +static int ma1026_capture_path_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct ma1026_priv *ma1026 = snd_soc_component_get_drvdata(component); + + MA_DBG("ma1026 %s : capture_path %ld\n", __func__, + ma1026->capture_path); + + ucontrol->value.integer.value[0] = ma1026->capture_path; + return 0; +} + +static int ma1026_capture_path_config(struct snd_soc_component *component, + long pre_path, long target_path) +{ + struct ma1026_priv *ma1026 = snd_soc_component_get_drvdata(component); + + ma1026->capture_path = target_path; + + switch (ma1026->capture_path) { + case OPEN_DIGITAL_MIC: + snd_soc_update_ma1026(component, MA1026_PWRCTRL1, + MA1026_PDN_DMICB, 0<<6); + snd_soc_update_ma1026(component, MA1026_PWRCTRL1, + MA1026_PDN_DMICB, 0<<4); + snd_soc_update_ma1026(component, MA1026_PWRCTRL1, + MA1026_PDN_ADCB, 1<<7); + snd_soc_update_ma1026(component, MA1026_PWRCTRL1, + MA1026_PDN_ADCA, 1<<5); + break; + + case CLOSE_DIGITAL_MIC: + snd_soc_update_ma1026(component, MA1026_PWRCTRL1, + MA1026_PDN_DMICB, 0<<6); + snd_soc_update_ma1026(component, MA1026_PWRCTRL1, + MA1026_PDN_DMICB, 0<<4); + snd_soc_update_ma1026(component, MA1026_PWRCTRL1, + MA1026_PDN_ADCB, 0<<7); + snd_soc_update_ma1026(component, MA1026_PWRCTRL1, + MA1026_PDN_ADCA, 0<<5); + break; + + case SELECT_MIC_A: + snd_soc_update_ma1026(component, MA1026_ADCIPC, + MA1026_ADCIPC_MICB_LINEB, 1<<7); + break; + + case SELECT_LINE_A: + snd_soc_update_ma1026(component, MA1026_ADCIPC, + MA1026_ADCIPC_MICB_LINEB, 0<<7); + break; + + case SELECT_MIC_B: + snd_soc_update_ma1026(component, MA1026_ADCIPC, + MA1026_ADCIPC_MICA_LINEA, 1<<3); + break; + + case SELECT_LINE_B: + snd_soc_update_ma1026(component, MA1026_ADCIPC, + MA1026_ADCIPC_MICA_LINEA, 0<<3); + break; + + default: + break; + } + + return 0; +} + +static int ma1026_capture_path_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct ma1026_priv *ma1026 = snd_soc_component_get_drvdata(component); + static int isSet; + + if ((ma1026->capture_path == ucontrol->value.integer.value[0]) && + (isSet == 1)) { + MA_DBG("ma1026" "%s : capture_path is not changed!\n", + __func__); + return 0; + } + isSet = 1; + return ma1026_capture_path_config(component, ma1026->capture_path, + ucontrol->value.integer.value[0]); +} + +static int ma1026_mute_path_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct ma1026_priv *ma1026 = snd_soc_component_get_drvdata(component); + + MA_DBG("ma1026 %s : force_muted %ld\n", __func__, ma1026->force_muted); + + ucontrol->value.integer.value[0] = ma1026->force_muted; + return 0; +} + +static int ma1026_muted_path_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct ma1026_priv *ma1026 = snd_soc_component_get_drvdata(component); + + if (!ucontrol->value.integer.value[0]) { + ma1026->force_muted = 0; + snd_soc_update_ma1026(component, MA1026_HPDC, 1<<1, 0<<1); + snd_soc_update_ma1026(component, MA1026_HPDC, 1<<0, 0<<0); + } else { + ma1026->force_muted = 1; + snd_soc_update_ma1026(component, MA1026_HPDC, 1<<1, 1<<1); + snd_soc_update_ma1026(component, MA1026_HPDC, 1<<0, 1<<0); + } + + return 0; +} + +static const DECLARE_TLV_DB_SCALE(attn_tlv, -6300, 100, 1); + +static const struct snd_kcontrol_new ma1026_snd_controls[] = { + /* range 0-30 */ + SOC_DOUBLE_R_S_TLV("HP_A_PlaybackVolume", + MA1026_HPAAVOL, MA1026_HPBAVOL, 1, + -27, 3, 5, 0, hpa_tlv), + + SOC_DOUBLE_R("HP Analog Playback Mute", MA1026_HPAAVOL, + MA1026_HPBAVOL, 7, 1, 1), + + /* range 0-24 */ + SOC_DOUBLE_R_TLV("Input PGA Analog Volume", + MA1026_MICPGAAVOL, MA1026_MICPGABVOL, 0, + 0x18, 0, micpga_tlv), + + /* range 0-108 */ + SOC_DOUBLE_R_S_TLV("Input Path Digital Volume", + MA1026_IPADVOL, MA1026_IPBDVOL, 0x00, + -96, 12, 7, 0, ipdig_tlv), + + SOC_DOUBLE_R("MIC Preamp Switch", MA1026_MICPGAAVOL, + MA1026_MICPGABVOL, 6, 1, 1), + + SOC_SINGLE_TLV("ADC A 20db", + MA1026_ADCIPC, 2, + 0x01, 1, adc_20db_tlv), + + SOC_SINGLE_TLV("ADC B 20db", + MA1026_ADCIPC, 6, + 0x01, 1, adc_20db_tlv), + + SOC_DOUBLE("Input Path Digital Mute", MA1026_ADCIPC, 0, 4, 1, 1), + SOC_DOUBLE("HP Digital Playback left Mute", MA1026_HPDC, 0, 1, 1, 1), + SOC_SINGLE("PGA Soft Ramp Switch", MA1026_MIOPC, 3, 1, 0), + SOC_SINGLE("Analog 0 Cross Switch", MA1026_MIOPC, 2, 1, 0), + SOC_SINGLE("Digital Soft Ramp Switch", MA1026_MIOPC, 1, 1, 0), + SOC_SINGLE("Analog Output Soft Ramp Switch", MA1026_MIOPC, 0, 1, 0), + + SOC_DOUBLE("ADC Signal Polarity Switch", MA1026_ADCIPC, 1, 5, 1, 0), + + SOC_SINGLE("HP Limiter Attack Rate", MA1026_LIMATTRATEHP, 0, 0x3F, 0), + SOC_SINGLE("HP Limiter Release Rate", MA1026_LIMRLSRATEHP, 0, 0x3F, 0), + SOC_SINGLE("HP Limiter Switch", MA1026_LIMRLSRATEHP, 7, 1, 0), + SOC_SINGLE("HP Limiter All Channels Switch", + MA1026_LIMRLSRATEHP, 6, 1, 0), + + SOC_SINGLE_TLV("HP Limiter Max Threshold Vol", MA1026_LMAXMINHP, + 5, 7, 1, limiter_tlv), + SOC_SINGLE_TLV("HP Limiter Min Threshold Vol", MA1026_LMAXMINHP, + 2, 7, 1, limiter_tlv), + + SOC_SINGLE("ALC Attack Rate Volume", MA1026_ALCARATE, 0, 0x3F, 0), + SOC_SINGLE("ALC Release Rate Volume", MA1026_ALCRRATE, 0, 0x3F, 0), + SOC_DOUBLE("ALC Switch", MA1026_ALCARATE, 6, 7, 1, 0), + + SOC_SINGLE_TLV("ALC Max Threshold Volume", MA1026_ALCMINMAX, + 5, 7, 0, limiter_tlv), + SOC_SINGLE_TLV("ALC Min Threshold Volume", MA1026_ALCMINMAX, + 2, 7, 0, limiter_tlv), + + SOC_DOUBLE("NG Enable Switch", MA1026_NGCAB, 6, 7, 1, 0), + SOC_SINGLE("NG Boost Switch", MA1026_NGCAB, 5, 1, 0), + SOC_SINGLE("NG Threshold", MA1026_NGCAB, 2, 7, 0), + SOC_SINGLE("HP Amp CTRL", MA1026_PWRCTRL3, 0, 1, 0), + + SOC_ENUM("NG Delay", ng_delay_enum), + + SOC_DOUBLE_R_TLV("IP2ASP Volume", MA1026_IPA2ASPA, MA1026_IPB2ASPB, + 0, 0x3F, 1, attn_tlv), + SOC_DOUBLE_R_TLV("ASP2ASP Volume", MA1026_ASPA2ASPA, MA1026_ASPB2ASPB, + 0, 0x3F, 1, attn_tlv), + SOC_DOUBLE_R_TLV("IP2HP Volume", MA1026_IPA2HPA, MA1026_IPB2HPB, + 0, 0x3F, 1, attn_tlv), + SOC_DOUBLE_R_TLV("ASP2HP Volume", MA1026_ASPA2HPA, MA1026_ASPB2HPB, + 0, 0x3F, 1, attn_tlv), + + SOC_ENUM("IP Digital Swap/Mono Select", ip_swap_enum), + SOC_ENUM_EXT("Playback Opt", ma1026_playback_path_type, + ma1026_playback_path_get, ma1026_playback_path_put), + SOC_ENUM_EXT("Capture MIC Opt", ma1026_capture_path_type, + ma1026_capture_path_get, ma1026_capture_path_put), + SOC_ENUM_EXT("Mute", ma1026_mute_type, + ma1026_mute_path_get, ma1026_muted_path_put), +}; + +static int ma1026_init_regs( +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 00, 0)) + struct snd_soc_codec *codec +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(4, 00, 0)) + struct snd_soc_component *codec +#endif +) +{ + MA_DBG("ma1026" " init all regs...\n"); +#if TEMP_DEBUG + snd_soc_write_ma1026(codec, 0x00, 0x68); + snd_soc_write_ma1026(codec, ma1026_PWRCTRL1, 0x00); + snd_soc_update_ma1026(codec, ma1026_PWRCTRL1, ma1026_PDN_LDO, 1<<3); + snd_soc_update_ma1026(codec, ma1026_PWRCTRL1, ma1026_PDN, 0); + + /* Set the main clk division */ + snd_soc_update_ma1026(codec, ma1026_DMMCC, ma1026_FREQ_DIV, 2<<1); + snd_soc_update_ma1026(codec, ma1026_DMMCC, ma1026_MCLKDIS, 0); + + /* Open I2S input/output */ + snd_soc_update_ma1026(codec, ma1026_PWRCTRL2, ma1026_PDN_ASP_SDO, 0); + snd_soc_update_ma1026(codec, ma1026_PWRCTRL2, ma1026_PDN_ASP_SDI, 0); +#endif + snd_soc_write_ma1026(codec, 0x00, 0x68); + snd_soc_write_ma1026(codec, 0x0A, 0x88); + snd_soc_write_ma1026(codec, 0x01, 0x00); + snd_soc_write_ma1026(codec, 0x01, 0x08); + snd_soc_write_ma1026(codec, 0x05, 0x65); + snd_soc_write_ma1026(codec, 0x02, 0x1F); + snd_soc_write_ma1026(codec, 0x06, 0x04); + snd_soc_write_ma1026(codec, 0x02, 0x13); + snd_soc_write_ma1026(codec, 0x12, 0x02); + snd_soc_write_ma1026(codec, 0x13, 0x02); + + snd_soc_write_ma1026(codec, 0x21, 0x00); + snd_soc_write_ma1026(codec, 0x22, 0x00); + snd_soc_write_ma1026(codec, 0x23, 0x00); + snd_soc_write_ma1026(codec, 0x24, 0x00); + snd_soc_write_ma1026(codec, 0x03, 0x1c); + + snd_soc_write_ma1026(codec, 0x2c, 0xc1); + + return 0; +} + +static int ma1026_probe( +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 00, 0)) + struct snd_soc_codec *codec +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(4, 00, 0)) + struct snd_soc_component *codec +#endif +) +{ + int ret = 0; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 00, 0)) + struct ma1026_priv *ma1026 = snd_soc_codec_get_drvdata(codec); +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(4, 00, 0)) + struct ma1026_priv *ma1026 = snd_soc_component_get_drvdata(codec); +#endif + ma1026_codec = codec; + + MA_DBG("ma1026" " alsa start ....\n"); + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 00, 0)) + codec->control_data = ma1026->regmap; +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(4, 00, 0)) + snd_soc_component_init_regmap(codec, ma1026->regmap); +#endif + + ma1026_set_bias_level(codec, SND_SOC_BIAS_ON); + + ma1026_init_regs(codec); + + ma1026->mclk = devm_clk_get(codec->dev, "mclk"); + if (PTR_ERR(ma1026->mclk) == -EPROBE_DEFER) + return -EPROBE_DEFER; + + MA_DBG("ma1026" "alsa driver finish.... \n"); + return ret; +} + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 00, 0)) +static int ma1026_remove( + struct snd_soc_codec *codec +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(4, 00, 0)) +static void ma1026_remove( + struct snd_soc_component *codec +#endif +) +{ + ma1026_set_bias_level(codec, SND_SOC_BIAS_OFF); +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 00, 0)) + return 0; +#endif +} + +static int ma1026_suspend( +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 00, 0)) + struct snd_soc_codec *codec +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(4, 00, 0)) + struct snd_soc_component *codec +#endif + ) +{ + MA_DBG("ma1026" " suspend ...\n"); + ma1026_set_bias_level(codec, SND_SOC_BIAS_OFF); + return 0; +} + +static int ma1026_resume( +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 00, 0)) + struct snd_soc_codec *codec +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(4, 00, 0)) + struct snd_soc_component *codec +#endif + ) +{ + MA_DBG("ma1026" " resume ...\n"); + ma1026_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + return 0; +} + +static const struct snd_soc_dapm_widget dit_widgets[] = { + SND_SOC_DAPM_OUTPUT("HPOUTA"), + SND_SOC_DAPM_OUTPUT("HPOUTB"), + + SND_SOC_DAPM_INPUT("LINEIN1"), + SND_SOC_DAPM_INPUT("LINEIN2"), + SND_SOC_DAPM_INPUT("MIC1"), + SND_SOC_DAPM_INPUT("MIC2"), + + SND_SOC_DAPM_DAC("HP Amp", NULL, MA1026_PWRCTRL3, 0, 0), + + SND_SOC_DAPM_MIXER_NAMED_CTL("Input Left Capture", SND_SOC_NOPM, + 0, 0, input_left_mixer, ARRAY_SIZE(input_left_mixer)), + SND_SOC_DAPM_MIXER_NAMED_CTL("Input Right Capture", SND_SOC_NOPM, + 0, 0, input_right_mixer, ARRAY_SIZE(input_right_mixer)), + + SND_SOC_DAPM_ADC("DMIC Left", NULL, MA1026_PWRCTRL1, 6, 0), + SND_SOC_DAPM_ADC("DMIC Right", NULL, MA1026_PWRCTRL1, 4, 0), +}; + +static const struct snd_soc_dapm_route dit_routes[] = { + {"HPOUTA", NULL, "ASP Playback"}, + {"HPOUTA", NULL, "ASP Playback"}, +}; + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 00, 0)) +static struct snd_soc_codec_driver soc_codec_dev_ma1026 = { +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(4, 00, 0)) +static struct snd_soc_component_driver soc_codec_dev_ma1026 = { +#endif + .probe = ma1026_probe, + .remove = ma1026_remove, + .suspend = ma1026_suspend, + .resume = ma1026_resume, + .set_bias_level = ma1026_set_bias_level, + .dapm_widgets = dit_widgets, + .num_dapm_widgets = ARRAY_SIZE(dit_widgets), + .dapm_routes = dit_routes, + .num_dapm_routes = ARRAY_SIZE(dit_routes), + .controls = ma1026_snd_controls, + .num_controls = ARRAY_SIZE(ma1026_snd_controls), +}; + +static int ma1026_pcm_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + bool playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); + + if (playback) + msleep(50); + + return 0; +} + + +static int ma1026_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 00, 0)) + struct snd_soc_codec *codec = dai->codec; + struct ma1026_priv *priv = snd_soc_codec_get_drvdata(codec); +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(4, 00, 0)) + struct snd_soc_component *codec = dai->component; + struct ma1026_priv *priv = snd_soc_component_get_drvdata(codec); +#endif + int lrckfreq = params_rate(params); + int i, index = -1; + if (priv->config.mmcc & MA1026_MS_MASTER) { + + for (i = 0; i < ARRAY_SIZE(ma1026_mclk_coeffs); i++) { + if (ma1026_mclk_coeffs[i].lrckfreq == lrckfreq) + index = i; + } + + if (index < 0) { + MA_DBG("ma1026" " ma1026_pcm_hw_params, mclk = %d\n", index); + return -EINVAL; + } + + dev_dbg(codec->dev, "DAI[ ]: lrckfreq %u, MMCC[5:0] = %x\n", + lrckfreq, ma1026_mclk_coeffs[index].mmcc); + + priv->config.mmcc &= 0xC0; + priv->config.mmcc |= ma1026_mclk_coeffs[index].mmcc; + priv->config.spc &= 0xFC; + } else { + priv->config.spc &= 0xFC; + priv->config.spc |= MA1026_MCK_SCLK_64FS; + } + priv->config.lrckfreq = lrckfreq; + + snd_soc_write_ma1026(codec, MA1026_ASPMMCC, priv->config.mmcc); + + return 0; +} + +static int ma1026_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) +{ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 00, 0)) + struct snd_soc_codec *codec = codec_dai->codec; + struct ma1026_priv *priv = snd_soc_codec_get_drvdata(codec); +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(4, 00, 0)) + struct snd_soc_component *codec = codec_dai->component; + struct ma1026_priv *priv = snd_soc_component_get_drvdata(codec); +#endif + u8 spc, mmcc; + + spc = snd_soc_read_ma1026(codec, MA1026_ASPC); + mmcc = snd_soc_read_ma1026(codec, MA1026_ASPMMCC); + + if (fmt == SND_SOC_DAIFMT_CBM_CFM) + mmcc |= MA1026_MS_MASTER; + else + mmcc &= ~MA1026_MS_MASTER; + + if (fmt == SND_SOC_DAIFMT_I2S) + spc &= ~MA1026_SPDIF_PCM; + else + spc |= MA1026_SPDIF_PCM; + + if (spc & MA1026_SPDIF_PCM) + spc &= ~MA1026_PCM_BIT_ORDER; + + priv->config.spc = spc; + priv->config.mmcc = mmcc; + + return 0; +} + +static int ma1026_set_dai_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 00, 0)) + struct snd_soc_codec *codec = codec_dai->codec; + struct ma1026_priv *ma1026 = snd_soc_codec_get_drvdata(codec); +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(4, 00, 0)) + struct snd_soc_component *codec = codec_dai->component; + struct ma1026_priv *ma1026 = snd_soc_component_get_drvdata(codec); +#endif + MA_DBG("ma1026" " ma1026_set_dai_sysclk, freq = %d\n", freq); + + switch (freq) { + case 11289600: + case 18432000: + case 22579200: + case 36864000: + ma1026->sysclk_constraints = &constraints_112896; + ma1026->sysclk = freq; + return 0; + case 12288000: + case 19200000: + case 16934400: + case 24576000: + case 33868800: + ma1026->sysclk_constraints = &constraints_12288; + ma1026->sysclk = freq; + return 0; + case 12000000: + ma1026->sysclk_constraints = &constraints_12; + ma1026->sysclk = freq; + return 0; + } + return -EINVAL; +} + +static int ma1026_mute(struct snd_soc_dai *dai, int mute +#if (LINUX_VERSION_CODE > KERNEL_VERSION(5, 00, 0)) + , int stream +#endif +) +{ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 00, 0)) + struct snd_soc_codec *codec = dai->codec; + struct ma1026_priv *ma1026 = snd_soc_codec_get_drvdata(codec); +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(4, 00, 0)) + struct snd_soc_component *codec = dai->component; + struct ma1026_priv *ma1026 = snd_soc_component_get_drvdata(codec); +#endif + + MA_DBG("ma1026" " ma1026_mute, mute = %d\n", mute); + if (ma1026->force_muted) + return 0; + + if (mute) { + snd_soc_update_ma1026(codec, MA1026_HPDC, 1<<1, 1<<1); + snd_soc_update_ma1026(codec, MA1026_HPDC, 1<<0, 1<<0); + } else { + snd_soc_update_ma1026(codec, MA1026_HPDC, 1<<1, 0<<1); + snd_soc_update_ma1026(codec, MA1026_HPDC, 1<<0, 0<<0); + } + return 0; +} + +#define ma1026_pcm_shutdown NULL + +static struct snd_soc_dai_ops ma1026_ops = { + .startup = ma1026_pcm_startup, + .hw_params = ma1026_pcm_hw_params, + .set_fmt = ma1026_set_dai_fmt, + .set_sysclk = ma1026_set_dai_sysclk, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 00, 0)) + .digital_mute = ma1026_mute, +#else + .mute_stream = ma1026_mute, +#endif +}; + +static struct snd_soc_dai_driver ma1026_dai = { + .name = "ma1026-asp", + .playback = { + .stream_name = "ASP Playback", + .channels_min = 1, + .channels_max = 2, + .rates = MA1026_LRCK, + .formats = MA1026_FORMATS, + }, + .capture = { + .stream_name = "ASP Capture", + .channels_min = 1, + .channels_max = 2, + .rates = MA1026_LRCK, + .formats = MA1026_FORMATS, + }, + .ops = &ma1026_ops, + .symmetric_rates = 1, +}; + +static int ma1026_i2c_probe(struct i2c_client *i2c_client, + const struct i2c_device_id *id) +{ + struct ma1026_priv *ma1026; + int ret; + + MA_DBG("ma1026" " run driver .... \n"); + + ma1026 = devm_kzalloc(&i2c_client->dev, sizeof(struct ma1026_priv), + GFP_KERNEL); + if (!ma1026) { + MA_DBG("ma1026 " "could not allocate codec\n"); + return -ENOMEM; + } + memset(ma1026, 0x00, sizeof(struct ma1026_priv)); + ma1026->regmap = devm_regmap_init_i2c(i2c_client, &ma1026_regmap); + if (IS_ERR(ma1026->regmap)) { + ret = PTR_ERR(ma1026->regmap); + MA_DBG("ma1026 ""regmap_init() failed: %d\n", ret); + return ret; + } + + i2c_set_clientdata(i2c_client, ma1026); + + globe_ma1026 = ma1026; + + ma1026->hp_mute = 1; + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0)) + ret = snd_soc_register_codec(&i2c_client->dev, + &soc_codec_dev_ma1026, &ma1026_dai, 1); +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(4, 19, 0)) + ret = devm_snd_soc_register_component(&i2c_client->dev, + &soc_codec_dev_ma1026, &ma1026_dai, 1); +#endif + + if (ret < 0) { + MA_DBG("ma1026 ""%s() register codec error %d\n", + __func__, ret); + return ret; + } + + MA_DBG("ma1026" " load end ret=%d\n", ret); + + return 0; +} + +static int ma1026_i2c_remove(struct i2c_client *client) +{ + snd_soc_unregister_component(&client->dev); + return 0; +} + +static void ma1026_i2c_shutdown(struct i2c_client *client) +{ + if (ma1026_codec != NULL) { + msleep(20); + ma1026_set_bias_level(ma1026_codec, SND_SOC_BIAS_OFF); + } +} + + +static const struct of_device_id ma1026_of_match[] = { + {.compatible = "Phytium, ma1026", }, + {} +}; + +MODULE_DEVICE_TABLE(of, ma1026_of_match); + +static const struct i2c_device_id ma1026_id[] = { + {"ma1026", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, ma1026_id); + +static struct i2c_driver ma1026_i2c_driver = { + .driver = { + .name = "ma1026", + .of_match_table = ma1026_of_match, + }, + .probe = ma1026_i2c_probe, + .remove = ma1026_i2c_remove, + .shutdown = ma1026_i2c_shutdown, + .id_table = ma1026_id, +}; +module_i2c_driver(ma1026_i2c_driver); + +MODULE_DESCRIPTION("Cubiclattice ma1026 driver"); +MODULE_AUTHOR("Cubiclattice Ltd"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/ma1026.h b/sound/soc/codecs/ma1026.h new file mode 100644 index 0000000000..05aeb15fb3 --- /dev/null +++ b/sound/soc/codecs/ma1026.h @@ -0,0 +1,127 @@ +#ifndef __MA1026_H__ +#define __MA1026_H__ + +/* I2C Registers */ +#define MA1026_PWRCTRL1 0x01 /* Power Ctrl 1. */ +#define MA1026_PWRCTRL2 0x02 /* Power Ctrl 2. */ +#define MA1026_PWRCTRL3 0x03 /* Power Ctrl 3. */ +#define MA1026_CPFCHC 0x04 /* Charge Pump Freq. Class H Ctrl. */ +#define MA1026_MICBSVDDA 0x05 /* MIC Bias & VDDA Voltage*/ +#define MA1026_DMMCC 0x06 /* Digital MIC & Master Clock Ctrl. */ +#define MA1026_ASPC 0x07 /* Audio Serial Port (ASP) Control. */ +#define MA1026_ASPMMCC 0x08 /* ASP Master Mode Control. */ +#define MA1026_MIOPC 0x09 /* Input & Output Path Control. */ +#define MA1026_ADCIPC 0x0A /* ADC/IP Control. */ +#define MA1026_MICPGAAVOL 0x0B /* MIC 1 PreAmp, PGAA Vol. */ +#define MA1026_MICPGABVOL 0x0C /* MIC 2 PreAmp, PGAB Vol. */ +#define MA1026_IPADVOL 0x0D /* Input Path A Digital Volume. */ +#define MA1026_IPBDVOL 0x0E /* Input Path B Digital Volume. */ +#define MA1026_HPDC 0x0F /* HP Digital Control. */ +#define MA1026_HPADVOL 0x10 /* HP A Digital Vol. */ +#define MA1026_HPBDVOL 0x11 /* HP B Digital Vol. */ +#define MA1026_HPAAVOL 0x12 /* HP A Analog Volume. */ +#define MA1026_HPBAVOL 0x13 /* HP B Analog Volume. */ +#define MA1026_ANAINVOL 0x14 /* Analog Input Path Advisory Vol. */ +#define MA1026_ASPINVOL 0x15 /* ASP Input Path Advisory Vol. */ +#define MA1026_LIMATTRATEHP 0x16 /* Limit Attack Rate HP. */ +#define MA1026_LIMRLSRATEHP 0x17 /* Limit Release Rate HP. */ +#define MA1026_LMAXMINHP 0x18 /* Limit Thresholds HP. */ +#define MA1026_ALCARATE 0x19 /* ALC Enable, Attack Rate AB. */ +#define MA1026_ALCRRATE 0x1A /* ALC Release Rate AB. */ +#define MA1026_ALCMINMAX 0x1B /* ALC Thresholds AB. */ +#define MA1026_NGCAB 0x1C /* Noise Gate Ctrl AB. */ +#define MA1026_ALCNG 0x1D /* ALC & Noise Gate Ctrl. */ +#define MA1026_MIXERCTL 0x1E /* Mixer Control. */ +#define MA1026_IPA2HPA 0x1F /* HP Left Mixer */ +#define MA1026_IPB2HPB 0x20 /* HP Right Mixer */ +#define MA1026_ASPA2HPA 0x21 /* HP Left Mixer */ +#define MA1026_ASPB2HPB 0x22 /* HP Right Mixer */ +#define MA1026_IPA2ASPA 0x23 /* ASP Left Mixer */ +#define MA1026_IPB2ASPB 0x24 /* ASP Right Mixer */ +#define MA1026_ASPA2ASPA 0x25 /* ASP Left Mixer */ +#define MA1026_ASPB2ASPB 0x26 /* ASP Right Mixer */ +#define MA1026_IM 0x5E /* Interrupt Mask */ +#define MA1026_IS 0x60 /* Interrupt Status */ +#define MA1026_MAX_REGISTER 0xff /* Total Registers */ +/* Bitfield Definitions */ + +/* MA1026_PWRCTRL1 */ +#define MA1026_PDN_ADCB (1 << 7) +#define MA1026_PDN_DMICB (1 << 6) +#define MA1026_PDN_ADCA (1 << 5) +#define MA1026_PDN_DMICA (1 << 4) +#define MA1026_PDN_LDO (1 << 3) +#define MA1026_PDN (1 << 0) + +/* MA1026_PWRCTRL2 */ +#define MA1026_PDN_MICBS2 (1 << 7) +#define MA1026_PDN_MICBS1 (1 << 6) +#define MA1026_PDN_ASP_SDO (1 << 3) +#define MA1026_PDN_ASP_SDI (1 << 2) + +/* MA1026_PWRCTRL3 */ +#define MA1026_PDN_HP (1 << 0) + +#define MA1026_CP_MASK (0xF0) + +/* MA1026_ASPC */ +#define MA1026_SP_3ST (1 << 7) +#define MA1026_SPDIF_PCM (1 << 6) +#define MA1026_PCM_BIT_ORDER (1 << 3) +#define MA1026_MCK_SCLK_64FS (0 << 0) +#define MA1026_MCK_SCLK_MCLK (2 << 0) +#define MA1026_MCK_SCLK_PREMCLK (3 << 0) + +/* MA1026_ASPMMCC */ +#define MA1026_MS_MASTER (1 << 7) + + +/* MA1026_DMMCC */ +#define MA1026_MCLKDIS (1 << 0) +#define MA1026_FREQ_DIV (2 << 1) +/* IS1, IM1 */ +#define MA1026_MIC_SDET (1 << 6) + +/* Analog Softramp */ +#define MA1026_ANLGOSFT (1 << 0) + +/* MA1026 MCLK 0 from EXT CLK; 1 from PLL OUTPUT*/ +#define MA1026_CLKID 0 + +/*MA1026_MICBSVDDA */ +#define MA1026_MICBSVDDA_HPA (1<<5) +#define MA1026_MICBSVDDA_HPB (1<<6) + +/*MA1026_ADCIPC */ +#define MA1026_ADCIPC_MICB_LINEB (1<<7) +#define MA1026_ADCIPC_MICA_LINEA (1<<3) + +enum output +{ + OPEN_SPK_E, + CLOSE_SPK, + + OPEN_HP_A, + CLOSE_HP_A, + + OPEN_HP_B, + CLOSE_HP_B, + + OPEN_HP, + CLOSE_HP, +} ; +enum input +{ + OPEN_DIGITAL_MIC, + CLOSE_DIGITAL_MIC, + + SELECT_MIC_A, + SELECT_LINE_A, + + SELECT_MIC_B, + SELECT_LINE_B, + +}; + + +#endif /* __MA1026_H__ */ diff --git a/sound/soc/phytium/Kconfig b/sound/soc/phytium/Kconfig index c567699bcb..6c7b4570e5 100644 --- a/sound/soc/phytium/Kconfig +++ b/sound/soc/phytium/Kconfig @@ -48,3 +48,10 @@ config SND_PMDK_DP Say Y if you want to add Phytium machine support for Displayport. + +config SND_PMDK_MA1026 + tristate "Phytium machine support with MA1026" + depends on I2C && SND_SOC_PHYTIUM_I2S + select SND_SOC_MA1026 + help + Say Y if you want to add Phytium machine support for MA1026 \ No newline at end of file diff --git a/sound/soc/phytium/Makefile b/sound/soc/phytium/Makefile index b3e38c874d..f00fa8a35c 100644 --- a/sound/soc/phytium/Makefile +++ b/sound/soc/phytium/Makefile @@ -18,3 +18,6 @@ obj-$(CONFIG_SND_SOC_PHYTIUM_I2S_V2) += snd-soc-phytium-i2s-v2.o snd-soc-phytium-machine-v2-objs := phytium-machine-v2.o obj-$(CONFIG_SND_SOC_PHYTIUM_MACHINE_V2) += snd-soc-phytium-machine-v2.o + +snd-soc-pmdk-ma1026-objs :=pmdk_ma1026.o +obj-$(CONFIG_SND_PMDK_MA1026) += snd-soc-pmdk-ma1026.o diff --git a/sound/soc/phytium/pmdk_ma1026.c b/sound/soc/phytium/pmdk_ma1026.c new file mode 100644 index 0000000000..508163b5e4 --- /dev/null +++ b/sound/soc/phytium/pmdk_ma1026.c @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021-2024 Phytium Technology Co.,Ltd. + */ + +#include +#include +#include +#include +#include + +/* PMDK widgets */ +static const struct snd_soc_dapm_widget pmdk_ma1026_dapm_widgets[] = { + SND_SOC_DAPM_HP("HP", NULL), + SND_SOC_DAPM_MIC("Int Mic", NULL), + SND_SOC_DAPM_MIC("Mic In", NULL), +}; + +/* PMDK control */ +static const struct snd_kcontrol_new pmdk_ma1026_controls[] = { + SOC_DAPM_PIN_SWITCH("HP"), + SOC_DAPM_PIN_SWITCH("Int Mic"), + SOC_DAPM_PIN_SWITCH("Mic In"), +}; + +/* PMDK connections */ +static const struct snd_soc_dapm_route pmdk_ma1026_audio_map[] = { + {"DMIC", NULL, "Int Mic"}, + {"MIC1", NULL, "Mic In"}, + {"MIC2", NULL, "Mic In"}, + + {"HP", NULL, "HPOL"}, + {"HP", NULL, "HPOR"}, +}; + +#define PMDK_DAI_FMT (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | \ + SND_SOC_DAIFMT_CBS_CFS) + +SND_SOC_DAILINK_DEFS(pmdk_ma1026, + DAILINK_COMP_ARRAY(COMP_CPU("phytium-i2s-lsd")), + DAILINK_COMP_ARRAY(COMP_CODEC("i2c-MA1026:00", "ma1026-hifi")), + DAILINK_COMP_ARRAY(COMP_PLATFORM("snd-soc-dummy"))); + +static struct snd_soc_dai_link pmdk_dai[] = { + { + .name = "MA1026 HIFI", + .stream_name = "MA1026 HIFI", + .dai_fmt = PMDK_DAI_FMT, + SND_SOC_DAILINK_REG(pmdk_ma1026), + }, +}; + +static struct snd_soc_card pmdk = { + .name = "PMDK-I2S", + .owner = THIS_MODULE, + .dai_link = pmdk_dai, + .num_links = ARRAY_SIZE(pmdk_dai), + + .dapm_widgets = pmdk_ma1026_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(pmdk_ma1026_dapm_widgets), + .controls = pmdk_ma1026_controls, + .num_controls = ARRAY_SIZE(pmdk_ma1026_controls), + .dapm_routes = pmdk_ma1026_audio_map, + .num_dapm_routes = ARRAY_SIZE(pmdk_ma1026_audio_map), +}; + +static int pmdk_sound_probe(struct platform_device *pdev) +{ + struct snd_soc_card *card = &pmdk; + struct device *dev = &pdev->dev; + + card->dev = dev; + return devm_snd_soc_register_card(&pdev->dev, card); +} + +static const struct acpi_device_id pmdk_sound_acpi_match[] = { + { "PHYT8013", 0}, + { } +}; +MODULE_DEVICE_TABLE(acpi, pmdk_sound_acpi_match); + +static const struct of_device_id phytium_ma1026_of_match[] = { + { .compatible = "phytium,audio-ma1026",}, + {}, +}; + +static struct platform_driver pmdk_sound_driver = { + .probe = pmdk_sound_probe, + .driver = { + .name = "pmdk_ma1026", + .acpi_match_table = pmdk_sound_acpi_match, + .of_match_table = phytium_ma1026_of_match, +#ifdef CONFIG_PM + .pm = &snd_soc_pm_ops, +#endif + }, +}; + +module_platform_driver(pmdk_sound_driver); + +MODULE_AUTHOR("harry guo "); +MODULE_DESCRIPTION("ALSA SoC PMDK CL1026"); +MODULE_LICENSE("GPL"); -- Gitee From af06e13e10f747fa85a54e6124fcb40909543019 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8F=B2=E5=85=89=E8=BF=9C?= Date: Thu, 20 Feb 2025 08:17:52 +0000 Subject: [PATCH 142/155] driver: i2s: implement ma1026 support for ACPI Signed-off-by: liutianyu1250 --- sound/soc/codecs/Kconfig | 8 ++++---- sound/soc/codecs/Makefile | 4 ++-- sound/soc/codecs/ma1026.c | 20 +++++++++++++------- sound/soc/phytium/Kconfig | 8 ++++++++ sound/soc/phytium/pmdk_ma1026.c | 17 +++++------------ 5 files changed, 32 insertions(+), 25 deletions(-) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 5c81b1a5e3..5486ea1df2 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -224,7 +224,6 @@ config SND_SOC_ALL_CODECS imply SND_SOC_SIMPLE_AMPLIFIER imply SND_SOC_SIMPLE_MUX imply SND_SOC_SMA1303 - imply SND_SOC_MA1026 if I2C imply SND_SOC_SPDIF imply SND_SOC_SRC4XXX_I2C imply SND_SOC_SSM2305 @@ -1136,6 +1135,10 @@ config SND_SOC_LOCHNAGAR_SC This driver support the sound card functionality of the Cirrus Logic Lochnagar audio development board. +config SND_SOC_MA1026 + tristate "Cubiclattice MA1026 CODEC" + depends on I2C + config SND_SOC_MADERA tristate default y if SND_SOC_CS47L15=y @@ -1701,9 +1704,6 @@ config SND_SOC_SMA1303 help Enable support for Iron Device SMA1303 Boosted Class-D amplifier -config SND_SOC_MA1026 - tristate "Cubiclattice MA1026 CODEC" - config SND_SOC_SPDIF tristate "S/PDIF CODEC" diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index da8664ebed..32660fd0b6 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -141,6 +141,7 @@ snd-soc-lpass-rx-macro-objs := lpass-rx-macro.o snd-soc-lpass-tx-macro-objs := lpass-tx-macro.o snd-soc-lpass-wsa-macro-objs := lpass-wsa-macro.o snd-soc-lpass-va-macro-objs := lpass-va-macro.o +snd-soc-ma1026-objs := ma1026.o snd-soc-madera-objs := madera.o snd-soc-max9759-objs := max9759.o snd-soc-max9768-objs := max9768.o @@ -256,7 +257,6 @@ snd-soc-sigmadsp-i2c-objs := sigmadsp-i2c.o snd-soc-sigmadsp-regmap-objs := sigmadsp-regmap.o snd-soc-si476x-objs := si476x.o snd-soc-sma1303-objs := sma1303.o -snd-soc-ma1026-objs := ma1026.o snd-soc-spdif-tx-objs := spdif_transmitter.o snd-soc-spdif-rx-objs := spdif_receiver.o snd-soc-src4xxx-objs := src4xxx.o @@ -527,6 +527,7 @@ obj-$(CONFIG_SND_SOC_JZ4770_CODEC) += snd-soc-jz4770-codec.o obj-$(CONFIG_SND_SOC_LM4857) += snd-soc-lm4857.o obj-$(CONFIG_SND_SOC_LM49453) += snd-soc-lm49453.o obj-$(CONFIG_SND_SOC_LOCHNAGAR_SC) += snd-soc-lochnagar-sc.o +obj-$(CONFIG_SND_SOC_MA1026) += snd-soc-ma1026.o obj-$(CONFIG_SND_SOC_MADERA) += snd-soc-madera.o obj-$(CONFIG_SND_SOC_MAX9759) += snd-soc-max9759.o obj-$(CONFIG_SND_SOC_MAX9768) += snd-soc-max9768.o @@ -643,7 +644,6 @@ obj-$(CONFIG_SND_SOC_SI476X) += snd-soc-si476x.o obj-$(CONFIG_SND_SOC_SMA1303) += snd-soc-sma1303.o obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif-rx.o snd-soc-spdif-tx.o obj-$(CONFIG_SND_SOC_SIRF_AUDIO_CODEC) += sirf-audio-codec.o -obj-$(CONFIG_SND_SOC_MA1026) += snd-soc-ma1026.o obj-$(CONFIG_SND_SOC_SRC4XXX) += snd-soc-src4xxx.o obj-$(CONFIG_SND_SOC_SRC4XXX_I2C) += snd-soc-src4xxx-i2c.o obj-$(CONFIG_SND_SOC_SSM2305) += snd-soc-ssm2305.o diff --git a/sound/soc/codecs/ma1026.c b/sound/soc/codecs/ma1026.c index c3d6ad74f3..a544d6c088 100755 --- a/sound/soc/codecs/ma1026.c +++ b/sound/soc/codecs/ma1026.c @@ -43,7 +43,7 @@ snd_soc_component_write(codec, addr, value); #define snd_soc_update_ma1026(component, reg, mask, val) \ snd_soc_component_update_bits(component, reg, mask, val) -#elif (LINUX_VERSION_CODE < KERNEL_VERSION(6, 00, 0)) +#else #define snd_soc_write_ma1026(codec, addr, value) \ snd_soc_component_write(codec, addr, value); #define snd_soc_update_ma1026(component, reg, mask, val) \ @@ -56,7 +56,7 @@ #elif (LINUX_VERSION_CODE < KERNEL_VERSION(5, 00, 0)) #define snd_soc_read_ma1026(codec, addr) \ snd_soc_component_read32(codec, addr); -#elif (LINUX_VERSION_CODE < KERNEL_VERSION(6, 00, 0)) +#else #define snd_soc_read_ma1026(codec, addr) \ snd_soc_component_read(codec, addr); #endif @@ -185,7 +185,7 @@ static int ma1026_set_bias_level( struct snd_soc_codec *codec, #elif (LINUX_VERSION_CODE < KERNEL_VERSION(5, 00, 0)) struct snd_soc_component *codec, -#elif (LINUX_VERSION_CODE < KERNEL_VERSION(6, 00, 0)) +#else struct snd_soc_component *codec, #endif enum snd_soc_bias_level level) @@ -1017,6 +1017,11 @@ static void ma1026_i2c_shutdown(struct i2c_client *client) } } +static const struct i2c_device_id ma1026_id[] = { + {"ma1026", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, ma1026_id); static const struct of_device_id ma1026_of_match[] = { {.compatible = "Phytium, ma1026", }, @@ -1025,16 +1030,17 @@ static const struct of_device_id ma1026_of_match[] = { MODULE_DEVICE_TABLE(of, ma1026_of_match); -static const struct i2c_device_id ma1026_id[] = { - {"ma1026", 0}, - {} +static const struct acpi_device_id ma1026_acpi_match[] = { + { "MAMA1026", 0}, + { } }; -MODULE_DEVICE_TABLE(i2c, ma1026_id); +MODULE_DEVICE_TABLE(acpi, ma1026_acpi_match); static struct i2c_driver ma1026_i2c_driver = { .driver = { .name = "ma1026", .of_match_table = ma1026_of_match, + .acpi_match_table = ma1026_acpi_match, }, .probe = ma1026_i2c_probe, .remove = ma1026_i2c_remove, diff --git a/sound/soc/phytium/Kconfig b/sound/soc/phytium/Kconfig index 6c7b4570e5..0ded12199c 100644 --- a/sound/soc/phytium/Kconfig +++ b/sound/soc/phytium/Kconfig @@ -26,6 +26,14 @@ config SND_PMDK_ES8336 Say Y if you want to add Phytium machine support for ES8336 codecs. +config SND_PMDK_MA1026 + tristate "Phytium machine support with MA1026" + depends on I2C && SND_SOC_PHYTIUM_I2S + select SND_SOC_MA1026 + help + Say Y if you want to add Phytium machine support for + MA1026 codecs. + config SND_SOC_PHYTIUM_I2S_V2 tristate "Phytium I2S V2 Device Driver" help diff --git a/sound/soc/phytium/pmdk_ma1026.c b/sound/soc/phytium/pmdk_ma1026.c index 508163b5e4..a63b0fad68 100644 --- a/sound/soc/phytium/pmdk_ma1026.c +++ b/sound/soc/phytium/pmdk_ma1026.c @@ -38,13 +38,13 @@ static const struct snd_soc_dapm_route pmdk_ma1026_audio_map[] = { SND_SOC_DAILINK_DEFS(pmdk_ma1026, DAILINK_COMP_ARRAY(COMP_CPU("phytium-i2s-lsd")), - DAILINK_COMP_ARRAY(COMP_CODEC("i2c-MA1026:00", "ma1026-hifi")), + DAILINK_COMP_ARRAY(COMP_CODEC("i2c-MAMA1026:00", "ma1026-asp")), DAILINK_COMP_ARRAY(COMP_PLATFORM("snd-soc-dummy"))); static struct snd_soc_dai_link pmdk_dai[] = { { - .name = "MA1026 HIFI", - .stream_name = "MA1026 HIFI", + .name = "MA1026 ASP", + .stream_name = "MA1026 ASP", .dai_fmt = PMDK_DAI_FMT, SND_SOC_DAILINK_REG(pmdk_ma1026), }, @@ -55,13 +55,6 @@ static struct snd_soc_card pmdk = { .owner = THIS_MODULE, .dai_link = pmdk_dai, .num_links = ARRAY_SIZE(pmdk_dai), - - .dapm_widgets = pmdk_ma1026_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(pmdk_ma1026_dapm_widgets), - .controls = pmdk_ma1026_controls, - .num_controls = ARRAY_SIZE(pmdk_ma1026_controls), - .dapm_routes = pmdk_ma1026_audio_map, - .num_dapm_routes = ARRAY_SIZE(pmdk_ma1026_audio_map), }; static int pmdk_sound_probe(struct platform_device *pdev) @@ -98,6 +91,6 @@ static struct platform_driver pmdk_sound_driver = { module_platform_driver(pmdk_sound_driver); -MODULE_AUTHOR("harry guo "); -MODULE_DESCRIPTION("ALSA SoC PMDK CL1026"); +MODULE_AUTHOR("Shi Guangyuan "); +MODULE_DESCRIPTION("ALSA SoC PMDK MA1026"); MODULE_LICENSE("GPL"); -- Gitee From d57a151ba640a15eb97e62a9c998bd99082b7171 Mon Sep 17 00:00:00 2001 From: liutianyu1250 Date: Wed, 24 Sep 2025 14:23:05 +0800 Subject: [PATCH 143/155] sound: codec: ma1026: fix build error and warning in 6.6 Signed-off-by: liutianyu1250 --- sound/soc/codecs/ma1026.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/ma1026.c b/sound/soc/codecs/ma1026.c index a544d6c088..3c35b0e358 100755 --- a/sound/soc/codecs/ma1026.c +++ b/sound/soc/codecs/ma1026.c @@ -251,7 +251,7 @@ static const struct snd_kcontrol_new input_right_mixer[] = { SOC_DAPM_SINGLE("DMIC Right Input", MA1026_PWRCTRL1, 6, 1, 1), }; -static DECLARE_TLV_DB_SCALE(hpd_tlv, -10200, 50, 0); +//static DECLARE_TLV_DB_SCALE(hpd_tlv, -10200, 50, 0); static DECLARE_TLV_DB_SCALE(hpa_tlv, -5400, 200, 0); static const unsigned int limiter_tlv[] = { @@ -953,11 +953,10 @@ static struct snd_soc_dai_driver ma1026_dai = { .formats = MA1026_FORMATS, }, .ops = &ma1026_ops, - .symmetric_rates = 1, + .symmetric_rate = 1, }; -static int ma1026_i2c_probe(struct i2c_client *i2c_client, - const struct i2c_device_id *id) +static int ma1026_i2c_probe(struct i2c_client *i2c_client) { struct ma1026_priv *ma1026; int ret; @@ -1003,10 +1002,9 @@ static int ma1026_i2c_probe(struct i2c_client *i2c_client, return 0; } -static int ma1026_i2c_remove(struct i2c_client *client) +static void ma1026_i2c_remove(struct i2c_client *client) { snd_soc_unregister_component(&client->dev); - return 0; } static void ma1026_i2c_shutdown(struct i2c_client *client) -- Gitee From ab643aad9b32569cffb421355a1daa2dd8305c0e Mon Sep 17 00:00:00 2001 From: liutianyu1250 Date: Thu, 25 Sep 2025 14:25:08 +0800 Subject: [PATCH 144/155] net: phy: add linkyum driver Signed-off-by: liutianyu1250 --- drivers/net/phy/Kconfig | 5 + drivers/net/phy/Makefile | 1 + drivers/net/phy/linkyum.c | 1816 +++++++++++++++++++++++++++++++++++++ 3 files changed, 1822 insertions(+) create mode 100644 drivers/net/phy/linkyum.c diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 107880d13d..3305eaad31 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -189,6 +189,11 @@ config ICPLUS_PHY help Currently supports the IP175C and IP1001 PHYs. +config LINKYUM_PHY + tristate "LINKYUM PHYs" + help + Currently supports the LY1211A LY1211S LY1241A LY1241BPHYs. + config LXT_PHY tristate "Intel LXT PHYs" help diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index c945ed9bd1..215d06d054 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -64,6 +64,7 @@ obj-$(CONFIG_DP83TD510_PHY) += dp83td510.o obj-$(CONFIG_FIXED_PHY) += fixed_phy.o obj-$(CONFIG_ICPLUS_PHY) += icplus.o obj-$(CONFIG_INTEL_XWAY_PHY) += intel-xway.o +obj-$(CONFIG_LINKYUM_PHY) += linkyum.o obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o obj-$(CONFIG_LXT_PHY) += lxt.o obj-$(CONFIG_MARVELL_10G_PHY) += marvell10g.o diff --git a/drivers/net/phy/linkyum.c b/drivers/net/phy/linkyum.c new file mode 100644 index 0000000000..2393de565b --- /dev/null +++ b/drivers/net/phy/linkyum.c @@ -0,0 +1,1816 @@ +/**************************************************************************** + * Copyright (c) 2023 Shanghai Linkyum Microelectronics Co. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +***************************************************************************** + * drivers/net/phy/linkyum.c + * Description : Driver for LY1211A LY1211S LY1241A LY1241BPHYs. + * Version : V0.7 Fixed an issue where the network cannot link + * V0.8 Follow link to switch Page automatically in mode 2 + * V0.9 Adapts to ly1211a wol functions and 1000M utp optimise + * V0.10 There is a probability that the optimized phy will fail to link and add ly1210 driver + * V1.0 Optimize 125M clkout and add 1y1211 cfg function + * V1.1 Optimized adaptation 1y1241 cfg function + * V1.2 Support LY1211V3 cfg opt +*****************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef LINUX_VERSION_CODE +#include +#else +#define KERNEL_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c)) +#endif + + +/* WOL Enable Flag: + * disable by default to enable system WOL feature of phy + * please define this phy to 1 otherwise, define it to 0. + */ +#define LINKYUM_PHY_WOL_FEATURE_ENABLE 0 +#define LINKYUM_PHY_WOL_PASSWD_ENABLE 0 + +#define LINKYUM_PHY_MODE_SET_ENABLE 0 +#define LINKYUM_PHY_RXC_DELAY_SET_ENABLE 0 +#define LINKYUM_PHY_RXC_DELAY_VAL 0x00 +#define LINKYUM_PHY_CLK_OUT_125M_ENABLE 1 +#define LINKYUM_PHY_LINK_OPT_ENABLE 0 + + +/* Config Enable Flag */ +#define LINKYUM_PHY_LY1211_CFG_ENABLE 0 +#define LINKYUM_PHY_LY1211V2_CFG_ENABLE 0 +#define LINKYUM_PHY_LY1211V3_CFG_ENABLE 0 +#define LINKYUM_PHY_LY1241V2_CFG_ENABLE 0 + +#if LINKYUM_PHY_LY1211_CFG_ENABLE || LINKYUM_PHY_LY1211V2_CFG_ENABLE || \ + LINKYUM_PHY_LY1211V3_CFG_ENABLE || LINKYUM_PHY_LY1241V2_CFG_ENABLE +#include "linkyum.h" +#endif + +#define LYPHY_GLB_DISABLE 0 +#define LYPHY_GLB_ENABLE 1 +#define LYPHY_LINK_DOWN 0 +#define LYPHY_LINK_UP 1 +/* Mask used for ID comparisons */ +#define LINKYUM_PHY_ID_MASK 0xffffffff + +/* LY1211 PHY IDs */ +#define LY1210_PHY_ID 0xADB40400 +/* LY1211 PHY IDs */ +#define LY1211_PHY_ID 0xADB40412 +/* LY1141 PHY IDs */ +#define LY1241_PHY_ID 0xADB40411 + +/*LY1211 PHY LED */ +#define LY1211_EXTREG_LED0 0x1E33 // 0 +#define LY1211_EXTREG_LED1 0x1E34 // 00101111 +#define LY1211_EXTREG_LED2 0x1E35 // 0x40 +/*LY1241 PHY BX LED */ +#define LY1241_EXTREG_LEDCTRL 0x0621 +#define LY1241_EXTREG_LED0_1 0x0700 +#define LY1241_EXTREG_LED0_2 0x0701 +#define LY1241_EXTREG_LED1_1 0x0702 +#define LY1241_EXTREG_LED1_2 0x0703 +#define LY1241_EXTREG_LED2_1 0x0706 +#define LY1241_EXTREG_LED2_2 0x0707 +#define LY1241_EXTREG_LED3_1 0x0708 +#define LY1241_EXTREG_LED3_2 0x0709 +#define LY1241_EXTREG_LED4_1 0x070C +#define LY1241_EXTREG_LED4_2 0x070D +#define LY1241_EXTREG_LED5_1 0x070E +#define LY1241_EXTREG_LED5_2 0x070F +#define LY1241_EXTREG_LED6_1 0x0712 +#define LY1241_EXTREG_LED6_2 0x0713 +#define LY1241_EXTREG_LED7_1 0x0714 +#define LY1241_EXTREG_LED7_2 0x0715 + +/* PHY MODE OPSREG*/ +#define LY1211_EXTREG_GET_PORT_PHY_MODE 0x062B +#define LY1211_EXTREG_PHY_MODE_MASK 0x0070 +/* Magic Packet MAC address registers */ +#define LINKYUM_MAGIC_PACKET_MAC_ADDR 0x0229 +/* Magic Packet MAC Passwd registers */ +#define LINKYUM_MAGIC_PACKET_PASSWD_ADDR 0x022F +#define LINKYUM_PHY_WOL_PULSE_MODE_SET 0x062a + +/* Magic Packet MAC Passwd Val*/ +#define LINKYUM_MAGIC_PACKET_PASSWD1 0x11 +#define LINKYUM_MAGIC_PACKET_PASSWD2 0x22 +#define LINKYUM_MAGIC_PACKET_PASSWD3 0x33 +#define LINKYUM_MAGIC_PACKET_PASSWD4 0x44 +#define LINKYUM_MAGIC_PACKET_PASSWD5 0x55 +#define LINKYUM_MAGIC_PACKET_PASSWD6 0x66 + +/* Linyum wol config register */ +#define LINKYUM_WOL_CFG_REG0 0x0220 +#define LINKYUM_WOL_CFG_REG1 0x0221 +#define LINKYUM_WOL_CFG_REG2 0x0222 +#define LINKYUM_WOL_STA_REG 0x0223 +/* 8 PHY MODE */ +#define LY1211_EXTREG_PHY_MODE_UTP_TO_RGMII 0x00 +#define LY1211_EXTREG_PHY_MODE_FIBER_TO_RGMII 0x10 +#define LY1211_EXTREG_PHY_MODE_UTP_OR_FIBER_TO_RGMII 0x20 +#define LY1211_EXTREG_PHY_MODE_UTP_TO_SGMII 0x30 +#define LY1211_EXTREG_PHY_MODE_SGMII_PHY_TO_RGMII_MAC 0x40 +#define LY1211_EXTREG_PHY_MODE_SGMII_MAC_TO_RGMII_PHY 0x50 +#define LY1211_EXTREG_PHY_MODE_UTP_TO_FIBER_AUTO 0x60 +#define LY1211_EXTREG_PHY_MODE_UTP_TO_FIBER_FORCE 0x70 + +/* PHY EXTRW OPSREG */ +#define LY1211_EXTREG_ADDR 0x0E +#define LY1211_EXTREG_DATA 0x0D +/* PHY PAGE SPACE */ +#define LYPHY_REG_UTP_SPACE 0 +#define LYPHY_REG_FIBER_SPACE 1 + +/* PHY PAGE SELECT */ +#define LY1211_EXTREG_PHY_MODE_PAGE_SELECT 0x0016 +#define LYPHY_REG_UTP_SPACE_SETADDR 0x0000 +#define LYPHY_REG_FIBER_SPACE_SETADDR 0x0100 +//utp +#define UTP_REG_PAUSE_CAP 0x0400 /* Can pause */ +#define UTP_REG_PAUSE_ASYM 0x0800 /* Can pause asymetrically */ +//fiber +#define FIBER_REG_PAUSE_CAP 0x0080 /* Can pause */ +#define FIBER_REG_PAUSE_ASYM 0x0100 /* Can pause asymetrically */ + +/* specific status register */ +#define LINKYUM_SPEC_REG 0x0011 + +/* Interrupt Enable Register */ +#define LINKYUM_INTR_REG 0x0017 +/* Phy Patch Register */ +#define LY_CFG_INIT 0xC460 +#define LY_CFG_WAIT 0xC45C +#define LY_CFG_EPHY_INIT 0xC413 +#define LY_CFG_ADDR 0xC800 +#define LY_CFG_ENABLE 0xC45D +#define LY_CFG_ENABLE_ACK 0xC45E + +/* WOL TYPE */ +#define LINKYUM_WOL_TYPE BIT(0) +/* WOL Pulse Width */ +#define LINKYUM_WOL_WIDTH1 BIT(1) +#define LINKYUM_WOL_WIDTH2 BIT(2) +/* WOL dest addr check enable */ +#define LINKYUM_WOL_SECURE_CHECK BIT(5) +/* WOL crc check enable */ +#define LINKYUM_WOL_CRC_CHECK BIT(4) +/* WOL dest addr check enable */ +#define LINKYUM_WOL_DESTADDR_CHECK BIT(5) +/* WOL Event Interrupt Enable */ +#define LINKYUM_WOL_INTR_EN BIT(2) +/* WOL Enable */ +#define LINKYUM_WOL_EN BIT(7) + +#define LINKYUM_WOL_RESTARTANEG BIT(9) +/* GET PHY MODE */ +#define LYPHY_MODE_CURR lyphy_get_port_type(phydev) + +enum linkyum_port_type_e +{ + LYPHY_PORT_TYPE_UTP, + LYPHY_PORT_TYPE_FIBER, + LYPHY_PORT_TYPE_COMBO, + LYPHY_PORT_TYPE_EXT +}; +enum linkyum_wol_type_e +{ + LYPHY_WOL_TYPE_LEVEL, + LYPHY_WOL_TYPE_PULSE, + LYPHY_WOL_TYPE_EXT +}; + +enum linkyum_wol_width_e +{ + LYPHY_WOL_WIDTH_84MS, + LYPHY_WOL_WIDTH_168MS, + LYPHY_WOL_WIDTH_336MS, + LYPHY_WOL_WIDTH_672MS, + LYPHY_WOL_WIDTH_EXT +}; + +typedef struct linkyum_wol_cfg_s +{ + int wolen; + int type; + int width; + int secure; + int checkcrc; + int checkdst; +}linkyum_wol_cfg_t; + +#if (KERNEL_VERSION(5, 5, 0) > LINUX_VERSION_CODE) +static inline void phy_lock_mdio_bus(struct phy_device *phydev) +{ +#if (KERNEL_VERSION(4, 5, 0) > LINUX_VERSION_CODE) + mutex_lock(&phydev->bus->mdio_lock); +#else + mutex_lock(&phydev->mdio.bus->mdio_lock); +#endif +} + +static inline void phy_unlock_mdio_bus(struct phy_device *phydev) +{ +#if (KERNEL_VERSION(4, 5, 0) > LINUX_VERSION_CODE) + mutex_unlock(&phydev->bus->mdio_lock); +#else + mutex_unlock(&phydev->mdio.bus->mdio_lock); +#endif +} +#endif + +#if (KERNEL_VERSION(4, 16, 0) > LINUX_VERSION_CODE) +static inline int __phy_read(struct phy_device *phydev, u32 regnum) +{ +#if (KERNEL_VERSION(4, 5, 0) > LINUX_VERSION_CODE) + struct mii_bus *bus = phydev->bus; + int addr = phydev->addr; + return bus->read(bus, phydev->addr, regnum); +#else + struct mii_bus *bus = phydev->mdio.bus; + int addr = phydev->mdio.addr; +#endif + return bus->read(bus, addr, regnum); +} + +static inline int __phy_write(struct phy_device *phydev, u32 regnum, u16 val) +{ +#if (KERNEL_VERSION(4, 5, 0) > LINUX_VERSION_CODE) + struct mii_bus *bus = phydev->bus; + int addr = phydev->addr; +#else + struct mii_bus *bus = phydev->mdio.bus; + int addr = phydev->mdio.addr; +#endif + return bus->write(bus, addr, regnum, val); +} +#endif + +#if (KERNEL_VERSION(4, 12, 0) <= LINUX_VERSION_CODE) && (KERNEL_VERSION(4, 16, 0) > LINUX_VERSION_CODE) +static int genphy_read_mmd_unsupported(struct phy_device *phdev, int devad, u16 regnum) +{ + return -EOPNOTSUPP; +} + +static int genphy_write_mmd_unsupported(struct phy_device *phdev, int devnum, + u16 regnum, u16 val) +{ + return -EOPNOTSUPP; +} +#endif + +static int ly1241_phy_read(struct phy_device *phydev, u32 regnum) +{ + int ret, val, oldval = 0; + + phy_lock_mdio_bus(phydev); + + ret = __phy_read(phydev, LY1211_EXTREG_ADDR); + if (ret < 0) + goto err_handle; + oldval = ret; + + ret = __phy_read(phydev, regnum); + if (ret < 0) + goto err_handle; + val = ret; + + ret = __phy_write(phydev, LY1211_EXTREG_ADDR, oldval); + if (ret < 0) + goto err_handle; + ret = val; + +err_handle: + phy_unlock_mdio_bus(phydev); + return ret; +} + +// static int ly1241_phy_write(struct phy_device *phydev, u32 regnum, u16 val) +// { +// int ret, oldval = 0; + +// phy_lock_mdio_bus(phydev); + +// ret = __phy_read(phydev, LY1211_EXTREG_ADDR); +// if (ret < 0) +// goto err_handle; +// oldval = ret; + +// ret = __phy_write(phydev, regnum, val); +// if(ret<0) +// goto err_handle; + +// ret = __phy_write(phydev, LY1211_EXTREG_ADDR, oldval); +// if (ret < 0) +// goto err_handle; + +// err_handle: +// phy_unlock_mdio_bus(phydev); +// return ret; +// } + +static int ly1211_phy_ext_read(struct phy_device *phydev, u32 regnum) +{ + int ret, val, oldpage = 0, oldval = 0; + + phy_lock_mdio_bus(phydev); + + ret = __phy_read(phydev, LY1211_EXTREG_ADDR); + if (ret < 0) + goto err_handle; + oldval = ret; + + /* Force change to utp page */ + ret = __phy_read(phydev, LY1211_EXTREG_PHY_MODE_PAGE_SELECT);//get old page + if (ret < 0) + goto err_handle; + oldpage = ret; + + ret = __phy_write(phydev, LY1211_EXTREG_PHY_MODE_PAGE_SELECT, LYPHY_REG_UTP_SPACE_SETADDR); + if (ret < 0) + goto err_handle; + + /* Default utp ext rw */ + ret = __phy_write(phydev, LY1211_EXTREG_ADDR, regnum); + if (ret < 0) + goto err_handle; + + ret = __phy_read(phydev, LY1211_EXTREG_DATA); + if (ret < 0) + goto err_handle; + val = ret; + + /* Recover to old page */ + ret = __phy_write(phydev, LY1211_EXTREG_PHY_MODE_PAGE_SELECT, oldpage); + if (ret < 0) + goto err_handle; + + ret = __phy_write(phydev, LY1211_EXTREG_ADDR, oldval); + if (ret < 0) + goto err_handle; + ret = val; + +err_handle: + phy_unlock_mdio_bus(phydev); + return ret; +} + +static int ly1211_phy_ext_write(struct phy_device *phydev, u32 regnum, u16 val) +{ + int ret, oldpage = 0, oldval = 0; + + phy_lock_mdio_bus(phydev); + + ret = __phy_read(phydev, LY1211_EXTREG_ADDR); + if (ret < 0) + goto err_handle; + oldval = ret; + + /* Force change to utp page */ + ret = __phy_read(phydev, LY1211_EXTREG_PHY_MODE_PAGE_SELECT); //get old page + if (ret < 0) + goto err_handle; + oldpage = ret; + + ret = __phy_write(phydev, LY1211_EXTREG_PHY_MODE_PAGE_SELECT, LYPHY_REG_UTP_SPACE_SETADDR); + if (ret < 0) + goto err_handle; + + /* Default utp ext rw */ + ret = __phy_write(phydev, LY1211_EXTREG_ADDR, regnum); + if (ret < 0) + goto err_handle; + + ret = __phy_write(phydev, LY1211_EXTREG_DATA, val); + if (ret < 0) + goto err_handle; + + /* Recover to old page */ + ret = __phy_write(phydev, LY1211_EXTREG_PHY_MODE_PAGE_SELECT, oldpage); + if (ret < 0) + goto err_handle; + + ret = __phy_write(phydev, LY1211_EXTREG_ADDR, oldval); + if (ret < 0) + goto err_handle; + +err_handle: + phy_unlock_mdio_bus(phydev); + return ret; + +} + +static int linkyum_phy_select_reg_page(struct phy_device *phydev, int space) +{ + int ret; + if (space == LYPHY_REG_UTP_SPACE) + ret = phy_write(phydev, LY1211_EXTREG_PHY_MODE_PAGE_SELECT, LYPHY_REG_UTP_SPACE_SETADDR); + else + ret = phy_write(phydev, LY1211_EXTREG_PHY_MODE_PAGE_SELECT, LYPHY_REG_FIBER_SPACE_SETADDR); + return ret; +} + +static int linkyum_phy_get_reg_page(struct phy_device *phydev) +{ + return phy_read(phydev, LY1211_EXTREG_PHY_MODE_PAGE_SELECT); +} + +static int linkyum_phy_ext_read(struct phy_device *phydev, u32 regnum) +{ + return ly1211_phy_ext_read(phydev, regnum); +} + + +static int linkyum_phy_ext_write(struct phy_device *phydev, u32 regnum, u16 val) +{ + return ly1211_phy_ext_write(phydev, regnum, val); +} + +static int lyphy_page_read(struct phy_device *phydev, int page, u32 regnum) +{ + int ret, val, oldpage = 0, oldval = 0; + + phy_lock_mdio_bus(phydev); + + ret = __phy_read(phydev, LY1211_EXTREG_ADDR); + if (ret < 0) + goto err_handle; + oldval = ret; + + ret = __phy_read(phydev, LY1211_EXTREG_PHY_MODE_PAGE_SELECT); + if (ret < 0) + goto err_handle; + oldpage = ret; + + //Select page + ret = __phy_write(phydev, LY1211_EXTREG_PHY_MODE_PAGE_SELECT, (page << 8)); + if (ret < 0) + goto err_handle; + + ret = __phy_read(phydev, regnum); + if (ret < 0) + goto err_handle; + val = ret; + + /* Recover to old page */ + ret = __phy_write(phydev, LY1211_EXTREG_PHY_MODE_PAGE_SELECT, oldpage); + if (ret < 0) + goto err_handle; + + ret = __phy_write(phydev, LY1211_EXTREG_ADDR, oldval); + if (ret < 0) + goto err_handle; + ret = val; + +err_handle: + phy_unlock_mdio_bus(phydev); + return ret; +} + +static int lyphy_page_write(struct phy_device *phydev, int page, u32 regnum, u16 value) +{ + int ret, oldpage = 0, oldval = 0; + + phy_lock_mdio_bus(phydev); + + ret = __phy_read(phydev, LY1211_EXTREG_ADDR); + if (ret < 0) + goto err_handle; + oldval = ret; + + ret = __phy_read(phydev, LY1211_EXTREG_PHY_MODE_PAGE_SELECT); + if (ret < 0) + goto err_handle; + oldpage = ret; + + //Select page + ret = __phy_write(phydev, LY1211_EXTREG_PHY_MODE_PAGE_SELECT, (page << 8)); + if(ret<0) + goto err_handle; + + ret = __phy_write(phydev, regnum, value); + if(ret<0) + goto err_handle; + + /* Recover to old page */ + ret = __phy_write(phydev, LY1211_EXTREG_PHY_MODE_PAGE_SELECT, oldpage); + if (ret < 0) + goto err_handle; + + ret = __phy_write(phydev, LY1211_EXTREG_ADDR, oldval); + if (ret < 0) + goto err_handle; + +err_handle: + phy_unlock_mdio_bus(phydev); + return ret; +} + +//get port type +static int lyphy_get_port_type(struct phy_device *phydev) +{ + int ret, mode; + + ret = linkyum_phy_ext_read(phydev, LY1211_EXTREG_GET_PORT_PHY_MODE); + if (ret < 0) + return ret; + ret &= LY1211_EXTREG_PHY_MODE_MASK; + + if (ret == LY1211_EXTREG_PHY_MODE_UTP_TO_RGMII || + ret == LY1211_EXTREG_PHY_MODE_UTP_TO_SGMII) { + mode = LYPHY_PORT_TYPE_UTP; + } else if (ret == LY1211_EXTREG_PHY_MODE_FIBER_TO_RGMII || + ret == LY1211_EXTREG_PHY_MODE_SGMII_PHY_TO_RGMII_MAC || + ret == LY1211_EXTREG_PHY_MODE_SGMII_MAC_TO_RGMII_PHY) { + mode = LYPHY_PORT_TYPE_FIBER; + } else { + mode = LYPHY_PORT_TYPE_COMBO; + } + + return mode; +} + +static int ly1121_led_init(struct phy_device *phydev) +{ + int ret; + + ret = linkyum_phy_ext_write(phydev, LY1211_EXTREG_LED0, 0x00); + if (ret < 0) + return ret; + ret = linkyum_phy_ext_write(phydev, LY1211_EXTREG_LED1, 0x2F); + if (ret < 0) + return ret; + + return linkyum_phy_ext_write(phydev, LY1211_EXTREG_LED2, 0x40); +} + +static int ly1241_led_init(struct phy_device *phydev) +{ + int ret; + // set led put low level + ret = linkyum_phy_ext_write(phydev, LY1241_EXTREG_LEDCTRL, 0x04); + if (ret < 0) + return ret; + ret = linkyum_phy_ext_read(phydev, LY1241_EXTREG_LED0_1); + if (ret < 0) + return ret; + ret = linkyum_phy_ext_read(phydev, LY1241_EXTREG_LED0_2); + if (ret < 0) + return ret; + + + // set led 0 1 + ret = linkyum_phy_ext_write(phydev, LY1241_EXTREG_LED0_1, 0x00); + if (ret < 0) + return ret; + ret = linkyum_phy_ext_write(phydev, LY1241_EXTREG_LED0_2, 0x08); + if (ret < 0) + return ret; + ret = linkyum_phy_ext_write(phydev, LY1241_EXTREG_LED1_1, 0xF0); + if (ret < 0) + return ret; + ret = linkyum_phy_ext_write(phydev, LY1241_EXTREG_LED1_2, 0x0E); + if (ret < 0) + return ret; + + // set led 2 3 + ret = linkyum_phy_ext_write(phydev, LY1241_EXTREG_LED2_1, 0x00); + if (ret < 0) + return ret; + ret = linkyum_phy_ext_write(phydev, LY1241_EXTREG_LED2_2, 0x18); + if (ret < 0) + return ret; + ret = linkyum_phy_ext_write(phydev, LY1241_EXTREG_LED3_1, 0xF0); + if (ret < 0) + return ret; + ret = linkyum_phy_ext_write(phydev, LY1241_EXTREG_LED3_2, 0x1E); + if (ret < 0) + return ret; + + // set led 4 + ret = linkyum_phy_ext_write(phydev, LY1241_EXTREG_LED4_1, 0x00); + if (ret < 0) + return ret; + ret = linkyum_phy_ext_write(phydev, LY1241_EXTREG_LED4_2, 0x28); + if (ret < 0) + return ret; + ret = linkyum_phy_ext_write(phydev, LY1241_EXTREG_LED5_1, 0xFE); + if (ret < 0) + return ret; + ret = linkyum_phy_ext_write(phydev, LY1241_EXTREG_LED5_2, 0x2E); + if (ret < 0) + return ret; + + // set led 6 + ret = linkyum_phy_ext_write(phydev, LY1241_EXTREG_LED6_2, 0x00); + if (ret < 0) + return ret; + ret = linkyum_phy_ext_write(phydev, LY1241_EXTREG_LED6_2, 0x38); + if (ret < 0) + return ret; + ret = linkyum_phy_ext_write(phydev, LY1241_EXTREG_LED7_1, 0xF0); + if (ret < 0) + return ret; + ret = linkyum_phy_ext_write(phydev, LY1241_EXTREG_LED7_2, 0x3E); + if (ret < 0) + return ret; + + return ret; +} + + +static int lyphy_restart_aneg(struct phy_device *phydev) +{ + int ret, ctl; + + ctl = lyphy_page_read(phydev, LYPHY_REG_FIBER_SPACE, MII_BMCR); + if (ctl < 0) + return ctl; + ctl |= BMCR_ANENABLE; + ret = lyphy_page_write(phydev, LYPHY_REG_FIBER_SPACE, MII_BMCR, ctl); + if (ret < 0) + return ret; + + return 0; +} + +int ly1211_config_aneg(struct phy_device *phydev) +{ + int ret, phymode, oldpage = 0; + + phymode = LYPHY_MODE_CURR; + + if (phymode == LYPHY_PORT_TYPE_UTP || phymode == LYPHY_PORT_TYPE_COMBO) { + oldpage = linkyum_phy_get_reg_page(phydev); + if (oldpage < 0) + return oldpage; + ret = linkyum_phy_select_reg_page(phydev, LYPHY_REG_UTP_SPACE); + if (ret < 0) + return ret; + ret = genphy_config_aneg(phydev); + if (ret < 0) + return ret; + ret = linkyum_phy_select_reg_page(phydev, oldpage); + if (ret < 0) + return ret; + } + + if (phymode == LYPHY_PORT_TYPE_FIBER || phymode == LYPHY_PORT_TYPE_COMBO) { + oldpage = linkyum_phy_get_reg_page(phydev); + if (oldpage < 0) + return oldpage; + ret = linkyum_phy_select_reg_page(phydev, LYPHY_REG_FIBER_SPACE); + if (ret < 0) + return ret; + if (AUTONEG_ENABLE != phydev->autoneg) + return genphy_setup_forced(phydev); + ret = lyphy_restart_aneg(phydev); + if (ret < 0) + return ret; + ret = linkyum_phy_select_reg_page(phydev, oldpage); + if (ret < 0) + return ret; + } + return 0; +} + +#if (KERNEL_VERSION(3, 14, 79) < LINUX_VERSION_CODE) +int ly1211_aneg_done(struct phy_device *phydev) +{ + int val = 0; + + val = phy_read(phydev, 0x16); + + if (val == LYPHY_REG_FIBER_SPACE_SETADDR) { + val = phy_read(phydev, 0x1); + val = phy_read(phydev, 0x1); + return (val < 0) ? val : (val & BMSR_LSTATUS); + } + + return genphy_aneg_done(phydev); +} +#endif + +#if (LINKYUM_PHY_WOL_FEATURE_ENABLE) +static void linkyum_get_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol) +{ + int val = 0; + wol->supported = WAKE_MAGIC; + wol->wolopts = 0; + + val = linkyum_phy_ext_read(phydev, LINKYUM_WOL_CFG_REG1); + if (val < 0) + return; + + if (val & LINKYUM_WOL_EN) + wol->wolopts |= WAKE_MAGIC; + + return; +} + +static int linkyum_wol_en_cfg(struct phy_device *phydev, linkyum_wol_cfg_t wol_cfg) +{ + int ret, val0,val1; + + val0 = linkyum_phy_ext_read(phydev, LINKYUM_WOL_CFG_REG0); + if (val0 < 0) + return val0; + val1 = linkyum_phy_ext_read(phydev, LINKYUM_WOL_CFG_REG1); + if (val1 < 0) + return val1; + if (wol_cfg.wolen) { + val1 |= LINKYUM_WOL_EN; + if (wol_cfg.type == LYPHY_WOL_TYPE_LEVEL) { + val0 |= LINKYUM_WOL_TYPE; + } else if (wol_cfg.type == LYPHY_WOL_TYPE_PULSE) { + ret = linkyum_phy_ext_write(phydev, LINKYUM_PHY_WOL_PULSE_MODE_SET, 0x04);//set int pin pulse + if (ret < 0) + return ret; + val0 &= ~LINKYUM_WOL_TYPE; + if (wol_cfg.width == LYPHY_WOL_WIDTH_84MS) { + val0 &= ~LINKYUM_WOL_WIDTH1; + val0 &= ~LINKYUM_WOL_WIDTH2; + } else if (wol_cfg.width == LYPHY_WOL_WIDTH_168MS) { + val0 |= LINKYUM_WOL_WIDTH1; + val0 &= ~LINKYUM_WOL_WIDTH2; + } else if (wol_cfg.width == LYPHY_WOL_WIDTH_336MS) { + val0 &= ~LINKYUM_WOL_WIDTH1; + val0 |= LINKYUM_WOL_WIDTH2; + } else if (wol_cfg.width == LYPHY_WOL_WIDTH_672MS) { + val0 |= LINKYUM_WOL_WIDTH1; + val0 |= LINKYUM_WOL_WIDTH2; + } + } + if (wol_cfg.secure == LYPHY_GLB_ENABLE) + val1 |= LINKYUM_WOL_SECURE_CHECK; + else + val1 &= ~LINKYUM_WOL_SECURE_CHECK; + if (wol_cfg.checkcrc == LYPHY_GLB_ENABLE) + val0 |= LINKYUM_WOL_CRC_CHECK; + else + val0 &= ~LINKYUM_WOL_CRC_CHECK; + if (wol_cfg.checkdst == LYPHY_GLB_ENABLE) + val0 |= LINKYUM_WOL_DESTADDR_CHECK; + else + val0 &= ~LINKYUM_WOL_DESTADDR_CHECK; + } else { + val1 &= ~LINKYUM_WOL_EN; + } + + ret = linkyum_phy_ext_write(phydev, LINKYUM_WOL_CFG_REG0, val0); + if (ret < 0) + return ret; + ret = linkyum_phy_ext_write(phydev, LINKYUM_WOL_CFG_REG1, val1); + if (ret < 0) + return ret; + return 0; +} + +static int linkyum_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol) +{ + int ret, val, i, phymode; + linkyum_wol_cfg_t wol_cfg; + + phymode = LYPHY_MODE_CURR; + memset(&wol_cfg,0,sizeof(linkyum_wol_cfg_t)); + + if (wol->wolopts & WAKE_MAGIC) { + if (phymode == LYPHY_PORT_TYPE_UTP || phymode == LYPHY_PORT_TYPE_COMBO) { + /* Enable the WOL interrupt */ + val = lyphy_page_read(phydev, LYPHY_REG_UTP_SPACE, LINKYUM_INTR_REG); + val |= LINKYUM_WOL_INTR_EN; + ret = lyphy_page_write(phydev, LYPHY_REG_UTP_SPACE, LINKYUM_INTR_REG, val); + if (ret < 0) + return ret; + } + if (phymode == LYPHY_PORT_TYPE_FIBER || phymode == LYPHY_PORT_TYPE_COMBO) { + /* Enable the WOL interrupt */ + val = lyphy_page_read(phydev, LYPHY_REG_FIBER_SPACE, LINKYUM_INTR_REG); + val |= LINKYUM_WOL_INTR_EN; + ret = lyphy_page_write(phydev, LYPHY_REG_FIBER_SPACE, LINKYUM_INTR_REG, val); + if (ret < 0) + return ret; + } + /* Set the WOL config */ + wol_cfg.wolen = LYPHY_GLB_ENABLE; + wol_cfg.type = LYPHY_WOL_TYPE_PULSE; + wol_cfg.width = LYPHY_WOL_WIDTH_672MS; + wol_cfg.checkdst = LYPHY_GLB_ENABLE; + wol_cfg.checkcrc = LYPHY_GLB_ENABLE; + ret = linkyum_wol_en_cfg(phydev, wol_cfg); + if (ret < 0) + return ret; + + /* Store the device address for the magic packet */ + for(i = 0; i < 6; ++i) { + ret = linkyum_phy_ext_write(phydev, LINKYUM_MAGIC_PACKET_MAC_ADDR - i, + ((phydev->attached_dev->dev_addr[i]))); + if (ret < 0) + return ret; + } +#if LINKYUM_PHY_WOL_PASSWD_ENABLE + /* Set passwd for the magic packet */ + ret = linkyum_phy_ext_write(phydev, LINKYUM_MAGIC_PACKET_PASSWD_ADDR, LINKYUM_MAGIC_PACKET_PASSWD1); + if (ret < 0) + return ret; + ret = linkyum_phy_ext_write(phydev, LINKYUM_MAGIC_PACKET_PASSWD_ADDR - 1, LINKYUM_MAGIC_PACKET_PASSWD2); + if (ret < 0) + return ret; + ret = linkyum_phy_ext_write(phydev, LINKYUM_MAGIC_PACKET_PASSWD_ADDR - 2, LINKYUM_MAGIC_PACKET_PASSWD3); + if (ret < 0) + return ret; + ret = linkyum_phy_ext_write(phydev, LINKYUM_MAGIC_PACKET_PASSWD_ADDR - 3, LINKYUM_MAGIC_PACKET_PASSWD4); + if (ret < 0) + return ret; + ret = linkyum_phy_ext_write(phydev, LINKYUM_MAGIC_PACKET_PASSWD_ADDR - 4, LINKYUM_MAGIC_PACKET_PASSWD5); + if (ret < 0) + return ret; + ret = linkyum_phy_ext_write(phydev, LINKYUM_MAGIC_PACKET_PASSWD_ADDR - 5, LINKYUM_MAGIC_PACKET_PASSWD6); + if (ret < 0) + return ret; +#endif + } else { + wol_cfg.wolen = LYPHY_GLB_DISABLE; + wol_cfg.type = LYPHY_WOL_TYPE_EXT; + wol_cfg.width = LYPHY_WOL_WIDTH_EXT; + wol_cfg.checkdst = LYPHY_GLB_DISABLE; + wol_cfg.checkcrc = LYPHY_GLB_DISABLE; + ret = linkyum_wol_en_cfg(phydev, wol_cfg); + if (ret < 0) + return ret; + } + + if (val == LY1211_EXTREG_PHY_MODE_UTP_TO_SGMII) { + val = lyphy_page_read(phydev, LYPHY_REG_UTP_SPACE, MII_BMCR); + val |= LINKYUM_WOL_RESTARTANEG; + ret = lyphy_page_write(phydev, LYPHY_REG_UTP_SPACE, MII_BMCR, val); + if (ret < 0) + return ret; + } + + return 0; +} +#endif +static int ly1211_rxc_init(struct phy_device *phydev) +{ + int ret; + + ret = (linkyum_phy_ext_read(phydev, LY1211_EXTREG_GET_PORT_PHY_MODE) & + LY1211_EXTREG_PHY_MODE_MASK); + if (ret < 0) + return ret; + + if ((ret == LY1211_EXTREG_PHY_MODE_UTP_TO_SGMII) || + (ret == LY1211_EXTREG_PHY_MODE_UTP_TO_FIBER_AUTO) || + (ret == LY1211_EXTREG_PHY_MODE_UTP_TO_FIBER_FORCE)) + return 0; + + // Init rxc and enable rxc + if (ret == LY1211_EXTREG_PHY_MODE_UTP_TO_RGMII) { + ret = phy_read(phydev, 0x11); + if ((ret & 0x4) == 0x0) { + ret = linkyum_phy_ext_write(phydev,0x1E0C, 0x17); + if (ret < 0) + return ret; + ret = linkyum_phy_ext_write(phydev,0x1E58, 0x00); + if (ret < 0) + return ret; + } + } + + +#if LINKYUM_PHY_RXC_DELAY_SET_ENABLE + // Init rxc delay + ret = linkyum_phy_ext_write(phydev,0x0282, LINKYUM_PHY_RXC_DELAY_VAL); + if (ret < 0) + return ret; +#endif + + return ret; +} +static int ly1211_config_opt(struct phy_device *phydev) +{ + int ret; + //100M utp optimise + ret = linkyum_phy_ext_write(phydev, 0x0149, 0x84); + if (ret < 0) + return ret; + + ret = linkyum_phy_ext_write(phydev, 0x014A, 0x86); + if (ret < 0) + return ret; + + ret = linkyum_phy_ext_write(phydev, 0x023C, 0x81); + if (ret < 0) + return ret; + + //1000M utp optimise + ret = linkyum_phy_ext_write(phydev, 0x0184, 0x85); + if (ret < 0) + return ret; + + ret = linkyum_phy_ext_write(phydev, 0x0185, 0x86); + if (ret < 0) + return ret; + + ret = linkyum_phy_ext_write(phydev, 0x0186, 0x85); + if (ret < 0) + return ret; + + ret = linkyum_phy_ext_write(phydev, 0x0187, 0x86); + if (ret < 0) + return ret; + return ret; +} + +#if LINKYUM_PHY_CLK_OUT_125M_ENABLE +static int ly1211_clkout_init(struct phy_device *phydev) +{ + int ret; + + ret = linkyum_phy_ext_write(phydev, 0x0272 , 0x49); + if (ret < 0) + return ret; + + return ret; +} +#endif + +#if LINKYUM_PHY_MODE_SET_ENABLE +//set mode +static int phy_mode_set(struct phy_device *phydev, u16 phyMode) +{ + int ret, num = 0; + + ret = linkyum_phy_ext_read(phydev, 0xC417); + if (ret < 0) + return ret; + + ret = (ret & 0xF0) | (0x8 | phyMode); + + ret = linkyum_phy_ext_write(phydev, 0xC417, ret); + if (ret < 0) + return ret; + + while ((linkyum_phy_ext_read(phydev, 0xC415) & 0x07) != phyMode) { + msleep(10); + if(++num == 5) { + printk("Phy Mode Set Time Out!\r\n"); + break; + } + } + + while (linkyum_phy_ext_read(phydev, 0xC413) != 0) { + msleep(10); + if(++num == 10) { + printk("Phy Mode Set Time Out!\r\n"); + break; + } + } + + return 0; +} +#endif + +#if (KERNEL_VERSION(3, 16, 0) > LINUX_VERSION_CODE) +static int genphy_config_init(struct phy_device *phydev) +{ + int val; + u32 features; + + features = (SUPPORTED_TP | SUPPORTED_MII + | SUPPORTED_AUI | SUPPORTED_FIBRE | + SUPPORTED_BNC | SUPPORTED_Pause | SUPPORTED_Asym_Pause); + + /* Do we support autonegotiation? */ + val = phy_read(phydev, MII_BMSR); + if (val < 0) + return val; + + if (val & BMSR_ANEGCAPABLE) + features |= SUPPORTED_Autoneg; + + if (val & BMSR_100FULL) + features |= SUPPORTED_100baseT_Full; + if (val & BMSR_100HALF) + features |= SUPPORTED_100baseT_Half; + if (val & BMSR_10FULL) + features |= SUPPORTED_10baseT_Full; + if (val & BMSR_10HALF) + features |= SUPPORTED_10baseT_Half; + + if (val & BMSR_ESTATEN) { + val = phy_read(phydev, MII_ESTATUS); + if (val < 0) + return val; + + if (val & ESTATUS_1000_TFULL) + features |= SUPPORTED_1000baseT_Full; + if (val & ESTATUS_1000_THALF) + features |= SUPPORTED_1000baseT_Half; + } + + phydev->supported &= features; + phydev->advertising &= features; + + return 0; +} +#endif + +int ly1241_power_updown_init(struct phy_device *phydev) +{ + int ret = 0, num = 0; + + ret = linkyum_phy_ext_read(phydev, 0xC419);//version + if (ret < 0 || ret > 0x02) + return ret; + + ret = linkyum_phy_ext_write(phydev, 0xC464, 0x01);//powerdown + if (ret < 0) + return ret; + + while (!(linkyum_phy_ext_read(phydev, 0xC465))) { + msleep(10); + if(++num == 5) { + printk("Phy powerdown Set Time Out!\r\n"); + break; + } + } + + ret = linkyum_phy_ext_write(phydev, 0x060E, 0x00); + if (ret < 0) + return ret; + + ret = linkyum_phy_ext_read(phydev, 0x20A4); + if (ret < 0) + return ret; + ret = linkyum_phy_ext_write(phydev, 0x20A4, ret | 0x04); + if (ret < 0) + return ret; + + ret = linkyum_phy_ext_read(phydev, 0x20A4); + if (ret < 0) + return ret; + ret = linkyum_phy_ext_write(phydev, 0x20A4, ret & ~(0x04)); + if (ret < 0) + return ret; + + ret = linkyum_phy_ext_write(phydev, 0x060E, 0x01); + if (ret < 0) + return ret; + + ret = linkyum_phy_ext_write(phydev, 0xC464, 0x00);//powerup + if (ret < 0) + return ret; + + msleep(10); + + return ret; +} + +#if LINKYUM_PHY_LY1241V2_CFG_ENABLE +static int ly1241phy_load_cfg(struct phy_device *phydev) +{ + int i, ver, ret; + + // get version + ret = linkyum_phy_ext_read(phydev, 0xC419); + if (ret < 0) + return ret; + ver = ret; + + // disable startup patch and restart + ret = linkyum_phy_ext_write(phydev, LY_CFG_INIT, 0x85); + if (ret < 0) + return ret; + ret = linkyum_phy_ext_write(phydev, LY_CFG_WAIT, 0x01); + if (ret < 0) + return ret; + ret = linkyum_phy_ext_write(phydev, LY_CFG_EPHY_INIT, 0x85); + if (ret < 0) + return ret; + + // init exp write, addr auto inc for fast load cfg + ret = phy_write(phydev, 0x16, 0x01); + if (ret < 0) + return ret; + + ret = phy_write(phydev, 0x0E, LY_CFG_ADDR); + if (ret < 0) + return ret; + +#if LINKYUM_PHY_LY1241V2_CFG_ENABLE + for(i = 0; i < sizeof(LINKYUM_LY1241V2_CFG) / sizeof(LINKYUM_LY1241V2_CFG[0]); i++) { + ret = phy_write(phydev, 0x0D, LINKYUM_LY1241V2_CFG[i]); + if (ret < 0) + return ret; + } +#endif + + ret = phy_write(phydev, 0x16, 0x00); + if (ret < 0) + return ret; + + ret = linkyum_phy_ext_write(phydev, LY_CFG_WAIT, 0x00); + if (ret < 0) + return ret; + + i = 0; + + // check + while (!((linkyum_phy_ext_read(phydev, LY_CFG_ENABLE) == 0x85) && + (linkyum_phy_ext_read(phydev, LY_CFG_ENABLE_ACK) == 0x85))) { + msleep(10); + if(++i == 5) { + printk("Phy LY1241 CFG Load Time Out!\r\n"); + break; + } + } + + printk("Phy LY1241 CFG VERSION : 0x%x\r\n", linkyum_phy_ext_read(phydev, 0xC461)); + + return 0; +} +#endif + +int ly1241_config_init(struct phy_device *phydev) +{ + int ret; + +#if LINKYUM_PHY_LY1241V2_CFG_ENABLE + ret = ly1241phy_load_cfg(phydev); + if (ret < 0) + return ret; +#endif + +#if (KERNEL_VERSION(5, 4, 0) > LINUX_VERSION_CODE) + ret = genphy_config_init(phydev); +#else + ret = genphy_read_abilities(phydev); +#endif + if (ret < 0) + return ret; + + +#if (KERNEL_VERSION(5, 0, 0) > LINUX_VERSION_CODE) + phydev->supported |= SUPPORTED_1000baseT_Full; + phydev->advertising |= SUPPORTED_1000baseT_Full; +#else + linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, + phydev->supported, ESTATUS_1000_TFULL); + linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, + phydev->advertising, ESTATUS_1000_TFULL); +#endif + +#if LINKYUM_PHY_LINK_OPT_ENABLE + ret = ly1241_power_updown_init(phydev); + if (ret < 0) + return ret; +#endif + + return ly1241_led_init(phydev); +} + +int ly1210_power_updown_init(struct phy_device *phydev) +{ + int ret = 0, num = 0; + + ret = ly1211_phy_ext_read(phydev, 0xC419);//version + if (ret < 0 || ret > 0x02) + return ret; + + ret = ly1211_phy_ext_write(phydev, 0xC464, 0x01);//powerdown + if (ret < 0) + return ret; + + while (!(ly1211_phy_ext_read(phydev, 0xC465))) { + msleep(10); + if(++num == 5) { + printk("Phy powerdown Set Time Out!\r\n"); + break; + } + } + + ret = ly1211_phy_ext_write(phydev, 0x060E, 0x00); + if (ret < 0) + return ret; + + ret = ly1211_phy_ext_read(phydev, 0x20A4); + if (ret < 0) + return ret; + ret = ly1211_phy_ext_write(phydev, 0x20A4, ret | 0x20); + if (ret < 0) + return ret; + + ret = ly1211_phy_ext_read(phydev, 0x20A4); + if (ret < 0) + return ret; + ret = ly1211_phy_ext_write(phydev, 0x20A4, ret & ~(0x20)); + if (ret < 0) + return ret; + + ret = ly1211_phy_ext_write(phydev, 0x060E, 0x01); + if (ret < 0) + return ret; + + ret = ly1211_phy_ext_write(phydev, 0xC464, 0x00);//powerup + if (ret < 0) + return ret; + + msleep(10); + + return ret; +} + + +int ly1210_config_init(struct phy_device *phydev) +{ + int ret = 0; +#if LINKYUM_PHY_LINK_OPT_ENABLE + ret = ly1210_power_updown_init(phydev); + if (ret < 0) + return ret; +#endif + + return ret; +} + + +int ly1211_power_updown_init(struct phy_device *phydev) +{ + int ret = 0, num = 0, temp = 0; + + ret = ly1211_phy_ext_read(phydev, 0xC419);//version + if (ret < 0 || ret > 0x02) + return ret; + + ret = phy_read(phydev, 0x1C); + if (ret < 0) + return ret; + temp = ret; + + ret = phy_write(phydev, 0x1C, 0x4000);//powerdown + if (ret < 0) + return ret; + + while (ly1211_phy_ext_read(phydev, 0x40) || ly1211_phy_ext_read(phydev, 0x256)) { + msleep(10); + if(++num == 5) { + printk("Phy powerdown Set Time Out!\r\n"); + break; + } + } + + ret = ly1211_phy_ext_write(phydev, 0x060E, 0x00); + if (ret < 0) + return ret; + + ret = ly1211_phy_ext_read(phydev, 0x20A4); + if (ret < 0) + return ret; + ret = ly1211_phy_ext_write(phydev, 0x20A4, ret | 0x04); + if (ret < 0) + return ret; + + ret = ly1211_phy_ext_read(phydev, 0x20A4); + if (ret < 0) + return ret; + ret = ly1211_phy_ext_write(phydev, 0x20A4, ret & ~(0x04)); + if (ret < 0) + return ret; + + ret = ly1211_phy_ext_write(phydev, 0x060E, 0x01); + if (ret < 0) + return ret; + + ret = phy_write(phydev, 0x1C, temp);//powerup + if (ret < 0) + return ret; + + while (ly1211_phy_ext_read(phydev, 0x40) || ly1211_phy_ext_read(phydev, 0x256)) { + msleep(10); + if(++num == 5) { + printk("Phy powerup Set Time Out!\r\n"); + break; + } + } + + return ret; +} + +#if LINKYUM_PHY_LY1211_CFG_ENABLE || LINKYUM_PHY_LY1211V2_CFG_ENABLE || LINKYUM_PHY_LY1211V3_CFG_ENABLE +static int ly1211phy_load_cfg(struct phy_device *phydev) +{ + int i, ver, ret; + + // get version + ret = ly1211_phy_ext_read(phydev, 0xC419); + if (ret < 0) + return ret; + ver = ret; + + // disable startup patch and restart + ret = ly1211_phy_ext_write(phydev, LY_CFG_INIT, 0x85); + if (ret < 0) + return ret; + ret = ly1211_phy_ext_write(phydev, LY_CFG_WAIT, 0x01); + if (ret < 0) + return ret; + ret = ly1211_phy_ext_write(phydev, LY_CFG_EPHY_INIT, 0x85); + if (ret < 0) + return ret; + + // init exp write, addr auto inc for fast load cfg + ret = phy_write(phydev, 0x16, 0x01); + if (ret < 0) + return ret; + + ret = phy_write(phydev, 0x0E, LY_CFG_ADDR); + if (ret < 0) + return ret; + +#if LINKYUM_PHY_LY1211_CFG_ENABLE + if (ver == 0x01) { + for(i = 0; i < sizeof(LINKYUM_LY1211_CFG) / sizeof(LINKYUM_LY1211_CFG[0]); i++) { + ret = phy_write(phydev, 0x0D, LINKYUM_LY1211_CFG[i]); + if (ret < 0) + return ret; + } + } +#endif + +#if LINKYUM_PHY_LY1211V2_CFG_ENABLE + if (ver == 0x02) { + for(i = 0; i < sizeof(LINKYUM_LY1211V2_CFG) / sizeof(LINKYUM_LY1211V2_CFG[0]); i++) { + ret = phy_write(phydev, 0x0D, LINKYUM_LY1211V2_CFG[i]); + if (ret < 0) + return ret; + } + } +#endif + +#if LINKYUM_PHY_LY1211V3_CFG_ENABLE + if (ver == 0x03) { + for(i = 0; i < sizeof(LINKYUM_LY1211V3_CFG) / sizeof(LINKYUM_LY1211V3_CFG[0]); i++) { + ret = phy_write(phydev, 0x0D, LINKYUM_LY1211V3_CFG[i]); + if (ret < 0) + return ret; + } + } +#endif + + ret = phy_write(phydev, 0x16, 0x00); + if (ret < 0) + return ret; + + ret = ly1211_phy_ext_write(phydev, LY_CFG_WAIT, 0x00); + if (ret < 0) + return ret; + + i = 0; + + // check + while (!((linkyum_phy_ext_read(phydev, LY_CFG_ENABLE) == 0x85) && + (linkyum_phy_ext_read(phydev, LY_CFG_ENABLE_ACK) == 0x85))) { + msleep(10); + if(++i == 5) { + printk("Phy LY1211 CFG Load Time Out!\r\n"); + break; + } + } + + printk("Phy LY1211 CFG VERSION : 0x%x\r\n", linkyum_phy_ext_read(phydev, 0xC461)); + + return 0; +} +#endif + +int ly1211_config_init(struct phy_device *phydev) +{ + int ret, phymode; + +#if LINKYUM_PHY_LY1211_CFG_ENABLE || LINKYUM_PHY_LY1211V2_CFG_ENABLE || LINKYUM_PHY_LY1211V3_CFG_ENABLE + ret = ly1211phy_load_cfg(phydev); + if (ret < 0) + return ret; +#endif + +#if LINKYUM_PHY_WOL_FEATURE_ENABLE + struct ethtool_wolinfo wol; +#endif + +#if LINKYUM_PHY_MODE_SET_ENABLE + ret = phy_mode_set(phydev, 0x0); + if (ret < 0) + return ret; +#endif + phymode = LYPHY_MODE_CURR; + + if (phymode == LYPHY_PORT_TYPE_UTP || phymode == LYPHY_PORT_TYPE_COMBO) { + linkyum_phy_select_reg_page(phydev, LYPHY_REG_UTP_SPACE); +#if (KERNEL_VERSION(5, 4, 0) > LINUX_VERSION_CODE) + ret = genphy_config_init(phydev); +#else + ret = genphy_read_abilities(phydev); +#endif + if (ret < 0) + return ret; + } else { + linkyum_phy_select_reg_page(phydev, LYPHY_REG_FIBER_SPACE); +#if (KERNEL_VERSION(5, 4, 0) > LINUX_VERSION_CODE) + ret = genphy_config_init(phydev); + if (ret < 0) + return ret; +#else + ret = genphy_read_abilities(phydev); + if (ret < 0) + return ret; +#endif + +#if (KERNEL_VERSION(5, 0, 0) > LINUX_VERSION_CODE) + phydev->supported |= SUPPORTED_1000baseT_Full; + phydev->advertising |= SUPPORTED_1000baseT_Full; +#else + linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, + phydev->supported, ESTATUS_1000_TFULL); + linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, + phydev->advertising, ESTATUS_1000_TFULL); +#endif + } + +#if LINKYUM_PHY_LINK_OPT_ENABLE + ret = ly1211_power_updown_init(phydev); + if (ret < 0) + return ret; +#endif + + ret = ly1211_rxc_init(phydev); + if (ret < 0) + return ret; + + ret = ly1211_config_opt(phydev); + if (ret < 0) + return ret; + +#if LINKYUM_PHY_CLK_OUT_125M_ENABLE + ret = ly1211_clkout_init(phydev); + if (ret < 0) + return ret; +#endif + +#if LINKYUM_PHY_WOL_FEATURE_ENABLE + wol.wolopts = 0; + wol.supported = WAKE_MAGIC; + wol.wolopts |= WAKE_MAGIC; + linkyum_set_wol(phydev, &wol); +#endif + + return ly1121_led_init(phydev); +} + +static int ly1211_update_link(struct phy_device *phydev) +{ + int ret, val, phymode; + + phymode = LYPHY_MODE_CURR; + + if (phymode == LYPHY_PORT_TYPE_UTP || phymode == LYPHY_PORT_TYPE_COMBO) { + /* Do a fake read */ + ret = lyphy_page_read(phydev, LYPHY_REG_UTP_SPACE, MII_BMSR); + if (ret < 0) + return ret; + + /* Read link and autonegotiation status */ + ret = lyphy_page_read(phydev, LYPHY_REG_UTP_SPACE, MII_BMSR); + if (ret < 0) + return ret; + if ((ret & BMSR_LSTATUS) == 0) { + phydev->link = LYPHY_LINK_DOWN; + } else { + phydev->link = LYPHY_LINK_UP; + + val = linkyum_phy_ext_read(phydev, LY1211_EXTREG_GET_PORT_PHY_MODE) & LY1211_EXTREG_PHY_MODE_MASK; + if (val < 0) + return val; + if (val == LY1211_EXTREG_PHY_MODE_UTP_OR_FIBER_TO_RGMII) { + linkyum_phy_select_reg_page(phydev, LYPHY_REG_UTP_SPACE); + } + return LYPHY_REG_UTP_SPACE; + } + } + + if (phymode == LYPHY_PORT_TYPE_FIBER || phymode == LYPHY_PORT_TYPE_COMBO) { + /* Do a fake read */ + ret = lyphy_page_read(phydev, LYPHY_REG_FIBER_SPACE, MII_BMSR); + if (ret < 0) + return ret; + + /* Read link and autonegotiation status */ + ret = lyphy_page_read(phydev, LYPHY_REG_FIBER_SPACE, MII_BMSR); + if (ret < 0) + return ret; + + if ((ret & BMSR_LSTATUS) == 0) { + phydev->link = LYPHY_LINK_DOWN; + return LYPHY_REG_UTP_SPACE; + } else { + val = linkyum_phy_ext_read(phydev, LY1211_EXTREG_GET_PORT_PHY_MODE) & LY1211_EXTREG_PHY_MODE_MASK; + if (val < 0) + return val; + if (val != LY1211_EXTREG_PHY_MODE_SGMII_MAC_TO_RGMII_PHY) { + if (val == LY1211_EXTREG_PHY_MODE_UTP_OR_FIBER_TO_RGMII) { + linkyum_phy_select_reg_page(phydev, LYPHY_REG_FIBER_SPACE); + } + phydev->link = LYPHY_LINK_UP; + } else { + ret = lyphy_page_read(phydev, LYPHY_REG_FIBER_SPACE, 0x1C); + if ((ret & 0x8000) == 0) { + phydev->link = LYPHY_LINK_DOWN; + } else { + phydev->link = LYPHY_LINK_UP; + } + } + return LYPHY_REG_FIBER_SPACE; + } + } + return LYPHY_REG_UTP_SPACE; +} + +static int ly1211_read_status(struct phy_device *phydev) +{ + int val, ret, lpa, page; + + /* Update the link, but return if there was an error */ + ret = ly1211_update_link(phydev); + if (ret < 0) + return ret; + page = ret; + + phydev->speed = SPEED_10; + phydev->duplex = DUPLEX_HALF; + phydev->pause = 0; + phydev->asym_pause = 0; + + val = lyphy_page_read(phydev, page, LINKYUM_SPEC_REG); + if (val < 0) + return val; + + lpa = lyphy_page_read(phydev, page, MII_LPA); + if (lpa < 0) + return lpa; + + if (val & 0x02) + phydev->duplex = DUPLEX_FULL; + if ((val & 0x18) == 0x10) + phydev->speed = SPEED_1000; + if ((val & 0x18) == 0x08) + phydev->speed = SPEED_100; + if (phydev->duplex == DUPLEX_FULL) { + if(page == LYPHY_REG_UTP_SPACE) { + phydev->pause = lpa & UTP_REG_PAUSE_CAP ? 1 : 0; + phydev->asym_pause = lpa & UTP_REG_PAUSE_ASYM ? 1 : 0; + } else { + phydev->pause = lpa & FIBER_REG_PAUSE_CAP ? 1 : 0; + phydev->asym_pause = lpa & FIBER_REG_PAUSE_ASYM ? 1 : 0; + } + } + return 0; +} + + +static int ly1241_update_link(struct phy_device *phydev) +{ + int ret; + + /* Do a fake read */ + ret = ly1241_phy_read(phydev, MII_BMSR); + if (ret < 0) + return ret; + + /* Read link and autonegotiation status */ + ret = ly1241_phy_read(phydev, MII_BMSR); + if (ret < 0) + return ret; + + if ((ret & BMSR_LSTATUS) == 0) + phydev->link = LYPHY_LINK_DOWN; + else + phydev->link = LYPHY_LINK_UP; + + return 0; +} + +static int ly1241_read_status(struct phy_device *phydev) +{ + int val, ret, lpa; + + /* Update the link, but return if there was an error */ + ret = ly1241_update_link(phydev); + if (ret < 0) + return ret; + + phydev->speed = SPEED_10; + phydev->duplex = DUPLEX_HALF; + phydev->pause = 0; + phydev->asym_pause = 0; + + val = ly1241_phy_read(phydev, LINKYUM_SPEC_REG); + if (val < 0) + return val; + + lpa = ly1241_phy_read(phydev, MII_LPA); + if (lpa < 0) + return lpa; + + if (val & 0x02) + phydev->duplex = DUPLEX_FULL; + if ((val & 0x18) == 0x10) + phydev->speed = SPEED_1000; + if ((val & 0x18) == 0x08) + phydev->speed = SPEED_100; + if (phydev->duplex == DUPLEX_FULL) { + phydev->pause = lpa & UTP_REG_PAUSE_CAP ? 1 : 0; + phydev->asym_pause = lpa & UTP_REG_PAUSE_ASYM ? 1 : 0; + } + return 0; +} + +static int ly1210_read_status(struct phy_device *phydev) +{ + int val, ret, lpa; + + /* Update the link, but return if there was an error */ + ret = ly1241_update_link(phydev); + if (ret < 0) + return ret; + + phydev->speed = SPEED_10; + phydev->duplex = DUPLEX_HALF; + phydev->pause = 0; + phydev->asym_pause = 0; + + val = ly1241_phy_read(phydev, LINKYUM_SPEC_REG); + if (val < 0) + return val; + + lpa = ly1241_phy_read(phydev, MII_LPA); + if (lpa < 0) + return lpa; + + if (val & 0x02) + phydev->duplex = DUPLEX_FULL; + // if ((val & 0x18) == 0x10) + // phydev->speed = SPEED_1000; + if ((val & 0x18) == 0x08) + phydev->speed = SPEED_100; + if (phydev->duplex == DUPLEX_FULL) { + phydev->pause = lpa & UTP_REG_PAUSE_CAP ? 1 : 0; + phydev->asym_pause = lpa & UTP_REG_PAUSE_ASYM ? 1 : 0; + } + return 0; +} + +static struct phy_driver ly_phy_drivers[] = { + { + .phy_id = LY1210_PHY_ID, + .phy_id_mask = LINKYUM_PHY_ID_MASK, + .name = "LY1210A 100M Ethernet", + .features = PHY_BASIC_FEATURES, + .flags = PHY_POLL, + .config_init = ly1210_config_init, + .read_status = ly1210_read_status, +#if (KERNEL_VERSION(4, 12, 0) <= LINUX_VERSION_CODE) + .write_mmd = genphy_write_mmd_unsupported, + .read_mmd = genphy_read_mmd_unsupported, +#endif + }, + + { + .phy_id = LY1211_PHY_ID, + .phy_id_mask = LINKYUM_PHY_ID_MASK, + .name = "LY1211A_LY1211S Gigabit Ethernet", + .features = PHY_GBIT_FEATURES, + .flags = PHY_POLL, + .config_init = ly1211_config_init, + .config_aneg = ly1211_config_aneg, +#if (KERNEL_VERSION(3, 14, 79) < LINUX_VERSION_CODE) + .aneg_done = ly1211_aneg_done, +#endif + .read_status = ly1211_read_status, +#if (KERNEL_VERSION(4, 12, 0) <= LINUX_VERSION_CODE) + .write_mmd = genphy_write_mmd_unsupported, + .read_mmd = genphy_read_mmd_unsupported, +#endif + .suspend = genphy_suspend, + .resume = genphy_resume, +#if LINKYUM_PHY_WOL_FEATURE_ENABLE + .get_wol = &linkyum_get_wol, + .set_wol = &linkyum_set_wol, +#endif + }, + + { + .phy_id = LY1241_PHY_ID, + .phy_id_mask = LINKYUM_PHY_ID_MASK, + .name = "LY1241A_LY1241B Gigabit Ethernet", + .features = PHY_GBIT_FEATURES, + .flags = PHY_POLL, + .config_init = ly1241_config_init, + .config_aneg = genphy_config_aneg, + .read_status = ly1241_read_status, +#if (KERNEL_VERSION(4, 12, 0) <= LINUX_VERSION_CODE) + .write_mmd = genphy_write_mmd_unsupported, + .read_mmd = genphy_read_mmd_unsupported, +#endif + .suspend = genphy_suspend, + .resume = genphy_resume, + }, +}; + +#if (KERNEL_VERSION(4, 0, 0) > LINUX_VERSION_CODE) +static int ly_phy_drivers_register(struct phy_driver *phy_drvs, int size) +{ + int i, j; + int ret; + + for (i = 0; i < size; i++) { + ret = phy_driver_register(&phy_drvs[i]); + if (ret) + goto err; + } + + return 0; + +err: + for (j = 0; j < i; j++) + phy_driver_unregister(&phy_drvs[j]); + + return ret; +} + +static void ly_phy_drivers_unregister(struct phy_driver *phy_drvs, int size) +{ + int i; + + for (i = 0; i < size; i++) + phy_driver_unregister(&phy_drvs[i]); +} + +static int __init ly_phy_init(void) +{ + return ly_phy_drivers_register(ly_phy_drivers, ARRAY_SIZE(ly_phy_drivers)); +} + +static void __exit ly_phy_exit(void) +{ + ly_phy_drivers_unregister(ly_phy_drivers, ARRAY_SIZE(ly_phy_drivers)); +} + +module_init(ly_phy_init); +module_exit(ly_phy_exit); +#else +/* for linux 4.x */ +module_phy_driver(ly_phy_drivers); +#endif + +static struct mdio_device_id __maybe_unused linkyum_phy_tbl[] = { + { LY1210_PHY_ID, LINKYUM_PHY_ID_MASK }, + { LY1211_PHY_ID, LINKYUM_PHY_ID_MASK }, + { LY1241_PHY_ID, LINKYUM_PHY_ID_MASK }, + {}, +}; + +MODULE_DEVICE_TABLE(mdio, linkyum_phy_tbl); + +MODULE_DESCRIPTION("Linkyum PHY driver"); +MODULE_AUTHOR("Huxl"); +MODULE_LICENSE("GPL"); -- Gitee From dd51aa40f41589c5dcda33e97b5b6c91d3b25c82 Mon Sep 17 00:00:00 2001 From: liutianyu1250 Date: Thu, 25 Sep 2025 16:45:35 +0800 Subject: [PATCH 145/155] net: phy: skip scan c45 when yumlink phy We need skip scan c45 when use yumlink phy, otherwise phy match will be [Generic Clause 45 PHY], and won't work correctly. Signed-off-by: liutianyu1250 --- drivers/net/phy/mdio_bus.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index 25dcaa49ab..6a7635be65 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -632,7 +632,8 @@ static bool mdiobus_prevent_c45_scan(struct mii_bus *bus) continue; oui = phydev->phy_id >> 10; - if (oui == MICREL_OUI) + /* skip c45 scan when linkyum phy */ + if (oui == MICREL_OUI || oui == 0x2B6D01) return true; } return false; -- Gitee From 5766475400f38392ea638895a325e37ef7e3fad2 Mon Sep 17 00:00:00 2001 From: liutianyu1250 Date: Fri, 26 Sep 2025 15:46:05 +0800 Subject: [PATCH 146/155] arm64: phytium_defconfig: add ma1026 codec add yumlink phy Signed-off-by: liutianyu1250 --- arch/arm64/configs/phytium_defconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/configs/phytium_defconfig b/arch/arm64/configs/phytium_defconfig index 111b8e2db6..d15c578dc0 100644 --- a/arch/arm64/configs/phytium_defconfig +++ b/arch/arm64/configs/phytium_defconfig @@ -296,6 +296,7 @@ CONFIG_NGBE=y CONFIG_AQUANTIA_PHY=y CONFIG_BROADCOM_PHY=m CONFIG_BCM54140_PHY=m +CONFIG_LINKYUM_PHY=y CONFIG_MARVELL_PHY=m CONFIG_MARVELL_10G_PHY=y CONFIG_MICREL_PHY=y @@ -630,6 +631,7 @@ CONFIG_SND_SOC_IMX_AUDMUX=m CONFIG_SND_SOC_PHYTIUM_I2S=y CONFIG_SND_PMDK_ES8388=y CONFIG_SND_PMDK_ES8336=y +CONFIG_SND_PMDK_MA1026=y CONFIG_SND_SOC_PHYTIUM_I2S_V2=y CONFIG_SND_SOC_PHYTIUM_MACHINE_V2=y CONFIG_SND_PMDK_DP=y -- Gitee From d93fa9c65b76e648488778d48eb205a47bcd04e3 Mon Sep 17 00:00:00 2001 From: zuoqian Date: Sun, 28 Sep 2025 14:38:21 +0800 Subject: [PATCH 147/155] net: phytmac: fix fixed-link link down ethtool status Add reset pdata->speed & duplex when not link in fixed-link mode. When link is down, ethtool will show: ... Speed: Unknown! Duplex: Unknown! (255) ... rather than the old speed & duplex info at link up. Signed-off-by: zuoqian --- drivers/net/ethernet/phytium/phytmac_ethtool.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/phytium/phytmac_ethtool.c b/drivers/net/ethernet/phytium/phytmac_ethtool.c index bed3d6e4d0..86e8c7b5c4 100644 --- a/drivers/net/ethernet/phytium/phytmac_ethtool.c +++ b/drivers/net/ethernet/phytium/phytmac_ethtool.c @@ -385,8 +385,13 @@ static int phytmac_get_link_ksettings(struct net_device *ndev, if (!ndev->phydev) { kset->base.port = PORT_FIBRE; kset->base.transceiver = XCVR_INTERNAL; - kset->base.duplex = pdata->duplex; - kset->base.speed = pdata->speed; + if (netif_carrier_ok(ndev)) { + kset->base.duplex = pdata->duplex; + kset->base.speed = pdata->speed; + } else { + kset->base.duplex = DUPLEX_UNKNOWN; + kset->base.speed = SPEED_UNKNOWN; + } if (pdata->phy_interface == PHY_INTERFACE_MODE_USXGMII || pdata->phy_interface == PHY_INTERFACE_MODE_10GBASER) { -- Gitee From c66b142d29771112ef355f35075f2c9355650436 Mon Sep 17 00:00:00 2001 From: zuoqian Date: Mon, 29 Sep 2025 14:06:46 +0800 Subject: [PATCH 148/155] net: macb: fix fixed-link link down ethtool status Signed-off-by: zuoqian --- drivers/net/ethernet/cadence/macb_main.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index 65c375e8a4..c9d554e978 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -989,6 +989,9 @@ static void macb_mac_link_up(struct phylink_config *config, macb_set_tx_clk(bp, speed); + bp->speed = speed; + bp->duplex = duplex; + /* Initialize rings & buffers as clearing MACB_BIT(TE) in link down * cleared the pipeline and control registers. */ @@ -3775,8 +3778,13 @@ static int macb_get_link_ksettings(struct net_device *netdev, supported); ethtool_convert_legacy_u32_to_link_mode(kset->link_modes.advertising, advertising); - kset->base.speed = bp->speed; - kset->base.duplex = bp->duplex; + if (netif_carrier_ok(netdev)) { + kset->base.speed = bp->speed; + kset->base.duplex = bp->duplex; + } else { + kset->base.speed = SPEED_UNKNOWN; + kset->base.duplex = DUPLEX_UNKNOWN; + } } else { phylink_ethtool_ksettings_get(bp->phylink, kset); } -- Gitee From eb54c8de617cf2e91f64d34640bfafbc77eb1e6c Mon Sep 17 00:00:00 2001 From: liutianyu1250 Date: Wed, 15 Oct 2025 15:00:22 +0800 Subject: [PATCH 149/155] arm64: phytium_defconfig: Set CONFIG_USB_ONBOARD_HUB to y for USB boot stability Fix USB read/write errors when booting from USB drive attached to hub Change config from module (m) to built-in (y) to avoid module load issues Signed-off-by: liutianyu1250 --- arch/arm64/configs/phytium_defconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/configs/phytium_defconfig b/arch/arm64/configs/phytium_defconfig index d15c578dc0..ea2cb78d20 100644 --- a/arch/arm64/configs/phytium_defconfig +++ b/arch/arm64/configs/phytium_defconfig @@ -727,7 +727,7 @@ CONFIG_USB_SERIAL_CP210X=m CONFIG_USB_SERIAL_FTDI_SIO=m CONFIG_USB_SERIAL_OPTION=m CONFIG_USB_HSIC_USB3503=y -CONFIG_USB_ONBOARD_HUB=m +CONFIG_USB_ONBOARD_HUB=y CONFIG_NOP_USB_XCEIV=y CONFIG_USB_ULPI=y CONFIG_USB_GADGET=y -- Gitee From 7c9ca9af7d15d02f20347c3030f179881f3eb596 Mon Sep 17 00:00:00 2001 From: liutianyu1250 Date: Thu, 16 Oct 2025 18:05:41 +0800 Subject: [PATCH 150/155] net/phytmac: update mdc early to fix PHY ID read issue The MDC modification in the driver was previously positioned after mdiobus_register, which caused the MDC not to be properly configured when reading the PHY ID. This resulted in potential issues during PHY ID detection. This commit adjusts the driver by moving the MDC modification logic to before the call to mdiobus_register, ensuring the MDC is correctly set up prior to PHY ID reading operations. Signed-off-by: liutianyu1250 --- drivers/net/ethernet/phytium/phytmac_v2.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/phytium/phytmac_v2.c b/drivers/net/ethernet/phytium/phytmac_v2.c index 4dd3ddd18e..0df1771ca3 100644 --- a/drivers/net/ethernet/phytium/phytmac_v2.c +++ b/drivers/net/ethernet/phytium/phytmac_v2.c @@ -194,7 +194,6 @@ static int phytmac_v2_init_hw(struct phytmac *pdata) struct phytmac_dma_info dma; struct phytmac_eth_info eth; u32 ptrconfig = 0; - u8 mdc; if (pdata->capacities & PHYTMAC_CAPS_TAILPTR) ptrconfig |= PHYTMAC_BIT(TXTAIL_EN); @@ -257,10 +256,6 @@ static int phytmac_v2_init_hw(struct phytmac *pdata) dma.hw_dma_cap |= HW_DMA_CAP_DDW128; phytmac_v2_msg_send(pdata, cmd_id, cmd_subid, (void *)&dma, sizeof(dma), 0); - cmd_subid = PHYTMAC_MSG_CMD_SET_MDC; - mdc = PHYTMAC_CLK_DIV96; - phytmac_v2_msg_send(pdata, cmd_id, cmd_subid, (void *)(&mdc), sizeof(mdc), 0); - memset(ð, 0, sizeof(eth)); cmd_subid = PHYTMAC_MSG_CMD_SET_ETH_MATCH; eth.index = 0; @@ -705,8 +700,13 @@ static int phytmac_v2_enable_txcsum(struct phytmac *pdata, int enable) static int phytmac_v2_enable_mdio(struct phytmac *pdata, int enable) { u16 cmd_id, cmd_subid; + u8 mdc; cmd_id = PHYTMAC_MSG_CMD_SET; + cmd_subid = PHYTMAC_MSG_CMD_SET_MDC; + mdc = PHYTMAC_CLK_DIV96; + phytmac_v2_msg_send(pdata, cmd_id, cmd_subid, (void *)(&mdc), sizeof(mdc), 0); + if (enable) cmd_subid = PHYTMAC_MSG_CMD_SET_ENABLE_MDIO; else -- Gitee From 9bc24c634575287721a14bbd1aa0944dd17d9bfe Mon Sep 17 00:00:00 2001 From: zuoqian Date: Thu, 16 Oct 2025 17:26:01 +0800 Subject: [PATCH 151/155] net: phytmac: support ipv6 TSO Signed-off-by: zuoqian --- drivers/net/ethernet/phytium/phytmac_main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/phytium/phytmac_main.c b/drivers/net/ethernet/phytium/phytmac_main.c index ece14f0a7b..ccdb2be4ab 100644 --- a/drivers/net/ethernet/phytium/phytmac_main.c +++ b/drivers/net/ethernet/phytium/phytmac_main.c @@ -2365,7 +2365,7 @@ static netdev_features_t phytmac_features_check(struct sk_buff *skb, hdrlen = skb_transport_offset(skb); if (!IS_ALIGNED(skb_headlen(skb) - hdrlen, PHYTMAC_TX_LEN_ALIGN)) - return features & ~NETIF_F_TSO; + return features & ~(NETIF_F_TSO | NETIF_F_TSO6); nr_frags = skb_shinfo(skb)->nr_frags; /* No need to check last fragment */ @@ -2374,7 +2374,7 @@ static netdev_features_t phytmac_features_check(struct sk_buff *skb, const skb_frag_t *frag = &skb_shinfo(skb)->frags[f]; if (!IS_ALIGNED(skb_frag_size(frag), PHYTMAC_TX_LEN_ALIGN)) - return features & ~NETIF_F_TSO; + return features & ~(NETIF_F_TSO | NETIF_F_TSO6); } return features; } @@ -2664,7 +2664,7 @@ void phytmac_default_config(struct phytmac *pdata) ndev->hw_features = NETIF_F_SG; if (pdata->capacities & PHYTMAC_CAPS_LSO) - ndev->hw_features |= NETIF_F_TSO; + ndev->hw_features |= NETIF_F_TSO | NETIF_F_TSO6; if (pdata->use_ncsi) { ndev->hw_features &= ~(NETIF_F_HW_CSUM | NETIF_F_RXCSUM); -- Gitee From a0edceb84c2112150cf9c15dcd46bcd7765d094b Mon Sep 17 00:00:00 2001 From: Huangjie Date: Thu, 16 Oct 2025 15:58:28 +0800 Subject: [PATCH 152/155] drivers: edac/phytium: ignore pe220x soc_err 40~43 soc_err 40-43 is for debug not open for user Signed-off-by: Huangjie --- drivers/edac/phytium_edac.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/edac/phytium_edac.c b/drivers/edac/phytium_edac.c index aaca6ac8b9..e01b7dee8c 100644 --- a/drivers/edac/phytium_edac.c +++ b/drivers/edac/phytium_edac.c @@ -189,7 +189,7 @@ static const struct ras_error_info pd2208_ras_sram_err[] = { {30, CORRECTED_ERROR, "gmactx2_corrected_err"}, {31, UNCORRECTED_ERROR, "gmactx2_uncorrected_err"}, {32, CORRECTED_ERROR, "gmactx3_corrected_err"}, - {33, UNCORRECTED_ERROR, "gmactx3_uncorrected_err"}, + {33, UNCORRECTED_ERROR, "gmactx3_uncorrected_err"}, }; static const struct ras_error_info pd2208_ras_peu_sram0_err[] = { @@ -500,6 +500,11 @@ static void phytium_edac_error_report(struct phytium_edac *edac, const struct ras_error_info *err_info = edac->error_info[error_group]; + /* ignore pe220x soc_err id 40~43 */ + if ((err_info == pe220x_ras_soc_error) && + (error_id >= 40) && (error_id <= 43)) + return; + if (err_info[error_id].error_type == UNCORRECTED_ERROR) { edac_printk(KERN_CRIT, EDAC_MOD_STR, "uncorrected error: %s\n", err_info[error_id].error_str); -- Gitee From cddaca1cd698c7998a61829e658b7f7f2f8ac00f Mon Sep 17 00:00:00 2001 From: zuoqian Date: Fri, 17 Oct 2025 17:17:42 +0800 Subject: [PATCH 153/155] net: macb: support ipv6 TSO Signed-off-by: zuoqian --- drivers/net/ethernet/cadence/macb_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index c9d554e978..f656e817c5 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -88,7 +88,7 @@ struct sifive_fu540_macb_mgmt { #define GEM_MAX_TX_LEN (unsigned int)(0x3FC0) #define GEM_MTU_MIN_SIZE ETH_MIN_MTU -#define MACB_NETIF_LSO NETIF_F_TSO +#define MACB_NETIF_LSO (NETIF_F_TSO | NETIF_F_TSO6) #define MACB_WOL_HAS_MAGIC_PACKET (0x1 << 0) #define MACB_WOL_ENABLED (0x1 << 1) -- Gitee From 47bd4cd0d8a389bbfad50b681b13196059e659eb Mon Sep 17 00:00:00 2001 From: liutianyu1250 Date: Mon, 20 Oct 2025 16:22:07 +0800 Subject: [PATCH 154/155] arm64: phytium_defconfig: default enable CIFS Signed-off-by: liutianyu1250 --- arch/arm64/configs/phytium_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/configs/phytium_defconfig b/arch/arm64/configs/phytium_defconfig index ea2cb78d20..8407833152 100644 --- a/arch/arm64/configs/phytium_defconfig +++ b/arch/arm64/configs/phytium_defconfig @@ -975,6 +975,7 @@ CONFIG_NFSD_V2=y CONFIG_NFSD_V2_ACL=y CONFIG_NFSD_V3_ACL=y CONFIG_NFSD_V4=y +CONFIG_CIFS=y CONFIG_9P_FS=y CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ISO8859_1=y -- Gitee From 2a7ebb49038970103032ff6679cd627d848c66f3 Mon Sep 17 00:00:00 2001 From: liutianyu1250 Date: Mon, 20 Oct 2025 17:21:17 +0800 Subject: [PATCH 155/155] sound: ma1026: remove error makefile object Signed-off-by: liutianyu1250 --- sound/soc/codecs/Makefile | 1 - sound/soc/phytium/Kconfig | 7 ------- 2 files changed, 8 deletions(-) diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 32660fd0b6..791be6458d 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -643,7 +643,6 @@ obj-$(CONFIG_SND_SOC_SIGMADSP_REGMAP) += snd-soc-sigmadsp-regmap.o obj-$(CONFIG_SND_SOC_SI476X) += snd-soc-si476x.o obj-$(CONFIG_SND_SOC_SMA1303) += snd-soc-sma1303.o obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif-rx.o snd-soc-spdif-tx.o -obj-$(CONFIG_SND_SOC_SIRF_AUDIO_CODEC) += sirf-audio-codec.o obj-$(CONFIG_SND_SOC_SRC4XXX) += snd-soc-src4xxx.o obj-$(CONFIG_SND_SOC_SRC4XXX_I2C) += snd-soc-src4xxx-i2c.o obj-$(CONFIG_SND_SOC_SSM2305) += snd-soc-ssm2305.o diff --git a/sound/soc/phytium/Kconfig b/sound/soc/phytium/Kconfig index 0ded12199c..20ddf8e26b 100644 --- a/sound/soc/phytium/Kconfig +++ b/sound/soc/phytium/Kconfig @@ -56,10 +56,3 @@ config SND_PMDK_DP Say Y if you want to add Phytium machine support for Displayport. - -config SND_PMDK_MA1026 - tristate "Phytium machine support with MA1026" - depends on I2C && SND_SOC_PHYTIUM_I2S - select SND_SOC_MA1026 - help - Say Y if you want to add Phytium machine support for MA1026 \ No newline at end of file -- Gitee