From c1b3475def4bca962cc8904cc0cdac22e7b6b6b3 Mon Sep 17 00:00:00 2001 From: Rob Gardner Date: Fri, 7 Aug 2015 14:47:35 -0600 Subject: sparc64: Fix incorrect ASI_ST_BLKINIT_MRU_S value ASI_ST_BLKINIT_MRU_S is incorrectly defined as 0xf2 when it should be 0xf3 according to section 10.3.1 of the Sparc Architecture manual. Signed-off-by: Rob Gardner Signed-off-by: David S. Miller diff --git a/arch/sparc/include/uapi/asm/asi.h b/arch/sparc/include/uapi/asm/asi.h index aace6f3..7ad7203d 100644 --- a/arch/sparc/include/uapi/asm/asi.h +++ b/arch/sparc/include/uapi/asm/asi.h @@ -279,7 +279,7 @@ * Most-Recently-Used, primary, * implicit */ -#define ASI_ST_BLKINIT_MRU_S 0xf2 /* (NG4) init-store, twin load, +#define ASI_ST_BLKINIT_MRU_S 0xf3 /* (NG4) init-store, twin load, * Most-Recently-Used, secondary, * implicit */ -- cgit v0.10.2 From 73958c651fbf70d8d8bf2a60b871af5f7a2e3199 Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Fri, 7 Aug 2015 20:34:12 +0200 Subject: sparc64: use ENTRY/ENDPROC in VISsave From 7d8a508d74e6cacf0f2438286a959c3195a35a37 Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Fri, 7 Aug 2015 20:26:12 +0200 Subject: [PATCH] sparc64: use ENTRY/ENDPROC in VISsave Commit 44922150d87cef616fd183220d43d8fde4d41390 ("sparc64: Fix userspace FPU register corruptions") left a stale globl symbol which was not used. Fix this and introduce use of ENTRY/ENDPROC Signed-off-by: Sam Ravnborg Signed-off-by: David S. Miller diff --git a/arch/sparc/lib/VISsave.S b/arch/sparc/lib/VISsave.S index a063d84..62c2647b 100644 --- a/arch/sparc/lib/VISsave.S +++ b/arch/sparc/lib/VISsave.S @@ -6,24 +6,23 @@ * Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz) */ +#include + #include #include #include #include #include - .text - .globl VISenter, VISenterhalf - /* On entry: %o5=current FPRS value, %g7 is callers address */ /* May clobber %o5, %g1, %g2, %g3, %g7, %icc, %xcc */ /* Nothing special need be done here to handle pre-emption, this * FPU save/restore mechanism is already preemption safe. */ - + .text .align 32 -VISenter: +ENTRY(VISenter) ldub [%g6 + TI_FPDEPTH], %g1 brnz,a,pn %g1, 1f cmp %g1, 1 @@ -79,3 +78,4 @@ vis1: ldub [%g6 + TI_FPSAVED], %g3 .align 32 80: jmpl %g7 + %g0, %g0 nop +ENDPROC(VISenter) -- cgit v0.10.2 From d618382ba5f1a4905db63f4980bf7b0a5826de9d Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 4 Nov 2015 11:30:57 -0800 Subject: iommu-common: Fix error code used in iommu_tbl_range_{alloc,free}(). The value returned from iommu_tbl_range_alloc() (and the one passed in as a fourth argument to iommu_tbl_range_free) is not a DMA address, it is rather an index into the IOMMU page table. Therefore using DMA_ERROR_CODE is not appropriate. Use a more type matching error code define, IOMMU_ERROR_CODE, and update all users of this interface. Reported-by: Andre Przywara Signed-off-by: David S. Miller diff --git a/arch/sparc/kernel/iommu.c b/arch/sparc/kernel/iommu.c index 5320689..3768682 100644 --- a/arch/sparc/kernel/iommu.c +++ b/arch/sparc/kernel/iommu.c @@ -161,7 +161,7 @@ static inline iopte_t *alloc_npages(struct device *dev, entry = iommu_tbl_range_alloc(dev, &iommu->tbl, npages, NULL, (unsigned long)(-1), 0); - if (unlikely(entry == DMA_ERROR_CODE)) + if (unlikely(entry == IOMMU_ERROR_CODE)) return NULL; return iommu->page_table + entry; @@ -253,7 +253,7 @@ static void dma_4u_free_coherent(struct device *dev, size_t size, npages = IO_PAGE_ALIGN(size) >> IO_PAGE_SHIFT; iommu = dev->archdata.iommu; - iommu_tbl_range_free(&iommu->tbl, dvma, npages, DMA_ERROR_CODE); + iommu_tbl_range_free(&iommu->tbl, dvma, npages, IOMMU_ERROR_CODE); order = get_order(size); if (order < 10) @@ -426,7 +426,7 @@ static void dma_4u_unmap_page(struct device *dev, dma_addr_t bus_addr, iommu_free_ctx(iommu, ctx); spin_unlock_irqrestore(&iommu->lock, flags); - iommu_tbl_range_free(&iommu->tbl, bus_addr, npages, DMA_ERROR_CODE); + iommu_tbl_range_free(&iommu->tbl, bus_addr, npages, IOMMU_ERROR_CODE); } static int dma_4u_map_sg(struct device *dev, struct scatterlist *sglist, @@ -492,7 +492,7 @@ static int dma_4u_map_sg(struct device *dev, struct scatterlist *sglist, &handle, (unsigned long)(-1), 0); /* Handle failure */ - if (unlikely(entry == DMA_ERROR_CODE)) { + if (unlikely(entry == IOMMU_ERROR_CODE)) { if (printk_ratelimit()) printk(KERN_INFO "iommu_alloc failed, iommu %p paddr %lx" " npages %lx\n", iommu, paddr, npages); @@ -571,7 +571,7 @@ iommu_map_failed: iopte_make_dummy(iommu, base + j); iommu_tbl_range_free(&iommu->tbl, vaddr, npages, - DMA_ERROR_CODE); + IOMMU_ERROR_CODE); s->dma_address = DMA_ERROR_CODE; s->dma_length = 0; @@ -648,7 +648,7 @@ static void dma_4u_unmap_sg(struct device *dev, struct scatterlist *sglist, iopte_make_dummy(iommu, base + i); iommu_tbl_range_free(&iommu->tbl, dma_handle, npages, - DMA_ERROR_CODE); + IOMMU_ERROR_CODE); sg = sg_next(sg); } diff --git a/arch/sparc/kernel/ldc.c b/arch/sparc/kernel/ldc.c index 1ae5eb1..59d5038 100644 --- a/arch/sparc/kernel/ldc.c +++ b/arch/sparc/kernel/ldc.c @@ -1953,7 +1953,7 @@ static struct ldc_mtable_entry *alloc_npages(struct ldc_iommu *iommu, entry = iommu_tbl_range_alloc(NULL, &iommu->iommu_map_table, npages, NULL, (unsigned long)-1, 0); - if (unlikely(entry < 0)) + if (unlikely(entry == IOMMU_ERROR_CODE)) return NULL; return iommu->page_table + entry; diff --git a/arch/sparc/kernel/pci_sun4v.c b/arch/sparc/kernel/pci_sun4v.c index d2fe57d..836e8ce 100644 --- a/arch/sparc/kernel/pci_sun4v.c +++ b/arch/sparc/kernel/pci_sun4v.c @@ -159,7 +159,7 @@ static void *dma_4v_alloc_coherent(struct device *dev, size_t size, entry = iommu_tbl_range_alloc(dev, &iommu->tbl, npages, NULL, (unsigned long)(-1), 0); - if (unlikely(entry == DMA_ERROR_CODE)) + if (unlikely(entry == IOMMU_ERROR_CODE)) goto range_alloc_fail; *dma_addrp = (iommu->tbl.table_map_base + (entry << IO_PAGE_SHIFT)); @@ -187,7 +187,7 @@ static void *dma_4v_alloc_coherent(struct device *dev, size_t size, return ret; iommu_map_fail: - iommu_tbl_range_free(&iommu->tbl, *dma_addrp, npages, DMA_ERROR_CODE); + iommu_tbl_range_free(&iommu->tbl, *dma_addrp, npages, IOMMU_ERROR_CODE); range_alloc_fail: free_pages(first_page, order); @@ -226,7 +226,7 @@ static void dma_4v_free_coherent(struct device *dev, size_t size, void *cpu, devhandle = pbm->devhandle; entry = ((dvma - iommu->tbl.table_map_base) >> IO_PAGE_SHIFT); dma_4v_iommu_demap(&devhandle, entry, npages); - iommu_tbl_range_free(&iommu->tbl, dvma, npages, DMA_ERROR_CODE); + iommu_tbl_range_free(&iommu->tbl, dvma, npages, IOMMU_ERROR_CODE); order = get_order(size); if (order < 10) free_pages((unsigned long)cpu, order); @@ -256,7 +256,7 @@ static dma_addr_t dma_4v_map_page(struct device *dev, struct page *page, entry = iommu_tbl_range_alloc(dev, &iommu->tbl, npages, NULL, (unsigned long)(-1), 0); - if (unlikely(entry == DMA_ERROR_CODE)) + if (unlikely(entry == IOMMU_ERROR_CODE)) goto bad; bus_addr = (iommu->tbl.table_map_base + (entry << IO_PAGE_SHIFT)); @@ -288,7 +288,7 @@ bad: return DMA_ERROR_CODE; iommu_map_fail: - iommu_tbl_range_free(&iommu->tbl, bus_addr, npages, DMA_ERROR_CODE); + iommu_tbl_range_free(&iommu->tbl, bus_addr, npages, IOMMU_ERROR_CODE); return DMA_ERROR_CODE; } @@ -317,7 +317,7 @@ static void dma_4v_unmap_page(struct device *dev, dma_addr_t bus_addr, bus_addr &= IO_PAGE_MASK; entry = (bus_addr - iommu->tbl.table_map_base) >> IO_PAGE_SHIFT; dma_4v_iommu_demap(&devhandle, entry, npages); - iommu_tbl_range_free(&iommu->tbl, bus_addr, npages, DMA_ERROR_CODE); + iommu_tbl_range_free(&iommu->tbl, bus_addr, npages, IOMMU_ERROR_CODE); } static int dma_4v_map_sg(struct device *dev, struct scatterlist *sglist, @@ -376,7 +376,7 @@ static int dma_4v_map_sg(struct device *dev, struct scatterlist *sglist, &handle, (unsigned long)(-1), 0); /* Handle failure */ - if (unlikely(entry == DMA_ERROR_CODE)) { + if (unlikely(entry == IOMMU_ERROR_CODE)) { if (printk_ratelimit()) printk(KERN_INFO "iommu_alloc failed, iommu %p paddr %lx" " npages %lx\n", iommu, paddr, npages); @@ -451,7 +451,7 @@ iommu_map_failed: npages = iommu_num_pages(s->dma_address, s->dma_length, IO_PAGE_SIZE); iommu_tbl_range_free(&iommu->tbl, vaddr, npages, - DMA_ERROR_CODE); + IOMMU_ERROR_CODE); /* XXX demap? XXX */ s->dma_address = DMA_ERROR_CODE; s->dma_length = 0; @@ -496,7 +496,7 @@ static void dma_4v_unmap_sg(struct device *dev, struct scatterlist *sglist, entry = ((dma_handle - tbl->table_map_base) >> shift); dma_4v_iommu_demap(&devhandle, entry, npages); iommu_tbl_range_free(&iommu->tbl, dma_handle, npages, - DMA_ERROR_CODE); + IOMMU_ERROR_CODE); sg = sg_next(sg); } diff --git a/include/linux/iommu-common.h b/include/linux/iommu-common.h index bbced83..376a27c 100644 --- a/include/linux/iommu-common.h +++ b/include/linux/iommu-common.h @@ -7,6 +7,7 @@ #define IOMMU_POOL_HASHBITS 4 #define IOMMU_NR_POOLS (1 << IOMMU_POOL_HASHBITS) +#define IOMMU_ERROR_CODE (~(unsigned long) 0) struct iommu_pool { unsigned long start; diff --git a/lib/iommu-common.c b/lib/iommu-common.c index ff19f66..0f2c887 100644 --- a/lib/iommu-common.c +++ b/lib/iommu-common.c @@ -11,10 +11,6 @@ #include #include -#ifndef DMA_ERROR_CODE -#define DMA_ERROR_CODE (~(dma_addr_t)0x0) -#endif - static unsigned long iommu_large_alloc = 15; static DEFINE_PER_CPU(unsigned int, iommu_hash_common); @@ -124,7 +120,7 @@ unsigned long iommu_tbl_range_alloc(struct device *dev, /* Sanity check */ if (unlikely(npages == 0)) { WARN_ON_ONCE(1); - return DMA_ERROR_CODE; + return IOMMU_ERROR_CODE; } if (largealloc) { @@ -207,7 +203,7 @@ unsigned long iommu_tbl_range_alloc(struct device *dev, goto again; } else { /* give up */ - n = DMA_ERROR_CODE; + n = IOMMU_ERROR_CODE; goto bail; } } @@ -259,7 +255,7 @@ void iommu_tbl_range_free(struct iommu_map_table *iommu, u64 dma_addr, unsigned long flags; unsigned long shift = iommu->table_shift; - if (entry == DMA_ERROR_CODE) /* use default addr->entry mapping */ + if (entry == IOMMU_ERROR_CODE) /* use default addr->entry mapping */ entry = (dma_addr - iommu->table_map_base) >> shift; pool = get_pool(iommu, entry); -- cgit v0.10.2 From cae9af6a820b47d3e5e0da4edf23cf6fa69b18d8 Mon Sep 17 00:00:00 2001 From: Rob Gardner Date: Fri, 30 Oct 2015 22:36:23 -0600 Subject: sparc64: Don't restrict fp regs for no-fault loads The function handle_ldf_stq() deals with no-fault ASI loads and stores, but restricts fp registers to quad word regs (ie, %f0, %f4 etc). This is valid for the STQ case, but unnecessarily restricts loads, which may be single precision, double, or quad. This results in SIGFPE being raised for this instruction when the source address is invalid: ldda [%g1] ASI_PNF, %f2 but not for this one: ldda [%g1] ASI_PNF, %f4 The validation check for quad register is moved to within the STQ block so that loads are not affected by the check. An additional problem is that the calculation for freg is incorrect when a single precision load is being handled. This causes %f1 to be seen as %f32 etc, and the incorrect register ends up being overwritten. This code sequence demonstrates the problem: ldd [%g1], %f32 ! g1 = valid address lda [%i3] ASI_PNF, %f1 ! i3 = invalid address std %f32, [%g1] This is corrected by basing the freg calculation on the load size. Signed-off-by: Rob Gardner Signed-off-by: David S. Miller diff --git a/arch/sparc/kernel/unaligned_64.c b/arch/sparc/kernel/unaligned_64.c index 62098a8..d89e97b 100644 --- a/arch/sparc/kernel/unaligned_64.c +++ b/arch/sparc/kernel/unaligned_64.c @@ -436,24 +436,26 @@ extern void sun4v_data_access_exception(struct pt_regs *regs, int handle_ldf_stq(u32 insn, struct pt_regs *regs) { unsigned long addr = compute_effective_address(regs, insn, 0); - int freg = ((insn >> 25) & 0x1e) | ((insn >> 20) & 0x20); + int freg; struct fpustate *f = FPUSTATE; int asi = decode_asi(insn, regs); - int flag = (freg < 32) ? FPRS_DL : FPRS_DU; + int flag; perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, 0); save_and_clear_fpu(); current_thread_info()->xfsr[0] &= ~0x1c000; - if (freg & 3) { - current_thread_info()->xfsr[0] |= (6 << 14) /* invalid_fp_register */; - do_fpother(regs); - return 0; - } if (insn & 0x200000) { /* STQ */ u64 first = 0, second = 0; + freg = ((insn >> 25) & 0x1e) | ((insn >> 20) & 0x20); + flag = (freg < 32) ? FPRS_DL : FPRS_DU; + if (freg & 3) { + current_thread_info()->xfsr[0] |= (6 << 14) /* invalid_fp_register */; + do_fpother(regs); + return 0; + } if (current_thread_info()->fpsaved[0] & flag) { first = *(u64 *)&f->regs[freg]; second = *(u64 *)&f->regs[freg+2]; @@ -513,6 +515,12 @@ int handle_ldf_stq(u32 insn, struct pt_regs *regs) case 0x100000: size = 4; break; default: size = 2; break; } + if (size == 1) + freg = (insn >> 25) & 0x1f; + else + freg = ((insn >> 25) & 0x1e) | ((insn >> 20) & 0x20); + flag = (freg < 32) ? FPRS_DL : FPRS_DU; + for (i = 0; i < size; i++) data[i] = 0; -- cgit v0.10.2 From 52708d690b8be132ba9d294464625dbbdb9fa5df Mon Sep 17 00:00:00 2001 From: Nitin Gupta Date: Mon, 2 Nov 2015 16:30:24 -0500 Subject: sparc64: Fix numa distance values Orabug: 21896119 Use machine descriptor (MD) to get node latency values instead of just using default values. Testing: On an T5-8 system with: - total nodes = 8 - self latencies = 0x26d18 - latency to other nodes = 0x3a598 => latency ratio = ~1.5 output of numactl --hardware - before fix: node distances: node 0 1 2 3 4 5 6 7 0: 10 20 20 20 20 20 20 20 1: 20 10 20 20 20 20 20 20 2: 20 20 10 20 20 20 20 20 3: 20 20 20 10 20 20 20 20 4: 20 20 20 20 10 20 20 20 5: 20 20 20 20 20 10 20 20 6: 20 20 20 20 20 20 10 20 7: 20 20 20 20 20 20 20 10 - after fix: node distances: node 0 1 2 3 4 5 6 7 0: 10 15 15 15 15 15 15 15 1: 15 10 15 15 15 15 15 15 2: 15 15 10 15 15 15 15 15 3: 15 15 15 10 15 15 15 15 4: 15 15 15 15 10 15 15 15 5: 15 15 15 15 15 10 15 15 6: 15 15 15 15 15 15 10 15 7: 15 15 15 15 15 15 15 10 Signed-off-by: Nitin Gupta Reviewed-by: Chris Hyser Reviewed-by: Santosh Shilimkar Signed-off-by: David S. Miller diff --git a/arch/sparc/include/asm/topology_64.h b/arch/sparc/include/asm/topology_64.h index 01d1704..bec481a 100644 --- a/arch/sparc/include/asm/topology_64.h +++ b/arch/sparc/include/asm/topology_64.h @@ -31,6 +31,9 @@ static inline int pcibus_to_node(struct pci_bus *pbus) cpu_all_mask : \ cpumask_of_node(pcibus_to_node(bus))) +int __node_distance(int, int); +#define node_distance(a, b) __node_distance(a, b) + #else /* CONFIG_NUMA */ #include diff --git a/arch/sparc/mm/init_64.c b/arch/sparc/mm/init_64.c index 4ac88b7..3025bd5 100644 --- a/arch/sparc/mm/init_64.c +++ b/arch/sparc/mm/init_64.c @@ -93,6 +93,8 @@ static unsigned long cpu_pgsz_mask; static struct linux_prom64_registers pavail[MAX_BANKS]; static int pavail_ents; +u64 numa_latency[MAX_NUMNODES][MAX_NUMNODES]; + static int cmp_p64(const void *a, const void *b) { const struct linux_prom64_registers *x = a, *y = b; @@ -1157,6 +1159,48 @@ static struct mdesc_mlgroup * __init find_mlgroup(u64 node) return NULL; } +int __node_distance(int from, int to) +{ + if ((from >= MAX_NUMNODES) || (to >= MAX_NUMNODES)) { + pr_warn("Returning default NUMA distance value for %d->%d\n", + from, to); + return (from == to) ? LOCAL_DISTANCE : REMOTE_DISTANCE; + } + return numa_latency[from][to]; +} + +static int find_best_numa_node_for_mlgroup(struct mdesc_mlgroup *grp) +{ + int i; + + for (i = 0; i < MAX_NUMNODES; i++) { + struct node_mem_mask *n = &node_masks[i]; + + if ((grp->mask == n->mask) && (grp->match == n->val)) + break; + } + return i; +} + +static void find_numa_latencies_for_group(struct mdesc_handle *md, u64 grp, + int index) +{ + u64 arc; + + mdesc_for_each_arc(arc, md, grp, MDESC_ARC_TYPE_FWD) { + int tnode; + u64 target = mdesc_arc_target(md, arc); + struct mdesc_mlgroup *m = find_mlgroup(target); + + if (!m) + continue; + tnode = find_best_numa_node_for_mlgroup(m); + if (tnode == MAX_NUMNODES) + continue; + numa_latency[index][tnode] = m->latency; + } +} + static int __init numa_attach_mlgroup(struct mdesc_handle *md, u64 grp, int index) { @@ -1220,9 +1264,16 @@ static int __init numa_parse_mdesc_group(struct mdesc_handle *md, u64 grp, static int __init numa_parse_mdesc(void) { struct mdesc_handle *md = mdesc_grab(); - int i, err, count; + int i, j, err, count; u64 node; + /* Some sane defaults for numa latency values */ + for (i = 0; i < MAX_NUMNODES; i++) { + for (j = 0; j < MAX_NUMNODES; j++) + numa_latency[i][j] = (i == j) ? + LOCAL_DISTANCE : REMOTE_DISTANCE; + } + node = mdesc_node_by_name(md, MDESC_NODE_NULL, "latency-groups"); if (node == MDESC_NODE_NULL) { mdesc_release(md); @@ -1245,6 +1296,23 @@ static int __init numa_parse_mdesc(void) count++; } + count = 0; + mdesc_for_each_node_by_name(md, node, "group") { + find_numa_latencies_for_group(md, node, count); + count++; + } + + /* Normalize numa latency matrix according to ACPI SLIT spec. */ + for (i = 0; i < MAX_NUMNODES; i++) { + u64 self_latency = numa_latency[i][i]; + + for (j = 0; j < MAX_NUMNODES; j++) { + numa_latency[i][j] = + (numa_latency[i][j] * LOCAL_DISTANCE) / + self_latency; + } + } + add_node_ranges(); for (i = 0; i < num_node_masks; i++) { -- cgit v0.10.2