Commit 5dadc1be authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'char-misc-6.11-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc

Pull char/misc driver fixes from Greg KH:
 "Here are some small char/misc/other driver fixes for 6.11-rc7. It's
  nothing huge, just a bunch of small fixes of reported problems,
  including:

   - lots of tiny iio driver fixes

   - nvmem driver fixex

   - binder UAF bugfix

   - uio driver crash fix

   - other small fixes

  All of these have been in linux-next this week with no reported
  problems"

* tag 'char-misc-6.11-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (21 commits)
  VMCI: Fix use-after-free when removing resource in vmci_resource_remove()
  Drivers: hv: vmbus: Fix rescind handling in uio_hv_generic
  uio_hv_generic: Fix kernel NULL pointer dereference in hv_uio_rescind
  misc: keba: Fix sysfs group creation
  dt-bindings: nvmem: Use soc-nvmem node name instead of nvmem
  nvmem: Fix return type of devm_nvmem_device_get() in kerneldoc
  nvmem: u-boot-env: error if NVMEM device is too small
  misc: fastrpc: Fix double free of 'buf' in error path
  binder: fix UAF caused by offsets overwrite
  iio: imu: inv_mpu6050: fix interrupt status read for old buggy chips
  iio: adc: ad7173: fix GPIO device info
  iio: adc: ad7124: fix DT configuration parsing
  iio: adc: ad_sigma_delta: fix irq_flags on irq request
  iio: adc: ads1119: Fix IRQ flags
  iio: fix scale application in iio_convert_raw_to_processed_unlocked
  iio: adc: ad7124: fix config comparison
  iio: adc: ad7124: fix chip ID mismatch
  iio: adc: ad7173: Fix incorrect compatible string
  iio: buffer-dmaengine: fix releasing dma channel on error
  iio: adc: ad7606: remove frstdata check for serial mode
  ...
