Commit 89bddde3 authored by David S. Miller's avatar David S. Miller

Merge branch 'gve-dqo'

Bailey Forrest says:

====================
gve: Introduce DQO descriptor format

DQO is the descriptor format for our next generation virtual NIC. The existing
descriptor format will be referred to as "GQI" in the patch set.

One major change with DQO is it uses dual descriptor rings for both TX and RX
queues.

The TX path uses a TX queue to send descriptors to HW, and receives packet
completion events on a TX completion queue.

The RX path posts buffers to HW using an RX buffer queue and receives incoming
packets on an RX queue.

One important note is that DQO descriptors and doorbells are little endian. We
continue to use the existing big endian control plane infrastructure.

The general format of the patch series is:
- Refactor existing code/data structures to be shared by DQO
- Expand admin queues to support DQO device setup
- Expand data structures and device setup to support DQO
- Add logic to setup DQO queues
- Implement datapath
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 47889068 9b8dd5e5
......@@ -47,13 +47,24 @@ The driver interacts with the device in the following ways:
- Transmit and Receive Queues
- See description below
Descriptor Formats
------------------
GVE supports two descriptor formats: GQI and DQO. These two formats have
entirely different descriptors, which will be described below.
Registers
---------
All registers are MMIO and big endian.
All registers are MMIO.
The registers are used for initializing and configuring the device as well as
querying device status in response to management interrupts.
Endianness
----------
- Admin Queue messages and registers are all Big Endian.
- GQI descriptors and datapath registers are Big Endian.
- DQO descriptors and datapath registers are Little Endian.
Admin Queue (AQ)
----------------
The Admin Queue is a PAGE_SIZE memory block, treated as an array of AQ
......@@ -97,10 +108,10 @@ the queues associated with that interrupt.
The handler for these irqs schedule the napi for that block to run
and poll the queues.
Traffic Queues
--------------
gVNIC's queues are composed of a descriptor ring and a buffer and are
assigned to a notification block.
GQI Traffic Queues
------------------
GQI queues are composed of a descriptor ring and a buffer and are assigned to a
notification block.
The descriptor rings are power-of-two-sized ring buffers consisting of
fixed-size descriptors. They advance their head pointer using a __be32
......@@ -121,3 +132,35 @@ Receive
The buffers for receive rings are put into a data ring that is the same
length as the descriptor ring and the head and tail pointers advance over
the rings together.
DQO Traffic Queues
------------------
- Every TX and RX queue is assigned a notification block.
- TX and RX buffers queues, which send descriptors to the device, use MMIO
doorbells to notify the device of new descriptors.
- RX and TX completion queues, which receive descriptors from the device, use a
"generation bit" to know when a descriptor was populated by the device. The
driver initializes all bits with the "current generation". The device will
populate received descriptors with the "next generation" which is inverted
from the current generation. When the ring wraps, the current/next generation
are swapped.
- It's the driver's responsibility to ensure that the RX and TX completion
queues are not overrun. This can be accomplished by limiting the number of
descriptors posted to HW.
- TX packets have a 16 bit completion_tag and RX buffers have a 16 bit
buffer_id. These will be returned on the TX completion and RX queues
respectively to let the driver know which packet/buffer was completed.
Transmit
~~~~~~~~
A packet's buffers are DMA mapped for the device to access before transmission.
After the packet was successfully transmitted, the buffers are unmapped.
Receive
~~~~~~~
The driver posts fixed sized buffers to HW on the RX buffer queue. The packet
received on the associated RX queue may span multiple descriptors.
......@@ -17,7 +17,7 @@ if NET_VENDOR_GOOGLE
config GVE
tristate "Google Virtual NIC (gVNIC) support"
depends on PCI_MSI
depends on (PCI_MSI && (X86 || CPU_LITTLE_ENDIAN))
help
This driver supports Google Virtual NIC (gVNIC)"
......
# Makefile for the Google virtual Ethernet (gve) driver
obj-$(CONFIG_GVE) += gve.o
gve-objs := gve_main.o gve_tx.o gve_rx.o gve_ethtool.o gve_adminq.o
gve-objs := gve_main.o gve_tx.o gve_tx_dqo.o gve_rx.o gve_rx_dqo.o gve_ethtool.o gve_adminq.o gve_utils.o
This diff is collapsed.
/* SPDX-License-Identifier: (GPL-2.0 OR MIT)
* Google virtual Ethernet (gve) driver
*
* Copyright (C) 2015-2019 Google, Inc.
* Copyright (C) 2015-2021 Google, Inc.
*/
#ifndef _GVE_ADMINQ_H
......@@ -22,7 +22,8 @@ enum gve_adminq_opcodes {
GVE_ADMINQ_DECONFIGURE_DEVICE_RESOURCES = 0x9,
GVE_ADMINQ_SET_DRIVER_PARAMETER = 0xB,
GVE_ADMINQ_REPORT_STATS = 0xC,
GVE_ADMINQ_REPORT_LINK_SPEED = 0xD
GVE_ADMINQ_REPORT_LINK_SPEED = 0xD,
GVE_ADMINQ_GET_PTYPE_MAP = 0xE,
};
/* Admin queue status codes */
......@@ -82,14 +83,54 @@ static_assert(sizeof(struct gve_device_descriptor) == 40);
struct gve_device_option {
__be16 option_id;
__be16 option_length;
__be32 feat_mask;
__be32 required_features_mask;
};
static_assert(sizeof(struct gve_device_option) == 8);
#define GVE_DEV_OPT_ID_RAW_ADDRESSING 0x1
#define GVE_DEV_OPT_LEN_RAW_ADDRESSING 0x0
#define GVE_DEV_OPT_FEAT_MASK_RAW_ADDRESSING 0x0
struct gve_device_option_gqi_rda {
__be32 supported_features_mask;
};
static_assert(sizeof(struct gve_device_option_gqi_rda) == 4);
struct gve_device_option_gqi_qpl {
__be32 supported_features_mask;
};
static_assert(sizeof(struct gve_device_option_gqi_qpl) == 4);
struct gve_device_option_dqo_rda {
__be32 supported_features_mask;
__be16 tx_comp_ring_entries;
__be16 rx_buff_ring_entries;
};
static_assert(sizeof(struct gve_device_option_dqo_rda) == 8);
/* Terminology:
*
* RDA - Raw DMA Addressing - Buffers associated with SKBs are directly DMA
* mapped and read/updated by the device.
*
* QPL - Queue Page Lists - Driver uses bounce buffers which are DMA mapped with
* the device for read/write and data is copied from/to SKBs.
*/
enum gve_dev_opt_id {
GVE_DEV_OPT_ID_GQI_RAW_ADDRESSING = 0x1,
GVE_DEV_OPT_ID_GQI_RDA = 0x2,
GVE_DEV_OPT_ID_GQI_QPL = 0x3,
GVE_DEV_OPT_ID_DQO_RDA = 0x4,
};
enum gve_dev_opt_req_feat_mask {
GVE_DEV_OPT_REQ_FEAT_MASK_GQI_RAW_ADDRESSING = 0x0,
GVE_DEV_OPT_REQ_FEAT_MASK_GQI_RDA = 0x0,
GVE_DEV_OPT_REQ_FEAT_MASK_GQI_QPL = 0x0,
GVE_DEV_OPT_REQ_FEAT_MASK_DQO_RDA = 0x0,
};
#define GVE_DEV_OPT_LEN_GQI_RAW_ADDRESSING 0x0
struct gve_adminq_configure_device_resources {
__be64 counter_array;
......@@ -98,9 +139,11 @@ struct gve_adminq_configure_device_resources {
__be32 num_irq_dbs;
__be32 irq_db_stride;
__be32 ntfy_blk_msix_base_idx;
u8 queue_format;
u8 padding[7];
};
static_assert(sizeof(struct gve_adminq_configure_device_resources) == 32);
static_assert(sizeof(struct gve_adminq_configure_device_resources) == 40);
struct gve_adminq_register_page_list {
__be32 page_list_id;
......@@ -125,9 +168,13 @@ struct gve_adminq_create_tx_queue {
__be64 tx_ring_addr;
__be32 queue_page_list_id;
__be32 ntfy_id;
__be64 tx_comp_ring_addr;
__be16 tx_ring_size;
__be16 tx_comp_ring_size;
u8 padding[4];
};
static_assert(sizeof(struct gve_adminq_create_tx_queue) == 32);
static_assert(sizeof(struct gve_adminq_create_tx_queue) == 48);
struct gve_adminq_create_rx_queue {
__be32 queue_id;
......@@ -138,10 +185,14 @@ struct gve_adminq_create_rx_queue {
__be64 rx_desc_ring_addr;
__be64 rx_data_ring_addr;
__be32 queue_page_list_id;
u8 padding[4];
__be16 rx_ring_size;
__be16 packet_buffer_size;
__be16 rx_buff_ring_size;
u8 enable_rsc;
u8 padding[5];
};
static_assert(sizeof(struct gve_adminq_create_rx_queue) == 48);
static_assert(sizeof(struct gve_adminq_create_rx_queue) == 56);
/* Queue resources that are shared with the device */
struct gve_queue_resources {
......@@ -226,6 +277,41 @@ enum gve_stat_names {
RX_DROPS_INVALID_CHECKSUM = 68,
};
enum gve_l3_type {
/* Must be zero so zero initialized LUT is unknown. */
GVE_L3_TYPE_UNKNOWN = 0,
GVE_L3_TYPE_OTHER,
GVE_L3_TYPE_IPV4,
GVE_L3_TYPE_IPV6,
};
enum gve_l4_type {
/* Must be zero so zero initialized LUT is unknown. */
GVE_L4_TYPE_UNKNOWN = 0,
GVE_L4_TYPE_OTHER,
GVE_L4_TYPE_TCP,
GVE_L4_TYPE_UDP,
GVE_L4_TYPE_ICMP,
GVE_L4_TYPE_SCTP,
};
/* These are control path types for PTYPE which are the same as the data path
* types.
*/
struct gve_ptype_entry {
u8 l3_type;
u8 l4_type;
};
struct gve_ptype_map {
struct gve_ptype_entry ptypes[1 << 10]; /* PTYPES are always 10 bits. */
};
struct gve_adminq_get_ptype_map {
__be64 ptype_map_len;
__be64 ptype_map_addr;
};
union gve_adminq_command {
struct {
__be32 opcode;
......@@ -243,6 +329,7 @@ union gve_adminq_command {
struct gve_adminq_set_driver_parameter set_driver_param;
struct gve_adminq_report_stats report_stats;
struct gve_adminq_report_link_speed report_link_speed;
struct gve_adminq_get_ptype_map get_ptype_map;
};
};
u8 reserved[64];
......@@ -271,4 +358,9 @@ int gve_adminq_set_mtu(struct gve_priv *priv, u64 mtu);
int gve_adminq_report_stats(struct gve_priv *priv, u64 stats_report_len,
dma_addr_t stats_report_addr, u64 interval);
int gve_adminq_report_link_speed(struct gve_priv *priv);
struct gve_ptype_lut;
int gve_adminq_get_ptype_map_dqo(struct gve_priv *priv,
struct gve_ptype_lut *ptype_lut);
#endif /* _GVE_ADMINQ_H */
/* SPDX-License-Identifier: (GPL-2.0 OR MIT)
* Google virtual Ethernet (gve) driver
*
* Copyright (C) 2015-2021 Google, Inc.
*/
/* GVE DQO Descriptor formats */
#ifndef _GVE_DESC_DQO_H_
#define _GVE_DESC_DQO_H_
#include <linux/build_bug.h>
#define GVE_TX_MAX_HDR_SIZE_DQO 255
#define GVE_TX_MIN_TSO_MSS_DQO 88
#ifndef __LITTLE_ENDIAN_BITFIELD
#error "Only little endian supported"
#endif
/* Basic TX descriptor (DTYPE 0x0C) */
struct gve_tx_pkt_desc_dqo {
__le64 buf_addr;
/* Must be GVE_TX_PKT_DESC_DTYPE_DQO (0xc) */
u8 dtype: 5;
/* Denotes the last descriptor of a packet. */
u8 end_of_packet: 1;
u8 checksum_offload_enable: 1;
/* If set, will generate a descriptor completion for this descriptor. */
u8 report_event: 1;
u8 reserved0;
__le16 reserved1;
/* The TX completion associated with this packet will contain this tag.
*/
__le16 compl_tag;
u16 buf_size: 14;
u16 reserved2: 2;
} __packed;
static_assert(sizeof(struct gve_tx_pkt_desc_dqo) == 16);
#define GVE_TX_PKT_DESC_DTYPE_DQO 0xc
#define GVE_TX_MAX_BUF_SIZE_DQO ((16 * 1024) - 1)
/* Maximum number of data descriptors allowed per packet, or per-TSO segment. */
#define GVE_TX_MAX_DATA_DESCS 10
/* Min gap between tail and head to avoid cacheline overlap */
#define GVE_TX_MIN_DESC_PREVENT_CACHE_OVERLAP 4
/* "report_event" on TX packet descriptors may only be reported on the last
* descriptor of a TX packet, and they must be spaced apart with at least this
* value.
*/
#define GVE_TX_MIN_RE_INTERVAL 32
struct gve_tx_context_cmd_dtype {
u8 dtype: 5;
u8 tso: 1;
u8 reserved1: 2;
u8 reserved2;
};
static_assert(sizeof(struct gve_tx_context_cmd_dtype) == 2);
/* TX Native TSO Context DTYPE (0x05)
*
* "flex" fields allow the driver to send additional packet context to HW.
*/
struct gve_tx_tso_context_desc_dqo {
/* The L4 payload bytes that should be segmented. */
u32 tso_total_len: 24;
u32 flex10: 8;
/* Max segment size in TSO excluding headers. */
u16 mss: 14;
u16 reserved: 2;
u8 header_len; /* Header length to use for TSO offload */
u8 flex11;
struct gve_tx_context_cmd_dtype cmd_dtype;
u8 flex0;
u8 flex5;
u8 flex6;
u8 flex7;
u8 flex8;
u8 flex9;
} __packed;
static_assert(sizeof(struct gve_tx_tso_context_desc_dqo) == 16);
#define GVE_TX_TSO_CTX_DESC_DTYPE_DQO 0x5
/* General context descriptor for sending metadata. */
struct gve_tx_general_context_desc_dqo {
u8 flex4;
u8 flex5;
u8 flex6;
u8 flex7;
u8 flex8;
u8 flex9;
u8 flex10;
u8 flex11;
struct gve_tx_context_cmd_dtype cmd_dtype;
u16 reserved;
u8 flex0;
u8 flex1;
u8 flex2;
u8 flex3;
} __packed;
static_assert(sizeof(struct gve_tx_general_context_desc_dqo) == 16);
#define GVE_TX_GENERAL_CTX_DESC_DTYPE_DQO 0x4
/* Logical structure of metadata which is packed into context descriptor flex
* fields.
*/
struct gve_tx_metadata_dqo {
union {
struct {
u8 version;
/* If `skb->l4_hash` is set, this value should be
* derived from `skb->hash`.
*
* A zero value means no l4_hash was associated with the
* skb.
*/
u16 path_hash: 15;
/* Should be set to 1 if the flow associated with the
* skb had a rehash from the TCP stack.
*/
u16 rehash_event: 1;
} __packed;
u8 bytes[12];
};
} __packed;
static_assert(sizeof(struct gve_tx_metadata_dqo) == 12);
#define GVE_TX_METADATA_VERSION_DQO 0
/* TX completion descriptor */
struct gve_tx_compl_desc {
/* For types 0-4 this is the TX queue ID associated with this
* completion.
*/
u16 id: 11;
/* See: GVE_COMPL_TYPE_DQO* */
u16 type: 3;
u16 reserved0: 1;
/* Flipped by HW to notify the descriptor is populated. */
u16 generation: 1;
union {
/* For descriptor completions, this is the last index fetched
* by HW + 1.
*/
__le16 tx_head;
/* For packet completions, this is the completion tag set on the
* TX packet descriptors.
*/
__le16 completion_tag;
};
__le32 reserved1;
} __packed;
static_assert(sizeof(struct gve_tx_compl_desc) == 8);
#define GVE_COMPL_TYPE_DQO_PKT 0x2 /* Packet completion */
#define GVE_COMPL_TYPE_DQO_DESC 0x4 /* Descriptor completion */
#define GVE_COMPL_TYPE_DQO_MISS 0x1 /* Miss path completion */
#define GVE_COMPL_TYPE_DQO_REINJECTION 0x3 /* Re-injection completion */
/* Descriptor to post buffers to HW on buffer queue. */
struct gve_rx_desc_dqo {
__le16 buf_id; /* ID returned in Rx completion descriptor */
__le16 reserved0;
__le32 reserved1;
__le64 buf_addr; /* DMA address of the buffer */
__le64 header_buf_addr;
__le64 reserved2;
} __packed;
static_assert(sizeof(struct gve_rx_desc_dqo) == 32);
/* Descriptor for HW to notify SW of new packets received on RX queue. */
struct gve_rx_compl_desc_dqo {
/* Must be 1 */
u8 rxdid: 4;
u8 reserved0: 4;
/* Packet originated from this system rather than the network. */
u8 loopback: 1;
/* Set when IPv6 packet contains a destination options header or routing
* header.
*/
u8 ipv6_ex_add: 1;
/* Invalid packet was received. */
u8 rx_error: 1;
u8 reserved1: 5;
u16 packet_type: 10;
u16 ip_hdr_err: 1;
u16 udp_len_err: 1;
u16 raw_cs_invalid: 1;
u16 reserved2: 3;
u16 packet_len: 14;
/* Flipped by HW to notify the descriptor is populated. */
u16 generation: 1;
/* Should be zero. */
u16 buffer_queue_id: 1;
u16 header_len: 10;
u16 rsc: 1;
u16 split_header: 1;
u16 reserved3: 4;
u8 descriptor_done: 1;
u8 end_of_packet: 1;
u8 header_buffer_overflow: 1;
u8 l3_l4_processed: 1;
u8 csum_ip_err: 1;
u8 csum_l4_err: 1;
u8 csum_external_ip_err: 1;
u8 csum_external_udp_err: 1;
u8 status_error1;
__le16 reserved5;
__le16 buf_id; /* Buffer ID which was sent on the buffer queue. */
union {
/* Packet checksum. */
__le16 raw_cs;
/* Segment length for RSC packets. */
__le16 rsc_seg_len;
};
__le32 hash;
__le32 reserved6;
__le64 reserved7;
} __packed;
static_assert(sizeof(struct gve_rx_compl_desc_dqo) == 32);
/* Ringing the doorbell too often can hurt performance.
*
* HW requires this value to be at least 8.
*/
#define GVE_RX_BUF_THRESH_DQO 32
#endif /* _GVE_DESC_DQO_H_ */
/* SPDX-License-Identifier: (GPL-2.0 OR MIT)
* Google virtual Ethernet (gve) driver
*
* Copyright (C) 2015-2021 Google, Inc.
*/
#ifndef _GVE_DQO_H_
#define _GVE_DQO_H_
#include "gve_adminq.h"
#define GVE_ITR_ENABLE_BIT_DQO BIT(0)
#define GVE_ITR_CLEAR_PBA_BIT_DQO BIT(1)
#define GVE_ITR_NO_UPDATE_DQO (3 << 3)
#define GVE_ITR_INTERVAL_DQO_SHIFT 5
#define GVE_ITR_INTERVAL_DQO_MASK ((1 << 12) - 1)
#define GVE_TX_IRQ_RATELIMIT_US_DQO 50
#define GVE_RX_IRQ_RATELIMIT_US_DQO 20
/* Timeout in seconds to wait for a reinjection completion after receiving
* its corresponding miss completion.
*/
#define GVE_REINJECT_COMPL_TIMEOUT 1
/* Timeout in seconds to deallocate the completion tag for a packet that was
* prematurely freed for not receiving a valid completion. This should be large
* enough to rule out the possibility of receiving the corresponding valid
* completion after this interval.
*/
#define GVE_DEALLOCATE_COMPL_TIMEOUT 60
netdev_tx_t gve_tx_dqo(struct sk_buff *skb, struct net_device *dev);
bool gve_tx_poll_dqo(struct gve_notify_block *block, bool do_clean);
int gve_rx_poll_dqo(struct gve_notify_block *block, int budget);
int gve_tx_alloc_rings_dqo(struct gve_priv *priv);
void gve_tx_free_rings_dqo(struct gve_priv *priv);
int gve_rx_alloc_rings_dqo(struct gve_priv *priv);
void gve_rx_free_rings_dqo(struct gve_priv *priv);
int gve_clean_tx_done_dqo(struct gve_priv *priv, struct gve_tx_ring *tx,
struct napi_struct *napi);
void gve_rx_post_buffers_dqo(struct gve_rx_ring *rx);
void gve_rx_write_doorbell_dqo(const struct gve_priv *priv, int queue_idx);
static inline void
gve_tx_put_doorbell_dqo(const struct gve_priv *priv,
const struct gve_queue_resources *q_resources, u32 val)
{
u64 index;
index = be32_to_cpu(q_resources->db_index);
iowrite32(val, &priv->db_bar2[index]);
}
/* Builds register value to write to DQO IRQ doorbell to enable with specified
* ratelimit.
*/
static inline u32 gve_set_itr_ratelimit_dqo(u32 ratelimit_us)
{
u32 result = GVE_ITR_ENABLE_BIT_DQO;
/* Interval has 2us granularity. */
ratelimit_us >>= 1;
ratelimit_us &= GVE_ITR_INTERVAL_DQO_MASK;
result |= (ratelimit_us << GVE_ITR_INTERVAL_DQO_SHIFT);
return result;
}
static inline void
gve_write_irq_doorbell_dqo(const struct gve_priv *priv,
const struct gve_notify_block *block, u32 val)
{
u32 index = be32_to_cpu(block->irq_db_index);
iowrite32(val, &priv->db_bar2[index]);
}
#endif /* _GVE_DQO_H_ */
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
/* Google virtual Ethernet (gve) driver
*
* Copyright (C) 2015-2019 Google, Inc.
* Copyright (C) 2015-2021 Google, Inc.
*/
#include <linux/ethtool.h>
......@@ -311,8 +311,16 @@ gve_get_ethtool_stats(struct net_device *netdev,
for (ring = 0; ring < priv->tx_cfg.num_queues; ring++) {
struct gve_tx_ring *tx = &priv->tx[ring];
data[i++] = tx->req;
data[i++] = tx->done;
if (gve_is_gqi(priv)) {
data[i++] = tx->req;
data[i++] = tx->done;
} else {
/* DQO doesn't currently support
* posted/completed descriptor counts;
*/
data[i++] = 0;
data[i++] = 0;
}
do {
start =
u64_stats_fetch_begin(&priv->tx[ring].statss);
......@@ -453,11 +461,16 @@ static int gve_set_tunable(struct net_device *netdev,
switch (etuna->id) {
case ETHTOOL_RX_COPYBREAK:
{
u32 max_copybreak = gve_is_gqi(priv) ?
(PAGE_SIZE / 2) : priv->data_buffer_size_dqo;
len = *(u32 *)value;
if (len > PAGE_SIZE / 2)
if (len > max_copybreak)
return -EINVAL;
priv->rx_copybreak = len;
return 0;
}
default:
return -EOPNOTSUPP;
}
......
This diff is collapsed.
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
/* Google virtual Ethernet (gve) driver
*
* Copyright (C) 2015-2019 Google, Inc.
* Copyright (C) 2015-2021 Google, Inc.
*/
#include "gve.h"
#include "gve_adminq.h"
#include "gve_utils.h"
#include <linux/etherdevice.h>
static void gve_rx_remove_from_block(struct gve_priv *priv, int queue_idx)
{
struct gve_notify_block *block =
&priv->ntfy_blocks[gve_rx_idx_to_ntfy(priv, queue_idx)];
block->rx = NULL;
}
static void gve_rx_free_buffer(struct device *dev,
struct gve_rx_slot_page_info *page_info,
union gve_rx_data_slot *data_slot)
......@@ -137,16 +130,6 @@ static int gve_prefill_rx_pages(struct gve_rx_ring *rx)
return err;
}
static void gve_rx_add_to_block(struct gve_priv *priv, int queue_idx)
{
u32 ntfy_idx = gve_rx_idx_to_ntfy(priv, queue_idx);
struct gve_notify_block *block = &priv->ntfy_blocks[ntfy_idx];
struct gve_rx_ring *rx = &priv->rx[queue_idx];
block->rx = rx;
rx->ntfy_id = ntfy_idx;
}
static int gve_rx_alloc_ring(struct gve_priv *priv, int idx)
{
struct gve_rx_ring *rx = &priv->rx[idx];
......@@ -165,7 +148,7 @@ static int gve_rx_alloc_ring(struct gve_priv *priv, int idx)
slots = priv->rx_data_slot_cnt;
rx->mask = slots - 1;
rx->data.raw_addressing = priv->raw_addressing;
rx->data.raw_addressing = priv->queue_format == GVE_GQI_RDA_FORMAT;
/* alloc rx data ring */
bytes = sizeof(*rx->data.data_ring) * slots;
......@@ -255,7 +238,7 @@ int gve_rx_alloc_rings(struct gve_priv *priv)
return err;
}
void gve_rx_free_rings(struct gve_priv *priv)
void gve_rx_free_rings_gqi(struct gve_priv *priv)
{
int i;
......@@ -279,27 +262,6 @@ static enum pkt_hash_types gve_rss_type(__be16 pkt_flags)
return PKT_HASH_TYPE_L2;
}
static struct sk_buff *gve_rx_copy(struct net_device *dev,
struct napi_struct *napi,
struct gve_rx_slot_page_info *page_info,
u16 len)
{
struct sk_buff *skb = napi_alloc_skb(napi, len);
void *va = page_info->page_address + GVE_RX_PAD +
(page_info->page_offset ? PAGE_SIZE / 2 : 0);
if (unlikely(!skb))
return NULL;
__skb_put(skb, len);
skb_copy_to_linear_data(skb, va, len);
skb->protocol = eth_type_trans(skb, dev);
return skb;
}
static struct sk_buff *gve_rx_add_frags(struct napi_struct *napi,
struct gve_rx_slot_page_info *page_info,
u16 len)
......@@ -310,7 +272,7 @@ static struct sk_buff *gve_rx_add_frags(struct napi_struct *napi,
return NULL;
skb_add_rx_frag(skb, 0, page_info->page,
(page_info->page_offset ? PAGE_SIZE / 2 : 0) +
page_info->page_offset +
GVE_RX_PAD, len, PAGE_SIZE / 2);
return skb;
......@@ -321,7 +283,7 @@ static void gve_rx_flip_buff(struct gve_rx_slot_page_info *page_info, __be64 *sl
const __be64 offset = cpu_to_be64(PAGE_SIZE / 2);
/* "flip" to other packet buffer on this page */
page_info->page_offset ^= 0x1;
page_info->page_offset ^= PAGE_SIZE / 2;
*(slot_addr) ^= offset;
}
......@@ -388,7 +350,7 @@ gve_rx_qpl(struct device *dev, struct net_device *netdev,
gve_rx_flip_buff(page_info, &data_slot->qpl_offset);
}
} else {
skb = gve_rx_copy(netdev, napi, page_info, len);
skb = gve_rx_copy(netdev, napi, page_info, len, GVE_RX_PAD);
if (skb) {
u64_stats_update_begin(&rx->statss);
rx->rx_copied_pkt++;
......@@ -430,7 +392,7 @@ static bool gve_rx(struct gve_rx_ring *rx, struct gve_rx_desc *rx_desc,
if (len <= priv->rx_copybreak) {
/* Just copy small packets */
skb = gve_rx_copy(dev, napi, page_info, len);
skb = gve_rx_copy(dev, napi, page_info, len, GVE_RX_PAD);
u64_stats_update_begin(&rx->statss);
rx->rx_copied_pkt++;
rx->rx_copybreak_pkt++;
......
This diff is collapsed.
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
/* Google virtual Ethernet (gve) driver
*
* Copyright (C) 2015-2019 Google, Inc.
* Copyright (C) 2015-2021 Google, Inc.
*/
#include "gve.h"
#include "gve_adminq.h"
#include "gve_utils.h"
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/vmalloc.h>
......@@ -131,14 +132,6 @@ static void gve_tx_free_fifo(struct gve_tx_fifo *fifo, size_t bytes)
atomic_add(bytes, &fifo->available);
}
static void gve_tx_remove_from_block(struct gve_priv *priv, int queue_idx)
{
struct gve_notify_block *block =
&priv->ntfy_blocks[gve_tx_idx_to_ntfy(priv, queue_idx)];
block->tx = NULL;
}
static int gve_clean_tx_done(struct gve_priv *priv, struct gve_tx_ring *tx,
u32 to_do, bool try_to_wake);
......@@ -174,16 +167,6 @@ static void gve_tx_free_ring(struct gve_priv *priv, int idx)
netif_dbg(priv, drv, priv->dev, "freed tx queue %d\n", idx);
}
static void gve_tx_add_to_block(struct gve_priv *priv, int queue_idx)
{
int ntfy_idx = gve_tx_idx_to_ntfy(priv, queue_idx);
struct gve_notify_block *block = &priv->ntfy_blocks[ntfy_idx];
struct gve_tx_ring *tx = &priv->tx[queue_idx];
block->tx = tx;
tx->ntfy_id = ntfy_idx;
}
static int gve_tx_alloc_ring(struct gve_priv *priv, int idx)
{
struct gve_tx_ring *tx = &priv->tx[idx];
......@@ -208,7 +191,7 @@ static int gve_tx_alloc_ring(struct gve_priv *priv, int idx)
if (!tx->desc)
goto abort_with_info;
tx->raw_addressing = priv->raw_addressing;
tx->raw_addressing = priv->queue_format == GVE_GQI_RDA_FORMAT;
tx->dev = &priv->pdev->dev;
if (!tx->raw_addressing) {
tx->tx_fifo.qpl = gve_assign_tx_qpl(priv);
......@@ -273,7 +256,7 @@ int gve_tx_alloc_rings(struct gve_priv *priv)
return err;
}
void gve_tx_free_rings(struct gve_priv *priv)
void gve_tx_free_rings_gqi(struct gve_priv *priv)
{
int i;
......
This diff is collapsed.
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
/* Google virtual Ethernet (gve) driver
*
* Copyright (C) 2015-2021 Google, Inc.
*/
#include "gve.h"
#include "gve_adminq.h"
#include "gve_utils.h"
void gve_tx_remove_from_block(struct gve_priv *priv, int queue_idx)
{
struct gve_notify_block *block =
&priv->ntfy_blocks[gve_tx_idx_to_ntfy(priv, queue_idx)];
block->tx = NULL;
}
void gve_tx_add_to_block(struct gve_priv *priv, int queue_idx)
{
int ntfy_idx = gve_tx_idx_to_ntfy(priv, queue_idx);
struct gve_notify_block *block = &priv->ntfy_blocks[ntfy_idx];
struct gve_tx_ring *tx = &priv->tx[queue_idx];
block->tx = tx;
tx->ntfy_id = ntfy_idx;
}
void gve_rx_remove_from_block(struct gve_priv *priv, int queue_idx)
{
struct gve_notify_block *block =
&priv->ntfy_blocks[gve_rx_idx_to_ntfy(priv, queue_idx)];
block->rx = NULL;
}
void gve_rx_add_to_block(struct gve_priv *priv, int queue_idx)
{
u32 ntfy_idx = gve_rx_idx_to_ntfy(priv, queue_idx);
struct gve_notify_block *block = &priv->ntfy_blocks[ntfy_idx];
struct gve_rx_ring *rx = &priv->rx[queue_idx];
block->rx = rx;
rx->ntfy_id = ntfy_idx;
}
struct sk_buff *gve_rx_copy(struct net_device *dev, struct napi_struct *napi,
struct gve_rx_slot_page_info *page_info, u16 len,
u16 pad)
{
struct sk_buff *skb = napi_alloc_skb(napi, len);
void *va = page_info->page_address + pad +
page_info->page_offset;
if (unlikely(!skb))
return NULL;
__skb_put(skb, len);
skb_copy_to_linear_data(skb, va, len);
skb->protocol = eth_type_trans(skb, dev);
return skb;
}
void gve_dec_pagecnt_bias(struct gve_rx_slot_page_info *page_info)
{
page_info->pagecnt_bias--;
if (page_info->pagecnt_bias == 0) {
int pagecount = page_count(page_info->page);
/* If we have run out of bias - set it back up to INT_MAX
* minus the existing refs.
*/
page_info->pagecnt_bias = INT_MAX - pagecount;
/* Set pagecount back up to max. */
page_ref_add(page_info->page, INT_MAX - pagecount);
}
}
/* SPDX-License-Identifier: (GPL-2.0 OR MIT)
* Google virtual Ethernet (gve) driver
*
* Copyright (C) 2015-2021 Google, Inc.
*/
#ifndef _GVE_UTILS_H
#define _GVE_UTILS_H
#include <linux/etherdevice.h>
#include "gve.h"
void gve_tx_remove_from_block(struct gve_priv *priv, int queue_idx);
void gve_tx_add_to_block(struct gve_priv *priv, int queue_idx);
void gve_rx_remove_from_block(struct gve_priv *priv, int queue_idx);
void gve_rx_add_to_block(struct gve_priv *priv, int queue_idx);
struct sk_buff *gve_rx_copy(struct net_device *dev, struct napi_struct *napi,
struct gve_rx_slot_page_info *page_info, u16 len,
u16 pad);
/* Decrement pagecnt_bias. Set it back to INT_MAX if it reached zero. */
void gve_dec_pagecnt_bias(struct gve_rx_slot_page_info *page_info);
#endif /* _GVE_UTILS_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment