All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/2] [v5] pinctrl: qcom: add support for sparse GPIOs
From: Stephen Boyd @ 2017-10-04 21:50 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <40a0ab68-dc3a-10e2-f78e-9a386b4a72bd@codeaurora.org>

On 10/03, Timur Tabi wrote:
> On 10/03/2017 05:03 PM, Stephen Boyd wrote:
> >I've run into this now on our mobile SoCs after I pull in commit
> >8e51533780ba ("pinctrl: qcom: add get_direction function").
> >Before that commit we never read each pin of the device. On our
> >mobile SoCs we have devicetree and it feels like having that
> >describe which pins are available and not available is
> >half-duplicating information we would already have via consumers
> >indicating which pins they care about. I don't see any value
> >beyond system wide debug in figuring out the default pin
> >configuration of a pin that doesn't have a consumer in Linux.
> 
> At the time I wrote that patch, the ACPI tables exposed all of the
> GPIOs, even the ones it didn't care about.  The new ACPI tables list
> only specific GPIOs, and so we no longer need to blindly read the
> direction of all GPIOs.
> 

Do you avoid this problem on new ACPI tables because only pins
that are able to be read are exposed?

> 
> >This is basically a revert of commit 72d320006177 ("gpio: set up
> >initial state from .get_direction()").
> 
> I would be in favor of either reverting that patch, or moving the
> code into gpiochip_add_pin_range().

If it's in gpiochip_add_pin_range() would we still read the
hardware when creating the pin ranges? I don't want to have to
describe pin ranges of "valid" pins that won't cause the system
to blow up if we touch them, because those pins are never used by
Linux so reading them is not useful.

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

^ permalink raw reply

* Re: [PATCH 0/2] [v5] pinctrl: qcom: add support for sparse GPIOs
From: Stephen Boyd @ 2017-10-04 21:50 UTC (permalink / raw)
  To: Timur Tabi
  Cc: Linus Walleij, Andy Gross, David Brown, anjiandi, Bjorn Andersson,
	linux-gpio@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
	linux-arm-msm@vger.kernel.org, thierry.reding@gmail.com,
	Mika Westerberg, Andy Shevchenko
In-Reply-To: <40a0ab68-dc3a-10e2-f78e-9a386b4a72bd@codeaurora.org>

On 10/03, Timur Tabi wrote:
> On 10/03/2017 05:03 PM, Stephen Boyd wrote:
> >I've run into this now on our mobile SoCs after I pull in commit
> >8e51533780ba ("pinctrl: qcom: add get_direction function").
> >Before that commit we never read each pin of the device. On our
> >mobile SoCs we have devicetree and it feels like having that
> >describe which pins are available and not available is
> >half-duplicating information we would already have via consumers
> >indicating which pins they care about. I don't see any value
> >beyond system wide debug in figuring out the default pin
> >configuration of a pin that doesn't have a consumer in Linux.
> 
> At the time I wrote that patch, the ACPI tables exposed all of the
> GPIOs, even the ones it didn't care about.  The new ACPI tables list
> only specific GPIOs, and so we no longer need to blindly read the
> direction of all GPIOs.
> 

Do you avoid this problem on new ACPI tables because only pins
that are able to be read are exposed?

> 
> >This is basically a revert of commit 72d320006177 ("gpio: set up
> >initial state from .get_direction()").
> 
> I would be in favor of either reverting that patch, or moving the
> code into gpiochip_add_pin_range().

If it's in gpiochip_add_pin_range() would we still read the
hardware when creating the pin ranges? I don't want to have to
describe pin ranges of "valid" pins that won't cause the system
to blow up if we touch them, because those pins are never used by
Linux so reading them is not useful.

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

^ permalink raw reply

* [PATCH v15 00/32] Unified fwnode endpoint parser, async sub-device notifier support, N9 flash DTS
From: Sakari Ailus @ 2017-10-04 21:50 UTC (permalink / raw)
  To: linux-media
  Cc: niklas.soderlund, maxime.ripard, hverkuil, laurent.pinchart,
	pavel, sre, devicetree, linux-acpi

Hi folks,

	I've dropped the full set from devicetree and linux-acpi lists;
	let me know if you want it back. The entire set is posted to
	linux-media list.

We have a large influx of new, unmerged, drivers that are now parsing
fwnode endpoints and each one of them is doing this a little bit
differently. The needs are still exactly the same for the graph data
structure is device independent. This is still a non-trivial task and the
majority of the driver implementations are buggy, just buggy in different
ways.

Facilitate parsing endpoints by adding a convenience function for parsing
the endpoints, and make the omap3isp and rcar-vin drivers use them as an
example.

To show where we're getting with this, I've added support for async
sub-device notifier support that is notifiers that can be registered by
sub-device drivers as well as V4L2 fwnode improvements to make use of them
and the DTS changes for the Nokia N9. Some of these patches I've posted
previously in this set here:

<URL:http://www.spinics.net/lists/linux-media/msg118764.html>

Since that, the complete callback of the master notifier registering the
V4L2 device is only called once all sub-notifiers have been completed as
well. This way the device node creation can be postponed until all devices
have been successfully initialised.

With this, the as3645a driver successfully registers a sub-device to the
media device created by the omap3isp driver. The kernel also has the
information it's related to the sensor driven by the smiapp driver but we
don't have a way to expose that information yet.

The patches have a dependency to the as3645a driver fixes:

<URL:https://git.kernel.org/pub/scm/linux/kernel/git/j.anaszewski/linux-leds.git/log/?h=fixes-4.14-rc3>

since v14:

- Patch "v4l: fwnode: Support generic parsing of graph endpoints in a
  device" depends on another patch "device property: preserve usecount for
  node passed to of_fwnode_graph_get_port_parent()". Add Depends-on tag.

- Add patch "v4l: async: fix unbind error in
  v4l2_async_notifier_unregister()" by Niklas. Effectively the notifier's
  unbind callback is called before v4l2_async_cleanup(), not after it.

- Fix complete callback error handling (patch "v4l: async: Fix notifier
  complete callback error handling").

- Rework error handling in in v4l2_async_match_notify() and add comments.
  No functional changes there.

- Don't assign sd->dev to NULL in v4l2_async_cleanup() (patch "v4l: async:
  Don't set sd->dev NULL in v4l2_async_cleanup").

- Introduce a function to unbind sub-devices from a notifier. This is a
  common operation so a common implementation is beneficial.

- Assign notifier's v4l2_dev (or sd for sub-device notifiers) NULL on
  failure.

- Make v4l2_async_notifier_unregister() safe to call with a NULL argument.

- Set the implicitly allocated sub-device notifier NULL on async
  sub-device unregistration (used to be a dangling pointer).

- Clean up async sub-device unregistration.

- Fix v4l2_fwnode_endpoint_free() comment to match KernelDoc style, i.e.
  make the function visible in documentation.

- Don't add a random newline near the end of v4l2_async.h.

- Move patch "v4l: fwnode: Move KernelDoc documentation to the header"
  later in the set. The five first patches should now address bugs in the
  V4L2 async framework, causing an oops on complete callback failure.

since v13:

- Add patch "v4l: fwnode: Add a convenience function for registering sensors"
  and make the sensor driver changes a lot smaller.

- Fix v4l2_async_notifier_parse_fwnode_endpoints() error handling for
  omap3isp.

- Return -ENODEV in rcar-vin if no async sub-device is available. I.e. fix
  a bug in previous versions of "rcar-vin: Use generic parser for parsing
  fwnode endpoints".

- Rework notifier completion in patch "v4l: async: Allow binding notifiers to
  sub-devices". This fixes calling complete notifiers more than once; they
  are now all called once when all async sub-devices in all related
  notifiers have been bound.

- Split the same patch ("v4l: async: Allow binding notifiers to
  sub-devices") into two, first one that prepares for async sub-devices
  and another that implements the bulk of support for sub-device notifiers.

- Postpone sub-device bound callback until v4l2_device is available in all
  cases. This also applies to the media device. The notifier's bound
  callback was in some cases called before having v4l2_device in v13.

- Prevent registering fwnodes as async sub-devices more than once.

- Use list_move instead of list_del and list_add in
  v4l2_async_notifier_unbind_all_subdevs.

- Call v4l2_async_notifier_release v4l2_async_notifier_cleanup instead.
  It's a cleanup function and does not release the object passed to it.

- In v4l2_async_notifier_fwnode_parse_endpoint, set match_type field with
  the fwnode.fwnode field, not later.

- In debug and other messages, use port@number/endpoint@number format.

- Call fwnode_handle_put() to release references obtained using e.g.
  fwnode_graph_get_port_parent.

- Multiple KernelDoc documentation fixes.

since v12:

- Merge patches "v4l: fwnode: Support generic parsing of graph endpoints
  in a device" and "v4l: fwnode: Support generic parsing of graph
  endpoints, per port". Improve the commit and KernelDoc documentation as
  well.

- Reformat loop conditions in v4l2_async_notifier_try_complete() and
  v4l2_fwnode_reference_get_int_prop(). Improve comments in
  fwnode_property_get_reference_args() return value handling. Also check
  for -ENODATA in v4l2_fwnode_reference_parse_int_props().

- Add an ACPI example for v4l2_fwnode_reference_get_int_prop().

- Document index parameter, document nprops parameter better and fix
  -EINVAL error code documentation for
  v4l2_fwnode_reference_get_int_prop().

- Use WARN_ON_ONCE(true) instead of WARN_ON_ONCE(1) in
  v4l2_async_notifier_release().

since v11:

- Add patch "et8ek8: Add support for flash and lens devices".

- Add patch "v4l: fwnode: Support generic parsing of graph endpoints, per
  port". The use case for this is to parse only upstream ports in a device
  with sources and sinks. The downstream ports have already been parsed by
  other drivers.

- Rename v4l2_fwnode_reference_parse_sensor_common as
  v4l2_async_notifier_parse_fwnode_sensor_common. This is in line with
  other functions that parse information using fwnode API and set up async
  sub-devices in the notifier.

since v10:

- Rename v4l2_async_get_subdev_notifier as
  v4l2_async_find_subdev_notifier, as this is what it effectively does:
  finds a notifier for a sub-device. Same for v4l2_async_notifier_get_v4l2_dev
  / v4l2_async_notifier_get_v4l2_dev.

- Initialise lists before calling v4l2_async_notifier_call_complete() if
  there are no sub-devices in a notifier.

- Warn on missing sub-device or existing v4l2_device on sub-device
  notifier register, and conversely missing v4l2_device or existing
  sub-device for a master notifier.

- Set notifier's sd and v4l2_dev fields NULL when the sub-device is
  unregistered.

- Document the newly added helper functions for parsing external
  references in v4l2-fwnode.c better.

- Return -ENOENT in v4l2_fwnode_reference_parse if no entries are found,
  and other errors as they occur.

- Turn the loop in v4l2_fwnode_reference_get_int_prop a while loop (was
  for).

- Don't put fwnodes in v4l2_fwnode_reference_parse_int_props.

- Fix description of parent field in struct v4l2_async_notifier.

- In the documentation of v4l2_async_notifier_release, document that this
  function must be called also after
  v4l2_fwnode_reference_parse_sensor_common, not just
  v4l2_async_notifier_parse_fwnode_endpoints. The same goes for
  v4l2_async_notifier_parse_fwnode_endpoints as well as
  v4l2_fwnode_reference_parse_sensor_common.

since v9:

- Drop "as3645a: Switch to fwnode property API" and "ACPI: Document how to
  refer to LEDs from remote nodes" patches. They're better off separately
  from this set.

- Address property documentation redundancy in smiapp DT binding
  documentation.

- Add patches "ov5670: Add support for flash and lens devices" and
  "ov13858: Add support for flash and lens devices".

since v8:

- Improve terminology for notifiers. Instead of master / subdev, we
  have root, parent and subdev notifiers.

- Renamed "flash" property as "flash-leds". There are many, and currently
  we make assumptions in a lot of places (e.g. LED bindings) that these
  are LEDs. While we don't have any other types of flashes supported right
  now (e.g. Xenon), it's safer to assume we might have them in the future.

- Use ENOTCONN instead of EPERM to tell from driver's callback function
  that an endpoint is to be skipped but not handled as an error.

- Avoid accessing notifier's subdevs array as well as num_subdevs field
  from rcar-vin driver.

- Add a patch "v4l: async: Allow async notifier register call succeed with no
  subdevs", which allows, well, what the subject says.

- Move checks for subdev / v4l2_dev from __v4l2_async_notifier_register()
  to v4l2_async_notifier_register() and
  v4l2_async_subdev_notifier_register().

- Don't initialise notifier->list. There was no need to do so, as this is
  the entry added to the list and not used otherwise. I.e. regarding this,
  the state before this patchset is restored.

- Clean up error handling in v4l2_async_notifier_fwnode_parse_endpoint().

- WARN_ON() in v4l2_async_notifier_parse_fwnode_endpoints() if the
  asd_struct_size is smaller than size of struct v4l2_async_subdev.

- Make v4l2_fwnode_reference_parse() static as there should be no need to
  use it outside the V4L2 fwnode framework. Also, remove the callback
  function as well as other arguments that always have the same value in
  current usage. (This can be changed later on if needed without affecting
  drivers.)

- Add the patch "v4l: fwnode: Add a helper function to obtain device /
  interger references", which allows similar use than
  v4l2_fwnode_reference_parse() but is more useful on ACPI based systems
  --- on ACPI, you can only refer to device nodes (corresponding struct
  deice in Linux), not to data extension nodes under the devices.

- Improve v4l2_fwnode_reference_parse_sensor_common() to work on ACPI
  based systems.

- Add patch "ACPI: Document how to refer to LEDs from remote nodes" to
  document using and referring to LEDs on ACPI.

- Rebase the set on AS3645A fixes I just sent ("AS3645A fixes")

- In v4l2_fwnode_reference_parse_sensor_common(), tell if parsing a
  property failed.

- Improved documentation for v4l2_async_notifier_parse_fwnode_endpoints().

- Fix v4l2_async_notifier_try_all_subdevs(); it is allowed that the list
  entry being iterated over is deleted but no other changes to the list
  are allowed. This could be the case if a sub-device driver's notifier
  binds a sub-device. Restart the loop whenever a match is found.

- Add patch "as3645a: Switch to fwnode property API" which also adds ACPI
  support.

since v7:

- Added three more patches:

	v4l: async: Remove re-probing support
	v4l: async: Use more intuitive names for internal functions
	dt: bindings: smiapp: Document lens-focus and flash properties

  The last one was already sent previously after the rest of the patchset.

- Removed re-probing support. This is hard to support and only useful in
  special cases. It can be reintroduced later on if there's really a need
  --- note that in e.g. omap3isp this was always broken and no-one ever
  complained.

- Remove smiapp driver's async complete callback (and ops). It is
  redundant: the sub-device nodes are created through the master notifier.

- Improve flash property documentation in video-interfaces.txt.

- Introduce helper functions to call notifier operations, one for each
  operation.

- Rename v4l2_async_test_notify as v4l2_async_match_notify and
  v4l2_async_belongs to v4l2_async_find_match.

- v4l2_async_notifier_test_all_subdevs() renamed as
  v4l2_async_notifier_try_all_subdevs().

- Made notifier_v4l2_dev a function (it was a macro).

- Registering subdev notifiers from sub-device drivers that control
  sub-devices created through sub-notifiers is now supported. In other
  words, subdev notifiers may be registered through other subdev
  notifiers. This is the source of the bulk of the changes between v7 and
  v8.

- Add explanatory comments to helper functions used by V4L2 async
  framework. This should help understanding the internal workings of the
  framework.

- Removed the "notifiers" list in struct v4l2_async_notifier. The
  information can be found from existing data structures.

- Explicitly check that registering a non-subdev notifier has v4l2_dev and
  a subdev notifier has a sub-device pointer.

- Unified several code paths between subdev notifiers and non-subdev
  notifiers.

- Fixed v4l2_async_notifier_release() --- calling it on a notifier for
  which the driver had allocated the subdevs array would lead calling
  kvfree() on that array. Now notifier->max_subdevs is checked before
  proceeding.

- Fixed a use-after-free issue in
  v4l2_async_notifier_fwnode_parse_endpoints().

- Small fixes to KernelDoc documentation for
  v4l2_async_notifier_parse_fwnode_endpoints().

since v6:

- Drop the last patch that added variant for parsing endpoints given
  specific port and endpoints numbers.

- Separate driver changes from the fwnode endpoint parser patch into two
  patches. rcar-vin driver is now using the name function.

- Use -ENOTCONN to tell the parser that and endpoint (or a reference) is
  to be ignored.

- parse_endpoint and parse_single callback functions are now optional and
  documented as such.

- Added Laurent's patch adding notifier operations struct which I rebase
  on the fwnode parser patchset. I wrote another patch to call the
  notifier operations through macros.

- Add DT bindings for flash and lens devices.

- V4L2 fwnode parser for references (such as flash and lens).

- Added smiapp driver support for async sub-devices (lens and flash).

- Added a few fixes for omap3isp.

since v5:

- Use v4l2_async_ prefix for static functions as well (4th patch)

- Use memcpy() to copy array rather than a loop

- Document that the v4l2_async_subdev pointer in driver specific struct
  must be the first member

- Improve documentation of the added functions (4th and 5th
  patches)

	- Arguments

	- More thorough explation of the purpose, usage and object
	  lifetime

- Added acks

since v4:

- Prepend the set with three documentation fixes.

- The driver's async struct must begin with struct v4l2_async_subdev. Fix this
  for omap3isp and document it.

- Improve documentation for new functions.

- Don't use devm_ family of functions for allocating memory. Introduce
  v4l2_async_notifier_release() to release memory resources.

- Rework both v4l2_async_notifier_fwnode_parse_endpoints() and
  v4l2_async_notifier_fwnode_parse_endpoint() and the local functions they
  call. This should make the code cleaner. Despite the name, for linking
  and typical usage reasons the functions remain in v4l2-fwnode.c.

- Convert rcar-vin to use v4l2_async_notifier_fwnode_parse_endpoint().

- Use kvmalloc() for allocating the notifier's subdevs array.

- max_subdevs argument for notifier_realloc is now the total maximum
  number of subdevs, not the number of available subdevs.

- Use fwnode_device_is_available() to make sure the device actually
  exists.

- Move the note telling v4l2_async_notifier_fwnode_parse_endpoints()
  should not be used by new drivers to the last patch adding
  v4l2_async_notifier_fwnode_parse_endpoint().

since v3:

- Rebase on current mediatree master.

since v2:

- Rebase on CCP2 support patches.

- Prepend a patch cleaning up omap3isp driver a little.

since v1:

- The first patch has been merged (it was a bugfix).

- In anticipation that the parsing can take place over several iterations,
  take the existing number of async sub-devices into account when
  re-allocating an array of async sub-devices.

- Rework the first patch to better anticipate parsing single endpoint at a
  time by a driver.

- Add a second patch that adds a function for parsing endpoints one at a
  time based on port and endpoint numbers.

Laurent Pinchart (1):
  v4l: async: Move async subdev notifier operations to a separate
    structure

Niklas Söderlund (1):
  v4l: async: fix unbind error in v4l2_async_notifier_unregister()

Sakari Ailus (30):
  v4l: async: Remove re-probing support
  v4l: async: Don't set sd->dev NULL in v4l2_async_cleanup
  v4l: async: Fix notifier complete callback error handling
  v4l: async: Correctly serialise async sub-device unregistration
  v4l: async: Use more intuitive names for internal functions
  v4l: async: Add V4L2 async documentation to the documentation build
  v4l: fwnode: Support generic parsing of graph endpoints in a device
  omap3isp: Use generic parser for parsing fwnode endpoints
  rcar-vin: Use generic parser for parsing fwnode endpoints
  omap3isp: Fix check for our own sub-devices
  omap3isp: Print the name of the entity where no source pads could be
    found
  v4l: async: Introduce helpers for calling async ops callbacks
  v4l: async: Register sub-devices before calling bound callback
  v4l: async: Allow async notifier register call succeed with no subdevs
  v4l: async: Prepare for async sub-device notifiers
  v4l: async: Allow binding notifiers to sub-devices
  v4l: async: Ensure only unique fwnodes are registered to notifiers
  dt: bindings: Add a binding for flash LED devices associated to a
    sensor
  dt: bindings: Add lens-focus binding for image sensors
  v4l: fwnode: Move KernelDoc documentation to the header
  v4l: fwnode: Add a helper function for parsing generic references
  v4l: fwnode: Add a helper function to obtain device / integer
    references
  v4l: fwnode: Add convenience function for parsing common external refs
  v4l: fwnode: Add a convenience function for registering sensors
  dt: bindings: smiapp: Document lens-focus and flash-leds properties
  smiapp: Add support for flash and lens devices
  et8ek8: Add support for flash and lens devices
  ov5670: Add support for flash and lens devices
  ov13858: Add support for flash and lens devices
  arm: dts: omap3: N9/N950: Add flash references to the camera

 .../devicetree/bindings/media/i2c/nokia,smia.txt   |   2 +
 .../devicetree/bindings/media/video-interfaces.txt |  10 +
 Documentation/media/kapi/v4l2-async.rst            |   3 +
 Documentation/media/kapi/v4l2-core.rst             |   1 +
 arch/arm/boot/dts/omap3-n9.dts                     |   1 +
 arch/arm/boot/dts/omap3-n950-n9.dtsi               |   4 +-
 arch/arm/boot/dts/omap3-n950.dts                   |   1 +
 drivers/media/i2c/et8ek8/et8ek8_driver.c           |   2 +-
 drivers/media/i2c/ov13858.c                        |   2 +-
 drivers/media/i2c/ov5670.c                         |   2 +-
 drivers/media/i2c/smiapp/smiapp-core.c             |   2 +-
 drivers/media/platform/am437x/am437x-vpfe.c        |   8 +-
 drivers/media/platform/atmel/atmel-isc.c           |  10 +-
 drivers/media/platform/atmel/atmel-isi.c           |  10 +-
 drivers/media/platform/davinci/vpif_capture.c      |   8 +-
 drivers/media/platform/davinci/vpif_display.c      |   8 +-
 drivers/media/platform/exynos4-is/media-dev.c      |   8 +-
 drivers/media/platform/omap3isp/isp.c              | 133 ++---
 drivers/media/platform/omap3isp/isp.h              |   5 +-
 drivers/media/platform/pxa_camera.c                |   8 +-
 drivers/media/platform/qcom/camss-8x16/camss.c     |   8 +-
 drivers/media/platform/rcar-vin/rcar-core.c        | 117 ++--
 drivers/media/platform/rcar-vin/rcar-dma.c         |  10 +-
 drivers/media/platform/rcar-vin/rcar-v4l2.c        |  14 +-
 drivers/media/platform/rcar-vin/rcar-vin.h         |   4 +-
 drivers/media/platform/rcar_drif.c                 |  10 +-
 drivers/media/platform/soc_camera/soc_camera.c     |  14 +-
 drivers/media/platform/stm32/stm32-dcmi.c          |  10 +-
 drivers/media/platform/ti-vpe/cal.c                |   8 +-
 drivers/media/platform/xilinx/xilinx-vipp.c        |   8 +-
 drivers/media/v4l2-core/v4l2-async.c               | 537 ++++++++++++++----
 drivers/media/v4l2-core/v4l2-fwnode.c              | 623 ++++++++++++++++++---
 drivers/staging/media/imx/imx-media-dev.c          |   8 +-
 include/media/v4l2-async.h                         |  90 ++-
 include/media/v4l2-fwnode.h                        | 220 +++++++-
 include/media/v4l2-subdev.h                        |   3 +
 36 files changed, 1488 insertions(+), 424 deletions(-)
 create mode 100644 Documentation/media/kapi/v4l2-async.rst

-- 
2.11.0

^ permalink raw reply

* [PATCH tip/core/rcu 0/4] RCU CPU stall warning updates for v4.15
From: Paul E. McKenney @ 2017-10-04 21:50 UTC (permalink / raw)
  To: linux-kernel
  Cc: mingo, jiangshanlai, dipankar, akpm, mathieu.desnoyers, josh,
	tglx, peterz, rostedt, dhowells, edumazet, fweisbec, oleg

Hello!

This series updates RCU CPU stall warnings, and also, due to conflicts,
pulls along a long-standing patch that allows cond_resched() to do the
work that cond_resched_rcu_qs() does.

1.	Make cond_resched() provide RCU quiescent state.  This has been
	heavily optimized over its lifetime, which is almost one year.
	It should be close enough.  Yes, some benchmarks show that it
	results in higher context-switch rates, but then again, the
	problem being solved is in fact too few context switches.  ;-)

2.	Make RCU CPU stall warnings check for irq-disabled CPUs.

3.	Turn off tracing before dumping traces.

4.	Suppress RCU CPU stall warnings while dumping RCU-related traces.

							Thanx, Paul

------------------------------------------------------------------------

 include/linux/sched.h    |    3 -
 kernel/rcu/rcu.h         |   21 +++++++
 kernel/rcu/tree.c        |  129 +++++++++++++++++++++++++++++++++++------------
 kernel/rcu/tree.h        |    5 +
 kernel/rcu/tree_plugin.h |    7 ++
 kernel/rcu/update.c      |    1 
 kernel/sched/core.c      |    1 
 7 files changed, 132 insertions(+), 35 deletions(-)

^ permalink raw reply

* Re: [PATCH 2/2] drm/i915/cnl: Fix PLL initialization for HDMI.
From: Manasi Navare @ 2017-10-04 21:54 UTC (permalink / raw)
  To: Rodrigo Vivi; +Cc: intel-gfx, Kahola, Paulo Zanoni
In-Reply-To: <20171003220859.21352-3-rodrigo.vivi@intel.com>

Good catch. Looks good to me as per the Bspec.

Reviewed-by: Manasi Navare <manasi.d.navare@intel.com>

Manasi

On Tue, Oct 03, 2017 at 03:08:59PM -0700, Rodrigo Vivi wrote:
> HDMI Mode selection on CNL is on CFGCR0 for that PLL, not
> on in a global CTRL1 as it was on SKL.
> 
> The original patch addressed this difference, but leaving behind
> this single entry here. So we were checking the wrong bits during
> the PLL initialization and consequently avoiding the CFGCR1 setup
> during HDMI initialization. Luckly when only HDMI was in use BIOS
> had already setup this for us. But the dual display with hot plug
> were messed up.
> 
> Fixes: a927c927de34 ("drm/i915/cnl: Initialize PLLs")
> Cc: Paulo Zanoni <paulo.r.zanoni@intel.com>
> Cc: Manasi Navare <manasi.d.navare@intel.com>
> Cc: Kahola, Mika <mika.kahola@intel.com>
> Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
> ---
>  drivers/gpu/drm/i915/intel_dpll_mgr.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.c b/drivers/gpu/drm/i915/intel_dpll_mgr.c
> index 55997389a29f..032fd915e929 100644
> --- a/drivers/gpu/drm/i915/intel_dpll_mgr.c
> +++ b/drivers/gpu/drm/i915/intel_dpll_mgr.c
> @@ -2000,7 +2000,7 @@ static void cnl_ddi_pll_enable(struct drm_i915_private *dev_priv,
>  
>  	/* 3. Configure DPLL_CFGCR0 */
>  	/* Avoid touch CFGCR1 if HDMI mode is not enabled */
> -	if (pll->state.hw_state.cfgcr0 & DPLL_CTRL1_HDMI_MODE(pll->id)) {
> +	if (pll->state.hw_state.cfgcr0 & DPLL_CFGCR0_HDMI_MODE) {
>  		val = pll->state.hw_state.cfgcr1;
>  		I915_WRITE(CNL_DPLL_CFGCR1(pll->id), val);
>  		/* 4. Reab back to ensure writes completed */
> -- 
> 2.13.5
> 
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply

* Kernel 4.13 is broken on m68k
From: John Paul Adrian Glaubitz @ 2017-10-04 21:49 UTC (permalink / raw)
  To: Linux/m68k; +Cc: Debian m68k

Hi!

While working on updated installation images for m68k, I ran into a serious
problem with shell-scripts which makes booting Linux on m68k impossible.

With debian-installer, the problem manifests with the script /sbin/reopen-console
which fails with:

/sbin/reopen-console: line 74: syntax error: unterminated quoted string

with reopen-console coming from [1].

In order to rule out a problem with debian-installer, I dist-upgraded an
existing system which also upgraded the kernel from 4.12 to 4.13.

And, indeed, after upgrading the system, the boot fails with:

[    0.520000] ADB mouse at 3, handler 1
[    0.520000]
[    0.520000] input: ADB mouse as /devices/virtual/input/input1
[    0.520000] adb: finished probe task...
Loading, please wait...
/init: line 69: syntax error: missing '}'
[    0.610000] Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000200
[    0.610000]
[    0.610000] CPU: 0 PID: 1 Comm: init Not tainted 4.13.0-1-m68k #1 Debian 4.13.4-1
[    0.610000] Stack from 3dc35f48:
[    0.610000]         3dc35f48 00355ab1 0002c9bc 000002ff 0004bea0 0028ede6 00000000 3dc33390
[    0.610000]         0038643c 00000000 3dc35fb0 0002e63c 00322d0f 00000200 00000200 000000f7
[    0.610000]         00000000 00000000 00000000 00000000 d00b0140 d00b1404 c0154000 00000001
[    0.610000]         3dc35fa8 3dc35fa8 efe128c8 0002e9d4 00000200 00000002 0002e9e8 00000200
[    0.610000]         00002934 00000002 00000002 000000f7 00000000 00000000 d00b1008 efe128e0
[    0.610000]         d00b1408 000000f7 000000f7 00000000 0000c00b c04e0080
[    0.610000] Call Trace: [<0002c9bc>] panic+0xa6/0x22e
[    0.610000]  [<0004bea0>] up_read+0x0/0x6
[    0.610000]  [<0028ede6>] down_read+0x0/0x6
[    0.610000]  [<0002e63c>] do_exit+0x490/0x75c
[    0.610000]  [<0002e9d4>] SyS_exit_group+0x0/0x14
[    0.610000]  [<0002e9e8>] __wake_up_parent+0x0/0x24
[    0.610000]  [<00002934>] syscall+0x8/0xc
[    0.610000]  [<0000c00b>] mac_hwclk+0x501/0x62c
[    0.610000] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000200
[    0.610000]

I can trigger the problem by switching between 4.12 and 4.13, 4.12 is fin while 4.13 is broken.

Adrian

> [1] https://anonscm.debian.org/cgit/d-i/rootskel.git/tree/src/sbin/reopen-console-linux

-- 
 .''`.  John Paul Adrian Glaubitz
: :' :  Debian Developer - glaubitz@debian.org
`. `'   Freie Universitaet Berlin - glaubitz@physik.fu-berlin.de
  `-    GPG: 62FF 8A75 84E0 2956 9546  0006 7426 3B37 F5B5 F913

^ permalink raw reply

* [PATCH v3 7/7] net/mlx4: add loopback Tx from VF
From: Ophir Munk @ 2017-10-04 21:49 UTC (permalink / raw)
  To: Adrien Mazarguil
  Cc: dev, Thomas Monjalon, Olga Shern, Matan Azrad, Moti Haimovsky
In-Reply-To: <1507153746-31255-1-git-send-email-ophirmu@mellanox.com>

From: Moti Haimovsky <motih@mellanox.com>

This patch adds loopback functionality used when the chip is a VF
in order to enable packet transmission between VFs and between VFs and PF.

Signed-off-by: Moti Haimovsky <motih@mellanox.com>
---
 drivers/net/mlx4/mlx4_rxtx.c | 38 ++++++++++++++++++++++++++------------
 drivers/net/mlx4/mlx4_rxtx.h |  2 ++
 drivers/net/mlx4/mlx4_txq.c  |  2 ++
 3 files changed, 30 insertions(+), 12 deletions(-)

diff --git a/drivers/net/mlx4/mlx4_rxtx.c b/drivers/net/mlx4/mlx4_rxtx.c
index ca66b1d..87c4c38 100644
--- a/drivers/net/mlx4/mlx4_rxtx.c
+++ b/drivers/net/mlx4/mlx4_rxtx.c
@@ -321,10 +321,13 @@ struct pv {
 	struct mlx4_wqe_data_seg *dseg;
 	struct mlx4_sq *sq = &txq->msq;
 	struct rte_mbuf *buf;
+	union {
+		uint32_t flags;
+		uint16_t flags16[2];
+	} srcrb;
 	uint32_t head_idx = sq->head & sq->txbb_cnt_mask;
 	uint32_t lkey;
 	uintptr_t addr;
-	uint32_t srcrb_flags;
 	uint32_t owner_opcode = MLX4_OPCODE_SEND;
 	uint32_t byte_count;
 	int wqe_real_size;
@@ -422,21 +425,15 @@ struct pv {
 	/* Fill the control parameters for this packet. */
 	ctrl->fence_size = (wqe_real_size >> 4) & 0x3f;
 	/*
-	 * The caller should prepare "imm" in advance in order to support
-	 * VF to VF communication (when the device is a virtual-function
-	 * device (VF)).
-	*/
-	ctrl->imm = 0;
-	/*
 	 * For raw Ethernet, the SOLICIT flag is used to indicate that no icrc
 	 * should be calculated.
 	 */
 	txq->elts_comp_cd -= nr_txbbs;
 	if (unlikely(txq->elts_comp_cd <= 0)) {
 		txq->elts_comp_cd = txq->elts_comp_cd_init;
-		srcrb_flags = MLX4_WQE_CTRL_SOLICIT | MLX4_WQE_CTRL_CQ_UPDATE;
+		srcrb.flags = MLX4_WQE_CTRL_SOLICIT | MLX4_WQE_CTRL_CQ_UPDATE;
 	} else {
-		srcrb_flags = MLX4_WQE_CTRL_SOLICIT;
+		srcrb.flags = MLX4_WQE_CTRL_SOLICIT;
 	}
 	/* Enable HW checksum offload if requested */
 	if (txq->csum &&
@@ -450,13 +447,30 @@ struct pv {
 			owner_opcode |= MLX4_WQE_CTRL_IIP_HDR_CSUM |
 					MLX4_WQE_CTRL_IL4_HDR_CSUM;
 			if (pkt->ol_flags & PKT_TX_OUTER_IP_CKSUM)
-				srcrb_flags |= MLX4_WQE_CTRL_IP_HDR_CSUM;
+				srcrb.flags |= MLX4_WQE_CTRL_IP_HDR_CSUM;
 		} else {
-			srcrb_flags |= MLX4_WQE_CTRL_IP_HDR_CSUM |
+			srcrb.flags |= MLX4_WQE_CTRL_IP_HDR_CSUM |
 				      MLX4_WQE_CTRL_TCP_UDP_CSUM;
 		}
 	}
-	ctrl->srcrb_flags = rte_cpu_to_be_32(srcrb_flags);
+	/*
+	 * convert flags to BE before adding the mac address (if at all)
+	 * to it
+	 */
+	srcrb.flags = rte_cpu_to_be_32(srcrb.flags);
+	if (txq->lb) {
+		/*
+		 * Copy destination mac address to the wqe,
+		 * this allows loopback in eSwitch, so that VFs and PF
+		 * can communicate with each other.
+		 */
+		srcrb.flags16[0] = *(rte_pktmbuf_mtod(pkt, uint16_t *));
+		ctrl->imm = *(rte_pktmbuf_mtod_offset(pkt, uint32_t *,
+						      sizeof(uint16_t)));
+	} else {
+		ctrl->imm = 0;
+	}
+	ctrl->srcrb_flags = srcrb.flags;
 	/*
 	 * Make sure descriptor is fully written before
 	 * setting ownership bit (because HW can start
diff --git a/drivers/net/mlx4/mlx4_rxtx.h b/drivers/net/mlx4/mlx4_rxtx.h
index 75c98c1..6f33d1c 100644
--- a/drivers/net/mlx4/mlx4_rxtx.h
+++ b/drivers/net/mlx4/mlx4_rxtx.h
@@ -114,6 +114,8 @@ struct txq {
 	uint32_t max_inline; /**< Max inline send size. */
 	uint32_t csum:1; /**< Checksum is supported and enabled */
 	uint32_t csum_l2tun:1; /**< L2 tun Checksum is supported and enabled */
+	uint32_t lb:1;
+	/**< Whether pkts should be looped-back by eswitch or not */
 	char *bounce_buf;
 	/**< memory used for storing the first DWORD of data TXBBs. */
 	struct {
diff --git a/drivers/net/mlx4/mlx4_txq.c b/drivers/net/mlx4/mlx4_txq.c
index 4eb739c..8205647 100644
--- a/drivers/net/mlx4/mlx4_txq.c
+++ b/drivers/net/mlx4/mlx4_txq.c
@@ -415,6 +415,8 @@ struct txq_mp2mr_mbuf_check_data {
 		      (void *)dev, strerror(rte_errno));
 		goto error;
 	}
+	/* If a VF device - need to loopback xmitted packets */
+	tmpl.lb = !!(priv->vf);
 	/* Clean up txq in case we're reinitializing it. */
 	DEBUG("%p: cleaning-up old txq just in case", (void *)txq);
 	mlx4_txq_cleanup(txq);
-- 
1.8.3.1

^ permalink raw reply related

* [PATCH v3 6/7] net/mlx4: get back Rx checksum offloads
From: Ophir Munk @ 2017-10-04 21:49 UTC (permalink / raw)
  To: Adrien Mazarguil
  Cc: dev, Thomas Monjalon, Olga Shern, Matan Azrad, Moti Haimovsky,
	Vasily Philipov
In-Reply-To: <1507153746-31255-1-git-send-email-ophirmu@mellanox.com>

From: Moti Haimovsky <motih@mellanox.com>

This patch adds hardware offloading support for IPV4, UDP and TCP
checksum verification.
This commit also includes support for offloading IPV4, UDP and TCP tunnel
checksum verification to the hardware.

Signed-off-by: Vasily Philipov <vasilyf@mellanox.com>
---
 drivers/net/mlx4/mlx4.c        |   2 +
 drivers/net/mlx4/mlx4_ethdev.c |   8 ++-
 drivers/net/mlx4/mlx4_prm.h    |  19 +++++++
 drivers/net/mlx4/mlx4_rxq.c    |   5 ++
 drivers/net/mlx4/mlx4_rxtx.c   | 120 ++++++++++++++++++++++++++++++++++++++++-
 drivers/net/mlx4/mlx4_rxtx.h   |   2 +
 6 files changed, 152 insertions(+), 4 deletions(-)

diff --git a/drivers/net/mlx4/mlx4.c b/drivers/net/mlx4/mlx4.c
index a0e76ee..865ffdd 100644
--- a/drivers/net/mlx4/mlx4.c
+++ b/drivers/net/mlx4/mlx4.c
@@ -535,6 +535,8 @@ struct mlx4_conf {
 		priv->vf = vf;
 		priv->hw_csum =
 		     !!(device_attr.device_cap_flags & IBV_DEVICE_RAW_IP_CSUM);
+		DEBUG("checksum offloading is %ssupported",
+		      (priv->hw_csum ? "" : "not "));
 		priv->hw_csum_l2tun = tunnel_en;
 		DEBUG("L2 tunnel checksum offloads are %ssupported",
 		      (priv->hw_csum_l2tun ? "" : "not "));
diff --git a/drivers/net/mlx4/mlx4_ethdev.c b/drivers/net/mlx4/mlx4_ethdev.c
index 95cc6e4..6dbf273 100644
--- a/drivers/net/mlx4/mlx4_ethdev.c
+++ b/drivers/net/mlx4/mlx4_ethdev.c
@@ -553,10 +553,14 @@
 	info->max_mac_addrs = 1;
 	info->rx_offload_capa = 0;
 	info->tx_offload_capa = 0;
-	if (priv->hw_csum)
+	if (priv->hw_csum) {
 		info->tx_offload_capa |= (DEV_TX_OFFLOAD_IPV4_CKSUM |
-					  DEV_TX_OFFLOAD_UDP_CKSUM  |
+					  DEV_TX_OFFLOAD_UDP_CKSUM |
 					  DEV_TX_OFFLOAD_TCP_CKSUM);
+		info->rx_offload_capa |= (DEV_RX_OFFLOAD_IPV4_CKSUM |
+					  DEV_RX_OFFLOAD_UDP_CKSUM |
+					  DEV_RX_OFFLOAD_TCP_CKSUM);
+	}
 	if (priv->hw_csum_l2tun)
 		info->tx_offload_capa |= DEV_TX_OFFLOAD_OUTER_IPV4_CKSUM;
 	if (mlx4_get_ifname(priv, &ifname) == 0)
diff --git a/drivers/net/mlx4/mlx4_prm.h b/drivers/net/mlx4/mlx4_prm.h
index 57f5a46..73c3d55 100644
--- a/drivers/net/mlx4/mlx4_prm.h
+++ b/drivers/net/mlx4/mlx4_prm.h
@@ -70,6 +70,25 @@
 #define MLX4_SIZE_TO_TXBBS(size) \
 		(RTE_ALIGN((size), (MLX4_TXBB_SIZE)) >> (MLX4_TXBB_SHIFT))
 
+/* Generic macro to convert MLX4 to IBV flags. */
+#define MLX4_TRANSPOSE(val, from, to) \
+		(__extension__({ \
+			typeof(val) _val = (val); \
+			typeof(from) _from = (from); \
+			typeof(to) _to = (to); \
+			(((_from) >= (_to)) ? \
+			(((_val) & (_from)) / ((_from) / (_to))) : \
+			(((_val) & (_from)) * ((_to) / (_from)))); \
+		}))
+
+/* CQE checksum flags */
+enum {
+	MLX4_CQE_L2_TUNNEL_IPV4 = (int)(1U << 25),
+	MLX4_CQE_L2_TUNNEL_L4_CSUM = (int)(1U << 26),
+	MLX4_CQE_L2_TUNNEL = (int)(1U << 27),
+	MLX4_CQE_L2_TUNNEL_IPOK = (int)(1U << 31),
+};
+
 /* Send queue information. */
 struct mlx4_sq {
 	char *buf; /**< SQ buffer. */
diff --git a/drivers/net/mlx4/mlx4_rxq.c b/drivers/net/mlx4/mlx4_rxq.c
index 7d13121..889f05c 100644
--- a/drivers/net/mlx4/mlx4_rxq.c
+++ b/drivers/net/mlx4/mlx4_rxq.c
@@ -267,6 +267,11 @@
 	int ret;
 
 	(void)conf; /* Thresholds configuration (ignored). */
+	/* Toggle Rx checksum offload if hardware supports it. */
+	if (priv->hw_csum)
+		tmpl.csum = !!dev->data->dev_conf.rxmode.hw_ip_checksum;
+	if (priv->hw_csum_l2tun)
+		tmpl.csum_l2tun = !!dev->data->dev_conf.rxmode.hw_ip_checksum;
 	mb_len = rte_pktmbuf_data_room_size(mp);
 	/* Enable scattered packets support for this queue if necessary. */
 	assert(mb_len >= RTE_PKTMBUF_HEADROOM);
diff --git a/drivers/net/mlx4/mlx4_rxtx.c b/drivers/net/mlx4/mlx4_rxtx.c
index ea92ebb..ca66b1d 100644
--- a/drivers/net/mlx4/mlx4_rxtx.c
+++ b/drivers/net/mlx4/mlx4_rxtx.c
@@ -563,6 +563,110 @@ struct pv {
 }
 
 /**
+ * Translate Rx completion flags to packet type.
+ *
+ * @param flags
+ *   Rx completion flags returned by poll_length_flags().
+ *
+ * @return
+ *   Packet type for struct rte_mbuf.
+ */
+static inline uint32_t
+rxq_cq_to_pkt_type(uint32_t flags)
+{
+	uint32_t pkt_type;
+
+	if (flags & MLX4_CQE_L2_TUNNEL)
+		pkt_type =
+			MLX4_TRANSPOSE(flags,
+			       (uint32_t)MLX4_CQE_L2_TUNNEL_IPV4,
+			       (uint32_t)RTE_PTYPE_L3_IPV4_EXT_UNKNOWN) |
+			MLX4_TRANSPOSE(flags,
+			       (uint32_t)MLX4_CQE_STATUS_IPV4_PKT,
+			       (uint32_t)RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN);
+	else
+		pkt_type =
+			MLX4_TRANSPOSE(flags,
+			       (uint32_t)MLX4_CQE_STATUS_IPV4_PKT,
+			       (uint32_t)RTE_PTYPE_L3_IPV4_EXT_UNKNOWN);
+	ERROR("pkt_type 0x%x", pkt_type); //
+	return pkt_type;
+}
+
+/**
+ * Translate Rx completion flags to offload flags.
+ *
+ * @param  flags
+ *   Rx completion flags returned by poll_length_flags().
+ * @param csum
+ *   Rx checksum enable flag
+ * @param csum_l2tun
+ *   Rx L2 tunnel checksum enable flag
+ *
+ * @return
+ *   Offload flags (ol_flags) for struct rte_mbuf.
+ */
+static inline uint32_t
+rxq_cq_to_ol_flags(uint32_t flags, unsigned int csum, unsigned int csum_l2tun)
+{
+	uint32_t ol_flags = 0;
+
+	if (csum)
+		ol_flags |=
+			MLX4_TRANSPOSE(flags,
+				(uint64_t)MLX4_CQE_STATUS_IP_HDR_CSUM_OK,
+				PKT_RX_IP_CKSUM_GOOD) |
+			MLX4_TRANSPOSE(flags,
+				(uint64_t)MLX4_CQE_STATUS_TCP_UDP_CSUM_OK,
+				PKT_RX_L4_CKSUM_GOOD);
+	if ((flags & MLX4_CQE_L2_TUNNEL) && csum_l2tun)
+		ol_flags |=
+			MLX4_TRANSPOSE(flags,
+				       (uint64_t)MLX4_CQE_L2_TUNNEL_IPOK,
+				       PKT_RX_IP_CKSUM_GOOD) |
+			MLX4_TRANSPOSE(flags,
+				       (uint64_t)MLX4_CQE_L2_TUNNEL_L4_CSUM,
+				       PKT_RX_L4_CKSUM_GOOD);
+	return ol_flags;
+}
+
+/**
+ * Get Rx checksum CQE flags.
+ *
+ * @param cqe
+ *   Pointer to cqe structure.
+ * @param csum
+ *   Rx checksum enable flag
+ * @param csum_l2tun
+ *   RX L2 tunnel checksum enable flag
+ *
+ * @return
+ *   CQE flags in CPU order
+ */
+static inline uint32_t
+mlx4_cqe_flags(struct mlx4_cqe *cqe,
+	       int csum, unsigned int csum_l2tun)
+{
+	uint32_t flags = 0;
+
+	/*
+	 * The relevant bits are in different locations on their
+	 * CQE fields therefore we can join them in one 32-bit
+	 * variable.
+	 */
+	if (csum)
+		flags = rte_be_to_cpu_32(cqe->status) &
+			MLX4_CQE_STATUS_IPV4_CSUM_OK;
+	if (csum_l2tun)
+		flags |= rte_be_to_cpu_32(cqe->vlan_my_qpn) &
+			 (MLX4_CQE_L2_TUNNEL |
+			  MLX4_CQE_L2_TUNNEL_IPOK |
+			  MLX4_CQE_L2_TUNNEL_L4_CSUM |
+			  MLX4_CQE_L2_TUNNEL_IPV4);
+		return flags;
+}
+
+/**
  * Poll one CQE from CQ.
  *
  * @param rxq
@@ -601,7 +705,7 @@ struct pv {
 }
 
 /**
- * DPDK callback for RX with scattered packets support.
+ * DPDK callback for Rx with scattered packets support.
  *
  * @param dpdk_rxq
  *   Generic pointer to Rx queue structure.
@@ -666,7 +770,7 @@ struct pv {
 				break;
 			}
 			if (unlikely(len < 0)) {
-				/* RX error, packet is likely too large. */
+				/* Rx error, packet is likely too large. */
 				rte_mbuf_raw_free(rep);
 				++rxq->stats.idropped;
 				goto skip;
@@ -674,6 +778,18 @@ struct pv {
 			pkt = seg;
 			pkt->packet_type = 0;
 			pkt->ol_flags = 0;
+			if (rxq->csum | rxq->csum_l2tun) {
+				uint32_t flags =
+					mlx4_cqe_flags(cqe, rxq->csum,
+						       rxq->csum_l2tun);
+				pkt->ol_flags =
+					rxq_cq_to_ol_flags(flags, rxq->csum,
+							   rxq->csum_l2tun);
+				pkt->packet_type = rxq_cq_to_pkt_type(flags);
+			} else {
+				pkt->packet_type = 0;
+				pkt->ol_flags = 0;
+			}
 			pkt->pkt_len = len;
 		}
 		rep->nb_segs = 1;
diff --git a/drivers/net/mlx4/mlx4_rxtx.h b/drivers/net/mlx4/mlx4_rxtx.h
index dc283e1..75c98c1 100644
--- a/drivers/net/mlx4/mlx4_rxtx.h
+++ b/drivers/net/mlx4/mlx4_rxtx.h
@@ -80,6 +80,8 @@ struct rxq {
 	} hw;
 	struct mlx4_cq mcq;  /**< Info for directly manipulating the CQ. */
 	unsigned int sge_n; /**< Log 2 of SGEs number. */
+	unsigned int csum:1; /**< Enable checksum offloading. */
+	unsigned int csum_l2tun:1; /**< Enable checksum for L2 tunnels. */
 	struct mlx4_rxq_stats stats; /**< Rx queue counters. */
 	unsigned int socket; /**< CPU socket ID for allocations. */
 };
-- 
1.8.3.1

^ permalink raw reply related

* [PATCH v3 4/7] net/mlx4: support multi-segments Tx
From: Ophir Munk @ 2017-10-04 21:49 UTC (permalink / raw)
  To: Adrien Mazarguil
  Cc: dev, Thomas Monjalon, Olga Shern, Matan Azrad, Moti Haimovsky
In-Reply-To: <1507153746-31255-1-git-send-email-ophirmu@mellanox.com>

From: Moti Haimovsky <motih@mellanox.com>

This patch adds support for transmitting packets spanning over
multiple buffers.
In this patch we also take into consideration the amount of entries
a packet occupies in the TxQ when setting the report-completion flag
of the chip.

Signed-off-by: Moti Haimovsky <motih@mellanox.com>
---
 drivers/net/mlx4/mlx4_rxtx.c | 208 ++++++++++++++++++++++++-------------------
 drivers/net/mlx4/mlx4_rxtx.h |   6 +-
 drivers/net/mlx4/mlx4_txq.c  |  12 ++-
 3 files changed, 129 insertions(+), 97 deletions(-)

diff --git a/drivers/net/mlx4/mlx4_rxtx.c b/drivers/net/mlx4/mlx4_rxtx.c
index f517505..bc0e353 100644
--- a/drivers/net/mlx4/mlx4_rxtx.c
+++ b/drivers/net/mlx4/mlx4_rxtx.c
@@ -63,6 +63,16 @@
 #include "mlx4_rxtx.h"
 #include "mlx4_utils.h"
 
+/*
+ * Pointer-value pair structure
+ * used in tx_post_send for saving the first DWORD (32 byte)
+ * of a TXBB0
+ */
+struct pv {
+	struct mlx4_wqe_data_seg *dseg;
+	uint32_t val;
+};
+
 /**
  * Stamp a WQE so it won't be reused by the HW.
  * Routine is used when freeing WQE used by the chip or when failing
@@ -297,34 +307,38 @@
  *
  * @param txq
  *   The Tx queue to post to.
- * @param wr
- *   The work request to handle.
- * @param bad_wr
- *   The wr in case that posting had failed.
+ * @param pkt
+ *   The packet to transmit.
  *
  * @return
  *   0 - success, negative errno value otherwise and rte_errno is set.
  */
 static inline int
 mlx4_post_send(struct txq *txq,
-	       struct rte_mbuf *pkt,
-	       uint32_t send_flags)
+	       struct rte_mbuf *pkt)
 {
 	struct mlx4_wqe_ctrl_seg *ctrl;
 	struct mlx4_wqe_data_seg *dseg;
 	struct mlx4_sq *sq = &txq->msq;
+	struct rte_mbuf *buf;
 	uint32_t head_idx = sq->head & sq->txbb_cnt_mask;
 	uint32_t lkey;
 	uintptr_t addr;
+	uint32_t srcrb_flags;
+	uint32_t owner_opcode = MLX4_OPCODE_SEND;
+	uint32_t byte_count;
 	int wqe_real_size;
 	int nr_txbbs;
 	int rc;
+	struct pv *pv = (struct pv *)txq->bounce_buf;
+	int pv_counter = 0;
 
 	/* Calculate the needed work queue entry size for this packet. */
 	wqe_real_size = sizeof(struct mlx4_wqe_ctrl_seg) +
 			pkt->nb_segs * sizeof(struct mlx4_wqe_data_seg);
 	nr_txbbs = MLX4_SIZE_TO_TXBBS(wqe_real_size);
-	/* Check that there is room for this WQE in the send queue and
+	/*
+	 * Check that there is room for this WQE in the send queue and
 	 * that the WQE size is legal.
 	 */
 	if (likely(((sq->head - sq->tail) + nr_txbbs +
@@ -333,76 +347,108 @@
 		rc = ENOSPC;
 		goto err;
 	}
-	/* Get the control and single-data entries of the WQE */
+	/* Get the control and data entries of the WQE. */
 	ctrl = (struct mlx4_wqe_ctrl_seg *)mlx4_get_send_wqe(sq, head_idx);
 	dseg = (struct mlx4_wqe_data_seg *)(((char *)ctrl) +
 		sizeof(struct mlx4_wqe_ctrl_seg));
-	/*
-	 * Fill the data segment with buffer information.
-	 */
-	addr = rte_pktmbuf_mtod(pkt, uintptr_t);
-	rte_prefetch0((volatile void *)addr);
-	dseg->addr = rte_cpu_to_be_64(addr);
-	/* Memory region key for this memory pool. */
-	lkey = mlx4_txq_mp2mr(txq, mlx4_txq_mb2mp(pkt));
-	if (unlikely(lkey == (uint32_t)-1)) {
-		/* MR does not exist. */
-		DEBUG("%p: unable to get MP <-> MR"
-		      " association", (void *)txq);
-		/*
-		 * Restamp entry in case of failure.
-		 * Make sure that size is written correctly.
-		 * Note that we give ownership to the SW, not the HW.
+	/* Fill the data segments with buffer information. */
+	for (buf = pkt; buf != NULL; buf = buf->next, dseg++) {
+		addr = rte_pktmbuf_mtod(buf, uintptr_t);
+		rte_prefetch0((volatile void *)addr);
+		/* Handle WQE wraparound. */
+		if (unlikely(dseg >= (struct mlx4_wqe_data_seg *)sq->eob))
+			dseg = (struct mlx4_wqe_data_seg *)sq->buf;
+		dseg->addr = rte_cpu_to_be_64(addr);
+		/* Memory region key for this memory pool. */
+		lkey = mlx4_txq_mp2mr(txq, mlx4_txq_mb2mp(buf));
+		if (unlikely(lkey == (uint32_t)-1)) {
+			/* MR does not exist. */
+			DEBUG("%p: unable to get MP <-> MR"
+			      " association", (void *)txq);
+			/*
+			 * Restamp entry in case of failure.
+			 * Make sure that size is written correctly
+			 * Note that we give ownership to the SW, not the HW.
+			 */
+			ctrl->fence_size = (wqe_real_size >> 4) & 0x3f;
+			mlx4_txq_stamp_freed_wqe(sq, head_idx,
+				     (sq->head & sq->txbb_cnt) ? 0 : 1);
+			rc = EFAULT;
+			goto err;
+		}
+		dseg->lkey = rte_cpu_to_be_32(lkey);
+		if (likely(buf->data_len))
+			byte_count = rte_cpu_to_be_32(buf->data_len);
+		else
+			/*
+			 * Zero length segment is treated as inline segment
+			 * with zero data.
+			 */
+			byte_count = RTE_BE32(0x80000000);
+		/* If the data segment is not at the beginning of a
+		 * Tx basic block(TXBB) then write the byte count,
+		 * else postpone the writing to just before updating the
+		 * control segment.
 		 */
-		ctrl->fence_size = (wqe_real_size >> 4) & 0x3f;
-		mlx4_txq_stamp_freed_wqe(sq, head_idx,
-					 (sq->head & sq->txbb_cnt) ? 0 : 1);
-		rc = EFAULT;
-		goto err;
+		if ((uintptr_t)dseg & (uintptr_t)(MLX4_TXBB_SIZE - 1)) {
+			/*
+			 * Need a barrier here before writing the byte_count
+			 * fields to make sure that all the data is visible
+			 * before the byte_count field is set.
+			 * Otherwise, if the segment begins a new cacheline,
+			 * the HCA prefetcher could grab the 64-byte chunk and
+			 * get a valid (!= * 0xffffffff) byte count but stale
+			 * data, and end up sending the wrong data.
+			 */
+			rte_io_wmb();
+			dseg->byte_count = byte_count;
+		} else {
+			/*
+			 * This data segment starts at the beginning of a new
+			 * TXBB, so we need to postpone its byte_count writing
+			 * for later.
+			 */
+			pv[pv_counter].dseg = dseg;
+			pv[pv_counter++].val = byte_count;
+		}
 	}
-	dseg->lkey = rte_cpu_to_be_32(lkey);
-	/*
-	 * Need a barrier here before writing the byte_count field to
-	 * make sure that all the data is visible before the
-	 * byte_count field is set.  Otherwise, if the segment begins
-	 * a new cacheline, the HCA prefetcher could grab the 64-byte
-	 * chunk and get a valid (!= * 0xffffffff) byte count but
-	 * stale data, and end up sending the wrong data.
-	 */
-	rte_io_wmb();
-	if (likely(pkt->data_len))
-		dseg->byte_count = rte_cpu_to_be_32(pkt->data_len);
-	else
-		/*
-		 * Zero length segment is treated as inline segment
-		 * with zero data.
-		 */
-		dseg->byte_count = RTE_BE32(0x80000000);
-	/*
-	 * Fill the control parameters for this packet.
-	 * For raw Ethernet, the SOLICIT flag is used to indicate that no icrc
-	 * should be calculated
-	 */
-	ctrl->srcrb_flags =
-		rte_cpu_to_be_32(MLX4_WQE_CTRL_SOLICIT |
-				 (send_flags & MLX4_WQE_CTRL_CQ_UPDATE));
+	/* Write the first DWORD of each TXBB save earlier. */
+	if (pv_counter) {
+		/* Need a barrier here before writing the byte_count. */
+		rte_io_wmb();
+		for (--pv_counter; pv_counter  >= 0; pv_counter--)
+			pv[pv_counter].dseg->byte_count = pv[pv_counter].val;
+	}
+	/* Fill the control parameters for this packet. */
 	ctrl->fence_size = (wqe_real_size >> 4) & 0x3f;
 	/*
 	 * The caller should prepare "imm" in advance in order to support
 	 * VF to VF communication (when the device is a virtual-function
 	 * device (VF)).
-	 */
+	*/
 	ctrl->imm = 0;
 	/*
+	 * For raw Ethernet, the SOLICIT flag is used to indicate that no icrc
+	 * should be calculated.
+	 */
+	txq->elts_comp_cd -= nr_txbbs;
+	if (unlikely(txq->elts_comp_cd <= 0)) {
+		txq->elts_comp_cd = txq->elts_comp_cd_init;
+		srcrb_flags = RTE_BE32(MLX4_WQE_CTRL_SOLICIT |
+				       MLX4_WQE_CTRL_CQ_UPDATE);
+	} else {
+		srcrb_flags = RTE_BE32(MLX4_WQE_CTRL_SOLICIT);
+	}
+	ctrl->srcrb_flags = srcrb_flags;
+	/*
 	 * Make sure descriptor is fully written before
 	 * setting ownership bit (because HW can start
 	 * executing as soon as we do).
 	 */
-	rte_wmb();
-	ctrl->owner_opcode =
-		rte_cpu_to_be_32(MLX4_OPCODE_SEND |
-				 ((sq->head & sq->txbb_cnt) ?
-				  MLX4_BIT_WQE_OWN : 0));
+	 rte_wmb();
+	 ctrl->owner_opcode = rte_cpu_to_be_32(owner_opcode |
+					       ((sq->head & sq->txbb_cnt) ?
+					       MLX4_BIT_WQE_OWN : 0));
 	sq->head += nr_txbbs;
 	return 0;
 err:
@@ -429,14 +475,13 @@
 	struct txq *txq = (struct txq *)dpdk_txq;
 	unsigned int elts_head = txq->elts_head;
 	const unsigned int elts_n = txq->elts_n;
-	unsigned int elts_comp_cd = txq->elts_comp_cd;
 	unsigned int elts_comp = 0;
 	unsigned int bytes_sent = 0;
 	unsigned int i;
 	unsigned int max;
 	int err;
 
-	assert(elts_comp_cd != 0);
+	assert(txq->elts_comp_cd != 0);
 	mlx4_txq_complete(txq);
 	max = (elts_n - (elts_head - txq->elts_tail));
 	if (max > elts_n)
@@ -455,8 +500,6 @@
 			(((elts_head + 1) == elts_n) ? 0 : elts_head + 1);
 		struct txq_elt *elt_next = &(*txq->elts)[elts_head_next];
 		struct txq_elt *elt = &(*txq->elts)[elts_head];
-		unsigned int segs = buf->nb_segs;
-		uint32_t send_flags = 0;
 
 		/* Clean up old buffer. */
 		if (likely(elt->buf != NULL)) {
@@ -474,34 +517,16 @@
 				tmp = next;
 			} while (tmp != NULL);
 		}
-		/* Request Tx completion. */
-		if (unlikely(--elts_comp_cd == 0)) {
-			elts_comp_cd = txq->elts_comp_cd_init;
-			++elts_comp;
-			send_flags |= MLX4_WQE_CTRL_CQ_UPDATE;
-		}
-		if (likely(segs == 1)) {
-			/* Update element. */
-			elt->buf = buf;
-			RTE_MBUF_PREFETCH_TO_FREE(elt_next->buf);
-			/* post the pkt for sending */
-			err = mlx4_post_send(txq, buf, send_flags);
-			if (unlikely(err)) {
-				if (unlikely(send_flags &
-					     MLX4_WQE_CTRL_CQ_UPDATE)) {
-					elts_comp_cd = 1;
-					--elts_comp;
-				}
-				elt->buf = NULL;
-				goto stop;
-			}
-			elt->buf = buf;
-			bytes_sent += buf->pkt_len;
-		} else {
-			err = -EINVAL;
-			rte_errno = -err;
+		RTE_MBUF_PREFETCH_TO_FREE(elt_next->buf);
+		/* post the packet for sending. */
+		err = mlx4_post_send(txq, buf);
+		if (unlikely(err)) {
+			elt->buf = NULL;
 			goto stop;
 		}
+		elt->buf = buf;
+		bytes_sent += buf->pkt_len;
+		++elts_comp;
 		elts_head = elts_head_next;
 	}
 stop:
@@ -517,7 +542,6 @@
 	rte_write32(txq->msq.doorbell_qpn, txq->msq.db);
 	txq->elts_head = elts_head;
 	txq->elts_comp += elts_comp;
-	txq->elts_comp_cd = elts_comp_cd;
 	return i;
 }
 
diff --git a/drivers/net/mlx4/mlx4_rxtx.h b/drivers/net/mlx4/mlx4_rxtx.h
index df83552..1b90533 100644
--- a/drivers/net/mlx4/mlx4_rxtx.h
+++ b/drivers/net/mlx4/mlx4_rxtx.h
@@ -103,13 +103,15 @@ struct txq {
 	struct mlx4_cq mcq; /**< Info for directly manipulating the CQ. */
 	unsigned int elts_head; /**< Current index in (*elts)[]. */
 	unsigned int elts_tail; /**< First element awaiting completion. */
-	unsigned int elts_comp; /**< Number of completion requests. */
-	unsigned int elts_comp_cd; /**< Countdown for next completion. */
+	unsigned int elts_comp; /**< Number of pkts waiting for completion. */
+	int elts_comp_cd; /**< Countdown for next completion. */
 	unsigned int elts_comp_cd_init; /**< Initial value for countdown. */
 	unsigned int elts_n; /**< (*elts)[] length. */
 	struct txq_elt (*elts)[]; /**< Tx elements. */
 	struct mlx4_txq_stats stats; /**< Tx queue counters. */
 	uint32_t max_inline; /**< Max inline send size. */
+	char *bounce_buf;
+	/**< memory used for storing the first DWORD of data TXBBs. */
 	struct {
 		const struct rte_mempool *mp; /**< Cached memory pool. */
 		struct ibv_mr *mr; /**< Memory region (for mp). */
diff --git a/drivers/net/mlx4/mlx4_txq.c b/drivers/net/mlx4/mlx4_txq.c
index 492779f..bbdeda3 100644
--- a/drivers/net/mlx4/mlx4_txq.c
+++ b/drivers/net/mlx4/mlx4_txq.c
@@ -83,8 +83,14 @@
 		rte_calloc_socket("TXQ", 1, sizeof(*elts), 0, txq->ctrl.socket);
 	int ret = 0;
 
-	if (elts == NULL) {
-		ERROR("%p: can't allocate packets array", (void *)txq);
+	/* Allocate Bounce-buf memory */
+	txq->bounce_buf = (char *)rte_zmalloc_socket("TXQ",
+						     MLX4_MAX_WQE_SIZE,
+						     RTE_CACHE_LINE_MIN_SIZE,
+						     txq->ctrl.socket);
+
+	if (elts == NULL || txq->bounce_buf == NULL) {
+		ERROR("%p: can't allocate TXQ memory", (void *)txq);
 		ret = ENOMEM;
 		goto error;
 	}
@@ -110,6 +116,7 @@
 	assert(ret == 0);
 	return 0;
 error:
+	rte_free(txq->bounce_buf);
 	rte_free(elts);
 	DEBUG("%p: failed, freed everything", (void *)txq);
 	assert(ret > 0);
@@ -303,7 +310,6 @@ struct txq_mp2mr_mbuf_check_data {
 	struct mlx4dv_obj mlxdv;
 	struct mlx4dv_qp dv_qp;
 	struct mlx4dv_cq dv_cq;
-
 	struct txq tmpl = {
 		.ctrl = {
 			.priv = priv,
-- 
1.8.3.1

^ permalink raw reply related

* [PATCH v3 5/7] net/mlx4: get back Tx checksum offloads
From: Ophir Munk @ 2017-10-04 21:49 UTC (permalink / raw)
  To: Adrien Mazarguil
  Cc: dev, Thomas Monjalon, Olga Shern, Matan Azrad, Moti Haimovsky
In-Reply-To: <1507153746-31255-1-git-send-email-ophirmu@mellanox.com>

From: Moti Haimovsky <motih@mellanox.com>

This patch adds hardware offloading support for IPV4, UDP and TCP
checksum calculation.
This commit also includes support for offloading IPV4, UDP and TCP
tunnel checksum calculation to the hardware.

Signed-off-by: Moti Haimovsky <motih@mellanox.com>
---
 drivers/net/mlx4/mlx4.c        |  9 +++++++++
 drivers/net/mlx4/mlx4.h        |  2 ++
 drivers/net/mlx4/mlx4_ethdev.c |  6 ++++++
 drivers/net/mlx4/mlx4_prm.h    |  2 ++
 drivers/net/mlx4/mlx4_rxtx.c   | 25 +++++++++++++++++++++----
 drivers/net/mlx4/mlx4_rxtx.h   |  2 ++
 drivers/net/mlx4/mlx4_txq.c    |  2 ++
 7 files changed, 44 insertions(+), 4 deletions(-)

diff --git a/drivers/net/mlx4/mlx4.c b/drivers/net/mlx4/mlx4.c
index b084903..a0e76ee 100644
--- a/drivers/net/mlx4/mlx4.c
+++ b/drivers/net/mlx4/mlx4.c
@@ -397,6 +397,7 @@ struct mlx4_conf {
 		.ports.present = 0,
 	};
 	unsigned int vf;
+	unsigned int tunnel_en;
 	int i;
 
 	(void)pci_drv;
@@ -456,6 +457,9 @@ struct mlx4_conf {
 		rte_errno = ENODEV;
 		goto error;
 	}
+	/* Only cx3-pro supports L3 tunneling */
+	tunnel_en = (device_attr.vendor_part_id ==
+		     PCI_DEVICE_ID_MELLANOX_CONNECTX3PRO);
 	INFO("%u port(s) detected", device_attr.phys_port_cnt);
 	conf.ports.present |= (UINT64_C(1) << device_attr.phys_port_cnt) - 1;
 	if (mlx4_args(pci_dev->device.devargs, &conf)) {
@@ -529,6 +533,11 @@ struct mlx4_conf {
 		priv->pd = pd;
 		priv->mtu = ETHER_MTU;
 		priv->vf = vf;
+		priv->hw_csum =
+		     !!(device_attr.device_cap_flags & IBV_DEVICE_RAW_IP_CSUM);
+		priv->hw_csum_l2tun = tunnel_en;
+		DEBUG("L2 tunnel checksum offloads are %ssupported",
+		      (priv->hw_csum_l2tun ? "" : "not "));
 		/* Configure the first MAC address by default. */
 		if (mlx4_get_mac(priv, &mac.addr_bytes)) {
 			ERROR("cannot get MAC address, is mlx4_en loaded?"
diff --git a/drivers/net/mlx4/mlx4.h b/drivers/net/mlx4/mlx4.h
index b6e1ef2..d0bce91 100644
--- a/drivers/net/mlx4/mlx4.h
+++ b/drivers/net/mlx4/mlx4.h
@@ -93,6 +93,8 @@ struct priv {
 	unsigned int vf:1; /* This is a VF device. */
 	unsigned int intr_alarm:1; /* An interrupt alarm is scheduled. */
 	unsigned int isolated:1; /* Toggle isolated mode. */
+	unsigned int hw_csum:1; /* Checksum offload is supported. */
+	unsigned int hw_csum_l2tun:1; /* Checksum support for L2 tunnels. */
 	struct rte_intr_handle intr_handle; /* Port interrupt handle. */
 	struct rte_flow_drop *flow_drop_queue; /* Flow drop queue. */
 	LIST_HEAD(mlx4_flows, rte_flow) flows;
diff --git a/drivers/net/mlx4/mlx4_ethdev.c b/drivers/net/mlx4/mlx4_ethdev.c
index a9e8059..95cc6e4 100644
--- a/drivers/net/mlx4/mlx4_ethdev.c
+++ b/drivers/net/mlx4/mlx4_ethdev.c
@@ -553,6 +553,12 @@
 	info->max_mac_addrs = 1;
 	info->rx_offload_capa = 0;
 	info->tx_offload_capa = 0;
+	if (priv->hw_csum)
+		info->tx_offload_capa |= (DEV_TX_OFFLOAD_IPV4_CKSUM |
+					  DEV_TX_OFFLOAD_UDP_CKSUM  |
+					  DEV_TX_OFFLOAD_TCP_CKSUM);
+	if (priv->hw_csum_l2tun)
+		info->tx_offload_capa |= DEV_TX_OFFLOAD_OUTER_IPV4_CKSUM;
 	if (mlx4_get_ifname(priv, &ifname) == 0)
 		info->if_index = if_nametoindex(ifname);
 	info->speed_capa =
diff --git a/drivers/net/mlx4/mlx4_prm.h b/drivers/net/mlx4/mlx4_prm.h
index 6d1800a..57f5a46 100644
--- a/drivers/net/mlx4/mlx4_prm.h
+++ b/drivers/net/mlx4/mlx4_prm.h
@@ -64,6 +64,8 @@
 
 /* Work queue element (WQE) flags. */
 #define MLX4_BIT_WQE_OWN 0x80000000
+#define MLX4_WQE_CTRL_IIP_HDR_CSUM (1 << 28)
+#define MLX4_WQE_CTRL_IL4_HDR_CSUM (1 << 27)
 
 #define MLX4_SIZE_TO_TXBBS(size) \
 		(RTE_ALIGN((size), (MLX4_TXBB_SIZE)) >> (MLX4_TXBB_SHIFT))
diff --git a/drivers/net/mlx4/mlx4_rxtx.c b/drivers/net/mlx4/mlx4_rxtx.c
index bc0e353..ea92ebb 100644
--- a/drivers/net/mlx4/mlx4_rxtx.c
+++ b/drivers/net/mlx4/mlx4_rxtx.c
@@ -434,12 +434,29 @@ struct pv {
 	txq->elts_comp_cd -= nr_txbbs;
 	if (unlikely(txq->elts_comp_cd <= 0)) {
 		txq->elts_comp_cd = txq->elts_comp_cd_init;
-		srcrb_flags = RTE_BE32(MLX4_WQE_CTRL_SOLICIT |
-				       MLX4_WQE_CTRL_CQ_UPDATE);
+		srcrb_flags = MLX4_WQE_CTRL_SOLICIT | MLX4_WQE_CTRL_CQ_UPDATE;
 	} else {
-		srcrb_flags = RTE_BE32(MLX4_WQE_CTRL_SOLICIT);
+		srcrb_flags = MLX4_WQE_CTRL_SOLICIT;
 	}
-	ctrl->srcrb_flags = srcrb_flags;
+	/* Enable HW checksum offload if requested */
+	if (txq->csum &&
+	    (pkt->ol_flags &
+	     (PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM | PKT_TX_UDP_CKSUM))) {
+		const uint64_t is_tunneled = pkt->ol_flags &
+					     (PKT_TX_TUNNEL_GRE |
+					      PKT_TX_TUNNEL_VXLAN);
+
+		if (is_tunneled && txq->csum_l2tun) {
+			owner_opcode |= MLX4_WQE_CTRL_IIP_HDR_CSUM |
+					MLX4_WQE_CTRL_IL4_HDR_CSUM;
+			if (pkt->ol_flags & PKT_TX_OUTER_IP_CKSUM)
+				srcrb_flags |= MLX4_WQE_CTRL_IP_HDR_CSUM;
+		} else {
+			srcrb_flags |= MLX4_WQE_CTRL_IP_HDR_CSUM |
+				      MLX4_WQE_CTRL_TCP_UDP_CSUM;
+		}
+	}
+	ctrl->srcrb_flags = rte_cpu_to_be_32(srcrb_flags);
 	/*
 	 * Make sure descriptor is fully written before
 	 * setting ownership bit (because HW can start
diff --git a/drivers/net/mlx4/mlx4_rxtx.h b/drivers/net/mlx4/mlx4_rxtx.h
index 1b90533..dc283e1 100644
--- a/drivers/net/mlx4/mlx4_rxtx.h
+++ b/drivers/net/mlx4/mlx4_rxtx.h
@@ -110,6 +110,8 @@ struct txq {
 	struct txq_elt (*elts)[]; /**< Tx elements. */
 	struct mlx4_txq_stats stats; /**< Tx queue counters. */
 	uint32_t max_inline; /**< Max inline send size. */
+	uint32_t csum:1; /**< Checksum is supported and enabled */
+	uint32_t csum_l2tun:1; /**< L2 tun Checksum is supported and enabled */
 	char *bounce_buf;
 	/**< memory used for storing the first DWORD of data TXBBs. */
 	struct {
diff --git a/drivers/net/mlx4/mlx4_txq.c b/drivers/net/mlx4/mlx4_txq.c
index bbdeda3..4eb739c 100644
--- a/drivers/net/mlx4/mlx4_txq.c
+++ b/drivers/net/mlx4/mlx4_txq.c
@@ -340,6 +340,8 @@ struct txq_mp2mr_mbuf_check_data {
 		      (void *)dev, strerror(rte_errno));
 		goto error;
 	}
+	tmpl.csum = priv->hw_csum;
+	tmpl.csum_l2tun = priv->hw_csum_l2tun;
 	DEBUG("priv->device_attr.max_qp_wr is %d",
 	      priv->device_attr.max_qp_wr);
 	DEBUG("priv->device_attr.max_sge is %d",
-- 
1.8.3.1

^ permalink raw reply related

* [PATCH v3 3/7] net/mlx4: support multi-segments Rx
From: Ophir Munk @ 2017-10-04 21:49 UTC (permalink / raw)
  To: Adrien Mazarguil
  Cc: dev, Thomas Monjalon, Olga Shern, Matan Azrad, Vasily Philipov,
	Ophir Munk
In-Reply-To: <1507153746-31255-1-git-send-email-ophirmu@mellanox.com>

From: Vasily Philipov <vasilyf@mellanox.com>

Getting hw directly on RX fast path without verbs call.

Now the number of scatters is calculated on the fly according to the
maximum expected packet size.

Signed-off-by: Vasily Philipov <vasilyf@mellanox.com>
Signed-off-by: Ophir Munk <ophirmu@mellanox.com>
---
This commit is a split from a previous commit
"net/mlx4: get back Rx flow functionality"

 drivers/net/mlx4/mlx4_rxq.c  | 29 ++++++++++++++++++++++-------
 drivers/net/mlx4/mlx4_rxtx.c | 10 +++++++---
 drivers/net/mlx4/mlx4_rxtx.h |  1 +
 3 files changed, 30 insertions(+), 10 deletions(-)

diff --git a/drivers/net/mlx4/mlx4_rxq.c b/drivers/net/mlx4/mlx4_rxq.c
index cb18f20..7d13121 100644
--- a/drivers/net/mlx4/mlx4_rxq.c
+++ b/drivers/net/mlx4/mlx4_rxq.c
@@ -78,6 +78,7 @@
 mlx4_rxq_alloc_elts(struct rxq *rxq, unsigned int elts_n)
 {
 	unsigned int i;
+	const unsigned int sge_n = 1 << rxq->sge_n;
 	struct rte_mbuf *(*elts)[elts_n] =
 		rte_calloc_socket("RXQ", 1, sizeof(*elts), 0, rxq->socket);
 
@@ -105,6 +106,9 @@
 		assert(rte_pktmbuf_data_len(buf) == 0);
 		assert(rte_pktmbuf_pkt_len(buf) == 0);
 		assert(!buf->next);
+		/* Only the first segment keeps headroom. */
+		if (i % sge_n)
+			buf->data_off = 0;
 		buf->port = rxq->port_id;
 		buf->data_len = rte_pktmbuf_tailroom(buf);
 		buf->pkt_len = rte_pktmbuf_tailroom(buf);
@@ -119,8 +123,8 @@
 		};
 		(*rxq->elts)[i] = buf;
 	}
-	DEBUG("%p: allocated and configured %u single-segment WRs",
-	      (void *)rxq, elts_n);
+	DEBUG("%p: allocated and configured %u segments (max %u packets)",
+	      (void *)rxq, elts_n, elts_n >> rxq->sge_n);
 	rxq->elts_n = log2above(elts_n);
 	return 0;
 error:
@@ -199,7 +203,8 @@
  *   QP pointer or NULL in case of error and rte_errno is set.
  */
 static struct ibv_qp *
-mlx4_rxq_setup_qp(struct priv *priv, struct ibv_cq *cq, uint16_t desc)
+mlx4_rxq_setup_qp(struct priv *priv, struct ibv_cq *cq,
+		  uint16_t desc, unsigned int sge_n)
 {
 	struct ibv_qp *qp;
 	struct ibv_qp_init_attr attr = {
@@ -213,7 +218,7 @@
 					priv->device_attr.max_qp_wr :
 					desc),
 			/* Max number of scatter/gather elements in a WR. */
-			.max_recv_sge = 1,
+			.max_recv_sge = sge_n,
 		},
 		.qp_type = IBV_QPT_RAW_PACKET,
 	};
@@ -267,8 +272,9 @@
 	assert(mb_len >= RTE_PKTMBUF_HEADROOM);
 	if (dev->data->dev_conf.rxmode.max_rx_pkt_len <=
 	    (mb_len - RTE_PKTMBUF_HEADROOM)) {
-		;
+		tmpl.sge_n = 0;
 	} else if (dev->data->dev_conf.rxmode.enable_scatter) {
+		unsigned int sge_n;
 		unsigned int rx_pkt_len =
 				dev->data->dev_conf.rxmode.jumbo_frame ?
 				dev->data->dev_conf.rxmode.max_rx_pkt_len :
@@ -278,6 +284,13 @@
 			rx_pkt_len = ETHER_MTU;
 		/* Only the first mbuf has a headroom */
 		rx_pkt_len = rx_pkt_len - mb_len + RTE_PKTMBUF_HEADROOM;
+		/*
+		 * Determine the number of SGEs needed for a full packet
+		 * and round it to the next power of two.
+		 */
+		sge_n = (rx_pkt_len / mb_len) + !!(rx_pkt_len % mb_len) + 1;
+		tmpl.sge_n = log2above(sge_n);
+		desc >>= tmpl.sge_n;
 	} else {
 		WARN("%p: the requested maximum Rx packet size (%u) is"
 		     " larger than a single mbuf (%u) and scattered"
@@ -286,6 +299,8 @@
 		     dev->data->dev_conf.rxmode.max_rx_pkt_len,
 		     mb_len - RTE_PKTMBUF_HEADROOM);
 	}
+	DEBUG("%p: number of sges %u (%u WRs)",
+	      (void *)dev, 1 << tmpl.sge_n, desc);
 	/* Use the entire Rx mempool as the memory region. */
 	tmpl.mr = mlx4_mp2mr(priv->pd, mp);
 	if (tmpl.mr == NULL) {
@@ -321,7 +336,7 @@
 	      priv->device_attr.max_qp_wr);
 	DEBUG("priv->device_attr.max_sge is %d",
 	      priv->device_attr.max_sge);
-	tmpl.qp = mlx4_rxq_setup_qp(priv, tmpl.cq, desc);
+	tmpl.qp = mlx4_rxq_setup_qp(priv, tmpl.cq, desc, 1 << tmpl.sge_n);
 	if (tmpl.qp == NULL) {
 		ERROR("%p: QP creation failure: %s",
 		      (void *)dev, strerror(rte_errno));
@@ -373,7 +388,7 @@
 	/* Save port ID. */
 	tmpl.port_id = dev->data->port_id;
 	DEBUG("%p: RTE port ID: %u", (void *)rxq, tmpl.port_id);
-	ret = mlx4_rxq_alloc_elts(&tmpl, desc);
+	ret = mlx4_rxq_alloc_elts(&tmpl, desc << tmpl.sge_n);
 	if (ret) {
 		ERROR("%p: RXQ allocation failed: %s",
 		      (void *)dev, strerror(rte_errno));
diff --git a/drivers/net/mlx4/mlx4_rxtx.c b/drivers/net/mlx4/mlx4_rxtx.c
index b4391bf..f517505 100644
--- a/drivers/net/mlx4/mlx4_rxtx.c
+++ b/drivers/net/mlx4/mlx4_rxtx.c
@@ -577,10 +577,11 @@
 {
 	struct rxq *rxq = dpdk_rxq;
 	const unsigned int wr_cnt = (1 << rxq->elts_n) - 1;
+	const unsigned int sge_n = rxq->sge_n;
 	struct rte_mbuf *pkt = NULL;
 	struct rte_mbuf *seg = NULL;
 	unsigned int i = 0;
-	unsigned int rq_ci = (rxq->hw.rq_ci);
+	unsigned int rq_ci = (rxq->hw.rq_ci << sge_n);
 	int len = 0;
 
 	while (pkts_n) {
@@ -661,12 +662,15 @@
 		--pkts_n;
 		++i;
 skip:
+		/* Align consumer index to the next stride. */
+		rq_ci >>= sge_n;
 		++rq_ci;
+		rq_ci <<= sge_n;
 	}
-	if (unlikely(i == 0 && rq_ci == rxq->hw.rq_ci))
+	if (unlikely(i == 0 && (rq_ci >> sge_n) == rxq->hw.rq_ci))
 		return 0;
 	/* Update the consumer index. */
-	rxq->hw.rq_ci = rq_ci;
+	rxq->hw.rq_ci = rq_ci >> sge_n;
 	rte_wmb();
 	*rxq->hw.rq_db = rte_cpu_to_be_32(rxq->hw.rq_ci);
 	*rxq->mcq.set_ci_db =
diff --git a/drivers/net/mlx4/mlx4_rxtx.h b/drivers/net/mlx4/mlx4_rxtx.h
index fa2481c..df83552 100644
--- a/drivers/net/mlx4/mlx4_rxtx.h
+++ b/drivers/net/mlx4/mlx4_rxtx.h
@@ -79,6 +79,7 @@ struct rxq {
 		uint16_t rq_ci;
 	} hw;
 	struct mlx4_cq mcq;  /**< Info for directly manipulating the CQ. */
+	unsigned int sge_n; /**< Log 2 of SGEs number. */
 	struct mlx4_rxq_stats stats; /**< Rx queue counters. */
 	unsigned int socket; /**< CPU socket ID for allocations. */
 };
-- 
1.8.3.1

^ permalink raw reply related

* [PATCH v3 2/7] net/mlx4: get back Rx flow functionality
From: Ophir Munk @ 2017-10-04 21:49 UTC (permalink / raw)
  To: Adrien Mazarguil
  Cc: dev, Thomas Monjalon, Olga Shern, Matan Azrad, Moti Haimovsky,
	Vasily Philipov, Ophir Munk
In-Reply-To: <1507153746-31255-1-git-send-email-ophirmu@mellanox.com>

From: Moti Haimovsky <motih@mellanox.com>

This patch adds support for accessing the hardware directly when
handling Rx packets eliminating the need to use verbs in the Rx
datapath.

The number of scatters is limited to one.

Signed-off-by: Vasily Philipov <vasilyf@mellanox.com>
Signed-off-by: Moti Haimovsky <motih@mellanox.com>
Signed-off-by: Ophir Munk <ophirmu@mellanox.com>
---
 drivers/net/mlx4/mlx4.h       |  11 ---
 drivers/net/mlx4/mlx4_rxq.c   | 149 ++++++++++++++++------------
 drivers/net/mlx4/mlx4_rxtx.c  | 225 ++++++++++++++++++++++++------------------
 drivers/net/mlx4/mlx4_rxtx.h  |  18 ++--
 drivers/net/mlx4/mlx4_utils.h |  20 ++++
 5 files changed, 242 insertions(+), 181 deletions(-)

diff --git a/drivers/net/mlx4/mlx4.h b/drivers/net/mlx4/mlx4.h
index 93e5502..b6e1ef2 100644
--- a/drivers/net/mlx4/mlx4.h
+++ b/drivers/net/mlx4/mlx4.h
@@ -57,17 +57,6 @@
 /* Maximum size for inline data. */
 #define MLX4_PMD_MAX_INLINE 0
 
-/*
- * Maximum number of cached Memory Pools (MPs) per TX queue. Each RTE MP
- * from which buffers are to be transmitted will have to be mapped by this
- * driver to their own Memory Region (MR). This is a slow operation.
- *
- * This value is always 1 for RX queues.
- */
-#ifndef MLX4_PMD_TX_MP_CACHE
-#define MLX4_PMD_TX_MP_CACHE 8
-#endif
-
 /* Interrupt alarm timeout value in microseconds. */
 #define MLX4_INTR_ALARM_TIMEOUT 100000
 
diff --git a/drivers/net/mlx4/mlx4_rxq.c b/drivers/net/mlx4/mlx4_rxq.c
index 409983f..cb18f20 100644
--- a/drivers/net/mlx4/mlx4_rxq.c
+++ b/drivers/net/mlx4/mlx4_rxq.c
@@ -51,6 +51,7 @@
 #pragma GCC diagnostic error "-Wpedantic"
 #endif
 
+#include <rte_byteorder.h>
 #include <rte_common.h>
 #include <rte_errno.h>
 #include <rte_ethdev.h>
@@ -77,60 +78,59 @@
 mlx4_rxq_alloc_elts(struct rxq *rxq, unsigned int elts_n)
 {
 	unsigned int i;
-	struct rxq_elt (*elts)[elts_n] =
-		rte_calloc_socket("RXQ elements", 1, sizeof(*elts), 0,
-				  rxq->socket);
+	struct rte_mbuf *(*elts)[elts_n] =
+		rte_calloc_socket("RXQ", 1, sizeof(*elts), 0, rxq->socket);
 
 	if (elts == NULL) {
+		elts_n = 0;
 		rte_errno = ENOMEM;
 		ERROR("%p: can't allocate packets array", (void *)rxq);
 		goto error;
 	}
-	/* For each WR (packet). */
-	for (i = 0; (i != elts_n); ++i) {
-		struct rxq_elt *elt = &(*elts)[i];
-		struct ibv_recv_wr *wr = &elt->wr;
-		struct ibv_sge *sge = &(*elts)[i].sge;
-		struct rte_mbuf *buf = rte_pktmbuf_alloc(rxq->mp);
+	rxq->elts = elts;
+	for (i = 0; i != elts_n; ++i) {
+		struct rte_mbuf *buf;
+		volatile struct mlx4_wqe_data_seg *scat =
+			&(*rxq->hw.wqes)[i];
 
+		buf = rte_pktmbuf_alloc(rxq->mp);
 		if (buf == NULL) {
 			rte_errno = ENOMEM;
 			ERROR("%p: empty mbuf pool", (void *)rxq);
 			goto error;
 		}
-		elt->buf = buf;
-		wr->next = &(*elts)[(i + 1)].wr;
-		wr->sg_list = sge;
-		wr->num_sge = 1;
 		/* Headroom is reserved by rte_pktmbuf_alloc(). */
 		assert(buf->data_off == RTE_PKTMBUF_HEADROOM);
 		/* Buffer is supposed to be empty. */
 		assert(rte_pktmbuf_data_len(buf) == 0);
 		assert(rte_pktmbuf_pkt_len(buf) == 0);
-		/* sge->addr must be able to store a pointer. */
-		assert(sizeof(sge->addr) >= sizeof(uintptr_t));
-		/* SGE keeps its headroom. */
-		sge->addr = (uintptr_t)
-			((uint8_t *)buf->buf_addr + RTE_PKTMBUF_HEADROOM);
-		sge->length = (buf->buf_len - RTE_PKTMBUF_HEADROOM);
-		sge->lkey = rxq->mr->lkey;
-		/* Redundant check for tailroom. */
-		assert(sge->length == rte_pktmbuf_tailroom(buf));
+		assert(!buf->next);
+		buf->port = rxq->port_id;
+		buf->data_len = rte_pktmbuf_tailroom(buf);
+		buf->pkt_len = rte_pktmbuf_tailroom(buf);
+		buf->nb_segs = 1;
+		/* scat->addr must be able to store a pointer. */
+		assert(sizeof(scat->addr) >= sizeof(uintptr_t));
+		*scat = (struct mlx4_wqe_data_seg){
+			.addr =
+			    rte_cpu_to_be_64(rte_pktmbuf_mtod(buf, uintptr_t)),
+			.byte_count = rte_cpu_to_be_32(buf->data_len),
+			.lkey = rte_cpu_to_be_32(rxq->mr->lkey),
+		};
+		(*rxq->elts)[i] = buf;
 	}
-	/* The last WR pointer must be NULL. */
-	(*elts)[(i - 1)].wr.next = NULL;
 	DEBUG("%p: allocated and configured %u single-segment WRs",
 	      (void *)rxq, elts_n);
-	rxq->elts_n = elts_n;
-	rxq->elts_head = 0;
-	rxq->elts = elts;
+	rxq->elts_n = log2above(elts_n);
 	return 0;
 error:
-	if (elts != NULL) {
-		for (i = 0; (i != RTE_DIM(*elts)); ++i)
-			rte_pktmbuf_free_seg((*elts)[i].buf);
-		rte_free(elts);
+	for (i = 0; i != elts_n; ++i) {
+		if ((*rxq->elts)[i] != NULL)
+			rte_pktmbuf_free_seg((*rxq->elts)[i]);
+		(*rxq->elts)[i] = NULL;
 	}
+	rte_free(rxq->elts);
+	rxq->elts = NULL;
 	DEBUG("%p: failed, freed everything", (void *)rxq);
 	assert(rte_errno > 0);
 	return -rte_errno;
@@ -146,17 +146,18 @@
 mlx4_rxq_free_elts(struct rxq *rxq)
 {
 	unsigned int i;
-	unsigned int elts_n = rxq->elts_n;
-	struct rxq_elt (*elts)[elts_n] = rxq->elts;
 
 	DEBUG("%p: freeing WRs", (void *)rxq);
+	if (rxq->elts == NULL)
+		return;
+
+	for (i = 0; i != (1u << rxq->elts_n); ++i) {
+		if ((*rxq->elts)[i] != NULL)
+			rte_pktmbuf_free_seg((*rxq->elts)[i]);
+	}
+	rte_free(rxq->elts);
 	rxq->elts_n = 0;
 	rxq->elts = NULL;
-	if (elts == NULL)
-		return;
-	for (i = 0; (i != RTE_DIM(*elts)); ++i)
-		rte_pktmbuf_free_seg((*elts)[i].buf);
-	rte_free(elts);
 }
 
 /**
@@ -248,32 +249,35 @@
 	       struct rte_mempool *mp)
 {
 	struct priv *priv = dev->data->dev_private;
+	struct mlx4dv_obj mlxdv;
+	struct mlx4dv_qp dv_qp;
+	struct mlx4dv_cq dv_cq;
 	struct rxq tmpl = {
 		.priv = priv,
 		.mp = mp,
 		.socket = socket
 	};
 	struct ibv_qp_attr mod;
-	struct ibv_recv_wr *bad_wr;
 	unsigned int mb_len;
 	int ret;
 
 	(void)conf; /* Thresholds configuration (ignored). */
 	mb_len = rte_pktmbuf_data_room_size(mp);
-	if (desc == 0) {
-		rte_errno = EINVAL;
-		ERROR("%p: invalid number of Rx descriptors", (void *)dev);
-		goto error;
-	}
 	/* Enable scattered packets support for this queue if necessary. */
 	assert(mb_len >= RTE_PKTMBUF_HEADROOM);
 	if (dev->data->dev_conf.rxmode.max_rx_pkt_len <=
 	    (mb_len - RTE_PKTMBUF_HEADROOM)) {
 		;
 	} else if (dev->data->dev_conf.rxmode.enable_scatter) {
-		WARN("%p: scattered mode has been requested but is"
-		     " not supported, this may lead to packet loss",
-		     (void *)dev);
+		unsigned int rx_pkt_len =
+				dev->data->dev_conf.rxmode.jumbo_frame ?
+				dev->data->dev_conf.rxmode.max_rx_pkt_len :
+				ETHER_MTU;
+
+		if (rx_pkt_len < ETHER_MTU)
+			rx_pkt_len = ETHER_MTU;
+		/* Only the first mbuf has a headroom */
+		rx_pkt_len = rx_pkt_len - mb_len + RTE_PKTMBUF_HEADROOM;
 	} else {
 		WARN("%p: the requested maximum Rx packet size (%u) is"
 		     " larger than a single mbuf (%u) and scattered"
@@ -336,21 +340,6 @@
 		      (void *)dev, strerror(rte_errno));
 		goto error;
 	}
-	ret = mlx4_rxq_alloc_elts(&tmpl, desc);
-	if (ret) {
-		ERROR("%p: RXQ allocation failed: %s",
-		      (void *)dev, strerror(rte_errno));
-		goto error;
-	}
-	ret = ibv_post_recv(tmpl.qp, &(*tmpl.elts)[0].wr, &bad_wr);
-	if (ret) {
-		rte_errno = ret;
-		ERROR("%p: ibv_post_recv() failed for WR %p: %s",
-		      (void *)dev,
-		      (void *)bad_wr,
-		      strerror(rte_errno));
-		goto error;
-	}
 	mod = (struct ibv_qp_attr){
 		.qp_state = IBV_QPS_RTR
 	};
@@ -361,14 +350,44 @@
 		      (void *)dev, strerror(rte_errno));
 		goto error;
 	}
+	/* Get HW depended info */
+	mlxdv.cq.in = tmpl.cq;
+	mlxdv.cq.out = &dv_cq;
+	mlxdv.qp.in = tmpl.qp;
+	mlxdv.qp.out = &dv_qp;
+	ret = mlx4dv_init_obj(&mlxdv, MLX4DV_OBJ_QP | MLX4DV_OBJ_CQ);
+	if (ret) {
+		ERROR("%p: Failed to retrieve device obj info", (void *)dev);
+		goto error;
+	}
+	/* Init HW depended fields */
+	tmpl.hw.wqes =
+		(volatile struct mlx4_wqe_data_seg (*)[])
+		((char *)dv_qp.buf.buf + dv_qp.rq.offset);
+	tmpl.hw.rq_db = dv_qp.rdb;
+	tmpl.hw.rq_ci = 0;
+	tmpl.mcq.buf = dv_cq.buf.buf;
+	tmpl.mcq.cqe_cnt = dv_cq.cqe_cnt;
+	tmpl.mcq.set_ci_db = dv_cq.set_ci_db;
+	tmpl.mcq.cqe_64 = (dv_cq.cqe_size & 64) ? 1 : 0;
 	/* Save port ID. */
 	tmpl.port_id = dev->data->port_id;
 	DEBUG("%p: RTE port ID: %u", (void *)rxq, tmpl.port_id);
+	ret = mlx4_rxq_alloc_elts(&tmpl, desc);
+	if (ret) {
+		ERROR("%p: RXQ allocation failed: %s",
+		      (void *)dev, strerror(rte_errno));
+		goto error;
+	}
 	/* Clean up rxq in case we're reinitializing it. */
 	DEBUG("%p: cleaning-up old rxq just in case", (void *)rxq);
 	mlx4_rxq_cleanup(rxq);
 	*rxq = tmpl;
 	DEBUG("%p: rxq updated with %p", (void *)rxq, (void *)&tmpl);
+	/* Update doorbell counter. */
+	rxq->hw.rq_ci = desc;
+	rte_wmb();
+	*rxq->hw.rq_db = rte_cpu_to_be_32(rxq->hw.rq_ci);
 	return 0;
 error:
 	ret = rte_errno;
@@ -406,6 +425,12 @@
 	struct rxq *rxq = dev->data->rx_queues[idx];
 	int ret;
 
+	if (!rte_is_power_of_2(desc)) {
+		desc = 1 << log2above(desc);
+		WARN("%p: increased number of descriptors in RX queue %u"
+		     " to the next power of two (%d)",
+		     (void *)dev, idx, desc);
+	}
 	DEBUG("%p: configuring queue %u for %u descriptors",
 	      (void *)dev, idx, desc);
 	if (idx >= dev->data->nb_rx_queues) {
diff --git a/drivers/net/mlx4/mlx4_rxtx.c b/drivers/net/mlx4/mlx4_rxtx.c
index c7c190d..b4391bf 100644
--- a/drivers/net/mlx4/mlx4_rxtx.c
+++ b/drivers/net/mlx4/mlx4_rxtx.c
@@ -522,9 +522,45 @@
 }
 
 /**
- * DPDK callback for Rx.
+ * Poll one CQE from CQ.
  *
- * The following function doesn't manage scattered packets.
+ * @param rxq
+ *   Pointer to the receive queue structure.
+ * @param[out] out
+ *   Just polled CQE.
+ *
+ * @return
+ *   Number of bytes of the CQE, 0 in case there is no completion.
+ */
+static unsigned int
+mlx4_cq_poll_one(struct rxq *rxq,
+		 struct mlx4_cqe **out)
+{
+	int ret = 0;
+	struct mlx4_cqe *cqe = NULL;
+	struct mlx4_cq *cq = &rxq->mcq;
+
+	cqe = (struct mlx4_cqe *)mlx4_get_cqe(cq, cq->cons_index);
+	if (!!(cqe->owner_sr_opcode & MLX4_CQE_OWNER_MASK) ^
+	    !!(cq->cons_index & cq->cqe_cnt))
+		goto out;
+	/*
+	 * Make sure we read CQ entry contents after we've checked the
+	 * ownership bit.
+	 */
+	rte_rmb();
+	assert(!(cqe->owner_sr_opcode & MLX4_CQE_IS_SEND_MASK));
+	assert((cqe->owner_sr_opcode & MLX4_CQE_OPCODE_MASK) !=
+	       MLX4_CQE_OPCODE_ERROR);
+	ret = rte_be_to_cpu_32(cqe->byte_cnt);
+	++cq->cons_index;
+out:
+	*out = cqe;
+	return ret;
+}
+
+/**
+ * DPDK callback for RX with scattered packets support.
  *
  * @param dpdk_rxq
  *   Generic pointer to Rx queue structure.
@@ -539,112 +575,105 @@
 uint16_t
 mlx4_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n)
 {
-	struct rxq *rxq = (struct rxq *)dpdk_rxq;
-	struct rxq_elt (*elts)[rxq->elts_n] = rxq->elts;
-	const unsigned int elts_n = rxq->elts_n;
-	unsigned int elts_head = rxq->elts_head;
-	struct ibv_wc wcs[pkts_n];
-	struct ibv_recv_wr *wr_head = NULL;
-	struct ibv_recv_wr **wr_next = &wr_head;
-	struct ibv_recv_wr *wr_bad = NULL;
-	unsigned int i;
-	unsigned int pkts_ret = 0;
-	int ret;
+	struct rxq *rxq = dpdk_rxq;
+	const unsigned int wr_cnt = (1 << rxq->elts_n) - 1;
+	struct rte_mbuf *pkt = NULL;
+	struct rte_mbuf *seg = NULL;
+	unsigned int i = 0;
+	unsigned int rq_ci = (rxq->hw.rq_ci);
+	int len = 0;
 
-	ret = ibv_poll_cq(rxq->cq, pkts_n, wcs);
-	if (unlikely(ret == 0))
-		return 0;
-	if (unlikely(ret < 0)) {
-		DEBUG("rxq=%p, ibv_poll_cq() failed (wc_n=%d)",
-		      (void *)rxq, ret);
-		return 0;
-	}
-	assert(ret <= (int)pkts_n);
-	/* For each work completion. */
-	for (i = 0; i != (unsigned int)ret; ++i) {
-		struct ibv_wc *wc = &wcs[i];
-		struct rxq_elt *elt = &(*elts)[elts_head];
-		struct ibv_recv_wr *wr = &elt->wr;
-		uint32_t len = wc->byte_len;
-		struct rte_mbuf *seg = elt->buf;
-		struct rte_mbuf *rep;
+	while (pkts_n) {
+		struct mlx4_cqe *cqe;
+		unsigned int idx = rq_ci & wr_cnt;
+		struct rte_mbuf *rep = (*rxq->elts)[idx];
+		volatile struct mlx4_wqe_data_seg *scat =
+					&(*rxq->hw.wqes)[idx];
 
-		/* Sanity checks. */
-		assert(wr->sg_list == &elt->sge);
-		assert(wr->num_sge == 1);
-		assert(elts_head < rxq->elts_n);
-		assert(rxq->elts_head < rxq->elts_n);
-		/*
-		 * Fetch initial bytes of packet descriptor into a
-		 * cacheline while allocating rep.
-		 */
-		rte_mbuf_prefetch_part1(seg);
-		rte_mbuf_prefetch_part2(seg);
-		/* Link completed WRs together for repost. */
-		*wr_next = wr;
-		wr_next = &wr->next;
-		if (unlikely(wc->status != IBV_WC_SUCCESS)) {
-			/* Whatever, just repost the offending WR. */
-			DEBUG("rxq=%p: bad work completion status (%d): %s",
-			      (void *)rxq, wc->status,
-			      ibv_wc_status_str(wc->status));
-			/* Increment dropped packets counter. */
-			++rxq->stats.idropped;
-			goto repost;
-		}
+		/* Update the 'next' pointer of the previous segment. */
+		if (pkt)
+			seg->next = rep;
+		seg = rep;
+		rte_prefetch0(seg);
+		rte_prefetch0(scat);
 		rep = rte_mbuf_raw_alloc(rxq->mp);
 		if (unlikely(rep == NULL)) {
-			/*
-			 * Unable to allocate a replacement mbuf,
-			 * repost WR.
-			 */
-			DEBUG("rxq=%p: can't allocate a new mbuf",
-			      (void *)rxq);
-			/* Increase out of memory counters. */
 			++rxq->stats.rx_nombuf;
-			++rxq->priv->dev->data->rx_mbuf_alloc_failed;
-			goto repost;
+			if (!pkt) {
+				/*
+				 * No buffers before we even started,
+				 * bail out silently.
+				 */
+				break;
+			}
+			while (pkt != seg) {
+				assert(pkt != (*rxq->elts)[idx]);
+				rep = pkt->next;
+				pkt->next = NULL;
+				pkt->nb_segs = 1;
+				rte_mbuf_raw_free(pkt);
+				pkt = rep;
+			}
+			break;
+		}
+		if (!pkt) {
+			/* Looking for the new packet */
+			len = mlx4_cq_poll_one(rxq, &cqe);
+			if (!len) {
+				rte_mbuf_raw_free(rep);
+				break;
+			}
+			if (unlikely(len < 0)) {
+				/* RX error, packet is likely too large. */
+				rte_mbuf_raw_free(rep);
+				++rxq->stats.idropped;
+				goto skip;
+			}
+			pkt = seg;
+			pkt->packet_type = 0;
+			pkt->ol_flags = 0;
+			pkt->pkt_len = len;
 		}
-		/* Reconfigure sge to use rep instead of seg. */
-		elt->sge.addr = (uintptr_t)rep->buf_addr + RTE_PKTMBUF_HEADROOM;
-		assert(elt->sge.lkey == rxq->mr->lkey);
-		elt->buf = rep;
-		/* Update seg information. */
-		seg->data_off = RTE_PKTMBUF_HEADROOM;
-		seg->nb_segs = 1;
-		seg->port = rxq->port_id;
-		seg->next = NULL;
-		seg->pkt_len = len;
+		rep->nb_segs = 1;
+		rep->port = rxq->port_id;
+		rep->data_len = seg->data_len;
+		rep->data_off = seg->data_off;
+		(*rxq->elts)[idx] = rep;
+		/*
+		 * Fill NIC descriptor with the new buffer. The lkey and size
+		 * of the buffers are already known, only the buffer address
+		 * changes.
+		 */
+		scat->addr = rte_cpu_to_be_64(rte_pktmbuf_mtod(rep, uintptr_t));
+		if (len > seg->data_len) {
+			len -= seg->data_len;
+			++pkt->nb_segs;
+			++rq_ci;
+			continue;
+		}
+		/* The last segment. */
 		seg->data_len = len;
-		seg->packet_type = 0;
-		seg->ol_flags = 0;
+		/* Increment bytes counter. */
+		rxq->stats.ibytes += pkt->pkt_len;
 		/* Return packet. */
-		*(pkts++) = seg;
-		++pkts_ret;
-		/* Increase bytes counter. */
-		rxq->stats.ibytes += len;
-repost:
-		if (++elts_head >= elts_n)
-			elts_head = 0;
-		continue;
+		*(pkts++) = pkt;
+		pkt = NULL;
+		--pkts_n;
+		++i;
+skip:
+		++rq_ci;
 	}
-	if (unlikely(i == 0))
+	if (unlikely(i == 0 && rq_ci == rxq->hw.rq_ci))
 		return 0;
-	/* Repost WRs. */
-	*wr_next = NULL;
-	assert(wr_head);
-	ret = ibv_post_recv(rxq->qp, wr_head, &wr_bad);
-	if (unlikely(ret)) {
-		/* Inability to repost WRs is fatal. */
-		DEBUG("%p: recv_burst(): failed (ret=%d)",
-		      (void *)rxq->priv,
-		      ret);
-		abort();
-	}
-	rxq->elts_head = elts_head;
-	/* Increase packets counter. */
-	rxq->stats.ipackets += pkts_ret;
-	return pkts_ret;
+	/* Update the consumer index. */
+	rxq->hw.rq_ci = rq_ci;
+	rte_wmb();
+	*rxq->hw.rq_db = rte_cpu_to_be_32(rxq->hw.rq_ci);
+	*rxq->mcq.set_ci_db =
+		rte_cpu_to_be_32(rxq->mcq.cons_index & 0xffffff);
+	/* Increment packets counter. */
+	rxq->stats.ipackets += i;
+	return i;
 }
 
 /**
diff --git a/drivers/net/mlx4/mlx4_rxtx.h b/drivers/net/mlx4/mlx4_rxtx.h
index b515472..fa2481c 100644
--- a/drivers/net/mlx4/mlx4_rxtx.h
+++ b/drivers/net/mlx4/mlx4_rxtx.h
@@ -62,13 +62,6 @@ struct mlx4_rxq_stats {
 	uint64_t rx_nombuf; /**< Total of Rx mbuf allocation failures. */
 };
 
-/** Rx element. */
-struct rxq_elt {
-	struct ibv_recv_wr wr; /**< Work request. */
-	struct ibv_sge sge; /**< Scatter/gather element. */
-	struct rte_mbuf *buf; /**< Buffer. */
-};
-
 /** Rx queue descriptor. */
 struct rxq {
 	struct priv *priv; /**< Back pointer to private data. */
@@ -78,9 +71,14 @@ struct rxq {
 	struct ibv_qp *qp; /**< Queue pair. */
 	struct ibv_comp_channel *channel; /**< Rx completion channel. */
 	unsigned int port_id; /**< Port ID for incoming packets. */
-	unsigned int elts_n; /**< (*elts)[] length. */
-	unsigned int elts_head; /**< Current index in (*elts)[]. */
-	struct rxq_elt (*elts)[]; /**< Rx elements. */
+	unsigned int elts_n; /**< Log 2 of Mbufs. */
+	struct rte_mbuf *(*elts)[]; /**< Rx elements. */
+	struct {
+		volatile struct mlx4_wqe_data_seg(*wqes)[];
+		volatile uint32_t *rq_db;
+		uint16_t rq_ci;
+	} hw;
+	struct mlx4_cq mcq;  /**< Info for directly manipulating the CQ. */
 	struct mlx4_rxq_stats stats; /**< Rx queue counters. */
 	unsigned int socket; /**< CPU socket ID for allocations. */
 };
diff --git a/drivers/net/mlx4/mlx4_utils.h b/drivers/net/mlx4/mlx4_utils.h
index 0fbdc71..d6f729f 100644
--- a/drivers/net/mlx4/mlx4_utils.h
+++ b/drivers/net/mlx4/mlx4_utils.h
@@ -108,4 +108,24 @@
 
 int mlx4_fd_set_non_blocking(int fd);
 
+/**
+ * Return nearest power of two above input value.
+ *
+ * @param v
+ *   Input value.
+ *
+ * @return
+ *   Nearest power of two above input value.
+ */
+static inline unsigned int
+log2above(unsigned int v)
+{
+	unsigned int l;
+	unsigned int r;
+
+	for (l = 0, r = 0; (v >> 1); ++l, v >>= 1)
+		r |= (v & 1);
+	return l + r;
+}
+
 #endif /* MLX4_UTILS_H_ */
-- 
1.8.3.1

^ permalink raw reply related

* [PATCH v3 1/7] net/mlx4: add simple Tx bypassing ibverbs
From: Ophir Munk @ 2017-10-04 21:49 UTC (permalink / raw)
  To: Adrien Mazarguil
  Cc: dev, Thomas Monjalon, Olga Shern, Matan Azrad, Moti Haimovsky
In-Reply-To: <1507153746-31255-1-git-send-email-ophirmu@mellanox.com>

From: Moti Haimovsky <motih@mellanox.com>

Modify PMD to send single-buffer packets directly to the device
bypassing the ibv Tx post and poll routines.

Signed-off-by: Moti Haimovsky <motih@mellanox.com>
---
 drivers/net/mlx4/mlx4_prm.h  | 108 +++++++++++++
 drivers/net/mlx4/mlx4_rxtx.c | 354 ++++++++++++++++++++++++++++++++-----------
 drivers/net/mlx4/mlx4_rxtx.h |  32 ++--
 drivers/net/mlx4/mlx4_txq.c  |  90 ++++++++---
 mk/rte.app.mk                |   2 +-
 5 files changed, 464 insertions(+), 122 deletions(-)
 create mode 100644 drivers/net/mlx4/mlx4_prm.h

diff --git a/drivers/net/mlx4/mlx4_prm.h b/drivers/net/mlx4/mlx4_prm.h
new file mode 100644
index 0000000..6d1800a
--- /dev/null
+++ b/drivers/net/mlx4/mlx4_prm.h
@@ -0,0 +1,108 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright 2017 6WIND S.A.
+ *   Copyright 2017 Mellanox
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of 6WIND S.A. nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef RTE_PMD_MLX4_PRM_H_
+#define RTE_PMD_MLX4_PRM_H_
+
+#include <rte_byteorder.h>
+#include <rte_branch_prediction.h>
+#include <rte_atomic.h>
+
+/* Verbs headers do not support -pedantic. */
+#ifdef PEDANTIC
+#pragma GCC diagnostic ignored "-Wpedantic"
+#endif
+#include <infiniband/verbs.h>
+#include <infiniband/mlx4dv.h>
+#ifdef PEDANTIC
+#pragma GCC diagnostic error "-Wpedantic"
+#endif
+
+/* ConnectX-3 Tx queue basic block. */
+#define MLX4_TXBB_SHIFT 6
+#define MLX4_TXBB_SIZE (1 << MLX4_TXBB_SHIFT)
+
+/* Typical TSO descriptor with 16 gather entries is 352 bytes. */
+#define MLX4_MAX_WQE_SIZE 512
+#define MLX4_MAX_WQE_TXBBS (MLX4_MAX_WQE_SIZE / MLX4_TXBB_SIZE)
+
+/* Send queue stamping/invalidating information. */
+#define MLX4_SQ_STAMP_STRIDE 64
+#define MLX4_SQ_STAMP_DWORDS (MLX4_SQ_STAMP_STRIDE / 4)
+#define MLX4_SQ_STAMP_SHIFT 31
+#define MLX4_SQ_STAMP_VAL 0x7fffffff
+
+/* Work queue element (WQE) flags. */
+#define MLX4_BIT_WQE_OWN 0x80000000
+
+#define MLX4_SIZE_TO_TXBBS(size) \
+		(RTE_ALIGN((size), (MLX4_TXBB_SIZE)) >> (MLX4_TXBB_SHIFT))
+
+/* Send queue information. */
+struct mlx4_sq {
+	char *buf; /**< SQ buffer. */
+	char *eob; /**< End of SQ buffer */
+	uint32_t head; /**< SQ head counter in units of TXBBS. */
+	uint32_t tail; /**< SQ tail counter in units of TXBBS. */
+	uint32_t txbb_cnt; /**< Num of WQEBB in the Q (should be ^2). */
+	uint32_t txbb_cnt_mask; /**< txbbs_cnt mask (txbb_cnt is ^2). */
+	uint32_t headroom_txbbs; /**< Num of txbbs that should be kept free. */
+	uint32_t *db; /**< Pointer to the doorbell. */
+	uint32_t doorbell_qpn; /**< qp number to write to the doorbell. */
+};
+
+#define mlx4_get_send_wqe(sq, n) ((sq)->buf + ((n) * (MLX4_TXBB_SIZE)))
+
+/* Completion queue information. */
+struct mlx4_cq {
+	char *buf; /**< Pointer to the completion queue buffer. */
+	uint32_t cqe_cnt; /**< Number of entries in the queue. */
+	uint32_t cqe_64:1; /**< CQ entry size is 64 bytes. */
+	uint32_t cons_index; /**< Last queue entry that was handled. */
+	uint32_t *set_ci_db; /**< Pointer to the completion queue doorbell. */
+};
+
+/*
+ * cqe = cq->buf + cons_index * cqe_size + cqe_offset
+ * Where cqe_size is 32 or 64 bytes and
+ * cqe_offset is 0 or 32 (depending on cqe_size).
+ */
+#define mlx4_get_cqe(cq, n) (__extension__({ \
+				typeof(cq) q = (cq); \
+				(q)->buf + \
+				(((n) & ((q)->cqe_cnt - 1)) << \
+				 (5 + (q)->cqe_64)) + \
+				((q)->cqe_64 << 5); \
+			    }))
+
+#endif /* RTE_PMD_MLX4_PRM_H_ */
diff --git a/drivers/net/mlx4/mlx4_rxtx.c b/drivers/net/mlx4/mlx4_rxtx.c
index b5e7777..c7c190d 100644
--- a/drivers/net/mlx4/mlx4_rxtx.c
+++ b/drivers/net/mlx4/mlx4_rxtx.c
@@ -40,6 +40,7 @@
 #include <inttypes.h>
 #include <stdint.h>
 #include <string.h>
+#include <stdbool.h>
 
 /* Verbs headers do not support -pedantic. */
 #ifdef PEDANTIC
@@ -52,15 +53,76 @@
 
 #include <rte_branch_prediction.h>
 #include <rte_common.h>
+#include <rte_io.h>
 #include <rte_mbuf.h>
 #include <rte_mempool.h>
 #include <rte_prefetch.h>
 
 #include "mlx4.h"
+#include "mlx4_prm.h"
 #include "mlx4_rxtx.h"
 #include "mlx4_utils.h"
 
 /**
+ * Stamp a WQE so it won't be reused by the HW.
+ * Routine is used when freeing WQE used by the chip or when failing
+ * building an WQ entry has failed leaving partial information on the queue.
+ *
+ * @param sq
+ *   Pointer to the sq structure.
+ * @param index
+ *   Index of the freed WQE.
+ * @param num_txbbs
+ *   Number of blocks to stamp.
+ *   If < 0 the routine will use the size written in the WQ entry.
+ * @param owner
+ *   The value of the WQE owner bit to use in the stamp.
+ *
+ * @return
+ *   The number of TX basic blocs (TXBB) the WQE contained.
+ */
+static int
+mlx4_txq_stamp_freed_wqe(struct mlx4_sq *sq, uint16_t index, uint8_t owner)
+{
+	uint32_t stamp =
+		rte_cpu_to_be_32(MLX4_SQ_STAMP_VAL |
+				 (!!owner << MLX4_SQ_STAMP_SHIFT));
+	char *wqe = mlx4_get_send_wqe(sq, (index & sq->txbb_cnt_mask));
+	uint32_t *ptr = (uint32_t *)wqe;
+	int i;
+	int txbbs_size;
+	int num_txbbs;
+
+	/* Extract the size from the control segment of the WQE. */
+	num_txbbs = MLX4_SIZE_TO_TXBBS((((struct mlx4_wqe_ctrl_seg *)
+					 wqe)->fence_size & 0x3f) << 4);
+	txbbs_size = num_txbbs * MLX4_TXBB_SIZE;
+	/* Optimize the common case when there is no wrap-around */
+	if (wqe + txbbs_size <= sq->eob) {
+		/* Stamp the freed descriptor */
+		for (i = 0;
+		     i < txbbs_size;
+		     i += MLX4_SQ_STAMP_STRIDE) {
+			*ptr = stamp;
+			ptr += MLX4_SQ_STAMP_DWORDS;
+		}
+	} else {
+		/* Stamp the freed descriptor */
+		for (i = 0;
+		     i < txbbs_size;
+		     i += MLX4_SQ_STAMP_STRIDE) {
+			*ptr = stamp;
+			ptr += MLX4_SQ_STAMP_DWORDS;
+			if ((char *)ptr >= sq->eob) {
+				ptr = (uint32_t *)sq->buf;
+				stamp ^= RTE_BE32(0x80000000);
+			}
+		}
+	}
+	return num_txbbs;
+}
+
+/**
  * Manage Tx completions.
  *
  * When sending a burst, mlx4_tx_burst() posts several WRs.
@@ -80,26 +142,74 @@
 	unsigned int elts_comp = txq->elts_comp;
 	unsigned int elts_tail = txq->elts_tail;
 	const unsigned int elts_n = txq->elts_n;
-	struct ibv_wc wcs[elts_comp];
-	int wcs_n;
+	struct mlx4_cq *cq = &txq->mcq;
+	struct mlx4_sq *sq = &txq->msq;
+	struct mlx4_cqe *cqe;
+	uint32_t cons_index = cq->cons_index;
+	uint16_t new_index;
+	uint16_t nr_txbbs = 0;
+	int pkts = 0;
 
 	if (unlikely(elts_comp == 0))
 		return 0;
-	wcs_n = ibv_poll_cq(txq->cq, elts_comp, wcs);
-	if (unlikely(wcs_n == 0))
+	/*
+	 * Traverse over all CQ entries reported and handle each WQ entry
+	 * reported by them.
+	 */
+	do {
+		cqe = (struct mlx4_cqe *)mlx4_get_cqe(cq, cons_index);
+		if (unlikely(!!(cqe->owner_sr_opcode & MLX4_CQE_OWNER_MASK) ^
+		    !!(cons_index & cq->cqe_cnt)))
+			break;
+		/*
+		 * make sure we read the CQE after we read the
+		 * ownership bit
+		 */
+		rte_rmb();
+		if (unlikely((cqe->owner_sr_opcode & MLX4_CQE_OPCODE_MASK) ==
+			     MLX4_CQE_OPCODE_ERROR)) {
+			struct mlx4_err_cqe *cqe_err =
+				(struct mlx4_err_cqe *)cqe;
+			ERROR("%p CQE error - vendor syndrome: 0x%x"
+			      " syndrome: 0x%x\n",
+			      (void *)txq, cqe_err->vendor_err,
+			      cqe_err->syndrome);
+		}
+		/* Get WQE index reported in the CQE. */
+		new_index =
+			rte_be_to_cpu_16(cqe->wqe_index) & sq->txbb_cnt_mask;
+		do {
+			/* free next descriptor */
+			nr_txbbs +=
+				mlx4_txq_stamp_freed_wqe(sq,
+				     (sq->tail + nr_txbbs) & sq->txbb_cnt_mask,
+				     !!((sq->tail + nr_txbbs) & sq->txbb_cnt));
+			pkts++;
+		} while (((sq->tail + nr_txbbs) & sq->txbb_cnt_mask) !=
+			 new_index);
+		cons_index++;
+	} while (true);
+	if (unlikely(pkts == 0))
 		return 0;
-	if (unlikely(wcs_n < 0)) {
-		DEBUG("%p: ibv_poll_cq() failed (wcs_n=%d)",
-		      (void *)txq, wcs_n);
-		return -1;
-	}
-	elts_comp -= wcs_n;
+	/*
+	 * Update CQ.
+	 * To prevent CQ overflow we first update CQ consumer and only then
+	 * the ring consumer.
+	 */
+	cq->cons_index = cons_index;
+	*cq->set_ci_db = rte_cpu_to_be_32(cq->cons_index & 0xffffff);
+	rte_wmb();
+	sq->tail = sq->tail + nr_txbbs;
+	/*
+	 * Update the list of packets posted for transmission.
+	 */
+	elts_comp -= pkts;
 	assert(elts_comp <= txq->elts_comp);
 	/*
-	 * Assume WC status is successful as nothing can be done about it
-	 * anyway.
+	 * Assume completion status is successful as nothing can be done about
+	 * it anyway.
 	 */
-	elts_tail += wcs_n * txq->elts_comp_cd_init;
+	elts_tail += pkts;
 	if (elts_tail >= elts_n)
 		elts_tail -= elts_n;
 	txq->elts_tail = elts_tail;
@@ -117,7 +227,7 @@
  * @return
  *   Memory pool where data is located for given mbuf.
  */
-static struct rte_mempool *
+static inline struct rte_mempool *
 mlx4_txq_mb2mp(struct rte_mbuf *buf)
 {
 	if (unlikely(RTE_MBUF_INDIRECT(buf)))
@@ -158,7 +268,7 @@
 	/* Add a new entry, register MR first. */
 	DEBUG("%p: discovered new memory pool \"%s\" (%p)",
 	      (void *)txq, mp->name, (void *)mp);
-	mr = mlx4_mp2mr(txq->priv->pd, mp);
+	mr = mlx4_mp2mr(txq->ctrl.priv->pd, mp);
 	if (unlikely(mr == NULL)) {
 		DEBUG("%p: unable to configure MR, ibv_reg_mr() failed.",
 		      (void *)txq);
@@ -183,6 +293,124 @@
 }
 
 /**
+ * Posts a single work request to a send queue.
+ *
+ * @param txq
+ *   The Tx queue to post to.
+ * @param wr
+ *   The work request to handle.
+ * @param bad_wr
+ *   The wr in case that posting had failed.
+ *
+ * @return
+ *   0 - success, negative errno value otherwise and rte_errno is set.
+ */
+static inline int
+mlx4_post_send(struct txq *txq,
+	       struct rte_mbuf *pkt,
+	       uint32_t send_flags)
+{
+	struct mlx4_wqe_ctrl_seg *ctrl;
+	struct mlx4_wqe_data_seg *dseg;
+	struct mlx4_sq *sq = &txq->msq;
+	uint32_t head_idx = sq->head & sq->txbb_cnt_mask;
+	uint32_t lkey;
+	uintptr_t addr;
+	int wqe_real_size;
+	int nr_txbbs;
+	int rc;
+
+	/* Calculate the needed work queue entry size for this packet. */
+	wqe_real_size = sizeof(struct mlx4_wqe_ctrl_seg) +
+			pkt->nb_segs * sizeof(struct mlx4_wqe_data_seg);
+	nr_txbbs = MLX4_SIZE_TO_TXBBS(wqe_real_size);
+	/* Check that there is room for this WQE in the send queue and
+	 * that the WQE size is legal.
+	 */
+	if (likely(((sq->head - sq->tail) + nr_txbbs +
+		    sq->headroom_txbbs >= sq->txbb_cnt) ||
+		    nr_txbbs > MLX4_MAX_WQE_TXBBS)) {
+		rc = ENOSPC;
+		goto err;
+	}
+	/* Get the control and single-data entries of the WQE */
+	ctrl = (struct mlx4_wqe_ctrl_seg *)mlx4_get_send_wqe(sq, head_idx);
+	dseg = (struct mlx4_wqe_data_seg *)(((char *)ctrl) +
+		sizeof(struct mlx4_wqe_ctrl_seg));
+	/*
+	 * Fill the data segment with buffer information.
+	 */
+	addr = rte_pktmbuf_mtod(pkt, uintptr_t);
+	rte_prefetch0((volatile void *)addr);
+	dseg->addr = rte_cpu_to_be_64(addr);
+	/* Memory region key for this memory pool. */
+	lkey = mlx4_txq_mp2mr(txq, mlx4_txq_mb2mp(pkt));
+	if (unlikely(lkey == (uint32_t)-1)) {
+		/* MR does not exist. */
+		DEBUG("%p: unable to get MP <-> MR"
+		      " association", (void *)txq);
+		/*
+		 * Restamp entry in case of failure.
+		 * Make sure that size is written correctly.
+		 * Note that we give ownership to the SW, not the HW.
+		 */
+		ctrl->fence_size = (wqe_real_size >> 4) & 0x3f;
+		mlx4_txq_stamp_freed_wqe(sq, head_idx,
+					 (sq->head & sq->txbb_cnt) ? 0 : 1);
+		rc = EFAULT;
+		goto err;
+	}
+	dseg->lkey = rte_cpu_to_be_32(lkey);
+	/*
+	 * Need a barrier here before writing the byte_count field to
+	 * make sure that all the data is visible before the
+	 * byte_count field is set.  Otherwise, if the segment begins
+	 * a new cacheline, the HCA prefetcher could grab the 64-byte
+	 * chunk and get a valid (!= * 0xffffffff) byte count but
+	 * stale data, and end up sending the wrong data.
+	 */
+	rte_io_wmb();
+	if (likely(pkt->data_len))
+		dseg->byte_count = rte_cpu_to_be_32(pkt->data_len);
+	else
+		/*
+		 * Zero length segment is treated as inline segment
+		 * with zero data.
+		 */
+		dseg->byte_count = RTE_BE32(0x80000000);
+	/*
+	 * Fill the control parameters for this packet.
+	 * For raw Ethernet, the SOLICIT flag is used to indicate that no icrc
+	 * should be calculated
+	 */
+	ctrl->srcrb_flags =
+		rte_cpu_to_be_32(MLX4_WQE_CTRL_SOLICIT |
+				 (send_flags & MLX4_WQE_CTRL_CQ_UPDATE));
+	ctrl->fence_size = (wqe_real_size >> 4) & 0x3f;
+	/*
+	 * The caller should prepare "imm" in advance in order to support
+	 * VF to VF communication (when the device is a virtual-function
+	 * device (VF)).
+	 */
+	ctrl->imm = 0;
+	/*
+	 * Make sure descriptor is fully written before
+	 * setting ownership bit (because HW can start
+	 * executing as soon as we do).
+	 */
+	rte_wmb();
+	ctrl->owner_opcode =
+		rte_cpu_to_be_32(MLX4_OPCODE_SEND |
+				 ((sq->head & sq->txbb_cnt) ?
+				  MLX4_BIT_WQE_OWN : 0));
+	sq->head += nr_txbbs;
+	return 0;
+err:
+	rte_errno = rc;
+	return -rc;
+}
+
+/**
  * DPDK callback for Tx.
  *
  * @param dpdk_txq
@@ -199,13 +427,11 @@
 mlx4_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
 {
 	struct txq *txq = (struct txq *)dpdk_txq;
-	struct ibv_send_wr *wr_head = NULL;
-	struct ibv_send_wr **wr_next = &wr_head;
-	struct ibv_send_wr *wr_bad = NULL;
 	unsigned int elts_head = txq->elts_head;
 	const unsigned int elts_n = txq->elts_n;
 	unsigned int elts_comp_cd = txq->elts_comp_cd;
 	unsigned int elts_comp = 0;
+	unsigned int bytes_sent = 0;
 	unsigned int i;
 	unsigned int max;
 	int err;
@@ -229,9 +455,7 @@
 			(((elts_head + 1) == elts_n) ? 0 : elts_head + 1);
 		struct txq_elt *elt_next = &(*txq->elts)[elts_head_next];
 		struct txq_elt *elt = &(*txq->elts)[elts_head];
-		struct ibv_send_wr *wr = &elt->wr;
 		unsigned int segs = buf->nb_segs;
-		unsigned int sent_size = 0;
 		uint32_t send_flags = 0;
 
 		/* Clean up old buffer. */
@@ -254,93 +478,43 @@
 		if (unlikely(--elts_comp_cd == 0)) {
 			elts_comp_cd = txq->elts_comp_cd_init;
 			++elts_comp;
-			send_flags |= IBV_SEND_SIGNALED;
+			send_flags |= MLX4_WQE_CTRL_CQ_UPDATE;
 		}
 		if (likely(segs == 1)) {
-			struct ibv_sge *sge = &elt->sge;
-			uintptr_t addr;
-			uint32_t length;
-			uint32_t lkey;
-
-			/* Retrieve buffer information. */
-			addr = rte_pktmbuf_mtod(buf, uintptr_t);
-			length = buf->data_len;
-			/* Retrieve memory region key for this memory pool. */
-			lkey = mlx4_txq_mp2mr(txq, mlx4_txq_mb2mp(buf));
-			if (unlikely(lkey == (uint32_t)-1)) {
-				/* MR does not exist. */
-				DEBUG("%p: unable to get MP <-> MR"
-				      " association", (void *)txq);
-				/* Clean up Tx element. */
+			/* Update element. */
+			elt->buf = buf;
+			RTE_MBUF_PREFETCH_TO_FREE(elt_next->buf);
+			/* post the pkt for sending */
+			err = mlx4_post_send(txq, buf, send_flags);
+			if (unlikely(err)) {
+				if (unlikely(send_flags &
+					     MLX4_WQE_CTRL_CQ_UPDATE)) {
+					elts_comp_cd = 1;
+					--elts_comp;
+				}
 				elt->buf = NULL;
 				goto stop;
 			}
-			/* Update element. */
 			elt->buf = buf;
-			if (txq->priv->vf)
-				rte_prefetch0((volatile void *)
-					      (uintptr_t)addr);
-			RTE_MBUF_PREFETCH_TO_FREE(elt_next->buf);
-			sge->addr = addr;
-			sge->length = length;
-			sge->lkey = lkey;
-			sent_size += length;
+			bytes_sent += buf->pkt_len;
 		} else {
-			err = -1;
+			err = -EINVAL;
+			rte_errno = -err;
 			goto stop;
 		}
-		if (sent_size <= txq->max_inline)
-			send_flags |= IBV_SEND_INLINE;
 		elts_head = elts_head_next;
-		/* Increment sent bytes counter. */
-		txq->stats.obytes += sent_size;
-		/* Set up WR. */
-		wr->sg_list = &elt->sge;
-		wr->num_sge = segs;
-		wr->opcode = IBV_WR_SEND;
-		wr->send_flags = send_flags;
-		*wr_next = wr;
-		wr_next = &wr->next;
 	}
 stop:
 	/* Take a shortcut if nothing must be sent. */
 	if (unlikely(i == 0))
 		return 0;
-	/* Increment sent packets counter. */
+	/* Increment send statistics counters. */
 	txq->stats.opackets += i;
+	txq->stats.obytes += bytes_sent;
+	/* Make sure that descriptors are written before doorbell record. */
+	rte_wmb();
 	/* Ring QP doorbell. */
-	*wr_next = NULL;
-	assert(wr_head);
-	err = ibv_post_send(txq->qp, wr_head, &wr_bad);
-	if (unlikely(err)) {
-		uint64_t obytes = 0;
-		uint64_t opackets = 0;
-
-		/* Rewind bad WRs. */
-		while (wr_bad != NULL) {
-			int j;
-
-			/* Force completion request if one was lost. */
-			if (wr_bad->send_flags & IBV_SEND_SIGNALED) {
-				elts_comp_cd = 1;
-				--elts_comp;
-			}
-			++opackets;
-			for (j = 0; j < wr_bad->num_sge; ++j)
-				obytes += wr_bad->sg_list[j].length;
-			elts_head = (elts_head ? elts_head : elts_n) - 1;
-			wr_bad = wr_bad->next;
-		}
-		txq->stats.opackets -= opackets;
-		txq->stats.obytes -= obytes;
-		i -= opackets;
-		DEBUG("%p: ibv_post_send() failed, %" PRIu64 " packets"
-		      " (%" PRIu64 " bytes) rejected: %s",
-		      (void *)txq,
-		      opackets,
-		      obytes,
-		      (err <= -1) ? "Internal error" : strerror(err));
-	}
+	rte_write32(txq->msq.doorbell_qpn, txq->msq.db);
 	txq->elts_head = elts_head;
 	txq->elts_comp += elts_comp;
 	txq->elts_comp_cd = elts_comp_cd;
diff --git a/drivers/net/mlx4/mlx4_rxtx.h b/drivers/net/mlx4/mlx4_rxtx.h
index fec998a..b515472 100644
--- a/drivers/net/mlx4/mlx4_rxtx.h
+++ b/drivers/net/mlx4/mlx4_rxtx.h
@@ -40,6 +40,7 @@
 #ifdef PEDANTIC
 #pragma GCC diagnostic ignored "-Wpedantic"
 #endif
+#include <infiniband/mlx4dv.h>
 #include <infiniband/verbs.h>
 #ifdef PEDANTIC
 #pragma GCC diagnostic error "-Wpedantic"
@@ -50,6 +51,7 @@
 #include <rte_mempool.h>
 
 #include "mlx4.h"
+#include "mlx4_prm.h"
 
 /** Rx queue counters. */
 struct mlx4_rxq_stats {
@@ -85,8 +87,6 @@ struct rxq {
 
 /** Tx element. */
 struct txq_elt {
-	struct ibv_send_wr wr; /* Work request. */
-	struct ibv_sge sge; /* Scatter/gather element. */
 	struct rte_mbuf *buf; /**< Buffer. */
 };
 
@@ -100,24 +100,28 @@ struct mlx4_txq_stats {
 
 /** Tx queue descriptor. */
 struct txq {
-	struct priv *priv; /**< Back pointer to private data. */
-	struct {
-		const struct rte_mempool *mp; /**< Cached memory pool. */
-		struct ibv_mr *mr; /**< Memory region (for mp). */
-		uint32_t lkey; /**< mr->lkey copy. */
-	} mp2mr[MLX4_PMD_TX_MP_CACHE]; /**< MP to MR translation table. */
-	struct ibv_cq *cq; /**< Completion queue. */
-	struct ibv_qp *qp; /**< Queue pair. */
-	uint32_t max_inline; /**< Max inline send size. */
-	unsigned int elts_n; /**< (*elts)[] length. */
-	struct txq_elt (*elts)[]; /**< Tx elements. */
+	struct mlx4_sq msq; /**< Info for directly manipulating the SQ. */
+	struct mlx4_cq mcq; /**< Info for directly manipulating the CQ. */
 	unsigned int elts_head; /**< Current index in (*elts)[]. */
 	unsigned int elts_tail; /**< First element awaiting completion. */
 	unsigned int elts_comp; /**< Number of completion requests. */
 	unsigned int elts_comp_cd; /**< Countdown for next completion. */
 	unsigned int elts_comp_cd_init; /**< Initial value for countdown. */
+	unsigned int elts_n; /**< (*elts)[] length. */
+	struct txq_elt (*elts)[]; /**< Tx elements. */
 	struct mlx4_txq_stats stats; /**< Tx queue counters. */
-	unsigned int socket; /**< CPU socket ID for allocations. */
+	uint32_t max_inline; /**< Max inline send size. */
+	struct {
+		const struct rte_mempool *mp; /**< Cached memory pool. */
+		struct ibv_mr *mr; /**< Memory region (for mp). */
+		uint32_t lkey; /**< mr->lkey copy. */
+	} mp2mr[MLX4_PMD_TX_MP_CACHE]; /**< MP to MR translation table. */
+	struct {
+		struct priv *priv; /**< Back pointer to private data. */
+		unsigned int socket; /**< CPU socket ID for allocations. */
+		struct ibv_cq *cq; /**< Completion queue. */
+		struct ibv_qp *qp; /**< Queue pair. */
+	} ctrl;
 };
 
 /* mlx4_rxq.c */
diff --git a/drivers/net/mlx4/mlx4_txq.c b/drivers/net/mlx4/mlx4_txq.c
index e0245b0..492779f 100644
--- a/drivers/net/mlx4/mlx4_txq.c
+++ b/drivers/net/mlx4/mlx4_txq.c
@@ -62,6 +62,7 @@
 #include "mlx4_autoconf.h"
 #include "mlx4_rxtx.h"
 #include "mlx4_utils.h"
+#include "mlx4_prm.h"
 
 /**
  * Allocate Tx queue elements.
@@ -79,7 +80,7 @@
 {
 	unsigned int i;
 	struct txq_elt (*elts)[elts_n] =
-		rte_calloc_socket("TXQ", 1, sizeof(*elts), 0, txq->socket);
+		rte_calloc_socket("TXQ", 1, sizeof(*elts), 0, txq->ctrl.socket);
 	int ret = 0;
 
 	if (elts == NULL) {
@@ -170,10 +171,10 @@
 
 	DEBUG("cleaning up %p", (void *)txq);
 	mlx4_txq_free_elts(txq);
-	if (txq->qp != NULL)
-		claim_zero(ibv_destroy_qp(txq->qp));
-	if (txq->cq != NULL)
-		claim_zero(ibv_destroy_cq(txq->cq));
+	if (txq->ctrl.qp != NULL)
+		claim_zero(ibv_destroy_qp(txq->ctrl.qp));
+	if (txq->ctrl.cq != NULL)
+		claim_zero(ibv_destroy_cq(txq->ctrl.cq));
 	for (i = 0; (i != RTE_DIM(txq->mp2mr)); ++i) {
 		if (txq->mp2mr[i].mp == NULL)
 			break;
@@ -242,6 +243,42 @@ struct txq_mp2mr_mbuf_check_data {
 }
 
 /**
+ * Retrieves information needed in order to directly access the Tx queue.
+ *
+ * @param txq
+ *   Pointer to Tx queue structure.
+ * @param mlxdv
+ *   Pointer to device information for this Tx queue.
+ */
+static void
+mlx4_txq_fill_dv_obj_info(struct txq *txq, struct mlx4dv_obj *mlxdv)
+{
+	struct mlx4_sq *sq = &txq->msq;
+	struct mlx4_cq *cq = &txq->mcq;
+	struct mlx4dv_qp *dqp = mlxdv->qp.out;
+	struct mlx4dv_cq *dcq = mlxdv->cq.out;
+	/* Total sq length, including headroom and spare WQEs*/
+	uint32_t sq_size = (uint32_t)dqp->rq.offset - (uint32_t)dqp->sq.offset;
+
+	sq->buf = ((char *)dqp->buf.buf) + dqp->sq.offset;
+	/* Total len, including headroom and spare WQEs*/
+	sq->eob = sq->buf + sq_size;
+	sq->head = 0;
+	sq->tail = 0;
+	sq->txbb_cnt =
+		(dqp->sq.wqe_cnt << dqp->sq.wqe_shift) >> MLX4_TXBB_SHIFT;
+	sq->txbb_cnt_mask = sq->txbb_cnt - 1;
+	sq->db = dqp->sdb;
+	sq->doorbell_qpn = dqp->doorbell_qpn;
+	sq->headroom_txbbs =
+		(2048 + (1 << dqp->sq.wqe_shift)) >> MLX4_TXBB_SHIFT;
+	cq->buf = dcq->buf.buf;
+	cq->cqe_cnt = dcq->cqe_cnt;
+	cq->set_ci_db = dcq->set_ci_db;
+	cq->cqe_64 = (dcq->cqe_size & 64) ? 1 : 0;
+}
+
+/**
  * Configure a Tx queue.
  *
  * @param dev
@@ -263,9 +300,15 @@ struct txq_mp2mr_mbuf_check_data {
 	       unsigned int socket, const struct rte_eth_txconf *conf)
 {
 	struct priv *priv = dev->data->dev_private;
+	struct mlx4dv_obj mlxdv;
+	struct mlx4dv_qp dv_qp;
+	struct mlx4dv_cq dv_cq;
+
 	struct txq tmpl = {
-		.priv = priv,
-		.socket = socket
+		.ctrl = {
+			.priv = priv,
+			.socket = socket
+		},
 	};
 	union {
 		struct ibv_qp_init_attr init;
@@ -284,8 +327,8 @@ struct txq_mp2mr_mbuf_check_data {
 		goto error;
 	}
 	/* MRs will be registered in mp2mr[] later. */
-	tmpl.cq = ibv_create_cq(priv->ctx, desc, NULL, NULL, 0);
-	if (tmpl.cq == NULL) {
+	tmpl.ctrl.cq = ibv_create_cq(priv->ctx, desc, NULL, NULL, 0);
+	if (tmpl.ctrl.cq == NULL) {
 		rte_errno = ENOMEM;
 		ERROR("%p: CQ creation failure: %s",
 		      (void *)dev, strerror(rte_errno));
@@ -297,9 +340,9 @@ struct txq_mp2mr_mbuf_check_data {
 	      priv->device_attr.max_sge);
 	attr.init = (struct ibv_qp_init_attr){
 		/* CQ to be associated with the send queue. */
-		.send_cq = tmpl.cq,
+		.send_cq = tmpl.ctrl.cq,
 		/* CQ to be associated with the receive queue. */
-		.recv_cq = tmpl.cq,
+		.recv_cq = tmpl.ctrl.cq,
 		.cap = {
 			/* Max number of outstanding WRs. */
 			.max_send_wr = ((priv->device_attr.max_qp_wr < desc) ?
@@ -316,8 +359,8 @@ struct txq_mp2mr_mbuf_check_data {
 		 */
 		.sq_sig_all = 0,
 	};
-	tmpl.qp = ibv_create_qp(priv->pd, &attr.init);
-	if (tmpl.qp == NULL) {
+	tmpl.ctrl.qp = ibv_create_qp(priv->pd, &attr.init);
+	if (tmpl.ctrl.qp == NULL) {
 		rte_errno = errno ? errno : EINVAL;
 		ERROR("%p: QP creation failure: %s",
 		      (void *)dev, strerror(rte_errno));
@@ -331,7 +374,8 @@ struct txq_mp2mr_mbuf_check_data {
 		/* Primary port number. */
 		.port_num = priv->port
 	};
-	ret = ibv_modify_qp(tmpl.qp, &attr.mod, IBV_QP_STATE | IBV_QP_PORT);
+	ret = ibv_modify_qp(tmpl.ctrl.qp, &attr.mod,
+			    IBV_QP_STATE | IBV_QP_PORT);
 	if (ret) {
 		rte_errno = ret;
 		ERROR("%p: QP state to IBV_QPS_INIT failed: %s",
@@ -348,7 +392,7 @@ struct txq_mp2mr_mbuf_check_data {
 	attr.mod = (struct ibv_qp_attr){
 		.qp_state = IBV_QPS_RTR
 	};
-	ret = ibv_modify_qp(tmpl.qp, &attr.mod, IBV_QP_STATE);
+	ret = ibv_modify_qp(tmpl.ctrl.qp, &attr.mod, IBV_QP_STATE);
 	if (ret) {
 		rte_errno = ret;
 		ERROR("%p: QP state to IBV_QPS_RTR failed: %s",
@@ -356,7 +400,7 @@ struct txq_mp2mr_mbuf_check_data {
 		goto error;
 	}
 	attr.mod.qp_state = IBV_QPS_RTS;
-	ret = ibv_modify_qp(tmpl.qp, &attr.mod, IBV_QP_STATE);
+	ret = ibv_modify_qp(tmpl.ctrl.qp, &attr.mod, IBV_QP_STATE);
 	if (ret) {
 		rte_errno = ret;
 		ERROR("%p: QP state to IBV_QPS_RTS failed: %s",
@@ -370,6 +414,18 @@ struct txq_mp2mr_mbuf_check_data {
 	DEBUG("%p: txq updated with %p", (void *)txq, (void *)&tmpl);
 	/* Pre-register known mempools. */
 	rte_mempool_walk(mlx4_txq_mp2mr_iter, txq);
+	/* Retrieve device Q info */
+	mlxdv.cq.in = txq->ctrl.cq;
+	mlxdv.cq.out = &dv_cq;
+	mlxdv.qp.in = txq->ctrl.qp;
+	mlxdv.qp.out = &dv_qp;
+	ret = mlx4dv_init_obj(&mlxdv, MLX4DV_OBJ_QP | MLX4DV_OBJ_CQ);
+	if (ret) {
+		ERROR("%p: Failed to obtain information needed for "
+		      "accessing the device queues", (void *)dev);
+		goto error;
+	}
+	mlx4_txq_fill_dv_obj_info(txq, &mlxdv);
 	return 0;
 error:
 	ret = rte_errno;
@@ -459,7 +515,7 @@ struct txq_mp2mr_mbuf_check_data {
 
 	if (txq == NULL)
 		return;
-	priv = txq->priv;
+	priv = txq->ctrl.priv;
 	for (i = 0; i != priv->dev->data->nb_tx_queues; ++i)
 		if (priv->dev->data->tx_queues[i] == txq) {
 			DEBUG("%p: removing Tx queue %p from list",
diff --git a/mk/rte.app.mk b/mk/rte.app.mk
index c25fdd9..2f1286e 100644
--- a/mk/rte.app.mk
+++ b/mk/rte.app.mk
@@ -128,7 +128,7 @@ ifeq ($(CONFIG_RTE_LIBRTE_KNI),y)
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_KNI)        += -lrte_pmd_kni
 endif
 _LDLIBS-$(CONFIG_RTE_LIBRTE_LIO_PMD)        += -lrte_pmd_lio
-_LDLIBS-$(CONFIG_RTE_LIBRTE_MLX4_PMD)       += -lrte_pmd_mlx4 -libverbs
+_LDLIBS-$(CONFIG_RTE_LIBRTE_MLX4_PMD)       += -lrte_pmd_mlx4 -libverbs -lmlx4
 _LDLIBS-$(CONFIG_RTE_LIBRTE_MLX5_PMD)       += -lrte_pmd_mlx5 -libverbs
 _LDLIBS-$(CONFIG_RTE_LIBRTE_NFP_PMD)        += -lrte_pmd_nfp
 _LDLIBS-$(CONFIG_RTE_LIBRTE_PMD_NULL)       += -lrte_pmd_null
-- 
1.8.3.1

^ permalink raw reply related

* [PATCH v3 0/7] new mlx4 datapath bypassing ibverbs
From: Ophir Munk @ 2017-10-04 21:48 UTC (permalink / raw)
  To: Adrien Mazarguil
  Cc: dev, Thomas Monjalon, Olga Shern, Matan Azrad, Ophir Munk
In-Reply-To: <1507027711-879-1-git-send-email-matan@mellanox.com>

Changes from v2:
* Split "net/mlx4: support multi-segments Rx" commit from "net/mlx4: get back Rx flow functionality" commit
* Semantics, code styling
* Fix check-git-log warnings
* Fix checkpatches warnings

Next (currently not included) changes:
* Replacing MLX4_TRANSPOSE() macro (Generic macro to convert MLX4 to IBV flags) with a look-up table as in mlx5
for example: mlx5_set_ptype_table() function - in order to improve performance.
This change is delicate and should be verified first with regression tests

* PMD documentation update when no longer working with MLNX_OFED
Documentation updtes require specific kernel, rdma_core and FW versions as well as installation procedures.
These details should be supplied by regression team.

Moti Haimovsky (6):
  net/mlx4: add simple Tx bypassing ibverbs
  net/mlx4: get back Rx flow functionality
  net/mlx4: support multi-segments Tx
  net/mlx4: get back Tx checksum offloads
  net/mlx4: get back Rx checksum offloads
  net/mlx4: add loopback Tx from VF

Vasily Philipov (1):
  net/mlx4: support multi-segments Rx

 drivers/net/mlx4/mlx4.c        |  11 +
 drivers/net/mlx4/mlx4.h        |  13 +-
 drivers/net/mlx4/mlx4_ethdev.c |  10 +
 drivers/net/mlx4/mlx4_prm.h    | 129 +++++++
 drivers/net/mlx4/mlx4_rxq.c    | 181 ++++++----
 drivers/net/mlx4/mlx4_rxtx.c   | 788 ++++++++++++++++++++++++++++++-----------
 drivers/net/mlx4/mlx4_rxtx.h   |  61 ++--
 drivers/net/mlx4/mlx4_txq.c    | 104 +++++-
 drivers/net/mlx4/mlx4_utils.h  |  20 ++
 mk/rte.app.mk                  |   2 +-
 10 files changed, 990 insertions(+), 329 deletions(-)
 create mode 100644 drivers/net/mlx4/mlx4_prm.h

-- 
1.8.3.1

^ permalink raw reply

* Re: [PATCH] serial: imx-serial - move DMA buffer configuration to DT
From: Uwe Kleine-König @ 2017-10-04 21:49 UTC (permalink / raw)
  To: Han, Nandor (GE Healthcare)
  Cc: Romain Perier, Greg Kroah-Hartman, Jiri Slaby,
	linux-serial-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <AM3P101MB0180F7019908E059648488F0E67D0-Irc2Ng3OI610aGNDtyle9VAr667LJVwUiGd9ebBGJoev3QGu/rdwKA@public.gmane.org>

Hello,

On Mon, Oct 02, 2017 at 01:17:41PM +0000, Han, Nandor (GE Healthcare) wrote:
> > -----Original Message-----
> > From: Uwe Kleine-König [mailto:u.kleine-koenig-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org]
> > Sent: 29 June 2017 21:26
> > To: Romain Perier <romain.perier-ZGY8ohtN/8qB+jHODAdFcQ@public.gmane.org>
> > Cc: Greg Kroah-Hartman <gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r@public.gmane.org>; Jiri Slaby
> > <jslaby-IBi9RG/b67k@public.gmane.org>; linux-serial-u79uwXL29TY76Z2rM5mHXA@public.gmane.org; Han, Nandor (GE
> > Healthcare) <nandor.han-JJi787mZWgc@public.gmane.org>; devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> > Subject: EXT: Re: [PATCH] serial: imx-serial - move DMA buffer configuration
> > to DT
> > 
> > Hello,
> > 
> > Cc: += devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> > 
> > On Wed, Jun 28, 2017 at 12:15:14PM +0200, Romain Perier wrote:
> > > From: Nandor Han <nandor.han-JJi787mZWgc@public.gmane.org>
> > >
> > > The size of the DMA buffer can affect the delta time between data
> > > being produced and data being consumed. Basically the DMA system will
> > > move data to tty buffer when a) DMA buffer is full b) serial line is idle.
> > > The situation is visible when producer generates data continuously and
> > > there is no possibility for idle line. At this point the DMA buffer is
> > > directly affecting the delta time.
> 
> Hi Uwe,
>    Maybe I can explain a bit better the situation. At least I've tried to explain well enough
> the problem and the fix. :)
> 
> > 
> > This doesn't look like a hw property but a configuration item. Also I don't
> > understand the problematic case. The i.MX is sending continuously and then
> > doesn't receive bytes until the DMA buffer is full?
> 
> Yes
> 
> > What is the DMA buffer?
> > You don't mean the FIFO here, do you?
> > 
> 
> DMA buffer is not HW FIFO. Is the buffer provided by serial driver to DMA to store data.
> 
> > That doesn't sound like a good fix but more like a work around. Which other
> > options did you test to fix your problem?
> > 
> 
> I haven't tried any other, because except using maybe, ioctl I haven't
> got anything better.

My question didn't target where to configure the buffer size instead of
dts. I wonder if it would help to change the fifo watermark limits for
example.

> Our problem is that in our system some serial ports needs to have
> really low data latency, where others trade more bytes over data
> latency. This situation results in a need of beeing able to have
> different DMA buffer size for different ports. 
> 
> How can DMA buffer size affect latency?
> DMA works like this: (To answer to your question DMA buffer is not FIFO)
>  1. Transfer the data from HW FIFO to DMA buffer based on some interrupts (character received, etc)
>  2. Transfer the DMA buffer back to serial port based on some events (buffer full, aging timer, etc)
>  3. Serial port forwards to tty buffer.

BTW In the past I saw the serial core introduce latency, too. Are you
sure that's not your bottle neck?

> Data availability to consumer depends on: DMA buffer size, baud rate
> and communication pattern. By communication patter I'm refering that
> we send data continuoselly (serial line is never idle) or packet by
> packet (serial line is idle in between)
> Example:
>       Baud: 19200 (1Byte = 0.52 ms)
>       DMA buffer size: 100 bytes
>       Communication pattern: continuously 
>       =>  DMA will return data to serial port only when DMA buffer is
>       full, since the communication is continuously. This result in a
>       data latency of 0.52 ms* 100bytes = 52ms. In case the buffer
>       will be 200bytes the letency will be double.
> 
> I agree with you, this is not directly a hw property but a DMA configuration item. 
> But I've found this to be the best way to configure this comparing with using ioctl.
> 
> Let me know if you need more clarification and I would really be open
> to other options that will solve our problem.
> 
> <snip>
> 
> > > +- fsl,dma-size : Indicate the size of the DMA buffer and its periods
> > 
> > This is a sparse description, just from reading that I don't understand what it
> > does.
> > 
> 
> Serial driver configures a circular ring of buffers for DMA. Here we
> can configure the size and the number of buffers.

The problem is: How should a person, who wants to make available a port
on a machine via dts, choose what value to use for fsl,dma-size?

What you want (for a low latency port) is that also small amounts of
data received are passed quickly to the upper layer. The knob you
identified to be available for that is the dma buffer size.

I'd prefer to talk about low latency instead of buffer sizes when
setting parameters for the port. That this influences the buffer size
(and maybe watermark settings) under the hood shouldn't matter for the
person configuring the low latency property.

Best regards
Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-König            |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH v5 0/5] net/i40e: implement dynamic mapping of flow types to pctypes
From: Ferruh Yigit @ 2017-10-04 21:48 UTC (permalink / raw)
  To: Kirill Rybalchenko, dev; +Cc: andrey.chilikin, beilei.xing, jingjing.wu
In-Reply-To: <1507121533-142655-1-git-send-email-kirill.rybalchenko@intel.com>

On 10/4/2017 1:52 PM, Kirill Rybalchenko wrote:
> Implement dynamic mapping of software flow types to hardware pctypes.
> This allows to map new flow types to pctypes without changing
> API of the driver.
> 
> v2:
> Remove unnecessary check for new flow types.
> Re-arrange patchset to avoid compillation errors.
> Remove unnecessary usage of statically defined flow types and pctypes.
> 
> v3:
> Remove unnecessary bit operations in I40E_PFQF_HENA and I40E_VFQF_HENA registers.
> Add new definition in enum i40e_filter_pctype for for invalid pctype.
> Fixed bugs in i40e_pctype_to_flowtype and i40e_flowtype_to_pctype functions.
> Function rte_pmd_i40e_flow_type_mapping_get returns now full mapping table.
> testpmd: changed command syntax from 'pctype mapping...' to
> 'port config pctype mapping...' and 'show port pctype mapping'
> Various small modifications in code style after reviewing.
> 
> v4:
> Change prototypes of some static functions.
> Move declaration of automatic variables to beginning of function.
> Move declaration of I40E_FILTER_PCTYPE_INVALID to i40e_ethdev.h
> Fix some typos in source filea and documentation.
> 
> v5:
> Fix code style warnings and documentation.
> No functional changes.
> 

> 
> Kirill Rybalchenko (5):
>   net/i40e: remove unnecessary bit operations
>   net/i40e: implement dynamic mapping of sw flow types to hw pctypes
>   net/i40e: add new functions to manipulate with pctype mapping table
>   app/testpmd: add new commands to manipulate with      pctype mapping
>   ethdev: remove unnecessary check for new flow type

Series Reviewed-by: Ferruh Yigit <ferruh.yigit@intel.com>

^ permalink raw reply

* Re: [Part2 PATCH v5 09/31] crypto: ccp: Build the AMD secure processor driver only with AMD CPU support
From: Borislav Petkov @ 2017-10-04 21:47 UTC (permalink / raw)
  To: Brijesh Singh
  Cc: x86, kvm, linux-kernel, Tom Lendacky, Gary Hook, Herbert Xu,
	David S. Miller, linux-crypto
In-Reply-To: <20171004131412.13038-10-brijesh.singh@amd.com>

On Wed, Oct 04, 2017 at 08:13:50AM -0500, Brijesh Singh wrote:
> From: Borislav Petkov <bp@suse.de>
> 
> This is AMD-specific hardware so present it in Kconfig only when AMD
> CPU support is enabled or on ARM64 where it is also used.
> 
> Signed-off-by: <brijesh.singh@amd.com>
> Signed-off-by: Borislav Petkov <bp@suse.de>

For the future, when you carry a patch from someone else, your SOB
should come after the author's. I.e.,

Signed-off-by: Borislav Petkov <bp@suse.de>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>

i.e., the first SOB is the author's and the second is yours which means,
you've handled the patch further on, like sending it upstream, for
example.

Thx.

-- 
Regards/Gruss,
    Boris.

SUSE Linux GmbH, GF: Felix Imendörffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nürnberg)
-- 

^ permalink raw reply

* Re: Mimic timeline
From: Sage Weil @ 2017-10-04 21:46 UTC (permalink / raw)
  To: ceph-devel, ceph-maintainers, ceph-users
In-Reply-To: <alpine.DEB.2.11.1710042054030.27705@piezo.novalocal>

On Wed, 4 Oct 2017, Sage Weil wrote:
> Hi everyone,
> 
> After further discussion we are targetting 9 months for Mimic 13.2.0:
> 
>  - Mar 16, 2018 feature freeze
>  - May 1, 2018 release
> 
> Upgrades for Mimic will be from Luminous only (we've already made that a 
> required stop), but we plan to allow Luminous -> Nautilus too (and Mimic 
> -> O).

Also, each release will be stable, with bug fixes for 2 cycles (18 
months).  Here are the proposed changes to the release cycle docs:

	https://github.com/ceph/ceph/pull/18117/files

sage

^ permalink raw reply

* Re: [PATCH 1/2] arm64: qcom: sbc: Name GPIO lines
From: Stephen Boyd @ 2017-10-04 21:45 UTC (permalink / raw)
  To: Linus Walleij
  Cc: linux-arm-kernel, linux-arm-msm, Andy Gross, David Brown,
	Bjorn Andersson, linux-soc
In-Reply-To: <20171003091155.7138-1-linus.walleij@linaro.org>

On 10/03, Linus Walleij wrote:
> This names the GPIO lines on the APQ8016 "SBC" also known
> as the DragonBoard 410c, according to the schematic. This
> is necessary for a conforming userspace looking across
> all GPIO chips for the GPIO lines named "GPIO-A" thru
> "GPIO-L".
> 
> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
> ---
> I don't have this hardware available, you can test it
> easily by compiling tools/gpio/* and issue "lsgpio" to
> see the GPIO line names in the console.
> 
> Please apply this even if you're not applying the second
> patch renaming the DTS files.
> ---
>  arch/arm64/boot/dts/qcom/apq8016-sbc.dts | 167 +++++++++++++++++++++++++++++++

Can you add this to the apq8016-sbc.dtsi file instead? Probably
we should fold the two files together, but so far nothing goes
into the .dts file besides compatible string and model for the
board.

>  1 file changed, 167 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/qcom/apq8016-sbc.dts b/arch/arm64/boot/dts/qcom/apq8016-sbc.dts
> index 825f489a2af7..40b0d62861bb 100644
> --- a/arch/arm64/boot/dts/qcom/apq8016-sbc.dts
> +++ b/arch/arm64/boot/dts/qcom/apq8016-sbc.dts
> @@ -19,3 +19,170 @@
>  	model = "Qualcomm Technologies, Inc. APQ 8016 SBC";
>  	compatible = "qcom,apq8016-sbc", "qcom,apq8016", "qcom,sbc";
>  };
> +
> +/*
> + * Legend: proper name = the GPIO line is used as GPIO
> + *         NC = not connected (pin out but not routed from the chip to
> + *              anything the board)
> + *         "[PER]" = pin is muxed for [peripheral] (not GPIO)
> + *         "" = no idea, schematic doesn't say, could be
> + *              unrouted (not connected to any external pin)

This never happens?

> + *         LSEC = Low Speed External Connector
> + *         HSEC = High Speed External Connector

This is not in the patch?

> + *
> + * Line names are taken from the schematic "DragonBoard410c"
> + * dated monday, august 31, 2015. Page 5 in particular.
> + *
> + * For the lines routed to the external connectors the
> + * lines are named after the 96Boards CE Specification 1.0,
> + * Appendix "Expansion Connector Signal Description".
> + *
> + * When the 96Board naming of a line and the schematic name of
> + * the same line are in conflict, the 96Board specification
> + * takes precedence, which means that the external UART on the
> + * LSEC is named UART0 while the schematic and SoC names this
> + * UART3. This is only for the informational lines i.e. "[FOO]",
> + * the GPIO named lines "GPIO-A" thru "GPIO-L" are the only
> + * ones actually used for GPIO.
> + */
> +&msmgpio {

And also not use phandles and put the gpio-line-names into the
node at the correct path?

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

^ permalink raw reply

* [PATCH 1/2] arm64: qcom: sbc: Name GPIO lines
From: Stephen Boyd @ 2017-10-04 21:45 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20171003091155.7138-1-linus.walleij@linaro.org>

On 10/03, Linus Walleij wrote:
> This names the GPIO lines on the APQ8016 "SBC" also known
> as the DragonBoard 410c, according to the schematic. This
> is necessary for a conforming userspace looking across
> all GPIO chips for the GPIO lines named "GPIO-A" thru
> "GPIO-L".
> 
> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
> ---
> I don't have this hardware available, you can test it
> easily by compiling tools/gpio/* and issue "lsgpio" to
> see the GPIO line names in the console.
> 
> Please apply this even if you're not applying the second
> patch renaming the DTS files.
> ---
>  arch/arm64/boot/dts/qcom/apq8016-sbc.dts | 167 +++++++++++++++++++++++++++++++

Can you add this to the apq8016-sbc.dtsi file instead? Probably
we should fold the two files together, but so far nothing goes
into the .dts file besides compatible string and model for the
board.

>  1 file changed, 167 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/qcom/apq8016-sbc.dts b/arch/arm64/boot/dts/qcom/apq8016-sbc.dts
> index 825f489a2af7..40b0d62861bb 100644
> --- a/arch/arm64/boot/dts/qcom/apq8016-sbc.dts
> +++ b/arch/arm64/boot/dts/qcom/apq8016-sbc.dts
> @@ -19,3 +19,170 @@
>  	model = "Qualcomm Technologies, Inc. APQ 8016 SBC";
>  	compatible = "qcom,apq8016-sbc", "qcom,apq8016", "qcom,sbc";
>  };
> +
> +/*
> + * Legend: proper name = the GPIO line is used as GPIO
> + *         NC = not connected (pin out but not routed from the chip to
> + *              anything the board)
> + *         "[PER]" = pin is muxed for [peripheral] (not GPIO)
> + *         "" = no idea, schematic doesn't say, could be
> + *              unrouted (not connected to any external pin)

This never happens?

> + *         LSEC = Low Speed External Connector
> + *         HSEC = High Speed External Connector

This is not in the patch?

> + *
> + * Line names are taken from the schematic "DragonBoard410c"
> + * dated monday, august 31, 2015. Page 5 in particular.
> + *
> + * For the lines routed to the external connectors the
> + * lines are named after the 96Boards CE Specification 1.0,
> + * Appendix "Expansion Connector Signal Description".
> + *
> + * When the 96Board naming of a line and the schematic name of
> + * the same line are in conflict, the 96Board specification
> + * takes precedence, which means that the external UART on the
> + * LSEC is named UART0 while the schematic and SoC names this
> + * UART3. This is only for the informational lines i.e. "[FOO]",
> + * the GPIO named lines "GPIO-A" thru "GPIO-L" are the only
> + * ones actually used for GPIO.
> + */
> +&msmgpio {

And also not use phandles and put the gpio-line-names into the
node at the correct path?

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

^ permalink raw reply

* Re: [Qemu-devel] [PATCH v1 2/5] netduino2: Specify the valid CPUs
From: Alistair Francis @ 2017-10-04 21:43 UTC (permalink / raw)
  To: Igor Mammedov
  Cc: Alistair Francis, qemu-devel@nongnu.org Developers,
	Eduardo Habkost, Philippe Mathieu-Daudé, Marcel Apfelbaum
In-Reply-To: <20171004130258.0a977151@nial.brq.redhat.com>

On Wed, Oct 4, 2017 at 4:02 AM, Igor Mammedov <imammedo@redhat.com> wrote:
> On Tue, 3 Oct 2017 13:05:11 -0700
> Alistair Francis <alistair.francis@xilinx.com> wrote:
>
>> List all possible valid CPU options.
>>
>> Although the board only ever has a Cortex-M3 we mark the Cortex-M4 as
>> supported because the Netduino2 Plus supports the Cortex-M4 and the
>> Netduino2 Plus is similar to the Netduino2.
>>
>> Signed-off-by: Alistair Francis <alistair.francis@xilinx.com>
>> ---
>>
>> RFC v2:
>>  - Use a NULL terminated list
>>  - Add the Cortex-M4 for testing
>>
>>
>>  hw/arm/netduino2.c | 9 ++++++++-
>>  1 file changed, 8 insertions(+), 1 deletion(-)
>>
>> diff --git a/hw/arm/netduino2.c b/hw/arm/netduino2.c
>> index f936017d4a..b68ecf2c08 100644
>> --- a/hw/arm/netduino2.c
>> +++ b/hw/arm/netduino2.c
>> @@ -34,18 +34,25 @@ static void netduino2_init(MachineState *machine)
>>      DeviceState *dev;
>>
>>      dev = qdev_create(NULL, TYPE_STM32F205_SOC);
>> -    qdev_prop_set_string(dev, "cpu-type", ARM_CPU_TYPE_NAME("cortex-m3"));
>> +    qdev_prop_set_string(dev, "cpu-type", machine->cpu_type);
>>      object_property_set_bool(OBJECT(dev), true, "realized", &error_fatal);
>>
>>      armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename,
>>                         FLASH_SIZE);
>>  }
>>
>> +const char *netduino_valid_cpus[] = { ARM_CPU_TYPE_NAME("cortex-m3"),
> style nit,                               ^^^ put entries on new line with typical 4 space alignment

Do you mean like this?

const char *netduino_valid_cpus[] = {
                                    ARM_CPU_TYPE_NAME("cortex-m3"),
                                    ARM_CPU_TYPE_NAME("cortex-m4"),
                                    NULL };

Thanks,
Alistair

>> +                                      ARM_CPU_TYPE_NAME("cortex-m4"),
>> +                                      NULL
>> +                                    };
>
>> +
>>  static void netduino2_machine_init(MachineClass *mc)
>>  {
>>      mc->desc = "Netduino 2 Machine";
>>      mc->init = netduino2_init;
>>      mc->ignore_memory_transaction_failures = true;
>> +    mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-m3");
>> +    mc->valid_cpu_types = netduino_valid_cpus;
>>  }
>>
>>  DEFINE_MACHINE("netduino2", netduino2_machine_init)
>

^ permalink raw reply

* Re: [PATCH 1/2] Revert "vmalloc: back off when the current task is killed"
From: Tetsuo Handa @ 2017-10-04 21:42 UTC (permalink / raw)
  To: hannes; +Cc: akpm, alan, hch, mhocko, linux-mm, linux-kernel, kernel-team
In-Reply-To: <20171004210027.GA2973@cmpxchg.org>

Johannes Weiner wrote:
> On Thu, Oct 05, 2017 at 05:49:43AM +0900, Tetsuo Handa wrote:
> > On 2017/10/05 3:59, Johannes Weiner wrote:
> > > But the justification to make that vmalloc() call fail like this isn't
> > > convincing, either. The patch mentions an OOM victim exhausting the
> > > memory reserves and thus deadlocking the machine. But the OOM killer
> > > is only one, improbable source of fatal signals. It doesn't make sense
> > > to fail allocations preemptively with plenty of memory in most cases.
> > 
> > By the time the current thread reaches do_exit(), fatal_signal_pending(current)
> > should become false. As far as I can guess, the source of fatal signal will be
> > tty_signal_session_leader(tty, exit_session) which is called just before
> > tty_ldisc_hangup(tty, cons_filp != NULL) rather than the OOM killer. I don't
> > know whether it is possible to make fatal_signal_pending(current) true inside
> > do_exit() though...
> 
> It's definitely not the OOM killer, the memory situation looks fine
> when this happens. I didn't look closer where the signal comes from.
> 

Then, we could check tsk_is_oom_victim() instead of fatal_signal_pending().

> That said, we trigger this issue fairly easily. We tested the revert
> over night on a couple thousand machines, and it fixed the issue
> (whereas the control group still saw the crashes).
> 

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

^ permalink raw reply

* Re: [PATCH 1/2] Revert "vmalloc: back off when the current task is killed"
From: Tetsuo Handa @ 2017-10-04 21:42 UTC (permalink / raw)
  To: hannes; +Cc: akpm, alan, hch, mhocko, linux-mm, linux-kernel, kernel-team
In-Reply-To: <20171004210027.GA2973@cmpxchg.org>

Johannes Weiner wrote:
> On Thu, Oct 05, 2017 at 05:49:43AM +0900, Tetsuo Handa wrote:
> > On 2017/10/05 3:59, Johannes Weiner wrote:
> > > But the justification to make that vmalloc() call fail like this isn't
> > > convincing, either. The patch mentions an OOM victim exhausting the
> > > memory reserves and thus deadlocking the machine. But the OOM killer
> > > is only one, improbable source of fatal signals. It doesn't make sense
> > > to fail allocations preemptively with plenty of memory in most cases.
> > 
> > By the time the current thread reaches do_exit(), fatal_signal_pending(current)
> > should become false. As far as I can guess, the source of fatal signal will be
> > tty_signal_session_leader(tty, exit_session) which is called just before
> > tty_ldisc_hangup(tty, cons_filp != NULL) rather than the OOM killer. I don't
> > know whether it is possible to make fatal_signal_pending(current) true inside
> > do_exit() though...
> 
> It's definitely not the OOM killer, the memory situation looks fine
> when this happens. I didn't look closer where the signal comes from.
> 

Then, we could check tsk_is_oom_victim() instead of fatal_signal_pending().

> That said, we trigger this issue fairly easily. We tested the revert
> over night on a couple thousand machines, and it fixed the issue
> (whereas the control group still saw the crashes).
> 

^ permalink raw reply

* Re: [PATCH] btrfs: avoid overflow when sector_t is 32 bit
From: Goffredo Baroncelli @ 2017-10-04 21:42 UTC (permalink / raw)
  To: bo.li.liu, dsterba, linux-btrfs, Jean-Denis Girard,
	Goffredo Baroncelli
In-Reply-To: <20171004171350.GA4902@dhcp-10-211-47-181.usdhcp.oraclecorp.com>

On 10/04/2017 07:13 PM, Liu Bo wrote:
> On Wed, Oct 04, 2017 at 04:22:28PM +0200, David Sterba wrote:
>> On Tue, Oct 03, 2017 at 07:31:10PM +0200, Goffredo Baroncelli wrote:
>>> From: Goffredo Baroncelli <kreijack@inwind.it>
>>>
>>> Jean-Denis Girard noticed commit c821e7f3 "pass bytes to
>>> btrfs_bio_alloc" (https://patchwork.kernel.org/patch/9763081/) introduces a
>>> regression on 32 bit machines.
>>> When CONFIG_LBDAF is _not_ defined (CONFIG_LBDAF == Support for large
>>> (2TB+) block devices and files) sector_t is 32 bit on 32bit machines.
>>>
>>> In the function submit_extent_page, 'sector' (which is sector_t type) is
>>> multiplied by 512 to convert it from sectors to bytes, leading to an
>>> overflow when the disk is bigger than 4GB (!).
>>
>> That's not good. There are some known typedefs that hide the 32bit/64bit
>> differences but the LBDAF and sector_t is new to me. Thanks for the
>> report and fix, I'll get it to linus/master tree in the next batch so it
>> can go to stable tree.
>>
>> I've seen sector_t used in places where it is not necessary so I'll try
>> to minimize the usage and more surprises from the << 9 shifts.
>>
>> Reviewed-by: David Sterba <dsterba@suse.com>
>> Fixes: c821e7f3 ("btrfs: pass bytes to btrfs_bio_alloc")
>> CC: stable@vger.kernel.org # 4.13+
> 
> However, this sector_t is passed from its callers, e.g.
> 
> __do_readpage()
> {
> 	sector_t sector;
> 	...
> 	sector = em->block_start >> 9;
> 	...
> }
> 
> if sector_t is 32bit, the above %sector could also lose high bits.
> Some cleanups are needed to use u64 directly.

If sector_t is  32bit, the kernel can't access disk bigger than 2TB. So I suppose that block_start is less than 4GB.
> 
> Even with this patch, I suspect that there might be errors from block
> layer as sector_t is used everywhere in block layer.
> 
> For a btrfs FS that is created and used on 64bit system, it'll be
> causing trouble anyway if letting it mount 32bit system, lets refuse
> the mount firstly.

I think that the check should be:

if sizeof(sector_t) < 8 && filesystem_end > 2TB then
	do_not_mount_it


I am not sure what the other fs does

> 
> Thanks,
> 
> -liubo
> 


-- 
gpg @keyserver.linux.it: Goffredo Baroncelli <kreijackATinwind.it>
Key fingerprint BBF5 1610 0B64 DAC6 5F7D  17B2 0EDA 9B37 8B82 E0B5

^ permalink raw reply

* Re: Linux Plumbers MD BOF discussion notes
From: NeilBrown @ 2017-10-04 21:41 UTC (permalink / raw)
  To: Artur Paszkiewicz, Mikael Abrahamsson; +Cc: linux-raid
In-Reply-To: <619758c0-9ca4-c25d-c61b-f411b095041d@intel.com>

[-- Attachment #1: Type: text/plain, Size: 8435 bytes --]

On Wed, Oct 04 2017, Artur Paszkiewicz wrote:

>
> Also, our customers are asking specifically for an option to "hide" the
> member drives. Making it impossible to write to the devices is ok, but
> they would like to see only the md device, "like hardware raid". One of
> the reasons is that some monitoring or inventory scan applications treat
> md arrays and their components as separate storage devices. They should
> probably modify their software but maybe that's not possible.

What exactly is meant by "hide".  How, exactly, does this software scan
all devices?  /proc/partitions? /sys/block? /sys/class/block?
/dev/disks?  All of the above.

Modifying their application *must* be on the table, else modify the
kernel is *not* on the table.  I'm certainly open to enhancing the
kernel so that it is easy to skip a particular class of devices, but if
their application chooses to ignore the information the kernel provides,
then the fact that the application doesn't work is their problem, not
ours.


>
> I've been experimenting with different solutions and here is a patch
> that allows to "hide" disk devices and their partitions by writing to a
> sysfs attribute. It removes the device nodes (on devtmpfs), links in
> /sys/block/ and removes the devices from the block class list, so they
> won't be included in places like /proc/partitions, /sys/class/block/,
> lsblk and so on. The device's "real" sysfs directory under /sys/devices/
> is still available, also the links in /sys/dev/block/ are preserved.
> Applications like mdadm can use this to hide/unhide their component
> devices.

Can you confirm that this addresses the customer problem?  Do you know
which of these lists their code looks at?

Thanks,
NeilBrown


>
> Thanks,
> Artur
>
> diff --git a/block/genhd.c b/block/genhd.c
> index 7f520fa25d16..58b8e3eb14af 100644
> --- a/block/genhd.c
> +++ b/block/genhd.c
> @@ -685,6 +685,55 @@ void del_gendisk(struct gendisk *disk)
>  }
>  EXPORT_SYMBOL(del_gendisk);
>  
> +static int hide_disk(struct gendisk *disk)
> +{
> +	struct device *ddev = disk_to_dev(disk);
> +	struct disk_part_iter piter;
> +	struct hd_struct *part;
> +	int ret;
> +
> +	ret = device_hide(ddev);
> +	if (ret)
> +		return ret;
> +
> +	disk_part_iter_init(&piter, disk,
> +			     DISK_PITER_INCL_EMPTY | DISK_PITER_REVERSE);
> +	while ((part = disk_part_iter_next(&piter)))
> +		device_hide(part_to_dev(part));
> +	disk_part_iter_exit(&piter);
> +
> +	if (!sysfs_deprecated)
> +		sysfs_remove_link(block_depr, dev_name(ddev));
> +
> +	return ret;
> +}
> +
> +static int unhide_disk(struct gendisk *disk)
> +{
> +	struct device *ddev = disk_to_dev(disk);
> +	struct disk_part_iter piter;
> +	struct hd_struct *part;
> +	int ret;
> +
> +	ret = device_unhide(ddev);
> +	if (ret)
> +		return ret;
> +
> +	disk_part_iter_init(&piter, disk, DISK_PITER_INCL_EMPTY);
> +	while ((part = disk_part_iter_next(&piter)))
> +		device_unhide(part_to_dev(part));
> +	disk_part_iter_exit(&piter);
> +
> +	if (!sysfs_deprecated) {
> +		if (sysfs_create_link(block_depr, &ddev->kobj,
> +				      kobject_name(&ddev->kobj)))
> +			pr_warn("%s: failed to restore /sys/block link\n",
> +				disk->disk_name);
> +	}
> +
> +	return ret;
> +}
> +
>  /* sysfs access to bad-blocks list. */
>  static ssize_t disk_badblocks_show(struct device *dev,
>  					struct device_attribute *attr,
> @@ -1017,6 +1066,31 @@ static ssize_t disk_discard_alignment_show(struct device *dev,
>  	return sprintf(buf, "%d\n", queue_discard_alignment(disk->queue));
>  }
>  
> +static ssize_t disk_hidden_show(struct device *dev,
> +				struct device_attribute *attr,
> +				char *buf)
> +{
> +	return sprintf(buf, "%d\n", device_is_hidden(dev));
> +}
> +
> +static ssize_t disk_hidden_store(struct device *dev,
> +				 struct device_attribute *attr,
> +				 const char *buf, size_t len)
> +{
> +	struct gendisk *disk = dev_to_disk(dev);
> +	bool hide;
> +	int ret;
> +
> +	ret = kstrtobool(buf, &hide);
> +	if (ret)
> +		return ret;
> +
> +	if (hide != device_is_hidden(dev))
> +		ret = hide ? hide_disk(disk) : unhide_disk(disk);
> +
> +	return ret ?: len;
> +}
> +
>  static DEVICE_ATTR(range, S_IRUGO, disk_range_show, NULL);
>  static DEVICE_ATTR(ext_range, S_IRUGO, disk_ext_range_show, NULL);
>  static DEVICE_ATTR(removable, S_IRUGO, disk_removable_show, NULL);
> @@ -1030,6 +1104,8 @@ static DEVICE_ATTR(stat, S_IRUGO, part_stat_show, NULL);
>  static DEVICE_ATTR(inflight, S_IRUGO, part_inflight_show, NULL);
>  static DEVICE_ATTR(badblocks, S_IRUGO | S_IWUSR, disk_badblocks_show,
>  		disk_badblocks_store);
> +static DEVICE_ATTR(hidden, S_IRUGO | S_IWUSR, disk_hidden_show,
> +		   disk_hidden_store);
>  #ifdef CONFIG_FAIL_MAKE_REQUEST
>  static struct device_attribute dev_attr_fail =
>  	__ATTR(make-it-fail, S_IRUGO|S_IWUSR, part_fail_show, part_fail_store);
> @@ -1058,6 +1134,7 @@ static struct attribute *disk_attrs[] = {
>  #ifdef CONFIG_FAIL_IO_TIMEOUT
>  	&dev_attr_fail_timeout.attr,
>  #endif
> +	&dev_attr_hidden.attr,
>  	NULL
>  };
>  
> diff --git a/block/partition-generic.c b/block/partition-generic.c
> index c5ec8246e25e..0223a37c7a8c 100644
> --- a/block/partition-generic.c
> +++ b/block/partition-generic.c
> @@ -350,6 +350,9 @@ struct hd_struct *add_partition(struct gendisk *disk, int partno,
>  	if (err)
>  		goto out_put;
>  
> +	if (device_is_hidden(ddev))
> +		device_hide(pdev);
> +
>  	err = -ENOMEM;
>  	p->holder_dir = kobject_create_and_add("holders", &pdev->kobj);
>  	if (!p->holder_dir)
> diff --git a/drivers/base/core.c b/drivers/base/core.c
> index 755451f684bc..0804a45b8fbf 100644
> --- a/drivers/base/core.c
> +++ b/drivers/base/core.c
> @@ -1871,6 +1871,71 @@ void device_del(struct device *dev)
>  }
>  EXPORT_SYMBOL_GPL(device_del);
>  
> +DEFINE_KLIST(klist_hidden_devices, NULL, NULL);
> +
> +bool device_is_hidden(struct device *dev)
> +{
> +	bool ret = false;
> +
> +	if (dev->class) {
> +		mutex_lock(&dev->class->p->mutex);
> +		ret = (dev->knode_class.n_klist == &klist_hidden_devices);
> +		mutex_unlock(&dev->class->p->mutex);
> +	}
> +	return ret;
> +}
> +
> +int device_hide(struct device *dev)
> +{
> +	char *envp[] = { "EVENT=hide", NULL };
> +
> +	if (!dev->class)
> +		return -EINVAL;
> +
> +	if (MAJOR(dev->devt))
> +		devtmpfs_delete_node(dev);
> +
> +	device_remove_class_symlinks(dev);
> +
> +	mutex_lock(&dev->class->p->mutex);
> +	/* remove the device from the class list */
> +	klist_remove(&dev->knode_class);
> +	/* add to the hidden devices list */
> +	klist_add_tail(&dev->knode_class, &klist_hidden_devices);
> +	mutex_unlock(&dev->class->p->mutex);
> +
> +	kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
> +
> +	return 0;
> +}
> +
> +int device_unhide(struct device *dev)
> +{
> +	char *envp[] = { "EVENT=unhide", NULL };
> +	int err;
> +
> +	if (!dev->class)
> +		return -EINVAL;
> +
> +	err = device_add_class_symlinks(dev);
> +	if (err)
> +		return err;
> +
> +	if (MAJOR(dev->devt))
> +		devtmpfs_create_node(dev);
> +
> +	mutex_lock(&dev->class->p->mutex);
> +	/* remove the device from the hidden devices list */
> +	klist_remove(&dev->knode_class);
> +	/* tie the class to the device */
> +	klist_add_tail(&dev->knode_class, &dev->class->p->klist_devices);
> +	mutex_unlock(&dev->class->p->mutex);
> +
> +	kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
> +
> +	return err;
> +}
> +
>  /**
>   * device_unregister - unregister device from system.
>   * @dev: device going away.
> diff --git a/include/linux/device.h b/include/linux/device.h
> index beabdbc08420..90ab1e6b63c6 100644
> --- a/include/linux/device.h
> +++ b/include/linux/device.h
> @@ -1118,6 +1118,9 @@ extern void device_unregister(struct device *dev);
>  extern void device_initialize(struct device *dev);
>  extern int __must_check device_add(struct device *dev);
>  extern void device_del(struct device *dev);
> +extern bool device_is_hidden(struct device *dev);
> +extern int device_hide(struct device *dev);
> +extern int device_unhide(struct device *dev);
>  extern int device_for_each_child(struct device *dev, void *data,
>  		     int (*fn)(struct device *dev, void *data));
>  extern int device_for_each_child_reverse(struct device *dev, void *data,

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 832 bytes --]

^ permalink raw reply


This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.