Re: [ath9k-devel] [PATCH v2 01/10] ath10k: decouple pci init/deinit logic
On 13/06/13 20:09, Kalle Valo wrote: So when booting the firwmware we call: hif_power_up() hif_start() and when we want to kill the firmware we do: hif_stop() hif_power_down() [...] You're right. I'll fix that. I noticed ath10k_pci_ce_init() also allocs host memory etc. If possible, in the future we might want to refactor the function into two: ath10k_pci_ce_init() and ath10k_pci_ce_start(). And the former would be called only from ath10k_pci_probe(). That way we would not need to do any memory allocation during start time. But no need to refactor it right now, this is good enough for the first implementation. There's also some an asymmetry here. We should be enabling/disabling irqs when we start/stop, shouldn't we? But then again we need interrupts _before_ start() for BMI phase, while it's a also a good idea to disable them upon stop(). We do stop CE interrupts by poking up device registers, but we don't unregister irq handlers. There might be a race in there that we're not aware of/observed yet. I'm thinking of having only 3 functions: start_bmi_phase, start_htc_phase, stop (that would handle either state transition). But that would require the aforementioned proper alloc/init/setup separation to be done first. -- Pozdrawiam / Best regards, Michal Kazior. ___ ath9k-devel mailing list ath9k-devel@lists.ath9k.org https://lists.ath9k.org/mailman/listinfo/ath9k-devel
Re: [ath9k-devel] [PATCH v2 01/10] ath10k: decouple pci init/deinit logic
Michal Kazior michal.kaz...@tieto.com writes: I noticed ath10k_pci_ce_init() also allocs host memory etc. If possible, in the future we might want to refactor the function into two: ath10k_pci_ce_init() and ath10k_pci_ce_start(). And the former would be called only from ath10k_pci_probe(). That way we would not need to do any memory allocation during start time. But no need to refactor it right now, this is good enough for the first implementation. There's also some an asymmetry here. We should be enabling/disabling irqs when we start/stop, shouldn't we? But then again we need interrupts _before_ start() for BMI phase, while it's a also a good idea to disable them upon stop(). We do stop CE interrupts by poking up device registers, but we don't unregister irq handlers. There might be a race in there that we're not aware of/observed yet. Hehe, our emails crossed. I was thinking exactly the same issue in my previous email. So I agree, disabling interrupts from host would be good to have. But that's again for the future. I'm thinking of having only 3 functions: start_bmi_phase, start_htc_phase, stop (that would handle either state transition). But that would require the aforementioned proper alloc/init/setup separation to be done first. Yeah, we can discuss about this later. -- Kalle Valo ___ ath9k-devel mailing list ath9k-devel@lists.ath9k.org https://lists.ath9k.org/mailman/listinfo/ath9k-devel
Re: [ath9k-devel] [PATCH v2 01/10] ath10k: decouple pci init/deinit logic
Michal Kazior michal.kaz...@tieto.com writes: Split logic that prepares the device for BMI phase/cleans up related resources. This is necessary for ath10k to be able to restart hw on the fly without reloading the module. Signed-off-by: Michal Kazior michal.kaz...@tieto.com Few comments: --- a/drivers/net/wireless/ath/ath10k/hif.h +++ b/drivers/net/wireless/ath/ath10k/hif.h @@ -46,8 +46,11 @@ struct ath10k_hif_ops { void *request, u32 request_len, void *response, u32 *response_len); + /* Post BMI phase, after FW is loaded. Starts regular operation */ int (*start)(struct ath10k *ar); + /* Clean up what start() did. This does not revert to BMI phase. If + * desired so, call deinit() and init() */ void (*stop)(struct ath10k *ar); int (*map_service_to_pipe)(struct ath10k *ar, u16 service_id, @@ -70,6 +73,13 @@ struct ath10k_hif_ops { struct ath10k_hif_cb *callbacks); u16 (*get_free_queue_number)(struct ath10k *ar, u8 pipe_id); + + /* Power up the device and enter BMI transfer mode for FW download */ + int (*init)(struct ath10k *ar); + + /* Power down the device and free up resources. stop() must be called + * before this if start() was called earlier */ + void (*deinit)(struct ath10k *ar); I think terminology is mixed here as well. To me init() does here a lot more than other init() functions in ath10k. Should we rename these to power_up() and power_down(), as how your documentation already uses those terms? So when booting the firwmware we call: hif_power_up() hif_start() and when we want to kill the firmware we do: hif_stop() hif_power_down() [...] +static int ath10k_pci_hif_init(struct ath10k *ar) +{ + int ret; + + /* + * Bring the target up cleanly. + * + * The target may be in an undefined state with an AUX-powered Target + * and a Host in WoW mode. If the Host crashes, loses power, or is + * restarted (without unloading the driver) then the Target is left + * (aux) powered and running. On a subsequent driver load, the Target + * is in an unexpected state. We try to catch that here in order to + * reset the Target and retry the probe. + */ + ath10k_pci_device_reset(ar); + + ret = ath10k_pci_reset_target(ar); + if (ret) + goto err; + + if (ath10k_target_ps) { + ath10k_dbg(ATH10K_DBG_PCI, on-chip power save enabled\n); + } else { + /* Force AWAKE forever */ + ath10k_dbg(ATH10K_DBG_PCI, on-chip power save disabled\n); + ath10k_do_pci_wake(ar); + } + + ret = ath10k_pci_ce_init(ar); + if (ret) + goto err_ps; I noticed ath10k_pci_ce_init() also allocs host memory etc. If possible, in the future we might want to refactor the function into two: ath10k_pci_ce_init() and ath10k_pci_ce_start(). And the former would be called only from ath10k_pci_probe(). That way we would not need to do any memory allocation during start time. But no need to refactor it right now, this is good enough for the first implementation. -- Kalle Valo ___ ath9k-devel mailing list ath9k-devel@lists.ath9k.org https://lists.ath9k.org/mailman/listinfo/ath9k-devel
[ath9k-devel] [PATCH v2 01/10] ath10k: decouple pci init/deinit logic
Split logic that prepares the device for BMI phase/cleans up related resources. This is necessary for ath10k to be able to restart hw on the fly without reloading the module. Signed-off-by: Michal Kazior michal.kaz...@tieto.com --- drivers/net/wireless/ath/ath10k/hif.h | 20 ++ drivers/net/wireless/ath/ath10k/pci.c | 110 + 2 files changed, 91 insertions(+), 39 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/hif.h b/drivers/net/wireless/ath/ath10k/hif.h index 010e265..3a257d1 100644 --- a/drivers/net/wireless/ath/ath10k/hif.h +++ b/drivers/net/wireless/ath/ath10k/hif.h @@ -46,8 +46,11 @@ struct ath10k_hif_ops { void *request, u32 request_len, void *response, u32 *response_len); + /* Post BMI phase, after FW is loaded. Starts regular operation */ int (*start)(struct ath10k *ar); + /* Clean up what start() did. This does not revert to BMI phase. If +* desired so, call deinit() and init() */ void (*stop)(struct ath10k *ar); int (*map_service_to_pipe)(struct ath10k *ar, u16 service_id, @@ -70,6 +73,13 @@ struct ath10k_hif_ops { struct ath10k_hif_cb *callbacks); u16 (*get_free_queue_number)(struct ath10k *ar, u8 pipe_id); + + /* Power up the device and enter BMI transfer mode for FW download */ + int (*init)(struct ath10k *ar); + + /* Power down the device and free up resources. stop() must be called +* before this if start() was called earlier */ + void (*deinit)(struct ath10k *ar); }; @@ -134,4 +144,14 @@ static inline u16 ath10k_hif_get_free_queue_number(struct ath10k *ar, return ar-hif.ops-get_free_queue_number(ar, pipe_id); } +static inline int ath10k_hif_init(struct ath10k *ar) +{ + return ar-hif.ops-init(ar); +} + +static inline void ath10k_hif_deinit(struct ath10k *ar) +{ + ar-hif.ops-deinit(ar); +} + #endif /* _HIF_H_ */ diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 06124a4..97f80e5 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -54,6 +54,8 @@ static int ath10k_pci_post_rx_pipe(struct hif_ce_pipe_info *pipe_info, int num); static void ath10k_pci_rx_pipe_cleanup(struct hif_ce_pipe_info *pipe_info); static void ath10k_pci_stop_ce(struct ath10k *ar); +static void ath10k_pci_device_reset(struct ath10k *ar); +static int ath10k_pci_reset_target(struct ath10k *ar); static const struct ce_attr host_ce_config_wlan[] = { /* host-target HTC control and raw streams */ @@ -1755,6 +1757,66 @@ static void ath10k_pci_fw_interrupt_handler(struct ath10k *ar) ath10k_pci_sleep(ar); } +static int ath10k_pci_hif_init(struct ath10k *ar) +{ + int ret; + + /* +* Bring the target up cleanly. +* +* The target may be in an undefined state with an AUX-powered Target +* and a Host in WoW mode. If the Host crashes, loses power, or is +* restarted (without unloading the driver) then the Target is left +* (aux) powered and running. On a subsequent driver load, the Target +* is in an unexpected state. We try to catch that here in order to +* reset the Target and retry the probe. +*/ + ath10k_pci_device_reset(ar); + + ret = ath10k_pci_reset_target(ar); + if (ret) + goto err; + + if (ath10k_target_ps) { + ath10k_dbg(ATH10K_DBG_PCI, on-chip power save enabled\n); + } else { + /* Force AWAKE forever */ + ath10k_dbg(ATH10K_DBG_PCI, on-chip power save disabled\n); + ath10k_do_pci_wake(ar); + } + + ret = ath10k_pci_ce_init(ar); + if (ret) + goto err_ps; + + ret = ath10k_pci_init_config(ar); + if (ret) + goto err_ce; + + ret = ath10k_pci_wake_target_cpu(ar); + if (ret) { + ath10k_err(could not wake up target CPU (%d)\n, ret); + goto err_ce; + } + + return 0; + +err_ce: + ath10k_pci_ce_deinit(ar); +err_ps: + if (!ath10k_target_ps) + ath10k_do_pci_sleep(ar); +err: + return ret; +} + +static void ath10k_pci_hif_deinit(struct ath10k *ar) +{ + ath10k_pci_ce_deinit(ar); + if (!ath10k_target_ps) + ath10k_do_pci_sleep(ar); +} + static const struct ath10k_hif_ops ath10k_pci_hif_ops = { .send_head = ath10k_pci_hif_send_head, .exchange_bmi_msg = ath10k_pci_hif_exchange_bmi_msg, @@ -1765,6 +1827,8 @@ static const struct ath10k_hif_ops ath10k_pci_hif_ops = { .send_complete_check= ath10k_pci_hif_send_complete_check, .set_callbacks = ath10k_pci_hif_set_callbacks, .get_free_queue_number =