1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
|
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _TSO_H
#define _TSO_H
#include <linux/skbuff.h>
#include <linux/dma-mapping.h>
#include <net/ip.h>
#define TSO_HEADER_SIZE 256
struct tso_t {
int next_frag_idx;
int size;
void *data;
u16 ip_id;
u8 tlen; /* transport header len */
bool ipv6;
u32 tcp_seq;
};
/* Calculate the worst case buffer count */
static inline int tso_count_descs(const struct sk_buff *skb)
{
return skb_shinfo(skb)->gso_segs * 2 + skb_shinfo(skb)->nr_frags;
}
void tso_build_hdr(const struct sk_buff *skb, char *hdr, struct tso_t *tso,
int size, bool is_last);
void tso_build_data(const struct sk_buff *skb, struct tso_t *tso, int size);
int tso_start(struct sk_buff *skb, struct tso_t *tso);
/**
* struct tso_dma_map - DMA mapping state for GSO payload
* @dev: device used for DMA mapping
* @skb: the GSO skb being mapped
* @hdr_len: per-segment header length
* @iova_state: DMA IOVA state (when IOMMU available)
* @iova_offset: global byte offset into IOVA range (IOVA path only)
* @total_len: total payload length
* @frag_idx: current region (-1 = linear, 0..nr_frags-1 = frag)
* @offset: byte offset within current region
* @linear_dma: DMA address of the linear payload
* @linear_len: length of the linear payload
* @nr_frags: number of frags successfully DMA-mapped
* @frags: per-frag DMA address and length
*
* DMA-maps the payload regions of a GSO skb (linear data + frags).
* Prefers the DMA IOVA API for a single contiguous mapping with one
* IOTLB sync; falls back to per-region dma_map_phys() otherwise.
*/
struct tso_dma_map {
struct device *dev;
const struct sk_buff *skb;
unsigned int hdr_len;
/* IOVA path */
struct dma_iova_state iova_state;
size_t iova_offset;
size_t total_len;
/* Fallback path if IOVA path fails */
int frag_idx;
unsigned int offset;
dma_addr_t linear_dma;
unsigned int linear_len;
unsigned int nr_frags;
struct {
dma_addr_t dma;
unsigned int len;
} frags[MAX_SKB_FRAGS];
};
/**
* struct tso_dma_map_completion_state - Completion-time cleanup state
* @iova_state: DMA IOVA state (when IOMMU available)
* @total_len: total payload length of the IOVA mapping
*
* Drivers store this on their SW ring at xmit time via
* tso_dma_map_completion_save(), then call tso_dma_map_complete() at
* completion time.
*/
struct tso_dma_map_completion_state {
struct dma_iova_state iova_state;
size_t total_len;
};
int tso_dma_map_init(struct tso_dma_map *map, struct device *dev,
const struct sk_buff *skb, unsigned int hdr_len);
void tso_dma_map_cleanup(struct tso_dma_map *map);
unsigned int tso_dma_map_count(struct tso_dma_map *map, unsigned int len);
bool tso_dma_map_next(struct tso_dma_map *map, dma_addr_t *addr,
unsigned int *chunk_len, unsigned int *mapping_len,
unsigned int seg_remaining);
/**
* tso_dma_map_completion_save - save state needed for completion-time cleanup
* @map: the xmit-time DMA map
* @cstate: driver-owned storage that persists until completion
*
* Should be called at xmit time to update the completion state and later passed
* to tso_dma_map_complete().
*/
static inline void
tso_dma_map_completion_save(const struct tso_dma_map *map,
struct tso_dma_map_completion_state *cstate)
{
cstate->iova_state = map->iova_state;
cstate->total_len = map->total_len;
}
/**
* tso_dma_map_complete - tear down mapping at completion time
* @dev: the device that owns the mapping
* @cstate: state saved by tso_dma_map_completion_save()
*
* Return: true if the IOVA path was used and the mapping has been
* destroyed; false if the fallback per-region path was used and the
* driver must unmap via its normal completion path.
*/
static inline bool
tso_dma_map_complete(struct device *dev,
struct tso_dma_map_completion_state *cstate)
{
if (dma_use_iova(&cstate->iova_state)) {
dma_iova_destroy(dev, &cstate->iova_state, cstate->total_len,
DMA_TO_DEVICE, 0);
return true;
}
return false;
}
#endif /* _TSO_H */
|