Commit 68da1c2a authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://bk.arm.linux.org.uk/linux-2.6-pcmcia

into ppc970.osdl.org:/home/torvalds/v2.6/linux
parents 9c2d00e7 a7336008
...@@ -789,9 +789,10 @@ static int alloc_io_space(struct pcmcia_socket *s, u_int attr, ioaddr_t *base, ...@@ -789,9 +789,10 @@ static int alloc_io_space(struct pcmcia_socket *s, u_int attr, ioaddr_t *base,
return 1; return 1;
for (i = 0; i < MAX_IO_WIN; i++) { for (i = 0; i < MAX_IO_WIN; i++) {
if (s->io[i].NumPorts == 0) { 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].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; s->io[i].NumPorts = s->io[i].InUse = num;
break; break;
} else } else
...@@ -801,7 +802,8 @@ static int alloc_io_space(struct pcmcia_socket *s, u_int attr, ioaddr_t *base, ...@@ -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 to extend top of window */
try = s->io[i].BasePort + s->io[i].NumPorts; try = s->io[i].BasePort + s->io[i].NumPorts;
if ((*base == 0) || (*base == try)) 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; *base = try;
s->io[i].NumPorts += num; s->io[i].NumPorts += num;
s->io[i].InUse += 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, ...@@ -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 to extend bottom of window */
try = s->io[i].BasePort - num; try = s->io[i].BasePort - num;
if ((*base == 0) || (*base == try)) 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].BasePort = *base = try;
s->io[i].NumPorts += num; s->io[i].NumPorts += num;
s->io[i].InUse += num; s->io[i].InUse += num;
...@@ -824,15 +827,18 @@ static void release_io_space(struct pcmcia_socket *s, ioaddr_t base, ...@@ -824,15 +827,18 @@ static void release_io_space(struct pcmcia_socket *s, ioaddr_t base,
ioaddr_t num) ioaddr_t num)
{ {
int i; int i;
if(!(s->features & SS_CAP_STATIC_MAP))
release_region(base, num);
for (i = 0; i < MAX_IO_WIN; i++) { for (i = 0; i < MAX_IO_WIN; i++) {
if ((s->io[i].BasePort <= base) && if ((s->io[i].BasePort <= base) &&
(s->io[i].BasePort+s->io[i].NumPorts >= base+num)) { (s->io[i].BasePort+s->io[i].NumPorts >= base+num)) {
s->io[i].InUse -= num; s->io[i].InUse -= num;
/* Free the window if no one else is using it */ /* 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; 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); ...@@ -181,8 +181,10 @@ int copy_memory(memory_handle_t handle, copy_op_t *req);
/* In rsrc_mgr */ /* In rsrc_mgr */
void validate_mem(struct pcmcia_socket *s); 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); 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 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);
int try_irq(u_int Attributes, int irq, int specific); int try_irq(u_int Attributes, int irq, int specific);
......
...@@ -550,7 +550,7 @@ pcmcia_align(void *align_data, struct resource *res, ...@@ -550,7 +550,7 @@ pcmcia_align(void *align_data, struct resource *res,
for (m = data->map->next; m != data->map; m = m->next) { for (m = data->map->next; m != data->map; m = m->next) {
unsigned long start = m->base; unsigned long start = m->base;
unsigned long end = m->base + m->num; unsigned long end = m->base + m->num - 1;
/* /*
* If the lower resources are not available, try aligning * If the lower resources are not available, try aligning
...@@ -569,7 +569,7 @@ pcmcia_align(void *align_data, struct resource *res, ...@@ -569,7 +569,7 @@ pcmcia_align(void *align_data, struct resource *res,
if (res->start >= res->end) if (res->start >= res->end)
break; break;
if ((res->start + size) <= end) if ((res->start + size - 1) <= end)
break; break;
} }
...@@ -580,6 +580,32 @@ pcmcia_align(void *align_data, struct resource *res, ...@@ -580,6 +580,32 @@ pcmcia_align(void *align_data, struct resource *res,
res->start = res->end; 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 These find ranges of I/O ports or memory addresses that are not
...@@ -593,40 +619,37 @@ pcmcia_align(void *align_data, struct resource *res, ...@@ -593,40 +619,37 @@ pcmcia_align(void *align_data, struct resource *res,
======================================================================*/ ======================================================================*/
int find_io_region(ioaddr_t *base, ioaddr_t num, unsigned long align, struct resource *find_io_region(unsigned long base, int num,
char *name, struct pcmcia_socket *s) unsigned long align, char *name, struct pcmcia_socket *s)
{ {
struct resource *res = make_resource(0, num, IORESOURCE_IO, name); struct resource *res = make_resource(0, num, IORESOURCE_IO, name);
struct pcmcia_align_data data; struct pcmcia_align_data data;
unsigned long min = *base; unsigned long min = base;
int ret; int ret;
if (align == 0) if (align == 0)
align = 0x10000; align = 0x10000;
data.mask = align - 1; data.mask = align - 1;
data.offset = *base & data.mask; data.offset = base & data.mask;
data.map = &io_db; data.map = &io_db;
down(&rsrc_sem);
#ifdef CONFIG_PCI #ifdef CONFIG_PCI
if (s->cb_dev) { if (s->cb_dev) {
ret = pci_bus_alloc_resource(s->cb_dev->bus, res, num, 1, ret = pci_bus_alloc_resource(s->cb_dev->bus, res, num, 1,
min, 0, pcmcia_align, &data); min, 0, pcmcia_align, &data);
} else } else
#endif #endif
{
down(&rsrc_sem);
ret = allocate_resource(&ioport_resource, res, num, min, ~0UL, 0, ret = allocate_resource(&ioport_resource, res, num, min, ~0UL, 0,
pcmcia_align, &data); pcmcia_align, &data);
up(&rsrc_sem); up(&rsrc_sem);
}
if (ret != 0) { if (ret != 0) {
kfree(res); kfree(res);
} else { res = NULL;
*base = res->start;
} }
return ret; return res;
} }
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,
...@@ -652,6 +675,7 @@ int find_mem_region(u_long *base, u_long num, u_long align, ...@@ -652,6 +675,7 @@ int find_mem_region(u_long *base, u_long num, u_long align,
min = 0x100000UL + *base; min = 0x100000UL + *base;
} }
down(&rsrc_sem);
#ifdef CONFIG_PCI #ifdef CONFIG_PCI
if (s->cb_dev) { if (s->cb_dev) {
ret = pci_bus_alloc_resource(s->cb_dev->bus, res, num, ret = pci_bus_alloc_resource(s->cb_dev->bus, res, num,
...@@ -659,12 +683,9 @@ int find_mem_region(u_long *base, u_long num, u_long align, ...@@ -659,12 +683,9 @@ int find_mem_region(u_long *base, u_long num, u_long align,
pcmcia_align, &data); pcmcia_align, &data);
} else } else
#endif #endif
{
down(&rsrc_sem);
ret = allocate_resource(&iomem_resource, res, num, min, ret = allocate_resource(&iomem_resource, res, num, min,
max, 0, pcmcia_align, &data); max, 0, pcmcia_align, &data);
up(&rsrc_sem); up(&rsrc_sem);
}
if (ret == 0 || low) if (ret == 0 || low)
break; break;
low = 1; low = 1;
......
...@@ -145,6 +145,7 @@ typedef struct io_window_t { ...@@ -145,6 +145,7 @@ typedef struct io_window_t {
u_int Attributes; u_int Attributes;
ioaddr_t BasePort, NumPorts; ioaddr_t BasePort, NumPorts;
ioaddr_t InUse, Config; ioaddr_t InUse, Config;
struct resource *res;
} io_window_t; } io_window_t;
#define WINDOW_MAGIC 0xB35C #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