Example #1
0
uint8_t * get_afu_psa_addr(char * i_afu_path) {
    /*------------------------------------------------------------------------*/
    /*  Local Variables                                                       */
    /*------------------------------------------------------------------------*/
    struct cxl_afu_h * afu_master_h = NULL;
    int afu_master_fd = 0;
    uint8_t * afu_psa_addr = NULL;

    /*------------------------------------------------------------------------*/
    /*  Code                                                                  */
    /*------------------------------------------------------------------------*/
    if ((afu_master_h = cxl_afu_open_dev(i_afu_path)) < 0) {
        TRACEE("Unable to open AFU Master cxl device. errno = %d (%s).\n",
               errno, strerror(errno));
        return NULL;
    }

    TRACEI("Opened %p, now attempting to get FD.\n", afu_master_h);
    afu_master_fd = cxl_afu_fd(afu_master_h);
    TRACEI("Got FD! = %d\n", afu_master_fd);

    if (cxl_afu_attach(afu_master_h, 0)) {
        TRACEE("Call to cxl_afu_attach failed. errno = %d (%s)\n",
               errno, strerror(errno));
        return NULL;
    }

    afu_psa_addr = mmap_afu_registers(afu_master_fd);

    if (!afu_psa_addr) {
        TRACEE("Error attempting to map AFU problem state registers. \
            errno = %d (%s)\n", errno, strerror(errno));
        return NULL;
    }
Example #2
0
/*
 * Open AFU Master Device
 */
static int afu_m_open(struct mdev_ctx *mctx)
{
	int rc = 0;
	char device[64];
	long api_version, cr_device, cr_vendor;

	sprintf(device, "/dev/cxl/afu%d.0m", mctx->card);
	VERBOSE3("[%s] Enter, Open Device: %s\n", __func__, device);
	mctx->afu_h = cxl_afu_open_dev(device);
	if (NULL == mctx->afu_h) {
		VERBOSE0("[%s] Exit, Card Open error rc: %d\n", __func__, rc);
		return -1;
	}

	/* Check if the compiled in API version is compatible with the
	   one reported by the kernel driver */
	rc = cxl_get_api_version_compatible(mctx->afu_h, &api_version);
	if ((rc != 0) || (api_version != CXL_KERNEL_API_VERSION)) {
		VERBOSE0(" [%s] ERR: incompatible API version: %ld/%d rc=%d\n",
			 __func__, api_version, CXL_KERNEL_API_VERSION, rc);
		rc = -2;
		goto err_afu_free;
	}

	/* Check vendor id */
	rc = cxl_get_cr_vendor(mctx->afu_h, 0, &cr_vendor);
	if ((rc != 0) || (cr_vendor != CGZIP_CR_VENDOR)) {
		VERBOSE0(" [%s] ERR: vendor_id: %ld/%d rc=%d\n",
			 __func__, (unsigned long)cr_vendor,
			 CGZIP_CR_VENDOR, rc);
		rc = -3;
		goto err_afu_free;
	}

	/* Check device id */
	rc = cxl_get_cr_device(mctx->afu_h, 0, &cr_device);
	if ((rc != 0) || (cr_device != CGZIP_CR_DEVICE)) {
		VERBOSE0(" [%s] ERR: device_id: %ld/%d rc=%d\n",
			 __func__, (unsigned long)cr_device,
			 CGZIP_CR_VENDOR, rc);
		rc = -4;
		goto err_afu_free;
	}

	/* If we cannot get it, continue with warning ... */
	mctx->errinfo = NULL;
	rc = cxl_errinfo_size(mctx->afu_h, &mctx->errinfo_size);
	if (0 == rc) {
		mctx->errinfo = malloc(mctx->errinfo_size);
		if (mctx->errinfo == NULL) {
			rc = -5;
			goto err_afu_free;
		}
	} else
		VERBOSE0(" [%s] WARN: Cannot retrieve errinfo size rc=%d\n",
			 __func__, rc);

	rc = cxl_afu_attach(mctx->afu_h, (__u64)(unsigned long)
			    (void *)mctx->wed);
	if (0 != rc) {
		rc = -6;
		goto err_free_errinfo;
	}

	rc = cxl_mmio_map(mctx->afu_h, CXL_MMIO_BIG_ENDIAN);
	if (rc != 0) {
		rc = -7;
		goto err_free_errinfo;
	}

	return 0;

 err_free_errinfo:
	if (mctx->errinfo)
		free(mctx->errinfo);
	mctx->errinfo = NULL;
 err_afu_free:
	cxl_afu_free(mctx->afu_h);
	mctx->afu_h = NULL;
	VERBOSE3("[%s] Exit rc=%d\n", __func__, rc);
	return rc;
}
Example #3
0
bool initialize_wwpn(char* i_afu_path, const AFU_PORT_ID i_port, const uint64_t i_wwpn)
{
    //Locals
	struct cxl_afu_h *afu_master_h = NULL;
	int afu_master_fd = 0;
	uint8_t *afu_psa_addr = NULL;
    uint32_t mmio_data32 = 0;
    uint64_t mmio_data = 0;
    int l_fc_port_offset = 0; //todo: replace all references with "l_fc_port_offset"
    bool l_rc = 0;
    
    //Code
    do
    {
        if(i_port >= MAX_WWPNS_PER_ADAPTER)
        {
            TRACEE("Port number %d is not a valid port number. We only support up to %d numbers.\n", i_port, MAX_WWPNS_PER_ADAPTER);
            l_rc = false;
            break;
        }
        if(i_wwpn == 0)
        {
            TRACEE("WWPN for %s port %d is zero and therefore invalid.\n", i_afu_path, i_port);
            l_rc = false;
            break;
        }
        
        l_fc_port_offset = FC_PORT_BASE_OFFSET + (i_port * FC_PORT_REG_SIZE);
        TRACEV("Target reg bank for port %d = 0x%08x\n",i_port, l_fc_port_offset);
        
        TRACEI("Attempting to open device '%s'\n", i_afu_path);
        
        /* now that the AFU is started, lets set config options */
        if ((afu_master_h = cxl_afu_open_dev(i_afu_path)) < 0) {
            TRACEE("Unable to open AFU Master cxl device. errno = %d (%s)\n", errno, strerror(errno));
            l_rc = false;
            break;
        }
        TRACEV("Opened %p, now attempting to get FD\n", afu_master_h);
        afu_master_fd = cxl_afu_fd(afu_master_h);
        TRACEV("Got FD! = %d\n", afu_master_fd);
        
        if (cxl_afu_attach(afu_master_h,
                           0)) //no WEQ needed
        {
            TRACEE("Call to cxl_afu_attach failed. errno = %d (%s)\n", errno, strerror(errno));
            l_rc = false;
            break;
        }
        
        
        afu_psa_addr = mmap_afu_wwpn_registers(afu_master_fd);
        if (!afu_psa_addr) {
            TRACEE("Error attempting to map AFU problem state registers. errno = %d (%s)\n", errno, strerror(errno));
            l_rc = -1;
            break;
        }
        
        //Take port offline
        
        //TRACED("Bringing port offline\n");

        
        //get status bits for debug
        //TODO: maybe wrap up this print into a nice macro...
        mmio_data32 = in_mmio32((__u64*)&afu_psa_addr[FC_MTIP_STATUS + l_fc_port_offset]);
        TRACEV("FC_MTIP_STATUS    (0x%08X): 0x%08X\n", FC_MTIP_STATUS + l_fc_port_offset, mmio_data32);
        mmio_data32 = in_mmio32((__u64*)&afu_psa_addr[FC_MTIP_CMDCONFIG + l_fc_port_offset]);
        TRACEV("FC_MTIP_CMDCONFIG (0x%08X): 0x%08X\n", FC_MTIP_CMDCONFIG + l_fc_port_offset, mmio_data32);
        mmio_data32 &= ~0x20; // clear ON_LINE
        mmio_data32 |= 0x40;  // set OFF_LINE
        TRACEV("FC_MTIP_CMDCONFIG: Proposed:    0x%08X\n", mmio_data32);
        out_mmio32((__u64*)&afu_psa_addr[FC_MTIP_CMDCONFIG + l_fc_port_offset], mmio_data32);
        
        //wait for the port to be offline
        l_rc = wait_port_state(afu_psa_addr, l_fc_port_offset, false);
        if(l_rc == false)
        {
            TRACEE("Port not offline in time. Aborting.\n");
            l_rc = -1;
            break;
        }
        
        //now we know we are offline, so write the PN...
        
        
        //read out the current PN
        //PN register is 64-bit as per spec
        mmio_data = in_mmio64((__u64*)&afu_psa_addr[FC_PNAME + l_fc_port_offset]);
        TRACEV("FC_PNAME:         (0x%08X): 0x%"PRIx64"\n",FC_PNAME + l_fc_port_offset, mmio_data);
        TRACEI("Current Port Name is  0x%"PRIx64"\n", mmio_data);
        
        mmio_data = i_wwpn;
        TRACEI("New Port Name will be 0x%"PRIx64"\n", mmio_data);
        
        out_mmio64((__u64*)&afu_psa_addr[FC_PNAME + l_fc_port_offset], mmio_data);
        
        //bring the port back online
        //read control bits...
        mmio_data32 = in_mmio32((__u64*)&afu_psa_addr[FC_MTIP_CMDCONFIG + l_fc_port_offset]);
        TRACEV("FC_MTIP_CMDCONFIG (0x%08X): 0x%08X\n", FC_MTIP_CMDCONFIG + l_fc_port_offset, mmio_data32);
        mmio_data32 |= 0x20; // set ON_LINE
        mmio_data32 &= ~0x40;  // clear OFF_LINE
                               //TODO: ask todd - should we explicitly-set other bits? I needed to force the port into FC mode (set bit 1)
        //net result is we write 0x23 to the lowest byte
        TRACEV("FC_MTIP_CMDCONFIG: Proposed:    0x%08X\n", mmio_data32);
        out_mmio32((__u64*)&afu_psa_addr[FC_MTIP_CMDCONFIG + l_fc_port_offset], mmio_data32);
        
        //wait for the port to be online
        l_rc = wait_port_state(afu_psa_addr, l_fc_port_offset, true);
        if(l_rc == false)
        {
            TRACEE("Port not online in time.\n");
            l_rc = -1;
            break;
        }
        
        //done!
        munmap_afu_wwpn_registers((void *) afu_psa_addr);
        cxl_afu_free(afu_master_h);
        
        
        
        TRACEI("Successfully programmed WWPN!\n");
        l_rc = true;
        
    } while (0);
    
	return l_rc;
    
}
Example #4
0
bool loopbackDiag(char* i_afu_path, const AFU_PORT_ID i_port, uint64_t i_test_time_us)
{
    //Locals
    struct cxl_afu_h *afu_master_h = NULL;
    int afu_master_fd = 0;
    uint8_t *afu_psa_addr = NULL;
    uint64_t mmio_data = 0;
    int l_fc_port_offset = 0;
    bool l_rc = true;
    uint64_t l_init_txcount = 0;
    uint64_t l_init_errcount = 0;
    uint64_t l_init_passcount = 0;
    uint64_t l_txcount = 0;
    uint64_t l_errcount = 0;
    uint64_t l_passcount = 0;
    
    //Code
    do
    {
        if(i_port >= MAX_WWPNS_PER_ADAPTER)
        {
            TRACEE("Port number %d is not a valid port number. We only support up to %d numbers.\n", i_port, MAX_WWPNS_PER_ADAPTER);
            l_rc = false;
            break;
        }
        
        l_fc_port_offset = FC_PORT_BASE_OFFSET + (i_port * FC_PORT_REG_SIZE);
        TRACEV("Target reg bank for port %d = 0x%08x\n",i_port, l_fc_port_offset);
        
        TRACEI("Attempting to open device '%s'\n", i_afu_path);
        
        /* now that the AFU is started, lets set config options */
        if ((afu_master_h = cxl_afu_open_dev(i_afu_path)) < 0) {
            TRACEE("Unable to open AFU Master cxl device. errno = %d (%s)\n", errno, strerror(errno));
            l_rc = false;
            break;
        }
        TRACEV("Opened %p, now attempting to get FD\n", afu_master_h);
        afu_master_fd = cxl_afu_fd(afu_master_h);
        TRACEV("Got FD! = %d\n", afu_master_fd);
        
        if (cxl_afu_attach(afu_master_h,
                           0)) //no WEQ needed
        {
            TRACEE("Call to cxl_afu_attach failed. errno = %d (%s)\n", errno, strerror(errno));
            l_rc = false;
            break;
        }
        
        
        afu_psa_addr = mmap_afu_wwpn_registers(afu_master_fd);
        if (!afu_psa_addr) {
            TRACEE("Error attempting to map AFU problem state registers. errno = %d (%s)\n", errno, strerror(errno));
            l_rc = false;
            break;
        }
        
        //Loopback enables a special echo mode and checks tx and rx counts to make sure
        //the phy works correctly. The test is relatively short.
        TRACEI("Enabling loopback mode for adapter %s, port %d\n", i_afu_path, i_port);
        //first read back all test register counts. The AFU does not zero them
        l_init_txcount =   in_mmio64((__u64*)&afu_psa_addr[FC_LOOPBACK_TXCNT + l_fc_port_offset]);
        l_init_errcount =  in_mmio64((__u64*)&afu_psa_addr[FC_LOOPBACK_ERRCNT + l_fc_port_offset]);
        l_init_passcount = in_mmio64((__u64*)&afu_psa_addr[FC_LOOPBACK_PASSCNT + l_fc_port_offset]);


        //enable the test
        mmio_data = in_mmio64((__u64*)&afu_psa_addr[FC_CONFIG2 + l_fc_port_offset]);
        mmio_data |= (uint64_t)0x01 << 40; //set ECHO generator for this port (bit 40)
        out_mmio64((__u64*)&afu_psa_addr[FC_CONFIG2 + l_fc_port_offset], mmio_data);

        TRACEI("Waiting %"PRIu64" microseconds for the test to complete...\n", i_test_time_us);
        usleep(i_test_time_us);
        TRACEI("Disabling loopback mode.\n");
        mmio_data = in_mmio64((__u64*)&afu_psa_addr[FC_CONFIG2 + l_fc_port_offset]);
        mmio_data &= ~((uint64_t)0x01 << 40); //clear ECHO generator for this port (bit 40)
        out_mmio64((__u64*)&afu_psa_addr[FC_CONFIG2 + l_fc_port_offset], mmio_data);

        TRACEI("Waiting for the link to quiesce...\n");
        usleep(LOOPBACK_TEST_QUIET_PERIOD);//wait for quiesce and any final timeouts
        
        //check test results from HW - subtract out initial readings
        l_txcount =   in_mmio64((__u64*)&afu_psa_addr[FC_LOOPBACK_TXCNT + l_fc_port_offset]) - l_init_txcount;
        l_errcount =  in_mmio64((__u64*)&afu_psa_addr[FC_LOOPBACK_ERRCNT + l_fc_port_offset]) - l_init_errcount;
        l_passcount = in_mmio64((__u64*)&afu_psa_addr[FC_LOOPBACK_PASSCNT + l_fc_port_offset]) - l_init_passcount;

        if((l_txcount == 0) || 
           (l_errcount != 0) || 
           (l_txcount != l_passcount))
        {
            TRACED("Loopback diagnostic failure detected. AFU: %s, port: %d, Tx Count: %"PRIu64", Pass Count: %"PRIu64", Error Count: %"PRIu64"\n", i_afu_path, i_port, l_txcount, l_passcount, l_errcount);
            l_rc = false;
        }
        else
        {
            TRACEV("Loopback test passed. AFU: %s, port: %d, Tx Count: %"PRIu64", Pass Count: %"PRIu64", Error Count: %"PRIu64"\n", i_afu_path, i_port, l_txcount, l_passcount, l_errcount);
            l_rc = true;
        }

        //done!
        munmap_afu_wwpn_registers((void *) afu_psa_addr);
        cxl_afu_free(afu_master_h);
        
        
    } while (0);
    
    return l_rc;
    
}
int main (int argc, char **argv)
{
    int ret;
    int i, count, data_size;
    uint64_t mmio_state = 0;

    struct wed * capi_wed = NULL;
    struct wed_tx * p_wed_tx = NULL;
    char cxl_device [64];
 
    __u8 * source_buf, * result_buf;
    int16_t * ptr = NULL;
    struct cxl_afu_h * afu_h = NULL;
    FILE *fp;

    int send_num, received_num, loops;
    struct timeval start;
    struct timeval end;
    double interval;

    if(argc != 2)
    {
        printf("uasge: %s imagepath \n", argv[0]);
        exit(1);
    }
    // Malloc buffer for the work element descriptor
    // posix_memalign is used to keep alignment requirement and make DMA engine simple
    ret = posix_memalign ((void **) &capi_wed, CACHELINE_BYTES, sizeof(struct wed));
    if (ret) {
        printf ("Error. Can not malloc buffer for wed.\n");
        return -1;
    }

    ret = posix_memalign ((void **) &p_wed_tx, CACHELINE_BYTES, sizeof(struct wed_tx));
    if (ret) {
        printf ("Error. Can not malloc buffer for wed.\n");
        return -1;
    }

    // Malloc buffer for the source data
    // posix_memalign is used to keep alignment requirement and make DMA engine simple
    ret = posix_memalign ((void **) &source_buf, CACHELINE_BYTES, DATA_SIZE);
    if (ret) {
        printf ("Error. Can not malloc buffer for source buffer.\n");
        free (capi_wed);
        return -1;
    }

    // Malloc buffer for the result
    // posix_memalign is used to keep alignment requirement and make DMA engine simple
    ret = posix_memalign ((void **) &result_buf, CACHELINE_BYTES, DATA_SIZE);
    if (ret) {
        printf ("Error. Can not malloc buffer for result buffer.\n");
        free (capi_wed);
        free (source_buf);
        return -1;
    }

    if ((fp = fopen(argv[1], "r")) == NULL)
    {
        printf ("Image file can not be opened.\n");
        exit(1);
    }
    
    //Read the input data from the file, the data should be 16bits, 
    //You can modify here to for your own data.
    ptr = (int16_t*) source_buf;
    count = 0;
    while(fscanf(fp, "%hd", ptr++) > 0)
    {
        count ++;
        if (count >= DATA_SIZE / sizeof(int16_t))
        {
            printf ("Buff overflow.\n");
            exit(1);
        }
    }
    
    data_size = count * sizeof(int16_t);
    
    //The input data buffer should be aligined with cache line (128bytes)   
    if(data_size % CACHELINE_BYTES)
    {
        data_size = (data_size / CACHELINE_BYTES + 1) * CACHELINE_BYTES;
    }

    capi_wed->data_size = data_size;
    capi_wed->param_s0 = 0x11223344;
    capi_wed->param_s1 = 0x55667788;
    capi_wed->source = source_buf;
    capi_wed->result = result_buf;
    capi_wed->p_wed_tx = (__u8 *)p_wed_tx;

    //Detect which device is avaliable
    strncpy (cxl_device, DEVICE, 64);
    for (ret = 0; ret < 8; ret ++) {
        if (access(cxl_device, W_OK) == 0)
            break;
        cxl_device [12] ++;
    }

    if (ret == 8) {
        printf ("Can not find available CAPI device.\n");
        return -1;
    }
    //Open CAPI device
    afu_h = cxl_afu_open_dev (cxl_device);
    if (!afu_h) {
        printf ("Error. Can not open CAPI device : %s\n", DEVICE);
        return -1;
    }
    printf ("Open CAPI device %s\n", cxl_device);

    // Create the CAPI hardware thread, AFU is enabled
    // capi_wed pointer is sent to the AFU
    // The DMA dose not run at this moment, it will only read the capi_wed struction
    // to the DAM engine
    cxl_afu_attach (afu_h, (__u64) capi_wed);
    printf ("Attach AFU to current application.\n");

    // Map some register from AFU to user space to do runtime control
    // This is an optinal step for CAPI application development dependent on AFU
    if ((cxl_mmio_map (afu_h, CXL_MMIO_BIG_ENDIAN)) < 0) {
        printf ("Error. Can not map registers\n");
        return -1;
    }

    // We clear the status to Zero
    capi_wed->status = 0;
    capi_wed->jcounter = 0;
    capi_wed->ret_size = 0;
    
    // We use a register to show whether the AFU is ready
    // This is an optinal step for CAPI application development dependent on AFU
    do {
        cxl_mmio_read64 (afu_h, MMIO_TRACE_ADDR, &mmio_state);
    } while ((mmio_state & 0xf) != 0x1);

    gettimeofday(&start, NULL);
    //Start the data receive DMA
    cxl_mmio_write64 (afu_h, MMIO_TRACE_ADDR, 0xf0);
    //Start the data send DMA
    cxl_mmio_write64 (afu_h, MMIO_TRACE_ADDR, 0x0f);
    
    loops = 100;

    send_num = 1;
    received_num = 0;
    while(1)
    {
        if(capi_wed->status)
        {
            received_num ++;
            if (received_num >= loops)break;
            //Clear the status bit
            capi_wed->status = 0;
            cxl_mmio_write64 (afu_h, MMIO_TRACE_ADDR, 0xf0);
        }
        if (p_wed_tx -> status)
        {
            p_wed_tx->status = 0;
            if (send_num < loops)
            {
                //clear the status bit
                p_wed_tx->status = 0;
                cxl_mmio_write64 (afu_h, MMIO_TRACE_ADDR, 0x0f);
                send_num ++;
            }
        }
    }
    gettimeofday(&end, NULL);

    interval = ((end.tv_sec * 1000000 + end.tv_usec) - (start.tv_sec * 1000000 + start.tv_usec)) / 1000000.0;

    printf ("The %dst job finish. Return Size = 0x%x\n", capi_wed->jcounter, capi_wed->ret_size);
    printf ("The total time cost (%d loops) is %.3fs, each loop cost is %.3fms.\n", loops, interval, interval/loops * 1000.0);

    ptr = (int16_t*) result_buf;
    printf ("Recognition Results (without softmax):\n");
    for (i = 0; i < 10; i++)
    {
        printf("%d \t", *ptr ++);
    }
    printf ("\n");

    free (capi_wed);
    free (source_buf);
    free (result_buf);

    // We use register write to trigger the DAM to finish all jobs
    // This is an optinal step for CAPI application development dependent on AFU
    cxl_mmio_write64 (afu_h, MMIO_TRACE_ADDR, 0xf1);

    // We do register unmap because we map register above
    cxl_mmio_unmap (afu_h);

    // Close the CAPI device
    cxl_afu_free (afu_h);

    return 0;
}