Skip to content

Commit 7ed2ed2

Browse files
LeoBrasmpe
authored andcommitted
powerpc/pseries/iommu: Add ddw_property_create() and refactor enable_ddw()
Code used to create a ddw property that was previously scattered in enable_ddw() is now gathered in ddw_property_create(), which deals with allocation and filling the property, letting it ready for of_property_add(), which now occurs in sequence. This created an opportunity to reorganize the second part of enable_ddw(): Without this patch enable_ddw() does, in order: kzalloc() property & members, create_ddw(), fill ddwprop inside property, ddw_list_new_entry(), do tce_setrange_multi_pSeriesLP_walk in all memory, of_add_property(), and list_add(). With this patch enable_ddw() does, in order: create_ddw(), ddw_property_create(), of_add_property(), ddw_list_new_entry(), do tce_setrange_multi_pSeriesLP_walk in all memory, and list_add(). This change requires of_remove_property() in case anything fails after of_add_property(), but we get to do tce_setrange_multi_pSeriesLP_walk in all memory, which looks the most expensive operation, only if everything else succeeds. Also, the error path got remove_ddw() replaced by a new helper __remove_dma_window(), which only removes the new DDW with an rtas-call. For this, a new helper clean_dma_window() was needed to clean anything that could left if walk_system_ram_range() fails. Signed-off-by: Leonardo Bras <[email protected]> Reviewed-by: Alexey Kardashevskiy <[email protected]> Signed-off-by: Michael Ellerman <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 2ca73c5 commit 7ed2ed2

File tree

1 file changed

+84
-45
lines changed
  • arch/powerpc/platforms/pseries

1 file changed

+84
-45
lines changed

arch/powerpc/platforms/pseries/iommu.c

Lines changed: 84 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -795,17 +795,10 @@ static int __init disable_ddw_setup(char *str)
795795

796796
early_param("disable_ddw", disable_ddw_setup);
797797

