cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

fec.c (7138B)


      1/*
      2 * Bestcomm FEC tasks driver
      3 *
      4 *
      5 * Copyright (C) 2006-2007 Sylvain Munaut <tnt@246tNt.com>
      6 * Copyright (C) 2003-2004 MontaVista, Software, Inc.
      7 *                         ( by Dale Farnsworth <dfarnsworth@mvista.com> )
      8 *
      9 * This file is licensed under the terms of the GNU General Public License
     10 * version 2. This program is licensed "as is" without any warranty of any
     11 * kind, whether express or implied.
     12 */
     13
     14#include <linux/kernel.h>
     15#include <linux/module.h>
     16#include <linux/types.h>
     17#include <asm/io.h>
     18
     19#include <linux/fsl/bestcomm/bestcomm.h>
     20#include <linux/fsl/bestcomm/bestcomm_priv.h>
     21#include <linux/fsl/bestcomm/fec.h>
     22
     23
     24/* ======================================================================== */
     25/* Task image/var/inc                                                       */
     26/* ======================================================================== */
     27
     28/* fec tasks images */
     29extern u32 bcom_fec_rx_task[];
     30extern u32 bcom_fec_tx_task[];
     31
     32/* rx task vars that need to be set before enabling the task */
     33struct bcom_fec_rx_var {
     34	u32 enable;		/* (u16*) address of task's control register */
     35	u32 fifo;		/* (u32*) address of fec's fifo */
     36	u32 bd_base;		/* (struct bcom_bd*) beginning of ring buffer */
     37	u32 bd_last;		/* (struct bcom_bd*) end of ring buffer */
     38	u32 bd_start;		/* (struct bcom_bd*) current bd */
     39	u32 buffer_size;	/* size of receive buffer */
     40};
     41
     42/* rx task incs that need to be set before enabling the task */
     43struct bcom_fec_rx_inc {
     44	u16 pad0;
     45	s16 incr_bytes;
     46	u16 pad1;
     47	s16 incr_dst;
     48	u16 pad2;
     49	s16 incr_dst_ma;
     50};
     51
     52/* tx task vars that need to be set before enabling the task */
     53struct bcom_fec_tx_var {
     54	u32 DRD;		/* (u32*) address of self-modified DRD */
     55	u32 fifo;		/* (u32*) address of fec's fifo */
     56	u32 enable;		/* (u16*) address of task's control register */
     57	u32 bd_base;		/* (struct bcom_bd*) beginning of ring buffer */
     58	u32 bd_last;		/* (struct bcom_bd*) end of ring buffer */
     59	u32 bd_start;		/* (struct bcom_bd*) current bd */
     60	u32 buffer_size;	/* set by uCode for each packet */
     61};
     62
     63/* tx task incs that need to be set before enabling the task */
     64struct bcom_fec_tx_inc {
     65	u16 pad0;
     66	s16 incr_bytes;
     67	u16 pad1;
     68	s16 incr_src;
     69	u16 pad2;
     70	s16 incr_src_ma;
     71};
     72
     73/* private structure in the task */
     74struct bcom_fec_priv {
     75	phys_addr_t	fifo;
     76	int		maxbufsize;
     77};
     78
     79
     80/* ======================================================================== */
     81/* Task support code                                                        */
     82/* ======================================================================== */
     83
     84struct bcom_task *
     85bcom_fec_rx_init(int queue_len, phys_addr_t fifo, int maxbufsize)
     86{
     87	struct bcom_task *tsk;
     88	struct bcom_fec_priv *priv;
     89
     90	tsk = bcom_task_alloc(queue_len, sizeof(struct bcom_fec_bd),
     91				sizeof(struct bcom_fec_priv));
     92	if (!tsk)
     93		return NULL;
     94
     95	tsk->flags = BCOM_FLAGS_NONE;
     96
     97	priv = tsk->priv;
     98	priv->fifo = fifo;
     99	priv->maxbufsize = maxbufsize;
    100
    101	if (bcom_fec_rx_reset(tsk)) {
    102		bcom_task_free(tsk);
    103		return NULL;
    104	}
    105
    106	return tsk;
    107}
    108EXPORT_SYMBOL_GPL(bcom_fec_rx_init);
    109
    110int
    111bcom_fec_rx_reset(struct bcom_task *tsk)
    112{
    113	struct bcom_fec_priv *priv = tsk->priv;
    114	struct bcom_fec_rx_var *var;
    115	struct bcom_fec_rx_inc *inc;
    116
    117	/* Shutdown the task */
    118	bcom_disable_task(tsk->tasknum);
    119
    120	/* Reset the microcode */
    121	var = (struct bcom_fec_rx_var *) bcom_task_var(tsk->tasknum);
    122	inc = (struct bcom_fec_rx_inc *) bcom_task_inc(tsk->tasknum);
    123
    124	if (bcom_load_image(tsk->tasknum, bcom_fec_rx_task))
    125		return -1;
    126
    127	var->enable	= bcom_eng->regs_base +
    128				offsetof(struct mpc52xx_sdma, tcr[tsk->tasknum]);
    129	var->fifo	= (u32) priv->fifo;
    130	var->bd_base	= tsk->bd_pa;
    131	var->bd_last	= tsk->bd_pa + ((tsk->num_bd-1) * tsk->bd_size);
    132	var->bd_start	= tsk->bd_pa;
    133	var->buffer_size = priv->maxbufsize;
    134
    135	inc->incr_bytes	= -(s16)sizeof(u32);	/* These should be in the   */
    136	inc->incr_dst	= sizeof(u32);		/* task image, but we stick */
    137	inc->incr_dst_ma= sizeof(u8);		/* to the official ones     */
    138
    139	/* Reset the BDs */
    140	tsk->index = 0;
    141	tsk->outdex = 0;
    142
    143	memset_io(tsk->bd, 0x00, tsk->num_bd * tsk->bd_size);
    144
    145	/* Configure some stuff */
    146	bcom_set_task_pragma(tsk->tasknum, BCOM_FEC_RX_BD_PRAGMA);
    147	bcom_set_task_auto_start(tsk->tasknum, tsk->tasknum);
    148
    149	out_8(&bcom_eng->regs->ipr[BCOM_INITIATOR_FEC_RX], BCOM_IPR_FEC_RX);
    150
    151	out_be32(&bcom_eng->regs->IntPend, 1<<tsk->tasknum);	/* Clear ints */
    152
    153	return 0;
    154}
    155EXPORT_SYMBOL_GPL(bcom_fec_rx_reset);
    156
    157void
    158bcom_fec_rx_release(struct bcom_task *tsk)
    159{
    160	/* Nothing special for the FEC tasks */
    161	bcom_task_free(tsk);
    162}
    163EXPORT_SYMBOL_GPL(bcom_fec_rx_release);
    164
    165
    166
    167	/* Return 2nd to last DRD */
    168	/* This is an ugly hack, but at least it's only done
    169	   once at initialization */
    170static u32 *self_modified_drd(int tasknum)
    171{
    172	u32 *desc;
    173	int num_descs;
    174	int drd_count;
    175	int i;
    176
    177	num_descs = bcom_task_num_descs(tasknum);
    178	desc = bcom_task_desc(tasknum) + num_descs - 1;
    179	drd_count = 0;
    180	for (i=0; i<num_descs; i++, desc--)
    181		if (bcom_desc_is_drd(*desc) && ++drd_count == 3)
    182			break;
    183	return desc;
    184}
    185
    186struct bcom_task *
    187bcom_fec_tx_init(int queue_len, phys_addr_t fifo)
    188{
    189	struct bcom_task *tsk;
    190	struct bcom_fec_priv *priv;
    191
    192	tsk = bcom_task_alloc(queue_len, sizeof(struct bcom_fec_bd),
    193				sizeof(struct bcom_fec_priv));
    194	if (!tsk)
    195		return NULL;
    196
    197	tsk->flags = BCOM_FLAGS_ENABLE_TASK;
    198
    199	priv = tsk->priv;
    200	priv->fifo = fifo;
    201
    202	if (bcom_fec_tx_reset(tsk)) {
    203		bcom_task_free(tsk);
    204		return NULL;
    205	}
    206
    207	return tsk;
    208}
    209EXPORT_SYMBOL_GPL(bcom_fec_tx_init);
    210
    211int
    212bcom_fec_tx_reset(struct bcom_task *tsk)
    213{
    214	struct bcom_fec_priv *priv = tsk->priv;
    215	struct bcom_fec_tx_var *var;
    216	struct bcom_fec_tx_inc *inc;
    217
    218	/* Shutdown the task */
    219	bcom_disable_task(tsk->tasknum);
    220
    221	/* Reset the microcode */
    222	var = (struct bcom_fec_tx_var *) bcom_task_var(tsk->tasknum);
    223	inc = (struct bcom_fec_tx_inc *) bcom_task_inc(tsk->tasknum);
    224
    225	if (bcom_load_image(tsk->tasknum, bcom_fec_tx_task))
    226		return -1;
    227
    228	var->enable	= bcom_eng->regs_base +
    229				offsetof(struct mpc52xx_sdma, tcr[tsk->tasknum]);
    230	var->fifo	= (u32) priv->fifo;
    231	var->DRD	= bcom_sram_va2pa(self_modified_drd(tsk->tasknum));
    232	var->bd_base	= tsk->bd_pa;
    233	var->bd_last	= tsk->bd_pa + ((tsk->num_bd-1) * tsk->bd_size);
    234	var->bd_start	= tsk->bd_pa;
    235
    236	inc->incr_bytes	= -(s16)sizeof(u32);	/* These should be in the   */
    237	inc->incr_src	= sizeof(u32);		/* task image, but we stick */
    238	inc->incr_src_ma= sizeof(u8);		/* to the official ones     */
    239
    240	/* Reset the BDs */
    241	tsk->index = 0;
    242	tsk->outdex = 0;
    243
    244	memset_io(tsk->bd, 0x00, tsk->num_bd * tsk->bd_size);
    245
    246	/* Configure some stuff */
    247	bcom_set_task_pragma(tsk->tasknum, BCOM_FEC_TX_BD_PRAGMA);
    248	bcom_set_task_auto_start(tsk->tasknum, tsk->tasknum);
    249
    250	out_8(&bcom_eng->regs->ipr[BCOM_INITIATOR_FEC_TX], BCOM_IPR_FEC_TX);
    251
    252	out_be32(&bcom_eng->regs->IntPend, 1<<tsk->tasknum);	/* Clear ints */
    253
    254	return 0;
    255}
    256EXPORT_SYMBOL_GPL(bcom_fec_tx_reset);
    257
    258void
    259bcom_fec_tx_release(struct bcom_task *tsk)
    260{
    261	/* Nothing special for the FEC tasks */
    262	bcom_task_free(tsk);
    263}
    264EXPORT_SYMBOL_GPL(bcom_fec_tx_release);
    265
    266
    267MODULE_DESCRIPTION("BestComm FEC tasks driver");
    268MODULE_AUTHOR("Dale Farnsworth <dfarnsworth@mvista.com>");
    269MODULE_LICENSE("GPL v2");
    270