Skip to content

Commit d398231

Browse files
yangbolu1991davem330
authored andcommitted
enetc: add hardware timestamping support
This patch is to add hardware timestamping support for ENETC. On Rx, timestamping is enabled for all frames. On Tx, we only instruct the hardware to timestamp the frames marked accordingly by the stack. Because the RX BD ring dynamic allocation has not been supported and it is too expensive to use extended RX BDs if timestamping is not used, a Kconfig option is used to enable extended RX BDs in order to support hardware timestamping. This option will be removed once RX BD ring dynamic allocation is implemented. Signed-off-by: Yangbo Lu <[email protected]> Signed-off-by: Claudiu Manoil <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent dfb569f commit d398231

File tree

6 files changed

+189
-6
lines changed

6 files changed

+189
-6
lines changed

drivers/net/ethernet/freescale/enetc/Kconfig

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,13 @@ config FSL_ENETC_PTP_CLOCK
2929
packets using the SO_TIMESTAMPING API.
3030

3131
If compiled as module (M), the module name is fsl-enetc-ptp.
32+
33+
config FSL_ENETC_HW_TIMESTAMPING
34+
bool "ENETC hardware timestamping support"
35+
depends on FSL_ENETC || FSL_ENETC_VF
36+
help
37+
Enable hardware timestamping support on the Ethernet packets
38+
using the SO_TIMESTAMPING API. Because the RX BD ring dynamic
39+
allocation has not been supported and it is too expensive to use
40+
extended RX BDs if timestamping is not used, this option enables
41+
extended RX BDs in order to support hardware timestamping.

drivers/net/ethernet/freescale/enetc/enetc.c

Lines changed: 153 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@
1313
#define ENETC_MAX_SKB_FRAGS 13
1414
#define ENETC_TXBDS_MAX_NEEDED ENETC_TXBDS_NEEDED(ENETC_MAX_SKB_FRAGS + 1)
1515

16-
static int enetc_map_tx_buffs(struct enetc_bdr *tx_ring, struct sk_buff *skb);
16+
static int enetc_map_tx_buffs(struct enetc_bdr *tx_ring, struct sk_buff *skb,
17+
int active_offloads);
1718

1819
netdev_tx_t enetc_xmit(struct sk_buff *skb, struct net_device *ndev)
1920
{
@@ -33,7 +34,7 @@ netdev_tx_t enetc_xmit(struct sk_buff *skb, struct net_device *ndev)
3334
return NETDEV_TX_BUSY;
3435
}
3536

36-
count = enetc_map_tx_buffs(tx_ring, skb);
37+
count = enetc_map_tx_buffs(tx_ring, skb, priv->active_offloads);
3738
if (unlikely(!count))
3839
goto drop_packet_err;
3940

@@ -105,7 +106,8 @@ static void enetc_free_tx_skb(struct enetc_bdr *tx_ring,
105106
}
106107
}
107108

108-
static int enetc_map_tx_buffs(struct enetc_bdr *tx_ring, struct sk_buff *skb)
109+
static int enetc_map_tx_buffs(struct enetc_bdr *tx_ring, struct sk_buff *skb,
110+
int active_offloads)
109111
{
110112
struct enetc_tx_swbd *tx_swbd;
111113
struct skb_frag_struct *frag;
@@ -137,7 +139,10 @@ static int enetc_map_tx_buffs(struct enetc_bdr *tx_ring, struct sk_buff *skb)
137139
count++;
138140

139141
do_vlan = skb_vlan_tag_present(skb);
140-
do_tstamp = skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP;
142+
do_tstamp = (active_offloads & ENETC_F_TX_TSTAMP) &&
143+
(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP);
144+
tx_swbd->do_tstamp = do_tstamp;
145+
tx_swbd->check_wb = tx_swbd->do_tstamp;
141146

142147
if (do_vlan || do_tstamp)
143148
flags |= ENETC_TXBD_FLAGS_EX;
@@ -299,24 +304,69 @@ static int enetc_bd_ready_count(struct enetc_bdr *tx_ring, int ci)
299304
return pi >= ci ? pi - ci : tx_ring->bd_count - ci + pi;
300305
}
301306

