Re: [PATCH v2 1/2] dmaengine: avalon: Intel Avalon-MM DMA Interface for PCIe

2019-10-15 Thread Alexander Gordeev
On Tue, Oct 15, 2019 at 04:19:55PM +0300, Dan Carpenter wrote:
> On Tue, Oct 15, 2019 at 01:24:50PM +0200, Alexander Gordeev wrote:
> > On Thu, Oct 10, 2019 at 02:30:34PM +0300, Dan Carpenter wrote:
> > > On Thu, Oct 10, 2019 at 10:51:45AM +0200, Alexander Gordeev wrote:
> > > > On Wed, Oct 09, 2019 at 09:53:23PM +0300, Dan Carpenter wrote:
> > > > > > > > +   u32 *rd_flags = hw->dma_desc_table_rd.cpu_addr->flags;
> > > > > > > > +   u32 *wr_flags = hw->dma_desc_table_wr.cpu_addr->flags;
> > > > > > > > +   struct avalon_dma_desc *desc;
> > > > > > > > +   struct virt_dma_desc *vdesc;
> > > > > > > > +   bool rd_done;
> > > > > > > > +   bool wr_done;
> > > > > > > > +
> > > > > > > > +   spin_lock(lock);
> > 
> > [*]
> > 
> > > > > > > > +
> > > > > > > > +   rd_done = (hw->h2d_last_id < 0);
> > > > > > > > +   wr_done = (hw->d2h_last_id < 0);
> > > > > > > > +
> > > > > > > > +   if (rd_done && wr_done) {
> > > > > > > > +   spin_unlock(lock);
> > > > > > > > +   return IRQ_NONE;
> > > > > > > > +   }
> > > > > > > > +
> > > > > > > > +   do {
> > > > > > > > +   if (!rd_done && rd_flags[hw->h2d_last_id])
> > > > > > > > +   rd_done = true;
> > > > > > > > +
> > > > > > > > +   if (!wr_done && wr_flags[hw->d2h_last_id])
> > > > > > > > +   wr_done = true;
> > > > > > > > +   } while (!rd_done || !wr_done);
> 
> 
> Thinking about this some more, my initial instinct was still correct
> actually.  If we're holding the lock to prevent the CPU from writing
> to it then how is hw->d2h_last_id updated in the other thread?  Either
> it must deadlock or it must be a race condition.

hw->d2h_last_id and hw->h2d_last_id indexes are not expected to get
updated while within the handler.

It is wr_flags[hw->d2h_last_id] and/or rd_flags[hw->h2d_last_id] that
should be set from zero to one by the DMA controller once/before it
sends the MSI interrupt. Therefore, once we're in the handler, either
wr_flags[hw->d2h_last_id] or rd_flags[hw->h2d_last_id] should be non-
zero.

However, the Intel documentation uses a suspicious wording for description
of the above: "The Descriptor Controller writes a 1 to the done bit of
the status DWORD to indicate successful completion. The Descriptor
Controller also sends an MSI interrupt for the final descriptor.
After receiving this MSI, host software can poll the done bit to
determine status."

(The "the status DWORD" in the excerpt above are located in coherent DMA
memory-mapped arrays wr_flags[hw->d2h_last_id] and rd_flags[hw->h2d_last_id])

The confusing statement is "After receiving this MSI, host software can
poll the done bit to determine status." Why would one poll a bit *after*
the MSI received? In good design it should be set by the time the MSI
arrived. May be they meant "checked" rather than "polled" or implied the
CPU still could see zero in the status DWORD due to DMA memory incoherency..

Anyways, that has never been observed and I added the loop out of the
paranoia, it never loops for me.

HTH

> regards,
> dan carpenter
> 
___
devel mailing list
de...@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel


Re: [PATCH v2 1/2] dmaengine: avalon: Intel Avalon-MM DMA Interface for PCIe

2019-10-15 Thread Alexander Gordeev
On Tue, Oct 15, 2019 at 04:03:21PM +0530, Vinod Koul wrote:
> what kind of device is this? I dont think we want these and the ones
> coming below as part of kernel kconfig!

Yes, I have already been pointed out on this and will put those as
kernel module parameters in the next version. The device is an IP
block for Intel FPGAs.

