blob: dcd1a4ad3d631b42dc93114e686231e733ff5718 [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
31#include <pcmcia/cs_types.h>
32#include <pcmcia/ss.h>
33#include <pcmcia/cs.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <pcmcia/cistpl.h>
35#include "cs_internal.h"
36
Dominik Brodowski49b11532010-03-07 16:41:57 +010037/* moved to rsrc_mgr.c
Linus Torvalds1da177e2005-04-16 15:20:36 -070038MODULE_AUTHOR("David A. Hinds, Dominik Brodowski");
39MODULE_LICENSE("GPL");
Dominik Brodowski49b11532010-03-07 16:41:57 +010040*/
Linus Torvalds1da177e2005-04-16 15:20:36 -070041
42/* Parameters that can be set with 'insmod' */
43
44#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0444)
45
46INT_MODULE_PARM(probe_mem, 1); /* memory probe? */
47#ifdef CONFIG_PCMCIA_PROBE
48INT_MODULE_PARM(probe_io, 1); /* IO port probe? */
49INT_MODULE_PARM(mem_limit, 0x10000);
50#endif
51
52/* for io_db and mem_db */
53struct resource_map {
54 u_long base, num;
55 struct resource_map *next;
56};
57
58struct socket_data {
59 struct resource_map mem_db;
Dominik Brodowski7b4884c2010-02-17 16:25:53 +010060 struct resource_map mem_db_valid;
Linus Torvalds1da177e2005-04-16 15:20:36 -070061 struct resource_map io_db;
Linus Torvalds1da177e2005-04-16 15:20:36 -070062};
63
Linus Torvalds1da177e2005-04-16 15:20:36 -070064#define MEM_PROBE_LOW (1 << 0)
65#define MEM_PROBE_HIGH (1 << 1)
66
67
68/*======================================================================
69
70 Linux resource management extensions
71
72======================================================================*/
73
74static struct resource *
Greg Kroah-Hartman2427ddd2006-06-12 17:07:52 -070075claim_region(struct pcmcia_socket *s, resource_size_t base,
76 resource_size_t size, int type, char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -070077{
78 struct resource *res, *parent;
79
80 parent = type & IORESOURCE_MEM ? &iomem_resource : &ioport_resource;
Dominik Brodowski49b11532010-03-07 16:41:57 +010081 res = pcmcia_make_resource(base, size, type | IORESOURCE_BUSY, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -070082
83 if (res) {
84#ifdef CONFIG_PCI
85 if (s && s->cb_dev)
86 parent = pci_find_parent_resource(s->cb_dev, res);
87#endif
88 if (!parent || request_resource(parent, res)) {
89 kfree(res);
90 res = NULL;
91 }
92 }
93 return res;
94}
95
96static void free_region(struct resource *res)
97{
98 if (res) {
99 release_resource(res);
100 kfree(res);
101 }
102}
103
104/*======================================================================
105
106 These manage the internal databases of available resources.
107
108======================================================================*/
109
110static int add_interval(struct resource_map *map, u_long base, u_long num)
111{
Dominik Brodowski11683862008-08-03 10:22:47 +0200112 struct resource_map *p, *q;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113
Dominik Brodowski11683862008-08-03 10:22:47 +0200114 for (p = map; ; p = p->next) {
Dominik Brodowskif309cb32010-02-17 14:35:33 +0100115 if ((p != map) && (p->base+p->num >= base)) {
116 p->num = max(num + base - p->base, p->num);
117 return 0;
118 }
Dominik Brodowski11683862008-08-03 10:22:47 +0200119 if ((p->next == map) || (p->next->base > base+num-1))
120 break;
121 }
122 q = kmalloc(sizeof(struct resource_map), GFP_KERNEL);
123 if (!q) {
124 printk(KERN_WARNING "out of memory to update resources\n");
125 return -ENOMEM;
126 }
127 q->base = base; q->num = num;
128 q->next = p->next; p->next = q;
129 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130}
131
132/*====================================================================*/
133
134static int sub_interval(struct resource_map *map, u_long base, u_long num)
135{
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100136 struct resource_map *p, *q;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100138 for (p = map; ; p = q) {
139 q = p->next;
140 if (q == map)
141 break;
142 if ((q->base+q->num > base) && (base+num > q->base)) {
143 if (q->base >= base) {
144 if (q->base+q->num <= base+num) {
145 /* Delete whole block */
146 p->next = q->next;
147 kfree(q);
148 /* don't advance the pointer yet */
149 q = p;
150 } else {
151 /* Cut off bit from the front */
152 q->num = q->base + q->num - base - num;
153 q->base = base + num;
154 }
155 } else if (q->base+q->num <= base+num) {
156 /* Cut off bit from the end */
157 q->num = base - q->base;
158 } else {
159 /* Split the block into two pieces */
160 p = kmalloc(sizeof(struct resource_map),
161 GFP_KERNEL);
162 if (!p) {
163 printk(KERN_WARNING "out of memory to update resources\n");
164 return -ENOMEM;
165 }
166 p->base = base+num;
167 p->num = q->base+q->num - p->base;
168 q->num = base - q->base;
169 p->next = q->next ; q->next = p;
170 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 }
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100173 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174}
175
176/*======================================================================
177
178 These routines examine a region of IO or memory addresses to
179 determine what ranges might be genuinely available.
180
181======================================================================*/
182
183#ifdef CONFIG_PCMCIA_PROBE
Olof Johansson906da802008-02-04 22:27:35 -0800184static void do_io_probe(struct pcmcia_socket *s, unsigned int base,
185 unsigned int num)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186{
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100187 struct resource *res;
188 struct socket_data *s_data = s->resource_data;
189 unsigned int i, j, bad;
190 int any;
191 u_char *b, hole, most;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100193 dev_printk(KERN_INFO, &s->dev, "cs: IO port probe %#x-%#x:",
194 base, base+num-1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100196 /* First, what does a floating port look like? */
197 b = kzalloc(256, GFP_KERNEL);
198 if (!b) {
199 printk("\n");
200 dev_printk(KERN_ERR, &s->dev,
201 "do_io_probe: unable to kmalloc 256 bytes");
202 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203 }
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100204 for (i = base, most = 0; i < base+num; i += 8) {
Dominik Brodowski509b0862010-04-08 19:23:07 +0200205 res = claim_region(s, i, 8, IORESOURCE_IO, "PCMCIA ioprobe");
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100206 if (!res)
207 continue;
208 hole = inb(i);
209 for (j = 1; j < 8; j++)
210 if (inb(i+j) != hole)
211 break;
212 free_region(res);
213 if ((j == 8) && (++b[hole] > b[most]))
214 most = hole;
215 if (b[most] == 127)
216 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217 }
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100218 kfree(b);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100220 bad = any = 0;
221 for (i = base; i < base+num; i += 8) {
Dominik Brodowski509b0862010-04-08 19:23:07 +0200222 res = claim_region(s, i, 8, IORESOURCE_IO, "PCMCIA ioprobe");
223 if (!res) {
224 if (!any)
225 printk(" excluding");
226 if (!bad)
227 bad = any = i;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100228 continue;
Dominik Brodowski509b0862010-04-08 19:23:07 +0200229 }
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100230 for (j = 0; j < 8; j++)
231 if (inb(i+j) != most)
232 break;
233 free_region(res);
234 if (j < 8) {
235 if (!any)
236 printk(" excluding");
237 if (!bad)
238 bad = any = i;
239 } else {
240 if (bad) {
241 sub_interval(&s_data->io_db, bad, i-bad);
242 printk(" %#x-%#x", bad, i-1);
243 bad = 0;
244 }
245 }
246 }
247 if (bad) {
248 if ((num > 16) && (bad == base) && (i == base+num)) {
Dominik Brodowski509b0862010-04-08 19:23:07 +0200249 sub_interval(&s_data->io_db, bad, i-bad);
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100250 printk(" nothing: probe failed.\n");
251 return;
252 } else {
253 sub_interval(&s_data->io_db, bad, i-bad);
254 printk(" %#x-%#x", bad, i-1);
255 }
256 }
257
258 printk(any ? "\n" : " clean.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259}
260#endif
261
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100262/*======================================================================*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100264/**
265 * readable() - iomem validation function for cards with a valid CIS
266 */
Dominik Brodowskic5081d52008-06-19 20:12:34 +0200267static int readable(struct pcmcia_socket *s, struct resource *res,
268 unsigned int *count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269{
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100270 int ret = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271
Dominik Brodowski7ab248552010-02-17 18:00:07 +0100272 if (s->fake_cis) {
273 dev_dbg(&s->dev, "fake CIS is being used: can't validate mem\n");
274 return 0;
275 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276
277 s->cis_mem.res = res;
278 s->cis_virt = ioremap(res->start, s->map_size);
279 if (s->cis_virt) {
Dominik Brodowski6b8e0872010-01-12 21:42:51 +0100280 mutex_unlock(&s->ops_mutex);
Dominik Brodowski6e7b51a2010-01-06 13:57:43 +0100281 /* as we're only called from pcmcia.c, we're safe */
282 if (s->callback->validate)
283 ret = s->callback->validate(s, count);
Dominik Brodowski904e3772010-01-02 12:28:04 +0100284 /* invalidate mapping */
Dominik Brodowski6b8e0872010-01-12 21:42:51 +0100285 mutex_lock(&s->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286 iounmap(s->cis_virt);
287 s->cis_virt = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 }
289 s->cis_mem.res = NULL;
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100290 if ((ret) || (*count == 0))
291 return -EINVAL;
292 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293}
294
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100295/**
296 * checksum() - iomem validation function for simple memory cards
297 */
298static int checksum(struct pcmcia_socket *s, struct resource *res,
299 unsigned int *value)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300{
301 pccard_mem_map map;
302 int i, a = 0, b = -1, d;
303 void __iomem *virt;
304
305 virt = ioremap(res->start, s->map_size);
306 if (virt) {
307 map.map = 0;
308 map.flags = MAP_ACTIVE;
309 map.speed = 0;
310 map.res = res;
311 map.card_start = 0;
312 s->ops->set_mem_map(s, &map);
313
314 /* Don't bother checking every word... */
315 for (i = 0; i < s->map_size; i += 44) {
316 d = readl(virt+i);
317 a += d;
318 b &= d;
319 }
320
321 map.flags = 0;
322 s->ops->set_mem_map(s, &map);
323
324 iounmap(virt);
325 }
326
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100327 if (b == -1)
328 return -EINVAL;
329
330 *value = a;
331
332 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333}
334
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100335/**
336 * do_validate_mem() - low level validate a memory region for PCMCIA use
337 * @s: PCMCIA socket to validate
338 * @base: start address of resource to check
339 * @size: size of resource to check
340 * @validate: validation function to use
341 *
342 * do_validate_mem() splits up the memory region which is to be checked
343 * into two parts. Both are passed to the @validate() function. If
344 * @validate() returns non-zero, or the value parameter to @validate()
345 * is zero, or the value parameter is different between both calls,
346 * the check fails, and -EINVAL is returned. Else, 0 is returned.
347 */
348static int do_validate_mem(struct pcmcia_socket *s,
349 unsigned long base, unsigned long size,
350 int validate (struct pcmcia_socket *s,
351 struct resource *res,
352 unsigned int *value))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353{
Dominik Brodowski7b4884c2010-02-17 16:25:53 +0100354 struct socket_data *s_data = s->resource_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 struct resource *res1, *res2;
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100356 unsigned int info1 = 1, info2 = 1;
357 int ret = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100359 res1 = claim_region(s, base, size/2, IORESOURCE_MEM, "PCMCIA memprobe");
360 res2 = claim_region(s, base + size/2, size/2, IORESOURCE_MEM,
361 "PCMCIA memprobe");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362
363 if (res1 && res2) {
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100364 ret = 0;
365 if (validate) {
366 ret = validate(s, res1, &info1);
367 ret += validate(s, res2, &info2);
368 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 }
370
371 free_region(res2);
372 free_region(res1);
373
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100374 dev_dbg(&s->dev, "cs: memory probe 0x%06lx-0x%06lx: %p %p %u %u %u",
375 base, base+size-1, res1, res2, ret, info1, info2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100377 if ((ret) || (info1 != info2) || (info1 == 0))
378 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379
Dominik Brodowski7b4884c2010-02-17 16:25:53 +0100380 if (validate && !s->fake_cis) {
381 /* move it to the validated data set */
382 add_interval(&s_data->mem_db_valid, base, size);
383 sub_interval(&s_data->mem_db, base, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 }
385
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100386 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387}
388
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100390/**
391 * do_mem_probe() - validate a memory region for PCMCIA use
392 * @s: PCMCIA socket to validate
393 * @base: start address of resource to check
394 * @num: size of resource to check
395 * @validate: validation function to use
396 * @fallback: validation function to use if validate fails
397 *
398 * do_mem_probe() checks a memory region for use by the PCMCIA subsystem.
399 * To do so, the area is split up into sensible parts, and then passed
400 * into the @validate() function. Only if @validate() and @fallback() fail,
401 * the area is marked as unavaibale for use by the PCMCIA subsystem. The
402 * function returns the size of the usable memory area.
403 */
404static int do_mem_probe(struct pcmcia_socket *s, u_long base, u_long num,
405 int validate (struct pcmcia_socket *s,
406 struct resource *res,
407 unsigned int *value),
408 int fallback (struct pcmcia_socket *s,
409 struct resource *res,
410 unsigned int *value))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411{
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100412 struct socket_data *s_data = s->resource_data;
413 u_long i, j, bad, fail, step;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100415 dev_printk(KERN_INFO, &s->dev, "cs: memory probe 0x%06lx-0x%06lx:",
416 base, base+num-1);
417 bad = fail = 0;
418 step = (num < 0x20000) ? 0x2000 : ((num>>4) & ~0x1fff);
419 /* don't allow too large steps */
420 if (step > 0x800000)
421 step = 0x800000;
422 /* cis_readable wants to map 2x map_size */
423 if (step < 2 * s->map_size)
424 step = 2 * s->map_size;
425 for (i = j = base; i < base+num; i = j + step) {
426 if (!fail) {
427 for (j = i; j < base+num; j += step) {
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100428 if (!do_validate_mem(s, j, step, validate))
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100429 break;
430 }
431 fail = ((i == base) && (j == base+num));
432 }
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100433 if ((fail) && (fallback)) {
434 for (j = i; j < base+num; j += step)
435 if (!do_validate_mem(s, j, step, fallback))
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100436 break;
437 }
438 if (i != j) {
439 if (!bad)
440 printk(" excluding");
441 printk(" %#05lx-%#05lx", i, j-1);
442 sub_interval(&s_data->mem_db, i, j-i);
443 bad += j-i;
444 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 }
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100446 printk(bad ? "\n" : " clean.\n");
447 return num - bad;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448}
449
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100450
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451#ifdef CONFIG_PCMCIA_PROBE
452
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100453/**
454 * inv_probe() - top-to-bottom search for one usuable high memory area
455 * @s: PCMCIA socket to validate
456 * @m: resource_map to check
457 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458static u_long inv_probe(struct resource_map *m, struct pcmcia_socket *s)
459{
Dominik Brodowskide759142005-09-28 19:41:56 +0200460 struct socket_data *s_data = s->resource_data;
461 u_long ok;
462 if (m == &s_data->mem_db)
463 return 0;
464 ok = inv_probe(m->next, s);
465 if (ok) {
466 if (m->base >= 0x100000)
467 sub_interval(&s_data->mem_db, m->base, m->num);
468 return ok;
469 }
470 if (m->base < 0x100000)
471 return 0;
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100472 return do_mem_probe(s, m->base, m->num, readable, checksum);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473}
474
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100475/**
476 * validate_mem() - memory probe function
477 * @s: PCMCIA socket to validate
478 * @probe_mask: MEM_PROBE_LOW | MEM_PROBE_HIGH
479 *
480 * The memory probe. If the memory list includes a 64K-aligned block
481 * below 1MB, we probe in 64K chunks, and as soon as we accumulate at
482 * least mem_limit free space, we quit. Returns 0 on usuable ports.
483 */
Dominik Brodowskide759142005-09-28 19:41:56 +0200484static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485{
Dominik Brodowskide759142005-09-28 19:41:56 +0200486 struct resource_map *m, mm;
487 static unsigned char order[] = { 0xd0, 0xe0, 0xc0, 0xf0 };
488 unsigned long b, i, ok = 0;
489 struct socket_data *s_data = s->resource_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490
Dominik Brodowskide759142005-09-28 19:41:56 +0200491 /* We do up to four passes through the list */
492 if (probe_mask & MEM_PROBE_HIGH) {
493 if (inv_probe(s_data->mem_db.next, s) > 0)
494 return 0;
Dominik Brodowski7b4884c2010-02-17 16:25:53 +0100495 if (s_data->mem_db_valid.next != &s_data->mem_db_valid)
496 return 0;
Dominik Brodowskidbe4ea52008-08-02 21:36:19 +0200497 dev_printk(KERN_NOTICE, &s->dev,
498 "cs: warning: no high memory space available!\n");
Dominik Brodowskide759142005-09-28 19:41:56 +0200499 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 }
Dominik Brodowskide759142005-09-28 19:41:56 +0200501
502 for (m = s_data->mem_db.next; m != &s_data->mem_db; m = mm.next) {
503 mm = *m;
504 /* Only probe < 1 MB */
505 if (mm.base >= 0x100000)
506 continue;
507 if ((mm.base | mm.num) & 0xffff) {
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100508 ok += do_mem_probe(s, mm.base, mm.num, readable,
509 checksum);
Dominik Brodowskide759142005-09-28 19:41:56 +0200510 continue;
511 }
512 /* Special probe for 64K-aligned block */
513 for (i = 0; i < 4; i++) {
514 b = order[i] << 12;
515 if ((b >= mm.base) && (b+0x10000 <= mm.base+mm.num)) {
516 if (ok >= mem_limit)
517 sub_interval(&s_data->mem_db, b, 0x10000);
518 else
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100519 ok += do_mem_probe(s, b, 0x10000,
520 readable, checksum);
Dominik Brodowskide759142005-09-28 19:41:56 +0200521 }
522 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 }
Dominik Brodowskide759142005-09-28 19:41:56 +0200524
525 if (ok > 0)
526 return 0;
527
528 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529}
530
531#else /* CONFIG_PCMCIA_PROBE */
532
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100533/**
534 * validate_mem() - memory probe function
535 * @s: PCMCIA socket to validate
536 * @probe_mask: ignored
537 *
538 * Returns 0 on usuable ports.
539 */
Andrew Morton2cff9442005-11-16 21:29:26 -0800540static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541{
542 struct resource_map *m, mm;
543 struct socket_data *s_data = s->resource_data;
Andrew Morton2cff9442005-11-16 21:29:26 -0800544 unsigned long ok = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545
546 for (m = s_data->mem_db.next; m != &s_data->mem_db; m = mm.next) {
547 mm = *m;
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100548 ok += do_mem_probe(s, mm.base, mm.num, readable, checksum);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 }
Andrew Morton2cff9442005-11-16 21:29:26 -0800550 if (ok > 0)
551 return 0;
552 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553}
554
555#endif /* CONFIG_PCMCIA_PROBE */
556
557
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100558/**
559 * pcmcia_nonstatic_validate_mem() - try to validate iomem for PCMCIA use
560 * @s: PCMCIA socket to validate
561 *
562 * This is tricky... when we set up CIS memory, we try to validate
563 * the memory window space allocations.
564 *
Dominik Brodowski7fe908d2006-01-10 21:20:36 +0100565 * Locking note: Must be called with skt_mutex held!
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 */
Dominik Brodowskide759142005-09-28 19:41:56 +0200567static int pcmcia_nonstatic_validate_mem(struct pcmcia_socket *s)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568{
569 struct socket_data *s_data = s->resource_data;
Dominik Brodowskide759142005-09-28 19:41:56 +0200570 unsigned int probe_mask = MEM_PROBE_LOW;
Dominik Brodowski7b4884c2010-02-17 16:25:53 +0100571 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572
Dominik Brodowski7b4884c2010-02-17 16:25:53 +0100573 if (!probe_mem || !(s->state & SOCKET_PRESENT))
Dominik Brodowskide759142005-09-28 19:41:56 +0200574 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575
Dominik Brodowskide759142005-09-28 19:41:56 +0200576 if (s->features & SS_CAP_PAGE_REGS)
577 probe_mask = MEM_PROBE_HIGH;
578
Dominik Brodowski7b4884c2010-02-17 16:25:53 +0100579 ret = validate_mem(s, probe_mask);
Dominik Brodowskide759142005-09-28 19:41:56 +0200580
Dominik Brodowski7b4884c2010-02-17 16:25:53 +0100581 if (s_data->mem_db_valid.next != &s_data->mem_db_valid)
582 return 0;
Dominik Brodowskide759142005-09-28 19:41:56 +0200583
584 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585}
586
587struct pcmcia_align_data {
588 unsigned long mask;
589 unsigned long offset;
590 struct resource_map *map;
591};
592
Dominik Brodowski147a2742010-04-04 18:10:35 +0200593static resource_size_t pcmcia_common_align(struct pcmcia_align_data *align_data,
594 resource_size_t start)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595{
Dominik Brodowski147a2742010-04-04 18:10:35 +0200596 resource_size_t ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 /*
598 * Ensure that we have the correct start address
599 */
Dominik Brodowski147a2742010-04-04 18:10:35 +0200600 ret = (start & ~align_data->mask) + align_data->offset;
601 if (ret < start)
602 ret += align_data->mask + 1;
603 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604}
605
Dominik Brodowskib26b2d42010-01-01 17:40:49 +0100606static resource_size_t
Dominik Brodowski3b7a17f2010-01-01 17:40:50 +0100607pcmcia_align(void *align_data, const struct resource *res,
608 resource_size_t size, resource_size_t align)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609{
610 struct pcmcia_align_data *data = align_data;
611 struct resource_map *m;
Dominik Brodowskib26b2d42010-01-01 17:40:49 +0100612 resource_size_t start;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613
Dominik Brodowski147a2742010-04-04 18:10:35 +0200614 start = pcmcia_common_align(data, res->start);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615
616 for (m = data->map->next; m != data->map; m = m->next) {
Dominik Brodowski147a2742010-04-04 18:10:35 +0200617 unsigned long map_start = m->base;
618 unsigned long map_end = m->base + m->num - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619
620 /*
621 * If the lower resources are not available, try aligning
622 * to this entry of the resource database to see if it'll
623 * fit here.
624 */
Dominik Brodowski147a2742010-04-04 18:10:35 +0200625 if (start < map_start)
626 start = pcmcia_common_align(data, map_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627
628 /*
629 * If we're above the area which was passed in, there's
630 * no point proceeding.
631 */
Dominik Brodowski147a2742010-04-04 18:10:35 +0200632 if (start >= res->end)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 break;
634
Dominik Brodowski147a2742010-04-04 18:10:35 +0200635 if ((start + size - 1) <= map_end)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 break;
637 }
638
639 /*
640 * If we failed to find something suitable, ensure we fail.
641 */
642 if (m == data->map)
Dominik Brodowskib26b2d42010-01-01 17:40:49 +0100643 start = res->end;
644
645 return start;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646}
647
648/*
649 * Adjust an existing IO region allocation, but making sure that we don't
650 * encroach outside the resources which the user supplied.
651 */
Dominik Brodowskib19a7272010-03-20 13:10:47 +0100652static int __nonstatic_adjust_io_region(struct pcmcia_socket *s,
653 unsigned long r_start,
654 unsigned long r_end)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655{
656 struct resource_map *m;
657 struct socket_data *s_data = s->resource_data;
658 int ret = -ENOMEM;
659
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 for (m = s_data->io_db.next; m != &s_data->io_db; m = m->next) {
661 unsigned long start = m->base;
662 unsigned long end = m->base + m->num - 1;
663
664 if (start > r_start || r_end > end)
665 continue;
666
Dominik Brodowskib19a7272010-03-20 13:10:47 +0100667 ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669
670 return ret;
671}
672
673/*======================================================================
674
675 These find ranges of I/O ports or memory addresses that are not
676 currently allocated by other devices.
677
678 The 'align' field should reflect the number of bits of address
679 that need to be preserved from the initial value of *base. It
680 should be a power of two, greater than or equal to 'num'. A value
681 of 0 means that all bits of *base are significant. *base should
682 also be strictly less than 'align'.
683
684======================================================================*/
685
Dominik Brodowskib19a7272010-03-20 13:10:47 +0100686static struct resource *__nonstatic_find_io_region(struct pcmcia_socket *s,
687 unsigned long base, int num,
688 unsigned long align)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689{
Dominik Brodowski49b11532010-03-07 16:41:57 +0100690 struct resource *res = pcmcia_make_resource(0, num, IORESOURCE_IO,
691 dev_name(&s->dev));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 struct socket_data *s_data = s->resource_data;
693 struct pcmcia_align_data data;
694 unsigned long min = base;
695 int ret;
696
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 data.mask = align - 1;
698 data.offset = base & data.mask;
699 data.map = &s_data->io_db;
700
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701#ifdef CONFIG_PCI
702 if (s->cb_dev) {
703 ret = pci_bus_alloc_resource(s->cb_dev->bus, res, num, 1,
704 min, 0, pcmcia_align, &data);
705 } else
706#endif
707 ret = allocate_resource(&ioport_resource, res, num, min, ~0UL,
708 1, pcmcia_align, &data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709
710 if (ret != 0) {
711 kfree(res);
712 res = NULL;
713 }
714 return res;
715}
716
Dominik Brodowskib19a7272010-03-20 13:10:47 +0100717static int nonstatic_find_io(struct pcmcia_socket *s, unsigned int attr,
718 unsigned int *base, unsigned int num,
719 unsigned int align)
720{
721 int i, ret = 0;
722
723 /* Check for an already-allocated window that must conflict with
724 * what was asked for. It is a hack because it does not catch all
725 * potential conflicts, just the most obvious ones.
726 */
727 for (i = 0; i < MAX_IO_WIN; i++) {
728 if (!s->io[i].res)
729 continue;
730
731 if (!*base)
732 continue;
733
734 if ((s->io[i].res->start & (align-1)) == *base)
735 return -EBUSY;
736 }
737
738 for (i = 0; i < MAX_IO_WIN; i++) {
739 struct resource *res = s->io[i].res;
740 unsigned int try;
741
742 if (res && (res->flags & IORESOURCE_BITS) !=
743 (attr & IORESOURCE_BITS))
744 continue;
745
746 if (!res) {
747 if (align == 0)
748 align = 0x10000;
749
750 res = s->io[i].res = __nonstatic_find_io_region(s,
751 *base, num,
752 align);
753 if (!res)
754 return -EINVAL;
755
756 *base = res->start;
757 s->io[i].res->flags =
758 ((res->flags & ~IORESOURCE_BITS) |
759 (attr & IORESOURCE_BITS));
760 s->io[i].InUse = num;
761 return 0;
762 }
763
764 /* Try to extend top of window */
765 try = res->end + 1;
766 if ((*base == 0) || (*base == try)) {
767 ret = __nonstatic_adjust_io_region(s, res->start,
768 res->end + num);
769 if (!ret) {
770 ret = adjust_resource(s->io[i].res, res->start,
771 res->end - res->start + num + 1);
772 if (ret)
773 continue;
774 *base = try;
775 s->io[i].InUse += num;
776 return 0;
777 }
778 }
779
780 /* Try to extend bottom of window */
781 try = res->start - num;
782 if ((*base == 0) || (*base == try)) {
783 ret = __nonstatic_adjust_io_region(s,
784 res->start - num,
785 res->end);
786 if (!ret) {
787 ret = adjust_resource(s->io[i].res,
788 res->start - num,
789 res->end - res->start + num + 1);
790 if (ret)
791 continue;
792 *base = try;
793 s->io[i].InUse += num;
794 return 0;
795 }
796 }
797 }
798
799 return -EINVAL;
800}
801
802
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100803static struct resource *nonstatic_find_mem_region(u_long base, u_long num,
Dominik Brodowskie94e15f2005-06-27 16:28:15 -0700804 u_long align, int low, struct pcmcia_socket *s)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805{
Dominik Brodowski49b11532010-03-07 16:41:57 +0100806 struct resource *res = pcmcia_make_resource(0, num, IORESOURCE_MEM,
807 dev_name(&s->dev));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 struct socket_data *s_data = s->resource_data;
809 struct pcmcia_align_data data;
810 unsigned long min, max;
Dominik Brodowski7b4884c2010-02-17 16:25:53 +0100811 int ret, i, j;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812
813 low = low || !(s->features & SS_CAP_PAGE_REGS);
814
815 data.mask = align - 1;
816 data.offset = base & data.mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817
818 for (i = 0; i < 2; i++) {
Dominik Brodowski7b4884c2010-02-17 16:25:53 +0100819 data.map = &s_data->mem_db_valid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 if (low) {
821 max = 0x100000UL;
822 min = base < max ? base : 0;
823 } else {
824 max = ~0UL;
825 min = 0x100000UL + base;
826 }
827
Dominik Brodowski7b4884c2010-02-17 16:25:53 +0100828 for (j = 0; j < 2; j++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829#ifdef CONFIG_PCI
Dominik Brodowski7b4884c2010-02-17 16:25:53 +0100830 if (s->cb_dev) {
831 ret = pci_bus_alloc_resource(s->cb_dev->bus,
832 res, num, 1, min, 0,
833 pcmcia_align, &data);
834 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835#endif
Dominik Brodowski7b4884c2010-02-17 16:25:53 +0100836 {
837 ret = allocate_resource(&iomem_resource,
838 res, num, min, max, 1,
839 pcmcia_align, &data);
840 }
841 if (ret == 0)
842 break;
843 data.map = &s_data->mem_db;
844 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 if (ret == 0 || low)
846 break;
847 low = 1;
848 }
849
850 if (ret != 0) {
851 kfree(res);
852 res = NULL;
853 }
854 return res;
855}
856
857
Dominik Brodowski22916632005-06-27 16:28:46 -0700858static int adjust_memory(struct pcmcia_socket *s, unsigned int action, unsigned long start, unsigned long end)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 struct socket_data *data = s->resource_data;
Dominik Brodowski22916632005-06-27 16:28:46 -0700861 unsigned long size = end - start + 1;
862 int ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863
Dominik Brodowski1146bc72005-09-28 19:28:37 +0200864 if (end < start)
Dominik Brodowski22916632005-06-27 16:28:46 -0700865 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866
Dominik Brodowski22916632005-06-27 16:28:46 -0700867 switch (action) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 case ADD_MANAGED_RESOURCE:
Dominik Brodowski22916632005-06-27 16:28:46 -0700869 ret = add_interval(&data->mem_db, start, size);
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100870 if (!ret)
871 do_mem_probe(s, start, size, NULL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872 break;
873 case REMOVE_MANAGED_RESOURCE:
Dominik Brodowski22916632005-06-27 16:28:46 -0700874 ret = sub_interval(&data->mem_db, start, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 break;
876 default:
Dominik Brodowski22916632005-06-27 16:28:46 -0700877 ret = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879
880 return ret;
881}
882
883
Dominik Brodowski22916632005-06-27 16:28:46 -0700884static int adjust_io(struct pcmcia_socket *s, unsigned int action, unsigned long start, unsigned long end)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885{
886 struct socket_data *data = s->resource_data;
Dominik Brodowski41b97ab2010-04-15 19:01:53 +0200887 unsigned long size;
Dominik Brodowski22916632005-06-27 16:28:46 -0700888 int ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889
Dominik Brodowski9713ab22010-03-23 16:05:00 +0100890#if defined(CONFIG_X86)
891 /* on x86, avoid anything < 0x100 for it is often used for
892 * legacy platform devices */
893 if (start < 0x100)
894 start = 0x100;
895#endif
896
Dominik Brodowski41b97ab2010-04-15 19:01:53 +0200897 size = end - start + 1;
898
Dominik Brodowski1146bc72005-09-28 19:28:37 +0200899 if (end < start)
Dominik Brodowski22916632005-06-27 16:28:46 -0700900 return -EINVAL;
901
902 if (end > IO_SPACE_LIMIT)
903 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904
Dominik Brodowski22916632005-06-27 16:28:46 -0700905 switch (action) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 case ADD_MANAGED_RESOURCE:
Dominik Brodowski22916632005-06-27 16:28:46 -0700907 if (add_interval(&data->io_db, start, size) != 0) {
908 ret = -EBUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 break;
910 }
911#ifdef CONFIG_PCMCIA_PROBE
912 if (probe_io)
Dominik Brodowski22916632005-06-27 16:28:46 -0700913 do_io_probe(s, start, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914#endif
915 break;
916 case REMOVE_MANAGED_RESOURCE:
Dominik Brodowski22916632005-06-27 16:28:46 -0700917 sub_interval(&data->io_db, start, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 break;
919 default:
Dominik Brodowski22916632005-06-27 16:28:46 -0700920 ret = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921 break;
922 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923
924 return ret;
925}
926
927
Dominik Brodowski3c299762005-06-27 16:28:46 -0700928#ifdef CONFIG_PCI
929static int nonstatic_autoadd_resources(struct pcmcia_socket *s)
930{
931 struct resource *res;
932 int i, done = 0;
933
934 if (!s->cb_dev || !s->cb_dev->bus)
935 return -ENODEV;
936
Brian Gerst0d078f62005-10-30 14:59:20 -0800937#if defined(CONFIG_X86)
Dominik Brodowskicf26e8d2010-03-29 21:40:35 +0200938 /* If this is the root bus, the risk of hitting some strange
939 * system devices is too high: If a driver isn't loaded, the
940 * resources are not claimed; even if a driver is loaded, it
941 * may not request all resources or even the wrong one. We
942 * can neither trust the rest of the kernel nor ACPI/PNP and
943 * CRS parsing to get it right. Therefore, use several
944 * safeguards:
945 *
946 * - Do not auto-add resources if the CardBus bridge is on
947 * the PCI root bus
948 *
949 * - Avoid any I/O ports < 0x100.
950 *
951 * - On PCI-PCI bridges, only use resources which are set up
952 * exclusively for the secondary PCI bus: the risk of hitting
953 * system devices is quite low, as they usually aren't
954 * connected to the secondary PCI bus.
Dominik Brodowskib6d00f02005-06-27 16:29:02 -0700955 */
956 if (s->cb_dev->bus->number == 0)
957 return -EINVAL;
Dominik Brodowskib6d00f02005-06-27 16:29:02 -0700958
Dominik Brodowskicf26e8d2010-03-29 21:40:35 +0200959 for (i = 0; i < PCI_BRIDGE_RESOURCE_NUM; i++) {
960 res = s->cb_dev->bus->resource[i];
961#else
Bjorn Helgaas89a74ec2010-02-23 10:24:31 -0700962 pci_bus_for_each_resource(s->cb_dev->bus, res, i) {
Dominik Brodowskicf26e8d2010-03-29 21:40:35 +0200963#endif
Dominik Brodowski3c299762005-06-27 16:28:46 -0700964 if (!res)
965 continue;
966
967 if (res->flags & IORESOURCE_IO) {
Dominik Brodowskicf26e8d2010-03-29 21:40:35 +0200968 /* safeguard against the root resource, where the
969 * risk of hitting any other device would be too
970 * high */
Dominik Brodowski3c299762005-06-27 16:28:46 -0700971 if (res == &ioport_resource)
972 continue;
Dominik Brodowskicf26e8d2010-03-29 21:40:35 +0200973
Dominik Brodowskidbe4ea52008-08-02 21:36:19 +0200974 dev_printk(KERN_INFO, &s->cb_dev->dev,
Bjorn Helgaase1944c62010-03-16 15:53:08 -0600975 "pcmcia: parent PCI bridge window: %pR\n",
976 res);
Dominik Brodowski3c299762005-06-27 16:28:46 -0700977 if (!adjust_io(s, ADD_MANAGED_RESOURCE, res->start, res->end))
978 done |= IORESOURCE_IO;
979
980 }
981
982 if (res->flags & IORESOURCE_MEM) {
Dominik Brodowskicf26e8d2010-03-29 21:40:35 +0200983 /* safeguard against the root resource, where the
984 * risk of hitting any other device would be too
985 * high */
Dominik Brodowski3c299762005-06-27 16:28:46 -0700986 if (res == &iomem_resource)
987 continue;
Dominik Brodowskicf26e8d2010-03-29 21:40:35 +0200988
Dominik Brodowskidbe4ea52008-08-02 21:36:19 +0200989 dev_printk(KERN_INFO, &s->cb_dev->dev,
Bjorn Helgaase1944c62010-03-16 15:53:08 -0600990 "pcmcia: parent PCI bridge window: %pR\n",
991 res);
Dominik Brodowski3c299762005-06-27 16:28:46 -0700992 if (!adjust_memory(s, ADD_MANAGED_RESOURCE, res->start, res->end))
993 done |= IORESOURCE_MEM;
994 }
995 }
996
997 /* if we got at least one of IO, and one of MEM, we can be glad and
998 * activate the PCMCIA subsystem */
Dominik Brodowski54bb5672005-09-28 19:29:59 +0200999 if (done == (IORESOURCE_MEM | IORESOURCE_IO))
Dominik Brodowski3c299762005-06-27 16:28:46 -07001000 s->resource_setup_done = 1;
1001
1002 return 0;
1003}
1004
1005#else
1006
1007static inline int nonstatic_autoadd_resources(struct pcmcia_socket *s)
1008{
1009 return -ENODEV;
1010}
1011
1012#endif
1013
1014
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015static int nonstatic_init(struct pcmcia_socket *s)
1016{
1017 struct socket_data *data;
1018
Dominik Brodowski8084b372005-12-11 21:18:26 +01001019 data = kzalloc(sizeof(struct socket_data), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 if (!data)
1021 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022
1023 data->mem_db.next = &data->mem_db;
Dominik Brodowski7b4884c2010-02-17 16:25:53 +01001024 data->mem_db_valid.next = &data->mem_db_valid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 data->io_db.next = &data->io_db;
1026
1027 s->resource_data = (void *) data;
1028
Dominik Brodowski3c299762005-06-27 16:28:46 -07001029 nonstatic_autoadd_resources(s);
1030
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031 return 0;
1032}
1033
1034static void nonstatic_release_resource_db(struct pcmcia_socket *s)
1035{
1036 struct socket_data *data = s->resource_data;
1037 struct resource_map *p, *q;
1038
Dominik Brodowski7b4884c2010-02-17 16:25:53 +01001039 for (p = data->mem_db_valid.next; p != &data->mem_db_valid; p = q) {
1040 q = p->next;
1041 kfree(p);
1042 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043 for (p = data->mem_db.next; p != &data->mem_db; p = q) {
1044 q = p->next;
1045 kfree(p);
1046 }
1047 for (p = data->io_db.next; p != &data->io_db; p = q) {
1048 q = p->next;
1049 kfree(p);
1050 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051}
1052
1053
1054struct pccard_resource_ops pccard_nonstatic_ops = {
1055 .validate_mem = pcmcia_nonstatic_validate_mem,
Dominik Brodowskib19a7272010-03-20 13:10:47 +01001056 .find_io = nonstatic_find_io,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057 .find_mem = nonstatic_find_mem_region,
Dominik Brodowskic5023802008-06-19 19:02:52 +02001058 .add_io = adjust_io,
1059 .add_mem = adjust_memory,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060 .init = nonstatic_init,
1061 .exit = nonstatic_release_resource_db,
1062};
1063EXPORT_SYMBOL(pccard_nonstatic_ops);
1064
1065
1066/* sysfs interface to the resource database */
1067
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001068static ssize_t show_io_db(struct device *dev,
1069 struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070{
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001071 struct pcmcia_socket *s = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072 struct socket_data *data;
1073 struct resource_map *p;
1074 ssize_t ret = 0;
1075
Dominik Brodowskicfe5d802010-01-17 19:31:45 +01001076 mutex_lock(&s->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077 data = s->resource_data;
1078
1079 for (p = data->io_db.next; p != &data->io_db; p = p->next) {
1080 if (ret > (PAGE_SIZE - 10))
1081 continue;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001082 ret += snprintf(&buf[ret], (PAGE_SIZE - ret - 1),
1083 "0x%08lx - 0x%08lx\n",
1084 ((unsigned long) p->base),
1085 ((unsigned long) p->base + p->num - 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086 }
1087
Dominik Brodowskicfe5d802010-01-17 19:31:45 +01001088 mutex_unlock(&s->ops_mutex);
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001089 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090}
1091
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001092static ssize_t store_io_db(struct device *dev,
1093 struct device_attribute *attr,
1094 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095{
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001096 struct pcmcia_socket *s = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097 unsigned long start_addr, end_addr;
Dominik Brodowski22916632005-06-27 16:28:46 -07001098 unsigned int add = ADD_MANAGED_RESOURCE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 ssize_t ret = 0;
1100
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001101 ret = sscanf(buf, "+ 0x%lx - 0x%lx", &start_addr, &end_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 if (ret != 2) {
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001103 ret = sscanf(buf, "- 0x%lx - 0x%lx", &start_addr, &end_addr);
Dominik Brodowski22916632005-06-27 16:28:46 -07001104 add = REMOVE_MANAGED_RESOURCE;
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,
1107 &end_addr);
Dominik Brodowski22916632005-06-27 16:28:46 -07001108 add = ADD_MANAGED_RESOURCE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109 if (ret != 2)
1110 return -EINVAL;
1111 }
1112 }
Dominik Brodowski1146bc72005-09-28 19:28:37 +02001113 if (end_addr < start_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 return -EINVAL;
1115
Dominik Brodowskicfe5d802010-01-17 19:31:45 +01001116 mutex_lock(&s->ops_mutex);
Dominik Brodowski22916632005-06-27 16:28:46 -07001117 ret = adjust_io(s, add, start_addr, end_addr);
Dominik Brodowski3c299762005-06-27 16:28:46 -07001118 if (!ret)
1119 s->resource_setup_new = 1;
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 Brodowski3c299762005-06-27 16:28:46 -07001186 if (!ret)
1187 s->resource_setup_new = 1;
Dominik Brodowskicfe5d802010-01-17 19:31:45 +01001188 mutex_unlock(&s->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189
1190 return ret ? ret : count;
1191}
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001192static DEVICE_ATTR(available_resources_mem, 0600, show_mem_db, store_mem_db);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193
David Brownell7d578962008-06-12 12:13:55 -07001194static struct attribute *pccard_rsrc_attributes[] = {
1195 &dev_attr_available_resources_io.attr,
1196 &dev_attr_available_resources_mem.attr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197 NULL,
1198};
1199
David Brownell7d578962008-06-12 12:13:55 -07001200static const struct attribute_group rsrc_attributes = {
1201 .attrs = pccard_rsrc_attributes,
1202};
1203
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001204static int __devinit pccard_sysfs_add_rsrc(struct device *dev,
Dmitry Torokhovd8539d82005-09-15 02:01:36 -05001205 struct class_interface *class_intf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206{
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001207 struct pcmcia_socket *s = dev_get_drvdata(dev);
David Brownell7d578962008-06-12 12:13:55 -07001208
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209 if (s->resource_ops != &pccard_nonstatic_ops)
1210 return 0;
David Brownell7d578962008-06-12 12:13:55 -07001211 return sysfs_create_group(&dev->kobj, &rsrc_attributes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212}
1213
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001214static void __devexit pccard_sysfs_remove_rsrc(struct device *dev,
Dmitry Torokhovd8539d82005-09-15 02:01:36 -05001215 struct class_interface *class_intf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216{
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001217 struct pcmcia_socket *s = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218
1219 if (s->resource_ops != &pccard_nonstatic_ops)
1220 return;
David Brownell7d578962008-06-12 12:13:55 -07001221 sysfs_remove_group(&dev->kobj, &rsrc_attributes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222}
1223
Sam Ravnborged49f5d2008-05-01 04:34:50 -07001224static struct class_interface pccard_rsrc_interface __refdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225 .class = &pcmcia_socket_class,
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001226 .add_dev = &pccard_sysfs_add_rsrc,
1227 .remove_dev = __devexit_p(&pccard_sysfs_remove_rsrc),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228};
1229
1230static int __init nonstatic_sysfs_init(void)
1231{
1232 return class_interface_register(&pccard_rsrc_interface);
1233}
1234
1235static void __exit nonstatic_sysfs_exit(void)
1236{
1237 class_interface_unregister(&pccard_rsrc_interface);
1238}
1239
1240module_init(nonstatic_sysfs_init);
1241module_exit(nonstatic_sysfs_exit);