aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/osl.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi/osl.c')
-rw-r--r--drivers/acpi/osl.c139
1 files changed, 79 insertions, 60 deletions
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 4a6753009d79..45ad4ffef533 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -76,7 +76,6 @@ EXPORT_SYMBOL(acpi_in_debugger);
76extern char line_buf[80]; 76extern char line_buf[80];
77#endif /*ENABLE_DEBUGGER */ 77#endif /*ENABLE_DEBUGGER */
78 78
79static unsigned int acpi_irq_irq;
80static acpi_osd_handler acpi_irq_handler; 79static acpi_osd_handler acpi_irq_handler;
81static void *acpi_irq_context; 80static void *acpi_irq_context;
82static struct workqueue_struct *kacpid_wq; 81static struct workqueue_struct *kacpid_wq;
@@ -105,11 +104,11 @@ struct acpi_ioremap {
105 void __iomem *virt; 104 void __iomem *virt;
106 acpi_physical_address phys; 105 acpi_physical_address phys;
107 acpi_size size; 106 acpi_size size;
108 struct kref ref; 107 unsigned long refcount;
109}; 108};
110 109
111static LIST_HEAD(acpi_ioremaps); 110static LIST_HEAD(acpi_ioremaps);
112static DEFINE_SPINLOCK(acpi_ioremap_lock); 111static DEFINE_MUTEX(acpi_ioremap_lock);
113 112
114static void __init acpi_osi_setup_late(void); 113static void __init acpi_osi_setup_late(void);
115 114
@@ -285,6 +284,22 @@ acpi_map_vaddr_lookup(acpi_physical_address phys, unsigned int size)
285 return NULL; 284 return NULL;
286} 285}
287 286
287void __iomem *acpi_os_get_iomem(acpi_physical_address phys, unsigned int size)
288{
289 struct acpi_ioremap *map;
290 void __iomem *virt = NULL;
291
292 mutex_lock(&acpi_ioremap_lock);
293 map = acpi_map_lookup(phys, size);
294 if (map) {
295 virt = map->virt + (phys - map->phys);
296 map->refcount++;
297 }
298 mutex_unlock(&acpi_ioremap_lock);
299 return virt;
300}
301EXPORT_SYMBOL_GPL(acpi_os_get_iomem);
302
288/* Must be called with 'acpi_ioremap_lock' or RCU read lock held. */ 303/* Must be called with 'acpi_ioremap_lock' or RCU read lock held. */
289static struct acpi_ioremap * 304static struct acpi_ioremap *
290acpi_map_lookup_virt(void __iomem *virt, acpi_size size) 305acpi_map_lookup_virt(void __iomem *virt, acpi_size size)
@@ -302,8 +317,7 @@ acpi_map_lookup_virt(void __iomem *virt, acpi_size size)
302void __iomem *__init_refok 317void __iomem *__init_refok
303acpi_os_map_memory(acpi_physical_address phys, acpi_size size) 318acpi_os_map_memory(acpi_physical_address phys, acpi_size size)
304{ 319{
305 struct acpi_ioremap *map, *tmp_map; 320 struct acpi_ioremap *map;
306 unsigned long flags;
307 void __iomem *virt; 321 void __iomem *virt;
308 acpi_physical_address pg_off; 322 acpi_physical_address pg_off;
309 acpi_size pg_sz; 323 acpi_size pg_sz;
@@ -316,14 +330,25 @@ acpi_os_map_memory(acpi_physical_address phys, acpi_size size)
316 if (!acpi_gbl_permanent_mmap) 330 if (!acpi_gbl_permanent_mmap)
317 return __acpi_map_table((unsigned long)phys, size); 331 return __acpi_map_table((unsigned long)phys, size);
318 332
333 mutex_lock(&acpi_ioremap_lock);
334 /* Check if there's a suitable mapping already. */
335 map = acpi_map_lookup(phys, size);
336 if (map) {
337 map->refcount++;
338 goto out;
339 }
340
319 map = kzalloc(sizeof(*map), GFP_KERNEL); 341 map = kzalloc(sizeof(*map), GFP_KERNEL);
320 if (!map) 342 if (!map) {
343 mutex_unlock(&acpi_ioremap_lock);
321 return NULL; 344 return NULL;
345 }
322 346
323 pg_off = round_down(phys, PAGE_SIZE); 347 pg_off = round_down(phys, PAGE_SIZE);
324 pg_sz = round_up(phys + size, PAGE_SIZE) - pg_off; 348 pg_sz = round_up(phys + size, PAGE_SIZE) - pg_off;
325 virt = acpi_os_ioremap(pg_off, pg_sz); 349 virt = acpi_os_ioremap(pg_off, pg_sz);
326 if (!virt) { 350 if (!virt) {
351 mutex_unlock(&acpi_ioremap_lock);
327 kfree(map); 352 kfree(map);
328 return NULL; 353 return NULL;
329 } 354 }
@@ -332,62 +357,51 @@ acpi_os_map_memory(acpi_physical_address phys, acpi_size size)
332 map->virt = virt; 357 map->virt = virt;
333 map->phys = pg_off; 358 map->phys = pg_off;
334 map->size = pg_sz; 359 map->size = pg_sz;
335 kref_init(&map->ref); 360 map->refcount = 1;
336 361
337 spin_lock_irqsave(&acpi_ioremap_lock, flags);
338 /* Check if page has already been mapped. */
339 tmp_map = acpi_map_lookup(phys, size);
340 if (tmp_map) {
341 kref_get(&tmp_map->ref);
342 spin_unlock_irqrestore(&acpi_ioremap_lock, flags);
343 iounmap(map->virt);
344 kfree(map);
345 return tmp_map->virt + (phys - tmp_map->phys);
346 }
347 list_add_tail_rcu(&map->list, &acpi_ioremaps); 362 list_add_tail_rcu(&map->list, &acpi_ioremaps);
348 spin_unlock_irqrestore(&acpi_ioremap_lock, flags);
349 363
364 out:
365 mutex_unlock(&acpi_ioremap_lock);
350 return map->virt + (phys - map->phys); 366 return map->virt + (phys - map->phys);
351} 367}
352EXPORT_SYMBOL_GPL(acpi_os_map_memory); 368EXPORT_SYMBOL_GPL(acpi_os_map_memory);
353 369
354static void acpi_kref_del_iomap(struct kref *ref) 370static void acpi_os_drop_map_ref(struct acpi_ioremap *map)
355{ 371{
356 struct acpi_ioremap *map; 372 if (!--map->refcount)
373 list_del_rcu(&map->list);
374}
357 375
358 map = container_of(ref, struct acpi_ioremap, ref); 376static void acpi_os_map_cleanup(struct acpi_ioremap *map)
359 list_del_rcu(&map->list); 377{
378 if (!map->refcount) {
379 synchronize_rcu();
380 iounmap(map->virt);
381 kfree(map);
382 }
360} 383}
361 384
362void __ref acpi_os_unmap_memory(void __iomem *virt, acpi_size size) 385void __ref acpi_os_unmap_memory(void __iomem *virt, acpi_size size)
363{ 386{
364 struct acpi_ioremap *map; 387 struct acpi_ioremap *map;
365 unsigned long flags;
366 int del;
367 388
368 if (!acpi_gbl_permanent_mmap) { 389 if (!acpi_gbl_permanent_mmap) {
369 __acpi_unmap_table(virt, size); 390 __acpi_unmap_table(virt, size);
370 return; 391 return;
371 } 392 }
372 393
373 spin_lock_irqsave(&acpi_ioremap_lock, flags); 394 mutex_lock(&acpi_ioremap_lock);
374 map = acpi_map_lookup_virt(virt, size); 395 map = acpi_map_lookup_virt(virt, size);
375 if (!map) { 396 if (!map) {
376 spin_unlock_irqrestore(&acpi_ioremap_lock, flags); 397 mutex_unlock(&acpi_ioremap_lock);
377 printk(KERN_ERR PREFIX "%s: bad address %p\n", __func__, virt); 398 WARN(true, PREFIX "%s: bad address %p\n", __func__, virt);
378 dump_stack();
379 return; 399 return;
380 } 400 }
401 acpi_os_drop_map_ref(map);
402 mutex_unlock(&acpi_ioremap_lock);
381 403
382 del = kref_put(&map->ref, acpi_kref_del_iomap); 404 acpi_os_map_cleanup(map);
383 spin_unlock_irqrestore(&acpi_ioremap_lock, flags);
384
385 if (!del)
386 return;
387
388 synchronize_rcu();
389 iounmap(map->virt);
390 kfree(map);
391} 405}
392EXPORT_SYMBOL_GPL(acpi_os_unmap_memory); 406EXPORT_SYMBOL_GPL(acpi_os_unmap_memory);
393 407
@@ -397,7 +411,7 @@ void __init early_acpi_os_unmap_memory(void __iomem *virt, acpi_size size)
397 __acpi_unmap_table(virt, size); 411 __acpi_unmap_table(virt, size);
398} 412}
399 413
400int acpi_os_map_generic_address(struct acpi_generic_address *addr) 414static int acpi_os_map_generic_address(struct acpi_generic_address *addr)
401{ 415{
402 void __iomem *virt; 416 void __iomem *virt;
403 417
@@ -413,13 +427,10 @@ int acpi_os_map_generic_address(struct acpi_generic_address *addr)
413 427
414 return 0; 428 return 0;
415} 429}
416EXPORT_SYMBOL_GPL(acpi_os_map_generic_address);
417 430
418void acpi_os_unmap_generic_address(struct acpi_generic_address *addr) 431static void acpi_os_unmap_generic_address(struct acpi_generic_address *addr)
419{ 432{
420 void __iomem *virt; 433 struct acpi_ioremap *map;
421 unsigned long flags;
422 acpi_size size = addr->bit_width / 8;
423 434
424 if (addr->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) 435 if (addr->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY)
425 return; 436 return;
@@ -427,13 +438,17 @@ void acpi_os_unmap_generic_address(struct acpi_generic_address *addr)
427 if (!addr->address || !addr->bit_width) 438 if (!addr->address || !addr->bit_width)
428 return; 439 return;
429 440
430 spin_lock_irqsave(&acpi_ioremap_lock, flags); 441 mutex_lock(&acpi_ioremap_lock);
431 virt = acpi_map_vaddr_lookup(addr->address, size); 442 map = acpi_map_lookup(addr->address, addr->bit_width / 8);
432 spin_unlock_irqrestore(&acpi_ioremap_lock, flags); 443 if (!map) {
444 mutex_unlock(&acpi_ioremap_lock);
445 return;
446 }
447 acpi_os_drop_map_ref(map);
448 mutex_unlock(&acpi_ioremap_lock);
433 449
434 acpi_os_unmap_memory(virt, size); 450 acpi_os_map_cleanup(map);
435} 451}
436EXPORT_SYMBOL_GPL(acpi_os_unmap_generic_address);
437 452
438#ifdef ACPI_FUTURE_USAGE 453#ifdef ACPI_FUTURE_USAGE
439acpi_status 454acpi_status
@@ -516,11 +531,15 @@ acpi_os_install_interrupt_handler(u32 gsi, acpi_osd_handler handler,
516 acpi_irq_stats_init(); 531 acpi_irq_stats_init();
517 532
518 /* 533 /*
519 * Ignore the GSI from the core, and use the value in our copy of the 534 * ACPI interrupts different from the SCI in our copy of the FADT are
520 * FADT. It may not be the same if an interrupt source override exists 535 * not supported.
521 * for the SCI.
522 */ 536 */
523 gsi = acpi_gbl_FADT.sci_interrupt; 537 if (gsi != acpi_gbl_FADT.sci_interrupt)
538 return AE_BAD_PARAMETER;
539
540 if (acpi_irq_handler)
541 return AE_ALREADY_ACQUIRED;
542
524 if (acpi_gsi_to_irq(gsi, &irq) < 0) { 543 if (acpi_gsi_to_irq(gsi, &irq) < 0) {
525 printk(KERN_ERR PREFIX "SCI (ACPI GSI %d) not registered\n", 544 printk(KERN_ERR PREFIX "SCI (ACPI GSI %d) not registered\n",
526 gsi); 545 gsi);
@@ -531,20 +550,20 @@ acpi_os_install_interrupt_handler(u32 gsi, acpi_osd_handler handler,
531 acpi_irq_context = context; 550 acpi_irq_context = context;
532 if (request_irq(irq, acpi_irq, IRQF_SHARED, "acpi", acpi_irq)) { 551 if (request_irq(irq, acpi_irq, IRQF_SHARED, "acpi", acpi_irq)) {
533 printk(KERN_ERR PREFIX "SCI (IRQ%d) allocation failed\n", irq); 552 printk(KERN_ERR PREFIX "SCI (IRQ%d) allocation failed\n", irq);
553 acpi_irq_handler = NULL;
534 return AE_NOT_ACQUIRED; 554 return AE_NOT_ACQUIRED;
535 } 555 }
536 acpi_irq_irq = irq;
537 556
538 return AE_OK; 557 return AE_OK;
539} 558}
540 559
541acpi_status acpi_os_remove_interrupt_handler(u32 irq, acpi_osd_handler handler) 560acpi_status acpi_os_remove_interrupt_handler(u32 irq, acpi_osd_handler handler)
542{ 561{
543 if (irq) { 562 if (irq != acpi_gbl_FADT.sci_interrupt)
544 free_irq(irq, acpi_irq); 563 return AE_BAD_PARAMETER;
545 acpi_irq_handler = NULL; 564
546 acpi_irq_irq = 0; 565 free_irq(irq, acpi_irq);
547 } 566 acpi_irq_handler = NULL;
548 567
549 return AE_OK; 568 return AE_OK;
550} 569}
@@ -1603,7 +1622,7 @@ acpi_status __init acpi_os_initialize1(void)
1603acpi_status acpi_os_terminate(void) 1622acpi_status acpi_os_terminate(void)
1604{ 1623{
1605 if (acpi_irq_handler) { 1624 if (acpi_irq_handler) {
1606 acpi_os_remove_interrupt_handler(acpi_irq_irq, 1625 acpi_os_remove_interrupt_handler(acpi_gbl_FADT.sci_interrupt,
1607 acpi_irq_handler); 1626 acpi_irq_handler);
1608 } 1627 }
1609 1628