1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * CMA SysFS Interface
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (c) 2021 Minchan Kim <minchan@kernel.org>
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun #include <linux/cma.h>
9*4882a593Smuzhiyun #include <linux/kernel.h>
10*4882a593Smuzhiyun #include <linux/slab.h>
11*4882a593Smuzhiyun #include <linux/module.h>
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun #include "cma.h"
14*4882a593Smuzhiyun
15*4882a593Smuzhiyun static bool experimental;
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun #define CMA_ATTR_RO(_name) \
18*4882a593Smuzhiyun static struct kobj_attribute _name##_attr = __ATTR_RO(_name)
19*4882a593Smuzhiyun
cma_sysfs_account_success_pages(struct cma * cma,unsigned long nr_pages)20*4882a593Smuzhiyun void cma_sysfs_account_success_pages(struct cma *cma, unsigned long nr_pages)
21*4882a593Smuzhiyun {
22*4882a593Smuzhiyun atomic64_add(nr_pages, &cma->nr_pages_succeeded);
23*4882a593Smuzhiyun }
24*4882a593Smuzhiyun
cma_sysfs_account_fail_pages(struct cma * cma,unsigned long nr_pages)25*4882a593Smuzhiyun void cma_sysfs_account_fail_pages(struct cma *cma, unsigned long nr_pages)
26*4882a593Smuzhiyun {
27*4882a593Smuzhiyun atomic64_add(nr_pages, &cma->nr_pages_failed);
28*4882a593Smuzhiyun }
29*4882a593Smuzhiyun
cma_from_kobj(struct kobject * kobj)30*4882a593Smuzhiyun static inline struct cma *cma_from_kobj(struct kobject *kobj)
31*4882a593Smuzhiyun {
32*4882a593Smuzhiyun return container_of(kobj, struct cma_kobject, kobj)->cma;
33*4882a593Smuzhiyun }
34*4882a593Smuzhiyun
alloc_pages_success_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)35*4882a593Smuzhiyun static ssize_t alloc_pages_success_show(struct kobject *kobj,
36*4882a593Smuzhiyun struct kobj_attribute *attr, char *buf)
37*4882a593Smuzhiyun {
38*4882a593Smuzhiyun struct cma *cma = cma_from_kobj(kobj);
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun return sysfs_emit(buf, "%llu\n",
41*4882a593Smuzhiyun atomic64_read(&cma->nr_pages_succeeded));
42*4882a593Smuzhiyun }
43*4882a593Smuzhiyun CMA_ATTR_RO(alloc_pages_success);
44*4882a593Smuzhiyun
alloc_pages_fail_show(struct kobject * kobj,struct kobj_attribute * attr,char * buf)45*4882a593Smuzhiyun static ssize_t alloc_pages_fail_show(struct kobject *kobj,
46*4882a593Smuzhiyun struct kobj_attribute *attr, char *buf)
47*4882a593Smuzhiyun {
48*4882a593Smuzhiyun struct cma *cma = cma_from_kobj(kobj);
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun return sysfs_emit(buf, "%llu\n", atomic64_read(&cma->nr_pages_failed));
51*4882a593Smuzhiyun }
52*4882a593Smuzhiyun CMA_ATTR_RO(alloc_pages_fail);
53*4882a593Smuzhiyun
cma_kobj_release(struct kobject * kobj)54*4882a593Smuzhiyun static void cma_kobj_release(struct kobject *kobj)
55*4882a593Smuzhiyun {
56*4882a593Smuzhiyun struct cma *cma = cma_from_kobj(kobj);
57*4882a593Smuzhiyun struct cma_kobject *cma_kobj = cma->cma_kobj;
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun kfree(cma_kobj);
60*4882a593Smuzhiyun cma->cma_kobj = NULL;
61*4882a593Smuzhiyun }
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun static struct attribute *cma_attrs[] = {
64*4882a593Smuzhiyun &alloc_pages_success_attr.attr,
65*4882a593Smuzhiyun &alloc_pages_fail_attr.attr,
66*4882a593Smuzhiyun NULL,
67*4882a593Smuzhiyun };
68*4882a593Smuzhiyun ATTRIBUTE_GROUPS(cma);
69*4882a593Smuzhiyun
70*4882a593Smuzhiyun static struct kobj_type cma_ktype = {
71*4882a593Smuzhiyun .release = cma_kobj_release,
72*4882a593Smuzhiyun .sysfs_ops = &kobj_sysfs_ops,
73*4882a593Smuzhiyun .default_groups = cma_groups,
74*4882a593Smuzhiyun };
75*4882a593Smuzhiyun
cma_sysfs_init(void)76*4882a593Smuzhiyun static int __init cma_sysfs_init(void)
77*4882a593Smuzhiyun {
78*4882a593Smuzhiyun struct kobject *cma_kobj_root;
79*4882a593Smuzhiyun struct cma_kobject *cma_kobj;
80*4882a593Smuzhiyun struct cma *cma;
81*4882a593Smuzhiyun int i, err;
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun if (!experimental)
84*4882a593Smuzhiyun return 0;
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun cma_kobj_root = kobject_create_and_add("cma", mm_kobj);
87*4882a593Smuzhiyun if (!cma_kobj_root)
88*4882a593Smuzhiyun return -ENOMEM;
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun for (i = 0; i < cma_area_count; i++) {
91*4882a593Smuzhiyun cma_kobj = kzalloc(sizeof(*cma_kobj), GFP_KERNEL);
92*4882a593Smuzhiyun if (!cma_kobj) {
93*4882a593Smuzhiyun err = -ENOMEM;
94*4882a593Smuzhiyun goto out;
95*4882a593Smuzhiyun }
96*4882a593Smuzhiyun
97*4882a593Smuzhiyun cma = &cma_areas[i];
98*4882a593Smuzhiyun cma->cma_kobj = cma_kobj;
99*4882a593Smuzhiyun cma_kobj->cma = cma;
100*4882a593Smuzhiyun err = kobject_init_and_add(&cma_kobj->kobj, &cma_ktype,
101*4882a593Smuzhiyun cma_kobj_root, "%s", cma->name);
102*4882a593Smuzhiyun if (err) {
103*4882a593Smuzhiyun kobject_put(&cma_kobj->kobj);
104*4882a593Smuzhiyun goto out;
105*4882a593Smuzhiyun }
106*4882a593Smuzhiyun }
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun return 0;
109*4882a593Smuzhiyun out:
110*4882a593Smuzhiyun while (--i >= 0) {
111*4882a593Smuzhiyun cma = &cma_areas[i];
112*4882a593Smuzhiyun kobject_put(&cma->cma_kobj->kobj);
113*4882a593Smuzhiyun }
114*4882a593Smuzhiyun kobject_put(cma_kobj_root);
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun return err;
117*4882a593Smuzhiyun }
118*4882a593Smuzhiyun subsys_initcall(cma_sysfs_init);
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun module_param(experimental, bool, 0400);
121