Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  *  Functions for incremental construction of fcx enabled I/O control blocks.
0004  *
0005  *    Copyright IBM Corp. 2008
0006  *    Author(s): Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
0007  */
0008 
0009 #include <linux/kernel.h>
0010 #include <linux/types.h>
0011 #include <linux/string.h>
0012 #include <linux/errno.h>
0013 #include <linux/err.h>
0014 #include <linux/module.h>
0015 #include <asm/fcx.h>
0016 #include <asm/itcw.h>
0017 
0018 /*
0019  * struct itcw - incremental tcw helper data type
0020  *
0021  * This structure serves as a handle for the incremental construction of a
0022  * tcw and associated tccb, tsb, data tidaw-list plus an optional interrogate
0023  * tcw and associated data. The data structures are contained inside a single
0024  * contiguous buffer provided by the user.
0025  *
0026  * The itcw construction functions take care of overall data integrity:
0027  * - reset unused fields to zero
0028  * - fill in required pointers
0029  * - ensure required alignment for data structures
0030  * - prevent data structures to cross 4k-byte boundary where required
0031  * - calculate tccb-related length fields
0032  * - optionally provide ready-made interrogate tcw and associated structures
0033  *
0034  * Restrictions apply to the itcws created with these construction functions:
0035  * - tida only supported for data address, not for tccb
0036  * - only contiguous tidaw-lists (no ttic)
0037  * - total number of bytes required per itcw may not exceed 4k bytes
0038  * - either read or write operation (may not work with r=0 and w=0)
0039  *
0040  * Example:
0041  * struct itcw *itcw;
0042  * void *buffer;
0043  * size_t size;
0044  *
0045  * size = itcw_calc_size(1, 2, 0);
0046  * buffer = kmalloc(size, GFP_KERNEL | GFP_DMA);
0047  * if (!buffer)
0048  *  return -ENOMEM;
0049  * itcw = itcw_init(buffer, size, ITCW_OP_READ, 1, 2, 0);
0050  * if (IS_ERR(itcw))
0051  *  return PTR_ER(itcw);
0052  * itcw_add_dcw(itcw, 0x2, 0, NULL, 0, 72);
0053  * itcw_add_tidaw(itcw, 0, 0x30000, 20);
0054  * itcw_add_tidaw(itcw, 0, 0x40000, 52);
0055  * itcw_finalize(itcw);
0056  *
0057  */
0058 struct itcw {
0059     struct tcw *tcw;
0060     struct tcw *intrg_tcw;
0061     int num_tidaws;
0062     int max_tidaws;
0063     int intrg_num_tidaws;
0064     int intrg_max_tidaws;
0065 };
0066 
0067 /**
0068  * itcw_get_tcw - return pointer to tcw associated with the itcw
0069  * @itcw: address of the itcw
0070  *
0071  * Return pointer to the tcw associated with the itcw.
0072  */
0073 struct tcw *itcw_get_tcw(struct itcw *itcw)
0074 {
0075     return itcw->tcw;
0076 }
0077 EXPORT_SYMBOL(itcw_get_tcw);
0078 
0079 /**
0080  * itcw_calc_size - return the size of an itcw with the given parameters
0081  * @intrg: if non-zero, add an interrogate tcw
0082  * @max_tidaws: maximum number of tidaws to be used for data addressing or zero
0083  * if no tida is to be used.
0084  * @intrg_max_tidaws: maximum number of tidaws to be used for data addressing
0085  * by the interrogate tcw, if specified
0086  *
0087  * Calculate and return the number of bytes required to hold an itcw with the
0088  * given parameters and assuming tccbs with maximum size.
0089  *
0090  * Note that the resulting size also contains bytes needed for alignment
0091  * padding as well as padding to ensure that data structures don't cross a
0092  * 4k-boundary where required.
0093  */
0094 size_t itcw_calc_size(int intrg, int max_tidaws, int intrg_max_tidaws)
0095 {
0096     size_t len;
0097     int cross_count;
0098 
0099     /* Main data. */
0100     len = sizeof(struct itcw);
0101     len += /* TCW */ sizeof(struct tcw) + /* TCCB */ TCCB_MAX_SIZE +
0102            /* TSB */ sizeof(struct tsb) +
0103            /* TIDAL */ max_tidaws * sizeof(struct tidaw);
0104     /* Interrogate data. */
0105     if (intrg) {
0106         len += /* TCW */ sizeof(struct tcw) + /* TCCB */ TCCB_MAX_SIZE +
0107                /* TSB */ sizeof(struct tsb) +
0108                /* TIDAL */ intrg_max_tidaws * sizeof(struct tidaw);
0109     }
0110 
0111     /* Maximum required alignment padding. */
0112     len += /* Initial TCW */ 63 + /* Interrogate TCCB */ 7;
0113 
0114     /* TIDAW lists may not cross a 4k boundary. To cross a
0115      * boundary we need to add a TTIC TIDAW. We need to reserve
0116      * one additional TIDAW for a TTIC that we may need to add due
0117      * to the placement of the data chunk in memory, and a further
0118      * TIDAW for each page boundary that the TIDAW list may cross
0119      * due to it's own size.
0120      */
0121     if (max_tidaws) {
0122         cross_count = 1 + ((max_tidaws * sizeof(struct tidaw) - 1)
0123                    >> PAGE_SHIFT);
0124         len += cross_count * sizeof(struct tidaw);
0125     }
0126     if (intrg_max_tidaws) {
0127         cross_count = 1 + ((intrg_max_tidaws * sizeof(struct tidaw) - 1)
0128                    >> PAGE_SHIFT);
0129         len += cross_count * sizeof(struct tidaw);
0130     }
0131     return len;
0132 }
0133 EXPORT_SYMBOL(itcw_calc_size);
0134 
0135 #define CROSS4K(x, l)   (((x) & ~4095) != ((x + l) & ~4095))
0136 
0137 static inline void *fit_chunk(addr_t *start, addr_t end, size_t len,
0138                   int align, int check_4k)
0139 {
0140     addr_t addr;
0141 
0142     addr = ALIGN(*start, align);
0143     if (check_4k && CROSS4K(addr, len)) {
0144         addr = ALIGN(addr, 4096);
0145         addr = ALIGN(addr, align);
0146     }
0147     if (addr + len > end)
0148         return ERR_PTR(-ENOSPC);
0149     *start = addr + len;
0150     return (void *) addr;
0151 }
0152 
0153 /**
0154  * itcw_init - initialize incremental tcw data structure
0155  * @buffer: address of buffer to use for data structures
0156  * @size: number of bytes in buffer
0157  * @op: %ITCW_OP_READ for a read operation tcw, %ITCW_OP_WRITE for a write
0158  * operation tcw
0159  * @intrg: if non-zero, add and initialize an interrogate tcw
0160  * @max_tidaws: maximum number of tidaws to be used for data addressing or zero
0161  * if no tida is to be used.
0162  * @intrg_max_tidaws: maximum number of tidaws to be used for data addressing
0163  * by the interrogate tcw, if specified
0164  *
0165  * Prepare the specified buffer to be used as an incremental tcw, i.e. a
0166  * helper data structure that can be used to construct a valid tcw by
0167  * successive calls to other helper functions. Note: the buffer needs to be
0168  * located below the 2G address limit. The resulting tcw has the following
0169  * restrictions:
0170  *  - no tccb tidal
0171  *  - input/output tidal is contiguous (no ttic)
0172  *  - total data should not exceed 4k
0173  *  - tcw specifies either read or write operation
0174  *
0175  * On success, return pointer to the resulting incremental tcw data structure,
0176  * ERR_PTR otherwise.
0177  */
0178 struct itcw *itcw_init(void *buffer, size_t size, int op, int intrg,
0179                int max_tidaws, int intrg_max_tidaws)
0180 {
0181     struct itcw *itcw;
0182     void *chunk;
0183     addr_t start;
0184     addr_t end;
0185     int cross_count;
0186 
0187     /* Check for 2G limit. */
0188     start = (addr_t) buffer;
0189     end = start + size;
0190     if (end > (1 << 31))
0191         return ERR_PTR(-EINVAL);
0192     memset(buffer, 0, size);
0193     /* ITCW. */
0194     chunk = fit_chunk(&start, end, sizeof(struct itcw), 1, 0);
0195     if (IS_ERR(chunk))
0196         return chunk;
0197     itcw = chunk;
0198     /* allow for TTIC tidaws that may be needed to cross a page boundary */
0199     cross_count = 0;
0200     if (max_tidaws)
0201         cross_count = 1 + ((max_tidaws * sizeof(struct tidaw) - 1)
0202                    >> PAGE_SHIFT);
0203     itcw->max_tidaws = max_tidaws + cross_count;
0204     cross_count = 0;
0205     if (intrg_max_tidaws)
0206         cross_count = 1 + ((intrg_max_tidaws * sizeof(struct tidaw) - 1)
0207                    >> PAGE_SHIFT);
0208     itcw->intrg_max_tidaws = intrg_max_tidaws + cross_count;
0209     /* Main TCW. */
0210     chunk = fit_chunk(&start, end, sizeof(struct tcw), 64, 0);
0211     if (IS_ERR(chunk))
0212         return chunk;
0213     itcw->tcw = chunk;
0214     tcw_init(itcw->tcw, (op == ITCW_OP_READ) ? 1 : 0,
0215          (op == ITCW_OP_WRITE) ? 1 : 0);
0216     /* Interrogate TCW. */
0217     if (intrg) {
0218         chunk = fit_chunk(&start, end, sizeof(struct tcw), 64, 0);
0219         if (IS_ERR(chunk))
0220             return chunk;
0221         itcw->intrg_tcw = chunk;
0222         tcw_init(itcw->intrg_tcw, 1, 0);
0223         tcw_set_intrg(itcw->tcw, itcw->intrg_tcw);
0224     }
0225     /* Data TIDAL. */
0226     if (max_tidaws > 0) {
0227         chunk = fit_chunk(&start, end, sizeof(struct tidaw) *
0228                   itcw->max_tidaws, 16, 0);
0229         if (IS_ERR(chunk))
0230             return chunk;
0231         tcw_set_data(itcw->tcw, chunk, 1);
0232     }
0233     /* Interrogate data TIDAL. */
0234     if (intrg && (intrg_max_tidaws > 0)) {
0235         chunk = fit_chunk(&start, end, sizeof(struct tidaw) *
0236                   itcw->intrg_max_tidaws, 16, 0);
0237         if (IS_ERR(chunk))
0238             return chunk;
0239         tcw_set_data(itcw->intrg_tcw, chunk, 1);
0240     }
0241     /* TSB. */
0242     chunk = fit_chunk(&start, end, sizeof(struct tsb), 8, 0);
0243     if (IS_ERR(chunk))
0244         return chunk;
0245     tsb_init(chunk);
0246     tcw_set_tsb(itcw->tcw, chunk);
0247     /* Interrogate TSB. */
0248     if (intrg) {
0249         chunk = fit_chunk(&start, end, sizeof(struct tsb), 8, 0);
0250         if (IS_ERR(chunk))
0251             return chunk;
0252         tsb_init(chunk);
0253         tcw_set_tsb(itcw->intrg_tcw, chunk);
0254     }
0255     /* TCCB. */
0256     chunk = fit_chunk(&start, end, TCCB_MAX_SIZE, 8, 0);
0257     if (IS_ERR(chunk))
0258         return chunk;
0259     tccb_init(chunk, TCCB_MAX_SIZE, TCCB_SAC_DEFAULT);
0260     tcw_set_tccb(itcw->tcw, chunk);
0261     /* Interrogate TCCB. */
0262     if (intrg) {
0263         chunk = fit_chunk(&start, end, TCCB_MAX_SIZE, 8, 0);
0264         if (IS_ERR(chunk))
0265             return chunk;
0266         tccb_init(chunk, TCCB_MAX_SIZE, TCCB_SAC_INTRG);
0267         tcw_set_tccb(itcw->intrg_tcw, chunk);
0268         tccb_add_dcw(chunk, TCCB_MAX_SIZE, DCW_CMD_INTRG, 0, NULL,
0269                  sizeof(struct dcw_intrg_data), 0);
0270         tcw_finalize(itcw->intrg_tcw, 0);
0271     }
0272     return itcw;
0273 }
0274 EXPORT_SYMBOL(itcw_init);
0275 
0276 /**
0277  * itcw_add_dcw - add a dcw to the itcw
0278  * @itcw: address of the itcw
0279  * @cmd: the dcw command
0280  * @flags: flags for the dcw
0281  * @cd: address of control data for this dcw or NULL if none is required
0282  * @cd_count: number of control data bytes for this dcw
0283  * @count: number of data bytes for this dcw
0284  *
0285  * Add a new dcw to the specified itcw by writing the dcw information specified
0286  * by @cmd, @flags, @cd, @cd_count and @count to the tca of the tccb. Return
0287  * a pointer to the newly added dcw on success or -%ENOSPC if the new dcw
0288  * would exceed the available space.
0289  *
0290  * Note: the tcal field of the tccb header will be updated to reflect added
0291  * content.
0292  */
0293 struct dcw *itcw_add_dcw(struct itcw *itcw, u8 cmd, u8 flags, void *cd,
0294              u8 cd_count, u32 count)
0295 {
0296     return tccb_add_dcw(tcw_get_tccb(itcw->tcw), TCCB_MAX_SIZE, cmd,
0297                 flags, cd, cd_count, count);
0298 }
0299 EXPORT_SYMBOL(itcw_add_dcw);
0300 
0301 /**
0302  * itcw_add_tidaw - add a tidaw to the itcw
0303  * @itcw: address of the itcw
0304  * @flags: flags for the new tidaw
0305  * @addr: address value for the new tidaw
0306  * @count: count value for the new tidaw
0307  *
0308  * Add a new tidaw to the input/output data tidaw-list of the specified itcw
0309  * (depending on the value of the r-flag and w-flag). Return a pointer to
0310  * the new tidaw on success or -%ENOSPC if the new tidaw would exceed the
0311  * available space.
0312  *
0313  * Note: TTIC tidaws are automatically added when needed, so explicitly calling
0314  * this interface with the TTIC flag is not supported. The last-tidaw flag
0315  * for the last tidaw in the list will be set by itcw_finalize.
0316  */
0317 struct tidaw *itcw_add_tidaw(struct itcw *itcw, u8 flags, void *addr, u32 count)
0318 {
0319     struct tidaw *following;
0320 
0321     if (itcw->num_tidaws >= itcw->max_tidaws)
0322         return ERR_PTR(-ENOSPC);
0323     /*
0324      * Is the tidaw, which follows the one we are about to fill, on the next
0325      * page? Then we have to insert a TTIC tidaw first, that points to the
0326      * tidaw on the new page.
0327      */
0328     following = ((struct tidaw *) tcw_get_data(itcw->tcw))
0329         + itcw->num_tidaws + 1;
0330     if (itcw->num_tidaws && !((unsigned long) following & ~PAGE_MASK)) {
0331         tcw_add_tidaw(itcw->tcw, itcw->num_tidaws++,
0332                   TIDAW_FLAGS_TTIC, following, 0);
0333         if (itcw->num_tidaws >= itcw->max_tidaws)
0334             return ERR_PTR(-ENOSPC);
0335     }
0336     return tcw_add_tidaw(itcw->tcw, itcw->num_tidaws++, flags, addr, count);
0337 }
0338 EXPORT_SYMBOL(itcw_add_tidaw);
0339 
0340 /**
0341  * itcw_set_data - set data address and tida flag of the itcw
0342  * @itcw: address of the itcw
0343  * @addr: the data address
0344  * @use_tidal: zero of the data address specifies a contiguous block of data,
0345  * non-zero if it specifies a list if tidaws.
0346  *
0347  * Set the input/output data address of the itcw (depending on the value of the
0348  * r-flag and w-flag). If @use_tidal is non-zero, the corresponding tida flag
0349  * is set as well.
0350  */
0351 void itcw_set_data(struct itcw *itcw, void *addr, int use_tidal)
0352 {
0353     tcw_set_data(itcw->tcw, addr, use_tidal);
0354 }
0355 EXPORT_SYMBOL(itcw_set_data);
0356 
0357 /**
0358  * itcw_finalize - calculate length and count fields of the itcw
0359  * @itcw: address of the itcw
0360  *
0361  * Calculate tcw input-/output-count and tccbl fields and add a tcat the tccb.
0362  * In case input- or output-tida is used, the tidaw-list must be stored in
0363  * continuous storage (no ttic). The tcal field in the tccb must be
0364  * up-to-date.
0365  */
0366 void itcw_finalize(struct itcw *itcw)
0367 {
0368     tcw_finalize(itcw->tcw, itcw->num_tidaws);
0369 }
0370 EXPORT_SYMBOL(itcw_finalize);