rsrc_nonstatic.c 26.9 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
/*
 * rsrc_nonstatic.c -- Resource management routines for !SS_CAP_STATIC_MAP sockets
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * The initial developer of the original code is David A. Hinds
 * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
 * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
 *
 * (C) 1999		David A. Hinds
 */

#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/timer.h>
#include <linux/pci.h>
#include <linux/device.h>
D
Dominik Brodowski 已提交
27
#include <linux/io.h>
L
Linus Torvalds 已提交
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61

#include <asm/irq.h>

#include <pcmcia/cs_types.h>
#include <pcmcia/ss.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include "cs_internal.h"

MODULE_AUTHOR("David A. Hinds, Dominik Brodowski");
MODULE_LICENSE("GPL");

/* Parameters that can be set with 'insmod' */

#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0444)

INT_MODULE_PARM(probe_mem,	1);		/* memory probe? */
#ifdef CONFIG_PCMCIA_PROBE
INT_MODULE_PARM(probe_io,	1);		/* IO port probe? */
INT_MODULE_PARM(mem_limit,	0x10000);
#endif

/* for io_db and mem_db */
struct resource_map {
	u_long			base, num;
	struct resource_map	*next;
};

struct socket_data {
	struct resource_map		mem_db;
	struct resource_map		io_db;
	unsigned int			rsrc_mem_probe;
};

62
static DEFINE_MUTEX(rsrc_mutex);
L
Linus Torvalds 已提交
63 64 65 66 67 68 69 70 71 72 73
#define MEM_PROBE_LOW	(1 << 0)
#define MEM_PROBE_HIGH	(1 << 1)


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

    Linux resource management extensions

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

static struct resource *
74
make_resource(resource_size_t b, resource_size_t n, int flags, const char *name)
L
Linus Torvalds 已提交
75
{
76
	struct resource *res = kzalloc(sizeof(*res), GFP_KERNEL);
L
Linus Torvalds 已提交
77 78 79 80 81 82 83 84 85 86 87

	if (res) {
		res->name = name;
		res->start = b;
		res->end = b + n - 1;
		res->flags = flags;
	}
	return res;
}

static struct resource *
88 89
claim_region(struct pcmcia_socket *s, resource_size_t base,
		resource_size_t size, int type, char *name)
L
Linus Torvalds 已提交
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
{
	struct resource *res, *parent;

	parent = type & IORESOURCE_MEM ? &iomem_resource : &ioport_resource;
	res = make_resource(base, size, type | IORESOURCE_BUSY, name);

	if (res) {
#ifdef CONFIG_PCI
		if (s && s->cb_dev)
			parent = pci_find_parent_resource(s->cb_dev, res);
#endif
		if (!parent || request_resource(parent, res)) {
			kfree(res);
			res = NULL;
		}
	}
	return res;
}

static void free_region(struct resource *res)
{
	if (res) {
		release_resource(res);
		kfree(res);
	}
}

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

    These manage the internal databases of available resources.

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

static int add_interval(struct resource_map *map, u_long base, u_long num)
{
125
	struct resource_map *p, *q;
L
Linus Torvalds 已提交
126

127 128 129 130 131 132 133 134 135 136 137 138 139 140
	for (p = map; ; p = p->next) {
		if ((p != map) && (p->base+p->num-1 >= base))
			return -1;
		if ((p->next == map) || (p->next->base > base+num-1))
			break;
	}
	q = kmalloc(sizeof(struct resource_map), GFP_KERNEL);
	if (!q) {
		printk(KERN_WARNING "out of memory to update resources\n");
		return -ENOMEM;
	}
	q->base = base; q->num = num;
	q->next = p->next; p->next = q;
	return 0;
L
Linus Torvalds 已提交
141 142 143 144 145 146
}

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

static int sub_interval(struct resource_map *map, u_long base, u_long num)
{
D
Dominik Brodowski 已提交
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
	struct resource_map *p, *q;

	for (p = map; ; p = q) {
		q = p->next;
		if (q == map)
			break;
		if ((q->base+q->num > base) && (base+num > q->base)) {
			if (q->base >= base) {
				if (q->base+q->num <= base+num) {
					/* Delete whole block */
					p->next = q->next;
					kfree(q);
					/* don't advance the pointer yet */
					q = p;
				} else {
					/* Cut off bit from the front */
					q->num = q->base + q->num - base - num;
					q->base = base + num;
				}
			} else if (q->base+q->num <= base+num) {
				/* Cut off bit from the end */
				q->num = base - q->base;
			} else {
				/* Split the block into two pieces */
				p = kmalloc(sizeof(struct resource_map),
					GFP_KERNEL);
				if (!p) {
					printk(KERN_WARNING "out of memory to update resources\n");
					return -ENOMEM;
				}
				p->base = base+num;
				p->num = q->base+q->num - p->base;
				q->num = base - q->base;
				p->next = q->next ; q->next = p;
			}
182
		}
D
Dominik Brodowski 已提交
183 184
	}
	return 0;
L
Linus Torvalds 已提交
185 186 187 188 189 190 191 192 193 194
}

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

    These routines examine a region of IO or memory addresses to
    determine what ranges might be genuinely available.

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

