RE: [PATCH 1/2] misc: add CARMA DATA-FPGA Access Driver

2011-02-10 Thread David Laight
 
  I was completely unaware of that feature. I hunch that many
drivers
  are incapable of dealing with an unbind while they are still open.
 
 Hmm, maybe older drivers... Anythig hotpluggable (USB, PCI, etc)
should
 be in a better shape because they expect to be yanked at any time.

Whim and prayer ???

David


___
Linuxppc-dev mailing list
Linuxppc-dev@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/linuxppc-dev


Re: [PATCH 1/2] misc: add CARMA DATA-FPGA Access Driver

2011-02-09 Thread Dmitry Torokhov
Hi Ira,

On Tue, Feb 08, 2011 at 03:37:46PM -0800, Ira W. Snyder wrote:
 This driver allows userspace to access the data processing FPGAs on the
 OVRO CARMA board. It has two modes of operation:
 

Thank you for making the changes, some more comments below.

 +
 +#define inode_to_dev(inode) container_of(inode-i_cdev, struct fpga_device, 
 cdev)
 +

Does not seem to be used.

 +/*
 + * Data Buffer Allocation Helpers
 + */
 +
 +static int data_map_buffer(struct device *dev, struct data_buf *buf)
 +{
 + return videobuf_dma_map(dev, buf-vb);
 +}
 +
 +static void data_unmap_buffer(struct device *dev, struct data_buf *buf)
 +{
 + videobuf_dma_unmap(dev, buf-vb);
 +}

