1// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
2/*
3 * Copyright(c) 2020 Intel Corporation.
4 *
5 */
6
7#include "netdev.h"
8#include "ipoib.h"
9
10#define HFI1_IPOIB_SKB_PAD ((NET_SKB_PAD) + (NET_IP_ALIGN))
11
12static void copy_ipoib_buf(struct sk_buff *skb, void *data, int size)
13{
14	skb_checksum_none_assert(skb);
15	skb->protocol = *((__be16 *)data);
16
17	skb_put_data(skb, data, size);
18	skb->mac_header = HFI1_IPOIB_PSEUDO_LEN;
19	skb_pull(skb, HFI1_IPOIB_ENCAP_LEN);
20}
21
22static struct sk_buff *prepare_frag_skb(struct napi_struct *napi, int size)
23{
24	struct sk_buff *skb;
25	int skb_size = SKB_DATA_ALIGN(size + HFI1_IPOIB_SKB_PAD);
26	void *frag;
27
28	skb_size += SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
29	skb_size = SKB_DATA_ALIGN(skb_size);
30	frag = napi_alloc_frag(skb_size);
31
32	if (unlikely(!frag))
33		return napi_alloc_skb(napi, size);
34
35	skb = build_skb(frag, skb_size);
36
37	if (unlikely(!skb)) {
38		skb_free_frag(frag);
39		return NULL;
40	}
41
42	skb_reserve(skb, HFI1_IPOIB_SKB_PAD);
43	return skb;
44}
45
46struct sk_buff *hfi1_ipoib_prepare_skb(struct hfi1_netdev_rxq *rxq,
47				       int size, void *data)
48{
49	struct napi_struct *napi = &rxq->napi;
50	int skb_size = size + HFI1_IPOIB_ENCAP_LEN;
51	struct sk_buff *skb;
52
53	/*
54	 * For smaller(4k + skb overhead) allocations we will go using
55	 * napi cache. Otherwise we will try to use napi frag cache.
56	 */
57	if (size <= SKB_WITH_OVERHEAD(PAGE_SIZE))
58		skb = napi_alloc_skb(napi, skb_size);
59	else
60		skb = prepare_frag_skb(napi, skb_size);
61
62	if (unlikely(!skb))
63		return NULL;
64
65	copy_ipoib_buf(skb, data, size);
66
67	return skb;
68}
69
70int hfi1_ipoib_rxq_init(struct net_device *netdev)
71{
72	struct hfi1_ipoib_dev_priv *ipoib_priv = hfi1_ipoib_priv(netdev);
73	struct hfi1_devdata *dd = ipoib_priv->dd;
74	int ret;
75
76	ret = hfi1_netdev_rx_init(dd);
77	if (ret)
78		return ret;
79
80	hfi1_init_aip_rsm(dd);
81
82	return ret;
83}
84
85void hfi1_ipoib_rxq_deinit(struct net_device *netdev)
86{
87	struct hfi1_ipoib_dev_priv *ipoib_priv = hfi1_ipoib_priv(netdev);
88	struct hfi1_devdata *dd = ipoib_priv->dd;
89
90	hfi1_deinit_aip_rsm(dd);
91	hfi1_netdev_rx_destroy(dd);
92}
93