Skip to content

Commit

Permalink
net: aquantia: add PTP rings infrastructure
Browse files Browse the repository at this point in the history
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 <epomozov@marvell.com>
Co-developed-by: Sergey Samoilenko <sergey.samoilenko@aquantia.com>
Signed-off-by: Sergey Samoilenko <sergey.samoilenko@aquantia.com>
Co-developed-by: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Signed-off-by: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com>
Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Egor Pomozov authored and David S. Miller committed Oct 24, 2019
1 parent 910479a commit 94ad945
Show file tree
Hide file tree
Showing 11 changed files with 365 additions and 12 deletions.
4 changes: 4 additions & 0 deletions drivers/net/ethernet/aquantia/atlantic/aq_hw.h
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,10 @@ struct aq_hw_ops {
int (*hw_set_offload)(struct aq_hw_s *self,
struct aq_nic_cfg_s *aq_nic_cfg);

int (*hw_tx_tc_mode_get)(struct aq_hw_s *self, u32 *tc_mode);

int (*hw_rx_tc_mode_get)(struct aq_hw_s *self, u32 *tc_mode);

void (*hw_get_ptp_ts)(struct aq_hw_s *self, u64 *stamp);

int (*hw_adj_clock_freq)(struct aq_hw_s *self, s32 delta);
Expand Down
16 changes: 16 additions & 0 deletions drivers/net/ethernet/aquantia/atlantic/aq_nic.c
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,14 @@ int aq_nic_init(struct aq_nic_s *self)
if (err < 0)
goto err_exit;

err = aq_ptp_ring_alloc(self);
if (err < 0)
goto err_exit;

err = aq_ptp_ring_init(self);
if (err < 0)
goto err_exit;

netif_carrier_off(self->ndev);

err_exit:
Expand Down Expand Up @@ -369,6 +377,10 @@ int aq_nic_start(struct aq_nic_s *self)
goto err_exit;
}

err = aq_ptp_ring_start(self);
if (err < 0)
goto err_exit;

err = self->aq_hw_ops->hw_start(self->aq_hw);
if (err < 0)
goto err_exit;
Expand Down Expand Up @@ -965,6 +977,8 @@ int aq_nic_stop(struct aq_nic_s *self)
self->aq_vecs > i; ++i, aq_vec = self->aq_vec[i])
aq_vec_stop(aq_vec);

aq_ptp_ring_stop(self);

return self->aq_hw_ops->hw_stop(self->aq_hw);
}

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

aq_ptp_unregister(self);
aq_ptp_ring_deinit(self);
aq_ptp_ring_free(self);
aq_ptp_free(self);

