2005-04-16 16:20:36 -06:00
|
|
|
/*
|
|
|
|
* resource.c - Contains functions for registering and analyzing resource information
|
|
|
|
*
|
2007-10-15 01:50:19 -06:00
|
|
|
* based on isapnp.c resource management (c) Jaroslav Kysela <perex@perex.cz>
|
2005-04-16 16:20:36 -06:00
|
|
|
* Copyright 2003 Adam Belay <ambx1@neo.rr.com>
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/module.h>
|
|
|
|
#include <linux/errno.h>
|
|
|
|
#include <linux/interrupt.h>
|
|
|
|
#include <linux/kernel.h>
|
|
|
|
#include <asm/io.h>
|
|
|
|
#include <asm/dma.h>
|
|
|
|
#include <asm/irq.h>
|
|
|
|
#include <linux/pci.h>
|
|
|
|
#include <linux/ioport.h>
|
|
|
|
#include <linux/init.h>
|
|
|
|
|
|
|
|
#include <linux/pnp.h>
|
|
|
|
#include "base.h"
|
|
|
|
|
2007-07-26 11:41:21 -06:00
|
|
|
static int pnp_reserve_irq[16] = {[0 ... 15] = -1 }; /* reserve (don't use) some IRQ */
|
|
|
|
static int pnp_reserve_dma[8] = {[0 ... 7] = -1 }; /* reserve (don't use) some DMA */
|
|
|
|
static int pnp_reserve_io[16] = {[0 ... 15] = -1 }; /* reserve (don't use) some I/O region */
|
|
|
|
static int pnp_reserve_mem[16] = {[0 ... 15] = -1 }; /* reserve (don't use) some memory region */
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
/*
|
|
|
|
* option registration
|
|
|
|
*/
|
|
|
|
|
2008-05-14 17:05:34 -06:00
|
|
|
struct pnp_option *pnp_build_option(int priority)
|
2005-04-16 16:20:36 -06:00
|
|
|
{
|
|
|
|
struct pnp_option *option = pnp_alloc(sizeof(struct pnp_option));
|
|
|
|
|
|
|
|
if (!option)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
option->priority = priority & 0xff;
|
|
|
|
/* make sure the priority is valid */
|
|
|
|
if (option->priority > PNP_RES_PRIORITY_FUNCTIONAL)
|
|
|
|
option->priority = PNP_RES_PRIORITY_INVALID;
|
|
|
|
|
|
|
|
return option;
|
|
|
|
}
|
|
|
|
|
2007-07-26 11:41:20 -06:00
|
|
|
struct pnp_option *pnp_register_independent_option(struct pnp_dev *dev)
|
2005-04-16 16:20:36 -06:00
|
|
|
{
|
|
|
|
struct pnp_option *option;
|
2007-07-26 11:41:21 -06:00
|
|
|
|
2005-04-16 16:20:36 -06:00
|
|
|
option = pnp_build_option(PNP_RES_PRIORITY_PREFERRED);
|
|
|
|
|
|
|
|
/* this should never happen but if it does we'll try to continue */
|
|
|
|
if (dev->independent)
|
2007-10-17 00:31:10 -06:00
|
|
|
dev_err(&dev->dev, "independent resource already registered\n");
|
2005-04-16 16:20:36 -06:00
|
|
|
dev->independent = option;
|
2008-04-28 16:34:04 -06:00
|
|
|
|
|
|
|
dev_dbg(&dev->dev, "new independent option\n");
|
2005-04-16 16:20:36 -06:00
|
|
|
return option;
|
|
|
|
}
|
|
|
|
|
2007-07-26 11:41:20 -06:00
|
|
|
struct pnp_option *pnp_register_dependent_option(struct pnp_dev *dev,
|
|
|
|
int priority)
|
2005-04-16 16:20:36 -06:00
|
|
|
{
|
|
|
|
struct pnp_option *option;
|
2007-07-26 11:41:21 -06:00
|
|
|
|
2005-04-16 16:20:36 -06:00
|
|
|
option = pnp_build_option(priority);
|
|
|
|
|
|
|
|
if (dev->dependent) {
|
|
|
|
struct pnp_option *parent = dev->dependent;
|
|
|
|
while (parent->next)
|
|
|
|
parent = parent->next;
|
|
|
|
parent->next = option;
|
|
|
|
} else
|
|
|
|
dev->dependent = option;
|
2008-04-28 16:34:04 -06:00
|
|
|
|
|
|
|
dev_dbg(&dev->dev, "new dependent option (priority %#x)\n", priority);
|
2005-04-16 16:20:36 -06:00
|
|
|
return option;
|
|
|
|
}
|
|
|
|
|
2008-04-28 16:34:04 -06:00
|
|
|
int pnp_register_irq_resource(struct pnp_dev *dev, struct pnp_option *option,
|
2008-06-27 16:57:11 -06:00
|
|
|
pnp_irq_mask_t *map, unsigned char flags)
|
2005-04-16 16:20:36 -06:00
|
|
|
{
|
2008-06-27 16:57:11 -06:00
|
|
|
struct pnp_irq *data, *ptr;
|
2008-04-28 16:34:04 -06:00
|
|
|
#ifdef DEBUG
|
|
|
|
char buf[PNP_IRQ_NR]; /* hex-encoded, so this is overkill but safe */
|
|
|
|
#endif
|
2007-07-26 11:41:21 -06:00
|
|
|
|
2008-06-27 16:57:11 -06:00
|
|
|
data = kzalloc(sizeof(struct pnp_irq), GFP_KERNEL);
|
|
|
|
if (!data)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
data->map = *map;
|
|
|
|
data->flags = flags;
|
|
|
|
|
2005-04-16 16:20:36 -06:00
|
|
|
ptr = option->irq;
|
|
|
|
while (ptr && ptr->next)
|
|
|
|
ptr = ptr->next;
|
|
|
|
if (ptr)
|
|
|
|
ptr->next = data;
|
|
|
|
else
|
|
|
|
option->irq = data;
|
|
|
|
|
|
|
|
#ifdef CONFIG_PCI
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < 16; i++)
|
2008-06-27 16:57:05 -06:00
|
|
|
if (test_bit(i, data->map.bits))
|
2005-03-31 22:07:31 -07:00
|
|
|
pcibios_penalize_isa_irq(i, 0);
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
|
|
|
#endif
|
2008-04-28 16:34:04 -06:00
|
|
|
|
|
|
|
#ifdef DEBUG
|
2008-06-27 16:57:05 -06:00
|
|
|
bitmap_scnprintf(buf, sizeof(buf), data->map.bits, PNP_IRQ_NR);
|
2008-04-28 16:34:04 -06:00
|
|
|
dev_dbg(&dev->dev, " irq bitmask %s flags %#x\n", buf,
|
|
|
|
data->flags);
|
|
|
|
#endif
|
2005-04-16 16:20:36 -06:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-04-28 16:34:04 -06:00
|
|
|
int pnp_register_dma_resource(struct pnp_dev *dev, struct pnp_option *option,
|
2008-06-27 16:57:11 -06:00
|
|
|
unsigned char map, unsigned char flags)
|
2005-04-16 16:20:36 -06:00
|
|
|
{
|
2008-06-27 16:57:11 -06:00
|
|
|
struct pnp_dma *data, *ptr;
|
|
|
|
|
|
|
|
data = kzalloc(sizeof(struct pnp_dma), GFP_KERNEL);
|
|
|
|
if (!data)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
data->map = map;
|
|
|
|
data->flags = flags;
|
2007-07-26 11:41:21 -06:00
|
|
|
|
2005-04-16 16:20:36 -06:00
|
|
|
ptr = option->dma;
|
|
|
|
while (ptr && ptr->next)
|
|
|
|
ptr = ptr->next;
|
|
|
|
if (ptr)
|
|
|
|
ptr->next = data;
|
|
|
|
else
|
|
|
|
option->dma = data;
|
|
|
|
|
2008-04-28 16:34:04 -06:00
|
|
|
dev_dbg(&dev->dev, " dma bitmask %#x flags %#x\n", data->map,
|
|
|
|
data->flags);
|
2005-04-16 16:20:36 -06:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-04-28 16:34:04 -06:00
|
|
|
int pnp_register_port_resource(struct pnp_dev *dev, struct pnp_option *option,
|
2008-06-27 16:57:11 -06:00
|
|
|
resource_size_t min, resource_size_t max,
|
|
|
|
resource_size_t align, resource_size_t size,
|
|
|
|
unsigned char flags)
|
2005-04-16 16:20:36 -06:00
|
|
|
{
|
2008-06-27 16:57:11 -06:00
|
|
|
struct pnp_port *data, *ptr;
|
|
|
|
|
|
|
|
data = kzalloc(sizeof(struct pnp_port), GFP_KERNEL);
|
|
|
|
if (!data)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
data->min = min;
|
|
|
|
data->max = max;
|
|
|
|
data->align = align;
|
|
|
|
data->size = size;
|
|
|
|
data->flags = flags;
|
2007-07-26 11:41:21 -06:00
|
|
|
|
2005-04-16 16:20:36 -06:00
|
|
|
ptr = option->port;
|
|
|
|
while (ptr && ptr->next)
|
|
|
|
ptr = ptr->next;
|
|
|
|
if (ptr)
|
|
|
|
ptr->next = data;
|
|
|
|
else
|
|
|
|
option->port = data;
|
|
|
|
|
2008-04-28 16:34:04 -06:00
|
|
|
dev_dbg(&dev->dev, " io "
|
2008-06-27 16:57:06 -06:00
|
|
|
"min %#llx max %#llx align %lld size %lld flags %#x\n",
|
|
|
|
(unsigned long long) data->min,
|
|
|
|
(unsigned long long) data->max,
|
|
|
|
(unsigned long long) data->align,
|
|
|
|
(unsigned long long) data->size, data->flags);
|
2005-04-16 16:20:36 -06:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-04-28 16:34:04 -06:00
|
|
|
int pnp_register_mem_resource(struct pnp_dev *dev, struct pnp_option *option,
|
2008-06-27 16:57:11 -06:00
|
|
|
resource_size_t min, resource_size_t max,
|
|
|
|
resource_size_t align, resource_size_t size,
|
|
|
|
unsigned char flags)
|
2005-04-16 16:20:36 -06:00
|
|
|
{
|
2008-06-27 16:57:11 -06:00
|
|
|
struct pnp_mem *data, *ptr;
|
|
|
|
|
|
|
|
data = kzalloc(sizeof(struct pnp_mem), GFP_KERNEL);
|
|
|
|
if (!data)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
data->min = min;
|
|
|
|
data->max = max;
|
|
|
|
data->align = align;
|
|
|
|
data->size = size;
|
|
|
|
data->flags = flags;
|
2007-07-26 11:41:21 -06:00
|
|
|
|
2005-04-16 16:20:36 -06:00
|
|
|
ptr = option->mem;
|
|
|
|
while (ptr && ptr->next)
|
|
|
|
ptr = ptr->next;
|
|
|
|
if (ptr)
|
|
|
|
ptr->next = data;
|
|
|
|
else
|
|
|
|
option->mem = data;
|
2008-04-28 16:34:04 -06:00
|
|
|
|
|
|
|
dev_dbg(&dev->dev, " mem "
|
2008-06-27 16:57:06 -06:00
|
|
|
"min %#llx max %#llx align %lld size %lld flags %#x\n",
|
|
|
|
(unsigned long long) data->min,
|
|
|
|
(unsigned long long) data->max,
|
|
|
|
(unsigned long long) data->align,
|
|
|
|
(unsigned long long) data->size, data->flags);
|
2005-04-16 16:20:36 -06:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void pnp_free_port(struct pnp_port *port)
|
|
|
|
{
|
|
|
|
struct pnp_port *next;
|
|
|
|
|
|
|
|
while (port) {
|
|
|
|
next = port->next;
|
|
|
|
kfree(port);
|
|
|
|
port = next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void pnp_free_irq(struct pnp_irq *irq)
|
|
|
|
{
|
|
|
|
struct pnp_irq *next;
|
|
|
|
|
|
|
|
while (irq) {
|
|
|
|
next = irq->next;
|
|
|
|
kfree(irq);
|
|
|
|
irq = next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void pnp_free_dma(struct pnp_dma *dma)
|
|
|
|
{
|
|
|
|
struct pnp_dma *next;
|
|
|
|
|
|
|
|
while (dma) {
|
|
|
|
next = dma->next;
|
|
|
|
kfree(dma);
|
|
|
|
dma = next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void pnp_free_mem(struct pnp_mem *mem)
|
|
|
|
{
|
|
|
|
struct pnp_mem *next;
|
|
|
|
|
|
|
|
while (mem) {
|
|
|
|
next = mem->next;
|
|
|
|
kfree(mem);
|
|
|
|
mem = next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void pnp_free_option(struct pnp_option *option)
|
|
|
|
{
|
|
|
|
struct pnp_option *next;
|
|
|
|
|
|
|
|
while (option) {
|
|
|
|
next = option->next;
|
|
|
|
pnp_free_port(option->port);
|
|
|
|
pnp_free_irq(option->irq);
|
|
|
|
pnp_free_dma(option->dma);
|
|
|
|
pnp_free_mem(option->mem);
|
|
|
|
kfree(option);
|
|
|
|
option = next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* resource validity checking
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define length(start, end) (*(end) - *(start) + 1)
|
|
|
|
|
|
|
|
/* Two ranges conflict if one doesn't end before the other starts */
|
|
|
|
#define ranged_conflict(starta, enda, startb, endb) \
|
|
|
|
!((*(enda) < *(startb)) || (*(endb) < *(starta)))
|
|
|
|
|
|
|
|
#define cannot_compare(flags) \
|
PNP: replace pnp_resource_table with dynamically allocated resources
PNP used to have a fixed-size pnp_resource_table for tracking the
resources used by a device. This table often overflowed, so we've
had to increase the table size, which wastes memory because most
devices have very few resources.
This patch replaces the table with a linked list of resources where
the entries are allocated on demand.
This removes messages like these:
pnpacpi: exceeded the max number of IO resources
00:01: too many I/O port resources
References:
http://bugzilla.kernel.org/show_bug.cgi?id=9535
http://bugzilla.kernel.org/show_bug.cgi?id=9740
http://lkml.org/lkml/2007/11/30/110
This patch also changes the way PNP uses the IORESOURCE_UNSET,
IORESOURCE_AUTO, and IORESOURCE_DISABLED flags.
Prior to this patch, the pnp_resource_table entries used the flags
like this:
IORESOURCE_UNSET
This table entry is unused and available for use. When this flag
is set, we shouldn't look at anything else in the resource structure.
This flag is set when a resource table entry is initialized.
IORESOURCE_AUTO
This resource was assigned automatically by pnp_assign_{io,mem,etc}().
This flag is set when a resource table entry is initialized and
cleared whenever we discover a resource setting by reading an ISAPNP
config register, parsing a PNPBIOS resource data stream, parsing an
ACPI _CRS list, or interpreting a sysfs "set" command.
Resources marked IORESOURCE_AUTO are reinitialized and marked as
IORESOURCE_UNSET by pnp_clean_resource_table() in these cases:
- before we attempt to assign resources automatically,
- if we fail to assign resources automatically,
- after disabling a device
IORESOURCE_DISABLED
Set by pnp_assign_{io,mem,etc}() when automatic assignment fails.
Also set by PNPBIOS and PNPACPI for:
- invalid IRQs or GSI registration failures
- invalid DMA channels
- I/O ports above 0x10000
- mem ranges with negative length
After this patch, there is no pnp_resource_table, and the resource list
entries use the flags like this:
IORESOURCE_UNSET
This flag is no longer used in PNP. Instead of keeping
IORESOURCE_UNSET entries in the resource list, we remove
entries from the list and free them.
IORESOURCE_AUTO
No change in meaning: it still means the resource was assigned
automatically by pnp_assign_{port,mem,etc}(), but these functions
now set the bit explicitly.
We still "clean" a device's resource list in the same places,
but rather than reinitializing IORESOURCE_AUTO entries, we
just remove them from the list.
Note that IORESOURCE_AUTO entries are always at the end of the
list, so removing them doesn't reorder other list entries.
This is because non-IORESOURCE_AUTO entries are added by the
ISAPNP, PNPBIOS, or PNPACPI "get resources" methods and by the
sysfs "set" command. In each of these cases, we completely free
the resource list first.
IORESOURCE_DISABLED
In addition to the cases where we used to set this flag, ISAPNP now
adds an IORESOURCE_DISABLED resource when it reads a configuration
register with a "disabled" value.
Signed-off-by: Bjorn Helgaas <bjorn.helgaas@hp.com>
Signed-off-by: Len Brown <len.brown@intel.com>
Signed-off-by: Andi Kleen <ak@linux.intel.com>
2008-06-27 16:56:57 -06:00
|
|
|
((flags) & IORESOURCE_DISABLED)
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2008-04-28 16:34:22 -06:00
|
|
|
int pnp_check_port(struct pnp_dev *dev, struct resource *res)
|
2005-04-16 16:20:36 -06:00
|
|
|
{
|
2008-04-28 16:34:17 -06:00
|
|
|
int i;
|
2005-04-16 16:20:36 -06:00
|
|
|
struct pnp_dev *tdev;
|
2008-04-28 16:34:22 -06:00
|
|
|
struct resource *tres;
|
2006-06-12 18:07:07 -06:00
|
|
|
resource_size_t *port, *end, *tport, *tend;
|
2007-07-26 11:41:21 -06:00
|
|
|
|
2008-04-28 16:34:19 -06:00
|
|
|
port = &res->start;
|
|
|
|
end = &res->end;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
/* if the resource doesn't exist, don't complain about it */
|
2008-04-28 16:34:19 -06:00
|
|
|
if (cannot_compare(res->flags))
|
2005-04-16 16:20:36 -06:00
|
|
|
return 1;
|
|
|
|
|
|
|
|
/* check if the resource is already in use, skip if the
|
|
|
|
* device is active because it itself may be in use */
|
2007-07-26 11:41:20 -06:00
|
|
|
if (!dev->active) {
|
|
|
|
if (__check_region(&ioport_resource, *port, length(port, end)))
|
2005-04-16 16:20:36 -06:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check if the resource is reserved */
|
2008-04-28 16:34:17 -06:00
|
|
|
for (i = 0; i < 8; i++) {
|
|
|
|
int rport = pnp_reserve_io[i << 1];
|
|
|
|
int rend = pnp_reserve_io[(i << 1) + 1] + rport - 1;
|
2007-07-26 11:41:20 -06:00
|
|
|
if (ranged_conflict(port, end, &rport, &rend))
|
2005-04-16 16:20:36 -06:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check for internal conflicts */
|
2008-04-28 16:34:26 -06:00
|
|
|
for (i = 0; (tres = pnp_get_resource(dev, IORESOURCE_IO, i)); i++) {
|
|
|
|
if (tres != res && tres->flags & IORESOURCE_IO) {
|
2008-04-28 16:34:19 -06:00
|
|
|
tport = &tres->start;
|
|
|
|
tend = &tres->end;
|
2007-07-26 11:41:20 -06:00
|
|
|
if (ranged_conflict(port, end, tport, tend))
|
2005-04-16 16:20:36 -06:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check for conflicts with other pnp devices */
|
|
|
|
pnp_for_each_dev(tdev) {
|
|
|
|
if (tdev == dev)
|
|
|
|
continue;
|
2008-04-28 16:34:26 -06:00
|
|
|
for (i = 0;
|
|
|
|
(tres = pnp_get_resource(tdev, IORESOURCE_IO, i));
|
|
|
|
i++) {
|
|
|
|
if (tres->flags & IORESOURCE_IO) {
|
2008-04-28 16:34:19 -06:00
|
|
|
if (cannot_compare(tres->flags))
|
2005-04-16 16:20:36 -06:00
|
|
|
continue;
|
2008-04-28 16:34:19 -06:00
|
|
|
tport = &tres->start;
|
|
|
|
tend = &tres->end;
|
2007-07-26 11:41:20 -06:00
|
|
|
if (ranged_conflict(port, end, tport, tend))
|
2005-04-16 16:20:36 -06:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2008-04-28 16:34:22 -06:00
|
|
|
int pnp_check_mem(struct pnp_dev *dev, struct resource *res)
|
2005-04-16 16:20:36 -06:00
|
|
|
{
|
2008-04-28 16:34:17 -06:00
|
|
|
int i;
|
2005-04-16 16:20:36 -06:00
|
|
|
struct pnp_dev *tdev;
|
2008-04-28 16:34:22 -06:00
|
|
|
struct resource *tres;
|
2006-06-12 18:07:07 -06:00
|
|
|
resource_size_t *addr, *end, *taddr, *tend;
|
2007-07-26 11:41:21 -06:00
|
|
|
|
2008-04-28 16:34:19 -06:00
|
|
|
addr = &res->start;
|
|
|
|
end = &res->end;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
/* if the resource doesn't exist, don't complain about it */
|
2008-04-28 16:34:19 -06:00
|
|
|
if (cannot_compare(res->flags))
|
2005-04-16 16:20:36 -06:00
|
|
|
return 1;
|
|
|
|
|
|
|
|
/* check if the resource is already in use, skip if the
|
|
|
|
* device is active because it itself may be in use */
|
2007-07-26 11:41:20 -06:00
|
|
|
if (!dev->active) {
|
|
|
|
if (check_mem_region(*addr, length(addr, end)))
|
2005-04-16 16:20:36 -06:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check if the resource is reserved */
|
2008-04-28 16:34:17 -06:00
|
|
|
for (i = 0; i < 8; i++) {
|
|
|
|
int raddr = pnp_reserve_mem[i << 1];
|
|
|
|
int rend = pnp_reserve_mem[(i << 1) + 1] + raddr - 1;
|
2007-07-26 11:41:20 -06:00
|
|
|
if (ranged_conflict(addr, end, &raddr, &rend))
|
2005-04-16 16:20:36 -06:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check for internal conflicts */
|
2008-04-28 16:34:26 -06:00
|
|
|
for (i = 0; (tres = pnp_get_resource(dev, IORESOURCE_MEM, i)); i++) {
|
|
|
|
if (tres != res && tres->flags & IORESOURCE_MEM) {
|
2008-04-28 16:34:19 -06:00
|
|
|
taddr = &tres->start;
|
|
|
|
tend = &tres->end;
|
2007-07-26 11:41:20 -06:00
|
|
|
if (ranged_conflict(addr, end, taddr, tend))
|
2005-04-16 16:20:36 -06:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check for conflicts with other pnp devices */
|
|
|
|
pnp_for_each_dev(tdev) {
|
|
|
|
if (tdev == dev)
|
|
|
|
continue;
|
2008-04-28 16:34:26 -06:00
|
|
|
for (i = 0;
|
|
|
|
(tres = pnp_get_resource(tdev, IORESOURCE_MEM, i));
|
|
|
|
i++) {
|
|
|
|
if (tres->flags & IORESOURCE_MEM) {
|
2008-04-28 16:34:19 -06:00
|
|
|
if (cannot_compare(tres->flags))
|
2005-04-16 16:20:36 -06:00
|
|
|
continue;
|
2008-04-28 16:34:19 -06:00
|
|
|
taddr = &tres->start;
|
|
|
|
tend = &tres->end;
|
2007-07-26 11:41:20 -06:00
|
|
|
if (ranged_conflict(addr, end, taddr, tend))
|
2005-04-16 16:20:36 -06:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
IRQ: Maintain regs pointer globally rather than passing to IRQ handlers
Maintain a per-CPU global "struct pt_regs *" variable which can be used instead
of passing regs around manually through all ~1800 interrupt handlers in the
Linux kernel.
The regs pointer is used in few places, but it potentially costs both stack
space and code to pass it around. On the FRV arch, removing the regs parameter
from all the genirq function results in a 20% speed up of the IRQ exit path
(ie: from leaving timer_interrupt() to leaving do_IRQ()).
Where appropriate, an arch may override the generic storage facility and do
something different with the variable. On FRV, for instance, the address is
maintained in GR28 at all times inside the kernel as part of general exception
handling.
Having looked over the code, it appears that the parameter may be handed down
through up to twenty or so layers of functions. Consider a USB character
device attached to a USB hub, attached to a USB controller that posts its
interrupts through a cascaded auxiliary interrupt controller. A character
device driver may want to pass regs to the sysrq handler through the input
layer which adds another few layers of parameter passing.
I've build this code with allyesconfig for x86_64 and i386. I've runtested the
main part of the code on FRV and i386, though I can't test most of the drivers.
I've also done partial conversion for powerpc and MIPS - these at least compile
with minimal configurations.
This will affect all archs. Mostly the changes should be relatively easy.
Take do_IRQ(), store the regs pointer at the beginning, saving the old one:
struct pt_regs *old_regs = set_irq_regs(regs);
And put the old one back at the end:
set_irq_regs(old_regs);
Don't pass regs through to generic_handle_irq() or __do_IRQ().
In timer_interrupt(), this sort of change will be necessary:
- update_process_times(user_mode(regs));
- profile_tick(CPU_PROFILING, regs);
+ update_process_times(user_mode(get_irq_regs()));
+ profile_tick(CPU_PROFILING);
I'd like to move update_process_times()'s use of get_irq_regs() into itself,
except that i386, alone of the archs, uses something other than user_mode().
Some notes on the interrupt handling in the drivers:
(*) input_dev() is now gone entirely. The regs pointer is no longer stored in
the input_dev struct.
(*) finish_unlinks() in drivers/usb/host/ohci-q.c needs checking. It does
something different depending on whether it's been supplied with a regs
pointer or not.
(*) Various IRQ handler function pointers have been moved to type
irq_handler_t.
Signed-Off-By: David Howells <dhowells@redhat.com>
(cherry picked from 1b16e7ac850969f38b375e511e3fa2f474a33867 commit)
2006-10-05 07:55:46 -06:00
|
|
|
static irqreturn_t pnp_test_handler(int irq, void *dev_id)
|
2005-04-16 16:20:36 -06:00
|
|
|
{
|
|
|
|
return IRQ_HANDLED;
|
|
|
|
}
|
|
|
|
|
2008-04-28 16:34:22 -06:00
|
|
|
int pnp_check_irq(struct pnp_dev *dev, struct resource *res)
|
2005-04-16 16:20:36 -06:00
|
|
|
{
|
2008-04-28 16:34:17 -06:00
|
|
|
int i;
|
2005-04-16 16:20:36 -06:00
|
|
|
struct pnp_dev *tdev;
|
2008-04-28 16:34:22 -06:00
|
|
|
struct resource *tres;
|
2008-04-28 16:34:19 -06:00
|
|
|
resource_size_t *irq;
|
|
|
|
|
|
|
|
irq = &res->start;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
/* if the resource doesn't exist, don't complain about it */
|
2008-04-28 16:34:19 -06:00
|
|
|
if (cannot_compare(res->flags))
|
2005-04-16 16:20:36 -06:00
|
|
|
return 1;
|
|
|
|
|
|
|
|
/* check if the resource is valid */
|
|
|
|
if (*irq < 0 || *irq > 15)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* check if the resource is reserved */
|
2008-04-28 16:34:17 -06:00
|
|
|
for (i = 0; i < 16; i++) {
|
|
|
|
if (pnp_reserve_irq[i] == *irq)
|
2005-04-16 16:20:36 -06:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check for internal conflicts */
|
2008-04-28 16:34:26 -06:00
|
|
|
for (i = 0; (tres = pnp_get_resource(dev, IORESOURCE_IRQ, i)); i++) {
|
|
|
|
if (tres != res && tres->flags & IORESOURCE_IRQ) {
|
2008-04-28 16:34:19 -06:00
|
|
|
if (tres->start == *irq)
|
2005-04-16 16:20:36 -06:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef CONFIG_PCI
|
|
|
|
/* check if the resource is being used by a pci device */
|
|
|
|
{
|
|
|
|
struct pci_dev *pci = NULL;
|
|
|
|
for_each_pci_dev(pci) {
|
2007-11-28 17:21:36 -07:00
|
|
|
if (pci->irq == *irq) {
|
|
|
|
pci_dev_put(pci);
|
2005-04-16 16:20:36 -06:00
|
|
|
return 0;
|
2007-11-28 17:21:36 -07:00
|
|
|
}
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* check if the resource is already in use, skip if the
|
|
|
|
* device is active because it itself may be in use */
|
2007-07-26 11:41:20 -06:00
|
|
|
if (!dev->active) {
|
2006-07-01 05:36:37 -06:00
|
|
|
if (request_irq(*irq, pnp_test_handler,
|
2007-07-26 11:41:20 -06:00
|
|
|
IRQF_DISABLED | IRQF_PROBE_SHARED, "pnp", NULL))
|
2005-04-16 16:20:36 -06:00
|
|
|
return 0;
|
|
|
|
free_irq(*irq, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check for conflicts with other pnp devices */
|
|
|
|
pnp_for_each_dev(tdev) {
|
|
|
|
if (tdev == dev)
|
|
|
|
continue;
|
2008-04-28 16:34:26 -06:00
|
|
|
for (i = 0;
|
|
|
|
(tres = pnp_get_resource(tdev, IORESOURCE_IRQ, i));
|
|
|
|
i++) {
|
|
|
|
if (tres->flags & IORESOURCE_IRQ) {
|
2008-04-28 16:34:19 -06:00
|
|
|
if (cannot_compare(tres->flags))
|
2005-04-16 16:20:36 -06:00
|
|
|
continue;
|
2008-04-28 16:34:19 -06:00
|
|
|
if (tres->start == *irq)
|
2005-04-16 16:20:36 -06:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2008-04-28 16:34:22 -06:00
|
|
|
int pnp_check_dma(struct pnp_dev *dev, struct resource *res)
|
2005-04-16 16:20:36 -06:00
|
|
|
{
|
|
|
|
#ifndef CONFIG_IA64
|
2008-04-28 16:34:17 -06:00
|
|
|
int i;
|
2005-04-16 16:20:36 -06:00
|
|
|
struct pnp_dev *tdev;
|
2008-04-28 16:34:22 -06:00
|
|
|
struct resource *tres;
|
2008-04-28 16:34:19 -06:00
|
|
|
resource_size_t *dma;
|
|
|
|
|
|
|
|
dma = &res->start;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
/* if the resource doesn't exist, don't complain about it */
|
2008-04-28 16:34:19 -06:00
|
|
|
if (cannot_compare(res->flags))
|
2005-04-16 16:20:36 -06:00
|
|
|
return 1;
|
|
|
|
|
|
|
|
/* check if the resource is valid */
|
|
|
|
if (*dma < 0 || *dma == 4 || *dma > 7)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* check if the resource is reserved */
|
2008-04-28 16:34:17 -06:00
|
|
|
for (i = 0; i < 8; i++) {
|
|
|
|
if (pnp_reserve_dma[i] == *dma)
|
2005-04-16 16:20:36 -06:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check for internal conflicts */
|
2008-04-28 16:34:26 -06:00
|
|
|
for (i = 0; (tres = pnp_get_resource(dev, IORESOURCE_DMA, i)); i++) {
|
|
|
|
if (tres != res && tres->flags & IORESOURCE_DMA) {
|
2008-04-28 16:34:19 -06:00
|
|
|
if (tres->start == *dma)
|
2005-04-16 16:20:36 -06:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check if the resource is already in use, skip if the
|
|
|
|
* device is active because it itself may be in use */
|
2007-07-26 11:41:20 -06:00
|
|
|
if (!dev->active) {
|
2005-04-16 16:20:36 -06:00
|
|
|
if (request_dma(*dma, "pnp"))
|
|
|
|
return 0;
|
|
|
|
free_dma(*dma);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check for conflicts with other pnp devices */
|
|
|
|
pnp_for_each_dev(tdev) {
|
|
|
|
if (tdev == dev)
|
|
|
|
continue;
|
2008-04-28 16:34:26 -06:00
|
|
|
for (i = 0;
|
|
|
|
(tres = pnp_get_resource(tdev, IORESOURCE_DMA, i));
|
|
|
|
i++) {
|
|
|
|
if (tres->flags & IORESOURCE_DMA) {
|
2008-04-28 16:34:19 -06:00
|
|
|
if (cannot_compare(tres->flags))
|
2005-04-16 16:20:36 -06:00
|
|
|
continue;
|
2008-04-28 16:34:19 -06:00
|
|
|
if (tres->start == *dma)
|
2005-04-16 16:20:36 -06:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
#else
|
2007-07-26 11:41:21 -06:00
|
|
|
/* IA64 does not have legacy DMA */
|
2005-04-16 16:20:36 -06:00
|
|
|
return 0;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2008-06-27 16:56:54 -06:00
|
|
|
int pnp_resource_type(struct resource *res)
|
|
|
|
{
|
|
|
|
return res->flags & (IORESOURCE_IO | IORESOURCE_MEM |
|
|
|
|
IORESOURCE_IRQ | IORESOURCE_DMA);
|
|
|
|
}
|
|
|
|
|
2008-04-28 16:34:31 -06:00
|
|
|
struct resource *pnp_get_resource(struct pnp_dev *dev,
|
|
|
|
unsigned int type, unsigned int num)
|
|
|
|
{
|
|
|
|
struct pnp_resource *pnp_res;
|
PNP: replace pnp_resource_table with dynamically allocated resources
PNP used to have a fixed-size pnp_resource_table for tracking the
resources used by a device. This table often overflowed, so we've
had to increase the table size, which wastes memory because most
devices have very few resources.
This patch replaces the table with a linked list of resources where
the entries are allocated on demand.
This removes messages like these:
pnpacpi: exceeded the max number of IO resources
00:01: too many I/O port resources
References:
http://bugzilla.kernel.org/show_bug.cgi?id=9535
http://bugzilla.kernel.org/show_bug.cgi?id=9740
http://lkml.org/lkml/2007/11/30/110
This patch also changes the way PNP uses the IORESOURCE_UNSET,
IORESOURCE_AUTO, and IORESOURCE_DISABLED flags.
Prior to this patch, the pnp_resource_table entries used the flags
like this:
IORESOURCE_UNSET
This table entry is unused and available for use. When this flag
is set, we shouldn't look at anything else in the resource structure.
This flag is set when a resource table entry is initialized.
IORESOURCE_AUTO
This resource was assigned automatically by pnp_assign_{io,mem,etc}().
This flag is set when a resource table entry is initialized and
cleared whenever we discover a resource setting by reading an ISAPNP
config register, parsing a PNPBIOS resource data stream, parsing an
ACPI _CRS list, or interpreting a sysfs "set" command.
Resources marked IORESOURCE_AUTO are reinitialized and marked as
IORESOURCE_UNSET by pnp_clean_resource_table() in these cases:
- before we attempt to assign resources automatically,
- if we fail to assign resources automatically,
- after disabling a device
IORESOURCE_DISABLED
Set by pnp_assign_{io,mem,etc}() when automatic assignment fails.
Also set by PNPBIOS and PNPACPI for:
- invalid IRQs or GSI registration failures
- invalid DMA channels
- I/O ports above 0x10000
- mem ranges with negative length
After this patch, there is no pnp_resource_table, and the resource list
entries use the flags like this:
IORESOURCE_UNSET
This flag is no longer used in PNP. Instead of keeping
IORESOURCE_UNSET entries in the resource list, we remove
entries from the list and free them.
IORESOURCE_AUTO
No change in meaning: it still means the resource was assigned
automatically by pnp_assign_{port,mem,etc}(), but these functions
now set the bit explicitly.
We still "clean" a device's resource list in the same places,
but rather than reinitializing IORESOURCE_AUTO entries, we
just remove them from the list.
Note that IORESOURCE_AUTO entries are always at the end of the
list, so removing them doesn't reorder other list entries.
This is because non-IORESOURCE_AUTO entries are added by the
ISAPNP, PNPBIOS, or PNPACPI "get resources" methods and by the
sysfs "set" command. In each of these cases, we completely free
the resource list first.
IORESOURCE_DISABLED
In addition to the cases where we used to set this flag, ISAPNP now
adds an IORESOURCE_DISABLED resource when it reads a configuration
register with a "disabled" value.
Signed-off-by: Bjorn Helgaas <bjorn.helgaas@hp.com>
Signed-off-by: Len Brown <len.brown@intel.com>
Signed-off-by: Andi Kleen <ak@linux.intel.com>
2008-06-27 16:56:57 -06:00
|
|
|
struct resource *res;
|
2008-04-28 16:34:31 -06:00
|
|
|
|
PNP: replace pnp_resource_table with dynamically allocated resources
PNP used to have a fixed-size pnp_resource_table for tracking the
resources used by a device. This table often overflowed, so we've
had to increase the table size, which wastes memory because most
devices have very few resources.
This patch replaces the table with a linked list of resources where
the entries are allocated on demand.
This removes messages like these:
pnpacpi: exceeded the max number of IO resources
00:01: too many I/O port resources
References:
http://bugzilla.kernel.org/show_bug.cgi?id=9535
http://bugzilla.kernel.org/show_bug.cgi?id=9740
http://lkml.org/lkml/2007/11/30/110
This patch also changes the way PNP uses the IORESOURCE_UNSET,
IORESOURCE_AUTO, and IORESOURCE_DISABLED flags.
Prior to this patch, the pnp_resource_table entries used the flags
like this:
IORESOURCE_UNSET
This table entry is unused and available for use. When this flag
is set, we shouldn't look at anything else in the resource structure.
This flag is set when a resource table entry is initialized.
IORESOURCE_AUTO
This resource was assigned automatically by pnp_assign_{io,mem,etc}().
This flag is set when a resource table entry is initialized and
cleared whenever we discover a resource setting by reading an ISAPNP
config register, parsing a PNPBIOS resource data stream, parsing an
ACPI _CRS list, or interpreting a sysfs "set" command.
Resources marked IORESOURCE_AUTO are reinitialized and marked as
IORESOURCE_UNSET by pnp_clean_resource_table() in these cases:
- before we attempt to assign resources automatically,
- if we fail to assign resources automatically,
- after disabling a device
IORESOURCE_DISABLED
Set by pnp_assign_{io,mem,etc}() when automatic assignment fails.
Also set by PNPBIOS and PNPACPI for:
- invalid IRQs or GSI registration failures
- invalid DMA channels
- I/O ports above 0x10000
- mem ranges with negative length
After this patch, there is no pnp_resource_table, and the resource list
entries use the flags like this:
IORESOURCE_UNSET
This flag is no longer used in PNP. Instead of keeping
IORESOURCE_UNSET entries in the resource list, we remove
entries from the list and free them.
IORESOURCE_AUTO
No change in meaning: it still means the resource was assigned
automatically by pnp_assign_{port,mem,etc}(), but these functions
now set the bit explicitly.
We still "clean" a device's resource list in the same places,
but rather than reinitializing IORESOURCE_AUTO entries, we
just remove them from the list.
Note that IORESOURCE_AUTO entries are always at the end of the
list, so removing them doesn't reorder other list entries.
This is because non-IORESOURCE_AUTO entries are added by the
ISAPNP, PNPBIOS, or PNPACPI "get resources" methods and by the
sysfs "set" command. In each of these cases, we completely free
the resource list first.
IORESOURCE_DISABLED
In addition to the cases where we used to set this flag, ISAPNP now
adds an IORESOURCE_DISABLED resource when it reads a configuration
register with a "disabled" value.
Signed-off-by: Bjorn Helgaas <bjorn.helgaas@hp.com>
Signed-off-by: Len Brown <len.brown@intel.com>
Signed-off-by: Andi Kleen <ak@linux.intel.com>
2008-06-27 16:56:57 -06:00
|
|
|
list_for_each_entry(pnp_res, &dev->resources, list) {
|
|
|
|
res = &pnp_res->res;
|
|
|
|
if (pnp_resource_type(res) == type && num-- == 0)
|
|
|
|
return res;
|
|
|
|
}
|
2008-04-28 16:34:31 -06:00
|
|
|
return NULL;
|
|
|
|
}
|
2008-04-28 16:34:14 -06:00
|
|
|
EXPORT_SYMBOL(pnp_get_resource);
|
|
|
|
|
PNP: replace pnp_resource_table with dynamically allocated resources
PNP used to have a fixed-size pnp_resource_table for tracking the
resources used by a device. This table often overflowed, so we've
had to increase the table size, which wastes memory because most
devices have very few resources.
This patch replaces the table with a linked list of resources where
the entries are allocated on demand.
This removes messages like these:
pnpacpi: exceeded the max number of IO resources
00:01: too many I/O port resources
References:
http://bugzilla.kernel.org/show_bug.cgi?id=9535
http://bugzilla.kernel.org/show_bug.cgi?id=9740
http://lkml.org/lkml/2007/11/30/110
This patch also changes the way PNP uses the IORESOURCE_UNSET,
IORESOURCE_AUTO, and IORESOURCE_DISABLED flags.
Prior to this patch, the pnp_resource_table entries used the flags
like this:
IORESOURCE_UNSET
This table entry is unused and available for use. When this flag
is set, we shouldn't look at anything else in the resource structure.
This flag is set when a resource table entry is initialized.
IORESOURCE_AUTO
This resource was assigned automatically by pnp_assign_{io,mem,etc}().
This flag is set when a resource table entry is initialized and
cleared whenever we discover a resource setting by reading an ISAPNP
config register, parsing a PNPBIOS resource data stream, parsing an
ACPI _CRS list, or interpreting a sysfs "set" command.
Resources marked IORESOURCE_AUTO are reinitialized and marked as
IORESOURCE_UNSET by pnp_clean_resource_table() in these cases:
- before we attempt to assign resources automatically,
- if we fail to assign resources automatically,
- after disabling a device
IORESOURCE_DISABLED
Set by pnp_assign_{io,mem,etc}() when automatic assignment fails.
Also set by PNPBIOS and PNPACPI for:
- invalid IRQs or GSI registration failures
- invalid DMA channels
- I/O ports above 0x10000
- mem ranges with negative length
After this patch, there is no pnp_resource_table, and the resource list
entries use the flags like this:
IORESOURCE_UNSET
This flag is no longer used in PNP. Instead of keeping
IORESOURCE_UNSET entries in the resource list, we remove
entries from the list and free them.
IORESOURCE_AUTO
No change in meaning: it still means the resource was assigned
automatically by pnp_assign_{port,mem,etc}(), but these functions
now set the bit explicitly.
We still "clean" a device's resource list in the same places,
but rather than reinitializing IORESOURCE_AUTO entries, we
just remove them from the list.
Note that IORESOURCE_AUTO entries are always at the end of the
list, so removing them doesn't reorder other list entries.
This is because non-IORESOURCE_AUTO entries are added by the
ISAPNP, PNPBIOS, or PNPACPI "get resources" methods and by the
sysfs "set" command. In each of these cases, we completely free
the resource list first.
IORESOURCE_DISABLED
In addition to the cases where we used to set this flag, ISAPNP now
adds an IORESOURCE_DISABLED resource when it reads a configuration
register with a "disabled" value.
Signed-off-by: Bjorn Helgaas <bjorn.helgaas@hp.com>
Signed-off-by: Len Brown <len.brown@intel.com>
Signed-off-by: Andi Kleen <ak@linux.intel.com>
2008-06-27 16:56:57 -06:00
|
|
|
static struct pnp_resource *pnp_new_resource(struct pnp_dev *dev)
|
2008-04-28 16:34:33 -06:00
|
|
|
{
|
|
|
|
struct pnp_resource *pnp_res;
|
|
|
|
|
PNP: replace pnp_resource_table with dynamically allocated resources
PNP used to have a fixed-size pnp_resource_table for tracking the
resources used by a device. This table often overflowed, so we've
had to increase the table size, which wastes memory because most
devices have very few resources.
This patch replaces the table with a linked list of resources where
the entries are allocated on demand.
This removes messages like these:
pnpacpi: exceeded the max number of IO resources
00:01: too many I/O port resources
References:
http://bugzilla.kernel.org/show_bug.cgi?id=9535
http://bugzilla.kernel.org/show_bug.cgi?id=9740
http://lkml.org/lkml/2007/11/30/110
This patch also changes the way PNP uses the IORESOURCE_UNSET,
IORESOURCE_AUTO, and IORESOURCE_DISABLED flags.
Prior to this patch, the pnp_resource_table entries used the flags
like this:
IORESOURCE_UNSET
This table entry is unused and available for use. When this flag
is set, we shouldn't look at anything else in the resource structure.
This flag is set when a resource table entry is initialized.
IORESOURCE_AUTO
This resource was assigned automatically by pnp_assign_{io,mem,etc}().
This flag is set when a resource table entry is initialized and
cleared whenever we discover a resource setting by reading an ISAPNP
config register, parsing a PNPBIOS resource data stream, parsing an
ACPI _CRS list, or interpreting a sysfs "set" command.
Resources marked IORESOURCE_AUTO are reinitialized and marked as
IORESOURCE_UNSET by pnp_clean_resource_table() in these cases:
- before we attempt to assign resources automatically,
- if we fail to assign resources automatically,
- after disabling a device
IORESOURCE_DISABLED
Set by pnp_assign_{io,mem,etc}() when automatic assignment fails.
Also set by PNPBIOS and PNPACPI for:
- invalid IRQs or GSI registration failures
- invalid DMA channels
- I/O ports above 0x10000
- mem ranges with negative length
After this patch, there is no pnp_resource_table, and the resource list
entries use the flags like this:
IORESOURCE_UNSET
This flag is no longer used in PNP. Instead of keeping
IORESOURCE_UNSET entries in the resource list, we remove
entries from the list and free them.
IORESOURCE_AUTO
No change in meaning: it still means the resource was assigned
automatically by pnp_assign_{port,mem,etc}(), but these functions
now set the bit explicitly.
We still "clean" a device's resource list in the same places,
but rather than reinitializing IORESOURCE_AUTO entries, we
just remove them from the list.
Note that IORESOURCE_AUTO entries are always at the end of the
list, so removing them doesn't reorder other list entries.
This is because non-IORESOURCE_AUTO entries are added by the
ISAPNP, PNPBIOS, or PNPACPI "get resources" methods and by the
sysfs "set" command. In each of these cases, we completely free
the resource list first.
IORESOURCE_DISABLED
In addition to the cases where we used to set this flag, ISAPNP now
adds an IORESOURCE_DISABLED resource when it reads a configuration
register with a "disabled" value.
Signed-off-by: Bjorn Helgaas <bjorn.helgaas@hp.com>
Signed-off-by: Len Brown <len.brown@intel.com>
Signed-off-by: Andi Kleen <ak@linux.intel.com>
2008-06-27 16:56:57 -06:00
|
|
|
pnp_res = kzalloc(sizeof(struct pnp_resource), GFP_KERNEL);
|
|
|
|
if (!pnp_res)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
list_add_tail(&pnp_res->list, &dev->resources);
|
|
|
|
return pnp_res;
|
2008-04-28 16:34:33 -06:00
|
|
|
}
|
|
|
|
|
2008-04-28 16:34:34 -06:00
|
|
|
struct pnp_resource *pnp_add_irq_resource(struct pnp_dev *dev, int irq,
|
|
|
|
int flags)
|
|
|
|
{
|
|
|
|
struct pnp_resource *pnp_res;
|
|
|
|
struct resource *res;
|
|
|
|
|
PNP: replace pnp_resource_table with dynamically allocated resources
PNP used to have a fixed-size pnp_resource_table for tracking the
resources used by a device. This table often overflowed, so we've
had to increase the table size, which wastes memory because most
devices have very few resources.
This patch replaces the table with a linked list of resources where
the entries are allocated on demand.
This removes messages like these:
pnpacpi: exceeded the max number of IO resources
00:01: too many I/O port resources
References:
http://bugzilla.kernel.org/show_bug.cgi?id=9535
http://bugzilla.kernel.org/show_bug.cgi?id=9740
http://lkml.org/lkml/2007/11/30/110
This patch also changes the way PNP uses the IORESOURCE_UNSET,
IORESOURCE_AUTO, and IORESOURCE_DISABLED flags.
Prior to this patch, the pnp_resource_table entries used the flags
like this:
IORESOURCE_UNSET
This table entry is unused and available for use. When this flag
is set, we shouldn't look at anything else in the resource structure.
This flag is set when a resource table entry is initialized.
IORESOURCE_AUTO
This resource was assigned automatically by pnp_assign_{io,mem,etc}().
This flag is set when a resource table entry is initialized and
cleared whenever we discover a resource setting by reading an ISAPNP
config register, parsing a PNPBIOS resource data stream, parsing an
ACPI _CRS list, or interpreting a sysfs "set" command.
Resources marked IORESOURCE_AUTO are reinitialized and marked as
IORESOURCE_UNSET by pnp_clean_resource_table() in these cases:
- before we attempt to assign resources automatically,
- if we fail to assign resources automatically,
- after disabling a device
IORESOURCE_DISABLED
Set by pnp_assign_{io,mem,etc}() when automatic assignment fails.
Also set by PNPBIOS and PNPACPI for:
- invalid IRQs or GSI registration failures
- invalid DMA channels
- I/O ports above 0x10000
- mem ranges with negative length
After this patch, there is no pnp_resource_table, and the resource list
entries use the flags like this:
IORESOURCE_UNSET
This flag is no longer used in PNP. Instead of keeping
IORESOURCE_UNSET entries in the resource list, we remove
entries from the list and free them.
IORESOURCE_AUTO
No change in meaning: it still means the resource was assigned
automatically by pnp_assign_{port,mem,etc}(), but these functions
now set the bit explicitly.
We still "clean" a device's resource list in the same places,
but rather than reinitializing IORESOURCE_AUTO entries, we
just remove them from the list.
Note that IORESOURCE_AUTO entries are always at the end of the
list, so removing them doesn't reorder other list entries.
This is because non-IORESOURCE_AUTO entries are added by the
ISAPNP, PNPBIOS, or PNPACPI "get resources" methods and by the
sysfs "set" command. In each of these cases, we completely free
the resource list first.
IORESOURCE_DISABLED
In addition to the cases where we used to set this flag, ISAPNP now
adds an IORESOURCE_DISABLED resource when it reads a configuration
register with a "disabled" value.
Signed-off-by: Bjorn Helgaas <bjorn.helgaas@hp.com>
Signed-off-by: Len Brown <len.brown@intel.com>
Signed-off-by: Andi Kleen <ak@linux.intel.com>
2008-06-27 16:56:57 -06:00
|
|
|
pnp_res = pnp_new_resource(dev);
|
2008-04-28 16:34:34 -06:00
|
|
|
if (!pnp_res) {
|
2008-06-27 16:56:59 -06:00
|
|
|
dev_err(&dev->dev, "can't add resource for IRQ %d\n", irq);
|
2008-04-28 16:34:34 -06:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
res = &pnp_res->res;
|
|
|
|
res->flags = IORESOURCE_IRQ | flags;
|
|
|
|
res->start = irq;
|
|
|
|
res->end = irq;
|
|
|
|
|
|
|
|
dev_dbg(&dev->dev, " add irq %d flags %#x\n", irq, flags);
|
|
|
|
return pnp_res;
|
|
|
|
}
|
|
|
|
|
2008-04-28 16:34:35 -06:00
|
|
|
struct pnp_resource *pnp_add_dma_resource(struct pnp_dev *dev, int dma,
|
|
|
|
int flags)
|
|
|
|
{
|
|
|
|
struct pnp_resource *pnp_res;
|
|
|
|
struct resource *res;
|
|
|
|
|
PNP: replace pnp_resource_table with dynamically allocated resources
PNP used to have a fixed-size pnp_resource_table for tracking the
resources used by a device. This table often overflowed, so we've
had to increase the table size, which wastes memory because most
devices have very few resources.
This patch replaces the table with a linked list of resources where
the entries are allocated on demand.
This removes messages like these:
pnpacpi: exceeded the max number of IO resources
00:01: too many I/O port resources
References:
http://bugzilla.kernel.org/show_bug.cgi?id=9535
http://bugzilla.kernel.org/show_bug.cgi?id=9740
http://lkml.org/lkml/2007/11/30/110
This patch also changes the way PNP uses the IORESOURCE_UNSET,
IORESOURCE_AUTO, and IORESOURCE_DISABLED flags.
Prior to this patch, the pnp_resource_table entries used the flags
like this:
IORESOURCE_UNSET
This table entry is unused and available for use. When this flag
is set, we shouldn't look at anything else in the resource structure.
This flag is set when a resource table entry is initialized.
IORESOURCE_AUTO
This resource was assigned automatically by pnp_assign_{io,mem,etc}().
This flag is set when a resource table entry is initialized and
cleared whenever we discover a resource setting by reading an ISAPNP
config register, parsing a PNPBIOS resource data stream, parsing an
ACPI _CRS list, or interpreting a sysfs "set" command.
Resources marked IORESOURCE_AUTO are reinitialized and marked as
IORESOURCE_UNSET by pnp_clean_resource_table() in these cases:
- before we attempt to assign resources automatically,
- if we fail to assign resources automatically,
- after disabling a device
IORESOURCE_DISABLED
Set by pnp_assign_{io,mem,etc}() when automatic assignment fails.
Also set by PNPBIOS and PNPACPI for:
- invalid IRQs or GSI registration failures
- invalid DMA channels
- I/O ports above 0x10000
- mem ranges with negative length
After this patch, there is no pnp_resource_table, and the resource list
entries use the flags like this:
IORESOURCE_UNSET
This flag is no longer used in PNP. Instead of keeping
IORESOURCE_UNSET entries in the resource list, we remove
entries from the list and free them.
IORESOURCE_AUTO
No change in meaning: it still means the resource was assigned
automatically by pnp_assign_{port,mem,etc}(), but these functions
now set the bit explicitly.
We still "clean" a device's resource list in the same places,
but rather than reinitializing IORESOURCE_AUTO entries, we
just remove them from the list.
Note that IORESOURCE_AUTO entries are always at the end of the
list, so removing them doesn't reorder other list entries.
This is because non-IORESOURCE_AUTO entries are added by the
ISAPNP, PNPBIOS, or PNPACPI "get resources" methods and by the
sysfs "set" command. In each of these cases, we completely free
the resource list first.
IORESOURCE_DISABLED
In addition to the cases where we used to set this flag, ISAPNP now
adds an IORESOURCE_DISABLED resource when it reads a configuration
register with a "disabled" value.
Signed-off-by: Bjorn Helgaas <bjorn.helgaas@hp.com>
Signed-off-by: Len Brown <len.brown@intel.com>
Signed-off-by: Andi Kleen <ak@linux.intel.com>
2008-06-27 16:56:57 -06:00
|
|
|
pnp_res = pnp_new_resource(dev);
|
2008-04-28 16:34:35 -06:00
|
|
|
if (!pnp_res) {
|
2008-06-27 16:56:59 -06:00
|
|
|
dev_err(&dev->dev, "can't add resource for DMA %d\n", dma);
|
2008-04-28 16:34:35 -06:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
res = &pnp_res->res;
|
|
|
|
res->flags = IORESOURCE_DMA | flags;
|
|
|
|
res->start = dma;
|
|
|
|
res->end = dma;
|
|
|
|
|
|
|
|
dev_dbg(&dev->dev, " add dma %d flags %#x\n", dma, flags);
|
|
|
|
return pnp_res;
|
|
|
|
}
|
|
|
|
|
2008-04-28 16:34:36 -06:00
|
|
|
struct pnp_resource *pnp_add_io_resource(struct pnp_dev *dev,
|
|
|
|
resource_size_t start,
|
|
|
|
resource_size_t end, int flags)
|
|
|
|
{
|
|
|
|
struct pnp_resource *pnp_res;
|
|
|
|
struct resource *res;
|
|
|
|
|
PNP: replace pnp_resource_table with dynamically allocated resources
PNP used to have a fixed-size pnp_resource_table for tracking the
resources used by a device. This table often overflowed, so we've
had to increase the table size, which wastes memory because most
devices have very few resources.
This patch replaces the table with a linked list of resources where
the entries are allocated on demand.
This removes messages like these:
pnpacpi: exceeded the max number of IO resources
00:01: too many I/O port resources
References:
http://bugzilla.kernel.org/show_bug.cgi?id=9535
http://bugzilla.kernel.org/show_bug.cgi?id=9740
http://lkml.org/lkml/2007/11/30/110
This patch also changes the way PNP uses the IORESOURCE_UNSET,
IORESOURCE_AUTO, and IORESOURCE_DISABLED flags.
Prior to this patch, the pnp_resource_table entries used the flags
like this:
IORESOURCE_UNSET
This table entry is unused and available for use. When this flag
is set, we shouldn't look at anything else in the resource structure.
This flag is set when a resource table entry is initialized.
IORESOURCE_AUTO
This resource was assigned automatically by pnp_assign_{io,mem,etc}().
This flag is set when a resource table entry is initialized and
cleared whenever we discover a resource setting by reading an ISAPNP
config register, parsing a PNPBIOS resource data stream, parsing an
ACPI _CRS list, or interpreting a sysfs "set" command.
Resources marked IORESOURCE_AUTO are reinitialized and marked as
IORESOURCE_UNSET by pnp_clean_resource_table() in these cases:
- before we attempt to assign resources automatically,
- if we fail to assign resources automatically,
- after disabling a device
IORESOURCE_DISABLED
Set by pnp_assign_{io,mem,etc}() when automatic assignment fails.
Also set by PNPBIOS and PNPACPI for:
- invalid IRQs or GSI registration failures
- invalid DMA channels
- I/O ports above 0x10000
- mem ranges with negative length
After this patch, there is no pnp_resource_table, and the resource list
entries use the flags like this:
IORESOURCE_UNSET
This flag is no longer used in PNP. Instead of keeping
IORESOURCE_UNSET entries in the resource list, we remove
entries from the list and free them.
IORESOURCE_AUTO
No change in meaning: it still means the resource was assigned
automatically by pnp_assign_{port,mem,etc}(), but these functions
now set the bit explicitly.
We still "clean" a device's resource list in the same places,
but rather than reinitializing IORESOURCE_AUTO entries, we
just remove them from the list.
Note that IORESOURCE_AUTO entries are always at the end of the
list, so removing them doesn't reorder other list entries.
This is because non-IORESOURCE_AUTO entries are added by the
ISAPNP, PNPBIOS, or PNPACPI "get resources" methods and by the
sysfs "set" command. In each of these cases, we completely free
the resource list first.
IORESOURCE_DISABLED
In addition to the cases where we used to set this flag, ISAPNP now
adds an IORESOURCE_DISABLED resource when it reads a configuration
register with a "disabled" value.
Signed-off-by: Bjorn Helgaas <bjorn.helgaas@hp.com>
Signed-off-by: Len Brown <len.brown@intel.com>
Signed-off-by: Andi Kleen <ak@linux.intel.com>
2008-06-27 16:56:57 -06:00
|
|
|
pnp_res = pnp_new_resource(dev);
|
2008-04-28 16:34:36 -06:00
|
|
|
if (!pnp_res) {
|
2008-06-27 16:56:59 -06:00
|
|
|
dev_err(&dev->dev, "can't add resource for IO %#llx-%#llx\n",
|
|
|
|
(unsigned long long) start,
|
|
|
|
(unsigned long long) end);
|
2008-04-28 16:34:36 -06:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
res = &pnp_res->res;
|
|
|
|
res->flags = IORESOURCE_IO | flags;
|
|
|
|
res->start = start;
|
|
|
|
res->end = end;
|
|
|
|
|
|
|
|
dev_dbg(&dev->dev, " add io %#llx-%#llx flags %#x\n",
|
|
|
|
(unsigned long long) start, (unsigned long long) end, flags);
|
|
|
|
return pnp_res;
|
|
|
|
}
|
|
|
|
|
2008-04-28 16:34:37 -06:00
|
|
|
struct pnp_resource *pnp_add_mem_resource(struct pnp_dev *dev,
|
|
|
|
resource_size_t start,
|
|
|
|
resource_size_t end, int flags)
|
|
|
|
{
|
|
|
|
struct pnp_resource *pnp_res;
|
|
|
|
struct resource *res;
|
|
|
|
|
PNP: replace pnp_resource_table with dynamically allocated resources
PNP used to have a fixed-size pnp_resource_table for tracking the
resources used by a device. This table often overflowed, so we've
had to increase the table size, which wastes memory because most
devices have very few resources.
This patch replaces the table with a linked list of resources where
the entries are allocated on demand.
This removes messages like these:
pnpacpi: exceeded the max number of IO resources
00:01: too many I/O port resources
References:
http://bugzilla.kernel.org/show_bug.cgi?id=9535
http://bugzilla.kernel.org/show_bug.cgi?id=9740
http://lkml.org/lkml/2007/11/30/110
This patch also changes the way PNP uses the IORESOURCE_UNSET,
IORESOURCE_AUTO, and IORESOURCE_DISABLED flags.
Prior to this patch, the pnp_resource_table entries used the flags
like this:
IORESOURCE_UNSET
This table entry is unused and available for use. When this flag
is set, we shouldn't look at anything else in the resource structure.
This flag is set when a resource table entry is initialized.
IORESOURCE_AUTO
This resource was assigned automatically by pnp_assign_{io,mem,etc}().
This flag is set when a resource table entry is initialized and
cleared whenever we discover a resource setting by reading an ISAPNP
config register, parsing a PNPBIOS resource data stream, parsing an
ACPI _CRS list, or interpreting a sysfs "set" command.
Resources marked IORESOURCE_AUTO are reinitialized and marked as
IORESOURCE_UNSET by pnp_clean_resource_table() in these cases:
- before we attempt to assign resources automatically,
- if we fail to assign resources automatically,
- after disabling a device
IORESOURCE_DISABLED
Set by pnp_assign_{io,mem,etc}() when automatic assignment fails.
Also set by PNPBIOS and PNPACPI for:
- invalid IRQs or GSI registration failures
- invalid DMA channels
- I/O ports above 0x10000
- mem ranges with negative length
After this patch, there is no pnp_resource_table, and the resource list
entries use the flags like this:
IORESOURCE_UNSET
This flag is no longer used in PNP. Instead of keeping
IORESOURCE_UNSET entries in the resource list, we remove
entries from the list and free them.
IORESOURCE_AUTO
No change in meaning: it still means the resource was assigned
automatically by pnp_assign_{port,mem,etc}(), but these functions
now set the bit explicitly.
We still "clean" a device's resource list in the same places,
but rather than reinitializing IORESOURCE_AUTO entries, we
just remove them from the list.
Note that IORESOURCE_AUTO entries are always at the end of the
list, so removing them doesn't reorder other list entries.
This is because non-IORESOURCE_AUTO entries are added by the
ISAPNP, PNPBIOS, or PNPACPI "get resources" methods and by the
sysfs "set" command. In each of these cases, we completely free
the resource list first.
IORESOURCE_DISABLED
In addition to the cases where we used to set this flag, ISAPNP now
adds an IORESOURCE_DISABLED resource when it reads a configuration
register with a "disabled" value.
Signed-off-by: Bjorn Helgaas <bjorn.helgaas@hp.com>
Signed-off-by: Len Brown <len.brown@intel.com>
Signed-off-by: Andi Kleen <ak@linux.intel.com>
2008-06-27 16:56:57 -06:00
|
|
|
pnp_res = pnp_new_resource(dev);
|
2008-04-28 16:34:37 -06:00
|
|
|
if (!pnp_res) {
|
2008-06-27 16:56:59 -06:00
|
|
|
dev_err(&dev->dev, "can't add resource for MEM %#llx-%#llx\n",
|
|
|
|
(unsigned long long) start,
|
|
|
|
(unsigned long long) end);
|
2008-04-28 16:34:37 -06:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
res = &pnp_res->res;
|
|
|
|
res->flags = IORESOURCE_MEM | flags;
|
|
|
|
res->start = start;
|
|
|
|
res->end = end;
|
|
|
|
|
|
|
|
dev_dbg(&dev->dev, " add mem %#llx-%#llx flags %#x\n",
|
|
|
|
(unsigned long long) start, (unsigned long long) end, flags);
|
|
|
|
return pnp_res;
|
|
|
|
}
|
|
|
|
|
2008-06-27 16:57:01 -06:00
|
|
|
static int pnp_possible_option(struct pnp_option *option, int type,
|
|
|
|
resource_size_t start, resource_size_t size)
|
|
|
|
{
|
|
|
|
struct pnp_option *tmp;
|
|
|
|
struct pnp_port *port;
|
|
|
|
struct pnp_mem *mem;
|
|
|
|
struct pnp_irq *irq;
|
|
|
|
struct pnp_dma *dma;
|
|
|
|
|
|
|
|
if (!option)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
for (tmp = option; tmp; tmp = tmp->next) {
|
|
|
|
switch (type) {
|
|
|
|
case IORESOURCE_IO:
|
|
|
|
for (port = tmp->port; port; port = port->next) {
|
|
|
|
if (port->min == start && port->size == size)
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case IORESOURCE_MEM:
|
|
|
|
for (mem = tmp->mem; mem; mem = mem->next) {
|
|
|
|
if (mem->min == start && mem->size == size)
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case IORESOURCE_IRQ:
|
|
|
|
for (irq = tmp->irq; irq; irq = irq->next) {
|
|
|
|
if (start < PNP_IRQ_NR &&
|
2008-06-27 16:57:05 -06:00
|
|
|
test_bit(start, irq->map.bits))
|
2008-06-27 16:57:01 -06:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case IORESOURCE_DMA:
|
|
|
|
for (dma = tmp->dma; dma; dma = dma->next) {
|
|
|
|
if (dma->map & (1 << start))
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Determine whether the specified resource is a possible configuration
|
|
|
|
* for this device.
|
|
|
|
*/
|
|
|
|
int pnp_possible_config(struct pnp_dev *dev, int type, resource_size_t start,
|
|
|
|
resource_size_t size)
|
|
|
|
{
|
|
|
|
if (pnp_possible_option(dev->independent, type, start, size))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
if (pnp_possible_option(dev->dependent, type, start, size))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(pnp_possible_config);
|
|
|
|
|
2005-04-16 16:20:36 -06:00
|
|
|
/* format is: pnp_reserve_irq=irq1[,irq2] .... */
|
|
|
|
static int __init pnp_setup_reserve_irq(char *str)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < 16; i++)
|
2007-07-26 11:41:20 -06:00
|
|
|
if (get_option(&str, &pnp_reserve_irq[i]) != 2)
|
2005-04-16 16:20:36 -06:00
|
|
|
break;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
__setup("pnp_reserve_irq=", pnp_setup_reserve_irq);
|
|
|
|
|
|
|
|
/* format is: pnp_reserve_dma=dma1[,dma2] .... */
|
|
|
|
static int __init pnp_setup_reserve_dma(char *str)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < 8; i++)
|
2007-07-26 11:41:20 -06:00
|
|
|
if (get_option(&str, &pnp_reserve_dma[i]) != 2)
|
2005-04-16 16:20:36 -06:00
|
|
|
break;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
__setup("pnp_reserve_dma=", pnp_setup_reserve_dma);
|
|
|
|
|
|
|
|
/* format is: pnp_reserve_io=io1,size1[,io2,size2] .... */
|
|
|
|
static int __init pnp_setup_reserve_io(char *str)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < 16; i++)
|
2007-07-26 11:41:20 -06:00
|
|
|
if (get_option(&str, &pnp_reserve_io[i]) != 2)
|
2005-04-16 16:20:36 -06:00
|
|
|
break;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
__setup("pnp_reserve_io=", pnp_setup_reserve_io);
|
|
|
|
|
|
|
|
/* format is: pnp_reserve_mem=mem1,size1[,mem2,size2] .... */
|
|
|
|
static int __init pnp_setup_reserve_mem(char *str)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < 16; i++)
|
2007-07-26 11:41:20 -06:00
|
|
|
if (get_option(&str, &pnp_reserve_mem[i]) != 2)
|
2005-04-16 16:20:36 -06:00
|
|
|
break;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
__setup("pnp_reserve_mem=", pnp_setup_reserve_mem);
|