Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3035689d authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "atlantic forwarding driver v1.1.22"

parents 9172e2d4 1298adeb
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -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);

+2 −15
Original line number Diff line number Diff line
@@ -20,7 +20,7 @@
#include <linux/netdevice.h>
#include <linux/moduleparam.h>

#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);
+123 −0
Original line number Diff line number Diff line
/* 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
+21 −0
Original line number Diff line number Diff line
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 <device> 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 <input_file>_parsed folder.
+296 −0
Original line number Diff line number Diff line
#include <stdio.h>
#include <stddef.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
#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;
}
Loading