DPDK patches and discussions
 help / color / mirror / Atom feed
* [dpdk-dev] [RFC PATCH 0/2] RAW Device Support
@ 2017-11-08 17:40 Hemant Agrawal
  2017-11-08 17:40 ` [dpdk-dev] [RFC PATCH 1/2] lib: introduce raw device library Hemant Agrawal
  2017-11-08 17:40 ` [dpdk-dev] [RFC PATCH 2/2] config: enable compilation of " Hemant Agrawal
  0 siblings, 2 replies; 3+ messages in thread
From: Hemant Agrawal @ 2017-11-08 17:40 UTC (permalink / raw)
  To: dev; +Cc: fiona.trahe, rosen.xu, shreyansh.jain

Rawdevice Support in DPDK
-------------------------

This RFC describes support for rawdevices or generic device support in DPDK.
It is supported by following writeup accompanied by skeleton header file with
declarations.

Motivation
==========

In terms of device flavor (type) support, DPDK currently has ethernet
(lib_ether), cryptodev (libcryptodev), eventdev (libeventdev) and vdev
(virtual device) support.

For a new type of device, for example an accelerator, there are not many
options except either:
1. create another lib/librte_MySpecialDev, driver/MySpecialDrv and use it
through Bus/PMD model.
2. Or, create a vdev and implement necessary custom APIs which are directly
exposed from driver layer. However this may still require changes in bus code
in DPDK.

Either method is unclean (touching lib for specific context) and possibly
non-upstreamable (custom APIs). Applications and customers prefers uniform
device view and programming model.


Scope
=====

The rawdevice implementation is targetted towards various accelerator use cases
which cannot be generalized within existing device models. Aim is to provided a
generalized structure at the cost of portability guarantee. Specific PMDs may
also expose any specific config APIs. Applications built over such devices are
special use-cases involving IP blocks.

The rawdevice  may also connect to other standard devices using adapter or other
methods e.g. eventdev – single place to get all events.

Proposed Solution
=================

Defining a very generic super-set of device type and its device operations that
can be exposed such that any new/upcoming/experimental device can be layered
over it. This RFC names it 'rawdevice' to signify that the device doesn't have
any flavor/type associated with it which is advertised (like net, crypto etc).

A *rte_rawdevice* is a raw/generic device without any standard configuration
or input/output method assumption.

Thus, driver for a new accelerator block, which requires operations for
start/stop/enqueue/dequeue, can be quickly strapped over this rawdevice layer.
Thereafter, any appropriate bus can scan for it (assuming device is discoverable
over the Linux interfaces like sysfs) and match it against registered drivers.

Similarly, for a new accelerator or a wireless device, which doesn't fit the eth
type, a driver can be registered with a bus (on which its device would be
scannable) and use this layer for configuring the device.

It can also serve as a staging area for new type of devices till they
find some commonality and can be standardized.

The outline of this proposed library is same as existing ether/crypto devices.

     +-----------------------------------------------------------+
     |                     Application(s)                        |
     +------------------------------.----------------------------+
                                    |
                                    |
     +------------------------------'----------------------------+
     |                       DPDK Framework (APIs)               |
     +--------------|----|-----------------|---------------------+
                   /      \                 \
            (crypto ops)  (eth ops)      (rawdev ops)        +----+
            /               \                 \              |DrvA|
     +-----'---+        +----`----+        +---'-----+       +----+
     | crypto  |        | ethdev  |        | raw     |
     +--/------+        +---/-----+        +----/----+       +----+
       /\                __/\                  /   ..........|DrvB|
      /  \              /    \                / ../    \     +----+
  +====+ +====+    +====+ +====+            +==/=+      ```Bus Probe 
  |DevA| |DevB|    |DevC| |DevD|            |DevF|
  +====+ +====+    +====+ +====+            +====+
    |      |        |      |                 |    
  ``|``````|````````|``````|`````````````````|````````Bus Scan
   (PCI)   |       (PCI)  (PCI)            (PCI)
         (BusA)

 * It is assumed above that DrvB is a PCI type driver which registers itself
   with PCI Bus
 * Thereafter, when the PCI scan is done, during probe DrvB would match the
   rawdev DevF ID and take control of device
 * Applications can then continue using the device through rawdev API interfaces


Proposed Interfaces
===================

Following broad API categories are exposed by the rawdevice:

1) Device State Operations (start/stop/reset)
2) Communication Channel setup/teardown (queue)
3) Stat Operations (xstats)
4) Enqueue/Dequeue Operations
5) Firmware Operations (Load/unload)

Notes:
For (1), other than standard start/stop, reset has been added extra. This is for
cases where device power cycle has various definitions. Semantics of what
stop->start and what reset would mean are still open-ended.

For (2), though currently `queue` has been used a semantic, it would be possible
in implementation to use this with other methods like internally hosted rte_ring.

For (3), Reason for choosing xstats is to allow for the device to define its own
stats. Being a generic layer, it doesn't provide any existing fields.

For (4), Aim is to allow applications to post buffers (which can be arbit data)
to the device. It is device's responsibility to interpret and handle the buffer.
It can also be expanded to synchronous and async methods of posting buffer.
That would provide broader use-cases.

For (5), Aim is to allow for most basic device firmware management. In this, as
well as other operations, it is expected that those which are not implemneted
would return ENOTSUP allow the application to fail gracefully.

Future Work
===========
1. Support for hotplugging and interrupt handling
2. Support for adding dynamic operations (~IOCTLs)
3. Support for callbacks for enqueue and dequeue of buffers
4. Interfacing with Eth/Crypto/Event type devices for inline offloading

Hemant Agrawal (2):
  lib: introduce raw device library
  config: enable compilation of raw device library

 config/common_base                       |   7 +
 lib/Makefile                             |   3 +
 lib/librte_rawdev/Makefile               |  53 +++
 lib/librte_rawdev/rte_rawdev.c           | 626 +++++++++++++++++++++++++++++++
 lib/librte_rawdev/rte_rawdev.h           | 524 ++++++++++++++++++++++++++
 lib/librte_rawdev/rte_rawdev_pmd.h       | 540 ++++++++++++++++++++++++++
 lib/librte_rawdev/rte_rawdev_version.map |  28 ++
 7 files changed, 1781 insertions(+)
 create mode 100644 lib/librte_rawdev/Makefile
 create mode 100644 lib/librte_rawdev/rte_rawdev.c
 create mode 100644 lib/librte_rawdev/rte_rawdev.h
 create mode 100644 lib/librte_rawdev/rte_rawdev_pmd.h
 create mode 100644 lib/librte_rawdev/rte_rawdev_version.map

-- 
2.7.4

^ permalink raw reply	[flat|nested] 3+ messages in thread

* [dpdk-dev] [RFC PATCH 1/2] lib: introduce raw device library
  2017-11-08 17:40 [dpdk-dev] [RFC PATCH 0/2] RAW Device Support Hemant Agrawal
@ 2017-11-08 17:40 ` Hemant Agrawal
  2017-11-08 17:40 ` [dpdk-dev] [RFC PATCH 2/2] config: enable compilation of " Hemant Agrawal
  1 sibling, 0 replies; 3+ messages in thread
From: Hemant Agrawal @ 2017-11-08 17:40 UTC (permalink / raw)
  To: dev; +Cc: fiona.trahe, rosen.xu, shreyansh.jain

Raw device is a generalized interface for expanding non-generic devices
into DPDK framework. This library provides primitive interfaces which
enable creation of raw devices.

Signed-off-by: Hemant Agrawal <hemant.agrawal@nxp.com>
---
 lib/librte_rawdev/Makefile               |  53 +++
 lib/librte_rawdev/rte_rawdev.c           | 626 +++++++++++++++++++++++++++++++
 lib/librte_rawdev/rte_rawdev.h           | 524 ++++++++++++++++++++++++++
 lib/librte_rawdev/rte_rawdev_pmd.h       | 540 ++++++++++++++++++++++++++
 lib/librte_rawdev/rte_rawdev_version.map |  28 ++
 5 files changed, 1771 insertions(+)
 create mode 100644 lib/librte_rawdev/Makefile
 create mode 100644 lib/librte_rawdev/rte_rawdev.c
 create mode 100644 lib/librte_rawdev/rte_rawdev.h
 create mode 100644 lib/librte_rawdev/rte_rawdev_pmd.h
 create mode 100644 lib/librte_rawdev/rte_rawdev_version.map

