[PATCH] pcmcia fix from 2.4

Paul Mackerras (paulus@au1.ibm.com)
Mon, 30 Sep 2002 15:19:17 +1000 (EST)


Linus,

The patch below is a forward-port from 2.4 of a fix that went in to
the 2.4.x PCMCIA code some time back. It makes sure that that we
request I/O and memory regions from the correct resource (the parent
of the PCMCIA bridge chip, for PCMCIA bridges connected to a PCI bus)
rather than always requesting them from the top-level ioport_resource
or iomem_resource.

Thanks,
Paul.

diff -urN linux-2.5/drivers/pcmcia/cistpl.c pmac-2.5/drivers/pcmcia/cistpl.c
--- linux-2.5/drivers/pcmcia/cistpl.c 2002-02-05 18:55:14.000000000 +1100
+++ pmac-2.5/drivers/pcmcia/cistpl.c 2002-07-21 14:01:56.000000000 +1000
@@ -264,11 +264,11 @@
(s->cis_mem.sys_start == 0)) {
int low = !(s->cap.features & SS_CAP_PAGE_REGS);
vs = s;
- validate_mem(cis_readable, checksum_match, low);
+ validate_mem(cis_readable, checksum_match, low, s);
s->cis_mem.sys_start = 0;
vs = NULL;
if (find_mem_region(&s->cis_mem.sys_start, s->cap.map_size,
- s->cap.map_size, low, "card services")) {
+ s->cap.map_size, low, "card services", s)) {
printk(KERN_NOTICE "cs: unable to map card memory!\n");
return CS_OUT_OF_RESOURCE;
}
diff -urN linux-2.5/drivers/pcmcia/cs.c pmac-2.5/drivers/pcmcia/cs.c
--- linux-2.5/drivers/pcmcia/cs.c 2002-02-05 18:55:14.000000000 +1100
+++ pmac-2.5/drivers/pcmcia/cs.c 2002-07-20 20:41:46.000000000 +1000
@@ -809,7 +809,7 @@
return 1;
for (i = 0; i < MAX_IO_WIN; i++) {
if (s->io[i].NumPorts == 0) {
- if (find_io_region(base, num, align, name) == 0) {
+ if (find_io_region(base, num, align, name, s) == 0) {
s->io[i].Attributes = attr;
s->io[i].BasePort = *base;
s->io[i].NumPorts = s->io[i].InUse = num;
@@ -821,7 +821,7 @@
/* Try to extend top of window */
try = s->io[i].BasePort + s->io[i].NumPorts;
if ((*base == 0) || (*base == try))
- if (find_io_region(&try, num, 0, name) == 0) {
+ if (find_io_region(&try, num, 0, name, s) == 0) {
*base = try;
s->io[i].NumPorts += num;
s->io[i].InUse += num;
@@ -830,7 +830,7 @@
/* Try to extend bottom of window */
try = s->io[i].BasePort - num;
if ((*base == 0) || (*base == try))
- if (find_io_region(&try, num, 0, name) == 0) {
+ if (find_io_region(&try, num, 0, name, s) == 0) {
s->io[i].BasePort = *base = try;
s->io[i].NumPorts += num;
s->io[i].InUse += num;
@@ -1974,7 +1974,7 @@
find_mem_region(&win->base, win->size, align,
(req->Attributes & WIN_MAP_BELOW_1MB) ||
!(s->cap.features & SS_CAP_PAGE_REGS),
- (*handle)->dev_info))
+ (*handle)->dev_info, s))
return CS_IN_USE;
(*handle)->state |= CLIENT_WIN_REQ(w);

diff -urN linux-2.5/drivers/pcmcia/cs_internal.h pmac-2.5/drivers/pcmcia/cs_internal.h
--- linux-2.5/drivers/pcmcia/cs_internal.h 2002-02-06 04:40:18.000000000 +1100
+++ pmac-2.5/drivers/pcmcia/cs_internal.h 2002-07-20 20:38:06.000000000 +1000
@@ -238,11 +238,11 @@

/* In rsrc_mgr */
void validate_mem(int (*is_valid)(u_long), int (*do_cksum)(u_long),
- int force_low);
+ int force_low, socket_info_t *s);
int find_io_region(ioaddr_t *base, ioaddr_t num, ioaddr_t align,
- char *name);
+ char *name, socket_info_t *s);
int find_mem_region(u_long *base, u_long num, u_long align,
- int force_low, char *name);
+ int force_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 -urN linux-2.5/drivers/pcmcia/rsrc_mgr.c pmac-2.5/drivers/pcmcia/rsrc_mgr.c
--- linux-2.5/drivers/pcmcia/rsrc_mgr.c 2002-02-05 18:55:14.000000000 +1100
+++ pmac-2.5/drivers/pcmcia/rsrc_mgr.c 2002-07-21 14:02:02.000000000 +1000
@@ -44,6 +44,7 @@
#include <linux/ioport.h>
#include <linux/timer.h>
#include <linux/proc_fs.h>
+#include <linux/pci.h>
#include <asm/irq.h>
#include <asm/io.h>

@@ -103,8 +104,82 @@

======================================================================*/

-#define check_io_resource(b,n) check_resource(&ioport_resource, (b), (n))
-#define check_mem_resource(b,n) check_resource(&iomem_resource, (b), (n))
+static struct resource *resource_parent(unsigned long b, unsigned long n,
+ int flags, struct pci_dev *dev)
+{
+#ifdef CONFIG_PCI
+ struct resource res, *pr;
+
+ if (dev != NULL) {
+ res.start = b;
+ res.end = b + n - 1;
+ res.flags = flags;
+ pr = pci_find_parent_resource(dev, &res);
+ if (pr)
+ return pr;
+ }
+#endif /* CONFIG_PCI */
+ if (flags & IORESOURCE_MEM)
+ return &iomem_resource;
+ return &ioport_resource;
+}
+
+static inline int check_io_resource(unsigned long b, unsigned long n,
+ struct pci_dev *dev)
+{
+ return check_resource(resource_parent(b, n, IORESOURCE_IO, dev), b, n);
+}
+
+static inline int check_mem_resource(unsigned long b, unsigned long n,
+ struct pci_dev *dev)
+{
+ return check_resource(resource_parent(b, n, IORESOURCE_MEM, dev), b, n);
+}
+
+static struct resource *make_resource(unsigned long b, unsigned long n,
+ int flags, char *name)
+{
+ struct resource *res = kmalloc(sizeof(*res), GFP_KERNEL);
+
+ if (res) {
+ memset(res, 0, sizeof(*res));
+ res->name = name;
+ res->start = b;
+ res->end = b + n - 1;
+ res->flags = flags | IORESOURCE_BUSY;
+ }
+ return res;
+}
+
+static int request_io_resource(unsigned long b, unsigned long n,
+ char *name, struct pci_dev *dev)
+{
+ struct resource *res = make_resource(b, n, IORESOURCE_IO, name);
+ struct resource *pr = resource_parent(b, n, IORESOURCE_IO, dev);
+ int err = -ENOMEM;
+
+ if (res) {
+ err = request_resource(pr, res);
+ if (err)
+ kfree(res);
+ }
+ return err;
+}
+
+static int 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);
+ struct resource *pr = resource_parent(b, n, IORESOURCE_MEM, dev);
+ int err = -ENOMEM;
+
+ if (res) {
+ err = request_resource(pr, res);
+ if (err)
+ kfree(res);
+ }
+ return err;
+}

/*======================================================================

@@ -194,7 +269,7 @@
}
memset(b, 0, 256);
for (i = base, most = 0; i < base+num; i += 8) {
- if (check_io_resource(i, 8))
+ if (check_io_resource(i, 8, NULL))
continue;
hole = inb(i);
for (j = 1; j < 8; j++)
@@ -207,7 +282,7 @@

bad = any = 0;
for (i = base; i < base+num; i += 8) {
- if (check_io_resource(i, 8))
+ if (check_io_resource(i, 8, NULL))
continue;
for (j = 0; j < 8; j++)
if (inb(i+j) != most) break;
@@ -247,7 +322,8 @@
======================================================================*/

static int do_mem_probe(u_long base, u_long num,
- int (*is_valid)(u_long), int (*do_cksum)(u_long))
+ int (*is_valid)(u_long), int (*do_cksum)(u_long),
+ socket_info_t *s)
{
u_long i, j, bad, fail, step;

@@ -258,13 +334,14 @@
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) == 0) && is_valid(j))
+ if ((check_mem_resource(j, step, s->cap.cb_dev) == 0) &&
+ is_valid(j))
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) == 0) &&
+ if ((check_mem_resource(j, 2*step, s->cap.cb_dev) == 0) &&
do_cksum(j) && do_cksum(j+step))
break;
}
@@ -283,12 +360,12 @@

