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]
Message-ID: <CAHp75VeXqFgqiGUkS71B1xCD-60iQFS4EKJwVFX-L_dTUFMc6A@mail.gmail.com>
Date:   Thu, 30 Jul 2020 14:31:31 +0300
From:   Andy Shevchenko <andy.shevchenko@...il.com>
To:     Christian Eggers <ceggers@...i.de>
Cc:     Rob Herring <robh+dt@...nel.org>,
        Jonathan Cameron <jic23@...nel.org>,
        Jonathan Cameron <Jonathan.Cameron@...wei.com>,
        Hartmut Knaack <knaack.h@....de>,
        Lars-Peter Clausen <lars@...afoo.de>,
        Peter Meerwald-Stadler <pmeerw@...erw.net>,
        linux-iio <linux-iio@...r.kernel.org>,
        devicetree <devicetree@...r.kernel.org>,
        Linux Kernel Mailing List <linux-kernel@...r.kernel.org>
Subject: Re: [PATCH v3 2/2] iio: light: as73211: New driver

On Thu, Jul 30, 2020 at 1:52 PM Christian Eggers <ceggers@...i.de> wrote:
> Support for AMS AS73211 JENCOLOR(R) Digital XYZ Sensor.
>
> This driver has no built-in trigger. In order for making triggered
> measurements, an external (software) trigger driver like
> iio-trig-hrtimer or iio-trig-sysfs is required.
>
> The sensor supports single and continuous measurement modes. The latter
> is not used by design as this would require tight timing synchronization
> between hardware and driver without much benefit.

...

> +#include <linux/iio/iio.h>
> +#include <linux/iio/sysfs.h>
> +#include <linux/iio/trigger_consumer.h>
> +#include <linux/iio/buffer.h>
> +#include <linux/iio/triggered_buffer.h>

Ordered?

...

> +/**
> + * struct as73211_data - Instance data for one AS73211
> + * @client: I2C client.
> + * @osr:    Cached Operational State Register.
> + * @creg1:  Cached Configuration Register 1.
> + * @creg2:  Cached Configuration Register 2.
> + * @creg3:  Cached Configuration Register 3.
> + * @buffer: Buffer for triggered measurements.
> + * @mutex:  Keeps cached registers in synch with the device.
> + * @completion: Completion to wait for interrupt.
> + */
> +struct as73211_data {
> +       struct i2c_client *client;
> +       u8 osr;
> +       u8 creg1;
> +       u8 creg2;
> +       u8 creg3;
> +       struct mutex mutex;
> +       struct completion completion;
> +};

Actually Jonathan is correct -- the above has kernel doc issues.

...

> +#define AS73211_SCAN_MASK_COLOR \
> +       (BIT(AS73211_SCAN_INDEX_X) | BIT(AS73211_SCAN_INDEX_Y) | BIT(AS73211_SCAN_INDEX_Z))

> +#define AS73211_SCAN_MASK_ALL (BIT(AS73211_SCAN_INDEX_TEMP) | AS73211_SCAN_MASK_COLOR)

Perhaps split for easy reading.

...

> +static unsigned int as73211_integration_time_us(struct as73211_data *data)
> +{
> +       /* Integration time has 15 steps, the step size depends on the clock. */
> +       unsigned int mul = BIT(3 - (data->creg3 & GENMASK(1, 0)));

Shouldn't be rather

#define FOO  GENMASK(1, 0)
mul = BIT(FOO - (creg & FOO));

with a descriptive name of FOO?

Or if both 3:s have different meaning, two definitions?

> +       return as73211_integration_time_cycles(data) * 125 * mul;
> +}

...

> +static unsigned int as73211_gain(struct as73211_data *data)
> +{

> +       return BIT(0xb - FIELD_GET(AS73211_CREG1_GAIN_MASK, data->creg1));

Magic!

> +}

...

> +       struct device *dev = &data->client->dev;
> +       unsigned int time_us = as73211_integration_time_us(data);
> +       int ret;
> +       union i2c_smbus_data smbus_data;
> +       u16 osr_status;

Can you keep this in reversed tree order?

       unsigned int time_us = as73211_integration_time_us(data);
       struct device *dev = &data->client->dev;
       union i2c_smbus_data smbus_data;
       u16 osr_status;
       int ret;

Same comment to the rest where applicable.

...

> +       /* Add some extra margin for the timeout. sensor timing is not as precise
> +        * as our one ...
> +        */

Comment style. Same to the rest of the code where applicable.

...

> +       if (data->client->irq) {
> +               dev_dbg(dev, "Waiting for completion...\n");
> +               ret = wait_for_completion_timeout(&data->completion,

> +                                       2 + usecs_to_jiffies(time_us));

Magic!

> +               if (!ret) {
> +                       dev_err(dev, "timeout waiting for READY IRQ\n");
> +                       i2c_unlock_bus(data->client->adapter, I2C_LOCK_SEGMENT);
> +                       return -ETIMEDOUT;
> +               }
> +       } else {
> +               /* Wait integration time */

> +               dev_dbg(dev, "Sleeping %d us\n", time_us);

Looks like a noise (good for development, bad for upstream)

> +               usleep_range(time_us, time_us + 100000);

If time_us appears to be, let's say, 100. The above margin is way too high.

> +       }

...

> +       osr_status = (u16)ret;

Why casting?

...

> +       dev_dbg(dev, "osr_status = 0x%04x\n", osr_status);

Looks like a noise (good for development, bad for upstream)

...

> +               if (osr_status & AS73211_OSR_SS) {
> +                       dev_warn(dev, "%s() Measurement has not stopped\n", __func__);
> +                       return -ETIME;
> +               }
> +               if (osr_status & AS73211_OSR_STATUS_NOTREADY) {
> +                       dev_warn(dev, "%s() Data is not ready\n", __func__);
> +                       return -ENODATA;
> +               }
> +               if (!(osr_status & AS73211_OSR_STATUS_NDATA)) {
> +                       dev_warn(dev, "%s() New new data available\n", __func__);
> +                       return -ENODATA;
> +               }
> +               if (osr_status & AS73211_OSR_STATUS_LDATA) {
> +                       dev_warn(dev, "%s() Result buffer overrun\n", __func__);
> +                       return -ENOBUFS;
> +               }
> +               if (osr_status & AS73211_OSR_STATUS_ADCOF) {
> +                       dev_warn(dev, "%s() ADC overflow\n", __func__);
> +                       return -EOVERFLOW;
> +               }
> +               if (osr_status & AS73211_OSR_STATUS_MRESOF) {
> +                       dev_warn(dev, "%s() Measurement result overflow\n", __func__);
> +                       return -EOVERFLOW;
> +               }
> +               if (osr_status & AS73211_OSR_STATUS_OUTCONVOF) {
> +                       dev_warn(dev, "%s() Timer overflow\n", __func__);
> +                       return -EOVERFLOW;
> +               }
> +               dev_warn(dev, "%s() Unexpected status value\n", __func__);
> +               return -EIO;
> +       }

All above dev_warn() are wrong. Should be dev_err(). Otherwise all
return -ERRNO are wrong.

...

> +               int ret = iio_device_claim_direct_mode(indio_dev);
> +
> +               if (ret)
> +                       return ret;

Please, use better arrangement, i.e.

  int ret;

  ret = ...
  if (ret)
  ...

+ blank line.

> +               ret = as73211_req_data(data);
> +               if (ret < 0) {
> +                       iio_device_release_direct_mode(indio_dev);
> +                       return ret;
> +               }

+ blank line

> +               ret = i2c_smbus_read_word_data(data->client, chan->address);
> +               iio_device_release_direct_mode(indio_dev);
> +               if (ret < 0)
> +                       return ret;

+ blank line

> +               *val = ret;
> +               return IIO_VAL_INT;
> +       }

...