diff --git a/lib/librte_rawdev/Makefile b/lib/librte_rawdev/Makefile
new file mode 100644
index 0000000..a2b22a1
--- /dev/null
+++ b/lib/librte_rawdev/Makefile
@@ -0,0 +1,53 @@
+#   BSD LICENSE
+#
+#   Copyright 2017 NXP
+#
+#   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 NXPnor 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.
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+# library name
+LIB = librte_rawdev.a
+
+# library version
+LIBABIVER := 1
+
+# build flags
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+LDLIBS += -lrte_eal -lrte_mempool -lrte_ring -lrte_mbuf
+
+# library source files
+SRCS-y += rte_rawdev.c
+
+# export include files
+SYMLINK-y-include += rte_rawdev.h
+
+# versioning export map
+EXPORT_MAP := rte_rawdev_version.map
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_rawdev/rte_rawdev.c b/lib/librte_rawdev/rte_rawdev.c
new file mode 100644
index 0000000..1269193
--- /dev/null
+++ b/lib/librte_rawdev/rte_rawdev.c
@@ -0,0 +1,626 @@
+/*
+ *   BSD LICENSE
+ *
+ *   Copyright 2017 NXP
+ *
+ *   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 NXPnor 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.
+ */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+
+#include <rte_byteorder.h>
+#include <rte_log.h>
+#include <rte_debug.h>
+#include <rte_dev.h>
+#include <rte_memory.h>
+#include <rte_memcpy.h>
+#include <rte_memzone.h>
+#include <rte_eal.h>
+#include <rte_per_lcore.h>
+#include <rte_lcore.h>
+#include <rte_atomic.h>
+#include <rte_branch_prediction.h>
+#include <rte_common.h>
+#include <rte_malloc.h>
+#include <rte_errno.h>
+
+#include "rte_rawdev.h"
+#include "rte_rawdev_pmd.h"
+
+#define RTE_RAW_MAX_DEVS	2
+
+struct rte_rawdev rte_rawdevices[RTE_RAW_MAX_DEVS];
+
+struct rte_rawdev *rte_rawdevs = &rte_rawdevices[0];
+
+static struct rte_rawdev_global rawdev_globals = {
+	.nb_devs		= 0
+};
+
+struct rte_rawdev_global *rte_rawdev_globals = &rawdev_globals;
+
+/* Event dev north bound API implementation */
+
+uint8_t
+rte_rawdev_count(void)
+{
+	return rte_rawdev_globals->nb_devs;
+}
+
+int
+rte_rawdev_get_dev_id(const char *name)
+{
+	int i;
+
+	if (!name)
+		return -EINVAL;
+
+	for (i = 0; i < rte_rawdev_globals->nb_devs; i++)
+		if ((strcmp(rte_rawdevices[i].data->name, name)
+				== 0) &&
+				(rte_rawdevices[i].attached ==
+						RTE_RAWDEV_ATTACHED))
+			return i;
+	return -ENODEV;
+}
+
+int
+rte_rawdev_socket_id(uint16_t dev_id)
+{
+	struct rte_rawdev *dev;
+
+	RTE_RAWDEV_VALID_DEVID_OR_ERR_RET(dev_id, -EINVAL);
+	dev = &rte_rawdevs[dev_id];
+
+	return dev->data->socket_id;
+}
+
+int
+rte_rawdev_info_get(uint16_t dev_id, struct rte_rawdev_info *dev_info)
+{
+	struct rte_rawdev *dev;
+
+	RTE_RAWDEV_VALID_DEVID_OR_ERR_RET(dev_id, -EINVAL);
+	dev = &rte_rawdevs[dev_id];
+
+	if (dev_info == NULL)
+		return -EINVAL;
+
+	memset(dev_info, 0, sizeof(struct rte_rawdev_info));
+
+	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dev_infos_get, -ENOTSUP);
+	(*dev->dev_ops->dev_infos_get)(dev, dev_info);
+
+	dev_info->dev = dev->dev;
+	if (dev->driver)
+		dev_info->driver_name = dev->driver->name;
+	return 0;
+}
+
+static inline int
+rte_rawdev_queue_config(struct rte_rawdev *dev __rte_unused,
+			 uint8_t nb_queues __rte_unused)
+{
+	/* to be done */
+	return 0;
+}
+
+int
+rte_rawdev_configure(uint16_t dev_id, void *dev_conf)
+{
+	struct rte_rawdev *dev;
+	struct rte_rawdev_info info;
+	int diag;
+
+	RTE_RAWDEV_VALID_DEVID_OR_ERR_RET(dev_id, -EINVAL);
+	dev = &rte_rawdevs[dev_id];
+
+	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dev_infos_get, -ENOTSUP);
+	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dev_configure, -ENOTSUP);
+
+	if (dev->data->dev_started) {
+		RTE_RDEV_LOG_ERR(
+		    "device %d must be stopped to allow configuration", dev_id);
+		return -EBUSY;
+	}
+
+	if (dev_conf == NULL)
+		return -EINVAL;
+
+	(*dev->dev_ops->dev_infos_get)(dev, &info);
+
+	/* Configure the device */
+	diag = (*dev->dev_ops->dev_configure)(dev);
+	if (diag != 0)
+		RTE_RDEV_LOG_ERR("dev%d dev_configure = %d", dev_id, diag);
+
+	return diag;
+}
+
+int
+rte_rawdev_queue_conf_get(uint16_t dev_id, uint8_t queue_id, void *queue_conf)
+{
+	struct rte_rawdev *dev;
+
+	RTE_RAWDEV_VALID_DEVID_OR_ERR_RET(dev_id, -EINVAL);
+	dev = &rte_rawdevs[dev_id];
+
+	if (queue_conf == NULL)
+		return -EINVAL;
+
+
+	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->queue_def_conf, -ENOTSUP);
+	(*dev->dev_ops->queue_def_conf)(dev, queue_id, queue_conf);
+	return 0;
+}
+
+
+int
+rte_rawdev_queue_setup(uint16_t dev_id, uint8_t queue_id, void *queue_conf)
+{
+	struct rte_rawdev *dev;
+	void *def_conf;
+
+	RTE_RAWDEV_VALID_DEVID_OR_ERR_RET(dev_id, -EINVAL);
+	dev = &rte_rawdevs[dev_id];
+
+	if (queue_conf == NULL) {
+		RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->queue_def_conf,
+					-ENOTSUP);
+		(*dev->dev_ops->queue_def_conf)(dev, queue_id, &def_conf);
+		queue_conf = &def_conf;
+	}
+
+	return (*dev->dev_ops->queue_setup)(dev, queue_id, queue_conf);
+}
+
+uint8_t
+rte_rawdev_queue_count(uint16_t dev_id)
+{
+	struct rte_rawdev *dev;
+
+	dev = &rte_rawdevs[dev_id];
+	return dev->data->nb_queues;
+}
+
+int
+rte_rawdev_dump(uint16_t dev_id, FILE *f)
+{
+	struct rte_rawdev *dev;
+
+	RTE_RAWDEV_VALID_DEVID_OR_ERR_RET(dev_id, -EINVAL);
+	dev = &rte_rawdevs[dev_id];
+	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dump, -ENOTSUP);
+
+	(*dev->dev_ops->dump)(dev, f);
+	return 0;
+
+}
+
+static int
+xstats_get_count(uint16_t dev_id, enum rte_rawdev_xstats_mode mode,
+		uint8_t queue_port_id)
+{
+	struct rte_rawdev *dev = &rte_rawdevs[dev_id];
+	if (dev->dev_ops->xstats_get_names != NULL)
+		return (*dev->dev_ops->xstats_get_names)(dev, mode,
+							queue_port_id,
+							NULL, NULL, 0);
+	return 0;
+}
+
+int
+rte_rawdev_xstats_names_get(uint16_t dev_id,
+		enum rte_rawdev_xstats_mode mode, uint8_t queue_port_id,
+		struct rte_rawdev_xstats_name *xstats_names,
+		unsigned int *ids, unsigned int size)
+{
+	RTE_RAWDEV_VALID_DEVID_OR_ERR_RET(dev_id, -ENODEV);
+	const int cnt_expected_entries = xstats_get_count(dev_id, mode,
+							  queue_port_id);
+	if (xstats_names == NULL || cnt_expected_entries < 0 ||
+			(int)size < cnt_expected_entries)
+		return cnt_expected_entries;
+
+	/* dev_id checked above */
+	const struct rte_rawdev *dev = &rte_rawdevs[dev_id];
+
+	if (dev->dev_ops->xstats_get_names != NULL)
+		return (*dev->dev_ops->xstats_get_names)(dev, mode,
+				queue_port_id, xstats_names, ids, size);
+
+	return -ENOTSUP;
+}
+
+/* retrieve rawdev extended statistics */
+int
+rte_rawdev_xstats_get(uint16_t dev_id, enum rte_rawdev_xstats_mode mode,
+		uint8_t queue_port_id, const unsigned int ids[],
+		uint64_t values[], unsigned int n)
+{
+	RTE_RAWDEV_VALID_DEVID_OR_ERR_RET(dev_id, -ENODEV);
+	const struct rte_rawdev *dev = &rte_rawdevs[dev_id];
+
+	/* implemented by the driver */
+	if (dev->dev_ops->xstats_get != NULL)
+		return (*dev->dev_ops->xstats_get)(dev, mode, queue_port_id,
+				ids, values, n);
+	return -ENOTSUP;
+}
+
+uint64_t
+rte_rawdev_xstats_by_name_get(uint16_t dev_id, const char *name,
+		unsigned int *id)
+{
+	RTE_RAWDEV_VALID_DEVID_OR_ERR_RET(dev_id, 0);
+	const struct rte_rawdev *dev = &rte_rawdevs[dev_id];
+	unsigned int temp = -1;
+
+	if (id != NULL)
+		*id = (unsigned int)-1;
+	else
+		id = &temp; /* ensure driver never gets a NULL value */
+
+	/* implemented by driver */
+	if (dev->dev_ops->xstats_get_by_name != NULL)
+		return (*dev->dev_ops->xstats_get_by_name)(dev, name, id);
+	return -ENOTSUP;
+}
+
+int
+rte_rawdev_xstats_reset(uint16_t dev_id,
+		enum rte_rawdev_xstats_mode mode, int16_t queue_port_id,
+		const uint32_t ids[], uint32_t nb_ids)
+{
+	RTE_RAWDEV_VALID_DEVID_OR_ERR_RET(dev_id, -EINVAL);
+	struct rte_rawdev *dev = &rte_rawdevs[dev_id];
+
+	if (dev->dev_ops->xstats_reset != NULL)
+		return (*dev->dev_ops->xstats_reset)(dev, mode, queue_port_id,
+							ids, nb_ids);
+	return -ENOTSUP;
+}
+
+int
+rte_rawdev_firmware_status_get(uint16_t dev_id, void *status_info)
+{
+	RTE_RAWDEV_VALID_DEVID_OR_ERR_RET(dev_id, -EINVAL);
+	struct rte_rawdev *dev = &rte_rawdevs[dev_id];
+
+	if (dev->dev_ops->firmware_status_get != NULL)
+		return (*dev->dev_ops->firmware_status_get)(dev, status_info);
+
+	return -ENOTSUP;
+}
+
+int
+rte_rawdev_firmware_version_get(uint16_t dev_id, void *version_info)
+{
+	RTE_RAWDEV_VALID_DEVID_OR_ERR_RET(dev_id, -EINVAL);
+	struct rte_rawdev *dev = &rte_rawdevs[dev_id];
+
+	if (dev->dev_ops->firmware_version_get != NULL)
+		return (*dev->dev_ops->firmware_status_get)(dev, version_info);
+
+	return -ENOTSUP;
+}
+
+int
+rte_rawdev_firmware_load(uint16_t dev_id, void *firmware_image)
+{
+	RTE_RAWDEV_VALID_DEVID_OR_ERR_RET(dev_id, -EINVAL);
+	struct rte_rawdev *dev = &rte_rawdevs[dev_id];
+
+	if (!firmware_image)
+		return -EINVAL;
+
+	if (dev->dev_ops->firmware_load != NULL)
+		return (*dev->dev_ops->firmware_load)(dev, firmware_image);
+
+	return -ENOTSUP;
+}
+
+int
+rte_rawdev_firmware_unload(uint16_t dev_id)
+{
+	RTE_RAWDEV_VALID_DEVID_OR_ERR_RET(dev_id, -EINVAL);
+	struct rte_rawdev *dev = &rte_rawdevs[dev_id];
+
+	if (dev->dev_ops->firmware_unload != NULL)
+		return (*dev->dev_ops->firmware_unload)(dev);
+
+	return -ENOTSUP;
+}
+
+int
+rte_rawdev_start(uint16_t dev_id)
+{
+	struct rte_rawdev *dev;
+	int diag;
+
+	RTE_RDEV_LOG_DEBUG("Start dev_id=%" PRIu8, dev_id);
+
+	RTE_RAWDEV_VALID_DEVID_OR_ERR_RET(dev_id, -EINVAL);
+	dev = &rte_rawdevs[dev_id];
+	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dev_start, -ENOTSUP);
+
+	if (dev->data->dev_started != 0) {
+		RTE_RDEV_LOG_ERR("Device with dev_id=%" PRIu8 "already started",
+			dev_id);
+		return 0;
+	}
+
+	diag = (*dev->dev_ops->dev_start)(dev);
+	if (diag == 0)
+		dev->data->dev_started = 1;
+	else
+		return diag;
+
+	return 0;
+}
+
+void
+rte_rawdev_stop(uint16_t dev_id)
+{
+	struct rte_rawdev *dev;
+
+	RTE_RDEV_LOG_DEBUG("Stop dev_id=%" PRIu8, dev_id);
+
+	RTE_RAWDEV_VALID_DEVID_OR_RET(dev_id);
+	dev = &rte_rawdevs[dev_id];
+	RTE_FUNC_PTR_OR_RET(*dev->dev_ops->dev_stop);
+
+	if (dev->data->dev_started == 0) {
+		RTE_RDEV_LOG_ERR("Device with dev_id=%" PRIu8 "already stopped",
+			dev_id);
+		return;
+	}
+
+	dev->data->dev_started = 0;
+	(*dev->dev_ops->dev_stop)(dev);
+}
+
+int
+rte_rawdev_close(uint16_t dev_id)
+{
+	struct rte_rawdev *dev;
+
+	RTE_RAWDEV_VALID_DEVID_OR_ERR_RET(dev_id, -EINVAL);
+	dev = &rte_rawdevs[dev_id];
+	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dev_close, -ENOTSUP);
+
+	/* Device must be stopped before it can be closed */
+	if (dev->data->dev_started == 1) {
+		RTE_RDEV_LOG_ERR("Device %u must be stopped before closing",
+				dev_id);
+		return -EBUSY;
+	}
+
+	return (*dev->dev_ops->dev_close)(dev);
+}
+
+int
+rte_rawdev_reset(uint16_t dev_id)
+{
+	struct rte_rawdev *dev;
+
+	RTE_RAWDEV_VALID_DEVID_OR_ERR_RET(dev_id, -EINVAL);
+	dev = &rte_rawdevs[dev_id];
+	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dev_reset, -ENOTSUP);
+
+	/* Device must be stopped before it can be reset */
+	/* XXX: Is forced reset also a possibility? */
+	if (dev->data->dev_started == 1) {
+		RTE_RDEV_LOG_ERR("Device %u must be stopped before resetting",
+				dev_id);
+		return -EBUSY;
+	}
+
+	return (*dev->dev_ops->dev_reset)(dev);
+}
+
+static inline int
+rte_rawdev_data_alloc(uint16_t dev_id, struct rte_rawdev_data **data,
+		int socket_id)
+{
+	char mz_name[RTE_RAWDEV_NAME_MAX_LEN];
+	const struct rte_memzone *mz;
+	int n;
+
+	/* Generate memzone name */
+	n = snprintf(mz_name, sizeof(mz_name), "rte_rawdev_data_%u", dev_id);
+	if (n >= (int)sizeof(mz_name))
+		return -EINVAL;
+
+	if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
+		mz = rte_memzone_reserve(mz_name,
+				sizeof(struct rte_rawdev_data),
+				socket_id, 0);
+	} else
+		mz = rte_memzone_lookup(mz_name);
+
+	if (mz == NULL)
+		return -ENOMEM;
+
+	*data = mz->addr;
+	if (rte_eal_process_type() == RTE_PROC_PRIMARY)
+		memset(*data, 0, sizeof(struct rte_rawdev_data));
+
+	return 0;
+}
+
+static inline uint8_t
+rte_rawdev_find_free_device_index(void)
+{
+	uint16_t dev_id;
+
+	for (dev_id = 0; dev_id < RTE_RAW_MAX_DEVS; dev_id++) {
+		if (rte_rawdevs[dev_id].attached ==
+				RTE_RAWDEV_DETACHED)
+			return dev_id;
+	}
+	return RTE_RAW_MAX_DEVS;
+}
+
+struct rte_rawdev *
+rte_rawdev_pmd_allocate(const char *name, int socket_id)
+{
+	struct rte_rawdev *rawdev;
+	uint16_t dev_id;
+
+	if (rte_rawdev_pmd_get_named_dev(name) != NULL) {
+		RTE_RDEV_LOG_ERR("Event device with name %s already "
+				"allocated!", name);
+		return NULL;
+	}
+
+	dev_id = rte_rawdev_find_free_device_index();
+	if (dev_id == RTE_RAW_MAX_DEVS) {
+		RTE_RDEV_LOG_ERR("Reached maximum number of raw devices");
+		return NULL;
+	}
+
+	rawdev = &rte_rawdevs[dev_id];
+
+	if (rawdev->data == NULL) {
+		struct rte_rawdev_data *rawdev_data = NULL;
+
+		int retval = rte_rawdev_data_alloc(dev_id, &rawdev_data,
+				socket_id);
+
+		if (retval < 0 || rawdev_data == NULL)
+			return NULL;
+
+		rawdev->data = rawdev_data;
+
+		snprintf(rawdev->data->name, RTE_RAWDEV_NAME_MAX_LEN,
+				"%s", name);
+
+		rawdev->data->dev_id = dev_id;
+		rawdev->data->socket_id = socket_id;
+		rawdev->data->dev_started = 0;
+
+		rawdev->attached = RTE_RAWDEV_ATTACHED;
+
+		rawdev_globals.nb_devs++;
+	}
+
+	return rawdev;
+}
+
+int
+rte_rawdev_pmd_release(struct rte_rawdev *rawdev)
+{
+	int ret;
+	char mz_name[RTE_RAWDEV_NAME_MAX_LEN];
+	const struct rte_memzone *mz;
+
+	if (rawdev == NULL)
+		return -EINVAL;
+
+	ret = rte_rawdev_close(rawdev->data->dev_id);
+	if (ret < 0)
+		return ret;
+
+	rawdev->attached = RTE_RAWDEV_DETACHED;
+	rawdev_globals.nb_devs--;
+
+	if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
+		rte_free(rawdev->data->dev_private);
+
+		/* Generate memzone name */
+		ret = snprintf(mz_name, sizeof(mz_name), "rte_rawdev_data_%u",
+				rawdev->data->dev_id);
+		if (ret >= (int)sizeof(mz_name))
+			return -EINVAL;
+
+		mz = rte_memzone_lookup(mz_name);
+		if (mz == NULL)
+			return -ENOMEM;
+
+		ret = rte_memzone_free(mz);
+		if (ret)
+			return ret;
+	}
+
+	rawdev->data = NULL;
+	return 0;
+}
+
+struct rte_rawdev *
+rte_rawdev_pmd_vdev_init(const char *name, size_t dev_private_size,
+		int socket_id)
+{
+	struct rte_rawdev *rawdev;
+
+	/* Allocate device structure */
+	rawdev = rte_rawdev_pmd_allocate(name, socket_id);
+	if (rawdev == NULL)
+		return NULL;
+
+	/* Allocate private device structure */
+	if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
+		rawdev->data->dev_private =
+				rte_zmalloc_socket("rawdev device private",
+						dev_private_size,
+						RTE_CACHE_LINE_SIZE,
+						socket_id);
+
+		if (rawdev->data->dev_private == NULL)
+			rte_panic("Cannot allocate memzone for private device"
+					" data");
+	}
+
+	return rawdev;
+}
+
+int
+rte_rawdev_pmd_vdev_uninit(const char *name)
+{
+	struct rte_rawdev *rawdev;
+
+	if (name == NULL)
+		return -EINVAL;
+
+	rawdev = rte_rawdev_pmd_get_named_dev(name);
+	if (rawdev == NULL)
+		return -ENODEV;
+
+	/* Free the raw device */
+	rte_rawdev_pmd_release(rawdev);
+
+	return 0;
+}
diff --git a/lib/librte_rawdev/rte_rawdev.h b/lib/librte_rawdev/rte_rawdev.h
new file mode 100644
index 0000000..aec437e
--- /dev/null
+++ b/lib/librte_rawdev/rte_rawdev.h
@@ -0,0 +1,524 @@
+/*
+ *   BSD LICENSE
+ *
+ *   Copyright 2017 NXP
+ *
+ *   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 NXPnor 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_RAWDEV_H_
+#define _RTE_RAWDEV_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rte_common.h>
+#include <rte_memory.h>
+#include <rte_errno.h>
+
+/** TODO: Revisit this - no specific reason for this limitation */
+#define RTE_RAWDEV_MAX_DEVS	2
+
+/**
+ * Get the total number of raw devices that have been successfully
+ * initialised.
+ *
+ * @return
+ *   The total number of usable raw devices.
+ */
+uint8_t
+rte_rawdev_count(void);
+
+/**
+ * Get the device identifier for the named raw device.
+ *
+ * @param name
+ *   Raw device name to select the raw device identifier.
+ *
+ * @return
+ *   Returns raw device identifier on success.
+ *   - <0: Failure to find named raw device.
+ */
+int
+rte_rawdev_get_dev_id(const char *name);
+
+/**
+ * Return the NUMA socket to which a device is connected.
+ *
+ * @param dev_id
+ *   The identifier of the device.
+ * @return
+ *   The NUMA socket id to which the device is connected or
+ *   a default of zero if the socket could not be determined.
+ *   -(-EINVAL)  dev_id value is out of range.
+ */
+int
+rte_rawdev_socket_id(uint16_t dev_id);
+
+/**
+ * Raw device information
+ */
+struct rte_rawdev_info {
+	const char *driver_name; /**< Raw driver name */
+	struct rte_device *dev;  /**< Generic device encapsulation */
+	void *info;              /**< Opaque information */
+	int is_attached;         /**< Device state */
+};
+
+/**
+ * Retrieve the contextual information of an raw device.
+ *
+ * @param dev_id
+ *   The identifier of the device.
+ *
+ * @param[out] dev_info
+ *   A pointer to a structure of type *rte_rawdev_info* to be filled with the
+ *   contextual information of the device.
+ *
+ * @return
+ *   - 0: Success, driver updates the contextual information of the raw device
+ *   - <0: Error code returned by the driver info get function.
+ *
+ */
+int
+rte_rawdev_info_get(uint16_t dev_id, struct rte_rawdev_info *dev_info);
+
+/**
+ * Configure an raw device.
+ *
+ * This function must be invoked first before any other function in the
+ * API. This function can also be re-invoked when a device is in the
+ * stopped state.
+ *
+ * The caller may use rte_rawdev_info_get() to get the capability of each
+ * resources available for this raw device.
+ *
+ * @param dev_id
+ *   The identifier of the device to configure.
+ * @param dev_conf
+ *   The raw device configuration structure as void - to be interpreted by
+ *   by the given driver.
+ *
+ * @return
+ *   - 0: Success, device configured.
+ *   - <0: Error code returned by the driver configuration function.
+ */
+int
+rte_rawdev_configure(uint16_t dev_id, void *dev_conf);
+
+
+/**
+ * Retrieve the current configuration information of an raw queue designated
+ * by its *queue_id* from the raw driver for an raw device.
+ *
+ * This function intended to be used in conjunction with rte_raw_queue_setup()
+ * where caller needs to set up the queue by overriding few default values.
+ *
+ * @param dev_id
+ *   The identifier of the device.
+ * @param queue_id
+ *   The index of the raw queue to get the configuration information.
+ *   The value must be in the range [0, nb_raw_queues - 1]
+ *   previously supplied to rte_rawdev_configure().
+ * @param[out] queue_conf
+ *   The pointer to the default raw queue configuration data.
+ * @return
+ *   - 0: Success, driver updates the default raw queue configuration data.
+ *   - <0: Error code returned by the driver info get function.
+ *
+ * @see rte_raw_queue_setup()
+ *
+ */
+int
+rte_rawdev_queue_conf_get(uint16_t dev_id, uint8_t queue_id, void *queue_conf);
+
+/**
+ * Allocate and set up an raw queue for an raw device.
+ *
+ * @param dev_id
+ *   The identifier of the device.
+ * @param queue_id
+ *   The index of the raw queue to setup. The value must be in the range
+ *   [0, nb_raw_queues - 1] previously supplied to rte_rawdev_configure().
+ * @param queue_conf
+ *   The pointer to the configuration data to be used for the raw queue.
+ *   NULL value is allowed, in which case default configuration	used.
+ *
+ * @see rte_rawdev_queue_default_conf_get()
+ *
+ * @return
+ *   - 0: Success, raw queue correctly set up.
+ *   - <0: raw queue configuration failed
+ */
+int
+rte_rawdev_queue_setup(uint16_t dev_id, uint8_t queue_id, void *queue_conf);
+
+/**
+ * Get the number of raw queues on a specific raw device
+ *
+ * @param dev_id
+ *   Raw device identifier.
+ * @return
+ *   - The number of configured raw queues
+ */
+uint8_t
+rte_rawdev_queue_count(uint16_t dev_id);
+
+/**
+ * Start an raw device.
+ *
+ * The device start step is the last one and consists of setting the raw
+ * queues to start accepting the raws and schedules to raw ports.
+ *
+ * On success, all basic functions exported by the API (raw enqueue,
+ * raw dequeue and so on) can be invoked.
+ *
+ * @param dev_id
+ *   Raw device identifier
+ * @return
+ *   - 0: Success, device started.
+ *   < 0: Failure
+ */
+int
+rte_rawdev_start(uint16_t dev_id);
+
+/**
+ * Stop an raw device. The device can be restarted with a call to
+ * rte_rawdev_start()
+ *
+ * @param dev_id
+ *   Raw device identifier.
+ */
+void
+rte_rawdev_stop(uint16_t dev_id);
+
+/**
+ * Close an raw device. The device cannot be restarted after this call.
+ *
+ * @param dev_id
+ *   Raw device identifier
+ *
+ * @return
+ *  - 0 on successfully closing device
+ *  - <0 on failure to close device
+ *  - (-EAGAIN) if device is busy
+ */
+int
+rte_rawdev_close(uint16_t dev_id);
+
+/**
+ * Reset a raw device.
+ * This is different from cycle of rte_rawdev_start->rte_rawdev_stop in the
+ * sense similar to hard or soft reset.
+ *
+ * @param dev_id
+ *   Raw device identifiers
+ * @return
+ *   0 for sucessful reset,
+ *  !0 for failure in resetting
+ */
+int
+rte_rawdev_reset(uint16_t dev_id);
+
+#define RTE_RAWDEV_NAME_MAX_LEN	(64)
+/**< @internal Max length of name of raw PMD */
+
+/**
+ * @internal
+ * The data part, with no function pointers, associated with each device.
+ *
+ * This structure is safe to place in shared memory to be common among
+ * different processes in a multi-process configuration.
+ */
+struct rte_rawdev_data {
+	int socket_id;
+	/**< Socket ID where memory is allocated */
+	uint16_t dev_id;
+	/**< Device ID for this instance */
+	uint8_t nb_queues;
+	/**< Number of raw queues. */
+	void *dev_private;
+	/**< PMD-specific private data */
+
+	RTE_STD_C11
+	uint8_t dev_started : 1;
+	/**< Device state: STARTED(1)/STOPPED(0) */
+
+	char name[RTE_RAWDEV_NAME_MAX_LEN];
+	/**< Unique identifier name */
+} __rte_cache_aligned;
+
+/** @internal The data structure associated with each raw device. */
+struct rte_rawdev {
+	struct rte_rawdev_data *data;
+	/**< Generic device information */
+
+	const struct rte_rawdev_ops *dev_ops;
+	/**< Functions exported by PMD */
+
+	struct rte_device *dev;
+	/**< Device info. supplied by probing */
+
+	struct rte_driver *driver;
+	/**< Device info. supplied by probing */
+
+	RTE_STD_C11
+	uint8_t attached : 1;
+	/**< Flag indicating the device is attached */
+} __rte_cache_aligned;
+
+extern struct rte_rawdev *rte_rawdevs;
+/** @internal The pool of rte_rawdev structures. */
+
+
+/**
+ * Dump internal information about *dev_id* to the FILE* provided in *f*.
+ *
+ * @param dev_id
+ *   The identifier of the device.
+ *
+ * @param f
+ *   A pointer to a file for output
+ *
+ * @return
+ *   - 0: on success
+ *   - <0: on failure.
+ */
+int
+rte_rawdev_dump(uint16_t dev_id, FILE *f);
+
+/** Maximum name length for extended statistics counters */
+#define RTE_RAW_DEV_XSTATS_NAME_SIZE 64
+
+/**
+ * Selects the component of the rawdev to retrieve statistics from.
+ */
+enum rte_rawdev_xstats_mode {
+	RTE_RAW_DEV_XSTATS_DEVICE,
+	RTE_RAW_DEV_XSTATS_PORT,
+	RTE_RAW_DEV_XSTATS_QUEUE,
+};
+
+/**
+ * A name-key lookup element for extended statistics.
+ *
+ * This structure is used to map between names and ID numbers
+ * for extended ethdev statistics.
+ */
+struct rte_rawdev_xstats_name {
+	char name[RTE_RAW_DEV_XSTATS_NAME_SIZE];
+};
+
+/**
+ * Retrieve names of extended statistics of an raw device.
+ *
+ * @param dev_id
+ *   The identifier of the raw device.
+ * @param mode
+ *   The mode of statistics to retrieve. Choices include the device statistics,
+ *   port statistics or queue statistics.
+ * @param queue_port_id
+ *   Used to specify the port or queue number in queue or port mode, and is
+ *   ignored in device mode.
+ * @param[out] xstats_names
+ *   Block of memory to insert names into. Must be at least size in capacity.
+ *   If set to NULL, function returns required capacity.
+ * @param[out] ids
+ *   Block of memory to insert ids into. Must be at least size in capacity.
+ *   If set to NULL, function returns required capacity. The id values returned
+ *   can be passed to *rte_rawdev_xstats_get* to select statistics.
+ * @param size
+ *   Capacity of xstats_names (number of names).
+ * @return
+ *   - positive value lower or equal to size: success. The return value
+ *     is the number of entries filled in the stats table.
+ *   - positive value higher than size: error, the given statistics table
+ *     is too small. The return value corresponds to the size that should
+ *     be given to succeed. The entries in the table are not valid and
+ *     shall not be used by the caller.
+ *   - negative value on error:
+ *        -ENODEV for invalid *dev_id*
+ *        -EINVAL for invalid mode, queue port or id parameters
+ *        -ENOTSUP if the device doesn't support this function.
+ */
+int
+rte_rawdev_xstats_names_get(uint16_t dev_id,
+			    enum rte_rawdev_xstats_mode mode,
+			    uint8_t queue_port_id,
+			    struct rte_rawdev_xstats_name *xstats_names,
+			    unsigned int *ids,
+			    unsigned int size);
+
+/**
+ * Retrieve extended statistics of an raw device.
+ *
+ * @param dev_id
+ *   The identifier of the device.
+ * @param mode
+ *  The mode of statistics to retrieve. Choices include the device statistics,
+ *  port statistics or queue statistics.
+ * @param queue_port_id
+ *   Used to specify the port or queue number in queue or port mode, and is
+ *   ignored in device mode.
+ * @param ids
+ *   The id numbers of the stats to get. The ids can be got from the stat
+ *   position in the stat list from rte_rawdev_get_xstats_names(), or
+ *   by using rte_rawdev_get_xstats_by_name()
+ * @param[out] values
+ *   The values for each stats request by ID.
+ * @param n
+ *   The number of stats requested
+ * @return
+ *   - positive value: number of stat entries filled into the values array
+ *   - negative value on error:
+ *        -ENODEV for invalid *dev_id*
+ *        -EINVAL for invalid mode, queue port or id parameters
+ *        -ENOTSUP if the device doesn't support this function.
+ */
+int
+rte_rawdev_xstats_get(uint16_t dev_id,
+		      enum rte_rawdev_xstats_mode mode,
+		      uint8_t queue_port_id,
+		      const unsigned int ids[],
+		      uint64_t values[],
+		      unsigned int n);
+
+/**
+ * Retrieve the value of a single stat by requesting it by name.
+ *
+ * @param dev_id
+ *   The identifier of the device
+ * @param name
+ *   The stat name to retrieve
+ * @param[out] id
+ *   If non-NULL, the numerical id of the stat will be returned, so that further
+ *   requests for the stat can be got using rte_rawdev_xstats_get, which will
+ *   be faster as it doesn't need to scan a list of names for the stat.
+ *   If the stat cannot be found, the id returned will be (unsigned)-1.
+ * @return
+ *   - positive value or zero: the stat value
+ *   - negative value: -EINVAL if stat not found, -ENOTSUP if not supported.
+ */
+uint64_t
+rte_rawdev_xstats_by_name_get(uint16_t dev_id, const char *name,
+			      unsigned int *id);
+
+/**
+ * Reset the values of the xstats of the selected component in the device.
+ *
+ * @param dev_id
+ *   The identifier of the device
+ * @param mode
+ *   The mode of the statistics to reset. Choose from device, queue or port.
+ * @param queue_port_id
+ *   The queue or port to reset. 0 and positive values select ports and queues,
+ *   while -1 indicates all ports or queues.
+ * @param ids
+ *   Selects specific statistics to be reset. When NULL, all statistics selected
+ *   by *mode* will be reset. If non-NULL, must point to array of at least
+ *   *nb_ids* size.
+ * @param nb_ids
+ *   The number of ids available from the *ids* array. Ignored when ids is NULL.
+ * @return
+ *   - zero: successfully reset the statistics to zero
+ *   - negative value: -EINVAL invalid parameters, -ENOTSUP if not supported.
+ */
+int
+rte_rawdev_xstats_reset(uint16_t dev_id,
+			enum rte_rawdev_xstats_mode mode,
+			int16_t queue_port_id,
+			const uint32_t ids[],
+			uint32_t nb_ids);
+
+/**
+ * Get Firmware status of the device..
+ * Returns a memory allocated by driver/implementation containing status
+ * information block. It is responsibility of caller to release the buffer.
+ *
+ * @param dev_id
+ *   Raw device identifier
+ * @param status_info
+ *   Pointer to status information area. Caller is responsible for releasing
+ *   the memory associated.
+ * @return
+ *   0 for success,
+ *  !0 for failure, `status_info` argument state is undefined
+ */
+int
+rte_rawdev_firmware_status_get(uint16_t dev_id, void *status_info);
+
+/**
+ * Get Firmware version of the device.
+ * Returns a memory allocated by driver/implementation containing version
+ * information block. It is responsibility of caller to release the buffer.
+ *
+ * @param dev_id
+ *   Raw device identifier
+ * @param version_info
+ *   Pointer to version information area. Caller is responsible for releasing
+ *   the memory associated.
+ * @return
+ *   0 for success,
+ *  !0 for failure, `version_info` argument state is undefined
+ */
+int
+rte_rawdev_firmware_version_get(uint16_t dev_id, void *version_info);
+
+/**
+ * Load firmware on the device.
+ * TODO: In future, methods like directly flashing from file too can be
+ * supported.
+ *
+ * @param dev_id
+ *   Raw device identifier
+ * @param firmware_image
+ *   Pointer to buffer containing image binary data
+ * @return
+ *   0 for successful Load
+ *  !0 for failure to load the provided image, or image incorrect.
+ */
+int
+rte_rawdev_firmware_load(uint16_t dev_id, void *firmware_image);
+
+/**
+ * Unload firmware from the device.
+ *
+ * @param dev_id
+ *   Raw device identifiers
+ * @return
+ *   0 for successful Unload
+ *  !0 for failure in unloading
+ */
+int
+rte_rawdev_firmware_unload(uint16_t dev_id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_RAWDEV_H_ */
diff --git a/lib/librte_rawdev/rte_rawdev_pmd.h b/lib/librte_rawdev/rte_rawdev_pmd.h
new file mode 100644
index 0000000..3963523
--- /dev/null
+++ b/lib/librte_rawdev/rte_rawdev_pmd.h
@@ -0,0 +1,540 @@
+/*
+ *
+ *   Copyright 2017 NXP
+ *
+ *   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 NXPnor 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_RAWDEV_PMD_H_
+#define _RTE_RAWDEV_PMD_H_
+
+/** @file
+ * RTE RAW PMD APIs
+ *
+ * @note
+ * Driver facing APIs for a raw device. These are not to be called directly by
+ * any application.
+ * @b EXPERIMENTAL: this API may change without prior notice
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <string.h>
+
+#include <rte_dev.h>
+#include <rte_malloc.h>
+#include <rte_log.h>
+#include <rte_common.h>
+
+#include "rte_rawdev.h"
+
+/* Logging Macros */
+#define RTE_RDEV_LOG_ERR(...) \
+	RTE_LOG(ERR, USER8, \
+		RTE_FMT("%s() line %u: " RTE_FMT_HEAD(__VA_ARGS__,) "\n", \
+			__func__, __LINE__, RTE_FMT_TAIL(__VA_ARGS__,)))
+
+#ifdef RTE_LIBRTE_RAWDEV_DEBUG
+#define RTE_RDEV_LOG_DEBUG(...) \
+	RTE_LOG(DEBUG, USER8, \
+		RTE_FMT("%s() line %u: " RTE_FMT_HEAD(__VA_ARGS__,) "\n", \
+			__func__, __LINE__, RTE_FMT_TAIL(__VA_ARGS__,)))
+#else
+#define RTE_RDEV_LOG_DEBUG(...) (void)0
+#endif
+
+/* Macros to check for valid device */
+#define RTE_RAWDEV_VALID_DEVID_OR_ERR_RET(dev_id, retval) do { \
+	if (!rte_rawdev_pmd_is_valid_dev((dev_id))) { \
+		RTE_RDEV_LOG_ERR("Invalid dev_id=%d\n", dev_id); \
+		return retval; \
+	} \
+} while (0)
+
+#define RTE_RAWDEV_VALID_DEVID_OR_RET(dev_id) do { \
+	if (!rte_rawdev_pmd_is_valid_dev((dev_id))) { \
+		RTE_RDEV_LOG_ERR("Invalid dev_id=%d\n", dev_id); \
+		return; \
+	} \
+} while (0)
+
+#define RTE_RAWDEV_DETACHED  (0)
+#define RTE_RAWDEV_ATTACHED  (1)
+
+/** Global structure used for maintaining state of allocated raw devices */
+struct rte_rawdev_global {
+	uint8_t nb_devs;	/**< Number of devices found */
+};
+
+extern struct rte_rawdev_global *rte_rawdev_globals;
+/** Pointer to global raw devices data structure. */
+extern struct rte_rawdev *rte_rawdevs;
+/** The pool of rte_rawdev structures. */
+
+/**
+ * Get the rte_rawdev structure device pointer for the named device.
+ *
+ * @param name
+ *   device name to select the device structure.
+ *
+ * @return
+ *   - The rte_rawdev structure pointer for the given device ID.
+ */
+static inline struct rte_rawdev *
+rte_rawdev_pmd_get_named_dev(const char *name)
+{
+	struct rte_rawdev *dev;
+	unsigned int i;
+
+	if (name == NULL)
+		return NULL;
+
+	for (i = 0; i < RTE_RAWDEV_MAX_DEVS; i++) {
+		dev = &rte_rawdevs[i];
+		if ((dev->attached == RTE_RAWDEV_ATTACHED) &&
+		   (strcmp(dev->data->name, name) == 0))
+			return dev;
+	}
+
+	return NULL;
+}
+
+/**
+ * Validate if the raw device index is a valid attached raw device.
+ *
+ * @param dev_id
+ *   raw device index.
+ *
+ * @return
+ *   - If the device index is valid (1) or not (0).
+ */
+static inline unsigned
+rte_rawdev_pmd_is_valid_dev(uint8_t dev_id)
+{
+	struct rte_rawdev *dev;
+
+	if (dev_id >= RTE_RAWDEV_MAX_DEVS)
+		return 0;
+
+	dev = &rte_rawdevs[dev_id];
+	if (dev->attached != RTE_RAWDEV_ATTACHED)
+		return 0;
+	else
+		return 1;
+}
+
+/**
+ * Definitions of all functions exported by a driver through the
+ * the generic structure of type *rawdev_ops* supplied in the
+ * *rte_rawdev* structure associated with a device.
+ */
+
+/**
+ * Get device information of a device.
+ *
+ * @param dev
+ *   Raw device pointer
+ * @param dev_info
+ *   Raw device information structure
+ *
+ * @return
+ *   Returns 0 on success
+ */
+typedef void (*rawdev_info_get_t)(struct rte_rawdev *dev, void *dev_info);
+
+/**
+ * Configure a device.
+ *
+ * @param dev
+ *   Raw device pointer
+ *
+ * @return
+ *   Returns 0 on success
+ */
+typedef int (*rawdev_configure_t)(const struct rte_rawdev *dev);
+
+/**
+ * Start a configured device.
+ *
+ * @param dev
+ *   Raw device pointer
+ *
+ * @return
+ *   Returns 0 on success
+ */
+typedef int (*rawdev_start_t)(struct rte_rawdev *dev);
+
+/**
+ * Stop a configured device.
+ *
+ * @param dev
+ *   Raw device pointer
+ */
+typedef void (*rawdev_stop_t)(struct rte_rawdev *dev);
+
+/**
+ * Close a configured device.
+ *
+ * @param dev
+ *   Raw device pointer
+ *
+ * @return
+ * - 0 on success
+ * - (-EAGAIN) if can't close as device is busy
+ */
+typedef int (*rawdev_close_t)(struct rte_rawdev *dev);
+
+/**
+ * Reset a configured device.
+ *
+ * @param dev
+ *   Raw device pointer
+ * @return
+ *   0 for success
+ *   !0 for failure
+ */
+typedef int (*rawdev_reset_t)(struct rte_rawdev *dev);
+
+/**
+ * Retrieve the current raw queue configuration.
+ *
+ * @param dev
+ *   Raw device pointer
+ * @param queue_id
+ *   Raw device queue index
+ * @param[out] queue_conf
+ *   Raw device queue configuration structure
+ *
+ */
+typedef void (*rawdev_queue_conf_get_t)(struct rte_rawdev *dev,
+					uint8_t queue_id,
+					void *queue_conf);
+
+/**
+ * Setup an raw queue.
+ *
+ * @param dev
+ *   Rawdevice pointer
+ * @param queue_id
+ *   Rawqueue index
+ * @param queue_conf
+ *   Rawqueue configuration structure
+ *
+ * @return
+ *   Returns 0 on success.
+ */
+typedef int (*rawdev_queue_setup_t)(struct rte_rawdev *dev,
+				    uint8_t queue_id,
+				    void *queue_conf);
+
+/**
+ * Release resources allocated by given raw queue.
+ *
+ * @param dev
+ *   Raw device pointer
+ * @param queue_id
+ *   Raw queue index
+ *
+ */
+typedef void (*rawdev_queue_release_t)(struct rte_rawdev *dev,
+				       uint8_t queue_id);
+
+/**
+ * Enqueue an array of raw buffers to the device.
+ *
+ * Buffer being used is opaque - it can be obtained from mempool or from
+ * any other source. Interpretation of buffer is responsibility of driver.
+ *
+ * @param dev
+ *   Raw deviec pointer
+ * @param bufs
+ *   array of void buffers
+ * @param count
+ *   number of buffers passed
+ */
+typedef int (*rawdev_enqueue_bufs_t)(struct rte_rawdev *dev,
+				     void **bufs,
+				     unsigned int count);
+
+/**
+ * Dequeue an array of raw buffers from the device.
+ *
+ * @param dev
+ *   Raw deviec pointer
+ * @param bufs
+ *   array of void buffers
+ * @return
+ *   >0, ~0: Count of buffers returned
+ *   <0: Error
+ *   XXX: Should error be returned or unsigned? (0 as combined success/failure)
+ */
+typedef int (*rawdev_dequeue_bufs_t)(struct rte_rawdev *dev, void **bufs);
+
+/**
+ * Dump internal information
+ *
+ * @param dev
+ *   Raw device pointer
+ * @param f
+ *   A pointer to a file for output
+ *
+ */
+typedef void (*rawdev_dump_t)(struct rte_rawdev *dev, FILE *f);
+
+/**
+ * Retrieve a set of statistics from device.
+ * Note: Being a raw device, the stats are specific to the device being
+ * implemented thus represented as xstats.
+ *
+ * @param dev
+ *   Raw device pointer
+ * @param ids
+ *   The stat ids to retrieve
+ * @param values
+ *   The returned stat values
+ * @param n
+ *   The number of id values and entries in the values array
+ * @return
+ *   The number of stat values successfully filled into the values array
+ */
+typedef int (*rawdev_xstats_get_t)(const struct rte_rawdev *dev,
+		enum rte_rawdev_xstats_mode mode, uint8_t queue_port_id,
+		const unsigned int ids[], uint64_t values[], unsigned int n);
+
+/**
+ * Resets the statistic values in xstats for the device, based on mode.
+ */
+typedef int (*rawdev_xstats_reset_t)(struct rte_rawdev *dev,
+		enum rte_rawdev_xstats_mode mode,
+		int16_t queue_port_id,
+		const uint32_t ids[],
+		uint32_t nb_ids);
+
+/**
+ * Get names of extended stats of an raw device
+ *
+ * @param dev
+ *   Raw device pointer
+ * @param xstats_names
+ *   Array of name values to be filled in
+ * @param size
+ *   Number of values in the xstats_names array
+ * @return
+ *   When size >= the number of stats, return the number of stat values filled
+ *   into the array.
+ *   When size < the number of available stats, return the number of stats
+ *   values, and do not fill in any data into xstats_names.
+ */
+typedef int (*rawdev_xstats_get_names_t)(const struct rte_rawdev *dev,
+		enum rte_rawdev_xstats_mode mode, uint8_t queue_port_id,
+		struct rte_rawdev_xstats_name *xstats_names,
+		unsigned int *ids, unsigned int size);
+
+/**
+ * Get value of one stats and optionally return its id
+ *
+ * @param dev
+ *   Raw device pointer
+ * @param name
+ *   The name of the stat to retrieve
+ * @param id
+ *   Pointer to an unsigned int where we store the stat-id for future reference.
+ *   This pointer may be null if the id is not required.
+ * @return
+ *   The value of the stat, or (uint64_t)-1 if the stat is not found.
+ *   If the stat is not found, the id value will be returned as (unsigned)-1,
+ *   if id pointer is non-NULL
+ */
+typedef uint64_t (*rawdev_xstats_get_by_name)(const struct rte_rawdev *dev,
+					      const char *name,
+					      unsigned int *id);
+
+/**
+ * Get firmware/device-stack status.
+ * Implementation to allocate buffer for returning information.
+ *
+ * @param dev
+ *   Raw device pointer
+ * @param status
+ *   void block containing device specific status information
+ * @return
+ *   0 for success,
+ *   !0 for failure, with undefined value in `status_info`
+ */
+typedef int (*rawdev_firmware_status_get_t)(struct rte_rawdev *dev,
+					    void *status_info);
+
+/**
+ * Get firmware version information
+ *
+ * @param dev
+ *   Raw device pointer
+ * @param version_info
+ *   void pointer to version information returned by device
+ * @return
+ *   0 for success,
+ *   !0 for failure, with undefined value in `version_info`
+ */
+typedef int (*rawdev_firmware_version_get_t)(struct rte_rawdev *dev,
+					     void *version_info);
+
+/**
+ * Load firwmare from a buffer (DMA'able)
+ *
+ * @param dev
+ *   Raw device pointer
+ * @param firmware_file
+ *   file pointer to firmware area
+ * @return
+ *   >0, ~0: for successful load
+ *   <0: for failure
+ *
+ * @see Application may use 'firmware_version_get` for ascertaining successful
+ * load
+ */
+typedef int (*rawdev_firmware_load_t)(struct rte_rawdev *dev,
+				      void *firmware_buf);
+
+/**
+ * Unload firwmare
+ *
+ * @param dev
+ *   Raw device pointer
+ * @return
+ *   >0, ~0 for successful unloading
+ *   <0 for failure in unloading
+ *
+ * Note: Application can use the `firmware_status_get` or
+ * `firmware_version_get` to get result of unload.
+ */
+typedef int (*rawdev_firmware_unload_t)(struct rte_rawdev *dev);
+
+
+/** Rawdevice operations function pointer table */
+struct rte_rawdev_ops {
+	rawdev_info_get_t dev_infos_get;	/**< Get device info. */
+	rawdev_configure_t dev_configure;	/**< Configure device. */
+	rawdev_start_t dev_start;		/**< Start device. */
+	rawdev_stop_t dev_stop;			/**< Stop device. */
+	rawdev_close_t dev_close;		/**< Close device. */
+	rawdev_reset_t dev_reset;               /**< Reset device. */
+
+	rawdev_queue_conf_get_t queue_def_conf;
+	/**< Get raw queue configuration. */
+	rawdev_queue_setup_t queue_setup;
+	/**< Set up an raw queue. */
+	rawdev_queue_release_t queue_release;
+	/**< Release an raw queue. */
+	rawdev_enqueue_bufs_t enqueue_bufs;
+	/**< Enqueue an array of raw buffers to device. */
+	rawdev_dequeue_bufs_t dequeue_bufs;
+	/**< Dequeue an array of raw buffers from device. */
+	/** TODO: Callback based enqueue and dequeue can also be supported  */
+
+	rawdev_dump_t dump;
+	/* Dump internal information */
+
+	rawdev_xstats_get_t xstats_get;
+	/**< Get extended device statistics. */
+	rawdev_xstats_get_names_t xstats_get_names;
+	/**< Get names of extended stats. */
+	rawdev_xstats_get_by_name xstats_get_by_name;
+	/**< Get one value by name. */
+	rawdev_xstats_reset_t xstats_reset;
+	/**< Reset the statistics values in xstats. */
+
+	rawdev_firmware_status_get_t firmware_status_get;
+	/**< Obtainer firmware status */
+	rawdev_firmware_version_get_t firmware_version_get;
+	/**< Obtain firmware version information */
+	rawdev_firmware_load_t firmware_load;
+	/**< Load firmware */
+	rawdev_firmware_unload_t firmware_unload;
+	/**< Unload firmware */
+};
+
+/**
+ * Allocates a new rawdev slot for an raw device and returns the pointer
+ * to that slot for the driver to use.
+ *
+ * @param name
+ *   Unique identifier name for each device
+ * @param socket_id
+ *   Socket to allocate resources on.
+ * @return
+ *   - Slot in the rte_dev_devices array for a new device;
+ */
+struct rte_rawdev *
+rte_rawdev_pmd_allocate(const char *name, int socket_id);
+
+/**
+ * Release the specified rawdev device.
+ *
+ * @param rawdev
+ * The *rawdev* pointer is the address of the *rte_rawdev* structure.
+ * @return
+ *   - 0 on success, negative on error
+ */
+int
+rte_rawdev_pmd_release(struct rte_rawdev *rawdev);
+
+/**
+ * Creates a new virtual raw device and returns the pointer to that device.
+ *
+ * @param name
+ *   PMD type name
+ * @param dev_private_size
+ *   Size of raw PMDs private data
+ * @param socket_id
+ *   Socket to allocate resources on.
+ *
+ * @return
+ *   - Raw device pointer if device is successfully created.
+ *   - NULL if device cannot be created.
+ */
+struct rte_rawdev *
+rte_rawdev_pmd_vdev_init(const char *name, size_t dev_private_size,
+		int socket_id);
+
+/**
+ * Destroy the given virtual raw device
+ *
+ * @param name
+ *   PMD type name
+ * @return
+ *   - 0 on success, negative on error
+ */
+int
+rte_rawdev_pmd_vdev_uninit(const char *name);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_RAWDEV_PMD_H_ */
diff --git a/lib/librte_rawdev/rte_rawdev_version.map b/lib/librte_rawdev/rte_rawdev_version.map
new file mode 100644
index 0000000..fd9b969
--- /dev/null
+++ b/lib/librte_rawdev/rte_rawdev_version.map
@@ -0,0 +1,28 @@
+EXPERIMENTAL {
+	global:
+
+	rte_rawdev_close;
+	rte_rawdev_configure;
+	rte_rawdev_count;
+	rte_rawdev_firmware_load;
+	rte_rawdev_firmware_status_get;
+	rte_rawdev_firmware_unload;
+	rte_rawdev_firmware_version_get;
+	rte_rawdev_get_dev_id;
+	rte_rawdev_info_get;
+	rte_rawdev_pmd_allocate;
+	rte_rawdev_pmd_release;
+	rte_rawdev_queue_conf_get;
+	rte_rawdev_queue_setup;
+	rte_rawdev_queue_release;
+	rte_rawdev_reset;
+	rte_rawdev_socket_id;
+	rte_rawdev_start;
+	rte_rawdev_stop;
+	rte_rawdev_xstats_by_name_get;
+	rte_rawdev_xstats_get;
+	rte_rawdev_xstats_names_get;
+	rte_rawdev_xstats_reset;
+
+	local: *;
+};
-- 
2.7.4

