From: Carlos Munoz <cmu...@cavium.com>

Add support for Octeon III PKI logic block for BGX Ethernet.

Signed-off-by: Carlos Munoz <cmu...@cavium.com>
Signed-off-by: Steven J. Hill <steven.h...@cavium.com>
---
 drivers/net/ethernet/cavium/octeon/octeon3-pki.c | 781 +++++++++++++++++++++++
 1 file changed, 781 insertions(+)
 create mode 100644 drivers/net/ethernet/cavium/octeon/octeon3-pki.c

diff --git a/drivers/net/ethernet/cavium/octeon/octeon3-pki.c 
b/drivers/net/ethernet/cavium/octeon/octeon3-pki.c
new file mode 100644
index 0000000..63e136b
--- /dev/null
+++ b/drivers/net/ethernet/cavium/octeon/octeon3-pki.c
@@ -0,0 +1,781 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Octeon III Packet Input Unit (PKI)
+ *
+ * Copyright (C) 2018 Cavium, Inc.
+ */
+
+#include <linux/firmware.h>
+
+#include "octeon3.h"
+
+#define PKI_CLUSTER_FIRMWARE           "cavium/pki-cluster.bin"
+#define VERSION_LEN                    8
+
+#define MAX_CLUSTERS                   4
+#define MAX_BANKS                      2
+#define MAX_BANK_ENTRIES               192
+#define PKI_NUM_QPG_ENTRY              2048
+#define PKI_NUM_STYLE                  256
+#define PKI_NUM_FINAL_STYLE            64
+#define MAX_PKNDS                      64
+
+/* Registers are accessed via xkphys */
+#define PKI_BASE                       0x1180044000000ull
+#define PKI_ADDR(node)                 (SET_XKPHYS + NODE_OFFSET(node) +      \
+                                        PKI_BASE)
+
+#define PKI_SFT_RST(n)                 (PKI_ADDR(n)                 + 0x000010)
+#define PKI_BUF_CTL(n)                 (PKI_ADDR(n)                 + 0x000100)
+#define PKI_STAT_CTL(n)                        (PKI_ADDR(n)                 + 
0x000110)
+#define PKI_ICG_CFG(n)                 (PKI_ADDR(n)                 + 0x00a000)
+
+#define CLUSTER_OFFSET(c)              ((c) << 16)
+#define CL_ADDR(n, c)                  (PKI_ADDR(n) + CLUSTER_OFFSET(c))
+#define PKI_CL_ECC_CTL(n, c)           (CL_ADDR(n, c)               + 0x00c020)
+
+#define PKI_STYLE_BUF(n, s)            (PKI_ADDR(n) + ((s) << 3)    + 0x024000)
+
+#define PKI_LTYPE_MAP(n, l)            (PKI_ADDR(n) + ((l) << 3)    + 0x005000)
+#define PKI_IMEM(n, i)                 (PKI_ADDR(n) + ((i) << 3)    + 0x100000)
+
+#define PKI_CL_PKIND_CFG(n, c, p)      (CL_ADDR(n, c) + ((p) << 8)  + 0x300040)
+#define PKI_CL_PKIND_STYLE(n, c, p)    (CL_ADDR(n, c) + ((p) << 8)  + 0x300048)
+#define PKI_CL_PKIND_SKIP(n, c, p)     (CL_ADDR(n, c) + ((p) << 8)  + 0x300050)
+#define PKI_CL_PKIND_L2_CUSTOM(n, c, p)        (CL_ADDR(n, c) + ((p) << 8)  + 
0x300058)
+#define PKI_CL_PKIND_LG_CUSTOM(n, c, p)        (CL_ADDR(n, c) + ((p) << 8)  + 
0x300060)
+
+#define STYLE_OFFSET(s)                        ((s) << 3)
+#define STYLE_ADDR(n, c, s)            (PKI_ADDR(n) + CLUSTER_OFFSET(c) +     \
+                                        STYLE_OFFSET(s))
+#define PKI_CL_STYLE_CFG(n, c, s)      (STYLE_ADDR(n, c, s)         + 0x500000)
+#define PKI_CL_STYLE_CFG2(n, c, s)     (STYLE_ADDR(n, c, s)         + 0x500800)
+#define PKI_CLX_STYLEX_ALG(n, c, s)    (STYLE_ADDR(n, c, s)         + 0x501000)
+
+#define PCAM_OFFSET(bank)              ((bank) << 12)
+#define PCAM_ENTRY_OFFSET(entry)       ((entry) << 3)
+#define PCAM_ADDR(n, c, b, e)          (PKI_ADDR(n) + CLUSTER_OFFSET(c) +     \
+                                        PCAM_OFFSET(b) + PCAM_ENTRY_OFFSET(e))
+#define PKI_CL_PCAM_TERM(n, c, b, e)   (PCAM_ADDR(n, c, b, e)       + 0x700000)
+#define PKI_CL_PCAM_MATCH(n, c, b, e)  (PCAM_ADDR(n, c, b, e)       + 0x704000)
+#define PKI_CL_PCAM_ACTION(n, c, b, e) (PCAM_ADDR(n, c, b, e)       + 0x708000)
+
+#define PKI_QPG_TBLX(n, i)             (PKI_ADDR(n) + ((i) << 3)    + 0x800000)
+#define PKI_AURAX_CFG(n, a)            (PKI_ADDR(n) + ((a) << 3)    + 0x900000)
+#define PKI_STATX_STAT0(n, p)          (PKI_ADDR(n) + ((p) << 8)    + 0xe00038)
+#define PKI_STATX_STAT1(n, p)          (PKI_ADDR(n) + ((p) << 8)    + 0xe00040)
+#define PKI_STATX_STAT3(n, p)          (PKI_ADDR(n) + ((p) << 8)    + 0xe00050)
+
+enum pcam_term {
+       NONE,
+       L2_CUSTOM = 0x2,
+       HIGIGD = 0x4,
+       HIGIG = 0x5,
+       SMACH = 0x8,
+       SMACL = 0x9,
+       DMACH = 0xa,
+       DMACL = 0xb,
+       GLORT = 0x12,
+       DSA = 0x13,
+       ETHTYPE0 = 0x18,
+       ETHTYPE1 = 0x19,
+       ETHTYPE2 = 0x1a,
+       ETHTYPE3 = 0x1b,
+       MPLS0 = 0x1e,
+       L3_SIPHH = 0x1f,
+       L3_SIPMH = 0x20,
+       L3_SIPML = 0x21,
+       L3_SIPLL = 0x22,
+       L3_FLAGS = 0x23,
+       L3_DIPHH = 0x24,
+       L3_DIPMH = 0x25,
+       L3_DIPML = 0x26,
+       L3_DIPLL = 0x27,
+       LD_VNI = 0x28,
+       IL3_FLAGS = 0x2b,
+       LF_SPI = 0x2e,
+       L4_SPORT = 0x2f,
+       L4_PORT = 0x30,
+       LG_CUSTOM = 0x39
+};
+
+enum pki_ltype {
+       LTYPE_NONE,
+       LTYPE_ENET,
+       LTYPE_VLAN,
+       LTYPE_SNAP_PAYLD = 0x05,
+       LTYPE_ARP = 0x06,
+       LTYPE_RARP = 0x07,
+       LTYPE_IP4 = 0x08,
+       LTYPE_IP4_OPT = 0x09,
+       LTYPE_IP6 = 0x0a,
+       LTYPE_IP6_OPT = 0x0b,
+       LTYPE_IPSEC_ESP = 0x0c,
+       LTYPE_IPFRAG = 0x0d,
+       LTYPE_IPCOMP = 0x0e,
+       LTYPE_TCP = 0x10,
+       LTYPE_UDP = 0x11,
+       LTYPE_SCTP = 0x12,
+       LTYPE_UDP_VXLAN = 0x13,
+       LTYPE_GRE = 0x14,
+       LTYPE_NVGRE = 0x15,
+       LTYPE_GTP = 0x16,
+       LTYPE_UDP_GENEVE = 0x17,
+       LTYPE_SW28 = 0x1c,
+       LTYPE_SW29 = 0x1d,
+       LTYPE_SW30 = 0x1e,
+       LTYPE_SW31 = 0x1f
+};
+
+enum pki_beltype {
+       BELTYPE_NONE,
+       BELTYPE_MISC,
+       BELTYPE_IP4,
+       BELTYPE_IP6,
+       BELTYPE_TCP,
+       BELTYPE_UDP,
+       BELTYPE_SCTP,
+       BELTYPE_SNAP
+};
+
+struct ltype_beltype {
+       enum pki_ltype ltype;
+       enum pki_beltype beltype;
+};
+
+/* struct pcam_term_info - Describes a term to configure in the PCAM.
+ * @term: Identifies the term to configure.
+ * @term_mask: Specifies don't cares in the term.
+ * @style: Style to compare.
+ * @style_mask: Specifies don't cares in the style.
+ * @data: Data to compare.
+ * @data_mask: Specifies don't cares in the data.
+ */
+struct pcam_term_info {
+       u8 term;
+       u8 term_mask;
+       u8 style;
+       u8 style_mask;
+       u32 data;
+       u32 data_mask;
+};
+
+/* struct fw_hdr - Describes the firmware.
+ * @version: Firmware version.
+ * @size: Size of the data in bytes.
+ * @data: Actual firmware data.
+ */
+struct fw_hdr {
+       char version[VERSION_LEN];
+       u64 size;
+       u64 data[];
+};
+
+static struct ltype_beltype dflt_ltype_config[] = {
+       { LTYPE_NONE, BELTYPE_NONE },
+       { LTYPE_ENET, BELTYPE_MISC },
+       { LTYPE_VLAN, BELTYPE_MISC },
+       { LTYPE_SNAP_PAYLD, BELTYPE_MISC },
+       { LTYPE_ARP, BELTYPE_MISC },
+       { LTYPE_RARP, BELTYPE_MISC },
+       { LTYPE_IP4, BELTYPE_IP4 },
+       { LTYPE_IP4_OPT, BELTYPE_IP4 },
+       { LTYPE_IP6, BELTYPE_IP6 },
+       { LTYPE_IP6_OPT, BELTYPE_IP6 },
+       { LTYPE_IPSEC_ESP, BELTYPE_MISC },
+       { LTYPE_IPFRAG, BELTYPE_MISC },
+       { LTYPE_IPCOMP, BELTYPE_MISC },
+       { LTYPE_TCP, BELTYPE_TCP },
+       { LTYPE_UDP, BELTYPE_UDP },
+       { LTYPE_SCTP, BELTYPE_SCTP },
+       { LTYPE_UDP_VXLAN, BELTYPE_UDP },
+       { LTYPE_GRE, BELTYPE_MISC },
+       { LTYPE_NVGRE, BELTYPE_MISC },
+       { LTYPE_GTP, BELTYPE_MISC },
+       { LTYPE_UDP_GENEVE, BELTYPE_UDP },
+       { LTYPE_SW28, BELTYPE_MISC },
+       { LTYPE_SW29, BELTYPE_MISC },
+       { LTYPE_SW30, BELTYPE_MISC },
+       { LTYPE_SW31, BELTYPE_MISC }
+};
+
+static int get_num_clusters(void)
+{
+       if (OCTEON_IS_MODEL(OCTEON_CN73XX) || OCTEON_IS_MODEL(OCTEON_CNF75XX))
+               return 2;
+       return 4;
+}
+
+static int octeon3_pki_pcam_alloc_entry(int node, int entry, int bank)
+{
+       struct global_resource_tag tag;
+       int i, rc, num_clusters;
+       char buf[16];
+
+       /* Allocate a PCAM entry for cluster0. */
+       strncpy((char *)&tag.lo, "cvm_pcam", 8);
+       snprintf(buf, 16, "_%d%d%d....", node, 0, bank);
+       memcpy(&tag.hi, buf, 8);
+
+       res_mgr_create_resource(tag, MAX_BANK_ENTRIES);
+       rc = res_mgr_alloc(tag, entry, false);
+       if (rc < 0)
+               return rc;
+
+       entry = rc;
+
+       /* Allocate entries for all clusters. */
+       num_clusters = get_num_clusters();
+       for (i = 1; i < num_clusters; i++) {
+               strncpy((char *)&tag.lo, "cvm_pcam", 8);
+               snprintf(buf, 16, "_%d%d%d....", node, i, bank);
+               memcpy(&tag.hi, buf, 8);
+
+               res_mgr_create_resource(tag, MAX_BANK_ENTRIES);
+               rc = res_mgr_alloc(tag, entry, false);
+               if (rc < 0) {
+                       int     j;
+
+                       pr_err("%s: Failed to allocate PCAM entry\n", __FILE__);
+                       /* Undo whatever we've did */
+                       for (j = 0; i < i; j++) {
+                               strncpy((char *)&tag.lo, "cvm_pcam", 8);
+                               snprintf(buf, 16, "_%d%d%d....", node, j, bank);
+                               memcpy(&tag.hi, buf, 8);
+                               res_mgr_free(tag, entry);
+                       }
+
+                       return -1;
+               }
+       }
+
+       return entry;
+}
+
+static int octeon3_pki_pcam_write_entry(int node,
+                                       struct pcam_term_info *term_info)
+{
+       int bank, entry, i, num_clusters;
+       u64 action, match, term;
+
+       /* Bit 0 of the PCAM term determines the bank to use. */
+       bank = term_info->term & 1;
+
+       /* Allocate a PCAM entry. */
+       entry = octeon3_pki_pcam_alloc_entry(node, -1, bank);
+       if (entry < 0)
+               return entry;
+
+       term = 1ull << 63;
+       term |= (u64)(term_info->term & term_info->term_mask) << 40;
+       term |= (~term_info->term & term_info->term_mask) << 8;
+       term |= (u64)(term_info->style & term_info->style_mask) << 32;
+       term |= ~term_info->style & term_info->style_mask;
+
+       match = (u64)(term_info->data & term_info->data_mask) << 32;
+       match |= ~term_info->data & term_info->data_mask;
+
+       action = 0;
+       if (term_info->term >= ETHTYPE0 && term_info->term <= ETHTYPE3) {
+               action |= 2 << 8;
+               action |= 4;
+       }
+
+       /* Must write the term to all clusters. */
+       num_clusters = get_num_clusters();
+       for (i = 0; i < num_clusters; i++) {
+               oct_csr_write(0, PKI_CL_PCAM_TERM(node, i, bank, entry));
+               oct_csr_write(match, PKI_CL_PCAM_MATCH(node, i, bank, entry));
+               oct_csr_write(action, PKI_CL_PCAM_ACTION(node, i, bank, entry));
+               oct_csr_write(term, PKI_CL_PCAM_TERM(node, i, bank, entry));
+       }
+
+       return 0;
+}
+
+static int octeon3_pki_alloc_qpg_entry(int node)
+{
+       struct global_resource_tag tag;
+       char buf[16];
+       int entry;
+
+       /* Allocate a Qpg entry. */
+       strncpy((char *)&tag.lo, "cvm_qpge", 8);
+       snprintf(buf, 16, "t_%d.....", node);
+       memcpy(&tag.hi, buf, 8);
+
+       res_mgr_create_resource(tag, PKI_NUM_QPG_ENTRY);
+       entry = res_mgr_alloc(tag, -1, false);
+       if (entry < 0)
+               pr_err("%s: Failed to allocate qpg entry", __FILE__);
+
+       return entry;
+}
+
+static int octeon3_pki_alloc_style(int node)
+{
+       struct global_resource_tag tag;
+       char buf[16];
+       int entry;
+
+       /* Allocate a style entry. */
+       strncpy((char *)&tag.lo, "cvm_styl", 8);
+       snprintf(buf, 16, "e_%d.....", node);
+       memcpy(&tag.hi, buf, 8);
+
+       res_mgr_create_resource(tag, PKI_NUM_STYLE);
+       entry = res_mgr_alloc(tag, -1, false);
+       if (entry < 0)
+               pr_err("%s: Failed to allocate style", __FILE__);
+
+       return entry;
+}
+
+int octeon3_pki_set_ptp_skip(int node, int pknd, int skip)
+{
+       int i, num_clusters;
+       u64 data;
+
+       num_clusters = get_num_clusters();
+       for (i = 0; i < num_clusters; i++) {
+               data = oct_csr_read(PKI_CL_PKIND_SKIP(node, i, pknd));
+               data &= ~(GENMASK_ULL(15, 8) | GENMASK_ULL(7, 0));
+               data |= (skip << 8) | skip;
+               oct_csr_write(data, PKI_CL_PKIND_SKIP(node, i, pknd));
+
+               data = oct_csr_read(PKI_CL_PKIND_L2_CUSTOM(node, i, pknd));
+               data &= ~GENMASK_ULL(7, 0);
+               data |= skip;
+               oct_csr_write(data, PKI_CL_PKIND_L2_CUSTOM(node, i, pknd));
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(octeon3_pki_set_ptp_skip);
+
+/* octeon3_pki_get_stats - Get the statistics for a given pknd (port).
+ * @node: Node to get statistics for.
+ * @pknd: Pknd to get statistis for.
+ * @packets: Updated with the number of packets received.
+ * @octets: Updated with the number of octets received.
+ * @dropped: Updated with the number of dropped packets.
+ *
+ * Returns 0 if successful.
+ * Returns <0 for error codes.
+ */
+int octeon3_pki_get_stats(int node, int pknd, u64 *packets, u64 *octets,
+                         u64 *dropped)
+{
+       /* PKI-20775, must read until not all ones. */
+       do {
+               *packets = oct_csr_read(PKI_STATX_STAT0(node, pknd));
+       } while (*packets == 0xffffffffffffffffull);
+
+       do {
+               *octets = oct_csr_read(PKI_STATX_STAT1(node, pknd));
+       } while (*octets == 0xffffffffffffffffull);
+
+       do {
+               *dropped = oct_csr_read(PKI_STATX_STAT3(node, pknd));
+       } while (*dropped == 0xffffffffffffffffull);
+
+       return 0;
+}
+EXPORT_SYMBOL(octeon3_pki_get_stats);
+
+/* octeon3_pki_port_init - Initialize a port.
+ * @node: Node port is using.
+ * @aura: Aura to use for packet buffers.
+ * @grp: SSO group packets will be queued up for.
+ * @skip: Extra bytes to skip before packet data.
+ * @mb_size: Size of packet buffers.
+ * @pknd: Port kind assigned to the port.
+ * @num_rx_cxt: Number of SSO groups used by the port.
+ *
+ * Returns 0 if successful.
+ * Returns <0 for error codes.
+ */
+int octeon3_pki_port_init(int node, int aura, int grp, int skip, int mb_size,
+                         int pknd, int num_rx_cxt)
+{
+       int num_clusters, qpg_entry, style;
+       u64 data, i;
+
+       /* Allocate and configure a Qpg table entry for the port's group. */
+       i = 0;
+       while ((num_rx_cxt & (1 << i)) == 0)
+               i++;
+       qpg_entry = octeon3_pki_alloc_qpg_entry(node);
+       data = oct_csr_read(PKI_QPG_TBLX(node, qpg_entry));
+       data &= ~(GENMASK_ULL(59, 48) | GENMASK_ULL(47, 45) |
+                 GENMASK_ULL(41, 32) | GENMASK_ULL(31, 29) |
+                 GENMASK_ULL(25, 16) | GENMASK_ULL(9, 0));
+       data |= i << 45;
+       data |= ((u64)((node << 8) | grp) << 32);
+       data |= i << 29;
+       data |= (((node << 8) | grp) << 16);
+       data |= aura;
+       oct_csr_write(data, PKI_QPG_TBLX(node, qpg_entry));
+
+       /* Allocate a style for the port */
+       style = octeon3_pki_alloc_style(node);
+
+       /* Map the Qpg table entry to the style. */
+       num_clusters = get_num_clusters();
+       for (i = 0; i < num_clusters; i++) {
+               data = BIT(29) | BIT(22) | qpg_entry;
+               oct_csr_write(data, PKI_CL_STYLE_CFG(node, i, style));
+
+               /* Specify the tag generation rules and checksum to use. */
+               oct_csr_write(0xfff49f, PKI_CL_STYLE_CFG2(node, i, style));
+
+               data = BIT(31);
+               oct_csr_write(data, PKI_CLX_STYLEX_ALG(node, i, style));
+       }
+
+       /* Set the style's buffer size and skips:
+        *      Every buffer has 128 bytes reserved for Linux.
+        *      The first buffer must also skip the WQE (40 bytes).
+        *      SRIO also requires skipping its header (skip).
+        */
+       data = 1ull << 28;
+       data |= ((128 + 40 + skip) / 8) << 22;
+       data |= (128 / 8) << 16;
+       data |= (mb_size & ~0xf) / 8;
+       oct_csr_write(data, PKI_STYLE_BUF(node, style));
+
+       /* Assign the initial style to the port via the pknd. */
+       for (i = 0; i < num_clusters; i++) {
+               data = oct_csr_read(PKI_CL_PKIND_STYLE(node, i, pknd));
+               data &= ~GENMASK_ULL(7, 0);
+               data |= style;
+               oct_csr_write(data, PKI_CL_PKIND_STYLE(node, i, pknd));
+       }
+
+       /* Enable red. */
+       data = BIT(18);
+       oct_csr_write(data, PKI_AURAX_CFG(node, aura));
+
+       /* Clear statistic counters. */
+       oct_csr_write(0, PKI_STATX_STAT0(node, pknd));
+       oct_csr_write(0, PKI_STATX_STAT1(node, pknd));
+       oct_csr_write(0, PKI_STATX_STAT3(node, pknd));
+
+       return 0;
+}
+EXPORT_SYMBOL(octeon3_pki_port_init);
+
+/* octeon3_pki_port_shutdown - Release all the resources used by a port.
+ * @node: Node the port is on.
+ * @pknd: Pknd assigned to the port.
+ *
+ * Returns 0 if successful.
+ * Returns <0 for error codes.
+ */
+int octeon3_pki_port_shutdown(int node, int pknd)
+{
+       /* Nothing at the moment. */
+       return 0;
+}
+EXPORT_SYMBOL(octeon3_pki_port_shutdown);
+
+/* octeon3_pki_cluster_init - Loads cluster firmware into the PKI clusters.
+ * @node: Node to configure.
+ * @pdev: Device requesting the firmware.
+ *
+ * Returns 0 if successful.
+ * Returns <0 for error codes.
+ */
+int octeon3_pki_cluster_init(int node, struct platform_device *pdev)
+{
+       const struct firmware *pki_fw;
+       const struct fw_hdr *hdr;
+       const u64 *data;
+       int i, rc;
+
+       rc = request_firmware(&pki_fw, PKI_CLUSTER_FIRMWARE, &pdev->dev);
+       if (rc) {
+               dev_err(&pdev->dev, "%s: Failed to load %s error=%d\n",
+                       __FILE__, PKI_CLUSTER_FIRMWARE, rc);
+               return rc;
+       }
+
+       /* Verify the firmware is valid. */
+       hdr = (const struct fw_hdr *)pki_fw->data;
+       if ((pki_fw->size - sizeof(const struct fw_hdr) != hdr->size) ||
+           hdr->size % 8) {
+               dev_err(&pdev->dev, "%s: Corrupted PKI firmware\n", __FILE__);
+               goto err;
+       }
+
+       dev_info(&pdev->dev, "%s: Loading PKI firmware %s\n", __FILE__,
+                hdr->version);
+       data = hdr->data;
+       for (i = 0; i < hdr->size / 8; i++) {
+               oct_csr_write(cpu_to_be64(*data), PKI_IMEM(node, i));
+               data++;
+       }
+err:
+       release_firmware(pki_fw);
+
+       return 0;
+}
+EXPORT_SYMBOL(octeon3_pki_cluster_init);
+
+/* octeon3_pki_vlan_init - Configure PCAM to recognize the VLAN ethtypes.
+ * @node: Node to configure.
+ *
+ * Returns 0 if successful.
+ * Returns <0 for error codes.
+ */
+int octeon3_pki_vlan_init(int node)
+{
+       int i, rc;
+       u64 data;
+
+       /* PKI-20858 */
+       if (OCTEON_IS_MODEL(OCTEON_CN78XX_PASS1_X)) {
+               for (i = 0; i < 4; i++) {
+                       data = oct_csr_read(PKI_CL_ECC_CTL(node, i));
+                       data &= ~BIT(63);
+                       data |= BIT(4) | BIT(3);
+                       oct_csr_write(data, PKI_CL_ECC_CTL(node, i));
+               }
+       }
+
+       /* Configure the pcam ethtype0 and ethtype1 terms */
+       for (i = ETHTYPE0; i <= ETHTYPE1; i++) {
+               struct pcam_term_info   term_info;
+
+               /* Term for 0x8100 ethtype */
+               term_info.term = i;
+               term_info.term_mask = 0xfd;
+               term_info.style = 0;
+               term_info.style_mask = 0;
+               term_info.data = 0x81000000;
+               term_info.data_mask = 0xffff0000;
+               rc = octeon3_pki_pcam_write_entry(node, &term_info);
+               if (rc)
+                       return rc;
+
+               /* Term for 0x88a8 ethtype */
+               term_info.data = 0x88a80000;
+               rc = octeon3_pki_pcam_write_entry(node, &term_info);
+               if (rc)
+                       return rc;
+
+               /* Term for 0x9200 ethtype */
+               term_info.data = 0x92000000;
+               rc = octeon3_pki_pcam_write_entry(node, &term_info);
+               if (rc)
+                       return rc;
+
+               /* Term for 0x9100 ethtype */
+               term_info.data = 0x91000000;
+               rc = octeon3_pki_pcam_write_entry(node, &term_info);
+               if (rc)
+                       return rc;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(octeon3_pki_vlan_init);
+
+/* octeon3_pki_ltype_init - Configures the PKI layer types.
+ * @node: Node to configure.
+ *
+ * Returns 0 if successful.
+ * Returns <0 for error codes.
+ */
+int octeon3_pki_ltype_init(int node)
+{
+       enum pki_ltype ltype;
+       u64 data;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(dflt_ltype_config); i++) {
+               ltype = dflt_ltype_config[i].ltype;
+               data = oct_csr_read(PKI_LTYPE_MAP(node, ltype));
+               data &= ~GENMASK_ULL(2, 0);
+               data |= dflt_ltype_config[i].beltype;
+               oct_csr_write(data, PKI_LTYPE_MAP(node, ltype));
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(octeon3_pki_ltype_init);
+
+int octeon3_pki_srio_init(int node, int pknd)
+{
+       int i, num_clusters, style;
+       u64 data;
+
+       num_clusters = get_num_clusters();
+       for (i = 0; i < num_clusters; i++) {
+               data = oct_csr_read(PKI_CL_PKIND_STYLE(node, i, pknd));
+               style = data & GENMASK_ULL(7, 0);
+               data &= ~GENMASK_ULL(14, 8);
+               oct_csr_write(data, PKI_CL_PKIND_STYLE(node, i, pknd));
+
+               /* Disable packet length errors and FCS. */
+               data = oct_csr_read(PKI_CL_STYLE_CFG(node, i, style));
+               data &= ~(BIT(29) | BIT(26) | BIT(25) | BIT(23) | BIT(22));
+               oct_csr_write(data, PKI_CL_STYLE_CFG(node, i, style));
+
+               /* Packets have no FCS. */
+               data = oct_csr_read(PKI_CL_PKIND_CFG(node, i, pknd));
+               data &= ~BIT(7);
+               oct_csr_write(data, PKI_CL_PKIND_CFG(node, i, pknd));
+
+               /* Skip the SRIO header and the INST_HDR_S data. */
+               data = oct_csr_read(PKI_CL_PKIND_SKIP(node, i, pknd));
+               data &= ~(GENMASK_ULL(15, 8) | GENMASK_ULL(7, 0));
+               data |= (16 << 8) | 16;
+               oct_csr_write(data, PKI_CL_PKIND_SKIP(node, i, pknd));
+
+               /* Exclude port number from Qpg. */
+               data = oct_csr_read(PKI_CLX_STYLEX_ALG(node, i, style));
+               data &= ~GENMASK_ULL(20, 17);
+               oct_csr_write(data, PKI_CLX_STYLEX_ALG(node, i, style));
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(octeon3_pki_srio_init);
+
+int octeon3_pki_enable(int node)
+{
+       int timeout;
+       u64 data;
+
+       /* Enable backpressure. */
+       data = oct_csr_read(PKI_BUF_CTL(node));
+       data |= BIT(2);
+       oct_csr_write(data, PKI_BUF_CTL(node));
+
+       /* Enable cluster parsing. */
+       data = oct_csr_read(PKI_ICG_CFG(node));
+       data |= BIT(24);
+       oct_csr_write(data, PKI_ICG_CFG(node));
+
+       /* Wait until the PKI is out of reset. */
+       timeout = 10000;
+       do {
+               data = oct_csr_read(PKI_SFT_RST(node));
+               if (!(data & BIT(63)))
+                       break;
+               timeout--;
+               udelay(1);
+       } while (timeout);
+       if (!timeout) {
+               pr_err("%s: timeout waiting for reset\n", __FILE__);
+               return -1;
+       }
+
+       /* Enable the PKI. */
+       data = oct_csr_read(PKI_BUF_CTL(node));
+       data |= BIT(0);
+       oct_csr_write(data, PKI_BUF_CTL(node));
+
+       /* Statistics are kept per pknd. */
+       oct_csr_write(0, PKI_STAT_CTL(node));
+
+       return 0;
+}
+EXPORT_SYMBOL(octeon3_pki_enable);
+
+void octeon3_pki_shutdown(int node)
+{
+       struct global_resource_tag tag;
+       int i, j, k, timeout;
+       char buf[16];
+       u64 data;
+
+       /* Disable the PKI. */
+       data = oct_csr_read(PKI_BUF_CTL(node));
+       if (data & BIT(0)) {
+               data &= ~BIT(0);
+               oct_csr_write(data, PKI_BUF_CTL(node));
+
+               /* Wait until the PKI has finished processing packets. */
+               timeout = 10000;
+               do {
+                       data = oct_csr_read(PKI_SFT_RST(node));
+                       if (data & BIT(32))
+                               break;
+                       timeout--;
+                       udelay(1);
+               } while (timeout);
+               if (!timeout)
+                       pr_warn("%s: disable timeout\n", __FILE__);
+       }
+
+       /* Give all prefetched buffers back to the FPA. */
+       data = oct_csr_read(PKI_BUF_CTL(node));
+       data |= BIT(5) | BIT(9);
+       oct_csr_write(data, PKI_BUF_CTL(node));
+
+       /* Dummy read to get the register write to take effect. */
+       data = oct_csr_read(PKI_BUF_CTL(node));
+
+       /* Now we can reset the PKI. */
+       data = oct_csr_read(PKI_SFT_RST(node));
+       data |= BIT(0);
+       oct_csr_write(data, PKI_SFT_RST(node));
+       timeout = 10000;
+       do {
+               data = oct_csr_read(PKI_SFT_RST(node));
+               if ((data & BIT(63)) == 0)
+                       break;
+               timeout--;
+               udelay(1);
+       } while (timeout);
+       if (!timeout)
+               pr_warn("%s: reset timeout\n", __FILE__);
+
+       /* Free all the allocated resources. */
+       for (i = 0; i < PKI_NUM_STYLE; i++) {
+               strncpy((char *)&tag.lo, "cvm_styl", 8);
+               snprintf(buf, 16, "e_%d.....", node);
+               memcpy(&tag.hi, buf, 8);
+               res_mgr_free(tag, i);
+       }
+       for (i = 0; i < PKI_NUM_QPG_ENTRY; i++) {
+               strncpy((char *)&tag.lo, "cvm_qpge", 8);
+               snprintf(buf, 16, "t_%d.....", node);
+               memcpy(&tag.hi, buf, 8);
+               res_mgr_free(tag, i);
+       }
+       for (i = 0; i < get_num_clusters(); i++) {
+               for (j = 0; j < MAX_BANKS; j++) {
+                       strncpy((char *)&tag.lo, "cvm_pcam", 8);
+                       snprintf(buf, 16, "_%d%d%d....", node, i, j);
+                       memcpy(&tag.hi, buf, 8);
+                       for (k = 0; k < MAX_BANK_ENTRIES; k++)
+                               res_mgr_free(tag, k);
+               }
+       }
+
+       /* Restore the registers back to their reset state. */
+       for (i = 0; i < get_num_clusters(); i++) {
+               for (j = 0; j < MAX_PKNDS; j++) {
+                       oct_csr_write(0, PKI_CL_PKIND_CFG(node, i, j));
+                       oct_csr_write(0, PKI_CL_PKIND_STYLE(node, i, j));
+                       oct_csr_write(0, PKI_CL_PKIND_SKIP(node, i, j));
+                       oct_csr_write(0, PKI_CL_PKIND_L2_CUSTOM(node, i, j));
+                       oct_csr_write(0, PKI_CL_PKIND_LG_CUSTOM(node, i, j));
+               }
+               for (j = 0; j < PKI_NUM_FINAL_STYLE; j++) {
+                       oct_csr_write(0, PKI_CL_STYLE_CFG(node, i, j));
+                       oct_csr_write(0, PKI_CL_STYLE_CFG2(node, i, j));
+                       oct_csr_write(0, PKI_CLX_STYLEX_ALG(node, i, j));
+               }
+       }
+       for (i = 0; i < PKI_NUM_FINAL_STYLE; i++)
+               oct_csr_write((0x5 << 22) | 0x20, PKI_STYLE_BUF(node, i));
+}
+EXPORT_SYMBOL(octeon3_pki_shutdown);
+
+MODULE_LICENSE("GPL");
+MODULE_FIRMWARE(PKI_CLUSTER_FIRMWARE);
+MODULE_AUTHOR("Carlos Munoz <cmu...@cavium.com>");
+MODULE_DESCRIPTION("Octeon III PKI management.");
-- 
2.1.4

Reply via email to