#ifdef CONFIG_PCMCIA_PROBE
195 196
static void do_io_probe(struct pcmcia_socket *s, unsigned int base,
			unsigned int num)
L
Linus Torvalds 已提交
197
{
D
Dominik Brodowski 已提交
198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263
	struct resource *res;
	struct socket_data *s_data = s->resource_data;
	unsigned int i, j, bad;
	int any;
	u_char *b, hole, most;

	dev_printk(KERN_INFO, &s->dev, "cs: IO port probe %#x-%#x:",
		base, base+num-1);

	/* First, what does a floating port look like? */
	b = kzalloc(256, GFP_KERNEL);
	if (!b) {
		printk("\n");
		dev_printk(KERN_ERR, &s->dev,
			"do_io_probe: unable to kmalloc 256 bytes");
		return;
	}
	for (i = base, most = 0; i < base+num; i += 8) {
		res = claim_region(NULL, i, 8, IORESOURCE_IO, "PCMCIA ioprobe");
		if (!res)
			continue;
		hole = inb(i);
		for (j = 1; j < 8; j++)
			if (inb(i+j) != hole)
				break;
		free_region(res);
		if ((j == 8) && (++b[hole] > b[most]))
			most = hole;
		if (b[most] == 127)
			break;
	}
	kfree(b);

	bad = any = 0;
	for (i = base; i < base+num; i += 8) {
		res = claim_region(NULL, i, 8, IORESOURCE_IO, "PCMCIA ioprobe");
		if (!res)
			continue;
		for (j = 0; j < 8; j++)
			if (inb(i+j) != most)
				break;
		free_region(res);
		if (j < 8) {
			if (!any)
				printk(" excluding");
			if (!bad)
				bad = any = i;
		} else {
			if (bad) {
				sub_interval(&s_data->io_db, bad, i-bad);
				printk(" %#x-%#x", bad, i-1);
				bad = 0;
			}
		}
	}
	if (bad) {
		if ((num > 16) && (bad == base) && (i == base+num)) {
			printk(" nothing: probe failed.\n");
			return;
		} else {
			sub_interval(&s_data->io_db, bad, i-bad);
			printk(" %#x-%#x", bad, i-1);
		}
	}

	printk(any ? "\n" : " clean.\n");
L
Linus Torvalds 已提交
264 265 266
}
#endif

267
/*======================================================================*/
L
Linus Torvalds 已提交
268

269 270 271
/**
 * readable() - iomem validation function for cards with a valid CIS
 */
272 273
static int readable(struct pcmcia_socket *s, struct resource *res,
		    unsigned int *count)
L
Linus Torvalds 已提交
274
{
275
	int ret = -EINVAL;
L
Linus Torvalds 已提交
276

277
	mutex_lock(&s->ops_mutex);
L
Linus Torvalds 已提交
278 279 280
	s->cis_mem.res = res;
	s->cis_virt = ioremap(res->start, s->map_size);
	if (s->cis_virt) {
281
		mutex_unlock(&s->ops_mutex);
282 283 284
		/* as we're only called from pcmcia.c, we're safe */
		if (s->callback->validate)
			ret = s->callback->validate(s, count);
285
		/* invalidate mapping */
286
		mutex_lock(&s->ops_mutex);
L
Linus Torvalds 已提交
287 288 289 290
		iounmap(s->cis_virt);
		s->cis_virt = NULL;
	}
	s->cis_mem.res = NULL;
291
	mutex_unlock(&s->ops_mutex);
292 293 294
	if ((ret) || (*count == 0))
		return -EINVAL;
	return 0;
L
Linus Torvalds 已提交
295 296
}

297 298 299 300 301
/**
 * checksum() - iomem validation function for simple memory cards
 */
static int checksum(struct pcmcia_socket *s, struct resource *res,
		    unsigned int *value)
L
Linus Torvalds 已提交
302 303 304 305 306
{
	pccard_mem_map map;
	int i, a = 0, b = -1, d;
	void __iomem *virt;

307 308
	mutex_lock(&s->ops_mutex);

L
Linus Torvalds 已提交
309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330
	virt = ioremap(res->start, s->map_size);
	if (virt) {
		map.map = 0;
		map.flags = MAP_ACTIVE;
		map.speed = 0;
		map.res = res;
		map.card_start = 0;
		s->ops->set_mem_map(s, &map);

		/* Don't bother checking every word... */
		for (i = 0; i < s->map_size; i += 44) {
			d = readl(virt+i);
			a += d;
			b &= d;
		}

		map.flags = 0;
		s->ops->set_mem_map(s, &map);

		iounmap(virt);
	}

331 332
	mutex_unlock(&s->ops_mutex);

333 334
	if (b == -1)
		return -EINVAL;
L
Linus Torvalds 已提交
335

336
	*value = a;
L
Linus Torvalds 已提交
337

338
	return 0;
L
Linus Torvalds 已提交
339 340
}

