Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1758493AbcLUJVj (ORCPT ); Wed, 21 Dec 2016 04:21:39 -0500 Received: from mail-bn3nam01on0057.outbound.protection.outlook.com ([104.47.33.57]:25990 "EHLO NAM01-BN3-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1750750AbcLUJVd (ORCPT ); Wed, 21 Dec 2016 04:21:33 -0500 Authentication-Results: spf=none (sender IP is ) smtp.mailfrom=Satha.Rao@cavium.com; From: Satha Koteswara Rao To: CC: , , , , , , , , , Subject: [RFC PATCH 4/7] HW Filter Initialization code and register access APIs Date: Wed, 21 Dec 2016 14:16:48 +0530 Message-ID: <1482310011-1862-5-git-send-email-satha.rao@caviumnetworks.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1482310011-1862-1-git-send-email-satha.rao@caviumnetworks.com> References: <1482310011-1862-1-git-send-email-satha.rao@caviumnetworks.com> MIME-Version: 1.0 Content-Type: text/plain X-Originating-IP: [111.93.218.67] X-ClientProxiedBy: MAXPR01CA0030.INDPRD01.PROD.OUTLOOK.COM (10.164.147.37) To CY4PR07MB2838.namprd07.prod.outlook.com (10.169.252.16) X-MS-Office365-Filtering-Correlation-Id: 9a24961c-cd41-4fe2-83ea-08d4297e1f1d X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:(22001);SRVR:CY4PR07MB2838; X-Microsoft-Exchange-Diagnostics: 1;CY4PR07MB2838;3:i6aRrRqsotKt5F6MyK6fTzqFXLY/Mdo00UnJHH2v6SDUl0rRpA0/RB7EjTAYle5X4ZjXpkvRPOXlpJSH75FJnayiUunemG/pg1WwP2ceI+lCijn97iWzEbe35Jkhos+V+etPBCkRgT4uDtL6xWFJQn9oZViJiBFC9KPf7rjXJS7Z9cfjMgFeRLnkpzPBJiJEOLjB+iZb9t3V+rELZzDUOYheJAHfRnAIsLb520DHZop6498rUSwN6uurj6uZggLABz78xH46c05qOyHSwDgB6Q==;25:NSzpbdDF5K3YNZ271vrV8LVleENCjPrJCnshsdK5URzVZ6vR+N7HN5eymN7jhKZoIGLxAiJIQyDB3LmjlU1r6fwxu98oyA7U5KPJrnmugF7/3MlUwfrME70FvJnoEYw3XqU4DVat80SRgZBuOiOnr57qvHxGZAJ3y7r7/N/fE2iwscHNjDBJnfLDK0SmHU2z6r/azmCbcWN1l/o2l/z5h3JfM6SUt+yfWtLtgScyKTw/fXOUm9WpkE30JPz2QzC9KGU7qklc+rip4SH+XFSU2004xS9lCGUySwO0KQSTAxeA83RYDEIjXPWs0DJksxpj+85ZANq7qIy+vDVR3Ur6xiPYEbuIxO5/OeGFg6OWHPiubZ161EIW8y2iypgjK8gbeXJGSM6wnNXeapHSsCKG7/kYB+xF+6D0TORvPrvmEtSh3EHtvdVlIla1bpUdTKnKWa+NJRn0h8Y5IOyQw2jwlg== X-Microsoft-Exchange-Diagnostics: 1;CY4PR07MB2838;31:nRHWcaOWrVpxuKttgWA4RbICsCYQukjGPirHpm7iVJh18egaLefGgnNFgfVHZg2aOY49tTMZu2xTIpyP+jHOdNf9nwf6EuDL0IHuVsPtR3/KzFG7s0nLviCIvUNaIbEje6DXiV0lJtDRQAXOxU2dcoQIYEOpIRTL3XzRtt+/VNBJBv6TzGj3GXCP2ANd4Not7G3wzBb7nDRtRoge0mUy0b4s5sEPySBzXqpldr98XVPbOTU8f+jvRS1TbA/smtE9;20:RttIY+9RUt5kqwOTon5ZcrlW6ckOWKxQytfma91xCcIzwc1Sleacl20pt9gTshBVbs3TxBBw9Y7kqS/T1emkqzWFkpUfxS228dTF7OzCnMle/P/v8YI1UumC0z+nuPgYs0oRouGNftm7Y5Zw5mZ/3usgoPfPPt6LkFd6j5/UbUFbQ+nDnhuz+ddJKNRxEatB9ENT2upuZIADMBYcgWjIEZxJ0uRpctpgeamTBK+DG6og7OU7SomqPCrXFFmCA9lMDVPRWp1eKk06iJonNY5fnaM1G+xFF9+rMhqYTvxQxkc73ECxpJfXdXul6rA06p6LSatejjpHJcROA6ivsagrHz95FISwoWwOcWh3O7Gc3y7fIr9E0N+5PYutYJVMyceFR9FHi0uyKXV+GPAlzXp4qG4uyF1v7cMTXuCQ4Lq9ed4GkoivUoLRBaaDuFi8ZdgpI6gLngQO8bBNI5ewRfEdgEbP5MJLTgIllKvK9rWzLb47AfaAg47DuI+IeaO+PVv2/N5cOYOXthklzJ54GuW5VJbSp9WgS1z9cDUUx9sgVzPtgFp2GGY6IpNhCQ+cisKQv5NV1hTomZxHbpXbHPnv/SIpvmtIoUZGnMNFKyGtzKo= X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:; X-Exchange-Antispam-Report-CFA-Test: BCL:0;PCL:0;RULEID:(6040375)(601004)(2401047)(5005006)(8121501046)(10201501046)(3002001)(6041248)(20161123562025)(20161123564025)(20161123560025)(20161123555025)(6072148);SRVR:CY4PR07MB2838;BCL:0;PCL:0;RULEID:;SRVR:CY4PR07MB2838; X-Microsoft-Exchange-Diagnostics: 1;CY4PR07MB2838;4:g5lNZFQQ2jKz6AoES07SJBBuTDYyzsLuoMirbrLR6ypf8v9Zk7LEFqXEm4t+68wDucyo+Wl2qdhxO6vUnOau+RWLc/UBQ+0hIXvChQK6xQd1YtJoN6mqboRtVWh4WFzbdftoMtKhT9OYqd50WoW8Nsh82gDQsm3hTkCpFs6eB+FIK6HiT8fo5mfvfM5cdgqjJ6KbnPAc7EJcriWqePBMbsAqI45EgEB8TP37zoui6s4zXwo+cPX648th9y4i8kMpKo7vIz1WgF6FETmixlKD+BNINZs8Db3T7Ps3wZ7bKYib9x6Z07MRRs5QDKnHeRueyFlOYYwsGQRquvTWdyCZuY2ZdXrLvtb9uxgxW8jiTlClhaf0bHsy6QqAUdPfuaCueJ9CS+CjtVGE5QLQ0b/fCN2Wz1VpZCi/mqA8s4bnrIzRy+VUMgpqfIwGI5Nv3ffeIPeU+ufd1Rn7IyoE14E3H6jUiUj9ecUCLaciLihgdaHoWqM2Q+0mcazbBISsp23LdH9VA0is7NZoBXfdKb6i+tcO8Y+U4CjIo5e1aAjIGgv9Zf9/FW5CkeoQfd+nReS7 X-Forefront-PRVS: 01630974C0 X-Forefront-Antispam-Report: SFV:NSPM;SFS:(10009020)(4630300001)(6069001)(6009001)(7916002)(39450400003)(189002)(199003)(2906002)(4326007)(101416001)(33646002)(5009440100003)(106356001)(2351001)(68736007)(105586002)(8676002)(50986999)(5003940100001)(53416004)(76506005)(76176999)(48376002)(81156014)(81166006)(42186005)(66066001)(5660300001)(92566002)(50466002)(6506006)(110136003)(7736002)(6916009)(47776003)(189998001)(36756003)(6116002)(6666003)(50226002)(3846002)(97736004)(42882006)(25786008)(2950100002)(305945005)(6512006)(69596002)(38730400001)(6486002)(4720700003)(7099028)(2004002)(217873001);DIR:OUT;SFP:1101;SCL:1;SRVR:CY4PR07MB2838;H:localhost.caveonetworks.com;FPR:;SPF:None;PTR:InfoNoRecords;MX:1;A:1;LANG:en; X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1;CY4PR07MB2838;23:qUaIUfyT1woml7FeYuOFq6fs8EOVULUF8qgK33vKh?= =?us-ascii?Q?PcsJgy+9czytl9AgkqjLWLV3T0XMkdN57bxZmE9MZd8Zm7hwHbil1prpaLeZ?= =?us-ascii?Q?/XqxpAAzz1CHtGvwwEoipGTR8+/xaMnA2TJWNClC2RbSpud3aROkUX0Uka6u?= =?us-ascii?Q?22H4UTla9xtpY671FIYD1Fq2SnTl+u+7gxu0lwBVWsGDXu1V5grE9caU4Rgb?= =?us-ascii?Q?tVCBe9L68fFqZLs+tuo1J5LSmXtD9m5tgbQHdh+0VdvMHcS23bNBwi9K7dgp?= =?us-ascii?Q?YSO8VM+kykaFUrVto/nkzWfasrBH3cpoovbxDzdEnqJZPPodVL58jqlWctHH?= =?us-ascii?Q?J4JufIMp+rNMjRJmLBmwLQleTnia85RTJQhbeS4G3TQKmaC29ADK/LUVEKtX?= =?us-ascii?Q?8dbH9mzUnegkJUpptZ71PFsqWZw39KOFlnn13Z1tPs4T6oXf+M0pPAxm/Cld?= =?us-ascii?Q?sufMPISh/GoRXjsqJyg394Lxg1Xfzg6qOIIkuaT1l2q+fJmMhyv9gUoxLnBa?= =?us-ascii?Q?Us9uIhgPBoGijC9TgwJXAcsLGCt+1gtHuiThmlhPmJECZRPLUf1tuWNxkfQQ?= =?us-ascii?Q?xfIzRKfha5AQSc3mK6YI/CIVKgYfc6zhADqv7jpD3msjJ4i3LXoWyJiwfXJa?= =?us-ascii?Q?poIhCLTHR+Gu//D7C9fofFMmqIrBwfcZENv1jUkM3r0DtCtsWWq6gqmBH9xT?= =?us-ascii?Q?cZa7FSgT4kXgWLGdtr/U8E92k2DExVrIQs8M7H7qxW6wgxd+vv+GZv4qCdgL?= =?us-ascii?Q?wzB0NyERDlyaeGteESNKaymmbW1zuakvi0lkPguuF4ZkhEUn9dWFu13Dv6Sl?= =?us-ascii?Q?C57OWQMq43Q4/cWrmND3zZbdot36FOqdi3nMBYKydKkPFiKybk1AQm317/xR?= =?us-ascii?Q?CGIy95w8qsXXO8plX8awWdf2sGOv1GnVij+WJtRmeY387VZPBEz90cGrU6aU?= =?us-ascii?Q?Y4KVklVL0w450Qjf92yrm+N8anAk/dMQOR8iRZx8/1NJXKBXRETJth2+YrcK?= =?us-ascii?Q?KGgMkluhRLAor4DMNc+Z9Xvdjp75+e8awlYD/G6GnZYPJSgLBH1OL0dKZuMe?= =?us-ascii?Q?2OZtxsdF3TdZA3eYdbZpgrjVWKcrEbwq9Lo7tpwH9M1WguOlUJxZ3NtePJ9i?= =?us-ascii?Q?Zl5KvOpA1ck7e44FWae2Es+13q20EUtM4wAgHqyntT2Wocp8GuOKUf6DXtWw?= =?us-ascii?Q?/IagOKZTBc0dSH/zIX2rsh9aL25WqPF/2tvffCORy8oxV7znPtoxe+CuXchO?= =?us-ascii?Q?l4Nj69YdjA3+DuuwKuhn0kSZBHQ+xxF/VG+gVAFGO/CyXwcY1HaCn0tO92i9?= =?us-ascii?B?QT09?= X-Microsoft-Exchange-Diagnostics: 1;CY4PR07MB2838;6:pfgznfgljV6imUQen2givmfJ2/uS62SMmN25GAv05Q5wsYBTkc0pH1Lw977KpQ8qXSzAkOMCGVxJfn50BVhx8bDkGhFB3dKixJOitdLVVkYWDxphRG9qVvEqUukiULnrW2pSt/3GAzr1cq8toNwRrSwMkYw10J0NZeI0ktw9QwVGSAEMJMSDbUj3oa/qMi4FHxMDShMrym1GHTx8aT/WF10DcDzCTfWHVd2bI0o4LXwebzzGZz3t1iBIAJaXSEjrZeylIVYlfbuSktw7jDHdhMv7mcuKROzSUo8HwxFxQir8Bm2OrtliE3gJlW+EEQPLlB7eSsXHU/x89hG0FD7m9oVqDmFT6Gd/QnZH01r+a4SxETyj9z0HOKRbrPdwuTCCof35QQ7SZaeDHmrJ2ri3JYNaXtyJPlP5KILDHxvKCEA=;5:77xRX9golZqhgbStD6mNXNGEhJMpUtvZt3S2NjhCUoEoSDPkGZkE6t3PKutkRwBUKaPcy4TfaGC6fVNX+UhYZLRVdzUV+em8wWiAHIV1l6QIQJxLWOukMzF1hi2yyCz4ikCiv84MDcLhib9zKFVLTg==;24:XSpTCVrNuQJN1jfTF2uzOrNvfUIxxFLPPKHP7JVEJ/7Prev3Yj+l0XZV1/YKfvkLHiPy+dtq50+K/GNhbDlVQWHTGdZQDPNMzW6kwbTDcEA= SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-Microsoft-Exchange-Diagnostics: 1;CY4PR07MB2838;7:9W7SnVaM6VLziqk7X07MF/hRYzDzzQfiSOdSgwYSfrIOv96DnBZtta1DiDHv8y8Az3MR+L8io4Se8NBKRl0YOcxjdBUqCfqcLZwdUxJzcgZ4diazyjlXDbxFJBVuh0badBjs/tgyQzZz7xSUFrf/EfmHthXuRf8RQyrJrCqm/LhtNEweEaZneI2EihQPn4a4DRKqOwPAYaRjCYc2xd4k8bhLBm+cyeLUCcWW/sKGoBGAJb4AMIiwaf3haQ3QbtRUtiLHs/9mcCc4kdbXrLRFMkqSWZ+6mf7Z2u6pwupABsA915LhGsE+9qXDLXkkPwEgwYFOzmOAUoV8vg89Onhd4ES1UENQw5WtnvGm4b6vc6DzNGPS3hxy7okEA8wbYj3FNz4sugki5Cp3UWENjgrHr559ldtehm9IRl8M+vH5CeRmM/zuc8j1o2DGbCvqVibuUD8YMV1i7OC623oIKf0LhA== X-OriginatorOrg: caviumnetworks.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 21 Dec 2016 08:48:19.8892 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-Transport-CrossTenantHeadersStamped: CY4PR07MB2838 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 17830 Lines: 673 --- drivers/net/ethernet/cavium/thunder/pf_reg.c | 660 +++++++++++++++++++++++++++ 1 file changed, 660 insertions(+) create mode 100644 drivers/net/ethernet/cavium/thunder/pf_reg.c diff --git a/drivers/net/ethernet/cavium/thunder/pf_reg.c b/drivers/net/ethernet/cavium/thunder/pf_reg.c new file mode 100644 index 0000000..1f95c7f --- /dev/null +++ b/drivers/net/ethernet/cavium/thunder/pf_reg.c @@ -0,0 +1,660 @@ +/* + * Copyright (C) 2015 Cavium, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License + * as published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pf_globals.h" +#include "pf_locals.h" +#include "tbl_access.h" +#include "linux/lz4.h" + +struct tns_table_s tbl_info[TNS_MAX_TABLE]; + +#define TNS_TDMA_SST_ACC_CMD_ADDR 0x0000842000000270ull + +#define BAR0_START 0x842000000000 +#define BAR0_END 0x84200000FFFF +#define BAR0_SIZE (64 * 1024) +#define BAR2_START 0x842040000000 +#define BAR2_END 0x84207FFFFFFF +#define BAR2_SIZE (1024 * 1024 * 1024) + +#define NODE1_BAR0_START 0x942000000000 +#define NODE1_BAR0_END 0x94200000FFFF +#define NODE1_BAR0_SIZE (64 * 1024) +#define NODE1_BAR2_START 0x942040000000 +#define NODE1_BAR2_END 0x94207FFFFFFF +#define NODE1_BAR2_SIZE (1024 * 1024 * 1024) +/* Allow a max of 4 chunks for the Indirect Read/Write */ +#define MAX_SIZE (64 * 4) +#define CHUNK_SIZE (64) +/* To protect register access */ +spinlock_t pf_reg_lock; + +u64 iomem0; +u64 iomem2; +u8 tns_enabled; +u64 node1_iomem0; +u64 node1_iomem2; +u8 node1_tns; +int n1_tns; + +int tns_write_register_indirect(int node_id, u64 address, u8 size, + u8 *kern_buffer) +{ + union tns_tdma_sst_acc_cmd acccmd; + union tns_tdma_sst_acc_stat_t accstat; + union tns_acc_data data; + int i, j, w = 0; + int cnt = 0; + u32 *dataw = NULL; + int temp = 0; + int k = 0; + int chunks = 0; + u64 acccmd_address; + u64 lmem2 = 0, lmem0 = 0; + + if (size == 0 || !kern_buffer) { + filter_dbg(FERR, "%s data size cannot be zero\n", __func__); + return TNS_ERROR_INVALID_ARG; + } + if (size > MAX_SIZE) { + filter_dbg(FERR, "%s Max allowed size exceeded\n", __func__); + return TNS_ERROR_DATA_TOO_LARGE; + } + if (node_id) { + lmem0 = node1_iomem0; + lmem2 = node1_iomem2; + } else { + lmem0 = iomem0; + lmem2 = iomem2; + } + + chunks = ((size + (CHUNK_SIZE - 1)) / CHUNK_SIZE); + acccmd_address = (address & 0x00000000ffffffff); + spin_lock_bh(&pf_reg_lock); + + for (k = 0; k < chunks; k++) { + /* Should never happen */ + if (size < 0) { + filter_dbg(FERR, "%s size mismatch [CHUNK %d]\n", + __func__, k); + break; + } + temp = (size > CHUNK_SIZE) ? CHUNK_SIZE : size; + dataw = (u32 *)(kern_buffer + (k * CHUNK_SIZE)); + cnt = ((temp + 3) / 4); + data.u = 0ULL; + for (j = 0, i = 0; i < cnt; i++) { + /* Odd words go in the upper 32 bits of the data + * register + */ + if (i & 1) { + data.s.upper32 = dataw[i]; + writeq_relaxed(data.u, (void *)(lmem0 + + TNS_TDMA_SST_ACC_WDATX(j))); + data.u = 0ULL; + j++; /* Advance to the next data word */ + w = 0; + } else { + /* Lower 32 bits contain words 0, 2, 4, etc. */ + data.s.lower32 = dataw[i]; + w = 1; + } + } + + /* If the last word was a partial (< 64 bits) then + * see if we need to write it. + */ + if (w) + writeq_relaxed(data.u, (void *)(lmem0 + + TNS_TDMA_SST_ACC_WDATX(j))); + + acccmd.u = 0ULL; + acccmd.s.go = 1; /* Cleared once the request is serviced */ + acccmd.s.size = cnt; + acccmd.s.addr = (acccmd_address >> 2); + writeq_relaxed(acccmd.u, (void *)(lmem0 + + TDMA_SST_ACC_CMD)); + accstat.u = 0ULL; + + while (!accstat.s.cmd_done && !accstat.s.error) + accstat.u = readq_relaxed((void *)(lmem0 + + TDMA_SST_ACC_STAT)); + + if (accstat.s.error) { + data.u = readq_relaxed((void *)(lmem2 + + TDMA_NB_INT_STAT)); + filter_dbg(FERR, "%s Reading data from ", __func__); + filter_dbg(FERR, "0x%0lx chunk %d failed 0x%0lx", + (unsigned long)address, k, + (unsigned long)data.u); + spin_unlock_bh(&pf_reg_lock); + kfree(kern_buffer); + return TNS_ERROR_INDIRECT_WRITE; + } + /* Calculate the next offset to write */ + acccmd_address = acccmd_address + CHUNK_SIZE; + size -= CHUNK_SIZE; + } + spin_unlock_bh(&pf_reg_lock); + + return 0; +} + +int tns_read_register_indirect(int node_id, u64 address, u8 size, + u8 *kern_buffer) +{ + union tns_tdma_sst_acc_cmd acccmd; + union tns_tdma_sst_acc_stat_t accstat; + union tns_acc_data data; + int i, j, dcnt; + int cnt = 0; + u32 *dataw = NULL; + int temp = 0; + int k = 0; + int chunks = 0; + u64 acccmd_address; + u64 lmem2 = 0, lmem0 = 0; + + if (size == 0 || !kern_buffer) { + filter_dbg(FERR, "%s data size cannot be zero\n", __func__); + return TNS_ERROR_INVALID_ARG; + } + if (size > MAX_SIZE) { + filter_dbg(FERR, "%s Max allowed size exceeded\n", __func__); + return TNS_ERROR_DATA_TOO_LARGE; + } + if (node_id) { + lmem0 = node1_iomem0; + lmem2 = node1_iomem2; + } else { + lmem0 = iomem0; + lmem2 = iomem2; + } + + chunks = ((size + (CHUNK_SIZE - 1)) / CHUNK_SIZE); + acccmd_address = (address & 0x00000000ffffffff); + spin_lock_bh(&pf_reg_lock); + for (k = 0; k < chunks; k++) { + /* This should never happen */ + if (size < 0) { + filter_dbg(FERR, "%s size mismatch [CHUNK:%d]\n", + __func__, k); + break; + } + temp = (size > CHUNK_SIZE) ? CHUNK_SIZE : size; + dataw = (u32 *)(kern_buffer + (k * CHUNK_SIZE)); + cnt = ((temp + 3) / 4); + acccmd.u = 0ULL; + acccmd.s.op = 1; /* Read operation */ + acccmd.s.size = cnt; + acccmd.s.addr = (acccmd_address >> 2); + acccmd.s.go = 1; /* Execute */ + writeq_relaxed(acccmd.u, (void *)(lmem0 + + TDMA_SST_ACC_CMD)); + accstat.u = 0ULL; + + while (!accstat.s.cmd_done && !accstat.s.error) + accstat.u = readq_relaxed((void *)(lmem0 + + TDMA_SST_ACC_STAT)); + + if (accstat.s.error) { + data.u = readq_relaxed((void *)(lmem2 + + TDMA_NB_INT_STAT)); + filter_dbg(FERR, "%s Reading data from", __func__); + filter_dbg(FERR, "0x%0lx chunk %d failed 0x%0lx", + (unsigned long)address, k, + (unsigned long)data.u); + spin_unlock_bh(&pf_reg_lock); + kfree(kern_buffer); + return TNS_ERROR_INDIRECT_READ; + } + + dcnt = cnt / 2; + if (cnt & 1) + dcnt++; + for (i = 0, j = 0; (j < dcnt) && (i < cnt); j++) { + data.u = readq_relaxed((void *)(lmem0 + + TNS_TDMA_SST_ACC_RDATX(j))); + dataw[i++] = data.s.lower32; + if (i < cnt) + dataw[i++] = data.s.upper32; + } + /* Calculate the next offset to read */ + acccmd_address = acccmd_address + CHUNK_SIZE; + size -= CHUNK_SIZE; + } + spin_unlock_bh(&pf_reg_lock); + return 0; +} + +u64 tns_read_register(u64 start, u64 offset) +{ + return readq_relaxed((void *)(start + offset)); +} + +void tns_write_register(u64 start, u64 offset, u64 data) +{ + writeq_relaxed(data, (void *)(start + offset)); +} + +/* Check if TNS is available. If yes return 0 else 1 */ +int is_tns_available(void) +{ + union tns_tdma_cap tdma_cap; + + tdma_cap.u = tns_read_register(iomem0, TNS_TDMA_CAP_OFFSET); + tns_enabled = tdma_cap.s.switch_capable; + /* In multi-node systems, make sure TNS should be there in both nodes */ + if (nr_node_ids > 1) { + tdma_cap.u = tns_read_register(node1_iomem0, + TNS_TDMA_CAP_OFFSET); + if (tdma_cap.s.switch_capable) + n1_tns = 1; + } + tns_enabled &= tdma_cap.s.switch_capable; + return (!tns_enabled); +} + +int bist_error_check(void) +{ + int fail = 0, i; + u64 bist_stat = 0; + + for (i = 0; i < 12; i++) { + bist_stat = tns_read_register(iomem0, (i * 16)); + if (bist_stat) { + filter_dbg(FERR, "TNS BIST%d fail 0x%llx\n", + i, bist_stat); + fail = 1; + } + if (!n1_tns) + continue; + bist_stat = tns_read_register(node1_iomem0, (i * 16)); + if (bist_stat) { + filter_dbg(FERR, "TNS(N1) BIST%d fail 0x%llx\n", + i, bist_stat); + fail = 1; + } + } + + return fail; +} + +int replay_indirect_trace(int node, u64 *buf_ptr, int idx) +{ + union _tns_sst_config cmd = (union _tns_sst_config)(buf_ptr[idx]); + int remaining = cmd.cmd.run; + u64 io_addr; + int word_cnt = cmd.cmd.word_cnt; + int size = (word_cnt + 1) / 2; + u64 stride = word_cnt; + u64 acc_cmd = cmd.copy.do_copy; + u64 lmem2 = 0, lmem0 = 0; + union tns_tdma_sst_acc_stat_t accstat; + union tns_acc_data data; + + if (node) { + lmem0 = node1_iomem0; + lmem2 = node1_iomem2; + } else { + lmem0 = iomem0; + lmem2 = iomem2; + } + + if (word_cnt == 0) { + word_cnt = 16; + stride = 16; + size = 8; + } else { + // make stride next power of 2 + if (cmd.cmd.powerof2stride) + while ((stride & (stride - 1)) != 0) + stride++; + } + stride *= 4; //convert stride from 32-bit words to bytes + + do { + int addr_p = 1; + /* extract (big endian) data from the config + * into the data array + */ + while (size > 0) { + io_addr = lmem0 + TDMA_SST_ACC_CMD + addr_p * 16; + tns_write_register(io_addr, 0, buf_ptr[idx + size]); + addr_p += 1; + size--; + } + tns_write_register((lmem0 + TDMA_SST_ACC_CMD), 0, acc_cmd); + /* TNS Block access registers indirectly, ran memory barrier + * between two writes + */ + wmb(); + /* Check for completion */ + accstat.u = 0ULL; + while (!accstat.s.cmd_done && !accstat.s.error) + accstat.u = readq_relaxed((void *)(lmem0 + + TDMA_SST_ACC_STAT)); + + /* Check for error, and report it */ + if (accstat.s.error) { + filter_dbg(FERR, "%s data from 0x%0llx failed 0x%llx\n", + __func__, acc_cmd, accstat.u); + data.u = readq_relaxed((void *)(lmem2 + + TDMA_NB_INT_STAT)); + filter_dbg(FERR, "Status 0x%llx\n", data.u); + } + /* update the address */ + acc_cmd += stride; + size = (word_cnt + 1) / 2; + usleep_range(20, 30); + } while (remaining-- > 0); + + return size; +} + +void replay_tns_node(int node, u64 *buf_ptr, int reg_cnt) +{ + int counter = 0; + u64 offset = 0; + u64 io_address; + int datapathmode = 1; + u64 lmem2 = 0, lmem0 = 0; + + if (node) { + lmem0 = node1_iomem0; + lmem2 = node1_iomem2; + } else { + lmem0 = iomem0; + lmem2 = iomem2; + } + for (counter = 0; counter < reg_cnt; counter++) { + if (buf_ptr[counter] == 0xDADADADADADADADAull) { + datapathmode = 1; + continue; + } else if (buf_ptr[counter] == 0xDEDEDEDEDEDEDEDEull) { + datapathmode = 0; + continue; + } + if (datapathmode == 1) { + if (buf_ptr[counter] >= BAR0_START && + buf_ptr[counter] <= BAR0_END) { + offset = buf_ptr[counter] - BAR0_START; + io_address = lmem0 + offset; + } else if (buf_ptr[counter] >= BAR2_START && + buf_ptr[counter] <= BAR2_END) { + offset = buf_ptr[counter] - BAR2_START; + io_address = lmem2 + offset; + } else { + filter_dbg(FERR, "%s Address 0x%llx invalid\n", + __func__, buf_ptr[counter]); + return; + } + + tns_write_register(io_address, 0, buf_ptr[counter + 1]); + /* TNS Block access registers indirectly, ran memory + * barrier between two writes + */ + wmb(); + counter += 1; + usleep_range(20, 30); + } else if (datapathmode == 0) { + int sz = replay_indirect_trace(node, buf_ptr, counter); + + counter += sz; + } + } +} + +int alloc_table_info(int i, struct table_static_s tbl_sdata[]) +{ + tbl_info[i].ddata[0].bitmap = kcalloc(BITS_TO_LONGS(tbl_sdata[i].depth), + sizeof(uintptr_t), GFP_KERNEL); + if (!tbl_info[i].ddata[0].bitmap) + return 1; + + if (!n1_tns) + return 0; + + tbl_info[i].ddata[1].bitmap = kcalloc(BITS_TO_LONGS(tbl_sdata[i].depth), + sizeof(uintptr_t), GFP_KERNEL); + if (!tbl_info[i].ddata[1].bitmap) { + kfree(tbl_info[i].ddata[0].bitmap); + return 1; + } + + return 0; +} + +void tns_replay_register_trace(const struct firmware *fw, struct device *dev) +{ + int i; + int node = 0; + u8 *buffer = NULL; + u64 *buf_ptr = NULL; + struct tns_global_st *fw_header = NULL; + struct table_static_s tbl_sdata[TNS_MAX_TABLE]; + size_t src_len; + size_t dest_len = TNS_FW_MAX_SIZE; + int rc; + u8 *fw2_buf = NULL; + unsigned char *decomp_dest = NULL; + + fw2_buf = (u8 *)fw->data; + src_len = fw->size - 8; + + decomp_dest = kcalloc((dest_len * 2), sizeof(char), GFP_KERNEL); + if (!decomp_dest) + return; + + memset(decomp_dest, 0, (dest_len * 2)); + rc = lz4_decompress_unknownoutputsize(&fw2_buf[8], src_len, decomp_dest, + &dest_len); + if (rc) { + filter_dbg(FERR, "Decompress Error %d\n", rc); + pr_info("Uncompressed destination length %ld\n", dest_len); + kfree(decomp_dest); + return; + } + fw_header = (struct tns_global_st *)decomp_dest; + buffer = (u8 *)decomp_dest; + + filter_dbg(FINFO, "TNS Firmware version: %s Loading...\n", + fw_header->version); + + memset(tbl_info, 0x0, sizeof(tbl_info)); + buf_ptr = (u64 *)(buffer + sizeof(struct tns_global_st)); + memcpy(tbl_sdata, fw_header->tbl_info, sizeof(fw_header->tbl_info)); + + for (i = 0; i < TNS_MAX_TABLE; i++) { + if (!tbl_sdata[i].valid) + continue; + memcpy(&tbl_info[i].sdata, &tbl_sdata[i], + sizeof(struct table_static_s)); + if (alloc_table_info(i, tbl_sdata)) { + kfree(decomp_dest); + return; + } + } + + for (node = 0; node < nr_node_ids; node++) + replay_tns_node(node, buf_ptr, fw_header->reg_cnt); + + kfree(decomp_dest); + release_firmware(fw); +} + +int tns_init(const struct firmware *fw, struct device *dev) +{ + int result = 0; + int i = 0; + int temp; + union tns_tdma_config tdma_config; + union tns_tdma_lmacx_config tdma_lmac_cfg; + u64 reg_init_val; + + spin_lock_init(&pf_reg_lock); + + /* use two regions insted of a single big mapping to save + * the kernel virtual space + */ + iomem0 = (u64)ioremap(BAR0_START, BAR0_SIZE); + if (iomem0 == 0ULL) { + filter_dbg(FERR, "Node0 ioremap failed for BAR0\n"); + result = -EAGAIN; + goto error; + } else { + filter_dbg(FINFO, "ioremap success for BAR0\n"); + } + + if (nr_node_ids > 1) { + node1_iomem0 = (u64)ioremap(NODE1_BAR0_START, NODE1_BAR0_SIZE); + if (node1_iomem0 == 0ULL) { + filter_dbg(FERR, "Node1 ioremap failed for BAR0\n"); + result = -EAGAIN; + goto error; + } else { + filter_dbg(FINFO, "ioremap success for BAR0\n"); + } + } + + if (is_tns_available()) { + filter_dbg(FERR, "TNS NOT AVAILABLE\n"); + goto error; + } + + if (bist_error_check()) { + filter_dbg(FERR, "BIST ERROR CHECK FAILED"); + goto error; + } + + /* NIC0-BGX0 is TNS, NIC1-BGX1 is TNS, DISABLE BACKPRESSURE */ + reg_init_val = 0ULL; + pr_info("NIC Block configured in TNS/TNS mode"); + tns_write_register(iomem0, TNS_RDMA_CONFIG_OFFSET, reg_init_val); + usleep_range(10, 20); + if (n1_tns) { + tns_write_register(node1_iomem0, TNS_RDMA_CONFIG_OFFSET, + reg_init_val); + usleep_range(10, 20); + } + + // Configure each LMAC with 512 credits in BYPASS mode + for (i = TNS_MIN_LMAC; i < (TNS_MIN_LMAC + TNS_MAX_LMAC); i++) { + tdma_lmac_cfg.u = 0ULL; + tdma_lmac_cfg.s.fifo_cdts = 0x200; + tns_write_register(iomem0, TNS_TDMA_LMACX_CONFIG_OFFSET(i), + tdma_lmac_cfg.u); + usleep_range(10, 20); + if (n1_tns) { + tns_write_register(node1_iomem0, + TNS_TDMA_LMACX_CONFIG_OFFSET(i), + tdma_lmac_cfg.u); + usleep_range(10, 20); + } + } + + //ENABLE TNS CLOCK AND CSR READS + temp = tns_read_register(iomem0, TNS_TDMA_CONFIG_OFFSET); + tdma_config.u = temp; + tdma_config.s.clk_2x_ena = 1; + tdma_config.s.clk_ena = 1; + tns_write_register(iomem0, TNS_TDMA_CONFIG_OFFSET, tdma_config.u); + if (n1_tns) + tns_write_register(node1_iomem0, TNS_TDMA_CONFIG_OFFSET, + tdma_config.u); + + temp = tns_read_register(iomem0, TNS_TDMA_CONFIG_OFFSET); + tdma_config.u = temp; + tdma_config.s.csr_access_ena = 1; + tns_write_register(iomem0, TNS_TDMA_CONFIG_OFFSET, tdma_config.u); + if (n1_tns) + tns_write_register(node1_iomem0, TNS_TDMA_CONFIG_OFFSET, + tdma_config.u); + + reg_init_val = 0ULL; + tns_write_register(iomem0, TNS_TDMA_RESET_CTL_OFFSET, reg_init_val); + if (n1_tns) + tns_write_register(node1_iomem0, TNS_TDMA_RESET_CTL_OFFSET, + reg_init_val); + + iomem2 = (u64)ioremap(BAR2_START, BAR2_SIZE); + if (iomem2 == 0ULL) { + filter_dbg(FERR, "ioremap failed for BAR2\n"); + result = -EAGAIN; + goto error; + } else { + filter_dbg(FINFO, "ioremap success for BAR2\n"); + } + + if (n1_tns) { + node1_iomem2 = (u64)ioremap(NODE1_BAR2_START, NODE1_BAR2_SIZE); + if (node1_iomem2 == 0ULL) { + filter_dbg(FERR, "Node1 ioremap failed for BAR2\n"); + result = -EAGAIN; + goto error; + } else { + filter_dbg(FINFO, "Node1 ioremap success for BAR2\n"); + } + } + msleep(1000); + //We will replay register trace to initialize TNS block + tns_replay_register_trace(fw, dev); + + return 0; +error: + if (iomem0 != 0) + iounmap((void *)iomem0); + if (iomem2 != 0) + iounmap((void *)iomem2); + + if (node1_iomem0 != 0) + iounmap((void *)node1_iomem0); + if (node1_iomem2 != 0) + iounmap((void *)node1_iomem2); + + return result; +} + +void tns_exit(void) +{ + int i; + + if (iomem0 != 0) + iounmap((void *)iomem0); + if (iomem2 != 0) + iounmap((void *)iomem2); + + if (node1_iomem0 != 0) + iounmap((void *)node1_iomem0); + if (node1_iomem2 != 0) + iounmap((void *)node1_iomem2); + + for (i = 0; i < TNS_MAX_TABLE; i++) { + if (!tbl_info[i].sdata.valid) + continue; + kfree(tbl_info[i].ddata[0].bitmap); + kfree(tbl_info[i].ddata[n1_tns].bitmap); + } +} -- 1.8.3.1