Commit 434cebab authored by Claudiu Manoil's avatar Claudiu Manoil Committed by David S. Miller

enetc: Add dynamic allocation of extended Rx BD rings

Hardware timestamping support (PTP) on Rx requires extended
buffer descriptors, double the size of normal Rx descriptors.
On the current controller revision only the timestamping offload
requires extended Rx descriptors.
Since Rx timestamping can be turned on/off at runtime, make Rx ring
allocation configurable at runtime too. As a result, the static
config option FSL_ENETC_HW_TIMESTAMPING can be dropped and the
extended descriptors can be used only when Rx timestamping gets
activated.
The extension has the same size as the base descriptor, making
the descriptor iterators easy to update for the extended case.
Signed-off-by: default avatarClaudiu Manoil <claudiu.manoil@nxp.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 714239ac
...@@ -42,16 +42,6 @@ config FSL_ENETC_PTP_CLOCK ...@@ -42,16 +42,6 @@ config FSL_ENETC_PTP_CLOCK
If compiled as module (M), the module name is fsl-enetc-ptp. If compiled as module (M), the module name is fsl-enetc-ptp.
config FSL_ENETC_HW_TIMESTAMPING
bool "ENETC hardware timestamping support"
depends on FSL_ENETC || FSL_ENETC_VF
help
Enable hardware timestamping support on the Ethernet packets
using the SO_TIMESTAMPING API. 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, this option enables
extended RX BDs in order to support hardware timestamping.
config FSL_ENETC_QOS config FSL_ENETC_QOS
bool "ENETC hardware Time-sensitive Network support" bool "ENETC hardware Time-sensitive Network support"
depends on (FSL_ENETC || FSL_ENETC_VF) && (NET_SCH_TAPRIO || NET_SCH_CBS) depends on (FSL_ENETC || FSL_ENETC_VF) && (NET_SCH_TAPRIO || NET_SCH_CBS)
......
...@@ -487,7 +487,7 @@ static int enetc_refill_rx_ring(struct enetc_bdr *rx_ring, const int buff_cnt) ...@@ -487,7 +487,7 @@ static int enetc_refill_rx_ring(struct enetc_bdr *rx_ring, const int buff_cnt)
return j; return j;
} }
#ifdef CONFIG_FSL_ENETC_HW_TIMESTAMPING #ifdef CONFIG_FSL_ENETC_PTP_CLOCK
static void enetc_get_rx_tstamp(struct net_device *ndev, static void enetc_get_rx_tstamp(struct net_device *ndev,
union enetc_rx_bd *rxbd, union enetc_rx_bd *rxbd,
struct sk_buff *skb) struct sk_buff *skb)
...@@ -501,7 +501,8 @@ static void enetc_get_rx_tstamp(struct net_device *ndev, ...@@ -501,7 +501,8 @@ static void enetc_get_rx_tstamp(struct net_device *ndev,
if (le16_to_cpu(rxbd->r.flags) & ENETC_RXBD_FLAG_TSTMP) { if (le16_to_cpu(rxbd->r.flags) & ENETC_RXBD_FLAG_TSTMP) {
lo = enetc_rd(hw, ENETC_SICTR0); lo = enetc_rd(hw, ENETC_SICTR0);
hi = enetc_rd(hw, ENETC_SICTR1); hi = enetc_rd(hw, ENETC_SICTR1);
tstamp_lo = le32_to_cpu(rxbd->r.tstamp); rxbd = enetc_rxbd_ext(rxbd);
tstamp_lo = le32_to_cpu(rxbd->ext.tstamp);
if (lo <= tstamp_lo) if (lo <= tstamp_lo)
hi -= 1; hi -= 1;
...@@ -515,7 +516,7 @@ static void enetc_get_rx_tstamp(struct net_device *ndev, ...@@ -515,7 +516,7 @@ static void enetc_get_rx_tstamp(struct net_device *ndev,
static void enetc_get_offloads(struct enetc_bdr *rx_ring, static void enetc_get_offloads(struct enetc_bdr *rx_ring,
union enetc_rx_bd *rxbd, struct sk_buff *skb) union enetc_rx_bd *rxbd, struct sk_buff *skb)
{ {
#ifdef CONFIG_FSL_ENETC_HW_TIMESTAMPING #ifdef CONFIG_FSL_ENETC_PTP_CLOCK
struct enetc_ndev_priv *priv = netdev_priv(rx_ring->ndev); struct enetc_ndev_priv *priv = netdev_priv(rx_ring->ndev);
#endif #endif
/* TODO: hashing */ /* TODO: hashing */
...@@ -532,7 +533,7 @@ static void enetc_get_offloads(struct enetc_bdr *rx_ring, ...@@ -532,7 +533,7 @@ static void enetc_get_offloads(struct enetc_bdr *rx_ring,
if (le16_to_cpu(rxbd->r.flags) & ENETC_RXBD_FLAG_VLAN) if (le16_to_cpu(rxbd->r.flags) & ENETC_RXBD_FLAG_VLAN)
__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
le16_to_cpu(rxbd->r.vlan_opt)); le16_to_cpu(rxbd->r.vlan_opt));
#ifdef CONFIG_FSL_ENETC_HW_TIMESTAMPING #ifdef CONFIG_FSL_ENETC_PTP_CLOCK
if (priv->active_offloads & ENETC_F_RX_TSTAMP) if (priv->active_offloads & ENETC_F_RX_TSTAMP)
enetc_get_rx_tstamp(rx_ring->ndev, rxbd, skb); enetc_get_rx_tstamp(rx_ring->ndev, rxbd, skb);
#endif #endif
...@@ -838,15 +839,19 @@ static void enetc_free_tx_resources(struct enetc_ndev_priv *priv) ...@@ -838,15 +839,19 @@ static void enetc_free_tx_resources(struct enetc_ndev_priv *priv)
enetc_free_txbdr(priv->tx_ring[i]); enetc_free_txbdr(priv->tx_ring[i]);
} }
static int enetc_alloc_rxbdr(struct enetc_bdr *rxr) static int enetc_alloc_rxbdr(struct enetc_bdr *rxr, bool extended)
{ {
size_t size = sizeof(union enetc_rx_bd);
int err; int err;
rxr->rx_swbd = vzalloc(rxr->bd_count * sizeof(struct enetc_rx_swbd)); rxr->rx_swbd = vzalloc(rxr->bd_count * sizeof(struct enetc_rx_swbd));
if (!rxr->rx_swbd) if (!rxr->rx_swbd)
return -ENOMEM; return -ENOMEM;
err = enetc_dma_alloc_bdr(rxr, sizeof(union enetc_rx_bd)); if (extended)
size *= 2;
err = enetc_dma_alloc_bdr(rxr, size);
if (err) { if (err) {
vfree(rxr->rx_swbd); vfree(rxr->rx_swbd);
return err; return err;
...@@ -855,6 +860,7 @@ static int enetc_alloc_rxbdr(struct enetc_bdr *rxr) ...@@ -855,6 +860,7 @@ static int enetc_alloc_rxbdr(struct enetc_bdr *rxr)
rxr->next_to_clean = 0; rxr->next_to_clean = 0;
rxr->next_to_use = 0; rxr->next_to_use = 0;
rxr->next_to_alloc = 0; rxr->next_to_alloc = 0;
rxr->ext_en = extended;
return 0; return 0;
} }
...@@ -874,10 +880,11 @@ static void enetc_free_rxbdr(struct enetc_bdr *rxr) ...@@ -874,10 +880,11 @@ static void enetc_free_rxbdr(struct enetc_bdr *rxr)
static int enetc_alloc_rx_resources(struct enetc_ndev_priv *priv) static int enetc_alloc_rx_resources(struct enetc_ndev_priv *priv)
{ {
bool extended = !!(priv->active_offloads & ENETC_F_RX_TSTAMP);
int i, err; int i, err;
for (i = 0; i < priv->num_rx_rings; i++) { for (i = 0; i < priv->num_rx_rings; i++) {
err = enetc_alloc_rxbdr(priv->rx_ring[i]); err = enetc_alloc_rxbdr(priv->rx_ring[i], extended);
if (err) if (err)
goto fail; goto fail;
...@@ -1167,9 +1174,10 @@ static void enetc_setup_rxbdr(struct enetc_hw *hw, struct enetc_bdr *rx_ring) ...@@ -1167,9 +1174,10 @@ static void enetc_setup_rxbdr(struct enetc_hw *hw, struct enetc_bdr *rx_ring)
enetc_rxbdr_wr(hw, idx, ENETC_RBICIR0, ENETC_RBICIR0_ICEN | 0x1); enetc_rxbdr_wr(hw, idx, ENETC_RBICIR0, ENETC_RBICIR0_ICEN | 0x1);
rbmr = ENETC_RBMR_EN; rbmr = ENETC_RBMR_EN;
#ifdef CONFIG_FSL_ENETC_HW_TIMESTAMPING
if (rx_ring->ext_en)
rbmr |= ENETC_RBMR_BDS; rbmr |= ENETC_RBMR_BDS;
#endif
if (rx_ring->ndev->features & NETIF_F_HW_VLAN_CTAG_RX) if (rx_ring->ndev->features & NETIF_F_HW_VLAN_CTAG_RX)
rbmr |= ENETC_RBMR_VTE; rbmr |= ENETC_RBMR_VTE;
...@@ -1570,11 +1578,12 @@ int enetc_set_features(struct net_device *ndev, ...@@ -1570,11 +1578,12 @@ int enetc_set_features(struct net_device *ndev,
return 0; return 0;
} }
#ifdef CONFIG_FSL_ENETC_HW_TIMESTAMPING #ifdef CONFIG_FSL_ENETC_PTP_CLOCK
static int enetc_hwtstamp_set(struct net_device *ndev, struct ifreq *ifr) static int enetc_hwtstamp_set(struct net_device *ndev, struct ifreq *ifr)
{ {
struct enetc_ndev_priv *priv = netdev_priv(ndev); struct enetc_ndev_priv *priv = netdev_priv(ndev);
struct hwtstamp_config config; struct hwtstamp_config config;
int ao;
if (copy_from_user(&config, ifr->ifr_data, sizeof(config))) if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
return -EFAULT; return -EFAULT;
...@@ -1590,6 +1599,7 @@ static int enetc_hwtstamp_set(struct net_device *ndev, struct ifreq *ifr) ...@@ -1590,6 +1599,7 @@ static int enetc_hwtstamp_set(struct net_device *ndev, struct ifreq *ifr)
return -ERANGE; return -ERANGE;
} }
ao = priv->active_offloads;
switch (config.rx_filter) { switch (config.rx_filter) {
case HWTSTAMP_FILTER_NONE: case HWTSTAMP_FILTER_NONE:
priv->active_offloads &= ~ENETC_F_RX_TSTAMP; priv->active_offloads &= ~ENETC_F_RX_TSTAMP;
...@@ -1599,6 +1609,11 @@ static int enetc_hwtstamp_set(struct net_device *ndev, struct ifreq *ifr) ...@@ -1599,6 +1609,11 @@ static int enetc_hwtstamp_set(struct net_device *ndev, struct ifreq *ifr)
config.rx_filter = HWTSTAMP_FILTER_ALL; config.rx_filter = HWTSTAMP_FILTER_ALL;
} }
if (netif_running(ndev) && ao != priv->active_offloads) {
enetc_close(ndev);
enetc_open(ndev);
}
return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ? return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
-EFAULT : 0; -EFAULT : 0;
} }
...@@ -1625,7 +1640,7 @@ static int enetc_hwtstamp_get(struct net_device *ndev, struct ifreq *ifr) ...@@ -1625,7 +1640,7 @@ static int enetc_hwtstamp_get(struct net_device *ndev, struct ifreq *ifr)
int enetc_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) int enetc_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
{ {
#ifdef CONFIG_FSL_ENETC_HW_TIMESTAMPING #ifdef CONFIG_FSL_ENETC_PTP_CLOCK
if (cmd == SIOCSHWTSTAMP) if (cmd == SIOCSHWTSTAMP)
return enetc_hwtstamp_set(ndev, rq); return enetc_hwtstamp_set(ndev, rq);
if (cmd == SIOCGHWTSTAMP) if (cmd == SIOCGHWTSTAMP)
......
...@@ -73,6 +73,7 @@ struct enetc_bdr { ...@@ -73,6 +73,7 @@ struct enetc_bdr {
dma_addr_t bd_dma_base; dma_addr_t bd_dma_base;
u8 tsd_enable; /* Time specific departure */ u8 tsd_enable; /* Time specific departure */
bool ext_en; /* enable h/w descriptor extensions */
} ____cacheline_aligned_in_smp; } ____cacheline_aligned_in_smp;
static inline void enetc_bdr_idx_inc(struct enetc_bdr *bdr, int *i) static inline void enetc_bdr_idx_inc(struct enetc_bdr *bdr, int *i)
...@@ -107,7 +108,13 @@ struct enetc_cbdr { ...@@ -107,7 +108,13 @@ struct enetc_cbdr {
static inline union enetc_rx_bd *enetc_rxbd(struct enetc_bdr *rx_ring, int i) static inline union enetc_rx_bd *enetc_rxbd(struct enetc_bdr *rx_ring, int i)
{ {
return &(((union enetc_rx_bd *)rx_ring->bd_base)[i]); int hw_idx = i;
#ifdef CONFIG_FSL_ENETC_PTP_CLOCK
if (rx_ring->ext_en)
hw_idx = 2 * i;
#endif
return &(((union enetc_rx_bd *)rx_ring->bd_base)[hw_idx]);
} }
static inline union enetc_rx_bd *enetc_rxbd_next(struct enetc_bdr *rx_ring, static inline union enetc_rx_bd *enetc_rxbd_next(struct enetc_bdr *rx_ring,
...@@ -115,12 +122,21 @@ static inline union enetc_rx_bd *enetc_rxbd_next(struct enetc_bdr *rx_ring, ...@@ -115,12 +122,21 @@ static inline union enetc_rx_bd *enetc_rxbd_next(struct enetc_bdr *rx_ring,
int i) int i)
{ {
rxbd++; rxbd++;
#ifdef CONFIG_FSL_ENETC_PTP_CLOCK
if (rx_ring->ext_en)
rxbd++;
#endif
if (unlikely(++i == rx_ring->bd_count)) if (unlikely(++i == rx_ring->bd_count))
rxbd = rx_ring->bd_base; rxbd = rx_ring->bd_base;
return rxbd; return rxbd;
} }
static inline union enetc_rx_bd *enetc_rxbd_ext(union enetc_rx_bd *rxbd)
{
return ++rxbd;
}
struct enetc_msg_swbd { struct enetc_msg_swbd {
void *vaddr; void *vaddr;
dma_addr_t dma; dma_addr_t dma;
......
...@@ -574,7 +574,7 @@ static int enetc_get_ts_info(struct net_device *ndev, ...@@ -574,7 +574,7 @@ static int enetc_get_ts_info(struct net_device *ndev,
info->phc_index = -1; info->phc_index = -1;
} }
#ifdef CONFIG_FSL_ENETC_HW_TIMESTAMPING #ifdef CONFIG_FSL_ENETC_PTP_CLOCK
info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE | info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE |
SOF_TIMESTAMPING_RX_HARDWARE | SOF_TIMESTAMPING_RX_HARDWARE |
SOF_TIMESTAMPING_RAW_HARDWARE; SOF_TIMESTAMPING_RAW_HARDWARE;
......
...@@ -418,9 +418,6 @@ union enetc_rx_bd { ...@@ -418,9 +418,6 @@ union enetc_rx_bd {
struct { struct {
__le64 addr; __le64 addr;
u8 reserved[8]; u8 reserved[8];
#ifdef CONFIG_FSL_ENETC_HW_TIMESTAMPING
u8 reserved1[16];
#endif
} w; } w;
struct { struct {
__le16 inet_csum; __le16 inet_csum;
...@@ -435,11 +432,11 @@ union enetc_rx_bd { ...@@ -435,11 +432,11 @@ union enetc_rx_bd {
}; };
__le32 lstatus; __le32 lstatus;
}; };
#ifdef CONFIG_FSL_ENETC_HW_TIMESTAMPING } r;
struct {
__le32 tstamp; __le32 tstamp;
u8 reserved[12]; u8 reserved[12];
#endif } ext;
} r;
}; };
#define ENETC_RXBD_LSTATUS_R BIT(30) #define ENETC_RXBD_LSTATUS_R BIT(30)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment