Message ID | 20181130150247.26294-2-bgodavar@codeaurora.org (mailing list archive) |
---|---|
State | Not Applicable, archived |
Headers | show |
Series | Bug fixes for Qualcomm BT chip wcn3990 | expand |
On Fri, Nov 30, 2018 at 08:32:44PM +0530, Balakrishna Godavarthi wrote: > wcn3990 requires a power pulse to turn ON/OFF along with > regulators. Sometimes we are observing the power pulses are sent > out with some time delay, due to queuing these commands. This is > causing synchronization issues with chip, which intern delay the > chip setup or may end up with communication issues. > > Signed-off-by: Balakrishna Godavarthi <bgodavar@codeaurora.org> > --- > v3: > * no change. > v2: > * Updated function qca_send_power_pulse() > * addressed reviewer comments. Please make sure to include reviewers on CC when resending, and as someone else already mentioned, be a bit more specific about what changes you actually made in response to the review feedback you received. > v1: > * initial patch > --- > drivers/bluetooth/hci_qca.c | 37 +++++++++++++------------------------ > 1 file changed, 13 insertions(+), 24 deletions(-) > > diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c > index f036c8f98ea3..f5dd323c1967 100644 > --- a/drivers/bluetooth/hci_qca.c > +++ b/drivers/bluetooth/hci_qca.c > @@ -1013,11 +1013,9 @@ static inline void host_set_baudrate(struct hci_uart *hu, unsigned int speed) > hci_uart_set_baudrate(hu, speed); > } > > -static int qca_send_power_pulse(struct hci_dev *hdev, u8 cmd) > +static int qca_send_power_pulse(struct hci_uart *hu, u8 cmd) > { > - struct hci_uart *hu = hci_get_drvdata(hdev); > - struct qca_data *qca = hu->priv; > - struct sk_buff *skb; > + int ret; > > /* These power pulses are single byte command which are sent > * at required baudrate to wcn3990. On wcn3990, we have an external > @@ -1029,19 +1027,16 @@ static int qca_send_power_pulse(struct hci_dev *hdev, u8 cmd) > * save power. Disabling hardware flow control is mandatory while > * sending power pulses to SoC. > */ > - bt_dev_dbg(hdev, "sending power pulse %02x to SoC", cmd); > - > - skb = bt_skb_alloc(sizeof(cmd), GFP_KERNEL); > - if (!skb) > - return -ENOMEM; > - > + bt_dev_dbg(hu->hdev, "sending power pulse %02x to SoC", cmd); > hci_uart_set_flow_control(hu, true); > + ret = serdev_device_write(hu->serdev, &cmd, sizeof(cmd), 0); You're still using 0 as a timeout here which is broken, as I already told you. From 4.21 this will result in an indefinite timeout, but currently implies not to wait for a full write buffer to drain at all. As I also mentioned, you need to to make sure to call serdev_device_write_wakeup() in the write_wakup() path if you are going to use serdev_device_write() at all. Johan
Hi Johan, On 2018-12-05 11:55, Johan Hovold wrote: > On Fri, Nov 30, 2018 at 08:32:44PM +0530, Balakrishna Godavarthi wrote: >> wcn3990 requires a power pulse to turn ON/OFF along with >> regulators. Sometimes we are observing the power pulses are sent >> out with some time delay, due to queuing these commands. This is >> causing synchronization issues with chip, which intern delay the >> chip setup or may end up with communication issues. >> >> Signed-off-by: Balakrishna Godavarthi <bgodavar@codeaurora.org> >> --- >> v3: >> * no change. >> v2: >> * Updated function qca_send_power_pulse() >> * addressed reviewer comments. > > Please make sure to include reviewers on CC when resending, and as > someone else already mentioned, be a bit more specific about what > changes you actually made in response to the review feedback you > received. > [Bala]: sure will add and provide more info in version change history. >> v1: >> * initial patch >> --- >> drivers/bluetooth/hci_qca.c | 37 >> +++++++++++++------------------------ >> 1 file changed, 13 insertions(+), 24 deletions(-) >> >> diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c >> index f036c8f98ea3..f5dd323c1967 100644 >> --- a/drivers/bluetooth/hci_qca.c >> +++ b/drivers/bluetooth/hci_qca.c >> @@ -1013,11 +1013,9 @@ static inline void host_set_baudrate(struct >> hci_uart *hu, unsigned int speed) >> hci_uart_set_baudrate(hu, speed); >> } >> >> -static int qca_send_power_pulse(struct hci_dev *hdev, u8 cmd) >> +static int qca_send_power_pulse(struct hci_uart *hu, u8 cmd) >> { >> - struct hci_uart *hu = hci_get_drvdata(hdev); >> - struct qca_data *qca = hu->priv; >> - struct sk_buff *skb; >> + int ret; >> >> /* These power pulses are single byte command which are sent >> * at required baudrate to wcn3990. On wcn3990, we have an external >> @@ -1029,19 +1027,16 @@ static int qca_send_power_pulse(struct hci_dev >> *hdev, u8 cmd) >> * save power. Disabling hardware flow control is mandatory while >> * sending power pulses to SoC. >> */ >> - bt_dev_dbg(hdev, "sending power pulse %02x to SoC", cmd); >> - >> - skb = bt_skb_alloc(sizeof(cmd), GFP_KERNEL); >> - if (!skb) >> - return -ENOMEM; >> - >> + bt_dev_dbg(hu->hdev, "sending power pulse %02x to SoC", cmd); >> hci_uart_set_flow_control(hu, true); >> + ret = serdev_device_write(hu->serdev, &cmd, sizeof(cmd), 0); > > You're still using 0 as a timeout here which is broken, as I already > told you. > [Bala]: got the change now will update to timeout to non zero value. > From 4.21 this will result in an indefinite timeout, but currently > implies not to wait for a full write buffer to drain at all. > > As I also mentioned, you need to to make sure to call > serdev_device_write_wakeup() in the write_wakup() path if you are going > to use serdev_device_write() at all. > [Bala]: this where i am confused. calling serdev_device_write is calling an wakeup internally. below is the flow ttyport_write_buf: * calling serdev_device_write() will call write_buf() in this call we are enabling bit "TTY_DO_WRITE_WAKEUP" and calling write() i.e. uart_write() where we call in start_tx. this will go to the vendor specific write where in isr we call uart_write_wakeup() https://elixir.bootlin.com/linux/latest/source/drivers/tty/serial/qcom_geni_serial.c#L756 uart_write_wakeup()->ttyport_write_wakeup()->serdev_controller_write_wakeup()->hci_uart_write_wakeup()->hci_uart_tx_wakeup() the above is flow when serdev_device_write() is called, it is indirectly calling serdev_write_wakeup(). Why actual we need to call an serdev_write_wakeup() is this wakeup related to the UART port or for the BT chip. > Johan
Hi Johan, On 2018-12-06 16:10, Balakrishna Godavarthi wrote: > Hi Johan, > > On 2018-12-05 11:55, Johan Hovold wrote: >> On Fri, Nov 30, 2018 at 08:32:44PM +0530, Balakrishna Godavarthi >> wrote: >>> wcn3990 requires a power pulse to turn ON/OFF along with >>> regulators. Sometimes we are observing the power pulses are sent >>> out with some time delay, due to queuing these commands. This is >>> causing synchronization issues with chip, which intern delay the >>> chip setup or may end up with communication issues. >>> >>> Signed-off-by: Balakrishna Godavarthi <bgodavar@codeaurora.org> >>> --- >>> v3: >>> * no change. >>> v2: >>> * Updated function qca_send_power_pulse() >>> * addressed reviewer comments. >> >> Please make sure to include reviewers on CC when resending, and as >> someone else already mentioned, be a bit more specific about what >> changes you actually made in response to the review feedback you >> received. >> > > [Bala]: sure will add and provide more info in version change history. > >>> v1: >>> * initial patch >>> --- >>> drivers/bluetooth/hci_qca.c | 37 >>> +++++++++++++------------------------ >>> 1 file changed, 13 insertions(+), 24 deletions(-) >>> >>> diff --git a/drivers/bluetooth/hci_qca.c >>> b/drivers/bluetooth/hci_qca.c >>> index f036c8f98ea3..f5dd323c1967 100644 >>> --- a/drivers/bluetooth/hci_qca.c >>> +++ b/drivers/bluetooth/hci_qca.c >>> @@ -1013,11 +1013,9 @@ static inline void host_set_baudrate(struct >>> hci_uart *hu, unsigned int speed) >>> hci_uart_set_baudrate(hu, speed); >>> } >>> >>> -static int qca_send_power_pulse(struct hci_dev *hdev, u8 cmd) >>> +static int qca_send_power_pulse(struct hci_uart *hu, u8 cmd) >>> { >>> - struct hci_uart *hu = hci_get_drvdata(hdev); >>> - struct qca_data *qca = hu->priv; >>> - struct sk_buff *skb; >>> + int ret; >>> >>> /* These power pulses are single byte command which are sent >>> * at required baudrate to wcn3990. On wcn3990, we have an external >>> @@ -1029,19 +1027,16 @@ static int qca_send_power_pulse(struct >>> hci_dev *hdev, u8 cmd) >>> * save power. Disabling hardware flow control is mandatory while >>> * sending power pulses to SoC. >>> */ >>> - bt_dev_dbg(hdev, "sending power pulse %02x to SoC", cmd); >>> - >>> - skb = bt_skb_alloc(sizeof(cmd), GFP_KERNEL); >>> - if (!skb) >>> - return -ENOMEM; >>> - >>> + bt_dev_dbg(hu->hdev, "sending power pulse %02x to SoC", cmd); >>> hci_uart_set_flow_control(hu, true); >>> + ret = serdev_device_write(hu->serdev, &cmd, sizeof(cmd), 0); >> >> You're still using 0 as a timeout here which is broken, as I already >> told you. >> > > [Bala]: got the change now will update to timeout to non zero value. > >> From 4.21 this will result in an indefinite timeout, but currently >> implies not to wait for a full write buffer to drain at all. >> >> As I also mentioned, you need to to make sure to call >> serdev_device_write_wakeup() in the write_wakup() path if you are >> going >> to use serdev_device_write() at all. >> > > [Bala]: this where i am confused. > calling serdev_device_write is calling an wakeup internally. > below is the flow > > ttyport_write_buf: > * calling serdev_device_write() will call write_buf() in > this call we are enabling bit "TTY_DO_WRITE_WAKEUP" and calling > write() > i.e. uart_write() where we call in start_tx. this will > go to the vendor specific write where in isr we call > uart_write_wakeup() > > https://elixir.bootlin.com/linux/latest/source/drivers/tty/serial/qcom_geni_serial.c#L756 > > > uart_write_wakeup()->ttyport_write_wakeup()->serdev_controller_write_wakeup()->hci_uart_write_wakeup()->hci_uart_tx_wakeup() > > the above is flow when serdev_device_write() is called, it is > indirectly calling serdev_write_wakeup(). > > Why actual we need to call an serdev_write_wakeup() is this > wakeup related to the UART port or for the BT chip. > >> Johan Can you help me to understand, whether my understating is correct wrt serdev_wakeup().
On Thu, Dec 06, 2018 at 04:10:07PM +0530, Balakrishna Godavarthi wrote: > Hi Johan, > > On 2018-12-05 11:55, Johan Hovold wrote: > > On Fri, Nov 30, 2018 at 08:32:44PM +0530, Balakrishna Godavarthi wrote: > >> + ret = serdev_device_write(hu->serdev, &cmd, sizeof(cmd), 0); > > > > You're still using 0 as a timeout here which is broken, as I already > > told you. > > [Bala]: got the change now will update to timeout to non zero value. > > > From 4.21 this will result in an indefinite timeout, but currently > > implies not to wait for a full write buffer to drain at all. > > > > As I also mentioned, you need to to make sure to call > > serdev_device_write_wakeup() in the write_wakup() path if you are going > > to use serdev_device_write() at all. > > [Bala]: this where i am confused. > calling serdev_device_write is calling an wakeup internally. > below is the flow > > ttyport_write_buf: > * calling serdev_device_write() will call write_buf() in > this call we are enabling bit "TTY_DO_WRITE_WAKEUP" and calling write() > i.e. uart_write() where we call in start_tx. this will > go to the vendor specific write where in isr we call uart_write_wakeup() > > https://elixir.bootlin.com/linux/latest/source/drivers/tty/serial/qcom_geni_serial.c#L756 > > > uart_write_wakeup()->ttyport_write_wakeup()->serdev_controller_write_wakeup()->hci_uart_write_wakeup()->hci_uart_tx_wakeup() > > the above is flow when serdev_device_write() is called, it is > indirectly calling serdev_write_wakeup(). No, serdev_device_write_wakeup() is currently not called in this path, which means you cannot use serdev_device_write(). > Why actual we need to call an serdev_write_wakeup() is this > wakeup related to the UART port or for the BT chip. serdev_device_write_wakeup() is where a writer blocked on a full write buffer in serdev_device_write() is woken up. Johan
Hi Johan, On 2018-12-12 22:12, Johan Hovold wrote: > On Thu, Dec 06, 2018 at 04:10:07PM +0530, Balakrishna Godavarthi wrote: >> Hi Johan, >> >> On 2018-12-05 11:55, Johan Hovold wrote: >> > On Fri, Nov 30, 2018 at 08:32:44PM +0530, Balakrishna Godavarthi wrote: > >> >> + ret = serdev_device_write(hu->serdev, &cmd, sizeof(cmd), 0); >> > >> > You're still using 0 as a timeout here which is broken, as I already >> > told you. >> >> [Bala]: got the change now will update to timeout to non zero value. >> >> > From 4.21 this will result in an indefinite timeout, but currently >> > implies not to wait for a full write buffer to drain at all. >> > >> > As I also mentioned, you need to to make sure to call >> > serdev_device_write_wakeup() in the write_wakup() path if you are going >> > to use serdev_device_write() at all. >> >> [Bala]: this where i am confused. >> calling serdev_device_write is calling an wakeup internally. >> below is the flow >> >> ttyport_write_buf: >> * calling serdev_device_write() will call write_buf() >> in >> this call we are enabling bit "TTY_DO_WRITE_WAKEUP" and calling >> write() >> i.e. uart_write() where we call in start_tx. this >> will >> go to the vendor specific write where in isr we call >> uart_write_wakeup() >> >> https://elixir.bootlin.com/linux/latest/source/drivers/tty/serial/qcom_geni_serial.c#L756 >> >> >> uart_write_wakeup()->ttyport_write_wakeup()->serdev_controller_write_wakeup()->hci_uart_write_wakeup()->hci_uart_tx_wakeup() >> >> the above is flow when serdev_device_write() is called, it is >> indirectly calling serdev_write_wakeup(). > > No, serdev_device_write_wakeup() is currently not called in this path, > which means you cannot use serdev_device_write(). > >> Why actual we need to call an serdev_write_wakeup() is this >> wakeup related to the UART port or for the BT chip. > > serdev_device_write_wakeup() is where a writer blocked on a full write > buffer in serdev_device_write() is woken up. > > Johan Is it preferred to use and serdev_device_write_buf() followed by serdev_device_wait_until_sent() or do we required an write_wakeup() called before writing into serdev_device_write_buf()
On Fri, Dec 14, 2018 at 06:02:40PM +0530, Balakrishna Godavarthi wrote: > Hi Johan, > > On 2018-12-12 22:12, Johan Hovold wrote: > > On Thu, Dec 06, 2018 at 04:10:07PM +0530, Balakrishna Godavarthi wrote: > >> uart_write_wakeup()->ttyport_write_wakeup()->serdev_controller_write_wakeup()->hci_uart_write_wakeup()->hci_uart_tx_wakeup() > >> > >> the above is flow when serdev_device_write() is called, it is > >> indirectly calling serdev_write_wakeup(). > > > > No, serdev_device_write_wakeup() is currently not called in this path, > > which means you cannot use serdev_device_write(). > > > >> Why actual we need to call an serdev_write_wakeup() is this > >> wakeup related to the UART port or for the BT chip. > > > > serdev_device_write_wakeup() is where a writer blocked on a full write > > buffer in serdev_device_write() is woken up. > > > > Johan > > Is it preferred to use and serdev_device_write_buf() followed by > serdev_device_wait_until_sent() That's up to the driver author and depends on what you want to achieve. If you want to do something synchronously, you always have to call serdev_device_wait_until_sent() after, as both serdev_device_write_buf() and serdev_device_write() only buffer the data. If you use serdev_device_write_buf() you also have to make sure that you can handle incomplete buffering yourself (e.g. when the underlying tty driver buffer is getting full). serdev_device_write() was added as a convenience helper for this, but depends on serdev_device_write_wakeup() being called in the write_wakeup path to make forward progress. > or do we required an write_wakeup() called before writing into > serdev_device_write_buf() No, that doesn't make any sense. serdev_device_write_wakeup() needs to be called in the write-wakeup path, but only if you use serdev_device_write(). Please see the documentation of these function that I added to linux-next (and that I linked to earlier). Johan
Hi Johan, On 2018-12-14 18:46, Johan Hovold wrote: > On Fri, Dec 14, 2018 at 06:02:40PM +0530, Balakrishna Godavarthi wrote: >> Hi Johan, >> >> On 2018-12-12 22:12, Johan Hovold wrote: >> > On Thu, Dec 06, 2018 at 04:10:07PM +0530, Balakrishna Godavarthi wrote: > >> >> uart_write_wakeup()->ttyport_write_wakeup()->serdev_controller_write_wakeup()->hci_uart_write_wakeup()->hci_uart_tx_wakeup() >> >> >> >> the above is flow when serdev_device_write() is called, it is >> >> indirectly calling serdev_write_wakeup(). >> > >> > No, serdev_device_write_wakeup() is currently not called in this path, >> > which means you cannot use serdev_device_write(). >> > >> >> Why actual we need to call an serdev_write_wakeup() is this >> >> wakeup related to the UART port or for the BT chip. >> > >> > serdev_device_write_wakeup() is where a writer blocked on a full write >> > buffer in serdev_device_write() is woken up. >> > >> > Johan >> >> Is it preferred to use and serdev_device_write_buf() followed by >> serdev_device_wait_until_sent() > > That's up to the driver author and depends on what you want to achieve. > [Bala]: During the BT on & of, we need to send the commands to the controller at a specific baudrate. as the data is getting queued in the buffer we see some times the data is transmitting on the newer baudrate instead of the actual baudrate. we want to achieve an synchronous data transfer for some commands to over come byte corruptions. > If you want to do something synchronously, you always have to call > serdev_device_wait_until_sent() after, as both > serdev_device_write_buf() > and serdev_device_write() only buffer the data. > > If you use serdev_device_write_buf() you also have to make sure that > you > can handle incomplete buffering yourself (e.g. when the underlying tty > driver buffer is getting full). > > serdev_device_write() was added as a convenience helper for this, but > depends on serdev_device_write_wakeup() being called in the > write_wakeup > path to make forward progress. > [Bala]: Thanks for the info, now i understood the usage of the both write() and write_buf(). >> or do we required an write_wakeup() called before writing into >> serdev_device_write_buf() > > No, that doesn't make any sense. serdev_device_write_wakeup() needs to > be called in the write-wakeup path, but only if you use > serdev_device_write(). > > Please see the documentation of these function that I added to > linux-next (and that I linked to earlier). > > Johan Thanks Johan for the detailed info.
diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c index f036c8f98ea3..f5dd323c1967 100644 --- a/drivers/bluetooth/hci_qca.c +++ b/drivers/bluetooth/hci_qca.c @@ -1013,11 +1013,9 @@ static inline void host_set_baudrate(struct hci_uart *hu, unsigned int speed) hci_uart_set_baudrate(hu, speed); } -static int qca_send_power_pulse(struct hci_dev *hdev, u8 cmd) +static int qca_send_power_pulse(struct hci_uart *hu, u8 cmd) { - struct hci_uart *hu = hci_get_drvdata(hdev); - struct qca_data *qca = hu->priv; - struct sk_buff *skb; + int ret; /* These power pulses are single byte command which are sent * at required baudrate to wcn3990. On wcn3990, we have an external @@ -1029,19 +1027,16 @@ static int qca_send_power_pulse(struct hci_dev *hdev, u8 cmd) * save power. Disabling hardware flow control is mandatory while * sending power pulses to SoC. */ - bt_dev_dbg(hdev, "sending power pulse %02x to SoC", cmd); - - skb = bt_skb_alloc(sizeof(cmd), GFP_KERNEL); - if (!skb) - return -ENOMEM; - + bt_dev_dbg(hu->hdev, "sending power pulse %02x to SoC", cmd); hci_uart_set_flow_control(hu, true); + ret = serdev_device_write(hu->serdev, &cmd, sizeof(cmd), 0); + if (ret < 0) { + bt_dev_err(hu->hdev, "failed to send power pulse %02x to SoC", + cmd); + return ret; + } - skb_put_u8(skb, cmd); - hci_skb_pkt_type(skb) = HCI_COMMAND_PKT; - - skb_queue_tail(&qca->txq, skb); - hci_uart_tx_wakeup(hu); + serdev_device_wait_until_sent(hu->serdev, 0); /* Wait for 100 uS for SoC to settle down */ usleep_range(100, 200); @@ -1116,7 +1111,6 @@ static int qca_set_speed(struct hci_uart *hu, enum qca_speed_type speed_type) static int qca_wcn3990_init(struct hci_uart *hu) { - struct hci_dev *hdev = hu->hdev; struct qca_serdev *qcadev; int ret; @@ -1139,12 +1133,12 @@ static int qca_wcn3990_init(struct hci_uart *hu) /* Forcefully enable wcn3990 to enter in to boot mode. */ host_set_baudrate(hu, 2400); - ret = qca_send_power_pulse(hdev, QCA_WCN3990_POWEROFF_PULSE); + ret = qca_send_power_pulse(hu, QCA_WCN3990_POWEROFF_PULSE); if (ret) return ret; qca_set_speed(hu, QCA_INIT_SPEED); - ret = qca_send_power_pulse(hdev, QCA_WCN3990_POWERON_PULSE); + ret = qca_send_power_pulse(hu, QCA_WCN3990_POWERON_PULSE); if (ret) return ret; @@ -1274,13 +1268,8 @@ static const struct qca_vreg_data qca_soc_data = { static void qca_power_shutdown(struct hci_uart *hu) { - struct serdev_device *serdev = hu->serdev; - unsigned char cmd = QCA_WCN3990_POWEROFF_PULSE; - host_set_baudrate(hu, 2400); - hci_uart_set_flow_control(hu, true); - serdev_device_write_buf(serdev, &cmd, sizeof(cmd)); - hci_uart_set_flow_control(hu, false); + qca_send_power_pulse(hu, QCA_WCN3990_POWEROFF_PULSE); qca_power_setup(hu, false); }
wcn3990 requires a power pulse to turn ON/OFF along with regulators. Sometimes we are observing the power pulses are sent out with some time delay, due to queuing these commands. This is causing synchronization issues with chip, which intern delay the chip setup or may end up with communication issues. Signed-off-by: Balakrishna Godavarthi <bgodavar@codeaurora.org> --- v3: * no change. v2: * Updated function qca_send_power_pulse() * addressed reviewer comments. v1: * initial patch --- drivers/bluetooth/hci_qca.c | 37 +++++++++++++------------------------ 1 file changed, 13 insertions(+), 24 deletions(-)