Commit 40ac26f8 authored by Russell King's avatar Russell King

[PCMCIA] Use kernel resource core as primary resource allocator.

Turn the resource management on its head.  Rather than using PCMCIA's
resource database as the primary object to allocate resources, use
Linux's standard resource allocation instead.
 
When we have a socket on a PCI bus, we always use the PCI resource
allocation functions rather than the kernels core resource allocation,
so that we can take account of any bridges.
parent bdafa19e
...@@ -152,36 +152,6 @@ static void free_region(struct resource *res) ...@@ -152,36 +152,6 @@ static void free_region(struct resource *res)
} }
} }
static int request_io_resource(unsigned long b, unsigned long n,
char *name, struct pci_dev *dev)
{
struct resource *res = make_resource(b, n, IORESOURCE_IO, name);
struct resource *pr = resource_parent(b, n, IORESOURCE_IO, dev);
int err = -ENOMEM;
if (res) {
err = request_resource(pr, res);
if (err)
kfree(res);
}
return err;
}
static int request_mem_resource(unsigned long b, unsigned long n,
char *name, struct pci_dev *dev)
{
struct resource *res = make_resource(b, n, IORESOURCE_MEM, name);
struct resource *pr = resource_parent(b, n, IORESOURCE_MEM, dev);
int err = -ENOMEM;
if (res) {
err = request_resource(pr, res);
if (err)
kfree(res);
}
return err;
}
/*====================================================================== /*======================================================================
These manage the internal databases of available resources. These manage the internal databases of available resources.
...@@ -547,6 +517,68 @@ void validate_mem(struct pcmcia_socket *s) ...@@ -547,6 +517,68 @@ void validate_mem(struct pcmcia_socket *s)
#endif /* CONFIG_PCMCIA_PROBE */ #endif /* CONFIG_PCMCIA_PROBE */
struct pcmcia_align_data {
unsigned long mask;
unsigned long offset;
resource_map_t *map;
};
static void
pcmcia_common_align(void *align_data, struct resource *res,
unsigned long size, unsigned long align)
{
struct pcmcia_align_data *data = align_data;
unsigned long start;
/*
* Ensure that we have the correct start address
*/
start = (res->start & ~data->mask) + data->offset;
if (start < res->start)
start += data->mask + 1;
res->start = start;
}
static void
pcmcia_align(void *align_data, struct resource *res,
unsigned long size, unsigned long align)
{
struct pcmcia_align_data *data = align_data;
resource_map_t *m;
pcmcia_common_align(data, res, size, align);
for (m = data->map->next; m != data->map; m = m->next) {
unsigned long start = m->base;
unsigned long end = m->base + m->num;
/*
* If the lower resources are not available, try aligning
* to this entry of the resource database to see if it'll
* fit here.
*/
if (res->start < start) {
res->start = start;
pcmcia_common_align(data, res, size, align);
}
/*
* If we're above the area which was passed in, there's
* no point proceeding.
*/
if (res->start >= res->end)
break;
if ((res->start + size) <= end)
break;
}
/*
* If we failed to find something suitable, ensure we fail.
*/
if (m == data->map)
res->start = res->end;
}
/*====================================================================== /*======================================================================
These find ranges of I/O ports or memory addresses that are not These find ranges of I/O ports or memory addresses that are not
...@@ -563,66 +595,86 @@ void validate_mem(struct pcmcia_socket *s) ...@@ -563,66 +595,86 @@ void validate_mem(struct pcmcia_socket *s)
int find_io_region(ioaddr_t *base, ioaddr_t num, ioaddr_t align, int find_io_region(ioaddr_t *base, ioaddr_t num, ioaddr_t align,
char *name, struct pcmcia_socket *s) char *name, struct pcmcia_socket *s)
{ {
ioaddr_t try; struct resource *res = make_resource(0, num, IORESOURCE_IO, name);
resource_map_t *m; struct pcmcia_align_data data;
int ret = -1; unsigned long min = *base;
int ret;
down(&rsrc_sem); if (align == 0)
for (m = io_db.next; m != &io_db; m = m->next) { align = 0x10000UL;
try = (m->base & ~(align-1)) + *base;
for (try = (try >= m->base) ? try : try+align; data.mask = align - 1;
(try >= m->base) && (try+num <= m->base+m->num); data.offset = *base & data.mask;
try += align) { data.map = &io_db;
if (request_io_resource(try, num, name, s->cb_dev) == 0) {
*base = try; #ifdef CONFIG_PCI
ret = 0; if (s->cb_dev) {
goto out; ret = pci_bus_alloc_resource(s->cb_dev->bus, res, num, 1,
} min, 0, pcmcia_align, &data);
if (!align) } else
break; #endif
{
down(&rsrc_sem);
ret = allocate_resource(&ioport_resource, res, num, min, ~0UL, 0,
pcmcia_align, &data);
up(&rsrc_sem);
} }
}
out: if (ret != 0) {
up(&rsrc_sem); kfree(res);
return ret; } else {
*base = res->start;
}
return ret;
} }
int find_mem_region(u_long *base, u_long num, u_long align, int find_mem_region(u_long *base, u_long num, u_long align,
int low, char *name, struct pcmcia_socket *s) int low, char *name, struct pcmcia_socket *s)
{ {
u_long try; struct resource *res = make_resource(0, num, IORESOURCE_MEM, name);
resource_map_t *m; struct pcmcia_align_data data;
int ret = -1; unsigned long min, max;
int ret, i;
low = low || !(s->features & SS_CAP_PAGE_REGS); low = low || !(s->features & SS_CAP_PAGE_REGS);
down(&rsrc_sem); data.mask = align - 1;
while (1) { data.offset = *base & data.mask;
for (m = mem_db.next; m != &mem_db; m = m->next) { data.map = &mem_db;
/* first pass >1MB, second pass <1MB */
if ((low != 0) ^ (m->base < 0x100000)) for (i = 0; i < 2; i++) {
continue; if (low) {
max = 0x100000UL;
try = (m->base & ~(align-1)) + *base; min = *base < max ? *base : 0;
for (try = (try >= m->base) ? try : try+align; } else {
(try >= m->base) && (try+num <= m->base+m->num); max = ~0UL;
try += align) { min = 0x100000UL + *base;
if (request_mem_resource(try, num, name, s->cb_dev) == 0) {
*base = try;
ret = 0;
goto out;
} }
if (!align)
break; #ifdef CONFIG_PCI
} if (s->cb_dev) {
ret = pci_bus_alloc_resource(s->cb_dev->bus, res, num,
1, min, 0,
pcmcia_align, &data);
} else
#endif
{
down(&rsrc_sem);
ret = allocate_resource(&iomem_resource, res, num, min,
max, 0, pcmcia_align, &data);
up(&rsrc_sem);
}
if (ret == 0 || low)
break;
low = 1;
} }
if (low)
break; if (ret != 0) {
low++; kfree(res);
} } else {
out: *base = res->start;
up(&rsrc_sem); }
return ret; return ret;
} }
/*====================================================================== /*======================================================================
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment