[PATCH] Fix for i82365 problems

Pavel Roskin proski at gnu.org
Mon Apr 19 19:09:31 BST 2004


Hello!

This patch fixes problems with my ISA PCMCIA card.  Namely, the PCMCIA
drivers would stop working after cardmgr is restarted.

The simplest /etc/pcmcia/config.opts to reproduce the problem is this:

include port 0x100-0x1ff
include memory 0xc0000-0xfffff

The default config.opts would have the problem too.  Setting "include
memory" to exclude used areas would work around the problem.

$ cat /proc/iomem
00000000-0009ffff : System RAM
000a0000-000bffff : Video RAM area
000c0000-000c7fff : Video ROM
000f0000-000fffff : System ROM
00100000-3ffeffff : System RAM
...

When I load the modules and run cardmgr, everything is fine:

Linux Kernel Card Services
  options:  [pci] [pm]
Intel ISA PCIC probe:
  Vadem VG-469 ISA-to-PCMCIA at port 0x3e0 ofs 0x00, 2 sockets
    host opts [0]: [ext mode] [isa buf]
    host opts [1]: [ext mode] [isa buf]
    ISA irqs (scanned) = 9 polling interval = 1000 ms
cs: IO port probe 0x0100-0x01ff: clean.
cs: memory probe 0x0d0000-0x0dffff: clean.

The card is supported by orinoco_cs, but it's not installed for
simplicity.  Now I kill cardmgr and start is again.  Kernel log shows:

cs: IO port probe 0x0100-0x01ff: clean.
cs: unable to map card memory!

Following is happening in the driver.  find_mem_region() calls
allocate_resource(), which in turn calls find_resource().  This function
returns the resource starting with 0xd0000 in the first run and with
0xc0000 in the second case.

This happens because pcmcia_align() takes the resource start from mem_db,
the resource map from rsrc_mgr.c.  In the first run, the first entry is
0xd0000-0xdffff.  In the second run, it's 0xc0000-0xfffff, exactly as
written in /etc/pcmcia/config.opts.

As a side note, I don't think it's a good idea to use 0 as the align
argument to allocate_resource().  find_resource() doesn't seem to be
written with this possibility in mind, so it would reset the resource to 0
every time:

new->start = (new->start + align - 1) & ~(align - 1);

~(align - 1) is 0.  It only works because pcmcia_align() is a misnomer -
is sets the resource start without any regard to the suggested value.

Anyway, let's see why mem_db is adjusted the first time but not the
second.  "cs: memory probe" is printed in do_mem_probe(), which is not run
the second time.  The first time, it's run from validate_mem().

validate_mem() has static variables "hi" and "lo".  "lo" prevents
running do_mem_probe() for low memory more than once.  "hi" prevents
running inv_probe() for high memory more than once.

I don't think it's such a good idea considering the scenario when cardmgr
is restarted.  The attached patch removes "hi" and "lo" variables and
allows memory probe every time.  It fixes the problem with cardmgr
restart.  It also removed similar variable "done" in the the other
validate_mem() used without ISA support.

I also tested the patch with TI 1410 without CONFIG_ISA.  I used a high
memory region starting with a busy area.  mem_db was unadjusted after
cardmgr restart (0xd6000000-0xd6100000 rather than actually free
0xd6080000-0xd6100000), but pcmcia_align() would return a free memory
region after several iterations.

After writing all that I realized that it would be better to keep mem_db
unadjusted (i.e as written in /etc/pcmcia/config.opts) and exclude busy
resources only when find_mem_region() is called.  But I'll post the patch
anyway.  It may still be a good interim solution.

-- 
Regards,
Pavel Roskin
-------------- next part --------------
--- linux.orig/drivers/pcmcia/rsrc_mgr.c
+++ linux/drivers/pcmcia/rsrc_mgr.c
@@ -457,7 +457,6 @@ void validate_mem(struct pcmcia_socket *
 {
     resource_map_t *m, mm;
     static u_char order[] = { 0xd0, 0xe0, 0xc0, 0xf0 };
-    static int hi = 0, lo = 0;
     u_long b, i, ok = 0;
     int force_low = !(s->features & SS_CAP_PAGE_REGS);
 
@@ -467,13 +466,11 @@ void validate_mem(struct pcmcia_socket *
     down(&rsrc_sem);
     /* We do up to four passes through the list */
     if (!force_low) {
-	if (hi++ || (inv_probe(mem_db.next, s) > 0))
+	if (inv_probe(mem_db.next, s) > 0)
 	    goto out;
 	printk(KERN_NOTICE "cs: warning: no high memory space "
 	       "available!\n");
     }
-    if (lo++)
-	goto out;
     for (m = mem_db.next; m != &mem_db; m = mm.next) {
 	mm = *m;
 	/* Only probe < 1 MB */
@@ -502,9 +499,8 @@ void validate_mem(struct pcmcia_socket *
 void validate_mem(struct pcmcia_socket *s)
 {
     resource_map_t *m, mm;
-    static int done = 0;
     
-    if (probe_mem && done++ == 0) {
+    if (probe_mem) {
 	down(&rsrc_sem);
 	for (m = mem_db.next; m != &mem_db; m = mm.next) {
 	    mm = *m;


More information about the linux-pcmcia mailing list