if (likely(self->aq_fw_ops->deinit)) {
Expand Down
235 changes: 235 additions & 0 deletions drivers/net/ethernet/aquantia/atlantic/aq_ptp.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,55 @@

#include "aq_nic.h"
#include "aq_ptp.h"
#include "aq_ring.h"

struct ptp_skb_ring {
struct sk_buff **buff;
spinlock_t lock;
unsigned int size;
unsigned int head;
unsigned int tail;
};

struct aq_ptp_s {
struct aq_nic_s *aq_nic;
spinlock_t ptp_lock;
spinlock_t ptp_ring_lock;
struct ptp_clock *ptp_clock;
struct ptp_clock_info ptp_info;

struct aq_ring_param_s ptp_ring_param;

struct aq_ring_s ptp_tx;
struct aq_ring_s ptp_rx;
struct aq_ring_s hwts_rx;

struct ptp_skb_ring skb_ring;
};

static int aq_ptp_skb_ring_init(struct ptp_skb_ring *ring, unsigned int size)
{
struct sk_buff **buff = kmalloc(sizeof(*buff) * size, GFP_KERNEL);

if (!buff)
return -ENOMEM;

spin_lock_init(&ring->lock);

ring->buff = buff;
ring->size = size;
ring->head = 0;
ring->tail = 0;

return 0;
}

static void aq_ptp_skb_ring_release(struct ptp_skb_ring *ring)
{
kfree(ring->buff);
ring->buff = NULL;
}

/* aq_ptp_adjfine
* @ptp: the ptp clock structure
* @ppb: parts per billion adjustment from base
Expand Down Expand Up @@ -107,6 +148,190 @@ static int aq_ptp_settime(struct ptp_clock_info *ptp,
return 0;
}

int aq_ptp_ring_init(struct aq_nic_s *aq_nic)
{
struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp;
int err = 0;

if (!aq_ptp)
return 0;

err = aq_ring_init(&aq_ptp->ptp_tx);
if (err < 0)
goto err_exit;
err = aq_nic->aq_hw_ops->hw_ring_tx_init(aq_nic->aq_hw,
&aq_ptp->ptp_tx,
&aq_ptp->ptp_ring_param);
if (err < 0)
goto err_exit;

err = aq_ring_init(&aq_ptp->ptp_rx);
if (err < 0)
goto err_exit;
err = aq_nic->aq_hw_ops->hw_ring_rx_init(aq_nic->aq_hw,
&aq_ptp->ptp_rx,
&aq_ptp->ptp_ring_param);
if (err < 0)
goto err_exit;

err = aq_ring_rx_fill(&aq_ptp->ptp_rx);
if (err < 0)
goto err_rx_free;
err = aq_nic->aq_hw_ops->hw_ring_rx_fill(aq_nic->aq_hw,
&aq_ptp->ptp_rx,
0U);
if (err < 0)
goto err_rx_free;

err = aq_ring_init(&aq_ptp->hwts_rx);
if (err < 0)
goto err_rx_free;
err = aq_nic->aq_hw_ops->hw_ring_rx_init(aq_nic->aq_hw,
&aq_ptp->hwts_rx,
&aq_ptp->ptp_ring_param);

return err;

err_rx_free:
aq_ring_rx_deinit(&aq_ptp->ptp_rx);
err_exit:
return err;
}

int aq_ptp_ring_start(struct aq_nic_s *aq_nic)
{
struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp;
int err = 0;

if (!aq_ptp)
return 0;

err = aq_nic->aq_hw_ops->hw_ring_tx_start(aq_nic->aq_hw, &aq_ptp->ptp_tx);
if (err < 0)
goto err_exit;

err = aq_nic->aq_hw_ops->hw_ring_rx_start(aq_nic->aq_hw, &aq_ptp->ptp_rx);
if (err < 0)
goto err_exit;

err = aq_nic->aq_hw_ops->hw_ring_rx_start(aq_nic->aq_hw,
&aq_ptp->hwts_rx);
if (err < 0)
goto err_exit;

err_exit:
return err;
}

void aq_ptp_ring_stop(struct aq_nic_s *aq_nic)
{
struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp;

if (!aq_ptp)
return;

aq_nic->aq_hw_ops->hw_ring_tx_stop(aq_nic->aq_hw, &aq_ptp->ptp_tx);
aq_nic->aq_hw_ops->hw_ring_rx_stop(aq_nic->aq_hw, &aq_ptp->ptp_rx);

aq_nic->aq_hw_ops->hw_ring_rx_stop(aq_nic->aq_hw, &aq_ptp->hwts_rx);
}

void aq_ptp_ring_deinit(struct aq_nic_s *aq_nic)
{
struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp;

if (!aq_ptp || !aq_ptp->ptp_tx.aq_nic || !aq_ptp->ptp_rx.aq_nic)
return;

aq_ring_tx_clean(&aq_ptp->ptp_tx);
aq_ring_rx_deinit(&aq_ptp->ptp_rx);
}

#define PTP_8TC_RING_IDX 8
#define PTP_4TC_RING_IDX 16
#define PTP_HWST_RING_IDX 31

int aq_ptp_ring_alloc(struct aq_nic_s *aq_nic)
{
struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp;
unsigned int tx_ring_idx, rx_ring_idx;
struct aq_ring_s *hwts = 0;
u32 tx_tc_mode, rx_tc_mode;
struct aq_ring_s *ring;
int err;

if (!aq_ptp)
return 0;

/* Index must to be 8 (8 TCs) or 16 (4 TCs).
* It depends from Traffic Class mode.
*/
aq_nic->aq_hw_ops->hw_tx_tc_mode_get(aq_nic->aq_hw, &tx_tc_mode);
if (tx_tc_mode == 0)
tx_ring_idx = PTP_8TC_RING_IDX;
else
tx_ring_idx = PTP_4TC_RING_IDX;

ring = aq_ring_tx_alloc(&aq_ptp->ptp_tx, aq_nic,
tx_ring_idx, &aq_nic->aq_nic_cfg);
if (!ring) {
err = -ENOMEM;
goto err_exit;
}

aq_nic->aq_hw_ops->hw_rx_tc_mode_get(aq_nic->aq_hw, &rx_tc_mode);
if (rx_tc_mode == 0)
rx_ring_idx = PTP_8TC_RING_IDX;
else
rx_ring_idx = PTP_4TC_RING_IDX;

ring = aq_ring_rx_alloc(&aq_ptp->ptp_rx, aq_nic,
rx_ring_idx, &aq_nic->aq_nic_cfg);
if (!ring) {
err = -ENOMEM;
goto err_exit_ptp_tx;
}

hwts = aq_ring_hwts_rx_alloc(&aq_ptp->hwts_rx, aq_nic, PTP_HWST_RING_IDX,
aq_nic->aq_nic_cfg.rxds,
aq_nic->aq_nic_cfg.aq_hw_caps->rxd_size);
if (!hwts) {
err = -ENOMEM;
goto err_exit_ptp_rx;
}

err = aq_ptp_skb_ring_init(&aq_ptp->skb_ring, aq_nic->aq_nic_cfg.rxds);
if (err != 0) {
err = -ENOMEM;
goto err_exit_hwts_rx;
}

return 0;

err_exit_hwts_rx:
aq_ring_free(&aq_ptp->hwts_rx);
err_exit_ptp_rx:
aq_ring_free(&aq_ptp->ptp_rx);
err_exit_ptp_tx:
aq_ring_free(&aq_ptp->ptp_tx);
err_exit:
return err;
}

