162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * CMA SysFS Interface 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2021 Minchan Kim <minchan@kernel.org> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/cma.h> 962306a36Sopenharmony_ci#include <linux/kernel.h> 1062306a36Sopenharmony_ci#include <linux/slab.h> 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include "cma.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#define CMA_ATTR_RO(_name) \ 1562306a36Sopenharmony_ci static struct kobj_attribute _name##_attr = __ATTR_RO(_name) 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_civoid cma_sysfs_account_success_pages(struct cma *cma, unsigned long nr_pages) 1862306a36Sopenharmony_ci{ 1962306a36Sopenharmony_ci atomic64_add(nr_pages, &cma->nr_pages_succeeded); 2062306a36Sopenharmony_ci} 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_civoid cma_sysfs_account_fail_pages(struct cma *cma, unsigned long nr_pages) 2362306a36Sopenharmony_ci{ 2462306a36Sopenharmony_ci atomic64_add(nr_pages, &cma->nr_pages_failed); 2562306a36Sopenharmony_ci} 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistatic inline struct cma *cma_from_kobj(struct kobject *kobj) 2862306a36Sopenharmony_ci{ 2962306a36Sopenharmony_ci return container_of(kobj, struct cma_kobject, kobj)->cma; 3062306a36Sopenharmony_ci} 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_cistatic ssize_t alloc_pages_success_show(struct kobject *kobj, 3362306a36Sopenharmony_ci struct kobj_attribute *attr, char *buf) 3462306a36Sopenharmony_ci{ 3562306a36Sopenharmony_ci struct cma *cma = cma_from_kobj(kobj); 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci return sysfs_emit(buf, "%llu\n", 3862306a36Sopenharmony_ci atomic64_read(&cma->nr_pages_succeeded)); 3962306a36Sopenharmony_ci} 4062306a36Sopenharmony_ciCMA_ATTR_RO(alloc_pages_success); 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_cistatic ssize_t alloc_pages_fail_show(struct kobject *kobj, 4362306a36Sopenharmony_ci struct kobj_attribute *attr, char *buf) 4462306a36Sopenharmony_ci{ 4562306a36Sopenharmony_ci struct cma *cma = cma_from_kobj(kobj); 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci return sysfs_emit(buf, "%llu\n", atomic64_read(&cma->nr_pages_failed)); 4862306a36Sopenharmony_ci} 4962306a36Sopenharmony_ciCMA_ATTR_RO(alloc_pages_fail); 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_cistatic void cma_kobj_release(struct kobject *kobj) 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci struct cma *cma = cma_from_kobj(kobj); 5462306a36Sopenharmony_ci struct cma_kobject *cma_kobj = cma->cma_kobj; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci kfree(cma_kobj); 5762306a36Sopenharmony_ci cma->cma_kobj = NULL; 5862306a36Sopenharmony_ci} 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_cistatic struct attribute *cma_attrs[] = { 6162306a36Sopenharmony_ci &alloc_pages_success_attr.attr, 6262306a36Sopenharmony_ci &alloc_pages_fail_attr.attr, 6362306a36Sopenharmony_ci NULL, 6462306a36Sopenharmony_ci}; 6562306a36Sopenharmony_ciATTRIBUTE_GROUPS(cma); 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_cistatic const struct kobj_type cma_ktype = { 6862306a36Sopenharmony_ci .release = cma_kobj_release, 6962306a36Sopenharmony_ci .sysfs_ops = &kobj_sysfs_ops, 7062306a36Sopenharmony_ci .default_groups = cma_groups, 7162306a36Sopenharmony_ci}; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_cistatic int __init cma_sysfs_init(void) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci struct kobject *cma_kobj_root; 7662306a36Sopenharmony_ci struct cma_kobject *cma_kobj; 7762306a36Sopenharmony_ci struct cma *cma; 7862306a36Sopenharmony_ci int i, err; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci cma_kobj_root = kobject_create_and_add("cma", mm_kobj); 8162306a36Sopenharmony_ci if (!cma_kobj_root) 8262306a36Sopenharmony_ci return -ENOMEM; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci for (i = 0; i < cma_area_count; i++) { 8562306a36Sopenharmony_ci cma_kobj = kzalloc(sizeof(*cma_kobj), GFP_KERNEL); 8662306a36Sopenharmony_ci if (!cma_kobj) { 8762306a36Sopenharmony_ci err = -ENOMEM; 8862306a36Sopenharmony_ci goto out; 8962306a36Sopenharmony_ci } 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci cma = &cma_areas[i]; 9262306a36Sopenharmony_ci cma->cma_kobj = cma_kobj; 9362306a36Sopenharmony_ci cma_kobj->cma = cma; 9462306a36Sopenharmony_ci err = kobject_init_and_add(&cma_kobj->kobj, &cma_ktype, 9562306a36Sopenharmony_ci cma_kobj_root, "%s", cma->name); 9662306a36Sopenharmony_ci if (err) { 9762306a36Sopenharmony_ci kobject_put(&cma_kobj->kobj); 9862306a36Sopenharmony_ci goto out; 9962306a36Sopenharmony_ci } 10062306a36Sopenharmony_ci } 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci return 0; 10362306a36Sopenharmony_ciout: 10462306a36Sopenharmony_ci while (--i >= 0) { 10562306a36Sopenharmony_ci cma = &cma_areas[i]; 10662306a36Sopenharmony_ci kobject_put(&cma->cma_kobj->kobj); 10762306a36Sopenharmony_ci } 10862306a36Sopenharmony_ci kobject_put(cma_kobj_root); 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci return err; 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_cisubsys_initcall(cma_sysfs_init); 113