Why can't we all videobuf_dma_map() and videobuf_dma_unmap() directly?
What these helpers supposed to solve?

 +static int data_alloc_buffers(struct fpga_device *priv)
 +{
 + struct data_buf *buf;
 + int i, ret;
 +
 + for (i = 0; i  MAX_DATA_BUFS; i++) {
 +
 + /* allocate a buffer */
 + buf = data_alloc_buffer(priv-bufsize);
 + if (!buf)
 + continue;

break?

 +
 + /* map it for DMA */
 + ret = data_map_buffer(priv-dev, buf);
 + if (ret) {
 + data_free_buffer(buf);
 + continue;

and here as well?

 + }
 +
 + /* add it to the list of free buffers */
 + list_add_tail(buf-entry, priv-free);
 + priv-num_buffers++;
 + }
 +
 + /* Make sure we allocated the minimum required number of buffers */
 + if (priv-num_buffers  MIN_DATA_BUFS) {
 + dev_err(priv-dev, Unable to allocate enough data buffers\n);
 + data_free_buffers(priv);
 + return -ENOMEM;
 + }
 +
 + /* Warn if we are running in a degraded state, but do not fail */
 + if (priv-num_buffers  MAX_DATA_BUFS) {
 + dev_warn(priv-dev, Unable to allocate one second worth of 
 + buffers, using %d buffers instead\n, i);

The latest style is not break strings even if they exceed 80 column
limit to make sure they are easily greppable.

 +static void data_dma_cb(void *data)
 +{
 + struct fpga_device *priv = data;
 + struct data_buf *buf;
 + unsigned long flags;
 +
 + spin_lock_irqsave(priv-lock, flags);
 +
 + /* clear the FPGA status and re-enable interrupts */
 + data_enable_interrupts(priv);
 +
 + /* If the inflight list is empty, we've got a bug */
 + BUG_ON(list_empty(priv-inflight));
 +
 + /* Grab the first buffer from the inflight list */
 + buf = list_first_entry(priv-inflight, struct data_buf, entry);
 + list_del_init(buf-entry);
 +
 + /* Add it to the used list */
 + list_add_tail(buf-entry, priv-used);

or
list_move_tail(buf-entry, priv-used);

 +
 +static irqreturn_t data_irq(int irq, void *dev_id)
 +{
 + struct fpga_device *priv = dev_id;
 + struct data_buf *buf;
 + u32 status;
 + int i;
 +
 + /* detect spurious interrupts via FPGA status */
 + for (i = 0; i  4; i++) {
 + status = fpga_read_reg(priv, i, MMAP_REG_STATUS);
 + if (!(status  (CORL_DONE | CORL_ERR))) {
 + dev_err(priv-dev, spurious irq detected (FPGA)\n);
 + return IRQ_NONE;
 + }
 + }
 +
 + /* detect spurious interrupts via raw IRQ pin readback */
 + status = ioread32be(priv-regs + SYS_IRQ_INPUT_DATA);
 + if (status  IRQ_CORL_DONE) {
 + dev_err(priv-dev, spurious irq detected (IRQ)\n);
 + return IRQ_NONE;
 + }
 +
 + spin_lock(priv-lock);
 +
 + /* hide the interrupt by switching the IRQ driver to GPIO */
 + data_disable_interrupts(priv);
 +
 + /* Check that we actually have a free buffer */
 + if (list_empty(priv-free)) {
 + priv-num_dropped++;
 + data_enable_interrupts(priv);
 + goto out_unlock;
 + }
 +
 + buf = list_first_entry(priv-free, struct data_buf, entry);
 + list_del_init(buf-entry);
 +
 + /* Check the buffer size */
 + BUG_ON(buf-size != priv-bufsize);
 +
 + /* Submit a DMA transfer to get the correlation data */
 + if (data_submit_dma(priv, buf)) {
 + dev_err(priv-dev, Unable to setup DMA transfer\n);
 + list_add_tail(buf-entry, priv-free);
 + data_enable_interrupts(priv);
 + goto out_unlock;
 + }
 +
 + /* DMA setup succeeded, GO!!! */
 + list_add_tail(buf-entry, priv-inflight);
 + dma_async_memcpy_issue_pending(priv-chan);
 +
 +out_unlock:
 + spin_unlock(priv-lock);
 + return IRQ_HANDLED;
 +}

Hmm, I wonder if we could simplify this a bit by using list_move()...

bool submitted = false;
...

if (list_empty(priv-free)) {
priv-num_dropped++;
goto out;
}

buf = list_first_entry(priv-free, struct data_buf, 

RE: [PATCH 1/2] misc: add CARMA DATA-FPGA Access Driver

2011-02-09 Thread David Laight
 
 This driver allows userspace to access the data processing 
 FPGAs on the OVRO CARMA board. It has two modes of operation:
 
 1) random access
 
 This allows users to poke any DATA-FPGA registers by using mmap to map
 the address region directly into their memory map.

I needed something similar, but used pread() and pwrite()
to request the transfers.
While this does require a system call per transfer, it allows
the driver to use dma (if available) to speed up the request.
In my case doing single cycle transfers would be too slow.

David


___
Linuxppc-dev mailing list
Linuxppc-dev@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/linuxppc-dev


Re: [PATCH 1/2] misc: add CARMA DATA-FPGA Access Driver

2011-02-09 Thread Ira W. Snyder
On Wed, Feb 09, 2011 at 04:30:23PM -, David Laight wrote:
  
  This driver allows userspace to access the data processing 
  FPGAs on the OVRO CARMA board. It has two modes of operation:
  
  1) random access
  
  This allows users to poke any DATA-FPGA registers by using mmap to map
  the address region directly into their memory map.
 
 I needed something similar, but used pread() and pwrite()
 to request the transfers.
 While this does require a system call per transfer, it allows
 the driver to use dma (if available) to speed up the request.
 In my case doing single cycle transfers would be too slow.
 

We initially started with a read()/write() interface for individual
register reads and writes, just like you describe. It turned out that
mmap was plenty fast for our use. I made the decision to ditch all of
the extra code needed to setup and execute the DMA for the much simpler
mmap code.

In our case, going all the way through the DMA engine code just to
transfer 4 bytes is overkill. The local bus is already quite fast, and
we can increase the clock speed if needed.

Ira
___
Linuxppc-dev mailing list
Linuxppc-dev@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/linuxppc-dev


Re: [PATCH 1/2] misc: add CARMA DATA-FPGA Access Driver

2011-02-09 Thread Ira W. Snyder
On Wed, Feb 09, 2011 at 12:33:25AM -0800, Dmitry Torokhov wrote:
 Hi Ira,
 
 On Tue, Feb 08, 2011 at 03:37:46PM -0800, Ira W. Snyder wrote:
  This driver allows userspace to access the data processing FPGAs on the
  OVRO CARMA board. It has two modes of operation:
  
 
 Thank you for making the changes, some more comments below.
 
  +
  +#define inode_to_dev(inode) container_of(inode-i_cdev, struct 
  fpga_device, cdev)
  +
 
 Does not seem to be used.
 

Leftovers from earlier versions, will remove.

  +/*
  + * Data Buffer Allocation Helpers
  + */
  +
  +static int data_map_buffer(struct device *dev, struct data_buf *buf)
  +{
  +   return videobuf_dma_map(dev, buf-vb);
  +}
  +
  +static void data_unmap_buffer(struct device *dev, struct data_buf *buf)
  +{
  +   videobuf_dma_unmap(dev, buf-vb);
  +}
 
 Why can't we all videobuf_dma_map() and videobuf_dma_unmap() directly?
 What these helpers supposed to solve?
 

The helpers were useful in the past. Now they are not. Will change.

  +static int data_alloc_buffers(struct fpga_device *priv)
  +{
  +   struct data_buf *buf;
  +   int i, ret;
  +
  +   for (i = 0; i  MAX_DATA_BUFS; i++) {
  +
  +   /* allocate a buffer */
  +   buf = data_alloc_buffer(priv-bufsize);
  +   if (!buf)
  +   continue;
 
 break?
 
  +
  +   /* map it for DMA */
  +   ret = data_map_buffer(priv-dev, buf);
  +   if (ret) {
  +   data_free_buffer(buf);
  +   continue;
 
 and here as well?
 

Yep, break is fine also.

  +   }
  +
  +   /* add it to the list of free buffers */
  +   list_add_tail(buf-entry, priv-free);
  +   priv-num_buffers++;
  +   }
  +
  +   /* Make sure we allocated the minimum required number of buffers */
  +   if (priv-num_buffers  MIN_DATA_BUFS) {
  +   dev_err(priv-dev, Unable to allocate enough data buffers\n);
  +   data_free_buffers(priv);
  +   return -ENOMEM;
  +   }
  +
  +   /* Warn if we are running in a degraded state, but do not fail */
  +   if (priv-num_buffers  MAX_DATA_BUFS) {
  +   dev_warn(priv-dev, Unable to allocate one second worth of 
  +   buffers, using %d buffers instead\n, i);
 
 The latest style is not break strings even if they exceed 80 column
 limit to make sure they are easily greppable.
 

I usually just follow checkpatch warnings. I'll combine the strings onto
one line.

  +static void data_dma_cb(void *data)
  +{
  +   struct fpga_device *priv = data;
  +   struct data_buf *buf;
  +   unsigned long flags;
  +
  +   spin_lock_irqsave(priv-lock, flags);
  +
  +   /* clear the FPGA status and re-enable interrupts */
  +   data_enable_interrupts(priv);
  +
  +   /* If the inflight list is empty, we've got a bug */
  +   BUG_ON(list_empty(priv-inflight));
  +
  +   /* Grab the first buffer from the inflight list */
  +   buf = list_first_entry(priv-inflight, struct data_buf, entry);
  +   list_del_init(buf-entry);
  +
  +   /* Add it to the used list */
  +   list_add_tail(buf-entry, priv-used);
 
 or
   list_move_tail(buf-entry, priv-used);
 

Using list_move_tail() didn't occur to me. I'll change it.

  +
  +static irqreturn_t data_irq(int irq, void *dev_id)
  +{
  +   struct fpga_device *priv = dev_id;
  +   struct data_buf *buf;
  +   u32 status;
  +   int i;
  +
  +   /* detect spurious interrupts via FPGA status */
  +   for (i = 0; i  4; i++) {
  +   status = fpga_read_reg(priv, i, MMAP_REG_STATUS);
  +   if (!(status  (CORL_DONE | CORL_ERR))) {
  +   dev_err(priv-dev, spurious irq detected (FPGA)\n);
  +   return IRQ_NONE;
  +   }
  +   }
  +
  +   /* detect spurious interrupts via raw IRQ pin readback */
  +   status = ioread32be(priv-regs + SYS_IRQ_INPUT_DATA);
  +   if (status  IRQ_CORL_DONE) {
  +   dev_err(priv-dev, spurious irq detected (IRQ)\n);
  +   return IRQ_NONE;
  +   }
  +
  +   spin_lock(priv-lock);
  +
  +   /* hide the interrupt by switching the IRQ driver to GPIO */
  +   data_disable_interrupts(priv);
  +
  +   /* Check that we actually have a free buffer */
  +   if (list_empty(priv-free)) {
  +   priv-num_dropped++;
  +   data_enable_interrupts(priv);
  +   goto out_unlock;
  +   }
  +
  +   buf = list_first_entry(priv-free, struct data_buf, entry);
  +   list_del_init(buf-entry);
  +
  +   /* Check the buffer size */
  +   BUG_ON(buf-size != priv-bufsize);
  +
  +   /* Submit a DMA transfer to get the correlation data */
  +   if (data_submit_dma(priv, buf)) {
  +   dev_err(priv-dev, Unable to setup DMA transfer\n);
  +   list_add_tail(buf-entry, priv-free);
  +   data_enable_interrupts(priv);
  +   goto out_unlock;
  +   }
  +
  +   /* DMA setup succeeded, GO!!! */
  +   list_add_tail(buf-entry, priv-inflight);
  +   dma_async_memcpy_issue_pending(priv-chan);
  +
  +out_unlock:
  +   

Re: [PATCH 1/2] misc: add CARMA DATA-FPGA Access Driver

2011-02-09 Thread Dmitry Torokhov
On Wed, Feb 09, 2011 at 09:35:32AM -0800, Ira W. Snyder wrote:
 On Wed, Feb 09, 2011 at 12:33:25AM -0800, Dmitry Torokhov wrote:
   +
   + /* Warn if we are running in a degraded state, but do not fail */
   + if (priv-num_buffers  MAX_DATA_BUFS) {
   + dev_warn(priv-dev, Unable to allocate one second worth of 
   + buffers, using %d buffers instead\n, i);
  
  The latest style is not break strings even if they exceed 80 column
  limit to make sure they are easily greppable.
  
 
 I usually just follow checkpatch warnings. I'll combine the strings onto
 one line.

Does it still warn? I think they tried to fix it so it recognizes long
messages.

  
  OTOH, we can't have more than 1 in-flight buffer, can we? Should
  we even have a list?
  
 
 This looks like a good change. I didn't know about list_move_tail()
 before you mentioned it. Good catch.
 
 You are correct that it is not possible to have more than one in flight
 buffer at the same time. It was previously possible in an earlier
 version of the driver. That was before I was forced to come up with the
 ugly IRQ disabling scheme due to the hardware design.
 
 What would you replace the inflight list with? A struct data_buf
 *inflight; in the priv structure?
 

Yes. Then one would not worry of it is safe to always mark first element
of in-flight list as complete

  
  Have you considered enabling the device when someone opens the device
  node and closing it when last user drops off?
  
  
 
 Yes. Unfortunately it is not possible. Blame my userspace software
 engineers, who refused this model of operation.
 
 I must meet the requirement that the device must remain open while the
 DATA-FPGAs are reconfigured. This means that the FPGAs are completely
 powered down, and a new FPGA bitfile is loaded into them.
 
 After a reconfiguration, the data buffer size may change.
 
 The userspace coders were willing to use a sysfs file to enable/disable
 reading from the device, but they were not willing to open/close the
 device each time. It was the best compromise they would accept.
 
 I'm not happy about it either.

I see.

 
   +
   +/*
   + * FPGA Realtime Data Character Device
   + */
   +
   +static int data_open(struct inode *inode, struct file *filp)
   +{
   + /*
   +  * The miscdevice layer puts our struct miscdevice into the
   +  * filp-private_data field. We use this to find our private
   +  * data and then overwrite it with our own private structure.
   +  */
   + struct fpga_device *priv = container_of(filp-private_data,
   + struct fpga_device, miscdev);
   + struct fpga_reader *reader;
   + int ret;
   +
   + /* allocate private data */
   + reader = kzalloc(sizeof(*reader), GFP_KERNEL);
   + if (!reader)
   + return -ENOMEM;
   +
   + reader-priv = priv;
   + reader-buf = NULL;
   +
   + filp-private_data = reader;
   + ret = nonseekable_open(inode, filp);
   + if (ret) {
   + dev_err(priv-dev, nonseekable-open failed\n);
   + kfree(reader);
   + return ret;
   + }
   +
  
  I wonder if the device should allow only exclusive open... Unless you
  distribute copies of data between all readers.
  
 
 I wish to allow multiple different processes to mmap() the device. This
 requires open(), followed by mmap(). I only care about a single realtime
 data reader (which calls read()). Splitting the two use cases into two
 drivers seemed like a big waste of time and effort. I have no idea how
 to accomplish a single read()er while allowing multiple mmap()ers.

I see.

 
   + return 0;
   +}
   +
   +static int data_release(struct inode *inode, struct file *filp)
   +{
   + struct fpga_reader *reader = filp-private_data;
   +
   + /* free the per-reader structure */
   + data_free_buffer(reader-buf);
   + kfree(reader);
   + filp-private_data = NULL;
   + return 0;
   +}
   +
   +static ssize_t data_read(struct file *filp, char __user *ubuf, size_t 
   count,
   +  loff_t *f_pos)
   +{
   + struct fpga_reader *reader = filp-private_data;
   + struct fpga_device *priv = reader-priv;
   + struct list_head *used = priv-used;
   + struct data_buf *dbuf;
   + size_t avail;
   + void *data;
   + int ret;
   +
   + /* check if we already have a partial buffer */
   + if (reader-buf) {
   + dbuf = reader-buf;
   + goto have_buffer;
   + }
   +
   + spin_lock_irq(priv-lock);
   +
   + /* Block until there is at least one buffer on the used list */
   + while (list_empty(used)) {
  
  I believe we should stop and return error when device is disabled so the
  condition should be:
  
  while (!reader-buf  list_empty()  priv-enabled)
  
  
 
 The requirement is that the device stay open during reconfiguration.
 This provides for that. Readers just block for as long as the device is
 not producing data.

OK, you still need to make sure you do not touch free/used buffer while
device is disabled. Also, you need to kick readers if 

Re: [PATCH 1/2] misc: add CARMA DATA-FPGA Access Driver

2011-02-09 Thread Ira W. Snyder
On Wed, Feb 09, 2011 at 10:27:40AM -0800, Dmitry Torokhov wrote:

[ snip stuff I've already fixed in the next version ]

  
  The requirement is that the device stay open during reconfiguration.
  This provides for that. Readers just block for as long as the device is
  not producing data.
 
 OK, you still need to make sure you do not touch free/used buffer while
 device is disabled. Also, you need to kick readers if you unbind the
 driver, so maybe a new flag priv-exists should be introduced and
 checked.
 

I don't understand what you mean by kick readers if you unbind the
driver. The kernel automatically increases the refcount on a module
when a process is using the module. This shows up in the Used by
column of lsmod's output.

The kernel will not let you rmmod a module with a non-zero refcount. You
cannot get into the situation where you have rmmod'ed the module and a
reader is still blocking in read()/poll().

Thanks for the review. A v6 is coming right up.

Ira
___
Linuxppc-dev mailing list
Linuxppc-dev@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/linuxppc-dev


Re: [PATCH 1/2] misc: add CARMA DATA-FPGA Access Driver

2011-02-09 Thread Dmitry Torokhov
On Wed, Feb 09, 2011 at 03:35:45PM -0800, Ira W. Snyder wrote:
 On Wed, Feb 09, 2011 at 10:27:40AM -0800, Dmitry Torokhov wrote:
 
 [ snip stuff I've already fixed in the next version ]
 
   
   The requirement is that the device stay open during reconfiguration.
   This provides for that. Readers just block for as long as the device is
   not producing data.
  
  OK, you still need to make sure you do not touch free/used buffer while
  device is disabled. Also, you need to kick readers if you unbind the
  driver, so maybe a new flag priv-exists should be introduced and
  checked.
  
 
 I don't understand what you mean by kick readers if you unbind the
 driver. The kernel automatically increases the refcount on a module
 when a process is using the module. This shows up in the Used by
 column of lsmod's output.
 
 The kernel will not let you rmmod a module with a non-zero refcount. You
 cannot get into the situation where you have rmmod'ed the module and a
 reader is still blocking in read()/poll().

However you can still unbind the driver from the device by writing into
driver's sysfs 'unbind' attribute.

See drivers/base/bus.c::driver_unbind().

Thanks.

-- 
Dmitry
___
Linuxppc-dev mailing list
Linuxppc-dev@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/linuxppc-dev


Re: [PATCH 1/2] misc: add CARMA DATA-FPGA Access Driver

2011-02-09 Thread Ira W. Snyder
On Wed, Feb 09, 2011 at 03:42:31PM -0800, Dmitry Torokhov wrote:
 On Wed, Feb 09, 2011 at 03:35:45PM -0800, Ira W. Snyder wrote:
  On Wed, Feb 09, 2011 at 10:27:40AM -0800, Dmitry Torokhov wrote:
  
  [ snip stuff I've already fixed in the next version ]
  

The requirement is that the device stay open during reconfiguration.
This provides for that. Readers just block for as long as the device is
not producing data.
   
   OK, you still need to make sure you do not touch free/used buffer while
   device is disabled. Also, you need to kick readers if you unbind the
   driver, so maybe a new flag priv-exists should be introduced and
   checked.
   
  
  I don't understand what you mean by kick readers if you unbind the
  driver. The kernel automatically increases the refcount on a module
  when a process is using the module. This shows up in the Used by
  column of lsmod's output.
  
  The kernel will not let you rmmod a module with a non-zero refcount. You
  cannot get into the situation where you have rmmod'ed the module and a
  reader is still blocking in read()/poll().
 
 However you can still unbind the driver from the device by writing into
 driver's sysfs 'unbind' attribute.
 
 See drivers/base/bus.c::driver_unbind().
 

I was completely unaware of that feature. I hunch that many drivers
are incapable of dealing with an unbind while they are still open.

Matter of fact, I don't see how this can EVER be safe. The driver core
automatically calls the data_of_remove() routine while there are still
blocked readers. This kfree()s the private data structure, which
contains the suggested priv-exists flag. What happens if the memory
allocator re-allocates that memory to a different driver before the
reader process is woken up to check the priv-exists flag?

The only way to solve this is to count the number of open()s and
close()s, and block the unbind until all users have close()d the device.

Thanks,
Ira
___
Linuxppc-dev mailing list
Linuxppc-dev@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/linuxppc-dev


Re: [PATCH 1/2] misc: add CARMA DATA-FPGA Access Driver

2011-02-09 Thread Dmitry Torokhov
On Wed, Feb 09, 2011 at 04:10:55PM -0800, Ira W. Snyder wrote:
 On Wed, Feb 09, 2011 at 03:42:31PM -0800, Dmitry Torokhov wrote:
  On Wed, Feb 09, 2011 at 03:35:45PM -0800, Ira W. Snyder wrote:
   On Wed, Feb 09, 2011 at 10:27:40AM -0800, Dmitry Torokhov wrote:
   
   [ snip stuff I've already fixed in the next version ]
   
 
 The requirement is that the device stay open during reconfiguration.
 This provides for that. Readers just block for as long as the device 
 is
 not producing data.

OK, you still need to make sure you do not touch free/used buffer while
device is disabled. Also, you need to kick readers if you unbind the
driver, so maybe a new flag priv-exists should be introduced and
checked.

   
   I don't understand what you mean by kick readers if you unbind the
   driver. The kernel automatically increases the refcount on a module
   when a process is using the module. This shows up in the Used by
   column of lsmod's output.
   
   The kernel will not let you rmmod a module with a non-zero refcount. You
   cannot get into the situation where you have rmmod'ed the module and a
   reader is still blocking in read()/poll().
  
  However you can still unbind the driver from the device by writing into
  driver's sysfs 'unbind' attribute.
  
  See drivers/base/bus.c::driver_unbind().
  
 
 I was completely unaware of that feature. I hunch that many drivers
 are incapable of dealing with an unbind while they are still open.

Hmm, maybe older drivers... Anythig hotpluggable (USB, PCI, etc) should
be in a better shape because they expect to be yanked at any time.

 
 Matter of fact, I don't see how this can EVER be safe. The driver core
 automatically calls the data_of_remove() routine while there are still
 blocked readers. This kfree()s the private data structure, which
 contains the suggested priv-exists flag. What happens if the memory
 allocator re-allocates that memory to a different driver before the
 reader process is woken up to check the priv-exists flag?
 
 The only way to solve this is to count the number of open()s and
 close()s, and block the unbind until all users have close()d the device.
 

Yes, you can kick readers and wait, or you can refcount that private
structure and have readers grab a reference when they open your device
and drop it in their fops-release() method. Your remove() should also
drop reference instead of doing kfree() outright.

Thanks.

-- 
Dmitry
___
Linuxppc-dev mailing list
Linuxppc-dev@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/linuxppc-dev


Re: [PATCH 1/2] misc: add CARMA DATA-FPGA Access Driver

2011-02-08 Thread Ira W. Snyder
On Mon, Feb 07, 2011 at 11:33:10PM -0800, Dmitry Torokhov wrote:
 Hi Ira,
 
 On Mon, Feb 07, 2011 at 03:23:40PM -0800, Ira W. Snyder wrote:
  This driver allows userspace to access the data processing FPGAs on the
  OVRO CARMA board. It has two modes of operation:
  
  1) random access
  
  This allows users to poke any DATA-FPGA registers by using mmap to map
  the address region directly into their memory map.
  
  2) correlation dumping
  
  When correlating, the DATA-FPGA's have special requirements for getting
  the data out of their memory before the next correlation. This nominally
  happens at 64Hz (every 15.625ms). If the data is not dumped before the
  next correlation, data is lost.
  
  The data dumping driver handles buffering up to 1 second worth of
  correlation data from the FPGAs. This lowers the realtime scheduling
  requirements for the userspace process reading the device.
 
 Kind of a fly-by review but it looks like the locking in the driver
 needs work.
 

Hi Dmitry,

Thanks for the review. I have a few comments inline below.

  
  Signed-off-by: Ira W. Snyder i...@ovro.caltech.edu
  ---
   drivers/misc/Kconfig|1 +
   drivers/misc/Makefile   |1 +
   drivers/misc/carma/Kconfig  |9 +
   drivers/misc/carma/Makefile |1 +
   drivers/misc/carma/carma-fpga.c | 1446 
  +++
   5 files changed, 1458 insertions(+), 0 deletions(-)
   create mode 100644 drivers/misc/carma/Kconfig
   create mode 100644 drivers/misc/carma/Makefile
   create mode 100644 drivers/misc/carma/carma-fpga.c
  
  diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
  index 4d073f1..f457f14 100644
  --- a/drivers/misc/Kconfig
  +++ b/drivers/misc/Kconfig
  @@ -457,5 +457,6 @@ source drivers/misc/eeprom/Kconfig
   source drivers/misc/cb710/Kconfig
   source drivers/misc/iwmc3200top/Kconfig
   source drivers/misc/ti-st/Kconfig
  +source drivers/misc/carma/Kconfig
   
   endif # MISC_DEVICES
  diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
  index 98009cc..2c1610e 100644
  --- a/drivers/misc/Makefile
  +++ b/drivers/misc/Makefile
  @@ -42,3 +42,4 @@ obj-$(CONFIG_ARM_CHARLCD) += arm-charlcd.o
   obj-$(CONFIG_PCH_PHUB) += pch_phub.o
   obj-y  += ti-st/
   obj-$(CONFIG_AB8500_PWM)   += ab8500-pwm.o
  +obj-y  += carma/
  diff --git a/drivers/misc/carma/Kconfig b/drivers/misc/carma/Kconfig
  new file mode 100644
  index 000..4be183f
  --- /dev/null
  +++ b/drivers/misc/carma/Kconfig
  @@ -0,0 +1,9 @@
  +config CARMA_FPGA
  +   tristate CARMA DATA-FPGA Access Driver
  +   depends on FSL_SOC  PPC_83xx  MEDIA_SUPPORT  HAS_DMA  FSL_DMA
  +   select VIDEOBUF_DMA_SG
  +   default n
  +   help
  + Say Y here to include support for communicating with the data
  + processing FPGAs on the OVRO CARMA board.
  +
  diff --git a/drivers/misc/carma/Makefile b/drivers/misc/carma/Makefile
  new file mode 100644
  index 000..0b69fa7
  --- /dev/null
  +++ b/drivers/misc/carma/Makefile
  @@ -0,0 +1 @@
  +obj-$(CONFIG_CARMA_FPGA)   += carma-fpga.o
  diff --git a/drivers/misc/carma/carma-fpga.c 
  b/drivers/misc/carma/carma-fpga.c
  new file mode 100644
  index 000..52620b3
  --- /dev/null
  +++ b/drivers/misc/carma/carma-fpga.c
  @@ -0,0 +1,1446 @@
  +/*
  + * CARMA DATA-FPGA Access Driver
  + *
  + * Copyright (c) 2009-2010 Ira W. Snyder i...@ovro.caltech.edu
  + *
  + * This program is free software; you can redistribute it and/or modify it
  + * under the terms of the GNU General Public License as published by the
  + * Free Software Foundation; either version 2 of the License, or (at your
  + * option) any later version.
  + */
  +
  +/*
  + * FPGA Memory Dump Format
  + *
  + * FPGA #0 control registers (32 x 32-bit words)
  + * FPGA #1 control registers (32 x 32-bit words)
  + * FPGA #2 control registers (32 x 32-bit words)
  + * FPGA #3 control registers (32 x 32-bit words)
  + * SYSFPGA control registers (32 x 32-bit words)
  + * FPGA #0 correlation array (NUM_CORL0 correlation blocks)
  + * FPGA #1 correlation array (NUM_CORL1 correlation blocks)
  + * FPGA #2 correlation array (NUM_CORL2 correlation blocks)
  + * FPGA #3 correlation array (NUM_CORL3 correlation blocks)
  + *
  + * Each correlation array consists of:
  + *
  + * Correlation Data  (2 x NUM_LAGSn x 32-bit words)
  + * Pipeline Metadata (2 x NUM_METAn x 32-bit words)
  + * Quantization Counters (2 x NUM_QCNTn x 32-bit words)
  + *
  + * The NUM_CORLn, NUM_LAGSn, NUM_METAn, and NUM_QCNTn values come from
  + * the FPGA configuration registers. They do not change once the FPGA's
  + * have been programmed, they only change on re-programming.
  + */
  +
  +/*
  + * Basic Description:
  + *
  + * This driver is used to capture correlation spectra off of the four data
  + * processing FPGAs. The FPGAs are often reprogrammed at runtime, therefore
  + * this driver supports dynamic 

Re: [PATCH 1/2] misc: add CARMA DATA-FPGA Access Driver

2011-02-08 Thread Dave Jones
On Tue, Feb 08, 2011 at 09:20:46AM -0800, Ira W. Snyder wrote:

+static DEVICE_ATTR(enable, S_IWUGO | S_IRUGO, data_en_show, 
data_en_set);
   
   Are all of these really needed or most of them are for debug?
   
  
  Most are for debugging. They have proved useful a few times in
  production to track down bugs.
 
File mode should probably not be world writable.
(checkpatch.pl should warn you about this now btw)

Dave

___
Linuxppc-dev mailing list
Linuxppc-dev@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/linuxppc-dev


Re: [PATCH 1/2] misc: add CARMA DATA-FPGA Access Driver

2011-02-08 Thread Dmitry Torokhov
On Tue, Feb 08, 2011 at 09:20:46AM -0800, Ira W. Snyder wrote:
 On Mon, Feb 07, 2011 at 11:33:10PM -0800, Dmitry Torokhov wrote:
   +static void data_free_buffer(struct device *dev, struct data_buf *buf)
   +{
   + /* It is ok to free a NULL buffer */
   + if (!buf)
   + return;
   +
   + /* Make sure the buffer is not on any list */
   + list_del_init(buf-entry);
  
  And what happens if it is? Should it be WARN_ON(!list_empty()) instead?
  
 
 This was only defensive programming. Everywhere this function is called,
 the buffer has already been removed from the list.

I am concerned as sometimes defencive programming is the sign that we
arenot quite sure how the code works. I believe defensive programming
should be used when providing library-like code, not in local cases.

   +
   + list_for_each_entry_safe(buf, tmp, priv-free, entry) {
   + list_del_init(buf-entry);
   + spin_unlock_irq(priv-lock);
   + data_free_buffer(priv-dev, buf);
   + spin_lock_irq(priv-lock);
   + }
  
  This is messed up. If there is concurrent access to the free list then
  it is not safe to continue iterating list after releasing the lock, you
  need to do:
  
  spin_lock_irq(priv-lock);
  while (!list_empty(priv-free)) {
  buf = list_first_entry(priv-free, struct data_buf, entry);
  list_del_init(buf-entry);
  spin_unlock_irq(priv-lock);
  data_free_buffer(priv-dev, buf);
  spin_lock_irq(priv-lock);
  }
  
  BUT, the function is only called when you disable (or fail to enable) device
  which, at this point, should be quiesced, thus all this locking is not
  really needed.
  
 
 Correct.
 
 I thought it would be clearer to reviewers if I always used the lock to
 protect a data structure, even when it isn't technically needed.

No, locks should protect wehat needs to be protected. The rest just
muddles water.

   +
   + spin_lock_irq(priv-lock);
   + while (!list_empty(list)) {
   + spin_unlock_irq(priv-lock);
   +
   + ret = wait_event_interruptible(priv-wait, list_empty(list));
   + if (ret)
   + return -ERESTARTSYS;
   +
   + spin_lock_irq(priv-lock);
   + }
   + spin_unlock_irq(priv-lock);
  
  Locking is not needed - if you disable interrupyts what would put more
  stuff on the list?
  
 
 The locking is definitely needed.
 
 You've missed a critical piece of information. There are *two* devices
 we are interacting with here, and BOTH generate interrupts.
 

No, I did not miss this fact. The point is that when we get to this code
the device _putting_ items on wauiting list is stopped and we only need
to wait for the list to drain. Nobody puts more stuff on it. You can
check fir list_empty() condition without locking.

And if someone _is_ putting more stuff on the list - you are screwed
since list may become non-empty the moment you release the lock.

   +
   +static ssize_t data_num_buffers_show(struct device *dev,
   +  struct device_attribute *attr, char *buf)
   +{
   + struct fpga_device *priv = dev_get_drvdata(dev);
   + unsigned int num;
   +
   + spin_lock_irq(priv-lock);
   + num = priv-num_buffers;
   + spin_unlock_irq(priv-lock);
  
  This spin lock is pointless, priv-num_buffers might be already changed
  here, you can't guarantee that you show accurate data.
  
 
 Correct, I know this. I just wanted to protect the data structure at all
 points of use in the driver.

Protect from what? integer reads are guaranteed to be complete and you
are not concerned with missing updates as information is obsolete the
moment you release trhe lock.

 Would an atomic_t be better for this, or
 should I just remove the locking completely?

Just remove the locking.

   +
   + if (mutex_lock_interruptible(priv-mutex))
   + return -ERESTARTSYS;
  
  Why don't
  
  error = mutex_lock_interruptible(priv-mutex);
  if (error)
  return error;
  
  - do not clobber perfectly valid error codes.
  
 
 That's what the Linux Device Drivers 3rd Edition book does. See page
 112. I will change it to fix the return code.


LDD3 is quite old by now...

   +
   +static struct attribute *data_sysfs_attrs[] = {
   + dev_attr_num_buffers.attr,
   + dev_attr_buffer_size.attr,
   + dev_attr_num_inflight.attr,
   + dev_attr_num_free.attr,
   + dev_attr_num_used.attr,
   + dev_attr_num_dropped.attr,
   + dev_attr_enable.attr,
   + NULL,
   +};
  
  Are all of these really needed or most of them are for debug?
  
 
 Most are for debugging. They have proved useful a few times in
 production to track down bugs.
 

Consider switching over to debugfs then. Or, if you believe the device
is sufficiently bug-free just cut the code.

   +
   +static ssize_t data_read(struct file *filp, char __user *ubuf, size_t 
   count,
   +  loff_t *f_pos)
   +{
   + struct fpga_reader *reader = filp-private_data;
   + struct fpga_device *priv = 

Re: [PATCH 1/2] misc: add CARMA DATA-FPGA Access Driver

2011-02-08 Thread Ira W. Snyder
On Tue, Feb 08, 2011 at 09:50:29AM -0800, Dmitry Torokhov wrote:
 On Tue, Feb 08, 2011 at 09:20:46AM -0800, Ira W. Snyder wrote:
  On Mon, Feb 07, 2011 at 11:33:10PM -0800, Dmitry Torokhov wrote:
+static void data_free_buffer(struct device *dev, struct data_buf *buf)
+{
+   /* It is ok to free a NULL buffer */
+   if (!buf)
+   return;
+
+   /* Make sure the buffer is not on any list */
+   list_del_init(buf-entry);
   
   And what happens if it is? Should it be WARN_ON(!list_empty()) instead?
   
  
  This was only defensive programming. Everywhere this function is called,
  the buffer has already been removed from the list.
 
 I am concerned as sometimes defencive programming is the sign that we
 arenot quite sure how the code works. I believe defensive programming
 should be used when providing library-like code, not in local cases.
 

Ok.

+
+   list_for_each_entry_safe(buf, tmp, priv-free, entry) {
+   list_del_init(buf-entry);
+   spin_unlock_irq(priv-lock);
+   data_free_buffer(priv-dev, buf);
+   spin_lock_irq(priv-lock);
+   }
   
   This is messed up. If there is concurrent access to the free list then
   it is not safe to continue iterating list after releasing the lock, you
   need to do:
   
 spin_lock_irq(priv-lock);
 while (!list_empty(priv-free)) {
 buf = list_first_entry(priv-free, struct data_buf, entry);
 list_del_init(buf-entry);
 spin_unlock_irq(priv-lock);
 data_free_buffer(priv-dev, buf);
 spin_lock_irq(priv-lock);
 }
   
   BUT, the function is only called when you disable (or fail to enable) 
   device
   which, at this point, should be quiesced, thus all this locking is not
   really needed.
   
  
  Correct.
  
  I thought it would be clearer to reviewers if I always used the lock to
  protect a data structure, even when it isn't technically needed.
 
 No, locks should protect wehat needs to be protected. The rest just
 muddles water.
 

Ok.

+
+   spin_lock_irq(priv-lock);
+   while (!list_empty(list)) {
+   spin_unlock_irq(priv-lock);
+
+   ret = wait_event_interruptible(priv-wait, 
list_empty(list));
+   if (ret)
+   return -ERESTARTSYS;
+
+   spin_lock_irq(priv-lock);
+   }
+   spin_unlock_irq(priv-lock);
   
   Locking is not needed - if you disable interrupyts what would put more
   stuff on the list?
   
  
  The locking is definitely needed.
  
  You've missed a critical piece of information. There are *two* devices
  we are interacting with here, and BOTH generate interrupts.
  
 
 No, I did not miss this fact. The point is that when we get to this code
 the device _putting_ items on wauiting list is stopped and we only need
 to wait for the list to drain. Nobody puts more stuff on it. You can
 check fir list_empty() condition without locking.
 
 And if someone _is_ putting more stuff on the list - you are screwed
 since list may become non-empty the moment you release the lock.
 

Ok, I understand what you mean now. You are correct, nothing else can
add things to the list. Thanks for clarifying this for me. :)

+
+static ssize_t data_num_buffers_show(struct device *dev,
+struct device_attribute *attr, 
char *buf)
+{
+   struct fpga_device *priv = dev_get_drvdata(dev);
+   unsigned int num;
+
+   spin_lock_irq(priv-lock);
+   num = priv-num_buffers;
+   spin_unlock_irq(priv-lock);
   
   This spin lock is pointless, priv-num_buffers might be already changed
   here, you can't guarantee that you show accurate data.
   
  
  Correct, I know this. I just wanted to protect the data structure at all
  points of use in the driver.
 
 Protect from what? integer reads are guaranteed to be complete and you
 are not concerned with missing updates as information is obsolete the
 moment you release trhe lock.
 
  Would an atomic_t be better for this, or
  should I just remove the locking completely?
 
 Just remove the locking.
 

Ok.

+
+   if (mutex_lock_interruptible(priv-mutex))
+   return -ERESTARTSYS;
   
   Why don't
   
 error = mutex_lock_interruptible(priv-mutex);
 if (error)
 return error;
   
   - do not clobber perfectly valid error codes.
   
  
  That's what the Linux Device Drivers 3rd Edition book does. See page
  112. I will change it to fix the return code.
 
 
 LDD3 is quite old by now...
 

I know, but it is still the best written reference I have. Reviewers
like yourself are better, but I can't look up your advice in a book. :)

I'll return the error code.

+
+static struct attribute *data_sysfs_attrs[] = {
+   dev_attr_num_buffers.attr,
+   

Re: [PATCH 1/2] misc: add CARMA DATA-FPGA Access Driver

2011-02-08 Thread Dmitry Torokhov
On Tue, Feb 08, 2011 at 11:11:44AM -0800, Ira W. Snyder wrote:
 On Tue, Feb 08, 2011 at 09:50:29AM -0800, Dmitry Torokhov wrote:
  On Tue, Feb 08, 2011 at 09:20:46AM -0800, Ira W. Snyder wrote:
  
   Go back and re-think my loop. This is a
   common idiom straight of out LDD3 pages 153-154.
   
   You should note that it is only possible to exit the loop with the lock
   held AND !list_empty(used). The lock protects the used list, and
   therefore, there must be a buffer on the list.
  
  No, because you are woken up while not holding the lock so another
  reader is free to take it off the list.
  
 
 Correct. But then I go around the loop and check list_empty() again
 before exiting the loop. The list MUST NOT be empty before the loop will
 terminate.

Yes, you are right, I competely missed the fact that we'd loop around
and check the condition again. I'll go grab another coffee now.

-- 
Dmitry
___
Linuxppc-dev mailing list
Linuxppc-dev@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/linuxppc-dev


[PATCH 1/2] misc: add CARMA DATA-FPGA Access Driver

2011-02-08 Thread Ira W. Snyder
This driver allows userspace to access the data processing FPGAs on the
OVRO CARMA board. It has two modes of operation:

1) random access

This allows users to poke any DATA-FPGA registers by using mmap to map
the address region directly into their memory map.

2) correlation dumping

When correlating, the DATA-FPGA's have special requirements for getting
the data out of their memory before the next correlation. This nominally
happens at 64Hz (every 15.625ms). If the data is not dumped before the
next correlation, data is lost.

The data dumping driver handles buffering up to 1 second worth of
correlation data from the FPGAs. This lowers the realtime scheduling
requirements for the userspace process reading the device.

Signed-off-by: Ira W. Snyder i...@ovro.caltech.edu
---
 drivers/misc/Kconfig|1 +
 drivers/misc/Makefile   |1 +
 drivers/misc/carma/Kconfig  |9 +
 drivers/misc/carma/Makefile |1 +
 drivers/misc/carma/carma-fpga.c | 1396 +++
 5 files changed, 1408 insertions(+), 0 deletions(-)
 create mode 100644 drivers/misc/carma/Kconfig
 create mode 100644 drivers/misc/carma/Makefile
 create mode 100644 drivers/misc/carma/carma-fpga.c

diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index cc8e49d..93cf1e6 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -457,5 +457,6 @@ source drivers/misc/eeprom/Kconfig
 source drivers/misc/cb710/Kconfig
 source drivers/misc/iwmc3200top/Kconfig
 source drivers/misc/ti-st/Kconfig
+source drivers/misc/carma/Kconfig
 
 endif # MISC_DEVICES
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 98009cc..2c1610e 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -42,3 +42,4 @@ obj-$(CONFIG_ARM_CHARLCD) += arm-charlcd.o
 obj-$(CONFIG_PCH_PHUB) += pch_phub.o
 obj-y  += ti-st/
 obj-$(CONFIG_AB8500_PWM)   += ab8500-pwm.o
+obj-y  += carma/
diff --git a/drivers/misc/carma/Kconfig b/drivers/misc/carma/Kconfig
new file mode 100644
index 000..4be183f
--- /dev/null
+++ b/drivers/misc/carma/Kconfig
@@ -0,0 +1,9 @@
+config CARMA_FPGA
+   tristate CARMA DATA-FPGA Access Driver
+   depends on FSL_SOC  PPC_83xx  MEDIA_SUPPORT  HAS_DMA  FSL_DMA
+   select VIDEOBUF_DMA_SG
+   default n
+   help
+ Say Y here to include support for communicating with the data
+ processing FPGAs on the OVRO CARMA board.
+
diff --git a/drivers/misc/carma/Makefile b/drivers/misc/carma/Makefile
new file mode 100644
index 000..0b69fa7
--- /dev/null
+++ b/drivers/misc/carma/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_CARMA_FPGA)   += carma-fpga.o
diff --git a/drivers/misc/carma/carma-fpga.c b/drivers/misc/carma/carma-fpga.c
new file mode 100644
index 000..4ea473a
--- /dev/null
+++ b/drivers/misc/carma/carma-fpga.c
@@ -0,0 +1,1396 @@
+/*
+ * CARMA DATA-FPGA Access Driver
+ *
+ * Copyright (c) 2009-2011 Ira W. Snyder i...@ovro.caltech.edu
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+/*
+ * FPGA Memory Dump Format
+ *
+ * FPGA #0 control registers (32 x 32-bit words)
+ * FPGA #1 control registers (32 x 32-bit words)
+ * FPGA #2 control registers (32 x 32-bit words)
+ * FPGA #3 control registers (32 x 32-bit words)
+ * SYSFPGA control registers (32 x 32-bit words)
+ * FPGA #0 correlation array (NUM_CORL0 correlation blocks)
+ * FPGA #1 correlation array (NUM_CORL1 correlation blocks)
+ * FPGA #2 correlation array (NUM_CORL2 correlation blocks)
+ * FPGA #3 correlation array (NUM_CORL3 correlation blocks)
+ *
+ * Each correlation array consists of:
+ *
+ * Correlation Data  (2 x NUM_LAGSn x 32-bit words)
+ * Pipeline Metadata (2 x NUM_METAn x 32-bit words)
+ * Quantization Counters (2 x NUM_QCNTn x 32-bit words)
+ *
+ * The NUM_CORLn, NUM_LAGSn, NUM_METAn, and NUM_QCNTn values come from
+ * the FPGA configuration registers. They do not change once the FPGA's
+ * have been programmed, they only change on re-programming.
+ */
+
+/*
+ * Basic Description:
+ *
+ * This driver is used to capture correlation spectra off of the four data
+ * processing FPGAs. The FPGAs are often reprogrammed at runtime, therefore
+ * this driver supports dynamic enable/disable of capture while the device
+ * remains open.
+ *
+ * The nominal capture rate is 64Hz (every 15.625ms). To facilitate this fast
+ * capture rate, all buffers are pre-allocated to avoid any potentially long
+ * running memory allocations while capturing.
+ *
+ * There are three lists which are used to keep track of the different states
+ * of data buffers.
+ *
+ * 1) free list
+ * This list holds all empty data buffers which are ready to receive data.
+ *
+ * 2) inflight list
+ * This list holds data 

[PATCH 1/2] misc: add CARMA DATA-FPGA Access Driver

2011-02-07 Thread Ira W. Snyder
This driver allows userspace to access the data processing FPGAs on the
OVRO CARMA board. It has two modes of operation:

1) random access

This allows users to poke any DATA-FPGA registers by using mmap to map
the address region directly into their memory map.

2) correlation dumping

When correlating, the DATA-FPGA's have special requirements for getting
the data out of their memory before the next correlation. This nominally
happens at 64Hz (every 15.625ms). If the data is not dumped before the
next correlation, data is lost.

The data dumping driver handles buffering up to 1 second worth of
correlation data from the FPGAs. This lowers the realtime scheduling
requirements for the userspace process reading the device.

Signed-off-by: Ira W. Snyder i...@ovro.caltech.edu
---
 drivers/misc/Kconfig|1 +
 drivers/misc/Makefile   |1 +
 drivers/misc/carma/Kconfig  |9 +
 drivers/misc/carma/Makefile |1 +
 drivers/misc/carma/carma-fpga.c | 1446 +++
 5 files changed, 1458 insertions(+), 0 deletions(-)
 create mode 100644 drivers/misc/carma/Kconfig
 create mode 100644 drivers/misc/carma/Makefile
 create mode 100644 drivers/misc/carma/carma-fpga.c

diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 4d073f1..f457f14 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -457,5 +457,6 @@ source drivers/misc/eeprom/Kconfig
 source drivers/misc/cb710/Kconfig
 source drivers/misc/iwmc3200top/Kconfig
 source drivers/misc/ti-st/Kconfig
+source drivers/misc/carma/Kconfig
 
 endif # MISC_DEVICES
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 98009cc..2c1610e 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -42,3 +42,4 @@ obj-$(CONFIG_ARM_CHARLCD) += arm-charlcd.o
 obj-$(CONFIG_PCH_PHUB) += pch_phub.o
 obj-y  += ti-st/
 obj-$(CONFIG_AB8500_PWM)   += ab8500-pwm.o
+obj-y  += carma/
diff --git a/drivers/misc/carma/Kconfig b/drivers/misc/carma/Kconfig
new file mode 100644
index 000..4be183f
--- /dev/null
+++ b/drivers/misc/carma/Kconfig
@@ -0,0 +1,9 @@
+config CARMA_FPGA
+   tristate CARMA DATA-FPGA Access Driver
+   depends on FSL_SOC  PPC_83xx  MEDIA_SUPPORT  HAS_DMA  FSL_DMA
+   select VIDEOBUF_DMA_SG
+   default n
+   help
+ Say Y here to include support for communicating with the data
+ processing FPGAs on the OVRO CARMA board.
+
diff --git a/drivers/misc/carma/Makefile b/drivers/misc/carma/Makefile
new file mode 100644
index 000..0b69fa7
--- /dev/null
+++ b/drivers/misc/carma/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_CARMA_FPGA)   += carma-fpga.o
diff --git a/drivers/misc/carma/carma-fpga.c b/drivers/misc/carma/carma-fpga.c
new file mode 100644
index 000..52620b3
--- /dev/null
+++ b/drivers/misc/carma/carma-fpga.c
@@ -0,0 +1,1446 @@
+/*
+ * CARMA DATA-FPGA Access Driver
+ *
+ * Copyright (c) 2009-2010 Ira W. Snyder i...@ovro.caltech.edu
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+/*
+ * FPGA Memory Dump Format
+ *
+ * FPGA #0 control registers (32 x 32-bit words)
+ * FPGA #1 control registers (32 x 32-bit words)
+ * FPGA #2 control registers (32 x 32-bit words)
+ * FPGA #3 control registers (32 x 32-bit words)
+ * SYSFPGA control registers (32 x 32-bit words)
+ * FPGA #0 correlation array (NUM_CORL0 correlation blocks)
+ * FPGA #1 correlation array (NUM_CORL1 correlation blocks)
+ * FPGA #2 correlation array (NUM_CORL2 correlation blocks)
+ * FPGA #3 correlation array (NUM_CORL3 correlation blocks)
+ *
+ * Each correlation array consists of:
+ *
+ * Correlation Data  (2 x NUM_LAGSn x 32-bit words)
+ * Pipeline Metadata (2 x NUM_METAn x 32-bit words)
+ * Quantization Counters (2 x NUM_QCNTn x 32-bit words)
+ *
+ * The NUM_CORLn, NUM_LAGSn, NUM_METAn, and NUM_QCNTn values come from
+ * the FPGA configuration registers. They do not change once the FPGA's
+ * have been programmed, they only change on re-programming.
+ */
+
+/*
+ * Basic Description:
+ *
+ * This driver is used to capture correlation spectra off of the four data
+ * processing FPGAs. The FPGAs are often reprogrammed at runtime, therefore
+ * this driver supports dynamic enable/disable of capture while the device
+ * remains open.
+ *
+ * The nominal capture rate is 64Hz (every 15.625ms). To facilitate this fast
+ * capture rate, all buffers are pre-allocated to avoid any potentially long
+ * running memory allocations while capturing.
+ *
+ * There are three lists which are used to keep track of the different states
+ * of data buffers.
+ *
+ * 1) free list
+ * This list holds all empty data buffers which are ready to receive data.
+ *
+ * 2) inflight list
+ * This list holds data 

Re: [PATCH 1/2] misc: add CARMA DATA-FPGA Access Driver

2011-02-07 Thread Dmitry Torokhov
Hi Ira,

On Mon, Feb 07, 2011 at 03:23:40PM -0800, Ira W. Snyder wrote:
 This driver allows userspace to access the data processing FPGAs on the
 OVRO CARMA board. It has two modes of operation:
 
 1) random access
 
 This allows users to poke any DATA-FPGA registers by using mmap to map
 the address region directly into their memory map.
 
 2) correlation dumping
 
 When correlating, the DATA-FPGA's have special requirements for getting
 the data out of their memory before the next correlation. This nominally
 happens at 64Hz (every 15.625ms). If the data is not dumped before the
 next correlation, data is lost.
 
 The data dumping driver handles buffering up to 1 second worth of
 correlation data from the FPGAs. This lowers the realtime scheduling
 requirements for the userspace process reading the device.

Kind of a fly-by review but it looks like the locking in the driver
needs work.

 
 Signed-off-by: Ira W. Snyder i...@ovro.caltech.edu
 ---
  drivers/misc/Kconfig|1 +
  drivers/misc/Makefile   |1 +
  drivers/misc/carma/Kconfig  |9 +
  drivers/misc/carma/Makefile |1 +
  drivers/misc/carma/carma-fpga.c | 1446 
 +++
  5 files changed, 1458 insertions(+), 0 deletions(-)
  create mode 100644 drivers/misc/carma/Kconfig
  create mode 100644 drivers/misc/carma/Makefile
  create mode 100644 drivers/misc/carma/carma-fpga.c
 
 diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
 index 4d073f1..f457f14 100644
 --- a/drivers/misc/Kconfig
 +++ b/drivers/misc/Kconfig
 @@ -457,5 +457,6 @@ source drivers/misc/eeprom/Kconfig
  source drivers/misc/cb710/Kconfig
  source drivers/misc/iwmc3200top/Kconfig
  source drivers/misc/ti-st/Kconfig
 +source drivers/misc/carma/Kconfig
  
  endif # MISC_DEVICES
 diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
 index 98009cc..2c1610e 100644
 --- a/drivers/misc/Makefile
 +++ b/drivers/misc/Makefile
 @@ -42,3 +42,4 @@ obj-$(CONFIG_ARM_CHARLCD)   += arm-charlcd.o
  obj-$(CONFIG_PCH_PHUB)   += pch_phub.o
  obj-y+= ti-st/
  obj-$(CONFIG_AB8500_PWM) += ab8500-pwm.o
 +obj-y+= carma/
 diff --git a/drivers/misc/carma/Kconfig b/drivers/misc/carma/Kconfig
 new file mode 100644
 index 000..4be183f
 --- /dev/null
 +++ b/drivers/misc/carma/Kconfig
 @@ -0,0 +1,9 @@
 +config CARMA_FPGA
 + tristate CARMA DATA-FPGA Access Driver
 + depends on FSL_SOC  PPC_83xx  MEDIA_SUPPORT  HAS_DMA  FSL_DMA
 + select VIDEOBUF_DMA_SG
 + default n
 + help
 +   Say Y here to include support for communicating with the data
 +   processing FPGAs on the OVRO CARMA board.
 +
 diff --git a/drivers/misc/carma/Makefile b/drivers/misc/carma/Makefile
 new file mode 100644
 index 000..0b69fa7
 --- /dev/null
 +++ b/drivers/misc/carma/Makefile
 @@ -0,0 +1 @@
 +obj-$(CONFIG_CARMA_FPGA) += carma-fpga.o
 diff --git a/drivers/misc/carma/carma-fpga.c b/drivers/misc/carma/carma-fpga.c
 new file mode 100644
 index 000..52620b3
 --- /dev/null
 +++ b/drivers/misc/carma/carma-fpga.c
 @@ -0,0 +1,1446 @@
 +/*
 + * CARMA DATA-FPGA Access Driver
 + *
 + * Copyright (c) 2009-2010 Ira W. Snyder i...@ovro.caltech.edu
 + *
 + * This program is free software; you can redistribute it and/or modify it
 + * under the terms of the GNU General Public License as published by the
 + * Free Software Foundation; either version 2 of the License, or (at your
 + * option) any later version.
 + */
 +
 +/*
 + * FPGA Memory Dump Format
 + *
 + * FPGA #0 control registers (32 x 32-bit words)
 + * FPGA #1 control registers (32 x 32-bit words)
 + * FPGA #2 control registers (32 x 32-bit words)
 + * FPGA #3 control registers (32 x 32-bit words)
 + * SYSFPGA control registers (32 x 32-bit words)
 + * FPGA #0 correlation array (NUM_CORL0 correlation blocks)
 + * FPGA #1 correlation array (NUM_CORL1 correlation blocks)
 + * FPGA #2 correlation array (NUM_CORL2 correlation blocks)
 + * FPGA #3 correlation array (NUM_CORL3 correlation blocks)
 + *
 + * Each correlation array consists of:
 + *
 + * Correlation Data  (2 x NUM_LAGSn x 32-bit words)
 + * Pipeline Metadata (2 x NUM_METAn x 32-bit words)
 + * Quantization Counters (2 x NUM_QCNTn x 32-bit words)
 + *
 + * The NUM_CORLn, NUM_LAGSn, NUM_METAn, and NUM_QCNTn values come from
 + * the FPGA configuration registers. They do not change once the FPGA's
 + * have been programmed, they only change on re-programming.
 + */
 +
 +/*
 + * Basic Description:
 + *
 + * This driver is used to capture correlation spectra off of the four data
 + * processing FPGAs. The FPGAs are often reprogrammed at runtime, therefore
 + * this driver supports dynamic enable/disable of capture while the device
 + * remains open.
 + *
 + * The nominal capture rate is 64Hz (every 15.625ms). To facilitate this fast
 + * capture rate, all buffers are pre-allocated to avoid any potentially long
 + * running memory