ath6kl: move bmi calls to hif driver
authorKalle Valo <kvalo@qca.qualcomm.com>
Fri, 11 Nov 2011 10:17:33 +0000 (12:17 +0200)
committerKalle Valo <kvalo@qca.qualcomm.com>
Sun, 13 Nov 2011 10:34:29 +0000 (12:34 +0200)
In preparation for USB support which has it's own method for bmi.

Based on code by Kevin Fang.

Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
drivers/net/wireless/ath/ath6kl/bmi.c
drivers/net/wireless/ath/ath6kl/hif-ops.h
drivers/net/wireless/ath/ath6kl/hif.h
drivers/net/wireless/ath/ath6kl/sdio.c

index a962fe4..12f5b57 100644 (file)
 #include "target.h"
 #include "debug.h"
 
-static int ath6kl_get_bmi_cmd_credits(struct ath6kl *ar)
-{
-       u32 addr;
-       unsigned long timeout;
-       int ret;
-
-       ar->bmi.cmd_credits = 0;
-
-       /* Read the counter register to get the command credits */
-       addr = COUNT_DEC_ADDRESS + (HTC_MAILBOX_NUM_MAX + ENDPOINT1) * 4;
-
-       timeout = jiffies + msecs_to_jiffies(BMI_COMMUNICATION_TIMEOUT);
-       while (time_before(jiffies, timeout) && !ar->bmi.cmd_credits) {
-
-               /*
-                * Hit the credit counter with a 4-byte access, the first byte
-                * read will hit the counter and cause a decrement, while the
-                * remaining 3 bytes has no effect. The rationale behind this
-                * is to make all HIF accesses 4-byte aligned.
-                */
-               ret = hif_read_write_sync(ar, addr,
-                                        (u8 *)&ar->bmi.cmd_credits, 4,
-                                        HIF_RD_SYNC_BYTE_INC);
-               if (ret) {
-                       ath6kl_err("Unable to decrement the command credit count register: %d\n",
-                                  ret);
-                       return ret;
-               }
-
-               /* The counter is only 8 bits.
-                * Ignore anything in the upper 3 bytes
-                */
-               ar->bmi.cmd_credits &= 0xFF;
-       }
-
-       if (!ar->bmi.cmd_credits) {
-               ath6kl_err("bmi communication timeout\n");
-               return -ETIMEDOUT;
-       }
-
-       return 0;
-}
-
-static int ath6kl_bmi_get_rx_lkahd(struct ath6kl *ar)
-{
-       unsigned long timeout;
-       u32 rx_word = 0;
-       int ret = 0;
-
-       timeout = jiffies + msecs_to_jiffies(BMI_COMMUNICATION_TIMEOUT);
-       while (time_before(jiffies, timeout) && !rx_word) {
-               ret = hif_read_write_sync(ar, RX_LOOKAHEAD_VALID_ADDRESS,
-                                         (u8 *)&rx_word, sizeof(rx_word),
-                                         HIF_RD_SYNC_BYTE_INC);
-               if (ret) {
-                       ath6kl_err("unable to read RX_LOOKAHEAD_VALID\n");
-                       return ret;
-               }
-
-                /* all we really want is one bit */
-               rx_word &= (1 << ENDPOINT1);
-       }
-
-       if (!rx_word) {
-               ath6kl_err("bmi_recv_buf FIFO empty\n");
-               return -EINVAL;
-       }
-
-       return ret;
-}
-
-static int ath6kl_bmi_send_buf(struct ath6kl *ar, u8 *buf, u32 len)
-{
-       int ret;
-       u32 addr;
-
-       ret = ath6kl_get_bmi_cmd_credits(ar);
-       if (ret)
-               return ret;
-
-       addr = ar->mbox_info.htc_addr;
-
-       ret = hif_read_write_sync(ar, addr, buf, len,
-                                 HIF_WR_SYNC_BYTE_INC);
-       if (ret)
-               ath6kl_err("unable to send the bmi data to the device\n");
-
-       return ret;
-}
-
-static int ath6kl_bmi_recv_buf(struct ath6kl *ar, u8 *buf, u32 len)
-{
-       int ret;
-       u32 addr;
-
-       /*
-        * During normal bootup, small reads may be required.
-        * Rather than issue an HIF Read and then wait as the Target
-        * adds successive bytes to the FIFO, we wait here until
-        * we know that response data is available.
-        *
-        * This allows us to cleanly timeout on an unexpected
-        * Target failure rather than risk problems at the HIF level.
-        * In particular, this avoids SDIO timeouts and possibly garbage
-        * data on some host controllers.  And on an interconnect
-        * such as Compact Flash (as well as some SDIO masters) which
-        * does not provide any indication on data timeout, it avoids
-        * a potential hang or garbage response.
-        *
-        * Synchronization is more difficult for reads larger than the
-        * size of the MBOX FIFO (128B), because the Target is unable
-        * to push the 129th byte of data until AFTER the Host posts an
-        * HIF Read and removes some FIFO data.  So for large reads the
-        * Host proceeds to post an HIF Read BEFORE all the data is
-        * actually available to read.  Fortunately, large BMI reads do
-        * not occur in practice -- they're supported for debug/development.
-        *
-        * So Host/Target BMI synchronization is divided into these cases:
-        *  CASE 1: length < 4
-        *        Should not happen
-        *
-        *  CASE 2: 4 <= length <= 128
-        *        Wait for first 4 bytes to be in FIFO
-        *        If CONSERVATIVE_BMI_READ is enabled, also wait for
-        *        a BMI command credit, which indicates that the ENTIRE
-        *        response is available in the the FIFO
-        *
-        *  CASE 3: length > 128
-        *        Wait for the first 4 bytes to be in FIFO
-        *
-        * For most uses, a small timeout should be sufficient and we will
-        * usually see a response quickly; but there may be some unusual
-        * (debug) cases of BMI_EXECUTE where we want an larger timeout.
-        * For now, we use an unbounded busy loop while waiting for
-        * BMI_EXECUTE.
-        *
-        * If BMI_EXECUTE ever needs to support longer-latency execution,
-        * especially in production, this code needs to be enhanced to sleep
-        * and yield.  Also note that BMI_COMMUNICATION_TIMEOUT is currently
-        * a function of Host processor speed.
-        */
-       if (len >= 4) { /* NB: Currently, always true */
-               ret = ath6kl_bmi_get_rx_lkahd(ar);
-               if (ret)
-                       return ret;
-       }
-
-       addr = ar->mbox_info.htc_addr;
-       ret = hif_read_write_sync(ar, addr, buf, len,
-                                 HIF_RD_SYNC_BYTE_INC);
-       if (ret) {
-               ath6kl_err("Unable to read the bmi data from the device: %d\n",
-                          ret);
-               return ret;
-       }
-
-       return 0;
-}
-
 int ath6kl_bmi_done(struct ath6kl *ar)
 {
        int ret;
@@ -190,7 +31,7 @@ int ath6kl_bmi_done(struct ath6kl *ar)
 
        ar->bmi.done_sent = true;
 
-       ret = ath6kl_bmi_send_buf(ar, (u8 *)&cid, sizeof(cid));
+       ret = ath6kl_hif_bmi_write(ar, (u8 *)&cid, sizeof(cid));
        if (ret) {
                ath6kl_err("Unable to send bmi done: %d\n", ret);
                return ret;
@@ -210,13 +51,13 @@ int ath6kl_bmi_get_target_info(struct ath6kl *ar,
                return -EACCES;
        }
 
-       ret = ath6kl_bmi_send_buf(ar, (u8 *)&cid, sizeof(cid));
+       ret = ath6kl_hif_bmi_write(ar, (u8 *)&cid, sizeof(cid));
        if (ret) {
                ath6kl_err("Unable to send get target info: %d\n", ret);
                return ret;
        }
 
-       ret = ath6kl_bmi_recv_buf(ar, (u8 *)&targ_info->version,
+       ret = ath6kl_hif_bmi_read(ar, (u8 *)&targ_info->version,
                                  sizeof(targ_info->version));
        if (ret) {
                ath6kl_err("Unable to recv target info: %d\n", ret);
@@ -225,7 +66,7 @@ int ath6kl_bmi_get_target_info(struct ath6kl *ar,
 
        if (le32_to_cpu(targ_info->version) == TARGET_VERSION_SENTINAL) {
                /* Determine how many bytes are in the Target's targ_info */
-               ret = ath6kl_bmi_recv_buf(ar,
+               ret = ath6kl_hif_bmi_read(ar,
                                   (u8 *)&targ_info->byte_count,
                                   sizeof(targ_info->byte_count));
                if (ret) {
@@ -244,7 +85,7 @@ int ath6kl_bmi_get_target_info(struct ath6kl *ar,
                }
 
                /* Read the remainder of the targ_info */
-               ret = ath6kl_bmi_recv_buf(ar,
+               ret = ath6kl_hif_bmi_read(ar,
                                   ((u8 *)targ_info) +
                                   sizeof(targ_info->byte_count),
                                   sizeof(*targ_info) -
@@ -300,13 +141,13 @@ int ath6kl_bmi_read(struct ath6kl *ar, u32 addr, u8 *buf, u32 len)
                memcpy(&(ar->bmi.cmd_buf[offset]), &rx_len, sizeof(rx_len));
                offset += sizeof(len);
 
-               ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset);
+               ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset);
                if (ret) {
                        ath6kl_err("Unable to write to the device: %d\n",
                                   ret);
                        return ret;
                }
-               ret = ath6kl_bmi_recv_buf(ar, ar->bmi.cmd_buf, rx_len);
+               ret = ath6kl_hif_bmi_read(ar, ar->bmi.cmd_buf, rx_len);
                if (ret) {
                        ath6kl_err("Unable to read from the device: %d\n",
                                   ret);
@@ -371,7 +212,7 @@ int ath6kl_bmi_write(struct ath6kl *ar, u32 addr, u8 *buf, u32 len)
                memcpy(&(ar->bmi.cmd_buf[offset]), src, tx_len);
                offset += tx_len;
 
-               ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset);
+               ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset);
                if (ret) {
                        ath6kl_err("Unable to write to the device: %d\n",
                                   ret);
@@ -413,13 +254,13 @@ int ath6kl_bmi_execute(struct ath6kl *ar, u32 addr, u32 *param)
        memcpy(&(ar->bmi.cmd_buf[offset]), param, sizeof(*param));
        offset += sizeof(*param);
 
-       ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset);
+       ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset);
        if (ret) {
                ath6kl_err("Unable to write to the device: %d\n", ret);
                return ret;
        }
 
-       ret = ath6kl_bmi_recv_buf(ar, ar->bmi.cmd_buf, sizeof(*param));
+       ret = ath6kl_hif_bmi_read(ar, ar->bmi.cmd_buf, sizeof(*param));
        if (ret) {
                ath6kl_err("Unable to read from the device: %d\n", ret);
                return ret;
@@ -457,7 +298,7 @@ int ath6kl_bmi_set_app_start(struct ath6kl *ar, u32 addr)
        memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr));
        offset += sizeof(addr);
 
-       ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset);
+       ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset);
        if (ret) {
                ath6kl_err("Unable to write to the device: %d\n", ret);
                return ret;
@@ -493,13 +334,13 @@ int ath6kl_bmi_reg_read(struct ath6kl *ar, u32 addr, u32 *param)
        memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr));
        offset += sizeof(addr);
 
-       ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset);
+       ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset);
        if (ret) {
                ath6kl_err("Unable to write to the device: %d\n", ret);
                return ret;
        }
 
