]> git.karo-electronics.de Git - mv-sheeva.git/commitdiff
Merge git://git.kernel.org/pub/scm/linux/kernel/git/brodo/pcmcia-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Sun, 28 Feb 2010 00:18:30 +0000 (16:18 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sun, 28 Feb 2010 00:18:30 +0000 (16:18 -0800)
* git://git.kernel.org/pub/scm/linux/kernel/git/brodo/pcmcia-2.6: (49 commits)
  pcmcia: validate late-added resources
  pcmcia: allow for extension of resource interval
  pcmcia: remove useless msleep in ds.c
  pcmcia: use read_cis_mem return value
  pcmcia: handle error in serial_cs config calls
  pcmcia: add locking to pcmcia_{read,write}_cis_mem
  pcmcia: avoid prod_id memleak
  pcmcia: avoid sysfs-related lockup for cardbus
  pcmcia: use state machine for extended requery
  pcmcia: delay re-scanning and re-querying of PCMCIA bus
  pcmcia: use pccardd to handle eject, insert, suspend and resume requests
  pcmcia: use ops_mutex for rsrc_{mgr,nonstatic} locking
  pcmcia: use mutex for dynid lock
  pcmcia: assert locking to struct pcmcia_device
  pcmcia: add locking documentation
  pcmcia: simplify locking
  pcmcia: add locking to struct pcmcia_socket->pcmcia_state()
  pcmcia: protect s->device_count
  pcmcia: properly lock skt->irq, skt->irq_mask
  pcmcia: lock ops->set_socket
  ...

1  2 
drivers/pcmcia/rsrc_mgr.c
drivers/pcmcia/rsrc_nonstatic.c
drivers/pcmcia/yenta_socket.c
drivers/serial/serial_cs.c

index f8401a0ef89b97de9d5cebc76b8867ddd097875d,aca2cfd02ca5406b1ee9aa23fc77846591ab3ce3..e6f7d410aed618a8f1a80d8bfcdd4715b5cb97da
  #include <pcmcia/cistpl.h>
  #include "cs_internal.h"
  
- int pcmcia_validate_mem(struct pcmcia_socket *s)
- {
-       if (s->resource_ops->validate_mem)
-               return s->resource_ops->validate_mem(s);
-       /* if there is no callback, we can assume that everything is OK */
-       return 0;
- }
- EXPORT_SYMBOL(pcmcia_validate_mem);
- int pcmcia_adjust_io_region(struct resource *res, unsigned long r_start,
-                    unsigned long r_end, struct pcmcia_socket *s)
- {
-       if (s->resource_ops->adjust_io_region)
-               return s->resource_ops->adjust_io_region(res, r_start, r_end, s);
-       return -ENOMEM;
- }
- EXPORT_SYMBOL(pcmcia_adjust_io_region);
- struct resource *pcmcia_find_io_region(unsigned long base, int num,
-                  unsigned long align, struct pcmcia_socket *s)
- {
-       if (s->resource_ops->find_io)
-               return s->resource_ops->find_io(base, num, align, s);
-       return NULL;
- }
- EXPORT_SYMBOL(pcmcia_find_io_region);
- struct resource *pcmcia_find_mem_region(u_long base, u_long num, u_long align,
-                                int low, struct pcmcia_socket *s)
- {
-       if (s->resource_ops->find_mem)
-               return s->resource_ops->find_mem(base, num, align, low, s);
-       return NULL;
- }
- EXPORT_SYMBOL(pcmcia_find_mem_region);
- void release_resource_db(struct pcmcia_socket *s)
- {
-       if (s->resource_ops->exit)
-               s->resource_ops->exit(s);
- }
  static int static_init(struct pcmcia_socket *s)
  {
-       unsigned long flags;
        /* the good thing about SS_CAP_STATIC_MAP sockets is
         * that they don't need a resource database */
  
-       spin_lock_irqsave(&s->lock, flags);
        s->resource_setup_done = 1;
-       spin_unlock_irqrestore(&s->lock, flags);
  
        return 0;
  }
