Beispiel #1
0
/* Handle a received packet.  Second half: Touches packet payload. */
void __efx_rx_packet(struct efx_channel *channel,
		     struct efx_rx_buffer *rx_buf, bool checksummed)
{
	struct efx_nic *efx = channel->efx;
	struct sk_buff *skb;

	/* If we're in loopback test, then pass the packet directly to the
	 * loopback layer, and free the rx_buf here
	 */
	if (unlikely(efx->loopback_selftest)) {
		efx_loopback_rx_packet(efx, rx_buf->data, rx_buf->len);
		efx_free_rx_buffer(efx, rx_buf);
		goto done;
	}

	if (rx_buf->skb) {
		prefetch(skb_shinfo(rx_buf->skb));

		skb_put(rx_buf->skb, rx_buf->len);

		/* Move past the ethernet header. rx_buf->data still points
		 * at the ethernet header */
		rx_buf->skb->protocol = eth_type_trans(rx_buf->skb,
						       efx->net_dev);
	}

	if (likely(checksummed || rx_buf->page)) {
		efx_rx_packet_lro(channel, rx_buf);
		goto done;
	}

	/* We now own the SKB */
	skb = rx_buf->skb;
	rx_buf->skb = NULL;

	EFX_BUG_ON_PARANOID(rx_buf->page);
	EFX_BUG_ON_PARANOID(rx_buf->skb);
	EFX_BUG_ON_PARANOID(!skb);

	/* Set the SKB flags */
	skb->ip_summed = CHECKSUM_NONE;

	skb_record_rx_queue(skb, channel->channel);

	/* Pass the packet up */
	netif_receive_skb(skb);

	/* Update allocation strategy method */
	channel->rx_alloc_level += RX_ALLOC_FACTOR_SKB;

done:
	;
}
Beispiel #2
0
/* Handle a received packet.  Second half: Touches packet payload. */
void __efx_rx_packet(struct efx_channel *channel,
		     struct efx_rx_buffer *rx_buf, bool checksummed)
{
	struct efx_nic *efx = channel->efx;
	struct sk_buff *skb;
	bool lro = !!(efx->net_dev->features & NETIF_F_LRO);

	/* If we're in loopback test, then pass the packet directly to the
	 * loopback layer, and free the rx_buf here
	 */
	if (unlikely(efx->loopback_selftest)) {
		efx_loopback_rx_packet(efx, rx_buf->data, rx_buf->len);
		efx_free_rx_buffer(efx, rx_buf);
		goto done;
	}

	if (rx_buf->skb) {
		prefetch(skb_shinfo(rx_buf->skb));

		skb_put(rx_buf->skb, rx_buf->len);

		/* Move past the ethernet header. rx_buf->data still points
		 * at the ethernet header */
		rx_buf->skb->protocol = eth_type_trans(rx_buf->skb,
						       efx->net_dev);
	}

	/* Both our generic-LRO and SFC-SSR support skb and page based
	 * allocation, but neither support switching from one to the
	 * other on the fly. If we spot that the allocation mode has
	 * changed, then flush the LRO state.
	 */
	if (unlikely(channel->rx_alloc_pop_pages != (rx_buf->page != NULL))) {
		efx_flush_lro(channel);
		channel->rx_alloc_pop_pages = (rx_buf->page != NULL);
	}
	if (likely(checksummed && lro)) {
		efx_rx_packet_lro(channel, rx_buf);
		goto done;
	}

	/* Form an skb if required */
	if (rx_buf->page) {
		int hdr_len = min(rx_buf->len, EFX_SKB_HEADERS);
		skb = efx_rx_mk_skb(rx_buf, efx, hdr_len);
		if (unlikely(skb == NULL)) {
			efx_free_rx_buffer(efx, rx_buf);
			goto done;
		}
	} else {
		/* We now own the SKB */
		skb = rx_buf->skb;
		rx_buf->skb = NULL;
	}

	EFX_BUG_ON_PARANOID(rx_buf->page);
	EFX_BUG_ON_PARANOID(rx_buf->skb);
	EFX_BUG_ON_PARANOID(!skb);

	/* Set the SKB flags */
	if (unlikely(!checksummed || !efx->rx_checksum_enabled))
		skb->ip_summed = CHECKSUM_NONE;

	/* Pass the packet up */
	netif_receive_skb(skb);

	/* Update allocation strategy method */
	channel->rx_alloc_level += RX_ALLOC_FACTOR_SKB;

done:
	;
}