/* Repartition PBA for greater than 9k MTU if required */
pba = IGC_PBA_34K;
/* flow control settings * The high water mark must be low enough to fit one full frame * after transmitting the pause frame. As such we must have enough * space to allow for us to complete our current transmit and then * receive the frame that is in progress from the link partner. * Set it to: * - the full Rx FIFO size minus one full Tx plus one full Rx frame
*/
hwm = (pba << 10) - (adapter->max_frame_size + MAX_JUMBO_FRAME_SIZE);
if (!netif_running(adapter->netdev))
igc_power_down_phy_copper_base(&adapter->hw);
/* Enable HW to recognize an 802.1Q VLAN Ethernet packet */
wr32(IGC_VET, ETH_P_8021Q);
/* Re-enable PTP, where applicable. */
igc_ptp_reset(adapter);
/* Re-enable TSN offloading, where applicable. */
igc_tsn_reset(adapter);
igc_get_phy_info(hw);
}
/** * igc_power_up_link - Power up the phy link * @adapter: address of board private structure
*/ staticvoid igc_power_up_link(struct igc_adapter *adapter)
{
igc_reset_phy(&adapter->hw);
igc_power_up_phy_copper(&adapter->hw);
igc_setup_link(&adapter->hw);
}
/** * igc_release_hw_control - release control of the h/w to f/w * @adapter: address of board private structure * * igc_release_hw_control resets CTRL_EXT:DRV_LOAD bit. * For ASF and Pass Through versions of f/w this means that the * driver is no longer loaded.
*/ staticvoid igc_release_hw_control(struct igc_adapter *adapter)
{ struct igc_hw *hw = &adapter->hw;
u32 ctrl_ext;
if (!pci_device_is_present(adapter->pdev)) return;
/* Let firmware take over control of h/w */
ctrl_ext = rd32(IGC_CTRL_EXT);
wr32(IGC_CTRL_EXT,
ctrl_ext & ~IGC_CTRL_EXT_DRV_LOAD);
}
/** * igc_get_hw_control - get control of the h/w from f/w * @adapter: address of board private structure * * igc_get_hw_control sets CTRL_EXT:DRV_LOAD bit. * For ASF and Pass Through versions of f/w this means that * the driver is loaded.
*/ staticvoid igc_get_hw_control(struct igc_adapter *adapter)
{ struct igc_hw *hw = &adapter->hw;
u32 ctrl_ext;
/* Let firmware know the driver has taken over */
ctrl_ext = rd32(IGC_CTRL_EXT);
wr32(IGC_CTRL_EXT,
ctrl_ext | IGC_CTRL_EXT_DRV_LOAD);
}
/** * igc_clean_tx_ring - Free Tx Buffers * @tx_ring: ring to be cleaned
*/ staticvoid igc_clean_tx_ring(struct igc_ring *tx_ring)
{
u16 i = tx_ring->next_to_clean; struct igc_tx_buffer *tx_buffer = &tx_ring->tx_buffer_info[i];
u32 xsk_frames = 0;
while (i != tx_ring->next_to_use) { union igc_adv_tx_desc *eop_desc, *tx_desc;
switch (tx_buffer->type) { case IGC_TX_BUFFER_TYPE_XSK:
xsk_frames++; break; case IGC_TX_BUFFER_TYPE_XDP:
xdp_return_frame(tx_buffer->xdpf);
igc_unmap_tx_buffer(tx_ring->dev, tx_buffer); break; case IGC_TX_BUFFER_TYPE_SKB:
dev_kfree_skb_any(tx_buffer->skb);
igc_unmap_tx_buffer(tx_ring->dev, tx_buffer); break; default:
netdev_warn_once(tx_ring->netdev, "Unknown Tx buffer type\n"); break;
}
/* check for eop_desc to determine the end of the packet */
eop_desc = tx_buffer->next_to_watch;
tx_desc = IGC_TX_DESC(tx_ring, i);
/* unmap remaining buffers */ while (tx_desc != eop_desc) {
tx_buffer++;
tx_desc++;
i++; if (unlikely(i == tx_ring->count)) {
i = 0;
tx_buffer = tx_ring->tx_buffer_info;
tx_desc = IGC_TX_DESC(tx_ring, 0);
}
/* unmap any remaining paged data */ if (dma_unmap_len(tx_buffer, len))
igc_unmap_tx_buffer(tx_ring->dev, tx_buffer);
}
tx_buffer->next_to_watch = NULL;
/* move us one more past the eop_desc for start of next pkt */
tx_buffer++;
i++; if (unlikely(i == tx_ring->count)) {
i = 0;
tx_buffer = tx_ring->tx_buffer_info;
}
}
if (tx_ring->xsk_pool && xsk_frames)
xsk_tx_completed(tx_ring->xsk_pool, xsk_frames);
/* reset BQL for queue */
netdev_tx_reset_queue(txring_txq(tx_ring));
/* Zero out the buffer ring */
memset(tx_ring->tx_buffer_info, 0, sizeof(*tx_ring->tx_buffer_info) * tx_ring->count);
/* Zero out the descriptor ring */
memset(tx_ring->desc, 0, tx_ring->size);
err:
vfree(tx_ring->tx_buffer_info);
netdev_err(ndev, "Unable to allocate memory for Tx descriptor ring\n"); return -ENOMEM;
}
/** * igc_setup_all_tx_resources - wrapper to allocate Tx resources for all queues * @adapter: board private structure * * Return 0 on success, negative on failure
*/ staticint igc_setup_all_tx_resources(struct igc_adapter *adapter)
{ struct net_device *dev = adapter->netdev; int i, err = 0;
for (i = 0; i < adapter->num_tx_queues; i++) {
err = igc_setup_tx_resources(adapter->tx_ring[i]); if (err) {
netdev_err(dev, "Error on Tx queue %u setup\n", i); for (i--; i >= 0; i--)
igc_free_tx_resources(adapter->tx_ring[i]); break;
}
}
return err;
}
staticvoid igc_clean_rx_ring_page_shared(struct igc_ring *rx_ring)
{
u16 i = rx_ring->next_to_clean;
dev_kfree_skb(rx_ring->skb);
rx_ring->skb = NULL;
/* Free all the Rx ring sk_buffs */ while (i != rx_ring->next_to_alloc) { struct igc_rx_buffer *buffer_info = &rx_ring->rx_buffer_info[i];
/* Invalidate cache lines that may have been written to by * device so that we avoid corrupting memory.
*/
dma_sync_single_range_for_cpu(rx_ring->dev,
buffer_info->dma,
buffer_info->page_offset,
igc_rx_bufsz(rx_ring),
DMA_FROM_DEVICE);
/** * igc_free_all_rx_resources - Free Rx Resources for All Queues * @adapter: board private structure * * Free all receive software resources
*/ staticvoid igc_free_all_rx_resources(struct igc_adapter *adapter)
{ int i;
for (i = 0; i < adapter->num_rx_queues; i++)
igc_free_rx_resources(adapter->rx_ring[i]);
}
/** * igc_setup_rx_resources - allocate Rx resources (Descriptors) * @rx_ring: rx descriptor ring (for a specific queue) to setup * * Returns 0 on success, negative on failure
*/ int igc_setup_rx_resources(struct igc_ring *rx_ring)
{ struct net_device *ndev = rx_ring->netdev; struct device *dev = rx_ring->dev;
u8 index = rx_ring->queue_index; int size, desc_len, res;
/* XDP RX-queue info */ if (xdp_rxq_info_is_reg(&rx_ring->xdp_rxq))
xdp_rxq_info_unreg(&rx_ring->xdp_rxq);
res = xdp_rxq_info_reg(&rx_ring->xdp_rxq, ndev, index,
rx_ring->q_vector->napi.napi_id); if (res < 0) {
netdev_err(ndev, "Failed to register xdp_rxq index %u\n",
index); return res;
}
err:
xdp_rxq_info_unreg(&rx_ring->xdp_rxq);
vfree(rx_ring->rx_buffer_info);
rx_ring->rx_buffer_info = NULL;
netdev_err(ndev, "Unable to allocate memory for Rx descriptor ring\n"); return -ENOMEM;
}
/** * igc_setup_all_rx_resources - wrapper to allocate Rx resources * (Descriptors) for all queues * @adapter: board private structure * * Return 0 on success, negative on failure
*/ staticint igc_setup_all_rx_resources(struct igc_adapter *adapter)
{ struct net_device *dev = adapter->netdev; int i, err = 0;
for (i = 0; i < adapter->num_rx_queues; i++) {
err = igc_setup_rx_resources(adapter->rx_ring[i]); if (err) {
netdev_err(dev, "Error on Rx queue %u setup\n", i); for (i--; i >= 0; i--)
igc_free_rx_resources(adapter->rx_ring[i]); break;
}
}
/** * igc_configure_rx_ring - Configure a receive ring after Reset * @adapter: board private structure * @ring: receive ring to be configured * * Configure the Rx unit of the MAC after a reset.
*/ staticvoid igc_configure_rx_ring(struct igc_adapter *adapter, struct igc_ring *ring)
{ struct igc_hw *hw = &adapter->hw; union igc_adv_rx_desc *rx_desc; int reg_idx = ring->reg_idx;
u32 srrctl = 0, rxdctl = 0;
u64 rdba = ring->dma;
u32 buf_size;
/** * igc_configure_rx - Configure receive Unit after Reset * @adapter: board private structure * * Configure the Rx unit of the MAC after a reset.
*/ staticvoid igc_configure_rx(struct igc_adapter *adapter)
{ int i;
/* Setup the HW Rx Head and Tail Descriptor Pointers and * the Base and Length of the Rx Descriptor Ring
*/ for (i = 0; i < adapter->num_rx_queues; i++)
igc_configure_rx_ring(adapter, adapter->rx_ring[i]);
}
/** * igc_configure_tx_ring - Configure transmit ring after Reset * @adapter: board private structure * @ring: tx ring to configure * * Configure a transmit ring after a reset.
*/ staticvoid igc_configure_tx_ring(struct igc_adapter *adapter, struct igc_ring *ring)
{ struct igc_hw *hw = &adapter->hw; int reg_idx = ring->reg_idx;
u64 tdba = ring->dma;
u32 txdctl = 0;
ring->xsk_pool = igc_get_xsk_pool(adapter, ring);
/* disable the queue */
wr32(IGC_TXDCTL(reg_idx), 0);
wrfl();
/** * igc_configure_tx - Configure transmit Unit after Reset * @adapter: board private structure * * Configure the Tx unit of the MAC after a reset.
*/ staticvoid igc_configure_tx(struct igc_adapter *adapter)
{ int i;
for (i = 0; i < adapter->num_tx_queues; i++)
igc_configure_tx_ring(adapter, adapter->tx_ring[i]);
}
/* Disable raw packet checksumming so that RSS hash is placed in * descriptor on writeback. No need to enable TCP/UDP/IP checksum * offloads as they are enabled by default
*/
rxcsum = rd32(IGC_RXCSUM);
rxcsum |= IGC_RXCSUM_PCSD;
/* This is useful for sniffing bad packets. */ if (adapter->netdev->features & NETIF_F_RXALL) { /* UPE and MPE will be handled by normal PROMISC logic * in set_rx_mode
*/
rctl |= (IGC_RCTL_SBP | /* Receive bad packets */
IGC_RCTL_BAM | /* RX All Bcast Pkts */
IGC_RCTL_PMCF); /* RX All MAC Ctrl Pkts */
/* disable queue 0 which icould be enabled by default */
wr32(IGC_TXDCTL(0), 0);
/* Program the Transmit Control Register */
tctl = rd32(IGC_TCTL);
tctl &= ~IGC_TCTL_CT;
tctl |= IGC_TCTL_PSP | IGC_TCTL_RTLC |
(IGC_COLLISION_THRESHOLD << IGC_CT_SHIFT);
/* Enable transmits */
tctl |= IGC_TCTL_EN;
wr32(IGC_TCTL, tctl);
}
/** * igc_set_mac_filter_hw() - Set MAC address filter in hardware * @adapter: Pointer to adapter where the filter should be set * @index: Filter index * @type: MAC address filter type (source or destination) * @addr: MAC address * @queue: If non-negative, queue assignment feature is enabled and frames * matching the filter are enqueued onto 'queue'. Otherwise, queue * assignment is disabled.
*/ staticvoid igc_set_mac_filter_hw(struct igc_adapter *adapter, int index, enum igc_mac_filter_type type, const u8 *addr, int queue)
{ struct net_device *dev = adapter->netdev; struct igc_hw *hw = &adapter->hw;
u32 ral, rah;
if (WARN_ON(index >= hw->mac.rar_entry_count)) return;
netdev_dbg(dev, "MAC address filter set in HW: index %d", index);
}
/** * igc_clear_mac_filter_hw() - Clear MAC address filter in hardware * @adapter: Pointer to adapter where the filter should be cleared * @index: Filter index
*/ staticvoid igc_clear_mac_filter_hw(struct igc_adapter *adapter, int index)
{ struct net_device *dev = adapter->netdev; struct igc_hw *hw = &adapter->hw;
if (WARN_ON(index >= hw->mac.rar_entry_count)) return;
wr32(IGC_RAL(index), 0);
wr32(IGC_RAH(index), 0);
netdev_dbg(dev, "MAC address filter cleared in HW: index %d", index);
}
/* Set default MAC address for the PF in the first RAR entry */ staticvoid igc_set_default_mac_filter(struct igc_adapter *adapter)
{ struct net_device *dev = adapter->netdev;
u8 *addr = adapter->hw.mac.addr;
netdev_dbg(dev, "Set default MAC address filter: address %pM", addr);
/* set the correct pool for the new PF MAC address in entry 0 */
igc_set_default_mac_filter(adapter);
return 0;
}
/** * igc_write_mc_addr_list - write multicast addresses to MTA * @netdev: network interface device structure * * Writes multicast address list to the MTA hash table. * Returns: -ENOMEM on failure * 0 on no addresses written * X on writing X addresses to MTA
**/ staticint igc_write_mc_addr_list(struct net_device *netdev)
{ struct igc_adapter *adapter = netdev_priv(netdev); struct igc_hw *hw = &adapter->hw; struct netdev_hw_addr *ha;
u8 *mta_list; int i;
if (netdev_mc_empty(netdev)) { /* nothing to program, so clear mc list */
igc_update_mc_addr_list(hw, NULL, 0); return 0;
}
mta_list = kcalloc(netdev_mc_count(netdev), 6, GFP_ATOMIC); if (!mta_list) return -ENOMEM;
/* The shared function expects a packed array of only addresses. */
i = 0;
netdev_for_each_mc_addr(ha, netdev)
memcpy(mta_list + (i++ * ETH_ALEN), ha->addr, ETH_ALEN);
if (ktime_compare(txtime, end_of_cycle) >= 0) { if (baset_est != ring->last_ff_cycle) {
*first_flag = true;
ring->last_ff_cycle = baset_est;
if (ktime_compare(end_of_cycle, ring->last_tx_cycle) > 0)
*insert_empty = true;
}
}
/* Introducing a window at end of cycle on which packets * potentially not honor launchtime. Window of 5us chosen * considering software update the tail pointer and packets * are dma'ed to packet buffer.
*/ if ((ktime_sub_ns(end_of_cycle, now) < 5 * NSEC_PER_USEC))
netdev_warn(ring->netdev, "Packet with txtime=%llu may not be honoured\n",
txtime);
i++;
tx_ring->next_to_use = (i < tx_ring->count) ? i : 0;
/* set bits to identify this as an advanced context descriptor */
type_tucmd |= IGC_TXD_CMD_DEXT | IGC_ADVTXD_DTYP_CTXT;
/* For i225, context index must be unique per ring. */ if (test_bit(IGC_RING_FLAG_TX_CTX_IDX, &tx_ring->flags))
mss_l4len_idx |= tx_ring->reg_idx << 4;
if (first_flag)
mss_l4len_idx |= IGC_ADVTXD_TSN_CNTX_FIRST;
static u32 igc_tx_cmd_type(struct sk_buff *skb, u32 tx_flags)
{ /* set type for advanced descriptor with frame checksum insertion */
u32 cmd_type = IGC_ADVTXD_DTYP_DATA |
IGC_ADVTXD_DCMD_DEXT |
IGC_ADVTXD_DCMD_IFCS;
/* set HW vlan bit if vlan is present */
cmd_type |= IGC_SET_FLAG(tx_flags, IGC_TX_FLAGS_VLAN,
IGC_ADVTXD_DCMD_VLE);
/* set segmentation bits for TSO */
cmd_type |= IGC_SET_FLAG(tx_flags, IGC_TX_FLAGS_TSO,
(IGC_ADVTXD_DCMD_TSE));
/* set timestamp bit if present, will select the register set * based on the _TSTAMP(_X) bit.
*/
cmd_type |= IGC_SET_FLAG(tx_flags, IGC_TX_FLAGS_TSTAMP,
(IGC_ADVTXD_MAC_TSTAMP));
/* Use the second timer (free running, in general) for the timestamp */
olinfo_status |= IGC_SET_FLAG(tx_flags, IGC_TX_FLAGS_TSTAMP_TIMER_1,
IGC_TXD_PTP2_TIMER_1);
/* set the timestamp */
first->time_stamp = jiffies;
skb_tx_timestamp(skb);
/* Force memory writes to complete before letting h/w know there * are new descriptors to fetch. (Only applicable for weak-ordered * memory model archs, such as IA-64). * * We also need this memory barrier to make certain all of the * status bits have been updated before next_to_watch is written.
*/
wmb();
/* set next_to_watch value indicating a packet is present */
first->next_to_watch = tx_desc;
i++; if (i == tx_ring->count)
i = 0;
tx_ring->next_to_use = i;
/* Make sure there is space in the ring for the next send. */
igc_maybe_stop_tx(tx_ring, DESC_NEEDED);
if (netif_xmit_stopped(txring_txq(tx_ring)) || !netdev_xmit_more()) {
writel(i, tx_ring->tail);
}
/* IP header will have to cancel out any data that * is not a part of the outer IP header
*/
ip.v4->check = csum_fold(csum_partial(trans_start,
csum_start - trans_start,
0));
type_tucmd |= IGC_ADVTXD_TUCMD_IPV4;
/* need: 1 descriptor per page * PAGE_SIZE/IGC_MAX_DATA_PER_TXD, * + 1 desc for skb_headlen/IGC_MAX_DATA_PER_TXD, * + 2 desc gap to keep tail from touching head, * + 1 desc for context descriptor, * + 2 desc for inserting an empty packet for launch time, * otherwise try next time
*/ for (f = 0; f < skb_shinfo(skb)->nr_frags; f++)
count += TXD_USE_COUNT(skb_frag_size(
&skb_shinfo(skb)->frags[f]));
if (igc_maybe_stop_tx(tx_ring, count + 5)) { /* this is a hard error */ return NETDEV_TX_BUSY;
}
if (insert_empty) { /* Reset the launch time if the required empty frame fails to * be inserted. However, this packet is not dropped, so it * "dirties" the current Qbv cycle. This ensures that the * upcoming packet, which is scheduled in the next Qbv cycle, * does not require an empty frame. This way, the launch time * continues to function correctly despite the current failure * to insert the empty frame.
*/ if (igc_insert_empty_frame(tx_ring))
launch_time = 0;
}
done: /* record the location of the first descriptor for this packet */
first = &tx_ring->tx_buffer_info[tx_ring->next_to_use];
first->type = IGC_TX_BUFFER_TYPE_SKB;
first->skb = skb;
first->bytecount = skb->len;
first->gso_segs = 1;
if (adapter->qbv_transition || tx_ring->oper_gate_closed) goto out_drop;
/* record initial flags and protocol */
first->tx_flags = tx_flags;
first->protocol = protocol;
/* For preemptible queue, manually pad the skb so that HW includes * padding bytes in mCRC calculation
*/ if (tx_ring->preemptible && skb->len < ETH_ZLEN) { if (skb_padto(skb, ETH_ZLEN)) goto out_drop;
skb_put(skb, ETH_ZLEN - skb->len);
}
/* The minimum packet size with TCTL.PSP set is 17 so pad the skb * in order to meet this minimum size requirement.
*/ if (skb->len < 17) { if (skb_padto(skb, 17)) return NETDEV_TX_OK;
skb->len = 17;
}
/* Ignore Checksum bit is set */ if (igc_test_staterr(rx_desc, IGC_RXD_STAT_IXSM)) return;
/* Rx checksum disabled via ethtool */ if (!(ring->netdev->features & NETIF_F_RXCSUM)) return;
/* TCP/UDP checksum error bit is set */ if (igc_test_staterr(rx_desc,
IGC_RXDEXT_STATERR_L4E |
IGC_RXDEXT_STATERR_IPE)) { /* work around errata with sctp packets where the TCPE aka * L4E bit is set incorrectly on 64 byte (60 byte w/o crc) * packets (aka let the stack check the crc32c)
*/ if (!(skb->len == 60 &&
test_bit(IGC_RING_FLAG_RX_SCTP_CSUM, &ring->flags))) {
u64_stats_update_begin(&ring->rx_syncp);
ring->rx_stats.csum_err++;
u64_stats_update_end(&ring->rx_syncp);
} /* let the stack verify checksum errors */ return;
} /* It must be a TCP or UDP packet with a valid checksum */ if (igc_test_staterr(rx_desc, IGC_RXD_STAT_TCPCS |
IGC_RXD_STAT_UDPCS))
skb->ip_summed = CHECKSUM_UNNECESSARY;
/** * igc_process_skb_fields - Populate skb header fields from Rx descriptor * @rx_ring: rx descriptor ring packet is being transacted on * @rx_desc: pointer to the EOP Rx descriptor * @skb: pointer to current skb being populated * * This function checks the ring, descriptor, and packet information in order * to populate the hash, checksum, VLAN, protocol, and other fields within the * skb.
*/ staticvoid igc_process_skb_fields(struct igc_ring *rx_ring, union igc_adv_rx_desc *rx_desc, struct sk_buff *skb)
{
igc_rx_hash(rx_ring, rx_desc, skb);
/* we are reusing so sync this buffer for CPU use */
dma_sync_single_range_for_cpu(rx_ring->dev,
rx_buffer->dma,
rx_buffer->page_offset,
size,
DMA_FROM_DEVICE);
/** * igc_add_rx_frag - Add contents of Rx buffer to sk_buff * @rx_ring: rx descriptor ring to transact packets on * @rx_buffer: buffer containing page to add * @skb: sk_buff to place the data into * @size: size of buffer to be added * * This function will add the data contained in rx_buffer->page to the skb.
*/ staticvoid igc_add_rx_frag(struct igc_ring *rx_ring, struct igc_rx_buffer *rx_buffer, struct sk_buff *skb, unsignedint size)
{ unsignedint truesize;
/* prefetch first cache line of first page */
net_prefetch(xdp->data_meta);
/* build an skb around the page buffer */
skb = napi_build_skb(xdp->data_hard_start, truesize); if (unlikely(!skb)) return NULL;
/* update pointers within the skb to store the data */
skb_reserve(skb, xdp->data - xdp->data_hard_start);
__skb_put(skb, size); if (metasize)
skb_metadata_set(skb, metasize);
/* prefetch first cache line of first page */
net_prefetch(xdp->data_meta);
/* allocate a skb to store the frags */
skb = napi_alloc_skb(&rx_ring->q_vector->napi,
IGC_RX_HDR_LEN + metasize); if (unlikely(!skb)) return NULL;
if (ctx->rx_ts) {
skb_shinfo(skb)->tx_flags |= SKBTX_HW_TSTAMP_NETDEV;
skb_hwtstamps(skb)->netdev_data = ctx->rx_ts;
}
/* Determine available headroom for copy */
headlen = size; if (headlen > IGC_RX_HDR_LEN)
headlen = eth_get_headlen(skb->dev, va, IGC_RX_HDR_LEN);
/* align pull length to size of long to optimize memcpy performance */
memcpy(__skb_put(skb, headlen + metasize), xdp->data_meta,
ALIGN(headlen + metasize, sizeof(long)));
if (metasize) {
skb_metadata_set(skb, metasize);
__skb_pull(skb, metasize);
}
/* update all of the pointers */
size -= headlen; if (size) {
skb_add_rx_frag(skb, 0, rx_buffer->page,
(va + headlen) - page_address(rx_buffer->page),
size, truesize);
igc_rx_buffer_flip(rx_buffer, truesize);
} else {
rx_buffer->pagecnt_bias++;
}
return skb;
}
/** * igc_reuse_rx_page - page flip buffer and store it back on the ring * @rx_ring: rx descriptor ring to store buffers on * @old_buff: donor buffer to have page reused * * Synchronizes page for reuse by the adapter
*/ staticvoid igc_reuse_rx_page(struct igc_ring *rx_ring, struct igc_rx_buffer *old_buff)
{
u16 nta = rx_ring->next_to_alloc; struct igc_rx_buffer *new_buff;
new_buff = &rx_ring->rx_buffer_info[nta];
/* update, and store next to alloc */
nta++;
rx_ring->next_to_alloc = (nta < rx_ring->count) ? nta : 0;
/* Transfer page from old buffer to new buffer. * Move each member individually to avoid possible store * forwarding stalls.
*/
new_buff->dma = old_buff->dma;
new_buff->page = old_buff->page;
new_buff->page_offset = old_buff->page_offset;
new_buff->pagecnt_bias = old_buff->pagecnt_bias;
}
/* avoid re-using remote and pfmemalloc pages */ if (!dev_page_is_reusable(page)) returnfalse;
#if (PAGE_SIZE < 8192) /* if we are only owner of page we can reuse it */ if (unlikely((rx_buffer_pgcnt - pagecnt_bias) > 1)) returnfalse; #else #define IGC_LAST_OFFSET \
(SKB_WITH_OVERHEAD(PAGE_SIZE) - IGC_RXBUFFER_2048)
if (rx_buffer->page_offset > IGC_LAST_OFFSET) returnfalse; #endif
/* If we have drained the page fragment pool we need to update * the pagecnt_bias and page count so that we fully restock the * number of references the driver holds.
*/ if (unlikely(pagecnt_bias == 1)) {
page_ref_add(page, USHRT_MAX - 1);
rx_buffer->pagecnt_bias = USHRT_MAX;
}
returntrue;
}
/** * igc_is_non_eop - process handling of non-EOP buffers * @rx_ring: Rx ring being processed * @rx_desc: Rx descriptor for current buffer * * This function updates next to clean. If the buffer is an EOP buffer * this function exits returning false, otherwise it will place the * sk_buff in the next buffer to be chained and return true indicating * that this is in fact a non-EOP buffer.
*/ staticbool igc_is_non_eop(struct igc_ring *rx_ring, union igc_adv_rx_desc *rx_desc)
{
u32 ntc = rx_ring->next_to_clean + 1;
/* fetch, update, and store next to clean */
ntc = (ntc < rx_ring->count) ? ntc : 0;
rx_ring->next_to_clean = ntc;
prefetch(IGC_RX_DESC(rx_ring, ntc));
if (likely(igc_test_staterr(rx_desc, IGC_RXD_STAT_EOP))) returnfalse;
returntrue;
}
/** * igc_cleanup_headers - Correct corrupted or empty headers * @rx_ring: rx descriptor ring packet is being transacted on * @rx_desc: pointer to the EOP Rx descriptor * @skb: pointer to current skb being fixed * * Address the case where we are pulling data in on pages only * and as such no data is present in the skb header. * * In addition if skb is not at least 60 bytes we need to pad it so that * it is large enough to qualify as a valid Ethernet frame. * * Returns true if an error was encountered and skb was freed.
*/ staticbool igc_cleanup_headers(struct igc_ring *rx_ring, union igc_adv_rx_desc *rx_desc, struct sk_buff *skb)
{ if (unlikely(igc_test_staterr(rx_desc, IGC_RXDEXT_STATERR_RXE))) { struct net_device *netdev = rx_ring->netdev;
if (!(netdev->features & NETIF_F_RXALL)) {
dev_kfree_skb_any(skb); returntrue;
}
}
/* if eth_skb_pad returns an error the skb was freed */ if (eth_skb_pad(skb)) returntrue;
returnfalse;
}
staticvoid igc_put_rx_buffer(struct igc_ring *rx_ring, struct igc_rx_buffer *rx_buffer, int rx_buffer_pgcnt)
{ if (igc_can_reuse_rx_page(rx_buffer, rx_buffer_pgcnt)) { /* hand second half of page back to the ring */
igc_reuse_rx_page(rx_ring, rx_buffer);
} else { /* We are not reusing the buffer so unmap it and free * any references we are holding to it
*/
dma_unmap_page_attrs(rx_ring->dev, rx_buffer->dma,
igc_rx_pg_size(rx_ring), DMA_FROM_DEVICE,
IGC_RX_DMA_ATTR);
__page_frag_cache_drain(rx_buffer->page,
rx_buffer->pagecnt_bias);
}
/* clear contents of rx_buffer */
rx_buffer->page = NULL;
}
/* since we are recycling buffers we should seldom need to alloc */ if (likely(page)) returntrue;
/* alloc new page for storage */
page = dev_alloc_pages(igc_rx_pg_order(rx_ring)); if (unlikely(!page)) {
rx_ring->rx_stats.alloc_failed++;
set_bit(IGC_RING_FLAG_RX_ALLOC_FAILED, &rx_ring->flags); returnfalse;
}
/* map page for use */
dma = dma_map_page_attrs(rx_ring->dev, page, 0,
igc_rx_pg_size(rx_ring),
DMA_FROM_DEVICE,
IGC_RX_DMA_ATTR);
/* if mapping failed free memory back to system since * there isn't much point in holding memory we can't use
*/ if (dma_mapping_error(rx_ring->dev, dma)) {
__free_page(page);
/** * igc_alloc_rx_buffers - Replace used receive buffers; packet split * @rx_ring: rx descriptor ring * @cleaned_count: number of buffers to clean
*/ staticvoid igc_alloc_rx_buffers(struct igc_ring *rx_ring, u16 cleaned_count)
{ union igc_adv_rx_desc *rx_desc;
u16 i = rx_ring->next_to_use; struct igc_rx_buffer *bi;
u16 bufsz;
/* nothing to do */ if (!cleaned_count) return;
rx_desc = IGC_RX_DESC(rx_ring, i);
bi = &rx_ring->rx_buffer_info[i];
i -= rx_ring->count;
bufsz = igc_rx_bufsz(rx_ring);
do { if (!igc_alloc_mapped_page(rx_ring, bi)) break;
/* sync the buffer for use by the device */
dma_sync_single_range_for_device(rx_ring->dev, bi->dma,
bi->page_offset, bufsz,
DMA_FROM_DEVICE);
/* Refresh the desc even if buffer_addrs didn't change * because each write-back erases this info.
*/
rx_desc->read.pkt_addr = cpu_to_le64(bi->dma + bi->page_offset);
rx_desc++;
bi++;
i++; if (unlikely(!i)) {
rx_desc = IGC_RX_DESC(rx_ring, 0);
bi = rx_ring->rx_buffer_info;
i -= rx_ring->count;
}
/* clear the length for the next_to_use descriptor */
rx_desc->wb.upper.length = 0;
cleaned_count--;
} while (cleaned_count);
i += rx_ring->count;
if (rx_ring->next_to_use != i) { /* record the next descriptor to use */
rx_ring->next_to_use = i;
/* update next to alloc since we have filled the ring */
rx_ring->next_to_alloc = i;
/* Force memory writes to complete before letting h/w * know there are new descriptors to fetch. (Only * applicable for weak-ordered memory model archs, * such as IA-64).
*/
wmb();
writel(i, rx_ring->tail);
}
}
staticbool igc_alloc_rx_buffers_zc(struct igc_ring *ring, u16 count)
{ union igc_adv_rx_desc *desc;
u16 i = ring->next_to_use; struct igc_rx_buffer *bi;
dma_addr_t dma; bool ok = true;
if (!count) return ok;
XSK_CHECK_PRIV_TYPE(struct igc_xdp_buff);
desc = IGC_RX_DESC(ring, i);
bi = &ring->rx_buffer_info[i];
i -= ring->count;
do {
bi->xdp = xsk_buff_alloc(ring->xsk_pool); if (!bi->xdp) {
ok = false; break;
}
desc++;
bi++;
i++; if (unlikely(!i)) {
desc = IGC_RX_DESC(ring, 0);
bi = ring->rx_buffer_info;
i -= ring->count;
}
/* Clear the length for the next_to_use descriptor. */
desc->wb.upper.length = 0;
count--;
} while (count);
i += ring->count;
if (ring->next_to_use != i) {
ring->next_to_use = i;
/* Force memory writes to complete before letting h/w * know there are new descriptors to fetch. (Only * applicable for weak-ordered memory model archs, * such as IA-64).
*/
wmb();
writel(i, ring->tail);
}
return ok;
}
/* This function requires __netif_tx_lock is held by the caller. */ staticint igc_xdp_init_tx_descriptor(struct igc_ring *ring, struct xdp_frame *xdpf)
{ struct skb_shared_info *sinfo = xdp_get_shared_info_from_frame(xdpf);
u8 nr_frags = unlikely(xdp_frame_has_frags(xdpf)) ? sinfo->nr_frags : 0;
u16 count, index = ring->next_to_use; struct igc_tx_buffer *head = &ring->tx_buffer_info[index]; struct igc_tx_buffer *buffer = head; union igc_adv_tx_desc *desc = IGC_TX_DESC(ring, index);
u32 olinfo_status, len = xdpf->len, cmd_type; void *data = xdpf->data;
u16 i;
count = TXD_USE_COUNT(len); for (i = 0; i < nr_frags; i++)
count += TXD_USE_COUNT(skb_frag_size(&sinfo->frags[i]));
if (igc_maybe_stop_tx(ring, count + 3)) { /* this is a hard error */ return -EBUSY;
}
data = skb_frag_address(&sinfo->frags[i]);
len = skb_frag_size(&sinfo->frags[i]);
i++;
}
desc->read.cmd_type_len |= cpu_to_le32(IGC_TXD_DCMD);
netdev_tx_sent_queue(txring_txq(ring), head->bytecount); /* set the timestamp */
head->time_stamp = jiffies; /* set next_to_watch value indicating a packet is present */
head->next_to_watch = desc;
ring->next_to_use = index;
return 0;
unmap: for (;;) {
buffer = &ring->tx_buffer_info[index]; if (dma_unmap_len(buffer, len))
dma_unmap_page(ring->dev,
dma_unmap_addr(buffer, dma),
dma_unmap_len(buffer, len),
DMA_TO_DEVICE);
dma_unmap_len_set(buffer, len, 0); if (buffer == head) break;
if (!index)
index += ring->count;
index--;
}
return -ENOMEM;
}
struct igc_ring *igc_get_tx_ring(struct igc_adapter *adapter, int cpu)
{ int index = cpu;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.