Merge tag 'dt-5.15' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
[linux-2.6-microblaze.git] / drivers / crypto / hisilicon / sec2 / sec_main.c
index 490db7b..90551bf 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
+#include <linux/pm_runtime.h>
 #include <linux/seq_file.h>
 #include <linux/topology.h>
 #include <linux/uacce.h>
 #define SEC_MEM_START_INIT_REG 0x301100
 #define SEC_MEM_INIT_DONE_REG          0x301104
 
+/* clock gating */
 #define SEC_CONTROL_REG                0x301200
-#define SEC_TRNG_EN_SHIFT              8
+#define SEC_DYNAMIC_GATE_REG           0x30121c
+#define SEC_CORE_AUTO_GATE             0x30212c
+#define SEC_DYNAMIC_GATE_EN            0x7bff
+#define SEC_CORE_AUTO_GATE_EN          GENMASK(3, 0)
 #define SEC_CLK_GATE_ENABLE            BIT(3)
 #define SEC_CLK_GATE_DISABLE           (~BIT(3))
+
+#define SEC_TRNG_EN_SHIFT              8
 #define SEC_AXI_SHUTDOWN_ENABLE        BIT(12)
 #define SEC_AXI_SHUTDOWN_DISABLE       0xFFFFEFFF
 
@@ -312,31 +319,20 @@ static const struct pci_device_id sec_dev_ids[] = {
 };
 MODULE_DEVICE_TABLE(pci, sec_dev_ids);
 
-static u8 sec_get_endian(struct hisi_qm *qm)
+static void sec_set_endian(struct hisi_qm *qm)
 {
        u32 reg;
 
-       /*
-        * As for VF, it is a wrong way to get endian setting by
-        * reading a register of the engine
-        */
-       if (qm->pdev->is_virtfn) {
-               dev_err_ratelimited(&qm->pdev->dev,
-                                   "cannot access a register in VF!\n");
-               return SEC_LE;
-       }
        reg = readl_relaxed(qm->io_base + SEC_CONTROL_REG);
-       /* BD little endian mode */
-       if (!(reg & BIT(0)))
-               return SEC_LE;
+       reg &= ~(BIT(1) | BIT(0));
+       if (!IS_ENABLED(CONFIG_64BIT))
+               reg |= BIT(1);
 
-       /* BD 32-bits big endian mode */
-       else if (!(reg & BIT(1)))
-               return SEC_32BE;
 
-       /* BD 64-bits big endian mode */
-       else
-               return SEC_64BE;
+       if (!IS_ENABLED(CONFIG_CPU_LITTLE_ENDIAN))
+               reg |= BIT(0);
+
+       writel_relaxed(reg, qm->io_base + SEC_CONTROL_REG);
 }
 
 static void sec_open_sva_prefetch(struct hisi_qm *qm)
@@ -378,15 +374,43 @@ static void sec_close_sva_prefetch(struct hisi_qm *qm)
                pci_err(qm->pdev, "failed to close sva prefetch\n");
 }
 
+static void sec_enable_clock_gate(struct hisi_qm *qm)
+{
+       u32 val;
+
+       if (qm->ver < QM_HW_V3)
+               return;
+
+       val = readl_relaxed(qm->io_base + SEC_CONTROL_REG);
+       val |= SEC_CLK_GATE_ENABLE;
+       writel_relaxed(val, qm->io_base + SEC_CONTROL_REG);
+
+       val = readl(qm->io_base + SEC_DYNAMIC_GATE_REG);
+       val |= SEC_DYNAMIC_GATE_EN;
+       writel(val, qm->io_base + SEC_DYNAMIC_GATE_REG);
+
+       val = readl(qm->io_base + SEC_CORE_AUTO_GATE);
+       val |= SEC_CORE_AUTO_GATE_EN;
+       writel(val, qm->io_base + SEC_CORE_AUTO_GATE);
+}
+
+static void sec_disable_clock_gate(struct hisi_qm *qm)
+{
+       u32 val;
+
+       /* Kunpeng920 needs to close clock gating */
+       val = readl_relaxed(qm->io_base + SEC_CONTROL_REG);
+       val &= SEC_CLK_GATE_DISABLE;
+       writel_relaxed(val, qm->io_base + SEC_CONTROL_REG);
+}
+
 static int sec_engine_init(struct hisi_qm *qm)
 {
        int ret;
        u32 reg;
 
-       /* disable clock gate control */
-       reg = readl_relaxed(qm->io_base + SEC_CONTROL_REG);
-       reg &= SEC_CLK_GATE_DISABLE;
-       writel_relaxed(reg, qm->io_base + SEC_CONTROL_REG);
+       /* disable clock gate control before mem init */
+       sec_disable_clock_gate(qm);
 
        writel_relaxed(0x1, qm->io_base + SEC_MEM_START_INIT_REG);
 
@@ -429,9 +453,9 @@ static int sec_engine_init(struct hisi_qm *qm)
                       qm->io_base + SEC_BD_ERR_CHK_EN_REG3);
 
        /* config endian */