341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358
/**
 * 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))
L
Linus Torvalds 已提交
359 360
{
	struct resource *res1, *res2;
361 362
	unsigned int info1 = 1, info2 = 1;
	int ret = -EINVAL;
L
Linus Torvalds 已提交
363

D
Dominik Brodowski 已提交
364 365 366
	res1 = claim_region(s, base, size/2, IORESOURCE_MEM, "PCMCIA memprobe");
	res2 = claim_region(s, base + size/2, size/2, IORESOURCE_MEM,
			"PCMCIA memprobe");
L
Linus Torvalds 已提交
367 368

	if (res1 && res2) {
369 370 371 372 373
		ret = 0;
		if (validate) {
			ret = validate(s, res1, &info1);
			ret += validate(s, res2, &info2);
		}
L
Linus Torvalds 已提交
374 375 376 377 378
	}

	free_region(res2);
	free_region(res1);

379 380
	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);
L
Linus Torvalds 已提交
381

382 383
	if ((ret) || (info1 != info2) || (info1 == 0))
		return -EINVAL;
L
Linus Torvalds 已提交
384

385 386
	return 0;
}
L
Linus Torvalds 已提交
387 388


389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409
/**
 * 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))
L
Linus Torvalds 已提交
410
{
D
Dominik Brodowski 已提交
411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426
	struct socket_data *s_data = s->resource_data;
	u_long i, j, bad, fail, step;

	dev_printk(KERN_INFO, &s->dev, "cs: memory probe 0x%06lx-0x%06lx:",
		base, base+num-1);
	bad = fail = 0;
	step = (num < 0x20000) ? 0x2000 : ((num>>4) & ~0x1fff);
	/* don't allow too large steps */
	if (step > 0x800000)
		step = 0x800000;
	/* cis_readable wants to map 2x map_size */
	if (step < 2 * s->map_size)
		step = 2 * s->map_size;
	for (i = j = base; i < base+num; i = j + step) {
		if (!fail) {
			for (j = i; j < base+num; j += step) {
427
				if (!do_validate_mem(s, j, step, validate))
D
Dominik Brodowski 已提交
428 429 430 431
					break;
			}
			fail = ((i == base) && (j == base+num));
		}
432 433 434
		if ((fail) && (fallback)) {
			for (j = i; j < base+num; j += step)
				if (!do_validate_mem(s, j, step, fallback))
D
Dominik Brodowski 已提交
435 436 437 438 439 440 441 442 443 444 445 446
					break;
		}
		if (i != j) {
			if (!bad)
				printk(" excluding");
			printk(" %#05lx-%#05lx", i, j-1);
			sub_interval(&s_data->mem_db, i, j-i);
			bad += j-i;
		}
	}
	printk(bad ? "\n" : " clean.\n");
	return num - bad;
L
Linus Torvalds 已提交
447 448
}

449

L
Linus Torvalds 已提交
450 451
#ifdef CONFIG_PCMCIA_PROBE

452 453 454 455 456
/**
 * inv_probe() - top-to-bottom search for one usuable high memory area
 * @s:		PCMCIA socket to validate
 * @m:		resource_map to check
 */
L
Linus Torvalds 已提交
457 458
static u_long inv_probe(struct resource_map *m, struct pcmcia_socket *s)
{
459 460 461 462 463 464 465 466 467 468 469 470
	struct socket_data *s_data = s->resource_data;
	u_long ok;
	if (m == &s_data->mem_db)
		return 0;
	ok = inv_probe(m->next, s);
	if (ok) {
		if (m->base >= 0x100000)
			sub_interval(&s_data->mem_db, m->base, m->num);
		return ok;
	}
	if (m->base < 0x100000)
		return 0;
471
	return do_mem_probe(s, m->base, m->num, readable, checksum);
L
Linus Torvalds 已提交
472 473
}

474 475 476 477 478 479 480 481 482
/**
 * 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.
 */
