pcmcia: validate CIS, not CIS cache.
Dominik Brodowski [Sat, 2 Jan 2010 11:28:04 +0000 (12:28 +0100)]
In pccard_validate_cis(), validate the card CIS, not the CIS cache.
Also, destroy the CIS cache if pccard_validate_cis fails.

Furthermore, do not remove the fake CIS in destroy_cis_cache() but
do so explicitely in the code paths where it makes sense.

Tested-by: Wolfram Sang <w.sang@pengutronix.de>
Signed-off-by: Dominik Brodowski <linux@dominikbrodowski.net>

drivers/pcmcia/cistpl.c
drivers/pcmcia/cs.c
drivers/pcmcia/rsrc_nonstatic.c

index 25b1cd2..41ec772 100644 (file)
@@ -319,22 +319,23 @@ remove_cis_cache(struct pcmcia_socket *s, int attr, u_int addr, u_int len)
                }
 }
 
+/**
+ * destroy_cis_cache() - destroy the CIS cache
+ * @s:         pcmcia_socket for which CIS cache shall be destroyed
+ *
+ * This destroys the CIS cache but keeps any fake CIS alive.
+ */
+
 void destroy_cis_cache(struct pcmcia_socket *s)
 {
        struct list_head *l, *n;
+       struct cis_cache_entry *cis;
 
        list_for_each_safe(l, n, &s->cis_cache) {
-               struct cis_cache_entry *cis = list_entry(l, struct cis_cache_entry, node);
-
+               cis = list_entry(l, struct cis_cache_entry, node);
                list_del(&cis->node);
                kfree(cis);
        }
-
-       /*
-        * If there was a fake CIS, destroy that as well.
-        */
-       kfree(s->fake_cis);
-       s->fake_cis = NULL;
 }
 EXPORT_SYMBOL(destroy_cis_cache);
 
@@ -1596,6 +1597,9 @@ int pccard_validate_cis(struct pcmcia_socket *s, unsigned int *info)
     if (!s)
        return -EINVAL;
 
+    /* We do not want to validate the CIS cache... */
+    destroy_cis_cache(s);
+
     tuple = kmalloc(sizeof(*tuple), GFP_KERNEL);
     if (tuple == NULL) {
            dev_printk(KERN_WARNING, &s->dev, "no memory to validate CIS\n");
@@ -1647,6 +1651,10 @@ int pccard_validate_cis(struct pcmcia_socket *s, unsigned int *info)
        count = 0;
 
 done:
+    /* invalidate CIS cache on failure */
+    if (!dev_ok || !ident_ok || !count)
+           destroy_cis_cache(s);
+
     if (info)
            *info = count;
     kfree(tuple);
index 6d6f82b..96d8d25 100644 (file)
@@ -407,6 +407,8 @@ static void socket_shutdown(struct pcmcia_socket *s)
        s->irq.AssignedIRQ = s->irq.Config = 0;
        s->lock_count = 0;
        destroy_cis_cache(s);
+       kfree(s->fake_cis);
+       s->fake_cis = NULL;
 #ifdef CONFIG_CARDBUS
        cb_free(s);
 #endif
@@ -577,6 +579,8 @@ static int socket_late_resume(struct pcmcia_socket *skt)
                        dev_dbg(&skt->dev, "cis mismatch - different card\n");
                        socket_remove_drivers(skt);
                        destroy_cis_cache(skt);
+                       kfree(skt->fake_cis);
+                       skt->fake_cis = NULL;
                        /*
                         * Workaround: give DS time to schedule removal.
                         * Remove me once the 100ms delay is eliminated
index 4f93889..b886385 100644 (file)
@@ -281,10 +281,9 @@ static int readable(struct pcmcia_socket *s, struct resource *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 */
+               /* invalidate mapping */
                iounmap(s->cis_virt);
                s->cis_virt = NULL;
-               destroy_cis_cache(s);
        }
        s->cis_mem.res = NULL;
        if ((ret != 0) || (*count == 0))