ath6kl: add back beginnings of USB support
[cascardo/linux.git] / drivers / net / wireless / ath / ath6kl / bmi.c
index a962fe4..aef00d5 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,14 +51,20 @@ 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,
-                                 sizeof(targ_info->version));
+       if (ar->hif_type == ATH6KL_HIF_TYPE_USB) {
+               ret = ath6kl_hif_bmi_read(ar, (u8 *)targ_info,
+                                         sizeof(*targ_info));
+       } else {
+               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);
                return ret;
@@ -225,7 +72,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 +91,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) -
@@ -276,8 +123,8 @@ int ath6kl_bmi_read(struct ath6kl *ar, u32 addr, u8 *buf, u32 len)
                return -EACCES;
        }
 
-       size = BMI_DATASZ_MAX + sizeof(cid) + sizeof(addr) + sizeof(len);
-       if (size > MAX_BMI_CMDBUF_SZ) {
+       size = ar->bmi.max_data_size + sizeof(cid) + sizeof(addr) + sizeof(len);
+       if (size > ar->bmi.max_cmd_size) {
                WARN_ON(1);
                return -EINVAL;
        }
@@ -290,8 +137,8 @@ int ath6kl_bmi_read(struct ath6kl *ar, u32 addr, u8 *buf, u32 len)
        len_remain = len;
 
        while (len_remain) {
-               rx_len = (len_remain < BMI_DATASZ_MAX) ?
-                                       len_remain : BMI_DATASZ_MAX;
+               rx_len = (len_remain < ar->bmi.max_data_size) ?
+                                       len_remain : ar->bmi.max_data_size;
                offset = 0;
                memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid));
                offset += sizeof(cid);
@@ -300,13 +147,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);
@@ -326,7 +173,7 @@ int ath6kl_bmi_write(struct ath6kl *ar, u32 addr, u8 *buf, u32 len)
        u32 offset;
        u32 len_remain, tx_len;
        const u32 header = sizeof(cid) + sizeof(addr) + sizeof(len);
-       u8 aligned_buf[BMI_DATASZ_MAX];
+       u8 aligned_buf[400];
        u8 *src;
 
        if (ar->bmi.done_sent) {
@@ -334,12 +181,15 @@ int ath6kl_bmi_write(struct ath6kl *ar, u32 addr, u8 *buf, u32 len)
                return -EACCES;
        }
 