> > +static int start_dma_xfer(struct avalon_dma_hw *hw,
> > + struct avalon_dma_desc *desc)
> > +{
> > +   size_t ctrl_off;
> > +   struct __dma_desc_table *__table;
> > +   struct dma_desc_table *table;
> > +   u32 rc_src_hi, rc_src_lo;
> > +   u32 ep_dst_lo, ep_dst_hi;
> > +   int last_id, *__last_id;
> > +   int nr_descs;
> > +
> > +   if (desc->direction == DMA_TO_DEVICE) {
> > +   __table = >dma_desc_table_rd;
> > +
> > +   ctrl_off = AVALON_DMA_RD_CTRL_OFFSET;
> > +
> > +   ep_dst_hi = AVALON_DMA_RD_EP_DST_HI;
> > +   ep_dst_lo = AVALON_DMA_RD_EP_DST_LO;
> > +
> > +   __last_id = >h2d_last_id;
> > +   } else if (desc->direction == DMA_FROM_DEVICE) {
> > +   __table = >dma_desc_table_wr;
> > +
> > +   ctrl_off = AVALON_DMA_WR_CTRL_OFFSET;
> > +
> > +   ep_dst_hi = AVALON_DMA_WR_EP_DST_HI;
> > +   ep_dst_lo = AVALON_DMA_WR_EP_DST_LO;
> > +
> > +   __last_id = >d2h_last_id;
> > +   } else {
> > +   BUG();
> > +   }
> > +
> > +   table = __table->cpu_addr;
> > +   memset(>flags, 0, sizeof(table->flags));
> > +
> > +   nr_descs = setup_dma_descs(table->descs, desc);
> > +   if (WARN_ON(nr_descs < 1))
> > +   return nr_descs;

(1) Here it may fail.

> > +   last_id = nr_descs - 1;
> > +   *__last_id = last_id;
> > +
> > +   rc_src_hi = __table->dma_addr >> 32;
> > +   rc_src_lo = (u32)__table->dma_addr;
> > +
> > +   start_xfer(hw->regs, ctrl_off,
> > +  rc_src_hi, rc_src_lo,
> > +  ep_dst_hi, ep_dst_lo,
> > +  last_id);
> > +
> > +   return 0;
> 
> why have a return when you always return 0?

Please see (1) above.

> > +static irqreturn_t avalon_dma_interrupt(int irq, void *dev_id)
> > +{
> > +   struct avalon_dma *adma = (struct avalon_dma *)dev_id;
> > +   struct avalon_dma_chan *chan = >chan;
> > +   struct avalon_dma_hw *hw = >hw;
> > +   spinlock_t *lock = >vchan.lock;
> > +   u32 *rd_flags = hw->dma_desc_table_rd.cpu_addr->flags;
> > +   u32 *wr_flags = hw->dma_desc_table_wr.cpu_addr->flags;

(2)

> > +   struct avalon_dma_desc *desc;
> > +   struct virt_dma_desc *vdesc;
> > +   bool rd_done;
> > +   bool wr_done;
> > +
> > +   spin_lock(lock);
> > +
> > +   rd_done = (hw->h2d_last_id < 0);
> > +   wr_done = (hw->d2h_last_id < 0);

(3)

> > +
> > +   if (rd_done && wr_done) {
> > +   spin_unlock(lock);
> > +   return IRQ_NONE;
> > +   }
> > +
> > +   do {
> > +   if (!rd_done && rd_flags[hw->h2d_last_id])
> > +   rd_done = true;
> > +
> > +   if (!wr_done && wr_flags[hw->d2h_last_id])
> > +   wr_done = true;
> > +   } while (!rd_done || !wr_done);
> 
> Can you explain this logic. I dont like busy loop in isr and who updates

Here is the comment in the next version of the patch:

The Intel documentation claims "The Descriptor Controller
writes a 1 to the done bit of the status DWORD to indicate
successful completion. The Descriptor Controller also sends
an MSI interrupt for the final descriptor. After receiving
this MSI, host software can poll the done bit to determine
status."

The above could be read like MSI interrupt might be delivered
before the corresponding done bit is set. But in reality it
does not happen at all (or happens really rare). So put here
the done bit polling, just in case.

> rd_done and rd_flags etc..?

rd_flags/wr_flags are updated by the hardware (2) and mapped in as
coherent DMA memory.

rd_done/wr_done are just local variables (3)

> > +static int __init avalon_pci_probe(struct pci_dev *pci_dev,
> > +  const struct pci_device_id *id)
> > +{
> > +   void *adma;
> > +   void __iomem *regs;
> > +   int ret;
> > +
> > +   ret = pci_enable_device(pci_dev);
> > +   if (ret)
> > +   goto enable_err;
> > +
> > +   ret = pci_request_regions(pci_dev, DRIVER_NAME);
> > +   if (ret)
> > +   goto reg_err;
> > +
> > +   regs = pci_ioremap_bar(pci_dev, PCI_BAR);
> 
> This is a pci device, so we should really be using the PCI way of
> setting and querying the resources. Doing this thru kernel config
> options is not correct!

I assume you are referring to PCI_BAR in this particular case, right?
If so, this is an excerpt from the documentation that I read like a
BAR the DMA controller is mapped to needs to be configurable:

"When the DMA Descriptor Controller is externally instantiated, these
registers are accessed through a BAR. The offsets must be added to the
base address for the read controller. When the Descriptor Controller
is internally instantiated these registers are accessed through BAR0."

Thank 

Re: [PATCH v2 1/2] dmaengine: avalon: Intel Avalon-MM DMA Interface for PCIe

2019-10-15 Thread Alexander Gordeev
On Tue, Oct 15, 2019 at 02:41:08PM +0300, Dan Carpenter wrote:
> > > > > > > > +   spin_lock(lock);
> > 
> > [*]
> 
> [ snip ]
> 
> > I struggle to realize how the spinlock I use (see [*] above) does not
> > protect the reader.
> 
> Argh  I'm really sorry.  I completely didn't see the spinlock.  :P

Np ;) May be in the next version it will be more visible.
I done it the way you asked ( even though I do not like it :D ):

spin_lock(>vchan.lock);

> I am embarrassed.  Wow...
> 
> regards,
> dan carpenter
> 
___
devel mailing list
de...@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel


Re: [PATCH v2 1/2] dmaengine: avalon: Intel Avalon-MM DMA Interface for PCIe

2019-10-15 Thread Alexander Gordeev
On Thu, Oct 10, 2019 at 02:30:34PM +0300, Dan Carpenter wrote:
> On Thu, Oct 10, 2019 at 10:51:45AM +0200, Alexander Gordeev wrote:
> > On Wed, Oct 09, 2019 at 09:53:23PM +0300, Dan Carpenter wrote:
> > > > > > +   u32 *rd_flags = hw->dma_desc_table_rd.cpu_addr->flags;
> > > > > > +   u32 *wr_flags = hw->dma_desc_table_wr.cpu_addr->flags;
> > > > > > +   struct avalon_dma_desc *desc;
> > > > > > +   struct virt_dma_desc *vdesc;
> > > > > > +   bool rd_done;
> > > > > > +   bool wr_done;
> > > > > > +
> > > > > > +   spin_lock(lock);

[*]

> > > > > > +
> > > > > > +   rd_done = (hw->h2d_last_id < 0);
> > > > > > +   wr_done = (hw->d2h_last_id < 0);
> > > > > > +
> > > > > > +   if (rd_done && wr_done) {
> > > > > > +   spin_unlock(lock);
> > > > > > +   return IRQ_NONE;
> > > > > > +   }
> > > > > > +
> > > > > > +   do {
> > > > > > +   if (!rd_done && rd_flags[hw->h2d_last_id])
> > > > > > +   rd_done = true;
> > > > > > +
> > > > > > +   if (!wr_done && wr_flags[hw->d2h_last_id])
> > > > > > +   wr_done = true;
> > > > > > +   } while (!rd_done || !wr_done);
> > > > > 
> > > > > This loop is very strange.  It feels like the last_id indexes needs
> > > > > to atomic or protected from racing somehow so we don't do an out of
> > > > > bounds read.
> > 
> > [...]
> > 
> > > You're missing my point.  When we set
> > > hw->d2h_last_id = 1;
> > [1]
> > > ...
> > > hw->d2h_last_id = 2;
> > [2]
> > 
> > > There is a tiny moment where ->d2h_last_id is transitioning from 1 to 2
> > > where its value is unknown.  We're in a busy loop here so we have a
> > > decent chance of hitting that 1/1000,000th of a second.  If we happen to
> > > hit it at exactly the right time then we're reading from a random
> > > address and it will cause an oops.
> > > 
> > > We have to use atomic_t types or something to handle race conditions.
> > 
> > Err.. I am still missing the point :( In your example I do see a chance
> > for a reader to read out 1 at point in time [2] - because of SMP race.
> > But what could it be other than 1 or 2?
> > 
> 
> The 1 to 2 transition was a poorly chosen example, but a -1 to 1
> trasition is better.  The cpu could write a byte at a time.  So maybe
> it only wrote the two highest bytes so now it's 0x.  It's not -1 and
> it's not 1 and it's not a valid index.
> 
> > Anyways, all code paths dealing with h2d_last_id and d2h_last_id indexes
> > are protected with a spinlock.
> 
> You have to protect both the writer and the reader.  (That's why this
> bug is so easy to spot).  https://lwn.net/Articles/793253/

I struggle to realize how the spinlock I use (see [*] above) does not
protect the reader.

I am going to post updated version shortly, hopefully it will make more
sense.

> regards,
> dan carpenter
> 
___
devel mailing list
de...@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel


Re: [PATCH v2 1/2] dmaengine: avalon: Intel Avalon-MM DMA Interface for PCIe

2019-10-10 Thread Alexander Gordeev
On Wed, Oct 09, 2019 at 09:53:23PM +0300, Dan Carpenter wrote:
> > > > +   u32 *rd_flags = hw->dma_desc_table_rd.cpu_addr->flags;
> > > > +   u32 *wr_flags = hw->dma_desc_table_wr.cpu_addr->flags;
> > > > +   struct avalon_dma_desc *desc;
> > > > +   struct virt_dma_desc *vdesc;
> > > > +   bool rd_done;
> > > > +   bool wr_done;
> > > > +
> > > > +   spin_lock(lock);
> > > > +
> > > > +   rd_done = (hw->h2d_last_id < 0);
> > > > +   wr_done = (hw->d2h_last_id < 0);
> > > > +
> > > > +   if (rd_done && wr_done) {
> > > > +   spin_unlock(lock);
> > > > +   return IRQ_NONE;
> > > > +   }
> > > > +
> > > > +   do {
> > > > +   if (!rd_done && rd_flags[hw->h2d_last_id])
> > > > +   rd_done = true;
> > > > +
> > > > +   if (!wr_done && wr_flags[hw->d2h_last_id])
> > > > +   wr_done = true;
> > > > +   } while (!rd_done || !wr_done);
> > > 
> > > This loop is very strange.  It feels like the last_id indexes needs
> > > to atomic or protected from racing somehow so we don't do an out of
> > > bounds read.

[...]

> You're missing my point.  When we set
> hw->d2h_last_id = 1;
[1]
> ...
> hw->d2h_last_id = 2;
[2]

> There is a tiny moment where ->d2h_last_id is transitioning from 1 to 2
> where its value is unknown.  We're in a busy loop here so we have a
> decent chance of hitting that 1/1000,000th of a second.  If we happen to
> hit it at exactly the right time then we're reading from a random
> address and it will cause an oops.
> 
> We have to use atomic_t types or something to handle race conditions.

Err.. I am still missing the point :( In your example I do see a chance
for a reader to read out 1 at point in time [2] - because of SMP race.
But what could it be other than 1 or 2?

Anyways, all code paths dealing with h2d_last_id and d2h_last_id indexes
are protected with a spinlock.

> regards,
> dan carpenter
> 
___
devel mailing list
de...@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel


Re: [PATCH v2 1/2] dmaengine: avalon: Intel Avalon-MM DMA Interface for PCIe

2019-10-09 Thread Alexander Gordeev
On Wed, Oct 09, 2019 at 03:14:41PM +0300, Dan Carpenter wrote:
> > +config AVALON_DMA_PCI_VENDOR_ID
> > +   hex "PCI vendor ID"
> > +   default "0x1172"
> > +
> > +config AVALON_DMA_PCI_DEVICE_ID
> > +   hex "PCI device ID"
> > +   default "0xe003"
> 
> This feels wrong.  Why isn't it known in advance.

Because device designers would likely use they own IDs. The ones I
put are just defaults inherited from the (Altera) reference design.

> > +   u32 *rd_flags = hw->dma_desc_table_rd.cpu_addr->flags;
> > +   u32 *wr_flags = hw->dma_desc_table_wr.cpu_addr->flags;
> > +   struct avalon_dma_desc *desc;
> > +   struct virt_dma_desc *vdesc;
> > +   bool rd_done;
> > +   bool wr_done;
> > +
> > +   spin_lock(lock);
> > +
> > +   rd_done = (hw->h2d_last_id < 0);
> > +   wr_done = (hw->d2h_last_id < 0);
> > +
> > +   if (rd_done && wr_done) {
> > +   spin_unlock(lock);
> > +   return IRQ_NONE;
> > +   }
> > +
> > +   do {
> > +   if (!rd_done && rd_flags[hw->h2d_last_id])
> > +   rd_done = true;
> > +
> > +   if (!wr_done && wr_flags[hw->d2h_last_id])
> > +   wr_done = true;
> > +   } while (!rd_done || !wr_done);
> 
> This loop is very strange.  It feels like the last_id indexes needs
> to atomic or protected from racing somehow so we don't do an out of
> bounds read.

My bad. I should have put a comment on this. This polling comes from my
reading of the Intel documentation:

"The MSI interrupt notifies the host when a DMA operation has completed.
After the host receives this interrupt, it can poll the DMA read or write
status table to determine which entry or entries have the done bit set."

"The Descriptor Controller writes a 1 to the done bit of the status DWORD
to indicate successful completion. The Descriptor Controller also sends
an MSI interrupt for the final descriptor. After receiving this MSI,
host software can poll the done bit to determine status."

I sense an ambiguity above. It sounds possible an MSI interrupt could be
delivered before corresponding done bit is set. May be imperfect wording..
Anyway, the loop does look weird and in reality I doubt I observed the
done bit unset even once. So I put this polling just in case.

> > +   struct avalon_dma_chan *chan = to_avalon_dma_chan(dma_chan);
> > +   struct avalon_dma_desc *desc;
> > +   gfp_t gfp_flags = in_interrupt() ? GFP_NOWAIT : GFP_KERNEL;
> > +   dma_addr_t dev_addr;
> > +
> > +   if (direction == DMA_MEM_TO_DEV)
> > +   dev_addr = chan->dst_addr;
> > +   else if (direction == DMA_DEV_TO_MEM)
> > +   dev_addr = chan->src_addr;
> > +   else
> > +   return NULL;
> > +
> > +   desc = kzalloc(sizeof(*desc), gfp_flags);
> 
> Everyone else does GFP_WAIT or GFP_ATOMIC.  Is GFP_KERNEL really okay?

I am not sure why not to use GFP_KERNEL from non-atomic context.
Documentation/driver-api/dmaengine/provider.rst claims always to
use GFP_NOWAIT though:

  - Any allocation you might do should be using the GFP_NOWAIT
flag, in order not to potentially sleep, but without depleting
the emergency pool either.

So probably I just should use GFP_NOWAIT.

Thanks, Dan!

> regards,
> dan carpenter
> 
___
devel mailing list
de...@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel


Re: [PATCH RFC 0/2] staging: Support Avalon-MM DMA Interface for PCIe

2019-10-09 Thread Alexander Gordeev
On Thu, Sep 19, 2019 at 01:37:08PM +0200, Greg KH wrote:
> Why is this being submitted for drivers/staging/ and not the "real" part
> of the kernel tree?

Hi Greg!

I sent v2 of the patchset, but it does not need to be part of the
staging tree. I CC-ed de...@driverdev.osuosl.org for reference.

Thanks!

> All staging code must have a TODO file listing what needs to be done in
> order to get it out of staging, and be self-contained (i.e. no files
> include/linux/)
> 
> Please fix that up when resending this series.
> 
> thanks,
> 
> greg k-h
___
devel mailing list
de...@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel


[PATCH RFC v2 2/2] dmaengine: avalon: Intel Avalon-MM DMA Interface for PCIe test

2019-10-09 Thread Alexander Gordeev
This is sample implementation of a driver that uses "avalon-dma"
driver interface to perform data transfers between on-chip and
system memory in devices using Avalon-MM DMA Interface for PCIe
design. Companion user-level tool could be found at
https://github.com/a-gordeev/avalon-tool.git

CC: Michael Chen 
CC: de...@driverdev.osuosl.org
CC: dmaeng...@vger.kernel.org

Signed-off-by: Alexander Gordeev 
---
 drivers/dma/Kconfig |   1 +
 drivers/dma/Makefile|   1 +
 drivers/dma/avalon-test/Kconfig |  23 +
 drivers/dma/avalon-test/Makefile|  14 +
 drivers/dma/avalon-test/avalon-dev.c|  65 +++
 drivers/dma/avalon-test/avalon-dev.h|  33 ++
 drivers/dma/avalon-test/avalon-ioctl.c  | 128 +
 drivers/dma/avalon-test/avalon-ioctl.h  |  12 +
 drivers/dma/avalon-test/avalon-mmap.c   |  93 
 drivers/dma/avalon-test/avalon-mmap.h   |  12 +
 drivers/dma/avalon-test/avalon-sg-buf.c | 132 +
 drivers/dma/avalon-test/avalon-sg-buf.h |  26 +
 drivers/dma/avalon-test/avalon-util.c   |  54 ++
 drivers/dma/avalon-test/avalon-util.h   |  12 +
 drivers/dma/avalon-test/avalon-xfer.c   | 697 
 drivers/dma/avalon-test/avalon-xfer.h   |  28 +
 include/uapi/linux/avalon-ioctl.h   |  32 ++
 17 files changed, 1363 insertions(+)
 create mode 100644 drivers/dma/avalon-test/Kconfig
 create mode 100644 drivers/dma/avalon-test/Makefile
 create mode 100644 drivers/dma/avalon-test/avalon-dev.c
 create mode 100644 drivers/dma/avalon-test/avalon-dev.h
 create mode 100644 drivers/dma/avalon-test/avalon-ioctl.c
 create mode 100644 drivers/dma/avalon-test/avalon-ioctl.h
 create mode 100644 drivers/dma/avalon-test/avalon-mmap.c
 create mode 100644 drivers/dma/avalon-test/avalon-mmap.h
 create mode 100644 drivers/dma/avalon-test/avalon-sg-buf.c
 create mode 100644 drivers/dma/avalon-test/avalon-sg-buf.h
 create mode 100644 drivers/dma/avalon-test/avalon-util.c
 create mode 100644 drivers/dma/avalon-test/avalon-util.h
 create mode 100644 drivers/dma/avalon-test/avalon-xfer.c
 create mode 100644 drivers/dma/avalon-test/avalon-xfer.h
 create mode 100644 include/uapi/linux/avalon-ioctl.h

diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index f6f43480a4a4..4b3c6a6baf4c 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -670,6 +670,7 @@ source "drivers/dma/sh/Kconfig"
 source "drivers/dma/ti/Kconfig"
 
 source "drivers/dma/avalon/Kconfig"
+source "drivers/dma/avalon-test/Kconfig"
 
 # clients
 comment "DMA Clients"
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index fd7e11417b73..eb3ee7f6cac6 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -76,6 +76,7 @@ obj-$(CONFIG_XGENE_DMA) += xgene-dma.o
 obj-$(CONFIG_ZX_DMA) += zx_dma.o
 obj-$(CONFIG_ST_FDMA) += st_fdma.o
 obj-$(CONFIG_AVALON_DMA) += avalon/
+obj-$(CONFIG_AVALON_TEST) += avalon-test/
 
 obj-y += mediatek/
 obj-y += qcom/
diff --git a/drivers/dma/avalon-test/Kconfig b/drivers/dma/avalon-test/Kconfig
new file mode 100644
index ..021c28fe77a6
--- /dev/null
+++ b/drivers/dma/avalon-test/Kconfig
@@ -0,0 +1,23 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Avalon DMA engine
+#
+# Author: Alexander Gordeev 
+#
+config AVALON_TEST
+   select AVALON_DMA
+   tristate "Intel Avalon-MM DMA Interface for PCIe test driver"
+   help
+ This selects a test driver for Avalon-MM DMA Interface for PCI
+
+if AVALON_TEST
+
+config AVALON_TEST_TARGET_BASE
+   hex "Target device base address"
+   default "0x7000"
+
+config AVALON_TEST_TARGET_SIZE
+   hex "Target device memory size"
+   default "0x1000"
+
+endif
diff --git a/drivers/dma/avalon-test/Makefile b/drivers/dma/avalon-test/Makefile
new file mode 100644
index ..63351c52478a
--- /dev/null
+++ b/drivers/dma/avalon-test/Makefile
@@ -0,0 +1,14 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Avalon DMA driver
+#
+# Author: Alexander Gordeev 
+#
+obj-$(CONFIG_AVALON_TEST)  += avalon-test.o
+
+avalon-test-objs :=avalon-dev.o \
+   avalon-ioctl.o \
+   avalon-mmap.o \
+   avalon-sg-buf.o \
+   avalon-xfer.o \
+   avalon-util.o
diff --git a/drivers/dma/avalon-test/avalon-dev.c 
b/drivers/dma/avalon-test/avalon-dev.c
new file mode 100644
index ..9e83f777f937
--- /dev/null
+++ b/drivers/dma/avalon-test/avalon-dev.c
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Avalon DMA driver
+ *
+ * Author: Alexander Gordeev 
+ */
+#include 
+#include 
+#include 
+
+#include "avalon-dev.h"
+#include "avalon-ioctl.h"
+#include "avalon-mmap.h"
+
+const struct file_operations avalon_dev_fops = {
+   .llseek = generic_file_llseek,
+   .unlocked_ioctl = avalon_dev_ioctl,
+   .mmap   = avalo

[PATCH v2 1/2] dmaengine: avalon: Intel Avalon-MM DMA Interface for PCIe

2019-10-09 Thread Alexander Gordeev
Support Avalon-MM DMA Interface for PCIe used in hard IPs for
Intel Arria, Cyclone or Stratix FPGAs.

CC: Michael Chen 
CC: de...@driverdev.osuosl.org
CC: dmaeng...@vger.kernel.org

Signed-off-by: Alexander Gordeev 
---
 drivers/dma/Kconfig  |   2 +
 drivers/dma/Makefile |   1 +
 drivers/dma/avalon/Kconfig   |  88 +++
 drivers/dma/avalon/Makefile  |   6 +
 drivers/dma/avalon/avalon-core.c | 432 +++
 drivers/dma/avalon/avalon-core.h |  90 +++
 drivers/dma/avalon/avalon-hw.c   | 212 +++
 drivers/dma/avalon/avalon-hw.h   |  86 ++
 drivers/dma/avalon/avalon-pci.c  | 150 +++
 9 files changed, 1067 insertions(+)
 create mode 100644 drivers/dma/avalon/Kconfig
 create mode 100644 drivers/dma/avalon/Makefile
 create mode 100644 drivers/dma/avalon/avalon-core.c
 create mode 100644 drivers/dma/avalon/avalon-core.h
 create mode 100644 drivers/dma/avalon/avalon-hw.c
 create mode 100644 drivers/dma/avalon/avalon-hw.h
 create mode 100644 drivers/dma/avalon/avalon-pci.c

diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 7af874b69ffb..f6f43480a4a4 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -669,6 +669,8 @@ source "drivers/dma/sh/Kconfig"
 
 source "drivers/dma/ti/Kconfig"
 
+source "drivers/dma/avalon/Kconfig"
+
 # clients
 comment "DMA Clients"
depends on DMA_ENGINE
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index f5ce8665e944..fd7e11417b73 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -75,6 +75,7 @@ obj-$(CONFIG_UNIPHIER_MDMAC) += uniphier-mdmac.o
 obj-$(CONFIG_XGENE_DMA) += xgene-dma.o
 obj-$(CONFIG_ZX_DMA) += zx_dma.o
 obj-$(CONFIG_ST_FDMA) += st_fdma.o
+obj-$(CONFIG_AVALON_DMA) += avalon/
 
 obj-y += mediatek/
 obj-y += qcom/
diff --git a/drivers/dma/avalon/Kconfig b/drivers/dma/avalon/Kconfig
new file mode 100644
index ..09e0773fcdb2
--- /dev/null
+++ b/drivers/dma/avalon/Kconfig
@@ -0,0 +1,88 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Avalon DMA engine
+#
+# Author: Alexander Gordeev 
+#
+config AVALON_DMA
+   tristate "Intel Avalon-MM DMA Interface for PCIe"
+   depends on PCI
+   select DMA_ENGINE
+   select DMA_VIRTUAL_CHANNELS
+   help
+ This selects a driver for Avalon-MM DMA Interface for PCIe
+ hard IP block used in Intel Arria, Cyclone or Stratix FPGAs.
+
+if AVALON_DMA
+
+config AVALON_DMA_MASK_WIDTH
+   int "Avalon DMA streaming and coherent bitmask width"
+   range 0 64
+   default 64
+   help
+ Width of bitmask for streaming and coherent DMA operations
+
+config AVALON_DMA_CTRL_BASE
+   hex "Avalon DMA controllers base"
+   default "0x"
+
+config AVALON_DMA_RD_EP_DST_LO
+   hex "Avalon DMA read controller base low"
+   default "0x8000"
+   help
+ Specifies the lower 32-bits of the base address of the read
+ status and descriptor table in the Root Complex memory.
+
+config AVALON_DMA_RD_EP_DST_HI
+   hex "Avalon DMA read controller base high"
+   default "0x"
+   help
+ Specifies the upper 32-bits of the base address of the read
+ status and descriptor table in the Root Complex memory.
+
+config AVALON_DMA_WR_EP_DST_LO
+   hex "Avalon DMA write controller base low"
+   default "0x80002000"
+   help
+ Specifies the lower 32-bits of the base address of the write
+ status and descriptor table in the Root Complex memory.
+
+config AVALON_DMA_WR_EP_DST_HI
+   hex "Avalon DMA write controller base high"
+   default "0x"
+   help
+ Specifies the upper 32-bits of the base address of the write
+ status and descriptor table in the Root Complex memory.
+
+config AVALON_DMA_PCI_VENDOR_ID
+   hex "PCI vendor ID"
+   default "0x1172"
+
+config AVALON_DMA_PCI_DEVICE_ID
+   hex "PCI device ID"
+   default "0xe003"
+
+config AVALON_DMA_PCI_BAR
+   int "PCI device BAR the Avalon DMA controller is mapped to"
+   range 0 5
+   default 0
+   help
+ Number of PCI BAR the DMA controller is mapped to
+
+config AVALON_DMA_PCI_MSI_COUNT_ORDER
+   int "Count of MSIs the PCI device provides (order)"
+   range 0 5
+   default 5
+   help
+ Number of vectors the PCI device uses in multiple MSI mode.
+ This number is provided as the power of two.
+
+config AVALON_DMA_PCI_MSI_VECTOR
+   int "Vector number the DMA controller is mapped to"
+   range 0 31
+   default 0
+   help
+ Number of MSI vector the DMA controller is mapped to in
+ multiple MSI mode.
+
+endif
diff --git a/drivers/dma/avalon/Makefile b/drivers/dma/avalon

[PATCH v2 0/2] dmaengine: avalon: Support Avalon-MM DMA Interface for PCIe

2019-10-09 Thread Alexander Gordeev
This series is against v5.4-rc2

Changes since v1:
- "avalon-dma" converted to "dmaengine" model;
- "avalon-drv" renamed to "avalon-test";

The Avalon-MM DMA Interface for PCIe is a design used in hard IPs for
Intel Arria, Cyclone or Stratix FPGAs. It transfers data between on-chip
memory and system memory.

Patch 1. This patch introduces "avalon-dma" driver that conforms to
"dmaengine" model.

Patch 2. The existing "dmatest" is not meant for DMA_SLAVE type of
transfers needed by "avalon-dma". Instead, custom "avalon-test" driver
was used to debug and stress "avalon-dma". If it could be useful for a
wider audience, I can make it optional part of "avalon-dma" sources or
leave it as separate driver. Marking patch 2 as RFC for now.

Testing was done using a custom FPGA build with Arria 10 FPGA streaming
data to target device RAM:

  +--++--++--++--+
  | Nios CPU |<-->|   RAM|<-->|  Avalon  |<-PCIe->| Host CPU |
  +--++--++--++--+

The RAM was examined for data integrity by examining RAM contents
from host CPU (indirectly - checking data DMAed to the system) and
from Nios CPU that has direct access to the device RAM. A companion
tool using "avalon-test" driver was used to DMA files to the device:
https://github.com/a-gordeev/avalon-tool.git

CC: Michael Chen 
CC: de...@driverdev.osuosl.org
CC: dmaeng...@vger.kernel.org

Alexander Gordeev (2):
  dmaengine: avalon: Intel Avalon-MM DMA Interface for PCIe
  dmaengine: avalon: Intel Avalon-MM DMA Interface for PCIe test

 drivers/dma/Kconfig |   3 +
 drivers/dma/Makefile|   2 +
 drivers/dma/avalon-test/Kconfig |  23 +
 drivers/dma/avalon-test/Makefile|  14 +
 drivers/dma/avalon-test/avalon-dev.c|  65 +++
 drivers/dma/avalon-test/avalon-dev.h|  33 ++
 drivers/dma/avalon-test/avalon-ioctl.c  | 128 +
 drivers/dma/avalon-test/avalon-ioctl.h  |  12 +
 drivers/dma/avalon-test/avalon-mmap.c   |  93 
 drivers/dma/avalon-test/avalon-mmap.h   |  12 +
 drivers/dma/avalon-test/avalon-sg-buf.c | 132 +
 drivers/dma/avalon-test/avalon-sg-buf.h |  26 +
 drivers/dma/avalon-test/avalon-util.c   |  54 ++
 drivers/dma/avalon-test/avalon-util.h   |  12 +
 drivers/dma/avalon-test/avalon-xfer.c   | 697 
 drivers/dma/avalon-test/avalon-xfer.h   |  28 +
 drivers/dma/avalon/Kconfig  |  88 +++
 drivers/dma/avalon/Makefile |   6 +
 drivers/dma/avalon/avalon-core.c| 432 +++
 drivers/dma/avalon/avalon-core.h|  90 +++
 drivers/dma/avalon/avalon-hw.c  | 212 +++
 drivers/dma/avalon/avalon-hw.h  |  86 +++
 drivers/dma/avalon/avalon-pci.c | 150 +
 include/uapi/linux/avalon-ioctl.h   |  32 ++
 24 files changed, 2430 insertions(+)
 create mode 100644 drivers/dma/avalon-test/Kconfig
 create mode 100644 drivers/dma/avalon-test/Makefile
 create mode 100644 drivers/dma/avalon-test/avalon-dev.c
 create mode 100644 drivers/dma/avalon-test/avalon-dev.h
 create mode 100644 drivers/dma/avalon-test/avalon-ioctl.c
 create mode 100644 drivers/dma/avalon-test/avalon-ioctl.h
 create mode 100644 drivers/dma/avalon-test/avalon-mmap.c
 create mode 100644 drivers/dma/avalon-test/avalon-mmap.h
 create mode 100644 drivers/dma/avalon-test/avalon-sg-buf.c
 create mode 100644 drivers/dma/avalon-test/avalon-sg-buf.h
 create mode 100644 drivers/dma/avalon-test/avalon-util.c
 create mode 100644 drivers/dma/avalon-test/avalon-util.h
 create mode 100644 drivers/dma/avalon-test/avalon-xfer.c
 create mode 100644 drivers/dma/avalon-test/avalon-xfer.h
 create mode 100644 drivers/dma/avalon/Kconfig
 create mode 100644 drivers/dma/avalon/Makefile
 create mode 100644 drivers/dma/avalon/avalon-core.c
 create mode 100644 drivers/dma/avalon/avalon-core.h
 create mode 100644 drivers/dma/avalon/avalon-hw.c
 create mode 100644 drivers/dma/avalon/avalon-hw.h
 create mode 100644 drivers/dma/avalon/avalon-pci.c
 create mode 100644 include/uapi/linux/avalon-ioctl.h

-- 
2.23.0

___
devel mailing list
de...@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel


[PATCH RFC 1/2] staging: avalon-dma: Avalon DMA engine

2019-09-19 Thread Alexander Gordeev
Basic support for Avalon-MM DMA Interface for PCIe found in
hard IPs for Intel Arria, Cyclone or Stratix FPGAs. This is
an alternative (though minimal functionality) implementation
of reference design driver from Intel.

Unlike the reference design, the introduced interface allows
submitting contiguous buffers, scatterlists and DMA completion
callbacks - much like "dmaengine" does.

CC: Michael Chen 
CC: de...@driverdev.osuosl.org
CC: dmaeng...@vger.kernel.org

Signed-off-by: Alexander Gordeev 
---
 drivers/staging/Kconfig   |   2 +
 drivers/staging/Makefile  |   1 +
 drivers/staging/avalon-dma/Kconfig|  45 ++
 drivers/staging/avalon-dma/Makefile   |  11 +
 drivers/staging/avalon-dma/avalon-dma-core.c  | 515 ++
 drivers/staging/avalon-dma/avalon-dma-core.h  |  52 ++
 .../staging/avalon-dma/avalon-dma-interrupt.c | 118 
 .../staging/avalon-dma/avalon-dma-interrupt.h |  13 +
 drivers/staging/avalon-dma/avalon-dma-util.c  | 196 +++
 drivers/staging/avalon-dma/avalon-dma-util.h  |  25 +
 include/linux/avalon-dma-hw.h |  72 +++
 include/linux/avalon-dma.h|  68 +++
 12 files changed, 1118 insertions(+)
 create mode 100644 drivers/staging/avalon-dma/Kconfig
 create mode 100644 drivers/staging/avalon-dma/Makefile
 create mode 100644 drivers/staging/avalon-dma/avalon-dma-core.c
 create mode 100644 drivers/staging/avalon-dma/avalon-dma-core.h
 create mode 100644 drivers/staging/avalon-dma/avalon-dma-interrupt.c
 create mode 100644 drivers/staging/avalon-dma/avalon-dma-interrupt.h
 create mode 100644 drivers/staging/avalon-dma/avalon-dma-util.c
 create mode 100644 drivers/staging/avalon-dma/avalon-dma-util.h
 create mode 100644 include/linux/avalon-dma-hw.h
 create mode 100644 include/linux/avalon-dma.h

diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 7c96a01eef6c..31c732ececd1 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -120,4 +120,6 @@ source "drivers/staging/kpc2000/Kconfig"
 
 source "drivers/staging/isdn/Kconfig"
 
+source "drivers/staging/avalon-dma/Kconfig"
+
 endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index fcaac9693b83..eb974cac85d3 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -50,3 +50,4 @@ obj-$(CONFIG_EROFS_FS)+= erofs/
 obj-$(CONFIG_FIELDBUS_DEV) += fieldbus/
 obj-$(CONFIG_KPC2000)  += kpc2000/
 obj-$(CONFIG_ISDN_CAPI)+= isdn/
+obj-$(CONFIG_AVALON_DMA)   += avalon-dma/
diff --git a/drivers/staging/avalon-dma/Kconfig 
b/drivers/staging/avalon-dma/Kconfig
new file mode 100644
index ..5164e990a62b
--- /dev/null
+++ b/drivers/staging/avalon-dma/Kconfig
@@ -0,0 +1,45 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Avalon DMA engine
+#
+# Author: Alexander Gordeev 
+#
+config AVALON_DMA
+   tristate "Avalon DMA engine"
+   help
+ This selects a driver for Avalon DMA engine IP block
+
+config AVALON_DMA_TARGET_BASE
+   hex "Target device base address"
+   default "0x7000"
+   depends on AVALON_DMA
+
+config AVALON_DMA_TARGET_SIZE
+   hex "Target device memory size"
+   default "0x1000"
+   depends on AVALON_DMA
+
+config AVALON_DMA_CTRL_BASE
+   hex "Avalon DMA controllers base"
+   default "0x"
+   depends on AVALON_DMA
+
+config AVALON_DMA_RD_EP_DST_LO
+   hex "Avalon DMA read controller base low"
+   default "0x8000"
+   depends on AVALON_DMA
+
+config AVALON_DMA_RD_EP_DST_HI
+   hex "Avalon DMA read controller base high"
+   default "0x"
+   depends on AVALON_DMA
+
+config AVALON_DMA_WR_EP_DST_LO
+   hex "Avalon DMA write controller base low"
+   default "0x80002000"
+   depends on AVALON_DMA
+
+config AVALON_DMA_WR_EP_DST_HI
+   hex "Avalon DMA write controller base high"
+   default "0x"
+   depends on AVALON_DMA
diff --git a/drivers/staging/avalon-dma/Makefile 
b/drivers/staging/avalon-dma/Makefile
new file mode 100644
index 0000..61cb0ee7c7a8
--- /dev/null
+++ b/drivers/staging/avalon-dma/Makefile
@@ -0,0 +1,11 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Avalon DMA engine
+#
+# Author: Alexander Gordeev 
+#
+obj-$(CONFIG_AVALON_DMA)   += avalon-dma.o
+
+avalon-dma-objs := avalon-dma-core.o \
+   avalon-dma-util.o \
+   avalon-dma-interrupt.o
diff --git a/drivers/staging/avalon-dma/avalon-dma-core.c 
b/drivers/staging/avalon-dma/avalon-dma-core.c
new file mode 100644
index 0000..9e90c694785f
--- /dev/null
+++ b/drivers/staging/avalon-dma/avalon-dma-core.c
@@ -0,0 +1,515 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Avalon D

[PATCH RFC 0/2] staging: Support Avalon-MM DMA Interface for PCIe

2019-09-19 Thread Alexander Gordeev
The Avalon-MM DMA Interface for PCIe is a design found in hard IPs for
Intel Arria, Cyclone or Stratix FPGAs. It transfers data between on-chip
memory and system memory. This RFC is an attempt to provide a generic API:

typedef void (*avalon_dma_xfer_callback)(void *dma_async_param);
 
int avalon_dma_submit_xfer(
struct avalon_dma *avalon_dma,
enum dma_data_direction direction,
dma_addr_t dev_addr, dma_addr_t host_addr,
unsigned int size,
avalon_dma_xfer_callback callback,
void *callback_param);
 
int avalon_dma_submit_xfer_sg(struct avalon_dma *avalon_dma,
enum dma_data_direction direction,
dma_addr_t dev_addr,
struct sg_table *sg_table,
avalon_dma_xfer_callback callback,
void *callback_param);
 
int avalon_dma_issue_pending(struct avalon_dma *avalon_dma);

Patch 1 introduces "avalon-dma" driver that provides the above-mentioned
generic interface.

Patch 2 adds "avalon-drv" driver using "avalon-dma" to transfer user-
provided data. This driver was used to debug and stress "avalon-dma"
and could be used as a code base for other implementations. Strictly
speaking, it does not need to be part of the kernel tree.
A companion tool using "avalon-drv" to DMA files (not part of this
patchset) is located at g...@github.com:a-gordeev/avalon-drv-tool.git

The suggested interface is developed with the standard "dmaengine"
in mind and could be reworked to suit it. I would appreciate, however
gathering some feedback on the implemenation first - as the hardware-
specific code would persist. It is also a call for testing - I only
have access to a single Arria 10 device to try on.

This series is against v5.3 and could be found at
g...@github.com:a-gordeev/linux.git avalon-dma-engine


CC: Michael Chen 
CC: de...@driverdev.osuosl.org
CC: dmaeng...@vger.kernel.org

Alexander Gordeev (2):
  staging: avalon-dma: Avalon DMA engine
  staging: avalon-drv: Avalon DMA driver

 drivers/staging/Kconfig   |   4 +
 drivers/staging/Makefile  |   2 +
 drivers/staging/avalon-dma/Kconfig|  45 ++
 drivers/staging/avalon-dma/Makefile   |  11 +
 drivers/staging/avalon-dma/avalon-dma-core.c  | 515 ++
 drivers/staging/avalon-dma/avalon-dma-core.h  |  52 ++
 .../staging/avalon-dma/avalon-dma-interrupt.c | 118 
 .../staging/avalon-dma/avalon-dma-interrupt.h |  13 +
 drivers/staging/avalon-dma/avalon-dma-util.c  | 196 ++
 drivers/staging/avalon-dma/avalon-dma-util.h  |  25 +
 drivers/staging/avalon-drv/Kconfig|  34 +
 drivers/staging/avalon-drv/Makefile   |  14 +
 drivers/staging/avalon-drv/avalon-drv-dev.c   | 193 ++
 drivers/staging/avalon-drv/avalon-drv-ioctl.c | 137 
 drivers/staging/avalon-drv/avalon-drv-ioctl.h |  12 +
 drivers/staging/avalon-drv/avalon-drv-mmap.c  |  93 +++
 drivers/staging/avalon-drv/avalon-drv-mmap.h  |  12 +
 .../staging/avalon-drv/avalon-drv-sg-buf.c| 132 
 .../staging/avalon-drv/avalon-drv-sg-buf.h|  26 +
 drivers/staging/avalon-drv/avalon-drv-util.c  |  54 ++
 drivers/staging/avalon-drv/avalon-drv-util.h  |  12 +
 drivers/staging/avalon-drv/avalon-drv-xfer.c  | 655 ++
 drivers/staging/avalon-drv/avalon-drv-xfer.h  |  24 +
 drivers/staging/avalon-drv/avalon-drv.h   |  22 +
 include/linux/avalon-dma-hw.h |  72 ++
 include/linux/avalon-dma.h|  68 ++
 include/uapi/linux/avalon-drv-ioctl.h |  30 +
 27 files changed, 2571 insertions(+)
 create mode 100644 drivers/staging/avalon-dma/Kconfig
 create mode 100644 drivers/staging/avalon-dma/Makefile
 create mode 100644 drivers/staging/avalon-dma/avalon-dma-core.c
 create mode 100644 drivers/staging/avalon-dma/avalon-dma-core.h
 create mode 100644 drivers/staging/avalon-dma/avalon-dma-interrupt.c
 create mode 100644 drivers/staging/avalon-dma/avalon-dma-interrupt.h
 create mode 100644 drivers/staging/avalon-dma/avalon-dma-util.c
 create mode 100644 drivers/staging/avalon-dma/avalon-dma-util.h
 create mode 100644 drivers/staging/avalon-drv/Kconfig
 create mode 100644 drivers/staging/avalon-drv/Makefile
 create mode 100644 drivers/staging/avalon-drv/avalon-drv-dev.c
 create mode 100644 drivers/staging/avalon-drv/avalon-drv-ioctl.c
 create mode 100644 drivers/staging/avalon-drv/avalon-drv-ioctl.h
 create mode 100644 drivers/staging/avalon-drv/avalon-drv-mmap.c
 create mode 100644 drivers/staging/avalon-drv/avalon-drv-mmap.h
 create mode 100644 drivers/staging/avalon-drv/avalon-drv-sg-buf.c
 create mode 100644 drivers/staging/avalon-drv/avalon-drv-sg-buf.h
 create mode 100644 drivers/staging/avalon-drv/avalon-drv-util.c
 create mode 100644 drivers/staging/avalon-drv/avalon-drv-util.h
 create mode 100644 drivers/staging/avalon-drv/aval

[PATCH RFC 2/2] staging: avalon-drv: Avalon DMA driver

2019-09-19 Thread Alexander Gordeev
This is sample implementation of a driver that uses "avalon-dma"
driver interface to perform data transfers between on-chip and
system memory in devices using Avalon-MM DMA Interface for PCIe
design.

Companion user-level tool could be found at
g...@github.com:a-gordeev/avalon-drv-tool.git

CC: Michael Chen 
CC: de...@driverdev.osuosl.org
CC: dmaeng...@vger.kernel.org

Signed-off-by: Alexander Gordeev 
---
 drivers/staging/Kconfig   |   2 +
 drivers/staging/Makefile  |   1 +
 drivers/staging/avalon-drv/Kconfig|  34 +
 drivers/staging/avalon-drv/Makefile   |  14 +
 drivers/staging/avalon-drv/avalon-drv-dev.c   | 193 ++
 drivers/staging/avalon-drv/avalon-drv-ioctl.c | 137 
 drivers/staging/avalon-drv/avalon-drv-ioctl.h |  12 +
 drivers/staging/avalon-drv/avalon-drv-mmap.c  |  93 +++
 drivers/staging/avalon-drv/avalon-drv-mmap.h  |  12 +
 .../staging/avalon-drv/avalon-drv-sg-buf.c| 132 
 .../staging/avalon-drv/avalon-drv-sg-buf.h|  26 +
 drivers/staging/avalon-drv/avalon-drv-util.c  |  54 ++
 drivers/staging/avalon-drv/avalon-drv-util.h  |  12 +
 drivers/staging/avalon-drv/avalon-drv-xfer.c  | 655 ++
 drivers/staging/avalon-drv/avalon-drv-xfer.h  |  24 +
 drivers/staging/avalon-drv/avalon-drv.h   |  22 +
 include/uapi/linux/avalon-drv-ioctl.h |  30 +
 17 files changed, 1453 insertions(+)
 create mode 100644 drivers/staging/avalon-drv/Kconfig
 create mode 100644 drivers/staging/avalon-drv/Makefile
 create mode 100644 drivers/staging/avalon-drv/avalon-drv-dev.c
 create mode 100644 drivers/staging/avalon-drv/avalon-drv-ioctl.c
 create mode 100644 drivers/staging/avalon-drv/avalon-drv-ioctl.h
 create mode 100644 drivers/staging/avalon-drv/avalon-drv-mmap.c
 create mode 100644 drivers/staging/avalon-drv/avalon-drv-mmap.h
 create mode 100644 drivers/staging/avalon-drv/avalon-drv-sg-buf.c
 create mode 100644 drivers/staging/avalon-drv/avalon-drv-sg-buf.h
 create mode 100644 drivers/staging/avalon-drv/avalon-drv-util.c
 create mode 100644 drivers/staging/avalon-drv/avalon-drv-util.h
 create mode 100644 drivers/staging/avalon-drv/avalon-drv-xfer.c
 create mode 100644 drivers/staging/avalon-drv/avalon-drv-xfer.h
 create mode 100644 drivers/staging/avalon-drv/avalon-drv.h
 create mode 100644 include/uapi/linux/avalon-drv-ioctl.h

diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 31c732ececd1..6a4e9fdae9f6 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -122,4 +122,6 @@ source "drivers/staging/isdn/Kconfig"
 
 source "drivers/staging/avalon-dma/Kconfig"
 
+source "drivers/staging/avalon-drv/Kconfig"
+
 endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index eb974cac85d3..e09e1aea1506 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -51,3 +51,4 @@ obj-$(CONFIG_FIELDBUS_DEV) += fieldbus/
 obj-$(CONFIG_KPC2000)  += kpc2000/
 obj-$(CONFIG_ISDN_CAPI)+= isdn/
 obj-$(CONFIG_AVALON_DMA)   += avalon-dma/
+obj-$(CONFIG_AVALON_DRV)   += avalon-drv/
diff --git a/drivers/staging/avalon-drv/Kconfig 
b/drivers/staging/avalon-drv/Kconfig
new file mode 100644
index ..18c43a65b6f5
--- /dev/null
+++ b/drivers/staging/avalon-drv/Kconfig
@@ -0,0 +1,34 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Avalon DMA driver
+#
+# Author: Alexander Gordeev 
+#
+config AVALON_DRV
+   depends on AVALON_DMA
+   tristate "Avalon DMA driver"
+   help
+ This selects a driver for Avalon DMA
+
+config AVALON_DRV_PCI_VENDOR_ID
+   hex "PCI vendor ID"
+   default "0x1172"
+
+config AVALON_DRV_PCI_DEVICE_ID
+   hex "PCI device ID"
+   default "0xe003"
+
+config AVALON_DRV_PCI_BAR
+   int "PCI device BAR the Avalon DMA controller is mapped to"
+   range 0 5
+   default 0
+
+config AVALON_DRV_PCI_MSI_COUNT_ORDER
+   int "Count of MSIs the PCI device provides (order)"
+   range 0 5
+   default 5
+
+config AVALON_DRV_PCI_MSI_VECTOR
+   int "MSI vector the Avalon DMA controller uses in multi-MSI mode"
+   range 0 31
+   default 0
diff --git a/drivers/staging/avalon-drv/Makefile 
b/drivers/staging/avalon-drv/Makefile
new file mode 100644
index ..2e0f5f46488e
--- /dev/null
+++ b/drivers/staging/avalon-drv/Makefile
@@ -0,0 +1,14 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Avalon DMA driver
+#
+# Author: Alexander Gordeev 
+#
+obj-$(CONFIG_AVALON_DRV)   += avalon-drv.o
+
+avalon-drv-objs := avalon-drv-dev.o \
+   avalon-drv-ioctl.o \
+   avalon-drv-mmap.o \
+   avalon-drv-sg-buf.o \
+   avalon-drv-xfer.o \
+   avalon-drv-util.o
diff --git a/drivers/staging/avalon-drv/avalon-drv-dev.c 
b/drivers/staging/avalon-drv/aval