forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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 <[email protected]> Signed-off-by: Andi Kleen <[email protected]> Acked-by: Rene Herman <[email protected]> Signed-off-by: Len Brown <[email protected]>
- Loading branch information
Bjorn Helgaas
authored and
Andi Kleen
committed
Jul 16, 2008
1 parent
bbe413b
commit 1f32ca3
Showing
11 changed files
with
571 additions
and
634 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,8 @@ | ||
/* | ||
* Copyright (C) 2008 Hewlett-Packard Development Company, L.P. | ||
* Bjorn Helgaas <[email protected]> | ||
*/ | ||
|
||
extern spinlock_t pnp_lock; | ||
void *pnp_alloc(long size); | ||
|
||
|
@@ -25,8 +30,6 @@ struct pnp_port { | |
resource_size_t align; /* align boundary */ | ||
resource_size_t size; /* size of range */ | ||
unsigned char flags; /* port flags */ | ||
unsigned char pad; /* pad */ | ||
struct pnp_port *next; /* next port */ | ||
}; | ||
|
||
#define PNP_IRQ_NR 256 | ||
|
@@ -35,14 +38,11 @@ typedef struct { DECLARE_BITMAP(bits, PNP_IRQ_NR); } pnp_irq_mask_t; | |
struct pnp_irq { | ||
pnp_irq_mask_t map; /* bitmap for IRQ lines */ | ||
unsigned char flags; /* IRQ flags */ | ||
unsigned char pad; /* pad */ | ||
struct pnp_irq *next; /* next IRQ */ | ||
}; | ||
|
||
struct pnp_dma { | ||
unsigned char map; /* bitmask for DMA channels */ | ||
unsigned char flags; /* DMA flags */ | ||
struct pnp_dma *next; /* next port */ | ||
}; | ||
|
||
struct pnp_mem { | ||
|
@@ -51,44 +51,91 @@ struct pnp_mem { | |
resource_size_t align; /* align boundary */ | ||
resource_size_t size; /* size of range */ | ||
unsigned char flags; /* memory flags */ | ||
unsigned char pad; /* pad */ | ||
struct pnp_mem *next; /* next memory resource */ | ||
}; | ||
|
||
#define PNP_OPTION_DEPENDENT 0x80000000 | ||
#define PNP_OPTION_SET_MASK 0xffff | ||
#define PNP_OPTION_SET_SHIFT 12 | ||
#define PNP_OPTION_PRIORITY_MASK 0xfff | ||
#define PNP_OPTION_PRIORITY_SHIFT 0 | ||
|
||
#define PNP_RES_PRIORITY_PREFERRED 0 | ||
#define PNP_RES_PRIORITY_ACCEPTABLE 1 | ||
#define PNP_RES_PRIORITY_FUNCTIONAL 2 | ||
#define PNP_RES_PRIORITY_INVALID 65535 | ||
#define PNP_RES_PRIORITY_INVALID PNP_OPTION_PRIORITY_MASK | ||
|
||
struct pnp_option { | ||
unsigned short priority; /* priority */ | ||
struct pnp_port *port; /* first port */ | ||
struct pnp_irq *irq; /* first IRQ */ | ||
struct pnp_dma *dma; /* first DMA */ | ||
struct pnp_mem *mem; /* first memory resource */ | ||
struct pnp_option *next; /* used to chain dependent resources */ | ||
struct list_head list; | ||
unsigned int flags; /* independent/dependent, set, priority */ | ||
|
||
unsigned long type; /* IORESOURCE_{IO,MEM,IRQ,DMA} */ | ||
union { | ||
struct pnp_port port; | ||
struct pnp_irq irq; | ||
struct pnp_dma dma; | ||
struct pnp_mem mem; | ||
} u; | ||
}; | ||
|
||
struct pnp_option *pnp_build_option(int priority); | ||
struct pnp_option *pnp_register_independent_option(struct pnp_dev *dev); | ||
struct pnp_option *pnp_register_dependent_option(struct pnp_dev *dev, | ||
int priority); | ||
int pnp_register_irq_resource(struct pnp_dev *dev, struct pnp_option *option, | ||
int pnp_register_irq_resource(struct pnp_dev *dev, unsigned int option_flags, | ||
pnp_irq_mask_t *map, unsigned char flags); | ||
int pnp_register_dma_resource(struct pnp_dev *dev, struct pnp_option *option, | ||
int pnp_register_dma_resource(struct pnp_dev *dev, unsigned int option_flags, | ||
unsigned char map, unsigned char flags); | ||
int pnp_register_port_resource(struct pnp_dev *dev, struct pnp_option *option, | ||
int pnp_register_port_resource(struct pnp_dev *dev, unsigned int option_flags, | ||
resource_size_t min, resource_size_t max, | ||
resource_size_t align, resource_size_t size, | ||
unsigned char flags); | ||
int pnp_register_mem_resource(struct pnp_dev *dev, struct pnp_option *option, | ||
int pnp_register_mem_resource(struct pnp_dev *dev, unsigned int option_flags, | ||
resource_size_t min, resource_size_t max, | ||
resource_size_t align, resource_size_t size, | ||
unsigned char flags); | ||
|
||
static inline int pnp_option_is_dependent(struct pnp_option *option) | ||
{ | ||
return option->flags & PNP_OPTION_DEPENDENT ? 1 : 0; | ||
} | ||
|
||
static inline unsigned int pnp_option_set(struct pnp_option *option) | ||
{ | ||
return (option->flags >> PNP_OPTION_SET_SHIFT) & PNP_OPTION_SET_MASK; | ||
} | ||
|
||
static inline unsigned int pnp_option_priority(struct pnp_option *option) | ||
{ | ||
return (option->flags >> PNP_OPTION_PRIORITY_SHIFT) & | ||
PNP_OPTION_PRIORITY_MASK; | ||
} | ||
|
||
static inline unsigned int pnp_new_dependent_set(struct pnp_dev *dev, | ||
int priority) | ||
{ | ||
unsigned int flags; | ||
|
||
if (priority > PNP_RES_PRIORITY_FUNCTIONAL) { | ||
dev_warn(&dev->dev, "invalid dependent option priority %d " | ||
"clipped to %d", priority, | ||
PNP_RES_PRIORITY_INVALID); | ||
priority = PNP_RES_PRIORITY_INVALID; | ||
} | ||
|
||
flags = PNP_OPTION_DEPENDENT | | ||
((dev->num_dependent_sets & PNP_OPTION_SET_MASK) << | ||
PNP_OPTION_SET_SHIFT) | | ||
((priority & PNP_OPTION_PRIORITY_MASK) << | ||
PNP_OPTION_PRIORITY_SHIFT); | ||
|
||
dev->num_dependent_sets++; | ||
|
||
return flags; | ||
} | ||
|
||
char *pnp_option_priority_name(struct pnp_option *option); | ||
void dbg_pnp_show_option(struct pnp_dev *dev, struct pnp_option *option); | ||
|
||
void pnp_init_resources(struct pnp_dev *dev); | ||
|
||
void pnp_fixup_device(struct pnp_dev *dev); | ||
void pnp_free_option(struct pnp_option *option); | ||
void pnp_free_options(struct pnp_dev *dev); | ||
int __pnp_add_device(struct pnp_dev *dev); | ||
void __pnp_remove_device(struct pnp_dev *dev); | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,8 @@ | |
* | ||
* Some code, especially possible resource dumping is based on isapnp_proc.c (c) Jaroslav Kysela <[email protected]> | ||
* Copyright 2002 Adam Belay <[email protected]> | ||
* Copyright (C) 2008 Hewlett-Packard Development Company, L.P. | ||
* Bjorn Helgaas <[email protected]> | ||
*/ | ||
|
||
#include <linux/pnp.h> | ||
|
@@ -184,49 +186,32 @@ static void pnp_print_mem(pnp_info_buffer_t * buffer, char *space, | |
} | ||
|
||
static void pnp_print_option(pnp_info_buffer_t * buffer, char *space, | ||
struct pnp_option *option, int dep) | ||
struct pnp_option *option) | ||
{ | ||
char *s; | ||
struct pnp_port *port; | ||
struct pnp_irq *irq; | ||
struct pnp_dma *dma; | ||
struct pnp_mem *mem; | ||
|
||
if (dep) { | ||
switch (option->priority) { | ||
case PNP_RES_PRIORITY_PREFERRED: | ||
s = "preferred"; | ||
break; | ||
case PNP_RES_PRIORITY_ACCEPTABLE: | ||
s = "acceptable"; | ||
break; | ||
case PNP_RES_PRIORITY_FUNCTIONAL: | ||
s = "functional"; | ||
break; | ||
default: | ||
s = "invalid"; | ||
} | ||
pnp_printf(buffer, "Dependent: %02i - Priority %s\n", dep, s); | ||
switch (option->type) { | ||
case IORESOURCE_IO: | ||
pnp_print_port(buffer, space, &option->u.port); | ||
break; | ||
case IORESOURCE_MEM: | ||
pnp_print_mem(buffer, space, &option->u.mem); | ||
break; | ||
case IORESOURCE_IRQ: | ||
pnp_print_irq(buffer, space, &option->u.irq); | ||
break; | ||
case IORESOURCE_DMA: | ||
pnp_print_dma(buffer, space, &option->u.dma); | ||
break; | ||
} | ||
|
||
for (port = option->port; port; port = port->next) | ||
pnp_print_port(buffer, space, port); | ||
for (irq = option->irq; irq; irq = irq->next) | ||
pnp_print_irq(buffer, space, irq); | ||
for (dma = option->dma; dma; dma = dma->next) | ||
pnp_print_dma(buffer, space, dma); | ||
for (mem = option->mem; mem; mem = mem->next) | ||
pnp_print_mem(buffer, space, mem); | ||
} | ||
|
||
static ssize_t pnp_show_options(struct device *dmdev, | ||
struct device_attribute *attr, char *buf) | ||
{ | ||
struct pnp_dev *dev = to_pnp_dev(dmdev); | ||
pnp_info_buffer_t *buffer; | ||
struct pnp_option *independent = dev->independent; | ||
struct pnp_option *dependent = dev->dependent; | ||
int ret, dep = 1; | ||
struct pnp_option *option; | ||
int ret, dep = 0, set = 0; | ||
char *indent; | ||
|
||
buffer = pnp_alloc(sizeof(pnp_info_buffer_t)); | ||
if (!buffer) | ||
|
@@ -235,14 +220,24 @@ static ssize_t pnp_show_options(struct device *dmdev, | |
buffer->len = PAGE_SIZE; | ||
buffer->buffer = buf; | ||
buffer->curr = buffer->buffer; | ||
if (independent) | ||
pnp_print_option(buffer, "", independent, 0); | ||
|
||
while (dependent) { | ||
pnp_print_option(buffer, " ", dependent, dep); | ||
dependent = dependent->next; | ||
dep++; | ||
list_for_each_entry(option, &dev->options, list) { | ||
if (pnp_option_is_dependent(option)) { | ||
indent = " "; | ||
if (!dep || pnp_option_set(option) != set) { | ||
set = pnp_option_set(option); | ||
dep = 1; | ||
pnp_printf(buffer, "Dependent: %02i - " | ||
"Priority %s\n", set, | ||
pnp_option_priority_name(option)); | ||
} | ||
} else { | ||
dep = 0; | ||
indent = ""; | ||
} | ||
pnp_print_option(buffer, indent, option); | ||
} | ||
|
||
ret = (buffer->curr - buf); | ||
kfree(buffer); | ||
return ret; | ||
|
Oops, something went wrong.