From 1298adebf7661a3e5fdd6e0c1f64c0457c9c3243 Mon Sep 17 00:00:00 2001 From: Sameer Saurabh Date: Wed, 10 Mar 2021 05:27:30 -0500 Subject: [PATCH] atlantic forwarding driver v1.1.22 - Fixed header file and warning complain - Atl-fwd: Fix name string for mac_phy stats in ethtool-dump - Atl-fwd: Minor additions to ethtool dump implementation - Atl-fwd: Add ethtool-dump parser - ATLDRV-1776: Fix for link flip during IPA ring reconfig - Atl-fwd: Update crash-dump structure to fixed size structure - Atl-fwd: Correct driver README file and export couple of APIs - Atl-fwd: Populate Action resolve table and Ring data in the ethtool-dump - ATLDRV-1766: Fix to update HWTS ring tail value to HW - Fix error in populating the extended stats - AQC113 register dump support - stats+crashdump implementation draft - Statistics and crash dump API proposal - factor out fwd stuff to drop headers dependencies - ATLDRV-1744] - Add FW version check in Atl-fwd driver - Move check for PTP UDP packets to separate function, Enable TX pad insert and Handle all FFs in ptp tx TS - ATLDRV-1582] - Link not Up after FLR reset - ATLDRV-1653] - Packet with vlan id 1 doesn't get received when rx vlan filter is disabled - ATLDRV-1659] - Failed to compile with CONFIG_ATLFWD_FWD=y flag on RHEL 8.3 kernel. Change-Id: Ie1c4a42f9938b0b4dfb26418a755010baadad011 Signed-off-by: Sameer Saurabh Git-commit: d86086216c6d511576d63dd216ab2cc1a8d46309 Git-repo: https://github.com/aquantia/linux-4.14-atlantic-forwarding Signed-off-by: Raihan Haider --- .../ethernet/aquantia/atlantic-fwd/atl2_fw.c | 9 + .../aquantia/atlantic-fwd/atl_common.h | 17 +- .../ethernet/aquantia/atlantic-fwd/atl_dump.h | 123 ++++++++ .../atlantic-fwd/atl_dump_parser/README | 21 ++ .../atl_dump_parser/atl_dump_parser.c | 296 ++++++++++++++++++ .../atl_dump_parser/atl_dump_parser.h | 10 + .../aquantia/atlantic-fwd/atl_ethtool.c | 52 +-- .../ethernet/aquantia/atlantic-fwd/atl_fw.c | 40 +++ .../ethernet/aquantia/atlantic-fwd/atl_fwd.c | 215 +++++++++++++ .../ethernet/aquantia/atlantic-fwd/atl_fwd.h | 39 ++- .../aquantia/atlantic-fwd/atl_fwdnl.c | 5 +- .../aquantia/atlantic-fwd/atl_fwdnl_params.c | 1 + .../ethernet/aquantia/atlantic-fwd/atl_hw.c | 46 ++- .../aquantia/atlantic-fwd/atl_hw_ptp.c | 2 + .../aquantia/atlantic-fwd/atl_macsec.c | 1 + .../ethernet/aquantia/atlantic-fwd/atl_main.c | 51 ++- .../ethernet/aquantia/atlantic-fwd/atl_ptp.c | 9 +- .../ethernet/aquantia/atlantic-fwd/atl_regs.h | 17 + .../ethernet/aquantia/atlantic-fwd/atl_ring.c | 30 +- .../aquantia/atlantic-fwd/atl_stats.h | 11 +- .../aquantia/atlantic-fwd/release_notes.txt | 35 +++ 21 files changed, 973 insertions(+), 57 deletions(-) create mode 100644 drivers/net/ethernet/aquantia/atlantic-fwd/atl_dump.h create mode 100644 drivers/net/ethernet/aquantia/atlantic-fwd/atl_dump_parser/README create mode 100644 drivers/net/ethernet/aquantia/atlantic-fwd/atl_dump_parser/atl_dump_parser.c create mode 100644 drivers/net/ethernet/aquantia/atlantic-fwd/atl_dump_parser/atl_dump_parser.h diff --git a/drivers/net/ethernet/aquantia/atlantic-fwd/atl2_fw.c b/drivers/net/ethernet/aquantia/atlantic-fwd/atl2_fw.c index 59991ae6839a..ef8aed24a729 100644 --- a/drivers/net/ethernet/aquantia/atlantic-fwd/atl2_fw.c +++ b/drivers/net/ethernet/aquantia/atlantic-fwd/atl2_fw.c @@ -973,6 +973,15 @@ int atl2_fw_init(struct atl_hw *hw) atl2_get_fw_version(hw); + /* Warn if FW is lower than 1.3.1 */ + if (((mcp->fw_rev >> 24) < 1) || + (((mcp->fw_rev >> 16) & 0xFFU) < 3) || + ((mcp->fw_rev & 0xFFFFU) < 1)) + atl_dev_warn("FW_version: %u.%u.%u, is not stable version", + (mcp->fw_rev >> 24), + ((mcp->fw_rev >> 16) & 0xFFU), + (mcp->fw_rev & 0xFFFFU)); + mcp->ops = &atl2_fw_ops; atl_dev_dbg("Detect ATL2FW %x\n", mcp->fw_rev); diff --git a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_common.h b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_common.h index cd0814608d29..29a7525bf4fa 100644 --- a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_common.h +++ b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_common.h @@ -20,7 +20,7 @@ #include #include -#define ATL_VERSION "1.1.18" +#define ATL_VERSION "1.1.22" struct atl_nic; @@ -32,8 +32,6 @@ struct atl_nic; #define ATL_MAX_QUEUES 8 -#include "atl_fwd.h" - struct atl_ptp; enum { @@ -414,6 +412,7 @@ void atl_update_global_stats(struct atl_nic *nic); void atl_set_loopback(struct atl_nic *nic, int idx, bool on); void atl_set_intr_mod(struct atl_nic *nic); void atl_update_ntuple_flt(struct atl_nic *nic, int idx); +int atl_vlan_promisc_status(struct net_device *ndev); void atl_set_vlan_promisc(struct atl_hw *hw, int promisc); int atl_hwsem_get(struct atl_hw *hw, int idx); void atl_hwsem_put(struct atl_hw *hw, int idx); @@ -424,18 +423,6 @@ int atl_msm_write(struct atl_hw *hw, uint32_t addr, uint32_t val); int atl_update_eth_stats(struct atl_nic *nic); void atl_adjust_eth_stats(struct atl_ether_stats *stats, struct atl_ether_stats *base, bool add); -void atl_fwd_release_rings(struct atl_nic *nic); -#if IS_ENABLED(CONFIG_ATLFWD_FWD) -enum atl_fwd_notify; -int atl_fwd_suspend_rings(struct atl_nic *nic); -int atl_fwd_resume_rings(struct atl_nic *nic); -void atl_fwd_notify(struct atl_nic *nic, enum atl_fwd_notify notif, void *data); -#else -static inline int atl_fwd_suspend_rings(struct atl_nic *nic) { return 0; } -static inline int atl_fwd_resume_rings(struct atl_nic *nic) { return 0; } -static inline void atl_fwd_notify(struct atl_nic *nic, - enum atl_fwd_notify notif, void *data) {} -#endif int atl_get_lpi_timer(struct atl_nic *nic, uint32_t *lpi_delay); void atl_refresh_rxfs(struct atl_nic *nic); void atl_schedule_work(struct atl_nic *nic); diff --git a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_dump.h b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_dump.h new file mode 100644 index 000000000000..f4a415dea82c --- /dev/null +++ b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_dump.h @@ -0,0 +1,123 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Atlantic Network Driver + * + * Copyright (C) 2021 Marvell International Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _ATL_DUMP_H_ +#define _ATL_DUMP_H_ + +enum atl_crash_dump_types { + atl_crash_dump_type_regs = 0, + atl_crash_dump_type_fwiface = 1, + atl_crash_dump_type_act_res = 2, + atl_crash_dump_type_ring = 3, +}; + +/** Some of the registers we can not read safely from the device. + * Those will not be read, with value 0xFFFFFFFF stored instead. + */ +struct atl_crash_dump_regs { + u32 type; + u32 length; + union { + u32 regs_data[0x9000/4]; + struct{ + u32 mif[0x1000/4]; + u32 pci[0x1000/4]; + u32 itr[0x1000/4]; + u32 com[0x1000/4]; + u32 mac_phy[0x1000/4]; + union { + u32 rx[0x2000/4]; + struct{ + u32 res1[0x700/4]; + u32 pb_ctrl; + u32 res2; + u32 pb_status; + u32 res3; + /* 0x5710 */ + struct{ + u32 pb_reg1; + u32 pb_reg2; + u32 pb_reg3; + } pb[8]; + u32 res4[0x100]; /* TODO */ + /* 0x5B00 */ + struct{ + u32 base_lo; + u32 base_hi; + u32 ctrl; + u32 head; + u32 tail; + u32 status; + u32 size; + u32 threshold; + } dma_desc[32]; + } layout; + }; + u32 tx[0x2000/4]; + } layout; + }; +}; + +struct atl_crash_dump_fwiface { + u32 type; + u32 length; + /* struct fw_interface_in */ + u32 fw_interface_in[0x1000/4]; + /* struct fw_interface_out */ + u32 fw_interface_out[0x1000/4]; +}; + +/* Record table size of 128 with each entry holding (tag, mask, action) */ +#define ATL_ACT_RES_TABLE_SIZE 384 +struct atl_crash_dump_act_res { + u32 type; + u32 length; + u32 act_res_data[ATL_ACT_RES_TABLE_SIZE]; +}; + +/* max_size = 'ring_size * (tx + rx) * 16 byte raw descriptor data' */ +#define ATL_MAX_RING_DESC_SIZE ATL_MAX_RING_SIZE * 32 +struct atl_crash_dump_ring { + u32 type; + u32 length; + u32 index; + u32 rx_head; + u32 rx_tail; + u32 tx_head; + u32 tx_tail; + u32 rx_ring_size; + u32 tx_ring_size; + u8 ring_data[ATL_MAX_RING_DESC_SIZE]; +}; + +/* This is an extensible structure to collect various debug data from + * AQC device + */ +struct atl_crash_dump { + u32 length; /* total crash structure length, in bytes */ + u32 sections_count; /* number of sections of type atl_crash_dump* following */ + u8 drv_version[16]; + u8 fw_version[16]; + union { + struct { + struct atl_crash_dump_regs regs; + struct atl_crash_dump_fwiface fwiface; + struct atl_crash_dump_act_res act_res; + struct atl_crash_dump_ring ring[ATL_MAX_QUEUES]; + } antigua; + struct { + struct atl_crash_dump_regs regs; + struct atl_crash_dump_ring ring[ATL_MAX_QUEUES]; + } atlantic; + }; +}; + + +#endif diff --git a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_dump_parser/README b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_dump_parser/README new file mode 100644 index 000000000000..fbf0aeec4ccf --- /dev/null +++ b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_dump_parser/README @@ -0,0 +1,21 @@ +The tool atl_dump_parser is used to parse the register/device dump collected +using "ethtool -d" command. Parser accepts dump in the binary format, hence the +dump must be collected using 'raw' option i.e., 'ethtool -d raw on' + +Use gcc to build the binary from sources, + gcc -o atl_dump_parser atl_dump_parser.c + +Example: +-------- +1. Collect ethtool dump from SUT machine + #ethtool -d enp1s0 raw on > ethd_dump + +2. Parse the dump + #ls + atl_dump_parser ethd_dump + #./atl_dump_parser ethd_dump + Parsing is completed successfully + #ls ethd_dump_parsed + action_resolver.txt atl_dump_parser ethd_dump fw_interface.txt registers.txt rings.txt + # + Parsed data will be copied to the text files under _parsed folder. diff --git a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_dump_parser/atl_dump_parser.c b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_dump_parser/atl_dump_parser.c new file mode 100644 index 000000000000..00eb433bd596 --- /dev/null +++ b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_dump_parser/atl_dump_parser.c @@ -0,0 +1,296 @@ +#include +#include +#include +#include +#include +#include +#include +#include "atl_dump_parser.h" +#include "../atl_dump.h" + +#define DEV_FILE "device.txt" +#define REG_FILE "registers.txt" +#define FW_IFACE_FILE "fw_interface.txt" +#define ACT_RES_FILE "action_resolver.txt" +#define RING_FILE "rings.txt" + +struct section_header { + u32 type; + u32 length; +}; + +char out_folder[64]; + +int dump_device_info(struct atl_crash_dump *crash_dump) +{ + char file_name[64]; + FILE *file; + + snprintf(file_name, 64, "%s/%s", out_folder, DEV_FILE); + file = fopen(file_name, "w"); + if (file == NULL) { + printf("Error opening file %s\n", file_name); + return -1; + } + + fprintf(file, "Driver version: %s\n", crash_dump->drv_version); + fprintf(file, "FW version: %s\n", crash_dump->fw_version); + + fclose(file); + + return 0; +} + +int dump_registers(struct atl_crash_dump_regs *reg) +{ + int block = 0x1000/4, i, offset; + char file_name[64]; + FILE *file; + + snprintf(file_name, 64, "%s/%s", out_folder, REG_FILE); + file = fopen(file_name, "w"); + if (file == NULL) { + printf("Error opening file %s\n", file_name); + return -1; + } + + /* Skip MIF block */ + + offset = block * 4; + fprintf(file, "PCI Registers\n"); + fprintf(file, "=============\n"); + for (i = 0; i < block; i++) + fprintf(file, "0x%08x: 0x%08x\n", offset + i * 4, reg->layout.pci[i]); + + offset += block * 4; + fprintf(file, "\n\nInterrupt Registers\n"); + fprintf(file, "=====================\n"); + for (i = 0; i < block; i++) + fprintf(file, "0x%08x: 0x%08x\n", offset + i * 4, reg->layout.itr[i]); + + offset += block * 4; + fprintf(file, "\n\nCOM Registers\n"); + fprintf(file, "===============\n"); + for (i = 0; i < block; i++) + fprintf(file, "0x%08x: 0x%08x\n", offset + i * 4, reg->layout.com[i]); + + offset += block * 4; + fprintf(file, "\n\nMac Phy Registers\n"); + fprintf(file, "=====================\n"); + for (i = 0; i < block; i++) + fprintf(file, "0x%08x: 0x%08x\n", offset + i * 4, reg->layout.mac_phy[i]); + + offset += block * 4; + fprintf(file, "\n\nRx Registers\n"); + fprintf(file, "===============\n"); + /* Rx block size is 0x2000 */ + for (i = 0; i < block * 2; i++) + fprintf(file, "0x%08x: 0x%08x\n", offset + i * 4, reg->layout.rx[i]); + + offset += block * 2 * 4; + fprintf(file, "\n\nTx Registers\n"); + fprintf(file, "===============\n"); + /* Tx block size is 0x2000 */ + for (i = 0; i < block * 2; i++) + fprintf(file, "0x%08x: 0x%08x\n", offset + i * 4, reg->layout.tx[i]); + + fclose(file); + + return 0; +} + +int dump_fwiface(struct atl_crash_dump_fwiface *fwiface) +{ + int block = 0x1000/4, i; + char file_name[64]; + FILE *file; + + snprintf(file_name, 64, "%s/%s", out_folder, FW_IFACE_FILE); + file = fopen(file_name, "w"); + if (file == NULL) { + printf("Error opening file %s\n", file_name); + return -1; + } + + fprintf(file, "FW input interface\n"); + fprintf(file, "==================\n"); + for (i = 0; i < block; i += 4) + fprintf(file, "0x%08x:\t0x%08x 0x%08x 0x%08x 0x%08x\n", i, + fwiface->fw_interface_in[i], fwiface->fw_interface_in[i + 1], + fwiface->fw_interface_in[i + 2], fwiface->fw_interface_in[i + 3]); + + fprintf(file, "\n\nFW output interface\n"); + fprintf(file, "=======================\n"); + for (i = 0; i < block; i += 4) + fprintf(file, "0x%08x:\t0x%08x 0x%08x 0x%08x 0x%08x\n", i, + fwiface->fw_interface_out[i], fwiface->fw_interface_out[i + 1], + fwiface->fw_interface_out[i + 2], fwiface->fw_interface_out[i + 3]); + + fclose(file); + + return 0; +} + +int dump_act_res(struct atl_crash_dump_act_res *act_res) +{ + char file_name[64]; + int i, idx; + FILE *file; + + snprintf(file_name, 64, "%s/%s", out_folder, ACT_RES_FILE); + file = fopen(file_name, "w"); + if (file == NULL) { + printf("Error opening file %s\n", file_name); + return -1; + } + + fprintf(file, "RECORD RESOLVER TAG TAG Mask Action\n"); + fprintf(file, "==================================================\n"); + for (i = 0, idx = 0; i < ATL_ACT_RES_TABLE_SIZE / 3; i++) { + fprintf(file, "%d\t0x%08x\t0x%08x\t0x%08x\n", i, act_res->act_res_data[idx++], + act_res->act_res_data[idx++], act_res->act_res_data[idx++]); + } + + fclose(file); + + return 0; +} + +int dump_ring(struct atl_crash_dump_ring *ring) +{ + char file_name[64]; + FILE *file; + u32 *data; + int i; + + /* Assumption - file 'rings.txt' shouldn't exists */ + snprintf(file_name, 64, "%s/%s", out_folder, RING_FILE); + file = fopen(file_name, "a+"); + if (file == NULL) { + printf("Error opening file %s\n", file_name); + return -1; + } + + fprintf(file, "Ring Index %d\n", ring->index); + fprintf(file, "==============\n"); + fprintf(file, "Rx head = 0x%08x tail = 0x%08x\n", ring->rx_head, ring->rx_tail); + fprintf(file, "Tx head = 0x%08x tail = 0x%08x\n", ring->tx_head, ring->tx_tail); + fprintf(file, "HW Ring rx_size = %d tx_size = %d\n", ring->rx_ring_size, ring->tx_ring_size); + fprintf(file, "Rx Ring descriptor:\n"); + fprintf(file, "-------------------\n"); + data = (u32 *)ring->ring_data; + for (i = 0; i < ring->rx_ring_size; i += 4) + fprintf(file, "0x%08x:\t0x%08x 0x%08x 0x%08x 0x%08x\n", i, data[i], data[i + 1], + data[i + 2], data[i + 3]); + fprintf(file, "Tx Ring descriptor:\n"); + fprintf(file, "-------------------\n"); + data = (u32 *)ring->ring_data + ring->rx_ring_size; + for (i = 0; i < ring->tx_ring_size; i += 4) + fprintf(file, "0x%08x:\t0x%08x 0x%08x 0x%08x 0x%08x\n", i, data[i], data[i + 1], + data[i + 2], data[i + 3]); + fprintf(file, "\n"); + + fclose(file); + + return 0; + +} + +int main(int argc, char *argv[]) +{ + struct atl_crash_dump *crash_dump; + struct section_header *header; + int i, offset, ret = 0; + time_t t = time(NULL); + struct tm *tm_val; + FILE *input_file; + struct stat st; + char *buffer; + + if (argc < 2) { + printf("No intput file\n"); + return -1; + } + + if (stat(argv[1], &st) == -1) { + printf("File stat error\n"); + return -1; + } + + buffer = malloc(st.st_size); + if (!buffer) { + printf("Mem alloc error\n"); + return -1; + } + /* open the source file for reading */ + input_file = fopen(argv[1],"rb"); + if (input_file == NULL) { + ret = -1; + printf("Error opening file %s\n", argv[1]); + goto err; + } + + fread(buffer, sizeof(char), st.st_size, input_file); + fclose(input_file); + + tm_val = localtime(&t); + tm_val = NULL; + if (tm_val) + snprintf(out_folder, 64, "%s_%02d-%02d-%02d_%02d-%02d-%02d", argv[1], + tm_val->tm_mon + 1, (int) tm_val->tm_mday, 1900 + tm_val->tm_year, + tm_val->tm_hour, tm_val->tm_min, tm_val->tm_sec); + else + snprintf(out_folder, 64, "%s_parsed", argv[1]); + if (stat(out_folder, &st) == -1) { + if (mkdir(out_folder, 0644) == -1) { + ret = -1; + printf("Failed to creat folder` %s\n", out_folder); + goto err; + } + } + + crash_dump = (struct atl_crash_dump *)buffer; + ret = dump_device_info(crash_dump); + if (ret) + goto err; + + offset = offsetof(struct atl_crash_dump, antigua); + for (i = 0; i < crash_dump->sections_count; i++) { + header = (struct section_header *)(buffer + offset); + switch (header->type) { + case atl_crash_dump_type_regs: + ret = dump_registers((struct atl_crash_dump_regs *)(buffer + offset)); + if (ret) + goto err; + break; + case atl_crash_dump_type_fwiface: + ret = dump_fwiface((struct atl_crash_dump_fwiface *)(buffer + offset)); + if (ret) + goto err; + break; + case atl_crash_dump_type_act_res: + ret = dump_act_res((struct atl_crash_dump_act_res *)(buffer + offset)); + if (ret) + goto err; + break; + case atl_crash_dump_type_ring: + ret = dump_ring((struct atl_crash_dump_ring *)(buffer + offset)); + if (ret) + goto err; + break; + default: + printf("Parsing Error - invalid section\n"); + goto err; + } + offset += header->length; + } + +err: + free(buffer); + if (ret) + printf("Failed to parse the dump\n"); + else + printf("Parsing is completed successfully\n"); + + return 0; +} diff --git a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_dump_parser/atl_dump_parser.h b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_dump_parser/atl_dump_parser.h new file mode 100644 index 000000000000..698036f78968 --- /dev/null +++ b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_dump_parser/atl_dump_parser.h @@ -0,0 +1,10 @@ +#ifndef __ATL_DUMP_PARSER +#define __ATL_DUMP_PARSER + +#define ATL_MAX_RING_SIZE (8192 - 8) +#define ATL_MAX_QUEUES 8 + +typedef unsigned int u32; +typedef unsigned char u8; + +#endif diff --git a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_ethtool.c b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_ethtool.c index a365d2a9cc10..992f8e63feba 100644 --- a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_ethtool.c +++ b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_ethtool.c @@ -20,6 +20,7 @@ #include "atl_fwdnl.h" #include "atl_macsec.h" #include "atl_ptp.h" +#include "atl_fwd.h" static uint32_t atl_ethtool_get_link(struct net_device *ndev) { @@ -633,8 +634,8 @@ static const struct atl_stat_desc eth_stat_descs[] = { ATL_ETH_STAT(tx_pause, tx_pause), ATL_ETH_STAT(tx_ether_pkts, tx_ether_pkts), ATL_ETH_STAT(tx_ether_octets, tx_ether_octets), + ATL_ETH_STAT(tx_errors, tx_errors), ATL_ETH_STAT(rx_pause, rx_pause), - ATL_ETH_STAT(rx_ether_drops, rx_ether_drops), ATL_ETH_STAT(rx_ether_octets, rx_ether_octets), ATL_ETH_STAT(rx_ether_pkts, rx_ether_pkts), ATL_ETH_STAT(rx_ether_broacasts, rx_ether_broacasts), @@ -642,6 +643,13 @@ static const struct atl_stat_desc eth_stat_descs[] = { ATL_ETH_STAT(rx_ether_crc_align_errs, rx_ether_crc_align_errs), ATL_ETH_STAT(rx_filter_host, rx_filter_host), ATL_ETH_STAT(rx_filter_lost, rx_filter_lost), + ATL_ETH_STAT(rx_errors, rx_errors), + ATL_ETH_STAT(rx_drops, rx_drops), + ATL_ETH_STAT(rx_dma_packets, rx_dma_packets), + ATL_ETH_STAT(rx_dma_octets, rx_dma_octets), + ATL_ETH_STAT(rx_dma_drops, rx_dma_drops), + ATL_ETH_STAT(tx_dma_packets, tx_dma_packets), + ATL_ETH_STAT(tx_dma_octets, tx_dma_octets), }; #define ATL_PRIV_FLAG(_name, _bit) \ @@ -2711,9 +2719,7 @@ static void atl_refresh_rxf_desc(struct atl_nic *nic, atl_for_each_rxf_idx(desc, idx) desc->update_rxf(nic, idx); - atl_set_vlan_promisc(&nic->hw, (nic->ndev->flags & IFF_PROMISC) || - nic->rxf_vlan.promisc_count || - !nic->rxf_vlan.vlans_active); + atl_set_vlan_promisc(&nic->hw, atl_vlan_promisc_status(nic->ndev)); } void atl_refresh_rxfs(struct atl_nic *nic) @@ -2723,9 +2729,7 @@ void atl_refresh_rxfs(struct atl_nic *nic) atl_for_each_rxf_desc(desc) atl_refresh_rxf_desc(nic, desc); - atl_set_vlan_promisc(&nic->hw, (nic->ndev->flags & IFF_PROMISC) || - nic->rxf_vlan.promisc_count || - !nic->rxf_vlan.vlans_active); + atl_set_vlan_promisc(&nic->hw, atl_vlan_promisc_status(nic->ndev)); } static bool atl_vlan_pull_from_promisc(struct atl_nic *nic, uint32_t idx) @@ -2765,9 +2769,8 @@ static bool atl_vlan_pull_from_promisc(struct atl_nic *nic, uint32_t idx) } while (idx & ATL_VIDX_FREE); kfree(map); - atl_set_vlan_promisc(&nic->hw, (nic->ndev->flags & IFF_PROMISC) || - vlan->promisc_count || - !vlan->vlans_active); + atl_set_vlan_promisc(&nic->hw, atl_vlan_promisc_status(nic->ndev)); + return true; } @@ -2955,9 +2958,7 @@ int atl_vlan_rx_add_vid(struct net_device *ndev, __be16 proto, u16 vid) vlan->promisc_count++; if (pm_runtime_active(&nic->hw.pdev->dev)) atl_set_vlan_promisc(&nic->hw, - (ndev->flags & IFF_PROMISC) || - vlan->promisc_count || - !vlan->vlans_active); + atl_vlan_promisc_status(nic->ndev)); return 0; } @@ -2984,9 +2985,8 @@ update_vlan: atl_rxf_update_vlan(nic, idx); if (pm_runtime_active(&nic->hw.pdev->dev)) atl_set_vlan_promisc(&nic->hw, - (nic->ndev->flags & IFF_PROMISC) || - vlan->promisc_count || - !vlan->vlans_active); + atl_vlan_promisc_status(nic->ndev)); + return 0; } @@ -3027,9 +3027,9 @@ int atl_vlan_rx_kill_vid(struct net_device *ndev, __be16 proto, u16 vid) update_vlan_promisc: if (pm_runtime_active(&nic->hw.pdev->dev)) - atl_set_vlan_promisc(&nic->hw, (ndev->flags & IFF_PROMISC) || - vlan->promisc_count || - !vlan->vlans_active); + atl_set_vlan_promisc(&nic->hw, + atl_vlan_promisc_status(nic->ndev)); + return 0; } @@ -3086,6 +3086,18 @@ static void atl_ethtool_complete(struct net_device *ndev) pm_runtime_put(&nic->hw.pdev->dev); } +static int atl_ethool_get_regs_len(struct net_device *ndev) +{ + return atl_get_crash_dump(ndev, NULL); +} + +static void atl_ethool_get_regs(struct net_device *ndev, struct ethtool_regs *regs, void *buf) +{ + regs->version = 0; + memset(buf, 0, regs->len); + atl_get_crash_dump(ndev, buf); +} + const struct ethtool_ops atl_ethtool_ops = { #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0) .supported_coalesce_params = ETHTOOL_COALESCE_USECS | @@ -3128,4 +3140,6 @@ const struct ethtool_ops atl_ethtool_ops = { .set_wol = atl_set_wol, .begin = atl_ethtool_begin, .complete = atl_ethtool_complete, + .get_regs_len = atl_ethool_get_regs_len, + .get_regs = atl_ethool_get_regs, }; diff --git a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_fw.c b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_fw.c index cafd661c4dd8..7c86311a6df3 100644 --- a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_fw.c +++ b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_fw.c @@ -1172,6 +1172,39 @@ int atl_update_thermal_flag(struct atl_hw *hw, int bit, bool val) static unsigned int atl_wdog_period = 1100; module_param_named(wdog_period, atl_wdog_period, uint, 0644); +static int atl_fw_rev_check_and_warn(int fw_rev) +{ + int major = (fw_rev >> 24) & 0xFFU; + bool ret = true; + + switch (major) { + case 2: + if ((((fw_rev >> 16) & 0xFFU) < 12) && + ((fw_rev & 0xFFFFU) < 12)) + ret = false; + break; + + case 3: + if ((((fw_rev >> 16) & 0xFFU) < 1) && + ((fw_rev & 0xFFFFU) < 102)) + ret = false; + + break; + + case 4: + if ((((fw_rev >> 16) & 0xFFU) < 2) && + ((fw_rev & 0xFFFFU) < 37)) + ret = false; + + break; + + default: + ret = false; + } + + return ret; +} + int atl_fw_init(struct atl_hw *hw) { uint32_t tries, reg, major; @@ -1186,6 +1219,13 @@ int atl_fw_init(struct atl_hw *hw) atl_dev_dbg("FW startup took %d ms\n", tries); major = (reg >> 24) & 0xff; + + /* Warn if FW is lower than 2.12.12, 3.1.102 and 4.2.37 */ + if (!atl_fw_rev_check_and_warn(reg)) + atl_dev_warn("FW_version: %u.%u.%u, is not stable version", + (reg >> 24), ((reg >> 16) & 0xFFU), + (reg & 0xFFFFU)); + if (!major || major > 3) { atl_dev_err("Unsupported FW major version: %u\n", major); return -EINVAL; diff --git a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_fwd.c b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_fwd.c index 2b5e899c6bf8..d46dfa2d9463 100644 --- a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_fwd.c +++ b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_fwd.c @@ -12,6 +12,46 @@ #include #include "atl_common.h" #include "atl_desc.h" +#include "atl_fwd.h" +#include "atl_ring.h" + +static u32 atl_skip_reglist[] = { + /* PCIE */ + 0x1030, 0x1200, 0x1514, 0x1F00, 0x1F04, 0x1F20, 0x1F24, + + /* INTR Registers */ + 0x21A0, 0x21A4, 0x21A8, + + /* COM Registers */ + 0x30A0, 0x30A8, 0x3900, 0x3920, + + /* MAC PHY Registers */ + 0x4058, 0x4060, 0x4064, 0x40B0, 0x40B4, 0x40B8, 0x40BC, + 0x4120, 0x4140, 0x4144, 0x4190, 0x419C, 0x41A0, 0x41A4, + 0x41A8, 0x4270, 0x4288, 0x428C, 0x4290, 0x4294, 0x42E8, + 0x42EC, 0x434C, 0x4378, 0x4380, 0x4384, 0x4440, 0x4444, + 0x4970, 0x4B40, 0x4B44, 0x4B48, 0x4B4C, + + /* RX Registers */ + 0x5108, 0x54CC, 0x55B0, 0x55B4, 0x55C0, 0x55E0, 0x55E4, + 0x5640, 0x5718, 0x5728, 0x5738, 0x5748, 0x5758, 0x5768, + 0x5778, 0x5788, 0x5808, 0x580C, 0x5A10, 0x5B14, 0x5B34, + 0x5B54, 0x5B74, 0x5B94, 0x5BB4, 0x5BD4, 0x5BF4, 0x5C14, + 0x5C34, 0x5C54, 0x5C74, 0x5C94, 0x5CB4, 0x5CD4, 0x5CF4, + 0x5D14, 0x5D34, 0x5D54, 0x5D74, 0x5D94, 0x5DB4, 0x5DD4, + 0x5DF4, 0x5E14, 0x5E34, 0x5E54, 0x5E74, 0x5E94, 0x5EB4, + 0x5ED4, 0x5EF4, 0x6900, 0x6F00, 0x6F20, + + /* TX Registers */ + 0x7808, 0x7848, 0x784C, 0x78B0, 0x78B4, 0x7918, 0x7928, + 0x7938, 0x7948, 0x7958, 0x7968, 0x7978, 0x7988, 0x7A34, + 0x7B10, 0x7B14, 0x7B18, 0x7C14, 0x7C54, 0x7C94, 0x7CD4, + 0x7D14, 0x7D54, 0x7D94, 0x7DD4, 0x7E14, 0x7E54, 0x7E94, + 0x7ED4, 0x7F14, 0x7F54, 0x7F94, 0x7FD4, 0x8014, 0x8054, + 0x8094, 0x80D4, 0x8114, 0x8154, 0x8194, 0x81D4, 0x8214, + 0x8254, 0x8294, 0x82D4, 0x8314, 0x8354, 0x8394, 0x83D4, + 0x8900, 0x8904, 0x8F00, 0x8F20, +}; static const char *atl_fwd_dir_str(struct atl_fwd_ring *ring) { @@ -903,3 +943,178 @@ int atl_fwd_resume_rings(struct atl_nic *nic) err: return ret; } + +int atl_get_ext_stats(struct net_device *ndev, struct atl_ext_stats *stats) +{ + struct atl_nic *nic = netdev_priv(ndev); + + if (!stats) + return -EINVAL; + + atl_update_eth_stats(nic); + atl_update_global_stats(nic); + + memcpy(&stats->rx, &nic->stats.rx, sizeof(stats->rx)); + memcpy(&stats->tx, &nic->stats.tx, sizeof(stats->tx)); + memcpy(&stats->rx_fwd, &nic->stats.rx_fwd, sizeof(stats->rx_fwd)); + memcpy(&stats->eth, &nic->stats.eth, sizeof(stats->eth)); + + return 0; +} +EXPORT_SYMBOL(atl_get_ext_stats); + +static bool atl_skip_register(u32 reg) +{ + int i, count; + + count = sizeof(atl_skip_reglist) / sizeof(u32); + for (i = 0; i < count; i++) + if (atl_skip_reglist[i] == reg) + return true; + + return false; +} + +static int atl_get_crash_dump_regs(struct atl_hw *hw, struct atl_crash_dump_regs *section) +{ + int addr, index; + + section->type = atl_crash_dump_type_regs; + section->length = sizeof(struct atl_crash_dump_regs); + + /* prefill with 'skip' value */ + for (addr = 0; addr < sizeof(section->regs_data); addr++) + section->regs_data[addr] = 0xFFFFFFFF; + + for (addr = 0x1000, index = 0x1000 / 4; addr < 0x9000; addr += 4, index++) { + if (atl_skip_register(addr)) + continue; + section->regs_data[index] = atl_read(hw, addr); + } + + return section->length; +} + +static int atl_get_crash_dump_fwiface(struct atl_hw *hw, struct atl_crash_dump_fwiface *section) +{ + int i; + + section->type = atl_crash_dump_type_fwiface; + section->length = sizeof(struct atl_crash_dump_fwiface); + + for (i = 0; i < ARRAY_SIZE(section->fw_interface_in); i++) + section->fw_interface_in[i] = atl_read(hw, ATL2_MIF_SHARED_BUFFER_IN(i)); + + for (i = 0; i < ARRAY_SIZE(section->fw_interface_out); i++) + section->fw_interface_out[i] = atl_read(hw, ATL2_MIF_SHARED_BUFFER_OUT(i)); + + return section->length; +} + +static int atl_get_crash_dump_act_res(struct atl_hw *hw, struct atl_crash_dump_act_res *section) +{ + int i, idx, err; + + section->type = atl_crash_dump_type_act_res; + section->length = sizeof(struct atl_crash_dump_act_res); + + err = atl_hwsem_get(hw, ATL2_MCP_SEM_ACT_RSLVR); + if (err) { + printk("Failed to aquire act_res semaphore\n"); + goto ret; + } + + for (i = 0, idx = 0; i < ATL_ACT_RES_TABLE_SIZE / 3; i++) { + section->act_res_data[idx++] = atl_read(hw, ATL2_RPF_ACT_RSLVR_REQ_TAG(i)); + section->act_res_data[idx++] = atl_read(hw, ATL2_RPF_ACT_RSLVR_TAG_MASK(i)); + section->act_res_data[idx++] = atl_read(hw, ATL2_RPF_ACT_RSLVR_ACTN(i)); + } + + atl_hwsem_put(hw, ATL2_MCP_SEM_ACT_RSLVR); + +ret: + return section->length; +} + +static int atl_get_crash_dump_ring(struct atl_nic *nic, int idx, + struct atl_crash_dump_ring *section) +{ + int size = sizeof(struct atl_crash_dump_ring), offset; + struct atl_queue_vec *qvec = &nic->qvecs[idx]; + struct atl_hw_ring *hwring; + + if (!test_bit(ATL_ST_UP, &nic->hw.state)) { + memset(section, 0, size); + goto ret; + } + + section->type = atl_crash_dump_type_ring; + section->index = qvec->idx; + section->length = size; + section->rx_head = qvec->rx.head; + section->rx_tail = qvec->rx.tail; + section->tx_head = qvec->tx.head; + section->tx_tail = qvec->tx.tail; + hwring = &qvec->rx.hw; + section->rx_ring_size = hwring->size; + memcpy(section->ring_data, hwring->descs, hwring->size * sizeof(*hwring->descs)); + offset = hwring->size * sizeof(*hwring->descs); + hwring = &qvec->tx.hw; + section->tx_ring_size = hwring->size; + memcpy(section->ring_data + offset, hwring->descs, hwring->size * sizeof(*hwring->descs)); + +ret: + return size; +} + + +int atl_get_crash_dump(struct net_device *ndev, struct atl_crash_dump *crash_dump) +{ + struct atl_nic *nic = netdev_priv(ndev); + u32 fw_rev = nic->hw.mcp.fw_rev; + int recorded_sz = 0, i, nvecs; + u8 *section; + + if (!crash_dump) + return sizeof(struct atl_crash_dump); + + crash_dump->length = sizeof(*crash_dump); + crash_dump->sections_count = 0; + + strlcpy(crash_dump->drv_version, ATL_VERSION, sizeof(crash_dump->drv_version)); + snprintf(crash_dump->fw_version, sizeof(crash_dump->fw_version), + "%d.%d.%d", fw_rev >> 24, fw_rev >> 16 & 0xff, fw_rev & 0xffff); + + if (nic->hw.chip_id == ATL_ANTIGUA) + section = (void *)&crash_dump->antigua.regs; + else + section = (void *)&crash_dump->atlantic.regs; + + recorded_sz = atl_get_crash_dump_regs(&nic->hw, (void *)section); + crash_dump->sections_count++; + crash_dump->length += recorded_sz; + section += recorded_sz; + + if (nic->hw.chip_id == ATL_ANTIGUA) { + recorded_sz = atl_get_crash_dump_fwiface(&nic->hw, (void *)section); + crash_dump->sections_count++; + crash_dump->length += recorded_sz; + section += recorded_sz; + + recorded_sz = atl_get_crash_dump_act_res(&nic->hw, (void *)section); + crash_dump->sections_count++; + crash_dump->length += recorded_sz; + section += recorded_sz; + } + + nvecs = min_t(int, nic->nvecs, ATL_MAX_QUEUES); + for (i = 0; i < nvecs; i++) { + recorded_sz = atl_get_crash_dump_ring(nic, i, (void *)section); + crash_dump->sections_count++; + crash_dump->length += recorded_sz; + section += recorded_sz; + } + + return crash_dump->length; +} +EXPORT_SYMBOL(atl_get_crash_dump); diff --git a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_fwd.h b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_fwd.h index 57b31320be5a..61b2aca5174c 100644 --- a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_fwd.h +++ b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_fwd.h @@ -13,9 +13,10 @@ #define _ATL_FWD_H_ #include "atl_common.h" +#include "atl_dump.h" /* Each incompatible API change bumps the API version */ -#define ATL_FWD_API_VERSION 3 +#define ATL_FWD_API_VERSION 4 struct atl_fwd_event; @@ -405,4 +406,40 @@ enum atl_fwd_ring_state { ATL_FWR_ST_EVT_ENABLED = BIT(1), }; +#if IS_ENABLED(CONFIG_ATLFWD_FWD) +enum atl_fwd_notify; +void atl_fwd_release_rings(struct atl_nic *nic); +int atl_fwd_suspend_rings(struct atl_nic *nic); +int atl_fwd_resume_rings(struct atl_nic *nic); +void atl_fwd_notify(struct atl_nic *nic, enum atl_fwd_notify notif, void *data); +#else +static inline void atl_fwd_release_rings(struct atl_nic *nic) {} +static inline int atl_fwd_suspend_rings(struct atl_nic *nic) { return 0; } +static inline int atl_fwd_resume_rings(struct atl_nic *nic) { return 0; } +static inline void atl_fwd_notify(struct atl_nic *nic, + enum atl_fwd_notify notif, void *data) {} +#endif + +struct atl_ext_stats { + struct atl_rx_ring_stats rx; + struct atl_tx_ring_stats tx; + struct atl_rx_fwd_ring_stats rx_fwd; + + struct atl_ether_stats eth; +}; + +/** + * Direct statistics fetch call for the device + */ +int atl_get_ext_stats(struct net_device *ndev, struct atl_ext_stats *stats); + +/** + * Get the register and other crash related information from the device + * If @crash_dump is NULL, function will return the requested length of the buffer to + * store dump, in bytes + * if @crash_dump is not null, function will fill the buffer with crashdump + * sections filled, up to crash_dump->length + */ +int atl_get_crash_dump(struct net_device *ndev, struct atl_crash_dump *crash_dump); + #endif diff --git a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_fwdnl.c b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_fwdnl.c index b9e86c4a300d..a11c42f6eec2 100644 --- a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_fwdnl.c +++ b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_fwdnl.c @@ -21,6 +21,7 @@ #include "atl_fwdnl.h" #include "atl_common.h" +#include "atl_fwd.h" #include "atl_fwdnl_params.h" #include "atl_ring.h" #include "atl_trace.h" @@ -1742,7 +1743,9 @@ static const struct nla_policy atlfwd_nl_policy[NUM_ATL_FWD_ATTR] = { [ATL_FWD_ATTR_QUEUE_INDEX] = { .type = NLA_S32 }, }; -#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 2, 0) + +#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 2, 0) && \ + RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(8, 0) #define ATLFWD_NL_OP_POLICY(op_policy) .policy = op_policy #else #define ATLFWD_NL_OP_POLICY(op_policy) diff --git a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_fwdnl_params.c b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_fwdnl_params.c index 73b01c15e442..5da85ab5ccf3 100644 --- a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_fwdnl_params.c +++ b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_fwdnl_params.c @@ -13,6 +13,7 @@ #include #include "atl_common.h" +#include "atl_fwd.h" unsigned int atlfwd_nl_tx_clean_threshold_msec = 200; unsigned int atlfwd_nl_tx_clean_threshold_frac = 8; diff --git a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_hw.c b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_hw.c index 8f019ee9efac..e0635888b97b 100644 --- a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_hw.c +++ b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_hw.c @@ -114,6 +114,16 @@ static void atl_set_promisc(struct atl_hw *hw, bool enabled, bool allmulti) } } +int atl_vlan_promisc_status(struct net_device *ndev) +{ + struct atl_nic *nic = netdev_priv(ndev); + + return ndev->flags & IFF_PROMISC || + nic->rxf_vlan.promisc_count || + !nic->rxf_vlan.vlans_active || + !(ndev->features & NETIF_F_HW_VLAN_CTAG_FILTER); +} + void atl_set_vlan_promisc(struct atl_hw *hw, int promisc) { atl_write_bit(hw, ATL_RX_VLAN_FLT_CTRL1, 1, !!promisc); @@ -746,7 +756,7 @@ void atl_start_hw_global(struct atl_nic *nic) (tpb_size * 32 * 66 / 100) << 16 | (tpb_size * 32 * 50 / 100)); /* 4-TC | Enable TPB */ - atl_set_bits(hw, ATL_TX_PBUF_CTRL1, BIT(8) | BIT(0)); + atl_set_bits(hw, ATL_TX_PBUF_CTRL1, BIT(8) | BIT(2) | BIT(0)); /* TX Buffer clk gate off */ if (hw->chip_id == ATL_ANTIGUA) atl_clear_bits(hw, ATL_TX_PBUF_CTRL1, BIT(5)); @@ -910,9 +920,7 @@ void atl_set_rx_mode(struct net_device *ndev) /* Enable promisc VLAN mode if IFF_PROMISC explicitly * requested or too many VIDs registered */ - atl_set_vlan_promisc(hw, - ndev->flags & IFF_PROMISC || nic->rxf_vlan.promisc_count || - !nic->rxf_vlan.vlans_active); + atl_set_vlan_promisc(hw, atl_vlan_promisc_status(ndev)); atl_set_promisc(hw, promisc_needed, is_multicast_enabled && all_multi_needed); @@ -1319,6 +1327,14 @@ static int __atl_fetch_msm2_stats(struct atl_hw *hw, __READ_MSM_OR_GOTO(ret, hw, ATL_MSM2_CTR_TX_OCTETS_HI, ®2, hwsem_put); stats->tx_ether_octets = ((uint64_t)reg2 << 32) | reg; + __READ_MSM_OR_GOTO(ret, hw, ATL_MSM2_CTR_TX_FCS_ERRS_CNTR_LO, ®, hwsem_put); + __READ_MSM_OR_GOTO(ret, hw, ATL_MSM2_CTR_TX_FCS_ERRS_CNTR_HI, ®2, hwsem_put); + stats->tx_errors = ((uint64_t)reg2 << 32) | reg; + + __READ_MSM_OR_GOTO(ret, hw, ATL_MSM2_CTR_TX_FIFO_ERRS_CNTR_LO, ®, hwsem_put); + __READ_MSM_OR_GOTO(ret, hw, ATL_MSM2_CTR_TX_FIFO_ERRS_CNTR_HI, ®2, hwsem_put); + stats->tx_errors += ((uint64_t)reg2 << 32) | reg; + __READ_MSM_OR_GOTO(ret, hw, ATL_MSM2_CTR_RX_PAUSE_LO, ®, hwsem_put); __READ_MSM_OR_GOTO(ret, hw, ATL_MSM2_CTR_RX_PAUSE_HI, ®2, hwsem_put); stats->rx_pause = ((uint64_t)reg2 << 32) | reg; @@ -1346,6 +1362,13 @@ static int __atl_fetch_msm2_stats(struct atl_hw *hw, __READ_MSM_OR_GOTO(ret, hw, ATL_MSM2_CTR_RX_ALIGN_ERRS_HI, ®2, hwsem_put); stats->rx_ether_crc_align_errs += ((uint64_t)reg2 << 32) | reg; + __READ_MSM_OR_GOTO(ret, hw, ATL_MSM2_CTR_RX_ERRS_CNTR_LO, ®, hwsem_put); + __READ_MSM_OR_GOTO(ret, hw, ATL_MSM2_CTR_RX_ERRS_CNTR_HI, ®2, hwsem_put); + stats->rx_errors = ((uint64_t)reg2 << 32) | reg; + + __READ_MSM_OR_GOTO(ret, hw, ATL_MSM2_CTR_RX_DROP_CNTR_LO, ®, hwsem_put); + __READ_MSM_OR_GOTO(ret, hw, ATL_MSM2_CTR_RX_DROP_CNTR_HI, ®2, hwsem_put); + stats->rx_drops = ((uint64_t)reg2 << 32) | reg; hwsem_put: atl_hwsem_put(hw, ATL_MCP_SEM_MSM); return ret; @@ -1373,7 +1396,19 @@ int atl_update_eth_stats(struct atl_nic *nic) if (ret) goto unlock_fw; - stats.rx_ether_drops = atl_read(hw, ATL_RX_DMA_STATS_CNT7); + stats.rx_dma_drops = atl_read(hw, ATL_RX_DMA_STATS_CNT7); + + stats.rx_dma_packets = atl_read(hw, ATL_RX_DMA_STATS_CNT1); + stats.rx_dma_packets += (uint64_t)atl_read(hw, ATL_RX_DMA_STATS_CNT2) << 32; + + stats.rx_dma_octets = atl_read(hw, ATL_RX_DMA_STATS_CNT3); + stats.rx_dma_octets += (uint64_t)atl_read(hw, ATL_RX_DMA_STATS_CNT4) << 32; + + stats.tx_dma_packets = atl_read(hw, ATL_TX_DMA_STATS_CNT1); + stats.tx_dma_packets += (uint64_t)atl_read(hw, ATL_RX_DMA_STATS_CNT2) << 32; + + stats.tx_dma_octets = atl_read(hw, ATL_TX_DMA_STATS_CNT3); + stats.tx_dma_octets += (uint64_t)atl_read(hw, ATL_TX_DMA_STATS_CNT4) << 32; /* capture debug counters*/ atl_write_bit(hw, ATL_RX_RPF_DBG_CNT_CTRL, 0x1f, 1); @@ -1685,4 +1720,3 @@ static void atl2_hw_new_rx_filter_promisc(struct atl_hw *hw, bool promisc, off_action); } - diff --git a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_hw_ptp.c b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_hw_ptp.c index fd2f0bd549b7..7f43a5ba5956 100644 --- a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_hw_ptp.c +++ b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_hw_ptp.c @@ -241,6 +241,8 @@ void hw_atl_extract_hwts(struct atl_hw *hw, struct atl_rx_desc_hwts_wb *hwts_wb, sec += tmp; tmp = (u64)((hwts_wb->sec_hw >> 22) & 0x3ff) << 38; sec += tmp; + if (sec == 0xffffffffffff && hwts_wb->ns == 0xffffffff) + return; ns = sec * NSEC_PER_SEC + hwts_wb->ns; if (timestamp) *timestamp = ns + hw->ptp_clk_offset; diff --git a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_macsec.c b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_macsec.c index fea067b78f20..e9b1c4f9330e 100644 --- a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_macsec.c +++ b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_macsec.c @@ -12,6 +12,7 @@ #include "atl_macsec.h" #if IS_ENABLED(CONFIG_MACSEC) && defined(NETIF_F_HW_MACSEC) #include "atl_common.h" +#include "atl_fwd.h" #include #include "macsec/macsec_api.h" diff --git a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_main.c b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_main.c index c4a2be5768ba..b14b788bbdc0 100644 --- a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_main.c +++ b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_main.c @@ -17,6 +17,7 @@ #include #include "atl_macsec.h" #include "atl_ptp.h" +#include "atl_fwd.h" const char atl_driver_name[] = "atlantic-fwd"; @@ -384,7 +385,7 @@ int atl_do_reset(struct atl_nic *nic) hw->mcp.ops->dump_cfg(hw); - atl_stop(nic, true); + atl_stop(nic, false); atl_fwd_suspend_rings(nic); @@ -765,9 +766,7 @@ static void atl_remove(struct pci_dev *pdev) atl_ptp_unregister(nic); unregister_netdev(nic->ndev); -#if IS_ENABLED(CONFIG_ATLFWD_FWD) atl_fwd_release_rings(nic); -#endif atl_clear_datapath(nic); @@ -948,6 +947,47 @@ static int atl_pm_runtime_idle(struct device *dev) return -EBUSY; } +#if (LINUX_VERSION_CODE > KERNEL_VERSION(4, 13, 0)) +static void atl_reset_prepare(struct pci_dev *pdev) +{ + struct atl_nic *nic = pci_get_drvdata(pdev); + + pm_runtime_get_sync(&nic->hw.pdev->dev); + rtnl_lock(); + + if (netif_running(nic->ndev)) + atl_stop(nic, false); + + rtnl_unlock(); + pm_runtime_put_sync(&nic->hw.pdev->dev); +} + +static void atl_reset_done(struct pci_dev *pdev) +{ + struct atl_nic *nic = pci_get_drvdata(pdev); + + if (!nic) { + dev_err(&pdev->dev, "%s failed, device is unrecoverable\n", + __func__); + return; + } + + pm_runtime_get_sync(&nic->hw.pdev->dev); + rtnl_lock(); + + if (netif_running(nic->ndev)) + atl_start(nic); + + rtnl_unlock(); + pm_runtime_put_sync(&nic->hw.pdev->dev); +} + +static const struct pci_error_handlers atl_err_handlers = { + .reset_prepare = atl_reset_prepare, + .reset_done = atl_reset_done, +}; +#endif + const struct dev_pm_ops atl_pm_ops = { .suspend = atl_suspend_poweroff, .poweroff = atl_suspend_poweroff, @@ -968,6 +1008,11 @@ static struct pci_driver atl_pci_ops = { #ifdef CONFIG_PM .driver.pm = &atl_pm_ops, #endif + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(4, 13, 0)) + .err_handler = &atl_err_handlers, +#endif + }; struct atl_thermal atl_def_thermal; diff --git a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_ptp.c b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_ptp.c index 622ba980a20f..ee00257e66f9 100644 --- a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_ptp.c +++ b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_ptp.c @@ -893,8 +893,13 @@ void atl_ptp_tx_hwtstamp(struct atl_nic *nic, u64 timestamp) return; } - timestamp += atomic_read(&ptp->offset_egress); - atl_ptp_convert_to_hwtstamp(&hwtstamp, timestamp); + if (!timestamp) { + atl_nic_err("ptp timestamp all-F from FW\n"); + memset(&hwtstamp, 0, sizeof(hwtstamp)); + } else { + timestamp += atomic_read(&ptp->offset_egress); + atl_ptp_convert_to_hwtstamp(&hwtstamp, timestamp); + } do { skb_tstamp_tx(skb, &hwtstamp); dev_kfree_skb_any(skb); diff --git a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_regs.h b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_regs.h index cbe8fbf5e174..c3969a613256 100644 --- a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_regs.h +++ b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_regs.h @@ -176,8 +176,17 @@ enum mcp_scratchpad { #define ATL_RX_RING_BUF_SIZE(ring) ATL_RING_OFFT(ring, 0x18) #define ATL_RX_RING_THRESH(ring) ATL_RING_OFFT(ring, 0x1c) +#define ATL_RX_DMA_STATS_CNT1 0x6800 +#define ATL_RX_DMA_STATS_CNT2 0x6804 +#define ATL_RX_DMA_STATS_CNT3 0x6808 +#define ATL_RX_DMA_STATS_CNT4 0x680C #define ATL_RX_DMA_STATS_CNT7 0x6818 +#define ATL_TX_DMA_STATS_CNT1 0x8800 +#define ATL_TX_DMA_STATS_CNT2 0x8804 +#define ATL_TX_DMA_STATS_CNT3 0x8808 +#define ATL_TX_DMA_STATS_CNT4 0x880C + /* TX @ 0x7000 */ #define ATL_TX_CTRL1 0x7000 #define ATL_TX_PO_CTRL1 0x7800 @@ -224,6 +233,10 @@ enum mcp_scratchpad { #define ATL_MSM_CTR_RX_ERRS 0x120 +#define ATL_MSM2_CTR_RX_DROP_CNTR_LO 0x158 +#define ATL_MSM2_CTR_RX_DROP_CNTR_HI 0x15C +#define ATL_MSM2_CTR_RX_ERRS_CNTR_LO 0x138 +#define ATL_MSM2_CTR_RX_ERRS_CNTR_HI 0x13C #define ATL_MSM2_CTR_RX_OCTETS_LO 0x100 #define ATL_MSM2_CTR_RX_OCTETS_HI 0x104 #define ATL_MSM2_CTR_RX_ALIGN_ERRS_LO 0x110 @@ -245,5 +258,9 @@ enum mcp_scratchpad { #define ATL_MSM2_CTR_TX_PKTS_LO 0x220 #define ATL_MSM2_CTR_TX_PKTS_HI 0x224 +#define ATL_MSM2_CTR_TX_FCS_ERRS_CNTR_LO 0x228 +#define ATL_MSM2_CTR_TX_FCS_ERRS_CNTR_HI 0x22C +#define ATL_MSM2_CTR_TX_FIFO_ERRS_CNTR_LO 0x238 +#define ATL_MSM2_CTR_TX_FIFO_ERRS_CNTR_HI 0x23C #endif diff --git a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_ring.c b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_ring.c index b30a04c44ffd..31827eaa7fa5 100644 --- a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_ring.c +++ b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_ring.c @@ -244,6 +244,14 @@ static uint32_t atl_insert_context(struct atl_txbuf *txbuf, return tx_cmd; } +static bool atl_ptp_udp(struct sk_buff *skb) +{ + return (ip_hdr(skb)->version == 4) && + (ip_hdr(skb)->protocol == IPPROTO_UDP) && + ((udp_hdr(skb)->dest == htons(319)) || + (udp_hdr(skb)->dest == htons(320))); +} + netdev_tx_t atl_start_xmit(struct sk_buff *skb, struct net_device *ndev) { struct atl_nic *nic = netdev_priv(ndev); @@ -257,12 +265,9 @@ netdev_tx_t atl_start_xmit(struct sk_buff *skb, struct net_device *ndev) * and hardware PTP design of the chip. Otherwise ptp stream * will fail to sync */ - if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) || - unlikely((ip_hdr(skb)->version == 4) && - (ip_hdr(skb)->protocol == IPPROTO_UDP) && - ((udp_hdr(skb)->dest == htons(319)) || - (udp_hdr(skb)->dest == htons(320)))) || - unlikely(eth_hdr(skb)->h_proto == htons(ETH_P_1588))) + if (unlikely((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) || + atl_ptp_udp(skb) || + (eth_hdr(skb)->h_proto == htons(ETH_P_1588)))) return atl_ptp_start_xmit(nic, skb); } @@ -448,7 +453,7 @@ static bool atl_checksum_workaround(struct sk_buff *skb, if (((desc->pkt_type & atl_rx_pkt_type_vlan_msk) == atl_rx_pkt_type_vlan) && - !(desc->rx_estat & atl_rx_estat_vlan_stripped)) + !(desc->rx_estat & atl_rx_estat_vlan_stripped)) ip_header_offset += sizeof(struct vlan_hdr); if ((desc->pkt_type & atl_rx_pkt_type_vlan_msk) == @@ -773,6 +778,9 @@ static int atl_fill_hwts_rx(struct atl_desc_ring *ring, uint32_t count, bool ato count--; } + wmb(); + atl_write(ring_hw(ring), ATL_RX_RING_TAIL(ring), ring->tail); + return 0; } @@ -1208,7 +1216,7 @@ int atl_clean_hwts_rx(struct atl_desc_ring *ring, int budget) uint32_t space = ring_space(ring); struct atl_rx_desc_hwts_wb *wb; struct atl_rxbuf *rxbuf; - u64 ns; + u64 ns = 0; DECLARE_SCRATCH_DESC(scratch); if (space >= refill_batch) @@ -2104,9 +2112,15 @@ void atl_stop_rings(struct atl_nic *nic) int atl_set_features(struct net_device *ndev, netdev_features_t features) { netdev_features_t changed = ndev->features ^ features; + struct atl_nic *nic = netdev_priv(ndev); ndev->features = features; + if (changed & NETIF_F_HW_VLAN_CTAG_FILTER) { + atl_set_vlan_promisc(&nic->hw, + atl_vlan_promisc_status(ndev)); + } + if (changed & NETIF_F_LRO) atl_set_lro(netdev_priv(ndev)); diff --git a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_stats.h b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_stats.h index 070d078ed61f..5adfc9feed2b 100644 --- a/drivers/net/ethernet/aquantia/atlantic-fwd/atl_stats.h +++ b/drivers/net/ethernet/aquantia/atlantic-fwd/atl_stats.h @@ -39,7 +39,7 @@ struct atl_rx_fwd_ring_stats { struct atl_tx_ring_stats { uint64_t packets; uint64_t bytes; - uint64_t tx_busy; + uint64_t tx_busy; /* number of times ring was full and tx failed */ uint64_t tx_restart; uint64_t dma_map_failed; }; @@ -55,8 +55,8 @@ struct atl_ether_stats { uint64_t tx_pause; uint64_t tx_ether_pkts; uint64_t tx_ether_octets; + uint64_t tx_errors; /* from MSM block */ uint64_t rx_pause; - uint64_t rx_ether_drops; uint64_t rx_ether_octets; uint64_t rx_ether_pkts; uint64_t rx_ether_broacasts; @@ -64,6 +64,13 @@ struct atl_ether_stats { uint64_t rx_ether_crc_align_errs; uint64_t rx_filter_host; uint64_t rx_filter_lost; + uint64_t rx_errors; /* from MSM block */ + uint64_t rx_drops; /* from MSM block */ + uint64_t rx_dma_packets; + uint64_t rx_dma_octets; + uint64_t rx_dma_drops; /* DMA level RX drops */ + uint64_t tx_dma_packets; + uint64_t tx_dma_octets; }; struct atl_global_stats { diff --git a/drivers/net/ethernet/aquantia/atlantic-fwd/release_notes.txt b/drivers/net/ethernet/aquantia/atlantic-fwd/release_notes.txt index a15f3635f4e4..367bffeccd11 100644 --- a/drivers/net/ethernet/aquantia/atlantic-fwd/release_notes.txt +++ b/drivers/net/ethernet/aquantia/atlantic-fwd/release_notes.txt @@ -1,3 +1,38 @@ +Version 1.1.22 +Date 11/10/2021 +============== +- Fixed header file and warning complains + +Version 1.1.21 +Date 29/09/2021 +============== +- Atl-fwd: Fix name string for mac_phy stats in ethtool-dump +- Atl-fwd: Minor additions to ethtool dump implementation +- Atl-fwd: Add ethtool-dump parser +- ATLDRV-1776: Fix for link flip during IPA ring reconfig +- Atl-fwd: Update crash-dump structure to fixed size structure + +Version 1.1.20 +Date 23/08/2021 +============== +- Atl-fwd: Correct driver README file and export couple of APIs +- Atl-fwd: Populate Action resolve table and Ring data in the ethtool-dump +- ATLDRV-1766: Fix to update HWTS ring tail value to HW +- Fix error in populating the extended stats +- AQC113 register dump support +- stats+crashdump implementation draft +- Statistics and crash dump API proposal +- factor out fwd stuff to drop headers dependencies + +Version 1.1.19 +Date 12/07/2021 +============== +[ATLDRV-1744] - Add FW version check in Atl-fwd driver +- Move check for PTP UDP packets to separate function, Enable TX pad insert and Handle all FFs in ptp tx TS +[ATLDRV-1582] - Link not Up after FLR reset +[ATLDRV-1653] - Packet with vlan id 1 doesn't get received when rx vlan filter is disabled +[ATLDRV-1659] - Failed to compile with CONFIG_ATLFWD_FWD=y flag on RHEL 8.3 kernel + Version 1.1.18 Date 21/02/2021 ==============