From 29d330ede3e8f42b8887596212eb795173c9422d Mon Sep 17 00:00:00 2001 From: Jing Li Date: Fri, 8 Dec 2023 17:12:39 +0800 Subject: [PATCH 01/49] anolis: sw64: smp: suppress function setup_smp() when ACPI enabled ANBZ: #4688 When ACPI enabled, we setup rcid and cpu mask via SW CINTC entry in ACPI MADT table. At this point, function setup_smp() is no longer needed. This function is only used to keep compatibility with legacy codes. Signed-off-by: Jing Li Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/kernel/setup.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/sw_64/kernel/setup.c b/arch/sw_64/kernel/setup.c index 43e03cb4ea78..28e1c0f61c25 100644 --- a/arch/sw_64/kernel/setup.c +++ b/arch/sw_64/kernel/setup.c @@ -848,11 +848,13 @@ setup_arch(char **cmdline_p) /* Parse the ACPI tables for possible boot-time configuration */ acpi_boot_table_init(); + if (acpi_disabled) { #ifdef CONFIG_SMP - setup_smp(); + setup_smp(); #else - store_cpu_data(0); + store_cpu_data(0); #endif + } sw64_numa_init(); -- Gitee From 638264e60b54f9b76d329df1a951ddac25882591 Mon Sep 17 00:00:00 2001 From: Jing Li Date: Wed, 27 Dec 2023 17:03:25 +0800 Subject: [PATCH 02/49] anolis: sw64: pci: fix compile error when CONFIG_ACPI=n ANBZ: #4688 Signed-off-by: Jing Li Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- drivers/pci/controller/pci-sunway.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/controller/pci-sunway.c b/drivers/pci/controller/pci-sunway.c index 894e88ef5c39..d524a1d15185 100644 --- a/drivers/pci/controller/pci-sunway.c +++ b/drivers/pci/controller/pci-sunway.c @@ -600,12 +600,12 @@ static void __iomem *sw64_pcie_map_bus(struct pci_bus *bus, return cfg_iobase; } -#ifdef CONFIG_ACPI int sw64_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) { return map_irq(dev, slot, pin); } +#ifdef CONFIG_ACPI static void setup_intx_irqs(struct pci_controller *hose) { unsigned long int_conf, node, val_node; -- Gitee From 9b84ffb452dc9960abc74d6d3c9e4fe46655f0ff Mon Sep 17 00:00:00 2001 From: Yan Bo Date: Thu, 18 Jan 2024 16:16:03 +0000 Subject: [PATCH 03/49] anolis: sw64: iommu: use a generic implementation of DMA ops MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ANBZ: #4688 We deprecate the specific IOMMU DMA ops of SW64 arch and use a generic implementation instead, it seems to be a more common practice as other architectures. Besides, we also fix a NULL dereference on the member iova_cookie of  struct iommu_domain. Signed-off-by: Yan Bo Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- drivers/iommu/sw64/Kconfig | 1 + drivers/iommu/sw64/sunway_iommu.c | 439 +----------------------------- 2 files changed, 4 insertions(+), 436 deletions(-) diff --git a/drivers/iommu/sw64/Kconfig b/drivers/iommu/sw64/Kconfig index bffc464f2de8..3a6a1e994f31 100644 --- a/drivers/iommu/sw64/Kconfig +++ b/drivers/iommu/sw64/Kconfig @@ -4,6 +4,7 @@ config SUNWAY_IOMMU bool "Sunway IOMMU Support" select IOMMU_API select IOMMU_IOVA + select IOMMU_DMA depends on SW64 && PCI && SUBARCH_C3B help Support for IOMMU on SW64 platform. It can enable or bypass specific device by diff --git a/drivers/iommu/sw64/sunway_iommu.c b/drivers/iommu/sw64/sunway_iommu.c index e9fc7bb5e890..a1b593109407 100644 --- a/drivers/iommu/sw64/sunway_iommu.c +++ b/drivers/iommu/sw64/sunway_iommu.c @@ -447,32 +447,6 @@ static struct sunway_iommu_dev *search_dev_data(u16 devid) return NULL; } -/* dma_ops helpers*/ -static struct sunway_iommu_domain *get_sunway_domain(struct device *dev) -{ - struct sunway_iommu_domain *sdomain; - struct iommu_domain *domain; - struct pci_dev *pdev; - struct sunway_iommu_dev *sdev; - - pdev = to_pci_dev(dev); - if (!pdev) - return ERR_PTR(-ENODEV); - - sdev = dev_iommu_priv_get(dev); - sdomain = sdev->domain; - if (sdomain == NULL) { - domain = iommu_get_domain_for_dev(dev); - sdomain = to_sunway_domain(domain); - attach_device(dev, sdomain); - } - - if (sdomain == NULL) - return ERR_PTR(-EBUSY); - - return sdomain; -} - /********************************************************************** * * Following functions describe IOMMU init ops @@ -902,415 +876,6 @@ int sunway_iommu_map_page(struct sunway_iommu_domain *sunway_domain, return 0; } -static unsigned long -sunway_alloc_iova(struct dma_domain *dma_dom, unsigned int pages) -{ - unsigned long pfn = 0; - - pages = __roundup_pow_of_two(pages); - /* IOVA boundary should be 16M ~ 3.5G */ - pfn = alloc_iova_fast(&dma_dom->iovad, pages, - IOVA_PFN(SW64_DMA_LIMIT), true); - if (!pfn) - return 0; - - return (pfn << PAGE_SHIFT); -} - -static void sunway_free_iova(struct dma_domain *dma_dom, - unsigned long address, unsigned int pages) -{ - pages = __roundup_pow_of_two(pages); - address >>= PAGE_SHIFT; - - free_iova_fast(&dma_dom->iovad, address, pages); -} - -static dma_addr_t -__sunway_map_single(struct dma_domain *dma_dom, - struct pci_dev *pdev, phys_addr_t paddr, size_t size) -{ - struct pci_controller *hose = pci_bus_to_pci_controller(pdev->bus); - dma_addr_t ret, address, start; - long npages; - int i; - - if (hose == NULL) { - pr_err("%s:hose does not exist!\n", __func__); - return 0; - } - - npages = iommu_num_pages(paddr, size, PAGE_SIZE); - - address = sunway_alloc_iova(dma_dom, npages); - if (!address) - return 0; - - start = address; - for (i = 0; i < npages; ++i) { - ret = sunway_iommu_map_page(&dma_dom->sdomain, start, - paddr, PAGE_SIZE); - if (ret) { - pr_info("error when map page.\n"); - goto out_unmap; - } - - start += PAGE_SIZE; - paddr += PAGE_SIZE; - } - - address += paddr & ~PAGE_MASK; - return address; - -out_unmap: - for (--i; i >= 0; --i) { - start -= PAGE_SIZE; - sunway_iommu_unmap_page(&dma_dom->sdomain, start, PAGE_SIZE); - } - - sunway_free_iova(dma_dom, address, npages); - return 0; -} - -static dma_addr_t -pci_iommu_map_single(struct pci_dev *pdev, - struct dma_domain *dma_dom, void *cpu_addr, size_t size) -{ - struct pci_controller *hose = pci_bus_to_pci_controller(pdev->bus); - unsigned long paddr; - - if (hose == NULL) { - pr_err("%s: hose does not exist!\n", __func__); - return 0; - } - - paddr = __sunway_map_single(dma_dom, pdev, __pa(cpu_addr), size); - - pr_debug("pci_alloc_consistent: %zx -> [%px,%lx] from %ps\n", - size, cpu_addr, paddr, __builtin_return_address(0)); - - return paddr; -} - -static void *sunway_alloc_coherent(struct device *dev, - size_t size, - dma_addr_t *dma_addr, gfp_t gfp, - unsigned long attrs) -{ - struct pci_dev *pdev = to_pci_dev(dev); - struct pci_controller *hose; - struct sunway_iommu_domain *sdomain; - struct dma_domain *dma_dom; - struct sunway_iommu_dev *sdev; - struct page *page; - void *cpu_addr; - - if (!pdev) - return NULL; - - hose = pci_bus_to_pci_controller(pdev->bus); - if (!hose) - return NULL; - - gfp &= ~GFP_DMA; - -try_again: - page = alloc_pages_node(dev_to_node(dev), gfp | __GFP_ZERO, get_order(size)); - cpu_addr = page_address(page); - if (!cpu_addr) { - pr_info - ("pci_alloc_consistent: get_free_pages failed from %ps\n", - __builtin_return_address(0)); - - return NULL; - } - - *dma_addr = __pa(cpu_addr); - if (!(hose->iommu_enable)) - return cpu_addr; - - sdev = dev_iommu_priv_get(dev); - if (sdev->passthrough & DMA_MASK64) - return cpu_addr; - else if (sdev->passthrough) { - if (min_not_zero(*dev->dma_mask, dev->coherent_dma_mask) - > DMA_BIT_MASK(32)) { - sdev->passthrough |= DMA_MASK64; - return cpu_addr; - } - - __free_pages(page, get_order(size)); - set_dma_ops(dev, get_arch_dma_ops(dev->bus)); - return dev->dma_ops->alloc(dev, size, dma_addr, gfp, attrs); - } - - sdomain = get_sunway_domain(dev); - dma_dom = to_dma_domain(sdomain); - - *dma_addr = pci_iommu_map_single(pdev, dma_dom, cpu_addr, size); - if (*dma_addr == 0) { - free_pages((unsigned long)cpu_addr, get_order(size)); - if (gfp & GFP_DMA) - return NULL; - - gfp |= GFP_DMA; - goto try_again; - } - - return cpu_addr; -} - -static void -__sunway_unmap_single(struct dma_domain *dma_dom, dma_addr_t dma_addr, size_t size) -{ - dma_addr_t start; - long npages; - int i; - - npages = iommu_num_pages(dma_addr, size, PAGE_SIZE); - dma_addr &= PAGE_MASK; - start = dma_addr; - - for (i = 0; i < npages; ++i) { - sunway_iommu_unmap_page(&dma_dom->sdomain, start, PAGE_SIZE); - start += PAGE_SIZE; - } - - sunway_free_iova(dma_dom, dma_addr, npages); - pr_debug("pci_free_consistent: %zx -> [%llx] from %ps\n", - size, dma_addr, __builtin_return_address(0)); - -} - -static void -sunway_free_coherent(struct device *dev, size_t size, - void *vaddr, dma_addr_t dma_addr, unsigned long attrs) -{ - struct sunway_iommu_domain *sdomain; - struct dma_domain *dma_dom; - struct pci_dev *pdev = to_pci_dev(dev); - struct pci_controller *hose; - struct sunway_iommu_dev *sdev; - - if (!pdev) - goto out_unmap; - - hose = pci_bus_to_pci_controller(pdev->bus); - if (!hose || !(hose->iommu_enable)) - goto out_unmap; - - sdev = dev_iommu_priv_get(dev); - if (sdev->passthrough) - goto out_unmap; - - sdomain = get_sunway_domain(dev); - dma_dom = to_dma_domain(sdomain); - __sunway_unmap_single(dma_dom, dma_addr, size); - goto out_free; - -out_unmap: - pci_unmap_single(pdev, dma_addr, size, PCI_DMA_BIDIRECTIONAL); - -out_free: - pr_debug("sunway_free_consistent: [%llx,%zx] from %ps\n", - dma_addr, size, __builtin_return_address(0)); - - free_pages((unsigned long)vaddr, get_order(size)); -} - -static dma_addr_t -sunway_map_page(struct device *dev, struct page *page, - unsigned long offset, size_t size, - enum dma_data_direction dir, unsigned long attrs) -{ - struct pci_dev *pdev = to_pci_dev(dev); - struct sunway_iommu_domain *sdomain; - struct dma_domain *dma_dom; - struct pci_controller *hose; - struct sunway_iommu_dev *sdev; - phys_addr_t paddr = page_to_phys(page) + offset; - - if (dir == PCI_DMA_NONE) - BUG(); - - if (!pdev) - return 0; - - hose = pci_bus_to_pci_controller(pdev->bus); - if (!hose || !(hose->iommu_enable)) - return paddr; - - sdev = dev_iommu_priv_get(dev); - if (sdev->passthrough & DMA_MASK64) - return paddr; - else if (sdev->passthrough) { - if (min_not_zero(*dev->dma_mask, dev->coherent_dma_mask) - > DMA_BIT_MASK(32)) { - sdev->passthrough |= DMA_MASK64; - return paddr; - } - - set_dma_ops(dev, get_arch_dma_ops(dev->bus)); - return dev->dma_ops->map_page(dev, page, offset, - size, dir, attrs); - } - - sdomain = get_sunway_domain(dev); - dma_dom = to_dma_domain(sdomain); - - return pci_iommu_map_single(pdev, dma_dom, - (char *)page_address(page) + offset, size); -} - -static void -sunway_unmap_page(struct device *dev, dma_addr_t dma_addr, - size_t size, enum dma_data_direction dir, unsigned long attrs) -{ - struct sunway_iommu_domain *sdomain; - struct dma_domain *dma_dom; - struct pci_dev *pdev; - struct pci_controller *hose; - struct sunway_iommu_dev *sdev; - - pdev = to_pci_dev(dev); - if (!pdev) - return; - - hose = pci_bus_to_pci_controller(pdev->bus); - if (hose == NULL) - return; - - if (!hose->iommu_enable) - return; - - sdev = dev_iommu_priv_get(dev); - if (sdev->passthrough) - return; - - sdomain = get_sunway_domain(dev); - dma_dom = to_dma_domain(sdomain); - __sunway_unmap_single(dma_dom, dma_addr, size); -} - -#define SG_ENT_VIRT_ADDRESS(SG) (sg_virt((SG))) -static int -sunway_map_sg(struct device *dev, struct scatterlist *sgl, - int nents, enum dma_data_direction dir, unsigned long attrs) -{ - struct sunway_iommu_domain *sdomain; - struct dma_domain *dma_dom = NULL; - struct scatterlist *sg; - struct pci_dev *pdev = to_pci_dev(dev); - struct pci_controller *hose; - struct sunway_iommu_dev *sdev; - int i, out_nents = 0; - - if (dir == PCI_DMA_NONE) - BUG(); - - if (!pdev) - return 0; - - hose = pci_bus_to_pci_controller(pdev->bus); - if (!hose) - return 0; - - sdomain = get_sunway_domain(dev); - dma_dom = to_dma_domain(sdomain); - - for_each_sg(sgl, sg, nents, i) { - BUG_ON(!sg_page(sg)); - - sg_dma_address(sg) = __pa(SG_ENT_VIRT_ADDRESS(sg)); - if (!(hose->iommu_enable)) - goto check; - - sdev = dev_iommu_priv_get(dev); - if (sdev->passthrough & DMA_MASK64) - goto check; - else if (sdev->passthrough) { - if (min_not_zero(*dev->dma_mask, dev->coherent_dma_mask) - > DMA_BIT_MASK(32)) { - sdev->passthrough |= DMA_MASK64; - goto check; - } - - set_dma_ops(dev, get_arch_dma_ops(dev->bus)); - return dev->dma_ops->map_sg(dev, sgl, nents, - dir, attrs); - } - - sg_dma_address(sg) = - pci_iommu_map_single(pdev, dma_dom, - SG_ENT_VIRT_ADDRESS(sg), sg->length); -check: - if (sg_dma_address(sg) == 0) - goto error; - - sg_dma_len(sg) = sg->length; - out_nents++; - } - - return nents; - -error: - pr_warn("pci_map_sg failed:"); - pr_warn("could not allocate dma page tables\n"); - - if (out_nents) - pci_unmap_sg(pdev, sgl, out_nents, dir); - return 0; -} - -static void -sunway_unmap_sg(struct device *dev, struct scatterlist *sgl, - int nents, enum dma_data_direction dir, unsigned long attrs) -{ - struct sunway_iommu_domain *sdomain; - struct dma_domain *dma_dom; - struct scatterlist *sg; - struct pci_dev *pdev; - struct pci_controller *hose; - struct sunway_iommu_dev *sdev; - dma_addr_t dma_addr; - long size; - int j; - - pdev = to_pci_dev(dev); - if (!pdev) - return; - - hose = pci_bus_to_pci_controller(pdev->bus); - if (!hose->iommu_enable) - return; - - sdev = dev_iommu_priv_get(dev); - if (sdev->passthrough) - return; - - sdomain = get_sunway_domain(dev); - dma_dom = to_dma_domain(sdomain); - - for_each_sg(sgl, sg, nents, j) { - dma_addr = sg->dma_address; - size = sg->dma_length; - if (!size) - break; - - __sunway_unmap_single(dma_dom, dma_addr, size); - } -} - -static const struct dma_map_ops sunway_dma_ops = { - .alloc = sunway_alloc_coherent, - .free = sunway_free_coherent, - .map_sg = sunway_map_sg, - .unmap_sg = sunway_unmap_sg, - .map_page = sunway_map_page, - .unmap_page = sunway_unmap_page, - .dma_supported = dma_direct_supported, -}; - /********************************************************************** * * IOMMU OPS Functions @@ -1346,6 +911,8 @@ static struct iommu_domain *sunway_iommu_domain_alloc(unsigned type) } sdomain = &dma_dom->sdomain; + if (iommu_get_dma_cookie(&sdomain->domain) == -ENOMEM) + return NULL; break; case IOMMU_DOMAIN_IDENTITY: @@ -1655,7 +1222,7 @@ static void sunway_iommu_probe_finalize(struct device *dev) domain = iommu_get_domain_for_dev(dev); if (domain) - set_dma_ops(dev, &sunway_dma_ops); + iommu_setup_dma_ops(dev, SW64_DMA_START, SW64_DMA_LIMIT); } const struct iommu_ops sunway_iommu_ops = { -- Gitee From b4e2cafb526b1d26be2f91a381a731998dddd415 Mon Sep 17 00:00:00 2001 From: Gu Zitao Date: Wed, 24 Jan 2024 15:56:10 +0800 Subject: [PATCH 04/49] anolis: sw64: fix dtb address validity check ANBZ: #4688 Call __boot_pa() to keep compatible with old firmware. Signed-off-by: Gu Zitao Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/kernel/setup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/sw_64/kernel/setup.c b/arch/sw_64/kernel/setup.c index 28e1c0f61c25..eacd6a65595f 100644 --- a/arch/sw_64/kernel/setup.c +++ b/arch/sw_64/kernel/setup.c @@ -594,7 +594,7 @@ static void __init setup_machine_fdt(void) } } - if (!phys_addr_valid(virt_to_phys(dt_virt)) || + if (!phys_addr_valid(__boot_pa(dt_virt)) || !early_init_dt_scan(dt_virt)) { pr_crit("\n" "Error: invalid device tree blob at virtual address %px\n" -- Gitee From 20a01b29c1eca58b45a8b3f8325a4ea7e671f9a7 Mon Sep 17 00:00:00 2001 From: Yan Bo Date: Wed, 21 Feb 2024 16:35:15 +0000 Subject: [PATCH 05/49] anolis: sw64: iommu: remove unnecessary locking for sunway iommu driver ANBZ: #4688 We encounter a `scheduling while atomic` bug when using an nvme ssd or mellanox card . This bug is caused by locks in sunway_iommu_map and sunway_iommu_unmap. This patch removes these locks to fix it. Detailed in commit 37ec8eb851c1 ("iommu/amd: Remove unnecessary locking from AMD iommu driver"). Signed-off-by: Yan Bo Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- drivers/iommu/sw64/sunway_iommu.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/iommu/sw64/sunway_iommu.c b/drivers/iommu/sw64/sunway_iommu.c index a1b593109407..f13215bbaa32 100644 --- a/drivers/iommu/sw64/sunway_iommu.c +++ b/drivers/iommu/sw64/sunway_iommu.c @@ -242,7 +242,6 @@ static u16 sunway_domain_id_alloc(void) static int sunway_domain_init(struct sunway_iommu_domain *sdomain) { spin_lock_init(&sdomain->lock); - mutex_init(&sdomain->api_lock); sdomain->id = sunway_domain_id_alloc(); if (!sdomain->id) return -ENOMEM; @@ -1073,9 +1072,7 @@ sunway_iommu_map(struct iommu_domain *dom, unsigned long iova, if (iova >= SW64_BAR_ADDRESS) return 0; - mutex_lock(&sdomain->api_lock); ret = sunway_iommu_map_page(sdomain, iova, paddr, page_size); - mutex_unlock(&sdomain->api_lock); return ret; } @@ -1091,9 +1088,7 @@ sunway_iommu_unmap(struct iommu_domain *dom, unsigned long iova, if (iova >= SW64_BAR_ADDRESS) return page_size; - mutex_lock(&sdomain->api_lock); unmap_size = sunway_iommu_unmap_page(sdomain, iova, page_size); - mutex_unlock(&sdomain->api_lock); return unmap_size; } -- Gitee From 8c9571138c8c1cf578e130e0ebb015d8096ac332 Mon Sep 17 00:00:00 2001 From: Xu Yiwei Date: Mon, 4 Mar 2024 15:48:48 +0000 Subject: [PATCH 06/49] anolis: sw64: iommu: rename sunway iommu filenames ANBZ: #4688 Remove 'sunway' suffix in iommu filenames since they have already located in sw64 directory. Signed-off-by: Xu Yiwei Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- drivers/iommu/sw64/Makefile | 4 ++-- drivers/iommu/sw64/{sunway_iommu.c => iommu.c} | 0 drivers/iommu/sw64/{sunway_iommu_v2.c => iommu_v2.c} | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename drivers/iommu/sw64/{sunway_iommu.c => iommu.c} (100%) rename drivers/iommu/sw64/{sunway_iommu_v2.c => iommu_v2.c} (100%) diff --git a/drivers/iommu/sw64/Makefile b/drivers/iommu/sw64/Makefile index da7a604f253c..e61b343490aa 100644 --- a/drivers/iommu/sw64/Makefile +++ b/drivers/iommu/sw64/Makefile @@ -1,3 +1,3 @@ # SPDX-License-Identifier: GPL-2.0-only -obj-$(CONFIG_SUNWAY_IOMMU) += sunway_iommu.o -obj-$(CONFIG_SUNWAY_IOMMU_V2) += sunway_iommu_v2.o +obj-$(CONFIG_SUNWAY_IOMMU) += iommu.o +obj-$(CONFIG_SUNWAY_IOMMU_V2) += iommu_v2.o diff --git a/drivers/iommu/sw64/sunway_iommu.c b/drivers/iommu/sw64/iommu.c similarity index 100% rename from drivers/iommu/sw64/sunway_iommu.c rename to drivers/iommu/sw64/iommu.c diff --git a/drivers/iommu/sw64/sunway_iommu_v2.c b/drivers/iommu/sw64/iommu_v2.c similarity index 100% rename from drivers/iommu/sw64/sunway_iommu_v2.c rename to drivers/iommu/sw64/iommu_v2.c -- Gitee From 26bf319fcffa0005287a5dea40ef75a732296543 Mon Sep 17 00:00:00 2001 From: Xu Yiwei Date: Mon, 4 Mar 2024 16:02:50 +0000 Subject: [PATCH 07/49] anolis: sw64: iommu: fix group allocation semantics ANBZ: #4688 The current implementation of our IOMMU device-group allocation strategy is not consistent with its semantics. It only happens because of another misunderstanding of which devices are allowed to be added into the IOMMU device initiation process. The fix mainly changes the allocation strategy to a more appropriate one. Also, it allows bridges and root ports to be added as IOMMU managed devices again. Signed-off-by: Xu Yiwei Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- drivers/iommu/sw64/iommu.c | 13 ++++++------- drivers/iommu/sw64/iommu_v2.c | 8 +------- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/drivers/iommu/sw64/iommu.c b/drivers/iommu/sw64/iommu.c index f13215bbaa32..9b5e3d18bd5d 100644 --- a/drivers/iommu/sw64/iommu.c +++ b/drivers/iommu/sw64/iommu.c @@ -1095,7 +1095,12 @@ sunway_iommu_unmap(struct iommu_domain *dom, unsigned long iova, static struct iommu_group *sunway_iommu_device_group(struct device *dev) { - return pci_device_group(dev); + /* + * As sw64 requires all DMA transactions to go through RC right now, + * there is no need to consider group isolation yet. Thus, we decide + * to use the one device/function per group strategy here. + */ + return generic_device_group(dev); } static int iommu_init_device(struct device *dev) @@ -1165,12 +1170,6 @@ static struct iommu_device *sunway_iommu_probe_device(struct device *dev) if (!pdev) return ERR_PTR(-ENODEV); - if (pdev->hdr_type == PCI_HEADER_TYPE_BRIDGE) - return ERR_PTR(-ENODEV); - - if (pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT) - return ERR_PTR(-ENODEV); - hose = pci_bus_to_pci_controller(pdev->bus); if (!hose) return ERR_PTR(-ENODEV); diff --git a/drivers/iommu/sw64/iommu_v2.c b/drivers/iommu/sw64/iommu_v2.c index de862462be37..c3714a57b609 100644 --- a/drivers/iommu/sw64/iommu_v2.c +++ b/drivers/iommu/sw64/iommu_v2.c @@ -1596,7 +1596,7 @@ sunway_iommu_unmap(struct iommu_domain *dom, unsigned long iova, static struct iommu_group *sunway_iommu_device_group(struct device *dev) { - return pci_device_group(dev); + return generic_device_group(dev); } static void iommu_uninit_device(struct device *dev) @@ -1666,12 +1666,6 @@ static struct iommu_device *sunway_iommu_probe_device(struct device *dev) if (!pdev) return ERR_PTR(-ENODEV); - if (pdev->hdr_type == PCI_HEADER_TYPE_BRIDGE) - return ERR_PTR(-ENODEV); - - if (pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT) - return ERR_PTR(-ENODEV); - hose = pci_bus_to_pci_controller(pdev->bus); if (!hose) return ERR_PTR(-ENODEV); -- Gitee From 39eb22659576811be67f6ba827756cdcd6b8b2fb Mon Sep 17 00:00:00 2001 From: Xu Yiwei Date: Mon, 4 Mar 2024 17:06:36 +0000 Subject: [PATCH 08/49] anolis: sw64: iommu: recognize potential multiple aliases for devices ANBZ: #4688 A device may use an alias as its DMA requester ID under certain circumstances, which has caused failed DMA and unexpected IOMMU interrupts since the device table only registered its own PCI ID. We implement a recognition system for DMA aliases to fix this. The device table will now register the device's PCI ID and alias together when setting entries, so DMA can walk into the correct page tables. Signed-off-by: Xu Yiwei Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- drivers/iommu/sw64/iommu.c | 104 ++++++++++++++++++++++++++++------ drivers/iommu/sw64/iommu_v2.c | 93 ++++++++++++++++++++++++------ 2 files changed, 164 insertions(+), 33 deletions(-) diff --git a/drivers/iommu/sw64/iommu.c b/drivers/iommu/sw64/iommu.c index 9b5e3d18bd5d..d872ceb9de5a 100644 --- a/drivers/iommu/sw64/iommu.c +++ b/drivers/iommu/sw64/iommu.c @@ -81,6 +81,21 @@ struct dma_domain { const struct iommu_ops sunway_iommu_ops; static const struct dma_map_ops sunway_dma_ops; +static int __last_alias(struct pci_dev *pdev, u16 alias, void *data) +{ + *(u16 *)data = alias; + return 0; +} + +static int get_alias(struct pci_dev *pdev) +{ + u16 pci_alias; + + /* As far as I know, few devices are using more than 2 aliases. */ + pci_for_each_dma_alias(pdev, __last_alias, &pci_alias); + + return pci_alias; +} /* flush helpers */ static void piu_flush_all(struct pci_controller *hose) @@ -125,15 +140,28 @@ void flush_ptlb_by_addr(struct sunway_iommu_domain *sdomain, struct pci_controller *hose; struct pci_dev *pdev; struct sunway_iommu_dev *sdev_data; + unsigned long address; + u16 alias, bus_number, devfn; list_for_each_entry(sdev_data, &sdomain->dev_list, list) { pdev = sdev_data->pdev; hose = pci_bus_to_pci_controller(pdev->bus); - flush_addr = (pdev->bus->number << 8) + address = (pdev->bus->number << 8) | pdev->devfn | (flush_addr << 16); write_piu_ior0(hose->node, hose->index, PTLB_FLUSHVADDR, flush_addr); + + if (sdev_data->alias != sdev_data->devid) { + alias = sdev_data->alias; + bus_number = PCI_BUS_NUM(alias); + devfn = PCI_SLOT(alias) | PCI_FUNC(alias); + + address = (bus_number << 8) + | devfn | (flush_addr << 16); + write_piu_ior0(hose->node, hose->index, + PTLB_FLUSHVADDR, flush_addr); + } } } @@ -297,44 +325,80 @@ static void device_flush_all(struct sunway_iommu_dev *sdata) write_piu_ior0(hose->node, hose->index, DTLB_FLUSHDEV, sdata->devid); write_piu_ior0(hose->node, hose->index, PTLB_FLUSHDEV, sdata->devid); write_piu_ior0(hose->node, hose->index, PCACHE_FLUSHDEV, sdata->devid); + + if (sdata->devid != sdata->alias) { + write_piu_ior0(hose->node, hose->index, DTLB_FLUSHDEV, sdata->alias); + write_piu_ior0(hose->node, hose->index, PTLB_FLUSHDEV, sdata->alias); + write_piu_ior0(hose->node, hose->index, PCACHE_FLUSHDEV, sdata->alias); + } } /* iommu_ops device attach/unattach helpers */ -static void -set_dte_entry(struct sunway_iommu_dev *sdev, struct sunway_iommu_domain *sdomain) +static bool +set_entry_by_devid(u16 devid, + struct sunway_iommu_domain *sdomain, + struct sunway_iommu *iommu) { - struct sunway_iommu *iommu; - struct pci_dev *pdev; - struct page *page; + struct page *dt_page, *pt_page; unsigned long *dte_l1, *dte_l2; unsigned long dte_l1_val, dte_l2_base, dte_l2_val; + u16 bus_number, devfn; - pdev = sdev->pdev; - if (pdev->hdr_type == PCI_HEADER_TYPE_BRIDGE) - return; + bus_number = PCI_BUS_NUM(devid); + devfn = PCI_SLOT(devid) | PCI_FUNC(devid); - sdev->devid = PCI_DEVID(pdev->bus->number, pdev->devfn); - iommu = sdev->iommu; - dte_l1 = iommu->iommu_dtbr + (pdev->bus->number); + dte_l1 = iommu->iommu_dtbr + bus_number; dte_l1_val = *dte_l1; if (!dte_l1_val) { /* Alloc a new level-2 device table page */ - page = alloc_pages_node(iommu->node, __GFP_ZERO, + dt_page = alloc_pages_node(iommu->node, GFP_KERNEL | __GFP_ZERO, get_order(PAGE_SIZE)); - dte_l2_base = (unsigned long)page_address(page); + + WARN_ON(!dt_page); + dte_l2_base = (unsigned long)page_address(dt_page); dte_l1_val = (__pa(dte_l2_base) & PAGE_MASK) | SW64_IOMMU_ENTRY_VALID; *dte_l1 = dte_l1_val; } - dte_l2 = __va(dte_l1_val & ~(SW64_IOMMU_ENTRY_VALID) & PAGE_MASK) + (pdev->devfn << 3); - BUG_ON(!sdomain->pt_root); + if (!sdomain->pt_root) { + pt_page = alloc_pages_node(iommu->node, GFP_KERNEL | __GFP_ZERO, 0); + WARN_ON(!pt_page); + sdomain->pt_root = page_address(pt_page); + } + + dte_l2 = __va(dte_l1_val & ~(SW64_IOMMU_ENTRY_VALID) & PAGE_MASK) + (devfn << 3); dte_l2_val = (__pa(sdomain->pt_root) & PAGE_MASK) | SW64_IOMMU_ENTRY_VALID; if (sdomain->type == IOMMU_DOMAIN_IDENTITY) { dte_l2_val |= 0x1; - sdev->passthrough = IDENTMAP_ALL; + *dte_l2 = dte_l2_val; + return true; } + *dte_l2 = dte_l2_val; + pr_debug("iommu: device with id %d added to domain: %d\n", devid, sdomain->id); + + return false; +} + +static void +set_dte_entry(struct sunway_iommu_dev *sdev, struct sunway_iommu_domain *sdomain) +{ + struct sunway_iommu *iommu; + struct pci_dev *pdev; + bool is_identity; + + pdev = sdev->pdev; + if (pdev->hdr_type == PCI_HEADER_TYPE_BRIDGE) + return; + + iommu = sdev->iommu; + is_identity = set_entry_by_devid(sdev->devid, sdomain, iommu); + if (sdev->devid != sdev->alias) + is_identity = set_entry_by_devid(sdev->alias, sdomain, iommu); + + if (is_identity) + sdev->passthrough = IDENTMAP_ALL; device_flush_all(sdev); } @@ -1118,6 +1182,9 @@ static int iommu_init_device(struct device *dev) return -ENOMEM; pdev = to_pci_dev(dev); + sdev->devid = PCI_DEVID(pdev->bus->number, pdev->devfn); + sdev->alias = get_alias(pdev); + hose = pci_bus_to_pci_controller(pdev->bus); iommu = hose->pci_iommu; llist_add(&sdev->dev_data_list, &dev_data_list); @@ -1166,6 +1233,9 @@ static struct iommu_device *sunway_iommu_probe_device(struct device *dev) struct sunway_iommu *iommu; int ret; + if (!dev_is_pci(dev)) + return 0; + pdev = to_pci_dev(dev); if (!pdev) return ERR_PTR(-ENODEV); diff --git a/drivers/iommu/sw64/iommu_v2.c b/drivers/iommu/sw64/iommu_v2.c index c3714a57b609..94aded8297cb 100644 --- a/drivers/iommu/sw64/iommu_v2.c +++ b/drivers/iommu/sw64/iommu_v2.c @@ -95,6 +95,20 @@ struct dma_domain { const struct iommu_ops sunway_iommu_ops; static const struct dma_map_ops sunway_dma_ops; +static int __last_alias(struct pci_dev *pdev, u16 alias, void *data) +{ + *(u16 *)data = alias; + return 0; +} + +static int get_alias(struct pci_dev *pdev) +{ + u16 pci_alias; + + pci_for_each_dma_alias(pdev, __last_alias, &pci_alias); + + return pci_alias; +} /* flush helpers */ static void piu_flush_all(struct pci_controller *hose) @@ -113,8 +127,6 @@ void flush_pcache_by_addr(struct sunway_iommu_domain *sdomain, unsigned long flu hose = pci_bus_to_pci_controller(sdev->pdev->bus); flush_addr = __pa(flush_addr); - /* Set memory bar here */ - mb(); write_piu_ior0(hose->node, hose->index, PCACHE_FLUSHPADDR, flush_addr); } @@ -125,15 +137,28 @@ void flush_ptlb_by_addr(struct sunway_iommu_domain *sdomain, unsigned long flush struct pci_controller *hose; struct sunway_iommu_dev *sdev; struct pci_dev *pdev; + unsigned long address; + u16 alias, bus_number, devfn; list_for_each_entry(sdev, &sdomain->dev_list, list) { pdev = sdev->pdev; hose = pci_bus_to_pci_controller(pdev->bus); - flush_addr = (pdev->bus->number << 8) + address = (pdev->bus->number << 8) | pdev->devfn | (flush_addr << 16); write_piu_ior0(hose->node, hose->index, PTLB_FLUSHVADDR, flush_addr); + + if (sdev_data->alias != sdev_data->devid) { + alias = sdev_data->alias; + bus_number = PCI_BUS_NUM(alias); + devfn = PCI_SLOT(alias) | PCI_FUNC(alias); + + address = (bus_number << 8) + | devfn | (flush_addr << 16); + write_piu_ior0(hose->node, hose->index, + PTLB_FLUSHVADDR, address); + } } } @@ -307,25 +332,29 @@ static void device_flush_all(struct sunway_iommu_dev *sdata) write_piu_ior0(hose->node, hose->index, DTLB_FLUSHDEV, sdata->devid); write_piu_ior0(hose->node, hose->index, PTLB_FLUSHDEV, sdata->devid); write_piu_ior0(hose->node, hose->index, PCACHE_FLUSHDEV, sdata->devid); + + if (sdata->devid != sdata->alias) { + write_piu_ior0(hose->node, hose->index, DTLB_FLUSHDEV, sdata->alias); + write_piu_ior0(hose->node, hose->index, PTLB_FLUSHDEV, sdata->alias); + write_piu_ior0(hose->node, hose->index, PCACHE_FLUSHDEV, sdata->alias); + } } /* iommu_ops device attach/unattach helpers */ -static void -set_dte_entry(struct sunway_iommu_dev *sdev, struct sunway_iommu_domain *sdomain) + +static bool set_entry_by_devid(u16 devid, + struct sunway_iommu_domain *sdomain, + struct sunway_iommu *iommu) { - struct sunway_iommu *iommu; - struct pci_dev *pdev; struct page *dt_page, *pt_page; unsigned long *dte_l1, *dte_l2; unsigned long dte_l1_val, dte_l2_base, dte_l2_val; + u16 bus_number, devfn; - pdev = sdev->pdev; - if (pdev->hdr_type == PCI_HEADER_TYPE_BRIDGE) - return; + bus_number = PCI_BUS_NUM(devid); + devfn = PCI_SLOT(devid) | PCI_FUNC(devid); - sdev->devid = PCI_DEVID(pdev->bus->number, pdev->devfn); - iommu = sdev->iommu; - dte_l1 = iommu->iommu_dtbr + (pdev->bus->number); + dte_l1 = iommu->iommu_dtbr + bus_number; dte_l1_val = *dte_l1; if (!dte_l1_val) { @@ -345,13 +374,39 @@ set_dte_entry(struct sunway_iommu_dev *sdev, struct sunway_iommu_domain *sdomain sdomain->pt_root = page_address(pt_page); } - dte_l2 = __va(dte_l1_val & ~(SW64_IOMMU_ENTRY_VALID) & PAGE_MASK) + (pdev->devfn << 3); + dte_l2 = __va(dte_l1_val & ~(SW64_IOMMU_ENTRY_VALID) & PAGE_MASK) + (devfn << 3); dte_l2_val = (__pa(sdomain->pt_root) & PAGE_MASK) | SW64_IOMMU_ENTRY_VALID; if (sdomain->type == IOMMU_DOMAIN_IDENTITY) { dte_l2_val |= 0x1; - sdev->passthrough = IDENTMAP_ALL; + *dte_l2 = dte_l2_val; + return true; } + *dte_l2 = dte_l2_val; + pr_debug("iommu: device with id %d added to domain: %d\n", devid, sdomain->id); + + return false; +} + +static void +set_dte_entry(struct sunway_iommu_dev *sdev, struct sunway_iommu_domain *sdomain) +{ + struct sunway_iommu *iommu; + struct pci_dev *pdev; + bool is_identity; + + pdev = sdev->pdev; + if (pdev->hdr_type == PCI_HEADER_TYPE_BRIDGE) + return; + + iommu = sdev->iommu; + is_identity = set_entry_by_devid(sdev->devid, sdomain, iommu); + if (sdev->devid != sdev->alias) + is_identity = set_entry_by_devid(sdev->alias, sdomain, iommu); + + if (is_identity) + sdev->passthrough = IDENTMAP_ALL; + device_flush_all(sdev); } @@ -1373,7 +1428,7 @@ static struct iommu_domain *sunway_iommu_domain_alloc(unsigned int type) sdomain->domain.geometry.aperture_start = 0UL; sdomain->domain.geometry.aperture_end = ~0ULL; - sdomain->domain.geometry.force_aperture = true; + sdomain->domain.geometry.force_aperture = true; sdomain->type = IOMMU_DOMAIN_UNMANAGED; break; @@ -1644,6 +1699,9 @@ static int iommu_init_device(struct device *dev) return -ENOMEM; pdev = to_pci_dev(dev); + sdev_data->devid = PCI_DEVID(pdev->bus->number, pdev->devfn); + sdev_data->alias = get_alias(pdev); + hose = pci_bus_to_pci_controller(pdev->bus); iommu = hose->pci_iommu; llist_add(&sdev->dev_data_list, &dev_data_list); @@ -1662,6 +1720,9 @@ static struct iommu_device *sunway_iommu_probe_device(struct device *dev) struct sunway_iommu *iommu; int ret; + if (!dev_is_pci(dev)) + return 0; + pdev = to_pci_dev(dev); if (!pdev) return ERR_PTR(-ENODEV); -- Gitee From c5028d6263755cc8f23b8bea8d4b54483aecad82 Mon Sep 17 00:00:00 2001 From: Xu Yiwei Date: Tue, 5 Mar 2024 10:37:07 +0000 Subject: [PATCH 09/49] anolis: sw64: iommu: add default DMA ops for passthrough domains ANBZ: #4688 After switching to generic DMA ops implementation, we missed the original way of setting identity domain's DMA ops. This commit adds direct DMA ops back to support passthrough devices. Signed-off-by: Xu Yiwei Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- drivers/iommu/sw64/iommu.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/iommu/sw64/iommu.c b/drivers/iommu/sw64/iommu.c index d872ceb9de5a..ad037e5a219b 100644 --- a/drivers/iommu/sw64/iommu.c +++ b/drivers/iommu/sw64/iommu.c @@ -1285,8 +1285,10 @@ static void sunway_iommu_probe_finalize(struct device *dev) struct iommu_domain *domain; domain = iommu_get_domain_for_dev(dev); - if (domain) + if (domain->type == IOMMU_DOMAIN_DMA) iommu_setup_dma_ops(dev, SW64_DMA_START, SW64_DMA_LIMIT); + else + set_dma_ops(dev, get_arch_dma_ops(dev->bus)); } const struct iommu_ops sunway_iommu_ops = { -- Gitee From 62dd922d0b7a3245d8a954841aa98bd6d5b07202 Mon Sep 17 00:00:00 2001 From: Zheng Chongzhen Date: Thu, 10 Aug 2023 10:30:56 +0800 Subject: [PATCH 10/49] anolis: sw64: msi: make vector_irq_t and sw64_msi_chip_data cache line aligned ANBZ: #4688 This may improve the performance of msi interrupt handling. Signed-off-by: Zheng Chongzhen Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/include/asm/hw_irq.h | 2 +- arch/sw_64/include/asm/msi.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/sw_64/include/asm/hw_irq.h b/arch/sw_64/include/asm/hw_irq.h index 3cfc725f7517..2988d2a81a70 100644 --- a/arch/sw_64/include/asm/hw_irq.h +++ b/arch/sw_64/include/asm/hw_irq.h @@ -10,7 +10,7 @@ DECLARE_PER_CPU(unsigned long, irq_pmi_count); #define ACTUAL_NR_IRQS NR_IRQS #ifdef CONFIG_PCI_MSI -typedef unsigned int vector_irq_t[PERCPU_MSI_IRQS]; +typedef unsigned int vector_irq_t[PERCPU_MSI_IRQS] ____cacheline_aligned; DECLARE_PER_CPU(vector_irq_t, vector_irq); #endif #endif /* _ASM_SW64_HW_IRQ_H */ diff --git a/arch/sw_64/include/asm/msi.h b/arch/sw_64/include/asm/msi.h index e378326b6754..ce3edf7de803 100644 --- a/arch/sw_64/include/asm/msi.h +++ b/arch/sw_64/include/asm/msi.h @@ -58,7 +58,7 @@ struct sw64_msi_chip_data { unsigned int prev_vector; unsigned int multi_msi; bool move_in_progress; -}; +} ____cacheline_aligned; static inline int rcid_to_msicid(int rcid) { -- Gitee From e1247fea476ef8ed14f25dedeb7da36815a8e482 Mon Sep 17 00:00:00 2001 From: Zhou Xuemei Date: Tue, 15 Aug 2023 02:07:56 +0000 Subject: [PATCH 11/49] anolis: USB: Fix ehci infinite suspend-resume loop issue in zhaoxin ANBZ: #4688 commit f085bd4bfe0907ce2fad2c787fc65871ec5ca6d6 upstream. In zhaoxin platform, some ehci projects will latch a wakeup signal internal when plug in a device on port during system S0. This wakeup signal will turn on when ehci runtime suspend, which will trigger a system control interrupt that will resume ehci back to D0. As no device connect, ehci will be set to runtime suspend and turn on the internal latched wakeup signal again. It will cause a suspend-resume loop and generate system control interrupt continuously. Fixed this issue by clear wakeup signal latched in ehci internal when ehci resume callback is called. Signed-off-by: Zhou Xuemei Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- drivers/usb/host/ehci-hcd.c | 23 +++++++++++++++++++++++ drivers/usb/host/ehci-pci.c | 4 ++++ drivers/usb/host/ehci.h | 1 + 3 files changed, 28 insertions(+) diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 8aff19ff8e8f..2588706c7273 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -1109,6 +1109,26 @@ static void ehci_remove_device(struct usb_hcd *hcd, struct usb_device *udev) #ifdef CONFIG_PM +/* Clear wakeup signal locked in zhaoxin platform when device plug in. */ +static void ehci_zx_wakeup_clear(struct ehci_hcd *ehci) +{ + u32 __iomem *reg = &ehci->regs->port_status[4]; + u32 t1 = ehci_readl(ehci, reg); + + t1 &= (u32)~0xf0000; + t1 |= PORT_TEST_FORCE; + ehci_writel(ehci, t1, reg); + t1 = ehci_readl(ehci, reg); + msleep(1); + t1 &= (u32)~0xf0000; + ehci_writel(ehci, t1, reg); + ehci_readl(ehci, reg); + msleep(1); + t1 = ehci_readl(ehci, reg); + ehci_writel(ehci, t1 | PORT_CSC, reg); + ehci_readl(ehci, reg); +} + /* suspend/resume, section 4.3 */ /* These routines handle the generic parts of controller suspend/resume */ @@ -1160,6 +1180,9 @@ int ehci_resume(struct usb_hcd *hcd, bool force_reset) if (ehci->shutdown) return 0; /* Controller is dead */ + if (ehci->zx_wakeup_clear_needed) + ehci_zx_wakeup_clear(ehci); + /* * If CF is still set and reset isn't forced * then we maintained suspend power. diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index 638f03b89739..9937c5a7efc2 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -231,6 +231,10 @@ static int ehci_pci_setup(struct usb_hcd *hcd) ehci->is_aspeed = 1; } break; + case PCI_VENDOR_ID_ZHAOXIN: + if (pdev->device == 0x3104 && (pdev->revision & 0xf0) == 0x90) + ehci->zx_wakeup_clear_needed = 1; + break; } /* optional debug port, normally in the first BAR */ diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index 59fd523c55f3..480833c942e7 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -219,6 +219,7 @@ struct ehci_hcd { /* one per controller */ unsigned need_oc_pp_cycle:1; /* MPC834X port power */ unsigned imx28_write_fix:1; /* For Freescale i.MX28 */ unsigned is_aspeed:1; + unsigned zx_wakeup_clear_needed:1; /* required for usb32 quirk */ #define OHCI_CTRL_HCFS (3 << 6) -- Gitee From 8806faecf3d8ba0b907baf582ab8875c8fe14f61 Mon Sep 17 00:00:00 2001 From: Du Yilong Date: Mon, 28 Aug 2023 16:30:47 +0800 Subject: [PATCH 12/49] anolis: sw64: kvm: fix return value of vmem_mmap ANBZ: #4688 The ret is uninitialized and may lead to unexpected result. Signed-off-by: Du Yilong Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/kvm/vmem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/sw_64/kvm/vmem.c b/arch/sw_64/kvm/vmem.c index fa893f5e26a7..24f95521f432 100644 --- a/arch/sw_64/kvm/vmem.c +++ b/arch/sw_64/kvm/vmem.c @@ -144,7 +144,7 @@ static int vmem_mmap(struct file *flip, struct vm_area_struct *vma) /*to do if size bigger than vm_mem_size*/ pr_info("sw64_vmem: vm_start=%#lx, size= %#lx\n", vma->vm_start, size); - vmem_vm_insert_page(vma); + ret = vmem_vm_insert_page(vma); if (ret < 0) return ret; -- Gitee From 9d45285679b16c213e62556e7534aefbeaab4133 Mon Sep 17 00:00:00 2001 From: Zhou Xuemei Date: Wed, 20 Sep 2023 06:01:16 +0000 Subject: [PATCH 13/49] anolis: sw64: pci: reset dma mask for devices on zx200 ANBZ: #4688 Only UHCI and EHCI do not have 64-bit addressing capability, there is no need to set all devices on zx200 with DMA_BIT_MASK(32) except UHCI and EHCI. We set dma ops of UHCI and EHCI to swiotlb_dma_ops when iommu is not enabled. When iommu is enabled, dma ops is managed by iommu. Signed-off-by: Zhou Xuemei Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/pci/pci.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/arch/sw_64/pci/pci.c b/arch/sw_64/pci/pci.c index c20691c10a02..ccdf1cbda373 100644 --- a/arch/sw_64/pci/pci.c +++ b/arch/sw_64/pci/pci.c @@ -219,18 +219,13 @@ static void fixup_root_complex(struct pci_dev *dev) DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_JN, PCI_DEVICE_ID_SW64_ROOT_BRIDGE, fixup_root_complex); -static int setup_bus_dma_cb(struct pci_dev *pdev, void *data) +static void quirk_zx200_dma_mask(struct pci_dev *pdev) { - pdev->dev.bus_dma_limit = DMA_BIT_MASK(32); - return 0; + pr_info("Set ZX200 UHCI & EHCI dma mask to DMA_BIT_MASK(32)\n"); + pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); } - -static void fix_bus_dma_limit(struct pci_dev *dev) -{ - pci_walk_bus(dev->subordinate, setup_bus_dma_cb, NULL); - pr_info("Set zx200 bus_dma_limit to 32-bit\n"); -} -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ZHAOXIN, 0x071f, fix_bus_dma_limit); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ZHAOXIN, 0x3038, quirk_zx200_dma_mask); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ZHAOXIN, 0x3104, quirk_zx200_dma_mask); #ifdef CONFIG_DCA static void enable_sw_dca(struct pci_dev *dev) -- Gitee From cb99953afeb421d46dd12ee041fd73f443533365 Mon Sep 17 00:00:00 2001 From: Zhang Yi Date: Sat, 7 Oct 2023 15:04:51 +0800 Subject: [PATCH 14/49] anolis: sw64: kvm: scale up the range of target vcpu parsed by hypervisor ANBZ: #4688 The range of target vcpu parsed by hypervisor was 0-31 when hypervisor injected msi into guest. It's not always, but it's very likely to cause guest runs slowly when the number of vcpus is more than 32. This patch scales up the range of target vcpu parsed by hypervisor to 0-255. Signed-off-by: Zhang Yi Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/kvm/sw64.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/arch/sw_64/kvm/sw64.c b/arch/sw_64/kvm/sw64.c index 4afa535407b0..4d19714d0542 100644 --- a/arch/sw_64/kvm/sw64.c +++ b/arch/sw_64/kvm/sw64.c @@ -52,19 +52,17 @@ int kvm_arch_check_processor_compat(void *opaque) int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e, struct kvm *kvm, int irq_source_id, int level, bool line_status) { - unsigned int vcid; - unsigned int vcpu_idx; + unsigned int dest_id; struct kvm_vcpu *vcpu = NULL; - int irq = e->msi.data & 0xff; + int vector = e->msi.data & 0xff; - vcid = (e->msi.address_lo & VT_MSIX_ADDR_DEST_ID_MASK) >> VT_MSIX_ADDR_DEST_ID_SHIFT; - vcpu_idx = vcid & 0x1f; - vcpu = kvm_get_vcpu(kvm, vcpu_idx); + dest_id = (e->msi.address_lo & VT_MSIX_ADDR_DEST_ID_MASK) >> VT_MSIX_ADDR_DEST_ID_SHIFT; + vcpu = kvm_get_vcpu(kvm, dest_id); if (!vcpu) return -EINVAL; - return vcpu_interrupt_line(vcpu, irq, true); + return vcpu_interrupt_line(vcpu, vector, true); } void sw64_kvm_switch_vpn(struct kvm_vcpu *vcpu) -- Gitee From 16dd58b0b0413b757526dab4b28a8664f3f67e6d Mon Sep 17 00:00:00 2001 From: Tang Jinyang Date: Sat, 7 Oct 2023 16:40:11 +0800 Subject: [PATCH 15/49] anolis: sw64: add macros for mother board config info ANBZ: #4688 This patch replaces magic constant with macro definitions to improve code readability. Signed-off-by: Tang Jinyang Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/include/asm/setup.h | 5 +++++ arch/sw_64/platform/cpufreq_xuelang.c | 2 +- drivers/clocksource/timer-sw64.c | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/arch/sw_64/include/asm/setup.h b/arch/sw_64/include/asm/setup.h index 384eeba02144..a22e79095fb4 100644 --- a/arch/sw_64/include/asm/setup.h +++ b/arch/sw_64/include/asm/setup.h @@ -38,6 +38,11 @@ #define INITRD_START_OFF (0x10000UL - 0xA100UL) #define INITRD_SIZE_OFF (0x10000UL - 0xA108UL) +/* Motherboard Configuration Tables */ +#define MB_CONFIG_START 0x908000 +#define MB_MCLK (MB_CONFIG_START + 0x1) +#define MB_EXTCLK (MB_CONFIG_START + 0x11) + #ifndef __ASSEMBLY__ #include extern struct boot_params *sunway_boot_params; diff --git a/arch/sw_64/platform/cpufreq_xuelang.c b/arch/sw_64/platform/cpufreq_xuelang.c index 3988d7df08ba..e639fdc34fb9 100644 --- a/arch/sw_64/platform/cpufreq_xuelang.c +++ b/arch/sw_64/platform/cpufreq_xuelang.c @@ -46,7 +46,7 @@ static int __init sw64_cpufreq_init(void) max_rate = get_cpu_freq() / 1000; - external_clk = *((unsigned char *)__va(0x908011)); + external_clk = *((unsigned char *)__va(MB_EXTCLK)); if (external_clk == 240) freq_off = 60000; diff --git a/drivers/clocksource/timer-sw64.c b/drivers/clocksource/timer-sw64.c index 10fab75e449a..01ae2b4655e7 100644 --- a/drivers/clocksource/timer-sw64.c +++ b/drivers/clocksource/timer-sw64.c @@ -126,7 +126,7 @@ static struct clocksource clocksource_tc = { void __init sw64_setup_clocksource(void) { - unsigned int mclk = *((unsigned char *)__va(0x908001)); + unsigned int mclk = *((unsigned char *)__va(MB_MCLK)); if (!mclk) mclk = DEFAULT_MCLK; -- Gitee From bc62cc651a15467c630090a726ca0fe688ad00b6 Mon Sep 17 00:00:00 2001 From: Zhou Xuemei Date: Wed, 25 Oct 2023 07:43:08 +0000 Subject: [PATCH 16/49] anolis: i2c: designware: Do not complete i2c read without RX_FULL interrupt ANBZ: #4688 commit f4e0ba52a89fc2f1b009b3f6af8e617ad1a3c315 upstream. Intel Keem Bay platform supports multi-master operations over same i2c bus using Synopsys i2c DesignWare IP. When multi-masters initiate i2c operation simultaneously in a loop, SCL line is stucked low forever after few i2c operations. Following interrupt sequences are observed in: working case: TX_EMPTY, RX_FULL and STOP_DET non working case: TX_EMPTY, STOP_DET, RX_FULL. DW_apb_i2c stretches the SCL line when the TX FIFO is empty or when RX FIFO is full. The DW_apb_i2c master will continue to hold the SCL line LOW until RX FIFO is read. Linux kernel i2c DesignWare driver does not handle above non working sequence. TX_EMPTY, RX_FULL and STOP_DET routine execution are required in sequence although RX_FULL interrupt is raised after STOP_DET by hardware. Clear STOP_DET for the following conditions: (STOP_DET ,RX_FULL, rx_outstanding) Write Operation: (1, 0, 0) Read Operation: RX_FULL followed by STOP_DET: (0, 1, 1) -> (1, 0, 0) STOP_DET followed by RX_FULL: (1, 0, 1) -> (1, 1, 0) RX_FULL and STOP_DET together: (1, 1, 1) Signed-off-by: Zhou Xuemei Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- drivers/i2c/busses/i2c-designware-master.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c index 873ef38eb1c8..0895560b2c8d 100644 --- a/drivers/i2c/busses/i2c-designware-master.c +++ b/drivers/i2c/busses/i2c-designware-master.c @@ -597,7 +597,9 @@ static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev) regmap_read(dev->map, DW_IC_CLR_RX_DONE, &dummy); if (stat & DW_IC_INTR_ACTIVITY) regmap_read(dev->map, DW_IC_CLR_ACTIVITY, &dummy); - if (stat & DW_IC_INTR_STOP_DET) + if ((stat & DW_IC_INTR_STOP_DET) && + ((dev->rx_outstanding == 0) || + (stat & DW_IC_INTR_RX_FULL))) regmap_read(dev->map, DW_IC_CLR_STOP_DET, &dummy); if (stat & DW_IC_INTR_START_DET) regmap_read(dev->map, DW_IC_CLR_START_DET, &dummy); @@ -619,6 +621,7 @@ static int i2c_dw_irq_handler_master(struct dw_i2c_dev *dev) if (stat & DW_IC_INTR_TX_ABRT) { dev->cmd_err |= DW_IC_ERR_TX_ABRT; dev->status = STATUS_IDLE; + dev->rx_outstanding = 0; /* * Anytime TX_ABRT is set, the contents of the tx/rx @@ -641,7 +644,8 @@ static int i2c_dw_irq_handler_master(struct dw_i2c_dev *dev) */ tx_aborted: - if ((stat & (DW_IC_INTR_TX_ABRT | DW_IC_INTR_STOP_DET)) || dev->msg_err) + if (((stat & (DW_IC_INTR_TX_ABRT | DW_IC_INTR_STOP_DET)) || dev->msg_err) && + (dev->rx_outstanding == 0)) complete(&dev->cmd_complete); else if (unlikely(dev->flags & ACCESS_INTR_MASK)) { /* Workaround to trigger pending interrupt */ -- Gitee From 440b387d2af9cb97d948237c68398bed063e2e01 Mon Sep 17 00:00:00 2001 From: Tang Jinyang Date: Tue, 26 Dec 2023 17:04:43 +0800 Subject: [PATCH 17/49] anolis: sw64: fix macro definition compilation error ANBZ: #4688 Signed-off-by: Tang Jinyang Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/include/asm/csr.h | 34 +++++--- arch/sw_64/kernel/irq_sw64.c | 8 +- arch/sw_64/kernel/match.c | 46 +++++----- arch/sw_64/kernel/ptrace.c | 114 ++++++++++++------------- arch/sw_64/kernel/smp.c | 8 +- arch/sw_64/kernel/vdso/vgettimeofday.c | 2 +- arch/sw_64/kvm/emulate.c | 4 +- arch/sw_64/kvm/kvm_core4.c | 6 +- arch/sw_64/kvm/mmio.c | 2 +- arch/sw_64/kvm/mmu.c | 10 +-- drivers/clocksource/timer-sw64.c | 4 +- 11 files changed, 122 insertions(+), 116 deletions(-) diff --git a/arch/sw_64/include/asm/csr.h b/arch/sw_64/include/asm/csr.h index 0610384208a4..dc400069a771 100644 --- a/arch/sw_64/include/asm/csr.h +++ b/arch/sw_64/include/asm/csr.h @@ -61,30 +61,36 @@ #ifdef CONFIG_HAVE_CSRRW -#define read_csr(x) \ - ({ unsigned long __val; \ - __asm__ __volatile__("csrr %0,%1" : "=r"(__val) : "i"(x)); \ - __val; }) - -#define write_csr(x, y) \ - ({ __asm__ __volatile__("csrw %0,%1" ::"r"(x), "i"(y)); }) +#ifndef __ASSEMBLY__ +static inline unsigned long sw64_read_csr(unsigned long x) +{ + unsigned long __val; + __asm__ __volatile__("csrr %0,%1" : "=r"(__val) : "i"(x)); + return __val; +} -#define write_csr_imb(x, y) \ - ({ __asm__ __volatile__("csrw %0,%1; imemb" ::"r"(x), "i"(y)); }) +static inline void sw64_write_csr(unsigned long x, unsigned long y) +{ + __asm__ __volatile__("csrw %0,%1" ::"r"(x), "i"(y)); +} +static inline void sw64_write_csr_imb(unsigned long x, unsigned long y) +{ + __asm__ __volatile__("csrw %0,%1; imemb" ::"r"(x), "i"(y)); +} -#ifndef __ASSEMBLY__ #include static inline void update_ptbr_sys(unsigned long ptbr) { imemb(); - write_csr_imb(ptbr, CSR_PTBR_SYS); + sw64_write_csr_imb(ptbr, CSR_PTBR_SYS); } + #endif #else -#define read_csr(x) (0) -#define write_csr(x, y) do { } while (0) -#define write_csr_imb(x, y) do { } while (0) +#define sw64_read_csr(x) (0) +#define sw64_write_csr(x, y) do { } while (0) +#define sw64_write_csr_imb(x, y) do { } while (0) #ifndef __ASSEMBLY__ static inline void update_ptbr_sys(unsigned long ptbr) diff --git a/arch/sw_64/kernel/irq_sw64.c b/arch/sw_64/kernel/irq_sw64.c index 989d55ee1b1b..03aef463ec05 100644 --- a/arch/sw_64/kernel/irq_sw64.c +++ b/arch/sw_64/kernel/irq_sw64.c @@ -17,10 +17,10 @@ init_IRQ(void) * (as is the case with RAWHIDE, at least). */ if (is_in_host()) { - write_csr(0xffffffffffffffffUL, CSR_PCIE_MSI0_INTEN); - write_csr(0xffffffffffffffffUL, CSR_PCIE_MSI1_INTEN); - write_csr(0xffffffffffffffffUL, CSR_PCIE_MSI2_INTEN); - write_csr(0xffffffffffffffffUL, CSR_PCIE_MSI3_INTEN); + sw64_write_csr(0xffffffffffffffffUL, CSR_PCIE_MSI0_INTEN); + sw64_write_csr(0xffffffffffffffffUL, CSR_PCIE_MSI1_INTEN); + sw64_write_csr(0xffffffffffffffffUL, CSR_PCIE_MSI2_INTEN); + sw64_write_csr(0xffffffffffffffffUL, CSR_PCIE_MSI3_INTEN); } wrent(entInt, 0); diff --git a/arch/sw_64/kernel/match.c b/arch/sw_64/kernel/match.c index 3926391270da..9ecd5d838846 100644 --- a/arch/sw_64/kernel/match.c +++ b/arch/sw_64/kernel/match.c @@ -97,14 +97,14 @@ write_da_match(void *i) { unsigned long dc_ctl; - write_csr(da_match_cf1, CSR_DA_MATCH); - write_csr(da_match_cf2, CSR_DA_MASK); - dc_ctl = read_csr(CSR_DC_CTLP); + sw64_write_csr(da_match_cf1, CSR_DA_MATCH); + sw64_write_csr(da_match_cf2, CSR_DA_MASK); + dc_ctl = sw64_read_csr(CSR_DC_CTLP); dc_ctl &= ~((0x1UL << 3) | (0x3UL << DA_MATCH_EN_S) | (0x1UL << DAV_MATCH_EN_S) | (0x1UL << DPM_MATCH_EN_S) | (0x3UL << DPM_MATCH)); dc_ctl |= da_match_cf3; - write_csr(dc_ctl, CSR_DC_CTLP); + sw64_write_csr(dc_ctl, CSR_DC_CTLP); } static void @@ -112,13 +112,13 @@ write_dv_match(void *i) { unsigned long dc_ctl; - write_csr(dv_match_cf1, CSR_DV_MATCH); - write_csr(dv_match_cf2, CSR_DV_MASK); - dc_ctl = read_csr(CSR_DC_CTLP); + sw64_write_csr(dv_match_cf1, CSR_DV_MATCH); + sw64_write_csr(dv_match_cf2, CSR_DV_MASK); + dc_ctl = sw64_read_csr(CSR_DC_CTLP); dc_ctl &= ~((0x1UL << DAV_MATCH_EN_S) | (0x1UL << DPM_MATCH_EN_S) | (0x3UL << DPM_MATCH)); dc_ctl |= ((0x1UL << DV_MATCH_EN_S) | dv_match_cf3); - write_csr(dc_ctl, CSR_DC_CTLP); + sw64_write_csr(dc_ctl, CSR_DC_CTLP); } static void @@ -126,26 +126,26 @@ write_dav_match(void *i) { unsigned long dc_ctl; - write_csr(dav_match_cf1, CSR_DA_MATCH); - write_csr(dav_match_cf2, CSR_DA_MASK); - write_csr(dav_match_cf3, CSR_DV_MATCH); - write_csr(dav_match_cf4, CSR_DV_MASK); - dc_ctl = read_csr(CSR_DC_CTLP); + sw64_write_csr(dav_match_cf1, CSR_DA_MATCH); + sw64_write_csr(dav_match_cf2, CSR_DA_MASK); + sw64_write_csr(dav_match_cf3, CSR_DV_MATCH); + sw64_write_csr(dav_match_cf4, CSR_DV_MASK); + dc_ctl = sw64_read_csr(CSR_DC_CTLP); dc_ctl &= ~((0x1UL << 3) | (0x3UL << DA_MATCH_EN_S) | (0x1UL << DPM_MATCH_EN_S) | (0x3UL << DPM_MATCH)); dc_ctl |= ((0x1UL << DV_MATCH_EN_S) | (0x1UL << DAV_MATCH_EN_S) | dav_match_cf5); - write_csr(dc_ctl, CSR_DC_CTLP); + sw64_write_csr(dc_ctl, CSR_DC_CTLP); } static void write_ia_match(void *i) { ia_match_cf1 |= (0x1UL << IA_MATCH_EN_S); - write_csr_imb(ia_match_cf1, CSR_IA_MATCH); - write_csr_imb(ia_match_cf2, CSR_IA_MASK); - write_csr(((0x3ffUL << 18) | ia_match_cf3), CSR_IA_VPNMATCH); - write_csr(((0x3ffUL << 18) | ia_match_cf4), CSR_IA_UPNMATCH); + sw64_write_csr_imb(ia_match_cf1, CSR_IA_MATCH); + sw64_write_csr_imb(ia_match_cf2, CSR_IA_MASK); + sw64_write_csr(((0x3ffUL << 18) | ia_match_cf3), CSR_IA_VPNMATCH); + sw64_write_csr(((0x3ffUL << 18) | ia_match_cf4), CSR_IA_UPNMATCH); } static void @@ -153,12 +153,12 @@ write_iv_match(void *i) { unsigned long ia_match_tmp; - ia_match_tmp = read_csr(CSR_IA_MATCH); + ia_match_tmp = sw64_read_csr(CSR_IA_MATCH); ia_match_tmp &= ~(0x1UL << IV_PM_EN_S); ia_match_tmp |= ((((iv_match_cf2 >> IV_PM_EN_S) & 0x1) << IV_PM_EN_S) | (iv_match_cf2 & 0x3) | (0x1UL << IV_MATCH_EN_S)); - write_csr_imb(iv_match_cf1, CSR_IV_MATCH); - write_csr_imb(ia_match_tmp, CSR_IA_MATCH); + sw64_write_csr_imb(iv_match_cf1, CSR_IV_MATCH); + sw64_write_csr_imb(ia_match_tmp, CSR_IA_MATCH); } static void @@ -166,8 +166,8 @@ write_ida_match(void *i) { ida_match_cf1 |= (0x1UL << IDA_MATCH_EN_S); - write_csr(ida_match_cf1, CSR_IDA_MATCH); - write_csr(ida_match_cf2, CSR_IDA_MASK); + sw64_write_csr(ida_match_cf1, CSR_IDA_MATCH); + sw64_write_csr(ida_match_cf2, CSR_IDA_MASK); } static ssize_t da_match_set(struct file *file, const char __user *user_buf, diff --git a/arch/sw_64/kernel/ptrace.c b/arch/sw_64/kernel/ptrace.c index 1911d5bd058b..9314f4755d72 100644 --- a/arch/sw_64/kernel/ptrace.c +++ b/arch/sw_64/kernel/ptrace.c @@ -547,49 +547,49 @@ int do_match(unsigned long address, unsigned long mmcsr, long cause, struct pt_r if (!(current->ptrace & PT_PTRACED)) { printk(" pid %d %s not be ptraced, return\n", current->pid, current->comm); if (mmcsr == MMCSR__DA_MATCH) { - match_ctl = read_csr(CSR_DC_CTLP); + match_ctl = sw64_read_csr(CSR_DC_CTLP); match_ctl &= ~(0x3UL << DA_MATCH_EN_S); - write_csr(match_ctl, CSR_DC_CTLP); - write_csr(0, CSR_DA_MATCH); // clear da_match + sw64_write_csr(match_ctl, CSR_DC_CTLP); + sw64_write_csr(0, CSR_DA_MATCH); // clear da_match task_thread_info(current)->pcb.match_ctl &= ~0x1; task_thread_info(current)->pcb.da_match = 0; } if (mmcsr == MMCSR__DV_MATCH) { - match_ctl = read_csr(CSR_DC_CTLP); + match_ctl = sw64_read_csr(CSR_DC_CTLP); match_ctl &= ~(0x1UL << DV_MATCH_EN_S); - write_csr(match_ctl, CSR_DC_CTLP); - write_csr(0, CSR_DV_MATCH); // clear dv_match + sw64_write_csr(match_ctl, CSR_DC_CTLP); + sw64_write_csr(0, CSR_DV_MATCH); // clear dv_match task_thread_info(current)->pcb.match_ctl &= ~(0x1 << 1); task_thread_info(current)->pcb.dv_match = 0; } if (mmcsr == MMCSR__DAV_MATCH) { - match_ctl = read_csr(CSR_DC_CTLP); + match_ctl = sw64_read_csr(CSR_DC_CTLP); match_ctl &= ~((0x3UL << DA_MATCH_EN_S) | (0x1UL << DV_MATCH_EN_S) | (0x1UL << DAV_MATCH_EN_S)); - write_csr(match_ctl, CSR_DC_CTLP); - write_csr(0, CSR_DA_MATCH); // clear da_match - write_csr(0, CSR_DV_MATCH); // clear dv_match + sw64_write_csr(match_ctl, CSR_DC_CTLP); + sw64_write_csr(0, CSR_DA_MATCH); // clear da_match + sw64_write_csr(0, CSR_DV_MATCH); // clear dv_match task_thread_info(current)->pcb.match_ctl &= ~(0x1 | (0x1 << 1) | (0x1 << 2)); task_thread_info(current)->pcb.da_match = 0; task_thread_info(current)->pcb.dv_match = 0; } if (mmcsr == MMCSR__IA_MATCH) { - ia_match = read_csr(CSR_IA_MATCH); + ia_match = sw64_read_csr(CSR_IA_MATCH); ia_match &= ~((0x1UL << IA_MATCH_EN_S) | (0x7ffffffffffffUL << 2)); - write_csr(ia_match, CSR_IA_MATCH); // clear ia_match + sw64_write_csr(ia_match, CSR_IA_MATCH); // clear ia_match task_thread_info(current)->pcb.match_ctl &= ~(0x1 << 3); task_thread_info(current)->pcb.ia_match = 0; } if (mmcsr == MMCSR__IV_MATCH) { - ia_match = read_csr(CSR_IA_MATCH); + ia_match = sw64_read_csr(CSR_IA_MATCH); ia_match &= ~((0x1UL << IV_MATCH_EN_S) | (0x1UL << IV_PM_EN_S)); - write_csr(ia_match, CSR_IA_MATCH); // clear ia_match - write_csr(0, CSR_IV_MATCH); // clear iv_match + sw64_write_csr(ia_match, CSR_IA_MATCH); // clear ia_match + sw64_write_csr(0, CSR_IV_MATCH); // clear iv_match task_thread_info(current)->pcb.match_ctl &= ~(0x1 << 4); task_thread_info(current)->pcb.ia_match &= ~((0x1UL << IV_MATCH_EN_S) | (0x1UL << IV_PM_EN_S)); task_thread_info(current)->pcb.iv_match = 0; } if (mmcsr == MMCSR__IDA_MATCH) { - write_csr(0, CSR_IDA_MATCH); // clear ida_match + sw64_write_csr(0, CSR_IDA_MATCH); // clear ida_match task_thread_info(current)->pcb.match_ctl &= ~(0x1 << 5); task_thread_info(current)->pcb.ida_match = 0; } @@ -604,54 +604,54 @@ int do_match(unsigned long address, unsigned long mmcsr, long cause, struct pt_r if (mmcsr == MMCSR__DA_MATCH) { info.si_errno = 1; - match_ctl = read_csr(CSR_DC_CTLP); + match_ctl = sw64_read_csr(CSR_DC_CTLP); match_ctl &= ~(0x3UL << DA_MATCH_EN_S); - write_csr(match_ctl, CSR_DC_CTLP); - write_csr(0, CSR_DA_MATCH); // clear da_match + sw64_write_csr(match_ctl, CSR_DC_CTLP); + sw64_write_csr(0, CSR_DA_MATCH); // clear da_match task_thread_info(current)->pcb.match_ctl &= ~0x1; task_thread_info(current)->pcb.da_match = 0; } if (mmcsr == MMCSR__DV_MATCH) { info.si_errno = 2; - match_ctl = read_csr(CSR_DC_CTLP); + match_ctl = sw64_read_csr(CSR_DC_CTLP); match_ctl &= ~(0x1UL << DV_MATCH_EN_S); - write_csr(match_ctl, CSR_DC_CTLP); - write_csr(0, CSR_DV_MATCH); // clear dv_match + sw64_write_csr(match_ctl, CSR_DC_CTLP); + sw64_write_csr(0, CSR_DV_MATCH); // clear dv_match task_thread_info(current)->pcb.match_ctl &= ~(0x1 << 1); task_thread_info(current)->pcb.dv_match = 0; } if (mmcsr == MMCSR__DAV_MATCH) { info.si_errno = 3; - match_ctl = read_csr(CSR_DC_CTLP); + match_ctl = sw64_read_csr(CSR_DC_CTLP); match_ctl &= ~((0x3UL << DA_MATCH_EN_S) | (0x1UL << DV_MATCH_EN_S) | (0x1UL << DAV_MATCH_EN_S)); - write_csr(match_ctl, CSR_DC_CTLP); - write_csr(0, CSR_DA_MATCH); // clear da_match - write_csr(0, CSR_DV_MATCH); // clear dv_match + sw64_write_csr(match_ctl, CSR_DC_CTLP); + sw64_write_csr(0, CSR_DA_MATCH); // clear da_match + sw64_write_csr(0, CSR_DV_MATCH); // clear dv_match task_thread_info(current)->pcb.match_ctl &= ~(0x1 | (0x1 << 1) | (0x1 << 2)); task_thread_info(current)->pcb.da_match = 0; task_thread_info(current)->pcb.dv_match = 0; } if (mmcsr == MMCSR__IA_MATCH) { info.si_errno = 4; - ia_match = read_csr(CSR_IA_MATCH); + ia_match = sw64_read_csr(CSR_IA_MATCH); ia_match &= ~((0x1UL << IA_MATCH_EN_S) | (0x7ffffffffffffUL << 2)); - write_csr(ia_match, CSR_IA_MATCH); // clear ia_match + sw64_write_csr(ia_match, CSR_IA_MATCH); // clear ia_match task_thread_info(current)->pcb.match_ctl &= ~(0x1 << 3); task_thread_info(current)->pcb.ia_match = 0; } if (mmcsr == MMCSR__IV_MATCH) { info.si_errno = 5; - ia_match = read_csr(CSR_IA_MATCH); + ia_match = sw64_read_csr(CSR_IA_MATCH); ia_match &= ~((0x1UL << IV_MATCH_EN_S) | (0x1UL << IV_PM_EN_S)); - write_csr(ia_match, CSR_IA_MATCH); // clear ia_match - write_csr(0, CSR_IV_MATCH); // clear iv_match + sw64_write_csr(ia_match, CSR_IA_MATCH); // clear ia_match + sw64_write_csr(0, CSR_IV_MATCH); // clear iv_match task_thread_info(current)->pcb.match_ctl &= ~(0x1 << 4); task_thread_info(current)->pcb.ia_match &= ~((0x1UL << IV_MATCH_EN_S) | (0x1UL << IV_PM_EN_S)); task_thread_info(current)->pcb.iv_match = 0; } if (mmcsr == MMCSR__IDA_MATCH) { info.si_errno = 6; - write_csr(0, CSR_IDA_MATCH); // clear ida_match + sw64_write_csr(0, CSR_IDA_MATCH); // clear ida_match task_thread_info(current)->pcb.match_ctl &= ~(0x1 << 5); task_thread_info(current)->pcb.ida_match = 0; } @@ -693,39 +693,39 @@ void restore_da_match_after_sched(void) pr_info("Restroe MATCH status, pid: %d\n", current->pid); if (pcb->match_ctl & DA_MATCH) { - write_csr(pcb->da_match, CSR_DA_MATCH); - write_csr(pcb->da_mask, CSR_DA_MASK); + sw64_write_csr(pcb->da_match, CSR_DA_MATCH); + sw64_write_csr(pcb->da_mask, CSR_DA_MASK); match_ctl_mode = (pcb->match_ctl >> 8) & 0x3; - match_ctl = read_csr(CSR_DC_CTLP); + match_ctl = sw64_read_csr(CSR_DC_CTLP); match_ctl &= ~((0x1UL << 3) | (0x3UL << DA_MATCH_EN_S) | (0x1UL << DV_MATCH_EN_S) | (0x1UL << DAV_MATCH_EN_S)); match_ctl |= (match_ctl_mode << DA_MATCH_EN_S) | (0x1UL << DPM_MATCH_EN_S) | (0x3UL << DPM_MATCH); - write_csr(match_ctl, CSR_DC_CTLP); + sw64_write_csr(match_ctl, CSR_DC_CTLP); pr_info("da_match:%#lx da_mask:%#lx match_ctl:%#lx\n", pcb->da_match, pcb->da_mask, match_ctl); } if (pcb->match_ctl & DV_MATCH) { - write_csr(pcb->dv_match, CSR_DV_MATCH); - write_csr(pcb->dv_mask, CSR_DV_MASK); - match_ctl = read_csr(CSR_DC_CTLP); + sw64_write_csr(pcb->dv_match, CSR_DV_MATCH); + sw64_write_csr(pcb->dv_mask, CSR_DV_MASK); + match_ctl = sw64_read_csr(CSR_DC_CTLP); match_ctl &= ~((0x1UL << 3) | (0x3UL << DA_MATCH_EN_S) | (0x1UL << DV_MATCH_EN_S) | (0x1UL << DAV_MATCH_EN_S)); match_ctl |= (0x1UL << DV_MATCH_EN_S) | (0x1UL << DPM_MATCH_EN_S) | (0x3UL << DPM_MATCH); - write_csr(match_ctl, CSR_DC_CTLP); + sw64_write_csr(match_ctl, CSR_DC_CTLP); pr_info("dv_match:%#lx dv_mask:%#lx match_ctl:%#lx\n", pcb->dv_match, pcb->dv_mask, match_ctl); } if (pcb->match_ctl & DAV_MATCH) { - write_csr(pcb->da_match, CSR_DA_MATCH); - write_csr(pcb->da_mask, CSR_DA_MASK); - write_csr(pcb->dv_match, CSR_DV_MATCH); - write_csr(pcb->dv_mask, CSR_DV_MASK); - write_csr(0xfffffffff, CSR_DA_MATCH_MODE); + sw64_write_csr(pcb->da_match, CSR_DA_MATCH); + sw64_write_csr(pcb->da_mask, CSR_DA_MASK); + sw64_write_csr(pcb->dv_match, CSR_DV_MATCH); + sw64_write_csr(pcb->dv_mask, CSR_DV_MASK); + sw64_write_csr(0xfffffffff, CSR_DA_MATCH_MODE); match_ctl_mode = (pcb->match_ctl >> 8) & 0x3; - match_ctl = read_csr(CSR_DC_CTLP); + match_ctl = sw64_read_csr(CSR_DC_CTLP); match_ctl &= ~((0x3UL << DA_MATCH_EN_S) | (0x1UL << DV_MATCH_EN_S) | (0x1UL << DAV_MATCH_EN_S)); match_ctl |= (match_ctl_mode << DA_MATCH_EN_S) | (0x1UL << DV_MATCH_EN_S) | (0x1UL << DAV_MATCH_EN_S) | (0x1UL << DPM_MATCH_EN_S) | (0x3UL << DPM_MATCH); - write_csr(match_ctl, CSR_DC_CTLP); + sw64_write_csr(match_ctl, CSR_DC_CTLP); pr_info("da_match:%#lx da_mask:%#lx dv_match:%#lx dv_mask:%#lx match_ctl:%#lx\n", pcb->da_match, pcb->da_mask, pcb->dv_match, pcb->dv_mask, match_ctl); } @@ -733,27 +733,27 @@ void restore_da_match_after_sched(void) if (pcb->match_ctl & IA_MATCH) { pcb->ia_match |= (0x1UL << IA_MATCH_EN_S) | 0x3; pcb->ia_mask |= 0x3; - write_csr(pcb->ia_match, CSR_IA_MATCH); - write_csr(pcb->ia_mask, CSR_IA_MASK); - vpn = read_csr(CSR_VPCR) >> 44; + sw64_write_csr(pcb->ia_match, CSR_IA_MATCH); + sw64_write_csr(pcb->ia_mask, CSR_IA_MASK); + vpn = sw64_read_csr(CSR_VPCR) >> 44; vpn &= 0x3ff; - upn = read_csr(CSR_UPCR); + upn = sw64_read_csr(CSR_UPCR); upn &= 0x3ff; - write_csr(((0x3ff << 18) | vpn), CSR_IA_VPNMATCH); - write_csr(((0x3ff << 18) | upn), CSR_IA_UPNMATCH); + sw64_write_csr(((0x3ff << 18) | vpn), CSR_IA_VPNMATCH); + sw64_write_csr(((0x3ff << 18) | upn), CSR_IA_UPNMATCH); pr_info("ia_match:%#lx ia_mask:%#lx\n", pcb->ia_match, pcb->ia_mask); } if (pcb->match_ctl & IV_MATCH) { pcb->ia_match |= (0x1UL << IV_MATCH_EN_S) | (0x1UL << IV_PM_EN_S) | 0x3; - write_csr(pcb->ia_match, CSR_IA_MATCH); - write_csr(pcb->iv_match, CSR_IV_MATCH); + sw64_write_csr(pcb->ia_match, CSR_IA_MATCH); + sw64_write_csr(pcb->iv_match, CSR_IV_MATCH); pr_info("ia_match:%#lx iv_match:%#lx\n", pcb->ia_match, pcb->iv_match); } if (pcb->match_ctl & IDA_MATCH) { pcb->ida_match |= (0x1UL << IDA_MATCH_EN_S) | 0x3; pcb->ida_mask |= 0x3; - write_csr(pcb->ida_match, CSR_IDA_MATCH); - write_csr(pcb->ida_mask, CSR_IDA_MASK); + sw64_write_csr(pcb->ida_match, CSR_IDA_MATCH); + sw64_write_csr(pcb->ida_mask, CSR_IDA_MASK); pr_info("ida_match:%#lx ida_mask:%#lx\n", pcb->ida_match, pcb->ida_mask); } } diff --git a/arch/sw_64/kernel/smp.c b/arch/sw_64/kernel/smp.c index e57222370e0e..feba4c131f14 100644 --- a/arch/sw_64/kernel/smp.c +++ b/arch/sw_64/kernel/smp.c @@ -84,10 +84,10 @@ void smp_callin(void) /* Set interrupt vector. */ if (is_in_host()) { - write_csr(0xffffffffffffffffUL, CSR_PCIE_MSI0_INTEN); - write_csr(0xffffffffffffffffUL, CSR_PCIE_MSI1_INTEN); - write_csr(0xffffffffffffffffUL, CSR_PCIE_MSI2_INTEN); - write_csr(0xffffffffffffffffUL, CSR_PCIE_MSI3_INTEN); + sw64_write_csr(0xffffffffffffffffUL, CSR_PCIE_MSI0_INTEN); + sw64_write_csr(0xffffffffffffffffUL, CSR_PCIE_MSI1_INTEN); + sw64_write_csr(0xffffffffffffffffUL, CSR_PCIE_MSI2_INTEN); + sw64_write_csr(0xffffffffffffffffUL, CSR_PCIE_MSI3_INTEN); } wrent(entInt, 0); diff --git a/arch/sw_64/kernel/vdso/vgettimeofday.c b/arch/sw_64/kernel/vdso/vgettimeofday.c index 0aa16e988e88..07e023d3d64b 100644 --- a/arch/sw_64/kernel/vdso/vgettimeofday.c +++ b/arch/sw_64/kernel/vdso/vgettimeofday.c @@ -88,7 +88,7 @@ static __always_inline u64 read_longtime(void) #elif defined(CONFIG_SUBARCH_C4) static __always_inline u64 read_longtime(void) { - return read_csr(CSR_SHTCLOCK); + return sw64_read_csr(CSR_SHTCLOCK); } #endif diff --git a/arch/sw_64/kvm/emulate.c b/arch/sw_64/kvm/emulate.c index 160c5c29c4d0..540b4590caf9 100644 --- a/arch/sw_64/kvm/emulate.c +++ b/arch/sw_64/kvm/emulate.c @@ -19,8 +19,8 @@ void sw64_decode(struct kvm_vcpu *vcpu, unsigned int insn, struct kvm_run *run) #elif defined(CONFIG_SUBARCH_C4) unsigned long ds_stat, exc_sum; - ds_stat = read_csr(CSR_DS_STAT); - exc_sum = read_csr(CSR_EXC_SUM); + ds_stat = sw64_read_csr(CSR_DS_STAT); + exc_sum = sw64_read_csr(CSR_EXC_SUM); opc = (ds_stat >> 4) & 0x3f; ra = (exc_sum >> 8) & 0x1f; diff --git a/arch/sw_64/kvm/kvm_core4.c b/arch/sw_64/kvm/kvm_core4.c index 870cd0a44438..d4af2c76ac8b 100644 --- a/arch/sw_64/kvm/kvm_core4.c +++ b/arch/sw_64/kvm/kvm_core4.c @@ -25,7 +25,7 @@ static unsigned long shtclock_offset; void update_aptp(unsigned long pgd) { imemb(); - write_csr_imb(pgd, CSR_APTP); + sw64_write_csr_imb(pgd, CSR_APTP); } void kvm_sw64_update_vpn(struct kvm_vcpu *vcpu, unsigned long vpn) @@ -77,7 +77,7 @@ long kvm_sw64_get_vcb(struct file *filp, unsigned long arg) struct kvm_vcpu *vcpu = filp->private_data; if (vcpu->arch.migration_mark) - vcpu->arch.shtclock = read_csr(CSR_SHTCLOCK) + vcpu->arch.shtclock = sw64_read_csr(CSR_SHTCLOCK) + vcpu->arch.vcb.shtclock_offset; if (copy_to_user((void __user *)arg, &(vcpu->arch.vcb), sizeof(struct vcpucb))) return -EINVAL; @@ -96,7 +96,7 @@ long kvm_sw64_set_vcb(struct file *filp, unsigned long arg) if (vcpu->arch.migration_mark) { /* synchronize the longtime of source and destination */ if (vcpu->arch.vcb.soft_cid == 0) - shtclock_offset = vcpu->arch.shtclock - read_csr(CSR_SHTCLOCK); + shtclock_offset = vcpu->arch.shtclock - sw64_read_csr(CSR_SHTCLOCK); vcpu->arch.vcb.shtclock_offset = shtclock_offset; set_timer(vcpu, 200000000); vcpu->arch.migration_mark = 0; diff --git a/arch/sw_64/kvm/mmio.c b/arch/sw_64/kvm/mmio.c index fad52fe31e64..3214a4efb0b1 100644 --- a/arch/sw_64/kvm/mmio.c +++ b/arch/sw_64/kvm/mmio.c @@ -72,7 +72,7 @@ int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run, run->mmio.phys_addr = hargs->arg1 & 0xfffffffffffffUL; sw64_decode(vcpu, hargs->arg2, run); #elif defined(CONFIG_SUBARCH_C4) - run->mmio.phys_addr = read_csr(CSR_DVA) & 0xfffffffffffffUL; + run->mmio.phys_addr = sw64_read_csr(CSR_DVA) & 0xfffffffffffffUL; sw64_decode(vcpu, 0, run); #endif if (run->mmio.is_write) { diff --git a/arch/sw_64/kvm/mmu.c b/arch/sw_64/kvm/mmu.c index e11275ab121f..b3e4b3da4ca6 100644 --- a/arch/sw_64/kvm/mmu.c +++ b/arch/sw_64/kvm/mmu.c @@ -791,8 +791,8 @@ static int apt_set_pte_fast(struct kvm *kvm, struct kvm_mmu_memory_cache *cache, pmd_t *pmd; pte_t *pte, old_pte; bool logging_active = flags & KVM_APT_FLAG_LOGGING_ACTIVE; - int inv_level = ((read_csr(CSR_AS_INFO)) >> AF_INV_LEVEL_SHIFT) & AF_INV_LEVEL_MASK; - unsigned long inv_hpa = read_csr(CSR_AS_INFO) & AF_ENTRY_ADDR_MASK; + int inv_level = ((sw64_read_csr(CSR_AS_INFO)) >> AF_INV_LEVEL_SHIFT) & AF_INV_LEVEL_MASK; + unsigned long inv_hpa = sw64_read_csr(CSR_AS_INFO) & AF_ENTRY_ADDR_MASK; VM_BUG_ON(logging_active && !cache); @@ -1149,7 +1149,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_gpa, unsigned long as_info, access_type; unsigned int vma_shift; - as_info = read_csr(CSR_AS_INFO); + as_info = sw64_read_csr(CSR_AS_INFO); access_type = (as_info >> AF_ACCESS_TYPE_SHIFT) & AF_ACCESS_TYPE_MASK; write_fault = kvm_is_write_fault(access_type); exec_fault = kvm_is_exec_fault(access_type); @@ -1353,13 +1353,13 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu, struct kvm_run *run) int ret, idx; - as_info = read_csr(CSR_AS_INFO); + as_info = sw64_read_csr(CSR_AS_INFO); access_type = (as_info >> AF_ACCESS_TYPE_SHIFT) & AF_ACCESS_TYPE_MASK; inv_level = (as_info >> AF_INV_LEVEL_SHIFT) & AF_INV_LEVEL_MASK; fault_status = (as_info >> AF_FAULT_STATUS_SHIFT) & AF_FAULT_STATUS_MASK; fault_entry_addr = (as_info & AF_ENTRY_ADDR_MASK) >> 3; - fault_gpa = read_csr(CSR_EXC_GPA); + fault_gpa = sw64_read_csr(CSR_EXC_GPA); idx = srcu_read_lock(&vcpu->kvm->srcu); gfn = fault_gpa >> PAGE_SHIFT; diff --git a/drivers/clocksource/timer-sw64.c b/drivers/clocksource/timer-sw64.c index 01ae2b4655e7..fda7755b99b5 100644 --- a/drivers/clocksource/timer-sw64.c +++ b/drivers/clocksource/timer-sw64.c @@ -19,7 +19,7 @@ #if defined(CONFIG_SUBARCH_C4) static u64 read_longtime(struct clocksource *cs) { - return read_csr(CSR_SHTCLOCK); + return sw64_read_csr(CSR_SHTCLOCK); } static struct clocksource clocksource_longtime = { @@ -34,7 +34,7 @@ static struct clocksource clocksource_longtime = { static u64 notrace read_sched_clock(void) { - return read_csr(CSR_SHTCLOCK); + return sw64_read_csr(CSR_SHTCLOCK); } void __init sw64_setup_clocksource(void) -- Gitee From e6cd94b3a3bf18e8f5fc1f68011255053d006f51 Mon Sep 17 00:00:00 2001 From: Xu Yiwei Date: Tue, 2 Jan 2024 06:26:53 +0000 Subject: [PATCH 18/49] anolis: sw64: add missing c4 intc kconfig ANBZ: #4688 SW64 Interrupt controller Kconfig is missing the new C4 config. Add this config to compile intc code when running C4 machines. Signed-off-by: Xu Yiwei Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- drivers/irqchip/Kconfig | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index a652375b8aae..ec861aee0172 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -13,14 +13,15 @@ config ARM_GIC config SW64_INTC_V2 bool "SW64 Interrupt Controller V2" - depends on UNCORE_XUELANG + depends on UNCORE_XUELANG || UNCORE_JUNZHANG default y select GENERIC_IRQ_CHIP select IRQ_DOMAIN help - This enables support for the INTC chip found in SW CHIP3 systems. - The INTC controls devices interrupts and connects them to each - core's local interrupt controller. + This enables support for the INTC chip found in SW systems. + The INTC receives all platform devices' interrupts and passes + them to certain core's local interrupt controller for further + interrupt handling. config SW64_LPC_INTC bool "SW64 cpu builtin LPC Interrupt Controller" -- Gitee From a5149ccbc84208542fd156e089025cae1095daca Mon Sep 17 00:00:00 2001 From: Wang Yuanheng Date: Thu, 4 Jan 2024 09:59:06 +0800 Subject: [PATCH 19/49] anolis: sw64: add missing c4 legacy power management code ANBZ: #4688 The c4 legacy power management is missing, which is causing errors when guest is excuting poweroff command. Signed-off-by: Wang Yuanheng Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- drivers/platform/sw64/Makefile | 1 + drivers/platform/sw64/legacy_junzhang.c | 62 +++++++++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 drivers/platform/sw64/legacy_junzhang.c diff --git a/drivers/platform/sw64/Makefile b/drivers/platform/sw64/Makefile index 28922224fb17..3efa835ade5d 100644 --- a/drivers/platform/sw64/Makefile +++ b/drivers/platform/sw64/Makefile @@ -1,2 +1,3 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_PLATFORM_XUELANG) += legacy_xuelang.o +obj-$(CONFIG_PLATFORM_JUNZHANG) += legacy_junzhang.o diff --git a/drivers/platform/sw64/legacy_junzhang.c b/drivers/platform/sw64/legacy_junzhang.c new file mode 100644 index 000000000000..17d6d151d0b8 --- /dev/null +++ b/drivers/platform/sw64/legacy_junzhang.c @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include +#include + +static void vt_mode_kill_arch(int mode) +{ + hcall(HCALL_SET_CLOCKEVENT, 0, 0, 0); + + switch (mode) { + case LINUX_REBOOT_CMD_RESTART: + hcall(HCALL_RESTART, 0, 0, 0); + mb(); + break; + case LINUX_REBOOT_CMD_HALT: + case LINUX_REBOOT_CMD_POWER_OFF: + hcall(HCALL_SHUTDOWN, 0, 0, 0); + mb(); + break; + default: + break; + } +} + +void sw64_halt(void) +{ + if (is_in_host()) + cpld_write(0x64, 0x00, 0xf0); + else + vt_mode_kill_arch(LINUX_REBOOT_CMD_HALT); +} + +void sw64_poweroff(void) +{ + if (is_in_host()) + cpld_write(0x64, 0x00, 0xf0); + else + vt_mode_kill_arch(LINUX_REBOOT_CMD_POWER_OFF); +} + +void sw64_restart(void) +{ + if (is_in_host()) { + fix_jm585_reset(); + cpld_write(0x64, 0x00, 0xc3); + } else + vt_mode_kill_arch(LINUX_REBOOT_CMD_RESTART); +} + +static int sw64_reset_init(void) +{ +#ifdef CONFIG_EFI + if (BIOS_SUPPORT_RESET_CLALLBACK((void *)bios_version)) + return 0; +#endif + pm_restart = sw64_restart; + pm_power_off = sw64_poweroff; + pm_halt = sw64_halt; + return 0; +} +subsys_initcall(sw64_reset_init); -- Gitee From 353b886c1b680c72ad6d71bd6b13a8f96b790c74 Mon Sep 17 00:00:00 2001 From: Min Fanlei Date: Tue, 2 Jan 2024 14:26:36 +0800 Subject: [PATCH 20/49] anolis: sw64: kvm: delete memory hotplug codes for CORE3B ANBZ: #4688 Guest memory hotplug of CORE3B is not support, so delete it to make the code clearer. Signed-off-by: Min Fanlei Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/include/asm/hcall.h | 1 - arch/sw_64/include/asm/kvm_asm.h | 2 - arch/sw_64/include/asm/kvm_host.h | 11 ---- arch/sw_64/include/asm/memory.h | 1 - arch/sw_64/kvm/Kconfig | 7 --- arch/sw_64/kvm/handle_exit.c | 6 -- arch/sw_64/kvm/kvm_core3.c | 97 ------------------------------- arch/sw_64/kvm/sw64.c | 3 - arch/sw_64/mm/init.c | 5 +- drivers/misc/sunway-ged.c | 2 - 10 files changed, 1 insertion(+), 134 deletions(-) diff --git a/arch/sw_64/include/asm/hcall.h b/arch/sw_64/include/asm/hcall.h index 65669e54c0f8..d62262b475e1 100644 --- a/arch/sw_64/include/asm/hcall.h +++ b/arch/sw_64/include/asm/hcall.h @@ -18,7 +18,6 @@ enum HCALL_TYPE { HCALL_SWNET = 20, /* guest request swnet service */ HCALL_SWNET_IRQ = 21, /* guest request swnet intr */ HCALL_FATAL_ERROR = 22, /* guest fatal error, issued by hmcode */ - HCALL_MEMHOTPLUG = 23, /* guest memory hotplug event */ NR_HCALL }; diff --git a/arch/sw_64/include/asm/kvm_asm.h b/arch/sw_64/include/asm/kvm_asm.h index fd1b25018fc8..a8e8ef3d68a0 100644 --- a/arch/sw_64/include/asm/kvm_asm.h +++ b/arch/sw_64/include/asm/kvm_asm.h @@ -14,7 +14,6 @@ #define SW64_KVM_EXIT_RESTART 17 #define SW64_KVM_EXIT_APT_FAULT 18 #define SW64_KVM_EXIT_FATAL_ERROR 22 -#define SW64_KVM_EXIT_MEMHOTPLUG 23 #define SW64_KVM_EXIT_DEBUG 24 @@ -29,7 +28,6 @@ {17, "RESTART" }, \ {18, "APT_FAULT" }, \ {22, "FATAL_ERROR" }, \ - {23, "MEMHOTPLUG" }, \ {24, "DEBUG" } diff --git a/arch/sw_64/include/asm/kvm_host.h b/arch/sw_64/include/asm/kvm_host.h index eb90ca72ec38..0b0da779db36 100644 --- a/arch/sw_64/include/asm/kvm_host.h +++ b/arch/sw_64/include/asm/kvm_host.h @@ -65,17 +65,12 @@ #define KVM_PHYS_MASK (KVM_PHYS_SIZE - _AC(1, ULL)) struct kvm_arch_memory_slot { - unsigned long host_phys_addr; - bool valid; }; struct kvm_arch { unsigned long host_phys_addr; unsigned long size; - /* segment table */ - unsigned long *seg_pgd; - struct swvm_mem mem; /* Addtional stage page table*/ pgd_t *pgd; @@ -156,9 +151,6 @@ struct kvm_vcpu_stat { u64 ipi_exits; u64 timer_exits; u64 debug_exits; -#ifdef CONFIG_KVM_MEMHOTPLUG - u64 memhotplug_exits; -#endif u64 fatal_error_exits; u64 halt_exits; u64 halt_successful_poll; @@ -175,9 +167,6 @@ struct kvm_vcpu_stat { u64 gtime; }; -#ifdef CONFIG_KVM_MEMHOTPLUG -void vcpu_mem_hotplug(struct kvm_vcpu *vcpu, unsigned long start_addr); -#endif #ifdef CONFIG_SUBARCH_C4 #define KVM_ARCH_WANT_MMU_NOTIFIER #endif diff --git a/arch/sw_64/include/asm/memory.h b/arch/sw_64/include/asm/memory.h index b2b7492ae477..d3191165c7b5 100644 --- a/arch/sw_64/include/asm/memory.h +++ b/arch/sw_64/include/asm/memory.h @@ -6,7 +6,6 @@ #include #endif -#define MIN_MEMORY_BLOCK_SIZE_VM_MEMHP (1UL << 30) #define NODE0_START (_TEXT_START - __START_KERNEL_map) #define MAX_PHYSMEM_BITS 48 diff --git a/arch/sw_64/kvm/Kconfig b/arch/sw_64/kvm/Kconfig index b7e43d0bae51..fdff308aed22 100644 --- a/arch/sw_64/kvm/Kconfig +++ b/arch/sw_64/kvm/Kconfig @@ -37,13 +37,6 @@ config KVM If unsure, say N. -config KVM_MEMHOTPLUG - bool "Memory hotplug support for guest" - depends on KVM && MEMORY_HOTPLUG && SUBARCH_C3B - help - Provides memory hotplug support for SW64 guest. - - source "drivers/vhost/Kconfig" endif # VIRTUALIZATION diff --git a/arch/sw_64/kvm/handle_exit.c b/arch/sw_64/kvm/handle_exit.c index 08c7f283c14e..b989017a40c1 100644 --- a/arch/sw_64/kvm/handle_exit.c +++ b/arch/sw_64/kvm/handle_exit.c @@ -63,12 +63,6 @@ int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run, vcpu->run->exit_reason = KVM_EXIT_DEBUG; vcpu->run->debug.arch.epc = vcpu->arch.regs.pc; return 0; -#ifdef CONFIG_KVM_MEMHOTPLUG - case SW64_KVM_EXIT_MEMHOTPLUG: - vcpu->stat.memhotplug_exits++; - vcpu_mem_hotplug(vcpu, hargs->arg0); - return 1; -#endif #ifdef CONFIG_SUBARCH_C4 case SW64_KVM_EXIT_APT_FAULT: return kvm_handle_guest_abort(vcpu, run); diff --git a/arch/sw_64/kvm/kvm_core3.c b/arch/sw_64/kvm/kvm_core3.c index 09ac213c676f..1a2c813de569 100644 --- a/arch/sw_64/kvm/kvm_core3.c +++ b/arch/sw_64/kvm/kvm_core3.c @@ -57,15 +57,6 @@ static void bind_vcpu_exit(void) { } static unsigned long longtime_offset; -#ifdef CONFIG_KVM_MEMHOTPLUG -static unsigned long get_vpcr(struct kvm_vcpu *vcpu, u64 vpn) -{ - unsigned long base; - - base = virt_to_phys(vcpu->kvm->arch.seg_pgd); - return base | ((vpn & VPN_MASK) << 44); -} -#else static unsigned long get_vpcr(struct kvm_vcpu *vcpu, u64 vpn) { unsigned long base, size; @@ -74,13 +65,11 @@ static unsigned long get_vpcr(struct kvm_vcpu *vcpu, u64 vpn) size = vcpu->kvm->arch.size; return (base >> 23) | ((size >> 23) << 16) | ((vpn & VPN_MASK) << 44); } -#endif void vcpu_set_numa_affinity(struct kvm_vcpu *vcpu) { if (vcpu->arch.vcb.vpcr == 0) { vcpu->arch.vcb.vpcr = get_vpcr(vcpu, 0); -#ifndef CONFIG_KVM_MEMHOTPLUG if (unlikely(bind_vcpu_enabled)) { int nid; unsigned long end; @@ -90,7 +79,6 @@ void vcpu_set_numa_affinity(struct kvm_vcpu *vcpu) if (pfn_to_nid(PHYS_PFN(end)) == nid) set_cpus_allowed_ptr(vcpu->arch.tsk, cpumask_of_node(nid)); } -#endif vcpu->arch.vcb.upcr = 0x7; } } @@ -108,37 +96,13 @@ void kvm_sw64_update_vpn(struct kvm_vcpu *vcpu, unsigned long vpn) int kvm_sw64_init_vm(struct kvm *kvm) { -#ifdef CONFIG_KVM_MEMHOTPLUG - unsigned long *seg_pgd; - - if (kvm->arch.seg_pgd != NULL) { - kvm_err("kvm_arch already initialized?\n"); - return -EINVAL; - } - - seg_pgd = alloc_pages_exact(PAGE_SIZE, GFP_KERNEL | __GFP_ZERO); - if (!seg_pgd) - return -ENOMEM; - - kvm->arch.seg_pgd = seg_pgd; - #endif return 0; } void kvm_sw64_destroy_vm(struct kvm *kvm) { int i; - #ifdef CONFIG_KVM_MEMHOTPLUG - void *seg_pgd = NULL; - if (kvm->arch.seg_pgd) { - seg_pgd = READ_ONCE(kvm->arch.seg_pgd); - kvm->arch.seg_pgd = NULL; - } - - if (seg_pgd) - free_pages_exact(seg_pgd, PAGE_SIZE); - #endif for (i = 0; i < KVM_MAX_VCPUS; ++i) { if (kvm->vcpus[i]) kvm_vcpu_destroy(kvm->vcpus[i]); @@ -146,24 +110,6 @@ void kvm_sw64_destroy_vm(struct kvm *kvm) atomic_set(&kvm->online_vcpus, 0); } -#ifdef CONFIG_KVM_MEMHOTPLUG -static void setup_segment_table(struct kvm *kvm, - struct kvm_memory_slot *memslot, unsigned long addr, size_t size) -{ - unsigned long *seg_pgd = kvm->arch.seg_pgd; - unsigned long num_of_entry; - unsigned long base_hpa = addr; - unsigned long i; - - num_of_entry = round_up(size, 1 << 30) >> 30; - - for (i = 0; i < num_of_entry; i++) { - *seg_pgd = base_hpa + (i << 30); - seg_pgd++; - } -} -#endif - int kvm_arch_prepare_memory_region(struct kvm *kvm, struct kvm_memory_slot *memslot, const struct kvm_userspace_memory_region *mem, @@ -185,12 +131,6 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm, if (test_bit(IO_MARK_BIT + 1, &(mem->guest_phys_addr))) return 0; -#ifndef CONFIG_KVM_MEMHOTPLUG - if (mem->guest_phys_addr) { - pr_info("%s, No KVM MEMHOTPLUG support!\n", __func__); - return 0; - } -#endif if (!sw64_kvm_pool) return -ENOMEM; @@ -220,17 +160,6 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm, if (!vma) return -ENOMEM; -#ifdef CONFIG_KVM_MEMHOTPLUG - if (memslot->base_gfn == 0x0UL) { - setup_segment_table(kvm, memslot, addr, size); - kvm->arch.host_phys_addr = (u64)addr; - memslot->arch.host_phys_addr = addr; - } else { - /* used for memory hotplug */ - memslot->arch.host_phys_addr = addr; - memslot->arch.valid = false; - } -#endif info->start = addr; info->size = size; vma->vm_private_data = (void *) info; @@ -248,10 +177,8 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm, pr_info("guest phys addr = %#lx, size = %#lx\n", addr, vma->vm_end - vma->vm_start); -#ifndef CONFIG_KVM_MEMHOTPLUG kvm->arch.host_phys_addr = (u64)addr; kvm->arch.size = round_up(mem->memory_size, 8<<20); -#endif memset(__va(addr), 0, 0x2000000); return 0; @@ -359,30 +286,6 @@ long kvm_sw64_set_vcb(struct file *filp, unsigned long arg) return 0; } -#ifdef CONFIG_KVM_MEMHOTPLUG -void vcpu_mem_hotplug(struct kvm_vcpu *vcpu, unsigned long start_addr) -{ - struct kvm *kvm = vcpu->kvm; - struct kvm_memory_slot *slot; - unsigned long start_pfn = start_addr >> PAGE_SHIFT; - - kvm_for_each_memslot(slot, kvm_memslots(kvm)) { - if (start_pfn == slot->base_gfn) { - unsigned long *seg_pgd; - unsigned long num_of_entry = slot->npages >> 17; - unsigned long base_hpa = slot->arch.host_phys_addr; - unsigned long i; - - seg_pgd = kvm->arch.seg_pgd + (start_pfn >> 17); - for (i = 0; i < num_of_entry; i++) { - *seg_pgd = base_hpa + (i << 30); - seg_pgd++; - } - } - } -} -#endif - void kvm_mmu_free_memory_caches(struct kvm_vcpu *vcpu) { } diff --git a/arch/sw_64/kvm/sw64.c b/arch/sw_64/kvm/sw64.c index 4d19714d0542..88785541cf33 100644 --- a/arch/sw_64/kvm/sw64.c +++ b/arch/sw_64/kvm/sw64.c @@ -125,9 +125,6 @@ struct kvm_stats_debugfs_item debugfs_entries[] = { VCPU_STAT("ipi_exits", ipi_exits), VCPU_STAT("timer_exits", timer_exits), VCPU_STAT("debug_exits", debug_exits), -#ifdef CONFIG_KVM_MEMHOTPLUG - VCPU_STAT("memhotplug_exits", memhotplug_exits), -#endif VCPU_STAT("fatal_error_exits", fatal_error_exits), VCPU_STAT("halt_exits", halt_exits), VCPU_STAT("halt_successful_poll", halt_successful_poll), diff --git a/arch/sw_64/mm/init.c b/arch/sw_64/mm/init.c index 46a9770e6410..e6700cae9975 100644 --- a/arch/sw_64/mm/init.c +++ b/arch/sw_64/mm/init.c @@ -38,10 +38,7 @@ static phys_addr_t mem_size_limit; #ifdef CONFIG_MEMORY_HOTPLUG_SPARSE unsigned long memory_block_size_bytes(void) { - if (is_in_guest()) - return MIN_MEMORY_BLOCK_SIZE_VM_MEMHP; - else - return MIN_MEMORY_BLOCK_SIZE; + return MIN_MEMORY_BLOCK_SIZE; } #endif /* CONFIG_MEMORY_HOTPLUG_SPARSE */ diff --git a/drivers/misc/sunway-ged.c b/drivers/misc/sunway-ged.c index b4e4ca315852..557608a78e29 100644 --- a/drivers/misc/sunway-ged.c +++ b/drivers/misc/sunway-ged.c @@ -161,8 +161,6 @@ static int sunway_memory_device_add(struct sunway_ged_device *device) list_add_tail(&mem_device->list, &device->dev_list); dev_dbg(device->dev, "Memory device configured\n"); - hcall(HCALL_MEMHOTPLUG, mem_device->start_addr, 0, 0); - return 1; } -- Gitee From 66808b67d91d557f1f88f535ff6fd191ddc53d85 Mon Sep 17 00:00:00 2001 From: Min Fanlei Date: Tue, 2 Jan 2024 10:51:13 +0800 Subject: [PATCH 21/49] anolis: sw64: kvm: fix clock sync of CORE4 live migration ANBZ: #4688 Move "migration_mark" and "shtclock" from struct kvm_vcpu_arch to struct vcpucb, so that they can be synced between the src and dst guest. Signed-off-by: Min Fanlei Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/include/asm/kvm_host.h | 4 ---- arch/sw_64/include/asm/vcpu.h | 4 +++- arch/sw_64/kvm/kvm_core4.c | 13 +++++++------ arch/sw_64/kvm/mmu.c | 2 +- 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/arch/sw_64/include/asm/kvm_host.h b/arch/sw_64/include/asm/kvm_host.h index 0b0da779db36..acaa42d1ec60 100644 --- a/arch/sw_64/include/asm/kvm_host.h +++ b/arch/sw_64/include/asm/kvm_host.h @@ -123,10 +123,6 @@ struct kvm_vcpu_arch { /* Cache some mmu pages needed inside spinlock regions */ struct kvm_mmu_memory_cache mmu_page_cache; - - /* guest live migration */ - unsigned long migration_mark; - unsigned long shtclock; }; struct vmem_info { diff --git a/arch/sw_64/include/asm/vcpu.h b/arch/sw_64/include/asm/vcpu.h index c4e3caacbc70..c29ae9797fa2 100644 --- a/arch/sw_64/include/asm/vcpu.h +++ b/arch/sw_64/include/asm/vcpu.h @@ -98,7 +98,9 @@ struct vcpucb { unsigned long ipaddr; unsigned long vcpu_pc_save; unsigned long shtclock_offset; - unsigned long reserved[8]; + unsigned long migration_mark; + unsigned long shtclock; + unsigned long reserved[6]; }; #endif diff --git a/arch/sw_64/kvm/kvm_core4.c b/arch/sw_64/kvm/kvm_core4.c index d4af2c76ac8b..96f053da84ca 100644 --- a/arch/sw_64/kvm/kvm_core4.c +++ b/arch/sw_64/kvm/kvm_core4.c @@ -76,9 +76,9 @@ long kvm_sw64_get_vcb(struct file *filp, unsigned long arg) { struct kvm_vcpu *vcpu = filp->private_data; - if (vcpu->arch.migration_mark) - vcpu->arch.shtclock = sw64_read_csr(CSR_SHTCLOCK) - + vcpu->arch.vcb.shtclock_offset; + if (vcpu->arch.vcb.migration_mark) + vcpu->arch.vcb.shtclock = sw64_read_csr(CSR_SHTCLOCK) + + vcpu->arch.vcb.shtclock_offset; if (copy_to_user((void __user *)arg, &(vcpu->arch.vcb), sizeof(struct vcpucb))) return -EINVAL; @@ -93,13 +93,14 @@ long kvm_sw64_set_vcb(struct file *filp, unsigned long arg) kvm_vcb = memdup_user((void __user *)arg, sizeof(*kvm_vcb)); memcpy(&(vcpu->arch.vcb), kvm_vcb, sizeof(struct vcpucb)); - if (vcpu->arch.migration_mark) { + if (vcpu->arch.vcb.migration_mark) { /* synchronize the longtime of source and destination */ if (vcpu->arch.vcb.soft_cid == 0) - shtclock_offset = vcpu->arch.shtclock - sw64_read_csr(CSR_SHTCLOCK); + shtclock_offset = vcpu->arch.vcb.shtclock - + sw64_read_csr(CSR_SHTCLOCK); vcpu->arch.vcb.shtclock_offset = shtclock_offset; set_timer(vcpu, 200000000); - vcpu->arch.migration_mark = 0; + vcpu->arch.vcb.migration_mark = 0; } return 0; } diff --git a/arch/sw_64/kvm/mmu.c b/arch/sw_64/kvm/mmu.c index b3e4b3da4ca6..42c4a3dd0dae 100644 --- a/arch/sw_64/kvm/mmu.c +++ b/arch/sw_64/kvm/mmu.c @@ -542,7 +542,7 @@ void kvm_mark_migration(struct kvm *kvm, int mark) int cpu; kvm_for_each_vcpu(cpu, vcpu, kvm) - vcpu->arch.migration_mark = mark; + vcpu->arch.vcb.migration_mark = mark; } void kvm_arch_commit_memory_region(struct kvm *kvm, -- Gitee From a3fe96904ac33eee75398cdd48d7b706778e6feb Mon Sep 17 00:00:00 2001 From: Xu Yiwei Date: Mon, 11 Dec 2023 07:15:22 +0000 Subject: [PATCH 22/49] anolis: sw64: refactor device interrupt domain ANBZ: #4688 Refactor device interrupt domain code to support sw64 interrupt controller redesign. Signed-off-by: Xu Yiwei Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/include/asm/hw_irq.h | 2 + arch/sw_64/include/asm/uncore_io_junzhang.h | 2 + arch/sw_64/include/asm/uncore_io_xuelang.h | 2 + drivers/gpio/gpio-sunway.c | 1 + drivers/irqchip/Kconfig | 12 +- drivers/irqchip/Makefile | 4 +- drivers/irqchip/irq-sunway-cpu.c | 5 +- ...-sw64-lpc-intc.c => irq-sunway-lpc-intc.c} | 153 ++++++---- drivers/irqchip/irq-sunway-pintc.c | 287 ++++++++++++++++++ drivers/irqchip/irq-sw64-intc-v2.c | 89 ------ 10 files changed, 394 insertions(+), 163 deletions(-) rename drivers/irqchip/{irq-sw64-lpc-intc.c => irq-sunway-lpc-intc.c} (34%) create mode 100644 drivers/irqchip/irq-sunway-pintc.c delete mode 100644 drivers/irqchip/irq-sw64-intc-v2.c diff --git a/arch/sw_64/include/asm/hw_irq.h b/arch/sw_64/include/asm/hw_irq.h index 2988d2a81a70..4acc9172abeb 100644 --- a/arch/sw_64/include/asm/hw_irq.h +++ b/arch/sw_64/include/asm/hw_irq.h @@ -9,6 +9,8 @@ DECLARE_PER_CPU(unsigned long, irq_pmi_count); #define ACTUAL_NR_IRQS NR_IRQS +extern struct irq_domain *mcu_irq_domain; + #ifdef CONFIG_PCI_MSI typedef unsigned int vector_irq_t[PERCPU_MSI_IRQS] ____cacheline_aligned; DECLARE_PER_CPU(vector_irq_t, vector_irq); diff --git a/arch/sw_64/include/asm/uncore_io_junzhang.h b/arch/sw_64/include/asm/uncore_io_junzhang.h index 37cfe1fd6807..ac37d186a29f 100644 --- a/arch/sw_64/include/asm/uncore_io_junzhang.h +++ b/arch/sw_64/include/asm/uncore_io_junzhang.h @@ -70,6 +70,8 @@ #define PIUCONFIG0_INIT_VAL 0x38016 +#define DEV_INT_TARGET(phy_cpu) ((((phy_cpu) >> 5) << 7) | ((phy_cpu) & 0x3f)) + /*-----------------------addr-----------------------*/ /* INTPU REG */ enum { diff --git a/arch/sw_64/include/asm/uncore_io_xuelang.h b/arch/sw_64/include/asm/uncore_io_xuelang.h index aeaadec5be16..873f7e86f83b 100644 --- a/arch/sw_64/include/asm/uncore_io_xuelang.h +++ b/arch/sw_64/include/asm/uncore_io_xuelang.h @@ -74,6 +74,8 @@ #define PIUCONFIG0_INIT_VAL 0x38056 +#define DEV_INT_TARGET(phy_cpu) ((((phy_cpu) >> 5) << 6) | ((phy_cpu) & 0x1f)) + /*-----------------------addr-----------------------*/ /* CAB0 REG */ enum { diff --git a/drivers/gpio/gpio-sunway.c b/drivers/gpio/gpio-sunway.c index 6ff8b554d6be..5feafc3bdd45 100644 --- a/drivers/gpio/gpio-sunway.c +++ b/drivers/gpio/gpio-sunway.c @@ -425,6 +425,7 @@ static void sunway_configure_irqs(struct sunway_gpio *gpio, for (i = 0; i < 2; i++) { ct = &irq_gc->chip_types[i]; + ct->chip.name = "GPIO-INT"; ct->chip.irq_ack = irq_gc_ack_set_bit; ct->chip.irq_mask = irq_gc_mask_set_bit; ct->chip.irq_unmask = irq_gc_mask_clr_bit; diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index ec861aee0172..b6dffec29aee 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -11,21 +11,21 @@ config ARM_GIC select GENERIC_IRQ_MULTI_HANDLER select GENERIC_IRQ_EFFECTIVE_AFF_MASK -config SW64_INTC_V2 - bool "SW64 Interrupt Controller V2" - depends on UNCORE_XUELANG || UNCORE_JUNZHANG +config SW64_PINTC + bool "SW64 Interrupt Controller" + depends on SW64 default y select GENERIC_IRQ_CHIP select IRQ_DOMAIN help - This enables support for the INTC chip found in SW systems. - The INTC receives all platform devices' interrupts and passes + This enables support for the pINTC chip found in SW systems. + The PINTC receives all platform devices' interrupts and passes them to certain core's local interrupt controller for further interrupt handling. config SW64_LPC_INTC bool "SW64 cpu builtin LPC Interrupt Controller" - depends on SW64_INTC_V2 + depends on SW64_PINTC help Say yes here to add support for the SW64 cpu builtin LPC IRQ controller. diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index 3f19fe8628f6..c1ffb90cfff1 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -27,8 +27,8 @@ obj-$(CONFIG_ARCH_SUNXI) += irq-sun4i.o obj-$(CONFIG_ARCH_SUNXI) += irq-sunxi-nmi.o obj-$(CONFIG_ARCH_SPEAR3XX) += spear-shirq.o obj-$(CONFIG_ARM_GIC) += irq-gic.o irq-gic-common.o -obj-$(CONFIG_SW64_INTC_V2) += irq-sw64-intc-v2.o -obj-$(CONFIG_SW64_LPC_INTC) += irq-sw64-lpc-intc.o +obj-$(CONFIG_SW64_PINTC) += irq-sunway-pintc.o +obj-$(CONFIG_SW64_LPC_INTC) += irq-sunway-lpc-intc.o obj-$(CONFIG_SW64_IRQ_CPU) += irq-sunway-cpu.o ifeq ($(CONFIG_UNCORE_XUELANG),y) diff --git a/drivers/irqchip/irq-sunway-cpu.c b/drivers/irqchip/irq-sunway-cpu.c index ca1b62b2d645..e3d9dac3dfb3 100644 --- a/drivers/irqchip/irq-sunway-cpu.c +++ b/drivers/irqchip/irq-sunway-cpu.c @@ -115,10 +115,9 @@ static void handle_dev_int(struct pt_regs *regs) while (stat) { hwirq = ffs(stat) - 1; - handle_domain_irq(NULL, hwirq, regs); + handle_domain_irq(mcu_irq_domain, hwirq, regs); stat &= ~(1UL << hwirq); } - /*do handle irq */ sw64_io_write(node, DEV_INT_CONFIG, config_val); } @@ -186,9 +185,7 @@ asmlinkage void do_entInt(unsigned long type, unsigned long vector, perf_irq(PMC_PC1, regs); return; case INT_DEV: - old_regs = set_irq_regs(regs); handle_dev_int(regs); - set_irq_regs(old_regs); return; case INT_FAULT: old_regs = set_irq_regs(regs); diff --git a/drivers/irqchip/irq-sw64-lpc-intc.c b/drivers/irqchip/irq-sunway-lpc-intc.c similarity index 34% rename from drivers/irqchip/irq-sw64-lpc-intc.c rename to drivers/irqchip/irq-sunway-lpc-intc.c index 1cbf87478242..b594ddb6eb24 100644 --- a/drivers/irqchip/irq-sw64-lpc-intc.c +++ b/drivers/irqchip/irq-sunway-lpc-intc.c @@ -11,65 +11,125 @@ #define LPC_IRQ 0x4 #define LPC_IRQ_MASK 0x8 -struct lpc_intc_data { - struct irq_domain *domain; - struct irq_chip_generic *gc; -}; +static DEFINE_RAW_SPINLOCK(lpc_lock); + +static int parent_irq; + +static unsigned int cached_irq_mask = 0xffffffff; +static void lpc_irq_mask(struct irq_data *irq_data) +{ + void __iomem *base = irq_data->domain->host_data; + unsigned long flags; + u32 mask = 1 << (irq_data->irq); + + raw_spin_lock_irqsave(&lpc_lock, flags); + cached_irq_mask |= mask; + writel(cached_irq_mask, base + LPC_IRQ_MASK); + raw_spin_unlock_irqrestore(&lpc_lock, flags); +} + +static void lpc_irq_unmask(struct irq_data *irq_data) +{ + void __iomem *base = irq_data->domain->host_data; + unsigned long flags; + u32 mask = 1 << (irq_data->irq); + + raw_spin_lock_irqsave(&lpc_lock, flags); + cached_irq_mask &= ~mask; + writel(cached_irq_mask, base + LPC_IRQ_MASK); + raw_spin_unlock_irqrestore(&lpc_lock, flags); +} -static void lpc_irq_mask_ack(struct irq_data *data) +static void lpc_irq_mask_ack(struct irq_data *irq_data) { - struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data); - struct irq_chip_type *ct = irq_data_get_chip_type(data); - unsigned int mask = data->mask; - - irq_gc_lock(gc); - *ct->mask_cache |= mask; - irq_reg_writel(gc, *ct->mask_cache, ct->regs.mask); - irq_reg_writel(gc, mask, ct->regs.ack); - irq_gc_unlock(gc); + void __iomem *base = irq_data->domain->host_data; + unsigned long flags; + u32 mask = 1 << (irq_data->irq); + + raw_spin_lock_irqsave(&lpc_lock, flags); + cached_irq_mask |= mask; + writel(cached_irq_mask, base + LPC_IRQ_MASK); + writel(mask, base + LPC_IRQ); + raw_spin_unlock_irqrestore(&lpc_lock, flags); } +static struct irq_chip sw64_lpc_chip = { + .name = "LPC-INT", + .irq_mask = lpc_irq_mask, + .irq_unmask = lpc_irq_unmask, + .irq_mask_ack = lpc_irq_mask_ack, + .irq_set_affinity = irq_chip_set_affinity_parent, +}; + static void lpc_irq_handler(struct irq_desc *desc) { - struct lpc_intc_data *b = irq_desc_get_handler_data(desc); + struct irq_domain *domain = irq_desc_get_handler_data(desc); struct irq_chip *chip = irq_desc_get_chip(desc); + void __iomem *base = domain->host_data; unsigned int irq; u32 status; chained_irq_enter(chip, desc); - status = irq_reg_readl(b->gc, LPC_IRQ); + status = readl(base + LPC_IRQ); if (status == 0) { - raw_spin_lock(&desc->lock); handle_bad_irq(desc); - raw_spin_unlock(&desc->lock); goto out; } while (status) { irq = __ffs(status); status &= ~BIT(irq); - generic_handle_irq(irq_find_mapping(b->domain, irq)); + generic_handle_irq(irq_find_mapping(domain, irq)); } out: chained_irq_exit(chip, desc); } +static int sw64_lpc_domain_map(struct irq_domain *d, unsigned int virq, + irq_hw_number_t hw) +{ + struct irq_data *irq_data, *parent_data; + + irq_data = irq_domain_get_irq_data(d, virq); + parent_data = irq_get_irq_data(parent_irq); + if (!parent_data) { + pr_warn("Failed to get lpc parent irq data!\n"); + return -EFAULT; + } + + irq_data->parent_data = parent_data; + + irq_set_chip_and_handler(virq, &sw64_lpc_chip, handle_level_irq); + irq_set_probe(virq); + irq_set_status_flags(virq, IRQ_LEVEL); + + return 0; +} + +static const struct irq_domain_ops sw64_lpc_domain_ops = { + .map = sw64_lpc_domain_map, + .xlate = irq_domain_xlate_onecell, +}; + +struct device_node *sw_lpc_intc_node; +EXPORT_SYMBOL(sw_lpc_intc_node); + static int __init lpc_intc_of_init(struct device_node *np, struct device_node *parent) { - unsigned int set = IRQ_NOPROBE | IRQ_LEVEL; - struct lpc_intc_data *data; - struct irq_chip_type *ct; - int parent_irq, ret; + struct irq_domain *lpc_domain; + int ret; void __iomem *base; - int hwirq = 0; - data = kzalloc(sizeof(*data), GFP_KERNEL); - if (!data) - return -ENOMEM; + sw_lpc_intc_node = np; + + if (!parent) { + pr_err("no parent intc found\n"); + return -ENXIO; + } base = of_iomap(np, 0); if (!base) { @@ -85,53 +145,22 @@ static int __init lpc_intc_of_init(struct device_node *np, goto out_unmap; } - data->domain = irq_domain_add_linear(np, LPC_NR_IRQS, - &irq_generic_chip_ops, NULL); - if (!data->domain) { + lpc_domain = irq_domain_add_legacy(np, LPC_NR_IRQS, + 0, 0, &sw64_lpc_domain_ops, base); + if (!lpc_domain) { ret = -ENOMEM; goto out_unmap; } - /* Allocate a single Generic IRQ chip for this node */ - ret = irq_alloc_domain_generic_chips(data->domain, 16, 1, np->name, - handle_level_irq, 0, set, - IRQ_GC_INIT_MASK_CACHE); - if (ret) { - pr_err("failed to allocate generic irq chip\n"); - goto out_free_domain; - } - /* Set the IRQ chaining logic */ irq_set_chained_handler_and_data(parent_irq, - lpc_irq_handler, data); - - data->gc = irq_get_domain_generic_chip(data->domain, 0); - data->gc->reg_base = base; - data->gc->private = data; - - ct = data->gc->chip_types; - - ct->regs.ack = LPC_IRQ; - ct->regs.mask = LPC_IRQ_MASK; - ct->chip.irq_mask = irq_gc_mask_set_bit; - ct->chip.irq_unmask = irq_gc_mask_clr_bit; - ct->chip.irq_ack = irq_gc_ack_set_bit; - ct->chip.irq_mask_ack = lpc_irq_mask_ack; - - for (hwirq = 0 ; hwirq < 16 ; hwirq++) - irq_create_mapping(data->domain, hwirq); - - /* Enable LPC interrupts */ - writel(0xffffebdd, base + LPC_IRQ_MASK); + lpc_irq_handler, lpc_domain); return 0; -out_free_domain: - irq_domain_remove(data->domain); out_unmap: iounmap(base); out_free: - kfree(data); return ret; } IRQCHIP_DECLARE(sw_lpc_intc, "sw64,lpc_intc", lpc_intc_of_init); diff --git a/drivers/irqchip/irq-sunway-pintc.c b/drivers/irqchip/irq-sunway-pintc.c new file mode 100644 index 000000000000..8d789fd255c8 --- /dev/null +++ b/drivers/irqchip/irq-sunway-pintc.c @@ -0,0 +1,287 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include +#include +#include +#include + +/* + * Multi-node platform device implementation hasn't been thought through yet, + * which means how to obtain CPU node is ambiguous here. It is highly likely + * that this will be passed through ACPI or DTS. Leave node with 0 as default + * for now and wait for platform guys to check this later. + */ +#define DEFAULT_CPU_NODE 0 +static int cpu_node = DEFAULT_CPU_NODE; + +struct devint_chipdata { + int node; +}; + +static DEFINE_RAW_SPINLOCK(devint_lock); +static void lock_dev_lock(void) +{ + raw_spin_lock(&devint_lock); +} + +static void unlock_dev_lock(void) +{ + raw_spin_unlock(&devint_lock); +} + +static void mcu_irq_mask(struct irq_data *data) +{ + struct devint_chipdata *chip_data = data->chip_data; + unsigned int mask; + int hwirq = data->hwirq; + int node; + + node = chip_data->node; + + mask = sw64_io_read(node, MCU_DVC_INT_EN); + mask &= ~(0x1UL << hwirq); + sw64_io_write(node, MCU_DVC_INT_EN, mask); +} + +static void mcu_irq_unmask(struct irq_data *data) +{ + struct devint_chipdata *chip_data = data->chip_data; + unsigned int mask; + int hwirq = data->hwirq; + int node; + + node = chip_data->node; + + mask = sw64_io_read(node, MCU_DVC_INT_EN); + mask |= (0x1UL << hwirq); + sw64_io_write(node, MCU_DVC_INT_EN, mask); +} + +static void mcu_irq_enable(struct irq_data *irq_data) +{ + struct devint_chipdata *data = irq_data->chip_data; + unsigned long devint_conf; + int node; + + node = data->node; + + devint_conf = sw64_io_read(node, DEV_INT_CONFIG); + devint_conf |= (1UL << 8); + sw64_io_write(node, DEV_INT_CONFIG, devint_conf); + mcu_irq_unmask(irq_data); +} + +static void mcu_irq_disable(struct irq_data *irq_data) +{ + struct devint_chipdata *data = irq_data->chip_data; + unsigned long devint_conf; + int node; + + node = data->node; + + devint_conf = sw64_io_read(node, DEV_INT_CONFIG); + devint_conf &= ~(1UL << 8); + sw64_io_write(node, DEV_INT_CONFIG, devint_conf); + mcu_irq_mask(irq_data); +} + +static int __assign_mcu_irq_config(int node, cpumask_t *targets) +{ + unsigned long dev_int_tar, val; + unsigned int cpu; + int phy_cpu; + + for_each_cpu(cpu, targets) { + /* + * Hardware requires dev ints be redirected to on-node + * cores only. Thus, we remove all off-node cpu in the + * target mask. + */ + if (cpu_to_node(cpu) != node) + cpumask_clear_cpu(cpu, targets); + } + + /* Use the last one in valid cpus to avoid core 0. */ + cpu = cpumask_last(targets); + if (cpu >= nr_cpu_ids) + return -EPERM; + + phy_cpu = cpu_to_rcid(cpu); + + val = sw64_io_read(node, DEV_INT_CONFIG); + dev_int_tar = DEV_INT_TARGET(phy_cpu); + val &= 0xffff; + val |= dev_int_tar << 16; + sw64_io_write(node, DEV_INT_CONFIG, val); + + return 0; +} + +static int assign_mcu_irq_config(int node, cpumask_t *targets) +{ + int ret; + + lock_dev_lock(); + ret = __assign_mcu_irq_config(node, targets); + unlock_dev_lock(); + + return ret; +} + +static int mcu_irq_set_affinity(struct irq_data *irq_data, + const struct cpumask *dest, bool force) +{ + struct devint_chipdata *chip_data = irq_data->chip_data; + cpumask_t targets; + int node, ret = 0; + + if (cpumask_any_and(dest, cpu_online_mask) >= nr_cpu_ids) + return -EINVAL; + + cpumask_and(&targets, dest, cpu_online_mask); + + node = chip_data->node; + + mcu_irq_disable(irq_data); + ret = assign_mcu_irq_config(node, &targets); + mcu_irq_enable(irq_data); + + return ret; +} + +static struct irq_chip onchip_intc = { + .name = "MCU-INT", + .irq_enable = mcu_irq_enable, + .irq_disable = mcu_irq_disable, + .irq_mask = mcu_irq_mask, + .irq_unmask = mcu_irq_unmask, + .irq_set_affinity = mcu_irq_set_affinity, +}; + +static struct devint_chipdata * +alloc_sw64_devint_chip_data(struct irq_data *irq_data) +{ + struct devint_chipdata *chip_data; + int node; + + node = irq_data_get_node(irq_data); + chip_data = kzalloc_node(sizeof(*chip_data), GFP_KERNEL, node); + if (!chip_data) + return NULL; + + return chip_data; +} + +static void sw64_intc_free_irqs(struct irq_domain *irq_domain, + unsigned int virq, unsigned int nr_irqs) +{ + struct irq_data *irq_data; + struct devint_chipdata *chip_data; + int i = 0; + + for (i = 0; i < nr_irqs; i++) { + irq_data = irq_domain_get_irq_data(irq_domain, virq + i); + if (irq_data && irq_data->chip_data) { + lock_dev_lock(); + chip_data = irq_data->chip_data; + irq_domain_reset_irq_data(irq_data); + kfree(chip_data); + unlock_dev_lock(); + } + } +} + +static int sw64_intc_alloc_irqs(struct irq_domain *irq_domain, + unsigned int virq, + unsigned int nr_irqs, + void *arg) +{ + struct irq_data *irq_data; + struct devint_chipdata *chip_data; + struct irq_fwspec *fwspec = arg; + int default_node = cpu_node, i = 0, hwirq; + + for (i = 0; i < nr_irqs; i++) { + irq_data = irq_domain_get_irq_data(irq_domain, virq + i); + hwirq = fwspec->param[0]; + irq_data->hwirq = hwirq; + + chip_data = alloc_sw64_devint_chip_data(irq_data); + if (!chip_data) + goto out_free; + + chip_data->node = default_node; + irq_data->chip_data = chip_data; + irq_set_chip_and_handler(virq, &onchip_intc, handle_level_irq); + irq_set_status_flags(virq, IRQ_LEVEL); + } + + return 0; + +out_free: + sw64_intc_free_irqs(irq_domain, virq, nr_irqs); + return -ENOMEM; +} + +static const struct irq_domain_ops sw64_intc_domain_ops = { + .xlate = irq_domain_xlate_onecell, + .alloc = sw64_intc_alloc_irqs, + .free = sw64_intc_free_irqs, +}; + +struct irq_domain *mcu_irq_domain; +EXPORT_SYMBOL(mcu_irq_domain); + +#ifdef CONFIG_OF +static int __init +init_mcu_IRQ(struct device_node *intc, struct device_node *parent) +{ + if (parent) { + pr_warn("DeviceTree incore intc not a root irq controller\n"); + return -ENODEV; + } + + mcu_irq_domain = irq_domain_add_linear(intc, 8, + &sw64_intc_domain_ops, NULL); + + if (!mcu_irq_domain) { + pr_warn("root irq domain not avail\n"); + return -ENODEV; + } + + /* with this we don't need to export root_domain */ + irq_set_default_host(mcu_irq_domain); + + /* mask all interrupts for now */ + sw64_io_write(cpu_node, MCU_DVC_INT_EN, 0x0); + + return 0; +} + +IRQCHIP_DECLARE(sw64_intc, "sw64,sw6_irq_controller", init_mcu_IRQ); + +static int __init +init_mcu_vt_IRQ(struct device_node *intc, struct device_node *parent) +{ + if (parent) { + pr_warn("DeviceTree incore intc not a root irq controller\n"); + return -ENODEV; + } + + mcu_irq_domain = irq_domain_add_legacy(intc, 16, 0, 0, + &sw64_intc_domain_ops, NULL); + + if (!mcu_irq_domain) { + pr_warn("root irq domain not avail\n"); + return -ENODEV; + } + + /* with this we don't need to export root_domain */ + irq_set_default_host(mcu_irq_domain); + + return 0; +} + +IRQCHIP_DECLARE(sw64_vt_intc, "sw64,sw6_irq_vt_controller", init_mcu_vt_IRQ); +#endif diff --git a/drivers/irqchip/irq-sw64-intc-v2.c b/drivers/irqchip/irq-sw64-intc-v2.c deleted file mode 100644 index bc2c8ef3ed2f..000000000000 --- a/drivers/irqchip/irq-sw64-intc-v2.c +++ /dev/null @@ -1,89 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include -#include -#include -#include -#include -#include - -static void fake_irq_mask(struct irq_data *data) -{ -} - -static void fake_irq_unmask(struct irq_data *data) -{ -} - -static struct irq_chip onchip_intc = { - .name = "SW fake Intc", - .irq_mask = fake_irq_mask, - .irq_unmask = fake_irq_unmask, -}; - -static int sw64_intc_domain_map(struct irq_domain *d, unsigned int irq, - irq_hw_number_t hw) -{ - - irq_set_chip_and_handler(irq, &onchip_intc, handle_level_irq); - irq_set_status_flags(irq, IRQ_LEVEL); - return 0; -} - -static const struct irq_domain_ops sw64_intc_domain_ops = { - .xlate = irq_domain_xlate_onecell, - .map = sw64_intc_domain_map, -}; - -#ifdef CONFIG_OF -static struct irq_domain *root_domain; - -static int __init -init_onchip_IRQ(struct device_node *intc, struct device_node *parent) -{ - - int node = 0; - int hwirq = 0, nirq = 8; - - if (parent) - panic("DeviceTree incore intc not a root irq controller\n"); - - root_domain = irq_domain_add_linear(intc, 8, - &sw64_intc_domain_ops, NULL); - - if (!root_domain) - panic("root irq domain not avail\n"); - - /* with this we don't need to export root_domain */ - irq_set_default_host(root_domain); - - for (hwirq = 0 ; hwirq < nirq ; hwirq++) - irq_create_mapping(root_domain, hwirq); - - /*enable MCU_DVC_INT_EN*/ - sw64_io_write(node, MCU_DVC_INT_EN, 0xff); - - return 0; -} - -IRQCHIP_DECLARE(sw64_intc, "sw64,sw6_irq_controller", init_onchip_IRQ); - -static int __init -init_onchip_vt_IRQ(struct device_node *intc, struct device_node *parent) -{ - if (parent) - panic("DeviceTree incore intc not a root irq controller\n"); - - root_domain = irq_domain_add_legacy(intc, 16, 0, 0, - &sw64_intc_domain_ops, NULL); - - if (!root_domain) - panic("root irq domain not avail\n"); - - /* with this we don't need to export root_domain */ - irq_set_default_host(root_domain); - - return 0; -} - -IRQCHIP_DECLARE(sw64_vt_intc, "sw64,sw6_irq_vt_controller", init_onchip_vt_IRQ); -#endif -- Gitee From 9c5c10707d73ae3205c72dd5bafff746972e58f2 Mon Sep 17 00:00:00 2001 From: Lei Yilong Date: Wed, 10 Jan 2024 16:53:30 +0800 Subject: [PATCH 23/49] anolis: sw64: export mclk for guest os ANBZ: #4688 Add a debug file /sys/kernel/debug/sw64/mclk. By reading this file, Qemu can save correct mclk into MB_MCLK of guest to maintain binary compatibility. Signed-off-by: Lei Yilong Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/kernel/setup.c | 15 +++++++++++++++ drivers/clocksource/timer-sw64.c | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/arch/sw_64/kernel/setup.c b/arch/sw_64/kernel/setup.c index eacd6a65595f..0df244c30ed8 100644 --- a/arch/sw_64/kernel/setup.c +++ b/arch/sw_64/kernel/setup.c @@ -1013,6 +1013,21 @@ static int __init debugfs_sw64(void) return 0; } arch_initcall(debugfs_sw64); + +static int __init debugfs_mclk_init(void) +{ + static u64 mclk; + + if (!sw64_debugfs_dir) + return -ENODEV; + + mclk = *((unsigned char *)__va(MB_MCLK)); + debugfs_create_u64("mclk", 0644, sw64_debugfs_dir, &mclk); + + return 0; + +} +late_initcall(debugfs_mclk_init); #endif #ifdef CONFIG_OF diff --git a/drivers/clocksource/timer-sw64.c b/drivers/clocksource/timer-sw64.c index fda7755b99b5..3cbd99f3fe32 100644 --- a/drivers/clocksource/timer-sw64.c +++ b/drivers/clocksource/timer-sw64.c @@ -135,7 +135,7 @@ void __init sw64_setup_clocksource(void) if (is_in_host()) clocksource_register_khz(&clocksource_longtime, mclk * 1000); else - clocksource_register_khz(&clocksource_vtime, DEFAULT_MCLK * 1000); + clocksource_register_khz(&clocksource_vtime, mclk * 1000); #else clocksource_register_hz(&clocksource_tc, get_cpu_freq()); pr_info("Setup clocksource TC, mult = %d\n", clocksource_tc.mult); -- Gitee From 8dd4b03d1ed2e7eb52901d8c6f71e7cdea5f8d58 Mon Sep 17 00:00:00 2001 From: He Chuyue Date: Fri, 5 Jan 2024 14:24:31 +0800 Subject: [PATCH 24/49] anolis: sw64: fix rd_f compatibility issue for C4 ANBZ: #4688 To maintain binary compatibility with existing programs, this patch replaces `rd_f` instruction when the specific exception is caught. Signed-off-by: He Chuyue Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/kernel/traps.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/arch/sw_64/kernel/traps.c b/arch/sw_64/kernel/traps.c index cc14d914c7d4..49edc5f8611e 100644 --- a/arch/sw_64/kernel/traps.c +++ b/arch/sw_64/kernel/traps.c @@ -193,6 +193,32 @@ void simd_emulate(unsigned int inst, unsigned long va) } } +static int try_fix_rd_f(unsigned int inst, struct pt_regs *regs) +{ + int copied; + unsigned int prev_inst, new_inst; + unsigned int ra, prev_ra; + + /* not rd_f */ + if ((inst & 0xfc00ffffU) != 0x18001000) + return -1; + + get_user(prev_inst, (__u32 *)(regs->pc - 8)); + if ((prev_inst & 0xfc00e000U) == 0x20008000) { /* lstw/lstl */ + ra = (inst >> 21) & 0x1f; + prev_ra = (prev_inst >> 21) & 0x1f; + /* ldi ra, 0(prev_ra) */ + new_inst = (0x3e << 26) | (ra << 21) | (prev_ra << 16); + copied = access_process_vm(current, regs->pc - 4, &new_inst, + sizeof(unsigned int), FOLL_FORCE | FOLL_WRITE); + if (copied != sizeof(unsigned int)) + return -1; + regs->pc -= 4; + return 0; + } + return -1; +} + /* * BPT/GENTRAP/OPDEC make regs->pc = exc_pc + 4. debugger should * do something necessary to handle it correctly. @@ -294,6 +320,8 @@ do_entIF(unsigned long inst_type, unsigned long va, struct pt_regs *regs) return; case IF_OPDEC: + if (try_fix_rd_f(inst, regs) == 0) + return; switch (inst) { #ifdef CONFIG_KPROBES case BREAK_KPROBE: -- Gitee From 325055577e297512f791cc4e9f3bdc3a4d967633 Mon Sep 17 00:00:00 2001 From: Jing Li Date: Tue, 16 Jan 2024 11:13:49 +0800 Subject: [PATCH 25/49] anolis: sw64: acpi: fix function acpi_numa_processor_affinity_init() ANBZ: #4688 Signed-off-by: Jing Li Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/kernel/acpi.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/arch/sw_64/kernel/acpi.c b/arch/sw_64/kernel/acpi.c index 452f0e635481..2244bc977c03 100644 --- a/arch/sw_64/kernel/acpi.c +++ b/arch/sw_64/kernel/acpi.c @@ -209,21 +209,24 @@ acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *pa) } if (pa->apic_id >= CONFIG_NR_CPUS) { - pr_err("SRAT: PXM %u -> CPU 0x%02x -> Node %u skipped apicid that is too big\n", pxm, pa->apic_id, node); + pr_err("SRAT: PXM %u -> CPU 0x%02x -> Node %u skipped apicid that is too big\n", + pxm, pa->apic_id, node); return; } /* Record the mapping from logical core id to node id */ cpu = rcid_to_cpu(pa->apic_id); if (cpu < 0) { - pr_err("SRAT: Can not find the logical id for physical Core 0x%02x\n", pa->apic_id); + pr_err("SRAT: Can not find the logical id for physical Core 0x%02x\n", + pa->apic_id); return; } early_map_cpu_to_node(cpu, node); node_set(node, numa_nodes_parsed); - pr_info("SRAT: PXM %u -> CPU 0x%02x -> Node %u\n", pxm, pa->apic_id, node); + pr_info("SRAT: PXM %u -> CPU 0x%02x -> Node %u\n", + pxm, pa->apic_id, node); } #ifdef CONFIG_MEMORY_HOTPLUG -- Gitee From 7518f83b1c249c5245e751aff8debacd950ca9e4 Mon Sep 17 00:00:00 2001 From: Jing Li Date: Wed, 17 Jan 2024 17:01:55 +0800 Subject: [PATCH 26/49] anolis: sw64: fix coding style and typos ANBZ: #4688 Make the coding style conform to linux style without any functional changes. Signed-off-by: Jing Li Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/include/asm/pci.h | 3 +- arch/sw_64/kernel/acpi.c | 13 ++-- arch/sw_64/pci/acpi.c | 112 +++++++++++++++------------- arch/sw_64/pci/pci.c | 35 +++++---- drivers/pci/controller/pci-sunway.c | 62 +++++++++------ 5 files changed, 129 insertions(+), 96 deletions(-) diff --git a/arch/sw_64/include/asm/pci.h b/arch/sw_64/include/asm/pci.h index 2f274e43d118..78ffce917a27 100644 --- a/arch/sw_64/include/asm/pci.h +++ b/arch/sw_64/include/asm/pci.h @@ -94,7 +94,8 @@ extern void __init setup_chip_pci_ops(void); #define setup_chip_pci_ops() do { } while (0) #endif -extern struct pci_controller *pci_bus_to_pci_controller(const struct pci_bus *bus); +extern struct pci_controller * +pci_bus_to_pci_controller(const struct pci_bus *bus); extern struct pci_controller *bus_num_to_pci_controller(unsigned long bus_num); extern void sw64_pci_root_bridge_prepare(struct pci_host_bridge *bridge); diff --git a/arch/sw_64/kernel/acpi.c b/arch/sw_64/kernel/acpi.c index 2244bc977c03..cb03e949cbc6 100644 --- a/arch/sw_64/kernel/acpi.c +++ b/arch/sw_64/kernel/acpi.c @@ -170,10 +170,9 @@ static int rcid_to_cpu(int physical_id) { int i; - for (i = 0; i < NR_CPUS; ++i) { + for (i = 0; i < ARRAY_SIZE(__cpu_to_rcid); ++i) if (__cpu_to_rcid[i] == physical_id) return i; - } /* physical id not found */ return -1; @@ -298,9 +297,9 @@ EXPORT_SYMBOL(acpi_unmap_cpu); static bool __init is_rcid_duplicate(int rcid) { - unsigned int i; + int i; - for (i = 0; (i < possible_cores) && (i < NR_CPUS); i++) { + for_each_possible_cpu(i) { if (cpu_to_rcid(i) == rcid) return true; } @@ -406,11 +405,11 @@ static int __init acpi_parse_sw_cintc(union acpi_subtable_headers *header, static int __init acpi_process_madt_sw_cintc(void) { - int logical_core, ret; + int i, ret; /* Clean the map from logical core ID to physical core ID */ - for (logical_core = 0; logical_core < NR_CPUS; ++logical_core) - set_rcid_map(logical_core, -1); + for (i = 0; i < ARRAY_SIZE(__cpu_to_rcid); ++i) + set_rcid_map(i, -1); /* Clean core mask */ init_cpu_possible(cpu_none_mask); diff --git a/arch/sw_64/pci/acpi.c b/arch/sw_64/pci/acpi.c index 9b465628c6e9..f1223dd700bd 100644 --- a/arch/sw_64/pci/acpi.c +++ b/arch/sw_64/pci/acpi.c @@ -42,6 +42,7 @@ pci_acpi_setup_ecam_mapping(struct acpi_pci_root *root) struct resource *bus_res = &root->secondary; struct resource cfg_res; struct acpi_device *adev = NULL; + resource_size_t bus_res_size; int ret = 0, bus_shift = 0; u16 seg = root->segment; @@ -53,11 +54,12 @@ pci_acpi_setup_ecam_mapping(struct acpi_pci_root *root) /** * Do the quirk of bus shift here, since we can not - * know the ECAM addr in MCFG table when fill mcfg_quirks + * get the ECAM addr when fill mcfg_quirks. */ bus_shift = ecam_ops->bus_shift; cfg_res.start = root->mcfg_addr + (bus_res->start << bus_shift); - cfg_res.end = cfg_res.start + ((resource_size(bus_res)) << bus_shift) - 1; + bus_res_size = resource_size(bus_res); + cfg_res.end = cfg_res.start + (bus_res_size << bus_shift) - 1; cfg_res.flags = IORESOURCE_MEM; /** @@ -87,66 +89,66 @@ static int pci_acpi_prepare_root_resources(struct acpi_pci_root_info *ci) { int status = 0; acpi_status rc; - unsigned long long mem_space_base = 0; + unsigned long long memh = 0; struct resource_entry *entry = NULL, *tmp = NULL; struct acpi_device *device = ci->bridge; + /** + * To distinguish between mem and pre_mem, firmware + * only pass the lower 32bits of mem via acpi and + * use vendor specific "MEMH" to record the upper + * 32 bits of mem. + * + * Get the upper 32 bits here. + */ + rc = acpi_evaluate_integer(ci->bridge->handle, "MEMH", NULL, &memh); + if (rc != AE_OK) { + dev_err(&device->dev, "unable to retrieve MEMH\n"); + return -EEXIST; + } + /** * Get host bridge resources via _CRS method, the return value * is the num of resource parsed. */ status = acpi_pci_probe_root_resources(ci); - if (status > 0) { + if (status <= 0) { /** - * To distinguish between mem and pre_mem, firmware only pass the - * lower 32bits of mem via acpi and use vendor specific "MEMH" to - * record the upper 32 bits of mem. - * - * Get the upper 32 bits here. + * If not successfully parse resources, destroy + * resources which have been parsed. */ - rc = acpi_evaluate_integer(ci->bridge->handle, - "MEMH", NULL, &mem_space_base); - if (rc != AE_OK) { - dev_err(&device->dev, "unable to retrieve MEMH\n"); - return -EEXIST; - } - resource_list_for_each_entry_safe(entry, tmp, &ci->resources) { - if (entry->res->flags & IORESOURCE_MEM) { - if (!(entry->res->end & 0xFFFFFFFF00000000ULL)) { - /* Patch the mem resource with upper 32 bits */ - entry->res->start |= (mem_space_base << 32); - entry->res->end |= (mem_space_base << 32); - } else { - /** - * Add PREFETCH and MEM_64 flags for pre_mem, - * so that we can distinguish between mem and - * pre_mem. - */ - entry->res->flags |= IORESOURCE_PREFETCH; - entry->res->flags |= IORESOURCE_MEM_64; - } - } - - dev_dbg(&device->dev, - "host bridge resource: 0x%llx-0x%llx flags [0x%lx]\n", - entry->res->start, entry->res->end, entry->res->flags); + dev_info(&device->dev, + "host bridge resource(ignored): %pR\n", + entry->res); + resource_list_destroy_entry(entry); } - return status; + + return 0; } - /** - * If not successfully parse resources, destory - * resources which have been parsed. - */ resource_list_for_each_entry_safe(entry, tmp, &ci->resources) { - dev_info(&device->dev, - "host bridge resource(ignored): 0x%llx-0x%llx flags [0x%lx]\n", - entry->res->start, entry->res->end, entry->res->flags); - resource_list_destroy_entry(entry); + if (entry->res->flags & IORESOURCE_MEM) { + if (!(entry->res->end & 0xFFFFFFFF00000000ULL)) { + /* Patch mem res with upper 32 bits */ + entry->res->start |= (memh << 32); + entry->res->end |= (memh << 32); + } else { + /** + * Add PREFETCH and MEM_64 flags for + * pre_mem, so that we can distinguish + * between mem and pre_mem. + */ + entry->res->flags |= IORESOURCE_PREFETCH; + entry->res->flags |= IORESOURCE_MEM_64; + } + } + + dev_dbg(&device->dev, + "host bridge resource: %pR\n", entry->res); } - return 0; + return status; } /** @@ -179,21 +181,26 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) bus = pci_find_bus(domain, busnum); if (bus) { - memcpy(bus->sysdata, pci_ri->cfg, sizeof(struct pci_config_window)); + memcpy(bus->sysdata, pci_ri->cfg, + sizeof(struct pci_config_window)); kfree(pci_ri->cfg); kfree(pci_ri); kfree(root_ops); } else { - bus = acpi_pci_root_create(root, root_ops, &pci_ri->info, pci_ri->cfg); + bus = acpi_pci_root_create(root, root_ops, + &pci_ri->info, pci_ri->cfg); /** - * No need to do kfree here, because acpi_pci_root_create will free - * mem alloced when it cannot create pci_bus. + * No need to do kfree here, because acpi_pci_root_create + * will free mem alloced when it cannot create pci_bus. */ if (!bus) return NULL; - /* Some quirks for pci controller of Sunway after scanning Root Complex */ + /** + * Some quirks for pci controller of Sunway + * after scanning Root Complex + */ sw64_pci_root_bridge_scan_finish_up(pci_find_host_bridge(bus)); pci_bus_size_bridges(bus); @@ -227,7 +234,10 @@ int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge) ACPI_COMPANION_SET(&bridge->dev, adev); set_dev_node(bus_dev, hose->node); - /* Some quirks for pci controller of Sunway before scanning Root Complex */ + /** + * Some quirks for pci controller of Sunway + * before scanning Root Complex + */ sw64_pci_root_bridge_prepare(bridge); } diff --git a/arch/sw_64/pci/pci.c b/arch/sw_64/pci/pci.c index ccdf1cbda373..11ff6df3505c 100644 --- a/arch/sw_64/pci/pci.c +++ b/arch/sw_64/pci/pci.c @@ -130,7 +130,8 @@ void pcibios_fixup_bus(struct pci_bus *bus) * Provide information on locations of various I/O regions in physical * memory. Do this on a per-card basis so that we choose the right hose. */ -asmlinkage long sys_pciconfig_iobase(long which, unsigned long bus, unsigned long dfn) +asmlinkage long +sys_pciconfig_iobase(long which, unsigned long bus, unsigned long dfn) { struct pci_controller *hose; @@ -172,7 +173,8 @@ void __init reserve_mem_for_pci(void) return; } - pr_info("reserved pages for pcie memory space %lx:%lx\n", base >> PAGE_SHIFT, + pr_info("reserved pages for pcie memory space %lx:%lx\n", + base >> PAGE_SHIFT, (base + PCI_32BIT_MEMIO_SIZE) >> PAGE_SHIFT); } @@ -184,7 +186,8 @@ static void quirk_isa_bridge(struct pci_dev *dev) { dev->class = PCI_CLASS_BRIDGE_ISA << 8; } -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82378, quirk_isa_bridge); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82378, + quirk_isa_bridge); /* * Early fix up the Root Complex settings @@ -246,8 +249,10 @@ static void enable_sw_dca(struct pci_dev *dev) continue; else { dca_conf = (1UL << 63) | (dev->bus->number << 8) | dev->devfn; - pr_info("dca device index %d, dca_conf = %#lx\n", i, dca_conf); - write_piu_ior1(node, rc_index, DEVICEID0 + (i << 7), dca_conf); + pr_info("dca device index %d, dca_conf = %#lx\n", + i, dca_conf); + write_piu_ior1(node, rc_index, + DEVICEID0 + (i << 7), dca_conf); break; } } @@ -283,7 +288,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, enable_sw_dca); * A question: when there is too much RCs, may 256 bus * numbers be insufficient? */ -static unsigned char last_bus = 0; +static unsigned char last_bus; void sw64_pci_root_bridge_prepare(struct pci_host_bridge *bridge) { @@ -319,7 +324,8 @@ void sw64_pci_root_bridge_prepare(struct pci_host_bridge *bridge) * So, need to update bus num of pci host bridge here. */ bridge->busnr = last_bus; - dev_set_name(&bridge->dev, "pci%04x:%02x", pci_domain_nr(bus), last_bus); + dev_set_name(&bridge->dev, "pci%04x:%02x", + pci_domain_nr(bus), last_bus); /** * At this point, pci_bus has been created and use old @@ -338,7 +344,8 @@ void sw64_pci_root_bridge_prepare(struct pci_host_bridge *bridge) pci_add_flags(PCI_REASSIGN_ALL_BUS); } -static void sw64_pci_root_bridge_reserve_legacy_io(struct pci_host_bridge *bridge) +static void +sw64_pci_root_bridge_reserve_legacy_io(struct pci_host_bridge *bridge) { struct pci_bus *bus = bridge->bus; struct resource_entry *entry = NULL; @@ -349,10 +356,8 @@ static void sw64_pci_root_bridge_reserve_legacy_io(struct pci_host_bridge *bridg continue; res = kzalloc(sizeof(struct resource), GFP_KERNEL); - if (res == NULL) { - pr_err("alloc resource for legacy io out of mem\n"); + if (WARN_ON(!res)) return; - } res->name = "legacy io"; res->flags = IORESOURCE_IO; @@ -421,11 +426,11 @@ void sw64_pci_root_bridge_scan_finish_up(struct pci_host_bridge *bridge) * * > echo 1 > /sys/bus/pci/rescan * - * Unexpected errors may occur on the endpoint devices due to the re-assign - * bus numbers of upstream bridges. + * Unexpected errors may occur on the endpoint devices due to the + * re-assign bus numbers of upstream bridges. * - * To work around this problem, the flag PCI_REASSIGN_ALL_BUS is set before - * scanning Root Complex and cleared after scanning Root Complex. + * To work around this problem, the flag PCI_REASSIGN_ALL_BUS is set + * before scanning Root Complex and cleared after scanning Root Complex. */ pci_clear_flags(PCI_REASSIGN_ALL_BUS); } diff --git a/drivers/pci/controller/pci-sunway.c b/drivers/pci/controller/pci-sunway.c index d524a1d15185..c58fdea39f17 100644 --- a/drivers/pci/controller/pci-sunway.c +++ b/drivers/pci/controller/pci-sunway.c @@ -2,8 +2,8 @@ #include #include #include +#include -#include #include void set_devint_wken(int node) @@ -27,10 +27,12 @@ void set_adr_int(int node) void set_pcieport_service_irq(int node, int index) { if (IS_ENABLED(CONFIG_PCIE_PME)) - write_piu_ior0(node, index, PMEINTCONFIG, PME_ENABLE_INTD_CORE0); + write_piu_ior0(node, index, + PMEINTCONFIG, PME_ENABLE_INTD_CORE0); if (IS_ENABLED(CONFIG_PCIEAER)) - write_piu_ior0(node, index, AERERRINTCONFIG, AER_ENABLE_INTD_CORE0); + write_piu_ior0(node, index, + AERERRINTCONFIG, AER_ENABLE_INTD_CORE0); } int chip_pcie_configure(struct pci_controller *hose) @@ -133,7 +135,7 @@ int chip_pcie_configure(struct pci_controller *hose) write_piu_ior0(node, rc_index, PIUCONFIG0, piuconfig0); } - printk("Node%ld RC%ld MPSS %luB, MRRS %luB, Piuconfig0 %#lx, ARI %s\n", + pr_info("Node%ld RC%ld MPSS %luB, MRRS %luB, Piuconfig0 %#lx, ARI %s\n", node, rc_index, (1UL << smallest_max_payload) << 7, (1UL << max_read_size) << 7, piuconfig0, rc_ari_disabled ? "disabled" : "enabled"); @@ -162,10 +164,12 @@ int chip_pcie_configure(struct pci_controller *hose) if (pcie_caps_offset == 0) continue; - pci_read_config_word(dev, pcie_caps_offset + PCI_EXP_DEVCTL, &devctl); + pci_read_config_word(dev, + pcie_caps_offset + PCI_EXP_DEVCTL, &devctl); devctl &= ~(PCI_EXP_DEVCTL_PAYLOAD | PCI_EXP_DEVCTL_READRQ); devctl |= new_values; - pci_write_config_word(dev, pcie_caps_offset + PCI_EXP_DEVCTL, devctl); + pci_write_config_word(dev, + pcie_caps_offset + PCI_EXP_DEVCTL, devctl); } return bus_max_num; @@ -213,7 +217,8 @@ static void set_rc_piu(unsigned long node, unsigned long index) /* set PCI-E root class code */ value = read_rc_conf(node, index, RC_REVISION_ID); - write_rc_conf(node, index, RC_REVISION_ID, (PCI_CLASS_BRIDGE_HOST << 16) | value); + write_rc_conf(node, index, RC_REVISION_ID, + (PCI_CLASS_BRIDGE_HOST << 16) | value); /* disable DBI_RO_WR_EN */ write_rc_conf(node, index, RC_MISC_CONTROL_1, rc_misc_ctrl); @@ -229,8 +234,8 @@ static void set_rc_piu(unsigned long node, unsigned long index) if (IS_ENABLED(CONFIG_PCI_MSI)) { write_piu_ior0(node, index, MSIADDR, MSIX_MSG_ADDR); #ifdef CONFIG_UNCORE_XUELANG - for (i = 0; i < 256; i++) - write_piu_ior0(node, index, MSICONFIG0 + (i << 7), 0); + for (i = 0; i < 256; i++) + write_piu_ior0(node, index, MSICONFIG0 + (i << 7), 0); #endif } } @@ -303,7 +308,8 @@ static void hose_init(struct pci_controller *hose) hose->pre_mem_space->flags = IORESOURCE_MEM | IORESOURCE_PREFETCH | IORESOURCE_MEM_64; if (request_resource(&iomem_resource, hose->pre_mem_space) < 0) - pr_err("Failed to request 64bit MEM on hose %ld\n", hose->index); + pr_err("Failed to request 64bit MEM on hose %ld\n", + hose->index); hose->io_space->start = pci_io_base | PCI_LEGACY_IO; hose->io_space->end = hose->io_space->start + PCI_LEGACY_IO_SIZE - 1; hose->io_space->name = "pci io space"; @@ -407,7 +413,9 @@ static int sw64_pcie_read_rc_cfg(struct pci_bus *bus, unsigned int devfn, if (IS_ENABLED(CONFIG_PCI_DEBUG)) pr_debug("rc read addr:%px bus %d, devfn %#x, where %#x size=%d\t", - cfg_iobase + ((where & ~3) << 5), bus->number, devfn, where, size); + cfg_iobase + ((where & ~3) << 5), + bus->number, + devfn, where, size); if ((uintptr_t)where & (size - 1)) { *val = 0; @@ -475,7 +483,9 @@ int sw64_pcie_write_rc_cfg(struct pci_bus *bus, unsigned int devfn, if (IS_ENABLED(CONFIG_PCI_DEBUG)) pr_debug("rc write addr:%px bus %d, devfn %#x, where %#x *val %#x size %d\n", - cfg_iobase + ((where & ~3) << 5), bus->number, devfn, where, val, size); + cfg_iobase + ((where & ~3) << 5), + bus->number, + devfn, where, val, size); writel(data, cfg_iobase + ((where & ~3) << 5)); @@ -483,7 +493,9 @@ int sw64_pcie_write_rc_cfg(struct pci_bus *bus, unsigned int devfn, } /** - * sw64_pcie_valid_device - check if a valid device is present on bus + * sw64_pcie_valid_device - check if a valid device is present + * on bus + * * @bus : PCI bus structure * @devfn: device/function * @@ -503,7 +515,9 @@ static bool sw64_pcie_valid_device(struct pci_bus *bus, unsigned int devfn) } /** - * sw64_pcie_config_read - read val from config space of PCI host controller or device + * sw64_pcie_config_read - read val from config space of + * PCI host controller or device + * * @bus : PCI bus structure * @devfn: device/function * @where: offset from base @@ -527,7 +541,8 @@ static int sw64_pcie_config_read(struct pci_bus *bus, unsigned int devfn, ret = sw64_pcie_read_rc_cfg(bus, devfn, where, size, val); } else { if (pci_get_rc_linkup(hose->node, hose->index)) { - ret = pci_generic_config_read(bus, devfn, where, size, val); + ret = pci_generic_config_read(bus, devfn, + where, size, val); } else { return ret; } @@ -536,7 +551,9 @@ static int sw64_pcie_config_read(struct pci_bus *bus, unsigned int devfn, } /** - * sw64_pcie_config_write - write val to config space of PCI host controller or device + * sw64_pcie_config_write - write val to config space of PCI + * host controller or device + * * @bus : PCI bus structure * @devfn: device/function * @where: offset from base @@ -668,21 +685,24 @@ static int sw64_pci_prepare_controller(struct pci_controller *hose, * pass Endpoint config space base address, and define Root Complex * config space base address("RCCB") separately in the ACPI namespace. */ - rc = acpi_evaluate_integer(adev->handle, "RCCB", NULL, &rc_config_base_addr); + rc = acpi_evaluate_integer(adev->handle, + "RCCB", NULL, &rc_config_base_addr); if (rc != AE_OK) { dev_err(&adev->dev, "unable to retrieve RCCB\n"); return -EEXIST; } /* Get Root Complex I/O space base addr from ACPI namespace */ - rc = acpi_evaluate_integer(adev->handle, "RCIO", NULL, &pci_io_base_addr); + rc = acpi_evaluate_integer(adev->handle, + "RCIO", NULL, &pci_io_base_addr); if (rc != AE_OK) { dev_err(&adev->dev, "unable to retrieve RCIO\n"); return -EEXIST; } /* Get Endpoint I/O space base addr from ACPI namespace */ - rc = acpi_evaluate_integer(adev->handle, "EPIO", NULL, &ep_io_base_addr); + rc = acpi_evaluate_integer(adev->handle, + "EPIO", NULL, &ep_io_base_addr); if (rc != AE_OK) { dev_err(&adev->dev, "unable to retrieve EPIO\n"); return -EEXIST; @@ -770,10 +790,8 @@ static int sw64_pci_ecam_init(struct pci_config_window *cfg) } hose = kzalloc(sizeof(*hose), GFP_KERNEL); - if (!hose) { - dev_err(dev, "out of memory when alloc mem for pci_controller\n"); + if (!hose) return -ENOMEM; - } /* Get Endpoint config space base address from MCFG table */ mcfg_addr = cfg->res.start - (cfg->busr.start << cfg->ops->bus_shift); -- Gitee From f7c59c2ebec5741f14a320921ceaecd61c96fcce Mon Sep 17 00:00:00 2001 From: Jing Li Date: Wed, 10 Jan 2024 16:45:32 +0800 Subject: [PATCH 27/49] anolis: sw64: dts: fix properties for spi controller device node ANBZ: #4688 Fix #address-cells and #size-cells. Remove unused properties and related code in driver. Signed-off-by: Jing Li Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/boot/dts/chip3.dts | 24 ++++++++---------------- drivers/spi/spi-chip3-mmio.c | 6 ------ 2 files changed, 8 insertions(+), 22 deletions(-) diff --git a/arch/sw_64/boot/dts/chip3.dts b/arch/sw_64/boot/dts/chip3.dts index 082506393ac9..502903040bbd 100644 --- a/arch/sw_64/boot/dts/chip3.dts +++ b/arch/sw_64/boot/dts/chip3.dts @@ -127,24 +127,20 @@ pvt: pvt@0x8030 { }; spi: spi@0x8032 { - #address-cells = <2>; - #size-cells = <2>; + #address-cells = <1>; + #size-cells = <0>; compatible = "sunway,chip3-spi"; reg = <0x8032 0x0 0x0 0x8000>; clocks = <&spiclk>; - interrupt-parent=<&intc>; - interrupts = <4>; + poll_mode = <1>; /* poll_mode:1 interrupt mode: 0 */ + reg-io-width = <2>; status = "okay"; flash@0 { - compatible = "winbond,w25q32dw", "jedec,spi-flash"; + compatible = "winbond,w25q32dw", "jedec,spi-nor"; spi-max-frequency = <25000000>; m25p,fast-read; - spi-cpha; - spi-cpol; - poll_mode = <1>; /* poll_mode:1 interrupt mode: 0 */ - reg-io-width = <2>; - reg = <0 0 0 0 >; /* 0: flash chip selected bit */ + reg = <0>; /* 0: flash chip selected bit */ partitions { compatible = "fixed-partitions"; @@ -159,14 +155,10 @@ partition@0 { }; flash@1 { - compatible = "winbond,w25q32dw", "jedec,spi-flash"; + compatible = "winbond,w25q32dw", "jedec,spi-nor"; spi-max-frequency = <25000000>; m25p,fast-read; - spi-cpha; - spi-cpol; - poll_mode = <1>; /* poll_mode:1 interrupt mode: 0 */ - reg-io-width = <2>; - reg = <1 0 0 0 >; /* 1: flash chip selected bit */ + reg = <1>; /* 1: flash chip selected bit */ partitions { compatible = "fixed-partitions"; diff --git a/drivers/spi/spi-chip3-mmio.c b/drivers/spi/spi-chip3-mmio.c index 3a76382e0fd9..1a1a9feaffa9 100644 --- a/drivers/spi/spi-chip3-mmio.c +++ b/drivers/spi/spi-chip3-mmio.c @@ -53,12 +53,6 @@ static int chip3_spi_mmio_probe(struct platform_device *pdev) return PTR_ERR(dws->regs); } - dws->irq = platform_get_irq(pdev, 0); - if (dws->irq < 0) { - dev_err(&pdev->dev, "no irq resource?\n"); - return dws->irq; /* -ENXIO */ - } - dwsmmio->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(dwsmmio->clk)) return PTR_ERR(dwsmmio->clk); -- Gitee From 16738324662c07f0940f187ccf6456c4e8a6a7f7 Mon Sep 17 00:00:00 2001 From: Jing Li Date: Mon, 15 Jan 2024 09:27:28 +0800 Subject: [PATCH 28/49] anolis: sw64: dts: add chosen node ANBZ: #4688 It is better to have a chosen node in the device tree. If not present, the newer kernel will give a warning. Signed-off-by: Jing Li Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/boot/dts/chip3.dts | 11 +++++++---- arch/sw_64/boot/dts/chip_vt.dts | 11 +++++++---- arch/sw_64/boot/dts/empty.dts | 11 +++++++---- 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/arch/sw_64/boot/dts/chip3.dts b/arch/sw_64/boot/dts/chip3.dts index 502903040bbd..587f9427cbf6 100644 --- a/arch/sw_64/boot/dts/chip3.dts +++ b/arch/sw_64/boot/dts/chip3.dts @@ -5,10 +5,13 @@ /dts-v1/; / { - compatible = "sunway,chip3"; - model = "chip3"; - #address-cells = <2>; - #size-cells = <2>; + compatible = "sunway,chip3"; + model = "chip3"; + #address-cells = <2>; + #size-cells = <2>; + + chosen { + }; soc { compatible = "simple-bus"; diff --git a/arch/sw_64/boot/dts/chip_vt.dts b/arch/sw_64/boot/dts/chip_vt.dts index f26285367f98..0c7227755b1c 100644 --- a/arch/sw_64/boot/dts/chip_vt.dts +++ b/arch/sw_64/boot/dts/chip_vt.dts @@ -5,10 +5,13 @@ /dts-v1/; / { - compatible = "sunway,chip3"; - model = "chip3"; - #address-cells = <2>; - #size-cells = <2>; + compatible = "sunway,chip3"; + model = "chip3"; + #address-cells = <2>; + #size-cells = <2>; + + chosen { + }; soc { compatible = "simple-bus"; diff --git a/arch/sw_64/boot/dts/empty.dts b/arch/sw_64/boot/dts/empty.dts index f8fe34e29641..367f75d43107 100644 --- a/arch/sw_64/boot/dts/empty.dts +++ b/arch/sw_64/boot/dts/empty.dts @@ -5,10 +5,13 @@ /dts-v1/; / { - compatible = "sunway,chip3"; - model = "chip3"; - #address-cells = <2>; - #size-cells = <2>; + compatible = "sunway,chip3"; + model = "chip3"; + #address-cells = <2>; + #size-cells = <2>; + + chosen { + }; soc { }; -- Gitee From 7621ff4d99a88332edc1a3cf992cc90682563864 Mon Sep 17 00:00:00 2001 From: Jing Li Date: Mon, 15 Jan 2024 09:28:41 +0800 Subject: [PATCH 29/49] anolis: sw64: dts: fix interrupt related properties for GPIO ANBZ: #4688 The GPIO controller can send two interrupts to the parent interrupt controller. Signed-off-by: Jing Li Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/boot/dts/chip3.dts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/arch/sw_64/boot/dts/chip3.dts b/arch/sw_64/boot/dts/chip3.dts index 587f9427cbf6..0a1ef5305351 100644 --- a/arch/sw_64/boot/dts/chip3.dts +++ b/arch/sw_64/boot/dts/chip3.dts @@ -226,10 +226,9 @@ porta: gpio-contraller@0 { reg = <0 0 0 0>; interrupt-controller; #interrupt-cells = <2>; - interrupt-parent=<&intc>; - interrupts = <0>; - }; + interrupts-extended = <&intc 0>, <&intc 1>; }; + }; }; }; -- Gitee From 585d42b2c910d841cb09882f6825c1bccc3705da Mon Sep 17 00:00:00 2001 From: Jing Li Date: Mon, 15 Jan 2024 11:14:21 +0800 Subject: [PATCH 30/49] anolis: sw64: dts: improve properties for LPC-INTC ANBZ: #4688 Add some SW64 specific properties: sw64,node : interrupt controller on which node sw64,irq-num : number of interrupts supported sw64,ver : hardware version It should be noted that the LPC-INTC device node will no longer maintain backward compatibility after this commit. Signed-off-by: Jing Li Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/boot/dts/chip3.dts | 3 ++ drivers/irqchip/irq-sunway-lpc-intc.c | 40 ++++++++++++++++++++------- 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/arch/sw_64/boot/dts/chip3.dts b/arch/sw_64/boot/dts/chip3.dts index 0a1ef5305351..c60c84074dfc 100644 --- a/arch/sw_64/boot/dts/chip3.dts +++ b/arch/sw_64/boot/dts/chip3.dts @@ -45,6 +45,9 @@ lpc_intc: interrupt-controller@0x8037 { compatible = "sw64,lpc_intc"; reg = <0x8037 0x40000000 0x0 0x8000>; interrupt-controller; + sw64,node = <0>; + sw64,irq-num = <16>; + sw64,ver = <1>; #interrupt-cells = <1>; interrupt-parent = <&intc>; interrupts = <2>; diff --git a/drivers/irqchip/irq-sunway-lpc-intc.c b/drivers/irqchip/irq-sunway-lpc-intc.c index b594ddb6eb24..bc69d1647aed 100644 --- a/drivers/irqchip/irq-sunway-lpc-intc.c +++ b/drivers/irqchip/irq-sunway-lpc-intc.c @@ -7,7 +7,8 @@ #include #include -#define LPC_NR_IRQS 16 +#define PREFIX "LPC-INTC: " + #define LPC_IRQ 0x4 #define LPC_IRQ_MASK 0x8 @@ -122,36 +123,56 @@ static int __init lpc_intc_of_init(struct device_node *np, { struct irq_domain *lpc_domain; int ret; + u32 nr_irqs, node, version; void __iomem *base; + if (WARN_ON(!np || !parent)) + return -ENODEV; + sw_lpc_intc_node = np; - if (!parent) { - pr_err("no parent intc found\n"); - return -ENXIO; + ret = of_property_read_u32(np, "sw64,node", &node); + if (ret) { + pr_err(PREFIX "\"sw64,node\" not found\n"); + return -EINVAL; + } + + ret = of_property_read_u32(np, "sw64,irq-num", &nr_irqs); + if (ret) { + pr_err(PREFIX "\"sw64,irq-num\" not found\n"); + return -EINVAL; + } + + ret = of_property_read_u32(np, "sw64,ver", &version); + if (ret) { + pr_err(PREFIX "\"sw64,ver\" not found\n"); + return -EINVAL; } base = of_iomap(np, 0); if (!base) { - pr_err("failed to remap lpc intc registers\n"); - ret = -ENOMEM; - goto out_free; + pr_err(PREFIX "failed to remap lpc intc registers\n"); + return -ENXIO; } parent_irq = irq_of_parse_and_map(np, 0); if (!parent_irq) { - pr_err("failed to find parent interrupt\n"); + pr_err(PREFIX "failed to find parent interrupt\n"); ret = -EINVAL; goto out_unmap; } - lpc_domain = irq_domain_add_legacy(np, LPC_NR_IRQS, + lpc_domain = irq_domain_add_legacy(np, nr_irqs, 0, 0, &sw64_lpc_domain_ops, base); if (!lpc_domain) { + pr_err(PREFIX "failed to create irq domain\n"); ret = -ENOMEM; goto out_unmap; } + pr_info(PREFIX "version [%u] on node [%u] initialized\n", + version, node); + /* Set the IRQ chaining logic */ irq_set_chained_handler_and_data(parent_irq, lpc_irq_handler, lpc_domain); @@ -160,7 +181,6 @@ static int __init lpc_intc_of_init(struct device_node *np, out_unmap: iounmap(base); -out_free: return ret; } IRQCHIP_DECLARE(sw_lpc_intc, "sw64,lpc_intc", lpc_intc_of_init); -- Gitee From 93d93548d4fea82be2a84450c2315be690e0abd2 Mon Sep 17 00:00:00 2001 From: Jing Li Date: Tue, 16 Jan 2024 10:16:37 +0800 Subject: [PATCH 31/49] anolis: sw64: dts: improve properties for PINTC ANBZ: #4688 Firstly, add some SW64 specific properties: sw64,node : interrupt controller on which node sw64,irq-num : number of interrupts supported sw64,ver : hardware version Secondly, the "reg" property is added to pass the base address of PINTC registers, decoupling the driver code and hardware. Thirdly, some refactoring is done, making each PINTC chip a chip data instead of each irq a chip data. It should be noted that the PINTC device node will no longer maintain backward compatibility after this commit. Signed-off-by: Jing Li Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/boot/dts/chip3.dts | 21 +- arch/sw_64/boot/dts/chip_vt.dts | 13 +- arch/sw_64/include/asm/uncore_io_junzhang.h | 2 - arch/sw_64/include/asm/uncore_io_xuelang.h | 2 - drivers/irqchip/irq-sunway-pintc.c | 306 +++++++++++--------- 5 files changed, 193 insertions(+), 151 deletions(-) diff --git a/arch/sw_64/boot/dts/chip3.dts b/arch/sw_64/boot/dts/chip3.dts index c60c84074dfc..0e9ad8f5d464 100644 --- a/arch/sw_64/boot/dts/chip3.dts +++ b/arch/sw_64/boot/dts/chip3.dts @@ -35,9 +35,14 @@ spiclk: spiclk { }; - intc: interrupt-controller { - compatible = "sw64,sw6_irq_controller"; + pintc: interrupt-controller { + compatible = "sw64,pintc"; interrupt-controller; + sw64,node = <0>; + sw64,irq-num = <8>; + sw64,ver = <1>; + reg = <0x802a 0x0 0x0 0x1680>, + <0x8030 0x0 0x0 0x8f00>; #interrupt-cells = <1>; }; @@ -49,7 +54,7 @@ lpc_intc: interrupt-controller@0x8037 { sw64,irq-num = <16>; sw64,ver = <1>; #interrupt-cells = <1>; - interrupt-parent = <&intc>; + interrupt-parent = <&pintc>; interrupts = <2>; }; @@ -58,7 +63,7 @@ uart: serial0@8033 { #size-cells = <2>; compatible = "sw6,sunway-apb-uart"; reg = <0x8033 0x0 0x0 0x1000>; - interrupt-parent=<&intc>; + interrupt-parent=<&pintc>; interrupts = <3>; reg-shift = <9>; reg-io-width = <4>; @@ -85,7 +90,7 @@ i2c0@0x8031 { reg = <0x8031 0x0 0x0 0x8000>; clock-frequency = <100000>; clocks = <&i2cclk>; - interrupt-parent=<&intc>; + interrupt-parent = <&pintc>; interrupts = <5>; status = "okay"; }; @@ -97,7 +102,7 @@ i2c1@0x8034 { reg = <0x8034 0x0 0x0 0x8000>; clock-frequency = <100000>; clocks = <&i2cclk>; - interrupt-parent=<&intc>; + interrupt-parent = <&pintc>; interrupts = <6>; status = "okay"; }; @@ -109,7 +114,7 @@ i2c2@0x8035 { reg = <0x8035 0x0 0x0 0x8000>; clock-frequency = <100000>; clocks = <&i2cclk>; - interrupt-parent=<&intc>; + interrupt-parent = <&pintc>; interrupts = <7>; status = "okay"; @@ -229,7 +234,7 @@ porta: gpio-contraller@0 { reg = <0 0 0 0>; interrupt-controller; #interrupt-cells = <2>; - interrupts-extended = <&intc 0>, <&intc 1>; + interrupts-extended = <&pintc 0>, <&pintc 1>; }; }; diff --git a/arch/sw_64/boot/dts/chip_vt.dts b/arch/sw_64/boot/dts/chip_vt.dts index 0c7227755b1c..9889fcae7a5c 100644 --- a/arch/sw_64/boot/dts/chip_vt.dts +++ b/arch/sw_64/boot/dts/chip_vt.dts @@ -19,9 +19,12 @@ soc { #size-cells = <2>; ranges; - intc: interrupt-controller{ - compatible = "sw64,sw6_irq_vt_controller"; + pintc: interrupt-controller { + compatible = "sw64,pintc_vt"; interrupt-controller; + sw64,node = <0>; + sw64,irq-num = <16>; + sw64,ver = <1>; #interrupt-cells = <1>; }; @@ -30,25 +33,27 @@ uart: serial0@8801 { #size-cells = <2>; compatible = "ns16550a"; reg = <0x8801 0x3f8 0x0 0x10>; - interrupt-parent=<&intc>; + interrupt-parent = <&pintc>; interrupts = <12>; reg-shift = <0>; reg-io-width = <1>; clock-frequency = <24000000>; status = "okay"; }; + misc: misc0@8036 { #address-cells = <2>; #size-cells = <2>; compatible = "sw6,sunway-ged"; reg = <0x8036 0x0 0x0 0x20>; - interrupt-parent=<&intc>; + interrupt-parent = <&pintc>; interrupts = <13>; reg-shift = <0>; reg-io-width = <8>; clock-frequency = <24000000>; status = "okay"; }; + fw_cfg: fw_cfg@8049 { dma-coherent; reg = <0x8049 0x20000000 0x0 0x18>; diff --git a/arch/sw_64/include/asm/uncore_io_junzhang.h b/arch/sw_64/include/asm/uncore_io_junzhang.h index ac37d186a29f..37cfe1fd6807 100644 --- a/arch/sw_64/include/asm/uncore_io_junzhang.h +++ b/arch/sw_64/include/asm/uncore_io_junzhang.h @@ -70,8 +70,6 @@ #define PIUCONFIG0_INIT_VAL 0x38016 -#define DEV_INT_TARGET(phy_cpu) ((((phy_cpu) >> 5) << 7) | ((phy_cpu) & 0x3f)) - /*-----------------------addr-----------------------*/ /* INTPU REG */ enum { diff --git a/arch/sw_64/include/asm/uncore_io_xuelang.h b/arch/sw_64/include/asm/uncore_io_xuelang.h index 873f7e86f83b..aeaadec5be16 100644 --- a/arch/sw_64/include/asm/uncore_io_xuelang.h +++ b/arch/sw_64/include/asm/uncore_io_xuelang.h @@ -74,8 +74,6 @@ #define PIUCONFIG0_INIT_VAL 0x38056 -#define DEV_INT_TARGET(phy_cpu) ((((phy_cpu) >> 5) << 6) | ((phy_cpu) & 0x1f)) - /*-----------------------addr-----------------------*/ /* CAB0 REG */ enum { diff --git a/drivers/irqchip/irq-sunway-pintc.c b/drivers/irqchip/irq-sunway-pintc.c index 8d789fd255c8..d65c788e354e 100644 --- a/drivers/irqchip/irq-sunway-pintc.c +++ b/drivers/irqchip/irq-sunway-pintc.c @@ -4,93 +4,107 @@ #include #include #include -#include - -/* - * Multi-node platform device implementation hasn't been thought through yet, - * which means how to obtain CPU node is ambiguous here. It is highly likely - * that this will be passed through ACPI or DTS. Leave node with 0 as default - * for now and wait for platform guys to check this later. - */ -#define DEFAULT_CPU_NODE 0 -static int cpu_node = DEFAULT_CPU_NODE; - -struct devint_chipdata { - int node; +#include +#include + +#define PREFIX "PINTC: " + +#define OFFSET_MCU_DVC_INT_EN 0x3080UL + +#define OFFSET_DEV_INT_CONFIG 0x480UL + +struct pintc_chip_data { + bool vt; /* virtual pintc */ + u32 node; /* node ID */ + u32 version; /* PINTC version */ + void __iomem *pintc_base; /* INTPU base address */ + void __iomem *mcu_base; /* MCU/SPBU base address */ }; -static DEFINE_RAW_SPINLOCK(devint_lock); +static DEFINE_RAW_SPINLOCK(pintc_lock); static void lock_dev_lock(void) { - raw_spin_lock(&devint_lock); + raw_spin_lock(&pintc_lock); } static void unlock_dev_lock(void) { - raw_spin_unlock(&devint_lock); + raw_spin_unlock(&pintc_lock); } static void mcu_irq_mask(struct irq_data *data) { - struct devint_chipdata *chip_data = data->chip_data; - unsigned int mask; + struct pintc_chip_data *chip_data = data->chip_data; + unsigned long mask; int hwirq = data->hwirq; - int node; - node = chip_data->node; - - mask = sw64_io_read(node, MCU_DVC_INT_EN); + mask = readq(chip_data->mcu_base + OFFSET_MCU_DVC_INT_EN); mask &= ~(0x1UL << hwirq); - sw64_io_write(node, MCU_DVC_INT_EN, mask); + writeq(mask, chip_data->mcu_base + OFFSET_MCU_DVC_INT_EN); } static void mcu_irq_unmask(struct irq_data *data) { - struct devint_chipdata *chip_data = data->chip_data; - unsigned int mask; + struct pintc_chip_data *chip_data = data->chip_data; + unsigned long mask; int hwirq = data->hwirq; - int node; - - node = chip_data->node; - mask = sw64_io_read(node, MCU_DVC_INT_EN); + mask = readq(chip_data->mcu_base + OFFSET_MCU_DVC_INT_EN); mask |= (0x1UL << hwirq); - sw64_io_write(node, MCU_DVC_INT_EN, mask); + writeq(mask, chip_data->mcu_base + OFFSET_MCU_DVC_INT_EN); } static void mcu_irq_enable(struct irq_data *irq_data) { - struct devint_chipdata *data = irq_data->chip_data; + struct pintc_chip_data *chip_data = irq_data->chip_data; unsigned long devint_conf; - int node; - node = data->node; - - devint_conf = sw64_io_read(node, DEV_INT_CONFIG); + devint_conf = readq(chip_data->pintc_base + OFFSET_DEV_INT_CONFIG); devint_conf |= (1UL << 8); - sw64_io_write(node, DEV_INT_CONFIG, devint_conf); + writeq(devint_conf, chip_data->pintc_base + OFFSET_DEV_INT_CONFIG); mcu_irq_unmask(irq_data); } static void mcu_irq_disable(struct irq_data *irq_data) { - struct devint_chipdata *data = irq_data->chip_data; + struct pintc_chip_data *chip_data = irq_data->chip_data; unsigned long devint_conf; - int node; - - node = data->node; - devint_conf = sw64_io_read(node, DEV_INT_CONFIG); + devint_conf = readq(chip_data->pintc_base + OFFSET_DEV_INT_CONFIG); devint_conf &= ~(1UL << 8); - sw64_io_write(node, DEV_INT_CONFIG, devint_conf); + writeq(devint_conf, chip_data->pintc_base + OFFSET_DEV_INT_CONFIG); mcu_irq_mask(irq_data); } -static int __assign_mcu_irq_config(int node, cpumask_t *targets) +static unsigned long make_mcu_int_target(u32 version, int rcid) +{ + int node, core, thread; + unsigned long target = 0; + + thread = rcid_to_thread_id(rcid); + core = rcid_to_core_id(rcid); + node = rcid_to_domain_id(rcid); + + switch (version) { + case 0x1: /* PINTC v1 */ + target = core | (thread << 5) | (node << 6); + break; + case 0x2: /* PINTC v2 */ + target = core | (thread << 6) | (node << 7); + break; + default: + break; + } + + return target; +} + +static int __assign_mcu_irq_config(const struct pintc_chip_data *chip_data, + cpumask_t *targets) { unsigned long dev_int_tar, val; unsigned int cpu; - int phy_cpu; + int rcid; for_each_cpu(cpu, targets) { /* @@ -98,7 +112,7 @@ static int __assign_mcu_irq_config(int node, cpumask_t *targets) * cores only. Thus, we remove all off-node cpu in the * target mask. */ - if (cpu_to_node(cpu) != node) + if (cpu_to_node(cpu) != chip_data->node) cpumask_clear_cpu(cpu, targets); } @@ -107,23 +121,24 @@ static int __assign_mcu_irq_config(int node, cpumask_t *targets) if (cpu >= nr_cpu_ids) return -EPERM; - phy_cpu = cpu_to_rcid(cpu); + rcid = cpu_to_rcid(cpu); - val = sw64_io_read(node, DEV_INT_CONFIG); - dev_int_tar = DEV_INT_TARGET(phy_cpu); + val = readq(chip_data->pintc_base + OFFSET_DEV_INT_CONFIG); + dev_int_tar = make_mcu_int_target(chip_data->version, rcid); val &= 0xffff; val |= dev_int_tar << 16; - sw64_io_write(node, DEV_INT_CONFIG, val); + writeq(val, chip_data->pintc_base + OFFSET_DEV_INT_CONFIG); return 0; } -static int assign_mcu_irq_config(int node, cpumask_t *targets) +static int assign_mcu_irq_config(const struct pintc_chip_data *chip_data, + cpumask_t *targets) { int ret; lock_dev_lock(); - ret = __assign_mcu_irq_config(node, targets); + ret = __assign_mcu_irq_config(chip_data, targets); unlock_dev_lock(); return ret; @@ -132,25 +147,23 @@ static int assign_mcu_irq_config(int node, cpumask_t *targets) static int mcu_irq_set_affinity(struct irq_data *irq_data, const struct cpumask *dest, bool force) { - struct devint_chipdata *chip_data = irq_data->chip_data; + struct pintc_chip_data *chip_data = irq_data->chip_data; cpumask_t targets; - int node, ret = 0; + int ret = 0; if (cpumask_any_and(dest, cpu_online_mask) >= nr_cpu_ids) return -EINVAL; cpumask_and(&targets, dest, cpu_online_mask); - node = chip_data->node; - mcu_irq_disable(irq_data); - ret = assign_mcu_irq_config(node, &targets); + ret = assign_mcu_irq_config(chip_data, &targets); mcu_irq_enable(irq_data); return ret; } -static struct irq_chip onchip_intc = { +static struct irq_chip pintc_mcu_chip = { .name = "MCU-INT", .irq_enable = mcu_irq_enable, .irq_disable = mcu_irq_disable, @@ -159,75 +172,40 @@ static struct irq_chip onchip_intc = { .irq_set_affinity = mcu_irq_set_affinity, }; -static struct devint_chipdata * -alloc_sw64_devint_chip_data(struct irq_data *irq_data) -{ - struct devint_chipdata *chip_data; - int node; - - node = irq_data_get_node(irq_data); - chip_data = kzalloc_node(sizeof(*chip_data), GFP_KERNEL, node); - if (!chip_data) - return NULL; - - return chip_data; -} - -static void sw64_intc_free_irqs(struct irq_domain *irq_domain, +static void pintc_mcu_free_irqs(struct irq_domain *irq_domain, unsigned int virq, unsigned int nr_irqs) { - struct irq_data *irq_data; - struct devint_chipdata *chip_data; int i = 0; - for (i = 0; i < nr_irqs; i++) { - irq_data = irq_domain_get_irq_data(irq_domain, virq + i); - if (irq_data && irq_data->chip_data) { - lock_dev_lock(); - chip_data = irq_data->chip_data; - irq_domain_reset_irq_data(irq_data); - kfree(chip_data); - unlock_dev_lock(); - } - } + irq_domain_free_irqs_top(irq_domain, virq, nr_irqs); + + for (i = 0; i < nr_irqs; i++) + irq_clear_status_flags(virq + i, IRQ_LEVEL); } -static int sw64_intc_alloc_irqs(struct irq_domain *irq_domain, +static int pintc_mcu_alloc_irqs(struct irq_domain *domain, unsigned int virq, unsigned int nr_irqs, void *arg) { - struct irq_data *irq_data; - struct devint_chipdata *chip_data; struct irq_fwspec *fwspec = arg; - int default_node = cpu_node, i = 0, hwirq; + irq_hw_number_t hwirq = fwspec->param[0]; + int i; for (i = 0; i < nr_irqs; i++) { - irq_data = irq_domain_get_irq_data(irq_domain, virq + i); - hwirq = fwspec->param[0]; - irq_data->hwirq = hwirq; - - chip_data = alloc_sw64_devint_chip_data(irq_data); - if (!chip_data) - goto out_free; - - chip_data->node = default_node; - irq_data->chip_data = chip_data; - irq_set_chip_and_handler(virq, &onchip_intc, handle_level_irq); - irq_set_status_flags(virq, IRQ_LEVEL); + irq_domain_set_info(domain, virq + i, hwirq + i, + &pintc_mcu_chip, domain->host_data, + handle_level_irq, NULL, NULL); + irq_set_status_flags(virq + i, IRQ_LEVEL); } return 0; - -out_free: - sw64_intc_free_irqs(irq_domain, virq, nr_irqs); - return -ENOMEM; } -static const struct irq_domain_ops sw64_intc_domain_ops = { +static const struct irq_domain_ops pintc_mcu_domain_ops = { .xlate = irq_domain_xlate_onecell, - .alloc = sw64_intc_alloc_irqs, - .free = sw64_intc_free_irqs, + .alloc = pintc_mcu_alloc_irqs, + .free = pintc_mcu_free_irqs, }; struct irq_domain *mcu_irq_domain; @@ -235,53 +213,111 @@ EXPORT_SYMBOL(mcu_irq_domain); #ifdef CONFIG_OF static int __init -init_mcu_IRQ(struct device_node *intc, struct device_node *parent) +pintc_of_init_common(struct device_node *pintc, + struct device_node *parent, bool vt) { - if (parent) { - pr_warn("DeviceTree incore intc not a root irq controller\n"); + int ret; + u32 nr_irqs, node, version; + void __iomem *pintc_base; + void __iomem *mcu_base; + struct pintc_chip_data *chip_data; + + if (WARN_ON(!pintc)) return -ENODEV; - } - mcu_irq_domain = irq_domain_add_linear(intc, 8, - &sw64_intc_domain_ops, NULL); + if (vt && parent) { + pr_err(PREFIX "virtual pintc has no parent controller\n"); + return -EINVAL; + } - if (!mcu_irq_domain) { - pr_warn("root irq domain not avail\n"); - return -ENODEV; + ret = of_property_read_u32(pintc, "sw64,node", &node); + if (ret) { + pr_err(PREFIX "\"sw64,node\" not found\n"); + return -EINVAL; } - /* with this we don't need to export root_domain */ - irq_set_default_host(mcu_irq_domain); + ret = of_property_read_u32(pintc, "sw64,irq-num", &nr_irqs); + if (ret) { + pr_err(PREFIX "\"sw64,irq-num\" not found\n"); + return -EINVAL; + } - /* mask all interrupts for now */ - sw64_io_write(cpu_node, MCU_DVC_INT_EN, 0x0); + ret = of_property_read_u32(pintc, "sw64,ver", &version); + if (ret) { + pr_err(PREFIX "\"sw64,ver\" not found\n"); + return -EINVAL; + } - return 0; -} + pintc_base = of_iomap(pintc, 0); + if (!pintc_base) { + pr_err(PREFIX "failed to map pintc base address\n"); + return -ENXIO; + } -IRQCHIP_DECLARE(sw64_intc, "sw64,sw6_irq_controller", init_mcu_IRQ); + mcu_base = of_iomap(pintc, 1); + if (!mcu_base) { + pr_err(PREFIX "failed to map mcu base address\n"); + ret = -ENXIO; + goto out_unmap0; + } -static int __init -init_mcu_vt_IRQ(struct device_node *intc, struct device_node *parent) -{ - if (parent) { - pr_warn("DeviceTree incore intc not a root irq controller\n"); - return -ENODEV; + chip_data = kzalloc_node(sizeof(*chip_data), GFP_KERNEL, node); + if (!chip_data) { + ret = -ENOMEM; + goto out_unmap1; } - mcu_irq_domain = irq_domain_add_legacy(intc, 16, 0, 0, - &sw64_intc_domain_ops, NULL); + chip_data->vt = vt; + chip_data->node = node; + chip_data->version = version; + chip_data->pintc_base = pintc_base; + chip_data->mcu_base = mcu_base; + + if (vt) + mcu_irq_domain = irq_domain_add_legacy(pintc, nr_irqs, 0, 0, + &pintc_mcu_domain_ops, chip_data); + else { + mcu_irq_domain = irq_domain_add_linear(pintc, nr_irqs, + &pintc_mcu_domain_ops, chip_data); + /* mask all interrupts for now */ + writeq(0x0, mcu_base + OFFSET_MCU_DVC_INT_EN); + } if (!mcu_irq_domain) { - pr_warn("root irq domain not avail\n"); - return -ENODEV; + pr_err(PREFIX "failed to create irq domain\n"); + ret = -ENOMEM; + goto out_free_mem; } - /* with this we don't need to export root_domain */ + pr_info(PREFIX "version [%u] on node [%u] initialized\n", + version, node); + irq_set_default_host(mcu_irq_domain); return 0; + +out_free_mem: + kfree(chip_data); +out_unmap1: + iounmap(mcu_base); +out_unmap0: + iounmap(pintc_base); + return ret; +} + +static int __init +pintc_of_init(struct device_node *pintc, struct device_node *parent) +{ + return pintc_of_init_common(pintc, parent, false); +} + +IRQCHIP_DECLARE(sw64_pintc, "sw64,pintc", pintc_of_init); + +static int __init +pintc_vt_of_init(struct device_node *pintc, struct device_node *parent) +{ + return pintc_of_init_common(pintc, parent, true); } -IRQCHIP_DECLARE(sw64_vt_intc, "sw64,sw6_irq_vt_controller", init_mcu_vt_IRQ); +IRQCHIP_DECLARE(sw64_pintc_vt, "sw64,pintc_vt", pintc_vt_of_init); #endif -- Gitee From 44452ef12acea8ff77ee9a5da312f4d7b4554dc6 Mon Sep 17 00:00:00 2001 From: Jing Li Date: Thu, 1 Feb 2024 15:35:31 +0800 Subject: [PATCH 32/49] anolis: sw64: irqchip: fix virtual PINTC not working properly ANBZ: #4688 Virtual PINTC is different from the physical one in the following aspects: - Virtual PINTC does not have the registers used in physical PINTC - The topology of virtual interrupt controllers containing virtual PINTC is a flat structure, which is different from the physical one Signed-off-by: Jing Li Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- drivers/irqchip/irq-sunway-pintc.c | 37 ++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/drivers/irqchip/irq-sunway-pintc.c b/drivers/irqchip/irq-sunway-pintc.c index d65c788e354e..41c52f9fb09b 100644 --- a/drivers/irqchip/irq-sunway-pintc.c +++ b/drivers/irqchip/irq-sunway-pintc.c @@ -19,6 +19,7 @@ struct pintc_chip_data { u32 version; /* PINTC version */ void __iomem *pintc_base; /* INTPU base address */ void __iomem *mcu_base; /* MCU/SPBU base address */ + struct irq_chip *mcu_chip; }; static DEFINE_RAW_SPINLOCK(pintc_lock); @@ -172,6 +173,10 @@ static struct irq_chip pintc_mcu_chip = { .irq_set_affinity = mcu_irq_set_affinity, }; +static struct irq_chip pintc_mcu_vt_chip = { + .name = "VMCU-INT", +}; + static void pintc_mcu_free_irqs(struct irq_domain *irq_domain, unsigned int virq, unsigned int nr_irqs) { @@ -183,6 +188,19 @@ static void pintc_mcu_free_irqs(struct irq_domain *irq_domain, irq_clear_status_flags(virq + i, IRQ_LEVEL); } +static int pintc_mcu_map_irq(struct irq_domain *domain, + unsigned int virq, irq_hw_number_t hwirq) +{ + struct pintc_chip_data *chip_data = domain->host_data; + + irq_domain_set_info(domain, virq, hwirq, + chip_data->mcu_chip, chip_data, + handle_level_irq, NULL, NULL); + irq_set_status_flags(virq, IRQ_LEVEL); + + return 0; +} + static int pintc_mcu_alloc_irqs(struct irq_domain *domain, unsigned int virq, unsigned int nr_irqs, @@ -192,17 +210,14 @@ static int pintc_mcu_alloc_irqs(struct irq_domain *domain, irq_hw_number_t hwirq = fwspec->param[0]; int i; - for (i = 0; i < nr_irqs; i++) { - irq_domain_set_info(domain, virq + i, hwirq + i, - &pintc_mcu_chip, domain->host_data, - handle_level_irq, NULL, NULL); - irq_set_status_flags(virq + i, IRQ_LEVEL); - } + for (i = 0; i < nr_irqs; i++) + pintc_mcu_map_irq(domain, virq + i, hwirq + i); return 0; } static const struct irq_domain_ops pintc_mcu_domain_ops = { + .map = pintc_mcu_map_irq, .xlate = irq_domain_xlate_onecell, .alloc = pintc_mcu_alloc_irqs, .free = pintc_mcu_free_irqs, @@ -249,13 +264,13 @@ pintc_of_init_common(struct device_node *pintc, } pintc_base = of_iomap(pintc, 0); - if (!pintc_base) { + if (!vt && !pintc_base) { pr_err(PREFIX "failed to map pintc base address\n"); return -ENXIO; } mcu_base = of_iomap(pintc, 1); - if (!mcu_base) { + if (!vt && !mcu_base) { pr_err(PREFIX "failed to map mcu base address\n"); ret = -ENXIO; goto out_unmap0; @@ -273,10 +288,12 @@ pintc_of_init_common(struct device_node *pintc, chip_data->pintc_base = pintc_base; chip_data->mcu_base = mcu_base; - if (vt) + if (vt) { + chip_data->mcu_chip = &pintc_mcu_vt_chip; mcu_irq_domain = irq_domain_add_legacy(pintc, nr_irqs, 0, 0, &pintc_mcu_domain_ops, chip_data); - else { + } else { + chip_data->mcu_chip = &pintc_mcu_chip; mcu_irq_domain = irq_domain_add_linear(pintc, nr_irqs, &pintc_mcu_domain_ops, chip_data); /* mask all interrupts for now */ -- Gitee From 36dbe4cde3c8a2e98aaecb7d4e28b76de84aee3d Mon Sep 17 00:00:00 2001 From: Zheng Chongzhen Date: Fri, 2 Feb 2024 18:02:05 +0000 Subject: [PATCH 33/49] anolis: sw64: pci: change pci transaction ordering rule settings ANBZ: #4688 Due to the risk of previous commit , running ltpstress on SW8A virtual machine cause IOMMU to report an error that the AHCI device level-3 page table is invalid. The AHCI driver reads the IO register to learn that the command has completed and then releases the dma address corresponding to the command. However, since Completion is permitted to pass a Posted Request, IO response has come back but the DMA write is not actually finished. To solve this problem, on SW8A platform, we change PCI transaction ordering settings by disabling CPL_PASS_P bit in RC's ORDER_RULE_CTRL register to ensure that a Completion must not pass a Posted Request. Signed-off-by: Zheng Chongzhen Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- drivers/pci/controller/pci-sunway.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/pci/controller/pci-sunway.c b/drivers/pci/controller/pci-sunway.c index c58fdea39f17..ece31736b051 100644 --- a/drivers/pci/controller/pci-sunway.c +++ b/drivers/pci/controller/pci-sunway.c @@ -205,7 +205,9 @@ static void set_rc_piu(unsigned long node, unsigned long index) write_rc_conf(node, index, RC_PORT_LINK_CTL, 0x1f0020); write_rc_conf(node, index, RC_EXP_DEVCTL, 0x2850); write_rc_conf(node, index, RC_EXP_DEVCTL2, 0x6); +#ifdef CONFIG_UNCORE_XUELANG write_rc_conf(node, index, RC_ORDER_RULE_CTL, 0x0100); +#endif /* enable DBI_RO_WR_EN */ rc_misc_ctrl = read_rc_conf(node, index, RC_MISC_CONTROL_1); -- Gitee From a33927d64126957fc1c9e18c41b8a9a64b3d5be3 Mon Sep 17 00:00:00 2001 From: Zheng Chongzhen Date: Tue, 6 Feb 2024 14:28:23 +0000 Subject: [PATCH 34/49] anolis: sw64: msi: fix bugs in multi-msi interrupts allocation and release ANBZ: #4688 First, according to the definition of the PCI bus specification (Rev. 4.0 Version 1.0, 7.7.1.5 "Message Data Register for MSI"), the first vector assigned to multi-msi interrupts must be aligned to the number of allocation. Second, since each irq_data of multi-msi interrupts corresponds to the same chip_data, it can only be released when all multi-msi interrupts have been released. Signed-off-by: Zheng Chongzhen Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- drivers/irqchip/irq-sunway-msi-v2.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/drivers/irqchip/irq-sunway-msi-v2.c b/drivers/irqchip/irq-sunway-msi-v2.c index 213a22f2b54b..8b8424d508a4 100644 --- a/drivers/irqchip/irq-sunway-msi-v2.c +++ b/drivers/irqchip/irq-sunway-msi-v2.c @@ -91,7 +91,7 @@ static bool find_free_cpu_vectors(const struct cpumask *search_mask, int *found_ cpu = cpumask_first(search_mask); try_again: - for (vector = 0; vector < 256; vector++) { + for (vector = 0; vector < 256; vector += nr_irqs) { for (i = 0; i < nr_irqs; i++) if (per_cpu(vector_irq, cpu)[vector + i]) break; @@ -102,8 +102,6 @@ static bool find_free_cpu_vectors(const struct cpumask *search_mask, int *found_ *found_vector = vector; return found; } - - vector += i; } cpu = cpumask_next(cpu, search_mask); @@ -212,7 +210,6 @@ static int __assign_irq_vector(int virq, unsigned int nr_irqs, struct sw64_msi_chip_data *cdata; int node; int i, vector, cpu; - unsigned long msiaddr; if (unlikely((nr_irqs > 1) && (!is_power_of_2(nr_irqs)))) nr_irqs = __roundup_pow_of_two(nr_irqs); @@ -308,10 +305,9 @@ static int assign_irq_vector(int irq, unsigned int nr_irqs, static void sw64_vector_free_irqs(struct irq_domain *domain, unsigned int virq, unsigned int nr_irqs) { - int i, j; + int i; struct irq_data *irq_data; unsigned long flags; - unsigned int multi_msi; for (i = 0; i < nr_irqs; i++) { irq_data = irq_domain_get_irq_data(domain, virq + i); @@ -321,13 +317,15 @@ static void sw64_vector_free_irqs(struct irq_domain *domain, raw_spin_lock_irqsave(&vector_lock, flags); cdata = irq_data->chip_data; irq_domain_reset_irq_data(irq_data); - multi_msi = cdata->multi_msi; - for (j = 0; j < multi_msi; j++) - per_cpu(vector_irq, cdata->dst_cpu)[cdata->vector + j] = 0; - kfree(cdata); + cdata->multi_msi--; + per_cpu(vector_irq, cdata->dst_cpu)[cdata->vector] = 0; + + if (cdata->multi_msi) + cdata->vector++; + + if (cdata->multi_msi == 0) + kfree(cdata); raw_spin_unlock_irqrestore(&vector_lock, flags); - if (multi_msi > 1) - break; } } } -- Gitee From 986c98e79fe472ae30bd34e449cb45c1ae9c0eb0 Mon Sep 17 00:00:00 2001 From: Mao Minkai Date: Tue, 20 Feb 2024 14:31:53 +0800 Subject: [PATCH 35/49] anolis: sw64: improve sw64_printk() ANBZ: #4688 Skip printk headers before writing into sw64_printk_buf, so we won't have unprintable characters in it. Make sw64_printk() void since the return value is never used. Signed-off-by: Mao Minkai Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/kernel/dup_print.c | 34 ++++++++++++++++++++-------------- kernel/printk/printk.c | 2 +- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/arch/sw_64/kernel/dup_print.c b/arch/sw_64/kernel/dup_print.c index 439ac75feb01..eef31527dc13 100644 --- a/arch/sw_64/kernel/dup_print.c +++ b/arch/sw_64/kernel/dup_print.c @@ -15,33 +15,39 @@ static DEFINE_SPINLOCK(printk_lock); unsigned long sw64_printk_offset; #define PRINTK_SIZE 0x100000UL -int sw64_printk(const char *fmt, va_list args) +void sw64_printk(const char *fmt, va_list args) { char *sw64_printk_buf; - int printed_len = 0; unsigned long flags; + char textbuf[1024]; + const char *text; + size_t text_len; spin_lock_irqsave(&printk_lock, flags); sw64_printk_buf = (char *)(KERNEL_PRINTK_BUFF_BASE + sw64_printk_offset); - if (sw64_printk_offset >= (PRINTK_SIZE-1024)) { //printk wrapped + text_len = vscnprintf(textbuf, sizeof(textbuf), fmt, args); + text = printk_skip_headers(textbuf); + text_len -= text - textbuf; + + if (sw64_printk_offset >= (PRINTK_SIZE - 1024)) { sw64_printk_offset = 0; sw64_printk_buf = (char *)(KERNEL_PRINTK_BUFF_BASE + sw64_printk_offset); memset(sw64_printk_buf, 0, PRINTK_SIZE); - printed_len += vscnprintf(sw64_printk_buf, 1024, fmt, args); - } else { - printed_len += vscnprintf(sw64_printk_buf, 1024, fmt, args); - if (is_in_emul()) { - void __iomem *addr = __va(QEMU_PRINTF_BUFF_BASE); - u64 data = ((u64)sw64_printk_buf & 0xffffffffUL) - | ((u64)printed_len << 32); - *(u64 *)addr = data; - } } - sw64_printk_offset += printed_len; + + memcpy(sw64_printk_buf, text, text_len); + sw64_printk_offset += text_len; + + if (is_in_emul()) { + void __iomem *addr = __va(QEMU_PRINTF_BUFF_BASE); + u64 data = ((u64)sw64_printk_buf & 0xffffffffUL) + | ((u64)text_len << 32); + *(u64 *)addr = data; + } + spin_unlock_irqrestore(&printk_lock, flags); - return printed_len; } #endif diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index 30837b66c14c..7493f4b0d702 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -1994,7 +1994,7 @@ int vprintk_store(int facility, int level, enum log_flags lflags = 0; #ifdef CONFIG_SW64_RRK - extern int sw64_printk(const char *fmt, va_list args); + extern void sw64_printk(const char *fmt, va_list args); sw64_printk(fmt, args); #endif -- Gitee From 61d3381a9b0ab8ef6dc7dd4c2e2bf806f56337e5 Mon Sep 17 00:00:00 2001 From: Mao Minkai Date: Tue, 20 Feb 2024 16:10:20 +0800 Subject: [PATCH 36/49] anolis: sw64: add a new kernel parameter to override mclk ANBZ: #4688 Add a new cmdline parameter to override the mclk we have got. Signed-off-by: Mao Minkai Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- drivers/clocksource/timer-sw64.c | 40 +++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/drivers/clocksource/timer-sw64.c b/drivers/clocksource/timer-sw64.c index 3cbd99f3fe32..2b1670426b8a 100644 --- a/drivers/clocksource/timer-sw64.c +++ b/drivers/clocksource/timer-sw64.c @@ -13,8 +13,7 @@ #include #include -#define SHTCLK_RATE_KHZ 25000 -#define SHTCLK_RATE (SHTCLK_RATE_KHZ * 1000) +#define DEFAULT_MCLK 25000 /* Khz */ #if defined(CONFIG_SUBARCH_C4) static u64 read_longtime(struct clocksource *cs) @@ -37,10 +36,31 @@ static u64 notrace read_sched_clock(void) return sw64_read_csr(CSR_SHTCLOCK); } +static int override_mclk_khz; +static int __init setup_mclk(char *str) +{ + get_option(&str, &override_mclk_khz); + + return 0; +} +early_param("mclk_khz", setup_mclk); + void __init sw64_setup_clocksource(void) { - clocksource_register_khz(&clocksource_longtime, SHTCLK_RATE_KHZ); - sched_clock_register(read_sched_clock, BITS_PER_LONG, SHTCLK_RATE); + unsigned long mclk_khz = *((unsigned char *)__va(MB_MCLK)) * 1000; + + if (override_mclk_khz) { + mclk_khz = override_mclk_khz; + pr_info("Override mclk by cmdline.\n"); + } + + if (!mclk_khz) + mclk_khz = DEFAULT_MCLK; + + pr_info("mclk: %ldKhz\n", mclk_khz); + + clocksource_register_khz(&clocksource_longtime, mclk_khz); + sched_clock_register(read_sched_clock, BITS_PER_LONG, mclk_khz * 1000); } void __init setup_sched_clock(void) { } @@ -122,20 +142,18 @@ static struct clocksource clocksource_tc = { }; #endif /* SMP */ -#define DEFAULT_MCLK 25 /* Mhz */ - void __init sw64_setup_clocksource(void) { - unsigned int mclk = *((unsigned char *)__va(MB_MCLK)); + unsigned long mclk_khz = *((unsigned char *)__va(MB_MCLK)) * 1000; - if (!mclk) - mclk = DEFAULT_MCLK; + if (!mclk_khz) + mclk_khz = DEFAULT_MCLK; #ifdef CONFIG_SMP if (is_in_host()) - clocksource_register_khz(&clocksource_longtime, mclk * 1000); + clocksource_register_khz(&clocksource_longtime, mclk_khz); else - clocksource_register_khz(&clocksource_vtime, mclk * 1000); + clocksource_register_khz(&clocksource_vtime, mclk_khz); #else clocksource_register_hz(&clocksource_tc, get_cpu_freq()); pr_info("Setup clocksource TC, mult = %d\n", clocksource_tc.mult); -- Gitee From 9786a69a92fbc4f0f2b76bd577627f117fcd80ac Mon Sep 17 00:00:00 2001 From: Wu Liliu Date: Mon, 15 Jan 2024 17:09:59 +0800 Subject: [PATCH 37/49] anolis: sw64: add four-socket system support ANBZ: #4688 Allow a maximum of 512 cpus to support 4-socket servers. Signed-off-by: Wu Liliu Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/Kconfig | 8 ++++---- arch/sw_64/configs/junzhang_defconfig | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/sw_64/Kconfig b/arch/sw_64/Kconfig index fb1bbd418d2b..4b9e8148e4c4 100644 --- a/arch/sw_64/Kconfig +++ b/arch/sw_64/Kconfig @@ -417,12 +417,12 @@ config SCHED_MC increased overhead in some places. If unsure say N here. config NR_CPUS - int "Maximum number of CPUs (2-256)" - range 2 256 + int "Maximum number of CPUs (2-512)" + range 2 512 depends on SMP - default "64" if UNCORE_XUELANG + default "512" if UNCORE_JUNZHANG help - SW6 support can handle a maximum of 256 CPUs. + SW64 support can handle a maximum of 512 CPUs. config HOTPLUG_CPU bool "Support for hot-pluggable CPUs" diff --git a/arch/sw_64/configs/junzhang_defconfig b/arch/sw_64/configs/junzhang_defconfig index 2a9a7bb9d70f..41fb26c112d4 100644 --- a/arch/sw_64/configs/junzhang_defconfig +++ b/arch/sw_64/configs/junzhang_defconfig @@ -28,7 +28,7 @@ CONFIG_DEBUG_PERF_USE_VMALLOC=y CONFIG_SUBARCH_C4=y CONFIG_SMP=y CONFIG_SCHED_SMT=y -CONFIG_NR_CPUS=64 +CONFIG_NR_CPUS=512 CONFIG_ARCH_SPARSEMEM_ENABLE=y CONFIG_NUMA=y CONFIG_HZ=100 -- Gitee From 82905976ce090b3142e6ce55f715ea9fbe0bf4f7 Mon Sep 17 00:00:00 2001 From: Mao Minkai Date: Tue, 12 Dec 2023 16:27:59 +0800 Subject: [PATCH 38/49] anolis: sw64: enable hardware denorm by default ANBZ: #4688 Enable hardware denormalized number processing by default to improve performance. Signed-off-by: Mao Minkai Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/include/uapi/asm/fpu.h | 2 ++ arch/sw_64/kernel/process.c | 11 ++++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/arch/sw_64/include/uapi/asm/fpu.h b/arch/sw_64/include/uapi/asm/fpu.h index 52ad5f137553..a462271cc3bb 100644 --- a/arch/sw_64/include/uapi/asm/fpu.h +++ b/arch/sw_64/include/uapi/asm/fpu.h @@ -6,6 +6,7 @@ * SW-64 floating-point control register defines: */ #define FPCR_DNOD (1UL << 47) /* denorm INV trap disable */ +#define FPCR_DNZ (1UL << 48) /* denorms to zero */ #define FPCR_DNOE (1UL << 48) /* hardware denormal support */ #define FPCR_INVD (1UL << 49) /* invalid op disable (opt.) */ #define FPCR_DZED (1UL << 50) /* division by zero disable (opt.) */ @@ -96,6 +97,7 @@ /* Denorm and Underflow flushing */ #define IEEE_MAP_DMZ (1UL << 12) /* Map denorm inputs to zero */ +#define IEEE_HARD_DM (1UL << 12) /* Hardware denorm processing */ #define IEEE_MAP_UMZ (1UL << 13) /* Map underflowed outputs to zero */ #define IEEE_MAP_MASK (IEEE_MAP_DMZ | IEEE_MAP_UMZ) diff --git a/arch/sw_64/kernel/process.c b/arch/sw_64/kernel/process.c index 6d7245d4f887..f63def23f326 100644 --- a/arch/sw_64/kernel/process.c +++ b/arch/sw_64/kernel/process.c @@ -33,12 +33,13 @@ flush_thread(void) /* Arrange for each exec'ed process to start off with a clean slate * with respect to the FPU. This is all exceptions disabled. */ - current_thread_info()->ieee_state = 0; -#ifdef CONFIG_SUBARCH_C3B - wrfpcr(FPCR_INIT | ieee_swcr_to_fpcr(0)); -#else - wrfpcr(FPCR_INIT | FPCR_DNOE | ieee_swcr_to_fpcr(0)); + unsigned int *ieee_state = ¤t_thread_info()->ieee_state; + + *ieee_state = 0; +#ifndef CONFIG_SUBARCH_C3B + *ieee_state |= IEEE_HARD_DM; #endif + wrfpcr(FPCR_INIT | ieee_swcr_to_fpcr(*ieee_state)); /* Clean slate for TLS. */ current_thread_info()->pcb.tp = 0; -- Gitee From 0558859dafb91337d11df24ccb6acb85d3d1c3e3 Mon Sep 17 00:00:00 2001 From: Mao Minkai Date: Thu, 14 Dec 2023 11:29:34 +0800 Subject: [PATCH 39/49] anolis: sw64: rewrite fpcr and swcr conversion ANBZ: #4688 Rewrite the conversion between fpcr and swcr. Add C4 new bits support and fix SIMD support. Signed-off-by: Mao Minkai Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/include/asm/fpu.h | 167 ++++++++++++++++++++- arch/sw_64/include/asm/sfp-machine.h | 5 + arch/sw_64/include/uapi/asm/fpu.h | 215 ++++++++++++++++++--------- arch/sw_64/kernel/sys_sw64.c | 6 +- arch/sw_64/kernel/traps.c | 42 +++++- arch/sw_64/math-emu/math.c | 90 ++++++----- 6 files changed, 395 insertions(+), 130 deletions(-) diff --git a/arch/sw_64/include/asm/fpu.h b/arch/sw_64/include/asm/fpu.h index a0b0ff5af168..1d5e9b0efecc 100644 --- a/arch/sw_64/include/asm/fpu.h +++ b/arch/sw_64/include/asm/fpu.h @@ -3,8 +3,85 @@ #define _ASM_SW64_FPU_H #include + +#define EXC_SUM_SWC (1UL << 0) + +#define EXC_SUM_DZE_INT (1UL << 39) + +#define EXC_SUM_INV0 (1UL << 1) +#define EXC_SUM_DZE0 (1UL << 2) +#define EXC_SUM_OVF0 (1UL << 3) +#define EXC_SUM_UNF0 (1UL << 4) +#define EXC_SUM_INE0 (1UL << 5) +#define EXC_SUM_OVI0 (1UL << 6) +#define EXC_SUM_DNO0 (1UL << 40) + +#define EXC_SUM_INV1 (1UL << 15) +#define EXC_SUM_DZE1 (1UL << 16) +#define EXC_SUM_OVF1 (1UL << 17) +#define EXC_SUM_UNF1 (1UL << 18) +#define EXC_SUM_INE1 (1UL << 19) +#define EXC_SUM_OVI1 (1UL << 20) +#define EXC_SUM_DNO1 (1UL << 41) + +#define EXC_SUM_INV2 (1UL << 21) +#define EXC_SUM_DZE2 (1UL << 22) +#define EXC_SUM_OVF2 (1UL << 23) +#define EXC_SUM_UNF2 (1UL << 24) +#define EXC_SUM_INE2 (1UL << 25) +#define EXC_SUM_OVI2 (1UL << 26) +#define EXC_SUM_DNO2 (1UL << 42) + +#define EXC_SUM_INV3 (1UL << 27) +#define EXC_SUM_DZE3 (1UL << 28) +#define EXC_SUM_OVF3 (1UL << 29) +#define EXC_SUM_UNF3 (1UL << 30) +#define EXC_SUM_INE3 (1UL << 31) +#define EXC_SUM_OVI3 (1UL << 32) +#define EXC_SUM_DNO3 (1UL << 43) + +#define EXC_SUM_FP_STATUS0 (EXC_SUM_INV0 | EXC_SUM_DZE0 | \ + EXC_SUM_OVF0 | EXC_SUM_UNF0 | \ + EXC_SUM_INE0 | EXC_SUM_OVI0 | \ + EXC_SUM_DNO0) + +#define EXC_SUM_FP_STATUS1 (EXC_SUM_INV1 | EXC_SUM_DZE1 | \ + EXC_SUM_OVF1 | EXC_SUM_UNF1 | \ + EXC_SUM_INE1 | EXC_SUM_OVI1 | \ + EXC_SUM_DNO1) + +#define EXC_SUM_FP_STATUS2 (EXC_SUM_INV2 | EXC_SUM_DZE2 | \ + EXC_SUM_OVF2 | EXC_SUM_UNF2 | \ + EXC_SUM_INE2 | EXC_SUM_OVI2 | \ + EXC_SUM_DNO2) + +#define EXC_SUM_FP_STATUS3 (EXC_SUM_INV3 | EXC_SUM_DZE3 | \ + EXC_SUM_OVF3 | EXC_SUM_UNF3 | \ + EXC_SUM_INE3 | EXC_SUM_OVI3 | \ + EXC_SUM_DNO3) + +#define EXC_SUM_FP_STATUS_ALL (EXC_SUM_FP_STATUS0 | EXC_SUM_FP_STATUS1 | \ + EXC_SUM_FP_STATUS2 | EXC_SUM_FP_STATUS3) + +#define EXC_SUM_INV (EXC_SUM_INV0 | EXC_SUM_INV1 | \ + EXC_SUM_INV2 | EXC_SUM_INV3) +#define EXC_SUM_DZE (EXC_SUM_DZE0 | EXC_SUM_DZE1 | \ + EXC_SUM_DZE2 | EXC_SUM_DZE3) +#define EXC_SUM_OVF (EXC_SUM_OVF0 | EXC_SUM_OVF1 | \ + EXC_SUM_OVF2 | EXC_SUM_OVF3) +#define EXC_SUM_UNF (EXC_SUM_UNF0 | EXC_SUM_UNF1 | \ + EXC_SUM_UNF2 | EXC_SUM_UNF3) +#define EXC_SUM_INE (EXC_SUM_INE0 | EXC_SUM_INE1 | \ + EXC_SUM_INE2 | EXC_SUM_INE3) +#define EXC_SUM_OVI (EXC_SUM_OVI0 | EXC_SUM_OVI1 | \ + EXC_SUM_OVI2 | EXC_SUM_OVI3) +#define EXC_SUM_DNO (EXC_SUM_DNO0 | EXC_SUM_DNO1 | \ + EXC_SUM_DNO2 | EXC_SUM_DNO3) + #ifdef __KERNEL__ +#include + /* * The following two functions don't need trapb/excb instructions * around the mf_fpcr/mt_fpcr instructions because (a) the kernel @@ -62,15 +139,93 @@ swcr_update_status(unsigned long swcr, unsigned long fpcr) * SW64 implements most of the bits in hardware. Collect * the acrued exception bits from the real fpcr. */ - swcr &= ~(IEEE_STATUS_MASK0 | IEEE_STATUS_MASK1 - | IEEE_STATUS_MASK2 | IEEE_STATUS_MASK3); - swcr |= (fpcr >> 35) & IEEE_STATUS_MASK0; - swcr |= (fpcr >> 13) & IEEE_STATUS_MASK1; - swcr |= (fpcr << 14) & IEEE_STATUS_MASK2; - swcr |= (fpcr << 36) & IEEE_STATUS_MASK3; + swcr &= ~IEEE_STATUS_MASK_ALL; + swcr |= ieee_status_fpcr_to_swcr(fpcr & FPCR_STATUS_MASK_ALL); return swcr; } +static inline unsigned long +swcr_status_to_fex(unsigned long swcr_status, int part) +{ + unsigned long fex = 0; + + if (part < -1 || part > 3) { + pr_warn("%s: invalid part index, counting all parts\n", __func__); + part = -1; + } + + if (part == -1 || part == 0) { + fex |= (swcr_status & (IEEE_STATUS_INV0 | IEEE_STATUS_DZE0 | + IEEE_STATUS_OVF0 | IEEE_STATUS_UNF0 | + IEEE_STATUS_INE0 | IEEE_STATUS_DNO0)) >> + (17 - 1); + fex |= fex & IEEE_STATUS_OVI0 ? FP_EX_OVERINT : 0; + } + + if (part == -1 || part == 1) { + fex |= (swcr_status & (IEEE_STATUS_INV1 | IEEE_STATUS_DZE1 | + IEEE_STATUS_OVF1 | IEEE_STATUS_UNF1 | + IEEE_STATUS_INE1 | IEEE_STATUS_DNO1)) >> + (23 - 1); + fex |= fex & IEEE_STATUS_OVI1 ? FP_EX_OVERINT : 0; + } + + if (part == -1 || part == 2) { + fex |= (swcr_status & (IEEE_STATUS_INV2 | IEEE_STATUS_DZE2 | + IEEE_STATUS_OVF2 | IEEE_STATUS_UNF2 | + IEEE_STATUS_INE2 | IEEE_STATUS_DNO2)) >> + (34 - 1); + fex |= fex & IEEE_STATUS_OVI2 ? FP_EX_OVERINT : 0; + } + + if (part == -1 || part == 3) { + fex |= (swcr_status & (IEEE_STATUS_INV3 | IEEE_STATUS_DZE3 | + IEEE_STATUS_OVF3 | IEEE_STATUS_UNF3 | + IEEE_STATUS_INE3 | IEEE_STATUS_DNO3)) >> + (40 - 1); + fex |= fex & IEEE_STATUS_OVI3 ? FP_EX_OVERINT : 0; + } + + return fex; +} + +static inline unsigned long +fex_to_swcr_status(unsigned long fex, int part) +{ + unsigned long swcr_status = 0; + + switch (part) { + case 0: + swcr_status |= (fex & (FP_EX_INVALID | FP_EX_OVERFLOW | + FP_EX_UNDERFLOW | FP_EX_DIVZERO | + FP_EX_INEXACT | FP_EX_DENORM)) << (17 - 1); + swcr_status |= fex & FP_EX_OVERINT ? IEEE_STATUS_OVI0 : 0; + break; + case 1: + swcr_status |= (fex & (FP_EX_INVALID | FP_EX_OVERFLOW | + FP_EX_UNDERFLOW | FP_EX_DIVZERO | + FP_EX_INEXACT | FP_EX_DENORM)) << (23 - 1); + swcr_status |= fex & FP_EX_OVERINT ? IEEE_STATUS_OVI1 : 0; + break; + case 2: + swcr_status |= (fex & (FP_EX_INVALID | FP_EX_OVERFLOW | + FP_EX_UNDERFLOW | FP_EX_DIVZERO | + FP_EX_INEXACT | FP_EX_DENORM)) << (34 - 1); + swcr_status |= fex & FP_EX_OVERINT ? IEEE_STATUS_OVI2 : 0; + break; + case 3: + swcr_status |= (fex & (FP_EX_INVALID | FP_EX_OVERFLOW | + FP_EX_UNDERFLOW | FP_EX_DIVZERO | + FP_EX_INEXACT | FP_EX_DENORM)) << (40 - 1); + swcr_status |= fex & FP_EX_OVERINT ? IEEE_STATUS_OVI3 : 0; + break; + default: + pr_err("%s: invalid part index\n", __func__); + } + + return swcr_status; +} + extern unsigned long sw64_read_fp_reg(unsigned long reg); extern void sw64_write_fp_reg(unsigned long reg, unsigned long val); extern unsigned long sw64_read_fp_reg_s(unsigned long reg); diff --git a/arch/sw_64/include/asm/sfp-machine.h b/arch/sw_64/include/asm/sfp-machine.h index c1b914898543..e6e14b918ae0 100644 --- a/arch/sw_64/include/asm/sfp-machine.h +++ b/arch/sw_64/include/asm/sfp-machine.h @@ -60,8 +60,13 @@ do { \ #define FP_EX_DIVZERO IEEE_TRAP_ENABLE_DZE #define FP_EX_INEXACT IEEE_TRAP_ENABLE_INE #define FP_EX_DENORM IEEE_TRAP_ENABLE_DNO +#define FP_EX_OVERINT IEEE_TRAP_ENABLE_OVI +#if defined(CONFIG_SUBARCH_C3A) || defined(CONFIG_SUBARCH_C3B) #define FP_DENORM_ZERO (swcr & IEEE_MAP_DMZ) +#elif defined(CONFIG_SUBARCH_C4) +#define FP_DENORM_ZERO 1 +#endif /* We write the results always */ #define FP_INHIBIT_RESULTS 0 diff --git a/arch/sw_64/include/uapi/asm/fpu.h b/arch/sw_64/include/uapi/asm/fpu.h index a462271cc3bb..4d468b75a25b 100644 --- a/arch/sw_64/include/uapi/asm/fpu.h +++ b/arch/sw_64/include/uapi/asm/fpu.h @@ -5,18 +5,14 @@ /* * SW-64 floating-point control register defines: */ +#define FPCR_EXUN (1UL << 44) /* exact denorm result underflow */ +#define FPCR_OVID (1UL << 45) /* integer overflow disable */ #define FPCR_DNOD (1UL << 47) /* denorm INV trap disable */ #define FPCR_DNZ (1UL << 48) /* denorms to zero */ #define FPCR_DNOE (1UL << 48) /* hardware denormal support */ #define FPCR_INVD (1UL << 49) /* invalid op disable (opt.) */ #define FPCR_DZED (1UL << 50) /* division by zero disable (opt.) */ #define FPCR_OVFD (1UL << 51) /* overflow disable (optional) */ -#define FPCR_INV (1UL << 52) /* invalid operation */ -#define FPCR_DZE (1UL << 53) /* division by zero */ -#define FPCR_OVF (1UL << 54) /* overflow */ -#define FPCR_UNF (1UL << 55) /* underflow */ -#define FPCR_INE (1UL << 56) /* inexact */ -#define FPCR_IOV (1UL << 57) /* integer overflow */ #define FPCR_UNDZ (1UL << 60) /* underflow to zero (opt.) */ #define FPCR_UNFD (1UL << 61) /* underflow disable (opt.) */ #define FPCR_INED (1UL << 62) /* inexact disable (opt.) */ @@ -34,6 +30,7 @@ #define FPCR_INIT FPCR_DYN_NORMAL /* status bit coming from hardware fpcr . definde by fire3 */ +#define FPCR_STATUS_DNO0 (1UL << 46) #define FPCR_STATUS_INV0 (1UL << 52) #define FPCR_STATUS_DZE0 (1UL << 53) #define FPCR_STATUS_OVF0 (1UL << 54) @@ -47,6 +44,7 @@ #define FPCR_STATUS_UNF1 (1UL << 39) #define FPCR_STATUS_INE1 (1UL << 40) #define FPCR_STATUS_OVI1 (1UL << 41) +#define FPCR_STATUS_DNO1 (1UL << 42) #define FPCR_STATUS_INV2 (1UL << 20) #define FPCR_STATUS_DZE2 (1UL << 21) @@ -54,6 +52,7 @@ #define FPCR_STATUS_UNF2 (1UL << 23) #define FPCR_STATUS_INE2 (1UL << 24) #define FPCR_STATUS_OVI2 (1UL << 25) +#define FPCR_STATUS_DNO2 (1UL << 26) #define FPCR_STATUS_INV3 (1UL << 4) #define FPCR_STATUS_DZE3 (1UL << 5) @@ -61,22 +60,30 @@ #define FPCR_STATUS_UNF3 (1UL << 7) #define FPCR_STATUS_INE3 (1UL << 8) #define FPCR_STATUS_OVI3 (1UL << 9) +#define FPCR_STATUS_DNO3 (1UL << 10) -#define FPCR_STATUS_MASK0 (FPCR_STATUS_INV0 | FPCR_STATUS_DZE0 | \ +#define FPCR_STATUS_MASK0 (FPCR_STATUS_INV0 | FPCR_STATUS_DZE0 | \ FPCR_STATUS_OVF0 | FPCR_STATUS_UNF0 | \ - FPCR_STATUS_INE0 | FPCR_STATUS_OVI0) + FPCR_STATUS_INE0 | FPCR_STATUS_OVI0 | \ + FPCR_STATUS_DNO0) -#define FPCR_STATUS_MASK1 (FPCR_STATUS_INV1 | FPCR_STATUS_DZE1 | \ +#define FPCR_STATUS_MASK1 (FPCR_STATUS_INV1 | FPCR_STATUS_DZE1 | \ FPCR_STATUS_OVF1 | FPCR_STATUS_UNF1 | \ - FPCR_STATUS_INE1 | FPCR_STATUS_OVI1) + FPCR_STATUS_INE1 | FPCR_STATUS_OVI1 | \ + FPCR_STATUS_DNO1) -#define FPCR_STATUS_MASK2 (FPCR_STATUS_INV2 | FPCR_STATUS_DZE2 | \ +#define FPCR_STATUS_MASK2 (FPCR_STATUS_INV2 | FPCR_STATUS_DZE2 | \ FPCR_STATUS_OVF2 | FPCR_STATUS_UNF2 | \ - FPCR_STATUS_INE2 | FPCR_STATUS_OVI2) + FPCR_STATUS_INE2 | FPCR_STATUS_OVI2 | \ + FPCR_STATUS_DNO2) -#define FPCR_STATUS_MASK3 (FPCR_STATUS_INV3 | FPCR_STATUS_DZE3 | \ +#define FPCR_STATUS_MASK3 (FPCR_STATUS_INV3 | FPCR_STATUS_DZE3 | \ FPCR_STATUS_OVF3 | FPCR_STATUS_UNF3 | \ - FPCR_STATUS_INE3 | FPCR_STATUS_OVI3) + FPCR_STATUS_INE3 | FPCR_STATUS_OVI3 | \ + FPCR_STATUS_DNO3) + +#define FPCR_STATUS_MASK_ALL (FPCR_STATUS_MASK0 | FPCR_STATUS_MASK1 |\ + FPCR_STATUS_MASK2 | FPCR_STATUS_MASK3) /* @@ -91,38 +98,25 @@ #define IEEE_TRAP_ENABLE_UNF (1UL << 4) /* underflow */ #define IEEE_TRAP_ENABLE_INE (1UL << 5) /* inexact */ #define IEEE_TRAP_ENABLE_DNO (1UL << 6) /* denorm */ +#define IEEE_TRAP_ENABLE_OVI (1UL << 7) /* integer overflow */ #define IEEE_TRAP_ENABLE_MASK (IEEE_TRAP_ENABLE_INV | IEEE_TRAP_ENABLE_DZE |\ IEEE_TRAP_ENABLE_OVF | IEEE_TRAP_ENABLE_UNF |\ - IEEE_TRAP_ENABLE_INE | IEEE_TRAP_ENABLE_DNO) + IEEE_TRAP_ENABLE_INE | IEEE_TRAP_ENABLE_DNO |\ + IEEE_TRAP_ENABLE_OVI) + +#define IEEE_CTL_EXUN (1UL << 10) /* exact denorm result underflow */ /* Denorm and Underflow flushing */ #define IEEE_MAP_DMZ (1UL << 12) /* Map denorm inputs to zero */ #define IEEE_HARD_DM (1UL << 12) /* Hardware denorm processing */ #define IEEE_MAP_UMZ (1UL << 13) /* Map underflowed outputs to zero */ -#define IEEE_MAP_MASK (IEEE_MAP_DMZ | IEEE_MAP_UMZ) +#define IEEE_MAP_MASK (IEEE_HARD_DM | IEEE_MAP_UMZ) /* status bits coming from fpcr: */ -#define IEEE_STATUS_INV (1UL << 17) -#define IEEE_STATUS_DZE (1UL << 18) -#define IEEE_STATUS_OVF (1UL << 19) -#define IEEE_STATUS_UNF (1UL << 20) -#define IEEE_STATUS_INE (1UL << 21) -#define IEEE_STATUS_DNO (1UL << 22) - - -#define IEEE_STATUS_MASK (IEEE_STATUS_INV | IEEE_STATUS_DZE | \ - IEEE_STATUS_OVF | IEEE_STATUS_UNF | \ - IEEE_STATUS_INE | IEEE_STATUS_DNO) - -#define IEEE_SW_MASK (IEEE_TRAP_ENABLE_MASK | \ - IEEE_STATUS_MASK | IEEE_MAP_MASK) - #define IEEE_CURRENT_RM_SHIFT 32 #define IEEE_CURRENT_RM_MASK (3UL << IEEE_CURRENT_RM_SHIFT) -#define IEEE_STATUS_TO_EXCSUM_SHIFT 16 - #define IEEE_INHERIT (1UL << 63) /* inherit on thread create? */ /* ieee_state expand to surport simd added by fire3 */ @@ -133,11 +127,11 @@ #define IEEE_STATUS_UNF0 (1UL << 20) #define IEEE_STATUS_INE0 (1UL << 21) #define IEEE_STATUS_DNO0 (1UL << 22) +#define IEEE_STATUS_OVI0 (1UL << 46) #define IEEE_STATUS_MASK0 (IEEE_STATUS_INV0 | IEEE_STATUS_DZE0 | \ IEEE_STATUS_OVF0 | IEEE_STATUS_UNF0 | \ - IEEE_STATUS_INE0 | IEEE_STATUS_DNO0) - -#define IEEE_STATUS0_TO_EXCSUM_SHIFT 16 + IEEE_STATUS_INE0 | IEEE_STATUS_DNO0 | \ + IEEE_STATUS_OVI0) #define IEEE_STATUS_INV1 (1UL << 23) #define IEEE_STATUS_DZE1 (1UL << 24) @@ -145,11 +139,11 @@ #define IEEE_STATUS_UNF1 (1UL << 26) #define IEEE_STATUS_INE1 (1UL << 27) #define IEEE_STATUS_DNO1 (1UL << 28) +#define IEEE_STATUS_OVI1 (1UL << 47) #define IEEE_STATUS_MASK1 (IEEE_STATUS_INV1 | IEEE_STATUS_DZE1 | \ IEEE_STATUS_OVF1 | IEEE_STATUS_UNF1 | \ - IEEE_STATUS_INE1 | IEEE_STATUS_DNO1) - -#define IEEE_STATUS1_TO_EXCSUM_SHIFT 22 + IEEE_STATUS_INE1 | IEEE_STATUS_DNO1 | \ + IEEE_STATUS_OVI1) #define IEEE_STATUS_INV2 (1UL << 34) #define IEEE_STATUS_DZE2 (1UL << 35) @@ -157,11 +151,11 @@ #define IEEE_STATUS_UNF2 (1UL << 37) #define IEEE_STATUS_INE2 (1UL << 38) #define IEEE_STATUS_DNO2 (1UL << 39) +#define IEEE_STATUS_OVI2 (1UL << 48) #define IEEE_STATUS_MASK2 (IEEE_STATUS_INV2 | IEEE_STATUS_DZE2 | \ IEEE_STATUS_OVF2 | IEEE_STATUS_UNF2 | \ - IEEE_STATUS_INE2 | IEEE_STATUS_DNO2) - -#define IEEE_STATUS2_TO_EXCSUM_SHIFT 33 + IEEE_STATUS_INE2 | IEEE_STATUS_DNO2 | \ + IEEE_STATUS_OVI2) #define IEEE_STATUS_INV3 (1UL << 40) #define IEEE_STATUS_DZE3 (1UL << 41) @@ -169,54 +163,139 @@ #define IEEE_STATUS_UNF3 (1UL << 43) #define IEEE_STATUS_INE3 (1UL << 44) #define IEEE_STATUS_DNO3 (1UL << 45) +#define IEEE_STATUS_OVI3 (1UL << 49) #define IEEE_STATUS_MASK3 (IEEE_STATUS_INV3 | IEEE_STATUS_DZE3 | \ IEEE_STATUS_OVF3 | IEEE_STATUS_UNF3 | \ - IEEE_STATUS_INE3 | IEEE_STATUS_DNO3) + IEEE_STATUS_INE3 | IEEE_STATUS_DNO3 | \ + IEEE_STATUS_OVI3) + +#define IEEE_STATUS_MASK_ALL (IEEE_STATUS_MASK0 | IEEE_STATUS_MASK1 |\ + IEEE_STATUS_MASK2 | IEEE_STATUS_MASK3) -#define IEEE_STATUS3_TO_EXCSUM_SHIFT 39 +#define IEEE_CTL_MASK (IEEE_TRAP_ENABLE_MASK | IEEE_MAP_MASK) +#define IEEE_SW_MASK (IEEE_STATUS_MASK_ALL | IEEE_CTL_MASK) /* * Convert the software IEEE trap enable and status bits into the * hardware fpcr format. */ + +static inline unsigned long +ieee_status_swcr_to_fpcr(unsigned long sw_status) +{ + unsigned long fp_status = 0; + + fp_status |= (sw_status & (IEEE_STATUS_INV0 | IEEE_STATUS_DZE0 | + IEEE_STATUS_OVF0 | IEEE_STATUS_UNF0 | + IEEE_STATUS_INE0)) << (52 - 17); + + fp_status |= (sw_status & (IEEE_STATUS_INV1 | IEEE_STATUS_DZE1 | + IEEE_STATUS_OVF1 | IEEE_STATUS_UNF1 | + IEEE_STATUS_INE1)) << (36 - 23); + + fp_status |= (sw_status & (IEEE_STATUS_INV2 | IEEE_STATUS_DZE2 | + IEEE_STATUS_OVF2 | IEEE_STATUS_UNF2 | + IEEE_STATUS_INE2)) >> (34 - 20); + + fp_status |= (sw_status & (IEEE_STATUS_INV3 | IEEE_STATUS_DZE3 | + IEEE_STATUS_OVF3 | IEEE_STATUS_UNF3 | + IEEE_STATUS_INE3)) >> (40 - 4); + + fp_status |= sw_status & IEEE_STATUS_OVI0 ? FPCR_STATUS_OVI0 : 0; + fp_status |= sw_status & IEEE_STATUS_DNO0 ? FPCR_STATUS_DNO0 : 0; + + fp_status |= sw_status & IEEE_STATUS_OVI1 ? FPCR_STATUS_OVI1 : 0; + fp_status |= sw_status & IEEE_STATUS_DNO1 ? FPCR_STATUS_DNO1 : 0; + + fp_status |= sw_status & IEEE_STATUS_OVI2 ? FPCR_STATUS_OVI2 : 0; + fp_status |= sw_status & IEEE_STATUS_DNO2 ? FPCR_STATUS_DNO2 : 0; + + fp_status |= sw_status & IEEE_STATUS_OVI3 ? FPCR_STATUS_OVI3 : 0; + fp_status |= sw_status & IEEE_STATUS_DNO3 ? FPCR_STATUS_DNO3 : 0; + + return fp_status; +} + static inline unsigned long ieee_swcr_to_fpcr(unsigned long sw) { unsigned long fp; - fp = (sw & IEEE_STATUS_MASK0) << 35; - fp |= (sw & IEEE_STATUS_MASK1) << 13; - fp |= (sw & IEEE_STATUS_MASK2) >> 14; - fp |= (sw & IEEE_STATUS_MASK3) >> 36; - - fp |= (sw & IEEE_MAP_DMZ) << 36; - fp |= (sw & IEEE_STATUS_MASK0 ? FPCR_SUM : 0); - fp |= (sw & IEEE_STATUS_MASK1 ? FPCR_SUM : 0); - fp |= (sw & IEEE_STATUS_MASK2 ? FPCR_SUM : 0); - fp |= (sw & IEEE_STATUS_MASK3 ? FPCR_SUM : 0); - fp |= (~sw & (IEEE_TRAP_ENABLE_INV - | IEEE_TRAP_ENABLE_DZE - | IEEE_TRAP_ENABLE_OVF)) << 48; - fp |= (~sw & (IEEE_TRAP_ENABLE_UNF | IEEE_TRAP_ENABLE_INE)) << 57; - fp |= (sw & IEEE_MAP_UMZ ? FPCR_UNDZ | FPCR_UNFD : 0); - fp |= (~sw & IEEE_TRAP_ENABLE_DNO) << 41; + fp = ieee_status_swcr_to_fpcr(sw & IEEE_STATUS_MASK_ALL); + + fp |= sw & IEEE_STATUS_MASK_ALL ? FPCR_SUM : 0; + + fp |= sw & IEEE_CTL_EXUN ? FPCR_EXUN : 0; + fp |= sw & IEEE_HARD_DM ? FPCR_DNOE : 0; + fp |= sw & IEEE_MAP_UMZ ? FPCR_UNDZ : 0; + + fp |= sw & IEEE_TRAP_ENABLE_INV ? 0 : FPCR_INVD; + fp |= sw & IEEE_TRAP_ENABLE_DZE ? 0 : FPCR_DZED; + fp |= sw & IEEE_TRAP_ENABLE_OVF ? 0 : FPCR_OVFD; + fp |= sw & IEEE_TRAP_ENABLE_UNF ? 0 : FPCR_UNFD; + fp |= sw & IEEE_TRAP_ENABLE_INE ? 0 : FPCR_INED; + fp |= sw & IEEE_TRAP_ENABLE_DNO ? 0 : FPCR_DNOD; + fp |= sw & IEEE_TRAP_ENABLE_OVI ? 0 : FPCR_OVID; + return fp; } +static inline unsigned long +ieee_status_fpcr_to_swcr(unsigned long fp_status) +{ + unsigned long sw_status = 0; + + sw_status |= (fp_status & (FPCR_STATUS_INV0 | FPCR_STATUS_DZE0 | + FPCR_STATUS_OVF0 | FPCR_STATUS_UNF0 | + FPCR_STATUS_INE0)) >> (52 - 17); + + sw_status |= (fp_status & (FPCR_STATUS_INV1 | FPCR_STATUS_DZE1 | + FPCR_STATUS_OVF1 | FPCR_STATUS_UNF1 | + FPCR_STATUS_INE1)) >> (36 - 23); + + sw_status |= (fp_status & (FPCR_STATUS_INV2 | FPCR_STATUS_DZE2 | + FPCR_STATUS_OVF2 | FPCR_STATUS_UNF2 | + FPCR_STATUS_INE2)) << (34 - 20); + + sw_status |= (fp_status & (FPCR_STATUS_INV3 | FPCR_STATUS_DZE3 | + FPCR_STATUS_OVF3 | FPCR_STATUS_UNF3 | + FPCR_STATUS_INE3)) << (40 - 4); + + sw_status |= fp_status & FPCR_STATUS_OVI0 ? IEEE_STATUS_OVI0 : 0; + sw_status |= fp_status & FPCR_STATUS_DNO0 ? IEEE_STATUS_DNO0 : 0; + + sw_status |= fp_status & FPCR_STATUS_OVI1 ? IEEE_STATUS_OVI1 : 0; + sw_status |= fp_status & FPCR_STATUS_DNO1 ? IEEE_STATUS_DNO1 : 0; + + sw_status |= fp_status & FPCR_STATUS_OVI2 ? IEEE_STATUS_OVI2 : 0; + sw_status |= fp_status & FPCR_STATUS_DNO2 ? IEEE_STATUS_DNO2 : 0; + + sw_status |= fp_status & FPCR_STATUS_OVI3 ? IEEE_STATUS_OVI3 : 0; + sw_status |= fp_status & FPCR_STATUS_DNO3 ? IEEE_STATUS_DNO3 : 0; + + return sw_status; +} + static inline unsigned long ieee_fpcr_to_swcr(unsigned long fp) { unsigned long sw; - sw = (fp >> 35) & IEEE_STATUS_MASK; - sw |= (fp >> 36) & IEEE_MAP_DMZ; - sw |= (~fp >> 48) & (IEEE_TRAP_ENABLE_INV - | IEEE_TRAP_ENABLE_DZE - | IEEE_TRAP_ENABLE_OVF); - sw |= (~fp >> 57) & (IEEE_TRAP_ENABLE_UNF | IEEE_TRAP_ENABLE_INE); - sw |= (fp >> 47) & IEEE_MAP_UMZ; - sw |= (~fp >> 41) & IEEE_TRAP_ENABLE_DNO; + sw = ieee_status_fpcr_to_swcr(fp & FPCR_STATUS_MASK_ALL); + + sw |= fp & FPCR_EXUN ? IEEE_CTL_EXUN : 0; + sw |= fp & FPCR_DNOE ? IEEE_HARD_DM : 0; + sw |= fp & FPCR_UNDZ ? IEEE_MAP_UMZ : 0; + + sw |= fp & FPCR_INVD ? 0 : IEEE_TRAP_ENABLE_INV; + sw |= fp & FPCR_DZED ? 0 : IEEE_TRAP_ENABLE_DZE; + sw |= fp & FPCR_OVFD ? 0 : IEEE_TRAP_ENABLE_OVF; + sw |= fp & FPCR_UNFD ? 0 : IEEE_TRAP_ENABLE_UNF; + sw |= fp & FPCR_INED ? 0 : IEEE_TRAP_ENABLE_INE; + sw |= fp & FPCR_DNOD ? 0 : IEEE_TRAP_ENABLE_DNO; + sw |= fp & FPCR_OVID ? 0 : IEEE_TRAP_ENABLE_OVI; + return sw; } #endif /* _UAPI_ASM_SW64_FPU_H */ diff --git a/arch/sw_64/kernel/sys_sw64.c b/arch/sw_64/kernel/sys_sw64.c index d0198aef554d..46e6197dce76 100644 --- a/arch/sw_64/kernel/sys_sw64.c +++ b/arch/sw_64/kernel/sys_sw64.c @@ -62,7 +62,7 @@ SYSCALL_DEFINE5(setsysinfo, unsigned long, op, void __user *, buffer, if (get_user(exc, (unsigned long __user *)buffer)) return -EFAULT; state = ¤t_thread_info()->ieee_state; - exc &= IEEE_STATUS_MASK; + exc &= IEEE_STATUS_MASK_ALL; /* Update softare trap enable bits. */ swcr = (*state & IEEE_SW_MASK) | exc; @@ -76,7 +76,7 @@ SYSCALL_DEFINE5(setsysinfo, unsigned long, op, void __user *, buffer, /* If any exceptions set by this call, and are unmasked, * send a signal. Old exceptions are not signaled. */ - fex = (exc >> IEEE_STATUS_TO_EXCSUM_SHIFT) & swcr; + fex = swcr_status_to_fex(exc, -1) & swcr; if (fex) { int si_code = FPE_FLTUNK; @@ -92,6 +92,8 @@ SYSCALL_DEFINE5(setsysinfo, unsigned long, op, void __user *, buffer, si_code = FPE_FLTDIV; if (fex & IEEE_TRAP_ENABLE_INV) si_code = FPE_FLTINV; + if (fex & IEEE_TRAP_ENABLE_OVI) + si_code = FPE_INTOVF; send_sig_fault(SIGFPE, si_code, (void __user *)NULL, current); } diff --git a/arch/sw_64/kernel/traps.c b/arch/sw_64/kernel/traps.c index 49edc5f8611e..79f5d8da4324 100644 --- a/arch/sw_64/kernel/traps.c +++ b/arch/sw_64/kernel/traps.c @@ -143,17 +143,47 @@ EXPORT_SYMBOL_GPL(sw64_fp_emul_imprecise); long (*sw64_fp_emul)(unsigned long pc) = (void *)dummy_emul; EXPORT_SYMBOL_GPL(sw64_fp_emul); #else -long sw64_fp_emul_imprecise(struct pt_regs *regs, unsigned long writemask); -long sw64_fp_emul(unsigned long pc); +extern long sw64_fp_emul_imprecise(struct pt_regs *regs, unsigned long writemask); +extern long sw64_fp_emul(unsigned long pc); #endif asmlinkage void -do_entArith(unsigned long summary, unsigned long write_mask, +do_entArith(unsigned long exc_sum, unsigned long write_mask, struct pt_regs *regs) { long si_code = FPE_FLTINV; - if (summary & 1) { +#ifndef CONFIG_SUBARCH_C3B + /* integer divide by zero */ + if (exc_sum & EXC_SUM_DZE_INT) + si_code = FPE_INTDIV; + /* integer overflow */ + else if (exc_sum & EXC_SUM_OVI) + si_code = FPE_INTOVF; + /* floating point invalid operation */ + else if (exc_sum & EXC_SUM_INV) + si_code = FPE_FLTINV; + /* floating point divide by zero */ + else if (exc_sum & EXC_SUM_DZE) + si_code = FPE_FLTDIV; + /* floating point overflow */ + else if (exc_sum & EXC_SUM_OVF) + si_code = FPE_FLTOVF; + /* floating point underflow */ + else if (exc_sum & EXC_SUM_UNF) + si_code = FPE_FLTUND; + /* floating point inexact result */ + else if (exc_sum & EXC_SUM_INE) + si_code = FPE_FLTRES; + /* denormalized operand */ + else if (exc_sum & EXC_SUM_DNO) + si_code = FPE_FLTUND; + /* undiagnosed floating-point exception */ + else + si_code = FPE_FLTUNK; +#endif + + if ((exc_sum & EXC_SUM_FP_STATUS_ALL) && (exc_sum & EXC_SUM_SWC)) { /* Software-completion summary bit is set, so try to * emulate the instruction. If the processor supports * precise exceptions, we don't have to search. @@ -166,10 +196,6 @@ do_entArith(unsigned long summary, unsigned long write_mask, if (!user_mode(regs)) die("Arithmetic fault", regs, 0); - /*summary<39> means integer divide by zero in C4.*/ - if ((summary >> 39) & 1) - si_code = FPE_INTDIV; - force_sig_fault(SIGFPE, si_code, (void __user *)regs->pc); } diff --git a/arch/sw_64/math-emu/math.c b/arch/sw_64/math-emu/math.c index 6da3aadcff88..2fd2709fd08c 100644 --- a/arch/sw_64/math-emu/math.c +++ b/arch/sw_64/math-emu/math.c @@ -30,8 +30,6 @@ * This is for sw64 */ -#define IEEE_E_STATUS_MASK IEEE_STATUS_MASK -#define IEEE_E_STATUS_TO_EXCSUM_SHIFT 0 #define SW64_FP_DENOMAL 1 /* A denormal data */ #define SW64_FP_NORMAL 0 /* A denormal data */ #define SW64_FP_NAN 2 @@ -601,9 +599,9 @@ long sw64_fp_emul(unsigned long pc) done: if (_fex) { /* Record exceptions in software control word. */ - swcr |= (_fex << IEEE_STATUS_TO_EXCSUM_SHIFT); + swcr |= fex_to_swcr_status(_fex, 0); current_thread_info()->ieee_state - |= (_fex << IEEE_STATUS_TO_EXCSUM_SHIFT); + |= fex_to_swcr_status(_fex, 0); /* Update hardware control register. */ fpcr &= (~FPCR_MASK | FPCR_DYN_MASK); @@ -860,9 +858,9 @@ long simd_cmp_emul_d(unsigned long pc) swcr_p0 = swcr_p1 = swcr_p2 = swcr_p3 = swcr; /* manage fpcr_p0 */ if (fex_p0) { - swcr_p0 |= (fex_p0 << IEEE_STATUS0_TO_EXCSUM_SHIFT); + swcr_p0 |= fex_to_swcr_status(fex_p0, 0); current_thread_info()->ieee_state - |= (fex_p0 << IEEE_STATUS0_TO_EXCSUM_SHIFT); + |= fex_to_swcr_status(fex_p0, 0); /* Update hardware control register. */ fpcr_p0 = fpcr; @@ -871,9 +869,9 @@ long simd_cmp_emul_d(unsigned long pc) } if (fex_p1) { - swcr_p1 |= (fex_p1 << IEEE_STATUS1_TO_EXCSUM_SHIFT); + swcr_p1 |= fex_to_swcr_status(fex_p1, 1); current_thread_info()->ieee_state - |= (fex_p1 << IEEE_STATUS1_TO_EXCSUM_SHIFT); + |= fex_to_swcr_status(fex_p1, 1); /* Update hardware control register. */ fpcr_p1 = fpcr; @@ -882,9 +880,9 @@ long simd_cmp_emul_d(unsigned long pc) } if (fex_p2) { - swcr_p2 |= (fex_p2 << IEEE_STATUS2_TO_EXCSUM_SHIFT); + swcr_p2 |= fex_to_swcr_status(fex_p2, 2); current_thread_info()->ieee_state - |= (fex_p2 << IEEE_STATUS2_TO_EXCSUM_SHIFT); + |= fex_to_swcr_status(fex_p2, 2); /* Update hardware control register. */ fpcr_p2 = fpcr; @@ -893,9 +891,9 @@ long simd_cmp_emul_d(unsigned long pc) } if (fex_p3) { - swcr_p3 |= (fex_p3 << IEEE_STATUS3_TO_EXCSUM_SHIFT); + swcr_p3 |= fex_to_swcr_status(fex_p3, 3); current_thread_info()->ieee_state - |= (fex_p3 << IEEE_STATUS3_TO_EXCSUM_SHIFT); + |= fex_to_swcr_status(fex_p3, 3); /* Update hardware control register. */ fpcr_p3 = fpcr; @@ -1127,9 +1125,9 @@ long simd_fp_emul_d(unsigned long pc) swcr_p0 = swcr_p1 = swcr_p2 = swcr_p3 = swcr; /* manage fpcr_p0 */ if (fex_p0) { - swcr_p0 |= (fex_p0 << IEEE_STATUS0_TO_EXCSUM_SHIFT); + swcr_p0 |= fex_to_swcr_status(fex_p0, 0); current_thread_info()->ieee_state - |= (fex_p0 << IEEE_STATUS0_TO_EXCSUM_SHIFT); + |= fex_to_swcr_status(fex_p0, 0); /* Update hardware control register. */ fpcr_p0 = fpcr; @@ -1138,9 +1136,9 @@ long simd_fp_emul_d(unsigned long pc) } if (fex_p1) { - swcr_p1 |= (fex_p1 << IEEE_STATUS1_TO_EXCSUM_SHIFT); + swcr_p1 |= fex_to_swcr_status(fex_p1, 1); current_thread_info()->ieee_state - |= (fex_p1 << IEEE_STATUS1_TO_EXCSUM_SHIFT); + |= fex_to_swcr_status(fex_p1, 1); /* Update hardware control register. */ fpcr_p1 = fpcr; @@ -1149,9 +1147,9 @@ long simd_fp_emul_d(unsigned long pc) } if (fex_p2) { - swcr_p2 |= (fex_p2 << IEEE_STATUS2_TO_EXCSUM_SHIFT); + swcr_p2 |= fex_to_swcr_status(fex_p2, 2); current_thread_info()->ieee_state - |= (fex_p2 << IEEE_STATUS2_TO_EXCSUM_SHIFT); + |= fex_to_swcr_status(fex_p2, 2); /* Update hardware control register. */ fpcr_p2 = fpcr; @@ -1160,9 +1158,9 @@ long simd_fp_emul_d(unsigned long pc) } if (fex_p3) { - swcr_p3 |= (fex_p3 << IEEE_STATUS3_TO_EXCSUM_SHIFT); + swcr_p3 |= fex_to_swcr_status(fex_p3, 3); current_thread_info()->ieee_state - |= (fex_p3 << IEEE_STATUS3_TO_EXCSUM_SHIFT); + |= fex_to_swcr_status(fex_p3, 3); /* Update hardware control register. */ fpcr_p3 = fpcr; @@ -1393,9 +1391,9 @@ long simd_fp_emul_s(unsigned long pc) swcr_p0 = swcr_p1 = swcr_p2 = swcr_p3 = swcr; /* manage fpcr_p0 */ if (fex_p0) { - swcr_p0 |= (fex_p0 << IEEE_STATUS0_TO_EXCSUM_SHIFT); + swcr_p0 |= fex_to_swcr_status(fex_p0, 0); current_thread_info()->ieee_state - |= (fex_p0 << IEEE_STATUS0_TO_EXCSUM_SHIFT); + |= fex_to_swcr_status(fex_p0, 0); /* Update hardware control register. */ fpcr_p0 = fpcr; @@ -1405,9 +1403,9 @@ long simd_fp_emul_s(unsigned long pc) } if (fex_p1) { - swcr_p1 |= (fex_p1 << IEEE_STATUS1_TO_EXCSUM_SHIFT); + swcr_p1 |= fex_to_swcr_status(fex_p1, 1); current_thread_info()->ieee_state - |= (fex_p1 << IEEE_STATUS1_TO_EXCSUM_SHIFT); + |= fex_to_swcr_status(fex_p1, 1); /* Update hardware control register. */ fpcr_p1 = fpcr; @@ -1417,9 +1415,9 @@ long simd_fp_emul_s(unsigned long pc) } if (fex_p2) { - swcr_p2 |= (fex_p2 << IEEE_STATUS2_TO_EXCSUM_SHIFT); + swcr_p2 |= fex_to_swcr_status(fex_p2, 2); current_thread_info()->ieee_state - |= (fex_p2 << IEEE_STATUS2_TO_EXCSUM_SHIFT); + |= fex_to_swcr_status(fex_p2, 2); /* Update hardware control register. */ fpcr_p2 = fpcr; @@ -1429,9 +1427,9 @@ long simd_fp_emul_s(unsigned long pc) } if (fex_p3) { - swcr_p3 |= (fex_p3 << IEEE_STATUS3_TO_EXCSUM_SHIFT); + swcr_p3 |= fex_to_swcr_status(fex_p3, 3); current_thread_info()->ieee_state - |= (fex_p3 << IEEE_STATUS3_TO_EXCSUM_SHIFT); + |= fex_to_swcr_status(fex_p3, 3); /* Update hardware control register. */ fpcr_p3 = fpcr; @@ -1606,9 +1604,9 @@ long mul_add_fp_emul(unsigned long pc) DEBUG_INFO("vd = %#lx\n", vd); if (_fex) { /* Record exceptions in software control word. */ - swcr |= (_fex << IEEE_STATUS_TO_EXCSUM_SHIFT); + swcr |= fex_to_swcr_status(_fex, 0); current_thread_info()->ieee_state - |= (_fex << IEEE_STATUS_TO_EXCSUM_SHIFT); + |= fex_to_swcr_status(_fex, 0); /* Update hardware control register. */ fpcr &= (~FPCR_MASK | FPCR_DYN_MASK); @@ -1851,9 +1849,9 @@ long simd_mul_add_fp_emul_s(unsigned long pc) swcr_p0 = swcr_p1 = swcr_p2 = swcr_p3 = swcr; /* manage fpcr_p0 */ if (fex_p0) { - swcr_p0 |= (fex_p0 << IEEE_STATUS0_TO_EXCSUM_SHIFT); + swcr_p0 |= fex_to_swcr_status(fex_p0, 0); current_thread_info()->ieee_state - |= (fex_p0 << IEEE_STATUS0_TO_EXCSUM_SHIFT); + |= fex_to_swcr_status(fex_p0, 0); /* Update hardware control register. */ fpcr_p0 = fpcr; @@ -1862,9 +1860,9 @@ long simd_mul_add_fp_emul_s(unsigned long pc) } if (fex_p1) { - swcr_p1 |= (fex_p1 << IEEE_STATUS1_TO_EXCSUM_SHIFT); + swcr_p1 |= fex_to_swcr_status(fex_p1, 1); current_thread_info()->ieee_state - |= (fex_p1 << IEEE_STATUS1_TO_EXCSUM_SHIFT); + |= fex_to_swcr_status(fex_p1, 1); /* Update hardware control register. */ fpcr_p1 = fpcr; @@ -1873,9 +1871,9 @@ long simd_mul_add_fp_emul_s(unsigned long pc) } if (fex_p2) { - swcr_p2 |= (fex_p2 << IEEE_STATUS2_TO_EXCSUM_SHIFT); + swcr_p2 |= fex_to_swcr_status(fex_p2, 2); current_thread_info()->ieee_state - |= (fex_p2 << IEEE_STATUS2_TO_EXCSUM_SHIFT); + |= fex_to_swcr_status(fex_p2, 2); /* Update hardware control register. */ fpcr_p2 = fpcr; @@ -1884,9 +1882,9 @@ long simd_mul_add_fp_emul_s(unsigned long pc) } if (fex_p3) { - swcr_p3 |= (fex_p3 << IEEE_STATUS3_TO_EXCSUM_SHIFT); + swcr_p3 |= fex_to_swcr_status(fex_p3, 3); current_thread_info()->ieee_state - |= (fex_p3 << IEEE_STATUS3_TO_EXCSUM_SHIFT); + |= fex_to_swcr_status(fex_p3, 3); /* Update hardware control register. */ fpcr_p3 = fpcr; @@ -2139,9 +2137,9 @@ long simd_mul_add_fp_emul_d(unsigned long pc) swcr_p0 = swcr_p1 = swcr_p2 = swcr_p3 = swcr; /* manage fpcr_p0 */ if (fex_p0) { - swcr_p0 |= (fex_p0 << IEEE_STATUS0_TO_EXCSUM_SHIFT); + swcr_p0 |= fex_to_swcr_status(fex_p0, 0); current_thread_info()->ieee_state - |= (fex_p0 << IEEE_STATUS0_TO_EXCSUM_SHIFT); + |= fex_to_swcr_status(fex_p0, 0); /* Update hardware control register. */ fpcr_p0 = fpcr; @@ -2150,9 +2148,9 @@ long simd_mul_add_fp_emul_d(unsigned long pc) } if (fex_p1) { - swcr_p1 |= (fex_p1 << IEEE_STATUS1_TO_EXCSUM_SHIFT); + swcr_p1 |= fex_to_swcr_status(fex_p1, 1); current_thread_info()->ieee_state - |= (fex_p1 << IEEE_STATUS1_TO_EXCSUM_SHIFT); + |= fex_to_swcr_status(fex_p1, 1); /* Update hardware control register. */ fpcr_p1 = fpcr; @@ -2161,9 +2159,9 @@ long simd_mul_add_fp_emul_d(unsigned long pc) } if (fex_p2) { - swcr_p2 |= (fex_p2 << IEEE_STATUS2_TO_EXCSUM_SHIFT); + swcr_p2 |= fex_to_swcr_status(fex_p2, 2); current_thread_info()->ieee_state - |= (fex_p2 << IEEE_STATUS2_TO_EXCSUM_SHIFT); + |= fex_to_swcr_status(fex_p2, 2); /* Update hardware control register. */ fpcr_p2 = fpcr; @@ -2172,9 +2170,9 @@ long simd_mul_add_fp_emul_d(unsigned long pc) } if (fex_p3) { - swcr_p3 |= (fex_p3 << IEEE_STATUS3_TO_EXCSUM_SHIFT); + swcr_p3 |= fex_to_swcr_status(fex_p3, 3); current_thread_info()->ieee_state - |= (fex_p3 << IEEE_STATUS3_TO_EXCSUM_SHIFT); + |= fex_to_swcr_status(fex_p3, 3); /* Update hardware control register. */ fpcr_p3 = fpcr; -- Gitee From e06e6ef066e14e25420a9cd3b1a644cb3b743abf Mon Sep 17 00:00:00 2001 From: Mao Minkai Date: Fri, 2 Feb 2024 17:12:13 +0800 Subject: [PATCH 40/49] anolis: sw64: use a new wrap_asid hmcall when asid wraps ANBZ: #4688 Use a new wrap_asid hmcall which loads the new asid and ptbr before tbivp(). Signed-off-by: Mao Minkai Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/include/asm/hmcall.h | 10 ++++++++++ arch/sw_64/include/asm/mmu_context.h | 7 +++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/arch/sw_64/include/asm/hmcall.h b/arch/sw_64/include/asm/hmcall.h index 62cb26117c1e..8e5afb9deeab 100644 --- a/arch/sw_64/include/asm/hmcall.h +++ b/arch/sw_64/include/asm/hmcall.h @@ -20,6 +20,7 @@ #define HMC_rdhtctl 0x0D #define HMC_wrksp 0x0E #define HMC_mtinten 0x0F +#define HMC_wrap_asid 0x10 #define HMC_load_mm 0x11 #define HMC_tbisasid 0x14 #define HMC_tbivpn 0x19 @@ -231,6 +232,15 @@ __CALL_HMC_W1(wrtp, unsigned long); /* Invalidate all user TLB with current UPN and VPN */ #define tbiu() __tbi(4, /* no second argument */) +#ifndef CONFIG_SUBARCH_C3B +__CALL_HMC_W2(wrap_asid, unsigned long, unsigned long); +#else +static inline void wrap_asid(unsigned long asid, unsigned long ptbr) +{ + tbivp(); +} +#endif + #endif /* !__ASSEMBLY__ */ #endif /* __KERNEL__ */ diff --git a/arch/sw_64/include/asm/mmu_context.h b/arch/sw_64/include/asm/mmu_context.h index c69de5e7a2aa..c8af39229cd1 100644 --- a/arch/sw_64/include/asm/mmu_context.h +++ b/arch/sw_64/include/asm/mmu_context.h @@ -41,10 +41,13 @@ static inline bool asid_valid(struct mm_struct *mm, unsigned int cpu) static inline void __get_new_mm_context(struct mm_struct *mm, long cpu) { + unsigned long ptbr; unsigned long asid = last_asid(cpu); - if (!(++asid & ASID_MASK)) - tbivp(); + if (!(++asid & ASID_MASK)) { + ptbr = virt_to_pfn(mm->pgd); + wrap_asid(asid, ptbr); + } mm->context.asid[cpu] = last_asid(cpu) = asid; } -- Gitee From 94498225f6101e6d42b9d64498b0351b741e3c75 Mon Sep 17 00:00:00 2001 From: He Chuyue Date: Tue, 27 Feb 2024 15:50:41 +0800 Subject: [PATCH 41/49] anolis: sw64: mm: fix PTE bits check ANBZ: #4688 PTE on SW64 is 64 bit, and some helper functions such as pmd_dirty() and pte_dirty() which check PTE bits return an int value. If PTE bit to be tested resides in bit [63:32], it will result in truncation of significant digits in the return value. This patch fix it with double logic negation to avoid possible truncation. Signed-off-by: He Chuyue Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/include/asm/pgtable.h | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/arch/sw_64/include/asm/pgtable.h b/arch/sw_64/include/asm/pgtable.h index defda893dd41..102da6a411fe 100644 --- a/arch/sw_64/include/asm/pgtable.h +++ b/arch/sw_64/include/asm/pgtable.h @@ -339,12 +339,12 @@ static inline int pte_none(pte_t pte) static inline int pte_present(pte_t pte) { - return pte_val(pte) & (_PAGE_VALID | _PAGE_PROTNONE); + return !!(pte_val(pte) & (_PAGE_VALID | _PAGE_PROTNONE)); } static inline int pte_huge(pte_t pte) { - return pte_val(pte) & _PAGE_LEAF; + return !!(pte_val(pte) & _PAGE_LEAF); } static inline void pte_clear(struct mm_struct *mm, @@ -384,7 +384,7 @@ static inline int pmd_present(pmd_t pmd) * the _PAGE_LEAF flag will remain set at all times while the * _PAGE_VALID bit is clear). */ - return pmd_val(pmd) & (_PAGE_VALID | _PAGE_PROTNONE | _PAGE_LEAF); + return !!(pmd_val(pmd) & (_PAGE_VALID | _PAGE_PROTNONE | _PAGE_LEAF)); } static inline void pmd_clear(pmd_t *pmdp) @@ -394,12 +394,12 @@ static inline void pmd_clear(pmd_t *pmdp) static inline int pmd_dirty(pmd_t pmd) { - return pmd_val(pmd) & _PAGE_DIRTY; + return !!(pmd_val(pmd) & _PAGE_DIRTY); } static inline int pmd_young(pmd_t pmd) { - return pmd_val(pmd) & _PAGE_ACCESSED; + return !!(pmd_val(pmd) & _PAGE_ACCESSED); } #define __HAVE_ARCH_PMD_WRITE @@ -482,7 +482,7 @@ static inline int pud_bad(pud_t pud) static inline int pud_present(pud_t pud) { - return pud_val(pud) & _PAGE_VALID; + return !!(pud_val(pud) & _PAGE_VALID); } static inline void pud_clear(pud_t *pudp) @@ -537,22 +537,22 @@ static inline int pte_write(pte_t pte) static inline int pte_dirty(pte_t pte) { - return pte_val(pte) & _PAGE_DIRTY; + return !!(pte_val(pte) & _PAGE_DIRTY); } static inline int pte_young(pte_t pte) { - return pte_val(pte) & _PAGE_ACCESSED; + return !!(pte_val(pte) & _PAGE_ACCESSED); } static inline int pte_special(pte_t pte) { - return pte_val(pte) & _PAGE_SPECIAL; + return !!(pte_val(pte) & _PAGE_SPECIAL); } static inline int pte_cont(pte_t pte) { - return pte_val(pte) & _PAGE_CONT; + return !!(pte_val(pte) & _PAGE_CONT); } static inline pte_t pte_wrprotect(pte_t pte) @@ -641,17 +641,17 @@ static inline int pte_devmap(pte_t a) static inline int pmd_trans_splitting(pmd_t pmd) { - return pmd_val(pmd) & _PAGE_SPLITTING; + return !!(pmd_val(pmd) & _PAGE_SPLITTING); } static inline int pmd_trans_cont(pmd_t pmd) { - return pmd_val(pmd) & _PAGE_CONT; + return !!(pmd_val(pmd) & _PAGE_CONT); } static inline int pmd_trans_huge(pmd_t pmd) { - return pmd_val(pmd) & _PAGE_LEAF; + return !!(pmd_val(pmd) & _PAGE_LEAF); } static inline int has_transparent_hugepage(void) -- Gitee From 7faf20a7bf3f5c8793712e41f387380ac3b51d18 Mon Sep 17 00:00:00 2001 From: Jing Li Date: Wed, 20 Dec 2023 19:45:03 +0800 Subject: [PATCH 42/49] anolis: sw64: acpi: add ACPI-style structures for SW PINTC, MSIC and LPC-INTC ANBZ: #4688 SW PINTC : Sunway Platform Interrupt Controller SW MSIC : Sunway MSI Controller SW LPC-INTC : Sunway LPC Interrupt Controller Signed-off-by: Jing Li Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- include/acpi/actbl2.h | 87 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/include/acpi/actbl2.h b/include/acpi/actbl2.h index b2a11da369ce..e4ca9817938a 100644 --- a/include/acpi/actbl2.h +++ b/include/acpi/actbl2.h @@ -560,6 +560,9 @@ enum acpi_madt_type { * used(start from 0x80). */ ACPI_MADT_TYPE_SW_CINTC = 0x80, + ACPI_MADT_TYPE_SW_PINTC = 0x81, + ACPI_MADT_TYPE_SW_MSIC = 0x82, + ACPI_MADT_TYPE_SW_LPC_INTC = 0x83 #endif }; @@ -930,6 +933,90 @@ enum acpi_madt_sw_cintc_version { ACPI_MADT_SW_CINTC_VERSION_V2 = 2, ACPI_MADT_SW_CINTC_VERSION_RESERVED = 3 /* 3 and greater are reserved */ }; + +/* 0x81: Sunway Platform Interrupt Controller (To be added to ACPI spec) */ + +struct acpi_madt_sw_sub_pintc { + u8 type; + u8 reserved[3]; + u32 hardware_id; + u64 address; + u32 size; + u32 gsi_base; + u32 gsi_count; + u32 cascade_vector; +}; + +struct acpi_madt_sw_pintc { + struct acpi_subtable_header header; + u8 version; + u8 reserved; + u32 flags; + u32 node; + u64 address; + u32 size; + u32 sub_num; + struct acpi_madt_sw_sub_pintc sub[]; +}; + +/* Values for version field above */ + +enum acpi_madt_sw_pintc_version { + ACPI_MADT_SW_PINTC_VERSION_NONE = 0, + ACPI_MADT_SW_PINTC_VERSION_V1 = 1, + ACPI_MADT_SW_PINTC_VERSION_V2 = 2, + ACPI_MADT_SW_PINTC_VERSION_RESERVED = 3 /* 3 and greater are reserved */ +}; + +/* 0x82: Sunway MSI Controller (To be added to ACPI spec) */ + +struct acpi_madt_sw_msic { + struct acpi_subtable_header header; + u8 version; + u8 reserved0; + u32 hardware_id; + u32 flags; + u64 address; + u32 size; + u32 cascade_vector; + u32 node; + u32 rc; + u32 num; + u32 reserved1[4]; +}; + +/* Values for version field above */ + +enum acpi_madt_sw_msic_version { + ACPI_MADT_SW_MSIC_VERSION_NONE = 0, + ACPI_MADT_SW_MSIC_VERSION_V1 = 1, + ACPI_MADT_SW_MSIC_VERSION_V2 = 2, + ACPI_MADT_SW_MSIC_VERSION_RESERVED = 3 /* 3 and greater are reserved */ +}; + +/* 0x83: Sunway LPC Interrupt Controller (To be added to ACPI spec) */ + +struct acpi_madt_sw_lpc_intc { + struct acpi_subtable_header header; + u8 version; + u8 reserved; + u32 hardware_id; + u32 flags; + u64 address; + u32 size; + u32 node; + u32 cascade_vector; + u32 gsi_base; + u32 gsi_count; +}; + +/* Values for version field above */ + +enum acpi_madt_sw_lpc_intc_version { + ACPI_MADT_SW_LPC_INTC_VERSION_NONE = 0, + ACPI_MADT_SW_LPC_INTC_VERSION_V1 = 1, + ACPI_MADT_SW_LPC_INTC_VERSION_RESERVED = 2 /* 2 and greater are reserved */ +}; #endif /* -- Gitee From ff535089f45fda614cffb7d660d874aaf0ba4639 Mon Sep 17 00:00:00 2001 From: Jing Li Date: Wed, 17 Jan 2024 19:16:33 +0800 Subject: [PATCH 43/49] anolis: sw64: acpi: support MADT entry print for SW PINTC, MSIC and LPC-INTC ANBZ: #4688 After this commit, we can print MADT entries of Sunway via the function acpi_table_print_madt_entry(). Signed-off-by: Jing Li Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- drivers/acpi/tables.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c index b90c901e7509..ad12ac173a04 100644 --- a/drivers/acpi/tables.c +++ b/drivers/acpi/tables.c @@ -227,6 +227,33 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header) p->version, p->flags, p->hardware_id); } break; + + case ACPI_MADT_TYPE_SW_PINTC: + { + struct acpi_madt_sw_pintc *p = + (struct acpi_madt_sw_pintc *)header; + pr_info("SW PINTC (version[%u] flags[0x%x] address[0x%llx])\n", + p->version, p->flags, p->address); + } + break; + + case ACPI_MADT_TYPE_SW_MSIC: + { + struct acpi_madt_sw_msic *p = + (struct acpi_madt_sw_msic *)header; + pr_info("SW MSIC (version[%u] flags[0x%x] hardware_id[0x%x])\n", + p->version, p->flags, p->hardware_id); + } + break; + + case ACPI_MADT_TYPE_SW_LPC_INTC: + { + struct acpi_madt_sw_lpc_intc *p = + (struct acpi_madt_sw_lpc_intc *)header; + pr_info("SW LPC INTC (version[%u] flags[0x%x] hardware_id[0x%x])\n", + p->version, p->flags, p->hardware_id); + } + break; #endif default: -- Gitee From bd93cd97bc1d23332b4b2fe81f3f24340ddacd9c Mon Sep 17 00:00:00 2001 From: Jing Li Date: Thu, 21 Dec 2023 16:50:05 +0800 Subject: [PATCH 44/49] anolis: sw64: irqchip: support ACPI-based interrupt controller initialization ANBZ: #4688 Update driver to support initialization of interrupt controllers in ACPI environment, enabling devices to use interrupts. Signed-off-by: Jing Li Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/include/asm/irq.h | 16 ++ arch/sw_64/kernel/acpi.c | 4 - drivers/acpi/bus.c | 5 + drivers/irqchip/Kconfig | 1 + drivers/irqchip/irq-sunway-cpu.c | 209 +++++++++++++++++ drivers/irqchip/irq-sunway-lpc-intc.c | 148 ++++++++++++- drivers/irqchip/irq-sunway-msi-v2.c | 33 +++ drivers/irqchip/irq-sunway-msi.c | 33 +++ drivers/irqchip/irq-sunway-pintc.c | 308 ++++++++++++++++++++++++-- include/acpi/actbl2.h | 6 +- include/linux/acpi.h | 3 + 11 files changed, 724 insertions(+), 42 deletions(-) diff --git a/arch/sw_64/include/asm/irq.h b/arch/sw_64/include/asm/irq.h index be98132ce340..f48e8686df1e 100644 --- a/arch/sw_64/include/asm/irq.h +++ b/arch/sw_64/include/asm/irq.h @@ -28,4 +28,20 @@ extern void (*perf_irq)(unsigned long, struct pt_regs *); extern void fixup_irqs(void); extern void sw64_timer_interrupt(void); +struct irq_domain; +struct fwnode_handle; + +struct acpi_madt_sw_pintc; +struct acpi_madt_sw_msic; +struct acpi_madt_sw_lpc_intc; + +extern int __init sw64_add_gsi_domain_map(u32 gsi_base, u32 gsi_count, + struct fwnode_handle *handle); +extern int __init pintc_acpi_init(struct irq_domain *parent, + struct acpi_madt_sw_pintc *pintc); +extern int __init msic_acpi_init(struct irq_domain *parent, + struct acpi_madt_sw_msic *msic); +extern int __init lpc_intc_acpi_init(struct irq_domain *parent, + struct acpi_madt_sw_lpc_intc *lpc_intc); + #endif /* _ASM_SW64_IRQ_H */ diff --git a/arch/sw_64/kernel/acpi.c b/arch/sw_64/kernel/acpi.c index cb03e949cbc6..9cb37be7ee34 100644 --- a/arch/sw_64/kernel/acpi.c +++ b/arch/sw_64/kernel/acpi.c @@ -28,13 +28,9 @@ u64 acpi_saved_sp_s3; #define SW_CINTC_FLAG_ENABLED ACPI_MADT_ENABLED /* 0x1 */ #define SW_CINTC_FLAG_ONLINE_CAPABLE 0x2 /* hotplug capable */ -#define SW_CINTC_FLAG_HT_CAPABLE 0x4 /* hyper thread capable */ -#define SW_CINTC_FLAG_HT_ENABLED 0x8 /* hyper thread enabled */ #define is_core_enabled(flags) ((flags) & SW_CINTC_FLAG_ENABLED) #define is_core_online_capable(flags) ((flags) & SW_CINTC_FLAG_ONLINE_CAPABLE) -#define is_core_ht_capable(flags) ((flags) & SW_CINTC_FLAG_HT_CAPABLE) -#define is_core_ht_enabled(flags) ((flags) & SW_CINTC_FLAG_HT_ENABLED) #define MAX_LOCAL_APIC 256 diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index c457a7b9e82f..ade4424bde4a 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -1001,6 +1001,11 @@ static int __init acpi_bus_init_irq(void) case ACPI_IRQ_MODEL_LPIC: message = "LPIC"; break; +#ifdef CONFIG_SW64 + case ACPI_IRQ_MODEL_SWPIC: + message = "SWPIC"; + break; +#endif default: printk(KERN_WARNING PREFIX "Unknown interrupt routing model\n"); return -ENODEV; diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index b6dffec29aee..010e788f1ef6 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -17,6 +17,7 @@ config SW64_PINTC default y select GENERIC_IRQ_CHIP select IRQ_DOMAIN + select IRQ_DOMAIN_HIERARCHY help This enables support for the pINTC chip found in SW systems. The PINTC receives all platform devices' interrupts and passes diff --git a/drivers/irqchip/irq-sunway-cpu.c b/drivers/irqchip/irq-sunway-cpu.c index e3d9dac3dfb3..c7f7f3e504da 100644 --- a/drivers/irqchip/irq-sunway-cpu.c +++ b/drivers/irqchip/irq-sunway-cpu.c @@ -2,12 +2,43 @@ #include #include +#include +#include #include #include #include #include +/** + * The topology of interrupt controllers of SW64 is as follows: + * + * +-----------------------------------------------------------+ + * | | + * | +-------------+ | + * | | Core | | + * | +-------------+ | + * | | | + * | +----------------------+ | + * | | SW CINTC | | + * | +----------------------+ | + * | ______| |______ | + * | | | | + * | +-----------+ +--------------+ | + * | | SW MSIC | | SW PINTC | | + * | +-----------+ +--------------+ | + * | | | + * | +--------------+ | + * | | SW LPC INTC | | + * | +--------------+ | + * | | + * +-----------------------------------------------------------+ + */ + +#define PREFIX "CINTC: " + +struct fwnode_handle *cintc_handle; + static void handle_intx(unsigned int offset) { struct pci_controller *hose; @@ -208,3 +239,181 @@ asmlinkage void do_entInt(unsigned long type, unsigned long vector, pr_crit("PC = %016lx PS = %04lx\n", regs->pc, regs->ps); } EXPORT_SYMBOL(do_entInt); + +#ifdef CONFIG_ACPI +#define SW_CINTC_FLAG_VIRTUAL 0x4 /* virtual CINTC */ + +#define is_core_virtual(flags) ((flags) & SW_CINTC_FLAG_VIRTUAL) + +struct gsi_domain_map { + u32 gsi_base; + u32 gsi_count; + struct fwnode_handle *handle; + struct gsi_domain_map *next; +}; + +static struct gsi_domain_map *gsi_domain_map_list; + +int __init sw64_add_gsi_domain_map(u32 gsi_base, u32 gsi_count, + struct fwnode_handle *handle) +{ + struct gsi_domain_map *map; + + if (WARN_ON(!handle)) + return -EINVAL; + + map = kzalloc(sizeof(struct gsi_domain_map), GFP_KERNEL); + if (!map) + return -ENOMEM; + + map->gsi_base = gsi_base; + map->gsi_count = gsi_count; + map->handle = handle; + + map->next = gsi_domain_map_list; + gsi_domain_map_list = map; + + return 0; +} + +/** + * The starting GSI num occupied by different domains are: + * + * SW CINTC on Node(x) : 0 + (512 * x) + * SW PINTC on Node(x) : 64 + (512 * x) + * SW LPC-INTC on Node(x) : 256 + (512 * x) + */ +static struct fwnode_handle *sw64_gsi_to_domain_id(u32 gsi) +{ + struct gsi_domain_map *map; + u32 base, limit; + + for (map = gsi_domain_map_list; map; map = map->next) { + base = map->gsi_base; + limit = map->gsi_base + map->gsi_count; + + if ((gsi >= base) && (gsi < limit)) + return map->handle; + } + + return NULL; +} + +static int __init pintc_parse_madt(union acpi_subtable_headers *header, + const unsigned long end) +{ + struct acpi_madt_sw_pintc *pintc; + + pintc = (struct acpi_madt_sw_pintc *)header; + + /* Not yet supported */ + if (pintc->node > 0) { + pr_warn(PREFIX "PINTC and LPC-INTC on node x(x > 0) are not supported\n"); + return 0; + } + + if ((pintc->version == ACPI_MADT_SW_PINTC_VERSION_NONE) || + (pintc->version >= ACPI_MADT_SW_PINTC_VERSION_RESERVED)) { + pr_err(PREFIX "invalid PINTC version\n"); + return -EINVAL; + } + + return pintc_acpi_init(NULL, pintc); +} + +static int __init msic_parse_madt(union acpi_subtable_headers *header, + const unsigned long end) +{ + struct acpi_madt_sw_msic *msic; + + msic = (struct acpi_madt_sw_msic *)header; + if ((msic->version == ACPI_MADT_SW_MSIC_VERSION_NONE) || + (msic->version >= ACPI_MADT_SW_MSIC_VERSION_RESERVED)) { + pr_err(PREFIX "invalid MSIC version\n"); + return -EINVAL; + } + + return msic_acpi_init(NULL, msic); +} + +static bool __init +acpi_check_sw_cintc_entry(struct acpi_subtable_header *header, + struct acpi_probe_entry *ape) +{ + struct acpi_madt_sw_cintc *cintc; + + cintc = (struct acpi_madt_sw_cintc *)header; + if (cintc->version != ape->driver_data) + return false; + + return true; +} + +static __init int cintc_acpi_init(union acpi_subtable_headers *header, + const unsigned long end) +{ + struct acpi_madt_sw_cintc *cintc; + bool virtual; + + /** + * There are more than one MADT entry of SW CINTC in + * multi-core system, but the initialization here only + * needs to be performed once per node. + */ + if (cintc_handle) + return 0; + + cintc = (struct acpi_madt_sw_cintc *)header; + virtual = is_core_virtual(cintc->flags); + pr_info(PREFIX "version [%u] (%s) found\n", cintc->version, + virtual ? "virtual" : "physical"); + + /** + * Currently, no irq_domain created for SW CINTC. The + * handle only used to avoid multiple initializations. + * Apart from this, there is no other meaning. + * + * Maybe we will create irq_domain for SW CINTC in the + * future to optimize the code. + */ + cintc_handle = irq_domain_alloc_named_fwnode("CINTC"); + if (!cintc_handle) { + pr_err(PREFIX "failed to alloc fwnode\n"); + return -ENOMEM; + } + + acpi_set_irq_model(ACPI_IRQ_MODEL_SWPIC, sw64_gsi_to_domain_id); + + /* Init SW PINTC */ + acpi_table_parse_madt(ACPI_MADT_TYPE_SW_PINTC, + pintc_parse_madt, 0); + + /* Init SW MSIC */ + acpi_table_parse_madt(ACPI_MADT_TYPE_SW_MSIC, + msic_parse_madt, 0); + + /** + * After initializing MSIC, it's time to enable MSI interrupts + * for boot core. For other SMP cores, if present, this + * initialization is performed during SMP startup. + */ + if (!virtual) { + sw64_write_csr(0xffffffffffffffffUL, CSR_PCIE_MSI0_INTEN); + sw64_write_csr(0xffffffffffffffffUL, CSR_PCIE_MSI1_INTEN); + sw64_write_csr(0xffffffffffffffffUL, CSR_PCIE_MSI2_INTEN); + sw64_write_csr(0xffffffffffffffffUL, CSR_PCIE_MSI3_INTEN); + } + + return 0; +} + +IRQCHIP_ACPI_DECLARE(cintc_v1, ACPI_MADT_TYPE_SW_CINTC, + acpi_check_sw_cintc_entry, + ACPI_MADT_SW_CINTC_VERSION_V1, + cintc_acpi_init); + +IRQCHIP_ACPI_DECLARE(cintc_v2, ACPI_MADT_TYPE_SW_CINTC, + acpi_check_sw_cintc_entry, + ACPI_MADT_SW_CINTC_VERSION_V2, + cintc_acpi_init); +#endif diff --git a/drivers/irqchip/irq-sunway-lpc-intc.c b/drivers/irqchip/irq-sunway-lpc-intc.c index bc69d1647aed..db10f363323a 100644 --- a/drivers/irqchip/irq-sunway-lpc-intc.c +++ b/drivers/irqchip/irq-sunway-lpc-intc.c @@ -12,6 +12,8 @@ #define LPC_IRQ 0x4 #define LPC_IRQ_MASK 0x8 +#define SW_LPC_INTC_GSI_BASE 256 + static DEFINE_RAW_SPINLOCK(lpc_lock); static int parent_irq; @@ -110,18 +112,70 @@ static int sw64_lpc_domain_map(struct irq_domain *d, unsigned int virq, return 0; } +static int lpc_intc_translate(struct irq_domain *domain, + struct irq_fwspec *fwspec, + unsigned long *hwirq, + unsigned int *type) +{ + if (WARN_ON(fwspec->param_count < 1)) + return -EINVAL; + + /* Device tree */ + if (is_of_node(fwspec->fwnode)) { + *hwirq = fwspec->param[0]; + *type = IRQ_TYPE_NONE; + return 0; + } + + /* ACPI */ + if (is_fwnode_irqchip(fwspec->fwnode)) { + if (WARN_ON(fwspec->param[0] < SW_LPC_INTC_GSI_BASE)) + return -EINVAL; + *hwirq = fwspec->param[0] - SW_LPC_INTC_GSI_BASE; + *type = IRQ_TYPE_NONE; + return 0; + } + + return -EINVAL; +} + static const struct irq_domain_ops sw64_lpc_domain_ops = { .map = sw64_lpc_domain_map, - .xlate = irq_domain_xlate_onecell, + .translate = lpc_intc_translate, }; +static struct irq_domain *lpc_irq_domain; + +static int __init lpc_intc_init(struct fwnode_handle *handle, + unsigned int irqnr, int parent_irq, void __iomem *base_addr) +{ + /** + * The current kernel does not support "irq_domain_create_legacy", + * we have to call "__irq_domain_add" directly. + */ + lpc_irq_domain = __irq_domain_add(handle, irqnr, irqnr, + 0, &sw64_lpc_domain_ops, base_addr); + if (!lpc_irq_domain) { + pr_info(PREFIX "failed to create irq domain\n"); + return -ENOMEM; + } + + irq_domain_associate_many(lpc_irq_domain, 0, 0, irqnr); + + /* Set the IRQ chaining logic */ + irq_set_chained_handler_and_data(parent_irq, + lpc_irq_handler, lpc_irq_domain); + + return 0; +} + +#ifdef CONFIG_OF struct device_node *sw_lpc_intc_node; EXPORT_SYMBOL(sw_lpc_intc_node); static int __init lpc_intc_of_init(struct device_node *np, struct device_node *parent) { - struct irq_domain *lpc_domain; int ret; u32 nr_irqs, node, version; void __iomem *base; @@ -162,21 +216,13 @@ static int __init lpc_intc_of_init(struct device_node *np, goto out_unmap; } - lpc_domain = irq_domain_add_legacy(np, nr_irqs, - 0, 0, &sw64_lpc_domain_ops, base); - if (!lpc_domain) { - pr_err(PREFIX "failed to create irq domain\n"); - ret = -ENOMEM; + ret = lpc_intc_init(of_node_to_fwnode(np), nr_irqs, parent_irq, base); + if (ret) goto out_unmap; - } pr_info(PREFIX "version [%u] on node [%u] initialized\n", version, node); - /* Set the IRQ chaining logic */ - irq_set_chained_handler_and_data(parent_irq, - lpc_irq_handler, lpc_domain); - return 0; out_unmap: @@ -184,3 +230,81 @@ static int __init lpc_intc_of_init(struct device_node *np, return ret; } IRQCHIP_DECLARE(sw_lpc_intc, "sw64,lpc_intc", lpc_intc_of_init); +#endif + +#ifdef CONFIG_ACPI +#define SW_LPC_INTC_FLAG_ENABLED ACPI_MADT_ENABLED /* 0x1 */ + +#define is_lpc_intc_enabled(flags) ((flags) & SW_LPC_INTC_FLAG_ENABLED) + +int __init lpc_intc_acpi_init(struct irq_domain *parent, + struct acpi_madt_sw_lpc_intc *lpc_intc) +{ + struct fwnode_handle *handle; + struct irq_fwspec fwspec; + void __iomem *base_addr; + int ret; + bool enabled; + + enabled = is_lpc_intc_enabled(lpc_intc->flags); + pr_info(PREFIX "version [%u] on node [%u] %s\n", + lpc_intc->version, lpc_intc->node, + enabled ? "found" : "disabled"); + if (!enabled) + return 0; + + if (lpc_intc->gsi_base != SW_LPC_INTC_GSI_BASE) { + pr_err(PREFIX "invalid GSI\n"); + return -EINVAL; + } + + handle = irq_domain_alloc_named_id_fwnode("LPC-INTC", lpc_intc->node); + if (!handle) { + pr_err(PREFIX "failed to alloc fwnode\n"); + return -ENOMEM; + } + + fwspec.fwnode = parent->fwnode; + fwspec.param[0] = lpc_intc->cascade_vector; + fwspec.param_count = 1; + + parent_irq = irq_create_fwspec_mapping(&fwspec); + if (parent_irq <= 0) { + pr_err(PREFIX "failed to map parent irq\n"); + ret = -EINVAL; + goto out_acpi_free_fwnode; + } + + base_addr = ioremap(lpc_intc->address, lpc_intc->size); + if (!base_addr) { + pr_err(PREFIX "failed to map base address\n"); + ret = -ENXIO; + goto out_acpi_free_fwnode; + } + + ret = lpc_intc_init(handle, lpc_intc->gsi_count, + parent_irq, base_addr); + if (ret) + goto out_acpi_unmap; + + ret = sw64_add_gsi_domain_map(lpc_intc->gsi_base, + lpc_intc->gsi_count, handle); + if (ret) { + pr_info(PREFIX "failed to add GSI map\n"); + goto out_acpi_free_lpc_domain; + } + + pr_info(PREFIX "version [%u] on node [%u] initialized\n", + lpc_intc->version, lpc_intc->node); + + return 0; + +out_acpi_free_lpc_domain: + irq_domain_remove(lpc_irq_domain); +out_acpi_unmap: + iounmap(base_addr); +out_acpi_free_fwnode: + irq_domain_free_fwnode(handle); + return ret; +} +#endif diff --git a/drivers/irqchip/irq-sunway-msi-v2.c b/drivers/irqchip/irq-sunway-msi-v2.c index 8b8424d508a4..0e6e46e5a02d 100644 --- a/drivers/irqchip/irq-sunway-msi-v2.c +++ b/drivers/irqchip/irq-sunway-msi-v2.c @@ -4,10 +4,13 @@ #include #include #include +#include #include #include +#define PREFIX "MSIC: " + static struct irq_domain *msi_default_domain; static DEFINE_RAW_SPINLOCK(vector_lock); DEFINE_PER_CPU(vector_irq_t, vector_irq) = { @@ -513,3 +516,33 @@ void handle_pci_msi_interrupt(unsigned long type, unsigned long vector, unsigned } MODULE_LICENSE("GPL v2"); + +#ifdef CONFIG_ACPI +#define SW_MSIC_FLAG_ENABLED ACPI_MADT_ENABLED /* 0x1 */ +#define SW_MSIC_FLAG_VIRTUAL 0x2 /* virtual MSIC */ + +#define is_msic_enabled(flags) ((flags) & SW_MSIC_FLAG_ENABLED) +#define is_msic_virtual(flags) ((flags) & SW_MSIC_FLAG_VIRTUAL) + +int __init msic_acpi_init(struct irq_domain *parent, + struct acpi_madt_sw_msic *msic) +{ + bool enabled, virtual; + + enabled = is_msic_enabled(msic->flags); + virtual = is_msic_virtual(msic->flags); + + pr_info(PREFIX "version [%u] on node [%u] Root Complex [%u] (%s) %s\n", + msic->version, msic->node, msic->rc, + virtual ? "virtual" : "physical", + enabled ? "found" : "disabled"); + + if (!enabled) + return 0; + + if (!msi_default_domain) + arch_init_msi_domain(parent); + + return 0; +} +#endif diff --git a/drivers/irqchip/irq-sunway-msi.c b/drivers/irqchip/irq-sunway-msi.c index d6d0c6a833d6..f5d0a19e9583 100644 --- a/drivers/irqchip/irq-sunway-msi.c +++ b/drivers/irqchip/irq-sunway-msi.c @@ -3,10 +3,13 @@ #include #include #include +#include #include #include +#define PREFIX "MSIC: " + static struct irq_domain *msi_default_domain; static DEFINE_RAW_SPINLOCK(vector_lock); DEFINE_PER_CPU(vector_irq_t, vector_irq) = { @@ -464,3 +467,33 @@ void handle_pci_msi_interrupt(unsigned long type, unsigned long vector, unsigned } MODULE_LICENSE("GPL v2"); + +#ifdef CONFIG_ACPI +#define SW_MSIC_FLAG_ENABLED ACPI_MADT_ENABLED /* 0x1 */ +#define SW_MSIC_FLAG_VIRTUAL 0x2 /* virtual MSIC */ + +#define is_msic_enabled(flags) ((flags) & SW_MSIC_FLAG_ENABLED) +#define is_msic_virtual(flags) ((flags) & SW_MSIC_FLAG_VIRTUAL) + +int __init msic_acpi_init(struct irq_domain *parent, + struct acpi_madt_sw_msic *msic) +{ + bool enabled, virtual; + + enabled = is_msic_enabled(msic->flags); + virtual = is_msic_virtual(msic->flags); + + pr_info(PREFIX "version [%u] on node [%u] Root Complex [%u] (%s) %s\n", + msic->version, msic->node, msic->rc, + virtual ? "virtual" : "physical", + enabled ? "found" : "disabled"); + + if (!enabled) + return 0; + + if (!msi_default_domain) + arch_init_msi_domain(parent); + + return 0; +} +#endif diff --git a/drivers/irqchip/irq-sunway-pintc.c b/drivers/irqchip/irq-sunway-pintc.c index 41c52f9fb09b..55ea830e26de 100644 --- a/drivers/irqchip/irq-sunway-pintc.c +++ b/drivers/irqchip/irq-sunway-pintc.c @@ -7,12 +7,48 @@ #include #include +/** + * Currently, Peripheral interrupt control logic of Sunway is mainly + * distributed on the device side, which are hardware entities + * corresponding to SW sub PINTC structures. + * + * At the same time, there are some interrupt configuration registers + * concentrated in INTPU, which is hardware entity corresponding to + * SW PINTC, excluding SW sub PINTC structures. + * + * The topology of SW PINTC(physical) is as follows: + * + * +----------------------------------------------------------------+ + * | | + * | +--------------------------------+ | + * | | SW CINTC | | + * | +--------------------------------+ | + * | | | | | | + * | _________| __| |__ |______ | + * | | | | | | + * | +-------|---------------|--------------|------------|------+ | + * | | | | | | | | + * | | +----------+ +--------+ +--------+ +--------+ | | + * | | | MCU | | MT | | ADR | | ...... | | | + * | | +----------+ +--------+ +--------+ +--------+ | | + * | | | SW PINTC | | + * | +-------|--------------------------------------------------+ | + * | | | + * | +--------------+ | + * | | SW LPC INTC | | + * | +--------------+ | + * | | + * +----------------------------------------------------------------+ + */ + #define PREFIX "PINTC: " #define OFFSET_MCU_DVC_INT_EN 0x3080UL #define OFFSET_DEV_INT_CONFIG 0x480UL +#define SW_PINTC_MCU_GSI_BASE 64 + struct pintc_chip_data { bool vt; /* virtual pintc */ u32 node; /* node ID */ @@ -20,6 +56,7 @@ struct pintc_chip_data { void __iomem *pintc_base; /* INTPU base address */ void __iomem *mcu_base; /* MCU/SPBU base address */ struct irq_chip *mcu_chip; + u32 mcu_irq_num; }; static DEFINE_RAW_SPINLOCK(pintc_lock); @@ -177,6 +214,33 @@ static struct irq_chip pintc_mcu_vt_chip = { .name = "VMCU-INT", }; +static int pintc_mcu_translate(struct irq_domain *domain, + struct irq_fwspec *fwspec, + unsigned long *hwirq, + unsigned int *type) +{ + if (WARN_ON(fwspec->param_count < 1)) + return -EINVAL; + + /* Device tree */ + if (is_of_node(fwspec->fwnode)) { + *hwirq = fwspec->param[0]; + *type = IRQ_TYPE_NONE; + return 0; + } + + /* ACPI */ + if (is_fwnode_irqchip(fwspec->fwnode)) { + if (WARN_ON(fwspec->param[0] < SW_PINTC_MCU_GSI_BASE)) + return -EINVAL; + *hwirq = fwspec->param[0] - SW_PINTC_MCU_GSI_BASE; + *type = IRQ_TYPE_NONE; + return 0; + } + + return -EINVAL; +} + static void pintc_mcu_free_irqs(struct irq_domain *irq_domain, unsigned int virq, unsigned int nr_irqs) { @@ -207,8 +271,13 @@ static int pintc_mcu_alloc_irqs(struct irq_domain *domain, void *arg) { struct irq_fwspec *fwspec = arg; - irq_hw_number_t hwirq = fwspec->param[0]; - int i; + irq_hw_number_t hwirq; + unsigned int type; + int i, ret; + + ret = pintc_mcu_translate(domain, fwspec, &hwirq, &type); + if (ret) + return ret; for (i = 0; i < nr_irqs; i++) pintc_mcu_map_irq(domain, virq + i, hwirq + i); @@ -218,7 +287,7 @@ static int pintc_mcu_alloc_irqs(struct irq_domain *domain, static const struct irq_domain_ops pintc_mcu_domain_ops = { .map = pintc_mcu_map_irq, - .xlate = irq_domain_xlate_onecell, + .translate = pintc_mcu_translate, .alloc = pintc_mcu_alloc_irqs, .free = pintc_mcu_free_irqs, }; @@ -226,6 +295,44 @@ static const struct irq_domain_ops pintc_mcu_domain_ops = { struct irq_domain *mcu_irq_domain; EXPORT_SYMBOL(mcu_irq_domain); +static int __init pintc_init_mcu(struct pintc_chip_data *chip_data, + struct fwnode_handle *handle) +{ + unsigned int mcu_irq_num = chip_data->mcu_irq_num; + + if (chip_data->vt) { + chip_data->mcu_chip = &pintc_mcu_vt_chip; + + /** + * The current kernel does not support the API + * "irq_domain_create_legacy", we have to call + * "__irq_domain_add" directly. + */ + mcu_irq_domain = __irq_domain_add(handle, mcu_irq_num, + mcu_irq_num, 0, &pintc_mcu_domain_ops, + chip_data); + if (mcu_irq_domain) + irq_domain_associate_many(mcu_irq_domain, + 0, 0, mcu_irq_num); + } else { + chip_data->mcu_chip = &pintc_mcu_chip; + mcu_irq_domain = irq_domain_create_linear(handle, mcu_irq_num, + &pintc_mcu_domain_ops, chip_data); + /* Mask all interrupts for now */ + writeq(0x0, chip_data->mcu_base + OFFSET_MCU_DVC_INT_EN); + } + + if (!mcu_irq_domain) { + pr_err(PREFIX "failed to create MCU irq domain\n"); + return -ENOMEM; + } + + pr_info(PREFIX "MCU sub controller [%u:%u] initialized\n", + chip_data->version, chip_data->node); + + return 0; +} + #ifdef CONFIG_OF static int __init pintc_of_init_common(struct device_node *pintc, @@ -287,29 +394,11 @@ pintc_of_init_common(struct device_node *pintc, chip_data->version = version; chip_data->pintc_base = pintc_base; chip_data->mcu_base = mcu_base; + chip_data->mcu_irq_num = nr_irqs; - if (vt) { - chip_data->mcu_chip = &pintc_mcu_vt_chip; - mcu_irq_domain = irq_domain_add_legacy(pintc, nr_irqs, 0, 0, - &pintc_mcu_domain_ops, chip_data); - } else { - chip_data->mcu_chip = &pintc_mcu_chip; - mcu_irq_domain = irq_domain_add_linear(pintc, nr_irqs, - &pintc_mcu_domain_ops, chip_data); - /* mask all interrupts for now */ - writeq(0x0, mcu_base + OFFSET_MCU_DVC_INT_EN); - } - - if (!mcu_irq_domain) { - pr_err(PREFIX "failed to create irq domain\n"); - ret = -ENOMEM; + ret = pintc_init_mcu(chip_data, of_node_to_fwnode(pintc)); + if (ret) goto out_free_mem; - } - - pr_info(PREFIX "version [%u] on node [%u] initialized\n", - version, node); - - irq_set_default_host(mcu_irq_domain); return 0; @@ -338,3 +427,174 @@ pintc_vt_of_init(struct device_node *pintc, struct device_node *parent) IRQCHIP_DECLARE(sw64_pintc_vt, "sw64,pintc_vt", pintc_vt_of_init); #endif + +#ifdef CONFIG_ACPI +#define SW_PINTC_FLAG_ENABLED ACPI_MADT_ENABLED /* 0x1 */ +#define SW_PINTC_FLAG_VIRTUAL 0x2 /* virtual PINTC */ + +#define is_pintc_enabled(flags) ((flags) & SW_PINTC_FLAG_ENABLED) +#define is_pintc_virtual(flags) ((flags) & SW_PINTC_FLAG_VIRTUAL) + +/* Physical sub interrupt controllers */ +enum sw_pintc_sub_type { + SW_PINTC_SUB_TYPE_MCU = 0x00, + SW_PINTC_SUB_TYPE_MT = 0x01, + SW_PINTC_SUB_TYPE_FAULT = 0x02, + SW_PINTC_SUB_TYPE_NMI = 0x03, + SW_PINTC_SUB_TYPE_S3 = 0x04, + SW_PINTC_SUB_TYPE_ADR = 0x05, + SW_PINTC_SUB_TYPE_COUNT +}; + +static int __init lpc_intc_parse_madt(union acpi_subtable_headers *header, + const unsigned long end) +{ + struct acpi_madt_sw_lpc_intc *lpc_intc; + + lpc_intc = (struct acpi_madt_sw_lpc_intc *)header; + + /* Not yet supported */ + if (lpc_intc->node > 0) + return 0; + + if ((lpc_intc->version == ACPI_MADT_SW_LPC_INTC_VERSION_NONE) || + (lpc_intc->version >= ACPI_MADT_SW_LPC_INTC_VERSION_RESERVED)) { + pr_err(PREFIX "invalid LPC-INTC version\n"); + return -EINVAL; + } + + return lpc_intc_acpi_init(mcu_irq_domain, lpc_intc); +} + +static bool __init +pintc_sub_type_check(const struct acpi_madt_sw_pintc *pintc) +{ + int i, count = 0; + + for (i = 0; i < pintc->sub_num; ++i) { + if (pintc->sub[i].type >= SW_PINTC_SUB_TYPE_COUNT) + count++; + } + + return count; +} + +static int __init pintc_acpi_init_mcu(struct pintc_chip_data *chip_data, + struct acpi_madt_sw_sub_pintc *mcu) +{ + struct fwnode_handle *handle; + int ret; + + if (!mcu->status) { + pr_info(PREFIX "MCU sub controller [%u:%u] disabled\n", + chip_data->version, chip_data->node); + return 0; + } + + if (mcu->gsi_base != SW_PINTC_MCU_GSI_BASE) { + pr_err(PREFIX "invalid MCU GSI\n"); + return -EINVAL; + } + + handle = irq_domain_alloc_named_id_fwnode("PINTC-MCU", chip_data->node); + if (!handle) { + pr_err(PREFIX "failed to alloc fwnode\n"); + return -ENOMEM; + } + + chip_data->mcu_irq_num = mcu->gsi_count; + + chip_data->mcu_base = ioremap(mcu->address, mcu->size); + if (!chip_data->mcu_base) { + pr_err(PREFIX "failed to map mcu base address\n"); + ret = -ENXIO; + goto out_acpi_free_fwnode; + } + + ret = pintc_init_mcu(chip_data, handle); + if (ret) + goto out_acpi_unmap_mcu; + + ret = sw64_add_gsi_domain_map(mcu->gsi_base, mcu->gsi_count, handle); + if (ret) { + pr_info(PREFIX "failed to add GSI map\n"); + goto out_acpi_free_mcu_domain; + } + + return 0; + +out_acpi_free_mcu_domain: + irq_domain_remove(mcu_irq_domain); +out_acpi_unmap_mcu: + iounmap(chip_data->mcu_base); +out_acpi_free_fwnode: + irq_domain_free_fwnode(handle); + return ret; +} + +int __init pintc_acpi_init(struct irq_domain *parent, + struct acpi_madt_sw_pintc *pintc) +{ + struct pintc_chip_data *chip_data; + int ret, i; + bool enabled, virtual; + + enabled = is_pintc_enabled(pintc->flags); + virtual = is_pintc_virtual(pintc->flags); + + pr_info(PREFIX "version [%u] on node [%u] (%s) %s\n", + pintc->version, pintc->node, + virtual ? "virtual" : "physical", + enabled ? "found" : "disabled"); + + if (!enabled) + return 0; + + if (pintc_sub_type_check(pintc)) { + pr_err(PREFIX "invalid sub type\n"); + return -EINVAL; + } + + chip_data = kzalloc_node(sizeof(*chip_data), GFP_KERNEL, + pintc->node); + if (!chip_data) + return -ENOMEM; + + /** + * The topology of interrupt controllers in Qemu is + * different from physical environment. We need to + * distinguish between them. + */ + chip_data->vt = virtual; + + chip_data->node = pintc->node; + chip_data->version = pintc->version; + + chip_data->pintc_base = ioremap(pintc->address, pintc->size); + if (!chip_data->pintc_base) { + pr_err(PREFIX "failed to map pintc base address\n"); + ret = -ENXIO; + goto out_acpi_free_chip_data; + } + + for (i = 0; i < pintc->sub_num; ++i) { + switch (pintc->sub[i].type) { + case SW_PINTC_SUB_TYPE_MCU: + pintc_acpi_init_mcu(chip_data, &pintc->sub[i]); + break; + default: + break; + } + } + + /* Init SW LPC INTC */ + acpi_table_parse_madt(ACPI_MADT_TYPE_SW_LPC_INTC, + lpc_intc_parse_madt, 0); + + return 0; + +out_acpi_free_chip_data: + kfree(chip_data); + return ret; +} +#endif diff --git a/include/acpi/actbl2.h b/include/acpi/actbl2.h index e4ca9817938a..839f72459451 100644 --- a/include/acpi/actbl2.h +++ b/include/acpi/actbl2.h @@ -938,7 +938,8 @@ enum acpi_madt_sw_cintc_version { struct acpi_madt_sw_sub_pintc { u8 type; - u8 reserved[3]; + u8 status; + u16 reserved; u32 hardware_id; u64 address; u32 size; @@ -982,7 +983,8 @@ struct acpi_madt_sw_msic { u32 node; u32 rc; u32 num; - u32 reserved1[4]; + u64 message_address; + u32 reserved1[2]; }; /* Values for version field above */ diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 3f97f129faa9..99e6b2020fed 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -106,6 +106,9 @@ enum acpi_irq_model_id { ACPI_IRQ_MODEL_PLATFORM, ACPI_IRQ_MODEL_GIC, ACPI_IRQ_MODEL_LPIC, +#ifdef CONFIG_SW64 + ACPI_IRQ_MODEL_SWPIC, +#endif ACPI_IRQ_MODEL_COUNT }; -- Gitee From 02c318d4a4e86b9e03b85264a9e2810ffc45e4ca Mon Sep 17 00:00:00 2001 From: Jing Li Date: Wed, 20 Dec 2023 19:12:17 +0800 Subject: [PATCH 45/49] anolis: sw64: acpi: enable generic GSI ANBZ: #4688 Use common implementation of GSI provided by kernel instead of the architecture specific implementation. In addition, this commit also remove some useless code. Signed-off-by: Jing Li Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/Kconfig | 1 + arch/sw_64/kernel/acpi.c | 68 +--------------------------------------- 2 files changed, 2 insertions(+), 67 deletions(-) diff --git a/arch/sw_64/Kconfig b/arch/sw_64/Kconfig index 4b9e8148e4c4..28a3788d8822 100644 --- a/arch/sw_64/Kconfig +++ b/arch/sw_64/Kconfig @@ -3,6 +3,7 @@ config SW64 bool default y select ACPI + select ACPI_GENERIC_GSI if ACPI select ACPI_MCFG if (ACPI && PCI) select ACPI_REDUCED_HARDWARE_ONLY select ARCH_HAS_ACPI_TABLE_UPGRADE if ACPI diff --git a/arch/sw_64/kernel/acpi.c b/arch/sw_64/kernel/acpi.c index 9cb37be7ee34..333b5ef7ea4d 100644 --- a/arch/sw_64/kernel/acpi.c +++ b/arch/sw_64/kernel/acpi.c @@ -35,11 +35,7 @@ u64 acpi_saved_sp_s3; #define MAX_LOCAL_APIC 256 #define PREFIX "ACPI: " -/* - * The default interrupt routing model is PIC (8259). This gets - * overridden if IOAPICs are enumerated (below). - */ -enum acpi_irq_model_id acpi_irq_model = ACPI_IRQ_MODEL_IOSAPIC; + void __iomem *__init __acpi_map_table(unsigned long phys, unsigned long size) { if (!phys || !size) @@ -54,17 +50,6 @@ void __init __acpi_unmap_table(void __iomem *map, unsigned long size) early_iounmap(map, size); } -/* - * Following __acpi_xx functions should be implemented for sepecific cpu. - */ -int acpi_gsi_to_irq(u32 gsi, unsigned int *irqp) -{ - if (irqp != NULL) - *irqp = acpi_register_gsi(NULL, gsi, -1, -1); - - return 0; -} -EXPORT_SYMBOL_GPL(acpi_gsi_to_irq); int acpi_isa_irq_to_gsi(unsigned int isa_irq, u32 *gsi) { @@ -76,57 +61,6 @@ int acpi_isa_irq_to_gsi(unsigned int isa_irq, u32 *gsi) int (*acpi_suspend_lowlevel)(void); -/* - * success: return IRQ number (>=0) - * failure: return < 0 - */ -static struct irq_domain *irq_default_domain; -int acpi_register_gsi(struct device *dev, u32 gsi, int trigger, int polarity) -{ - u32 irq; - - irq = irq_find_mapping(irq_default_domain, gsi); - - return irq; -} -EXPORT_SYMBOL_GPL(acpi_register_gsi); - -void acpi_unregister_gsi(u32 gsi) -{ - -} -EXPORT_SYMBOL_GPL(acpi_unregister_gsi); -/* - * ACPI based hotplug support for CPU - */ -#ifdef CONFIG_ACPI_HOTPLUG_CPU -#include - -/* wrapper to silence section mismatch warning */ -int __ref acpi_map_lsapic(acpi_handle handle, int physid, int *pcpu) -{ - return 0; -} -EXPORT_SYMBOL(acpi_map_lsapic); - -int acpi_unmap_lsapic(int cpu) -{ - return 0; -} -EXPORT_SYMBOL(acpi_unmap_lsapic); -#endif /* CONFIG_ACPI_HOTPLUG_CPU */ - -u8 acpi_checksum(u8 *table, u32 length) -{ - u8 ret = 0; - - while (length--) { - ret += *table; - table++; - } - return -ret; -} - static int __init parse_acpi(char *arg) { if (!arg) -- Gitee From 9dad44da6c45b4185b89ca1604389a36f97fcaee Mon Sep 17 00:00:00 2001 From: Jing Li Date: Wed, 21 Feb 2024 09:49:32 +0800 Subject: [PATCH 46/49] anolis: sw64: irq: remove unnecessary initialization ANBZ: #4688 It is unnecessary to set irqchip and handle for all irqs during early initialization. Signed-off-by: Jing Li Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/kernel/Makefile | 2 +- arch/sw_64/kernel/irq.c | 41 ++++++++++++++++++ arch/sw_64/kernel/irq_sw64.c | 84 ------------------------------------ 3 files changed, 42 insertions(+), 85 deletions(-) delete mode 100644 arch/sw_64/kernel/irq_sw64.c diff --git a/arch/sw_64/kernel/Makefile b/arch/sw_64/kernel/Makefile index d9cd8aab4631..87aaf6c26521 100644 --- a/arch/sw_64/kernel/Makefile +++ b/arch/sw_64/kernel/Makefile @@ -14,7 +14,7 @@ CFLAGS_REMOVE_printk.o = -pg endif obj-y := entry.o fpu.o traps.o process.o sys_sw64.o irq.o \ - irq_sw64.o signal.o setup.o ptrace.o time.o \ + signal.o setup.o ptrace.o time.o \ systbls.o dup_print.o chip_setup.o \ insn.o early_init.o topology.o cacheinfo.o \ vdso.o vdso/ hmcall.o stacktrace.o idle.o reset.o diff --git a/arch/sw_64/kernel/irq.c b/arch/sw_64/kernel/irq.c index 126fe2f70495..58ee5131e2a9 100644 --- a/arch/sw_64/kernel/irq.c +++ b/arch/sw_64/kernel/irq.c @@ -14,8 +14,11 @@ #include #include #include +#include #include +#include + volatile unsigned long irq_err_count; DEFINE_PER_CPU(unsigned long, irq_pmi_count); DEFINE_PER_CPU_SHARED_ALIGNED(irq_cpustat_t, irq_stat); @@ -106,3 +109,41 @@ void fixup_irqs(void) irq_migrate_all_off_this_cpu(); } #endif + +void __init init_IRQ(void) +{ + /* + * Just in case the platform init_irq() causes interrupts/mchecks + * (as is the case with RAWHIDE, at least). + */ + if (is_in_host()) { + sw64_write_csr(0xffffffffffffffffUL, CSR_PCIE_MSI0_INTEN); + sw64_write_csr(0xffffffffffffffffUL, CSR_PCIE_MSI1_INTEN); + sw64_write_csr(0xffffffffffffffffUL, CSR_PCIE_MSI2_INTEN); + sw64_write_csr(0xffffffffffffffffUL, CSR_PCIE_MSI3_INTEN); + } + + wrent(entInt, 0); + + sw64_init_irq(); + irqchip_init(); +} + +void __weak arch_init_msi_domain(struct irq_domain *parent) {} + +int __init arch_early_irq_init(void) +{ + arch_init_msi_domain(NULL); + + return 0; +} + +int __init arch_probe_nr_irqs(void) +{ + return NR_IRQS_LEGACY; +} + +struct irq_chip sw64_irq_chip = { + .name = "SW64_DUMMY" +}; +EXPORT_SYMBOL(sw64_irq_chip); diff --git a/arch/sw_64/kernel/irq_sw64.c b/arch/sw_64/kernel/irq_sw64.c deleted file mode 100644 index 03aef463ec05..000000000000 --- a/arch/sw_64/kernel/irq_sw64.c +++ /dev/null @@ -1,84 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * SW64 specific irq code. - */ - -#include -#include - -#include -#include - -void __init -init_IRQ(void) -{ - /* - * Just in case the platform init_irq() causes interrupts/mchecks - * (as is the case with RAWHIDE, at least). - */ - if (is_in_host()) { - sw64_write_csr(0xffffffffffffffffUL, CSR_PCIE_MSI0_INTEN); - sw64_write_csr(0xffffffffffffffffUL, CSR_PCIE_MSI1_INTEN); - sw64_write_csr(0xffffffffffffffffUL, CSR_PCIE_MSI2_INTEN); - sw64_write_csr(0xffffffffffffffffUL, CSR_PCIE_MSI3_INTEN); - } - - wrent(entInt, 0); - - sw64_init_irq(); - irqchip_init(); -} - -DEFINE_SPINLOCK(irq_lock); - -static void -__enable_irq(struct irq_data *d) -{ -} - -static void -__disable_irq(struct irq_data *d) -{ -} - -static unsigned int -__startup_irq(struct irq_data *d) -{ - __enable_irq(d); - return 0; -} - -static void -__mask_and_ack_irq(struct irq_data *d) -{ - spin_lock(&irq_lock); - __disable_irq(d); - spin_unlock(&irq_lock); -} - -struct irq_chip sw64_irq_chip = { - .name = "SW64_NODE", - .irq_startup = __startup_irq, - .irq_unmask = __enable_irq, - .irq_mask = __disable_irq, - .irq_mask_ack = __mask_and_ack_irq, -}; - -void __weak arch_init_msi_domain(struct irq_domain *parent) {} - -int __init arch_early_irq_init(void) -{ - int i; - - for (i = 0; i < NR_IRQS; ++i) { - irq_set_chip_and_handler(i, &sw64_irq_chip, handle_level_irq); - irq_set_status_flags(i, IRQ_LEVEL); - } - arch_init_msi_domain(NULL); - return 0; -} - -int __init arch_probe_nr_irqs(void) -{ - return NR_IRQS_LEGACY; -} -- Gitee From fae895de95f2dbb9ad951d0fba949253724f6e93 Mon Sep 17 00:00:00 2001 From: Jing Li Date: Thu, 11 Jan 2024 13:43:01 +0800 Subject: [PATCH 47/49] anolis: sw64: pci: remove duplicate pcie operations ANBZ: #4688 Use pcie operations implemented in pci-sunway.c and remove the duplicate one. Signed-off-by: Jing Li Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/include/asm/pci.h | 10 ++ arch/sw_64/pci/pci-legacy.c | 193 +++------------------------- drivers/pci/controller/pci-sunway.c | 17 ++- 3 files changed, 40 insertions(+), 180 deletions(-) diff --git a/arch/sw_64/include/asm/pci.h b/arch/sw_64/include/asm/pci.h index 78ffce917a27..8851c0779647 100644 --- a/arch/sw_64/include/asm/pci.h +++ b/arch/sw_64/include/asm/pci.h @@ -102,6 +102,16 @@ extern void sw64_pci_root_bridge_prepare(struct pci_host_bridge *bridge); extern void sw64_pci_root_bridge_scan_finish_up(struct pci_host_bridge *bridge); extern int sw64_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin); +extern void __iomem *sw64_pcie_map_bus(struct pci_bus *bus, + unsigned int devfn, int where); +extern int sw64_pcie_config_write(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 val); +extern int sw64_pcie_config_read(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 *val); + +extern void pci_mark_rc_linkup(unsigned long node, unsigned long index); +extern int pci_get_rc_linkup(unsigned long node, unsigned long index); + #ifdef CONFIG_PCI_DOMAINS static inline int pci_proc_domain(struct pci_bus *bus) { diff --git a/arch/sw_64/pci/pci-legacy.c b/arch/sw_64/pci/pci-legacy.c index df33890493f1..e0d515540e01 100644 --- a/arch/sw_64/pci/pci-legacy.c +++ b/arch/sw_64/pci/pci-legacy.c @@ -5,11 +5,10 @@ #include #include +#include #include #include -unsigned long rc_linkup; - /* * The PCI controller list. */ @@ -196,176 +195,10 @@ static void __init pcibios_reserve_legacy_regions(struct pci_bus *bus) return; } -/* PCIe RC operations */ -int sw6_pcie_read_rc_cfg(struct pci_bus *bus, unsigned int devfn, - int where, int size, u32 *val) -{ - u32 data; - struct pci_controller *hose = pci_bus_to_pci_controller(bus); - void __iomem *cfg_iobase = hose->rc_config_space_base; - - if (IS_ENABLED(CONFIG_PCI_DEBUG)) - pr_debug("rc read addr:%px bus %d, devfn %#x, where %#x size=%d\t", - cfg_iobase + ((where & ~3) << 5), bus->number, devfn, where, size); - - if ((uintptr_t)where & (size - 1)) { - *val = 0; - return PCIBIOS_BAD_REGISTER_NUMBER; - } - - if (unlikely(devfn > 0)) { - *val = ~0; - return PCIBIOS_DEVICE_NOT_FOUND; - } - - data = readl(cfg_iobase + ((where & ~3) << 5)); - - switch (size) { - case 1: - *val = (data >> (8 * (where & 0x3))) & 0xff; - break; - case 2: - *val = (data >> (8 * (where & 0x2))) & 0xffff; - break; - default: - *val = data; - break; - } - - if (IS_ENABLED(CONFIG_PCI_DEBUG)) - pr_debug("*val %#x\n ", *val); - - return PCIBIOS_SUCCESSFUL; -} - -int sw6_pcie_write_rc_cfg(struct pci_bus *bus, unsigned int devfn, - int where, int size, u32 val) -{ - u32 data; - u32 shift = 8 * (where & 3); - struct pci_controller *hose = pci_bus_to_pci_controller(bus); - void __iomem *cfg_iobase = (void *)hose->rc_config_space_base; - - if ((uintptr_t)where & (size - 1)) - return PCIBIOS_BAD_REGISTER_NUMBER; - - switch (size) { - case 1: - data = readl(cfg_iobase + ((where & ~3) << 5)); - data &= ~(0xff << shift); - data |= (val & 0xff) << shift; - break; - case 2: - data = readl(cfg_iobase + ((where & ~3) << 5)); - data &= ~(0xffff << shift); - data |= (val & 0xffff) << shift; - break; - default: - data = val; - break; - } - - if (IS_ENABLED(CONFIG_PCI_DEBUG)) - pr_debug("rc write addr:%px bus %d, devfn %#x, where %#x *val %#x size %d\n", - cfg_iobase + ((where & ~3) << 5), bus->number, devfn, where, val, size); - - writel(data, cfg_iobase + ((where & ~3) << 5)); - - return PCIBIOS_SUCCESSFUL; -} - -int sw6_pcie_config_read(struct pci_bus *bus, unsigned int devfn, - int where, int size, u32 *val) -{ - struct pci_controller *hose = pci_bus_to_pci_controller(bus); - int ret = PCIBIOS_DEVICE_NOT_FOUND; - - if (is_guest_or_emul()) - return pci_generic_config_read(bus, devfn, where, size, val); - - hose->self_busno = hose->busn_space->start; - - if (unlikely(bus->number == hose->self_busno)) { - ret = sw6_pcie_read_rc_cfg(bus, devfn, where, size, val); - } else { - if (test_bit(hose->node * 8 + hose->index, &rc_linkup)) { - ret = pci_generic_config_read(bus, devfn, where, size, val); - } else { - return ret; - } - } - return ret; -} - -int sw6_pcie_config_write(struct pci_bus *bus, unsigned int devfn, - int where, int size, u32 val) -{ - struct pci_controller *hose = pci_bus_to_pci_controller(bus); - - if (is_guest_or_emul()) - return pci_generic_config_write(bus, devfn, where, size, val); - - hose->self_busno = hose->busn_space->start; - - if (unlikely(bus->number == hose->self_busno)) - return sw6_pcie_write_rc_cfg(bus, devfn, where, size, val); - else - return pci_generic_config_write(bus, devfn, where, size, val); -} - -/* - *sw6_pcie_valid_device - Check if a valid device is present on bus - *@bus: PCI Bus structure - *@devfn: device/function - * - *Return: 'true' on success and 'false' if invalid device is found - */ -static bool sw6_pcie_valid_device(struct pci_bus *bus, unsigned int devfn) -{ - struct pci_controller *hose = pci_bus_to_pci_controller(bus); - - if (is_in_host()) { - /* Only one device down on each root complex */ - if (bus->number == hose->self_busno && devfn > 0) - return false; - } - - return true; -} - -/* - *sw6_pcie_map_bus - Get configuration base - *@bus: PCI Bus structure - *@devfn: Device/function - *@where: Offset from base - * - *Return: Base address of the configuration space needed to be - *accessed. - */ -static void __iomem *sw6_pcie_map_bus(struct pci_bus *bus, - unsigned int devfn, int where) -{ - struct pci_controller *hose = pci_bus_to_pci_controller(bus); - void __iomem *cfg_iobase; - unsigned long relbus; - - if (!sw6_pcie_valid_device(bus, devfn)) - return NULL; - - relbus = (bus->number << 24) | (devfn << 16) | where; - - cfg_iobase = hose->ep_config_space_base + relbus; - - if (IS_ENABLED(CONFIG_PCI_DEBUG)) - pr_debug("addr:%px bus %d, devfn %d, where %d\n", - cfg_iobase, bus->number, devfn, where); - return cfg_iobase; -} - struct pci_ops sw64_pci_ops = { - .map_bus = sw6_pcie_map_bus, - .read = sw6_pcie_config_read, - .write = sw6_pcie_config_write, + .map_bus = sw64_pcie_map_bus, + .read = sw64_pcie_config_read, + .write = sw64_pcie_config_write, }; int sw64_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) @@ -400,13 +233,25 @@ sw64_init_host(unsigned long node, unsigned long index) ret = sw64_chip_init->pci_init.check_pci_linkup(node, index); if (ret == 0) { /* Root Complex downstream port is link up */ - set_bit(node * 8 + index, &rc_linkup); //8-bit per node + pci_mark_rc_linkup(node, index); // 8-bit per node } } void __weak set_devint_wken(int node) {} void __weak set_adr_int(int node) {} +static bool __init is_any_rc_linkup_one_node(unsigned long node) +{ + int i; + + for (i = 0; i < 8; ++i) { + if (pci_get_rc_linkup(node, i)) + return true; + } + + return false; +} + void __init sw64_init_arch(void) { if (IS_ENABLED(CONFIG_PCI)) { @@ -438,11 +283,11 @@ void __init sw64_init_arch(void) if ((rc_enable >> i) & 0x1) sw64_init_host(node, i); } - if ((rc_linkup >> node * 8) & 0xff) { + if (is_any_rc_linkup_one_node(node)) { memset(msg, 0, 64); sprintf(msg, "Node %ld: RC [ ", node); for (i = 0; i < MAX_NR_RCS; i++) { - if ((rc_linkup >> (i + node * 8)) & 1) { + if (pci_get_rc_linkup(node, i)) { memset(id, 0, 8); sprintf(id, "%d ", i); strcat(msg, id); diff --git a/drivers/pci/controller/pci-sunway.c b/drivers/pci/controller/pci-sunway.c index ece31736b051..11df69dae968 100644 --- a/drivers/pci/controller/pci-sunway.c +++ b/drivers/pci/controller/pci-sunway.c @@ -349,15 +349,17 @@ void __init setup_chip_pci_ops(void) static unsigned long rc_linkup; static struct pci_controller *head, **tail = &head; -static void pci_mark_rc_linkup(unsigned long node, unsigned long index) +void pci_mark_rc_linkup(unsigned long node, unsigned long index) { set_bit(node * 8 + index, &rc_linkup); } +EXPORT_SYMBOL(pci_mark_rc_linkup); -static int pci_get_rc_linkup(unsigned long node, unsigned long index) +int pci_get_rc_linkup(unsigned long node, unsigned long index) { return test_bit(node * 8 + index, &rc_linkup); } +EXPORT_SYMBOL(pci_get_rc_linkup); /** * Link the specified pci controller to list @@ -456,7 +458,7 @@ static int sw64_pcie_read_rc_cfg(struct pci_bus *bus, unsigned int devfn, /** * PCIe Root Complex write config space operations */ -int sw64_pcie_write_rc_cfg(struct pci_bus *bus, unsigned int devfn, +static int sw64_pcie_write_rc_cfg(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val) { u32 data; @@ -528,7 +530,7 @@ static bool sw64_pcie_valid_device(struct pci_bus *bus, unsigned int devfn) * * @return: Whether read operation success */ -static int sw64_pcie_config_read(struct pci_bus *bus, unsigned int devfn, +int sw64_pcie_config_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *val) { struct pci_controller *hose = pci_bus_to_pci_controller(bus); @@ -551,6 +553,7 @@ static int sw64_pcie_config_read(struct pci_bus *bus, unsigned int devfn, } return ret; } +EXPORT_SYMBOL(sw64_pcie_config_read); /** * sw64_pcie_config_write - write val to config space of PCI @@ -564,7 +567,7 @@ static int sw64_pcie_config_read(struct pci_bus *bus, unsigned int devfn, * * @return: Whether write operation success */ -static int sw64_pcie_config_write(struct pci_bus *bus, unsigned int devfn, +int sw64_pcie_config_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val) { struct pci_controller *hose = pci_bus_to_pci_controller(bus); @@ -579,6 +582,7 @@ static int sw64_pcie_config_write(struct pci_bus *bus, unsigned int devfn, else return pci_generic_config_write(bus, devfn, where, size, val); } +EXPORT_SYMBOL(sw64_pcie_config_write); /** * sw64_pcie_map_bus - get configuration base address @@ -589,7 +593,7 @@ static int sw64_pcie_config_write(struct pci_bus *bus, unsigned int devfn, * @return: base address of the configuration space needed to be * accessed. */ -static void __iomem *sw64_pcie_map_bus(struct pci_bus *bus, +void __iomem *sw64_pcie_map_bus(struct pci_bus *bus, unsigned int devfn, int where) { struct pci_controller *hose = pci_bus_to_pci_controller(bus); @@ -618,6 +622,7 @@ static void __iomem *sw64_pcie_map_bus(struct pci_bus *bus, cfg_iobase, bus->number, devfn, where); return cfg_iobase; } +EXPORT_SYMBOL(sw64_pcie_map_bus); int sw64_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) { -- Gitee From d0c785ab7a57c993f3999ecc3815cb451afd68b6 Mon Sep 17 00:00:00 2001 From: Jing Li Date: Mon, 26 Feb 2024 08:31:19 +0800 Subject: [PATCH 48/49] anolis: sw64: acpi: fix missed upper bits of rcid for junzhang ANBZ: #4688 When initializing CPU affinity, only lower 8 bits of rcid are recorded. Because 8 bits are sufficient for xuelang's rcid. However, the rcid for junzhang needs more bits. Signed-off-by: Jing Li Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/kernel/acpi.c | 36 +++++++++++++++++------------------- include/linux/acpi.h | 3 +-- 2 files changed, 18 insertions(+), 21 deletions(-) diff --git a/arch/sw_64/kernel/acpi.c b/arch/sw_64/kernel/acpi.c index 333b5ef7ea4d..5982c44840e3 100644 --- a/arch/sw_64/kernel/acpi.c +++ b/arch/sw_64/kernel/acpi.c @@ -110,26 +110,24 @@ static int rcid_to_cpu(int physical_id) /* Callback for Proximity Domain -> CPUID mapping */ void __init -acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *pa) +acpi_numa_x2apic_affinity_init(struct acpi_srat_x2apic_cpu_affinity *pa) { int pxm, node; - int cpu; // logical core id + int cpu; // logical core id + int rcid; // physical core id if (srat_disabled()) return; - if (pa->header.length != sizeof(struct acpi_srat_cpu_affinity)) { + + if (pa->header.length != sizeof(struct acpi_srat_x2apic_cpu_affinity)) { bad_srat(); return; } + if ((pa->flags & ACPI_SRAT_CPU_ENABLED) == 0) return; - pxm = pa->proximity_domain_lo; - if (acpi_srat_revision >= 2) { - pxm |= (pa->proximity_domain_hi[0] << 8); - pxm |= (pa->proximity_domain_hi[1] << 16); - pxm |= (pa->proximity_domain_hi[2] << 24); - } + pxm = pa->proximity_domain; node = acpi_map_pxm_to_node(pxm); if (node < 0) { pr_err("SRAT: Too many proximity domains %x\n", pxm); @@ -137,25 +135,25 @@ acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *pa) return; } - if (pa->apic_id >= CONFIG_NR_CPUS) { - pr_err("SRAT: PXM %u -> CPU 0x%02x -> Node %u skipped apicid that is too big\n", - pxm, pa->apic_id, node); - return; - } + /** + * In fact, SW64 does not support local X2_APIC and just + * uses this structure to pass CPU affinity information. + */ + rcid = pa->apic_id; /* Record the mapping from logical core id to node id */ - cpu = rcid_to_cpu(pa->apic_id); + cpu = rcid_to_cpu(rcid); if (cpu < 0) { - pr_err("SRAT: Can not find the logical id for physical Core 0x%02x\n", - pa->apic_id); + pr_err("SRAT: Can not find the logical id for physical Core 0x%04x\n", + rcid); return; } early_map_cpu_to_node(cpu, node); node_set(node, numa_nodes_parsed); - pr_info("SRAT: PXM %u -> CPU 0x%02x -> Node %u\n", - pxm, pa->apic_id, node); + pr_debug("SRAT: PXM %u -> CPU 0x%04x -> Node %u\n", + pxm, rcid, node); } #ifdef CONFIG_MEMORY_HOTPLUG diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 99e6b2020fed..a90cbb8bb6e1 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -253,8 +253,7 @@ void acpi_table_print_madt_entry (struct acpi_subtable_header *madt); /* the following numa functions are architecture-dependent */ void acpi_numa_slit_init (struct acpi_table_slit *slit); -#if defined(CONFIG_X86) || defined(CONFIG_IA64) || \ - defined(CONFIG_LOONGARCH) || defined(CONFIG_SW64) +#if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(CONFIG_LOONGARCH) void acpi_numa_processor_affinity_init (struct acpi_srat_cpu_affinity *pa); #else static inline void -- Gitee From 222f96c37987a5b8d98db8e22f0a13863cedfa86 Mon Sep 17 00:00:00 2001 From: Mao Minkai Date: Thu, 7 Mar 2024 08:46:30 +0800 Subject: [PATCH 49/49] anolis: sw64: config: update junzhang_defconfig ANBZ: #4688 Update junzhang_defconfig to use IOMMU_V2 instead of IOMMU. Signed-off-by: Mao Minkai Reviewed-by: He Sheng Signed-off-by: Gu Zitao --- arch/sw_64/configs/junzhang_defconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/sw_64/configs/junzhang_defconfig b/arch/sw_64/configs/junzhang_defconfig index 41fb26c112d4..cb2f58172e85 100644 --- a/arch/sw_64/configs/junzhang_defconfig +++ b/arch/sw_64/configs/junzhang_defconfig @@ -584,7 +584,7 @@ CONFIG_VIRTIO_MMIO=y CONFIG_STAGING=y CONFIG_FB_SM750=y CONFIG_IOMMU_DEFAULT_PASSTHROUGH=y -CONFIG_SUNWAY_IOMMU=y +CONFIG_SUNWAY_IOMMU_V2=y CONFIG_EXT4_FS=y CONFIG_EXT4_FS_POSIX_ACL=y CONFIG_EXT4_FS_SECURITY=y -- Gitee