> +       case IIO_CHAN_INFO_SCALE:
> +       {

On one line.

...

> +               *val = BIT(data->creg3 & GENMASK(1, 0)) * 1024 * 1000;

1000 is magic and 1024 either.

1000 is frequency multiplier? If it's not defined do it like
  #define HZ_PER_KHZ
  #define KHZ_PER_MHZ
or what is that?

...

> +               *val = time_us / 1000000;
> +               *val2 = time_us % 1000000;

Ditto.

NSEC_PER_SEC or what?

...

> +               int reg_bits, freq_kHz = val / 1000;  /* 1024, 2048, ... */

HZ_PER_KHZ?

...

> +               if (val < 0 || (freq_kHz * 1000) != val || val2)

Ditto.

...

> +               return i2c_smbus_write_byte_data(data->client, AS73211_REG_CREG3, data->creg3);

Can it suddenly return positive number?

...

> +               int time_us = val * 1000000 + val2, time_ms;

NSEC_PER_MSEC ?
USEC_PER_SEC ?

...

> +               time_ms = (time_us * mul) / 1000;  /* 1 ms, 2 ms, ... (power of two) */

NSEC_PER_MSEC

...

> +               if (time_ms < 0 || !is_power_of_2(time_ms) || time_ms > 16384)

Magic! Shouldn't be rather BIT(14)  and defined somewhere?

...


> +       /* Need to switch to config mode ... */

Not sure how this comment related to locking.

> +       mutex_lock(&data->mutex);

...

> +               dev_dbg(&indio_dev->dev, "Switching to configuration state...");

Noise.

...

> +static irqreturn_t as73211_ready_handler(int irq __always_unused, void *priv)
> +{

> +       struct iio_dev *indio_dev = priv;

Unneeded churn.

> +       struct as73211_data *data = iio_priv(indio_dev);

iio_priv(priv)

> +       complete(&data->completion);
> +
> +       return IRQ_HANDLED;
> +}

...

> +       struct iio_dev *indio_dev = pf->indio_dev;

Ditto. Do you use indio_dev below (except one case)? I haven't noticed.

> +       struct as73211_data *data = iio_priv(indio_dev);

...

> +               struct i2c_msg msgs[] = {
> +                       {
> +                               .addr = data->client->addr,
> +                               .flags = 0,
> +                               .len = 1,
> +                               .buf = &addr

+ comma

> +                       },
> +                       {
> +                               .addr = data->client->addr,
> +                               .flags = I2C_M_RD,
> +                               .len = sizeof(scan.chan),
> +                               .buf = (u8 *)&scan.chan

+ comma

> +                       },
> +               };

...

> +       }
> +       /* Optimization for reading only color channels */
> +       else {

Should be one line. Had you run checkpatch?

...

> +static ssize_t as73211_show_samp_freq_available(struct device *dev __always_unused,
> +                                                struct device_attribute *attr __always_unused,
> +                                                char *buf)
> +{
> +}
> +
> +static ssize_t as73211_show_int_time_available(struct device *dev,
> +                                               struct device_attribute *attr __always_unused,
> +                                               char *buf)
> +{
> +}
> +
> +static ssize_t as73211_show_hardwaregain_available(struct device *dev __always_unused,
> +                                                   struct device_attribute *attr __always_unused,
> +                                                   char *buf)
> +{
> +}

I guess above is an overkill. See example here

commit 6085102c494b8afc62bc093f8f32d6248f6d33e5
Author: Andy Shevchenko <andriy.shevchenko@...ux.intel.com>
Date:   Mon Mar 23 12:41:26 2020 +0200

   iio: pressure: bmp280: Convert to use ->read_avail()

...

> +       ret = i2c_smbus_read_byte_data(data->client, AS73211_REG_OSR);
> +       if (ret < 0)
> +               return ret;

Yeah, be consistent. Either all such call should be checked against
negative error code, or drop ' < 0' everywhere it applies.

...

> +       /* At the time of writing this driver, only DEVID 2 and MUT 1 is known. */
> +       if ((ret & AS73211_AGEN_DEVID_MASK) != AS73211_AGEN_DEVID(2)
> +                       || (ret & AS73211_AGEN_MUT_MASK) != AS73211_AGEN_MUT(1))

Looks like broken indentation, and leave || on previous line.

> +               return -ENODEV;

...

> +       if (client->irq) {
> +               ret = request_threaded_irq(client->irq,
> +                               NULL,
> +                               as73211_ready_handler,

> +                               IRQF_TRIGGER_RISING | IRQF_ONESHOT,

Should not be IRQ trigger type here. (Do you have broken firmware table?)

> +                               client->name, indio_dev);
> +               if (ret)
> +                       goto buffer_cleanup;
> +       }

-- 
With Best Regards,
Andy Shevchenko

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