/**
  @brief wpalReadDeviceMemory provides a mechansim for a client
         to read data from the hardware address space

  @param  address:  Start address of physical memory to be read
  @param  d_buffer: Virtual destination address to which the
                    data will be written
  @param  len:      Number of bytes of data to be read

  @return SUCCESS if the data was successfully read
*/
wpt_status wpalReadDeviceMemory
(
  wpt_uint32 address,
  wpt_uint8* d_buffer,
  wpt_uint32 len
)
{
   /* if SSR is in progress, and WCNSS is not out of reset (re-init
    * not invoked), then do not access WCNSS registers */
   if (NULL == gpEnv ||
        (vos_is_logp_in_progress(VOS_MODULE_ID_WDI, NULL) &&
            !vos_is_reinit_in_progress(VOS_MODULE_ID_WDI, NULL))) {
      WPAL_TRACE(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                 "%s: invoked before subsystem initialized",
                 __func__);
      return eWLAN_PAL_STATUS_E_INVAL;
   }

   if ((address < gpEnv->wcnss_memory->start) ||
       ((address + len) > gpEnv->wcnss_memory->end)) {
      WPAL_TRACE(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                 "%s: Memory address 0x%0x len %d out of range 0x%0x - 0x%0x",
                 __func__, address, len,
                 (u32) gpEnv->wcnss_memory->start,
                 (u32) gpEnv->wcnss_memory->end);
      return eWLAN_PAL_STATUS_E_INVAL;
   }

   memcpy(d_buffer, gpEnv->mmio + (address - WCNSS_BASE_ADDRESS), len);
   rmb();

   return eWLAN_PAL_STATUS_SUCCESS;
}
/**
  @brief wpalReadDeviceMemory provides a mechansim for a client
         to read data from the hardware address space

  @param  address:  Start address of physical memory to be read
  @param  d_buffer: Virtual destination address to which the
                    data will be written
  @param  len:      Number of bytes of data to be read

  @return SUCCESS if the data was successfully read
*/
wpt_status wpalReadDeviceMemory
(
  wpt_uint32 address,
  wpt_uint8* d_buffer,
  wpt_uint32 len
)
{
   if (NULL == gpEnv || wcnss_device_is_shutdown() ||
        (vos_is_logp_in_progress(VOS_MODULE_ID_WDI, NULL) &&
            !vos_is_reinit_in_progress(VOS_MODULE_ID_WDI, NULL))) {
      WPAL_TRACE(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                 "%s: invoked before subsystem initialized",
                 __func__);
      return eWLAN_PAL_STATUS_E_INVAL;
   }

   address = (address | gpEnv->wcnss_memory->start);

   if ((address < gpEnv->wcnss_memory->start) ||
       ((address + len) > gpEnv->wcnss_memory->end)) {
      WPAL_TRACE(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                 "%s: Memory address 0x%0x len %d out of range 0x%0x - 0x%0x",
                 __func__, address, len,
                 gpEnv->wcnss_memory->start, gpEnv->wcnss_memory->end);
      return eWLAN_PAL_STATUS_E_INVAL;
   }

   vos_mem_copy(d_buffer,
                   gpEnv->mmio + (address - gpEnv->wcnss_memory->start), len);
   rmb();

   return eWLAN_PAL_STATUS_SUCCESS;
}
/**
  @brief wpalReadRegister provides a mechansim for a client
         to read data from a hardware data register

  @param  address:  Physical memory address of the register
  @param  data:     Return location for value that is read

  @return SUCCESS if the data was successfully read
*/
wpt_status wpalReadRegister
(
   wpt_uint32   address,
   wpt_uint32  *data
)
{
   /* if SSR is in progress, and WCNSS is not out of reset (re-init
    * not invoked), then do not access WCNSS registers */
   if (NULL == gpEnv || wcnss_device_is_shutdown() ||
        (vos_is_logp_in_progress(VOS_MODULE_ID_WDI, NULL) &&
            !vos_is_reinit_in_progress(VOS_MODULE_ID_WDI, NULL))) {
       /* Ratelimit wpalReadRegister failure messages which
        * can flood serial console during improper system
        * initialization or wcnss_device in shutdown state.
        * wpalRegisterInterrupt() call to wpalReadRegister is
        * likely to cause flooding. */
       if (__ratelimit(&wpalReadRegister_rs)) {
           WPAL_TRACE(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                   "%s: invoked before subsystem initialized",
                   __func__);
       }
       return eWLAN_PAL_STATUS_E_INVAL;
   }

   address = (address | gpEnv->wcnss_memory->start);

   if ((address < gpEnv->wcnss_memory->start) ||
       (address > gpEnv->wcnss_memory->end)) {
      WPAL_TRACE(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                 "%s: Register address 0x%0x out of range 0x%0x - 0x%0x",
                 __func__, address,
                 (u32) gpEnv->wcnss_memory->start,
                 (u32) gpEnv->wcnss_memory->end);
      return eWLAN_PAL_STATUS_E_INVAL;
   }

   if (0 != (address & 0x3)) {
      WPAL_TRACE(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                 "%s: Register address 0x%0x is not word aligned",
                 __func__, address);
      return eWLAN_PAL_STATUS_E_INVAL;
   }

   *data = readl_relaxed(gpEnv->mmio + (address - gpEnv->wcnss_memory->start));
   rmb();

   return eWLAN_PAL_STATUS_SUCCESS;
}
/**
  @brief wpalWriteRegister provides a mechansim for a client
         to write data into a hardware data register

  @param  address:  Physical memory address of the register
  @param  data:     Data value to be written

  @return SUCCESS if the data was successfully written
*/
wpt_status wpalWriteRegister
(
   wpt_uint32   address,
   wpt_uint32   data
)
{
   /* if SSR is in progress, and WCNSS is not out of reset (re-init
    * not invoked), then do not access WCNSS registers */
   if (NULL == gpEnv || wcnss_device_is_shutdown() ||
        (vos_is_logp_in_progress(VOS_MODULE_ID_WDI, NULL) &&
            !vos_is_reinit_in_progress(VOS_MODULE_ID_WDI, NULL))) {
      WPAL_TRACE(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                 "%s: invoked before subsystem initialized",
                 __func__);
      return eWLAN_PAL_STATUS_E_INVAL;
   }

   address = (address | gpEnv->wcnss_memory->start);

   if ((address < gpEnv->wcnss_memory->start) ||
       (address > gpEnv->wcnss_memory->end)) {
      WPAL_TRACE(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                 "%s: Register address 0x%0x out of range 0x%0x - 0x%0x",
                 __func__, address,
                 (u32) gpEnv->wcnss_memory->start,
                 (u32) gpEnv->wcnss_memory->end);
      return eWLAN_PAL_STATUS_E_INVAL;
   }

   if (0 != (address & 0x3)) {
      WPAL_TRACE(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                 "%s: Register address 0x%0x is not word aligned",
                 __func__, address);
      return eWLAN_PAL_STATUS_E_INVAL;
   }

   wmb();
   writel_relaxed(data, gpEnv->mmio + (address - gpEnv->wcnss_memory->start));

   return eWLAN_PAL_STATUS_SUCCESS;
}
wpt_status wpalReadRegister
(
   wpt_uint32   address,
   wpt_uint32  *data
)
{
   if (NULL == gpEnv || wcnss_device_is_shutdown() ||
        (vos_is_logp_in_progress(VOS_MODULE_ID_WDI, NULL) &&
            !vos_is_reinit_in_progress(VOS_MODULE_ID_WDI, NULL))) {
      WPAL_TRACE(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                 "%s: invoked before subsystem initialized",
                 __func__);
      return eWLAN_PAL_STATUS_E_INVAL;
   }

   address = (address | gpEnv->wcnss_memory->start);

   if ((address < gpEnv->wcnss_memory->start) ||
       (address > gpEnv->wcnss_memory->end)) {
      WPAL_TRACE(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                 "%s: Register address 0x%0x out of range 0x%0x - 0x%0x",
                 __func__, address,
                 gpEnv->wcnss_memory->start, gpEnv->wcnss_memory->end);
      return eWLAN_PAL_STATUS_E_INVAL;
   }

   if (0 != (address & 0x3)) {
      WPAL_TRACE(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_ERROR,
                 "%s: Register address 0x%0x is not word aligned",
                 __func__, address);
      return eWLAN_PAL_STATUS_E_INVAL;
   }

   *data = readl_relaxed(gpEnv->mmio + (address - gpEnv->wcnss_memory->start));
   rmb();

   return eWLAN_PAL_STATUS_SUCCESS;
}