18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  Functions for assembling fcx enabled I/O control blocks.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *    Copyright IBM Corp. 2008
68c2ecf20Sopenharmony_ci *    Author(s): Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/kernel.h>
108c2ecf20Sopenharmony_ci#include <linux/types.h>
118c2ecf20Sopenharmony_ci#include <linux/string.h>
128c2ecf20Sopenharmony_ci#include <linux/errno.h>
138c2ecf20Sopenharmony_ci#include <linux/err.h>
148c2ecf20Sopenharmony_ci#include <linux/module.h>
158c2ecf20Sopenharmony_ci#include <asm/fcx.h>
168c2ecf20Sopenharmony_ci#include "cio.h"
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci/**
198c2ecf20Sopenharmony_ci * tcw_get_intrg - return pointer to associated interrogate tcw
208c2ecf20Sopenharmony_ci * @tcw: pointer to the original tcw
218c2ecf20Sopenharmony_ci *
228c2ecf20Sopenharmony_ci * Return a pointer to the interrogate tcw associated with the specified tcw
238c2ecf20Sopenharmony_ci * or %NULL if there is no associated interrogate tcw.
248c2ecf20Sopenharmony_ci */
258c2ecf20Sopenharmony_cistruct tcw *tcw_get_intrg(struct tcw *tcw)
268c2ecf20Sopenharmony_ci{
278c2ecf20Sopenharmony_ci	return (struct tcw *) ((addr_t) tcw->intrg);
288c2ecf20Sopenharmony_ci}
298c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tcw_get_intrg);
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci/**
328c2ecf20Sopenharmony_ci * tcw_get_data - return pointer to input/output data associated with tcw
338c2ecf20Sopenharmony_ci * @tcw: pointer to the tcw
348c2ecf20Sopenharmony_ci *
358c2ecf20Sopenharmony_ci * Return the input or output data address specified in the tcw depending
368c2ecf20Sopenharmony_ci * on whether the r-bit or the w-bit is set. If neither bit is set, return
378c2ecf20Sopenharmony_ci * %NULL.
388c2ecf20Sopenharmony_ci */
398c2ecf20Sopenharmony_civoid *tcw_get_data(struct tcw *tcw)
408c2ecf20Sopenharmony_ci{
418c2ecf20Sopenharmony_ci	if (tcw->r)
428c2ecf20Sopenharmony_ci		return (void *) ((addr_t) tcw->input);
438c2ecf20Sopenharmony_ci	if (tcw->w)
448c2ecf20Sopenharmony_ci		return (void *) ((addr_t) tcw->output);
458c2ecf20Sopenharmony_ci	return NULL;
468c2ecf20Sopenharmony_ci}
478c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tcw_get_data);
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci/**
508c2ecf20Sopenharmony_ci * tcw_get_tccb - return pointer to tccb associated with tcw
518c2ecf20Sopenharmony_ci * @tcw: pointer to the tcw
528c2ecf20Sopenharmony_ci *
538c2ecf20Sopenharmony_ci * Return pointer to the tccb associated with this tcw.
548c2ecf20Sopenharmony_ci */
558c2ecf20Sopenharmony_cistruct tccb *tcw_get_tccb(struct tcw *tcw)
568c2ecf20Sopenharmony_ci{
578c2ecf20Sopenharmony_ci	return (struct tccb *) ((addr_t) tcw->tccb);
588c2ecf20Sopenharmony_ci}
598c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tcw_get_tccb);
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci/**
628c2ecf20Sopenharmony_ci * tcw_get_tsb - return pointer to tsb associated with tcw
638c2ecf20Sopenharmony_ci * @tcw: pointer to the tcw
648c2ecf20Sopenharmony_ci *
658c2ecf20Sopenharmony_ci * Return pointer to the tsb associated with this tcw.
668c2ecf20Sopenharmony_ci */
678c2ecf20Sopenharmony_cistruct tsb *tcw_get_tsb(struct tcw *tcw)
688c2ecf20Sopenharmony_ci{
698c2ecf20Sopenharmony_ci	return (struct tsb *) ((addr_t) tcw->tsb);
708c2ecf20Sopenharmony_ci}
718c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tcw_get_tsb);
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci/**
748c2ecf20Sopenharmony_ci * tcw_init - initialize tcw data structure
758c2ecf20Sopenharmony_ci * @tcw: pointer to the tcw to be initialized
768c2ecf20Sopenharmony_ci * @r: initial value of the r-bit
778c2ecf20Sopenharmony_ci * @w: initial value of the w-bit
788c2ecf20Sopenharmony_ci *
798c2ecf20Sopenharmony_ci * Initialize all fields of the specified tcw data structure with zero and
808c2ecf20Sopenharmony_ci * fill in the format, flags, r and w fields.
818c2ecf20Sopenharmony_ci */
828c2ecf20Sopenharmony_civoid tcw_init(struct tcw *tcw, int r, int w)
838c2ecf20Sopenharmony_ci{
848c2ecf20Sopenharmony_ci	memset(tcw, 0, sizeof(struct tcw));
858c2ecf20Sopenharmony_ci	tcw->format = TCW_FORMAT_DEFAULT;
868c2ecf20Sopenharmony_ci	tcw->flags = TCW_FLAGS_TIDAW_FORMAT(TCW_TIDAW_FORMAT_DEFAULT);
878c2ecf20Sopenharmony_ci	if (r)
888c2ecf20Sopenharmony_ci		tcw->r = 1;
898c2ecf20Sopenharmony_ci	if (w)
908c2ecf20Sopenharmony_ci		tcw->w = 1;
918c2ecf20Sopenharmony_ci}
928c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tcw_init);
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_cistatic inline size_t tca_size(struct tccb *tccb)
958c2ecf20Sopenharmony_ci{
968c2ecf20Sopenharmony_ci	return tccb->tcah.tcal - 12;
978c2ecf20Sopenharmony_ci}
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_cistatic u32 calc_dcw_count(struct tccb *tccb)
1008c2ecf20Sopenharmony_ci{
1018c2ecf20Sopenharmony_ci	int offset;
1028c2ecf20Sopenharmony_ci	struct dcw *dcw;
1038c2ecf20Sopenharmony_ci	u32 count = 0;
1048c2ecf20Sopenharmony_ci	size_t size;
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	size = tca_size(tccb);
1078c2ecf20Sopenharmony_ci	for (offset = 0; offset < size;) {
1088c2ecf20Sopenharmony_ci		dcw = (struct dcw *) &tccb->tca[offset];
1098c2ecf20Sopenharmony_ci		count += dcw->count;
1108c2ecf20Sopenharmony_ci		if (!(dcw->flags & DCW_FLAGS_CC))
1118c2ecf20Sopenharmony_ci			break;
1128c2ecf20Sopenharmony_ci		offset += sizeof(struct dcw) + ALIGN((int) dcw->cd_count, 4);
1138c2ecf20Sopenharmony_ci	}
1148c2ecf20Sopenharmony_ci	return count;
1158c2ecf20Sopenharmony_ci}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_cistatic u32 calc_cbc_size(struct tidaw *tidaw, int num)
1188c2ecf20Sopenharmony_ci{
1198c2ecf20Sopenharmony_ci	int i;
1208c2ecf20Sopenharmony_ci	u32 cbc_data;
1218c2ecf20Sopenharmony_ci	u32 cbc_count = 0;
1228c2ecf20Sopenharmony_ci	u64 data_count = 0;
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	for (i = 0; i < num; i++) {
1258c2ecf20Sopenharmony_ci		if (tidaw[i].flags & TIDAW_FLAGS_LAST)
1268c2ecf20Sopenharmony_ci			break;
1278c2ecf20Sopenharmony_ci		/* TODO: find out if padding applies to total of data
1288c2ecf20Sopenharmony_ci		 * transferred or data transferred by this tidaw. Assumption:
1298c2ecf20Sopenharmony_ci		 * applies to total. */
1308c2ecf20Sopenharmony_ci		data_count += tidaw[i].count;
1318c2ecf20Sopenharmony_ci		if (tidaw[i].flags & TIDAW_FLAGS_INSERT_CBC) {
1328c2ecf20Sopenharmony_ci			cbc_data = 4 + ALIGN(data_count, 4) - data_count;
1338c2ecf20Sopenharmony_ci			cbc_count += cbc_data;
1348c2ecf20Sopenharmony_ci			data_count += cbc_data;
1358c2ecf20Sopenharmony_ci		}
1368c2ecf20Sopenharmony_ci	}
1378c2ecf20Sopenharmony_ci	return cbc_count;
1388c2ecf20Sopenharmony_ci}
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci/**
1418c2ecf20Sopenharmony_ci * tcw_finalize - finalize tcw length fields and tidaw list
1428c2ecf20Sopenharmony_ci * @tcw: pointer to the tcw
1438c2ecf20Sopenharmony_ci * @num_tidaws: the number of tidaws used to address input/output data or zero
1448c2ecf20Sopenharmony_ci * if no tida is used
1458c2ecf20Sopenharmony_ci *
1468c2ecf20Sopenharmony_ci * Calculate the input-/output-count and tccbl field in the tcw, add a
1478c2ecf20Sopenharmony_ci * tcat the tccb and terminate the data tidaw list if used.
1488c2ecf20Sopenharmony_ci *
1498c2ecf20Sopenharmony_ci * Note: in case input- or output-tida is used, the tidaw-list must be stored
1508c2ecf20Sopenharmony_ci * in contiguous storage (no ttic). The tcal field in the tccb must be
1518c2ecf20Sopenharmony_ci * up-to-date.
1528c2ecf20Sopenharmony_ci */
1538c2ecf20Sopenharmony_civoid tcw_finalize(struct tcw *tcw, int num_tidaws)
1548c2ecf20Sopenharmony_ci{
1558c2ecf20Sopenharmony_ci	struct tidaw *tidaw;
1568c2ecf20Sopenharmony_ci	struct tccb *tccb;
1578c2ecf20Sopenharmony_ci	struct tccb_tcat *tcat;
1588c2ecf20Sopenharmony_ci	u32 count;
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	/* Terminate tidaw list. */
1618c2ecf20Sopenharmony_ci	tidaw = tcw_get_data(tcw);
1628c2ecf20Sopenharmony_ci	if (num_tidaws > 0)
1638c2ecf20Sopenharmony_ci		tidaw[num_tidaws - 1].flags |= TIDAW_FLAGS_LAST;
1648c2ecf20Sopenharmony_ci	/* Add tcat to tccb. */
1658c2ecf20Sopenharmony_ci	tccb = tcw_get_tccb(tcw);
1668c2ecf20Sopenharmony_ci	tcat = (struct tccb_tcat *) &tccb->tca[tca_size(tccb)];
1678c2ecf20Sopenharmony_ci	memset(tcat, 0, sizeof(*tcat));
1688c2ecf20Sopenharmony_ci	/* Calculate tcw input/output count and tcat transport count. */
1698c2ecf20Sopenharmony_ci	count = calc_dcw_count(tccb);
1708c2ecf20Sopenharmony_ci	if (tcw->w && (tcw->flags & TCW_FLAGS_OUTPUT_TIDA))
1718c2ecf20Sopenharmony_ci		count += calc_cbc_size(tidaw, num_tidaws);
1728c2ecf20Sopenharmony_ci	if (tcw->r)
1738c2ecf20Sopenharmony_ci		tcw->input_count = count;
1748c2ecf20Sopenharmony_ci	else if (tcw->w)
1758c2ecf20Sopenharmony_ci		tcw->output_count = count;
1768c2ecf20Sopenharmony_ci	tcat->count = ALIGN(count, 4) + 4;
1778c2ecf20Sopenharmony_ci	/* Calculate tccbl. */
1788c2ecf20Sopenharmony_ci	tcw->tccbl = (sizeof(struct tccb) + tca_size(tccb) +
1798c2ecf20Sopenharmony_ci		      sizeof(struct tccb_tcat) - 20) >> 2;
1808c2ecf20Sopenharmony_ci}
1818c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tcw_finalize);
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci/**
1848c2ecf20Sopenharmony_ci * tcw_set_intrg - set the interrogate tcw address of a tcw
1858c2ecf20Sopenharmony_ci * @tcw: the tcw address
1868c2ecf20Sopenharmony_ci * @intrg_tcw: the address of the interrogate tcw
1878c2ecf20Sopenharmony_ci *
1888c2ecf20Sopenharmony_ci * Set the address of the interrogate tcw in the specified tcw.
1898c2ecf20Sopenharmony_ci */
1908c2ecf20Sopenharmony_civoid tcw_set_intrg(struct tcw *tcw, struct tcw *intrg_tcw)
1918c2ecf20Sopenharmony_ci{
1928c2ecf20Sopenharmony_ci	tcw->intrg = (u32) ((addr_t) intrg_tcw);
1938c2ecf20Sopenharmony_ci}
1948c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tcw_set_intrg);
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci/**
1978c2ecf20Sopenharmony_ci * tcw_set_data - set data address and tida flag of a tcw
1988c2ecf20Sopenharmony_ci * @tcw: the tcw address
1998c2ecf20Sopenharmony_ci * @data: the data address
2008c2ecf20Sopenharmony_ci * @use_tidal: zero of the data address specifies a contiguous block of data,
2018c2ecf20Sopenharmony_ci * non-zero if it specifies a list if tidaws.
2028c2ecf20Sopenharmony_ci *
2038c2ecf20Sopenharmony_ci * Set the input/output data address of a tcw (depending on the value of the
2048c2ecf20Sopenharmony_ci * r-flag and w-flag). If @use_tidal is non-zero, the corresponding tida flag
2058c2ecf20Sopenharmony_ci * is set as well.
2068c2ecf20Sopenharmony_ci */
2078c2ecf20Sopenharmony_civoid tcw_set_data(struct tcw *tcw, void *data, int use_tidal)
2088c2ecf20Sopenharmony_ci{
2098c2ecf20Sopenharmony_ci	if (tcw->r) {
2108c2ecf20Sopenharmony_ci		tcw->input = (u64) ((addr_t) data);
2118c2ecf20Sopenharmony_ci		if (use_tidal)
2128c2ecf20Sopenharmony_ci			tcw->flags |= TCW_FLAGS_INPUT_TIDA;
2138c2ecf20Sopenharmony_ci	} else if (tcw->w) {
2148c2ecf20Sopenharmony_ci		tcw->output = (u64) ((addr_t) data);
2158c2ecf20Sopenharmony_ci		if (use_tidal)
2168c2ecf20Sopenharmony_ci			tcw->flags |= TCW_FLAGS_OUTPUT_TIDA;
2178c2ecf20Sopenharmony_ci	}
2188c2ecf20Sopenharmony_ci}
2198c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tcw_set_data);
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci/**
2228c2ecf20Sopenharmony_ci * tcw_set_tccb - set tccb address of a tcw
2238c2ecf20Sopenharmony_ci * @tcw: the tcw address
2248c2ecf20Sopenharmony_ci * @tccb: the tccb address
2258c2ecf20Sopenharmony_ci *
2268c2ecf20Sopenharmony_ci * Set the address of the tccb in the specified tcw.
2278c2ecf20Sopenharmony_ci */
2288c2ecf20Sopenharmony_civoid tcw_set_tccb(struct tcw *tcw, struct tccb *tccb)
2298c2ecf20Sopenharmony_ci{
2308c2ecf20Sopenharmony_ci	tcw->tccb = (u64) ((addr_t) tccb);
2318c2ecf20Sopenharmony_ci}
2328c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tcw_set_tccb);
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci/**
2358c2ecf20Sopenharmony_ci * tcw_set_tsb - set tsb address of a tcw
2368c2ecf20Sopenharmony_ci * @tcw: the tcw address
2378c2ecf20Sopenharmony_ci * @tsb: the tsb address
2388c2ecf20Sopenharmony_ci *
2398c2ecf20Sopenharmony_ci * Set the address of the tsb in the specified tcw.
2408c2ecf20Sopenharmony_ci */
2418c2ecf20Sopenharmony_civoid tcw_set_tsb(struct tcw *tcw, struct tsb *tsb)
2428c2ecf20Sopenharmony_ci{
2438c2ecf20Sopenharmony_ci	tcw->tsb = (u64) ((addr_t) tsb);
2448c2ecf20Sopenharmony_ci}
2458c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tcw_set_tsb);
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci/**
2488c2ecf20Sopenharmony_ci * tccb_init - initialize tccb
2498c2ecf20Sopenharmony_ci * @tccb: the tccb address
2508c2ecf20Sopenharmony_ci * @size: the maximum size of the tccb
2518c2ecf20Sopenharmony_ci * @sac: the service-action-code to be user
2528c2ecf20Sopenharmony_ci *
2538c2ecf20Sopenharmony_ci * Initialize the header of the specified tccb by resetting all values to zero
2548c2ecf20Sopenharmony_ci * and filling in defaults for format, sac and initial tcal fields.
2558c2ecf20Sopenharmony_ci */
2568c2ecf20Sopenharmony_civoid tccb_init(struct tccb *tccb, size_t size, u32 sac)
2578c2ecf20Sopenharmony_ci{
2588c2ecf20Sopenharmony_ci	memset(tccb, 0, size);
2598c2ecf20Sopenharmony_ci	tccb->tcah.format = TCCB_FORMAT_DEFAULT;
2608c2ecf20Sopenharmony_ci	tccb->tcah.sac = sac;
2618c2ecf20Sopenharmony_ci	tccb->tcah.tcal = 12;
2628c2ecf20Sopenharmony_ci}
2638c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tccb_init);
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci/**
2668c2ecf20Sopenharmony_ci * tsb_init - initialize tsb
2678c2ecf20Sopenharmony_ci * @tsb: the tsb address
2688c2ecf20Sopenharmony_ci *
2698c2ecf20Sopenharmony_ci * Initialize the specified tsb by resetting all values to zero.
2708c2ecf20Sopenharmony_ci */
2718c2ecf20Sopenharmony_civoid tsb_init(struct tsb *tsb)
2728c2ecf20Sopenharmony_ci{
2738c2ecf20Sopenharmony_ci	memset(tsb, 0, sizeof(*tsb));
2748c2ecf20Sopenharmony_ci}
2758c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tsb_init);
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci/**
2788c2ecf20Sopenharmony_ci * tccb_add_dcw - add a dcw to the tccb
2798c2ecf20Sopenharmony_ci * @tccb: the tccb address
2808c2ecf20Sopenharmony_ci * @tccb_size: the maximum tccb size
2818c2ecf20Sopenharmony_ci * @cmd: the dcw command
2828c2ecf20Sopenharmony_ci * @flags: flags for the dcw
2838c2ecf20Sopenharmony_ci * @cd: pointer to control data for this dcw or NULL if none is required
2848c2ecf20Sopenharmony_ci * @cd_count: number of control data bytes for this dcw
2858c2ecf20Sopenharmony_ci * @count: number of data bytes for this dcw
2868c2ecf20Sopenharmony_ci *
2878c2ecf20Sopenharmony_ci * Add a new dcw to the specified tccb by writing the dcw information specified
2888c2ecf20Sopenharmony_ci * by @cmd, @flags, @cd, @cd_count and @count to the tca of the tccb. Return
2898c2ecf20Sopenharmony_ci * a pointer to the newly added dcw on success or -%ENOSPC if the new dcw
2908c2ecf20Sopenharmony_ci * would exceed the available space as defined by @tccb_size.
2918c2ecf20Sopenharmony_ci *
2928c2ecf20Sopenharmony_ci * Note: the tcal field of the tccb header will be updates to reflect added
2938c2ecf20Sopenharmony_ci * content.
2948c2ecf20Sopenharmony_ci */
2958c2ecf20Sopenharmony_cistruct dcw *tccb_add_dcw(struct tccb *tccb, size_t tccb_size, u8 cmd, u8 flags,
2968c2ecf20Sopenharmony_ci			 void *cd, u8 cd_count, u32 count)
2978c2ecf20Sopenharmony_ci{
2988c2ecf20Sopenharmony_ci	struct dcw *dcw;
2998c2ecf20Sopenharmony_ci	int size;
3008c2ecf20Sopenharmony_ci	int tca_offset;
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci	/* Check for space. */
3038c2ecf20Sopenharmony_ci	tca_offset = tca_size(tccb);
3048c2ecf20Sopenharmony_ci	size = ALIGN(sizeof(struct dcw) + cd_count, 4);
3058c2ecf20Sopenharmony_ci	if (sizeof(struct tccb_tcah) + tca_offset + size +
3068c2ecf20Sopenharmony_ci	    sizeof(struct tccb_tcat) > tccb_size)
3078c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOSPC);
3088c2ecf20Sopenharmony_ci	/* Add dcw to tca. */
3098c2ecf20Sopenharmony_ci	dcw = (struct dcw *) &tccb->tca[tca_offset];
3108c2ecf20Sopenharmony_ci	memset(dcw, 0, size);
3118c2ecf20Sopenharmony_ci	dcw->cmd = cmd;
3128c2ecf20Sopenharmony_ci	dcw->flags = flags;
3138c2ecf20Sopenharmony_ci	dcw->count = count;
3148c2ecf20Sopenharmony_ci	dcw->cd_count = cd_count;
3158c2ecf20Sopenharmony_ci	if (cd)
3168c2ecf20Sopenharmony_ci		memcpy(&dcw->cd[0], cd, cd_count);
3178c2ecf20Sopenharmony_ci	tccb->tcah.tcal += size;
3188c2ecf20Sopenharmony_ci	return dcw;
3198c2ecf20Sopenharmony_ci}
3208c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tccb_add_dcw);
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci/**
3238c2ecf20Sopenharmony_ci * tcw_add_tidaw - add a tidaw to a tcw
3248c2ecf20Sopenharmony_ci * @tcw: the tcw address
3258c2ecf20Sopenharmony_ci * @num_tidaws: the current number of tidaws
3268c2ecf20Sopenharmony_ci * @flags: flags for the new tidaw
3278c2ecf20Sopenharmony_ci * @addr: address value for the new tidaw
3288c2ecf20Sopenharmony_ci * @count: count value for the new tidaw
3298c2ecf20Sopenharmony_ci *
3308c2ecf20Sopenharmony_ci * Add a new tidaw to the input/output data tidaw-list of the specified tcw
3318c2ecf20Sopenharmony_ci * (depending on the value of the r-flag and w-flag) and return a pointer to
3328c2ecf20Sopenharmony_ci * the new tidaw.
3338c2ecf20Sopenharmony_ci *
3348c2ecf20Sopenharmony_ci * Note: the tidaw-list is assumed to be contiguous with no ttics. The caller
3358c2ecf20Sopenharmony_ci * must ensure that there is enough space for the new tidaw. The last-tidaw
3368c2ecf20Sopenharmony_ci * flag for the last tidaw in the list will be set by tcw_finalize.
3378c2ecf20Sopenharmony_ci */
3388c2ecf20Sopenharmony_cistruct tidaw *tcw_add_tidaw(struct tcw *tcw, int num_tidaws, u8 flags,
3398c2ecf20Sopenharmony_ci			    void *addr, u32 count)
3408c2ecf20Sopenharmony_ci{
3418c2ecf20Sopenharmony_ci	struct tidaw *tidaw;
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	/* Add tidaw to tidaw-list. */
3448c2ecf20Sopenharmony_ci	tidaw = ((struct tidaw *) tcw_get_data(tcw)) + num_tidaws;
3458c2ecf20Sopenharmony_ci	memset(tidaw, 0, sizeof(struct tidaw));
3468c2ecf20Sopenharmony_ci	tidaw->flags = flags;
3478c2ecf20Sopenharmony_ci	tidaw->count = count;
3488c2ecf20Sopenharmony_ci	tidaw->addr = (u64) ((addr_t) addr);
3498c2ecf20Sopenharmony_ci	return tidaw;
3508c2ecf20Sopenharmony_ci}
3518c2ecf20Sopenharmony_ciEXPORT_SYMBOL(tcw_add_tidaw);
352