Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * TILER container manager specification and support functions for TI
0003  * TILER driver.
0004  *
0005  * Author: Lajos Molnar <molnar@ti.com>
0006  *
0007  * All rights reserved.
0008  *
0009  * Redistribution and use in source and binary forms, with or without
0010  * modification, are permitted provided that the following conditions
0011  * are met:
0012  *
0013  * * Redistributions of source code must retain the above copyright
0014  *   notice, this list of conditions and the following disclaimer.
0015  *
0016  * * Redistributions in binary form must reproduce the above copyright
0017  *   notice, this list of conditions and the following disclaimer in the
0018  *   documentation and/or other materials provided with the distribution.
0019  *
0020  * * Neither the name of Texas Instruments Incorporated nor the names of
0021  *   its contributors may be used to endorse or promote products derived
0022  *   from this software without specific prior written permission.
0023  *
0024  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0025  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
0026  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
0027  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
0028  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
0029  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
0030  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
0031  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
0032  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
0033  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
0034  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0035  */
0036 
0037 #ifndef TCM_H
0038 #define TCM_H
0039 
0040 struct tcm;
0041 
0042 /* point */
0043 struct tcm_pt {
0044     u16 x;
0045     u16 y;
0046 };
0047 
0048 /* 1d or 2d area */
0049 struct tcm_area {
0050     bool is2d;      /* whether area is 1d or 2d */
0051     struct tcm    *tcm; /* parent */
0052     struct tcm_pt  p0;
0053     struct tcm_pt  p1;
0054 };
0055 
0056 struct tcm {
0057     u16 width, height;  /* container dimensions */
0058     int lut_id;     /* Lookup table identifier */
0059 
0060     unsigned int y_offset;  /* offset to use for y coordinates */
0061 
0062     spinlock_t lock;
0063     unsigned long *bitmap;
0064     size_t map_size;
0065 
0066     /* function table */
0067     s32 (*reserve_2d)(struct tcm *tcm, u16 height, u16 width, u16 align,
0068               s16 offset, u16 slot_bytes,
0069               struct tcm_area *area);
0070     s32 (*reserve_1d)(struct tcm *tcm, u32 slots, struct tcm_area *area);
0071     s32 (*free)(struct tcm *tcm, struct tcm_area *area);
0072     void (*deinit)(struct tcm *tcm);
0073 };
0074 
0075 /*=============================================================================
0076     BASIC TILER CONTAINER MANAGER INTERFACE
0077 =============================================================================*/
0078 
0079 /*
0080  * NOTE:
0081  *
0082  * Since some basic parameter checking is done outside the TCM algorithms,
0083  * TCM implementation do NOT have to check the following:
0084  *
0085  *   area pointer is NULL
0086  *   width and height fits within container
0087  *   number of pages is more than the size of the container
0088  *
0089  */
0090 
0091 struct tcm *sita_init(u16 width, u16 height);
0092 
0093 
0094 /**
0095  * Deinitialize tiler container manager.
0096  *
0097  * @param tcm   Pointer to container manager.
0098  *
0099  * @return 0 on success, non-0 error value on error.  The call
0100  *     should free as much memory as possible and meaningful
0101  *     even on failure.  Some error codes: -ENODEV: invalid
0102  *     manager.
0103  */
0104 static inline void tcm_deinit(struct tcm *tcm)
0105 {
0106     if (tcm)
0107         tcm->deinit(tcm);
0108 }
0109 
0110 /**
0111  * Reserves a 2D area in the container.
0112  *
0113  * @param tcm       Pointer to container manager.
0114  * @param height    Height(in pages) of area to be reserved.
0115  * @param width     Width(in pages) of area to be reserved.
0116  * @param align     Alignment requirement for top-left corner of area. Not
0117  *          all values may be supported by the container manager,
0118  *          but it must support 0 (1), 32 and 64.
0119  *          0 value is equivalent to 1.
0120  * @param offset    Offset requirement, in bytes.  This is the offset
0121  *          from a 4KiB aligned virtual address.
0122  * @param slot_bytes    Width of slot in bytes
0123  * @param area      Pointer to where the reserved area should be stored.
0124  *
0125  * @return 0 on success.  Non-0 error code on failure.  Also,
0126  *     the tcm field of the area will be set to NULL on
0127  *     failure.  Some error codes: -ENODEV: invalid manager,
0128  *     -EINVAL: invalid area, -ENOMEM: not enough space for
0129  *      allocation.
0130  */
0131 static inline s32 tcm_reserve_2d(struct tcm *tcm, u16 width, u16 height,
0132                 u16 align, s16 offset, u16 slot_bytes,
0133                 struct tcm_area *area)
0134 {
0135     /* perform rudimentary error checking */
0136     s32 res = tcm  == NULL ? -ENODEV :
0137         (area == NULL || width == 0 || height == 0 ||
0138          /* align must be a 2 power */
0139          (align & (align - 1))) ? -EINVAL :
0140         (height > tcm->height || width > tcm->width) ? -ENOMEM : 0;
0141 
0142     if (!res) {
0143         area->is2d = true;
0144         res = tcm->reserve_2d(tcm, height, width, align, offset,
0145                     slot_bytes, area);
0146         area->tcm = res ? NULL : tcm;
0147     }
0148 
0149     return res;
0150 }
0151 
0152 /**
0153  * Reserves a 1D area in the container.
0154  *
0155  * @param tcm       Pointer to container manager.
0156  * @param slots     Number of (contiguous) slots to reserve.
0157  * @param area      Pointer to where the reserved area should be stored.
0158  *
0159  * @return 0 on success.  Non-0 error code on failure.  Also,
0160  *     the tcm field of the area will be set to NULL on
0161  *     failure.  Some error codes: -ENODEV: invalid manager,
0162  *     -EINVAL: invalid area, -ENOMEM: not enough space for
0163  *      allocation.
0164  */
0165 static inline s32 tcm_reserve_1d(struct tcm *tcm, u32 slots,
0166                  struct tcm_area *area)
0167 {
0168     /* perform rudimentary error checking */
0169     s32 res = tcm  == NULL ? -ENODEV :
0170         (area == NULL || slots == 0) ? -EINVAL :
0171         slots > (tcm->width * (u32) tcm->height) ? -ENOMEM : 0;
0172 
0173     if (!res) {
0174         area->is2d = false;
0175         res = tcm->reserve_1d(tcm, slots, area);
0176         area->tcm = res ? NULL : tcm;
0177     }
0178 
0179     return res;
0180 }
0181 
0182 /**
0183  * Free a previously reserved area from the container.
0184  *
0185  * @param area  Pointer to area reserved by a prior call to
0186  *      tcm_reserve_1d or tcm_reserve_2d call, whether
0187  *      it was successful or not. (Note: all fields of
0188  *      the structure must match.)
0189  *
0190  * @return 0 on success.  Non-0 error code on failure.  Also, the tcm
0191  *     field of the area is set to NULL on success to avoid subsequent
0192  *     freeing.  This call will succeed even if supplying
0193  *     the area from a failed reserved call.
0194  */
0195 static inline s32 tcm_free(struct tcm_area *area)
0196 {
0197     s32 res = 0; /* free succeeds by default */
0198 
0199     if (area && area->tcm) {
0200         res = area->tcm->free(area->tcm, area);
0201         if (res == 0)
0202             area->tcm = NULL;
0203     }
0204 
0205     return res;
0206 }
0207 
0208 /*=============================================================================
0209     HELPER FUNCTION FOR ANY TILER CONTAINER MANAGER
0210 =============================================================================*/
0211 
0212 /**
0213  * This method slices off the topmost 2D slice from the parent area, and stores
0214  * it in the 'slice' parameter.  The 'parent' parameter will get modified to
0215  * contain the remaining portion of the area.  If the whole parent area can
0216  * fit in a 2D slice, its tcm pointer is set to NULL to mark that it is no
0217  * longer a valid area.
0218  *
0219  * @param parent    Pointer to a VALID parent area that will get modified
0220  * @param slice     Pointer to the slice area that will get modified
0221  */
0222 static inline void tcm_slice(struct tcm_area *parent, struct tcm_area *slice)
0223 {
0224     *slice = *parent;
0225 
0226     /* check if we need to slice */
0227     if (slice->tcm && !slice->is2d &&
0228         slice->p0.y != slice->p1.y &&
0229         (slice->p0.x || (slice->p1.x != slice->tcm->width - 1))) {
0230         /* set end point of slice (start always remains) */
0231         slice->p1.x = slice->tcm->width - 1;
0232         slice->p1.y = (slice->p0.x) ? slice->p0.y : slice->p1.y - 1;
0233         /* adjust remaining area */
0234         parent->p0.x = 0;
0235         parent->p0.y = slice->p1.y + 1;
0236     } else {
0237         /* mark this as the last slice */
0238         parent->tcm = NULL;
0239     }
0240 }
0241 
0242 /* Verify if a tcm area is logically valid */
0243 static inline bool tcm_area_is_valid(struct tcm_area *area)
0244 {
0245     return area && area->tcm &&
0246         /* coordinate bounds */
0247         area->p1.x < area->tcm->width &&
0248         area->p1.y < area->tcm->height &&
0249         area->p0.y <= area->p1.y &&
0250         /* 1D coordinate relationship + p0.x check */
0251         ((!area->is2d &&
0252           area->p0.x < area->tcm->width &&
0253           area->p0.x + area->p0.y * area->tcm->width <=
0254           area->p1.x + area->p1.y * area->tcm->width) ||
0255          /* 2D coordinate relationship */
0256          (area->is2d &&
0257           area->p0.x <= area->p1.x));
0258 }
0259 
0260 /* see if a coordinate is within an area */
0261 static inline bool __tcm_is_in(struct tcm_pt *p, struct tcm_area *a)
0262 {
0263     u16 i;
0264 
0265     if (a->is2d) {
0266         return p->x >= a->p0.x && p->x <= a->p1.x &&
0267                p->y >= a->p0.y && p->y <= a->p1.y;
0268     } else {
0269         i = p->x + p->y * a->tcm->width;
0270         return i >= a->p0.x + a->p0.y * a->tcm->width &&
0271                i <= a->p1.x + a->p1.y * a->tcm->width;
0272     }
0273 }
0274 
0275 /* calculate area width */
0276 static inline u16 __tcm_area_width(struct tcm_area *area)
0277 {
0278     return area->p1.x - area->p0.x + 1;
0279 }
0280 
0281 /* calculate area height */
0282 static inline u16 __tcm_area_height(struct tcm_area *area)
0283 {
0284     return area->p1.y - area->p0.y + 1;
0285 }
0286 
0287 /* calculate number of slots in an area */
0288 static inline u16 __tcm_sizeof(struct tcm_area *area)
0289 {
0290     return area->is2d ?
0291         __tcm_area_width(area) * __tcm_area_height(area) :
0292         (area->p1.x - area->p0.x + 1) + (area->p1.y - area->p0.y) *
0293                             area->tcm->width;
0294 }
0295 #define tcm_sizeof(area) __tcm_sizeof(&(area))
0296 #define tcm_awidth(area) __tcm_area_width(&(area))
0297 #define tcm_aheight(area) __tcm_area_height(&(area))
0298 #define tcm_is_in(pt, area) __tcm_is_in(&(pt), &(area))
0299 
0300 /* limit a 1D area to the first N pages */
0301 static inline s32 tcm_1d_limit(struct tcm_area *a, u32 num_pg)
0302 {
0303     if (__tcm_sizeof(a) < num_pg)
0304         return -ENOMEM;
0305     if (!num_pg)
0306         return -EINVAL;
0307 
0308     a->p1.x = (a->p0.x + num_pg - 1) % a->tcm->width;
0309     a->p1.y = a->p0.y + ((a->p0.x + num_pg - 1) / a->tcm->width);
0310     return 0;
0311 }
0312 
0313 /**
0314  * Iterate through 2D slices of a valid area. Behaves
0315  * syntactically as a for(;;) statement.
0316  *
0317  * @param var       Name of a local variable of type 'struct
0318  *          tcm_area *' that will get modified to
0319  *          contain each slice.
0320  * @param area      Pointer to the VALID parent area. This
0321  *          structure will not get modified
0322  *          throughout the loop.
0323  *
0324  */
0325 #define tcm_for_each_slice(var, area, safe) \
0326     for (safe = area, \
0327          tcm_slice(&safe, &var); \
0328          var.tcm; tcm_slice(&safe, &var))
0329 
0330 #endif