Commit 85ca9b27 authored by Linus Torvalds's avatar Linus Torvalds

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

into home.transmeta.com:/home/torvalds/v2.5/linux
parents 1bc211f1 1fe184c8
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
# #
obj-$(CONFIG_PCMCIA) += pcmcia_core.o ds.o obj-$(CONFIG_PCMCIA) += pcmcia_core.o ds.o
obj-$(CONFIG_YENTA) += yenta.o obj-$(CONFIG_YENTA) += yenta_socket.o
obj-$(CONFIG_I82365) += i82365.o obj-$(CONFIG_I82365) += i82365.o
obj-$(CONFIG_I82092) += i82092.o obj-$(CONFIG_I82092) += i82092.o
......
...@@ -106,11 +106,10 @@ set_cis_map(struct pcmcia_socket *s, unsigned int card_offset, unsigned int flag ...@@ -106,11 +106,10 @@ set_cis_map(struct pcmcia_socket *s, unsigned int card_offset, unsigned int flag
pccard_mem_map *mem = &s->cis_mem; pccard_mem_map *mem = &s->cis_mem;
if (!(s->features & SS_CAP_STATIC_MAP) && if (!(s->features & SS_CAP_STATIC_MAP) &&
mem->sys_start == 0) { mem->sys_start == 0) {
int low = !(s->features & SS_CAP_PAGE_REGS);
validate_mem(s); validate_mem(s);
mem->sys_start = 0; mem->sys_start = 0;
if (find_mem_region(&mem->sys_start, s->map_size, if (find_mem_region(&mem->sys_start, s->map_size,
s->map_size, low, "card services", s)) { s->map_size, 0, "card services", s)) {
printk(KERN_NOTICE "cs: unable to map card memory!\n"); printk(KERN_NOTICE "cs: unable to map card memory!\n");
return NULL; return NULL;
} }
......
...@@ -816,7 +816,8 @@ static int pccardd(void *__skt) ...@@ -816,7 +816,8 @@ static int pccardd(void *__skt)
if ((skt->state & SOCKET_PRESENT) && if ((skt->state & SOCKET_PRESENT) &&
!(status & SS_DETECT)) !(status & SS_DETECT))
socket_shutdown(skt); socket_shutdown(skt);
if (status & SS_DETECT) if (!(skt->state & SOCKET_PRESENT) &&
(status & SS_DETECT))
socket_insert(skt); socket_insert(skt);
} }
if (events & SS_BATDEAD) if (events & SS_BATDEAD)
...@@ -2043,8 +2044,7 @@ int pcmcia_request_window(client_handle_t *handle, win_req_t *req, window_handle ...@@ -2043,8 +2044,7 @@ int pcmcia_request_window(client_handle_t *handle, win_req_t *req, window_handle
if (!(s->features & SS_CAP_STATIC_MAP) && if (!(s->features & SS_CAP_STATIC_MAP) &&
find_mem_region(&win->base, win->size, align, find_mem_region(&win->base, win->size, align,
(req->Attributes & WIN_MAP_BELOW_1MB) || (req->Attributes & WIN_MAP_BELOW_1MB),
!(s->features & SS_CAP_PAGE_REGS),
(*handle)->dev_info, s)) (*handle)->dev_info, s))
return CS_IN_USE; return CS_IN_USE;
(*handle)->state |= CLIENT_WIN_REQ(w); (*handle)->state |= CLIENT_WIN_REQ(w);
......
...@@ -168,7 +168,7 @@ void validate_mem(struct pcmcia_socket *s); ...@@ -168,7 +168,7 @@ 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);
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 force_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);
void undo_irq(u_int Attributes, int irq); void undo_irq(u_int Attributes, int irq);
int adjust_resource_info(client_handle_t handle, adjust_t *adj); int adjust_resource_info(client_handle_t handle, adjust_t *adj);
......
...@@ -139,22 +139,6 @@ static inline int check_io_resource(unsigned long b, unsigned long n, ...@@ -139,22 +139,6 @@ static inline int check_io_resource(unsigned long b, unsigned long n,
return 0; return 0;
} }
/* FIXME: Fundamentally racy. */
static inline int check_mem_resource(unsigned long b, unsigned long n,
struct pci_dev *dev)
{
struct resource *region;
region = __request_region(resource_parent(b, n, IORESOURCE_MEM, dev),
b, n, "check_mem_resource");
if (!region)
return -EBUSY;
release_resource(region);
kfree(region);
return 0;
}
static struct resource *make_resource(unsigned long b, unsigned long n, static struct resource *make_resource(unsigned long b, unsigned long n,
int flags, char *name) int flags, char *name)
{ {
...@@ -340,52 +324,103 @@ static void do_io_probe(ioaddr_t base, ioaddr_t num) ...@@ -340,52 +324,103 @@ static void do_io_probe(ioaddr_t base, ioaddr_t num)
======================================================================*/ ======================================================================*/
/* Validation function for cards with a valid CIS */ /* Validation function for cards with a valid CIS */
static int cis_readable(struct pcmcia_socket *s, u_long base) static int readable(struct pcmcia_socket *s, struct resource *res, cisinfo_t *info)
{ {
cisinfo_t info1, info2; int ret = -1;
int ret;
s->cis_mem.sys_start = base; s->cis_mem.sys_start = res->start;
s->cis_mem.sys_stop = base+s->map_size-1; s->cis_mem.sys_stop = res->end;
s->cis_virt = ioremap(base, s->map_size); s->cis_virt = ioremap(res->start, s->map_size);
ret = pcmcia_validate_cis(s->clients, &info1); if (s->cis_virt) {
/* invalidate mapping and CIS cache */ ret = pcmcia_validate_cis(s->clients, info);
iounmap(s->cis_virt); /* invalidate mapping and CIS cache */
destroy_cis_cache(s); iounmap(s->cis_virt);
if ((ret != 0) || (info1.Chains == 0)) s->cis_virt = NULL;
return 0; destroy_cis_cache(s);
s->cis_mem.sys_start = base+s->map_size; }
s->cis_mem.sys_stop = base+2*s->map_size-1; s->cis_mem.sys_start = 0;
s->cis_virt = ioremap(base+s->map_size, s->map_size); s->cis_mem.sys_stop = 0;
ret = pcmcia_validate_cis(s->clients, &info2); if ((ret != 0) || (info->Chains == 0))
iounmap(s->cis_virt); return 0;
destroy_cis_cache(s); return 1;
return ((ret == 0) && (info1.Chains == info2.Chains));
} }
/* Validation function for simple memory cards */ /* Validation function for simple memory cards */
static int checksum(struct pcmcia_socket *s, u_long base) static int checksum(struct pcmcia_socket *s, struct resource *res)
{ {
int i, a, b, d; pccard_mem_map map;
s->cis_mem.sys_start = base; int i, a = 0, b = -1, d;
s->cis_mem.sys_stop = base+s->map_size-1; void *virt;
s->cis_virt = ioremap(base, s->map_size);
s->cis_mem.card_start = 0; virt = ioremap(res->start, s->map_size);
s->cis_mem.flags = MAP_ACTIVE; if (virt) {
s->ss_entry->set_mem_map(s, &s->cis_mem); map.map = 0;
/* Don't bother checking every word... */ map.flags = MAP_ACTIVE;
a = 0; b = -1; map.speed = 0;
for (i = 0; i < s->map_size; i += 44) { map.sys_start = res->start;
d = readl(s->cis_virt+i); map.sys_stop = res->end;
a += d; b &= d; map.card_start = 0;
} s->ss_entry->set_mem_map(s, &map);
iounmap(s->cis_virt);
return (b == -1) ? -1 : (a>>1); /* Don't bother checking every word... */
for (i = 0; i < s->map_size; i += 44) {
d = readl(virt+i);
a += d;
b &= d;
}
map.flags = 0;
s->ss_entry->set_mem_map(s, &map);
iounmap(virt);
}
return (b == -1) ? -1 : (a>>1);
}
static int
cis_readable(struct pcmcia_socket *s, unsigned long base, unsigned long size)
{
struct resource *res1, *res2;
cisinfo_t info1, info2;
int ret = 0;
res1 = request_mem_region(base, size/2, "cs memory probe");
res2 = request_mem_region(base + size/2, size/2, "cs memory probe");
if (res1 && res2) {
ret = readable(s, res1, &info1);
ret += readable(s, res2, &info2);
}
if (res2)
release_resource(res2);
if (res1)
release_resource(res1);
return (ret == 2) && (info1.Chains == info2.Chains);
} }
static int checksum_match(struct pcmcia_socket *s, u_long base) static int
checksum_match(struct pcmcia_socket *s, unsigned long base, unsigned long size)
{ {
int a = checksum(s, base), b = checksum(s, base+s->map_size); struct resource *res1, *res2;
return ((a == b) && (a >= 0)); int a = -1, b = -1;
res1 = request_mem_region(base, size/2, "cs memory probe");
res2 = request_mem_region(base + size/2, size/2, "cs memory probe");
if (res1 && res2) {
a = checksum(s, res1);
b = checksum(s, res2);
}
if (res2)
release_resource(res2);
if (res1)
release_resource(res1);
return (a == b) && (a >= 0);
} }
/*====================================================================== /*======================================================================
...@@ -409,16 +444,16 @@ static int do_mem_probe(u_long base, u_long num, struct pcmcia_socket *s) ...@@ -409,16 +444,16 @@ static int do_mem_probe(u_long base, u_long num, struct pcmcia_socket *s)
step = 2 * s->map_size; step = 2 * s->map_size;
for (i = j = base; i < base+num; i = j + step) { for (i = j = base; i < base+num; i = j + step) {
if (!fail) { if (!fail) {
for (j = i; j < base+num; j += step) for (j = i; j < base+num; j += step) {
if ((check_mem_resource(j, step, s->cb_dev) == 0) && if (cis_readable(s, j, step))
cis_readable(s, j))
break; break;
}
fail = ((i == base) && (j == base+num)); fail = ((i == base) && (j == base+num));
} }
if (fail) { if (fail) {
for (j = i; j < base+num; j += 2*step) for (j = i; j < base+num; j += 2*step)
if ((check_mem_resource(j, 2*step, s->cb_dev) == 0) && if (checksum_match(s, j, step) &&
checksum_match(s, j) && checksum_match(s, j + step)) checksum_match(s, j + step, step))
break; break;
} }
if (i != j) { if (i != j) {
...@@ -555,17 +590,19 @@ int find_io_region(ioaddr_t *base, ioaddr_t num, ioaddr_t align, ...@@ -555,17 +590,19 @@ int find_io_region(ioaddr_t *base, ioaddr_t num, ioaddr_t align,
} }
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 force_low, char *name, struct pcmcia_socket *s) int low, char *name, struct pcmcia_socket *s)
{ {
u_long try; u_long try;
resource_map_t *m; resource_map_t *m;
int ret = -1; int ret = -1;
low = low || !(s->features & SS_CAP_PAGE_REGS);
down(&rsrc_sem); down(&rsrc_sem);
while (1) { while (1) {
for (m = mem_db.next; m != &mem_db; m = m->next) { for (m = mem_db.next; m != &mem_db; m = m->next) {
/* first pass >1MB, second pass <1MB */ /* first pass >1MB, second pass <1MB */
if ((force_low != 0) ^ (m->base < 0x100000)) if ((low != 0) ^ (m->base < 0x100000))
continue; continue;
try = (m->base & ~(align-1)) + *base; try = (m->base & ~(align-1)) + *base;
...@@ -581,9 +618,9 @@ int find_mem_region(u_long *base, u_long num, u_long align, ...@@ -581,9 +618,9 @@ int find_mem_region(u_long *base, u_long num, u_long align,
break; break;
} }
} }
if (force_low) if (low)
break; break;
force_low++; low++;
} }
out: out:
up(&rsrc_sem); up(&rsrc_sem);
......
/* /*
* Regular cardbus driver ("yenta") * Regular cardbus driver ("yenta_socket")
* *
* (C) Copyright 1999, 2000 Linus Torvalds * (C) Copyright 1999, 2000 Linus Torvalds
* *
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
#include <asm/io.h> #include <asm/io.h>
#include "yenta.h" #include "yenta_socket.h"
#include "i82365.h" #include "i82365.h"
......
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