798-
static void remove_dma_window(struct device_node *np, u32 *ddw_avail,
799-
struct property *win)
798+
static void clean_dma_window(struct device_node *np, struct dynamic_dma_window_prop *dwp)
800799
{
801-
struct dynamic_dma_window_prop *dwp;
802-
u64 liobn;
803800
int ret;
804801

805-
dwp = win->value;
806-
liobn = (u64)be32_to_cpu(dwp->liobn);
807-
808-
/* clear the whole window, note the arg is in kernel pages */
809802
ret = tce_clearrange_multi_pSeriesLP(0,
810803
1ULL << (be32_to_cpu(dwp->window_shift) - PAGE_SHIFT), dwp);
811804
if (ret)
@@ -814,18 +807,39 @@ static void remove_dma_window(struct device_node *np, u32 *ddw_avail,
814807
else
815808
pr_debug("%pOF successfully cleared tces in window.\n",
816809
np);
810+
}
811+
812+
/*
813+
* Call only if DMA window is clean.
814+
*/
815+
static void __remove_dma_window(struct device_node *np, u32 *ddw_avail, u64 liobn)
816+
{
817+
int ret;
817818

818819
ret = rtas_call(ddw_avail[DDW_REMOVE_PE_DMA_WIN], 1, 1, NULL, liobn);
819820
if (ret)
820-
pr_warn("%pOF: failed to remove direct window: rtas returned "
821+
pr_warn("%pOF: failed to remove DMA window: rtas returned "
821822
"%d to ibm,remove-pe-dma-window(%x) %llx\n",
822823
np, ret, ddw_avail[DDW_REMOVE_PE_DMA_WIN], liobn);
823824
else
824-
pr_debug("%pOF: successfully removed direct window: rtas returned "
825+
pr_debug("%pOF: successfully removed DMA window: rtas returned "
825826
"%d to ibm,remove-pe-dma-window(%x) %llx\n",
826827
np, ret, ddw_avail[DDW_REMOVE_PE_DMA_WIN], liobn);
827828
}
828829

830+
static void remove_dma_window(struct device_node *np, u32 *ddw_avail,
831+
struct property *win)
832+
{
833+
struct dynamic_dma_window_prop *dwp;
834+
u64 liobn;
835+
836+
dwp = win->value;
837+
liobn = (u64)be32_to_cpu(dwp->liobn);
838+
839+
clean_dma_window(np, dwp);
840+
__remove_dma_window(np, ddw_avail, liobn);
841+
}
842+
829843
static void remove_ddw(struct device_node *np, bool remove_prop)
830844
{
831845
struct property *win;
@@ -1153,6 +1167,35 @@ static int iommu_get_page_shift(u32 query_page_size)
11531167
return 0;
11541168
}
11551169

1170+
static struct property *ddw_property_create(const char *propname, u32 liobn, u64 dma_addr,
1171+
u32 page_shift, u32 window_shift)
1172+
{
1173+
struct dynamic_dma_window_prop *ddwprop;
1174+
struct property *win64;
1175+
1176+
win64 = kzalloc(sizeof(*win64), GFP_KERNEL);
1177+
if (!win64)
1178+
return NULL;
1179+
1180+
win64->name = kstrdup(propname, GFP_KERNEL);
1181+
ddwprop = kzalloc(sizeof(*ddwprop), GFP_KERNEL);
1182+
win64->value = ddwprop;
1183+
win64->length = sizeof(*ddwprop);
1184+
if (!win64->name || !win64->value) {
1185+
kfree(win64->name);
1186+
kfree(win64->value);
1187+
kfree(win64);
1188+
return NULL;
1189+
}
1190+
1191+
ddwprop->liobn = cpu_to_be32(liobn);
1192+
ddwprop->dma_base = cpu_to_be64(dma_addr);
1193+
ddwprop->tce_shift = cpu_to_be32(page_shift);
1194+
ddwprop->window_shift = cpu_to_be32(window_shift);
1195+
1196+
return win64;
1197+
}
1198+
11561199
/*
11571200
* If the PE supports dynamic dma windows, and there is space for a table
11581201
* that can map all pages in a linear offset, then setup such a table,
@@ -1171,12 +1214,12 @@ static bool enable_ddw(struct pci_dev *dev, struct device_node *pdn)
11711214
struct ddw_query_response query;
11721215
struct ddw_create_response create;
11731216
int page_shift;
1217+
u64 win_addr;
11741218
struct device_node *dn;
11751219
u32 ddw_avail[DDW_APPLICABLE_SIZE];
11761220
struct direct_window *window;
11771221
struct property *win64;
11781222
bool ddw_enabled = false;
1179-
struct dynamic_dma_window_prop *ddwprop;
11801223
struct failed_ddw_pdn *fpdn;
11811224
bool default_win_removed = false;
11821225
bool pmem_present;
@@ -1293,72 +1336,68 @@ static bool enable_ddw(struct pci_dev *dev, struct device_node *pdn)
12931336
1ULL << page_shift);
12941337
goto out_failed;
12951338
}
1296-
win64 = kzalloc(sizeof(struct property), GFP_KERNEL);
1297-
if (!win64) {
1298-
dev_info(&dev->dev,
1299-
"couldn't allocate property for 64bit dma window\n");
1300-
goto out_failed;
1301-
}
1302-
win64->name = kstrdup(DIRECT64_PROPNAME, GFP_KERNEL);
1303-
win64->value = ddwprop = kmalloc(sizeof(*ddwprop), GFP_KERNEL);
1304-
win64->length = sizeof(*ddwprop);
1305-
if (!win64->name || !win64->value) {
1306-
dev_info(&dev->dev,
1307-
"couldn't allocate property name and value\n");
1308-
goto out_free_prop;
1309-
}
13101339

13111340
ret = create_ddw(dev, ddw_avail, &create, page_shift, len);
13121341
if (ret != 0)
1313-
goto out_free_prop;
1314-
1315-
ddwprop->liobn = cpu_to_be32(create.liobn);
1316-
ddwprop->dma_base = cpu_to_be64(((u64)create.addr_hi << 32) |
1317-
create.addr_lo);
1318-
ddwprop->tce_shift = cpu_to_be32(page_shift);
1319-
ddwprop->window_shift = cpu_to_be32(len);
1342+
goto out_failed;
13201343

13211344
dev_dbg(&dev->dev, "created tce table LIOBN 0x%x for %pOF\n",
13221345
create.liobn, dn);
13231346

1324-
window = ddw_list_new_entry(pdn, ddwprop);
1347+
win_addr = ((u64)create.addr_hi << 32) | create.addr_lo;
1348+
win64 = ddw_property_create(DIRECT64_PROPNAME, create.liobn, win_addr,
1349+
page_shift, len);
1350+
if (!win64) {
1351+
dev_info(&dev->dev,
1352+
"couldn't allocate property, property name, or value\n");
1353+
goto out_remove_win;
1354+
}
1355+
1356+
ret = of_add_property(pdn, win64);
1357+
if (ret) {
1358+
dev_err(&dev->dev, "unable to add dma window property for %pOF: %d",
1359+
pdn, ret);
1360+
goto out_free_prop;
1361+
}
1362+
1363+
window = ddw_list_new_entry(pdn, win64->value);
13251364
if (!window)
1326-
goto out_clear_window;
1365+
goto out_del_prop;
13271366

13281367
ret = walk_system_ram_range(0, memblock_end_of_DRAM() >> PAGE_SHIFT,
13291368
win64->value, tce_setrange_multi_pSeriesLP_walk);
13301369
if (ret) {
13311370
dev_info(&dev->dev, "failed to map direct window for %pOF: %d\n",
13321371
dn, ret);
1333-
goto out_free_window;
1334-
}
13351372

1336-
ret = of_add_property(pdn, win64);
1337-
if (ret) {
1338-
dev_err(&dev->dev, "unable to add dma window property for %pOF: %d",
1339-
pdn, ret);
1340-
goto out_free_window;
1373+
/* Make sure to clean DDW if any TCE was set*/
1374+
clean_dma_window(pdn, win64->value);
1375+
goto out_del_list;
13411376
}
13421377

13431378
spin_lock(&direct_window_list_lock);
13441379
list_add(&window->list, &direct_window_list);
13451380
spin_unlock(&direct_window_list_lock);
13461381

1347-
dev->dev.archdata.dma_offset = be64_to_cpu(ddwprop->dma_base);
1382+
dev->dev.archdata.dma_offset = win_addr;
13481383
ddw_enabled = true;
13491384
goto out_unlock;
13501385

1351-
out_free_window:
1386+
out_del_list:
13521387
kfree(window);
13531388

1354-
out_clear_window:
1355-
remove_ddw(pdn, true);
1389+
out_del_prop:
1390+
of_remove_property(pdn, win64);
13561391

13571392
out_free_prop:
13581393
kfree(win64->name);
13591394
kfree(win64->value);
13601395
kfree(win64);
13611396

1397+
out_remove_win:
1398+
/* DDW is clean, so it's ok to call this directly. */
1399+
__remove_dma_window(pdn, ddw_avail, create.liobn);
1400+
13621401
out_failed:
13631402
if (default_win_removed)
13641403
reset_dma_window(dev, pdn);

0 commit comments

Comments
 (0)