Skip to content

Commit 8c86e70

Browse files
rhvgoyaltorvalds
authored andcommitted
resource: provide new functions to walk through resources
I have added two more functions to walk through resources. Currently walk_system_ram_range() deals with pfn and /proc/iomem can contain partial pages. By dealing in pfn, callback function loses the info that last page of a memory range is a partial page and not the full page. So I implemented walk_system_ram_res() which returns u64 values to callback functions and now it properly return start and end address. walk_system_ram_range() uses find_next_system_ram() to find the next ram resource. This in turn only travels through siblings of top level child and does not travers through all the nodes of the resoruce tree. I also need another function where I can walk through all the resources, for example figure out where "GART" aperture is. Figure out where ACPI memory is. So I wrote another function walk_iomem_res() which walks through all /proc/iomem resources and returns matches as asked by caller. Caller can specify "name" of resource, start and end and flags. Got rid of find_next_system_ram_res() and instead implemented more generic find_next_iomem_res() which can be used to traverse top level children only based on an argument. Signed-off-by: Vivek Goyal <[email protected]> Cc: Yinghai Lu <[email protected]> Cc: Borislav Petkov <[email protected]> Cc: Michael Kerrisk <[email protected]> Cc: Eric Biederman <[email protected]> Cc: H. Peter Anvin <[email protected]> Cc: Matthew Garrett <[email protected]> Cc: Greg Kroah-Hartman <[email protected]> Cc: Dave Young <[email protected]> Cc: WANG Chao <[email protected]> Cc: Baoquan He <[email protected]> Cc: Andy Lutomirski <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent 255aedd commit 8c86e70

File tree

2 files changed

+98
-9
lines changed

2 files changed

+98
-9
lines changed

include/linux/ioport.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,12 @@ extern int iomem_is_exclusive(u64 addr);
237237
extern int
238238
walk_system_ram_range(unsigned long start_pfn, unsigned long nr_pages,
239239
void *arg, int (*func)(unsigned long, unsigned long, void *));
240+
extern int
241+
walk_system_ram_res(u64 start, u64 end, void *arg,
242+
int (*func)(u64, u64, void *));
243+
extern int
244+
walk_iomem_res(char *name, unsigned long flags, u64 start, u64 end, void *arg,
245+
int (*func)(u64, u64, void *));
240246

241247
/* True if any part of r1 overlaps r2 */
242248
static inline bool resource_overlaps(struct resource *r1, struct resource *r2)

kernel/resource.c

Lines changed: 92 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -59,17 +59,26 @@ static DEFINE_RWLOCK(resource_lock);
5959
static struct resource *bootmem_resource_free;
6060
static DEFINE_SPINLOCK(bootmem_resource_lock);
6161

62-
static void *r_next(struct seq_file *m, void *v, loff_t *pos)
62+
static struct resource *next_resource(struct resource *p, bool sibling_only)
6363
{
64-
struct resource *p = v;
65-
(*pos)++;
64+
/* Caller wants to traverse through siblings only */
65+
if (sibling_only)
66+
return p->sibling;
67+
6668
if (p->child)
6769
return p->child;
6870
while (!p->sibling && p->parent)
6971
p = p->parent;
7072
return p->sibling;
7173
}
7274

75+
static void *r_next(struct seq_file *m, void *v, loff_t *pos)
76+
{
77+
struct resource *p = v;
78+
(*pos)++;
79+
return (void *)next_resource(p, false);
80+
}
81+
7382
#ifdef CONFIG_PROC_FS
7483

7584
enum { MAX_IORES_LEVEL = 5 };
@@ -322,16 +331,19 @@ int release_resource(struct resource *old)
322331

323332
EXPORT_SYMBOL(release_resource);
324333

