diff options
Diffstat (limited to 'drivers/staging/fsl_ppfe/pfe_ctrl.c')
-rw-r--r-- | drivers/staging/fsl_ppfe/pfe_ctrl.c | 226 |
1 files changed, 226 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 000000000000..15c97ece75c5 --- /dev/null +++ b/drivers/staging/fsl_ppfe/pfe_ctrl.c @@ -0,0 +1,226 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2015-2016 Freescale Semiconductor, Inc. + * Copyright 2017 NXP + */ + +#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__); +} |