From patchwork Wed Mar 21 18:58:14 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Cochran X-Patchwork-Id: 889024 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="JXkumB+y"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 405zbX4DMwz9s0t for ; Thu, 22 Mar 2018 05:58:32 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753283AbeCUS62 (ORCPT ); Wed, 21 Mar 2018 14:58:28 -0400 Received: from mail-pf0-f194.google.com ([209.85.192.194]:38934 "EHLO mail-pf0-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753266AbeCUS6W (ORCPT ); Wed, 21 Mar 2018 14:58:22 -0400 Received: by mail-pf0-f194.google.com with SMTP id u5so2348571pfh.6; Wed, 21 Mar 2018 11:58:22 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=zuz3AsI+pjFL/iF0NtGVGKho0pm7Bk1465LpvhKtfeU=; b=JXkumB+yLhjKlD1ykV7YGcEoDoYyEa+N+Ef/Bs8W0WUne7fGy8zUxpn241j6xp450N y73hBd1tcwWnqAZkMe3AtYhCMtA4FflIBYQ5huNJYe8p1oYDT8SuSfpDBIjzNCbhdQo+ FoosLNFIX+fjqJm4SuasZ9Y5hfsK2UR+ARzVR4MLDk2QKBsFFqez6pID5LY/iHdXERHM aq2Q/3cIBC0zn7PSW38+fm/oN9Lli3XhiYXGPjLd13CJCMk8ly77O3+Z2fgWqaCnC2NL SxFIsLCld/2ePEFr9Jq2gZzqEtJVRjOgiYNK1qX4uPwFMStA/2ZVhOsbEwe1jALbRDp+ KWUg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=zuz3AsI+pjFL/iF0NtGVGKho0pm7Bk1465LpvhKtfeU=; b=iTN/6+AfGPmBK264jX8j5+g41RyTu3xhYbZvWspsw7lO3ZPqAm2MS/GMryEeNqGEbV 9CRUvdWEwbjEWvFfq2plJ0+5q3VJTcPWWXS73CxCwhxv3h6xcVnTtUMIBp7BpUiXmx69 6uUe8GIitK65rbedsoPesOuK+PKBrfT+hs0qzQo3ma2XfESu6dmj1Um3zXOXdjwSZdsH 0vhYmTRRa54T7YMmRjQOqgkKkn6yCzYOWQYOVUYmBcdv+G2wm9AOJTSaeIL3saLLD7JU QUbfQFVTLuj1qMQKpK8fipq1fqDIdHBeR5dnmy6UdoR3s4JQQ8Mj68embDubGkAH9EOs Drzw== X-Gm-Message-State: AElRT7FdKOOXltgyhDXrmEaWxV/5RJ40zQOSdMGdMxjVXht7+z7kUcu2 VmQ5u/kHyYY08QAaSYq8X2wXt+Q1 X-Google-Smtp-Source: AG47ELtE7chQh8PoFECv+fTyxA4j81Odg+0xahoIZEv+yUbzwMWWe6qNt4URTy3uItGk128yE1QXCQ== X-Received: by 10.99.190.75 with SMTP id g11mr13991415pgo.127.1521658701920; Wed, 21 Mar 2018 11:58:21 -0700 (PDT) Received: from localhost.localdomain (c-24-4-232-46.hsd1.ca.comcast.net. [24.4.232.46]) by smtp.gmail.com with ESMTPSA id z13sm10532610pfk.129.2018.03.21.11.58.20 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 21 Mar 2018 11:58:21 -0700 (PDT) From: Richard Cochran To: netdev@vger.kernel.org Cc: devicetree@vger.kernel.org, Andrew Lunn , David Miller , Florian Fainelli , Mark Rutland , Miroslav Lichvar , Rob Herring , Willem de Bruijn Subject: [PATCH net-next RFC V1 1/5] net: Introduce peer to peer one step PTP time stamping. Date: Wed, 21 Mar 2018 11:58:14 -0700 Message-Id: <60ae964d6a0da497bcac1d3fdb5b3fe01f5d70f1.1521656774.git.richardcochran@gmail.com> X-Mailer: git-send-email 2.11.0 In-Reply-To: References: Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org The 1588 standard defines one step operation for both Sync and PDelay_Resp messages. Up until now, hardware with P2P one step has been rare, and kernel support was lacking. This patch adds support of the mode in anticipation of new hardware developments. Signed-off-by: Richard Cochran --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c | 1 + include/uapi/linux/net_tstamp.h | 8 ++++++++ net/core/dev_ioctl.c | 1 + 3 files changed, 10 insertions(+) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index 74fc9af4aadb..c6295e5c16af 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -15379,6 +15379,7 @@ int bnx2x_configure_ptp_filters(struct bnx2x *bp) NIG_REG_P0_TLLH_PTP_RULE_MASK, 0x3EEE); break; case HWTSTAMP_TX_ONESTEP_SYNC: + case HWTSTAMP_TX_ONESTEP_P2P: BNX2X_ERR("One-step timestamping is not supported\n"); return -ERANGE; } diff --git a/include/uapi/linux/net_tstamp.h b/include/uapi/linux/net_tstamp.h index 4fe104b2411f..f89b5a836c2a 100644 --- a/include/uapi/linux/net_tstamp.h +++ b/include/uapi/linux/net_tstamp.h @@ -90,6 +90,14 @@ enum hwtstamp_tx_types { * queue. */ HWTSTAMP_TX_ONESTEP_SYNC, + + /* + * Same as HWTSTAMP_TX_ONESTEP_SYNC, but also enables time + * stamp insertion directly into PDelay_Resp packets. In this + * case, neither transmitted Sync nor PDelay_Resp packets will + * receive a time stamp via the socket error queue. + */ + HWTSTAMP_TX_ONESTEP_P2P, }; /* possible values for hwtstamp_config->rx_filter */ diff --git a/net/core/dev_ioctl.c b/net/core/dev_ioctl.c index 0ab1af04296c..cdda085e4b47 100644 --- a/net/core/dev_ioctl.c +++ b/net/core/dev_ioctl.c @@ -187,6 +187,7 @@ static int net_hwtstamp_validate(struct ifreq *ifr) case HWTSTAMP_TX_OFF: case HWTSTAMP_TX_ON: case HWTSTAMP_TX_ONESTEP_SYNC: + case HWTSTAMP_TX_ONESTEP_P2P: tx_type_valid = 1; break; } From patchwork Wed Mar 21 18:58:15 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Cochran X-Patchwork-Id: 889023 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="eCFX9diW"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 405zbT69x7z9s0t for ; Thu, 22 Mar 2018 05:58:29 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753274AbeCUS60 (ORCPT ); Wed, 21 Mar 2018 14:58:26 -0400 Received: from mail-pl0-f66.google.com ([209.85.160.66]:45753 "EHLO mail-pl0-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753267AbeCUS6X (ORCPT ); Wed, 21 Mar 2018 14:58:23 -0400 Received: by mail-pl0-f66.google.com with SMTP id n15-v6so3690466plp.12; Wed, 21 Mar 2018 11:58:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=s2ugLdgiocOkzVBm/auaTd7Cqy7W8S21nEUg4omtNMw=; b=eCFX9diWOJ5iZk1CM89VK1NvykbvdyVgZWhcFd4rcHUyVfi72fY8Ogr6U43d7kSJrd 74ZWoLN+Jx0HO8j4LCf6nc/lgO40ajecakdFMMGtVoN72U0Z9e0RVghJc5DsX2iHfo4z eAJQhP2qz/jiEiMYEXd2S+h9ms5sxqSAaTtwaGy/ol0B5aTHhAyQeKq8YVq9zWVrJs73 h4wlZ2vMe/x5xjR9UKqoKt9TjrbMHz+DQAPJ/iffrx50r9I2jcwVWgk0BMOfKDeHW98f TFOOZzvQEd8iRQszk066de9jlDzxIwm8pPYyBFARgpASAzWtlXdHu7/7MRa/xhXtap8o svGg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=s2ugLdgiocOkzVBm/auaTd7Cqy7W8S21nEUg4omtNMw=; b=V/rT90mNHPn3Hi6nB3Ygug4F8nn+sBt4Ylk/Cvt5yuq7qV5+hjYPOMYYWGtqUuCNI1 8lVN5ztDYu569pRkJo5AoJVYf2sNCkekr1vEeYRvuGiDiczNcyJys4zKx527kZpL5j+m pT2D7JvnVYdnASGbQOjyeCOvBRXjsRwCDHd+4RPsJZnItFDIVgxS9aWvFgDpGDgGGsUP Pek2XuKM0erE50CKJWE9rW1nu//240RM/aKkPAVdtY6g7bXuGdPBborZfo7yraFqbYBU CD0h+jZfFcR7sm0OU/512sH6D+YTUwnxC/GiVxJe4qtZX7Yr3tJyeuMxS9EDyFbKu4ih uz3g== X-Gm-Message-State: AElRT7FvV8ComXw7AhuzGRRF3cOvZGR6I0v8LyozIYypaJZgyGdygJex yhzZhD7XMHDSzDOJjQfMvT8IhOBJ X-Google-Smtp-Source: AG47ELskgpHCPtXNTm2VJChuj5FXZMN3E6rvsB8oONIW6BL7TZJ12Rnrfyuy+Qre/81SHzMjF5GUXQ== X-Received: by 2002:a17:902:d889:: with SMTP id b9-v6mr14009964plz.8.1521658703006; Wed, 21 Mar 2018 11:58:23 -0700 (PDT) Received: from localhost.localdomain (c-24-4-232-46.hsd1.ca.comcast.net. [24.4.232.46]) by smtp.gmail.com with ESMTPSA id z13sm10532610pfk.129.2018.03.21.11.58.21 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 21 Mar 2018 11:58:22 -0700 (PDT) From: Richard Cochran To: netdev@vger.kernel.org Cc: devicetree@vger.kernel.org, Andrew Lunn , David Miller , Florian Fainelli , Mark Rutland , Miroslav Lichvar , Rob Herring , Willem de Bruijn Subject: [PATCH net-next RFC V1 2/5] net: phy: Move time stamping interface into the generic mdio layer. Date: Wed, 21 Mar 2018 11:58:15 -0700 Message-Id: X-Mailer: git-send-email 2.11.0 In-Reply-To: References: Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org There are different ways of obtaining hardware time stamps on network packets. The ingress and egress times can be measured in the MAC, in the PHY, or by a device listening on the MII bus. Up until now, the kernel has support for MAC and PHY time stamping, but not for other MII bus devices. This patch moves the PHY time stamping interface into the generic mdio device in order to support MII time stamping hardware. Signed-off-by: Richard Cochran --- drivers/net/phy/dp83640.c | 29 ++++++++++++++++++++--------- drivers/net/phy/phy.c | 4 ++-- include/linux/mdio.h | 23 +++++++++++++++++++++++ include/linux/phy.h | 23 ----------------------- net/core/ethtool.c | 4 ++-- net/core/timestamping.c | 8 ++++---- 6 files changed, 51 insertions(+), 40 deletions(-) diff --git a/drivers/net/phy/dp83640.c b/drivers/net/phy/dp83640.c index 654f42d00092..79aeb5eb471a 100644 --- a/drivers/net/phy/dp83640.c +++ b/drivers/net/phy/dp83640.c @@ -215,6 +215,10 @@ static LIST_HEAD(phyter_clocks); static DEFINE_MUTEX(phyter_clocks_lock); static void rx_timestamp_work(struct work_struct *work); +static int dp83640_ts_info(struct mdio_device *m, struct ethtool_ts_info *i); +static int dp83640_hwtstamp(struct mdio_device *m, struct ifreq *i); +static bool dp83640_rxtstamp(struct mdio_device *m, struct sk_buff *s, int t); +static void dp83640_txtstamp(struct mdio_device *m, struct sk_buff *s, int t); /* extended register access functions */ @@ -1162,6 +1166,12 @@ static int dp83640_probe(struct phy_device *phydev) list_add_tail(&dp83640->list, &clock->phylist); dp83640_clock_put(clock); + + phydev->mdio.ts_info = dp83640_ts_info; + phydev->mdio.hwtstamp = dp83640_hwtstamp; + phydev->mdio.rxtstamp = dp83640_rxtstamp; + phydev->mdio.txtstamp = dp83640_txtstamp; + return 0; no_register: @@ -1288,8 +1298,9 @@ static int dp83640_config_intr(struct phy_device *phydev) } } -static int dp83640_hwtstamp(struct phy_device *phydev, struct ifreq *ifr) +static int dp83640_hwtstamp(struct mdio_device *mdev, struct ifreq *ifr) { + struct phy_device *phydev = container_of(mdev, struct phy_device, mdio); struct dp83640_private *dp83640 = phydev->priv; struct hwtstamp_config cfg; u16 txcfg0, rxcfg0; @@ -1397,9 +1408,10 @@ static void rx_timestamp_work(struct work_struct *work) schedule_delayed_work(&dp83640->ts_work, SKB_TIMESTAMP_TIMEOUT); } -static bool dp83640_rxtstamp(struct phy_device *phydev, +static bool dp83640_rxtstamp(struct mdio_device *mdev, struct sk_buff *skb, int type) { + struct phy_device *phydev = container_of(mdev, struct phy_device, mdio); struct dp83640_private *dp83640 = phydev->priv; struct dp83640_skb_info *skb_info = (struct dp83640_skb_info *)skb->cb; struct list_head *this, *next; @@ -1446,9 +1458,10 @@ static bool dp83640_rxtstamp(struct phy_device *phydev, return true; } -static void dp83640_txtstamp(struct phy_device *phydev, +static void dp83640_txtstamp(struct mdio_device *mdev, struct sk_buff *skb, int type) { + struct phy_device *phydev = container_of(mdev, struct phy_device, mdio); struct dp83640_private *dp83640 = phydev->priv; switch (dp83640->hwts_tx_en) { @@ -1471,9 +1484,11 @@ static void dp83640_txtstamp(struct phy_device *phydev, } } -static int dp83640_ts_info(struct phy_device *dev, struct ethtool_ts_info *info) +static int dp83640_ts_info(struct mdio_device *mdev, + struct ethtool_ts_info *info) { - struct dp83640_private *dp83640 = dev->priv; + struct phy_device *phydev = container_of(mdev, struct phy_device, mdio); + struct dp83640_private *dp83640 = phydev->priv; info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE | @@ -1504,10 +1519,6 @@ static struct phy_driver dp83640_driver = { .config_init = dp83640_config_init, .ack_interrupt = dp83640_ack_interrupt, .config_intr = dp83640_config_intr, - .ts_info = dp83640_ts_info, - .hwtstamp = dp83640_hwtstamp, - .rxtstamp = dp83640_rxtstamp, - .txtstamp = dp83640_txtstamp, }; static int __init dp83640_init(void) diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index c2d9027be863..466bf88053ce 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -457,8 +457,8 @@ int phy_mii_ioctl(struct phy_device *phydev, struct ifreq *ifr, int cmd) return 0; case SIOCSHWTSTAMP: - if (phydev->drv && phydev->drv->hwtstamp) - return phydev->drv->hwtstamp(phydev, ifr); + if (phydev->mdio.hwtstamp) + return phydev->mdio.hwtstamp(&phydev->mdio, ifr); /* fall through */ default: diff --git a/include/linux/mdio.h b/include/linux/mdio.h index 2cfffe586885..70a82c973aed 100644 --- a/include/linux/mdio.h +++ b/include/linux/mdio.h @@ -37,6 +37,29 @@ struct mdio_device { void (*device_free)(struct mdio_device *mdiodev); void (*device_remove)(struct mdio_device *mdiodev); + /* Handles ethtool queries for hardware time stamping. */ + int (*ts_info)(struct mdio_device *dev, struct ethtool_ts_info *ti); + + /* Handles SIOCSHWTSTAMP ioctl for hardware time stamping. */ + int (*hwtstamp)(struct mdio_device *dev, struct ifreq *ifr); + + /* + * Requests a Rx timestamp for 'skb'. If the skb is accepted, + * the mdio device promises to deliver it using netif_rx() as + * soon as a timestamp becomes available. One of the + * PTP_CLASS_ values is passed in 'type'. The function must + * return true if the skb is accepted for delivery. + */ + bool (*rxtstamp)(struct mdio_device *dev, struct sk_buff *skb, int type); + + /* + * Requests a Tx timestamp for 'skb'. The mdio device promises + * to deliver it using skb_complete_tx_timestamp() as soon as a + * timestamp becomes available. One of the PTP_CLASS_ values + * is passed in 'type'. + */ + void (*txtstamp)(struct mdio_device *dev, struct sk_buff *skb, int type); + /* Bus address of the MDIO device (0-31) */ int addr; int flags; diff --git a/include/linux/phy.h b/include/linux/phy.h index 5a9b1753fdc5..77d3f703b8ce 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -570,29 +570,6 @@ struct phy_driver { */ int (*match_phy_device)(struct phy_device *phydev); - /* Handles ethtool queries for hardware time stamping. */ - int (*ts_info)(struct phy_device *phydev, struct ethtool_ts_info *ti); - - /* Handles SIOCSHWTSTAMP ioctl for hardware time stamping. */ - int (*hwtstamp)(struct phy_device *phydev, struct ifreq *ifr); - - /* - * Requests a Rx timestamp for 'skb'. If the skb is accepted, - * the phy driver promises to deliver it using netif_rx() as - * soon as a timestamp becomes available. One of the - * PTP_CLASS_ values is passed in 'type'. The function must - * return true if the skb is accepted for delivery. - */ - bool (*rxtstamp)(struct phy_device *dev, struct sk_buff *skb, int type); - - /* - * Requests a Tx timestamp for 'skb'. The phy driver promises - * to deliver it using skb_complete_tx_timestamp() as soon as a - * timestamp becomes available. One of the PTP_CLASS_ values - * is passed in 'type'. - */ - void (*txtstamp)(struct phy_device *dev, struct sk_buff *skb, int type); - /* Some devices (e.g. qnap TS-119P II) require PHY register changes to * enable Wake on LAN, so set_wol is provided to be called in the * ethernet driver's set_wol function. */ diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 157cd9efa4be..b4b81eaa15a9 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -2218,8 +2218,8 @@ static int ethtool_get_ts_info(struct net_device *dev, void __user *useraddr) memset(&info, 0, sizeof(info)); info.cmd = ETHTOOL_GET_TS_INFO; - if (phydev && phydev->drv && phydev->drv->ts_info) { - err = phydev->drv->ts_info(phydev, &info); + if (phydev && phydev->mdio.ts_info) { + err = phydev->mdio.ts_info(&phydev->mdio, &info); } else if (ops->get_ts_info) { err = ops->get_ts_info(dev, &info); } else { diff --git a/net/core/timestamping.c b/net/core/timestamping.c index 42689d5c468c..b8857028e652 100644 --- a/net/core/timestamping.c +++ b/net/core/timestamping.c @@ -46,11 +46,11 @@ void skb_clone_tx_timestamp(struct sk_buff *skb) return; phydev = skb->dev->phydev; - if (likely(phydev->drv->txtstamp)) { + if (likely(phydev->mdio.txtstamp)) { clone = skb_clone_sk(skb); if (!clone) return; - phydev->drv->txtstamp(phydev, clone, type); + phydev->mdio.txtstamp(&phydev->mdio, clone, type); } } EXPORT_SYMBOL_GPL(skb_clone_tx_timestamp); @@ -76,8 +76,8 @@ bool skb_defer_rx_timestamp(struct sk_buff *skb) return false; phydev = skb->dev->phydev; - if (likely(phydev->drv->rxtstamp)) - return phydev->drv->rxtstamp(phydev, skb, type); + if (likely(phydev->mdio.rxtstamp)) + return phydev->mdio.rxtstamp(&phydev->mdio, skb, type); return false; } From patchwork Wed Mar 21 18:58:16 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Cochran X-Patchwork-Id: 889025 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="i4nx0Ydw"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 405zbb2S9Pz9s0t for ; Thu, 22 Mar 2018 05:58:35 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753290AbeCUS6c (ORCPT ); Wed, 21 Mar 2018 14:58:32 -0400 Received: from mail-pf0-f195.google.com ([209.85.192.195]:41570 "EHLO mail-pf0-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752837AbeCUS6Z (ORCPT ); Wed, 21 Mar 2018 14:58:25 -0400 Received: by mail-pf0-f195.google.com with SMTP id f80so2344496pfa.8; Wed, 21 Mar 2018 11:58:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=dmXZkCwlcaGHMXeUmlB7JZmwiUppiGy+J4kJyKCzjBM=; b=i4nx0YdwKxMRHBA+EML/cEUdzlFt7Z9c0hWlHF49gtR9KcAE6ByDzSPSltiBk2ZJ3R qFHR3ursjwysT4QHGt/qVm+X/glsBriUyHvwZJSQQSx/G2UrzwfdmnoU6RKizL+c7xvW Mh2SEE+4yIg1PNwtlgkszYQNcA/9nTFYwz11wxa7E3xKwMmYtPzYoXCBPwPBzhd8kgWg /y8bDrg5Bm/bBBKi2hdxltBmPsuce82NgF2qfykPy1jrmcTlYy2A5sripJdfJ4Gok4zY 8ahYn95rZHHaLFLVX8OVwRUoBMJ6cWjhmVAkce5PQ4+s6WLQa5N88mNB3Tjvs6d+O6p9 LFJg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=dmXZkCwlcaGHMXeUmlB7JZmwiUppiGy+J4kJyKCzjBM=; b=YsSBESemHqDXqMsXzYwrkfFrq7TVGzOjB3zTsqE+9Km/pOgQIqGGQ2NxELD7nR/Y3o w9K7XSq9wXyJ0bJJUZnNjVpyKV9PcSUISITLmS8an2MZlYWdBxHxdI7MoNKIDf79ZgEB Uz9uWk16CfNnWWxfaBUvIlPhVK7QXEAP1/ihTQDqOK6DdmrwQ6tDfYbaasIa6vtYQeaR jIPy+6P4VLCSAAkiZGGRAoLfbFM0R9/h1sbSESKL7NkEEteXwyxxtjpe0A8D3KPbWz7G tqHfxtaJ8Ubtnpi+TKWRyRfHBom07yaF9RXaADqmc2PmyhNAOa9RxsSg2HN2dT7DOgQj Qc9Q== X-Gm-Message-State: AElRT7GaeHQfIHPW9QT6lk55wIHi2tiJrJqRmjoCJP3Mr1uYHx5jD597 QAtEKqw5D3b8BGMl72SkGu+mRyqY X-Google-Smtp-Source: AG47ELuAUL2W4Cf0zeF8XsuZaJ0YH4Isw9xq9rSKul+5cxCn2CNUZSEdaOODyQI9ZL3TfpUA4rs+Og== X-Received: by 10.101.93.71 with SMTP id e7mr15407586pgt.171.1521658704047; Wed, 21 Mar 2018 11:58:24 -0700 (PDT) Received: from localhost.localdomain (c-24-4-232-46.hsd1.ca.comcast.net. [24.4.232.46]) by smtp.gmail.com with ESMTPSA id z13sm10532610pfk.129.2018.03.21.11.58.23 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 21 Mar 2018 11:58:23 -0700 (PDT) From: Richard Cochran To: netdev@vger.kernel.org Cc: devicetree@vger.kernel.org, Andrew Lunn , David Miller , Florian Fainelli , Mark Rutland , Miroslav Lichvar , Rob Herring , Willem de Bruijn Subject: [PATCH net-next RFC V1 3/5] net: Introduce field for the MII time stamper. Date: Wed, 21 Mar 2018 11:58:16 -0700 Message-Id: <338f19a006839f1d00e3cfd3521bdd5fd0afc5fe.1521656774.git.richardcochran@gmail.com> X-Mailer: git-send-email 2.11.0 In-Reply-To: References: Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org This patch adds a new field to the network device structure to reference a time stamping device on the MII bus. By decoupling the time stamping function from the PHY device, we pave the way to allowing a non-PHY device to take this role. Signed-off-by: Richard Cochran --- drivers/net/phy/mdio_bus.c | 51 +++++++++++++++++++++++++++++++++++++++++++++- include/linux/netdevice.h | 1 + 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index 24b5511222c8..fdac8c8ac272 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -717,6 +717,47 @@ static int mdio_uevent(struct device *dev, struct kobj_uevent_env *env) return 0; } +static bool mdiodev_supports_timestamping(struct mdio_device *mdiodev) +{ + if (mdiodev->ts_info && mdiodev->hwtstamp && + mdiodev->rxtstamp && mdiodev->txtstamp) + return true; + else + return false; +} + +static int mdiobus_netdev_notification(struct notifier_block *nb, + unsigned long msg, void *ptr) +{ + struct net_device *netdev = netdev_notifier_info_to_dev(ptr); + struct phy_device *phydev = netdev->phydev; + struct mdio_device *mdev; + struct mii_bus *bus; + int i; + + if (netdev->mdiots || msg != NETDEV_UP || !phydev) + return NOTIFY_DONE; + + /* + * Examine the MII bus associated with the PHY that is + * attached to the MAC. If there is a time stamping device + * on the bus, then connect it to the network device. + */ + bus = phydev->mdio.bus; + + for (i = 0; i < PHY_MAX_ADDR; i++) { + mdev = bus->mdio_map[i]; + if (!mdev) + continue; + if (mdiodev_supports_timestamping(mdev)) { + netdev->mdiots = mdev; + return NOTIFY_OK; + } + } + + return NOTIFY_DONE; +} + #ifdef CONFIG_PM static int mdio_bus_suspend(struct device *dev) { @@ -772,6 +813,10 @@ struct bus_type mdio_bus_type = { }; EXPORT_SYMBOL(mdio_bus_type); +static struct notifier_block mdiobus_netdev_notifier __read_mostly = { + .notifier_call = mdiobus_netdev_notification, +}; + int __init mdio_bus_init(void) { int ret; @@ -782,14 +827,18 @@ int __init mdio_bus_init(void) if (ret) class_unregister(&mdio_bus_class); } + if (ret) + return ret; + + return register_netdevice_notifier(&mdiobus_netdev_notifier); - return ret; } EXPORT_SYMBOL_GPL(mdio_bus_init); #if IS_ENABLED(CONFIG_PHYLIB) void mdio_bus_exit(void) { + unregister_netdevice_notifier(&mdiobus_netdev_notifier); class_unregister(&mdio_bus_class); bus_unregister(&mdio_bus_type); } diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 5fbb9f1da7fd..223d691aa0b0 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1943,6 +1943,7 @@ struct net_device { struct netprio_map __rcu *priomap; #endif struct phy_device *phydev; + struct mdio_device *mdiots; struct lock_class_key *qdisc_tx_busylock; struct lock_class_key *qdisc_running_key; bool proto_down; From patchwork Wed Mar 21 18:58:17 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Cochran X-Patchwork-Id: 889026 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="V2CBA1HQ"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 405zbg3zsZz9s0t for ; Thu, 22 Mar 2018 05:58:39 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753291AbeCUS6f (ORCPT ); Wed, 21 Mar 2018 14:58:35 -0400 Received: from mail-pg0-f65.google.com ([74.125.83.65]:40102 "EHLO mail-pg0-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753044AbeCUS60 (ORCPT ); Wed, 21 Mar 2018 14:58:26 -0400 Received: by mail-pg0-f65.google.com with SMTP id g8so2294407pgv.7; Wed, 21 Mar 2018 11:58:26 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=t2+mmSGVBeZIaL0R/556vk8Xv+Lp4TNdFDJtsLSfkr4=; b=V2CBA1HQfR3pAsEfzcbZnMs4oD0KQTeVxkDfROAYtec/N+Suz6X0U8u4t3Yn1gsrDu pGlJV4SDzMeGur2djmKLdZeU7m3mB2H6+l97M/wEotNdg8SPX1U870lDXzbNziIQ2h7R aER33rDAIBEVh7e9nW4lbdbk7kzRalSQ7vT1RpCTDkP70yDQwmfeYFWLu48OWMPj1nJU BgQovgjfCMcdFfpfWEwltP1kNq2+bwkbEig6aF8RWIzcAT0Fmx1l2z0xeeYd93lNw/V0 tornpFKbIlCHH8CG7pD8tJKSzjpmKgUGvdSfxwuVByhCNuSuNkJcgTIT6VPmw5jczO+v nSXQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=t2+mmSGVBeZIaL0R/556vk8Xv+Lp4TNdFDJtsLSfkr4=; b=VamqbU03fDGhQTysQbdXfsPgfXUd+Jzzgzh63irL17kAu/B3byL5l6fTmLvQ/kt790 UhZAMl0IrFD/FO5TuTKcslCNcQqQJvJRLXkDKdt6Qth+CnkT4gKmr9o6WBjnE4p5fwbi axrKRUVGvC9c1h0BfuqnbBfwB4YjoA2ZLUSYfbc+wVlG/HQX4k00UBKLurbhyTUqUi/y 9HlzWhoFQ9HCU1aTKPvHDhuBXE4ryLNH6ttfqbjDE0czi7tInvD8qZC3X8xmcpq2hVE5 UjxoYcAKNBcHtGRT7iEDmZT0NvX+7U7Z2+2D4wp96e7knX2YK/HwZtpC5o7nRO1tHmus 9qpA== X-Gm-Message-State: AElRT7GuCPAN87AT6jiR80dO3d91oFBz2fwjT2MACAVtUr6flQrryoII oCF8gk4ew7zGpb/d3Hav0P4lIQo6 X-Google-Smtp-Source: AG47ELumWkNLfN7canwxW0nBrP1eUSYCDaRkdJYYl+oY9KFfxXDu7B70kn+uyCdI6jEiaPnJCrl+wA== X-Received: by 10.101.76.207 with SMTP id n15mr16091971pgt.313.1521658705676; Wed, 21 Mar 2018 11:58:25 -0700 (PDT) Received: from localhost.localdomain (c-24-4-232-46.hsd1.ca.comcast.net. [24.4.232.46]) by smtp.gmail.com with ESMTPSA id z13sm10532610pfk.129.2018.03.21.11.58.24 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 21 Mar 2018 11:58:25 -0700 (PDT) From: Richard Cochran To: netdev@vger.kernel.org Cc: devicetree@vger.kernel.org, Andrew Lunn , David Miller , Florian Fainelli , Mark Rutland , Miroslav Lichvar , Rob Herring , Willem de Bruijn Subject: [PATCH net-next RFC V1 4/5] net: Use the generic MII time stamper when available. Date: Wed, 21 Mar 2018 11:58:17 -0700 Message-Id: <461dff568dba6ea8c98582c79d16c3155e662cf5.1521656774.git.richardcochran@gmail.com> X-Mailer: git-send-email 2.11.0 In-Reply-To: References: Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Now that the infrastructure is in place, convert the PHY time stamping logic to use the generic MII device. This change has the added benefit of simplifying the code somewhat. Signed-off-by: Richard Cochran --- drivers/net/phy/phy.c | 6 ++++-- net/Kconfig | 8 ++++---- net/core/ethtool.c | 5 ++--- net/core/timestamping.c | 36 ++++++++++-------------------------- 4 files changed, 20 insertions(+), 35 deletions(-) diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 466bf88053ce..df80c6b14478 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -397,6 +397,7 @@ int phy_mii_ioctl(struct phy_device *phydev, struct ifreq *ifr, int cmd) struct mii_ioctl_data *mii_data = if_mii(ifr); u16 val = mii_data->val_in; bool change_autoneg = false; + struct net_device *netdev; switch (cmd) { case SIOCGMIIPHY: @@ -457,8 +458,9 @@ int phy_mii_ioctl(struct phy_device *phydev, struct ifreq *ifr, int cmd) return 0; case SIOCSHWTSTAMP: - if (phydev->mdio.hwtstamp) - return phydev->mdio.hwtstamp(&phydev->mdio, ifr); + netdev = phydev->attached_dev; + if (netdev->mdiots->hwtstamp) + return netdev->mdiots->hwtstamp(netdev->mdiots, ifr); /* fall through */ default: diff --git a/net/Kconfig b/net/Kconfig index 0428f12c25c2..e38403cd010c 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -102,12 +102,12 @@ config NET_PTP_CLASSIFY def_bool n config NETWORK_PHY_TIMESTAMPING - bool "Timestamping in PHY devices" + bool "Timestamping in PHY and MII bus devices" select NET_PTP_CLASSIFY help - This allows timestamping of network packets by PHYs with - hardware timestamping capabilities. This option adds some - overhead in the transmit and receive paths. + This allows timestamping of network packets by PHYs or other + MII bus devices with hardware timestamping capabilities. This + option adds some overhead in the transmit and receive paths. If you are unsure how to answer this question, answer N. diff --git a/net/core/ethtool.c b/net/core/ethtool.c index b4b81eaa15a9..507e56abecb7 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -2213,13 +2213,12 @@ static int ethtool_get_ts_info(struct net_device *dev, void __user *useraddr) int err = 0; struct ethtool_ts_info info; const struct ethtool_ops *ops = dev->ethtool_ops; - struct phy_device *phydev = dev->phydev; memset(&info, 0, sizeof(info)); info.cmd = ETHTOOL_GET_TS_INFO; - if (phydev && phydev->mdio.ts_info) { - err = phydev->mdio.ts_info(&phydev->mdio, &info); + if (dev->mdiots && dev->mdiots->ts_info) { + err = dev->mdiots->ts_info(dev->mdiots, &info); } else if (ops->get_ts_info) { err = ops->get_ts_info(dev, &info); } else { diff --git a/net/core/timestamping.c b/net/core/timestamping.c index b8857028e652..ecb0ecb03740 100644 --- a/net/core/timestamping.c +++ b/net/core/timestamping.c @@ -23,44 +23,32 @@ #include #include -static unsigned int classify(const struct sk_buff *skb) -{ - if (likely(skb->dev && skb->dev->phydev && - skb->dev->phydev->drv)) - return ptp_classify_raw(skb); - else - return PTP_CLASS_NONE; -} - void skb_clone_tx_timestamp(struct sk_buff *skb) { - struct phy_device *phydev; struct sk_buff *clone; unsigned int type; - if (!skb->sk) + if (!skb->sk || !skb->dev || !skb->dev->mdiots) return; - type = classify(skb); + type = ptp_classify_raw(skb); + if (type == PTP_CLASS_NONE) return; - phydev = skb->dev->phydev; - if (likely(phydev->mdio.txtstamp)) { - clone = skb_clone_sk(skb); - if (!clone) - return; - phydev->mdio.txtstamp(&phydev->mdio, clone, type); - } + clone = skb_clone_sk(skb); + if (!clone) + return; + + skb->dev->mdiots->txtstamp(skb->dev->mdiots, clone, type); } EXPORT_SYMBOL_GPL(skb_clone_tx_timestamp); bool skb_defer_rx_timestamp(struct sk_buff *skb) { - struct phy_device *phydev; unsigned int type; - if (!skb->dev || !skb->dev->phydev || !skb->dev->phydev->drv) + if (!skb->dev || !skb->dev->mdiots) return false; if (skb_headroom(skb) < ETH_HLEN) @@ -75,10 +63,6 @@ bool skb_defer_rx_timestamp(struct sk_buff *skb) if (type == PTP_CLASS_NONE) return false; - phydev = skb->dev->phydev; - if (likely(phydev->mdio.rxtstamp)) - return phydev->mdio.rxtstamp(&phydev->mdio, skb, type); - - return false; + return skb->dev->mdiots->rxtstamp(skb->dev->mdiots, skb, type); } EXPORT_SYMBOL_GPL(skb_defer_rx_timestamp); From patchwork Wed Mar 21 18:58:18 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Cochran X-Patchwork-Id: 889028 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="LNj8HEDd"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 405zbs6PGHz9s0t for ; Thu, 22 Mar 2018 05:58:49 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753047AbeCUS6q (ORCPT ); Wed, 21 Mar 2018 14:58:46 -0400 Received: from mail-pg0-f68.google.com ([74.125.83.68]:43358 "EHLO mail-pg0-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753278AbeCUS62 (ORCPT ); Wed, 21 Mar 2018 14:58:28 -0400 Received: by mail-pg0-f68.google.com with SMTP id i9so2288334pgq.10; Wed, 21 Mar 2018 11:58:27 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=PJ5MQm5Jw13xa4rGQ7NFjETcCgfgqCK3GxRaKACDX/M=; b=LNj8HEDd5KaLuFkNdHtssvucaOtdgjIn4AUg0A491BAHUyh5NwyBqn6KXt8TVeQ1ha k4xJg+c3bqLCf+EX68OUvdSA4vuN5XjHzmh81ZnN0Y4eeG/Ii9dzvKvWIjFCdKymN++m hAMnzzB1wi+DEG/wcgJ9ab63ivhXUVjEFT7lrwJrF4PJ3IGPsop2/wHHv8LtOqRQsKbf EGmf9yg9DRRNLKiRZO1NiGDaAnxiwVIdShPl6szBtPzD7CT6o3Rr6LZawA68h6QxLEGm BW6r0/2hhRnUtO/maJAw+GELtYuBHwJi8RZpTpsXO9ECf/bYHeoIp8B7Jvz66EsfmRWL nKUQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=PJ5MQm5Jw13xa4rGQ7NFjETcCgfgqCK3GxRaKACDX/M=; b=ES5QD89baGQvgodP/KQZjk/eS25vc7l2qNgShKjUT/YsI3h7NBt31nNP6/aiYnlSRe 3chYWmZ80YPbG6wVknhpDodSpUn/qKmCLxtqR6k/dc2YUCSMOLN6nKAYSnr0WO1k6cSS Zu8HV0rOdvozrFXm5gjTM+KmJxFSVCCZkL8EuWQeGPVJ8gBozOY4eL+FZ0zJ7g24llgN 8nNy9AW7BWFDa7A064co57sb9pwYsDn0T60cgH2OwM9bH6HmUxVGCyJnAEUZtsSHD3Su zGghxBckxkZPsrlQ87aubDxvz8enhWhF0ejj5tLcWkHNzVvWpGVo0JSJZZA3El3XjCFI nEAw== X-Gm-Message-State: AElRT7G311YwvrRXoH6aUTH91hiYW/fF4rsrKO6c7sei7roT1VHpfedd U28f2xqhqRrFRY1jim4bGIgHQrjl X-Google-Smtp-Source: AG47ELtUjvPMlx0bxXGe8iIsgyOiJLVreV7wH9aVpFPjZVZPFiFf4gFKIOG2FMY+W4O5WqD67Pwsqg== X-Received: by 10.101.77.145 with SMTP id p17mr4160496pgq.275.1521658706975; Wed, 21 Mar 2018 11:58:26 -0700 (PDT) Received: from localhost.localdomain (c-24-4-232-46.hsd1.ca.comcast.net. [24.4.232.46]) by smtp.gmail.com with ESMTPSA id z13sm10532610pfk.129.2018.03.21.11.58.25 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 21 Mar 2018 11:58:26 -0700 (PDT) From: Richard Cochran To: netdev@vger.kernel.org Cc: devicetree@vger.kernel.org, Andrew Lunn , David Miller , Florian Fainelli , Mark Rutland , Miroslav Lichvar , Rob Herring , Willem de Bruijn Subject: [PATCH net-next RFC V1 5/5] net: mdio: Add a driver for InES time stamping IP core. Date: Wed, 21 Mar 2018 11:58:18 -0700 Message-Id: X-Mailer: git-send-email 2.11.0 In-Reply-To: References: Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org The InES at the ZHAW offers a PTP time stamping IP core. The FPGA logic recognizes and time stamps PTP frames on the MII bus. This patch adds a driver for the core along with a device tree binding to allow hooking the driver to MAC devices. Signed-off-by: Richard Cochran --- Documentation/devicetree/bindings/net/ines-ptp.txt | 42 + drivers/net/phy/Makefile | 1 + drivers/net/phy/ines_ptp.c | 857 +++++++++++++++++++++ drivers/ptp/Kconfig | 10 + 4 files changed, 910 insertions(+) create mode 100644 Documentation/devicetree/bindings/net/ines-ptp.txt create mode 100644 drivers/net/phy/ines_ptp.c diff --git a/Documentation/devicetree/bindings/net/ines-ptp.txt b/Documentation/devicetree/bindings/net/ines-ptp.txt new file mode 100644 index 000000000000..ed7b1d773ded --- /dev/null +++ b/Documentation/devicetree/bindings/net/ines-ptp.txt @@ -0,0 +1,42 @@ +ZHAW InES PTP time stamping IP core + +The IP core needs two different kinds of nodes. The control node +lives somewhere in the memory map and specifies the address of the +control registers. There can be up to three port nodes placed on the +mdio bus. They associate a particular MAC with a port index within +the IP core. + +Required properties of the control node: + +- compatible: "ines,ptp-ctrl" +- reg: physical address and size of the register bank +- phandle: globally unique handle for the ports to point to + +Required properties of the port nodes: + +- compatible: "ines,ptp-port" +- ctrl-handle: points to the control node +- port-index: port channel within the IP core +- reg: phy address. This is required even though the + device does not respond to mdio operations + +Example: + + timestamper@60000000 { + compatible = "ines,ptp-ctrl"; + reg = <0x60000000 0x80>; + phandle = <0x10>; + }; + + ethernet@80000000 { + ... + mdio { + ... + timestamper@1f { + compatible = "ines,ptp-port"; + ctrl-handle = <0x10>; + port-index = <0>; + reg = <0x1f>; + }; + }; + }; diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 01acbcb2c798..e286bb822295 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -61,6 +61,7 @@ obj-$(CONFIG_DP83848_PHY) += dp83848.o obj-$(CONFIG_DP83867_PHY) += dp83867.o obj-$(CONFIG_FIXED_PHY) += fixed_phy.o obj-$(CONFIG_ICPLUS_PHY) += icplus.o +obj-$(CONFIG_INES_PTP_TSTAMP) += ines_ptp.o obj-$(CONFIG_INTEL_XWAY_PHY) += intel-xway.o obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o obj-$(CONFIG_LXT_PHY) += lxt.o diff --git a/drivers/net/phy/ines_ptp.c b/drivers/net/phy/ines_ptp.c new file mode 100644 index 000000000000..4f66459d4417 --- /dev/null +++ b/drivers/net/phy/ines_ptp.c @@ -0,0 +1,857 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2018 MOSER-BAER AG + */ +#define pr_fmt(fmt) "InES_PTP: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_DESCRIPTION("Driver for the ZHAW InES PTP time stamping IP core"); +MODULE_AUTHOR("Richard Cochran "); +MODULE_VERSION("1.0"); +MODULE_LICENSE("GPL"); + +/* GLOBAL register */ +#define MCAST_MAC_SELECT_SHIFT 2 +#define MCAST_MAC_SELECT_MASK 0x3 +#define IO_RESET BIT(1) +#define PTP_RESET BIT(0) + +/* VERSION register */ +#define IF_MAJOR_VER_SHIFT 12 +#define IF_MAJOR_VER_MASK 0xf +#define IF_MINOR_VER_SHIFT 8 +#define IF_MINOR_VER_MASK 0xf +#define FPGA_MAJOR_VER_SHIFT 4 +#define FPGA_MAJOR_VER_MASK 0xf +#define FPGA_MINOR_VER_SHIFT 0 +#define FPGA_MINOR_VER_MASK 0xf + +/* INT_STAT register */ +#define RX_INTR_STATUS_3 BIT(5) +#define RX_INTR_STATUS_2 BIT(4) +#define RX_INTR_STATUS_1 BIT(3) +#define TX_INTR_STATUS_3 BIT(2) +#define TX_INTR_STATUS_2 BIT(1) +#define TX_INTR_STATUS_1 BIT(0) + +/* INT_MSK register */ +#define RX_INTR_MASK_3 BIT(5) +#define RX_INTR_MASK_2 BIT(4) +#define RX_INTR_MASK_1 BIT(3) +#define TX_INTR_MASK_3 BIT(2) +#define TX_INTR_MASK_2 BIT(1) +#define TX_INTR_MASK_1 BIT(0) + +/* BUF_STAT register */ +#define RX_FIFO_NE_3 BIT(5) +#define RX_FIFO_NE_2 BIT(4) +#define RX_FIFO_NE_1 BIT(3) +#define TX_FIFO_NE_3 BIT(2) +#define TX_FIFO_NE_2 BIT(1) +#define TX_FIFO_NE_1 BIT(0) + +/* PORT_CONF register */ +#define CM_ONE_STEP BIT(6) +#define PHY_SPEED_SHIFT 4 +#define PHY_SPEED_MASK 0x3 +#define P2P_DELAY_WR_POS_SHIFT 2 +#define P2P_DELAY_WR_POS_MASK 0x3 +#define PTP_MODE_SHIFT 0 +#define PTP_MODE_MASK 0x3 + +/* TS_STAT_TX register */ +#define TS_ENABLE BIT(15) +#define DATA_READ_POS_SHIFT 8 +#define DATA_READ_POS_MASK 0x1f +#define DISCARDED_EVENTS_SHIFT 4 +#define DISCARDED_EVENTS_MASK 0xf + +#define INES_N_PORTS 3 +#define INES_REGISTER_SIZE 0x80 +#define INES_PORT_OFFSET 0x20 +#define INES_PORT_SIZE 0x20 +#define INES_FIFO_DEPTH 90 +#define INES_MAX_EVENTS 100 + +#define BC_PTP_V1 0 +#define BC_PTP_V2 1 +#define TC_E2E_PTP_V2 2 +#define TC_P2P_PTP_V2 3 + +#define OFF_PTP_CLOCK_ID 20 +#define OFF_PTP_PORT_NUM 28 + +#define PHY_SPEED_10 0 +#define PHY_SPEED_100 1 +#define PHY_SPEED_1000 2 + +#define PORT_CONF \ + ((PHY_SPEED_1000 << PHY_SPEED_SHIFT) | (BC_PTP_V2 << PTP_MODE_SHIFT)) + +#define ines_read32(s, r) __raw_readl(&s->regs->r) +#define ines_write32(s, v, r) __raw_writel(v, &s->regs->r) + +#define MESSAGE_TYPE_SYNC 1 +#define MESSAGE_TYPE_P_DELAY_REQ 2 +#define MESSAGE_TYPE_P_DELAY_RESP 3 +#define MESSAGE_TYPE_DELAY_REQ 4 + +#define SYNC 0x0 +#define DELAY_REQ 0x1 +#define PDELAY_REQ 0x2 +#define PDELAY_RESP 0x3 + +static LIST_HEAD(ines_clocks); +static DEFINE_MUTEX(ines_clocks_lock); + +struct ines_global_registers { + u32 id; + u32 test; + u32 global; + u32 version; + u32 test2; + u32 int_stat; + u32 int_msk; + u32 buf_stat; +}; + +struct ines_port_registers { + u32 port_conf; + u32 p_delay; + u32 ts_stat_tx; + u32 ts_stat_rx; + u32 ts_tx; + u32 ts_rx; +}; + +struct ines_timestamp { + struct list_head list; + unsigned long tmo; + u16 tag; + u64 sec; + u64 nsec; + u64 clkid; + u16 portnum; + u16 seqid; +}; + +struct ines_port { + struct ines_port_registers *regs; + struct ines_clock *clock; + bool rxts_enabled; + bool txts_enabled; + unsigned int index; + struct delayed_work ts_work; + /* lock protects event list and tx_skb */ + spinlock_t lock; + struct sk_buff *tx_skb; + struct list_head events; + struct list_head pool; + struct ines_timestamp pool_data[INES_MAX_EVENTS]; +}; + +struct ines_clock { + struct ines_port port[INES_N_PORTS]; + struct ines_global_registers *regs; + void __iomem *base; + struct device_node *node; + struct list_head list; +}; + +static bool ines_match(struct sk_buff *skb, unsigned int ptp_class, + struct ines_timestamp *ts); +static int ines_rxfifo_read(struct ines_port *port); +static u64 ines_rxts64(struct ines_port *port, unsigned int words); +static bool ines_timestamp_expired(struct ines_timestamp *ts); +static u64 ines_txts64(struct ines_port *port, unsigned int words); +static void ines_txtstamp_work(struct work_struct *work); +static bool is_sync_pdelay_resp(struct sk_buff *skb, int type); +static u8 tag_to_msgtype(u8 tag); + +static void ines_clock_cleanup(struct ines_clock *clock) +{ + struct ines_port *port; + int i; + + for (i = 0; i < INES_N_PORTS; i++) { + port = &clock->port[i]; + cancel_delayed_work_sync(&port->ts_work); + } +} + +static int ines_clock_init(struct ines_clock *clock, struct device_node *node, + void __iomem *addr) +{ + unsigned long port_addr; + struct ines_port *port; + int i, j; + + INIT_LIST_HEAD(&clock->list); + clock->node = node; + clock->base = addr; + clock->regs = clock->base; + + for (i = 0; i < INES_N_PORTS; i++) { + port = &clock->port[i]; + port_addr = (unsigned long) clock->base + + INES_PORT_OFFSET + i * INES_PORT_SIZE; + port->regs = (struct ines_port_registers *) port_addr; + port->clock = clock; + port->index = i; + INIT_DELAYED_WORK(&port->ts_work, ines_txtstamp_work); + spin_lock_init(&port->lock); + INIT_LIST_HEAD(&port->events); + INIT_LIST_HEAD(&port->pool); + for (j = 0; j < INES_MAX_EVENTS; j++) + list_add(&port->pool_data[j].list, &port->pool); + } + + ines_write32(clock, 0xBEEF, test); + ines_write32(clock, 0xBEEF, test2); + + pr_debug("ID 0x%x\n", ines_read32(clock, id)); + pr_debug("TEST 0x%x\n", ines_read32(clock, test)); + pr_debug("VERSION 0x%x\n", ines_read32(clock, version)); + pr_debug("TEST2 0x%x\n", ines_read32(clock, test2)); + + for (i = 0; i < INES_N_PORTS; i++) { + port = &clock->port[i]; + ines_write32(port, PORT_CONF, port_conf); + } + + return 0; +} + +static void ines_dump_ts(char *label, struct ines_timestamp *ts) +{ +#ifdef DEBUG + pr_err("%s timestamp, tag=0x%04hx t=%llu.%9llu c=0x%llx p=%hu s=%hu\n", + label, ts->tag, ts->sec, ts->nsec, + ts->clkid, ts->portnum, ts->seqid); +#endif +} + +static struct ines_port *ines_find_port(struct device_node *node, u32 index) +{ + struct ines_port *port = NULL; + struct ines_clock *clock; + struct list_head *this; + + if (index > INES_N_PORTS - 1) + return NULL; + + mutex_lock(&ines_clocks_lock); + list_for_each(this, &ines_clocks) { + clock = list_entry(this, struct ines_clock, list); + if (clock->node == node) { + port = &clock->port[index]; + break; + } + } + mutex_unlock(&ines_clocks_lock); + return port; +} + +static u64 ines_find_rxts(struct ines_port *port, struct sk_buff *skb, int type) +{ + struct list_head *this, *next; + struct ines_timestamp *ts; + unsigned long flags; + u64 ns = 0; + + if (type == PTP_CLASS_NONE) + return 0; + + spin_lock_irqsave(&port->lock, flags); + ines_rxfifo_read(port); + list_for_each_safe(this, next, &port->events) { + ts = list_entry(this, struct ines_timestamp, list); + if (ines_timestamp_expired(ts)) { + list_del_init(&ts->list); + list_add(&ts->list, &port->pool); + continue; + } + if (ines_match(skb, type, ts)) { + ns = ts->sec * 1000000000ULL + ts->nsec; + list_del_init(&ts->list); + list_add(&ts->list, &port->pool); + break; + } + } + spin_unlock_irqrestore(&port->lock, flags); + + return ns; +} + +static u64 ines_find_txts(struct ines_port *port, struct sk_buff *skb) +{ + unsigned int class = ptp_classify_raw(skb), i; + u32 data_rd_pos, buf_stat, mask, ts_stat_tx; + struct ines_timestamp ts; + unsigned long flags; + u64 ns = 0; + + mask = TX_FIFO_NE_1 << port->index; + + spin_lock_irqsave(&port->lock, flags); + + for (i = 0; i < INES_FIFO_DEPTH; i++) { + + buf_stat = ines_read32(port->clock, buf_stat); + if (!(buf_stat & mask)) { + pr_debug("Tx timestamp FIFO unexpectedly empty\n"); + break; + } + ts_stat_tx = ines_read32(port, ts_stat_tx); + data_rd_pos = (ts_stat_tx >> DATA_READ_POS_SHIFT) & + DATA_READ_POS_MASK; + if (data_rd_pos) { + pr_err("unexpected Tx read pos %u\n", data_rd_pos); + break; + } + + ts.tag = ines_read32(port, ts_tx); + ts.sec = ines_txts64(port, 3); + ts.nsec = ines_txts64(port, 2); + ts.clkid = ines_txts64(port, 4); + ts.portnum = ines_read32(port, ts_tx); + ts.seqid = ines_read32(port, ts_tx); + + ines_dump_ts("Tx", &ts); + + if (ines_match(skb, class, &ts)) { + ns = ts.sec * 1000000000ULL + ts.nsec; + break; + } + } + + spin_unlock_irqrestore(&port->lock, flags); + return ns; +} + +static int ines_hwtstamp(struct mdio_device *m, struct ifreq *ifr) +{ + u32 cm_one_step = 0, port_conf, ts_stat_rx, ts_stat_tx; + struct ines_port *port = dev_get_drvdata(&m->dev); + struct hwtstamp_config cfg; + unsigned long flags; + + if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg))) + return -EFAULT; + + /* reserved for future extensions */ + if (cfg.flags) + return -EINVAL; + + switch (cfg.tx_type) { + case HWTSTAMP_TX_OFF: + ts_stat_tx = 0; + break; + case HWTSTAMP_TX_ON: + ts_stat_tx = TS_ENABLE; + break; + case HWTSTAMP_TX_ONESTEP_P2P: + ts_stat_tx = TS_ENABLE; + cm_one_step = CM_ONE_STEP; + break; + default: + return -ERANGE; + } + + switch (cfg.rx_filter) { + case HWTSTAMP_FILTER_NONE: + ts_stat_rx = 0; + break; + case HWTSTAMP_FILTER_ALL: + case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: + case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: + case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: + return -ERANGE; + case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: + case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: + case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: + case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: + case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: + case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: + case HWTSTAMP_FILTER_PTP_V2_EVENT: + case HWTSTAMP_FILTER_PTP_V2_SYNC: + case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: + ts_stat_rx = TS_ENABLE; + cfg.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT; + break; + default: + return -ERANGE; + } + + spin_lock_irqsave(&port->lock, flags); + + port_conf = ines_read32(port, port_conf); + port_conf &= ~CM_ONE_STEP; + port_conf |= cm_one_step; + + ines_write32(port, port_conf, port_conf); + ines_write32(port, ts_stat_rx, ts_stat_rx); + ines_write32(port, ts_stat_tx, ts_stat_tx); + + port->rxts_enabled = ts_stat_rx == TS_ENABLE ? true : false; + port->txts_enabled = ts_stat_tx == TS_ENABLE ? true : false; + + spin_unlock_irqrestore(&port->lock, flags); + + return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0; +} + +static bool ines_match(struct sk_buff *skb, unsigned int ptp_class, + struct ines_timestamp *ts) +{ + u8 *msgtype, *data = skb_mac_header(skb); + unsigned int offset = 0; + u16 *portn, *seqid; + u64 *clkid; + + if (unlikely(ptp_class & PTP_CLASS_V1)) + return false; + + 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; + default: + return false; + } + + if (skb->len + ETH_HLEN < offset + OFF_PTP_SEQUENCE_ID + sizeof(*seqid)) + return false; + + msgtype = data + offset; + clkid = (u64 *)(data + offset + OFF_PTP_CLOCK_ID); + portn = (u16 *)(data + offset + OFF_PTP_PORT_NUM); + seqid = (u16 *)(data + offset + OFF_PTP_SEQUENCE_ID); + + if (tag_to_msgtype(ts->tag & 0x7) != (*msgtype & 0xf)) { + pr_debug("msgtype mismatch ts %hhu != skb %hhu\n", + tag_to_msgtype(ts->tag & 0x7), *msgtype & 0xf); + return false; + } + if (cpu_to_be64(ts->clkid) != *clkid) { + pr_debug("clkid mismatch ts %llx != skb %llx\n", + cpu_to_be64(ts->clkid), *clkid); + return false; + } + if (ts->portnum != ntohs(*portn)) { + pr_debug("portn mismatch ts %hu != skb %hu\n", + ts->portnum, ntohs(*portn)); + return false; + } + if (ts->seqid != ntohs(*seqid)) { + pr_debug("seqid mismatch ts %hu != skb %hu\n", + ts->seqid, ntohs(*seqid)); + return false; + } + + return true; +} + +static bool ines_rxtstamp(struct mdio_device *m, struct sk_buff *skb, int type) +{ + struct ines_port *port = dev_get_drvdata(&m->dev); + struct skb_shared_hwtstamps *ssh; + u64 ns; + + if (!port->rxts_enabled) + return false; + + ns = ines_find_rxts(port, skb, type); + if (!ns) + return false; + + ssh = skb_hwtstamps(skb); + ssh->hwtstamp = ns_to_ktime(ns); + netif_rx(skb); + + return true; +} + +static int ines_rxfifo_read(struct ines_port *port) +{ + u32 data_rd_pos, buf_stat, mask, ts_stat_rx; + struct ines_timestamp *ts; + unsigned int i; + + mask = RX_FIFO_NE_1 << port->index; + + for (i = 0; i < INES_FIFO_DEPTH; i++) { + if (list_empty(&port->pool)) { + pr_err("event pool is empty\n"); + return -1; + } + buf_stat = ines_read32(port->clock, buf_stat); + if (!(buf_stat & mask)) + break; + + ts_stat_rx = ines_read32(port, ts_stat_rx); + data_rd_pos = (ts_stat_rx >> DATA_READ_POS_SHIFT) & + DATA_READ_POS_MASK; + if (data_rd_pos) { + pr_err("unexpected Rx read pos %u\n", data_rd_pos); + break; + } + + ts = list_first_entry(&port->pool, struct ines_timestamp, list); + ts->tmo = jiffies + HZ; + ts->tag = ines_read32(port, ts_rx); + ts->sec = ines_rxts64(port, 3); + ts->nsec = ines_rxts64(port, 2); + ts->clkid = ines_rxts64(port, 4); + ts->portnum = ines_read32(port, ts_rx); + ts->seqid = ines_read32(port, ts_rx); + + ines_dump_ts("Rx", ts); + + list_del_init(&ts->list); + list_add_tail(&ts->list, &port->events); + } + + return 0; +} + +static u64 ines_rxts64(struct ines_port *port, unsigned int words) +{ + unsigned int i; + u64 result; + u16 word; + + word = ines_read32(port, ts_rx); + result = word; + words--; + for (i = 0; i < words; i++) { + word = ines_read32(port, ts_rx); + result <<= 16; + result |= word; + } + return result; +} + +static bool ines_timestamp_expired(struct ines_timestamp *ts) +{ + return time_after(jiffies, ts->tmo); +} + +static int ines_ts_info(struct mdio_device *m, struct ethtool_ts_info *info) +{ + info->so_timestamping = + SOF_TIMESTAMPING_TX_HARDWARE | + SOF_TIMESTAMPING_TX_SOFTWARE | + SOF_TIMESTAMPING_RX_HARDWARE | + SOF_TIMESTAMPING_RX_SOFTWARE | + SOF_TIMESTAMPING_SOFTWARE | + SOF_TIMESTAMPING_RAW_HARDWARE; + + info->phc_index = -1; + + info->tx_types = + (1 << HWTSTAMP_TX_OFF) | + (1 << HWTSTAMP_TX_ON) | + (1 << HWTSTAMP_TX_ONESTEP_P2P); + + info->rx_filters = + (1 << HWTSTAMP_FILTER_NONE) | + (1 << HWTSTAMP_FILTER_PTP_V2_EVENT); + + return 0; +} + +static u64 ines_txts64(struct ines_port *port, unsigned int words) +{ + unsigned int i; + u64 result; + u16 word; + + word = ines_read32(port, ts_tx); + result = word; + words--; + for (i = 0; i < words; i++) { + word = ines_read32(port, ts_tx); + result <<= 16; + result |= word; + } + return result; +} + +static bool ines_txts_onestep(struct ines_port *port, struct sk_buff *skb, int type) +{ + unsigned long flags; + u32 port_conf; + + spin_lock_irqsave(&port->lock, flags); + port_conf = ines_read32(port, port_conf); + spin_unlock_irqrestore(&port->lock, flags); + + if (port_conf & CM_ONE_STEP) + return is_sync_pdelay_resp(skb, type); + + return false; +} + +static void ines_txtstamp(struct mdio_device *m, struct sk_buff *skb, int type) +{ + struct ines_port *port = dev_get_drvdata(&m->dev); + struct sk_buff *old_skb; + unsigned long flags; + + if (!port->txts_enabled || ines_txts_onestep(port, skb, type)) { + kfree_skb(skb); + return; + } + + spin_lock_irqsave(&port->lock, flags); + + if (port->tx_skb) + old_skb = port->tx_skb; + + port->tx_skb = skb; + + spin_unlock_irqrestore(&port->lock, flags); + + if (old_skb) + kfree_skb(old_skb); + + schedule_delayed_work(&port->ts_work, 1); +} + +static void ines_txtstamp_work(struct work_struct *work) +{ + struct ines_port *port = + container_of(work, struct ines_port, ts_work.work); + struct skb_shared_hwtstamps ssh; + struct sk_buff *skb; + unsigned long flags; + u64 ns; + + spin_lock_irqsave(&port->lock, flags); + skb = port->tx_skb; + port->tx_skb = NULL; + spin_unlock_irqrestore(&port->lock, flags); + + ns = ines_find_txts(port, skb); + if (!ns) { + kfree_skb(skb); + return; + } + ssh.hwtstamp = ns_to_ktime(ns); + skb_complete_tx_timestamp(skb, &ssh); +} + +static bool is_sync_pdelay_resp(struct sk_buff *skb, int type) +{ + u8 *data = skb->data, *msgtype; + unsigned int offset = 0; + + if (type & PTP_CLASS_VLAN) + offset += VLAN_HLEN; + + switch (type & 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; + default: + return 0; + } + + if (type & PTP_CLASS_V1) + offset += OFF_PTP_CONTROL; + + if (skb->len < offset + 1) + return 0; + + msgtype = data + offset; + + switch ((*msgtype & 0xf)) { + case SYNC: + case PDELAY_RESP: + return true; + default: + return false; + } +} + +static u8 tag_to_msgtype(u8 tag) +{ + switch (tag) { + case MESSAGE_TYPE_SYNC: + return SYNC; + case MESSAGE_TYPE_P_DELAY_REQ: + return PDELAY_REQ; + case MESSAGE_TYPE_P_DELAY_RESP: + return PDELAY_RESP; + case MESSAGE_TYPE_DELAY_REQ: + return DELAY_REQ; + } + return 0xf; +} + +static int ines_ptp_ctrl_probe(struct platform_device *pld) +{ + struct ines_clock *clock; + struct resource *res; + void __iomem *addr; + int err = 0; + + res = platform_get_resource(pld, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pld->dev, "missing memory resource\n"); + return -EINVAL; + } + addr = devm_ioremap_resource(&pld->dev, res); + if (IS_ERR(addr)) { + err = PTR_ERR(addr); + goto out; + } + clock = kzalloc(sizeof(*clock), GFP_KERNEL); + if (!clock) { + err = -ENOMEM; + goto out; + } + if (ines_clock_init(clock, pld->dev.of_node, addr)) { + kfree(clock); + err = -ENOMEM; + goto out; + } + mutex_lock(&ines_clocks_lock); + list_add_tail(&ines_clocks, &clock->list); + mutex_unlock(&ines_clocks_lock); + + dev_set_drvdata(&pld->dev, clock); +out: + return err; +} + +static int ines_ptp_ctrl_remove(struct platform_device *pld) +{ + struct ines_clock *clock = dev_get_drvdata(&pld->dev); + + mutex_lock(&ines_clocks_lock); + list_del(&clock->list); + mutex_unlock(&ines_clocks_lock); + ines_clock_cleanup(clock); + kfree(clock); + return 0; +} + +static int ines_ptp_port_probe(struct mdio_device *mdiodev) +{ + struct device_node *node; + struct ines_port *port; + int err = 0; + u32 index; + + if (of_property_read_u32(mdiodev->dev.of_node, "port-index", &index)) { + dev_err(&mdiodev->dev, "missing port-index\n"); + return -EINVAL; + } + node = of_parse_phandle(mdiodev->dev.of_node, "ctrl-handle", 0); + if (IS_ERR(node)) { + dev_err(&mdiodev->dev, "missing ctrl-handle\n"); + return PTR_ERR(node); + } + port = ines_find_port(node, index); + if (!port) { + dev_err(&mdiodev->dev, "missing port\n"); + err = -ENODEV; + goto out; + } + mdiodev->ts_info = ines_ts_info; + mdiodev->hwtstamp = ines_hwtstamp; + mdiodev->rxtstamp = ines_rxtstamp; + mdiodev->txtstamp = ines_txtstamp; + dev_set_drvdata(&mdiodev->dev, port); +out: + of_node_put(node); + return err; +} + +static void ines_ptp_port_remove(struct mdio_device *mdiodev) +{ +} + +static const struct of_device_id ines_ptp_ctrl_of_match[] = { + { .compatible = "ines,ptp-ctrl" }, + { } +}; + +MODULE_DEVICE_TABLE(of, ines_ptp_ctrl_of_match); + +static struct platform_driver ines_ptp_ctrl_driver = { + .probe = ines_ptp_ctrl_probe, + .remove = ines_ptp_ctrl_remove, + .driver = { + .name = "ines_ptp_ctrl", + .of_match_table = of_match_ptr(ines_ptp_ctrl_of_match), + }, +}; + +static const struct of_device_id ines_ptp_port_of_match[] = { + { .compatible = "ines,ptp-port" }, + { } +}; + +static struct mdio_driver ines_ptp_port_driver = { + .probe = ines_ptp_port_probe, + .remove = ines_ptp_port_remove, + .mdiodrv.driver = { + .name = "ines_ptp_port", + .of_match_table = ines_ptp_port_of_match, + }, +}; + +static int __init ines_ptp_init(void) +{ + int err; + + err = platform_driver_register(&ines_ptp_ctrl_driver); + if (err) + return err; + + err = mdio_driver_register(&ines_ptp_port_driver); + if (err) + platform_driver_unregister(&ines_ptp_ctrl_driver); + + return err; +} + +static void __exit ines_ptp_cleanup(void) +{ + mdio_driver_unregister(&ines_ptp_port_driver); + platform_driver_unregister(&ines_ptp_ctrl_driver); +} + +module_init(ines_ptp_init); +module_exit(ines_ptp_cleanup); diff --git a/drivers/ptp/Kconfig b/drivers/ptp/Kconfig index a21ad10d613c..10ef161dd2a1 100644 --- a/drivers/ptp/Kconfig +++ b/drivers/ptp/Kconfig @@ -88,6 +88,16 @@ config DP83640_PHY In order for this to work, your MAC driver must also implement the skb_tx_timestamp() function. +config INES_PTP_TSTAMP + tristate "ZHAW InES PTP time stamping IP core" + depends on NETWORK_PHY_TIMESTAMPING + depends on PHYLIB + depends on PTP_1588_CLOCK + ---help--- + This driver adds support for using the ZHAW InES 1588 IP + core. This clock is only useful if the MII bus of your MAC + is wired up to the core. + config PTP_1588_CLOCK_PCH tristate "Intel PCH EG20T as PTP clock" depends on X86_32 || COMPILE_TEST