3 Replies Latest reply: Aug 10, 2010 12:29 PM by 807567 RSS

    Supporting 31 bit dma_attr_addr_hi address

    807567
      I am writing a Solaris Sparc 10 device driver for a pci express device. The driver has to pass a dma bus address of 31 bit to the device as the device do not support the full 32 bit address space. However I am not be able to specify the dma_attr_addr_hi with the address mask 0x7FFFFFFF and get the DDI_DMA_NOMAPPING error. Below is the code:
      ddi_dma_attr_t           dmaattr; /* used to allocate the handle */
      
             ddi_device_acc_attr_t devattr;
             ddi_dma_cookie_t      dmacookie;
      
             size_t                        real_length = 0;
             uint_t                         cntcookie   = 0;
             dev_info_t           *dip           = tag;
             int                      rc             = 0;
             caddr_t               kaddrp      = NULL;
      
             unsigned int          bytecount   = size
      
             dmaattr.dma_attr_version        = DMA_ATTR_V0;  
             dmaattr.dma_attr_addr_lo        = 0x0;          
             dmaattr.dma_attr_addr_hi        = 0x07fffffff; /* 31 bit mask  */  
             dmaattr.dma_attr_count_max   = 0x0ffffffff; 
             dmaattr.dma_attr_align            = 1;           
             dmaattr.dma_attr_burstsizes    = 0x01;         
             dmaattr.dma_attr_minxfer        = 0x01;         
             dmaattr.dma_attr_maxxfer       = 0x0ffffffff; 
             dmaattr.dma_attr_seg             = 0x0ffffffff; 
             dmaattr.dma_attr_sgllen          = 1;            
             dmaattr.dma_attr_granular       = 1;            
             dmaattr.dma_attr_flags            = 0;            
      
             rc = ddi_dma_alloc_handle(
              luna_p->tag,
              &dmaattr,
              DDI_DMA_SLEEP,
              NULL,
                 &(dma_addr->m_handle));
      
             if (rc !=DDI_SUCCESS)
             {
                 switch (rc)
                 {
                    case DDI_DMA_BADATTR:
                      vip_log(NULL, 
                              VIP_ERR, 
                              "ddi_dma_alloc_handle failed (DDI_DMA_BADATTR)");
                      break;
                    case DDI_DMA_NORESOURCES:
                      vip_log(NULL,
                       VIP_ERR,
                         "ddi_dma_alloc_handle failed (DDI_DMA_NORESOURCES)");
                      break;
                    default:
                      vip_log(NULL,
                     VIP_ERR, 
                     "ddi_dma_alloc_handle failed (%d)", rc);
                     break;
                 }
                 return NULL; /* handle allocation failed and stop the allocation process */ 
             }
      
             devattr.devacc_attr_version       = DDI_DEVICE_ATTR_V0;   
             devattr.devacc_attr_endian_flags  = DDI_NEVERSWAP_ACC; 
             devattr.devacc_attr_dataorder     = DDI_STRICTORDER_ACC;   
      
             rc = ddi_dma_mem_alloc(
                      dma_addr->m_handle,
                      bytecount,
                      &devattr,
                      DDI_DMA_CONSISTENT,
                      DDI_DMA_SLEEP,
                      NULL,
                      &kaddrp,
                      &real_length,
                      &(dma_addr->m_acchandle)
             );
      
             if (rc != DDI_SUCCESS)
             {
                vip_log(NULL, 
                        VIP_ERR, 
                        "ddi_dma_mem_alloc failed");
                return NULL;
             }
             else
             {
      #ifdef DEBUG
                vip_log(NULL,
                        VIP_DBG, 
                        "ddi_dma_mem_alloc request length= %d, real length= %d", 
                        bytecount, 
                        real_length);
      #endif
             }
      
             rc = ddi_dma_addr_bind_handle(
                      dma_addr->m_handle,
                      NULL,
                      kaddrp,
                      real_length,
                      DDI_DMA_RDWR | DDI_DMA_CONSISTENT, /* Note: all dma bufs are read/write */
                      DDI_DMA_SLEEP,
                      NULL,
                      &dmacookie,
                      &cntcookie
             );
      #ifdef DEBUG
             /* vip_log(NULL, VIP_DBG, "_AllocateDMABuffer: the return value is %x",rc); */
      #endif
      
             if (rc != DDI_DMA_MAPPED)
             {
                switch (rc)
                {
                     case DDI_DMA_PARTIAL_MAP:
                          vip_log(NULL,
                          VIP_ERR, 
                         "ddi_dma_addr_bind_handle failed (DDI_DMA_PARTIAL_MAP)");
                          break;
      
                     case DDI_DMA_INUSE:
                          vip_log(NULL, 
                         VIP_ERR, 
                         "ddi_dma_addr_bind_handle failed (DDI_DMA_INUSE)");
                           break;
      
                     case DDI_DMA_NORESOURCES:
                          vip_log(NULL, 
                         VIP_ERR,
                         "ddi_dma_addr_bind_handle failed (DDI_DMA_NORESOURCES)");
                          break;
      
                     case DDI_DMA_NOMAPPING:
                          vip_log(NULL, 
                         VIP_ERR,
                             "ddi_dma_addr_bind_handle failed (DDI_DMA_NOMAPPING)");
                          break;
      
                     case DDI_DMA_TOOBIG:
                          vip_log(NULL,
                         VIP_ERR,
                         "ddi_dma_addr_bind_handle failed (DDI_DMA_TOOBIG)");
                           break;
      
                     default:
                          vip_log(NULL,
                         VIP_ERR,
                         "ddi_dma_addr_bind_handle failed (%d)", rc);
                          break;
                }
                return NULL;
             }
      
             if (cntcookie!=1)
             {
                vip_log(NULL,
                  VIP_ERR, 
                  "ddi_dma_addr_bind_handle returned %d cookies (!=1)", cntcookie);
                return NULL;
             }
      
             bzero(kaddrp, bytecount);
      
             dma_addr->m_address      = dmacookie.dmac_address;
             dma_addr->m_kaddrp       = kaddrp;
             dma_addr->m_nbytes_req   = bytecount;
             dma_addr->m_nbytes_real  = real_length;
      
      
      /* #ifdef DEBUG */
      #if 0
             vip_log(NULL, VIP_DBG, "_AllocateDMABuffer: m_address = 0x%8x",dma_addr->m_address);
             vip_log(NULL, VIP_DBG, "_AllocateDMABuffer: m_kaddrp  = 0x%8x",dma_addr->m_kaddrp);
             vip_log(NULL, VIP_DBG, "_AllocateDMABuffer: dma_addr  = 0x%8x",dma_addr);
             vip_log(NULL, VIP_DBG, "_AllocateDMABuffer: *dma_addr  = 0x%8x",*dma_addr);
      #endif
             return kaddrp; /* kernel virtual address */ 
      }
        • 1. Re: Supporting 31 bit dma_attr_addr_hi address
          807567
          Sorry I click wrong button and post the in-completed message and I am re-doing the work again.

          I am writing a Solaris Sparc 10 device driver for a pci express device. The driver has to pass a dma bus address of 31 bit to the device as the device do not support the full 32 bit address space. However I am not be able to specify the dma_attr_addr_hi with the address mask 0x7FFFFFFF and get the DDI_DMA_NOMAPPING error. Below is the code:

          ddi_dma_attr_t dmaattr; /* used to allocate the handle */

          ddi_device_acc_attr_t devattr;
          ddi_dma_cookie_t dmacookie;

          size_t real_length = 0;
          uint_t cntcookie = 0;
          dev_info_t *dip           = tag;
          int rc = 0;
          caddr_t kaddrp = NULL;

          unsigned int bytecount = size

          dmaattr.dma_attr_version = DMA_ATTR_V0;
          dmaattr.dma_attr_addr_lo = 0x0;
          dmaattr.dma_attr_addr_hi = 0x07fffffff; /* 31 bit mask */
          dmaattr.dma_attr_count_max = 0x0ffffffff;
          dmaattr.dma_attr_align = 1;
          dmaattr.dma_attr_burstsizes = 0x01;
          dmaattr.dma_attr_minxfer = 0x01;
          dmaattr.dma_attr_maxxfer = 0x0ffffffff;
          dmaattr.dma_attr_seg = 0x0ffffffff;
          dmaattr.dma_attr_sgllen = 1;
          dmaattr.dma_attr_granular = 1;
          dmaattr.dma_attr_flags = 0;

          rc = ddi_dma_alloc_handle(
               dip,
               &dmaattr,
               DDI_DMA_SLEEP,
               NULL,
          &(dma_addr->m_handle));

          if (rc !=DDI_SUCCESS)
          {
          switch (rc)
          {
          case DDI_DMA_BADATTR:
          rc = DDI_DMA_BADATTR;
          break;
          case DDI_DMA_NORESOURCES:
          rc = DDI_DMA_NORESOURCES;
          break;
          default:

          break;
          }
          return rc; /* handle allocation failed and stop the allocation process */
          }

          devattr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
          devattr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
          devattr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;

          rc = ddi_dma_mem_alloc(
          dma_addr->m_handle,
          bytecount,
          &devattr,
          DDI_DMA_CONSISTENT,
          DDI_DMA_SLEEP,
          NULL,
          &kaddrp,
          &real_length,
          &(dma_addr->m_acchandle)
          );

          if (rc != DDI_SUCCESS)
          {
          return rc;
          }

          rc = ddi_dma_addr_bind_handle(
          dma_addr->m_handle,
          NULL,
          kaddrp,
          real_length,
          DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
          DDI_DMA_SLEEP,
          NULL,
          &dmacookie,
          &cntcookie
          );

          if (rc != DDI_DMA_MAPPED)
          {
          switch (rc)
          {
          case DDI_DMA_PARTIAL_MAP:
          rc = DDI_DMA_PARTIAL_MAP;
          break;

          case DDI_DMA_INUSE:
          rc = DDI_DMA_INUSE;
               break;

          case DDI_DMA_NORESOURCES:
          rc = DDI_DMA_NORESOURCES;
          break;

          case DDI_DMA_NOMAPPING:
          rc = DDI_DMA_NOMAPPING;
          break;

          case DDI_DMA_TOOBIG:
          rc = DDI_DMA_TOOBIG;
               break;

          default:

          break;
          }
          return rc;
          }

          if (cntcookie!=1)
          {
          return rc;
          }

          bzero(kaddrp, bytecount);

          dma_addr->m_address = dmacookie.dmac_address;
          dma_addr->m_kaddrp = kaddrp;
          dma_addr->m_nbytes_req = bytecount;
          dma_addr->m_nbytes_real = real_length;

          return kaddrp; /* kernel virtual address */

          Please note that if I set dma_attr_addr_hi = 0xffffffff, I do not get the DDI_DMA_NOMAPPING error any more and get a 32 bit dma bus address which is not usable by the device. How can get around this problem? Any suggestion will be helpful and greatly appreciated.

          Best Regards,

          Ying
          • 2. Re: Supporting 31 bit dma_attr_addr_hi address
            807567
            try using 24bit mask.
            • 3. Re: Supporting 31 bit dma_attr_addr_hi address
              807567
              tried the 24bit mask 0x00ffffff and got the same error.

              Thanks,

              Ying