]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/blame - drivers/pnp/manager.c
Merge tag 'for-5.3-rc4-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave...
[mirror_ubuntu-hirsute-kernel.git] / drivers / pnp / manager.c
CommitLineData
b2441318 1// SPDX-License-Identifier: GPL-2.0
1da177e4
LT
2/*
3 * manager.c - Resource Management, Conflict Resolution, Activation and Disabling of Devices
4 *
c1017a4c 5 * based on isapnp.c resource management (c) Jaroslav Kysela <perex@perex.cz>
1da177e4 6 * Copyright 2003 Adam Belay <ambx1@neo.rr.com>
1f32ca31
BH
7 * Copyright (C) 2008 Hewlett-Packard Development Company, L.P.
8 * Bjorn Helgaas <bjorn.helgaas@hp.com>
1da177e4
LT
9 */
10
1da177e4
LT
11#include <linux/errno.h>
12#include <linux/module.h>
13#include <linux/init.h>
14#include <linux/kernel.h>
1da177e4 15#include <linux/pnp.h>
4e57b681 16#include <linux/bitmap.h>
b3bd86e2 17#include <linux/mutex.h>
1da177e4
LT
18#include "base.h"
19
b3bd86e2 20DEFINE_MUTEX(pnp_res_mutex);
1da177e4 21
13cde3b2
WS
22static struct resource *pnp_find_resource(struct pnp_dev *dev,
23 unsigned char rule,
24 unsigned long type,
25 unsigned int bar)
26{
27 struct resource *res = pnp_get_resource(dev, type, bar);
28
29 /* when the resource already exists, set its resource bits from rule */
30 if (res) {
31 res->flags &= ~IORESOURCE_BITS;
32 res->flags |= rule & IORESOURCE_BITS;
33 }
34
35 return res;
36}
37
1da177e4
LT
38static int pnp_assign_port(struct pnp_dev *dev, struct pnp_port *rule, int idx)
39{
aee3ad81 40 struct resource *res, local_res;
1da177e4 41
13cde3b2 42 res = pnp_find_resource(dev, rule->flags, IORESOURCE_IO, idx);
aee3ad81 43 if (res) {
2f53432c 44 pnp_dbg(&dev->dev, " io %d already set to %#llx-%#llx "
28ccffcf
BH
45 "flags %#lx\n", idx, (unsigned long long) res->start,
46 (unsigned long long) res->end, res->flags);
6e906f0e 47 return 0;
81b5c75f
BH
48 }
49
aee3ad81
BH
50 res = &local_res;
51 res->flags = rule->flags | IORESOURCE_AUTO;
52 res->start = 0;
53 res->end = 0;
1da177e4
LT
54
55 if (!rule->size) {
28ccffcf 56 res->flags |= IORESOURCE_DISABLED;
2f53432c 57 pnp_dbg(&dev->dev, " io %d disabled\n", idx);
aee3ad81 58 goto __add;
1da177e4
LT
59 }
60
28ccffcf
BH
61 res->start = rule->min;
62 res->end = res->start + rule->size - 1;
1da177e4 63
f5d94ff0 64 while (!pnp_check_port(dev, res)) {
28ccffcf
BH
65 res->start += rule->align;
66 res->end = res->start + rule->size - 1;
67 if (res->start > rule->max || !rule->align) {
2f53432c 68 pnp_dbg(&dev->dev, " couldn't assign io %d "
fcfb7ce3
BH
69 "(min %#llx max %#llx)\n", idx,
70 (unsigned long long) rule->min,
71 (unsigned long long) rule->max);
6e906f0e 72 return -EBUSY;
81b5c75f 73 }
1da177e4 74 }
aee3ad81
BH
75
76__add:
77 pnp_add_io_resource(dev, res->start, res->end, res->flags);
6e906f0e 78 return 0;
1da177e4
LT
79}
80
81static int pnp_assign_mem(struct pnp_dev *dev, struct pnp_mem *rule, int idx)
82{
aee3ad81 83 struct resource *res, local_res;
1da177e4 84
13cde3b2 85 res = pnp_find_resource(dev, rule->flags, IORESOURCE_MEM, idx);
aee3ad81 86 if (res) {
2f53432c 87 pnp_dbg(&dev->dev, " mem %d already set to %#llx-%#llx "
28ccffcf
BH
88 "flags %#lx\n", idx, (unsigned long long) res->start,
89 (unsigned long long) res->end, res->flags);
6e906f0e 90 return 0;
81b5c75f
BH
91 }
92
aee3ad81
BH
93 res = &local_res;
94 res->flags = rule->flags | IORESOURCE_AUTO;
95 res->start = 0;
96 res->end = 0;
1da177e4 97
13cde3b2 98 /* ??? rule->flags restricted to 8 bits, all tests bogus ??? */
1da177e4 99 if (!(rule->flags & IORESOURCE_MEM_WRITEABLE))
28ccffcf 100 res->flags |= IORESOURCE_READONLY;
1da177e4 101 if (rule->flags & IORESOURCE_MEM_RANGELENGTH)
28ccffcf 102 res->flags |= IORESOURCE_RANGELENGTH;
1da177e4 103 if (rule->flags & IORESOURCE_MEM_SHADOWABLE)
28ccffcf 104 res->flags |= IORESOURCE_SHADOWABLE;
1da177e4
LT
105
106 if (!rule->size) {
28ccffcf 107 res->flags |= IORESOURCE_DISABLED;
2f53432c 108 pnp_dbg(&dev->dev, " mem %d disabled\n", idx);
aee3ad81 109 goto __add;
1da177e4
LT
110 }
111
28ccffcf
BH
112 res->start = rule->min;
113 res->end = res->start + rule->size - 1;
1da177e4 114
f5d94ff0 115 while (!pnp_check_mem(dev, res)) {
28ccffcf
BH
116 res->start += rule->align;
117 res->end = res->start + rule->size - 1;
118 if (res->start > rule->max || !rule->align) {
2f53432c 119 pnp_dbg(&dev->dev, " couldn't assign mem %d "
fcfb7ce3
BH
120 "(min %#llx max %#llx)\n", idx,
121 (unsigned long long) rule->min,
122 (unsigned long long) rule->max);
6e906f0e 123 return -EBUSY;
81b5c75f 124 }
1da177e4 125 }
aee3ad81
BH
126
127__add:
128 pnp_add_mem_resource(dev, res->start, res->end, res->flags);
6e906f0e 129 return 0;
1da177e4
LT
130}
131
9dd78466 132static int pnp_assign_irq(struct pnp_dev *dev, struct pnp_irq *rule, int idx)
1da177e4 133{
aee3ad81 134 struct resource *res, local_res;
1da177e4
LT
135 int i;
136
137 /* IRQ priority: this table is good for i386 */
138 static unsigned short xtab[16] = {
139 5, 10, 11, 12, 9, 14, 15, 7, 3, 4, 13, 0, 1, 6, 8, 2
140 };
141
13cde3b2 142 res = pnp_find_resource(dev, rule->flags, IORESOURCE_IRQ, idx);
aee3ad81 143 if (res) {
2f53432c 144 pnp_dbg(&dev->dev, " irq %d already set to %d flags %#lx\n",
28ccffcf 145 idx, (int) res->start, res->flags);
6e906f0e 146 return 0;
81b5c75f
BH
147 }
148
aee3ad81
BH
149 res = &local_res;
150 res->flags = rule->flags | IORESOURCE_AUTO;
151 res->start = -1;
152 res->end = -1;
1da177e4 153
7aefff51 154 if (bitmap_empty(rule->map.bits, PNP_IRQ_NR)) {
28ccffcf 155 res->flags |= IORESOURCE_DISABLED;
2f53432c 156 pnp_dbg(&dev->dev, " irq %d disabled\n", idx);
aee3ad81 157 goto __add;
1da177e4
LT
158 }
159
160 /* TBD: need check for >16 IRQ */
7aefff51 161 res->start = find_next_bit(rule->map.bits, PNP_IRQ_NR, 16);
28ccffcf
BH
162 if (res->start < PNP_IRQ_NR) {
163 res->end = res->start;
aee3ad81 164 goto __add;
1da177e4
LT
165 }
166 for (i = 0; i < 16; i++) {
7aefff51 167 if (test_bit(xtab[i], rule->map.bits)) {
28ccffcf 168 res->start = res->end = xtab[i];
aee3ad81
BH
169 if (pnp_check_irq(dev, res))
170 goto __add;
1da177e4
LT
171 }
172 }
d5ebde6e
BH
173
174 if (rule->flags & IORESOURCE_IRQ_OPTIONAL) {
175 res->start = -1;
176 res->end = -1;
177 res->flags |= IORESOURCE_DISABLED;
2f53432c 178 pnp_dbg(&dev->dev, " irq %d disabled (optional)\n", idx);
d5ebde6e
BH
179 goto __add;
180 }
181
2f53432c 182 pnp_dbg(&dev->dev, " couldn't assign irq %d\n", idx);
6e906f0e 183 return -EBUSY;
aee3ad81
BH
184
185__add:
186 pnp_add_irq_resource(dev, res->start, res->flags);
6e906f0e 187 return 0;
1da177e4
LT
188}
189
586f83e2 190#ifdef CONFIG_ISA_DMA_API
6e906f0e 191static int pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx)
1da177e4 192{
aee3ad81 193 struct resource *res, local_res;
1da177e4
LT
194 int i;
195
196 /* DMA priority: this table is good for i386 */
197 static unsigned short xtab[8] = {
198 1, 3, 5, 6, 7, 0, 2, 4
199 };
200
13cde3b2 201 res = pnp_find_resource(dev, rule->flags, IORESOURCE_DMA, idx);
aee3ad81 202 if (res) {
2f53432c 203 pnp_dbg(&dev->dev, " dma %d already set to %d flags %#lx\n",
28ccffcf 204 idx, (int) res->start, res->flags);
6e906f0e 205 return 0;
81b5c75f
BH
206 }
207
aee3ad81
BH
208 res = &local_res;
209 res->flags = rule->flags | IORESOURCE_AUTO;
210 res->start = -1;
211 res->end = -1;
1da177e4 212
bdf0eb3a
DF
213 if (!rule->map) {
214 res->flags |= IORESOURCE_DISABLED;
215 pnp_dbg(&dev->dev, " dma %d disabled\n", idx);
216 goto __add;
217 }
218
1da177e4 219 for (i = 0; i < 8; i++) {
9dd78466 220 if (rule->map & (1 << xtab[i])) {
28ccffcf 221 res->start = res->end = xtab[i];
aee3ad81
BH
222 if (pnp_check_dma(dev, res))
223 goto __add;
1da177e4
LT
224 }
225 }
bdf0eb3a
DF
226
227 pnp_dbg(&dev->dev, " couldn't assign dma %d\n", idx);
228 return -EBUSY;
1da177e4 229
aee3ad81
BH
230__add:
231 pnp_add_dma_resource(dev, res->start, res->flags);
6e906f0e 232 return 0;
d948a8da 233}
586f83e2 234#endif /* CONFIG_ISA_DMA_API */
d948a8da 235
2cd13930 236void pnp_init_resources(struct pnp_dev *dev)
1da177e4 237{
aee3ad81 238 pnp_free_resources(dev);
1da177e4
LT
239}
240
6969c7ed 241static void pnp_clean_resource_table(struct pnp_dev *dev)
1da177e4 242{
aee3ad81
BH
243 struct pnp_resource *pnp_res, *tmp;
244
245 list_for_each_entry_safe(pnp_res, tmp, &dev->resources, list) {
246 if (pnp_res->res.flags & IORESOURCE_AUTO)
247 pnp_free_resource(pnp_res);
1da177e4
LT
248 }
249}
250
251/**
252 * pnp_assign_resources - assigns resources to the device based on the specified dependent number
253 * @dev: pointer to the desired device
1f32ca31 254 * @set: the dependent function number
1da177e4 255 */
1f32ca31 256static int pnp_assign_resources(struct pnp_dev *dev, int set)
1da177e4 257{
1f32ca31 258 struct pnp_option *option;
586f83e2
DR
259 int nport = 0, nmem = 0, nirq = 0;
260 int ndma __maybe_unused = 0;
1f32ca31 261 int ret = 0;
1da177e4 262
2f53432c 263 pnp_dbg(&dev->dev, "pnp_assign_resources, try dependent set %d\n", set);
b3bd86e2 264 mutex_lock(&pnp_res_mutex);
6969c7ed 265 pnp_clean_resource_table(dev);
1da177e4 266
1f32ca31
BH
267 list_for_each_entry(option, &dev->options, list) {
268 if (pnp_option_is_dependent(option) &&
269 pnp_option_set(option) != set)
270 continue;
271
272 switch (option->type) {
273 case IORESOURCE_IO:
274 ret = pnp_assign_port(dev, &option->u.port, nport++);
275 break;
276 case IORESOURCE_MEM:
277 ret = pnp_assign_mem(dev, &option->u.mem, nmem++);
278 break;
279 case IORESOURCE_IRQ:
280 ret = pnp_assign_irq(dev, &option->u.irq, nirq++);
281 break;
586f83e2 282#ifdef CONFIG_ISA_DMA_API
1f32ca31
BH
283 case IORESOURCE_DMA:
284 ret = pnp_assign_dma(dev, &option->u.dma, ndma++);
285 break;
586f83e2 286#endif
1f32ca31
BH
287 default:
288 ret = -EINVAL;
289 break;
1da177e4 290 }
1f32ca31
BH
291 if (ret < 0)
292 break;
293 }
1da177e4 294
b3bd86e2 295 mutex_unlock(&pnp_res_mutex);
1f32ca31 296 if (ret < 0) {
2f53432c 297 pnp_dbg(&dev->dev, "pnp_assign_resources failed (%d)\n", ret);
1f32ca31
BH
298 pnp_clean_resource_table(dev);
299 } else
300 dbg_pnp_show_resources(dev, "pnp_assign_resources succeeded");
301 return ret;
1da177e4
LT
302}
303
1da177e4
LT
304/**
305 * pnp_auto_config_dev - automatically assigns resources to a device
306 * @dev: pointer to the desired device
1da177e4
LT
307 */
308int pnp_auto_config_dev(struct pnp_dev *dev)
309{
1f32ca31 310 int i, ret;
1da177e4 311
9dd78466 312 if (!pnp_can_configure(dev)) {
2f53432c 313 pnp_dbg(&dev->dev, "configuration not supported\n");
1da177e4
LT
314 return -ENODEV;
315 }
316
1f32ca31
BH
317 ret = pnp_assign_resources(dev, 0);
318 if (ret == 0)
319 return 0;
320
321 for (i = 1; i < dev->num_dependent_sets; i++) {
322 ret = pnp_assign_resources(dev, i);
323 if (ret == 0)
1da177e4 324 return 0;
1da177e4
LT
325 }
326
a05d0781 327 dev_err(&dev->dev, "unable to assign resources\n");
1f32ca31 328 return ret;
1da177e4
LT
329}
330
68094e32
PO
331/**
332 * pnp_start_dev - low-level start of the PnP device
333 * @dev: pointer to the desired device
334 *
07d4e9af 335 * assumes that resources have already been allocated
68094e32 336 */
68094e32
PO
337int pnp_start_dev(struct pnp_dev *dev)
338{
339 if (!pnp_can_write(dev)) {
2f53432c 340 pnp_dbg(&dev->dev, "activation not supported\n");
68094e32
PO
341 return -EINVAL;
342 }
343
81b5c75f 344 dbg_pnp_show_resources(dev, "pnp_start_dev");
59284cb4 345 if (dev->protocol->set(dev) < 0) {
a05d0781 346 dev_err(&dev->dev, "activation failed\n");
68094e32
PO
347 return -EIO;
348 }
349
a05d0781 350 dev_info(&dev->dev, "activated\n");
68094e32
PO
351 return 0;
352}
353
354/**
355 * pnp_stop_dev - low-level disable of the PnP device
356 * @dev: pointer to the desired device
357 *
358 * does not free resources
359 */
68094e32
PO
360int pnp_stop_dev(struct pnp_dev *dev)
361{
362 if (!pnp_can_disable(dev)) {
2f53432c 363 pnp_dbg(&dev->dev, "disabling not supported\n");
68094e32
PO
364 return -EINVAL;
365 }
9dd78466 366 if (dev->protocol->disable(dev) < 0) {
a05d0781 367 dev_err(&dev->dev, "disable failed\n");
68094e32
PO
368 return -EIO;
369 }
370
a05d0781 371 dev_info(&dev->dev, "disabled\n");
68094e32
PO
372 return 0;
373}
374
1da177e4
LT
375/**
376 * pnp_activate_dev - activates a PnP device for use
377 * @dev: pointer to the desired device
378 *
379 * does not validate or set resources so be careful.
380 */
381int pnp_activate_dev(struct pnp_dev *dev)
382{
68094e32
PO
383 int error;
384
07d4e9af 385 if (dev->active)
cc8259a6 386 return 0;
1da177e4
LT
387
388 /* ensure resources are allocated */
389 if (pnp_auto_config_dev(dev))
390 return -EBUSY;
391
68094e32
PO
392 error = pnp_start_dev(dev);
393 if (error)
394 return error;
1da177e4
LT
395
396 dev->active = 1;
cc8259a6 397 return 0;
1da177e4
LT
398}
399
400/**
401 * pnp_disable_dev - disables device
402 * @dev: pointer to the desired device
403 *
404 * inform the correct pnp protocol so that resources can be used by other devices
405 */
406int pnp_disable_dev(struct pnp_dev *dev)
407{
68094e32
PO
408 int error;
409
07d4e9af 410 if (!dev->active)
cc8259a6 411 return 0;
1da177e4 412
68094e32
PO
413 error = pnp_stop_dev(dev);
414 if (error)
415 return error;
1da177e4
LT
416
417 dev->active = 0;
1da177e4
LT
418
419 /* release the resources so that other devices can use them */
b3bd86e2 420 mutex_lock(&pnp_res_mutex);
6969c7ed 421 pnp_clean_resource_table(dev);
b3bd86e2 422 mutex_unlock(&pnp_res_mutex);
1da177e4 423
cc8259a6 424 return 0;
1da177e4
LT
425}
426
68094e32
PO
427EXPORT_SYMBOL(pnp_start_dev);
428EXPORT_SYMBOL(pnp_stop_dev);
1da177e4
LT
429EXPORT_SYMBOL(pnp_activate_dev);
430EXPORT_SYMBOL(pnp_disable_dev);