drivers/pcmcia/Makefile | 2 drivers/pcmcia/cistpl.c | 45 ++-------- drivers/pcmcia/cs.c | 101 ++++++++++------------- drivers/pcmcia/cs_internal.h | 10 +- drivers/pcmcia/map.h | 20 ++++ drivers/pcmcia/mapstatic.c | 144 +++++++++++++++++++++++++++++++++ drivers/pcmcia/mapwindow.c | 181 +++++++++++++++++++++++++++++++++++++++++ drivers/pcmcia/rsrc_mgr.c | 187 ++++++++++++++++++++++++++----------------- include/pcmcia/ss.h | 1 9 files changed, 525 insertions(+), 166 deletions(-) diff -puN drivers/pcmcia/cistpl.c~pcmcia-10 drivers/pcmcia/cistpl.c --- 25/drivers/pcmcia/cistpl.c~pcmcia-10 2003-03-21 20:04:46.000000000 -0800 +++ 25-akpm/drivers/pcmcia/cistpl.c 2003-03-21 20:04:46.000000000 -0800 @@ -53,6 +53,7 @@ #include #include #include "cs_internal.h" +#include "map.h" static const u_char mantissa[] = { 10, 12, 13, 15, 20, 25, 30, 35, @@ -82,17 +83,9 @@ static const u_int exponent[] = { INT_MODULE_PARM(cis_width, 0); /* 16-bit CIS? */ -void release_cis_mem(socket_info_t *s) +static void release_cis_mem(socket_info_t *s) { - if (s->cis_mem.sys_start != 0) { - s->cis_mem.flags &= ~MAP_ACTIVE; - s->ss_entry->set_mem_map(s->sock, &s->cis_mem); - if (!(s->cap.features & SS_CAP_STATIC_MAP)) - release_mem_region(s->cis_mem.sys_start, s->cap.map_size); - iounmap(s->cis_virt); - s->cis_mem.sys_start = 0; - s->cis_virt = NULL; - } + s->map_ops->cis_unmap(s); } /* @@ -103,29 +96,13 @@ void release_cis_mem(socket_info_t *s) static unsigned char * set_cis_map(socket_info_t *s, unsigned int card_offset, unsigned int flags) { - pccard_mem_map *mem = &s->cis_mem; - if (!(s->cap.features & SS_CAP_STATIC_MAP) && - mem->sys_start == 0) { - int low = !(s->cap.features & SS_CAP_PAGE_REGS); - validate_mem(s); - mem->sys_start = 0; - if (find_mem_region(&mem->sys_start, s->cap.map_size, - s->cap.map_size, low, "card services", s)) { - printk(KERN_NOTICE "cs: unable to map card memory!\n"); - return NULL; - } - mem->sys_stop = mem->sys_start+s->cap.map_size-1; - s->cis_virt = ioremap(mem->sys_start, s->cap.map_size); - } - mem->card_start = card_offset; - mem->flags = flags; - s->ss_entry->set_mem_map(s->sock, mem); - if (s->cap.features & SS_CAP_STATIC_MAP) { - if (s->cis_virt) - iounmap(s->cis_virt); - s->cis_virt = ioremap(mem->sys_start, s->cap.map_size); - } - return s->cis_virt; + void *ret; + + ret = s->map_ops->cis_map(s, card_offset, flags); + if (!ret) + printk(KERN_ERR "cs: unable to map card memory!\n"); + + return s->cis_virt; } /*====================================================================== @@ -196,6 +173,7 @@ int read_cis_mem(socket_info_t *s, int a addr = 0; } } + release_cis_mem(s); DEBUG(3, "cs: %#2.2x %#2.2x %#2.2x %#2.2x ...\n", *(u_char *)(ptr+0), *(u_char *)(ptr+1), *(u_char *)(ptr+2), *(u_char *)(ptr+3)); @@ -256,6 +234,7 @@ void write_cis_mem(socket_info_t *s, int addr = 0; } } + release_cis_mem(s); } /*====================================================================== diff -puN drivers/pcmcia/cs.c~pcmcia-10 drivers/pcmcia/cs.c --- 25/drivers/pcmcia/cs.c~pcmcia-10 2003-03-21 20:04:46.000000000 -0800 +++ 25-akpm/drivers/pcmcia/cs.c 2003-03-21 20:04:46.000000000 -0800 @@ -60,6 +60,7 @@ #include #include #include "cs_internal.h" +#include "map.h" #ifdef CONFIG_PCI #define PCI_OPT " [pci]" @@ -268,11 +269,6 @@ static int set_io_map(socket_info_t *s, return s->ss_entry->set_io_map(s->sock, io); } -static int set_mem_map(socket_info_t *s, struct pccard_mem_map *mem) -{ - return s->ss_entry->set_mem_map(s->sock, mem); -} - static int suspend_socket(socket_info_t *s) { s->socket = dead_socket; @@ -360,6 +356,12 @@ int pcmcia_register_socket(struct device init_socket(s); s->ss_entry->inquire_socket(s->sock, &s->cap); + + if (s->cap.features & SS_CAP_STATIC_MAP) + s->map_ops = &smap_ops; + else + s->map_ops = &winmap_ops; + #ifdef CONFIG_PROC_FS if (proc_pccard) { char name[3]; @@ -416,7 +418,6 @@ void pcmcia_unregister_socket(struct dev #endif shutdown_socket(s); - release_cis_mem(s); while (s->clients) { client = s->clients; s->clients = s->clients->next; @@ -511,6 +512,8 @@ static void shutdown_socket(socket_info_ } free_regions(&s->a_region); free_regions(&s->c_region); + + s->map_ops->remove(s); } /* shutdown_socket */ /* @@ -620,6 +623,9 @@ static void unreset_socket(socket_info_t else send_event(s, CS_EVENT_PM_RESUME, CS_EVENT_PRI_LOW); } else if (s->state & SOCKET_SETUP_PENDING) { + int ret = s->map_ops->insert(s); + if (ret) + printk(KERN_ERR "PCMCIA: insert failed: %d\n", ret); #ifdef CONFIG_CARDBUS if (s->state & SOCKET_CARDBUS) { cb_alloc(s); @@ -1194,8 +1200,8 @@ int pcmcia_get_window(window_handle_t *h if (w == MAX_WIN) return CS_NO_MORE_ITEMS; win = &s->win[w]; - req->Base = win->ctl.sys_start; - req->Size = win->ctl.sys_stop - win->ctl.sys_start + 1; + req->Base = win->ctl.res->start; + req->Size = win->ctl.res->end - win->ctl.res->start + 1; req->AccessSpeed = win->ctl.speed; req->Attributes = 0; if (win->ctl.flags & MAP_ATTRIB) @@ -1342,10 +1348,13 @@ int pcmcia_map_mem_page(window_handle_t return CS_BAD_HANDLE; if (req->Page != 0) return CS_BAD_PAGE; + s = win->sock; - win->ctl.card_start = req->CardOffset; - if (set_mem_map(s, &win->ctl) != 0) + + if (s->map_ops->mem_modify(s, &win->ctl, req->CardOffset, + win->ctl.speed, win->ctl.flags)) return CS_BAD_OFFSET; + return CS_SUCCESS; } /* map_mem_page */ @@ -1406,22 +1415,26 @@ int pcmcia_modify_configuration(client_h int pcmcia_modify_window(window_handle_t win, modwin_t *req) { + socket_info_t *s; + unsigned int flags; + if ((win == NULL) || (win->magic != WINDOW_MAGIC)) return CS_BAD_HANDLE; - win->ctl.flags &= ~(MAP_ATTRIB|MAP_ACTIVE); + flags = win->ctl.flags & ~(MAP_ATTRIB|MAP_ACTIVE); if (req->Attributes & WIN_MEMORY_TYPE) - win->ctl.flags |= MAP_ATTRIB; + flags |= MAP_ATTRIB; if (req->Attributes & WIN_ENABLE) - win->ctl.flags |= MAP_ACTIVE; + flags |= MAP_ACTIVE; if (req->Attributes & WIN_DATA_WIDTH_16) - win->ctl.flags |= MAP_16BIT; + flags |= MAP_16BIT; if (req->Attributes & WIN_USE_WAIT) - win->ctl.flags |= MAP_USE_WAIT; - win->ctl.speed = req->AccessSpeed; - set_mem_map(win->sock, &win->ctl); - - return CS_SUCCESS; + flags |= MAP_USE_WAIT; + + s = win->sock; + + return s->map_ops->mem_modify(s, &win->ctl, win->ctl.card_start, + req->AccessSpeed, flags); } /* modify_window */ /*====================================================================== @@ -1643,12 +1656,10 @@ int pcmcia_release_window(window_handle_ /* Shut down memory window */ win->ctl.flags &= ~MAP_ACTIVE; - set_mem_map(s, &win->ctl); - s->state &= ~SOCKET_WIN_REQ(win->index); - /* Release system memory */ - if(!(s->cap.features & SS_CAP_STATIC_MAP)) - release_mem_region(win->base, win->size); + s->map_ops->mem_unmap(s, &win->ctl); + + s->state &= ~SOCKET_WIN_REQ(win->index); win->handle->state &= ~CLIENT_WIN_REQ(win->index); win->magic = 0; @@ -1933,8 +1944,7 @@ int pcmcia_request_window(client_handle_ { socket_info_t *s; window_t *win; - u_long align; - int w; + int w, ret; if (CHECK_HANDLE(*handle)) return CS_BAD_HANDLE; @@ -1947,16 +1957,8 @@ int pcmcia_request_window(client_handle_ /* Window size defaults to smallest available */ if (req->Size == 0) req->Size = s->cap.map_size; - align = (((s->cap.features & SS_CAP_MEM_ALIGN) || - (req->Attributes & WIN_STRICT_ALIGN)) ? - req->Size : s->cap.map_size); if (req->Size & (s->cap.map_size-1)) return CS_BAD_SIZE; - if ((req->Base && (s->cap.features & SS_CAP_STATIC_MAP)) || - (req->Base & (align-1))) - return CS_BAD_BASE; - if (req->Base) - align = 0; /* Allocate system memory window */ for (w = 0; w < MAX_WIN; w++) @@ -1969,18 +1971,6 @@ int pcmcia_request_window(client_handle_ win->index = w; win->handle = *handle; win->sock = s; - win->base = req->Base; - win->size = req->Size; - - if (!(s->cap.features & SS_CAP_STATIC_MAP) && - find_mem_region(&win->base, win->size, align, - (req->Attributes & WIN_MAP_BELOW_1MB) || - !(s->cap.features & SS_CAP_PAGE_REGS), - (*handle)->dev_info, s)) - return CS_IN_USE; - (*handle)->state |= CLIENT_WIN_REQ(w); - - /* Configure the socket controller */ win->ctl.map = w+1; win->ctl.flags = 0; win->ctl.speed = req->AccessSpeed; @@ -1992,18 +1982,19 @@ int pcmcia_request_window(client_handle_ win->ctl.flags |= MAP_16BIT; if (req->Attributes & WIN_USE_WAIT) win->ctl.flags |= MAP_USE_WAIT; - win->ctl.sys_start = win->base; - win->ctl.sys_stop = win->base + win->size-1; win->ctl.card_start = 0; - if (set_mem_map(s, &win->ctl) != 0) - return CS_BAD_ARGS; - s->state |= SOCKET_WIN_REQ(w); - /* Return window handle */ - req->Base = win->ctl.sys_start; - *wh = win; + ret = s->map_ops->mem_map(s, &win->ctl, req, (*handle)->dev_info); + if (ret == CS_SUCCESS) { + (*handle)->state |= CLIENT_WIN_REQ(w); + s->state |= SOCKET_WIN_REQ(w); + + /* Return window handle */ + req->Base = win->ctl.res->start; + *wh = win; + } - return CS_SUCCESS; + return ret; } /* request_window */ /*====================================================================== diff -puN drivers/pcmcia/cs_internal.h~pcmcia-10 drivers/pcmcia/cs_internal.h --- 25/drivers/pcmcia/cs_internal.h~pcmcia-10 2003-03-21 20:04:46.000000000 -0800 +++ 25-akpm/drivers/pcmcia/cs_internal.h 2003-03-21 20:04:46.000000000 -0800 @@ -75,8 +75,6 @@ typedef struct window_t { u_short index; client_handle_t handle; struct socket_info_t *sock; - u_long base; - u_long size; pccard_mem_map ctl; } window_t; @@ -118,9 +116,12 @@ typedef struct config_t { #define MAX_CIS_TABLE 64 #define MAX_CIS_DATA 512 +struct map_operations; + typedef struct socket_info_t { spinlock_t lock; struct pccard_operations * ss_entry; + struct map_operations *map_ops; u_int sock; socket_state_t socket; socket_cap_t cap; @@ -207,7 +208,6 @@ int read_cis_mem(socket_info_t *s, int a u_int addr, u_int len, void *ptr); void write_cis_mem(socket_info_t *s, int attr, u_int addr, u_int len, void *ptr); -void release_cis_mem(socket_info_t *s); int verify_cis_cache(socket_info_t *s); void preload_cis_cache(socket_info_t *s); int get_first_tuple(client_handle_t handle, tuple_t *tuple); @@ -236,8 +236,8 @@ int copy_memory(memory_handle_t handle, void validate_mem(socket_info_t *s); int find_io_region(ioaddr_t *base, ioaddr_t num, ioaddr_t align, char *name, socket_info_t *s); -int find_mem_region(u_long *base, u_long num, u_long align, - int force_low, char *name, socket_info_t *s); +struct resource *find_mem_region(u_long base, u_long num, u_long align, + int low, char *name, socket_info_t *s); int try_irq(u_int Attributes, int irq, int specific); void undo_irq(u_int Attributes, int irq); int adjust_resource_info(client_handle_t handle, adjust_t *adj); diff -puN drivers/pcmcia/Makefile~pcmcia-10 drivers/pcmcia/Makefile --- 25/drivers/pcmcia/Makefile~pcmcia-10 2003-03-21 20:04:46.000000000 -0800 +++ 25-akpm/drivers/pcmcia/Makefile 2003-03-21 20:04:46.000000000 -0800 @@ -16,7 +16,7 @@ obj-$(CONFIG_PCMCIA_SA1111) += sa1111_c yenta_socket-objs := pci_socket.o yenta.o -pcmcia_core-objs-y := cistpl.o rsrc_mgr.o bulkmem.o cs.o +pcmcia_core-objs-y := cistpl.o rsrc_mgr.o bulkmem.o cs.o mapstatic.o mapwindow.o pcmcia_core-objs-$(CONFIG_CARDBUS) += cardbus.o pcmcia_core-objs := $(pcmcia_core-objs-y) diff -puN /dev/null drivers/pcmcia/map.h --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25-akpm/drivers/pcmcia/map.h 2003-03-21 20:04:46.000000000 -0800 @@ -0,0 +1,20 @@ + +struct socket_info_t; + +struct map_operations { + int (*insert)(struct socket_info_t *); + void (*remove)(struct socket_info_t *); + + void (*cis_unmap)(struct socket_info_t *); + void *(*cis_map)(struct socket_info_t *, unsigned int, unsigned int); + + void (*mem_unmap)(struct socket_info_t *, pccard_mem_map *); + int (*mem_map)(struct socket_info_t *, pccard_mem_map *, + struct win_req_t *, char *); + int (*mem_modify)(struct socket_info_t *, pccard_mem_map *, + unsigned int, unsigned int, unsigned int); +}; + +extern struct map_operations smap_ops; +extern struct map_operations winmap_ops; + diff -puN /dev/null drivers/pcmcia/mapstatic.c --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25-akpm/drivers/pcmcia/mapstatic.c 2003-03-21 20:04:46.000000000 -0800 @@ -0,0 +1,144 @@ +/* + * linux/drivers/pcmcia/mapstatic.c + * + * Handle static mapped sockets. Things to note: + * + * - the virtual address of a mapping can change when the card memory + * offset / type changes. Clients must not assume this is constant. + * (normal usage seems to indicate a call to RequestWindow, followed + * by a call to MapMemPage. This can not work for static mapped + * sockets, and requires all card drivers and cs.c to be fixed.) + * + * - the current way we obtain the base address of a mapping is bogus + * and needs to die - set_mem_map() offers a different interface + * for statically mapped sockets to that for windowed sockets. + */ +#include +#include +#include + +#include + +#include +struct proc_dir_entry; + +#include +#include +#include +#include +#include +#include +#include "cs_internal.h" +#include "map.h" + +static int smap_insert(struct socket_info_t *s) +{ + return 0; +} + +static void smap_remove(struct socket_info_t *s) +{ +} + +static void smap_cis_unmap(struct socket_info_t *s) +{ + pccard_mem_map *mem = &s->cis_mem; + + mem->flags = 0; + mem->card_start = 0; + + if (s->cis_virt) + iounmap(s->cis_virt); + if (s->cis_mem.res) + release_resource(s->cis_mem.res); + + s->cis_virt = NULL; + s->cis_mem.res = NULL; +} + +static void * +smap_cis_map(struct socket_info_t *s, unsigned int card_offset, unsigned int flags) +{ + pccard_mem_map *mem = &s->cis_mem; + + if (mem->card_start != card_offset || mem->flags != flags) { + smap_cis_unmap(s); + + mem->flags = flags; + mem->sys_start = 0; + mem->sys_stop = s->cap.map_size - 1; + mem->card_start = card_offset; + + s->ss_entry->set_mem_map(s->sock, mem); + + mem->res = request_mem_region(mem->sys_start, s->cap.map_size, + "card services"); + if (mem->res) + s->cis_virt = ioremap(mem->res->start, s->cap.map_size); + + if (!s->cis_virt) + smap_cis_unmap(s); + } + + return s->cis_virt; +} + + + + +static void smap_mem_unmap(struct socket_info_t *s, pccard_mem_map *map) +{ + BUG_ON(!map->res); + + release_resource(map->res); + map->res = NULL; +} + +static int +smap_mem_map(struct socket_info_t *s, pccard_mem_map *map, struct win_req_t *req, char *dev_info) +{ + BUG_ON(map->res); + + if (req->Base != 0) + return CS_BAD_BASE; + + map->sys_start = 0; + map->sys_stop = req->Size - 1; + + if (s->ss_entry->set_mem_map(s->sock, map) != 0) + return CS_BAD_ARGS; + + map->res = request_mem_region(map->sys_start, req->Size, dev_info); + + return map->res ? CS_SUCCESS : CS_IN_USE; +} + +static int +smap_mem_modify(struct socket_info_t *s, pccard_mem_map *map, + unsigned int card_offset, unsigned int speed, + unsigned int flags) +{ + BUG_ON(!map->res); + + if (map->card_start != card_offset) + return CS_BAD_OFFSET; + + map->speed = speed; + map->flags = flags; + + return s->ss_entry->set_mem_map(s->sock, map) ? CS_BAD_ARGS : 0; +} + + + +struct map_operations smap_ops = { + .insert = smap_insert, + .remove = smap_remove, + + .cis_unmap = smap_cis_unmap, + .cis_map = smap_cis_map, + + .mem_unmap = smap_mem_unmap, + .mem_map = smap_mem_map, + .mem_modify = smap_mem_modify, +}; diff -puN /dev/null drivers/pcmcia/mapwindow.c --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25-akpm/drivers/pcmcia/mapwindow.c 2003-03-21 20:04:46.000000000 -0800 @@ -0,0 +1,181 @@ +/* + * linux/drivers/pcmcia/mapwindow.c + * + * Handle window mapped sockets. Things to note: + * + * - validate_mem() will call winmap_cis_map and winmap_cis_unmap + * during it's probe for usable memory. + */ +#include +#include +#include +#include + +#include + +#include +struct proc_dir_entry; + +#include +#include +#include +#include +#include +#include +#include "cs_internal.h" +#include "map.h" + +/* + * A card was inserted. Find a memory resource for the CIS, claim it, + * and setup a mapping. + */ +static int winmap_insert(struct socket_info_t *s) +{ + BUG_ON(s->cis_mem.res); + BUG_ON(s->cis_virt); + + if (!(s->cap.features & SS_CAP_CARDBUS)) + validate_mem(s); + + s->cis_mem.res = find_mem_region(0, s->cap.map_size, s->cap.map_size, + 0, "card services", s); + + if (!s->cis_mem.res) + return -EBUSY; + + s->cis_virt = ioremap(s->cis_mem.res->start, s->cap.map_size); + if (!s->cis_virt) { + release_resource(s->cis_mem.res); + return -ENOMEM; + } + + return 0; +} + +/* + * The card was removed. Release resources claimed by winmap_insert(). + */ +static void winmap_remove(struct socket_info_t *s) +{ + if (s->cis_virt) + iounmap(s->cis_virt); + if (s->cis_mem.res) + release_resource(s->cis_mem.res); + + s->cis_virt = NULL; + s->cis_mem.res = NULL; +} + +/* + * Unmap a CIS mapping. Note that the resource and ioremap of + * the region remains in place since winmap_cis_map() did not + * setup this mapping. + */ +static void winmap_cis_unmap(struct socket_info_t *s) +{ + pccard_mem_map *mem = &s->cis_mem; + + if (mem->flags & MAP_ACTIVE) { + mem->flags &= ~MAP_ACTIVE; + s->ss_entry->set_mem_map(s->sock, mem); + } +} + +/* + * Map card memory at card_offset in the memory region defined + * by "flags" into memory, returning the virtual address of this + * mapping. We may be altering a pre-existing mapping. + */ +static void * +winmap_cis_map(struct socket_info_t *s, unsigned int card_offset, unsigned int flags) +{ + pccard_mem_map *mem = &s->cis_mem; + + if (s->cis_virt && + (mem->card_start != card_offset || mem->flags != flags)) { + mem->flags = flags; + mem->sys_start = mem->res->start; + mem->sys_stop = mem->res->start + s->cap.map_size - 1; + mem->card_start = card_offset; + + s->ss_entry->set_mem_map(s->sock, mem); + } + + return s->cis_virt; +} + + + + +static void winmap_mem_unmap(struct socket_info_t *s, pccard_mem_map *map) +{ + BUG_ON(!map->res); + + s->ss_entry->set_mem_map(s->sock, map); + + release_resource(map->res); + map->res = NULL; +} + +static int +winmap_mem_map(struct socket_info_t *s, pccard_mem_map *map, struct win_req_t *req, char *dev_info) +{ + unsigned long align; + + BUG_ON(map->res); + + align = s->cap.map_size; + if ((s->cap.features & SS_CAP_MEM_ALIGN) || + (req->Attributes & WIN_STRICT_ALIGN)) + align = req->Size; + + if (req->Base & (align-1)) + return CS_BAD_BASE; + if (req->Base) + align = 0; + + map->res = find_mem_region(req->Base, req->Size, align, + req->Attributes & WIN_MAP_BELOW_1MB, + dev_info, s); + if (!map->res) + return CS_IN_USE; + + map->sys_start = map->res->start; + map->sys_stop = map->res->end; + + if (s->ss_entry->set_mem_map(s->sock, map) != 0) { + release_resource(map->res); + map->res = NULL; + return CS_BAD_ARGS; + } + + return CS_SUCCESS; +} + +static int +winmap_mem_modify(struct socket_info_t *s, pccard_mem_map *map, + unsigned int card_offset, unsigned int speed, + unsigned int flags) +{ + BUG_ON(!map->res); + + map->card_start = card_offset; + map->speed = speed; + map->flags = flags; + + return s->ss_entry->set_mem_map(s->sock, map) ? CS_BAD_ARGS : 0; +} + + + +struct map_operations winmap_ops = { + .insert = winmap_insert, + .remove = winmap_remove, + + .cis_unmap = winmap_cis_unmap, + .cis_map = winmap_cis_map, + + .mem_unmap = winmap_mem_unmap, + .mem_map = winmap_mem_map, + .mem_modify = winmap_mem_modify, +}; diff -puN drivers/pcmcia/rsrc_mgr.c~pcmcia-10 drivers/pcmcia/rsrc_mgr.c --- 25/drivers/pcmcia/rsrc_mgr.c~pcmcia-10 2003-03-21 20:04:46.000000000 -0800 +++ 25-akpm/drivers/pcmcia/rsrc_mgr.c 2003-03-21 20:04:46.000000000 -0800 @@ -52,6 +52,7 @@ #include #include #include "cs_internal.h" +#include "map.h" /*====================================================================*/ @@ -140,22 +141,6 @@ static inline int check_io_resource(unsi 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, int flags, char *name) { @@ -186,7 +171,7 @@ static int request_io_resource(unsigned return err; } -static int request_mem_resource(unsigned long b, unsigned long n, +static struct resource *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); @@ -195,10 +180,12 @@ static int request_mem_resource(unsigned if (res) { err = request_resource(pr, res); - if (err) + if (err) { kfree(res); + res = NULL; + } } - return err; + return res; } /*====================================================================== @@ -341,52 +328,103 @@ static void do_io_probe(ioaddr_t base, i ======================================================================*/ /* Validation function for cards with a valid CIS */ -static int cis_readable(socket_info_t *s, u_long base) +static int readable(socket_info_t *s, struct resource *res, cisinfo_t *info) { - cisinfo_t info1, info2; - int ret; - s->cis_mem.sys_start = base; - s->cis_mem.sys_stop = base+s->cap.map_size-1; - s->cis_virt = ioremap(base, s->cap.map_size); - ret = pcmcia_validate_cis(s->clients, &info1); - /* invalidate mapping and CIS cache */ - iounmap(s->cis_virt); - s->cis_used = 0; - if ((ret != 0) || (info1.Chains == 0)) - return 0; - s->cis_mem.sys_start = base+s->cap.map_size; - s->cis_mem.sys_stop = base+2*s->cap.map_size-1; - s->cis_virt = ioremap(base+s->cap.map_size, s->cap.map_size); - ret = pcmcia_validate_cis(s->clients, &info2); - iounmap(s->cis_virt); - s->cis_used = 0; - return ((ret == 0) && (info1.Chains == info2.Chains)); + /* this can not work for now. */ + int ret = -1; + + s->cis_mem.res = res; + s->cis_virt = ioremap(res->start, s->cap.map_size); + if (s->cis_virt) { + ret = pcmcia_validate_cis(s->clients, info); + /* invalidate mapping and CIS cache */ + iounmap(s->cis_virt); + s->cis_virt = NULL; + s->cis_mem.res = NULL; + s->cis_used = 0; + } + if ((ret != 0) || (info->Chains == 0)) + return 0; + return 1; } /* Validation function for simple memory cards */ -static int checksum(socket_info_t *s, u_long base) +static int checksum(socket_info_t *s, struct resource *res) { - int i, a, b, d; - s->cis_mem.sys_start = base; - s->cis_mem.sys_stop = base+s->cap.map_size-1; - s->cis_virt = ioremap(base, s->cap.map_size); - s->cis_mem.card_start = 0; - s->cis_mem.flags = MAP_ACTIVE; - s->ss_entry->set_mem_map(s->sock, &s->cis_mem); - /* Don't bother checking every word... */ - a = 0; b = -1; - for (i = 0; i < s->cap.map_size; i += 44) { - d = readl(s->cis_virt+i); - a += d; b &= d; - } - iounmap(s->cis_virt); - return (b == -1) ? -1 : (a>>1); + pccard_mem_map map; + int i, a = 0, b = -1, d; + void *virt; + + virt = ioremap(res->start, s->cap.map_size); + if (virt) { + map.map = 0; + map.flags = MAP_ACTIVE; + map.speed = 0; + map.res = res; + map.sys_start = res->start; + map.sys_stop = res->end; + map.card_start = 0; + s->ss_entry->set_mem_map(s->sock, &map); + + /* Don't bother checking every word... */ + for (i = 0; i < s->cap.map_size; i += 44) { + d = readl(virt+i); + a += d; + b &= d; + } + + map.flags = 0; + s->ss_entry->set_mem_map(s->sock, &map); + + iounmap(virt); + } + + return (b == -1) ? -1 : (a>>1); } -static int checksum_match(socket_info_t *s, u_long base) +static int +cis_readable(socket_info_t *s, unsigned long base, unsigned long size) { - int a = checksum(s, base), b = checksum(s, base+s->cap.map_size); - return ((a == b) && (a >= 0)); + 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 socket_info_t *s, unsigned long base, unsigned long size) +{ + struct resource *res1, *res2; + 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)); } /*====================================================================== @@ -410,16 +448,16 @@ static int do_mem_probe(u_long base, u_l step = 2 * s->cap.map_size; for (i = j = base; i < base+num; i = j + step) { if (!fail) { - for (j = i; j < base+num; j += step) - if ((check_mem_resource(j, step, s->cap.cb_dev) == 0) && - cis_readable(s, j)) + for (j = i; j < base+num; j += step) { + if (cis_readable(s, j, step)) break; + } fail = ((i == base) && (j == base+num)); } if (fail) { for (j = i; j < base+num; j += 2*step) - if ((check_mem_resource(j, 2*step, s->cap.cb_dev) == 0) && - checksum_match(s, j) && checksum_match(s, j + step)) + if (checksum_match(s, j, step) && + checksum_match(s, j + step, step)) break; } if (i != j) { @@ -553,12 +591,16 @@ int find_io_region(ioaddr_t *base, ioadd return ret; } -int find_mem_region(u_long *base, u_long num, u_long align, - int force_low, char *name, socket_info_t *s) +struct resource * +find_mem_region(u_long base, u_long num, u_long align, int low, char *name, + socket_info_t *s) { + struct resource *res = NULL; u_long try; resource_map_t *m; - int ret = -1; + int force_low; + + force_low = low || !(s->cap.features & SS_CAP_PAGE_REGS); down(&rsrc_sem); while (1) { @@ -567,15 +609,13 @@ int find_mem_region(u_long *base, u_long if ((force_low != 0) ^ (m->base < 0x100000)) continue; - try = (m->base & ~(align-1)) + *base; + try = (m->base & ~(align-1)) + base; for (try = (try >= m->base) ? try : try+align; (try >= m->base) && (try+num <= m->base+m->num); try += align) { - if (request_mem_resource(try, num, name, s->cap.cb_dev) == 0) { - *base = try; - ret = 0; + res = request_mem_resource(try, num, name, s->cap.cb_dev); + if (res) goto out; - } if (!align) break; } @@ -586,7 +626,7 @@ int find_mem_region(u_long *base, u_long } out: up(&rsrc_sem); - return ret; + return res; } /*====================================================================== @@ -742,7 +782,10 @@ static int adjust_memory(adjust_t *adj) ret = sub_interval(&mem_db, base, num); if (ret == CS_SUCCESS) { for (i = 0; i < sockets; i++) { - release_cis_mem(socket_table[i]); + if (socket_table[i]->cis_virt) { + socket_table[i]->map_ops->remove(socket_table[i]); + socket_table[i]->map_ops->insert(socket_table[i]); + } #ifdef CONFIG_CARDBUS cb_release_cis_mem(socket_table[i]); #endif diff -puN include/pcmcia/ss.h~pcmcia-10 include/pcmcia/ss.h --- 25/include/pcmcia/ss.h~pcmcia-10 2003-03-21 20:04:46.000000000 -0800 +++ 25-akpm/include/pcmcia/ss.h 2003-03-21 20:04:46.000000000 -0800 @@ -111,6 +111,7 @@ typedef struct pccard_mem_map { u_char map; u_char flags; u_short speed; + struct resource *res; u_long sys_start, sys_stop; u_int card_start; } pccard_mem_map; _