blob: 9da9656242af8b327d2859169df0acae2a56fd17 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * rsrc_nonstatic.c -- Resource management routines for !SS_CAP_STATIC_MAP sockets
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * The initial developer of the original code is David A. Hinds
9 * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
10 * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
11 *
12 * (C) 1999 David A. Hinds
13 */
14
Linus Torvalds1da177e2005-04-16 15:20:36 -070015#include <linux/module.h>
16#include <linux/moduleparam.h>
17#include <linux/init.h>
18#include <linux/interrupt.h>
19#include <linux/kernel.h>
20#include <linux/errno.h>
21#include <linux/types.h>
22#include <linux/slab.h>
23#include <linux/ioport.h>
24#include <linux/timer.h>
25#include <linux/pci.h>
26#include <linux/device.h>
Dominik Brodowski9fea84f2009-12-07 22:11:45 +010027#include <linux/io.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070028
29#include <asm/irq.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070030
Linus Torvalds1da177e2005-04-16 15:20:36 -070031#include <pcmcia/ss.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include <pcmcia/cistpl.h>
33#include "cs_internal.h"
34
Dominik Brodowski49b11532010-03-07 16:41:57 +010035/* moved to rsrc_mgr.c
Linus Torvalds1da177e2005-04-16 15:20:36 -070036MODULE_AUTHOR("David A. Hinds, Dominik Brodowski");
37MODULE_LICENSE("GPL");
Dominik Brodowski49b11532010-03-07 16:41:57 +010038*/
Linus Torvalds1da177e2005-04-16 15:20:36 -070039
40/* Parameters that can be set with 'insmod' */
41
42#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0444)
43
44INT_MODULE_PARM(probe_mem, 1); /* memory probe? */
45#ifdef CONFIG_PCMCIA_PROBE
46INT_MODULE_PARM(probe_io, 1); /* IO port probe? */
47INT_MODULE_PARM(mem_limit, 0x10000);
48#endif
49
50/* for io_db and mem_db */
51struct resource_map {
52 u_long base, num;
53 struct resource_map *next;
54};
55
56struct socket_data {
57 struct resource_map mem_db;
Dominik Brodowski7b4884c2010-02-17 16:25:53 +010058 struct resource_map mem_db_valid;
Linus Torvalds1da177e2005-04-16 15:20:36 -070059 struct resource_map io_db;
Linus Torvalds1da177e2005-04-16 15:20:36 -070060};
61
Linus Torvalds1da177e2005-04-16 15:20:36 -070062#define MEM_PROBE_LOW (1 << 0)
63#define MEM_PROBE_HIGH (1 << 1)
64
Dominik Brodowski3dace8c2010-07-24 12:33:29 +020065/* Action field */
66#define REMOVE_MANAGED_RESOURCE 1
67#define ADD_MANAGED_RESOURCE 2
Linus Torvalds1da177e2005-04-16 15:20:36 -070068
69/*======================================================================
70
71 Linux resource management extensions
72
73======================================================================*/
74
75static struct resource *
Greg Kroah-Hartman2427ddd2006-06-12 17:07:52 -070076claim_region(struct pcmcia_socket *s, resource_size_t base,
77 resource_size_t size, int type, char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -070078{
79 struct resource *res, *parent;
80
81 parent = type & IORESOURCE_MEM ? &iomem_resource : &ioport_resource;
Dominik Brodowski49b11532010-03-07 16:41:57 +010082 res = pcmcia_make_resource(base, size, type | IORESOURCE_BUSY, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -070083
84 if (res) {
85#ifdef CONFIG_PCI
86 if (s && s->cb_dev)
87 parent = pci_find_parent_resource(s->cb_dev, res);
88#endif
89 if (!parent || request_resource(parent, res)) {
90 kfree(res);
91 res = NULL;
92 }
93 }
94 return res;
95}
96
97static void free_region(struct resource *res)
98{
99 if (res) {
100 release_resource(res);
101 kfree(res);
102 }
103}
104
105/*======================================================================
106
107 These manage the internal databases of available resources.
108
109======================================================================*/
110
111static int add_interval(struct resource_map *map, u_long base, u_long num)
112{
Dominik Brodowski11683862008-08-03 10:22:47 +0200113 struct resource_map *p, *q;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114
Dominik Brodowski11683862008-08-03 10:22:47 +0200115 for (p = map; ; p = p->next) {
Dominik Brodowskif309cb32010-02-17 14:35:33 +0100116 if ((p != map) && (p->base+p->num >= base)) {
117 p->num = max(num + base - p->base, p->num);
118 return 0;
119 }
Dominik Brodowski11683862008-08-03 10:22:47 +0200120 if ((p->next == map) || (p->next->base > base+num-1))
121 break;
122 }
123 q = kmalloc(sizeof(struct resource_map), GFP_KERNEL);
124 if (!q) {
125 printk(KERN_WARNING "out of memory to update resources\n");
126 return -ENOMEM;
127 }
128 q->base = base; q->num = num;
129 q->next = p->next; p->next = q;
130 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131}
132
133/*====================================================================*/
134
135static int sub_interval(struct resource_map *map, u_long base, u_long num)
136{
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100137 struct resource_map *p, *q;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100139 for (p = map; ; p = q) {
140 q = p->next;
141 if (q == map)
142 break;
143 if ((q->base+q->num > base) && (base+num > q->base)) {
144 if (q->base >= base) {
145 if (q->base+q->num <= base+num) {
146 /* Delete whole block */
147 p->next = q->next;
148 kfree(q);
149 /* don't advance the pointer yet */
150 q = p;
151 } else {
152 /* Cut off bit from the front */
153 q->num = q->base + q->num - base - num;
154 q->base = base + num;
155 }
156 } else if (q->base+q->num <= base+num) {
157 /* Cut off bit from the end */
158 q->num = base - q->base;
159 } else {
160 /* Split the block into two pieces */
161 p = kmalloc(sizeof(struct resource_map),
162 GFP_KERNEL);
163 if (!p) {
164 printk(KERN_WARNING "out of memory to update resources\n");
165 return -ENOMEM;
166 }
167 p->base = base+num;
168 p->num = q->base+q->num - p->base;
169 q->num = base - q->base;
170 p->next = q->next ; q->next = p;
171 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 }
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100174 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175}
176
177/*======================================================================
178
179 These routines examine a region of IO or memory addresses to
180 determine what ranges might be genuinely available.
181
182======================================================================*/
183
184#ifdef CONFIG_PCMCIA_PROBE
Olof Johansson906da802008-02-04 22:27:35 -0800185static void do_io_probe(struct pcmcia_socket *s, unsigned int base,
186 unsigned int num)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187{
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100188 struct resource *res;
189 struct socket_data *s_data = s->resource_data;
190 unsigned int i, j, bad;
191 int any;
192 u_char *b, hole, most;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100194 dev_printk(KERN_INFO, &s->dev, "cs: IO port probe %#x-%#x:",
195 base, base+num-1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100197 /* First, what does a floating port look like? */
198 b = kzalloc(256, GFP_KERNEL);
199 if (!b) {
200 printk("\n");
201 dev_printk(KERN_ERR, &s->dev,
202 "do_io_probe: unable to kmalloc 256 bytes");
203 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204 }
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100205 for (i = base, most = 0; i < base+num; i += 8) {
Dominik Brodowski509b0862010-04-08 19:23:07 +0200206 res = claim_region(s, i, 8, IORESOURCE_IO, "PCMCIA ioprobe");
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100207 if (!res)
208 continue;
209 hole = inb(i);
210 for (j = 1; j < 8; j++)
211 if (inb(i+j) != hole)
212 break;
213 free_region(res);
214 if ((j == 8) && (++b[hole] > b[most]))
215 most = hole;
216 if (b[most] == 127)
217 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218 }
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100219 kfree(b);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100221 bad = any = 0;
222 for (i = base; i < base+num; i += 8) {
Dominik Brodowski509b0862010-04-08 19:23:07 +0200223 res = claim_region(s, i, 8, IORESOURCE_IO, "PCMCIA ioprobe");
224 if (!res) {
225 if (!any)
226 printk(" excluding");
227 if (!bad)
228 bad = any = i;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100229 continue;
Dominik Brodowski509b0862010-04-08 19:23:07 +0200230 }
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100231 for (j = 0; j < 8; j++)
232 if (inb(i+j) != most)
233 break;
234 free_region(res);
235 if (j < 8) {
236 if (!any)
237 printk(" excluding");
238 if (!bad)
239 bad = any = i;
240 } else {
241 if (bad) {
242 sub_interval(&s_data->io_db, bad, i-bad);
243 printk(" %#x-%#x", bad, i-1);
244 bad = 0;
245 }
246 }
247 }
248 if (bad) {
249 if ((num > 16) && (bad == base) && (i == base+num)) {
Dominik Brodowski509b0862010-04-08 19:23:07 +0200250 sub_interval(&s_data->io_db, bad, i-bad);
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100251 printk(" nothing: probe failed.\n");
252 return;
253 } else {
254 sub_interval(&s_data->io_db, bad, i-bad);
255 printk(" %#x-%#x", bad, i-1);
256 }
257 }
258
259 printk(any ? "\n" : " clean.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260}
261#endif
262
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100263/*======================================================================*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100265/**
266 * readable() - iomem validation function for cards with a valid CIS
267 */
Dominik Brodowskic5081d52008-06-19 20:12:34 +0200268static int readable(struct pcmcia_socket *s, struct resource *res,
269 unsigned int *count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270{
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100271 int ret = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272
Dominik Brodowski7ab248552010-02-17 18:00:07 +0100273 if (s->fake_cis) {
274 dev_dbg(&s->dev, "fake CIS is being used: can't validate mem\n");
275 return 0;
276 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277
278 s->cis_mem.res = res;
279 s->cis_virt = ioremap(res->start, s->map_size);
280 if (s->cis_virt) {
Dominik Brodowski6b8e0872010-01-12 21:42:51 +0100281 mutex_unlock(&s->ops_mutex);
Dominik Brodowski6e7b51a2010-01-06 13:57:43 +0100282 /* as we're only called from pcmcia.c, we're safe */
283 if (s->callback->validate)
284 ret = s->callback->validate(s, count);
Dominik Brodowski904e3772010-01-02 12:28:04 +0100285 /* invalidate mapping */
Dominik Brodowski6b8e0872010-01-12 21:42:51 +0100286 mutex_lock(&s->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287 iounmap(s->cis_virt);
288 s->cis_virt = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 }
290 s->cis_mem.res = NULL;
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100291 if ((ret) || (*count == 0))
292 return -EINVAL;
293 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294}
295
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100296/**
297 * checksum() - iomem validation function for simple memory cards
298 */
299static int checksum(struct pcmcia_socket *s, struct resource *res,
300 unsigned int *value)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301{
302 pccard_mem_map map;
303 int i, a = 0, b = -1, d;
304 void __iomem *virt;
305
306 virt = ioremap(res->start, s->map_size);
307 if (virt) {
308 map.map = 0;
309 map.flags = MAP_ACTIVE;
310 map.speed = 0;
311 map.res = res;
312 map.card_start = 0;
313 s->ops->set_mem_map(s, &map);
314
315 /* Don't bother checking every word... */
316 for (i = 0; i < s->map_size; i += 44) {
317 d = readl(virt+i);
318 a += d;
319 b &= d;
320 }
321
322 map.flags = 0;
323 s->ops->set_mem_map(s, &map);
324
325 iounmap(virt);
326 }
327
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100328 if (b == -1)
329 return -EINVAL;
330
331 *value = a;
332
333 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334}
335
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100336/**
337 * do_validate_mem() - low level validate a memory region for PCMCIA use
338 * @s: PCMCIA socket to validate
339 * @base: start address of resource to check
340 * @size: size of resource to check
341 * @validate: validation function to use
342 *
343 * do_validate_mem() splits up the memory region which is to be checked
344 * into two parts. Both are passed to the @validate() function. If
345 * @validate() returns non-zero, or the value parameter to @validate()
346 * is zero, or the value parameter is different between both calls,
347 * the check fails, and -EINVAL is returned. Else, 0 is returned.
348 */
349static int do_validate_mem(struct pcmcia_socket *s,
350 unsigned long base, unsigned long size,
351 int validate (struct pcmcia_socket *s,
352 struct resource *res,
353 unsigned int *value))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354{
Dominik Brodowski7b4884c2010-02-17 16:25:53 +0100355 struct socket_data *s_data = s->resource_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 struct resource *res1, *res2;
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100357 unsigned int info1 = 1, info2 = 1;
358 int ret = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100360 res1 = claim_region(s, base, size/2, IORESOURCE_MEM, "PCMCIA memprobe");
361 res2 = claim_region(s, base + size/2, size/2, IORESOURCE_MEM,
362 "PCMCIA memprobe");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363
364 if (res1 && res2) {
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100365 ret = 0;
366 if (validate) {
367 ret = validate(s, res1, &info1);
368 ret += validate(s, res2, &info2);
369 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 }
371
372 free_region(res2);
373 free_region(res1);
374
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100375 dev_dbg(&s->dev, "cs: memory probe 0x%06lx-0x%06lx: %p %p %u %u %u",
376 base, base+size-1, res1, res2, ret, info1, info2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100378 if ((ret) || (info1 != info2) || (info1 == 0))
379 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380
Dominik Brodowski7b4884c2010-02-17 16:25:53 +0100381 if (validate && !s->fake_cis) {
382 /* move it to the validated data set */
383 add_interval(&s_data->mem_db_valid, base, size);
384 sub_interval(&s_data->mem_db, base, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 }
386
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100387 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388}
389
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100391/**
392 * do_mem_probe() - validate a memory region for PCMCIA use
393 * @s: PCMCIA socket to validate
394 * @base: start address of resource to check
395 * @num: size of resource to check
396 * @validate: validation function to use
397 * @fallback: validation function to use if validate fails
398 *
399 * do_mem_probe() checks a memory region for use by the PCMCIA subsystem.
400 * To do so, the area is split up into sensible parts, and then passed
401 * into the @validate() function. Only if @validate() and @fallback() fail,
402 * the area is marked as unavaibale for use by the PCMCIA subsystem. The
403 * function returns the size of the usable memory area.
404 */
405static int do_mem_probe(struct pcmcia_socket *s, u_long base, u_long num,
406 int validate (struct pcmcia_socket *s,
407 struct resource *res,
408 unsigned int *value),
409 int fallback (struct pcmcia_socket *s,
410 struct resource *res,
411 unsigned int *value))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412{
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100413 struct socket_data *s_data = s->resource_data;
414 u_long i, j, bad, fail, step;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100416 dev_printk(KERN_INFO, &s->dev, "cs: memory probe 0x%06lx-0x%06lx:",
417 base, base+num-1);
418 bad = fail = 0;
419 step = (num < 0x20000) ? 0x2000 : ((num>>4) & ~0x1fff);
420 /* don't allow too large steps */
421 if (step > 0x800000)
422 step = 0x800000;
423 /* cis_readable wants to map 2x map_size */
424 if (step < 2 * s->map_size)
425 step = 2 * s->map_size;
426 for (i = j = base; i < base+num; i = j + step) {
427 if (!fail) {
428 for (j = i; j < base+num; j += step) {
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100429 if (!do_validate_mem(s, j, step, validate))
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100430 break;
431 }
432 fail = ((i == base) && (j == base+num));
433 }
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100434 if ((fail) && (fallback)) {
435 for (j = i; j < base+num; j += step)
436 if (!do_validate_mem(s, j, step, fallback))
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100437 break;
438 }
439 if (i != j) {
440 if (!bad)
441 printk(" excluding");
442 printk(" %#05lx-%#05lx", i, j-1);
443 sub_interval(&s_data->mem_db, i, j-i);
444 bad += j-i;
445 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446 }
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100447 printk(bad ? "\n" : " clean.\n");
448 return num - bad;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449}
450
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100451
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452#ifdef CONFIG_PCMCIA_PROBE
453
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100454/**
455 * inv_probe() - top-to-bottom search for one usuable high memory area
456 * @s: PCMCIA socket to validate
457 * @m: resource_map to check
458 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459static u_long inv_probe(struct resource_map *m, struct pcmcia_socket *s)
460{
Dominik Brodowskide759142005-09-28 19:41:56 +0200461 struct socket_data *s_data = s->resource_data;
462 u_long ok;
463 if (m == &s_data->mem_db)
464 return 0;
465 ok = inv_probe(m->next, s);
466 if (ok) {
467 if (m->base >= 0x100000)
468 sub_interval(&s_data->mem_db, m->base, m->num);
469 return ok;
470 }
471 if (m->base < 0x100000)
472 return 0;
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100473 return do_mem_probe(s, m->base, m->num, readable, checksum);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474}
475
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100476/**
477 * validate_mem() - memory probe function
478 * @s: PCMCIA socket to validate
479 * @probe_mask: MEM_PROBE_LOW | MEM_PROBE_HIGH
480 *
481 * The memory probe. If the memory list includes a 64K-aligned block
482 * below 1MB, we probe in 64K chunks, and as soon as we accumulate at
483 * least mem_limit free space, we quit. Returns 0 on usuable ports.
484 */
Dominik Brodowskide759142005-09-28 19:41:56 +0200485static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486{
Dominik Brodowskide759142005-09-28 19:41:56 +0200487 struct resource_map *m, mm;
488 static unsigned char order[] = { 0xd0, 0xe0, 0xc0, 0xf0 };
489 unsigned long b, i, ok = 0;
490 struct socket_data *s_data = s->resource_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491
Dominik Brodowskide759142005-09-28 19:41:56 +0200492 /* We do up to four passes through the list */
493 if (probe_mask & MEM_PROBE_HIGH) {
494 if (inv_probe(s_data->mem_db.next, s) > 0)
495 return 0;
Dominik Brodowski7b4884c2010-02-17 16:25:53 +0100496 if (s_data->mem_db_valid.next != &s_data->mem_db_valid)
497 return 0;
Dominik Brodowskidbe4ea52008-08-02 21:36:19 +0200498 dev_printk(KERN_NOTICE, &s->dev,
499 "cs: warning: no high memory space available!\n");
Dominik Brodowskide759142005-09-28 19:41:56 +0200500 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 }
Dominik Brodowskide759142005-09-28 19:41:56 +0200502
503 for (m = s_data->mem_db.next; m != &s_data->mem_db; m = mm.next) {
504 mm = *m;
505 /* Only probe < 1 MB */
506 if (mm.base >= 0x100000)
507 continue;
508 if ((mm.base | mm.num) & 0xffff) {
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100509 ok += do_mem_probe(s, mm.base, mm.num, readable,
510 checksum);
Dominik Brodowskide759142005-09-28 19:41:56 +0200511 continue;
512 }
513 /* Special probe for 64K-aligned block */
514 for (i = 0; i < 4; i++) {
515 b = order[i] << 12;
516 if ((b >= mm.base) && (b+0x10000 <= mm.base+mm.num)) {
517 if (ok >= mem_limit)
518 sub_interval(&s_data->mem_db, b, 0x10000);
519 else
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100520 ok += do_mem_probe(s, b, 0x10000,
521 readable, checksum);
Dominik Brodowskide759142005-09-28 19:41:56 +0200522 }
523 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 }
Dominik Brodowskide759142005-09-28 19:41:56 +0200525
526 if (ok > 0)
527 return 0;
528
529 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530}
531
532#else /* CONFIG_PCMCIA_PROBE */
533
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100534/**
535 * validate_mem() - memory probe function
536 * @s: PCMCIA socket to validate
537 * @probe_mask: ignored
538 *
539 * Returns 0 on usuable ports.
540 */
Andrew Morton2cff9442005-11-16 21:29:26 -0800541static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542{
543 struct resource_map *m, mm;
544 struct socket_data *s_data = s->resource_data;
Andrew Morton2cff9442005-11-16 21:29:26 -0800545 unsigned long ok = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546
547 for (m = s_data->mem_db.next; m != &s_data->mem_db; m = mm.next) {
548 mm = *m;
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100549 ok += do_mem_probe(s, mm.base, mm.num, readable, checksum);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 }
Andrew Morton2cff9442005-11-16 21:29:26 -0800551 if (ok > 0)
552 return 0;
553 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554}
555
556#endif /* CONFIG_PCMCIA_PROBE */
557
558
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100559/**
560 * pcmcia_nonstatic_validate_mem() - try to validate iomem for PCMCIA use
561 * @s: PCMCIA socket to validate
562 *
563 * This is tricky... when we set up CIS memory, we try to validate
564 * the memory window space allocations.
565 *
Dominik Brodowski7fe908d2006-01-10 21:20:36 +0100566 * Locking note: Must be called with skt_mutex held!
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567 */
Dominik Brodowskide759142005-09-28 19:41:56 +0200568static int pcmcia_nonstatic_validate_mem(struct pcmcia_socket *s)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569{
570 struct socket_data *s_data = s->resource_data;
Dominik Brodowskide759142005-09-28 19:41:56 +0200571 unsigned int probe_mask = MEM_PROBE_LOW;
Dominik Brodowski7b4884c2010-02-17 16:25:53 +0100572 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573
Dominik Brodowski7b4884c2010-02-17 16:25:53 +0100574 if (!probe_mem || !(s->state & SOCKET_PRESENT))
Dominik Brodowskide759142005-09-28 19:41:56 +0200575 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576
Dominik Brodowskide759142005-09-28 19:41:56 +0200577 if (s->features & SS_CAP_PAGE_REGS)
578 probe_mask = MEM_PROBE_HIGH;
579
Dominik Brodowski7b4884c2010-02-17 16:25:53 +0100580 ret = validate_mem(s, probe_mask);
Dominik Brodowskide759142005-09-28 19:41:56 +0200581
Dominik Brodowski7b4884c2010-02-17 16:25:53 +0100582 if (s_data->mem_db_valid.next != &s_data->mem_db_valid)
583 return 0;
Dominik Brodowskide759142005-09-28 19:41:56 +0200584
585 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586}
587
588struct pcmcia_align_data {
589 unsigned long mask;
590 unsigned long offset;
591 struct resource_map *map;
592};
593
Dominik Brodowski147a2742010-04-04 18:10:35 +0200594static resource_size_t pcmcia_common_align(struct pcmcia_align_data *align_data,
595 resource_size_t start)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596{
Dominik Brodowski147a2742010-04-04 18:10:35 +0200597 resource_size_t ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 /*
599 * Ensure that we have the correct start address
600 */
Dominik Brodowski147a2742010-04-04 18:10:35 +0200601 ret = (start & ~align_data->mask) + align_data->offset;
602 if (ret < start)
603 ret += align_data->mask + 1;
604 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605}
606
Dominik Brodowskib26b2d42010-01-01 17:40:49 +0100607static resource_size_t
Dominik Brodowski3b7a17f2010-01-01 17:40:50 +0100608pcmcia_align(void *align_data, const struct resource *res,
609 resource_size_t size, resource_size_t align)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610{
611 struct pcmcia_align_data *data = align_data;
612 struct resource_map *m;
Dominik Brodowskib26b2d42010-01-01 17:40:49 +0100613 resource_size_t start;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614
Dominik Brodowski147a2742010-04-04 18:10:35 +0200615 start = pcmcia_common_align(data, res->start);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616
617 for (m = data->map->next; m != data->map; m = m->next) {
Dominik Brodowski147a2742010-04-04 18:10:35 +0200618 unsigned long map_start = m->base;
619 unsigned long map_end = m->base + m->num - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620
621 /*
622 * If the lower resources are not available, try aligning
623 * to this entry of the resource database to see if it'll
624 * fit here.
625 */
Dominik Brodowski147a2742010-04-04 18:10:35 +0200626 if (start < map_start)
627 start = pcmcia_common_align(data, map_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628
629 /*
630 * If we're above the area which was passed in, there's
631 * no point proceeding.
632 */
Dominik Brodowski147a2742010-04-04 18:10:35 +0200633 if (start >= res->end)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 break;
635
Dominik Brodowski147a2742010-04-04 18:10:35 +0200636 if ((start + size - 1) <= map_end)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 break;
638 }
639
640 /*
641 * If we failed to find something suitable, ensure we fail.
642 */
643 if (m == data->map)
Dominik Brodowskib26b2d42010-01-01 17:40:49 +0100644 start = res->end;
645
646 return start;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647}
648
649/*
650 * Adjust an existing IO region allocation, but making sure that we don't
651 * encroach outside the resources which the user supplied.
652 */
Dominik Brodowskib19a7272010-03-20 13:10:47 +0100653static int __nonstatic_adjust_io_region(struct pcmcia_socket *s,
654 unsigned long r_start,
655 unsigned long r_end)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656{
657 struct resource_map *m;
658 struct socket_data *s_data = s->resource_data;
659 int ret = -ENOMEM;
660
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 for (m = s_data->io_db.next; m != &s_data->io_db; m = m->next) {
662 unsigned long start = m->base;
663 unsigned long end = m->base + m->num - 1;
664
665 if (start > r_start || r_end > end)
666 continue;
667
Dominik Brodowskib19a7272010-03-20 13:10:47 +0100668 ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670
671 return ret;
672}
673
674/*======================================================================
675
676 These find ranges of I/O ports or memory addresses that are not
677 currently allocated by other devices.
678
679 The 'align' field should reflect the number of bits of address
680 that need to be preserved from the initial value of *base. It
681 should be a power of two, greater than or equal to 'num'. A value
682 of 0 means that all bits of *base are significant. *base should
683 also be strictly less than 'align'.
684
685======================================================================*/
686
Dominik Brodowskib19a7272010-03-20 13:10:47 +0100687static struct resource *__nonstatic_find_io_region(struct pcmcia_socket *s,
688 unsigned long base, int num,
689 unsigned long align)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690{
Dominik Brodowski49b11532010-03-07 16:41:57 +0100691 struct resource *res = pcmcia_make_resource(0, num, IORESOURCE_IO,
692 dev_name(&s->dev));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 struct socket_data *s_data = s->resource_data;
694 struct pcmcia_align_data data;
695 unsigned long min = base;
696 int ret;
697
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 data.mask = align - 1;
699 data.offset = base & data.mask;
700 data.map = &s_data->io_db;
701
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702#ifdef CONFIG_PCI
703 if (s->cb_dev) {
704 ret = pci_bus_alloc_resource(s->cb_dev->bus, res, num, 1,
705 min, 0, pcmcia_align, &data);
706 } else
707#endif
708 ret = allocate_resource(&ioport_resource, res, num, min, ~0UL,
709 1, pcmcia_align, &data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710
711 if (ret != 0) {
712 kfree(res);
713 res = NULL;
714 }
715 return res;
716}
717
Dominik Brodowskib19a7272010-03-20 13:10:47 +0100718static int nonstatic_find_io(struct pcmcia_socket *s, unsigned int attr,
719 unsigned int *base, unsigned int num,
Dominik Brodowskiad0c7be2010-07-25 13:10:22 +0200720 unsigned int align, struct resource **parent)
Dominik Brodowskib19a7272010-03-20 13:10:47 +0100721{
722 int i, ret = 0;
723
724 /* Check for an already-allocated window that must conflict with
725 * what was asked for. It is a hack because it does not catch all
726 * potential conflicts, just the most obvious ones.
727 */
728 for (i = 0; i < MAX_IO_WIN; i++) {
729 if (!s->io[i].res)
730 continue;
731
732 if (!*base)
733 continue;
734
735 if ((s->io[i].res->start & (align-1)) == *base)
736 return -EBUSY;
737 }
738
739 for (i = 0; i < MAX_IO_WIN; i++) {
740 struct resource *res = s->io[i].res;
741 unsigned int try;
742
743 if (res && (res->flags & IORESOURCE_BITS) !=
744 (attr & IORESOURCE_BITS))
745 continue;
746
747 if (!res) {
748 if (align == 0)
749 align = 0x10000;
750
751 res = s->io[i].res = __nonstatic_find_io_region(s,
752 *base, num,
753 align);
754 if (!res)
755 return -EINVAL;
756
757 *base = res->start;
758 s->io[i].res->flags =
759 ((res->flags & ~IORESOURCE_BITS) |
760 (attr & IORESOURCE_BITS));
761 s->io[i].InUse = num;
Dominik Brodowskiad0c7be2010-07-25 13:10:22 +0200762 *parent = res;
Dominik Brodowskib19a7272010-03-20 13:10:47 +0100763 return 0;
764 }
765
766 /* Try to extend top of window */
767 try = res->end + 1;
768 if ((*base == 0) || (*base == try)) {
769 ret = __nonstatic_adjust_io_region(s, res->start,
770 res->end + num);
771 if (!ret) {
772 ret = adjust_resource(s->io[i].res, res->start,
Joe Perches28f65c12011-06-09 09:13:32 -0700773 resource_size(res) + num);
Dominik Brodowskib19a7272010-03-20 13:10:47 +0100774 if (ret)
775 continue;
776 *base = try;
777 s->io[i].InUse += num;
Dominik Brodowskiad0c7be2010-07-25 13:10:22 +0200778 *parent = res;
Dominik Brodowskib19a7272010-03-20 13:10:47 +0100779 return 0;
780 }
781 }
782
783 /* Try to extend bottom of window */
784 try = res->start - num;
785 if ((*base == 0) || (*base == try)) {
786 ret = __nonstatic_adjust_io_region(s,
787 res->start - num,
788 res->end);
789 if (!ret) {
790 ret = adjust_resource(s->io[i].res,
Joe Perches28f65c12011-06-09 09:13:32 -0700791 res->start - num,
792 resource_size(res) + num);
Dominik Brodowskib19a7272010-03-20 13:10:47 +0100793 if (ret)
794 continue;
795 *base = try;
796 s->io[i].InUse += num;
Dominik Brodowskiad0c7be2010-07-25 13:10:22 +0200797 *parent = res;
Dominik Brodowskib19a7272010-03-20 13:10:47 +0100798 return 0;
799 }
800 }
801 }
802
803 return -EINVAL;
804}
805
806
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100807static struct resource *nonstatic_find_mem_region(u_long base, u_long num,
Dominik Brodowskie94e15f2005-06-27 16:28:15 -0700808 u_long align, int low, struct pcmcia_socket *s)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809{
Dominik Brodowski49b11532010-03-07 16:41:57 +0100810 struct resource *res = pcmcia_make_resource(0, num, IORESOURCE_MEM,
811 dev_name(&s->dev));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 struct socket_data *s_data = s->resource_data;
813 struct pcmcia_align_data data;
814 unsigned long min, max;
Dominik Brodowski7b4884c2010-02-17 16:25:53 +0100815 int ret, i, j;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816
817 low = low || !(s->features & SS_CAP_PAGE_REGS);
818
819 data.mask = align - 1;
820 data.offset = base & data.mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821
822 for (i = 0; i < 2; i++) {
Dominik Brodowski7b4884c2010-02-17 16:25:53 +0100823 data.map = &s_data->mem_db_valid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 if (low) {
825 max = 0x100000UL;
826 min = base < max ? base : 0;
827 } else {
828 max = ~0UL;
829 min = 0x100000UL + base;
830 }
831
Dominik Brodowski7b4884c2010-02-17 16:25:53 +0100832 for (j = 0; j < 2; j++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833#ifdef CONFIG_PCI
Dominik Brodowski7b4884c2010-02-17 16:25:53 +0100834 if (s->cb_dev) {
835 ret = pci_bus_alloc_resource(s->cb_dev->bus,
836 res, num, 1, min, 0,
837 pcmcia_align, &data);
838 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839#endif
Dominik Brodowski7b4884c2010-02-17 16:25:53 +0100840 {
841 ret = allocate_resource(&iomem_resource,
842 res, num, min, max, 1,
843 pcmcia_align, &data);
844 }
845 if (ret == 0)
846 break;
847 data.map = &s_data->mem_db;
848 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849 if (ret == 0 || low)
850 break;
851 low = 1;
852 }
853
854 if (ret != 0) {
855 kfree(res);
856 res = NULL;
857 }
858 return res;
859}
860
861
Dominik Brodowski22916632005-06-27 16:28:46 -0700862static int adjust_memory(struct pcmcia_socket *s, unsigned int action, unsigned long start, unsigned long end)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 struct socket_data *data = s->resource_data;
Dominik Brodowski22916632005-06-27 16:28:46 -0700865 unsigned long size = end - start + 1;
866 int ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867
Dominik Brodowski1146bc72005-09-28 19:28:37 +0200868 if (end < start)
Dominik Brodowski22916632005-06-27 16:28:46 -0700869 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870
Dominik Brodowski22916632005-06-27 16:28:46 -0700871 switch (action) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872 case ADD_MANAGED_RESOURCE:
Dominik Brodowski22916632005-06-27 16:28:46 -0700873 ret = add_interval(&data->mem_db, start, size);
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100874 if (!ret)
875 do_mem_probe(s, start, size, NULL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876 break;
877 case REMOVE_MANAGED_RESOURCE:
Dominik Brodowski22916632005-06-27 16:28:46 -0700878 ret = sub_interval(&data->mem_db, start, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 break;
880 default:
Dominik Brodowski22916632005-06-27 16:28:46 -0700881 ret = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883
884 return ret;
885}
886
887
Dominik Brodowski22916632005-06-27 16:28:46 -0700888static int adjust_io(struct pcmcia_socket *s, unsigned int action, unsigned long start, unsigned long end)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889{
890 struct socket_data *data = s->resource_data;
Dominik Brodowski41b97ab2010-04-15 19:01:53 +0200891 unsigned long size;
Dominik Brodowski22916632005-06-27 16:28:46 -0700892 int ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893
Dominik Brodowski9713ab22010-03-23 16:05:00 +0100894#if defined(CONFIG_X86)
895 /* on x86, avoid anything < 0x100 for it is often used for
896 * legacy platform devices */
897 if (start < 0x100)
898 start = 0x100;
899#endif
900
Dominik Brodowski41b97ab2010-04-15 19:01:53 +0200901 size = end - start + 1;
902
Dominik Brodowski1146bc72005-09-28 19:28:37 +0200903 if (end < start)
Dominik Brodowski22916632005-06-27 16:28:46 -0700904 return -EINVAL;
905
906 if (end > IO_SPACE_LIMIT)
907 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908
Dominik Brodowski22916632005-06-27 16:28:46 -0700909 switch (action) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 case ADD_MANAGED_RESOURCE:
Dominik Brodowski22916632005-06-27 16:28:46 -0700911 if (add_interval(&data->io_db, start, size) != 0) {
912 ret = -EBUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913 break;
914 }
915#ifdef CONFIG_PCMCIA_PROBE
916 if (probe_io)
Dominik Brodowski22916632005-06-27 16:28:46 -0700917 do_io_probe(s, start, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918#endif
919 break;
920 case REMOVE_MANAGED_RESOURCE:
Dominik Brodowski22916632005-06-27 16:28:46 -0700921 sub_interval(&data->io_db, start, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 break;
923 default:
Dominik Brodowski22916632005-06-27 16:28:46 -0700924 ret = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 break;
926 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927
928 return ret;
929}
930
931
Dominik Brodowski3c299762005-06-27 16:28:46 -0700932#ifdef CONFIG_PCI
933static int nonstatic_autoadd_resources(struct pcmcia_socket *s)
934{
935 struct resource *res;
936 int i, done = 0;
937
938 if (!s->cb_dev || !s->cb_dev->bus)
939 return -ENODEV;
940
Brian Gerst0d078f62005-10-30 14:59:20 -0800941#if defined(CONFIG_X86)
Dominik Brodowskicf26e8d2010-03-29 21:40:35 +0200942 /* If this is the root bus, the risk of hitting some strange
943 * system devices is too high: If a driver isn't loaded, the
944 * resources are not claimed; even if a driver is loaded, it
945 * may not request all resources or even the wrong one. We
946 * can neither trust the rest of the kernel nor ACPI/PNP and
947 * CRS parsing to get it right. Therefore, use several
948 * safeguards:
949 *
950 * - Do not auto-add resources if the CardBus bridge is on
951 * the PCI root bus
952 *
953 * - Avoid any I/O ports < 0x100.
954 *
955 * - On PCI-PCI bridges, only use resources which are set up
956 * exclusively for the secondary PCI bus: the risk of hitting
957 * system devices is quite low, as they usually aren't
958 * connected to the secondary PCI bus.
Dominik Brodowskib6d00f02005-06-27 16:29:02 -0700959 */
960 if (s->cb_dev->bus->number == 0)
961 return -EINVAL;
Dominik Brodowskib6d00f02005-06-27 16:29:02 -0700962
Dominik Brodowskicf26e8d2010-03-29 21:40:35 +0200963 for (i = 0; i < PCI_BRIDGE_RESOURCE_NUM; i++) {
964 res = s->cb_dev->bus->resource[i];
965#else
Bjorn Helgaas89a74ec2010-02-23 10:24:31 -0700966 pci_bus_for_each_resource(s->cb_dev->bus, res, i) {
Dominik Brodowskicf26e8d2010-03-29 21:40:35 +0200967#endif
Dominik Brodowski3c299762005-06-27 16:28:46 -0700968 if (!res)
969 continue;
970
971 if (res->flags & IORESOURCE_IO) {
Dominik Brodowskicf26e8d2010-03-29 21:40:35 +0200972 /* safeguard against the root resource, where the
973 * risk of hitting any other device would be too
974 * high */
Dominik Brodowski3c299762005-06-27 16:28:46 -0700975 if (res == &ioport_resource)
976 continue;
Dominik Brodowskicf26e8d2010-03-29 21:40:35 +0200977
Dominik Brodowskidbe4ea52008-08-02 21:36:19 +0200978 dev_printk(KERN_INFO, &s->cb_dev->dev,
Bjorn Helgaase1944c62010-03-16 15:53:08 -0600979 "pcmcia: parent PCI bridge window: %pR\n",
980 res);
Dominik Brodowski3c299762005-06-27 16:28:46 -0700981 if (!adjust_io(s, ADD_MANAGED_RESOURCE, res->start, res->end))
982 done |= IORESOURCE_IO;
983
984 }
985
986 if (res->flags & IORESOURCE_MEM) {
Dominik Brodowskicf26e8d2010-03-29 21:40:35 +0200987 /* safeguard against the root resource, where the
988 * risk of hitting any other device would be too
989 * high */
Dominik Brodowski3c299762005-06-27 16:28:46 -0700990 if (res == &iomem_resource)
991 continue;
Dominik Brodowskicf26e8d2010-03-29 21:40:35 +0200992
Dominik Brodowskidbe4ea52008-08-02 21:36:19 +0200993 dev_printk(KERN_INFO, &s->cb_dev->dev,
Bjorn Helgaase1944c62010-03-16 15:53:08 -0600994 "pcmcia: parent PCI bridge window: %pR\n",
995 res);
Dominik Brodowski3c299762005-06-27 16:28:46 -0700996 if (!adjust_memory(s, ADD_MANAGED_RESOURCE, res->start, res->end))
997 done |= IORESOURCE_MEM;
998 }
999 }
1000
1001 /* if we got at least one of IO, and one of MEM, we can be glad and
1002 * activate the PCMCIA subsystem */
Dominik Brodowski54bb5672005-09-28 19:29:59 +02001003 if (done == (IORESOURCE_MEM | IORESOURCE_IO))
Dominik Brodowski3c299762005-06-27 16:28:46 -07001004 s->resource_setup_done = 1;
1005
1006 return 0;
1007}
1008
1009#else
1010
1011static inline int nonstatic_autoadd_resources(struct pcmcia_socket *s)
1012{
1013 return -ENODEV;
1014}
1015
1016#endif
1017
1018
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019static int nonstatic_init(struct pcmcia_socket *s)
1020{
1021 struct socket_data *data;
1022
Dominik Brodowski8084b372005-12-11 21:18:26 +01001023 data = kzalloc(sizeof(struct socket_data), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024 if (!data)
1025 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026
1027 data->mem_db.next = &data->mem_db;
Dominik Brodowski7b4884c2010-02-17 16:25:53 +01001028 data->mem_db_valid.next = &data->mem_db_valid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029 data->io_db.next = &data->io_db;
1030
1031 s->resource_data = (void *) data;
1032
Dominik Brodowski3c299762005-06-27 16:28:46 -07001033 nonstatic_autoadd_resources(s);
1034
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035 return 0;
1036}
1037
1038static void nonstatic_release_resource_db(struct pcmcia_socket *s)
1039{
1040 struct socket_data *data = s->resource_data;
1041 struct resource_map *p, *q;
1042
Dominik Brodowski7b4884c2010-02-17 16:25:53 +01001043 for (p = data->mem_db_valid.next; p != &data->mem_db_valid; p = q) {
1044 q = p->next;
1045 kfree(p);
1046 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047 for (p = data->mem_db.next; p != &data->mem_db; p = q) {
1048 q = p->next;
1049 kfree(p);
1050 }
1051 for (p = data->io_db.next; p != &data->io_db; p = q) {
1052 q = p->next;
1053 kfree(p);
1054 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055}
1056
1057
1058struct pccard_resource_ops pccard_nonstatic_ops = {
1059 .validate_mem = pcmcia_nonstatic_validate_mem,
Dominik Brodowskib19a7272010-03-20 13:10:47 +01001060 .find_io = nonstatic_find_io,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 .find_mem = nonstatic_find_mem_region,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 .init = nonstatic_init,
1063 .exit = nonstatic_release_resource_db,
1064};
1065EXPORT_SYMBOL(pccard_nonstatic_ops);
1066
1067
1068/* sysfs interface to the resource database */
1069
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001070static ssize_t show_io_db(struct device *dev,
1071 struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072{
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001073 struct pcmcia_socket *s = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074 struct socket_data *data;
1075 struct resource_map *p;
1076 ssize_t ret = 0;
1077
Dominik Brodowskicfe5d802010-01-17 19:31:45 +01001078 mutex_lock(&s->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 data = s->resource_data;
1080
1081 for (p = data->io_db.next; p != &data->io_db; p = p->next) {
1082 if (ret > (PAGE_SIZE - 10))
1083 continue;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001084 ret += snprintf(&buf[ret], (PAGE_SIZE - ret - 1),
1085 "0x%08lx - 0x%08lx\n",
1086 ((unsigned long) p->base),
1087 ((unsigned long) p->base + p->num - 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088 }
1089
Dominik Brodowskicfe5d802010-01-17 19:31:45 +01001090 mutex_unlock(&s->ops_mutex);
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001091 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092}
1093
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001094static ssize_t store_io_db(struct device *dev,
1095 struct device_attribute *attr,
1096 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097{
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001098 struct pcmcia_socket *s = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 unsigned long start_addr, end_addr;
Dominik Brodowski22916632005-06-27 16:28:46 -07001100 unsigned int add = ADD_MANAGED_RESOURCE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 ssize_t ret = 0;
1102
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001103 ret = sscanf(buf, "+ 0x%lx - 0x%lx", &start_addr, &end_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104 if (ret != 2) {
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001105 ret = sscanf(buf, "- 0x%lx - 0x%lx", &start_addr, &end_addr);
Dominik Brodowski22916632005-06-27 16:28:46 -07001106 add = REMOVE_MANAGED_RESOURCE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107 if (ret != 2) {
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001108 ret = sscanf(buf, "0x%lx - 0x%lx", &start_addr,
1109 &end_addr);
Dominik Brodowski22916632005-06-27 16:28:46 -07001110 add = ADD_MANAGED_RESOURCE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111 if (ret != 2)
1112 return -EINVAL;
1113 }
1114 }
Dominik Brodowski1146bc72005-09-28 19:28:37 +02001115 if (end_addr < start_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116 return -EINVAL;
1117
Dominik Brodowskicfe5d802010-01-17 19:31:45 +01001118 mutex_lock(&s->ops_mutex);
Dominik Brodowski22916632005-06-27 16:28:46 -07001119 ret = adjust_io(s, add, start_addr, end_addr);
Dominik Brodowskicfe5d802010-01-17 19:31:45 +01001120 mutex_unlock(&s->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121
1122 return ret ? ret : count;
1123}
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001124static DEVICE_ATTR(available_resources_io, 0600, show_io_db, store_io_db);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001126static ssize_t show_mem_db(struct device *dev,
1127 struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128{
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001129 struct pcmcia_socket *s = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130 struct socket_data *data;
1131 struct resource_map *p;
1132 ssize_t ret = 0;
1133
Dominik Brodowskicfe5d802010-01-17 19:31:45 +01001134 mutex_lock(&s->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135 data = s->resource_data;
1136
Dominik Brodowski7b4884c2010-02-17 16:25:53 +01001137 for (p = data->mem_db_valid.next; p != &data->mem_db_valid;
1138 p = p->next) {
1139 if (ret > (PAGE_SIZE - 10))
1140 continue;
1141 ret += snprintf(&buf[ret], (PAGE_SIZE - ret - 1),
1142 "0x%08lx - 0x%08lx\n",
1143 ((unsigned long) p->base),
1144 ((unsigned long) p->base + p->num - 1));
1145 }
1146
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147 for (p = data->mem_db.next; p != &data->mem_db; p = p->next) {
1148 if (ret > (PAGE_SIZE - 10))
1149 continue;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001150 ret += snprintf(&buf[ret], (PAGE_SIZE - ret - 1),
1151 "0x%08lx - 0x%08lx\n",
1152 ((unsigned long) p->base),
1153 ((unsigned long) p->base + p->num - 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154 }
1155
Dominik Brodowskicfe5d802010-01-17 19:31:45 +01001156 mutex_unlock(&s->ops_mutex);
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001157 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158}
1159
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001160static ssize_t store_mem_db(struct device *dev,
1161 struct device_attribute *attr,
1162 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163{
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001164 struct pcmcia_socket *s = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 unsigned long start_addr, end_addr;
Dominik Brodowski22916632005-06-27 16:28:46 -07001166 unsigned int add = ADD_MANAGED_RESOURCE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167 ssize_t ret = 0;
1168
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001169 ret = sscanf(buf, "+ 0x%lx - 0x%lx", &start_addr, &end_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170 if (ret != 2) {
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001171 ret = sscanf(buf, "- 0x%lx - 0x%lx", &start_addr, &end_addr);
Dominik Brodowski22916632005-06-27 16:28:46 -07001172 add = REMOVE_MANAGED_RESOURCE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173 if (ret != 2) {
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001174 ret = sscanf(buf, "0x%lx - 0x%lx", &start_addr,
1175 &end_addr);
Dominik Brodowski22916632005-06-27 16:28:46 -07001176 add = ADD_MANAGED_RESOURCE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177 if (ret != 2)
1178 return -EINVAL;
1179 }
1180 }
Dominik Brodowski1146bc72005-09-28 19:28:37 +02001181 if (end_addr < start_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182 return -EINVAL;
1183
Dominik Brodowskicfe5d802010-01-17 19:31:45 +01001184 mutex_lock(&s->ops_mutex);
Dominik Brodowski22916632005-06-27 16:28:46 -07001185 ret = adjust_memory(s, add, start_addr, end_addr);
Dominik Brodowskicfe5d802010-01-17 19:31:45 +01001186 mutex_unlock(&s->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187
1188 return ret ? ret : count;
1189}
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001190static DEVICE_ATTR(available_resources_mem, 0600, show_mem_db, store_mem_db);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191
David Brownell7d578962008-06-12 12:13:55 -07001192static struct attribute *pccard_rsrc_attributes[] = {
1193 &dev_attr_available_resources_io.attr,
1194 &dev_attr_available_resources_mem.attr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195 NULL,
1196};
1197
David Brownell7d578962008-06-12 12:13:55 -07001198static const struct attribute_group rsrc_attributes = {
1199 .attrs = pccard_rsrc_attributes,
1200};
1201
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001202static int __devinit pccard_sysfs_add_rsrc(struct device *dev,
Dmitry Torokhovd8539d82005-09-15 02:01:36 -05001203 struct class_interface *class_intf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204{
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001205 struct pcmcia_socket *s = dev_get_drvdata(dev);
David Brownell7d578962008-06-12 12:13:55 -07001206
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207 if (s->resource_ops != &pccard_nonstatic_ops)
1208 return 0;
David Brownell7d578962008-06-12 12:13:55 -07001209 return sysfs_create_group(&dev->kobj, &rsrc_attributes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210}
1211
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001212static void __devexit pccard_sysfs_remove_rsrc(struct device *dev,
Dmitry Torokhovd8539d82005-09-15 02:01:36 -05001213 struct class_interface *class_intf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214{
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001215 struct pcmcia_socket *s = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216
1217 if (s->resource_ops != &pccard_nonstatic_ops)
1218 return;
David Brownell7d578962008-06-12 12:13:55 -07001219 sysfs_remove_group(&dev->kobj, &rsrc_attributes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220}
1221
Sam Ravnborged49f5d2008-05-01 04:34:50 -07001222static struct class_interface pccard_rsrc_interface __refdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223 .class = &pcmcia_socket_class,
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001224 .add_dev = &pccard_sysfs_add_rsrc,
1225 .remove_dev = __devexit_p(&pccard_sysfs_remove_rsrc),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226};
1227
1228static int __init nonstatic_sysfs_init(void)
1229{
1230 return class_interface_register(&pccard_rsrc_interface);
1231}
1232
1233static void __exit nonstatic_sysfs_exit(void)
1234{
1235 class_interface_unregister(&pccard_rsrc_interface);
1236}
1237
1238module_init(nonstatic_sysfs_init);
1239module_exit(nonstatic_sysfs_exit);