get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/21028/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 21028,
    "url": "https://patches.dpdk.org/api/patches/21028/?format=api",
    "web_url": "https://patches.dpdk.org/project/dpdk/patch/1488414008-162839-9-git-send-email-allain.legacy@windriver.com/",
    "project": {
        "id": 1,
        "url": "https://patches.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<1488414008-162839-9-git-send-email-allain.legacy@windriver.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/1488414008-162839-9-git-send-email-allain.legacy@windriver.com",
    "date": "2017-03-02T00:20:00",
    "name": "[dpdk-dev,v3,08/16] net/avp: device initialization",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "1f09b43c98a266825dfee0776eb255057522e609",
    "submitter": {
        "id": 679,
        "url": "https://patches.dpdk.org/api/people/679/?format=api",
        "name": "Allain Legacy",
        "email": "allain.legacy@windriver.com"
    },
    "delegate": {
        "id": 319,
        "url": "https://patches.dpdk.org/api/users/319/?format=api",
        "username": "fyigit",
        "first_name": "Ferruh",
        "last_name": "Yigit",
        "email": "ferruh.yigit@amd.com"
    },
    "mbox": "https://patches.dpdk.org/project/dpdk/patch/1488414008-162839-9-git-send-email-allain.legacy@windriver.com/mbox/",
    "series": [],
    "comments": "https://patches.dpdk.org/api/patches/21028/comments/",
    "check": "warning",
    "checks": "https://patches.dpdk.org/api/patches/21028/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@dpdk.org",
        "Delivered-To": "patchwork@dpdk.org",
        "Received": [
            "from [92.243.14.124] (localhost [IPv6:::1])\n\tby dpdk.org (Postfix) with ESMTP id 1F510D586;\n\tThu,  2 Mar 2017 01:21:23 +0100 (CET)",
            "from mail5.wrs.com (mail5.windriver.com [192.103.53.11])\n\tby dpdk.org (Postfix) with ESMTP id 3F8292B9D\n\tfor <dev@dpdk.org>; Thu,  2 Mar 2017 01:20:33 +0100 (CET)",
            "from ALA-HCA.corp.ad.wrs.com (ala-hca.corp.ad.wrs.com\n\t[147.11.189.40])\n\tby mail5.wrs.com (8.15.2/8.15.2) with ESMTPS id v220KWUn011288\n\t(version=TLSv1 cipher=AES128-SHA bits=128 verify=OK);\n\tWed, 1 Mar 2017 16:20:32 -0800",
            "from yow-cgts4-lx.wrs.com (128.224.145.137) by\n\tALA-HCA.corp.ad.wrs.com (147.11.189.50) with Microsoft SMTP Server\n\t(TLS) id 14.3.294.0; Wed, 1 Mar 2017 16:20:31 -0800"
        ],
        "From": "Allain Legacy <allain.legacy@windriver.com>",
        "To": "<ferruh.yigit@intel.com>",
        "CC": "<ian.jolliffe@windriver.com>, <jerin.jacob@caviumnetworks.com>,\n\t<stephen@networkplumber.org>, <thomas.monjalon@6wind.com>, <dev@dpdk.org>",
        "Date": "Wed, 1 Mar 2017 19:20:00 -0500",
        "Message-ID": "<1488414008-162839-9-git-send-email-allain.legacy@windriver.com>",
        "X-Mailer": "git-send-email 1.8.3.1",
        "In-Reply-To": "<1488414008-162839-1-git-send-email-allain.legacy@windriver.com>",
        "References": "<1488136143-116389-1-git-send-email-allain.legacy@windriver.com>\n\t<1488414008-162839-1-git-send-email-allain.legacy@windriver.com>",
        "MIME-Version": "1.0",
        "Content-Type": "text/plain",
        "X-Originating-IP": "[128.224.145.137]",
        "Subject": "[dpdk-dev] [PATCH v3 08/16] net/avp: device initialization",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<http://dpdk.org/ml/options/dev>,\n\t<mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://dpdk.org/ml/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<http://dpdk.org/ml/listinfo/dev>,\n\t<mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "Adds support for initialization newly probed AVP PCI devices.  Initial\nqueue translations are setup in preparation for device configuration.\n\nSigned-off-by: Allain Legacy <allain.legacy@windriver.com>\nSigned-off-by: Matt Peters <matt.peters@windriver.com>\n---\n drivers/net/avp/avp_ethdev.c | 733 +++++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 733 insertions(+)",
    "diff": "diff --git a/drivers/net/avp/avp_ethdev.c b/drivers/net/avp/avp_ethdev.c\nindex f0bf862..467cec8 100644\n--- a/drivers/net/avp/avp_ethdev.c\n+++ b/drivers/net/avp/avp_ethdev.c\n@@ -53,6 +53,7 @@\n #include <rte_dev.h>\n #include <rte_memory.h>\n #include <rte_eal.h>\n+#include <rte_io.h>\n \n #include \"rte_avp_common.h\"\n #include \"rte_avp_fifo.h\"\n@@ -60,6 +61,8 @@\n #include \"avp_logs.h\"\n \n \n+static int avp_dev_create(struct rte_pci_device *pci_dev,\n+\t\t\t  struct rte_eth_dev *eth_dev);\n \n static int eth_avp_dev_init(struct rte_eth_dev *eth_dev);\n static int eth_avp_dev_uninit(struct rte_eth_dev *eth_dev);\n@@ -103,6 +106,16 @@\n };\n \n \n+/**@{ AVP device flags */\n+#define AVP_F_PROMISC (1 << 1)\n+#define AVP_F_CONFIGURED (1 << 2)\n+#define AVP_F_LINKUP (1 << 3)\n+#define AVP_F_DETACHED (1 << 4)\n+/**@} */\n+\n+/* Ethernet device validation marker */\n+#define AVP_ETHDEV_MAGIC 0x92972862\n+\n /*\n  * Defines the AVP device attributes which are attached to an RTE ethernet\n  * device\n@@ -150,11 +163,701 @@ struct avp_adapter {\n \tstruct avp_dev avp;\n } __rte_cache_aligned;\n \n+\n+/* 32-bit MMIO register write */\n+#define AVP_WRITE32(_value, _addr) rte_write32_relaxed((_value), (_addr))\n+\n+/* 32-bit MMIO register read */\n+#define AVP_READ32(_addr) rte_read32_relaxed((_addr))\n+\n /* Macro to cast the ethernet device private data to a AVP object */\n #define AVP_DEV_PRIVATE_TO_HW(adapter) \\\n \t(&((struct avp_adapter *)adapter)->avp)\n \n /*\n+ * Defines the structure of a AVP device queue for the purpose of handling the\n+ * receive and transmit burst callback functions\n+ */\n+struct avp_queue {\n+\tstruct rte_eth_dev_data *dev_data;\n+\t/**< Backpointer to ethernet device data */\n+\tstruct avp_dev *avp; /**< Backpointer to AVP device */\n+\tuint16_t queue_id;\n+\t/**< Queue identifier used for indexing current queue */\n+\tuint16_t queue_base;\n+\t/**< Base queue identifier for queue servicing */\n+\tuint16_t queue_limit;\n+\t/**< Maximum queue identifier for queue servicing */\n+\n+\tuint64_t packets;\n+\tuint64_t bytes;\n+\tuint64_t errors;\n+};\n+\n+/* send a request and wait for a response\n+ *\n+ * @warning must be called while holding the avp->lock spinlock.\n+ */\n+static int\n+avp_dev_process_request(struct avp_dev *avp, struct rte_avp_request *request)\n+{\n+\tunsigned int retry = AVP_MAX_REQUEST_RETRY;\n+\tvoid *resp_addr = NULL;\n+\tunsigned int count;\n+\tint ret;\n+\n+\tPMD_DRV_LOG(DEBUG, \"Sending request %u to host\\n\", request->req_id);\n+\n+\trequest->result = -ENOTSUP;\n+\n+\t/* Discard any stale responses before starting a new request */\n+\twhile (avp_fifo_get(avp->resp_q, (void **)&resp_addr, 1))\n+\t\tPMD_DRV_LOG(DEBUG, \"Discarding stale response\\n\");\n+\n+\trte_memcpy(avp->sync_addr, request, sizeof(*request));\n+\tcount = avp_fifo_put(avp->req_q, &avp->host_sync_addr, 1);\n+\tif (count < 1) {\n+\t\tPMD_DRV_LOG(ERR, \"Cannot send request %u to host\\n\",\n+\t\t\t    request->req_id);\n+\t\tret = -EBUSY;\n+\t\tgoto done;\n+\t}\n+\n+\twhile (retry--) {\n+\t\t/* wait for a response */\n+\t\tusleep(AVP_REQUEST_DELAY_USECS);\n+\n+\t\tcount = avp_fifo_count(avp->resp_q);\n+\t\tif (count >= 1) {\n+\t\t\t/* response received */\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\tif ((count < 1) && (retry == 0)) {\n+\t\t\tPMD_DRV_LOG(ERR, \"Timeout while waiting for a response for %u\\n\",\n+\t\t\t\t    request->req_id);\n+\t\t\tret = -ETIME;\n+\t\t\tgoto done;\n+\t\t}\n+\t}\n+\n+\t/* retrieve the response */\n+\tcount = avp_fifo_get(avp->resp_q, (void **)&resp_addr, 1);\n+\tif ((count != 1) || (resp_addr != avp->host_sync_addr)) {\n+\t\tPMD_DRV_LOG(ERR, \"Invalid response from host, count=%u resp=%p host_sync_addr=%p\\n\",\n+\t\t\t    count, resp_addr, avp->host_sync_addr);\n+\t\tret = -ENODATA;\n+\t\tgoto done;\n+\t}\n+\n+\t/* copy to user buffer */\n+\trte_memcpy(request, avp->sync_addr, sizeof(*request));\n+\tret = 0;\n+\n+\tPMD_DRV_LOG(DEBUG, \"Result %d received for request %u\\n\",\n+\t\t    request->result, request->req_id);\n+\n+done:\n+\treturn ret;\n+}\n+\n+static int\n+avp_dev_ctrl_set_config(struct rte_eth_dev *eth_dev,\n+\t\t\tstruct rte_avp_device_config *config)\n+{\n+\tstruct avp_dev *avp = AVP_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private);\n+\tstruct rte_avp_request request;\n+\tint ret;\n+\n+\t/* setup a configure request */\n+\tmemset(&request, 0, sizeof(request));\n+\trequest.req_id = RTE_AVP_REQ_CFG_DEVICE;\n+\tmemcpy(&request.config, config, sizeof(request.config));\n+\n+\tret = avp_dev_process_request(avp, &request);\n+\n+\treturn ret == 0 ? request.result : ret;\n+}\n+\n+static int\n+avp_dev_ctrl_shutdown(struct rte_eth_dev *eth_dev)\n+{\n+\tstruct avp_dev *avp = AVP_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private);\n+\tstruct rte_avp_request request;\n+\tint ret;\n+\n+\t/* setup a shutdown request */\n+\tmemset(&request, 0, sizeof(request));\n+\trequest.req_id = RTE_AVP_REQ_SHUTDOWN_DEVICE;\n+\n+\tret = avp_dev_process_request(avp, &request);\n+\n+\treturn ret == 0 ? request.result : ret;\n+}\n+\n+/* translate from host physical address to guest virtual address */\n+static void *\n+avp_dev_translate_address(struct rte_eth_dev *eth_dev,\n+\t\t\t  phys_addr_t host_phys_addr)\n+{\n+\tstruct rte_pci_device *pci_dev = AVP_DEV_TO_PCI(eth_dev);\n+\tstruct rte_mem_resource *resource;\n+\tstruct rte_avp_memmap_info *info;\n+\tstruct rte_avp_memmap *map;\n+\toff_t offset;\n+\tvoid *addr;\n+\tunsigned int i;\n+\n+\taddr = pci_dev->mem_resource[RTE_AVP_PCI_MEMORY_BAR].addr;\n+\tresource = &pci_dev->mem_resource[RTE_AVP_PCI_MEMMAP_BAR];\n+\tinfo = (struct rte_avp_memmap_info *)resource->addr;\n+\n+\toffset = 0;\n+\tfor (i = 0; i < info->nb_maps; i++) {\n+\t\t/* search all segments looking for a matching address */\n+\t\tmap = &info->maps[i];\n+\n+\t\tif ((host_phys_addr >= map->phys_addr) &&\n+\t\t\t(host_phys_addr < (map->phys_addr + map->length))) {\n+\t\t\t/* address is within this segment */\n+\t\t\toffset += (host_phys_addr - map->phys_addr);\n+\t\t\taddr = RTE_PTR_ADD(addr, offset);\n+\n+\t\t\tPMD_DRV_LOG(DEBUG, \"Translating host physical 0x%\" PRIx64 \" to guest virtual 0x%p\\n\",\n+\t\t\t\t    host_phys_addr, addr);\n+\n+\t\t\treturn addr;\n+\t\t}\n+\t\toffset += map->length;\n+\t}\n+\n+\treturn NULL;\n+}\n+\n+/* verify that the incoming device version is compatible with our version */\n+static int\n+avp_dev_version_check(uint32_t version)\n+{\n+\tuint32_t driver = RTE_AVP_STRIP_MINOR_VERSION(AVP_DPDK_DRIVER_VERSION);\n+\tuint32_t device = RTE_AVP_STRIP_MINOR_VERSION(version);\n+\n+\tif (device <= driver) {\n+\t\t/* the host driver version is less than or equal to ours */\n+\t\treturn 0;\n+\t}\n+\n+\treturn 1;\n+}\n+\n+/* verify that memory regions have expected version and validation markers */\n+static int\n+avp_dev_check_regions(struct rte_eth_dev *eth_dev)\n+{\n+\tstruct rte_pci_device *pci_dev = AVP_DEV_TO_PCI(eth_dev);\n+\tstruct rte_avp_memmap_info *memmap;\n+\tstruct rte_avp_device_info *info;\n+\tstruct rte_mem_resource *resource;\n+\tunsigned int i;\n+\n+\t/* Dump resource info for debug */\n+\tfor (i = 0; i < PCI_MAX_RESOURCE; i++) {\n+\t\tresource = &pci_dev->mem_resource[i];\n+\t\tif ((resource->phys_addr == 0) || (resource->len == 0))\n+\t\t\tcontinue;\n+\n+\t\tPMD_DRV_LOG(DEBUG, \"resource[%u]: phys=0x%\" PRIx64 \" len=%\" PRIu64 \" addr=%p\\n\",\n+\t\t\t    i, resource->phys_addr,\n+\t\t\t    resource->len, resource->addr);\n+\n+\t\tswitch (i) {\n+\t\tcase RTE_AVP_PCI_MEMMAP_BAR:\n+\t\t\tmemmap = (struct rte_avp_memmap_info *)resource->addr;\n+\t\t\tif ((memmap->magic != RTE_AVP_MEMMAP_MAGIC) ||\n+\t\t\t    (memmap->version != RTE_AVP_MEMMAP_VERSION)) {\n+\t\t\t\tPMD_DRV_LOG(ERR, \"Invalid memmap magic 0x%08x and version %u\\n\",\n+\t\t\t\t\t    memmap->magic, memmap->version);\n+\t\t\t\treturn -EINVAL;\n+\t\t\t}\n+\t\t\tbreak;\n+\n+\t\tcase RTE_AVP_PCI_DEVICE_BAR:\n+\t\t\tinfo = (struct rte_avp_device_info *)resource->addr;\n+\t\t\tif ((info->magic != RTE_AVP_DEVICE_MAGIC) ||\n+\t\t\t    avp_dev_version_check(info->version)) {\n+\t\t\t\tPMD_DRV_LOG(ERR, \"Invalid device info magic 0x%08x or version 0x%08x > 0x%08x\\n\",\n+\t\t\t\t\t    info->magic, info->version,\n+\t\t\t\t\t    AVP_DPDK_DRIVER_VERSION);\n+\t\t\t\treturn -EINVAL;\n+\t\t\t}\n+\t\t\tbreak;\n+\n+\t\tcase RTE_AVP_PCI_MEMORY_BAR:\n+\t\tcase RTE_AVP_PCI_MMIO_BAR:\n+\t\t\tif (resource->addr == NULL) {\n+\t\t\t\tPMD_DRV_LOG(ERR, \"Missing address space for BAR%u\\n\",\n+\t\t\t\t\t    i);\n+\t\t\t\treturn -EINVAL;\n+\t\t\t}\n+\t\t\tbreak;\n+\n+\t\tcase RTE_AVP_PCI_MSIX_BAR:\n+\t\tdefault:\n+\t\t\t/* no validation required */\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int\n+avp_dev_detach(struct rte_eth_dev *eth_dev)\n+{\n+\tstruct avp_dev *avp = AVP_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private);\n+\tint ret;\n+\n+\tPMD_DRV_LOG(NOTICE, \"Detaching port %u from AVP device 0x%\" PRIx64 \"\\n\",\n+\t\t    eth_dev->data->port_id, avp->device_id);\n+\n+\trte_spinlock_lock(&avp->lock);\n+\n+\tif (avp->flags & AVP_F_DETACHED) {\n+\t\tPMD_DRV_LOG(NOTICE, \"port %u already detached\\n\",\n+\t\t\t    eth_dev->data->port_id);\n+\t\tret = 0;\n+\t\tgoto unlock;\n+\t}\n+\n+\t/* shutdown the device first so the host stops sending us packets. */\n+\tret = avp_dev_ctrl_shutdown(eth_dev);\n+\tif (ret < 0) {\n+\t\tPMD_DRV_LOG(ERR, \"Failed to send/recv shutdown to host, ret=%d\\n\",\n+\t\t\t    ret);\n+\t\tavp->flags &= ~AVP_F_DETACHED;\n+\t\tgoto unlock;\n+\t}\n+\n+\tavp->flags |= AVP_F_DETACHED;\n+\trte_wmb();\n+\n+\t/* wait for queues to acknowledge the presence of the detach flag */\n+\trte_delay_ms(1);\n+\n+\tret = 0;\n+\n+unlock:\n+\trte_spinlock_unlock(&avp->lock);\n+\treturn ret;\n+}\n+\n+static void\n+_avp_set_rx_queue_mappings(struct rte_eth_dev *eth_dev, uint16_t rx_queue_id)\n+{\n+\tstruct avp_dev *avp =\n+\t\tAVP_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private);\n+\tstruct avp_queue *rxq;\n+\tuint16_t queue_count;\n+\tuint16_t remainder;\n+\n+\trxq = (struct avp_queue *)eth_dev->data->rx_queues[rx_queue_id];\n+\n+\t/*\n+\t * Must map all AVP fifos as evenly as possible between the configured\n+\t * device queues.  Each device queue will service a subset of the AVP\n+\t * fifos. If there is an odd number of device queues the first set of\n+\t * device queues will get the extra AVP fifos.\n+\t */\n+\tqueue_count = avp->num_rx_queues / eth_dev->data->nb_rx_queues;\n+\tremainder = avp->num_rx_queues % eth_dev->data->nb_rx_queues;\n+\tif (rx_queue_id < remainder) {\n+\t\t/* these queues must service one extra FIFO */\n+\t\trxq->queue_base = rx_queue_id * (queue_count + 1);\n+\t\trxq->queue_limit = rxq->queue_base + (queue_count + 1) - 1;\n+\t} else {\n+\t\t/* these queues service the regular number of FIFO */\n+\t\trxq->queue_base = ((remainder * (queue_count + 1)) +\n+\t\t\t\t   ((rx_queue_id - remainder) * queue_count));\n+\t\trxq->queue_limit = rxq->queue_base + queue_count - 1;\n+\t}\n+\n+\tPMD_DRV_LOG(DEBUG, \"rxq %u at %p base %u limit %u\\n\",\n+\t\t    rx_queue_id, rxq, rxq->queue_base, rxq->queue_limit);\n+\n+\trxq->queue_id = rxq->queue_base;\n+}\n+\n+static void\n+_avp_set_queue_counts(struct rte_eth_dev *eth_dev)\n+{\n+\tstruct rte_pci_device *pci_dev = AVP_DEV_TO_PCI(eth_dev);\n+\tstruct avp_dev *avp = AVP_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private);\n+\tstruct rte_avp_device_info *host_info;\n+\tvoid *addr;\n+\n+\taddr = pci_dev->mem_resource[RTE_AVP_PCI_DEVICE_BAR].addr;\n+\thost_info = (struct rte_avp_device_info *)addr;\n+\n+\t/*\n+\t * the transmit direction is not negotiated beyond respecting the max\n+\t * number of queues because the host can handle arbitrary guest tx\n+\t * queues (host rx queues).\n+\t */\n+\tavp->num_tx_queues = eth_dev->data->nb_tx_queues;\n+\n+\t/*\n+\t * the receive direction is more restrictive.  The host requires a\n+\t * minimum number of guest rx queues (host tx queues) therefore\n+\t * negotiate a value that is at least as large as the host minimum\n+\t * requirement.  If the host and guest values are not identical then a\n+\t * mapping will be established in the receive_queue_setup function.\n+\t */\n+\tavp->num_rx_queues = RTE_MAX(host_info->min_rx_queues,\n+\t\t\t\t     eth_dev->data->nb_rx_queues);\n+\n+\tPMD_DRV_LOG(DEBUG, \"Requesting %u Tx and %u Rx queues from host\\n\",\n+\t\t    avp->num_tx_queues, avp->num_rx_queues);\n+}\n+\n+static int\n+avp_dev_attach(struct rte_eth_dev *eth_dev)\n+{\n+\tstruct avp_dev *avp = AVP_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private);\n+\tstruct rte_avp_device_config config;\n+\tunsigned int i;\n+\tint ret;\n+\n+\tPMD_DRV_LOG(NOTICE, \"Attaching port %u to AVP device 0x%\" PRIx64 \"\\n\",\n+\t\t    eth_dev->data->port_id, avp->device_id);\n+\n+\trte_spinlock_lock(&avp->lock);\n+\n+\tif (!(avp->flags & AVP_F_DETACHED)) {\n+\t\tPMD_DRV_LOG(NOTICE, \"port %u already attached\\n\",\n+\t\t\t    eth_dev->data->port_id);\n+\t\tret = 0;\n+\t\tgoto unlock;\n+\t}\n+\n+\t/*\n+\t * make sure that the detached flag is set prior to reconfiguring the\n+\t * queues.\n+\t */\n+\tavp->flags |= AVP_F_DETACHED;\n+\trte_wmb();\n+\n+\t/*\n+\t * re-run the device create utility which will parse the new host info\n+\t * and setup the AVP device queue pointers.\n+\t */\n+\tret = avp_dev_create(AVP_DEV_TO_PCI(eth_dev), eth_dev);\n+\tif (ret < 0) {\n+\t\tPMD_DRV_LOG(ERR, \"Failed to re-create AVP device, ret=%d\\n\",\n+\t\t\t    ret);\n+\t\tgoto unlock;\n+\t}\n+\n+\tif (avp->flags & AVP_F_CONFIGURED) {\n+\t\t/*\n+\t\t * Update the receive queue mapping to handle cases where the\n+\t\t * source and destination hosts have different queue\n+\t\t * requirements.  As long as the DETACHED flag is asserted the\n+\t\t * queue table should not be referenced so it should be safe to\n+\t\t * update it.\n+\t\t */\n+\t\t_avp_set_queue_counts(eth_dev);\n+\t\tfor (i = 0; i < eth_dev->data->nb_rx_queues; i++)\n+\t\t\t_avp_set_rx_queue_mappings(eth_dev, i);\n+\n+\t\t/*\n+\t\t * Update the host with our config details so that it knows the\n+\t\t * device is active.\n+\t\t */\n+\t\tmemset(&config, 0, sizeof(config));\n+\t\tconfig.device_id = avp->device_id;\n+\t\tconfig.driver_type = RTE_AVP_DRIVER_TYPE_DPDK;\n+\t\tconfig.driver_version = AVP_DPDK_DRIVER_VERSION;\n+\t\tconfig.features = avp->features;\n+\t\tconfig.num_tx_queues = avp->num_tx_queues;\n+\t\tconfig.num_rx_queues = avp->num_rx_queues;\n+\t\tconfig.if_up = !!(avp->flags & AVP_F_LINKUP);\n+\n+\t\tret = avp_dev_ctrl_set_config(eth_dev, &config);\n+\t\tif (ret < 0) {\n+\t\t\tPMD_DRV_LOG(ERR, \"Config request failed by host, ret=%d\\n\",\n+\t\t\t\t    ret);\n+\t\t\tgoto unlock;\n+\t\t}\n+\t}\n+\n+\trte_wmb();\n+\tavp->flags &= ~AVP_F_DETACHED;\n+\n+\tret = 0;\n+\n+unlock:\n+\trte_spinlock_unlock(&avp->lock);\n+\treturn ret;\n+}\n+\n+static void\n+avp_dev_interrupt_handler(struct rte_intr_handle *intr_handle,\n+\t\t\t\t\t\t  void *data)\n+{\n+\tstruct rte_eth_dev *eth_dev = data;\n+\tstruct rte_pci_device *pci_dev = AVP_DEV_TO_PCI(eth_dev);\n+\tvoid *registers = pci_dev->mem_resource[RTE_AVP_PCI_MMIO_BAR].addr;\n+\tuint32_t status, value;\n+\tint ret;\n+\n+\tif (registers == NULL)\n+\t\trte_panic(\"no mapped MMIO register space\\n\");\n+\n+\t/* read the interrupt status register\n+\t * note: this register clears on read so all raised interrupts must be\n+\t *    handled or remembered for later processing\n+\t */\n+\tstatus = AVP_READ32(\n+\t\tRTE_PTR_ADD(registers,\n+\t\t\t    RTE_AVP_INTERRUPT_STATUS_OFFSET));\n+\n+\tif (status | RTE_AVP_MIGRATION_INTERRUPT_MASK) {\n+\t\t/* handle interrupt based on current status */\n+\t\tvalue = AVP_READ32(\n+\t\t\tRTE_PTR_ADD(registers,\n+\t\t\t\t    RTE_AVP_MIGRATION_STATUS_OFFSET));\n+\t\tswitch (value) {\n+\t\tcase RTE_AVP_MIGRATION_DETACHED:\n+\t\t\tret = avp_dev_detach(eth_dev);\n+\t\t\tbreak;\n+\t\tcase RTE_AVP_MIGRATION_ATTACHED:\n+\t\t\tret = avp_dev_attach(eth_dev);\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tPMD_DRV_LOG(ERR, \"unexpected migration status, status=%u\\n\",\n+\t\t\t\t    value);\n+\t\t\tret = -EINVAL;\n+\t\t}\n+\n+\t\t/* acknowledge the request by writing out our current status */\n+\t\tvalue = (ret == 0 ? value : RTE_AVP_MIGRATION_ERROR);\n+\t\tAVP_WRITE32(value,\n+\t\t\t    RTE_PTR_ADD(registers,\n+\t\t\t\t\tRTE_AVP_MIGRATION_ACK_OFFSET));\n+\n+\t\tPMD_DRV_LOG(NOTICE, \"AVP migration interrupt handled\\n\");\n+\t}\n+\n+\tif (status & ~RTE_AVP_MIGRATION_INTERRUPT_MASK)\n+\t\tPMD_DRV_LOG(WARNING, \"AVP unexpected interrupt, status=0x%08x\\n\",\n+\t\t\t    status);\n+\n+\t/* re-enable UIO interrupt handling */\n+\tret = rte_intr_enable(intr_handle);\n+\tif (ret < 0) {\n+\t\tPMD_DRV_LOG(ERR, \"Failed to re-enable UIO interrupts, ret=%d\\n\",\n+\t\t\t    ret);\n+\t\t/* continue */\n+\t}\n+}\n+\n+static int\n+avp_dev_enable_interrupts(struct rte_eth_dev *eth_dev)\n+{\n+\tstruct rte_pci_device *pci_dev = AVP_DEV_TO_PCI(eth_dev);\n+\tvoid *registers = pci_dev->mem_resource[RTE_AVP_PCI_MMIO_BAR].addr;\n+\tint ret;\n+\n+\tif (registers == NULL)\n+\t\treturn -EINVAL;\n+\n+\t/* enable UIO interrupt handling */\n+\tret = rte_intr_enable(&pci_dev->intr_handle);\n+\tif (ret < 0) {\n+\t\tPMD_DRV_LOG(ERR, \"Failed to enable UIO interrupts, ret=%d\\n\",\n+\t\t\t    ret);\n+\t\treturn ret;\n+\t}\n+\n+\t/* inform the device that all interrupts are enabled */\n+\tAVP_WRITE32(RTE_AVP_APP_INTERRUPTS_MASK,\n+\t\t    RTE_PTR_ADD(registers, RTE_AVP_INTERRUPT_MASK_OFFSET));\n+\n+\treturn 0;\n+}\n+\n+static int\n+avp_dev_setup_interrupts(struct rte_eth_dev *eth_dev)\n+{\n+\tstruct rte_pci_device *pci_dev = AVP_DEV_TO_PCI(eth_dev);\n+\tint ret;\n+\n+\t/* register a callback handler with UIO for interrupt notifications */\n+\tret = rte_intr_callback_register(&pci_dev->intr_handle,\n+\t\t\t\t\t avp_dev_interrupt_handler,\n+\t\t\t\t\t (void *)eth_dev);\n+\tif (ret < 0) {\n+\t\tPMD_DRV_LOG(ERR, \"Failed to register UIO interrupt callback, ret=%d\\n\",\n+\t\t\t    ret);\n+\t\treturn ret;\n+\t}\n+\n+\t/* enable interrupt processing */\n+\treturn avp_dev_enable_interrupts(eth_dev);\n+}\n+\n+static int\n+avp_dev_migration_pending(struct rte_eth_dev *eth_dev)\n+{\n+\tstruct rte_pci_device *pci_dev = AVP_DEV_TO_PCI(eth_dev);\n+\tvoid *registers = pci_dev->mem_resource[RTE_AVP_PCI_MMIO_BAR].addr;\n+\tuint32_t value;\n+\n+\tif (registers == NULL)\n+\t\treturn 0;\n+\n+\tvalue = AVP_READ32(RTE_PTR_ADD(registers,\n+\t\t\t\t       RTE_AVP_MIGRATION_STATUS_OFFSET));\n+\tif (value == RTE_AVP_MIGRATION_DETACHED) {\n+\t\t/* migration is in progress; ack it if we have not already */\n+\t\tAVP_WRITE32(value,\n+\t\t\t    RTE_PTR_ADD(registers,\n+\t\t\t\t\tRTE_AVP_MIGRATION_ACK_OFFSET));\n+\t\treturn 1;\n+\t}\n+\treturn 0;\n+}\n+\n+/*\n+ * create a AVP device using the supplied device info by first translating it\n+ * to guest address space(s).\n+ */\n+static int\n+avp_dev_create(struct rte_pci_device *pci_dev,\n+\t       struct rte_eth_dev *eth_dev)\n+{\n+\tstruct avp_dev *avp = AVP_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private);\n+\tstruct rte_avp_device_info *host_info;\n+\tstruct rte_mem_resource *resource;\n+\tunsigned int i;\n+\n+\tresource = &pci_dev->mem_resource[RTE_AVP_PCI_DEVICE_BAR];\n+\tif (resource->addr == NULL) {\n+\t\tPMD_DRV_LOG(ERR, \"BAR%u is not mapped\\n\",\n+\t\t\t    RTE_AVP_PCI_DEVICE_BAR);\n+\t\treturn -EFAULT;\n+\t}\n+\thost_info = (struct rte_avp_device_info *)resource->addr;\n+\n+\tif ((host_info->magic != RTE_AVP_DEVICE_MAGIC) ||\n+\t\tavp_dev_version_check(host_info->version)) {\n+\t\tPMD_DRV_LOG(ERR, \"Invalid AVP PCI device, magic 0x%08x version 0x%08x > 0x%08x\\n\",\n+\t\t\t    host_info->magic, host_info->version,\n+\t\t\t    AVP_DPDK_DRIVER_VERSION);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tPMD_DRV_LOG(DEBUG, \"AVP host device is v%u.%u.%u\\n\",\n+\t\t    RTE_AVP_GET_RELEASE_VERSION(host_info->version),\n+\t\t    RTE_AVP_GET_MAJOR_VERSION(host_info->version),\n+\t\t    RTE_AVP_GET_MINOR_VERSION(host_info->version));\n+\n+\tPMD_DRV_LOG(DEBUG, \"AVP host supports %u to %u TX queue(s)\\n\",\n+\t\t    host_info->min_tx_queues, host_info->max_tx_queues);\n+\tPMD_DRV_LOG(DEBUG, \"AVP host supports %u to %u RX queue(s)\\n\",\n+\t\t    host_info->min_rx_queues, host_info->max_rx_queues);\n+\tPMD_DRV_LOG(DEBUG, \"AVP host supports features 0x%08x\\n\",\n+\t\t    host_info->features);\n+\n+\tif (avp->magic != AVP_ETHDEV_MAGIC) {\n+\t\t/*\n+\t\t * First time initialization (i.e., not during a VM\n+\t\t * migration)\n+\t\t */\n+\t\tmemset(avp, 0, sizeof(*avp));\n+\t\tavp->magic = AVP_ETHDEV_MAGIC;\n+\t\tavp->dev_data = eth_dev->data;\n+\t\tavp->port_id = eth_dev->data->port_id;\n+\t\tavp->host_mbuf_size = host_info->mbuf_size;\n+\t\tavp->host_features = host_info->features;\n+\t\trte_spinlock_init(&avp->lock);\n+\t\tmemcpy(&avp->ethaddr.addr_bytes[0],\n+\t\t       host_info->ethaddr, ETHER_ADDR_LEN);\n+\t\t/* adjust max values to not exceed our max */\n+\t\tavp->max_tx_queues =\n+\t\t\tRTE_MIN(host_info->max_tx_queues, RTE_AVP_MAX_QUEUES);\n+\t\tavp->max_rx_queues =\n+\t\t\tRTE_MIN(host_info->max_rx_queues, RTE_AVP_MAX_QUEUES);\n+\t} else {\n+\t\t/* Re-attaching during migration */\n+\n+\t\t/* TODO... requires validation of host values */\n+\t\tif ((host_info->features & avp->features) != avp->features) {\n+\t\t\tPMD_DRV_LOG(ERR, \"AVP host features mismatched; 0x%08x, host=0x%08x\\n\",\n+\t\t\t\t    avp->features, host_info->features);\n+\t\t\t/* this should not be possible; continue for now */\n+\t\t}\n+\t}\n+\n+\t/* the device id is allowed to change over migrations */\n+\tavp->device_id = host_info->device_id;\n+\n+\t/* translate incoming host addresses to guest address space */\n+\tPMD_DRV_LOG(DEBUG, \"AVP first host tx queue at 0x%\" PRIx64 \"\\n\",\n+\t\t    host_info->tx_phys);\n+\tPMD_DRV_LOG(DEBUG, \"AVP first host alloc queue at 0x%\" PRIx64 \"\\n\",\n+\t\t    host_info->alloc_phys);\n+\tfor (i = 0; i < avp->max_tx_queues; i++) {\n+\t\tavp->tx_q[i] = avp_dev_translate_address(eth_dev,\n+\t\t\thost_info->tx_phys + (i * host_info->tx_size));\n+\n+\t\tavp->alloc_q[i] = avp_dev_translate_address(eth_dev,\n+\t\t\thost_info->alloc_phys + (i * host_info->alloc_size));\n+\t}\n+\n+\tPMD_DRV_LOG(DEBUG, \"AVP first host rx queue at 0x%\" PRIx64 \"\\n\",\n+\t\t    host_info->rx_phys);\n+\tPMD_DRV_LOG(DEBUG, \"AVP first host free queue at 0x%\" PRIx64 \"\\n\",\n+\t\t    host_info->free_phys);\n+\tfor (i = 0; i < avp->max_rx_queues; i++) {\n+\t\tavp->rx_q[i] = avp_dev_translate_address(eth_dev,\n+\t\t\thost_info->rx_phys + (i * host_info->rx_size));\n+\t\tavp->free_q[i] = avp_dev_translate_address(eth_dev,\n+\t\t\thost_info->free_phys + (i * host_info->free_size));\n+\t}\n+\n+\tPMD_DRV_LOG(DEBUG, \"AVP host request queue at 0x%\" PRIx64 \"\\n\",\n+\t\t    host_info->req_phys);\n+\tPMD_DRV_LOG(DEBUG, \"AVP host response queue at 0x%\" PRIx64 \"\\n\",\n+\t\t    host_info->resp_phys);\n+\tPMD_DRV_LOG(DEBUG, \"AVP host sync address at 0x%\" PRIx64 \"\\n\",\n+\t\t    host_info->sync_phys);\n+\tPMD_DRV_LOG(DEBUG, \"AVP host mbuf address at 0x%\" PRIx64 \"\\n\",\n+\t\t    host_info->mbuf_phys);\n+\tavp->req_q = avp_dev_translate_address(eth_dev, host_info->req_phys);\n+\tavp->resp_q = avp_dev_translate_address(eth_dev, host_info->resp_phys);\n+\tavp->sync_addr =\n+\t\tavp_dev_translate_address(eth_dev, host_info->sync_phys);\n+\tavp->mbuf_addr =\n+\t\tavp_dev_translate_address(eth_dev, host_info->mbuf_phys);\n+\n+\t/*\n+\t * store the host mbuf virtual address so that we can calculate\n+\t * relative offsets for each mbuf as they are processed\n+\t */\n+\tavp->host_mbuf_addr = host_info->mbuf_va;\n+\tavp->host_sync_addr = host_info->sync_va;\n+\n+\t/*\n+\t * store the maximum packet length that is supported by the host.\n+\t */\n+\tavp->max_rx_pkt_len = host_info->max_rx_pkt_len;\n+\tPMD_DRV_LOG(DEBUG, \"AVP host max receive packet length is %u\\n\",\n+\t\t\t\thost_info->max_rx_pkt_len);\n+\n+\treturn 0;\n+}\n+\n+/*\n  * This function is based on probe() function in avp_pci.c\n  * It returns 0 on success.\n  */\n@@ -164,6 +867,7 @@ struct avp_adapter {\n \tstruct avp_dev *avp =\n \t\tAVP_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private);\n \tstruct rte_pci_device *pci_dev;\n+\tint ret;\n \n \tpci_dev = AVP_DEV_TO_PCI(eth_dev);\n \n@@ -181,6 +885,34 @@ struct avp_adapter {\n \n \teth_dev->data->dev_flags |= RTE_ETH_DEV_DETACHABLE;\n \n+\t/* Check current migration status */\n+\tif (avp_dev_migration_pending(eth_dev)) {\n+\t\tPMD_DRV_LOG(ERR, \"VM live migration operation in progress\\n\");\n+\t\treturn -EBUSY;\n+\t}\n+\n+\t/* Check BAR resources */\n+\tret = avp_dev_check_regions(eth_dev);\n+\tif (ret < 0) {\n+\t\tPMD_DRV_LOG(ERR, \"Failed to validate BAR resources, ret=%d\\n\",\n+\t\t\t    ret);\n+\t\treturn ret;\n+\t}\n+\n+\t/* Enable interrupts */\n+\tret = avp_dev_setup_interrupts(eth_dev);\n+\tif (ret < 0) {\n+\t\tPMD_DRV_LOG(ERR, \"Failed to enable interrupts, ret=%d\\n\", ret);\n+\t\treturn ret;\n+\t}\n+\n+\t/* Handle each subtype */\n+\tret = avp_dev_create(pci_dev, eth_dev);\n+\tif (ret < 0) {\n+\t\tPMD_DRV_LOG(ERR, \"Failed to create device, ret=%d\\n\", ret);\n+\t\treturn ret;\n+\t}\n+\n \t/* Allocate memory for storing MAC addresses */\n \teth_dev->data->mac_addrs = rte_zmalloc(\"avp_ethdev\", ETHER_ADDR_LEN, 0);\n \tif (eth_dev->data->mac_addrs == NULL) {\n@@ -189,6 +921,7 @@ struct avp_adapter {\n \t\treturn -ENOMEM;\n \t}\n \n+\t/* Get a mac from device config */\n \tether_addr_copy(&avp->ethaddr, &eth_dev->data->mac_addrs[0]);\n \n \treturn 0;\n",
    "prefixes": [
        "dpdk-dev",
        "v3",
        "08/16"
    ]
}