[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <1482310011-1862-7-git-send-email-satha.rao@caviumnetworks.com>
Date: Wed, 21 Dec 2016 14:16:50 +0530
From: Satha Koteswara Rao <satha.rao@...iumnetworks.com>
To: <linux-kernel@...r.kernel.org>
CC: <sgoutham@...ium.com>, <rric@...nel.org>, <davem@...emloft.net>,
<david.daney@...ium.com>, <rvatsavayi@...iumnetworks.com>,
<derek.chickles@...iumnetworks.com>,
<satha.rao@...iumnetworks.com>, <philip.romanov@...ium.com>,
<netdev@...r.kernel.org>, <linux-arm-kernel@...ts.infradead.org>
Subject: [RFC PATCH 6/7] HW Filter Table access API's
---
drivers/net/ethernet/cavium/thunder/tbl_access.c | 262 +++++++++++++++++++++++
drivers/net/ethernet/cavium/thunder/tbl_access.h | 61 ++++++
2 files changed, 323 insertions(+)
create mode 100644 drivers/net/ethernet/cavium/thunder/tbl_access.c
create mode 100644 drivers/net/ethernet/cavium/thunder/tbl_access.h
diff --git a/drivers/net/ethernet/cavium/thunder/tbl_access.c b/drivers/net/ethernet/cavium/thunder/tbl_access.c
new file mode 100644
index 0000000..6be31eb
--- /dev/null
+++ b/drivers/net/ethernet/cavium/thunder/tbl_access.c
@@ -0,0 +1,262 @@
+/*
+ * 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 <linux/uaccess.h>
+#include "pf_globals.h"
+#include "pf_locals.h"
+#include "tbl_access.h"
+
+struct tns_table_s *get_table_information(int table_id)
+{
+ int i;
+
+ for (i = 0; i < TNS_MAX_TABLE; i++) {
+ if (!tbl_info[i].sdata.valid)
+ continue;
+
+ if (tbl_info[i].sdata.tbl_id == table_id)
+ return &tbl_info[i];
+ }
+
+ return NULL;
+}
+
+int tbl_write(int node, int table_id, int tbl_index, void *key, void *mask,
+ void *data)
+{
+ int i;
+ struct tns_table_s *tbl = get_table_information(table_id);
+ int bck_cnt, data_index, data_offset;
+ u64 data_entry[4];
+
+ if (!tbl) {
+ filter_dbg(FERR, "Invalid Table ID: %d\n", table_id);
+ return TNS_ERR_INVALID_TBL_ID;
+ }
+
+ bck_cnt = tbl->sdata.data_width / tbl->sdata.data_size;
+ data_index = (tbl_index / bck_cnt);
+ data_offset = (tbl_index % bck_cnt);
+ //TCAM Table, we need to parse key & mask into single array
+ if (tbl->sdata.tbl_type == TNS_TBL_TYPE_TT) {
+ struct filter_keymask_s *tk = (struct filter_keymask_s *)key;
+ struct filter_keymask_s *tm = (struct filter_keymask_s *)mask;
+ u8 km[32];
+ u64 mod_key, mod_mask, temp_mask;
+ int index = 0, offset = 0;
+
+ memset(km, 0x0, 32);
+
+/* TCAM truth table data creation. Translation from data/mask to following
+ * truth table:
+ *
+ * Mask Data Content
+ * 0 0 X
+ * 0 1 1
+ * 1 0 0
+ * 1 1 Always Mismatch
+ *
+ */
+ mod_mask = ~tk->key_value;
+ temp_mask = tm->key_value;
+ mod_key = tk->key_value;
+ mod_key = mod_key & (~temp_mask);
+ mod_mask = mod_mask & (~temp_mask);
+
+ for (i = 0; i < 64; i++) {
+ km[index] = km[index] | (((mod_mask >> i) & 0x1) <<
+ offset);
+ km[index] = km[index] | (((mod_key >> i) & 0x1) <<
+ (offset + 1));
+ offset += 2;
+ if (offset == 8) {
+ offset = 0;
+ index += 1;
+ }
+ }
+ km[index] = 0x2;
+ if (tns_write_register_indirect(node,
+ (tbl->sdata.key_base_addr +
+ (tbl_index * 32)), 32,
+ (void *)&km[0])) {
+ filter_dbg(FERR, "key write failed node %d tbl ID %d",
+ node, table_id);
+ filter_dbg(FERR, " index %d\n", tbl_index);
+ return TNS_ERR_DRIVER_WRITE;
+ }
+ }
+
+ /* Data Writes are ReadModifyWrite */
+ if (tns_read_register_indirect(node, (tbl->sdata.data_base_addr +
+ (data_index * 32)), 32,
+ (void *)&data_entry[0])) {
+ filter_dbg(FERR, "data read failed node %d tbl ID %d idx %d\n",
+ node, table_id, tbl_index);
+ return TNS_ERR_DRIVER_READ;
+ }
+ memcpy(&data_entry[data_offset], data, tbl->sdata.data_size / 8);
+ if (tns_write_register_indirect(node, (tbl->sdata.data_base_addr +
+ (data_index * 32)), 32,
+ (void *)&data_entry[0])) {
+ filter_dbg(FERR, "data write failed node %d tbl ID %d idx %d\n",
+ node, table_id, tbl_index);
+ return TNS_ERR_DRIVER_WRITE;
+ }
+
+ return TNS_NO_ERR;
+}
+
+int tbl_read(int node, int table_id, int tbl_index, void *key, void *mask,
+ void *data)
+{
+ struct tns_table_s *tbl = get_table_information(table_id);
+ int i, bck_cnt, data_index, data_offset;
+ u64 data_entry[4];
+ u8 km[32];
+
+ if (!tbl) {
+ filter_dbg(FERR, "Invalid Table ID: %d\n", table_id);
+ return TNS_ERR_INVALID_TBL_ID;
+ }
+
+ bck_cnt = tbl->sdata.data_width / tbl->sdata.data_size;
+ data_index = (tbl_index / bck_cnt);
+ data_offset = (tbl_index % bck_cnt);
+
+ //TCAM Table, we need to parse key & mask into single array
+ if (tbl->sdata.tbl_type == TNS_TBL_TYPE_TT) {
+ memset(km, 0x0, 32);
+
+ if (tns_read_register_indirect(node, (tbl->sdata.key_base_addr +
+ (tbl_index * 32)), 32,
+ (void *)&km[0])) {
+ filter_dbg(FERR, "key read failed node %d tbl ID %d",
+ node, table_id);
+ filter_dbg(FERR, " idx %d\n", tbl_index);
+ return TNS_ERR_DRIVER_READ;
+ }
+ if (!(km[((tbl->sdata.key_size * 2) / 8)] == 0x2))
+ return TNS_ERR_MAC_FILTER_INVALID_ENTRY;
+ }
+
+ if (tns_read_register_indirect(node, (tbl->sdata.data_base_addr +
+ (data_index * 32)), 32,
+ (void *)&data_entry[0])) {
+ filter_dbg(FERR, "data read failed node %d tbl ID %d idx %d\n",
+ node, table_id, tbl_index);
+ return TNS_ERR_DRIVER_READ;
+ }
+ memcpy(data, (void *)(&data_entry[data_offset]),
+ (tbl->sdata.data_size / 8));
+
+ if (tbl->sdata.tbl_type == TNS_TBL_TYPE_TT) {
+ struct filter_keymask_s *tk = (struct filter_keymask_s *)key;
+ struct filter_keymask_s *tm = (struct filter_keymask_s *)mask;
+ u8 temp_km;
+ int index = 0, offset = 0;
+
+ tk->key_value = 0x0ull;
+ tm->key_value = 0x0ull;
+ temp_km = km[0];
+ for (i = 0; i < 64; i++) {
+ tm->key_value = tm->key_value |
+ ((temp_km & 0x1ull) << i);
+ temp_km >>= 1;
+ tk->key_value = tk->key_value |
+ ((temp_km & 0x1ull) << i);
+ temp_km >>= 1;
+ offset += 2;
+ if (offset == 8) {
+ offset = 0;
+ index += 1;
+ temp_km = km[index];
+ }
+ }
+ tm->key_value = ~tm->key_value & ~tk->key_value;
+ tk->is_valid = 1;
+ tm->is_valid = 0;
+ }
+
+ return TNS_NO_ERR;
+}
+
+int invalidate_table_entry(int node, int table_id, int tbl_idx)
+{
+ struct tns_table_s *tbl = get_table_information(table_id);
+
+ if (!tbl) {
+ filter_dbg(FERR, "Invalid Table ID: %d\n", table_id);
+ return TNS_ERR_INVALID_TBL_ID;
+ }
+
+ if (tbl->sdata.tbl_type == TNS_TBL_TYPE_TT) {
+ u8 km[32];
+
+ memset(km, 0x0, 32);
+ km[((tbl->sdata.key_size * 2) / 8)] = 0x1;
+
+ if (tns_write_register_indirect(node,
+ (tbl->sdata.key_base_addr +
+ (tbl_idx * 32)), 32,
+ (void *)&km[0])) {
+ filter_dbg(FERR, "%s failed node %d tbl ID %d idx %d\n",
+ __func__, node, table_id, tbl_idx);
+ return TNS_ERR_DRIVER_WRITE;
+ }
+ }
+
+ return TNS_NO_ERR;
+}
+
+int alloc_table_index(int node, int table_id, int *index)
+{
+ int err = 0;
+ struct tns_table_s *tbl = get_table_information(table_id);
+
+ if (!tbl) {
+ filter_dbg(FERR, "%s Invalid TableID %d\n", __func__, table_id);
+ return TNS_ERR_INVALID_TBL_ID;
+ }
+
+ if (*index == -1) {
+ *index = find_first_zero_bit(tbl->ddata[node].bitmap,
+ tbl->sdata.depth);
+
+ if (*index < 0 || *index >= tbl->sdata.depth)
+ err = -ENOSPC;
+ else
+ __set_bit(*index, tbl->ddata[node].bitmap);
+
+ return err;
+ } else if (*index < 0 || *index >= tbl->sdata.depth) {
+ filter_dbg(FERR, "%s Out of bound index %d requested[0...%d]\n",
+ __func__, *index, tbl->sdata.depth);
+ return TNS_ERR_MAC_FILTER_INVALID_ENTRY;
+ }
+ if (test_and_set_bit(*index, tbl->ddata[node].bitmap))
+ filter_dbg(FDEBUG, "%s Entry Already exists\n", __func__);
+
+ return err;
+}
+
+void free_table_index(int node, int table_id, int index)
+{
+ struct tns_table_s *tbl = get_table_information(table_id);
+
+ if (!tbl) {
+ filter_dbg(FERR, "%s Invalid TableID %d\n", __func__, table_id);
+ return;
+ }
+ if (index < 0 || index >= tbl->sdata.depth) {
+ filter_dbg(FERR, "%s Invalid Index %d Max Limit %d\n",
+ __func__, index, tbl->sdata.depth);
+ return;
+ }
+
+ __clear_bit(index, tbl->ddata[node].bitmap);
+}
diff --git a/drivers/net/ethernet/cavium/thunder/tbl_access.h b/drivers/net/ethernet/cavium/thunder/tbl_access.h
new file mode 100644
index 0000000..c098410
--- /dev/null
+++ b/drivers/net/ethernet/cavium/thunder/tbl_access.h
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+#ifndef __TBL_ACCESS_H__
+#define __TBL_ACCESS_H__
+
+#define TNS_MAX_TABLE 8
+
+enum {
+ TNS_TBL_TYPE_DT,
+ TNS_TBL_TYPE_HT,
+ TNS_TBL_TYPE_TT,
+ TNS_TBL_TYPE_MAX
+};
+
+struct table_static_s {
+ u8 tbl_type;
+ u8 tbl_id;
+ u8 valid;
+ u8 rsvd;
+ u16 key_size;
+ u16 data_size;
+ u16 data_width;
+ u16 key_width;
+ u32 depth;
+ u64 key_base_addr;
+ u64 data_base_addr;
+ u8 tbl_name[32];
+};
+
+struct table_dynamic_s {
+ unsigned long *bitmap;
+};
+
+struct tns_table_s {
+ struct table_static_s sdata;
+ struct table_dynamic_s ddata[MAX_NUMNODES];
+};
+
+enum {
+ MAC_FILTER_TABLE = 102,
+ VLAN_FILTER_TABLE = 103,
+ MAC_EVIF_TABLE = 140,
+ VLAN_EVIF_TABLE = 201,
+ PORT_CONFIG_TABLE = 202,
+ TABLE_ID_END
+};
+
+extern struct tns_table_s tbl_info[TNS_MAX_TABLE];
+
+struct filter_keymask_s {
+ u8 is_valid;
+ u64 key_value;
+};
+
+#endif /* __TBL_ACCESS_H__ */
--
1.8.3.1
Powered by blists - more mailing lists