return 0;
 }
 
-int gpiochip_sysfs_register_all(void)
-{
-       struct gpio_device *gdev;
-       int ret;
-
-       guard(rwsem_read)(&gpio_devices_sem);
-
-       list_for_each_entry(gdev, &gpio_devices, list) {
-               if (gdev->mockdev)
-                       continue;
-
-               ret = gpiochip_sysfs_register(gdev);
-               if (ret)
-                       return ret;
-       }
-
-       return 0;
-}
-
 void gpiochip_sysfs_unregister(struct gpio_device *gdev)
 {
        struct gpio_desc *desc;
 
 static int __init gpiolib_sysfs_init(void)
 {
-       int status;
+       int             status;
+       unsigned long   flags;
+       struct gpio_device *gdev;
 
        status = class_register(&gpio_class);
        if (status < 0)
         * We run before arch_initcall() so chip->dev nodes can have
         * registered, and so arch_initcall() can always gpiod_export().
         */
-       return gpiochip_sysfs_register_all();
+       spin_lock_irqsave(&gpio_lock, flags);
+       list_for_each_entry(gdev, &gpio_devices, list) {
+               if (gdev->mockdev)
+                       continue;
+
+               /*
+                * TODO we yield gpio_lock here because
+                * gpiochip_sysfs_register() acquires a mutex. This is unsafe
+                * and needs to be fixed.
+                *
+                * Also it would be nice to use gpio_device_find() here so we
+                * can keep gpio_chips local to gpiolib.c, but the yield of
+                * gpio_lock prevents us from doing this.
+                */
+               spin_unlock_irqrestore(&gpio_lock, flags);
+               status = gpiochip_sysfs_register(gdev);
+               spin_lock_irqsave(&gpio_lock, flags);
+       }
+       spin_unlock_irqrestore(&gpio_lock, flags);
+
+       return status;
 }
 postcore_initcall(gpiolib_sysfs_init);
 
 
 #include <linux/acpi.h>
 #include <linux/bitmap.h>
-#include <linux/cleanup.h>
 #include <linux/compat.h>
 #include <linux/debugfs.h>
 #include <linux/device.h>
 #include <linux/kernel.h>
 #include <linux/list.h>
 #include <linux/module.h>
-#include <linux/mutex.h>
 #include <linux/of.h>
 #include <linux/pinctrl/consumer.h>
 #include <linux/seq_file.h>
 
 static DEFINE_MUTEX(gpio_lookup_lock);
 static LIST_HEAD(gpio_lookup_list);
-
 LIST_HEAD(gpio_devices);
-DECLARE_RWSEM(gpio_devices_sem);
 
 static DEFINE_MUTEX(gpio_machine_hogs_mutex);
 static LIST_HEAD(gpio_machine_hogs);
 struct gpio_desc *gpio_to_desc(unsigned gpio)
 {
        struct gpio_device *gdev;
+       unsigned long flags;
+
+       spin_lock_irqsave(&gpio_lock, flags);
 
-       scoped_guard(rwsem_read, &gpio_devices_sem) {
-               list_for_each_entry(gdev, &gpio_devices, list) {
-                       if (gdev->base <= gpio &&
-                           gdev->base + gdev->ngpio > gpio)
-                               return &gdev->descs[gpio - gdev->base];
+       list_for_each_entry(gdev, &gpio_devices, list) {
+               if (gdev->base <= gpio &&
+                   gdev->base + gdev->ngpio > gpio) {
+                       spin_unlock_irqrestore(&gpio_lock, flags);
+                       return &gdev->descs[gpio - gdev->base];
                }
        }
 
+       spin_unlock_irqrestore(&gpio_lock, flags);
+
        if (!gpio_is_valid(gpio))
                pr_warn("invalid GPIO %d\n", gpio);
 
 static struct gpio_desc *gpio_name_to_desc(const char * const name)
 {
        struct gpio_device *gdev;
+       unsigned long flags;
 
        if (!name)
                return NULL;
 
-       guard(rwsem_read)(&gpio_devices_sem);
+       spin_lock_irqsave(&gpio_lock, flags);
 
        list_for_each_entry(gdev, &gpio_devices, list) {
                struct gpio_desc *desc;
 
                for_each_gpio_desc(gdev->chip, desc) {
-                       if (desc->name && !strcmp(desc->name, name))
+                       if (desc->name && !strcmp(desc->name, name)) {
+                               spin_unlock_irqrestore(&gpio_lock, flags);
                                return desc;
+                       }
                }
        }
 
+       spin_unlock_irqrestore(&gpio_lock, flags);
+
        return NULL;
 }
 
                               struct lock_class_key *request_key)
 {
        struct gpio_device *gdev;
+       unsigned long flags;
        unsigned int i;
        int base = 0;
        int ret = 0;
 
        gdev->ngpio = gc->ngpio;
 
-       scoped_guard(rwsem_write, &gpio_devices_sem) {
-               /*
-                * TODO: this allocates a Linux GPIO number base in the global
-                * GPIO numberspace for this chip. In the long run we want to
-                * get *rid* of this numberspace and use only descriptors, but
-                * it may be a pipe dream. It will not happen before we get rid
-                * of the sysfs interface anyways.
-                */
-               base = gc->base;
+       spin_lock_irqsave(&gpio_lock, flags);
 
+       /*
+        * TODO: this allocates a Linux GPIO number base in the global
+        * GPIO numberspace for this chip. In the long run we want to
+        * get *rid* of this numberspace and use only descriptors, but
+        * it may be a pipe dream. It will not happen before we get rid
+        * of the sysfs interface anyways.
+        */
+       base = gc->base;
+       if (base < 0) {
+               base = gpiochip_find_base_unlocked(gc->ngpio);
                if (base < 0) {
-                       base = gpiochip_find_base_unlocked(gc->ngpio);
-                       if (base < 0) {
-                               ret = base;
-                               base = 0;
-                               goto err_free_label;
-                       }
-                       /*
-                        * TODO: it should not be necessary to reflect the assigned
-                        * base outside of the GPIO subsystem. Go over drivers and
-                        * see if anyone makes use of this, else drop this and assign
-                        * a poison instead.
-                        */
-                       gc->base = base;
-               } else {
-                       dev_warn(&gdev->dev,
-                                "Static allocation of GPIO base is deprecated, use dynamic allocation.\n");
-               }
-               gdev->base = base;
-
-               ret = gpiodev_add_to_list_unlocked(gdev);
-               if (ret) {
-                       chip_err(gc, "GPIO integer space overlap, cannot add chip\n");
+                       spin_unlock_irqrestore(&gpio_lock, flags);
+                       ret = base;
+                       base = 0;
                        goto err_free_label;
                }
+               /*
+                * TODO: it should not be necessary to reflect the assigned
+                * base outside of the GPIO subsystem. Go over drivers and
+                * see if anyone makes use of this, else drop this and assign
+                * a poison instead.
+                */
+               gc->base = base;
+       } else {
+               dev_warn(&gdev->dev,
+                        "Static allocation of GPIO base is deprecated, use dynamic allocation.\n");
+       }
+       gdev->base = base;
 
-               for (i = 0; i < gc->ngpio; i++)
-                       gdev->descs[i].gdev = gdev;
+       ret = gpiodev_add_to_list_unlocked(gdev);
+       if (ret) {
+               spin_unlock_irqrestore(&gpio_lock, flags);
+               chip_err(gc, "GPIO integer space overlap, cannot add chip\n");
+               goto err_free_label;
        }
 
+       for (i = 0; i < gc->ngpio; i++)
+               gdev->descs[i].gdev = gdev;
+
+       spin_unlock_irqrestore(&gpio_lock, flags);
+
        BLOCKING_INIT_NOTIFIER_HEAD(&gdev->line_state_notifier);
        BLOCKING_INIT_NOTIFIER_HEAD(&gdev->device_notifier);
        init_rwsem(&gdev->sem);
                goto err_print_message;
        }
 err_remove_from_list:
-       scoped_guard(rwsem_write, &gpio_devices_sem)
-               list_del(&gdev->list);
+       spin_lock_irqsave(&gpio_lock, flags);
+       list_del(&gdev->list);
+       spin_unlock_irqrestore(&gpio_lock, flags);
 err_free_label:
        kfree_const(gdev->label);
 err_free_descs:
                dev_crit(&gdev->dev,
                         "REMOVING GPIOCHIP WITH GPIOS STILL REQUESTED\n");
 
-       scoped_guard(rwsem_write, &gpio_devices_sem)
+       scoped_guard(spinlock_irqsave, &gpio_lock)
                list_del(&gdev->list);
 
        /*
         */
        might_sleep();
 
-       guard(rwsem_read)(&gpio_devices_sem);
+       guard(spinlock_irqsave)(&gpio_lock);
 
        list_for_each_entry(gdev, &gpio_devices, list) {
                if (gdev->chip && match(gdev->chip, data))
 
 static void *gpiolib_seq_start(struct seq_file *s, loff_t *pos)
 {
+       unsigned long flags;
        struct gpio_device *gdev = NULL;
        loff_t index = *pos;
 
        s->private = "";
 
-       guard(rwsem_read)(&gpio_devices_sem);
-
-       list_for_each_entry(gdev, &gpio_devices, list) {
-               if (index-- == 0)
+       spin_lock_irqsave(&gpio_lock, flags);
+       list_for_each_entry(gdev, &gpio_devices, list)
+               if (index-- == 0) {
+                       spin_unlock_irqrestore(&gpio_lock, flags);
                        return gdev;
-       }
+               }
+       spin_unlock_irqrestore(&gpio_lock, flags);
 
        return NULL;
 }
 
 static void *gpiolib_seq_next(struct seq_file *s, void *v, loff_t *pos)
 {
+       unsigned long flags;
        struct gpio_device *gdev = v;
        void *ret = NULL;
 
-       scoped_guard(rwsem_read, &gpio_devices_sem) {
-               if (list_is_last(&gdev->list, &gpio_devices))
-                       ret = NULL;
-               else
-                       ret = list_first_entry(&gdev->list, struct gpio_device,
-                                              list);
-       }
+       spin_lock_irqsave(&gpio_lock, flags);
+       if (list_is_last(&gdev->list, &gpio_devices))
+               ret = NULL;
+       else
+               ret = list_first_entry(&gdev->list, struct gpio_device, list);
+       spin_unlock_irqrestore(&gpio_lock, flags);
 
        s->private = "\n";
        ++*pos;