diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-03-21 21:55:10 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-03-21 21:55:10 -0400 |
commit | 5375871d432ae9fc581014ac117b96aaee3cd0c7 (patch) | |
tree | be98e8255b0f927fb920fb532a598b93fa140dbe /drivers/misc/carma/carma-fpga.c | |
parent | b57cb7231b2ce52d3dda14a7b417ae125fb2eb97 (diff) | |
parent | dfbc2d75c1bd47c3186fa91f1655ea2f3825b0ec (diff) |
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc
Pull powerpc merge from Benjamin Herrenschmidt:
"Here's the powerpc batch for this merge window. It is going to be a
bit more nasty than usual as in touching things outside of
arch/powerpc mostly due to the big iSeriesectomy :-) We finally got
rid of the bugger (legacy iSeries support) which was a PITA to
maintain and that nobody really used anymore.
Here are some of the highlights:
- Legacy iSeries is gone. Thanks Stephen ! There's still some bits
and pieces remaining if you do a grep -ir series arch/powerpc but
they are harmless and will be removed in the next few weeks
hopefully.
- The 'fadump' functionality (Firmware Assisted Dump) replaces the
previous (equivalent) "pHyp assisted dump"... it's a rewrite of a
mechanism to get the hypervisor to do crash dumps on pSeries, the
new implementation hopefully being much more reliable. Thanks
Mahesh Salgaonkar.
- The "EEH" code (pSeries PCI error handling & recovery) got a big
spring cleaning, motivated by the need to be able to implement a
new backend for it on top of some new different type of firwmare.
The work isn't complete yet, but a good chunk of the cleanups is
there. Note that this adds a field to struct device_node which is
not very nice and which Grant objects to. I will have a patch soon
that moves that to a powerpc private data structure (hopefully
before rc1) and we'll improve things further later on (hopefully
getting rid of the need for that pointer completely). Thanks Gavin
Shan.
- I dug into our exception & interrupt handling code to improve the
way we do lazy interrupt handling (and make it work properly with
"edge" triggered interrupt sources), and while at it found & fixed
a wagon of issues in those areas, including adding support for page
fault retry & fatal signals on page faults.
- Your usual random batch of small fixes & updates, including a bunch
of new embedded boards, both Freescale and APM based ones, etc..."
I fixed up some conflicts with the generalized irq-domain changes from
Grant Likely, hopefully correctly.
* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc: (141 commits)
powerpc/ps3: Do not adjust the wrapper load address
powerpc: Remove the rest of the legacy iSeries include files
powerpc: Remove the remaining CONFIG_PPC_ISERIES pieces
init: Remove CONFIG_PPC_ISERIES
powerpc: Remove FW_FEATURE ISERIES from arch code
tty/hvc_vio: FW_FEATURE_ISERIES is no longer selectable
powerpc/spufs: Fix double unlocks
powerpc/5200: convert mpc5200 to use of_platform_populate()
powerpc/mpc5200: add options to mpc5200_defconfig
powerpc/mpc52xx: add a4m072 board support
powerpc/mpc5200: update mpc5200_defconfig to fit for charon board
Documentation/powerpc/mpc52xx.txt: Checkpatch cleanup
powerpc/44x: Add additional device support for APM821xx SoC and Bluestone board
powerpc/44x: Add support PCI-E for APM821xx SoC and Bluestone board
MAINTAINERS: Update PowerPC 4xx tree
powerpc/44x: The bug fixed support for APM821xx SoC and Bluestone board
powerpc: document the FSL MPIC message register binding
powerpc: add support for MPIC message register API
powerpc/fsl: Added aliased MSIIR register address to MSI node in dts
powerpc/85xx: mpc8548cds - add 36-bit dts
...
Diffstat (limited to 'drivers/misc/carma/carma-fpga.c')
-rw-r--r-- | drivers/misc/carma/carma-fpga.c | 114 |
1 files changed, 72 insertions, 42 deletions
diff --git a/drivers/misc/carma/carma-fpga.c b/drivers/misc/carma/carma-fpga.c index 366bc156e34d..8c279da07410 100644 --- a/drivers/misc/carma/carma-fpga.c +++ b/drivers/misc/carma/carma-fpga.c | |||
@@ -560,6 +560,9 @@ static void data_enable_interrupts(struct fpga_device *priv) | |||
560 | 560 | ||
561 | /* flush the writes */ | 561 | /* flush the writes */ |
562 | fpga_read_reg(priv, 0, MMAP_REG_STATUS); | 562 | fpga_read_reg(priv, 0, MMAP_REG_STATUS); |
563 | fpga_read_reg(priv, 1, MMAP_REG_STATUS); | ||
564 | fpga_read_reg(priv, 2, MMAP_REG_STATUS); | ||
565 | fpga_read_reg(priv, 3, MMAP_REG_STATUS); | ||
563 | 566 | ||
564 | /* switch back to the external interrupt source */ | 567 | /* switch back to the external interrupt source */ |
565 | iowrite32be(0x3F, priv->regs + SYS_IRQ_SOURCE_CTL); | 568 | iowrite32be(0x3F, priv->regs + SYS_IRQ_SOURCE_CTL); |
@@ -591,8 +594,12 @@ static void data_dma_cb(void *data) | |||
591 | list_move_tail(&priv->inflight->entry, &priv->used); | 594 | list_move_tail(&priv->inflight->entry, &priv->used); |
592 | priv->inflight = NULL; | 595 | priv->inflight = NULL; |
593 | 596 | ||
594 | /* clear the FPGA status and re-enable interrupts */ | 597 | /* |
595 | data_enable_interrupts(priv); | 598 | * If data dumping is still enabled, then clear the FPGA |
599 | * status registers and re-enable FPGA interrupts | ||
600 | */ | ||
601 | if (priv->enabled) | ||
602 | data_enable_interrupts(priv); | ||
596 | 603 | ||
597 | spin_unlock_irqrestore(&priv->lock, flags); | 604 | spin_unlock_irqrestore(&priv->lock, flags); |
598 | 605 | ||
@@ -708,6 +715,15 @@ static irqreturn_t data_irq(int irq, void *dev_id) | |||
708 | 715 | ||
709 | spin_lock(&priv->lock); | 716 | spin_lock(&priv->lock); |
710 | 717 | ||
718 | /* | ||
719 | * This is an error case that should never happen. | ||
720 | * | ||
721 | * If this driver has a bug and manages to re-enable interrupts while | ||
722 | * a DMA is in progress, then we will hit this statement and should | ||
723 | * start paying attention immediately. | ||
724 | */ | ||
725 | BUG_ON(priv->inflight != NULL); | ||
726 | |||
711 | /* hide the interrupt by switching the IRQ driver to GPIO */ | 727 | /* hide the interrupt by switching the IRQ driver to GPIO */ |
712 | data_disable_interrupts(priv); | 728 | data_disable_interrupts(priv); |
713 | 729 | ||
@@ -762,11 +778,15 @@ out: | |||
762 | */ | 778 | */ |
763 | static int data_device_enable(struct fpga_device *priv) | 779 | static int data_device_enable(struct fpga_device *priv) |
764 | { | 780 | { |
781 | bool enabled; | ||
765 | u32 val; | 782 | u32 val; |
766 | int ret; | 783 | int ret; |
767 | 784 | ||
768 | /* multiple enables are safe: they do nothing */ | 785 | /* multiple enables are safe: they do nothing */ |
769 | if (priv->enabled) | 786 | spin_lock_irq(&priv->lock); |
787 | enabled = priv->enabled; | ||
788 | spin_unlock_irq(&priv->lock); | ||
789 | if (enabled) | ||
770 | return 0; | 790 | return 0; |
771 | 791 | ||
772 | /* check that the FPGAs are programmed */ | 792 | /* check that the FPGAs are programmed */ |
@@ -797,6 +817,9 @@ static int data_device_enable(struct fpga_device *priv) | |||
797 | goto out_error; | 817 | goto out_error; |
798 | } | 818 | } |
799 | 819 | ||
820 | /* prevent the FPGAs from generating interrupts */ | ||
821 | data_disable_interrupts(priv); | ||
822 | |||
800 | /* hookup the irq handler */ | 823 | /* hookup the irq handler */ |
801 | ret = request_irq(priv->irq, data_irq, IRQF_SHARED, drv_name, priv); | 824 | ret = request_irq(priv->irq, data_irq, IRQF_SHARED, drv_name, priv); |
802 | if (ret) { | 825 | if (ret) { |
@@ -804,11 +827,13 @@ static int data_device_enable(struct fpga_device *priv) | |||
804 | goto out_error; | 827 | goto out_error; |
805 | } | 828 | } |
806 | 829 | ||
807 | /* switch to the external FPGA IRQ line */ | 830 | /* allow the DMA callback to re-enable FPGA interrupts */ |
808 | data_enable_interrupts(priv); | 831 | spin_lock_irq(&priv->lock); |
809 | |||
810 | /* success, we're enabled */ | ||
811 | priv->enabled = true; | 832 | priv->enabled = true; |
833 | spin_unlock_irq(&priv->lock); | ||
834 | |||
835 | /* allow the FPGAs to generate interrupts */ | ||
836 | data_enable_interrupts(priv); | ||
812 | return 0; | 837 | return 0; |
813 | 838 | ||
814 | out_error: | 839 | out_error: |
@@ -834,41 +859,40 @@ out_error: | |||
834 | */ | 859 | */ |
835 | static int data_device_disable(struct fpga_device *priv) | 860 | static int data_device_disable(struct fpga_device *priv) |
836 | { | 861 | { |
837 | int ret; | 862 | spin_lock_irq(&priv->lock); |
838 | 863 | ||
839 | /* allow multiple disable */ | 864 | /* allow multiple disable */ |
840 | if (!priv->enabled) | 865 | if (!priv->enabled) { |
866 | spin_unlock_irq(&priv->lock); | ||
841 | return 0; | 867 | return 0; |
868 | } | ||
869 | |||
870 | /* | ||
871 | * Mark the device disabled | ||
872 | * | ||
873 | * This stops DMA callbacks from re-enabling interrupts | ||
874 | */ | ||
875 | priv->enabled = false; | ||
842 | 876 | ||
843 | /* switch to the internal GPIO IRQ line */ | 877 | /* prevent the FPGAs from generating interrupts */ |
844 | data_disable_interrupts(priv); | 878 | data_disable_interrupts(priv); |
845 | 879 | ||
880 | /* wait until all ongoing DMA has finished */ | ||
881 | while (priv->inflight != NULL) { | ||
882 | spin_unlock_irq(&priv->lock); | ||
883 | wait_event(priv->wait, priv->inflight == NULL); | ||
884 | spin_lock_irq(&priv->lock); | ||
885 | } | ||
886 | |||
887 | spin_unlock_irq(&priv->lock); | ||
888 | |||
846 | /* unhook the irq handler */ | 889 | /* unhook the irq handler */ |
847 | free_irq(priv->irq, priv); | 890 | free_irq(priv->irq, priv); |
848 | 891 | ||
849 | /* | ||
850 | * wait for all outstanding DMA to complete | ||
851 | * | ||
852 | * Device interrupts are disabled, therefore another buffer cannot | ||
853 | * be marked inflight. | ||
854 | */ | ||
855 | ret = wait_event_interruptible(priv->wait, priv->inflight == NULL); | ||
856 | if (ret) | ||
857 | return ret; | ||
858 | |||
859 | /* free the correlation table */ | 892 | /* free the correlation table */ |
860 | sg_free_table(&priv->corl_table); | 893 | sg_free_table(&priv->corl_table); |
861 | priv->corl_nents = 0; | 894 | priv->corl_nents = 0; |
862 | 895 | ||
863 | /* | ||
864 | * We are taking the spinlock not to protect priv->enabled, but instead | ||
865 | * to make sure that there are no readers in the process of altering | ||
866 | * the free or used lists while we are setting this flag. | ||
867 | */ | ||
868 | spin_lock_irq(&priv->lock); | ||
869 | priv->enabled = false; | ||
870 | spin_unlock_irq(&priv->lock); | ||
871 | |||
872 | /* free all buffers: the free and used lists are not being changed */ | 896 | /* free all buffers: the free and used lists are not being changed */ |
873 | data_free_buffers(priv); | 897 | data_free_buffers(priv); |
874 | return 0; | 898 | return 0; |
@@ -896,15 +920,6 @@ static unsigned int list_num_entries(struct list_head *list) | |||
896 | static int data_debug_show(struct seq_file *f, void *offset) | 920 | static int data_debug_show(struct seq_file *f, void *offset) |
897 | { | 921 | { |
898 | struct fpga_device *priv = f->private; | 922 | struct fpga_device *priv = f->private; |
899 | int ret; | ||
900 | |||
901 | /* | ||
902 | * Lock the mutex first, so that we get an accurate value for enable | ||
903 | * Lock the spinlock next, to get accurate list counts | ||
904 | */ | ||
905 | ret = mutex_lock_interruptible(&priv->mutex); | ||
906 | if (ret) | ||
907 | return ret; | ||
908 | 923 | ||
909 | spin_lock_irq(&priv->lock); | 924 | spin_lock_irq(&priv->lock); |
910 | 925 | ||
@@ -917,7 +932,6 @@ static int data_debug_show(struct seq_file *f, void *offset) | |||
917 | seq_printf(f, "num_dropped: %d\n", priv->num_dropped); | 932 | seq_printf(f, "num_dropped: %d\n", priv->num_dropped); |
918 | 933 | ||
919 | spin_unlock_irq(&priv->lock); | 934 | spin_unlock_irq(&priv->lock); |
920 | mutex_unlock(&priv->mutex); | ||
921 | return 0; | 935 | return 0; |
922 | } | 936 | } |
923 | 937 | ||
@@ -970,7 +984,13 @@ static ssize_t data_en_show(struct device *dev, struct device_attribute *attr, | |||
970 | char *buf) | 984 | char *buf) |
971 | { | 985 | { |
972 | struct fpga_device *priv = dev_get_drvdata(dev); | 986 | struct fpga_device *priv = dev_get_drvdata(dev); |
973 | return snprintf(buf, PAGE_SIZE, "%u\n", priv->enabled); | 987 | int ret; |
988 | |||
989 | spin_lock_irq(&priv->lock); | ||
990 | ret = snprintf(buf, PAGE_SIZE, "%u\n", priv->enabled); | ||
991 | spin_unlock_irq(&priv->lock); | ||
992 | |||
993 | return ret; | ||
974 | } | 994 | } |
975 | 995 | ||
976 | static ssize_t data_en_set(struct device *dev, struct device_attribute *attr, | 996 | static ssize_t data_en_set(struct device *dev, struct device_attribute *attr, |
@@ -986,6 +1006,7 @@ static ssize_t data_en_set(struct device *dev, struct device_attribute *attr, | |||
986 | return -EINVAL; | 1006 | return -EINVAL; |
987 | } | 1007 | } |
988 | 1008 | ||
1009 | /* protect against concurrent enable/disable */ | ||
989 | ret = mutex_lock_interruptible(&priv->mutex); | 1010 | ret = mutex_lock_interruptible(&priv->mutex); |
990 | if (ret) | 1011 | if (ret) |
991 | return ret; | 1012 | return ret; |
@@ -1079,6 +1100,7 @@ static ssize_t data_read(struct file *filp, char __user *ubuf, size_t count, | |||
1079 | struct fpga_reader *reader = filp->private_data; | 1100 | struct fpga_reader *reader = filp->private_data; |
1080 | struct fpga_device *priv = reader->priv; | 1101 | struct fpga_device *priv = reader->priv; |
1081 | struct list_head *used = &priv->used; | 1102 | struct list_head *used = &priv->used; |
1103 | bool drop_buffer = false; | ||
1082 | struct data_buf *dbuf; | 1104 | struct data_buf *dbuf; |
1083 | size_t avail; | 1105 | size_t avail; |
1084 | void *data; | 1106 | void *data; |
@@ -1166,10 +1188,12 @@ have_buffer: | |||
1166 | * One of two things has happened, the device is disabled, or the | 1188 | * One of two things has happened, the device is disabled, or the |
1167 | * device has been reconfigured underneath us. In either case, we | 1189 | * device has been reconfigured underneath us. In either case, we |
1168 | * should just throw away the buffer. | 1190 | * should just throw away the buffer. |
1191 | * | ||
1192 | * Lockdep complains if this is done under the spinlock, so we | ||
1193 | * handle it during the unlock path. | ||
1169 | */ | 1194 | */ |
1170 | if (!priv->enabled || dbuf->size != priv->bufsize) { | 1195 | if (!priv->enabled || dbuf->size != priv->bufsize) { |
1171 | videobuf_dma_unmap(priv->dev, &dbuf->vb); | 1196 | drop_buffer = true; |
1172 | data_free_buffer(dbuf); | ||
1173 | goto out_unlock; | 1197 | goto out_unlock; |
1174 | } | 1198 | } |
1175 | 1199 | ||
@@ -1178,6 +1202,12 @@ have_buffer: | |||
1178 | 1202 | ||
1179 | out_unlock: | 1203 | out_unlock: |
1180 | spin_unlock_irq(&priv->lock); | 1204 | spin_unlock_irq(&priv->lock); |
1205 | |||
1206 | if (drop_buffer) { | ||
1207 | videobuf_dma_unmap(priv->dev, &dbuf->vb); | ||
1208 | data_free_buffer(dbuf); | ||
1209 | } | ||
1210 | |||
1181 | return count; | 1211 | return count; |
1182 | } | 1212 | } |
1183 | 1213 | ||