@@@ -114,21 -66,22 +66,21 @@@ struct pcmcia_align_data 
        unsigned long   offset;
  };
  
 -static void pcmcia_align(void *align_data, struct resource *res,
 -                      unsigned long size, unsigned long align)
 +static resource_size_t pcmcia_align(void *align_data,
 +                              const struct resource *res,
 +                              resource_size_t size, resource_size_t align)
  {
        struct pcmcia_align_data *data = align_data;
 -      unsigned long start;
 +      resource_size_t start;
  
        start = (res->start & ~data->mask) + data->offset;
        if (start < res->start)
                start += data->mask + 1;
 -      res->start = start;
  
  #ifdef CONFIG_X86
        if (res->flags & IORESOURCE_IO) {
                if (start & 0x300) {
                        start = (start + 0x3ff) & ~0x3ff;
 -                      res->start = start;
                }
        }
  #endif
  #ifdef CONFIG_M68K
        if (res->flags & IORESOURCE_IO) {
                if ((res->start + size - 1) >= 1024)
 -                      res->start = res->end;
 +                      start = res->end;
        }
  #endif
 +
 +      return start;
  }
  
  
index c67638fe69146b05656187f94a41f76a06de32ad,a69eed6c5b92930ea717a7a32ff06ff3fc46a2c0..4663b3fa9f9616a66db5214fc6f5ef16c1b37dc0
@@@ -55,11 -55,10 +55,10 @@@ struct resource_map 
  
  struct socket_data {
        struct resource_map             mem_db;
+       struct resource_map             mem_db_valid;
        struct resource_map             io_db;
-       unsigned int                    rsrc_mem_probe;
  };
  
- static DEFINE_MUTEX(rsrc_mutex);
  #define MEM_PROBE_LOW (1 << 0)
  #define MEM_PROBE_HIGH        (1 << 1)
  
@@@ -125,8 -124,10 +124,10 @@@ static int add_interval(struct resource
        struct resource_map *p, *q;
  
        for (p = map; ; p = p->next) {
-               if ((p != map) && (p->base+p->num-1 >= base))
-                       return -1;
+               if ((p != map) && (p->base+p->num >= base)) {
+                       p->num = max(num + base - p->base, p->num);
+                       return 0;
+               }
                if ((p->next == map) || (p->next->base > base+num-1))
                        break;
        }
@@@ -264,36 -265,44 +265,44 @@@ static void do_io_probe(struct pcmcia_s
  }
  #endif
  
- /*======================================================================
-     This is tricky... when we set up CIS memory, we try to validate
-     the memory window space allocations.
- ======================================================================*/
+ /*======================================================================*/
  
- /* Validation function for cards with a valid CIS */
+ /**
+  * readable() - iomem validation function for cards with a valid CIS
+  */
  static int readable(struct pcmcia_socket *s, struct resource *res,
                    unsigned int *count)
  {
-       int ret = -1;
+       int ret = -EINVAL;
+       if (s->fake_cis) {
+               dev_dbg(&s->dev, "fake CIS is being used: can't validate mem\n");
+               return 0;
+       }
  
        s->cis_mem.res = res;
        s->cis_virt = ioremap(res->start, s->map_size);
        if (s->cis_virt) {
-               ret = pccard_validate_cis(s, count);
-               /* invalidate mapping and CIS cache */
+               mutex_unlock(&s->ops_mutex);
+               /* as we're only called from pcmcia.c, we're safe */
+               if (s->callback->validate)
+                       ret = s->callback->validate(s, count);
+               /* invalidate mapping */
+               mutex_lock(&s->ops_mutex);
                iounmap(s->cis_virt);
                s->cis_virt = NULL;
-               destroy_cis_cache(s);
        }
        s->cis_mem.res = NULL;
-       if ((ret != 0) || (*count == 0))
-               return 0;
-       return 1;
+       if ((ret) || (*count == 0))
+               return -EINVAL;
+       return 0;
  }
  
- /* Validation function for simple memory cards */
- static int checksum(struct pcmcia_socket *s, struct resource *res)
+ /**
+  * checksum() - iomem validation function for simple memory cards
+  */
+ static int checksum(struct pcmcia_socket *s, struct resource *res,
+                   unsigned int *value)
  {
        pccard_mem_map map;
        int i, a = 0, b = -1, d;
                iounmap(virt);
        }
  
-       return (b == -1) ? -1 : (a>>1);
+       if (b == -1)
+               return -EINVAL;
+       *value = a;
+       return 0;
  }
  
