Lines Matching +full:my +full:- +full:dma +full:- +full:window
1 // SPDX-License-Identifier: GPL-2.0-or-later
23 #include <linux/dma-map-ops.h>
29 #include <asm/dma.h>
47 * vio_cmo_pool - A pool of IO memory for CMO use
64 * vio_cmo_dev_entry - A device that is CMO-enabled and requires entitlement
75 * vio_cmo - VIO bus accounting structure for CMO entitlement
79 * @device_list: list of CMO-enabled devices requiring entitlement
104 * vio_cmo_OF_devices - Count the number of OF devices that have DMA windows
113 * ibm,my-dma-window OF property in vio_cmo_num_OF_devs()
121 prop = of_find_property(of_node, "ibm,my-dma-window", in vio_cmo_num_OF_devs()
132 * vio_cmo_alloc - allocate IO memory for CMO-enable devices
143 * 0 for successful allocation and -ENOMEM for a failure
150 int ret = -ENOMEM; in vio_cmo_alloc()
155 if (viodev->cmo.entitled > viodev->cmo.allocated) in vio_cmo_alloc()
156 reserve_free = viodev->cmo.entitled - viodev->cmo.allocated; in vio_cmo_alloc()
167 viodev->cmo.allocated += size; in vio_cmo_alloc()
168 size -= min(reserve_free, size); in vio_cmo_alloc()
169 vio_cmo.excess.free -= size; in vio_cmo_alloc()
178 * vio_cmo_dealloc - deallocate IO memory from CMO-enable devices
199 vio_cmo.curr -= size; in vio_cmo_dealloc()
202 if (viodev->cmo.allocated > viodev->cmo.entitled) { in vio_cmo_dealloc()
203 excess_freed = min(reserve_freed, (viodev->cmo.allocated - in vio_cmo_dealloc()
204 viodev->cmo.entitled)); in vio_cmo_dealloc()
205 reserve_freed -= excess_freed; in vio_cmo_dealloc()
209 viodev->cmo.allocated -= (reserve_freed + excess_freed); in vio_cmo_dealloc()
212 spare_needed = VIO_CMO_MIN_ENT - vio_cmo.spare; in vio_cmo_dealloc()
220 vio_cmo.excess.size -= tmp; in vio_cmo_dealloc()
223 excess_freed -= tmp; in vio_cmo_dealloc()
224 spare_needed -= tmp; in vio_cmo_dealloc()
235 tmp = min3(spare_needed, reserve_freed, (viodev->cmo.entitled - VIO_CMO_MIN_ENT)); in vio_cmo_dealloc()
238 viodev->cmo.entitled -= tmp; in vio_cmo_dealloc()
239 reserve_freed -= tmp; in vio_cmo_dealloc()
240 spare_needed -= tmp; in vio_cmo_dealloc()
250 tmp = min(excess_freed, (vio_cmo.desired - vio_cmo.reserve.size)); in vio_cmo_dealloc()
252 vio_cmo.excess.size -= tmp; in vio_cmo_dealloc()
254 excess_freed -= tmp; in vio_cmo_dealloc()
268 * vio_cmo_entitlement_update - Manage system entitlement changes
276 * Returns: 0 on success, -ENOMEM when change can not be made
289 delta = new_entitlement - vio_cmo.entitled; in vio_cmo_entitlement_update()
293 tmp = min(delta, (VIO_CMO_MIN_ENT - vio_cmo.spare)); in vio_cmo_entitlement_update()
296 delta -= tmp; in vio_cmo_entitlement_update()
308 delta = vio_cmo.entitled - new_entitlement; in vio_cmo_entitlement_update()
319 viodev = dev_ent->viodev; in vio_cmo_entitlement_update()
320 if ((viodev->cmo.entitled > viodev->cmo.allocated) && in vio_cmo_entitlement_update()
321 (viodev->cmo.entitled > VIO_CMO_MIN_ENT)) in vio_cmo_entitlement_update()
322 avail += viodev->cmo.entitled - in vio_cmo_entitlement_update()
323 max_t(size_t, viodev->cmo.allocated, in vio_cmo_entitlement_update()
328 vio_cmo.entitled -= delta; in vio_cmo_entitlement_update()
332 vio_cmo.excess.size -= tmp; in vio_cmo_entitlement_update()
333 vio_cmo.excess.free -= tmp; in vio_cmo_entitlement_update()
334 delta -= tmp; in vio_cmo_entitlement_update()
344 viodev = dev_ent->viodev; in vio_cmo_entitlement_update()
346 if ((viodev->cmo.entitled > viodev->cmo.allocated) && in vio_cmo_entitlement_update()
347 (viodev->cmo.entitled > VIO_CMO_MIN_ENT)) in vio_cmo_entitlement_update()
348 tmp = viodev->cmo.entitled - in vio_cmo_entitlement_update()
349 max_t(size_t, viodev->cmo.allocated, in vio_cmo_entitlement_update()
351 viodev->cmo.entitled -= min(tmp, delta); in vio_cmo_entitlement_update()
352 delta -= min(tmp, delta); in vio_cmo_entitlement_update()
356 return -ENOMEM; in vio_cmo_entitlement_update()
366 * vio_cmo_balance - Balance entitlement among devices
400 cmo->min = vio_cmo_num_OF_devs() * VIO_CMO_MIN_ENT; in vio_cmo_balance()
401 BUG_ON(cmo->min > cmo->entitled); in vio_cmo_balance()
402 cmo->spare = min_t(size_t, VIO_CMO_MIN_ENT, (cmo->entitled - cmo->min)); in vio_cmo_balance()
403 cmo->min += cmo->spare; in vio_cmo_balance()
404 cmo->desired = cmo->min; in vio_cmo_balance()
410 avail = cmo->entitled - cmo->spare; in vio_cmo_balance()
412 viodev = dev_ent->viodev; in vio_cmo_balance()
414 viodev->cmo.entitled = VIO_CMO_MIN_ENT; in vio_cmo_balance()
415 cmo->desired += (viodev->cmo.desired - VIO_CMO_MIN_ENT); in vio_cmo_balance()
416 avail -= max_t(size_t, viodev->cmo.allocated, VIO_CMO_MIN_ENT); in vio_cmo_balance()
428 viodev = dev_ent->viodev; in vio_cmo_balance()
430 if (viodev->cmo.desired <= level) { in vio_cmo_balance()
441 chunk = min(chunk, (viodev->cmo.desired - in vio_cmo_balance()
442 viodev->cmo.entitled)); in vio_cmo_balance()
443 viodev->cmo.entitled += chunk; in vio_cmo_balance()
450 need = max(viodev->cmo.allocated, viodev->cmo.entitled)- in vio_cmo_balance()
451 max(viodev->cmo.allocated, level); in vio_cmo_balance()
452 avail -= need; in vio_cmo_balance()
461 cmo->reserve.size = cmo->min; in vio_cmo_balance()
462 cmo->excess.free = 0; in vio_cmo_balance()
463 cmo->excess.size = 0; in vio_cmo_balance()
466 viodev = dev_ent->viodev; in vio_cmo_balance()
468 if (viodev->cmo.entitled) in vio_cmo_balance()
469 cmo->reserve.size += (viodev->cmo.entitled - in vio_cmo_balance()
472 if (viodev->cmo.allocated > viodev->cmo.entitled) in vio_cmo_balance()
473 need += viodev->cmo.allocated - viodev->cmo.entitled; in vio_cmo_balance()
475 cmo->excess.size = cmo->entitled - cmo->reserve.size; in vio_cmo_balance()
476 cmo->excess.free = cmo->excess.size - need; in vio_cmo_balance()
490 atomic_inc(&viodev->cmo.allocs_failed); in vio_dma_iommu_alloc_coherent()
495 dma_handle, dev->coherent_dma_mask, flag, in vio_dma_iommu_alloc_coherent()
499 atomic_inc(&viodev->cmo.allocs_failed); in vio_dma_iommu_alloc_coherent()
535 atomic_inc(&viodev->cmo.allocs_failed); in vio_dma_iommu_map_page()
562 alloc_size += roundup(sgl->length, IOMMU_PAGE_SIZE(tbl)); in vio_dma_iommu_map_sg()
573 alloc_size -= roundup(sgl->dma_length, IOMMU_PAGE_SIZE(tbl)); in vio_dma_iommu_map_sg()
581 atomic_inc(&viodev->cmo.allocs_failed); in vio_dma_iommu_map_sg()
597 alloc_size += roundup(sgl->dma_length, IOMMU_PAGE_SIZE(tbl)); in vio_dma_iommu_unmap_sg()
619 * vio_cmo_set_dev_desired - Set desired entitlement for a device
647 if (viodev == dev_ent->viodev) { in vio_cmo_set_dev_desired()
657 if (desired >= viodev->cmo.desired) { in vio_cmo_set_dev_desired()
659 vio_cmo.desired += desired - viodev->cmo.desired; in vio_cmo_set_dev_desired()
660 viodev->cmo.desired = desired; in vio_cmo_set_dev_desired()
663 vio_cmo.desired -= viodev->cmo.desired - desired; in vio_cmo_set_dev_desired()
664 viodev->cmo.desired = desired; in vio_cmo_set_dev_desired()
669 if (viodev->cmo.entitled > desired) { in vio_cmo_set_dev_desired()
670 vio_cmo.reserve.size -= viodev->cmo.entitled - desired; in vio_cmo_set_dev_desired()
671 vio_cmo.excess.size += viodev->cmo.entitled - desired; in vio_cmo_set_dev_desired()
677 if (viodev->cmo.allocated < viodev->cmo.entitled) in vio_cmo_set_dev_desired()
678 vio_cmo.excess.free += viodev->cmo.entitled - in vio_cmo_set_dev_desired()
679 max(viodev->cmo.allocated, desired); in vio_cmo_set_dev_desired()
680 viodev->cmo.entitled = desired; in vio_cmo_set_dev_desired()
688 * vio_cmo_bus_probe - Handle CMO specific bus probe activities
690 * @viodev - Pointer to struct vio_dev for device
696 * Returns: 0 on success, -EINVAL when device doesn't support CMO, and
697 * -ENOMEM when entitlement is not available for device or
704 struct device *dev = &viodev->dev; in vio_cmo_bus_probe()
706 struct vio_driver *viodrv = to_vio_driver(dev->driver); in vio_cmo_bus_probe()
713 /* A device requires entitlement if it has a DMA window property */ in vio_cmo_bus_probe()
714 switch (viodev->family) { in vio_cmo_bus_probe()
716 if (of_get_property(viodev->dev.of_node, in vio_cmo_bus_probe()
717 "ibm,my-dma-window", NULL)) in vio_cmo_bus_probe()
724 dev_warn(dev, "unknown device family: %d\n", viodev->family); in vio_cmo_bus_probe()
731 /* Check that the driver is CMO enabled and get desired DMA */ in vio_cmo_bus_probe()
732 if (!viodrv->get_desired_dma) { in vio_cmo_bus_probe()
735 return -EINVAL; in vio_cmo_bus_probe()
738 viodev->cmo.desired = in vio_cmo_bus_probe()
739 IOMMU_PAGE_ALIGN(viodrv->get_desired_dma(viodev), tbl); in vio_cmo_bus_probe()
740 if (viodev->cmo.desired < VIO_CMO_MIN_ENT) in vio_cmo_bus_probe()
741 viodev->cmo.desired = VIO_CMO_MIN_ENT; in vio_cmo_bus_probe()
747 return -ENOMEM; in vio_cmo_bus_probe()
749 dev_ent->viodev = viodev; in vio_cmo_bus_probe()
751 list_add(&dev_ent->list, &vio_cmo.device_list); in vio_cmo_bus_probe()
753 viodev->cmo.desired = 0; in vio_cmo_bus_probe()
768 vio_cmo.desired += (viodev->cmo.desired - in vio_cmo_bus_probe()
780 return -ENOMEM; in vio_cmo_bus_probe()
785 vio_cmo.excess.free -= tmp; in vio_cmo_bus_probe()
786 vio_cmo.excess.size -= tmp; in vio_cmo_bus_probe()
790 vio_cmo.spare -= size - tmp; in vio_cmo_bus_probe()
794 vio_cmo.desired += viodev->cmo.desired; in vio_cmo_bus_probe()
801 * vio_cmo_bus_remove - Handle CMO specific bus removal activities
803 * @viodev - Pointer to struct vio_dev for device
817 if (viodev->cmo.allocated) { in vio_cmo_bus_remove()
818 dev_err(&viodev->dev, "%s: device had %lu bytes of IO " in vio_cmo_bus_remove()
820 __func__, viodev->cmo.allocated); in vio_cmo_bus_remove()
829 if (viodev == dev_ent->viodev) { in vio_cmo_bus_remove()
830 list_del(&dev_ent->list); in vio_cmo_bus_remove()
840 if (viodev->cmo.entitled) { in vio_cmo_bus_remove()
846 vio_cmo.desired -= (viodev->cmo.desired - VIO_CMO_MIN_ENT); in vio_cmo_bus_remove()
853 viodev->cmo.entitled -= VIO_CMO_MIN_ENT; in vio_cmo_bus_remove()
856 if (viodev->cmo.entitled && (vio_cmo.spare < VIO_CMO_MIN_ENT)) { in vio_cmo_bus_remove()
857 tmp = min(viodev->cmo.entitled, (VIO_CMO_MIN_ENT - in vio_cmo_bus_remove()
860 viodev->cmo.entitled -= tmp; in vio_cmo_bus_remove()
864 vio_cmo.excess.size += viodev->cmo.entitled; in vio_cmo_bus_remove()
865 vio_cmo.excess.free += viodev->cmo.entitled; in vio_cmo_bus_remove()
866 vio_cmo.reserve.size -= viodev->cmo.entitled; in vio_cmo_bus_remove()
873 viodev->cmo.entitled = VIO_CMO_MIN_ENT; in vio_cmo_bus_remove()
874 viodev->cmo.desired = VIO_CMO_MIN_ENT; in vio_cmo_bus_remove()
875 atomic_set(&viodev->cmo.allocs_failed, 0); in vio_cmo_bus_remove()
883 set_dma_ops(&viodev->dev, &vio_dma_mapping_ops); in vio_cmo_set_dma_ops()
887 * vio_cmo_bus_init - CMO entitlement initialization at bus init time
930 vio_cmo.excess.size = vio_cmo.entitled - vio_cmo.reserve.size; in vio_cmo_bus_init()
943 return sprintf(buf, "%lu\n", to_vio_dev(dev)->cmo.name); \
950 return sprintf(buf, "%d\n", atomic_read(&viodev->cmo.allocs_failed)); in cmo_allocs_failed_show()
957 atomic_set(&viodev->cmo.allocs_failed, 0); in cmo_allocs_failed_store()
1072 * vio_h_cop_sync - Perform a synchronous PFO co-processor operation
1074 * @vdev - Pointer to a struct vio_dev for device
1075 * @op - Pointer to a struct vio_pfo_op for the operation parameters
1079 * the operation will be re-submitted indefinitely unless a non-zero timeout
1081 * stop re-submitting a operation, the total time can be exceeded if an
1084 * If op->hcall_ret is not NULL, this will be set to the return from the
1090 * -EINVAL if the h_call fails due to an invalid parameter,
1091 * -E2BIG if the h_call can not be performed synchronously,
1092 * -EBUSY if a timeout is specified and has elapsed,
1093 * -EACCES if the memory area for data/status has been rescinded, or
1094 * -EPERM if a hardware fault has been indicated
1098 struct device *dev = &vdev->dev; in vio_h_cop_sync()
1103 if (op->timeout) in vio_h_cop_sync()
1104 deadline = jiffies + msecs_to_jiffies(op->timeout); in vio_h_cop_sync()
1107 hret = plpar_hcall_norets(H_COP, op->flags, in vio_h_cop_sync()
1108 vdev->resource_id, in vio_h_cop_sync()
1109 op->in, op->inlen, op->out, in vio_h_cop_sync()
1110 op->outlen, op->csbcpb); in vio_h_cop_sync()
1115 (op->timeout && time_after(deadline, jiffies))) in vio_h_cop_sync()
1127 ret = -E2BIG; in vio_h_cop_sync()
1130 ret = -EACCES; in vio_h_cop_sync()
1133 ret = -EPERM; in vio_h_cop_sync()
1138 ret = -EBUSY; in vio_h_cop_sync()
1141 ret = -EINVAL; in vio_h_cop_sync()
1149 op->hcall_err = hret; in vio_h_cop_sync()
1160 dma_window = of_get_property(dev->dev.of_node, in vio_build_iommu_table()
1161 "ibm,my-dma-window", NULL); in vio_build_iommu_table()
1169 kref_init(&tbl->it_kref); in vio_build_iommu_table()
1171 of_parse_dma_window(dev->dev.of_node, dma_window, in vio_build_iommu_table()
1172 &tbl->it_index, &offset, &size); in vio_build_iommu_table()
1174 /* TCE table size - measured in tce entries */ in vio_build_iommu_table()
1175 tbl->it_page_shift = IOMMU_PAGE_SHIFT_4K; in vio_build_iommu_table()
1176 tbl->it_size = size >> tbl->it_page_shift; in vio_build_iommu_table()
1178 tbl->it_offset = offset >> tbl->it_page_shift; in vio_build_iommu_table()
1179 tbl->it_busno = 0; in vio_build_iommu_table()
1180 tbl->it_type = TCE_VB; in vio_build_iommu_table()
1181 tbl->it_blocksize = 16; in vio_build_iommu_table()
1184 tbl->it_ops = &iommu_table_lpar_multi_ops; in vio_build_iommu_table()
1186 tbl->it_ops = &iommu_table_pseries_ops; in vio_build_iommu_table()
1188 return iommu_init_table(tbl, -1, 0, 0); in vio_build_iommu_table()
1192 * vio_match_device: - Tell if a VIO device has a matching
1204 while (ids->type[0] != '\0') { in vio_match_device()
1205 if ((strncmp(dev->type, ids->type, strlen(ids->type)) == 0) && in vio_match_device()
1206 of_device_is_compatible(dev->dev.of_node, in vio_match_device()
1207 ids->compat)) in vio_match_device()
1216 * dev->driver has already been set by generic code because vio_bus_match
1222 struct vio_driver *viodrv = to_vio_driver(dev->driver); in vio_bus_probe()
1224 int error = -ENODEV; in vio_bus_probe()
1226 if (!viodrv->probe) in vio_bus_probe()
1229 id = vio_match_device(viodrv->id_table, viodev); in vio_bus_probe()
1231 memset(&viodev->cmo, 0, sizeof(viodev->cmo)); in vio_bus_probe()
1237 error = viodrv->probe(viodev, id); in vio_bus_probe()
1249 struct vio_driver *viodrv = to_vio_driver(dev->driver); in vio_bus_remove()
1258 if (viodrv->remove) in vio_bus_remove()
1259 viodrv->remove(viodev); in vio_bus_remove()
1272 if (dev->driver) { in vio_bus_shutdown()
1273 viodrv = to_vio_driver(dev->driver); in vio_bus_shutdown()
1274 if (viodrv->shutdown) in vio_bus_shutdown()
1275 viodrv->shutdown(viodev); in vio_bus_shutdown()
1282 * vio_register_driver: - Register a new vio driver
1290 return -ENODEV; in __vio_register_driver()
1292 pr_debug("%s: driver %s registering\n", __func__, viodrv->name); in __vio_register_driver()
1295 viodrv->driver.name = viodrv->name; in __vio_register_driver()
1296 viodrv->driver.pm = viodrv->pm; in __vio_register_driver()
1297 viodrv->driver.bus = &vio_bus_type; in __vio_register_driver()
1298 viodrv->driver.owner = owner; in __vio_register_driver()
1299 viodrv->driver.mod_name = mod_name; in __vio_register_driver()
1301 return driver_register(&viodrv->driver); in __vio_register_driver()
1306 * vio_unregister_driver - Remove registration of vio driver.
1311 driver_unregister(&viodrv->driver); in vio_unregister_driver()
1322 of_node_put(dev->of_node); in vio_dev_release()
1327 * vio_register_device_node: - Register a new vio device.
1344 * /ibm,platform-facilities node. This decides the device's family. in vio_register_device_node()
1348 if (of_node_is_type(parent_node, "ibm,platform-facilities")) in vio_register_device_node()
1368 if (of_property_read_bool(of_node, "interrupt-controller")) { in vio_register_device_node()
1383 viodev->family = family; in vio_register_device_node()
1384 if (viodev->family == VDEVICE) { in vio_register_device_node()
1387 viodev->type = of_node_get_device_type(of_node); in vio_register_device_node()
1388 if (!viodev->type) { in vio_register_device_node()
1401 dev_set_name(&viodev->dev, "%x", unit_address); in vio_register_device_node()
1402 viodev->irq = irq_of_parse_and_map(of_node, 0); in vio_register_device_node()
1403 viodev->unit_address = unit_address; in vio_register_device_node()
1408 prop = of_get_property(of_node, "ibm,resource-id", NULL); in vio_register_device_node()
1410 viodev->resource_id = of_read_number(prop, 1); in vio_register_device_node()
1412 dev_set_name(&viodev->dev, "%pOFn", of_node); in vio_register_device_node()
1413 viodev->type = dev_name(&viodev->dev); in vio_register_device_node()
1414 viodev->irq = 0; in vio_register_device_node()
1417 viodev->name = of_node->name; in vio_register_device_node()
1418 viodev->dev.of_node = of_node_get(of_node); in vio_register_device_node()
1420 set_dev_node(&viodev->dev, of_node_to_nid(of_node)); in vio_register_device_node()
1423 viodev->dev.parent = &vio_bus_device.dev; in vio_register_device_node()
1424 viodev->dev.bus = &vio_bus_type; in vio_register_device_node()
1425 viodev->dev.release = vio_dev_release; in vio_register_device_node()
1427 if (of_property_present(viodev->dev.of_node, "ibm,my-dma-window")) { in vio_register_device_node()
1431 set_dma_ops(&viodev->dev, &dma_iommu_ops); in vio_register_device_node()
1433 set_iommu_table_base(&viodev->dev, in vio_register_device_node()
1438 viodev->dev.coherent_dma_mask = DMA_BIT_MASK(64); in vio_register_device_node()
1439 viodev->dev.dma_mask = &viodev->dev.coherent_dma_mask; in vio_register_device_node()
1443 if (device_register(&viodev->dev)) { in vio_register_device_node()
1445 __func__, dev_name(&viodev->dev)); in vio_register_device_node()
1446 put_device(&viodev->dev); in vio_register_device_node()
1460 * vio_bus_scan_for_devices - Scan OF and register each child device
1461 * @root_name - OF node name for the root of the subtree to search.
1462 * This must be non-NULL
1491 * vio_bus_init: - Initialize the virtual IO bus
1527 vio_bus_scan_register_devices("ibm,platform-facilities"); in vio_device_init()
1536 return sprintf(buf, "%s\n", to_vio_dev(dev)->name); in name_show()
1543 struct device_node *of_node = dev->of_node; in devspec_show()
1556 dn = dev->of_node; in modalias_show()
1567 return sprintf(buf, "vio:T%sS%s\n", vio_dev->type, cp); in modalias_show()
1573 device_unregister(&viodev->dev); in vio_unregister_device()
1574 if (viodev->family == VDEVICE) in vio_unregister_device()
1575 irq_dispose_mapping(viodev->irq); in vio_unregister_device()
1583 const struct vio_device_id *ids = vio_drv->id_table; in vio_bus_match()
1594 dn = dev->of_node; in vio_hotplug()
1596 add_uevent_var(env, "MODALIAS=vio:T%sS%s", vio_dev->type, cp); in vio_hotplug()
1645 * vio_get_attribute: - get attribute for virtual device
1655 return of_get_property(vdev->dev.of_node, which, length); in vio_get_attribute()
1659 /* vio_find_name() - internal because only vio.c knows how we formatted the
1674 * vio_find_node - find an already-registered vio_dev
1698 } else if (of_node_is_type(vnode_parent, "ibm,platform-facilities")) in vio_find_node()
1713 int rc = h_vio_signal(dev->unit_address, VIO_IRQ_ENABLE); in vio_enable_interrupts()
1722 int rc = h_vio_signal(dev->unit_address, VIO_IRQ_DISABLE); in vio_disable_interrupts()