From patchwork Fri Dec 27 21:36:16 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 1215794 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="sVIv1jKI"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 47l0XB1Rk6z9sPV for ; Sat, 28 Dec 2019 08:36:58 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726578AbfL0Vg4 (ORCPT ); Fri, 27 Dec 2019 16:36:56 -0500 Received: from mail-wr1-f66.google.com ([209.85.221.66]:37002 "EHLO mail-wr1-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726416AbfL0Vgx (ORCPT ); Fri, 27 Dec 2019 16:36:53 -0500 Received: by mail-wr1-f66.google.com with SMTP id w15so14650613wru.4 for ; Fri, 27 Dec 2019 13:36:51 -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=QP/2Bmqa2OlptzTt4Bt0tS4N2p0i9VyZ3bTfTiXn7q8=; b=sVIv1jKIsgU/T4p7UpB1ifp+qeMzo1AC54IkTW3fdMcbxWhSfOjUiqYOfO1UIA/HHv LyuTjc/YXiLssdOoox1hpVELPAS1vxGVu7l7rZR31OBsQ4HGbA5b1nM5m/GOCQi7nW2O QPgT0vwDwOZBTogvas2O7/WADIgbneQThGOg5o3/SW0nksLz42RcQ0tgs5j7SLSb+qZU 10RwJswUcMudQhdYAB0fPqndK5hm0KbamyhJvh9+aNu8Gw/R/8MJsDz0195dkjm8fHtb D8uUC/4OtMa53/zIMlBCuBdAdWnxcegH1jxAILh/Xt1v+hRLMEzoxeQ9cZi3XSCD7NE9 Vs0Q== 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=QP/2Bmqa2OlptzTt4Bt0tS4N2p0i9VyZ3bTfTiXn7q8=; b=nfEvZI8N06KlHIhE93J6WUQ0wt0UJ8+l+HPVBnMoBZMRaYLMaHeR0bHji1vETfEoAW xMlkqL0je/YiPt2akpMUMAqt3h/Debku9hg5Z0CbqbeF2chDhWHp7zELj7Q0cTWOy0uG YU1FTHo2Y80/b9lRZXMkS5imtoi2TMeVonRGPfCItO40kcyVgwlji73KU4ouIuulL9l1 DL2bx1RzMOSU3R1JWLfb2JsFf07NdrYdvdulF9WvgNx2l0yjlX4NnB+LzheuxedFZgDt bVWcwZXBgVxiSWrfFjOvc4z/KEFjxwnIqfEdPs8kQOkA5GPY7HUgRbHCnDGKUwxKFhqx KKAw== X-Gm-Message-State: APjAAAXW/jsEAtb7PjXDLCetim7u255AGjUMRvm6lwEz+33q7j8mz204 J9b3nr+lit3EdzKXvDVNuFgAgcm6ynacaQ== X-Google-Smtp-Source: APXvYqyE00+RAxBfKjKAPuKxlfhRMKVCwKbXHjwe0h880jdmTvUNyJPLNa9a2acKW2i0J+9NKMpEZg== X-Received: by 2002:adf:cf0a:: with SMTP id o10mr42515046wrj.325.1577482610648; Fri, 27 Dec 2019 13:36:50 -0800 (PST) Received: from localhost.localdomain ([188.25.254.226]) by smtp.gmail.com with ESMTPSA id v3sm36330504wru.32.2019.12.27.13.36.49 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 27 Dec 2019 13:36:50 -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 v3 net-next 01/11] mii: Add helpers for parsing SGMII auto-negotiation Date: Fri, 27 Dec 2019 23:36:16 +0200 Message-Id: <20191227213626.4404-2-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20191227213626.4404-1-olteanv@gmail.com> References: <20191227213626.4404-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 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 Dec 27 21:36:17 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 1215796 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="k4nJ0H4z"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 47l0XD5Txdz9sPV for ; Sat, 28 Dec 2019 08:37:00 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726559AbfL0Vg4 (ORCPT ); Fri, 27 Dec 2019 16:36:56 -0500 Received: from mail-wr1-f66.google.com ([209.85.221.66]:33655 "EHLO mail-wr1-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726400AbfL0Vgx (ORCPT ); Fri, 27 Dec 2019 16:36:53 -0500 Received: by mail-wr1-f66.google.com with SMTP id b6so27316521wrq.0 for ; Fri, 27 Dec 2019 13:36: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=lPcT1nIQRIywQ1Uddl11jQkMYgW4aZQzKVOqbOR3dDs=; b=k4nJ0H4zJRQyHuV1I4Drn8n6+RgkitXc2PlKDCqMYw8sRK1fyZ+7f47JpvCFsrukrJ R5JM069SIXrzl4ggN+BzAj5Fvz/wY/wpD72qvGiFSDrra6iAqA5W9njK0C4PjXd5v9LM 3sJjTAh10ppzXzZG/xND5AebvB25uKUHKQRJTZzq4iYyQY+PZkk9I7sRVPPUfhdkocvA r5mtT6RghKPqBlCH4glv5X+CFjwkvWtpcRdIaWQ9YjCXXwUlc0PnxM8CE9EgFWCRL+Qn rV2bwM17SUSglZ1J9eJYAKTzLLFXwfxiS89aZiFgqY0r3RntA166Xrc7mudSWviUNs0U yfvA== 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=lPcT1nIQRIywQ1Uddl11jQkMYgW4aZQzKVOqbOR3dDs=; b=dj5mXd/V4B2HB/iwd/rJ8uTXcmMiQO0uoN24QchjRJZiT78Hs/bELaT/o4Q/ZguXsZ 3IcMkLpi84l0WFMTUpRBR+hN6fC10gEVL0ug1oO3jlueRYkwFKENHmcr/zCEgprLAjea d2lRgnQWLJvx/Pbk1gviIZWRTnyeNLfJ2fWyNLEF2wa2DTpRHBy2JbAjwUtivf8SAzcD 27FAM0q2pEeH7m0W5/NhgIYpkGXe1ZKakziJRI7EIc9wZTT8m6ATOoVOw9iW4yKVG+ce WuDQ/F+a6qtW0zZHje3XNa5Cl1nc1Y385+u671dbABk1LNiuf+RlFdgSrVHsva5fIxgv ZhlQ== X-Gm-Message-State: APjAAAXo48RG1HIcMGNUtbwJyDCPSwJ1Uei6m9wtLiJTx9KKwClA6tOs kdEWGURmVGhCGwFQ+jrXDog= X-Google-Smtp-Source: APXvYqx1Wg7u6ymdDXhxtixfZ3Yn5Ln0dHEyib/Gw8ZFIt8vdwcWvy63O7+7Zw0HvEyYVtyCIVASag== X-Received: by 2002:a5d:4b88:: with SMTP id b8mr4938219wrt.343.1577482611917; Fri, 27 Dec 2019 13:36:51 -0800 (PST) Received: from localhost.localdomain ([188.25.254.226]) by smtp.gmail.com with ESMTPSA id v3sm36330504wru.32.2019.12.27.13.36.50 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 27 Dec 2019 13:36: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 v3 net-next 02/11] net: phylink: make QSGMII a valid PHY mode for in-band AN Date: Fri, 27 Dec 2019 23:36:17 +0200 Message-Id: <20191227213626.4404-3-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20191227213626.4404-1-olteanv@gmail.com> References: <20191227213626.4404-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 v3: - 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 Dec 27 21:36:18 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 1215795 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="ifrY46Gg"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 47l0XC0D0wz9sR7 for ; Sat, 28 Dec 2019 08:36:59 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726597AbfL0Vg5 (ORCPT ); Fri, 27 Dec 2019 16:36:57 -0500 Received: from mail-wr1-f66.google.com ([209.85.221.66]:35485 "EHLO mail-wr1-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726509AbfL0Vgz (ORCPT ); Fri, 27 Dec 2019 16:36:55 -0500 Received: by mail-wr1-f66.google.com with SMTP id g17so27264644wro.2 for ; Fri, 27 Dec 2019 13:36: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=BQgcorw9ZHn+5QoaS5q7D5CecKqMr/nL6G8U/tu3Bnk=; b=ifrY46Ggzd9V2/7paI9lVjq+g58fC7cxFENnPoXHnCTrGhMqv8aatCV8cp6pHa9GDM DsvMimeEd9cIXhM3OHURs+xIokEnKDg/ojJ8SP2HZC5bo8uQOtx6KMPp2MiPrkMLs+li GKmR2rioDlqx81YrxKfvKypa1QzbSkvnnG4hCr5cd/M24HHopjeK9uorLnq0PGrK2nyP iYBa1SQIf7HDUcv85eqcRMHIyDVwP1HPrwTFLgmDKVu3WOfdW+7R6brLSBIxW0aMSRLd 6lkHcYY+UkrLw3rktW4NAiG0yp0FLC8gv0IdEPe0fa8npdebYhqLsj4h2ZZ7gVY4h/R/ oV9g== 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=BQgcorw9ZHn+5QoaS5q7D5CecKqMr/nL6G8U/tu3Bnk=; b=KMTs1mEYOjplPrud4TK7U1YhPfwNJs536jsakinxQJCt4uRDTWKkT0UqL9kOzxckVo gaRhBaBTOkpjslczxkfc0OX5DBriwk/UWef9yBzhK2qNVmeg7jroRrfHs4Aqu6gzGwAd DTtw6RMAY4YjVGTGfef/Ztnexg44O9WY9thNkQ4lqReUNjVUwZ+ek8nv9Vnhfi7jZPfZ huqp+ExOigTZoz+i6SBp/lW5ubhqReNdJRQLLAGP+yGexVhkekOse7Y1qRphyRaLH/9I IFB8R3N1PSz0CWVKRrEU110MCxCrzmJ93SLPWNBTHvlUGHcWbnLs8Pz2UaYk3Y9O5zRA I/cQ== X-Gm-Message-State: APjAAAV4+gvOE8MiowwlcbS0hzksfLK5GRSOd1ZIKGyZJlCGdaS5Zco3 tUuaEWilHR5NzcIPSP1KHOU= X-Google-Smtp-Source: APXvYqzO7I9yybsqaxBs93Myi4jJ2eQvS1qLZyqITQwealMKwII4bwzsfYAdaVgn8zRRuLocYcDgJg== X-Received: by 2002:a5d:6284:: with SMTP id k4mr51677180wru.398.1577482613206; Fri, 27 Dec 2019 13:36:53 -0800 (PST) Received: from localhost.localdomain ([188.25.254.226]) by smtp.gmail.com with ESMTPSA id v3sm36330504wru.32.2019.12.27.13.36.51 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 27 Dec 2019 13:36: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 v3 net-next 03/11] net: phylink: add support for polling MAC PCS Date: Fri, 27 Dec 2019 23:36:18 +0200 Message-Id: <20191227213626.4404-4-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20191227213626.4404-1-olteanv@gmail.com> References: <20191227213626.4404-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 v3: - Patch is new. 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 Dec 27 21:36:19 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 1215797 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="EHSf9KU4"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 47l0XF5Hrsz9sR7 for ; Sat, 28 Dec 2019 08:37:01 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726627AbfL0VhA (ORCPT ); Fri, 27 Dec 2019 16:37:00 -0500 Received: from mail-wm1-f68.google.com ([209.85.128.68]:35679 "EHLO mail-wm1-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726377AbfL0Vg4 (ORCPT ); Fri, 27 Dec 2019 16:36:56 -0500 Received: by mail-wm1-f68.google.com with SMTP id p17so9333391wmb.0 for ; Fri, 27 Dec 2019 13:36:55 -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=xfN39Oz9ZmU3S9X/6XdkFgiI/Sthvy4DYI4YSniTb7c=; b=EHSf9KU4DMULjdTdwlddRnmQSykp56QBoXBk4ODRMXPUSyLvNjUOPsmSE2udNOnQS/ u8b/bdCBUlIXlzU2rk6PjACUoRNKoD0xhXf30k9peN5kdTrXojH80clpf+rCZ3dncS7j qtBdSW5hMZWJCXOOMT+5TWGAxsGSoL/M43hswvncinXwFM2rW/VIero2Fa2CUkHH6/cN i83BXLdVgZHpFyeFOJBYbEpxpYFrEOTNSYFB330YzdxqdwfXZ52CVzeEJTd2l5Tl4dP9 Pn7PgHusWpfz0jWxgNNRdhGC7UAFPEOI/u3bqpvCcPaYrDK24NX+V3+9Jsy+NDPn9X+x bMdA== 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=xfN39Oz9ZmU3S9X/6XdkFgiI/Sthvy4DYI4YSniTb7c=; b=qS2B4EZ+jw90mKXIblFNWNuLjKu3dqhE8wGyi3Vz+VRRpE4Nq9rmNQxOzfB/01Slgg 0EVD0a0NSMyijXMqMlLV811ZjPWrL0BYLCrzN8GsgESqzETXEyUET/HYpvi66tB8Rbyc CWRJanBC8PWqj7ijNZa9QJhX7XhfMbWg4s9DXwy++tpktFpIu76nUfvtBPIhi8Z2+HQo jss5Ft1pQv3TS8mWGgn89vyQPxxm6e6+R1Pmuk/aLHFg+XAcEiusXPaJthM9ttcyA/mA jE/6Hq7tkhkBKRg+pfEgE7qO8knpWKoGSQsmyB2mtgKmZyybA2z7J57vSdxpvEpE0N5u ETCg== X-Gm-Message-State: APjAAAWnHX7hUvAm4hveTxZY9/FjjHzsNNN5Xqbd86aqUdrx/7OpIYcy jThqQRlauAQoslBbpjX8jZQ= X-Google-Smtp-Source: APXvYqyBL+6WP0bmhhAf2VlbXadsIs26o5yafMWxF9EI/1YKtIn2K45SLSxKzy+bJaTZHfycQu3H/Q== X-Received: by 2002:a1c:5a0a:: with SMTP id o10mr20177157wmb.114.1577482614478; Fri, 27 Dec 2019 13:36:54 -0800 (PST) Received: from localhost.localdomain ([188.25.254.226]) by smtp.gmail.com with ESMTPSA id v3sm36330504wru.32.2019.12.27.13.36.53 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 27 Dec 2019 13:36:54 -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 v3 net-next 04/11] net: dsa: Pass pcs_poll flag from driver to PHYLINK Date: Fri, 27 Dec 2019 23:36:19 +0200 Message-Id: <20191227213626.4404-5-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20191227213626.4404-1-olteanv@gmail.com> References: <20191227213626.4404-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 v3: - Patch is new. 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 Dec 27 21:36:20 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 1215801 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="G3qYYmpX"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 47l0XS18FZz9sR7 for ; Sat, 28 Dec 2019 08:37:12 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726809AbfL0VhK (ORCPT ); Fri, 27 Dec 2019 16:37:10 -0500 Received: from mail-wm1-f65.google.com ([209.85.128.65]:40163 "EHLO mail-wm1-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726552AbfL0Vg6 (ORCPT ); Fri, 27 Dec 2019 16:36:58 -0500 Received: by mail-wm1-f65.google.com with SMTP id t14so9301237wmi.5 for ; Fri, 27 Dec 2019 13:36: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=K5D3W/fCixiqiMl4ZhilHiF+8en5/MvOq3+tMTVW4iQ=; b=G3qYYmpXvUgvfgr56cjceFVGlbBB8aYGhZkf7sgIwpZBDDMfOrCIjZowsKBwjh2qOY ORpVBsrKWw55oZIgJ7Xh15oDAd0Bk0G22TTMfWbMylZbejj/o/x4ZsSa8Hb19XZTTSvq yBdwAbU3b5/G2SJcwicujyTIVOnOv9ceavlsKJ5BFg4kp+ESjTGYfbwyppngffYjWGg4 a9cwXxa1EFYeOFigSpGBv0tLqwcyszglj6BrEzwwlIzHXIMgEUawpQa6anECoyQXzss1 rkGfbu+LxYKqNU+iestQtWSXSUUWyjFd2mq4QAAQbOYkdFZyG/Te0CFFUOKw0P7Kc/w2 G69Q== 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=K5D3W/fCixiqiMl4ZhilHiF+8en5/MvOq3+tMTVW4iQ=; b=Z9RPKIa0BD8ZTHUpjE7H9a2yolGtBnmwqkS80sSUIL/xYDwEqogLeofgghq40Q++Ly +RAL/tKVGIpx9Khl72LpgHwYrFmpA6k8bi8K/ctbMfiL4Rk17aT8OOTDULMykbCYuEoK xf0VhFYuGpRmh6j7lLTc8vLeRF/P3WmaBKQFmUS8rk4XlXlj0Xc6B7HrEsizoKZmJKiV KkmVztKsR8hrKYET3aj8jTG6RlbGA+0XJQ/Dh4syGoV1Mgn/TSVZzpRzwuBGNRpigTFp Fhy3Nw9JTiAAGhAxssIdz+jXq1E7JhraU7YGNEWyqEtTjzihQ/Pw7KoQlz99mHR+iOx9 92lg== X-Gm-Message-State: APjAAAWZCLZOcLkee7/pNdQqM2/tAyDZGwBWuvbZknfmHr4qRlqw2Kvp 2BgFUe3E7JXezJtR2wKtsoA= X-Google-Smtp-Source: APXvYqzP+5ydcHbRI9MpIym4+SXSqb3o5g75fu2hbOehqpWzT+mVL1I6Kq1/9BuvzIJ5sI4zKwrqwA== X-Received: by 2002:a1c:1b41:: with SMTP id b62mr20289275wmb.53.1577482615742; Fri, 27 Dec 2019 13:36:55 -0800 (PST) Received: from localhost.localdomain ([188.25.254.226]) by smtp.gmail.com with ESMTPSA id v3sm36330504wru.32.2019.12.27.13.36.54 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 27 Dec 2019 13:36: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 v3 net-next 05/11] net: phy: Add a property for controlling in-band auto-negotiation Date: Fri, 27 Dec 2019 23:36:20 +0200 Message-Id: <20191227213626.4404-6-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20191227213626.4404-1-olteanv@gmail.com> References: <20191227213626.4404-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 patch aims to solve a simple problem: for SerDes interfaces, the MAC has a PCS layer which serializes the data before passing it to the link partner (typically a PHY with its own PCS, but not necessarily, it can also be a remote PHY). Some of these SerDes protocols have a configuration word that is transmitted in-band, to establish the link parameters. Some SerDes implementations strictly require this handshake (in-band AN) to complete before passing data, while on others it may be bypassed. From a user perspective, the top-most entity of this in-band AN relationship is the MAC PCS, driven by an Ethernet driver. When the MAC PCS operates as PHY-less, there is little that can be done from our side to prevent a settings mismatch, since the link partner may be remote and outside our control. When the MAC PCS is connected to a PHY driven by the PHY library, that is when we want to ensure the in-band AN settings are in sync and can be fulfilled by both parties. This setting is ternary and requested by the MAC PCS driver. For compatibility with existing code, we introduce a IN_BAND_AN_DEFAULT state equal to 0, which means that the MAC driver, caller of the PHY library, has no opinion about in-band AN settings. It is assumed that somebody else has taken care of this setting and nothing should be done. When the PHYLIB caller requests an explicit setting (IN_BAND_AN_ENABLED or IN_BAND_AN_DISABLED), the PHY driver must veto this operation in its .config_init callback if it can't do as requested. As mentioned, this is to avoid mismatches, which will be taken to result in failure to pass data between MAC and PHY. As for the caller of PHYLIB, it shouldn't hardcode any particular value for phydev->in_band_autoneg, but rather take this information from a board description file such as device tree. This gives the caller a chance to veto the setting as well, if it doesn't support it, and it leaves the choice at the level of individual MAC-PHY instances instead of drivers. A more-or-less standard device tree binding that can be used to gather this information is: managed = "in-band-status"; which PHYLINK already uses. Make PHYLINK the first user of this scheme, by parsing the DT binding mentioned above and passing it to the PHY library. Signed-off-by: Vladimir Oltean --- Changes in v3: - Patch is new. drivers/net/phy/phylink.c | 2 ++ include/linux/phy.h | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index 73a01ea5fc55..af574d5a8426 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -878,6 +878,8 @@ int phylink_of_phy_connect(struct phylink *pl, struct device_node *dn, if (!phy_dev) return -ENODEV; + phy_dev->in_band_autoneg = (pl->cfg_link_an_mode == MLO_AN_INBAND); + ret = phy_attach_direct(pl->netdev, phy_dev, flags, pl->link_interface); if (ret) diff --git a/include/linux/phy.h b/include/linux/phy.h index 30e599c454db..090e4ba303e2 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -318,6 +318,22 @@ enum phy_state { PHY_NOLINK, }; +/* Settings for system-side PHY auto-negotiation: + * - IN_BAND_AN_DEFAULT: the PHY is left in the default configuration, be it + * out-of-reset, preconfigured by boot firmware, etc. In-band AN can be + * disabled, enabled or even unsupported when this setting is on. + * - IN_BAND_AN_ENABLED: the PHY must enable system-side auto-negotiation with + * the attached MAC, or veto this setting if it can't. + * - IN_BAND_AN_DISABLED: the PHY must disable or bypass system-side + * auto-negotiation with the attached MAC (and force the link settings if + * applicable), or veto this setting if it can't. + */ +enum phy_in_band_autoneg { + IN_BAND_AN_DEFAULT = 0, + IN_BAND_AN_ENABLED, + IN_BAND_AN_DISABLED, +}; + /** * struct phy_c45_device_ids - 802.3-c45 Device Identifiers * @devices_in_package: Bit vector of devices present. @@ -388,6 +404,8 @@ struct phy_device { /* Interrupts are enabled */ unsigned interrupts:1; + enum phy_in_band_autoneg in_band_autoneg; + enum phy_state state; u32 dev_flags; From patchwork Fri Dec 27 21:36:21 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 1215802 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="rfDOBMQQ"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 47l0XV11Vgz9sPV for ; Sat, 28 Dec 2019 08:37:14 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726832AbfL0VhM (ORCPT ); Fri, 27 Dec 2019 16:37:12 -0500 Received: from mail-wm1-f66.google.com ([209.85.128.66]:39041 "EHLO mail-wm1-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726509AbfL0Vg6 (ORCPT ); Fri, 27 Dec 2019 16:36:58 -0500 Received: by mail-wm1-f66.google.com with SMTP id 20so9299370wmj.4 for ; Fri, 27 Dec 2019 13:36:57 -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=7V5fBkcvHjU8SacvQbqTer+Jpx5oyXeJlKJjN0LLnos=; b=rfDOBMQQ4BoFHPI0zQvR1Hms0QkpBbCKBI+F/5uUziflwr3T1HEFjTVzeML0g4KcDz HpuURUTdITnQ1+Zr+6AU/fQ98dWAbPOVrTzaK5tzrNeOvNYyy8VvDJRMTVWgkiWgitjC nNXQl1B7/NouY7wecqjCqhXLGXO46PBezFIWslqkE6fU8UJtUZF7uoaLUViyyEl+tPDv 5WHdQbmG/yjfjUuUQtqT51kQUNmdqu/ew5X6vblrf5QpJGG9EX+OmwGnqhQILInqAgjo zrR3r5wsPPmv3uGV1EY8c+pJwf9UX5xYXmL4LZ0gvap0Rzxy8ixHVWPy1m9JcG/uBx59 lk8g== 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=7V5fBkcvHjU8SacvQbqTer+Jpx5oyXeJlKJjN0LLnos=; b=t5FsFGAwAMlJd+BYY3QoLWiskITjUVmmDGRhL4nOBuoKYu1UC26F5/CwOPYlp4OiU1 fhpUzgMgAEN5rX7AevqU9z6L51qj+lDEDPkfG1jcgCGx68kFSe+qN7MTFxupxJOSWQ0k z3Dw3PIZgPOTFzF5sfAlcJICswJ/IAZ89D6OQadrhO/rsAq12gtf01AV4d4jIEVc6QC7 F2rNbXtG3Fx7bGSAhhAWEPPMXbpIzkuN7QSSIIyOz8cIe2S/e32PnYGuMIqB1ca9xVjc OSWb6ZFwwebYw8uBaBAtUOTtqx8MV9+zalmiSMexHRGd142gFOQr0t7+q7q2aTURXks2 US9g== X-Gm-Message-State: APjAAAUWGJFhvAoJ3kfbOPmIAMBd1IZoSyoueIN0+Uu7pWRV284GV0J7 wr1mN9x0lAct4LTuhjN4NOc= X-Google-Smtp-Source: APXvYqzyiUuqrCfMx9gkZ4inV0SIP/0jWgm9vfb8vpy/GEYXJcQKCpkdiBnFCuOLQfB8aHh4Vhfw9A== X-Received: by 2002:a05:600c:21c6:: with SMTP id x6mr19964502wmj.177.1577482617006; Fri, 27 Dec 2019 13:36:57 -0800 (PST) Received: from localhost.localdomain ([188.25.254.226]) by smtp.gmail.com with ESMTPSA id v3sm36330504wru.32.2019.12.27.13.36.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 27 Dec 2019 13:36: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 v3 net-next 06/11] net: phy: vsc8514: configure explicit in-band SGMII auto-negotiation settings Date: Fri, 27 Dec 2019 23:36:21 +0200 Message-Id: <20191227213626.4404-7-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20191227213626.4404-1-olteanv@gmail.com> References: <20191227213626.4404-1-olteanv@gmail.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Alex Marginean The IN_BAND_AN_DEFAULT setting for the VSC8514 PHY is not very reliable: its out-of-reset state is with SerDes AN disabled, but certain boot firmware (such as U-Boot) enables it during the boot process. So its final state as seen by Linux depends on whether the U-Boot PHY driver has run or not. If SGMII auto-negotiation is enabled but not acknowledged by the MAC, the PHY does not pass traffic. But otherwise, it is able to pass traffic both with AN disabled, and with AN enabled. So make it explicitly configurable. Signed-off-by: Alex Marginean Signed-off-by: Vladimir Oltean --- Changes in v3: - Patch is new. drivers/net/phy/mscc.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/net/phy/mscc.c b/drivers/net/phy/mscc.c index 50214c081164..b9a22474a715 100644 --- a/drivers/net/phy/mscc.c +++ b/drivers/net/phy/mscc.c @@ -176,6 +176,8 @@ enum rgmii_rx_clock_delay { #define SECURE_ON_PASSWD_LEN_4 0x4000 /* Extended Page 3 Registers */ +#define MSCC_PHY_SERDES_CON 16 +#define MSCC_PHY_SERDES_ANEG BIT(7) #define MSCC_PHY_SERDES_TX_VALID_CNT 21 #define MSCC_PHY_SERDES_TX_CRC_ERR_CNT 22 #define MSCC_PHY_SERDES_RX_VALID_CNT 28 @@ -2157,6 +2159,19 @@ static int vsc8514_config_init(struct phy_device *phydev) mutex_unlock(&phydev->mdio.bus->mdio_lock); + ret = phy_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_EXTENDED_3); + if (ret) + return ret; + + if (phydev->in_band_autoneg == IN_BAND_AN_ENABLED) + ret = phy_set_bits(phydev, MSCC_PHY_SERDES_CON, + MSCC_PHY_SERDES_ANEG); + else if (phydev->in_band_autoneg == IN_BAND_AN_DISABLED) + ret = phy_clear_bits(phydev, MSCC_PHY_SERDES_CON, + MSCC_PHY_SERDES_ANEG); + if (ret) + return ret; + ret = phy_write(phydev, MSCC_EXT_PAGE_ACCESS, MSCC_PHY_PAGE_STANDARD); if (ret) From patchwork Fri Dec 27 21:36:22 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 1215798 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="chO6fy/0"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 47l0XJ2nVQz9sPV for ; Sat, 28 Dec 2019 08:37:04 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726371AbfL0VhD (ORCPT ); Fri, 27 Dec 2019 16:37:03 -0500 Received: from mail-wm1-f65.google.com ([209.85.128.65]:37752 "EHLO mail-wm1-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726602AbfL0VhB (ORCPT ); Fri, 27 Dec 2019 16:37:01 -0500 Received: by mail-wm1-f65.google.com with SMTP id f129so9324736wmf.2 for ; Fri, 27 Dec 2019 13:36:59 -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=PI6Mu6bUkQ4xa8J760mGJUxE44m1xX+QrZlkblvo0aA=; b=chO6fy/0WJ0JfqSID6soFIftquTh5OdUX+diHK51611nui7kL0qvEVChvYkCsdElYY q+Vv8h9iEC1mvTSrIpVbd9QJugk+ZNNExaB/x9pzY/MdKxzsK9PyNm/qTtRT9wLZW1vJ b0JLgERGmLQ1TIt4TDeO0x67iKdJsmAclczWkn/YZnRCwadMfIihGyxYGrkIfQ9CxmmI hn0VtbIqD8SnBE/iLQKrriPz3zw4rTASN/M0FF+pfWUwmMe1mzgpXR4t+J3ZK2VqMbP5 un3mYtftP5fgkxYqcHHBPmxvC3e3Z9tubAQ6IeUZjUWHEFDQzFws6DpLaBvWWeouxLOg 1lHQ== 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=PI6Mu6bUkQ4xa8J760mGJUxE44m1xX+QrZlkblvo0aA=; b=bNIYHbd9/KiPkAe+KQtH17DGJSrt519MwO96rGkY4145wm7re+8WKzp7pqUQ6TcCyL koUoHOkx9y4N0Rc4ILB9C/1sHLI3kLj+mSH6FPxjAI1trQPFGDIm529Nkib0iq+aHAI3 oviuY4mf4I/wZW8Br8dSEQESB/7chb4q0tm8rpe3vmQwqNwAXr1+CgJZx8GMX0DFdxMa VAwYoE0D55JUNbeJzmT6bHJ955ErSnZCH1jLySxhPPiPM3IlLxbhg7lWUeO4Qh+znrrQ qhg1hHRltsJ4wbrS6jUBY5mXzU9sUsiflep0UNG4zFgvGYmkQWtuMypaqkBJujsVV+Ne Pxhw== X-Gm-Message-State: APjAAAW2F2FWhZmq3ltxZhd0Fsv67RDzlMyOVAayBr6vEZqIuDIAkaEu rdHjEaaXZsXAmyw/KNCdzLI= X-Google-Smtp-Source: APXvYqwORFmqttWczIzKN2V7WhuG9d4crMTffL46VTcqCYAbmrSo8LqdUc1M1JKXbLvVcbAkMXnoYw== X-Received: by 2002:a1c:9c4c:: with SMTP id f73mr21829424wme.125.1577482618371; Fri, 27 Dec 2019 13:36:58 -0800 (PST) Received: from localhost.localdomain ([188.25.254.226]) by smtp.gmail.com with ESMTPSA id v3sm36330504wru.32.2019.12.27.13.36.57 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 27 Dec 2019 13:36:57 -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 v3 net-next 07/11] enetc: Make MDIO accessors more generic and export to include/linux/fsl Date: Fri, 27 Dec 2019 23:36:22 +0200 Message-Id: <20191227213626.4404-8-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20191227213626.4404-1-olteanv@gmail.com> References: <20191227213626.4404-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 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 51f543ef37a8..7df4482af1b7 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 Dec 27 21:36:23 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 1215799 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="dvjHdYBP"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 47l0XK3mJNz9sR7 for ; Sat, 28 Dec 2019 08:37:05 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726667AbfL0VhE (ORCPT ); Fri, 27 Dec 2019 16:37:04 -0500 Received: from mail-wm1-f66.google.com ([209.85.128.66]:37753 "EHLO mail-wm1-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726075AbfL0VhB (ORCPT ); Fri, 27 Dec 2019 16:37:01 -0500 Received: by mail-wm1-f66.google.com with SMTP id f129so9324749wmf.2 for ; Fri, 27 Dec 2019 13:37:00 -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=rz3IKddwzsp7RU1FAAdxYiRU4evSdprM+Rl6DrXOpPI=; b=dvjHdYBPFCIOrwJCTJJovQiYQdZp4j0NCdZISad1Ggv77aNzAMUtqpKKj5ygQ/jROI Io9786uwU4ZT4PIZjpJgfeT5dERbP9DvQAc75h6yI0PKjl+uJkSTgeAAVZQNsS6RTm5n YiVBHI6kOuMp2PPmNs7cXbk/NSahCnpiaxO6UfUWZnc2Njk6ZYh301J0s8uoBLVU66u6 /WOTyH1BL3Lrc2W4aMoBH1AK82/AnI423ylEFpzkgOWSly4H8uH/5ZaVM+GClLileRcl 3ySyMcdFixxObHLWBX2/RLMbD2RmfB/NyCHyAlw39kLVaiQ4df0jmdCSGuAJLOinuj5F 1RoQ== 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=rz3IKddwzsp7RU1FAAdxYiRU4evSdprM+Rl6DrXOpPI=; b=R3ZyckUPF/hPSfaSvkZCYzIhPBaecHZHFOHaUhB6TyUSF7hV8KG9b6+RAs0uvNLAZ3 QDB+7bAAPO72eQ10Uz1juSJ9YI6vzZUzxaGLP/XPft642MRrKb3kMq328H8TDmf9Fuen 2cAttsZGeCZahrmSqvv9AFEKSCZyFOBI10HAIuOwPsO5xh578YJfS6BraKR4xd3MXqAk xZ82w+7tSpFY8ay+1dPsbSzbFSfhQESeV2uzEyOaqDXsNuUqzHFwfHnTzvoe9IqZQ0Ma hmtYo5D6Mgs8DewCmbMIqWlMZtqk2M2MBc61JvR2WOKoh5HAf+PcVMHdLKhQ5S7O3Cj5 zsqA== X-Gm-Message-State: APjAAAVanrBS/EXA8tRvB5AG5iX+sqOVLG6rBcGf7Be6x7YeQpXtrO0Q oESZ3fg3//vXNT6ISZoQwPE= X-Google-Smtp-Source: APXvYqz13lFM6NY7BIX6dykSI+GhjohLNIumjMvAzozBErz2wFTz9IfhNe/LI9qIjg1f2t1L8zuVhg== X-Received: by 2002:a7b:c00c:: with SMTP id c12mr20529473wmb.174.1577482619630; Fri, 27 Dec 2019 13:36:59 -0800 (PST) Received: from localhost.localdomain ([188.25.254.226]) by smtp.gmail.com with ESMTPSA id v3sm36330504wru.32.2019.12.27.13.36.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 27 Dec 2019 13:36:59 -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 v3 net-next 08/11] enetc: Set MDIO_CFG_HOLD to the recommended value of 2 Date: Fri, 27 Dec 2019 23:36:23 +0200 Message-Id: <20191227213626.4404-9-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20191227213626.4404-1-olteanv@gmail.com> References: <20191227213626.4404-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 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 Dec 27 21:36:24 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 1215800 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="gPuGbfY8"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 47l0XL4HK3z9sPV for ; Sat, 28 Dec 2019 08:37:06 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726688AbfL0VhF (ORCPT ); Fri, 27 Dec 2019 16:37:05 -0500 Received: from mail-wr1-f66.google.com ([209.85.221.66]:40552 "EHLO mail-wr1-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726628AbfL0VhC (ORCPT ); Fri, 27 Dec 2019 16:37:02 -0500 Received: by mail-wr1-f66.google.com with SMTP id c14so27252856wrn.7 for ; Fri, 27 Dec 2019 13:37:01 -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=eY6ZMTsDwezDW4jo5zoA1I50kL17vbuuaabkHmF3h90=; b=gPuGbfY8bccNc22WB9EBMTp5ffJZWnQ0KPcMc+D4Z7o6iqrzsniVXqX1qeKe+AojKd i8pFwXujTiCDwtFRgNekaeOL2PHvAEKcE2t9VEOZMlMXoU1qbMkztpycnUmADrEz33rT BVuvNaLAITRs13Va7KkIZn5SguB4oq8hqTaWYMyuTTZJkbmKy2AxJFHHrf6Sp5S6gRWg p1S7oU7vTU7tb/e09ekXscMI521eyxdCAwrZznMm46h4xbZBF4g8BmXux22X0Kgjg4VJ DTKm7uEBsrSrM/sKDunUmWuTKy2XSs5+Mta/okEpsExCMBH3W57PD/TKIRNuwkyPs+Im aQNg== 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=eY6ZMTsDwezDW4jo5zoA1I50kL17vbuuaabkHmF3h90=; b=bcreWP0FUu0sQFVh5oy9MwJfkPzaq2NGaNpEPvX9J2PgdG+9hFTaRsuIrj+Ij+vK0K odaMI3ZVSFZWkprcHwdORShjG3FmKIT9dLC5G8UWY9R1M9uTpvYrj044JkUGs3cLV7qg 73nZrbGLyCV/ALwcFRW1CtwgRc3q2ARFhwjDGwSDzAd+5itsitrH20Q/zwxwtdOmZays 9HnVpLwqVRwP2GjpKg4diKLMqfTtXnamC5FyVrF3vx/c5Nc/DcEWUH8qmTpxB3BN3Pql aPzPXCYBZ/EVWjFxBcda2P7y04SFYtT/JE6GGUt6KLgqNRzn/xOD1oNyHqufyKWsV+nv 5RaA== X-Gm-Message-State: APjAAAUhFoXWnWqU6VLhL1jVYba9kra+l+X5cGm7ZLI5G2LvbfTM1iER B9GZ6PhXhsU+IkCj5sgBN8E= X-Google-Smtp-Source: APXvYqy4OG85aHopFnJ8KUQtOcyfVnanAsD3uk1NHQ0oasEAg85Ew2EzR7CcSEtl6o1gqjon5Obquw== X-Received: by 2002:adf:9c8a:: with SMTP id d10mr51714394wre.156.1577482620859; Fri, 27 Dec 2019 13:37:00 -0800 (PST) Received: from localhost.localdomain ([188.25.254.226]) by smtp.gmail.com with ESMTPSA id v3sm36330504wru.32.2019.12.27.13.36.59 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 27 Dec 2019 13:37:00 -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 v3 net-next 09/11] net: mscc: ocelot: make phy_mode a member of the common struct ocelot_port Date: Fri, 27 Dec 2019 23:36:24 +0200 Message-Id: <20191227213626.4404-10-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20191227213626.4404-1-olteanv@gmail.com> References: <20191227213626.4404-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 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 Dec 27 21:36:25 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 1215803 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="l+wpcdNf"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 47l0XW1D3Jz9sR7 for ; Sat, 28 Dec 2019 08:37:15 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726752AbfL0VhK (ORCPT ); Fri, 27 Dec 2019 16:37:10 -0500 Received: from mail-wr1-f67.google.com ([209.85.221.67]:46559 "EHLO mail-wr1-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726658AbfL0VhD (ORCPT ); Fri, 27 Dec 2019 16:37:03 -0500 Received: by mail-wr1-f67.google.com with SMTP id z7so27211087wrl.13 for ; Fri, 27 Dec 2019 13:37:02 -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=Re3b0bz8lr1F2HpvCJp0ubBbAeK4gIrOKlD0QBAZeew=; b=l+wpcdNfbbP+CmijzBeZysK/ec34EeiIf2H09jZY5/HD6opy5RyVVUVtuwePSdJo59 SfbgdgxYErgnsWZFRdvppOyI58ueCNwMoHsfA86rOjXHh1Acz2GIEgPJkxtIpVbjqrak eP/HcNcyC5bN2sDe0x2qFoiElMOpUeffKXFYXl6nSx6VWQo87yKR5bxobRjbfdWgJScP XTNme9PMi1T954BU/mpl26uFvqYlLJ0xFge2RudMqaLEmHWtS533RpYF67ws9ShZr9eD 2OYmk3r28furj/Pk8fjHBci+VNGDiCuTdT5cSjwU2iPiVgdppFbl2PiSzIZ6lD8aG6d1 f7JQ== 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=Re3b0bz8lr1F2HpvCJp0ubBbAeK4gIrOKlD0QBAZeew=; b=J0V1ddGZodbVAN6YKLvX+cFhaQYoOn/7C59U9IWhIZ5Uj1AQ6zPOc+avXLswV4q3Rs lsNZJcTwUNg6zIK0MMsZIG45h1KIWKAW61YAeUIoCSiuz5zqdFvHRuNOys0l93vw9ly7 UDSWWKbAqJUTPEUpymRcdCX4sAcsrSrB8+VMPFAUDd0a1wjVZAePnIFNSRimA5O7cign up0W3JDuTQcRFAI1XaubtuSs4T6KTO8a9H7uX20RrG6I+CQxcUFTlgdhwUmoU/3i3G3Y /VmPVlaja1ZlgGw257tiGhobEVtFYGte6bbkuOt9hYS/JcO44QwVm8KfJzSKtxyi+c7i tRWg== X-Gm-Message-State: APjAAAWp/rOWuuN2gRC7KzS++C0ErsF8XL1Q0UAjQbHc5x0yph/jp2nb w40/Ra0rkXzleLIH2uKdAjI= X-Google-Smtp-Source: APXvYqxMF2faVgGV5yQVD2LuQiKSteC10Il9F01sFwgC5J1hKkOfe/w5UgUKvHhGrfiFdHE8wCgNTQ== X-Received: by 2002:a5d:62d0:: with SMTP id o16mr51190570wrv.197.1577482622153; Fri, 27 Dec 2019 13:37:02 -0800 (PST) Received: from localhost.localdomain ([188.25.254.226]) by smtp.gmail.com with ESMTPSA id v3sm36330504wru.32.2019.12.27.13.37.00 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 27 Dec 2019 13:37:01 -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 v3 net-next 10/11] net: mscc: ocelot: export ANA, DEV and QSYS registers to include/soc/mscc Date: Fri, 27 Dec 2019 23:36:25 +0200 Message-Id: <20191227213626.4404-11-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20191227213626.4404-1-olteanv@gmail.com> References: <20191227213626.4404-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 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 Dec 27 21:36:26 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 1215804 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="iAYwAZKD"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 47l0XW6jhcz9sPV for ; Sat, 28 Dec 2019 08:37:15 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726728AbfL0VhJ (ORCPT ); Fri, 27 Dec 2019 16:37:09 -0500 Received: from mail-wr1-f66.google.com ([209.85.221.66]:42855 "EHLO mail-wr1-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726675AbfL0VhH (ORCPT ); Fri, 27 Dec 2019 16:37:07 -0500 Received: by mail-wr1-f66.google.com with SMTP id q6so27221322wro.9 for ; Fri, 27 Dec 2019 13:37:04 -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=myoJdfH8K1GhoMXSoqTso1OFwPfRRuVjCk51mI8glyU=; b=iAYwAZKDlcepu8212Yz/bLmCWsiEr41wzer8edQYGcw+MxJAm2U/aDahhRZ0yw9Q7j MODzf1WZikCwmrePMSimgbUEgELZDRYSPKpMm97WOnUbSi00pK6BH3kkezjs1r/+u0He imDR2dj58EKCv1InSCoHyJb8CbHioZD/WfqgmPC4BLrp0eirgSZz6zdyBZKWK8+09XxY ki9i2EcbeVchbYYArEdRR8pq7Wx2XcdTNOjQEdTZHkDswAQWc9dOKjjZMVMzkna0PtBR jYl4S2yu1gTWorWg6JUZ8hrkrqgTRYNlKpckrhAxWuzgkYZi3lEdyRq5VwtCrcBQIHKV 33Ag== 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=myoJdfH8K1GhoMXSoqTso1OFwPfRRuVjCk51mI8glyU=; b=sfvaC2EzWkahwgvDQpfHap9iULIsCdUM49VFpliD1bvm6tByW81wV7BgptDssP0Tn8 ur7GLs0k+qBaHvscZt1uk/etTWGD5NwJ9w2tFU8tCyrLQtXvPq/1Cx8yOvlAPbJamwCe Vb+mY+eSOT7+1BNW3vAkqibvCZ7vCgKyh1bp3p3lOl7+iMWbDtvORevtORhcbnQ04WQS zlzocI8jCz8s4UGvJYPv31BuJKbSyqWsY2nbarhlV2ZVHnIPCatpxR74EcOgb3AEU/7T yCIt2juTh6OvAnEWDb7IFVxLTpStUNOvNfvBLgmaAR1zYzc+wl/UYXiM9E8xcuV7nHEi ofrg== X-Gm-Message-State: APjAAAW0fBQ9w4QNdMFf4Bw/u0ke+XqQ6P2mQgXLYD7/ozIYlWtlmWUz meNnuLDwQvs4XiyTdcpmaYA= X-Google-Smtp-Source: APXvYqz5FiwjTZFEjZALOTI/fSMbEc541LlgAgPaIwz2Ng2u/wNQfD+hvAIx9RJ5b6ug8uICkBWDcw== X-Received: by 2002:adf:f58a:: with SMTP id f10mr54789384wro.105.1577482623580; Fri, 27 Dec 2019 13:37:03 -0800 (PST) Received: from localhost.localdomain ([188.25.254.226]) by smtp.gmail.com with ESMTPSA id v3sm36330504wru.32.2019.12.27.13.37.02 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 27 Dec 2019 13:37:03 -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 v3 net-next 11/11] net: dsa: felix: Add PCS operations for PHYLINK Date: Fri, 27 Dec 2019 23:36:26 +0200 Message-Id: <20191227213626.4404-12-olteanv@gmail.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20191227213626.4404-1-olteanv@gmail.com> References: <20191227213626.4404-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 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 | 266 ++++++++++++- drivers/net/dsa/ocelot/felix.h | 16 +- drivers/net/dsa/ocelot/felix_vsc9959.c | 501 ++++++++++++++++++++++++- 4 files changed, 768 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..236f28306f7d 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,139 @@ 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; + + /* Take MAC, Port, Phy (intern) and PCS (SGMII/Serdes) clock out of + * reset */ + ocelot_port_writel(ocelot_port, DEV_CLOCK_CFG_LINK_SPEED(state->speed), + DEV_CLOCK_CFG); + + /* No PFC */ + ocelot_write_gix(ocelot, ANA_PFC_PFC_CFG_FC_LINK_SPEED(state->speed), + ANA_PFC_PFC_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); + + /* Flow control */ + 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); +} + static void felix_get_strings(struct dsa_switch *ds, int port, u32 stringset, u8 *data) { @@ -185,10 +315,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 +399,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 +422,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 +439,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 +454,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 +514,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 +600,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..41b684fb0f36 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 switches, where both link + * partners attempt to operate as AN masters 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, so 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, };