2013-03-08 10:26:52

by Kalle Valo

[permalink] [raw]
Subject: [PATCH 0/3] ath6kl: fix usb warm reboot and cleanups

While looking at the usb warm reboot I had to some cleanup, especially with error
handling.

---

Kalle Valo (3):
ath6kl: cleanup ath6kl_reset_device()
ath6kl: fix usb related error handling and warnings
ath6kl: cold reset target after host warm boot


drivers/net/wireless/ath/ath6kl/core.h | 2 --
drivers/net/wireless/ath/ath6kl/htc_pipe.c | 12 +++++----
drivers/net/wireless/ath/ath6kl/init.c | 37 +++++++++++++++++++---------
drivers/net/wireless/ath/ath6kl/main.c | 33 -------------------------
drivers/net/wireless/ath/ath6kl/target.h | 2 +-
drivers/net/wireless/ath/ath6kl/usb.c | 34 +++++++++++++++++---------
6 files changed, 54 insertions(+), 66 deletions(-)



2013-03-08 10:26:59

by Kalle Valo

[permalink] [raw]
Subject: [PATCH 1/3] ath6kl: cleanup ath6kl_reset_device()

Move it to init.c, make it static, remove all useless checks and force it to always do cold reset.

Signed-off-by: Kalle Valo <[email protected]>
---
drivers/net/wireless/ath/ath6kl/core.h | 2 --
drivers/net/wireless/ath/ath6kl/init.c | 12 ++++++++---
drivers/net/wireless/ath/ath6kl/main.c | 33 ------------------------------
drivers/net/wireless/ath/ath6kl/target.h | 2 +-
4 files changed, 10 insertions(+), 39 deletions(-)

diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h
index 1c9ed40..26b0f92 100644
--- a/drivers/net/wireless/ath/ath6kl/core.h
+++ b/drivers/net/wireless/ath/ath6kl/core.h
@@ -935,8 +935,6 @@ void aggr_recv_addba_req_evt(struct ath6kl_vif *vif, u8 tid, u16 seq_no,
u8 win_sz);
void ath6kl_wakeup_event(void *dev);

-void ath6kl_reset_device(struct ath6kl *ar, u32 target_type,
- bool wait_fot_compltn, bool cold_reset);
void ath6kl_init_control_info(struct ath6kl_vif *vif);
struct ath6kl_vif *ath6kl_vif_first(struct ath6kl *ar);
void ath6kl_cfg80211_vif_stop(struct ath6kl_vif *vif, bool wmi_ready);
diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c
index 3e45adc..ae1e477 100644
--- a/drivers/net/wireless/ath/ath6kl/init.c
+++ b/drivers/net/wireless/ath/ath6kl/init.c
@@ -1619,6 +1619,14 @@ static void ath6kl_init_get_fwcaps(struct ath6kl *ar, char *buf, size_t buf_len)
buf[len] = '\0';
}

+static int ath6kl_init_hw_reset(struct ath6kl *ar)
+{
+ ath6kl_dbg(ATH6KL_DBG_BOOT, "cold resetting the device");
+
+ return ath6kl_diag_write32(ar, RESET_CONTROL_ADDRESS,
+ cpu_to_le32(RESET_CONTROL_COLD_RST));
+}
+
static int __ath6kl_init_hw_start(struct ath6kl *ar)
{
long timeleft;
@@ -1836,9 +1844,7 @@ void ath6kl_stop_txrx(struct ath6kl *ar)
* Try to reset the device if we can. The driver may have been
* configure NOT to reset the target during a debug session.
*/
- ath6kl_dbg(ATH6KL_DBG_TRC,
- "attempting to reset target on instance destroy\n");
- ath6kl_reset_device(ar, ar->target_type, true, true);
+ ath6kl_init_hw_reset(ar);

up(&ar->sem);
}
diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c
index bd50b6b..bad62b3 100644
--- a/drivers/net/wireless/ath/ath6kl/main.c
+++ b/drivers/net/wireless/ath/ath6kl/main.c
@@ -345,39 +345,6 @@ out:
return ret;
}