- static int
- cis_readable(struct pcmcia_socket *s, unsigned long base, unsigned long size)
+ /**
+  * do_validate_mem() - low level validate a memory region for PCMCIA use
+  * @s:                PCMCIA socket to validate
+  * @base:     start address of resource to check
+  * @size:     size of resource to check
+  * @validate: validation function to use
+  *
+  * do_validate_mem() splits up the memory region which is to be checked
+  * into two parts. Both are passed to the @validate() function. If
+  * @validate() returns non-zero, or the value parameter to @validate()
+  * is zero, or the value parameter is different between both calls,
+  * the check fails, and -EINVAL is returned. Else, 0 is returned.
+  */
+ static int do_validate_mem(struct pcmcia_socket *s,
+                          unsigned long base, unsigned long size,
+                          int validate (struct pcmcia_socket *s,
+                                        struct resource *res,
+                                        unsigned int *value))
  {
+       struct socket_data *s_data = s->resource_data;
        struct resource *res1, *res2;
-       unsigned int info1, info2;
-       int ret = 0;
+       unsigned int info1 = 1, info2 = 1;
+       int ret = -EINVAL;
  
        res1 = claim_region(s, base, size/2, IORESOURCE_MEM, "PCMCIA memprobe");
        res2 = claim_region(s, base + size/2, size/2, IORESOURCE_MEM,
                        "PCMCIA memprobe");
  
        if (res1 && res2) {
-               ret = readable(s, res1, &info1);
-               ret += readable(s, res2, &info2);
+               ret = 0;
+               if (validate) {
+                       ret = validate(s, res1, &info1);
+                       ret += validate(s, res2, &info2);
+               }
        }
  
        free_region(res2);
        free_region(res1);
  
-       return (ret == 2) && (info1 == info2);
- }
+       dev_dbg(&s->dev, "cs: memory probe 0x%06lx-0x%06lx: %p %p %u %u %u",
+               base, base+size-1, res1, res2, ret, info1, info2);
  
