|
@@ -649,14 +649,47 @@ static u64 phys_pmem_align_down(struct nd_pfn *nd_pfn, u64 phys)
|
|
|
ALIGN_DOWN(phys, nd_pfn->align));
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Check if pmem collides with 'System RAM', or other regions when
|
|
|
+ * section aligned. Trim it accordingly.
|
|
|
+ */
|
|
|
+static void trim_pfn_device(struct nd_pfn *nd_pfn, u32 *start_pad, u32 *end_trunc)
|
|
|
+{
|
|
|
+ struct nd_namespace_common *ndns = nd_pfn->ndns;
|
|
|
+ struct nd_namespace_io *nsio = to_nd_namespace_io(&ndns->dev);
|
|
|
+ struct nd_region *nd_region = to_nd_region(nd_pfn->dev.parent);
|
|
|
+ const resource_size_t start = nsio->res.start;
|
|
|
+ const resource_size_t end = start + resource_size(&nsio->res);
|
|
|
+ resource_size_t adjust, size;
|
|
|
+
|
|
|
+ *start_pad = 0;
|
|
|
+ *end_trunc = 0;
|
|
|
+
|
|
|
+ adjust = start - PHYS_SECTION_ALIGN_DOWN(start);
|
|
|
+ size = resource_size(&nsio->res) + adjust;
|
|
|
+ if (region_intersects(start - adjust, size, IORESOURCE_SYSTEM_RAM,
|
|
|
+ IORES_DESC_NONE) == REGION_MIXED
|
|
|
+ || nd_region_conflict(nd_region, start - adjust, size))
|
|
|
+ *start_pad = PHYS_SECTION_ALIGN_UP(start) - start;
|
|
|
+
|
|
|
+ /* Now check that end of the range does not collide. */
|
|
|
+ adjust = PHYS_SECTION_ALIGN_UP(end) - end;
|
|
|
+ size = resource_size(&nsio->res) + adjust;
|
|
|
+ if (region_intersects(start, size, IORESOURCE_SYSTEM_RAM,
|
|
|
+ IORES_DESC_NONE) == REGION_MIXED
|
|
|
+ || !IS_ALIGNED(end, nd_pfn->align)
|
|
|
+ || nd_region_conflict(nd_region, start, size + adjust))
|
|
|
+ *end_trunc = end - phys_pmem_align_down(nd_pfn, end);
|
|
|
+}
|
|
|
+
|
|
|
static int nd_pfn_init(struct nd_pfn *nd_pfn)
|
|
|
{
|
|
|
u32 dax_label_reserve = is_nd_dax(&nd_pfn->dev) ? SZ_128K : 0;
|
|
|
struct nd_namespace_common *ndns = nd_pfn->ndns;
|
|
|
- u32 start_pad = 0, end_trunc = 0;
|
|
|
+ struct nd_namespace_io *nsio = to_nd_namespace_io(&ndns->dev);
|
|
|
resource_size_t start, size;
|
|
|
- struct nd_namespace_io *nsio;
|
|
|
struct nd_region *nd_region;
|
|
|
+ u32 start_pad, end_trunc;
|
|
|
struct nd_pfn_sb *pfn_sb;
|
|
|
unsigned long npfns;
|
|
|
phys_addr_t offset;
|
|
@@ -688,30 +721,7 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn)
|
|
|
|
|
|
memset(pfn_sb, 0, sizeof(*pfn_sb));
|
|
|
|
|
|
- /*
|
|
|
- * Check if pmem collides with 'System RAM' when section aligned and
|
|
|
- * trim it accordingly
|
|
|
- */
|
|
|
- nsio = to_nd_namespace_io(&ndns->dev);
|
|
|
- start = PHYS_SECTION_ALIGN_DOWN(nsio->res.start);
|
|
|
- size = resource_size(&nsio->res);
|
|
|
- if (region_intersects(start, size, IORESOURCE_SYSTEM_RAM,
|
|
|
- IORES_DESC_NONE) == REGION_MIXED) {
|
|
|
- start = nsio->res.start;
|
|
|
- start_pad = PHYS_SECTION_ALIGN_UP(start) - start;
|
|
|
- }
|
|
|
-
|
|
|
- start = nsio->res.start;
|
|
|
- size = PHYS_SECTION_ALIGN_UP(start + size) - start;
|
|
|
- if (region_intersects(start, size, IORESOURCE_SYSTEM_RAM,
|
|
|
- IORES_DESC_NONE) == REGION_MIXED
|
|
|
- || !IS_ALIGNED(start + resource_size(&nsio->res),
|
|
|
- nd_pfn->align)) {
|
|
|
- size = resource_size(&nsio->res);
|
|
|
- end_trunc = start + size - phys_pmem_align_down(nd_pfn,
|
|
|
- start + size);
|
|
|
- }
|
|
|
-
|
|
|
+ trim_pfn_device(nd_pfn, &start_pad, &end_trunc);
|
|
|
if (start_pad + end_trunc)
|
|
|
dev_info(&nd_pfn->dev, "%s alignment collision, truncate %d bytes\n",
|
|
|
dev_name(&ndns->dev), start_pad + end_trunc);
|
|
@@ -722,7 +732,7 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn)
|
|
|
* implementation will limit the pfns advertised through
|
|
|
* ->direct_access() to those that are included in the memmap.
|
|
|
*/
|
|
|
- start += start_pad;
|
|
|
+ start = nsio->res.start + start_pad;
|
|
|
size = resource_size(&nsio->res);
|
|
|
npfns = PFN_SECTION_ALIGN_UP((size - start_pad - end_trunc - SZ_8K)
|
|
|
/ PAGE_SIZE);
|