diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
commit | 8dea78da5cee153b8af9c07a2745f6c55057fe12 (patch) | |
tree | a8f4d49d63b1ecc92f2fddceba0655b2472c5bd9 /drivers/misc/carma/carma-fpga.c | |
parent | 406089d01562f1e2bf9f089fd7637009ebaad589 (diff) |
Patched in Tegra support.
Diffstat (limited to 'drivers/misc/carma/carma-fpga.c')
-rw-r--r-- | drivers/misc/carma/carma-fpga.c | 140 |
1 files changed, 64 insertions, 76 deletions
diff --git a/drivers/misc/carma/carma-fpga.c b/drivers/misc/carma/carma-fpga.c index 8835eabb3b8..3965821fef1 100644 --- a/drivers/misc/carma/carma-fpga.c +++ b/drivers/misc/carma/carma-fpga.c | |||
@@ -560,9 +560,6 @@ 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); | ||
566 | 563 | ||
567 | /* switch back to the external interrupt source */ | 564 | /* switch back to the external interrupt source */ |
568 | iowrite32be(0x3F, priv->regs + SYS_IRQ_SOURCE_CTL); | 565 | iowrite32be(0x3F, priv->regs + SYS_IRQ_SOURCE_CTL); |
@@ -594,12 +591,8 @@ static void data_dma_cb(void *data) | |||
594 | list_move_tail(&priv->inflight->entry, &priv->used); | 591 | list_move_tail(&priv->inflight->entry, &priv->used); |
595 | priv->inflight = NULL; | 592 | priv->inflight = NULL; |
596 | 593 | ||
597 | /* | 594 | /* clear the FPGA status and re-enable interrupts */ |
598 | * If data dumping is still enabled, then clear the FPGA | 595 | data_enable_interrupts(priv); |
599 | * status registers and re-enable FPGA interrupts | ||
600 | */ | ||
601 | if (priv->enabled) | ||
602 | data_enable_interrupts(priv); | ||
603 | 596 | ||
604 | spin_unlock_irqrestore(&priv->lock, flags); | 597 | spin_unlock_irqrestore(&priv->lock, flags); |
605 | 598 | ||
@@ -666,7 +659,7 @@ static int data_submit_dma(struct fpga_device *priv, struct data_buf *buf) | |||
666 | src = SYS_FPGA_BLOCK; | 659 | src = SYS_FPGA_BLOCK; |
667 | tx = chan->device->device_prep_dma_memcpy(chan, dst, src, | 660 | tx = chan->device->device_prep_dma_memcpy(chan, dst, src, |
668 | REG_BLOCK_SIZE, | 661 | REG_BLOCK_SIZE, |
669 | 0); | 662 | DMA_PREP_INTERRUPT); |
670 | if (!tx) { | 663 | if (!tx) { |
671 | dev_err(priv->dev, "unable to prep SYS-FPGA DMA\n"); | 664 | dev_err(priv->dev, "unable to prep SYS-FPGA DMA\n"); |
672 | return -ENOMEM; | 665 | return -ENOMEM; |
@@ -715,15 +708,6 @@ static irqreturn_t data_irq(int irq, void *dev_id) | |||
715 | 708 | ||
716 | spin_lock(&priv->lock); | 709 | spin_lock(&priv->lock); |
717 | 710 | ||
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 | |||
727 | /* hide the interrupt by switching the IRQ driver to GPIO */ | 711 | /* hide the interrupt by switching the IRQ driver to GPIO */ |
728 | data_disable_interrupts(priv); | 712 | data_disable_interrupts(priv); |
729 | 713 | ||
@@ -778,15 +762,11 @@ out: | |||
778 | */ | 762 | */ |
779 | static int data_device_enable(struct fpga_device *priv) | 763 | static int data_device_enable(struct fpga_device *priv) |
780 | { | 764 | { |
781 | bool enabled; | ||
782 | u32 val; | 765 | u32 val; |
783 | int ret; | 766 | int ret; |
784 | 767 | ||
785 | /* multiple enables are safe: they do nothing */ | 768 | /* multiple enables are safe: they do nothing */ |
786 | spin_lock_irq(&priv->lock); | 769 | if (priv->enabled) |
787 | enabled = priv->enabled; | ||
788 | spin_unlock_irq(&priv->lock); | ||
789 | if (enabled) | ||
790 | return 0; | 770 | return 0; |
791 | 771 | ||
792 | /* check that the FPGAs are programmed */ | 772 | /* check that the FPGAs are programmed */ |
@@ -817,9 +797,6 @@ static int data_device_enable(struct fpga_device *priv) | |||
817 | goto out_error; | 797 | goto out_error; |
818 | } | 798 | } |
819 | 799 | ||
820 | /* prevent the FPGAs from generating interrupts */ | ||
821 | data_disable_interrupts(priv); | ||
822 | |||
823 | /* hookup the irq handler */ | 800 | /* hookup the irq handler */ |
824 | ret = request_irq(priv->irq, data_irq, IRQF_SHARED, drv_name, priv); | 801 | ret = request_irq(priv->irq, data_irq, IRQF_SHARED, drv_name, priv); |
825 | if (ret) { | 802 | if (ret) { |
@@ -827,13 +804,11 @@ static int data_device_enable(struct fpga_device *priv) | |||
827 | goto out_error; | 804 | goto out_error; |
828 | } | 805 | } |
829 | 806 | ||
830 | /* allow the DMA callback to re-enable FPGA interrupts */ | 807 | /* switch to the external FPGA IRQ line */ |
831 | spin_lock_irq(&priv->lock); | ||
832 | priv->enabled = true; | ||
833 | spin_unlock_irq(&priv->lock); | ||
834 | |||
835 | /* allow the FPGAs to generate interrupts */ | ||
836 | data_enable_interrupts(priv); | 808 | data_enable_interrupts(priv); |
809 | |||
810 | /* success, we're enabled */ | ||
811 | priv->enabled = true; | ||
837 | return 0; | 812 | return 0; |
838 | 813 | ||
839 | out_error: | 814 | out_error: |
@@ -859,40 +834,41 @@ out_error: | |||
859 | */ | 834 | */ |
860 | static int data_device_disable(struct fpga_device *priv) | 835 | static int data_device_disable(struct fpga_device *priv) |
861 | { | 836 | { |
862 | spin_lock_irq(&priv->lock); | 837 | int ret; |
863 | 838 | ||
864 | /* allow multiple disable */ | 839 | /* allow multiple disable */ |
865 | if (!priv->enabled) { | 840 | if (!priv->enabled) |
866 | spin_unlock_irq(&priv->lock); | ||
867 | return 0; | 841 | 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; | ||
876 | 842 | ||
877 | /* prevent the FPGAs from generating interrupts */ | 843 | /* switch to the internal GPIO IRQ line */ |
878 | data_disable_interrupts(priv); | 844 | data_disable_interrupts(priv); |
879 | 845 | ||
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 | |||
889 | /* unhook the irq handler */ | 846 | /* unhook the irq handler */ |
890 | free_irq(priv->irq, priv); | 847 | free_irq(priv->irq, priv); |
891 | 848 | ||
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 | |||
892 | /* free the correlation table */ | 859 | /* free the correlation table */ |
893 | sg_free_table(&priv->corl_table); | 860 | sg_free_table(&priv->corl_table); |
894 | priv->corl_nents = 0; | 861 | priv->corl_nents = 0; |
895 | 862 | ||
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 | |||
896 | /* free all buffers: the free and used lists are not being changed */ | 872 | /* free all buffers: the free and used lists are not being changed */ |
897 | data_free_buffers(priv); | 873 | data_free_buffers(priv); |
898 | return 0; | 874 | return 0; |
@@ -920,6 +896,15 @@ static unsigned int list_num_entries(struct list_head *list) | |||
920 | static int data_debug_show(struct seq_file *f, void *offset) | 896 | static int data_debug_show(struct seq_file *f, void *offset) |
921 | { | 897 | { |
922 | struct fpga_device *priv = f->private; | 898 | 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; | ||
923 | 908 | ||
924 | spin_lock_irq(&priv->lock); | 909 | spin_lock_irq(&priv->lock); |
925 | 910 | ||
@@ -932,6 +917,7 @@ static int data_debug_show(struct seq_file *f, void *offset) | |||
932 | seq_printf(f, "num_dropped: %d\n", priv->num_dropped); | 917 | seq_printf(f, "num_dropped: %d\n", priv->num_dropped); |
933 | 918 | ||
934 | spin_unlock_irq(&priv->lock); | 919 | spin_unlock_irq(&priv->lock); |
920 | mutex_unlock(&priv->mutex); | ||
935 | return 0; | 921 | return 0; |
936 | } | 922 | } |
937 | 923 | ||
@@ -984,13 +970,7 @@ static ssize_t data_en_show(struct device *dev, struct device_attribute *attr, | |||
984 | char *buf) | 970 | char *buf) |
985 | { | 971 | { |
986 | struct fpga_device *priv = dev_get_drvdata(dev); | 972 | struct fpga_device *priv = dev_get_drvdata(dev); |
987 | int ret; | 973 | return snprintf(buf, PAGE_SIZE, "%u\n", priv->enabled); |
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; | ||
994 | } | 974 | } |
995 | 975 | ||
996 | static ssize_t data_en_set(struct device *dev, struct device_attribute *attr, | 976 | static ssize_t data_en_set(struct device *dev, struct device_attribute *attr, |
@@ -1006,7 +986,6 @@ static ssize_t data_en_set(struct device *dev, struct device_attribute *attr, | |||
1006 | return -EINVAL; | 986 | return -EINVAL; |
1007 | } | 987 | } |
1008 | 988 | ||
1009 | /* protect against concurrent enable/disable */ | ||
1010 | ret = mutex_lock_interruptible(&priv->mutex); | 989 | ret = mutex_lock_interruptible(&priv->mutex); |
1011 | if (ret) | 990 | if (ret) |
1012 | return ret; | 991 | return ret; |
@@ -1100,7 +1079,6 @@ static ssize_t data_read(struct file *filp, char __user *ubuf, size_t count, | |||
1100 | struct fpga_reader *reader = filp->private_data; | 1079 | struct fpga_reader *reader = filp->private_data; |
1101 | struct fpga_device *priv = reader->priv; | 1080 | struct fpga_device *priv = reader->priv; |
1102 | struct list_head *used = &priv->used; | 1081 | struct list_head *used = &priv->used; |
1103 | bool drop_buffer = false; | ||
1104 | struct data_buf *dbuf; | 1082 | struct data_buf *dbuf; |
1105 | size_t avail; | 1083 | size_t avail; |
1106 | void *data; | 1084 | void *data; |
@@ -1188,12 +1166,10 @@ have_buffer: | |||
1188 | * One of two things has happened, the device is disabled, or the | 1166 | * One of two things has happened, the device is disabled, or the |
1189 | * device has been reconfigured underneath us. In either case, we | 1167 | * device has been reconfigured underneath us. In either case, we |
1190 | * should just throw away the buffer. | 1168 | * 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. | ||
1194 | */ | 1169 | */ |
1195 | if (!priv->enabled || dbuf->size != priv->bufsize) { | 1170 | if (!priv->enabled || dbuf->size != priv->bufsize) { |
1196 | drop_buffer = true; | 1171 | videobuf_dma_unmap(priv->dev, &dbuf->vb); |
1172 | data_free_buffer(dbuf); | ||
1197 | goto out_unlock; | 1173 | goto out_unlock; |
1198 | } | 1174 | } |
1199 | 1175 | ||
@@ -1202,12 +1178,6 @@ have_buffer: | |||
1202 | 1178 | ||
1203 | out_unlock: | 1179 | out_unlock: |
1204 | spin_unlock_irq(&priv->lock); | 1180 | 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 | |||
1211 | return count; | 1181 | return count; |
1212 | } | 1182 | } |
1213 | 1183 | ||
@@ -1243,6 +1213,8 @@ static int data_mmap(struct file *filp, struct vm_area_struct *vma) | |||
1243 | return -EINVAL; | 1213 | return -EINVAL; |
1244 | } | 1214 | } |
1245 | 1215 | ||
1216 | /* IO memory (stop cacheing) */ | ||
1217 | vma->vm_flags |= VM_IO | VM_RESERVED; | ||
1246 | vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); | 1218 | vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); |
1247 | 1219 | ||
1248 | return io_remap_pfn_range(vma, vma->vm_start, addr, vsize, | 1220 | return io_remap_pfn_range(vma, vma->vm_start, addr, vsize, |
@@ -1277,7 +1249,8 @@ static bool dma_filter(struct dma_chan *chan, void *data) | |||
1277 | return true; | 1249 | return true; |
1278 | } | 1250 | } |
1279 | 1251 | ||
1280 | static int data_of_probe(struct platform_device *op) | 1252 | static int data_of_probe(struct platform_device *op, |
1253 | const struct of_device_id *match) | ||
1281 | { | 1254 | { |
1282 | struct device_node *of_node = op->dev.of_node; | 1255 | struct device_node *of_node = op->dev.of_node; |
1283 | struct device *this_device; | 1256 | struct device *this_device; |
@@ -1428,7 +1401,7 @@ static struct of_device_id data_of_match[] = { | |||
1428 | {}, | 1401 | {}, |
1429 | }; | 1402 | }; |
1430 | 1403 | ||
1431 | static struct platform_driver data_of_driver = { | 1404 | static struct of_platform_driver data_of_driver = { |
1432 | .probe = data_of_probe, | 1405 | .probe = data_of_probe, |
1433 | .remove = data_of_remove, | 1406 | .remove = data_of_remove, |
1434 | .driver = { | 1407 | .driver = { |
@@ -1438,8 +1411,23 @@ static struct platform_driver data_of_driver = { | |||
1438 | }, | 1411 | }, |
1439 | }; | 1412 | }; |
1440 | 1413 | ||
1441 | module_platform_driver(data_of_driver); | 1414 | /* |
1415 | * Module Init / Exit | ||
1416 | */ | ||
1417 | |||
1418 | static int __init data_init(void) | ||
1419 | { | ||
1420 | return of_register_platform_driver(&data_of_driver); | ||
1421 | } | ||
1422 | |||
1423 | static void __exit data_exit(void) | ||
1424 | { | ||
1425 | of_unregister_platform_driver(&data_of_driver); | ||
1426 | } | ||
1442 | 1427 | ||
1443 | MODULE_AUTHOR("Ira W. Snyder <iws@ovro.caltech.edu>"); | 1428 | MODULE_AUTHOR("Ira W. Snyder <iws@ovro.caltech.edu>"); |
1444 | MODULE_DESCRIPTION("CARMA DATA-FPGA Access Driver"); | 1429 | MODULE_DESCRIPTION("CARMA DATA-FPGA Access Driver"); |
1445 | MODULE_LICENSE("GPL"); | 1430 | MODULE_LICENSE("GPL"); |
1431 | |||
1432 | module_init(data_init); | ||
1433 | module_exit(data_exit); | ||