Skip to content

Commit c4faf62

Browse files
aikgregkh
authored andcommitted
powerpc/pseries: Allow not having ibm, hypertas-functions::hcall-multi-tce for DDW
commit 7559d3d upstream. By default a pseries guest supports a H_PUT_TCE hypercall which maps a single IOMMU page in a DMA window. Additionally the hypervisor may support H_PUT_TCE_INDIRECT/H_STUFF_TCE which update multiple TCEs at once; this is advertised via the device tree /rtas/ibm,hypertas-functions property which Linux converts to FW_FEATURE_MULTITCE. FW_FEATURE_MULTITCE is checked when dma_iommu_ops is used; however the code managing the huge DMA window (DDW) ignores it and calls H_PUT_TCE_INDIRECT even if it is explicitly disabled via the "multitce=off" kernel command line parameter. This adds FW_FEATURE_MULTITCE checking to the DDW code path. This changes tce_build_pSeriesLP to take liobn and page size as the huge window does not have iommu_table descriptor which usually the place to store these numbers. Fixes: 4e8b0cf ("powerpc/pseries: Add support for dynamic dma windows") Signed-off-by: Alexey Kardashevskiy <[email protected]> Reviewed-by: Thiago Jung Bauermann <[email protected]> Tested-by: Thiago Jung Bauermann <[email protected]> Signed-off-by: Michael Ellerman <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent cff30ed commit c4faf62

File tree

1 file changed

+29
-14
lines changed
  • arch/powerpc/platforms/pseries

1 file changed

+29
-14
lines changed

arch/powerpc/platforms/pseries/iommu.c

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -132,10 +132,10 @@ static unsigned long tce_get_pseries(struct iommu_table *tbl, long index)
132132
return be64_to_cpu(*tcep);
133133
}
134134

135-
static void tce_free_pSeriesLP(struct iommu_table*, long, long);
135+
static void tce_free_pSeriesLP(unsigned long liobn, long, long);
136136
static void tce_freemulti_pSeriesLP(struct iommu_table*, long, long);
137137

