Re: [PATCH v5 1/4] mfd: add support for Diolan DLN-2 devices

2014-09-25 Thread Octavian Purdila
On Wed, Sep 24, 2014 at 6:22 PM, Octavian Purdila
octavian.purd...@intel.com wrote:
 On Wed, Sep 24, 2014 at 6:07 PM, Johan Hovold jo...@kernel.org wrote:
 On Wed, Sep 24, 2014 at 05:54:15PM +0300, Octavian Purdila wrote:
 On Wed, Sep 24, 2014 at 4:54 PM, Johan Hovold jo...@kernel.org wrote:
  On Wed, Sep 24, 2014 at 04:36:22PM +0300, Octavian Purdila wrote:
  On Wed, Sep 24, 2014 at 1:48 PM, Johan Hovold jo...@kernel.org wrote:
   On Fri, Sep 19, 2014 at 11:22:42PM +0300, Octavian Purdila wrote:
 
  snip
 
   + * dln2_dev.mod_rx_slots and then the echo header field to index the
   + * slots field and find the receive context for a particular
   + * request.
   + */
   +struct dln2_mod_rx_slots {
   + /* RX slots bitmap */
   + unsigned long bmap;
   +
   + /* used to wait for a free RX slot */
   + wait_queue_head_t wq;
   +
   + /* used to wait for an RX operation to complete */
   + struct dln2_rx_context slots[DLN2_MAX_RX_SLOTS];
   +
   + /* device has been disconnected */
   + bool disconnected;
  
   This belongs in the dln2_dev struct.
  
   I think you're overcomplicating the disconnect handling by intertwining
   it with your slots.
  
   Add a lock, an active-transfer counter, a disconnected flag, and a wait
   queue to struct dln2_dev.
  
 
  I agree that disconnected is better suited in dln2_dev.
 
  However, I don't think that we need the active-transfer counter and a
  new wait queue. We can simply use the existing waiting queues and the
  implicit alloc_rx_slot()/free_rx_slot() calls to see if we are still
  waiting for I/O.
 
  Just because you can reuse them doesn't mean it's a good idea. By
  separating a generic disconnect solution from your custom slot
  implementation we get something that is way easier to verify for
  correctness and that could also be reused in other drivers.

 Maybe I miss-understood what you are proposing, let me try to
 summarize it to see if I got it right.

 You are suggesting to add a counter, increment it in alloc_rx_slot(),
 decrement it in free_rx_slot().

 No increment it at the start of _dln2_transfer, and decrement it before
 returning from that function.

 Then add a new waitqueue in dln2_dev
 and in free_rx_slot() wake it up while in disconnect do a wait_event()
 on it and check for the counter.

 Where you also wake the disconnect (or wait-until-sent) wait queue.

 Also, alloc_rx_slot() should fail if
 the disconnect flag is set.

 That is not required, but you can bail out early after alloc_rx_slot if
 the disconnect flag is set (no locking).

 In this case we are still coupled to the slots implementation, in the
 sense that you would need to understand the slots implementation to
 understand how the disconnect works. We are also doing two wake-up
 operations which I find redundant and which does not add much value in
 clarity (since we still need to wake-up all completions for each
 handle).

 I do agree that using a counter instead of checking the bitmaps is
 cleaner though.

 You only need to the wake up if disconnected is set when returning from
 _dln2_transfer.

 Sure, the optimisation bit -- to abort any ongoing transfer -- still
 requires some insight into the slot implementation.

 But this way everything disconnect related (correctness-wise) is
 isolated to _dln2_transfer and dln2_disconnect.


 OK, I see what you mean now. I'll give it a try and will follow up
 with a new patch set.


Johan, I think we don't really need the spinlock, the disconnect flag
and an atomic counter should work. Do you see any issues with that?
--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v5 1/4] mfd: add support for Diolan DLN-2 devices

2014-09-25 Thread Johan Hovold
On Thu, Sep 25, 2014 at 01:25:24PM +0300, Octavian Purdila wrote:

 Johan, I think we don't really need the spinlock, the disconnect flag
 and an atomic counter should work. Do you see any issues with that?

No, you need to test and increment atomically so the lock is needed.

