227 lines
4.8 KiB
C
227 lines
4.8 KiB
C
// 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__);
|
|
}
|