| // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0-or-later |
| /* |
| * Copyright 2017 NXP |
| */ |
| |
| #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
| |
| #include <linux/slab.h> |
| |
| #include "fman_keygen.h" |
| |
| /* Maximum number of HW Ports */ |
| #define FMAN_MAX_NUM_OF_HW_PORTS 64 |
| |
| /* Maximum number of KeyGen Schemes */ |
| #define FM_KG_MAX_NUM_OF_SCHEMES 32 |
| |
| /* Number of generic KeyGen Generic Extract Command Registers */ |
| #define FM_KG_NUM_OF_GENERIC_REGS 8 |
| |
| /* Dummy port ID */ |
| #define DUMMY_PORT_ID 0 |
| |
| /* Select Scheme Value Register */ |
| #define KG_SCH_DEF_USE_KGSE_DV_0 2 |
| #define KG_SCH_DEF_USE_KGSE_DV_1 3 |
| |
| /* Registers Shifting values */ |
| #define FM_KG_KGAR_NUM_SHIFT 16 |
| #define KG_SCH_DEF_L4_PORT_SHIFT 8 |
| #define KG_SCH_DEF_IP_ADDR_SHIFT 18 |
| #define KG_SCH_HASH_CONFIG_SHIFT_SHIFT 24 |
| |
| /* KeyGen Registers bit field masks: */ |
| |
| /* Enable bit field mask for KeyGen General Configuration Register */ |
| #define FM_KG_KGGCR_EN 0x80000000 |
| |
| /* KeyGen Global Registers bit field masks */ |
| #define FM_KG_KGAR_GO 0x80000000 |
| #define FM_KG_KGAR_READ 0x40000000 |
| #define FM_KG_KGAR_WRITE 0x00000000 |
| #define FM_KG_KGAR_SEL_SCHEME_ENTRY 0x00000000 |
| #define FM_KG_KGAR_SCM_WSEL_UPDATE_CNT 0x00008000 |
| |
| #define FM_KG_KGAR_ERR 0x20000000 |
| #define FM_KG_KGAR_SEL_CLS_PLAN_ENTRY 0x01000000 |
| #define FM_KG_KGAR_SEL_PORT_ENTRY 0x02000000 |
| #define FM_KG_KGAR_SEL_PORT_WSEL_SP 0x00008000 |
| #define FM_KG_KGAR_SEL_PORT_WSEL_CPP 0x00004000 |
| |
| /* Error events exceptions */ |
| #define FM_EX_KG_DOUBLE_ECC 0x80000000 |
| #define FM_EX_KG_KEYSIZE_OVERFLOW 0x40000000 |
| |
| /* Scheme Registers bit field masks */ |
| #define KG_SCH_MODE_EN 0x80000000 |
| #define KG_SCH_VSP_NO_KSP_EN 0x80000000 |
| #define KG_SCH_HASH_CONFIG_SYM 0x40000000 |
| |
| /* Known Protocol field codes */ |
| #define KG_SCH_KN_PORT_ID 0x80000000 |
| #define KG_SCH_KN_MACDST 0x40000000 |
| #define KG_SCH_KN_MACSRC 0x20000000 |
| #define KG_SCH_KN_TCI1 0x10000000 |
| #define KG_SCH_KN_TCI2 0x08000000 |
| #define KG_SCH_KN_ETYPE 0x04000000 |
| #define KG_SCH_KN_PPPSID 0x02000000 |
| #define KG_SCH_KN_PPPID 0x01000000 |
| #define KG_SCH_KN_MPLS1 0x00800000 |
| #define KG_SCH_KN_MPLS2 0x00400000 |
| #define KG_SCH_KN_MPLS_LAST 0x00200000 |
| #define KG_SCH_KN_IPSRC1 0x00100000 |
| #define KG_SCH_KN_IPDST1 0x00080000 |
| #define KG_SCH_KN_PTYPE1 0x00040000 |
| #define KG_SCH_KN_IPTOS_TC1 0x00020000 |
| #define KG_SCH_KN_IPV6FL1 0x00010000 |
| #define KG_SCH_KN_IPSRC2 0x00008000 |
| #define KG_SCH_KN_IPDST2 0x00004000 |
| #define KG_SCH_KN_PTYPE2 0x00002000 |
| #define KG_SCH_KN_IPTOS_TC2 0x00001000 |
| #define KG_SCH_KN_IPV6FL2 0x00000800 |
| #define KG_SCH_KN_GREPTYPE 0x00000400 |
| #define KG_SCH_KN_IPSEC_SPI 0x00000200 |
| #define KG_SCH_KN_IPSEC_NH 0x00000100 |
| #define KG_SCH_KN_IPPID 0x00000080 |
| #define KG_SCH_KN_L4PSRC 0x00000004 |
| #define KG_SCH_KN_L4PDST 0x00000002 |
| #define KG_SCH_KN_TFLG 0x00000001 |
| |
| /* NIA values */ |
| #define NIA_ENG_BMI 0x00500000 |
| #define NIA_BMI_AC_ENQ_FRAME 0x00000002 |
| #define ENQUEUE_KG_DFLT_NIA (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME) |
| |
| /* Hard-coded configuration: |
| * These values are used as hard-coded values for KeyGen configuration |
| * and they replace user selections for this hard-coded version |
| */ |
| |
| /* Hash distribution shift */ |
| #define DEFAULT_HASH_DIST_FQID_SHIFT 0 |
| |
| /* Hash shift */ |
| #define DEFAULT_HASH_SHIFT 0 |
| |
| /* Symmetric hash usage: |
| * Warning: |
| * - the value for symmetric hash usage must be in accordance with hash |
| * key defined below |
| * - according to tests performed, spreading is not working if symmetric |
| * hash is set on true |
| * So ultimately symmetric hash functionality should be always disabled: |
| */ |
| #define DEFAULT_SYMMETRIC_HASH false |
| |
| /* Hash Key extraction fields: */ |
| #define DEFAULT_HASH_KEY_EXTRACT_FIELDS \ |
| (KG_SCH_KN_IPSRC1 | KG_SCH_KN_IPDST1 | \ |
| KG_SCH_KN_L4PSRC | KG_SCH_KN_L4PDST | \ |
| KG_SCH_KN_IPSEC_SPI) |
| |
| /* Default values to be used as hash key in case IPv4 or L4 (TCP, UDP) |
| * don't exist in the frame |
| */ |
| /* Default IPv4 address */ |
| #define DEFAULT_HASH_KEY_IPv4_ADDR 0x0A0A0A0A |
| /* Default L4 port */ |
| #define DEFAULT_HASH_KEY_L4_PORT 0x0B0B0B0B |
| |
| /* KeyGen Memory Mapped Registers: */ |
| |
| /* Scheme Configuration RAM Registers */ |
| struct fman_kg_scheme_regs { |
| u32 kgse_mode; /* 0x100: MODE */ |
| u32 kgse_ekfc; /* 0x104: Extract Known Fields Command */ |
| u32 kgse_ekdv; /* 0x108: Extract Known Default Value */ |
| u32 kgse_bmch; /* 0x10C: Bit Mask Command High */ |
| u32 kgse_bmcl; /* 0x110: Bit Mask Command Low */ |
| u32 kgse_fqb; /* 0x114: Frame Queue Base */ |
| u32 kgse_hc; /* 0x118: Hash Command */ |
| u32 kgse_ppc; /* 0x11C: Policer Profile Command */ |
| u32 kgse_gec[FM_KG_NUM_OF_GENERIC_REGS]; |
| /* 0x120: Generic Extract Command */ |
| u32 kgse_spc; |
| /* 0x140: KeyGen Scheme Entry Statistic Packet Counter */ |
| u32 kgse_dv0; /* 0x144: KeyGen Scheme Entry Default Value 0 */ |
| u32 kgse_dv1; /* 0x148: KeyGen Scheme Entry Default Value 1 */ |
| u32 kgse_ccbs; |
| /* 0x14C: KeyGen Scheme Entry Coarse Classification Bit*/ |
| u32 kgse_mv; /* 0x150: KeyGen Scheme Entry Match vector */ |
| u32 kgse_om; /* 0x154: KeyGen Scheme Entry Operation Mode bits */ |
| u32 kgse_vsp; |
| /* 0x158: KeyGen Scheme Entry Virtual Storage Profile */ |
| }; |
| |
| /* Port Partition Configuration Registers */ |
| struct fman_kg_pe_regs { |
| u32 fmkg_pe_sp; /* 0x100: KeyGen Port entry Scheme Partition */ |
| u32 fmkg_pe_cpp; |
| /* 0x104: KeyGen Port Entry Classification Plan Partition */ |
| }; |
| |
| /* General Configuration and Status Registers |
| * Global Statistic Counters |
| * KeyGen Global Registers |
| */ |
| struct fman_kg_regs { |
| u32 fmkg_gcr; /* 0x000: KeyGen General Configuration Register */ |
| u32 res004; /* 0x004: Reserved */ |
| u32 res008; /* 0x008: Reserved */ |
| u32 fmkg_eer; /* 0x00C: KeyGen Error Event Register */ |
| u32 fmkg_eeer; /* 0x010: KeyGen Error Event Enable Register */ |
| u32 res014; /* 0x014: Reserved */ |
| u32 res018; /* 0x018: Reserved */ |
| u32 fmkg_seer; /* 0x01C: KeyGen Scheme Error Event Register */ |
| u32 fmkg_seeer; /* 0x020: KeyGen Scheme Error Event Enable Register */ |
| u32 fmkg_gsr; /* 0x024: KeyGen Global Status Register */ |
| u32 fmkg_tpc; /* 0x028: Total Packet Counter Register */ |
| u32 fmkg_serc; /* 0x02C: Soft Error Capture Register */ |
| u32 res030[4]; /* 0x030: Reserved */ |
| u32 fmkg_fdor; /* 0x034: Frame Data Offset Register */ |
| u32 fmkg_gdv0r; /* 0x038: Global Default Value Register 0 */ |
| u32 fmkg_gdv1r; /* 0x03C: Global Default Value Register 1 */ |
| u32 res04c[6]; /* 0x040: Reserved */ |
| u32 fmkg_feer; /* 0x044: Force Error Event Register */ |
| u32 res068[38]; /* 0x048: Reserved */ |
| union { |
| u32 fmkg_indirect[63]; /* 0x100: Indirect Access Registers */ |
| struct fman_kg_scheme_regs fmkg_sch; /* Scheme Registers */ |
| struct fman_kg_pe_regs fmkg_pe; /* Port Partition Registers */ |
| }; |
| u32 fmkg_ar; /* 0x1FC: KeyGen Action Register */ |
| }; |
| |
| /* KeyGen Scheme data */ |
| struct keygen_scheme { |
| bool used; /* Specifies if this scheme is used */ |
| u8 hw_port_id; |
| /* Hardware port ID |
| * schemes sharing between multiple ports is not |
| * currently supported |
| * so we have only one port id bound to a scheme |
| */ |
| u32 base_fqid; |
| /* Base FQID: |
| * Must be between 1 and 2^24-1 |
| * If hash is used and an even distribution is |
| * expected according to hash_fqid_count, |
| * base_fqid must be aligned to hash_fqid_count |
| */ |
| u32 hash_fqid_count; |
| /* FQ range for hash distribution: |
| * Must be a power of 2 |
| * Represents the range of queues for spreading |
| */ |
| bool use_hashing; /* Usage of Hashing and spreading over FQ */ |
| bool symmetric_hash; /* Symmetric Hash option usage */ |
| u8 hashShift; |
| /* Hash result right shift. |
| * Select the 24 bits out of the 64 hash result. |
| * 0 means using the 24 LSB's, otherwise |
| * use the 24 LSB's after shifting right |
| */ |
| u32 match_vector; /* Match Vector */ |
| }; |
| |
| /* KeyGen driver data */ |
| struct fman_keygen { |
| struct keygen_scheme schemes[FM_KG_MAX_NUM_OF_SCHEMES]; |
| /* Array of schemes */ |
| struct fman_kg_regs __iomem *keygen_regs; /* KeyGen registers */ |
| }; |
| |
| /* keygen_write_ar_wait |
| * |
| * Write Action Register with specified value, wait for GO bit field to be |
| * idle and then read the error |
| * |
| * regs: KeyGen registers |
| * fmkg_ar: Action Register value |
| * |
| * Return: Zero for success or error code in case of failure |
| */ |
| static int keygen_write_ar_wait(struct fman_kg_regs __iomem *regs, u32 fmkg_ar) |
| { |
| iowrite32be(fmkg_ar, ®s->fmkg_ar); |
| |
| /* Wait for GO bit field to be idle */ |
| while (fmkg_ar & FM_KG_KGAR_GO) |
| fmkg_ar = ioread32be(®s->fmkg_ar); |
| |
| if (fmkg_ar & FM_KG_KGAR_ERR) |
| return -EINVAL; |
| |
| return 0; |
| } |
| |
| /* build_ar_scheme |
| * |
| * Build Action Register value for scheme settings |
| * |
| * scheme_id: Scheme ID |
| * update_counter: update scheme counter |
| * write: true for action to write the scheme or false for read action |
| * |
| * Return: AR value |
| */ |
| static u32 build_ar_scheme(u8 scheme_id, bool update_counter, bool write) |
| { |
| u32 rw = (u32)(write ? FM_KG_KGAR_WRITE : FM_KG_KGAR_READ); |
| |
| return (u32)(FM_KG_KGAR_GO | |
| rw | |
| FM_KG_KGAR_SEL_SCHEME_ENTRY | |
| DUMMY_PORT_ID | |
| ((u32)scheme_id << FM_KG_KGAR_NUM_SHIFT) | |
| (update_counter ? FM_KG_KGAR_SCM_WSEL_UPDATE_CNT : 0)); |
| } |
| |
| /* build_ar_bind_scheme |
| * |
| * Build Action Register value for port binding to schemes |
| * |
| * hwport_id: HW Port ID |
| * write: true for action to write the bind or false for read action |
| * |
| * Return: AR value |
| */ |
| static u32 build_ar_bind_scheme(u8 hwport_id, bool write) |
| { |
| u32 rw = write ? (u32)FM_KG_KGAR_WRITE : (u32)FM_KG_KGAR_READ; |
| |
| return (u32)(FM_KG_KGAR_GO | |
| rw | |
| FM_KG_KGAR_SEL_PORT_ENTRY | |
| hwport_id | |
| FM_KG_KGAR_SEL_PORT_WSEL_SP); |
| } |
| |
| /* keygen_write_sp |
| * |
| * Write Scheme Partition Register with specified value |
| * |
| * regs: KeyGen Registers |
| * sp: Scheme Partition register value |
| * add: true to add a scheme partition or false to clear |
| * |
| * Return: none |
| */ |
| static void keygen_write_sp(struct fman_kg_regs __iomem *regs, u32 sp, bool add) |
| { |
| u32 tmp; |
| |
| tmp = ioread32be(®s->fmkg_pe.fmkg_pe_sp); |
| |
| if (add) |
| tmp |= sp; |
| else |
| tmp &= ~sp; |
| |
| iowrite32be(tmp, ®s->fmkg_pe.fmkg_pe_sp); |
| } |
| |
| /* build_ar_bind_cls_plan |
| * |
| * Build Action Register value for Classification Plan |
| * |
| * hwport_id: HW Port ID |
| * write: true for action to write the CP or false for read action |
| * |
| * Return: AR value |
| */ |
| static u32 build_ar_bind_cls_plan(u8 hwport_id, bool write) |
| { |
| u32 rw = write ? (u32)FM_KG_KGAR_WRITE : (u32)FM_KG_KGAR_READ; |
| |
| return (u32)(FM_KG_KGAR_GO | |
| rw | |
| FM_KG_KGAR_SEL_PORT_ENTRY | |
| hwport_id | |
| FM_KG_KGAR_SEL_PORT_WSEL_CPP); |
| } |
| |
| /* keygen_write_cpp |
| * |
| * Write Classification Plan Partition Register with specified value |
| * |
| * regs: KeyGen Registers |
| * cpp: CPP register value |
| * |
| * Return: none |
| */ |
| static void keygen_write_cpp(struct fman_kg_regs __iomem *regs, u32 cpp) |
| { |
| iowrite32be(cpp, ®s->fmkg_pe.fmkg_pe_cpp); |
| } |
| |
| /* keygen_write_scheme |
| * |
| * Write all Schemes Registers with specified values |
| * |
| * regs: KeyGen Registers |
| * scheme_id: Scheme ID |
| * scheme_regs: Scheme registers values desired to be written |
| * update_counter: update scheme counter |
| * |
| * Return: Zero for success or error code in case of failure |
| */ |
| static int keygen_write_scheme(struct fman_kg_regs __iomem *regs, u8 scheme_id, |
| struct fman_kg_scheme_regs *scheme_regs, |
| bool update_counter) |
| { |
| u32 ar_reg; |
| int err, i; |
| |
| /* Write indirect scheme registers */ |
| iowrite32be(scheme_regs->kgse_mode, ®s->fmkg_sch.kgse_mode); |
| iowrite32be(scheme_regs->kgse_ekfc, ®s->fmkg_sch.kgse_ekfc); |
| iowrite32be(scheme_regs->kgse_ekdv, ®s->fmkg_sch.kgse_ekdv); |
| iowrite32be(scheme_regs->kgse_bmch, ®s->fmkg_sch.kgse_bmch); |
| iowrite32be(scheme_regs->kgse_bmcl, ®s->fmkg_sch.kgse_bmcl); |
| iowrite32be(scheme_regs->kgse_fqb, ®s->fmkg_sch.kgse_fqb); |
| iowrite32be(scheme_regs->kgse_hc, ®s->fmkg_sch.kgse_hc); |
| iowrite32be(scheme_regs->kgse_ppc, ®s->fmkg_sch.kgse_ppc); |
| iowrite32be(scheme_regs->kgse_spc, ®s->fmkg_sch.kgse_spc); |
| iowrite32be(scheme_regs->kgse_dv0, ®s->fmkg_sch.kgse_dv0); |
| iowrite32be(scheme_regs->kgse_dv1, ®s->fmkg_sch.kgse_dv1); |
| iowrite32be(scheme_regs->kgse_ccbs, ®s->fmkg_sch.kgse_ccbs); |
| iowrite32be(scheme_regs->kgse_mv, ®s->fmkg_sch.kgse_mv); |
| iowrite32be(scheme_regs->kgse_om, ®s->fmkg_sch.kgse_om); |
| iowrite32be(scheme_regs->kgse_vsp, ®s->fmkg_sch.kgse_vsp); |
| |
| for (i = 0 ; i < FM_KG_NUM_OF_GENERIC_REGS ; i++) |
| iowrite32be(scheme_regs->kgse_gec[i], |
| ®s->fmkg_sch.kgse_gec[i]); |
| |
| /* Write AR (Action register) */ |
| ar_reg = build_ar_scheme(scheme_id, update_counter, true); |
| err = keygen_write_ar_wait(regs, ar_reg); |
| if (err != 0) { |
| pr_err("Writing Action Register failed\n"); |
| return err; |
| } |
| |
| return err; |
| } |
| |
| /* get_free_scheme_id |
| * |
| * Find the first free scheme available to be used |
| * |
| * keygen: KeyGen handle |
| * scheme_id: pointer to scheme id |
| * |
| * Return: 0 on success, -EINVAL when the are no available free schemes |
| */ |
| static int get_free_scheme_id(struct fman_keygen *keygen, u8 *scheme_id) |
| { |
| u8 i; |
| |
| for (i = 0; i < FM_KG_MAX_NUM_OF_SCHEMES; i++) |
| if (!keygen->schemes[i].used) { |
| *scheme_id = i; |
| return 0; |
| } |
| |
| return -EINVAL; |
| } |
| |
| /* get_scheme |
| * |
| * Provides the scheme for specified ID |
| * |
| * keygen: KeyGen handle |
| * scheme_id: Scheme ID |
| * |
| * Return: handle to required scheme |
| */ |
| static struct keygen_scheme *get_scheme(struct fman_keygen *keygen, |
| u8 scheme_id) |
| { |
| if (scheme_id >= FM_KG_MAX_NUM_OF_SCHEMES) |
| return NULL; |
| return &keygen->schemes[scheme_id]; |
| } |
| |
| /* keygen_bind_port_to_schemes |
| * |
| * Bind the port to schemes |
| * |
| * keygen: KeyGen handle |
| * scheme_id: id of the scheme to bind to |
| * bind: true to bind the port or false to unbind it |
| * |
| * Return: Zero for success or error code in case of failure |
| */ |
| static int keygen_bind_port_to_schemes(struct fman_keygen *keygen, |
| u8 scheme_id, |
| bool bind) |
| { |
| struct fman_kg_regs __iomem *keygen_regs = keygen->keygen_regs; |
| struct keygen_scheme *scheme; |
| u32 ar_reg; |
| u32 schemes_vector = 0; |
| int err; |
| |
| scheme = get_scheme(keygen, scheme_id); |
| if (!scheme) { |
| pr_err("Requested Scheme does not exist\n"); |
| return -EINVAL; |
| } |
| if (!scheme->used) { |
| pr_err("Cannot bind port to an invalid scheme\n"); |
| return -EINVAL; |
| } |
| |
| schemes_vector |= 1 << (31 - scheme_id); |
| |
| ar_reg = build_ar_bind_scheme(scheme->hw_port_id, false); |
| err = keygen_write_ar_wait(keygen_regs, ar_reg); |
| if (err != 0) { |
| pr_err("Reading Action Register failed\n"); |
| return err; |
| } |
| |
| keygen_write_sp(keygen_regs, schemes_vector, bind); |
| |
| ar_reg = build_ar_bind_scheme(scheme->hw_port_id, true); |
| err = keygen_write_ar_wait(keygen_regs, ar_reg); |
| if (err != 0) { |
| pr_err("Writing Action Register failed\n"); |
| return err; |
| } |
| |
| return 0; |
| } |
| |
| /* keygen_scheme_setup |
| * |
| * Setup the scheme according to required configuration |
| * |
| * keygen: KeyGen handle |
| * scheme_id: scheme ID |
| * enable: true to enable scheme or false to disable it |
| * |
| * Return: Zero for success or error code in case of failure |
| */ |
| static int keygen_scheme_setup(struct fman_keygen *keygen, u8 scheme_id, |
| bool enable) |
| { |
| struct fman_kg_regs __iomem *keygen_regs = keygen->keygen_regs; |
| struct fman_kg_scheme_regs scheme_regs; |
| struct keygen_scheme *scheme; |
| u32 tmp_reg; |
| int err; |
| |
| scheme = get_scheme(keygen, scheme_id); |
| if (!scheme) { |
| pr_err("Requested Scheme does not exist\n"); |
| return -EINVAL; |
| } |
| if (enable && scheme->used) { |
| pr_err("The requested Scheme is already used\n"); |
| return -EINVAL; |
| } |
| |
| /* Clear scheme registers */ |
| memset(&scheme_regs, 0, sizeof(struct fman_kg_scheme_regs)); |
| |
| /* Setup all scheme registers: */ |
| tmp_reg = 0; |
| |
| if (enable) { |
| /* Enable Scheme */ |
| tmp_reg |= KG_SCH_MODE_EN; |
| /* Enqueue frame NIA */ |
| tmp_reg |= ENQUEUE_KG_DFLT_NIA; |
| } |
| |
| scheme_regs.kgse_mode = tmp_reg; |
| |
| scheme_regs.kgse_mv = scheme->match_vector; |
| |
| /* Scheme don't override StorageProfile: |
| * valid only for DPAA_VERSION >= 11 |
| */ |
| scheme_regs.kgse_vsp = KG_SCH_VSP_NO_KSP_EN; |
| |
| /* Configure Hard-Coded Rx Hashing: */ |
| |
| if (scheme->use_hashing) { |
| /* configure kgse_ekfc */ |
| scheme_regs.kgse_ekfc = DEFAULT_HASH_KEY_EXTRACT_FIELDS; |
| |
| /* configure kgse_ekdv */ |
| tmp_reg = 0; |
| tmp_reg |= (KG_SCH_DEF_USE_KGSE_DV_0 << |
| KG_SCH_DEF_IP_ADDR_SHIFT); |
| tmp_reg |= (KG_SCH_DEF_USE_KGSE_DV_1 << |
| KG_SCH_DEF_L4_PORT_SHIFT); |
| scheme_regs.kgse_ekdv = tmp_reg; |
| |
| /* configure kgse_dv0 */ |
| scheme_regs.kgse_dv0 = DEFAULT_HASH_KEY_IPv4_ADDR; |
| /* configure kgse_dv1 */ |
| scheme_regs.kgse_dv1 = DEFAULT_HASH_KEY_L4_PORT; |
| |
| /* configure kgse_hc */ |
| tmp_reg = 0; |
| tmp_reg |= ((scheme->hash_fqid_count - 1) << |
| DEFAULT_HASH_DIST_FQID_SHIFT); |
| tmp_reg |= scheme->hashShift << KG_SCH_HASH_CONFIG_SHIFT_SHIFT; |
| |
| if (scheme->symmetric_hash) { |
| /* Normally extraction key should be verified if |
| * complies with symmetric hash |
| * But because extraction is hard-coded, we are sure |
| * the key is symmetric |
| */ |
| tmp_reg |= KG_SCH_HASH_CONFIG_SYM; |
| } |
| scheme_regs.kgse_hc = tmp_reg; |
| } else { |
| scheme_regs.kgse_ekfc = 0; |
| scheme_regs.kgse_hc = 0; |
| scheme_regs.kgse_ekdv = 0; |
| scheme_regs.kgse_dv0 = 0; |
| scheme_regs.kgse_dv1 = 0; |
| } |
| |
| /* configure kgse_fqb: Scheme FQID base */ |
| tmp_reg = 0; |
| tmp_reg |= scheme->base_fqid; |
| scheme_regs.kgse_fqb = tmp_reg; |
| |
| /* features not used by hard-coded configuration */ |
| scheme_regs.kgse_bmch = 0; |
| scheme_regs.kgse_bmcl = 0; |
| scheme_regs.kgse_spc = 0; |
| |
| /* Write scheme registers */ |
| err = keygen_write_scheme(keygen_regs, scheme_id, &scheme_regs, true); |
| if (err != 0) { |
| pr_err("Writing scheme registers failed\n"); |
| return err; |
| } |
| |
| /* Update used field for Scheme */ |
| scheme->used = enable; |
| |
| return 0; |
| } |
| |
| /* keygen_init |
| * |
| * KeyGen initialization: |
| * Initializes and enables KeyGen, allocate driver memory, setup registers, |
| * clear port bindings, invalidate all schemes |
| * |
| * keygen_regs: KeyGen registers base address |
| * |
| * Return: Handle to KeyGen driver |
| */ |
| struct fman_keygen *keygen_init(struct fman_kg_regs __iomem *keygen_regs) |
| { |
| struct fman_keygen *keygen; |
| u32 ar; |
| int i; |
| |
| /* Allocate memory for KeyGen driver */ |
| keygen = kzalloc(sizeof(*keygen), GFP_KERNEL); |
| if (!keygen) |
| return NULL; |
| |
| keygen->keygen_regs = keygen_regs; |
| |
| /* KeyGen initialization (for Master partition): |
| * Setup KeyGen registers |
| */ |
| iowrite32be(ENQUEUE_KG_DFLT_NIA, &keygen_regs->fmkg_gcr); |
| |
| iowrite32be(FM_EX_KG_DOUBLE_ECC | FM_EX_KG_KEYSIZE_OVERFLOW, |
| &keygen_regs->fmkg_eer); |
| |
| iowrite32be(0, &keygen_regs->fmkg_fdor); |
| iowrite32be(0, &keygen_regs->fmkg_gdv0r); |
| iowrite32be(0, &keygen_regs->fmkg_gdv1r); |
| |
| /* Clear binding between ports to schemes and classification plans |
| * so that all ports are not bound to any scheme/classification plan |
| */ |
| for (i = 0; i < FMAN_MAX_NUM_OF_HW_PORTS; i++) { |
| /* Clear all pe sp schemes registers */ |
| keygen_write_sp(keygen_regs, 0xffffffff, false); |
| ar = build_ar_bind_scheme(i, true); |
| keygen_write_ar_wait(keygen_regs, ar); |
| |
| /* Clear all pe cpp classification plans registers */ |
| keygen_write_cpp(keygen_regs, 0); |
| ar = build_ar_bind_cls_plan(i, true); |
| keygen_write_ar_wait(keygen_regs, ar); |
| } |
| |
| /* Enable all scheme interrupts */ |
| iowrite32be(0xFFFFFFFF, &keygen_regs->fmkg_seer); |
| iowrite32be(0xFFFFFFFF, &keygen_regs->fmkg_seeer); |
| |
| /* Enable KyeGen */ |
| iowrite32be(ioread32be(&keygen_regs->fmkg_gcr) | FM_KG_KGGCR_EN, |
| &keygen_regs->fmkg_gcr); |
| |
| return keygen; |
| } |
| EXPORT_SYMBOL(keygen_init); |
| |
| /* keygen_port_hashing_init |
| * |
| * Initializes a port for Rx Hashing with specified configuration parameters |
| * |
| * keygen: KeyGen handle |
| * hw_port_id: HW Port ID |
| * hash_base_fqid: Hashing Base FQID used for spreading |
| * hash_size: Hashing size |
| * |
| * Return: Zero for success or error code in case of failure |
| */ |
| int keygen_port_hashing_init(struct fman_keygen *keygen, u8 hw_port_id, |
| u32 hash_base_fqid, u32 hash_size) |
| { |
| struct keygen_scheme *scheme; |
| u8 scheme_id; |
| int err; |
| |
| /* Validate Scheme configuration parameters */ |
| if (hash_base_fqid == 0 || (hash_base_fqid & ~0x00FFFFFF)) { |
| pr_err("Base FQID must be between 1 and 2^24-1\n"); |
| return -EINVAL; |
| } |
| if (hash_size == 0 || (hash_size & (hash_size - 1)) != 0) { |
| pr_err("Hash size must be power of two\n"); |
| return -EINVAL; |
| } |
| |
| /* Find a free scheme */ |
| err = get_free_scheme_id(keygen, &scheme_id); |
| if (err) { |
| pr_err("The maximum number of available Schemes has been exceeded\n"); |
| return -EINVAL; |
| } |
| |
| /* Create and configure Hard-Coded Scheme: */ |
| |
| scheme = get_scheme(keygen, scheme_id); |
| if (!scheme) { |
| pr_err("Requested Scheme does not exist\n"); |
| return -EINVAL; |
| } |
| if (scheme->used) { |
| pr_err("The requested Scheme is already used\n"); |
| return -EINVAL; |
| } |
| |
| /* Clear all scheme fields because the scheme may have been |
| * previously used |
| */ |
| memset(scheme, 0, sizeof(struct keygen_scheme)); |
| |
| /* Setup scheme: */ |
| scheme->hw_port_id = hw_port_id; |
| scheme->use_hashing = true; |
| scheme->base_fqid = hash_base_fqid; |
| scheme->hash_fqid_count = hash_size; |
| scheme->symmetric_hash = DEFAULT_SYMMETRIC_HASH; |
| scheme->hashShift = DEFAULT_HASH_SHIFT; |
| |
| /* All Schemes in hard-coded configuration |
| * are Indirect Schemes |
| */ |
| scheme->match_vector = 0; |
| |
| err = keygen_scheme_setup(keygen, scheme_id, true); |
| if (err != 0) { |
| pr_err("Scheme setup failed\n"); |
| return err; |
| } |
| |
| /* Bind Rx port to Scheme */ |
| err = keygen_bind_port_to_schemes(keygen, scheme_id, true); |
| if (err != 0) { |
| pr_err("Binding port to schemes failed\n"); |
| return err; |
| } |
| |
| return 0; |
| } |
| EXPORT_SYMBOL(keygen_port_hashing_init); |