Consider what could happen if you get a disconnect after testing but
before incrementing.

Johan
--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v5 1/4] mfd: add support for Diolan DLN-2 devices

2014-09-25 Thread Octavian Purdila
On Thu, Sep 25, 2014 at 1:30 PM, Johan Hovold jo...@kernel.org wrote:
 On Thu, Sep 25, 2014 at 01:25:24PM +0300, Octavian Purdila wrote:

 Johan, I think we don't really need the spinlock, the disconnect flag
 and an atomic counter should work. Do you see any issues with that?

 No, you need to test and increment atomically so the lock is needed.

 Consider what could happen if you get a disconnect after testing but
 before incrementing.


I am still not seeing the problem. We would continue with the
increment, we will try to send which will fail and go on the error
path where we will decrement and wake_up. What am I missing?
--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v5 1/4] mfd: add support for Diolan DLN-2 devices

2014-09-25 Thread Johan Hovold
On Thu, Sep 25, 2014 at 01:41:16PM +0300, Octavian Purdila wrote:
 On Thu, Sep 25, 2014 at 1:30 PM, Johan Hovold jo...@kernel.org wrote:
  On Thu, Sep 25, 2014 at 01:25:24PM +0300, Octavian Purdila wrote:
 
  Johan, I think we don't really need the spinlock, the disconnect flag
  and an atomic counter should work. Do you see any issues with that?
 
  No, you need to test and increment atomically so the lock is needed.
 
  Consider what could happen if you get a disconnect after testing but
  before incrementing.
 
 I am still not seeing the problem. We would continue with the
 increment, we will try to send which will fail and go on the error
 path where we will decrement and wake_up. What am I missing?

The whole point of the counter and flag is to make sure that no
transfers are started after the flag is set. If you remove the lock you
cannot guarantee that.

Disconnect sets the flag (after you test it in transfer() but before
incrementing the counter), checks the counter which is 0 and proceeds
with deregistration and deallocation. Then transfer() gets to run...

Johan
--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v5 1/4] mfd: add support for Diolan DLN-2 devices