^ permalink raw reply	[flat|nested] 3+ messages in thread

* [dpdk-dev] [RFC PATCH 2/2] config: enable compilation of raw device library
  2017-11-08 17:40 [dpdk-dev] [RFC PATCH 0/2] RAW Device Support Hemant Agrawal
  2017-11-08 17:40 ` [dpdk-dev] [RFC PATCH 1/2] lib: introduce raw device library Hemant Agrawal
@ 2017-11-08 17:40 ` Hemant Agrawal
  1 sibling, 0 replies; 3+ messages in thread
From: Hemant Agrawal @ 2017-11-08 17:40 UTC (permalink / raw)
  To: dev; +Cc: fiona.trahe, rosen.xu, shreyansh.jain

Signed-off-by: Hemant Agrawal <hemant.agrawal@nxp.com>
---
 config/common_base | 7 +++++++
 lib/Makefile       | 3 +++
 2 files changed, 10 insertions(+)

diff --git a/config/common_base b/config/common_base
index 34f04a9..30ab741 100644
--- a/config/common_base
+++ b/config/common_base
@@ -793,6 +793,13 @@ CONFIG_RTE_LIBRTE_VHOST_NUMA=n
 CONFIG_RTE_LIBRTE_VHOST_DEBUG=n
 
 #
