aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorJesper Nilsson <jesper.nilsson@axis.com>2010-08-02 07:17:05 -0400
committerJesper Nilsson <jesper.nilsson@axis.com>2010-08-04 06:59:14 -0400
commit60362158e2419b20cc04d43a6ffa60c1845775dc (patch)
tree5c255d6b869bd98592b862a31dc79110df91557a /arch
parent16bc0fe5ce84df89c8e802be210af88721d4cc4f (diff)
CRIS: gpio: don't call copy_to_user()/copy_from_user() while holding spinlocks
copy_to_user()/copy_from_user() must not be used with spinlocks held. Move locks inside each case so we have better control of when the locks are held. Also, since we use spinlocks, we don't need to hold the BKL, so remove it. Reported-by: Kulikov Vasiliy <segooon@gmail.com> Signed-off-by: Jesper Nilsson <jesper.nilsson@axis.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/cris/arch-v10/drivers/gpio.c80
1 files changed, 48 insertions, 32 deletions
diff --git a/arch/cris/arch-v10/drivers/gpio.c b/arch/cris/arch-v10/drivers/gpio.c
index 080927ffe63b..a07b6d25b0c7 100644
--- a/arch/cris/arch-v10/drivers/gpio.c
+++ b/arch/cris/arch-v10/drivers/gpio.c
@@ -16,7 +16,6 @@
16#include <linux/errno.h> 16#include <linux/errno.h>
17#include <linux/kernel.h> 17#include <linux/kernel.h>
18#include <linux/fs.h> 18#include <linux/fs.h>
19#include <linux/smp_lock.h>
20#include <linux/string.h> 19#include <linux/string.h>
21#include <linux/poll.h> 20#include <linux/poll.h>
22#include <linux/init.h> 21#include <linux/init.h>
@@ -46,7 +45,7 @@ static char gpio_name[] = "etrax gpio";
46static wait_queue_head_t *gpio_wq; 45static wait_queue_head_t *gpio_wq;
47#endif 46#endif
48 47
49static int gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg); 48static long gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
50static ssize_t gpio_write(struct file *file, const char __user *buf, 49static ssize_t gpio_write(struct file *file, const char __user *buf,
51 size_t count, loff_t *off); 50 size_t count, loff_t *off);
52static int gpio_open(struct inode *inode, struct file *filp); 51static int gpio_open(struct inode *inode, struct file *filp);
@@ -323,7 +322,6 @@ gpio_open(struct inode *inode, struct file *filp)
323 if (!priv) 322 if (!priv)
324 return -ENOMEM; 323 return -ENOMEM;
325 324
326 lock_kernel();
327 priv->minor = p; 325 priv->minor = p;
328 326
329 /* initialize the io/alarm struct */ 327 /* initialize the io/alarm struct */
@@ -358,7 +356,6 @@ gpio_open(struct inode *inode, struct file *filp)
358 alarmlist = priv; 356 alarmlist = priv;
359 spin_unlock_irqrestore(&gpio_lock, flags); 357 spin_unlock_irqrestore(&gpio_lock, flags);
360 358
361 unlock_kernel();
362 return 0; 359 return 0;
363} 360}
364 361
@@ -503,8 +500,7 @@ unsigned long inline setget_output(struct gpio_private *priv, unsigned long arg)
503static int 500static int
504gpio_leds_ioctl(unsigned int cmd, unsigned long arg); 501gpio_leds_ioctl(unsigned int cmd, unsigned long arg);
505 502
506static int 503static long gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
507gpio_ioctl_unlocked(struct file *file, unsigned int cmd, unsigned long arg)
508{ 504{
509 unsigned long flags; 505 unsigned long flags;
510 unsigned long val; 506 unsigned long val;
@@ -514,54 +510,65 @@ gpio_ioctl_unlocked(struct file *file, unsigned int cmd, unsigned long arg)
514 if (_IOC_TYPE(cmd) != ETRAXGPIO_IOCTYPE) 510 if (_IOC_TYPE(cmd) != ETRAXGPIO_IOCTYPE)
515 return -EINVAL; 511 return -EINVAL;
516 512
517 spin_lock_irqsave(&gpio_lock, flags);
518
519 switch (_IOC_NR(cmd)) { 513 switch (_IOC_NR(cmd)) {
520 case IO_READBITS: /* Use IO_READ_INBITS and IO_READ_OUTBITS instead */ 514 case IO_READBITS: /* Use IO_READ_INBITS and IO_READ_OUTBITS instead */
521 // read the port 515 // read the port
516 spin_lock_irqsave(&gpio_lock, flags);
522 if (USE_PORTS(priv)) { 517 if (USE_PORTS(priv)) {
523 ret = *priv->port; 518 ret = *priv->port;
524 } else if (priv->minor == GPIO_MINOR_G) { 519 } else if (priv->minor == GPIO_MINOR_G) {
525 ret = (*R_PORT_G_DATA) & 0x7FFFFFFF; 520 ret = (*R_PORT_G_DATA) & 0x7FFFFFFF;
526 } 521 }
522 spin_unlock_irqrestore(&gpio_lock, flags);
523
527 break; 524 break;
528 case IO_SETBITS: 525 case IO_SETBITS:
529 // set changeable bits with a 1 in arg 526 // set changeable bits with a 1 in arg
527 spin_lock_irqsave(&gpio_lock, flags);
528
530 if (USE_PORTS(priv)) { 529 if (USE_PORTS(priv)) {
531 *priv->port = *priv->shadow |= 530 *priv->port = *priv->shadow |=
532 ((unsigned char)arg & priv->changeable_bits); 531 ((unsigned char)arg & priv->changeable_bits);
533 } else if (priv->minor == GPIO_MINOR_G) { 532 } else if (priv->minor == GPIO_MINOR_G) {
534 *R_PORT_G_DATA = port_g_data_shadow |= (arg & dir_g_out_bits); 533 *R_PORT_G_DATA = port_g_data_shadow |= (arg & dir_g_out_bits);
535 } 534 }
535 spin_unlock_irqrestore(&gpio_lock, flags);
536
536 break; 537 break;
537 case IO_CLRBITS: 538 case IO_CLRBITS:
538 // clear changeable bits with a 1 in arg 539 // clear changeable bits with a 1 in arg
540 spin_lock_irqsave(&gpio_lock, flags);
539 if (USE_PORTS(priv)) { 541 if (USE_PORTS(priv)) {
540 *priv->port = *priv->shadow &= 542 *priv->port = *priv->shadow &=
541 ~((unsigned char)arg & priv->changeable_bits); 543 ~((unsigned char)arg & priv->changeable_bits);
542 } else if (priv->minor == GPIO_MINOR_G) { 544 } else if (priv->minor == GPIO_MINOR_G) {
543 *R_PORT_G_DATA = port_g_data_shadow &= ~((unsigned long)arg & dir_g_out_bits); 545 *R_PORT_G_DATA = port_g_data_shadow &= ~((unsigned long)arg & dir_g_out_bits);
544 } 546 }
547 spin_unlock_irqrestore(&gpio_lock, flags);
545 break; 548 break;
546 case IO_HIGHALARM: 549 case IO_HIGHALARM:
547 // set alarm when bits with 1 in arg go high 550 // set alarm when bits with 1 in arg go high
551 spin_lock_irqsave(&gpio_lock, flags);
548 priv->highalarm |= arg; 552 priv->highalarm |= arg;
549 gpio_some_alarms = 1; 553 gpio_some_alarms = 1;
554 spin_unlock_irqrestore(&gpio_lock, flags);
550 break; 555 break;
551 case IO_LOWALARM: 556 case IO_LOWALARM:
552 // set alarm when bits with 1 in arg go low 557 // set alarm when bits with 1 in arg go low
558 spin_lock_irqsave(&gpio_lock, flags);
553 priv->lowalarm |= arg; 559 priv->lowalarm |= arg;
554 gpio_some_alarms = 1; 560 gpio_some_alarms = 1;
561 spin_unlock_irqrestore(&gpio_lock, flags);
555 break; 562 break;
556 case IO_CLRALARM: 563 case IO_CLRALARM:
557 // clear alarm for bits with 1 in arg 564 /* clear alarm for bits with 1 in arg */
565 spin_lock_irqsave(&gpio_lock, flags);
558 priv->highalarm &= ~arg; 566 priv->highalarm &= ~arg;
559 priv->lowalarm &= ~arg; 567 priv->lowalarm &= ~arg;
560 { 568 {
561 /* Must update gpio_some_alarms */ 569 /* Must update gpio_some_alarms */
562 struct gpio_private *p = alarmlist; 570 struct gpio_private *p = alarmlist;
563 int some_alarms; 571 int some_alarms;
564 spin_lock_irq(&gpio_lock);
565 p = alarmlist; 572 p = alarmlist;
566 some_alarms = 0; 573 some_alarms = 0;
567 while (p) { 574 while (p) {
@@ -572,11 +579,12 @@ gpio_ioctl_unlocked(struct file *file, unsigned int cmd, unsigned long arg)
572 p = p->next; 579 p = p->next;
573 } 580 }
574 gpio_some_alarms = some_alarms; 581 gpio_some_alarms = some_alarms;
575 spin_unlock_irq(&gpio_lock);
576 } 582 }
583 spin_unlock_irqrestore(&gpio_lock, flags);
577 break; 584 break;
578 case IO_READDIR: /* Use IO_SETGET_INPUT/OUTPUT instead! */ 585 case IO_READDIR: /* Use IO_SETGET_INPUT/OUTPUT instead! */
579 /* Read direction 0=input 1=output */ 586 /* Read direction 0=input 1=output */
587 spin_lock_irqsave(&gpio_lock, flags);
580 if (USE_PORTS(priv)) { 588 if (USE_PORTS(priv)) {
581 ret = *priv->dir_shadow; 589 ret = *priv->dir_shadow;
582 } else if (priv->minor == GPIO_MINOR_G) { 590 } else if (priv->minor == GPIO_MINOR_G) {
@@ -585,30 +593,40 @@ gpio_ioctl_unlocked(struct file *file, unsigned int cmd, unsigned long arg)
585 */ 593 */
586 ret = (dir_g_shadow | dir_g_out_bits) & 0x7FFFFFFF; 594 ret = (dir_g_shadow | dir_g_out_bits) & 0x7FFFFFFF;
587 } 595 }
596 spin_unlock_irqrestore(&gpio_lock, flags);
588 break; 597 break;
589 case IO_SETINPUT: /* Use IO_SETGET_INPUT instead! */ 598 case IO_SETINPUT: /* Use IO_SETGET_INPUT instead! */
590 /* Set direction 0=unchanged 1=input, 599 /* Set direction 0=unchanged 1=input,
591 * return mask with 1=input 600 * return mask with 1=input
592 */ 601 */
602 spin_lock_irqsave(&gpio_lock, flags);
593 ret = setget_input(priv, arg) & 0x7FFFFFFF; 603 ret = setget_input(priv, arg) & 0x7FFFFFFF;
604 spin_unlock_irqrestore(&gpio_lock, flags);
594 break; 605 break;
595 case IO_SETOUTPUT: /* Use IO_SETGET_OUTPUT instead! */ 606 case IO_SETOUTPUT: /* Use IO_SETGET_OUTPUT instead! */
596 /* Set direction 0=unchanged 1=output, 607 /* Set direction 0=unchanged 1=output,
597 * return mask with 1=output 608 * return mask with 1=output
598 */ 609 */
610 spin_lock_irqsave(&gpio_lock, flags);
599 ret = setget_output(priv, arg) & 0x7FFFFFFF; 611 ret = setget_output(priv, arg) & 0x7FFFFFFF;
612 spin_unlock_irqrestore(&gpio_lock, flags);
600 break; 613 break;
601 case IO_SHUTDOWN: 614 case IO_SHUTDOWN:
615 spin_lock_irqsave(&gpio_lock, flags);
602 SOFT_SHUTDOWN(); 616 SOFT_SHUTDOWN();
617 spin_unlock_irqrestore(&gpio_lock, flags);
603 break; 618 break;
604 case IO_GET_PWR_BT: 619 case IO_GET_PWR_BT:
620 spin_lock_irqsave(&gpio_lock, flags);
605#if defined (CONFIG_ETRAX_SOFT_SHUTDOWN) 621#if defined (CONFIG_ETRAX_SOFT_SHUTDOWN)
606 ret = (*R_PORT_G_DATA & ( 1 << CONFIG_ETRAX_POWERBUTTON_BIT)); 622 ret = (*R_PORT_G_DATA & ( 1 << CONFIG_ETRAX_POWERBUTTON_BIT));
607#else 623#else
608 ret = 0; 624 ret = 0;
609#endif 625#endif
626 spin_unlock_irqrestore(&gpio_lock, flags);
610 break; 627 break;
611 case IO_CFG_WRITE_MODE: 628 case IO_CFG_WRITE_MODE:
629 spin_lock_irqsave(&gpio_lock, flags);
612 priv->clk_mask = arg & 0xFF; 630 priv->clk_mask = arg & 0xFF;
613 priv->data_mask = (arg >> 8) & 0xFF; 631 priv->data_mask = (arg >> 8) & 0xFF;
614 priv->write_msb = (arg >> 16) & 0x01; 632 priv->write_msb = (arg >> 16) & 0x01;
@@ -624,28 +642,33 @@ gpio_ioctl_unlocked(struct file *file, unsigned int cmd, unsigned long arg)
624 priv->data_mask = 0; 642 priv->data_mask = 0;
625 ret = -EPERM; 643 ret = -EPERM;
626 } 644 }
645 spin_unlock_irqrestore(&gpio_lock, flags);
627 break; 646 break;
628 case IO_READ_INBITS: 647 case IO_READ_INBITS:
629 /* *arg is result of reading the input pins */ 648 /* *arg is result of reading the input pins */
649 spin_lock_irqsave(&gpio_lock, flags);
630 if (USE_PORTS(priv)) { 650 if (USE_PORTS(priv)) {
631 val = *priv->port; 651 val = *priv->port;
632 } else if (priv->minor == GPIO_MINOR_G) { 652 } else if (priv->minor == GPIO_MINOR_G) {
633 val = *R_PORT_G_DATA; 653 val = *R_PORT_G_DATA;
634 } 654 }
655 spin_unlock_irqrestore(&gpio_lock, flags);
635 if (copy_to_user((void __user *)arg, &val, sizeof(val))) 656 if (copy_to_user((void __user *)arg, &val, sizeof(val)))
636 ret = -EFAULT; 657 ret = -EFAULT;
637 break; 658 break;
638 case IO_READ_OUTBITS: 659 case IO_READ_OUTBITS:
639 /* *arg is result of reading the output shadow */ 660 /* *arg is result of reading the output shadow */
661 spin_lock_irqsave(&gpio_lock, flags);
640 if (USE_PORTS(priv)) { 662 if (USE_PORTS(priv)) {
641 val = *priv->shadow; 663 val = *priv->shadow;
642 } else if (priv->minor == GPIO_MINOR_G) { 664 } else if (priv->minor == GPIO_MINOR_G) {
643 val = port_g_data_shadow; 665 val = port_g_data_shadow;
644 } 666 }
667 spin_unlock_irqrestore(&gpio_lock, flags);
645 if (copy_to_user((void __user *)arg, &val, sizeof(val))) 668 if (copy_to_user((void __user *)arg, &val, sizeof(val)))
646 ret = -EFAULT; 669 ret = -EFAULT;
647 break; 670 break;
648 case IO_SETGET_INPUT: 671 case IO_SETGET_INPUT:
649 /* bits set in *arg is set to input, 672 /* bits set in *arg is set to input,
650 * *arg updated with current input pins. 673 * *arg updated with current input pins.
651 */ 674 */
@@ -654,7 +677,9 @@ gpio_ioctl_unlocked(struct file *file, unsigned int cmd, unsigned long arg)
654 ret = -EFAULT; 677 ret = -EFAULT;
655 break; 678 break;
656 } 679 }
680 spin_lock_irqsave(&gpio_lock, flags);
657 val = setget_input(priv, val); 681 val = setget_input(priv, val);
682 spin_unlock_irqrestore(&gpio_lock, flags);
658 if (copy_to_user((void __user *)arg, &val, sizeof(val))) 683 if (copy_to_user((void __user *)arg, &val, sizeof(val)))
659 ret = -EFAULT; 684 ret = -EFAULT;
660 break; 685 break;
@@ -666,34 +691,25 @@ gpio_ioctl_unlocked(struct file *file, unsigned int cmd, unsigned long arg)
666 ret = -EFAULT; 691 ret = -EFAULT;
667 break; 692 break;
668 } 693 }
694 spin_lock_irqsave(&gpio_lock, flags);
669 val = setget_output(priv, val); 695 val = setget_output(priv, val);
696 spin_unlock_irqrestore(&gpio_lock, flags);
670 if (copy_to_user((void __user *)arg, &val, sizeof(val))) 697 if (copy_to_user((void __user *)arg, &val, sizeof(val)))
671 ret = -EFAULT; 698 ret = -EFAULT;
672 break; 699 break;
673 default: 700 default:
701 spin_lock_irqsave(&gpio_lock, flags);
674 if (priv->minor == GPIO_MINOR_LEDS) 702 if (priv->minor == GPIO_MINOR_LEDS)
675 ret = gpio_leds_ioctl(cmd, arg); 703 ret = gpio_leds_ioctl(cmd, arg);
676 else 704 else
677 ret = -EINVAL; 705 ret = -EINVAL;
706 spin_unlock_irqrestore(&gpio_lock, flags);
678 } /* switch */ 707 } /* switch */
679 708
680 spin_unlock_irqrestore(&gpio_lock, flags);
681 return ret; 709 return ret;
682} 710}
683 711
684static int 712static int
685gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
686{
687 long ret;
688
689 lock_kernel();
690 ret = gpio_ioctl_unlocked(file, cmd, arg);
691 unlock_kernel();
692
693 return ret;
694}
695
696static int
697gpio_leds_ioctl(unsigned int cmd, unsigned long arg) 713gpio_leds_ioctl(unsigned int cmd, unsigned long arg)
698{ 714{
699 unsigned char green; 715 unsigned char green;