From: Scott Wood <hidden> Date: 2014-08-08 23:41:09
Platform code can call limit_zone_pfn() to set appropriate limits
for ZONE_DMA and ZONE_DMA32, and dma_direct_alloc_coherent() will
select a suitable zone based on a device's mask and the pfn limits that
platform code has configured.
Signed-off-by: Scott Wood <redacted>
Cc: Shaohui Xie <redacted>
---
arch/powerpc/Kconfig | 4 +++
arch/powerpc/include/asm/pgtable.h | 3 ++
arch/powerpc/kernel/dma.c | 20 +++++++++++++
arch/powerpc/mm/mem.c | 61 ++++++++++++++++++++++++++++++++++----
4 files changed, 83 insertions(+), 5 deletions(-)
From: Scott Wood <hidden> Date: 2014-08-08 23:41:11
FSL PCI cannot directly address the whole lower 4 GiB due to
conflicts with PCICSRBAR and outbound windows, and thus
max_direct_dma_addr is less than 4GiB. Honor that limit in
dma_direct_alloc_coherent().
Note that setting the DMA mask to 31 bits is not an option, since many
PCI drivers would fail if we reject 32-bit DMA in dma_supported(), and
we have no control over the setting of coherent_dma_mask if
dma_supported() returns true.
Signed-off-by: Scott Wood <redacted>
Cc: Shaohui Xie <redacted>
---
arch/powerpc/kernel/dma.c | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
From: Scott Wood <hidden> Date: 2014-08-08 23:41:12
A DMA zone is still needed with swiotlb, for coherent allocations.
This doesn't affect platforms that don't use swiotlb or that don't call
swiotlb_detect_4g().
Signed-off-by: Scott Wood <redacted>
Cc: Shaohui Xie <redacted>
---
arch/powerpc/kernel/dma-swiotlb.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
From: Scott Wood <hidden> Date: 2014-08-08 23:41:13
FSL PCI cannot directly address the whole lower 4 GiB due to
conflicts with PCICSRBAR and outbound windows. By the time
max_direct_dma_addr is set to the precise limit, it will be too late to
alter the zone limits, but we should always have at least 2 GiB mapped
(unless RAM is smaller than that).
Signed-off-by: Scott Wood <redacted>
Cc: Shaohui Xie <redacted>
---
arch/powerpc/platforms/85xx/corenet_generic.c | 11 +++++++++++
arch/powerpc/platforms/85xx/qemu_e500.c | 10 ++++++++++
2 files changed, 21 insertions(+)
From: Anton Blanchard <hidden> Date: 2014-10-13 07:14:37
Hi Scott,
Platform code can call limit_zone_pfn() to set appropriate limits
for ZONE_DMA and ZONE_DMA32, and dma_direct_alloc_coherent() will
select a suitable zone based on a device's mask and the pfn limits
that platform code has configured.
This patch breaks my POWER8 box:
ipr 0001:08:00.0: Using 64-bit DMA iommu bypass
ipr 0001:08:00.0: dma_direct_alloc_coherent: No suitable zone for pfn 0x10000
ipr 0001:08:00.0: Couldn't allocate enough memory for device driver!
ipr: probe of 0001:08:00.0 failed with error -12
ipr isn't setting a coherent mask, but we shouldn't care on these boxes.
Could we ignore the coherent mask or copy the dma mask to it?
Anton
--
@@ -261,6 +261,54 @@ static int __init mark_nonram_nosave(void)return0;}+staticboolzone_limits_final;++staticunsignedlongmax_zone_pfns[MAX_NR_ZONES]={+[0...MAX_NR_ZONES-1]=~0UL+};++/*+*Restrictthespecifiedzoneandallmorerestrictivezones+*tobebelowthespecifiedpfn.Maynotbecalledafter+*paging_init().+*/+void__initlimit_zone_pfn(enumzone_typezone,unsignedlong
pfn_limit) +{
+ int i;
+
+ if (WARN_ON(zone_limits_final))
+ return;
+
+ for (i = zone; i >= 0; i--) {
+ if (max_zone_pfns[i] > pfn_limit)
+ max_zone_pfns[i] = pfn_limit;
+ }
+}
+
+/*
+ * Find the least restrictive zone that is entirely below the
+ * specified pfn limit. Returns < 0 if no suitable zone is found.
+ *
+ * pfn_limit must be u64 because it can exceed 32 bits even on 32-bit
+ * systems -- the DMA limit can be higher than any possible real pfn.
+ */
+int dma_pfn_limit_to_zone(u64 pfn_limit)
+{
+ enum zone_type top_zone = ZONE_NORMAL;
+ int i;
+
+#ifdef CONFIG_HIGHMEM
+ top_zone = ZONE_HIGHMEM;
+#endif
+
+ for (i = top_zone; i >= 0; i--) {
+ if (max_zone_pfns[i] <= pfn_limit)
+ return i;
+ }
+
+ return -EPERM;
+}
+
/*
* paging_init() sets up the page tables - in fact we've already
done this. */
@@ -268,7 +316,7 @@ void __init paging_init(void) { unsigned long long total_ram = memblock_phys_mem_size(); phys_addr_t top_of_ram = memblock_end_of_DRAM();- unsigned long max_zone_pfns[MAX_NR_ZONES];+ enum zone_type top_zone; #ifdef CONFIG_PPC32 unsigned long v = __fix_to_virt(__end_of_fixed_addresses -
From: Benjamin Herrenschmidt <benh@kernel.crashing.org> Date: 2014-10-13 07:31:01
On Mon, 2014-10-13 at 18:14 +1100, Anton Blanchard wrote:
Hi Scott,
quoted
Platform code can call limit_zone_pfn() to set appropriate limits
for ZONE_DMA and ZONE_DMA32, and dma_direct_alloc_coherent() will
select a suitable zone based on a device's mask and the pfn limits
that platform code has configured.
This patch breaks my POWER8 box:
ipr 0001:08:00.0: Using 64-bit DMA iommu bypass
ipr 0001:08:00.0: dma_direct_alloc_coherent: No suitable zone for pfn 0x10000
ipr 0001:08:00.0: Couldn't allocate enough memory for device driver!
ipr: probe of 0001:08:00.0 failed with error -12
ipr isn't setting a coherent mask, but we shouldn't care on these boxes.
Could we ignore the coherent mask or copy the dma mask to it?
So this depends what the coherent_mask actually means vs. the dma_mask.
I've always been extremely confused by the distinction. Since the
coherent_mask is set by the driver, I assume it represents a driver
limitation on coherent memory which might be *different* from the
restriction on streaming mappings, in which case we might have to honor
it...
The problem is that our whole mechanism for switching dma_ops is based
on having one mask.
So even if we somewhat "fix" IPR, we still have an issue in that we
don't honor the coherent mask properly in case a driver really wants a
different mask.
If we new have two, I think we need to (in the long run that is, for
3.18 we can probably find an ifdef based band-aid):
- Either have a ppc_md hook for set_coherent_mask along with
dma_set_mask and make the decision to flip based on the AND of both
masks (gross)
- Or, since that's basically what some of our HW can do, basically make
the decision on a per-hook basis. That is, something like powernv would
no longer need to hook dma_set_mask to switch the ops. Instead, it could
permanently set a set of pnv_dma_ops that for each hook chose the
"right" mask and route the mapping toward either the iommu or the bypass
accordingly.
Both seem like quite a bit of refactoring and the latter would be tricky
for some pseries cases where we actually *remove* the 32-bit window to
establish the 64-bit one (DDW cases).
Any better idea ? Are there any drivers that don't actually have the
same mask for both that we care about ?
Ben.
@@ -261,6 +261,54 @@ static int __init mark_nonram_nosave(void)return0;}+staticboolzone_limits_final;++staticunsignedlongmax_zone_pfns[MAX_NR_ZONES]={+[0...MAX_NR_ZONES-1]=~0UL+};++/*+*Restrictthespecifiedzoneandallmorerestrictivezones+*tobebelowthespecifiedpfn.Maynotbecalledafter+*paging_init().+*/+void__initlimit_zone_pfn(enumzone_typezone,unsignedlong
pfn_limit) +{
+ int i;
+
+ if (WARN_ON(zone_limits_final))
+ return;
+
+ for (i = zone; i >= 0; i--) {
+ if (max_zone_pfns[i] > pfn_limit)
+ max_zone_pfns[i] = pfn_limit;
+ }
+}
+
+/*
+ * Find the least restrictive zone that is entirely below the
+ * specified pfn limit. Returns < 0 if no suitable zone is found.
+ *
+ * pfn_limit must be u64 because it can exceed 32 bits even on 32-bit
+ * systems -- the DMA limit can be higher than any possible real pfn.
+ */
+int dma_pfn_limit_to_zone(u64 pfn_limit)
+{
+ enum zone_type top_zone = ZONE_NORMAL;
+ int i;
+
+#ifdef CONFIG_HIGHMEM
+ top_zone = ZONE_HIGHMEM;
+#endif
+
+ for (i = top_zone; i >= 0; i--) {
+ if (max_zone_pfns[i] <= pfn_limit)
+ return i;
+ }
+
+ return -EPERM;
+}
+
/*
* paging_init() sets up the page tables - in fact we've already
done this. */
@@ -268,7 +316,7 @@ void __init paging_init(void) { unsigned long long total_ram = memblock_phys_mem_size(); phys_addr_t top_of_ram = memblock_end_of_DRAM();- unsigned long max_zone_pfns[MAX_NR_ZONES];+ enum zone_type top_zone; #ifdef CONFIG_PPC32 unsigned long v = __fix_to_virt(__end_of_fixed_addresses -
From: Michael Ellerman <mpe@ellerman.id.au> Date: 2014-10-13 09:00:50
On Mon, 2014-10-13 at 18:14 +1100, Anton Blanchard wrote:
Hi Scott,
quoted
Platform code can call limit_zone_pfn() to set appropriate limits
for ZONE_DMA and ZONE_DMA32, and dma_direct_alloc_coherent() will
select a suitable zone based on a device's mask and the pfn limits
that platform code has configured.
This patch breaks my POWER8 box:
ipr 0001:08:00.0: Using 64-bit DMA iommu bypass
ipr 0001:08:00.0: dma_direct_alloc_coherent: No suitable zone for pfn 0x10000
ipr 0001:08:00.0: Couldn't allocate enough memory for device driver!
ipr: probe of 0001:08:00.0 failed with error -12
ipr isn't setting a coherent mask, but we shouldn't care on these boxes.
Could we ignore the coherent mask or copy the dma mask to it?
Talking to Ben the answer seems to be "it's complicated".
We shouldn't be ignoring the coherent mask, but we have been, and have been
getting away with it.
The PCI code sets a default 32-bit mask, so we can't even detect when a device
hasn't set it. Though maybe the powernv PCI code could be initialising it to
64-bit ?
For this cycle I'm thinking of the below patch.
Scott & Anton can you test please?
Also the depends on FSL_PCI was totally a guess, so please correct that if it's
wrong Scott.
cheers
[PATCH] powerpc: Only do dynamic DMA zone limits on platforms that need it
Scott's patch 1c98025c6c95 "Dynamic DMA zone limits" changed
dma_direct_alloc_coherent() to start using dev->coherent_dma_mask.
That seems fair enough, but it exposes the fact that some of the drivers
we care about on IBM platforms aren't setting the coherent mask.
The proper fix is to have drivers set the coherent mask and also have
the platform code honor it.
For now, just restrict the dynamic DMA zone limits to the platforms that
need it, which is those using FSL_PCI.
Fixes: 1c98025c6c95 ("powerpc: Dynamic DMA zone limits")
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
---
arch/powerpc/Kconfig | 2 +-
arch/powerpc/kernel/dma.c | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
From: Scott Wood <hidden> Date: 2014-10-14 07:40:43
On Mon, 2014-10-13 at 20:00 +1100, Michael Ellerman wrote:
On Mon, 2014-10-13 at 18:14 +1100, Anton Blanchard wrote:
quoted
Hi Scott,
quoted
Platform code can call limit_zone_pfn() to set appropriate limits
for ZONE_DMA and ZONE_DMA32, and dma_direct_alloc_coherent() will
select a suitable zone based on a device's mask and the pfn limits
that platform code has configured.
This patch breaks my POWER8 box:
ipr 0001:08:00.0: Using 64-bit DMA iommu bypass
ipr 0001:08:00.0: dma_direct_alloc_coherent: No suitable zone for pfn 0x10000
ipr 0001:08:00.0: Couldn't allocate enough memory for device driver!
ipr: probe of 0001:08:00.0 failed with error -12
ipr isn't setting a coherent mask, but we shouldn't care on these boxes.
Could we ignore the coherent mask or copy the dma mask to it?
Talking to Ben the answer seems to be "it's complicated".
We shouldn't be ignoring the coherent mask, but we have been, and have been
getting away with it.
The PCI code sets a default 32-bit mask, so we can't even detect when a device
hasn't set it. Though maybe the powernv PCI code could be initialising it to
64-bit ?
For this cycle I'm thinking of the below patch.
Scott & Anton can you test please?
Also the depends on FSL_PCI was totally a guess, so please correct that if it's
wrong Scott.
We need the DMA zone for non-PCI devices, so FSL_SOC would be a better
choice.
For a short-term workaround, I'd rather leave CONFIG_ZONE_DMA32 where it
is and put #ifdef CONFIG_FSL_SOC (with a comment) around the whole
thing.
-Scott
From: Scott Wood <hidden> Date: 2014-10-14 09:44:47
On Tue, 2014-10-14 at 18:57 +1100, Benjamin Herrenschmidt wrote:
On Tue, 2014-10-14 at 09:39 +0200, Scott Wood wrote:
quoted
For a short-term workaround, I'd rather leave CONFIG_ZONE_DMA32 where
it
is and put #ifdef CONFIG_FSL_SOC (with a comment) around the whole
thing.
I'd like to not enable CONFIG_ZONE_DMA32 when we don't need it, ie,
on !BOOKE 64-bit
How does 64-bit powermac deal with it, with random PCI cards? Does it
use an IOMMU for coherent allocations?
In any case, CONFIG_ZONE_DMA32 should be harmless if the zone isn't
dynamically created, but we can limit it to booke if you want. The
current breakage has nothing to do with ZONE_DMA32, but rather to the
fact that we now check zones at all. This is why I'd rather have the
short term workaround be a new ifdef, rather than moving ifdef
CONFIG_ZONE_DMA32 (moving it also obscures the way the code should look
if and when the workaround can be removed).
-Scott