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