#include #include #include #include #include #include #include #include #include static char test_channel[20]; module_param_string(channel, test_channel, sizeof(test_channel), S_IRUGO); MODULE_PARM_DESC(channel, "Bus ID of the channel to test (default: any)"); static char test_device[20]; module_param_string(device, test_device, sizeof(test_device), S_IRUGO); MODULE_PARM_DESC(device, "Bus ID of the DMA Engine to test (default: any)"); struct chan_list { struct dma_chan *chan; struct list_head list; }; static bool dmatest_match_channel(struct dma_chan *chan) { if (test_channel[0] == '\0') return true; return strcmp(dma_chan_name(chan), test_channel) == 0; } static bool dmatest_match_device(struct dma_device *device) { if (test_device[0] == '\0') return true; return strcmp(dev_name(device->dev), test_device) == 0; } static bool filter(struct dma_chan *chan, void *param) { if (!dmatest_match_channel(chan) || !dmatest_match_device(chan->device)) return false; else return true; } int checkTypeSupport (struct dma_chan *chan, int type) { struct dma_device *dma_dev = chan->device; //printk("memory copy %d %d %d %d\n",DMA_MEMCPY,DMA_MEMSET,DMA_XOR,DMA_PQ); return dma_has_cap(type, dma_dev->cap_mask); } int dmaTestLoop( int (*test_fun)(struct dma_chan *chan, int type) , int op_type, int release_chan ) { dma_cap_mask_t mask; int count = 0; int result_count = 0; struct list_head chan_head, *next; struct chan_list cl[20]; // student list struct chan_list *chanP; // student pointer INIT_LIST_HEAD(&chan_head); /* Check whether the std_head is empty */ if(list_empty(&chan_head) == true) { printk(KERN_INFO "chan_head is NULL\n"); } dma_cap_zero(mask); dma_cap_set(op_type, mask); //dmaengine_get(); count=0; for (;;) { //*chan = (struct dma_chan *) cl[count].chan; cl[count].chan = dma_request_channel(mask, filter, NULL); if (cl[count].chan) { printk(">>> %d \n",count); if (test_fun(cl[count].chan,op_type)){ result_count++; } list_add(&cl[count].list, &chan_head); count++; }else{ break; /* no more channels available */ } } // printk("MEMCPY %d \n", count); count=0; list_for_each(next, &chan_head) { //if(count>0) { printk(KERN_INFO "release\n"); if (release_chan){ chanP = (struct chan_list *) list_entry(next, struct chan_list, list); dma_release_channel(chanP->chan); } //} count++; } list_empty(&chan_head); return result_count; } void dmaInterfaceTest(void){ int cpy_cnt=0; char msg[1000]; cpy_cnt=dmaTestLoop(&checkTypeSupport,DMA_MEMCPY, 1); sprintf(msg, "dmaInterfaceTest cpy_cnt: %d", cpy_cnt); // FIXME (Some envirment the cpy_cnt is not 8) mark the test item first. //if (cpy_cnt!=8){ // commReportError(MEC_DMA, 0, 0, msg, // 0, 0, 0, DG_FORMAT_NONE); //} } void dmaSetTxInterruptEnable(struct dma_async_tx_descriptor *pTX) { struct ioat_ring_ent *pDesc; struct ioat_dma_descriptor *pHWDesc; pDesc = container_of(pTX, struct ioat_ring_ent, txd); pHWDesc = pDesc->hw; pHWDesc->ctl_f.int_en= 1; } typedef struct ComponentTestControlBlockStruct { wait_queue_head_t waitqueue; /* The wait queue used to wake up sleeping conponent test process */ atomic_t numTotalCmd; /* The number of total commands in this compontent test */ atomic_t numIssuedCmd; /* The number of issued commands in this compontent test */ atomic_t numSuccessCmd; /* The number of success commands in this compontent test */ atomic_t numFailedCmd; /* The number of failed commands in this compontent test */ }COMP_CB; static void callback(COMP_CB *pCompCB) { printk(" : %d \n", atomic_read(&pCompCB->numIssuedCmd)); if(atomic_dec_and_test(&pCompCB->numIssuedCmd)) { printk(" >>> callback: %d \n",pCompCB->numIssuedCmd); wake_up_interruptible(&pCompCB->waitqueue); } } static void dmatest_callback(void *completion) { complete(completion); } #define CBDMA_MAX_TRANSFER_SIZE (1 << 20) // 1 MB int asyncTest (struct dma_chan *chan,int type) { struct dma_device *dma_dev = chan->device; struct dma_async_tx_descriptor* pTX; struct async_submit_ctl submit; struct completion cmp; dma_cookie_t cookie; COMP_CB* pCompCB; if (dma_has_cap(DMA_MEMCPY, dma_dev->cap_mask)) { pCompCB = (COMP_CB *)kmalloc(sizeof(COMP_CB), GFP_KERNEL); init_waitqueue_head(&pCompCB->waitqueue); pCompCB->numIssuedCmd = (atomic_t)ATOMIC_INIT(0); pTX = dma_dev->device_prep_dma_memcpy(chan, (u64)(num_physpages << PAGE_SHIFT), (u64)(num_physpages << PAGE_SHIFT) + CBDMA_MAX_TRANSFER_SIZE, CBDMA_MAX_TRANSFER_SIZE, DMA_PREP_INTERRUPT); if (pTX){ dmaSetTxInterruptEnable(pTX); pTX->callback = (dma_async_tx_callback)callback; pTX->callback_param = &pCompCB; cookie = pTX->tx_submit(pTX); if (dma_submit_error(cookie)) { printk("dma_submit_error \n"); } dma_async_issue_pending(chan); printk(" : %d \n", atomic_read(&pCompCB->numIssuedCmd)); wait_event_interruptible_timeout(pCompCB->waitqueue, (atomic_read(&pCompCB->numIssuedCmd) == 0), msecs_to_jiffies(300)); } kfree(pCompCB); }else{ printk(" no support \n"); } } void dmaInterrupt(void){ dmaTestLoop(&asyncTest,DMA_MEMCPY, 1); }