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 | 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 | 291 | #endif /* __ASSEMBLY__ */ |
| 290 | 292 | #endif /* _LINUX_IOPORT_H */ |
| @@ -1628,6 +1628,45 @@ void resource_list_free(struct list_head *head) · 1627 unmodified lines | ||
| 1628 | 1628 | } |
| 1629 | 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 | 1670 | static int __init strict_iomem(char *str) |
| 1632 | 1671 | { |
| 1633 | 1672 | if (strstr(str, "relaxed")) |
| @@ -25,8 +25,6 @@ · 24 unmodified lines | ||
| 25 | 25 | #include <linux/mmu_notifier.h> |
| 26 | 26 | #include <linux/memory_hotplug.h> |
| 27 | 27 | |
| 28 | −#define PA_SECTION_SIZE (1UL << PA_SECTION_SHIFT) | |
| 29 | − | |
| 30 | 28 | #if IS_ENABLED(CONFIG_HMM_MIRROR) |
| 31 | 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 | 1406 | unsigned long size) |
| 1409 | 1407 | { |
| 1410 | 1408 | struct hmm_devmem *devmem; |
| 1411 | − resource_size_t addr; | |
| 1412 | 1409 | void *result; |
| 1413 | 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 | 1427 | if (ret) |
| 1431 | 1428 | return ERR_PTR(ret); |
| 1432 | 1429 | |
| 1433 | − size = ALIGN(size, PA_SECTION_SIZE); | |
| 1434 | − addr = min((unsigned long)iomem_resource.end, | |
| 1435 | − (1UL << MAX_PHYSMEM_BITS) - 1); | |
| 1436 | − addr = addr - size + 1UL; | |
| 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; | |
| 1430 | + devmem->resource = devm_request_free_mem_region(device, &iomem_resource, | |
| 1431 | + size); | |
| 1432 | + if (IS_ERR(devmem->resource)) | |
| 1433 | + return ERR_CAST(devmem->resource); | |
| 1459 | 1434 | devmem->pfn_first = devmem->resource->start >> PAGE_SHIFT; |
| 1460 | 1435 | devmem->pfn_last = devmem->pfn_first + |
| 1461 | 1436 | (resource_size(devmem->resource) >> PAGE_SHIFT); |