Re: [Intel-wired-lan] [PATCH iwl-net] ice: ensure periodic output start time is in the future
> -Original Message- > From: Intel-wired-lan On Behalf Of Jacob > Keller > Sent: 20 February 2025 03:43 > To: Nguyen, Anthony L ; Kitszel, Przemyslaw > ; Kubalewski, Arkadiusz > ; Kolacinski, Karol > Cc: intel-wired-...@lists.osuosl.org; net...@vger.kernel.org; Keller, Jacob E > Subject: [Intel-wired-lan] [PATCH iwl-net] ice: ensure periodic output start > time is in the future > > From: Karol Kolacinski > > On E800 series hardware, if the start time for a periodic output signal is > programmed into GLTSYN_TGT_H and GLTSYN_TGT_L registers, the hardware logic > locks up and the periodic output signal never starts. Any future attempt to > reprogram the clock function is futile as the hardware will not reset until a > power on. > > The ice_ptp_cfg_perout function has logic to prevent this, as it checks if > the requested start time is in the past. If so, a new start time is > calculated by rounding up. > > Since commit d755a7e129a5 ("ice: Cache perout/extts requests and check > flags"), the rounding is done to the nearest multiple of the clock period, > rather than to a full second. This is more accurate, since it ensures the > signal matches the user request precisely. > > Unfortunately, there is a race condition with this rounding logic. If the > current time is close to the multiple of the period, we could calculate a > target time that is extremely soon. It takes time for the software to program > the registers, during which time this requested start time could become a > start time in the past. If that happens, the periodic output signal will lock > up. > > For large enough periods, or for the logic prior to the mentioned commit, > this is unlikely. However, with the new logic rounding to the period and with > a small enough period, this becomes inevitable. > > For example, attempting to enable a 10MHz signal requires a period of 100 > nanoseconds. This means in the *best* case, we have 99 nanoseconds to program > the clock output. This is essentially impossible, and thus such a small > period practically guarantees that the clock output function will lock up. > > To fix this, add some slop to the clock time used to check if the start time > is in the past. Because it is not critical that output signals start > immediately, but it *is* critical that we do not brick the function, 0.5 > seconds is selected. > This does mean that any requested output will be > delayed by at least 0.5 seconds. > > This slop is applied before rounding, so that we always round up to the > nearest multiple of the period that is at least 0.5 seconds in the future, > ensuring a minimum of 0.5 seconds to program the clock output registers. > > Finally, to ensure that the hardware registers programming the clock output > complete in a timely manner, add a write flush to the end of > ice_ptp_write_perout. This ensures we don't risk any issue with PCIe > transaction batching. > > Strictly speaking, this fixes a race condition all the way back at the > initial implementation of periodic output programming, as it is theoretically > possible to trigger this bug even on the old logic when always rounding to a > full second. However, the window is narrow, and the code has been refactored > heavily since then, making a direct backport not apply cleanly. > > Fixes: d755a7e129a5 ("ice: Cache perout/extts requests and check flags") > Signed-off-by: Karol Kolacinski > Signed-off-by: Jacob Keller > --- > drivers/net/ethernet/intel/ice/ice_ptp.c | 6 -- > 1 file changed, 4 insertions(+), 2 deletions(-) > Tested-by: Rinitha S (A Contingent worker at Intel)
[Intel-wired-lan] [PATCH iwl-next v8 00/15] ixgbe: Add basic devlink support
Create devlink specific directory for more convenient future feature development. Flashing and reloading are supported only by E610 devices. Introduce basic FW/NVM validation since devlink reload introduces possibility of runtime NVM update. Check FW API version, FW recovery mode and FW rollback mode. Introduce minimal recovery probe to let user to reload the faulty FW when recovery mode is detected. This series is based on the series introducing initial E610 device support: https://lore.kernel.org/intel-wired-lan/20241205084450.4651-1-piotr.kwapulin...@intel.com/ --- v3: introduce to the series additional patch touching devlink/dev.c v4: introduce to the series additional patch changing netdev allocation --- Andrii Staikov (1): ixgbe: add support for FW rollback mode Jedrzej Jagielski (10): devlink: add value check to devlink_info_version_put() ixgbe: add initial devlink support ixgbe: add handler for devlink .info_get() ixgbe: add .info_get extension specific for E610 devices ixgbe: add E610 functions getting PBA and FW ver info ixgbe: extend .info_get with() stored versions ixgbe: add device flash update via devlink ixgbe: add support for devlink reload ixgbe: add FW API version check ixgbe: add E610 implementation of FW recovery mode Przemek Kitszel (1): ixgbe: wrap netdev_priv() usage Slawomir Mrozowicz (3): ixgbe: add E610 functions for acquiring flash data ixgbe: read the OROM version information ixgbe: read the netlist version information Documentation/networking/devlink/index.rst|1 + Documentation/networking/devlink/ixgbe.rst| 110 ++ drivers/net/ethernet/intel/Kconfig|2 + drivers/net/ethernet/intel/ixgbe/Makefile |3 +- .../ethernet/intel/ixgbe/devlink/devlink.c| 585 +++ .../ethernet/intel/ixgbe/devlink/devlink.h| 10 + drivers/net/ethernet/intel/ixgbe/ixgbe.h | 21 + .../net/ethernet/intel/ixgbe/ixgbe_82598.c|1 + .../net/ethernet/intel/ixgbe/ixgbe_82599.c|1 + .../net/ethernet/intel/ixgbe/ixgbe_common.c |1 + .../net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c | 56 +- drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c | 1515 +++-- drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h | 16 + .../net/ethernet/intel/ixgbe/ixgbe_ethtool.c | 86 +- drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c | 12 +- .../ethernet/intel/ixgbe/ixgbe_fw_update.c| 707 .../ethernet/intel/ixgbe/ixgbe_fw_update.h| 12 + .../net/ethernet/intel/ixgbe/ixgbe_ipsec.c| 10 +- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 269 ++- .../net/ethernet/intel/ixgbe/ixgbe_sriov.c| 16 +- drivers/net/ethernet/intel/ixgbe/ixgbe_type.h |5 + .../ethernet/intel/ixgbe/ixgbe_type_e610.h| 161 +- drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c |1 + drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c |1 + drivers/net/ethernet/intel/ixgbe/ixgbe_xsk.c |2 +- net/devlink/dev.c |2 +- 26 files changed, 3364 insertions(+), 242 deletions(-) create mode 100644 Documentation/networking/devlink/ixgbe.rst create mode 100644 drivers/net/ethernet/intel/ixgbe/devlink/devlink.c create mode 100644 drivers/net/ethernet/intel/ixgbe/devlink/devlink.h create mode 100644 drivers/net/ethernet/intel/ixgbe/ixgbe_fw_update.c create mode 100644 drivers/net/ethernet/intel/ixgbe/ixgbe_fw_update.h base-commit: 0a5f2afff8673e66160725b8ec8310f47c74f8b9 -- 2.31.1
[Intel-wired-lan] [PATCH iwl-next v8 11/15] ixgbe: add device flash update via devlink
Use the pldmfw library to implement device flash update for the Intel ixgbe networking device driver specifically for E610 devices. This support uses the devlink flash update interface. Using the pldmfw library, the provided firmware file will be scanned for the three major components, "fw.undi" for the Option ROM, "fw.mgmt" for the main NVM module containing the primary device firmware, and "fw.netlist" containing the netlist module. The flash is separated into two banks, the active bank containing the running firmware, and the inactive bank which we use for update. Each module is updated in a staged process. First, the inactive bank is erased, preparing the device for update. Second, the contents of the component are copied to the inactive portion of the flash. After all components are updated, the driver signals the device to switch the active bank during the next EMP reset. With this implementation, basic flash update for the E610 hardware is supported. Reviewed-by: Jacob Keller Tested-by: Bharath R Co-developed-by: Slawomir Mrozowicz Signed-off-by: Slawomir Mrozowicz Co-developed-by: Piotr Kwapulinski Signed-off-by: Piotr Kwapulinski Co-developed-by: Stefan Wegrzyn Signed-off-by: Stefan Wegrzyn Signed-off-by: Jedrzej Jagielski --- v5: fix caps->nvm_unified_update assignment v8: fix doc --- Documentation/networking/devlink/ixgbe.rst| 27 + drivers/net/ethernet/intel/Kconfig| 1 + drivers/net/ethernet/intel/ixgbe/Makefile | 2 +- .../ethernet/intel/ixgbe/devlink/devlink.c| 4 + drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c | 210 ++ drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h | 11 + .../ethernet/intel/ixgbe/ixgbe_fw_update.c| 668 ++ .../ethernet/intel/ixgbe/ixgbe_fw_update.h| 12 + .../ethernet/intel/ixgbe/ixgbe_type_e610.h| 64 ++ 9 files changed, 998 insertions(+), 1 deletion(-) create mode 100644 drivers/net/ethernet/intel/ixgbe/ixgbe_fw_update.c create mode 100644 drivers/net/ethernet/intel/ixgbe/ixgbe_fw_update.h diff --git a/Documentation/networking/devlink/ixgbe.rst b/Documentation/networking/devlink/ixgbe.rst index a41073a62776..aa4eab95b3d5 100644 --- a/Documentation/networking/devlink/ixgbe.rst +++ b/Documentation/networking/devlink/ixgbe.rst @@ -64,3 +64,30 @@ The ``ixgbe`` driver reports the following versions - running - 0xee16ced7 - The first 4 bytes of the hash of the netlist module contents. + +Flash Update + + +The ``ixgbe`` driver implements support for flash update using the +``devlink-flash`` interface. It supports updating the device flash using a +combined flash image that contains the ``fw.mgmt``, ``fw.undi``, and +``fw.netlist`` components. + +.. list-table:: List of supported overwrite modes + :widths: 5 95 + + * - Bits + - Behavior + * - ``DEVLINK_FLASH_OVERWRITE_SETTINGS`` + - Do not preserve settings stored in the flash components being + updated. This includes overwriting the port configuration that + determines the number of physical functions the device will + initialize with. + * - ``DEVLINK_FLASH_OVERWRITE_SETTINGS`` and ``DEVLINK_FLASH_OVERWRITE_IDENTIFIERS`` + - Do not preserve either settings or identifiers. Overwrite everything + in the flash with the contents from the provided image, without + performing any preservation. This includes overwriting device + identifying fields such as the MAC address, Vital product Data (VPD) area, + and device serial number. It is expected that this combination be used with an + image customized for the specific device. + diff --git a/drivers/net/ethernet/intel/Kconfig b/drivers/net/ethernet/intel/Kconfig index 3366738c57c8..8fecb8a4e249 100644 --- a/drivers/net/ethernet/intel/Kconfig +++ b/drivers/net/ethernet/intel/Kconfig @@ -148,6 +148,7 @@ config IXGBE depends on PTP_1588_CLOCK_OPTIONAL select MDIO select NET_DEVLINK + select PLDMFW select PHYLIB help This driver supports Intel(R) 10GbE PCI Express family of diff --git a/drivers/net/ethernet/intel/ixgbe/Makefile b/drivers/net/ethernet/intel/ixgbe/Makefile index 11f37140c0a3..ce447540d146 100644 --- a/drivers/net/ethernet/intel/ixgbe/Makefile +++ b/drivers/net/ethernet/intel/ixgbe/Makefile @@ -10,7 +10,7 @@ obj-$(CONFIG_IXGBE) += ixgbe.o ixgbe-y := ixgbe_main.o ixgbe_common.o ixgbe_ethtool.o \ ixgbe_82599.o ixgbe_82598.o ixgbe_phy.o ixgbe_sriov.o \ ixgbe_mbx.o ixgbe_x540.o ixgbe_x550.o ixgbe_lib.o ixgbe_ptp.o \ - ixgbe_xsk.o ixgbe_e610.o devlink/devlink.o + ixgbe_xsk.o ixgbe_e610.o devlink/devlink.o ixgbe_fw_update.o ixgbe-$(CONFIG_IXGBE_DCB) += ixgbe_dcb.o ixgbe_dcb_82598.o \ ixgbe_dcb_82599.o ixgbe_dcb_nl.o diff --git a/drivers/net/ethernet/intel/ixgbe/devlink/devlink.c b/drivers/net/ethernet/intel/ixgbe/devlink/devlink.c index 6b45846f0ddd..2ffe59a8881
[Intel-wired-lan] [PATCH iwl-next v8 05/15] ixgbe: add E610 functions for acquiring flash data
From: Slawomir Mrozowicz Read NVM related info from the flash. Add several helper functions used to access the flash data, find memory banks, calculate offsets, calculate the flash size. Reviewed-by: Przemek Kitszel Reviewed-by: Mateusz Polchlopek Tested-by: Bharath R Signed-off-by: Slawomir Mrozowicz Co-developed-by: Piotr Kwapulinski Signed-off-by: Piotr Kwapulinski Co-developed-by: Jedrzej Jagielski Signed-off-by: Jedrzej Jagielski --- drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c | 509 +- drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h | 1 + drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 4 + .../ethernet/intel/ixgbe/ixgbe_type_e610.h| 40 +- 4 files changed, 552 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c index 683c668672d6..3654b7e32cc8 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c @@ -2264,6 +2264,513 @@ int ixgbe_nvm_validate_checksum(struct ixgbe_hw *hw) return err; } +/** + * ixgbe_discover_flash_size - Discover the available flash size + * @hw: pointer to the HW struct + * + * The device flash could be up to 16MB in size. However, it is possible that + * the actual size is smaller. Use bisection to determine the accessible size + * of flash memory. + * + * Return: the exit code of the operation. + */ +static int ixgbe_discover_flash_size(struct ixgbe_hw *hw) +{ + u32 min_size = 0, max_size = IXGBE_ACI_NVM_MAX_OFFSET + 1; + int err; + + err = ixgbe_acquire_nvm(hw, IXGBE_RES_READ); + if (err) + return err; + + while ((max_size - min_size) > 1) { + u32 offset = (max_size + min_size) / 2; + u32 len = 1; + u8 data; + + err = ixgbe_read_flat_nvm(hw, offset, &len, &data, false); + if (err == -EIO && + hw->aci.last_status == IXGBE_ACI_RC_EINVAL) { + err = 0; + max_size = offset; + } else if (!err) { + min_size = offset; + } else { + /* an unexpected error occurred */ + goto err_read_flat_nvm; + } + } + + hw->flash.flash_size = max_size; + +err_read_flat_nvm: + ixgbe_release_nvm(hw); + + return err; +} + +/** + * ixgbe_read_sr_base_address - Read the value of a Shadow RAM pointer word + * @hw: pointer to the HW structure + * @offset: the word offset of the Shadow RAM word to read + * @pointer: pointer value read from Shadow RAM + * + * Read the given Shadow RAM word, and convert it to a pointer value specified + * in bytes. This function assumes the specified offset is a valid pointer + * word. + * + * Each pointer word specifies whether it is stored in word size or 4KB + * sector size by using the highest bit. The reported pointer value will be in + * bytes, intended for flat NVM reads. + * + * Return: the exit code of the operation. + */ +static int ixgbe_read_sr_base_address(struct ixgbe_hw *hw, u16 offset, + u32 *pointer) +{ + u16 value; + int err; + + err = ixgbe_read_ee_aci_e610(hw, offset, &value); + if (err) + return err; + + /* Determine if the pointer is in 4KB or word units */ + if (value & IXGBE_SR_NVM_PTR_4KB_UNITS) + *pointer = (value & ~IXGBE_SR_NVM_PTR_4KB_UNITS) * SZ_4K; + else + *pointer = value * sizeof(u16); + + return 0; +} + +/** + * ixgbe_read_sr_area_size - Read an area size from a Shadow RAM word + * @hw: pointer to the HW structure + * @offset: the word offset of the Shadow RAM to read + * @size: size value read from the Shadow RAM + * + * Read the given Shadow RAM word, and convert it to an area size value + * specified in bytes. This function assumes the specified offset is a valid + * area size word. + * + * Each area size word is specified in 4KB sector units. This function reports + * the size in bytes, intended for flat NVM reads. + * + * Return: the exit code of the operation. + */ +static int ixgbe_read_sr_area_size(struct ixgbe_hw *hw, u16 offset, u32 *size) +{ + u16 value; + int err; + + err = ixgbe_read_ee_aci_e610(hw, offset, &value); + if (err) + return err; + + /* Area sizes are always specified in 4KB units */ + *size = value * SZ_4K; + + return 0; +} + +/** + * ixgbe_determine_active_flash_banks - Discover active bank for each module + * @hw: pointer to the HW struct + * + * Read the Shadow RAM control word and determine which banks are active for + * the NVM, OROM, and Netlist modules. Also read and calculate the associated + * pointer and size. These values are then cached into the ixgbe_flash_info + * structure for later use in order to calculate the correct offset to read
[Intel-wired-lan] [PATCH iwl-next v8 07/15] ixgbe: read the netlist version information
From: Slawomir Mrozowicz Add functions reading the netlist version info and use them as a part of the setting NVM info procedure. Reviewed-by: Mateusz Polchlopek Tested-by: Bharath R Signed-off-by: Slawomir Mrozowicz Co-developed-by: Piotr Kwapulinski Signed-off-by: Piotr Kwapulinski Signed-off-by: Jedrzej Jagielski --- drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c | 112 ++ .../ethernet/intel/ixgbe/ixgbe_type_e610.h| 33 ++ 2 files changed, 145 insertions(+) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c index bad4bc04bb66..b34570b244d9 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c @@ -2582,6 +2582,33 @@ static int ixgbe_read_nvm_module(struct ixgbe_hw *hw, return err; } +/** + * ixgbe_read_netlist_module - Read data from the netlist module area + * @hw: pointer to the HW structure + * @bank: whether to read from the active or inactive module + * @offset: offset into the netlist to read from + * @data: storage for returned word value + * + * Read a word from the specified netlist bank. + * + * Return: the exit code of the operation. + */ +static int ixgbe_read_netlist_module(struct ixgbe_hw *hw, +enum ixgbe_bank_select bank, +u32 offset, u16 *data) +{ + __le16 data_local; + int err; + + err = ixgbe_read_flash_module(hw, bank, IXGBE_E610_SR_NETLIST_BANK_PTR, + offset * sizeof(data_local), + (u8 *)&data_local, sizeof(data_local)); + if (!err) + *data = le16_to_cpu(data_local); + + return err; +} + /** * ixgbe_read_orom_module - Read from the active Option ROM module * @hw: pointer to the HW structure @@ -2887,6 +2914,86 @@ static int ixgbe_get_nvm_ver_info(struct ixgbe_hw *hw, return 0; } +/** + * ixgbe_get_netlist_info - Read the netlist version information + * @hw: pointer to the HW struct + * @bank: whether to read from the active or inactive flash bank + * @netlist: pointer to netlist version info structure + * + * Get the netlist version information from the requested bank. Reads the Link + * Topology section to find the Netlist ID block and extract the relevant + * information into the netlist version structure. + * + * Return: the exit code of the operation. + */ +static int ixgbe_get_netlist_info(struct ixgbe_hw *hw, + enum ixgbe_bank_select bank, + struct ixgbe_netlist_info *netlist) +{ + u16 module_id, length, node_count, i; + u16 *id_blk; + int err; + + err = ixgbe_read_netlist_module(hw, bank, IXGBE_NETLIST_TYPE_OFFSET, + &module_id); + if (err) + return err; + + if (module_id != IXGBE_NETLIST_LINK_TOPO_MOD_ID) + return -EIO; + + err = ixgbe_read_netlist_module(hw, bank, IXGBE_LINK_TOPO_MODULE_LEN, + &length); + if (err) + return err; + + /* Sanity check that we have at least enough words to store the +* netlist ID block. +*/ + if (length < IXGBE_NETLIST_ID_BLK_SIZE) + return -EIO; + + err = ixgbe_read_netlist_module(hw, bank, IXGBE_LINK_TOPO_NODE_COUNT, + &node_count); + if (err) + return err; + + node_count &= IXGBE_LINK_TOPO_NODE_COUNT_M; + + id_blk = kcalloc(IXGBE_NETLIST_ID_BLK_SIZE, sizeof(*id_blk), GFP_KERNEL); + if (!id_blk) + return -ENOMEM; + + /* Read out the entire Netlist ID Block at once. */ + err = ixgbe_read_flash_module(hw, bank, IXGBE_E610_SR_NETLIST_BANK_PTR, + IXGBE_NETLIST_ID_BLK_OFFSET(node_count) * + sizeof(*id_blk), (u8 *)id_blk, + IXGBE_NETLIST_ID_BLK_SIZE * + sizeof(*id_blk)); + if (err) + goto free_id_blk; + + for (i = 0; i < IXGBE_NETLIST_ID_BLK_SIZE; i++) + id_blk[i] = le16_to_cpu(((__le16 *)id_blk)[i]); + + netlist->major = id_blk[IXGBE_NETLIST_ID_BLK_MAJOR_VER_HIGH] << 16 | +id_blk[IXGBE_NETLIST_ID_BLK_MAJOR_VER_LOW]; + netlist->minor = id_blk[IXGBE_NETLIST_ID_BLK_MINOR_VER_HIGH] << 16 | +id_blk[IXGBE_NETLIST_ID_BLK_MINOR_VER_LOW]; + netlist->type = id_blk[IXGBE_NETLIST_ID_BLK_TYPE_HIGH] << 16 | + id_blk[IXGBE_NETLIST_ID_BLK_TYPE_LOW]; + netlist->rev = id_blk[IXGBE_NETLIST_ID_BLK_REV_HIGH] << 16 | + id_blk[IXGBE_NETLIST_ID_BLK_REV_LOW]; + netlist->cust_ver = id_blk[IXGBE_NETLIST_ID_BLK_CUST_VER]; + /* Read the left m
[Intel-wired-lan] [PATCH iwl-next v8 01/15] devlink: add value check to devlink_info_version_put()
Prevent from proceeding if there's nothing to print. Suggested-by: Przemek Kitszel Reviewed-by: Jiri Pirko Reviewed-by: Kalesh AP Tested-by: Bharath R Signed-off-by: Jedrzej Jagielski --- net/devlink/dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/devlink/dev.c b/net/devlink/dev.c index d6e3db300acb..02602704bdea 100644 --- a/net/devlink/dev.c +++ b/net/devlink/dev.c @@ -775,7 +775,7 @@ static int devlink_info_version_put(struct devlink_info_req *req, int attr, req->version_cb(version_name, version_type, req->version_cb_priv); - if (!req->msg) + if (!req->msg || !*version_value) return 0; nest = nla_nest_start_noflag(req->msg, attr); -- 2.31.1
[Intel-wired-lan] [PATCH iwl-next v8 02/15] ixgbe: wrap netdev_priv() usage
From: Przemek Kitszel Wrap use of netdev_priv() in order to change the allocator of the device private structure from alloc_etherdev_mq() to the devlink in next commit. All but one netdev_priv() calls in the whole driver are replaced, the remaining one is called on MACVLAN (so not ixgbe) device. Signed-off-by: Przemek Kitszel Tested-by: Bharath R Signed-off-by: Jedrzej Jagielski --- drivers/net/ethernet/intel/ixgbe/ixgbe.h | 5 ++ .../net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c | 56 +++--- .../net/ethernet/intel/ixgbe/ixgbe_ethtool.c | 74 +-- drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c | 12 +-- .../net/ethernet/intel/ixgbe/ixgbe_ipsec.c| 10 +-- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 74 +-- .../net/ethernet/intel/ixgbe/ixgbe_sriov.c| 16 ++-- drivers/net/ethernet/intel/ixgbe/ixgbe_xsk.c | 2 +- 8 files changed, 127 insertions(+), 122 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h index e6a380d4929b..0efd6da874a5 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h @@ -830,6 +830,11 @@ struct ixgbe_adapter { spinlock_t vfs_lock; }; +static inline struct ixgbe_adapter *ixgbe_from_netdev(struct net_device *netdev) +{ + return netdev_priv(netdev); +} + static inline int ixgbe_determine_xdp_q_idx(int cpu) { if (static_key_enabled(&ixgbe_xdp_locking_key)) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c index 19d6b6fa8fb3..3dd5a16a14df 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c @@ -118,14 +118,14 @@ static int ixgbe_copy_dcb_cfg(struct ixgbe_adapter *adapter, int tc_max) static u8 ixgbe_dcbnl_get_state(struct net_device *netdev) { - struct ixgbe_adapter *adapter = netdev_priv(netdev); + struct ixgbe_adapter *adapter = ixgbe_from_netdev(netdev); return !!(adapter->flags & IXGBE_FLAG_DCB_ENABLED); } static u8 ixgbe_dcbnl_set_state(struct net_device *netdev, u8 state) { - struct ixgbe_adapter *adapter = netdev_priv(netdev); + struct ixgbe_adapter *adapter = ixgbe_from_netdev(netdev); /* Fail command if not in CEE mode */ if (!(adapter->dcbx_cap & DCB_CAP_DCBX_VER_CEE)) @@ -142,7 +142,7 @@ static u8 ixgbe_dcbnl_set_state(struct net_device *netdev, u8 state) static void ixgbe_dcbnl_get_perm_hw_addr(struct net_device *netdev, u8 *perm_addr) { - struct ixgbe_adapter *adapter = netdev_priv(netdev); + struct ixgbe_adapter *adapter = ixgbe_from_netdev(netdev); int i, j; memset(perm_addr, 0xff, MAX_ADDR_LEN); @@ -167,7 +167,7 @@ static void ixgbe_dcbnl_set_pg_tc_cfg_tx(struct net_device *netdev, int tc, u8 prio, u8 bwg_id, u8 bw_pct, u8 up_map) { - struct ixgbe_adapter *adapter = netdev_priv(netdev); + struct ixgbe_adapter *adapter = ixgbe_from_netdev(netdev); if (prio != DCB_ATTR_VALUE_UNDEFINED) adapter->temp_dcb_cfg.tc_config[tc].path[0].prio_type = prio; @@ -184,7 +184,7 @@ static void ixgbe_dcbnl_set_pg_tc_cfg_tx(struct net_device *netdev, int tc, static void ixgbe_dcbnl_set_pg_bwg_cfg_tx(struct net_device *netdev, int bwg_id, u8 bw_pct) { - struct ixgbe_adapter *adapter = netdev_priv(netdev); + struct ixgbe_adapter *adapter = ixgbe_from_netdev(netdev); adapter->temp_dcb_cfg.bw_percentage[0][bwg_id] = bw_pct; } @@ -193,7 +193,7 @@ static void ixgbe_dcbnl_set_pg_tc_cfg_rx(struct net_device *netdev, int tc, u8 prio, u8 bwg_id, u8 bw_pct, u8 up_map) { - struct ixgbe_adapter *adapter = netdev_priv(netdev); + struct ixgbe_adapter *adapter = ixgbe_from_netdev(netdev); if (prio != DCB_ATTR_VALUE_UNDEFINED) adapter->temp_dcb_cfg.tc_config[tc].path[1].prio_type = prio; @@ -210,7 +210,7 @@ static void ixgbe_dcbnl_set_pg_tc_cfg_rx(struct net_device *netdev, int tc, static void ixgbe_dcbnl_set_pg_bwg_cfg_rx(struct net_device *netdev, int bwg_id, u8 bw_pct) { - struct ixgbe_adapter *adapter = netdev_priv(netdev); + struct ixgbe_adapter *adapter = ixgbe_from_netdev(netdev); adapter->temp_dcb_cfg.bw_percentage[1][bwg_id] = bw_pct; } @@ -219,7 +219,7 @@ static void ixgbe_dcbnl_get_pg_tc_cfg_tx(struct net_device *netdev, int tc, u8 *prio, u8 *bwg_id, u8 *bw_pct, u8 *up_map) { - struct ixgbe_adapter *adapter = netdev_priv(netdev); + struct ixgbe_adapter *adapter = ixgbe_from_netdev(netd
[Intel-wired-lan] [PATCH iwl-next v8 03/15] ixgbe: add initial devlink support
Add an initial support for devlink interface to ixgbe driver. Similarly to i40e driver the implementation doesn't enable devlink to manage device-wide configuration. Devlink instance is created for each physical function of PCIe device. Create separate directory for devlink related ixgbe files and use naming scheme similar to the one used in the ice driver. Add a stub for Documentation, to be extended by further patches. Change struct ixgbe_adapter allocation to be done by devlink (Przemek), as suggested by Jiri. Reviewed-by: Mateusz Polchlopek Co-developed-by: Przemek Kitszel Signed-off-by: Przemek Kitszel Tested-by: Bharath R Signed-off-by: Jedrzej Jagielski --- v2: fix error path in probe; minor tweaks v4: alloc ixgbe_adapter by devlink --- Documentation/networking/devlink/index.rst| 1 + Documentation/networking/devlink/ixgbe.rst| 8 ++ drivers/net/ethernet/intel/Kconfig| 1 + drivers/net/ethernet/intel/ixgbe/Makefile | 3 +- .../ethernet/intel/ixgbe/devlink/devlink.c| 77 +++ .../ethernet/intel/ixgbe/devlink/devlink.h| 10 +++ drivers/net/ethernet/intel/ixgbe/ixgbe.h | 12 ++- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 30 +++- 8 files changed, 138 insertions(+), 4 deletions(-) create mode 100644 Documentation/networking/devlink/ixgbe.rst create mode 100644 drivers/net/ethernet/intel/ixgbe/devlink/devlink.c create mode 100644 drivers/net/ethernet/intel/ixgbe/devlink/devlink.h diff --git a/Documentation/networking/devlink/index.rst b/Documentation/networking/devlink/index.rst index 948c8c44e233..8319f43b5933 100644 --- a/Documentation/networking/devlink/index.rst +++ b/Documentation/networking/devlink/index.rst @@ -84,6 +84,7 @@ parameters, info versions, and other features it supports. i40e ionic ice + ixgbe mlx4 mlx5 mlxsw diff --git a/Documentation/networking/devlink/ixgbe.rst b/Documentation/networking/devlink/ixgbe.rst new file mode 100644 index ..c04ac51c6d85 --- /dev/null +++ b/Documentation/networking/devlink/ixgbe.rst @@ -0,0 +1,8 @@ +.. SPDX-License-Identifier: GPL-2.0 + += +ixgbe devlink support += + +This document describes the devlink features implemented by the ``ixgbe`` +device driver. diff --git a/drivers/net/ethernet/intel/Kconfig b/drivers/net/ethernet/intel/Kconfig index 5579fb9bfd55..3366738c57c8 100644 --- a/drivers/net/ethernet/intel/Kconfig +++ b/drivers/net/ethernet/intel/Kconfig @@ -147,6 +147,7 @@ config IXGBE depends on PCI depends on PTP_1588_CLOCK_OPTIONAL select MDIO + select NET_DEVLINK select PHYLIB help This driver supports Intel(R) 10GbE PCI Express family of diff --git a/drivers/net/ethernet/intel/ixgbe/Makefile b/drivers/net/ethernet/intel/ixgbe/Makefile index b456d102655a..11f37140c0a3 100644 --- a/drivers/net/ethernet/intel/ixgbe/Makefile +++ b/drivers/net/ethernet/intel/ixgbe/Makefile @@ -4,12 +4,13 @@ # Makefile for the Intel(R) 10GbE PCI Express ethernet driver # +subdir-ccflags-y += -I$(src) obj-$(CONFIG_IXGBE) += ixgbe.o ixgbe-y := ixgbe_main.o ixgbe_common.o ixgbe_ethtool.o \ ixgbe_82599.o ixgbe_82598.o ixgbe_phy.o ixgbe_sriov.o \ ixgbe_mbx.o ixgbe_x540.o ixgbe_x550.o ixgbe_lib.o ixgbe_ptp.o \ - ixgbe_xsk.o ixgbe_e610.o + ixgbe_xsk.o ixgbe_e610.o devlink/devlink.o ixgbe-$(CONFIG_IXGBE_DCB) += ixgbe_dcb.o ixgbe_dcb_82598.o \ ixgbe_dcb_82599.o ixgbe_dcb_nl.o diff --git a/drivers/net/ethernet/intel/ixgbe/devlink/devlink.c b/drivers/net/ethernet/intel/ixgbe/devlink/devlink.c new file mode 100644 index ..6c3452cf5d7d --- /dev/null +++ b/drivers/net/ethernet/intel/ixgbe/devlink/devlink.c @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2025, Intel Corporation. */ + +#include "ixgbe.h" +#include "devlink.h" + +static const struct devlink_ops ixgbe_devlink_ops = { +}; + +/** + * ixgbe_allocate_devlink - Allocate devlink instance + * @dev: device to allocate devlink for + * + * Allocate a devlink instance for this physical function. + * + * Return: pointer to the device adapter structure on success, + * ERR_PTR(-ENOMEM) when allocation failed. + */ +struct ixgbe_adapter *ixgbe_allocate_devlink(struct device *dev) +{ + struct ixgbe_adapter *adapter; + struct devlink *devlink; + + devlink = devlink_alloc(&ixgbe_devlink_ops, sizeof(*adapter), dev); + if (!devlink) + return ERR_PTR(-ENOMEM); + + adapter = devlink_priv(devlink); + adapter->devlink = devlink; + + return adapter; +} + +/** + * ixgbe_devlink_set_switch_id - Set unique switch ID based on PCI DSN + * @adapter: pointer to the device adapter structure + * @ppid: struct with switch id information + */ +static void ixgbe_devlink_set_switch_id(struct ixgbe_adapter *adapter, + struct netd
[Intel-wired-lan] [PATCH iwl-next v8 12/15] ixgbe: add support for devlink reload
The E610 adapters contain an embedded chip with firmware which can be updated using devlink flash. The firmware which runs on this chip is referred to as the Embedded Management Processor firmware (EMP firmware). Activating the new firmware image currently requires that the system be rebooted. This is not ideal as rebooting the system can cause unwanted downtime. The EMP firmware itself can be reloaded by issuing a special update to the device called an Embedded Management Processor reset (EMP reset). This reset causes the device to reset and reload the EMP firmware. Implement support for devlink reload with the "fw_activate" flag. This allows user space to request the firmware be activated immediately. Reviewed-by: Mateusz Polchlopek Tested-by: Bharath R Co-developed-by: Slawomir Mrozowicz Signed-off-by: Slawomir Mrozowicz Co-developed-by: Piotr Kwapulinski Signed-off-by: Piotr Kwapulinski Co-developed-by: Stefan Wegrzyn Signed-off-by: Stefan Wegrzyn Signed-off-by: Jedrzej Jagielski --- v6: fix doc --- Documentation/networking/devlink/ixgbe.rst| 17 +++ .../ethernet/intel/ixgbe/devlink/devlink.c| 112 ++ drivers/net/ethernet/intel/ixgbe/ixgbe.h | 4 + drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c | 18 +++ drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h | 1 + .../net/ethernet/intel/ixgbe/ixgbe_ethtool.c | 12 ++ .../ethernet/intel/ixgbe/ixgbe_fw_update.c| 37 +- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 5 +- 8 files changed, 199 insertions(+), 7 deletions(-) diff --git a/Documentation/networking/devlink/ixgbe.rst b/Documentation/networking/devlink/ixgbe.rst index aa4eab95b3d5..31aef3793845 100644 --- a/Documentation/networking/devlink/ixgbe.rst +++ b/Documentation/networking/devlink/ixgbe.rst @@ -91,3 +91,20 @@ combined flash image that contains the ``fw.mgmt``, ``fw.undi``, and and device serial number. It is expected that this combination be used with an image customized for the specific device. +Reload +== + +The ``ixgbe`` driver supports activating new firmware after a flash update +using ``DEVLINK_CMD_RELOAD`` with the ``DEVLINK_RELOAD_ACTION_FW_ACTIVATE`` +action. + +.. code:: shell + +$ devlink dev reload pci/:01:00.0 reload action fw_activate + +The new firmware is activated by issuing a device specific Embedded +Management Processor reset which requests the device to reset and reload the +EMP firmware image. + +The driver does not currently support reloading the driver via +``DEVLINK_RELOAD_ACTION_DRIVER_REINIT``. diff --git a/drivers/net/ethernet/intel/ixgbe/devlink/devlink.c b/drivers/net/ethernet/intel/ixgbe/devlink/devlink.c index 2ffe59a88811..391d53503627 100644 --- a/drivers/net/ethernet/intel/ixgbe/devlink/devlink.c +++ b/drivers/net/ethernet/intel/ixgbe/devlink/devlink.c @@ -352,6 +352,9 @@ static int ixgbe_devlink_info_get(struct devlink *devlink, if (!ctx) return -ENOMEM; + if (hw->mac.type == ixgbe_mac_e610) + ixgbe_refresh_fw_version(adapter); + ixgbe_info_get_dsn(adapter, ctx); err = devlink_info_serial_number_put(req, ctx->buf); if (err) @@ -393,11 +396,120 @@ static int ixgbe_devlink_info_get(struct devlink *devlink, return err; } +/** + * ixgbe_devlink_reload_empr_start - Start EMP reset to activate new firmware + * @devlink: pointer to the devlink instance to reload + * @netns_change: if true, the network namespace is changing + * @action: the action to perform. Must be DEVLINK_RELOAD_ACTION_FW_ACTIVATE + * @limit: limits on what reload should do, such as not resetting + * @extack: netlink extended ACK structure + * + * Allow user to activate new Embedded Management Processor firmware by + * issuing device specific EMP reset. Called in response to + * a DEVLINK_CMD_RELOAD with the DEVLINK_RELOAD_ACTION_FW_ACTIVATE. + * + * Note that teardown and rebuild of the driver state happens automatically as + * part of an interrupt and watchdog task. This is because all physical + * functions on the device must be able to reset when an EMP reset occurs from + * any source. + * + * Return: the exit code of the operation. + */ +static int ixgbe_devlink_reload_empr_start(struct devlink *devlink, + bool netns_change, + enum devlink_reload_action action, + enum devlink_reload_limit limit, + struct netlink_ext_ack *extack) +{ + struct ixgbe_adapter *adapter = devlink_priv(devlink); + struct ixgbe_hw *hw = &adapter->hw; + u8 pending; + int err; + + if (hw->mac.type != ixgbe_mac_e610) + return -EOPNOTSUPP; + + err = ixgbe_get_pending_updates(adapter, &pending, extack); + if (err) + return err; + + /* Pending is a bitmask of which flash banks have a pending update, +* incl
[Intel-wired-lan] [PATCH iwl-next v8 13/15] ixgbe: add FW API version check
Add E610 specific function checking whether the FW API version is compatible with the driver expectations. The major API version should be less than or equal to the expected API version. If not the driver won't be fully operational. Check the minor version, and if it is more than two versions lesser or greater than the expected version, print a message indicating that the NVM or driver should be updated respectively. Reviewed-by: Mateusz Polchlopek Co-developed-by: Piotr Kwapulinski Signed-off-by: Piotr Kwapulinski Signed-off-by: Jedrzej Jagielski --- v5: add get_fw_ver --- .../ethernet/intel/ixgbe/devlink/devlink.c| 2 ++ drivers/net/ethernet/intel/ixgbe/ixgbe.h | 1 + drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c | 1 + drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 34 +++ drivers/net/ethernet/intel/ixgbe/ixgbe_type.h | 1 + .../ethernet/intel/ixgbe/ixgbe_type_e610.h| 4 +++ 6 files changed, 43 insertions(+) diff --git a/drivers/net/ethernet/intel/ixgbe/devlink/devlink.c b/drivers/net/ethernet/intel/ixgbe/devlink/devlink.c index 391d53503627..87ec2dea5862 100644 --- a/drivers/net/ethernet/intel/ixgbe/devlink/devlink.c +++ b/drivers/net/ethernet/intel/ixgbe/devlink/devlink.c @@ -499,6 +499,8 @@ static int ixgbe_devlink_reload_empr_finish(struct devlink *devlink, *actions_performed = BIT(DEVLINK_RELOAD_ACTION_FW_ACTIVATE); + adapter->flags2 &= ~IXGBE_FLAG2_API_MISMATCH; + return 0; } diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h index 83d4d7368cda..2246997bc9fb 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h @@ -671,6 +671,7 @@ struct ixgbe_adapter { #define IXGBE_FLAG2_PHY_FW_LOAD_FAILED BIT(20) #define IXGBE_FLAG2_NO_MEDIA BIT(21) #define IXGBE_FLAG2_MOD_POWER_UNSUPPORTED BIT(22) +#define IXGBE_FLAG2_API_MISMATCH BIT(23) /* Tx fast path data */ int num_tx_queues; diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c index e6b35792fdee..5aa66534aa75 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c @@ -3877,6 +3877,7 @@ static const struct ixgbe_mac_operations mac_ops_e610 = { .led_off= ixgbe_led_off_generic, .init_led_link_act = ixgbe_init_led_link_act_generic, .reset_hw = ixgbe_reset_hw_e610, + .get_fw_ver = ixgbe_aci_get_fw_ver, .get_media_type = ixgbe_get_media_type_e610, .setup_link = ixgbe_setup_link_e610, .get_link_capabilities = ixgbe_get_link_capabilities_e610, diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 9892d3f41620..de74132f9001 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -8361,6 +8361,34 @@ static void ixgbe_reset_subtask(struct ixgbe_adapter *adapter) rtnl_unlock(); } +static int ixgbe_check_fw_api_mismatch(struct ixgbe_adapter *adapter) +{ + struct ixgbe_hw *hw = &adapter->hw; + + if (hw->mac.type != ixgbe_mac_e610) + return 0; + + if (hw->mac.ops.get_fw_ver && hw->mac.ops.get_fw_ver(hw)) + return 0; + + if (hw->api_maj_ver > IXGBE_FW_API_VER_MAJOR) { + e_dev_err("The driver for the device stopped because the NVM image is newer than expected. You must install the most recent version of the network driver.\n"); + + adapter->flags2 |= IXGBE_FLAG2_API_MISMATCH; + return -EOPNOTSUPP; + } else if (hw->api_maj_ver == IXGBE_FW_API_VER_MAJOR && + hw->api_min_ver > IXGBE_FW_API_VER_MINOR + IXGBE_FW_API_VER_DIFF_ALLOWED) { + e_dev_info("The driver for the device detected a newer version of the NVM image than expected. Please install the most recent version of the network driver.\n"); + adapter->flags2 |= IXGBE_FLAG2_API_MISMATCH; + } else if (hw->api_maj_ver < IXGBE_FW_API_VER_MAJOR || + hw->api_min_ver < IXGBE_FW_API_VER_MINOR - IXGBE_FW_API_VER_DIFF_ALLOWED) { + e_dev_info("The driver for the device detected an older version of the NVM image than expected. Please update the NVM image.\n"); + adapter->flags2 |= IXGBE_FLAG2_API_MISMATCH; + } + + return 0; +} + /** * ixgbe_check_fw_error - Check firmware for errors * @adapter: the adapter private structure @@ -8371,6 +8399,7 @@ static bool ixgbe_check_fw_error(struct ixgbe_adapter *adapter) { struct ixgbe_hw *hw = &adapter->hw; u32 fwsm; + int err; /* read fwsm.ext_err_ind register and log errors */ fwsm = IXGBE_READ
[Intel-wired-lan] [PATCH iwl-next v8 15/15] ixgbe: add support for FW rollback mode
From: Andrii Staikov The driver should detect whether the device entered FW rollback mode and then notify user with the dedicated message including FW and NVM versions. Even if the driver detected rollback mode, this should not result in an probe error and the normal flow proceeds. FW tries to rollback to “old” operational FW located in the inactive NVM bank in cases when newly loaded FW exhibits faulty behavior. If something goes wrong during boot the FW may switch into rollback mode in an attempt to avoid recovery mode and stay operational. After rollback is successful, the banks are swapped, and the “rollback” bank becomes the active bank for the next reset. Reviewed-by: Mateusz Polchlopek Signed-off-by: Andrii Staikov Signed-off-by: Jedrzej Jagielski --- .../ethernet/intel/ixgbe/devlink/devlink.c| 3 +- drivers/net/ethernet/intel/ixgbe/ixgbe.h | 1 + drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c | 33 +++ drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 26 +++ drivers/net/ethernet/intel/ixgbe/ixgbe_type.h | 2 ++ .../ethernet/intel/ixgbe/ixgbe_type_e610.h| 1 + 6 files changed, 65 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/ixgbe/devlink/devlink.c b/drivers/net/ethernet/intel/ixgbe/devlink/devlink.c index 87ec2dea5862..88335912bd6f 100644 --- a/drivers/net/ethernet/intel/ixgbe/devlink/devlink.c +++ b/drivers/net/ethernet/intel/ixgbe/devlink/devlink.c @@ -499,7 +499,8 @@ static int ixgbe_devlink_reload_empr_finish(struct devlink *devlink, *actions_performed = BIT(DEVLINK_RELOAD_ACTION_FW_ACTIVATE); - adapter->flags2 &= ~IXGBE_FLAG2_API_MISMATCH; + adapter->flags2 &= ~(IXGBE_FLAG2_API_MISMATCH | +IXGBE_FLAG2_FW_ROLLBACK); return 0; } diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h index 2246997bc9fb..23c2e2c2649c 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h @@ -672,6 +672,7 @@ struct ixgbe_adapter { #define IXGBE_FLAG2_NO_MEDIA BIT(21) #define IXGBE_FLAG2_MOD_POWER_UNSUPPORTED BIT(22) #define IXGBE_FLAG2_API_MISMATCH BIT(23) +#define IXGBE_FLAG2_FW_ROLLBACKBIT(24) /* Tx fast path data */ int num_tx_queues; diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c index 84b015e2dac2..bc1a5775a3a0 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c @@ -1831,6 +1831,22 @@ static bool ixgbe_fw_recovery_mode_e610(struct ixgbe_hw *hw) return !!(fwsm & IXGBE_GL_MNG_FWSM_RECOVERY_M); } +/** + * ixgbe_fw_rollback_mode_e610 - Check FW NVM rollback mode + * @hw: pointer to hardware structure + * + * Check FW NVM rollback mode by reading the value of + * the dedicated register. + * + * Return: true if FW is in rollback mode, otherwise false. + */ +static bool ixgbe_fw_rollback_mode_e610(struct ixgbe_hw *hw) +{ + u32 fwsm = IXGBE_READ_REG(hw, IXGBE_GL_MNG_FWSM); + + return !!(fwsm & IXGBE_GL_MNG_FWSM_ROLLBACK_M); +} + /** * ixgbe_init_phy_ops_e610 - PHY specific init * @hw: pointer to hardware structure @@ -3163,6 +3179,21 @@ int ixgbe_get_inactive_nvm_ver(struct ixgbe_hw *hw, struct ixgbe_nvm_info *nvm) return ixgbe_get_nvm_ver_info(hw, IXGBE_INACTIVE_FLASH_BANK, nvm); } +/** + * ixgbe_get_active_nvm_ver - Read Option ROM version from the active bank + * @hw: pointer to the HW structure + * @nvm: storage for Option ROM version information + * + * Reads the NVM EETRACK ID, Map version, and security revision of the + * active NVM bank. + * + * Return: the exit code of the operation. + */ +static int ixgbe_get_active_nvm_ver(struct ixgbe_hw *hw, struct ixgbe_nvm_info *nvm) +{ + return ixgbe_get_nvm_ver_info(hw, IXGBE_ACTIVE_FLASH_BANK, nvm); +} + /** * ixgbe_get_netlist_info - Read the netlist version information * @hw: pointer to the HW struct @@ -3897,6 +3928,8 @@ static const struct ixgbe_mac_operations mac_ops_e610 = { .get_media_type = ixgbe_get_media_type_e610, .setup_link = ixgbe_setup_link_e610, .fw_recovery_mode = ixgbe_fw_recovery_mode_e610, + .fw_rollback_mode = ixgbe_fw_rollback_mode_e610, + .get_nvm_ver= ixgbe_get_active_nvm_ver, .get_link_capabilities = ixgbe_get_link_capabilities_e610, .get_bus_info = ixgbe_get_bus_info_generic, .acquire_swfw_sync = ixgbe_acquire_swfw_sync_X540, diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 5c9de1fafd28..ce73a47ce00a 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -8420,6 +
[Intel-wired-lan] [PATCH iwl-next v8 06/15] ixgbe: read the OROM version information
From: Slawomir Mrozowicz Add functions reading the OROM version info and use them as a part of the setting NVM info procedure. Reviewed-by: Mateusz Polchlopek Reviewed-by: Przemek Kitszel Tested-by: Bharath R Signed-off-by: Slawomir Mrozowicz Co-developed-by: Piotr Kwapulinski Signed-off-by: Piotr Kwapulinski Signed-off-by: Jedrzej Jagielski --- drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c | 172 ++ .../ethernet/intel/ixgbe/ixgbe_type_e610.h| 15 ++ 2 files changed, 187 insertions(+) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c index 3654b7e32cc8..bad4bc04bb66 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c @@ -2582,6 +2582,35 @@ static int ixgbe_read_nvm_module(struct ixgbe_hw *hw, return err; } +/** + * ixgbe_read_orom_module - Read from the active Option ROM module + * @hw: pointer to the HW structure + * @bank: whether to read from active or inactive OROM module + * @offset: offset into the OROM module to read, in words + * @data: storage for returned word value + * + * Read the specified word from the active Option ROM module of the flash. + * Note that unlike the NVM module, the CSS data is stored at the end of the + * module instead of at the beginning. + * + * Return: the exit code of the operation. + */ +static int ixgbe_read_orom_module(struct ixgbe_hw *hw, + enum ixgbe_bank_select bank, + u32 offset, u16 *data) +{ + __le16 data_local; + int err; + + err = ixgbe_read_flash_module(hw, bank, IXGBE_E610_SR_1ST_OROM_BANK_PTR, + offset * sizeof(data_local), + (u8 *)&data_local, sizeof(data_local)); + if (!err) + *data = le16_to_cpu(data_local); + + return err; +} + /** * ixgbe_get_nvm_css_hdr_len - Read the CSS header length * @hw: pointer to the HW struct @@ -2678,6 +2707,143 @@ static int ixgbe_get_nvm_srev(struct ixgbe_hw *hw, return 0; } +/** + * ixgbe_get_orom_civd_data - Get the combo version information from Option ROM + * @hw: pointer to the HW struct + * @bank: whether to read from the active or inactive flash module + * @civd: storage for the Option ROM CIVD data. + * + * Searches through the Option ROM flash contents to locate the CIVD data for + * the image. + * + * Return: the exit code of the operation. + */ +static int +ixgbe_get_orom_civd_data(struct ixgbe_hw *hw, enum ixgbe_bank_select bank, +struct ixgbe_orom_civd_info *civd) +{ + struct ixgbe_orom_civd_info tmp; + u32 offset; + int err; + + /* The CIVD section is located in the Option ROM aligned to 512 bytes. +* The first 4 bytes must contain the ASCII characters "$CIV". +* A simple modulo 256 sum of all of the bytes of the structure must +* equal 0. +*/ + for (offset = 0; (offset + SZ_512) <= hw->flash.banks.orom_size; +offset += SZ_512) { + u8 sum = 0; + u32 i; + + err = ixgbe_read_flash_module(hw, bank, + IXGBE_E610_SR_1ST_OROM_BANK_PTR, + offset, + (u8 *)&tmp, sizeof(tmp)); + if (err) + return err; + + /* Skip forward until we find a matching signature */ + if (memcmp(IXGBE_OROM_CIV_SIGNATURE, tmp.signature, + sizeof(tmp.signature))) + continue; + + /* Verify that the simple checksum is zero */ + for (i = 0; i < sizeof(tmp); i++) + sum += ((u8 *)&tmp)[i]; + + if (sum) + return -EDOM; + + *civd = tmp; + return 0; + } + + return -ENODATA; +} + +/** + * ixgbe_get_orom_srev - Read the security revision from the OROM CSS header + * @hw: pointer to the HW struct + * @bank: whether to read from active or inactive flash module + * @srev: storage for security revision + * + * Read the security revision out of the CSS header of the active OROM module + * bank. + * + * Return: the exit code of the operation. + */ +static int ixgbe_get_orom_srev(struct ixgbe_hw *hw, + enum ixgbe_bank_select bank, + u32 *srev) +{ + u32 orom_size_word = hw->flash.banks.orom_size / 2; + u32 css_start, hdr_len; + u16 srev_l, srev_h; + int err; + + err = ixgbe_get_nvm_css_hdr_len(hw, bank, &hdr_len); + if (err) + return err; + + if (orom_size_word < hdr_len) + return -EINVAL; + + /* Calculate how far into the Option ROM the CSS header starts. Note +* that ixgbe_r
[Intel-wired-lan] [PATCH iwl-next v8 14/15] ixgbe: add E610 implementation of FW recovery mode
Add E610 implementation of fw_recovery_mode MAC operation. In case of E610 information about recovery mode is obtained from FW_MODES field in IXGBE_GL_MNG_FWSM register (0x000B6134). Introduce recovery specific probing flow and init only vital features. User should be able to perform NVM update using devlink once FW error is detected in order to load a healthy img. Reviewed-by: Mateusz Polchlopek Co-developed-by: Stefan Wegrzyn Signed-off-by: Stefan Wegrzyn Signed-off-by: Jedrzej Jagielski --- v7: unregister mdiobus before unregistering netdev --- drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c | 17 .../ethernet/intel/ixgbe/ixgbe_fw_update.c| 14 ++- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 94 +-- .../ethernet/intel/ixgbe/ixgbe_type_e610.h| 3 + 4 files changed, 117 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c index 5aa66534aa75..84b015e2dac2 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c @@ -1815,6 +1815,22 @@ void ixgbe_disable_rx_e610(struct ixgbe_hw *hw) } } +/** + * ixgbe_fw_recovery_mode_e610 - Check FW NVM recovery mode + * @hw: pointer to hardware structure + * + * Check FW NVM recovery mode by reading the value of + * the dedicated register. + * + * Return: true if FW is in recovery mode, otherwise false. + */ +static bool ixgbe_fw_recovery_mode_e610(struct ixgbe_hw *hw) +{ + u32 fwsm = IXGBE_READ_REG(hw, IXGBE_GL_MNG_FWSM); + + return !!(fwsm & IXGBE_GL_MNG_FWSM_RECOVERY_M); +} + /** * ixgbe_init_phy_ops_e610 - PHY specific init * @hw: pointer to hardware structure @@ -3880,6 +3896,7 @@ static const struct ixgbe_mac_operations mac_ops_e610 = { .get_fw_ver = ixgbe_aci_get_fw_ver, .get_media_type = ixgbe_get_media_type_e610, .setup_link = ixgbe_setup_link_e610, + .fw_recovery_mode = ixgbe_fw_recovery_mode_e610, .get_link_capabilities = ixgbe_get_link_capabilities_e610, .get_bus_info = ixgbe_get_bus_info_generic, .acquire_swfw_sync = ixgbe_acquire_swfw_sync_X540, diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_fw_update.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_fw_update.c index 052d5b3fb371..39f106e39be6 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_fw_update.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_fw_update.c @@ -73,6 +73,8 @@ static int ixgbe_check_component_response(struct ixgbe_adapter *adapter, u8 response, u8 code, struct netlink_ext_ack *extack) { + struct ixgbe_hw *hw = &adapter->hw; + switch (response) { case IXGBE_ACI_NVM_PASS_COMP_CAN_BE_UPDATED: /* Firmware indicated this update is good to proceed. */ @@ -84,6 +86,11 @@ static int ixgbe_check_component_response(struct ixgbe_adapter *adapter, case IXGBE_ACI_NVM_PASS_COMP_CAN_NOT_BE_UPDATED: NL_SET_ERR_MSG_MOD(extack, "Firmware has rejected updating."); break; + case IXGBE_ACI_NVM_PASS_COMP_PARTIAL_CHECK: + if (hw->mac.ops.fw_recovery_mode && + hw->mac.ops.fw_recovery_mode(hw)) + return 0; + break; } switch (code) { @@ -653,7 +660,12 @@ int ixgbe_flash_pldm_image(struct devlink *devlink, return -EOPNOTSUPP; } - if (!hw->dev_caps.common_cap.nvm_unified_update) { + /* Cannot get caps in recovery mode, so lack of nvm_unified_update bit +* cannot lead to error +*/ + if (!hw->dev_caps.common_cap.nvm_unified_update && + (hw->mac.ops.fw_recovery_mode && +!hw->mac.ops.fw_recovery_mode(hw))) { NL_SET_ERR_MSG_MOD(extack, "Current firmware does not support unified update"); return -EOPNOTSUPP; diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index de74132f9001..5c9de1fafd28 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -8423,6 +8423,18 @@ static bool ixgbe_check_fw_error(struct ixgbe_adapter *adapter) return false; } +static void ixgbe_recovery_service_task(struct work_struct *work) +{ + struct ixgbe_adapter *adapter = container_of(work, +struct ixgbe_adapter, +service_task); + + ixgbe_handle_fw_event(adapter); + ixgbe_service_event_complete(adapter); + + mod_timer(&adapter->service_timer, jiffies + msecs_to_jiffies(100)); +} + /** * ixgbe_service_task - manages and runs subtas
[Intel-wired-lan] [PATCH iwl-next v8 04/15] ixgbe: add handler for devlink .info_get()
Provide devlink .info_get() callback implementation to allow the driver to report detailed version information. The following info is reported: "serial_number" -> The PCI DSN of the adapter "fw.bundle_id" -> Unique identifier for the combined flash image "fw.undi" -> Version of the Option ROM containing the UEFI driver "board.id" -> The PBA ID string Reviewed-by: Mateusz Polchlopek Tested-by: Bharath R Signed-off-by: Jedrzej Jagielski --- v2: zero the ctx buff when chance it won't be filled out v4: use devlink_priv() v6: fix devlink_*_put() labels --- Documentation/networking/devlink/ixgbe.rst| 32 ++ .../ethernet/intel/ixgbe/devlink/devlink.c| 101 ++ 2 files changed, 133 insertions(+) diff --git a/Documentation/networking/devlink/ixgbe.rst b/Documentation/networking/devlink/ixgbe.rst index c04ac51c6d85..b63645de37e8 100644 --- a/Documentation/networking/devlink/ixgbe.rst +++ b/Documentation/networking/devlink/ixgbe.rst @@ -6,3 +6,35 @@ ixgbe devlink support This document describes the devlink features implemented by the ``ixgbe`` device driver. + +Info versions += + +The ``ixgbe`` driver reports the following versions + +.. list-table:: devlink info versions implemented +:widths: 5 5 5 90 + +* - Name + - Type + - Example + - Description +* - ``board.id`` + - fixed + - H49289-000 + - The Product Board Assembly (PBA) identifier of the board. +* - ``fw.undi`` + - running + - 1.1937.0 + - Version of the Option ROM containing the UEFI driver. The version is +reported in ``major.minor.patch`` format. The major version is +incremented whenever a major breaking change occurs, or when the +minor version would overflow. The minor version is incremented for +non-breaking changes and reset to 1 when the major version is +incremented. The patch version is normally 0 but is incremented when +a fix is delivered as a patch against an older base Option ROM. +* - ``fw.bundle_id`` + - running + - 0x8d0d + - Unique identifier of the firmware image file that was loaded onto +the device. Also referred to as the EETRACK identifier of the NVM. diff --git a/drivers/net/ethernet/intel/ixgbe/devlink/devlink.c b/drivers/net/ethernet/intel/ixgbe/devlink/devlink.c index 6c3452cf5d7d..d91252da4a61 100644 --- a/drivers/net/ethernet/intel/ixgbe/devlink/devlink.c +++ b/drivers/net/ethernet/intel/ixgbe/devlink/devlink.c @@ -4,7 +4,108 @@ #include "ixgbe.h" #include "devlink.h" +struct ixgbe_info_ctx { + char buf[128]; +}; + +static void ixgbe_info_get_dsn(struct ixgbe_adapter *adapter, + struct ixgbe_info_ctx *ctx) +{ + u8 dsn[8]; + + /* Copy the DSN into an array in Big Endian format */ + put_unaligned_be64(pci_get_dsn(adapter->pdev), dsn); + + snprintf(ctx->buf, sizeof(ctx->buf), "%8phD", dsn); +} + +static void ixgbe_info_nvm_ver(struct ixgbe_adapter *adapter, + struct ixgbe_info_ctx *ctx) +{ + struct ixgbe_hw *hw = &adapter->hw; + struct ixgbe_nvm_version nvm_ver; + + ctx->buf[0] = '\0'; + + ixgbe_get_oem_prod_version(hw, &nvm_ver); + if (nvm_ver.oem_valid) { + snprintf(ctx->buf, sizeof(ctx->buf), "%x.%x.%x", +nvm_ver.oem_major, nvm_ver.oem_minor, +nvm_ver.oem_release); + + return; + } + + ixgbe_get_orom_version(hw, &nvm_ver); + if (nvm_ver.or_valid) + snprintf(ctx->buf, sizeof(ctx->buf), "%d.%d.%d", +nvm_ver.or_major, nvm_ver.or_build, nvm_ver.or_patch); +} + +static void ixgbe_info_eetrack(struct ixgbe_adapter *adapter, + struct ixgbe_info_ctx *ctx) +{ + struct ixgbe_hw *hw = &adapter->hw; + struct ixgbe_nvm_version nvm_ver; + + ixgbe_get_oem_prod_version(hw, &nvm_ver); + + /* No ETRACK version for OEM */ + if (nvm_ver.oem_valid) { + ctx->buf[0] = '\0'; + return; + } + + ixgbe_get_etk_id(hw, &nvm_ver); + snprintf(ctx->buf, sizeof(ctx->buf), "0x%08x", nvm_ver.etk_id); +} + +static int ixgbe_devlink_info_get(struct devlink *devlink, + struct devlink_info_req *req, + struct netlink_ext_ack *extack) +{ + struct ixgbe_adapter *adapter = devlink_priv(devlink); + struct ixgbe_hw *hw = &adapter->hw; + struct ixgbe_info_ctx *ctx; + int err; + + ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + ixgbe_info_get_dsn(adapter, ctx); + err = devlink_info_serial_number_put(req, ctx->buf); + if (err) + goto free_ctx; + + err = ixgbe_read_pba_string_generic(hw, ctx->buf, sizeof(ctx->buf)); + if (err) + goto free
[Intel-wired-lan] [PATCH iwl-next v8 09/15] ixgbe: add E610 functions getting PBA and FW ver info
Introduce 2 E610 specific callbacks implementations: -ixgbe_start_hw_e610() which expands the regular .start_hw callback with getting FW version information -ixgbe_read_pba_string_e610() which gets Product Board Assembly string Extend EEPROM ops with new .read_pba_string in order to distinguish generic one and the E610 one. Reviewed-by: Mateusz Polchlopek Tested-by: Bharath R Co-developed-by: Stefan Wegrzyn Signed-off-by: Stefan Wegrzyn Signed-off-by: Jedrzej Jagielski --- v7: add .init_params() callback implementation --- .../ethernet/intel/ixgbe/devlink/devlink.c| 2 +- .../net/ethernet/intel/ixgbe/ixgbe_82598.c| 1 + .../net/ethernet/intel/ixgbe/ixgbe_82599.c| 1 + .../net/ethernet/intel/ixgbe/ixgbe_common.c | 1 + drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c | 184 +- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 4 +- drivers/net/ethernet/intel/ixgbe/ixgbe_type.h | 2 + .../ethernet/intel/ixgbe/ixgbe_type_e610.h| 1 + drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c | 1 + drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c | 1 + 10 files changed, 194 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/devlink/devlink.c b/drivers/net/ethernet/intel/ixgbe/devlink/devlink.c index 365310a6910d..8f44c3dee0b5 100644 --- a/drivers/net/ethernet/intel/ixgbe/devlink/devlink.c +++ b/drivers/net/ethernet/intel/ixgbe/devlink/devlink.c @@ -198,7 +198,7 @@ static int ixgbe_devlink_info_get(struct devlink *devlink, if (err) goto free_ctx; - err = ixgbe_read_pba_string_generic(hw, ctx->buf, sizeof(ctx->buf)); + err = hw->eeprom.ops.read_pba_string(hw, ctx->buf, sizeof(ctx->buf)); if (err) goto free_ctx; diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c index 4aaaea3b5f8f..444da982593f 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c @@ -1169,6 +1169,7 @@ static const struct ixgbe_eeprom_operations eeprom_ops_82598 = { .calc_checksum = &ixgbe_calc_eeprom_checksum_generic, .validate_checksum = &ixgbe_validate_eeprom_checksum_generic, .update_checksum= &ixgbe_update_eeprom_checksum_generic, + .read_pba_string= &ixgbe_read_pba_string_generic, }; static const struct ixgbe_phy_operations phy_ops_82598 = { diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c index 964988b4d58b..d5b1b974b4a3 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c @@ -2230,6 +2230,7 @@ static const struct ixgbe_eeprom_operations eeprom_ops_82599 = { .calc_checksum = &ixgbe_calc_eeprom_checksum_generic, .validate_checksum = &ixgbe_validate_eeprom_checksum_generic, .update_checksum= &ixgbe_update_eeprom_checksum_generic, + .read_pba_string= &ixgbe_read_pba_string_generic, }; static const struct ixgbe_phy_operations phy_ops_82599 = { diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c index 7beaf6ea57f9..5784d5d1896e 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c @@ -332,6 +332,7 @@ int ixgbe_start_hw_generic(struct ixgbe_hw *hw) * Devices in the second generation: * 82599 * X540 + * E610 **/ int ixgbe_start_hw_gen2(struct ixgbe_hw *hw) { diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c index b34570b244d9..457d1f4b8784 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c @@ -343,6 +343,41 @@ void ixgbe_fill_dflt_direct_cmd_desc(struct ixgbe_aci_desc *desc, u16 opcode) desc->flags = cpu_to_le16(IXGBE_ACI_FLAG_SI); } +/** + * ixgbe_aci_get_fw_ver - Get the firmware version + * @hw: pointer to the HW struct + * + * Get the firmware version using ACI command (0x0001). + * + * Return: the exit code of the operation. + */ +static int ixgbe_aci_get_fw_ver(struct ixgbe_hw *hw) +{ + struct ixgbe_aci_cmd_get_ver *resp; + struct ixgbe_aci_desc desc; + int err; + + resp = &desc.params.get_ver; + + ixgbe_fill_dflt_direct_cmd_desc(&desc, ixgbe_aci_opc_get_ver); + + err = ixgbe_aci_send_cmd(hw, &desc, NULL, 0); + + if (!err) { + hw->fw_branch = resp->fw_branch; + hw->fw_maj_ver = resp->fw_major; + hw->fw_min_ver = resp->fw_minor; + hw->fw_patch = resp->fw_patch; + hw->fw_build = le32_to_cpu(resp->fw_build); + hw->api_branch = resp->api_branch; + hw->api_maj_ver = resp->api_major; + hw->api_min_ver = resp->api_minor; +
[Intel-wired-lan] [PATCH iwl-net v4 1/1] e1000e: change k1 configuration on MTP and later platforms
Starting from Meteor Lake, the Kumeran interface between the integrated MAC and the I219 PHY works at a different frequency. This causes sporadic MDI errors when accessing the PHY, and in rare circumstances could lead to packet corruption. To overcome this, introduce minor changes to the Kumeran idle state (K1) parameters during device initialization. Hardware reset reverts this configuration, therefore it needs to be applied in a few places. Fixes: cc23f4f0b6b9 ("e1000e: Add support for Meteor Lake") Signed-off-by: Vitaly Lifshits --- v4: fix a typo v3: refactor code to avoid edge case errors v2: address community comments v1: initial version --- drivers/net/ethernet/intel/e1000e/defines.h | 3 + drivers/net/ethernet/intel/e1000e/ich8lan.c | 80 +++-- drivers/net/ethernet/intel/e1000e/ich8lan.h | 4 ++ 3 files changed, 82 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/intel/e1000e/defines.h b/drivers/net/ethernet/intel/e1000e/defines.h index 5e2cfa73f889..8294a7c4f122 100644 --- a/drivers/net/ethernet/intel/e1000e/defines.h +++ b/drivers/net/ethernet/intel/e1000e/defines.h @@ -803,4 +803,7 @@ /* SerDes Control */ #define E1000_GEN_POLL_TIMEOUT 640 +#define E1000_FEXTNVM12_PHYPD_CTRL_MASK0x00C0 +#define E1000_FEXTNVM12_PHYPD_CTRL_P1 0x0080 + #endif /* _E1000_DEFINES_H_ */ diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.c b/drivers/net/ethernet/intel/e1000e/ich8lan.c index 2f9655cf5dd9..364378133526 100644 --- a/drivers/net/ethernet/intel/e1000e/ich8lan.c +++ b/drivers/net/ethernet/intel/e1000e/ich8lan.c @@ -285,6 +285,45 @@ static void e1000_toggle_lanphypc_pch_lpt(struct e1000_hw *hw) } } +/** + * e1000_reconfigure_k1_exit_timeout - reconfigure K1 exit timeout to + * align to MTP and later platform requirements. + * @hw: pointer to the HW structure + * + * Context: PHY semaphore must be held by caller. + * Return: 0 on success, negative on failure + */ +static s32 e1000_reconfigure_k1_exit_timeout(struct e1000_hw *hw) +{ + u16 phy_timeout; + u32 fextnvm12; + s32 ret_val; + + if (hw->mac.type < e1000_pch_mtp) + return 0; + + /* Change Kumeran K1 power down state from P0s to P1 */ + fextnvm12 = er32(FEXTNVM12); + fextnvm12 &= ~E1000_FEXTNVM12_PHYPD_CTRL_MASK; + fextnvm12 |= E1000_FEXTNVM12_PHYPD_CTRL_P1; + ew32(FEXTNVM12, fextnvm12); + + /* Wait for the interface the settle */ + usleep_range(1000, 1100); + + /* Change K1 exit timeout */ + ret_val = e1e_rphy_locked(hw, I217_PHY_TIMEOUTS_REG, + &phy_timeout); + if (ret_val) + return ret_val; + + phy_timeout &= ~I217_PHY_TIMEOUTS_K1_EXIT_TO_MASK; + phy_timeout |= 0xF00; + + return e1e_wphy_locked(hw, I217_PHY_TIMEOUTS_REG, + phy_timeout); +} + /** * e1000_init_phy_workarounds_pchlan - PHY initialization workarounds * @hw: pointer to the HW structure @@ -327,15 +366,22 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw) * LANPHYPC Value bit to force the interconnect to PCIe mode. */ switch (hw->mac.type) { + case e1000_pch_mtp: + case e1000_pch_lnp: + case e1000_pch_ptp: + case e1000_pch_nvp: + /* At this point the PHY might be inaccessible so don't +* propagate the failure +*/ + if (e1000_reconfigure_k1_exit_timeout(hw)) + e_dbg("Failed to reconfigure K1 exit timeout\n"); + + fallthrough; case e1000_pch_lpt: case e1000_pch_spt: case e1000_pch_cnp: case e1000_pch_tgp: case e1000_pch_adp: - case e1000_pch_mtp: - case e1000_pch_lnp: - case e1000_pch_ptp: - case e1000_pch_nvp: if (e1000_phy_is_accessible_pchlan(hw)) break; @@ -419,8 +465,20 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw) * the PHY is in. */ ret_val = hw->phy.ops.check_reset_block(hw); - if (ret_val) + if (ret_val) { e_err("ME blocked access to PHY after reset\n"); + goto out; + } + + if (hw->mac.type >= e1000_pch_mtp) { + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) { + e_err("Failed to reconfigure K1 exit timeout\n"); + goto out; + } + ret_val = e1000_reconfigure_k1_exit_timeout(hw); + hw->phy.ops.release(hw); + } } out: @@ -4888,6 +4946,18 @@ static s32 e1000_init_hw_ich8lan(struct e1000_hw *hw) u16 i; e1000_initialize_hw_bits_ich8lan(hw); + if (hw->m
Re: [Intel-wired-lan] [PATCH net v2 2/5] renesas: reject PTP_STRICT_FLAGS as unsupported
Hi Jacob, Thanks for your work. On 2025-03-12 15:15:51 -0700, Jacob Keller wrote: > The ravb_ptp_extts() function checks the flags coming from the > PTP_EXTTS_REQUEST ioctl, to ensure that future flags are not accepted on > accident. > > This was updated to 'honor' the PTP_STRICT_FLAGS in commit 6138e687c7b6 > ("ptp: Introduce strict checking of external time stamp options."). > However, the driver does not *actually* validate the flags. > > I originally fixed this driver to reject future flags in commit > 592025a03b34 ("renesas: reject unsupported external timestamp flags"). It > is still unclear whether this hardware timestamps the rising, falling, or > both edges of the input signal. > > Accepting requests with PTP_STRICT_FLAGS is a bug, as this could lead to > users mistakenly assuming a request with PTP_RISING_EDGE actually > timestamps the rising edge only. > > Reject requests with PTP_STRICT_FLAGS (and hence all PTP_EXTTS_REQUEST2 > requests) until someone with access to the datasheet or hardware knowledge > can confirm the timestamping behavior and update this driver. > > Fixes: 6138e687c7b6 ("ptp: Introduce strict checking of external time stamp > options.") > Signed-off-by: Jacob Keller Reviewed-by: Niklas Söderlund > --- > drivers/net/ethernet/renesas/ravb_ptp.c | 3 +-- > 1 file changed, 1 insertion(+), 2 deletions(-) > > diff --git a/drivers/net/ethernet/renesas/ravb_ptp.c > b/drivers/net/ethernet/renesas/ravb_ptp.c > index > 6e4ef7af27bf31ab2aad8e06a65e0ede6046e3c0..b4365906669f3bd40953813e263aeaafd2e1eb70 > 100644 > --- a/drivers/net/ethernet/renesas/ravb_ptp.c > +++ b/drivers/net/ethernet/renesas/ravb_ptp.c > @@ -179,8 +179,7 @@ static int ravb_ptp_extts(struct ptp_clock_info *ptp, > /* Reject requests with unsupported flags */ > if (req->flags & ~(PTP_ENABLE_FEATURE | > PTP_RISING_EDGE | > -PTP_FALLING_EDGE | > -PTP_STRICT_FLAGS)) > +PTP_FALLING_EDGE)) > return -EOPNOTSUPP; > > if (req->index) > > -- > 2.48.1.397.gec9d649cc640 > -- Kind Regards, Niklas Söderlund
[Intel-wired-lan] [PATCH iwl-next] igc: enable HW vlan tag insertion/stripping by default
This is enabled by default in other Intel drivers I've checked (e1000, e1000e, iavf, igb and ice). Fixes an out-of-the-box performance issue when running OpenWrt on typical mini-PCs with igc-supported Ethernet controllers and 802.1Q VLAN configurations, as ethtool isn't part of the default packages and sane defaults are expected. In my specific case, with an Intel N100-based machine with four I226-V Ethernet controllers, my upload performance increased from under 30 Mb/s to the expected ~1 Gb/s. Signed-off-by: Rui Salvaterra --- drivers/net/ethernet/intel/igc/igc_main.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index 84307bb7313e..1cb9ce8aa743 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -7049,6 +7049,9 @@ static int igc_probe(struct pci_dev *pdev, netdev->xdp_features = NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_REDIRECT | NETDEV_XDP_ACT_XSK_ZEROCOPY; + /* enable HW vlan tag insertion/stripping by default */ + netdev->features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX; + /* MTU range: 68 - 9216 */ netdev->min_mtu = ETH_MIN_MTU; netdev->max_mtu = MAX_STD_JUMBO_FRAME_SIZE; -- 2.48.1
[Intel-wired-lan] [PATCH iwl-next v3] ice: add E830 Earliest TxTime First Offload support
E830 supports Earliest TxTime First (ETF) hardware offload, which is configured via the ETF Qdisc (see tc-etf(8)). ETF introduces a new Tx flow mechanism that utilizes a timestamp ring (tstamp_ring) alongside the standard Tx ring. This timestamp ring is used to indicate when hardware will transmit a packet. The allocation and initialization of the timestamp ring occur when the feature is enabled via tc-etf. Since the timestamp ring and Tx ring are tightly coupled, both must be configured simultaneously. To support ETF, the following flags are introduced: - ICE_F_TXTIME: Device feature flag set for E830 NICs, indicating ETF support. - ICE_FLAG_TXTIME: PF-level flag indicating whether ETF is enabled on any Tx queue. It is checked during ring allocation to determine if timestamp rings should be allocated and is also referenced when modifying queue count via ethtool -G. - ICE_TX_FLAGS_TXTIME: Per-ring flag set when ETF is enabled and cleared when disabled for a specific Tx queue. It helps determine ETF status when transmitting timestamped packets and is used by ice_is_txtime_ena() to check if ETF is enabled on any Tx queue. Due to a hardware issue that can result in a malicious driver detection event, additional timestamp descriptors are required when wrapping the timestamp ring. Up to 64 additional timestamp descriptors are reserved, reducing the available Tx descriptors. To accommodate this, ICE_MAX_NUM_DESC_BY_MAC is introduced, defining: - E830: Maximum Tx descriptor length of 8096 (8K - 32 - 64 for timestamp fetch descriptors). - E810 and E82X: Maximum Tx descriptor length of 8160 (8K - 32) . Reviewed-by: Aleksandr Loktionov Co-developed-by: Alice Michael Signed-off-by: Alice Michael Signed-off-by: Paul Greenwalt --- Changelog: v2->v3: - Fix const compiler warning. - Fix spelling error in function header. - Fix Changelog verions number. v1->v2: - Resolve patch apply isue. - Fixes RCT, zero struct initialization, move bailout condition to top of function, removed unnecessary newlines, and added use of str_enable_disable. v1: https://patchwork.ozlabs.org/project/intel-wired-lan/patch/20250227111333.30675-1-paul.greenw...@intel.com/ --- drivers/net/ethernet/intel/ice/ice.h | 9 +- .../net/ethernet/intel/ice/ice_adminq_cmd.h | 53 + drivers/net/ethernet/intel/ice/ice_base.c | 212 +++--- drivers/net/ethernet/intel/ice/ice_base.h | 1 + drivers/net/ethernet/intel/ice/ice_common.c | 118 ++ drivers/net/ethernet/intel/ice/ice_common.h | 10 + drivers/net/ethernet/intel/ice/ice_ethtool.c | 61 - .../net/ethernet/intel/ice/ice_hw_autogen.h | 3 + .../net/ethernet/intel/ice/ice_lan_tx_rx.h| 42 drivers/net/ethernet/intel/ice/ice_lib.c | 45 +++- drivers/net/ethernet/intel/ice/ice_main.c | 174 +- drivers/net/ethernet/intel/ice/ice_txrx.c | 129 ++- drivers/net/ethernet/intel/ice/ice_txrx.h | 4 + drivers/net/ethernet/intel/ice/ice_txrx_lib.h | 14 ++ drivers/net/ethernet/intel/ice/ice_virtchnl.c | 2 +- 15 files changed, 823 insertions(+), 54 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index 2694951a0b1d..43a34e3fa762 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -83,7 +83,11 @@ #define ICE_BAR0 0 #define ICE_REQ_DESC_MULTIPLE 32 #define ICE_MIN_NUM_DESC 64 -#define ICE_MAX_NUM_DESC 8160 +#define ICE_MAX_NUM_DESC_E810 8160 +#define ICE_MAX_NUM_DESC_E830 8096 +#define ICE_MAX_NUM_DESC_BY_MAC(hw) ((hw)->mac_type == ICE_MAC_E830 ? \ +ICE_MAX_NUM_DESC_E830 : \ +ICE_MAX_NUM_DESC_E810) #define ICE_DFLT_MIN_RX_DESC 512 #define ICE_DFLT_NUM_TX_DESC 256 #define ICE_DFLT_NUM_RX_DESC 2048 @@ -201,6 +205,7 @@ enum ice_feature { ICE_F_SMA_CTRL, ICE_F_CGU, ICE_F_GNSS, + ICE_F_TXTIME, ICE_F_GCS, ICE_F_ROCE_LAG, ICE_F_SRIOV_LAG, @@ -332,6 +337,7 @@ struct ice_vsi { struct ice_pf *back; /* back pointer to PF */ struct ice_rx_ring **rx_rings; /* Rx ring array */ struct ice_tx_ring **tx_rings; /* Tx ring array */ + struct ice_tx_ring **tstamp_rings; /* Time stamp ring array */ struct ice_q_vector **q_vectors; /* q_vector array */ irqreturn_t (*irq_handler)(int irq, void *data); @@ -516,6 +522,7 @@ enum ice_pf_flags { ICE_FLAG_GNSS, /* GNSS successfully initialized */ ICE_FLAG_DPLL, /* SyncE/PTP dplls initialized */ ICE_FLAG_LLDP_AQ_FLTR, + ICE_FLAG_TXTIME, ICE_PF_FLAGS_NBITS /* must be last */ }; diff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h index bdee499f991a..2eaa4ab8e791 100644 -
Re: [Intel-wired-lan] [PATCH iwl-next v3] igc: Change Tx mode for MQPRIO offloading
On Tue, Mar 11, 2025 at 04:03:57PM +0800, Abdul Rahim, Faizal wrote: > On 7/3/2025 11:02 pm, Vladimir Oltean wrote: > > How do you and Faizal plan to serialize your changes on these flags? > > You delete IGC_FLAG_TSN_LEGACY_ENABLED and he adds > > IGC_FLAG_TSN_PREEMPT_ENABLED. > > From what I’ve experienced before, when there’s a conflict like this, the > Intel maintainer handles it and gets both authors to review the resolution > (this has happened to both of us before) before they proceed to submit the > patch. > > But if one patch gets merged first, the other person can just rebase and > submit a new version ? Yes, rebasing after the other's patch is merged works just fine. I was asking if you had decided which one should go in first just to avoid any ambiguity, but if the answer is 'any', that is also fine.
Re: [Intel-wired-lan] [PATCH net-next 08/16] idpf: make complq cleaning dependent on scheduling mode
From: Maciej Fijalkowski Date: Fri, 7 Mar 2025 12:11:05 +0100 > On Wed, Mar 05, 2025 at 05:21:24PM +0100, Alexander Lobakin wrote: >> From: Michal Kubiak >> >> Extend completion queue cleaning function to support queue-based >> scheduling mode needed for XDP queues. >> Add 4-byte descriptor for queue-based scheduling mode and >> perform some refactoring to extract the common code for >> both scheduling modes. TBH it's not needed at all as the cleaning logic for XDP queues is in xdp.c and doesn't depend on the regular Tx. Previously, the same functions were used for both, but then we rewrote stuff and I forgot to toss it off =\ I only need to add 4-byte completion descriptors and allocation depending on the queue type. Regular skb functions don't use queue-based mode, XDP path doesn't use flow-based mode. Thanks, Olek
Re: [Intel-wired-lan] [PATCH net-next 10/16] idpf: add support for nointerrupt queues
From: Maciej Fijalkowski Date: Fri, 7 Mar 2025 13:10:29 +0100 > On Wed, Mar 05, 2025 at 05:21:26PM +0100, Alexander Lobakin wrote: >> Currently, queues are associated 1:1 with interrupt vectors as it's >> assumed queues are always interrupt-driven. >> In order to use a queue without an interrupt, idpf still needs to have >> a vector assigned to it to flush descriptors. This vector can be global >> and only one for the whole vport to handle all its noirq queues. >> Always request one excessive vector and configure it in non-interrupt >> mode right away when creating vport, so that it can be used later by >> queues when needed. > > Description sort of miss the purpose of this commit, you don't ever > mention that your design choice for XDP Tx queues is to have them > irq-less. Because this is not directly related to XDP and maybe some time later more code could make use of noirq queues, who knows :> But I'll mention why this is needed, ok. > >> >> Co-developed-by: Michal Kubiak >> Signed-off-by: Michal Kubiak >> Signed-off-by: Alexander Lobakin >> --- >> drivers/net/ethernet/intel/idpf/idpf.h| 8 +++ >> drivers/net/ethernet/intel/idpf/idpf_txrx.h | 4 ++ >> drivers/net/ethernet/intel/idpf/idpf_dev.c| 11 +++- >> drivers/net/ethernet/intel/idpf/idpf_lib.c| 2 +- >> drivers/net/ethernet/intel/idpf/idpf_txrx.c | 8 +++ >> drivers/net/ethernet/intel/idpf/idpf_vf_dev.c | 11 +++- >> .../net/ethernet/intel/idpf/idpf_virtchnl.c | 53 +-- >> 7 files changed, 79 insertions(+), 18 deletions(-) Thanks, Olek
Re: [Intel-wired-lan] [PATCH net-next 09/16] idpf: remove SW marker handling from NAPI
From: Maciej Fijalkowski Date: Fri, 7 Mar 2025 12:42:10 +0100 > On Wed, Mar 05, 2025 at 05:21:25PM +0100, Alexander Lobakin wrote: >> From: Michal Kubiak >> >> SW marker descriptors on completion queues are used only when a queue >> is about to be destroyed. It's far from hotpath and handling it in the >> hotpath NAPI poll makes no sense. [...] >> +/** >> + * idpf_wait_for_sw_marker_completion - wait for SW marker of disabled Tx >> queue >> + * @txq: disabled Tx queue >> + */ >> +void idpf_wait_for_sw_marker_completion(struct idpf_tx_queue *txq) >> +{ >> +struct idpf_compl_queue *complq = txq->txq_grp->complq; >> +struct idpf_splitq_4b_tx_compl_desc *tx_desc; >> +s16 ntc = complq->next_to_clean; >> +unsigned long timeout; >> +bool flow, gen_flag; >> +u32 pos = ntc; >> + >> +if (!idpf_queue_has(SW_MARKER, txq)) >> +return; >> + >> +flow = idpf_queue_has(FLOW_SCH_EN, complq); >> +gen_flag = idpf_queue_has(GEN_CHK, complq); >> + >> +timeout = jiffies + msecs_to_jiffies(IDPF_WAIT_FOR_MARKER_TIMEO); >> +tx_desc = flow ? &complq->comp[pos].common : &complq->comp_4b[pos]; >> +ntc -= complq->desc_count; > > could we stop this logic? it was introduced back in the days as comparison > against 0 for wrap case was faster, here as you said it doesn't have much > in common with hot path. +1 > >> + >> +do { >> +struct idpf_tx_queue *tx_q; >> +int ctype; >> + >> +ctype = idpf_parse_compl_desc(tx_desc, complq, &tx_q, >> + gen_flag); >> +if (ctype == IDPF_TXD_COMPLT_SW_MARKER) { >> +idpf_queue_clear(SW_MARKER, tx_q); >> +if (txq == tx_q) >> +break; >> +} else if (ctype == -ENODATA) { >> +usleep_range(500, 1000); >> +continue; >> +} >> + >> +pos++; >> +ntc++; >> +if (unlikely(!ntc)) { >> +ntc -= complq->desc_count; >> +pos = 0; >> +gen_flag = !gen_flag; >> +} >> + >> +tx_desc = flow ? &complq->comp[pos].common : >> + &complq->comp_4b[pos]; >> +prefetch(tx_desc); >> +} while (time_before(jiffies, timeout)); > > what if timeout expires and you didn't find the marker desc? why do you Then we'll print "failed to receive marker" and that's it. Usually that happens only if HW went out for cigarettes and won't come back until a full power cycle. In that case, timeout prevents the kernel from hanging. > need timer? couldn't you scan the whole ring instead? Queue destroy marker is always the last written descriptor, there's no point in scanning the whole ring. The marker arrives as the CP receives the virtchnl message, queues the queue (lol) for destroying and sends the marker. This may take up to several msecs, but you never know. So you anyway need a loop with some sane sleeps (here it's 500-1000 usec and it usually takes 2-3 iterations). > >> + >> +idpf_tx_update_complq_indexes(complq, ntc, gen_flag); >> +} Thanks, Olek
[Intel-wired-lan] [PATCH v9 iwl-next 04/10] idpf: negotiate PTP capabilities and get PTP clock
PTP capabilities are negotiated using virtchnl command. Add get capabilities function, direct access to read the PTP clock time and direct access to read the cross timestamp - system time and PTP clock time. Set initial PTP capabilities exposed to the stack. Reviewed-by: Alexander Lobakin Reviewed-by: Willem de Bruijn Tested-by: Willem de Bruijn Tested-by: Mina Almasry Signed-off-by: Milena Olech --- v1 -> v2: change the size of access fields in ptp struct, remove CONFIG_PCIE_PTM dependency drivers/net/ethernet/intel/idpf/Makefile | 2 + drivers/net/ethernet/intel/idpf/idpf.h| 2 + drivers/net/ethernet/intel/idpf/idpf_dev.c| 14 + .../ethernet/intel/idpf/idpf_lan_pf_regs.h| 4 + drivers/net/ethernet/intel/idpf/idpf_ptp.c| 263 ++ drivers/net/ethernet/intel/idpf/idpf_ptp.h| 89 ++ .../ethernet/intel/idpf/idpf_virtchnl_ptp.c | 95 +++ 7 files changed, 469 insertions(+) create mode 100644 drivers/net/ethernet/intel/idpf/idpf_virtchnl_ptp.c diff --git a/drivers/net/ethernet/intel/idpf/Makefile b/drivers/net/ethernet/intel/idpf/Makefile index 1f38a9d7125c..83ac5e296382 100644 --- a/drivers/net/ethernet/intel/idpf/Makefile +++ b/drivers/net/ethernet/intel/idpf/Makefile @@ -17,4 +17,6 @@ idpf-y := \ idpf_vf_dev.o idpf-$(CONFIG_IDPF_SINGLEQ)+= idpf_singleq_txrx.o + idpf-$(CONFIG_PTP_1588_CLOCK) += idpf_ptp.o +idpf-$(CONFIG_PTP_1588_CLOCK) += idpf_virtchnl_ptp.o diff --git a/drivers/net/ethernet/intel/idpf/idpf.h b/drivers/net/ethernet/intel/idpf/idpf.h index 2e8b14dd9d96..d5d5064d313b 100644 --- a/drivers/net/ethernet/intel/idpf/idpf.h +++ b/drivers/net/ethernet/intel/idpf/idpf.h @@ -189,6 +189,7 @@ struct idpf_vport_max_q { * @mb_intr_reg_init: Mailbox interrupt register initialization * @reset_reg_init: Reset register initialization * @trigger_reset: Trigger a reset to occur + * @ptp_reg_init: PTP register initialization */ struct idpf_reg_ops { void (*ctlq_reg_init)(struct idpf_ctlq_create_info *cq); @@ -197,6 +198,7 @@ struct idpf_reg_ops { void (*reset_reg_init)(struct idpf_adapter *adapter); void (*trigger_reset)(struct idpf_adapter *adapter, enum idpf_flags trig_cause); + void (*ptp_reg_init)(const struct idpf_adapter *adapter); }; /** diff --git a/drivers/net/ethernet/intel/idpf/idpf_dev.c b/drivers/net/ethernet/intel/idpf/idpf_dev.c index 41e4bd49402a..3fae81f1f988 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_dev.c +++ b/drivers/net/ethernet/intel/idpf/idpf_dev.c @@ -4,6 +4,7 @@ #include "idpf.h" #include "idpf_lan_pf_regs.h" #include "idpf_virtchnl.h" +#include "idpf_ptp.h" #define IDPF_PF_ITR_IDX_SPACING0x4 @@ -148,6 +149,18 @@ static void idpf_trigger_reset(struct idpf_adapter *adapter, idpf_get_reg_addr(adapter, PFGEN_CTRL)); } +/** + * idpf_ptp_reg_init - Initialize required registers + * @adapter: Driver specific private structure + * + * Set the bits required for enabling shtime and cmd execution + */ +static void idpf_ptp_reg_init(const struct idpf_adapter *adapter) +{ + adapter->ptp->cmd.shtime_enable_mask = PF_GLTSYN_CMD_SYNC_SHTIME_EN_M; + adapter->ptp->cmd.exec_cmd_mask = PF_GLTSYN_CMD_SYNC_EXEC_CMD_M; +} + /** * idpf_reg_ops_init - Initialize register API function pointers * @adapter: Driver specific private structure @@ -159,6 +172,7 @@ static void idpf_reg_ops_init(struct idpf_adapter *adapter) adapter->dev_ops.reg_ops.mb_intr_reg_init = idpf_mb_intr_reg_init; adapter->dev_ops.reg_ops.reset_reg_init = idpf_reset_reg_init; adapter->dev_ops.reg_ops.trigger_reset = idpf_trigger_reset; + adapter->dev_ops.reg_ops.ptp_reg_init = idpf_ptp_reg_init; } /** diff --git a/drivers/net/ethernet/intel/idpf/idpf_lan_pf_regs.h b/drivers/net/ethernet/intel/idpf/idpf_lan_pf_regs.h index 24edb8a6ec2e..cc9aa2b6a14a 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_lan_pf_regs.h +++ b/drivers/net/ethernet/intel/idpf/idpf_lan_pf_regs.h @@ -53,6 +53,10 @@ #define PF_FW_ATQH_ATQH_M GENMASK(9, 0) #define PF_FW_ATQT (PF_FW_BASE + 0x24) +/* Timesync registers */ +#define PF_GLTSYN_CMD_SYNC_EXEC_CMD_M GENMASK(1, 0) +#define PF_GLTSYN_CMD_SYNC_SHTIME_EN_M BIT(2) + /* Interrupts */ #define PF_GLINT_BASE 0x0890 #define PF_GLINT_DYN_CTL(_INT) (PF_GLINT_BASE + ((_INT) * 0x1000)) diff --git a/drivers/net/ethernet/intel/idpf/idpf_ptp.c b/drivers/net/ethernet/intel/idpf/idpf_ptp.c index 1ac6367f5989..12caeaf4c1a1 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_ptp.c +++ b/drivers/net/ethernet/intel/idpf/idpf_ptp.c @@ -4,6 +4,258 @@ #include "idpf.h" #include "idpf_ptp.h" +/** + * idpf_ptp_get_access - Determine the access type of the PTP features + * @adapter: Driver specific private structure + * @direct: Capability that indicates the direct access + * @mailbox: Capability that indicates
[Intel-wired-lan] [PATCH v9 iwl-next 03/10] idpf: move virtchnl structures to the header file
Move virtchnl structures to the header file to expose them for the PTP virtchnl file. Reviewed-by: Alexander Lobakin Reviewed-by: Willem de Bruijn Tested-by: Mina Almasry Signed-off-by: Milena Olech --- v1 -> v2: fix commit message title .../net/ethernet/intel/idpf/idpf_virtchnl.c | 86 +-- .../net/ethernet/intel/idpf/idpf_virtchnl.h | 84 ++ 2 files changed, 86 insertions(+), 84 deletions(-) diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c index 7004289b974c..a55ff20895ed 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c +++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c @@ -7,88 +7,6 @@ #include "idpf_virtchnl.h" #include "idpf_ptp.h" -#define IDPF_VC_XN_MIN_TIMEOUT_MSEC2000 -#define IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC(60 * 1000) -#define IDPF_VC_XN_IDX_M GENMASK(7, 0) -#define IDPF_VC_XN_SALT_M GENMASK(15, 8) -#define IDPF_VC_XN_RING_LENU8_MAX - -/** - * enum idpf_vc_xn_state - Virtchnl transaction status - * @IDPF_VC_XN_IDLE: not expecting a reply, ready to be used - * @IDPF_VC_XN_WAITING: expecting a reply, not yet received - * @IDPF_VC_XN_COMPLETED_SUCCESS: a reply was expected and received, - * buffer updated - * @IDPF_VC_XN_COMPLETED_FAILED: a reply was expected and received, but there - * was an error, buffer not updated - * @IDPF_VC_XN_SHUTDOWN: transaction object cannot be used, VC torn down - * @IDPF_VC_XN_ASYNC: transaction sent asynchronously and doesn't have the - * return context; a callback may be provided to handle - * return - */ -enum idpf_vc_xn_state { - IDPF_VC_XN_IDLE = 1, - IDPF_VC_XN_WAITING, - IDPF_VC_XN_COMPLETED_SUCCESS, - IDPF_VC_XN_COMPLETED_FAILED, - IDPF_VC_XN_SHUTDOWN, - IDPF_VC_XN_ASYNC, -}; - -struct idpf_vc_xn; -/* Callback for asynchronous messages */ -typedef int (*async_vc_cb) (struct idpf_adapter *, struct idpf_vc_xn *, - const struct idpf_ctlq_msg *); - -/** - * struct idpf_vc_xn - Data structure representing virtchnl transactions - * @completed: virtchnl event loop uses that to signal when a reply is - *available, uses kernel completion API - * @state: virtchnl event loop stores the data below, protected by the - *completion's lock. - * @reply_sz: Original size of reply, may be > reply_buf.iov_len; it will be - * truncated on its way to the receiver thread according to - * reply_buf.iov_len. - * @reply: Reference to the buffer(s) where the reply data should be written - *to. May be 0-length (then NULL address permitted) if the reply data - *should be ignored. - * @async_handler: if sent asynchronously, a callback can be provided to handle - *the reply when it's received - * @vc_op: corresponding opcode sent with this transaction - * @idx: index used as retrieval on reply receive, used for cookie - * @salt: changed every message to make unique, used for cookie - */ -struct idpf_vc_xn { - struct completion completed; - enum idpf_vc_xn_state state; - size_t reply_sz; - struct kvec reply; - async_vc_cb async_handler; - u32 vc_op; - u8 idx; - u8 salt; -}; - -/** - * struct idpf_vc_xn_params - Parameters for executing transaction - * @send_buf: kvec for send buffer - * @recv_buf: kvec for recv buffer, may be NULL, must then have zero length - * @timeout_ms: timeout to wait for reply - * @async: send message asynchronously, will not wait on completion - * @async_handler: If sent asynchronously, optional callback handler. The user - *must be careful when using async handlers as the memory for - *the recv_buf _cannot_ be on stack if this is async. - * @vc_op: virtchnl op to send - */ -struct idpf_vc_xn_params { - struct kvec send_buf; - struct kvec recv_buf; - int timeout_ms; - bool async; - async_vc_cb async_handler; - u32 vc_op; -}; - /** * struct idpf_vc_xn_manager - Manager for tracking transactions * @ring: backing and lookup for transactions @@ -450,8 +368,8 @@ static void idpf_vc_xn_push_free(struct idpf_vc_xn_manager *vcxn_mngr, * >= @recv_buf.iov_len, but we never overflow @@recv_buf_iov_base). < 0 for * error. */ -static ssize_t idpf_vc_xn_exec(struct idpf_adapter *adapter, - const struct idpf_vc_xn_params *params) +ssize_t idpf_vc_xn_exec(struct idpf_adapter *adapter, + const struct idpf_vc_xn_params *params) { const struct kvec *send_buf = ¶ms->send_buf; struct idpf_vc_xn *xn; diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.h index 83da5d8da56b..3522c1238ea2 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl
[Intel-wired-lan] [PATCH v9 iwl-next 02/10] virtchnl: add PTP virtchnl definitions
PTP capabilities are negotiated using virtchnl commands. There are two available modes of the PTP support: direct and mailbox. When the direct access to PTP resources is negotiated, virtchnl messages returns a set of registers that allow read/write directly. When the mailbox access to PTP resources is negotiated, virtchnl messages are used to access PTP clock and to read the timestamp values. Virtchnl API covers both modes and exposes a set of PTP capabilities. Using virtchnl API, the driver recognizes also HW abilities - maximum adjustment of the clock and the basic increment value. Additionally, API allows to configure the secondary mailbox, dedicated exclusively for PTP purposes. Reviewed-by: Alexander Lobakin Reviewed-by: Willem de Bruijn Tested-by: Mina Almasry Signed-off-by: Milena Olech --- v1 -> v2: fix struct description drivers/net/ethernet/intel/idpf/virtchnl2.h | 302 1 file changed, 302 insertions(+) diff --git a/drivers/net/ethernet/intel/idpf/virtchnl2.h b/drivers/net/ethernet/intel/idpf/virtchnl2.h index 63deb120359c..44a5ee84ed60 100644 --- a/drivers/net/ethernet/intel/idpf/virtchnl2.h +++ b/drivers/net/ethernet/intel/idpf/virtchnl2.h @@ -68,6 +68,16 @@ enum virtchnl2_op { VIRTCHNL2_OP_ADD_MAC_ADDR = 535, VIRTCHNL2_OP_DEL_MAC_ADDR = 536, VIRTCHNL2_OP_CONFIG_PROMISCUOUS_MODE= 537, + + /* TimeSync opcodes */ + VIRTCHNL2_OP_PTP_GET_CAPS = 541, + VIRTCHNL2_OP_PTP_GET_VPORT_TX_TSTAMP= 542, + VIRTCHNL2_OP_PTP_GET_DEV_CLK_TIME = 543, + VIRTCHNL2_OP_PTP_GET_CROSS_TIME = 544, + VIRTCHNL2_OP_PTP_SET_DEV_CLK_TIME = 545, + VIRTCHNL2_OP_PTP_ADJ_DEV_CLK_FINE = 546, + VIRTCHNL2_OP_PTP_ADJ_DEV_CLK_TIME = 547, + VIRTCHNL2_OP_PTP_GET_VPORT_TX_TSTAMP_CAPS = 548, }; /** @@ -1270,4 +1280,296 @@ struct virtchnl2_promisc_info { }; VIRTCHNL2_CHECK_STRUCT_LEN(8, virtchnl2_promisc_info); +/** + * enum virtchnl2_ptp_caps - PTP capabilities + * @VIRTCHNL2_CAP_PTP_GET_DEVICE_CLK_TIME: direct access to get the time of + *device clock + * @VIRTCHNL2_CAP_PTP_GET_DEVICE_CLK_TIME_MB: mailbox access to get the time of + * device clock + * @VIRTCHNL2_CAP_PTP_GET_CROSS_TIME: direct access to cross timestamp + * @VIRTCHNL2_CAP_PTP_GET_CROSS_TIME_MB: mailbox access to cross timestamp + * @VIRTCHNL2_CAP_PTP_SET_DEVICE_CLK_TIME: direct access to set the time of + *device clock + * @VIRTCHNL2_CAP_PTP_SET_DEVICE_CLK_TIME_MB: mailbox access to set the time of + * device clock + * @VIRTCHNL2_CAP_PTP_ADJ_DEVICE_CLK: direct access to adjust the time of device + * clock + * @VIRTCHNL2_CAP_PTP_ADJ_DEVICE_CLK_MB: mailbox access to adjust the time of + * device clock + * @VIRTCHNL2_CAP_PTP_TX_TSTAMPS: direct access to the Tx timestamping + * @VIRTCHNL2_CAP_PTP_TX_TSTAMPS_MB: mailbox access to the Tx timestamping + * + * PF/VF negotiates a set of supported PTP capabilities with the Control Plane. + * There are two access methods - mailbox (_MB) and direct. + * PTP capabilities enables Main Timer operations: get/set/adjust Main Timer, + * cross timestamping and the Tx timestamping. + */ +enum virtchnl2_ptp_caps { + VIRTCHNL2_CAP_PTP_GET_DEVICE_CLK_TIME = BIT(0), + VIRTCHNL2_CAP_PTP_GET_DEVICE_CLK_TIME_MB= BIT(1), + VIRTCHNL2_CAP_PTP_GET_CROSS_TIME= BIT(2), + VIRTCHNL2_CAP_PTP_GET_CROSS_TIME_MB = BIT(3), + VIRTCHNL2_CAP_PTP_SET_DEVICE_CLK_TIME = BIT(4), + VIRTCHNL2_CAP_PTP_SET_DEVICE_CLK_TIME_MB= BIT(5), + VIRTCHNL2_CAP_PTP_ADJ_DEVICE_CLK= BIT(6), + VIRTCHNL2_CAP_PTP_ADJ_DEVICE_CLK_MB = BIT(7), + VIRTCHNL2_CAP_PTP_TX_TSTAMPS= BIT(8), + VIRTCHNL2_CAP_PTP_TX_TSTAMPS_MB = BIT(9), +}; + +/** + * struct virtchnl2_ptp_clk_reg_offsets - Offsets of device and PHY clocks + * registers. + * @dev_clk_ns_l: Device clock low register offset + * @dev_clk_ns_h: Device clock high register offset + * @phy_clk_ns_l: PHY clock low register offset + * @phy_clk_ns_h: PHY clock high register offset + * @cmd_sync_trigger: The command sync trigger register offset + * @pad: Padding for future extensions + */ +struct virtchnl2_ptp_clk_reg_offsets { + __le32 dev_clk_ns_l; + __le32 dev_clk_ns_h; + __le32 phy_clk_ns_l; + __le32 phy_clk_ns_h; + __le32 cmd_sync_trigger; + u8 pad[4]; +}; +VIRTCHNL2_CHECK_STRUCT_LEN(24, virtchnl2_ptp_clk_reg_offsets); + +/** + * struct virtchnl2_ptp_cross_time_reg_offsets - Offsets of the device
[Intel-wired-lan] [PATCH v9 iwl-next 00/10] idpf: add initial PTP support
This patch series introduces support for Precision Time Protocol (PTP) to Intel(R) Infrastructure Data Path Function (IDPF) driver. PTP feature is supported when the PTP capability is negotiated with the Control Plane (CP). IDPF creates a PTP clock and sets a set of supported functions. During the PTP initialization, IDPF requests a set of PTP capabilities and receives a writeback from the CP with the set of supported options. These options are: - get time of the PTP clock - get cross timestamp - set the time of the PTP clock - adjust the PTP clock - Tx timestamping Each feature is considered to have direct access, where the operations on PCIe BAR registers are allowed, or the mailbox access, where the virtchnl messages are used to perform any PTP action. Mailbox access means that PTP requests are sent to the CP through dedicated secondary mailbox and the CP reads/writes/modifies desired resource - PTP Clock or Tx timestamp registers. Tx timestamp capabilities are negotiated only for vports that have UPLINK_VPORT flag set by the CP. Capabilities provide information about the number of available Tx timestamp latches, their indexes and size of the Tx timestamp value. IDPF requests Tx timestamp by setting the TSYN bit and the requested timestamp index in the context descriptor for the PTP packets. When the completion tag for that packet is received, IDPF schedules a worker to read the Tx timestamp value. v8 -> v9: fix Rx filters upscaling, check if the link is up in idpf_hwtstamp_get/set, fix typo v7 -> v8: split Tx and Rx timestamping enablement, refactor idpf_for_each_vport v6 -> v7: remove section about Tx timestamp limitation from cover letter since it has been fixed, change preparing flow descriptor method v5 -> v6: change locking mechanism in get_ts_info, clean timestamp fields when preparing flow descriptor, add Rx filter v4 -> v5: fix spin unlock when Tx timestamp index is requested v3 -> v4: change timestamp filters dependent on Tx timestamp cap, rewrite function that extends Tx timestamp value, minor fixes v2 -> v3: fix minor issues, revert idpf_for_each_vport changes, extend idpf_ptp_set_rx_tstamp, split tstamp statistics v1 -> v2: add stats for timestamping, use ndo_hwtamp_get/set, fix minor spelling issues Milena Olech (10): idpf: add initial PTP support virtchnl: add PTP virtchnl definitions idpf: move virtchnl structures to the header file idpf: negotiate PTP capabilities and get PTP clock idpf: add mailbox access to read PTP clock time idpf: add PTP clock configuration idpf: add Tx timestamp capabilities negotiation idpf: add Tx timestamp flows idpf: add support for Rx timestamping idpf: change the method for mailbox workqueue allocation drivers/net/ethernet/intel/idpf/Kconfig | 1 + drivers/net/ethernet/intel/idpf/Makefile | 3 + drivers/net/ethernet/intel/idpf/idpf.h| 35 + .../ethernet/intel/idpf/idpf_controlq_api.h | 3 + drivers/net/ethernet/intel/idpf/idpf_dev.c| 14 + .../net/ethernet/intel/idpf/idpf_ethtool.c| 75 +- .../ethernet/intel/idpf/idpf_lan_pf_regs.h| 4 + .../net/ethernet/intel/idpf/idpf_lan_txrx.h | 13 +- drivers/net/ethernet/intel/idpf/idpf_lib.c| 57 + drivers/net/ethernet/intel/idpf/idpf_main.c | 9 +- drivers/net/ethernet/intel/idpf/idpf_ptp.c| 996 ++ drivers/net/ethernet/intel/idpf/idpf_ptp.h| 370 +++ drivers/net/ethernet/intel/idpf/idpf_txrx.c | 171 ++- drivers/net/ethernet/intel/idpf/idpf_txrx.h | 18 +- .../net/ethernet/intel/idpf/idpf_virtchnl.c | 160 ++- .../net/ethernet/intel/idpf/idpf_virtchnl.h | 84 ++ .../ethernet/intel/idpf/idpf_virtchnl_ptp.c | 677 drivers/net/ethernet/intel/idpf/virtchnl2.h | 314 +- 18 files changed, 2901 insertions(+), 103 deletions(-) create mode 100644 drivers/net/ethernet/intel/idpf/idpf_ptp.c create mode 100644 drivers/net/ethernet/intel/idpf/idpf_ptp.h create mode 100644 drivers/net/ethernet/intel/idpf/idpf_virtchnl_ptp.c -- 2.31.1
[Intel-wired-lan] [PATCH v9 iwl-next 01/10] idpf: add initial PTP support
PTP feature is supported if the VIRTCHNL2_CAP_PTP is negotiated during the capabilities recognition. Initial PTP support includes PTP initialization and registration of the clock. Reviewed-by: Alexander Lobakin Reviewed-by: Vadim Fedorenko Reviewed-by: Willem de Bruijn Tested-by: Mina Almasry Signed-off-by: Milena Olech --- drivers/net/ethernet/intel/idpf/Kconfig | 1 + drivers/net/ethernet/intel/idpf/Makefile | 1 + drivers/net/ethernet/intel/idpf/idpf.h| 3 + drivers/net/ethernet/intel/idpf/idpf_main.c | 4 + drivers/net/ethernet/intel/idpf/idpf_ptp.c| 89 +++ drivers/net/ethernet/intel/idpf/idpf_ptp.h| 32 +++ .../net/ethernet/intel/idpf/idpf_virtchnl.c | 9 +- 7 files changed, 138 insertions(+), 1 deletion(-) create mode 100644 drivers/net/ethernet/intel/idpf/idpf_ptp.c create mode 100644 drivers/net/ethernet/intel/idpf/idpf_ptp.h diff --git a/drivers/net/ethernet/intel/idpf/Kconfig b/drivers/net/ethernet/intel/idpf/Kconfig index 1addd663acad..2c359a8551c7 100644 --- a/drivers/net/ethernet/intel/idpf/Kconfig +++ b/drivers/net/ethernet/intel/idpf/Kconfig @@ -4,6 +4,7 @@ config IDPF tristate "Intel(R) Infrastructure Data Path Function Support" depends on PCI_MSI + depends on PTP_1588_CLOCK_OPTIONAL select DIMLIB select LIBETH help diff --git a/drivers/net/ethernet/intel/idpf/Makefile b/drivers/net/ethernet/intel/idpf/Makefile index 2ce01a0b5898..1f38a9d7125c 100644 --- a/drivers/net/ethernet/intel/idpf/Makefile +++ b/drivers/net/ethernet/intel/idpf/Makefile @@ -17,3 +17,4 @@ idpf-y := \ idpf_vf_dev.o idpf-$(CONFIG_IDPF_SINGLEQ)+= idpf_singleq_txrx.o +idpf-$(CONFIG_PTP_1588_CLOCK) += idpf_ptp.o diff --git a/drivers/net/ethernet/intel/idpf/idpf.h b/drivers/net/ethernet/intel/idpf/idpf.h index 66544faab710..2e8b14dd9d96 100644 --- a/drivers/net/ethernet/intel/idpf/idpf.h +++ b/drivers/net/ethernet/intel/idpf/idpf.h @@ -530,6 +530,7 @@ struct idpf_vc_xn_manager; * @vector_lock: Lock to protect vector distribution * @queue_lock: Lock to protect queue distribution * @vc_buf_lock: Lock to protect virtchnl buffer + * @ptp: Storage for PTP-related data */ struct idpf_adapter { struct pci_dev *pdev; @@ -587,6 +588,8 @@ struct idpf_adapter { struct mutex vector_lock; struct mutex queue_lock; struct mutex vc_buf_lock; + + struct idpf_ptp *ptp; }; /** diff --git a/drivers/net/ethernet/intel/idpf/idpf_main.c b/drivers/net/ethernet/intel/idpf/idpf_main.c index b6c515d14cbf..60bae3081035 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_main.c +++ b/drivers/net/ethernet/intel/idpf/idpf_main.c @@ -163,6 +163,10 @@ static int idpf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_free; } + err = pci_enable_ptm(pdev, NULL); + if (err) + pci_dbg(pdev, "PCIe PTM is not supported by PCIe bus/controller\n"); + /* set up for high or low dma */ err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); if (err) { diff --git a/drivers/net/ethernet/intel/idpf/idpf_ptp.c b/drivers/net/ethernet/intel/idpf/idpf_ptp.c new file mode 100644 index ..1ac6367f5989 --- /dev/null +++ b/drivers/net/ethernet/intel/idpf/idpf_ptp.c @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (C) 2024 Intel Corporation */ + +#include "idpf.h" +#include "idpf_ptp.h" + +/** + * idpf_ptp_create_clock - Create PTP clock device for userspace + * @adapter: Driver specific private structure + * + * This function creates a new PTP clock device. + * + * Return: 0 on success, -errno otherwise. + */ +static int idpf_ptp_create_clock(const struct idpf_adapter *adapter) +{ + struct ptp_clock *clock; + + /* Attempt to register the clock before enabling the hardware. */ + clock = ptp_clock_register(&adapter->ptp->info, + &adapter->pdev->dev); + if (IS_ERR(clock)) { + pci_err(adapter->pdev, "PTP clock creation failed: %pe\n", clock); + return PTR_ERR(clock); + } + + adapter->ptp->clock = clock; + + return 0; +} + +/** + * idpf_ptp_init - Initialize PTP hardware clock support + * @adapter: Driver specific private structure + * + * Set up the device for interacting with the PTP hardware clock for all + * functions. Function will allocate and register a ptp_clock with the + * PTP_1588_CLOCK infrastructure. + * + * Return: 0 on success, -errno otherwise. + */ +int idpf_ptp_init(struct idpf_adapter *adapter) +{ + int err; + + if (!idpf_is_cap_ena(adapter, IDPF_OTHER_CAPS, VIRTCHNL2_CAP_PTP)) { + pci_dbg(adapter->pdev, "PTP capability is not detected\n"); + return -EOPNOTSUPP; + } + + adapter->ptp = kzalloc(sizeof(*adapter->ptp), GFP_KERNEL); + if (!adapter->ptp) + return -ENOMEM; + + /* add
[Intel-wired-lan] [PATCH v9 iwl-next 05/10] idpf: add mailbox access to read PTP clock time
When the access to read PTP clock is specified as mailbox, the driver needs to send virtchnl message to perform PTP actions. Message is sent using idpf_mbq_opc_send_msg_to_peer_drv mailbox opcode, with the parameters received during PTP capabilities negotiation. Add functions to recognize PTP messages, move them to dedicated secondary mailbox, read the PTP clock time and cross timestamp using mailbox messages. Reviewed-by: Alexander Lobakin Reviewed-by: Willem de Bruijn Signed-off-by: Milena Olech --- .../ethernet/intel/idpf/idpf_controlq_api.h | 3 + drivers/net/ethernet/intel/idpf/idpf_ptp.c| 66 +++ drivers/net/ethernet/intel/idpf/idpf_ptp.h| 43 ++ .../net/ethernet/intel/idpf/idpf_virtchnl.c | 47 +++ .../ethernet/intel/idpf/idpf_virtchnl_ptp.c | 83 +++ 5 files changed, 242 insertions(+) diff --git a/drivers/net/ethernet/intel/idpf/idpf_controlq_api.h b/drivers/net/ethernet/intel/idpf/idpf_controlq_api.h index e8e046ef2f0d..9642494a67d8 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_controlq_api.h +++ b/drivers/net/ethernet/intel/idpf/idpf_controlq_api.h @@ -123,9 +123,12 @@ struct idpf_ctlq_info { /** * enum idpf_mbx_opc - PF/VF mailbox commands * @idpf_mbq_opc_send_msg_to_cp: used by PF or VF to send a message to its CP + * @idpf_mbq_opc_send_msg_to_peer_drv: used by PF or VF to send a message to + *any peer driver */ enum idpf_mbx_opc { idpf_mbq_opc_send_msg_to_cp = 0x0801, + idpf_mbq_opc_send_msg_to_peer_drv = 0x0804, }; /* API supported for control queue management */ diff --git a/drivers/net/ethernet/intel/idpf/idpf_ptp.c b/drivers/net/ethernet/intel/idpf/idpf_ptp.c index 12caeaf4c1a1..01e28085eb39 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_ptp.c +++ b/drivers/net/ethernet/intel/idpf/idpf_ptp.c @@ -95,6 +95,37 @@ static u64 idpf_ptp_read_src_clk_reg_direct(struct idpf_adapter *adapter, return ((u64)hi << 32) | lo; } +/** + * idpf_ptp_read_src_clk_reg_mailbox - Read the main timer value through mailbox + * @adapter: Driver specific private structure + * @sts: Optional parameter for holding a pair of system timestamps from + * the system clock. Will be ignored when NULL is given. + * @src_clk: Returned main timer value in nanoseconds unit + * + * Return: 0 on success, -errno otherwise. + */ +static int idpf_ptp_read_src_clk_reg_mailbox(struct idpf_adapter *adapter, +struct ptp_system_timestamp *sts, +u64 *src_clk) +{ + struct idpf_ptp_dev_timers clk_time; + int err; + + /* Read the system timestamp pre PHC read */ + ptp_read_system_prets(sts); + + err = idpf_ptp_get_dev_clk_time(adapter, &clk_time); + if (err) + return err; + + /* Read the system timestamp post PHC read */ + ptp_read_system_postts(sts); + + *src_clk = clk_time.dev_clk_time_ns; + + return 0; +} + /** * idpf_ptp_read_src_clk_reg - Read the main timer value * @adapter: Driver specific private structure @@ -110,6 +141,8 @@ static int idpf_ptp_read_src_clk_reg(struct idpf_adapter *adapter, u64 *src_clk, switch (adapter->ptp->get_dev_clk_time_access) { case IDPF_PTP_NONE: return -EOPNOTSUPP; + case IDPF_PTP_MAILBOX: + return idpf_ptp_read_src_clk_reg_mailbox(adapter, sts, src_clk); case IDPF_PTP_DIRECT: *src_clk = idpf_ptp_read_src_clk_reg_direct(adapter, sts); break; @@ -146,6 +179,31 @@ static void idpf_ptp_get_sync_device_time_direct(struct idpf_adapter *adapter, *sys_time = ((u64)sys_time_hi << 32) | sys_time_lo; } +/** + * idpf_ptp_get_sync_device_time_mailbox - Get the cross time stamp values + *through mailbox + * @adapter: Driver specific private structure + * @dev_time: 64bit main timer value expressed in nanoseconds + * @sys_time: 64bit system time value expressed in nanoseconds + * + * Return: a pair of cross timestamp values on success, -errno otherwise. + */ +static int idpf_ptp_get_sync_device_time_mailbox(struct idpf_adapter *adapter, +u64 *dev_time, u64 *sys_time) +{ + struct idpf_ptp_dev_timers cross_time; + int err; + + err = idpf_ptp_get_cross_time(adapter, &cross_time); + if (err) + return err; + + *dev_time = cross_time.dev_clk_time_ns; + *sys_time = cross_time.sys_time_ns; + + return err; +} + /** * idpf_ptp_get_sync_device_time - Get the cross time stamp info * @device: Current device time @@ -161,10 +219,18 @@ static int idpf_ptp_get_sync_device_time(ktime_t *device, { struct idpf_adapter *adapter = ctx; u64 ns_time_dev, ns_time_sys; + int err; switch (adapter->ptp->get_cross_tstamp_access) {
[Intel-wired-lan] [PATCH v9 iwl-next 07/10] idpf: add Tx timestamp capabilities negotiation
Tx timestamp capabilities are negotiated for the uplink Vport. Driver receives information about the number of available Tx timestamp latches, the size of Tx timestamp value and the set of indexes used for Tx timestamping. Add function to get the Tx timestamp capabilities and parse the uplink vport flag. Reviewed-by: Alexander Lobakin Co-developed-by: Emil Tantilov Signed-off-by: Emil Tantilov Co-developed-by: Pavan Kumar Linga Signed-off-by: Pavan Kumar Linga Signed-off-by: Milena Olech --- v7 -> v8: refactor idpf_for_each_vport, change a function that checks if Tx timestamp for a given vport is enabled v2 -> v3: revert changes in idpf_for_each_vport, fix minor issues v1 -> v2: change the idpf_for_each_vport macro drivers/net/ethernet/intel/idpf/idpf.h| 10 ++ drivers/net/ethernet/intel/idpf/idpf_ptp.c| 65 + drivers/net/ethernet/intel/idpf/idpf_ptp.h| 95 - .../net/ethernet/intel/idpf/idpf_virtchnl.c | 11 ++ .../ethernet/intel/idpf/idpf_virtchnl_ptp.c | 128 +- drivers/net/ethernet/intel/idpf/virtchnl2.h | 12 +- 6 files changed, 317 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/intel/idpf/idpf.h b/drivers/net/ethernet/intel/idpf/idpf.h index d5d5064d313b..fe4d8ad75b04 100644 --- a/drivers/net/ethernet/intel/idpf/idpf.h +++ b/drivers/net/ethernet/intel/idpf/idpf.h @@ -292,6 +292,7 @@ struct idpf_port_stats { * @port_stats: per port csum, header split, and other offload stats * @link_up: True if link is up * @sw_marker_wq: workqueue for marker packets + * @tx_tstamp_caps: Capabilities negotiated for Tx timestamping */ struct idpf_vport { u16 num_txq; @@ -336,6 +337,8 @@ struct idpf_vport { bool link_up; wait_queue_head_t sw_marker_wq; + + struct idpf_ptp_vport_tx_tstamp_caps *tx_tstamp_caps; }; /** @@ -480,6 +483,13 @@ struct idpf_vport_config { struct idpf_vc_xn_manager; +#define idpf_for_each_vport(adapter, iter) \ + for (struct idpf_vport **__##iter = &(adapter)->vports[0], \ +*iter = (adapter)->max_vports ? *__##iter : NULL; \ +iter; \ +iter = (++__##iter) < &(adapter)->vports[(adapter)->max_vports] ? \ +*__##iter : NULL) + /** * struct idpf_adapter - Device data struct generated on probe * @pdev: PCI device struct given on probe diff --git a/drivers/net/ethernet/intel/idpf/idpf_ptp.c b/drivers/net/ethernet/intel/idpf/idpf_ptp.c index 54b7ccb16da0..d096a16bd262 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_ptp.c +++ b/drivers/net/ethernet/intel/idpf/idpf_ptp.c @@ -62,6 +62,13 @@ void idpf_ptp_get_features_access(const struct idpf_adapter *adapter) ptp->adj_dev_clk_time_access = idpf_ptp_get_access(adapter, direct, mailbox); + + /* Tx timestamping */ + direct = VIRTCHNL2_CAP_PTP_TX_TSTAMPS; + mailbox = VIRTCHNL2_CAP_PTP_TX_TSTAMPS_MB; + ptp->tx_tstamp_access = idpf_ptp_get_access(adapter, + direct, + mailbox); } /** @@ -517,6 +524,61 @@ static int idpf_ptp_create_clock(const struct idpf_adapter *adapter) return 0; } +/** + * idpf_ptp_release_vport_tstamp - Release the Tx timestamps trakcers for a + *given vport. + * @vport: Virtual port structure + * + * Remove the queues and delete lists that tracks Tx timestamp entries for a + * given vport. + */ +static void idpf_ptp_release_vport_tstamp(struct idpf_vport *vport) +{ + struct idpf_ptp_tx_tstamp *ptp_tx_tstamp, *tmp; + struct list_head *head; + + /* Remove list with free latches */ + spin_lock(&vport->tx_tstamp_caps->lock_free); + + head = &vport->tx_tstamp_caps->latches_free; + list_for_each_entry_safe(ptp_tx_tstamp, tmp, head, list_member) { + list_del(&ptp_tx_tstamp->list_member); + kfree(ptp_tx_tstamp); + } + + spin_unlock(&vport->tx_tstamp_caps->lock_free); + + /* Remove list with latches in use */ + spin_lock(&vport->tx_tstamp_caps->lock_in_use); + + head = &vport->tx_tstamp_caps->latches_in_use; + list_for_each_entry_safe(ptp_tx_tstamp, tmp, head, list_member) { + list_del(&ptp_tx_tstamp->list_member); + kfree(ptp_tx_tstamp); + } + + spin_unlock(&vport->tx_tstamp_caps->lock_in_use); + + kfree(vport->tx_tstamp_caps); + vport->tx_tstamp_caps = NULL; +} + +/** + * idpf_ptp_release_tstamp - Release the Tx timestamps trackers + * @adapter: Driver specific private structure + * + * Remove the queues and delete lists that tracks Tx timestamp entries. + */ +static void idpf_ptp_release_tstamp(struct idpf_adapter *adapter) +{ + idpf_for_each_vport(adapter, vport) { + if (!idpf_ptp_is_vpo
[Intel-wired-lan] [PATCH v9 iwl-next 09/10] idpf: add support for Rx timestamping
Add Rx timestamp function when the Rx timestamp value is read directly from the Rx descriptor. In order to extend the Rx timestamp value to 64 bit in hot path, the PHC time is cached in the receive groups. Add supported Rx timestamp modes. Tested-by: YiFei Zhu Tested-by: Mina Almasry Signed-off-by: Milena Olech --- v8 -> v9: upscale Rx filters to HWTSTAMP_FILTER_ALL if Rx filter is different than HWTSTAMP_FILTER_NONE v7 -> v8: add a function to check if the Rx timestamp for a given vport is enabled v5 -> v6: add Rx filter v2 -> v3: add disable Rx timestamp v1 -> v2: extend commit message .../net/ethernet/intel/idpf/idpf_ethtool.c| 1 + drivers/net/ethernet/intel/idpf/idpf_lib.c| 6 +- drivers/net/ethernet/intel/idpf/idpf_ptp.c| 89 ++- drivers/net/ethernet/intel/idpf/idpf_ptp.h| 21 + drivers/net/ethernet/intel/idpf/idpf_txrx.c | 30 +++ drivers/net/ethernet/intel/idpf/idpf_txrx.h | 7 +- 6 files changed, 150 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/intel/idpf/idpf_ethtool.c b/drivers/net/ethernet/intel/idpf/idpf_ethtool.c index ec4183a609c4..7a4793749bc5 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_ethtool.c +++ b/drivers/net/ethernet/intel/idpf/idpf_ethtool.c @@ -1333,6 +1333,7 @@ static void idpf_get_timestamp_filters(const struct idpf_vport *vport, SOF_TIMESTAMPING_RAW_HARDWARE; info->tx_types = BIT(HWTSTAMP_TX_OFF); + info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) | BIT(HWTSTAMP_FILTER_ALL); if (!vport->tx_tstamp_caps || vport->adapter->ptp->tx_tstamp_access == IDPF_PTP_NONE) diff --git a/drivers/net/ethernet/intel/idpf/idpf_lib.c b/drivers/net/ethernet/intel/idpf/idpf_lib.c index 26ea0d4eab0a..7e9a414dffa5 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_lib.c +++ b/drivers/net/ethernet/intel/idpf/idpf_lib.c @@ -2374,7 +2374,8 @@ static int idpf_hwtstamp_set(struct net_device *netdev, return -EPERM; } - if (!idpf_ptp_is_vport_tx_tstamp_ena(vport)) { + if (!idpf_ptp_is_vport_tx_tstamp_ena(vport) && + !idpf_ptp_is_vport_rx_tstamp_ena(vport)) { idpf_vport_ctrl_unlock(netdev); return -EOPNOTSUPP; } @@ -2399,7 +2400,8 @@ static int idpf_hwtstamp_get(struct net_device *netdev, return -EPERM; } - if (!idpf_ptp_is_vport_tx_tstamp_ena(vport)) { + if (!idpf_ptp_is_vport_tx_tstamp_ena(vport) && + !idpf_ptp_is_vport_rx_tstamp_ena(vport)) { idpf_vport_ctrl_unlock(netdev); return 0; } diff --git a/drivers/net/ethernet/intel/idpf/idpf_ptp.c b/drivers/net/ethernet/intel/idpf/idpf_ptp.c index ddccd409b864..4def3400a44c 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_ptp.c +++ b/drivers/net/ethernet/intel/idpf/idpf_ptp.c @@ -317,12 +317,41 @@ static int idpf_ptp_gettimex64(struct ptp_clock_info *info, return 0; } +/** + * idpf_ptp_update_phctime_rxq_grp - Update the cached PHC time for a given Rx + * queue group. + * @grp: receive queue group in which Rx timestamp is enabled + * @split: Indicates whether the queue model is split or single queue + * @systime: Cached system time + */ +static void +idpf_ptp_update_phctime_rxq_grp(const struct idpf_rxq_group *grp, bool split, + u64 systime) +{ + struct idpf_rx_queue *rxq; + u16 i; + + if (!split) { + for (i = 0; i < grp->singleq.num_rxq; i++) { + rxq = grp->singleq.rxqs[i]; + if (rxq) + WRITE_ONCE(rxq->cached_phc_time, systime); + } + } else { + for (i = 0; i < grp->splitq.num_rxq_sets; i++) { + rxq = &grp->splitq.rxq_sets[i]->rxq; + if (rxq) + WRITE_ONCE(rxq->cached_phc_time, systime); + } + } +} + /** * idpf_ptp_update_cached_phctime - Update the cached PHC time values * @adapter: Driver specific private structure * * This function updates the system time values which are cached in the adapter - * structure. + * structure and the Rx queues. * * This function must be called periodically to ensure that the cached value * is never more than 2 seconds old. @@ -345,6 +374,21 @@ static int idpf_ptp_update_cached_phctime(struct idpf_adapter *adapter) WRITE_ONCE(adapter->ptp->cached_phc_time, systime); WRITE_ONCE(adapter->ptp->cached_phc_jiffies, jiffies); + idpf_for_each_vport(adapter, vport) { + bool split; + + if (!vport || !vport->rxq_grps) + continue; + + split = idpf_is_queue_model_split(vport->rxq_model); + + for (u16 i = 0; i < vport->num_rxq_grp; i++) { + struct idpf_rxq_group *grp = &vport->rxq_grps[i
[Intel-wired-lan] [PATCH iwl-next v8 10/15] ixgbe: extend .info_get with() stored versions
Add functions reading inactive versions from the inactive flash bank. Print stored NVM, OROM and netlist versions by devlink when there is an ongoing update for E610 device. Reviewed-by: Mateusz Polchlopek Reviewed-by: Przemek Kitszel Tested-by: Bharath R Co-developed-by: Slawomir Mrozowicz Signed-off-by: Slawomir Mrozowicz Co-developed-by: Piotr Kwapulinski Signed-off-by: Piotr Kwapulinski Signed-off-by: Jedrzej Jagielski --- v3: use devlink_info_version_*_put() function; squash functions dealing with running and stored versions into single ones v5: add else to if/else if statements --- .../ethernet/intel/ixgbe/devlink/devlink.c| 214 -- drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c | 59 + drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h | 3 + 3 files changed, 252 insertions(+), 24 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/devlink/devlink.c b/drivers/net/ethernet/intel/ixgbe/devlink/devlink.c index 8f44c3dee0b5..6b45846f0ddd 100644 --- a/drivers/net/ethernet/intel/ixgbe/devlink/devlink.c +++ b/drivers/net/ethernet/intel/ixgbe/devlink/devlink.c @@ -6,6 +6,15 @@ struct ixgbe_info_ctx { char buf[128]; + struct ixgbe_orom_info pending_orom; + struct ixgbe_nvm_info pending_nvm; + struct ixgbe_netlist_info pending_netlist; + struct ixgbe_hw_dev_caps dev_caps; +}; + +enum ixgbe_devlink_version_type { + IXGBE_DL_VERSION_RUNNING, + IXGBE_DL_VERSION_STORED }; static void ixgbe_info_get_dsn(struct ixgbe_adapter *adapter, @@ -20,7 +29,8 @@ static void ixgbe_info_get_dsn(struct ixgbe_adapter *adapter, } static void ixgbe_info_orom_ver(struct ixgbe_adapter *adapter, - struct ixgbe_info_ctx *ctx) + struct ixgbe_info_ctx *ctx, + enum ixgbe_devlink_version_type type) { struct ixgbe_hw *hw = &adapter->hw; struct ixgbe_nvm_version nvm_ver; @@ -28,7 +38,14 @@ static void ixgbe_info_orom_ver(struct ixgbe_adapter *adapter, ctx->buf[0] = '\0'; if (hw->mac.type == ixgbe_mac_e610) { - struct ixgbe_orom_info *orom = &adapter->hw.flash.orom; + struct ixgbe_orom_info *orom; + + if (type == IXGBE_DL_VERSION_RUNNING) + orom = &adapter->hw.flash.orom; + else if (type == IXGBE_DL_VERSION_STORED) + orom = &ctx->pending_orom; + else + return; snprintf(ctx->buf, sizeof(ctx->buf), "%u.%u.%u", orom->major, orom->build, orom->patch); @@ -51,14 +68,23 @@ static void ixgbe_info_orom_ver(struct ixgbe_adapter *adapter, } static void ixgbe_info_eetrack(struct ixgbe_adapter *adapter, - struct ixgbe_info_ctx *ctx) + struct ixgbe_info_ctx *ctx, + enum ixgbe_devlink_version_type type) { struct ixgbe_hw *hw = &adapter->hw; struct ixgbe_nvm_version nvm_ver; if (hw->mac.type == ixgbe_mac_e610) { - snprintf(ctx->buf, sizeof(ctx->buf), "0x%08x", -hw->flash.nvm.eetrack); + u32 eetrack; + + if (type == IXGBE_DL_VERSION_RUNNING) + eetrack = hw->flash.nvm.eetrack; + else if (type == IXGBE_DL_VERSION_STORED) + eetrack = ctx->pending_nvm.eetrack; + else + return; + + snprintf(ctx->buf, sizeof(ctx->buf), "0x%08x", eetrack); return; } @@ -92,33 +118,65 @@ static void ixgbe_info_fw_build(struct ixgbe_adapter *adapter, } static void ixgbe_info_fw_srev(struct ixgbe_adapter *adapter, - struct ixgbe_info_ctx *ctx) + struct ixgbe_info_ctx *ctx, + enum ixgbe_devlink_version_type type) { - struct ixgbe_nvm_info *nvm = &adapter->hw.flash.nvm; + struct ixgbe_nvm_info *nvm; + + if (type == IXGBE_DL_VERSION_RUNNING) + nvm = &adapter->hw.flash.nvm; + else if (type == IXGBE_DL_VERSION_STORED) + nvm = &ctx->pending_nvm; + else + return; snprintf(ctx->buf, sizeof(ctx->buf), "%u", nvm->srev); } static void ixgbe_info_orom_srev(struct ixgbe_adapter *adapter, -struct ixgbe_info_ctx *ctx) +struct ixgbe_info_ctx *ctx, +enum ixgbe_devlink_version_type type) { - struct ixgbe_orom_info *orom = &adapter->hw.flash.orom; + struct ixgbe_orom_info *orom; + + if (type == IXGBE_DL_VERSION_RUNNING) + orom = &adapter->hw.flash.orom; + else if (type == IXGBE_DL_VERSION_STORED) + orom = &ctx->pending_orom; + else + return; sn
[Intel-wired-lan] [PATCH v9 iwl-next 08/10] idpf: add Tx timestamp flows
Add functions to request Tx timestamp for the PTP packets, read the Tx timestamp when the completion tag for that packet is being received, extend the Tx timestamp value and set the supported timestamping modes. Tx timestamp is requested for the PTP packets by setting a TSYN bit and index value in the Tx context descriptor. The driver assumption is that the Tx timestamp value is ready to be read when the completion tag is received. Then the driver schedules delayed work and the Tx timestamp value read is requested through virtchnl message. At the end, the Tx timestamp value is extended to 64-bit and provided back to the skb. Co-developed-by: Josh Hay Signed-off-by: Josh Hay Signed-off-by: Milena Olech --- v8 -> v9: update kernel_hwtstamp_config when timestamp mode is set, check link status in timestamp callbacks idpf_hwtstamp_get/set v7 -> v8: change the type of delta calculated when the timestamp is extended to 64 bit based on the device clock value v6 -> v7: change the method for preparing flow desciptor to set tstamp fields to 0 indirectly v5 -> v6: change locking mechanism in get_ts_info, clean timestamp fields when preparing flow descriptor to prevent collisions with PHY timestamping v4 -> v5: fix the spin_unlock_bh when the Tx timestamp is requested and the list of free latches is empty v3 -> v4: change Tx timestamp filters based on the PTP capabilities, use list_for_each_entry_safe when deleting list items, rewrite function that extends Tx timestamp value to 64 bits, minor fixes v2 -> v3: change get_timestamp_filter function name, split stats into vport-based and tx queue-based v1 -> v2: add timestamping stats, use ndo_hwtamp_get/ndo_hwstamp_set drivers/net/ethernet/intel/idpf/idpf.h| 20 ++ .../net/ethernet/intel/idpf/idpf_ethtool.c| 74 +- .../net/ethernet/intel/idpf/idpf_lan_txrx.h | 13 +- drivers/net/ethernet/intel/idpf/idpf_lib.c| 55 drivers/net/ethernet/intel/idpf/idpf_ptp.c| 239 +- drivers/net/ethernet/intel/idpf/idpf_ptp.h| 51 drivers/net/ethernet/intel/idpf/idpf_txrx.c | 141 ++- drivers/net/ethernet/intel/idpf/idpf_txrx.h | 11 +- .../net/ethernet/intel/idpf/idpf_virtchnl.c | 6 +- .../ethernet/intel/idpf/idpf_virtchnl_ptp.c | 235 + 10 files changed, 830 insertions(+), 15 deletions(-) diff --git a/drivers/net/ethernet/intel/idpf/idpf.h b/drivers/net/ethernet/intel/idpf/idpf.h index fe4d8ad75b04..d7dbf7d9c7d3 100644 --- a/drivers/net/ethernet/intel/idpf/idpf.h +++ b/drivers/net/ethernet/intel/idpf/idpf.h @@ -246,9 +246,23 @@ struct idpf_port_stats { u64_stats_t tx_busy; u64_stats_t tx_drops; u64_stats_t tx_dma_map_errs; + u64_stats_t tx_hwtstamp_skipped; struct virtchnl2_vport_stats vport_stats; }; +/** + * struct idpf_tx_tstamp_stats - Tx timestamp statistics + * @tx_hwtstamp_lock: Lock to protect Tx tstamp stats + * @tx_hwtstamp_discarded: Number of Tx skbs discarded due to cached PHC time + *being too old to correctly extend timestamp + * @tx_hwtstamp_flushed: Number of Tx skbs flushed due to interface closed + */ +struct idpf_tx_tstamp_stats { + struct mutex tx_hwtstamp_lock; + u32 tx_hwtstamp_discarded; + u32 tx_hwtstamp_flushed; +}; + /** * struct idpf_vport - Handle for netdevices and queue resources * @num_txq: Number of allocated TX queues @@ -293,6 +307,9 @@ struct idpf_port_stats { * @link_up: True if link is up * @sw_marker_wq: workqueue for marker packets * @tx_tstamp_caps: Capabilities negotiated for Tx timestamping + * @tstamp_config: The Tx tstamp config + * @tstamp_task: Tx timestamping task + * @tstamp_stats: Tx timestamping statistics */ struct idpf_vport { u16 num_txq; @@ -339,6 +356,9 @@ struct idpf_vport { wait_queue_head_t sw_marker_wq; struct idpf_ptp_vport_tx_tstamp_caps *tx_tstamp_caps; + struct kernel_hwtstamp_config tstamp_config; + struct work_struct tstamp_task; + struct idpf_tx_tstamp_stats tstamp_stats; }; /** diff --git a/drivers/net/ethernet/intel/idpf/idpf_ethtool.c b/drivers/net/ethernet/intel/idpf/idpf_ethtool.c index 59b1a1a09996..ec4183a609c4 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_ethtool.c +++ b/drivers/net/ethernet/intel/idpf/idpf_ethtool.c @@ -2,6 +2,7 @@ /* Copyright (C) 2023 Intel Corporation */ #include "idpf.h" +#include "idpf_ptp.h" /** * idpf_get_rxnfc - command to get RX flow classification rules @@ -479,6 +480,9 @@ static const struct idpf_stats idpf_gstrings_port_stats[] = { IDPF_PORT_STAT("tx-unicast_pkts", port_stats.vport_stats.tx_unicast), IDPF_PORT_STAT("tx-multicast_pkts", port_stats.vport_stats.tx_multicast), IDPF_PORT_STAT("tx-broadcast_pkts", port_stats.vport_stats.tx_broadcast), + IDPF_PORT_STAT("tx-hwtstamp_skipped", port_stats.tx_hwtstamp_skipped), + IDPF_PORT_STAT("tx-hwtstamp_flushed", tstamp_stats.tx_hwtstamp_flushed
[Intel-wired-lan] [PATCH v9 iwl-next 10/10] idpf: change the method for mailbox workqueue allocation
Since workqueues are created per CPU, the works scheduled to this workqueues are run on the CPU they were assigned. It may result in overloaded CPU that is not able to handle virtchnl messages in relatively short time. Allocating workqueue with WQ_UNBOUND and WQ_HIGHPRI flags allows scheduler to queue virtchl messages on less loaded CPUs, what eliminates delays. Reviewed-by: Alexander Lobakin Signed-off-by: Milena Olech --- drivers/net/ethernet/intel/idpf/idpf_main.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/intel/idpf/idpf_main.c b/drivers/net/ethernet/intel/idpf/idpf_main.c index 60bae3081035..022645f4fa9c 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_main.c +++ b/drivers/net/ethernet/intel/idpf/idpf_main.c @@ -198,9 +198,8 @@ static int idpf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_serv_wq_alloc; } - adapter->mbx_wq = alloc_workqueue("%s-%s-mbx", - WQ_UNBOUND | WQ_MEM_RECLAIM, 0, - dev_driver_string(dev), + adapter->mbx_wq = alloc_workqueue("%s-%s-mbx", WQ_UNBOUND | WQ_HIGHPRI, + 0, dev_driver_string(dev), dev_name(dev)); if (!adapter->mbx_wq) { dev_err(dev, "Failed to allocate mailbox workqueue\n"); -- 2.31.1
[Intel-wired-lan] [PATCH v9 iwl-next 06/10] idpf: add PTP clock configuration
PTP clock configuration operations - set time, adjust time and adjust frequency are required to control the clock and maintain synchronization process. Extend get PTP capabilities function to request for the clock adjustments and add functions to enable these actions using dedicated virtchnl messages. Reviewed-by: Alexander Lobakin Reviewed-by: Willem de Bruijn Tested-by: Mina Almasry Signed-off-by: Milena Olech --- v8 -> v9: minor - remove unnecessary dot in the function description drivers/net/ethernet/intel/idpf/idpf_ptp.c| 191 ++ drivers/net/ethernet/intel/idpf/idpf_ptp.h| 43 +++- .../net/ethernet/intel/idpf/idpf_virtchnl.c | 3 + .../ethernet/intel/idpf/idpf_virtchnl_ptp.c | 142 - 4 files changed, 376 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/intel/idpf/idpf_ptp.c b/drivers/net/ethernet/intel/idpf/idpf_ptp.c index 01e28085eb39..54b7ccb16da0 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_ptp.c +++ b/drivers/net/ethernet/intel/idpf/idpf_ptp.c @@ -48,6 +48,20 @@ void idpf_ptp_get_features_access(const struct idpf_adapter *adapter) ptp->get_cross_tstamp_access = idpf_ptp_get_access(adapter, direct, mailbox); + + /* Set the device clock time */ + direct = VIRTCHNL2_CAP_PTP_SET_DEVICE_CLK_TIME; + mailbox = VIRTCHNL2_CAP_PTP_SET_DEVICE_CLK_TIME; + ptp->set_dev_clk_time_access = idpf_ptp_get_access(adapter, + direct, + mailbox); + + /* Adjust the device clock time */ + direct = VIRTCHNL2_CAP_PTP_ADJ_DEVICE_CLK; + mailbox = VIRTCHNL2_CAP_PTP_ADJ_DEVICE_CLK_MB; + ptp->adj_dev_clk_time_access = idpf_ptp_get_access(adapter, + direct, + mailbox); } /** @@ -296,6 +310,154 @@ static int idpf_ptp_gettimex64(struct ptp_clock_info *info, return 0; } +/** + * idpf_ptp_settime64 - Set the time of the clock + * @info: the driver's PTP info structure + * @ts: timespec64 structure that holds the new time value + * + * Set the device clock to the user input value. The conversion from timespec + * to ns happens in the write function. + * + * Return: 0 on success, -errno otherwise. + */ +static int idpf_ptp_settime64(struct ptp_clock_info *info, + const struct timespec64 *ts) +{ + struct idpf_adapter *adapter = idpf_ptp_info_to_adapter(info); + enum idpf_ptp_access access; + int err; + u64 ns; + + access = adapter->ptp->set_dev_clk_time_access; + if (access != IDPF_PTP_MAILBOX) + return -EOPNOTSUPP; + + ns = timespec64_to_ns(ts); + + err = idpf_ptp_set_dev_clk_time(adapter, ns); + if (err) { + pci_err(adapter->pdev, "Failed to set the time, err: %pe\n", ERR_PTR(err)); + return err; + } + + return 0; +} + +/** + * idpf_ptp_adjtime_nonatomic - Do a non-atomic clock adjustment + * @info: the driver's PTP info structure + * @delta: Offset in nanoseconds to adjust the time by + * + * Return: 0 on success, -errno otherwise. + */ +static int idpf_ptp_adjtime_nonatomic(struct ptp_clock_info *info, s64 delta) +{ + struct timespec64 now, then; + int err; + + err = idpf_ptp_gettimex64(info, &now, NULL); + if (err) + return err; + + then = ns_to_timespec64(delta); + now = timespec64_add(now, then); + + return idpf_ptp_settime64(info, &now); +} + +/** + * idpf_ptp_adjtime - Adjust the time of the clock by the indicated delta + * @info: the driver's PTP info structure + * @delta: Offset in nanoseconds to adjust the time by + * + * Return: 0 on success, -errno otherwise. + */ +static int idpf_ptp_adjtime(struct ptp_clock_info *info, s64 delta) +{ + struct idpf_adapter *adapter = idpf_ptp_info_to_adapter(info); + enum idpf_ptp_access access; + int err; + + access = adapter->ptp->adj_dev_clk_time_access; + if (access != IDPF_PTP_MAILBOX) + return -EOPNOTSUPP; + + /* Hardware only supports atomic adjustments using signed 32-bit +* integers. For any adjustment outside this range, perform +* a non-atomic get->adjust->set flow. +*/ + if (delta > S32_MAX || delta < S32_MIN) + return idpf_ptp_adjtime_nonatomic(info, delta); + + err = idpf_ptp_adj_dev_clk_time(adapter, delta); + if (err) { + pci_err(adapter->pdev, "Failed to adjust the clock with delta %lld err: %pe\n", delta, ERR_PTR(err)); + return err; + } + + return 0; +} + +/** + * idpf_ptp_adjfine - Adjust clock increment rate + * @info: the driver's PTP info structure +
[Intel-wired-lan] [PATCH iwl-next v8 08/15] ixgbe: add .info_get extension specific for E610 devices
E610 devices give possibility to show more detailed info than the previous boards. Extend reporting NVM info with following pieces: fw.mgmt.api -> version number of the API fw.mgmt.build -> identifier of the source for the FW fw.psid.api -> version defining the format of the flash contents fw.netlist -> version of the netlist module fw.netlist.build -> first 4 bytes of the netlist hash Reviewed-by: Mateusz Polchlopek Tested-by: Bharath R Co-developed-by: Slawomir Mrozowicz Signed-off-by: Slawomir Mrozowicz Co-developed-by: Piotr Kwapulinski Signed-off-by: Piotr Kwapulinski Signed-off-by: Jedrzej Jagielski --- Documentation/networking/devlink/ixgbe.rst| 26 .../ethernet/intel/ixgbe/devlink/devlink.c| 132 +- 2 files changed, 153 insertions(+), 5 deletions(-) diff --git a/Documentation/networking/devlink/ixgbe.rst b/Documentation/networking/devlink/ixgbe.rst index b63645de37e8..a41073a62776 100644 --- a/Documentation/networking/devlink/ixgbe.rst +++ b/Documentation/networking/devlink/ixgbe.rst @@ -38,3 +38,29 @@ The ``ixgbe`` driver reports the following versions - 0x8d0d - Unique identifier of the firmware image file that was loaded onto the device. Also referred to as the EETRACK identifier of the NVM. +* - ``fw.mgmt.api`` + - running + - 1.5.1 + - 3-digit version number (major.minor.patch) of the API exported over +the AdminQ by the management firmware. Used by the driver to +identify what commands are supported. Historical versions of the +kernel only displayed a 2-digit version number (major.minor). +* - ``fw.mgmt.build`` + - running + - 0x305d955f + - Unique identifier of the source for the management firmware. +* - ``fw.psid.api`` + - running + - 0.80 + - Version defining the format of the flash contents. +* - ``fw.netlist`` + - running + - 1.1.2000-6.7.0 + - The version of the netlist module. This module defines the device's +Ethernet capabilities and default settings, and is used by the +management firmware as part of managing link and device +connectivity. +* - ``fw.netlist.build`` + - running + - 0xee16ced7 + - The first 4 bytes of the hash of the netlist module contents. diff --git a/drivers/net/ethernet/intel/ixgbe/devlink/devlink.c b/drivers/net/ethernet/intel/ixgbe/devlink/devlink.c index d91252da4a61..365310a6910d 100644 --- a/drivers/net/ethernet/intel/ixgbe/devlink/devlink.c +++ b/drivers/net/ethernet/intel/ixgbe/devlink/devlink.c @@ -19,14 +19,22 @@ static void ixgbe_info_get_dsn(struct ixgbe_adapter *adapter, snprintf(ctx->buf, sizeof(ctx->buf), "%8phD", dsn); } -static void ixgbe_info_nvm_ver(struct ixgbe_adapter *adapter, - struct ixgbe_info_ctx *ctx) +static void ixgbe_info_orom_ver(struct ixgbe_adapter *adapter, + struct ixgbe_info_ctx *ctx) { struct ixgbe_hw *hw = &adapter->hw; struct ixgbe_nvm_version nvm_ver; ctx->buf[0] = '\0'; + if (hw->mac.type == ixgbe_mac_e610) { + struct ixgbe_orom_info *orom = &adapter->hw.flash.orom; + + snprintf(ctx->buf, sizeof(ctx->buf), "%u.%u.%u", +orom->major, orom->build, orom->patch); + return; + } + ixgbe_get_oem_prod_version(hw, &nvm_ver); if (nvm_ver.oem_valid) { snprintf(ctx->buf, sizeof(ctx->buf), "%x.%x.%x", @@ -48,6 +56,12 @@ static void ixgbe_info_eetrack(struct ixgbe_adapter *adapter, struct ixgbe_hw *hw = &adapter->hw; struct ixgbe_nvm_version nvm_ver; + if (hw->mac.type == ixgbe_mac_e610) { + snprintf(ctx->buf, sizeof(ctx->buf), "0x%08x", +hw->flash.nvm.eetrack); + return; + } + ixgbe_get_oem_prod_version(hw, &nvm_ver); /* No ETRACK version for OEM */ @@ -60,6 +74,112 @@ static void ixgbe_info_eetrack(struct ixgbe_adapter *adapter, snprintf(ctx->buf, sizeof(ctx->buf), "0x%08x", nvm_ver.etk_id); } +static void ixgbe_info_fw_api(struct ixgbe_adapter *adapter, + struct ixgbe_info_ctx *ctx) +{ + struct ixgbe_hw *hw = &adapter->hw; + + snprintf(ctx->buf, sizeof(ctx->buf), "%u.%u.%u", +hw->api_maj_ver, hw->api_min_ver, hw->api_patch); +} + +static void ixgbe_info_fw_build(struct ixgbe_adapter *adapter, + struct ixgbe_info_ctx *ctx) +{ + struct ixgbe_hw *hw = &adapter->hw; + + snprintf(ctx->buf, sizeof(ctx->buf), "0x%08x", hw->fw_build); +} + +static void ixgbe_info_fw_srev(struct ixgbe_adapter *adapter, + struct ixgbe_info_ctx *ctx) +{ + struct ixgbe_nvm_info *nvm = &adapter->hw.flash.nvm; + + snprintf(ctx->buf, sizeof(ctx->buf), "%u", nvm->srev); +} + +static void ixgbe_info_oro
[Intel-wired-lan] [PATCH net v2 3/5] net: lan743x: reject unsupported external timestamp requests
The lan743x_ptp_io_event_cap_en() function checks that the given request sets only one of PTP_RISING_EDGE or PTP_FALLING_EDGE, but not both. However, this driver does not check whether other flags (such as PTP_EXT_OFF) are set, nor whether any future unrecognized flags are set. Fix this by adding the appropriate check to the lan743x_ptp_io_extts() function. Fixes: 60942c397af6 ("net: lan743x: Add support for PTP-IO Event Input External Timestamp (extts)") Signed-off-by: Jacob Keller --- drivers/net/ethernet/microchip/lan743x_ptp.c | 6 ++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/ethernet/microchip/lan743x_ptp.c b/drivers/net/ethernet/microchip/lan743x_ptp.c index 4a777b449ecd03ac0d7576f8570f1a7794fb3d06..0be44dcb339387e9756f36f909f65c20870bc49b 100644 --- a/drivers/net/ethernet/microchip/lan743x_ptp.c +++ b/drivers/net/ethernet/microchip/lan743x_ptp.c @@ -942,6 +942,12 @@ static int lan743x_ptp_io_extts(struct lan743x_adapter *adapter, int on, extts = &ptp->extts[index]; + if (extts_request->flags & ~(PTP_ENABLE_FEATURE | +PTP_RISING_EDGE | +PTP_FALLING_EDGE | +PTP_STRICT_FLAGS)) + return -EOPNOTSUPP; + if (on) { extts_pin = ptp_find_pin(ptp->ptp_clock, PTP_PF_EXTTS, index); if (extts_pin < 0) -- 2.48.1.397.gec9d649cc640
Re: [Intel-wired-lan] [iwl-next v4 1/1] iidc/ice/irdma: Update IDC to support multiple consumers
On 3/2/2025 12:26 AM, Leon Romanovsky wrote: On Wed, Feb 26, 2025 at 11:01:52PM +, Ertman, David M wrote: -Original Message- From: Leon Romanovsky Sent: Wednesday, February 26, 2025 10:50 AM To: Ertman, David M Cc: Nikolova, Tatyana E ; j...@nvidia.com; intel-wired-...@lists.osuosl.org; linux-r...@vger.kernel.org; net...@vger.kernel.org Subject: Re: [iwl-next v4 1/1] iidc/ice/irdma: Update IDC to support multiple consumers On Wed, Feb 26, 2025 at 05:36:44PM +, Ertman, David M wrote: -Original Message- From: Leon Romanovsky Sent: Monday, February 24, 2025 11:56 PM To: Nikolova, Tatyana E Cc: j...@nvidia.com; intel-wired-...@lists.osuosl.org; linux- r...@vger.kernel.org; net...@vger.kernel.org; Ertman, David M Subject: Re: [iwl-next v4 1/1] iidc/ice/irdma: Update IDC to support multiple consumers On Mon, Feb 24, 2025 at 11:04:28PM -0600, Tatyana Nikolova wrote: From: Dave Ertman To support RDMA for E2000 product, the idpf driver will use the IDC interface with the irdma auxiliary driver, thus becoming a second consumer of it. This requires the IDC be updated to support multiple consumers. The use of exported symbols no longer makes sense because it will require all core drivers (ice/idpf) that can interface with irdma auxiliary driver to be loaded even if hardware is not present for those drivers. In auxiliary bus world, the code drivers (ice/idpf) need to created auxiliary devices only if specific device present. That auxiliary device will trigger the load of specific module (irdma in our case). EXPORT_SYMBOL won't trigger load of irdma driver, but the opposite is true, load of irdma will trigger load of ice/idpf drivers (depends on their exported symbol). To address this, implement an ops struct that will be universal set of naked function pointers that will be populated by each core driver for the irdma auxiliary driver to call. No, we worked very hard to make proper HW discovery and driver autoload, let's not return back. For now, it is no-go. Hi Leon, I am a little confused about what the problem here is. The main issue I pull from your response is: Removing exported symbols will stop ice/idpf from autoloading when irdma loads. Is this correct or did I miss your point? It is one of the main points. But, if there is an ice or idpf supported device present in the system, the appropriate driver will have already been loaded anyway (and gone through its probe flow to create auxiliary devices). If it is not loaded, then the system owner has either unloaded it manually or blacklisted it. This would not cause an issue anyway, since irdma and ice/idpf can load in any order. There are two assumptions above, which both not true. 1. Users never issue "modprobe irdma" command alone and always will call to whole chain "modprobe ice ..." before. 2. You open-code module subsystem properly with reference counters, ownership and locks to protect from function pointers to be set/clear dynamically. Ah, I see your reasoning now. Our goal was to make the two modules independent, with no prescribed load order mandated, and utilize the auxiliary bus and device subsystem to handle load order and unload of one or the other module. The auxiliary device only has the lifespan of the core PCI driver, so if the core driver unloads, then the auxiliary device gets destroyed, and the associated link based off it will be gone. We wanted to be able to unload and reload either of the modules (core or irdma) and have the interaction be able to restart with a new probe. All our inter-driver function calls are protected by device lock on the auxiliary device for the duration of the call. Yes, you are trying to return to pre-aux era. The main motivation to go with callbacks to the parent driver instead of using exported symbols is to allow loading only the parent driver required for a particular deployment. irdma is a common rdma auxilary driver that supports multiple parent pci drivers(ice, idpf, i40e, iavf). If we use exported symbols, all these modules will get loaded even on a system with only idpf device. The documentation for auxiliary bus https://docs.kernel.org/driver-api/auxiliary_bus.html shows an example on how shared data/callbacks can be used to establish connection with the parent. Auxiliary devices are created and registered by a subsystem-level core device that needs to break up its functionality into smaller fragments. One way to extend the scope of an auxiliary_device is to encapsulate it within a domain-specific structure defined by the parent device. This structure contains the auxiliary_device and any associated shared data/callbacks needed to establish the connection with the parent. An example is: struct foo { struct auxiliary_device auxdev; void (*connect)(struct auxiliary_device *auxdev); void (*disconnect)(struct auxiliary_device *auxdev); void *data; }; This example clear
Re: [Intel-wired-lan] [PATCH iwl-next v7 11/15] ixgbe: add device flash update via devlink
From: Simon Horman Sent: Wednesday, March 12, 2025 3:56 PM >On Wed, Mar 12, 2025 at 01:58:39PM +0100, Jedrzej Jagielski wrote: > >... > >> diff --git a/Documentation/networking/devlink/ixgbe.rst >> b/Documentation/networking/devlink/ixgbe.rst >> index a41073a62776..41aedf4b8017 100644 >> --- a/Documentation/networking/devlink/ixgbe.rst >> +++ b/Documentation/networking/devlink/ixgbe.rst >> @@ -64,3 +64,27 @@ The ``ixgbe`` driver reports the following versions >>- running >>- 0xee16ced7 >>- The first 4 bytes of the hash of the netlist module contents. >> + >> +Flash Update >> + >> +The ``ixgbe`` driver implements support for flash update using the >> +``devlink-flash`` interface. It supports updating the device flash using a >> +combined flash image that contains the ``fw.mgmt``, ``fw.undi``, and >> +``fw.netlist`` components. >> +.. list-table:: List of supported overwrite modes >> + :widths: 5 95 > >Hi Jedrzej, > >make htmldocs flags two warnings, which I believe can be resolved by >adding a blank line here. > > .../ixgbe.rst:75: ERROR: Unexpected indentation. > .../ixgbe.rst:76: WARNING: Field list ends without a blank line; unexpected > unindent. Hello Simon thanks for finding these. I will fix it and resend it later today probably. > >> + * - Bits >> + - Behavior >> + * - ``DEVLINK_FLASH_OVERWRITE_SETTINGS`` >> + - Do not preserve settings stored in the flash components being >> + updated. This includes overwriting the port configuration that >> + determines the number of physical functions the device will >> + initialize with. >> + * - ``DEVLINK_FLASH_OVERWRITE_SETTINGS`` and >> ``DEVLINK_FLASH_OVERWRITE_IDENTIFIERS`` >> + - Do not preserve either settings or identifiers. Overwrite everything >> + in the flash with the contents from the provided image, without >> + performing any preservation. This includes overwriting device >> + identifying fields such as the MAC address, Vital product Data (VPD) >> area, >> + and device serial number. It is expected that this combination be >> used with an >> + image customized for the specific device. >> + > >...