From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-wr0-f196.google.com (mail-wr0-f196.google.com [209.85.128.196]) by dpdk.org (Postfix) with ESMTP id B04032BE1 for ; Wed, 23 May 2018 14:11:46 +0200 (CEST) Received: by mail-wr0-f196.google.com with SMTP id u12-v6so7041266wrn.8 for ; Wed, 23 May 2018 05:11:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=HEhV1fGNLPDZf0yV2RbefNZMMJa/0h8tPZ4zq2YxQYo=; b=gr3e3sWGdi/BDXRxAvsTJXrd2WYQFwFqLFIDRgta8LWMf7sAeZgEke3ZSFkYJzQqB8 tpE0Zq1+RdfClSvKLdsWhvoBYTDQzhDSPha0DQ+lmIHCNVh6xeBEfbhxUb8uQWGbeMxz j6foiRwp7Ja06HRmM64OCU1Ea8NCHZrLlPivQa6Cn3JVpByY+u4gCcE9cvBxZDYoWaIJ T8YX2BqoPLbPJfTGMBKC+IiKKtiq7txBkTlFn+MsR7263J/aXPlUedqmqcAYR/CAd8Cx jOHxCblF7FgaHOkwDahpOC82X2+b131YipwSh0Ss3EdDerTtg1R4/8Cr6sX5bezW0yyO MP0g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=HEhV1fGNLPDZf0yV2RbefNZMMJa/0h8tPZ4zq2YxQYo=; b=XSHVbW/6q+7fSL2dYGvk4JAUQZE8lJyOeT5MdjzIxFxwIcP085FxPJOOisPSFSMbNX 44++weOK/9e42cb05UnGN/DwUbSMN+3SqjkGxnu+Pn9Za9nrs/Iz6bJ6GyUwwjHMFxlu aj4mpvMXzDivPEexL2QpndH5xpBLFldhXqsbcCjipvq1L9ZUYNpyfUmDNOkhdPvAZ9QN ZmwsPwJNejBR8wHCyyehH35cGOM7ve/k0w80w7A0k9+AvO9ehATo/GfykttbmHyS0ONX KIKOKTQNaQsMqN59G/+o1BVOdFLHBq4Fris0ewkvrklWjxa8Dfjoqcm16Qab/9gR+IY6 00SQ== X-Gm-Message-State: ALKqPwfg0rrZXtRjeYRE6iF2r6zTkp1r3rZm/RJHySChRMGLLoWGispf ZibDDWASgaMRDMMxfIwCEVY= X-Google-Smtp-Source: AB8JxZrVLgo93Eqd9cXu622Ef1xEUYDnZVSOtcgwXbAzhDtSbwIU/tBECUiuCdqybTHTAgFvvyXb3A== X-Received: by 2002:adf:e8c3:: with SMTP id k3-v6mr1971671wrn.182.1527077506334; Wed, 23 May 2018 05:11:46 -0700 (PDT) Received: from localhost ([2a00:23c5:be9a:5200:ce4c:82c0:d567:ecbb]) by smtp.gmail.com with ESMTPSA id h12-v6sm3574613wmc.7.2018.05.23.05.11.45 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Wed, 23 May 2018 05:11:45 -0700 (PDT) From: luca.boccassi@gmail.com To: Ajit Khaparde Cc: Qingmin Liu , Somnath Kotur , dpdk stable Date: Wed, 23 May 2018 13:10:07 +0100 Message-Id: <20180523121010.8385-56-luca.boccassi@gmail.com> X-Mailer: git-send-email 2.14.2 In-Reply-To: <20180523121010.8385-1-luca.boccassi@gmail.com> References: <20180516101323.2234-2-luca.boccassi@gmail.com> <20180523121010.8385-1-luca.boccassi@gmail.com> Subject: [dpdk-stable] patch 'net/bnxt: use first completion ring for fwd and async event' has been queued to stable release 18.02.2 X-BeenThere: stable@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: patches for DPDK stable branches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 23 May 2018 12:11:46 -0000 Hi, FYI, your patch has been queued to stable release 18.02.2 Note it hasn't been pushed to http://dpdk.org/browse/dpdk-stable yet. It will be pushed if I get no objections before 05/25/18. So please shout if anyone has objections. Thanks. Luca Boccassi --- >>From 4a7aec6135f302ead8277a948b3f0dd63722f254 Mon Sep 17 00:00:00 2001 From: Ajit Khaparde Date: Tue, 22 May 2018 11:13:44 -0700 Subject: [PATCH] net/bnxt: use first completion ring for fwd and async event [ upstream commit 2b947bd294ffce2d980d092683de82269abe3676 ] In order to save completion resource, use the first completion ring from PF or VF as the default completion ring for async event & HWRM forward response handling. Add bnxt_hwrm_set_async_event_cr() to set async_event_cr for either PF or VF. Fixes: 7bc8e9a227cc ("net/bnxt: support async link notification") Signed-off-by: Qingmin Liu Signed-off-by: Somnath Kotur Signed-off-by: Ajit Khaparde --- drivers/net/bnxt/bnxt_cpr.c | 90 ++++++++++++------------------------------ drivers/net/bnxt/bnxt_cpr.h | 5 +-- drivers/net/bnxt/bnxt_ethdev.c | 20 +--------- drivers/net/bnxt/bnxt_hwrm.c | 19 +++++++-- drivers/net/bnxt/bnxt_hwrm.h | 1 + drivers/net/bnxt/bnxt_irq.c | 28 +++---------- drivers/net/bnxt/bnxt_ring.c | 45 ++++++++++++++------- drivers/net/bnxt/bnxt_rxr.c | 17 ++++++-- 8 files changed, 94 insertions(+), 131 deletions(-) diff --git a/drivers/net/bnxt/bnxt_cpr.c b/drivers/net/bnxt/bnxt_cpr.c index 737bb060a..ced1643c9 100644 --- a/drivers/net/bnxt/bnxt_cpr.c +++ b/drivers/net/bnxt/bnxt_cpr.c @@ -159,69 +159,31 @@ reject: return; } -/* For the default completion ring only */ -int bnxt_alloc_def_cp_ring(struct bnxt *bp) +int bnxt_event_hwrm_resp_handler(struct bnxt *bp, struct cmpl_base *cmp) { - struct bnxt_cp_ring_info *cpr = bp->def_cp_ring; - struct bnxt_ring *cp_ring = cpr->cp_ring_struct; - int rc; - - rc = bnxt_hwrm_ring_alloc(bp, cp_ring, - HWRM_RING_ALLOC_INPUT_RING_TYPE_L2_CMPL, - 0, HWRM_NA_SIGNATURE, - HWRM_NA_SIGNATURE); - if (rc) - goto err_out; - cpr->cp_doorbell = bp->pdev->mem_resource[2].addr; - B_CP_DIS_DB(cpr, cpr->cp_raw_cons); - if (BNXT_PF(bp)) - rc = bnxt_hwrm_func_cfg_def_cp(bp); - else - rc = bnxt_hwrm_vf_func_cfg_def_cp(bp); - -err_out: - return rc; -} - -void bnxt_free_def_cp_ring(struct bnxt *bp) -{ - struct bnxt_cp_ring_info *cpr = bp->def_cp_ring; - - if (cpr == NULL) - return; - - bnxt_free_ring(cpr->cp_ring_struct); - cpr->cp_ring_struct = NULL; - rte_free(cpr->cp_ring_struct); - rte_free(cpr); - bp->def_cp_ring = NULL; -} - -/* For the default completion ring only */ -int bnxt_init_def_ring_struct(struct bnxt *bp, unsigned int socket_id) -{ - struct bnxt_cp_ring_info *cpr; - struct bnxt_ring *ring; - - cpr = rte_zmalloc_socket("cpr", - sizeof(struct bnxt_cp_ring_info), - RTE_CACHE_LINE_SIZE, socket_id); - if (cpr == NULL) - return -ENOMEM; - bp->def_cp_ring = cpr; - - ring = rte_zmalloc_socket("bnxt_cp_ring_struct", - sizeof(struct bnxt_ring), - RTE_CACHE_LINE_SIZE, socket_id); - if (ring == NULL) - return -ENOMEM; - cpr->cp_ring_struct = ring; - ring->bd = (void *)cpr->cp_desc_ring; - ring->bd_dma = cpr->cp_desc_mapping; - ring->ring_size = rte_align32pow2(DEFAULT_CP_RING_SIZE); - ring->ring_mask = ring->ring_size - 1; - ring->vmem_size = 0; - ring->vmem = NULL; - - return 0; + bool evt = 0; + + if (bp == NULL || cmp == NULL) { + PMD_DRV_LOG(ERR, "invalid NULL argument\n"); + return evt; + } + + switch (CMP_TYPE(cmp)) { + case CMPL_BASE_TYPE_HWRM_ASYNC_EVENT: + /* Handle any async event */ + bnxt_handle_async_event(bp, cmp); + evt = 1; + break; + case CMPL_BASE_TYPE_HWRM_FWD_RESP: + /* Handle HWRM forwarded responses */ + bnxt_handle_fwd_req(bp, cmp); + evt = 1; + break; + default: + /* Ignore any other events */ + PMD_DRV_LOG(INFO, "Ignoring %02x completion\n", CMP_TYPE(cmp)); + break; + } + + return evt; } diff --git a/drivers/net/bnxt/bnxt_cpr.h b/drivers/net/bnxt/bnxt_cpr.h index ce2b0cb8a..10216193a 100644 --- a/drivers/net/bnxt/bnxt_cpr.h +++ b/drivers/net/bnxt/bnxt_cpr.h @@ -100,12 +100,9 @@ struct bnxt_cp_ring_info { #define RX_CMP_L2_ERRORS \ (RX_PKT_CMPL_ERRORS_BUFFER_ERROR_MASK | RX_PKT_CMPL_ERRORS_CRC_ERROR) - struct bnxt; -int bnxt_alloc_def_cp_ring(struct bnxt *bp); -void bnxt_free_def_cp_ring(struct bnxt *bp); -int bnxt_init_def_ring_struct(struct bnxt *bp, unsigned int socket_id); void bnxt_handle_async_event(struct bnxt *bp, struct cmpl_base *cmp); void bnxt_handle_fwd_req(struct bnxt *bp, struct cmpl_base *cmp); +int bnxt_event_hwrm_resp_handler(struct bnxt *bp, struct cmpl_base *cmp); #endif diff --git a/drivers/net/bnxt/bnxt_ethdev.c b/drivers/net/bnxt/bnxt_ethdev.c index 58cfbf9c6..6a3572823 100644 --- a/drivers/net/bnxt/bnxt_ethdev.c +++ b/drivers/net/bnxt/bnxt_ethdev.c @@ -168,23 +168,12 @@ static void bnxt_free_mem(struct bnxt *bp) bnxt_free_stats(bp); bnxt_free_tx_rings(bp); bnxt_free_rx_rings(bp); - bnxt_free_def_cp_ring(bp); } static int bnxt_alloc_mem(struct bnxt *bp) { int rc; - /* Default completion ring */ - rc = bnxt_init_def_ring_struct(bp, SOCKET_ID_ANY); - if (rc) - goto alloc_mem_err; - - rc = bnxt_alloc_rings(bp, 0, NULL, NULL, - bp->def_cp_ring, "def_cp"); - if (rc) - goto alloc_mem_err; - rc = bnxt_alloc_vnic_mem(bp); if (rc) goto alloc_mem_err; @@ -518,11 +507,11 @@ static int bnxt_dev_configure_op(struct rte_eth_dev *eth_dev) /* Inherit new configurations */ if (eth_dev->data->nb_rx_queues > bp->max_rx_rings || eth_dev->data->nb_tx_queues > bp->max_tx_rings || - eth_dev->data->nb_rx_queues + eth_dev->data->nb_tx_queues + 1 > + eth_dev->data->nb_rx_queues + eth_dev->data->nb_tx_queues > bp->max_cp_rings || eth_dev->data->nb_rx_queues + eth_dev->data->nb_tx_queues > bp->max_stat_ctx || - (uint32_t)(eth_dev->data->nb_rx_queues + 1) > bp->max_ring_grps) { + (uint32_t)(eth_dev->data->nb_rx_queues) > bp->max_ring_grps) { PMD_DRV_LOG(ERR, "Insufficient resources to support requested config\n"); PMD_DRV_LOG(ERR, @@ -3365,10 +3354,6 @@ skip_init: if (rc) goto error_free_int; - rc = bnxt_alloc_def_cp_ring(bp); - if (rc) - goto error_free_int; - bnxt_enable_int(bp); bnxt_init_nic(bp); @@ -3376,7 +3361,6 @@ skip_init: error_free_int: bnxt_disable_int(bp); - bnxt_free_def_cp_ring(bp); bnxt_hwrm_func_buf_unrgtr(bp); bnxt_free_int(bp); bnxt_free_mem(bp); diff --git a/drivers/net/bnxt/bnxt_hwrm.c b/drivers/net/bnxt/bnxt_hwrm.c index ea40e4961..f5358a44f 100644 --- a/drivers/net/bnxt/bnxt_hwrm.c +++ b/drivers/net/bnxt/bnxt_hwrm.c @@ -1759,7 +1759,7 @@ int bnxt_free_all_hwrm_rings(struct bnxt *bp) struct bnxt_tx_ring_info *txr = txq->tx_ring; struct bnxt_ring *ring = txr->tx_ring_struct; struct bnxt_cp_ring_info *cpr = txq->cp_ring; - unsigned int idx = bp->rx_cp_nr_rings + i + 1; + unsigned int idx = bp->rx_cp_nr_rings + i; if (ring->fw_ring_id != INVALID_HW_RING_ID) { bnxt_hwrm_ring_free(bp, ring, @@ -1785,13 +1785,12 @@ int bnxt_free_all_hwrm_rings(struct bnxt *bp) struct bnxt_rx_ring_info *rxr = rxq->rx_ring; struct bnxt_ring *ring = rxr->rx_ring_struct; struct bnxt_cp_ring_info *cpr = rxq->cp_ring; - unsigned int idx = i + 1; if (ring->fw_ring_id != INVALID_HW_RING_ID) { bnxt_hwrm_ring_free(bp, ring, HWRM_RING_FREE_INPUT_RING_TYPE_RX); ring->fw_ring_id = INVALID_HW_RING_ID; - bp->grp_info[idx].rx_fw_ring_id = INVALID_HW_RING_ID; + bp->grp_info[i].rx_fw_ring_id = INVALID_HW_RING_ID; memset(rxr->rx_desc_ring, 0, rxr->rx_ring_struct->ring_size * sizeof(*rxr->rx_desc_ring)); @@ -1812,7 +1811,7 @@ int bnxt_free_all_hwrm_rings(struct bnxt *bp) bp->grp_info[i].ag_fw_ring_id = INVALID_HW_RING_ID; } if (cpr->cp_ring_struct->fw_ring_id != INVALID_HW_RING_ID) { - bnxt_free_cp_ring(bp, cpr, idx); + bnxt_free_cp_ring(bp, cpr, i); bp->grp_info[i].cp_fw_ring_id = INVALID_HW_RING_ID; cpr->cp_ring_struct->fw_ring_id = INVALID_HW_RING_ID; } @@ -2922,6 +2921,18 @@ int bnxt_hwrm_set_vf_vlan(struct bnxt *bp, int vf) return rc; } +int bnxt_hwrm_set_async_event_cr(struct bnxt *bp) +{ + int rc; + + if (BNXT_PF(bp)) + rc = bnxt_hwrm_func_cfg_def_cp(bp); + else + rc = bnxt_hwrm_vf_func_cfg_def_cp(bp); + + return rc; +} + int bnxt_hwrm_reject_fwd_resp(struct bnxt *bp, uint16_t target_id, void *encaped, size_t ec_size) { diff --git a/drivers/net/bnxt/bnxt_hwrm.h b/drivers/net/bnxt/bnxt_hwrm.h index f11e72a35..2a667c88a 100644 --- a/drivers/net/bnxt/bnxt_hwrm.h +++ b/drivers/net/bnxt/bnxt_hwrm.h @@ -88,6 +88,7 @@ int bnxt_hwrm_vf_func_cfg_def_cp(struct bnxt *bp); int bnxt_hwrm_queue_qportcfg(struct bnxt *bp); +int bnxt_hwrm_set_async_event_cr(struct bnxt *bp); int bnxt_hwrm_ring_alloc(struct bnxt *bp, struct bnxt_ring *ring, uint32_t ring_type, uint32_t map_index, diff --git a/drivers/net/bnxt/bnxt_irq.c b/drivers/net/bnxt/bnxt_irq.c index 8ab986936..3510120ed 100644 --- a/drivers/net/bnxt/bnxt_irq.c +++ b/drivers/net/bnxt/bnxt_irq.c @@ -68,30 +68,10 @@ static void bnxt_int_handler(void *param) if (!CMP_VALID(cmp, raw_cons, cpr->cp_ring_struct)) break; - switch (CMP_TYPE(cmp)) { - case CMPL_BASE_TYPE_HWRM_ASYNC_EVENT: - /* Handle any async event */ - bnxt_handle_async_event(bp, cmp); - break; - case CMPL_BASE_TYPE_HWRM_FWD_REQ: - /* Handle HWRM forwarded responses */ - bnxt_handle_fwd_req(bp, cmp); - break; - default: - /* Ignore any other events */ - if (cmp->type & rte_cpu_to_le_16(0x01)) { - if (!CMP_VALID(cmp, raw_cons, - cpr->cp_ring_struct)) - goto no_more; - } - PMD_DRV_LOG(INFO, - "Ignoring %02x completion\n", CMP_TYPE(cmp)); - break; - } + bnxt_event_hwrm_resp_handler(bp, cmp); raw_cons = NEXT_RAW_CMP(raw_cons); - }; -no_more: + cpr->cp_raw_cons = raw_cons; B_CP_DB_REARM(cpr, cpr->cp_raw_cons); } @@ -127,7 +107,9 @@ void bnxt_enable_int(struct bnxt *bp) { struct bnxt_cp_ring_info *cpr = bp->def_cp_ring; - B_CP_DB_ARM(cpr); + /* Only the default completion ring */ + if (cpr != NULL && cpr->cp_doorbell != NULL) + B_CP_DB_ARM(cpr); } int bnxt_setup_int(struct bnxt *bp) diff --git a/drivers/net/bnxt/bnxt_ring.c b/drivers/net/bnxt/bnxt_ring.c index 75c0830fe..c0b844d4f 100644 --- a/drivers/net/bnxt/bnxt_ring.c +++ b/drivers/net/bnxt/bnxt_ring.c @@ -297,33 +297,50 @@ int bnxt_alloc_hwrm_rings(struct bnxt *bp) struct bnxt_ring *cp_ring = cpr->cp_ring_struct; struct bnxt_rx_ring_info *rxr = rxq->rx_ring; struct bnxt_ring *ring = rxr->rx_ring_struct; - unsigned int idx = i + 1; - unsigned int map_idx = idx + bp->rx_cp_nr_rings; + unsigned int map_idx = i + bp->rx_cp_nr_rings; bp->grp_info[i].fw_stats_ctx = cpr->hw_stats_ctx_id; /* Rx cmpl */ - rc = bnxt_hwrm_ring_alloc(bp, cp_ring, - HWRM_RING_ALLOC_INPUT_RING_TYPE_L2_CMPL, - idx, HWRM_NA_SIGNATURE, - HWRM_NA_SIGNATURE); + rc = bnxt_hwrm_ring_alloc + (bp, + cp_ring, + HWRM_RING_ALLOC_INPUT_RING_TYPE_L2_CMPL, + i, + HWRM_NA_SIGNATURE, + HWRM_NA_SIGNATURE); if (rc) goto err_out; cpr->cp_doorbell = (char *)pci_dev->mem_resource[2].addr + - idx * 0x80; + i * 0x80; bp->grp_info[i].cp_fw_ring_id = cp_ring->fw_ring_id; B_CP_DIS_DB(cpr, cpr->cp_raw_cons); + if (!i) { + /* + * In order to save completion resource, use the first + * completion ring from PF or VF as the default + * completion ring for async event & HWRM + * forward response handling. + */ + bp->def_cp_ring = cpr; + rc = bnxt_hwrm_set_async_event_cr(bp); + if (rc) + goto err_out; + } + /* Rx ring */ - rc = bnxt_hwrm_ring_alloc(bp, ring, - HWRM_RING_ALLOC_INPUT_RING_TYPE_RX, - idx, cpr->hw_stats_ctx_id, - cp_ring->fw_ring_id); + rc = bnxt_hwrm_ring_alloc(bp, + ring, + HWRM_RING_ALLOC_INPUT_RING_TYPE_RX, + i, + cpr->hw_stats_ctx_id, + cp_ring->fw_ring_id); if (rc) goto err_out; rxr->rx_prod = 0; rxr->rx_doorbell = (char *)pci_dev->mem_resource[2].addr + - idx * 0x80; + i * 0x80; bp->grp_info[i].rx_fw_ring_id = ring->fw_ring_id; B_RX_DB(rxr->rx_doorbell, rxr->rx_prod); @@ -357,7 +374,7 @@ int bnxt_alloc_hwrm_rings(struct bnxt *bp) } B_RX_DB(rxr->rx_doorbell, rxr->rx_prod); B_RX_DB(rxr->ag_doorbell, rxr->ag_prod); - rxq->index = idx; + rxq->index = i; } for (i = 0; i < bp->tx_cp_nr_rings; i++) { @@ -366,7 +383,7 @@ int bnxt_alloc_hwrm_rings(struct bnxt *bp) struct bnxt_ring *cp_ring = cpr->cp_ring_struct; struct bnxt_tx_ring_info *txr = txq->tx_ring; struct bnxt_ring *ring = txr->tx_ring_struct; - unsigned int idx = i + 1 + bp->rx_cp_nr_rings; + unsigned int idx = i + bp->rx_cp_nr_rings; /* Tx cmpl */ rc = bnxt_hwrm_ring_alloc(bp, cp_ring, diff --git a/drivers/net/bnxt/bnxt_rxr.c b/drivers/net/bnxt/bnxt_rxr.c index 829a95f9f..de6719122 100644 --- a/drivers/net/bnxt/bnxt_rxr.c +++ b/drivers/net/bnxt/bnxt_rxr.c @@ -562,6 +562,7 @@ uint16_t bnxt_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t prod = rxr->rx_prod; uint16_t ag_prod = rxr->ag_prod; int rc = 0; + bool evt = false; /* If Rx Q was stopped return */ if (rxq->rx_deferred_start) @@ -586,14 +587,19 @@ uint16_t bnxt_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, nb_rx_pkts++; if (rc == -EBUSY) /* partial completion */ break; + } else { + evt = + bnxt_event_hwrm_resp_handler(rxq->bp, + (struct cmpl_base *)rxcmp); } + raw_cons = NEXT_RAW_CMP(raw_cons); - if (nb_rx_pkts == nb_pkts) + if (nb_rx_pkts == nb_pkts || evt) break; } cpr->cp_raw_cons = raw_cons; - if (prod == rxr->rx_prod && ag_prod == rxr->ag_prod) { + if ((prod == rxr->rx_prod && ag_prod == rxr->ag_prod) && !evt) { /* * For PMD, there is no need to keep on pushing to REARM * the doorbell if there are no new completions @@ -602,9 +608,12 @@ uint16_t bnxt_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, } B_CP_DIS_DB(cpr, cpr->cp_raw_cons); - B_RX_DB(rxr->rx_doorbell, rxr->rx_prod); + if (prod != rxr->rx_prod) + B_RX_DB(rxr->rx_doorbell, rxr->rx_prod); + /* Ring the AGG ring DB */ - B_RX_DB(rxr->ag_doorbell, rxr->ag_prod); + if (ag_prod != rxr->ag_prod) + B_RX_DB(rxr->ag_doorbell, rxr->ag_prod); /* Attempt to alloc Rx buf in case of a previous allocation failure. */ if (rc == -ENOMEM) { -- 2.14.2