From patchwork Thu Jun 23 13:41:01 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Karol Kolacinski X-Patchwork-Id: 1647191 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: bilbo.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=osuosl.org header.i=@osuosl.org header.a=rsa-sha256 header.s=default header.b=1n2gaTZP; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=osuosl.org (client-ip=140.211.166.133; helo=smtp2.osuosl.org; envelope-from=intel-wired-lan-bounces@osuosl.org; receiver=) Received: from smtp2.osuosl.org (smtp2.osuosl.org [140.211.166.133]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4LTLxl0g6qz9sGT for ; Thu, 23 Jun 2022 23:41:13 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id DA436400AF; Thu, 23 Jun 2022 13:41:10 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp2.osuosl.org DA436400AF DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=osuosl.org; s=default; t=1655991670; bh=Pkc9y7NRkdNP0Wxkwcc2jV4W3V7nvDF50S07eoyExCw=; h=From:To:Date:Subject:List-Id:List-Unsubscribe:List-Archive: List-Post:List-Help:List-Subscribe:Cc:From; b=1n2gaTZPYAo/sXGAYH0/OtBhhw6YpRT3BdeCkFohIDKvsWWiCoJesM4rrU0nLqdm/ tgqNNaET5dnafZRMz2V47R6k+yDRY9SUxVkEIq7C2VyZwVgESFXA5FEnNrB//+i0w1 Y9OfKd4zycCyxi/4/oeZQ1PbHfCWZsiqwn9rN/dJlPrmBhnBCh3rSfrFjr+N2IyDQ4 ZB/PV9ye4AhooMr1QXJFG0Fvm0k/x6Tl9gVOVjkLX0ZbSW0Uv9xyw05gUloPp24LA8 pL0sUAJusyGxqHptsr3VHw6bYnEv97/J8+mvcJBFgHvdgFmaKcCaAws2ZpWC5JyOv8 jb1dhp79pRiGA== X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp2.osuosl.org ([127.0.0.1]) by localhost (smtp2.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 8PdeHlhLHm7Q; Thu, 23 Jun 2022 13:41:10 +0000 (UTC) Received: from ash.osuosl.org (ash.osuosl.org [140.211.166.34]) by smtp2.osuosl.org (Postfix) with ESMTP id CA387400FD; Thu, 23 Jun 2022 13:41:09 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp2.osuosl.org CA387400FD X-Original-To: intel-wired-lan@lists.osuosl.org Delivered-To: intel-wired-lan@lists.osuosl.org Received: from smtp1.osuosl.org (smtp1.osuosl.org [140.211.166.138]) by ash.osuosl.org (Postfix) with ESMTP id 4E6E91BF405 for ; Thu, 23 Jun 2022 13:41:08 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id 212A884720 for ; Thu, 23 Jun 2022 13:41:08 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp1.osuosl.org 212A884720 X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp1.osuosl.org ([127.0.0.1]) by localhost (smtp1.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id Peso4zUfAWEF for ; Thu, 23 Jun 2022 13:41:07 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 DKIM-Filter: OpenDKIM Filter v2.11.0 smtp1.osuosl.org D4561846FF Received: from mga04.intel.com (mga04.intel.com [192.55.52.120]) by smtp1.osuosl.org (Postfix) with ESMTPS id D4561846FF for ; Thu, 23 Jun 2022 13:41:06 +0000 (UTC) X-IronPort-AV: E=McAfee;i="6400,9594,10386"; a="279489177" X-IronPort-AV: E=Sophos;i="5.92,216,1650956400"; d="scan'208";a="279489177" Received: from fmsmga002.fm.intel.com ([10.253.24.26]) by fmsmga104.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jun 2022 06:41:06 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.92,216,1650956400"; d="scan'208";a="691027892" Received: from kkolacin-desk1.igk.intel.com ([172.22.229.172]) by fmsmga002.fm.intel.com with ESMTP; 23 Jun 2022 06:41:05 -0700 From: Karol Kolacinski To: intel-wired-lan@lists.osuosl.org Date: Thu, 23 Jun 2022 15:41:01 +0200 Message-Id: <20220623134102.166331-1-karol.kolacinski@intel.com> X-Mailer: git-send-email 2.34.1 MIME-Version: 1.0 Organization: Intel Technology Poland sp. z o.o. - ul. Slowackiego 173, 80-298 Gdansk - KRS 101882 - NIP 957-07-52-316 X-Mailman-Original-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1655991666; x=1687527666; h=from:to:cc:subject:date:message-id:mime-version: content-transfer-encoding; bh=GElFWm0bl3xU117KiH01P8f4yYHRC86Q1539Bob5isY=; b=ccL7M39P4vD4CZSa1uTKaxZbipa8GuiO/NXaShAtVuXS2c473vCAbXJp lB7ue2CTRLgrcrEWbM4tCse/dkiLfU+njGYQZSv3FN2geSpWRBZcf3Gve UtXpuL600zcMZj8NqDtOUzGyTD4m+PSjgk/pugSKUGBVe1OkiqspRv7yO +3O7u1rmtJb/6Q+7QfPgHCG+ifdsg5OZrqhwe7qB7DQ2a6oE8fLsivy7w Uat+75nS4NxtTx51+SSWo1AcCtyfyuLyzPfL2lcsVQ7w14oc7vDUF3xsE 8OPu+HgH8iwSbYbGxKvFfD6ymEgkmnOyarSaKmL9vC/1XjeiqsLrQeBes Q==; X-Mailman-Original-Authentication-Results: smtp1.osuosl.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.a=rsa-sha256 header.s=Intel header.b=ccL7M39P Subject: [Intel-wired-lan] [PATCH intel-next 1/2] ice: add i2c write command X-BeenThere: intel-wired-lan@osuosl.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Intel Wired Ethernet Linux Kernel Driver Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Karol Kolacinski Errors-To: intel-wired-lan-bounces@osuosl.org Sender: "Intel-wired-lan" Add the possibility to write to connected i2c devices using the AQ command. FW may reject the write if the device is not on allowlist. Signed-off-by: Karol Kolacinski --- .../net/ethernet/intel/ice/ice_adminq_cmd.h | 7 +-- drivers/net/ethernet/intel/ice/ice_common.c | 48 ++++++++++++++++++- drivers/net/ethernet/intel/ice/ice_common.h | 4 ++ 3 files changed, 55 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h index c018f6ff8ee2..64cfdb7edaa8 100644 --- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h +++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h @@ -1396,7 +1396,7 @@ struct ice_aqc_get_link_topo { u8 rsvd[9]; }; -/* Read I2C (direct, 0x06E2) */ +/* Read/Write I2C (direct, 0x06E2/0x06E3) */ struct ice_aqc_i2c { struct ice_aqc_link_topo_addr topo_addr; __le16 i2c_addr; @@ -1406,7 +1406,7 @@ struct ice_aqc_i2c { u8 rsvd; __le16 i2c_bus_addr; - u8 rsvd2[4]; + u8 i2c_data[4]; /* Used only by write command, reserved in read. */ }; /* Read I2C Response (direct, 0x06E2) */ @@ -2125,7 +2125,7 @@ struct ice_aq_desc { struct ice_aqc_get_link_status get_link_status; struct ice_aqc_event_lan_overflow lan_overflow; struct ice_aqc_get_link_topo get_link_topo; - struct ice_aqc_i2c read_i2c; + struct ice_aqc_i2c read_write_i2c; struct ice_aqc_read_i2c_resp read_i2c_resp; } params; }; @@ -2242,6 +2242,7 @@ enum ice_adminq_opc { ice_aqc_opc_set_mac_lb = 0x0620, ice_aqc_opc_get_link_topo = 0x06E0, ice_aqc_opc_read_i2c = 0x06E2, + ice_aqc_opc_write_i2c = 0x06E3, ice_aqc_opc_set_port_id_led = 0x06E9, ice_aqc_opc_set_gpio = 0x06EC, ice_aqc_opc_get_gpio = 0x06ED, diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c index 237a2296ff96..7b0f5c63dbd4 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.c +++ b/drivers/net/ethernet/intel/ice/ice_common.c @@ -4831,7 +4831,7 @@ ice_aq_read_i2c(struct ice_hw *hw, struct ice_aqc_link_topo_addr topo_addr, int status; ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_read_i2c); - cmd = &desc.params.read_i2c; + cmd = &desc.params.read_write_i2c; if (!data) return -EINVAL; @@ -4858,6 +4858,52 @@ ice_aq_read_i2c(struct ice_hw *hw, struct ice_aqc_link_topo_addr topo_addr, return status; } +/** + * ice_aq_write_i2c + * @hw: pointer to the hw struct + * @topo_addr: topology address for a device to communicate with + * @bus_addr: 7-bit I2C bus address + * @addr: I2C memory address (I2C offset) with up to 16 bits + * @params: I2C parameters: bit [4] - I2C address type, bits [3:0] - data size to write (0-7 bytes) + * @data: pointer to data (0 to 4 bytes) to be written to the I2C device + * @cd: pointer to command details structure or NULL + * + * Write I2C (0x06E3) + * + * * Return: + * * 0 - Successful write to the i2c device + * * -EINVAL - Data size greater than 4 bytes + * * -EIO - FW error + */ +int +ice_aq_write_i2c(struct ice_hw *hw, struct ice_aqc_link_topo_addr topo_addr, + u16 bus_addr, __le16 addr, u8 params, u8 *data, + struct ice_sq_cd *cd) +{ + struct ice_aq_desc desc = { 0 }; + struct ice_aqc_i2c *cmd; + unsigned int i; + u8 data_size; + + ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_write_i2c); + cmd = &desc.params.read_write_i2c; + + data_size = FIELD_GET(ICE_AQC_I2C_DATA_SIZE_M, params); + + /* data_size limited to 4 */ + if (data_size > 4) + return -EINVAL; + + cmd->i2c_bus_addr = cpu_to_le16(bus_addr); + cmd->topo_addr = topo_addr; + cmd->i2c_params = params; + cmd->i2c_addr = addr; + + memcpy(cmd->i2c_data, data, data_size); + + return ice_aq_send_cmd(hw, &desc, NULL, 0, cd); +} + /** * ice_aq_set_driver_param - Set driver parameter to share via firmware * @hw: pointer to the HW struct diff --git a/drivers/net/ethernet/intel/ice/ice_common.h b/drivers/net/ethernet/intel/ice/ice_common.h index 6a7764dd264c..a74df1d3a002 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.h +++ b/drivers/net/ethernet/intel/ice/ice_common.h @@ -215,5 +215,9 @@ int ice_aq_read_i2c(struct ice_hw *hw, struct ice_aqc_link_topo_addr topo_addr, u16 bus_addr, __le16 addr, u8 params, u8 *data, struct ice_sq_cd *cd); +int +ice_aq_write_i2c(struct ice_hw *hw, struct ice_aqc_link_topo_addr topo_addr, + u16 bus_addr, __le16 addr, u8 params, u8 *data, + struct ice_sq_cd *cd); bool ice_fw_supports_report_dflt_cfg(struct ice_hw *hw); #endif /* _ICE_COMMON_H_ */ From patchwork Thu Jun 23 13:41:02 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Karol Kolacinski X-Patchwork-Id: 1647192 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: bilbo.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=osuosl.org header.i=@osuosl.org header.a=rsa-sha256 header.s=default header.b=wyY5rRm2; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=osuosl.org (client-ip=2605:bc80:3010::137; helo=smtp4.osuosl.org; envelope-from=intel-wired-lan-bounces@osuosl.org; receiver=) Received: from smtp4.osuosl.org (smtp4.osuosl.org [IPv6:2605:bc80:3010::137]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4LTLxp0k4gz9sGT for ; Thu, 23 Jun 2022 23:41:18 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id E6D02424D5; Thu, 23 Jun 2022 13:41:15 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org E6D02424D5 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=osuosl.org; s=default; t=1655991675; bh=AU8usFbWVHF5x9V4spcuxyaHil2JKNHe/5i8POU9GwQ=; h=From:To:Date:In-Reply-To:References:Subject:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: Cc:From; b=wyY5rRm2kaUSwdzN+NX2B462xbkLM5R24ML4Oq1Zn9kg7ytNvwyLkgov+rOfcXT/v Lqx/HTjvE+47z1MJ62nH0ogXZiw7cckdv7RaR9Pu0Lm+C8lFF3dZxFZcXQfyLyY6RF a4PqJX94CMhXnFuTW8vMJYQ3qgXVUiDNaN9TTetuQaQqS5v1TE+fIsMzPthe9E+T5M NZrXzNHBLAGwwXbOO13JLmY5rgwqkhLpp/hT61MuTaTyDxTnVE7AGqwU4TjegLZovz EaO5RF+nDIFyI+i6wvedK5KD0qLTygWoy7hzTBLPi58GNEHPl7dmFGq8Ra0hd0C/m3 Pme9V9X/xSHiA== X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp4.osuosl.org ([127.0.0.1]) by localhost (smtp4.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id V-ncLDJxlX2j; Thu, 23 Jun 2022 13:41:14 +0000 (UTC) Received: from ash.osuosl.org (ash.osuosl.org [140.211.166.34]) by smtp4.osuosl.org (Postfix) with ESMTP id DF549417A7; Thu, 23 Jun 2022 13:41:13 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org DF549417A7 X-Original-To: intel-wired-lan@lists.osuosl.org Delivered-To: intel-wired-lan@lists.osuosl.org Received: from smtp1.osuosl.org (smtp1.osuosl.org [140.211.166.138]) by ash.osuosl.org (Postfix) with ESMTP id 2116F1BF405 for ; Thu, 23 Jun 2022 13:41:11 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id F039A84720 for ; Thu, 23 Jun 2022 13:41:10 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp1.osuosl.org F039A84720 X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp1.osuosl.org ([127.0.0.1]) by localhost (smtp1.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 2tYw-G1Vhe-R for ; Thu, 23 Jun 2022 13:41:10 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 DKIM-Filter: OpenDKIM Filter v2.11.0 smtp1.osuosl.org BFAA8846FF Received: from mga04.intel.com (mga04.intel.com [192.55.52.120]) by smtp1.osuosl.org (Postfix) with ESMTPS id BFAA8846FF for ; Thu, 23 Jun 2022 13:41:09 +0000 (UTC) X-IronPort-AV: E=McAfee;i="6400,9594,10386"; a="279489186" X-IronPort-AV: E=Sophos;i="5.92,216,1650956400"; d="scan'208";a="279489186" Received: from fmsmga002.fm.intel.com ([10.253.24.26]) by fmsmga104.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jun 2022 06:41:09 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.92,216,1650956400"; d="scan'208";a="691027934" Received: from kkolacin-desk1.igk.intel.com ([172.22.229.172]) by fmsmga002.fm.intel.com with ESMTP; 23 Jun 2022 06:41:07 -0700 From: Karol Kolacinski To: intel-wired-lan@lists.osuosl.org Date: Thu, 23 Jun 2022 15:41:02 +0200 Message-Id: <20220623134102.166331-2-karol.kolacinski@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220623134102.166331-1-karol.kolacinski@intel.com> References: <20220623134102.166331-1-karol.kolacinski@intel.com> MIME-Version: 1.0 Organization: Intel Technology Poland sp. z o.o. - ul. Slowackiego 173, 80-298 Gdansk - KRS 101882 - NIP 957-07-52-316 X-Mailman-Original-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1655991669; x=1687527669; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=mVDg9Jp3HzHYeOUWl1Lsukqy1lcxBC70R30Pkoym7Mc=; b=RHzRGSwgEgcSuh9KM9DFj0u0N6y0H18ig1/j6tii0gLeJq+6uDTxL90M CLNm3H0RjNOVvh55aXK+IBcJSSNxkGrKynWVOSZ0Hj0Bwim0AZ9YvTaNn k2j1fDTfWd3vfrPNfSZGCGmzQLBBGcucGMsPoFHEFcTCCMlFqJXouZzbc jU+ACcQ/D+EX9XC0SPhw8HLCDYymWJsheaznlRHP4CqqvGXlNHi7ewq+0 3jl/DqmjOkdtykmAJ/xVI2FQ/STUgitEil8S3WVSwcvTeVAOxUZGyTpHn fRwDMn2nTRIIzf31h3inC80BM3vIK6g8F8MjPO1m2pO8Tr8V1IEm0ETwx Q==; X-Mailman-Original-Authentication-Results: smtp1.osuosl.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.a=rsa-sha256 header.s=Intel header.b=RHzRGSwg Subject: [Intel-wired-lan] [PATCH intel-next 2/2] ice: add write functionality for GNSS TTY X-BeenThere: intel-wired-lan@osuosl.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Intel Wired Ethernet Linux Kernel Driver Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Karol Kolacinski Errors-To: intel-wired-lan-bounces@osuosl.org Sender: "Intel-wired-lan" Add the possibility to write raw bytes to the GNSS module through the first TTY device. This allows user to configure the module. Create a second read-only TTY device. Signed-off-by: Karol Kolacinski --- .../device_drivers/ethernet/intel/ice.rst | 9 + drivers/net/ethernet/intel/ice/ice.h | 4 +- drivers/net/ethernet/intel/ice/ice_gnss.c | 242 ++++++++++++++++-- drivers/net/ethernet/intel/ice/ice_gnss.h | 30 ++- 4 files changed, 254 insertions(+), 31 deletions(-) diff --git a/Documentation/networking/device_drivers/ethernet/intel/ice.rst b/Documentation/networking/device_drivers/ethernet/intel/ice.rst index 67b7a701ce9e..dc2e60ced927 100644 --- a/Documentation/networking/device_drivers/ethernet/intel/ice.rst +++ b/Documentation/networking/device_drivers/ethernet/intel/ice.rst @@ -901,6 +901,15 @@ To enable/disable UDP Segmentation Offload, issue the following command:: # ethtool -K tx-udp-segmentation [off|on] +GNSS module +----------- +Allows user to read messages from the GNSS module and write supported commands. +If the module is physically present, driver creates 2 TTYs for each supported +device in /dev, ttyGNSS_:_0 and _1. First one (_0) is RW and +the second one is RO. +The protocol of write commands is dependent on the GNSS module as the driver +writes raw bytes from the TTY to the GNSS i2c. Please refer to the module +documentation for details. Performance Optimization ======================== diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index 70ed8afdbf2b..3f18aa7d8247 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -545,8 +545,8 @@ struct ice_pf { u32 msg_enable; struct ice_ptp ptp; struct tty_driver *ice_gnss_tty_driver; - struct tty_port gnss_tty_port; - struct gnss_serial *gnss_serial; + struct tty_port *gnss_tty_port[ICE_GNSS_TTY_MINOR_DEVICES]; + struct gnss_serial *gnss_serial[ICE_GNSS_TTY_MINOR_DEVICES]; u16 num_rdma_msix; /* Total MSIX vectors for RDMA driver */ u16 rdma_base_vector; diff --git a/drivers/net/ethernet/intel/ice/ice_gnss.c b/drivers/net/ethernet/intel/ice/ice_gnss.c index c6d755f707aa..3e4f08453eff 100644 --- a/drivers/net/ethernet/intel/ice/ice_gnss.c +++ b/drivers/net/ethernet/intel/ice/ice_gnss.c @@ -1,10 +1,103 @@ // SPDX-License-Identifier: GPL-2.0 -/* Copyright (C) 2018-2021, Intel Corporation. */ +/* Copyright (C) 2021-2022, Intel Corporation. */ #include "ice.h" #include "ice_lib.h" #include +/** + * ice_gnss_do_write - Write data to internal GNSS + * @pf: board private structure + * @buf: command buffer + * @size: command buffer size + * + * Write UBX command data to the GNSS receiver + */ +static unsigned int +ice_gnss_do_write(struct ice_pf *pf, unsigned char *buf, unsigned int size) +{ + struct ice_aqc_link_topo_addr link_topo; + struct ice_hw *hw = &pf->hw; + unsigned int offset = 0; + int err = 0; + + memset(&link_topo, 0, sizeof(struct ice_aqc_link_topo_addr)); + link_topo.topo_params.index = ICE_E810T_GNSS_I2C_BUS; + link_topo.topo_params.node_type_ctx |= + FIELD_PREP(ICE_AQC_LINK_TOPO_NODE_CTX_M, + ICE_AQC_LINK_TOPO_NODE_CTX_OVERRIDE); + + /* It's not possible to write a single byte to u-blox. + * Write all bytes in a loop until there are 6 or less bytes left. If + * there are exactly 6 bytes left, the last write would be only a byte. + * In this case, do 4+2 bytes writes instead of 5+1. Otherwise, do the + * last 2 to 5 bytes write. + */ + while (size - offset > ICE_GNSS_UBX_WRITE_BYTES + 1) { + err = ice_aq_write_i2c(hw, link_topo, ICE_GNSS_UBX_I2C_BUS_ADDR, + cpu_to_le16(buf[offset]), + ICE_MAX_I2C_WRITE_BYTES, + &buf[offset + 1], NULL); + if (err) + goto err_out; + + offset += ICE_GNSS_UBX_WRITE_BYTES; + } + + /* Single byte would be written. Write 4 bytes instead of 5. */ + if (size - offset == ICE_GNSS_UBX_WRITE_BYTES + 1) { + err = ice_aq_write_i2c(hw, link_topo, ICE_GNSS_UBX_I2C_BUS_ADDR, + cpu_to_le16(buf[offset]), + ICE_MAX_I2C_WRITE_BYTES - 1, + &buf[offset + 1], NULL); + if (err) + goto err_out; + + offset += ICE_GNSS_UBX_WRITE_BYTES - 1; + } + + /* Do the last write, 2 to 5 bytes. */ + err = ice_aq_write_i2c(hw, link_topo, ICE_GNSS_UBX_I2C_BUS_ADDR, + cpu_to_le16(buf[offset]), size - offset - 1, + &buf[offset + 1], NULL); + if (err) + goto err_out; + + return size; + +err_out: + dev_err(ice_pf_to_dev(pf), "GNSS failed to write, offset=%u, size=%u, err=%d\n", + offset, size, err); + + return offset; +} + +/** + * ice_gnss_write_pending - Write all pending data to internal GNSS + * @work: GNSS write work structure + */ +static void ice_gnss_write_pending(struct kthread_work *work) +{ + struct gnss_serial *gnss = container_of(work, struct gnss_serial, + write_work); + struct ice_pf *pf = gnss->back; + + if (!list_empty(&gnss->queue)) { + struct gnss_write_buf *write_buf = NULL; + unsigned int bytes; + + write_buf = list_first_entry(&gnss->queue, + struct gnss_write_buf, queue); + + bytes = ice_gnss_do_write(pf, write_buf->buf, write_buf->size); + dev_dbg(ice_pf_to_dev(pf), "%u bytes written to GNSS\n", bytes); + + list_del(&write_buf->queue); + kfree(write_buf->buf); + kfree(write_buf); + } +} + /** * ice_gnss_read - Read data from internal GNSS module * @work: GNSS read work structure @@ -104,8 +197,9 @@ static void ice_gnss_read(struct kthread_work *work) /** * ice_gnss_struct_init - Initialize GNSS structure for the TTY * @pf: Board private structure + * @index: TTY device index */ -static struct gnss_serial *ice_gnss_struct_init(struct ice_pf *pf) +static struct gnss_serial *ice_gnss_struct_init(struct ice_pf *pf, int index) { struct device *dev = ice_pf_to_dev(pf); struct kthread_worker *kworker; @@ -118,9 +212,11 @@ static struct gnss_serial *ice_gnss_struct_init(struct ice_pf *pf) mutex_init(&gnss->gnss_mutex); gnss->open_count = 0; gnss->back = pf; - pf->gnss_serial = gnss; + pf->gnss_serial[index] = gnss; kthread_init_delayed_work(&gnss->read_work, ice_gnss_read); + INIT_LIST_HEAD(&gnss->queue); + kthread_init_work(&gnss->write_work, ice_gnss_write_pending); /* Allocate a kworker for handling work required for the GNSS TTY * writes. */ @@ -156,10 +252,10 @@ static int ice_gnss_tty_open(struct tty_struct *tty, struct file *filp) tty->driver_data = NULL; /* Get the serial object associated with this tty pointer */ - gnss = pf->gnss_serial; + gnss = pf->gnss_serial[tty->index]; if (!gnss) { /* Initialize GNSS struct on the first device open */ - gnss = ice_gnss_struct_init(pf); + gnss = ice_gnss_struct_init(pf, tty->index); if (!gnss) return -ENOMEM; } @@ -212,25 +308,100 @@ static void ice_gnss_tty_close(struct tty_struct *tty, struct file *filp) } /** - * ice_gnss_tty_write - Dummy TTY write function to avoid kernel panic + * ice_gnss_tty_write - Write GNSS data * @tty: pointer to the tty_struct * @buf: pointer to the user data - * @cnt: the number of characters that was able to be sent to the hardware (or - * queued to be sent at a later time) + * @count: the number of characters queued to be sent to the HW + * + * The write function call is called by the user when there is data to be sent + * to the hardware. First the tty core receives the call, and then it passes the + * data on to the tty driver’s write function. The tty core also tells the tty + * driver the size of the data being sent. + * If any errors happen during the write call, a negative error value should be + * returned instead of the number of characters queued to be written. */ static int -ice_gnss_tty_write(struct tty_struct *tty, const unsigned char *buf, int cnt) +ice_gnss_tty_write(struct tty_struct *tty, const unsigned char *buf, int count) { - return 0; + struct gnss_write_buf *write_buf; + struct gnss_serial *gnss; + unsigned char *cmd_buf; + struct ice_pf *pf; + int err = count; + + /* We cannot write a single byte using our I2C implementation. */ + if (count <= 1 || count > ICE_GNSS_TTY_WRITE_BUF) + return -EINVAL; + + gnss = tty->driver_data; + if (!gnss) + return -EFAULT; + + pf = (struct ice_pf *)tty->driver->driver_state; + if (!pf) + return -EFAULT; + + /* Only allow to write on TTY 0 */ + if (gnss != pf->gnss_serial[0]) + return -EIO; + + mutex_lock(&gnss->gnss_mutex); + + if (!gnss->open_count) { + err = -EINVAL; + goto exit; + } + + cmd_buf = kcalloc(count, sizeof(*buf), GFP_KERNEL); + if (!cmd_buf) { + err = -ENOMEM; + goto exit; + } + + memcpy(cmd_buf, buf, count); + + /* Send the data out to a hardware port */ + write_buf = kzalloc(sizeof(*write_buf), GFP_KERNEL); + if (!write_buf) { + err = -ENOMEM; + goto exit; + } + + write_buf->buf = cmd_buf; + write_buf->size = count; + INIT_LIST_HEAD(&write_buf->queue); + list_add_tail(&write_buf->queue, &gnss->queue); + kthread_queue_work(gnss->kworker, &gnss->write_work); +exit: + mutex_unlock(&gnss->gnss_mutex); + return err; } /** - * ice_gnss_tty_write_room - Dummy TTY write_room function to avoid kernel panic + * ice_gnss_tty_write_room - Returns the numbers of characters to be written. * @tty: pointer to the tty_struct + * + * This routine returns the numbers of characters the tty driver will accept + * for queuing to be written or 0 if either the TTY is not open or user + * tries to write to the TTY other than the first. */ static unsigned int ice_gnss_tty_write_room(struct tty_struct *tty) { - return 0; + struct gnss_serial *gnss = tty->driver_data; + + /* Only allow to write on TTY 0*/ + if (!gnss || gnss != gnss->back->gnss_serial[0]) + return 0; + + mutex_lock(&gnss->gnss_mutex); + + if (!gnss->open_count) { + mutex_unlock(&gnss->gnss_mutex); + return 0; + } + + mutex_unlock(&gnss->gnss_mutex); + return ICE_GNSS_TTY_WRITE_BUF; } static const struct tty_operations tty_gps_ops = { @@ -250,11 +421,13 @@ static struct tty_driver *ice_gnss_create_tty_driver(struct ice_pf *pf) const int ICE_TTYDRV_NAME_MAX = 14; struct tty_driver *tty_driver; char *ttydrv_name; + unsigned int i; int err; - tty_driver = tty_alloc_driver(1, TTY_DRIVER_REAL_RAW); + tty_driver = tty_alloc_driver(ICE_GNSS_TTY_MINOR_DEVICES, + TTY_DRIVER_REAL_RAW); if (IS_ERR(tty_driver)) { - dev_err(ice_pf_to_dev(pf), "Failed to allocate memory for GNSS TTY\n"); + dev_err(dev, "Failed to allocate memory for GNSS TTY\n"); return NULL; } @@ -284,23 +457,32 @@ static struct tty_driver *ice_gnss_create_tty_driver(struct ice_pf *pf) tty_driver->driver_state = pf; tty_set_operations(tty_driver, &tty_gps_ops); - pf->gnss_serial = NULL; + for (i = 0; i < ICE_GNSS_TTY_MINOR_DEVICES; i++) { + pf->gnss_tty_port[i] = kzalloc(sizeof(*pf->gnss_tty_port[i]), + GFP_KERNEL); + pf->gnss_serial[i] = NULL; - tty_port_init(&pf->gnss_tty_port); - tty_port_link_device(&pf->gnss_tty_port, tty_driver, 0); + tty_port_init(pf->gnss_tty_port[i]); + tty_port_link_device(pf->gnss_tty_port[i], tty_driver, i); + } err = tty_register_driver(tty_driver); if (err) { - dev_err(ice_pf_to_dev(pf), "Failed to register TTY driver err=%d\n", - err); + dev_err(dev, "Failed to register TTY driver err=%d\n", err); - tty_port_destroy(&pf->gnss_tty_port); + for (i = 0; i < ICE_GNSS_TTY_MINOR_DEVICES; i++) { + tty_port_destroy(pf->gnss_tty_port[i]); + kfree(pf->gnss_tty_port[i]); + } kfree(ttydrv_name); tty_driver_kref_put(pf->ice_gnss_tty_driver); return NULL; } + for (i = 0; i < ICE_GNSS_TTY_MINOR_DEVICES; i++) + dev_info(dev, "%s%d registered\n", ttydrv_name, i); + return tty_driver; } @@ -328,17 +510,25 @@ void ice_gnss_init(struct ice_pf *pf) */ void ice_gnss_exit(struct ice_pf *pf) { + unsigned int i; + if (!test_bit(ICE_FLAG_GNSS, pf->flags) || !pf->ice_gnss_tty_driver) return; - tty_port_destroy(&pf->gnss_tty_port); + for (i = 0; i < ICE_GNSS_TTY_MINOR_DEVICES; i++) { + if (pf->gnss_tty_port[i]) { + tty_port_destroy(pf->gnss_tty_port[i]); + kfree(pf->gnss_tty_port[i]); + } - if (pf->gnss_serial) { - struct gnss_serial *gnss = pf->gnss_serial; + if (pf->gnss_serial[i]) { + struct gnss_serial *gnss = pf->gnss_serial[i]; - kthread_cancel_delayed_work_sync(&gnss->read_work); - kfree(gnss); - pf->gnss_serial = NULL; + kthread_cancel_work_sync(&gnss->write_work); + kthread_cancel_delayed_work_sync(&gnss->read_work); + kfree(gnss); + pf->gnss_serial[i] = NULL; + } } tty_unregister_driver(pf->ice_gnss_tty_driver); diff --git a/drivers/net/ethernet/intel/ice/ice_gnss.h b/drivers/net/ethernet/intel/ice/ice_gnss.h index 9211adb2372c..f454dd1d9285 100644 --- a/drivers/net/ethernet/intel/ice/ice_gnss.h +++ b/drivers/net/ethernet/intel/ice/ice_gnss.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0 */ -/* Copyright (C) 2018-2021, Intel Corporation. */ +/* Copyright (C) 2021-2022, Intel Corporation. */ #ifndef _ICE_GNSS_H_ #define _ICE_GNSS_H_ @@ -8,14 +8,34 @@ #include #define ICE_E810T_GNSS_I2C_BUS 0x2 +#define ICE_GNSS_TIMER_DELAY_TIME (HZ / 10) /* 0.1 second per message */ +/* Create 2 minor devices, both using the same GNSS module. First one is RW, + * second one RO. + */ +#define ICE_GNSS_TTY_MINOR_DEVICES 2 +#define ICE_GNSS_TTY_WRITE_BUF 250 +#define ICE_MAX_I2C_DATA_SIZE FIELD_MAX(ICE_AQC_I2C_DATA_SIZE_M) +#define ICE_MAX_I2C_WRITE_BYTES 4 + +/* u-blox ZED-F9T specific definitions */ #define ICE_GNSS_UBX_I2C_BUS_ADDR 0x42 /* Data length register is big endian */ #define ICE_GNSS_UBX_DATA_LEN_H 0xFD #define ICE_GNSS_UBX_DATA_LEN_WIDTH 2 #define ICE_GNSS_UBX_EMPTY_DATA 0xFF -#define ICE_GNSS_TIMER_DELAY_TIME (HZ / 10) /* 0.1 second per message */ -#define ICE_MAX_I2C_DATA_SIZE FIELD_MAX(ICE_AQC_I2C_DATA_SIZE_M) +/* For u-blox writes are performed without address so the first byte to write is + * passed as I2C addr parameter. + */ +#define ICE_GNSS_UBX_WRITE_BYTES (ICE_MAX_I2C_WRITE_BYTES + 1) #define ICE_MAX_UBX_READ_TRIES 255 +#define ICE_MAX_UBX_ACK_READ_TRIES 4095 + +struct gnss_write_buf { + struct list_head queue; + unsigned int size; + unsigned char *buf; +}; + /** * struct gnss_serial - data used to initialize GNSS TTY port @@ -25,6 +45,8 @@ * @gnss_mutex: gnss_mutex used to protect GNSS serial operations * @kworker: kwork thread for handling periodic work * @read_work: read_work function for handling GNSS reads + * @write_work: write_work function for handling GNSS writes + * @queue: write buffers queue */ struct gnss_serial { struct ice_pf *back; @@ -33,6 +55,8 @@ struct gnss_serial { struct mutex gnss_mutex; /* protects GNSS serial structure */ struct kthread_worker *kworker; struct kthread_delayed_work read_work; + struct kthread_work write_work; + struct list_head queue; }; #if IS_ENABLED(CONFIG_TTY)