483
static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask)
L
Linus Torvalds 已提交
484
{
485 486 487 488
	struct resource_map *m, mm;
	static unsigned char order[] = { 0xd0, 0xe0, 0xc0, 0xf0 };
	unsigned long b, i, ok = 0;
	struct socket_data *s_data = s->resource_data;
L
Linus Torvalds 已提交
489

490 491 492 493
	/* We do up to four passes through the list */
	if (probe_mask & MEM_PROBE_HIGH) {
		if (inv_probe(s_data->mem_db.next, s) > 0)
			return 0;
494 495
		dev_printk(KERN_NOTICE, &s->dev,
			   "cs: warning: no high memory space available!\n");
496
		return -ENODEV;
L
Linus Torvalds 已提交
497
	}
498 499 500 501 502 503 504

	for (m = s_data->mem_db.next; m != &s_data->mem_db; m = mm.next) {
		mm = *m;
		/* Only probe < 1 MB */
		if (mm.base >= 0x100000)
			continue;
		if ((mm.base | mm.num) & 0xffff) {
505 506
			ok += do_mem_probe(s, mm.base, mm.num, readable,
					   checksum);
507 508 509 510 511 512 513 514 515
			continue;
		}
		/* Special probe for 64K-aligned block */
		for (i = 0; i < 4; i++) {
			b = order[i] << 12;
			if ((b >= mm.base) && (b+0x10000 <= mm.base+mm.num)) {
				if (ok >= mem_limit)
					sub_interval(&s_data->mem_db, b, 0x10000);
				else
516 517
					ok += do_mem_probe(s, b, 0x10000,
							   readable, checksum);
518 519
			}
		}
L
Linus Torvalds 已提交
520
	}
521 522 523 524 525

	if (ok > 0)
		return 0;

	return -ENODEV;
L
Linus Torvalds 已提交
526 527 528 529
}

#else /* CONFIG_PCMCIA_PROBE */

530 531 532 533 534 535 536
/**
 * validate_mem() - memory probe function
 * @s:		PCMCIA socket to validate
 * @probe_mask: ignored
 *
 * Returns 0 on usuable ports.
 */
A
Andrew Morton 已提交
537
static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask)
L
Linus Torvalds 已提交
538 539 540
{
	struct resource_map *m, mm;
	struct socket_data *s_data = s->resource_data;
A
Andrew Morton 已提交
541
	unsigned long ok = 0;
L
Linus Torvalds 已提交
542 543 544

	for (m = s_data->mem_db.next; m != &s_data->mem_db; m = mm.next) {
		mm = *m;
545
		ok += do_mem_probe(s, mm.base, mm.num, readable, checksum);
L
Linus Torvalds 已提交
546
	}
A
Andrew Morton 已提交
547 548 549
	if (ok > 0)
		return 0;
	return -ENODEV;
L
Linus Torvalds 已提交
550 551 552 553 554
}

#endif /* CONFIG_PCMCIA_PROBE */


555 556 557 558 559 560 561
/**
 * 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.
 *
562
 * Locking note: Must be called with skt_mutex held!
L
Linus Torvalds 已提交
563
 */
564
static int pcmcia_nonstatic_validate_mem(struct pcmcia_socket *s)
L
Linus Torvalds 已提交
565 566
{
	struct socket_data *s_data = s->resource_data;
567 568 569 570 571
	unsigned int probe_mask = MEM_PROBE_LOW;
	int ret = 0;

	if (!probe_mem)
		return 0;
L
Linus Torvalds 已提交
572

573
	mutex_lock(&rsrc_mutex);
L
Linus Torvalds 已提交
574

575 576
	if (s->features & SS_CAP_PAGE_REGS)
		probe_mask = MEM_PROBE_HIGH;
L
Linus Torvalds 已提交
577

578
	if (probe_mask & ~s_data->rsrc_mem_probe) {
579
		if (s->state & SOCKET_PRESENT) {
580
			ret = validate_mem(s, probe_mask);
581 582 583
			if (!ret)
				s_data->rsrc_mem_probe |= probe_mask;
		}
584
	}
L
Linus Torvalds 已提交
585

586
	mutex_unlock(&rsrc_mutex);
L
Linus Torvalds 已提交
587

588
	return ret;
L
Linus Torvalds 已提交
589 590 591 592 593 594 595 596 597 598
}

struct pcmcia_align_data {
	unsigned long	mask;
	unsigned long	offset;
	struct resource_map	*map;
};

static void
pcmcia_common_align(void *align_data, struct resource *res,
599
			resource_size_t size, resource_size_t align)
L
Linus Torvalds 已提交
600 601
{
	struct pcmcia_align_data *data = align_data;
602
	resource_size_t start;
L
Linus Torvalds 已提交
603 604 605 606 607 608 609 610 611 612
	/*
	 * Ensure that we have the correct start address
	 */
	start = (res->start & ~data->mask) + data->offset;
	if (start < res->start)
		start += data->mask + 1;
	res->start = start;
}

static void
613 614
pcmcia_align(void *align_data, struct resource *res, resource_size_t size,
		resource_size_t align)
L
Linus Torvalds 已提交
615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663
{
	struct pcmcia_align_data *data = align_data;
	struct resource_map *m;

	pcmcia_common_align(data, res, size, align);

	for (m = data->map->next; m != data->map; m = m->next) {
		unsigned long start = m->base;
		unsigned long end = m->base + m->num - 1;

		/*
		 * If the lower resources are not available, try aligning
		 * to this entry of the resource database to see if it'll
		 * fit here.
		 */
		if (res->start < start) {
			res->start = start;
			pcmcia_common_align(data, res, size, align);
		}

		/*
		 * If we're above the area which was passed in, there's
		 * no point proceeding.
		 */
		if (res->start >= res->end)
			break;

		if ((res->start + size - 1) <= end)
			break;
	}

	/*
	 * If we failed to find something suitable, ensure we fail.
	 */
	if (m == data->map)
		res->start = res->end;
}

