From patchwork Fri Jan 3 20:01:19 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 1217417 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 (no SPF record) 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="uM6Y4uLo"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 47qG5C4l78z9sR1 for ; Sat, 4 Jan 2020 07:01:51 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728689AbgACUBu (ORCPT ); Fri, 3 Jan 2020 15:01:50 -0500 Received: from mail-wr1-f65.google.com ([209.85.221.65]:41714 "EHLO mail-wr1-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728654AbgACUBt (ORCPT ); Fri, 3 Jan 2020 15:01:49 -0500 Received: by mail-wr1-f65.google.com with SMTP id c9so43475684wrw.8 for ; Fri, 03 Jan 2020 12:01:46 -0800 (PST) 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=0NuFrsJsJe1ZD2gjej39RnA7WNRUq88hu4Umo0kelpg=; b=uM6Y4uLo2XVDWPL1dmP9WaJtixPkJnT/5MjVh0nKjlsJOsSIkR+9XDo7im4N6QQW+j L1UCz5RU8k5ewOGhFD8whikhic0q/iAwRBP+otinoriYpnO2yWW7Es0w6EjxQ9jpGSRP 9rmlaoDsouaRbV4zp6bXVTU6oFvkQhfOWGbQhL1yyz/ckCMgJa1JCaw7FPUXCXKgOQ09 HvAcDqaMcc0AEvHaWB4K8WO4RJYVsgQHnfKKkJr83bAxOADrdxLDODRsCfZUxowr0aKV gPskR1TfFZCYQw/EIU6aR55qvjY3NnINMLA+Dkevynr68snQZWLGspZlaBGshZUCt2/x 9/hQ== 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=0NuFrsJsJe1ZD2gjej39RnA7WNRUq88hu4Umo0kelpg=; b=HFa74q7n3FwgQRcoPjpmIvQrfj+R9zqttr7X3rYttZxYyuopd6sgdmpai7gFTBJS9f FjJ92yzRZdHfW2Htsq4KZeIwktz31iK2lsE44lvh/bJ8nnhy3KwpbIIjKV6vEo+P/fnn /U51GQQbAtRgssXWVeYk3n2HFXN3WlfCSb5lNfUQRQJ57iQJroCcGy+3ZuiVVsILg0BO 0qDrpm18Fm38/UlQ8EehSj7FydB8q+tVHv00zAo+MJ1YC3e7WAcXuH8pStdz9907aCvW 3+aurfuRIDPGEtM5gTqkKsHjmmATBgl1BoYdTF4Aw4lQD4660CWgsdrXCRDgUyQqc2gY g64g== X-Gm-Message-State: APjAAAVz0oXzo3rICcAKr3uwn5URHuQJWQcQ6f+04PuCImqexUh+0oVi upJubjlZnCPTgyZJZK6ejjY= X-Google-Smtp-Source: APXvYqxQndrgUkenY7kGV8MH/BKePURHVrMDi8nRkXD0D9sz4ER8rTiMfNQM/3Xefz8UWDIoFORL4g== X-Received: by 2002:a5d:540f:: with SMTP id g15mr86351917wrv.86.1578081706316; Fri, 03 Jan 2020 12:01:46 -0800 (PST) Received: from localhost.localdomain ([188.25.254.226]) by smtp.gmail.com with ESMTPSA id e12sm60998154wrn.56.2020.01.03.12.01.44 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 03 Jan 2020 12:01:45 -0800 (PST) From: Vladimir Oltean To: davem@davemloft.net, jakub.kicinski@netronome.com, linux@armlinux.org.uk, andrew@lunn.ch, f.fainelli@gmail.com, vivien.didelot@gmail.com Cc: alexandru.marginean@nxp.com, claudiu.manoil@nxp.com, xiaoliang.yang_1@nxp.com, yangbo.lu@nxp.com, netdev@vger.kernel.org, alexandre.belloni@bootlin.com, horatiu.vultur@microchip.com, UNGLinuxDriver@microchip.com, Vladimir Oltean Subject: [PATCH v4 net-next 1/9] mii: Add helpers for parsing SGMII auto-negotiation Date: Fri, 3 Jan 2020 22:01:19 +0200 Message-Id: <20200103200127.6331-2-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200103200127.6331-1-olteanv@gmail.com> References: <20200103200127.6331-1-olteanv@gmail.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Vladimir Oltean Typically a MAC PCS auto-configures itself after it receives the negotiated copper-side link settings from the PHY, but some MAC devices are more special and need manual interpretation of the SGMII AN result. In other cases, the PCS exposes the entire tx_config_reg base page as it is transmitted on the wire during auto-negotiation, so it makes sense to be able to decode the equivalent lp_advertised bit mask from the raw u16 (of course, "lp" considering the PCS to be the local PHY). Therefore, add the bit definitions for the SGMII registers 4 and 5 (local device ability, link partner ability), as well as a link_mode conversion helper that can be used to feed the AN results into phy_resolve_aneg_linkmode. Signed-off-by: Vladimir Oltean --- Changes in v4: - None. Changes in v3: - Moved the LPA_* and ADVERTISE_* bits for SGMII to a separate group of defines. include/linux/mii.h | 50 ++++++++++++++++++++++++++++++++++++++++ include/uapi/linux/mii.h | 12 ++++++++++ 2 files changed, 62 insertions(+) diff --git a/include/linux/mii.h b/include/linux/mii.h index 4ce8901a1af6..18c6208f56fc 100644 --- a/include/linux/mii.h +++ b/include/linux/mii.h @@ -372,6 +372,56 @@ static inline u32 mii_lpa_to_ethtool_lpa_x(u32 lpa) return result | mii_adv_to_ethtool_adv_x(lpa); } +/** + * mii_lpa_mod_linkmode_adv_sgmii + * @lp_advertising: pointer to destination link mode. + * @lpa: value of the MII_LPA register + * + * A small helper function that translates MII_LPA bits to + * linkmode advertisement settings for SGMII. + * Leaves other bits unchanged. + */ +static inline void +mii_lpa_mod_linkmode_lpa_sgmii(unsigned long *lp_advertising, u32 lpa) +{ + u32 speed_duplex = lpa & LPA_SGMII_DPX_SPD_MASK; + + linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT, lp_advertising, + speed_duplex == LPA_SGMII_1000HALF); + + linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, lp_advertising, + speed_duplex == LPA_SGMII_1000FULL); + + linkmode_mod_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT, lp_advertising, + speed_duplex == LPA_SGMII_100HALF); + + linkmode_mod_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, lp_advertising, + speed_duplex == LPA_SGMII_100FULL); + + linkmode_mod_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT, lp_advertising, + speed_duplex == LPA_SGMII_10HALF); + + linkmode_mod_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT, lp_advertising, + speed_duplex == LPA_SGMII_10FULL); +} + +/** + * mii_lpa_to_linkmode_adv_sgmii + * @advertising: pointer to destination link mode. + * @lpa: value of the MII_LPA register + * + * A small helper function that translates MII_ADVERTISE bits + * to linkmode advertisement settings when in SGMII mode. + * Clears the old value of advertising. + */ +static inline void mii_lpa_to_linkmode_lpa_sgmii(unsigned long *lp_advertising, + u32 lpa) +{ + linkmode_zero(lp_advertising); + + mii_lpa_mod_linkmode_lpa_sgmii(lp_advertising, lpa); +} + /** * mii_adv_mod_linkmode_adv_t * @advertising:pointer to destination link mode. diff --git a/include/uapi/linux/mii.h b/include/uapi/linux/mii.h index 51b48e4be1f2..0b9c3beda345 100644 --- a/include/uapi/linux/mii.h +++ b/include/uapi/linux/mii.h @@ -131,6 +131,18 @@ #define NWAYTEST_LOOPBACK 0x0100 /* Enable loopback for N-way */ #define NWAYTEST_RESV2 0xfe00 /* Unused... */ +/* MAC and PHY tx_config_Reg[15:0] for SGMII in-band auto-negotiation.*/ +#define ADVERTISE_SGMII 0x0001 /* MAC can do SGMII */ +#define LPA_SGMII 0x0001 /* PHY can do SGMII */ +#define LPA_SGMII_DPX_SPD_MASK 0x1C00 /* SGMII duplex and speed bits */ +#define LPA_SGMII_10HALF 0x0000 /* Can do 10mbps half-duplex */ +#define LPA_SGMII_10FULL 0x1000 /* Can do 10mbps full-duplex */ +#define LPA_SGMII_100HALF 0x0400 /* Can do 100mbps half-duplex */ +#define LPA_SGMII_100FULL 0x1400 /* Can do 100mbps full-duplex */ +#define LPA_SGMII_1000HALF 0x0800 /* Can do 1000mbps half-duplex */ +#define LPA_SGMII_1000FULL 0x1800 /* Can do 1000mbps full-duplex */ +#define LPA_SGMII_LINK 0x8000 /* PHY link with copper-side partner */ + /* 1000BASE-T Control register */ #define ADVERTISE_1000FULL 0x0200 /* Advertise 1000BASE-T full duplex */ #define ADVERTISE_1000HALF 0x0100 /* Advertise 1000BASE-T half duplex */ From patchwork Fri Jan 3 20:01:20 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 1217416 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 (no SPF record) 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="Jgb84Z3Z"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 47qG5B4jSwz9sPn for ; Sat, 4 Jan 2020 07:01:50 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728684AbgACUBt (ORCPT ); Fri, 3 Jan 2020 15:01:49 -0500 Received: from mail-wr1-f65.google.com ([209.85.221.65]:39229 "EHLO mail-wr1-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728671AbgACUBt (ORCPT ); Fri, 3 Jan 2020 15:01:49 -0500 Received: by mail-wr1-f65.google.com with SMTP id y11so43463706wrt.6 for ; Fri, 03 Jan 2020 12:01:48 -0800 (PST) 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=wqXMXCnxhaXI8tjirHvg26Psm0q12h6CVvV+f3E6dtk=; b=Jgb84Z3ZiwzOF++4Rb8Dt/+1y65WcFB0L+GPQpmNpvp6gaNfafSLM+secvvdzefGxT CHrMlFDV9h5FctXDOxME+xfc4Z/xiuMwppJNnpXlBM51KimHAglM4alY9Y+CYTqxTouL XhP6raCi1oAvqydNFLm0TAQeh7JSFfrnt8UplEzpdJaxTNp6LlrHjJu5GYu+tASmDOdC AE9K60NlX/65yH2RqjMlQd37+JDkTBX1aMFTYANXRVhfnB6O0ZSzl2mcAkJQjdOx3H2g s2xNuusW07tqOUNNqluNIDa8dB8YQaQZeWobUlKoNgy7Ob0hqNAtjtGfH1IwmZ693hnJ m0HQ== 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=wqXMXCnxhaXI8tjirHvg26Psm0q12h6CVvV+f3E6dtk=; b=AhL7rmo6kl6SJFlrNZTeK9SADb9I6LDSbk2FqDxDjAQI+wNdRKAKE1/I3ulyON3mnK DFJXIdLCCpGxmBnIwmHekvJ8V0Qgt2qviSB1uk8grRwhCDBKtusdT6iz6NBOEAaP0d59 uYO3rvUR5VF8SOoheqoEmnVGnHa8T2gDR3o1IOLAGcDMys1XEYSHEzcdTsqjjNdy/uCL WqIKA2tuMI/EA5yLA9vGTxSzAk1JmyOhD3xR63sKrKfKC1EzhkjiL3QMqDaKOiBVXEhe xG+2qECNDXjEdRTN7harmBtv/qiInOHXqsxDEAQB0cDJB8IWdMiPK4YygAfGVhMBqYZX aiiA== X-Gm-Message-State: APjAAAV2EqR/gHtE080sBThjGu+I6t+vVidKixywxawzvgMCrRSZI4ci 3UtSl5XPA3bDFwa4ifQ8CFk= X-Google-Smtp-Source: APXvYqzXsN+wSauBKnx8rhDaehHJT8hIEYVEhFg9Qp+VfgWR+ojKBrdQkqDh17CLQEPaUUPOkjwRcA== X-Received: by 2002:adf:f6c1:: with SMTP id y1mr96258007wrp.17.1578081707563; Fri, 03 Jan 2020 12:01:47 -0800 (PST) Received: from localhost.localdomain ([188.25.254.226]) by smtp.gmail.com with ESMTPSA id e12sm60998154wrn.56.2020.01.03.12.01.46 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 03 Jan 2020 12:01:47 -0800 (PST) From: Vladimir Oltean To: davem@davemloft.net, jakub.kicinski@netronome.com, linux@armlinux.org.uk, andrew@lunn.ch, f.fainelli@gmail.com, vivien.didelot@gmail.com Cc: alexandru.marginean@nxp.com, claudiu.manoil@nxp.com, xiaoliang.yang_1@nxp.com, yangbo.lu@nxp.com, netdev@vger.kernel.org, alexandre.belloni@bootlin.com, horatiu.vultur@microchip.com, UNGLinuxDriver@microchip.com, Vladimir Oltean Subject: [PATCH v4 net-next 2/9] net: phylink: make QSGMII a valid PHY mode for in-band AN Date: Fri, 3 Jan 2020 22:01:20 +0200 Message-Id: <20200103200127.6331-3-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200103200127.6331-1-olteanv@gmail.com> References: <20200103200127.6331-1-olteanv@gmail.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Vladimir Oltean QSGMII is a SerDes protocol clocked at 5 Gbaud (4 times higher than SGMII which is clocked at 1.25 Gbaud), with the same 8b/10b encoding and some extra symbols for synchronization. Logically it offers 4 SGMII interfaces multiplexed onto the same physical lanes. Each MAC PCS has its own in-band AN process with the system side of the QSGMII PHY, which is identical to the regular SGMII AN process. So allow QSGMII as a valid in-band AN mode, since it is no different from software perspective from regular SGMII. Signed-off-by: Vladimir Oltean --- Changes in v4: - None. Changes in v3: - None. Changes in v2: - None. drivers/net/phy/phylink.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index ba9468cc8e13..c19cbcf183e6 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -281,6 +281,7 @@ static int phylink_parse_mode(struct phylink *pl, struct fwnode_handle *fwnode) switch (pl->link_config.interface) { case PHY_INTERFACE_MODE_SGMII: + case PHY_INTERFACE_MODE_QSGMII: phylink_set(pl->supported, 10baseT_Half); phylink_set(pl->supported, 10baseT_Full); phylink_set(pl->supported, 100baseT_Half); From patchwork Fri Jan 3 20:01:21 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 1217418 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 (no SPF record) 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="fJ7yPPm+"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 47qG5F74rcz9sPn for ; Sat, 4 Jan 2020 07:01:53 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728703AbgACUBw (ORCPT ); Fri, 3 Jan 2020 15:01:52 -0500 Received: from mail-wr1-f68.google.com ([209.85.221.68]:42703 "EHLO mail-wr1-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728686AbgACUBu (ORCPT ); Fri, 3 Jan 2020 15:01:50 -0500 Received: by mail-wr1-f68.google.com with SMTP id q6so43388087wro.9 for ; Fri, 03 Jan 2020 12:01:49 -0800 (PST) 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=EYv2xTqIo2hEVHOG41HfTo46xhtWfJgsQgJ1Y9/YNjQ=; b=fJ7yPPm+xIlXeAVcQCHdsakpJon9YqYJseY5+R4VwBrKejZTUzTbarDja5VCdrRLTq cGr/2H58S5eQf0hzcuBilc27hXvDk0i48Gc+XFgaI3tC0hOiZYr6NGRcUyD8KddaTVHh mIwdAaauNuWYruBEZRpDROWqTBdb4e5uFzwLnCWUthQYFznwMQaqzhqNUFXMLi61N1tX ejxr82TAQW+l2/xe15YcFLiUkHQs/KRKd/X9i7Xbq/NavHxeCoRe6U0TftWISGMcWBWC 5pG0lPSwXxx/U6zOPHBcoiNe7yWg6sQYtZMG1vn4C0eMXxUjJTmEHPVxfmgrkIK59tO4 P56A== 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=EYv2xTqIo2hEVHOG41HfTo46xhtWfJgsQgJ1Y9/YNjQ=; b=rC25RDyI7k6RaUXzdZ+fRU7mNRMR7uDs0iuWUlOoBY7A6C8XBPHvibIdWE/PdUOm1G wg/MRgiiSPPsB0/1Kmy6u/JSq4ODYbP5HzrXoPRcILtnKQFMsHxeP0Lu0txFYpCqvq1Q MNu7pD/1QH+FeJMyZ+Ga2ReeDBKbJVsmpP8Uv/RSGAMGTDE/11m9b3PASQoRNMHUpryp 48a3J/bidMCa6Mkozj2KX+l2pEDczdjuhXN6OXzlz3cJ/5chsCmXI1f2AV30mxpBlVFr sckvHABFKAOcHXinVA8quC052YqbDedcynPRmFbXhHYsQEUyi2x4XcvH8jqnNOXu28bW bx2g== X-Gm-Message-State: APjAAAVhgt7FAI/2WITeBvBV15nEBj71tpBRu0pPsmSL9WvT2Dn24jO2 fyYaOwty1VlTo3J894rPFX4= X-Google-Smtp-Source: APXvYqxFlQroFR7a54UTwxmeHU9SOE6xKV2O4D1TYIxpYxVJxgNvFu4AC56WQ/dGYN/dZOascQe5ig== X-Received: by 2002:a5d:4d8d:: with SMTP id b13mr94342266wru.6.1578081708937; Fri, 03 Jan 2020 12:01:48 -0800 (PST) Received: from localhost.localdomain ([188.25.254.226]) by smtp.gmail.com with ESMTPSA id e12sm60998154wrn.56.2020.01.03.12.01.47 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 03 Jan 2020 12:01:48 -0800 (PST) From: Vladimir Oltean To: davem@davemloft.net, jakub.kicinski@netronome.com, linux@armlinux.org.uk, andrew@lunn.ch, f.fainelli@gmail.com, vivien.didelot@gmail.com Cc: alexandru.marginean@nxp.com, claudiu.manoil@nxp.com, xiaoliang.yang_1@nxp.com, yangbo.lu@nxp.com, netdev@vger.kernel.org, alexandre.belloni@bootlin.com, horatiu.vultur@microchip.com, UNGLinuxDriver@microchip.com, Vladimir Oltean Subject: [PATCH v4 net-next 3/9] net: phylink: add support for polling MAC PCS Date: Fri, 3 Jan 2020 22:01:21 +0200 Message-Id: <20200103200127.6331-4-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200103200127.6331-1-olteanv@gmail.com> References: <20200103200127.6331-1-olteanv@gmail.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Vladimir Oltean Some MAC PCS blocks are unable to provide interrupts when their status changes. As we already have support in phylink for polling status, use this to provide a hook for MACs to enable polling mode. The patch idea was picked up from Russell King's suggestion on the macb phylink patch thread here [0] but the implementation was changed. Instead of introducing a new phylink_start_poll() function, which would make the implementation cumbersome for common PHYLINK implementations for multiple types of devices, like DSA, just add a boolean property to the phylink_config structure, which is just as backwards-compatible. https://lkml.org/lkml/2019/12/16/603 Suggested-by: Russell King Signed-off-by: Vladimir Oltean --- Changes in v4: - None. Documentation/networking/sfp-phylink.rst | 3 ++- drivers/net/phy/phylink.c | 3 ++- include/linux/phylink.h | 2 ++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Documentation/networking/sfp-phylink.rst b/Documentation/networking/sfp-phylink.rst index a5e00a159d21..d753a309f9d1 100644 --- a/Documentation/networking/sfp-phylink.rst +++ b/Documentation/networking/sfp-phylink.rst @@ -251,7 +251,8 @@ this documentation. phylink_mac_change(priv->phylink, link_is_up); where ``link_is_up`` is true if the link is currently up or false - otherwise. + otherwise. If a MAC is unable to provide these interrupts, then + it should set ``priv->phylink_config.pcs_poll = true;`` in step 9. 11. Verify that the driver does not call:: diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index c19cbcf183e6..73a01ea5fc55 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -1021,7 +1021,8 @@ void phylink_start(struct phylink *pl) if (irq <= 0) mod_timer(&pl->link_poll, jiffies + HZ); } - if (pl->cfg_link_an_mode == MLO_AN_FIXED && pl->get_fixed_state) + if ((pl->cfg_link_an_mode == MLO_AN_FIXED && pl->get_fixed_state) || + pl->config->pcs_poll) mod_timer(&pl->link_poll, jiffies + HZ); if (pl->phydev) phy_start(pl->phydev); diff --git a/include/linux/phylink.h b/include/linux/phylink.h index fed5488e3c75..523209e70947 100644 --- a/include/linux/phylink.h +++ b/include/linux/phylink.h @@ -63,10 +63,12 @@ enum phylink_op_type { * struct phylink_config - PHYLINK configuration structure * @dev: a pointer to a struct device associated with the MAC * @type: operation type of PHYLINK instance + * @pcs_poll: MAC PCS cannot provide link change interrupt */ struct phylink_config { struct device *dev; enum phylink_op_type type; + bool pcs_poll; }; /** From patchwork Fri Jan 3 20:01:22 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 1217419 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 (no SPF record) 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="EA4f5nm6"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 47qG5H559Qz9sR1 for ; Sat, 4 Jan 2020 07:01:55 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728718AbgACUBy (ORCPT ); Fri, 3 Jan 2020 15:01:54 -0500 Received: from mail-wr1-f67.google.com ([209.85.221.67]:42712 "EHLO mail-wr1-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728691AbgACUBv (ORCPT ); Fri, 3 Jan 2020 15:01:51 -0500 Received: by mail-wr1-f67.google.com with SMTP id q6so43388163wro.9 for ; Fri, 03 Jan 2020 12:01:50 -0800 (PST) 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=LZJqYBX7CDzgsniXXIG3bnkLFsj6LYm4IJNFXgIYNOQ=; b=EA4f5nm6sCGHSmEqbMN747ukVVRzmghXo+eDqYJaSjgsMZvyxmgz2ftFU5t4i2svyA n7lfc4d+0gltQNAusjzMHxhcTSE3M0qxuP137c0V2Q0u1bMD9sh8OKsPkOi11VHSxXwe cxuHB/VKXU85JdwE7oEtaqIxHSUZXrY3e4R7VYqT6B1BQCer/s4Z3O8xNrKGM/H7qbNe /6Hsp+/6jVXYO/6AeTKdbBJpnHqWXr4iU5u8LLClUnmVQzj2LrmY3d6LUpicq3k+StfV uP3d5DQXw0NPPsV0l3KIXkq1aRPqTUAa9E1+I+4IqLa5v9d9c2+UPmYFpVB8Mp79+4Di Ngyg== 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=LZJqYBX7CDzgsniXXIG3bnkLFsj6LYm4IJNFXgIYNOQ=; b=rwgsPs75I/SLt4bM71K5iOfHuk5B6SH+R7g2jtLIbjOv1ThE3hudVgsQusWOXXcSj0 DKo2spPqhEwma/u85IvYhxjkolN46feDLEEzJGw6ECAxgmPOtPOOH1Gx2HWb9O0XVHm+ Mj3eJD0A2Qgw62XKTxRDNajQ7A9YV5U+KOfB5UfcBL46gbEOehBLtVAZUzMBNcX2vM9z bQaP0rgddIaQI+HCYS+y4RMmNirM/NOpCiCKZV28HTQX9VuRmqcL80cFO2W+fG3Yq3SZ ZRgjgD4bYAEykaRfVsI0AT2mn5+UsffUVVmwlhITClEbRT5eMAvTcHF6hZjiLWqX5G/2 uWrA== X-Gm-Message-State: APjAAAXxV1K1K4b2SOWQEfcqV8ixd3UyPEcmutTrOpYylmVwgABLUcXj DrQtr4Q9kKnGnASTq1Zqzmc= X-Google-Smtp-Source: APXvYqypOWy75U8rY1dJPKUGwnUzLE8YvBO41hZ7yQCs3YkcmX8OHOesTXJfekjb8vusTEa4uI3UZQ== X-Received: by 2002:adf:df90:: with SMTP id z16mr95207331wrl.273.1578081710306; Fri, 03 Jan 2020 12:01:50 -0800 (PST) Received: from localhost.localdomain ([188.25.254.226]) by smtp.gmail.com with ESMTPSA id e12sm60998154wrn.56.2020.01.03.12.01.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 03 Jan 2020 12:01:49 -0800 (PST) From: Vladimir Oltean To: davem@davemloft.net, jakub.kicinski@netronome.com, linux@armlinux.org.uk, andrew@lunn.ch, f.fainelli@gmail.com, vivien.didelot@gmail.com Cc: alexandru.marginean@nxp.com, claudiu.manoil@nxp.com, xiaoliang.yang_1@nxp.com, yangbo.lu@nxp.com, netdev@vger.kernel.org, alexandre.belloni@bootlin.com, horatiu.vultur@microchip.com, UNGLinuxDriver@microchip.com, Vladimir Oltean Subject: [PATCH v4 net-next 4/9] net: dsa: Pass pcs_poll flag from driver to PHYLINK Date: Fri, 3 Jan 2020 22:01:22 +0200 Message-Id: <20200103200127.6331-5-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200103200127.6331-1-olteanv@gmail.com> References: <20200103200127.6331-1-olteanv@gmail.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Vladimir Oltean The DSA drivers that implement .phylink_mac_link_state should normally register an interrupt for the PCS, from which they should call phylink_mac_change(). However not all switches implement this, and those who don't should set this flag in dsa_switch in the .setup callback, so that PHYLINK will poll for a few ms until the in-band AN link timer expires and the PCS state settles. Signed-off-by: Vladimir Oltean --- Changes in v4: - None. include/net/dsa.h | 5 +++++ net/dsa/port.c | 1 + 2 files changed, 6 insertions(+) diff --git a/include/net/dsa.h b/include/net/dsa.h index da5578db228e..dab1c4415f1e 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -283,6 +283,11 @@ struct dsa_switch { */ bool vlan_filtering; + /* MAC PCS does not provide link state change interrupt, and requires + * polling. Flag passed on to PHYLINK. + */ + bool pcs_poll; + size_t num_ports; }; diff --git a/net/dsa/port.c b/net/dsa/port.c index ffb5601f7ed6..774facb8d547 100644 --- a/net/dsa/port.c +++ b/net/dsa/port.c @@ -599,6 +599,7 @@ static int dsa_port_phylink_register(struct dsa_port *dp) dp->pl_config.dev = ds->dev; dp->pl_config.type = PHYLINK_DEV; + dp->pl_config.pcs_poll = ds->pcs_poll; dp->pl = phylink_create(&dp->pl_config, of_fwnode_handle(port_dn), mode, &dsa_port_phylink_mac_ops); From patchwork Fri Jan 3 20:01:23 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 1217421 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 (no SPF record) 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="bNr+BnZ7"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 47qG5L5fQZz9sR4 for ; Sat, 4 Jan 2020 07:01:58 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728726AbgACUB4 (ORCPT ); Fri, 3 Jan 2020 15:01:56 -0500 Received: from mail-wr1-f66.google.com ([209.85.221.66]:36067 "EHLO mail-wr1-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728686AbgACUBy (ORCPT ); Fri, 3 Jan 2020 15:01:54 -0500 Received: by mail-wr1-f66.google.com with SMTP id z3so43507967wru.3 for ; Fri, 03 Jan 2020 12:01:52 -0800 (PST) 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=sGF4DcIFoaC10o25i9rQ39i80YHF4sJeHOd9v+yZqKM=; b=bNr+BnZ75MSPhe7SFjFvYYxsqN4OZ4RvjUH7dc/MpyDIOro/SUvxgkLv407/iFoqIT pyF0W+s8jB36nNTGLjCXBUgP204CdeVX53Acq+DdLiLtsHynzaNlFFxFjDJTiDvHvOt+ dxr0CTrt1poMAfNVEP0RapvpZFZ4Eh5YlQnMYhrRbh0T2jcRAx6M/aIGzLKZ8wedPE+z +4fpl55DX5pcNmvjZHibRoLsq+D9LvzhjsSpvMfhQC4zGHXVnNW9TrorFbkPB8GT/PUX lpbu2bn+n/o7PeElXQRd2/089xIisKWs/vZftoBq8tm5/kPFnrfvdPBCt56ycZFaVhnO Rmaw== 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=sGF4DcIFoaC10o25i9rQ39i80YHF4sJeHOd9v+yZqKM=; b=tPcLdi8bya0zQQS96CDh8dn/jQiAWdlNIZMzb/cWqtd13G7WHT1zb9+6NlB0xlp46H Gm3LSBqKRe/z0fZobw1n4uj1ThsDOX6XKQew3D+qOU+c/uXRWrhDsHlMtPHgX6vVeGUJ j3r0uyuTT8K3jv9ErUBTLIj0mpygMIRFyh6GHXPUPNtSpYd8gzkP0zk5TOWjXNwcsUMM m0FyzWmtBVh8Dm1zQ+PxPl0FNy+Fn6RW25dXU4TFBNVpB+rQQaQxFO9DDyc9j27QM1Zb xcWPhU1RPVAH2iJSCwHE+HPGxITunoj8wztgjlpYykAbCnUQW5iNJzTtX4xd67hN6gZh bqdg== X-Gm-Message-State: APjAAAU4utOeBOEBrShvr08+06wQesN62Ldo+BDVetqVmfNSUE8TOAKj gmBc8XSi8R3QgqrgXrr7Jlg= X-Google-Smtp-Source: APXvYqwBZbn2ysOApqZvg5iKkHf/AFBNQXwxSyRM4FxUhi4qmJ9RYFdRtIOOCsBDfSYM+Tn00QP3sA== X-Received: by 2002:adf:fc03:: with SMTP id i3mr91708122wrr.306.1578081711749; Fri, 03 Jan 2020 12:01:51 -0800 (PST) Received: from localhost.localdomain ([188.25.254.226]) by smtp.gmail.com with ESMTPSA id e12sm60998154wrn.56.2020.01.03.12.01.50 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 03 Jan 2020 12:01:51 -0800 (PST) From: Vladimir Oltean To: davem@davemloft.net, jakub.kicinski@netronome.com, linux@armlinux.org.uk, andrew@lunn.ch, f.fainelli@gmail.com, vivien.didelot@gmail.com Cc: alexandru.marginean@nxp.com, claudiu.manoil@nxp.com, xiaoliang.yang_1@nxp.com, yangbo.lu@nxp.com, netdev@vger.kernel.org, alexandre.belloni@bootlin.com, horatiu.vultur@microchip.com, UNGLinuxDriver@microchip.com, Vladimir Oltean Subject: [PATCH v4 net-next 5/9] enetc: Make MDIO accessors more generic and export to include/linux/fsl Date: Fri, 3 Jan 2020 22:01:23 +0200 Message-Id: <20200103200127.6331-6-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200103200127.6331-1-olteanv@gmail.com> References: <20200103200127.6331-1-olteanv@gmail.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Claudiu Manoil Within the LS1028A SoC, the register map for the ENETC MDIO controller is instantiated a few times: for the central (external) MDIO controller, for the internal bus of each standalone ENETC port, and for the internal bus of the Felix switch. Refactoring is needed to support multiple MDIO buses from multiple drivers. The enetc_hw structure is made an opaque type and a smaller enetc_mdio_priv is created. 'mdio_base' - MDIO registers base address - is being parameterized, to be able to work with different MDIO register bases. The ENETC MDIO bus operations are exported from the fsl-enetc-mdio kernel object, the same that registers the central MDIO controller (the dedicated PF). The ENETC main driver has been changed to select it, and use its exported helpers to further register its private MDIO bus. The DSA Felix driver will do the same. Signed-off-by: Claudiu Manoil Signed-off-by: Vladimir Oltean --- Changes in v4: - None. Changes in v3: - Removed enetc_mdio.o from fsl-enetc.o, which caused a build error in the previous series, because enetc_mdio_read and enetc_mdio_write were exported from 2 different kernel objects. - Some associated code movement from enetc_mdio.c to enetc_pf.c drivers/net/ethernet/freescale/enetc/Kconfig | 1 + drivers/net/ethernet/freescale/enetc/Makefile | 2 +- .../net/ethernet/freescale/enetc/enetc_hw.h | 1 + .../net/ethernet/freescale/enetc/enetc_mdio.c | 110 +++++++----------- .../net/ethernet/freescale/enetc/enetc_mdio.h | 12 -- .../ethernet/freescale/enetc/enetc_pci_mdio.c | 43 ++++--- .../net/ethernet/freescale/enetc/enetc_pf.c | 47 ++++++++ .../net/ethernet/freescale/enetc/enetc_pf.h | 4 - include/linux/fsl/enetc_mdio.h | 55 +++++++++ 9 files changed, 176 insertions(+), 99 deletions(-) delete mode 100644 drivers/net/ethernet/freescale/enetc/enetc_mdio.h create mode 100644 include/linux/fsl/enetc_mdio.h diff --git a/drivers/net/ethernet/freescale/enetc/Kconfig b/drivers/net/ethernet/freescale/enetc/Kconfig index edad4ca46327..fe942de19597 100644 --- a/drivers/net/ethernet/freescale/enetc/Kconfig +++ b/drivers/net/ethernet/freescale/enetc/Kconfig @@ -2,6 +2,7 @@ config FSL_ENETC tristate "ENETC PF driver" depends on PCI && PCI_MSI && (ARCH_LAYERSCAPE || COMPILE_TEST) + select FSL_ENETC_MDIO select PHYLIB help This driver supports NXP ENETC gigabit ethernet controller PCIe diff --git a/drivers/net/ethernet/freescale/enetc/Makefile b/drivers/net/ethernet/freescale/enetc/Makefile index d0db33e5b6b7..74f7ac253b8b 100644 --- a/drivers/net/ethernet/freescale/enetc/Makefile +++ b/drivers/net/ethernet/freescale/enetc/Makefile @@ -3,7 +3,7 @@ common-objs := enetc.o enetc_cbdr.o enetc_ethtool.o obj-$(CONFIG_FSL_ENETC) += fsl-enetc.o -fsl-enetc-y := enetc_pf.o enetc_mdio.o $(common-objs) +fsl-enetc-y := enetc_pf.o $(common-objs) fsl-enetc-$(CONFIG_PCI_IOV) += enetc_msg.o fsl-enetc-$(CONFIG_FSL_ENETC_QOS) += enetc_qos.o diff --git a/drivers/net/ethernet/freescale/enetc/enetc_hw.h b/drivers/net/ethernet/freescale/enetc/enetc_hw.h index 8375cd886dba..62554f28ce07 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc_hw.h +++ b/drivers/net/ethernet/freescale/enetc/enetc_hw.h @@ -200,6 +200,7 @@ enum enetc_bdr_type {TX, RX}; #define ENETC_PFPMR 0x1900 #define ENETC_PFPMR_PMACE BIT(1) #define ENETC_PFPMR_MWLM BIT(0) +#define ENETC_EMDIO_BASE 0x1c00 #define ENETC_PSIUMHFR0(n, err) (((err) ? 0x1d08 : 0x1d00) + (n) * 0x10) #define ENETC_PSIUMHFR1(n) (0x1d04 + (n) * 0x10) #define ENETC_PSIMMHFR0(n, err) (((err) ? 0x1d00 : 0x1d08) + (n) * 0x10) diff --git a/drivers/net/ethernet/freescale/enetc/enetc_mdio.c b/drivers/net/ethernet/freescale/enetc/enetc_mdio.c index 149883c8f0b8..18c68e048d43 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc_mdio.c +++ b/drivers/net/ethernet/freescale/enetc/enetc_mdio.c @@ -1,24 +1,35 @@ // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) /* Copyright 2019 NXP */ +#include #include #include #include #include -#include "enetc_mdio.h" +#include "enetc_pf.h" -#define ENETC_MDIO_REG_OFFSET 0x1c00 #define ENETC_MDIO_CFG 0x0 /* MDIO configuration and status */ #define ENETC_MDIO_CTL 0x4 /* MDIO control */ #define ENETC_MDIO_DATA 0x8 /* MDIO data */ #define ENETC_MDIO_ADDR 0xc /* MDIO address */ -#define enetc_mdio_rd(hw, off) \ - enetc_port_rd(hw, ENETC_##off + ENETC_MDIO_REG_OFFSET) -#define enetc_mdio_wr(hw, off, val) \ - enetc_port_wr(hw, ENETC_##off + ENETC_MDIO_REG_OFFSET, val) -#define enetc_mdio_rd_reg(off) enetc_mdio_rd(hw, off) +static inline u32 _enetc_mdio_rd(struct enetc_mdio_priv *mdio_priv, int off) +{ + return enetc_port_rd(mdio_priv->hw, mdio_priv->mdio_base + off); +} + +static inline void _enetc_mdio_wr(struct enetc_mdio_priv *mdio_priv, int off, + u32 val) +{ + enetc_port_wr(mdio_priv->hw, mdio_priv->mdio_base + off, val); +} + +#define enetc_mdio_rd(mdio_priv, off) \ + _enetc_mdio_rd(mdio_priv, ENETC_##off) +#define enetc_mdio_wr(mdio_priv, off, val) \ + _enetc_mdio_wr(mdio_priv, ENETC_##off, val) +#define enetc_mdio_rd_reg(off) enetc_mdio_rd(mdio_priv, off) #define ENETC_MDC_DIV 258 @@ -35,7 +46,7 @@ #define MDIO_DATA(x) ((x) & 0xffff) #define TIMEOUT 1000 -static int enetc_mdio_wait_complete(struct enetc_hw *hw) +static int enetc_mdio_wait_complete(struct enetc_mdio_priv *mdio_priv) { u32 val; @@ -46,7 +57,6 @@ static int enetc_mdio_wait_complete(struct enetc_hw *hw) int enetc_mdio_write(struct mii_bus *bus, int phy_id, int regnum, u16 value) { struct enetc_mdio_priv *mdio_priv = bus->priv; - struct enetc_hw *hw = mdio_priv->hw; u32 mdio_ctl, mdio_cfg; u16 dev_addr; int ret; @@ -61,39 +71,39 @@ int enetc_mdio_write(struct mii_bus *bus, int phy_id, int regnum, u16 value) mdio_cfg &= ~MDIO_CFG_ENC45; } - enetc_mdio_wr(hw, MDIO_CFG, mdio_cfg); + enetc_mdio_wr(mdio_priv, MDIO_CFG, mdio_cfg); - ret = enetc_mdio_wait_complete(hw); + ret = enetc_mdio_wait_complete(mdio_priv); if (ret) return ret; /* set port and dev addr */ mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr); - enetc_mdio_wr(hw, MDIO_CTL, mdio_ctl); + enetc_mdio_wr(mdio_priv, MDIO_CTL, mdio_ctl); /* set the register address */ if (regnum & MII_ADDR_C45) { - enetc_mdio_wr(hw, MDIO_ADDR, regnum & 0xffff); + enetc_mdio_wr(mdio_priv, MDIO_ADDR, regnum & 0xffff); - ret = enetc_mdio_wait_complete(hw); + ret = enetc_mdio_wait_complete(mdio_priv); if (ret) return ret; } /* write the value */ - enetc_mdio_wr(hw, MDIO_DATA, MDIO_DATA(value)); + enetc_mdio_wr(mdio_priv, MDIO_DATA, MDIO_DATA(value)); - ret = enetc_mdio_wait_complete(hw); + ret = enetc_mdio_wait_complete(mdio_priv); if (ret) return ret; return 0; } +EXPORT_SYMBOL_GPL(enetc_mdio_write); int enetc_mdio_read(struct mii_bus *bus, int phy_id, int regnum) { struct enetc_mdio_priv *mdio_priv = bus->priv; - struct enetc_hw *hw = mdio_priv->hw; u32 mdio_ctl, mdio_cfg; u16 dev_addr, value; int ret; @@ -107,86 +117,56 @@ int enetc_mdio_read(struct mii_bus *bus, int phy_id, int regnum) mdio_cfg &= ~MDIO_CFG_ENC45; } - enetc_mdio_wr(hw, MDIO_CFG, mdio_cfg); + enetc_mdio_wr(mdio_priv, MDIO_CFG, mdio_cfg); - ret = enetc_mdio_wait_complete(hw); + ret = enetc_mdio_wait_complete(mdio_priv); if (ret) return ret; /* set port and device addr */ mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr); - enetc_mdio_wr(hw, MDIO_CTL, mdio_ctl); + enetc_mdio_wr(mdio_priv, MDIO_CTL, mdio_ctl); /* set the register address */ if (regnum & MII_ADDR_C45) { - enetc_mdio_wr(hw, MDIO_ADDR, regnum & 0xffff); + enetc_mdio_wr(mdio_priv, MDIO_ADDR, regnum & 0xffff); - ret = enetc_mdio_wait_complete(hw); + ret = enetc_mdio_wait_complete(mdio_priv); if (ret) return ret; } /* initiate the read */ - enetc_mdio_wr(hw, MDIO_CTL, mdio_ctl | MDIO_CTL_READ); + enetc_mdio_wr(mdio_priv, MDIO_CTL, mdio_ctl | MDIO_CTL_READ); - ret = enetc_mdio_wait_complete(hw); + ret = enetc_mdio_wait_complete(mdio_priv); if (ret) return ret; /* return all Fs if nothing was there */ - if (enetc_mdio_rd(hw, MDIO_CFG) & MDIO_CFG_RD_ER) { + if (enetc_mdio_rd(mdio_priv, MDIO_CFG) & MDIO_CFG_RD_ER) { dev_dbg(&bus->dev, "Error while reading PHY%d reg at %d.%hhu\n", phy_id, dev_addr, regnum); return 0xffff; } - value = enetc_mdio_rd(hw, MDIO_DATA) & 0xffff; + value = enetc_mdio_rd(mdio_priv, MDIO_DATA) & 0xffff; return value; } +EXPORT_SYMBOL_GPL(enetc_mdio_read); -int enetc_mdio_probe(struct enetc_pf *pf) +struct enetc_hw *enetc_hw_alloc(struct device *dev, void __iomem *port_regs) { - struct device *dev = &pf->si->pdev->dev; - struct enetc_mdio_priv *mdio_priv; - struct device_node *np; - struct mii_bus *bus; - int err; - - bus = devm_mdiobus_alloc_size(dev, sizeof(*mdio_priv)); - if (!bus) - return -ENOMEM; - - bus->name = "Freescale ENETC MDIO Bus"; - bus->read = enetc_mdio_read; - bus->write = enetc_mdio_write; - bus->parent = dev; - mdio_priv = bus->priv; - mdio_priv->hw = &pf->si->hw; - snprintf(bus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev)); - - np = of_get_child_by_name(dev->of_node, "mdio"); - if (!np) { - dev_err(dev, "MDIO node missing\n"); - return -EINVAL; - } - - err = of_mdiobus_register(bus, np); - if (err) { - of_node_put(np); - dev_err(dev, "cannot register MDIO bus\n"); - return err; - } + struct enetc_hw *hw; - of_node_put(np); - pf->mdio = bus; + hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL); + if (!hw) + return ERR_PTR(-ENOMEM); - return 0; -} + hw->port = port_regs; -void enetc_mdio_remove(struct enetc_pf *pf) -{ - if (pf->mdio) - mdiobus_unregister(pf->mdio); + return hw; } +EXPORT_SYMBOL_GPL(enetc_hw_alloc); diff --git a/drivers/net/ethernet/freescale/enetc/enetc_mdio.h b/drivers/net/ethernet/freescale/enetc/enetc_mdio.h deleted file mode 100644 index 60c9a3889824..000000000000 --- a/drivers/net/ethernet/freescale/enetc/enetc_mdio.h +++ /dev/null @@ -1,12 +0,0 @@ -/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */ -/* Copyright 2019 NXP */ - -#include -#include "enetc_pf.h" - -struct enetc_mdio_priv { - struct enetc_hw *hw; -}; - -int enetc_mdio_write(struct mii_bus *bus, int phy_id, int regnum, u16 value); -int enetc_mdio_read(struct mii_bus *bus, int phy_id, int regnum); diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pci_mdio.c b/drivers/net/ethernet/freescale/enetc/enetc_pci_mdio.c index fbd41ce01f06..87c0e969da40 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc_pci_mdio.c +++ b/drivers/net/ethernet/freescale/enetc/enetc_pci_mdio.c @@ -1,7 +1,8 @@ // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) /* Copyright 2019 NXP */ +#include #include -#include "enetc_mdio.h" +#include "enetc_pf.h" #define ENETC_MDIO_DEV_ID 0xee01 #define ENETC_MDIO_DEV_NAME "FSL PCIe IE Central MDIO" @@ -13,17 +14,29 @@ static int enetc_pci_mdio_probe(struct pci_dev *pdev, { struct enetc_mdio_priv *mdio_priv; struct device *dev = &pdev->dev; + void __iomem *port_regs; struct enetc_hw *hw; struct mii_bus *bus; int err; - hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL); - if (!hw) - return -ENOMEM; + port_regs = pci_iomap(pdev, 0, 0); + if (!port_regs) { + dev_err(dev, "iomap failed\n"); + err = -ENXIO; + goto err_ioremap; + } + + hw = enetc_hw_alloc(dev, port_regs); + if (IS_ERR(enetc_hw_alloc)) { + err = PTR_ERR(hw); + goto err_hw_alloc; + } bus = devm_mdiobus_alloc_size(dev, sizeof(*mdio_priv)); - if (!bus) - return -ENOMEM; + if (!bus) { + err = -ENOMEM; + goto err_mdiobus_alloc; + } bus->name = ENETC_MDIO_BUS_NAME; bus->read = enetc_mdio_read; @@ -31,13 +44,14 @@ static int enetc_pci_mdio_probe(struct pci_dev *pdev, bus->parent = dev; mdio_priv = bus->priv; mdio_priv->hw = hw; + mdio_priv->mdio_base = ENETC_EMDIO_BASE; snprintf(bus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev)); pcie_flr(pdev); err = pci_enable_device_mem(pdev); if (err) { dev_err(dev, "device enable failed\n"); - return err; + goto err_pci_enable; } err = pci_request_region(pdev, 0, KBUILD_MODNAME); @@ -46,13 +60,6 @@ static int enetc_pci_mdio_probe(struct pci_dev *pdev, goto err_pci_mem_reg; } - hw->port = pci_iomap(pdev, 0, 0); - if (!hw->port) { - err = -ENXIO; - dev_err(dev, "iomap failed\n"); - goto err_ioremap; - } - err = of_mdiobus_register(bus, dev->of_node); if (err) goto err_mdiobus_reg; @@ -62,12 +69,14 @@ static int enetc_pci_mdio_probe(struct pci_dev *pdev, return 0; err_mdiobus_reg: - iounmap(mdio_priv->hw->port); -err_ioremap: pci_release_mem_regions(pdev); err_pci_mem_reg: pci_disable_device(pdev); - +err_pci_enable: +err_mdiobus_alloc: + iounmap(port_regs); +err_hw_alloc: +err_ioremap: return err; } diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.c b/drivers/net/ethernet/freescale/enetc/enetc_pf.c index e7482d483b28..fc0d7d99e9a1 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c +++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c @@ -2,6 +2,7 @@ /* Copyright 2017-2019 NXP */ #include +#include #include #include #include "enetc_pf.h" @@ -749,6 +750,52 @@ static void enetc_pf_netdev_setup(struct enetc_si *si, struct net_device *ndev, enetc_get_primary_mac_addr(&si->hw, ndev->dev_addr); } +static int enetc_mdio_probe(struct enetc_pf *pf) +{ + struct device *dev = &pf->si->pdev->dev; + struct enetc_mdio_priv *mdio_priv; + struct device_node *np; + struct mii_bus *bus; + int err; + + bus = devm_mdiobus_alloc_size(dev, sizeof(*mdio_priv)); + if (!bus) + return -ENOMEM; + + bus->name = "Freescale ENETC MDIO Bus"; + bus->read = enetc_mdio_read; + bus->write = enetc_mdio_write; + bus->parent = dev; + mdio_priv = bus->priv; + mdio_priv->hw = &pf->si->hw; + mdio_priv->mdio_base = ENETC_EMDIO_BASE; + snprintf(bus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev)); + + np = of_get_child_by_name(dev->of_node, "mdio"); + if (!np) { + dev_err(dev, "MDIO node missing\n"); + return -EINVAL; + } + + err = of_mdiobus_register(bus, np); + if (err) { + of_node_put(np); + dev_err(dev, "cannot register MDIO bus\n"); + return err; + } + + of_node_put(np); + pf->mdio = bus; + + return 0; +} + +static void enetc_mdio_remove(struct enetc_pf *pf) +{ + if (pf->mdio) + mdiobus_unregister(pf->mdio); +} + static int enetc_of_get_phy(struct enetc_ndev_priv *priv) { struct enetc_pf *pf = enetc_si_priv(priv->si); diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.h b/drivers/net/ethernet/freescale/enetc/enetc_pf.h index 10dd1b53bb08..59e65a6f6c3e 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc_pf.h +++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.h @@ -49,7 +49,3 @@ struct enetc_pf { int enetc_msg_psi_init(struct enetc_pf *pf); void enetc_msg_psi_free(struct enetc_pf *pf); void enetc_msg_handle_rxmsg(struct enetc_pf *pf, int mbox_id, u16 *status); - -/* MDIO */ -int enetc_mdio_probe(struct enetc_pf *pf); -void enetc_mdio_remove(struct enetc_pf *pf); diff --git a/include/linux/fsl/enetc_mdio.h b/include/linux/fsl/enetc_mdio.h new file mode 100644 index 000000000000..4875dd38af7e --- /dev/null +++ b/include/linux/fsl/enetc_mdio.h @@ -0,0 +1,55 @@ +/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */ +/* Copyright 2019 NXP */ + +#ifndef _FSL_ENETC_MDIO_H_ +#define _FSL_ENETC_MDIO_H_ + +#include + +/* PCS registers */ +#define ENETC_PCS_LINK_TIMER1 0x12 +#define ENETC_PCS_LINK_TIMER1_VAL 0x06a0 +#define ENETC_PCS_LINK_TIMER2 0x13 +#define ENETC_PCS_LINK_TIMER2_VAL 0x0003 +#define ENETC_PCS_IF_MODE 0x14 +#define ENETC_PCS_IF_MODE_SGMII_EN BIT(0) +#define ENETC_PCS_IF_MODE_USE_SGMII_AN BIT(1) +#define ENETC_PCS_IF_MODE_SGMII_SPEED(x) (((x) << 2) & GENMASK(3, 2)) + +/* Not a mistake, the SerDes PLL needs to be set at 3.125 GHz by Reset + * Configuration Word (RCW, outside Linux control) for 2.5G SGMII mode. The PCS + * still thinks it's at gigabit. + */ +enum enetc_pcs_speed { + ENETC_PCS_SPEED_10 = 0, + ENETC_PCS_SPEED_100 = 1, + ENETC_PCS_SPEED_1000 = 2, + ENETC_PCS_SPEED_2500 = 2, +}; + +struct enetc_hw; + +struct enetc_mdio_priv { + struct enetc_hw *hw; + int mdio_base; +}; + +#if IS_REACHABLE(CONFIG_FSL_ENETC_MDIO) + +int enetc_mdio_read(struct mii_bus *bus, int phy_id, int regnum); +int enetc_mdio_write(struct mii_bus *bus, int phy_id, int regnum, u16 value); +struct enetc_hw *enetc_hw_alloc(struct device *dev, void __iomem *port_regs); + +#else + +static inline int enetc_mdio_read(struct mii_bus *bus, int phy_id, int regnum) +{ return -EINVAL; } +static inline int enetc_mdio_write(struct mii_bus *bus, int phy_id, int regnum, + u16 value) +{ return -EINVAL; } +struct enetc_hw *enetc_hw_alloc(struct device *dev, void __iomem *port_regs) +{ return ERR_PTR(-EINVAL); } + +#endif + +#endif From patchwork Fri Jan 3 20:01:24 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 1217420 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 (no SPF record) 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="pEhyJTzG"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 47qG5K5bR4z9sR1 for ; Sat, 4 Jan 2020 07:01:57 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728733AbgACUB4 (ORCPT ); Fri, 3 Jan 2020 15:01:56 -0500 Received: from mail-wr1-f65.google.com ([209.85.221.65]:36069 "EHLO mail-wr1-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728704AbgACUBy (ORCPT ); Fri, 3 Jan 2020 15:01:54 -0500 Received: by mail-wr1-f65.google.com with SMTP id z3so43508031wru.3 for ; Fri, 03 Jan 2020 12:01:53 -0800 (PST) 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=zW7UsPAFTTe3uwNU8N1BaQOosPHalsZyFyP+jBr1OrY=; b=pEhyJTzGWP3CoFtGzcbv2MotKcZ9eFwUJJMyZGPsyWb9VricsoSRHJ3a81ZQZp9POM g25quR8VGltrlPKoP9V8nSvv5twtI3O65rRU5crNNfezZvt3OLanZYzYLUpwnV73o8X7 656tbyMXpMzn5ItBZOHtsc3zJuQ3/J7ACGX8T3VlY5U00KehzA/E44TayKpG/8bxlWdf 5iyKdsiVxB334HTwEDEZ5iwz4T3tB4fpxPypQcIGcA3IbDX+66bu+pIC+d0BWGEIlmNb TCNw/90AM0p91t2iTNh0JOlpqaBHGUz5fjPx46wbKOU7nAb6hCpJKXJVdbOkz+SkkLUk K+pA== 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=zW7UsPAFTTe3uwNU8N1BaQOosPHalsZyFyP+jBr1OrY=; b=DjHcSD6b3vKscE41xwMeg50SGg4Ax56XZuWH45/1Vtwh7koF8g+ero5/IbbZ0oKxJQ aSfkLaMXej4xfaJOev1ycbKLQySYmI5QAKTMYs+uXegK/Q2w0HRyfJsmqsthgdEfmtYA rJaZX6B3hSKs1fP/NYqkaW6/QLixcOa+DM6zfxswb0VrYe5+IWbbSGxpO3dtF7gKVgD/ Xw2FWPXkvOgIfn+a1CBcBOO1PP88UlekwDyIfYxyf8M3VW3povGOsMijsFPJicni9Tby rv7fW9W+R5q/yQUp2F7q8NI1k80nUpJaOFdfWJ5PJU5EHnwqglsVtCRU58qjWe2Ew8q6 tX5g== X-Gm-Message-State: APjAAAUFZ429CaHsloFWCuYRqmLcJEgvY81DumiyXcYobGcDrGOMml1I 2OxinYFpj2Wd5LyuJglzqGw= X-Google-Smtp-Source: APXvYqw0GpGcrBIHuZfl2+j2tJC0U97YLLLlEpV2c2Xt4yVCB4uFRPAdOF0m2rDimA1W9wVoqWGFVA== X-Received: by 2002:adf:fc4b:: with SMTP id e11mr23884690wrs.326.1578081713041; Fri, 03 Jan 2020 12:01:53 -0800 (PST) Received: from localhost.localdomain ([188.25.254.226]) by smtp.gmail.com with ESMTPSA id e12sm60998154wrn.56.2020.01.03.12.01.51 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 03 Jan 2020 12:01:52 -0800 (PST) From: Vladimir Oltean To: davem@davemloft.net, jakub.kicinski@netronome.com, linux@armlinux.org.uk, andrew@lunn.ch, f.fainelli@gmail.com, vivien.didelot@gmail.com Cc: alexandru.marginean@nxp.com, claudiu.manoil@nxp.com, xiaoliang.yang_1@nxp.com, yangbo.lu@nxp.com, netdev@vger.kernel.org, alexandre.belloni@bootlin.com, horatiu.vultur@microchip.com, UNGLinuxDriver@microchip.com, Vladimir Oltean Subject: [PATCH v4 net-next 6/9] enetc: Set MDIO_CFG_HOLD to the recommended value of 2 Date: Fri, 3 Jan 2020 22:01:24 +0200 Message-Id: <20200103200127.6331-7-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200103200127.6331-1-olteanv@gmail.com> References: <20200103200127.6331-1-olteanv@gmail.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Vladimir Oltean This increases the MDIO hold time to 5 enet_clk cycles from the previous value of 0. This is actually the out-of-reset value, that the driver was previously overwriting with 0. Zero worked for the external MDIO, but breaks communication with the internal MDIO buses on which the PCS of ENETC SI's and Felix switch are found. Signed-off-by: Vladimir Oltean --- Changes in v4: - None. Changes in v3: - None. drivers/net/ethernet/freescale/enetc/enetc_mdio.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/freescale/enetc/enetc_mdio.c b/drivers/net/ethernet/freescale/enetc/enetc_mdio.c index 18c68e048d43..48c32a171afa 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc_mdio.c +++ b/drivers/net/ethernet/freescale/enetc/enetc_mdio.c @@ -31,15 +31,19 @@ static inline void _enetc_mdio_wr(struct enetc_mdio_priv *mdio_priv, int off, _enetc_mdio_wr(mdio_priv, ENETC_##off, val) #define enetc_mdio_rd_reg(off) enetc_mdio_rd(mdio_priv, off) -#define ENETC_MDC_DIV 258 - #define MDIO_CFG_CLKDIV(x) ((((x) >> 1) & 0xff) << 8) #define MDIO_CFG_BSY BIT(0) #define MDIO_CFG_RD_ER BIT(1) +#define MDIO_CFG_HOLD(x) (((x) << 2) & GENMASK(4, 2)) #define MDIO_CFG_ENC45 BIT(6) /* external MDIO only - driven on neg MDC edge */ #define MDIO_CFG_NEG BIT(23) +#define ENETC_EMDIO_CFG \ + (MDIO_CFG_HOLD(2) | \ + MDIO_CFG_CLKDIV(258) | \ + MDIO_CFG_NEG) + #define MDIO_CTL_DEV_ADDR(x) ((x) & 0x1f) #define MDIO_CTL_PORT_ADDR(x) (((x) & 0x1f) << 5) #define MDIO_CTL_READ BIT(15) @@ -61,7 +65,7 @@ int enetc_mdio_write(struct mii_bus *bus, int phy_id, int regnum, u16 value) u16 dev_addr; int ret; - mdio_cfg = MDIO_CFG_CLKDIV(ENETC_MDC_DIV) | MDIO_CFG_NEG; + mdio_cfg = ENETC_EMDIO_CFG; if (regnum & MII_ADDR_C45) { dev_addr = (regnum >> 16) & 0x1f; mdio_cfg |= MDIO_CFG_ENC45; @@ -108,7 +112,7 @@ int enetc_mdio_read(struct mii_bus *bus, int phy_id, int regnum) u16 dev_addr, value; int ret; - mdio_cfg = MDIO_CFG_CLKDIV(ENETC_MDC_DIV) | MDIO_CFG_NEG; + mdio_cfg = ENETC_EMDIO_CFG; if (regnum & MII_ADDR_C45) { dev_addr = (regnum >> 16) & 0x1f; mdio_cfg |= MDIO_CFG_ENC45; From patchwork Fri Jan 3 20:01:25 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 1217422 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 (no SPF record) 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="iAr5gEJJ"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 47qG5P39Ghz9sPn for ; Sat, 4 Jan 2020 07:02:01 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728740AbgACUCA (ORCPT ); Fri, 3 Jan 2020 15:02:00 -0500 Received: from mail-wr1-f66.google.com ([209.85.221.66]:42721 "EHLO mail-wr1-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728720AbgACUBz (ORCPT ); Fri, 3 Jan 2020 15:01:55 -0500 Received: by mail-wr1-f66.google.com with SMTP id q6so43388363wro.9 for ; Fri, 03 Jan 2020 12:01:54 -0800 (PST) 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=533HndW8yiheJA6L+7iVNxbvS14a9dEIxpWE3iVywkw=; b=iAr5gEJJEbcIOjxjgdllSQ81vaD1T50E68CB5sBp1cOBGsmFu64fD4b1UZXo2ustwV nJuueFZirt1vINkDgLyvGGkQZyIAd9k1Yx0wUuiKZAlJEiDu8bNGdwQAYiAfs5PDWmU+ L5//Pcuke7R0nS5BYiiv3tXoD2VGcijaRcQzaCix/gLN76m16X7v3NOpEHuCGC35oKLh 3wzKP+nTRopkzYdAcbtTM8P1G20lqizdEmEa/74sekR9xiAv/t3mmGY0DLbpPE1M1LHG JulYPClxUM5vwrO+IZqu+cafafOgGPoIJpb1pI3JJvu88xuaiANF/iCmrLi08GdDQBQF oiKg== 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=533HndW8yiheJA6L+7iVNxbvS14a9dEIxpWE3iVywkw=; b=CnvxOMeWsxjPnR4aNNJT5VI8YSRUgBS6GlIZqBUUiIxBpIACUsak3MhXMJX9lbfqFR u8Cxcx1+mgicQz842CrcLKy5nw86SjAw+JxEC6F1R02nNgYOWQL7Fi0bMj3Tggc+6zZh t6xF3bUtiXylHX07P+/XxCXLwSA4qtQnldqGDk4XAePrdOhEiABZJm8ieEKdkV4gvyt8 vK6xapkvpkniVkqi1JVu6VqFBj3f4b7vDinnV5hP1DGGRVbDoFP8r8UsyM/fbI2n9AVj 78f0P2TBK1qPq5DcuRi5UPq8U9UN/Y7/ykDCik9DF2/Clqx+8cbXVyJN8zGXnVp3AJC8 kJ5A== X-Gm-Message-State: APjAAAUvR/nVx6vGVFPvvKQwzkM/fSldZoXyf9FPoLkHHW5qOuUpzZGb EZAHGm3M7tS9OZpcvINec5U= X-Google-Smtp-Source: APXvYqwaOCsBtSPtoIHeXACCDjCwhSGcwDD2cjgUhqClcZAXc+82cSEa2IF52m+dsQBvHTvbie0eCQ== X-Received: by 2002:adf:ec83:: with SMTP id z3mr88365337wrn.133.1578081714380; Fri, 03 Jan 2020 12:01:54 -0800 (PST) Received: from localhost.localdomain ([188.25.254.226]) by smtp.gmail.com with ESMTPSA id e12sm60998154wrn.56.2020.01.03.12.01.53 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 03 Jan 2020 12:01:53 -0800 (PST) From: Vladimir Oltean To: davem@davemloft.net, jakub.kicinski@netronome.com, linux@armlinux.org.uk, andrew@lunn.ch, f.fainelli@gmail.com, vivien.didelot@gmail.com Cc: alexandru.marginean@nxp.com, claudiu.manoil@nxp.com, xiaoliang.yang_1@nxp.com, yangbo.lu@nxp.com, netdev@vger.kernel.org, alexandre.belloni@bootlin.com, horatiu.vultur@microchip.com, UNGLinuxDriver@microchip.com, Vladimir Oltean Subject: [PATCH v4 net-next 7/9] net: mscc: ocelot: make phy_mode a member of the common struct ocelot_port Date: Fri, 3 Jan 2020 22:01:25 +0200 Message-Id: <20200103200127.6331-8-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200103200127.6331-1-olteanv@gmail.com> References: <20200103200127.6331-1-olteanv@gmail.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Vladimir Oltean The Ocelot switchdev driver and the Felix DSA one need it for different reasons. Felix (or at least the VSC9959 instantiation in NXP LS1028A) is integrated with the traditional NXP Layerscape PCS design which does not support runtime configuration of SerDes protocol. So it needs to pre-validate the phy-mode from the device tree and prevent PHYLINK from attempting to change it. For this, it needs to cache it in a private variable. Signed-off-by: Vladimir Oltean --- Changes in v4: - None. Changes in v3: - None. drivers/net/ethernet/mscc/ocelot.c | 7 ++++--- drivers/net/ethernet/mscc/ocelot.h | 1 - drivers/net/ethernet/mscc/ocelot_board.c | 4 ++-- include/soc/mscc/ocelot.h | 2 ++ 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c index 985b46d7e3d1..86d543ab1ab9 100644 --- a/drivers/net/ethernet/mscc/ocelot.c +++ b/drivers/net/ethernet/mscc/ocelot.c @@ -500,13 +500,14 @@ EXPORT_SYMBOL(ocelot_port_enable); static int ocelot_port_open(struct net_device *dev) { struct ocelot_port_private *priv = netdev_priv(dev); - struct ocelot *ocelot = priv->port.ocelot; + struct ocelot_port *ocelot_port = &priv->port; + struct ocelot *ocelot = ocelot_port->ocelot; int port = priv->chip_port; int err; if (priv->serdes) { err = phy_set_mode_ext(priv->serdes, PHY_MODE_ETHERNET, - priv->phy_mode); + ocelot_port->phy_mode); if (err) { netdev_err(dev, "Could not set mode of SerDes\n"); return err; @@ -514,7 +515,7 @@ static int ocelot_port_open(struct net_device *dev) } err = phy_connect_direct(dev, priv->phy, &ocelot_port_adjust_link, - priv->phy_mode); + ocelot_port->phy_mode); if (err) { netdev_err(dev, "Could not attach to PHY\n"); return err; diff --git a/drivers/net/ethernet/mscc/ocelot.h b/drivers/net/ethernet/mscc/ocelot.h index c259114c48fd..7b77d44ed7cf 100644 --- a/drivers/net/ethernet/mscc/ocelot.h +++ b/drivers/net/ethernet/mscc/ocelot.h @@ -68,7 +68,6 @@ struct ocelot_port_private { u8 vlan_aware; - phy_interface_t phy_mode; struct phy *serdes; struct ocelot_port_tc tc; diff --git a/drivers/net/ethernet/mscc/ocelot_board.c b/drivers/net/ethernet/mscc/ocelot_board.c index 2da8eee27e98..b38820849faa 100644 --- a/drivers/net/ethernet/mscc/ocelot_board.c +++ b/drivers/net/ethernet/mscc/ocelot_board.c @@ -402,9 +402,9 @@ static int mscc_ocelot_probe(struct platform_device *pdev) of_get_phy_mode(portnp, &phy_mode); - priv->phy_mode = phy_mode; + ocelot_port->phy_mode = phy_mode; - switch (priv->phy_mode) { + switch (ocelot_port->phy_mode) { case PHY_INTERFACE_MODE_NA: continue; case PHY_INTERFACE_MODE_SGMII: diff --git a/include/soc/mscc/ocelot.h b/include/soc/mscc/ocelot.h index 64cbbbe74a36..068f96b1a83e 100644 --- a/include/soc/mscc/ocelot.h +++ b/include/soc/mscc/ocelot.h @@ -420,6 +420,8 @@ struct ocelot_port { u8 ptp_cmd; struct sk_buff_head tx_skbs; u8 ts_id; + + phy_interface_t phy_mode; }; struct ocelot { From patchwork Fri Jan 3 20:01:26 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 1217423 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 (no SPF record) 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="Fa1Tf4p3"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 47qG5R22p7z9sR1 for ; Sat, 4 Jan 2020 07:02:03 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728744AbgACUCC (ORCPT ); Fri, 3 Jan 2020 15:02:02 -0500 Received: from mail-wm1-f68.google.com ([209.85.128.68]:36875 "EHLO mail-wm1-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728727AbgACUB5 (ORCPT ); Fri, 3 Jan 2020 15:01:57 -0500 Received: by mail-wm1-f68.google.com with SMTP id f129so9582053wmf.2 for ; Fri, 03 Jan 2020 12:01:56 -0800 (PST) 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=gOyWZHwWigvTYV6cjaZTxMUtX51yoCmVNOlPeIgPDrg=; b=Fa1Tf4p3tr6tUbl1jBemiqp4wqdi0po2K/RRuHK3223mh8s510FVnTHU/2OIhbcXFy R68qkOBUf2+f/s96We8jwD2qyts/wPDo/b7shLPbssqIUFYAsbw3q+eLdeGMfoNlF6hu wrQD2R73H/s/QM7CUtpStzGYUxaI70+2YmOlNH13xWO3eXvanlBy8+RiMA1pIrHH5yaM Xk33m8VylgJI/dTQrflEgplzB2ziHac025w9sw/aGqmX1YGNIaTadzofgEEnLH02inLH GrmY10eyr/nJUIeE7vL5UymXvB/e+J4cgfzmG30fAIoBo1ic0+yJd7blZuBXtzs4NTnw VHiQ== 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=gOyWZHwWigvTYV6cjaZTxMUtX51yoCmVNOlPeIgPDrg=; b=kUvjkz2mRAJfbbiZSjWFwXi76Hh0xh2uoUGJ6gXtGrIgvDO20CfPKr+1bh9gOuHke/ fTZgN0UfR6YV6Fxj8eR556OGZl7n7mRzRpF+1pZu3aIMI0Vo/BeeT/nj3VwTSgUSiKnF ZydPA+I5qE21nRWnLc7V0l6e8eZ6+pADuX0tgz9jr1rvw/DRplMWJ3ql2zffshbhvf9p S4u36BhgxXM/JhcfbLTyzwShuU58yZsxyz8uKwKmL22ZUlm6N20ZFerijg9GyJaSroWE GBV7yaNj6bsPa+50Rc69YlOeAjmQzvRkhRgx69VHJ4eTuDVvVKOY1tWUDHYvtgUYay6I CdyQ== X-Gm-Message-State: APjAAAU3GwSwps7x6oDro1gyRZmMgdbgwkeeDk2OWL/yB7hUkY9KyrnO aDekX5JQMCgsVsD6Y0qaih0= X-Google-Smtp-Source: APXvYqz1Oc2TC30gdhDBSyLa2Fe7ybv4FmqRA9cKxy89kihSbnGsxaWQVoqixDQIWhZJzgDWJZqk3A== X-Received: by 2002:a7b:c444:: with SMTP id l4mr20541305wmi.178.1578081715662; Fri, 03 Jan 2020 12:01:55 -0800 (PST) Received: from localhost.localdomain ([188.25.254.226]) by smtp.gmail.com with ESMTPSA id e12sm60998154wrn.56.2020.01.03.12.01.54 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 03 Jan 2020 12:01:55 -0800 (PST) From: Vladimir Oltean To: davem@davemloft.net, jakub.kicinski@netronome.com, linux@armlinux.org.uk, andrew@lunn.ch, f.fainelli@gmail.com, vivien.didelot@gmail.com Cc: alexandru.marginean@nxp.com, claudiu.manoil@nxp.com, xiaoliang.yang_1@nxp.com, yangbo.lu@nxp.com, netdev@vger.kernel.org, alexandre.belloni@bootlin.com, horatiu.vultur@microchip.com, UNGLinuxDriver@microchip.com, Vladimir Oltean Subject: [PATCH v4 net-next 8/9] net: mscc: ocelot: export ANA, DEV and QSYS registers to include/soc/mscc Date: Fri, 3 Jan 2020 22:01:26 +0200 Message-Id: <20200103200127.6331-9-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200103200127.6331-1-olteanv@gmail.com> References: <20200103200127.6331-1-olteanv@gmail.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Vladimir Oltean Since the Felix DSA driver is implementing its own PHYLINK instance due to SoC differences, it needs access to the few registers that are common, mainly for flow control. Signed-off-by: Vladimir Oltean --- Changes in v4: - None. Changes in v3: - None. drivers/net/ethernet/mscc/ocelot.h | 6 +++--- {drivers/net/ethernet => include/soc}/mscc/ocelot_ana.h | 0 {drivers/net/ethernet => include/soc}/mscc/ocelot_dev.h | 0 {drivers/net/ethernet => include/soc}/mscc/ocelot_qsys.h | 0 4 files changed, 3 insertions(+), 3 deletions(-) rename {drivers/net/ethernet => include/soc}/mscc/ocelot_ana.h (100%) rename {drivers/net/ethernet => include/soc}/mscc/ocelot_dev.h (100%) rename {drivers/net/ethernet => include/soc}/mscc/ocelot_qsys.h (100%) diff --git a/drivers/net/ethernet/mscc/ocelot.h b/drivers/net/ethernet/mscc/ocelot.h index 7b77d44ed7cf..04372ba72fec 100644 --- a/drivers/net/ethernet/mscc/ocelot.h +++ b/drivers/net/ethernet/mscc/ocelot.h @@ -18,11 +18,11 @@ #include #include +#include #include +#include +#include #include -#include "ocelot_ana.h" -#include "ocelot_dev.h" -#include "ocelot_qsys.h" #include "ocelot_rew.h" #include "ocelot_qs.h" #include "ocelot_tc.h" diff --git a/drivers/net/ethernet/mscc/ocelot_ana.h b/include/soc/mscc/ocelot_ana.h similarity index 100% rename from drivers/net/ethernet/mscc/ocelot_ana.h rename to include/soc/mscc/ocelot_ana.h diff --git a/drivers/net/ethernet/mscc/ocelot_dev.h b/include/soc/mscc/ocelot_dev.h similarity index 100% rename from drivers/net/ethernet/mscc/ocelot_dev.h rename to include/soc/mscc/ocelot_dev.h diff --git a/drivers/net/ethernet/mscc/ocelot_qsys.h b/include/soc/mscc/ocelot_qsys.h similarity index 100% rename from drivers/net/ethernet/mscc/ocelot_qsys.h rename to include/soc/mscc/ocelot_qsys.h From patchwork Fri Jan 3 20:01:27 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 1217424 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 (no SPF record) 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="hNGJ1OeP"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 47qG5T2Pj1z9sPn for ; Sat, 4 Jan 2020 07:02:05 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728748AbgACUCD (ORCPT ); Fri, 3 Jan 2020 15:02:03 -0500 Received: from mail-wr1-f68.google.com ([209.85.221.68]:36080 "EHLO mail-wr1-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728704AbgACUCC (ORCPT ); Fri, 3 Jan 2020 15:02:02 -0500 Received: by mail-wr1-f68.google.com with SMTP id z3so43508287wru.3 for ; Fri, 03 Jan 2020 12:01:58 -0800 (PST) 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=5CtBD6HrRGWPSaOvRiTM4utlZYNTXSkhefA4sgNJ4JU=; b=hNGJ1OePG5jI4KhZ4Vy804kmZ+BfMtOYm1dXeYIsiSj87e82eGe2Q/k+LLxmaABlJY 32WhdxrOZ12jd2zGhMxLuhyQJ0ki0Iz4BOU1id2lgQygJjC2FFEbNzk/TuTUew7iJEg/ 6T6V7Z0nw0qHVLhpcYV5ByNTCbchDivo6Fo7esNOucwJcBnDJjmjo+YdkWU0fNf66hQ7 eWpc653PE14hB3OhTtW+QAUiCoE3pUPfaKb9G4ej/aLDpQSPncFvHmYnbEh5fDLMh4x5 9aPyNrYp3IZ+k5WjBluS04zGJ+Uesnct09FyRClXOBauDd0d7UlJXYU2JUFBeH/zXYGW qIyg== 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=5CtBD6HrRGWPSaOvRiTM4utlZYNTXSkhefA4sgNJ4JU=; b=B1GjT2Xkp36Ozz+VCIdn6euqM5o9+6u6ZQriajndy7zL0sBc8LvTLIs04vJlQI/V89 1AZQnh1m2CGQvT5iLHhlgPIr0hMTNbQULGMOpTcU3+RtLC2YtXvEk/vhWcTFq9DYrC31 BmjsDbNcg+kUAZHa8TAmVE9fgudbZBkotl98/rpR9UP8LST4LB1/l8/oopaPAJl2W4CC 29x/dYZmkjIuNjPb9oRknxLrcy2JZi9PfhfmA4/dep81O5NiVmzzfbCBc5qqmERmQKpb b7/Sf2uizRFtymg+IpnukEAVZU2BXaqKmebJx72HJUiP9vlEg9RELIojzSgc3uCFJqcA VtRA== X-Gm-Message-State: APjAAAXRxU6o4I0WRqigWUsphwj8R7iQBQIcD4+SVe39F6yxtDvF6sk2 4FuHrb/bkiFjKH18bzI7YSc= X-Google-Smtp-Source: APXvYqze7yglVf0pRV/+dNg6oP552oF0QoQaupzXXDPj3xkQp7KKgCT0xiRRs+t3s9hDJLn31qyVcw== X-Received: by 2002:a5d:4b45:: with SMTP id w5mr93954582wrs.224.1578081717456; Fri, 03 Jan 2020 12:01:57 -0800 (PST) Received: from localhost.localdomain ([188.25.254.226]) by smtp.gmail.com with ESMTPSA id e12sm60998154wrn.56.2020.01.03.12.01.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 03 Jan 2020 12:01:56 -0800 (PST) From: Vladimir Oltean To: davem@davemloft.net, jakub.kicinski@netronome.com, linux@armlinux.org.uk, andrew@lunn.ch, f.fainelli@gmail.com, vivien.didelot@gmail.com Cc: alexandru.marginean@nxp.com, claudiu.manoil@nxp.com, xiaoliang.yang_1@nxp.com, yangbo.lu@nxp.com, netdev@vger.kernel.org, alexandre.belloni@bootlin.com, horatiu.vultur@microchip.com, UNGLinuxDriver@microchip.com, Vladimir Oltean Subject: [PATCH v4 net-next 9/9] net: dsa: felix: Add PCS operations for PHYLINK Date: Fri, 3 Jan 2020 22:01:27 +0200 Message-Id: <20200103200127.6331-10-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200103200127.6331-1-olteanv@gmail.com> References: <20200103200127.6331-1-olteanv@gmail.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Vladimir Oltean Layerscape SoCs traditionally expose the SerDes configuration/status for Ethernet protocols (PCS for SGMII/XFI/USXGMII etc etc) in a register format that is compatible with clause 22 or clause 45 (depending on SerDes protocol). Each MAC has its own internal MDIO bus on which there is one or more of these PCS's, responding to commands at a configurable PHY address. The per-port internal MDIO bus (which is just for PCSs) is totally separate and has nothing to do with the dedicated external MDIO controller (which is just for PHYs), but the register map for the MDIO controller is the same. The VSC9959 (Felix) switch instantiated in the LS1028A is integrated in hardware with the ENETC PCS of its DSA master, and reuses its MDIO controller driver, so Felix has been made to depend on it in Kconfig. +------------------------------------------------------------------------+ | +--------+ GMII (typically disabled via RCW) | | ENETC PCI | ENETC |--------------------------+ | | Root Complex | port 3 |-----------------------+ | | | Integrated +--------+ | | | | Endpoint | | | | +--------+ 2.5G GMII | | | | | ENETC |--------------+ | | | | | port 2 |-----------+ | | | | | +--------+ | | | | | | +--------+ +--------+ | | | Felix | | Felix | | | | port 4 | | port 5 | | | +--------+ +--------+ | | | | +--------+ +--------+ +--------+ +--------+ +--------+ +--------+ | | | ENETC | | ENETC | | Felix | | Felix | | Felix | | Felix | | | | port 0 | | port 1 | | port 0 | | port 1 | | port 2 | | port 3 | | +------------------------------------------------------------------------+ | |||| SerDes | |||| |||| |||| |||| | | +--------+block | +--------------------------------------------+ | | | ENETC | | | ENETC port 2 internal MDIO bus | | | | port 0 | | | PCS PCS PCS PCS | | | | PCS | | | 0 1 2 3 | | +-----------------|------------------------------------------------------+ v v v v v v SGMII/ RGMII QSGMII/QSXGMII/4xSGMII/4x100Base-X/4x2500Base-X USXGMII/ (bypasses 1000Base-X/ SerDes) 2500Base-X In the LS1028A SoC described above, the VSC9959 Felix switch is PF5 of the ENETC root complex, and has 2 BARs: - BAR 4: the switch's effective registers - BAR 0: the MDIO controller register map lended from ENETC port 2 (PF2), for accessing its associated PCS's. This explanation is necessary because the patch does some renaming "pci_bar" -> "switch_pci_bar" for clarity, which would otherwise appear a bit obtuse. The fact that the internal MDIO bus is "borrowed" is relevant because the register map is found in PF5 (the switch) but it triggers an access fault if PF2 (the ENETC DSA master) is not enabled. This is not treated in any way (and I don't think it can be treated). All of this is so SoC-specific, that it was contained as much as possible in the platform-integration file felix_vsc9959.c. We need to parse and pre-validate the device tree because of 2 reasons: - The PHY mode (SerDes protocol) cannot change at runtime due to SoC design. - There is a circular dependency in that we need to know what clause the PCS speaks in order to find it on the internal MDIO bus. But the clause of the PCS depends on what phy-mode it is configured for. The goal of this patch is to make steps towards removing the bootloader dependency for SGMII PCS pre-configuration, as well as to add support for monitoring the in-band SGMII AN between the PCS and the system-side link partner (PHY or other MAC). In practice the bootloader dependency is not completely removed. U-Boot pre-programs the PHY address at which each PCS can be found on the internal MDIO bus (MDEV_PORT). This is needed because the PCS of each port has the same out-of-reset PHY address of zero. The SerDes register for changing MDEV_PORT is pretty deep in the SoC (outside the addresses of the ENETC PCI BARs) and therefore inaccessible to us from here. Felix VSC9959 and Ocelot VSC7514 are integrated very differently in their respective SoCs, and for that reason Felix does not use the Ocelot core library for PHYLINK. On one hand we don't want to impose the fixed phy-mode limitation to Ocelot, and on the other hand Felix doesn't need to force the MAC link speed the way Ocelot does, since the MAC is connected to the PCS through a fixed GMII, and the PCS is the one who does the rate adaptation at lower link speeds, which the MAC does not even need to know about. In fact changing the GMII speed for Felix irrecoverably breaks transmission through that port until a reset. Yet another reason for wanting to convert Felix to PHYLINK is to configure the MAC of port 5 (the one that is typically disabled, in the setup with ENETC 2 as DSA master it doesn't support tagging so when it's enabled it is a regular fixed-link slave port, something that DSA PHYLIB doesn't control with .adjust_link). Signed-off-by: Vladimir Oltean --- Changes in v4: - Some cleanup of unneeded register writes in felix_phylink_mac_config, inherited from ocelot. Changes in v3: - Made a few tweaks to vsc9959_pcs_init_sgmii so that it works without MLO_AN_INBAND with the VSC8514 PHY. - Added proper dependencies on ENETC MDIO (re: "depends on NET_VENDOR_FREESCALE": yes, I know, the hardware really is a Frankenstein, can't do much about it). - Dropped the polling from vsc9959_pcs_link_state and let PHYLINK do its timer thing. drivers/net/dsa/ocelot/Kconfig | 2 + drivers/net/dsa/ocelot/felix.c | 259 ++++++++++++- drivers/net/dsa/ocelot/felix.h | 16 +- drivers/net/dsa/ocelot/felix_vsc9959.c | 501 ++++++++++++++++++++++++- 4 files changed, 761 insertions(+), 17 deletions(-) diff --git a/drivers/net/dsa/ocelot/Kconfig b/drivers/net/dsa/ocelot/Kconfig index 6f9804093150..a5b7cca03d09 100644 --- a/drivers/net/dsa/ocelot/Kconfig +++ b/drivers/net/dsa/ocelot/Kconfig @@ -3,8 +3,10 @@ config NET_DSA_MSCC_FELIX tristate "Ocelot / Felix Ethernet switch support" depends on NET_DSA && PCI depends on NET_VENDOR_MICROSEMI + depends on NET_VENDOR_FREESCALE select MSCC_OCELOT_SWITCH select NET_DSA_TAG_OCELOT + select FSL_ENETC_MDIO help This driver supports the VSC9959 network switch, which is a member of the Vitesse / Microsemi / Microchip Ocelot family of switching cores. diff --git a/drivers/net/dsa/ocelot/felix.c b/drivers/net/dsa/ocelot/felix.c index b7f92464815d..554ab69c89ff 100644 --- a/drivers/net/dsa/ocelot/felix.c +++ b/drivers/net/dsa/ocelot/felix.c @@ -2,9 +2,14 @@ /* Copyright 2019 NXP Semiconductors */ #include +#include +#include +#include +#include #include #include #include +#include #include #include #include @@ -26,14 +31,6 @@ static int felix_set_ageing_time(struct dsa_switch *ds, return 0; } -static void felix_adjust_link(struct dsa_switch *ds, int port, - struct phy_device *phydev) -{ - struct ocelot *ocelot = ds->priv; - - ocelot_adjust_link(ocelot, port, phydev); -} - static int felix_fdb_dump(struct dsa_switch *ds, int port, dsa_fdb_dump_cb_t *cb, void *data) { @@ -155,6 +152,132 @@ static void felix_port_disable(struct dsa_switch *ds, int port) return ocelot_port_disable(ocelot, port); } +static void felix_phylink_validate(struct dsa_switch *ds, int port, + unsigned long *supported, + struct phylink_link_state *state) +{ + struct ocelot *ocelot = ds->priv; + struct ocelot_port *ocelot_port = ocelot->ports[port]; + __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; + + if (state->interface != PHY_INTERFACE_MODE_NA && + state->interface != ocelot_port->phy_mode) { + bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); + return; + } + + /* No half-duplex. */ + phylink_set_port_modes(mask); + phylink_set(mask, Autoneg); + phylink_set(mask, Pause); + phylink_set(mask, Asym_Pause); + if (state->interface != PHY_INTERFACE_MODE_2500BASEX) { + phylink_set(mask, 10baseT_Full); + phylink_set(mask, 100baseT_Full); + phylink_set(mask, 1000baseT_Full); + } + /* The internal ports that run at 2.5G are overclocked GMII */ + if (state->interface == PHY_INTERFACE_MODE_GMII || + state->interface == PHY_INTERFACE_MODE_2500BASEX || + state->interface == PHY_INTERFACE_MODE_USXGMII) { + phylink_set(mask, 2500baseT_Full); + phylink_set(mask, 2500baseX_Full); + } + + bitmap_and(supported, supported, mask, + __ETHTOOL_LINK_MODE_MASK_NBITS); + bitmap_and(state->advertising, state->advertising, mask, + __ETHTOOL_LINK_MODE_MASK_NBITS); +} + +static int felix_phylink_mac_pcs_get_state(struct dsa_switch *ds, int port, + struct phylink_link_state *state) +{ + struct ocelot *ocelot = ds->priv; + struct felix *felix = ocelot_to_felix(ocelot); + + if (felix->info->pcs_link_state) + felix->info->pcs_link_state(ocelot, port, state); + + return 0; +} + +static void felix_phylink_mac_config(struct dsa_switch *ds, int port, + unsigned int link_an_mode, + const struct phylink_link_state *state) +{ + struct ocelot *ocelot = ds->priv; + struct ocelot_port *ocelot_port = ocelot->ports[port]; + struct felix *felix = ocelot_to_felix(ocelot); + u32 mac_fc_cfg; + + /* Flow control. Link speed is only used here to evaluate the time + * specification in incoming pause frames. + */ + mac_fc_cfg = SYS_MAC_FC_CFG_FC_LINK_SPEED(state->speed); + if (state->pause & MLO_PAUSE_RX) + mac_fc_cfg |= SYS_MAC_FC_CFG_RX_FC_ENA; + if (state->pause & MLO_PAUSE_TX) + mac_fc_cfg |= SYS_MAC_FC_CFG_TX_FC_ENA | + SYS_MAC_FC_CFG_PAUSE_VAL_CFG(0xffff) | + SYS_MAC_FC_CFG_FC_LATENCY_CFG(0x7) | + SYS_MAC_FC_CFG_ZERO_PAUSE_ENA; + ocelot_write_rix(ocelot, mac_fc_cfg, SYS_MAC_FC_CFG, port); + + ocelot_write_rix(ocelot, 0, ANA_POL_FLOWC, port); + + if (felix->info->pcs_init) + felix->info->pcs_init(ocelot, port, link_an_mode, state); +} + +static void felix_phylink_mac_an_restart(struct dsa_switch *ds, int port) +{ + struct ocelot *ocelot = ds->priv; + struct felix *felix = ocelot_to_felix(ocelot); + + if (felix->info->pcs_an_restart) + felix->info->pcs_an_restart(ocelot, port); +} + +static void felix_phylink_mac_link_down(struct dsa_switch *ds, int port, + unsigned int link_an_mode, + phy_interface_t interface) +{ + struct ocelot *ocelot = ds->priv; + struct ocelot_port *ocelot_port = ocelot->ports[port]; + + ocelot_port_writel(ocelot_port, 0, DEV_MAC_ENA_CFG); + ocelot_rmw_rix(ocelot, 0, QSYS_SWITCH_PORT_MODE_PORT_ENA, + QSYS_SWITCH_PORT_MODE, port); +} + +static void felix_phylink_mac_link_up(struct dsa_switch *ds, int port, + unsigned int link_an_mode, + phy_interface_t interface, + struct phy_device *phydev) +{ + struct ocelot *ocelot = ds->priv; + struct ocelot_port *ocelot_port = ocelot->ports[port]; + + /* Enable MAC module */ + ocelot_port_writel(ocelot_port, DEV_MAC_ENA_CFG_RX_ENA | + DEV_MAC_ENA_CFG_TX_ENA, DEV_MAC_ENA_CFG); + + /* Enable receiving frames on the port, and activate auto-learning of + * MAC addresses. + */ + ocelot_write_gix(ocelot, ANA_PORT_PORT_CFG_LEARNAUTO | + ANA_PORT_PORT_CFG_RECV_ENA | + ANA_PORT_PORT_CFG_PORTID_VAL(port), + ANA_PORT_PORT_CFG, port); + + /* Core: Enable port for frame transfer */ + ocelot_write_rix(ocelot, QSYS_SWITCH_PORT_MODE_INGRESS_DROP_MODE | + QSYS_SWITCH_PORT_MODE_SCH_NEXT_CFG(1) | + QSYS_SWITCH_PORT_MODE_PORT_ENA, + QSYS_SWITCH_PORT_MODE, port); +} + static void felix_get_strings(struct dsa_switch *ds, int port, u32 stringset, u8 *data) { @@ -185,10 +308,76 @@ static int felix_get_ts_info(struct dsa_switch *ds, int port, return ocelot_get_ts_info(ocelot, port, info); } +static int felix_parse_ports_node(struct felix *felix, + struct device_node *ports_node, + phy_interface_t *port_phy_modes) +{ + struct ocelot *ocelot = &felix->ocelot; + struct device *dev = felix->ocelot.dev; + struct device_node *child; + + for_each_child_of_node(ports_node, child) { + phy_interface_t phy_mode; + u32 port; + int err; + + /* Get switch port number from DT */ + if (of_property_read_u32(child, "reg", &port) < 0) { + dev_err(dev, "Port number not defined in device tree " + "(property \"reg\")\n"); + of_node_put(child); + return -ENODEV; + } + + /* Get PHY mode from DT */ + err = of_get_phy_mode(child, &phy_mode); + if (err) { + dev_err(dev, "Failed to read phy-mode or " + "phy-interface-type property for port %d\n", + port); + of_node_put(child); + return -ENODEV; + } + + err = felix->info->prevalidate_phy_mode(ocelot, port, phy_mode); + if (err < 0) { + dev_err(dev, "Unsupported PHY mode %s on port %d\n", + phy_modes(phy_mode), port); + return err; + } + + port_phy_modes[port] = phy_mode; + } + + return 0; +} + +static int felix_parse_dt(struct felix *felix, phy_interface_t *port_phy_modes) +{ + struct device *dev = felix->ocelot.dev; + struct device_node *switch_node; + struct device_node *ports_node; + int err; + + switch_node = dev->of_node; + + ports_node = of_get_child_by_name(switch_node, "ports"); + if (!ports_node) { + dev_err(dev, "Incorrect bindings: absent \"ports\" node\n"); + return -ENODEV; + } + + err = felix_parse_ports_node(felix, ports_node, port_phy_modes); + of_node_put(ports_node); + + return err; +} + static int felix_init_structs(struct felix *felix, int num_phys_ports) { struct ocelot *ocelot = &felix->ocelot; - resource_size_t base; + phy_interface_t *port_phy_modes; + resource_size_t switch_base; int port, i, err; ocelot->num_phys_ports = num_phys_ports; @@ -203,7 +392,19 @@ static int felix_init_structs(struct felix *felix, int num_phys_ports) ocelot->shared_queue_sz = felix->info->shared_queue_sz; ocelot->ops = felix->info->ops; - base = pci_resource_start(felix->pdev, felix->info->pci_bar); + port_phy_modes = kcalloc(num_phys_ports, sizeof(phy_interface_t), + GFP_KERNEL); + if (!port_phy_modes) + return -ENOMEM; + + err = felix_parse_dt(felix, port_phy_modes); + if (err) { + kfree(port_phy_modes); + return err; + } + + switch_base = pci_resource_start(felix->pdev, + felix->info->switch_pci_bar); for (i = 0; i < TARGET_MAX; i++) { struct regmap *target; @@ -214,13 +415,14 @@ static int felix_init_structs(struct felix *felix, int num_phys_ports) res = &felix->info->target_io_res[i]; res->flags = IORESOURCE_MEM; - res->start += base; - res->end += base; + res->start += switch_base; + res->end += switch_base; target = ocelot_regmap_init(ocelot, res); if (IS_ERR(target)) { dev_err(ocelot->dev, "Failed to map device memory space\n"); + kfree(port_phy_modes); return PTR_ERR(target); } @@ -230,6 +432,7 @@ static int felix_init_structs(struct felix *felix, int num_phys_ports) err = ocelot_regfields_init(ocelot, felix->info->regfields); if (err) { dev_err(ocelot->dev, "failed to init reg fields map\n"); + kfree(port_phy_modes); return err; } @@ -244,26 +447,37 @@ static int felix_init_structs(struct felix *felix, int num_phys_ports) if (!ocelot_port) { dev_err(ocelot->dev, "failed to allocate port memory\n"); + kfree(port_phy_modes); return -ENOMEM; } res = &felix->info->port_io_res[port]; res->flags = IORESOURCE_MEM; - res->start += base; - res->end += base; + res->start += switch_base; + res->end += switch_base; port_regs = devm_ioremap_resource(ocelot->dev, res); if (IS_ERR(port_regs)) { dev_err(ocelot->dev, "failed to map registers for port %d\n", port); + kfree(port_phy_modes); return PTR_ERR(port_regs); } + ocelot_port->phy_mode = port_phy_modes[port]; ocelot_port->ocelot = ocelot; ocelot_port->regs = port_regs; ocelot->ports[port] = ocelot_port; } + kfree(port_phy_modes); + + if (felix->info->mdio_bus_alloc) { + err = felix->info->mdio_bus_alloc(ocelot); + if (err < 0) + return err; + } + return 0; } @@ -293,12 +507,22 @@ static int felix_setup(struct dsa_switch *ds) OCELOT_TAG_PREFIX_LONG); } + /* It looks like the MAC/PCS interrupt register - PM0_IEVENT (0x8040) + * isn't instantiated for the Felix PF. + * In-band AN may take a few ms to complete, so we need to poll. + */ + ds->pcs_poll = true; + return 0; } static void felix_teardown(struct dsa_switch *ds) { struct ocelot *ocelot = ds->priv; + struct felix *felix = ocelot_to_felix(ocelot); + + if (felix->info->mdio_bus_free) + felix->info->mdio_bus_free(ocelot); /* stop workqueue thread */ ocelot_deinit(ocelot); @@ -369,7 +593,12 @@ static const struct dsa_switch_ops felix_switch_ops = { .get_ethtool_stats = felix_get_ethtool_stats, .get_sset_count = felix_get_sset_count, .get_ts_info = felix_get_ts_info, - .adjust_link = felix_adjust_link, + .phylink_validate = felix_phylink_validate, + .phylink_mac_link_state = felix_phylink_mac_pcs_get_state, + .phylink_mac_config = felix_phylink_mac_config, + .phylink_mac_an_restart = felix_phylink_mac_an_restart, + .phylink_mac_link_down = felix_phylink_mac_link_down, + .phylink_mac_link_up = felix_phylink_mac_link_up, .port_enable = felix_port_enable, .port_disable = felix_port_disable, .port_fdb_dump = felix_fdb_dump, diff --git a/drivers/net/dsa/ocelot/felix.h b/drivers/net/dsa/ocelot/felix.h index 204296e51d0c..3a7580015b62 100644 --- a/drivers/net/dsa/ocelot/felix.h +++ b/drivers/net/dsa/ocelot/felix.h @@ -10,6 +10,7 @@ struct felix_info { struct resource *target_io_res; struct resource *port_io_res; + struct resource *imdio_res; const struct reg_field *regfields; const u32 *const *map; const struct ocelot_ops *ops; @@ -17,7 +18,18 @@ struct felix_info { const struct ocelot_stat_layout *stats_layout; unsigned int num_stats; int num_ports; - int pci_bar; + int switch_pci_bar; + int imdio_pci_bar; + int (*mdio_bus_alloc)(struct ocelot *ocelot); + void (*mdio_bus_free)(struct ocelot *ocelot); + void (*pcs_init)(struct ocelot *ocelot, int port, + unsigned int link_an_mode, + const struct phylink_link_state *state); + void (*pcs_an_restart)(struct ocelot *ocelot, int port); + void (*pcs_link_state)(struct ocelot *ocelot, int port, + struct phylink_link_state *state); + int (*prevalidate_phy_mode)(struct ocelot *ocelot, int port, + phy_interface_t phy_mode); }; extern struct felix_info felix_info_vsc9959; @@ -32,6 +44,8 @@ struct felix { struct pci_dev *pdev; struct felix_info *info; struct ocelot ocelot; + struct mii_bus *imdio; + struct phy_device **pcs; }; #endif diff --git a/drivers/net/dsa/ocelot/felix_vsc9959.c b/drivers/net/dsa/ocelot/felix_vsc9959.c index b9758b0d18c7..03482616faa7 100644 --- a/drivers/net/dsa/ocelot/felix_vsc9959.c +++ b/drivers/net/dsa/ocelot/felix_vsc9959.c @@ -2,12 +2,33 @@ /* Copyright 2017 Microsemi Corporation * Copyright 2018-2019 NXP Semiconductors */ +#include #include #include #include #include #include "felix.h" +/* TODO: should find a better place for these */ +#define USXGMII_BMCR_RESET BIT(15) +#define USXGMII_BMCR_AN_EN BIT(12) +#define USXGMII_BMCR_RST_AN BIT(9) +#define USXGMII_BMSR_LNKS(status) (((status) & GENMASK(2, 2)) >> 2) +#define USXGMII_BMSR_AN_CMPL(status) (((status) & GENMASK(5, 5)) >> 5) +#define USXGMII_ADVERTISE_LNKS(x) (((x) << 15) & BIT(15)) +#define USXGMII_ADVERTISE_FDX BIT(12) +#define USXGMII_ADVERTISE_SPEED(x) (((x) << 9) & GENMASK(11, 9)) +#define USXGMII_LPA_LNKS(lpa) ((lpa) >> 15) +#define USXGMII_LPA_DUPLEX(lpa) (((lpa) & GENMASK(12, 12)) >> 12) +#define USXGMII_LPA_SPEED(lpa) (((lpa) & GENMASK(11, 9)) >> 9) + +enum usxgmii_speed { + USXGMII_SPEED_10 = 0, + USXGMII_SPEED_100 = 1, + USXGMII_SPEED_1000 = 2, + USXGMII_SPEED_2500 = 4, +}; + static const u32 vsc9959_ana_regmap[] = { REG(ANA_ADVLEARN, 0x0089a0), REG(ANA_VLANMASK, 0x0089a4), @@ -386,6 +407,15 @@ static struct resource vsc9959_port_io_res[] = { }, }; +/* Port MAC 0 Internal MDIO bus through which the SerDes acting as an + * SGMII/QSGMII MAC PCS can be found. + */ +static struct resource vsc9959_imdio_res = { + .start = 0x8030, + .end = 0x8040, + .name = "imdio", +}; + static const struct reg_field vsc9959_regfields[] = { [ANA_ADVLEARN_VLAN_CHK] = REG_FIELD(ANA_ADVLEARN, 6, 6), [ANA_ADVLEARN_LEARN_MIRROR] = REG_FIELD(ANA_ADVLEARN, 0, 5), @@ -565,13 +595,475 @@ static int vsc9959_reset(struct ocelot *ocelot) return 0; } +static void vsc9959_pcs_an_restart_sgmii(struct phy_device *pcs) +{ + phy_set_bits(pcs, MII_BMCR, BMCR_ANRESTART); +} + +static void vsc9959_pcs_an_restart_usxgmii(struct phy_device *pcs) +{ + phy_write_mmd(pcs, MDIO_MMD_VEND2, MII_BMCR, + USXGMII_BMCR_RESET | + USXGMII_BMCR_AN_EN | + USXGMII_BMCR_RST_AN); +} + +static void vsc9959_pcs_an_restart(struct ocelot *ocelot, int port) +{ + struct felix *felix = ocelot_to_felix(ocelot); + struct phy_device *pcs = felix->pcs[port]; + + if (!pcs) + return; + + switch (pcs->interface) { + case PHY_INTERFACE_MODE_SGMII: + case PHY_INTERFACE_MODE_QSGMII: + vsc9959_pcs_an_restart_sgmii(pcs); + break; + case PHY_INTERFACE_MODE_USXGMII: + vsc9959_pcs_an_restart_usxgmii(pcs); + break; + default: + dev_err(ocelot->dev, "Invalid PCS interface type %s\n", + phy_modes(pcs->interface)); + break; + } +} + +/* We enable SGMII AN only when the PHY has managed = "in-band-status" in the + * device tree. If we are in MLO_AN_PHY mode, we program directly state->speed + * into the PCS, which is retrieved out-of-band over MDIO. This also has the + * benefit of working with SGMII fixed-links, like downstream switches, where + * both link partners attempt to operate as AN slaves and therefore AN never + * completes. But it also has the disadvantage that some PHY chips don't pass + * traffic if SGMII AN is enabled but not completed (acknowledged by us), so + * setting MLO_AN_INBAND is actually required for those. + */ +static void vsc9959_pcs_init_sgmii(struct phy_device *pcs, + unsigned int link_an_mode, + const struct phylink_link_state *state) +{ + if (link_an_mode == MLO_AN_INBAND) { + /* SGMII spec requires tx_config_Reg[15:0] to be exactly 0x4001 + * for the MAC PCS in order to acknowledge the AN. + */ + phy_write(pcs, MII_ADVERTISE, ADVERTISE_SGMII | + ADVERTISE_LPACK); + + phy_write(pcs, ENETC_PCS_IF_MODE, + ENETC_PCS_IF_MODE_SGMII_EN | + ENETC_PCS_IF_MODE_USE_SGMII_AN); + + /* Adjust link timer for SGMII */ + phy_write(pcs, ENETC_PCS_LINK_TIMER1, + ENETC_PCS_LINK_TIMER1_VAL); + phy_write(pcs, ENETC_PCS_LINK_TIMER2, + ENETC_PCS_LINK_TIMER2_VAL); + + phy_write(pcs, MII_BMCR, BMCR_ANRESTART | BMCR_ANENABLE); + } else { + int speed; + + if (state->duplex == DUPLEX_HALF) { + phydev_err(pcs, "Half duplex not supported\n"); + return; + } + switch (state->speed) { + case SPEED_1000: + speed = ENETC_PCS_SPEED_1000; + break; + case SPEED_100: + speed = ENETC_PCS_SPEED_100; + break; + case SPEED_10: + speed = ENETC_PCS_SPEED_10; + break; + case SPEED_UNKNOWN: + /* Silently don't do anything */ + return; + default: + phydev_err(pcs, "Invalid PCS speed %d\n", state->speed); + return; + } + + phy_write(pcs, ENETC_PCS_IF_MODE, + ENETC_PCS_IF_MODE_SGMII_EN | + ENETC_PCS_IF_MODE_SGMII_SPEED(speed)); + + /* Yes, not a mistake: speed is given by IF_MODE. */ + phy_write(pcs, MII_BMCR, BMCR_RESET | + BMCR_SPEED1000 | + BMCR_FULLDPLX); + } +} + +/* 2500Base-X is SerDes protocol 7 on Felix and 6 on ENETC. It is a SerDes lane + * clocked at 3.125 GHz which encodes symbols with 8b/10b and does not have + * auto-negotiation of any link parameters. Electrically it is compatible with + * a single lane of XAUI. + * The hardware reference manual wants to call this mode SGMII, but it isn't + * really, since the fundamental features of SGMII: + * - Downgrading the link speed by duplicating symbols + * - Auto-negotiation + * are not there. + * The speed is configured at 1000 in the IF_MODE and BMCR MDIO registers + * because the clock frequency is actually given by a PLL configured in the + * Reset Configuration Word (RCW). + * Since there is no difference between fixed speed SGMII w/o AN and 802.3z w/o + * AN, we call this PHY interface type 2500Base-X. In case a PHY negotiates a + * lower link speed on line side, the system-side interface remains fixed at + * 2500 Mbps and we do rate adaptation through pause frames. + */ +static void vsc9959_pcs_init_2500basex(struct phy_device *pcs, + unsigned int link_an_mode, + const struct phylink_link_state *state) +{ + if (link_an_mode == MLO_AN_INBAND) { + phydev_err(pcs, "AN not supported on 3.125GHz SerDes lane\n"); + return; + } + + phy_write(pcs, ENETC_PCS_IF_MODE, + ENETC_PCS_IF_MODE_SGMII_EN | + ENETC_PCS_IF_MODE_SGMII_SPEED(ENETC_PCS_SPEED_2500)); + + phy_write(pcs, MII_BMCR, BMCR_SPEED1000 | + BMCR_FULLDPLX | + BMCR_RESET); +} + +static void vsc9959_pcs_init_usxgmii(struct phy_device *pcs, + unsigned int link_an_mode, + const struct phylink_link_state *state) +{ + if (link_an_mode != MLO_AN_INBAND) { + phydev_err(pcs, "USXGMII only supports in-band AN for now\n"); + return; + } + + /* Configure device ability for the USXGMII Replicator */ + phy_write_mmd(pcs, MDIO_MMD_VEND2, MII_ADVERTISE, + USXGMII_ADVERTISE_SPEED(USXGMII_SPEED_2500) | + USXGMII_ADVERTISE_LNKS(1) | + ADVERTISE_SGMII | + ADVERTISE_LPACK | + USXGMII_ADVERTISE_FDX); +} + +static void vsc9959_pcs_init(struct ocelot *ocelot, int port, + unsigned int link_an_mode, + const struct phylink_link_state *state) +{ + struct felix *felix = ocelot_to_felix(ocelot); + struct phy_device *pcs = felix->pcs[port]; + + if (!pcs) + return; + + /* The PCS does not implement the BMSR register fully, so capability + * detection via genphy_read_abilities does not work. Since we can get + * the PHY config word from the LPA register though, there is still + * value in using the generic phy_resolve_aneg_linkmode function. So + * populate the supported and advertising link modes manually here. + */ + linkmode_set_bit_array(phy_basic_ports_array, + ARRAY_SIZE(phy_basic_ports_array), + pcs->supported); + linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT, pcs->supported); + linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, pcs->supported); + linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, pcs->supported); + if (pcs->interface == PHY_INTERFACE_MODE_2500BASEX || + pcs->interface == PHY_INTERFACE_MODE_USXGMII) + linkmode_set_bit(ETHTOOL_LINK_MODE_2500baseX_Full_BIT, + pcs->supported); + if (pcs->interface != PHY_INTERFACE_MODE_2500BASEX) + linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, + pcs->supported); + phy_advertise_supported(pcs); + + switch (pcs->interface) { + case PHY_INTERFACE_MODE_SGMII: + case PHY_INTERFACE_MODE_QSGMII: + vsc9959_pcs_init_sgmii(pcs, link_an_mode, state); + break; + case PHY_INTERFACE_MODE_2500BASEX: + vsc9959_pcs_init_2500basex(pcs, link_an_mode, state); + break; + case PHY_INTERFACE_MODE_USXGMII: + vsc9959_pcs_init_usxgmii(pcs, link_an_mode, state); + break; + default: + dev_err(ocelot->dev, "Unsupported link mode %s\n", + phy_modes(pcs->interface)); + } +} + +static void vsc9959_pcs_link_state_resolve(struct phy_device *pcs, + struct phylink_link_state *state) +{ + state->an_complete = pcs->autoneg_complete; + state->an_enabled = pcs->autoneg; + state->link = pcs->link; + state->duplex = pcs->duplex; + state->speed = pcs->speed; + /* SGMII AN does not negotiate flow control, but that's ok, + * since phylink already knows that, and does: + * link_state.pause |= pl->phy_state.pause; + */ + state->pause = MLO_PAUSE_NONE; + + phydev_dbg(pcs, + "mode=%s/%s/%s adv=%*pb lpa=%*pb link=%u an_enabled=%u an_complete=%u\n", + phy_modes(pcs->interface), + phy_speed_to_str(pcs->speed), + phy_duplex_to_str(pcs->duplex), + __ETHTOOL_LINK_MODE_MASK_NBITS, pcs->advertising, + __ETHTOOL_LINK_MODE_MASK_NBITS, pcs->lp_advertising, + pcs->link, pcs->autoneg, pcs->autoneg_complete); +} + +static void vsc9959_pcs_link_state_sgmii(struct phy_device *pcs, + struct phylink_link_state *state) +{ + int err; + + err = genphy_update_link(pcs); + if (err < 0) + return; + + if (pcs->autoneg_complete) { + u16 lpa = phy_read(pcs, MII_LPA); + + mii_lpa_to_linkmode_lpa_sgmii(pcs->lp_advertising, lpa); + + phy_resolve_aneg_linkmode(pcs); + } +} + +static void vsc9959_pcs_link_state_2500basex(struct phy_device *pcs, + struct phylink_link_state *state) +{ + int err; + + err = genphy_update_link(pcs); + if (err < 0) + return; + + pcs->speed = SPEED_2500; + pcs->asym_pause = true; + pcs->pause = true; +} + +static void vsc9959_pcs_link_state_usxgmii(struct phy_device *pcs, + struct phylink_link_state *state) +{ + int status, lpa; + + status = phy_read_mmd(pcs, MDIO_MMD_VEND2, MII_BMSR); + if (status < 0) + return; + + pcs->autoneg = true; + pcs->autoneg_complete = USXGMII_BMSR_AN_CMPL(status); + pcs->link = USXGMII_BMSR_LNKS(status); + + if (!pcs->link || !pcs->autoneg_complete) + return; + + lpa = phy_read_mmd(pcs, MDIO_MMD_VEND2, MII_LPA); + if (lpa < 0) + return; + + switch (USXGMII_LPA_SPEED(lpa)) { + case USXGMII_SPEED_10: + pcs->speed = SPEED_10; + break; + case USXGMII_SPEED_100: + pcs->speed = SPEED_100; + break; + case USXGMII_SPEED_1000: + pcs->speed = SPEED_1000; + break; + case USXGMII_SPEED_2500: + pcs->speed = SPEED_2500; + break; + default: + break; + } + + pcs->link = USXGMII_LPA_LNKS(lpa); + if (USXGMII_LPA_DUPLEX(lpa)) + pcs->duplex = DUPLEX_FULL; + else + pcs->duplex = DUPLEX_HALF; +} + +static void vsc9959_pcs_link_state(struct ocelot *ocelot, int port, + struct phylink_link_state *state) +{ + struct felix *felix = ocelot_to_felix(ocelot); + struct phy_device *pcs = felix->pcs[port]; + + if (!pcs) + return; + + pcs->speed = SPEED_UNKNOWN; + pcs->duplex = DUPLEX_UNKNOWN; + pcs->pause = 0; + pcs->asym_pause = 0; + + switch (pcs->interface) { + case PHY_INTERFACE_MODE_SGMII: + case PHY_INTERFACE_MODE_QSGMII: + vsc9959_pcs_link_state_sgmii(pcs, state); + break; + case PHY_INTERFACE_MODE_2500BASEX: + vsc9959_pcs_link_state_2500basex(pcs, state); + break; + case PHY_INTERFACE_MODE_USXGMII: + vsc9959_pcs_link_state_usxgmii(pcs, state); + break; + default: + return; + } + + vsc9959_pcs_link_state_resolve(pcs, state); +} + +static int vsc9959_prevalidate_phy_mode(struct ocelot *ocelot, int port, + phy_interface_t phy_mode) +{ + switch (phy_mode) { + case PHY_INTERFACE_MODE_GMII: + /* Only supported on internal to-CPU ports */ + if (port != 4 && port != 5) + return -ENOTSUPP; + return 0; + case PHY_INTERFACE_MODE_SGMII: + case PHY_INTERFACE_MODE_QSGMII: + case PHY_INTERFACE_MODE_USXGMII: + case PHY_INTERFACE_MODE_2500BASEX: + /* Not supported on internal to-CPU ports */ + if (port == 4 || port == 5) + return -ENOTSUPP; + return 0; + default: + return -ENOTSUPP; + } +} + static const struct ocelot_ops vsc9959_ops = { .reset = vsc9959_reset, }; +static int vsc9959_mdio_bus_alloc(struct ocelot *ocelot) +{ + struct felix *felix = ocelot_to_felix(ocelot); + struct enetc_mdio_priv *mdio_priv; + struct device *dev = ocelot->dev; + resource_size_t imdio_base; + void __iomem *imdio_regs; + struct resource *res; + struct enetc_hw *hw; + struct mii_bus *bus; + int port; + int rc; + + felix->pcs = devm_kcalloc(dev, felix->info->num_ports, + sizeof(struct phy_device *), + GFP_KERNEL); + if (!felix->pcs) { + dev_err(dev, "failed to allocate array for PCS PHYs\n"); + return -ENOMEM; + } + + imdio_base = pci_resource_start(felix->pdev, + felix->info->imdio_pci_bar); + + res = felix->info->imdio_res; + res->flags = IORESOURCE_MEM; + res->start += imdio_base; + res->end += imdio_base; + + imdio_regs = devm_ioremap_resource(dev, res); + if (IS_ERR(imdio_regs)) { + dev_err(dev, "failed to map internal MDIO registers\n"); + return PTR_ERR(imdio_regs); + } + + hw = enetc_hw_alloc(dev, imdio_regs); + if (IS_ERR(hw)) { + dev_err(dev, "failed to allocate ENETC HW structure\n"); + return PTR_ERR(hw); + } + + bus = devm_mdiobus_alloc_size(dev, sizeof(*mdio_priv)); + if (!bus) + return -ENOMEM; + + bus->name = "VSC9959 internal MDIO bus"; + bus->read = enetc_mdio_read; + bus->write = enetc_mdio_write; + bus->parent = dev; + mdio_priv = bus->priv; + mdio_priv->hw = hw; + /* This gets added to imdio_regs, which already maps addresses + * starting with the proper offset. + */ + mdio_priv->mdio_base = 0; + snprintf(bus->id, MII_BUS_ID_SIZE, "%s-imdio", dev_name(dev)); + + /* Needed in order to initialize the bus mutex lock */ + rc = mdiobus_register(bus); + if (rc < 0) { + dev_err(dev, "failed to register MDIO bus\n"); + return rc; + } + + felix->imdio = bus; + + for (port = 0; port < felix->info->num_ports; port++) { + struct ocelot_port *ocelot_port = ocelot->ports[port]; + struct phy_device *pcs; + bool is_c45 = false; + + if (ocelot_port->phy_mode == PHY_INTERFACE_MODE_USXGMII) + is_c45 = true; + + pcs = get_phy_device(felix->imdio, port, is_c45); + if (IS_ERR(pcs)) + continue; + + pcs->interface = ocelot_port->phy_mode; + felix->pcs[port] = pcs; + + dev_info(dev, "Found PCS at internal MDIO address %d\n", port); + } + + return 0; +} + +static void vsc9959_mdio_bus_free(struct ocelot *ocelot) +{ + struct felix *felix = ocelot_to_felix(ocelot); + int port; + + for (port = 0; port < ocelot->num_phys_ports; port++) { + struct phy_device *pcs = felix->pcs[port]; + + if (!pcs) + continue; + + put_device(&pcs->mdio.dev); + } + mdiobus_unregister(felix->imdio); +} + struct felix_info felix_info_vsc9959 = { .target_io_res = vsc9959_target_io_res, .port_io_res = vsc9959_port_io_res, + .imdio_res = &vsc9959_imdio_res, .regfields = vsc9959_regfields, .map = vsc9959_regmap, .ops = &vsc9959_ops, @@ -579,5 +1071,12 @@ struct felix_info felix_info_vsc9959 = { .num_stats = ARRAY_SIZE(vsc9959_stats_layout), .shared_queue_sz = 128 * 1024, .num_ports = 6, - .pci_bar = 4, + .switch_pci_bar = 4, + .imdio_pci_bar = 0, + .mdio_bus_alloc = vsc9959_mdio_bus_alloc, + .mdio_bus_free = vsc9959_mdio_bus_free, + .pcs_init = vsc9959_pcs_init, + .pcs_an_restart = vsc9959_pcs_an_restart, + .pcs_link_state = vsc9959_pcs_link_state, + .prevalidate_phy_mode = vsc9959_prevalidate_phy_mode, };