aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pnp/base.h
diff options
context:
space:
mode:
authorBjorn Helgaas <bjorn.helgaas@hp.com>2008-06-27 18:57:17 -0400
committerAndi Kleen <andi@basil.nowhere.org>2008-07-16 17:27:07 -0400
commit1f32ca31e7409d37c1b25e5f81840fb184380cdf (patch)
treee587c85b46b04dbbb5987e2a4986ab174f3bd6fa /drivers/pnp/base.h
parentbbe413b4fc7f791248c7ee00ce7b3778491a3700 (diff)
PNP: convert resource options to single linked list
ISAPNP, PNPBIOS, and ACPI describe the "possible resource settings" of a device, i.e., the possibilities an OS bus driver has when it assigns I/O port, MMIO, and other resources to the device. PNP used to maintain this "possible resource setting" information in one independent option structure and a list of dependent option structures for each device. Each of these option structures had lists of I/O, memory, IRQ, and DMA resources, for example: dev independent options ind-io0 -> ind-io1 ... ind-mem0 -> ind-mem1 ... ... dependent option set 0 dep0-io0 -> dep0-io1 ... dep0-mem0 -> dep0-mem1 ... ... dependent option set 1 dep1-io0 -> dep1-io1 ... dep1-mem0 -> dep1-mem1 ... ... ... This data structure was designed for ISAPNP, where the OS configures device resource settings by writing directly to configuration registers. The OS can write the registers in arbitrary order much like it writes PCI BARs. However, for PNPBIOS and ACPI devices, the OS uses firmware interfaces that perform device configuration, and it is important to pass the desired settings to those interfaces in the correct order. The OS learns the correct order by using firmware interfaces that return the "current resource settings" and "possible resource settings," but the option structures above doesn't store the ordering information. This patch replaces the independent and dependent lists with a single list of options. For example, a device might have possible resource settings like this: dev options ind-io0 -> dep0-io0 -> dep1->io0 -> ind-io1 ... All the possible settings are in the same list, in the order they come from the firmware "possible resource settings" list. Each entry is tagged with an independent/dependent flag. Dependent entries also have a "set number" and an optional priority value. All dependent entries must be assigned from the same set. For example, the OS can use all the entries from dependent set 0, or all the entries from dependent set 1, but it cannot mix entries from set 0 with entries from set 1. Prior to this patch PNP didn't keep track of the order of this list, and it assigned all independent options first, then all dependent ones. Using the example above, that resulted in a "desired configuration" list like this: ind->io0 -> ind->io1 -> depN-io0 ... instead of the list the firmware expects, which looks like this: ind->io0 -> depN-io0 -> ind-io1 ... Signed-off-by: Bjorn Helgaas <bjorn.helgaas@hp.com> Signed-off-by: Andi Kleen <ak@linux.intel.com> Acked-by: Rene Herman <rene.herman@gmail.com> Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/pnp/base.h')
-rw-r--r--drivers/pnp/base.h93
1 files changed, 70 insertions, 23 deletions
diff --git a/drivers/pnp/base.h b/drivers/pnp/base.h
index 360c6385686c..e3fa9a2d9a3d 100644
--- a/drivers/pnp/base.h
+++ b/drivers/pnp/base.h
@@ -1,3 +1,8 @@
1/*
2 * Copyright (C) 2008 Hewlett-Packard Development Company, L.P.
3 * Bjorn Helgaas <bjorn.helgaas@hp.com>
4 */
5
1extern spinlock_t pnp_lock; 6extern spinlock_t pnp_lock;
2void *pnp_alloc(long size); 7void *pnp_alloc(long size);
3 8
@@ -25,8 +30,6 @@ struct pnp_port {
25 resource_size_t align; /* align boundary */ 30 resource_size_t align; /* align boundary */
26 resource_size_t size; /* size of range */ 31 resource_size_t size; /* size of range */
27 unsigned char flags; /* port flags */ 32 unsigned char flags; /* port flags */
28 unsigned char pad; /* pad */
29 struct pnp_port *next; /* next port */
30}; 33};
31 34
32#define PNP_IRQ_NR 256 35#define PNP_IRQ_NR 256
@@ -35,14 +38,11 @@ typedef struct { DECLARE_BITMAP(bits, PNP_IRQ_NR); } pnp_irq_mask_t;
35struct pnp_irq { 38struct pnp_irq {
36 pnp_irq_mask_t map; /* bitmap for IRQ lines */ 39 pnp_irq_mask_t map; /* bitmap for IRQ lines */
37 unsigned char flags; /* IRQ flags */ 40 unsigned char flags; /* IRQ flags */
38 unsigned char pad; /* pad */
39 struct pnp_irq *next; /* next IRQ */
40}; 41};
41 42
42struct pnp_dma { 43struct pnp_dma {
43 unsigned char map; /* bitmask for DMA channels */ 44 unsigned char map; /* bitmask for DMA channels */
44 unsigned char flags; /* DMA flags */ 45 unsigned char flags; /* DMA flags */
45 struct pnp_dma *next; /* next port */
46}; 46};
47 47
48struct pnp_mem { 48struct pnp_mem {
@@ -51,44 +51,91 @@ struct pnp_mem {
51 resource_size_t align; /* align boundary */ 51 resource_size_t align; /* align boundary */
52 resource_size_t size; /* size of range */ 52 resource_size_t size; /* size of range */
53 unsigned char flags; /* memory flags */ 53 unsigned char flags; /* memory flags */
54 unsigned char pad; /* pad */
55 struct pnp_mem *next; /* next memory resource */
56}; 54};
57 55
56#define PNP_OPTION_DEPENDENT 0x80000000
57#define PNP_OPTION_SET_MASK 0xffff
58#define PNP_OPTION_SET_SHIFT 12
59#define PNP_OPTION_PRIORITY_MASK 0xfff
60#define PNP_OPTION_PRIORITY_SHIFT 0
61
58#define PNP_RES_PRIORITY_PREFERRED 0 62#define PNP_RES_PRIORITY_PREFERRED 0
59#define PNP_RES_PRIORITY_ACCEPTABLE 1 63#define PNP_RES_PRIORITY_ACCEPTABLE 1
60#define PNP_RES_PRIORITY_FUNCTIONAL 2 64#define PNP_RES_PRIORITY_FUNCTIONAL 2
61#define PNP_RES_PRIORITY_INVALID 65535 65#define PNP_RES_PRIORITY_INVALID PNP_OPTION_PRIORITY_MASK
62 66
63struct pnp_option { 67struct pnp_option {
64 unsigned short priority; /* priority */ 68 struct list_head list;
65 struct pnp_port *port; /* first port */ 69 unsigned int flags; /* independent/dependent, set, priority */
66 struct pnp_irq *irq; /* first IRQ */ 70
67 struct pnp_dma *dma; /* first DMA */ 71 unsigned long type; /* IORESOURCE_{IO,MEM,IRQ,DMA} */
68 struct pnp_mem *mem; /* first memory resource */ 72 union {
69 struct pnp_option *next; /* used to chain dependent resources */ 73 struct pnp_port port;
74 struct pnp_irq irq;
75 struct pnp_dma dma;
76 struct pnp_mem mem;
77 } u;
70}; 78};
71 79
72struct pnp_option *pnp_build_option(int priority); 80int pnp_register_irq_resource(struct pnp_dev *dev, unsigned int option_flags,
73struct pnp_option *pnp_register_independent_option(struct pnp_dev *dev);
74struct pnp_option *pnp_register_dependent_option(struct pnp_dev *dev,
75 int priority);
76int pnp_register_irq_resource(struct pnp_dev *dev, struct pnp_option *option,
77 pnp_irq_mask_t *map, unsigned char flags); 81 pnp_irq_mask_t *map, unsigned char flags);
78int pnp_register_dma_resource(struct pnp_dev *dev, struct pnp_option *option, 82int pnp_register_dma_resource(struct pnp_dev *dev, unsigned int option_flags,
79 unsigned char map, unsigned char flags); 83 unsigned char map, unsigned char flags);
80int pnp_register_port_resource(struct pnp_dev *dev, struct pnp_option *option, 84int pnp_register_port_resource(struct pnp_dev *dev, unsigned int option_flags,
81 resource_size_t min, resource_size_t max, 85 resource_size_t min, resource_size_t max,
82 resource_size_t align, resource_size_t size, 86 resource_size_t align, resource_size_t size,
83 unsigned char flags); 87 unsigned char flags);
84int pnp_register_mem_resource(struct pnp_dev *dev, struct pnp_option *option, 88int pnp_register_mem_resource(struct pnp_dev *dev, unsigned int option_flags,
85 resource_size_t min, resource_size_t max, 89 resource_size_t min, resource_size_t max,
86 resource_size_t align, resource_size_t size, 90 resource_size_t align, resource_size_t size,
87 unsigned char flags); 91 unsigned char flags);
92
93static inline int pnp_option_is_dependent(struct pnp_option *option)
94{
95 return option->flags & PNP_OPTION_DEPENDENT ? 1 : 0;
96}
97
98static inline unsigned int pnp_option_set(struct pnp_option *option)
99{
100 return (option->flags >> PNP_OPTION_SET_SHIFT) & PNP_OPTION_SET_MASK;
101}
102
103static inline unsigned int pnp_option_priority(struct pnp_option *option)
104{
105 return (option->flags >> PNP_OPTION_PRIORITY_SHIFT) &
106 PNP_OPTION_PRIORITY_MASK;
107}
108
109static inline unsigned int pnp_new_dependent_set(struct pnp_dev *dev,
110 int priority)
111{
112 unsigned int flags;
113
114 if (priority > PNP_RES_PRIORITY_FUNCTIONAL) {
115 dev_warn(&dev->dev, "invalid dependent option priority %d "
116 "clipped to %d", priority,
117 PNP_RES_PRIORITY_INVALID);
118 priority = PNP_RES_PRIORITY_INVALID;
119 }
120
121 flags = PNP_OPTION_DEPENDENT |
122 ((dev->num_dependent_sets & PNP_OPTION_SET_MASK) <<
123 PNP_OPTION_SET_SHIFT) |
124 ((priority & PNP_OPTION_PRIORITY_MASK) <<
125 PNP_OPTION_PRIORITY_SHIFT);
126
127 dev->num_dependent_sets++;
128
129 return flags;
130}
131
132char *pnp_option_priority_name(struct pnp_option *option);
133void dbg_pnp_show_option(struct pnp_dev *dev, struct pnp_option *option);
134
88void pnp_init_resources(struct pnp_dev *dev); 135void pnp_init_resources(struct pnp_dev *dev);
89 136
90void pnp_fixup_device(struct pnp_dev *dev); 137void pnp_fixup_device(struct pnp_dev *dev);
91void pnp_free_option(struct pnp_option *option); 138void pnp_free_options(struct pnp_dev *dev);
92int __pnp_add_device(struct pnp_dev *dev); 139int __pnp_add_device(struct pnp_dev *dev);
93void __pnp_remove_device(struct pnp_dev *dev); 140void __pnp_remove_device(struct pnp_dev *dev);
94 141