@@ -47,6 +47,20 @@ extern int rtas_setup_phb(struct pci_controller *phb);
extern unsigned long pci_probe_only;
+/* Dynamic DMA Window support */
+struct ddw_query_response {
+ u32 windows_available;
+ u32 largest_available_block;
+ u32 page_size;
+ u32 migration_capable;
+};
+
+struct ddw_create_response {
+ u32 liobn;
+ u32 addr_hi;
+ u32 addr_lo;
+};
+
/* ---- EEH internal-use-only related routines ---- */
#ifdef CONFIG_EEH
@@ -323,7 +323,7 @@ static int tce_clearrange_multi_pSeriesLP(unsigned long start_pfn,
dma_offset = next + be64_to_cpu(maprange->dma_base);
rc = plpar_tce_stuff((u64)be32_to_cpu(maprange->liobn),
- (u64)dma_offset,
+ dma_offset,
0, limit);
num_tce -= limit;
} while (num_tce > 0 && !rc);
@@ -383,7 +383,7 @@ static int tce_setrange_multi_pSeriesLP(unsigned long start_pfn,
}
rc = plpar_tce_put_indirect(liobn,
- (u64)dma_offset,
+ dma_offset,
(u64)virt_to_abs(tcep),
limit);
@@ -731,7 +731,8 @@ static u64 dupe_ddw_if_kexec(struct pci_dev *dev, struct device_node *pdn)
return dma_addr;
}
-static int query_ddw(struct pci_dev *dev, const u32 *ddr_avail, u32 *query)
+static int query_ddw(struct pci_dev *dev, const u32 *ddr_avail,
+ struct ddw_query_response *query)
{
struct device_node *dn;
struct pci_dn *pcidn;
@@ -751,7 +752,7 @@ static int query_ddw(struct pci_dev *dev, const u32 *ddr_avail, u32 *query)
if (pcidn->eeh_pe_config_addr)
cfg_addr = pcidn->eeh_pe_config_addr;
buid = pcidn->phb->buid;
- ret = rtas_call(ddr_avail[0], 3, 5, query,
+ ret = rtas_call(ddr_avail[0], 3, 5, (u32 *)query,
cfg_addr, BUID_HI(buid), BUID_LO(buid));
dev_info(&dev->dev, "ibm,query-pe-dma-windows(%x) %x %x %x"
" returned %d\n", ddr_avail[0], cfg_addr, BUID_HI(buid),
@@ -759,7 +760,9 @@ static int query_ddw(struct pci_dev *dev, const u32 *ddr_avail, u32 *query)
return ret;
}
-static int create_ddw(struct pci_dev *dev, const u32 *ddr_avail, u32 *create, int page_shift, int window_shift)
+static int create_ddw(struct pci_dev *dev, const u32 *ddr_avail,
+ struct ddw_create_response *create, int page_shift,
+ int window_shift)
{
struct device_node *dn;
struct pci_dn *pcidn;
@@ -782,15 +785,15 @@ static int create_ddw(struct pci_dev *dev, const u32 *ddr_avail, u32 *create, in
do {
/* extra outputs are LIOBN and dma-addr (hi, lo) */
- ret = rtas_call(ddr_avail[1], 5, 4, &create[0], cfg_addr,
+ ret = rtas_call(ddr_avail[1], 5, 4, (u32 *)create, cfg_addr,
BUID_HI(buid), BUID_LO(buid), page_shift, window_shift);
- } while(rtas_busy_delay(ret));
+ } while (rtas_busy_delay(ret));
dev_info(&dev->dev,
"ibm,create-pe-dma-window(%x) %x %x %x %x %x returned %d "
"(liobn = 0x%x starting addr = %x %x)\n", ddr_avail[1],
cfg_addr, BUID_HI(buid), BUID_LO(buid), page_shift,
- window_shift, ret, create[0], create[1], create[2]);
-
+ window_shift, ret, create->liobn, create->addr_hi, create->addr_lo);
+
return ret;
}
@@ -808,7 +811,8 @@ static int create_ddw(struct pci_dev *dev, const u32 *ddr_avail, u32 *create, in
static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn)
{
int len, ret;
- u32 query[4], create[3];
+ struct ddw_query_response query;
+ struct ddw_create_response create;
int page_shift;
u64 dma_addr, max_addr;
struct device_node *dn;
@@ -846,11 +850,11 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn)
* of page sizes: supported and supported for migrate-dma.
*/
dn = pci_device_to_OF_node(dev);
- ret = query_ddw(dev, ddr_avail, &query[0]);
+ ret = query_ddw(dev, ddr_avail, &query);
if (ret != 0)
goto out_unlock;
- if (!query[0]) {
+ if (query.windows_available == 0) {
/*
* no additional windows are available for this device.
* We might be able to reallocate the existing window,
@@ -859,23 +863,23 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn)
dev_dbg(&dev->dev, "no free dynamic windows");
goto out_unlock;
}
- if (query[2] & 4) {
+ if (query.page_size & 4) {
page_shift = 24; /* 16MB */
- } else if (query[2] & 2) {
+ } else if (query.page_size & 2) {
page_shift = 16; /* 64kB */
- } else if (query[2] & 1) {
+ } else if (query.page_size & 1) {
page_shift = 12; /* 4kB */
} else {
dev_dbg(&dev->dev, "no supported direct page size in mask %x",
- query[2]);
+ query.page_size);
goto out_unlock;
}
/* verify the window * number of ptes will map the partition */
/* check largest block * page size > max memory hotplug addr */
max_addr = memory_hotplug_max();
- if (query[1] < (max_addr >> page_shift)) {
+ if (query.largest_available_block < (max_addr >> page_shift)) {
dev_dbg(&dev->dev, "can't map partiton max 0x%llx with %u "
- "%llu-sized pages\n", max_addr, query[1],
+ "%llu-sized pages\n", max_addr, query.largest_available_block,
1ULL << page_shift);
goto out_unlock;
}
@@ -894,19 +898,17 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn)
goto out_free_prop;
}
- ret = create_ddw(dev, ddr_avail, &create[0], page_shift, len);
+ ret = create_ddw(dev, ddr_avail, &create, page_shift, len);
if (ret != 0)
goto out_free_prop;
- *ddwprop = (struct dynamic_dma_window_prop) {
- .liobn = cpu_to_be32(create[0]),
- .dma_base = cpu_to_be64(((u64)create[1] << 32) + (u64)create[2]),
- .tce_shift = cpu_to_be32(page_shift),
- .window_shift = cpu_to_be32(len)
- };
+ ddwprop->liobn = cpu_to_be32(create.liobn);
+ ddwprop->dma_base = cpu_to_be64(of_read_number(&create.addr_hi, 2));
+ ddwprop->tce_shift = cpu_to_be32(page_shift);
+ ddwprop->window_shift = cpu_to_be32(len);
dev_dbg(&dev->dev, "created tce table LIOBN 0x%x for %s\n",
- create[0], dn->full_name);
+ create.liobn, dn->full_name);
window = kzalloc(sizeof(*window), GFP_KERNEL);
if (!window)
@@ -933,7 +935,7 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn)
list_add(&window->list, &direct_window_list);
spin_unlock(&direct_window_list_lock);
- dma_addr = of_read_number(&create[1], 2);
+ dma_addr = of_read_number(&create.addr_hi, 2);
set_dma_offset(&dev->dev, dma_addr);
goto out_unlock;
@@ -1015,7 +1017,7 @@ static int dma_set_mask_pSeriesLP(struct device *dev, u64 dma_mask)
dn = pci_device_to_OF_node(pdev);
dev_dbg(dev, "node is %s\n", dn->full_name);
- /*
+ /*
* the device tree might contain the dma-window properties
* per-device and not neccesarily for the bus. So we need to
* search upwards in the tree until we either hit a dma-window
@@ -1118,7 +1120,15 @@ static int iommu_reconfig_notifier(struct notifier_block *nb, unsigned long acti
}
spin_unlock(&direct_window_list_lock);
- remove_ddw(np);
+ /*
+ * Because the notifier runs after isolation of the
+ * slot, we are guaranteed any DMA window has already
+ * been revoked and the TCEs have been marked invalid,
+ * so we don't need a call to remove_ddw(np). However,
+ * if an additional notifier action is added before the
+ * isolate call, we should update this code for
+ * completeness with such a call.
+ */
break;
default:
err = NOTIFY_DONE;