void aq_ptp_ring_free(struct aq_nic_s *aq_nic)
{
struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp;

if (!aq_ptp)
return;

aq_ring_free(&aq_ptp->ptp_tx);
aq_ring_free(&aq_ptp->ptp_rx);
aq_ring_free(&aq_ptp->hwts_rx);

aq_ptp_skb_ring_release(&aq_ptp->skb_ring);
}

static struct ptp_clock_info aq_ptp_clock = {
.owner = THIS_MODULE,
.name = "atlantic ptp",
Expand All @@ -122,6 +347,15 @@ static struct ptp_clock_info aq_ptp_clock = {
.pin_config = NULL,
};

void aq_ptp_clock_init(struct aq_nic_s *aq_nic)
{
struct aq_ptp_s *aq_ptp = aq_nic->aq_ptp;
struct timespec64 ts;

ktime_get_real_ts64(&ts);
aq_ptp_settime(&aq_ptp->ptp_info, &ts);
}

int aq_ptp_init(struct aq_nic_s *aq_nic, unsigned int idx_vec)
{
struct hw_atl_utils_mbox mbox;
Expand Down Expand Up @@ -155,6 +389,7 @@ int aq_ptp_init(struct aq_nic_s *aq_nic, unsigned int idx_vec)
aq_ptp->aq_nic = aq_nic;

spin_lock_init(&aq_ptp->ptp_lock);
spin_lock_init(&aq_ptp->ptp_ring_lock);

aq_ptp->ptp_info = aq_ptp_clock;
clock = ptp_clock_register(&aq_ptp->ptp_info, &aq_nic->ndev->dev);
Expand Down
8 changes: 8 additions & 0 deletions drivers/net/ethernet/aquantia/atlantic/aq_ptp.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@ int aq_ptp_init(struct aq_nic_s *aq_nic, unsigned int idx_vec);
void aq_ptp_unregister(struct aq_nic_s *aq_nic);
void aq_ptp_free(struct aq_nic_s *aq_nic);

int aq_ptp_ring_alloc(struct aq_nic_s *aq_nic);
void aq_ptp_ring_free(struct aq_nic_s *aq_nic);

int aq_ptp_ring_init(struct aq_nic_s *aq_nic);
int aq_ptp_ring_start(struct aq_nic_s *aq_nic);
void aq_ptp_ring_stop(struct aq_nic_s *aq_nic);
void aq_ptp_ring_deinit(struct aq_nic_s *aq_nic);

void aq_ptp_clock_init(struct aq_nic_s *aq_nic);

#endif /* AQ_PTP_H */
26 changes: 25 additions & 1 deletion drivers/net/ethernet/aquantia/atlantic/aq_ring.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* aQuantia Corporation Network Driver
* Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved
* Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved
*/

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

struct aq_ring_s *
aq_ring_hwts_rx_alloc(struct aq_ring_s *self, struct aq_nic_s *aq_nic,
unsigned int idx, unsigned int size, unsigned int dx_size)
{
struct device *dev = aq_nic_get_dev(aq_nic);
size_t sz = size * dx_size + AQ_CFG_RXDS_DEF;

memset(self, 0, sizeof(*self));

self->aq_nic = aq_nic;
self->idx = idx;
self->size = size;
self->dx_size = dx_size;

self->dx_ring = dma_alloc_coherent(dev, sz, &self->dx_ring_pa,
GFP_KERNEL);
if (!self->dx_ring) {
aq_ring_free(self);
return NULL;
}

return self;
}

int aq_ring_init(struct aq_ring_s *self)
{
self->hw_head = 0;
Expand Down
6 changes: 5 additions & 1 deletion drivers/net/ethernet/aquantia/atlantic/aq_ring.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* aQuantia Corporation Network Driver
* Copyright (C) 2014-2017 aQuantia Corporation. All rights reserved
* Copyright (C) 2014-2019 aQuantia Corporation. All rights reserved
*/

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

struct aq_ring_s *aq_ring_hwts_rx_alloc(struct aq_ring_s *self,
struct aq_nic_s *aq_nic, unsigned int idx,
unsigned int size, unsigned int dx_size);

#endif /* AQ_RING_H */
Loading

0 comments on commit 94ad945

Please sign in to comment.