summaryrefslogtreecommitdiff
path: root/drivers/staging/fsl_ppfe/pfe_ctrl.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/fsl_ppfe/pfe_ctrl.c')
-rw-r--r--drivers/staging/fsl_ppfe/pfe_ctrl.c238
1 files changed, 238 insertions, 0 deletions
diff --git a/drivers/staging/fsl_ppfe/pfe_ctrl.c b/drivers/staging/fsl_ppfe/pfe_ctrl.c
new file mode 100644
index 0000000..dfa8547
--- /dev/null
+++ b/drivers/staging/fsl_ppfe/pfe_ctrl.c
@@ -0,0 +1,238 @@
+/*
+ * Copyright 2015-2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/kthread.h>
+
+#include "pfe_mod.h"
+#include "pfe_ctrl.h"
+
+#define TIMEOUT_MS 1000
+
+int relax(unsigned long end)
+{
+ if (time_after(jiffies, end)) {
+ if (time_after(jiffies, end + (TIMEOUT_MS * HZ) / 1000))
+ return -1;
+
+ if (need_resched())
+ schedule();
+ }
+
+ return 0;
+}
+
+void pfe_ctrl_suspend(struct pfe_ctrl *ctrl)
+{
+ int id;
+
+ mutex_lock(&ctrl->mutex);
+
+ for (id = CLASS0_ID; id <= CLASS_MAX_ID; id++)
+ pe_dmem_write(id, cpu_to_be32(0x1), CLASS_DM_RESUME, 4);
+
+ for (id = TMU0_ID; id <= TMU_MAX_ID; id++) {
+ if (id == TMU2_ID)
+ continue;
+ pe_dmem_write(id, cpu_to_be32(0x1), TMU_DM_RESUME, 4);
+ }
+
+#if !defined(CONFIG_FSL_PPFE_UTIL_DISABLED)
+ pe_dmem_write(UTIL_ID, cpu_to_be32(0x1), UTIL_DM_RESUME, 4);
+#endif
+ mutex_unlock(&ctrl->mutex);
+}
+
+void pfe_ctrl_resume(struct pfe_ctrl *ctrl)
+{
+ int pe_mask = CLASS_MASK | TMU_MASK;
+
+#if !defined(CONFIG_FSL_PPFE_UTIL_DISABLED)
+ pe_mask |= UTIL_MASK;
+#endif
+ mutex_lock(&ctrl->mutex);
+ pe_start(&pfe->ctrl, pe_mask);
+ mutex_unlock(&ctrl->mutex);
+}
+
+/* PE sync stop.
+ * Stops packet processing for a list of PE's (specified using a bitmask).
+ * The caller must hold ctrl->mutex.
+ *
+ * @param ctrl Control context
+ * @param pe_mask Mask of PE id's to stop
+ *
+ */
+int pe_sync_stop(struct pfe_ctrl *ctrl, int pe_mask)
+{
+ struct pe_sync_mailbox *mbox;
+ int pe_stopped = 0;
+ unsigned long end = jiffies + 2;
+ int i;
+
+ pe_mask &= 0x2FF; /*Exclude Util + TMU2 */
+
+ for (i = 0; i < MAX_PE; i++)
+ if (pe_mask & (1 << i)) {
+ mbox = (void *)ctrl->sync_mailbox_baseaddr[i];
+
+ pe_dmem_write(i, cpu_to_be32(0x1), (unsigned
+ long)&mbox->stop, 4);
+ }
+
+ while (pe_stopped != pe_mask) {
+ for (i = 0; i < MAX_PE; i++)
+ if ((pe_mask & (1 << i)) && !(pe_stopped & (1 << i))) {
+ mbox = (void *)ctrl->sync_mailbox_baseaddr[i];
+
+ if (pe_dmem_read(i, (unsigned
+ long)&mbox->stopped, 4) &
+ cpu_to_be32(0x1))
+ pe_stopped |= (1 << i);
+ }
+
+ if (relax(end) < 0)
+ goto err;
+ }
+
+ return 0;
+
+err:
+ pr_err("%s: timeout, %x %x\n", __func__, pe_mask, pe_stopped);
+
+ for (i = 0; i < MAX_PE; i++)
+ if (pe_mask & (1 << i)) {
+ mbox = (void *)ctrl->sync_mailbox_baseaddr[i];
+
+ pe_dmem_write(i, cpu_to_be32(0x0), (unsigned
+ long)&mbox->stop, 4);
+ }
+
+ return -EIO;
+}
+
+/* PE start.
+ * Starts packet processing for a list of PE's (specified using a bitmask).
+ * The caller must hold ctrl->mutex.
+ *
+ * @param ctrl Control context
+ * @param pe_mask Mask of PE id's to start
+ *
+ */
+void pe_start(struct pfe_ctrl *ctrl, int pe_mask)
+{
+ struct pe_sync_mailbox *mbox;
+ int i;
+
+ for (i = 0; i < MAX_PE; i++)
+ if (pe_mask & (1 << i)) {
+ mbox = (void *)ctrl->sync_mailbox_baseaddr[i];
+
+ pe_dmem_write(i, cpu_to_be32(0x0), (unsigned
+ long)&mbox->stop, 4);
+ }
+}
+
+/* This function will ensure all PEs are put in to idle state */
+int pe_reset_all(struct pfe_ctrl *ctrl)
+{
+ struct pe_sync_mailbox *mbox;
+ int pe_stopped = 0;
+ unsigned long end = jiffies + 2;
+ int i;
+ int pe_mask = CLASS_MASK | TMU_MASK;
+
+#if !defined(CONFIG_FSL_PPFE_UTIL_DISABLED)
+ pe_mask |= UTIL_MASK;
+#endif
+
+ for (i = 0; i < MAX_PE; i++)
+ if (pe_mask & (1 << i)) {
+ mbox = (void *)ctrl->sync_mailbox_baseaddr[i];
+
+ pe_dmem_write(i, cpu_to_be32(0x2), (unsigned
+ long)&mbox->stop, 4);
+ }
+
+ while (pe_stopped != pe_mask) {
+ for (i = 0; i < MAX_PE; i++)
+ if ((pe_mask & (1 << i)) && !(pe_stopped & (1 << i))) {
+ mbox = (void *)ctrl->sync_mailbox_baseaddr[i];
+
+ if (pe_dmem_read(i, (unsigned long)
+ &mbox->stopped, 4) &
+ cpu_to_be32(0x1))
+ pe_stopped |= (1 << i);
+ }
+
+ if (relax(end) < 0)
+ goto err;
+ }
+
+ return 0;
+
+err:
+ pr_err("%s: timeout, %x %x\n", __func__, pe_mask, pe_stopped);
+ return -EIO;
+}
+
+int pfe_ctrl_init(struct pfe *pfe)
+{
+ struct pfe_ctrl *ctrl = &pfe->ctrl;
+ int id;
+
+ pr_info("%s\n", __func__);
+
+ mutex_init(&ctrl->mutex);
+ spin_lock_init(&ctrl->lock);
+
+ for (id = CLASS0_ID; id <= CLASS_MAX_ID; id++) {
+ ctrl->sync_mailbox_baseaddr[id] = CLASS_DM_SYNC_MBOX;
+ ctrl->msg_mailbox_baseaddr[id] = CLASS_DM_MSG_MBOX;
+ }
+
+ for (id = TMU0_ID; id <= TMU_MAX_ID; id++) {
+ if (id == TMU2_ID)
+ continue;
+ ctrl->sync_mailbox_baseaddr[id] = TMU_DM_SYNC_MBOX;
+ ctrl->msg_mailbox_baseaddr[id] = TMU_DM_MSG_MBOX;
+ }
+
+#if !defined(CONFIG_FSL_PPFE_UTIL_DISABLED)
+ ctrl->sync_mailbox_baseaddr[UTIL_ID] = UTIL_DM_SYNC_MBOX;
+ ctrl->msg_mailbox_baseaddr[UTIL_ID] = UTIL_DM_MSG_MBOX;
+#endif
+
+ ctrl->hash_array_baseaddr = pfe->ddr_baseaddr + ROUTE_TABLE_BASEADDR;
+ ctrl->hash_array_phys_baseaddr = pfe->ddr_phys_baseaddr +
+ ROUTE_TABLE_BASEADDR;
+
+ ctrl->dev = pfe->dev;
+
+ pr_info("%s finished\n", __func__);
+
+ return 0;
+}
+
+void pfe_ctrl_exit(struct pfe *pfe)
+{
+ pr_info("%s\n", __func__);
+}