/*
 * Adjust an existing IO region allocation, but making sure that we don't
 * encroach outside the resources which the user supplied.
 */
static int nonstatic_adjust_io_region(struct resource *res, unsigned long r_start,
				      unsigned long r_end, struct pcmcia_socket *s)
{
	struct resource_map *m;
	struct socket_data *s_data = s->resource_data;
	int ret = -ENOMEM;

664
	mutex_lock(&rsrc_mutex);
L
Linus Torvalds 已提交
665 666 667 668 669 670 671 672 673 674
	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;

		if (start > r_start || r_end > end)
			continue;

		ret = adjust_resource(res, r_start, r_end - r_start + 1);
		break;
	}
675
	mutex_unlock(&rsrc_mutex);
L
Linus Torvalds 已提交
676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692

	return ret;
}

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

    These find ranges of I/O ports or memory addresses that are not
    currently allocated by other devices.

    The 'align' field should reflect the number of bits of address
    that need to be preserved from the initial value of *base.  It
    should be a power of two, greater than or equal to 'num'.  A value
    of 0 means that all bits of *base are significant.  *base should
    also be strictly less than 'align'.

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

D
Dominik Brodowski 已提交
693
static struct resource *nonstatic_find_io_region(unsigned long base, int num,
L
Linus Torvalds 已提交
694 695
		   unsigned long align, struct pcmcia_socket *s)
{
696
	struct resource *res = make_resource(0, num, IORESOURCE_IO, dev_name(&s->dev));
L
Linus Torvalds 已提交
697 698 699 700 701 702 703 704 705 706 707 708
	struct socket_data *s_data = s->resource_data;
	struct pcmcia_align_data data;
	unsigned long min = base;
	int ret;

	if (align == 0)
		align = 0x10000;

	data.mask = align - 1;
	data.offset = base & data.mask;
	data.map = &s_data->io_db;

709
	mutex_lock(&rsrc_mutex);
L
Linus Torvalds 已提交
710 711 712 713 714 715 716 717
#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
#endif
		ret = allocate_resource(&ioport_resource, res, num, min, ~0UL,
					1, pcmcia_align, &data);
718
	mutex_unlock(&rsrc_mutex);
L
Linus Torvalds 已提交
719 720 721 722 723 724 725 726

	if (ret != 0) {
		kfree(res);
		res = NULL;
	}
	return res;
}

D
Dominik Brodowski 已提交
727
static struct resource *nonstatic_find_mem_region(u_long base, u_long num,
D
Dominik Brodowski 已提交
728
		u_long align, int low, struct pcmcia_socket *s)
L
Linus Torvalds 已提交
729
{
730
	struct resource *res = make_resource(0, num, IORESOURCE_MEM, dev_name(&s->dev));
L
Linus Torvalds 已提交
731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750
	struct socket_data *s_data = s->resource_data;
	struct pcmcia_align_data data;
	unsigned long min, max;
	int ret, i;

	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++) {
		if (low) {
			max = 0x100000UL;
			min = base < max ? base : 0;
		} else {
			max = ~0UL;
			min = 0x100000UL + base;
		}

751
		mutex_lock(&rsrc_mutex);
L
Linus Torvalds 已提交
752 753 754 755 756 757 758 759 760
#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
#endif
			ret = allocate_resource(&iomem_resource, res, num, min,
						max, 1, pcmcia_align, &data);
761
		mutex_unlock(&rsrc_mutex);
L
Linus Torvalds 已提交
762 763 764 765 766 767 768 769 770 771 772 773 774
		if (ret == 0 || low)
			break;
		low = 1;
	}

	if (ret != 0) {
		kfree(res);
		res = NULL;
	}
	return res;
}


775
static int adjust_memory(struct pcmcia_socket *s, unsigned int action, unsigned long start, unsigned long end)
L
Linus Torvalds 已提交
776 777
{
	struct socket_data *data = s->resource_data;
778 779
	unsigned long size = end - start + 1;
	int ret = 0;
L
Linus Torvalds 已提交
780

781
	if (end < start)
782
		return -EINVAL;
L
Linus Torvalds 已提交
783

784
	mutex_lock(&rsrc_mutex);
785
	switch (action) {
L
Linus Torvalds 已提交
786
	case ADD_MANAGED_RESOURCE:
787
		ret = add_interval(&data->mem_db, start, size);
788 789
		if (!ret)
			do_mem_probe(s, start, size, NULL, NULL);
L
Linus Torvalds 已提交
790 791
		break;
	case REMOVE_MANAGED_RESOURCE:
792
		ret = sub_interval(&data->mem_db, start, size);
L
Linus Torvalds 已提交
793 794
		break;
	default:
795
		ret = -EINVAL;
L
Linus Torvalds 已提交
796
	}
797
	mutex_unlock(&rsrc_mutex);
L
Linus Torvalds 已提交
798 799 800 801 802

	return ret;
}


