Keep the physical address allocation that hmm_add_device does with the rest of the resource code, and allow future reuse of it without the hmm wrapper.
Unified · Split
| @@ -285,6 +285,8 @@ static inline bool resource_overlaps(struct resource *r1, struct resource *r2) · 284 unmodified lines | |||
| 285 | return (r1->start <= r2->end && r1->end >= r2->start); | 285 | return (r1->start <= r2->end && r1->end >= r2->start); |
| 286 | } | 286 | } |
| 287 | 287 | ||
| 288 | struct resource *devm_request_free_mem_region(struct device *dev, | ||
| 289 | struct resource *base, unsigned long size); | ||
| 288 | 290 | ||
| 289 | #endif /* __ASSEMBLY__ */ | 291 | #endif /* __ASSEMBLY__ */ |
| 290 | #endif /* _LINUX_IOPORT_H */ | 292 | #endif /* _LINUX_IOPORT_H */ |
| @@ -1628,6 +1628,45 @@ void resource_list_free(struct list_head *head) · 1627 unmodified lines | |||
| 1628 | } | 1628 | } |
| 1629 | EXPORT_SYMBOL(resource_list_free); | 1629 | EXPORT_SYMBOL(resource_list_free); |
| 1630 | 1630 | ||
| 1631 | #ifdef CONFIG_DEVICE_PRIVATE | ||
| 1632 | /** | ||
| 1633 | * devm_request_free_mem_region - find free region for device private memory | ||
| 1634 | * | ||
| 1635 | * @dev: device struct to bind the resource to | ||
| 1636 | * @size: size in bytes of the device memory to add | ||
| 1637 | * @base: resource tree to look in | ||
| 1638 | * | ||
| 1639 | * This function tries to find an empty range of physical address big enough to | ||
| 1640 | * contain the new resource, so that it can later be hotplugged as ZONE_DEVICE | ||
| 1641 | * memory, which in turn allocates struct pages. | ||
| 1642 | */ | ||
| 1643 | struct resource *devm_request_free_mem_region(struct device *dev, | ||
| 1644 | struct resource *base, unsigned long size) | ||
| 1645 | { | ||
| 1646 | resource_size_t end, addr; | ||
| 1647 | struct resource *res; | ||
| 1648 | |||
| 1649 | size = ALIGN(size, 1UL << PA_SECTION_SHIFT); | ||
| 1650 | end = min_t(unsigned long, base->end, (1UL << MAX_PHYSMEM_BITS) - 1); | ||
| 1651 | addr = end - size + 1UL; | ||
| 1652 | |||
| 1653 | for (; addr > size && addr >= base->start; addr -= size) { | ||
| 1654 | if (region_intersects(addr, size, 0, IORES_DESC_NONE) != | ||
| 1655 | REGION_DISJOINT) | ||
| 1656 | continue; | ||
| 1657 | |||
| 1658 | res = devm_request_mem_region(dev, addr, size, dev_name(dev)); | ||
| 1659 | if (!res) | ||
| 1660 | return ERR_PTR(-ENOMEM); | ||
| 1661 | res->desc = IORES_DESC_DEVICE_PRIVATE_MEMORY; | ||
| 1662 | return res; | ||
| 1663 | } | ||
| 1664 | |||
| 1665 | return ERR_PTR(-ERANGE); | ||
| 1666 | } | ||
| 1667 | EXPORT_SYMBOL_GPL(devm_request_free_mem_region); | ||
| 1668 | #endif /* CONFIG_DEVICE_PRIVATE */ | ||
| 1669 | |||
| 1631 | static int __init strict_iomem(char *str) | 1670 | static int __init strict_iomem(char *str) |
| 1632 | { | 1671 | { |
| 1633 | if (strstr(str, "relaxed")) | 1672 | if (strstr(str, "relaxed")) |
| @@ -25,8 +25,6 @@ · 24 unmodified lines | |||
| 25 | #include <linux/mmu_notifier.h> | 25 | #include <linux/mmu_notifier.h> |
| 26 | #include <linux/memory_hotplug.h> | 26 | #include <linux/memory_hotplug.h> |
| 27 | 27 | ||
| 28 | #define PA_SECTION_SIZE (1UL << PA_SECTION_SHIFT) | ||
| 29 | |||
| 30 | #if IS_ENABLED(CONFIG_HMM_MIRROR) | 28 | #if IS_ENABLED(CONFIG_HMM_MIRROR) |
| 31 | static const struct mmu_notifier_ops hmm_mmu_notifier_ops; | 29 | static const struct mmu_notifier_ops hmm_mmu_notifier_ops; |
| 32 | 30 | ||
| @@ -1408,7 +1406,6 @@ struct hmm_devmem *hmm_devmem_add(const struct hmm_devmem_ops *ops, · 1375 unmodified lines | |||
| 1408 | unsigned long size) | 1406 | unsigned long size) |
| 1409 | { | 1407 | { |
| 1410 | struct hmm_devmem *devmem; | 1408 | struct hmm_devmem *devmem; |
| 1411 | resource_size_t addr; | ||
| 1412 | void *result; | 1409 | void *result; |
| 1413 | int ret; | 1410 | int ret; |
| 1414 | 1411 | ||
| @@ -1430,32 +1427,10 @@ struct hmm_devmem *hmm_devmem_add(const struct hmm_devmem_ops *ops, · 15 unmodified lines | |||
| 1430 | if (ret) | 1427 | if (ret) |
| 1431 | return ERR_PTR(ret); | 1428 | return ERR_PTR(ret); |
| 1432 | 1429 | ||
| 1433 | size = ALIGN(size, PA_SECTION_SIZE); | 1430 | devmem->resource = devm_request_free_mem_region(device, &iomem_resource, |
| 1434 | addr = min((unsigned long)iomem_resource.end, | 1431 | size); |
| 1435 | (1UL << MAX_PHYSMEM_BITS) - 1); | 1432 | if (IS_ERR(devmem->resource)) |
| 1436 | addr = addr - size + 1UL; | 1433 | return ERR_CAST(devmem->resource); |
| 1437 | |||
| 1438 | /* | ||
| 1439 | * FIXME add a new helper to quickly walk resource tree and find free | ||
| 1440 | * range | ||
| 1441 | * | ||
| 1442 | * FIXME what about ioport_resource resource ? | ||
| 1443 | */ | ||
| 1444 | for (; addr > size && addr >= iomem_resource.start; addr -= size) { | ||
| 1445 | ret = region_intersects(addr, size, 0, IORES_DESC_NONE); | ||
| 1446 | if (ret != REGION_DISJOINT) | ||
| 1447 | continue; | ||
| 1448 | |||
| 1449 | devmem->resource = devm_request_mem_region(device, addr, size, | ||
| 1450 | dev_name(device)); | ||
| 1451 | if (!devmem->resource) | ||
| 1452 | return ERR_PTR(-ENOMEM); | ||
| 1453 | break; | ||
| 1454 | } | ||
| 1455 | if (!devmem->resource) | ||
| 1456 | return ERR_PTR(-ERANGE); | ||
| 1457 | |||
| 1458 | devmem->resource->desc = IORES_DESC_DEVICE_PRIVATE_MEMORY; | ||
| 1459 | devmem->pfn_first = devmem->resource->start >> PAGE_SHIFT; | 1434 | devmem->pfn_first = devmem->resource->start >> PAGE_SHIFT; |
| 1460 | devmem->pfn_last = devmem->pfn_first + | 1435 | devmem->pfn_last = devmem->pfn_first + |
| 1461 | (resource_size(devmem->resource) >> PAGE_SHIFT); | 1436 | (resource_size(devmem->resource) >> PAGE_SHIFT); |