-       if ((BMI_DATASZ_MAX + header) > MAX_BMI_CMDBUF_SZ) {
+       if ((ar->bmi.max_data_size + header) > ar->bmi.max_cmd_size) {
                WARN_ON(1);
                return -EINVAL;
        }
 
-       memset(ar->bmi.cmd_buf, 0, BMI_DATASZ_MAX + header);
+       if (WARN_ON(ar->bmi.max_data_size > sizeof(aligned_buf)))
+               return -E2BIG;
+
+       memset(ar->bmi.cmd_buf, 0, ar->bmi.max_data_size + header);
 
        ath6kl_dbg(ATH6KL_DBG_BMI,
                  "bmi write memory: addr: 0x%x, len: %d\n", addr, len);
@@ -348,7 +198,7 @@ int ath6kl_bmi_write(struct ath6kl *ar, u32 addr, u8 *buf, u32 len)
        while (len_remain) {
                src = &buf[len - len_remain];
 
-               if (len_remain < (BMI_DATASZ_MAX - header)) {
+               if (len_remain < (ar->bmi.max_data_size - header)) {
                        if (len_remain & 3) {
                                /* align it with 4 bytes */
                                len_remain = len_remain +
@@ -358,7 +208,7 @@ int ath6kl_bmi_write(struct ath6kl *ar, u32 addr, u8 *buf, u32 len)
                        }
                        tx_len = len_remain;
                } else {
-                       tx_len = (BMI_DATASZ_MAX - header);
+                       tx_len = (ar->bmi.max_data_size - header);
                }
 
                offset = 0;
@@ -371,7 +221,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);
@@ -396,7 +246,7 @@ int ath6kl_bmi_execute(struct ath6kl *ar, u32 addr, u32 *param)
        }
 
        size = sizeof(cid) + sizeof(addr) + sizeof(param);
-       if (size > MAX_BMI_CMDBUF_SZ) {
+       if (size > ar->bmi.max_cmd_size) {
                WARN_ON(1);
                return -EINVAL;
        }
@@ -413,13 +263,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;
@@ -443,7 +293,7 @@ int ath6kl_bmi_set_app_start(struct ath6kl *ar, u32 addr)
        }
 
        size = sizeof(cid) + sizeof(addr);
-       if (size > MAX_BMI_CMDBUF_SZ) {
+       if (size > ar->bmi.max_cmd_size) {
                WARN_ON(1);
                return -EINVAL;
        }
@@ -457,7 +307,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;
@@ -479,7 +329,7 @@ int ath6kl_bmi_reg_read(struct ath6kl *ar, u32 addr, u32 *param)
        }
 
        size = sizeof(cid) + sizeof(addr);
-       if (size > MAX_BMI_CMDBUF_SZ) {
+       if (size > ar->bmi.max_cmd_size) {
                WARN_ON(1);
                return -EINVAL;
        }
@@ -493,13 +343,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;
@@ -522,7 +372,7 @@ int ath6kl_bmi_reg_write(struct ath6kl *ar, u32 addr, u32 param)
        }
 
        size = sizeof(cid) + sizeof(addr) + sizeof(param);
-       if (size > MAX_BMI_CMDBUF_SZ) {
+       if (size > ar->bmi.max_cmd_size) {
                WARN_ON(1);
                return -EINVAL;
        }
@@ -540,7 +390,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;
@@ -563,8 +413,8 @@ int ath6kl_bmi_lz_data(struct ath6kl *ar, u8 *buf, u32 len)
                return -EACCES;
        }
 
-       size = BMI_DATASZ_MAX + header;
-       if (size > MAX_BMI_CMDBUF_SZ) {
+       size = ar->bmi.max_data_size + header;
+       if (size > ar->bmi.max_cmd_size) {
                WARN_ON(1);
                return -EINVAL;
        }
@@ -575,8 +425,8 @@ int ath6kl_bmi_lz_data(struct ath6kl *ar, u8 *buf, u32 len)
 
        len_remain = len;
        while (len_remain) {
-               tx_len = (len_remain < (BMI_DATASZ_MAX - header)) ?
-                         len_remain : (BMI_DATASZ_MAX - header);
+               tx_len = (len_remain < (ar->bmi.max_data_size - header)) ?
+                         len_remain : (ar->bmi.max_data_size - header);
 
                offset = 0;
                memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid));
@@ -587,7 +437,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);
@@ -613,7 +463,7 @@ int ath6kl_bmi_lz_stream_start(struct ath6kl *ar, u32 addr)
        }
 
        size = sizeof(cid) + sizeof(addr);
-       if (size > MAX_BMI_CMDBUF_SZ) {
+       if (size > ar->bmi.max_cmd_size) {
                WARN_ON(1);
                return -EINVAL;
        }
@@ -629,7 +479,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);
@@ -677,8 +527,13 @@ void ath6kl_bmi_reset(struct ath6kl *ar)
 
 int ath6kl_bmi_init(struct ath6kl *ar)
 {
-       ar->bmi.cmd_buf = kzalloc(MAX_BMI_CMDBUF_SZ, GFP_ATOMIC);
+       if (WARN_ON(ar->bmi.max_data_size == 0))
+               return -EINVAL;
+
+       /* cmd + addr + len + data_size */
+       ar->bmi.max_cmd_size = ar->bmi.max_data_size + (sizeof(u32) * 3);
 
+       ar->bmi.cmd_buf = kzalloc(ar->bmi.max_cmd_size, GFP_ATOMIC);
        if (!ar->bmi.cmd_buf)
                return -ENOMEM;