* Re: [PATCH v3 3/5] net: asix: Fix AX88772x resume failures
From: Jon Hunter @ 2016-11-18 15:09 UTC (permalink / raw)
To: allan, robert.foss, freddy, Dean_Jenkins, Mark_Craske, davem,
ivecera, john.stultz, vpalatin, stephen, grundler, changchias,
andrew, tremyfr, colin.king, linux-usb, netdev, linux-kernel,
vpalatin
In-Reply-To: <010d01d23e5b$d8993130$89cb9390$@asix.com.tw>
Hi Allan,
On 14/11/16 09:45, ASIX_Allan [Office] wrote:
> Hi Jon,
>
> Please help to double check if the USB host controller of your Terga
> platform had been powered OFF while running the ax88772_suspend() routine or
> not?
Sorry for the delay. Today I set up a local board to reproduce this on
and was able to recreate the same problem. The Tegra xhci driver does
not power off during suspend and simply calls xhci_suspend(). I also
checked vbus to see if it was turning off but it is not. Furthermore I
don't see a new USB device detected after the error and so I don't see
any evidence that it ever disconnects.
Cheers
Jon
--
nvpublic
^ permalink raw reply
* [PATCH net] rtnetlink: fix FDB size computation
From: Sabrina Dubroca @ 2016-11-18 14:50 UTC (permalink / raw)
To: netdev; +Cc: Sabrina Dubroca, Hubert Sokolowski
Add missing NDA_VLAN attribute's size.
Fixes: 1e53d5bb8878 ("net: Pass VLAN ID to rtnl_fdb_notify.")
Signed-off-by: Sabrina Dubroca <sd@queasysnail.net>
---
net/core/rtnetlink.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 2a75127f0e9e..92e75af2dc6a 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -2863,7 +2863,10 @@ static int nlmsg_populate_fdb_fill(struct sk_buff *skb,
static inline size_t rtnl_fdb_nlmsg_size(void)
{
- return NLMSG_ALIGN(sizeof(struct ndmsg)) + nla_total_size(ETH_ALEN);
+ return NLMSG_ALIGN(sizeof(struct ndmsg)) +
+ nla_total_size(ETH_ALEN) + /* NDA_LLADDR */
+ nla_total_size(sizeof(u16)) + /* NDA_VLAN */
+ 0;
}
static void rtnl_fdb_notify(struct net_device *dev, u8 *addr, u16 vid, int type,
--
2.10.2
^ permalink raw reply related
* Re: [PATCH] net: fec: Detect and recover receive queue hangs
From: Chris Lesiak @ 2016-11-18 14:36 UTC (permalink / raw)
To: Andy Duan
Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
Jaccon Bastiaansen
In-Reply-To: <AM4PR0401MB2260764510A33C534AB0136FFFB00@AM4PR0401MB2260.eurprd04.prod.outlook.com>
On 11/18/2016 12:44 AM, Andy Duan wrote:
> From: Chris Lesiak <chris.lesiak@licor.com> Sent: Friday, November 18, 2016 5:15 AM
> >To: Andy Duan <fugang.duan@nxp.com>
> >Cc: netdev@vger.kernel.org; linux-kernel@vger.kernel.org; Jaccon
> >Bastiaansen <jaccon.bastiaansen@gmail.com>; chris.lesiak@licor.com
> >Subject: [PATCH] net: fec: Detect and recover receive queue hangs
> >
> >This corrects a problem that appears to be similar to ERR006358. But while
> >ERR006358 is a race when the tx queue transitions from empty to not empty,
> >this problem is a race when the rx queue transitions from full to not full.
> >
> >The symptom is a receive queue that is stuck. The ENET_RDAR register will
> >read 0, indicating that there are no empty receive descriptors in the receive
> >ring. Since no additional frames can be queued, no RXF interrupts occur.
> >
> >This problem can be triggered with a 1 Gb link and about 400 Mbps of traffic.
I can cause the error by running the following on an imx6q: iperf -s -u
And sending packets from the other end of a 1 Gbps link:
iperf -c $IPADDR -u -b40000pps
A few others have seen this problem.
See: https://community.nxp.com/thread/322882
> >
> >This patch detects this condition, sets the work_rx bit, and reschedules the
> >poll method.
> >
> >Signed-off-by: Chris Lesiak <chris.lesiak@licor.com>
> >---
> > drivers/net/ethernet/freescale/fec_main.c | 31
> >+++++++++++++++++++++++++++++++
> > 1 file changed, 31 insertions(+)
> >
> Firstly, how to reproduce the issue, pls list the reproduce steps. Thanks.
> Secondly, pls check below comments.
>
> >diff --git a/drivers/net/ethernet/freescale/fec_main.c
> >b/drivers/net/ethernet/freescale/fec_main.c
> >index fea0f33..8a87037 100644
> >--- a/drivers/net/ethernet/freescale/fec_main.c
> >+++ b/drivers/net/ethernet/freescale/fec_main.c
> >@@ -1588,6 +1588,34 @@ fec_enet_interrupt(int irq, void *dev_id)
> > return ret;
> > }
> >
> >+static inline bool
> >+fec_enet_recover_rxq(struct fec_enet_private *fep, u16 queue_id) {
> >+ int work_bit = (queue_id == 0) ? 2 : ((queue_id == 1) ? 0 : 1);
> >+
> >+ if (readl(fep->rx_queue[queue_id]->bd.reg_desc_active))
> If rx ring is really empty in slight throughput cases, rdar is always cleared, then there always do napi reschedule.
I think that you are concerned that if rdar is zero due to this hardware
problem,
but the rx ring is actually empty, then fec_enet_rx_queue will never do
a write
to rdar so that it can be non-zero. That will cause napi to always be
resceduled.
I suppose that might be the case with zero rx traffic, and I was
concerned that
it might be true even when there was rx traffic. I suspected that the
hardware,
seeing that rdar is zero, would never queue another packet, even if
there were
in fact empty descriptors. But it doesn't seem to be the case. It does
reschedule
multiple times, but eventually sees some packets in the rx ring and
recovers.
I admit that I do not completely understand how that can happen. I did
confirm
that fec_enet_active_rxring is not being called.
Maybe someone with a deeper understanding of the fec than I can provide an
explanation.
>
> >+ return false;
> >+
> >+ dev_notice_once(&fep->pdev->dev, "Recovered rx queue\n");
> >+
> >+ fep->work_rx |= 1 << work_bit;
> >+
> >+ return true;
> >+}
> >+
> >+static inline bool fec_enet_recover_rxqs(struct fec_enet_private *fep)
> >+{
> >+ unsigned int q;
> >+ bool ret = false;
> >+
> >+ for (q = 0; q < fep->num_rx_queues; q++) {
> >+ if (fec_enet_recover_rxq(fep, q))
> >+ ret = true;
> >+ }
> >+
> >+ return ret;
> >+}
> >+
> > static int fec_enet_rx_napi(struct napi_struct *napi, int budget) {
> > struct net_device *ndev = napi->dev;
> >@@ -1601,6 +1629,9 @@ static int fec_enet_rx_napi(struct napi_struct *napi,
> >int budget)
> > if (pkts < budget) {
> > napi_complete(napi);
> > writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
> >+
> >+ if (fec_enet_recover_rxqs(fep) && napi_reschedule(napi))
> >+ writel(FEC_NAPI_IMASK, fep->hwp + FEC_IMASK);
> > }
> > return pkts;
> > }
> >--
> >2.5.5
>
--
Chris Lesiak
Principal Design Engineer, Software
LI-COR Biosciences
chris.lesiak@licor.com
Any opinions expressed are those of the author and
do not necessarily represent those of his employer.
^ permalink raw reply
* [RFC PATCH v2 2/2] macb: Enable 1588 support in SAMA5D2 platform.
From: Andrei Pistirica @ 2016-11-18 14:21 UTC (permalink / raw)
To: netdev, linux-kernel, linux-arm-kernel, davem, nicolas.ferre,
harinikatakamlinux, harini.katakam
Cc: punnaia, michals, anirudh, boris.brezillon, alexandre.belloni,
tbultel, richardcochran, Andrei Pistirica
In-Reply-To: <1479478912-14067-1-git-send-email-andrei.pistirica@microchip.com>
Hardware time stamp on the PTP Ethernet packets are received using the
SO_TIMESTAMPING API. Where timers are obtained from the PTP event/peer
registers.
Signed-off-by: Andrei Pistirica <andrei.pistirica@microchip.com>
---
Version 2 patch for: https://patchwork.kernel.org/patch/9310991/
Modificaions:
- add PTP caps for SAMA5D2/3/4 platforms
- and cosmetic changes
drivers/net/ethernet/cadence/macb.c | 24 +++-
drivers/net/ethernet/cadence/macb.h | 13 ++
drivers/net/ethernet/cadence/macb_ptp.c | 222 ++++++++++++++++++++++++++++++++
3 files changed, 254 insertions(+), 5 deletions(-)
diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
index d975882..eb66b76 100644
--- a/drivers/net/ethernet/cadence/macb.c
+++ b/drivers/net/ethernet/cadence/macb.c
@@ -697,6 +697,8 @@ static void macb_tx_interrupt(struct macb_queue *queue)
/* First, update TX stats if needed */
if (skb) {
+ macb_ptp_do_txstamp(bp, skb);
+
netdev_vdbg(bp->dev, "skb %u (data %p) TX complete\n",
macb_tx_ring_wrap(tail), skb->data);
bp->stats.tx_packets++;
@@ -853,6 +855,8 @@ static int gem_rx(struct macb *bp, int budget)
GEM_BFEXT(RX_CSUM, ctrl) & GEM_RX_CSUM_CHECKED_MASK)
skb->ip_summed = CHECKSUM_UNNECESSARY;
+ macb_ptp_do_rxstamp(bp, skb);
+
bp->stats.rx_packets++;
bp->stats.rx_bytes += skb->len;
@@ -1946,6 +1950,8 @@ static int macb_open(struct net_device *dev)
netif_tx_start_all_queues(dev);
+ macb_ptp_init(dev);
+
return 0;
}
@@ -2204,7 +2210,7 @@ static const struct ethtool_ops gem_ethtool_ops = {
.get_regs_len = macb_get_regs_len,
.get_regs = macb_get_regs,
.get_link = ethtool_op_get_link,
- .get_ts_info = ethtool_op_get_ts_info,
+ .get_ts_info = macb_get_ts_info,
.get_ethtool_stats = gem_get_ethtool_stats,
.get_strings = gem_get_ethtool_strings,
.get_sset_count = gem_get_sset_count,
@@ -2221,7 +2227,14 @@ static int macb_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
if (!phydev)
return -ENODEV;
- return phy_mii_ioctl(phydev, rq, cmd);
+ switch (cmd) {
+ case SIOCSHWTSTAMP:
+ return macb_hwtst_set(dev, rq, cmd);
+ case SIOCGHWTSTAMP:
+ return macb_hwtst_get(dev, rq);
+ default:
+ return phy_mii_ioctl(phydev, rq, cmd);
+ }
}
static int macb_set_features(struct net_device *netdev,
@@ -2812,7 +2825,7 @@ static const struct macb_config pc302gem_config = {
};
static const struct macb_config sama5d2_config = {
- .caps = MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII,
+ .caps = MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII | MACB_CAPS_GEM_HAS_PTP,
.dma_burst_length = 16,
.clk_init = macb_clk_init,
.init = macb_init,
@@ -2820,14 +2833,15 @@ static const struct macb_config sama5d2_config = {
static const struct macb_config sama5d3_config = {
.caps = MACB_CAPS_SG_DISABLED | MACB_CAPS_GIGABIT_MODE_AVAILABLE
- | MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII,
+ | MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII
+ | MACB_CAPS_GEM_HAS_PTP,
.dma_burst_length = 16,
.clk_init = macb_clk_init,
.init = macb_init,
};
static const struct macb_config sama5d4_config = {
- .caps = MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII,
+ .caps = MACB_CAPS_USRIO_DEFAULT_IS_MII_GMII | MACB_CAPS_GEM_HAS_PTP,
.dma_burst_length = 4,
.clk_init = macb_clk_init,
.init = macb_init,
diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h
index 2ee9af8..3ac824a 100644
--- a/drivers/net/ethernet/cadence/macb.h
+++ b/drivers/net/ethernet/cadence/macb.h
@@ -918,8 +918,21 @@ struct macb {
#ifdef CONFIG_MACB_USE_HWSTAMP
void macb_ptp_init(struct net_device *ndev);
+void macb_ptp_do_rxstamp(struct macb *bp, struct sk_buff *skb);
+void macb_ptp_do_txstamp(struct macb *bp, struct sk_buff *skb);
+int macb_ptp_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info);
+#define macb_get_ts_info macb_ptp_get_ts_info
+int macb_hwtst_set(struct net_device *netdev, struct ifreq *ifr, int cmd);
+int macb_hwtst_get(struct net_device *netdev, struct ifreq *ifr);
#else
void macb_ptp_init(struct net_device *ndev) { }
+void macb_ptp_do_rxstamp(struct macb *bp, struct sk_buff *skb) { }
+void macb_ptp_do_txstamp(struct macb *bp, struct sk_buff *skb) { }
+#define macb_get_ts_info ethtool_op_get_ts_info
+int macb_hwtst_set(struct net_device *netdev, struct ifreq *ifr, int cmd)
+ { return -EOPNOTSUPP; }
+int macb_hwtst_get(struct net_device *netdev, struct ifreq *ifr)
+ { return -EOPNOTSUPP; }
#endif
static inline bool macb_is_gem(struct macb *bp)
diff --git a/drivers/net/ethernet/cadence/macb_ptp.c b/drivers/net/ethernet/cadence/macb_ptp.c
index 81ce3a9..f476b55 100644
--- a/drivers/net/ethernet/cadence/macb_ptp.c
+++ b/drivers/net/ethernet/cadence/macb_ptp.c
@@ -227,3 +227,225 @@ void macb_ptp_init(struct net_device *ndev)
dev_info(&bp->pdev->dev, "%s ptp clock registered.\n", GMAC_TIMER_NAME);
}
+/* While the GEM can timestamp PTP packets, it does not mark the RX descriptor
+ * to identify them. UDP packets must be parsed to identify PTP packets.
+ *
+ * Note: Inspired from drivers/net/ethernet/ti/cpts.c
+ */
+static int macb_get_ptp_peer(struct sk_buff *skb, int ptp_class)
+{
+ unsigned int offset = 0;
+ u8 *msgtype, *data = skb->data;
+
+ /* PTP frames are rare! */
+ if (likely(ptp_class == PTP_CLASS_NONE))
+ return -1;
+
+ if (ptp_class & PTP_CLASS_VLAN)
+ offset += VLAN_HLEN;
+
+ switch (ptp_class & PTP_CLASS_PMASK) {
+ case PTP_CLASS_IPV4:
+ offset += ETH_HLEN + IPV4_HLEN(data + offset) + UDP_HLEN;
+ break;
+ case PTP_CLASS_IPV6:
+ offset += ETH_HLEN + IP6_HLEN + UDP_HLEN;
+ break;
+ case PTP_CLASS_L2:
+ offset += ETH_HLEN;
+ break;
+
+ /* something went wrong! */
+ default:
+ return -1;
+ }
+
+ if (skb->len + ETH_HLEN < offset + OFF_PTP_SEQUENCE_ID)
+ return -1;
+
+ if (unlikely(ptp_class & PTP_CLASS_V1))
+ msgtype = data + offset + OFF_PTP_CONTROL;
+ else
+ msgtype = data + offset;
+
+ return (*msgtype) & 0x2;
+}
+
+static void macb_ptp_tx_hwtstamp(struct macb *bp, struct sk_buff *skb,
+ int peer_ev)
+{
+ struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb);
+ struct timespec64 ts;
+ u64 ns;
+
+ /* PTP Peer Event Frame packets */
+ if (peer_ev) {
+ ts.tv_sec = gem_readl(bp, PEFTSL);
+ ts.tv_nsec = gem_readl(bp, PEFTN);
+
+ /* PTP Event Frame packets */
+ } else {
+ ts.tv_sec = gem_readl(bp, EFTSL);
+ ts.tv_nsec = gem_readl(bp, EFTN);
+ }
+ ns = timespec64_to_ns(&ts);
+
+ memset(shhwtstamps, 0, sizeof(struct skb_shared_hwtstamps));
+ shhwtstamps->hwtstamp = ns_to_ktime(ns);
+ skb_tstamp_tx(skb, skb_hwtstamps(skb));
+}
+
+/* no static since it is called from macb driver! */
+void macb_ptp_do_txstamp(struct macb *bp, struct sk_buff *skb)
+{
+ if (!bp->hwts_tx_en)
+ return;
+
+ if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) {
+ int class = ptp_classify_raw(skb);
+ int peer;
+
+ peer = macb_get_ptp_peer(skb, class);
+ if (peer < 0)
+ return;
+
+ /* Timestamp this packet */
+ macb_ptp_tx_hwtstamp(bp, skb, peer);
+ }
+}
+
+static void macb_ptp_rx_hwtstamp(struct macb *bp, struct sk_buff *skb,
+ int peer_ev)
+{
+ struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb);
+ struct timespec64 ts;
+ u64 ns;
+
+ if (peer_ev) {
+ /* PTP Peer Event Frame packets */
+ ts.tv_sec = gem_readl(bp, PEFRSL);
+ ts.tv_nsec = gem_readl(bp, PEFRN);
+ } else {
+ /* PTP Event Frame packets */
+ ts.tv_sec = gem_readl(bp, EFRSL);
+ ts.tv_nsec = gem_readl(bp, EFRN);
+ }
+ ns = timespec64_to_ns(&ts);
+
+ memset(shhwtstamps, 0, sizeof(struct skb_shared_hwtstamps));
+ shhwtstamps->hwtstamp = ns_to_ktime(ns);
+}
+
+/* no static since it is called from macb driver! */
+void macb_ptp_do_rxstamp(struct macb *bp, struct sk_buff *skb)
+{
+ int class;
+ int peer;
+
+ if (!bp->hwts_rx_en)
+ return;
+
+ __skb_push(skb, ETH_HLEN);
+ class = ptp_classify_raw(skb);
+ __skb_pull(skb, ETH_HLEN);
+
+ peer = macb_get_ptp_peer(skb, class);
+ if (peer < 0)
+ return;
+
+ macb_ptp_rx_hwtstamp(bp, skb, peer);
+}
+
+int macb_ptp_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info)
+{
+ struct macb *bp = netdev_priv(dev);
+
+ ethtool_op_get_ts_info(dev, info);
+ info->so_timestamping =
+ SOF_TIMESTAMPING_TX_SOFTWARE |
+ SOF_TIMESTAMPING_RX_SOFTWARE |
+ SOF_TIMESTAMPING_SOFTWARE |
+ SOF_TIMESTAMPING_TX_HARDWARE |
+ SOF_TIMESTAMPING_RX_HARDWARE |
+ SOF_TIMESTAMPING_RAW_HARDWARE;
+ info->phc_index = -1;
+
+ if (bp->ptp_clock)
+ info->phc_index = ptp_clock_index(bp->ptp_clock);
+
+ return 0;
+}
+
+int macb_hwtst_set(struct net_device *netdev, struct ifreq *ifr, int cmd)
+{
+ struct hwtstamp_config config;
+ struct macb *priv = netdev_priv(netdev);
+ u32 regval;
+
+ netdev_vdbg(netdev, "macb_hwtstamp_ioctl\n");
+
+ if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
+ return -EFAULT;
+
+ /* reserved for future extensions */
+ if (config.flags)
+ return -EINVAL;
+
+ switch (config.tx_type) {
+ case HWTSTAMP_TX_OFF:
+ priv->hwts_tx_en = 0;
+ break;
+ case HWTSTAMP_TX_ON:
+ priv->hwts_tx_en = 1;
+ break;
+ default:
+ return -ERANGE;
+ }
+
+ switch (config.rx_filter) {
+ case HWTSTAMP_FILTER_NONE:
+ if (priv->hwts_rx_en)
+ priv->hwts_rx_en = 0;
+ break;
+ case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
+ case HWTSTAMP_FILTER_ALL:
+ case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
+ case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
+ case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
+ case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
+ case HWTSTAMP_FILTER_PTP_V2_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
+ config.rx_filter = HWTSTAMP_FILTER_ALL;
+ regval = macb_readl(priv, NCR);
+ macb_writel(priv, NCR, (regval | MACB_BIT(SRTSM)));
+
+ if (!priv->hwts_rx_en)
+ priv->hwts_rx_en = 1;
+ break;
+ default:
+ return -ERANGE;
+ }
+
+ return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
+ -EFAULT : 0;
+}
+
+int macb_hwtst_get(struct net_device *netdev, struct ifreq *ifr)
+{
+ struct hwtstamp_config config;
+ struct macb *priv = netdev_priv(netdev);
+
+ config.flags = 0;
+ config.tx_type = priv->hwts_tx_en ? HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF;
+ config.rx_filter = (priv->hwts_rx_en ?
+ HWTSTAMP_FILTER_ALL : HWTSTAMP_FILTER_NONE);
+
+ return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
+ -EFAULT : 0;
+}
+
--
1.9.1
^ permalink raw reply related
* [RFC PATCH v2 1/2] macb: Add 1588 support in Cadence GEM.
From: Andrei Pistirica @ 2016-11-18 14:21 UTC (permalink / raw)
To: netdev, linux-kernel, linux-arm-kernel, davem, nicolas.ferre,
harinikatakamlinux, harini.katakam
Cc: punnaia, michals, anirudh, boris.brezillon, alexandre.belloni,
tbultel, richardcochran, Andrei Pistirica
Cadence GEM provides a 102 bit time counter with 48 bits for seconds,
30 bits for nsecs and 24 bits for sub-nsecs to control 1588 timestamping.
This patch does the following:
- Registers to ptp clock framework
- Timer initialization is done by writing time of day to the timer counter.
- ns increment register is programmed as NSEC_PER_SEC/TSU_CLK.
For a 16 bit subns precision, the subns increment equals
remainder of (NS_PER_SEC/TSU_CLK) * (2^16).
- HW time stamp capabilities are advertised via ethtool and macb ioctl is
updated accordingly.
- Timestamps are obtained from the TX/RX PTP event/PEER registers.
The timestamp obtained thus is updated in skb for upper layers to access.
- The drivers register functions with ptp to perform time and frequency
adjustment.
- Time adjustment is done by writing to the 1558_ADJUST register.
The controller will read the delta in this register and update the timer
counter register. Alternatively, for large time offset adjustments,
the driver reads the secs and nsecs counter values, adds/subtracts the
delta and updates the timer counter.
- Frequency adjustment is not directly supported by this IP.
addend is the initial value ns increment and similarly addendesub.
The ppb (parts per billion) provided is used as
ns_incr = addend +/- (ppb/rate).
Similarly the remainder of the above is used to populate subns increment.
In case the ppb requested is negative AND subns adjustment greater than
the addendsub, ns_incr is reduced by 1 and subns_incr is adjusted in
positive accordingly.
Signed-off-by: Andrei Pistirica <andrei.pistirica@microchip.com>
Signed-off-by: Harini Katakam <harinik@xilinx.com>
---
Version 2 patch for: https://patchwork.kernel.org/patch/9310989/.
Modifications:
- bitfields for TSU are named according to SAMA5D2 data sheet
- identify GEM-PTP support based on platform capability
- add spinlock for TSU access
- change macb_ptp_adjfreq and use fewer 64bit divisions
drivers/net/ethernet/cadence/Kconfig | 10 +-
drivers/net/ethernet/cadence/Makefile | 8 +-
drivers/net/ethernet/cadence/macb.h | 80 +++++++++++
drivers/net/ethernet/cadence/macb_ptp.c | 229 ++++++++++++++++++++++++++++++++
4 files changed, 325 insertions(+), 2 deletions(-)
create mode 100644 drivers/net/ethernet/cadence/macb_ptp.c
diff --git a/drivers/net/ethernet/cadence/Kconfig b/drivers/net/ethernet/cadence/Kconfig
index f0bcb15..ebbc65f 100644
--- a/drivers/net/ethernet/cadence/Kconfig
+++ b/drivers/net/ethernet/cadence/Kconfig
@@ -29,6 +29,14 @@ config MACB
support for the MACB/GEM chip.
To compile this driver as a module, choose M here: the module
- will be called macb.
+ will be called cadence-macb.
+
+config MACB_USE_HWSTAMP
+ bool "Use IEEE 1588 hwstamp"
+ depends on MACB
+ default y
+ select PTP_1588_CLOCK
+ ---help---
+ Enable IEEE 1588 Precision Time Protocol (PTP) support for MACB.
endif # NET_CADENCE
diff --git a/drivers/net/ethernet/cadence/Makefile b/drivers/net/ethernet/cadence/Makefile
index 91f79b1..4402d42 100644
--- a/drivers/net/ethernet/cadence/Makefile
+++ b/drivers/net/ethernet/cadence/Makefile
@@ -2,4 +2,10 @@
# Makefile for the Atmel network device drivers.
#
-obj-$(CONFIG_MACB) += macb.o
+cadence-macb-y := macb.o
+
+ifeq ($(CONFIG_MACB_USE_HWSTAMP),y)
+cadence-macb-y += macb_ptp.o
+endif
+
+obj-$(CONFIG_MACB) += cadence-macb.o
diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h
index 3f385ab..2ee9af8 100644
--- a/drivers/net/ethernet/cadence/macb.h
+++ b/drivers/net/ethernet/cadence/macb.h
@@ -10,6 +10,10 @@
#ifndef _MACB_H
#define _MACB_H
+#include <linux/net_tstamp.h>
+#include <linux/ptp_clock.h>
+#include <linux/ptp_clock_kernel.h>
+
#define MACB_GREGS_NBR 16
#define MACB_GREGS_VERSION 2
#define MACB_MAX_QUEUES 8
@@ -129,6 +133,20 @@
#define GEM_RXIPCCNT 0x01a8 /* IP header Checksum Error Counter */
#define GEM_RXTCPCCNT 0x01ac /* TCP Checksum Error Counter */
#define GEM_RXUDPCCNT 0x01b0 /* UDP Checksum Error Counter */
+#define GEM_TISUBN 0x01bc /* 1588 Timer Increment Sub-ns */
+#define GEM_TSH 0x01c0 /* 1588 Timer Seconds High */
+#define GEM_TSL 0x01d0 /* 1588 Timer Seconds Low */
+#define GEM_TN 0x01d4 /* 1588 Timer Nanoseconds */
+#define GEM_TA 0x01d8 /* 1588 Timer Adjust */
+#define GEM_TI 0x01dc /* 1588 Timer Increment */
+#define GEM_EFTSL 0x01e0 /* PTP Event Frame Tx Seconds Low */
+#define GEM_EFTN 0x01e4 /* PTP Event Frame Tx Nanoseconds */
+#define GEM_EFRSL 0x01e8 /* PTP Event Frame Rx Seconds Low */
+#define GEM_EFRN 0x01ec /* PTP Event Frame Rx Nanoseconds */
+#define GEM_PEFTSL 0x01f0 /* PTP Peer Event Frame Tx Secs Low */
+#define GEM_PEFTN 0x01f4 /* PTP Peer Event Frame Tx Ns */
+#define GEM_PEFRSL 0x01f8 /* PTP Peer Event Frame Rx Sec Low */
+#define GEM_PEFRN 0x01fc /* PTP Peer Event Frame Rx Ns */
#define GEM_DCFG1 0x0280 /* Design Config 1 */
#define GEM_DCFG2 0x0284 /* Design Config 2 */
#define GEM_DCFG3 0x0288 /* Design Config 3 */
@@ -171,6 +189,7 @@
#define MACB_NCR_TPF_SIZE 1
#define MACB_TZQ_OFFSET 12 /* Transmit zero quantum pause frame */
#define MACB_TZQ_SIZE 1
+#define MACB_SRTSM_OFFSET 15
/* Bitfields in NCFGR */
#define MACB_SPD_OFFSET 0 /* Speed */
@@ -312,6 +331,36 @@
#define MACB_PFR_SIZE 1
#define MACB_PTZ_OFFSET 13 /* Enable pause time zero interrupt */
#define MACB_PTZ_SIZE 1
+#define MACB_PFTR_OFFSET 14 /* Pause Frame Transmitted */
+#define MACB_PFTR_SIZE 1
+#define MACB_DRQFR_OFFSET 18 /* PTP Delay Request Frame Received */
+#define MACB_DRQFR_SIZE 1
+#define MACB_SFR_OFFSET 19 /* PTP Sync Frame Received */
+#define MACB_SFR_SIZE 1
+#define MACB_DRQFT_OFFSET 20 /* PTP Delay Request Frame Transmitted */
+#define MACB_DRQFT_SIZE 1
+#define MACB_SFT_OFFSET 21 /* PTP Sync Frame Transmitted */
+#define MACB_SFT_SIZE 1
+#define MACB_PDRQFR_OFFSET 22 /* PDelay Request Frame Received */
+#define MACB_PDRQFR_SIZE 1
+#define MACB_PDRSFR_OFFSET 23 /* PDelay Response Frame Received */
+#define MACB_PDRSFR_SIZE 1
+#define MACB_PDRQFT_OFFSET 24 /* PDelay Request Frame Transmitted */
+#define MACB_PDRQFT_SIZE 1
+#define MACB_PDRSFT_OFFSET 25 /* PDelay Response Frame Transmitted */
+#define MACB_PDRSFT_SIZE 1
+#define MACB_SRI_OFFSET 26 /* TSU Seconds Register Increment */
+#define MACB_SRI_SIZE 1
+#define MACB_WOL_OFFSET 28 /* Wake On LAN */
+#define MACB_WOL_SIZE 1
+
+/* Timer increment fields */
+#define MACB_TI_CNS_OFFSET 0
+#define MACB_TI_CNS_SIZE 8
+#define MACB_TI_ACNS_OFFSET 8
+#define MACB_TI_ACNS_SIZE 8
+#define MACB_TI_NIT_OFFSET 16
+#define MACB_TI_NIT_SIZE 8
/* Bitfields in MAN */
#define MACB_DATA_OFFSET 0 /* data */
@@ -375,6 +424,18 @@
#define GEM_TX_PKT_BUFF_OFFSET 21
#define GEM_TX_PKT_BUFF_SIZE 1
+/* Bitfields in TISUBN */
+#define GEM_SUBNSINCR_OFFSET 0
+#define GEM_SUBNSINCR_SIZE 16
+
+/* Bitfields in TI */
+#define GEM_NSINCR_OFFSET 0
+#define GEM_NSINCR_SIZE 8
+
+/* Bitfields in ADJ */
+#define GEM_ADDSUB_OFFSET 31
+#define GEM_ADDSUB_SIZE 1
+
/* Constants for CLK */
#define MACB_CLK_DIV8 0
#define MACB_CLK_DIV16 1
@@ -405,6 +466,7 @@
#define MACB_CAPS_SG_DISABLED 0x40000000
#define MACB_CAPS_MACB_IS_GEM 0x80000000
#define MACB_CAPS_JUMBO 0x00000010
+#define MACB_CAPS_GEM_HAS_PTP 0x00000020
/* Bit manipulation macros */
#define MACB_BIT(name) \
@@ -840,8 +902,26 @@ struct macb {
unsigned int rx_frm_len_mask;
unsigned int jumbo_max_len;
+
+#ifdef CONFIG_MACB_USE_HWSTAMP
+ unsigned int hwts_tx_en;
+ unsigned int hwts_rx_en;
+ spinlock_t tsu_clk_lock;
+ unsigned int tsu_rate;
+
+ struct ptp_clock *ptp_clock;
+ struct ptp_clock_info ptp_caps;
+ unsigned int ns_incr;
+ unsigned int subns_incr;
+#endif
};
+#ifdef CONFIG_MACB_USE_HWSTAMP
+void macb_ptp_init(struct net_device *ndev);
+#else
+void macb_ptp_init(struct net_device *ndev) { }
+#endif
+
static inline bool macb_is_gem(struct macb *bp)
{
return !!(bp->caps & MACB_CAPS_MACB_IS_GEM);
diff --git a/drivers/net/ethernet/cadence/macb_ptp.c b/drivers/net/ethernet/cadence/macb_ptp.c
new file mode 100644
index 0000000..81ce3a9
--- /dev/null
+++ b/drivers/net/ethernet/cadence/macb_ptp.c
@@ -0,0 +1,229 @@
+/*
+ * PTP 1588 clock for SAMA5D2 platform.
+ *
+ * Copyright (C) 2015 Xilinx Inc.
+ * Copyright (C) 2016 Microchip Technology
+ *
+ * Authors: Harini Katakam <harinik@xilinx.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/etherdevice.h>
+#include <linux/platform_device.h>
+#include <linux/time64.h>
+#include <linux/ptp_classify.h>
+#include <linux/if_ether.h>
+#include <linux/if_vlan.h>
+
+#include "macb.h"
+
+#define GMAC_TIMER_NAME "gmac-gem-ptp"
+
+static inline void macb_tsu_get_time(struct macb *bp, struct timespec64 *ts)
+{
+ u64 sec, sech, secl;
+
+ spin_lock(&bp->tsu_clk_lock);
+
+ /* get GEM internal time */
+ sech = gem_readl(bp, TSH);
+ secl = gem_readl(bp, TSL);
+ ts->tv_nsec = gem_readl(bp, TN);
+ ts->tv_sec = (sech << 32) | secl;
+
+ /* minimize the error */
+ sech = gem_readl(bp, TSH);
+ secl = gem_readl(bp, TSL);
+ sec = (sech << 32) | secl;
+ if (ts->tv_sec != sec) {
+ ts->tv_sec = sec;
+ ts->tv_nsec = gem_readl(bp, TN);
+ }
+
+ spin_unlock(&bp->tsu_clk_lock);
+}
+
+static inline void macb_tsu_set_time(struct macb *bp,
+ const struct timespec64 *ts)
+{
+ u32 ns, sech, secl;
+ s64 word_mask = 0xffffffff;
+
+ sech = (u32)ts->tv_sec;
+ secl = (u32)ts->tv_sec;
+ ns = ts->tv_nsec;
+ if (ts->tv_sec > word_mask)
+ sech = (ts->tv_sec >> 32);
+
+ spin_lock(&bp->tsu_clk_lock);
+
+ /* TSH doesn't latch the time and no atomicity! */
+ gem_writel(bp, TSH, sech);
+ gem_writel(bp, TSL, secl);
+ gem_writel(bp, TN, ns);
+
+ spin_unlock(&bp->tsu_clk_lock);
+}
+
+static int macb_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
+{
+ struct macb *bp = container_of(ptp, struct macb, ptp_caps);
+ u32 addend, addend_frac, rem;
+ u64 drift_tmr, diff, diff_frac = 0;
+ int neg_adj = 0;
+
+ if (ppb < 0) {
+ neg_adj = 1;
+ ppb = -ppb;
+ }
+
+ /* drift/period */
+ drift_tmr = (bp->ns_incr * ppb) +
+ ((bp->subns_incr * ppb) >> 16);
+
+ /* drift/cycle */
+ diff = div_u64_rem(drift_tmr, 1000000000ULL, &rem);
+
+ /* drift fraction/cycle, if necessary */
+ if (rem) {
+ u64 fraction = rem;
+ fraction = fraction << 16;
+
+ diff_frac = div_u64(fraction, 1000000000ULL);
+ }
+
+ /* adjustmets */
+ addend = neg_adj ? (bp->ns_incr - diff) : (bp->ns_incr + diff);
+ addend_frac = neg_adj ? (bp->subns_incr - diff_frac) :
+ (bp->subns_incr + diff_frac);
+
+ spin_lock(&bp->tsu_clk_lock);
+
+ gem_writel(bp, TISUBN, GEM_BF(SUBNSINCR, addend_frac));
+ gem_writel(bp, TI, GEM_BF(NSINCR, addend));
+
+ spin_unlock(&bp->tsu_clk_lock);
+ return 0;
+}
+
+static int macb_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
+{
+ struct macb *bp = container_of(ptp, struct macb, ptp_caps);
+ struct timespec64 now, then = ns_to_timespec64(delta);
+ u32 adj, sign = 0;
+
+ if (delta < 0) {
+ delta = -delta;
+ sign = 1;
+ }
+
+ if (delta > 0x3FFFFFFF) {
+ macb_tsu_get_time(bp, &now);
+
+ if (sign)
+ now = timespec64_sub(now, then);
+ else
+ now = timespec64_add(now, then);
+
+ macb_tsu_set_time(bp, (const struct timespec64 *)&now);
+ } else {
+ adj = delta;
+ if (sign)
+ adj |= GEM_BIT(ADDSUB);
+
+ gem_writel(bp, TA, adj);
+ }
+
+ return 0;
+}
+
+static int macb_ptp_gettime(struct ptp_clock_info *ptp,
+ struct timespec64 *ts)
+{
+ struct macb *bp = container_of(ptp, struct macb, ptp_caps);
+
+ macb_tsu_get_time(bp, ts);
+
+ return 0;
+}
+
+static int macb_ptp_settime(struct ptp_clock_info *ptp,
+ const struct timespec64 *ts)
+{
+ struct macb *bp = container_of(ptp, struct macb, ptp_caps);
+
+ macb_tsu_set_time(bp, ts);
+
+ return 0;
+}
+
+static int macb_ptp_enable(struct ptp_clock_info *ptp,
+ struct ptp_clock_request *rq, int on)
+{
+ return -EOPNOTSUPP;
+}
+
+static struct ptp_clock_info macb_ptp_caps = {
+ .owner = THIS_MODULE,
+ .name = GMAC_TIMER_NAME,
+ .max_adj = 250000000,
+ .n_alarm = 0,
+ .n_ext_ts = 0,
+ .n_per_out = 0,
+ .n_pins = 0,
+ .pps = 0,
+ .adjfreq = macb_ptp_adjfreq,
+ .adjtime = macb_ptp_adjtime,
+ .gettime64 = macb_ptp_gettime,
+ .settime64 = macb_ptp_settime,
+ .enable = macb_ptp_enable,
+};
+
+void macb_ptp_init(struct net_device *ndev)
+{
+ struct macb *bp = netdev_priv(ndev);
+ struct timespec64 now;
+ u32 rem = 0;
+
+ if (!(bp->caps | MACB_CAPS_GEM_HAS_PTP)){
+ netdev_vdbg(bp->dev, "Platform does not support PTP!\n");
+ return;
+ }
+
+ spin_lock_init(&bp->tsu_clk_lock);
+
+ bp->ptp_caps = macb_ptp_caps;
+ bp->tsu_rate = clk_get_rate(bp->pclk);
+
+ getnstimeofday64(&now);
+ macb_tsu_set_time(bp, (const struct timespec64 *)&now);
+
+ bp->ns_incr = div_u64_rem(NSEC_PER_SEC, bp->tsu_rate, &rem);
+ if (rem) {
+ u64 adj = rem;
+ /* Multiply by 2^16 as subns register is 16 bits */
+ adj <<= 16;
+ bp->subns_incr = div_u64(adj, bp->tsu_rate);
+ } else {
+ bp->subns_incr = 0;
+ }
+
+ gem_writel(bp, TISUBN, GEM_BF(SUBNSINCR, bp->subns_incr));
+ gem_writel(bp, TI, GEM_BF(NSINCR, bp->ns_incr));
+ gem_writel(bp, TA, 0);
+
+ bp->ptp_clock = ptp_clock_register(&bp->ptp_caps, NULL);
+ if (IS_ERR(&bp->ptp_clock)) {
+ bp->ptp_clock = NULL;
+ pr_err("ptp clock register failed\n");
+ return;
+ }
+
+ dev_info(&bp->pdev->dev, "%s ptp clock registered.\n", GMAC_TIMER_NAME);
+}
+
--
1.9.1
^ permalink raw reply related
* Re: Synopsys Ethernet QoS Driver
From: Joao Pinto @ 2016-11-18 14:20 UTC (permalink / raw)
To: mued dib, Joao Pinto
Cc: davem, jeffrey.t.kirsher, jiri, saeedm, idosch, netdev,
linux-kernel, CARLOS.PALMINHA, andreas.irestal
In-Reply-To: <CADvZ6ErjyVR5ShWTk0QesWLYR1m3p8yAMkK8v9gm2kN5xTv8zw@mail.gmail.com>
Hello Ozgur,
Thanks for your feedback.
On 18-11-2016 13:09, mued dib wrote:
> Dear Joao;
>
> thanks for support and this project is good. I have some questions, Linux
> already support to QoS with "tc". right?
>
> Can you send us a list of driver files you are interested?
For now we are interesting in improving the synopsys QoS driver under
/nect/ethernet/synopsys. For now the driver structure consists of a single file
called dwc_eth_qos.c, containing synopsys ethernet qos common ops and platform
related stuff.
Our strategy would be:
a) Implement a platform glue driver (dwc_eth_qos_pltfm.c)
b) Implement a pci glue driver (dwc_eth_qos_pci.c)
c) Implement a "core driver" (dwc_eth_qos.c) that would only have Ethernet QoS
related stuff to be reused by the platform / pci drivers
d) Add a set of features to the "core driver" that we have available internally
Thanks,
Joao
>
> Regards,
>
> Ozgur Karatas
>
> 2016-11-18 15:28 GMT+03:00 Joao Pinto <Joao.Pinto@synopsys.com>:
>
>>
>> Dear all,
>>
>> My name is Joao Pinto and I work at Synopsys.
>> I am a kernel developer with special focus in mainline collaboration, both
>> Linux
>> and Buildroot. I was recently named one of the maintainers of the PCIe
>> Designware core driver and I was the author of the Designware UFS driver
>> stack.
>>
>> I am sending you this e-mail because you were the suggested contacts from
>> the
>> get_maintainers script concerning Ethernet drivers :).
>>
>> Currently I have the task to work on the mainline Ethernet QoS driver in
>> which
>> you are the author. The work would consist of the following:
>>
>> a) Separate the current driver in a Core driver (common ops) + platform
>> glue
>> driver + pci glue driver
>> b) Add features that are currently only available internally
>> c) Add specific phy support using the PHY framework
>>
>> I would also gladly be available to be its maintainer if you agree with it.
>>
>> It would be great to have your collaboration in the project if you are
>> available
>> to review the work in progress.
>>
>> Thank you and I am looking forward for your feedback!
>>
>> Joao Pinto
>>
>
^ permalink raw reply
* Re: [PATCH iproute2 0/2] tc: flower: Support matching on SCTP ports
From: Simon Horman @ 2016-11-18 13:27 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: David Miller, netdev
In-Reply-To: <20161112103209.242d3e5e@samsung9>
On Sat, Nov 12, 2016 at 10:32:09AM +0300, Stephen Hemminger wrote:
> On Thu, 3 Nov 2016 13:26:39 +0100
> Simon Horman <simon.horman@netronome.com> wrote:
>
> > Hi,
> >
> > this short series adds support for matching on SCTP ports in the same way
> > that matching on TCP and UDP ports is already supported. It corresponds to
> > a net-next patch to add the same support to the kernel.
> >
> > Example usage:
> >
> > tc qdisc add dev eth0 ingress
> >
> > tc filter add dev eth0 protocol ip parent ffff: \
> > flower indev eth0 ip_proto sctp dst_port 80 \
> > action drop
> >
> >
> > Simon Horman (2):
> > tc: update headers for TCA_FLOWER_KEY_SCTP_*
> > tc: flower: Support matching on SCTP ports
> >
> > include/linux/pkt_cls.h | 5 ++++
> > tc/f_flower.c | 65 +++++++++++++++++++++++--------------------------
> > 2 files changed, 36 insertions(+), 34 deletions(-)
> >
>
> Applied, thanks.
Hi Stephen,
I'm not seeing these on
git://git.kernel.org/pub/scm/linux/kernel/git/shemminger/iproute2.git
Could you push them or let me know where to look?
I found a few problems that want fixing.
^ permalink raw reply
* Re: [RFC PATCH 2/3] net: macb: Add support for 1588 for Zynq Ultrascale+ MPSoC
From: Rafal Ozieblo @ 2016-11-18 13:03 UTC (permalink / raw)
To: harini.katakam@xilinx.com
Cc: Nicolas Ferre, Andrei Pistirica, netdev@vger.kernel.org,
linux-kernel@vger.kernel.org, Richard Cochran
>+static inline void macb_handle_txtstamp(struct macb *bp, struct sk_buff *skb,
>+ struct macb_dma_desc *desc)
>+{
>+ u32 ts_s, ts_ns;
>+ u8 msg_type;
>+
>+ skb_copy_from_linear_data_offset(skb, GEM_TX_PTPHDR_OFFSET,
>+ &msg_type, 1);
>+
>+ /* Bit[32:6] of TS secs from register
>+ * Bit[5:0] of TS secs from BD
>+ * TS nano secs is available in BD
>+ */
>+ if (msg_type & 0x2) {
>+ /* PTP Peer Event Frame packets */
>+ ts_s = (gem_readl(bp, 1588PEERTXSEC) & GEM_SEC_MASK) |
>+ ((desc->tsl >> GEM_TSL_SEC_RS) |
>+ (desc->tsh << GEM_TSH_SEC_LS));
>+ ts_ns = desc->tsl & GEM_TSL_NSEC_MASK;
>+ } else {
>+ /* PTP Event Frame packets */
>+ ts_s = (gem_readl(bp, 1588TXSEC) & GEM_SEC_MASK) |
>+ ((desc->tsl >> GEM_TSL_SEC_RS) |
>+ (desc->tsh << GEM_TSH_SEC_LS));
>+ ts_ns = desc->tsl & GEM_TSL_NSEC_MASK;
>+ }
>+
>+ struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb);
>+
>+ memset(shhwtstamps, 0, sizeof(struct skb_shared_hwtstamps));
>+ shhwtstamps->hwtstamp = ns_to_ktime((ts_s * NS_PER_SEC) + ts_ns);
>+ skb_tstamp_tx(skb, skb_hwtstamps(skb));
>+}
>+
> static void macb_tx_interrupt(struct macb_queue *queue)
> {
> unsigned int tail;
>@@ -703,6 +745,10 @@ static void macb_tx_interrupt(struct macb_queue *queue)
> bp->stats.tx_bytes += skb->len;
> }
>
>+#ifdef CONFIG_MACB_EXT_BD
>+ if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)
>+ macb_handle_txtstamp(bp, skb, desc);
>+#endif
> /* Now we can safely release resources */
> macb_tx_unmap(bp, tx_skb);
>
>@@ -796,6 +842,39 @@ static void discard_partial_frame(struct macb *bp,
>unsigned int begin,
> */
> }
I think, you can not do it in that way.
It will hold two locks. If you enable appropriate option in kernel (as far as I remember CONFIG_DEBUG_SPINLOCK) you will get a warning here.
Please look at following call-stack:
1. macb_interrupt() // spin_lock(&bp->lock) is taken
2. macb_tx_interrupt()
3. macb_handle_txtstamp()
4. skb_tstamp_tx()
5. __skb_tstamp_tx()
6. skb_may_tx_timestamp()
7. read_lock_bh() // second lock is taken
I know that those are different locks and different types. But this could lead to deadlocks. This is the reason of warning I could see.
And this is the reason why I get timestamp in interrupt routine but pass it to skb outside interrupt (using circular buffer).
Best regards,
Rafal Ozieblo | Firmware System Engineer,
phone nbr.: +48 32 5085469
www.cadence.com
^ permalink raw reply
* Re: [PATCH v8 5/6] net: ipv4, ipv6: run cgroup eBPF egress programs
From: Pablo Neira Ayuso @ 2016-11-18 12:37 UTC (permalink / raw)
To: Daniel Mack
Cc: htejun-b10kYP2dOMg, daniel-FeC+5ew28dpmcu3hnIyYJQ,
ast-b10kYP2dOMg, davem-fT/PcQaiUtIeIZ0/mPfg9Q, kafai-b10kYP2dOMg,
fw-HFFVJYpyMKqzQB+pC5nmwQ, harald-H+wXaHxf7aLQT0dZR+AlfA,
netdev-u79uwXL29TY76Z2rM5mHXA, sargun-GaZTRHToo+CzQB+pC5nmwQ,
cgroups-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1479407229-14861-6-git-send-email-daniel-cYrQPVfZoowdnm+yROfE0A@public.gmane.org>
On Thu, Nov 17, 2016 at 07:27:08PM +0100, Daniel Mack wrote:
[...]
> @@ -312,6 +314,12 @@ int ip_mc_output(struct net *net, struct sock *sk, struct sk_buff *skb)
> skb->dev = dev;
> skb->protocol = htons(ETH_P_IP);
>
> + ret = BPF_CGROUP_RUN_PROG_INET_EGRESS(sk, skb);
> + if (ret) {
> + kfree_skb(skb);
> + return ret;
> + }
> +
> /*
> * Multicasts are looped back for other local users
> */
> @@ -364,12 +372,19 @@ int ip_mc_output(struct net *net, struct sock *sk, struct sk_buff *skb)
> int ip_output(struct net *net, struct sock *sk, struct sk_buff *skb)
> {
> struct net_device *dev = skb_dst(skb)->dev;
> + int ret;
>
> IP_UPD_PO_STATS(net, IPSTATS_MIB_OUT, skb->len);
>
> skb->dev = dev;
> skb->protocol = htons(ETH_P_IP);
>
> + ret = BPF_CGROUP_RUN_PROG_INET_EGRESS(sk, skb);
> + if (ret) {
> + kfree_skb(skb);
> + return ret;
> + }
> +
> return NF_HOOK_COND(NFPROTO_IPV4, NF_INET_POST_ROUTING,
> net, sk, skb, NULL, dev,
> ip_finish_output,
Please, place this after the netfilter hook.
Since this new hook may mangle output packets, any mangling
potentially interfers and breaks conntrack.
Thank you.
^ permalink raw reply
* Synopsys Ethernet QoS Driver
From: Joao Pinto @ 2016-11-18 12:31 UTC (permalink / raw)
To: davem, jeffrey.t.kirsher, jiri, saeedm, idosch
Cc: netdev, linux-kernel, CARLOS.PALMINHA, andreas.irestal
In-Reply-To: <cbe5f79b-53a4-e116-1e09-bc975a66a8ca@synopsys.com>
[The previous e-mail had an error, please consider this one. Thank you.]
Dear all,
My name is Joao Pinto and I work at Synopsys.
I am a kernel developer with special focus in mainline collaboration, both Linux
and Buildroot. I was recently named one of the maintainers of the PCIe
Designware core driver and I was the author of the Designware UFS driver stack.
I am sending you this e-mail because you were the suggested contacts from the
get_maintainers script concerning Ethernet drivers :).
Currently I have the task to work on the mainline Ethernet QoS driver. The work
would consist of the following:
a) Separate the current driver in a Core driver (common ops) + platform glue
driver + pci glue driver
b) Add features that are currently only available internally
c) Add specific phy support using the PHY framework
I would also gladly be available to be its maintainer if you agree with it.
It would be great to have your collaboration in the project if you are available
to review the work in progress.
Thank you and I am looking forward for your feedback!
Joao Pinto
^ permalink raw reply
* Synopsys Ethernet QoS Driver
From: Joao Pinto @ 2016-11-18 12:28 UTC (permalink / raw)
To: davem, jeffrey.t.kirsher, jiri, saeedm, idosch
Cc: netdev, linux-kernel, CARLOS.PALMINHA, andreas.irestal
Dear all,
My name is Joao Pinto and I work at Synopsys.
I am a kernel developer with special focus in mainline collaboration, both Linux
and Buildroot. I was recently named one of the maintainers of the PCIe
Designware core driver and I was the author of the Designware UFS driver stack.
I am sending you this e-mail because you were the suggested contacts from the
get_maintainers script concerning Ethernet drivers :).
Currently I have the task to work on the mainline Ethernet QoS driver in which
you are the author. The work would consist of the following:
a) Separate the current driver in a Core driver (common ops) + platform glue
driver + pci glue driver
b) Add features that are currently only available internally
c) Add specific phy support using the PHY framework
I would also gladly be available to be its maintainer if you agree with it.
It would be great to have your collaboration in the project if you are available
to review the work in progress.
Thank you and I am looking forward for your feedback!
Joao Pinto
^ permalink raw reply
* Re: [PATCH net-next] cadence: Add hardware PTP support.
From: Richard Cochran @ 2016-11-18 12:27 UTC (permalink / raw)
To: Rafal Ozieblo
Cc: Harini Katakam, Nicolas Ferre, Andrei Pistirica,
netdev@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <BN3PR07MB2516D135ECCF2A68C1687EB6C9B00@BN3PR07MB2516.namprd07.prod.outlook.com>
On Fri, Nov 18, 2016 at 11:55:37AM +0000, Rafal Ozieblo wrote:
> >I'm not sure of your application and why this is necessary.
> >Can you please check Andrei's patches and mine and Richard Cochran's comments?
> >I use linuxptp to test.
And please, PLEASE, put me onto CC for all PTP related patches. I am
the maintainer, you know.
Thanks,
Richard
^ permalink raw reply
* [RFC PATCH 1/2] macb: Add 1588 support in Cadence GEM.
From: Rafal Ozieblo @ 2016-11-18 12:05 UTC (permalink / raw)
To: andrei.pistirica@microchip.com
Cc: Nicolas Ferre, harini.katakam@xilinx.com, netdev@vger.kernel.org,
linux-kernel@vger.kernel.org
Hello Andrei,
>+static struct ptp_clock_info macb_ptp_caps = {
>+ .owner = THIS_MODULE,
>+ .name = GMAC_TIMER_NAME,
>+ .max_adj = 250000000,
>+ .n_alarm = 0,
>+ .n_ext_ts = 0,
>+ .n_per_out = 0,
>+ .n_pins = 0,
>+ .pps = 0,
>+ .adjfreq = macb_ptp_adjfreq,
>+ .adjtime = macb_ptp_adjtime,
>+ .gettime64 = macb_ptp_gettime,
>+ .settime64 = macb_ptp_settime,
>+ .enable = macb_ptp_enable,
>+};
I'm wondering, how did you count max_adj ?
Best regards,
Rafal Ozieblo | Firmware System Engineer,
phone nbr.: +48 32 5085469
www.cadence.com
^ permalink raw reply
* Re: [PATCH net 1/2] r8152: fix the sw rx checksum is unavailable
From: Mark Lord @ 2016-11-18 12:03 UTC (permalink / raw)
To: Hayes Wang, netdev@vger.kernel.org
Cc: nic_swsd, linux-kernel@vger.kernel.org, linux-usb@vger.kernel.org
In-Reply-To: <0835B3720019904CB8F7AA43166CEEB201050B7E@RTITMBSV03.realtek.com.tw>
On 16-11-18 02:57 AM, Hayes Wang wrote:
..
> Besides, the maximum data length which the RTL8152 would send to
> the host is 16KB. That is, if the agg_buf_sz is 16KB, the host
> wouldn't split it. However, you still see problems for it.
How does the RTL8152 know that the limit is 16KB,
rather than some other number? Is this a hardwired number
in the hardware, or is it a parameter that the software
sends to the chip during initialization?
I have a USB analyzer, but it is difficult to figure out how
to program an appropriate trigger point for the capture,
since the problem (with 16KB URBs) takes minutes to hours
or even days to trigger.
And the output from the analyzer is in some proprietary format.
The in-kernel software analzer could be useful, but I have never
figured out how to use it. :)
Since my earlier email, I have figured out another piece of the
puzzle with this dongle.
The first issue is that a packet sometimes begins in one URB,
and completes in the next URB, without an rx_desc at the start
of the second URB. This I have already reported earlier.
But the driver, as written, sometimes accesses bytes outside
of the 16KB URB buffer, because it trusts the non-existent
rx_desc in these cases, and also because it accesses bytes
from the rx_desc without first checking whether there is
sufficient remaining space in the URB to hold an rx_desc.
These incorrect accesses sometimes touch memory outside
of the URB buffer. Since the driver allocates all of its
rx URB buffers at once, they are highly likely to be
physically (and therefore virtually) adjacent in memory.
So mistakenly accessing beyond the end of one buffer will
often result in a read from memory of the next URB buffer.
Which causes a portion of it to be loaded in the the D-cache.
When that URB is subsequently filled by DMA, there then exists
a data-consistency issue: the D-cache contains stale information
from before the latest DMA cycle.
So this explains the strange memory behaviour observed earlier on.
When I add a call to invalidate_dcache_range() to the driver
just before it begins examining a new rx URB, the problems go away.
So this confirms the observations.
Using non-cacheable RAM also makes the problem go away.
But neither is a fix for the real buffer overrun accesses in the driver.
Fix the "packet spans URBs" bug, and fix the driver to ALWAYS
test lengths/ranges before accessing the actual buffer,
and everything should begin working reliably.
Cheers
--
Mark Lord
Real-Time Remedies Inc.
mlord@pobox.com
^ permalink raw reply
* RE: [PATCH net-next] cadence: Add hardware PTP support.
From: Rafal Ozieblo @ 2016-11-18 11:55 UTC (permalink / raw)
To: Harini Katakam
Cc: Nicolas Ferre, Andrei Pistirica, netdev@vger.kernel.org,
linux-kernel@vger.kernel.org
In-Reply-To: <CAFcVECLoMyJJLwAQ_+xN9GNLeVbew7RU_vURZjK94VXH2zS7EA@mail.gmail.com>
>Hi Rafal
>
>I'm still comparing the full solution but just a couple of things first:
><snip>
>> @@ -876,6 +964,17 @@ static int gem_rx(struct macb *bp, int budget)
>> bp->stats.rx_packets++;
>> bp->stats.rx_bytes += skb->len;
>>
>> +#if IS_ENABLED(CONFIG_PTP_1588_CLOCK)
>> + if (bp->ptp_hw_support) {
>> + struct timespec64 ts;
>> +
>> + if (MACB_BFEXT(DMA_RX_TS_VALID, desc->addr)) {
>> + macb_hw_timestamp(bp, desc->dma_desc_ts_1, desc->dma_desc_ts_2, &ts);
>> + skb_hwtstamps(skb)->hwtstamp = ktime_set(ts.tv_sec, ts.tv_nsec);
>> + }
>> + }
>> +#endif
>> +
>
>I've had to read PTP event registers for upper part of seconds timestamp in addition to the descriptor (since descriptor only has 5 bits of seconds TS).
>I don't know which version of the IP you use - it could be different.
>Please let me know so that I can check the spec.
>Same with tx timestamp of course.
I use GEM_GXL 1p9 and 1p10 but I should be comatible with old version as well.
From documentation:
Receive Buffer Descriptor Entry
Word 0:
Bit 2:
Address [2] of beginning of buffer.
Or
In Extended Buffer Descriptor Mode (DMA configuration register[28] = 1), indicates a valid timestamp in the BD entry
Transmit Buffer Descriptor Entry
Word 1:
Bit 23:
For Extended Buffer Descriptor Mode this bit Indicates a timestamp has been captured in the BD. Otherwise Reserved.
>
><snip>
>> @@ -1195,6 +1297,87 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id)
>> queue_writel(queue, ISR, MACB_BIT(HRESP));
>> }
>>
>> +#if IS_ENABLED(CONFIG_PTP_1588_CLOCK)
>> + if (status & MACB_BIT(PTP_DELAY_REQ_FRAME_RECEIVED)) {
>> + if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
>> + queue_writel(queue, ISR, MACB_BIT(PTP_DELAY_REQ_FRAME_RECEIVED));
>> + if (macb_ptp_time_frame_rx_get(bp, &ts) != 0) {
>> + ts.tv_sec = 0;
>> + ts.tv_nsec = 0;
>> + }
>> + macb_ptp_event(bp, &ts);
>> + }
>> +
>> + if (status & MACB_BIT(PTP_SYNC_FRAME_RECEIVED)) {
>> + if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
>> + queue_writel(queue, ISR, MACB_BIT(PTP_SYNC_FRAME_RECEIVED));
>> + if (macb_ptp_time_frame_rx_get(bp, &ts) != 0) {
>> + ts.tv_sec = 0;
>> + ts.tv_nsec = 0;
>> + }
>> + macb_ptp_event(bp, &ts);
>> + }
>> +
>> + if (status & MACB_BIT(PTP_DELAY_REQ_FRAME_TRANSMITTED)) {
>> + if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
>> + queue_writel(queue, ISR, MACB_BIT(PTP_DELAY_REQ_FRAME_TRANSMITTED));
>> + if (macb_ptp_time_frame_tx_get(bp, &ts) != 0) {
>> + ts.tv_sec = 0;
>> + ts.tv_nsec = 0;
>> + }
>> + macb_ptp_event(bp, &ts);
>> + }
>> +
>> + if (status & MACB_BIT(PTP_SYNC_FRAME_TRANSMITTED)) {
>> + if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
>> + queue_writel(queue, ISR, MACB_BIT(PTP_SYNC_FRAME_TRANSMITTED));
>> + if (macb_ptp_time_frame_tx_get(bp, &ts) != 0) {
>> + ts.tv_sec = 0;
>> + ts.tv_nsec = 0;
>> + }
>> + macb_ptp_event(bp, &ts);
>> + }
>> +
>> + if (status & MACB_BIT(PTP_PDELAY_REQ_FRAME_RECEIVED)) {
>> + if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
>> + queue_writel(queue, ISR, MACB_BIT(PTP_PDELAY_REQ_FRAME_RECEIVED));
>> + if (macb_ptp_time_peer_frame_rx_get(bp, &ts) != 0) {
>> + ts.tv_sec = 0;
>> + ts.tv_nsec = 0;
>> + }
>> + macb_ptp_event(bp, &ts);
>> + }
>> +
>> + if (status & MACB_BIT(PTP_PDELAY_RESP_FRAME_RECEIVED)) {
>> + if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
>> + queue_writel(queue, ISR, MACB_BIT(PTP_PDELAY_RESP_FRAME_RECEIVED));
>> + if (macb_ptp_time_peer_frame_rx_get(bp, &ts) != 0) {
>> + ts.tv_sec = 0;
>> + ts.tv_nsec = 0;
>> + }
>> + macb_ptp_event(bp, &ts);
>> + }
>> +
>> + if (status & MACB_BIT(PTP_PDELAY_REQ_FRAME_TRANSMITTED)) {
>> + if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
>> + queue_writel(queue, ISR, MACB_BIT(PTP_PDELAY_REQ_FRAME_TRANSMITTED));
>> + if (macb_ptp_time_peer_frame_tx_get(bp, &ts) != 0) {
>> + ts.tv_sec = 0;
>> + ts.tv_nsec = 0;
>> + }
>> + macb_ptp_event(bp, &ts);
>> + }
>> +
>> + if (status & MACB_BIT(PTP_PDELAY_RESP_FRAME_TRANSMITTED)) {
>> + if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
>> + queue_writel(queue, ISR, MACB_BIT(PTP_PDELAY_RESP_FRAME_TRANSMITTED));
>> + if (macb_ptp_time_peer_frame_tx_get(bp, &ts) != 0) {
>> + ts.tv_sec = 0;
>> + ts.tv_nsec = 0;
>> + }
>> + macb_ptp_event(bp, &ts);
>> + }
>> +#endif
>
>I'm not sure of your application and why this is necessary.
>Can you please check Andrei's patches and mine and Richard Cochran's comments?
>I use linuxptp to test.
>
This could be an overhead. I use linuxptp as well and it works.
>Regards,
>Harini
>
Best regards,
Rafal Ozieblo | Firmware System Engineer,
phone nbr.: +48 32 5085469
www.cadence.com
^ permalink raw reply
* [patch net-next] liquidio CN23XX: bitwise vs logical AND typo
From: Dan Carpenter @ 2016-11-18 11:47 UTC (permalink / raw)
To: Derek Chickles, Raghu Vatsavayi
Cc: Satanand Burla, Felix Manlunas, netdev, kernel-janitors
We obviously intended a bitwise AND here, not a logical one.
Fixes: 8c978d059224 ("liquidio CN23XX: Mailbox support")
Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_mailbox.c b/drivers/net/ethernet/cavium/liquidio/octeon_mailbox.c
index 5309384..73696b42 100644
--- a/drivers/net/ethernet/cavium/liquidio/octeon_mailbox.c
+++ b/drivers/net/ethernet/cavium/liquidio/octeon_mailbox.c
@@ -301,7 +301,7 @@ int octeon_mbox_process_message(struct octeon_mbox *mbox)
sizeof(struct octeon_mbox_cmd));
if (!mbox_cmd.msg.s.resp_needed) {
mbox->state &= ~OCTEON_MBOX_STATE_REQUEST_RECEIVED;
- if (!(mbox->state &&
+ if (!(mbox->state &
OCTEON_MBOX_STATE_RESPONSE_PENDING))
mbox->state = OCTEON_MBOX_STATE_IDLE;
writeq(OCTEON_PFVFSIG, mbox->mbox_read_reg);
^ permalink raw reply related
* Re: [PATCH net-next] cadence: Add hardware PTP support.
From: Harini Katakam @ 2016-11-18 11:44 UTC (permalink / raw)
To: Rafal Ozieblo
Cc: Nicolas Ferre, Andrei Pistirica, netdev,
linux-kernel@vger.kernel.org
In-Reply-To: <1479466028-29914-1-git-send-email-rafalo@cadence.com>
Hi Rafal
I'm still comparing the full solution but just a couple of things first:
<snip>
> @@ -876,6 +964,17 @@ static int gem_rx(struct macb *bp, int budget)
> bp->stats.rx_packets++;
> bp->stats.rx_bytes += skb->len;
>
> +#if IS_ENABLED(CONFIG_PTP_1588_CLOCK)
> + if (bp->ptp_hw_support) {
> + struct timespec64 ts;
> +
> + if (MACB_BFEXT(DMA_RX_TS_VALID, desc->addr)) {
> + macb_hw_timestamp(bp, desc->dma_desc_ts_1, desc->dma_desc_ts_2, &ts);
> + skb_hwtstamps(skb)->hwtstamp = ktime_set(ts.tv_sec, ts.tv_nsec);
> + }
> + }
> +#endif
> +
I've had to read PTP event registers for upper part of seconds timestamp
in addition to the descriptor (since descriptor only has 5 bits of seconds TS).
I don't know which version of the IP you use - it could be different.
Please let me know so that I can check the spec.
Same with tx timestamp of course.
<snip>
> @@ -1195,6 +1297,87 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id)
> queue_writel(queue, ISR, MACB_BIT(HRESP));
> }
>
> +#if IS_ENABLED(CONFIG_PTP_1588_CLOCK)
> + if (status & MACB_BIT(PTP_DELAY_REQ_FRAME_RECEIVED)) {
> + if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
> + queue_writel(queue, ISR, MACB_BIT(PTP_DELAY_REQ_FRAME_RECEIVED));
> + if (macb_ptp_time_frame_rx_get(bp, &ts) != 0) {
> + ts.tv_sec = 0;
> + ts.tv_nsec = 0;
> + }
> + macb_ptp_event(bp, &ts);
> + }
> +
> + if (status & MACB_BIT(PTP_SYNC_FRAME_RECEIVED)) {
> + if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
> + queue_writel(queue, ISR, MACB_BIT(PTP_SYNC_FRAME_RECEIVED));
> + if (macb_ptp_time_frame_rx_get(bp, &ts) != 0) {
> + ts.tv_sec = 0;
> + ts.tv_nsec = 0;
> + }
> + macb_ptp_event(bp, &ts);
> + }
> +
> + if (status & MACB_BIT(PTP_DELAY_REQ_FRAME_TRANSMITTED)) {
> + if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
> + queue_writel(queue, ISR, MACB_BIT(PTP_DELAY_REQ_FRAME_TRANSMITTED));
> + if (macb_ptp_time_frame_tx_get(bp, &ts) != 0) {
> + ts.tv_sec = 0;
> + ts.tv_nsec = 0;
> + }
> + macb_ptp_event(bp, &ts);
> + }
> +
> + if (status & MACB_BIT(PTP_SYNC_FRAME_TRANSMITTED)) {
> + if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
> + queue_writel(queue, ISR, MACB_BIT(PTP_SYNC_FRAME_TRANSMITTED));
> + if (macb_ptp_time_frame_tx_get(bp, &ts) != 0) {
> + ts.tv_sec = 0;
> + ts.tv_nsec = 0;
> + }
> + macb_ptp_event(bp, &ts);
> + }
> +
> + if (status & MACB_BIT(PTP_PDELAY_REQ_FRAME_RECEIVED)) {
> + if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
> + queue_writel(queue, ISR, MACB_BIT(PTP_PDELAY_REQ_FRAME_RECEIVED));
> + if (macb_ptp_time_peer_frame_rx_get(bp, &ts) != 0) {
> + ts.tv_sec = 0;
> + ts.tv_nsec = 0;
> + }
> + macb_ptp_event(bp, &ts);
> + }
> +
> + if (status & MACB_BIT(PTP_PDELAY_RESP_FRAME_RECEIVED)) {
> + if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
> + queue_writel(queue, ISR, MACB_BIT(PTP_PDELAY_RESP_FRAME_RECEIVED));
> + if (macb_ptp_time_peer_frame_rx_get(bp, &ts) != 0) {
> + ts.tv_sec = 0;
> + ts.tv_nsec = 0;
> + }
> + macb_ptp_event(bp, &ts);
> + }
> +
> + if (status & MACB_BIT(PTP_PDELAY_REQ_FRAME_TRANSMITTED)) {
> + if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
> + queue_writel(queue, ISR, MACB_BIT(PTP_PDELAY_REQ_FRAME_TRANSMITTED));
> + if (macb_ptp_time_peer_frame_tx_get(bp, &ts) != 0) {
> + ts.tv_sec = 0;
> + ts.tv_nsec = 0;
> + }
> + macb_ptp_event(bp, &ts);
> + }
> +
> + if (status & MACB_BIT(PTP_PDELAY_RESP_FRAME_TRANSMITTED)) {
> + if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
> + queue_writel(queue, ISR, MACB_BIT(PTP_PDELAY_RESP_FRAME_TRANSMITTED));
> + if (macb_ptp_time_peer_frame_tx_get(bp, &ts) != 0) {
> + ts.tv_sec = 0;
> + ts.tv_nsec = 0;
> + }
> + macb_ptp_event(bp, &ts);
> + }
> +#endif
I'm not sure of your application and why this is necessary.
Can you please check Andrei's patches and mine and
Richard Cochran's comments?
I use linuxptp to test.
Regards,
Harini
^ permalink raw reply
* RE: [RFC PATCH 2/2] net: macb: Add 64 bit addressing support for GEM
From: Rafal Ozieblo @ 2016-11-18 11:28 UTC (permalink / raw)
To: Harini Katakam
Cc: Nicolas Ferre, harini.katakam@xilinx.com, netdev@vger.kernel.org,
linux-kernel@vger.kernel.org
In-Reply-To: <CAFcVECK=tUrfz=ejKHLimVU3uX7GgBNLrObjSP=87RmV4CSLkw@mail.gmail.com>
>Hi Rafal,
>
>On Fri, Nov 18, 2016 at 2:29 PM, Rafal Ozieblo <rafalo@cadence.com> wrote:
>> Hello,
>>
>>> From: Harini Katakam [mailto:harinikatakamlinux@gmail.com]
>>> Sent: 18 listopada 2016 05:30
>>> To: Rafal Ozieblo
>>> Cc: Nicolas Ferre; harini.katakam@xilinx.com; netdev@vger.kernel.org;
>>> linux-kernel@vger.kernel.org
>>> Subject: Re: [RFC PATCH 2/2] net: macb: Add 64 bit addressing support
>>> for GEM
>>>
>>> Hi Rafal,
>>>
>>> On Thu, Nov 17, 2016 at 7:05 PM, Rafal Ozieblo <rafalo@cadence.com> wrote:
>>> > -----Original Message-----
>>> > From: Nicolas Ferre [mailto:nicolas.ferre@atmel.com]
>>> > Sent: 17 listopada 2016 14:29
>>> > To: Harini Katakam; Rafal Ozieblo
>>> > Cc: harini.katakam@xilinx.com; netdev@vger.kernel.org;
>>> > linux-kernel@vger.kernel.org
>>> > Subject: Re: [RFC PATCH 2/2] net: macb: Add 64 bit addressing
>>> > support for GEM
>>> >
>>> >> Le 17/11/2016 à 13:21, Harini Katakam a écrit :
>>> >> > Hi Rafal,
>>> >> >
>>> >> > On Thu, Nov 17, 2016 at 5:20 PM, Rafal Ozieblo <rafalo@cadence.com> wrote:
>>> >> >> Hello,
>>> >> >> I think, there could a bug in your patch.
>>> >> >>
>>> >> >>> +
>>> >> >>> +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
>>> >> >>> + dmacfg |= GEM_BIT(ADDR64); #endif
>>> >> >>
>>> >> >> You enable 64 bit addressing (64b dma bus width) always when appropriate architecture config option is enabled.
>>> >> >> But there are some legacy controllers which do not support that feature. According Cadence hardware team:
>>> >> >> "64 bit addressing was added in July 2013. Earlier version do not have it.
>>> >> >> This feature was enhanced in release August 2014 to have separate upper address values for transmit and receive."
>>> >> >>
>>> >> >>> /* Bitfields in NSR */
>>> >> >>> @@ -474,6 +479,10 @@
>>> >> >>> struct macb_dma_desc {
>>> >> >> > u32 addr;
>>> >> >>> u32 ctrl;
>>> >> >>> +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
>>> >> >>> + u32 addrh;
>>> >> >>> + u32 resvd;
>>> >> >>> +#endif
>>> >> >>> };
>>> >> >>
>>> >> >> It will not work for legacy hardware. Old descriptor is 2 words wide, the new one is 4 words wide.
>>> >> >> If you enable CONFIG_ARCH_DMA_ADDR_T_64BIT but hardware doesn't
>>> >> >> support it at all, you will miss every second descriptor.
>>> >> >>
>>> >> >
>>> >> > True, this feature is not available in all of Cadence IP versions.
>>> >> > In fact, the IP version Zynq does not support this. But the one in ZynqMP does.
>>> >> > So, we enable kernel config for 64 bit DMA addressing for this
>>> >> > SoC and hence the driver picks it up. My assumption was that if
>>> >> > the legacy IP does not support
>>> >> > 64 bit addressing, then this DMA option wouldn't be enabled.
>>> >> >
>>> >> > There is a design config register in Cadence IP which is being
>>> >> > read to check for 64 bit address support - DMA mask is set based on that.
>>> >> > But the addition of two descriptor words cannot be based on this runtime check.
>>> >> > For this reason, all the static changes were placed under this check.
>>> >>
>>> >> We have quite a bunch of options in this driver to determinate what is the real capacity of the underlying hardware.
>>> >> If HW configuration registers are not appropriate, and it seems they are not, I would advice to simply use the DT compatibility string.
>>> >>
>>> >> Best regards,
>>> >> --
>>> >> Nicolas Ferre
>>> >
>>> > HW configuration registers are appropriate. The issue is that this code doesn’t use the capability bit to switch between different dma descriptors (2 words vs. 4 words).
>>> > DMA descriptor size is chosen based on kernel configuration, not based on hardware capabilities.
>>>
>>> HW configuration register does give appropriate information.
>>> But addition of two address words in the macb descriptor structure is a static change.
>>>
>>> +static inline void macb_set_addr(struct macb_dma_desc *desc,
>>> +dma_addr_t
>>> +addr) {
>>> + desc->addr = (u32)addr;
>>> +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
>>> + desc->addrh = (u32)(addr >> 32); #endif
>>> +
>>>
>>> Even if the #ifdef condition here is changed to HW config check, addr and addrh are different.
>>> And "addrh" entry has to be present for 64 bit desc case to be handled separately.
>>> Can you please tell me how you propose change in DMA descriptor
>>> structure from
>>> 4 to 2 or 2 to 4 words *after* reading the DCFG register?
>>
>> It is very complex problem. I wrote to you because I faced the same issue. I'm working on PTP implementation for macb. When PTP is enabled there are additional two words in buffer descriptor.
>> But hardware might not be compatible with PTP. Therefore I have to change DMA descriptor between 2 and 4 words after reading DCFG register (the same as you between 32b and 64b).
>> When we consider both PTP and 64 bits, we end up with 4 different descriptors!
>
>Agree
>
><snip>
>> (Below is kind of pseudo code only to show my idea. All defines like
>> 64B or PTP are omitted for simplicity)
>>
>> 1. Prepare appropriate structures:
>>
>> struct macb_dma_desc {
>> u32 addr;
>> u32 ctrl;
>> }
>>
>> struct macb_dma_desc_64 {
>> u32 addrh;
>> u32 resvd;
>> }
>>
>> struct macb_dma_desc_ptp {
>> u32 dma_desc_ts_1;
>> u32 dma_desc_ts_2;
>> }
>>
>> 2. Add hardware support information to macb:
>>
>> enum macb_hw_cap {
>> HW_CAP_NONE,
>> HW_CAP_64B,
>> HW_CAP_PTP,
>> HW_CAP_64B_PTP,
>> };
>>
>> struct macb {
>> // (...)
>> macb_hw_cap hw_cap;
>>
>> }
>>
>> 3. Set bp->hw_cap on macb_probe()
>>
>
>hw_cap can alreayd be obtained from config structures based on compatible string.
>
>> 4. Additional function might be helpful:
>>
>> static unsigned char macb_dma_desc_get_mul(struct macb *bp) {
>> switch (bp->hw_cap) {
>> case HW_CAP_NONE:
>> return 1;
>> case HW_CAP_64B:
>> case HW_CAP_PTP:
>> return 2;
>> case HW_CAP_64B_PTP:
>> return 3;
>> }
>> }
>>
>> 5. Change sizeof struct to function:
>> (sizeof(struct macb_dma_desc) change to macb_dma_desc_get_size(bp). It will return sizeof(struct macb_dma_desc) * macb_dma_desc_get_mul(bp).
>> There is a hidden assumption that all three structures have the same size.
>>
>> 6. macb_rx_desc() and macb_tx_desc() will still return struct macb_dma_desc * but descriptor index will be counted in different way, ex.
>>
>> static struct macb_dma_desc *macb_rx_desc(struct macb *bp, unsigned
>> int index) {
>> index *= macb_dma_desc_get_mul(bp);
>> return &bp->rx_ring[macb_rx_ring_wrap(bp, index)]; }
>>
>> 7. Two additional functions to dereference PTP and 64b information:
>>
>> static struct macb_dma_desc_64 *macb_64b_desc(struct macb *bp, struct
>> macb_dma_desc *desc) {
>> switch (bp->hw_cap) {
>> case HW_CAP_64B:
>> case HW_CAP_64B_PTP:
>> return (struct macb_dma_desc_64 *)(desc + 1); // ugly casting
>> default:
>> return NULL;
>> }
>> }
>>
>> static struct macb_dma_desc_ptp *macb_ptp_desc(struct macb *bp, struct
>> macb_dma_desc *desc) {
>> switch (bp->hw_cap) {
>> case HW_CAP_PTP:
>> return (struct macb_dma_desc_ptp *)(desc + 1);
>> case HW_CAP_64B_PTP:
>> return (struct macb_dma_desc_ptp *)(desc + 2);
>> default:
>> return NULL;
>> }
>> }
>>
>> Whenever you want to reach fields in appropriate descriptor, above function should be used.
>>
>
>Theoretically I agree this will work.
>But we'll have to try to see how this will affect/slow down the desc reading.. especially with PTP.
>
>Regards,
>Harini
It is done very similarly in sdhci driver:
http://lxr.free-electrons.com/source/drivers/mmc/host/sdhci.c
For example, please look at sdhci_adma_write_desc().
If we change my idea to operate directly on void * instead of macb_dma_desc *, it would be even better. (rx_ring, tx_ring and others), ex.:
struct void *rx_ring;
struct void *tx_ring;
static macb_dma_desc *macb_rx_desc(struct macb *bp, unsigned int index)
{
index *= macb_dma_desc_get_size(bp);
return (macb_dma_desc *)&bp->rx_ring[macb_rx_ring_wrap(bp, index)];
}
>> This is only my very first idea. Of course, we can leave it as it is and say, that old hardware is not support either when PTP enabled or 64b enabled.
>
Best regards,
Rafal Ozieblo | Firmware System Engineer,
phone nbr.: +48 32 5085469
www.cadence.com
^ permalink raw reply
* Re: [PATCH v9 0/8] thunderbolt: Introducing Thunderbolt(TM) Networking
From: Simon Guinot @ 2016-11-18 11:20 UTC (permalink / raw)
To: Levy, Amir (Jer)
Cc: gregkh@linuxfoundation.org, andreas.noever@gmail.com,
bhelgaas@google.com, corbet@lwn.net, linux-kernel@vger.kernel.org,
linux-pci@vger.kernel.org, netdev@vger.kernel.org,
linux-doc@vger.kernel.org, mario_limonciello@dell.com,
thunderbolt-linux, Westerberg, Mika, Winkler, Tomas,
Zhang, Xiong Y, Jamet, Michael, remi.rerolle@seagate.com
In-Reply-To: <E607265CB020454880711A6F96C05A03BE2199EE@hasmsx108.ger.corp.intel.com>
[-- Attachment #1: Type: text/plain, Size: 4034 bytes --]
On Fri, Nov 18, 2016 at 08:48:36AM +0000, Levy, Amir (Jer) wrote:
> On Tue, Nov 15 2016, 12:59 PM, Simon Guinot wrote:
> > On Wed, Nov 09, 2016 at 03:42:53PM +0000, Levy, Amir (Jer) wrote:
> > > On Wed, Nov 9 2016, 04:36 PM, Simon Guinot wrote:
> > > > Hi Amir,
> > > >
> > > > I have an ASUS "All Series/Z87-DELUXE/QUAD" motherboard with a
> > > > Thunderbolt 2 "Falcon Ridge" chipset (device ID 156d).
> > > >
> > > > Is the thunderbolt-icm driver supposed to work with this chipset ?
> > > >
> > >
> > > Yes, the thunderbolt-icm supports Falcon Ridge, device ID 156c.
> > > 156d is the bridge -
> > > http://lxr.free-electrons.com/source/include/linux/pci_ids.h#L2619
> > >
> > > > I have installed both a 4.8.6 Linux kernel (patched with your v9
> > > > series) and the thunderbolt-software-daemon (27 october release)
> > > > inside a Debian system (Jessie).
> > > >
> > > > If I connect the ASUS motherboard with a MacBook Pro (Thunderbolt
> > > > 2, device ID 156c), I can see that the thunderbolt-icm driver is
> > > > loaded and that the thunderbolt-software-daemon is well started.
> > > > But the Ethernet interface is not created.
> > > >
> > > > I have attached to this email the syslog file. There is the logs
> > > > from both the kernel and the daemon inside. Note that the daemon
> > > > logs are everything but clear about what could be the issue. Maybe
> > > > I missed some kind of configuration ? But I failed to find any
> > > > valuable information about configuring the driver and/or the
> > > > daemon in
> > the various documentation files.
> > > >
> > > > Please, can you provide some guidance ? I'd really like to test
> > > > your patch series.
> > >
> > > First, thank you very much for willing to test it.
> > > Thunderbolt Networking support was added during Falcon Ridge, in the
> > latest FR images.
> > > Do you know which Thunderbolt image version you have on your system?
> > > Currently I submitted only Thunderbolt Networking feature in Linux,
> > > and we plan to add more features like reading the image version and
> > updating the image.
> > > If you don't know the image version, the only thing I can suggest is
> > > to load windows, install thunderbolt SW and check in the Thunderbolt
> > application the image version.
> > > To know if image update is needed, you can check -
> > > https://thunderbolttechnology.net/updates
> >
> > Hi Amir,
> >
> > From the Windows Thunderbolt software, I can read 13.00 for the
> > firmware version. And from https://thunderbolttechnology.net/updates,
> > I can see that there is no update available for my ASUS motherboard.
> >
> > Am I good to go ?
> >
>
> Thunderbolt Networking is supported on both Thunderbolt(tm) 2 and Thunderbolt(tm) 3 systems.
> Thunderbolt 2 systems must have updated NVM (version 25 or later) in order for the functionality to work properly.
> If the system does not have the update, please contact the OEM directly for an updated NVM.
> For best functionality and support, Intel recommends using Thunderbolt 3 systems for all validation and testing.
Maybe it is worth mentioning in the documentation and/or in the Kconfig
help message that a minimal firmware version is needed for Thunderbolt 2
controllers.
It would have saved some time for me :)
>
> > BTW, it is quite a shame that the Thunderbolt firmware version can't
> > be read from Linux.
> >
>
> This is WIP, once this patch will be upstream, we will be able to focus more
> on aligning Linux with the Thunderbolt features that we have for windows.
Well, I rather see the firmware identification and update as basic
features on the top of which ones you can build a driver. For example in
this case this would allow the ICM driver and/or the userland daemon to
exit with a useful error message rather than just not working without any
explanation.
Next week I'll try the driver with a Thunderbolt 3 controller.
Thanks for your help!
Simon
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 181 bytes --]
^ permalink raw reply
* Re: [PATCH net-next] cadence: Add hardware PTP support.
From: Nicolas Ferre @ 2016-11-18 11:12 UTC (permalink / raw)
To: Rafal Ozieblo, Andrei Pistirica, netdev, David Miller
Cc: Harini Katakam, linux-kernel
In-Reply-To: <1479466028-29914-1-git-send-email-rafalo@cadence.com>
Le 18/11/2016 à 11:47, Rafal Ozieblo a écrit :
> Signed-off-by: Rafal Ozieblo <rafalo@cadence.com>
Note to David: This is more a RFC: we are discussing the addition of
this feature and how to cover all macb revisions and optional features
implemented in actual products.
regards,
> ---
> Documentation/devicetree/bindings/net/macb.txt | 1 +
> drivers/net/ethernet/cadence/macb.c | 742 ++++++++++++++++++++++++-
> drivers/net/ethernet/cadence/macb.h | 217 +++++++-
> 3 files changed, 950 insertions(+), 10 deletions(-)
[..]
--
Nicolas Ferre
^ permalink raw reply
* [PATCH net-next] cxgb4: Allocate Tx queues dynamically
From: Atul Gupta @ 2016-11-18 11:07 UTC (permalink / raw)
To: netdev, linux-scsi, target-devel, linux-rdma, linux-crypto
Cc: davem, nab, jejb, martin.petersen, dledford, herbert, leedom,
nirranjan, varun, swise, hariprasad, Atul Gupta
From: Hariprasad Shenai <hariprasad@chelsio.com>
Allocate resources dynamically for Upper layer driver's (ULD) like
cxgbit, iw_cxgb4, cxgb4i and chcr. The resources allocated include Tx
queues which are allocated when ULD register with cxgb4 driver and freed
while un-registering. The Tx queues which are shared by ULD shall be
allocated by first registering driver and un-allocated by last
unregistering driver.
Signed-off-by: Atul Gupta <atul.gupta@chelsio.com>
---
drivers/crypto/chelsio/chcr_algo.c | 16 +--
drivers/crypto/chelsio/chcr_core.c | 3 +-
drivers/infiniband/hw/cxgb4/device.c | 1 +
drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 19 +++-
drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c | 12 --
drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 64 +++++++----
drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c | 114 +++++++++++++++++++
drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h | 17 +++
drivers/net/ethernet/chelsio/cxgb4/sge.c | 121 +++++++++++++++------
drivers/scsi/cxgbi/cxgb4i/cxgb4i.c | 1 +
drivers/target/iscsi/cxgbit/cxgbit_main.c | 1 +
11 files changed, 287 insertions(+), 82 deletions(-)
diff --git a/drivers/crypto/chelsio/chcr_algo.c b/drivers/crypto/chelsio/chcr_algo.c
index e4ddb921d7b3..56b153805462 100644
--- a/drivers/crypto/chelsio/chcr_algo.c
+++ b/drivers/crypto/chelsio/chcr_algo.c
@@ -592,16 +592,18 @@ static int chcr_aes_cbc_setkey(struct crypto_ablkcipher *tfm, const u8 *key,
static int cxgb4_is_crypto_q_full(struct net_device *dev, unsigned int idx)
{
- int ret = 0;
- struct sge_ofld_txq *q;
struct adapter *adap = netdev2adap(dev);
+ struct sge_uld_txq_info *txq_info =
+ adap->sge.uld_txq_info[CXGB4_TX_CRYPTO];
+ struct sge_uld_txq *txq;
+ int ret = 0;
local_bh_disable();
- q = &adap->sge.ofldtxq[idx];
- spin_lock(&q->sendq.lock);
- if (q->full)
+ txq = &txq_info->uldtxq[idx];
+ spin_lock(&txq->sendq.lock);
+ if (txq->full)
ret = -1;
- spin_unlock(&q->sendq.lock);
+ spin_unlock(&txq->sendq.lock);
local_bh_enable();
return ret;
}
@@ -674,11 +676,11 @@ static int chcr_device_init(struct chcr_context *ctx)
}
u_ctx = ULD_CTX(ctx);
rxq_perchan = u_ctx->lldi.nrxq / u_ctx->lldi.nchan;
- ctx->dev->tx_channel_id = 0;
rxq_idx = ctx->dev->tx_channel_id * rxq_perchan;
rxq_idx += id % rxq_perchan;
spin_lock(&ctx->dev->lock_chcr_dev);
ctx->tx_channel_id = rxq_idx;
+ ctx->dev->tx_channel_id = !ctx->dev->tx_channel_id;
spin_unlock(&ctx->dev->lock_chcr_dev);
}
out:
diff --git a/drivers/crypto/chelsio/chcr_core.c b/drivers/crypto/chelsio/chcr_core.c
index fb5f9bbfa09c..4d7f6700fd7e 100644
--- a/drivers/crypto/chelsio/chcr_core.c
+++ b/drivers/crypto/chelsio/chcr_core.c
@@ -42,6 +42,7 @@ static chcr_handler_func work_handlers[NUM_CPL_CMDS] = {
static struct cxgb4_uld_info chcr_uld_info = {
.name = DRV_MODULE_NAME,
.nrxq = MAX_ULD_QSETS,
+ .ntxq = MAX_ULD_QSETS,
.rxq_size = 1024,
.add = chcr_uld_add,
.state_change = chcr_uld_state_change,
@@ -126,7 +127,7 @@ static int cpl_fw6_pld_handler(struct chcr_dev *dev,
int chcr_send_wr(struct sk_buff *skb)
{
- return cxgb4_ofld_send(skb->dev, skb);
+ return cxgb4_crypto_send(skb->dev, skb);
}
static void *chcr_uld_add(const struct cxgb4_lld_info *lld)
diff --git a/drivers/infiniband/hw/cxgb4/device.c b/drivers/infiniband/hw/cxgb4/device.c
index 93e3d270a98a..4e5baf4fe15e 100644
--- a/drivers/infiniband/hw/cxgb4/device.c
+++ b/drivers/infiniband/hw/cxgb4/device.c
@@ -1481,6 +1481,7 @@ static int c4iw_uld_control(void *handle, enum cxgb4_control control, ...)
static struct cxgb4_uld_info c4iw_uld_info = {
.name = DRV_NAME,
.nrxq = MAX_ULD_QSETS,
+ .ntxq = MAX_ULD_QSETS,
.rxq_size = 511,
.ciq = true,
.lro = false,
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
index 2125903043fb..0bce1bf9ca0f 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
@@ -635,6 +635,7 @@ struct tx_sw_desc;
struct sge_txq {
unsigned int in_use; /* # of in-use Tx descriptors */
+ unsigned int q_type; /* Q type Eth/Ctrl/Ofld */
unsigned int size; /* # of descriptors */
unsigned int cidx; /* SW consumer index */
unsigned int pidx; /* producer index */
@@ -665,7 +666,7 @@ struct sge_eth_txq { /* state for an SGE Ethernet Tx queue */
unsigned long mapping_err; /* # of I/O MMU packet mapping errors */
} ____cacheline_aligned_in_smp;
-struct sge_ofld_txq { /* state for an SGE offload Tx queue */
+struct sge_uld_txq { /* state for an SGE offload Tx queue */
struct sge_txq q;
struct adapter *adap;
struct sk_buff_head sendq; /* list of backpressured packets */
@@ -693,14 +694,20 @@ struct sge_uld_rxq_info {
u8 uld; /* uld type */
};
+struct sge_uld_txq_info {
+ struct sge_uld_txq *uldtxq; /* Txq's for ULD */
+ atomic_t users; /* num users */
+ u16 ntxq; /* # of egress uld queues */
+};
+
struct sge {
struct sge_eth_txq ethtxq[MAX_ETH_QSETS];
- struct sge_ofld_txq ofldtxq[MAX_OFLD_QSETS];
struct sge_ctrl_txq ctrlq[MAX_CTRL_QUEUES];
struct sge_eth_rxq ethrxq[MAX_ETH_QSETS];
struct sge_rspq fw_evtq ____cacheline_aligned_in_smp;
struct sge_uld_rxq_info **uld_rxq_info;
+ struct sge_uld_txq_info **uld_txq_info;
struct sge_rspq intrq ____cacheline_aligned_in_smp;
spinlock_t intrq_lock;
@@ -1298,8 +1305,9 @@ int t4_sge_alloc_ctrl_txq(struct adapter *adap, struct sge_ctrl_txq *txq,
unsigned int cmplqid);
int t4_sge_mod_ctrl_txq(struct adapter *adap, unsigned int eqid,
unsigned int cmplqid);
-int t4_sge_alloc_ofld_txq(struct adapter *adap, struct sge_ofld_txq *txq,
- struct net_device *dev, unsigned int iqid);
+int t4_sge_alloc_uld_txq(struct adapter *adap, struct sge_uld_txq *txq,
+ struct net_device *dev, unsigned int iqid,
+ unsigned int uld_type);
irqreturn_t t4_sge_intr_msix(int irq, void *cookie);
int t4_sge_init(struct adapter *adap);
void t4_sge_start(struct adapter *adap);
@@ -1661,4 +1669,7 @@ int t4_uld_mem_alloc(struct adapter *adap);
void t4_uld_clean_up(struct adapter *adap);
void t4_register_netevent_notifier(void);
void free_rspq_fl(struct adapter *adap, struct sge_rspq *rq, struct sge_fl *fl);
+void free_tx_desc(struct adapter *adap, struct sge_txq *q,
+ unsigned int n, bool unmap);
+void free_txq(struct adapter *adap, struct sge_txq *q);
#endif /* __CXGB4_H__ */
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c
index 20455d082cb8..acc231293e4d 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c
@@ -2512,18 +2512,6 @@ do { \
RL("FLLow:", fl.low);
RL("FLStarving:", fl.starving);
- } else if (ofld_idx < ofld_entries) {
- const struct sge_ofld_txq *tx =
- &adap->sge.ofldtxq[ofld_idx * 4];
- int n = min(4, adap->sge.ofldqsets - 4 * ofld_idx);
-
- S("QType:", "OFLD-Txq");
- T("TxQ ID:", q.cntxt_id);
- T("TxQ size:", q.size);
- T("TxQ inuse:", q.in_use);
- T("TxQ CIDX:", q.cidx);
- T("TxQ PIDX:", q.pidx);
-
} else if (ctrl_idx < ctrl_entries) {
const struct sge_ctrl_txq *tx = &adap->sge.ctrlq[ctrl_idx * 4];
int n = min(4, adap->params.nports - 4 * ctrl_idx);
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
index c0cc2ee77be7..449884f8dd67 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
@@ -530,15 +530,15 @@ static int fwevtq_handler(struct sge_rspq *q, const __be64 *rsp,
txq = q->adap->sge.egr_map[qid - q->adap->sge.egr_start];
txq->restarts++;
- if ((u8 *)txq < (u8 *)q->adap->sge.ofldtxq) {
+ if (txq->q_type == CXGB4_TXQ_ETH) {
struct sge_eth_txq *eq;
eq = container_of(txq, struct sge_eth_txq, q);
netif_tx_wake_queue(eq->txq);
} else {
- struct sge_ofld_txq *oq;
+ struct sge_uld_txq *oq;
- oq = container_of(txq, struct sge_ofld_txq, q);
+ oq = container_of(txq, struct sge_uld_txq, q);
tasklet_schedule(&oq->qresume_tsk);
}
} else if (opcode == CPL_FW6_MSG || opcode == CPL_FW4_MSG) {
@@ -885,15 +885,6 @@ static int setup_sge_queues(struct adapter *adap)
}
}
- j = s->ofldqsets / adap->params.nports; /* iscsi queues per channel */
- for_each_ofldtxq(s, i) {
- err = t4_sge_alloc_ofld_txq(adap, &s->ofldtxq[i],
- adap->port[i / j],
- s->fw_evtq.cntxt_id);
- if (err)
- goto freeout;
- }
-
for_each_port(adap, i) {
/* Note that cmplqid below is 0 if we don't
* have RDMA queues, and that's the right value.
@@ -1922,8 +1913,18 @@ static void disable_dbs(struct adapter *adap)
for_each_ethrxq(&adap->sge, i)
disable_txq_db(&adap->sge.ethtxq[i].q);
- for_each_ofldtxq(&adap->sge, i)
- disable_txq_db(&adap->sge.ofldtxq[i].q);
+ if (is_offload(adap)) {
+ struct sge_uld_txq_info *txq_info =
+ adap->sge.uld_txq_info[CXGB4_TX_OFLD];
+
+ if (txq_info) {
+ for_each_ofldtxq(&adap->sge, i) {
+ struct sge_uld_txq *txq = &txq_info->uldtxq[i];
+
+ disable_txq_db(&txq->q);
+ }
+ }
+ }
for_each_port(adap, i)
disable_txq_db(&adap->sge.ctrlq[i].q);
}
@@ -1934,8 +1935,18 @@ static void enable_dbs(struct adapter *adap)
for_each_ethrxq(&adap->sge, i)
enable_txq_db(adap, &adap->sge.ethtxq[i].q);
- for_each_ofldtxq(&adap->sge, i)
- enable_txq_db(adap, &adap->sge.ofldtxq[i].q);
+ if (is_offload(adap)) {
+ struct sge_uld_txq_info *txq_info =
+ adap->sge.uld_txq_info[CXGB4_TX_OFLD];
+
+ if (txq_info) {
+ for_each_ofldtxq(&adap->sge, i) {
+ struct sge_uld_txq *txq = &txq_info->uldtxq[i];
+
+ enable_txq_db(adap, &txq->q);
+ }
+ }
+ }
for_each_port(adap, i)
enable_txq_db(adap, &adap->sge.ctrlq[i].q);
}
@@ -2006,8 +2017,17 @@ static void recover_all_queues(struct adapter *adap)
for_each_ethrxq(&adap->sge, i)
sync_txq_pidx(adap, &adap->sge.ethtxq[i].q);
- for_each_ofldtxq(&adap->sge, i)
- sync_txq_pidx(adap, &adap->sge.ofldtxq[i].q);
+ if (is_offload(adap)) {
+ struct sge_uld_txq_info *txq_info =
+ adap->sge.uld_txq_info[CXGB4_TX_OFLD];
+ if (txq_info) {
+ for_each_ofldtxq(&adap->sge, i) {
+ struct sge_uld_txq *txq = &txq_info->uldtxq[i];
+
+ sync_txq_pidx(adap, &txq->q);
+ }
+ }
+ }
for_each_port(adap, i)
sync_txq_pidx(adap, &adap->sge.ctrlq[i].q);
}
@@ -3991,7 +4011,7 @@ static inline bool is_x_10g_port(const struct link_config *lc)
static void cfg_queues(struct adapter *adap)
{
struct sge *s = &adap->sge;
- int i, n10g = 0, qidx = 0;
+ int i = 0, n10g = 0, qidx = 0;
#ifndef CONFIG_CHELSIO_T4_DCB
int q10g = 0;
#endif
@@ -4006,8 +4026,7 @@ static void cfg_queues(struct adapter *adap)
adap->params.crypto = 0;
}
- for_each_port(adap, i)
- n10g += is_x_10g_port(&adap2pinfo(adap, i)->link_cfg);
+ n10g += is_x_10g_port(&adap2pinfo(adap, i)->link_cfg);
#ifdef CONFIG_CHELSIO_T4_DCB
/* For Data Center Bridging support we need to be able to support up
* to 8 Traffic Priorities; each of which will be assigned to its
@@ -4075,9 +4094,6 @@ static void cfg_queues(struct adapter *adap)
for (i = 0; i < ARRAY_SIZE(s->ctrlq); i++)
s->ctrlq[i].q.size = 512;
- for (i = 0; i < ARRAY_SIZE(s->ofldtxq); i++)
- s->ofldtxq[i].q.size = 1024;
-
init_rspq(adap, &s->fw_evtq, 0, 1, 1024, 64);
init_rspq(adap, &s->intrq, 0, 1, 512, 64);
}
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c
index 2471ff465d5c..565a6c6bfeaf 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c
@@ -447,6 +447,106 @@ static void quiesce_rx_uld(struct adapter *adap, unsigned int uld_type)
quiesce_rx(adap, &rxq_info->uldrxq[idx].rspq);
}
+static void
+free_sge_txq_uld(struct adapter *adap, struct sge_uld_txq_info *txq_info)
+{
+ int nq = txq_info->ntxq;
+ int i;
+
+ for (i = 0; i < nq; i++) {
+ struct sge_uld_txq *txq = &txq_info->uldtxq[i];
+
+ if (txq && txq->q.desc) {
+ tasklet_kill(&txq->qresume_tsk);
+ t4_ofld_eq_free(adap, adap->mbox, adap->pf, 0,
+ txq->q.cntxt_id);
+ free_tx_desc(adap, &txq->q, txq->q.in_use, false);
+ kfree(txq->q.sdesc);
+ __skb_queue_purge(&txq->sendq);
+ free_txq(adap, &txq->q);
+ }
+ }
+}
+
+static int
+alloc_sge_txq_uld(struct adapter *adap, struct sge_uld_txq_info *txq_info,
+ unsigned int uld_type)
+{
+ struct sge *s = &adap->sge;
+ int nq = txq_info->ntxq;
+ int i, j, err;
+
+ j = nq / adap->params.nports;
+ for (i = 0; i < nq; i++) {
+ struct sge_uld_txq *txq = &txq_info->uldtxq[i];
+
+ txq->q.size = 1024;
+ err = t4_sge_alloc_uld_txq(adap, txq, adap->port[i / j],
+ s->fw_evtq.cntxt_id, uld_type);
+ if (err)
+ goto freeout;
+ }
+ return 0;
+freeout:
+ free_sge_txq_uld(adap, txq_info);
+ return err;
+}
+
+static void
+release_sge_txq_uld(struct adapter *adap, unsigned int uld_type)
+{
+ struct sge_uld_txq_info *txq_info = NULL;
+ int tx_uld_type = TX_ULD(uld_type);
+
+ txq_info = adap->sge.uld_txq_info[tx_uld_type];
+
+ if (txq_info && atomic_dec_and_test(&txq_info->users)) {
+ free_sge_txq_uld(adap, txq_info);
+ kfree(txq_info->uldtxq);
+ kfree(txq_info);
+ adap->sge.uld_txq_info[tx_uld_type] = NULL;
+ }
+}
+
+static int
+setup_sge_txq_uld(struct adapter *adap, unsigned int uld_type,
+ const struct cxgb4_uld_info *uld_info)
+{
+ struct sge_uld_txq_info *txq_info = NULL;
+ int tx_uld_type, i;
+
+ tx_uld_type = TX_ULD(uld_type);
+ txq_info = adap->sge.uld_txq_info[tx_uld_type];
+
+ if ((tx_uld_type == CXGB4_TX_OFLD) && txq_info &&
+ (atomic_inc_return(&txq_info->users) > 1))
+ return 0;
+
+ txq_info = kzalloc(sizeof(*txq_info), GFP_KERNEL);
+ if (!txq_info)
+ return -ENOMEM;
+
+ i = min_t(int, uld_info->ntxq, num_online_cpus());
+ txq_info->ntxq = roundup(i, adap->params.nports);
+
+ txq_info->uldtxq = kcalloc(txq_info->ntxq, sizeof(struct sge_uld_txq),
+ GFP_KERNEL);
+ if (!txq_info->uldtxq) {
+ kfree(txq_info->uldtxq);
+ return -ENOMEM;
+ }
+
+ if (alloc_sge_txq_uld(adap, txq_info, tx_uld_type)) {
+ kfree(txq_info->uldtxq);
+ kfree(txq_info);
+ return -ENOMEM;
+ }
+
+ atomic_inc(&txq_info->users);
+ adap->sge.uld_txq_info[tx_uld_type] = txq_info;
+ return 0;
+}
+
static void uld_queue_init(struct adapter *adap, unsigned int uld_type,
struct cxgb4_lld_info *lli)
{
@@ -472,7 +572,15 @@ int t4_uld_mem_alloc(struct adapter *adap)
if (!s->uld_rxq_info)
goto err_uld;
+ s->uld_txq_info = kzalloc(CXGB4_TX_MAX *
+ sizeof(struct sge_uld_txq_info *),
+ GFP_KERNEL);
+ if (!s->uld_txq_info)
+ goto err_uld_rx;
return 0;
+
+err_uld_rx:
+ kfree(s->uld_rxq_info);
err_uld:
kfree(adap->uld);
return -ENOMEM;
@@ -482,6 +590,7 @@ void t4_uld_mem_free(struct adapter *adap)
{
struct sge *s = &adap->sge;
+ kfree(s->uld_txq_info);
kfree(s->uld_rxq_info);
kfree(adap->uld);
}
@@ -616,6 +725,9 @@ int cxgb4_register_uld(enum cxgb4_uld type,
ret = -EBUSY;
goto free_irq;
}
+ ret = setup_sge_txq_uld(adap, type, p);
+ if (ret)
+ goto free_irq;
adap->uld[type] = *p;
uld_attach(adap, type);
adap_idx++;
@@ -644,6 +756,7 @@ int cxgb4_register_uld(enum cxgb4_uld type,
break;
adap->uld[type].handle = NULL;
adap->uld[type].add = NULL;
+ release_sge_txq_uld(adap, type);
if (adap->flags & FULL_INIT_DONE)
quiesce_rx_uld(adap, type);
if (adap->flags & USING_MSIX)
@@ -679,6 +792,7 @@ int cxgb4_unregister_uld(enum cxgb4_uld type)
continue;
adap->uld[type].handle = NULL;
adap->uld[type].add = NULL;
+ release_sge_txq_uld(adap, type);
if (adap->flags & FULL_INIT_DONE)
quiesce_rx_uld(adap, type);
if (adap->flags & USING_MSIX)
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h
index 2996793b1aaa..4c856605fdfa 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h
@@ -77,6 +77,8 @@ enum {
/* Special asynchronous notification message */
#define CXGB4_MSG_AN ((void *)1)
+#define TX_ULD(uld)(((uld) != CXGB4_ULD_CRYPTO) ? CXGB4_TX_OFLD :\
+ CXGB4_TX_CRYPTO)
struct serv_entry {
void *data;
@@ -223,6 +225,19 @@ enum cxgb4_uld {
CXGB4_ULD_MAX
};
+enum cxgb4_tx_uld {
+ CXGB4_TX_OFLD,
+ CXGB4_TX_CRYPTO,
+ CXGB4_TX_MAX
+};
+
+enum cxgb4_txq_type {
+ CXGB4_TXQ_ETH,
+ CXGB4_TXQ_ULD,
+ CXGB4_TXQ_CTRL,
+ CXGB4_TXQ_MAX
+};
+
enum cxgb4_state {
CXGB4_STATE_UP,
CXGB4_STATE_START_RECOVERY,
@@ -316,6 +331,7 @@ struct cxgb4_uld_info {
void *handle;
unsigned int nrxq;
unsigned int rxq_size;
+ unsigned int ntxq;
bool ciq;
bool lro;
void *(*add)(const struct cxgb4_lld_info *p);
@@ -333,6 +349,7 @@ struct cxgb4_uld_info {
int cxgb4_register_uld(enum cxgb4_uld type, const struct cxgb4_uld_info *p);
int cxgb4_unregister_uld(enum cxgb4_uld type);
int cxgb4_ofld_send(struct net_device *dev, struct sk_buff *skb);
+int cxgb4_crypto_send(struct net_device *dev, struct sk_buff *skb);
unsigned int cxgb4_dbfifo_count(const struct net_device *dev, int lpfifo);
unsigned int cxgb4_port_chan(const struct net_device *dev);
unsigned int cxgb4_port_viid(const struct net_device *dev);
diff --git a/drivers/net/ethernet/chelsio/cxgb4/sge.c b/drivers/net/ethernet/chelsio/cxgb4/sge.c
index 1e74fd6085df..b7d0753b9242 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/sge.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/sge.c
@@ -377,8 +377,8 @@ unmap: dma_unmap_page(dev, be64_to_cpu(p->addr[0]),
* Reclaims Tx descriptors from an SGE Tx queue and frees the associated
* Tx buffers. Called with the Tx queue lock held.
*/
-static void free_tx_desc(struct adapter *adap, struct sge_txq *q,
- unsigned int n, bool unmap)
+void free_tx_desc(struct adapter *adap, struct sge_txq *q,
+ unsigned int n, bool unmap)
{
struct tx_sw_desc *d;
unsigned int cidx = q->cidx;
@@ -1543,7 +1543,7 @@ static inline unsigned int calc_tx_flits_ofld(const struct sk_buff *skb)
* inability to map packets. A periodic timer attempts to restart
* queues so marked.
*/
-static void txq_stop_maperr(struct sge_ofld_txq *q)
+static void txq_stop_maperr(struct sge_uld_txq *q)
{
q->mapping_err++;
q->q.stops++;
@@ -1559,7 +1559,7 @@ static void txq_stop_maperr(struct sge_ofld_txq *q)
* Stops an offload Tx queue that has become full and modifies the packet
* being written to request a wakeup.
*/
-static void ofldtxq_stop(struct sge_ofld_txq *q, struct sk_buff *skb)
+static void ofldtxq_stop(struct sge_uld_txq *q, struct sk_buff *skb)
{
struct fw_wr_hdr *wr = (struct fw_wr_hdr *)skb->data;
@@ -1586,7 +1586,7 @@ static void ofldtxq_stop(struct sge_ofld_txq *q, struct sk_buff *skb)
* boolean "service_ofldq_running" to make sure that only one instance
* is ever running at a time ...
*/
-static void service_ofldq(struct sge_ofld_txq *q)
+static void service_ofldq(struct sge_uld_txq *q)
{
u64 *pos, *before, *end;
int credits;
@@ -1706,7 +1706,7 @@ static void service_ofldq(struct sge_ofld_txq *q)
*
* Send an offload packet through an SGE offload queue.
*/
-static int ofld_xmit(struct sge_ofld_txq *q, struct sk_buff *skb)
+static int ofld_xmit(struct sge_uld_txq *q, struct sk_buff *skb)
{
skb->priority = calc_tx_flits_ofld(skb); /* save for restart */
spin_lock(&q->sendq.lock);
@@ -1735,7 +1735,7 @@ static int ofld_xmit(struct sge_ofld_txq *q, struct sk_buff *skb)
*/
static void restart_ofldq(unsigned long data)
{
- struct sge_ofld_txq *q = (struct sge_ofld_txq *)data;
+ struct sge_uld_txq *q = (struct sge_uld_txq *)data;
spin_lock(&q->sendq.lock);
q->full = 0; /* the queue actually is completely empty now */
@@ -1767,17 +1767,23 @@ static inline unsigned int is_ctrl_pkt(const struct sk_buff *skb)
return skb->queue_mapping & 1;
}
-static inline int ofld_send(struct adapter *adap, struct sk_buff *skb)
+static inline int uld_send(struct adapter *adap, struct sk_buff *skb,
+ unsigned int tx_uld_type)
{
+ struct sge_uld_txq_info *txq_info;
+ struct sge_uld_txq *txq;
unsigned int idx = skb_txq(skb);
+ txq_info = adap->sge.uld_txq_info[tx_uld_type];
+ txq = &txq_info->uldtxq[idx];
+
if (unlikely(is_ctrl_pkt(skb))) {
/* Single ctrl queue is a requirement for LE workaround path */
if (adap->tids.nsftids)
idx = 0;
return ctrl_xmit(&adap->sge.ctrlq[idx], skb);
}
- return ofld_xmit(&adap->sge.ofldtxq[idx], skb);
+ return ofld_xmit(txq, skb);
}
/**
@@ -1794,7 +1800,7 @@ int t4_ofld_send(struct adapter *adap, struct sk_buff *skb)
int ret;
local_bh_disable();
- ret = ofld_send(adap, skb);
+ ret = uld_send(adap, skb, CXGB4_TX_OFLD);
local_bh_enable();
return ret;
}
@@ -1813,6 +1819,39 @@ int cxgb4_ofld_send(struct net_device *dev, struct sk_buff *skb)
}
EXPORT_SYMBOL(cxgb4_ofld_send);
+/**
+ * t4_crypto_send - send crypto packet
+ * @adap: the adapter
+ * @skb: the packet
+ *
+ * Sends crypto packet. We use the packet queue_mapping to select the
+ * appropriate Tx queue as follows: bit 0 indicates whether the packet
+ * should be sent as regular or control, bits 1-15 select the queue.
+ */
+static int t4_crypto_send(struct adapter *adap, struct sk_buff *skb)
+{
+ int ret;
+
+ local_bh_disable();
+ ret = uld_send(adap, skb, CXGB4_TX_CRYPTO);
+ local_bh_enable();
+ return ret;
+}
+
+/**
+ * cxgb4_crypto_send - send crypto packet
+ * @dev: the net device
+ * @skb: the packet
+ *
+ * Sends crypto packet. This is an exported version of @t4_crypto_send,
+ * intended for ULDs.
+ */
+int cxgb4_crypto_send(struct net_device *dev, struct sk_buff *skb)
+{
+ return t4_crypto_send(netdev2adap(dev), skb);
+}
+EXPORT_SYMBOL(cxgb4_crypto_send);
+
static inline void copy_frags(struct sk_buff *skb,
const struct pkt_gl *gl, unsigned int offset)
{
@@ -2479,7 +2518,7 @@ static void sge_tx_timer_cb(unsigned long data)
for (i = 0; i < BITS_TO_LONGS(s->egr_sz); i++)
for (m = s->txq_maperr[i]; m; m &= m - 1) {
unsigned long id = __ffs(m) + i * BITS_PER_LONG;
- struct sge_ofld_txq *txq = s->egr_map[id];
+ struct sge_uld_txq *txq = s->egr_map[id];
clear_bit(id, s->txq_maperr);
tasklet_schedule(&txq->qresume_tsk);
@@ -2799,6 +2838,7 @@ int t4_sge_alloc_eth_txq(struct adapter *adap, struct sge_eth_txq *txq,
return ret;
}
+ txq->q.q_type = CXGB4_TXQ_ETH;
init_txq(adap, &txq->q, FW_EQ_ETH_CMD_EQID_G(ntohl(c.eqid_pkd)));
txq->txq = netdevq;
txq->tso = txq->tx_cso = txq->vlan_ins = 0;
@@ -2852,6 +2892,7 @@ int t4_sge_alloc_ctrl_txq(struct adapter *adap, struct sge_ctrl_txq *txq,
return ret;
}
+ txq->q.q_type = CXGB4_TXQ_CTRL;
init_txq(adap, &txq->q, FW_EQ_CTRL_CMD_EQID_G(ntohl(c.cmpliqid_eqid)));
txq->adap = adap;
skb_queue_head_init(&txq->sendq);
@@ -2872,13 +2913,15 @@ int t4_sge_mod_ctrl_txq(struct adapter *adap, unsigned int eqid,
return t4_set_params(adap, adap->mbox, adap->pf, 0, 1, ¶m, &val);
}
-int t4_sge_alloc_ofld_txq(struct adapter *adap, struct sge_ofld_txq *txq,
- struct net_device *dev, unsigned int iqid)
+int t4_sge_alloc_uld_txq(struct adapter *adap, struct sge_uld_txq *txq,
+ struct net_device *dev, unsigned int iqid,
+ unsigned int uld_type)
{
int ret, nentries;
struct fw_eq_ofld_cmd c;
struct sge *s = &adap->sge;
struct port_info *pi = netdev_priv(dev);
+ int cmd = FW_EQ_OFLD_CMD;
/* Add status entries */
nentries = txq->q.size + s->stat_len / sizeof(struct tx_desc);
@@ -2891,7 +2934,9 @@ int t4_sge_alloc_ofld_txq(struct adapter *adap, struct sge_ofld_txq *txq,
return -ENOMEM;
memset(&c, 0, sizeof(c));
- c.op_to_vfn = htonl(FW_CMD_OP_V(FW_EQ_OFLD_CMD) | FW_CMD_REQUEST_F |
+ if (unlikely(uld_type == CXGB4_TX_CRYPTO))
+ cmd = FW_EQ_CTRL_CMD;
+ c.op_to_vfn = htonl(FW_CMD_OP_V(cmd) | FW_CMD_REQUEST_F |
FW_CMD_WRITE_F | FW_CMD_EXEC_F |
FW_EQ_OFLD_CMD_PFN_V(adap->pf) |
FW_EQ_OFLD_CMD_VFN_V(0));
@@ -2919,6 +2964,7 @@ int t4_sge_alloc_ofld_txq(struct adapter *adap, struct sge_ofld_txq *txq,
return ret;
}
+ txq->q.q_type = CXGB4_TXQ_ULD;
init_txq(adap, &txq->q, FW_EQ_OFLD_CMD_EQID_G(ntohl(c.eqid_pkd)));
txq->adap = adap;
skb_queue_head_init(&txq->sendq);
@@ -2928,7 +2974,7 @@ int t4_sge_alloc_ofld_txq(struct adapter *adap, struct sge_ofld_txq *txq,
return 0;
}
-static void free_txq(struct adapter *adap, struct sge_txq *q)
+void free_txq(struct adapter *adap, struct sge_txq *q)
{
struct sge *s = &adap->sge;
@@ -3026,21 +3072,6 @@ void t4_free_sge_resources(struct adapter *adap)
}
}
- /* clean up offload Tx queues */
- for (i = 0; i < ARRAY_SIZE(adap->sge.ofldtxq); i++) {
- struct sge_ofld_txq *q = &adap->sge.ofldtxq[i];
-
- if (q->q.desc) {
- tasklet_kill(&q->qresume_tsk);
- t4_ofld_eq_free(adap, adap->mbox, adap->pf, 0,
- q->q.cntxt_id);
- free_tx_desc(adap, &q->q, q->q.in_use, false);
- kfree(q->q.sdesc);
- __skb_queue_purge(&q->sendq);
- free_txq(adap, &q->q);
- }
- }
-
/* clean up control Tx queues */
for (i = 0; i < ARRAY_SIZE(adap->sge.ctrlq); i++) {
struct sge_ctrl_txq *cq = &adap->sge.ctrlq[i];
@@ -3093,12 +3124,34 @@ void t4_sge_stop(struct adapter *adap)
if (s->tx_timer.function)
del_timer_sync(&s->tx_timer);
- for (i = 0; i < ARRAY_SIZE(s->ofldtxq); i++) {
- struct sge_ofld_txq *q = &s->ofldtxq[i];
+ if (is_offload(adap)) {
+ struct sge_uld_txq_info *txq_info;
+
+ txq_info = adap->sge.uld_txq_info[CXGB4_TX_OFLD];
+ if (txq_info) {
+ struct sge_uld_txq *txq = txq_info->uldtxq;
- if (q->q.desc)
- tasklet_kill(&q->qresume_tsk);
+ for_each_ofldtxq(&adap->sge, i) {
+ if (txq->q.desc)
+ tasklet_kill(&txq->qresume_tsk);
+ }
+ }
}
+
+ if (is_pci_uld(adap)) {
+ struct sge_uld_txq_info *txq_info;
+
+ txq_info = adap->sge.uld_txq_info[CXGB4_TX_CRYPTO];
+ if (txq_info) {
+ struct sge_uld_txq *txq = txq_info->uldtxq;
+
+ for_each_ofldtxq(&adap->sge, i) {
+ if (txq->q.desc)
+ tasklet_kill(&txq->qresume_tsk);
+ }
+ }
+ }
+
for (i = 0; i < ARRAY_SIZE(s->ctrlq); i++) {
struct sge_ctrl_txq *cq = &s->ctrlq[i];
diff --git a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
index 0039bebaa9e2..4655a9f9dcea 100644
--- a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
+++ b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
@@ -85,6 +85,7 @@ static inline int send_tx_flowc_wr(struct cxgbi_sock *);
static const struct cxgb4_uld_info cxgb4i_uld_info = {
.name = DRV_MODULE_NAME,
.nrxq = MAX_ULD_QSETS,
+ .ntxq = MAX_ULD_QSETS,
.rxq_size = 1024,
.lro = false,
.add = t4_uld_add,
diff --git a/drivers/target/iscsi/cxgbit/cxgbit_main.c b/drivers/target/iscsi/cxgbit/cxgbit_main.c
index ad26b9372f10..96eedfc49c94 100644
--- a/drivers/target/iscsi/cxgbit/cxgbit_main.c
+++ b/drivers/target/iscsi/cxgbit/cxgbit_main.c
@@ -653,6 +653,7 @@ static struct iscsit_transport cxgbit_transport = {
static struct cxgb4_uld_info cxgbit_uld_info = {
.name = DRV_NAME,
.nrxq = MAX_ULD_QSETS,
+ .ntxq = MAX_ULD_QSETS,
.rxq_size = 1024,
.lro = true,
.add = cxgbit_uld_add,
--
2.3.4
^ permalink raw reply related
* Re: [PATCH net-next] bridge: add igmpv3 and mldv2 query support
From: kbuild test robot @ 2016-11-18 10:56 UTC (permalink / raw)
To: Hangbin Liu
Cc: kbuild-all, netdev, Hannes Frederic Sowa, Nikolay Aleksandrov,
linus.luessing, Hangbin Liu
In-Reply-To: <1479454321-31304-1-git-send-email-liuhangbin@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 2471 bytes --]
Hi Hangbin,
[auto build test ERROR on net-next/master]
url: https://github.com/0day-ci/linux/commits/Hangbin-Liu/bridge-add-igmpv3-and-mldv2-query-support/20161118-155854
config: powerpc-defconfig (attached as .config)
compiler: powerpc64-linux-gnu-gcc (Debian 6.1.1-9) 6.1.1 20160705
reproduce:
wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
make.cross ARCH=powerpc
All errors (new ones prefixed by >>):
net/bridge/br_multicast.c: In function 'mld_force_mld_version':
>> net/bridge/br_multicast.c:688:24: error: 'struct net' has no member named 'ipv6'; did you mean 'ipv4'?
if (dev_net(idev->dev)->ipv6.devconf_all->force_mld_version != 0)
^~
net/bridge/br_multicast.c:689:28: error: 'struct net' has no member named 'ipv6'; did you mean 'ipv4'?
return dev_net(idev->dev)->ipv6.devconf_all->force_mld_version;
^~
net/bridge/br_multicast.c: In function 'br_multicast_alloc_query':
net/bridge/br_multicast.c:699:27: error: implicit declaration of function '__in6_dev_get' [-Werror=implicit-function-declaration]
struct inet6_dev *idev = __in6_dev_get(br->dev);
^~~~~~~~~~~~~
net/bridge/br_multicast.c:699:27: warning: initialization makes pointer from integer without a cast [-Wint-conversion]
net/bridge/br_multicast.c:699:20: warning: unused variable 'idev' [-Wunused-variable]
struct inet6_dev *idev = __in6_dev_get(br->dev);
^~~~
At top level:
net/bridge/br_multicast.c:686:12: warning: 'mld_force_mld_version' defined but not used [-Wunused-function]
static int mld_force_mld_version(const struct inet6_dev *idev)
^~~~~~~~~~~~~~~~~~~~~
cc1: some warnings being treated as errors
vim +688 net/bridge/br_multicast.c
682 return skb;
683 }
684 #endif
685
686 static int mld_force_mld_version(const struct inet6_dev *idev)
687 {
> 688 if (dev_net(idev->dev)->ipv6.devconf_all->force_mld_version != 0)
689 return dev_net(idev->dev)->ipv6.devconf_all->force_mld_version;
690 else
691 return idev->cnf.force_mld_version;
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 22647 bytes --]
^ permalink raw reply
* [PATCH net-next] cadence: Add hardware PTP support.
From: Rafal Ozieblo @ 2016-11-18 10:47 UTC (permalink / raw)
To: Nicolas Ferre, Harini Katakam, Andrei Pistirica, netdev,
linux-kernel
Cc: Rafal Ozieblo
Signed-off-by: Rafal Ozieblo <rafalo@cadence.com>
---
Documentation/devicetree/bindings/net/macb.txt | 1 +
drivers/net/ethernet/cadence/macb.c | 742 ++++++++++++++++++++++++-
drivers/net/ethernet/cadence/macb.h | 217 +++++++-
3 files changed, 950 insertions(+), 10 deletions(-)
diff --git a/Documentation/devicetree/bindings/net/macb.txt b/Documentation/devicetree/bindings/net/macb.txt
index 1506e94..27966ae 100644
--- a/Documentation/devicetree/bindings/net/macb.txt
+++ b/Documentation/devicetree/bindings/net/macb.txt
@@ -22,6 +22,7 @@ Required properties:
Required elements: 'pclk', 'hclk'
Optional elements: 'tx_clk'
Optional elements: 'rx_clk' applies to cdns,zynqmp-gem
+ Optional elements: 'tsu_clk'
- clocks: Phandles to input clocks.
Optional properties for PHY child node:
diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
index e1847ce..8481e4a 100644
--- a/drivers/net/ethernet/cadence/macb.c
+++ b/drivers/net/ethernet/cadence/macb.c
@@ -32,7 +32,10 @@
#include <linux/of_gpio.h>
#include <linux/of_mdio.h>
#include <linux/of_net.h>
-
+#include <linux/ptp_clock_kernel.h>
+#include <linux/clocksource.h>
+#include <linux/net_tstamp.h>
+#include <linux/timecounter.h>
#include "macb.h"
#define MACB_RX_BUFFER_SIZE 128
@@ -665,6 +668,81 @@ static void macb_tx_error_task(struct work_struct *work)
spin_unlock_irqrestore(&bp->lock, flags);
}
+#if IS_ENABLED(CONFIG_PTP_1588_CLOCK)
+static int macb_hw_timestamp(struct macb *bp, u32 dma_desc_ts_1, u32 dma_desc_ts_2, struct timespec64 *ts)
+{
+ struct timespec64 tsu;
+
+ ts->tv_sec = (MACB_BFEXT(DMA_TS_MSB_SEC, dma_desc_ts_2) << MACB_DMA_TS_LSB_SEC_SIZE) |
+ MACB_BFEXT(DMA_TS_LSB_SEC, dma_desc_ts_1);
+ ts->tv_nsec = MACB_BFEXT(DMA_TS_NSEC, dma_desc_ts_1);
+
+ /* TSU overlaping workaround
+ * The timestamp only contains lower few bits of seconds,
+ * so add value from 1588 timer
+ */
+ macb_ptp_time_get(bp, &tsu);
+
+ /* If the top bit is set in the timestamp,
+ * but not in 1588 timer, it has rolled over,
+ * so subtract max size
+ */
+ if ((ts->tv_sec & (MACB_DMA_TS_SEC_TOP >> 1)) &&
+ !(tsu.tv_sec & (MACB_DMA_TS_SEC_TOP >> 1)))
+ ts->tv_sec -= MACB_DMA_TS_SEC_TOP;
+
+ ts->tv_sec += ((~MACB_DMA_TS_SEC_MASK) & (tsu.tv_sec));
+
+ return 0;
+}
+
+static void macb_tstamp_tx(struct macb *bp, struct sk_buff *skb, struct macb_dma_desc *desc)
+{
+ struct skb_shared_hwtstamps shhwtstamps;
+ struct timespec64 ts;
+
+ if(MACB_BFEXT(DMA_TX_TS_VALID, desc->ctrl)) {
+ macb_hw_timestamp(bp, desc->dma_desc_ts_1, desc->dma_desc_ts_2, &ts);
+ memset(&shhwtstamps, 0, sizeof(shhwtstamps));
+ shhwtstamps.hwtstamp = ktime_set(ts.tv_sec, ts.tv_nsec);
+ skb_tstamp_tx(skb, &shhwtstamps);
+ }
+}
+
+static void macb_tx_timestamp_flush(struct work_struct *work)
+{
+ struct macb_queue *queue = container_of(work, struct macb_queue, tx_timestamp_task);
+ struct macb_tx_timestamp *tx_timestamp;
+ unsigned long head = smp_load_acquire(&queue->tx_tstamp_head);
+ unsigned long tail = queue->tx_tstamp_tail;
+
+ while (CIRC_CNT(head, tail, PTP_TS_BUFFER_SIZE)) {
+ tx_timestamp = &queue->tx_timestamps[tail];
+ macb_tstamp_tx(queue->bp, tx_timestamp->skb, &tx_timestamp->desc);
+ /* cleanup */
+ dev_kfree_skb_any(tx_timestamp->skb);
+ smp_store_release(&queue->tx_tstamp_tail, (tail + 1) & (PTP_TS_BUFFER_SIZE - 1));
+ tail = queue->tx_tstamp_tail;
+ }
+}
+
+static int macb_tx_timestamp_add(struct macb_queue *queue, struct sk_buff *skb, struct macb_dma_desc *desc)
+{
+ struct macb_tx_timestamp *tx_timestamp;
+ unsigned long head = queue->tx_tstamp_head;
+ unsigned long tail = ACCESS_ONCE(queue->tx_tstamp_tail);
+
+ if (CIRC_SPACE(head, tail, PTP_TS_BUFFER_SIZE) == 0)
+ return -ENOMEM;
+
+ tx_timestamp = &queue->tx_timestamps[head];
+ tx_timestamp->skb = skb;
+ memcpy(&tx_timestamp->desc, desc, sizeof(tx_timestamp->desc));
+ smp_store_release(&queue->tx_tstamp_head, (head + 1) & (PTP_TS_BUFFER_SIZE - 1));
+ return 0;
+}
+#endif
+
static void macb_tx_interrupt(struct macb_queue *queue)
{
unsigned int tail;
@@ -712,6 +790,16 @@ static void macb_tx_interrupt(struct macb_queue *queue)
netdev_vdbg(bp->dev, "skb %u (data %p) TX complete\n",
macb_tx_ring_wrap(bp, tail),
skb->data);
+#if IS_ENABLED(CONFIG_PTP_1588_CLOCK)
+ if (bp->ptp_hw_support)
+ if (macb_tx_timestamp_add(queue, skb, desc) == 0) {
+ /* skb now belongs to timestamp buffer
+ * and will be removed later
+ */
+ tx_skb->skb = NULL;
+ schedule_work(&queue->tx_timestamp_task);
+ }
+#endif
bp->stats.tx_packets++;
bp->stats.tx_bytes += skb->len;
}
@@ -876,6 +964,17 @@ static int gem_rx(struct macb *bp, int budget)
bp->stats.rx_packets++;
bp->stats.rx_bytes += skb->len;
+#if IS_ENABLED(CONFIG_PTP_1588_CLOCK)
+ if (bp->ptp_hw_support) {
+ struct timespec64 ts;
+
+ if (MACB_BFEXT(DMA_RX_TS_VALID, desc->addr)) {
+ macb_hw_timestamp(bp, desc->dma_desc_ts_1, desc->dma_desc_ts_2, &ts);
+ skb_hwtstamps(skb)->hwtstamp = ktime_set(ts.tv_sec, ts.tv_nsec);
+ }
+ }
+#endif
+
#if defined(DEBUG) && defined(VERBOSE_DEBUG)
netdev_vdbg(bp->dev, "received skb of length %u, csum: %08x\n",
skb->len, skb->csum);
@@ -1103,6 +1202,9 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id)
struct macb *bp = queue->bp;
struct net_device *dev = bp->dev;
u32 status, ctrl;
+#if IS_ENABLED(CONFIG_PTP_1588_CLOCK)
+ struct timespec64 ts;
+#endif
status = queue_readl(queue, ISR);
@@ -1195,6 +1297,87 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id)
queue_writel(queue, ISR, MACB_BIT(HRESP));
}
+#if IS_ENABLED(CONFIG_PTP_1588_CLOCK)
+ if (status & MACB_BIT(PTP_DELAY_REQ_FRAME_RECEIVED)) {
+ if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
+ queue_writel(queue, ISR, MACB_BIT(PTP_DELAY_REQ_FRAME_RECEIVED));
+ if (macb_ptp_time_frame_rx_get(bp, &ts) != 0) {
+ ts.tv_sec = 0;
+ ts.tv_nsec = 0;
+ }
+ macb_ptp_event(bp, &ts);
+ }
+
+ if (status & MACB_BIT(PTP_SYNC_FRAME_RECEIVED)) {
+ if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
+ queue_writel(queue, ISR, MACB_BIT(PTP_SYNC_FRAME_RECEIVED));
+ if (macb_ptp_time_frame_rx_get(bp, &ts) != 0) {
+ ts.tv_sec = 0;
+ ts.tv_nsec = 0;
+ }
+ macb_ptp_event(bp, &ts);
+ }
+
+ if (status & MACB_BIT(PTP_DELAY_REQ_FRAME_TRANSMITTED)) {
+ if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
+ queue_writel(queue, ISR, MACB_BIT(PTP_DELAY_REQ_FRAME_TRANSMITTED));
+ if (macb_ptp_time_frame_tx_get(bp, &ts) != 0) {
+ ts.tv_sec = 0;
+ ts.tv_nsec = 0;
+ }
+ macb_ptp_event(bp, &ts);
+ }
+
+ if (status & MACB_BIT(PTP_SYNC_FRAME_TRANSMITTED)) {
+ if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
+ queue_writel(queue, ISR, MACB_BIT(PTP_SYNC_FRAME_TRANSMITTED));
+ if (macb_ptp_time_frame_tx_get(bp, &ts) != 0) {
+ ts.tv_sec = 0;
+ ts.tv_nsec = 0;
+ }
+ macb_ptp_event(bp, &ts);
+ }
+
+ if (status & MACB_BIT(PTP_PDELAY_REQ_FRAME_RECEIVED)) {
+ if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
+ queue_writel(queue, ISR, MACB_BIT(PTP_PDELAY_REQ_FRAME_RECEIVED));
+ if (macb_ptp_time_peer_frame_rx_get(bp, &ts) != 0) {
+ ts.tv_sec = 0;
+ ts.tv_nsec = 0;
+ }
+ macb_ptp_event(bp, &ts);
+ }
+
+ if (status & MACB_BIT(PTP_PDELAY_RESP_FRAME_RECEIVED)) {
+ if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
+ queue_writel(queue, ISR, MACB_BIT(PTP_PDELAY_RESP_FRAME_RECEIVED));
+ if (macb_ptp_time_peer_frame_rx_get(bp, &ts) != 0) {
+ ts.tv_sec = 0;
+ ts.tv_nsec = 0;
+ }
+ macb_ptp_event(bp, &ts);
+ }
+
+ if (status & MACB_BIT(PTP_PDELAY_REQ_FRAME_TRANSMITTED)) {
+ if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
+ queue_writel(queue, ISR, MACB_BIT(PTP_PDELAY_REQ_FRAME_TRANSMITTED));
+ if (macb_ptp_time_peer_frame_tx_get(bp, &ts) != 0) {
+ ts.tv_sec = 0;
+ ts.tv_nsec = 0;
+ }
+ macb_ptp_event(bp, &ts);
+ }
+
+ if (status & MACB_BIT(PTP_PDELAY_RESP_FRAME_TRANSMITTED)) {
+ if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
+ queue_writel(queue, ISR, MACB_BIT(PTP_PDELAY_RESP_FRAME_TRANSMITTED));
+ if (macb_ptp_time_peer_frame_tx_get(bp, &ts) != 0) {
+ ts.tv_sec = 0;
+ ts.tv_nsec = 0;
+ }
+ macb_ptp_event(bp, &ts);
+ }
+#endif
status = queue_readl(queue, ISR);
}
@@ -1422,7 +1605,10 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* Make newly initialized descriptor visible to hardware */
wmb();
- skb_tx_timestamp(skb);
+#if IS_ENABLED(CONFIG_PTP_1588_CLOCK)
+ if (!bp->ptp_hw_support)
+#endif
+ skb_tx_timestamp(skb);
macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(TSTART));
@@ -1752,6 +1938,9 @@ static void macb_configure_dma(struct macb *bp)
#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
dmacfg |= GEM_BIT(ADDR64);
#endif
+#if IS_ENABLED(CONFIG_PTP_1588_CLOCK)
+ dmacfg |= GEM_BIT(RX_EXTENDED_MODE) | GEM_BIT(TX_EXTENDED_MODE);
+#endif
netdev_dbg(bp->dev, "Cadence configure DMA with 0x%08x\n",
dmacfg);
gem_writel(bp, DMACFG, dmacfg);
@@ -1763,7 +1952,7 @@ static void macb_init_hw(struct macb *bp)
struct macb_queue *queue;
unsigned int q;
- u32 config;
+ u32 config, ier;
macb_reset_hw(bp);
macb_set_hwaddr(bp);
@@ -1808,10 +1997,21 @@ static void macb_init_hw(struct macb *bp)
#endif
/* Enable interrupts */
- queue_writel(queue, IER,
- MACB_RX_INT_FLAGS |
- MACB_TX_INT_FLAGS |
- MACB_BIT(HRESP));
+ ier = MACB_RX_INT_FLAGS |
+ MACB_TX_INT_FLAGS |
+ MACB_BIT(HRESP);
+#if IS_ENABLED(CONFIG_PTP_1588_CLOCK)
+ if (bp->ptp_hw_support)
+ ier |= MACB_BIT(PTP_DELAY_REQ_FRAME_TRANSMITTED) |
+ MACB_BIT(PTP_SYNC_FRAME_TRANSMITTED) |
+ MACB_BIT(PTP_PDELAY_REQ_FRAME_TRANSMITTED) |
+ MACB_BIT(PTP_PDELAY_RESP_FRAME_TRANSMITTED) |
+ MACB_BIT(PTP_DELAY_REQ_FRAME_RECEIVED) |
+ MACB_BIT(PTP_SYNC_FRAME_RECEIVED) |
+ MACB_BIT(PTP_PDELAY_REQ_FRAME_RECEIVED) |
+ MACB_BIT(PTP_PDELAY_RESP_FRAME_RECEIVED);
+#endif
+ queue_writel(queue, IER, ier);
}
/* Enable TX and RX */
@@ -2183,6 +2383,34 @@ static void macb_get_regs(struct net_device *dev, struct ethtool_regs *regs,
regs_buff[13] = gem_readl(bp, DMACFG);
}
+int macb_get_ts_info(struct net_device *dev, struct ethtool_ts_info *ts_info)
+{
+#if IS_ENABLED(CONFIG_PTP_1588_CLOCK)
+ struct macb *bp = netdev_priv(dev);
+
+ if (bp->ptp_hw_support) {
+ ts_info->phc_index = ptp_clock_index(bp->ptp_clock);
+ ts_info->so_timestamping =
+ SOF_TIMESTAMPING_TX_SOFTWARE |
+ SOF_TIMESTAMPING_RX_SOFTWARE |
+ SOF_TIMESTAMPING_TX_HARDWARE |
+ SOF_TIMESTAMPING_RX_HARDWARE |
+ SOF_TIMESTAMPING_RAW_HARDWARE |
+ SOF_TIMESTAMPING_SOFTWARE;
+ ts_info->tx_types =
+ (1 << HWTSTAMP_TX_ONESTEP_SYNC) |
+ (1 << HWTSTAMP_TX_OFF) |
+ (1 << HWTSTAMP_TX_ON);
+ ts_info->rx_filters =
+ (1 << HWTSTAMP_FILTER_NONE) |
+ (1 << HWTSTAMP_FILTER_ALL);
+ return 0;
+ }
+ else
+#endif
+ return ethtool_op_get_ts_info(dev, ts_info);
+}
+
static void macb_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
{
struct macb *bp = netdev_priv(netdev);
@@ -2283,7 +2511,7 @@ static const struct ethtool_ops gem_ethtool_ops = {
.get_regs_len = macb_get_regs_len,
.get_regs = macb_get_regs,
.get_link = ethtool_op_get_link,
- .get_ts_info = ethtool_op_get_ts_info,
+ .get_ts_info = macb_get_ts_info,
.get_ethtool_stats = gem_get_ethtool_stats,
.get_strings = gem_get_ethtool_strings,
.get_sset_count = gem_get_sset_count,
@@ -2293,6 +2521,100 @@ static const struct ethtool_ops gem_ethtool_ops = {
.set_ringparam = macb_set_ringparam,
};
+#if IS_ENABLED(CONFIG_PTP_1588_CLOCK)
+int macb_get_ts(struct net_device *dev, struct ifreq *rq)
+{
+ struct macb *bp = netdev_priv(dev);
+ struct hwtstamp_config *tstamp_config = &bp->tstamp_config;
+
+ if (!bp->ptp_hw_support)
+ return -EFAULT;
+ if (copy_to_user(rq->ifr_data, tstamp_config, sizeof(*tstamp_config)))
+ return -EFAULT;
+ else
+ return 0;
+}
+
+int macb_set_ts(struct net_device *dev, struct ifreq *rq)
+{
+ struct macb *bp = netdev_priv(dev);
+ struct hwtstamp_config *tstamp_config = &bp->tstamp_config;
+
+ struct timespec64 ts;
+ struct incrementspec incr_spec;
+
+ enum macb_bd_control tx_bd_control;
+ enum macb_bd_control rx_bd_control;
+
+ if (!bp->ptp_hw_support)
+ return -EFAULT;
+
+ if (copy_from_user(tstamp_config, rq->ifr_data, sizeof(*tstamp_config)))
+ return -EFAULT;
+
+ switch (tstamp_config->tx_type) {
+ case HWTSTAMP_TX_OFF:
+ break;
+ case HWTSTAMP_TX_ONESTEP_SYNC:
+ if (macb_ptp_set_one_step_sync(bp, 1) != 0)
+ return -ERANGE;
+ case HWTSTAMP_TX_ON:
+ tx_bd_control = TSTAMP_ALL_FRAMES;
+ break;
+ default:
+ return -ERANGE;
+ }
+
+ switch (tstamp_config->rx_filter) {
+ case HWTSTAMP_FILTER_NONE:
+ break;
+ case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
+ break;
+ case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
+ break;
+ case HWTSTAMP_FILTER_PTP_V2_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
+ case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
+ case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
+ rx_bd_control = TSTAMP_ALL_PTP_FRAMES;
+ tstamp_config->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
+ break;
+ case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
+ case HWTSTAMP_FILTER_ALL:
+ rx_bd_control = TSTAMP_ALL_FRAMES;
+ tstamp_config->rx_filter = HWTSTAMP_FILTER_ALL;
+ break;
+ default:
+ tstamp_config->rx_filter = HWTSTAMP_FILTER_NONE;
+ return -ERANGE;
+ }
+
+ /* 1. get current system time */
+ ts = ns_to_timespec64(ktime_to_ns(ktime_get_real()));
+
+ /* 2. set ptp timer */
+ macb_ptp_time_set(bp, &ts);
+
+ /* 3. set PTP timer increment value to BASE_INCREMENT */
+ incr_spec.sub_ns = bp->tsu_incr.sub_ns;
+ incr_spec.ns = bp->tsu_incr.ns;
+ macb_ptp_increment_set(bp, &incr_spec);
+
+ if (macb_ptp_set_tstamp_mode(bp, tx_bd_control, rx_bd_control) != 0)
+ return -ERANGE;
+
+ if (copy_to_user(rq->ifr_data, tstamp_config, sizeof(*tstamp_config)))
+ return -EFAULT;
+ else
+ return 0;
+}
+#endif
+
static int macb_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
struct phy_device *phydev = dev->phydev;
@@ -2303,6 +2625,13 @@ static int macb_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
if (!phydev)
return -ENODEV;
+#if IS_ENABLED(CONFIG_PTP_1588_CLOCK)
+ if (cmd == SIOCGHWTSTAMP)
+ return macb_get_ts(dev, rq);
+
+ if (cmd == SIOCSHWTSTAMP)
+ return macb_set_ts(dev, rq);
+#endif
return phy_mii_ioctl(phydev, rq, cmd);
}
@@ -3147,6 +3476,17 @@ static int macb_probe(struct platform_device *pdev)
macb_is_gem(bp) ? "GEM" : "MACB", macb_readl(bp, MID),
dev->base_addr, dev->irq, dev->dev_addr);
+#if IS_ENABLED(CONFIG_PTP_1588_CLOCK)
+ /* Enable PTP */
+ bp->ptp_hw_support = false;
+ if (GEM_BFEXT(TSU, gem_readl(bp, DCFG5))) {
+ err = macb_ptp_init(pdev);
+ if (err)
+ dev_err(&pdev->dev, "Cannot initialize ptp.\n");
+ else
+ bp->ptp_hw_support = true;
+ }
+#endif
return 0;
err_out_unregister_mdio:
@@ -3245,6 +3585,392 @@ static int __maybe_unused macb_resume(struct device *dev)
return 0;
}
+#if IS_ENABLED(CONFIG_PTP_1588_CLOCK)
+int macb_ptp_init(struct platform_device *pdev)
+{
+ struct net_device *dev = platform_get_drvdata(pdev);
+ struct macb *bp = netdev_priv(dev);
+ u64 tsu_f, temp;
+ unsigned int q;
+ struct macb_queue *queue;
+
+ for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) {
+ queue->tx_tstamp_head = 0;
+ queue->tx_tstamp_tail = 0;
+ INIT_WORK(&queue->tx_timestamp_task, macb_tx_timestamp_flush);
+ }
+
+ snprintf(bp->ptp_clock_info.name, 16, "macb_ptp");
+ bp->ptp_clock_info.max_adj = (64E6);
+ bp->ptp_clock_info.n_alarm = 1;
+ bp->ptp_clock_info.n_ext_ts = 1;
+ bp->ptp_clock_info.n_per_out = 0;
+ bp->ptp_clock_info.n_pins = 0;
+ bp->ptp_clock_info.pps = 1;
+ bp->ptp_clock_info.adjfreq = macb_ptp_adjfreq;
+ bp->ptp_clock_info.adjtime = macb_ptp_adjtime;
+ bp->ptp_clock_info.gettime64 = macb_ptp_gettime;
+ bp->ptp_clock_info.settime64 = macb_ptp_settime;
+ bp->ptp_clock_info.enable = macb_ptp_enable;
+
+ bp->ptp_clock = ptp_clock_register(&bp->ptp_clock_info, &pdev->dev);
+
+ bp->tsu_clk = devm_clk_get(&pdev->dev, "tsu_clk");
+ if (!IS_ERR(bp->tsu_clk)) {
+ tsu_f = clk_get_rate(bp->tsu_clk);
+ }
+ /* try pclk instead */
+ else if (!IS_ERR(bp->pclk)) {
+ bp->tsu_clk = bp->pclk;
+ tsu_f = clk_get_rate(bp->tsu_clk);
+ } else
+ return -ENOTSUPP;
+
+ bp->tsu_incr.ns = div_u64(NSEC_PER_SEC, tsu_f);
+ temp = (NSEC_PER_SEC - ((u64)bp->tsu_incr.ns * tsu_f));
+ temp *= (1 << MACB_SUB_NS_INCR_SIZE);
+ bp->tsu_incr.sub_ns = div_u64(temp, tsu_f);
+
+ return 0;
+}
+
+void macb_ptp_stop(struct platform_device *pdev)
+{
+ struct net_device *dev = platform_get_drvdata(pdev);
+ struct macb *bp = netdev_priv(dev);
+
+ if (bp->ptp_clock)
+ ptp_clock_unregister(bp->ptp_clock);
+}
+
+/* Interface of Linux PTP Framework */
+
+int macb_ptp_adjfreq(struct ptp_clock_info *ptp_clock_info, s32 ppb)
+{
+ struct incrementspec incr_spec;
+ struct macb *bp = container_of(ptp_clock_info, struct macb, ptp_clock_info);
+ u64 period, temp;
+ bool neg_adj = false;
+ unsigned long flags;
+
+ if (!ptp_clock_info)
+ return -EINVAL;
+
+ if (ppb < 0) {
+ neg_adj = true;
+ ppb = -ppb;
+ }
+
+ /* Adjustment is relative to base frequency */
+ incr_spec.sub_ns = bp->tsu_incr.sub_ns;
+ incr_spec.ns = bp->tsu_incr.ns;
+
+ /* scaling */
+ period = ((u64) incr_spec.ns << MACB_SUB_NS_INCR_SIZE) + incr_spec.sub_ns;
+ temp = (u64)ppb * period;
+ /* Divide with rounding, equivalent to floating dividing:
+ * (temp / NSEC_PER_SEC) + 0.5
+ */
+ temp = div_u64(temp + (NSEC_PER_SEC >> 1), NSEC_PER_SEC);
+
+ period = neg_adj ? (period - temp) : (period + temp);
+
+ incr_spec.ns = (period >> MACB_SUB_NS_INCR_SIZE) & ((1 << MACB_NUM_INCS_SIZE) - 1);
+ incr_spec.sub_ns = period & ((1 << MACB_SUB_NS_INCR_SIZE) - 1);
+
+ spin_lock_irqsave(&bp->lock, flags);
+ macb_ptp_increment_set(bp, &incr_spec);
+
+ spin_unlock_irqrestore(&bp->lock, flags);
+ return 0;
+}
+
+int macb_ptp_adjtime(struct ptp_clock_info *ptp_clock_info, s64 delta)
+{
+
+ u64 ts_nsec;
+ struct timespec64 ts;
+ struct macb *bp = container_of(ptp_clock_info, struct macb, ptp_clock_info);
+
+ if (!ptp_clock_info)
+ return -EINVAL;
+
+ if (delta >= -TSU_NSEC_MAX_VAL && delta <= TSU_NSEC_MAX_VAL) {
+ macb_ptp_time_adjust(bp, (s32)delta);
+ } else {
+ macb_ptp_time_get(bp, &ts);
+
+ ts_nsec = ts.tv_nsec + ts.tv_sec * NSEC_PER_SEC;
+ ts_nsec += delta;
+
+ ts.tv_sec = div_u64(ts_nsec, NSEC_PER_SEC);
+ ts.tv_nsec = ts_nsec - ts.tv_sec * NSEC_PER_SEC;
+
+ macb_ptp_time_set(bp, &ts);
+ }
+
+ return 0;
+}
+
+
+int macb_ptp_gettime(struct ptp_clock_info *ptp_clock_info, struct timespec64 *ts)
+{
+ struct macb *bp = container_of(ptp_clock_info, struct macb, ptp_clock_info);
+
+ if (!ptp_clock_info || !ts)
+ return -EINVAL;
+
+ macb_ptp_time_get(bp, ts);
+ return 0;
+}
+
+int macb_ptp_settime(struct ptp_clock_info *ptp_clock_info, const struct timespec64 *ts)
+{
+ struct macb *bp = container_of(ptp_clock_info, struct macb, ptp_clock_info);
+
+ if (!ptp_clock_info || !ts)
+ return -EINVAL;
+
+ macb_ptp_time_set(bp, ts);
+ return 0;
+}
+
+int macb_ptp_enable(struct ptp_clock_info *ptp_clock_info,
+ struct ptp_clock_request *request, int on)
+{
+ struct macb *bp = container_of(ptp_clock_info, struct macb, ptp_clock_info);
+ u32 mask;
+
+ if (!ptp_clock_info || !request)
+ return -EINVAL;
+
+ switch (request->type) {
+ case PTP_CLK_REQ_EXTTS: /* Toggle TSU match interrupt */
+ mask = macb_readl(bp, IMR) | (1 << MACB_TSU_TIMER_COMPARISON_INTERRUPT_OFFSET);
+ if (on)
+ macb_writel(bp, IER, mask);
+ else
+ macb_writel(bp, IDR, mask);
+ break;
+ case PTP_CLK_REQ_PEROUT: /* Toggle Periodic output */
+ return -EOPNOTSUPP;
+ /* break; */
+ case PTP_CLK_REQ_PPS: /* Toggle TSU periodic (second) interrupt */
+ mask = macb_readl(bp, IMR) | (1 << MACB_TSU_SECONDS_REGISTER_INCREMENT_OFFSET);
+ if (on)
+ macb_writel(bp, IER, mask);
+ else
+ macb_writel(bp, IDR, mask);
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+
+/* End of Interface of Linux PTP Framework */
+
+int macb_ptp_increment_get(struct macb *bp, struct incrementspec *incr_spec)
+{
+ u32 sub_ns_reg;
+ u32 ns_reg;
+
+ if (!bp || !incr_spec)
+ return -EINVAL;
+
+ sub_ns_reg = macb_readl(bp, TSU_TIMER_INCR_SUB_NSEC);
+ ns_reg = macb_readl(bp, TSU_TIMER_INCR);
+
+ incr_spec->sub_ns = MACB_BFEXT(SUB_NS_INCR_MSB, sub_ns_reg) << MACB_SUB_NS_INCR_LSB_SIZE | MACB_BFEXT(SUB_NS_INCR_LSB, sub_ns_reg);
+ incr_spec->ns = MACB_BFEXT(NS_INCREMENT, ns_reg);
+
+ return 0;
+}
+
+int macb_ptp_increment_set(struct macb *bp, struct incrementspec *incr_spec)
+{
+ u32 sub_ns_reg;
+ u32 ns_reg;
+
+ if (!bp || !incr_spec)
+ return -EINVAL;
+
+ sub_ns_reg = MACB_BF(SUB_NS_INCR_LSB, incr_spec->sub_ns)
+ | (((incr_spec->sub_ns & ~((1 << MACB_SUB_NS_INCR_LSB_SIZE) - 1)) >> MACB_SUB_NS_INCR_LSB_SIZE));
+ ns_reg = incr_spec->ns;
+
+ /* tsu_timer_incr register must be written after the tsu_timer_incr_sub_ns register
+ * and the write operation will cause the value written to the tsu_timer_incr_sub_ns
+ * register to take effect.
+ */
+ macb_writel(bp, TSU_TIMER_INCR_SUB_NSEC, sub_ns_reg);
+ macb_writel(bp, TSU_TIMER_INCR, ns_reg);
+
+ return 0;
+}
+
+int macb_ptp_time_adjust(struct macb *bp, s32 delta)
+{
+ bool subtract = 0;
+ u32 val = 0;
+
+ if (!bp)
+ return -EINVAL;
+
+ if ((delta < -TSU_NSEC_MAX_VAL) || (delta > TSU_NSEC_MAX_VAL))
+ return -EINVAL;
+
+ if (delta < 0) {
+ subtract = 1;
+ delta = -delta;
+ }
+
+ val = (subtract << MACB_ADD_SUBTRACT_OFFSET) | delta;
+
+ macb_writel(bp, TSU_TIMER_ADJUST, val);
+
+ return 0;
+}
+
+int macb_ptp_time_get(struct macb *bp, struct timespec64 *ts)
+{
+ long first, second;
+ u32 sec, msb_sec;
+
+ if (!bp || !ts)
+ return -EINVAL;
+
+ first = macb_readl(bp, TSU_TMR_NSEC);
+ sec = macb_readl(bp, TSU_TMR_SEC);
+ msb_sec = macb_readl(bp, TSU_TMR_MSB_SEC);
+ second = macb_readl(bp, TSU_TMR_NSEC);
+
+ /* test for nsec rollover */
+ if (first > second) {
+ /* if so, use later read & re-read seconds
+ * (assume all done within 1s)
+ */
+ ts->tv_nsec = macb_readl(bp, TSU_TMR_NSEC);
+ sec = macb_readl(bp, TSU_TMR_SEC);
+ msb_sec = macb_readl(bp, TSU_TMR_MSB_SEC);
+ } else
+ ts->tv_nsec = first;
+
+ ts->tv_sec = (((u64)msb_sec << MACB_TIMER_LSB_SEC_SIZE) | sec)
+ & TSU_SEC_MAX_VAL;
+
+ return 0;
+}
+
+int macb_ptp_time_set(struct macb *bp, const struct timespec64 *ts)
+{
+ if (!bp || !ts)
+ return -EINVAL;
+
+ macb_writel(bp, TSU_TMR_MSB_SEC, (ts->tv_sec >> MACB_TIMER_LSB_SEC_SIZE)
+ & ((1 << MACB_TIMER_MSB_SEC_SIZE) - 1));
+ /* write lower bits 2nd, for synchronised secs update */
+ macb_writel(bp, TSU_TMR_SEC, ts->tv_sec & (((u64)1 << MACB_TIMER_LSB_SEC_SIZE) - 1));
+ macb_writel(bp, TSU_TMR_NSEC, ts->tv_nsec);
+
+ return 0;
+}
+
+int macb_ptp_time_peer_frame_tx_get(struct macb *bp, struct timespec64 *ts)
+{
+ if (!bp || !ts)
+ return -EINVAL;
+
+ ts->tv_sec = (((u64)macb_readl(bp, TSU_PEER_TX_MSB_SEC) << 32) |
+ macb_readl(bp, TSU_PEER_TX_SEC)) & TSU_SEC_MAX_VAL;
+ ts->tv_nsec = macb_readl(bp, TSU_PEER_TX_NSEC);
+
+ return 0;
+}
+
+int macb_ptp_time_peer_frame_rx_get(struct macb *bp, struct timespec64 *ts)
+{
+ if (!bp || !ts)
+ return -EINVAL;
+
+ ts->tv_sec = (((u64)macb_readl(bp, TSU_PEER_RX_MSB_SEC) << 32) |
+ macb_readl(bp, TSU_PEER_RX_SEC)) & TSU_SEC_MAX_VAL;
+ ts->tv_nsec = macb_readl(bp, TSU_PEER_RX_NSEC);
+
+ return 0;
+}
+
+int macb_ptp_time_frame_tx_get(struct macb *bp, struct timespec64 *ts)
+{
+ if (!bp || !ts)
+ return -EINVAL;
+
+ ts->tv_sec = (((u64)macb_readl(bp, TSU_PTP_TX_MSB_SEC) << 32) |
+ macb_readl(bp, TSU_PTP_TX_SEC)) & TSU_SEC_MAX_VAL;
+ ts->tv_nsec = macb_readl(bp, TSU_PTP_TX_NSEC);
+
+ return 0;
+}
+
+int macb_ptp_time_frame_rx_get(struct macb *bp, struct timespec64 *ts)
+{
+ if (!bp || !ts)
+ return -EINVAL;
+
+ ts->tv_sec = (((u64)macb_readl(bp, TSU_PTP_RX_MSB_SEC) << 32) |
+ macb_readl(bp, TSU_PTP_RX_SEC)) & TSU_SEC_MAX_VAL;
+ ts->tv_nsec = macb_readl(bp, TSU_PTP_RX_NSEC);
+
+ return 0;
+}
+
+int macb_ptp_event(struct macb *bp, struct timespec64 *ts)
+{
+ struct ptp_clock_event event;
+
+ event.type = PTP_CLOCK_EXTTS;
+ event.index = 0;
+ event.timestamp = ts->tv_sec * NSEC_PER_SEC + ts->tv_nsec;
+
+ ptp_clock_event(bp->ptp_clock, &event);
+
+ return 0;
+}
+
+int macb_ptp_set_one_step_sync(struct macb *bp, u8 enable)
+{
+ u32 reg_val;
+
+ if (!bp)
+ return -EINVAL;
+ if (enable < 0 || enable > 1)
+ return -EINVAL;
+
+ reg_val = macb_readl(bp, NCR);
+
+ if (enable)
+ macb_writel(bp, NCR, reg_val | MACB_BIT(ONE_STEP_SYNC_MODE));
+ else
+ macb_writel(bp, NCR, reg_val & ~MACB_BIT(ONE_STEP_SYNC_MODE));
+
+ return 0;
+}
+
+int macb_ptp_set_tstamp_mode(struct macb *bp,
+ enum macb_bd_control tx_bd_control,
+ enum macb_bd_control rx_bd_control)
+{
+ if (!bp)
+ return -EINVAL;
+
+ macb_writel(bp, TX_BD_CONTROL, MACB_BF(TX_BD_TS_MODE, tx_bd_control));
+ macb_writel(bp, RX_BD_CONTROL, MACB_BF(RX_BD_TS_MODE, rx_bd_control));
+
+ return 0;
+}
+#endif
+
static SIMPLE_DEV_PM_OPS(macb_pm_ops, macb_suspend, macb_resume);
static struct platform_driver macb_driver = {
diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h
index 1216950..1381f0a 100644
--- a/drivers/net/ethernet/cadence/macb.h
+++ b/drivers/net/ethernet/cadence/macb.h
@@ -66,8 +66,32 @@
#define MACB_USRIO 0x00c0
#define MACB_WOL 0x00c4
#define MACB_MID 0x00fc
-#define MACB_TBQPH 0x04C8
-#define MACB_RBQPH 0x04D4
+
+#define MACB_TSU_PTP_TX_MSB_SEC 0x00e8 /* PTP Event Frame Transmitted Seconds Register 47:32 */
+#define MACB_TSU_PTP_RX_MSB_SEC 0x00ec /* PTP Event Frame Received Seconds Register 47:32 */
+#define MACB_TSU_PEER_TX_MSB_SEC 0x00f0 /* PTP Peer Event Frame Transmitted Seconds Register 47:32 */
+#define MACB_TSU_PEER_RX_MSB_SEC 0x00f4 /* PTP Peer Event Frame Received Seconds Register 47:32 */
+#define MACB_TSU_TIMER_INCR_SUB_NSEC 0x01bc /* Sub-nanoseconds increment */
+#define MACB_TSU_TIMER_INCR 0x01dc /* Nanoseconds increment */
+#define MACB_TSU_TMR_MSB_SEC 0x01c0 /* Upper second count of Time Stamp Unit */
+#define MACB_TSU_TMR_SEC 0x01d0 /* Lower second count of Time Stamp Unit */
+#define MACB_TSU_TMR_NSEC 0x01d4 /* Nanosecond count of Time Stamp Unit */
+#define MACB_TSU_TIMER_ADJUST 0x01d8 /* Nanosecond Adjust Register */
+#define MACB_TSU_TIMER_INCR_SUB_NSEC 0x01bc /* Sub-nanosecond Adjust Register */
+#define MACB_TSU_TIMER_INCR 0x01dc /* Nanosecond Adjust Register */
+#define MACB_TSU_PTP_TX_SEC 0x01e0 /* PTP Event Frame Transmitted Seconds Register 31:0 */
+#define MACB_TSU_PTP_TX_NSEC 0x01e4 /* PTP Event Frame Transmitted Nanoseconds Register */
+#define MACB_TSU_PTP_RX_SEC 0x01e8 /* PTP Event Frame Received Seconds Register 31:0 */
+#define MACB_TSU_PTP_RX_NSEC 0x01ec /* PTP Event Frame Received Nanoseconds Register */
+#define MACB_TSU_PEER_TX_SEC 0x01f0 /* PTP Peer Event Frame Transmitted Seconds Register 31:0 */
+#define MACB_TSU_PEER_TX_NSEC 0x01f4 /* PTP Peer Event Frame Transmitted Nanoseconds Register */
+#define MACB_TSU_PEER_RX_SEC 0x01f8 /* PTP Peer Event Frame Received Seconds Register 31:0 */
+#define MACB_TSU_PEER_RX_NSEC 0x01fc /* PTP Peer Event Frame Received Nanoseconds Register */
+
+#define MACB_TX_BD_CONTROL 0x04cc /* TX Buffer Descriptor control register */
+#define MACB_RX_BD_CONTROL 0x04d0 /* RX Buffer Descriptor control register */
+#define MACB_TBQPH 0x04c8
+#define MACB_RBQPH 0x04d4
/* GEM register offsets. */
#define GEM_NCFGR 0x0004 /* Network Config */
@@ -174,6 +198,8 @@
#define MACB_NCR_TPF_SIZE 1
#define MACB_TZQ_OFFSET 12 /* Transmit zero quantum pause frame */
#define MACB_TZQ_SIZE 1
+#define MACB_ONE_STEP_SYNC_MODE_OFFSET 24 /* Enable One Step Synchro Mode */
+#define MACB_ONE_STEP_SYNC_MODE_SIZE 1
/* Bitfields in NCFGR */
#define MACB_SPD_OFFSET 0 /* Speed */
@@ -252,6 +278,10 @@
#define GEM_RXBS_SIZE 8
#define GEM_DDRP_OFFSET 24 /* disc_when_no_ahb */
#define GEM_DDRP_SIZE 1
+#define GEM_RX_EXTENDED_MODE_OFFSET 28 /* RX extended Buffer Descriptor mode */
+#define GEM_RX_EXTENDED_MODE_SIZE 1
+#define GEM_TX_EXTENDED_MODE_OFFSET 29 /* TX extended Buffer Descriptor mode */
+#define GEM_TX_EXTENDED_MODE_SIZE 1
#define GEM_ADDR64_OFFSET 30 /* Address bus width - 64b or 32b */
#define GEM_ADDR64_SIZE 1
@@ -319,6 +349,26 @@
#define MACB_PTZ_SIZE 1
#define MACB_WOL_OFFSET 14 /* Enable wake-on-lan interrupt */
#define MACB_WOL_SIZE 1
+#define MACB_PTP_DELAY_REQ_FRAME_RECEIVED_OFFSET 18 /* PTP delay_req frame received */
+#define MACB_PTP_DELAY_REQ_FRAME_RECEIVED_SIZE 1
+#define MACB_PTP_SYNC_FRAME_RECEIVED_OFFSET 19 /* PTP sync frame received */
+#define MACB_PTP_SYNC_FRAME_RECEIVED_SIZE 1
+#define MACB_PTP_DELAY_REQ_FRAME_TRANSMITTED_OFFSET 20 /* PTP delay_req frame transmitted */
+#define MACB_PTP_DELAY_REQ_FRAME_TRANSMITTED_SIZE 1
+#define MACB_PTP_SYNC_FRAME_TRANSMITTED_OFFSET 21 /* PTP sync frame transmitted */
+#define MACB_PTP_SYNC_FRAME_TRANSMITTED_SIZE 1
+#define MACB_PTP_PDELAY_REQ_FRAME_RECEIVED_OFFSET 22 /* PTP pdelay_req frame received */
+#define MACB_PTP_PDELAY_REQ_FRAME_RECEIVED_SIZE 1
+#define MACB_PTP_PDELAY_RESP_FRAME_RECEIVED_OFFSET 23 /* PTP pdelay_resp frame received */
+#define MACB_PTP_PDELAY_RESP_FRAME_RECEIVED_SIZE 1
+#define MACB_PTP_PDELAY_REQ_FRAME_TRANSMITTED_OFFSET 24 /* PTP pdelay_req frame transmitted */
+#define MACB_PTP_PDELAY_REQ_FRAME_TRANSMITTED_SIZE 1
+#define MACB_PTP_PDELAY_RESP_FRAME_TRANSMITTED_OFFSET 25 /* PTP pdelay_resp frame transmitted */
+#define MACB_PTP_PDELAY_RESP_FRAME_TRANSMITTED_SIZE 1
+#define MACB_TSU_SECONDS_REGISTER_INCREMENT_OFFSET 26 /* TSU periodic (second) interrup */
+#define MACB_TSU_SECONDS_REGISTER_INCREMENT_SIZE 1
+#define MACB_TSU_TIMER_COMPARISON_INTERRUPT_OFFSET 29 /* TSU match interrupt */
+#define MACB_TSU_TIMER_COMPARISON_INTERRUPT_SIZE 1
/* Bitfields in MAN */
#define MACB_DATA_OFFSET 0 /* data */
@@ -382,6 +432,10 @@
#define GEM_TX_PKT_BUFF_OFFSET 21
#define GEM_TX_PKT_BUFF_SIZE 1
+/* Bitfields in DCFG5. */
+#define GEM_TSU_OFFSET 8
+#define GEM_TSU_SIZE 1
+
/* Constants for CLK */
#define MACB_CLK_DIV8 0
#define MACB_CLK_DIV16 1
@@ -402,6 +456,74 @@
#define MACB_MAN_READ 2
#define MACB_MAN_CODE 2
+/* Constants for TSU */
+/* MACB_TSU_TIMER_INCR_SUB_NSEC */
+#define MACB_SUB_NS_INCR_MSB_OFFSET 0 /* sub-ns MSB [23:8] which the 1588 timer will be incremented each clock cycle */
+#define MACB_SUB_NS_INCR_MSB_SIZE 16
+#define MACB_SUB_NS_INCR_LSB_OFFSET 24 /* sub-ns MSB [7:0] which the 1588 timer will be incremented each clock cycle */
+#define MACB_SUB_NS_INCR_LSB_SIZE 8
+#define MACB_SUB_NS_INCR_SIZE (MACB_SUB_NS_INCR_MSB_SIZE + MACB_SUB_NS_INCR_LSB_SIZE)
+
+/* MACB_TSU_TIMER_INCR */
+#define MACB_NS_INCREMENT_OFFSET 0 /* ns [7:0] which the 1588 timer will be incremented each clock cycle */
+#define MACB_NS_INCREMENT_SIZE 8
+#define MACB_ALT_NS_INCR_OFFSET 8 /* Alternative nanoseconds count */
+#define MACB_ALT_NS_INCR_SIZE 8
+#define MACB_NUM_INCS_OFFSET 16 /* Number of incs before alt inc */
+#define MACB_NUM_INCS_SIZE 8
+
+/* MACB_TSU_TIMER_ADJUST */
+#define MACB_INCREMENT_VALUE_OFFSET 0 /* Timer increment value */
+#define MACB_INCREMENT_VALUE_SIZE 30
+#define MACB_ADD_SUBTRACT_OFFSET 31 /* Write as one to subtract from the 1588 timer */
+#define MACB_ADD_SUBTRACT_SIZE 1
+
+/* MACB_TSU_TIMER_MSB_SEC */
+#define MACB_TIMER_MSB_SEC_OFFSET 0 /* TSU timer value (s). MSB [47:32] of seconds timer count */
+#define MACB_TIMER_MSB_SEC_SIZE 16
+
+/* MACB_TSU_TIMER_SEC */
+#define MACB_TIMER_LSB_SEC_OFFSET 0 /* TSU timer value (s). LSB [31:0] of seconds timer count */
+#define MACB_TIMER_LSB_SEC_SIZE 32
+
+/* MACB_TSU_TIMER_NSEC */
+#define MACB_TIMER_NSEC_OFFSET 0 /* TSU timer value (ns) */
+#define MACB_TIMER_NSEC_SIZE 30
+
+/* Transmit DMA buffer descriptor Word 1 */
+#define MACB_DMA_TX_TS_VALID_OFFSET 23 /* timestamp has been captured in the Buffer Descriptor */
+#define MACB_DMA_TX_TS_VALID_SIZE 1
+
+/* Receive DMA buffer descriptor Word 0 */
+#define MACB_DMA_RX_TS_VALID_OFFSET 2 /* indicates a valid timestamp in the Buffer Descriptor */
+#define MACB_DMA_RX_TS_VALID_SIZE 1
+
+/* DMA buffer descriptor Word 2 (32 bit addressing) or Word 4 (64 bit addressing) */
+#define MACB_DMA_TS_LSB_SEC_OFFSET 30 /* Timestamp seconds[1:0] */
+#define MACB_DMA_TS_LSB_SEC_SIZE 2
+#define MACB_DMA_TS_NSEC_OFFSET 0 /* Timestamp nanosecs [29:0] */
+#define MACB_DMA_TS_NSEC_SIZE 30
+
+/* DMA buffer descriptor Word 3 (32 bit addressing) or Word 5 (64 bit addressing) */
+
+/* New hardware supports 12 bit precision of timestamp in DMA buffer descriptor.
+ * Old hardware supports only 6 bit precision but it is enough for PTP.
+ * Less accuracy is used always instead of checking hardware version.
+ */
+#define MACB_DMA_TS_MSB_SEC_OFFSET 0 /* Timestamp seconds[5:2] */
+#define MACB_DMA_TS_MSB_SEC_SIZE 4
+#define MACB_DMA_TS_SEC_WIDTH (MACB_DMA_TS_MSB_SEC_SIZE + MACB_DMA_TS_LSB_SEC_SIZE)
+#define MACB_DMA_TS_SEC_TOP (1 << MACB_DMA_TS_SEC_WIDTH)
+#define MACB_DMA_TS_SEC_MASK (MACB_DMA_TS_SEC_TOP - 1)
+
+/* Constants for TX_BD_CONTROL */
+#define MACB_TX_BD_TS_MODE_OFFSET 4 /* TX Descriptor Timestamp Insertion mode */
+#define MACB_TX_BD_TS_MODE_SIZE 2
+
+/* Constants for RX_BD_CONTROL */
+#define MACB_RX_BD_TS_MODE_OFFSET 4 /* RX Descriptor Timestamp Insertion mode */
+#define MACB_RX_BD_TS_MODE_SIZE 2
+
/* Capability mask bits */
#define MACB_CAPS_ISR_CLEAR_ON_WRITE 0x00000001
#define MACB_CAPS_USRIO_HAS_CLKEN 0x00000002
@@ -449,6 +571,8 @@
#define queue_readl(queue, reg) (queue)->bp->macb_reg_readl((queue)->bp, (queue)->reg)
#define queue_writel(queue, reg, value) (queue)->bp->macb_reg_writel((queue)->bp, (queue)->reg, (value))
+#define PTP_TS_BUFFER_SIZE 128 /* must be power of 2 */
+
/* Conditional GEM/MACB macros. These perform the operation to the correct
* register dependent on whether the device is a GEM or a MACB. For registers
* and bitfields that are common across both devices, use macb_{read,write}l
@@ -483,7 +607,18 @@ struct macb_dma_desc {
u32 addrh;
u32 resvd;
#endif
+#if IS_ENABLED(CONFIG_PTP_1588_CLOCK)
+ u32 dma_desc_ts_1;
+ u32 dma_desc_ts_2;
+#endif
+};
+
+#if IS_ENABLED(CONFIG_PTP_1588_CLOCK)
+struct macb_tx_timestamp {
+ struct sk_buff *skb;
+ struct macb_dma_desc desc;
};
+#endif
/* DMA descriptor bitfields */
#define MACB_RX_USED_OFFSET 0
@@ -794,8 +929,22 @@ struct macb_queue {
struct macb_tx_skb *tx_skb;
dma_addr_t tx_ring_dma;
struct work_struct tx_error_task;
+
+#if IS_ENABLED(CONFIG_PTP_1588_CLOCK)
+ /* PTP support */
+ struct work_struct tx_timestamp_task;
+ unsigned int tx_tstamp_head, tx_tstamp_tail;
+ struct macb_tx_timestamp tx_timestamps[PTP_TS_BUFFER_SIZE];
+#endif
};
+#if IS_ENABLED(CONFIG_PTP_1588_CLOCK)
+struct incrementspec {
+ u32 sub_ns;
+ u32 ns;
+};
+#endif
+
struct macb {
void __iomem *regs;
bool native_io;
@@ -860,8 +1009,72 @@ struct macb {
unsigned int jumbo_max_len;
u32 wol;
+#if IS_ENABLED(CONFIG_PTP_1588_CLOCK)
+ /* PTP support */
+ bool ptp_hw_support;
+ struct ptp_clock_info ptp_clock_info;
+ struct ptp_clock *ptp_clock;
+ struct clk *tsu_clk;
+ struct incrementspec tsu_incr;
+ struct hwtstamp_config tstamp_config;
+#endif
+};
+
+#if IS_ENABLED(CONFIG_PTP_1588_CLOCK)
+#define MACB_TIMER_SEC_SIZE (MACB_TIMER_MSB_SEC_SIZE + MACB_TIMER_LSB_SEC_SIZE)
+#define TSU_SEC_MAX_VAL (((u64)1 << MACB_TIMER_SEC_SIZE) - 1)
+#define TSU_NSEC_MAX_VAL ((1 << MACB_TIMER_NSEC_SIZE) - 1)
+
+enum macb_bd_control {
+ TSTAMP_DISABLED,
+ TSTAMP_FRAME_PTP_EVENT_ONLY,
+ TSTAMP_ALL_PTP_FRAMES,
+ TSTAMP_ALL_FRAMES,
};
+int macb_ptp_init(struct platform_device *pdev);
+void macb_ptp_stop(struct platform_device *pdev);
+
+int macb_ptp_verify(struct ptp_clock_info *ptp_clock_info, unsigned int pin,
+ enum ptp_pin_function func, unsigned int chan);
+
+/* Following functions implement interface functions of Linux PTP
+ * Framework.
+ */
+int macb_ptp_adjfreq(struct ptp_clock_info *ptp_clock_info, s32 ppb);
+int macb_ptp_adjtime(struct ptp_clock_info *ptp_clock_info, s64 delta);
+int macb_ptp_gettime(struct ptp_clock_info *ptp_clock_info,
+ struct timespec64 *ts);
+int macb_ptp_settime(struct ptp_clock_info *ptp_clock_info,
+ const struct timespec64 *ts);
+int macb_ptp_enable(struct ptp_clock_info *ptp_clock_info,
+ struct ptp_clock_request *request, int on);
+
+/* Low level functions used by above interface. */
+int macb_ptp_time_get(struct macb *bp, struct timespec64 *ts);
+int macb_ptp_time_set(struct macb *bp, const struct timespec64 *ts);
+
+int macb_ptp_increment_get(struct macb *bp, struct incrementspec *incr_spec);
+int macb_ptp_increment_set(struct macb *bp, struct incrementspec *incr_spec);
+int macb_ptp_time_adjust(struct macb *bp, s32 delta);
+
+/* Timestamp reading functions */
+int macb_ptp_time_peer_frame_tx_get(struct macb *bp, struct timespec64 *ts);
+int macb_ptp_time_peer_frame_rx_get(struct macb *bp, struct timespec64 *ts);
+int macb_ptp_time_frame_tx_get(struct macb *bp, struct timespec64 *ts);
+int macb_ptp_time_frame_rx_get(struct macb *bp, struct timespec64 *ts);
+
+/* Event reporting functions */
+int macb_ptp_event(struct macb *bp, struct timespec64 *ts);
+
+/* Hardware configuratio functions */
+int macb_ptp_set_one_step_sync(struct macb *bp, u8 enable);
+int macb_ptp_set_tstamp_mode(struct macb *bp,
+ enum macb_bd_control tx_bd_control,
+ enum macb_bd_control rx_bd_control);
+
+#endif
+
static inline bool macb_is_gem(struct macb *bp)
{
return !!(bp->caps & MACB_CAPS_MACB_IS_GEM);
--
2.4.5
^ permalink raw reply related
* Re: [PATCH net-next] bridge: add igmpv3 and mldv2 query support
From: Nikolay Aleksandrov @ 2016-11-18 10:31 UTC (permalink / raw)
To: Hangbin Liu, netdev; +Cc: Hannes Frederic Sowa, linus.luessing, roopa
In-Reply-To: <c1c35821-cdba-4a5e-0e53-694d10fb5918@cumulusnetworks.com>
On 18/11/16 11:09, Nikolay Aleksandrov wrote:
> On 18/11/16 11:04, Nikolay Aleksandrov wrote:
>> (+CC Roopa)
>> Hi Hangbin,
>> This patch is not correct, you should not use the net device IGMP config in the bridge.
> * bridge net device, sorry not port
>
>> These packets may never make it to the host and they may not be reflected, even more the
>> host may have very different igmp config for the port net device than the bridge does.
> * again bridge net device, not port
>
>> Also your current implementation switches to V3 only if it is globally set, and that should
>> be controlled on a per-bridge basis, even per-vlan later.
> * it is per-bridge, you use the global net device IGMP config, but it should be in the bridge
> mcast control options, so we can do it per-vlan later and also be able to do the compat parts
> of the RFC and in general, the bridge is configured via its own options not the host net device
> because as I said these packets may never be received locally
Having the host netdev options affect the bridge-specific config is really undesirable and confusing.
>
>> One more thing, if someone does a V2 leave for a group, you can end up sending them V3
>> group-specific query.
>>
>> I have been working on an implementation for IGMPv3/MLDv2 querier for the bridge device, it re-uses
>> most of the current code and allows you to configure it per-bridge (and later per-vlan). The only
>> reason I've not yet sent it to upstream is that we (at Cumulus) are working out the compatibility
>> parts (e.g. RFC3376 sec 7, sec 8) of the RFC since it has some unclear cases.
Err, RFC3376 sec 7.3.1, 7.3.2, and RFC3810 sec 8.3.1, 8.3.2
I really should get coffee.. sorry for the multiple emails :-)
>> But I can rip the compatibility out and send it early for review if you'd like, we can add the
>> compat code later.
>>
>> Cheers,
>> Nik
>>
^ permalink raw reply
* Re: [RFC PATCH 2/2] net: macb: Add 64 bit addressing support for GEM
From: Harini Katakam @ 2016-11-18 10:32 UTC (permalink / raw)
To: Andrei Pistirica
Cc: Rafal Ozieblo, Nicolas Ferre, harini.katakam@xilinx.com,
netdev@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <27516aeb-b8f9-dc38-4d01-d2a5c5cf44dd@microchip.com>
tHi Andrei,
>> Yes, Andre's version of Cadence does not ability to report have RX
>> timestamp.
>> The version I worked with did. This is the old series I sent:
>> https://lkml.org/lkml/2015/9/11/92
>> But right now, i'm working on building on top of Andre's changes.
>
>
> I'm addressing maintainer's feedback on both patches:
> https://patchwork.kernel.org/patch/9310989/
> https://patchwork.kernel.org/patch/9310991/
>
> I've done all suggested updates, except the numerous 64bit divisions in the
> frequency adjustment callback. I've implemented a different algorithm which
> uses 2 64bit division, but I couldn't find a way to use only 1.
>
> Also, I have a version with timecounter/cyclecounter which shows a much
> better accuracy (less than 100ns level). In my opinion this could be a
> better implementation. What is you opinion about this? Did you try it?
>
I did not try timecounter on Cadence IP versions later than r1p06.
Because with sub ns precision in HW timestamp, that works better
than SW cyclecounter.
On older Zynq version, yes timecounter is used and is better.
Regards,
Harini
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox