1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * rsrc_nonstatic.c -- Resource management routines for !SS_CAP_STATIC_MAP sockets
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * The initial developer of the original code is David A. Hinds
6*4882a593Smuzhiyun * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
7*4882a593Smuzhiyun * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun * (C) 1999 David A. Hinds
10*4882a593Smuzhiyun */
11*4882a593Smuzhiyun
12*4882a593Smuzhiyun #include <linux/module.h>
13*4882a593Smuzhiyun #include <linux/moduleparam.h>
14*4882a593Smuzhiyun #include <linux/init.h>
15*4882a593Smuzhiyun #include <linux/interrupt.h>
16*4882a593Smuzhiyun #include <linux/kernel.h>
17*4882a593Smuzhiyun #include <linux/errno.h>
18*4882a593Smuzhiyun #include <linux/types.h>
19*4882a593Smuzhiyun #include <linux/slab.h>
20*4882a593Smuzhiyun #include <linux/ioport.h>
21*4882a593Smuzhiyun #include <linux/timer.h>
22*4882a593Smuzhiyun #include <linux/pci.h>
23*4882a593Smuzhiyun #include <linux/device.h>
24*4882a593Smuzhiyun #include <linux/io.h>
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun #include <asm/irq.h>
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun #include <pcmcia/ss.h>
29*4882a593Smuzhiyun #include <pcmcia/cistpl.h>
30*4882a593Smuzhiyun #include "cs_internal.h"
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun /* moved to rsrc_mgr.c
33*4882a593Smuzhiyun MODULE_AUTHOR("David A. Hinds, Dominik Brodowski");
34*4882a593Smuzhiyun MODULE_LICENSE("GPL");
35*4882a593Smuzhiyun */
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun /* Parameters that can be set with 'insmod' */
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun #define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0444)
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun INT_MODULE_PARM(probe_mem, 1); /* memory probe? */
42*4882a593Smuzhiyun #ifdef CONFIG_PCMCIA_PROBE
43*4882a593Smuzhiyun INT_MODULE_PARM(probe_io, 1); /* IO port probe? */
44*4882a593Smuzhiyun INT_MODULE_PARM(mem_limit, 0x10000);
45*4882a593Smuzhiyun #endif
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun /* for io_db and mem_db */
48*4882a593Smuzhiyun struct resource_map {
49*4882a593Smuzhiyun u_long base, num;
50*4882a593Smuzhiyun struct resource_map *next;
51*4882a593Smuzhiyun };
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun struct socket_data {
54*4882a593Smuzhiyun struct resource_map mem_db;
55*4882a593Smuzhiyun struct resource_map mem_db_valid;
56*4882a593Smuzhiyun struct resource_map io_db;
57*4882a593Smuzhiyun };
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun #define MEM_PROBE_LOW (1 << 0)
60*4882a593Smuzhiyun #define MEM_PROBE_HIGH (1 << 1)
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun /* Action field */
63*4882a593Smuzhiyun #define REMOVE_MANAGED_RESOURCE 1
64*4882a593Smuzhiyun #define ADD_MANAGED_RESOURCE 2
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun /*======================================================================
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun Linux resource management extensions
69*4882a593Smuzhiyun
70*4882a593Smuzhiyun ======================================================================*/
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun static struct resource *
claim_region(struct pcmcia_socket * s,resource_size_t base,resource_size_t size,int type,char * name)73*4882a593Smuzhiyun claim_region(struct pcmcia_socket *s, resource_size_t base,
74*4882a593Smuzhiyun resource_size_t size, int type, char *name)
75*4882a593Smuzhiyun {
76*4882a593Smuzhiyun struct resource *res, *parent;
77*4882a593Smuzhiyun
78*4882a593Smuzhiyun parent = type & IORESOURCE_MEM ? &iomem_resource : &ioport_resource;
79*4882a593Smuzhiyun res = pcmcia_make_resource(base, size, type | IORESOURCE_BUSY, name);
80*4882a593Smuzhiyun
81*4882a593Smuzhiyun if (res) {
82*4882a593Smuzhiyun #ifdef CONFIG_PCI
83*4882a593Smuzhiyun if (s && s->cb_dev)
84*4882a593Smuzhiyun parent = pci_find_parent_resource(s->cb_dev, res);
85*4882a593Smuzhiyun #endif
86*4882a593Smuzhiyun if (!parent || request_resource(parent, res)) {
87*4882a593Smuzhiyun kfree(res);
88*4882a593Smuzhiyun res = NULL;
89*4882a593Smuzhiyun }
90*4882a593Smuzhiyun }
91*4882a593Smuzhiyun return res;
92*4882a593Smuzhiyun }
93*4882a593Smuzhiyun
free_region(struct resource * res)94*4882a593Smuzhiyun static void free_region(struct resource *res)
95*4882a593Smuzhiyun {
96*4882a593Smuzhiyun if (res) {
97*4882a593Smuzhiyun release_resource(res);
98*4882a593Smuzhiyun kfree(res);
99*4882a593Smuzhiyun }
100*4882a593Smuzhiyun }
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun /*======================================================================
103*4882a593Smuzhiyun
104*4882a593Smuzhiyun These manage the internal databases of available resources.
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun ======================================================================*/
107*4882a593Smuzhiyun
add_interval(struct resource_map * map,u_long base,u_long num)108*4882a593Smuzhiyun static int add_interval(struct resource_map *map, u_long base, u_long num)
109*4882a593Smuzhiyun {
110*4882a593Smuzhiyun struct resource_map *p, *q;
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun for (p = map; ; p = p->next) {
113*4882a593Smuzhiyun if ((p != map) && (p->base+p->num >= base)) {
114*4882a593Smuzhiyun p->num = max(num + base - p->base, p->num);
115*4882a593Smuzhiyun return 0;
116*4882a593Smuzhiyun }
117*4882a593Smuzhiyun if ((p->next == map) || (p->next->base > base+num-1))
118*4882a593Smuzhiyun break;
119*4882a593Smuzhiyun }
120*4882a593Smuzhiyun q = kmalloc(sizeof(struct resource_map), GFP_KERNEL);
121*4882a593Smuzhiyun if (!q) {
122*4882a593Smuzhiyun printk(KERN_WARNING "out of memory to update resources\n");
123*4882a593Smuzhiyun return -ENOMEM;
124*4882a593Smuzhiyun }
125*4882a593Smuzhiyun q->base = base; q->num = num;
126*4882a593Smuzhiyun q->next = p->next; p->next = q;
127*4882a593Smuzhiyun return 0;
128*4882a593Smuzhiyun }
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun /*====================================================================*/
131*4882a593Smuzhiyun
sub_interval(struct resource_map * map,u_long base,u_long num)132*4882a593Smuzhiyun static int sub_interval(struct resource_map *map, u_long base, u_long num)
133*4882a593Smuzhiyun {
134*4882a593Smuzhiyun struct resource_map *p, *q;
135*4882a593Smuzhiyun
136*4882a593Smuzhiyun for (p = map; ; p = q) {
137*4882a593Smuzhiyun q = p->next;
138*4882a593Smuzhiyun if (q == map)
139*4882a593Smuzhiyun break;
140*4882a593Smuzhiyun if ((q->base+q->num > base) && (base+num > q->base)) {
141*4882a593Smuzhiyun if (q->base >= base) {
142*4882a593Smuzhiyun if (q->base+q->num <= base+num) {
143*4882a593Smuzhiyun /* Delete whole block */
144*4882a593Smuzhiyun p->next = q->next;
145*4882a593Smuzhiyun kfree(q);
146*4882a593Smuzhiyun /* don't advance the pointer yet */
147*4882a593Smuzhiyun q = p;
148*4882a593Smuzhiyun } else {
149*4882a593Smuzhiyun /* Cut off bit from the front */
150*4882a593Smuzhiyun q->num = q->base + q->num - base - num;
151*4882a593Smuzhiyun q->base = base + num;
152*4882a593Smuzhiyun }
153*4882a593Smuzhiyun } else if (q->base+q->num <= base+num) {
154*4882a593Smuzhiyun /* Cut off bit from the end */
155*4882a593Smuzhiyun q->num = base - q->base;
156*4882a593Smuzhiyun } else {
157*4882a593Smuzhiyun /* Split the block into two pieces */
158*4882a593Smuzhiyun p = kmalloc(sizeof(struct resource_map),
159*4882a593Smuzhiyun GFP_KERNEL);
160*4882a593Smuzhiyun if (!p) {
161*4882a593Smuzhiyun printk(KERN_WARNING "out of memory to update resources\n");
162*4882a593Smuzhiyun return -ENOMEM;
163*4882a593Smuzhiyun }
164*4882a593Smuzhiyun p->base = base+num;
165*4882a593Smuzhiyun p->num = q->base+q->num - p->base;
166*4882a593Smuzhiyun q->num = base - q->base;
167*4882a593Smuzhiyun p->next = q->next ; q->next = p;
168*4882a593Smuzhiyun }
169*4882a593Smuzhiyun }
170*4882a593Smuzhiyun }
171*4882a593Smuzhiyun return 0;
172*4882a593Smuzhiyun }
173*4882a593Smuzhiyun
174*4882a593Smuzhiyun /*======================================================================
175*4882a593Smuzhiyun
176*4882a593Smuzhiyun These routines examine a region of IO or memory addresses to
177*4882a593Smuzhiyun determine what ranges might be genuinely available.
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun ======================================================================*/
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun #ifdef CONFIG_PCMCIA_PROBE
do_io_probe(struct pcmcia_socket * s,unsigned int base,unsigned int num)182*4882a593Smuzhiyun static void do_io_probe(struct pcmcia_socket *s, unsigned int base,
183*4882a593Smuzhiyun unsigned int num)
184*4882a593Smuzhiyun {
185*4882a593Smuzhiyun struct resource *res;
186*4882a593Smuzhiyun struct socket_data *s_data = s->resource_data;
187*4882a593Smuzhiyun unsigned int i, j, bad;
188*4882a593Smuzhiyun int any;
189*4882a593Smuzhiyun u_char *b, hole, most;
190*4882a593Smuzhiyun
191*4882a593Smuzhiyun dev_info(&s->dev, "cs: IO port probe %#x-%#x:", base, base+num-1);
192*4882a593Smuzhiyun
193*4882a593Smuzhiyun /* First, what does a floating port look like? */
194*4882a593Smuzhiyun b = kzalloc(256, GFP_KERNEL);
195*4882a593Smuzhiyun if (!b) {
196*4882a593Smuzhiyun pr_cont("\n");
197*4882a593Smuzhiyun dev_err(&s->dev, "do_io_probe: unable to kmalloc 256 bytes\n");
198*4882a593Smuzhiyun return;
199*4882a593Smuzhiyun }
200*4882a593Smuzhiyun for (i = base, most = 0; i < base+num; i += 8) {
201*4882a593Smuzhiyun res = claim_region(s, i, 8, IORESOURCE_IO, "PCMCIA ioprobe");
202*4882a593Smuzhiyun if (!res)
203*4882a593Smuzhiyun continue;
204*4882a593Smuzhiyun hole = inb(i);
205*4882a593Smuzhiyun for (j = 1; j < 8; j++)
206*4882a593Smuzhiyun if (inb(i+j) != hole)
207*4882a593Smuzhiyun break;
208*4882a593Smuzhiyun free_region(res);
209*4882a593Smuzhiyun if ((j == 8) && (++b[hole] > b[most]))
210*4882a593Smuzhiyun most = hole;
211*4882a593Smuzhiyun if (b[most] == 127)
212*4882a593Smuzhiyun break;
213*4882a593Smuzhiyun }
214*4882a593Smuzhiyun kfree(b);
215*4882a593Smuzhiyun
216*4882a593Smuzhiyun bad = any = 0;
217*4882a593Smuzhiyun for (i = base; i < base+num; i += 8) {
218*4882a593Smuzhiyun res = claim_region(s, i, 8, IORESOURCE_IO, "PCMCIA ioprobe");
219*4882a593Smuzhiyun if (!res) {
220*4882a593Smuzhiyun if (!any)
221*4882a593Smuzhiyun pr_cont(" excluding");
222*4882a593Smuzhiyun if (!bad)
223*4882a593Smuzhiyun bad = any = i;
224*4882a593Smuzhiyun continue;
225*4882a593Smuzhiyun }
226*4882a593Smuzhiyun for (j = 0; j < 8; j++)
227*4882a593Smuzhiyun if (inb(i+j) != most)
228*4882a593Smuzhiyun break;
229*4882a593Smuzhiyun free_region(res);
230*4882a593Smuzhiyun if (j < 8) {
231*4882a593Smuzhiyun if (!any)
232*4882a593Smuzhiyun pr_cont(" excluding");
233*4882a593Smuzhiyun if (!bad)
234*4882a593Smuzhiyun bad = any = i;
235*4882a593Smuzhiyun } else {
236*4882a593Smuzhiyun if (bad) {
237*4882a593Smuzhiyun sub_interval(&s_data->io_db, bad, i-bad);
238*4882a593Smuzhiyun pr_cont(" %#x-%#x", bad, i-1);
239*4882a593Smuzhiyun bad = 0;
240*4882a593Smuzhiyun }
241*4882a593Smuzhiyun }
242*4882a593Smuzhiyun }
243*4882a593Smuzhiyun if (bad) {
244*4882a593Smuzhiyun if ((num > 16) && (bad == base) && (i == base+num)) {
245*4882a593Smuzhiyun sub_interval(&s_data->io_db, bad, i-bad);
246*4882a593Smuzhiyun pr_cont(" nothing: probe failed.\n");
247*4882a593Smuzhiyun return;
248*4882a593Smuzhiyun } else {
249*4882a593Smuzhiyun sub_interval(&s_data->io_db, bad, i-bad);
250*4882a593Smuzhiyun pr_cont(" %#x-%#x", bad, i-1);
251*4882a593Smuzhiyun }
252*4882a593Smuzhiyun }
253*4882a593Smuzhiyun
254*4882a593Smuzhiyun pr_cont("%s\n", !any ? " clean" : "");
255*4882a593Smuzhiyun }
256*4882a593Smuzhiyun #endif
257*4882a593Smuzhiyun
258*4882a593Smuzhiyun /*======================================================================*/
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun /**
261*4882a593Smuzhiyun * readable() - iomem validation function for cards with a valid CIS
262*4882a593Smuzhiyun */
readable(struct pcmcia_socket * s,struct resource * res,unsigned int * count)263*4882a593Smuzhiyun static int readable(struct pcmcia_socket *s, struct resource *res,
264*4882a593Smuzhiyun unsigned int *count)
265*4882a593Smuzhiyun {
266*4882a593Smuzhiyun int ret = -EINVAL;
267*4882a593Smuzhiyun
268*4882a593Smuzhiyun if (s->fake_cis) {
269*4882a593Smuzhiyun dev_dbg(&s->dev, "fake CIS is being used: can't validate mem\n");
270*4882a593Smuzhiyun return 0;
271*4882a593Smuzhiyun }
272*4882a593Smuzhiyun
273*4882a593Smuzhiyun s->cis_mem.res = res;
274*4882a593Smuzhiyun s->cis_virt = ioremap(res->start, s->map_size);
275*4882a593Smuzhiyun if (s->cis_virt) {
276*4882a593Smuzhiyun mutex_unlock(&s->ops_mutex);
277*4882a593Smuzhiyun /* as we're only called from pcmcia.c, we're safe */
278*4882a593Smuzhiyun if (s->callback->validate)
279*4882a593Smuzhiyun ret = s->callback->validate(s, count);
280*4882a593Smuzhiyun /* invalidate mapping */
281*4882a593Smuzhiyun mutex_lock(&s->ops_mutex);
282*4882a593Smuzhiyun iounmap(s->cis_virt);
283*4882a593Smuzhiyun s->cis_virt = NULL;
284*4882a593Smuzhiyun }
285*4882a593Smuzhiyun s->cis_mem.res = NULL;
286*4882a593Smuzhiyun if ((ret) || (*count == 0))
287*4882a593Smuzhiyun return -EINVAL;
288*4882a593Smuzhiyun return 0;
289*4882a593Smuzhiyun }
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun /**
292*4882a593Smuzhiyun * checksum() - iomem validation function for simple memory cards
293*4882a593Smuzhiyun */
checksum(struct pcmcia_socket * s,struct resource * res,unsigned int * value)294*4882a593Smuzhiyun static int checksum(struct pcmcia_socket *s, struct resource *res,
295*4882a593Smuzhiyun unsigned int *value)
296*4882a593Smuzhiyun {
297*4882a593Smuzhiyun pccard_mem_map map;
298*4882a593Smuzhiyun int i, a = 0, b = -1, d;
299*4882a593Smuzhiyun void __iomem *virt;
300*4882a593Smuzhiyun
301*4882a593Smuzhiyun virt = ioremap(res->start, s->map_size);
302*4882a593Smuzhiyun if (virt) {
303*4882a593Smuzhiyun map.map = 0;
304*4882a593Smuzhiyun map.flags = MAP_ACTIVE;
305*4882a593Smuzhiyun map.speed = 0;
306*4882a593Smuzhiyun map.res = res;
307*4882a593Smuzhiyun map.card_start = 0;
308*4882a593Smuzhiyun s->ops->set_mem_map(s, &map);
309*4882a593Smuzhiyun
310*4882a593Smuzhiyun /* Don't bother checking every word... */
311*4882a593Smuzhiyun for (i = 0; i < s->map_size; i += 44) {
312*4882a593Smuzhiyun d = readl(virt+i);
313*4882a593Smuzhiyun a += d;
314*4882a593Smuzhiyun b &= d;
315*4882a593Smuzhiyun }
316*4882a593Smuzhiyun
317*4882a593Smuzhiyun map.flags = 0;
318*4882a593Smuzhiyun s->ops->set_mem_map(s, &map);
319*4882a593Smuzhiyun
320*4882a593Smuzhiyun iounmap(virt);
321*4882a593Smuzhiyun }
322*4882a593Smuzhiyun
323*4882a593Smuzhiyun if (b == -1)
324*4882a593Smuzhiyun return -EINVAL;
325*4882a593Smuzhiyun
326*4882a593Smuzhiyun *value = a;
327*4882a593Smuzhiyun
328*4882a593Smuzhiyun return 0;
329*4882a593Smuzhiyun }
330*4882a593Smuzhiyun
331*4882a593Smuzhiyun /**
332*4882a593Smuzhiyun * do_validate_mem() - low level validate a memory region for PCMCIA use
333*4882a593Smuzhiyun * @s: PCMCIA socket to validate
334*4882a593Smuzhiyun * @base: start address of resource to check
335*4882a593Smuzhiyun * @size: size of resource to check
336*4882a593Smuzhiyun * @validate: validation function to use
337*4882a593Smuzhiyun *
338*4882a593Smuzhiyun * do_validate_mem() splits up the memory region which is to be checked
339*4882a593Smuzhiyun * into two parts. Both are passed to the @validate() function. If
340*4882a593Smuzhiyun * @validate() returns non-zero, or the value parameter to @validate()
341*4882a593Smuzhiyun * is zero, or the value parameter is different between both calls,
342*4882a593Smuzhiyun * the check fails, and -EINVAL is returned. Else, 0 is returned.
343*4882a593Smuzhiyun */
do_validate_mem(struct pcmcia_socket * s,unsigned long base,unsigned long size,int validate (struct pcmcia_socket * s,struct resource * res,unsigned int * value))344*4882a593Smuzhiyun static int do_validate_mem(struct pcmcia_socket *s,
345*4882a593Smuzhiyun unsigned long base, unsigned long size,
346*4882a593Smuzhiyun int validate (struct pcmcia_socket *s,
347*4882a593Smuzhiyun struct resource *res,
348*4882a593Smuzhiyun unsigned int *value))
349*4882a593Smuzhiyun {
350*4882a593Smuzhiyun struct socket_data *s_data = s->resource_data;
351*4882a593Smuzhiyun struct resource *res1, *res2;
352*4882a593Smuzhiyun unsigned int info1 = 1, info2 = 1;
353*4882a593Smuzhiyun int ret = -EINVAL;
354*4882a593Smuzhiyun
355*4882a593Smuzhiyun res1 = claim_region(s, base, size/2, IORESOURCE_MEM, "PCMCIA memprobe");
356*4882a593Smuzhiyun res2 = claim_region(s, base + size/2, size/2, IORESOURCE_MEM,
357*4882a593Smuzhiyun "PCMCIA memprobe");
358*4882a593Smuzhiyun
359*4882a593Smuzhiyun if (res1 && res2) {
360*4882a593Smuzhiyun ret = 0;
361*4882a593Smuzhiyun if (validate) {
362*4882a593Smuzhiyun ret = validate(s, res1, &info1);
363*4882a593Smuzhiyun ret += validate(s, res2, &info2);
364*4882a593Smuzhiyun }
365*4882a593Smuzhiyun }
366*4882a593Smuzhiyun
367*4882a593Smuzhiyun dev_dbg(&s->dev, "cs: memory probe 0x%06lx-0x%06lx: %pr %pr %u %u %u",
368*4882a593Smuzhiyun base, base+size-1, res1, res2, ret, info1, info2);
369*4882a593Smuzhiyun
370*4882a593Smuzhiyun free_region(res2);
371*4882a593Smuzhiyun free_region(res1);
372*4882a593Smuzhiyun
373*4882a593Smuzhiyun if ((ret) || (info1 != info2) || (info1 == 0))
374*4882a593Smuzhiyun return -EINVAL;
375*4882a593Smuzhiyun
376*4882a593Smuzhiyun if (validate && !s->fake_cis) {
377*4882a593Smuzhiyun /* move it to the validated data set */
378*4882a593Smuzhiyun add_interval(&s_data->mem_db_valid, base, size);
379*4882a593Smuzhiyun sub_interval(&s_data->mem_db, base, size);
380*4882a593Smuzhiyun }
381*4882a593Smuzhiyun
382*4882a593Smuzhiyun return 0;
383*4882a593Smuzhiyun }
384*4882a593Smuzhiyun
385*4882a593Smuzhiyun
386*4882a593Smuzhiyun /**
387*4882a593Smuzhiyun * do_mem_probe() - validate a memory region for PCMCIA use
388*4882a593Smuzhiyun * @s: PCMCIA socket to validate
389*4882a593Smuzhiyun * @base: start address of resource to check
390*4882a593Smuzhiyun * @num: size of resource to check
391*4882a593Smuzhiyun * @validate: validation function to use
392*4882a593Smuzhiyun * @fallback: validation function to use if validate fails
393*4882a593Smuzhiyun *
394*4882a593Smuzhiyun * do_mem_probe() checks a memory region for use by the PCMCIA subsystem.
395*4882a593Smuzhiyun * To do so, the area is split up into sensible parts, and then passed
396*4882a593Smuzhiyun * into the @validate() function. Only if @validate() and @fallback() fail,
397*4882a593Smuzhiyun * the area is marked as unavaibale for use by the PCMCIA subsystem. The
398*4882a593Smuzhiyun * function returns the size of the usable memory area.
399*4882a593Smuzhiyun */
do_mem_probe(struct pcmcia_socket * s,u_long base,u_long num,int validate (struct pcmcia_socket * s,struct resource * res,unsigned int * value),int fallback (struct pcmcia_socket * s,struct resource * res,unsigned int * value))400*4882a593Smuzhiyun static int do_mem_probe(struct pcmcia_socket *s, u_long base, u_long num,
401*4882a593Smuzhiyun int validate (struct pcmcia_socket *s,
402*4882a593Smuzhiyun struct resource *res,
403*4882a593Smuzhiyun unsigned int *value),
404*4882a593Smuzhiyun int fallback (struct pcmcia_socket *s,
405*4882a593Smuzhiyun struct resource *res,
406*4882a593Smuzhiyun unsigned int *value))
407*4882a593Smuzhiyun {
408*4882a593Smuzhiyun struct socket_data *s_data = s->resource_data;
409*4882a593Smuzhiyun u_long i, j, bad, fail, step;
410*4882a593Smuzhiyun
411*4882a593Smuzhiyun dev_info(&s->dev, "cs: memory probe 0x%06lx-0x%06lx:",
412*4882a593Smuzhiyun base, base+num-1);
413*4882a593Smuzhiyun bad = fail = 0;
414*4882a593Smuzhiyun step = (num < 0x20000) ? 0x2000 : ((num>>4) & ~0x1fff);
415*4882a593Smuzhiyun /* don't allow too large steps */
416*4882a593Smuzhiyun if (step > 0x800000)
417*4882a593Smuzhiyun step = 0x800000;
418*4882a593Smuzhiyun /* cis_readable wants to map 2x map_size */
419*4882a593Smuzhiyun if (step < 2 * s->map_size)
420*4882a593Smuzhiyun step = 2 * s->map_size;
421*4882a593Smuzhiyun for (i = j = base; i < base+num; i = j + step) {
422*4882a593Smuzhiyun if (!fail) {
423*4882a593Smuzhiyun for (j = i; j < base+num; j += step) {
424*4882a593Smuzhiyun if (!do_validate_mem(s, j, step, validate))
425*4882a593Smuzhiyun break;
426*4882a593Smuzhiyun }
427*4882a593Smuzhiyun fail = ((i == base) && (j == base+num));
428*4882a593Smuzhiyun }
429*4882a593Smuzhiyun if ((fail) && (fallback)) {
430*4882a593Smuzhiyun for (j = i; j < base+num; j += step)
431*4882a593Smuzhiyun if (!do_validate_mem(s, j, step, fallback))
432*4882a593Smuzhiyun break;
433*4882a593Smuzhiyun }
434*4882a593Smuzhiyun if (i != j) {
435*4882a593Smuzhiyun if (!bad)
436*4882a593Smuzhiyun pr_cont(" excluding");
437*4882a593Smuzhiyun pr_cont(" %#05lx-%#05lx", i, j-1);
438*4882a593Smuzhiyun sub_interval(&s_data->mem_db, i, j-i);
439*4882a593Smuzhiyun bad += j-i;
440*4882a593Smuzhiyun }
441*4882a593Smuzhiyun }
442*4882a593Smuzhiyun pr_cont("%s\n", !bad ? " clean" : "");
443*4882a593Smuzhiyun return num - bad;
444*4882a593Smuzhiyun }
445*4882a593Smuzhiyun
446*4882a593Smuzhiyun
447*4882a593Smuzhiyun #ifdef CONFIG_PCMCIA_PROBE
448*4882a593Smuzhiyun
449*4882a593Smuzhiyun /**
450*4882a593Smuzhiyun * inv_probe() - top-to-bottom search for one usuable high memory area
451*4882a593Smuzhiyun * @s: PCMCIA socket to validate
452*4882a593Smuzhiyun * @m: resource_map to check
453*4882a593Smuzhiyun */
inv_probe(struct resource_map * m,struct pcmcia_socket * s)454*4882a593Smuzhiyun static u_long inv_probe(struct resource_map *m, struct pcmcia_socket *s)
455*4882a593Smuzhiyun {
456*4882a593Smuzhiyun struct socket_data *s_data = s->resource_data;
457*4882a593Smuzhiyun u_long ok;
458*4882a593Smuzhiyun if (m == &s_data->mem_db)
459*4882a593Smuzhiyun return 0;
460*4882a593Smuzhiyun ok = inv_probe(m->next, s);
461*4882a593Smuzhiyun if (ok) {
462*4882a593Smuzhiyun if (m->base >= 0x100000)
463*4882a593Smuzhiyun sub_interval(&s_data->mem_db, m->base, m->num);
464*4882a593Smuzhiyun return ok;
465*4882a593Smuzhiyun }
466*4882a593Smuzhiyun if (m->base < 0x100000)
467*4882a593Smuzhiyun return 0;
468*4882a593Smuzhiyun return do_mem_probe(s, m->base, m->num, readable, checksum);
469*4882a593Smuzhiyun }
470*4882a593Smuzhiyun
471*4882a593Smuzhiyun /**
472*4882a593Smuzhiyun * validate_mem() - memory probe function
473*4882a593Smuzhiyun * @s: PCMCIA socket to validate
474*4882a593Smuzhiyun * @probe_mask: MEM_PROBE_LOW | MEM_PROBE_HIGH
475*4882a593Smuzhiyun *
476*4882a593Smuzhiyun * The memory probe. If the memory list includes a 64K-aligned block
477*4882a593Smuzhiyun * below 1MB, we probe in 64K chunks, and as soon as we accumulate at
478*4882a593Smuzhiyun * least mem_limit free space, we quit. Returns 0 on usuable ports.
479*4882a593Smuzhiyun */
validate_mem(struct pcmcia_socket * s,unsigned int probe_mask)480*4882a593Smuzhiyun static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask)
481*4882a593Smuzhiyun {
482*4882a593Smuzhiyun struct resource_map *m, mm;
483*4882a593Smuzhiyun static unsigned char order[] = { 0xd0, 0xe0, 0xc0, 0xf0 };
484*4882a593Smuzhiyun unsigned long b, i, ok = 0;
485*4882a593Smuzhiyun struct socket_data *s_data = s->resource_data;
486*4882a593Smuzhiyun
487*4882a593Smuzhiyun /* We do up to four passes through the list */
488*4882a593Smuzhiyun if (probe_mask & MEM_PROBE_HIGH) {
489*4882a593Smuzhiyun if (inv_probe(s_data->mem_db.next, s) > 0)
490*4882a593Smuzhiyun return 0;
491*4882a593Smuzhiyun if (s_data->mem_db_valid.next != &s_data->mem_db_valid)
492*4882a593Smuzhiyun return 0;
493*4882a593Smuzhiyun dev_notice(&s->dev,
494*4882a593Smuzhiyun "cs: warning: no high memory space available!\n");
495*4882a593Smuzhiyun return -ENODEV;
496*4882a593Smuzhiyun }
497*4882a593Smuzhiyun
498*4882a593Smuzhiyun for (m = s_data->mem_db.next; m != &s_data->mem_db; m = mm.next) {
499*4882a593Smuzhiyun mm = *m;
500*4882a593Smuzhiyun /* Only probe < 1 MB */
501*4882a593Smuzhiyun if (mm.base >= 0x100000)
502*4882a593Smuzhiyun continue;
503*4882a593Smuzhiyun if ((mm.base | mm.num) & 0xffff) {
504*4882a593Smuzhiyun ok += do_mem_probe(s, mm.base, mm.num, readable,
505*4882a593Smuzhiyun checksum);
506*4882a593Smuzhiyun continue;
507*4882a593Smuzhiyun }
508*4882a593Smuzhiyun /* Special probe for 64K-aligned block */
509*4882a593Smuzhiyun for (i = 0; i < 4; i++) {
510*4882a593Smuzhiyun b = order[i] << 12;
511*4882a593Smuzhiyun if ((b >= mm.base) && (b+0x10000 <= mm.base+mm.num)) {
512*4882a593Smuzhiyun if (ok >= mem_limit)
513*4882a593Smuzhiyun sub_interval(&s_data->mem_db, b, 0x10000);
514*4882a593Smuzhiyun else
515*4882a593Smuzhiyun ok += do_mem_probe(s, b, 0x10000,
516*4882a593Smuzhiyun readable, checksum);
517*4882a593Smuzhiyun }
518*4882a593Smuzhiyun }
519*4882a593Smuzhiyun }
520*4882a593Smuzhiyun
521*4882a593Smuzhiyun if (ok > 0)
522*4882a593Smuzhiyun return 0;
523*4882a593Smuzhiyun
524*4882a593Smuzhiyun return -ENODEV;
525*4882a593Smuzhiyun }
526*4882a593Smuzhiyun
527*4882a593Smuzhiyun #else /* CONFIG_PCMCIA_PROBE */
528*4882a593Smuzhiyun
529*4882a593Smuzhiyun /**
530*4882a593Smuzhiyun * validate_mem() - memory probe function
531*4882a593Smuzhiyun * @s: PCMCIA socket to validate
532*4882a593Smuzhiyun * @probe_mask: ignored
533*4882a593Smuzhiyun *
534*4882a593Smuzhiyun * Returns 0 on usuable ports.
535*4882a593Smuzhiyun */
validate_mem(struct pcmcia_socket * s,unsigned int probe_mask)536*4882a593Smuzhiyun static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask)
537*4882a593Smuzhiyun {
538*4882a593Smuzhiyun struct resource_map *m, mm;
539*4882a593Smuzhiyun struct socket_data *s_data = s->resource_data;
540*4882a593Smuzhiyun unsigned long ok = 0;
541*4882a593Smuzhiyun
542*4882a593Smuzhiyun for (m = s_data->mem_db.next; m != &s_data->mem_db; m = mm.next) {
543*4882a593Smuzhiyun mm = *m;
544*4882a593Smuzhiyun ok += do_mem_probe(s, mm.base, mm.num, readable, checksum);
545*4882a593Smuzhiyun }
546*4882a593Smuzhiyun if (ok > 0)
547*4882a593Smuzhiyun return 0;
548*4882a593Smuzhiyun return -ENODEV;
549*4882a593Smuzhiyun }
550*4882a593Smuzhiyun
551*4882a593Smuzhiyun #endif /* CONFIG_PCMCIA_PROBE */
552*4882a593Smuzhiyun
553*4882a593Smuzhiyun
554*4882a593Smuzhiyun /**
555*4882a593Smuzhiyun * pcmcia_nonstatic_validate_mem() - try to validate iomem for PCMCIA use
556*4882a593Smuzhiyun * @s: PCMCIA socket to validate
557*4882a593Smuzhiyun *
558*4882a593Smuzhiyun * This is tricky... when we set up CIS memory, we try to validate
559*4882a593Smuzhiyun * the memory window space allocations.
560*4882a593Smuzhiyun *
561*4882a593Smuzhiyun * Locking note: Must be called with skt_mutex held!
562*4882a593Smuzhiyun */
pcmcia_nonstatic_validate_mem(struct pcmcia_socket * s)563*4882a593Smuzhiyun static int pcmcia_nonstatic_validate_mem(struct pcmcia_socket *s)
564*4882a593Smuzhiyun {
565*4882a593Smuzhiyun struct socket_data *s_data = s->resource_data;
566*4882a593Smuzhiyun unsigned int probe_mask = MEM_PROBE_LOW;
567*4882a593Smuzhiyun int ret;
568*4882a593Smuzhiyun
569*4882a593Smuzhiyun if (!probe_mem || !(s->state & SOCKET_PRESENT))
570*4882a593Smuzhiyun return 0;
571*4882a593Smuzhiyun
572*4882a593Smuzhiyun if (s->features & SS_CAP_PAGE_REGS)
573*4882a593Smuzhiyun probe_mask = MEM_PROBE_HIGH;
574*4882a593Smuzhiyun
575*4882a593Smuzhiyun ret = validate_mem(s, probe_mask);
576*4882a593Smuzhiyun
577*4882a593Smuzhiyun if (s_data->mem_db_valid.next != &s_data->mem_db_valid)
578*4882a593Smuzhiyun return 0;
579*4882a593Smuzhiyun
580*4882a593Smuzhiyun return ret;
581*4882a593Smuzhiyun }
582*4882a593Smuzhiyun
583*4882a593Smuzhiyun struct pcmcia_align_data {
584*4882a593Smuzhiyun unsigned long mask;
585*4882a593Smuzhiyun unsigned long offset;
586*4882a593Smuzhiyun struct resource_map *map;
587*4882a593Smuzhiyun };
588*4882a593Smuzhiyun
pcmcia_common_align(struct pcmcia_align_data * align_data,resource_size_t start)589*4882a593Smuzhiyun static resource_size_t pcmcia_common_align(struct pcmcia_align_data *align_data,
590*4882a593Smuzhiyun resource_size_t start)
591*4882a593Smuzhiyun {
592*4882a593Smuzhiyun resource_size_t ret;
593*4882a593Smuzhiyun /*
594*4882a593Smuzhiyun * Ensure that we have the correct start address
595*4882a593Smuzhiyun */
596*4882a593Smuzhiyun ret = (start & ~align_data->mask) + align_data->offset;
597*4882a593Smuzhiyun if (ret < start)
598*4882a593Smuzhiyun ret += align_data->mask + 1;
599*4882a593Smuzhiyun return ret;
600*4882a593Smuzhiyun }
601*4882a593Smuzhiyun
602*4882a593Smuzhiyun static resource_size_t
pcmcia_align(void * align_data,const struct resource * res,resource_size_t size,resource_size_t align)603*4882a593Smuzhiyun pcmcia_align(void *align_data, const struct resource *res,
604*4882a593Smuzhiyun resource_size_t size, resource_size_t align)
605*4882a593Smuzhiyun {
606*4882a593Smuzhiyun struct pcmcia_align_data *data = align_data;
607*4882a593Smuzhiyun struct resource_map *m;
608*4882a593Smuzhiyun resource_size_t start;
609*4882a593Smuzhiyun
610*4882a593Smuzhiyun start = pcmcia_common_align(data, res->start);
611*4882a593Smuzhiyun
612*4882a593Smuzhiyun for (m = data->map->next; m != data->map; m = m->next) {
613*4882a593Smuzhiyun unsigned long map_start = m->base;
614*4882a593Smuzhiyun unsigned long map_end = m->base + m->num - 1;
615*4882a593Smuzhiyun
616*4882a593Smuzhiyun /*
617*4882a593Smuzhiyun * If the lower resources are not available, try aligning
618*4882a593Smuzhiyun * to this entry of the resource database to see if it'll
619*4882a593Smuzhiyun * fit here.
620*4882a593Smuzhiyun */
621*4882a593Smuzhiyun if (start < map_start)
622*4882a593Smuzhiyun start = pcmcia_common_align(data, map_start);
623*4882a593Smuzhiyun
624*4882a593Smuzhiyun /*
625*4882a593Smuzhiyun * If we're above the area which was passed in, there's
626*4882a593Smuzhiyun * no point proceeding.
627*4882a593Smuzhiyun */
628*4882a593Smuzhiyun if (start >= res->end)
629*4882a593Smuzhiyun break;
630*4882a593Smuzhiyun
631*4882a593Smuzhiyun if ((start + size - 1) <= map_end)
632*4882a593Smuzhiyun break;
633*4882a593Smuzhiyun }
634*4882a593Smuzhiyun
635*4882a593Smuzhiyun /*
636*4882a593Smuzhiyun * If we failed to find something suitable, ensure we fail.
637*4882a593Smuzhiyun */
638*4882a593Smuzhiyun if (m == data->map)
639*4882a593Smuzhiyun start = res->end;
640*4882a593Smuzhiyun
641*4882a593Smuzhiyun return start;
642*4882a593Smuzhiyun }
643*4882a593Smuzhiyun
644*4882a593Smuzhiyun /*
645*4882a593Smuzhiyun * Adjust an existing IO region allocation, but making sure that we don't
646*4882a593Smuzhiyun * encroach outside the resources which the user supplied.
647*4882a593Smuzhiyun */
__nonstatic_adjust_io_region(struct pcmcia_socket * s,unsigned long r_start,unsigned long r_end)648*4882a593Smuzhiyun static int __nonstatic_adjust_io_region(struct pcmcia_socket *s,
649*4882a593Smuzhiyun unsigned long r_start,
650*4882a593Smuzhiyun unsigned long r_end)
651*4882a593Smuzhiyun {
652*4882a593Smuzhiyun struct resource_map *m;
653*4882a593Smuzhiyun struct socket_data *s_data = s->resource_data;
654*4882a593Smuzhiyun int ret = -ENOMEM;
655*4882a593Smuzhiyun
656*4882a593Smuzhiyun for (m = s_data->io_db.next; m != &s_data->io_db; m = m->next) {
657*4882a593Smuzhiyun unsigned long start = m->base;
658*4882a593Smuzhiyun unsigned long end = m->base + m->num - 1;
659*4882a593Smuzhiyun
660*4882a593Smuzhiyun if (start > r_start || r_end > end)
661*4882a593Smuzhiyun continue;
662*4882a593Smuzhiyun
663*4882a593Smuzhiyun ret = 0;
664*4882a593Smuzhiyun }
665*4882a593Smuzhiyun
666*4882a593Smuzhiyun return ret;
667*4882a593Smuzhiyun }
668*4882a593Smuzhiyun
669*4882a593Smuzhiyun /*======================================================================
670*4882a593Smuzhiyun
671*4882a593Smuzhiyun These find ranges of I/O ports or memory addresses that are not
672*4882a593Smuzhiyun currently allocated by other devices.
673*4882a593Smuzhiyun
674*4882a593Smuzhiyun The 'align' field should reflect the number of bits of address
675*4882a593Smuzhiyun that need to be preserved from the initial value of *base. It
676*4882a593Smuzhiyun should be a power of two, greater than or equal to 'num'. A value
677*4882a593Smuzhiyun of 0 means that all bits of *base are significant. *base should
678*4882a593Smuzhiyun also be strictly less than 'align'.
679*4882a593Smuzhiyun
680*4882a593Smuzhiyun ======================================================================*/
681*4882a593Smuzhiyun
__nonstatic_find_io_region(struct pcmcia_socket * s,unsigned long base,int num,unsigned long align)682*4882a593Smuzhiyun static struct resource *__nonstatic_find_io_region(struct pcmcia_socket *s,
683*4882a593Smuzhiyun unsigned long base, int num,
684*4882a593Smuzhiyun unsigned long align)
685*4882a593Smuzhiyun {
686*4882a593Smuzhiyun struct resource *res = pcmcia_make_resource(0, num, IORESOURCE_IO,
687*4882a593Smuzhiyun dev_name(&s->dev));
688*4882a593Smuzhiyun struct socket_data *s_data = s->resource_data;
689*4882a593Smuzhiyun struct pcmcia_align_data data;
690*4882a593Smuzhiyun unsigned long min = base;
691*4882a593Smuzhiyun int ret;
692*4882a593Smuzhiyun
693*4882a593Smuzhiyun if (!res)
694*4882a593Smuzhiyun return NULL;
695*4882a593Smuzhiyun
696*4882a593Smuzhiyun data.mask = align - 1;
697*4882a593Smuzhiyun data.offset = base & data.mask;
698*4882a593Smuzhiyun data.map = &s_data->io_db;
699*4882a593Smuzhiyun
700*4882a593Smuzhiyun #ifdef CONFIG_PCI
701*4882a593Smuzhiyun if (s->cb_dev) {
702*4882a593Smuzhiyun ret = pci_bus_alloc_resource(s->cb_dev->bus, res, num, 1,
703*4882a593Smuzhiyun min, 0, pcmcia_align, &data);
704*4882a593Smuzhiyun } else
705*4882a593Smuzhiyun #endif
706*4882a593Smuzhiyun ret = allocate_resource(&ioport_resource, res, num, min, ~0UL,
707*4882a593Smuzhiyun 1, pcmcia_align, &data);
708*4882a593Smuzhiyun
709*4882a593Smuzhiyun if (ret != 0) {
710*4882a593Smuzhiyun kfree(res);
711*4882a593Smuzhiyun res = NULL;
712*4882a593Smuzhiyun }
713*4882a593Smuzhiyun return res;
714*4882a593Smuzhiyun }
715*4882a593Smuzhiyun
nonstatic_find_io(struct pcmcia_socket * s,unsigned int attr,unsigned int * base,unsigned int num,unsigned int align,struct resource ** parent)716*4882a593Smuzhiyun static int nonstatic_find_io(struct pcmcia_socket *s, unsigned int attr,
717*4882a593Smuzhiyun unsigned int *base, unsigned int num,
718*4882a593Smuzhiyun unsigned int align, struct resource **parent)
719*4882a593Smuzhiyun {
720*4882a593Smuzhiyun int i, ret = 0;
721*4882a593Smuzhiyun
722*4882a593Smuzhiyun /* Check for an already-allocated window that must conflict with
723*4882a593Smuzhiyun * what was asked for. It is a hack because it does not catch all
724*4882a593Smuzhiyun * potential conflicts, just the most obvious ones.
725*4882a593Smuzhiyun */
726*4882a593Smuzhiyun for (i = 0; i < MAX_IO_WIN; i++) {
727*4882a593Smuzhiyun if (!s->io[i].res)
728*4882a593Smuzhiyun continue;
729*4882a593Smuzhiyun
730*4882a593Smuzhiyun if (!*base)
731*4882a593Smuzhiyun continue;
732*4882a593Smuzhiyun
733*4882a593Smuzhiyun if ((s->io[i].res->start & (align-1)) == *base)
734*4882a593Smuzhiyun return -EBUSY;
735*4882a593Smuzhiyun }
736*4882a593Smuzhiyun
737*4882a593Smuzhiyun for (i = 0; i < MAX_IO_WIN; i++) {
738*4882a593Smuzhiyun struct resource *res = s->io[i].res;
739*4882a593Smuzhiyun unsigned int try;
740*4882a593Smuzhiyun
741*4882a593Smuzhiyun if (res && (res->flags & IORESOURCE_BITS) !=
742*4882a593Smuzhiyun (attr & IORESOURCE_BITS))
743*4882a593Smuzhiyun continue;
744*4882a593Smuzhiyun
745*4882a593Smuzhiyun if (!res) {
746*4882a593Smuzhiyun if (align == 0)
747*4882a593Smuzhiyun align = 0x10000;
748*4882a593Smuzhiyun
749*4882a593Smuzhiyun res = s->io[i].res = __nonstatic_find_io_region(s,
750*4882a593Smuzhiyun *base, num,
751*4882a593Smuzhiyun align);
752*4882a593Smuzhiyun if (!res)
753*4882a593Smuzhiyun return -EINVAL;
754*4882a593Smuzhiyun
755*4882a593Smuzhiyun *base = res->start;
756*4882a593Smuzhiyun s->io[i].res->flags =
757*4882a593Smuzhiyun ((res->flags & ~IORESOURCE_BITS) |
758*4882a593Smuzhiyun (attr & IORESOURCE_BITS));
759*4882a593Smuzhiyun s->io[i].InUse = num;
760*4882a593Smuzhiyun *parent = res;
761*4882a593Smuzhiyun return 0;
762*4882a593Smuzhiyun }
763*4882a593Smuzhiyun
764*4882a593Smuzhiyun /* Try to extend top of window */
765*4882a593Smuzhiyun try = res->end + 1;
766*4882a593Smuzhiyun if ((*base == 0) || (*base == try)) {
767*4882a593Smuzhiyun ret = __nonstatic_adjust_io_region(s, res->start,
768*4882a593Smuzhiyun res->end + num);
769*4882a593Smuzhiyun if (!ret) {
770*4882a593Smuzhiyun ret = adjust_resource(s->io[i].res, res->start,
771*4882a593Smuzhiyun resource_size(res) + num);
772*4882a593Smuzhiyun if (ret)
773*4882a593Smuzhiyun continue;
774*4882a593Smuzhiyun *base = try;
775*4882a593Smuzhiyun s->io[i].InUse += num;
776*4882a593Smuzhiyun *parent = res;
777*4882a593Smuzhiyun return 0;
778*4882a593Smuzhiyun }
779*4882a593Smuzhiyun }
780*4882a593Smuzhiyun
781*4882a593Smuzhiyun /* Try to extend bottom of window */
782*4882a593Smuzhiyun try = res->start - num;
783*4882a593Smuzhiyun if ((*base == 0) || (*base == try)) {
784*4882a593Smuzhiyun ret = __nonstatic_adjust_io_region(s,
785*4882a593Smuzhiyun res->start - num,
786*4882a593Smuzhiyun res->end);
787*4882a593Smuzhiyun if (!ret) {
788*4882a593Smuzhiyun ret = adjust_resource(s->io[i].res,
789*4882a593Smuzhiyun res->start - num,
790*4882a593Smuzhiyun resource_size(res) + num);
791*4882a593Smuzhiyun if (ret)
792*4882a593Smuzhiyun continue;
793*4882a593Smuzhiyun *base = try;
794*4882a593Smuzhiyun s->io[i].InUse += num;
795*4882a593Smuzhiyun *parent = res;
796*4882a593Smuzhiyun return 0;
797*4882a593Smuzhiyun }
798*4882a593Smuzhiyun }
799*4882a593Smuzhiyun }
800*4882a593Smuzhiyun
801*4882a593Smuzhiyun return -EINVAL;
802*4882a593Smuzhiyun }
803*4882a593Smuzhiyun
804*4882a593Smuzhiyun
nonstatic_find_mem_region(u_long base,u_long num,u_long align,int low,struct pcmcia_socket * s)805*4882a593Smuzhiyun static struct resource *nonstatic_find_mem_region(u_long base, u_long num,
806*4882a593Smuzhiyun u_long align, int low, struct pcmcia_socket *s)
807*4882a593Smuzhiyun {
808*4882a593Smuzhiyun struct resource *res = pcmcia_make_resource(0, num, IORESOURCE_MEM,
809*4882a593Smuzhiyun dev_name(&s->dev));
810*4882a593Smuzhiyun struct socket_data *s_data = s->resource_data;
811*4882a593Smuzhiyun struct pcmcia_align_data data;
812*4882a593Smuzhiyun unsigned long min, max;
813*4882a593Smuzhiyun int ret, i, j;
814*4882a593Smuzhiyun
815*4882a593Smuzhiyun if (!res)
816*4882a593Smuzhiyun return NULL;
817*4882a593Smuzhiyun
818*4882a593Smuzhiyun low = low || !(s->features & SS_CAP_PAGE_REGS);
819*4882a593Smuzhiyun
820*4882a593Smuzhiyun data.mask = align - 1;
821*4882a593Smuzhiyun data.offset = base & data.mask;
822*4882a593Smuzhiyun
823*4882a593Smuzhiyun for (i = 0; i < 2; i++) {
824*4882a593Smuzhiyun data.map = &s_data->mem_db_valid;
825*4882a593Smuzhiyun if (low) {
826*4882a593Smuzhiyun max = 0x100000UL;
827*4882a593Smuzhiyun min = base < max ? base : 0;
828*4882a593Smuzhiyun } else {
829*4882a593Smuzhiyun max = ~0UL;
830*4882a593Smuzhiyun min = 0x100000UL + base;
831*4882a593Smuzhiyun }
832*4882a593Smuzhiyun
833*4882a593Smuzhiyun for (j = 0; j < 2; j++) {
834*4882a593Smuzhiyun #ifdef CONFIG_PCI
835*4882a593Smuzhiyun if (s->cb_dev) {
836*4882a593Smuzhiyun ret = pci_bus_alloc_resource(s->cb_dev->bus,
837*4882a593Smuzhiyun res, num, 1, min, 0,
838*4882a593Smuzhiyun pcmcia_align, &data);
839*4882a593Smuzhiyun } else
840*4882a593Smuzhiyun #endif
841*4882a593Smuzhiyun {
842*4882a593Smuzhiyun ret = allocate_resource(&iomem_resource,
843*4882a593Smuzhiyun res, num, min, max, 1,
844*4882a593Smuzhiyun pcmcia_align, &data);
845*4882a593Smuzhiyun }
846*4882a593Smuzhiyun if (ret == 0)
847*4882a593Smuzhiyun break;
848*4882a593Smuzhiyun data.map = &s_data->mem_db;
849*4882a593Smuzhiyun }
850*4882a593Smuzhiyun if (ret == 0 || low)
851*4882a593Smuzhiyun break;
852*4882a593Smuzhiyun low = 1;
853*4882a593Smuzhiyun }
854*4882a593Smuzhiyun
855*4882a593Smuzhiyun if (ret != 0) {
856*4882a593Smuzhiyun kfree(res);
857*4882a593Smuzhiyun res = NULL;
858*4882a593Smuzhiyun }
859*4882a593Smuzhiyun return res;
860*4882a593Smuzhiyun }
861*4882a593Smuzhiyun
862*4882a593Smuzhiyun
adjust_memory(struct pcmcia_socket * s,unsigned int action,unsigned long start,unsigned long end)863*4882a593Smuzhiyun static int adjust_memory(struct pcmcia_socket *s, unsigned int action, unsigned long start, unsigned long end)
864*4882a593Smuzhiyun {
865*4882a593Smuzhiyun struct socket_data *data = s->resource_data;
866*4882a593Smuzhiyun unsigned long size = end - start + 1;
867*4882a593Smuzhiyun int ret = 0;
868*4882a593Smuzhiyun
869*4882a593Smuzhiyun if (end < start)
870*4882a593Smuzhiyun return -EINVAL;
871*4882a593Smuzhiyun
872*4882a593Smuzhiyun switch (action) {
873*4882a593Smuzhiyun case ADD_MANAGED_RESOURCE:
874*4882a593Smuzhiyun ret = add_interval(&data->mem_db, start, size);
875*4882a593Smuzhiyun if (!ret)
876*4882a593Smuzhiyun do_mem_probe(s, start, size, NULL, NULL);
877*4882a593Smuzhiyun break;
878*4882a593Smuzhiyun case REMOVE_MANAGED_RESOURCE:
879*4882a593Smuzhiyun ret = sub_interval(&data->mem_db, start, size);
880*4882a593Smuzhiyun break;
881*4882a593Smuzhiyun default:
882*4882a593Smuzhiyun ret = -EINVAL;
883*4882a593Smuzhiyun }
884*4882a593Smuzhiyun
885*4882a593Smuzhiyun return ret;
886*4882a593Smuzhiyun }
887*4882a593Smuzhiyun
888*4882a593Smuzhiyun
adjust_io(struct pcmcia_socket * s,unsigned int action,unsigned long start,unsigned long end)889*4882a593Smuzhiyun static int adjust_io(struct pcmcia_socket *s, unsigned int action, unsigned long start, unsigned long end)
890*4882a593Smuzhiyun {
891*4882a593Smuzhiyun struct socket_data *data = s->resource_data;
892*4882a593Smuzhiyun unsigned long size;
893*4882a593Smuzhiyun int ret = 0;
894*4882a593Smuzhiyun
895*4882a593Smuzhiyun #if defined(CONFIG_X86)
896*4882a593Smuzhiyun /* on x86, avoid anything < 0x100 for it is often used for
897*4882a593Smuzhiyun * legacy platform devices */
898*4882a593Smuzhiyun if (start < 0x100)
899*4882a593Smuzhiyun start = 0x100;
900*4882a593Smuzhiyun #endif
901*4882a593Smuzhiyun
902*4882a593Smuzhiyun size = end - start + 1;
903*4882a593Smuzhiyun
904*4882a593Smuzhiyun if (end < start)
905*4882a593Smuzhiyun return -EINVAL;
906*4882a593Smuzhiyun
907*4882a593Smuzhiyun if (end > IO_SPACE_LIMIT)
908*4882a593Smuzhiyun return -EINVAL;
909*4882a593Smuzhiyun
910*4882a593Smuzhiyun switch (action) {
911*4882a593Smuzhiyun case ADD_MANAGED_RESOURCE:
912*4882a593Smuzhiyun if (add_interval(&data->io_db, start, size) != 0) {
913*4882a593Smuzhiyun ret = -EBUSY;
914*4882a593Smuzhiyun break;
915*4882a593Smuzhiyun }
916*4882a593Smuzhiyun #ifdef CONFIG_PCMCIA_PROBE
917*4882a593Smuzhiyun if (probe_io)
918*4882a593Smuzhiyun do_io_probe(s, start, size);
919*4882a593Smuzhiyun #endif
920*4882a593Smuzhiyun break;
921*4882a593Smuzhiyun case REMOVE_MANAGED_RESOURCE:
922*4882a593Smuzhiyun sub_interval(&data->io_db, start, size);
923*4882a593Smuzhiyun break;
924*4882a593Smuzhiyun default:
925*4882a593Smuzhiyun ret = -EINVAL;
926*4882a593Smuzhiyun break;
927*4882a593Smuzhiyun }
928*4882a593Smuzhiyun
929*4882a593Smuzhiyun return ret;
930*4882a593Smuzhiyun }
931*4882a593Smuzhiyun
932*4882a593Smuzhiyun
933*4882a593Smuzhiyun #ifdef CONFIG_PCI
nonstatic_autoadd_resources(struct pcmcia_socket * s)934*4882a593Smuzhiyun static int nonstatic_autoadd_resources(struct pcmcia_socket *s)
935*4882a593Smuzhiyun {
936*4882a593Smuzhiyun struct resource *res;
937*4882a593Smuzhiyun int i, done = 0;
938*4882a593Smuzhiyun
939*4882a593Smuzhiyun if (!s->cb_dev || !s->cb_dev->bus)
940*4882a593Smuzhiyun return -ENODEV;
941*4882a593Smuzhiyun
942*4882a593Smuzhiyun #if defined(CONFIG_X86)
943*4882a593Smuzhiyun /* If this is the root bus, the risk of hitting some strange
944*4882a593Smuzhiyun * system devices is too high: If a driver isn't loaded, the
945*4882a593Smuzhiyun * resources are not claimed; even if a driver is loaded, it
946*4882a593Smuzhiyun * may not request all resources or even the wrong one. We
947*4882a593Smuzhiyun * can neither trust the rest of the kernel nor ACPI/PNP and
948*4882a593Smuzhiyun * CRS parsing to get it right. Therefore, use several
949*4882a593Smuzhiyun * safeguards:
950*4882a593Smuzhiyun *
951*4882a593Smuzhiyun * - Do not auto-add resources if the CardBus bridge is on
952*4882a593Smuzhiyun * the PCI root bus
953*4882a593Smuzhiyun *
954*4882a593Smuzhiyun * - Avoid any I/O ports < 0x100.
955*4882a593Smuzhiyun *
956*4882a593Smuzhiyun * - On PCI-PCI bridges, only use resources which are set up
957*4882a593Smuzhiyun * exclusively for the secondary PCI bus: the risk of hitting
958*4882a593Smuzhiyun * system devices is quite low, as they usually aren't
959*4882a593Smuzhiyun * connected to the secondary PCI bus.
960*4882a593Smuzhiyun */
961*4882a593Smuzhiyun if (s->cb_dev->bus->number == 0)
962*4882a593Smuzhiyun return -EINVAL;
963*4882a593Smuzhiyun
964*4882a593Smuzhiyun for (i = 0; i < PCI_BRIDGE_RESOURCE_NUM; i++) {
965*4882a593Smuzhiyun res = s->cb_dev->bus->resource[i];
966*4882a593Smuzhiyun #else
967*4882a593Smuzhiyun pci_bus_for_each_resource(s->cb_dev->bus, res, i) {
968*4882a593Smuzhiyun #endif
969*4882a593Smuzhiyun if (!res)
970*4882a593Smuzhiyun continue;
971*4882a593Smuzhiyun
972*4882a593Smuzhiyun if (res->flags & IORESOURCE_IO) {
973*4882a593Smuzhiyun /* safeguard against the root resource, where the
974*4882a593Smuzhiyun * risk of hitting any other device would be too
975*4882a593Smuzhiyun * high */
976*4882a593Smuzhiyun if (res == &ioport_resource)
977*4882a593Smuzhiyun continue;
978*4882a593Smuzhiyun
979*4882a593Smuzhiyun dev_info(&s->cb_dev->dev,
980*4882a593Smuzhiyun "pcmcia: parent PCI bridge window: %pR\n",
981*4882a593Smuzhiyun res);
982*4882a593Smuzhiyun if (!adjust_io(s, ADD_MANAGED_RESOURCE, res->start, res->end))
983*4882a593Smuzhiyun done |= IORESOURCE_IO;
984*4882a593Smuzhiyun
985*4882a593Smuzhiyun }
986*4882a593Smuzhiyun
987*4882a593Smuzhiyun if (res->flags & IORESOURCE_MEM) {
988*4882a593Smuzhiyun /* safeguard against the root resource, where the
989*4882a593Smuzhiyun * risk of hitting any other device would be too
990*4882a593Smuzhiyun * high */
991*4882a593Smuzhiyun if (res == &iomem_resource)
992*4882a593Smuzhiyun continue;
993*4882a593Smuzhiyun
994*4882a593Smuzhiyun dev_info(&s->cb_dev->dev,
995*4882a593Smuzhiyun "pcmcia: parent PCI bridge window: %pR\n",
996*4882a593Smuzhiyun res);
997*4882a593Smuzhiyun if (!adjust_memory(s, ADD_MANAGED_RESOURCE, res->start, res->end))
998*4882a593Smuzhiyun done |= IORESOURCE_MEM;
999*4882a593Smuzhiyun }
1000*4882a593Smuzhiyun }
1001*4882a593Smuzhiyun
1002*4882a593Smuzhiyun /* if we got at least one of IO, and one of MEM, we can be glad and
1003*4882a593Smuzhiyun * activate the PCMCIA subsystem */
1004*4882a593Smuzhiyun if (done == (IORESOURCE_MEM | IORESOURCE_IO))
1005*4882a593Smuzhiyun s->resource_setup_done = 1;
1006*4882a593Smuzhiyun
1007*4882a593Smuzhiyun return 0;
1008*4882a593Smuzhiyun }
1009*4882a593Smuzhiyun
1010*4882a593Smuzhiyun #else
1011*4882a593Smuzhiyun
1012*4882a593Smuzhiyun static inline int nonstatic_autoadd_resources(struct pcmcia_socket *s)
1013*4882a593Smuzhiyun {
1014*4882a593Smuzhiyun return -ENODEV;
1015*4882a593Smuzhiyun }
1016*4882a593Smuzhiyun
1017*4882a593Smuzhiyun #endif
1018*4882a593Smuzhiyun
1019*4882a593Smuzhiyun
1020*4882a593Smuzhiyun static int nonstatic_init(struct pcmcia_socket *s)
1021*4882a593Smuzhiyun {
1022*4882a593Smuzhiyun struct socket_data *data;
1023*4882a593Smuzhiyun
1024*4882a593Smuzhiyun data = kzalloc(sizeof(struct socket_data), GFP_KERNEL);
1025*4882a593Smuzhiyun if (!data)
1026*4882a593Smuzhiyun return -ENOMEM;
1027*4882a593Smuzhiyun
1028*4882a593Smuzhiyun data->mem_db.next = &data->mem_db;
1029*4882a593Smuzhiyun data->mem_db_valid.next = &data->mem_db_valid;
1030*4882a593Smuzhiyun data->io_db.next = &data->io_db;
1031*4882a593Smuzhiyun
1032*4882a593Smuzhiyun s->resource_data = (void *) data;
1033*4882a593Smuzhiyun
1034*4882a593Smuzhiyun nonstatic_autoadd_resources(s);
1035*4882a593Smuzhiyun
1036*4882a593Smuzhiyun return 0;
1037*4882a593Smuzhiyun }
1038*4882a593Smuzhiyun
1039*4882a593Smuzhiyun static void nonstatic_release_resource_db(struct pcmcia_socket *s)
1040*4882a593Smuzhiyun {
1041*4882a593Smuzhiyun struct socket_data *data = s->resource_data;
1042*4882a593Smuzhiyun struct resource_map *p, *q;
1043*4882a593Smuzhiyun
1044*4882a593Smuzhiyun for (p = data->mem_db_valid.next; p != &data->mem_db_valid; p = q) {
1045*4882a593Smuzhiyun q = p->next;
1046*4882a593Smuzhiyun kfree(p);
1047*4882a593Smuzhiyun }
1048*4882a593Smuzhiyun for (p = data->mem_db.next; p != &data->mem_db; p = q) {
1049*4882a593Smuzhiyun q = p->next;
1050*4882a593Smuzhiyun kfree(p);
1051*4882a593Smuzhiyun }
1052*4882a593Smuzhiyun for (p = data->io_db.next; p != &data->io_db; p = q) {
1053*4882a593Smuzhiyun q = p->next;
1054*4882a593Smuzhiyun kfree(p);
1055*4882a593Smuzhiyun }
1056*4882a593Smuzhiyun }
1057*4882a593Smuzhiyun
1058*4882a593Smuzhiyun
1059*4882a593Smuzhiyun struct pccard_resource_ops pccard_nonstatic_ops = {
1060*4882a593Smuzhiyun .validate_mem = pcmcia_nonstatic_validate_mem,
1061*4882a593Smuzhiyun .find_io = nonstatic_find_io,
1062*4882a593Smuzhiyun .find_mem = nonstatic_find_mem_region,
1063*4882a593Smuzhiyun .init = nonstatic_init,
1064*4882a593Smuzhiyun .exit = nonstatic_release_resource_db,
1065*4882a593Smuzhiyun };
1066*4882a593Smuzhiyun EXPORT_SYMBOL(pccard_nonstatic_ops);
1067*4882a593Smuzhiyun
1068*4882a593Smuzhiyun
1069*4882a593Smuzhiyun /* sysfs interface to the resource database */
1070*4882a593Smuzhiyun
1071*4882a593Smuzhiyun static ssize_t show_io_db(struct device *dev,
1072*4882a593Smuzhiyun struct device_attribute *attr, char *buf)
1073*4882a593Smuzhiyun {
1074*4882a593Smuzhiyun struct pcmcia_socket *s = dev_get_drvdata(dev);
1075*4882a593Smuzhiyun struct socket_data *data;
1076*4882a593Smuzhiyun struct resource_map *p;
1077*4882a593Smuzhiyun ssize_t ret = 0;
1078*4882a593Smuzhiyun
1079*4882a593Smuzhiyun mutex_lock(&s->ops_mutex);
1080*4882a593Smuzhiyun data = s->resource_data;
1081*4882a593Smuzhiyun
1082*4882a593Smuzhiyun for (p = data->io_db.next; p != &data->io_db; p = p->next) {
1083*4882a593Smuzhiyun if (ret > (PAGE_SIZE - 10))
1084*4882a593Smuzhiyun continue;
1085*4882a593Smuzhiyun ret += scnprintf(&buf[ret], (PAGE_SIZE - ret - 1),
1086*4882a593Smuzhiyun "0x%08lx - 0x%08lx\n",
1087*4882a593Smuzhiyun ((unsigned long) p->base),
1088*4882a593Smuzhiyun ((unsigned long) p->base + p->num - 1));
1089*4882a593Smuzhiyun }
1090*4882a593Smuzhiyun
1091*4882a593Smuzhiyun mutex_unlock(&s->ops_mutex);
1092*4882a593Smuzhiyun return ret;
1093*4882a593Smuzhiyun }
1094*4882a593Smuzhiyun
1095*4882a593Smuzhiyun static ssize_t store_io_db(struct device *dev,
1096*4882a593Smuzhiyun struct device_attribute *attr,
1097*4882a593Smuzhiyun const char *buf, size_t count)
1098*4882a593Smuzhiyun {
1099*4882a593Smuzhiyun struct pcmcia_socket *s = dev_get_drvdata(dev);
1100*4882a593Smuzhiyun unsigned long start_addr, end_addr;
1101*4882a593Smuzhiyun unsigned int add = ADD_MANAGED_RESOURCE;
1102*4882a593Smuzhiyun ssize_t ret = 0;
1103*4882a593Smuzhiyun
1104*4882a593Smuzhiyun ret = sscanf(buf, "+ 0x%lx - 0x%lx", &start_addr, &end_addr);
1105*4882a593Smuzhiyun if (ret != 2) {
1106*4882a593Smuzhiyun ret = sscanf(buf, "- 0x%lx - 0x%lx", &start_addr, &end_addr);
1107*4882a593Smuzhiyun add = REMOVE_MANAGED_RESOURCE;
1108*4882a593Smuzhiyun if (ret != 2) {
1109*4882a593Smuzhiyun ret = sscanf(buf, "0x%lx - 0x%lx", &start_addr,
1110*4882a593Smuzhiyun &end_addr);
1111*4882a593Smuzhiyun add = ADD_MANAGED_RESOURCE;
1112*4882a593Smuzhiyun if (ret != 2)
1113*4882a593Smuzhiyun return -EINVAL;
1114*4882a593Smuzhiyun }
1115*4882a593Smuzhiyun }
1116*4882a593Smuzhiyun if (end_addr < start_addr)
1117*4882a593Smuzhiyun return -EINVAL;
1118*4882a593Smuzhiyun
1119*4882a593Smuzhiyun mutex_lock(&s->ops_mutex);
1120*4882a593Smuzhiyun ret = adjust_io(s, add, start_addr, end_addr);
1121*4882a593Smuzhiyun mutex_unlock(&s->ops_mutex);
1122*4882a593Smuzhiyun
1123*4882a593Smuzhiyun return ret ? ret : count;
1124*4882a593Smuzhiyun }
1125*4882a593Smuzhiyun static DEVICE_ATTR(available_resources_io, 0600, show_io_db, store_io_db);
1126*4882a593Smuzhiyun
1127*4882a593Smuzhiyun static ssize_t show_mem_db(struct device *dev,
1128*4882a593Smuzhiyun struct device_attribute *attr, char *buf)
1129*4882a593Smuzhiyun {
1130*4882a593Smuzhiyun struct pcmcia_socket *s = dev_get_drvdata(dev);
1131*4882a593Smuzhiyun struct socket_data *data;
1132*4882a593Smuzhiyun struct resource_map *p;
1133*4882a593Smuzhiyun ssize_t ret = 0;
1134*4882a593Smuzhiyun
1135*4882a593Smuzhiyun mutex_lock(&s->ops_mutex);
1136*4882a593Smuzhiyun data = s->resource_data;
1137*4882a593Smuzhiyun
1138*4882a593Smuzhiyun for (p = data->mem_db_valid.next; p != &data->mem_db_valid;
1139*4882a593Smuzhiyun p = p->next) {
1140*4882a593Smuzhiyun if (ret > (PAGE_SIZE - 10))
1141*4882a593Smuzhiyun continue;
1142*4882a593Smuzhiyun ret += scnprintf(&buf[ret], (PAGE_SIZE - ret - 1),
1143*4882a593Smuzhiyun "0x%08lx - 0x%08lx\n",
1144*4882a593Smuzhiyun ((unsigned long) p->base),
1145*4882a593Smuzhiyun ((unsigned long) p->base + p->num - 1));
1146*4882a593Smuzhiyun }
1147*4882a593Smuzhiyun
1148*4882a593Smuzhiyun for (p = data->mem_db.next; p != &data->mem_db; p = p->next) {
1149*4882a593Smuzhiyun if (ret > (PAGE_SIZE - 10))
1150*4882a593Smuzhiyun continue;
1151*4882a593Smuzhiyun ret += scnprintf(&buf[ret], (PAGE_SIZE - ret - 1),
1152*4882a593Smuzhiyun "0x%08lx - 0x%08lx\n",
1153*4882a593Smuzhiyun ((unsigned long) p->base),
1154*4882a593Smuzhiyun ((unsigned long) p->base + p->num - 1));
1155*4882a593Smuzhiyun }
1156*4882a593Smuzhiyun
1157*4882a593Smuzhiyun mutex_unlock(&s->ops_mutex);
1158*4882a593Smuzhiyun return ret;
1159*4882a593Smuzhiyun }
1160*4882a593Smuzhiyun
1161*4882a593Smuzhiyun static ssize_t store_mem_db(struct device *dev,
1162*4882a593Smuzhiyun struct device_attribute *attr,
1163*4882a593Smuzhiyun const char *buf, size_t count)
1164*4882a593Smuzhiyun {
1165*4882a593Smuzhiyun struct pcmcia_socket *s = dev_get_drvdata(dev);
1166*4882a593Smuzhiyun unsigned long start_addr, end_addr;
1167*4882a593Smuzhiyun unsigned int add = ADD_MANAGED_RESOURCE;
1168*4882a593Smuzhiyun ssize_t ret = 0;
1169*4882a593Smuzhiyun
1170*4882a593Smuzhiyun ret = sscanf(buf, "+ 0x%lx - 0x%lx", &start_addr, &end_addr);
1171*4882a593Smuzhiyun if (ret != 2) {
1172*4882a593Smuzhiyun ret = sscanf(buf, "- 0x%lx - 0x%lx", &start_addr, &end_addr);
1173*4882a593Smuzhiyun add = REMOVE_MANAGED_RESOURCE;
1174*4882a593Smuzhiyun if (ret != 2) {
1175*4882a593Smuzhiyun ret = sscanf(buf, "0x%lx - 0x%lx", &start_addr,
1176*4882a593Smuzhiyun &end_addr);
1177*4882a593Smuzhiyun add = ADD_MANAGED_RESOURCE;
1178*4882a593Smuzhiyun if (ret != 2)
1179*4882a593Smuzhiyun return -EINVAL;
1180*4882a593Smuzhiyun }
1181*4882a593Smuzhiyun }
1182*4882a593Smuzhiyun if (end_addr < start_addr)
1183*4882a593Smuzhiyun return -EINVAL;
1184*4882a593Smuzhiyun
1185*4882a593Smuzhiyun mutex_lock(&s->ops_mutex);
1186*4882a593Smuzhiyun ret = adjust_memory(s, add, start_addr, end_addr);
1187*4882a593Smuzhiyun mutex_unlock(&s->ops_mutex);
1188*4882a593Smuzhiyun
1189*4882a593Smuzhiyun return ret ? ret : count;
1190*4882a593Smuzhiyun }
1191*4882a593Smuzhiyun static DEVICE_ATTR(available_resources_mem, 0600, show_mem_db, store_mem_db);
1192*4882a593Smuzhiyun
1193*4882a593Smuzhiyun static struct attribute *pccard_rsrc_attributes[] = {
1194*4882a593Smuzhiyun &dev_attr_available_resources_io.attr,
1195*4882a593Smuzhiyun &dev_attr_available_resources_mem.attr,
1196*4882a593Smuzhiyun NULL,
1197*4882a593Smuzhiyun };
1198*4882a593Smuzhiyun
1199*4882a593Smuzhiyun static const struct attribute_group rsrc_attributes = {
1200*4882a593Smuzhiyun .attrs = pccard_rsrc_attributes,
1201*4882a593Smuzhiyun };
1202*4882a593Smuzhiyun
1203*4882a593Smuzhiyun static int pccard_sysfs_add_rsrc(struct device *dev,
1204*4882a593Smuzhiyun struct class_interface *class_intf)
1205*4882a593Smuzhiyun {
1206*4882a593Smuzhiyun struct pcmcia_socket *s = dev_get_drvdata(dev);
1207*4882a593Smuzhiyun
1208*4882a593Smuzhiyun if (s->resource_ops != &pccard_nonstatic_ops)
1209*4882a593Smuzhiyun return 0;
1210*4882a593Smuzhiyun return sysfs_create_group(&dev->kobj, &rsrc_attributes);
1211*4882a593Smuzhiyun }
1212*4882a593Smuzhiyun
1213*4882a593Smuzhiyun static void pccard_sysfs_remove_rsrc(struct device *dev,
1214*4882a593Smuzhiyun struct class_interface *class_intf)
1215*4882a593Smuzhiyun {
1216*4882a593Smuzhiyun struct pcmcia_socket *s = dev_get_drvdata(dev);
1217*4882a593Smuzhiyun
1218*4882a593Smuzhiyun if (s->resource_ops != &pccard_nonstatic_ops)
1219*4882a593Smuzhiyun return;
1220*4882a593Smuzhiyun sysfs_remove_group(&dev->kobj, &rsrc_attributes);
1221*4882a593Smuzhiyun }
1222*4882a593Smuzhiyun
1223*4882a593Smuzhiyun static struct class_interface pccard_rsrc_interface __refdata = {
1224*4882a593Smuzhiyun .class = &pcmcia_socket_class,
1225*4882a593Smuzhiyun .add_dev = &pccard_sysfs_add_rsrc,
1226*4882a593Smuzhiyun .remove_dev = &pccard_sysfs_remove_rsrc,
1227*4882a593Smuzhiyun };
1228*4882a593Smuzhiyun
1229*4882a593Smuzhiyun static int __init nonstatic_sysfs_init(void)
1230*4882a593Smuzhiyun {
1231*4882a593Smuzhiyun return class_interface_register(&pccard_rsrc_interface);
1232*4882a593Smuzhiyun }
1233*4882a593Smuzhiyun
1234*4882a593Smuzhiyun static void __exit nonstatic_sysfs_exit(void)
1235*4882a593Smuzhiyun {
1236*4882a593Smuzhiyun class_interface_unregister(&pccard_rsrc_interface);
1237*4882a593Smuzhiyun }
1238*4882a593Smuzhiyun
1239*4882a593Smuzhiyun module_init(nonstatic_sysfs_init);
1240*4882a593Smuzhiyun module_exit(nonstatic_sysfs_exit);
1241