Linux Audio

Check our new training course

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