[driver-discuss] ddi_dma_attr_t, dma_attr_maxxfer quesiton.

Mark Johnson Mark.Johnson at Sun.COM
Tue Dec 4 16:36:59 PST 2007



Carlos Cumming wrote:
> Mark Johnson wrote:
>> What is MEMTYPE set to.  It looks like you have set
>> DDI_DMA_PARTIAL which is correct. 
> ...I think I intended to have DDI_DMA_PARTIAL off. But you say, "is 
> correct".  Is there a problem with turning it off if I want the whole 
> kit'n kaboodle?

You should support partial mappings.  You can see
1M transfers come down the scsi stack. You would
want that broken into multiple 128K DMA "windows".

e.g. I believe /dev/rdsk/c* is case where this
will happen.


>> e.g. if a dma engine has a 16 bit size for the DMA engine,  the max 
>> size it can DMA is 64K - 1 byte. (0xffff). A few DMA
>> engines will use 0 to signify the 0x10000 value, but that means adding 
>> another bit to the counter or adding some more
>> complicated logic.
> [the above] is how I understood it.... But if you want to get optimal 
> performance out of your hw, then you'd want to do a full 64k DMA 
> (somehow). Xfering 65535 (64k - 1) bytes is a really oddball value. 
> Specially if you have a block (512 byte) device like I have.
> 
> In my case I'm actually, "logically" limited. I.e., the firmware in the 
> device is limiting me to 128k, the actual counter goes to 2^32 - 1 (to 
> use your parlance). So I take it in my case using a full value of 128k 
> (i.e., 0x20000) in dma_attr_maxxfer is correct.

yes.



MRJ