- static int
- checksum_match(struct pcmcia_socket *s, unsigned long base, unsigned long size)
- {
-       struct resource *res1, *res2;
-       int a = -1, b = -1;
-       res1 = claim_region(s, base, size/2, IORESOURCE_MEM, "PCMCIA memprobe");
-       res2 = claim_region(s, base + size/2, size/2, IORESOURCE_MEM,
-                       "PCMCIA memprobe");
+       if ((ret) || (info1 != info2) || (info1 == 0))
+               return -EINVAL;
  
-       if (res1 && res2) {
-               a = checksum(s, res1);
-               b = checksum(s, res2);
+       if (validate && !s->fake_cis) {
+               /* move it to the validated data set */
+               add_interval(&s_data->mem_db_valid, base, size);
+               sub_interval(&s_data->mem_db, base, size);
        }
  
-       free_region(res2);
-       free_region(res1);
-       return (a == b) && (a >= 0);
+       return 0;
  }
  
- /*======================================================================
-     The memory probe.  If the memory list includes a 64K-aligned block
-     below 1MB, we probe in 64K chunks, and as soon as we accumulate at
-     least mem_limit free space, we quit.
- ======================================================================*/
  
- static int do_mem_probe(u_long base, u_long num, struct pcmcia_socket *s)
+ /**
+  * do_mem_probe() - validate a memory region for PCMCIA use
+  * @s:                PCMCIA socket to validate
+  * @base:     start address of resource to check
+  * @num:      size of resource to check
+  * @validate: validation function to use
+  * @fallback: validation function to use if validate fails
+  *
+  * do_mem_probe() checks a memory region for use by the PCMCIA subsystem.
+  * To do so, the area is split up into sensible parts, and then passed
+  * into the @validate() function. Only if @validate() and @fallback() fail,
+  * the area is marked as unavaibale for use by the PCMCIA subsystem. The
+  * function returns the size of the usable memory area.
+  */
+ static int do_mem_probe(struct pcmcia_socket *s, u_long base, u_long num,
+                       int validate (struct pcmcia_socket *s,
+                                     struct resource *res,
+                                     unsigned int *value),
+                       int fallback (struct pcmcia_socket *s,
+                                     struct resource *res,
+                                     unsigned int *value))
  {
        struct socket_data *s_data = s->resource_data;
        u_long i, j, bad, fail, step;
        for (i = j = base; i < base+num; i = j + step) {
                if (!fail) {
                        for (j = i; j < base+num; j += step) {
-                               if (cis_readable(s, j, step))
+                               if (!do_validate_mem(s, j, step, validate))
                                        break;
                        }
                        fail = ((i == base) && (j == base+num));
                }
-               if (fail) {
-                       for (j = i; j < base+num; j += 2*step)
-                               if (checksum_match(s, j, step) &&
-                                       checksum_match(s, j + step, step))
+               if ((fail) && (fallback)) {
+                       for (j = i; j < base+num; j += step)
+                               if (!do_validate_mem(s, j, step, fallback))
                                        break;
                }
                if (i != j) {
        return num - bad;
  }
  
  #ifdef CONFIG_PCMCIA_PROBE
  
+ /**
+  * inv_probe() - top-to-bottom search for one usuable high memory area
+  * @s:                PCMCIA socket to validate
+  * @m:                resource_map to check
+  */
  static u_long inv_probe(struct resource_map *m, struct pcmcia_socket *s)
  {
        struct socket_data *s_data = s->resource_data;
        }
        if (m->base < 0x100000)
                return 0;
-       return do_mem_probe(m->base, m->num, s);
+       return do_mem_probe(s, m->base, m->num, readable, checksum);
  }
  
+ /**
+  * validate_mem() - memory probe function
+  * @s:                PCMCIA socket to validate
+  * @probe_mask: MEM_PROBE_LOW | MEM_PROBE_HIGH
+  *
+  * The memory probe.  If the memory list includes a 64K-aligned block
+  * below 1MB, we probe in 64K chunks, and as soon as we accumulate at
+  * least mem_limit free space, we quit. Returns 0 on usuable ports.
+  */
  static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask)
  {
        struct resource_map *m, mm;
        if (probe_mask & MEM_PROBE_HIGH) {
                if (inv_probe(s_data->mem_db.next, s) > 0)
                        return 0;
+               if (s_data->mem_db_valid.next != &s_data->mem_db_valid)
+                       return 0;
                dev_printk(KERN_NOTICE, &s->dev,
                           "cs: warning: no high memory space available!\n");
                return -ENODEV;
                if (mm.base >= 0x100000)
                        continue;
                if ((mm.base | mm.num) & 0xffff) {
-                       ok += do_mem_probe(mm.base, mm.num, s);
+                       ok += do_mem_probe(s, mm.base, mm.num, readable,
+                                          checksum);
                        continue;
                }
                /* Special probe for 64K-aligned block */
                                if (ok >= mem_limit)
                                        sub_interval(&s_data->mem_db, b, 0x10000);
                                else
-                                       ok += do_mem_probe(b, 0x10000, s);
+                                       ok += do_mem_probe(s, b, 0x10000,
+                                                          readable, checksum);
                        }
                }
        }
  
  #else /* CONFIG_PCMCIA_PROBE */
  
+ /**
+  * validate_mem() - memory probe function
+  * @s:                PCMCIA socket to validate
+  * @probe_mask: ignored
+  *
+  * Returns 0 on usuable ports.
+  */
  static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask)
  {
        struct resource_map *m, mm;
  
        for (m = s_data->mem_db.next; m != &s_data->mem_db; m = mm.next) {
                mm = *m;
-               ok += do_mem_probe(mm.base, mm.num, s);
+               ok += do_mem_probe(s, mm.base, mm.num, readable, checksum);
        }
        if (ok > 0)
                return 0;
  #endif /* CONFIG_PCMCIA_PROBE */
  
  
- /*
+ /**
+  * pcmcia_nonstatic_validate_mem() - try to validate iomem for PCMCIA use
+  * @s:                PCMCIA socket to validate
+  *
+  * This is tricky... when we set up CIS memory, we try to validate
+  * the memory window space allocations.
+  *
   * Locking note: Must be called with skt_mutex held!
   */
  static int pcmcia_nonstatic_validate_mem(struct pcmcia_socket *s)
  {
        struct socket_data *s_data = s->resource_data;
        unsigned int probe_mask = MEM_PROBE_LOW;
-       int ret = 0;
+       int ret;
  
-       if (!probe_mem)
+       if (!probe_mem || !(s->state & SOCKET_PRESENT))
                return 0;
  
-       mutex_lock(&rsrc_mutex);
        if (s->features & SS_CAP_PAGE_REGS)
                probe_mask = MEM_PROBE_HIGH;
  
-       if (probe_mask & ~s_data->rsrc_mem_probe) {
-               if (s->state & SOCKET_PRESENT)
-                       ret = validate_mem(s, probe_mask);
-               if (!ret)
-                       s_data->rsrc_mem_probe |= probe_mask;
-       }
+       ret = validate_mem(s, probe_mask);
  
-       mutex_unlock(&rsrc_mutex);
+       if (s_data->mem_db_valid.next != &s_data->mem_db_valid)
+               return 0;
  
        return ret;
  }
@@@ -533,8 -596,8 +596,8 @@@ struct pcmcia_align_data 
        struct resource_map     *map;
  };
  
 -static void
 -pcmcia_common_align(void *align_data, struct resource *res,
 +static resource_size_t
 +pcmcia_common_align(void *align_data, const struct resource *res,
                        resource_size_t size, resource_size_t align)
  {
        struct pcmcia_align_data *data = align_data;
        start = (res->start & ~data->mask) + data->offset;
        if (start < res->start)
                start += data->mask + 1;
 -      res->start = start;
 +      return start;
  }
  
 -static void
 -pcmcia_align(void *align_data, struct resource *res, resource_size_t size,
 -              resource_size_t align)
 +static resource_size_t
 +pcmcia_align(void *align_data, const struct resource *res,
 +      resource_size_t size, resource_size_t align)
  {
        struct pcmcia_align_data *data = align_data;
        struct resource_map *m;
 +      resource_size_t start;
  
 -      pcmcia_common_align(data, res, size, align);
 +      start = pcmcia_common_align(data, res, size, align);
  
        for (m = data->map->next; m != data->map; m = m->next) {
                unsigned long start = m->base;
                 * fit here.
                 */
                if (res->start < start) {
 -                      res->start = start;
 -                      pcmcia_common_align(data, res, size, align);
 +                      start = pcmcia_common_align(data, res, size, align);
                }
  
                /*
         * If we failed to find something suitable, ensure we fail.
         */
        if (m == data->map)
 -              res->start = res->end;
 +              start = res->end;
 +
 +      return start;
  }
  
  /*
@@@ -602,7 -663,6 +665,6 @@@ static int nonstatic_adjust_io_region(s
        struct socket_data *s_data = s->resource_data;
        int ret = -ENOMEM;
  
-       mutex_lock(&rsrc_mutex);
        for (m = s_data->io_db.next; m != &s_data->io_db; m = m->next) {
                unsigned long start = m->base;
                unsigned long end = m->base + m->num - 1;
                ret = adjust_resource(res, r_start, r_end - r_start + 1);
                break;
        }
-       mutex_unlock(&rsrc_mutex);
  
        return ret;
  }
@@@ -647,7 -706,6 +708,6 @@@ static struct resource *nonstatic_find_
        data.offset = base & data.mask;
        data.map = &s_data->io_db;
  
-       mutex_lock(&rsrc_mutex);
  #ifdef CONFIG_PCI
        if (s->cb_dev) {
                ret = pci_bus_alloc_resource(s->cb_dev->bus, res, num, 1,
  #endif
                ret = allocate_resource(&ioport_resource, res, num, min, ~0UL,
                                        1, pcmcia_align, &data);
-       mutex_unlock(&rsrc_mutex);
  
        if (ret != 0) {
                kfree(res);
@@@ -672,15 -729,15 +731,15 @@@ static struct resource *nonstatic_find_
        struct socket_data *s_data = s->resource_data;
        struct pcmcia_align_data data;
        unsigned long min, max;
-       int ret, i;
+       int ret, i, j;
  
        low = low || !(s->features & SS_CAP_PAGE_REGS);
  
        data.mask = align - 1;
        data.offset = base & data.mask;
-       data.map = &s_data->mem_db;
  
        for (i = 0; i < 2; i++) {
+               data.map = &s_data->mem_db_valid;
                if (low) {
                        max = 0x100000UL;
                        min = base < max ? base : 0;
                        min = 0x100000UL + base;
                }
  
-               mutex_lock(&rsrc_mutex);
+               for (j = 0; j < 2; j++) {
  #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
+                       if (s->cb_dev) {
+                               ret = pci_bus_alloc_resource(s->cb_dev->bus,
+                                                       res, num, 1, min, 0,
+                                                       pcmcia_align, &data);
+                       } else
  #endif
-                       ret = allocate_resource(&iomem_resource, res, num, min,
-                                               max, 1, pcmcia_align, &data);
-               mutex_unlock(&rsrc_mutex);
+                       {
+                               ret = allocate_resource(&iomem_resource,
+                                                       res, num, min, max, 1,
+                                                       pcmcia_align, &data);
+                       }
+                       if (ret == 0)
+                               break;
+                       data.map = &s_data->mem_db;
+               }
                if (ret == 0 || low)
                        break;
                low = 1;
@@@ -722,25 -785,18 +787,18 @@@ static int adjust_memory(struct pcmcia_
        if (end < start)
                return -EINVAL;
  
-       mutex_lock(&rsrc_mutex);
        switch (action) {
        case ADD_MANAGED_RESOURCE:
                ret = add_interval(&data->mem_db, start, size);
+               if (!ret)
+                       do_mem_probe(s, start, size, NULL, NULL);
                break;
        case REMOVE_MANAGED_RESOURCE:
                ret = sub_interval(&data->mem_db, start, size);
-               if (!ret) {
-                       struct pcmcia_socket *socket;
-                       down_read(&pcmcia_socket_list_rwsem);
-                       list_for_each_entry(socket, &pcmcia_socket_list, socket_list)
-                               release_cis_mem(socket);
-                       up_read(&pcmcia_socket_list_rwsem);
-               }
                break;
        default:
                ret = -EINVAL;
        }
-       mutex_unlock(&rsrc_mutex);
  
        return ret;
  }
@@@ -758,7 -814,6 +816,6 @@@ static int adjust_io(struct pcmcia_sock
        if (end > IO_SPACE_LIMIT)
                return -EINVAL;
  
-       mutex_lock(&rsrc_mutex);
        switch (action) {
        case ADD_MANAGED_RESOURCE:
                if (add_interval(&data->io_db, start, size) != 0) {
                ret = -EINVAL;
                break;
        }
-       mutex_unlock(&rsrc_mutex);
  
        return ret;
  }
@@@ -803,7 -857,8 +859,7 @@@ static int nonstatic_autoadd_resources(
                return -EINVAL;
  #endif
  
 -      for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) {
 -              res = s->cb_dev->bus->resource[i];
 +      pci_bus_for_each_resource(s->cb_dev->bus, res, i) {
                if (!res)
                        continue;
  
@@@ -860,6 -915,7 +916,7 @@@ static int nonstatic_init(struct pcmcia
                return -ENOMEM;
  
        data->mem_db.next = &data->mem_db;
+       data->mem_db_valid.next = &data->mem_db_valid;
        data->io_db.next = &data->io_db;
  
        s->resource_data = (void *) data;
@@@ -874,7 -930,10 +931,10 @@@ static void nonstatic_release_resource_
        struct socket_data *data = s->resource_data;
        struct resource_map *p, *q;
  
-       mutex_lock(&rsrc_mutex);
+       for (p = data->mem_db_valid.next; p != &data->mem_db_valid; p = q) {
+               q = p->next;
+               kfree(p);
+       }
        for (p = data->mem_db.next; p != &data->mem_db; p = q) {
                q = p->next;
                kfree(p);
                q = p->next;
                kfree(p);
        }
-       mutex_unlock(&rsrc_mutex);
  }
  
  
@@@ -910,7 -968,7 +969,7 @@@ static ssize_t show_io_db(struct devic
        struct resource_map *p;
        ssize_t ret = 0;
  
-       mutex_lock(&rsrc_mutex);
+       mutex_lock(&s->ops_mutex);
        data = s->resource_data;
  
        for (p = data->io_db.next; p != &data->io_db; p = p->next) {
                                ((unsigned long) p->base + p->num - 1));
        }
  
-       mutex_unlock(&rsrc_mutex);
+       mutex_unlock(&s->ops_mutex);
        return ret;
  }
  
@@@ -950,9 -1008,11 +1009,11 @@@ static ssize_t store_io_db(struct devic
        if (end_addr < start_addr)
                return -EINVAL;
  
+       mutex_lock(&s->ops_mutex);
        ret = adjust_io(s, add, start_addr, end_addr);
        if (!ret)
                s->resource_setup_new = 1;
+       mutex_unlock(&s->ops_mutex);
  
        return ret ? ret : count;
  }
@@@ -966,9 -1026,19 +1027,19 @@@ static ssize_t show_mem_db(struct devic
        struct resource_map *p;
        ssize_t ret = 0;
  
-       mutex_lock(&rsrc_mutex);
+       mutex_lock(&s->ops_mutex);
        data = s->resource_data;
  
+       for (p = data->mem_db_valid.next; p != &data->mem_db_valid;
+            p = p->next) {
+               if (ret > (PAGE_SIZE - 10))
+                       continue;
+               ret += snprintf(&buf[ret], (PAGE_SIZE - ret - 1),
+                               "0x%08lx - 0x%08lx\n",
+                               ((unsigned long) p->base),
+                               ((unsigned long) p->base + p->num - 1));
+       }
        for (p = data->mem_db.next; p != &data->mem_db; p = p->next) {
                if (ret > (PAGE_SIZE - 10))
                        continue;
                                ((unsigned long) p->base + p->num - 1));
        }
  
-       mutex_unlock(&rsrc_mutex);
+       mutex_unlock(&s->ops_mutex);
        return ret;
  }
  
@@@ -1006,9 -1076,11 +1077,11 @@@ static ssize_t store_mem_db(struct devi
        if (end_addr < start_addr)
                return -EINVAL;
  
+       mutex_lock(&s->ops_mutex);
        ret = adjust_memory(s, add, start_addr, end_addr);
        if (!ret)
                s->resource_setup_new = 1;
+       mutex_unlock(&s->ops_mutex);
  
        return ret ? ret : count;
  }
index 1f2039d5e9661069bcd12e885551d921db66881c,041a75a7e55eeb2f86e1b60cc05c0be7d0fc541d..b85375f876228883e744d2c23ccc5b4c0667088f
@@@ -37,6 -37,11 +37,11 @@@ static int pwr_irqs_off
  module_param(pwr_irqs_off, bool, 0644);
  MODULE_PARM_DESC(pwr_irqs_off, "Force IRQs off during power-on of slot. Use only when seeing IRQ storms!");
  
+ static char o2_speedup[] = "default";
+ module_param_string(o2_speedup, o2_speedup, sizeof(o2_speedup), 0444);
+ MODULE_PARM_DESC(o2_speedup, "Use prefetch/burst for O2-bridges: 'on', 'off' "
+       "or 'default' (uses recommended behaviour for the detected bridge)");
  #define debug(x, s, args...) dev_dbg(&s->dev->dev, x, ##args)
  
  /* Don't ask.. */
@@@ -649,10 -654,9 +654,10 @@@ static int yenta_search_one_res(struct 
  static int yenta_search_res(struct yenta_socket *socket, struct resource *res,
                            u32 min)
  {
 +      struct resource *root;
        int i;
 -      for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) {
 -              struct resource *root = socket->dev->bus->resource[i];
 +
 +      pci_bus_for_each_resource(socket->dev->bus, root, i) {
                if (!root)
                        continue;
  
index 95421fa3b304d6418abea18b3e770e92fd47c06a,8d38eabda826d838de10610832c851d7a49af802..e91db4b380120fb1eae857179c1d42006b545bb1
@@@ -146,8 -146,7 +146,8 @@@ static void quirk_wakeup_oxsemi(struct 
  {
        struct serial_info *info = link->priv;
  
 -      outb(12, info->c950ctrl + 1);
 +      if (info->c950ctrl)
 +              outb(12, info->c950ctrl + 1);
  }
  
  /* request_region? oxsemi branch does no request_region too... */
@@@ -696,11 -695,11 +696,11 @@@ static int serial_config(struct pcmcia_
                info->multi = info->quirk->multi;
  
        if (info->multi > 1)
-               multi_config(link);
+               i = multi_config(link);
        else
-               simple_config(link);
+               i = simple_config(link);
  
-       if (info->ndev == 0)
+       if (i || info->ndev == 0)
                goto failed;
  
        /*
        return 0;
  
  failed:
+       dev_warn(&link->dev, "serial_cs: failed to initialize\n");
        serial_remove(link);
        return -ENODEV;
  }
@@@ -758,7 -758,6 +759,7 @@@ static struct pcmcia_device_id serial_i
        PCMCIA_PFC_DEVICE_PROD_ID12(1, "PCMCIAs", "LanModem", 0xdcfe12d3, 0xc67c648f),
        PCMCIA_PFC_DEVICE_PROD_ID12(1, "TDK", "GlobalNetworker 3410/3412", 0x1eae9475, 0xd9a93bed),
        PCMCIA_PFC_DEVICE_PROD_ID12(1, "Xircom", "CreditCard Ethernet+Modem II", 0x2e3ee845, 0xeca401bf),
 +      PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0032, 0x0e01),
        PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0032, 0x0a05),
        PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0032, 0x1101),
        PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x0104, 0x0070),