Commit a7336008 authored by Russell King's avatar Russell King

[PCMCIA] Convert IO resource allocation to use struct resource.

This causes PCMCIA to use struct resource internally for IO resources.
This means that we can keep track of the resource pointer, expand
this resource if necessary, and use release_resource() on it when
we're done.

This eventually means that we can change these to normal resources
which aren't marked busy.
parent 7529d8a4
......@@ -789,9 +789,10 @@ static int alloc_io_space(struct pcmcia_socket *s, u_int attr, ioaddr_t *base,
return 1;
for (i = 0; i < MAX_IO_WIN; i++) {
if (s->io[i].NumPorts == 0) {
if (find_io_region(base, num, align, name, s) == 0) {
s->io[i].res = find_io_region(*base, num, align, name, s);
if (s->io[i].res) {
s->io[i].Attributes = attr;
s->io[i].BasePort = *base;
s->io[i].BasePort = *base = s->io[i].res->start;
s->io[i].NumPorts = s->io[i].InUse = num;
break;
} else
......@@ -801,7 +802,8 @@ static int alloc_io_space(struct pcmcia_socket *s, u_int attr, ioaddr_t *base,
/* Try to extend top of window */
try = s->io[i].BasePort + s->io[i].NumPorts;
if ((*base == 0) || (*base == try))
if (find_io_region(&try, num, 0, name, s) == 0) {
if (adjust_io_region(s->io[i].res, s->io[i].res->start,
s->io[i].res->end + num, s) == 0) {
*base = try;
s->io[i].NumPorts += num;
s->io[i].InUse += num;
......@@ -810,7 +812,8 @@ static int alloc_io_space(struct pcmcia_socket *s, u_int attr, ioaddr_t *base,
/* Try to extend bottom of window */
try = s->io[i].BasePort - num;
if ((*base == 0) || (*base == try))
if (find_io_region(&try, num, 0, name, s) == 0) {
if (adjust_io_region(s->io[i].res, s->io[i].res->start - num,
s->io[i].res->end, s) == 0) {
s->io[i].BasePort = *base = try;
s->io[i].NumPorts += num;
s->io[i].InUse += num;
......@@ -824,15 +827,18 @@ static void release_io_space(struct pcmcia_socket *s, ioaddr_t base,
ioaddr_t num)
{
int i;
if(!(s->features & SS_CAP_STATIC_MAP))
release_region(base, num);
for (i = 0; i < MAX_IO_WIN; i++) {
if ((s->io[i].BasePort <= base) &&
(s->io[i].BasePort+s->io[i].NumPorts >= base+num)) {
s->io[i].InUse -= num;
/* Free the window if no one else is using it */
if (s->io[i].InUse == 0)
if (s->io[i].InUse == 0) {
s->io[i].NumPorts = 0;
release_resource(s->io[i].res);
kfree(s->io[i].res);
s->io[i].res = NULL;
}
}
}
}
......
......@@ -181,8 +181,10 @@ int copy_memory(memory_handle_t handle, copy_op_t *req);
/* In rsrc_mgr */
void validate_mem(struct pcmcia_socket *s);
int find_io_region(ioaddr_t *base, ioaddr_t num, unsigned long align,
struct resource *find_io_region(unsigned long base, int num, unsigned long align,
char *name, struct pcmcia_socket *s);
int adjust_io_region(struct resource *res, unsigned long r_start,
unsigned long r_end, struct pcmcia_socket *s);
int find_mem_region(u_long *base, u_long num, u_long align,
int low, char *name, struct pcmcia_socket *s);
int try_irq(u_int Attributes, int irq, int specific);
......
......@@ -580,6 +580,32 @@ pcmcia_align(void *align_data, struct resource *res,
res->start = res->end;
}
/*
* Adjust an existing IO region allocation, but making sure that we don't
* encroach outside the resources which the user supplied.
*/
int adjust_io_region(struct resource *res, unsigned long r_start,
unsigned long r_end, struct pcmcia_socket *s)
{
resource_map_t *m;
int ret = -ENOMEM;
down(&rsrc_sem);
for (m = io_db.next; m != &io_db; m = m->next) {
unsigned long start = m->base;
unsigned long end = m->base + m->num - 1;
if (start > r_start || r_end > end)
continue;
ret = adjust_resource(res, r_start, r_end - r_start + 1);
break;
}
up(&rsrc_sem);
return ret;
}
/*======================================================================
These find ranges of I/O ports or memory addresses that are not
......@@ -593,19 +619,19 @@ pcmcia_align(void *align_data, struct resource *res,
======================================================================*/
int find_io_region(ioaddr_t *base, ioaddr_t num, unsigned long align,
char *name, struct pcmcia_socket *s)
struct resource *find_io_region(unsigned long base, int num,
unsigned long align, char *name, struct pcmcia_socket *s)
{
struct resource *res = make_resource(0, num, IORESOURCE_IO, name);
struct pcmcia_align_data data;
unsigned long min = *base;
unsigned long min = base;
int ret;
if (align == 0)
align = 0x10000;
data.mask = align - 1;
data.offset = *base & data.mask;
data.offset = base & data.mask;
data.map = &io_db;
down(&rsrc_sem);
......@@ -621,10 +647,9 @@ int find_io_region(ioaddr_t *base, ioaddr_t num, unsigned long align,
if (ret != 0) {
kfree(res);
} else {
*base = res->start;
res = NULL;
}
return ret;
return res;
}
int find_mem_region(u_long *base, u_long num, u_long align,
......
......@@ -145,6 +145,7 @@ typedef struct io_window_t {
u_int Attributes;
ioaddr_t BasePort, NumPorts;
ioaddr_t InUse, Config;
struct resource *res;
} io_window_t;
#define WINDOW_MAGIC 0xB35C
......
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