Re: [PATCH 4/5] soc: qcom: wcnss_ctrl: Make wcnss_ctrl parent the other components
On Thu 31 Mar 11:47 PDT 2016, Andy Gross wrote: > On Mon, Mar 28, 2016 at 09:35:25PM -0700, Bjorn Andersson wrote: > > We need the signal from wcnss_ctrl indicating that the firmware is up > > and running before we can communicate with the other components of the > > chip. So make these other components children of the wcnss_ctrl device, > > so they can be probed in order. > > > > The process seems to take between 1/2-5 seconds, so this is done in a > > worker, instead of holding up the probe. > > > > Also adding the wait for a cbc completion if the firmware indicates this is > > needed - like on 8016. > > Can you define what a CBC is? > Unfortunately I have no clue and have not yet seen this abbreviation in any documentation... > > > > > /** > > * wcnss_download_nv() - send nv binary to WCNSS > > - * @work: work struct to acquire wcnss context > > + * @wcnss: wcnss_ctrl state handle > > + * > > + * Returns 1 on success or 2 to indicate upcoming cbc completion. Negative > > maybe a nit, but define the return values > I'll remap them a step down, so the function returns 0 on success and 1 on "need to wait for cbc complete". That way we don't have an undefined hole in the return set as well. > > + * errno on failure. > > */ > > -static void wcnss_download_nv(struct work_struct *work) > > +static int wcnss_download_nv(struct wcnss_ctrl *wcnss) > > { > > - struct wcnss_ctrl *wcnss = container_of(work, struct wcnss_ctrl, > > download_nv_work); > > struct wcnss_download_nv_req *req; > > const struct firmware *fw; > > const void *data; > > @@ -178,7 +207,7 @@ static void wcnss_download_nv(struct work_struct *work) > > > > req = kzalloc(sizeof(*req) + NV_FRAGMENT_SIZE, GFP_KERNEL); > > if (!req) > > - return; > > + return -ENOMEM; > > > > ret = request_firmware(, NVBIN_FILE, wcnss->dev); > > if (ret) { > > > > > +static void wcnss_async_probe(struct work_struct *work) > > +{ > > + struct wcnss_ctrl *wcnss = container_of(work, struct wcnss_ctrl, > > probe_work); > > + int ret; > > + > > + ret = wcnss_request_version(wcnss); > > + if (ret < 0) > > + return; > > + > > + ret = wcnss_download_nv(wcnss); > > + if (ret < 0) > > + return; > > + > > + /* Wait for pending CBC completion if download nv returns 2 */ > > + if (ret == 2) { > > Perhaps have a #define for the value is warranted > With the above remap I can rename ret here to need_cbc and the code will be understandable. > > + ret = wait_for_completion_timeout(>cbc, > > WCNSS_REQUEST_TIMEOUT); > > + if (!ret) > > + dev_err(wcnss->dev, "expected cbc completion\n"); > > + } > > + > > + of_platform_populate(wcnss->dev->of_node, NULL, NULL, wcnss->dev); > > } > > Thanks for the feedback! Regards, Bjorn
Re: [PATCH 4/5] soc: qcom: wcnss_ctrl: Make wcnss_ctrl parent the other components
On Thu 31 Mar 11:47 PDT 2016, Andy Gross wrote: > On Mon, Mar 28, 2016 at 09:35:25PM -0700, Bjorn Andersson wrote: > > We need the signal from wcnss_ctrl indicating that the firmware is up > > and running before we can communicate with the other components of the > > chip. So make these other components children of the wcnss_ctrl device, > > so they can be probed in order. > > > > The process seems to take between 1/2-5 seconds, so this is done in a > > worker, instead of holding up the probe. > > > > Also adding the wait for a cbc completion if the firmware indicates this is > > needed - like on 8016. > > Can you define what a CBC is? > Unfortunately I have no clue and have not yet seen this abbreviation in any documentation... > > > > > /** > > * wcnss_download_nv() - send nv binary to WCNSS > > - * @work: work struct to acquire wcnss context > > + * @wcnss: wcnss_ctrl state handle > > + * > > + * Returns 1 on success or 2 to indicate upcoming cbc completion. Negative > > maybe a nit, but define the return values > I'll remap them a step down, so the function returns 0 on success and 1 on "need to wait for cbc complete". That way we don't have an undefined hole in the return set as well. > > + * errno on failure. > > */ > > -static void wcnss_download_nv(struct work_struct *work) > > +static int wcnss_download_nv(struct wcnss_ctrl *wcnss) > > { > > - struct wcnss_ctrl *wcnss = container_of(work, struct wcnss_ctrl, > > download_nv_work); > > struct wcnss_download_nv_req *req; > > const struct firmware *fw; > > const void *data; > > @@ -178,7 +207,7 @@ static void wcnss_download_nv(struct work_struct *work) > > > > req = kzalloc(sizeof(*req) + NV_FRAGMENT_SIZE, GFP_KERNEL); > > if (!req) > > - return; > > + return -ENOMEM; > > > > ret = request_firmware(, NVBIN_FILE, wcnss->dev); > > if (ret) { > > > > > +static void wcnss_async_probe(struct work_struct *work) > > +{ > > + struct wcnss_ctrl *wcnss = container_of(work, struct wcnss_ctrl, > > probe_work); > > + int ret; > > + > > + ret = wcnss_request_version(wcnss); > > + if (ret < 0) > > + return; > > + > > + ret = wcnss_download_nv(wcnss); > > + if (ret < 0) > > + return; > > + > > + /* Wait for pending CBC completion if download nv returns 2 */ > > + if (ret == 2) { > > Perhaps have a #define for the value is warranted > With the above remap I can rename ret here to need_cbc and the code will be understandable. > > + ret = wait_for_completion_timeout(>cbc, > > WCNSS_REQUEST_TIMEOUT); > > + if (!ret) > > + dev_err(wcnss->dev, "expected cbc completion\n"); > > + } > > + > > + of_platform_populate(wcnss->dev->of_node, NULL, NULL, wcnss->dev); > > } > > Thanks for the feedback! Regards, Bjorn
Re: [PATCH 4/5] soc: qcom: wcnss_ctrl: Make wcnss_ctrl parent the other components
On Mon, Mar 28, 2016 at 09:35:25PM -0700, Bjorn Andersson wrote: > We need the signal from wcnss_ctrl indicating that the firmware is up > and running before we can communicate with the other components of the > chip. So make these other components children of the wcnss_ctrl device, > so they can be probed in order. > > The process seems to take between 1/2-5 seconds, so this is done in a > worker, instead of holding up the probe. > > Also adding the wait for a cbc completion if the firmware indicates this is > needed - like on 8016. Can you define what a CBC is? > /** > * wcnss_download_nv() - send nv binary to WCNSS > - * @work:work struct to acquire wcnss context > + * @wcnss: wcnss_ctrl state handle > + * > + * Returns 1 on success or 2 to indicate upcoming cbc completion. Negative maybe a nit, but define the return values > + * errno on failure. > */ > -static void wcnss_download_nv(struct work_struct *work) > +static int wcnss_download_nv(struct wcnss_ctrl *wcnss) > { > - struct wcnss_ctrl *wcnss = container_of(work, struct wcnss_ctrl, > download_nv_work); > struct wcnss_download_nv_req *req; > const struct firmware *fw; > const void *data; > @@ -178,7 +207,7 @@ static void wcnss_download_nv(struct work_struct *work) > > req = kzalloc(sizeof(*req) + NV_FRAGMENT_SIZE, GFP_KERNEL); > if (!req) > - return; > + return -ENOMEM; > > ret = request_firmware(, NVBIN_FILE, wcnss->dev); > if (ret) { > +static void wcnss_async_probe(struct work_struct *work) > +{ > + struct wcnss_ctrl *wcnss = container_of(work, struct wcnss_ctrl, > probe_work); > + int ret; > + > + ret = wcnss_request_version(wcnss); > + if (ret < 0) > + return; > + > + ret = wcnss_download_nv(wcnss); > + if (ret < 0) > + return; > + > + /* Wait for pending CBC completion if download nv returns 2 */ > + if (ret == 2) { Perhaps have a #define for the value is warranted > + ret = wait_for_completion_timeout(>cbc, > WCNSS_REQUEST_TIMEOUT); > + if (!ret) > + dev_err(wcnss->dev, "expected cbc completion\n"); > + } > + > + of_platform_populate(wcnss->dev->of_node, NULL, NULL, wcnss->dev); > }
Re: [PATCH 4/5] soc: qcom: wcnss_ctrl: Make wcnss_ctrl parent the other components
On Mon, Mar 28, 2016 at 09:35:25PM -0700, Bjorn Andersson wrote: > We need the signal from wcnss_ctrl indicating that the firmware is up > and running before we can communicate with the other components of the > chip. So make these other components children of the wcnss_ctrl device, > so they can be probed in order. > > The process seems to take between 1/2-5 seconds, so this is done in a > worker, instead of holding up the probe. > > Also adding the wait for a cbc completion if the firmware indicates this is > needed - like on 8016. Can you define what a CBC is? > /** > * wcnss_download_nv() - send nv binary to WCNSS > - * @work:work struct to acquire wcnss context > + * @wcnss: wcnss_ctrl state handle > + * > + * Returns 1 on success or 2 to indicate upcoming cbc completion. Negative maybe a nit, but define the return values > + * errno on failure. > */ > -static void wcnss_download_nv(struct work_struct *work) > +static int wcnss_download_nv(struct wcnss_ctrl *wcnss) > { > - struct wcnss_ctrl *wcnss = container_of(work, struct wcnss_ctrl, > download_nv_work); > struct wcnss_download_nv_req *req; > const struct firmware *fw; > const void *data; > @@ -178,7 +207,7 @@ static void wcnss_download_nv(struct work_struct *work) > > req = kzalloc(sizeof(*req) + NV_FRAGMENT_SIZE, GFP_KERNEL); > if (!req) > - return; > + return -ENOMEM; > > ret = request_firmware(, NVBIN_FILE, wcnss->dev); > if (ret) { > +static void wcnss_async_probe(struct work_struct *work) > +{ > + struct wcnss_ctrl *wcnss = container_of(work, struct wcnss_ctrl, > probe_work); > + int ret; > + > + ret = wcnss_request_version(wcnss); > + if (ret < 0) > + return; > + > + ret = wcnss_download_nv(wcnss); > + if (ret < 0) > + return; > + > + /* Wait for pending CBC completion if download nv returns 2 */ > + if (ret == 2) { Perhaps have a #define for the value is warranted > + ret = wait_for_completion_timeout(>cbc, > WCNSS_REQUEST_TIMEOUT); > + if (!ret) > + dev_err(wcnss->dev, "expected cbc completion\n"); > + } > + > + of_platform_populate(wcnss->dev->of_node, NULL, NULL, wcnss->dev); > }
[PATCH 4/5] soc: qcom: wcnss_ctrl: Make wcnss_ctrl parent the other components
We need the signal from wcnss_ctrl indicating that the firmware is up and running before we can communicate with the other components of the chip. So make these other components children of the wcnss_ctrl device, so they can be probed in order. The process seems to take between 1/2-5 seconds, so this is done in a worker, instead of holding up the probe. Also adding the wait for a cbc completion if the firmware indicates this is needed - like on 8016. Signed-off-by: Bjorn Andersson--- drivers/soc/qcom/wcnss_ctrl.c | 117 ++-- include/linux/soc/qcom/wcnss_ctrl.h | 8 +++ 2 files changed, 108 insertions(+), 17 deletions(-) create mode 100644 include/linux/soc/qcom/wcnss_ctrl.h diff --git a/drivers/soc/qcom/wcnss_ctrl.c b/drivers/soc/qcom/wcnss_ctrl.c index c544f3d2c6ee..80bea66889a2 100644 --- a/drivers/soc/qcom/wcnss_ctrl.c +++ b/drivers/soc/qcom/wcnss_ctrl.c @@ -1,4 +1,5 @@ /* + * Copyright (c) 2016, Linaro Ltd. * Copyright (c) 2015, Sony Mobile Communications Inc. * * This program is free software; you can redistribute it and/or modify @@ -14,8 +15,13 @@ #include #include #include +#include +#include +#include +#include #define WCNSS_REQUEST_TIMEOUT (5 * HZ) +#define WCNSS_CBC_TIMEOUT (10 * HZ) #define NV_FRAGMENT_SIZE 3072 #define NVBIN_FILE "wlan/prima/WCNSS_qcom_wlan_nv.bin" @@ -25,17 +31,19 @@ * @dev: device handle * @channel: SMD channel handle * @ack: completion for outstanding requests + * @cbc: completion for cbc complete indication * @ack_status:status of the outstanding request - * @download_nv_work: worker for uploading nv binary + * @probe_work: worker for uploading nv binary */ struct wcnss_ctrl { struct device *dev; struct qcom_smd_channel *channel; struct completion ack; + struct completion cbc; int ack_status; - struct work_struct download_nv_work; + struct work_struct probe_work; }; /* message types */ @@ -48,6 +56,11 @@ enum { WCNSS_UPLOAD_CAL_RESP, WCNSS_DOWNLOAD_CAL_REQ, WCNSS_DOWNLOAD_CAL_RESP, + WCNSS_VBAT_LEVEL_IND, + WCNSS_BUILD_VERSION_REQ, + WCNSS_BUILD_VERSION_RESP, + WCNSS_PM_CONFIG_REQ, + WCNSS_CBC_COMPLETE_IND, }; /** @@ -128,7 +141,7 @@ static int wcnss_ctrl_smd_callback(struct qcom_smd_channel *channel, version->major, version->minor, version->version, version->revision); - schedule_work(>download_nv_work); + complete(>ack); break; case WCNSS_DOWNLOAD_NV_RESP: if (count != sizeof(*nvresp)) { @@ -141,6 +154,10 @@ static int wcnss_ctrl_smd_callback(struct qcom_smd_channel *channel, wcnss->ack_status = nvresp->status; complete(>ack); break; + case WCNSS_CBC_COMPLETE_IND: + dev_dbg(wcnss->dev, "WCNSS booted\n"); + complete(>cbc); + break; default: dev_info(wcnss->dev, "unknown message type %d\n", hdr->type); break; @@ -156,20 +173,32 @@ static int wcnss_ctrl_smd_callback(struct qcom_smd_channel *channel, static int wcnss_request_version(struct wcnss_ctrl *wcnss) { struct wcnss_msg_hdr msg; + int ret; msg.type = WCNSS_VERSION_REQ; msg.len = sizeof(msg); + ret = qcom_smd_send(wcnss->channel, , sizeof(msg)); + if (ret < 0) + return ret; + + ret = wait_for_completion_timeout(>ack, WCNSS_CBC_TIMEOUT); + if (!ret) { + dev_err(wcnss->dev, "timeout waiting for version response\n"); + return -ETIMEDOUT; + } - return qcom_smd_send(wcnss->channel, , sizeof(msg)); + return 0; } /** * wcnss_download_nv() - send nv binary to WCNSS - * @work: work struct to acquire wcnss context + * @wcnss: wcnss_ctrl state handle + * + * Returns 1 on success or 2 to indicate upcoming cbc completion. Negative + * errno on failure. */ -static void wcnss_download_nv(struct work_struct *work) +static int wcnss_download_nv(struct wcnss_ctrl *wcnss) { - struct wcnss_ctrl *wcnss = container_of(work, struct wcnss_ctrl, download_nv_work); struct wcnss_download_nv_req *req; const struct firmware *fw; const void *data; @@ -178,7 +207,7 @@ static void wcnss_download_nv(struct work_struct *work) req = kzalloc(sizeof(*req) + NV_FRAGMENT_SIZE, GFP_KERNEL); if (!req) - return; + return -ENOMEM; ret = request_firmware(, NVBIN_FILE, wcnss->dev); if (ret) { @@ -220,16 +249,56 @@ static void wcnss_download_nv(struct work_struct *work) } while (left > 0); ret = wait_for_completion_timeout(>ack, WCNSS_REQUEST_TIMEOUT); - if (!ret) + if (!ret) {
[PATCH 4/5] soc: qcom: wcnss_ctrl: Make wcnss_ctrl parent the other components
We need the signal from wcnss_ctrl indicating that the firmware is up and running before we can communicate with the other components of the chip. So make these other components children of the wcnss_ctrl device, so they can be probed in order. The process seems to take between 1/2-5 seconds, so this is done in a worker, instead of holding up the probe. Also adding the wait for a cbc completion if the firmware indicates this is needed - like on 8016. Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/wcnss_ctrl.c | 117 ++-- include/linux/soc/qcom/wcnss_ctrl.h | 8 +++ 2 files changed, 108 insertions(+), 17 deletions(-) create mode 100644 include/linux/soc/qcom/wcnss_ctrl.h diff --git a/drivers/soc/qcom/wcnss_ctrl.c b/drivers/soc/qcom/wcnss_ctrl.c index c544f3d2c6ee..80bea66889a2 100644 --- a/drivers/soc/qcom/wcnss_ctrl.c +++ b/drivers/soc/qcom/wcnss_ctrl.c @@ -1,4 +1,5 @@ /* + * Copyright (c) 2016, Linaro Ltd. * Copyright (c) 2015, Sony Mobile Communications Inc. * * This program is free software; you can redistribute it and/or modify @@ -14,8 +15,13 @@ #include #include #include +#include +#include +#include +#include #define WCNSS_REQUEST_TIMEOUT (5 * HZ) +#define WCNSS_CBC_TIMEOUT (10 * HZ) #define NV_FRAGMENT_SIZE 3072 #define NVBIN_FILE "wlan/prima/WCNSS_qcom_wlan_nv.bin" @@ -25,17 +31,19 @@ * @dev: device handle * @channel: SMD channel handle * @ack: completion for outstanding requests + * @cbc: completion for cbc complete indication * @ack_status:status of the outstanding request - * @download_nv_work: worker for uploading nv binary + * @probe_work: worker for uploading nv binary */ struct wcnss_ctrl { struct device *dev; struct qcom_smd_channel *channel; struct completion ack; + struct completion cbc; int ack_status; - struct work_struct download_nv_work; + struct work_struct probe_work; }; /* message types */ @@ -48,6 +56,11 @@ enum { WCNSS_UPLOAD_CAL_RESP, WCNSS_DOWNLOAD_CAL_REQ, WCNSS_DOWNLOAD_CAL_RESP, + WCNSS_VBAT_LEVEL_IND, + WCNSS_BUILD_VERSION_REQ, + WCNSS_BUILD_VERSION_RESP, + WCNSS_PM_CONFIG_REQ, + WCNSS_CBC_COMPLETE_IND, }; /** @@ -128,7 +141,7 @@ static int wcnss_ctrl_smd_callback(struct qcom_smd_channel *channel, version->major, version->minor, version->version, version->revision); - schedule_work(>download_nv_work); + complete(>ack); break; case WCNSS_DOWNLOAD_NV_RESP: if (count != sizeof(*nvresp)) { @@ -141,6 +154,10 @@ static int wcnss_ctrl_smd_callback(struct qcom_smd_channel *channel, wcnss->ack_status = nvresp->status; complete(>ack); break; + case WCNSS_CBC_COMPLETE_IND: + dev_dbg(wcnss->dev, "WCNSS booted\n"); + complete(>cbc); + break; default: dev_info(wcnss->dev, "unknown message type %d\n", hdr->type); break; @@ -156,20 +173,32 @@ static int wcnss_ctrl_smd_callback(struct qcom_smd_channel *channel, static int wcnss_request_version(struct wcnss_ctrl *wcnss) { struct wcnss_msg_hdr msg; + int ret; msg.type = WCNSS_VERSION_REQ; msg.len = sizeof(msg); + ret = qcom_smd_send(wcnss->channel, , sizeof(msg)); + if (ret < 0) + return ret; + + ret = wait_for_completion_timeout(>ack, WCNSS_CBC_TIMEOUT); + if (!ret) { + dev_err(wcnss->dev, "timeout waiting for version response\n"); + return -ETIMEDOUT; + } - return qcom_smd_send(wcnss->channel, , sizeof(msg)); + return 0; } /** * wcnss_download_nv() - send nv binary to WCNSS - * @work: work struct to acquire wcnss context + * @wcnss: wcnss_ctrl state handle + * + * Returns 1 on success or 2 to indicate upcoming cbc completion. Negative + * errno on failure. */ -static void wcnss_download_nv(struct work_struct *work) +static int wcnss_download_nv(struct wcnss_ctrl *wcnss) { - struct wcnss_ctrl *wcnss = container_of(work, struct wcnss_ctrl, download_nv_work); struct wcnss_download_nv_req *req; const struct firmware *fw; const void *data; @@ -178,7 +207,7 @@ static void wcnss_download_nv(struct work_struct *work) req = kzalloc(sizeof(*req) + NV_FRAGMENT_SIZE, GFP_KERNEL); if (!req) - return; + return -ENOMEM; ret = request_firmware(, NVBIN_FILE, wcnss->dev); if (ret) { @@ -220,16 +249,56 @@ static void wcnss_download_nv(struct work_struct *work) } while (left > 0); ret = wait_for_completion_timeout(>ack, WCNSS_REQUEST_TIMEOUT); - if (!ret) + if (!ret) {