1 // SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only) 2 /* Copyright(c) 2022 Intel Corporation */ 3 #include <linux/bitfield.h> 4 #include <linux/iopoll.h> 5 #include "adf_accel_devices.h" 6 #include "adf_common_drv.h" 7 #include "adf_gen4_pm.h" 8 #include "adf_cfg_strings.h" 9 #include "icp_qat_fw_init_admin.h" 10 #include "adf_gen4_hw_data.h" 11 #include "adf_cfg.h" 12 13 enum qat_pm_host_msg { 14 PM_NO_CHANGE = 0, 15 PM_SET_MIN, 16 }; 17 18 struct adf_gen4_pm_data { 19 struct work_struct pm_irq_work; 20 struct adf_accel_dev *accel_dev; 21 u32 pm_int_sts; 22 }; 23 24 static int send_host_msg(struct adf_accel_dev *accel_dev) 25 { 26 char pm_idle_support_cfg[ADF_CFG_MAX_VAL_LEN_IN_BYTES] = {}; 27 void __iomem *pmisc = adf_get_pmisc_base(accel_dev); 28 bool pm_idle_support; 29 u32 msg; 30 int ret; 31 32 msg = ADF_CSR_RD(pmisc, ADF_GEN4_PM_HOST_MSG); 33 if (msg & ADF_GEN4_PM_MSG_PENDING) 34 return -EBUSY; 35 36 adf_cfg_get_param_value(accel_dev, ADF_GENERAL_SEC, 37 ADF_PM_IDLE_SUPPORT, pm_idle_support_cfg); 38 ret = kstrtobool(pm_idle_support_cfg, &pm_idle_support); 39 if (ret) 40 pm_idle_support = true; 41 42 /* Send HOST_MSG */ 43 msg = FIELD_PREP(ADF_GEN4_PM_MSG_PAYLOAD_BIT_MASK, 44 pm_idle_support ? PM_SET_MIN : PM_NO_CHANGE); 45 msg |= ADF_GEN4_PM_MSG_PENDING; 46 ADF_CSR_WR(pmisc, ADF_GEN4_PM_HOST_MSG, msg); 47 48 /* Poll status register to make sure the HOST_MSG has been processed */ 49 return read_poll_timeout(ADF_CSR_RD, msg, 50 !(msg & ADF_GEN4_PM_MSG_PENDING), 51 ADF_GEN4_PM_MSG_POLL_DELAY_US, 52 ADF_GEN4_PM_POLL_TIMEOUT_US, true, pmisc, 53 ADF_GEN4_PM_HOST_MSG); 54 } 55 56 static void pm_bh_handler(struct work_struct *work) 57 { 58 struct adf_gen4_pm_data *pm_data = 59 container_of(work, struct adf_gen4_pm_data, pm_irq_work); 60 struct adf_accel_dev *accel_dev = pm_data->accel_dev; 61 void __iomem *pmisc = adf_get_pmisc_base(accel_dev); 62 u32 pm_int_sts = pm_data->pm_int_sts; 63 u32 val; 64 65 /* PM Idle interrupt */ 66 if (pm_int_sts & ADF_GEN4_PM_IDLE_STS) { 67 /* Issue host message to FW */ 68 if (send_host_msg(accel_dev)) 69 dev_warn_ratelimited(&GET_DEV(accel_dev), 70 "Failed to send host msg to FW\n"); 71 } 72 73 /* Clear interrupt status */ 74 ADF_CSR_WR(pmisc, ADF_GEN4_PM_INTERRUPT, pm_int_sts); 75 76 /* Reenable PM interrupt */ 77 val = ADF_CSR_RD(pmisc, ADF_GEN4_ERRMSK2); 78 val &= ~ADF_GEN4_PM_SOU; 79 ADF_CSR_WR(pmisc, ADF_GEN4_ERRMSK2, val); 80 81 kfree(pm_data); 82 } 83 84 bool adf_gen4_handle_pm_interrupt(struct adf_accel_dev *accel_dev) 85 { 86 void __iomem *pmisc = adf_get_pmisc_base(accel_dev); 87 struct adf_gen4_pm_data *pm_data = NULL; 88 u32 errsou2; 89 u32 errmsk2; 90 u32 val; 91 92 /* Only handle the interrupt triggered by PM */ 93 errmsk2 = ADF_CSR_RD(pmisc, ADF_GEN4_ERRMSK2); 94 if (errmsk2 & ADF_GEN4_PM_SOU) 95 return false; 96 97 errsou2 = ADF_CSR_RD(pmisc, ADF_GEN4_ERRSOU2); 98 if (!(errsou2 & ADF_GEN4_PM_SOU)) 99 return false; 100 101 /* Disable interrupt */ 102 val = ADF_CSR_RD(pmisc, ADF_GEN4_ERRMSK2); 103 val |= ADF_GEN4_PM_SOU; 104 ADF_CSR_WR(pmisc, ADF_GEN4_ERRMSK2, val); 105 106 val = ADF_CSR_RD(pmisc, ADF_GEN4_PM_INTERRUPT); 107 108 pm_data = kzalloc(sizeof(*pm_data), GFP_ATOMIC); 109 if (!pm_data) 110 return false; 111 112 pm_data->pm_int_sts = val; 113 pm_data->accel_dev = accel_dev; 114 115 INIT_WORK(&pm_data->pm_irq_work, pm_bh_handler); 116 adf_misc_wq_queue_work(&pm_data->pm_irq_work); 117 118 return true; 119 } 120 EXPORT_SYMBOL_GPL(adf_gen4_handle_pm_interrupt); 121 122 int adf_gen4_enable_pm(struct adf_accel_dev *accel_dev) 123 { 124 void __iomem *pmisc = adf_get_pmisc_base(accel_dev); 125 int ret; 126 u32 val; 127 128 ret = adf_init_admin_pm(accel_dev, ADF_GEN4_PM_DEFAULT_IDLE_FILTER); 129 if (ret) 130 return ret; 131 132 /* Enable default PM interrupts: IDLE, THROTTLE */ 133 val = ADF_CSR_RD(pmisc, ADF_GEN4_PM_INTERRUPT); 134 val |= ADF_GEN4_PM_INT_EN_DEFAULT; 135 136 /* Clear interrupt status */ 137 val |= ADF_GEN4_PM_INT_STS_MASK; 138 ADF_CSR_WR(pmisc, ADF_GEN4_PM_INTERRUPT, val); 139 140 /* Unmask PM Interrupt */ 141 val = ADF_CSR_RD(pmisc, ADF_GEN4_ERRMSK2); 142 val &= ~ADF_GEN4_PM_SOU; 143 ADF_CSR_WR(pmisc, ADF_GEN4_ERRMSK2, val); 144 145 return 0; 146 } 147 EXPORT_SYMBOL_GPL(adf_gen4_enable_pm); 148