325-
#if !defined(CONFIG_ARCH_HAS_WALK_MEMORY)
326334
/*
327-
* Finds the lowest memory reosurce exists within [res->start.res->end)
335+
* Finds the lowest iomem reosurce exists with-in [res->start.res->end)
328336
* the caller must specify res->start, res->end, res->flags and "name".
329337
* If found, returns 0, res is overwritten, if not found, returns -1.
338+
* This walks through whole tree and not just first level children
339+
* until and unless first_level_children_only is true.
330340
*/
331-
static int find_next_system_ram(struct resource *res, char *name)
341+
static int find_next_iomem_res(struct resource *res, char *name,
342+
bool first_level_children_only)
332343
{
333344
resource_size_t start, end;
334345
struct resource *p;
346+
bool sibling_only = false;
335347

336348
BUG_ON(!res);
337349

@@ -340,8 +352,14 @@ static int find_next_system_ram(struct resource *res, char *name)
340352
BUG_ON(start >= end);
341353

342354
read_lock(&resource_lock);
343-
for (p = iomem_resource.child; p ; p = p->sibling) {
344-
/* system ram is just marked as IORESOURCE_MEM */
355+
356+
if (first_level_children_only) {
357+
p = iomem_resource.child;
358+
sibling_only = true;
359+
} else
360+
p = &iomem_resource;
361+
362+
while ((p = next_resource(p, sibling_only))) {
345363
if (p->flags != res->flags)
346364
continue;
347365
if (name && strcmp(p->name, name))
@@ -353,6 +371,7 @@ static int find_next_system_ram(struct resource *res, char *name)
353371
if ((p->end >= start) && (p->start < end))
354372
break;
355373
}
374+
356375
read_unlock(&resource_lock);
357376
if (!p)
358377
return -1;
@@ -364,6 +383,70 @@ static int find_next_system_ram(struct resource *res, char *name)
364383
return 0;
365384
}
366385

386+
/*
387+
* Walks through iomem resources and calls func() with matching resource
388+
* ranges. This walks through whole tree and not just first level children.
389+
* All the memory ranges which overlap start,end and also match flags and
390+
* name are valid candidates.
391+
*
392+
* @name: name of resource
393+
* @flags: resource flags
394+
* @start: start addr
395+
* @end: end addr
396+
*/
397+
int walk_iomem_res(char *name, unsigned long flags, u64 start, u64 end,
398+
void *arg, int (*func)(u64, u64, void *))
399+
{
400+
struct resource res;
401+
u64 orig_end;
402+
int ret = -1;
403+
404+
res.start = start;
405+
res.end = end;
406+
res.flags = flags;
407+
orig_end = res.end;
408+
while ((res.start < res.end) &&
409+
(!find_next_iomem_res(&res, name, false))) {
410+
ret = (*func)(res.start, res.end, arg);
411+
if (ret)
412+
break;
413+
res.start = res.end + 1;
414+
res.end = orig_end;
415+
}
416+
return ret;
417+
}
418+
419+
/*
420+
* This function calls callback against all memory range of "System RAM"
421+
* which are marked as IORESOURCE_MEM and IORESOUCE_BUSY.
422+
* Now, this function is only for "System RAM". This function deals with
423+
* full ranges and not pfn. If resources are not pfn aligned, dealing
424+
* with pfn can truncate ranges.
425+
*/
426+
int walk_system_ram_res(u64 start, u64 end, void *arg,
427+
int (*func)(u64, u64, void *))
428+
{
429+
struct resource res;
430+
u64 orig_end;
431+
int ret = -1;
432+
433+
res.start = start;
434+
res.end = end;
435+
res.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
436+
orig_end = res.end;
437+
while ((res.start < res.end) &&
438+
(!find_next_iomem_res(&res, "System RAM", true))) {
439+
ret = (*func)(res.start, res.end, arg);
440+
if (ret)
441+
break;
442+
res.start = res.end + 1;
443+
res.end = orig_end;
444+
}
445+
return ret;
446+
}
447+
448+
#if !defined(CONFIG_ARCH_HAS_WALK_MEMORY)
449+
367450
/*
368451
* This function calls callback against all memory range of "System RAM"
369452
* which are marked as IORESOURCE_MEM and IORESOUCE_BUSY.
@@ -382,7 +465,7 @@ int walk_system_ram_range(unsigned long start_pfn, unsigned long nr_pages,
382465
res.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
383466
orig_end = res.end;
384467
while ((res.start < res.end) &&
385-
(find_next_system_ram(&res, "System RAM") >= 0)) {
468+
(find_next_iomem_res(&res, "System RAM", true) >= 0)) {
386469
pfn = (res.start + PAGE_SIZE - 1) >> PAGE_SHIFT;
387470
end_pfn = (res.end + 1) >> PAGE_SHIFT;
388471
if (end_pfn > pfn)

0 commit comments

Comments
 (0)