Commit f7eeb076 authored by HardenedBSD Sync Service's avatar HardenedBSD Sync Service
Browse files

Merge branch 'freebsd/current/main' into hardened/current/master

parents 2b4fa286 f72926ea
......@@ -5,7 +5,7 @@
#
# PROVIDE: lockd
# REQUIRE: nfsclient nfsd rpcbind statd
# REQUIRE: nfsclient rpcbind statd
# BEFORE: DAEMON
# KEYWORD: nojail shutdown
......
......@@ -4,7 +4,7 @@
#
# PROVIDE: mountd
# REQUIRE: NETWORKING rpcbind quota
# REQUIRE: NETWORKING rpcbind quota mountlate
# KEYWORD: nojail shutdown
. /etc/rc.subr
......
......@@ -5,7 +5,7 @@
#
# PROVIDE: statd
# REQUIRE: nfsclient nfsd rpcbind
# REQUIRE: nfsclient rpcbind
# BEFORE: DAEMON
# KEYWORD: nojail shutdown
......
......@@ -71,6 +71,11 @@ is advertised by the device via the Admin Queue), a dedicated MSI-X
interrupt vector per Tx/Rx queue pair, and CPU cacheline optimized
data placement.
.Pp
When RSS is enabled, each Tx/Rx queue pair is bound to a corresponding
CPU core and its NUMA domain. The order of those bindings is based on
the RSS bucket mapping. For builds with RSS support disabled, the
CPU and NUMA management is left to the kernel.
.Pp
The
.Nm
driver supports industry standard TCP/IP offload features such
......@@ -413,12 +418,12 @@ passed to queue 0 and there will be no hash information.
.It ena%d: Failed to configure the device mode. Fallback to host mode policy.
.It ena%d: unable to allocate LLQ bar resource. Fallback to host mode policy.
.Pp
Error occured during Low-latency Queue mode setup.
Error occurred during Low-latency Queue mode setup.
.br
The device will work, but without the LLQ performance gain.
.It ena%d: failed to enable write combining.
.Pp
Error occured while setting the Write Combining mode, required for the LLQ.
Error occurred while setting the Write Combining mode, required for the LLQ.
.It ena%d: failed to tear down irq: %d
.It ena%d: dev has no parent while releasing res for irq: %d
Release of the interrupts failed.
......@@ -431,7 +436,7 @@ Requested MTU value is not supported and will not be set.
.It ena%d: Failed to set MTU to %d
.Pp
This message appears when either MTU change feature is not supported, or device
communication error has occured.
communication error has occurred.
.It ena%d: Keep alive watchdog timeout.
.Pp
Device stopped responding and will be reset.
......@@ -440,7 +445,7 @@ Device stopped responding and will be reset.
Packet was pushed to the NIC but not sent within given time limit.
.br
It may be caused by hang of the IO queue.
.It ena%d: The number of lost tx completion is aboce the threshold (%d > %d). Reset the device
.It ena%d: The number of lost tx completion is above the threshold (%d > %d). Reset the device
.Pp
If too many Tx weren't completed on time the device is going to be reset.
.br
......@@ -458,7 +463,7 @@ Reset task has been triggered, but the driver did not request it.
Device reset will not be performed.
.It ena%d: Device reset failed
.Pp
Error occured while trying to reset the device.
Error occurred while trying to reset the device.
.It ena%d: Cannot initialize device
.It ena%d: Error, mac address are different
.It ena%d: Error, device max mtu is smaller than ifp MTU
......@@ -467,7 +472,7 @@ Error occured while trying to reset the device.
.It ena%d: Failed to create I/O queues
.It ena%d: Reset attempt failed. Can not reset the device
.Pp
Error occured while trying to restore the device after reset.
Error occurred while trying to restore the device after reset.
.It ena%d: Device reset completed successfully, Driver info: %s
.Pp
Device has been correctly restored after reset and is ready to use.
......@@ -497,12 +502,12 @@ If happened during initialization of the IO queue, the interface will not be
brought up.
.It ena%d: NULL mbuf in rx_info
.Pp
Error occured while assembling mbuf from descriptors.
Error occurred while assembling mbuf from descriptors.
.It ena%d: tx_info doesn't have valid mbuf
.It ena%d: Invalid req_id: %hu
.It ena%d: failed to prepare tx bufs
.Pp
Error occured while preparing a packet for transmission.
Error occurred while preparing a packet for transmission.
.It ena%d: ioctl promisc/allmulti
.Pp
IOCTL request for the device to work in promiscuous/allmulti mode.
......@@ -515,7 +520,7 @@ for more details.
If an issue is identified with the released source code with a supported
adapter, please email the specific information related to the issue to
.Aq Mt mk@semihalf.com ,
.Aq Mt ar@semihalf.com
.Aq Mt dgr@semihalf.com
and
.Aq Mt mw@semihalf.com .
.Sh SEE ALSO
......
......@@ -42,6 +42,7 @@ __FBSDID("$FreeBSD$");
#include <sys/bus.h>
#include <sys/condvar.h>
#include <sys/domainset.h>
#include <sys/endian.h>
#include <sys/kernel.h>
#include <sys/kthread.h>
......@@ -170,6 +171,8 @@ static inline long PTR_ERR(const void *ptr)
#define ENA_COM_TIMER_EXPIRED ETIMEDOUT
#define ENA_COM_EIO EIO
#define ENA_NODE_ANY (-1)
#define ENA_MSLEEP(x) pause_sbt("ena", SBT_1MS * (x), SBT_1MS, 0)
#define ENA_USLEEP(x) pause_sbt("ena", SBT_1US * (x), SBT_1US, 0)
#define ENA_UDELAY(x) DELAY(x)
......@@ -277,7 +280,7 @@ typedef struct ifnet ena_netdev;
void ena_dmamap_callback(void *arg, bus_dma_segment_t *segs, int nseg,
int error);
int ena_dma_alloc(device_t dmadev, bus_size_t size, ena_mem_handle_t *dma,
int mapflags, bus_size_t alignment);
int mapflags, bus_size_t alignment, int domain);
static inline uint32_t
ena_reg_read32(struct ena_bus *bus, bus_size_t offset)
......@@ -299,16 +302,27 @@ ena_reg_read32(struct ena_bus *bus, bus_size_t offset)
} while (0)
#define ENA_MEM_ALLOC(dmadev, size) malloc(size, M_DEVBUF, M_NOWAIT | M_ZERO)
#define ENA_MEM_ALLOC_NODE(dmadev, size, virt, node, dev_node) (virt = NULL)
#define ENA_MEM_ALLOC_NODE(dmadev, size, virt, node, dev_node) \
do { \
(virt) = malloc_domainset((size), M_DEVBUF, \
(node) < 0 ? DOMAINSET_RR() : DOMAINSET_PREF(node), \
M_NOWAIT | M_ZERO); \
(void)(dev_node); \
} while (0)
#define ENA_MEM_FREE(dmadev, ptr, size) \
do { \
(void)(size); \
free(ptr, M_DEVBUF); \
} while (0)
#define ENA_MEM_ALLOC_COHERENT_NODE_ALIGNED(dmadev, size, virt, phys, \
handle, node, dev_node, alignment) \
dma, node, dev_node, alignment) \
do { \
((virt) = NULL); \
ena_dma_alloc((dmadev), (size), &(dma), 0, (alignment), \
(node)); \
(virt) = (void *)(dma).vaddr; \
(phys) = (dma).paddr; \
(void)(dev_node); \
} while (0)
......@@ -320,7 +334,8 @@ ena_reg_read32(struct ena_bus *bus, bus_size_t offset)
#define ENA_MEM_ALLOC_COHERENT_ALIGNED(dmadev, size, virt, phys, dma, \
alignment) \
do { \
ena_dma_alloc((dmadev), (size), &(dma), 0, alignment); \
ena_dma_alloc((dmadev), (size), &(dma), 0, (alignment), \
ENA_NODE_ANY); \
(virt) = (void *)(dma).vaddr; \
(phys) = (dma).paddr; \
} while (0)
......@@ -366,7 +381,6 @@ ena_reg_read32(struct ena_bus *bus, bus_size_t offset)
#define time_after(a,b) ((long)((unsigned long)(b) - (unsigned long)(a)) < 0)
#define VLAN_HLEN sizeof(struct ether_vlan_header)
#define CSUM_OFFLOAD (CSUM_IP|CSUM_TCP|CSUM_UDP)
#define prefetch(x) (void)(x)
#define prefetchw(x) (void)(x)
......
......@@ -198,7 +198,7 @@ ena_dmamap_callback(void *arg, bus_dma_segment_t *segs, int nseg, int error)
int
ena_dma_alloc(device_t dmadev, bus_size_t size,
ena_mem_handle_t *dma, int mapflags, bus_size_t alignment)
ena_mem_handle_t *dma, int mapflags, bus_size_t alignment, int domain)
{
struct ena_adapter* adapter = device_get_softc(dmadev);
device_t pdev = adapter->pdev;
......@@ -229,6 +229,13 @@ ena_dma_alloc(device_t dmadev, bus_size_t size,
goto fail_tag;
}
error = bus_dma_tag_set_domain(dma->tag, domain);
if (unlikely(error != 0)) {
ena_log(pdev, ERR, "bus_dma_tag_set_domain failed: %d\n",
error);
goto fail_map_create;
}
error = bus_dmamem_alloc(dma->tag, (void**) &dma->vaddr,
BUS_DMA_COHERENT | BUS_DMA_ZERO, &dma->map);
if (unlikely(error != 0)) {
......@@ -1445,6 +1452,8 @@ ena_create_io_queues(struct ena_adapter *adapter)
ctx.queue_size = adapter->requested_tx_ring_size;
ctx.msix_vector = msix_vector;
ctx.qid = ena_qid;
ctx.numa_node = adapter->que[i].domain;
rc = ena_com_create_io_queue(ena_dev, &ctx);
if (rc != 0) {
ena_log(adapter->pdev, ERR,
......@@ -1462,6 +1471,11 @@ ena_create_io_queues(struct ena_adapter *adapter)
ena_com_destroy_io_queue(ena_dev, ena_qid);
goto err_tx;
}
if (ctx.numa_node >= 0) {
ena_com_update_numa_node(ring->ena_com_io_cq,
ctx.numa_node);
}
}
/* Create RX queues */
......@@ -1473,6 +1487,8 @@ ena_create_io_queues(struct ena_adapter *adapter)
ctx.queue_size = adapter->requested_rx_ring_size;
ctx.msix_vector = msix_vector;
ctx.qid = ena_qid;
ctx.numa_node = adapter->que[i].domain;
rc = ena_com_create_io_queue(ena_dev, &ctx);
if (unlikely(rc != 0)) {
ena_log(adapter->pdev, ERR,
......@@ -1491,6 +1507,11 @@ ena_create_io_queues(struct ena_adapter *adapter)
ena_com_destroy_io_queue(ena_dev, ena_qid);
goto err_rx;
}
if (ctx.numa_node >= 0) {
ena_com_update_numa_node(ring->ena_com_io_cq,
ctx.numa_node);
}
}
for (i = 0; i < adapter->num_io_queues; i++) {
......@@ -1646,12 +1667,22 @@ ena_setup_io_intr(struct ena_adapter *adapter)
#ifdef RSS
int num_buckets = rss_getnumbuckets();
static int last_bind = 0;
int cur_bind;
int idx;
#endif
int irq_idx;
if (adapter->msix_entries == NULL)
return (EINVAL);
#ifdef RSS
if (adapter->first_bind < 0) {
adapter->first_bind = last_bind;
last_bind = (last_bind + adapter->num_io_queues) % num_buckets;
}
cur_bind = adapter->first_bind;
#endif
for (int i = 0; i < adapter->num_io_queues; i++) {
irq_idx = ENA_IO_IRQ_IDX(i);
......@@ -1666,9 +1697,17 @@ ena_setup_io_intr(struct ena_adapter *adapter)
#ifdef RSS
adapter->que[i].cpu = adapter->irq_tbl[irq_idx].cpu =
rss_getcpu(last_bind);
last_bind = (last_bind + 1) % num_buckets;
rss_getcpu(cur_bind);
cur_bind = (cur_bind + 1) % num_buckets;
CPU_SETOF(adapter->que[i].cpu, &adapter->que[i].cpu_mask);
for (idx = 0; idx < MAXMEMDOM; ++idx) {
if (CPU_ISSET(adapter->que[i].cpu, &cpuset_domain[idx]))
break;
}
adapter->que[i].domain = idx;
#else
adapter->que[i].domain = -1;
#endif
}
......@@ -2062,6 +2101,13 @@ ena_up(struct ena_adapter *adapter)
ena_log(adapter->pdev, INFO, "device is going UP\n");
/*
* ena_timer_service can use functions, which write to the admin queue.
* Those calls are not protected by ENA_LOCK, and because of that, the
* timer should be stopped when bringing the device up or down.
*/
ENA_TIMER_DRAIN(adapter);
/* setup interrupts for IO queues */
rc = ena_setup_io_intr(adapter);
if (unlikely(rc != 0)) {
......@@ -2104,19 +2150,12 @@ ena_up(struct ena_adapter *adapter)
if_setdrvflagbits(adapter->ifp, IFF_DRV_RUNNING,
IFF_DRV_OACTIVE);
/* Activate timer service only if the device is running.
* If this flag is not set, it means that the driver is being
* reset and timer service will be activated afterwards.
*/
if (ENA_FLAG_ISSET(ENA_FLAG_DEVICE_RUNNING, adapter)) {
callout_reset_sbt(&adapter->timer_service, SBT_1S,
SBT_1S, ena_timer_service, (void *)adapter, 0);
}
ENA_FLAG_SET_ATOMIC(ENA_FLAG_DEV_UP, adapter);
ena_unmask_all_io_irqs(adapter);
ENA_TIMER_RESET(adapter);
return (0);
err_up_complete:
......@@ -2126,6 +2165,8 @@ ena_up(struct ena_adapter *adapter)
err_create_queues_with_backoff:
ena_free_io_irq(adapter);
error:
ENA_TIMER_RESET(adapter);
return (rc);
}
......@@ -2430,9 +2471,10 @@ ena_down(struct ena_adapter *adapter)
if (!ENA_FLAG_ISSET(ENA_FLAG_DEV_UP, adapter))
return;
ena_log(adapter->pdev, INFO, "device is going DOWN\n");
/* Drain timer service to avoid admin queue race condition. */
ENA_TIMER_DRAIN(adapter);
callout_drain(&adapter->timer_service);
ena_log(adapter->pdev, INFO, "device is going DOWN\n");
ENA_FLAG_CLEAR_ATOMIC(ENA_FLAG_DEV_UP, adapter);
if_setdrvflagbits(adapter->ifp, IFF_DRV_OACTIVE,
......@@ -2456,6 +2498,8 @@ ena_down(struct ena_adapter *adapter)
ena_free_all_rx_resources(adapter);
counter_u64_add(adapter->dev_stats.interface_down, 1);
ENA_TIMER_RESET(adapter);
}
static uint32_t
......@@ -3210,8 +3254,10 @@ ena_timer_service(void *data)
adapter->eni_metrics_sample_interval)) {
/*
* There is no race with other admin queue calls, as:
* - Timer service runs after interface is up, so all
* - Timer service runs after attach function ends, so all
* configuration calls to the admin queue are finished.
* - Timer service is temporarily stopped when bringing
* the interface up or down.
* - After interface is up, the driver doesn't use (at least
* for now) other functions writing to the admin queue.
*
......@@ -3232,6 +3278,18 @@ ena_timer_service(void *data)
ena_update_host_info(host_info, adapter->ifp);
if (unlikely(ENA_FLAG_ISSET(ENA_FLAG_TRIGGER_RESET, adapter))) {
/*
* Timeout when validating version indicates that the device
* became unresponsive. If that happens skip the reset and
* reschedule timer service, so the reset can be retried later.
*/
if (ena_com_validate_version(adapter->ena_dev) ==
ENA_COM_TIMER_EXPIRED) {
ena_log(adapter->pdev, WARN,
"FW unresponsive, skipping reset\n");
ENA_TIMER_RESET(adapter);
return;
}
ena_log(adapter->pdev, WARN, "Trigger reset is on\n");
taskqueue_enqueue(adapter->reset_tq, &adapter->reset_task);
return;
......@@ -3240,7 +3298,7 @@ ena_timer_service(void *data)
/*
* Schedule another timeout one second from now.
*/
callout_schedule_sbt(&adapter->timer_service, SBT_1S, SBT_1S, 0);
ENA_TIMER_RESET(adapter);
}
void
......@@ -3255,7 +3313,7 @@ ena_destroy_device(struct ena_adapter *adapter, bool graceful)
if_link_state_change(ifp, LINK_STATE_DOWN);
callout_drain(&adapter->timer_service);
ENA_TIMER_DRAIN(adapter);
dev_up = ENA_FLAG_ISSET(ENA_FLAG_DEV_UP, adapter);
if (dev_up)
......@@ -3386,17 +3444,15 @@ ena_restore_device(struct ena_adapter *adapter)
/* Indicate that device is running again and ready to work */
ENA_FLAG_SET_ATOMIC(ENA_FLAG_DEVICE_RUNNING, adapter);
if (ENA_FLAG_ISSET(ENA_FLAG_DEV_UP_BEFORE_RESET, adapter)) {
/*
* As the AENQ handlers weren't executed during reset because
* the flag ENA_FLAG_DEVICE_RUNNING was turned off, the
* timestamp must be updated again That will prevent next reset
* caused by missing keep alive.
*/
adapter->keep_alive_timestamp = getsbinuptime();
callout_reset_sbt(&adapter->timer_service, SBT_1S, SBT_1S,
ena_timer_service, (void *)adapter, 0);
}
/*
* As the AENQ handlers weren't executed during reset because
* the flag ENA_FLAG_DEVICE_RUNNING was turned off, the
* timestamp must be updated again That will prevent next reset
* caused by missing keep alive.
*/
adapter->keep_alive_timestamp = getsbinuptime();
ENA_TIMER_RESET(adapter);
ENA_FLAG_CLEAR_ATOMIC(ENA_FLAG_DEV_UP_BEFORE_RESET, adapter);
ena_log(dev, INFO,
......@@ -3418,6 +3474,8 @@ ena_restore_device(struct ena_adapter *adapter)
ENA_FLAG_CLEAR_ATOMIC(ENA_FLAG_ONGOING_RESET, adapter);
ena_log(dev, ERR, "Reset attempt failed. Can not reset the device\n");
ENA_TIMER_RESET(adapter);
return (rc);
}
......@@ -3459,12 +3517,13 @@ ena_attach(device_t pdev)
adapter = device_get_softc(pdev);
adapter->pdev = pdev;
adapter->first_bind = -1;
/*
* Set up the timer service - driver is responsible for avoiding
* concurrency, as the callout won't be using any locking inside.
*/
callout_init(&adapter->timer_service, true);
ENA_TIMER_INIT(adapter);
adapter->keep_alive_timeout = DEFAULT_KEEP_ALIVE_TO;
adapter->missing_tx_timeout = DEFAULT_TX_CMP_TO;
adapter->missing_tx_max_queues = DEFAULT_TX_MONITORED_QUEUES;
......@@ -3649,6 +3708,9 @@ ena_attach(device_t pdev)
if_setdrvflagbits(adapter->ifp, IFF_DRV_OACTIVE, IFF_DRV_RUNNING);
ENA_FLAG_SET_ATOMIC(ENA_FLAG_DEVICE_RUNNING, adapter);
/* Run the timer service */
ENA_TIMER_RESET(adapter);
return (0);
#ifdef DEV_NETMAP
......@@ -3702,7 +3764,7 @@ ena_detach(device_t pdev)
/* Stop timer service */
ENA_LOCK_LOCK();
callout_drain(&adapter->timer_service);
ENA_TIMER_DRAIN(adapter);
ENA_LOCK_UNLOCK();
/* Release reset task */
......
......@@ -40,8 +40,8 @@
#include "ena-com/ena_eth_com.h"
#define DRV_MODULE_VER_MAJOR 2
#define DRV_MODULE_VER_MINOR 4
#define DRV_MODULE_VER_SUBMINOR 1
#define DRV_MODULE_VER_MINOR 5
#define DRV_MODULE_VER_SUBMINOR 0
#define DRV_MODULE_NAME "ena"
......@@ -222,6 +222,7 @@ struct ena_que {
int cpu;
cpuset_t cpu_mask;
#endif
int domain;
struct sysctl_oid *oid;
};
......@@ -439,6 +440,7 @@ struct ena_adapter {
uint32_t buf_ring_size;
/* RSS*/
int first_bind;
struct ena_indir *rss_indir;
uint8_t mac_addr[ETHER_ADDR_LEN];
......@@ -497,6 +499,14 @@ struct ena_adapter {
#define ENA_LOCK_UNLOCK() sx_unlock(&ena_global_lock)
#define ENA_LOCK_ASSERT() sx_assert(&ena_global_lock, SA_XLOCKED)
#define ENA_TIMER_INIT(_adapter) \
callout_init(&(_adapter)->timer_service, true)
#define ENA_TIMER_DRAIN(_adapter) \
callout_drain(&(_adapter)->timer_service)
#define ENA_TIMER_RESET(_adapter) \
callout_reset_sbt(&(_adapter)->timer_service, SBT_1S, SBT_1S, \
ena_timer_service, (void*)(_adapter), 0)
#define clamp_t(type, _x, min, max) min_t(type, max_t(type, _x, min), max)
#define clamp_val(val, lo, hi) clamp_t(__typeof(val), val, lo, hi)
......
......@@ -40,13 +40,16 @@ __FBSDID("$FreeBSD$");
#include <net/rss_config.h>
#endif /* RSS */
#include <netinet6/ip6_var.h>
/*********************************************************************
* Static functions prototypes
*********************************************************************/
static int ena_tx_cleanup(struct ena_ring *);
static int ena_rx_cleanup(struct ena_ring *);
static inline int validate_tx_req_id(struct ena_ring *, uint16_t);
static inline int ena_get_tx_req_id(struct ena_ring *tx_ring,
struct ena_com_io_cq *io_cq, uint16_t *req_id);
static void ena_rx_hash_mbuf(struct ena_ring *, struct ena_com_rx_ctx *,
struct mbuf *);
static struct mbuf* ena_rx_mbuf(struct ena_ring *, struct ena_com_rx_buf_info *,
......@@ -198,23 +201,27 @@ ena_qflush(if_t ifp)
*********************************************************************/
static inline int
validate_tx_req_id(struct ena_ring *tx_ring, uint16_t req_id)
ena_get_tx_req_id(struct ena_ring *tx_ring, struct ena_com_io_cq *io_cq,
uint16_t *req_id)
{
struct ena_adapter *adapter = tx_ring->adapter;
struct ena_tx_buffer *tx_info = NULL;
int rc;
if (likely(req_id < tx_ring->ring_size)) {
tx_info = &tx_ring->tx_buffer_info[req_id];
if (tx_info->mbuf != NULL)
return (0);
ena_log(adapter->pdev, ERR,
"tx_info doesn't have valid mbuf\n");
rc = ena_com_tx_comp_req_id_get(io_cq, req_id);
if (rc == ENA_COM_TRY_AGAIN)
return (EAGAIN);
if (unlikely(rc != 0)) {
ena_log(adapter->pdev, ERR, "Invalid req_id: %hu\n", *req_id);
counter_u64_add(tx_ring->tx_stats.bad_req_id, 1);
goto err;
}
ena_log(adapter->pdev, ERR, "Invalid req_id: %hu\n", req_id);
counter_u64_add(tx_ring->tx_stats.bad_req_id, 1);
if (tx_ring->tx_buffer_info[*req_id].mbuf != NULL)
return (0);
/* Trigger device reset */
ena_log(adapter->pdev, ERR, "tx_info doesn't have valid mbuf\n");
err:
ena_trigger_reset(adapter, ENA_REGS_RESET_INV_TX_REQ_ID);
return (EFAULT);
......@@ -260,11 +267,7 @@ ena_tx_cleanup(struct ena_ring *tx_ring)
struct ena_tx_buffer *tx_info;
struct mbuf *mbuf;
rc = ena_com_tx_comp_req_id_get(io_cq, &req_id);
if (unlikely(rc != 0))
break;
rc = validate_tx_req_id(tx_ring, req_id);
rc = ena_get_tx_req_id(tx_ring, io_cq, &req_id);
if (unlikely(rc != 0))
break;
......@@ -712,6 +715,7 @@ ena_tx_csum(struct ena_com_tx_ctx *ena_tx_ctx, struct mbuf *mbuf,
uint16_t etype;
int ehdrlen;
struct ip *ip;
int ipproto;
int iphlen;
struct tcphdr *th;
int offset;
......@@ -729,6 +733,9 @@ ena_tx_csum(struct ena_com_tx_ctx *ena_tx_ctx, struct mbuf *mbuf,
if ((mbuf->m_pkthdr.csum_flags & CSUM_OFFLOAD) != 0)
offload = true;
if ((mbuf->m_pkthdr.csum_flags & CSUM6_OFFLOAD) != 0)
offload = true;
if (!offload) {
if (disable_meta_caching) {
memset(ena_meta, 0, sizeof(*ena_meta));
......@@ -750,41 +757,47 @@ ena_tx_csum(struct ena_com_tx_ctx *ena_tx_ctx, struct mbuf *mbuf,
}
mbuf_next = m_getptr(mbuf, ehdrlen, &offset);
ip = (struct ip *)(mtodo(mbuf_next, offset));
iphlen = ip->ip_hl << 2;
mbuf_next = m_getptr(mbuf, iphlen + ehdrlen, &offset);
th = (struct tcphdr *)(mtodo(mbuf_next, offset));
if ((mbuf->m_pkthdr.csum_flags & CSUM_IP) != 0) {
ena_tx_ctx->l3_csum_enable = 1;
}
if ((mbuf->m_pkthdr.csum_flags & CSUM_TSO) != 0) {
ena_tx_ctx->tso_enable = 1;
ena_meta->l4_hdr_len = (th->th_off);
}
switch (etype) {
case ETHERTYPE_IP:
ip = (struct ip *)(mtodo(mbuf_next, offset));
iphlen = ip->ip_hl << 2;
ipproto = ip->ip_p;
ena_tx_ctx->l3_proto = ENA_ETH_IO_L3_PROTO_IPV4;
if ((ip->ip_off & htons(IP_DF)) != 0)
ena_tx_ctx->df = 1;
break;
case ETHERTYPE_IPV6:
ena_tx_ctx->l3_proto = ENA_ETH_IO_L3_PROTO_IPV6;
iphlen = ip6_lasthdr(mbuf, ehdrlen, IPPROTO_IPV6, &ipproto);
iphlen -= ehdrlen;
ena_tx_ctx->df = 1;
break;
default:
iphlen = 0;
ipproto = 0;