Blame view

drivers/pcmcia/rsrc_iodyn.c 3.6 KB
d2912cb15   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
49b1153ad   Dominik Brodowski   pcmcia: move all ...
2
3
4
  /*
   * rsrc_iodyn.c -- Resource management routines for MEM-static sockets.
   *
49b1153ad   Dominik Brodowski   pcmcia: move all ...
5
6
7
8
9
10
   * The initial developer of the original code is David A. Hinds
   * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
   * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
   *
   * (C) 1999		David A. Hinds
   */
6d59622e5   Tejun Heo   pcmcia: update gf...
11
  #include <linux/slab.h>
49b1153ad   Dominik Brodowski   pcmcia: move all ...
12
13
  #include <linux/module.h>
  #include <linux/kernel.h>
49b1153ad   Dominik Brodowski   pcmcia: move all ...
14
  #include <pcmcia/ss.h>
49b1153ad   Dominik Brodowski   pcmcia: move all ...
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
  #include <pcmcia/cistpl.h>
  #include "cs_internal.h"
  
  
  struct pcmcia_align_data {
  	unsigned long	mask;
  	unsigned long	offset;
  };
  
  static resource_size_t pcmcia_align(void *align_data,
  				const struct resource *res,
  				resource_size_t size, resource_size_t align)
  {
  	struct pcmcia_align_data *data = align_data;
  	resource_size_t start;
  
  	start = (res->start & ~data->mask) + data->offset;
  	if (start < res->start)
  		start += data->mask + 1;
  
  #ifdef CONFIG_X86
  	if (res->flags & IORESOURCE_IO) {
  		if (start & 0x300)
  			start = (start + 0x3ff) & ~0x3ff;
  	}
  #endif
  
  #ifdef CONFIG_M68K
  	if (res->flags & IORESOURCE_IO) {
  		if ((res->start + size - 1) >= 1024)
  			start = res->end;
  	}
  #endif
  
  	return start;
  }
b19a7275d   Dominik Brodowski   pcmcia: clarify a...
51
52
53
  static struct resource *__iodyn_find_io_region(struct pcmcia_socket *s,
  					unsigned long base, int num,
  					unsigned long align)
49b1153ad   Dominik Brodowski   pcmcia: move all ...
54
55
56
57
58
59
  {
  	struct resource *res = pcmcia_make_resource(0, num, IORESOURCE_IO,
  						dev_name(&s->dev));
  	struct pcmcia_align_data data;
  	unsigned long min = base;
  	int ret;
49b1153ad   Dominik Brodowski   pcmcia: move all ...
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
  	data.mask = align - 1;
  	data.offset = base & data.mask;
  
  #ifdef CONFIG_PCI
  	if (s->cb_dev) {
  		ret = pci_bus_alloc_resource(s->cb_dev->bus, res, num, 1,
  					     min, 0, pcmcia_align, &data);
  	} else
  #endif
  		ret = allocate_resource(&ioport_resource, res, num, min, ~0UL,
  					1, pcmcia_align, &data);
  
  	if (ret != 0) {
  		kfree(res);
  		res = NULL;
  	}
  	return res;
  }
b19a7275d   Dominik Brodowski   pcmcia: clarify a...
78
79
  static int iodyn_find_io(struct pcmcia_socket *s, unsigned int attr,
  			unsigned int *base, unsigned int num,
ad0c7be28   Dominik Brodowski   pcmcia: insert PC...
80
  			unsigned int align, struct resource **parent)
b19a7275d   Dominik Brodowski   pcmcia: clarify a...
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
  {
  	int i, ret = 0;
  
  	/* Check for an already-allocated window that must conflict with
  	 * what was asked for.  It is a hack because it does not catch all
  	 * potential conflicts, just the most obvious ones.
  	 */
  	for (i = 0; i < MAX_IO_WIN; i++) {
  		if (!s->io[i].res)
  			continue;
  
  		if (!*base)
  			continue;
  
  		if ((s->io[i].res->start & (align-1)) == *base)
  			return -EBUSY;
  	}
  
  	for (i = 0; i < MAX_IO_WIN; i++) {
  		struct resource *res = s->io[i].res;
  		unsigned int try;
  
  		if (res && (res->flags & IORESOURCE_BITS) !=
  			(attr & IORESOURCE_BITS))
  			continue;
  
  		if (!res) {
  			if (align == 0)
  				align = 0x10000;
  
  			res = s->io[i].res = __iodyn_find_io_region(s, *base,
  								num, align);
  			if (!res)
  				return -EINVAL;
  
  			*base = res->start;
  			s->io[i].res->flags =
  				((res->flags & ~IORESOURCE_BITS) |
  					(attr & IORESOURCE_BITS));
  			s->io[i].InUse = num;
ad0c7be28   Dominik Brodowski   pcmcia: insert PC...
121
  			*parent = res;
b19a7275d   Dominik Brodowski   pcmcia: clarify a...
122
123
124
125
126
127
128
  			return 0;
  		}
  
  		/* Try to extend top of window */
  		try = res->end + 1;
  		if ((*base == 0) || (*base == try)) {
  			if (adjust_resource(s->io[i].res, res->start,
28f65c11f   Joe Perches   treewide: Convert...
129
  					    resource_size(res) + num))
b19a7275d   Dominik Brodowski   pcmcia: clarify a...
130
131
132
  				continue;
  			*base = try;
  			s->io[i].InUse += num;
ad0c7be28   Dominik Brodowski   pcmcia: insert PC...
133
  			*parent = res;
b19a7275d   Dominik Brodowski   pcmcia: clarify a...
134
135
136
137
138
139
140
  			return 0;
  		}
  
  		/* Try to extend bottom of window */
  		try = res->start - num;
  		if ((*base == 0) || (*base == try)) {
  			if (adjust_resource(s->io[i].res,
28f65c11f   Joe Perches   treewide: Convert...
141
142
  					    res->start - num,
  					    resource_size(res) + num))
b19a7275d   Dominik Brodowski   pcmcia: clarify a...
143
144
145
  				continue;
  			*base = try;
  			s->io[i].InUse += num;
ad0c7be28   Dominik Brodowski   pcmcia: insert PC...
146
  			*parent = res;
b19a7275d   Dominik Brodowski   pcmcia: clarify a...
147
148
149
150
151
152
  			return 0;
  		}
  	}
  
  	return -EINVAL;
  }
49b1153ad   Dominik Brodowski   pcmcia: move all ...
153
154
  struct pccard_resource_ops pccard_iodyn_ops = {
  	.validate_mem = NULL,
b19a7275d   Dominik Brodowski   pcmcia: clarify a...
155
  	.find_io = iodyn_find_io,
49b1153ad   Dominik Brodowski   pcmcia: move all ...
156
  	.find_mem = NULL,
49b1153ad   Dominik Brodowski   pcmcia: move all ...
157
158
159
160
  	.init = static_init,
  	.exit = NULL,
  };
  EXPORT_SYMBOL(pccard_iodyn_ops);