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

tcm.h (10231B)


      1/*
      2 * TILER container manager specification and support functions for TI
      3 * TILER driver.
      4 *
      5 * Author: Lajos Molnar <molnar@ti.com>
      6 *
      7 * All rights reserved.
      8 *
      9 * Redistribution and use in source and binary forms, with or without
     10 * modification, are permitted provided that the following conditions
     11 * are met:
     12 *
     13 * * Redistributions of source code must retain the above copyright
     14 *   notice, this list of conditions and the following disclaimer.
     15 *
     16 * * Redistributions in binary form must reproduce the above copyright
     17 *   notice, this list of conditions and the following disclaimer in the
     18 *   documentation and/or other materials provided with the distribution.
     19 *
     20 * * Neither the name of Texas Instruments Incorporated nor the names of
     21 *   its contributors may be used to endorse or promote products derived
     22 *   from this software without specific prior written permission.
     23 *
     24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     25 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     26 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     27 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     28 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     29 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     30 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     31 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     32 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     33 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
     34 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     35 */
     36
     37#ifndef TCM_H
     38#define TCM_H
     39
     40struct tcm;
     41
     42/* point */
     43struct tcm_pt {
     44	u16 x;
     45	u16 y;
     46};
     47
     48/* 1d or 2d area */
     49struct tcm_area {
     50	bool is2d;		/* whether area is 1d or 2d */
     51	struct tcm    *tcm;	/* parent */
     52	struct tcm_pt  p0;
     53	struct tcm_pt  p1;
     54};
     55
     56struct tcm {
     57	u16 width, height;	/* container dimensions */
     58	int lut_id;		/* Lookup table identifier */
     59
     60	unsigned int y_offset;	/* offset to use for y coordinates */
     61
     62	spinlock_t lock;
     63	unsigned long *bitmap;
     64	size_t map_size;
     65
     66	/* function table */
     67	s32 (*reserve_2d)(struct tcm *tcm, u16 height, u16 width, u16 align,
     68			  s16 offset, u16 slot_bytes,
     69			  struct tcm_area *area);
     70	s32 (*reserve_1d)(struct tcm *tcm, u32 slots, struct tcm_area *area);
     71	s32 (*free)(struct tcm *tcm, struct tcm_area *area);
     72	void (*deinit)(struct tcm *tcm);
     73};
     74
     75/*=============================================================================
     76    BASIC TILER CONTAINER MANAGER INTERFACE
     77=============================================================================*/
     78
     79/*
     80 * NOTE:
     81 *
     82 * Since some basic parameter checking is done outside the TCM algorithms,
     83 * TCM implementation do NOT have to check the following:
     84 *
     85 *   area pointer is NULL
     86 *   width and height fits within container
     87 *   number of pages is more than the size of the container
     88 *
     89 */
     90
     91struct tcm *sita_init(u16 width, u16 height);
     92
     93
     94/**
     95 * Deinitialize tiler container manager.
     96 *
     97 * @param tcm	Pointer to container manager.
     98 *
     99 * @return 0 on success, non-0 error value on error.  The call
    100 *	   should free as much memory as possible and meaningful
    101 *	   even on failure.  Some error codes: -ENODEV: invalid
    102 *	   manager.
    103 */
    104static inline void tcm_deinit(struct tcm *tcm)
    105{
    106	if (tcm)
    107		tcm->deinit(tcm);
    108}
    109
    110/**
    111 * Reserves a 2D area in the container.
    112 *
    113 * @param tcm		Pointer to container manager.
    114 * @param height	Height(in pages) of area to be reserved.
    115 * @param width		Width(in pages) of area to be reserved.
    116 * @param align		Alignment requirement for top-left corner of area. Not
    117 *			all values may be supported by the container manager,
    118 *			but it must support 0 (1), 32 and 64.
    119 *			0 value is equivalent to 1.
    120 * @param offset	Offset requirement, in bytes.  This is the offset
    121 *			from a 4KiB aligned virtual address.
    122 * @param slot_bytes	Width of slot in bytes
    123 * @param area		Pointer to where the reserved area should be stored.
    124 *
    125 * @return 0 on success.  Non-0 error code on failure.  Also,
    126 *	   the tcm field of the area will be set to NULL on
    127 *	   failure.  Some error codes: -ENODEV: invalid manager,
    128 *	   -EINVAL: invalid area, -ENOMEM: not enough space for
    129 *	    allocation.
    130 */
    131static inline s32 tcm_reserve_2d(struct tcm *tcm, u16 width, u16 height,
    132				u16 align, s16 offset, u16 slot_bytes,
    133				struct tcm_area *area)
    134{
    135	/* perform rudimentary error checking */
    136	s32 res = tcm  == NULL ? -ENODEV :
    137		(area == NULL || width == 0 || height == 0 ||
    138		 /* align must be a 2 power */
    139		 (align & (align - 1))) ? -EINVAL :
    140		(height > tcm->height || width > tcm->width) ? -ENOMEM : 0;
    141
    142	if (!res) {
    143		area->is2d = true;
    144		res = tcm->reserve_2d(tcm, height, width, align, offset,
    145					slot_bytes, area);
    146		area->tcm = res ? NULL : tcm;
    147	}
    148
    149	return res;
    150}
    151
    152/**
    153 * Reserves a 1D area in the container.
    154 *
    155 * @param tcm		Pointer to container manager.
    156 * @param slots		Number of (contiguous) slots to reserve.
    157 * @param area		Pointer to where the reserved area should be stored.
    158 *
    159 * @return 0 on success.  Non-0 error code on failure.  Also,
    160 *	   the tcm field of the area will be set to NULL on
    161 *	   failure.  Some error codes: -ENODEV: invalid manager,
    162 *	   -EINVAL: invalid area, -ENOMEM: not enough space for
    163 *	    allocation.
    164 */
    165static inline s32 tcm_reserve_1d(struct tcm *tcm, u32 slots,
    166				 struct tcm_area *area)
    167{
    168	/* perform rudimentary error checking */
    169	s32 res = tcm  == NULL ? -ENODEV :
    170		(area == NULL || slots == 0) ? -EINVAL :
    171		slots > (tcm->width * (u32) tcm->height) ? -ENOMEM : 0;
    172
    173	if (!res) {
    174		area->is2d = false;
    175		res = tcm->reserve_1d(tcm, slots, area);
    176		area->tcm = res ? NULL : tcm;
    177	}
    178
    179	return res;
    180}
    181
    182/**
    183 * Free a previously reserved area from the container.
    184 *
    185 * @param area	Pointer to area reserved by a prior call to
    186 *		tcm_reserve_1d or tcm_reserve_2d call, whether
    187 *		it was successful or not. (Note: all fields of
    188 *		the structure must match.)
    189 *
    190 * @return 0 on success.  Non-0 error code on failure.  Also, the tcm
    191 *	   field of the area is set to NULL on success to avoid subsequent
    192 *	   freeing.  This call will succeed even if supplying
    193 *	   the area from a failed reserved call.
    194 */
    195static inline s32 tcm_free(struct tcm_area *area)
    196{
    197	s32 res = 0; /* free succeeds by default */
    198
    199	if (area && area->tcm) {
    200		res = area->tcm->free(area->tcm, area);
    201		if (res == 0)
    202			area->tcm = NULL;
    203	}
    204
    205	return res;
    206}
    207
    208/*=============================================================================
    209    HELPER FUNCTION FOR ANY TILER CONTAINER MANAGER
    210=============================================================================*/
    211
    212/**
    213 * This method slices off the topmost 2D slice from the parent area, and stores
    214 * it in the 'slice' parameter.  The 'parent' parameter will get modified to
    215 * contain the remaining portion of the area.  If the whole parent area can
    216 * fit in a 2D slice, its tcm pointer is set to NULL to mark that it is no
    217 * longer a valid area.
    218 *
    219 * @param parent	Pointer to a VALID parent area that will get modified
    220 * @param slice		Pointer to the slice area that will get modified
    221 */
    222static inline void tcm_slice(struct tcm_area *parent, struct tcm_area *slice)
    223{
    224	*slice = *parent;
    225
    226	/* check if we need to slice */
    227	if (slice->tcm && !slice->is2d &&
    228		slice->p0.y != slice->p1.y &&
    229		(slice->p0.x || (slice->p1.x != slice->tcm->width - 1))) {
    230		/* set end point of slice (start always remains) */
    231		slice->p1.x = slice->tcm->width - 1;
    232		slice->p1.y = (slice->p0.x) ? slice->p0.y : slice->p1.y - 1;
    233		/* adjust remaining area */
    234		parent->p0.x = 0;
    235		parent->p0.y = slice->p1.y + 1;
    236	} else {
    237		/* mark this as the last slice */
    238		parent->tcm = NULL;
    239	}
    240}
    241
    242/* Verify if a tcm area is logically valid */
    243static inline bool tcm_area_is_valid(struct tcm_area *area)
    244{
    245	return area && area->tcm &&
    246		/* coordinate bounds */
    247		area->p1.x < area->tcm->width &&
    248		area->p1.y < area->tcm->height &&
    249		area->p0.y <= area->p1.y &&
    250		/* 1D coordinate relationship + p0.x check */
    251		((!area->is2d &&
    252		  area->p0.x < area->tcm->width &&
    253		  area->p0.x + area->p0.y * area->tcm->width <=
    254		  area->p1.x + area->p1.y * area->tcm->width) ||
    255		 /* 2D coordinate relationship */
    256		 (area->is2d &&
    257		  area->p0.x <= area->p1.x));
    258}
    259
    260/* see if a coordinate is within an area */
    261static inline bool __tcm_is_in(struct tcm_pt *p, struct tcm_area *a)
    262{
    263	u16 i;
    264
    265	if (a->is2d) {
    266		return p->x >= a->p0.x && p->x <= a->p1.x &&
    267		       p->y >= a->p0.y && p->y <= a->p1.y;
    268	} else {
    269		i = p->x + p->y * a->tcm->width;
    270		return i >= a->p0.x + a->p0.y * a->tcm->width &&
    271		       i <= a->p1.x + a->p1.y * a->tcm->width;
    272	}
    273}
    274
    275/* calculate area width */
    276static inline u16 __tcm_area_width(struct tcm_area *area)
    277{
    278	return area->p1.x - area->p0.x + 1;
    279}
    280
    281/* calculate area height */
    282static inline u16 __tcm_area_height(struct tcm_area *area)
    283{
    284	return area->p1.y - area->p0.y + 1;
    285}
    286
    287/* calculate number of slots in an area */
    288static inline u16 __tcm_sizeof(struct tcm_area *area)
    289{
    290	return area->is2d ?
    291		__tcm_area_width(area) * __tcm_area_height(area) :
    292		(area->p1.x - area->p0.x + 1) + (area->p1.y - area->p0.y) *
    293							area->tcm->width;
    294}
    295#define tcm_sizeof(area) __tcm_sizeof(&(area))
    296#define tcm_awidth(area) __tcm_area_width(&(area))
    297#define tcm_aheight(area) __tcm_area_height(&(area))
    298#define tcm_is_in(pt, area) __tcm_is_in(&(pt), &(area))
    299
    300/* limit a 1D area to the first N pages */
    301static inline s32 tcm_1d_limit(struct tcm_area *a, u32 num_pg)
    302{
    303	if (__tcm_sizeof(a) < num_pg)
    304		return -ENOMEM;
    305	if (!num_pg)
    306		return -EINVAL;
    307
    308	a->p1.x = (a->p0.x + num_pg - 1) % a->tcm->width;
    309	a->p1.y = a->p0.y + ((a->p0.x + num_pg - 1) / a->tcm->width);
    310	return 0;
    311}
    312
    313/**
    314 * Iterate through 2D slices of a valid area. Behaves
    315 * syntactically as a for(;;) statement.
    316 *
    317 * @param var		Name of a local variable of type 'struct
    318 *			tcm_area *' that will get modified to
    319 *			contain each slice.
    320 * @param area		Pointer to the VALID parent area. This
    321 *			structure will not get modified
    322 *			throughout the loop.
    323 *
    324 */
    325#define tcm_for_each_slice(var, area, safe) \
    326	for (safe = area, \
    327	     tcm_slice(&safe, &var); \
    328	     var.tcm; tcm_slice(&safe, &var))
    329
    330#endif