lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Tue, 10 Jul 2018 09:12:46 -0700
From:   Matthias Kaehlcke <mka@...omium.org>
To:     Balakrishna Godavarthi <bgodavar@...eaurora.org>
Cc:     marcel@...tmann.org, johan.hedberg@...il.com,
        linux-kernel@...r.kernel.org, devicetree@...r.kernel.org,
        linux-bluetooth@...r.kernel.org, thierry.escande@...aro.org,
        rtatiya@...eaurora.org, hemantg@...eaurora.org,
        linux-arm-msm@...r.kernel.org
Subject: Re: [PATCH v9 4/7] Bluetooth: hci_qca: Add wrapper functions for
 setting UART speed

On Tue, Jul 10, 2018 at 05:49:20PM +0530, Balakrishna Godavarthi wrote:
> Hi Matthias,
> 
> On 2018-07-07 01:10, Matthias Kaehlcke wrote:
> > On Thu, Jul 05, 2018 at 10:25:12PM +0530, Balakrishna Godavarthi wrote:
> > > In function qca_setup, we set initial and operating speeds for
> > > Qualcomm
> > > Bluetooth SoC's. This block of code is common across different
> > > Qualcomm Bluetooth SoC's. Instead of duplicating the code, created
> > > a wrapper function to set the speeds. So that future coming SoC's
> > > can use these wrapper functions to set speeds.
> > > 
> > > Signed-off-by: Balakrishna Godavarthi <bgodavar@...eaurora.org>
> > > ---
> > > Changes in v9:
> > >     * added corner case to fail driver if speeds are missing.
> > > 
> > > Changes in v8:
> > >     * common function to set INIT and operating speeds.
> > > 
> > > Changes in v7:
> > >     * initial patch
> > >     * created wrapper functions for init and operating speeds.
> > > ---
> > >  drivers/bluetooth/hci_qca.c | 94
> > > ++++++++++++++++++++++++++++---------
> > >  1 file changed, 71 insertions(+), 23 deletions(-)
> > > 
> > > diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
> > > index c02e1d465cca..9106547324fa 100644
> > > --- a/drivers/bluetooth/hci_qca.c
> > > +++ b/drivers/bluetooth/hci_qca.c
> > > @@ -119,6 +119,11 @@ struct qca_data {
> > >  	u64 votes_off;
> > >  };
> > > 
> > > +enum qca_speed_type {
> > > +	QCA_INIT_SPEED = 1,
> > > +	QCA_OPER_SPEED
> > > +};
> > > +
> > >  struct qca_serdev {
> > >  	struct hci_uart	 serdev_hu;
> > >  	struct gpio_desc *bt_en;
> > > @@ -923,6 +928,62 @@ static inline void host_set_baudrate(struct
> > > hci_uart *hu, unsigned int speed)
> > >  		hci_uart_set_baudrate(hu, speed);
> > >  }
> > > 
> > > +static unsigned int qca_get_speed(struct hci_uart *hu,
> > > +				  enum qca_speed_type speed_type)
> > > +{
> > > +	unsigned int speed = 0;
> > > +
> > > +	if (speed_type == QCA_INIT_SPEED) {
> > > +		if (hu->init_speed)
> > > +			speed = hu->init_speed;
> > > +		else if (hu->proto->init_speed)
> > > +			speed = hu->proto->init_speed;
> > > +	} else {
> > > +		if (hu->oper_speed)
> > > +			speed = hu->oper_speed;
> > > +		else if (hu->proto->oper_speed)
> > > +			speed = hu->proto->oper_speed;
> > > +	}
> > > +
> > > +	return speed;
> > > +}
> > > +
> > > +static int qca_check_speeds(struct hci_uart *hu)
> > > +{
> > > +	/* One or the other speeds should be non zero. */
> > > +	if (!qca_get_speed(hu, QCA_INIT_SPEED) &&
> > > +	    !qca_get_speed(hu, QCA_OPER_SPEED))
> > > +		return -EINVAL;
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static int qca_set_speed(struct hci_uart *hu, enum qca_speed_type
> > > speed_type)
> > > +{
> > > +	unsigned int speed, qca_baudrate;
> > > +	int ret;
> > > +
> > > +	if (speed_type == QCA_INIT_SPEED) {
> > > +		speed = qca_get_speed(hu, QCA_INIT_SPEED);
> > > +		if (speed)
> > > +			host_set_baudrate(hu, speed);
> > 
> > mega-nit: for consistency with the 'else' branch you could return if
> > 'speed == 0'. Not important though, feel free to ignore.
> > 
> > > +	} else {
> > > +		speed = qca_get_speed(hu, QCA_OPER_SPEED);
> > > +		if (!speed)
> > > +			return 0;
> > > +
> > > +		qca_baudrate = qca_get_baudrate_value(speed);
> > > +		bt_dev_info(hu->hdev, "Set UART speed to %d", speed);
> > > +		ret = qca_set_baudrate(hu->hdev, qca_baudrate);
> > > +		if (ret)
> > > +			return ret;
> > > +
> > > +		host_set_baudrate(hu, speed);
> > > +	}
> > > +
> > > +	return 0;
> > > +}
> > > +
> > >  static int qca_setup(struct hci_uart *hu)
> > >  {
> > >  	struct hci_dev *hdev = hu->hdev;
> > > @@ -933,37 +994,24 @@ static int qca_setup(struct hci_uart *hu)
> > > 
> > >  	bt_dev_info(hdev, "ROME setup");
> > > 
> > > +	ret = qca_check_speeds(hu);
> > > +	if (ret)
> > > +		return ret;
> > > +
> > >  	/* Patch downloading has to be done without IBS mode */
> > >  	clear_bit(STATE_IN_BAND_SLEEP_ENABLED, &qca->flags);
> > > 
> > >  	/* Setup initial baudrate */
> > > -	speed = 0;
> > > -	if (hu->init_speed)
> > > -		speed = hu->init_speed;
> > > -	else if (hu->proto->init_speed)
> > > -		speed = hu->proto->init_speed;
> > > -
> > > -	if (speed)
> > > -		host_set_baudrate(hu, speed);
> > > +	qca_set_speed(hu, QCA_INIT_SPEED);
> > > 
> > >  	/* Setup user speed if needed */
> > > -	speed = 0;
> > > -	if (hu->oper_speed)
> > > -		speed = hu->oper_speed;
> > > -	else if (hu->proto->oper_speed)
> > > -		speed = hu->proto->oper_speed;
> > > -
> > > +	speed = qca_get_speed(hu, QCA_OPER_SPEED);
> > >  	if (speed) {
> > > -		qca_baudrate = qca_get_baudrate_value(speed);
> > > -
> > > -		bt_dev_info(hdev, "Set UART speed to %d", speed);
> > > -		ret = qca_set_baudrate(hdev, qca_baudrate);
> > > -		if (ret) {
> > > -			bt_dev_err(hdev, "Failed to change the baud rate (%d)",
> > > -				   ret);
> > > +		ret = qca_set_speed(hu, QCA_OPER_SPEED);
> > > +		if (ret)
> > >  			return ret;
> > > -		}
> > > -		host_set_baudrate(hu, speed);
> > > +
> > > +		qca_baudrate = qca_get_baudrate_value(speed);
> > >  	}
> > 
> > One doubt, the outcome of this change is:
> > 
> > 	qca_set_speed(hu, QCA_INIT_SPEED);
> > 
> > 	/* Setup user speed if needed */
> > 	speed = qca_get_speed(hu, QCA_OPER_SPEED);
> > 	if (speed) {
> > 		ret = qca_set_speed(hu, QCA_OPER_SPEED);
> > 		if (ret)
> > 			return ret;
> > 
> > 		qca_baudrate = qca_get_baudrate_value(speed);
> > 	}
> > 
> > So we set the init speed and then directly switch to operating speed
> > if it is defined.
> > 
> > Couldn't we do this instead:
> > 
> > 	/* Setup user speed if needed */
> > 	speed = qca_get_speed(hu, QCA_OPER_SPEED);
> > 	if (speed) {
> > 		ret = qca_set_speed(hu, QCA_OPER_SPEED);
> > 		if (ret)
> > 			return ret;
> > 
> > 		qca_baudrate = qca_get_baudrate_value(speed);
> > 	} else {
> > 	       qca_set_speed(hu, QCA_INIT_SPEED);
> > 	}
> > 
> > 
> 
> [Bala]: above else block is not required.
>         if we have operating speed to set, then we need to send the baud
> rate change request to BT chip on INIT baud rate. so before sending or
> setting operating baud rate.. HOST driver should be on the HOST init baud
> rate.
>         Pls refer below for more info how we set speed and hci driver works.
> > 
> > Or is setting the init speed needed before the operating speed can be
> > set? Sorry if we discussed this earlier in this series, I know I had a
> > few doubts about the speed management but don't recall this one
> > specifically.
> > 
> 
> [Bala]: Let me give a big picture how we make BT work via serdev HCI arch.
> (qca chip is taken as reference)
> 
>         1. first of all, probe is called when we have compatible string
> matches in qca_bluetooth_of_match table.
>         2. that will call qca_serdev_probe() in which based on BT device
> connected to the platform, we decide IO's
>            which required from HOST to chip i.e.. controls required to turn
> ON/OFF BT. which includes clocks and regulators and GPIO's.
>         3. in qca_serdev_probe() we call  hci_uart_register_device() and
> pass ops (operations handler) handler for driver registration.
>         4. in hci_uart_register_device(), we call qca_open().. where we open
> the port via serdev_device_open() that
>            intern will call Qualcomm specific lower level UART driver i.e..
> where we read and write to port register address.
>            so serdev_device_open() is a common function to all BT chip
> vendor, but the open routine in the low level driver is completely vendor
> dependent.
>            for example, some vendors will set an default UART speed (speed
> can be any) while opening the uart_port(). where as other will not set. Just
> open the port with basic configurations.
> 
>         5. coming back to qca_open(), we try to make chip to boot up by
> enabling clock from HOST for BT chip to operate..  it is purely chip
> defined.
>         6. moving back to hci_uart_register_device()... we will call
> hci_register_dev() in that function we call hci_power_on().. that will call
> hci_dev_do_open()
>         7. in hci_dev_do_open() we call hdev->setup() i.e. hci_uart_setup()
> in that function we set initial baud rate and operating bartender if we have
> protos defined for setting chip baud rate.(in our case it is null)
> 
>         8. so it will call setup function will be vendor specific.. as we
> are using an UART, HOST and chip need to stick to the agreement of initial
> UART speed for commands to send until and change baud rate request is
>            sent.
>         9. now in qca_setup(), we setup an initial host baud rate i.e. what
> we have agreement with BT chip for initial communication. Now here the
> question comes why are we setting init speed again and again
>            i.e uart_open() and hci_uart_setup().. here is the answer, wt
> ever layer we have are common to all vendors may also tend to change. we
> can't take a risk, we will setup init baud rate in vendor layer i.e.
>            qca_setup().
>         10. then we need to change the baud rate of chip..so we need to send
> commands to chip. at wt speed we need to send change baud rate request is
> totally based on agreement with BT Chip. so here we use initial
>             baud rate.
>         11. we need to change baud rate request command to chip on init baud
> rate. if command sending is successful we change the host baud rate from
> init to operating baud rate.. else we operate on init baud rate.
> 
> 
>         the above is based on my understanding. Pls let me know if i have
> cleared your doubt.

Thanks for the explanation. I focussed on the final outcome (operating
speed is set) and ignored that the host port needs to be at init speed
in order to send the baud rate change command to the chip.

Cheers

Matthias

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