162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Functions for incremental construction of fcx enabled I/O control blocks. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright IBM Corp. 2008 662306a36Sopenharmony_ci * Author(s): Peter Oberparleiter <peter.oberparleiter@de.ibm.com> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/kernel.h> 1062306a36Sopenharmony_ci#include <linux/types.h> 1162306a36Sopenharmony_ci#include <linux/string.h> 1262306a36Sopenharmony_ci#include <linux/io.h> 1362306a36Sopenharmony_ci#include <linux/errno.h> 1462306a36Sopenharmony_ci#include <linux/err.h> 1562306a36Sopenharmony_ci#include <linux/module.h> 1662306a36Sopenharmony_ci#include <asm/fcx.h> 1762306a36Sopenharmony_ci#include <asm/itcw.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci/* 2062306a36Sopenharmony_ci * struct itcw - incremental tcw helper data type 2162306a36Sopenharmony_ci * 2262306a36Sopenharmony_ci * This structure serves as a handle for the incremental construction of a 2362306a36Sopenharmony_ci * tcw and associated tccb, tsb, data tidaw-list plus an optional interrogate 2462306a36Sopenharmony_ci * tcw and associated data. The data structures are contained inside a single 2562306a36Sopenharmony_ci * contiguous buffer provided by the user. 2662306a36Sopenharmony_ci * 2762306a36Sopenharmony_ci * The itcw construction functions take care of overall data integrity: 2862306a36Sopenharmony_ci * - reset unused fields to zero 2962306a36Sopenharmony_ci * - fill in required pointers 3062306a36Sopenharmony_ci * - ensure required alignment for data structures 3162306a36Sopenharmony_ci * - prevent data structures to cross 4k-byte boundary where required 3262306a36Sopenharmony_ci * - calculate tccb-related length fields 3362306a36Sopenharmony_ci * - optionally provide ready-made interrogate tcw and associated structures 3462306a36Sopenharmony_ci * 3562306a36Sopenharmony_ci * Restrictions apply to the itcws created with these construction functions: 3662306a36Sopenharmony_ci * - tida only supported for data address, not for tccb 3762306a36Sopenharmony_ci * - only contiguous tidaw-lists (no ttic) 3862306a36Sopenharmony_ci * - total number of bytes required per itcw may not exceed 4k bytes 3962306a36Sopenharmony_ci * - either read or write operation (may not work with r=0 and w=0) 4062306a36Sopenharmony_ci * 4162306a36Sopenharmony_ci * Example: 4262306a36Sopenharmony_ci * struct itcw *itcw; 4362306a36Sopenharmony_ci * void *buffer; 4462306a36Sopenharmony_ci * size_t size; 4562306a36Sopenharmony_ci * 4662306a36Sopenharmony_ci * size = itcw_calc_size(1, 2, 0); 4762306a36Sopenharmony_ci * buffer = kmalloc(size, GFP_KERNEL | GFP_DMA); 4862306a36Sopenharmony_ci * if (!buffer) 4962306a36Sopenharmony_ci * return -ENOMEM; 5062306a36Sopenharmony_ci * itcw = itcw_init(buffer, size, ITCW_OP_READ, 1, 2, 0); 5162306a36Sopenharmony_ci * if (IS_ERR(itcw)) 5262306a36Sopenharmony_ci * return PTR_ER(itcw); 5362306a36Sopenharmony_ci * itcw_add_dcw(itcw, 0x2, 0, NULL, 0, 72); 5462306a36Sopenharmony_ci * itcw_add_tidaw(itcw, 0, 0x30000, 20); 5562306a36Sopenharmony_ci * itcw_add_tidaw(itcw, 0, 0x40000, 52); 5662306a36Sopenharmony_ci * itcw_finalize(itcw); 5762306a36Sopenharmony_ci * 5862306a36Sopenharmony_ci */ 5962306a36Sopenharmony_cistruct itcw { 6062306a36Sopenharmony_ci struct tcw *tcw; 6162306a36Sopenharmony_ci struct tcw *intrg_tcw; 6262306a36Sopenharmony_ci int num_tidaws; 6362306a36Sopenharmony_ci int max_tidaws; 6462306a36Sopenharmony_ci int intrg_num_tidaws; 6562306a36Sopenharmony_ci int intrg_max_tidaws; 6662306a36Sopenharmony_ci}; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci/** 6962306a36Sopenharmony_ci * itcw_get_tcw - return pointer to tcw associated with the itcw 7062306a36Sopenharmony_ci * @itcw: address of the itcw 7162306a36Sopenharmony_ci * 7262306a36Sopenharmony_ci * Return pointer to the tcw associated with the itcw. 7362306a36Sopenharmony_ci */ 7462306a36Sopenharmony_cistruct tcw *itcw_get_tcw(struct itcw *itcw) 7562306a36Sopenharmony_ci{ 7662306a36Sopenharmony_ci return itcw->tcw; 7762306a36Sopenharmony_ci} 7862306a36Sopenharmony_ciEXPORT_SYMBOL(itcw_get_tcw); 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci/** 8162306a36Sopenharmony_ci * itcw_calc_size - return the size of an itcw with the given parameters 8262306a36Sopenharmony_ci * @intrg: if non-zero, add an interrogate tcw 8362306a36Sopenharmony_ci * @max_tidaws: maximum number of tidaws to be used for data addressing or zero 8462306a36Sopenharmony_ci * if no tida is to be used. 8562306a36Sopenharmony_ci * @intrg_max_tidaws: maximum number of tidaws to be used for data addressing 8662306a36Sopenharmony_ci * by the interrogate tcw, if specified 8762306a36Sopenharmony_ci * 8862306a36Sopenharmony_ci * Calculate and return the number of bytes required to hold an itcw with the 8962306a36Sopenharmony_ci * given parameters and assuming tccbs with maximum size. 9062306a36Sopenharmony_ci * 9162306a36Sopenharmony_ci * Note that the resulting size also contains bytes needed for alignment 9262306a36Sopenharmony_ci * padding as well as padding to ensure that data structures don't cross a 9362306a36Sopenharmony_ci * 4k-boundary where required. 9462306a36Sopenharmony_ci */ 9562306a36Sopenharmony_cisize_t itcw_calc_size(int intrg, int max_tidaws, int intrg_max_tidaws) 9662306a36Sopenharmony_ci{ 9762306a36Sopenharmony_ci size_t len; 9862306a36Sopenharmony_ci int cross_count; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci /* Main data. */ 10162306a36Sopenharmony_ci len = sizeof(struct itcw); 10262306a36Sopenharmony_ci len += /* TCW */ sizeof(struct tcw) + /* TCCB */ TCCB_MAX_SIZE + 10362306a36Sopenharmony_ci /* TSB */ sizeof(struct tsb) + 10462306a36Sopenharmony_ci /* TIDAL */ max_tidaws * sizeof(struct tidaw); 10562306a36Sopenharmony_ci /* Interrogate data. */ 10662306a36Sopenharmony_ci if (intrg) { 10762306a36Sopenharmony_ci len += /* TCW */ sizeof(struct tcw) + /* TCCB */ TCCB_MAX_SIZE + 10862306a36Sopenharmony_ci /* TSB */ sizeof(struct tsb) + 10962306a36Sopenharmony_ci /* TIDAL */ intrg_max_tidaws * sizeof(struct tidaw); 11062306a36Sopenharmony_ci } 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci /* Maximum required alignment padding. */ 11362306a36Sopenharmony_ci len += /* Initial TCW */ 63 + /* Interrogate TCCB */ 7; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci /* TIDAW lists may not cross a 4k boundary. To cross a 11662306a36Sopenharmony_ci * boundary we need to add a TTIC TIDAW. We need to reserve 11762306a36Sopenharmony_ci * one additional TIDAW for a TTIC that we may need to add due 11862306a36Sopenharmony_ci * to the placement of the data chunk in memory, and a further 11962306a36Sopenharmony_ci * TIDAW for each page boundary that the TIDAW list may cross 12062306a36Sopenharmony_ci * due to it's own size. 12162306a36Sopenharmony_ci */ 12262306a36Sopenharmony_ci if (max_tidaws) { 12362306a36Sopenharmony_ci cross_count = 1 + ((max_tidaws * sizeof(struct tidaw) - 1) 12462306a36Sopenharmony_ci >> PAGE_SHIFT); 12562306a36Sopenharmony_ci len += cross_count * sizeof(struct tidaw); 12662306a36Sopenharmony_ci } 12762306a36Sopenharmony_ci if (intrg_max_tidaws) { 12862306a36Sopenharmony_ci cross_count = 1 + ((intrg_max_tidaws * sizeof(struct tidaw) - 1) 12962306a36Sopenharmony_ci >> PAGE_SHIFT); 13062306a36Sopenharmony_ci len += cross_count * sizeof(struct tidaw); 13162306a36Sopenharmony_ci } 13262306a36Sopenharmony_ci return len; 13362306a36Sopenharmony_ci} 13462306a36Sopenharmony_ciEXPORT_SYMBOL(itcw_calc_size); 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci#define CROSS4K(x, l) (((x) & ~4095) != ((x + l) & ~4095)) 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_cistatic inline void *fit_chunk(addr_t *start, addr_t end, size_t len, 13962306a36Sopenharmony_ci int align, int check_4k) 14062306a36Sopenharmony_ci{ 14162306a36Sopenharmony_ci addr_t addr; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci addr = ALIGN(*start, align); 14462306a36Sopenharmony_ci if (check_4k && CROSS4K(addr, len)) { 14562306a36Sopenharmony_ci addr = ALIGN(addr, 4096); 14662306a36Sopenharmony_ci addr = ALIGN(addr, align); 14762306a36Sopenharmony_ci } 14862306a36Sopenharmony_ci if (addr + len > end) 14962306a36Sopenharmony_ci return ERR_PTR(-ENOSPC); 15062306a36Sopenharmony_ci *start = addr + len; 15162306a36Sopenharmony_ci return (void *) addr; 15262306a36Sopenharmony_ci} 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci/** 15562306a36Sopenharmony_ci * itcw_init - initialize incremental tcw data structure 15662306a36Sopenharmony_ci * @buffer: address of buffer to use for data structures 15762306a36Sopenharmony_ci * @size: number of bytes in buffer 15862306a36Sopenharmony_ci * @op: %ITCW_OP_READ for a read operation tcw, %ITCW_OP_WRITE for a write 15962306a36Sopenharmony_ci * operation tcw 16062306a36Sopenharmony_ci * @intrg: if non-zero, add and initialize an interrogate tcw 16162306a36Sopenharmony_ci * @max_tidaws: maximum number of tidaws to be used for data addressing or zero 16262306a36Sopenharmony_ci * if no tida is to be used. 16362306a36Sopenharmony_ci * @intrg_max_tidaws: maximum number of tidaws to be used for data addressing 16462306a36Sopenharmony_ci * by the interrogate tcw, if specified 16562306a36Sopenharmony_ci * 16662306a36Sopenharmony_ci * Prepare the specified buffer to be used as an incremental tcw, i.e. a 16762306a36Sopenharmony_ci * helper data structure that can be used to construct a valid tcw by 16862306a36Sopenharmony_ci * successive calls to other helper functions. Note: the buffer needs to be 16962306a36Sopenharmony_ci * located below the 2G address limit. The resulting tcw has the following 17062306a36Sopenharmony_ci * restrictions: 17162306a36Sopenharmony_ci * - no tccb tidal 17262306a36Sopenharmony_ci * - input/output tidal is contiguous (no ttic) 17362306a36Sopenharmony_ci * - total data should not exceed 4k 17462306a36Sopenharmony_ci * - tcw specifies either read or write operation 17562306a36Sopenharmony_ci * 17662306a36Sopenharmony_ci * On success, return pointer to the resulting incremental tcw data structure, 17762306a36Sopenharmony_ci * ERR_PTR otherwise. 17862306a36Sopenharmony_ci */ 17962306a36Sopenharmony_cistruct itcw *itcw_init(void *buffer, size_t size, int op, int intrg, 18062306a36Sopenharmony_ci int max_tidaws, int intrg_max_tidaws) 18162306a36Sopenharmony_ci{ 18262306a36Sopenharmony_ci struct itcw *itcw; 18362306a36Sopenharmony_ci void *chunk; 18462306a36Sopenharmony_ci addr_t start; 18562306a36Sopenharmony_ci addr_t end; 18662306a36Sopenharmony_ci int cross_count; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci /* Check for 2G limit. */ 18962306a36Sopenharmony_ci start = (addr_t) buffer; 19062306a36Sopenharmony_ci end = start + size; 19162306a36Sopenharmony_ci if ((virt_to_phys(buffer) + size) > (1 << 31)) 19262306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 19362306a36Sopenharmony_ci memset(buffer, 0, size); 19462306a36Sopenharmony_ci /* ITCW. */ 19562306a36Sopenharmony_ci chunk = fit_chunk(&start, end, sizeof(struct itcw), 1, 0); 19662306a36Sopenharmony_ci if (IS_ERR(chunk)) 19762306a36Sopenharmony_ci return chunk; 19862306a36Sopenharmony_ci itcw = chunk; 19962306a36Sopenharmony_ci /* allow for TTIC tidaws that may be needed to cross a page boundary */ 20062306a36Sopenharmony_ci cross_count = 0; 20162306a36Sopenharmony_ci if (max_tidaws) 20262306a36Sopenharmony_ci cross_count = 1 + ((max_tidaws * sizeof(struct tidaw) - 1) 20362306a36Sopenharmony_ci >> PAGE_SHIFT); 20462306a36Sopenharmony_ci itcw->max_tidaws = max_tidaws + cross_count; 20562306a36Sopenharmony_ci cross_count = 0; 20662306a36Sopenharmony_ci if (intrg_max_tidaws) 20762306a36Sopenharmony_ci cross_count = 1 + ((intrg_max_tidaws * sizeof(struct tidaw) - 1) 20862306a36Sopenharmony_ci >> PAGE_SHIFT); 20962306a36Sopenharmony_ci itcw->intrg_max_tidaws = intrg_max_tidaws + cross_count; 21062306a36Sopenharmony_ci /* Main TCW. */ 21162306a36Sopenharmony_ci chunk = fit_chunk(&start, end, sizeof(struct tcw), 64, 0); 21262306a36Sopenharmony_ci if (IS_ERR(chunk)) 21362306a36Sopenharmony_ci return chunk; 21462306a36Sopenharmony_ci itcw->tcw = chunk; 21562306a36Sopenharmony_ci tcw_init(itcw->tcw, (op == ITCW_OP_READ) ? 1 : 0, 21662306a36Sopenharmony_ci (op == ITCW_OP_WRITE) ? 1 : 0); 21762306a36Sopenharmony_ci /* Interrogate TCW. */ 21862306a36Sopenharmony_ci if (intrg) { 21962306a36Sopenharmony_ci chunk = fit_chunk(&start, end, sizeof(struct tcw), 64, 0); 22062306a36Sopenharmony_ci if (IS_ERR(chunk)) 22162306a36Sopenharmony_ci return chunk; 22262306a36Sopenharmony_ci itcw->intrg_tcw = chunk; 22362306a36Sopenharmony_ci tcw_init(itcw->intrg_tcw, 1, 0); 22462306a36Sopenharmony_ci tcw_set_intrg(itcw->tcw, itcw->intrg_tcw); 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci /* Data TIDAL. */ 22762306a36Sopenharmony_ci if (max_tidaws > 0) { 22862306a36Sopenharmony_ci chunk = fit_chunk(&start, end, sizeof(struct tidaw) * 22962306a36Sopenharmony_ci itcw->max_tidaws, 16, 0); 23062306a36Sopenharmony_ci if (IS_ERR(chunk)) 23162306a36Sopenharmony_ci return chunk; 23262306a36Sopenharmony_ci tcw_set_data(itcw->tcw, chunk, 1); 23362306a36Sopenharmony_ci } 23462306a36Sopenharmony_ci /* Interrogate data TIDAL. */ 23562306a36Sopenharmony_ci if (intrg && (intrg_max_tidaws > 0)) { 23662306a36Sopenharmony_ci chunk = fit_chunk(&start, end, sizeof(struct tidaw) * 23762306a36Sopenharmony_ci itcw->intrg_max_tidaws, 16, 0); 23862306a36Sopenharmony_ci if (IS_ERR(chunk)) 23962306a36Sopenharmony_ci return chunk; 24062306a36Sopenharmony_ci tcw_set_data(itcw->intrg_tcw, chunk, 1); 24162306a36Sopenharmony_ci } 24262306a36Sopenharmony_ci /* TSB. */ 24362306a36Sopenharmony_ci chunk = fit_chunk(&start, end, sizeof(struct tsb), 8, 0); 24462306a36Sopenharmony_ci if (IS_ERR(chunk)) 24562306a36Sopenharmony_ci return chunk; 24662306a36Sopenharmony_ci tsb_init(chunk); 24762306a36Sopenharmony_ci tcw_set_tsb(itcw->tcw, chunk); 24862306a36Sopenharmony_ci /* Interrogate TSB. */ 24962306a36Sopenharmony_ci if (intrg) { 25062306a36Sopenharmony_ci chunk = fit_chunk(&start, end, sizeof(struct tsb), 8, 0); 25162306a36Sopenharmony_ci if (IS_ERR(chunk)) 25262306a36Sopenharmony_ci return chunk; 25362306a36Sopenharmony_ci tsb_init(chunk); 25462306a36Sopenharmony_ci tcw_set_tsb(itcw->intrg_tcw, chunk); 25562306a36Sopenharmony_ci } 25662306a36Sopenharmony_ci /* TCCB. */ 25762306a36Sopenharmony_ci chunk = fit_chunk(&start, end, TCCB_MAX_SIZE, 8, 0); 25862306a36Sopenharmony_ci if (IS_ERR(chunk)) 25962306a36Sopenharmony_ci return chunk; 26062306a36Sopenharmony_ci tccb_init(chunk, TCCB_MAX_SIZE, TCCB_SAC_DEFAULT); 26162306a36Sopenharmony_ci tcw_set_tccb(itcw->tcw, chunk); 26262306a36Sopenharmony_ci /* Interrogate TCCB. */ 26362306a36Sopenharmony_ci if (intrg) { 26462306a36Sopenharmony_ci chunk = fit_chunk(&start, end, TCCB_MAX_SIZE, 8, 0); 26562306a36Sopenharmony_ci if (IS_ERR(chunk)) 26662306a36Sopenharmony_ci return chunk; 26762306a36Sopenharmony_ci tccb_init(chunk, TCCB_MAX_SIZE, TCCB_SAC_INTRG); 26862306a36Sopenharmony_ci tcw_set_tccb(itcw->intrg_tcw, chunk); 26962306a36Sopenharmony_ci tccb_add_dcw(chunk, TCCB_MAX_SIZE, DCW_CMD_INTRG, 0, NULL, 27062306a36Sopenharmony_ci sizeof(struct dcw_intrg_data), 0); 27162306a36Sopenharmony_ci tcw_finalize(itcw->intrg_tcw, 0); 27262306a36Sopenharmony_ci } 27362306a36Sopenharmony_ci return itcw; 27462306a36Sopenharmony_ci} 27562306a36Sopenharmony_ciEXPORT_SYMBOL(itcw_init); 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci/** 27862306a36Sopenharmony_ci * itcw_add_dcw - add a dcw to the itcw 27962306a36Sopenharmony_ci * @itcw: address of the itcw 28062306a36Sopenharmony_ci * @cmd: the dcw command 28162306a36Sopenharmony_ci * @flags: flags for the dcw 28262306a36Sopenharmony_ci * @cd: address of control data for this dcw or NULL if none is required 28362306a36Sopenharmony_ci * @cd_count: number of control data bytes for this dcw 28462306a36Sopenharmony_ci * @count: number of data bytes for this dcw 28562306a36Sopenharmony_ci * 28662306a36Sopenharmony_ci * Add a new dcw to the specified itcw by writing the dcw information specified 28762306a36Sopenharmony_ci * by @cmd, @flags, @cd, @cd_count and @count to the tca of the tccb. Return 28862306a36Sopenharmony_ci * a pointer to the newly added dcw on success or -%ENOSPC if the new dcw 28962306a36Sopenharmony_ci * would exceed the available space. 29062306a36Sopenharmony_ci * 29162306a36Sopenharmony_ci * Note: the tcal field of the tccb header will be updated to reflect added 29262306a36Sopenharmony_ci * content. 29362306a36Sopenharmony_ci */ 29462306a36Sopenharmony_cistruct dcw *itcw_add_dcw(struct itcw *itcw, u8 cmd, u8 flags, void *cd, 29562306a36Sopenharmony_ci u8 cd_count, u32 count) 29662306a36Sopenharmony_ci{ 29762306a36Sopenharmony_ci return tccb_add_dcw(tcw_get_tccb(itcw->tcw), TCCB_MAX_SIZE, cmd, 29862306a36Sopenharmony_ci flags, cd, cd_count, count); 29962306a36Sopenharmony_ci} 30062306a36Sopenharmony_ciEXPORT_SYMBOL(itcw_add_dcw); 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci/** 30362306a36Sopenharmony_ci * itcw_add_tidaw - add a tidaw to the itcw 30462306a36Sopenharmony_ci * @itcw: address of the itcw 30562306a36Sopenharmony_ci * @flags: flags for the new tidaw 30662306a36Sopenharmony_ci * @addr: address value for the new tidaw 30762306a36Sopenharmony_ci * @count: count value for the new tidaw 30862306a36Sopenharmony_ci * 30962306a36Sopenharmony_ci * Add a new tidaw to the input/output data tidaw-list of the specified itcw 31062306a36Sopenharmony_ci * (depending on the value of the r-flag and w-flag). Return a pointer to 31162306a36Sopenharmony_ci * the new tidaw on success or -%ENOSPC if the new tidaw would exceed the 31262306a36Sopenharmony_ci * available space. 31362306a36Sopenharmony_ci * 31462306a36Sopenharmony_ci * Note: TTIC tidaws are automatically added when needed, so explicitly calling 31562306a36Sopenharmony_ci * this interface with the TTIC flag is not supported. The last-tidaw flag 31662306a36Sopenharmony_ci * for the last tidaw in the list will be set by itcw_finalize. 31762306a36Sopenharmony_ci */ 31862306a36Sopenharmony_cistruct tidaw *itcw_add_tidaw(struct itcw *itcw, u8 flags, void *addr, u32 count) 31962306a36Sopenharmony_ci{ 32062306a36Sopenharmony_ci struct tidaw *following; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci if (itcw->num_tidaws >= itcw->max_tidaws) 32362306a36Sopenharmony_ci return ERR_PTR(-ENOSPC); 32462306a36Sopenharmony_ci /* 32562306a36Sopenharmony_ci * Is the tidaw, which follows the one we are about to fill, on the next 32662306a36Sopenharmony_ci * page? Then we have to insert a TTIC tidaw first, that points to the 32762306a36Sopenharmony_ci * tidaw on the new page. 32862306a36Sopenharmony_ci */ 32962306a36Sopenharmony_ci following = ((struct tidaw *) tcw_get_data(itcw->tcw)) 33062306a36Sopenharmony_ci + itcw->num_tidaws + 1; 33162306a36Sopenharmony_ci if (itcw->num_tidaws && !((unsigned long) following & ~PAGE_MASK)) { 33262306a36Sopenharmony_ci tcw_add_tidaw(itcw->tcw, itcw->num_tidaws++, 33362306a36Sopenharmony_ci TIDAW_FLAGS_TTIC, following, 0); 33462306a36Sopenharmony_ci if (itcw->num_tidaws >= itcw->max_tidaws) 33562306a36Sopenharmony_ci return ERR_PTR(-ENOSPC); 33662306a36Sopenharmony_ci } 33762306a36Sopenharmony_ci return tcw_add_tidaw(itcw->tcw, itcw->num_tidaws++, flags, addr, count); 33862306a36Sopenharmony_ci} 33962306a36Sopenharmony_ciEXPORT_SYMBOL(itcw_add_tidaw); 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci/** 34262306a36Sopenharmony_ci * itcw_set_data - set data address and tida flag of the itcw 34362306a36Sopenharmony_ci * @itcw: address of the itcw 34462306a36Sopenharmony_ci * @addr: the data address 34562306a36Sopenharmony_ci * @use_tidal: zero of the data address specifies a contiguous block of data, 34662306a36Sopenharmony_ci * non-zero if it specifies a list if tidaws. 34762306a36Sopenharmony_ci * 34862306a36Sopenharmony_ci * Set the input/output data address of the itcw (depending on the value of the 34962306a36Sopenharmony_ci * r-flag and w-flag). If @use_tidal is non-zero, the corresponding tida flag 35062306a36Sopenharmony_ci * is set as well. 35162306a36Sopenharmony_ci */ 35262306a36Sopenharmony_civoid itcw_set_data(struct itcw *itcw, void *addr, int use_tidal) 35362306a36Sopenharmony_ci{ 35462306a36Sopenharmony_ci tcw_set_data(itcw->tcw, addr, use_tidal); 35562306a36Sopenharmony_ci} 35662306a36Sopenharmony_ciEXPORT_SYMBOL(itcw_set_data); 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci/** 35962306a36Sopenharmony_ci * itcw_finalize - calculate length and count fields of the itcw 36062306a36Sopenharmony_ci * @itcw: address of the itcw 36162306a36Sopenharmony_ci * 36262306a36Sopenharmony_ci * Calculate tcw input-/output-count and tccbl fields and add a tcat the tccb. 36362306a36Sopenharmony_ci * In case input- or output-tida is used, the tidaw-list must be stored in 36462306a36Sopenharmony_ci * continuous storage (no ttic). The tcal field in the tccb must be 36562306a36Sopenharmony_ci * up-to-date. 36662306a36Sopenharmony_ci */ 36762306a36Sopenharmony_civoid itcw_finalize(struct itcw *itcw) 36862306a36Sopenharmony_ci{ 36962306a36Sopenharmony_ci tcw_finalize(itcw->tcw, itcw->num_tidaws); 37062306a36Sopenharmony_ci} 37162306a36Sopenharmony_ciEXPORT_SYMBOL(itcw_finalize); 372