drm/ttm: Use Linux kobjects
authorFrançois Tigeot <ftigeot@wolfpond.org>
Wed, 19 Sep 2018 18:07:35 +0000 (20:07 +0200)
committerFrançois Tigeot <ftigeot@wolfpond.org>
Wed, 19 Sep 2018 18:11:11 +0000 (20:11 +0200)
* Reducing differences with Linux

* Changes based on Linux commit ecff665f5e3f1c6909353e00b9420e45ae23d995
  "drm/ttm: make ttm reservation calls behave like reservation calls"

sys/conf/files
sys/dev/drm/drm/Makefile
sys/dev/drm/drm_sysfs.c
sys/dev/drm/include/drm/drm_sysfs.h [new file with mode: 0644]
sys/dev/drm/include/drm/ttm/ttm_bo_driver.h
sys/dev/drm/include/drm/ttm/ttm_memory.h
sys/dev/drm/include/drm/ttm/ttm_module.h
sys/dev/drm/ttm/ttm_bo.c
sys/dev/drm/ttm/ttm_memory.c
sys/dev/drm/ttm/ttm_module.c [new file with mode: 0644]
sys/dev/drm/ttm/ttm_page_alloc.c

index 6464cfc..37b920c 100644 (file)
@@ -2307,6 +2307,7 @@ dev/drm/ttm/ttm_execbuf_util.c            optional drm compile-with "${NORMAL_C} -include
 dev/drm/ttm/ttm_memory.c               optional drm compile-with "${NORMAL_C} -include $S/dev/drm/kconfig.h"
 dev/drm/ttm/ttm_page_alloc.c           optional drm compile-with "${NORMAL_C} -include $S/dev/drm/kconfig.h"
 dev/drm/ttm/ttm_bo_vm.c                        optional drm compile-with "${NORMAL_C} -include $S/dev/drm/kconfig.h"
+dev/drm/ttm/ttm_module.c               optional drm compile-with "${NORMAL_C} -include $S/dev/drm/kconfig.h"
 dev/drm/i915/dvo_ch7017.c              optional i915 drm compile-with "${NORMAL_C} -include $S/dev/drm/kconfig.h"
 dev/drm/i915/dvo_ch7xxx.c              optional i915 drm compile-with "${NORMAL_C} -include $S/dev/drm/kconfig.h"
 dev/drm/i915/dvo_ivch.c                        optional i915 drm compile-with "${NORMAL_C} -include $S/dev/drm/kconfig.h"
index 504f16b..aabcb71 100644 (file)
@@ -70,7 +70,8 @@ SRCS  = \
        ttm_execbuf_util.c \
        ttm_memory.c \
        ttm_page_alloc.c \
-       ttm_bo_vm.c
+       ttm_bo_vm.c \
+       ttm_module.c
 
 SRCS   += device_if.h bus_if.h pci_if.h device_if.h iicbus_if.h opt_drm.h \
          opt_ktr.h opt_vm.h
index 040d977..ccc2910 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2015 François Tigeot
+ * Copyright 2015-2018 François Tigeot <ftigeot@wolfpond.org>
  * All Rights Reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -22,6 +22,9 @@
  * IN THE SOFTWARE.
  */
 
+#include <linux/device.h>
+
+#include <drm/drm_sysfs.h>
 #include <drm/drmP.h>
 #include "drm_internal.h"
 
@@ -37,3 +40,12 @@ void drm_sysfs_connector_remove(struct drm_connector *connector)
 void drm_sysfs_hotplug_event(struct drm_device *dev)
 {
 }
+
+int drm_class_device_register(struct device *dev)
+{
+       return 0;
+}
+
+void drm_class_device_unregister(struct device *dev)
+{
+}
diff --git a/sys/dev/drm/include/drm/drm_sysfs.h b/sys/dev/drm/include/drm/drm_sysfs.h
new file mode 100644 (file)
index 0000000..1d8e033
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef _DRM_SYSFS_H_
+#define _DRM_SYSFS_H_
+
+/**
+ * This minimalistic include file is intended for users (read TTM) that
+ * don't want to include the full drmP.h file.
+ */
+
+extern int drm_class_device_register(struct device *dev);
+extern void drm_class_device_unregister(struct device *dev);
+
+#endif
index 255bda1..36f3846 100644 (file)
@@ -482,12 +482,12 @@ struct ttm_bo_global_ref {
  */
 
 struct ttm_bo_global {
-       u_int kobj_ref;
 
        /**
         * Constant after init.
         */
 
+       struct kobject kobj;
        struct ttm_mem_global *mem_glob;
        struct page *dummy_read_page;
        struct ttm_mem_shrink shrink;
index 18df50a..a979a57 100644 (file)
  * USE OR OTHER DEALINGS IN THE SOFTWARE.
  *
  **************************************************************************/
-/* $FreeBSD: head/sys/dev/drm2/ttm/ttm_memory.h 247835 2013-03-05 09:49:34Z kib $ */
 
 #ifndef TTM_MEMORY_H
 #define TTM_MEMORY_H
 
+#include <linux/workqueue.h>
+#include <linux/spinlock.h>
+#include <linux/bug.h>
+#include <linux/wait.h>
+#include <linux/errno.h>
+#include <linux/kobject.h>
+#include <linux/mm.h>
+
 /**
  * struct ttm_mem_shrink - callback to shrink TTM memory usage.
  *
@@ -68,7 +75,7 @@ struct ttm_mem_shrink {
 #define TTM_MEM_MAX_ZONES 2
 struct ttm_mem_zone;
 struct ttm_mem_global {
-       u_int kobj_ref;
+       struct kobject kobj;
        struct ttm_mem_shrink *shrink;
        struct taskqueue *swap_queue;
        struct task work;
@@ -76,7 +83,11 @@ struct ttm_mem_global {
        struct ttm_mem_zone *zones[TTM_MEM_MAX_ZONES];
        unsigned int num_zones;
        struct ttm_mem_zone *zone_kernel;
+#ifdef CONFIG_HIGHMEM
+       struct ttm_mem_zone *zone_highmem;
+#else
        struct ttm_mem_zone *zone_dma32;
+#endif
 };
 
 /**
@@ -127,7 +138,7 @@ static inline void ttm_mem_unregister_shrink(struct ttm_mem_global *glob,
                                             struct ttm_mem_shrink *shrink)
 {
        spin_lock(&glob->spin);
-       KKASSERT(glob->shrink == shrink);
+       BUG_ON(glob->shrink != shrink);
        glob->shrink = NULL;
        spin_unlock(&glob->spin);
 }
index 769a795..45fa318 100644 (file)
 /*
  * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com>
  */
-/* $FreeBSD: head/sys/dev/drm2/ttm/ttm_module.h 247835 2013-03-05 09:49:34Z kib $ */
 
 #ifndef _TTM_MODULE_H_
 #define _TTM_MODULE_H_
 
+#include <linux/kernel.h>
+struct kobject;
+
 #define TTM_PFX "[TTM] "
+extern struct kobject *ttm_get_kobj(void);
 
 #endif /* _TTM_MODULE_H_ */
index 7901c45..441305a 100644 (file)
 #include <drm/ttm/ttm_module.h>
 #include <drm/ttm/ttm_bo_driver.h>
 #include <drm/ttm/ttm_placement.h>
+#include <linux/jiffies.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/file.h>
+#include <linux/module.h>
 #include <linux/atomic.h>
-#include <linux/errno.h>
-#include <linux/export.h>
-#include <linux/wait.h>
 
 #define TTM_ASSERT_LOCKED(param)       do { } while (0)
 #define TTM_DEBUG(fmt, arg...)         do { } while (0)
 
 static int ttm_bo_setup_vm(struct ttm_buffer_object *bo);
 static int ttm_bo_swapout(struct ttm_mem_shrink *shrink);
-static void ttm_bo_global_kobj_release(struct ttm_bo_global *glob);
+static void ttm_bo_global_kobj_release(struct kobject *kobj);
+
+static struct attribute ttm_bo_count = {
+       .name = "bo_count",
+       .mode = S_IRUGO
+};
 
 static inline int ttm_mem_type_from_place(const struct ttm_place *place,
                                          uint32_t *mem_type)
@@ -93,15 +101,31 @@ static void ttm_bo_mem_space_debug(struct ttm_buffer_object *bo,
        }
 }
 
-#if 0
-static ssize_t ttm_bo_global_show(struct ttm_bo_global *glob,
-    char *buffer)
+static ssize_t ttm_bo_global_show(struct kobject *kobj,
+                                 struct attribute *attr,
+                                 char *buffer)
 {
+       struct ttm_bo_global *glob =
+               container_of(kobj, struct ttm_bo_global, kobj);
 
-       return snprintf(buffer, PAGE_SIZE, "%lu\n",
+       return ksnprintf(buffer, PAGE_SIZE, "%lu\n",
                        (unsigned long) atomic_read(&glob->bo_count));
 }
-#endif
+
+static struct attribute *ttm_bo_global_attrs[] = {
+       &ttm_bo_count,
+       NULL
+};
+
+static const struct sysfs_ops ttm_bo_global_ops = {
+       .show = &ttm_bo_global_show
+};
+
+static struct kobj_type ttm_bo_glob_kobj_type  = {
+       .release = &ttm_bo_global_kobj_release,
+       .sysfs_ops = &ttm_bo_global_ops,
+       .default_attrs = ttm_bo_global_attrs
+};
 
 static inline uint32_t ttm_bo_type_flags(unsigned type)
 {
@@ -1522,19 +1546,22 @@ int ttm_bo_init_mm(struct ttm_bo_device *bdev, unsigned type,
 }
 EXPORT_SYMBOL(ttm_bo_init_mm);
 
-static void ttm_bo_global_kobj_release(struct ttm_bo_global *glob)
+static void ttm_bo_global_kobj_release(struct kobject *kobj)
 {
+       struct ttm_bo_global *glob =
+               container_of(kobj, struct ttm_bo_global, kobj);
+
        ttm_mem_unregister_shrink(glob->mem_glob, &glob->shrink);
        __free_page(glob->dummy_read_page);
-       glob->dummy_read_page = NULL;
+       kfree(glob);
 }
 
 void ttm_bo_global_release(struct drm_global_reference *ref)
 {
        struct ttm_bo_global *glob = ref->object;
 
-       if (refcount_release(&glob->kobj_ref))
-               ttm_bo_global_kobj_release(glob);
+       kobject_del(&glob->kobj);
+       kobject_put(&glob->kobj);
 }
 EXPORT_SYMBOL(ttm_bo_global_release);
 
@@ -1568,9 +1595,11 @@ int ttm_bo_global_init(struct drm_global_reference *ref)
 
        atomic_set(&glob->bo_count, 0);
 
-       refcount_init(&glob->kobj_ref, 1);
-       return (0);
-
+       ret = kobject_init_and_add(
+               &glob->kobj, &ttm_bo_glob_kobj_type, ttm_get_kobj(), "buffer_objects");
+       if (unlikely(ret != 0))
+               kobject_put(&glob->kobj);
+       return ret;
 out_no_shrink:
        __free_page(glob->dummy_read_page);
 out_no_drp:
index 9cc01b0..2e5942b 100644 (file)
@@ -37,7 +37,7 @@
 #define TTM_MEMORY_ALLOC_RETRIES 4
 
 struct ttm_mem_zone {
-       u_int kobj_ref;
+       struct kobject kobj;
        struct ttm_mem_global *glob;
        const char *name;
        uint64_t zone_mem;
@@ -47,23 +47,46 @@ struct ttm_mem_zone {
        uint64_t used_mem;
 };
 
-static void ttm_mem_zone_kobj_release(struct ttm_mem_zone *zone)
+static struct attribute ttm_mem_sys = {
+       .name = "zone_memory",
+       .mode = S_IRUGO
+};
+static struct attribute ttm_mem_emer = {
+       .name = "emergency_memory",
+       .mode = S_IRUGO | S_IWUSR
+};
+static struct attribute ttm_mem_max = {
+       .name = "available_memory",
+       .mode = S_IRUGO | S_IWUSR
+};
+static struct attribute ttm_mem_swap = {
+       .name = "swap_limit",
+       .mode = S_IRUGO | S_IWUSR
+};
+static struct attribute ttm_mem_used = {
+       .name = "used_memory",
+       .mode = S_IRUGO
+};
+
+static void ttm_mem_zone_kobj_release(struct kobject *kobj)
 {
+       struct ttm_mem_zone *zone =
+               container_of(kobj, struct ttm_mem_zone, kobj);
 
        pr_info("Zone %7s: Used memory at exit: %llu kiB\n",
                zone->name, (unsigned long long)zone->used_mem >> 10);
        kfree(zone);
 }
 
-#if 0
-/* XXXKIB sysctl */
-static ssize_t ttm_mem_zone_show(struct ttm_mem_zone *zone;
+static ssize_t ttm_mem_zone_show(struct kobject *kobj,
                                 struct attribute *attr,
                                 char *buffer)
 {
+       struct ttm_mem_zone *zone =
+               container_of(kobj, struct ttm_mem_zone, kobj);
        uint64_t val = 0;
 
-       mtx_lock(&zone->glob->lock);
+       spin_lock(&zone->glob->spin);
        if (attr == &ttm_mem_sys)
                val = zone->zone_mem;
        else if (attr == &ttm_mem_emer)
@@ -74,34 +97,33 @@ static ssize_t ttm_mem_zone_show(struct ttm_mem_zone *zone;
                val = zone->swap_limit;
        else if (attr == &ttm_mem_used)
                val = zone->used_mem;
-       mtx_unlock(&zone->glob->lock);
+       spin_unlock(&zone->glob->spin);
 
-       return snprintf(buffer, PAGE_SIZE, "%llu\n",
+       return ksnprintf(buffer, PAGE_SIZE, "%llu\n",
                        (unsigned long long) val >> 10);
 }
-#endif
 
 static void ttm_check_swapping(struct ttm_mem_global *glob);
 
-#if 0
-/* XXXKIB sysctl */
-static ssize_t ttm_mem_zone_store(struct ttm_mem_zone *zone,
+static ssize_t ttm_mem_zone_store(struct kobject *kobj,
                                  struct attribute *attr,
                                  const char *buffer,
                                  size_t size)
 {
+       struct ttm_mem_zone *zone =
+               container_of(kobj, struct ttm_mem_zone, kobj);
        int chars;
        unsigned long val;
        uint64_t val64;
 
-       chars = sscanf(buffer, "%lu", &val);
+       chars = ksscanf(buffer, "%lu", &val);
        if (chars == 0)
                return size;
 
        val64 = val;
        val64 <<= 10;
 
-       mtx_lock(&zone->glob->lock);
+       spin_lock(&zone->glob->spin);
        if (val64 > zone->zone_mem)
                val64 = zone->zone_mem;
        if (attr == &ttm_mem_emer) {
@@ -114,18 +136,45 @@ static ssize_t ttm_mem_zone_store(struct ttm_mem_zone *zone,
                        zone->emer_mem = val64;
        } else if (attr == &ttm_mem_swap)
                zone->swap_limit = val64;
-       mtx_unlock(&zone->glob->lock);
+       spin_unlock(&zone->glob->spin);
 
        ttm_check_swapping(zone->glob);
 
        return size;
 }
-#endif
 
-static void ttm_mem_global_kobj_release(struct ttm_mem_global *glob)
+static struct attribute *ttm_mem_zone_attrs[] = {
+       &ttm_mem_sys,
+       &ttm_mem_emer,
+       &ttm_mem_max,
+       &ttm_mem_swap,
+       &ttm_mem_used,
+       NULL
+};
+
+static const struct sysfs_ops ttm_mem_zone_ops = {
+       .show = &ttm_mem_zone_show,
+       .store = &ttm_mem_zone_store
+};
+
+static struct kobj_type ttm_mem_zone_kobj_type = {
+       .release = &ttm_mem_zone_kobj_release,
+       .sysfs_ops = &ttm_mem_zone_ops,
+       .default_attrs = ttm_mem_zone_attrs,
+};
+
+static void ttm_mem_global_kobj_release(struct kobject *kobj)
 {
+       struct ttm_mem_global *glob =
+               container_of(kobj, struct ttm_mem_global, kobj);
+
+       kfree(glob);
 }
 
+static struct kobj_type ttm_mem_glob_kobj_type = {
+       .release = &ttm_mem_global_kobj_release,
+};
+
 static bool ttm_zones_above_swap_target(struct ttm_mem_global *glob,
                                        bool from_wq, uint64_t extra)
 {
@@ -192,9 +241,8 @@ static void ttm_shrink_work(void *arg, int pending __unused)
 static int ttm_mem_init_kernel_zone(struct ttm_mem_global *glob,
     uint64_t mem)
 {
-       struct ttm_mem_zone *zone;
-
-       zone = kzalloc(sizeof(*zone), GFP_KERNEL);
+       struct ttm_mem_zone *zone = kzalloc(sizeof(*zone), GFP_KERNEL);
+       int ret;
 
        zone->name = "kernel";
        zone->zone_mem = mem;
@@ -204,17 +252,23 @@ static int ttm_mem_init_kernel_zone(struct ttm_mem_global *glob,
        zone->used_mem = 0;
        zone->glob = glob;
        glob->zone_kernel = zone;
-       refcount_init(&zone->kobj_ref, 1);
+       ret = kobject_init_and_add(
+               &zone->kobj, &ttm_mem_zone_kobj_type, &glob->kobj, zone->name);
+       if (unlikely(ret != 0)) {
+               kobject_put(&zone->kobj);
+               return ret;
+       }
        glob->zones[glob->num_zones++] = zone;
        return 0;
 }
 
+#ifdef CONFIG_HIGHMEM
+#else
 static int ttm_mem_init_dma32_zone(struct ttm_mem_global *glob,
     uint64_t mem)
 {
-       struct ttm_mem_zone *zone;
-
-       zone = kzalloc(sizeof(*zone), GFP_KERNEL);
+       struct ttm_mem_zone *zone = kzalloc(sizeof(*zone), GFP_KERNEL);
+       int ret;
 
        /**
         * No special dma32 zone needed.
@@ -241,10 +295,16 @@ static int ttm_mem_init_dma32_zone(struct ttm_mem_global *glob,
        zone->used_mem = 0;
        zone->glob = glob;
        glob->zone_dma32 = zone;
-       refcount_init(&zone->kobj_ref, 1);
+       ret = kobject_init_and_add(
+               &zone->kobj, &ttm_mem_zone_kobj_type, &glob->kobj, zone->name);
+       if (unlikely(ret != 0)) {
+               kobject_put(&zone->kobj);
+               return ret;
+       }
        glob->zones[glob->num_zones++] = zone;
        return 0;
 }
+#endif
 
 int ttm_mem_global_init(struct ttm_mem_global *glob)
 {
@@ -259,8 +319,12 @@ int ttm_mem_global_init(struct ttm_mem_global *glob)
        taskqueue_start_threads(&glob->swap_queue, 1, TDPRI_KERN_DAEMON,
                                -1, "ttm swap");
        TASK_INIT(&glob->work, 0, ttm_shrink_work, glob);
-
-       refcount_init(&glob->kobj_ref, 1);
+       ret = kobject_init_and_add(
+               &glob->kobj, &ttm_mem_glob_kobj_type, ttm_get_kobj(), "memory_accounting");
+       if (unlikely(ret != 0)) {
+               kobject_put(&glob->kobj);
+               return ret;
+       }
 
        /*
         * Managed contiguous memory for TTM.  Only use kernel-reserved
@@ -305,11 +369,12 @@ void ttm_mem_global_release(struct ttm_mem_global *glob)
        glob->swap_queue = NULL;
        for (i = 0; i < glob->num_zones; ++i) {
                zone = glob->zones[i];
-               if (refcount_release(&zone->kobj_ref))
-                       ttm_mem_zone_kobj_release(zone);
+               kobject_del(&zone->kobj);
+               kobject_put(&zone->kobj);
        }
-       if (refcount_release(&glob->kobj_ref))
-               ttm_mem_global_kobj_release(glob);
+       kobject_del(&glob->kobj);
+       kobject_put(&glob->kobj);
+       
 }
 EXPORT_SYMBOL(ttm_mem_global_release);
 
diff --git a/sys/dev/drm/ttm/ttm_module.c b/sys/dev/drm/ttm/ttm_module.c
new file mode 100644 (file)
index 0000000..9230ec3
--- /dev/null
@@ -0,0 +1,105 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2006-2009 VMware, Inc., Palo Alto, CA., USA
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+/*
+ * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com>
+ *         Jerome Glisse
+ */
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/sched.h>
+#include <drm/ttm/ttm_module.h>
+#include <drm/drm_sysfs.h>
+
+static DECLARE_WAIT_QUEUE_HEAD(exit_q);
+atomic_t device_released;
+
+#if 0
+static struct device_type ttm_drm_class_type = {
+       .name = "ttm",
+       /**
+        * Add pm ops here.
+        */
+};
+
+static void ttm_drm_class_device_release(struct device *dev)
+{
+       atomic_set(&device_released, 1);
+       wake_up_all(&exit_q);
+}
+#endif
+
+static struct device ttm_drm_class_device = {
+#if 0
+       .type = &ttm_drm_class_type,
+       .release = &ttm_drm_class_device_release
+#endif
+};
+
+struct kobject *ttm_get_kobj(void)
+{
+       struct kobject *kobj = &ttm_drm_class_device.kobj;
+       BUG_ON(kobj == NULL);
+       return kobj;
+}
+
+static int __init ttm_init(void)
+{
+       int ret;
+
+       ret = dev_set_name(&ttm_drm_class_device, "ttm");
+       if (unlikely(ret != 0))
+               return ret;
+
+       atomic_set(&device_released, 0);
+       ret = drm_class_device_register(&ttm_drm_class_device);
+       if (unlikely(ret != 0))
+               goto out_no_dev_reg;
+
+       return 0;
+out_no_dev_reg:
+       atomic_set(&device_released, 1);
+       wake_up_all(&exit_q);
+       return ret;
+}
+
+static void __exit ttm_exit(void)
+{
+       drm_class_device_unregister(&ttm_drm_class_device);
+
+       /**
+        * Refuse to unload until the TTM device is released.
+        * Not sure this is 100% needed.
+        */
+
+       wait_event(exit_q, atomic_read(&device_released) == 1);
+}
+
+module_init(ttm_init);
+module_exit(ttm_exit);
+
+MODULE_AUTHOR("Thomas Hellstrom, Jerome Glisse");
+MODULE_DESCRIPTION("TTM memory manager subsystem (for DRM device)");
index 742870a..db9fbae 100644 (file)
@@ -109,7 +109,7 @@ struct ttm_pool_opts {
  * @pools: All pool objects in use.
  **/
 struct ttm_pool_manager {
-       unsigned int kobj_ref;
+       struct kobject          kobj;
        eventhandler_tag lowmem_handler;
        struct ttm_pool_opts    options;
 
@@ -145,19 +145,41 @@ ttm_caching_state_to_vm(enum ttm_caching_state cstate)
        panic("caching state %d\n", cstate);
 }
 
-static void ttm_pool_kobj_release(struct ttm_pool_manager *m)
+static struct attribute ttm_page_pool_max = {
+       .name = "pool_max_size",
+       .mode = S_IRUGO | S_IWUSR
+};
+static struct attribute ttm_page_pool_small = {
+       .name = "pool_small_allocation",
+       .mode = S_IRUGO | S_IWUSR
+};
+static struct attribute ttm_page_pool_alloc_size = {
+       .name = "pool_allocation_size",
+       .mode = S_IRUGO | S_IWUSR
+};
+
+static struct attribute *ttm_pool_attrs[] = {
+       &ttm_page_pool_max,
+       &ttm_page_pool_small,
+       &ttm_page_pool_alloc_size,
+       NULL
+};
+
+static void ttm_pool_kobj_release(struct kobject *kobj)
 {
+       struct ttm_pool_manager *m =
+               container_of(kobj, struct ttm_pool_manager, kobj);
        kfree(m);
 }
 
-#if 0
-/* XXXKIB sysctl */
-static ssize_t ttm_pool_store(struct ttm_pool_manager *m,
+static ssize_t ttm_pool_store(struct kobject *kobj,
                struct attribute *attr, const char *buffer, size_t size)
 {
+       struct ttm_pool_manager *m =
+               container_of(kobj, struct ttm_pool_manager, kobj);
        int chars;
        unsigned val;
-       chars = sscanf(buffer, "%u", &val);
+       chars = ksscanf(buffer, "%u", &val);
        if (chars == 0)
                return size;
 
@@ -184,9 +206,11 @@ static ssize_t ttm_pool_store(struct ttm_pool_manager *m,
        return size;
 }
 
-static ssize_t ttm_pool_show(struct ttm_pool_manager *m,
+static ssize_t ttm_pool_show(struct kobject *kobj,
                struct attribute *attr, char *buffer)
 {
+       struct ttm_pool_manager *m =
+               container_of(kobj, struct ttm_pool_manager, kobj);
        unsigned val = 0;
 
        if (attr == &ttm_page_pool_max)
@@ -198,9 +222,19 @@ static ssize_t ttm_pool_show(struct ttm_pool_manager *m,
 
        val = val * (PAGE_SIZE >> 10);
 
-       return snprintf(buffer, PAGE_SIZE, "%u\n", val);
+       return ksnprintf(buffer, PAGE_SIZE, "%u\n", val);
 }
-#endif
+
+static const struct sysfs_ops ttm_pool_sysfs_ops = {
+       .show = &ttm_pool_show,
+       .store = &ttm_pool_store,
+};
+
+static struct kobj_type ttm_pool_kobj_type = {
+       .release = &ttm_pool_kobj_release,
+       .sysfs_ops = &ttm_pool_sysfs_ops,
+       .default_attrs = ttm_pool_attrs,
+};
 
 static struct ttm_pool_manager *_manager;
 
@@ -777,6 +811,8 @@ static void ttm_page_pool_init_locked(struct ttm_page_pool *pool, gfp_t flags,
 
 int ttm_page_alloc_init(struct ttm_mem_global *glob, unsigned max_pages)
 {
+       int ret;
+
        WARN_ON(_manager);
 
        pr_info("Initializing pool allocator\n");
@@ -794,7 +830,13 @@ int ttm_page_alloc_init(struct ttm_mem_global *glob, unsigned max_pages)
        _manager->options.small = SMALL_ALLOCATION;
        _manager->options.alloc_size = NUM_PAGES_TO_ALLOC;
 
-       refcount_init(&_manager->kobj_ref, 1);
+       ret = kobject_init_and_add(&_manager->kobj, &ttm_pool_kobj_type,
+                                  &glob->kobj, "pool");
+       if (unlikely(ret != 0)) {
+               kobject_put(&_manager->kobj);
+               _manager = NULL;
+               return ret;
+       }
        ttm_pool_mm_shrink_init(_manager);
 
        return 0;
@@ -810,8 +852,7 @@ void ttm_page_alloc_fini(void)
        for (i = 0; i < NUM_POOLS; ++i)
                ttm_page_pool_free(&_manager->pools[i], FREE_ALL_PAGES);
 
-       if (refcount_release(&_manager->kobj_ref))
-               ttm_pool_kobj_release(_manager);
+       kobject_put(&_manager->kobj);
        _manager = NULL;
 }
 
@@ -852,6 +893,7 @@ int ttm_pool_populate(struct ttm_tt *ttm)
        ttm->state = tt_unbound;
        return 0;
 }
+EXPORT_SYMBOL(ttm_pool_populate);
 
 void ttm_pool_unpopulate(struct ttm_tt *ttm)
 {
@@ -892,3 +934,4 @@ int ttm_page_alloc_debugfs(struct seq_file *m, void *data)
        return 0;
 }
 #endif
+EXPORT_SYMBOL(ttm_page_alloc_debugfs);