Skip to content

Commit 94ad945

Browse files
Egor Pomozovdavem330
authored andcommitted
net: aquantia: add PTP rings infrastructure
Add implementations of PTP rings alloc/free. PTP desing on this device uses two separate rings on a separate traffic class for traffic rx/tx. Third ring (hwts) is not a traffic ring, but is used only to receive timestamps of the transmitted packets. Signed-off-by: Egor Pomozov <[email protected]> Co-developed-by: Sergey Samoilenko <[email protected]> Signed-off-by: Sergey Samoilenko <[email protected]> Co-developed-by: Dmitry Bezrukov <[email protected]> Signed-off-by: Dmitry Bezrukov <[email protected]> Signed-off-by: Igor Russkikh <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 910479a commit 94ad945

File tree

11 files changed

+365
-12
lines changed

11 files changed

+365
-12
lines changed

drivers/net/ethernet/aquantia/atlantic/aq_hw.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,10 @@ struct aq_hw_ops {
240240
int (*hw_set_offload)(struct aq_hw_s *self,
241241
struct aq_nic_cfg_s *aq_nic_cfg);
242242

243+
int (*hw_tx_tc_mode_get)(struct aq_hw_s *self, u32 *tc_mode);
244+
245+
int (*hw_rx_tc_mode_get)(struct aq_hw_s *self, u32 *tc_mode);
246+
243247
void (*hw_get_ptp_ts)(struct aq_hw_s *self, u64 *stamp);
244248

245249
int (*hw_adj_clock_freq)(struct aq_hw_s *self, s32 delta);

drivers/net/ethernet/aquantia/atlantic/aq_nic.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,14 @@ int aq_nic_init(struct aq_nic_s *self)
339339
if (err < 0)
340340
goto err_exit;
341341

342+
err = aq_ptp_ring_alloc(self);
343+
if (err < 0)
344+
goto err_exit;
345+
346+
err = aq_ptp_ring_init(self);
347+
if (err < 0)
348+
goto err_exit;
349+
342350
netif_carrier_off(self->ndev);
343351

344352
err_exit:
@@ -369,6 +377,10 @@ int aq_nic_start(struct aq_nic_s *self)
369377
goto err_exit;
370378
}
371379

380+
err = aq_ptp_ring_start(self);
381+
if (err < 0)
382+
goto err_exit;
383+
372384
err = self->aq_hw_ops->hw_start(self->aq_hw);
373385
if (err < 0)
374386
goto err_exit;
@@ -965,6 +977,8 @@ int aq_nic_stop(struct aq_nic_s *self)
965977
self->aq_vecs > i; ++i, aq_vec = self->aq_vec[i])
966978
aq_vec_stop(aq_vec);
967979

980+
aq_ptp_ring_stop(self);
981+
968982
return self->aq_hw_ops->hw_stop(self->aq_hw);
969983
}
970984

@@ -981,6 +995,8 @@ void aq_nic_deinit(struct aq_nic_s *self)
981995
aq_vec_deinit(aq_vec);
982996

983997
aq_ptp_unregister(self);
998+
aq_ptp_ring_deinit(self);
999+
aq_ptp_ring_free(self);
9841000
aq_ptp_free(self);
9851001

