mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-05 18:39:59 +00:00
Revert "powerpc/pseries/iommu: remove default window before attempting DDW manipulation"
Ben rightfully pointed out that there is a race in the "newer" DDW code.
Presuming we are running on recent enough firmware that supports the
"reset" DDW manipulation call, we currently always remove the base
32-bit DMA window in order to maximize the resources for Phyp when
creating the 64-bit window. However, this can be problematic for the
case where multiple functions are in the same PE (partitionable
endpoint), where some funtions might be 32-bit DMA only. All of a
sudden, the only functional DMA window for such functions is gone. We
will have serious errors in such situations. The best solution is simply
to revert the extension to the DDW code where we ever remove the base
DMA window.
This reverts commit 25ebc45b93
.
Signed-off-by: Nishanth Aravamudan <nacc@linux.vnet.ibm.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
This commit is contained in:
parent
c141611fb1
commit
ae69e1eddc
1 changed files with 17 additions and 69 deletions
|
@ -721,21 +721,6 @@ static int __init disable_ddw_setup(char *str)
|
|||
|
||||
early_param("disable_ddw", disable_ddw_setup);
|
||||
|
||||
static inline void __remove_ddw(struct device_node *np, const u32 *ddw_avail, u64 liobn)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = rtas_call(ddw_avail[2], 1, 1, NULL, liobn);
|
||||
if (ret)
|
||||
pr_warning("%s: failed to remove DMA window: rtas returned "
|
||||
"%d to ibm,remove-pe-dma-window(%x) %llx\n",
|
||||
np->full_name, ret, ddw_avail[2], liobn);
|
||||
else
|
||||
pr_debug("%s: successfully removed DMA window: rtas returned "
|
||||
"%d to ibm,remove-pe-dma-window(%x) %llx\n",
|
||||
np->full_name, ret, ddw_avail[2], liobn);
|
||||
}
|
||||
|
||||
static void remove_ddw(struct device_node *np)
|
||||
{
|
||||
struct dynamic_dma_window_prop *dwp;
|
||||
|
@ -765,7 +750,15 @@ static void remove_ddw(struct device_node *np)
|
|||
pr_debug("%s successfully cleared tces in window.\n",
|
||||
np->full_name);
|
||||
|
||||
__remove_ddw(np, ddw_avail, liobn);
|
||||
ret = rtas_call(ddw_avail[2], 1, 1, NULL, liobn);
|
||||
if (ret)
|
||||
pr_warning("%s: failed to remove direct window: rtas returned "
|
||||
"%d to ibm,remove-pe-dma-window(%x) %llx\n",
|
||||
np->full_name, ret, ddw_avail[2], liobn);
|
||||
else
|
||||
pr_debug("%s: successfully removed direct window: rtas returned "
|
||||
"%d to ibm,remove-pe-dma-window(%x) %llx\n",
|
||||
np->full_name, ret, ddw_avail[2], liobn);
|
||||
|
||||
delprop:
|
||||
ret = of_remove_property(np, win64);
|
||||
|
@ -925,12 +918,6 @@ static int create_ddw(struct pci_dev *dev, const u32 *ddw_avail,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void restore_default_window(struct pci_dev *dev,
|
||||
u32 ddw_restore_token)
|
||||
{
|
||||
__restore_default_window(pci_dev_to_eeh_dev(dev), ddw_restore_token);
|
||||
}
|
||||
|
||||
struct failed_ddw_pdn {
|
||||
struct device_node *pdn;
|
||||
struct list_head list;
|
||||
|
@ -958,13 +945,9 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn)
|
|||
u64 dma_addr, max_addr;
|
||||
struct device_node *dn;
|
||||
const u32 *uninitialized_var(ddw_avail);
|
||||
const u32 *uninitialized_var(ddw_extensions);
|
||||
u32 ddw_restore_token = 0;
|
||||
struct direct_window *window;
|
||||
struct property *win64;
|
||||
struct dynamic_dma_window_prop *ddwprop;
|
||||
const void *dma_window = NULL;
|
||||
unsigned long liobn, offset, size;
|
||||
struct failed_ddw_pdn *fpdn;
|
||||
|
||||
mutex_lock(&direct_window_init_mutex);
|
||||
|
@ -995,40 +978,7 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn)
|
|||
*/
|
||||
ddw_avail = of_get_property(pdn, "ibm,ddw-applicable", &len);
|
||||
if (!ddw_avail || len < 3 * sizeof(u32))
|
||||
goto out_unlock;
|
||||
|
||||
/*
|
||||
* the extensions property is only required to exist in certain
|
||||
* levels of firmware and later
|
||||
* the ibm,ddw-extensions property is a list with the first
|
||||
* element containing the number of extensions and each
|
||||
* subsequent entry is a value corresponding to that extension
|
||||
*/
|
||||
ddw_extensions = of_get_property(pdn, "ibm,ddw-extensions", &len);
|
||||
if (ddw_extensions) {
|
||||
/*
|
||||
* each new defined extension length should be added to
|
||||
* the top of the switch so the "earlier" entries also
|
||||
* get picked up
|
||||
*/
|
||||
switch (ddw_extensions[0]) {
|
||||
/* ibm,reset-pe-dma-windows */
|
||||
case 1:
|
||||
ddw_restore_token = ddw_extensions[1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Only remove the existing DMA window if we can restore back to
|
||||
* the default state. Removing the existing window maximizes the
|
||||
* resources available to firmware for dynamic window creation.
|
||||
*/
|
||||
if (ddw_restore_token) {
|
||||
dma_window = of_get_property(pdn, "ibm,dma-window", NULL);
|
||||
of_parse_dma_window(pdn, dma_window, &liobn, &offset, &size);
|
||||
__remove_ddw(pdn, ddw_avail, liobn);
|
||||
}
|
||||
goto out_failed;
|
||||
|
||||
/*
|
||||
* Query if there is a second window of size to map the
|
||||
|
@ -1039,7 +989,7 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn)
|
|||
dn = pci_device_to_OF_node(dev);
|
||||
ret = query_ddw(dev, ddw_avail, &query);
|
||||
if (ret != 0)
|
||||
goto out_restore_window;
|
||||
goto out_failed;
|
||||
|
||||
if (query.windows_available == 0) {
|
||||
/*
|
||||
|
@ -1048,7 +998,7 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn)
|
|||
* trading in for a larger page size.
|
||||
*/
|
||||
dev_dbg(&dev->dev, "no free dynamic windows");
|
||||
goto out_restore_window;
|
||||
goto out_failed;
|
||||
}
|
||||
if (be32_to_cpu(query.page_size) & 4) {
|
||||
page_shift = 24; /* 16MB */
|
||||
|
@ -1059,7 +1009,7 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn)
|
|||
} else {
|
||||
dev_dbg(&dev->dev, "no supported direct page size in mask %x",
|
||||
query.page_size);
|
||||
goto out_restore_window;
|
||||
goto out_failed;
|
||||
}
|
||||
/* verify the window * number of ptes will map the partition */
|
||||
/* check largest block * page size > max memory hotplug addr */
|
||||
|
@ -1068,14 +1018,14 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn)
|
|||
dev_dbg(&dev->dev, "can't map partiton max 0x%llx with %u "
|
||||
"%llu-sized pages\n", max_addr, query.largest_available_block,
|
||||
1ULL << page_shift);
|
||||
goto out_restore_window;
|
||||
goto out_failed;
|
||||
}
|
||||
len = order_base_2(max_addr);
|
||||
win64 = kzalloc(sizeof(struct property), GFP_KERNEL);
|
||||
if (!win64) {
|
||||
dev_info(&dev->dev,
|
||||
"couldn't allocate property for 64bit dma window\n");
|
||||
goto out_restore_window;
|
||||
goto out_failed;
|
||||
}
|
||||
win64->name = kstrdup(DIRECT64_PROPNAME, GFP_KERNEL);
|
||||
win64->value = ddwprop = kmalloc(sizeof(*ddwprop), GFP_KERNEL);
|
||||
|
@ -1137,9 +1087,7 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn)
|
|||
kfree(win64->value);
|
||||
kfree(win64);
|
||||
|
||||
out_restore_window:
|
||||
if (ddw_restore_token)
|
||||
restore_default_window(dev, ddw_restore_token);
|
||||
out_failed:
|
||||
|
||||
fpdn = kzalloc(sizeof(*fpdn), GFP_KERNEL);
|
||||
if (!fpdn)
|
||||
|
|
Loading…
Reference in a new issue