static u_long inv_probe(int (*is_valid)(u_long),
int (*do_cksum)(u_long),
- resource_map_t *m)
+ resource_map_t *m, socket_info_t *s)
{
u_long ok;
if (m == &mem_db)
return 0;
- ok = inv_probe(is_valid, do_cksum, m->next);
+ ok = inv_probe(is_valid, do_cksum, m->next, s);
if (ok) {
if (m->base >= 0x100000)
sub_interval(&mem_db, m->base, m->num);
@@ -296,11 +373,11 @@
}
if (m->base < 0x100000)
return 0;
- return do_mem_probe(m->base, m->num, is_valid, do_cksum);
+ return do_mem_probe(m->base, m->num, is_valid, do_cksum, s);
}

void validate_mem(int (*is_valid)(u_long), int (*do_cksum)(u_long),
- int force_low)
+ int force_low, socket_info_t *s)
{
resource_map_t *m, *n;
static u_char order[] = { 0xd0, 0xe0, 0xc0, 0xf0 };
@@ -310,7 +387,7 @@
if (!probe_mem) return;
/* We do up to four passes through the list */
if (!force_low) {
- if (hi++ || (inv_probe(is_valid, do_cksum, mem_db.next) > 0))
+ if (hi++ || (inv_probe(is_valid, do_cksum, mem_db.next, s) > 0))
return;
printk(KERN_NOTICE "cs: warning: no high memory space "
"available!\n");
@@ -321,7 +398,7 @@
/* Only probe < 1 MB */
if (m->base >= 0x100000) continue;
if ((m->base | m->num) & 0xffff) {
- ok += do_mem_probe(m->base, m->num, is_valid, do_cksum);
+ ok += do_mem_probe(m->base, m->num, is_valid, do_cksum, s);
continue;
}
/* Special probe for 64K-aligned block */
@@ -331,7 +408,7 @@
if (ok >= mem_limit)
sub_interval(&mem_db, b, 0x10000);
else
- ok += do_mem_probe(b, 0x10000, is_valid, do_cksum);
+ ok += do_mem_probe(b, 0x10000, is_valid, do_cksum, s);
}
}
}
@@ -340,7 +417,7 @@
#else /* CONFIG_ISA */