138-
static int tce_build_pSeriesLP(struct iommu_table *tbl, long tcenum,
138+
static int tce_build_pSeriesLP(unsigned long liobn, long tcenum, long tceshift,
139139
long npages, unsigned long uaddr,
140140
enum dma_data_direction direction,
141141
unsigned long attrs)
@@ -146,25 +146,25 @@ static int tce_build_pSeriesLP(struct iommu_table *tbl, long tcenum,
146146
int ret = 0;
147147
long tcenum_start = tcenum, npages_start = npages;
148148

149-
rpn = __pa(uaddr) >> TCE_SHIFT;
149+
rpn = __pa(uaddr) >> tceshift;
150150
proto_tce = TCE_PCI_READ;
151151
if (direction != DMA_TO_DEVICE)
152152
proto_tce |= TCE_PCI_WRITE;
153153

154154
while (npages--) {
155-
tce = proto_tce | (rpn & TCE_RPN_MASK) << TCE_RPN_SHIFT;
156-
rc = plpar_tce_put((u64)tbl->it_index, (u64)tcenum << 12, tce);
155+
tce = proto_tce | (rpn & TCE_RPN_MASK) << tceshift;
156+
rc = plpar_tce_put((u64)liobn, (u64)tcenum << tceshift, tce);
157157

158158
if (unlikely(rc == H_NOT_ENOUGH_RESOURCES)) {
159159
ret = (int)rc;
160-
tce_free_pSeriesLP(tbl, tcenum_start,
160+
tce_free_pSeriesLP(liobn, tcenum_start,
161161
(npages_start - (npages + 1)));
162162
break;
163163
}
164164

165165
if (rc && printk_ratelimit()) {
166166
printk("tce_build_pSeriesLP: plpar_tce_put failed. rc=%lld\n", rc);
167-
printk("\tindex = 0x%llx\n", (u64)tbl->it_index);
167+
printk("\tindex = 0x%llx\n", (u64)liobn);
168168
printk("\ttcenum = 0x%llx\n", (u64)tcenum);
169169
printk("\ttce val = 0x%llx\n", tce );
170170
dump_stack();
@@ -193,7 +193,8 @@ static int tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum,
193193
unsigned long flags;
194194

195195
if ((npages == 1) || !firmware_has_feature(FW_FEATURE_MULTITCE)) {
196-
return tce_build_pSeriesLP(tbl, tcenum, npages, uaddr,
196+
return tce_build_pSeriesLP(tbl->it_index, tcenum,
197+
tbl->it_page_shift, npages, uaddr,
197198
direction, attrs);
198199
}
199200

@@ -209,8 +210,9 @@ static int tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum,
209210
/* If allocation fails, fall back to the loop implementation */
210211
if (!tcep) {
211212
local_irq_restore(flags);
212-
return tce_build_pSeriesLP(tbl, tcenum, npages, uaddr,
213-
direction, attrs);
213+
return tce_build_pSeriesLP(tbl->it_index, tcenum,
214+
tbl->it_page_shift,
215+
npages, uaddr, direction, attrs);
214216
}
215217
__this_cpu_write(tce_page, tcep);
216218
}
@@ -261,16 +263,16 @@ static int tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum,
261263
return ret;
262264
}
263265

264-
static void tce_free_pSeriesLP(struct iommu_table *tbl, long tcenum, long npages)
266+
static void tce_free_pSeriesLP(unsigned long liobn, long tcenum, long npages)
265267
{
266268
u64 rc;
267269

268270
while (npages--) {
269-
rc = plpar_tce_put((u64)tbl->it_index, (u64)tcenum << 12, 0);
271+
rc = plpar_tce_put((u64)liobn, (u64)tcenum << 12, 0);
270272

271273
if (rc && printk_ratelimit()) {
272274
printk("tce_free_pSeriesLP: plpar_tce_put failed. rc=%lld\n", rc);
273-
printk("\tindex = 0x%llx\n", (u64)tbl->it_index);
275+
printk("\tindex = 0x%llx\n", (u64)liobn);
274276
printk("\ttcenum = 0x%llx\n", (u64)tcenum);
275277
dump_stack();
276278
}
@@ -285,7 +287,7 @@ static void tce_freemulti_pSeriesLP(struct iommu_table *tbl, long tcenum, long n
285287
u64 rc;
286288

287289
if (!firmware_has_feature(FW_FEATURE_MULTITCE))
288-
return tce_free_pSeriesLP(tbl, tcenum, npages);
290+
return tce_free_pSeriesLP(tbl->it_index, tcenum, npages);
289291

290292
rc = plpar_tce_stuff((u64)tbl->it_index, (u64)tcenum << 12, 0, npages);
291293

@@ -400,6 +402,19 @@ static int tce_setrange_multi_pSeriesLP(unsigned long start_pfn,
400402
u64 rc = 0;
401403
long l, limit;
402404

405+
if (!firmware_has_feature(FW_FEATURE_MULTITCE)) {
406+
unsigned long tceshift = be32_to_cpu(maprange->tce_shift);
407+
unsigned long dmastart = (start_pfn << PAGE_SHIFT) +
408+
be64_to_cpu(maprange->dma_base);
409+
unsigned long tcenum = dmastart >> tceshift;
410+
unsigned long npages = num_pfn << PAGE_SHIFT >> tceshift;
411+
void *uaddr = __va(start_pfn << PAGE_SHIFT);
412+
413+
return tce_build_pSeriesLP(be32_to_cpu(maprange->liobn),
414+
tcenum, tceshift, npages, (unsigned long) uaddr,
415+
DMA_BIDIRECTIONAL, 0);
416+
}
417+
403418
local_irq_disable(); /* to protect tcep and the page behind it */
404419
tcep = __this_cpu_read(tce_page);
405420

0 commit comments

Comments
 (0)