int main(int argc, char *argv[]) { // Open first AFU found struct cxl_afu_h *afu_h; afu_h = cxl_afu_next(NULL); if (!afu_h) { fprintf(stderr, "\nNo AFU found!\n\n"); return -1; } afu_h = cxl_afu_open_h(afu_h, CXL_VIEW_DEDICATED); if (!afu_h) { perror("cxl_afu_open_h"); return -1; } // Prepare WED struct wed *wed = NULL; if (posix_memalign((void **)&wed, CACHELINE_BYTES, sizeof(struct wed))) { perror("posix_memalign"); return -1; } printf("Allocated WED memory @ 0x%016" PRIx64 "\n", (uint64_t) wed); wed->endian_test = 1; wed->status = 0; // Start AFU cxl_afu_attach(afu_h, (uint64_t) wed); // Map AFU MMIO registers, if needed printf("Mapping AFU registers...\n"); if ((cxl_mmio_map(afu_h, CXL_MMIO_BIG_ENDIAN)) < 0) { perror("cxl_mmio_map"); return -1; } /************************************************************************** Do something here and wait for results. cxl_mmio_*() functions can only be used here between cxl_mmio_map and cxl_mmio_unmap. Presumably your application will possibly monitor and/or possibly update values in the wed struct or some other place in memory that AFU was informed that it could access. Maybe a bit in the wed struct like those in the example "status" field could be updated by the AFU to indicate that it has completed a job. In this example that is why the status field is made volatile. This prevents the compiler from optimization polling of the status field. **************************************************************************/ // Unmap AFU MMIO registers, if previously mapped cxl_mmio_unmap(afu_h); // Free AFU cxl_afu_free(afu_h); return 0; }
int main(int argc, char *argv[]) { struct cxl_afu_h *afu_h; uint64_t wed, wed_check, rand64, rand64_check; uint32_t rand32_upper, rand32_lower; unsigned seed; int opt, option_index; char *name; name = strrchr(argv[0], '/'); if (name) name++; else name = argv[0]; static struct option long_options[] = { {"help", no_argument, 0, 'h'}, {"seed", required_argument, 0, 's'}, {NULL, 0, 0, 0} }; option_index = 0; seed = time(NULL); while ((opt = getopt_long (argc, argv, "hs:", long_options, &option_index)) >= 0) { switch (opt) { case 0: break; case 's': seed = strtoul(optarg, NULL, 0); break; case 'h': default: usage(name); return 0; } } // Seed random number generator srand(seed); printf("%s: seed=%d\n", name, seed); // Find first AFU in system afu_h = cxl_afu_next(NULL); if (!afu_h) { fprintf(stderr, "FAILED:No AFU found!\n"); goto done; } // Open AFU afu_h = cxl_afu_open_h(afu_h, CXL_VIEW_DEDICATED); if (!afu_h) { perror("FAILED:cxl_afu_open_h"); goto done; } printf("Attempt mapping AFU registers before attach\n"); if ((cxl_mmio_map(afu_h, CXL_MMIO_BIG_ENDIAN)) == 0) { printf("FAILED:cxl_mmio_map"); goto done; } printf("Attempt mmio read before successful mapping\n"); if (cxl_mmio_read64(afu_h, 0x8, &wed_check) == 0) { printf("FAILED:cxl_mmio_read64"); goto done; } // Generate random 64-bit value for WED wed = rand(); wed <<= 32; wed |= rand(); // Start AFU passing random WED value cxl_afu_attach(afu_h, wed); // Map AFU MMIO registers printf("Mapping AFU registers...\n"); if ((cxl_mmio_map(afu_h, CXL_MMIO_BIG_ENDIAN)) < 0) { perror("FAILED:cxl_mmio_map"); goto done; } ///////////////////////////////////////////////////// // CHECK 1 - WED value was passed to AFU correctly // ///////////////////////////////////////////////////// // Read WED from AFU and verify if (cxl_mmio_read64(afu_h, 0x8, &wed_check) < 0) { perror("FAILED:cxl_mmio_read64"); goto done; } if (wed != wed_check) { printf("\nFAILED:WED mismatch!\n"); printf("\tExpected:0x%016"PRIx64"\n", wed); printf("\tActual :0x%016"PRIx64"\n", wed_check); goto done; } printf("WED check complete\n"); ////////////////////////////////////////////////////////////// // CHECK 2 - Write 64-bit value and check with 32-bit reads // ////////////////////////////////////////////////////////////// // Write random 64-bit value to MMIO space rand64 = rand(); rand64 <<= 32; rand64 |= rand(); if (cxl_mmio_write64(afu_h, 0x17f0, rand64) < 0) { perror("FAILED:cxl_mmio_write64"); goto done; } // Use two 32-bit read to check 64-bit value written if (cxl_mmio_read32(afu_h, 0x17f0, &rand32_upper) < 0) { perror("FAILED:cxl_mmio_read32"); goto done; } if (cxl_mmio_read32(afu_h, 0x17f4, &rand32_lower) < 0) { perror("FAILED:cxl_mmio_read32"); goto done; } rand64_check = (uint64_t) rand32_upper; rand64_check <<= 32; rand64_check |= (uint64_t) rand32_lower; if (rand64 != rand64_check) { printf("\nFAILED:64-bit write => 32-bit reads mismatch!\n"); printf("\tExpected:0x%016"PRIx64"\n", rand64); printf("\tActual :0x%016"PRIx64"\n", rand64_check); goto done; } printf("64-bit write => 32-bit reads check complete\n"); ////////////////////////////////////////////////////////////// // CHECK 3 - Write 32-bit values and check with 64-bit read // ////////////////////////////////////////////////////////////// // Write two random 32-bit values to a single 64-bit MMIO register rand32_upper = rand(); if (cxl_mmio_write32(afu_h, 0x17f8, rand32_upper) < 0) { perror("FAILED:cxl_mmio_write32"); goto done; } rand32_lower = rand(); if (cxl_mmio_write32(afu_h, 0x17fc, rand32_lower) < 0) { perror("FAILED:cxl_mmio_write32"); goto done; } // Build 64-bit value from two 32-bit values rand64 = (uint64_t) rand32_upper; rand64 <<= 32; rand64 |= (uint64_t) rand32_lower; // Check 32-bit writes with one 64-bit read if (cxl_mmio_read64(afu_h, 0x17f8, &rand64_check) < 0) { perror("FAILED:cxl_mmio_read64"); goto done; } if (rand64 != rand64_check) { printf("\nFAILED:32-bit writes => 64-bit read mismatch!\n"); printf("\tExpected:0x%016"PRIx64"\n", rand64); printf("\tActual :0x%016"PRIx64"\n", rand64_check); goto done; } printf("32-bit writes => 64-bit read check complete\n"); // Report test as passing printf("PASSED\n"); done: if (afu_h) { // Unmap AFU MMIO registers cxl_mmio_unmap(afu_h); // Free AFU cxl_afu_free(afu_h); } return 0; }
int main(int argc, char *argv[]) { #ifdef PSL9 MachineConfig machine; char *cacheline0, *cacheline1, *name; uint64_t wed; unsigned seed; int i, quadrant, byte, opt, option_index; int response; int context, machine_number; name = strrchr(argv[0], '/'); if (name) name++; else name = argv[0]; static struct option long_options[] = { {"help", no_argument, 0, 'h'}, {"seed", required_argument, 0, 's'}, {NULL, 0, 0, 0} }; option_index = 0; seed = time(NULL); while ((opt = getopt_long (argc, argv, "hs:", long_options, &option_index)) >= 0) { switch (opt) { case 0: break; case 's': seed = strtoul(optarg, NULL, 0); break; case 'h': default: usage(name); return 0; } } // Seed random number generator srand(seed); printf("%s: seed=%d\n", name, seed); // find first AFU found struct cxl_afu_h *afu_h, *afu_m, *afu_s; afu_m = afu_s = NULL; afu_h = cxl_afu_next(NULL); if (!afu_h) { fprintf(stderr, "\nNo AFU found!\n\n"); goto done; } // afu master afu_m = cxl_afu_open_h(afu_h, CXL_VIEW_MASTER); if (!afu_m) { perror("cxl_afu_open_h for master"); goto done; } // Set WED to random value wed = rand(); wed <<= 32; wed |= rand(); // Start AFU for master printf("Attach AFU master\n"); if (cxl_afu_attach(afu_m, wed) < 0) { perror("FAILED:cxl_afu_attach for master"); goto done; } printf("wed = 0x%"PRIx64"\n", wed); // Map AFU MMIO registers printf("Mapping AFU master registers...\n"); if ((cxl_mmio_map(afu_m, CXL_MMIO_BIG_ENDIAN)) < 0) { perror("cxl_mmio_map for master"); goto done; } printf("End AFU master mmio map\n"); context = cxl_afu_get_process_element(afu_m); printf("Master context = %d\n", context); // Allocate aligned memory for two cachelines if (posix_memalign((void **)&cacheline0, CACHELINE_BYTES, CACHELINE_BYTES) != 0) { perror("FAILED:posix_memalign"); goto done; } if (posix_memalign((void **)&cacheline1, CACHELINE_BYTES, CACHELINE_BYTES) != 0) { perror("FAILED:posix_memalign"); goto done; } // Pollute first cacheline with random values printf("CACHELINE0 = 0x"); for (i = 0; i < CACHELINE_BYTES; i++) { cacheline0[i] = rand(); printf("%02x", cacheline0[i]); } printf("\n"); // Initialize machine configuration printf("initialize machine\n"); init_machine(&machine); printf("End init machine\n"); // Use AFU Machine 0 to read the first cacheline from memory to AFU printf("Configure, enable and run machine\n"); if ((response = config_enable_and_run_machine(afu_m, &machine, 0, context, PSL_COMMAND_XLAT_RD_P0, CACHELINE_BYTES, 0, 0, (uint64_t)cacheline0, CACHELINE_BYTES, DIRECTED_M)) < 0) { printf("FAILED:config_enable_and_run_machine for master XLAT_RD response = %d\n", response); goto done; } printf("End configure enable and run machine for XLAT_RD\n"); // Check for valid response if (response != PSL_RESPONSE_DONE) { printf("FAILED: Unexpected response code 0x%x\n", response); goto done; } printf("Completed cacheline read\n"); // Use AFU Machine 0 to write the data to the second cacheline if ((response = config_enable_and_run_machine(afu_m, &machine, 0, context, PSL_COMMAND_XLAT_WR_P0, CACHELINE_BYTES, 0, 0, (uint64_t)cacheline1, CACHELINE_BYTES, DIRECTED_M)) < 0) { printf("FAILED:config_enable_and_run_machine for master XLAT_WR response = %d\n", response); goto done; } printf("End configure enable and run machine for XLAT WR\n"); // Check for valid response if (response != PSL_RESPONSE_DONE) { printf("FAILED: Unexpected response code 0x%x\n", response); goto done; } // Test if copy from cacheline0 to cacheline1 was successful if (memcmp(cacheline0,cacheline1, CACHELINE_BYTES) != 0) { printf("FAILED:memcmp\n"); for (quadrant = 0; quadrant < 4; quadrant++) { printf("DEBUG: Expected Q%d 0x", quadrant); for (byte = 0; byte < CACHELINE_BYTES /4; byte++) { printf("%02x", cacheline0[byte+(quadrant*32)]); } printf("\n"); } for (quadrant = 0; quadrant < 4; quadrant++) { printf("DEBUG: Actual Q%d 0x", quadrant); for (byte = 0; byte < CACHELINE_BYTES / 4; byte++) { printf("%02x", cacheline1[byte+(quadrant*32)]); } printf("\n"); } goto done; } printf("Master AFU: PASSED\n"); // afu slave // find next afu afu_h = cxl_afu_next(NULL); if (!afu_h) { fprintf(stderr, "\nNo AFU found!\n\n"); goto done; } afu_s = cxl_afu_open_h(afu_h, CXL_VIEW_SLAVE); if (!afu_s) { perror("cxl_afu_open_h for slave"); goto done; } // Set WED to random value wed = rand(); wed <<= 32; wed |= rand(); // Start AFU for slave if (cxl_afu_attach(afu_s, wed) < 0) { perror("FAILED:cxl_afu_attach for slave"); goto done; } // Map AFU MMIO registers printf("Mapping AFU slave registers...\n"); if ((cxl_mmio_map(afu_s, CXL_MMIO_BIG_ENDIAN)) < 0) { perror("cxl_mmio_map for slave"); goto done; } printf("End AFU slave mmio map\n"); context = cxl_afu_get_process_element(afu_s); printf("Slave context = %d\n", context); machine_number = 20; // Allocate aligned memory for two cachelines if (posix_memalign((void **)&cacheline0, CACHELINE_BYTES, CACHELINE_BYTES) != 0) { perror("FAILED:posix_memalign"); goto done; } if (posix_memalign((void **)&cacheline1, CACHELINE_BYTES, CACHELINE_BYTES) != 0) { perror("FAILED:posix_memalign"); goto done; } // Pollute first cacheline with random values for (i = 0; i < CACHELINE_BYTES; i++) cacheline0[i] = rand(); // Initialize machine configuration //init_machine(&machine); // Use AFU Machine 1 to read the first cacheline from memory to AFU printf("Start config enable and run machine for slave\n"); if ((response = config_enable_and_run_machine(afu_s, &machine, machine_number, context, PSL_COMMAND_XLAT_RD_P0, CACHELINE_BYTES, 0, 0, (uint64_t)cacheline0, CACHELINE_BYTES, DIRECTED)) < 0) { printf("FAILED:config_enable_and_run_machine for slave"); goto done; } printf("End config enable and run machine for slave\n"); // Check for valid response if (response != PSL_RESPONSE_DONE) { printf("FAILED: Unexpected response code 0x%x\n", response); goto done; } printf("Completed cacheline read for slave\n"); // Use AFU Machine 1 to write the data to the second cacheline if ((response = config_enable_and_run_machine(afu_s, &machine, machine_number, context, PSL_COMMAND_XLAT_WR_P0, CACHELINE_BYTES, 0, 0, (uint64_t)cacheline1, CACHELINE_BYTES, DIRECTED)) < 0) { printf("FAILED:config_enable_and_run_machine for slave"); goto done; } // Check for valid response if (response != PSL_RESPONSE_DONE) { printf("FAILED: Unexpected response code 0x%x\n", response); goto done; } // Test if copy from cacheline0 to cacheline1 was successful if (memcmp(cacheline0,cacheline1, CACHELINE_BYTES) != 0) { printf("FAILED:memcmp\n"); for (quadrant = 0; quadrant < 4; quadrant++) { printf("DEBUG: Expected Q%d 0x", quadrant); for (byte = 0; byte < CACHELINE_BYTES /4; byte++) { printf("%02x", cacheline0[byte+(quadrant*32)]); } printf("\n"); } for (quadrant = 0; quadrant < 4; quadrant++) { printf("DEBUG: Actual Q%d 0x", quadrant); for (byte = 0; byte < CACHELINE_BYTES / 4; byte++) { printf("%02x", cacheline1[byte+(quadrant*32)]); } printf("\n"); } goto done; } printf("Slave AFU: PASSED\n"); done: // unmap and free slave afu if (afu_s) { cxl_mmio_unmap(afu_s); cxl_afu_free(afu_s); } // unmap and free master afu if (afu_m) { // Unmap AFU MMIO registers cxl_mmio_unmap(afu_m); // Free AFU cxl_afu_free(afu_m); } #endif return 0; }