aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Cox <alan@linux.intel.com>2010-03-29 13:38:00 -0400
committerJesse Barnes <jbarnes@virtuousgeek.org>2010-05-11 15:01:10 -0400
commit8b6d043b7ee2d1b819dc833d677ea2aead71a0c0 (patch)
tree757e0be31fc4951d6e0688191a929542751d6e49
parentd19f61f098ae9315b76a97962007f687683916d4 (diff)
resource: shared I/O region support
SuperIO devices share regions and use lock/unlock operations to chip select. We therefore need to be able to request a resource and wait for it to be freed by whichever other SuperIO device currently hogs it. Right now you have to poll which is horrible. Add a MUXED field to IO port resources. If the MUXED field is set on the resource and on the request (via request_muxed_region) then we block until the previous owner of the muxed resource releases their region. This allows us to implement proper resource sharing and locking for superio chips using code of the form enable_my_superio_dev() { request_muxed_region(0x44, 0x02, "superio:watchdog"); outb() ..sequence to enable chip } disable_my_superio_dev() { outb() .. sequence of disable chip release_region(0x44, 0x02); } Signed-off-by: Giel van Schijndel <me@mortis.eu> Signed-off-by: Alan Cox <alan@linux.intel.com> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
-rw-r--r--include/linux/ioport.h4
-rw-r--r--kernel/resource.c16
2 files changed, 18 insertions, 2 deletions
diff --git a/include/linux/ioport.h b/include/linux/ioport.h
index 26fad187d661..b22790268b64 100644
--- a/include/linux/ioport.h
+++ b/include/linux/ioport.h
@@ -52,6 +52,7 @@ struct resource_list {
52 52
53#define IORESOURCE_MEM_64 0x00100000 53#define IORESOURCE_MEM_64 0x00100000
54#define IORESOURCE_WINDOW 0x00200000 /* forwarded by bridge */ 54#define IORESOURCE_WINDOW 0x00200000 /* forwarded by bridge */
55#define IORESOURCE_MUXED 0x00400000 /* Resource is software muxed */
55 56
56#define IORESOURCE_EXCLUSIVE 0x08000000 /* Userland may not map this resource */ 57#define IORESOURCE_EXCLUSIVE 0x08000000 /* Userland may not map this resource */
57#define IORESOURCE_DISABLED 0x10000000 58#define IORESOURCE_DISABLED 0x10000000
@@ -143,7 +144,8 @@ static inline unsigned long resource_type(const struct resource *res)
143} 144}
144 145
145/* Convenience shorthand with allocation */ 146/* Convenience shorthand with allocation */
146#define request_region(start,n,name) __request_region(&ioport_resource, (start), (n), (name), 0) 147#define request_region(start,n,name) __request_region(&ioport_resource, (start), (n), (name), 0)
148#define request_muxed_region(start,n,name) __request_region(&ioport_resource, (start), (n), (name), IORESOURCE_MUXED)
147#define __request_mem_region(start,n,name, excl) __request_region(&iomem_resource, (start), (n), (name), excl) 149#define __request_mem_region(start,n,name, excl) __request_region(&iomem_resource, (start), (n), (name), excl)
148#define request_mem_region(start,n,name) __request_region(&iomem_resource, (start), (n), (name), 0) 150#define request_mem_region(start,n,name) __request_region(&iomem_resource, (start), (n), (name), 0)
149#define request_mem_region_exclusive(start,n,name) \ 151#define request_mem_region_exclusive(start,n,name) \
diff --git a/kernel/resource.c b/kernel/resource.c
index 9c358e263534..7b36976e5dea 100644
--- a/kernel/resource.c
+++ b/kernel/resource.c
@@ -15,6 +15,7 @@
15#include <linux/spinlock.h> 15#include <linux/spinlock.h>
16#include <linux/fs.h> 16#include <linux/fs.h>
17#include <linux/proc_fs.h> 17#include <linux/proc_fs.h>
18#include <linux/sched.h>
18#include <linux/seq_file.h> 19#include <linux/seq_file.h>
19#include <linux/device.h> 20#include <linux/device.h>
20#include <linux/pfn.h> 21#include <linux/pfn.h>
@@ -681,6 +682,8 @@ resource_size_t resource_alignment(struct resource *res)
681 * release_region releases a matching busy region. 682 * release_region releases a matching busy region.
682 */ 683 */
683 684
685static DECLARE_WAIT_QUEUE_HEAD(muxed_resource_wait);
686
684/** 687/**
685 * __request_region - create a new busy resource region 688 * __request_region - create a new busy resource region
686 * @parent: parent resource descriptor 689 * @parent: parent resource descriptor
@@ -693,6 +696,7 @@ struct resource * __request_region(struct resource *parent,
693 resource_size_t start, resource_size_t n, 696 resource_size_t start, resource_size_t n,
694 const char *name, int flags) 697 const char *name, int flags)
695{ 698{
699 DECLARE_WAITQUEUE(wait, current);
696 struct resource *res = kzalloc(sizeof(*res), GFP_KERNEL); 700 struct resource *res = kzalloc(sizeof(*res), GFP_KERNEL);
697 701
698 if (!res) 702 if (!res)
@@ -717,7 +721,15 @@ struct resource * __request_region(struct resource *parent,
717 if (!(conflict->flags & IORESOURCE_BUSY)) 721 if (!(conflict->flags & IORESOURCE_BUSY))
718 continue; 722 continue;
719 } 723 }
720 724 if (conflict->flags & flags & IORESOURCE_MUXED) {
725 add_wait_queue(&muxed_resource_wait, &wait);
726 write_unlock(&resource_lock);
727 set_current_state(TASK_UNINTERRUPTIBLE);
728 schedule();
729 remove_wait_queue(&muxed_resource_wait, &wait);
730 write_lock(&resource_lock);
731 continue;
732 }
721 /* Uhhuh, that didn't work out.. */ 733 /* Uhhuh, that didn't work out.. */
722 kfree(res); 734 kfree(res);
723 res = NULL; 735 res = NULL;
@@ -791,6 +803,8 @@ void __release_region(struct resource *parent, resource_size_t start,
791 break; 803 break;
792 *p = res->sibling; 804 *p = res->sibling;
793 write_unlock(&resource_lock); 805 write_unlock(&resource_lock);
806 if (res->flags & IORESOURCE_MUXED)
807 wake_up(&muxed_resource_wait);
794 kfree(res); 808 kfree(res);
795 return; 809 return;
796 } 810 }