2014-09-24 Thread Johan Hovold
On Fri, Sep 19, 2014 at 11:22:42PM +0300, Octavian Purdila wrote:
 This patch implements the USB part of the Diolan USB-I2C/SPI/GPIO
 Master Adapter DLN-2. Details about the device can be found here:
 
 https://www.diolan.com/i2c/i2c_interface.html.
 
 Information about the USB protocol can be found in the Programmer's
 Reference Manual [1], see section 1.7.
 
 Because the hardware has a single transmit endpoint and a single
 receive endpoint the communication between the various DLN2 drivers
 and the hardware will be muxed/demuxed by this driver.
 
 Each DLN2 module will be identified by the handle field within the DLN2
 message header. If a DLN2 module issues multiple commands in parallel
 they will be identified by the echo counter field in the message header.
 
 The DLN2 modules can use the dln2_transfer() function to issue a
 command and wait for its response. They can also register a callback
 that is going to be called when a specific event id is generated by
 the device (e.g. GPIO interrupts). The device uses handle 0 for
 sending events.
 
 [1] https://www.diolan.com/downloads/dln-api-manual.pdf
 
 Signed-off-by: Octavian Purdila octavian.purd...@intel.com
 ---
  drivers/mfd/Kconfig  |   9 +
  drivers/mfd/Makefile |   1 +
  drivers/mfd/dln2.c   | 758 
 +++
  include/linux/mfd/dln2.h |  67 +
  4 files changed, 835 insertions(+)
  create mode 100644 drivers/mfd/dln2.c
  create mode 100644 include/linux/mfd/dln2.h
 
 diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
 index de5abf2..7bcf895 100644
 --- a/drivers/mfd/Kconfig
 +++ b/drivers/mfd/Kconfig
 @@ -183,6 +183,15 @@ config MFD_DA9063
 Additional drivers must be enabled in order to use the functionality
 of the device.
  
 +config MFD_DLN2
 + tristate Diolan DLN2 support
 + select MFD_CORE
 + depends on USB
 + help
 +   This adds support for Diolan USB-I2C/SPI/GPIO Master Adapter DLN-2.
 +   Additional drivers must be enabled in order to use the functionality
 +   of the device.
 +
  config MFD_MC13XXX
   tristate
   depends on (SPI_MASTER || I2C)
 diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
 index f001487..591988d 100644
 --- a/drivers/mfd/Makefile
 +++ b/drivers/mfd/Makefile
 @@ -169,6 +169,7 @@ obj-$(CONFIG_MFD_AS3711)  += as3711.o
  obj-$(CONFIG_MFD_AS3722) += as3722.o
  obj-$(CONFIG_MFD_STW481X)+= stw481x.o
  obj-$(CONFIG_MFD_IPAQ_MICRO) += ipaq-micro.o
 +obj-$(CONFIG_MFD_DLN2)   += dln2.o
  
  intel-soc-pmic-objs  := intel_soc_pmic_core.o intel_soc_pmic_crc.o
  obj-$(CONFIG_INTEL_SOC_PMIC) += intel-soc-pmic.o
 diff --git a/drivers/mfd/dln2.c b/drivers/mfd/dln2.c
 new file mode 100644
 index 000..36c53cd
 --- /dev/null
 +++ b/drivers/mfd/dln2.c
 @@ -0,0 +1,758 @@
 +/*
 + * Driver for the Diolan DLN-2 USB adapter
 + *
 + * Copyright (c) 2014 Intel Corporation
 + *
 + * Derived from:
 + *  i2c-diolan-u2c.c
 + *  Copyright (c) 2010-2011 Ericsson AB
 + *
 + * 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, version 2.
 + */
 +
 +#include linux/kernel.h
 +#include linux/module.h
 +#include linux/types.h
 +#include linux/slab.h
 +#include linux/usb.h
 +#include linux/i2c.h
 +#include linux/mutex.h
 +#include linux/platform_device.h
 +#include linux/mfd/core.h
 +#include linux/mfd/dln2.h
 +#include linux/rculist.h
 +
 +struct dln2_header {
 + __le16 size;
 + __le16 id;
 + __le16 echo;
 + __le16 handle;
 +} __packed;
 +
 +struct dln2_response {
 + struct dln2_header hdr;
 + __le16 result;
 +} __packed;
 +
 +#define DLN2_GENERIC_MODULE_ID   0x00
 +#define DLN2_GENERIC_CMD(cmd)DLN2_CMD(cmd, 
 DLN2_GENERIC_MODULE_ID)
 +#define CMD_GET_DEVICE_VER   DLN2_GENERIC_CMD(0x30)
 +#define CMD_GET_DEVICE_SNDLN2_GENERIC_CMD(0x31)
 +
 +#define DLN2_HW_ID   0x200
 +#define DLN2_USB_TIMEOUT 200 /* in ms */
 +#define DLN2_MAX_RX_SLOTS16
 +#define DLN2_MAX_URBS16
 +#define DLN2_RX_BUF_SIZE 512
 +
 +#define DLN2_HANDLE_EVENT0
 +#define DLN2_HANDLE_CTRL 1
 +#define DLN2_HANDLE_GPIO 2
 +#define DLN2_HANDLE_I2C  3
 +#define DLN2_HANDLES 4

