blob: 5ef7b46a25786b30f214dfc5a2e93cbc07f79eea [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * rsrc_nonstatic.c -- Resource management routines for !SS_CAP_STATIC_MAP sockets
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * The initial developer of the original code is David A. Hinds
9 * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
10 * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
11 *
12 * (C) 1999 David A. Hinds
13 */
14
Linus Torvalds1da177e2005-04-16 15:20:36 -070015#include <linux/module.h>
16#include <linux/moduleparam.h>
17#include <linux/init.h>
18#include <linux/interrupt.h>
19#include <linux/kernel.h>
20#include <linux/errno.h>
21#include <linux/types.h>
22#include <linux/slab.h>
23#include <linux/ioport.h>
24#include <linux/timer.h>
25#include <linux/pci.h>
26#include <linux/device.h>
Dominik Brodowski9fea84f2009-12-07 22:11:45 +010027#include <linux/io.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070028
29#include <asm/irq.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070030
Linus Torvalds1da177e2005-04-16 15:20:36 -070031#include <pcmcia/ss.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include <pcmcia/cistpl.h>
33#include "cs_internal.h"
34
Dominik Brodowski49b11532010-03-07 16:41:57 +010035/* moved to rsrc_mgr.c
Linus Torvalds1da177e2005-04-16 15:20:36 -070036MODULE_AUTHOR("David A. Hinds, Dominik Brodowski");
37MODULE_LICENSE("GPL");
Dominik Brodowski49b11532010-03-07 16:41:57 +010038*/
Linus Torvalds1da177e2005-04-16 15:20:36 -070039
40/* Parameters that can be set with 'insmod' */
41
42#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0444)
43
44INT_MODULE_PARM(probe_mem, 1); /* memory probe? */
45#ifdef CONFIG_PCMCIA_PROBE
46INT_MODULE_PARM(probe_io, 1); /* IO port probe? */
47INT_MODULE_PARM(mem_limit, 0x10000);
48#endif
49
50/* for io_db and mem_db */
51struct resource_map {
52 u_long base, num;
53 struct resource_map *next;
54};
55
56struct socket_data {
57 struct resource_map mem_db;
Dominik Brodowski7b4884c2010-02-17 16:25:53 +010058 struct resource_map mem_db_valid;
Linus Torvalds1da177e2005-04-16 15:20:36 -070059 struct resource_map io_db;
Linus Torvalds1da177e2005-04-16 15:20:36 -070060};
61
Linus Torvalds1da177e2005-04-16 15:20:36 -070062#define MEM_PROBE_LOW (1 << 0)
63#define MEM_PROBE_HIGH (1 << 1)
64
Dominik Brodowski3dace8c2010-07-24 12:33:29 +020065/* Action field */
66#define REMOVE_MANAGED_RESOURCE 1
67#define ADD_MANAGED_RESOURCE 2
Linus Torvalds1da177e2005-04-16 15:20:36 -070068
69/*======================================================================
70
71 Linux resource management extensions
72
73======================================================================*/
74
75static struct resource *
Greg Kroah-Hartman2427ddd2006-06-12 17:07:52 -070076claim_region(struct pcmcia_socket *s, resource_size_t base,
77 resource_size_t size, int type, char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -070078{
79 struct resource *res, *parent;
80
81 parent = type & IORESOURCE_MEM ? &iomem_resource : &ioport_resource;
Dominik Brodowski49b11532010-03-07 16:41:57 +010082 res = pcmcia_make_resource(base, size, type | IORESOURCE_BUSY, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -070083
84 if (res) {
85#ifdef CONFIG_PCI
86 if (s && s->cb_dev)
87 parent = pci_find_parent_resource(s->cb_dev, res);
88#endif
89 if (!parent || request_resource(parent, res)) {
90 kfree(res);
91 res = NULL;
92 }
93 }
94 return res;
95}
96
97static void free_region(struct resource *res)
98{
99 if (res) {
100 release_resource(res);
101 kfree(res);
102 }
103}
104
105/*======================================================================
106
107 These manage the internal databases of available resources.
108
109======================================================================*/
110
111static int add_interval(struct resource_map *map, u_long base, u_long num)
112{
Dominik Brodowski11683862008-08-03 10:22:47 +0200113 struct resource_map *p, *q;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114
Dominik Brodowski11683862008-08-03 10:22:47 +0200115 for (p = map; ; p = p->next) {
Dominik Brodowskif309cb32010-02-17 14:35:33 +0100116 if ((p != map) && (p->base+p->num >= base)) {
117 p->num = max(num + base - p->base, p->num);
118 return 0;
119 }
Dominik Brodowski11683862008-08-03 10:22:47 +0200120 if ((p->next == map) || (p->next->base > base+num-1))
121 break;
122 }
123 q = kmalloc(sizeof(struct resource_map), GFP_KERNEL);
124 if (!q) {
125 printk(KERN_WARNING "out of memory to update resources\n");
126 return -ENOMEM;
127 }
128 q->base = base; q->num = num;
129 q->next = p->next; p->next = q;
130 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131}
132
133/*====================================================================*/
134
135static int sub_interval(struct resource_map *map, u_long base, u_long num)
136{
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100137 struct resource_map *p, *q;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100139 for (p = map; ; p = q) {
140 q = p->next;
141 if (q == map)
142 break;
143 if ((q->base+q->num > base) && (base+num > q->base)) {
144 if (q->base >= base) {
145 if (q->base+q->num <= base+num) {
146 /* Delete whole block */
147 p->next = q->next;
148 kfree(q);
149 /* don't advance the pointer yet */
150 q = p;
151 } else {
152 /* Cut off bit from the front */
153 q->num = q->base + q->num - base - num;
154 q->base = base + num;
155 }
156 } else if (q->base+q->num <= base+num) {
157 /* Cut off bit from the end */
158 q->num = base - q->base;
159 } else {
160 /* Split the block into two pieces */
161 p = kmalloc(sizeof(struct resource_map),
162 GFP_KERNEL);
163 if (!p) {
164 printk(KERN_WARNING "out of memory to update resources\n");
165 return -ENOMEM;
166 }
167 p->base = base+num;
168 p->num = q->base+q->num - p->base;
169 q->num = base - q->base;
170 p->next = q->next ; q->next = p;
171 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 }
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100174 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175}
176
177/*======================================================================
178
179 These routines examine a region of IO or memory addresses to
180 determine what ranges might be genuinely available.
181
182======================================================================*/
183
184#ifdef CONFIG_PCMCIA_PROBE
Olof Johansson906da802008-02-04 22:27:35 -0800185static void do_io_probe(struct pcmcia_socket *s, unsigned int base,
186 unsigned int num)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187{
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100188 struct resource *res;
189 struct socket_data *s_data = s->resource_data;
190 unsigned int i, j, bad;
191 int any;
192 u_char *b, hole, most;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193
Joe Perchesf2e6cf72014-10-10 09:12:47 -0700194 dev_info(&s->dev, "cs: IO port probe %#x-%#x:", 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) {
Joe Perchesf2e6cf72014-10-10 09:12:47 -0700199 pr_cont("\n");
200 dev_err(&s->dev, "do_io_probe: unable to kmalloc 256 bytes\n");
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100201 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202 }
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100203 for (i = base, most = 0; i < base+num; i += 8) {
Dominik Brodowski509b0862010-04-08 19:23:07 +0200204 res = claim_region(s, i, 8, IORESOURCE_IO, "PCMCIA ioprobe");
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100205 if (!res)
206 continue;
207 hole = inb(i);
208 for (j = 1; j < 8; j++)
209 if (inb(i+j) != hole)
210 break;
211 free_region(res);
212 if ((j == 8) && (++b[hole] > b[most]))
213 most = hole;
214 if (b[most] == 127)
215 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216 }
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100217 kfree(b);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100219 bad = any = 0;
220 for (i = base; i < base+num; i += 8) {
Dominik Brodowski509b0862010-04-08 19:23:07 +0200221 res = claim_region(s, i, 8, IORESOURCE_IO, "PCMCIA ioprobe");
222 if (!res) {
223 if (!any)
Joe Perchesf2e6cf72014-10-10 09:12:47 -0700224 pr_cont(" excluding");
Dominik Brodowski509b0862010-04-08 19:23:07 +0200225 if (!bad)
226 bad = any = i;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100227 continue;
Dominik Brodowski509b0862010-04-08 19:23:07 +0200228 }
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100229 for (j = 0; j < 8; j++)
230 if (inb(i+j) != most)
231 break;
232 free_region(res);
233 if (j < 8) {
234 if (!any)
Joe Perchesf2e6cf72014-10-10 09:12:47 -0700235 pr_cont(" excluding");
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100236 if (!bad)
237 bad = any = i;
238 } else {
239 if (bad) {
240 sub_interval(&s_data->io_db, bad, i-bad);
Joe Perchesf2e6cf72014-10-10 09:12:47 -0700241 pr_cont(" %#x-%#x", bad, i-1);
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100242 bad = 0;
243 }
244 }
245 }
246 if (bad) {
247 if ((num > 16) && (bad == base) && (i == base+num)) {
Dominik Brodowski509b0862010-04-08 19:23:07 +0200248 sub_interval(&s_data->io_db, bad, i-bad);
Joe Perchesf2e6cf72014-10-10 09:12:47 -0700249 pr_cont(" nothing: probe failed.\n");
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100250 return;
251 } else {
252 sub_interval(&s_data->io_db, bad, i-bad);
Joe Perchesf2e6cf72014-10-10 09:12:47 -0700253 pr_cont(" %#x-%#x", bad, i-1);
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100254 }
255 }
256
Joe Perchesf2e6cf72014-10-10 09:12:47 -0700257 pr_cont("%s\n", !any ? " clean" : "");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258}
259#endif
260
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100261/*======================================================================*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100263/**
264 * readable() - iomem validation function for cards with a valid CIS
265 */
Dominik Brodowskic5081d52008-06-19 20:12:34 +0200266static int readable(struct pcmcia_socket *s, struct resource *res,
267 unsigned int *count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268{
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100269 int ret = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270
Dominik Brodowski7ab248552010-02-17 18:00:07 +0100271 if (s->fake_cis) {
272 dev_dbg(&s->dev, "fake CIS is being used: can't validate mem\n");
273 return 0;
274 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275
276 s->cis_mem.res = res;
277 s->cis_virt = ioremap(res->start, s->map_size);
278 if (s->cis_virt) {
Dominik Brodowski6b8e0872010-01-12 21:42:51 +0100279 mutex_unlock(&s->ops_mutex);
Dominik Brodowski6e7b51a2010-01-06 13:57:43 +0100280 /* as we're only called from pcmcia.c, we're safe */
281 if (s->callback->validate)
282 ret = s->callback->validate(s, count);
Dominik Brodowski904e3772010-01-02 12:28:04 +0100283 /* invalidate mapping */
Dominik Brodowski6b8e0872010-01-12 21:42:51 +0100284 mutex_lock(&s->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 iounmap(s->cis_virt);
286 s->cis_virt = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287 }
288 s->cis_mem.res = NULL;
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100289 if ((ret) || (*count == 0))
290 return -EINVAL;
291 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292}
293
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100294/**
295 * checksum() - iomem validation function for simple memory cards
296 */
297static int checksum(struct pcmcia_socket *s, struct resource *res,
298 unsigned int *value)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299{
300 pccard_mem_map map;
301 int i, a = 0, b = -1, d;
302 void __iomem *virt;
303
304 virt = ioremap(res->start, s->map_size);
305 if (virt) {
306 map.map = 0;
307 map.flags = MAP_ACTIVE;
308 map.speed = 0;
309 map.res = res;
310 map.card_start = 0;
311 s->ops->set_mem_map(s, &map);
312
313 /* Don't bother checking every word... */
314 for (i = 0; i < s->map_size; i += 44) {
315 d = readl(virt+i);
316 a += d;
317 b &= d;
318 }
319
320 map.flags = 0;
321 s->ops->set_mem_map(s, &map);
322
323 iounmap(virt);
324 }
325
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100326 if (b == -1)
327 return -EINVAL;
328
329 *value = a;
330
331 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332}
333
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100334/**
335 * do_validate_mem() - low level validate a memory region for PCMCIA use
336 * @s: PCMCIA socket to validate
337 * @base: start address of resource to check
338 * @size: size of resource to check
339 * @validate: validation function to use
340 *
341 * do_validate_mem() splits up the memory region which is to be checked
342 * into two parts. Both are passed to the @validate() function. If
343 * @validate() returns non-zero, or the value parameter to @validate()
344 * is zero, or the value parameter is different between both calls,
345 * the check fails, and -EINVAL is returned. Else, 0 is returned.
346 */
347static int do_validate_mem(struct pcmcia_socket *s,
348 unsigned long base, unsigned long size,
349 int validate (struct pcmcia_socket *s,
350 struct resource *res,
351 unsigned int *value))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352{
Dominik Brodowski7b4884c2010-02-17 16:25:53 +0100353 struct socket_data *s_data = s->resource_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 struct resource *res1, *res2;
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100355 unsigned int info1 = 1, info2 = 1;
356 int ret = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100358 res1 = claim_region(s, base, size/2, IORESOURCE_MEM, "PCMCIA memprobe");
359 res2 = claim_region(s, base + size/2, size/2, IORESOURCE_MEM,
360 "PCMCIA memprobe");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361
362 if (res1 && res2) {
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100363 ret = 0;
364 if (validate) {
365 ret = validate(s, res1, &info1);
366 ret += validate(s, res2, &info2);
367 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 }
369
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100370 dev_dbg(&s->dev, "cs: memory probe 0x%06lx-0x%06lx: %p %p %u %u %u",
371 base, base+size-1, res1, res2, ret, info1, info2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372
Jesper Juhlbec0b2c2013-01-20 23:14:43 +0100373 free_region(res2);
374 free_region(res1);
375
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100376 if ((ret) || (info1 != info2) || (info1 == 0))
377 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378
Dominik Brodowski7b4884c2010-02-17 16:25:53 +0100379 if (validate && !s->fake_cis) {
380 /* move it to the validated data set */
381 add_interval(&s_data->mem_db_valid, base, size);
382 sub_interval(&s_data->mem_db, base, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 }
384
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100385 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386}
387
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100389/**
390 * do_mem_probe() - validate a memory region for PCMCIA use
391 * @s: PCMCIA socket to validate
392 * @base: start address of resource to check
393 * @num: size of resource to check
394 * @validate: validation function to use
395 * @fallback: validation function to use if validate fails
396 *
397 * do_mem_probe() checks a memory region for use by the PCMCIA subsystem.
398 * To do so, the area is split up into sensible parts, and then passed
399 * into the @validate() function. Only if @validate() and @fallback() fail,
400 * the area is marked as unavaibale for use by the PCMCIA subsystem. The
401 * function returns the size of the usable memory area.
402 */
403static int do_mem_probe(struct pcmcia_socket *s, u_long base, u_long num,
404 int validate (struct pcmcia_socket *s,
405 struct resource *res,
406 unsigned int *value),
407 int fallback (struct pcmcia_socket *s,
408 struct resource *res,
409 unsigned int *value))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410{
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100411 struct socket_data *s_data = s->resource_data;
412 u_long i, j, bad, fail, step;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413
Joe Perchesf2e6cf72014-10-10 09:12:47 -0700414 dev_info(&s->dev, "cs: memory probe 0x%06lx-0x%06lx:",
415 base, base+num-1);
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100416 bad = fail = 0;
417 step = (num < 0x20000) ? 0x2000 : ((num>>4) & ~0x1fff);
418 /* don't allow too large steps */
419 if (step > 0x800000)
420 step = 0x800000;
421 /* cis_readable wants to map 2x map_size */
422 if (step < 2 * s->map_size)
423 step = 2 * s->map_size;
424 for (i = j = base; i < base+num; i = j + step) {
425 if (!fail) {
426 for (j = i; j < base+num; j += step) {
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100427 if (!do_validate_mem(s, j, step, validate))
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100428 break;
429 }
430 fail = ((i == base) && (j == base+num));
431 }
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100432 if ((fail) && (fallback)) {
433 for (j = i; j < base+num; j += step)
434 if (!do_validate_mem(s, j, step, fallback))
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100435 break;
436 }
437 if (i != j) {
438 if (!bad)
Joe Perchesf2e6cf72014-10-10 09:12:47 -0700439 pr_cont(" excluding");
440 pr_cont(" %#05lx-%#05lx", i, j-1);
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100441 sub_interval(&s_data->mem_db, i, j-i);
442 bad += j-i;
443 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 }
Joe Perchesf2e6cf72014-10-10 09:12:47 -0700445 pr_cont("%s\n", !bad ? " clean" : "");
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100446 return num - bad;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447}
448
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100449
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450#ifdef CONFIG_PCMCIA_PROBE
451
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100452/**
453 * inv_probe() - top-to-bottom search for one usuable high memory area
454 * @s: PCMCIA socket to validate
455 * @m: resource_map to check
456 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457static u_long inv_probe(struct resource_map *m, struct pcmcia_socket *s)
458{
Dominik Brodowskide759142005-09-28 19:41:56 +0200459 struct socket_data *s_data = s->resource_data;
460 u_long ok;
461 if (m == &s_data->mem_db)
462 return 0;
463 ok = inv_probe(m->next, s);
464 if (ok) {
465 if (m->base >= 0x100000)
466 sub_interval(&s_data->mem_db, m->base, m->num);
467 return ok;
468 }
469 if (m->base < 0x100000)
470 return 0;
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100471 return do_mem_probe(s, m->base, m->num, readable, checksum);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472}
473
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100474/**
475 * validate_mem() - memory probe function
476 * @s: PCMCIA socket to validate
477 * @probe_mask: MEM_PROBE_LOW | MEM_PROBE_HIGH
478 *
479 * The memory probe. If the memory list includes a 64K-aligned block
480 * below 1MB, we probe in 64K chunks, and as soon as we accumulate at
481 * least mem_limit free space, we quit. Returns 0 on usuable ports.
482 */
Dominik Brodowskide759142005-09-28 19:41:56 +0200483static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484{
Dominik Brodowskide759142005-09-28 19:41:56 +0200485 struct resource_map *m, mm;
486 static unsigned char order[] = { 0xd0, 0xe0, 0xc0, 0xf0 };
487 unsigned long b, i, ok = 0;
488 struct socket_data *s_data = s->resource_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489
Dominik Brodowskide759142005-09-28 19:41:56 +0200490 /* We do up to four passes through the list */
491 if (probe_mask & MEM_PROBE_HIGH) {
492 if (inv_probe(s_data->mem_db.next, s) > 0)
493 return 0;
Dominik Brodowski7b4884c2010-02-17 16:25:53 +0100494 if (s_data->mem_db_valid.next != &s_data->mem_db_valid)
495 return 0;
Joe Perchesf2e6cf72014-10-10 09:12:47 -0700496 dev_notice(&s->dev,
Dominik Brodowskidbe4ea52008-08-02 21:36:19 +0200497 "cs: warning: no high memory space available!\n");
Dominik Brodowskide759142005-09-28 19:41:56 +0200498 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 }
Dominik Brodowskide759142005-09-28 19:41:56 +0200500
501 for (m = s_data->mem_db.next; m != &s_data->mem_db; m = mm.next) {
502 mm = *m;
503 /* Only probe < 1 MB */
504 if (mm.base >= 0x100000)
505 continue;
506 if ((mm.base | mm.num) & 0xffff) {
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100507 ok += do_mem_probe(s, mm.base, mm.num, readable,
508 checksum);
Dominik Brodowskide759142005-09-28 19:41:56 +0200509 continue;
510 }
511 /* Special probe for 64K-aligned block */
512 for (i = 0; i < 4; i++) {
513 b = order[i] << 12;
514 if ((b >= mm.base) && (b+0x10000 <= mm.base+mm.num)) {
515 if (ok >= mem_limit)
516 sub_interval(&s_data->mem_db, b, 0x10000);
517 else
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100518 ok += do_mem_probe(s, b, 0x10000,
519 readable, checksum);
Dominik Brodowskide759142005-09-28 19:41:56 +0200520 }
521 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 }
Dominik Brodowskide759142005-09-28 19:41:56 +0200523
524 if (ok > 0)
525 return 0;
526
527 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528}
529
530#else /* CONFIG_PCMCIA_PROBE */
531
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100532/**
533 * validate_mem() - memory probe function
534 * @s: PCMCIA socket to validate
535 * @probe_mask: ignored
536 *
537 * Returns 0 on usuable ports.
538 */
Andrew Morton2cff9442005-11-16 21:29:26 -0800539static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540{
541 struct resource_map *m, mm;
542 struct socket_data *s_data = s->resource_data;
Andrew Morton2cff9442005-11-16 21:29:26 -0800543 unsigned long ok = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544
545 for (m = s_data->mem_db.next; m != &s_data->mem_db; m = mm.next) {
546 mm = *m;
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100547 ok += do_mem_probe(s, mm.base, mm.num, readable, checksum);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 }
Andrew Morton2cff9442005-11-16 21:29:26 -0800549 if (ok > 0)
550 return 0;
551 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552}
553
554#endif /* CONFIG_PCMCIA_PROBE */
555
556
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100557/**
558 * pcmcia_nonstatic_validate_mem() - try to validate iomem for PCMCIA use
559 * @s: PCMCIA socket to validate
560 *
561 * This is tricky... when we set up CIS memory, we try to validate
562 * the memory window space allocations.
563 *
Dominik Brodowski7fe908d2006-01-10 21:20:36 +0100564 * Locking note: Must be called with skt_mutex held!
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 */
Dominik Brodowskide759142005-09-28 19:41:56 +0200566static int pcmcia_nonstatic_validate_mem(struct pcmcia_socket *s)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567{
568 struct socket_data *s_data = s->resource_data;
Dominik Brodowskide759142005-09-28 19:41:56 +0200569 unsigned int probe_mask = MEM_PROBE_LOW;
Dominik Brodowski7b4884c2010-02-17 16:25:53 +0100570 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571
Dominik Brodowski7b4884c2010-02-17 16:25:53 +0100572 if (!probe_mem || !(s->state & SOCKET_PRESENT))
Dominik Brodowskide759142005-09-28 19:41:56 +0200573 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574
Dominik Brodowskide759142005-09-28 19:41:56 +0200575 if (s->features & SS_CAP_PAGE_REGS)
576 probe_mask = MEM_PROBE_HIGH;
577
Dominik Brodowski7b4884c2010-02-17 16:25:53 +0100578 ret = validate_mem(s, probe_mask);
Dominik Brodowskide759142005-09-28 19:41:56 +0200579
Dominik Brodowski7b4884c2010-02-17 16:25:53 +0100580 if (s_data->mem_db_valid.next != &s_data->mem_db_valid)
581 return 0;
Dominik Brodowskide759142005-09-28 19:41:56 +0200582
583 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584}
585
586struct pcmcia_align_data {
587 unsigned long mask;
588 unsigned long offset;
589 struct resource_map *map;
590};
591
Dominik Brodowski147a2742010-04-04 18:10:35 +0200592static resource_size_t pcmcia_common_align(struct pcmcia_align_data *align_data,
593 resource_size_t start)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594{
Dominik Brodowski147a2742010-04-04 18:10:35 +0200595 resource_size_t ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596 /*
597 * Ensure that we have the correct start address
598 */
Dominik Brodowski147a2742010-04-04 18:10:35 +0200599 ret = (start & ~align_data->mask) + align_data->offset;
600 if (ret < start)
601 ret += align_data->mask + 1;
602 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603}
604
Dominik Brodowskib26b2d42010-01-01 17:40:49 +0100605static resource_size_t
Dominik Brodowski3b7a17f2010-01-01 17:40:50 +0100606pcmcia_align(void *align_data, const struct resource *res,
607 resource_size_t size, resource_size_t align)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608{
609 struct pcmcia_align_data *data = align_data;
610 struct resource_map *m;
Dominik Brodowskib26b2d42010-01-01 17:40:49 +0100611 resource_size_t start;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612
Dominik Brodowski147a2742010-04-04 18:10:35 +0200613 start = pcmcia_common_align(data, res->start);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614
615 for (m = data->map->next; m != data->map; m = m->next) {
Dominik Brodowski147a2742010-04-04 18:10:35 +0200616 unsigned long map_start = m->base;
617 unsigned long map_end = m->base + m->num - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618
619 /*
620 * If the lower resources are not available, try aligning
621 * to this entry of the resource database to see if it'll
622 * fit here.
623 */
Dominik Brodowski147a2742010-04-04 18:10:35 +0200624 if (start < map_start)
625 start = pcmcia_common_align(data, map_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626
627 /*
628 * If we're above the area which was passed in, there's
629 * no point proceeding.
630 */
Dominik Brodowski147a2742010-04-04 18:10:35 +0200631 if (start >= res->end)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 break;
633
Dominik Brodowski147a2742010-04-04 18:10:35 +0200634 if ((start + size - 1) <= map_end)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 break;
636 }
637
638 /*
639 * If we failed to find something suitable, ensure we fail.
640 */
641 if (m == data->map)
Dominik Brodowskib26b2d42010-01-01 17:40:49 +0100642 start = res->end;
643
644 return start;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645}
646
647/*
648 * Adjust an existing IO region allocation, but making sure that we don't
649 * encroach outside the resources which the user supplied.
650 */
Dominik Brodowskib19a7272010-03-20 13:10:47 +0100651static int __nonstatic_adjust_io_region(struct pcmcia_socket *s,
652 unsigned long r_start,
653 unsigned long r_end)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654{
655 struct resource_map *m;
656 struct socket_data *s_data = s->resource_data;
657 int ret = -ENOMEM;
658
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 for (m = s_data->io_db.next; m != &s_data->io_db; m = m->next) {
660 unsigned long start = m->base;
661 unsigned long end = m->base + m->num - 1;
662
663 if (start > r_start || r_end > end)
664 continue;
665
Dominik Brodowskib19a7272010-03-20 13:10:47 +0100666 ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668
669 return ret;
670}
671
672/*======================================================================
673
674 These find ranges of I/O ports or memory addresses that are not
675 currently allocated by other devices.
676
677 The 'align' field should reflect the number of bits of address
678 that need to be preserved from the initial value of *base. It
679 should be a power of two, greater than or equal to 'num'. A value
680 of 0 means that all bits of *base are significant. *base should
681 also be strictly less than 'align'.
682
683======================================================================*/
684
Dominik Brodowskib19a7272010-03-20 13:10:47 +0100685static struct resource *__nonstatic_find_io_region(struct pcmcia_socket *s,
686 unsigned long base, int num,
687 unsigned long align)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688{
Dominik Brodowski49b11532010-03-07 16:41:57 +0100689 struct resource *res = pcmcia_make_resource(0, num, IORESOURCE_IO,
690 dev_name(&s->dev));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 struct socket_data *s_data = s->resource_data;
692 struct pcmcia_align_data data;
693 unsigned long min = base;
694 int ret;
695
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 data.mask = align - 1;
697 data.offset = base & data.mask;
698 data.map = &s_data->io_db;
699
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700#ifdef CONFIG_PCI
701 if (s->cb_dev) {
702 ret = pci_bus_alloc_resource(s->cb_dev->bus, res, num, 1,
703 min, 0, pcmcia_align, &data);
704 } else
705#endif
706 ret = allocate_resource(&ioport_resource, res, num, min, ~0UL,
707 1, pcmcia_align, &data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708
709 if (ret != 0) {
710 kfree(res);
711 res = NULL;
712 }
713 return res;
714}
715
Dominik Brodowskib19a7272010-03-20 13:10:47 +0100716static int nonstatic_find_io(struct pcmcia_socket *s, unsigned int attr,
717 unsigned int *base, unsigned int num,
Dominik Brodowskiad0c7be2010-07-25 13:10:22 +0200718 unsigned int align, struct resource **parent)
Dominik Brodowskib19a7272010-03-20 13:10:47 +0100719{
720 int i, ret = 0;
721
722 /* Check for an already-allocated window that must conflict with
723 * what was asked for. It is a hack because it does not catch all
724 * potential conflicts, just the most obvious ones.
725 */
726 for (i = 0; i < MAX_IO_WIN; i++) {
727 if (!s->io[i].res)
728 continue;
729
730 if (!*base)
731 continue;
732
733 if ((s->io[i].res->start & (align-1)) == *base)
734 return -EBUSY;
735 }
736
737 for (i = 0; i < MAX_IO_WIN; i++) {
738 struct resource *res = s->io[i].res;
739 unsigned int try;
740
741 if (res && (res->flags & IORESOURCE_BITS) !=
742 (attr & IORESOURCE_BITS))
743 continue;
744
745 if (!res) {
746 if (align == 0)
747 align = 0x10000;
748
749 res = s->io[i].res = __nonstatic_find_io_region(s,
750 *base, num,
751 align);
752 if (!res)
753 return -EINVAL;
754
755 *base = res->start;
756 s->io[i].res->flags =
757 ((res->flags & ~IORESOURCE_BITS) |
758 (attr & IORESOURCE_BITS));
759 s->io[i].InUse = num;
Dominik Brodowskiad0c7be2010-07-25 13:10:22 +0200760 *parent = res;
Dominik Brodowskib19a7272010-03-20 13:10:47 +0100761 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,
Joe Perches28f65c112011-06-09 09:13:32 -0700771 resource_size(res) + num);
Dominik Brodowskib19a7272010-03-20 13:10:47 +0100772 if (ret)
773 continue;
774 *base = try;
775 s->io[i].InUse += num;
Dominik Brodowskiad0c7be2010-07-25 13:10:22 +0200776 *parent = res;
Dominik Brodowskib19a7272010-03-20 13:10:47 +0100777 return 0;
778 }
779 }
780
781 /* Try to extend bottom of window */
782 try = res->start - num;
783 if ((*base == 0) || (*base == try)) {
784 ret = __nonstatic_adjust_io_region(s,
785 res->start - num,
786 res->end);
787 if (!ret) {
788 ret = adjust_resource(s->io[i].res,
Joe Perches28f65c112011-06-09 09:13:32 -0700789 res->start - num,
790 resource_size(res) + num);
Dominik Brodowskib19a7272010-03-20 13:10:47 +0100791 if (ret)
792 continue;
793 *base = try;
794 s->io[i].InUse += num;
Dominik Brodowskiad0c7be2010-07-25 13:10:22 +0200795 *parent = res;
Dominik Brodowskib19a7272010-03-20 13:10:47 +0100796 return 0;
797 }
798 }
799 }
800
801 return -EINVAL;
802}
803
804
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100805static struct resource *nonstatic_find_mem_region(u_long base, u_long num,
Dominik Brodowskie94e15f2005-06-27 16:28:15 -0700806 u_long align, int low, struct pcmcia_socket *s)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807{
Dominik Brodowski49b11532010-03-07 16:41:57 +0100808 struct resource *res = pcmcia_make_resource(0, num, IORESOURCE_MEM,
809 dev_name(&s->dev));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 struct socket_data *s_data = s->resource_data;
811 struct pcmcia_align_data data;
812 unsigned long min, max;
Dominik Brodowski7b4884c2010-02-17 16:25:53 +0100813 int ret, i, j;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814
815 low = low || !(s->features & SS_CAP_PAGE_REGS);
816
817 data.mask = align - 1;
818 data.offset = base & data.mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819
820 for (i = 0; i < 2; i++) {
Dominik Brodowski7b4884c2010-02-17 16:25:53 +0100821 data.map = &s_data->mem_db_valid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 if (low) {
823 max = 0x100000UL;
824 min = base < max ? base : 0;
825 } else {
826 max = ~0UL;
827 min = 0x100000UL + base;
828 }
829
Dominik Brodowski7b4884c2010-02-17 16:25:53 +0100830 for (j = 0; j < 2; j++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831#ifdef CONFIG_PCI
Dominik Brodowski7b4884c2010-02-17 16:25:53 +0100832 if (s->cb_dev) {
833 ret = pci_bus_alloc_resource(s->cb_dev->bus,
834 res, num, 1, min, 0,
835 pcmcia_align, &data);
836 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837#endif
Dominik Brodowski7b4884c2010-02-17 16:25:53 +0100838 {
839 ret = allocate_resource(&iomem_resource,
840 res, num, min, max, 1,
841 pcmcia_align, &data);
842 }
843 if (ret == 0)
844 break;
845 data.map = &s_data->mem_db;
846 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 if (ret == 0 || low)
848 break;
849 low = 1;
850 }
851
852 if (ret != 0) {
853 kfree(res);
854 res = NULL;
855 }
856 return res;
857}
858
859
Dominik Brodowski22916632005-06-27 16:28:46 -0700860static int adjust_memory(struct pcmcia_socket *s, unsigned int action, unsigned long start, unsigned long end)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 struct socket_data *data = s->resource_data;
Dominik Brodowski22916632005-06-27 16:28:46 -0700863 unsigned long size = end - start + 1;
864 int ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865
Dominik Brodowski1146bc72005-09-28 19:28:37 +0200866 if (end < start)
Dominik Brodowski22916632005-06-27 16:28:46 -0700867 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868
Dominik Brodowski22916632005-06-27 16:28:46 -0700869 switch (action) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870 case ADD_MANAGED_RESOURCE:
Dominik Brodowski22916632005-06-27 16:28:46 -0700871 ret = add_interval(&data->mem_db, start, size);
Dominik Brodowski3f32b3c2010-01-02 22:22:50 +0100872 if (!ret)
873 do_mem_probe(s, start, size, NULL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874 break;
875 case REMOVE_MANAGED_RESOURCE:
Dominik Brodowski22916632005-06-27 16:28:46 -0700876 ret = sub_interval(&data->mem_db, start, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 break;
878 default:
Dominik Brodowski22916632005-06-27 16:28:46 -0700879 ret = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881
882 return ret;
883}
884
885
Dominik Brodowski22916632005-06-27 16:28:46 -0700886static int adjust_io(struct pcmcia_socket *s, unsigned int action, unsigned long start, unsigned long end)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887{
888 struct socket_data *data = s->resource_data;
Dominik Brodowski41b97ab2010-04-15 19:01:53 +0200889 unsigned long size;
Dominik Brodowski22916632005-06-27 16:28:46 -0700890 int ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891
Dominik Brodowski9713ab22010-03-23 16:05:00 +0100892#if defined(CONFIG_X86)
893 /* on x86, avoid anything < 0x100 for it is often used for
894 * legacy platform devices */
895 if (start < 0x100)
896 start = 0x100;
897#endif
898
Dominik Brodowski41b97ab2010-04-15 19:01:53 +0200899 size = end - start + 1;
900
Dominik Brodowski1146bc72005-09-28 19:28:37 +0200901 if (end < start)
Dominik Brodowski22916632005-06-27 16:28:46 -0700902 return -EINVAL;
903
904 if (end > IO_SPACE_LIMIT)
905 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906
Dominik Brodowski22916632005-06-27 16:28:46 -0700907 switch (action) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 case ADD_MANAGED_RESOURCE:
Dominik Brodowski22916632005-06-27 16:28:46 -0700909 if (add_interval(&data->io_db, start, size) != 0) {
910 ret = -EBUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911 break;
912 }
913#ifdef CONFIG_PCMCIA_PROBE
914 if (probe_io)
Dominik Brodowski22916632005-06-27 16:28:46 -0700915 do_io_probe(s, start, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916#endif
917 break;
918 case REMOVE_MANAGED_RESOURCE:
Dominik Brodowski22916632005-06-27 16:28:46 -0700919 sub_interval(&data->io_db, start, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 break;
921 default:
Dominik Brodowski22916632005-06-27 16:28:46 -0700922 ret = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923 break;
924 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925
926 return ret;
927}
928
929
Dominik Brodowski3c299762005-06-27 16:28:46 -0700930#ifdef CONFIG_PCI
931static int nonstatic_autoadd_resources(struct pcmcia_socket *s)
932{
933 struct resource *res;
934 int i, done = 0;
935
936 if (!s->cb_dev || !s->cb_dev->bus)
937 return -ENODEV;
938
Brian Gerst0d078f62005-10-30 14:59:20 -0800939#if defined(CONFIG_X86)
Dominik Brodowskicf26e8d2010-03-29 21:40:35 +0200940 /* If this is the root bus, the risk of hitting some strange
941 * system devices is too high: If a driver isn't loaded, the
942 * resources are not claimed; even if a driver is loaded, it
943 * may not request all resources or even the wrong one. We
944 * can neither trust the rest of the kernel nor ACPI/PNP and
945 * CRS parsing to get it right. Therefore, use several
946 * safeguards:
947 *
948 * - Do not auto-add resources if the CardBus bridge is on
949 * the PCI root bus
950 *
951 * - Avoid any I/O ports < 0x100.
952 *
953 * - On PCI-PCI bridges, only use resources which are set up
954 * exclusively for the secondary PCI bus: the risk of hitting
955 * system devices is quite low, as they usually aren't
956 * connected to the secondary PCI bus.
Dominik Brodowskib6d00f02005-06-27 16:29:02 -0700957 */
958 if (s->cb_dev->bus->number == 0)
959 return -EINVAL;
Dominik Brodowskib6d00f02005-06-27 16:29:02 -0700960
Dominik Brodowskicf26e8d2010-03-29 21:40:35 +0200961 for (i = 0; i < PCI_BRIDGE_RESOURCE_NUM; i++) {
962 res = s->cb_dev->bus->resource[i];
963#else
Bjorn Helgaas89a74ec2010-02-23 10:24:31 -0700964 pci_bus_for_each_resource(s->cb_dev->bus, res, i) {
Dominik Brodowskicf26e8d2010-03-29 21:40:35 +0200965#endif
Dominik Brodowski3c299762005-06-27 16:28:46 -0700966 if (!res)
967 continue;
968
969 if (res->flags & IORESOURCE_IO) {
Dominik Brodowskicf26e8d2010-03-29 21:40:35 +0200970 /* safeguard against the root resource, where the
971 * risk of hitting any other device would be too
972 * high */
Dominik Brodowski3c299762005-06-27 16:28:46 -0700973 if (res == &ioport_resource)
974 continue;
Dominik Brodowskicf26e8d2010-03-29 21:40:35 +0200975
Joe Perchesf2e6cf72014-10-10 09:12:47 -0700976 dev_info(&s->cb_dev->dev,
977 "pcmcia: parent PCI bridge window: %pR\n",
978 res);
Dominik Brodowski3c299762005-06-27 16:28:46 -0700979 if (!adjust_io(s, ADD_MANAGED_RESOURCE, res->start, res->end))
980 done |= IORESOURCE_IO;
981
982 }
983
984 if (res->flags & IORESOURCE_MEM) {
Dominik Brodowskicf26e8d2010-03-29 21:40:35 +0200985 /* safeguard against the root resource, where the
986 * risk of hitting any other device would be too
987 * high */
Dominik Brodowski3c299762005-06-27 16:28:46 -0700988 if (res == &iomem_resource)
989 continue;
Dominik Brodowskicf26e8d2010-03-29 21:40:35 +0200990
Joe Perchesf2e6cf72014-10-10 09:12:47 -0700991 dev_info(&s->cb_dev->dev,
992 "pcmcia: parent PCI bridge window: %pR\n",
993 res);
Dominik Brodowski3c299762005-06-27 16:28:46 -0700994 if (!adjust_memory(s, ADD_MANAGED_RESOURCE, res->start, res->end))
995 done |= IORESOURCE_MEM;
996 }
997 }
998
999 /* if we got at least one of IO, and one of MEM, we can be glad and
1000 * activate the PCMCIA subsystem */
Dominik Brodowski54bb5672005-09-28 19:29:59 +02001001 if (done == (IORESOURCE_MEM | IORESOURCE_IO))
Dominik Brodowski3c299762005-06-27 16:28:46 -07001002 s->resource_setup_done = 1;
1003
1004 return 0;
1005}
1006
1007#else
1008
1009static inline int nonstatic_autoadd_resources(struct pcmcia_socket *s)
1010{
1011 return -ENODEV;
1012}
1013
1014#endif
1015
1016
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017static int nonstatic_init(struct pcmcia_socket *s)
1018{
1019 struct socket_data *data;
1020
Dominik Brodowski8084b372005-12-11 21:18:26 +01001021 data = kzalloc(sizeof(struct socket_data), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 if (!data)
1023 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024
1025 data->mem_db.next = &data->mem_db;
Dominik Brodowski7b4884c2010-02-17 16:25:53 +01001026 data->mem_db_valid.next = &data->mem_db_valid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027 data->io_db.next = &data->io_db;
1028
1029 s->resource_data = (void *) data;
1030
Dominik Brodowski3c299762005-06-27 16:28:46 -07001031 nonstatic_autoadd_resources(s);
1032
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033 return 0;
1034}
1035
1036static void nonstatic_release_resource_db(struct pcmcia_socket *s)
1037{
1038 struct socket_data *data = s->resource_data;
1039 struct resource_map *p, *q;
1040
Dominik Brodowski7b4884c2010-02-17 16:25:53 +01001041 for (p = data->mem_db_valid.next; p != &data->mem_db_valid; p = q) {
1042 q = p->next;
1043 kfree(p);
1044 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045 for (p = data->mem_db.next; p != &data->mem_db; p = q) {
1046 q = p->next;
1047 kfree(p);
1048 }
1049 for (p = data->io_db.next; p != &data->io_db; p = q) {
1050 q = p->next;
1051 kfree(p);
1052 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053}
1054
1055
1056struct pccard_resource_ops pccard_nonstatic_ops = {
1057 .validate_mem = pcmcia_nonstatic_validate_mem,
Dominik Brodowskib19a7272010-03-20 13:10:47 +01001058 .find_io = nonstatic_find_io,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059 .find_mem = nonstatic_find_mem_region,
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 Brodowskicfe5d802010-01-17 19:31:45 +01001118 mutex_unlock(&s->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119
1120 return ret ? ret : count;
1121}
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001122static DEVICE_ATTR(available_resources_io, 0600, show_io_db, store_io_db);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001124static ssize_t show_mem_db(struct device *dev,
1125 struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126{
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001127 struct pcmcia_socket *s = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128 struct socket_data *data;
1129 struct resource_map *p;
1130 ssize_t ret = 0;
1131
Dominik Brodowskicfe5d802010-01-17 19:31:45 +01001132 mutex_lock(&s->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 data = s->resource_data;
1134
Dominik Brodowski7b4884c2010-02-17 16:25:53 +01001135 for (p = data->mem_db_valid.next; p != &data->mem_db_valid;
1136 p = p->next) {
1137 if (ret > (PAGE_SIZE - 10))
1138 continue;
1139 ret += snprintf(&buf[ret], (PAGE_SIZE - ret - 1),
1140 "0x%08lx - 0x%08lx\n",
1141 ((unsigned long) p->base),
1142 ((unsigned long) p->base + p->num - 1));
1143 }
1144
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145 for (p = data->mem_db.next; p != &data->mem_db; p = p->next) {
1146 if (ret > (PAGE_SIZE - 10))
1147 continue;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001148 ret += snprintf(&buf[ret], (PAGE_SIZE - ret - 1),
1149 "0x%08lx - 0x%08lx\n",
1150 ((unsigned long) p->base),
1151 ((unsigned long) p->base + p->num - 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152 }
1153
Dominik Brodowskicfe5d802010-01-17 19:31:45 +01001154 mutex_unlock(&s->ops_mutex);
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001155 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156}
1157
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001158static ssize_t store_mem_db(struct device *dev,
1159 struct device_attribute *attr,
1160 const char *buf, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161{
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001162 struct pcmcia_socket *s = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163 unsigned long start_addr, end_addr;
Dominik Brodowski22916632005-06-27 16:28:46 -07001164 unsigned int add = ADD_MANAGED_RESOURCE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 ssize_t ret = 0;
1166
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001167 ret = sscanf(buf, "+ 0x%lx - 0x%lx", &start_addr, &end_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168 if (ret != 2) {
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001169 ret = sscanf(buf, "- 0x%lx - 0x%lx", &start_addr, &end_addr);
Dominik Brodowski22916632005-06-27 16:28:46 -07001170 add = REMOVE_MANAGED_RESOURCE;
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,
1173 &end_addr);
Dominik Brodowski22916632005-06-27 16:28:46 -07001174 add = ADD_MANAGED_RESOURCE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175 if (ret != 2)
1176 return -EINVAL;
1177 }
1178 }
Dominik Brodowski1146bc72005-09-28 19:28:37 +02001179 if (end_addr < start_addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180 return -EINVAL;
1181
Dominik Brodowskicfe5d802010-01-17 19:31:45 +01001182 mutex_lock(&s->ops_mutex);
Dominik Brodowski22916632005-06-27 16:28:46 -07001183 ret = adjust_memory(s, add, start_addr, end_addr);
Dominik Brodowskicfe5d802010-01-17 19:31:45 +01001184 mutex_unlock(&s->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185
1186 return ret ? ret : count;
1187}
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001188static DEVICE_ATTR(available_resources_mem, 0600, show_mem_db, store_mem_db);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189
David Brownell7d578962008-06-12 12:13:55 -07001190static struct attribute *pccard_rsrc_attributes[] = {
1191 &dev_attr_available_resources_io.attr,
1192 &dev_attr_available_resources_mem.attr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193 NULL,
1194};
1195
David Brownell7d578962008-06-12 12:13:55 -07001196static const struct attribute_group rsrc_attributes = {
1197 .attrs = pccard_rsrc_attributes,
1198};
1199
Bill Pemberton34cdf252012-11-19 13:23:12 -05001200static int pccard_sysfs_add_rsrc(struct device *dev,
Dmitry Torokhovd8539d82005-09-15 02:01:36 -05001201 struct class_interface *class_intf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202{
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001203 struct pcmcia_socket *s = dev_get_drvdata(dev);
David Brownell7d578962008-06-12 12:13:55 -07001204
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205 if (s->resource_ops != &pccard_nonstatic_ops)
1206 return 0;
David Brownell7d578962008-06-12 12:13:55 -07001207 return sysfs_create_group(&dev->kobj, &rsrc_attributes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208}
1209
Bill Pembertone765a022012-11-19 13:26:05 -05001210static void pccard_sysfs_remove_rsrc(struct device *dev,
Dmitry Torokhovd8539d82005-09-15 02:01:36 -05001211 struct class_interface *class_intf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212{
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001213 struct pcmcia_socket *s = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214
1215 if (s->resource_ops != &pccard_nonstatic_ops)
1216 return;
David Brownell7d578962008-06-12 12:13:55 -07001217 sysfs_remove_group(&dev->kobj, &rsrc_attributes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218}
1219
Sam Ravnborged49f5d2008-05-01 04:34:50 -07001220static struct class_interface pccard_rsrc_interface __refdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221 .class = &pcmcia_socket_class,
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001222 .add_dev = &pccard_sysfs_add_rsrc,
Bill Pemberton96364e32012-11-19 13:20:38 -05001223 .remove_dev = &pccard_sysfs_remove_rsrc,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224};
1225
1226static int __init nonstatic_sysfs_init(void)
1227{
1228 return class_interface_register(&pccard_rsrc_interface);
1229}
1230
1231static void __exit nonstatic_sysfs_exit(void)
1232{
1233 class_interface_unregister(&pccard_rsrc_interface);
1234}
1235
1236module_init(nonstatic_sysfs_init);
1237module_exit(nonstatic_sysfs_exit);