+# Compile raw device support
+# EXPERIMENTAL: API may change without prior notice
+#
+CONFIG_RTE_LIBRTE_RAWDEV=y
+CONFIG_RTE_LIBRTE_RAWDEV_DEBUG=n
+
+#
 # Compile vhost PMD
 # To compile, CONFIG_RTE_LIBRTE_VHOST should be enabled.
 #
diff --git a/lib/Makefile b/lib/Makefile
index dc4e8df..4c60f30 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -126,4 +126,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_KNI) += librte_kni
 endif
 DEPDIRS-librte_kni := librte_eal librte_mempool librte_mbuf librte_ether
 
+DIRS-$(CONFIG_RTE_LIBRTE_RAWDEV) += librte_rawdev
+DEPDIRS-librte_rawdev := librte_eal librte_mbuf librte_ether librte_cryptodev
+
 include $(RTE_SDK)/mk/rte.subdir.mk
-- 
2.7.4

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2017-11-08 17:41 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-11-08 17:40 [dpdk-dev] [RFC PATCH 0/2] RAW Device Support Hemant Agrawal
2017-11-08 17:40 ` [dpdk-dev] [RFC PATCH 1/2] lib: introduce raw device library Hemant Agrawal
2017-11-08 17:40 ` [dpdk-dev] [RFC PATCH 2/2] config: enable compilation of " Hemant Agrawal

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).