Home Home > GIT Browse
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichal Suchanek <msuchanek@suse.de>2018-10-31 13:33:13 +0100
committerMichal Suchanek <msuchanek@suse.de>2018-10-31 23:28:42 +0100
commit37fbbd25e05b842f5335834879471ecd1cbbd5ae (patch)
treec2e5563fff9fedc0b230f77b2c5eae98766d0484
parent2bdb00682719e44b17952a3ac5b844961f919281 (diff)
powerpc/powernv: Move TCE manupulation code to its own file
(bsc#1061840). - Update patches.arch/powerpc-powernv-ioda2-Reduce-upper-limit-for-DMA-win.patch (bsc#1061840, bsc#1055120).
-rw-r--r--blacklist.conf1
-rw-r--r--patches.arch/powerpc-powernv-Move-TCE-manupulation-code-to-its-ow.patch783
-rw-r--r--patches.arch/powerpc-powernv-ioda2-Reduce-upper-limit-for-DMA-win.patch44
-rw-r--r--series.conf3
4 files changed, 813 insertions, 18 deletions
diff --git a/blacklist.conf b/blacklist.conf
index 30bec138ed..37a983703c 100644
--- a/blacklist.conf
+++ b/blacklist.conf
@@ -883,3 +883,4 @@ d60996ab430c8a6033a0944c068edc5ec5becb9b # Duplicate of 3af71f649d22f359790b4032
c894696188d5c2af1e636e458190e80c53fb893d # rtlwifi: the target function doesn't exist yet
16d571bb0fe6aa7fed82e19166ca1542026c9c06 # rt2x00: not cleanly applicable, merely optimization
d59d2f9995d28974877750f429e821324bd603c7 # r8822be: not present in SLE15
+d3d4ffaae439981e1e441ebb125aa3588627c5d8 # Duplicate of 7233b8cab39014620ac9534da11f0f3e506d8fd8
diff --git a/patches.arch/powerpc-powernv-Move-TCE-manupulation-code-to-its-ow.patch b/patches.arch/powerpc-powernv-Move-TCE-manupulation-code-to-its-ow.patch
new file mode 100644
index 0000000000..7cd037ac68
--- /dev/null
+++ b/patches.arch/powerpc-powernv-Move-TCE-manupulation-code-to-its-ow.patch
@@ -0,0 +1,783 @@
+From e1c4cc85fde0b60c09390dae2777e17c48eb25c2 Mon Sep 17 00:00:00 2001
+From: Alexey Kardashevskiy <aik@ozlabs.ru>
+Date: Wed, 4 Jul 2018 16:13:45 +1000
+Subject: [PATCH] powerpc/powernv: Move TCE manupulation code to its own file
+
+References: bsc#1061840
+Patch-mainline: v4.19-rc1
+Git-commit: 191c22879fbcfd98a7fe9a51786ef41253b1549b
+
+Right now we have allocation code in pci-ioda.c and traversing code in
+pci.c, let's keep them toghether. However both files are big enough
+already so let's move this business to a new file.
+
+While we at it, move the code which links IOMMU table groups to
+IOMMU tables as it is not specific to any PNV PHB model.
+
+These puts exported symbols from the new file together.
+
+This fixes several warnings from checkpatch.pl like this:
+"WARNING: Prefer 'unsigned int' to bare use of 'unsigned'".
+
+As this is almost cut-n-paste, there should be no behavioral change.
+
+Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
+Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
+Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
+Acked-by: Michal Suchanek <msuchanek@suse.de>
+---
+ arch/powerpc/platforms/powernv/Makefile | 2 +-
+ arch/powerpc/platforms/powernv/pci-ioda-tce.c | 313 ++++++++++++++++++++++++++
+ arch/powerpc/platforms/powernv/pci-ioda.c | 146 ------------
+ arch/powerpc/platforms/powernv/pci.c | 158 -------------
+ arch/powerpc/platforms/powernv/pci.h | 41 ++--
+ 5 files changed, 340 insertions(+), 320 deletions(-)
+ create mode 100644 arch/powerpc/platforms/powernv/pci-ioda-tce.c
+
+diff --git a/arch/powerpc/platforms/powernv/Makefile b/arch/powerpc/platforms/powernv/Makefile
+index 177b3d4542b5..be975390c4a6 100644
+--- a/arch/powerpc/platforms/powernv/Makefile
++++ b/arch/powerpc/platforms/powernv/Makefile
+@@ -5,7 +5,7 @@ obj-y += opal-msglog.o opal-hmi.o opal-power.o opal-irqchip.o
+ obj-y += opal-kmsg.o opal-powercap.o opal-psr.o opal-sensor-groups.o
+
+ obj-$(CONFIG_SMP) += smp.o subcore.o subcore-asm.o
+-obj-$(CONFIG_PCI) += pci.o pci-ioda.o npu-dma.o
++obj-$(CONFIG_PCI) += pci.o pci-ioda.o npu-dma.o pci-ioda-tce.o
+ obj-$(CONFIG_CXL_BASE) += pci-cxl.o
+ obj-$(CONFIG_EEH) += eeh-powernv.o
+ obj-$(CONFIG_PPC_SCOM) += opal-xscom.o
+diff --git a/arch/powerpc/platforms/powernv/pci-ioda-tce.c b/arch/powerpc/platforms/powernv/pci-ioda-tce.c
+new file mode 100644
+index 000000000000..726b8693f5ae
+--- /dev/null
++++ b/arch/powerpc/platforms/powernv/pci-ioda-tce.c
+@@ -0,0 +1,313 @@
++// SPDX-License-Identifier: GPL-2.0+
++/*
++ * TCE helpers for IODA PCI/PCIe on PowerNV platforms
++ *
++ * Copyright 2018 IBM Corp.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version
++ * 2 of the License, or (at your option) any later version.
++ */
++
++#include <linux/kernel.h>
++#include <linux/iommu.h>
++
++#include <asm/iommu.h>
++#include <asm/tce.h>
++#include "pci.h"
++
++void pnv_pci_setup_iommu_table(struct iommu_table *tbl,
++ void *tce_mem, u64 tce_size,
++ u64 dma_offset, unsigned int page_shift)
++{
++ tbl->it_blocksize = 16;
++ tbl->it_base = (unsigned long)tce_mem;
++ tbl->it_page_shift = page_shift;
++ tbl->it_offset = dma_offset >> tbl->it_page_shift;
++ tbl->it_index = 0;
++ tbl->it_size = tce_size >> 3;
++ tbl->it_busno = 0;
++ tbl->it_type = TCE_PCI;
++}
++
++static __be64 *pnv_tce(struct iommu_table *tbl, long idx)
++{
++ __be64 *tmp = ((__be64 *)tbl->it_base);
++ int level = tbl->it_indirect_levels;
++ const long shift = ilog2(tbl->it_level_size);
++ unsigned long mask = (tbl->it_level_size - 1) << (level * shift);
++
++ while (level) {
++ int n = (idx & mask) >> (level * shift);
++ unsigned long tce = be64_to_cpu(tmp[n]);
++
++ tmp = __va(tce & ~(TCE_PCI_READ | TCE_PCI_WRITE));
++ idx &= ~mask;
++ mask >>= shift;
++ --level;
++ }
++
++ return tmp + idx;
++}
++
++int pnv_tce_build(struct iommu_table *tbl, long index, long npages,
++ unsigned long uaddr, enum dma_data_direction direction,
++ unsigned long attrs)
++{
++ u64 proto_tce = iommu_direction_to_tce_perm(direction);
++ u64 rpn = __pa(uaddr) >> tbl->it_page_shift;
++ long i;
++
++ if (proto_tce & TCE_PCI_WRITE)
++ proto_tce |= TCE_PCI_READ;
++
++ for (i = 0; i < npages; i++) {
++ unsigned long newtce = proto_tce |
++ ((rpn + i) << tbl->it_page_shift);
++ unsigned long idx = index - tbl->it_offset + i;
++
++ *(pnv_tce(tbl, idx)) = cpu_to_be64(newtce);
++ }
++
++ return 0;
++}
++
++#ifdef CONFIG_IOMMU_API
++int pnv_tce_xchg(struct iommu_table *tbl, long index,
++ unsigned long *hpa, enum dma_data_direction *direction)
++{
++ u64 proto_tce = iommu_direction_to_tce_perm(*direction);
++ unsigned long newtce = *hpa | proto_tce, oldtce;
++ unsigned long idx = index - tbl->it_offset;
++
++ BUG_ON(*hpa & ~IOMMU_PAGE_MASK(tbl));
++
++ if (newtce & TCE_PCI_WRITE)
++ newtce |= TCE_PCI_READ;
++
++ oldtce = be64_to_cpu(xchg(pnv_tce(tbl, idx), cpu_to_be64(newtce)));
++ *hpa = oldtce & ~(TCE_PCI_READ | TCE_PCI_WRITE);
++ *direction = iommu_tce_direction(oldtce);
++
++ return 0;
++}
++#endif
++
++void pnv_tce_free(struct iommu_table *tbl, long index, long npages)
++{
++ long i;
++
++ for (i = 0; i < npages; i++) {
++ unsigned long idx = index - tbl->it_offset + i;
++
++ *(pnv_tce(tbl, idx)) = cpu_to_be64(0);
++ }
++}
++
++unsigned long pnv_tce_get(struct iommu_table *tbl, long index)
++{
++ return be64_to_cpu(*(pnv_tce(tbl, index - tbl->it_offset)));
++}
++
++static void pnv_pci_ioda2_table_do_free_pages(__be64 *addr,
++ unsigned long size, unsigned int levels)
++{
++ const unsigned long addr_ul = (unsigned long) addr &
++ ~(TCE_PCI_READ | TCE_PCI_WRITE);
++
++ if (levels) {
++ long i;
++ u64 *tmp = (u64 *) addr_ul;
++
++ for (i = 0; i < size; ++i) {
++ unsigned long hpa = be64_to_cpu(tmp[i]);
++
++ if (!(hpa & (TCE_PCI_READ | TCE_PCI_WRITE)))
++ continue;
++
++ pnv_pci_ioda2_table_do_free_pages(__va(hpa), size,
++ levels - 1);
++ }
++ }
++
++ free_pages(addr_ul, get_order(size << 3));
++}
++
++void pnv_pci_ioda2_table_free_pages(struct iommu_table *tbl)
++{
++ const unsigned long size = tbl->it_indirect_levels ?
++ tbl->it_level_size : tbl->it_size;
++
++ if (!tbl->it_size)
++ return;
++
++ pnv_pci_ioda2_table_do_free_pages((__be64 *)tbl->it_base, size,
++ tbl->it_indirect_levels);
++}
++
++static __be64 *pnv_pci_ioda2_table_do_alloc_pages(int nid, unsigned int shift,
++ unsigned int levels, unsigned long limit,
++ unsigned long *current_offset, unsigned long *total_allocated)
++{
++ struct page *tce_mem = NULL;
++ __be64 *addr, *tmp;
++ unsigned int order = max_t(unsigned int, shift, PAGE_SHIFT) -
++ PAGE_SHIFT;
++ unsigned long allocated = 1UL << (order + PAGE_SHIFT);
++ unsigned int entries = 1UL << (shift - 3);
++ long i;
++
++ tce_mem = alloc_pages_node(nid, GFP_KERNEL, order);
++ if (!tce_mem) {
++ pr_err("Failed to allocate a TCE memory, order=%d\n", order);
++ return NULL;
++ }
++ addr = page_address(tce_mem);
++ memset(addr, 0, allocated);
++ *total_allocated += allocated;
++
++ --levels;
++ if (!levels) {
++ *current_offset += allocated;
++ return addr;
++ }
++
++ for (i = 0; i < entries; ++i) {
++ tmp = pnv_pci_ioda2_table_do_alloc_pages(nid, shift,
++ levels, limit, current_offset, total_allocated);
++ if (!tmp)
++ break;
++
++ addr[i] = cpu_to_be64(__pa(tmp) |
++ TCE_PCI_READ | TCE_PCI_WRITE);
++
++ if (*current_offset >= limit)
++ break;
++ }
++
++ return addr;
++}
++
++long pnv_pci_ioda2_table_alloc_pages(int nid, __u64 bus_offset,
++ __u32 page_shift, __u64 window_size, __u32 levels,
++ struct iommu_table *tbl)
++{
++ void *addr;
++ unsigned long offset = 0, level_shift, total_allocated = 0;
++ const unsigned int window_shift = ilog2(window_size);
++ unsigned int entries_shift = window_shift - page_shift;
++ unsigned int table_shift = max_t(unsigned int, entries_shift + 3,
++ PAGE_SHIFT);
++ const unsigned long tce_table_size = 1UL << table_shift;
++
++ if (!levels || (levels > POWERNV_IOMMU_MAX_LEVELS))
++ return -EINVAL;
++
++ if (!is_power_of_2(window_size))
++ return -EINVAL;
++
++ /* Adjust direct table size from window_size and levels */
++ entries_shift = (entries_shift + levels - 1) / levels;
++ level_shift = entries_shift + 3;
++ level_shift = max_t(unsigned int, level_shift, PAGE_SHIFT);
++
++ if ((level_shift - 3) * levels + page_shift >= 60)
++ return -EINVAL;
++
++ /* Allocate TCE table */
++ addr = pnv_pci_ioda2_table_do_alloc_pages(nid, level_shift,
++ levels, tce_table_size, &offset, &total_allocated);
++
++ /* addr==NULL means that the first level allocation failed */
++ if (!addr)
++ return -ENOMEM;
++
++ /*
++ * First level was allocated but some lower level failed as
++ * we did not allocate as much as we wanted,
++ * release partially allocated table.
++ */
++ if (offset < tce_table_size) {
++ pnv_pci_ioda2_table_do_free_pages(addr,
++ 1ULL << (level_shift - 3), levels - 1);
++ return -ENOMEM;
++ }
++
++ /* Setup linux iommu table */
++ pnv_pci_setup_iommu_table(tbl, addr, tce_table_size, bus_offset,
++ page_shift);
++ tbl->it_level_size = 1ULL << (level_shift - 3);
++ tbl->it_indirect_levels = levels - 1;
++ tbl->it_allocated_size = total_allocated;
++
++ pr_devel("Created TCE table: ws=%08llx ts=%lx @%08llx\n",
++ window_size, tce_table_size, bus_offset);
++
++ return 0;
++}
++
++static void pnv_iommu_table_group_link_free(struct rcu_head *head)
++{
++ struct iommu_table_group_link *tgl = container_of(head,
++ struct iommu_table_group_link, rcu);
++
++ kfree(tgl);
++}
++
++void pnv_pci_unlink_table_and_group(struct iommu_table *tbl,
++ struct iommu_table_group *table_group)
++{
++ long i;
++ bool found;
++ struct iommu_table_group_link *tgl;
++
++ if (!tbl || !table_group)
++ return;
++
++ /* Remove link to a group from table's list of attached groups */
++ found = false;
++ list_for_each_entry_rcu(tgl, &tbl->it_group_list, next) {
++ if (tgl->table_group == table_group) {
++ list_del_rcu(&tgl->next);
++ call_rcu(&tgl->rcu, pnv_iommu_table_group_link_free);
++ found = true;
++ break;
++ }
++ }
++ if (WARN_ON(!found))
++ return;
++
++ /* Clean a pointer to iommu_table in iommu_table_group::tables[] */
++ found = false;
++ for (i = 0; i < IOMMU_TABLE_GROUP_MAX_TABLES; ++i) {
++ if (table_group->tables[i] == tbl) {
++ table_group->tables[i] = NULL;
++ found = true;
++ break;
++ }
++ }
++ WARN_ON(!found);
++}
++
++long pnv_pci_link_table_and_group(int node, int num,
++ struct iommu_table *tbl,
++ struct iommu_table_group *table_group)
++{
++ struct iommu_table_group_link *tgl = NULL;
++
++ if (WARN_ON(!tbl || !table_group))
++ return -EINVAL;
++
++ tgl = kzalloc_node(sizeof(struct iommu_table_group_link), GFP_KERNEL,
++ node);
++ if (!tgl)
++ return -ENOMEM;
++
++ tgl->table_group = table_group;
++ list_add_rcu(&tgl->next, &tbl->it_group_list);
++
++ table_group->tables[num] = tbl;
++
++ return 0;
++}
+diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c
+index bf0f7fda0876..732250618a50 100644
+--- a/arch/powerpc/platforms/powernv/pci-ioda.c
++++ b/arch/powerpc/platforms/powernv/pci-ioda.c
+@@ -51,11 +51,7 @@
+ #define PNV_IODA1_M64_SEGS 8 /* Segments per M64 BAR */
+ #define PNV_IODA1_DMA32_SEGSIZE 0x10000000
+
+-#define POWERNV_IOMMU_DEFAULT_LEVELS 1
+-#define POWERNV_IOMMU_MAX_LEVELS 5
+-
+ static const char * const pnv_phb_names[] = { "IODA1", "IODA2", "NPU" };
+-static void pnv_pci_ioda2_table_free_pages(struct iommu_table *tbl);
+
+ void pe_level_printk(const struct pnv_ioda_pe *pe, const char *level,
+ const char *fmt, ...)
+@@ -2307,10 +2303,6 @@ void pnv_pci_ioda2_set_bypass(struct pnv_ioda_pe *pe, bool enable)
+ pe->tce_bypass_enabled = enable;
+ }
+
+-static long pnv_pci_ioda2_table_alloc_pages(int nid, __u64 bus_offset,
+- __u32 page_shift, __u64 window_size, __u32 levels,
+- struct iommu_table *tbl);
+-
+ static long pnv_pci_ioda2_create_table(struct iommu_table_group *table_group,
+ int num, __u32 page_shift, __u64 window_size, __u32 levels,
+ struct iommu_table **ptbl)
+@@ -2598,144 +2590,6 @@ static void pnv_pci_ioda_setup_iommu_api(void)
+ static void pnv_pci_ioda_setup_iommu_api(void) { };
+ #endif
+
+-static __be64 *pnv_pci_ioda2_table_do_alloc_pages(int nid, unsigned shift,
+- unsigned levels, unsigned long limit,
+- unsigned long *current_offset, unsigned long *total_allocated)
+-{
+- struct page *tce_mem = NULL;
+- __be64 *addr, *tmp;
+- unsigned order = max_t(unsigned, shift, PAGE_SHIFT) - PAGE_SHIFT;
+- unsigned long allocated = 1UL << (order + PAGE_SHIFT);
+- unsigned entries = 1UL << (shift - 3);
+- long i;
+-
+- tce_mem = alloc_pages_node(nid, GFP_KERNEL, order);
+- if (!tce_mem) {
+- pr_err("Failed to allocate a TCE memory, order=%d\n", order);
+- return NULL;
+- }
+- addr = page_address(tce_mem);
+- memset(addr, 0, allocated);
+- *total_allocated += allocated;
+-
+- --levels;
+- if (!levels) {
+- *current_offset += allocated;
+- return addr;
+- }
+-
+- for (i = 0; i < entries; ++i) {
+- tmp = pnv_pci_ioda2_table_do_alloc_pages(nid, shift,
+- levels, limit, current_offset, total_allocated);
+- if (!tmp)
+- break;
+-
+- addr[i] = cpu_to_be64(__pa(tmp) |
+- TCE_PCI_READ | TCE_PCI_WRITE);
+-
+- if (*current_offset >= limit)
+- break;
+- }
+-
+- return addr;
+-}
+-
+-static void pnv_pci_ioda2_table_do_free_pages(__be64 *addr,
+- unsigned long size, unsigned level);
+-
+-static long pnv_pci_ioda2_table_alloc_pages(int nid, __u64 bus_offset,
+- __u32 page_shift, __u64 window_size, __u32 levels,
+- struct iommu_table *tbl)
+-{
+- void *addr;
+- unsigned long offset = 0, level_shift, total_allocated = 0;
+- const unsigned window_shift = ilog2(window_size);
+- unsigned entries_shift = window_shift - page_shift;
+- unsigned table_shift = max_t(unsigned, entries_shift + 3, PAGE_SHIFT);
+- const unsigned long tce_table_size = 1UL << table_shift;
+-
+- if (!levels || (levels > POWERNV_IOMMU_MAX_LEVELS))
+- return -EINVAL;
+-
+- if (!is_power_of_2(window_size))
+- return -EINVAL;
+-
+- /* Adjust direct table size from window_size and levels */
+- entries_shift = (entries_shift + levels - 1) / levels;
+- level_shift = entries_shift + 3;
+- level_shift = max_t(unsigned, level_shift, PAGE_SHIFT);
+-
+- if ((level_shift - 3) * levels + page_shift >= 60)
+- return -EINVAL;
+-
+- /* Allocate TCE table */
+- addr = pnv_pci_ioda2_table_do_alloc_pages(nid, level_shift,
+- levels, tce_table_size, &offset, &total_allocated);
+-
+- /* addr==NULL means that the first level allocation failed */
+- if (!addr)
+- return -ENOMEM;
+-
+- /*
+- * First level was allocated but some lower level failed as
+- * we did not allocate as much as we wanted,
+- * release partially allocated table.
+- */
+- if (offset < tce_table_size) {
+- pnv_pci_ioda2_table_do_free_pages(addr,
+- 1ULL << (level_shift - 3), levels - 1);
+- return -ENOMEM;
+- }
+-
+- /* Setup linux iommu table */
+- pnv_pci_setup_iommu_table(tbl, addr, tce_table_size, bus_offset,
+- page_shift);
+- tbl->it_level_size = 1ULL << (level_shift - 3);
+- tbl->it_indirect_levels = levels - 1;
+- tbl->it_allocated_size = total_allocated;
+-
+- pr_devel("Created TCE table: ws=%08llx ts=%lx @%08llx\n",
+- window_size, tce_table_size, bus_offset);
+-
+- return 0;
+-}
+-
+-static void pnv_pci_ioda2_table_do_free_pages(__be64 *addr,
+- unsigned long size, unsigned level)
+-{
+- const unsigned long addr_ul = (unsigned long) addr &
+- ~(TCE_PCI_READ | TCE_PCI_WRITE);
+-
+- if (level) {
+- long i;
+- u64 *tmp = (u64 *) addr_ul;
+-
+- for (i = 0; i < size; ++i) {
+- unsigned long hpa = be64_to_cpu(tmp[i]);
+-
+- if (!(hpa & (TCE_PCI_READ | TCE_PCI_WRITE)))
+- continue;
+-
+- pnv_pci_ioda2_table_do_free_pages(__va(hpa), size,
+- level - 1);
+- }
+- }
+-
+- free_pages(addr_ul, get_order(size << 3));
+-}
+-
+-static void pnv_pci_ioda2_table_free_pages(struct iommu_table *tbl)
+-{
+- const unsigned long size = tbl->it_indirect_levels ?
+- tbl->it_level_size : tbl->it_size;
+-
+- if (!tbl->it_size)
+- return;
+-
+- pnv_pci_ioda2_table_do_free_pages((__be64 *)tbl->it_base, size,
+- tbl->it_indirect_levels);
+-}
+-
+ static void pnv_pci_ioda2_setup_dma_pe(struct pnv_phb *phb,
+ struct pnv_ioda_pe *pe)
+ {
+diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c
+index 5422f4a6317c..7799b19bb5dd 100644
+--- a/arch/powerpc/platforms/powernv/pci.c
++++ b/arch/powerpc/platforms/powernv/pci.c
+@@ -800,85 +800,6 @@ struct pci_ops pnv_pci_ops = {
+ .write = pnv_pci_write_config,
+ };
+
+-static __be64 *pnv_tce(struct iommu_table *tbl, long idx)
+-{
+- __be64 *tmp = ((__be64 *)tbl->it_base);
+- int level = tbl->it_indirect_levels;
+- const long shift = ilog2(tbl->it_level_size);
+- unsigned long mask = (tbl->it_level_size - 1) << (level * shift);
+-
+- while (level) {
+- int n = (idx & mask) >> (level * shift);
+- unsigned long tce = be64_to_cpu(tmp[n]);
+-
+- tmp = __va(tce & ~(TCE_PCI_READ | TCE_PCI_WRITE));
+- idx &= ~mask;
+- mask >>= shift;
+- --level;
+- }
+-
+- return tmp + idx;
+-}
+-
+-int pnv_tce_build(struct iommu_table *tbl, long index, long npages,
+- unsigned long uaddr, enum dma_data_direction direction,
+- unsigned long attrs)
+-{
+- u64 proto_tce = iommu_direction_to_tce_perm(direction);
+- u64 rpn = __pa(uaddr) >> tbl->it_page_shift;
+- long i;
+-
+- if (proto_tce & TCE_PCI_WRITE)
+- proto_tce |= TCE_PCI_READ;
+-
+- for (i = 0; i < npages; i++) {
+- unsigned long newtce = proto_tce |
+- ((rpn + i) << tbl->it_page_shift);
+- unsigned long idx = index - tbl->it_offset + i;
+-
+- *(pnv_tce(tbl, idx)) = cpu_to_be64(newtce);
+- }
+-
+- return 0;
+-}
+-
+-#ifdef CONFIG_IOMMU_API
+-int pnv_tce_xchg(struct iommu_table *tbl, long index,
+- unsigned long *hpa, enum dma_data_direction *direction)
+-{
+- u64 proto_tce = iommu_direction_to_tce_perm(*direction);
+- unsigned long newtce = *hpa | proto_tce, oldtce;
+- unsigned long idx = index - tbl->it_offset;
+-
+- BUG_ON(*hpa & ~IOMMU_PAGE_MASK(tbl));
+-
+- if (newtce & TCE_PCI_WRITE)
+- newtce |= TCE_PCI_READ;
+-
+- oldtce = be64_to_cpu(xchg(pnv_tce(tbl, idx), cpu_to_be64(newtce)));
+- *hpa = oldtce & ~(TCE_PCI_READ | TCE_PCI_WRITE);
+- *direction = iommu_tce_direction(oldtce);
+-
+- return 0;
+-}
+-#endif
+-
+-void pnv_tce_free(struct iommu_table *tbl, long index, long npages)
+-{
+- long i;
+-
+- for (i = 0; i < npages; i++) {
+- unsigned long idx = index - tbl->it_offset + i;
+-
+- *(pnv_tce(tbl, idx)) = cpu_to_be64(0);
+- }
+-}
+-
+-unsigned long pnv_tce_get(struct iommu_table *tbl, long index)
+-{
+- return be64_to_cpu(*(pnv_tce(tbl, index - tbl->it_offset)));
+-}
+-
+ struct iommu_table *pnv_pci_table_alloc(int nid)
+ {
+ struct iommu_table *tbl;
+@@ -893,85 +814,6 @@ struct iommu_table *pnv_pci_table_alloc(int nid)
+ return tbl;
+ }
+
+-long pnv_pci_link_table_and_group(int node, int num,
+- struct iommu_table *tbl,
+- struct iommu_table_group *table_group)
+-{
+- struct iommu_table_group_link *tgl = NULL;
+-
+- if (WARN_ON(!tbl || !table_group))
+- return -EINVAL;
+-
+- tgl = kzalloc_node(sizeof(struct iommu_table_group_link), GFP_KERNEL,
+- node);
+- if (!tgl)
+- return -ENOMEM;
+-
+- tgl->table_group = table_group;
+- list_add_rcu(&tgl->next, &tbl->it_group_list);
+-
+- table_group->tables[num] = tbl;
+-
+- return 0;
+-}
+-
+-static void pnv_iommu_table_group_link_free(struct rcu_head *head)
+-{
+- struct iommu_table_group_link *tgl = container_of(head,
+- struct iommu_table_group_link, rcu);
+-
+- kfree(tgl);
+-}
+-
+-void pnv_pci_unlink_table_and_group(struct iommu_table *tbl,
+- struct iommu_table_group *table_group)
+-{
+- long i;
+- bool found;
+- struct iommu_table_group_link *tgl;
+-
+- if (!tbl || !table_group)
+- return;
+-
+- /* Remove link to a group from table's list of attached groups */
+- found = false;
+- list_for_each_entry_rcu(tgl, &tbl->it_group_list, next) {
+- if (tgl->table_group == table_group) {
+- list_del_rcu(&tgl->next);
+- call_rcu(&tgl->rcu, pnv_iommu_table_group_link_free);
+- found = true;
+- break;
+- }
+- }
+- if (WARN_ON(!found))
+- return;
+-
+- /* Clean a pointer to iommu_table in iommu_table_group::tables[] */
+- found = false;
+- for (i = 0; i < IOMMU_TABLE_GROUP_MAX_TABLES; ++i) {
+- if (table_group->tables[i] == tbl) {
+- table_group->tables[i] = NULL;
+- found = true;
+- break;
+- }
+- }
+- WARN_ON(!found);
+-}
+-
+-void pnv_pci_setup_iommu_table(struct iommu_table *tbl,
+- void *tce_mem, u64 tce_size,
+- u64 dma_offset, unsigned page_shift)
+-{
+- tbl->it_blocksize = 16;
+- tbl->it_base = (unsigned long)tce_mem;
+- tbl->it_page_shift = page_shift;
+- tbl->it_offset = dma_offset >> tbl->it_page_shift;
+- tbl->it_index = 0;
+- tbl->it_size = tce_size >> 3;
+- tbl->it_busno = 0;
+- tbl->it_type = TCE_PCI;
+-}
+-
+ void pnv_pci_dma_dev_setup(struct pci_dev *pdev)
+ {
+ struct pci_controller *hose = pci_bus_to_host(pdev->bus);
+diff --git a/arch/powerpc/platforms/powernv/pci.h b/arch/powerpc/platforms/powernv/pci.h
+index a95273c524f6..e1ab2a433d21 100644
+--- a/arch/powerpc/platforms/powernv/pci.h
++++ b/arch/powerpc/platforms/powernv/pci.h
+@@ -196,13 +196,6 @@ struct pnv_phb {
+ };
+
+ extern struct pci_ops pnv_pci_ops;
+-extern int pnv_tce_build(struct iommu_table *tbl, long index, long npages,
+- unsigned long uaddr, enum dma_data_direction direction,
+- unsigned long attrs);
+-extern void pnv_tce_free(struct iommu_table *tbl, long index, long npages);
+-extern int pnv_tce_xchg(struct iommu_table *tbl, long index,
+- unsigned long *hpa, enum dma_data_direction *direction);
+-extern unsigned long pnv_tce_get(struct iommu_table *tbl, long index);
+
+ void pnv_pci_dump_phb_diag_data(struct pci_controller *hose,
+ unsigned char *log_buff);
+@@ -212,14 +205,6 @@ int pnv_pci_cfg_write(struct pci_dn *pdn,
+ int where, int size, u32 val);
+ extern struct iommu_table *pnv_pci_table_alloc(int nid);
+
+-extern long pnv_pci_link_table_and_group(int node, int num,
+- struct iommu_table *tbl,
+- struct iommu_table_group *table_group);
+-extern void pnv_pci_unlink_table_and_group(struct iommu_table *tbl,
+- struct iommu_table_group *table_group);
+-extern void pnv_pci_setup_iommu_table(struct iommu_table *tbl,
+- void *tce_mem, u64 tce_size,
+- u64 dma_offset, unsigned page_shift);
+ extern void pnv_pci_init_ioda_hub(struct device_node *np);
+ extern void pnv_pci_init_ioda2_phb(struct device_node *np);
+ extern void pnv_pci_init_npu_phb(struct device_node *np);
+@@ -265,4 +250,30 @@ extern void pnv_cxl_cx4_teardown_msi_irqs(struct pci_dev *pdev);
+ /* phb ops (cxl switches these when enabling the kernel api on the phb) */
+ extern const struct pci_controller_ops pnv_cxl_cx4_ioda_controller_ops;
+
++/* pci-ioda-tce.c */
++#define POWERNV_IOMMU_DEFAULT_LEVELS 1
++#define POWERNV_IOMMU_MAX_LEVELS 5
++
++extern int pnv_tce_build(struct iommu_table *tbl, long index, long npages,
++ unsigned long uaddr, enum dma_data_direction direction,
++ unsigned long attrs);
++extern void pnv_tce_free(struct iommu_table *tbl, long index, long npages);
++extern int pnv_tce_xchg(struct iommu_table *tbl, long index,
++ unsigned long *hpa, enum dma_data_direction *direction);
++extern unsigned long pnv_tce_get(struct iommu_table *tbl, long index);
++
++extern long pnv_pci_ioda2_table_alloc_pages(int nid, __u64 bus_offset,
++ __u32 page_shift, __u64 window_size, __u32 levels,
++ struct iommu_table *tbl);
++extern void pnv_pci_ioda2_table_free_pages(struct iommu_table *tbl);
++
++extern long pnv_pci_link_table_and_group(int node, int num,
++ struct iommu_table *tbl,
++ struct iommu_table_group *table_group);
++extern void pnv_pci_unlink_table_and_group(struct iommu_table *tbl,
++ struct iommu_table_group *table_group);
++extern void pnv_pci_setup_iommu_table(struct iommu_table *tbl,
++ void *tce_mem, u64 tce_size,
++ u64 dma_offset, unsigned int page_shift);
++
+ #endif /* __POWERNV_PCI_H */
+--
+2.13.7
+
diff --git a/patches.arch/powerpc-powernv-ioda2-Reduce-upper-limit-for-DMA-win.patch b/patches.arch/powerpc-powernv-ioda2-Reduce-upper-limit-for-DMA-win.patch
index 94d2f3d057..4b20fb8998 100644
--- a/patches.arch/powerpc-powernv-ioda2-Reduce-upper-limit-for-DMA-win.patch
+++ b/patches.arch/powerpc-powernv-ioda2-Reduce-upper-limit-for-DMA-win.patch
@@ -1,38 +1,48 @@
-From d3d4ffaae439981e1e441ebb125aa3588627c5d8 Mon Sep 17 00:00:00 2001
+From 7233b8cab39014620ac9534da11f0f3e506d8fd8 Mon Sep 17 00:00:00 2001
From: Alexey Kardashevskiy <aik@ozlabs.ru>
-Date: Fri, 1 Jun 2018 18:06:16 +1000
+Date: Tue, 11 Sep 2018 15:38:05 +1000
Subject: [PATCH] powerpc/powernv/ioda2: Reduce upper limit for DMA window size
-References: bsc#1055120
-Patch-mainline: v4.19-rc1
-Git-commit: d3d4ffaae439981e1e441ebb125aa3588627c5d8
+References: bsc#1061840, bsc#1055120
+Patch-mainline: v4.19-rc6
+Git-commit: 7233b8cab39014620ac9534da11f0f3e506d8fd8
+
+mpe: This was fixed originally in commit d3d4ffaae439
+("powerpc/powernv/ioda2: Reduce upper limit for DMA window size"), but
+contrary to what the merge commit says was inadvertently lost by me in
+commit ce57c6610cc2 ("Merge branch 'topic/ppc-kvm' into next") which
+brought in changes that moved the code to a new file. So reapply it to
+the new file.
+
+Original commit message follows:
We use PHB in mode1 which uses bit 59 to select a correct DMA window.
However there is mode2 which uses bits 59:55 and allows up to 32 DMA
windows per a PE.
Even though documentation does not clearly specify that, it seems that
-the actual hardware does not support bits 59:55 even in mode1, in other
-words we can create a window as big as 1<<58 but DMA simply won't work.
+the actual hardware does not support bits 59:55 even in mode1, in
+other words we can create a window as big as 1<<58 but DMA simply
+won't work.
-This reduces the upper limit from 59 to 55 bits to let the userspace know
-about the hardware limits.
+This reduces the upper limit from 59 to 55 bits to let the userspace
+know about the hardware limits.
-Fixes: 7aafac11e3 "powerpc/powernv/ioda2: Gracefully fail if too many TCE levels requested"
+Fixes: ce57c6610cc2 ("Merge branch 'topic/ppc-kvm' into next")
Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Acked-by: Michal Suchanek <msuchanek@suse.de>
---
- arch/powerpc/platforms/powernv/pci-ioda.c | 2 +-
+ arch/powerpc/platforms/powernv/pci-ioda-tce.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
-diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c
-index 5bd0eb6681bc..ab678177d36e 100644
---- a/arch/powerpc/platforms/powernv/pci-ioda.c
-+++ b/arch/powerpc/platforms/powernv/pci-ioda.c
-@@ -2840,7 +2840,7 @@ static long pnv_pci_ioda2_table_alloc_pages(int nid, __u64 bus_offset,
+diff --git a/arch/powerpc/platforms/powernv/pci-ioda-tce.c b/arch/powerpc/platforms/powernv/pci-ioda-tce.c
+index 6c5db1acbe8d..fe9691040f54 100644
+--- a/arch/powerpc/platforms/powernv/pci-ioda-tce.c
++++ b/arch/powerpc/platforms/powernv/pci-ioda-tce.c
+@@ -276,7 +276,7 @@ long pnv_pci_ioda2_table_alloc_pages(int nid, __u64 bus_offset,
level_shift = entries_shift + 3;
- level_shift = max_t(unsigned, level_shift, PAGE_SHIFT);
+ level_shift = max_t(unsigned int, level_shift, PAGE_SHIFT);
- if ((level_shift - 3) * levels + page_shift >= 60)
+ if ((level_shift - 3) * levels + page_shift >= 55)
diff --git a/series.conf b/series.conf
index fb0dc643e5..661518573e 100644
--- a/series.conf
+++ b/series.conf
@@ -17660,7 +17660,7 @@
patches.suse/0002-module-setup-load-info-before-module_sig_check.patch
patches.suse/0003-modsign-log-module-name-in-the-event-of-an-error.patch
patches.suse/0004-ARM-module-fix-modsign-build-error.patch
- patches.arch/powerpc-powernv-ioda2-Reduce-upper-limit-for-DMA-win.patch
+ patches.arch/powerpc-powernv-Move-TCE-manupulation-code-to-its-ow.patch
patches.arch/cxl-Fix-wrong-comparison-in-cxl_adapter_context_get.patch
patches.arch/powerpc-pkeys-Give-all-threads-control-of-their-key-.patch
patches.arch/powerpc-pkeys-Deny-read-write-execute-by-default.patch
@@ -18153,6 +18153,7 @@
patches.fixes/0001-drm-amdgpu-Fix-vce-work-queue-was-not-cancelled-when.patch
patches.drivers/pinctrl-cannonlake-Fix-HOSTSW_OWN-register-offset-of.patch
patches.arch/powerpc-Avoid-code-patching-freed-init-sections.patch
+ patches.arch/powerpc-powernv-ioda2-Reduce-upper-limit-for-DMA-win.patch
patches.arch/powerpc-pkeys-Fix-reading-of-ibm-processor-storage-k.patch
patches.arch/powerpc-tm-Fix-userspace-r13-corruption.patch
patches.arch/powerpc-tm-Avoid-possible-userspace-r1-corruption-on.patch