]>
Commit | Line | Data |
---|---|---|
11fdf7f2 TL |
1 | /* SPDX-License-Identifier: BSD-3-Clause |
2 | * Copyright(c) 2018 Chelsio Communications. | |
3 | * All rights reserved. | |
4 | */ | |
5 | ||
9f95a23c | 6 | #include "base/common.h" |
11fdf7f2 TL |
7 | #include "clip_tbl.h" |
8 | ||
9 | /** | |
10 | * Allocate clip entry in HW with associated IPV4/IPv6 address | |
11 | */ | |
12 | static int clip6_get_mbox(const struct rte_eth_dev *dev, const u32 *lip) | |
13 | { | |
14 | struct adapter *adap = ethdev2adap(dev); | |
15 | struct fw_clip_cmd c; | |
16 | u64 hi = ((u64)lip[1]) << 32 | lip[0]; | |
17 | u64 lo = ((u64)lip[3]) << 32 | lip[2]; | |
18 | ||
19 | memset(&c, 0, sizeof(c)); | |
20 | c.op_to_write = cpu_to_be32(V_FW_CMD_OP(FW_CLIP_CMD) | | |
21 | F_FW_CMD_REQUEST | F_FW_CMD_WRITE); | |
22 | c.alloc_to_len16 = cpu_to_be32(F_FW_CLIP_CMD_ALLOC | FW_LEN16(c)); | |
23 | c.ip_hi = hi; | |
24 | c.ip_lo = lo; | |
25 | return t4_wr_mbox_meat(adap, adap->mbox, &c, sizeof(c), &c, false); | |
26 | } | |
27 | ||
28 | /** | |
29 | * Delete clip entry in HW having the associated IPV4/IPV6 address | |
30 | */ | |
31 | static int clip6_release_mbox(const struct rte_eth_dev *dev, const u32 *lip) | |
32 | { | |
33 | struct adapter *adap = ethdev2adap(dev); | |
34 | struct fw_clip_cmd c; | |
35 | u64 hi = ((u64)lip[1]) << 32 | lip[0]; | |
36 | u64 lo = ((u64)lip[3]) << 32 | lip[2]; | |
37 | ||
38 | memset(&c, 0, sizeof(c)); | |
39 | c.op_to_write = cpu_to_be32(V_FW_CMD_OP(FW_CLIP_CMD) | | |
40 | F_FW_CMD_REQUEST | F_FW_CMD_READ); | |
41 | c.alloc_to_len16 = cpu_to_be32(F_FW_CLIP_CMD_FREE | FW_LEN16(c)); | |
42 | c.ip_hi = hi; | |
43 | c.ip_lo = lo; | |
44 | return t4_wr_mbox_meat(adap, adap->mbox, &c, sizeof(c), &c, false); | |
45 | } | |
46 | ||
47 | /** | |
48 | * cxgbe_clip_release - Release associated CLIP entry | |
49 | * @ce: clip entry to release | |
50 | * | |
51 | * Releases ref count and frees up a clip entry from CLIP table | |
52 | */ | |
53 | void cxgbe_clip_release(struct rte_eth_dev *dev, struct clip_entry *ce) | |
54 | { | |
55 | int ret; | |
56 | ||
57 | t4_os_lock(&ce->lock); | |
58 | if (rte_atomic32_dec_and_test(&ce->refcnt)) { | |
59 | ret = clip6_release_mbox(dev, ce->addr); | |
60 | if (ret) | |
61 | dev_debug(adap, "CLIP FW DEL CMD failed: %d", ret); | |
62 | } | |
63 | t4_os_unlock(&ce->lock); | |
64 | } | |
65 | ||
66 | /** | |
67 | * find_or_alloc_clipe - Find/Allocate a free CLIP entry | |
68 | * @c: CLIP table | |
69 | * @lip: IPV4/IPV6 address to compare/add | |
70 | * Returns pointer to the IPV4/IPV6 entry found/created | |
71 | * | |
72 | * Finds/Allocates an CLIP entry to be used for a filter rule. | |
73 | */ | |
74 | static struct clip_entry *find_or_alloc_clipe(struct clip_tbl *c, | |
75 | const u32 *lip) | |
76 | { | |
77 | struct clip_entry *end, *e; | |
78 | struct clip_entry *first_free = NULL; | |
79 | unsigned int clipt_size = c->clipt_size; | |
80 | ||
81 | for (e = &c->cl_list[0], end = &c->cl_list[clipt_size]; e != end; ++e) { | |
82 | if (rte_atomic32_read(&e->refcnt) == 0) { | |
83 | if (!first_free) | |
84 | first_free = e; | |
85 | } else { | |
86 | if (memcmp(lip, e->addr, sizeof(e->addr)) == 0) | |
87 | goto exists; | |
88 | } | |
89 | } | |
90 | ||
91 | if (first_free) { | |
92 | e = first_free; | |
93 | goto exists; | |
94 | } | |
95 | ||
96 | return NULL; | |
97 | ||
98 | exists: | |
99 | return e; | |
100 | } | |
101 | ||
102 | static struct clip_entry *t4_clip_alloc(struct rte_eth_dev *dev, | |
103 | u32 *lip, u8 v6) | |
104 | { | |
105 | struct adapter *adap = ethdev2adap(dev); | |
106 | struct clip_tbl *ctbl = adap->clipt; | |
107 | struct clip_entry *ce; | |
108 | int ret = 0; | |
109 | ||
110 | if (!ctbl) | |
111 | return NULL; | |
112 | ||
113 | t4_os_write_lock(&ctbl->lock); | |
114 | ce = find_or_alloc_clipe(ctbl, lip); | |
115 | if (ce) { | |
116 | t4_os_lock(&ce->lock); | |
117 | if (!rte_atomic32_read(&ce->refcnt)) { | |
118 | rte_memcpy(ce->addr, lip, sizeof(ce->addr)); | |
119 | if (v6) { | |
120 | ce->type = FILTER_TYPE_IPV6; | |
121 | rte_atomic32_set(&ce->refcnt, 1); | |
122 | ret = clip6_get_mbox(dev, lip); | |
123 | if (ret) | |
124 | dev_debug(adap, | |
125 | "CLIP FW ADD CMD failed: %d", | |
126 | ret); | |
127 | } else { | |
128 | ce->type = FILTER_TYPE_IPV4; | |
129 | } | |
130 | } else { | |
131 | rte_atomic32_inc(&ce->refcnt); | |
132 | } | |
133 | t4_os_unlock(&ce->lock); | |
134 | } | |
135 | t4_os_write_unlock(&ctbl->lock); | |
136 | ||
137 | return ret ? NULL : ce; | |
138 | } | |
139 | ||
140 | /** | |
141 | * cxgbe_clip_alloc - Allocate a IPV6 CLIP entry | |
142 | * @dev: rte_eth_dev pointer | |
143 | * @lip: IPV6 address to add | |
144 | * Returns pointer to the CLIP entry created | |
145 | * | |
146 | * Allocates a IPV6 CLIP entry to be used for a filter rule. | |
147 | */ | |
148 | struct clip_entry *cxgbe_clip_alloc(struct rte_eth_dev *dev, u32 *lip) | |
149 | { | |
150 | return t4_clip_alloc(dev, lip, FILTER_TYPE_IPV6); | |
151 | } | |
152 | ||
153 | /** | |
154 | * Initialize CLIP Table | |
155 | */ | |
156 | struct clip_tbl *t4_init_clip_tbl(unsigned int clipt_start, | |
157 | unsigned int clipt_end) | |
158 | { | |
159 | unsigned int clipt_size; | |
160 | struct clip_tbl *ctbl; | |
161 | unsigned int i; | |
162 | ||
163 | if (clipt_start >= clipt_end) | |
164 | return NULL; | |
165 | ||
166 | clipt_size = clipt_end - clipt_start + 1; | |
167 | ||
168 | ctbl = t4_os_alloc(sizeof(*ctbl) + | |
169 | clipt_size * sizeof(struct clip_entry)); | |
170 | if (!ctbl) | |
171 | return NULL; | |
172 | ||
173 | ctbl->clipt_start = clipt_start; | |
174 | ctbl->clipt_size = clipt_size; | |
175 | ||
176 | t4_os_rwlock_init(&ctbl->lock); | |
177 | ||
178 | for (i = 0; i < ctbl->clipt_size; i++) { | |
179 | t4_os_lock_init(&ctbl->cl_list[i].lock); | |
180 | rte_atomic32_set(&ctbl->cl_list[i].refcnt, 0); | |
181 | } | |
182 | ||
183 | return ctbl; | |
184 | } | |
185 | ||
186 | /** | |
187 | * Cleanup CLIP Table | |
188 | */ | |
189 | void t4_cleanup_clip_tbl(struct adapter *adap) | |
190 | { | |
191 | if (adap->clipt) | |
192 | t4_os_free(adap->clipt); | |
193 | } |