-/* FIXME: move to a better place, target.h? */
-#define AR6003_RESET_CONTROL_ADDRESS 0x00004000
-#define AR6004_RESET_CONTROL_ADDRESS 0x00004000
-
-void ath6kl_reset_device(struct ath6kl *ar, u32 target_type,
- bool wait_fot_compltn, bool cold_reset)
-{
- int status = 0;
- u32 address;
- __le32 data;
-
- if (target_type != TARGET_TYPE_AR6003 &&
- target_type != TARGET_TYPE_AR6004)
- return;
-
- data = cold_reset ? cpu_to_le32(RESET_CONTROL_COLD_RST) :
- cpu_to_le32(RESET_CONTROL_MBOX_RST);
-
- switch (target_type) {
- case TARGET_TYPE_AR6003:
- address = AR6003_RESET_CONTROL_ADDRESS;
- break;
- case TARGET_TYPE_AR6004:
- address = AR6004_RESET_CONTROL_ADDRESS;
- break;
- }
-
- status = ath6kl_diag_write32(ar, address, data);
-
- if (status)
- ath6kl_err("failed to reset target\n");
-}
-
static void ath6kl_install_static_wep_keys(struct ath6kl_vif *vif)
{
u8 index;
diff --git a/drivers/net/wireless/ath/ath6kl/target.h b/drivers/net/wireless/ath/ath6kl/target.h
index a98c12b..a580a62 100644
--- a/drivers/net/wireless/ath/ath6kl/target.h
+++ b/drivers/net/wireless/ath/ath6kl/target.h
@@ -25,7 +25,7 @@
#define AR6004_BOARD_DATA_SZ 6144
#define AR6004_BOARD_EXT_DATA_SZ 0

-#define RESET_CONTROL_ADDRESS 0x00000000
+#define RESET_CONTROL_ADDRESS 0x00004000
#define RESET_CONTROL_COLD_RST 0x00000100
#define RESET_CONTROL_MBOX_RST 0x00000004



2013-03-08 10:27:08

by Kalle Valo

[permalink] [raw]
Subject: [PATCH 2/3] ath6kl: fix usb related error handling and warnings

It was annoying to debug usb warm reboot initialisation problems as many usb related functions
just ignored errors and it wasn't obvious from the kernel logs what was failing. Fix all that
so that error messages are printed and errors are handled properly.

Signed-off-by: Kalle Valo <[email protected]>
---
drivers/net/wireless/ath/ath6kl/htc_pipe.c | 10 ++++----
drivers/net/wireless/ath/ath6kl/init.c | 10 +++++---
drivers/net/wireless/ath/ath6kl/usb.c | 34 ++++++++++++++++++----------
3 files changed, 33 insertions(+), 21 deletions(-)

diff --git a/drivers/net/wireless/ath/ath6kl/htc_pipe.c b/drivers/net/wireless/ath/ath6kl/htc_pipe.c
index 9adb567..c02d9d3 100644
--- a/drivers/net/wireless/ath/ath6kl/htc_pipe.c
+++ b/drivers/net/wireless/ath/ath6kl/htc_pipe.c
@@ -1167,7 +1167,7 @@ static int htc_wait_recv_ctrl_message(struct htc_target *target)
}

if (count <= 0) {
- ath6kl_dbg(ATH6KL_DBG_HTC, "%s: Timeout!\n", __func__);
+ ath6kl_warn("htc pipe control receive timeout!\n");
return -ECOMM;
}

@@ -1581,16 +1581,16 @@ static int ath6kl_htc_pipe_wait_target(struct htc_target *target)
return status;

if (target->pipe.ctrl_response_len < sizeof(*ready_msg)) {
- ath6kl_dbg(ATH6KL_DBG_HTC, "invalid htc ready msg len:%d!\n",
- target->pipe.ctrl_response_len);
+ ath6kl_warn("invalid htc pipe ready msg len: %d\n",
+ target->pipe.ctrl_response_len);
return -ECOMM;
}

ready_msg = (struct htc_ready_ext_msg *) target->pipe.ctrl_response_buf;

if (ready_msg->ver2_0_info.msg_id != cpu_to_le16(HTC_MSG_READY_ID)) {
- ath6kl_dbg(ATH6KL_DBG_HTC, "invalid htc ready msg : 0x%X !\n",
- ready_msg->ver2_0_info.msg_id);
+ ath6kl_warn("invalid htc pipe ready msg: 0x%x\n",
+ ready_msg->ver2_0_info.msg_id);
return -ECOMM;
}

diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c
index ae1e477..8b01ec3 100644
--- a/drivers/net/wireless/ath/ath6kl/init.c
+++ b/drivers/net/wireless/ath/ath6kl/init.c
@@ -1657,13 +1657,15 @@ static int __ath6kl_init_hw_start(struct ath6kl *ar)
* driver layer has to init BMI in order to set the host block
* size.
*/
- if (ath6kl_htc_wait_target(ar->htc_target)) {
- ret = -EIO;
+ ret = ath6kl_htc_wait_target(ar->htc_target);
+ if (ret) {
+ ath6kl_err("htc wait target failed: %d\n", ret);
goto err_power_off;
}

- if (ath6kl_init_service_ep(ar)) {
- ret = -EIO;
+ ret = ath6kl_init_service_ep(ar);
+ if (ret) {
+ ath6kl_err("Endpoint service initilisation failed: %d\n", ret);
goto err_cleanup_scatter;
}

diff --git a/drivers/net/wireless/ath/ath6kl/usb.c b/drivers/net/wireless/ath/ath6kl/usb.c
index 5fcd342..63948f6 100644
--- a/drivers/net/wireless/ath/ath6kl/usb.c
+++ b/drivers/net/wireless/ath/ath6kl/usb.c
@@ -872,8 +872,9 @@ static int ath6kl_usb_submit_ctrl_out(struct ath6kl_usb *ar_usb,
size, 1000);

if (ret < 0) {
- ath6kl_dbg(ATH6KL_DBG_USB, "%s failed,result = %d\n",
- __func__, ret);
+ ath6kl_warn("Failed to submit usb control message: %d\n", ret);
+ kfree(buf);
+ return ret;
}

kfree(buf);
@@ -903,8 +904,9 @@ static int ath6kl_usb_submit_ctrl_in(struct ath6kl_usb *ar_usb,
size, 2 * HZ);

if (ret < 0) {
- ath6kl_dbg(ATH6KL_DBG_USB, "%s failed,result = %d\n",
- __func__, ret);
+ ath6kl_warn("Failed to read usb control message: %d\n", ret);
+ kfree(buf);
+ return ret;
}

memcpy((u8 *) data, buf, size);
@@ -961,8 +963,10 @@ static int ath6kl_usb_diag_read32(struct ath6kl *ar, u32 address, u32 *data)
ATH6KL_USB_CONTROL_REQ_DIAG_RESP,
ar_usb->diag_resp_buffer, &resp_len);

- if (ret)
+ if (ret) {
+ ath6kl_warn("diag read32 failed: %d\n", ret);
return ret;
+ }

resp = (struct ath6kl_usb_ctrl_diag_resp_read *)
ar_usb->diag_resp_buffer;
@@ -976,6 +980,7 @@ static int ath6kl_usb_diag_write32(struct ath6kl *ar, u32 address, __le32 data)
{
struct ath6kl_usb *ar_usb = ar->hif_priv;
struct ath6kl_usb_ctrl_diag_cmd_write *cmd;
+ int ret;

cmd = (struct ath6kl_usb_ctrl_diag_cmd_write *) ar_usb->diag_cmd_buffer;

@@ -984,12 +989,17 @@ static int ath6kl_usb_diag_write32(struct ath6kl *ar, u32 address, __le32 data)
cmd->address = cpu_to_le32(address);
cmd->value = data;

- return ath6kl_usb_ctrl_msg_exchange(ar_usb,
- ATH6KL_USB_CONTROL_REQ_DIAG_CMD,
- (u8 *) cmd,
- sizeof(*cmd),
- 0, NULL, NULL);
+ ret = ath6kl_usb_ctrl_msg_exchange(ar_usb,
+ ATH6KL_USB_CONTROL_REQ_DIAG_CMD,
+ (u8 *) cmd,
+ sizeof(*cmd),
+ 0, NULL, NULL);
+ if (ret) {
+ ath6kl_warn("diag_write32 failed: %d\n", ret);
+ return ret;
+ }

+ return 0;
}

static int ath6kl_usb_bmi_read(struct ath6kl *ar, u8 *buf, u32 len)
@@ -1001,7 +1011,7 @@ static int ath6kl_usb_bmi_read(struct ath6kl *ar, u8 *buf, u32 len)
ret = ath6kl_usb_submit_ctrl_in(ar_usb,
ATH6KL_USB_CONTROL_REQ_RECV_BMI_RESP,
0, 0, buf, len);
- if (ret != 0) {
+ if (ret) {
ath6kl_err("Unable to read the bmi data from the device: %d\n",
ret);
return ret;
@@ -1019,7 +1029,7 @@ static int ath6kl_usb_bmi_write(struct ath6kl *ar, u8 *buf, u32 len)
ret = ath6kl_usb_submit_ctrl_out(ar_usb,
ATH6KL_USB_CONTROL_REQ_SEND_BMI_CMD,
0, 0, buf, len);
- if (ret != 0) {
+ if (ret) {
ath6kl_err("unable to send the bmi data to the device: %d\n",
ret);
return ret;


2013-03-09 05:59:06

by Kalle Valo

[permalink] [raw]
Subject: Re: [PATCH 3/3] ath6kl: cold reset target after host warm boot

Kalle Valo <[email protected]> writes:

> Julien reported that ar6004 usb device fails to initialise after host has been rebooted and
> power is still on for the ar6004 device. He found out that doing a cold reset fixes the issue.
>
> I wasn't sure what would be the best way to detect if target needs a reset so I settled on
> checking a timeout from htc_wait_recv_ctrl_message().
>
> Reported-by: Julien Massot <[email protected]>
> Signed-off-by: Kalle Valo <[email protected]>

I need to fix my line wrapping, the lines are too long now.

> @@ -1842,12 +1853,6 @@ void ath6kl_stop_txrx(struct ath6kl *ar)
> ath6kl_htc_stop(ar->htc_target);
> }
>
> - /*
> - * Try to reset the device if we can. The driver may have been
> - * configure NOT to reset the target during a debug session.
> - */
> - ath6kl_init_hw_reset(ar);
> -

This shouldn't be there and most likely causes an regression. I'll send
v2 later.

--
Kalle Valo

2013-03-08 10:27:14

by Kalle Valo

[permalink] [raw]
Subject: [PATCH 3/3] ath6kl: cold reset target after host warm boot

Julien reported that ar6004 usb device fails to initialise after host has been rebooted and
power is still on for the ar6004 device. He found out that doing a cold reset fixes the issue.

I wasn't sure what would be the best way to detect if target needs a reset so I settled on
checking a timeout from htc_wait_recv_ctrl_message().

Reported-by: Julien Massot <[email protected]>
Signed-off-by: Kalle Valo <[email protected]>
---
drivers/net/wireless/ath/ath6kl/htc_pipe.c | 2 +-
drivers/net/wireless/ath/ath6kl/init.c | 19 ++++++++++++-------
2 files changed, 13 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wireless/ath/ath6kl/htc_pipe.c b/drivers/net/wireless/ath/ath6kl/htc_pipe.c
index c02d9d3..67aa924 100644
--- a/drivers/net/wireless/ath/ath6kl/htc_pipe.c
+++ b/drivers/net/wireless/ath/ath6kl/htc_pipe.c
@@ -1168,7 +1168,7 @@ static int htc_wait_recv_ctrl_message(struct htc_target *target)

if (count <= 0) {
ath6kl_warn("htc pipe control receive timeout!\n");
- return -ECOMM;
+ return -ETIMEDOUT;
}

return 0;
diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c
index 8b01ec3..ecf196f 100644
--- a/drivers/net/wireless/ath/ath6kl/init.c
+++ b/drivers/net/wireless/ath/ath6kl/init.c
@@ -1658,7 +1658,18 @@ static int __ath6kl_init_hw_start(struct ath6kl *ar)
* size.
*/
ret = ath6kl_htc_wait_target(ar->htc_target);
- if (ret) {
+
+ if (ret == -ETIMEDOUT) {
+ /*
+ * Most likely USB target is in odd state after reboot and
+ * needs a reset. A cold reset makes the whole device
+ * disappear from USB bus and initialisation starts from
+ * beginning.
+ */
+ ath6kl_warn("htc wait target timed out, resetting device\n");
+ ath6kl_init_hw_reset(ar);
+ goto err_power_off;
+ } else if (ret) {
ath6kl_err("htc wait target failed: %d\n", ret);
goto err_power_off;
}
@@ -1842,12 +1853,6 @@ void ath6kl_stop_txrx(struct ath6kl *ar)
ath6kl_htc_stop(ar->htc_target);
}

- /*
- * Try to reset the device if we can. The driver may have been
- * configure NOT to reset the target during a debug session.
- */
- ath6kl_init_hw_reset(ar);
-
up(&ar->sem);
}
EXPORT_SYMBOL(ath6kl_stop_txrx);