From patchwork Fri Jul 16 21:24:27 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tony Nguyen X-Patchwork-Id: 479561 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 93731C12002 for ; Fri, 16 Jul 2021 21:21:34 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 7B28D613D8 for ; Fri, 16 Jul 2021 21:21:34 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235006AbhGPVY2 (ORCPT ); Fri, 16 Jul 2021 17:24:28 -0400 Received: from mga02.intel.com ([134.134.136.20]:9335 "EHLO mga02.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235211AbhGPVYU (ORCPT ); Fri, 16 Jul 2021 17:24:20 -0400 X-IronPort-AV: E=McAfee;i="6200,9189,10047"; a="197980604" X-IronPort-AV: E=Sophos;i="5.84,246,1620716400"; d="scan'208";a="197980604" Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by orsmga101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 16 Jul 2021 14:21:25 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.84,246,1620716400"; d="scan'208";a="574434579" Received: from anguy11-desk2.jf.intel.com ([10.166.244.147]) by fmsmga001.fm.intel.com with ESMTP; 16 Jul 2021 14:21:24 -0700 From: Tony Nguyen To: davem@davemloft.net, kuba@kernel.org Cc: Kurt Kanzenbach , netdev@vger.kernel.org, anthony.l.nguyen@intel.com, sasha.neftin@intel.com, vitaly.lifshits@intel.com, vinicius.gomes@intel.com, Sebastian Andrzej Siewior , Dvora Fuxbrumer Subject: [PATCH net-next 5/5] igc: Export LEDs Date: Fri, 16 Jul 2021 14:24:27 -0700 Message-Id: <20210716212427.821834-6-anthony.l.nguyen@intel.com> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20210716212427.821834-1-anthony.l.nguyen@intel.com> References: <20210716212427.821834-1-anthony.l.nguyen@intel.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Kurt Kanzenbach Each i225 has three LEDs. Export them via the LED class framework. Each LED is controllable via sysfs. Example: $ cd /sys/class/leds/igc_led0 $ cat brightness # Current Mode $ cat max_brightness # 15 $ echo 0 > brightness # Mode 0 $ echo 1 > brightness # Mode 1 The brightness field here reflects the different LED modes ranging from 0 to 15. Signed-off-by: Kurt Kanzenbach Reviewed-by: Sebastian Andrzej Siewior Tested-by: Dvora Fuxbrumer Signed-off-by: Tony Nguyen --- drivers/net/ethernet/intel/Kconfig | 1 + drivers/net/ethernet/intel/igc/igc.h | 10 ++ drivers/net/ethernet/intel/igc/igc_defines.h | 10 ++ drivers/net/ethernet/intel/igc/igc_main.c | 132 +++++++++++++++++++ drivers/net/ethernet/intel/igc/igc_regs.h | 2 + 5 files changed, 155 insertions(+) diff --git a/drivers/net/ethernet/intel/Kconfig b/drivers/net/ethernet/intel/Kconfig index 82744a7501c7..3639cf79cfae 100644 --- a/drivers/net/ethernet/intel/Kconfig +++ b/drivers/net/ethernet/intel/Kconfig @@ -335,6 +335,7 @@ config IGC tristate "Intel(R) Ethernet Controller I225-LM/I225-V support" default n depends on PCI + depends on LEDS_CLASS help This driver supports Intel(R) Ethernet Controller I225-LM/I225-V family of adapters. diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h index a0ecfe5a4078..2df0fd2b9ecf 100644 --- a/drivers/net/ethernet/intel/igc/igc.h +++ b/drivers/net/ethernet/intel/igc/igc.h @@ -13,6 +13,7 @@ #include #include #include +#include #include "igc_hw.h" @@ -239,8 +240,17 @@ struct igc_adapter { struct timespec64 start; struct timespec64 period; } perout[IGC_N_PEROUT]; + + /* LEDs */ + struct mutex led_mutex; + struct led_classdev led0; + struct led_classdev led1; + struct led_classdev led2; }; +#define led_to_igc(ldev, led) \ + container_of(ldev, struct igc_adapter, led) + void igc_up(struct igc_adapter *adapter); void igc_down(struct igc_adapter *adapter); int igc_open(struct net_device *netdev); diff --git a/drivers/net/ethernet/intel/igc/igc_defines.h b/drivers/net/ethernet/intel/igc/igc_defines.h index c6315690e20f..156c3ef57c0a 100644 --- a/drivers/net/ethernet/intel/igc/igc_defines.h +++ b/drivers/net/ethernet/intel/igc/igc_defines.h @@ -144,6 +144,16 @@ #define IGC_CTRL_SDP0_DIR 0x00400000 /* SDP0 Data direction */ #define IGC_CTRL_SDP1_DIR 0x00800000 /* SDP1 Data direction */ +/* LED Control */ +#define IGC_LEDCTL_LED0_MODE_SHIFT 0 +#define IGC_LEDCTL_LED0_MODE_MASK GENMASK(3, 0) +#define IGC_LEDCTL_LED1_MODE_SHIFT 8 +#define IGC_LEDCTL_LED1_MODE_MASK GENMASK(11, 8) +#define IGC_LEDCTL_LED2_MODE_SHIFT 16 +#define IGC_LEDCTL_LED2_MODE_MASK GENMASK(19, 16) + +#define IGC_CONNSW_AUTOSENSE_EN 0x1 + /* As per the EAS the maximum supported size is 9.5KB (9728 bytes) */ #define MAX_JUMBO_FRAME_SIZE 0x2600 diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index 11385c380947..100819dcc7dd 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -6130,6 +6130,134 @@ int igc_set_spd_dplx(struct igc_adapter *adapter, u32 spd, u8 dplx) return -EINVAL; } +static void igc_select_led(struct igc_adapter *adapter, int led, + u32 *mask, u32 *shift) +{ + switch (led) { + case 0: + *mask = IGC_LEDCTL_LED0_MODE_MASK; + *shift = IGC_LEDCTL_LED0_MODE_SHIFT; + break; + case 1: + *mask = IGC_LEDCTL_LED1_MODE_MASK; + *shift = IGC_LEDCTL_LED1_MODE_SHIFT; + break; + case 2: + *mask = IGC_LEDCTL_LED2_MODE_MASK; + *shift = IGC_LEDCTL_LED2_MODE_SHIFT; + break; + default: + *mask = *shift = 0; + dev_err(&adapter->pdev->dev, "Unknown led %d selected!", led); + } +} + +static void igc_led_set(struct igc_adapter *adapter, int led, u16 brightness) +{ + struct igc_hw *hw = &adapter->hw; + u32 shift, mask, ledctl; + + igc_select_led(adapter, led, &mask, &shift); + + mutex_lock(&adapter->led_mutex); + ledctl = rd32(IGC_LEDCTL); + ledctl &= ~mask; + ledctl |= brightness << shift; + wr32(IGC_LEDCTL, ledctl); + mutex_unlock(&adapter->led_mutex); +} + +static enum led_brightness igc_led_get(struct igc_adapter *adapter, int led) +{ + struct igc_hw *hw = &adapter->hw; + u32 shift, mask, ledctl; + + igc_select_led(adapter, led, &mask, &shift); + + mutex_lock(&adapter->led_mutex); + ledctl = rd32(IGC_LEDCTL); + mutex_unlock(&adapter->led_mutex); + + return (ledctl & mask) >> shift; +} + +static void igc_led0_set(struct led_classdev *ldev, enum led_brightness b) +{ + struct igc_adapter *adapter = led_to_igc(ldev, led0); + + igc_led_set(adapter, 0, b); +} + +static enum led_brightness igc_led0_get(struct led_classdev *ldev) +{ + struct igc_adapter *adapter = led_to_igc(ldev, led0); + + return igc_led_get(adapter, 0); +} + +static void igc_led1_set(struct led_classdev *ldev, enum led_brightness b) +{ + struct igc_adapter *adapter = led_to_igc(ldev, led1); + + igc_led_set(adapter, 1, b); +} + +static enum led_brightness igc_led1_get(struct led_classdev *ldev) +{ + struct igc_adapter *adapter = led_to_igc(ldev, led1); + + return igc_led_get(adapter, 1); +} + +static void igc_led2_set(struct led_classdev *ldev, enum led_brightness b) +{ + struct igc_adapter *adapter = led_to_igc(ldev, led2); + + igc_led_set(adapter, 2, b); +} + +static enum led_brightness igc_led2_get(struct led_classdev *ldev) +{ + struct igc_adapter *adapter = led_to_igc(ldev, led2); + + return igc_led_get(adapter, 2); +} + +static int igc_led_setup(struct igc_adapter *adapter) +{ + /* Setup */ + mutex_init(&adapter->led_mutex); + + adapter->led0.name = "igc_led0"; + adapter->led0.max_brightness = 15; + adapter->led0.brightness_set = igc_led0_set; + adapter->led0.brightness_get = igc_led0_get; + + adapter->led1.name = "igc_led1"; + adapter->led1.max_brightness = 15; + adapter->led1.brightness_set = igc_led1_set; + adapter->led1.brightness_get = igc_led1_get; + + adapter->led2.name = "igc_led2"; + adapter->led2.max_brightness = 15; + adapter->led2.brightness_set = igc_led2_set; + adapter->led2.brightness_get = igc_led2_get; + + /* Register leds */ + led_classdev_register(&adapter->pdev->dev, &adapter->led0); + led_classdev_register(&adapter->pdev->dev, &adapter->led1); + led_classdev_register(&adapter->pdev->dev, &adapter->led2); + + return 0; +} + +static void igc_led_destroy(struct igc_adapter *adapter) +{ + led_classdev_unregister(&adapter->led0); + led_classdev_unregister(&adapter->led1); + led_classdev_unregister(&adapter->led2); +} + /** * igc_probe - Device Initialization Routine * @pdev: PCI device information struct @@ -6357,6 +6485,8 @@ static int igc_probe(struct pci_dev *pdev, pm_runtime_put_noidle(&pdev->dev); + igc_led_setup(adapter); + return 0; err_register: @@ -6398,6 +6528,8 @@ static void igc_remove(struct pci_dev *pdev) igc_ptp_stop(adapter); + igc_led_destroy(adapter); + set_bit(__IGC_DOWN, &adapter->state); del_timer_sync(&adapter->watchdog_timer); diff --git a/drivers/net/ethernet/intel/igc/igc_regs.h b/drivers/net/ethernet/intel/igc/igc_regs.h index 828c3501c448..f6247b00c4e3 100644 --- a/drivers/net/ethernet/intel/igc/igc_regs.h +++ b/drivers/net/ethernet/intel/igc/igc_regs.h @@ -10,6 +10,8 @@ #define IGC_EECD 0x00010 /* EEPROM/Flash Control - RW */ #define IGC_CTRL_EXT 0x00018 /* Extended Device Control - RW */ #define IGC_MDIC 0x00020 /* MDI Control - RW */ +#define IGC_LEDCTL 0x00E00 /* LED Control - RW */ +#define IGC_MDICNFG 0x00E04 /* MDC/MDIO Configuration - RW */ #define IGC_CONNSW 0x00034 /* Copper/Fiber switch control - RW */ #define IGC_VET 0x00038 /* VLAN Ether Type - RW */ #define IGC_I225_PHPM 0x00E14 /* I225 PHY Power Management */