803
static int adjust_io(struct pcmcia_socket *s, unsigned int action, unsigned long start, unsigned long end)
L
Linus Torvalds 已提交
804 805
{
	struct socket_data *data = s->resource_data;
806 807
	unsigned long size = end - start + 1;
	int ret = 0;
L
Linus Torvalds 已提交
808

809
	if (end < start)
810 811 812 813
		return -EINVAL;

	if (end > IO_SPACE_LIMIT)
		return -EINVAL;
L
Linus Torvalds 已提交
814

815
	mutex_lock(&rsrc_mutex);
816
	switch (action) {
L
Linus Torvalds 已提交
817
	case ADD_MANAGED_RESOURCE:
818 819
		if (add_interval(&data->io_db, start, size) != 0) {
			ret = -EBUSY;
L
Linus Torvalds 已提交
820 821 822 823
			break;
		}
#ifdef CONFIG_PCMCIA_PROBE
		if (probe_io)
824
			do_io_probe(s, start, size);
L
Linus Torvalds 已提交
825 826 827
#endif
		break;
	case REMOVE_MANAGED_RESOURCE:
828
		sub_interval(&data->io_db, start, size);
L
Linus Torvalds 已提交
829 830
		break;
	default:
831
		ret = -EINVAL;
L
Linus Torvalds 已提交
832 833
		break;
	}
834
	mutex_unlock(&rsrc_mutex);
L
Linus Torvalds 已提交
835 836 837 838 839

	return ret;
}


840 841 842 843 844 845 846 847 848
#ifdef CONFIG_PCI
static int nonstatic_autoadd_resources(struct pcmcia_socket *s)
{
	struct resource *res;
	int i, done = 0;

	if (!s->cb_dev || !s->cb_dev->bus)
		return -ENODEV;

B
Brian Gerst 已提交
849
#if defined(CONFIG_X86)
850 851 852 853 854 855 856 857 858 859
	/* If this is the root bus, the risk of hitting
	 * some strange system devices which aren't protected
	 * by either ACPI resource tables or properly requested
	 * resources is too big. Therefore, don't do auto-adding
	 * of resources at the moment.
	 */
	if (s->cb_dev->bus->number == 0)
		return -EINVAL;
#endif

D
Dominik Brodowski 已提交
860
	for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) {
861 862 863 864 865 866 867
		res = s->cb_dev->bus->resource[i];
		if (!res)
			continue;

		if (res->flags & IORESOURCE_IO) {
			if (res == &ioport_resource)
				continue;
868 869 870 871 872
			dev_printk(KERN_INFO, &s->cb_dev->dev,
				   "pcmcia: parent PCI bridge I/O "
				   "window: 0x%llx - 0x%llx\n",
				   (unsigned long long)res->start,
				   (unsigned long long)res->end);
873 874 875 876 877 878 879 880
			if (!adjust_io(s, ADD_MANAGED_RESOURCE, res->start, res->end))
				done |= IORESOURCE_IO;

		}

		if (res->flags & IORESOURCE_MEM) {
			if (res == &iomem_resource)
				continue;
881 882 883 884 885
			dev_printk(KERN_INFO, &s->cb_dev->dev,
				   "pcmcia: parent PCI bridge Memory "
				   "window: 0x%llx - 0x%llx\n",
				   (unsigned long long)res->start,
				   (unsigned long long)res->end);
886 887 888 889 890 891 892
			if (!adjust_memory(s, ADD_MANAGED_RESOURCE, res->start, res->end))
				done |= IORESOURCE_MEM;
		}
	}

	/* if we got at least one of IO, and one of MEM, we can be glad and
	 * activate the PCMCIA subsystem */
893
	if (done == (IORESOURCE_MEM | IORESOURCE_IO))
894 895 896 897 898 899 900 901 902 903 904 905 906 907 908
		s->resource_setup_done = 1;

	return 0;
}

#else

static inline int nonstatic_autoadd_resources(struct pcmcia_socket *s)
{
	return -ENODEV;
}

#endif


L
Linus Torvalds 已提交
909 910 911 912
static int nonstatic_init(struct pcmcia_socket *s)
{
	struct socket_data *data;

913
	data = kzalloc(sizeof(struct socket_data), GFP_KERNEL);
L
Linus Torvalds 已提交
914 915 916 917 918 919 920 921
	if (!data)
		return -ENOMEM;

	data->mem_db.next = &data->mem_db;
	data->io_db.next = &data->io_db;

	s->resource_data = (void *) data;

922 923
	nonstatic_autoadd_resources(s);

L
Linus Torvalds 已提交
924 925 926 927 928 929 930 931
	return 0;
}

static void nonstatic_release_resource_db(struct pcmcia_socket *s)
{
	struct socket_data *data = s->resource_data;
	struct resource_map *p, *q;

932
	mutex_lock(&rsrc_mutex);
L
Linus Torvalds 已提交
933 934 935 936 937 938 939 940
	for (p = data->mem_db.next; p != &data->mem_db; p = q) {
		q = p->next;
		kfree(p);
	}
	for (p = data->io_db.next; p != &data->io_db; p = q) {
		q = p->next;
		kfree(p);
	}
941
	mutex_unlock(&rsrc_mutex);
L
Linus Torvalds 已提交
942 943 944 945 946 947 948 949
}


struct pccard_resource_ops pccard_nonstatic_ops = {
	.validate_mem = pcmcia_nonstatic_validate_mem,
	.adjust_io_region = nonstatic_adjust_io_region,
	.find_io = nonstatic_find_io_region,
	.find_mem = nonstatic_find_mem_region,
950 951
	.add_io = adjust_io,
	.add_mem = adjust_memory,
L
Linus Torvalds 已提交
952 953 954 955 956 957 958 959
	.init = nonstatic_init,
	.exit = nonstatic_release_resource_db,
};
EXPORT_SYMBOL(pccard_nonstatic_ops);


/* sysfs interface to the resource database */

960 961
static ssize_t show_io_db(struct device *dev,
			  struct device_attribute *attr, char *buf)
L
Linus Torvalds 已提交
962
{
963
	struct pcmcia_socket *s = dev_get_drvdata(dev);
L
Linus Torvalds 已提交
964 965 966 967
	struct socket_data *data;
	struct resource_map *p;
	ssize_t ret = 0;

968
	mutex_lock(&rsrc_mutex);
L
Linus Torvalds 已提交
969 970 971 972 973
	data = s->resource_data;

	for (p = data->io_db.next; p != &data->io_db; p = p->next) {
		if (ret > (PAGE_SIZE - 10))
			continue;
D
Dominik Brodowski 已提交
974 975 976 977
		ret += snprintf(&buf[ret], (PAGE_SIZE - ret - 1),
				"0x%08lx - 0x%08lx\n",
				((unsigned long) p->base),
				((unsigned long) p->base + p->num - 1));
L
Linus Torvalds 已提交
978 979
	}

980
	mutex_unlock(&rsrc_mutex);
D
Dominik Brodowski 已提交
981
	return ret;
L
Linus Torvalds 已提交
982 983
}

984 985 986
static ssize_t store_io_db(struct device *dev,
			   struct device_attribute *attr,
			   const char *buf, size_t count)
L
Linus Torvalds 已提交
987
{
988
	struct pcmcia_socket *s = dev_get_drvdata(dev);
L
Linus Torvalds 已提交
989
	unsigned long start_addr, end_addr;
990
	unsigned int add = ADD_MANAGED_RESOURCE;
L
Linus Torvalds 已提交
991 992
	ssize_t ret = 0;

D
Dominik Brodowski 已提交
993
	ret = sscanf(buf, "+ 0x%lx - 0x%lx", &start_addr, &end_addr);
L
Linus Torvalds 已提交
994
	if (ret != 2) {
D
Dominik Brodowski 已提交
995
		ret = sscanf(buf, "- 0x%lx - 0x%lx", &start_addr, &end_addr);
996
		add = REMOVE_MANAGED_RESOURCE;
L
Linus Torvalds 已提交
997
		if (ret != 2) {
D
Dominik Brodowski 已提交
998 999
			ret = sscanf(buf, "0x%lx - 0x%lx", &start_addr,
				&end_addr);
1000
			add = ADD_MANAGED_RESOURCE;
L
Linus Torvalds 已提交
1001 1002 1003 1004
			if (ret != 2)
				return -EINVAL;
		}
	}
1005
	if (end_addr < start_addr)
L
Linus Torvalds 已提交
1006 1007
		return -EINVAL;

1008
	ret = adjust_io(s, add, start_addr, end_addr);
1009 1010
	if (!ret)
		s->resource_setup_new = 1;
L
Linus Torvalds 已提交
1011 1012 1013

	return ret ? ret : count;
}
1014
static DEVICE_ATTR(available_resources_io, 0600, show_io_db, store_io_db);
L
Linus Torvalds 已提交
1015

1016 1017
static ssize_t show_mem_db(struct device *dev,
			   struct device_attribute *attr, char *buf)