307+
static void enetc_get_tx_tstamp(struct enetc_hw *hw, union enetc_tx_bd *txbd,
308+
u64 *tstamp)
309+
{
310+
u32 lo, hi;
311+
312+
lo = enetc_rd(hw, ENETC_SICTR0);
313+
hi = enetc_rd(hw, ENETC_SICTR1);
314+
if (lo <= txbd->wb.tstamp)
315+
hi -= 1;
316+
*tstamp = (u64)hi << 32 | txbd->wb.tstamp;
317+
}
318+
319+
static void enetc_tstamp_tx(struct sk_buff *skb, u64 tstamp)
320+
{
321+
struct skb_shared_hwtstamps shhwtstamps;
322+
323+
if (skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS) {
324+
memset(&shhwtstamps, 0, sizeof(shhwtstamps));
325+
shhwtstamps.hwtstamp = ns_to_ktime(tstamp);
326+
skb_tstamp_tx(skb, &shhwtstamps);
327+
}
328+
}
329+
302330
static bool enetc_clean_tx_ring(struct enetc_bdr *tx_ring, int napi_budget)
303331
{
304332
struct net_device *ndev = tx_ring->ndev;
305333
int tx_frm_cnt = 0, tx_byte_cnt = 0;
306334
struct enetc_tx_swbd *tx_swbd;
307335
int i, bds_to_clean;
336+
bool do_tstamp;
337+
u64 tstamp = 0;
308338

309339
i = tx_ring->next_to_clean;
310340
tx_swbd = &tx_ring->tx_swbd[i];
311341
bds_to_clean = enetc_bd_ready_count(tx_ring, i);
312342

343+
do_tstamp = false;
344+
313345
while (bds_to_clean && tx_frm_cnt < ENETC_DEFAULT_TX_WORK) {
314346
bool is_eof = !!tx_swbd->skb;
315347

348+
if (unlikely(tx_swbd->check_wb)) {
349+
struct enetc_ndev_priv *priv = netdev_priv(ndev);
350+
union enetc_tx_bd *txbd;
351+
352+
txbd = ENETC_TXBD(*tx_ring, i);
353+
354+
if (txbd->flags & ENETC_TXBD_FLAGS_W &&
355+
tx_swbd->do_tstamp) {
356+
enetc_get_tx_tstamp(&priv->si->hw, txbd,
357+
&tstamp);
358+
do_tstamp = true;
359+
}
360+
}
361+
316362
if (likely(tx_swbd->dma))
317363
enetc_unmap_tx_buff(tx_ring, tx_swbd);
318364

319365
if (is_eof) {
366+
if (unlikely(do_tstamp)) {
367+
enetc_tstamp_tx(tx_swbd->skb, tstamp);
368+
do_tstamp = false;
369+
}
320370
napi_consume_skb(tx_swbd->skb, napi_budget);
321371
tx_swbd->skb = NULL;
322372
}
@@ -425,10 +475,37 @@ static int enetc_refill_rx_ring(struct enetc_bdr *rx_ring, const int buff_cnt)
425475
return j;
426476
}
427477

478+
#ifdef CONFIG_FSL_ENETC_HW_TIMESTAMPING
479+
static void enetc_get_rx_tstamp(struct net_device *ndev,
480+
union enetc_rx_bd *rxbd,
481+
struct sk_buff *skb)
482+
{
483+
struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb);
484+
struct enetc_ndev_priv *priv = netdev_priv(ndev);
485+
struct enetc_hw *hw = &priv->si->hw;
486+
u32 lo, hi;
487+
u64 tstamp;
488+
489+
if (rxbd->r.flags & ENETC_RXBD_FLAG_TSTMP) {
490+
lo = enetc_rd(hw, ENETC_SICTR0);
491+
hi = enetc_rd(hw, ENETC_SICTR1);
492+
if (lo <= rxbd->r.tstamp)
493+
hi -= 1;
494+
495+
tstamp = (u64)hi << 32 | rxbd->r.tstamp;
496+
memset(shhwtstamps, 0, sizeof(*shhwtstamps));
497+
shhwtstamps->hwtstamp = ns_to_ktime(tstamp);
498+
}
499+
}
500+
#endif
501+
428502
static void enetc_get_offloads(struct enetc_bdr *rx_ring,
429503
union enetc_rx_bd *rxbd, struct sk_buff *skb)
430504
{
431-
/* TODO: add tstamp, hashing */
505+
#ifdef CONFIG_FSL_ENETC_HW_TIMESTAMPING
506+
struct enetc_ndev_priv *priv = netdev_priv(rx_ring->ndev);
507+
#endif
508+
/* TODO: hashing */
432509
if (rx_ring->ndev->features & NETIF_F_RXCSUM) {
433510
u16 inet_csum = le16_to_cpu(rxbd->r.inet_csum);
434511

@@ -442,6 +519,10 @@ static void enetc_get_offloads(struct enetc_bdr *rx_ring,
442519
if (le16_to_cpu(rxbd->r.flags) & ENETC_RXBD_FLAG_VLAN)
443520
__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
444521
le16_to_cpu(rxbd->r.vlan_opt));
522+
#ifdef CONFIG_FSL_ENETC_HW_TIMESTAMPING
523+
if (priv->active_offloads & ENETC_F_RX_TSTAMP)
524+
enetc_get_rx_tstamp(rx_ring->ndev, rxbd, skb);
525+
#endif
445526
}
446527

447528
static void enetc_process_skb(struct enetc_bdr *rx_ring,
@@ -1074,6 +1155,9 @@ static void enetc_setup_rxbdr(struct enetc_hw *hw, struct enetc_bdr *rx_ring)
10741155
enetc_rxbdr_wr(hw, idx, ENETC_RBICIR0, ENETC_RBICIR0_ICEN | 0x1);
10751156

10761157
rbmr = ENETC_RBMR_EN;
1158+
#ifdef CONFIG_FSL_ENETC_HW_TIMESTAMPING
1159+
rbmr |= ENETC_RBMR_BDS;
1160+
#endif
10771161
if (rx_ring->ndev->features & NETIF_F_HW_VLAN_CTAG_RX)
10781162
rbmr |= ENETC_RBMR_VTE;
10791163

@@ -1396,6 +1480,70 @@ int enetc_set_features(struct net_device *ndev,
13961480
return 0;
13971481
}
13981482

1483+
#ifdef CONFIG_FSL_ENETC_HW_TIMESTAMPING
1484+
static int enetc_hwtstamp_set(struct net_device *ndev, struct ifreq *ifr)
1485+
{
1486+
struct enetc_ndev_priv *priv = netdev_priv(ndev);
1487+
struct hwtstamp_config config;
1488+
1489+
if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
1490+
return -EFAULT;
1491+
1492+
switch (config.tx_type) {
1493+
case HWTSTAMP_TX_OFF:
1494+
priv->active_offloads &= ~ENETC_F_TX_TSTAMP;
1495+
break;
1496+
case HWTSTAMP_TX_ON:
1497+
priv->active_offloads |= ENETC_F_TX_TSTAMP;
1498+
break;
1499+
default:
1500+
return -ERANGE;
1501+
}
1502+
1503+
switch (config.rx_filter) {
1504+
case HWTSTAMP_FILTER_NONE:
1505+
priv->active_offloads &= ~ENETC_F_RX_TSTAMP;
1506+
break;
1507+
default:
1508+
priv->active_offloads |= ENETC_F_RX_TSTAMP;
1509+
config.rx_filter = HWTSTAMP_FILTER_ALL;
1510+
}
1511+
1512+
return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
1513+
-EFAULT : 0;
1514+
}
1515+
1516+
static int enetc_hwtstamp_get(struct net_device *ndev, struct ifreq *ifr)
1517+
{
1518+
struct enetc_ndev_priv *priv = netdev_priv(ndev);
1519+
struct hwtstamp_config config;
1520+
1521+
config.flags = 0;
1522+
1523+
if (priv->active_offloads & ENETC_F_TX_TSTAMP)
1524+
config.tx_type = HWTSTAMP_TX_ON;
1525+
else
1526+
config.tx_type = HWTSTAMP_TX_OFF;
1527+
1528+
config.rx_filter = (priv->active_offloads & ENETC_F_RX_TSTAMP) ?
1529+
HWTSTAMP_FILTER_ALL : HWTSTAMP_FILTER_NONE;
1530+
1531+
return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
1532+
-EFAULT : 0;
1533+
}
1534+
#endif
1535+
1536+
int enetc_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
1537+
{
1538+
#ifdef CONFIG_FSL_ENETC_HW_TIMESTAMPING
1539+
if (cmd == SIOCSHWTSTAMP)
1540+
return enetc_hwtstamp_set(ndev, rq);
1541+
if (cmd == SIOCGHWTSTAMP)
1542+
return enetc_hwtstamp_get(ndev, rq);
1543+
#endif
1544+
return -EINVAL;
1545+
}
1546+
13991547
int enetc_alloc_msix(struct enetc_ndev_priv *priv)
14001548
{
14011549
struct pci_dev *pdev = priv->si->pdev;

drivers/net/ethernet/freescale/enetc/enetc.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ struct enetc_tx_swbd {
2121
struct sk_buff *skb;
2222
dma_addr_t dma;
2323
u16 len;
24-
u16 is_dma_page;
24+
u8 is_dma_page:1;
25+
u8 check_wb:1;
26+
u8 do_tstamp:1;
2527
};
2628

2729
#define ENETC_RX_MAXFRM_SIZE ENETC_MAC_MAXFRM_SIZE
@@ -167,6 +169,12 @@ struct enetc_cls_rule {
167169

168170
#define ENETC_MAX_BDR_INT 2 /* fixed to max # of available cpus */
169171

172+
/* TODO: more hardware offloads */
173+
enum enetc_active_offloads {
174+
ENETC_F_RX_TSTAMP = BIT(0),
175+
ENETC_F_TX_TSTAMP = BIT(1),
176+
};
177+
170178
struct enetc_ndev_priv {
171179
struct net_device *ndev;
172180
struct device *dev; /* dma-mapping device */
@@ -178,6 +186,7 @@ struct enetc_ndev_priv {
178186
u16 rx_bd_count, tx_bd_count;
179187

180188
u16 msg_enable;
189+
int active_offloads;
181190

182191
struct enetc_bdr *tx_ring[16];
183192
struct enetc_bdr *rx_ring[16];
@@ -216,6 +225,7 @@ netdev_tx_t enetc_xmit(struct sk_buff *skb, struct net_device *ndev);
216225
struct net_device_stats *enetc_get_stats(struct net_device *ndev);
217226
int enetc_set_features(struct net_device *ndev,
218227
netdev_features_t features);
228+
int enetc_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd);
219229
/* ethtool */
220230
void enetc_set_ethtool_ops(struct net_device *ndev);
221231

drivers/net/ethernet/freescale/enetc/enetc_hw.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,12 @@ union enetc_tx_bd {
361361
u8 e_flags;
362362
u8 flags;
363363
} ext; /* Tx BD extension */
364+
struct {
365+
__le32 tstamp;
366+
u8 reserved[10];
367+
u8 status;
368+
u8 flags;
369+
} wb; /* writeback descriptor */
364370
};
365371

366372
#define ENETC_TXBD_FLAGS_L4CS BIT(0)
@@ -399,6 +405,9 @@ union enetc_rx_bd {
399405
struct {
400406
__le64 addr;
401407
u8 reserved[8];
408+
#ifdef CONFIG_FSL_ENETC_HW_TIMESTAMPING
409+
u8 reserved1[16];
410+
#endif
402411
} w;
403412
struct {
404413
__le16 inet_csum;
@@ -413,6 +422,10 @@ union enetc_rx_bd {
413422
};
414423
__le32 lstatus;
415424
};
425+
#ifdef CONFIG_FSL_ENETC_HW_TIMESTAMPING
426+
__le32 tstamp;
427+
u8 reserved[12];
428+
#endif
416429
} r;
417430
};
418431

drivers/net/ethernet/freescale/enetc/enetc_pf.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -702,6 +702,7 @@ static const struct net_device_ops enetc_ndev_ops = {
702702
.ndo_set_vf_vlan = enetc_pf_set_vf_vlan,
703703
.ndo_set_vf_spoofchk = enetc_pf_set_vf_spoofchk,
704704
.ndo_set_features = enetc_pf_set_features,
705+
.ndo_do_ioctl = enetc_ioctl,
705706
};
706707

707708
static void enetc_pf_netdev_setup(struct enetc_si *si, struct net_device *ndev,

drivers/net/ethernet/freescale/enetc/enetc_vf.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ static const struct net_device_ops enetc_ndev_ops = {
111111
.ndo_get_stats = enetc_get_stats,
112112
.ndo_set_mac_address = enetc_vf_set_mac_addr,
113113
.ndo_set_features = enetc_vf_set_features,
114+
.ndo_do_ioctl = enetc_ioctl,
114115
};
115116

116117
static void enetc_vf_netdev_setup(struct enetc_si *si, struct net_device *ndev,

0 commit comments

Comments
 (0)