blob: 96f348b35fdea356daabb8b1836d438b163ca117 [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>
32#include <pcmcia/cs.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#include <pcmcia/cistpl.h>
34#include "cs_internal.h"
35
Dominik Brodowski49b11532010-03-07 16:41:57 +010036/* moved to rsrc_mgr.c
Linus Torvalds1da177e2005-04-16 15:20:36 -070037MODULE_AUTHOR("David A. Hinds, Dominik Brodowski");
38MODULE_LICENSE("GPL");
Dominik Brodowski49b11532010-03-07 16:41:57 +010039*/
Linus Torvalds1da177e2005-04-16 15:20:36 -070040
41/* Parameters that can be set with 'insmod' */
42
43#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0444)
44
45INT_MODULE_PARM(probe_mem, 1); /* memory probe? */
46#ifdef CONFIG_PCMCIA_PROBE
47INT_MODULE_PARM(probe_io, 1); /* IO port probe? */
48INT_MODULE_PARM(mem_limit, 0x10000);
49#endif
50
51/* for io_db and mem_db */
52struct resource_map {
53 u_long base, num;
54 struct resource_map *next;
55};
56
57struct socket_data {
58 struct resource_map mem_db;
Dominik Brodowski7b4884c2010-02-17 16:25:53 +010059 struct resource_map mem_db_valid;
Linus Torvalds1da177e2005-04-16 15:20:36 -070060 struct resource_map io_db;
Linus Torvalds1da177e2005-04-16 15:20:36 -070061};
62
Linus Torvalds1da177e2005-04-16 15:20:36 -070063#define MEM_PROBE_LOW (1 << 0)
64#define MEM_PROBE_HIGH (1 << 1)
65
Dominik Brodowski3dace8c2010-07-24 12:33:29 +020066/* Action field */
67#define REMOVE_MANAGED_RESOURCE 1
68#define ADD_MANAGED_RESOURCE 2
Linus Torvalds1da177e2005-04-16 15:20:36 -070069
70/*======================================================================
71
72 Linux resource management extensions
73
74======================================================================*/
75
76static struct resource *
Greg Kroah-Hartman2427ddd2006-06-12 17:07:52 -070077claim_region(struct pcmcia_socket *s, resource_size_t base,
78 resource_size_t size, int type, char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -070079{
80 struct resource *res, *parent;
81
82 parent = type & IORESOURCE_MEM ? &iomem_resource : &ioport_resource;
Dominik Brodowski49b11532010-03-07 16:41:57 +010083 res = pcmcia_make_resource(base, size, type | IORESOURCE_BUSY, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -070084
85 if (res) {
86#ifdef CONFIG_PCI
87 if (s && s->cb_dev)
88 parent = pci_find_parent_resource(s->cb_dev, res);
89#endif
90 if (!parent || request_resource(parent, res)) {
91 kfree(res);
92 res = NULL;
93 }
94 }
95 return res;
96}
97
98static void free_region(struct resource *res)
99{
100 if (res) {
101 release_resource(res);
102 kfree(res);
103 }
104}
105
106/*======================================================================
107
108 These manage the internal databases of available resources.
109
110======================================================================*/
111
112static int add_interval(struct resource_map *map, u_long base, u_long num)
113{
Dominik Brodowski11683862008-08-03 10:22:47 +0200114 struct resource_map *p, *q;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115
Dominik Brodowski11683862008-08-03 10:22:47 +0200116 for (p = map; ; p = p->next) {
Dominik Brodowskif309cb32010-02-17 14:35:33 +0100117 if ((p != map) && (p->base+p->num >= base)) {
118 p->num = max(num + base - p->base, p->num);
119 return 0;
120 }
Dominik Brodowski11683862008-08-03 10:22:47 +0200121 if ((p->next == map) || (p->next->base > base+num-1))
122 break;
123 }
124 q = kmalloc(sizeof(struct resource_map), GFP_KERNEL);
125 if (!q) {
126 printk(KERN_WARNING "out of memory to update resources\n");
127 return -ENOMEM;
128 }
129 q->base = base; q->num = num;
130 q->next = p->next; p->next = q;
131 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132}
133
134/*====================================================================*/
135
136static int sub_interval(struct resource_map *map, u_long base, u_long num)
137{
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100138 struct resource_map *p, *q;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100140 for (p = map; ; p = q) {
141 q = p->next;
142 if (q == map)
143 break;
144 if ((q->base+q->num > base) && (base+num > q->base)) {
145 if (q->base >= base) {
146 if (q->base+q->num <= base+num) {
147 /* Delete whole block */
148 p->next = q->next;
149 kfree(q);
150 /* don't advance the pointer yet */
151 q = p;
152 } else {
153 /* Cut off bit from the front */
154 q->num = q->base + q->num - base - num;
155 q->base = base + num;
156 }
157 } else if (q->base+q->num <= base+num) {
158 /* Cut off bit from the end */
159 q->num = base - q->base;
160 } else {
161 /* Split the block into two pieces */
162 p = kmalloc(sizeof(struct resource_map),
163 GFP_KERNEL);
164 if (!p) {
165 printk(KERN_WARNING "out of memory to update resources\n");
166 return -ENOMEM;
167 }
168 p->base = base+num;
169 p->num = q->base+q->num - p->base;
170 q->num = base - q->base;
171 p->next = q->next ; q->next = p;
172 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174 }
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100175 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176}
177
178/*======================================================================
179
180 These routines examine a region of IO or memory addresses to
181 determine what ranges might be genuinely available.
182
183======================================================================*/
184
185#ifdef CONFIG_PCMCIA_PROBE
Olof Johansson906da802008-02-04 22:27:35 -0800186static void do_io_probe(struct pcmcia_socket *s, unsigned int base,
187 unsigned int num)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188{
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100189 struct resource *res;
190 struct socket_data *s_data = s->resource_data;
191 unsigned int i, j, bad;
192 int any;
193 u_char *b, hole, most;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100195 dev_printk(KERN_INFO, &s->dev, "cs: IO port probe %#x-%#x:",
196 base, base+num-1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100198 /* First, what does a floating port look like? */
199 b = kzalloc(256, GFP_KERNEL);
200 if (!b) {
201 printk("\n");
202 dev_printk(KERN_ERR, &s->dev,
203 "do_io_probe: unable to kmalloc 256 bytes");
204 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205 }
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100206 for (i = base, most = 0; i < base+num; i += 8) {
Dominik Brodowski509b0862010-04-08 19:23:07 +0200207 res = claim_region(s, i, 8, IORESOURCE_IO, "PCMCIA ioprobe");
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100208 if (!res)
209 continue;
210 hole = inb(i);
211 for (j = 1; j < 8; j++)
212 if (inb(i+j) != hole)
213 break;
214 free_region(res);
215 if ((j == 8) && (++b[hole] > b[most]))
216 most = hole;
217 if (b[most] == 127)
218 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 }
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100220 kfree(b);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100222 bad = any = 0;
223 for (i = base; i < base+num; i += 8) {
Dominik Brodowski509b0862010-04-08 19:23:07 +0200224 res = claim_region(s, i, 8, IORESOURCE_IO, "PCMCIA ioprobe");
225 if (!res) {
226 if (!any)
227 printk(" excluding");
228 if (!bad)
229 bad = any = i;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100230 continue;
Dominik Brodowski509b0862010-04-08 19:23:07 +0200231 }
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100232 for (j = 0; j < 8; j++)
233 if (inb(i+j) != most)
234 break;
235 free_region(res);
236 if (j < 8) {
237 if (!any)
238 printk(" excluding");
239 if (!bad)
240 bad = any = i;
241 } else {
242 if (bad) {
243 sub_interval(&s_data->io_db, bad, i-bad);
244 printk(" %#x-%#x", bad, i-1);
245 bad = 0;
246 }
247 }
248 }
249 if (bad) {
250 if ((num > 16) && (bad == base) && (i == base+num)) {
Dominik Brodowski509b0862010-04-08 19:23:07 +0200251 sub_interval(&s_data->io_db, bad, i-bad);
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100252 printk(" nothing: probe failed.\n");
253 return;
254 } else {
255 sub_interval(&s_data->io_db, bad, i-bad);
256 printk(" %#x-%#x", bad, i-1);
257 }
258 }
259
260 printk(any ? "\n" : " clean.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261}
262#endif
263
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100264/*======================================================================*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100266/**
267 * readable() - iomem validation function for cards with a valid CIS
268 */
Dominik Brodowskic5081d52008-06-19 20:12:34 +0200269static int readable(struct pcmcia_socket *s, struct resource *res,
270 unsigned int *count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271{
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100272 int ret = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273
Dominik Brodowski7ab248552010-02-17 18:00:07 +0100274 if (s->fake_cis) {
275 dev_dbg(&s->dev, "fake CIS is being used: can't validate mem\n");
276 return 0;
277 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278
279 s->cis_mem.res = res;
280 s->cis_virt = ioremap(res->start, s->map_size);
281 if (s->cis_virt) {
Dominik Brodowski6b8e0872010-01-12 21:42:51 +0100282 mutex_unlock(&s->ops_mutex);
Dominik Brodowski6e7b51a2010-01-06 13:57:43 +0100283 /* as we're only called from pcmcia.c, we're safe */
284 if (s->callback->validate)
285 ret = s->callback->validate(s, count);
Dominik Brodowski904e3772010-01-02 12:28:04 +0100286 /* invalidate mapping */
Dominik Brodowski6b8e0872010-01-12 21:42:51 +0100287 mutex_lock(&s->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 iounmap(s->cis_virt);
289 s->cis_virt = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290 }
291 s->cis_mem.res = NULL;
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100292 if ((ret) || (*count == 0))
293 return -EINVAL;
294 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295}
296
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100297/**
298 * checksum() - iomem validation function for simple memory cards
299 */
300static int checksum(struct pcmcia_socket *s, struct resource *res,
301 unsigned int *value)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302{
303 pccard_mem_map map;
304 int i, a = 0, b = -1, d;
305 void __iomem *virt;
306
307 virt = ioremap(res->start, s->map_size);
308 if (virt) {
309 map.map = 0;
310 map.flags = MAP_ACTIVE;
311 map.speed = 0;
312 map.res = res;
313 map.card_start = 0;
314 s->ops->set_mem_map(s, &map);
315
316 /* Don't bother checking every word... */
317 for (i = 0; i < s->map_size; i += 44) {
318 d = readl(virt+i);
319 a += d;
320 b &= d;
321 }
322
323 map.flags = 0;
324 s->ops->set_mem_map(s, &map);
325
326 iounmap(virt);
327 }
328
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100329 if (b == -1)
330 return -EINVAL;
331
332 *value = a;
333
334 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335}
336
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100337/**
338 * do_validate_mem() - low level validate a memory region for PCMCIA use
339 * @s: PCMCIA socket to validate
340 * @base: start address of resource to check
341 * @size: size of resource to check
342 * @validate: validation function to use
343 *
344 * do_validate_mem() splits up the memory region which is to be checked
345 * into two parts. Both are passed to the @validate() function. If
346 * @validate() returns non-zero, or the value parameter to @validate()
347 * is zero, or the value parameter is different between both calls,
348 * the check fails, and -EINVAL is returned. Else, 0 is returned.
349 */
350static int do_validate_mem(struct pcmcia_socket *s,
351 unsigned long base, unsigned long size,
352 int validate (struct pcmcia_socket *s,
353 struct resource *res,
354 unsigned int *value))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355{
Dominik Brodowski7b4884c2010-02-17 16:25:53 +0100356 struct socket_data *s_data = s->resource_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 struct resource *res1, *res2;
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100358 unsigned int info1 = 1, info2 = 1;
359 int ret = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100361 res1 = claim_region(s, base, size/2, IORESOURCE_MEM, "PCMCIA memprobe");
362 res2 = claim_region(s, base + size/2, size/2, IORESOURCE_MEM,
363 "PCMCIA memprobe");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364
365 if (res1 && res2) {
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100366 ret = 0;
367 if (validate) {
368 ret = validate(s, res1, &info1);
369 ret += validate(s, res2, &info2);
370 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 }
372
373 free_region(res2);
374 free_region(res1);
375
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100376 dev_dbg(&s->dev, "cs: memory probe 0x%06lx-0x%06lx: %p %p %u %u %u",
377 base, base+size-1, res1, res2, ret, info1, info2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100379 if ((ret) || (info1 != info2) || (info1 == 0))
380 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381
Dominik Brodowski7b4884c2010-02-17 16:25:53 +0100382 if (validate && !s->fake_cis) {
383 /* move it to the validated data set */
384 add_interval(&s_data->mem_db_valid, base, size);
385 sub_interval(&s_data->mem_db, base, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386 }
387
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100388 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389}
390
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100392/**
393 * do_mem_probe() - validate a memory region for PCMCIA use
394 * @s: PCMCIA socket to validate
395 * @base: start address of resource to check
396 * @num: size of resource to check
397 * @validate: validation function to use
398 * @fallback: validation function to use if validate fails
399 *
400 * do_mem_probe() checks a memory region for use by the PCMCIA subsystem.
401 * To do so, the area is split up into sensible parts, and then passed
402 * into the @validate() function. Only if @validate() and @fallback() fail,
403 * the area is marked as unavaibale for use by the PCMCIA subsystem. The
404 * function returns the size of the usable memory area.
405 */
406static int do_mem_probe(struct pcmcia_socket *s, u_long base, u_long num,
407 int validate (struct pcmcia_socket *s,
408 struct resource *res,
409 unsigned int *value),
410 int fallback (struct pcmcia_socket *s,
411 struct resource *res,
412 unsigned int *value))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413{
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100414 struct socket_data *s_data = s->resource_data;
415 u_long i, j, bad, fail, step;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100417 dev_printk(KERN_INFO, &s->dev, "cs: memory probe 0x%06lx-0x%06lx:",
418 base, base+num-1);
419 bad = fail = 0;
420 step = (num < 0x20000) ? 0x2000 : ((num>>4) & ~0x1fff);
421 /* don't allow too large steps */
422 if (step > 0x800000)
423 step = 0x800000;
424 /* cis_readable wants to map 2x map_size */
425 if (step < 2 * s->map_size)
426 step = 2 * s->map_size;
427 for (i = j = base; i < base+num; i = j + step) {
428 if (!fail) {
429 for (j = i; j < base+num; j += step) {
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100430 if (!do_validate_mem(s, j, step, validate))
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100431 break;
432 }
433 fail = ((i == base) && (j == base+num));
434 }
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100435 if ((fail) && (fallback)) {
436 for (j = i; j < base+num; j += step)
437 if (!do_validate_mem(s, j, step, fallback))
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100438 break;
439 }
440 if (i != j) {
441 if (!bad)
442 printk(" excluding");
443 printk(" %#05lx-%#05lx", i, j-1);
444 sub_interval(&s_data->mem_db, i, j-i);
445 bad += j-i;
446 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447 }
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100448 printk(bad ? "\n" : " clean.\n");
449 return num - bad;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450}
451
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100452
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453#ifdef CONFIG_PCMCIA_PROBE
454
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100455/**
456 * inv_probe() - top-to-bottom search for one usuable high memory area
457 * @s: PCMCIA socket to validate
458 * @m: resource_map to check
459 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460static u_long inv_probe(struct resource_map *m, struct pcmcia_socket *s)
461{
Dominik Brodowskide759142005-09-28 19:41:56 +0200462 struct socket_data *s_data = s->resource_data;
463 u_long ok;
464 if (m == &s_data->mem_db)
465 return 0;
466 ok = inv_probe(m->next, s);
467 if (ok) {
468 if (m->base >= 0x100000)
469 sub_interval(&s_data->mem_db, m->base, m->num);
470 return ok;
471 }
472 if (m->base < 0x100000)
473 return 0;
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100474 return do_mem_probe(s, m->base, m->num, readable, checksum);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475}
476
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100477/**
478 * validate_mem() - memory probe function
479 * @s: PCMCIA socket to validate
480 * @probe_mask: MEM_PROBE_LOW | MEM_PROBE_HIGH
481 *
482 * The memory probe. If the memory list includes a 64K-aligned block
483 * below 1MB, we probe in 64K chunks, and as soon as we accumulate at
484 * least mem_limit free space, we quit. Returns 0 on usuable ports.
485 */
Dominik Brodowskide759142005-09-28 19:41:56 +0200486static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487{
Dominik Brodowskide759142005-09-28 19:41:56 +0200488 struct resource_map *m, mm;
489 static unsigned char order[] = { 0xd0, 0xe0, 0xc0, 0xf0 };
490 unsigned long b, i, ok = 0;
491 struct socket_data *s_data = s->resource_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492
Dominik Brodowskide759142005-09-28 19:41:56 +0200493 /* We do up to four passes through the list */
494 if (probe_mask & MEM_PROBE_HIGH) {
495 if (inv_probe(s_data->mem_db.next, s) > 0)
496 return 0;
Dominik Brodowski7b4884c2010-02-17 16:25:53 +0100497 if (s_data->mem_db_valid.next != &s_data->mem_db_valid)
498 return 0;
Dominik Brodowskidbe4ea52008-08-02 21:36:19 +0200499 dev_printk(KERN_NOTICE, &s->dev,
500 "cs: warning: no high memory space available!\n");
Dominik Brodowskide759142005-09-28 19:41:56 +0200501 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 }
Dominik Brodowskide759142005-09-28 19:41:56 +0200503
504 for (m = s_data->mem_db.next; m != &s_data->mem_db; m = mm.next) {
505 mm = *m;
506 /* Only probe < 1 MB */
507 if (mm.base >= 0x100000)
508 continue;
509 if ((mm.base | mm.num) & 0xffff) {
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100510 ok += do_mem_probe(s, mm.base, mm.num, readable,
511 checksum);
Dominik Brodowskide759142005-09-28 19:41:56 +0200512 continue;
513 }
514 /* Special probe for 64K-aligned block */
515 for (i = 0; i < 4; i++) {
516 b = order[i] << 12;
517 if ((b >= mm.base) && (b+0x10000 <= mm.base+mm.num)) {
518 if (ok >= mem_limit)
519 sub_interval(&s_data->mem_db, b, 0x10000);
520 else
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100521 ok += do_mem_probe(s, b, 0x10000,
522 readable, checksum);
Dominik Brodowskide759142005-09-28 19:41:56 +0200523 }
524 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 }
Dominik Brodowskide759142005-09-28 19:41:56 +0200526
527 if (ok > 0)
528 return 0;
529
530 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531}
532
533#else /* CONFIG_PCMCIA_PROBE */
534
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100535/**
536 * validate_mem() - memory probe function
537 * @s: PCMCIA socket to validate
538 * @probe_mask: ignored
539 *
540 * Returns 0 on usuable ports.
541 */
Andrew Morton2cff9442005-11-16 21:29:26 -0800542static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543{
544 struct resource_map *m, mm;
545 struct socket_data *s_data = s->resource_data;
Andrew Morton2cff9442005-11-16 21:29:26 -0800546 unsigned long ok = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547
548 for (m = s_data->mem_db.next; m != &s_data->mem_db; m = mm.next) {
549 mm = *m;
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100550 ok += do_mem_probe(s, mm.base, mm.num, readable, checksum);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551 }
Andrew Morton2cff9442005-11-16 21:29:26 -0800552 if (ok > 0)
553 return 0;
554 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555}
556
557#endif /* CONFIG_PCMCIA_PROBE */
558
559
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100560/**
561 * pcmcia_nonstatic_validate_mem() - try to validate iomem for PCMCIA use
562 * @s: PCMCIA socket to validate
563 *
564 * This is tricky... when we set up CIS memory, we try to validate
565 * the memory window space allocations.
566 *
Dominik Brodowski7fe908d2006-01-10 21:20:36 +0100567 * Locking note: Must be called with skt_mutex held!
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568 */
Dominik Brodowskide759142005-09-28 19:41:56 +0200569static int pcmcia_nonstatic_validate_mem(struct pcmcia_socket *s)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570{
571 struct socket_data *s_data = s->resource_data;
Dominik Brodowskide759142005-09-28 19:41:56 +0200572 unsigned int probe_mask = MEM_PROBE_LOW;
Dominik Brodowski7b4884c2010-02-17 16:25:53 +0100573 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574
Dominik Brodowski7b4884c2010-02-17 16:25:53 +0100575 if (!probe_mem || !(s->state & SOCKET_PRESENT))
Dominik Brodowskide759142005-09-28 19:41:56 +0200576 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577
Dominik Brodowskide759142005-09-28 19:41:56 +0200578 if (s->features & SS_CAP_PAGE_REGS)
579 probe_mask = MEM_PROBE_HIGH;
580
Dominik Brodowski7b4884c2010-02-17 16:25:53 +0100581 ret = validate_mem(s, probe_mask);
Dominik Brodowskide759142005-09-28 19:41:56 +0200582
Dominik Brodowski7b4884c2010-02-17 16:25:53 +0100583 if (s_data->mem_db_valid.next != &s_data->mem_db_valid)
584 return 0;
Dominik Brodowskide759142005-09-28 19:41:56 +0200585
586 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587}
588
589struct pcmcia_align_data {
590 unsigned long mask;
591 unsigned long offset;
592 struct resource_map *map;
593};
594
Dominik Brodowski147a2742010-04-04 18:10:35 +0200595static resource_size_t pcmcia_common_align(struct pcmcia_align_data *align_data,
596 resource_size_t start)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597{
Dominik Brodowski147a2742010-04-04 18:10:35 +0200598 resource_size_t ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 /*
600 * Ensure that we have the correct start address
601 */
Dominik Brodowski147a2742010-04-04 18:10:35 +0200602 ret = (start & ~align_data->mask) + align_data->offset;
603 if (ret < start)
604 ret += align_data->mask + 1;
605 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606}
607
Dominik Brodowskib26b2d42010-01-01 17:40:49 +0100608static resource_size_t
Dominik Brodowski3b7a17f2010-01-01 17:40:50 +0100609pcmcia_align(void *align_data, const struct resource *res,
610 resource_size_t size, resource_size_t align)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611{
612 struct pcmcia_align_data *data = align_data;
613 struct resource_map *m;
Dominik Brodowskib26b2d42010-01-01 17:40:49 +0100614 resource_size_t start;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615
Dominik Brodowski147a2742010-04-04 18:10:35 +0200616 start = pcmcia_common_align(data, res->start);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617
618 for (m = data->map->next; m != data->map; m = m->next) {
Dominik Brodowski147a2742010-04-04 18:10:35 +0200619 unsigned long map_start = m->base;
620 unsigned long map_end = m->base + m->num - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621
622 /*
623 * If the lower resources are not available, try aligning
624 * to this entry of the resource database to see if it'll
625 * fit here.
626 */
Dominik Brodowski147a2742010-04-04 18:10:35 +0200627 if (start < map_start)
628 start = pcmcia_common_align(data, map_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629
630 /*
631 * If we're above the area which was passed in, there's
632 * no point proceeding.
633 */
Dominik Brodowski147a2742010-04-04 18:10:35 +0200634 if (start >= res->end)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 break;
636
Dominik Brodowski147a2742010-04-04 18:10:35 +0200637 if ((start + size - 1) <= map_end)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 break;
639 }
640
641 /*
642 * If we failed to find something suitable, ensure we fail.
643 */
644 if (m == data->map)
Dominik Brodowskib26b2d42010-01-01 17:40:49 +0100645 start = res->end;
646
647 return start;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648}
649
650/*
651 * Adjust an existing IO region allocation, but making sure that we don't
652 * encroach outside the resources which the user supplied.
653 */
Dominik Brodowskib19a7272010-03-20 13:10:47 +0100654static int __nonstatic_adjust_io_region(struct pcmcia_socket *s,
655 unsigned long r_start,
656 unsigned long r_end)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657{
658 struct resource_map *m;
659 struct socket_data *s_data = s->resource_data;
660 int ret = -ENOMEM;
661
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 for (m = s_data->io_db.next; m != &s_data->io_db; m = m->next) {
663 unsigned long start = m->base;
664 unsigned long end = m->base + m->num - 1;
665
666 if (start > r_start || r_end > end)
667 continue;
668
Dominik Brodowskib19a7272010-03-20 13:10:47 +0100669 ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671
672 return ret;
673}
674
675/*======================================================================
676
677 These find ranges of I/O ports or memory addresses that are not
678 currently allocated by other devices.
679
680 The 'align' field should reflect the number of bits of address
681 that need to be preserved from the initial value of *base. It
682 should be a power of two, greater than or equal to 'num'. A value
683 of 0 means that all bits of *base are significant. *base should
684 also be strictly less than 'align'.
685
686======================================================================*/
687
Dominik Brodowskib19a7272010-03-20 13:10:47 +0100688static struct resource *__nonstatic_find_io_region(struct pcmcia_socket *s,
689 unsigned long base, int num,
690 unsigned long align)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691{
Dominik Brodowski49b11532010-03-07 16:41:57 +0100692 struct resource *res = pcmcia_make_resource(0, num, IORESOURCE_IO,
693 dev_name(&s->dev));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 struct socket_data *s_data = s->resource_data;
695 struct pcmcia_align_data data;
696 unsigned long min = base;
697 int ret;
698
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 data.mask = align - 1;
700 data.offset = base & data.mask;
701 data.map = &s_data->io_db;
702
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703#ifdef CONFIG_PCI
704 if (s->cb_dev) {
705 ret = pci_bus_alloc_resource(s->cb_dev->bus, res, num, 1,
706 min, 0, pcmcia_align, &data);
707 } else
708#endif
709 ret = allocate_resource(&ioport_resource, res, num, min, ~0UL,
710 1, pcmcia_align, &data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711
712 if (ret != 0) {
713 kfree(res);
714 res = NULL;
715 }
716 return res;
717}
718
Dominik Brodowskib19a7272010-03-20 13:10:47 +0100719static int nonstatic_find_io(struct pcmcia_socket *s, unsigned int attr,
720 unsigned int *base, unsigned int num,
Dominik Brodowskiad0c7be2010-07-25 13:10:22 +0200721 unsigned int align, struct resource **parent)
Dominik Brodowskib19a7272010-03-20 13:10:47 +0100722{
723 int i, ret = 0;
724
725 /* Check for an already-allocated window that must conflict with
726 * what was asked for. It is a hack because it does not catch all
727 * potential conflicts, just the most obvious ones.
728 */
729 for (i = 0; i < MAX_IO_WIN; i++) {
730 if (!s->io[i].res)
731 continue;
732
733 if (!*base)
734 continue;
735
736 if ((s->io[i].res->start & (align-1)) == *base)
737 return -EBUSY;
738 }
739
740 for (i = 0; i < MAX_IO_WIN; i++) {
741 struct resource *res = s->io[i].res;
742 unsigned int try;
743
744 if (res && (res->flags & IORESOURCE_BITS) !=
745 (attr & IORESOURCE_BITS))
746 continue;
747
748 if (!res) {
749 if (align == 0)
750 align = 0x10000;
751
752 res = s->io[i].res = __nonstatic_find_io_region(s,
753 *base, num,
754 align);
755 if (!res)
756 return -EINVAL;
757
758 *base = res->start;
759 s->io[i].res->flags =
760 ((res->flags & ~IORESOURCE_BITS) |
761 (attr & IORESOURCE_BITS));
762 s->io[i].InUse = num;
Dominik Brodowskiad0c7be2010-07-25 13:10:22 +0200763 *parent = res;
Dominik Brodowskib19a7272010-03-20 13:10:47 +0100764 return 0;
765 }
766
767 /* Try to extend top of window */
768 try = res->end + 1;
769 if ((*base == 0) || (*base == try)) {
770 ret = __nonstatic_adjust_io_region(s, res->start,
771 res->end + num);
772 if (!ret) {
773 ret = adjust_resource(s->io[i].res, res->start,
774 res->end - res->start + num + 1);
775 if (ret)
776 continue;
777 *base = try;
778 s->io[i].InUse += num;
Dominik Brodowskiad0c7be2010-07-25 13:10:22 +0200779 *parent = res;
Dominik Brodowskib19a7272010-03-20 13:10:47 +0100780 return 0;
781 }
782 }
783
784 /* Try to extend bottom of window */
785 try = res->start - num;
786 if ((*base == 0) || (*base == try)) {
787 ret = __nonstatic_adjust_io_region(s,
788 res->start - num,
789 res->end);
790 if (!ret) {
791 ret = adjust_resource(s->io[i].res,
792 res->start - num,
793 res->end - res->start + num + 1);
794 if (ret)
795 continue;
796 *base = try;
797 s->io[i].InUse += num;
Dominik Brodowskiad0c7be2010-07-25 13:10:22 +0200798 *parent = res;
Dominik Brodowskib19a7272010-03-20 13:10:47 +0100799 return 0;
800 }
801 }
802 }
803
804 return -EINVAL;
805}
806
807
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100808static struct resource *nonstatic_find_mem_region(u_long base, u_long num,
Dominik Brodowskie94e15f2005-06-27 16:28:15 -0700809 u_long align, int low, struct pcmcia_socket *s)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810{
Dominik Brodowski49b11532010-03-07 16:41:57 +0100811 struct resource *res = pcmcia_make_resource(0, num, IORESOURCE_MEM,
812 dev_name(&s->dev));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 struct socket_data *s_data = s->resource_data;
814 struct pcmcia_align_data data;
815 unsigned long min, max;
Dominik Brodowski7b4884c2010-02-17 16:25:53 +0100816 int ret, i, j;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817
818 low = low || !(s->features & SS_CAP_PAGE_REGS);
819
820 data.mask = align - 1;
821 data.offset = base & data.mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822
823 for (i = 0; i < 2; i++) {
Dominik Brodowski7b4884c2010-02-17 16:25:53 +0100824 data.map = &s_data->mem_db_valid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 if (low) {
826 max = 0x100000UL;
827 min = base < max ? base : 0;
828 } else {
829 max = ~0UL;
830 min = 0x100000UL + base;
831 }
832
Dominik Brodowski7b4884c2010-02-17 16:25:53 +0100833 for (j = 0; j < 2; j++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834#ifdef CONFIG_PCI
Dominik Brodowski7b4884c2010-02-17 16:25:53 +0100835 if (s->cb_dev) {
836 ret = pci_bus_alloc_resource(s->cb_dev->bus,
837 res, num, 1, min, 0,
838 pcmcia_align, &data);
839 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840#endif
Dominik Brodowski7b4884c2010-02-17 16:25:53 +0100841 {
842 ret = allocate_resource(&iomem_resource,
843 res, num, min, max, 1,
844 pcmcia_align, &data);
845 }
846 if (ret == 0)
847 break;
848 data.map = &s_data->mem_db;
849 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 if (ret == 0 || low)
851 break;
852 low = 1;
853 }
854
855 if (ret != 0) {
856 kfree(res);
857 res = NULL;
858 }
859 return res;
860}
861
862
Dominik Brodowski22916632005-06-27 16:28:46 -0700863static int adjust_memory(struct pcmcia_socket *s, unsigned int action, unsigned long start, unsigned long end)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 struct socket_data *data = s->resource_data;
Dominik Brodowski22916632005-06-27 16:28:46 -0700866 unsigned long size = end - start + 1;
867 int ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868
Dominik Brodowski1146bc72005-09-28 19:28:37 +0200869 if (end < start)
Dominik Brodowski22916632005-06-27 16:28:46 -0700870 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871
Dominik Brodowski22916632005-06-27 16:28:46 -0700872 switch (action) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 case ADD_MANAGED_RESOURCE:
Dominik Brodowski22916632005-06-27 16:28:46 -0700874 ret = add_interval(&data->mem_db, start, size);
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100875 if (!ret)
876 do_mem_probe(s, start, size, NULL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 break;
878 case REMOVE_MANAGED_RESOURCE:
Dominik Brodowski22916632005-06-27 16:28:46 -0700879 ret = sub_interval(&data->mem_db, start, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 break;
881 default:
Dominik Brodowski22916632005-06-27 16:28:46 -0700882 ret = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884
885 return ret;
886}
887
888
Dominik Brodowski22916632005-06-27 16:28:46 -0700889static int adjust_io(struct pcmcia_socket *s, unsigned int action, unsigned long start, unsigned long end)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890{
891 struct socket_data *data = s->resource_data;
Dominik Brodowski41b97ab2010-04-15 19:01:53 +0200892 unsigned long size;
Dominik Brodowski22916632005-06-27 16:28:46 -0700893 int ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894
Dominik Brodowski9713ab22010-03-23 16:05:00 +0100895#if defined(CONFIG_X86)
896 /* on x86, avoid anything < 0x100 for it is often used for
897 * legacy platform devices */
898 if (start < 0x100)
899 start = 0x100;
900#endif
901
Dominik Brodowski41b97ab2010-04-15 19:01:53 +0200902 size = end - start + 1;
903
Dominik Brodowski1146bc72005-09-28 19:28:37 +0200904 if (end < start)
Dominik Brodowski22916632005-06-27 16:28:46 -0700905 return -EINVAL;
906
907 if (end > IO_SPACE_LIMIT)
908 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909
Dominik Brodowski22916632005-06-27 16:28:46 -0700910 switch (action) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911 case ADD_MANAGED_RESOURCE:
Dominik Brodowski22916632005-06-27 16:28:46 -0700912 if (add_interval(&data->io_db, start, size) != 0) {
913 ret = -EBUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 break;
915 }
916#ifdef CONFIG_PCMCIA_PROBE
917 if (probe_io)
Dominik Brodowski22916632005-06-27 16:28:46 -0700918 do_io_probe(s, start, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919#endif
920 break;
921 case REMOVE_MANAGED_RESOURCE:
Dominik Brodowski22916632005-06-27 16:28:46 -0700922 sub_interval(&data->io_db, start, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923 break;
924 default:
Dominik Brodowski22916632005-06-27 16:28:46 -0700925 ret = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926 break;
927 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928
929 return ret;
930}
931
932
Dominik Brodowski3c299762005-06-27 16:28:46 -0700933#ifdef CONFIG_PCI
934static int nonstatic_autoadd_resources(struct pcmcia_socket *s)
935{
936 struct resource *res;
937 int i, done = 0;
938
939 if (!s->cb_dev || !s->cb_dev->bus)
940 return -ENODEV;
941
Brian Gerst0d078f62005-10-30 14:59:20 -0800942#if defined(CONFIG_X86)
Dominik Brodowskicf26e8d2010-03-29 21:40:35 +0200943 /* If this is the root bus, the risk of hitting some strange
944 * system devices is too high: If a driver isn't loaded, the
945 * resources are not claimed; even if a driver is loaded, it
946 * may not request all resources or even the wrong one. We
947 * can neither trust the rest of the kernel nor ACPI/PNP and
948 * CRS parsing to get it right. Therefore, use several
949 * safeguards:
950 *
951 * - Do not auto-add resources if the CardBus bridge is on
952 * the PCI root bus
953 *
954 * - Avoid any I/O ports < 0x100.
955 *
956 * - On PCI-PCI bridges, only use resources which are set up
957 * exclusively for the secondary PCI bus: the risk of hitting
958 * system devices is quite low, as they usually aren't
959 * connected to the secondary PCI bus.
Dominik Brodowskib6d00f02005-06-27 16:29:02 -0700960 */
961 if (s->cb_dev->bus->number == 0)
962 return -EINVAL;
Dominik Brodowskib6d00f02005-06-27 16:29:02 -0700963
Dominik Brodowskicf26e8d2010-03-29 21:40:35 +0200964 for (i = 0; i < PCI_BRIDGE_RESOURCE_NUM; i++) {
965 res = s->cb_dev->bus->resource[i];
966#else
Bjorn Helgaas89a74ec2010-02-23 10:24:31 -0700967 pci_bus_for_each_resource(s->cb_dev->bus, res, i) {
Dominik Brodowskicf26e8d2010-03-29 21:40:35 +0200968#endif
Dominik Brodowski3c299762005-06-27 16:28:46 -0700969 if (!res)
970 continue;
971
972 if (res->flags & IORESOURCE_IO) {
Dominik Brodowskicf26e8d2010-03-29 21:40:35 +0200973 /* safeguard against the root resource, where the
974 * risk of hitting any other device would be too
975 * high */
Dominik Brodowski3c299762005-06-27 16:28:46 -0700976 if (res == &ioport_resource)
977 continue;
Dominik Brodowskicf26e8d2010-03-29 21:40:35 +0200978
Dominik Brodowskidbe4ea52008-08-02 21:36:19 +0200979 dev_printk(KERN_INFO, &s->cb_dev->dev,
Bjorn Helgaase1944c62010-03-16 15:53:08 -0600980 "pcmcia: parent PCI bridge window: %pR\n",
981 res);
Dominik Brodowski3c299762005-06-27 16:28:46 -0700982 if (!adjust_io(s, ADD_MANAGED_RESOURCE, res->start, res->end))
983 done |= IORESOURCE_IO;
984
985 }
986
987 if (res->flags & IORESOURCE_MEM) {
Dominik Brodowskicf26e8d2010-03-29 21:40:35 +0200988 /* safeguard against the root resource, where the
989 * risk of hitting any other device would be too
990 * high */
Dominik Brodowski3c299762005-06-27 16:28:46 -0700991 if (res == &iomem_resource)
992 continue;
Dominik Brodowskicf26e8d2010-03-29 21:40:35 +0200993
Dominik Brodowskidbe4ea52008-08-02 21:36:19 +0200994 dev_printk(KERN_INFO, &s->cb_dev->dev,
Bjorn Helgaase1944c62010-03-16 15:53:08 -0600995 "pcmcia: parent PCI bridge window: %pR\n",
996 res);
Dominik Brodowski3c299762005-06-27 16:28:46 -0700997 if (!adjust_memory(s, ADD_MANAGED_RESOURCE, res->start, res->end))
998 done |= IORESOURCE_MEM;
999 }
1000 }
1001
1002 /* if we got at least one of IO, and one of MEM, we can be glad and
1003 * activate the PCMCIA subsystem */
Dominik Brodowski54bb5672005-09-28 19:29:59 +02001004 if (done == (IORESOURCE_MEM | IORESOURCE_IO))
Dominik Brodowski3c299762005-06-27 16:28:46 -07001005 s->resource_setup_done = 1;
1006
1007 return 0;
1008}
1009
1010#else
1011
1012static inline int nonstatic_autoadd_resources(struct pcmcia_socket *s)
1013{
1014 return -ENODEV;
1015}
1016
1017#endif
1018
1019
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020static int nonstatic_init(struct pcmcia_socket *s)
1021{
1022 struct socket_data *data;
1023
Dominik Brodowski8084b372005-12-11 21:18:26 +01001024 data = kzalloc(sizeof(struct socket_data), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 if (!data)
1026 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027
1028 data->mem_db.next = &data->mem_db;
Dominik Brodowski7b4884c2010-02-17 16:25:53 +01001029 data->mem_db_valid.next = &data->mem_db_valid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030 data->io_db.next = &data->io_db;
1031
1032 s->resource_data = (void *) data;
1033
Dominik Brodowski3c299762005-06-27 16:28:46 -07001034 nonstatic_autoadd_resources(s);
1035
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036 return 0;
1037}
1038
1039static void nonstatic_release_resource_db(struct pcmcia_socket *s)
1040{
1041 struct socket_data *data = s->resource_data;
1042 struct resource_map *p, *q;
1043
Dominik Brodowski7b4884c2010-02-17 16:25:53 +01001044 for (p = data->mem_db_valid.next; p != &data->mem_db_valid; p = q) {
1045 q = p->next;
1046 kfree(p);
1047 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048 for (p = data->mem_db.next; p != &data->mem_db; p = q) {
1049 q = p->next;
1050 kfree(p);
1051 }
1052 for (p = data->io_db.next; p != &data->io_db; p = q) {
1053 q = p->next;
1054 kfree(p);
1055 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056}
1057
1058
1059struct pccard_resource_ops pccard_nonstatic_ops = {
1060 .validate_mem = pcmcia_nonstatic_validate_mem,
Dominik Brodowskib19a7272010-03-20 13:10:47 +01001061 .find_io = nonstatic_find_io,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 .find_mem = nonstatic_find_mem_region,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 .init = nonstatic_init,
1064 .exit = nonstatic_release_resource_db,
1065};
1066EXPORT_SYMBOL(pccard_nonstatic_ops);
1067
1068
1069/* sysfs interface to the resource database */
1070
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001071static ssize_t show_io_db(struct device *dev,
1072 struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073{
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001074 struct pcmcia_socket *s = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075 struct socket_data *data;
1076 struct resource_map *p;
1077 ssize_t ret = 0;
1078
Dominik Brodowskicfe5d802010-01-17 19:31:45 +01001079 mutex_lock(&s->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080 data = s->resource_data;
1081
1082 for (p = data->io_db.next; p != &data->io_db; p = p->next) {
1083 if (ret > (PAGE_SIZE - 10))
1084 continue;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001085 ret += snprintf(&buf[ret], (PAGE_SIZE - ret - 1),
1086 "0x%08lx - 0x%08lx\n",
1087 ((unsigned long) p->base),
1088 ((unsigned long) p->base + p->num - 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089 }
1090
Dominik Brodowskicfe5d802010-01-17 19:31:45 +01001091 mutex_unlock(&s->ops_mutex);
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001092 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093}
1094
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001095static ssize_t store_io_db(struct device *dev,
1096 struct device_attribute *attr,
1097 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098{
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001099 struct pcmcia_socket *s = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100 unsigned long start_addr, end_addr;
Dominik Brodowski22916632005-06-27 16:28:46 -07001101 unsigned int add = ADD_MANAGED_RESOURCE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 ssize_t ret = 0;
1103
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001104 ret = sscanf(buf, "+ 0x%lx - 0x%lx", &start_addr, &end_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 if (ret != 2) {
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001106 ret = sscanf(buf, "- 0x%lx - 0x%lx", &start_addr, &end_addr);
Dominik Brodowski22916632005-06-27 16:28:46 -07001107 add = REMOVE_MANAGED_RESOURCE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108 if (ret != 2) {
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001109 ret = sscanf(buf, "0x%lx - 0x%lx", &start_addr,
1110 &end_addr);
Dominik Brodowski22916632005-06-27 16:28:46 -07001111 add = ADD_MANAGED_RESOURCE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 if (ret != 2)
1113 return -EINVAL;
1114 }
1115 }
Dominik Brodowski1146bc72005-09-28 19:28:37 +02001116 if (end_addr < start_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 return -EINVAL;
1118
Dominik Brodowskicfe5d802010-01-17 19:31:45 +01001119 mutex_lock(&s->ops_mutex);
Dominik Brodowski22916632005-06-27 16:28:46 -07001120 ret = adjust_io(s, add, start_addr, end_addr);
Dominik Brodowskicfe5d802010-01-17 19:31:45 +01001121 mutex_unlock(&s->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122
1123 return ret ? ret : count;
1124}
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001125static DEVICE_ATTR(available_resources_io, 0600, show_io_db, store_io_db);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001127static ssize_t show_mem_db(struct device *dev,
1128 struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129{
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001130 struct pcmcia_socket *s = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131 struct socket_data *data;
1132 struct resource_map *p;
1133 ssize_t ret = 0;
1134
Dominik Brodowskicfe5d802010-01-17 19:31:45 +01001135 mutex_lock(&s->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136 data = s->resource_data;
1137
Dominik Brodowski7b4884c2010-02-17 16:25:53 +01001138 for (p = data->mem_db_valid.next; p != &data->mem_db_valid;
1139 p = p->next) {
1140 if (ret > (PAGE_SIZE - 10))
1141 continue;
1142 ret += snprintf(&buf[ret], (PAGE_SIZE - ret - 1),
1143 "0x%08lx - 0x%08lx\n",
1144 ((unsigned long) p->base),
1145 ((unsigned long) p->base + p->num - 1));
1146 }
1147
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148 for (p = data->mem_db.next; p != &data->mem_db; p = p->next) {
1149 if (ret > (PAGE_SIZE - 10))
1150 continue;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001151 ret += snprintf(&buf[ret], (PAGE_SIZE - ret - 1),
1152 "0x%08lx - 0x%08lx\n",
1153 ((unsigned long) p->base),
1154 ((unsigned long) p->base + p->num - 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155 }
1156
Dominik Brodowskicfe5d802010-01-17 19:31:45 +01001157 mutex_unlock(&s->ops_mutex);
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001158 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159}
1160
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001161static ssize_t store_mem_db(struct device *dev,
1162 struct device_attribute *attr,
1163 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164{
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001165 struct pcmcia_socket *s = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 unsigned long start_addr, end_addr;
Dominik Brodowski22916632005-06-27 16:28:46 -07001167 unsigned int add = ADD_MANAGED_RESOURCE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168 ssize_t ret = 0;
1169
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001170 ret = sscanf(buf, "+ 0x%lx - 0x%lx", &start_addr, &end_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171 if (ret != 2) {
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001172 ret = sscanf(buf, "- 0x%lx - 0x%lx", &start_addr, &end_addr);
Dominik Brodowski22916632005-06-27 16:28:46 -07001173 add = REMOVE_MANAGED_RESOURCE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174 if (ret != 2) {
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001175 ret = sscanf(buf, "0x%lx - 0x%lx", &start_addr,
1176 &end_addr);
Dominik Brodowski22916632005-06-27 16:28:46 -07001177 add = ADD_MANAGED_RESOURCE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178 if (ret != 2)
1179 return -EINVAL;
1180 }
1181 }
Dominik Brodowski1146bc72005-09-28 19:28:37 +02001182 if (end_addr < start_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183 return -EINVAL;
1184
Dominik Brodowskicfe5d802010-01-17 19:31:45 +01001185 mutex_lock(&s->ops_mutex);
Dominik Brodowski22916632005-06-27 16:28:46 -07001186 ret = adjust_memory(s, add, start_addr, end_addr);
Dominik Brodowskicfe5d802010-01-17 19:31:45 +01001187 mutex_unlock(&s->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188
1189 return ret ? ret : count;
1190}
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001191static DEVICE_ATTR(available_resources_mem, 0600, show_mem_db, store_mem_db);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192
David Brownell7d578962008-06-12 12:13:55 -07001193static struct attribute *pccard_rsrc_attributes[] = {
1194 &dev_attr_available_resources_io.attr,
1195 &dev_attr_available_resources_mem.attr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196 NULL,
1197};
1198
David Brownell7d578962008-06-12 12:13:55 -07001199static const struct attribute_group rsrc_attributes = {
1200 .attrs = pccard_rsrc_attributes,
1201};
1202
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001203static int __devinit pccard_sysfs_add_rsrc(struct device *dev,
Dmitry Torokhovd8539d82005-09-15 02:01:36 -05001204 struct class_interface *class_intf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205{
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001206 struct pcmcia_socket *s = dev_get_drvdata(dev);
David Brownell7d578962008-06-12 12:13:55 -07001207
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208 if (s->resource_ops != &pccard_nonstatic_ops)
1209 return 0;
David Brownell7d578962008-06-12 12:13:55 -07001210 return sysfs_create_group(&dev->kobj, &rsrc_attributes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211}
1212
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001213static void __devexit pccard_sysfs_remove_rsrc(struct device *dev,
Dmitry Torokhovd8539d82005-09-15 02:01:36 -05001214 struct class_interface *class_intf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215{
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001216 struct pcmcia_socket *s = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217
1218 if (s->resource_ops != &pccard_nonstatic_ops)
1219 return;
David Brownell7d578962008-06-12 12:13:55 -07001220 sysfs_remove_group(&dev->kobj, &rsrc_attributes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221}
1222
Sam Ravnborged49f5d2008-05-01 04:34:50 -07001223static struct class_interface pccard_rsrc_interface __refdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224 .class = &pcmcia_socket_class,
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001225 .add_dev = &pccard_sysfs_add_rsrc,
1226 .remove_dev = __devexit_p(&pccard_sysfs_remove_rsrc),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227};
1228
1229static int __init nonstatic_sysfs_init(void)
1230{
1231 return class_interface_register(&pccard_rsrc_interface);
1232}
1233
1234static void __exit nonstatic_sysfs_exit(void)
1235{
1236 class_interface_unregister(&pccard_rsrc_interface);
1237}
1238
1239module_init(nonstatic_sysfs_init);
1240module_exit(nonstatic_sysfs_exit);