parents 51c4d5f1 48b9a8da
...@@ -28,7 +28,7 @@ unevaluatedProperties: false ...@@ -28,7 +28,7 @@ unevaluatedProperties: false
examples: examples:
- | - |
nvmem { soc-nvmem {
compatible = "xlnx,zynqmp-nvmem-fw"; compatible = "xlnx,zynqmp-nvmem-fw";
nvmem-layout { nvmem-layout {
compatible = "fixed-layout"; compatible = "fixed-layout";
......
...@@ -3422,6 +3422,7 @@ static void binder_transaction(struct binder_proc *proc, ...@@ -3422,6 +3422,7 @@ static void binder_transaction(struct binder_proc *proc,
*/ */
copy_size = object_offset - user_offset; copy_size = object_offset - user_offset;
if (copy_size && (user_offset > object_offset || if (copy_size && (user_offset > object_offset ||
object_offset > tr->data_size ||
binder_alloc_copy_user_to_buffer( binder_alloc_copy_user_to_buffer(
&target_proc->alloc, &target_proc->alloc,
t->buffer, user_offset, t->buffer, user_offset,
......
...@@ -1952,6 +1952,7 @@ void vmbus_device_unregister(struct hv_device *device_obj) ...@@ -1952,6 +1952,7 @@ void vmbus_device_unregister(struct hv_device *device_obj)
*/ */
device_unregister(&device_obj->device); device_unregister(&device_obj->device);
} }
EXPORT_SYMBOL_GPL(vmbus_device_unregister);
#ifdef CONFIG_ACPI #ifdef CONFIG_ACPI
/* /*
......
...@@ -147,15 +147,18 @@ struct ad7124_chip_info { ...@@ -147,15 +147,18 @@ struct ad7124_chip_info {
struct ad7124_channel_config { struct ad7124_channel_config {
bool live; bool live;
unsigned int cfg_slot; unsigned int cfg_slot;
enum ad7124_ref_sel refsel; /* Following fields are used to compare equality. */
bool bipolar; struct_group(config_props,
bool buf_positive; enum ad7124_ref_sel refsel;
bool buf_negative; bool bipolar;
unsigned int vref_mv; bool buf_positive;
unsigned int pga_bits; bool buf_negative;
unsigned int odr; unsigned int vref_mv;
unsigned int odr_sel_bits; unsigned int pga_bits;
unsigned int filter_type; unsigned int odr;
unsigned int odr_sel_bits;
unsigned int filter_type;
);
}; };
struct ad7124_channel { struct ad7124_channel {
...@@ -334,11 +337,12 @@ static struct ad7124_channel_config *ad7124_find_similar_live_cfg(struct ad7124_ ...@@ -334,11 +337,12 @@ static struct ad7124_channel_config *ad7124_find_similar_live_cfg(struct ad7124_
ptrdiff_t cmp_size; ptrdiff_t cmp_size;
int i; int i;
cmp_size = (u8 *)&cfg->live - (u8 *)cfg; cmp_size = sizeof_field(struct ad7124_channel_config, config_props);
for (i = 0; i < st->num_channels; i++) { for (i = 0; i < st->num_channels; i++) {
cfg_aux = &st->channels[i].cfg; cfg_aux = &st->channels[i].cfg;
if (cfg_aux->live && !memcmp(cfg, cfg_aux, cmp_size)) if (cfg_aux->live &&
!memcmp(&cfg->config_props, &cfg_aux->config_props, cmp_size))
return cfg_aux; return cfg_aux;
} }
...@@ -764,6 +768,7 @@ static int ad7124_soft_reset(struct ad7124_state *st) ...@@ -764,6 +768,7 @@ static int ad7124_soft_reset(struct ad7124_state *st)
if (ret < 0) if (ret < 0)
return ret; return ret;
fsleep(200);
timeout = 100; timeout = 100;
do { do {
ret = ad_sd_read_reg(&st->sd, AD7124_STATUS, 1, &readval); ret = ad_sd_read_reg(&st->sd, AD7124_STATUS, 1, &readval);
...@@ -839,8 +844,6 @@ static int ad7124_parse_channel_config(struct iio_dev *indio_dev, ...@@ -839,8 +844,6 @@ static int ad7124_parse_channel_config(struct iio_dev *indio_dev,
st->channels = channels; st->channels = channels;
device_for_each_child_node_scoped(dev, child) { device_for_each_child_node_scoped(dev, child) {
cfg = &st->channels[channel].cfg;
ret = fwnode_property_read_u32(child, "reg", &channel); ret = fwnode_property_read_u32(child, "reg", &channel);
if (ret) if (ret)
return ret; return ret;
...@@ -858,6 +861,7 @@ static int ad7124_parse_channel_config(struct iio_dev *indio_dev, ...@@ -858,6 +861,7 @@ static int ad7124_parse_channel_config(struct iio_dev *indio_dev,
st->channels[channel].ain = AD7124_CHANNEL_AINP(ain[0]) | st->channels[channel].ain = AD7124_CHANNEL_AINP(ain[0]) |
AD7124_CHANNEL_AINM(ain[1]); AD7124_CHANNEL_AINM(ain[1]);
cfg = &st->channels[channel].cfg;
cfg->bipolar = fwnode_property_read_bool(child, "bipolar"); cfg->bipolar = fwnode_property_read_bool(child, "bipolar");
ret = fwnode_property_read_u32(child, "adi,reference-select", &tmp); ret = fwnode_property_read_u32(child, "adi,reference-select", &tmp);
......
...@@ -302,7 +302,6 @@ static const struct ad7173_device_info ad4114_device_info = { ...@@ -302,7 +302,6 @@ static const struct ad7173_device_info ad4114_device_info = {
.num_configs = 8, .num_configs = 8,
.num_voltage_in = 16, .num_voltage_in = 16,
.num_gpios = 4, .num_gpios = 4,
.higher_gpio_bits = true,
.has_vincom_input = true, .has_vincom_input = true,
.has_temp = true, .has_temp = true,
.has_input_buf = true, .has_input_buf = true,
...@@ -320,7 +319,6 @@ static const struct ad7173_device_info ad4115_device_info = { ...@@ -320,7 +319,6 @@ static const struct ad7173_device_info ad4115_device_info = {
.num_configs = 8, .num_configs = 8,
.num_voltage_in = 16, .num_voltage_in = 16,
.num_gpios = 4, .num_gpios = 4,
.higher_gpio_bits = true,
.has_vincom_input = true, .has_vincom_input = true,
.has_temp = true, .has_temp = true,
.has_input_buf = true, .has_input_buf = true,
...@@ -338,7 +336,6 @@ static const struct ad7173_device_info ad4116_device_info = { ...@@ -338,7 +336,6 @@ static const struct ad7173_device_info ad4116_device_info = {
.num_configs = 8, .num_configs = 8,
.num_voltage_in = 16, .num_voltage_in = 16,
.num_gpios = 4, .num_gpios = 4,
.higher_gpio_bits = true,
.has_vincom_input = true, .has_vincom_input = true,
.has_temp = true, .has_temp = true,
.has_input_buf = true, .has_input_buf = true,
...@@ -1435,11 +1432,11 @@ static int ad7173_probe(struct spi_device *spi) ...@@ -1435,11 +1432,11 @@ static int ad7173_probe(struct spi_device *spi)
} }
static const struct of_device_id ad7173_of_match[] = { static const struct of_device_id ad7173_of_match[] = {
{ .compatible = "ad4111", .data = &ad4111_device_info }, { .compatible = "adi,ad4111", .data = &ad4111_device_info },
{ .compatible = "ad4112", .data = &ad4112_device_info }, { .compatible = "adi,ad4112", .data = &ad4112_device_info },
{ .compatible = "ad4114", .data = &ad4114_device_info }, { .compatible = "adi,ad4114", .data = &ad4114_device_info },
{ .compatible = "ad4115", .data = &ad4115_device_info }, { .compatible = "adi,ad4115", .data = &ad4115_device_info },
{ .compatible = "ad4116", .data = &ad4116_device_info }, { .compatible = "adi,ad4116", .data = &ad4116_device_info },
{ .compatible = "adi,ad7172-2", .data = &ad7172_2_device_info }, { .compatible = "adi,ad7172-2", .data = &ad7172_2_device_info },
{ .compatible = "adi,ad7172-4", .data = &ad7172_4_device_info }, { .compatible = "adi,ad7172-4", .data = &ad7172_4_device_info },
{ .compatible = "adi,ad7173-8", .data = &ad7173_8_device_info }, { .compatible = "adi,ad7173-8", .data = &ad7173_8_device_info },
......
...@@ -49,7 +49,7 @@ static const unsigned int ad7616_oversampling_avail[8] = { ...@@ -49,7 +49,7 @@ static const unsigned int ad7616_oversampling_avail[8] = {
1, 2, 4, 8, 16, 32, 64, 128, 1, 2, 4, 8, 16, 32, 64, 128,
}; };
static int ad7606_reset(struct ad7606_state *st) int ad7606_reset(struct ad7606_state *st)
{ {
if (st->gpio_reset) { if (st->gpio_reset) {
gpiod_set_value(st->gpio_reset, 1); gpiod_set_value(st->gpio_reset, 1);
...@@ -60,6 +60,7 @@ static int ad7606_reset(struct ad7606_state *st) ...@@ -60,6 +60,7 @@ static int ad7606_reset(struct ad7606_state *st)
return -ENODEV; return -ENODEV;
} }
EXPORT_SYMBOL_NS_GPL(ad7606_reset, IIO_AD7606);
static int ad7606_reg_access(struct iio_dev *indio_dev, static int ad7606_reg_access(struct iio_dev *indio_dev,
unsigned int reg, unsigned int reg,
...@@ -88,31 +89,6 @@ static int ad7606_read_samples(struct ad7606_state *st) ...@@ -88,31 +89,6 @@ static int ad7606_read_samples(struct ad7606_state *st)
{ {
unsigned int num = st->chip_info->num_channels - 1; unsigned int num = st->chip_info->num_channels - 1;
u16 *data = st->data; u16 *data = st->data;
int ret;
/*
* The frstdata signal is set to high while and after reading the sample
* of the first channel and low for all other channels. This can be used
* to check that the incoming data is correctly aligned. During normal
* operation the data should never become unaligned, but some glitch or
* electrostatic discharge might cause an extra read or clock cycle.
* Monitoring the frstdata signal allows to recover from such failure
* situations.
*/
if (st->gpio_frstdata) {
ret = st->bops->read_block(st->dev, 1, data);
if (ret)
return ret;
if (!gpiod_get_value(st->gpio_frstdata)) {
ad7606_reset(st);
return -EIO;
}
data++;
num--;
}
return st->bops->read_block(st->dev, num, data); return st->bops->read_block(st->dev, num, data);
} }
......
...@@ -151,6 +151,8 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address, ...@@ -151,6 +151,8 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
const char *name, unsigned int id, const char *name, unsigned int id,
const struct ad7606_bus_ops *bops); const struct ad7606_bus_ops *bops);
int ad7606_reset(struct ad7606_state *st);
enum ad7606_supported_device_ids { enum ad7606_supported_device_ids {
ID_AD7605_4, ID_AD7605_4,
ID_AD7606_8, ID_AD7606_8,
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <linux/mod_devicetable.h> #include <linux/mod_devicetable.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/gpio/consumer.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/err.h> #include <linux/err.h>
...@@ -21,8 +22,29 @@ static int ad7606_par16_read_block(struct device *dev, ...@@ -21,8 +22,29 @@ static int ad7606_par16_read_block(struct device *dev,
struct iio_dev *indio_dev = dev_get_drvdata(dev); struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct ad7606_state *st = iio_priv(indio_dev); struct ad7606_state *st = iio_priv(indio_dev);
insw((unsigned long)st->base_address, buf, count);
/*
* On the parallel interface, the frstdata signal is set to high while
* and after reading the sample of the first channel and low for all
* other channels. This can be used to check that the incoming data is
* correctly aligned. During normal operation the data should never
* become unaligned, but some glitch or electrostatic discharge might
* cause an extra read or clock cycle. Monitoring the frstdata signal
* allows to recover from such failure situations.
*/
int num = count;
u16 *_buf = buf;
if (st->gpio_frstdata) {
insw((unsigned long)st->base_address, _buf, 1);
if (!gpiod_get_value(st->gpio_frstdata)) {
ad7606_reset(st);
return -EIO;
}
_buf++;
num--;
}
insw((unsigned long)st->base_address, _buf, num);
return 0; return 0;
} }
...@@ -35,8 +57,28 @@ static int ad7606_par8_read_block(struct device *dev, ...@@ -35,8 +57,28 @@ static int ad7606_par8_read_block(struct device *dev,
{ {
struct iio_dev *indio_dev = dev_get_drvdata(dev); struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct ad7606_state *st = iio_priv(indio_dev); struct ad7606_state *st = iio_priv(indio_dev);
/*
insb((unsigned long)st->base_address, buf, count * 2); * On the parallel interface, the frstdata signal is set to high while
* and after reading the sample of the first channel and low for all
* other channels. This can be used to check that the incoming data is
* correctly aligned. During normal operation the data should never
* become unaligned, but some glitch or electrostatic discharge might
* cause an extra read or clock cycle. Monitoring the frstdata signal
* allows to recover from such failure situations.
*/
int num = count;
u16 *_buf = buf;
if (st->gpio_frstdata) {
insb((unsigned long)st->base_address, _buf, 2);
if (!gpiod_get_value(st->gpio_frstdata)) {
ad7606_reset(st);
return -EIO;
}
_buf++;
num--;
}
insb((unsigned long)st->base_address, _buf, num * 2);
return 0; return 0;
} }
......
...@@ -569,7 +569,7 @@ EXPORT_SYMBOL_NS_GPL(ad_sd_validate_trigger, IIO_AD_SIGMA_DELTA); ...@@ -569,7 +569,7 @@ EXPORT_SYMBOL_NS_GPL(ad_sd_validate_trigger, IIO_AD_SIGMA_DELTA);
static int devm_ad_sd_probe_trigger(struct device *dev, struct iio_dev *indio_dev) static int devm_ad_sd_probe_trigger(struct device *dev, struct iio_dev *indio_dev)
{ {
struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev); struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev);
unsigned long irq_flags = irq_get_trigger_type(sigma_delta->spi->irq); unsigned long irq_flags = irq_get_trigger_type(sigma_delta->irq_line);
int ret; int ret;
if (dev != &sigma_delta->spi->dev) { if (dev != &sigma_delta->spi->dev) {
......
...@@ -735,7 +735,7 @@ static int ads1119_probe(struct i2c_client *client) ...@@ -735,7 +735,7 @@ static int ads1119_probe(struct i2c_client *client)
if (client->irq > 0) { if (client->irq > 0) {
ret = devm_request_threaded_irq(dev, client->irq, ret = devm_request_threaded_irq(dev, client->irq,
ads1119_irq_handler, ads1119_irq_handler,
NULL, IRQF_TRIGGER_FALLING, NULL, IRQF_ONESHOT,
"ads1119", indio_dev); "ads1119", indio_dev);
if (ret) if (ret)
return dev_err_probe(dev, ret, return dev_err_probe(dev, ret,
......
...@@ -237,7 +237,7 @@ static struct iio_buffer *iio_dmaengine_buffer_alloc(struct device *dev, ...@@ -237,7 +237,7 @@ static struct iio_buffer *iio_dmaengine_buffer_alloc(struct device *dev,
ret = dma_get_slave_caps(chan, &caps); ret = dma_get_slave_caps(chan, &caps);
if (ret < 0) if (ret < 0)
goto err_free; goto err_release;
/* Needs to be aligned to the maximum of the minimums */ /* Needs to be aligned to the maximum of the minimums */
if (caps.src_addr_widths) if (caps.src_addr_widths)
...@@ -263,6 +263,8 @@ static struct iio_buffer *iio_dmaengine_buffer_alloc(struct device *dev, ...@@ -263,6 +263,8 @@ static struct iio_buffer *iio_dmaengine_buffer_alloc(struct device *dev,
return &dmaengine_buffer->queue.buffer; return &dmaengine_buffer->queue.buffer;
err_release:
dma_release_channel(chan);
err_free: err_free:
kfree(dmaengine_buffer); kfree(dmaengine_buffer);
return ERR_PTR(ret); return ERR_PTR(ret);
......
...@@ -248,12 +248,20 @@ static irqreturn_t inv_mpu6050_interrupt_handle(int irq, void *p) ...@@ -248,12 +248,20 @@ static irqreturn_t inv_mpu6050_interrupt_handle(int irq, void *p)
int result; int result;
switch (st->chip_type) { switch (st->chip_type) {
case INV_MPU6000:
case INV_MPU6050: case INV_MPU6050:
case INV_MPU9150:
/*
* WoM is not supported and interrupt status read seems to be broken for
* some chips. Since data ready is the only interrupt, bypass interrupt
* status read and always assert data ready bit.
*/
wom_bits = 0;
int_status = INV_MPU6050_BIT_RAW_DATA_RDY_INT;
goto data_ready_interrupt;
case INV_MPU6500: case INV_MPU6500:
case INV_MPU6515: case INV_MPU6515:
case INV_MPU6880: case INV_MPU6880:
case INV_MPU6000:
case INV_MPU9150:
case INV_MPU9250: case INV_MPU9250:
case INV_MPU9255: case INV_MPU9255:
wom_bits = INV_MPU6500_BIT_WOM_INT; wom_bits = INV_MPU6500_BIT_WOM_INT;
...@@ -279,6 +287,7 @@ static irqreturn_t inv_mpu6050_interrupt_handle(int irq, void *p) ...@@ -279,6 +287,7 @@ static irqreturn_t inv_mpu6050_interrupt_handle(int irq, void *p)
} }
} }
data_ready_interrupt:
/* handle raw data interrupt */ /* handle raw data interrupt */
if (int_status & INV_MPU6050_BIT_RAW_DATA_RDY_INT) { if (int_status & INV_MPU6050_BIT_RAW_DATA_RDY_INT) {
indio_dev->pollfunc->timestamp = st->it_timestamp; indio_dev->pollfunc->timestamp = st->it_timestamp;
......
...@@ -647,17 +647,17 @@ static int iio_convert_raw_to_processed_unlocked(struct iio_channel *chan, ...@@ -647,17 +647,17 @@ static int iio_convert_raw_to_processed_unlocked(struct iio_channel *chan,
break; break;
case IIO_VAL_INT_PLUS_MICRO: case IIO_VAL_INT_PLUS_MICRO:
if (scale_val2 < 0) if (scale_val2 < 0)
*processed = -raw64 * scale_val; *processed = -raw64 * scale_val * scale;
else else
*processed = raw64 * scale_val; *processed = raw64 * scale_val * scale;
*processed += div_s64(raw64 * (s64)scale_val2 * scale, *processed += div_s64(raw64 * (s64)scale_val2 * scale,
1000000LL); 1000000LL);
break; break;
case IIO_VAL_INT_PLUS_NANO: case IIO_VAL_INT_PLUS_NANO:
if (scale_val2 < 0) if (scale_val2 < 0)
*processed = -raw64 * scale_val; *processed = -raw64 * scale_val * scale;
else else
*processed = raw64 * scale_val; *processed = raw64 * scale_val * scale;
*processed += div_s64(raw64 * (s64)scale_val2 * scale, *processed += div_s64(raw64 * (s64)scale_val2 * scale,
1000000000LL); 1000000000LL);
break; break;
......
...@@ -1910,7 +1910,8 @@ static int fastrpc_req_mmap(struct fastrpc_user *fl, char __user *argp) ...@@ -1910,7 +1910,8 @@ static int fastrpc_req_mmap(struct fastrpc_user *fl, char __user *argp)
&args[0]); &args[0]);
if (err) { if (err) {
dev_err(dev, "mmap error (len 0x%08llx)\n", buf->size); dev_err(dev, "mmap error (len 0x%08llx)\n", buf->size);
goto err_invoke; fastrpc_buf_free(buf);
return err;
} }
/* update the buffer to be able to deallocate the memory on the DSP */ /* update the buffer to be able to deallocate the memory on the DSP */
...@@ -1948,8 +1949,6 @@ static int fastrpc_req_mmap(struct fastrpc_user *fl, char __user *argp) ...@@ -1948,8 +1949,6 @@ static int fastrpc_req_mmap(struct fastrpc_user *fl, char __user *argp)
err_assign: err_assign:
fastrpc_req_munmap_impl(fl, buf); fastrpc_req_munmap_impl(fl, buf);
err_invoke:
fastrpc_buf_free(buf);
return err; return err;
} }
......
...@@ -212,12 +212,12 @@ static ssize_t keep_cfg_store(struct device *dev, struct device_attribute *attr, ...@@ -212,12 +212,12 @@ static ssize_t keep_cfg_store(struct device *dev, struct device_attribute *attr,
} }
static DEVICE_ATTR_RW(keep_cfg); static DEVICE_ATTR_RW(keep_cfg);
static struct attribute *attrs[] = { static struct attribute *cp500_attrs[] = {
&dev_attr_version.attr, &dev_attr_version.attr,
&dev_attr_keep_cfg.attr, &dev_attr_keep_cfg.attr,
NULL NULL
}; };
static const struct attribute_group attrs_group = { .attrs = attrs }; ATTRIBUTE_GROUPS(cp500);
static void cp500_i2c_release(struct device *dev) static void cp500_i2c_release(struct device *dev)
{ {
...@@ -396,20 +396,15 @@ static int cp500_probe(struct pci_dev *pci_dev, const struct pci_device_id *id) ...@@ -396,20 +396,15 @@ static int cp500_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
pci_set_drvdata(pci_dev, cp500); pci_set_drvdata(pci_dev, cp500);
ret = sysfs_create_group(&pci_dev->dev.kobj, &attrs_group);
if (ret != 0)
goto out_free_irq;
ret = cp500_enable(cp500); ret = cp500_enable(cp500);
if (ret != 0) if (ret != 0)
goto out_remove_group; goto out_free_irq;
cp500_register_auxiliary_devs(cp500); cp500_register_auxiliary_devs(cp500);
return 0; return 0;
out_remove_group:
sysfs_remove_group(&pci_dev->dev.kobj, &attrs_group);
out_free_irq: out_free_irq:
pci_free_irq_vectors(pci_dev); pci_free_irq_vectors(pci_dev);
out_disable: out_disable:
...@@ -427,8 +422,6 @@ static void cp500_remove(struct pci_dev *pci_dev) ...@@ -427,8 +422,6 @@ static void cp500_remove(struct pci_dev *pci_dev)
cp500_disable(cp500); cp500_disable(cp500);
sysfs_remove_group(&pci_dev->dev.kobj, &attrs_group);
pci_set_drvdata(pci_dev, 0); pci_set_drvdata(pci_dev, 0);
pci_free_irq_vectors(pci_dev); pci_free_irq_vectors(pci_dev);
...@@ -450,6 +443,7 @@ static struct pci_driver cp500_driver = { ...@@ -450,6 +443,7 @@ static struct pci_driver cp500_driver = {
.id_table = cp500_ids, .id_table = cp500_ids,
.probe = cp500_probe, .probe = cp500_probe,
.remove = cp500_remove, .remove = cp500_remove,
.dev_groups = cp500_groups,
}; };
module_pci_driver(cp500_driver); module_pci_driver(cp500_driver);
......
...@@ -144,7 +144,8 @@ void vmci_resource_remove(struct vmci_resource *resource) ...@@ -144,7 +144,8 @@ void vmci_resource_remove(struct vmci_resource *resource)
spin_lock(&vmci_resource_table.lock); spin_lock(&vmci_resource_table.lock);
hlist_for_each_entry(r, &vmci_resource_table.entries[idx], node) { hlist_for_each_entry(r, &vmci_resource_table.entries[idx], node) {
if (vmci_handle_is_equal(r->handle, resource->handle)) { if (vmci_handle_is_equal(r->handle, resource->handle) &&
resource->type == r->type) {
hlist_del_init_rcu(&r->node); hlist_del_init_rcu(&r->node);
break; break;
} }
......
...@@ -1276,13 +1276,13 @@ void nvmem_device_put(struct nvmem_device *nvmem) ...@@ -1276,13 +1276,13 @@ void nvmem_device_put(struct nvmem_device *nvmem)
EXPORT_SYMBOL_GPL(nvmem_device_put); EXPORT_SYMBOL_GPL(nvmem_device_put);
/** /**
* devm_nvmem_device_get() - Get nvmem cell of device form a given id * devm_nvmem_device_get() - Get nvmem device of device form a given id
* *
* @dev: Device that requests the nvmem device. * @dev: Device that requests the nvmem device.
* @id: name id for the requested nvmem device. * @id: name id for the requested nvmem device.
* *
* Return: ERR_PTR() on error or a valid pointer to a struct nvmem_cell * Return: ERR_PTR() on error or a valid pointer to a struct nvmem_device
* on success. The nvmem_cell will be freed by the automatically once the * on success. The nvmem_device will be freed by the automatically once the
* device is freed. * device is freed.
*/ */
struct nvmem_device *devm_nvmem_device_get(struct device *dev, const char *id) struct nvmem_device *devm_nvmem_device_get(struct device *dev, const char *id)
......
...@@ -176,6 +176,13 @@ static int u_boot_env_parse(struct u_boot_env *priv) ...@@ -176,6 +176,13 @@ static int u_boot_env_parse(struct u_boot_env *priv)
data_offset = offsetof(struct u_boot_env_image_broadcom, data); data_offset = offsetof(struct u_boot_env_image_broadcom, data);
break; break;
} }
if (dev_size < data_offset) {
dev_err(dev, "Device too small for u-boot-env\n");
err = -EIO;
goto err_kfree;
}
crc32_addr = (__le32 *)(buf + crc32_offset); crc32_addr = (__le32 *)(buf + crc32_offset);
crc32 = le32_to_cpu(*crc32_addr); crc32 = le32_to_cpu(*crc32_addr);
crc32_data_len = dev_size - crc32_data_offset; crc32_data_len = dev_size - crc32_data_offset;
......
...@@ -114,7 +114,7 @@ static int ad9834_write_frequency(struct ad9834_state *st, ...@@ -114,7 +114,7 @@ static int ad9834_write_frequency(struct ad9834_state *st,
clk_freq = clk_get_rate(st->mclk); clk_freq = clk_get_rate(st->mclk);
if (fout > (clk_freq / 2)) if (!clk_freq || fout > (clk_freq / 2))
return -EINVAL; return -EINVAL;
regval = ad9834_calc_freqreg(clk_freq, fout); regval = ad9834_calc_freqreg(clk_freq, fout);
......
...@@ -106,10 +106,11 @@ static void hv_uio_channel_cb(void *context) ...@@ -106,10 +106,11 @@ static void hv_uio_channel_cb(void *context)
/* /*
* Callback from vmbus_event when channel is rescinded. * Callback from vmbus_event when channel is rescinded.
* It is meant for rescind of primary channels only.
*/ */
static void hv_uio_rescind(struct vmbus_channel *channel) static void hv_uio_rescind(struct vmbus_channel *channel)
{ {
struct hv_device *hv_dev = channel->primary_channel->device_obj; struct hv_device *hv_dev = channel->device_obj;
struct hv_uio_private_data *pdata = hv_get_drvdata(hv_dev); struct hv_uio_private_data *pdata = hv_get_drvdata(hv_dev);
/* /*
...@@ -120,6 +121,14 @@ static void hv_uio_rescind(struct vmbus_channel *channel) ...@@ -120,6 +121,14 @@ static void hv_uio_rescind(struct vmbus_channel *channel)
/* Wake up reader */ /* Wake up reader */
uio_event_notify(&pdata->info); uio_event_notify(&pdata->info);
/*
* With rescind callback registered, rescind path will not unregister the device
* from vmbus when the primary channel is rescinded.
* Without it, rescind handling is incomplete and next onoffer msg does not come.
* Unregister the device from vmbus here.
*/
vmbus_device_unregister(channel->device_obj);
} }
/* Sysfs API to allow mmap of the ring buffers /* Sysfs API to allow mmap of the ring buffers
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment