149ef06a4Smrg/* 249ef06a4Smrg * Copyright 2021 Advanced Micro Devices, Inc. 349ef06a4Smrg * 449ef06a4Smrg * Permission is hereby granted, free of charge, to any person obtaining a 549ef06a4Smrg * copy of this software and associated documentation files (the "Software"), 649ef06a4Smrg * to deal in the Software without restriction, including without limitation 749ef06a4Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 849ef06a4Smrg * and/or sell copies of the Software, and to permit persons to whom the 949ef06a4Smrg * Software is furnished to do so, subject to the following conditions: 1049ef06a4Smrg * 1149ef06a4Smrg * The above copyright notice and this permission notice shall be included in 1249ef06a4Smrg * all copies or substantial portions of the Software. 1349ef06a4Smrg * 1449ef06a4Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1549ef06a4Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1649ef06a4Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1749ef06a4Smrg * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 1849ef06a4Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 1949ef06a4Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 2049ef06a4Smrg * OTHER DEALINGS IN THE SOFTWARE. 2149ef06a4Smrg * 2249ef06a4Smrg*/ 2349ef06a4Smrg 2449ef06a4Smrg#include <stdio.h> 2549ef06a4Smrg#include <sys/types.h> 2649ef06a4Smrg#include <sys/stat.h> 2749ef06a4Smrg#include <fcntl.h> 2849ef06a4Smrg#include <stdarg.h> 2949ef06a4Smrg#include <string.h> 3049ef06a4Smrg#include <errno.h> 3149ef06a4Smrg#include <unistd.h> 3249ef06a4Smrg#include <stdlib.h> 33bbff01ceSmrg#include <inttypes.h> 3449ef06a4Smrg 3549ef06a4Smrg#include "drm.h" 3649ef06a4Smrg#include "xf86drmMode.h" 3749ef06a4Smrg#include "xf86drm.h" 3849ef06a4Smrg#include "amdgpu.h" 3949ef06a4Smrg#include "amdgpu_drm.h" 4049ef06a4Smrg#include "amdgpu_internal.h" 4149ef06a4Smrg 4249ef06a4Smrg#define MAX_CARDS_SUPPORTED 4 4349ef06a4Smrg#define NUM_BUFFER_OBJECTS 1024 4449ef06a4Smrg 4549ef06a4Smrg#define SDMA_PACKET(op, sub_op, e) ((((e) & 0xFFFF) << 16) | \ 4649ef06a4Smrg (((sub_op) & 0xFF) << 8) | \ 4749ef06a4Smrg (((op) & 0xFF) << 0)) 4849ef06a4Smrg 4949ef06a4Smrg#define SDMA_OPCODE_COPY 1 5049ef06a4Smrg# define SDMA_COPY_SUB_OPCODE_LINEAR 0 5149ef06a4Smrg 5249ef06a4Smrg 5349ef06a4Smrg#define SDMA_PACKET_SI(op, b, t, s, cnt) ((((op) & 0xF) << 28) | \ 5449ef06a4Smrg (((b) & 0x1) << 26) | \ 5549ef06a4Smrg (((t) & 0x1) << 23) | \ 5649ef06a4Smrg (((s) & 0x1) << 22) | \ 5749ef06a4Smrg (((cnt) & 0xFFFFF) << 0)) 5849ef06a4Smrg#define SDMA_OPCODE_COPY_SI 3 5949ef06a4Smrg 6049ef06a4Smrg 6149ef06a4Smrg/** Help string for command line parameters */ 6249ef06a4Smrgstatic const char usage[] = 6349ef06a4Smrg "Usage: %s [-?h] [-b v|g|vg size] " 6449ef06a4Smrg "[-c from to size count]\n" 6549ef06a4Smrg "where:\n" 6649ef06a4Smrg " b - Allocate a BO in VRAM, GTT or VRAM|GTT of size bytes.\n" 6749ef06a4Smrg " This flag can be used multiple times. The first bo will\n" 6849ef06a4Smrg " have id `1`, then second id `2`, ...\n" 6949ef06a4Smrg " c - Copy size bytes from BO (bo_id1) to BO (bo_id2), count times\n" 7049ef06a4Smrg " h - Display this help\n" 7149ef06a4Smrg "\n" 7249ef06a4Smrg "Sizes can be postfixes with k, m or g for kilo, mega and gigabyte scaling\n"; 7349ef06a4Smrg 7449ef06a4Smrg/** Specified options strings for getopt */ 7549ef06a4Smrgstatic const char options[] = "?hb:c:"; 7649ef06a4Smrg 7749ef06a4Smrg/* Open AMD devices. 7849ef06a4Smrg * Returns the fd of the first device it could open. 7949ef06a4Smrg */ 8049ef06a4Smrgstatic int amdgpu_open_device(void) 8149ef06a4Smrg{ 8249ef06a4Smrg drmDevicePtr devices[MAX_CARDS_SUPPORTED]; 8349ef06a4Smrg unsigned int i; 8449ef06a4Smrg int drm_count; 8549ef06a4Smrg 8649ef06a4Smrg drm_count = drmGetDevices2(0, devices, MAX_CARDS_SUPPORTED); 8749ef06a4Smrg if (drm_count < 0) { 8849ef06a4Smrg fprintf(stderr, "drmGetDevices2() returned an error %d\n", 8949ef06a4Smrg drm_count); 9049ef06a4Smrg return drm_count; 9149ef06a4Smrg } 9249ef06a4Smrg 9349ef06a4Smrg for (i = 0; i < drm_count; i++) { 9449ef06a4Smrg drmVersionPtr version; 9549ef06a4Smrg int fd; 9649ef06a4Smrg 9749ef06a4Smrg /* If this is not PCI device, skip*/ 9849ef06a4Smrg if (devices[i]->bustype != DRM_BUS_PCI) 9949ef06a4Smrg continue; 10049ef06a4Smrg 10149ef06a4Smrg /* If this is not AMD GPU vender ID, skip*/ 10249ef06a4Smrg if (devices[i]->deviceinfo.pci->vendor_id != 0x1002) 10349ef06a4Smrg continue; 10449ef06a4Smrg 10549ef06a4Smrg if (!(devices[i]->available_nodes & 1 << DRM_NODE_RENDER)) 10649ef06a4Smrg continue; 10749ef06a4Smrg 10849ef06a4Smrg fd = open(devices[i]->nodes[DRM_NODE_RENDER], O_RDWR | O_CLOEXEC); 10949ef06a4Smrg 11049ef06a4Smrg /* This node is not available. */ 11149ef06a4Smrg if (fd < 0) continue; 11249ef06a4Smrg 11349ef06a4Smrg version = drmGetVersion(fd); 11449ef06a4Smrg if (!version) { 11549ef06a4Smrg fprintf(stderr, 11649ef06a4Smrg "Warning: Cannot get version for %s." 11749ef06a4Smrg "Error is %s\n", 11849ef06a4Smrg devices[i]->nodes[DRM_NODE_RENDER], 11949ef06a4Smrg strerror(errno)); 12049ef06a4Smrg close(fd); 12149ef06a4Smrg continue; 12249ef06a4Smrg } 12349ef06a4Smrg 12449ef06a4Smrg if (strcmp(version->name, "amdgpu")) { 12549ef06a4Smrg /* This is not AMDGPU driver, skip.*/ 12649ef06a4Smrg drmFreeVersion(version); 12749ef06a4Smrg close(fd); 12849ef06a4Smrg continue; 12949ef06a4Smrg } 13049ef06a4Smrg 13149ef06a4Smrg drmFreeVersion(version); 13249ef06a4Smrg drmFreeDevices(devices, drm_count); 13349ef06a4Smrg return fd; 13449ef06a4Smrg } 13549ef06a4Smrg 13649ef06a4Smrg return -1; 13749ef06a4Smrg} 13849ef06a4Smrg 13949ef06a4Smrgamdgpu_device_handle device_handle; 14049ef06a4Smrgamdgpu_context_handle context_handle; 14149ef06a4Smrg 14249ef06a4Smrgamdgpu_bo_handle resources[NUM_BUFFER_OBJECTS]; 14349ef06a4Smrguint64_t virtual[NUM_BUFFER_OBJECTS]; 14449ef06a4Smrgunsigned int num_buffers; 14549ef06a4Smrguint32_t *pm4; 14649ef06a4Smrg 14749ef06a4Smrgint alloc_bo(uint32_t domain, uint64_t size) 14849ef06a4Smrg{ 14949ef06a4Smrg struct amdgpu_bo_alloc_request request = {}; 15049ef06a4Smrg amdgpu_bo_handle bo; 15149ef06a4Smrg amdgpu_va_handle va; 15249ef06a4Smrg uint64_t addr; 15349ef06a4Smrg int r; 15449ef06a4Smrg 15549ef06a4Smrg if (num_buffers >= NUM_BUFFER_OBJECTS) 15649ef06a4Smrg return -ENOSPC; 15749ef06a4Smrg 15849ef06a4Smrg request.alloc_size = size; 15949ef06a4Smrg request.phys_alignment = 0; 16049ef06a4Smrg request.preferred_heap = domain; 16149ef06a4Smrg request.flags = 0; 16249ef06a4Smrg r = amdgpu_bo_alloc(device_handle, &request, &bo); 16349ef06a4Smrg if (r) 16449ef06a4Smrg return r; 16549ef06a4Smrg 16649ef06a4Smrg r = amdgpu_va_range_alloc(device_handle, amdgpu_gpu_va_range_general, 16749ef06a4Smrg size, 0, 0, &addr, &va, 0); 16849ef06a4Smrg if (r) 16949ef06a4Smrg return r; 17049ef06a4Smrg 17149ef06a4Smrg r = amdgpu_bo_va_op_raw(device_handle, bo, 0, size, addr, 17249ef06a4Smrg AMDGPU_VM_PAGE_READABLE | AMDGPU_VM_PAGE_WRITEABLE | 17349ef06a4Smrg AMDGPU_VM_PAGE_EXECUTABLE, AMDGPU_VA_OP_MAP); 17449ef06a4Smrg if (r) 17549ef06a4Smrg return r; 17649ef06a4Smrg 17749ef06a4Smrg resources[num_buffers] = bo; 17849ef06a4Smrg virtual[num_buffers] = addr; 179bbff01ceSmrg fprintf(stdout, "Allocated BO number %u at 0x%" PRIx64 ", domain 0x%x, size %" PRIu64 "\n", 18049ef06a4Smrg num_buffers++, addr, domain, size); 18149ef06a4Smrg return 0; 18249ef06a4Smrg} 18349ef06a4Smrg 18449ef06a4Smrgint submit_ib(uint32_t from, uint32_t to, uint64_t size, uint32_t count) 18549ef06a4Smrg{ 18649ef06a4Smrg struct amdgpu_cs_request ibs_request; 18749ef06a4Smrg struct amdgpu_cs_fence fence_status; 18849ef06a4Smrg struct amdgpu_cs_ib_info ib_info; 18949ef06a4Smrg uint64_t copied = size, delta; 19049ef06a4Smrg struct timespec start, stop; 19149ef06a4Smrg 19249ef06a4Smrg uint64_t src = virtual[from]; 19349ef06a4Smrg uint64_t dst = virtual[to]; 19449ef06a4Smrg uint32_t expired; 19549ef06a4Smrg int i, r; 19649ef06a4Smrg 19749ef06a4Smrg i = 0; 19849ef06a4Smrg while (size) { 19949ef06a4Smrg uint64_t bytes = size < 0x40000 ? size : 0x40000; 20049ef06a4Smrg 20149ef06a4Smrg if (device_handle->info.family_id == AMDGPU_FAMILY_SI) { 20249ef06a4Smrg pm4[i++] = SDMA_PACKET_SI(SDMA_OPCODE_COPY_SI, 0, 0, 0, 20349ef06a4Smrg bytes); 20449ef06a4Smrg pm4[i++] = 0xffffffff & dst; 20549ef06a4Smrg pm4[i++] = 0xffffffff & src; 20649ef06a4Smrg pm4[i++] = (0xffffffff00000000 & dst) >> 32; 20749ef06a4Smrg pm4[i++] = (0xffffffff00000000 & src) >> 32; 20849ef06a4Smrg } else { 20949ef06a4Smrg pm4[i++] = SDMA_PACKET(SDMA_OPCODE_COPY, 21049ef06a4Smrg SDMA_COPY_SUB_OPCODE_LINEAR, 21149ef06a4Smrg 0); 21249ef06a4Smrg if ( device_handle->info.family_id >= AMDGPU_FAMILY_AI) 21349ef06a4Smrg pm4[i++] = bytes - 1; 21449ef06a4Smrg else 21549ef06a4Smrg pm4[i++] = bytes; 21649ef06a4Smrg pm4[i++] = 0; 21749ef06a4Smrg pm4[i++] = 0xffffffff & src; 21849ef06a4Smrg pm4[i++] = (0xffffffff00000000 & src) >> 32; 21949ef06a4Smrg pm4[i++] = 0xffffffff & dst; 22049ef06a4Smrg pm4[i++] = (0xffffffff00000000 & dst) >> 32; 22149ef06a4Smrg } 22249ef06a4Smrg 22349ef06a4Smrg size -= bytes; 22449ef06a4Smrg src += bytes; 22549ef06a4Smrg dst += bytes; 22649ef06a4Smrg } 22749ef06a4Smrg 22849ef06a4Smrg memset(&ib_info, 0, sizeof(ib_info)); 22949ef06a4Smrg ib_info.ib_mc_address = virtual[0]; 23049ef06a4Smrg ib_info.size = i; 23149ef06a4Smrg 23249ef06a4Smrg memset(&ibs_request, 0, sizeof(ibs_request)); 23349ef06a4Smrg ibs_request.ip_type = AMDGPU_HW_IP_DMA; 23449ef06a4Smrg ibs_request.ring = 0; 23549ef06a4Smrg ibs_request.number_of_ibs = 1; 23649ef06a4Smrg ibs_request.ibs = &ib_info; 23749ef06a4Smrg ibs_request.fence_info.handle = NULL; 23849ef06a4Smrg 23949ef06a4Smrg r = clock_gettime(CLOCK_MONOTONIC, &start); 24049ef06a4Smrg if (r) 24149ef06a4Smrg return errno; 24249ef06a4Smrg 24349ef06a4Smrg r = amdgpu_bo_list_create(device_handle, num_buffers, resources, NULL, 24449ef06a4Smrg &ibs_request.resources); 24549ef06a4Smrg if (r) 24649ef06a4Smrg return r; 24749ef06a4Smrg 24849ef06a4Smrg for (i = 0; i < count; ++i) { 24949ef06a4Smrg r = amdgpu_cs_submit(context_handle, 0, &ibs_request, 1); 25049ef06a4Smrg if (r) 25149ef06a4Smrg return r; 25249ef06a4Smrg } 25349ef06a4Smrg 25449ef06a4Smrg r = amdgpu_bo_list_destroy(ibs_request.resources); 25549ef06a4Smrg if (r) 25649ef06a4Smrg return r; 25749ef06a4Smrg 25849ef06a4Smrg memset(&fence_status, 0, sizeof(fence_status)); 25949ef06a4Smrg fence_status.ip_type = ibs_request.ip_type; 26049ef06a4Smrg fence_status.ip_instance = 0; 26149ef06a4Smrg fence_status.ring = ibs_request.ring; 26249ef06a4Smrg fence_status.context = context_handle; 26349ef06a4Smrg fence_status.fence = ibs_request.seq_no; 26449ef06a4Smrg r = amdgpu_cs_query_fence_status(&fence_status, 26549ef06a4Smrg AMDGPU_TIMEOUT_INFINITE, 26649ef06a4Smrg 0, &expired); 26749ef06a4Smrg if (r) 26849ef06a4Smrg return r; 26949ef06a4Smrg 27049ef06a4Smrg r = clock_gettime(CLOCK_MONOTONIC, &stop); 27149ef06a4Smrg if (r) 27249ef06a4Smrg return errno; 27349ef06a4Smrg 27449ef06a4Smrg delta = stop.tv_nsec + stop.tv_sec * 1000000000UL; 27549ef06a4Smrg delta -= start.tv_nsec + start.tv_sec * 1000000000UL; 27649ef06a4Smrg 277bbff01ceSmrg fprintf(stdout, "Submitted %u IBs to copy from %u(%" PRIx64 ") to %u(%" PRIx64 ") %" PRIu64 " bytes took %" PRIu64 " usec\n", 27849ef06a4Smrg count, from, virtual[from], to, virtual[to], copied, delta / 1000); 27949ef06a4Smrg return 0; 28049ef06a4Smrg} 28149ef06a4Smrg 28249ef06a4Smrgvoid next_arg(int argc, char **argv, const char *msg) 28349ef06a4Smrg{ 28449ef06a4Smrg optarg = argv[optind++]; 28549ef06a4Smrg if (optind > argc || optarg[0] == '-') { 28649ef06a4Smrg fprintf(stderr, "%s\n", msg); 28749ef06a4Smrg exit(EXIT_FAILURE); 28849ef06a4Smrg } 28949ef06a4Smrg} 29049ef06a4Smrg 29149ef06a4Smrguint64_t parse_size(void) 29249ef06a4Smrg{ 29349ef06a4Smrg uint64_t size; 29449ef06a4Smrg char ext[2]; 29549ef06a4Smrg 29649ef06a4Smrg ext[0] = 0; 297bbff01ceSmrg if (sscanf(optarg, "%" PRIi64 "%1[kmgKMG]", &size, ext) < 1) { 29849ef06a4Smrg fprintf(stderr, "Can't parse size arg: %s\n", optarg); 29949ef06a4Smrg exit(EXIT_FAILURE); 30049ef06a4Smrg } 30149ef06a4Smrg switch (ext[0]) { 30249ef06a4Smrg case 'k': 30349ef06a4Smrg case 'K': 30449ef06a4Smrg size *= 1024; 30549ef06a4Smrg break; 30649ef06a4Smrg case 'm': 30749ef06a4Smrg case 'M': 30849ef06a4Smrg size *= 1024 * 1024; 30949ef06a4Smrg break; 31049ef06a4Smrg case 'g': 31149ef06a4Smrg case 'G': 31249ef06a4Smrg size *= 1024 * 1024 * 1024; 31349ef06a4Smrg break; 31449ef06a4Smrg default: 31549ef06a4Smrg break; 31649ef06a4Smrg } 31749ef06a4Smrg return size; 31849ef06a4Smrg} 31949ef06a4Smrg 32049ef06a4Smrgint main(int argc, char **argv) 32149ef06a4Smrg{ 32249ef06a4Smrg uint32_t major_version, minor_version; 32349ef06a4Smrg uint32_t domain, from, to, count; 32449ef06a4Smrg uint64_t size; 32549ef06a4Smrg int fd, r, c; 32649ef06a4Smrg 32749ef06a4Smrg fd = amdgpu_open_device(); 32849ef06a4Smrg if (fd < 0) { 32949ef06a4Smrg perror("Cannot open AMDGPU device"); 33049ef06a4Smrg exit(EXIT_FAILURE); 33149ef06a4Smrg } 33249ef06a4Smrg 33349ef06a4Smrg r = amdgpu_device_initialize(fd, &major_version, &minor_version, &device_handle); 33449ef06a4Smrg if (r) { 33549ef06a4Smrg fprintf(stderr, "amdgpu_device_initialize returned %d\n", r); 33649ef06a4Smrg exit(EXIT_FAILURE); 33749ef06a4Smrg } 33849ef06a4Smrg 33949ef06a4Smrg r = amdgpu_cs_ctx_create(device_handle, &context_handle); 34049ef06a4Smrg if (r) { 34149ef06a4Smrg fprintf(stderr, "amdgpu_cs_ctx_create returned %d\n", r); 34249ef06a4Smrg exit(EXIT_FAILURE); 34349ef06a4Smrg } 34449ef06a4Smrg 34549ef06a4Smrg if (argc == 1) { 34649ef06a4Smrg fprintf(stderr, usage, argv[0]); 34749ef06a4Smrg exit(EXIT_FAILURE); 34849ef06a4Smrg } 34949ef06a4Smrg 35049ef06a4Smrg r = alloc_bo(AMDGPU_GEM_DOMAIN_GTT, 2ULL * 1024 * 1024); 35149ef06a4Smrg if (r) { 35249ef06a4Smrg fprintf(stderr, "Buffer allocation failed with %d\n", r); 35349ef06a4Smrg exit(EXIT_FAILURE); 35449ef06a4Smrg } 35549ef06a4Smrg 35649ef06a4Smrg r = amdgpu_bo_cpu_map(resources[0], (void **)&pm4); 35749ef06a4Smrg if (r) { 35849ef06a4Smrg fprintf(stderr, "Buffer mapping failed with %d\n", r); 35949ef06a4Smrg exit(EXIT_FAILURE); 36049ef06a4Smrg } 36149ef06a4Smrg 36249ef06a4Smrg opterr = 0; 36349ef06a4Smrg while ((c = getopt(argc, argv, options)) != -1) { 36449ef06a4Smrg switch (c) { 36549ef06a4Smrg case 'b': 36649ef06a4Smrg if (!strcmp(optarg, "v")) 36749ef06a4Smrg domain = AMDGPU_GEM_DOMAIN_VRAM; 36849ef06a4Smrg else if (!strcmp(optarg, "g")) 36949ef06a4Smrg domain = AMDGPU_GEM_DOMAIN_GTT; 37049ef06a4Smrg else if (!strcmp(optarg, "vg")) 37149ef06a4Smrg domain = AMDGPU_GEM_DOMAIN_VRAM | AMDGPU_GEM_DOMAIN_GTT; 37249ef06a4Smrg else { 37349ef06a4Smrg fprintf(stderr, "Invalid domain: %s\n", optarg); 37449ef06a4Smrg exit(EXIT_FAILURE); 37549ef06a4Smrg } 37649ef06a4Smrg next_arg(argc, argv, "Missing buffer size"); 37749ef06a4Smrg size = parse_size(); 37849ef06a4Smrg if (size < getpagesize()) { 379bbff01ceSmrg fprintf(stderr, "Buffer size to small %" PRIu64 "\n", size); 38049ef06a4Smrg exit(EXIT_FAILURE); 38149ef06a4Smrg } 38249ef06a4Smrg r = alloc_bo(domain, size); 38349ef06a4Smrg if (r) { 38449ef06a4Smrg fprintf(stderr, "Buffer allocation failed with %d\n", r); 38549ef06a4Smrg exit(EXIT_FAILURE); 38649ef06a4Smrg } 38749ef06a4Smrg break; 38849ef06a4Smrg case 'c': 38949ef06a4Smrg if (sscanf(optarg, "%u", &from) != 1) { 39049ef06a4Smrg fprintf(stderr, "Can't parse from buffer: %s\n", optarg); 39149ef06a4Smrg exit(EXIT_FAILURE); 39249ef06a4Smrg } 39349ef06a4Smrg next_arg(argc, argv, "Missing to buffer"); 39449ef06a4Smrg if (sscanf(optarg, "%u", &to) != 1) { 39549ef06a4Smrg fprintf(stderr, "Can't parse to buffer: %s\n", optarg); 39649ef06a4Smrg exit(EXIT_FAILURE); 39749ef06a4Smrg } 39849ef06a4Smrg next_arg(argc, argv, "Missing size"); 39949ef06a4Smrg size = parse_size(); 40049ef06a4Smrg next_arg(argc, argv, "Missing count"); 40149ef06a4Smrg count = parse_size(); 40249ef06a4Smrg r = submit_ib(from, to, size, count); 40349ef06a4Smrg if (r) { 40449ef06a4Smrg fprintf(stderr, "IB submission failed with %d\n", r); 40549ef06a4Smrg exit(EXIT_FAILURE); 40649ef06a4Smrg } 40749ef06a4Smrg break; 40849ef06a4Smrg case '?': 40949ef06a4Smrg case 'h': 41049ef06a4Smrg fprintf(stderr, usage, argv[0]); 41149ef06a4Smrg exit(EXIT_SUCCESS); 41249ef06a4Smrg default: 41349ef06a4Smrg fprintf(stderr, usage, argv[0]); 41449ef06a4Smrg exit(EXIT_FAILURE); 41549ef06a4Smrg } 41649ef06a4Smrg } 41749ef06a4Smrg 41849ef06a4Smrg return EXIT_SUCCESS; 41949ef06a4Smrg} 420