void validate_mem(int (*is_valid)(u_long), int (*do_cksum)(u_long),
- int force_low)
+ int force_low, socket_info_t *s)
{
resource_map_t *m;
static int done = 0;
@@ -348,7 +425,7 @@
if (!probe_mem || done++)
return;
for (m = mem_db.next; m != &mem_db; m = m->next)
- if (do_mem_probe(m->base, m->num, is_valid, do_cksum))
+ if (do_mem_probe(m->base, m->num, is_valid, do_cksum, s))
return;
}

@@ -368,7 +445,7 @@
======================================================================*/

int find_io_region(ioaddr_t *base, ioaddr_t num, ioaddr_t align,
- char *name)
+ char *name, socket_info_t *s)
{
ioaddr_t try;
resource_map_t *m;
@@ -378,9 +455,8 @@
for (try = (try >= m->base) ? try : try+align;
(try >= m->base) && (try+num <= m->base+m->num);
try += align) {
- if (check_io_resource(try, num) == 0) {
+ if (request_io_resource(try, num, name, s->cap.cb_dev) == 0) {
*base = try;
- request_region(try, num, name);
return 0;
}
if (!align) break;
@@ -390,7 +466,7 @@
}

int find_mem_region(u_long *base, u_long num, u_long align,
- int force_low, char *name)
+ int force_low, char *name, socket_info_t *s)
{
u_long try;
resource_map_t *m;
@@ -403,8 +479,7 @@
for (try = (try >= m->base) ? try : try+align;
(try >= m->base) && (try+num <= m->base+m->num);
try += align) {
- if (check_mem_resource(try, num) == 0) {
- request_mem_region(try, num, name);
+ if (request_mem_resource(try, num, name, s->cap.cb_dev) == 0) {
*base = try;
return 0;
}
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/