/* * 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 . */ #include #include #include #include #include #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__); }