-       ret = ath6kl_bmi_recv_buf(ar, ar->bmi.cmd_buf, sizeof(*param));
+       ret = ath6kl_hif_bmi_read(ar, ar->bmi.cmd_buf, sizeof(*param));
        if (ret) {
                ath6kl_err("Unable to read from the device: %d\n", ret);
                return ret;
@@ -540,7 +381,7 @@ int ath6kl_bmi_reg_write(struct ath6kl *ar, u32 addr, u32 param)
        memcpy(&(ar->bmi.cmd_buf[offset]), &param, sizeof(param));
        offset += sizeof(param);
 
-       ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset);
+       ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset);
        if (ret) {
                ath6kl_err("Unable to write to the device: %d\n", ret);
                return ret;
@@ -587,7 +428,7 @@ int ath6kl_bmi_lz_data(struct ath6kl *ar, u8 *buf, u32 len)
                        tx_len);
                offset += tx_len;
 
-               ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset);
+               ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset);
                if (ret) {
                        ath6kl_err("Unable to write to the device: %d\n",
                                   ret);
@@ -629,7 +470,7 @@ int ath6kl_bmi_lz_stream_start(struct ath6kl *ar, u32 addr)
        memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr));
        offset += sizeof(addr);
 
-       ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset);
+       ret = ath6kl_hif_bmi_write(ar, ar->bmi.cmd_buf, offset);
        if (ret) {
                ath6kl_err("Unable to start LZ stream to the device: %d\n",
                           ret);
index eed2287..0c4c602 100644 (file)
@@ -91,6 +91,16 @@ static inline int ath6kl_hif_suspend(struct ath6kl *ar,
        return ar->hif_ops->suspend(ar, wow);
 }
 
+static inline int ath6kl_hif_bmi_read(struct ath6kl *ar, u8 *buf, u32 len)
+{
+       return ar->hif_ops->bmi_read(ar, buf, len);
+}
+
+static inline int ath6kl_hif_bmi_write(struct ath6kl *ar, u8 *buf, u32 len)
+{
+       return ar->hif_ops->bmi_write(ar, buf, len);
+}
+
 static inline int ath6kl_hif_resume(struct ath6kl *ar)
 {
        ath6kl_dbg(ATH6KL_DBG_HIF, "hif resume\n");
index f2dc3bc..42004e9 100644 (file)
@@ -244,6 +244,8 @@ struct ath6kl_hif_ops {
        void (*cleanup_scatter)(struct ath6kl *ar);
        int (*suspend)(struct ath6kl *ar, struct cfg80211_wowlan *wow);
        int (*resume)(struct ath6kl *ar);
+       int (*bmi_read)(struct ath6kl *ar, u8 *buf, u32 len);
+       int (*bmi_write)(struct ath6kl *ar, u8 *buf, u32 len);
        int (*power_on)(struct ath6kl *ar);
        int (*power_off)(struct ath6kl *ar);
        void (*stop)(struct ath6kl *ar);
index beb5f9b..080be03 100644 (file)
@@ -845,6 +845,166 @@ static int ath6kl_sdio_resume(struct ath6kl *ar)
        return 0;
 }
 
+static int ath6kl_sdio_bmi_credits(struct ath6kl *ar)
+{
+       u32 addr;
+       unsigned long timeout;
+       int ret;
+
+       ar->bmi.cmd_credits = 0;
+
+       /* Read the counter register to get the command credits */
+       addr = COUNT_DEC_ADDRESS + (HTC_MAILBOX_NUM_MAX + ENDPOINT1) * 4;
+
+       timeout = jiffies + msecs_to_jiffies(BMI_COMMUNICATION_TIMEOUT);
+       while (time_before(jiffies, timeout) && !ar->bmi.cmd_credits) {
+
+               /*
+                * Hit the credit counter with a 4-byte access, the first byte
+                * read will hit the counter and cause a decrement, while the
+                * remaining 3 bytes has no effect. The rationale behind this
+                * is to make all HIF accesses 4-byte aligned.
+                */
+               ret = ath6kl_sdio_read_write_sync(ar, addr,
+                                        (u8 *)&ar->bmi.cmd_credits, 4,
+                                        HIF_RD_SYNC_BYTE_INC);
+               if (ret) {
+                       ath6kl_err("Unable to decrement the command credit "
+                                               "count register: %d\n", ret);
+                       return ret;
+               }
+
+               /* The counter is only 8 bits.
+                * Ignore anything in the upper 3 bytes
+                */
+               ar->bmi.cmd_credits &= 0xFF;
+       }
+
+       if (!ar->bmi.cmd_credits) {
+               ath6kl_err("bmi communication timeout\n");
+               return -ETIMEDOUT;
+       }
+
+       return 0;
+}
+
+static int ath6kl_bmi_get_rx_lkahd(struct ath6kl *ar)
+{
+       unsigned long timeout;
+       u32 rx_word = 0;
+       int ret = 0;
+
+       timeout = jiffies + msecs_to_jiffies(BMI_COMMUNICATION_TIMEOUT);
+       while ((time_before(jiffies, timeout)) && !rx_word) {
+               ret = ath6kl_sdio_read_write_sync(ar,
+                                       RX_LOOKAHEAD_VALID_ADDRESS,
+                                       (u8 *)&rx_word, sizeof(rx_word),
+                                       HIF_RD_SYNC_BYTE_INC);
+               if (ret) {
+                       ath6kl_err("unable to read RX_LOOKAHEAD_VALID\n");
+                       return ret;
+               }
+
+                /* all we really want is one bit */
+               rx_word &= (1 << ENDPOINT1);
+       }
+
+       if (!rx_word) {
+               ath6kl_err("bmi_recv_buf FIFO empty\n");
+               return -EINVAL;
+       }
+
+       return ret;
+}
+
+static int ath6kl_sdio_bmi_write(struct ath6kl *ar, u8 *buf, u32 len)
+{
+       int ret;
+       u32 addr;
+
+       ret = ath6kl_sdio_bmi_credits(ar);
+       if (ret)
+               return ret;
+
+       addr = ar->mbox_info.htc_addr;
+
+       ret = ath6kl_sdio_read_write_sync(ar, addr, buf, len,
+                                         HIF_WR_SYNC_BYTE_INC);
+       if (ret)
+               ath6kl_err("unable to send the bmi data to the device\n");
+
+       return ret;
+}
+
+static int ath6kl_sdio_bmi_read(struct ath6kl *ar, u8 *buf, u32 len)
+{
+       int ret;
+       u32 addr;
+
+       /*
+        * During normal bootup, small reads may be required.
+        * Rather than issue an HIF Read and then wait as the Target
+        * adds successive bytes to the FIFO, we wait here until
+        * we know that response data is available.
+        *
+        * This allows us to cleanly timeout on an unexpected
+        * Target failure rather than risk problems at the HIF level.
+        * In particular, this avoids SDIO timeouts and possibly garbage
+        * data on some host controllers.  And on an interconnect
+        * such as Compact Flash (as well as some SDIO masters) which
+        * does not provide any indication on data timeout, it avoids
+        * a potential hang or garbage response.
+        *
+        * Synchronization is more difficult for reads larger than the
+        * size of the MBOX FIFO (128B), because the Target is unable
+        * to push the 129th byte of data until AFTER the Host posts an
+        * HIF Read and removes some FIFO data.  So for large reads the
+        * Host proceeds to post an HIF Read BEFORE all the data is
+        * actually available to read.  Fortunately, large BMI reads do
+        * not occur in practice -- they're supported for debug/development.
+        *
+        * So Host/Target BMI synchronization is divided into these cases:
+        *  CASE 1: length < 4
+        *        Should not happen
+        *
+        *  CASE 2: 4 <= length <= 128
+        *        Wait for first 4 bytes to be in FIFO
+        *        If CONSERVATIVE_BMI_READ is enabled, also wait for
+        *        a BMI command credit, which indicates that the ENTIRE
+        *        response is available in the the FIFO
+        *
+        *  CASE 3: length > 128
+        *        Wait for the first 4 bytes to be in FIFO
+        *
+        * For most uses, a small timeout should be sufficient and we will
+        * usually see a response quickly; but there may be some unusual
+        * (debug) cases of BMI_EXECUTE where we want an larger timeout.
+        * For now, we use an unbounded busy loop while waiting for
+        * BMI_EXECUTE.
+        *
+        * If BMI_EXECUTE ever needs to support longer-latency execution,
+        * especially in production, this code needs to be enhanced to sleep
+        * and yield.  Also note that BMI_COMMUNICATION_TIMEOUT is currently
+        * a function of Host processor speed.
+        */
+       if (len >= 4) { /* NB: Currently, always true */
+               ret = ath6kl_bmi_get_rx_lkahd(ar);
+               if (ret)
+                       return ret;
+       }
+
+       addr = ar->mbox_info.htc_addr;
+       ret = ath6kl_sdio_read_write_sync(ar, addr, buf, len,
+                                 HIF_RD_SYNC_BYTE_INC);
+       if (ret) {
+               ath6kl_err("Unable to read the bmi data from the device: %d\n",
+                          ret);
+               return ret;
+       }
+
+       return 0;
+}
+
 static void ath6kl_sdio_stop(struct ath6kl *ar)
 {
        struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
@@ -889,6 +1049,8 @@ static const struct ath6kl_hif_ops ath6kl_sdio_ops = {
        .cleanup_scatter = ath6kl_sdio_cleanup_scatter,
        .suspend = ath6kl_sdio_suspend,
        .resume = ath6kl_sdio_resume,
+       .bmi_read = ath6kl_sdio_bmi_read,
+       .bmi_write = ath6kl_sdio_bmi_write,
        .power_on = ath6kl_sdio_power_on,
        .power_off = ath6kl_sdio_power_off,
        .stop = ath6kl_sdio_stop,