1. 13 3月, 2018 6 次提交
  2. 13 12月, 2017 1 次提交
    • D
      usb: dwc2: host: Don't retry NAKed transactions right away · 38d2b5fb
      Douglas Anderson 提交于
      On rk3288-veyron devices on Chrome OS it was found that plugging in an
      Arduino-based USB device could cause the system to lockup, especially
      if the CPU Frequency was at one of the slower operating points (like
      100 MHz / 200 MHz).
      
      Upon tracing, I found that the following was happening:
      * The USB device (full speed) was connected to a high speed hub and
        then to the rk3288.  Thus, we were dealing with split transactions,
        which is all handled in software on dwc2.
      * Userspace was initiating a BULK IN transfer
      * When we sent the SSPLIT (to start the split transaction), we got an
        ACK.  Good.  Then we issued the CSPLIT.
      * When we sent the CSPLIT, we got back a NAK.  We immediately (from
        the interrupt handler) started to retry and sent another SSPLIT.
      * The device kept NAKing our CSPLIT, so we kept ping-ponging between
        sending a SSPLIT and a CSPLIT, each time sending from the interrupt
        handler.
      * The handling of the interrupts was (because of the low CPU speed and
        the inefficiency of the dwc2 interrupt handler) was actually taking
        _longer_ than it took the other side to send the ACK/NAK.  Thus we
        were _always_ in the USB interrupt routine.
      * The fact that USB interrupts were always going off was preventing
        other things from happening in the system.  This included preventing
        the system from being able to transition to a higher CPU frequency.
      
      As I understand it, there is no requirement to retry super quickly
      after a NAK, we just have to retry sometime in the future.  Thus one
      solution to the above is to just add a delay between getting a NAK and
      retrying the transmission.  If this delay is sufficiently long to get
      out of the interrupt routine then the rest of the system will be able
      to make forward progress.  Even a 25 us delay would probably be
      enough, but we'll be extra conservative and try to delay 1 ms (the
      exact amount depends on HZ and the accuracy of the jiffy and how close
      the current jiffy is to ticking, but could be as much as 20 ms or as
      little as 1 ms).
      
      Presumably adding a delay like this could impact the USB throughput,
      so we only add the delay with repeated NAKs.
      
      NOTE: Upon further testing of a pl2303 serial adapter, I found that
      this fix may help with problems there.  Specifically I found that the
      pl2303 serial adapters tend to respond with a NAK when they have
      nothing to say and thus we end with this same sequence.
      Signed-off-by: NDouglas Anderson <dianders@chromium.org>
      Reviewed-by: NJulius Werner <jwerner@chromium.org>
      Tested-by: NStefan Wahren <stefan.wahren@i2se.com>
      Acked-by: NJohn Youn <johnyoun@synopsys.com>
      Signed-off-by: NFelipe Balbi <felipe.balbi@linux.intel.com>
      38d2b5fb
  3. 22 11月, 2017 1 次提交
    • K
      treewide: setup_timer() -> timer_setup() · e99e88a9
      Kees Cook 提交于
      This converts all remaining cases of the old setup_timer() API into using
      timer_setup(), where the callback argument is the structure already
      holding the struct timer_list. These should have no behavioral changes,
      since they just change which pointer is passed into the callback with
      the same available pointers after conversion. It handles the following
      examples, in addition to some other variations.
      
      Casting from unsigned long:
      
          void my_callback(unsigned long data)
          {
              struct something *ptr = (struct something *)data;
          ...
          }
          ...
          setup_timer(&ptr->my_timer, my_callback, ptr);
      
      and forced object casts:
      
          void my_callback(struct something *ptr)
          {
          ...
          }
          ...
          setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr);
      
      become:
      
          void my_callback(struct timer_list *t)
          {
              struct something *ptr = from_timer(ptr, t, my_timer);
          ...
          }
          ...
          timer_setup(&ptr->my_timer, my_callback, 0);
      
      Direct function assignments:
      
          void my_callback(unsigned long data)
          {
              struct something *ptr = (struct something *)data;
          ...
          }
          ...
          ptr->my_timer.function = my_callback;
      
      have a temporary cast added, along with converting the args:
      
          void my_callback(struct timer_list *t)
          {
              struct something *ptr = from_timer(ptr, t, my_timer);
          ...
          }
          ...
          ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback;
      
      And finally, callbacks without a data assignment:
      
          void my_callback(unsigned long data)
          {
          ...
          }
          ...
          setup_timer(&ptr->my_timer, my_callback, 0);
      
      have their argument renamed to verify they're unused during conversion:
      
          void my_callback(struct timer_list *unused)
          {
          ...
          }
          ...
          timer_setup(&ptr->my_timer, my_callback, 0);
      
      The conversion is done with the following Coccinelle script:
      
      spatch --very-quiet --all-includes --include-headers \
      	-I ./arch/x86/include -I ./arch/x86/include/generated \
      	-I ./include -I ./arch/x86/include/uapi \
      	-I ./arch/x86/include/generated/uapi -I ./include/uapi \
      	-I ./include/generated/uapi --include ./include/linux/kconfig.h \
      	--dir . \
      	--cocci-file ~/src/data/timer_setup.cocci
      
      @fix_address_of@
      expression e;
      @@
      
       setup_timer(
      -&(e)
      +&e
       , ...)
      
      // Update any raw setup_timer() usages that have a NULL callback, but
      // would otherwise match change_timer_function_usage, since the latter
      // will update all function assignments done in the face of a NULL
      // function initialization in setup_timer().
      @change_timer_function_usage_NULL@
      expression _E;
      identifier _timer;
      type _cast_data;
      @@
      
      (
      -setup_timer(&_E->_timer, NULL, _E);
      +timer_setup(&_E->_timer, NULL, 0);
      |
      -setup_timer(&_E->_timer, NULL, (_cast_data)_E);
      +timer_setup(&_E->_timer, NULL, 0);
      |
      -setup_timer(&_E._timer, NULL, &_E);
      +timer_setup(&_E._timer, NULL, 0);
      |
      -setup_timer(&_E._timer, NULL, (_cast_data)&_E);
      +timer_setup(&_E._timer, NULL, 0);
      )
      
      @change_timer_function_usage@
      expression _E;
      identifier _timer;
      struct timer_list _stl;
      identifier _callback;
      type _cast_func, _cast_data;
      @@
      
      (
      -setup_timer(&_E->_timer, _callback, _E);
      +timer_setup(&_E->_timer, _callback, 0);
      |
      -setup_timer(&_E->_timer, &_callback, _E);
      +timer_setup(&_E->_timer, _callback, 0);
      |
      -setup_timer(&_E->_timer, _callback, (_cast_data)_E);
      +timer_setup(&_E->_timer, _callback, 0);
      |
      -setup_timer(&_E->_timer, &_callback, (_cast_data)_E);
      +timer_setup(&_E->_timer, _callback, 0);
      |
      -setup_timer(&_E->_timer, (_cast_func)_callback, _E);
      +timer_setup(&_E->_timer, _callback, 0);
      |
      -setup_timer(&_E->_timer, (_cast_func)&_callback, _E);
      +timer_setup(&_E->_timer, _callback, 0);
      |
      -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E);
      +timer_setup(&_E->_timer, _callback, 0);
      |
      -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E);
      +timer_setup(&_E->_timer, _callback, 0);
      |
      -setup_timer(&_E._timer, _callback, (_cast_data)_E);
      +timer_setup(&_E._timer, _callback, 0);
      |
      -setup_timer(&_E._timer, _callback, (_cast_data)&_E);
      +timer_setup(&_E._timer, _callback, 0);
      |
      -setup_timer(&_E._timer, &_callback, (_cast_data)_E);
      +timer_setup(&_E._timer, _callback, 0);
      |
      -setup_timer(&_E._timer, &_callback, (_cast_data)&_E);
      +timer_setup(&_E._timer, _callback, 0);
      |
      -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E);
      +timer_setup(&_E._timer, _callback, 0);
      |
      -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E);
      +timer_setup(&_E._timer, _callback, 0);
      |
      -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E);
      +timer_setup(&_E._timer, _callback, 0);
      |
      -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E);
      +timer_setup(&_E._timer, _callback, 0);
      |
       _E->_timer@_stl.function = _callback;
      |
       _E->_timer@_stl.function = &_callback;
      |
       _E->_timer@_stl.function = (_cast_func)_callback;
      |
       _E->_timer@_stl.function = (_cast_func)&_callback;
      |
       _E._timer@_stl.function = _callback;
      |
       _E._timer@_stl.function = &_callback;
      |
       _E._timer@_stl.function = (_cast_func)_callback;
      |
       _E._timer@_stl.function = (_cast_func)&_callback;
      )
      
      // callback(unsigned long arg)
      @change_callback_handle_cast
       depends on change_timer_function_usage@
      identifier change_timer_function_usage._callback;
      identifier change_timer_function_usage._timer;
      type _origtype;
      identifier _origarg;
      type _handletype;
      identifier _handle;
      @@
      
       void _callback(
      -_origtype _origarg
      +struct timer_list *t
       )
       {
      (
      	... when != _origarg
      	_handletype *_handle =
      -(_handletype *)_origarg;
      +from_timer(_handle, t, _timer);
      	... when != _origarg
      |
      	... when != _origarg
      	_handletype *_handle =
      -(void *)_origarg;
      +from_timer(_handle, t, _timer);
      	... when != _origarg
      |
      	... when != _origarg
      	_handletype *_handle;
      	... when != _handle
      	_handle =
      -(_handletype *)_origarg;
      +from_timer(_handle, t, _timer);
      	... when != _origarg
      |
      	... when != _origarg
      	_handletype *_handle;
      	... when != _handle
      	_handle =
      -(void *)_origarg;
      +from_timer(_handle, t, _timer);
      	... when != _origarg
      )
       }
      
      // callback(unsigned long arg) without existing variable
      @change_callback_handle_cast_no_arg
       depends on change_timer_function_usage &&
                           !change_callback_handle_cast@
      identifier change_timer_function_usage._callback;
      identifier change_timer_function_usage._timer;
      type _origtype;
      identifier _origarg;
      type _handletype;
      @@
      
       void _callback(
      -_origtype _origarg
      +struct timer_list *t
       )
       {
      +	_handletype *_origarg = from_timer(_origarg, t, _timer);
      +
      	... when != _origarg
      -	(_handletype *)_origarg
      +	_origarg
      	... when != _origarg
       }
      
      // Avoid already converted callbacks.
      @match_callback_converted
       depends on change_timer_function_usage &&
                  !change_callback_handle_cast &&
      	    !change_callback_handle_cast_no_arg@
      identifier change_timer_function_usage._callback;
      identifier t;
      @@
      
       void _callback(struct timer_list *t)
       { ... }
      
      // callback(struct something *handle)
      @change_callback_handle_arg
       depends on change_timer_function_usage &&
      	    !match_callback_converted &&
                  !change_callback_handle_cast &&
                  !change_callback_handle_cast_no_arg@
      identifier change_timer_function_usage._callback;
      identifier change_timer_function_usage._timer;
      type _handletype;
      identifier _handle;
      @@
      
       void _callback(
      -_handletype *_handle
      +struct timer_list *t
       )
       {
      +	_handletype *_handle = from_timer(_handle, t, _timer);
      	...
       }
      
      // If change_callback_handle_arg ran on an empty function, remove
      // the added handler.
      @unchange_callback_handle_arg
       depends on change_timer_function_usage &&
      	    change_callback_handle_arg@
      identifier change_timer_function_usage._callback;
      identifier change_timer_function_usage._timer;
      type _handletype;
      identifier _handle;
      identifier t;
      @@
      
       void _callback(struct timer_list *t)
       {
      -	_handletype *_handle = from_timer(_handle, t, _timer);
       }
      
      // We only want to refactor the setup_timer() data argument if we've found
      // the matching callback. This undoes changes in change_timer_function_usage.
      @unchange_timer_function_usage
       depends on change_timer_function_usage &&
                  !change_callback_handle_cast &&
                  !change_callback_handle_cast_no_arg &&
      	    !change_callback_handle_arg@
      expression change_timer_function_usage._E;
      identifier change_timer_function_usage._timer;
      identifier change_timer_function_usage._callback;
      type change_timer_function_usage._cast_data;
      @@
      
      (
      -timer_setup(&_E->_timer, _callback, 0);
      +setup_timer(&_E->_timer, _callback, (_cast_data)_E);
      |
      -timer_setup(&_E._timer, _callback, 0);
      +setup_timer(&_E._timer, _callback, (_cast_data)&_E);
      )
      
      // If we fixed a callback from a .function assignment, fix the
      // assignment cast now.
      @change_timer_function_assignment
       depends on change_timer_function_usage &&
                  (change_callback_handle_cast ||
                   change_callback_handle_cast_no_arg ||
                   change_callback_handle_arg)@
      expression change_timer_function_usage._E;
      identifier change_timer_function_usage._timer;
      identifier change_timer_function_usage._callback;
      type _cast_func;
      typedef TIMER_FUNC_TYPE;
      @@
      
      (
       _E->_timer.function =
      -_callback
      +(TIMER_FUNC_TYPE)_callback
       ;
      |
       _E->_timer.function =
      -&_callback
      +(TIMER_FUNC_TYPE)_callback
       ;
      |
       _E->_timer.function =
      -(_cast_func)_callback;
      +(TIMER_FUNC_TYPE)_callback
       ;
      |
       _E->_timer.function =
      -(_cast_func)&_callback
      +(TIMER_FUNC_TYPE)_callback
       ;
      |
       _E._timer.function =
      -_callback
      +(TIMER_FUNC_TYPE)_callback
       ;
      |
       _E._timer.function =
      -&_callback;
      +(TIMER_FUNC_TYPE)_callback
       ;
      |
       _E._timer.function =
      -(_cast_func)_callback
      +(TIMER_FUNC_TYPE)_callback
       ;
      |
       _E._timer.function =
      -(_cast_func)&_callback
      +(TIMER_FUNC_TYPE)_callback
       ;
      )
      
      // Sometimes timer functions are called directly. Replace matched args.
      @change_timer_function_calls
       depends on change_timer_function_usage &&
                  (change_callback_handle_cast ||
                   change_callback_handle_cast_no_arg ||
                   change_callback_handle_arg)@
      expression _E;
      identifier change_timer_function_usage._timer;
      identifier change_timer_function_usage._callback;
      type _cast_data;
      @@
      
       _callback(
      (
      -(_cast_data)_E
      +&_E->_timer
      |
      -(_cast_data)&_E
      +&_E._timer
      |
      -_E
      +&_E->_timer
      )
       )
      
      // If a timer has been configured without a data argument, it can be
      // converted without regard to the callback argument, since it is unused.
      @match_timer_function_unused_data@
      expression _E;
      identifier _timer;
      identifier _callback;
      @@
      
      (
      -setup_timer(&_E->_timer, _callback, 0);
      +timer_setup(&_E->_timer, _callback, 0);
      |
      -setup_timer(&_E->_timer, _callback, 0L);
      +timer_setup(&_E->_timer, _callback, 0);
      |
      -setup_timer(&_E->_timer, _callback, 0UL);
      +timer_setup(&_E->_timer, _callback, 0);
      |
      -setup_timer(&_E._timer, _callback, 0);
      +timer_setup(&_E._timer, _callback, 0);
      |
      -setup_timer(&_E._timer, _callback, 0L);
      +timer_setup(&_E._timer, _callback, 0);
      |
      -setup_timer(&_E._timer, _callback, 0UL);
      +timer_setup(&_E._timer, _callback, 0);
      |
      -setup_timer(&_timer, _callback, 0);
      +timer_setup(&_timer, _callback, 0);
      |
      -setup_timer(&_timer, _callback, 0L);
      +timer_setup(&_timer, _callback, 0);
      |
      -setup_timer(&_timer, _callback, 0UL);
      +timer_setup(&_timer, _callback, 0);
      |
      -setup_timer(_timer, _callback, 0);
      +timer_setup(_timer, _callback, 0);
      |
      -setup_timer(_timer, _callback, 0L);
      +timer_setup(_timer, _callback, 0);
      |
      -setup_timer(_timer, _callback, 0UL);
      +timer_setup(_timer, _callback, 0);
      )
      
      @change_callback_unused_data
       depends on match_timer_function_unused_data@
      identifier match_timer_function_unused_data._callback;
      type _origtype;
      identifier _origarg;
      @@
      
       void _callback(
      -_origtype _origarg
      +struct timer_list *unused
       )
       {
      	... when != _origarg
       }
      Signed-off-by: NKees Cook <keescook@chromium.org>
      e99e88a9
  4. 04 11月, 2017 1 次提交
  5. 24 10月, 2017 1 次提交
    • J
      usb: dwc2: Improve gadget state disconnection handling · d2471d4a
      John Stultz 提交于
      In the earlier commit dad3f793 ("usb: dwc2: Make sure we
      disconnect the gadget state"), I was trying to fix up the
      fact that we somehow weren't disconnecting the gadget state,
      so that when the OTG port was plugged in the second time we
      would get warnings about the state tracking being wrong.
      
      (This seems to be due to a quirk of the HiKey board where
      we do not ever get any otg interrupts, particularly the session
      end detected signal. Instead we only see status change
      interrupt.)
      
      The fix there was somewhat simple, as it just made sure to
      call dwc2_hsotg_disconnect() before we connected things up
      in OTG mode, ensuring the state handling didn't throw errors.
      
      But in looking at a different issue I was seeing with UDC
      state handling, I realized that it would be much better
      to call dwc2_hsotg_disconnect when we get the state change
      signal moving to host mode.
      
      Thus, this patch removes the earlier disconnect call I added
      and moves it (and the needed locking) to the host mode
      transition.
      
      Cc: Wei Xu <xuwei5@hisilicon.com>
      Cc: Guodong Xu <guodong.xu@linaro.org>
      Cc: Amit Pundir <amit.pundir@linaro.org>
      Cc: YongQin Liu <yongqin.liu@linaro.org>
      Cc: John Youn <johnyoun@synopsys.com>
      Cc: Minas Harutyunyan <Minas.Harutyunyan@synopsys.com>
      Cc: Douglas Anderson <dianders@chromium.org>
      Cc: Chen Yu <chenyu56@huawei.com>
      Cc: Felipe Balbi <felipe.balbi@linux.intel.com>
      Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
      Cc: linux-usb@vger.kernel.org
      Acked-by: NMinas Harutyunyan <hminas@synopsys.com>
      Tested-by: NMinas Harutyunyan <hminas@synopsys.com>
      Signed-off-by: NJohn Stultz <john.stultz@linaro.org>
      Signed-off-by: NFelipe Balbi <felipe.balbi@linux.intel.com>
      d2471d4a
  6. 19 10月, 2017 1 次提交
  7. 15 8月, 2017 1 次提交
  8. 11 4月, 2017 2 次提交
    • B
      usb: dwc2: Add support for STM32F429/439/469 USB OTG HS/FS in FS mode (internal PHY) · e35b1350
      Bruno Herrera 提交于
      This patch introduces a new parameter to activate USB OTG HS/FS core
      embedded phy transceiver. The STM32F4x9 SoC uses the GGPIO register
      to enable the transceiver.
      Also add the dwc2_set_params function for stm32f4 otg fs.
      Acked-by: NJohn Youn <johnyoun@synopsys.com>
      Signed-off-by: NBruno Herrera <bruherrera@gmail.com>
      Signed-off-by: NFelipe Balbi <felipe.balbi@linux.intel.com>
      e35b1350
    • J
      usb: dwc2: Make sure we disconnect the gadget state · dad3f793
      John Stultz 提交于
      I had seen some odd behavior with HiKey's usb-gadget interface
      that I finally seemed to have chased down. Basically every other
      time I plugged in the OTG port, the gadget interface would
      properly initialize. The other times, I'd get a big WARN_ON
      in dwc2_hsotg_init_fifo() about the fifo_map not being clear.
      
      Ends up if we don't disconnect the gadget state, the fifo-map
      doesn't get cleared properly, which causes WARN_ON messages and
      also results in the device not properly being setup as a gadget
      every other time the OTG port is connected.
      
      So this patch adds a call to dwc2_hsotg_disconnect() in the
      reset path so the state is properly cleared.
      
      With it, the gadget interface initializes properly on every
      plug in.
      
      Cc: Wei Xu <xuwei5@hisilicon.com>
      Cc: Guodong Xu <guodong.xu@linaro.org>
      Cc: Amit Pundir <amit.pundir@linaro.org>
      Cc: Rob Herring <robh+dt@kernel.org>
      Cc: John Youn <johnyoun@synopsys.com>
      Cc: Douglas Anderson <dianders@chromium.org>
      Cc: Chen Yu <chenyu56@huawei.com>
      Cc: Felipe Balbi <felipe.balbi@linux.intel.com>
      Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
      Cc: linux-usb@vger.kernel.org
      Acked-by: NJohn Youn <johnyoun@synopsys.com>
      Signed-off-by: NJohn Stultz <john.stultz@linaro.org>
      Signed-off-by: NFelipe Balbi <felipe.balbi@linux.intel.com>
      dad3f793
  9. 26 1月, 2017 2 次提交
  10. 24 1月, 2017 11 次提交
  11. 16 1月, 2017 1 次提交
  12. 12 1月, 2017 1 次提交
    • J
      usb: dwc2: Avoid suspending if we're in gadget mode · 866932e2
      John Stultz 提交于
      I've found when booting HiKey with the usb gadget cable attached
      if I then try to connect via adb, I get an infinite spew of:
      
      dwc2 f72c0000.usb: dwc2_hsotg_ep_sethalt(ep ffffffc0790ecb18 ep1out, 0)
      dwc2 f72c0000.usb: dwc2_hsotg_ep_sethalt(ep ffffffc0790eca18 ep1in, 0)
      
      It seems that the usb autosuspend is suspending the bus shortly
      after bootup when the gadget cable is attached. So when adbd
      then tries to use the device, it doesn't work and it then tries
      to restart it over and over via the ep_sethalt calls (via
      FUNCTIONFS_CLEAR_HALT ioctl).
      
      Chen Yu suggested this patch to avoid suspending if we're
      in device mode, and it avoids the problem.
      
      Cc: Wei Xu <xuwei5@hisilicon.com>
      Cc: Guodong Xu <guodong.xu@linaro.org>
      Cc: Amit Pundir <amit.pundir@linaro.org>
      Cc: Rob Herring <robh+dt@kernel.org>
      Cc: John Youn <johnyoun@synopsys.com>
      Cc: Douglas Anderson <dianders@chromium.org>
      Cc: Chen Yu <chenyu56@huawei.com>
      Cc: Kishon Vijay Abraham I <kishon@ti.com>
      Cc: Felipe Balbi <felipe.balbi@linux.intel.com>
      Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
      Cc: linux-usb@vger.kernel.org
      Suggested-by: NChen Yu <chenyu56@huawei.com>
      Signed-off-by: NJohn Stultz <john.stultz@linaro.org>
      Signed-off-by: NJohn Youn <johnyoun@synopsys.com>
      Signed-off-by: NFelipe Balbi <felipe.balbi@linux.intel.com>
      866932e2
  13. 18 11月, 2016 7 次提交
  14. 25 8月, 2016 1 次提交
  15. 09 8月, 2016 1 次提交
  16. 28 4月, 2016 1 次提交
  17. 04 3月, 2016 1 次提交