-       reg = readl_relaxed(qm->io_base + SEC_CONTROL_REG);
-       reg |= sec_get_endian(qm);
-       writel_relaxed(reg, qm->io_base + SEC_CONTROL_REG);
+       sec_set_endian(qm);
+
+       sec_enable_clock_gate(qm);
 
        return 0;
 }
@@ -533,17 +557,14 @@ static void sec_hw_error_disable(struct hisi_qm *qm)
        writel(SEC_RAS_DISABLE, qm->io_base + SEC_RAS_NFE_REG);
 }
 
-static u32 sec_clear_enable_read(struct sec_debug_file *file)
+static u32 sec_clear_enable_read(struct hisi_qm *qm)
 {
-       struct hisi_qm *qm = file->qm;
-
        return readl(qm->io_base + SEC_CTRL_CNT_CLR_CE) &
                        SEC_CTRL_CNT_CLR_CE_BIT;
 }
 
-static int sec_clear_enable_write(struct sec_debug_file *file, u32 val)
+static int sec_clear_enable_write(struct hisi_qm *qm, u32 val)
 {
-       struct hisi_qm *qm = file->qm;
        u32 tmp;
 
        if (val != 1 && val)
@@ -561,24 +582,34 @@ static ssize_t sec_debug_read(struct file *filp, char __user *buf,
 {
        struct sec_debug_file *file = filp->private_data;
        char tbuf[SEC_DBGFS_VAL_MAX_LEN];
+       struct hisi_qm *qm = file->qm;
        u32 val;
        int ret;
 
+       ret = hisi_qm_get_dfx_access(qm);
+       if (ret)
+               return ret;
+
        spin_lock_irq(&file->lock);
 
        switch (file->index) {
        case SEC_CLEAR_ENABLE:
-               val = sec_clear_enable_read(file);
+               val = sec_clear_enable_read(qm);
                break;
        default:
-               spin_unlock_irq(&file->lock);
-               return -EINVAL;
+               goto err_input;
        }
 
        spin_unlock_irq(&file->lock);
-       ret = snprintf(tbuf, SEC_DBGFS_VAL_MAX_LEN, "%u\n", val);
 
+       hisi_qm_put_dfx_access(qm);
+       ret = snprintf(tbuf, SEC_DBGFS_VAL_MAX_LEN, "%u\n", val);
        return simple_read_from_buffer(buf, count, pos, tbuf, ret);
+
+err_input:
+       spin_unlock_irq(&file->lock);
+       hisi_qm_put_dfx_access(qm);
+       return -EINVAL;
 }
 
 static ssize_t sec_debug_write(struct file *filp, const char __user *buf,
@@ -586,6 +617,7 @@ static ssize_t sec_debug_write(struct file *filp, const char __user *buf,
 {
        struct sec_debug_file *file = filp->private_data;
        char tbuf[SEC_DBGFS_VAL_MAX_LEN];
+       struct hisi_qm *qm = file->qm;
        unsigned long val;
        int len, ret;
 
@@ -604,11 +636,15 @@ static ssize_t sec_debug_write(struct file *filp, const char __user *buf,
        if (kstrtoul(tbuf, 0, &val))
                return -EFAULT;
 
+       ret = hisi_qm_get_dfx_access(qm);
+       if (ret)
+               return ret;
+
        spin_lock_irq(&file->lock);
 
        switch (file->index) {
        case SEC_CLEAR_ENABLE:
-               ret = sec_clear_enable_write(file, val);
+               ret = sec_clear_enable_write(qm, val);
                if (ret)
                        goto err_input;
                break;
@@ -617,12 +653,11 @@ static ssize_t sec_debug_write(struct file *filp, const char __user *buf,
                goto err_input;
        }
 
-       spin_unlock_irq(&file->lock);
-
-       return count;
+       ret = count;
 
  err_input:
        spin_unlock_irq(&file->lock);
+       hisi_qm_put_dfx_access(qm);
        return ret;
 }
 
@@ -653,6 +688,15 @@ static int sec_debugfs_atomic64_set(void *data, u64 val)
 DEFINE_DEBUGFS_ATTRIBUTE(sec_atomic64_ops, sec_debugfs_atomic64_get,
                         sec_debugfs_atomic64_set, "%lld\n");
 
+static int sec_regs_show(struct seq_file *s, void *unused)
+{
+       hisi_qm_regs_dump(s, s->private);
+
+       return 0;
+}
+
+DEFINE_SHOW_ATTRIBUTE(sec_regs);
+
 static int sec_core_debug_init(struct hisi_qm *qm)
 {
        struct sec_dev *sec = container_of(qm, struct sec_dev, qm);
@@ -671,9 +715,10 @@ static int sec_core_debug_init(struct hisi_qm *qm)
        regset->regs = sec_dfx_regs;
        regset->nregs = ARRAY_SIZE(sec_dfx_regs);
        regset->base = qm->io_base;
+       regset->dev = dev;
 
        if (qm->pdev->device == SEC_PF_PCI_DEVICE_ID)
-               debugfs_create_regset32("regs", 0444, tmp_d, regset);
+               debugfs_create_file("regs", 0444, tmp_d, regset, &sec_regs_fops);
 
        for (i = 0; i < ARRAY_SIZE(sec_dfx_labels); i++) {
                atomic64_t *data = (atomic64_t *)((uintptr_t)dfx +
@@ -981,10 +1026,13 @@ static int sec_probe(struct pci_dev *pdev, const struct pci_device_id *id)
                        goto err_alg_unregister;
        }
 
+       hisi_qm_pm_init(qm);
+
        return 0;
 
 err_alg_unregister:
-       hisi_qm_alg_unregister(qm, &sec_devices);
+       if (qm->qp_num >= ctx_q_num)
+               hisi_qm_alg_unregister(qm, &sec_devices);
 err_qm_stop:
        sec_debugfs_exit(qm);
        hisi_qm_stop(qm, QM_NORMAL);
@@ -999,6 +1047,7 @@ static void sec_remove(struct pci_dev *pdev)
 {
        struct hisi_qm *qm = pci_get_drvdata(pdev);
 
+       hisi_qm_pm_uninit(qm);
        hisi_qm_wait_task_finish(qm, &sec_devices);
        if (qm->qp_num >= ctx_q_num)
                hisi_qm_alg_unregister(qm, &sec_devices);
@@ -1018,6 +1067,10 @@ static void sec_remove(struct pci_dev *pdev)
        sec_qm_uninit(qm);
 }
 
+static const struct dev_pm_ops sec_pm_ops = {
+       SET_RUNTIME_PM_OPS(hisi_qm_suspend, hisi_qm_resume, NULL)
+};
+
 static const struct pci_error_handlers sec_err_handler = {
        .error_detected = hisi_qm_dev_err_detected,
        .slot_reset     = hisi_qm_dev_slot_reset,
@@ -1033,6 +1086,7 @@ static struct pci_driver sec_pci_driver = {
        .err_handler = &sec_err_handler,
        .sriov_configure = hisi_qm_sriov_configure,
        .shutdown = hisi_qm_dev_shutdown,
+       .driver.pm = &sec_pm_ops,
 };
 
 static void sec_register_debugfs(void)