L
Linus Torvalds 已提交
1018
{
1019
	struct pcmcia_socket *s = dev_get_drvdata(dev);
L
Linus Torvalds 已提交
1020 1021 1022 1023
	struct socket_data *data;
	struct resource_map *p;
	ssize_t ret = 0;

1024
	mutex_lock(&rsrc_mutex);
L
Linus Torvalds 已提交
1025 1026 1027 1028 1029
	data = s->resource_data;

	for (p = data->mem_db.next; p != &data->mem_db; p = p->next) {
		if (ret > (PAGE_SIZE - 10))
			continue;
D
Dominik Brodowski 已提交
1030 1031 1032 1033
		ret += snprintf(&buf[ret], (PAGE_SIZE - ret - 1),
				"0x%08lx - 0x%08lx\n",
				((unsigned long) p->base),
				((unsigned long) p->base + p->num - 1));
L
Linus Torvalds 已提交
1034 1035
	}

1036
	mutex_unlock(&rsrc_mutex);
D
Dominik Brodowski 已提交
1037
	return ret;
L
Linus Torvalds 已提交
1038 1039
}

1040 1041 1042
static ssize_t store_mem_db(struct device *dev,
			    struct device_attribute *attr,
			    const char *buf, size_t count)
L
Linus Torvalds 已提交
1043
{
1044
	struct pcmcia_socket *s = dev_get_drvdata(dev);
L
Linus Torvalds 已提交
1045
	unsigned long start_addr, end_addr;
1046
	unsigned int add = ADD_MANAGED_RESOURCE;
L
Linus Torvalds 已提交
1047 1048
	ssize_t ret = 0;

D
Dominik Brodowski 已提交
1049
	ret = sscanf(buf, "+ 0x%lx - 0x%lx", &start_addr, &end_addr);
L
Linus Torvalds 已提交
1050
	if (ret != 2) {
D
Dominik Brodowski 已提交
1051
		ret = sscanf(buf, "- 0x%lx - 0x%lx", &start_addr, &end_addr);
1052
		add = REMOVE_MANAGED_RESOURCE;
L
Linus Torvalds 已提交
1053
		if (ret != 2) {
D
Dominik Brodowski 已提交
1054 1055
			ret = sscanf(buf, "0x%lx - 0x%lx", &start_addr,
				&end_addr);
1056
			add = ADD_MANAGED_RESOURCE;
L
Linus Torvalds 已提交
1057 1058 1059 1060
			if (ret != 2)
				return -EINVAL;
		}
	}
1061
	if (end_addr < start_addr)
L
Linus Torvalds 已提交
1062 1063
		return -EINVAL;

1064
	ret = adjust_memory(s, add, start_addr, end_addr);
1065 1066
	if (!ret)
		s->resource_setup_new = 1;
L
Linus Torvalds 已提交
1067 1068 1069

	return ret ? ret : count;
}
1070
static DEVICE_ATTR(available_resources_mem, 0600, show_mem_db, store_mem_db);
L
Linus Torvalds 已提交
1071

1072 1073 1074
static struct attribute *pccard_rsrc_attributes[] = {
	&dev_attr_available_resources_io.attr,
	&dev_attr_available_resources_mem.attr,
L
Linus Torvalds 已提交
1075 1076 1077
	NULL,
};

1078 1079 1080 1081
static const struct attribute_group rsrc_attributes = {
	.attrs = pccard_rsrc_attributes,
};

1082
static int __devinit pccard_sysfs_add_rsrc(struct device *dev,
1083
					   struct class_interface *class_intf)
L
Linus Torvalds 已提交
1084
{
1085
	struct pcmcia_socket *s = dev_get_drvdata(dev);
1086

L
Linus Torvalds 已提交
1087 1088
	if (s->resource_ops != &pccard_nonstatic_ops)
		return 0;
1089
	return sysfs_create_group(&dev->kobj, &rsrc_attributes);
L
Linus Torvalds 已提交
1090 1091
}

1092
static void __devexit pccard_sysfs_remove_rsrc(struct device *dev,
1093
					       struct class_interface *class_intf)
L
Linus Torvalds 已提交
1094
{
1095
	struct pcmcia_socket *s = dev_get_drvdata(dev);
L
Linus Torvalds 已提交
1096 1097 1098

	if (s->resource_ops != &pccard_nonstatic_ops)
		return;
1099
	sysfs_remove_group(&dev->kobj, &rsrc_attributes);
L
Linus Torvalds 已提交
1100 1101
}

1102
static struct class_interface pccard_rsrc_interface __refdata = {
L
Linus Torvalds 已提交
1103
	.class = &pcmcia_socket_class,
1104 1105
	.add_dev = &pccard_sysfs_add_rsrc,
	.remove_dev = __devexit_p(&pccard_sysfs_remove_rsrc),
L
Linus Torvalds 已提交
1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119
};

static int __init nonstatic_sysfs_init(void)
{
	return class_interface_register(&pccard_rsrc_interface);
}

static void __exit nonstatic_sysfs_exit(void)
{
	class_interface_unregister(&pccard_rsrc_interface);
}

module_init(nonstatic_sysfs_init);
module_exit(nonstatic_sysfs_exit);