This should be an enum.

 +
 +
 +/*
 + * Receive context used between the receive demultiplexer and the
 + * transfer routine. While sending a request the transfer routine
 + * will look for a free receive context and use it to wait for a
 + * response and to receive the URB and thus the response data.
 + */
 +struct dln2_rx_context {
 + /* completion used to wait a response */

wait for

 + struct completion done;
 +
 + /* if non-NULL the URB contains the response */
 + struct urb *urb;
 +
 + /* if true then 

Re: [PATCH v5 1/4] mfd: add support for Diolan DLN-2 devices

2014-09-24 Thread Octavian Purdila
On Wed, Sep 24, 2014 at 1:48 PM, Johan Hovold jo...@kernel.org wrote:
 On Fri, Sep 19, 2014 at 11:22:42PM +0300, Octavian Purdila wrote:

snip

 + * dln2_dev.mod_rx_slots and then the echo header field to index the
 + * slots field and find the receive context for a particular
 + * request.
 + */
 +struct dln2_mod_rx_slots {
 + /* RX slots bitmap */
 + unsigned long bmap;
 +
 + /* used to wait for a free RX slot */
 + wait_queue_head_t wq;
 +
 + /* used to wait for an RX operation to complete */
 + struct dln2_rx_context slots[DLN2_MAX_RX_SLOTS];
 +
 + /* device has been disconnected */
 + bool disconnected;

 This belongs in the dln2_dev struct.

 I think you're overcomplicating the disconnect handling by intertwining
 it with your slots.

 Add a lock, an active-transfer counter, a disconnected flag, and a wait
 queue to struct dln2_dev.


I agree that disconnected is better suited in dln2_dev.

However, I don't think that we need the active-transfer counter and a
new wait queue. We can simply use the existing waiting queues and the
implicit alloc_rx_slot()/free_rx_slot() calls to see if we are still
waiting for I/O.

snip

 +
 +static int _dln2_transfer(struct dln2_dev *dln2, u16 handle, u16 cmd,
 +   const void *obuf, unsigned obuf_len,
 +   void *ibuf, unsigned *ibuf_len)
 +{
 + int ret = 0;
 + u16 result;
 + int rx_slot;
 + unsigned long flags;
 + struct dln2_response *rsp;
 + struct dln2_rx_context *rxc;
 + struct device *dev;
 + const int timeout = DLN2_USB_TIMEOUT * HZ / 1000;
 + struct dln2_mod_rx_slots *rxs = dln2-mod_rx_slots[handle];
 +

 Check the disconnected flag before incrementing the transfer count
 (while holding the device lock) here. Then decrement counter before
 returning and wake up an waiters if disconnected below.

 That is sufficient to implement wait-until-io-has-completed. Anything
 else you do below and in the helper functions is only to speed things
 up at disconnect (and can be done without locking the device).

 + rx_slot = alloc_rx_slot(rxs);
 + if (rx_slot  0)
 + return rx_slot;
 +
 + dev = dln2-interface-dev;
 +
 + ret = dln2_send_wait(dln2, handle, cmd, rx_slot, obuf, obuf_len);
 + if (ret  0) {
 + free_rx_slot(dln2, rxs, rx_slot);

 goto out_free_rx_slot

 + dev_err(dev, USB write failed: %d, ret);
 + return ret;
 + }
 +
 + rxc = rxs-slots[rx_slot];
 +
 + ret = wait_for_completion_interruptible_timeout(rxc-done, timeout);
 + if (ret = 0) {
 + if (!ret)
 + ret = -ETIMEDOUT;
 + goto out_free_rx_slot;
 + }
 +
 + spin_lock_irqsave(rxs-lock, flags);
 +
 + if (!rxc-urb) {

 Just check the disconnected flag directly here. Locking not needed (see
 below).


I think we need the check here for the case when we cancel the
completion and no response has been received yet. In that case rx-urb
will be NULL (even if we remove the rx-urb = NULL statement in
dln2_stop).

 + ret = -ECONNRESET;

 -ENODEV

OK.


 + spin_unlock_irqrestore(rxs-lock, flags);
 + goto out_free_rx_slot;
 + }
 +
 + /* if we got here we know that the response header has been checked */
 + rsp = rxc-urb-transfer_buffer;
 +
 + spin_unlock_irqrestore(rxs-lock, flags);
 +
 +
 +static void dln2_stop(struct dln2_dev *dln2)
 +{
 + int i, j;
 +
 + for (i = 0; i  DLN2_HANDLES; i++) {
 + struct dln2_mod_rx_slots *rxs = dln2-mod_rx_slots[i];
 + unsigned long flags;
 +
 + spin_lock_irqsave(rxs-lock, flags);
 +
 + /* fail further alloc_rx_slot calls */
 + rxs-disconnected = true;
 +
 + /* cancel all response waiters */
 + for (j = 0; j  DLN2_MAX_RX_SLOTS; j++) {
 + struct dln2_rx_context *rxc = rxs-slots[j];
 +
 + if (rxc-connected) {
 + rxc-urb = NULL;

 Don't overload the meaning of urb. Check the disconnected flag were
 needed.

 Also what would prevent a racing completion handler from setting
 rxc-urb again when you release the lock below?


That should not be an issue, in that case _dln2_transfer will complete
successfully. But you are right, we don't need to set rxc-urb to NULL
here.

 + complete(rxc-done);
 + }
 + }
 + spin_unlock_irqrestore(rxs-lock, flags);
 +
 + /* wait for callers to release all rx_slots */
 + wait_event(rxs-wq, dln2_all_rx_slots_free(rxs));
 + }
 +}
 +
 +static void dln2_disconnect(struct usb_interface *interface)
 +{
 + struct dln2_dev *dln2 = usb_get_intfdata(interface);
 +

 First set the disconnected flag directly here to prevent any new
 transfers from starting.

 + dln2_stop(dln2);

 Then do all the completions (to speed things up 

Re: [PATCH v5 1/4] mfd: add support for Diolan DLN-2 devices

2014-09-24 Thread Johan Hovold
On Wed, Sep 24, 2014 at 04:36:22PM +0300, Octavian Purdila wrote:
 On Wed, Sep 24, 2014 at 1:48 PM, Johan Hovold jo...@kernel.org wrote:
  On Fri, Sep 19, 2014 at 11:22:42PM +0300, Octavian Purdila wrote:
 
 snip
 
  + * dln2_dev.mod_rx_slots and then the echo header field to index the
  + * slots field and find the receive context for a particular
  + * request.
  + */
  +struct dln2_mod_rx_slots {
  + /* RX slots bitmap */
  + unsigned long bmap;
  +
  + /* used to wait for a free RX slot */
  + wait_queue_head_t wq;
  +
  + /* used to wait for an RX operation to complete */
  + struct dln2_rx_context slots[DLN2_MAX_RX_SLOTS];
  +
  + /* device has been disconnected */
  + bool disconnected;
 
  This belongs in the dln2_dev struct.
 
  I think you're overcomplicating the disconnect handling by intertwining
  it with your slots.
 
  Add a lock, an active-transfer counter, a disconnected flag, and a wait
  queue to struct dln2_dev.
 
 
 I agree that disconnected is better suited in dln2_dev.
 
 However, I don't think that we need the active-transfer counter and a
 new wait queue. We can simply use the existing waiting queues and the
 implicit alloc_rx_slot()/free_rx_slot() calls to see if we are still
 waiting for I/O.

Just because you can reuse them doesn't mean it's a good idea. By
separating a generic disconnect solution from your custom slot
implementation we get something that is way easier to verify for
correctness and that could also be reused in other drivers.

 snip
 
  +
  +static int _dln2_transfer(struct dln2_dev *dln2, u16 handle, u16 cmd,
  +   const void *obuf, unsigned obuf_len,
  +   void *ibuf, unsigned *ibuf_len)
  +{
  + int ret = 0;
  + u16 result;
  + int rx_slot;
  + unsigned long flags;
  + struct dln2_response *rsp;
  + struct dln2_rx_context *rxc;
  + struct device *dev;
  + const int timeout = DLN2_USB_TIMEOUT * HZ / 1000;
  + struct dln2_mod_rx_slots *rxs = dln2-mod_rx_slots[handle];
  +
 
  Check the disconnected flag before incrementing the transfer count
  (while holding the device lock) here. Then decrement counter before
  returning and wake up an waiters if disconnected below.
 
  That is sufficient to implement wait-until-io-has-completed. Anything
  else you do below and in the helper functions is only to speed things
  up at disconnect (and can be done without locking the device).
 
  + rx_slot = alloc_rx_slot(rxs);
  + if (rx_slot  0)
  + return rx_slot;
  +
  + dev = dln2-interface-dev;
  +
  + ret = dln2_send_wait(dln2, handle, cmd, rx_slot, obuf, obuf_len);
  + if (ret  0) {
  + free_rx_slot(dln2, rxs, rx_slot);
 
  goto out_free_rx_slot
 
  + dev_err(dev, USB write failed: %d, ret);
  + return ret;
  + }
  +
  + rxc = rxs-slots[rx_slot];
  +
  + ret = wait_for_completion_interruptible_timeout(rxc-done, timeout);
  + if (ret = 0) {
  + if (!ret)
  + ret = -ETIMEDOUT;
  + goto out_free_rx_slot;
  + }
  +
  + spin_lock_irqsave(rxs-lock, flags);
  +
  + if (!rxc-urb) {
 
  Just check the disconnected flag directly here. Locking not needed (see
  below).
 
 
 I think we need the check here for the case when we cancel the
 completion and no response has been received yet. In that case rx-urb
 will be NULL (even if we remove the rx-urb = NULL statement in
 dln2_stop).

But the disconnect flag will also be set and makes it more obvious what
is going on.

[...]

  +static void dln2_disconnect(struct usb_interface *interface)
  +{
  + struct dln2_dev *dln2 = usb_get_intfdata(interface);
  +
 
  First set the disconnected flag directly here to prevent any new
  transfers from starting.
 
  + dln2_stop(dln2);
 
  Then do all the completions (to speed things up somewhat).
 
  Then wait for the transfer counter to reach 0.
 
  + mfd_remove_devices(interface-dev);
  + dln2_free(dln2);
  +}
  +
 
 As I mentioned above, I don't think we need the transfer counter, we
 can rely on the slots bitmap. Yes, a counter is simpler but it also
 requires adding a new waiting queue and a new lock.

That's really not a big deal. See above.

Johan
--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v5 1/4] mfd: add support for Diolan DLN-2 devices

2014-09-24 Thread Johan Hovold
On Wed, Sep 24, 2014 at 05:54:15PM +0300, Octavian Purdila wrote:
 On Wed, Sep 24, 2014 at 4:54 PM, Johan Hovold jo...@kernel.org wrote:
  On Wed, Sep 24, 2014 at 04:36:22PM +0300, Octavian Purdila wrote:
  On Wed, Sep 24, 2014 at 1:48 PM, Johan Hovold jo...@kernel.org wrote:
   On Fri, Sep 19, 2014 at 11:22:42PM +0300, Octavian Purdila wrote:
 
  snip
 
   + * dln2_dev.mod_rx_slots and then the echo header field to index the
   + * slots field and find the receive context for a particular
   + * request.
   + */
   +struct dln2_mod_rx_slots {
   + /* RX slots bitmap */
   + unsigned long bmap;
   +
   + /* used to wait for a free RX slot */
   + wait_queue_head_t wq;
   +
   + /* used to wait for an RX operation to complete */
   + struct dln2_rx_context slots[DLN2_MAX_RX_SLOTS];
   +
   + /* device has been disconnected */
   + bool disconnected;
  
   This belongs in the dln2_dev struct.
  
   I think you're overcomplicating the disconnect handling by intertwining
   it with your slots.
  
   Add a lock, an active-transfer counter, a disconnected flag, and a wait
   queue to struct dln2_dev.
  
 
  I agree that disconnected is better suited in dln2_dev.
 
  However, I don't think that we need the active-transfer counter and a
  new wait queue. We can simply use the existing waiting queues and the
  implicit alloc_rx_slot()/free_rx_slot() calls to see if we are still
  waiting for I/O.
 
  Just because you can reuse them doesn't mean it's a good idea. By
  separating a generic disconnect solution from your custom slot
  implementation we get something that is way easier to verify for
  correctness and that could also be reused in other drivers.
 
 Maybe I miss-understood what you are proposing, let me try to
 summarize it to see if I got it right.
 
 You are suggesting to add a counter, increment it in alloc_rx_slot(),
 decrement it in free_rx_slot().

No increment it at the start of _dln2_transfer, and decrement it before
returning from that function.

 Then add a new waitqueue in dln2_dev
 and in free_rx_slot() wake it up while in disconnect do a wait_event()
 on it and check for the counter.

Where you also wake the disconnect (or wait-until-sent) wait queue.

 Also, alloc_rx_slot() should fail if
 the disconnect flag is set.

That is not required, but you can bail out early after alloc_rx_slot if
the disconnect flag is set (no locking).

 In this case we are still coupled to the slots implementation, in the
 sense that you would need to understand the slots implementation to
 understand how the disconnect works. We are also doing two wake-up
 operations which I find redundant and which does not add much value in
 clarity (since we still need to wake-up all completions for each
 handle).

 I do agree that using a counter instead of checking the bitmaps is
 cleaner though.

You only need to the wake up if disconnected is set when returning from
_dln2_transfer.

Sure, the optimisation bit -- to abort any ongoing transfer -- still
requires some insight into the slot implementation.

But this way everything disconnect related (correctness-wise) is
isolated to _dln2_transfer and dln2_disconnect.

Johan
--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH v5 1/4] mfd: add support for Diolan DLN-2 devices

2014-09-24 Thread Octavian Purdila
On Wed, Sep 24, 2014 at 6:07 PM, Johan Hovold jo...@kernel.org wrote:
 On Wed, Sep 24, 2014 at 05:54:15PM +0300, Octavian Purdila wrote:
 On Wed, Sep 24, 2014 at 4:54 PM, Johan Hovold jo...@kernel.org wrote:
  On Wed, Sep 24, 2014 at 04:36:22PM +0300, Octavian Purdila wrote:
  On Wed, Sep 24, 2014 at 1:48 PM, Johan Hovold jo...@kernel.org wrote:
   On Fri, Sep 19, 2014 at 11:22:42PM +0300, Octavian Purdila wrote:
 
  snip
 
   + * dln2_dev.mod_rx_slots and then the echo header field to index the
   + * slots field and find the receive context for a particular
   + * request.
   + */
   +struct dln2_mod_rx_slots {
   + /* RX slots bitmap */
   + unsigned long bmap;
   +
   + /* used to wait for a free RX slot */
   + wait_queue_head_t wq;
   +
   + /* used to wait for an RX operation to complete */
   + struct dln2_rx_context slots[DLN2_MAX_RX_SLOTS];
   +
   + /* device has been disconnected */
   + bool disconnected;
  
   This belongs in the dln2_dev struct.
  
   I think you're overcomplicating the disconnect handling by intertwining
   it with your slots.
  
   Add a lock, an active-transfer counter, a disconnected flag, and a wait
   queue to struct dln2_dev.
  
 
  I agree that disconnected is better suited in dln2_dev.
 
  However, I don't think that we need the active-transfer counter and a
  new wait queue. We can simply use the existing waiting queues and the
  implicit alloc_rx_slot()/free_rx_slot() calls to see if we are still
  waiting for I/O.
 
  Just because you can reuse them doesn't mean it's a good idea. By
  separating a generic disconnect solution from your custom slot
  implementation we get something that is way easier to verify for
  correctness and that could also be reused in other drivers.

 Maybe I miss-understood what you are proposing, let me try to
 summarize it to see if I got it right.

 You are suggesting to add a counter, increment it in alloc_rx_slot(),
 decrement it in free_rx_slot().

 No increment it at the start of _dln2_transfer, and decrement it before
 returning from that function.

 Then add a new waitqueue in dln2_dev
 and in free_rx_slot() wake it up while in disconnect do a wait_event()
 on it and check for the counter.

 Where you also wake the disconnect (or wait-until-sent) wait queue.

 Also, alloc_rx_slot() should fail if
 the disconnect flag is set.

 That is not required, but you can bail out early after alloc_rx_slot if
 the disconnect flag is set (no locking).

 In this case we are still coupled to the slots implementation, in the
 sense that you would need to understand the slots implementation to
 understand how the disconnect works. We are also doing two wake-up
 operations which I find redundant and which does not add much value in
 clarity (since we still need to wake-up all completions for each
 handle).

 I do agree that using a counter instead of checking the bitmaps is
 cleaner though.

 You only need to the wake up if disconnected is set when returning from
 _dln2_transfer.

 Sure, the optimisation bit -- to abort any ongoing transfer -- still
 requires some insight into the slot implementation.

 But this way everything disconnect related (correctness-wise) is
 isolated to _dln2_transfer and dln2_disconnect.


OK, I see what you mean now. I'll give it a try and will follow up
with a new patch set.

Oh, and thanks for yet another review, it has been very educational to
me just like the rest  :)
--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html