> Thanks!!!
> 
> Carlos
>>
>> Carlos Cumming wrote:
>>> I'm writing a SCSI driver. The board I'm talking to can do a max 128k 
>>> (256 blocks) DMA. I am using the following two dma_attr_t's:
>>>
>>> static ddi_dma_attr_t hba_dma_attr = {
>>>     DMA_ATTR_V0,                        // dma_attr_version     
>>> Version of this structure
>>>     (u64)0,                             // dma_attr_addr_lo     
>>> Lowest usable address
>>>     (u64)0xffffffffffffffff,            // dma_attr_addr_hi     
>>> Highest usable address
>>>     (u64)(256 * 512) - 1,               // dma_attr_count_max   
>>> Maximum DMAable byte count (1 sge * maxxfer)
>>>     512,                                // dma_attr_align       
>>> Minimum alignment (This value correct?)
>>>     0x7f,                               // dma_attr_burstsizes  Burst 
>>> sizes (??? big values don't work)
>>>     (u64)4,                             // dma_attr_minxfer     
>>> Minimum transfer
>>>     (u64)(256 * 512) - 1,               // dma_attr_maxxfer     
>>> Maximum transfer count for entire I/O.
>>>     (u64)0xffffffffffffffff,            // dma_attr_seg         
>>> Maximum segment (boundry DMA engine cannot cross).
>>>     512,                                // dma_attr_sgllen      
>>> Maximum scatter gather list entries
>>>     512,                                // dma_attr_granular    
>>> Granularity
>>>     0,                                  // dma_attr_flags       Flags 
>>> (reserved)
>>> };
>>>
>>> static ddi_dma_attr_t cmd_dma_attr = {
>>>     DMA_ATTR_V0,                        // dma_attr_version     
>>> Version of this structure
>>>     (u64)0,                             // dma_attr_addr_lo     
>>> Lowest usable address
>>>     (u64)0xffffffffffffffff,            // dma_attr_addr_hi     
>>> Highest usable address
>>>     (u64)(256 * 512) - 1,               // dma_attr_count_max   
>>> Maximum DMAable byte count (1 sge * maxxfer)
>>>     512,                                // dma_attr_align       
>>> Minimum alignment (This value correct?)
>>>     0x7f,                               // dma_attr_burstsizes  Burst 
>>> sizes (??? big values don't work)
>>>     (u64)512,                           // dma_attr_minxfer     
>>> Minimum transfer
>>>     (u64)(256 * 512) - 1,               // dma_attr_maxxfer     
>>> Maximum transfer count for entire I/O.
>>>     (u64)0xffffffffffffffff,            // dma_attr_seg         
>>> Maximum segment (boundry DMA engine cannot cross).
>>>     512,                                // dma_attr_sgllen      
>>> Maximum scatter gather list entries
>>>     512,                                // dma_attr_granular    
>>> Granularity
>>>     0,                                  // dma_attr_flags       Flags 
>>> (reserved)
>>> };
>>>
>>>
>>>
>>> Some time later, I use the first one:
>>>
>>> if (scsi_hba_attach_setup(dev, &hba_dma_attr, softs->tran, 0) != 
>>> DDI_SUCCESS) ..
>>>
>>>
>>>
>>> Then even later (but still within attach if that matters) I use 
>>> cmd_dma_attr...
>>>
>>>     if (ddi_dma_alloc_handle(softs->dev, &cmd_dma_attr, 
>>> DDI_DMA_SLEEP, NULL, &softs->dma_hndl) != DDI_SUCCESS) {
>>>         cmn_err(CE_WARN, "tw%d: tw_create_reqs: Cannot alloc dma 
>>> handle for command blocks.", inst);
>>>         return(1);
>>>     }
>>>
>>> #define MEMSIZE (256 * 512)
>>>
>>>     if (ddi_dma_mem_alloc(softs->dma_hndl, MEMSIZE, &accattr, 
>>> MEMTYPE, DDI_DMA_SLEEP, NULL, &mem, &rlen, &softs->acc_hndl)
>>>       != DDI_SUCCESS) {
>>>         cmn_err(CE_WARN, "tw%d: tw_create_reqs: Cannot alloc dma 
>>> memory for command blocks.", inst);
>>>         goto free_hndl;
>>>     }
>>>
>>> {
>>>     int a;
>>>
>>>     if ((a = ddi_dma_addr_bind_handle(softs->dma_hndl, NULL, mem, 
>>> rlen, MEMTYPE, DDI_DMA_SLEEP, NULL, &dmacookie, &num_dmacookies)) != 
>>> DDI_DMA_MAPPED) {
>>>         cmn_err(CE_WARN, "tw%d: tw_create_reqs: Cannot bind dma 
>>> memory to handle for command blocks. %d", inst, a);
>>>         goto free_mem;
>>>     }
>>> }
>>>
>>>
>>> The above ddi_dma_addr_bind_handle(.. ) _FAILS. It prints "Cannot 
>>> bind dma memory to handle for command blocks. 1". The trailing ,"1" 
>>> is DDI_ENOMEM if I understand it correctly.
>> What is MEMTYPE set to.  It looks like you have set
>> DDI_DMA_PARTIAL which is correct.
>>
>> You are not getting a failure returned.  You are getting
>> DDI_DMA_PARTIAL_MAP which means you have multiple DMA
>> windows.
>>
>> #define DDI_DMA_PARTIAL_MAP     1
>>
>>
>>
>>
>>
>>> Now, here's where I get lost. If you look at 
>>> cmd_dma_attr.dma_attr_maxxfer above, it's set to (256 * 512) - 1. I'm 
>>> trying to get 256 * 512 of memory. So, it makes sense that it fails 
>>> ENOMEM, because I'm requesting one more byte than dma_attr_maxxfer.
>>>
>>> Or does it make sense...
>>>
>>> _Every_ example that I look at shows dma_attr_maxxfer set to a power 
>>> of 2 - 1. I.e., the way everyone else uses dma_attr_maxxfer is as if 
>>> it's the max value of a dma counter, just like dma_attr_count_max.
>>>
>>> So I'm feeling just a bit squeamish using a nice even power of two 
>>> value for dma_attr_maxxfer when nobody else is using it that way. I 
>>> figure they know something I don't.
>>>
>>> Can someone give me a clue???
>> The reason folks use power of 2's - 1 for things like maxxfer, seg,
>> dma count is because counters are usually powers of two :-)
>>
>> e.g. if a dma engine has a 16 bit size for the DMA engine,
>> the max size it can DMA is 64K - 1 byte. (0xffff). A few DMA
>> engines will use 0 to signify the 0x10000 value, but that
>> means adding another bit to the counter or adding some more
>> complicated logic.
>>
>>
>> MRJ
>>
>>
> 
> _______________________________________________
> driver-discuss mailing list
> driver-discuss at opensolaris.org
> http://mail.opensolaris.org/mailman/listinfo/driver-discuss


More information about the driver-discuss mailing list