9861002
if (likely(self->aq_fw_ops->deinit)) {

drivers/net/ethernet/aquantia/atlantic/aq_ptp.c

Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,55 @@
1212

1313
#include "aq_nic.h"
1414
#include "aq_ptp.h"
15+
#include "aq_ring.h"
16+
17+
struct ptp_skb_ring {
18+
struct sk_buff **buff;
19+
spinlock_t lock;
20+
unsigned int size;
21+
unsigned int head;
22+
unsigned int tail;
23+
};
1524

1625
struct aq_ptp_s {
1726
struct aq_nic_s *aq_nic;
1827
spinlock_t ptp_lock;
28+
spinlock_t ptp_ring_lock;
1929
struct ptp_clock *ptp_clock;
2030
struct ptp_clock_info ptp_info;
31+
32+
struct aq_ring_param_s ptp_ring_param;
33+
34+
struct aq_ring_s ptp_tx;
35+
struct aq_ring_s ptp_rx;
36+
struct aq_ring_s hwts_rx;
37+
38+
struct ptp_skb_ring skb_ring;
2139
};
2240

41+
static int aq_ptp_skb_ring_init(struct ptp_skb_ring *ring, unsigned int size)
42+
{
43+
struct sk_buff **buff = kmalloc(sizeof(*buff) * size, GFP_KERNEL);
44+
45+
if (!buff)
46+
return -ENOMEM;
47+
48+
spin_lock_init(&ring->lock);
49+
50+
ring->buff = buff;
51+
ring->size = size;
52+
ring->head = 0;
53+
ring->tail = 0;
54+
55+
return 0;
56+
}
57+
58+
static void aq_ptp_skb_ring_release(struct ptp_skb_ring *ring)
59+
{
60+
kfree(ring->buff);
61+
ring->buff = NULL;
62+
}
63+
2364
/* aq_ptp_adjfine
2465
* @ptp: the ptp clock structure
2566
* @ppb: parts per billion adjustment from base
@@ -107,6 +148,190 @@ static int aq_ptp_settime(struct ptp_clock_info *ptp,
107148
return 0;
108149
}
109150

151+
int aq_ptp_ring_init(struct aq_nic_s *aq_nic)
152+
{
153+
struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp;
154+
int err = 0;
155+
156+
if (!aq_ptp)
157+
return 0;
158+
159+
err = aq_ring_init(&aq_ptp->ptp_tx);
160+
if (err < 0)
161+
goto err_exit;
162+
err = aq_nic->aq_hw_ops->hw_ring_tx_init(aq_nic->aq_hw,
163+
&aq_ptp->ptp_tx,
164+
&aq_ptp->ptp_ring_param);
165+
if (err < 0)
166+
goto err_exit;
167+
168+
err = aq_ring_init(&aq_ptp->ptp_rx);
169+
if (err < 0)
170+
goto err_exit;
171+
err = aq_nic->aq_hw_ops->hw_ring_rx_init(aq_nic->aq_hw,
172+
&aq_ptp->ptp_rx,
173+
&aq_ptp->ptp_ring_param);
174+
if (err < 0)
175+
goto err_exit;
176+
177+
err = aq_ring_rx_fill(&aq_ptp->ptp_rx);
178+
if (err < 0)
179+
goto err_rx_free;
180+
err = aq_nic->aq_hw_ops->hw_ring_rx_fill(aq_nic->aq_hw,
181+
&aq_ptp->ptp_rx,
182+
0U);
183+
if (err < 0)
184+
goto err_rx_free;
185+
186+
err = aq_ring_init(&aq_ptp->hwts_rx);
187+
if (err < 0)
188+
goto err_rx_free;
189+
err = aq_nic->aq_hw_ops->hw_ring_rx_init(aq_nic->aq_hw,
190+
&aq_ptp->hwts_rx,
191+
&aq_ptp->ptp_ring_param);
192+
193+
return err;
194+
195+
err_rx_free:
196+
aq_ring_rx_deinit(&aq_ptp->ptp_rx);
197+
err_exit:
198+
return err;
199+
}
200+
201+
int aq_ptp_ring_start(struct aq_nic_s *aq_nic)
202+
{
203+
struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp;
204+
int err = 0;
205+
206+
if (!aq_ptp)
207+
return 0;
208+
209+
err = aq_nic->aq_hw_ops->hw_ring_tx_start(aq_nic->aq_hw, &aq_ptp->ptp_tx);
210+
if (err < 0)
211+
goto err_exit;
212+
213+
err = aq_nic->aq_hw_ops->hw_ring_rx_start(aq_nic->aq_hw, &aq_ptp->ptp_rx);
214+
if (err < 0)
215+
goto err_exit;
216+
217+
err = aq_nic->aq_hw_ops->hw_ring_rx_start(aq_nic->aq_hw,
218+
&aq_ptp->hwts_rx);
219+
if (err < 0)
220+
goto err_exit;
221+
222+
err_exit:
223+
return err;
224+
}
225+
226+
void aq_ptp_ring_stop(struct aq_nic_s *aq_nic)
227+
{
228+
struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp;
229+
230+
if (!aq_ptp)
231+
return;
232+
233+
aq_nic->aq_hw_ops->hw_ring_tx_stop(aq_nic->aq_hw, &aq_ptp->ptp_tx);
234+
aq_nic->aq_hw_ops->hw_ring_rx_stop(aq_nic->aq_hw, &aq_ptp->ptp_rx);
235+
236+
aq_nic->aq_hw_ops->hw_ring_rx_stop(aq_nic->aq_hw, &aq_ptp->hwts_rx);
237+
}
238+
239+
void aq_ptp_ring_deinit(struct aq_nic_s *aq_nic)
240+
{
241+
struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp;
242+
243+
if (!aq_ptp || !aq_ptp->ptp_tx.aq_nic || !aq_ptp->ptp_rx.aq_nic)
244+
return;
245+
246+
aq_ring_tx_clean(&aq_ptp->ptp_tx);
247+
aq_ring_rx_deinit(&aq_ptp->ptp_rx);
248+
}
249+
250+
#define PTP_8TC_RING_IDX 8
251+
#define PTP_4TC_RING_IDX 16
252+
#define PTP_HWST_RING_IDX 31
253+
254+
int aq_ptp_ring_alloc(struct aq_nic_s *aq_nic)
255+
{
256+
struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp;
257+
unsigned int tx_ring_idx, rx_ring_idx;
258+
struct aq_ring_s *hwts = 0;
259+
u32 tx_tc_mode, rx_tc_mode;
260+
struct aq_ring_s *ring;
261+
int err;
262+
263+
if (!aq_ptp)
264+
return 0;
265+
266+
/* Index must to be 8 (8 TCs) or 16 (4 TCs).
267+
* It depends from Traffic Class mode.
268+
*/
269+
aq_nic->aq_hw_ops->hw_tx_tc_mode_get(aq_nic->aq_hw, &tx_tc_mode);
270+
if (tx_tc_mode == 0)
271+
tx_ring_idx = PTP_8TC_RING_IDX;
272+
else
273+
tx_ring_idx = PTP_4TC_RING_IDX;
274+
275+
ring = aq_ring_tx_alloc(&aq_ptp->ptp_tx, aq_nic,
276+
tx_ring_idx, &aq_nic->aq_nic_cfg);
277+
if (!ring) {
278+
err = -ENOMEM;
279+
goto err_exit;
280+
}
281+
282+
aq_nic->aq_hw_ops->hw_rx_tc_mode_get(aq_nic->aq_hw, &rx_tc_mode);
283+
if (rx_tc_mode == 0)
284+
rx_ring_idx = PTP_8TC_RING_IDX;
285+
else
286+
rx_ring_idx = PTP_4TC_RING_IDX;
287+
288+
ring = aq_ring_rx_alloc(&aq_ptp->ptp_rx, aq_nic,
289+
rx_ring_idx, &aq_nic->aq_nic_cfg);
290+
if (!ring) {
291+
err = -ENOMEM;
292+
goto err_exit_ptp_tx;
293+
}
294+
295+
hwts = aq_ring_hwts_rx_alloc(&aq_ptp->hwts_rx, aq_nic, PTP_HWST_RING_IDX,
296+
aq_nic->aq_nic_cfg.rxds,
297+
aq_nic->aq_nic_cfg.aq_hw_caps->rxd_size);
298+
if (!hwts) {
299+
err = -ENOMEM;
300+
goto err_exit_ptp_rx;
301+
}
302+
303+
err = aq_ptp_skb_ring_init(&aq_ptp->skb_ring, aq_nic->aq_nic_cfg.rxds);
304+
if (err != 0) {
305+
err = -ENOMEM;
306+
goto err_exit_hwts_rx;
307+
}
308+
309+
return 0;
310+
311+
err_exit_hwts_rx:
312+
aq_ring_free(&aq_ptp->hwts_rx);
313+
err_exit_ptp_rx:
314+
aq_ring_free(&aq_ptp->ptp_rx);
315+
err_exit_ptp_tx:
316+
aq_ring_free(&aq_ptp->ptp_tx);
317+
err_exit:
318+
return err;
319+
}
320+
321+
void aq_ptp_ring_free(struct aq_nic_s *aq_nic)
322+
{
323+
struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp;
324+
325+
if (!aq_ptp)
326+
return;
327+
328+
aq_ring_free(&aq_ptp->ptp_tx);
329+
aq_ring_free(&aq_ptp->ptp_rx);
330+
aq_ring_free(&aq_ptp->hwts_rx);
331+
332+
aq_ptp_skb_ring_release(&aq_ptp->skb_ring);
333+
}
334+
110335
static struct ptp_clock_info aq_ptp_clock = {
111336
.owner = THIS_MODULE,
112337
.name = "atlantic ptp",
@@ -122,6 +347,15 @@ static struct ptp_clock_info aq_ptp_clock = {
122347
.pin_config = NULL,
123348
};
124349

350+
void aq_ptp_clock_init(struct aq_nic_s *aq_nic)
351+
{
352+
struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp;
353+
struct timespec64 ts;
354+
355+
ktime_get_real_ts64(&ts);
356+
aq_ptp_settime(&aq_ptp->ptp_info, &ts);
357+
}
358+
125359
int aq_ptp_init(struct aq_nic_s *aq_nic, unsigned int idx_vec)
126360
{
127361
struct hw_atl_utils_mbox mbox;
@@ -155,6 +389,7 @@ int aq_ptp_init(struct aq_nic_s *aq_nic, unsigned int idx_vec)
155389
aq_ptp->aq_nic = aq_nic;
156390

157391
spin_lock_init(&aq_ptp->ptp_lock);
392+
spin_lock_init(&aq_ptp->ptp_ring_lock);
158393

159394
aq_ptp->ptp_info = aq_ptp_clock;
160395
clock = ptp_clock_register(&aq_ptp->ptp_info, &aq_nic->ndev->dev);

drivers/net/ethernet/aquantia/atlantic/aq_ptp.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,14 @@ int aq_ptp_init(struct aq_nic_s *aq_nic, unsigned int idx_vec);
1717
void aq_ptp_unregister(struct aq_nic_s *aq_nic);
1818
void aq_ptp_free(struct aq_nic_s *aq_nic);
1919

20+
int aq_ptp_ring_alloc(struct aq_nic_s *aq_nic);
21+
void aq_ptp_ring_free(struct aq_nic_s *aq_nic);
22+
23+
int aq_ptp_ring_init(struct aq_nic_s *aq_nic);
24+
int aq_ptp_ring_start(struct aq_nic_s *aq_nic);
25+
void aq_ptp_ring_stop(struct aq_nic_s *aq_nic);
26+
void aq_ptp_ring_deinit(struct aq_nic_s *aq_nic);
27+
2028
void aq_ptp_clock_init(struct aq_nic_s *aq_nic);
2129

2230
#endif /* AQ_PTP_H */

drivers/net/ethernet/aquantia/atlantic/aq_ring.c

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// SPDX-License-Identifier: GPL-2.0-only
22
/*
33
* aQuantia Corporation Network Driver
4-
* Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved
4+
* Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved
55
*/
66

77
/* File aq_ring.c: Definition of functions for Rx/Tx rings. */
@@ -177,6 +177,30 @@ struct aq_ring_s *aq_ring_rx_alloc(struct aq_ring_s *self,
177177
return self;
178178
}
179179

180+
struct aq_ring_s *
181+
aq_ring_hwts_rx_alloc(struct aq_ring_s *self, struct aq_nic_s *aq_nic,
182+
unsigned int idx, unsigned int size, unsigned int dx_size)
183+
{
184+
struct device *dev = aq_nic_get_dev(aq_nic);
185+
size_t sz = size * dx_size + AQ_CFG_RXDS_DEF;
186+
187+
memset(self, 0, sizeof(*self));
188+
189+
self->aq_nic = aq_nic;
190+
self->idx = idx;
191+
self->size = size;
192+
self->dx_size = dx_size;
193+
194+
self->dx_ring = dma_alloc_coherent(dev, sz, &self->dx_ring_pa,
195+
GFP_KERNEL);
196+
if (!self->dx_ring) {
197+
aq_ring_free(self);
198+
return NULL;
199+
}
200+
201+
return self;
202+
}
203+
180204
int aq_ring_init(struct aq_ring_s *self)
181205
{
182206
self->hw_head = 0;

drivers/net/ethernet/aquantia/atlantic/aq_ring.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/* SPDX-License-Identifier: GPL-2.0-only */
22
/*
33
* aQuantia Corporation Network Driver
4-
* Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved
4+
* Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved
55
*/
66

77
/* File aq_ring.h: Declaration of functions for Rx/Tx rings. */
@@ -174,4 +174,8 @@ int aq_ring_rx_clean(struct aq_ring_s *self,
174174
int budget);
175175
int aq_ring_rx_fill(struct aq_ring_s *self);
176176

177+
struct aq_ring_s *aq_ring_hwts_rx_alloc(struct aq_ring_s *self,
178+
struct aq_nic_s *aq_nic, unsigned int idx,
179+
unsigned int size, unsigned int dx_size);
180+
177181
#endif /* AQ_RING_H */

0 commit comments

Comments
 (0)